IqcReturnQueryService.cs 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. using Admin.NET.Plugin.AiDOP.ProcurementExecution.Dto;
  2. namespace Admin.NET.Plugin.AiDOP.ProcurementExecution;
  3. /// <summary>
  4. /// S4 IQC 退货查询(只读列表)。数据:qms_qcp_insappnentry + qms_qcp_inspecapplyn + qms_qcp_inspbill,可选 PurOrdDetail / SuppMaster。
  5. /// 路由:/api/ProcurementExecution/iqc-return/list
  6. ///
  7. /// 【租户安全边界】租户一律经 <see cref="AidopTenantScope.ResolveOrThrow"/> 从认证后 JWT 解析,
  8. /// 无有效租户即拒绝,不读前端 tenantId、无默认回退。
  9. /// <para>
  10. /// 原实现:类级 <c>[AllowAnonymous]</c> + <c>AidopTenantHelper.Resolve(App.HttpContext)</c>
  11. /// (解析链含 query 参数 tenantId 与 DefaultTenantId 兜底),匿名携带 <c>?tenantId=&lt;任意租户&gt;</c> 可读回该租户 IQC 退货数据。
  12. /// </para>
  13. /// </summary>
  14. [ApiDescriptionSettings(Order = 322, Description = "S4 IQC退货查询")]
  15. [Route("api/ProcurementExecution")]
  16. [NonUnify]
  17. public class IqcReturnQueryService : IDynamicApiController, ITransient
  18. {
  19. private readonly ISqlSugarClient _db;
  20. private readonly UserManager _userManager;
  21. public IqcReturnQueryService(ISqlSugarClient db, UserManager userManager) { _db = db; _userManager = userManager; }
  22. /// <summary>
  23. /// 退货相关处理方式:NULL 视作 0;与 aidopdev 中 clfs 枚举一致时可再收紧为仅 clfs=3。
  24. /// </summary>
  25. private const string ReturnClfsPredicate = "(IFNULL(a.clfs, 0) IN (0, 3))";
  26. private static string NormalizeOrderBy(string field, string order)
  27. {
  28. var col = (field ?? "").Trim().ToLowerInvariant();
  29. var ord = string.Equals(order?.Trim(), "desc", StringComparison.OrdinalIgnoreCase) ? "DESC" : "ASC";
  30. var map = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
  31. {
  32. ["fbillno"] = "t.FBillNo",
  33. ["ordnbr"] = "t.OrdNbr",
  34. ["pch"] = "t.Pch",
  35. ["fmaterialcfg"] = "t.FMaterialCfg",
  36. ["sortname"] = "t.SortName",
  37. ["supp"] = "t.Supp",
  38. ["gysmc"] = "t.Gysmc",
  39. ["wlmc"] = "t.Wlmc",
  40. ["ggxh"] = "t.Ggxh",
  41. ["frinsqty"] = "t.FrInsQty",
  42. ["bhgsl"] = "t.Bhgsl",
  43. ["clfs"] = "t.Clfs",
  44. ["finspectstatus"] = "t.FInspectStatus",
  45. ["fapplytime"] = "t.FApplyTime",
  46. ["finspeenddate"] = "t.FInspeEndDate",
  47. };
  48. if (!map.TryGetValue(col, out var sqlCol))
  49. return "ORDER BY t.FApplyTime DESC, t.EntryId ASC";
  50. return $"ORDER BY {sqlCol} {ord}, t.EntryId ASC";
  51. }
  52. [DisplayName("IQC退货查询分页列表")]
  53. [HttpGet("iqc-return/list")]
  54. public async Task<object> GetList([FromQuery] IqcReturnListInput input)
  55. {
  56. var page = input.Page <= 0 ? 1 : input.Page;
  57. var pageSize = input.PageSize <= 0 ? 10 : input.PageSize;
  58. var offset = (page - 1) * pageSize;
  59. var tenantId = AidopTenantScope.ResolveOrThrow(_userManager);
  60. var cond = new List<string> { ReturnClfsPredicate };
  61. var pars = new List<SugarParameter>();
  62. var hasTenantColumn = await _db.Ado.GetIntAsync("""
  63. SELECT COUNT(1)
  64. FROM information_schema.COLUMNS
  65. WHERE TABLE_SCHEMA = DATABASE()
  66. AND TABLE_NAME = 'qms_qcp_insappnentry'
  67. AND COLUMN_NAME = 'tenant_id'
  68. """) > 0;
  69. if (hasTenantColumn)
  70. {
  71. // WP0-D4:申请明细/主表/检验单同租户
  72. cond.Add("c.tenant_id = @TenantId");
  73. cond.Add("b.tenant_id = @TenantId");
  74. cond.Add("(a.id IS NULL OR a.tenant_id = @TenantId)");
  75. pars.Add(new("@TenantId", tenantId));
  76. }
  77. if (!string.IsNullOrWhiteSpace(input.OrdNbr))
  78. {
  79. cond.Add("(TRIM(IFNULL(c.FSRCORDERNUM,'')) LIKE @OrdNbr OR TRIM(IFNULL(pod.PurOrd,'')) LIKE @OrdNbr)");
  80. pars.Add(new SugarParameter("@OrdNbr", $"%{input.OrdNbr.Trim()}%"));
  81. }
  82. if (!string.IsNullOrWhiteSpace(input.Pch))
  83. {
  84. cond.Add("TRIM(IFNULL(COALESCE(a.pch, c.FLOTNUMBER, ''),'')) LIKE @Pch");
  85. pars.Add(new SugarParameter("@Pch", $"%{input.Pch.Trim()}%"));
  86. }
  87. if (!string.IsNullOrWhiteSpace(input.FMaterialCfg))
  88. {
  89. cond.Add("TRIM(IFNULL(COALESCE(c.FMATERIALCFG, a.FMATERIALCFG, pod.ItemNum),'')) = TRIM(@FMat)");
  90. pars.Add(new SugarParameter("@FMat", input.FMaterialCfg.Trim()));
  91. }
  92. if (!string.IsNullOrWhiteSpace(input.SortName))
  93. {
  94. cond.Add("""
  95. (
  96. EXISTS (
  97. SELECT 1 FROM SuppMaster s
  98. WHERE TRIM(IFNULL(c.FSUPPLIER,'')) <> ''
  99. AND s.Supp = TRIM(IFNULL(c.FSUPPLIER,''))
  100. AND (pod.Domain IS NULL OR s.Domain = pod.Domain)
  101. AND TRIM(IFNULL(s.SortName,'')) LIKE @SortName
  102. LIMIT 1
  103. )
  104. OR TRIM(IFNULL(COALESCE(c.gysmc, a.gysmc, ''),'')) LIKE @SortName
  105. )
  106. """);
  107. pars.Add(new SugarParameter("@SortName", $"%{input.SortName.Trim()}%"));
  108. }
  109. var where = string.Join(" AND ", cond);
  110. var baseSql = $"""
  111. SELECT
  112. CAST(c.id AS CHAR(32)) AS RowKey,
  113. c.id AS EntryId,
  114. TRIM(IFNULL(
  115. NULLIF(TRIM(CAST(IFNULL(b.FBILLNO,'') AS CHAR(512))), ''),
  116. TRIM(IFNULL(a.FBILLNO,''))
  117. )) AS FBillNo,
  118. TRIM(IFNULL(c.FSRCORDERNUM,'')) AS OrdNbr,
  119. TRIM(IFNULL(COALESCE(a.pch, c.FLOTNUMBER, ''),'')) AS Pch,
  120. TRIM(IFNULL(COALESCE(c.FMATERIALCFG, a.FMATERIALCFG, pod.ItemNum),'')) AS FMaterialCfg,
  121. (SELECT TRIM(IFNULL(s.SortName,''))
  122. FROM SuppMaster s
  123. WHERE TRIM(IFNULL(c.FSUPPLIER,'')) <> ''
  124. AND s.Supp = TRIM(IFNULL(c.FSUPPLIER,''))
  125. AND (pod.Domain IS NULL OR s.Domain = pod.Domain)
  126. LIMIT 1) AS SortName,
  127. TRIM(IFNULL(c.FSUPPLIER,'')) AS Supp,
  128. TRIM(IFNULL(COALESCE(c.gysmc, a.gysmc, ''),'')) AS Gysmc,
  129. TRIM(IFNULL(COALESCE(c.wlmc, a.wlmc, ''),'')) AS Wlmc,
  130. TRIM(IFNULL(COALESCE(c.ggxh, a.ggxh, ''),'')) AS Ggxh,
  131. CAST(IFNULL(a.FRINSQTY, 0) AS DECIMAL(18,4)) AS FrInsQty,
  132. CAST(IFNULL(a.bhgsl, 0) AS DECIMAL(18,4)) AS Bhgsl,
  133. a.clfs AS Clfs,
  134. TRIM(IFNULL(a.thyy,'')) AS Thyy,
  135. TRIM(IFNULL(c.FINSPECTSTATUS,'')) AS FInspectStatus,
  136. b.FAPPLYTIME AS FApplyTime,
  137. a.FINSPEENDDATE AS FInspeEndDate
  138. FROM qms_qcp_insappnentry c
  139. INNER JOIN qms_qcp_inspecapplyn b ON b.id = c.glid
  140. LEFT JOIN qms_qcp_inspbill a
  141. ON BINARY TRIM(IFNULL(a.lydjbh,'')) = BINARY TRIM(CAST(IFNULL(b.FBILLNO,'') AS CHAR(512)))
  142. LEFT JOIN PurOrdDetail pod
  143. ON TRIM(IFNULL(c.FSRCORDERNUM,'')) <> ''
  144. AND pod.PurOrd = TRIM(IFNULL(c.FSRCORDERNUM,''))
  145. AND TRIM(IFNULL(c.FSRCBILLENTRYSEQ,'')) <> ''
  146. AND CAST(pod.Line AS CHAR(32)) = TRIM(IFNULL(c.FSRCBILLENTRYSEQ,''))
  147. WHERE {where}
  148. """;
  149. var orderBy = NormalizeOrderBy(input.SortField, input.SortOrder);
  150. var total = await _db.Ado.GetIntAsync($"SELECT COUNT(1) FROM ({baseSql}) t", pars);
  151. var list = await _db.Ado.SqlQueryAsync<IqcReturnListRow>(
  152. $"SELECT * FROM ({baseSql}) t {orderBy} LIMIT {pageSize} OFFSET {offset}", pars);
  153. return new { total, page, pageSize, list };
  154. }
  155. }