Ver Fonte

fix(s0): block deletion for referenced core master data

YY968XX há 1 mês atrás
pai
commit
dd12c603f1

+ 3 - 3
server/Admin.NET.Web.Entry/Admin.NET.Web.Entry.csproj

@@ -11,9 +11,9 @@
     <GenerateSatelliteAssembliesForCore>true</GenerateSatelliteAssembliesForCore>
     <Copyright>Admin.NET</Copyright>
     <Description>Admin.NET ͨÓÃȨÏÞ¿ª·¢Æ½Ì¨</Description>
-    <AssemblyVersion>1.0.170</AssemblyVersion>
-    <FileVersion>1.0.170</FileVersion>
-    <Version>1.0.170</Version>
+    <AssemblyVersion>1.0.171</AssemblyVersion>
+    <FileVersion>1.0.171</FileVersion>
+    <Version>1.0.171</Version>
   </PropertyGroup>
 
   <ItemGroup>

+ 9 - 1
server/Plugins/Admin.NET.Plugin.AiDOP/Controllers/S0/Manufacturing/AdoS0MfgPersonSkillsController.cs

@@ -12,10 +12,12 @@ namespace Admin.NET.Plugin.AiDOP.Controllers.S0.Manufacturing;
 public class AdoS0MfgPersonSkillsController : ControllerBase
 {
     private readonly SqlSugarRepository<AdoS0MfgPersonSkill> _rep;
+    private readonly AdoS0ReferenceChecker _refChecker;
 
-    public AdoS0MfgPersonSkillsController(SqlSugarRepository<AdoS0MfgPersonSkill> rep)
+    public AdoS0MfgPersonSkillsController(SqlSugarRepository<AdoS0MfgPersonSkill> rep, AdoS0ReferenceChecker refChecker)
     {
         _rep = rep;
+        _refChecker = refChecker;
     }
 
     [HttpGet]
@@ -130,6 +132,12 @@ public class AdoS0MfgPersonSkillsController : ControllerBase
     {
         var item = await _rep.GetByIdAsync(id);
         if (item == null) return NotFound();
+
+        var refInfo = await _refChecker.PersonSkillReferencesAsync(item.Id, item.Code);
+        if (refInfo is { } r)
+            return AdoS0ApiErrors.Conflict(AdoS0ErrorCodes.DeleteBlocked,
+                $"存在 {r.Count} 条 {r.Table} 引用该人员技能,无法删除");
+
         await _rep.DeleteAsync(item);
         return Ok(new { message = "删除成功" });
     }

+ 5 - 0
server/Plugins/Admin.NET.Plugin.AiDOP/Controllers/S0/Manufacturing/AdoS0MfgProductionLinesController.cs

@@ -190,6 +190,11 @@ public class AdoS0MfgProductionLinesController : ControllerBase
         var item = await _rep.GetByIdAsync(id);
         if (item == null) return NotFound();
 
+        var refInfo = await _refChecker.ProductionLineReferencesAsync(item.Id, item.Line);
+        if (refInfo is { } r)
+            return AdoS0ApiErrors.Conflict(AdoS0ErrorCodes.DeleteBlocked,
+                $"存在 {r.Count} 条 {r.Table} 引用该生产线,无法删除");
+
         await _rep.DeleteAsync(item);
         return Ok(new { message = "删除成功" });
     }

+ 6 - 0
server/Plugins/Admin.NET.Plugin.AiDOP/Controllers/S0/Warehouse/AdoS0EmployeesController.cs

@@ -164,6 +164,12 @@ public class AdoS0EmployeesController : ControllerBase
     {
         var item = await _rep.GetByIdAsync(id);
         if (item == null) return NotFound();
+
+        var refInfo = await _refChecker.EmployeeReferencesAsync(item.Employee);
+        if (refInfo is { } r)
+            return AdoS0ApiErrors.Conflict(AdoS0ErrorCodes.DeleteBlocked,
+                $"存在 {r.Count} 条 {r.Table} 引用该雇员,无法删除");
+
         await _rep.DeleteAsync(item);
         return Ok(new { message = "删除成功" });
     }

+ 10 - 1
server/Plugins/Admin.NET.Plugin.AiDOP/Controllers/S0/Warehouse/AdoS0NbrTypesController.cs

@@ -15,13 +15,16 @@ public class AdoS0NbrTypesController : ControllerBase
 {
     private readonly SqlSugarRepository<AdoS0NbrTypeMaster> _rep;
     private readonly SqlSugarRepository<AdoS0DepartmentMaster> _deptRep;
+    private readonly AdoS0ReferenceChecker _refChecker;
 
     public AdoS0NbrTypesController(
         SqlSugarRepository<AdoS0NbrTypeMaster> rep,
-        SqlSugarRepository<AdoS0DepartmentMaster> deptRep)
+        SqlSugarRepository<AdoS0DepartmentMaster> deptRep,
+        AdoS0ReferenceChecker refChecker)
     {
         _rep = rep;
         _deptRep = deptRep;
+        _refChecker = refChecker;
     }
 
     [HttpGet]
@@ -113,6 +116,12 @@ public class AdoS0NbrTypesController : ControllerBase
     {
         var item = await _rep.GetByIdAsync(id);
         if (item == null) return NotFound();
+
+        var refInfo = await _refChecker.NbrTypeReferencesAsync(item.NbrType);
+        if (refInfo is { } r)
+            return AdoS0ApiErrors.Conflict(AdoS0ErrorCodes.DeleteBlocked,
+                $"存在 {r.Count} 条 {r.Table} 引用该单号类型,无法删除");
+
         await _rep.DeleteAsync(item);
         return Ok(new { message = "删除成功" });
     }

+ 81 - 0
server/Plugins/Admin.NET.Plugin.AiDOP/Infrastructure/AdoS0ReferenceChecker.cs

@@ -310,4 +310,85 @@ public sealed class AdoS0ReferenceChecker
 
         return null;
     }
+
+    /// <summary>
+    /// 单号类型(NbrTypeMaster)删除前引用检查。
+    /// 覆盖下游:单号规则(NbrControl.NbrType)。
+    /// </summary>
+    public async Task<(int Count, string Table)?> NbrTypeReferencesAsync(string? nbrType)
+    {
+        if (string.IsNullOrWhiteSpace(nbrType)) return null;
+
+        var ctrl = await _db.Queryable<AdoS0NbrControl>()
+            .Where(x => x.NbrType == nbrType)
+            .CountAsync();
+        if (ctrl > 0) return (ctrl, "单号规则 (NbrControl)");
+
+        return null;
+    }
+
+    /// <summary>
+    /// 生产线(LineMaster)删除前引用检查。
+    /// 覆盖下游:生产线物料(ProdLineDetail.Line)/ 线体岗位(LinePost.ProductionLineId)。
+    /// </summary>
+    public async Task<(int Count, string Table)?> ProductionLineReferencesAsync(long id, string? line)
+    {
+        if (!string.IsNullOrWhiteSpace(line))
+        {
+            var detail = await _db.Queryable<AdoS0ProdLineDetail>()
+                .Where(x => x.Line == line)
+                .CountAsync();
+            if (detail > 0) return (detail, "生产线物料 (ProdLineDetail.Line)");
+        }
+
+        var post = await _db.Queryable<AdoS0MfgLinePost>()
+            .Where(x => x.ProductionLineId == id)
+            .CountAsync();
+        if (post > 0) return (post, "线体岗位 (LinePost.ProductionLineId)");
+
+        return null;
+    }
+
+    /// <summary>
+    /// 雇员(EmployeeMaster)删除前引用检查。
+    /// 覆盖下游:物料职责(EmpWorkDutyMaster.Employee)。
+    /// </summary>
+    public async Task<(int Count, string Table)?> EmployeeReferencesAsync(string? employee)
+    {
+        if (string.IsNullOrWhiteSpace(employee)) return null;
+
+        var duty = await _db.Queryable<AdoS0EmpWorkDutyMaster>()
+            .Where(x => x.Employee == employee)
+            .CountAsync();
+        if (duty > 0) return (duty, "物料职责 (EmpWorkDutyMaster)");
+
+        return null;
+    }
+
+    /// <summary>
+    /// 人员技能(PersonSkill)删除前引用检查。
+    /// 覆盖下游:人员技能关系(EmpSkills.SkillNo=Code)/ 产线岗位技能明细(LineSkillDetail.PersonSkillId=Id)/ 人员技能分配(PersonSkillAssignment.SkillId=Id)。
+    /// </summary>
+    public async Task<(int Count, string Table)?> PersonSkillReferencesAsync(long id, string? code)
+    {
+        if (!string.IsNullOrWhiteSpace(code))
+        {
+            var emp = await _db.Queryable<AdoS0EmpSkills>()
+                .Where(x => x.SkillNo == code)
+                .CountAsync();
+            if (emp > 0) return (emp, "人员技能关系 (EmpSkills.SkillNo)");
+        }
+
+        var lineSkill = await _db.Queryable<AdoS0LineSkillDetail>()
+            .Where(x => x.PersonSkillId == id)
+            .CountAsync();
+        if (lineSkill > 0) return (lineSkill, "产线岗位技能明细 (LineSkillDetail)");
+
+        var assign = await _db.Queryable<AdoS0MfgPersonSkillAssignment>()
+            .Where(x => x.SkillId == id)
+            .CountAsync();
+        if (assign > 0) return (assign, "人员技能分配 (PersonSkillAssignment)");
+
+        return null;
+    }
 }