Browse Source

feat(s8): sync responsible_dept_id on claim/transfer from assignee

YY968XX 3 tuần trước cách đây
mục cha
commit
f71a837570

+ 50 - 0
server/Plugins/Admin.NET.Plugin.AiDOP/Service/S8/S8TaskFlowService.cs

@@ -12,6 +12,7 @@ public class S8TaskFlowService : ITransient
     private readonly SqlSugarRepository<AdoS8Exception> _rep;
     private readonly SqlSugarRepository<AdoS8ExceptionTimeline> _timelineRep;
     private readonly SqlSugarRepository<AdoS0EmployeeMaster> _employeeRep;
+    private readonly SqlSugarRepository<AdoS0DepartmentMaster> _deptRep;
     private readonly SqlSugarRepository<ApprovalFlowInstance> _flowInstanceRep;
     private readonly SqlSugarRepository<ApprovalFlowTask> _flowTaskRep;
     private readonly FlowEngineService _flowEngine;
@@ -22,6 +23,7 @@ public class S8TaskFlowService : ITransient
         SqlSugarRepository<AdoS8Exception> rep,
         SqlSugarRepository<AdoS8ExceptionTimeline> timelineRep,
         SqlSugarRepository<AdoS0EmployeeMaster> employeeRep,
+        SqlSugarRepository<AdoS0DepartmentMaster> deptRep,
         SqlSugarRepository<ApprovalFlowInstance> flowInstanceRep,
         SqlSugarRepository<ApprovalFlowTask> flowTaskRep,
         FlowEngineService flowEngine,
@@ -31,6 +33,7 @@ public class S8TaskFlowService : ITransient
         _rep = rep;
         _timelineRep = timelineRep;
         _employeeRep = employeeRep;
+        _deptRep = deptRep;
         _flowInstanceRep = flowInstanceRep;
         _flowTaskRep = flowTaskRep;
         _flowEngine = flowEngine;
@@ -51,6 +54,20 @@ public class S8TaskFlowService : ITransient
         e.AssignedAt = DateTime.Now;
         e.UpdatedAt = DateTime.Now;
 
+        // S8-ASSIGNEE-RESP-DEPT-SYNC-1(P0-B-2):派单同步处理部门 = 处理人所属部门 RecID。
+        // 兜底策略:解析失败保留原 ResponsibleDeptId,仅 warn;避免误覆盖既有归属。
+        var resolvedDeptId = await ResolveEmployeeResponsibleDeptIdAsync(assigneeId, factoryId);
+        if (resolvedDeptId.HasValue)
+        {
+            e.ResponsibleDeptId = resolvedDeptId.Value;
+        }
+        else
+        {
+            _logger.LogWarning(
+                "s8_claim_dept_unresolved exceptionId={Id} assigneeId={AssigneeId} factoryId={FactoryId}",
+                e.Id, assigneeId, factoryId);
+        }
+
         await _rep.AsTenant().UseTranAsync(async () =>
         {
             await _rep.UpdateAsync(e);
@@ -78,6 +95,20 @@ public class S8TaskFlowService : ITransient
         e.AssigneeId = newAssigneeId;
         e.UpdatedAt = DateTime.Now;
 
+        // S8-ASSIGNEE-RESP-DEPT-SYNC-1(P0-B-2):转派同步处理部门 = 新处理人所属部门 RecID。
+        // 兜底策略:解析失败保留原 ResponsibleDeptId,仅 warn;避免误覆盖既有归属。
+        var resolvedDeptId = await ResolveEmployeeResponsibleDeptIdAsync(newAssigneeId, factoryId);
+        if (resolvedDeptId.HasValue)
+        {
+            e.ResponsibleDeptId = resolvedDeptId.Value;
+        }
+        else
+        {
+            _logger.LogWarning(
+                "s8_transfer_dept_unresolved exceptionId={Id} newAssigneeId={AssigneeId} factoryId={FactoryId}",
+                e.Id, newAssigneeId, factoryId);
+        }
+
         await _rep.AsTenant().UseTranAsync(async () =>
         {
             await _rep.UpdateAsync(e);
@@ -463,6 +494,25 @@ public class S8TaskFlowService : ITransient
         return currentUserId;
     }
 
+    // S8-ASSIGNEE-RESP-DEPT-SYNC-1(P0-B-2):处理人 RecID → 所属部门 RecID。
+    // 链路:EmployeeMaster.Department(codename) + FactoryRefId → DepartmentMaster.Department + FactoryRefId → RecID。
+    // ClearFilter 同口径(S8MasterDataAdapter / GetEmployeeSysUserIdAsync),factoryId 做硬边界。
+    // 解析失败返回 null —— 调用方按"保留原值 + warn"处理,绝不覆盖既有 ResponsibleDeptId。
+    private async Task<long?> ResolveEmployeeResponsibleDeptIdAsync(long assigneeId, long factoryId)
+    {
+        if (assigneeId <= 0 || factoryId <= 0) return null;
+        var emp = await _employeeRep.AsQueryable().ClearFilter()
+            .Where(x => x.Id == assigneeId && x.FactoryRefId == factoryId)
+            .Select(x => new { x.Department })
+            .FirstAsync();
+        if (emp == null || string.IsNullOrWhiteSpace(emp.Department)) return null;
+        var deptId = await _deptRep.AsQueryable().ClearFilter()
+            .Where(x => x.Department == emp.Department && x.FactoryRefId == factoryId && x.IsActive)
+            .Select(x => (long?)x.Id)
+            .FirstAsync();
+        return deptId;
+    }
+
     // 把异常上的处理人/检验人(employeeId) 经 EmployeeMaster.SysUserId 解析到系统账号 ID。
     // EmployeeMaster.tenant_id 与 SysUser.TenantId 历史错位,必须 ClearFilter 跳过多租户全局 filter;
     // 通过 employee.Id 主键精确查询作为安全边界,无跨租户泄漏风险。