using FastEndpoints; using GB5Shared.DTO.Framework.Login; using GB5Shared.DTO.Framework.ResponseStandard; using GB5Shared.FastEndPoint; using QMSBLL.Matrix; using static GB5Shared.GB5Constant.Constant; namespace QMSSL.EndPoints.Matrix { public class SaveSetSerialGenration : BaseEndpoint> { private readonly IMatrixBLL _bll; public SaveSetSerialGenration(IMatrixBLL bll) => _bll = bll; public override void Configure() { Post("/Matrix/SaveSetSerialGenration"); AllowAnonymous(); Description(x => x .WithTags("Matrix") .WithSummary("Save Set & Serial Generation") .WithDescription("Matrix-independent SAVE: persists the same per-item, per-set serials " + "shown by GenerateMatrixLots into TLOT and TLOTDETAIL only — does not touch TMATRIX, " + "TMATRIXINPUT, or TMATRIXOUTPUT. Caller passes AllotedAllocationId (e.g. from " + "GetSelectListAllocationWithItem) instead of MatrixId. SetsToGenerate controls how many " + "sets to save (0 = all remaining ungenerated sets). SelectedSerials (optional) lets the " + "caller deselect specific serial tiles shown in the FG View before saving — key is the " + "FG item's ItemId, value is the list of RunningNumbers to actually keep/issue for that " + "item this run; the count must exactly equal QtyPerSet × SetsToGenerate for that item. " + "Any generated number NOT in the list for an item that HAS an entry is still written (so " + "the sequence never reissues it) but marked skipped/available instead of issued, and can " + "be picked up later via GetSkippedSerials. Omit an ItemId entirely (or omit " + "SelectedSerials) to keep the old all-generated-numbers-issued behavior. " + "Irreversible — call GenerateMatrixLots first to review before calling this.")); } public record RequestBody( int AllotedAllocationId, int SetsToGenerate, Dictionary>? SelectedSerials = null); public record Params( [property: FromHeader] string Login, [property: FromBody] RequestBody Body); protected override string? GetCacheKey(Params req, LoginDTO login) => null; protected override async Task> ExecuteAsync( Params req, LoginDTO login, CancellationToken ct) { try { var result = await _bll.SaveSetSerialGenerationAsync( req.Body.AllotedAllocationId, req.Body.SetsToGenerate, login, ct, req.Body.SelectedSerials); return await GB5Shared.ResponseStandard.Response .CreateSuccessResponse(result, CacheKeyLevel.NOT_REQUIRED, login); } catch (InvalidOperationException ex) { // Includes the "please retry" message for a concurrent-save collision // (see SaveSetSerialGenerationAsync) — a caller input/timing problem, // not a server fault, so 400 not 500. return await GB5Shared.ResponseStandard.Response .CreateExceptionError(ex, CacheKeyLevel.NOT_REQUIRED, login, ex.Message, 400); } catch (Exception ex) { return await GB5Shared.ResponseStandard.Response .CreateExceptionError(ex, CacheKeyLevel.NOT_REQUIRED, login, ex.Message, 500); } } } }