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
});
}
}