using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; namespace Admin.NET.Plugin.AiDOP.MaterialWarehouse; /// 库存冷链手工补偿入口(管理员)。不接受前端 tenantId/domain/entityCode。 [ApiDescriptionSettings(Order = 310, Description = "S5库存冷链入站")] [Route("api/S5InventoryInbound")] [NonUnify] public sealed class InventoryInboundAdminService : IDynamicApiController, ITransient { private readonly InventoryMdpSyncService _sync; private readonly InventoryReconService _recon; private readonly ILogger _logger; public InventoryInboundAdminService( InventoryMdpSyncService sync, InventoryReconService recon, ILoggerFactory loggerFactory) { _sync = sync; _recon = recon; _logger = loggerFactory.CreateLogger(nameof(InventoryInboundAdminService)); } [DisplayName("库存冷链首刷")] [HttpPost("bootstrap")] [ApiDescriptionSettings(Name = "S5InventoryBootstrap")] public async Task Bootstrap(CancellationToken ct) { _logger.LogInformation("[S5InventoryInbound] bootstrap requested"); return await _sync.RunBootstrapAsync(ct); } [DisplayName("库存冷链跑一轮")] [HttpPost("run-once")] [ApiDescriptionSettings(Name = "S5InventoryRunOnce")] public async Task RunOnce(CancellationToken ct) { _logger.LogInformation("[S5InventoryInbound] run-once requested"); return await _sync.RunIncrementalAsync(ct); } [DisplayName("库存冷链全量校准")] [HttpPost("reconcile")] [ApiDescriptionSettings(Name = "S5InventoryReconcile")] public async Task Reconcile(CancellationToken ct) { _logger.LogInformation("[S5InventoryInbound] reconcile requested"); return await _sync.RunReconcileFullAsync(ct); } [DisplayName("库存流水 stg→std 补转换")] [HttpPost("transform-std")] [ApiDescriptionSettings(Name = "S5InventoryTransformStd")] public async Task TransformStd(CancellationToken ct) { _logger.LogInformation("[S5InventoryInbound] transform-std requested"); return await _sync.TransformTransStdFromStgAsync(ct); } /// /// 库存余额 stg→std 补物化:复用已完整落地的贴源批次,不访问源库。 /// UPSERT 语义,不删除既有标准层数据。 /// [DisplayName("库存余额 stg→std 补物化")] [HttpPost("transform-inventory-std")] [ApiDescriptionSettings(Name = "S5InventoryTransformInventoryStd")] public async Task TransformInventoryStd([FromQuery] string batchId, CancellationToken ct) { _logger.LogInformation("[S5InventoryInbound] transform-inventory-std requested batch={Batch}", batchId); return await _sync.TransformInventoryStdFromStgAsync(batchId, ct); } [DisplayName("库存日终对账(手工)")] [HttpPost("daily-recon")] [ApiDescriptionSettings(Name = "S5InventoryDailyRecon")] public async Task DailyRecon(CancellationToken ct) { _logger.LogInformation("[S5InventoryInbound] daily-recon requested"); var diffs = await _recon.RunDailyReconAsync(ct); return new { diffs, message = diffs == 0 ? "clean" : "diffs written" }; } }