using DS.Module.Core; using DS.WMS.Core.Fee.Entity; using DS.WMS.Core.Flow.Dtos; using DS.WMS.Core.Flow.Entity; using DS.WMS.Core.Flow.Method; using DS.WMS.Core.Op.Entity; using DS.WMS.Core.TaskInteraction.Dtos; using DS.WMS.Core.TaskInteraction.Entity; using DS.WMS.Core.TaskInteraction.Interface; using DS.WMS.Core.TaskPlat.Dtos; using Mapster; using Masuit.Tools; using Masuit.Tools.Systems; namespace DS.WMS.Core.TaskInteraction.Method { /// /// 费用审核任务 /// public sealed class FeeTaskService : TaskService, IFeeTaskService { internal static readonly TaskBaseTypeEnum[] FeeTypes = [TaskBaseTypeEnum.FEE_AUDIT, TaskBaseTypeEnum.FEE_MODIFY_AUDIT, TaskBaseTypeEnum.FEE_DELETE_AUDIT]; /// /// 初始化 /// /// public FeeTaskService(IServiceProvider provider) : base(provider) { } /// /// 创建关联任务 /// /// /// 是否使用事务 /// public override async Task CreateTaskAsync(TaskCreationRequest request, bool useTransaction = true) { if (!await HasAuthorizedAsync()) return DataResult.FailedWithDesc(nameof(MultiLanguageConst.ModuleUnauthorized)); if (request.Steps?.Count > 0) { if (request.Steps.Where(x => x.Type != StepType.NotSpecified).GroupBy(x => x.Type).Select(x => x.Key).Count() > 1) return DataResult.FailedWithDesc(nameof(MultiLanguageConst.DuplicateStepType)); if (request.Steps.Any(x => x.Type == StepType.NotSpecified && string.IsNullOrEmpty(x.Name))) return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TypeOrName)); } DataResult result = DataResult.Success; bool updateFlag = false; var task = await GetQuery(request.BusinessId, request.BusinessType, request.TaskType).FirstAsync(); if (task != null && AuditTaskTypes.Contains(request.TaskType) && (task.TaskStatus == TaskStatusEnum.Pending || task.TaskStatus == TaskStatusEnum.Cancel)) updateFlag = true; long userId = long.Parse(User.UserId); DateTime dtNow = DateTime.Now; if (useTransaction) await TenantDb.Ado.BeginTranAsync(); try { TaskManageOrderMessageInfo? info = null; if (task == null) { info = await CreateMessageAsync(request); if ((request.RecvUserIdList == null || request.RecvUserIdList.Length == 0) && IsOrderType(request.TaskType)) { //根据配置获取默认接收人 info.Main.RecvUserInfoList = await GetRecvUsersAsync(request.BusinessId, request.BusinessType, request.TaskType); } else if (AuditTaskTypes.Contains(request.TaskType)) { //审核任务默认为提交人,生成工作流后替换为工作流执行人 info.Main.RecvUserInfoList = await FillInUserInfoAsync(long.Parse(User.UserId)); } else { info.Main.RecvUserInfoList = await FillInUserInfoAsync(request.RecvUserIdList); } task = new BusinessTask { ParentId = request.ParentId, BusinessId = request.BusinessId, BusinessType = request.BusinessType, ParentBusinessId = request.ParentBusinessId, TaskType = request.TaskType, TaskStatus = TaskStatusEnum.Create, RecvUsers = string.Join(',', info.Main.RecvUserInfoList.Select(x => x.RecvUserId)) ?? string.Empty, NextType = request.NextType, CreateBy = userId, CreateTime = dtNow }; if (IsOrderType(request.TaskType) && !task.NextType.HasValue) task.NextType = await GetNextTypeAsync(task); await TenantDb.Insertable(task).ExecuteCommandAsync(); if (request.Steps?.Count > 0) { var steps = request.Steps.Select(x => new TaskStep { TaskId = task.Id, IsCompleted = x.IsCompleted, Name = x.Name, Type = x.Type, Priority = x.Priority ?? request.Steps.IndexOf(x), CreateBy = userId, CreateTime = dtNow }).ToList(); await TenantDb.Insertable(steps).ExecuteCommandAsync(); } result = await OnTaskCreated(task); if (!result.Succeeded) return result; //记录日志 await LogService.WriteLogAsync(task); } result = await CreateAndStartWorkflow(task, false); if (!result.Succeeded) return result; if (updateFlag) { result = await SetTaskStatusAsync(new TaskUpdateRequest { BusinessId = request.BusinessId, BusinessType = request.BusinessType, TaskTypeName = request.TaskTypeName, TaskStatus = TaskStatusEnum.Create }, false); if (!result.Succeeded) return result; } else //费用审核需拆分任务 { var instance = result.Data as FlowInstance; var ids = FlowInstanceService.GetMarkers(instance).Select(long.Parse).ToArray(); var recvUserList = await FillInUserInfoAsync(ids); var fee = await TenantDb.Queryable().Where(x => x.Id == request.BusinessId) .Select(x => new { x.Id, x.BusinessId, x.BusinessType }).FirstAsync(); foreach (var item in recvUserList) { var copiedInfo = info.DeepClone(); copiedInfo.Head.BSNO = fee.BusinessId; //替换为费用关联的订单ID copiedInfo.Main.RecvUserInfoList.Clear(); copiedInfo.Main.RecvUserInfoList.Add(item); copiedInfo.Main.ExtData = new { fee.BusinessType, FeeId = fee.Id }; result = await ManagerService.InitTaskJob(copiedInfo); if (!result.Succeeded) { await Db.Deleteable(instance).ExecuteCommandAsync(); return result; } } } if (useTransaction) await TenantDb.Ado.CommitTranAsync(); return DataResult.Success; } catch (Exception ex) { if (useTransaction) await TenantDb.Ado.RollbackTranAsync(); if (result.Data is FlowInstance instance) await Db.Deleteable(instance).ExecuteCommandAsync(); await ex.LogAsync(Db); return DataResult.FailedWithDesc(nameof(MultiLanguageConst.Operation_Failed)); } } /// /// 设置任务状态 /// /// /// 是否使用事务 /// public override async Task SetTaskStatusAsync(TaskUpdateRequest request, bool useTransaction = true) { if (!await HasAuthorizedAsync()) return DataResult.FailedWithDesc(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.ModuleUnauthorized))); if (useTransaction) await TenantDb.Ado.BeginTranAsync(); try { BusinessTask task = await GetQuery(request.BusinessId, request.BusinessType, request.TaskType).FirstAsync(); if (task == null) return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TaskNotExists)); if (task.TaskStatus == TaskStatusEnum.Complete) return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TaskCompleted)); if (request.TaskStatus == TaskStatusEnum.Complete && await TenantDb.Queryable().AnyAsync(x => x.ParentId == task.Id && x.TaskStatus != request.TaskStatus)) return DataResult.FailedWithDesc(nameof(MultiLanguageConst.UnfinishedItems)); //检查是否有未完成的任务步骤 var steps = await TenantDb.Queryable().Where(x => x.TaskId == task.Id && !x.IsCompleted) .Select(x => new { x.Type, x.Name }).ToListAsync(); if (steps.Count > 0) return DataResult.Failed( MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.UnfinishedItems)) + ":" + string.Join("|", steps.Select(x => x.Type == StepType.NotSpecified ? x.Name : x.Type.GetDescription())), nameof(MultiLanguageConst.UnfinishedItems)); //触发任务状态变更通知 if (task.TaskStatus != request.TaskStatus) await OnTaskStatusChanged(request); task.UpdateBy = long.Parse(User.UserId); task.UpdateTime = DateTime.Now; task.RejectReason = request.RejectReason; //更新当前任务状态 task.TaskStatus = request.TaskStatus; await TenantDb.Updateable(task).UpdateColumns(x => new { x.TaskStatus, x.RejectReason, x.UpdateBy, x.UpdateTime }).ExecuteCommandAsync(); //记录日志 await LogService.WriteLogAsync(request); if (useTransaction) await TenantDb.Ado.CommitTranAsync(); return DataResult.Success; } catch (Exception ex) { if (useTransaction) await TenantDb.Ado.RollbackTranAsync(); await ex.LogAsync(Db); return DataResult.FailedWithDesc(nameof(MultiLanguageConst.Operation_Failed)); } } /// /// 任务审核 /// /// public override async Task AuditAsync(TaskAuditRequest request) { var tasks = await TenantDb.Queryable().Where(x => x.TaskType == request.TaskType && request.Ids.Contains(x.BusinessId)) .WhereIF(request.BusinessType.HasValue, x => x.BusinessType == request.BusinessType.Value).ToListAsync(); if (tasks.Count == 0) return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TaskNotExists)); if (tasks.Count != request.Ids.Length) return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TaskCountNotMatch)); if (tasks.Exists(x => x.TaskStatus == TaskStatusEnum.Complete)) { return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TaskCompleted)); } else if (tasks.Exists(x => x.TaskStatus != TaskStatusEnum.Create && x.TaskStatus != TaskStatusEnum.Pending)) { return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TaskAuditStatusError)); } DataResult result = DataResult.Success; await TenantDb.Ado.BeginTranAsync(); try { var flowIds = tasks.Select(x => x.FlowId.Value); var flowInstances = await Db.Queryable().Where(x => flowIds.Contains(x.Id)).ToListAsync(); foreach (var instance in flowInstances) { result = await FlowService.Value.AuditAsync(new FlowAuditInfo { AuditNote = request.Remark, Status = request.Result, Instance = instance }); if (!result.Succeeded) return result; var req = new TaskUpdateRequest { BusinessId = instance.BusinessId, BusinessType = instance.BusinessType, RejectReason = request.Remark, TaskTypeName = request.TaskType.ToString(), TaskStatus = request.Result == 1 ? TaskStatusEnum.Complete : TaskStatusEnum.Pending, AutoCreateNext = true }; //根据审批结果更新任务状态 await SetTaskStatusAsync(req, false); if (instance.FlowStatus == FlowStatusEnum.Reject) result.Message = MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.TaskRejected)); if (IsOrderType(request.TaskType)) result.Data = new { instance.IsCompleted, instance.FlowStatus }; } var fees = await TenantDb.Queryable().Where(x => request.Ids.Contains(x.Id)) .Select(x => new { x.BusinessId, x.BusinessType, x.Id }).ToListAsync(); var bizList = fees.GroupBy(x => new { x.BusinessId, x.BusinessType }).ToList(); foreach (var biz in bizList) { var relativeFeeIds = biz.Select(x => x.Id).ToArray(); var relativeTasks = await GetFeeTasks(biz.Key.BusinessType, [biz.Key.BusinessId], relativeFeeIds); if (relativeTasks.All(x => x.TaskStatus == TaskStatusEnum.Complete)) { var userIdList = tasks.Where(x => relativeFeeIds.Contains(x.BusinessId)).SelectMany(x => x.RecvUserIdArray).Distinct().ToList(); //在此将费用关联的主任务设置为完成状态 result = await ManagerService.SetTaskStatusWithBsno(biz.Key.BusinessId, request.TaskType, TaskStatusEnum.Complete, DateTime.Now, false, userIdList: userIdList); if (!result.Succeeded) return result; } } await TenantDb.Ado.CommitTranAsync(); return result; } catch (Exception ex) { await TenantDb.Ado.RollbackTranAsync(); await ex.LogAsync(Db); return DataResult.FailedWithDesc(nameof(MultiLanguageConst.Operation_Failed)); } } /// /// 撤销审核任务 /// /// /// 是否使用事务 /// public override async Task WithdrawAsync(TaskRequest request, bool useTransaction = true) { if (!AuditTaskTypes.Contains(request.TaskType)) return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TaskTypeNotSupported)); var task = await GetQuery(request.BusinessId, request.BusinessType, request.TaskType).Select(x => new BusinessTask { Id = x.Id, TaskStatus = x.TaskStatus, FlowId = x.FlowId, RecvUsers = x.RecvUsers }).FirstAsync(); if (task == null) return DataResult.FailedWithDesc(nameof(MultiLanguageConst.EmptyData)); if (task.TaskStatus == TaskStatusEnum.Complete) return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TaskCompleted)); if (!task.FlowId.HasValue) return DataResult.FailedWithDesc(nameof(MultiLanguageConst.NotInFlows)); DataResult result; DateTime dt = DateTime.Now; long userId = long.Parse(User.UserId); if (useTransaction) await TenantDb.Ado.BeginTranAsync(); try { var fees = await TenantDb.Queryable().Where(x => request.Ids.Contains(x.Id)) .Select(x => new { x.BusinessId, x.BusinessType, x.Id }).ToListAsync(); var bizList = fees.GroupBy(x => new { x.BusinessId, x.BusinessType }).ToList(); foreach (var biz in bizList) { var relativeFeeIds = biz.Select(x => x.Id).ToArray(); var relativeTasks = await GetFeeTasks(biz.Key.BusinessType, [biz.Key.BusinessId], relativeFeeIds); if (relativeTasks.All(x => x.TaskStatus == TaskStatusEnum.Cancel)) { //在此将费用关联的主任务设置为完成状态 result = await ManagerService.SetTaskStatusWithBsno(biz.Key.BusinessId, request.TaskType, TaskStatusEnum.Cancel, DateTime.Now, false, userIdList: [.. task.RecvUserIdArray]); if (!result.Succeeded) return result; } } await TenantDb.Updateable().Where(x => x.Id == task.Id) .SetColumns(x => x.TaskStatus == TaskStatusEnum.Cancel) .SetColumns(x => x.UpdateBy == userId) .SetColumns(x => x.UpdateTime == dt) .ExecuteCommandAsync(); await LogService.WriteLogAsync(new BusinessTaskLog { ActionType = ActionType.StatusChanged, AuditStatus = FlowStatusEnum.Draft, BusinessId = request.BusinessId, BusinessType = request.BusinessType, CreateBy = userId, CreateTime = dt, TaskStatus = TaskStatusEnum.Cancel, TaskType = request.TaskType }); result = await FlowService.Value.WithdrawAsync([task.FlowId.Value], "用户撤销审核"); if (!result.Succeeded) return result; if (useTransaction) await TenantDb.Ado.CommitTranAsync(); return DataResult.Success; } catch (Exception ex) { if (useTransaction) await TenantDb.Ado.RollbackTranAsync(); await ex.LogAsync(Db); return DataResult.FailedWithDesc(nameof(MultiLanguageConst.Operation_Failed)); } } //获取指定业务的所有关联费用类任务 async Task> GetFeeTasks(BusinessType bsType, long[] bsIds, params long[] excludeFeeIds) { return await TenantDb.Queryable() .InnerJoin((t, f) => t.BusinessId == f.Id) .Where((t, f) => bsIds.Contains(f.BusinessId) && f.BusinessType == bsType && FeeTypes.Contains(t.TaskType) && t.TaskStatus != TaskStatusEnum.Cancel) .WhereIF(excludeFeeIds.Length > 0, (t, f) => !excludeFeeIds.Contains(f.Id)) .Select((t, f) => new BusinessTask { Id = t.Id, BusinessId = t.BusinessId, TaskType = t.TaskType, TaskStatus = t.TaskStatus, RecvUsers = t.RecvUsers }).ToListAsync(); } } }