using FrameworkDAL.CustomCode.ReportHeader; using FrameworkDAL.DTO.ReportHeader; using GB5Shared.DTO.Framework.Login; using GB5Shared.EventLogPublish; using GB5Shared.GenerateAutoNumber; using GB5Shared.Resource.Response; using GB5Shared.Telemetry; using GB5Shared.Validation; using Microsoft.Extensions.Logging; using System.ComponentModel.DataAnnotations; using static GB5Shared.GB5Constant.Constant; namespace FrameworkBLL.ReportHeaderMgmt { public class ReportHeaderBLL : IReportHeaderBLL { private readonly IReportHeaderDAL _dal; private readonly AutoNumber _autoNumber; private readonly IValidation _validation; private readonly EventLogPublish _eventLog; private readonly ILogger _logger; public ReportHeaderBLL( IReportHeaderDAL dal, AutoNumber autoNumber, IValidation validation, EventLogPublish eventLog, ILogger logger) { _dal = dal; _autoNumber = autoNumber; _validation = validation; _eventLog = eventLog; _logger = logger; } // ── Read ────────────────────────────────────────────────────────────── public async Task GetReportHeader(int reportHeaderId, LoginDTO login, CancellationToken ct) { try { return await _dal.GetReportHeader(reportHeaderId, login, ct).ConfigureAwait(false); } catch (Exception ex) { GB5Trace.MarkFailed("get-reportheader-failed", ex); _logger.LogError(ex, "GetReportHeader failed for ReportHeaderId {Id}", reportHeaderId); throw; } } public async Task GetReportHeaderList(LoginDTO login, CancellationToken ct) { try { return await _dal.GetReportHeaderList(login, ct).ConfigureAwait(false); } catch (Exception ex) { GB5Trace.MarkFailed("get-reportheaderlist-failed", ex); _logger.LogError(ex, "GetReportHeaderList failed for ClientId {ClientId}", login.ClientId); throw; } } public async Task GetReportHeaderPaged(int offset, int pageSize, LoginDTO login, CancellationToken ct) { try { return await _dal.GetReportHeaderPaged(offset, pageSize, login, ct).ConfigureAwait(false); } catch (Exception ex) { GB5Trace.MarkFailed("get-reportheaderpaged-failed", ex); _logger.LogError(ex, "GetReportHeaderPaged failed for ClientId {ClientId}", login.ClientId); throw; } } public async Task GetSelectListReportHeader(LoginDTO login, CancellationToken ct) { try { return await _dal.GetSelectListReportHeader(login, ct).ConfigureAwait(false); } catch (Exception ex) { GB5Trace.MarkFailed("get-selectlist-reportheader-failed", ex); _logger.LogError(ex, "GetSelectListReportHeader failed for ClientId {ClientId}", login.ClientId); throw; } } // ── Save ────────────────────────────────────────────────────────────── public async Task SaveReportHeader(ReportHeaderDTO dto, LoginDTO login, CancellationToken ct) { bool isNew = dto.ReportHeaderId == 0; int? allocatedHeaderId = null; int? allocatedDetailStartId = null; try { GB5Trace.Step("validate-reportheader", new { dto.ReportHeaderId }); await _validation.NotEmpty(dto.ReportHeaderCode, nameof(dto.ReportHeaderCode)).ConfigureAwait(false); await _validation.NotEmpty(dto.ReportHeaderName, nameof(dto.ReportHeaderName)).ConfigureAwait(false); await _validation.MaxLength("MREPORTHEADER", "REPORTHEADERCODE", dto.ReportHeaderCode).ConfigureAwait(false); await _validation.MaxLength("MREPORTHEADER", "REPORTHEADERNAME", dto.ReportHeaderName).ConfigureAwait(false); if (isNew) { var an = await _autoNumber.GetAutoNumber(1, "MREPORTHEADER", login).ConfigureAwait(false); dto.ReportHeaderId = an.StartNumber; allocatedHeaderId = dto.ReportHeaderId; dto.ReportHeaderCreatedById = login.UserId; dto.ReportHeaderCreatedOn = DateTime.UtcNow; dto.ReportHeaderBaseClinetId = login.ClientId; } dto.ReportHeaderModifiedById = login.UserId; dto.ReportHeaderModifiedOn = DateTime.UtcNow; // Allocate IDs for each new detail row int detailCount = dto.ReportHeaderDetailArray?.Count ?? 0; if (detailCount > 0) { var detailAn = await _autoNumber.GetAutoNumber(detailCount, "MREPORTHEADERDETAIL", login) .ConfigureAwait(false); allocatedDetailStartId = detailAn.StartNumber; int nextId = detailAn.StartNumber; foreach (var detail in dto.ReportHeaderDetailArray!) { if (detail.ReportHeaderDetailId == 0) detail.ReportHeaderDetailId = nextId++; detail.ReportHeaderId = dto.ReportHeaderId; detail.ReportHeaderDetailCreatedById = login.UserId; detail.ReportHeaderDetailCreatedOn = DateTime.UtcNow; detail.ReportHeaderDetailModifiedById = login.UserId; detail.ReportHeaderDetailModifiedOn = DateTime.UtcNow; } } GB5Trace.Step("save-reportheader", new { dto.ReportHeaderId, isNew, detailCount }); int savedId = await _dal.SaveReportHeader(dto, login, ct, isNew).ConfigureAwait(false); GB5Trace.Step("event-publish", new { EventTypeConstant.SAVEREPORTHEADEREVENTTYPEID }); await _eventLog.PublishEventLogAsync( "ReportHeader Saved", dto, EventTypeConstant.SAVEREPORTHEADEREVENTTYPEID, savedId, login, ct: ct).ConfigureAwait(false); return isNew ? $"{SuccessResponse.SaveSuccessMessage} {savedId}" : SuccessResponse.UpdateSuccess; } catch (ValidationException vex) { throw new Exception(vex.Message); } catch (Exception ex) { GB5Trace.MarkFailed("save-reportheader-failed", ex); _logger.LogError(ex, "SaveReportHeader failed for ReportHeaderId {Id}", dto.ReportHeaderId); if (isNew && allocatedHeaderId.HasValue) await _autoNumber.RollbackAutoNumber("MREPORTHEADER", allocatedHeaderId.Value, login).ConfigureAwait(false); throw; } } // ── Delete ──────────────────────────────────────────────────────────── public async Task DeleteReportHeader(int reportHeaderId, LoginDTO login, CancellationToken ct) { try { GB5Trace.Step("delete-reportheader", new { reportHeaderId }); await _dal.DeleteReportHeader(reportHeaderId, login, ct).ConfigureAwait(false); GB5Trace.Step("event-publish", new { EventTypeConstant.DELETEREPORTHEADEREVENTTYPEID }); await _eventLog.PublishEventLogAsync( "ReportHeader Deleted", new { ReportHeaderId = reportHeaderId }, EventTypeConstant.DELETEREPORTHEADEREVENTTYPEID, reportHeaderId, login, ct: ct).ConfigureAwait(false); return SuccessResponse.DeleteSuccessMessage; } catch (Exception ex) { GB5Trace.MarkFailed("delete-reportheader-failed", ex); _logger.LogError(ex, "DeleteReportHeader failed for ReportHeaderId {Id}", reportHeaderId); throw; } } } }