using FastEndpoints; using GB5Shared.DTO.Framework.Criteria; using GB5Shared.DTO.Framework.Login; using GB5Shared.DTO.Framework.ResponseStandard; using GB5Shared.FastEndPoint; using PayRollBLL.Periodic; using System.IO; using static GB5Shared.GB5Constant.Constant; namespace PayRollSL.EndPoints.Periodic { // GB4: Periodic.svc/Periodic/Service/Based/Export — IPeriodic.cs WebInvoke attribute: // [OperationContract(Name = "PeriodicServiceBasedExport")] // UriTemplate = "/Periodic/Service/Based/Export/?PayPeriodId={PayPeriodId}", Method = "POST" // → Periodic.svc.cs delegates to a SEPARATE class, DumpPerodicServiceBased (not PeriodicBLL). // Called with BOTH real PayPeriodIds and a -1 sentinel by different GB4 callers — same // operation both times, no branching here; -1 only matters at the SQL/data level (see // PeriodicQB.BuildPeriodicServiceBasedExport's GB4-parity note: there is no -1 wildcard // bypass in GB4's underlying query, so a genuine MPAYPERIOD row with PAYPERIODID=-1 must // exist in this database for the -1 case to return any data — a pre-existing data // dependency, not something introduced or fixed by this migration). // // GB4 returned Base64-encoded .xlsx bytes as a JSON string body (it wrote the file to disk // first, purely as an artifact of returning a "file" through a WCF string). GB5 modernizes // this to a real binary file-download response — see PeriodicBLL.PeriodicServiceBasedExport // for the full note — following the same HttpContext.Response.SendStreamAsync precedent // already established by TMSSL.EndPoints.Certificate.DownloadCertificate (BaseEndpoint's // ExecuteAsync contract is fixed to ResponseStandardDTO, so binary downloads write // directly to the response and return null!, rather than returning IResult). public class PeriodicServiceBasedExport : BaseEndpoint> { private readonly IPeriodicBLL _PeriodicBLL; public PeriodicServiceBasedExport(IPeriodicBLL PeriodicBLL) { _PeriodicBLL = PeriodicBLL; } public override void Configure() { Post("/Periodic/Service/Based/Export"); AllowAnonymous(); } public record Parameters( [property: FromHeader] string Login, [property: FromBody] CriteriaDTO CriteriaDTO, [property: QueryParam] int PayPeriodId ); // Binary export — never cached (matches every other Export* endpoint convention). protected override string? GetCacheKey(Parameters req, LoginDTO login) => null; protected override async Task> ExecuteAsync( Parameters req, LoginDTO loginDTO, CancellationToken ct) { using var ms = new MemoryStream(); try { await _PeriodicBLL.PeriodicServiceBasedExport(req.PayPeriodId, req.CriteriaDTO, loginDTO, ms, ct); } catch (Exception ex) { return await GB5Shared.ResponseStandard.Response.CreateExceptionError( ex, CacheKeyLevel.NOT_REQUIRED, loginDTO, ex.Message, 500); } // ── Stream — no more error returns after this point ───────────────────────── ms.Position = 0; string fileName = $"PeriodicServiceBased_{DateTime.UtcNow:yyyyMMddHHmmss}.xlsx"; const string contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; await HttpContext.Response.SendStreamAsync(ms, fileName, ms.Length, contentType, cancellation: ct); return null!; } } }