using Dapr.Client; using FastEndpoints; using GB5Shared.DTO.Framework.Login; using GB5Shared.DTO.Framework.ResponseStandard; using GB5Shared.FastEndPoint; using MMDAL.DTO.MRPRun; using static GB5Shared.GB5Constant.Constant; namespace MMSL.EndPoints.MRPRun { // Triggers a scoped MRP run for a specific AllocationId, SalesOrderId, or list of FG items. // Validation rules (per plan Phase 3a): // Scope=Allocation → AllocationId required // Scope=SalesOrder → SalesOrderId required // Scope=FGItem → FGItemIds required (1 to 50 items) public class TriggerScopedMRPRun : BaseEndpoint> { private readonly DaprClient _DaprClient; public TriggerScopedMRPRun(DaprClient daprClient) => _DaprClient = daprClient; public override void Configure() { Post("/MRPRun/TriggerScopedMRPRun"); AllowAnonymous(); } public record Params( [property: FromHeader] string Login, [property: FromBody] MRPRunTriggerDTO Trigger ); protected override string? GetCacheKey(Params req, LoginDTO login) => null; protected override async Task> ExecuteAsync( Params req, LoginDTO loginDTO, CancellationToken ct) { try { var trigger = req.Trigger; ValidateScopedTrigger(trigger); trigger.WorkOUId = loginDTO.WorkOUId; trigger.TenantId = loginDTO.ClientId; trigger.UserId = loginDTO.UserId; trigger.IsCombined = false; await _DaprClient.PublishEventAsync("pubsub", "mrprun.trigger", trigger, ct); return await GB5Shared.ResponseStandard.Response.CreateSuccessResponse( $"Scoped MRP run ({trigger.RunScope}) queued successfully.", CacheKeyLevel.NOT_REQUIRED, loginDTO); } catch (Exception ex) { return await GB5Shared.ResponseStandard.Response.CreateExceptionError( ex, CacheKeyLevel.NOT_REQUIRED, loginDTO, ex.Message, 500); } } private static void ValidateScopedTrigger(MRPRunTriggerDTO trigger) { switch (trigger.RunScope) { case MrpRunScope.Macro: throw new ArgumentException( "Use TriggerMRPRun for macro (full) runs. " + "TriggerScopedMRPRun requires a specific scope."); case MrpRunScope.Allocation: if (!trigger.AllocationId.HasValue || trigger.AllocationId <= 0) throw new ArgumentException("AllocationId is required for Allocation scope."); break; case MrpRunScope.SalesOrder: if (!trigger.SalesOrderId.HasValue || trigger.SalesOrderId <= 0) throw new ArgumentException("SalesOrderId is required for SalesOrder scope."); break; case MrpRunScope.FGItem: if (trigger.FGItemIds is null || trigger.FGItemIds.Count == 0) throw new ArgumentException("FGItemIds is required for FGItem scope."); if (trigger.FGItemIds.Count > 50) throw new ArgumentException( "FGItem scope supports a maximum of 50 items per run."); break; } } } }