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 ISqlSugarClient _db;
private readonly ILogger _logger;
public InventoryInboundAdminService(
InventoryMdpSyncService sync,
InventoryReconService recon,
ISqlSugarClient db,
ILoggerFactory loggerFactory)
{
_sync = sync;
_recon = recon;
_db = db;
_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);
}
///
/// 日终对账与 bootstrap / reconcile / transform 共享同一互斥闸门:
/// 对账读 mdp_std_inventory 并写差异,跑批期间的中间态会产生假差异,必须排他。
/// 锁在本入口而不是 InventoryReconService 内部,避免与 InventoryMdpSyncService 的自锁重入。
///
[DisplayName("库存日终对账(手工)")]
[HttpPost("daily-recon")]
[ApiDescriptionSettings(Name = "S5InventoryDailyRecon")]
public async Task