using FastEndpoints; using GB5Shared.DTO.Framework.Criteria; using GB5Shared.DTO.Framework.Login; using GB5Shared.DTO.Framework.ResponseStandard; using GB5Shared.FastEndPoint; using MMBLL.Production; using System.Globalization; using System.Text.Json; using static GB5Shared.GB5Constant.Constant; namespace MMSL.EndPoints.Production.Reports; /// /// GB4-compatible Work Order Register report endpoint. /// The posted body is the ReportCallingDTO envelope used by the common report UI. /// public sealed class WorkOrderRegister : BaseEndpoint> { private readonly IProductionReportBLL _bll; public WorkOrderRegister(IProductionReportBLL bll) => _bll = bll; public override void Configure() { Post("/Production/WorkOrderRegister"); AllowAnonymous(); } public record Parameters( [property: FromHeader] string Login, // JsonElement deliberately accepts the legacy report-shell object's normal form as // well as the one-element array form emitted by some GB4/Postman integrations. [property: FromBody] JsonElement ReportCallingDTO, [property: QueryParam] int Type, [property: QueryParam] int FirstNumber = 1, [property: QueryParam] int MaxResult = 50); protected override async Task> ExecuteAsync( Parameters req, LoginDTO login, CancellationToken ct) { try { if (req.Type != 0) throw new NotSupportedException($"WorkOrderRegister Type {req.Type} is not supported. Only Type=0 is available."); var criteria = ReadCriteria(GetCriteria(req.ReportCallingDTO)); var rows = await _bll.GetWorkOrderRegister( criteria.OUId, criteria.FromDate, criteria.ToDate, criteria.BizTransactionClassIds, login, ct) .ConfigureAwait(false); var first = Math.Max(1, req.FirstNumber); var pageSize = req.MaxResult <= 0 ? 50 : req.MaxResult; var page = rows.Skip(first - 1).Take(pageSize).ToList(); var response = await GB5Shared.ResponseStandard.Response.CreateSuccessResponse( page, CacheKeyLevel.NOT_REQUIRED, login); response.Total = rows.Count; return response; } catch (Exception ex) { return await GB5Shared.ResponseStandard.Response.CreateExceptionError( ex, CacheKeyLevel.NOT_REQUIRED, login, ex.Message, 500); } } private static (int OUId, DateTime FromDate, DateTime ToDate, IReadOnlyCollection BizTransactionClassIds) ReadCriteria(CriteriaDTO? criteria) { var values = criteria?.SectionCriteriaList? .Where(s => s?.AttributesCriteriaList != null) .SelectMany(s => s!.AttributesCriteriaList!) .ToDictionary(a => a.FieldName ?? a.CriteriaAttributeName ?? string.Empty, a => Convert.ToString(a.FieldValue, CultureInfo.InvariantCulture) ?? string.Empty, StringComparer.OrdinalIgnoreCase) ?? new Dictionary(StringComparer.OrdinalIgnoreCase); if (!values.TryGetValue("OUId", out var ouText) || !int.TryParse(ouText, out var ouId)) throw new ArgumentException("CriteriaDTO must contain a valid OUId."); if (!values.TryGetValue("PeriodFromDate", out var fromText) || !DateTime.TryParse(fromText, CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out var fromDate)) throw new ArgumentException("CriteriaDTO must contain a valid PeriodFromDate."); if (!values.TryGetValue("PeriodToDate", out var toText) || !DateTime.TryParse(toText, CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out var toDate)) throw new ArgumentException("CriteriaDTO must contain a valid PeriodToDate."); var classes = values.TryGetValue("BIZTransactionClassId", out var classText) ? classText.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) .Select(value => int.TryParse(value, out var id) ? (int?)id : null) .Where(id => id.HasValue).Select(id => id!.Value).Distinct().ToArray() : Array.Empty(); return (ouId, fromDate, toDate, classes); } private static CriteriaDTO? GetCriteria(JsonElement requestBody) { // Expected body: { "CriteriaDTO": { ... } }. Also support // { "ReportCallingDTO": { "CriteriaDTO": { ... } } } and [ { ... } ] so an // integration-side wrapping difference does not fail before report validation. var body = requestBody; if (body.ValueKind == JsonValueKind.Array) { if (body.GetArrayLength() != 1) throw new ArgumentException("The request array must contain exactly one report object."); body = body[0]; } if (body.ValueKind != JsonValueKind.Object) throw new ArgumentException("The request body must be a report JSON object."); if (body.TryGetProperty("ReportCallingDTO", out var envelope)) body = envelope; if (!body.TryGetProperty("CriteriaDTO", out var criteria)) throw new ArgumentException("The request body must contain CriteriaDTO."); return JsonSerializer.Deserialize(criteria.GetRawText(), new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); } }