| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758 |
- namespace Admin.NET.Plugin.AiDOP.Manufacturing;
- /// <summary>
- /// S6 模工具台账(MoldToolList)删除前的下游引用检查(FUNC-S6-004)。
- ///
- /// 刻意**不复用** Infrastructure/AdoS0ReferenceChecker:那是 S0 共享基础设施,
- /// 改它需抢提交锁且会把 S6 逻辑混入 S0 模块边界(CLAUDE.md 第九节)。
- ///
- /// 引用口径一律「租户内 + 按业务编码 MoldTypeCode 匹配」,与两张下游表的实际存储一致
- /// (下游存的是编码字符串,不是 MoldToolList.id)。
- ///
- /// 覆盖范围(2026-09-01 实测):
- /// MUST ProdLineDetail.MoldTypeCode —— S0 线边物料/产线物料在用,活跃写入路径,
- /// 同租户命中 896 行(另有 369 行历史孤儿,非本批修复范围)
- /// SHOULD ScheduleResultOpMaster.MoldTypeCode —— 排产结果;当前生成逻辑未写该列(命中 0),
- /// 但 ExecutableDailyPlanService 已按该列做筛选消费,
- /// 属已声明且已被消费的引用位,一并纳入以免将来漏检
- /// 不纳入:LineMaterial.MoldTypeCode —— 空表、无任何 controller/service 读写路径,仅 CodeFirst 注册
- ///
- /// 只读:本类只做 SELECT,不修改、不清空、不级联删除任何下游数据。
- /// </summary>
- public sealed class MoldToolReferenceChecker : ITransient
- {
- private readonly ISqlSugarClient _db;
- public MoldToolReferenceChecker(ISqlSugarClient db)
- {
- _db = db;
- }
- /// <summary>
- /// 租户内检查该模具类型编码是否被下游引用。命中返回(条数, 中文表述),未命中返回 null。
- /// </summary>
- public async Task<(int Count, string Table)?> ReferencesAsync(long tenantId, string? moldTypeCode)
- {
- if (string.IsNullOrWhiteSpace(moldTypeCode)) return null;
- var code = moldTypeCode.Trim();
- var prodLine = await CountAsync(
- "SELECT COUNT(1) FROM ProdLineDetail WHERE tenant_id = @TenantId AND MoldTypeCode = @Code",
- tenantId, code);
- if (prodLine > 0) return (prodLine, "线边物料/产线物料配置 (ProdLineDetail.MoldTypeCode)");
- var schedule = await CountAsync(
- "SELECT COUNT(1) FROM ScheduleResultOpMaster WHERE tenant_id = @TenantId AND MoldTypeCode = @Code",
- tenantId, code);
- if (schedule > 0) return (schedule, "排产结果工序 (ScheduleResultOpMaster.MoldTypeCode)");
- return null;
- }
- private Task<int> CountAsync(string sql, long tenantId, string code)
- => _db.Ado.GetIntAsync(sql, new List<SugarParameter>
- {
- new("@TenantId", tenantId),
- new("@Code", code)
- });
- }
|