using AccountsBLL.AccountReports.AccountProfitLossDashboard; using AccountsBLL.AccountReports; using AccountsDAL.DTO.AccountsReports; using FastEndpoints; using GB5Shared.DTO.Framework.Login; using GB5Shared.DTO.Report; using GB5Shared.FastEndPoint; namespace AccountsSL.EndPoints.AccountReports { // Profit & Loss Dashboard — legacy's "ProfitAndLossForDashboard" (AccountsReports.svc), reading // from the already-posted FFINANCE fact table for a period-bucketed waterfall view. See the // plan file's "Finance Dashboard Migration" section. Single-consolidated-object response // (Items + Totals), same pattern as AccountCashFlowIndirectReport/AccountRatioAnalysisReport — // the default ExecutePagedAsync is overridden since this is a small, bounded result, not a // real paged list. public class AccountProfitLossDashboardReport : BaseReportEndpoint { private readonly IAccountProfitLossDashboardBLL _bll; public AccountProfitLossDashboardReport(IAccountProfitLossDashboardBLL bll) { _bll = bll; } public override void Configure() { Post("/AccountReports/AccountProfitLossDashboardReport"); AllowAnonymous(); } public record AccountProfitLossDashboardReportParameter( [property: FromHeader] string Login, [property: FromBody] ReportCallingDTO ReportCallingDTO ); // Legacy's own PeriodType enum for this dashboard (0=Total,1=Daily,2=Weekly,3=Monthly, // 4=Quarterly,5=Yearly,6=FinancialQuarter,7=FinancialYear) is DELIBERATELY kept separate // from AccountReportCriteria.PeriodType (the MGBPERIOD-based periodic-resolution field used // by Trial Balance Phase 3, default 10=FN-Monthly) — the two are different enums with // different value semantics, so this dashboard reads its own "DashboardPeriodType" // criteria field directly rather than overloading the shared one. private static byte ParseDashboardPeriodType(GB5Shared.DTO.Framework.Criteria.CriteriaDTO? criteriaDTO) { if (criteriaDTO?.SectionCriteriaList == null) return 0; foreach (var section in criteriaDTO.SectionCriteriaList) { if (section.AttributesCriteriaList == null) continue; foreach (var attr in section.AttributesCriteriaList) { if (attr.FieldName?.ToLowerInvariant() == "dashboardperiodtype" && byte.TryParse(attr.FieldValue?.ToString(), out var value)) return value; } } return 0; } protected override async IAsyncEnumerable ExecuteReportAsync( AccountProfitLossDashboardReportParameter req, LoginDTO login, [System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken ct) { var criteria = AccountReportCriteriaParser.Parse(req.ReportCallingDTO.CriteriaDTO, login); var ouIds = criteria.OUIds is { Count: > 0 } ? criteria.OUIds : null; var periodType = ParseDashboardPeriodType(req.ReportCallingDTO.CriteriaDTO); var result = await _bll.GetProfitLossDashboard( criteria.PeriodFromDate, criteria.PeriodToDate, periodType, ouIds, criteria.OUGroupId, login, ct).ConfigureAwait(false); foreach (var row in result.Items) { ct.ThrowIfCancellationRequested(); yield return row; } } protected override async Task> ExecutePagedAsync( AccountProfitLossDashboardReportParameter req, LoginDTO login, CancellationToken ct) { try { var criteria = AccountReportCriteriaParser.Parse(req.ReportCallingDTO.CriteriaDTO, login); var ouIds = criteria.OUIds is { Count: > 0 } ? criteria.OUIds : null; var periodType = ParseDashboardPeriodType(req.ReportCallingDTO.CriteriaDTO); var result = await _bll.GetProfitLossDashboard( criteria.PeriodFromDate, criteria.PeriodToDate, periodType, ouIds, criteria.OUGroupId, login, ct).ConfigureAwait(false); return await GB5Shared.ResponseStandard.Response.CreateSuccessResponse( result, GB5Shared.GB5Constant.Constant.CacheKeyLevel.NOT_REQUIRED, login); } catch (Exception ex) { return await GB5Shared.ResponseStandard.Response.CreateExceptionError( ex, GB5Shared.GB5Constant.Constant.CacheKeyLevel.NOT_REQUIRED, login, ex.Message, 500); } } } }