MaterialRequirementGenerationService.cs 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. using Admin.NET.Plugin.AiDOP.Infrastructure;
  2. using Admin.NET.Plugin.AiDOP.Supply;
  3. namespace Admin.NET.Plugin.AiDOP.WorkOrder;
  4. /// <summary>
  5. /// 物料需求生成(MRP 入口,对接 S4 采购执行闭环)。
  6. ///
  7. /// 【租户安全边界】需认证访问(已移除类级 <c>[AllowAnonymous]</c>);租户一律经
  8. /// <c>AidopTenantScope.ResolveOrThrow</c> 从认证后 JWT 解析,无有效租户即拒绝,
  9. /// 不读前端 tenantId/domain 数字、无默认回退(原实现:类级匿名 + <c>ResolveTenantId(domain)</c>
  10. /// 信任前端直传的 domain 数字自选租户,否则回退宽松解析)。
  11. /// </summary>
  12. [ApiDescriptionSettings(Order = 261, Description = "物料需求生成")]
  13. [Route("api/WorkOrder")]
  14. [NonUnify]
  15. public class MaterialRequirementGenerationService : IDynamicApiController, ITransient
  16. {
  17. private readonly UserManager _userManager;
  18. private readonly ProcurementPipelineService _pipeline;
  19. private readonly AidopActionRunLogWriter _runLog;
  20. public MaterialRequirementGenerationService(
  21. UserManager userManager,
  22. ProcurementPipelineService pipeline,
  23. AidopActionRunLogWriter runLog)
  24. {
  25. _userManager = userManager;
  26. _pipeline = pipeline;
  27. _runLog = runLog;
  28. }
  29. /// <summary>同步/生成物料需求并执行采购闭环。</summary>
  30. [DisplayName("生成物料需求")]
  31. [HttpPost("material-requirement/generate")]
  32. public async Task<ProcurementPipelineResult> Generate([FromQuery] string domain)
  33. {
  34. var tenantId = ResolveTenantId(domain);
  35. var account = _userManager.Account ?? "system";
  36. var logId = await _runLog.StartAsync("S4_MRP_GENERATE", tenantId, "tenant", tenantId, domain ?? tenantId.ToString());
  37. try
  38. {
  39. var result = await _pipeline.ExecuteCoreAsync(tenantId, account, createFromShortage: true);
  40. await _runLog.SuccessAsync(logId, result.Message, result);
  41. return result;
  42. }
  43. catch (Exception ex)
  44. {
  45. await _runLog.FailedAsync(logId, ex.Message);
  46. throw Oops.Oh(ex.Message);
  47. }
  48. }
  49. private long ResolveTenantId(string? domain)
  50. {
  51. // 租户只信 JWT:不再从前端直传的 domain 数字解析(那是让调用方自选租户),
  52. // domain 仅作为公司域业务参数用于日志归档。
  53. return AidopTenantScope.ResolveOrThrow(_userManager);
  54. }
  55. }