using FrameworkDAL.CustomCode.ReportViewer; using FrameworkDAL.DTO.Menu; using FrameworkDAL.DTO.ReportViewer; using FrameworkDAL.Query.ReportViewer; using GB5Shared.DALCache; using GB5Shared.DaprCache; using GB5Shared.DTO.Framework.Criteria; 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 Newtonsoft.Json; using System.ComponentModel.DataAnnotations; using static GB5Shared.GB5Constant.Constant; namespace FrameworkBLL.ReportViewer { public class ReportViewBLL : IReportViewBLL { private readonly IReportViewDAL _dal; private readonly AutoNumber _autoNumber; private readonly IValidation _validation; private readonly EventLogPublish _eventLog; private readonly ILogger _logger; private readonly IDALCache _dalCache; private readonly CacheKeyGeneration _keyGen = new(); public ReportViewBLL( IReportViewDAL dal, AutoNumber autoNumber, IValidation validation, EventLogPublish eventLog, ILogger logger, IDALCache dalCache) { _dal = dal; _autoNumber = autoNumber; _validation = validation; _eventLog = eventLog; _logger = logger; _dalCache = dalCache; } // ── Existing picklist methods ───────────────────────────────────────── public async Task GetSelectListReportView(CriteriaDTO criteriaDTO, LoginDTO loginDTO, CancellationToken ct = default) { try { return await _dal.GetSelectListReportView(criteriaDTO, loginDTO, ct).ConfigureAwait(false); } catch (Exception) { throw; } } public async Task GetSelectListReportViewandFields(int FirstNumber, int MaxResult, CriteriaDTO CriteriaDTO, LoginDTO LoginDTO, CancellationToken ct = default) { try { return await _dal.GetSelectListReportViewandFields(FirstNumber, MaxResult, CriteriaDTO, LoginDTO, ct).ConfigureAwait(false); } catch (Exception) { throw; } } // ── Read methods ────────────────────────────────────────────────────── public async Task GetReportView(int reportViewId, LoginDTO login, CancellationToken ct) { try { return await _dal.GetReportView(reportViewId, login, ct).ConfigureAwait(false); } catch (Exception ex) { GB5Trace.MarkFailed("get-reportview-failed", ex); _logger.LogError(ex, "GetReportView failed for ReportViewId {Id}", reportViewId); throw; } } public async Task GetReportViewLite(int reportViewId, LoginDTO login, CancellationToken ct) { try { return await _dal.GetReportViewLite(reportViewId, login, ct).ConfigureAwait(false); } catch (Exception ex) { GB5Trace.MarkFailed("get-reportviewlite-failed", ex); _logger.LogError(ex, "GetReportViewLite failed for ReportViewId {Id}", reportViewId); throw; } } public async Task GetReportViewList(int reportId, LoginDTO login, CancellationToken ct) { try { return await _dal.GetReportViewList(reportId, login, ct).ConfigureAwait(false); } catch (Exception ex) { GB5Trace.MarkFailed("get-reportviewlist-failed", ex); _logger.LogError(ex, "GetReportViewList failed for ReportId {Id}", reportId); throw; } } public async Task GetReportViewPaged(int reportId, int offset, int pageSize, LoginDTO login, CancellationToken ct) { try { return await _dal.GetReportViewPaged(reportId, offset, pageSize, login, ct).ConfigureAwait(false); } catch (Exception ex) { GB5Trace.MarkFailed("get-reportviewpaged-failed", ex); _logger.LogError(ex, "GetReportViewPaged failed for ReportId {Id}", reportId); throw; } } public async Task GetReportViewByMenu(int reportId, int menuId, LoginDTO login, CancellationToken ct) { try { return await _dal.GetReportViewByMenu(reportId, menuId, login, ct).ConfigureAwait(false); } catch (Exception ex) { GB5Trace.MarkFailed("get-reportviewbymenu-failed", ex); _logger.LogError(ex, "GetReportViewByMenu failed for ReportId {ReportId} MenuId {MenuId}", reportId, menuId); throw; } } public async Task GetReportViewFieldsForView(int reportViewId, LoginDTO login, CancellationToken ct) { try { return await _dal.GetReportViewFieldsForView(reportViewId, login, ct).ConfigureAwait(false); } catch (Exception ex) { GB5Trace.MarkFailed("get-reportviewfields-failed", ex); _logger.LogError(ex, "GetReportViewFieldsForView failed for ReportViewId {Id}", reportViewId); throw; } } // ── Save ────────────────────────────────────────────────────────────── public async Task SaveReportView(ReportViewDTO dto, LoginDTO login, CancellationToken ct) { bool isNew = dto.ReportViewId == 0; int? allocatedId = null; try { GB5Trace.Step("validate-reportview", new { dto.ReportViewId }); await _validation.NotEmpty(dto.ReportViewName, nameof(dto.ReportViewName)).ConfigureAwait(false); //await _validation.MaxLength("MREPORTVIEW", "REPORTVIEWNAME", dto.ReportViewName).ConfigureAwait(false); if (!isNew) { var existing = await GetReportViewRaw(dto.ReportViewId, login, ct).ConfigureAwait(false); GuardSourceType(existing?.ReportViewSourceType, login.SourceType); } if (isNew) { var an = await _autoNumber.GetAutoNumber(1, "REPORTVIEW", login).ConfigureAwait(false); dto.ReportViewId = an.StartNumber; allocatedId = dto.ReportViewId; dto.CreatedById = login.UserId; dto.CreatedOn = DateTime.UtcNow; } dto.ModifiedById = login.UserId; dto.ModifiedOn = DateTime.UtcNow; GB5Trace.Step("save-reportview", new { dto.ReportViewId, isNew }); int savedId = await _dal.SaveReportView(dto, login, ct, isNew).ConfigureAwait(false); GB5Trace.Step("event-publish", new { EventTypeConstant.SAVEREPORTVIEWEVENTTYPEID }); await _eventLog.PublishEventLogAsync( "ReportView Saved", dto, EventTypeConstant.SAVEREPORTVIEWEVENTTYPEID, 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-reportview-failed", ex); _logger.LogError(ex, "SaveReportView failed for ReportViewId {Id}", dto.ReportViewId); if (isNew && allocatedId.HasValue) await _autoNumber.RollbackAutoNumber("REPORTVIEW", allocatedId.Value, login).ConfigureAwait(false); throw; } } public async Task SaveReportViewWithFields(ReportViewDTO dto, LoginDTO login, CancellationToken ct) { bool isNew = dto.ReportViewId == 0; int? allocatedId = null; try { GB5Trace.Step("validate-reportviewwithfields", new { dto.ReportViewId }); await _validation.NotEmpty(dto.ReportViewName, nameof(dto.ReportViewName)).ConfigureAwait(false); //await _validation.MaxLength("MREPORTVIEW", "REPORTVIEWNAME", dto.ReportViewName).ConfigureAwait(false); if (!isNew) { var existing = await GetReportViewRaw(dto.ReportViewId, login, ct).ConfigureAwait(false); GuardSourceType(existing?.ReportViewSourceType, login.SourceType); } if (isNew) { var an = await _autoNumber.GetAutoNumber(1, "REPORTVIEW", login).ConfigureAwait(false); dto.ReportViewId = an.StartNumber; allocatedId = dto.ReportViewId; dto.CreatedById = login.UserId; dto.CreatedOn = DateTime.UtcNow; } dto.ModifiedById = login.UserId; dto.ModifiedOn = DateTime.UtcNow; // Generate IDs for child records foreach (var field in dto.ReportViewFieldsDTOs) { if (field.ReportViewFieldsId == 0) { var fieldAutoNumber = await _autoNumber.GetAutoNumber(1, "REPORTVIEWFIELDS", login); field.ReportViewFieldsId = fieldAutoNumber.StartNumber; } field.ReportViewId = dto.ReportViewId; field.ReportId = dto.ReportId; } GB5Trace.Step("save-reportviewwithfields", new { dto.ReportViewId, isNew, fieldCount = dto.ReportViewFieldsDTOs.Count }); await _dal.SaveReportViewWithFields(dto, login, ct, isNew).ConfigureAwait(false); var rvKey = _keyGen.KeyGeneration(dto.ReportViewId, EntityConstant.OBJECTREPORTVIEW, CacheKeyLevel.CLIENT_LEVEL, login); await _dalCache.InvalidateAsync(rvKey, ct).ConfigureAwait(false); GB5Trace.Step("event-publish", new { EventTypeConstant.SAVEREPORTVIEWEVENTTYPEID }); await _eventLog.PublishEventLogAsync( "ReportView Saved With Fields", dto, EventTypeConstant.SAVEREPORTVIEWEVENTTYPEID, dto.ReportViewId, login, ct: ct).ConfigureAwait(false); return isNew ? $"{SuccessResponse.SaveSuccessMessage} {dto.ReportViewId}" : SuccessResponse.UpdateSuccess; } catch (ValidationException vex) { throw new Exception(vex.Message); } catch (Exception ex) { GB5Trace.MarkFailed("save-reportviewwithfields-failed", ex); _logger.LogError(ex, "SaveReportViewWithFields failed for ReportViewId {Id}", dto.ReportViewId); if (isNew && allocatedId.HasValue) await _autoNumber.RollbackAutoNumber("MREPORTVIEW", allocatedId.Value, login).ConfigureAwait(false); throw; } } // ── Delete ──────────────────────────────────────────────────────────── public async Task DeleteReportView(int reportViewId, LoginDTO login, CancellationToken ct) { try { GB5Trace.Step("delete-reportview", new { reportViewId }); var existing = await GetReportViewRaw(reportViewId, login, ct).ConfigureAwait(false); GuardSourceType(existing?.ReportViewSourceType, login.SourceType); await _dal.DeleteReportView(reportViewId, login, ct).ConfigureAwait(false); var rvKey = _keyGen.KeyGeneration(reportViewId, EntityConstant.OBJECTREPORTVIEW, CacheKeyLevel.CLIENT_LEVEL, login); await _dalCache.InvalidateAsync(rvKey, ct).ConfigureAwait(false); GB5Trace.Step("event-publish", new { EventTypeConstant.DELETEREPORTVIEWEVENTTYPEID }); await _eventLog.PublishEventLogAsync( "ReportView Deleted", new { ReportViewId = reportViewId }, EventTypeConstant.DELETEREPORTVIEWEVENTTYPEID, reportViewId, login, ct: ct).ConfigureAwait(false); return SuccessResponse.DeleteSuccessMessage; } catch (Exception ex) { GB5Trace.MarkFailed("delete-reportview-failed", ex); _logger.LogError(ex, "DeleteReportView failed for ReportViewId {Id}", reportViewId); throw; } } public async Task HardDeleteReportView(int reportViewId, LoginDTO login, CancellationToken ct) { try { GB5Trace.Step("harddelete-reportview", new { reportViewId }); var existing = await GetReportViewRaw(reportViewId, login, ct).ConfigureAwait(false); GuardSourceType(existing?.ReportViewSourceType, login.SourceType); await _dal.HardDeleteReportView(reportViewId, login, ct).ConfigureAwait(false); var rvKey = _keyGen.KeyGeneration(reportViewId, EntityConstant.OBJECTREPORTVIEW, CacheKeyLevel.CLIENT_LEVEL, login); await _dalCache.InvalidateAsync(rvKey, ct).ConfigureAwait(false); GB5Trace.Step("event-publish", new { EventTypeConstant.DELETEREPORTVIEWEVENTTYPEID }); await _eventLog.PublishEventLogAsync( "ReportView Hard Deleted", new { ReportViewId = reportViewId }, EventTypeConstant.DELETEREPORTVIEWEVENTTYPEID, reportViewId, login, ct: ct).ConfigureAwait(false); return SuccessResponse.DeleteSuccessMessage; } catch (Exception ex) { GB5Trace.MarkFailed("harddelete-reportview-failed", ex); _logger.LogError(ex, "HardDeleteReportView failed for ReportViewId {Id}", reportViewId); throw; } } // ── Private helpers ─────────────────────────────────────────────────── private async Task GetReportViewRaw(int reportViewId, LoginDTO login, CancellationToken ct) { try { string json = await _dal.GetReportView(reportViewId, login, ct).ConfigureAwait(false); return JsonConvert.DeserializeObject(json); } catch { return null; } } private static void GuardSourceType(byte? recordSourceType, int loginSourceType) { if (recordSourceType.HasValue && recordSourceType.Value < loginSourceType) throw new ValidationException("Insufficient privilege to modify this view."); } public async Task GetSelectListReportVsFormats(CriteriaDTO criteriaDTO, LoginDTO loginDTO) => await _dal.GetSelectListReportVsFormats(criteriaDTO, loginDTO); } }