IqcInspBillService.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. using Admin.NET.Plugin.AiDOP.MaterialWarehouse.Dto;
  2. namespace Admin.NET.Plugin.AiDOP.MaterialWarehouse;
  3. /// <summary>
  4. /// S5 来料检验单(qms_qcp_inspbill)只读 list 服务 —— 来料检验流程主入口。
  5. ///
  6. /// 数据源:aidopdev.qms_qcp_inspbill 单表直读(不 join 申请主表/明细/SuppMaster/ApprovalFlow/SQE)。
  7. /// 口径:检验单号=FBILLNO;来源单号=lydjbh;物料=FMATERIALCFG/wlmc/ggxh;供应商=gysmc(内嵌);
  8. /// 批次=pch;数量=FRINSQTY/jysl/dhsl/bhgsl;判定=pd(raw);处理方式=clfs(raw);状态=FBILLSTATUS(raw);
  9. /// 检验员=FINSPECTORID;检验起止=FINSPESTARTDATE/FINSPEENDDATE;创建=FCREATETIME。默认排序 FCREATETIME DESC, id DESC。
  10. ///
  11. /// tenant/组织:qms_qcp_inspbill **无 tenant_id**,不做租户过滤;FORGID 当前全 NULL,不做 FORGID 过滤。
  12. /// TenantId/ForgId 接收即忽略。本服务仅 SELECT:无新增/编辑/删除/详情/判定录入/主管审核/SQE 处置/仓储通知/
  13. /// 库存事务/流程实例;不写 qms_qcp_inspbill、不改 FBIZTYPE、不碰 ApprovalFlow。pd/clfs/FBILLSTATUS 字典未闭合,raw 展示。
  14. /// </summary>
  15. [ApiDescriptionSettings(Order = 309, Description = "来料检验单列表")]
  16. [Route("api/S5IqcInspBill")]
  17. [AllowAnonymous]
  18. [NonUnify]
  19. public class IqcInspBillService : IDynamicApiController, ITransient
  20. {
  21. private readonly ISqlSugarClient _db;
  22. public IqcInspBillService(ISqlSugarClient db)
  23. {
  24. _db = db;
  25. }
  26. /// <summary>排序字段白名单(前端 prop → 物理列),杜绝 orderBy 注入。</summary>
  27. private static readonly Dictionary<string, string> OrderByWhitelist = new(StringComparer.OrdinalIgnoreCase)
  28. {
  29. ["billNo"] = "ib.FBILLNO",
  30. ["sourceBillNo"] = "ib.lydjbh",
  31. ["materialCode"] = "ib.FMATERIALCFG",
  32. ["materialName"] = "ib.wlmc",
  33. ["supplierName"] = "ib.gysmc",
  34. ["lotNo"] = "ib.pch",
  35. ["billStatus"] = "ib.FBILLSTATUS",
  36. ["judgement"] = "ib.pd",
  37. ["inspectDate"] = "ib.FINSPESTARTDATE",
  38. ["createTime"] = "ib.FCREATETIME",
  39. };
  40. /// <summary>
  41. /// 来料检验单列表(只读分页查询)。
  42. /// </summary>
  43. [DisplayName("来料检验单列表")]
  44. [HttpGet("list")]
  45. public async Task<object> GetList([FromQuery] IqcInspBillListInput input)
  46. {
  47. var page = input.Page <= 0 ? 1 : input.Page;
  48. var pageSize = input.PageSize <= 0 ? 20 : (input.PageSize > 200 ? 200 : input.PageSize);
  49. var offset = (page - 1) * pageSize;
  50. // qms_qcp_inspbill 无 tenant_id、FORGID 全 NULL:不做租户/组织过滤(TenantId/ForgId 接收即忽略)。
  51. var where = new List<string> { "1=1" };
  52. var pars = new List<SugarParameter>();
  53. void AddLike(string? v, string col, string p)
  54. {
  55. if (string.IsNullOrWhiteSpace(v)) return;
  56. where.Add($"{col} LIKE @{p}");
  57. pars.Add(new SugarParameter($"@{p}", $"%{v.Trim()}%"));
  58. }
  59. AddLike(input.BillNo, "ib.FBILLNO", "BillNo");
  60. AddLike(input.SourceBillNo, "ib.lydjbh", "SourceBillNo");
  61. AddLike(input.MaterialCode, "ib.FMATERIALCFG", "MaterialCode");
  62. AddLike(input.MaterialName, "ib.wlmc", "MaterialName");
  63. AddLike(input.SupplierName, "ib.gysmc", "SupplierName");
  64. AddLike(input.LotNo, "ib.pch", "LotNo");
  65. AddLike(input.Inspector, "ib.FINSPECTORID", "Inspector");
  66. if (!string.IsNullOrWhiteSpace(input.BillStatus))
  67. {
  68. where.Add("ib.FBILLSTATUS = @BillStatus");
  69. pars.Add(new SugarParameter("@BillStatus", input.BillStatus.Trim()));
  70. }
  71. if (input.Judgement.HasValue)
  72. {
  73. where.Add("ib.pd = @Judgement");
  74. pars.Add(new SugarParameter("@Judgement", input.Judgement.Value));
  75. }
  76. if (input.ProcessMethod.HasValue)
  77. {
  78. where.Add("ib.clfs = @ProcessMethod");
  79. pars.Add(new SugarParameter("@ProcessMethod", input.ProcessMethod.Value));
  80. }
  81. if (!string.IsNullOrWhiteSpace(input.InspectDateFrom))
  82. {
  83. where.Add("ib.FINSPESTARTDATE >= @InspectDateFrom");
  84. pars.Add(new SugarParameter("@InspectDateFrom", $"{input.InspectDateFrom.Trim()} 00:00:00"));
  85. }
  86. if (!string.IsNullOrWhiteSpace(input.InspectDateTo))
  87. {
  88. where.Add("ib.FINSPESTARTDATE <= @InspectDateTo");
  89. pars.Add(new SugarParameter("@InspectDateTo", $"{input.InspectDateTo.Trim()} 23:59:59"));
  90. }
  91. if (!string.IsNullOrWhiteSpace(input.CreateDateFrom))
  92. {
  93. where.Add("ib.FCREATETIME >= @CreateDateFrom");
  94. pars.Add(new SugarParameter("@CreateDateFrom", $"{input.CreateDateFrom.Trim()} 00:00:00"));
  95. }
  96. if (!string.IsNullOrWhiteSpace(input.CreateDateTo))
  97. {
  98. where.Add("ib.FCREATETIME <= @CreateDateTo");
  99. pars.Add(new SugarParameter("@CreateDateTo", $"{input.CreateDateTo.Trim()} 23:59:59"));
  100. }
  101. var whereSql = string.Join(" AND ", where);
  102. // 排序:白名单回落,方向 asc/desc 回落 desc;默认 FCREATETIME DESC, id DESC。
  103. string orderSql;
  104. if (!string.IsNullOrWhiteSpace(input.OrderBy) && OrderByWhitelist.TryGetValue(input.OrderBy.Trim(), out var col))
  105. {
  106. var dir = string.Equals(input.OrderDir?.Trim(), "asc", StringComparison.OrdinalIgnoreCase) ? "ASC" : "DESC";
  107. orderSql = $"{col} {dir}, ib.id DESC";
  108. }
  109. else
  110. {
  111. orderSql = "ib.FCREATETIME DESC, ib.id DESC";
  112. }
  113. var total = await _db.Ado.GetIntAsync(
  114. $"SELECT COUNT(1) FROM qms_qcp_inspbill ib WHERE {whereSql}", pars);
  115. var list = await _db.Ado.SqlQueryAsync<IqcInspBillListRow>(
  116. $"""
  117. SELECT
  118. ib.id AS Id,
  119. ib.FBILLNO AS BillNo,
  120. ib.lydjbh AS SourceBillNo,
  121. ib.FMATERIALCFG AS MaterialCode,
  122. ib.wlmc AS MaterialName,
  123. ib.ggxh AS Spec,
  124. ib.gysmc AS SupplierName,
  125. ib.pch AS LotNo,
  126. ib.FRINSQTY AS ReportQty,
  127. ib.jysl AS InspectQty,
  128. ib.dhsl AS QualifiedQty,
  129. ib.bhgsl AS UnqualifiedQty,
  130. ib.pd AS Judgement,
  131. ib.clfs AS ProcessMethod,
  132. ib.FBILLSTATUS AS BillStatus,
  133. ib.FINSPECTORID AS Inspector,
  134. ib.FINSPESTARTDATE AS InspectStartDate,
  135. ib.FINSPEENDDATE AS InspectEndDate,
  136. ib.FCREATETIME AS CreateTime,
  137. ib.FORGID AS OrgId
  138. FROM qms_qcp_inspbill ib
  139. WHERE {whereSql}
  140. ORDER BY {orderSql}
  141. LIMIT {pageSize} OFFSET {offset}
  142. """,
  143. pars);
  144. return new { total, page, pageSize, list };
  145. }
  146. /// <summary>
  147. /// 来料检验单详情(只读,按 id 单表直读 qms_qcp_inspbill)。
  148. ///
  149. /// 仅 SELECT 单行:不 join 申请表/明细/SuppMaster/ApprovalFlow/SQE,不查字典,不写任何表。
  150. /// id&lt;=0 或不存在返回 null(HTTP 200)。字典字段 pd/clfs/FBILLSTATUS/pcsq/blwtflid/FBIZTYPE 全 raw。
  151. /// 流程占位 BizType/BizId/BizCode 由本方法拼装,**不查 ApprovalFlowInstance、不生成流程实例**。
  152. /// qms_qcp_inspbill 无 tenant_id、FORGID 全 NULL:不做租户/组织过滤,与 list 口径一致。
  153. /// </summary>
  154. [DisplayName("来料检验单详情")]
  155. [HttpGet("detail")]
  156. public async Task<object?> GetDetail([FromQuery] long id)
  157. {
  158. if (id <= 0) return null;
  159. var pars = new List<SugarParameter> { new("@id", id) };
  160. var list = await _db.Ado.SqlQueryAsync<IqcInspBillDetailRow>(
  161. """
  162. SELECT
  163. ib.id AS Id,
  164. ib.FBILLNO AS BillNo,
  165. ib.lydjbh AS SourceBillNo,
  166. ib.FBILLSTATUS AS BillStatus,
  167. ib.FBIZTYPE AS BizTypeRaw,
  168. ib.FORGID AS OrgId,
  169. ib.FCREATETIME AS CreateTime,
  170. ib.FCREATORID AS CreateUserId,
  171. ib.FMODIFYTIME AS UpdateTime,
  172. ib.FMODIFIERID AS UpdateUserId,
  173. ib.FMATERIALCFG AS MaterialCode,
  174. ib.wlmc AS MaterialName,
  175. ib.ggxh AS Spec,
  176. ib.gysmc AS SupplierName,
  177. ib.pch AS LotNo,
  178. ib.jgbh AS InspectionSpecNo,
  179. ib.jgbb AS InspectionSpecVersion,
  180. ib.jgsxrq AS InspectionSpecEffectiveDate,
  181. ib.FRINSQTY AS ReportQty,
  182. ib.jysl AS InspectQty,
  183. ib.SampleQty AS SampleQty,
  184. ib.TestQty AS TestQty,
  185. ib.dhsl AS QualifiedQty,
  186. ib.bhgsl AS UnqualifiedQty,
  187. ib.phsl AS DestructiveQty,
  188. ib.lysl AS RetainSampleQty,
  189. ib.FINSPECTORID AS Inspector,
  190. ib.jyr AS InspectorName,
  191. ib.FINSPESTARTDATE AS InspectStartDate,
  192. ib.FINSPEENDDATE AS InspectEndDate,
  193. ib.pd AS Judgement,
  194. ib.clfs AS ProcessMethod,
  195. ib.UnqualifiedDescription AS UnqualifiedDescription,
  196. ib.thyy AS ReturnReason,
  197. ib.blwtflid AS DefectCategoryId,
  198. ib.blwtflmc AS DefectCategoryName,
  199. ib.pcsq AS DeviationApply,
  200. ib.pcsm AS DeviationDescription,
  201. ib.leader AS Leader,
  202. ib.FAUDITORID AS AuditorId,
  203. ib.FAUDITDATE AS AuditDate
  204. FROM qms_qcp_inspbill ib
  205. WHERE ib.id = @id
  206. LIMIT 1
  207. """,
  208. pars);
  209. var row = list.FirstOrDefault();
  210. if (row == null) return null;
  211. // 流程占位:固定 BizType、BizId=id、BizCode=FBILLNO,供后续 C'/D'/E' 批次接入 ApprovalFlow 用。本批不查/不建流程实例。
  212. row.BizType = "S5_IQC_INSPBILL";
  213. row.BizId = row.Id;
  214. row.BizCode = row.BillNo;
  215. row.FlowHint = "流程将在后续 C'/D'/E' 批次接入";
  216. return row;
  217. }
  218. }