using Admin.NET.Plugin.AiDOP.ProcurementExecution.Dto;
using Admin.NET.Plugin.AiDOP.ProcurementExecution.Entity;
using Yitter.IdGenerator;
namespace Admin.NET.Plugin.AiDOP.ProcurementExecution;
///
/// S4 供应商发货单(列表 + 表单)
///
/// 【租户安全边界】租户一律经 从认证后 JWT 解析,
/// 无有效租户即拒绝,不读前端 tenantId、无默认回退。
///
/// 原实现:类级 [AllowAnonymous] + 全类使用 AidopTenantHelper.Resolve(App.HttpContext)。
/// 后者的解析顺序为 requestTenantId > JWT claim > query 参数 tenantId > DefaultTenantId 兜底,
/// 其自身注释即写明「允许前端指定租户且有默认回退,不得用于业务数据的查询与写入」。
/// 两者叠加的实测后果:匿名(无 Token、无 Cookie)GET
/// /api/ProcurementExecution/supplier-shipment/list?tenantId=<任意租户> 可读回该租户业务数据
/// (797 返回 13 条、UAT 返回 2 条);同类的 HttpPost 写接口走同一条解析链。
///
///
/// 本类的写 SQL 一律带 tenant_id = @TenantId:业务键 shddh/shdh 在库中无唯一索引,
/// 一旦将来出现跨租户重复单号,仅按业务键定位会造成越权改写。
///
///
/// 生成标签的 INSERT INTO MissedPrint ... SELECT ... FROM scm_shbq 另有两处缺陷一并修复:
/// ① 未写 tenant_id,导致库中 152 行标签全部为 NULL、下游 008/013 无法按租户过滤;
/// ② LEFT JOIN ItemMaster ON ItemNum 未限定租户,而 ItemMaster 有 663 个 ItemNum 跨租户重名
/// ((tenant_id, ItemNum) 唯一、单独 ItemNum 不唯一),实测按现网 scm_shbq 数据:
/// 797 的 50 行会放大成 82 行、UAT 的 24 行会放大成 48 行,且 ExpireDate 可能取自其它租户的物料主数据。
/// 现补 i.tenant_id / p.tenant_id / s.tenant_id = @TenantId。
///
///
[ApiDescriptionSettings(Order = 321, Description = "S4供应商发货单")]
[Route("api/ProcurementExecution")]
[NonUnify]
public class SupplierShipmentService : IDynamicApiController, ITransient
{
private readonly ISqlSugarClient _db;
private readonly SqlSugarRepository _masterRep;
private readonly SqlSugarRepository _detailRep;
private readonly UserManager _userManager;
private readonly DataPlatform.Wms.PurOrdWmsPushService _purOrdWmsPush;
private const int ShpcSerialWidth = 3; // yyMMdd + 3位流水:260508001
private const int LabelXhStart = 10001;
public SupplierShipmentService(
ISqlSugarClient db,
SqlSugarRepository masterRep,
SqlSugarRepository detailRep,
UserManager userManager,
DataPlatform.Wms.PurOrdWmsPushService purOrdWmsPush)
{
_db = db;
_masterRep = masterRep;
_detailRep = detailRep;
_userManager = userManager;
_purOrdWmsPush = purOrdWmsPush;
}
[DisplayName("供应商发货单列表")]
[HttpGet("supplier-shipment/list")]
public async Task