using System.Globalization;
using Admin.NET.Plugin.AiDOP.DataPlatform;
using Admin.NET.Plugin.AiDOP.DataPlatform.Wms;
using Admin.NET.Plugin.AiDOP.Infrastructure;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace Admin.NET.Plugin.AiDOP.WorkOrder;
///
/// 工单下达服务 🏭
/// 路由前缀:/api/WorkOrder/dispatch/...
///
/// 【租户安全边界】需认证访问(已移除类级 [AllowAnonymous]);租户一律经
/// AidopTenantScope.ResolveOrThrow 从认证后 JWT 解析,无有效租户即拒绝,
/// 不读前端 tenantId/domain、无默认回退(原实现:类级匿名 + 宽松解析 AidopTenantHelper.Resolve
/// 接受 query/Body 直传 tenantId,未认证方可指定任意租户取号与下达工单)。
///
[ApiDescriptionSettings(Order = 260, Description = "工单下达")]
[Route("api/WorkOrder")]
[NonUnify]
public class WorkOrderDispatchService : IDynamicApiController, ITransient
{
private readonly ISqlSugarClient _db;
private readonly UserManager _userManager;
private readonly WorkOrderKittingCheckService _kittingCheck;
private readonly IPickBillCreator _pickBillCreator;
private readonly AidopPickBillOptions _pickBillOpt;
private readonly MdpSourceScopeFactory _scopeFactory;
private readonly KeeperResolveService _keeper;
private readonly WorkOrdMesPushService _workOrdMesPush;
private readonly AidopActionRunLogWriter _runLog;
private readonly ILogger _logger;
/// 单次下达请求内的诊断上下文(写入 run_log.detail_json,不回传前端)。
private ReleaseDiagContext? _diag;
public WorkOrderDispatchService(
ISqlSugarClient db,
UserManager userManager,
WorkOrderKittingCheckService kittingCheck,
IPickBillCreator pickBillCreator,
IOptions pickBillOpt,
MdpSourceScopeFactory scopeFactory,
KeeperResolveService keeper,
WorkOrdMesPushService workOrdMesPush,
AidopActionRunLogWriter runLog,
ILogger logger)
{
_db = db;
_userManager = userManager;
_kittingCheck = kittingCheck;
_pickBillCreator = pickBillCreator;
_pickBillOpt = pickBillOpt.Value;
_scopeFactory = scopeFactory;
_keeper = keeper;
_workOrdMesPush = workOrdMesPush;
_runLog = runLog;
_logger = logger;
}
/// 租户只信认证后 JWT,不读前端 tenantId/domain,无默认回退。
private long ResolveTenantId() => AidopTenantScope.ResolveOrThrow(_userManager);
/// 校验:本租户下存在处于初始状态(p)的该工单。
private async Task AssertInitialWorkOrderExistsAsync(long tenantId, string workOrd)
{
var wo = workOrd.Trim();
var cnt = await _db.Ado.GetIntAsync(
"""
SELECT COUNT(*) FROM WorkOrdMaster
WHERE tenant_id = @TenantId
AND WorkOrd = @WorkOrd
AND LOWER(TRIM(IFNULL(Status,''))) = 'p'
""",
new SugarParameter("@TenantId", tenantId),
new SugarParameter("@WorkOrd", wo));
if (cnt == 0)
throw Oops.Oh("未找到处于初始状态(p)的本租户工单,请确认工单号与租户是否正确");
}
// ══════════════════════════════════════════════════════════════
// 列表 GET /api/WorkOrder/dispatch/list
// ══════════════════════════════════════════════════════════════
/// 获取工单下达分页列表 🏭
[DisplayName("获取工单下达列表")]
[HttpGet("dispatch/list")]
public async Task