diff --git a/ds-wms-service/DS.Module.Core/Constants/MultiLanguageConst.cs b/ds-wms-service/DS.Module.Core/Constants/MultiLanguageConst.cs index 6a85533f..1114ec46 100644 --- a/ds-wms-service/DS.Module.Core/Constants/MultiLanguageConst.cs +++ b/ds-wms-service/DS.Module.Core/Constants/MultiLanguageConst.cs @@ -1433,7 +1433,11 @@ public static class MultiLanguageConst #region 关联任务 [Description("此类型的任务已存在")] - public const string Task_Exists = "Task_Exists"; + public const string TaskExists = "Task_Exists"; + [Description("此任务已完成")] + public const string TaskCompleted = "Task_Completed"; + [Description("此任务已取消")] + public const string TaskCancelled = "Task_Cancelled"; #endregion #region 任务台相关 diff --git a/ds-wms-service/DS.WMS.Core/Flow/Method/FlowInstanceService.cs b/ds-wms-service/DS.WMS.Core/Flow/Method/FlowInstanceService.cs index 8fa01833..e755d0ab 100644 --- a/ds-wms-service/DS.WMS.Core/Flow/Method/FlowInstanceService.cs +++ b/ds-wms-service/DS.WMS.Core/Flow/Method/FlowInstanceService.cs @@ -288,7 +288,7 @@ public class FlowInstanceService : IFlowInstanceService UserName = userInfo.UserName }; db.Insertable(history).ExecuteCommand(); - return DataResult.Successed("更新成功!", MultiLanguageConst.FlowInstanceUpdateSuccess); + return DataResult.Successed("更新成功!", instance, MultiLanguageConst.FlowInstanceUpdateSuccess); } public DataResult AuditFlowInstance(FlowInstanceAuditReq req) @@ -309,6 +309,11 @@ public class FlowInstanceService : IFlowInstanceService protected virtual DataResult AuditFlowCore(int status, string auditNote, FlowInstance instance) { + ArgumentNullException.ThrowIfNull(instance, nameof(instance)); + + if (!instance.MakerList.Contains(user.UserId)) + return DataResult.FailedWithDesc(nameof(MultiLanguageConst.AuditUnauthorization)); + var tag = new FlowTag { UserName = user.UserName, diff --git a/ds-wms-service/DS.WMS.Core/Op/Method/TaskInteraction/SeaExportTaskService.cs b/ds-wms-service/DS.WMS.Core/Op/Method/TaskInteraction/SeaExportTaskService.cs index e7ec30dd..a1eb9422 100644 --- a/ds-wms-service/DS.WMS.Core/Op/Method/TaskInteraction/SeaExportTaskService.cs +++ b/ds-wms-service/DS.WMS.Core/Op/Method/TaskInteraction/SeaExportTaskService.cs @@ -113,7 +113,7 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction //放舱结束,根据业务所选服务,生成子任务 if (request.TaskType == TaskBaseTypeEnum.WAIT_SPACE_RELEASE && request.TaskStatus == TaskStatusEnum.Complete) { - var task = await GetTaskAsync(request.BusinessId, request.BusinessType, request.TaskType); + var task = await GetQuery(request.BusinessId, request.BusinessType, request.TaskType).FirstAsync(); var list = await GetSubRequestAsync(request.BusinessId, request.BusinessType, task?.RecvUserIdArray); await CreateSubTaskAsync(list); } diff --git a/ds-wms-service/DS.WMS.Core/Op/Method/TaskInteraction/TaskService.cs b/ds-wms-service/DS.WMS.Core/Op/Method/TaskInteraction/TaskService.cs index 564b2794..32683e96 100644 --- a/ds-wms-service/DS.WMS.Core/Op/Method/TaskInteraction/TaskService.cs +++ b/ds-wms-service/DS.WMS.Core/Op/Method/TaskInteraction/TaskService.cs @@ -1,6 +1,7 @@ using DS.Module.Core; using DS.Module.Core.Extensions; using DS.Module.Core.Helpers; +using DS.WMS.Core.Fee.Dtos; using DS.WMS.Core.Fee.Method; using DS.WMS.Core.Flow.Dtos; using DS.WMS.Core.Flow.Entity; @@ -46,11 +47,28 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction FlowService = new Lazy(provider.GetRequiredService()); } + /// + /// 获取给定任务的下一任务类型 + /// + /// 任务信息 + /// + internal static TaskBaseTypeEnum? GetNextType(BusinessTask current) + { + if (current.TaskType == TaskBaseTypeEnum.WAIT_CHECKOUT_BILL) //流程的最后一步 + return null; + + int currentTypeVal = (int)current.TaskType; + if (currentTypeVal >= 300) //300开始的枚举值为可选服务项目,不存在前后关联性 + return null; + + return (TaskBaseTypeEnum)currentTypeVal++; + } + /// /// 确保任务交互模块已授权 /// /// - protected virtual async Task EnsureModuleAuthorized() + protected virtual async Task EnsureModuleAuthorized() { //if (!await Db.Queryable().AnyAsync(x => x.PermissionId == PERMISSION_ID)) // return false; @@ -66,6 +84,53 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction return int.TryParse(EncrypteHelper.DecryptData(authStr, appSecret), out int authNum) && authNum > 0; } + /// + /// 任务审核 + /// + /// + /// + public async virtual Task AuditAsync(AuditRequest request) + { + long id = request.Ids[0]; + var task = await GetQuery(id, request.BusinessType.GetValueOrDefault(), TaskBaseTypeEnum.WAIT_ORDER_AUDIT).FirstAsync(); + if (task == null) + return DataResult.FailedWithDesc(nameof(MultiLanguageConst.EmptyData)); + + if (task.TaskStatus == TaskStatusEnum.Complete) + { + return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TaskCompleted)); + } + else if (task.TaskStatus == TaskStatusEnum.Pending) //二次审核 + { + //重新创建工作流 + var result = await Create_StartWorkflow(task); + if (!result.Succeeded) + return result; + + var flow = result.Data as FlowInstance; + //更新当前任务的工作流ID + task.FlowId = flow?.Id; + await TenantDb.Updateable(task).UpdateColumns(x => new { x.FlowId }).ExecuteCommandAsync(); + + return FlowService.Value.AuditFlowInstance(new FlowAuditInfo + { + AuditNote = request.Remark, + Status = request.Result, + Instance = flow + }); + } + + if (task.FlowId == null) + return DataResult.FailedWithDesc(nameof(MultiLanguageConst.FlowNotFound)); + + return FlowService.Value.AuditFlowInstance(new FlowAuditInfo + { + AuditNote = request.Remark, + Status = request.Result, + Instance = await Db.Queryable().FirstAsync(x => x.Id == task.FlowId.Value) + }); + } + /// /// 创建关联任务 /// @@ -77,9 +142,9 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction if (!await EnsureModuleAuthorized()) return DataResult.SuccessedWithDesc(nameof(MultiLanguageConst.ModuleUnauthorized)); - var task = await GetTaskAsync(request.BusinessId, request.BusinessType, request.TaskType); - if (task != null) - return DataResult.FailedWithDesc(nameof(MultiLanguageConst.Task_Exists)); + var task = await GetQuery(request.BusinessId, request.BusinessType, request.TaskType).FirstAsync(); + if (task != null && task.TaskStatus != TaskStatusEnum.Cancel) + return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TaskExists)); long tenatId = long.Parse(User.TenantId); string tenatName = Db.Queryable().Where(x => x.Id == tenatId).Select(x => x.Name).First(); @@ -159,38 +224,9 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction //待审核,需创建工作流 if (task.TaskType == TaskBaseTypeEnum.WAIT_ORDER_AUDIT) { - var template = await FindTemplateAsync(AuditType.SeaExport); - if (template == null) - return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TemplateNotFound)); - - result = FlowService.Value.CreateFlowInstance(new CreateFlowInstanceReq - { - BusinessId = task.BusinessId, - BusinessType = BusinessType.OceanShippingExport, - TemplateId = template.Id - }); - //创建并启动实例 - if (result.Succeeded) - { - var instance = result.Data as FlowInstance; - task.FlowId = instance.Id; - await TenantDb.Updateable(task).UpdateColumns(x => x.FlowId).ExecuteCommandAsync(); - - result = FlowService.Value.StartFlowInstance(instance.Id.ToString()); - //工作流为会签,需要更新任务接收人 - if (result.Succeeded && instance.ActivityType == 0) - { - var marker = FlowInstanceService.GetNextMarker(instance); - await UpdateReceiverAsync(new MakerChangedCallback - { - BusinessId = request.BusinessId, - BusinessType = request.BusinessType, - InstanceId = instance.Id, - Type = instance.Type, - NextUserId = long.Parse(marker) - }); - } - } + result = await Create_StartWorkflow(task); + if (!result.Succeeded) + return result; } result = await OnTaskCreated(task); @@ -212,6 +248,50 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction } } + /// + /// 创建并启动审批工作流 + /// + /// + /// + protected internal async Task Create_StartWorkflow(BusinessTask task) + { + var template = await FindTemplateAsync(AuditType.SeaExport); + if (template == null) + return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TemplateNotFound)); + + var result = FlowService.Value.CreateFlowInstance(new CreateFlowInstanceReq + { + BusinessId = task.BusinessId, + BusinessType = BusinessType.OceanShippingExport, + TemplateId = template.Id + }); + //创建并启动实例 + if (result.Succeeded) + { + var instance = result.Data as FlowInstance; + task.FlowId = instance.Id; + await TenantDb.Updateable(task).UpdateColumns(x => x.FlowId).ExecuteCommandAsync(); + + result = FlowService.Value.StartFlowInstance(instance.Id.ToString()); + instance = result.Data as FlowInstance; + //工作流为会签,需要更新任务接收人 + if (result.Succeeded && instance.ActivityType == 0) + { + var marker = FlowInstanceService.GetNextMarker(instance); + await UpdateReceiverAsync(new MakerChangedCallback + { + BusinessId = task.BusinessId, + BusinessType = task.BusinessType, + InstanceId = instance.Id, + Type = instance.Type, + NextUserId = long.Parse(marker) + }); + } + } + + return result; + } + /// /// 当任务创建时调用 /// @@ -242,14 +322,19 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction if (!result.Succeeded) return result; - //更新当前任务状态 - BusinessTask task = await GetTaskAsync(request.BusinessId, request.BusinessType, request.TaskType); + BusinessTask task = await GetQuery(request.BusinessId, request.BusinessType, request.TaskType).FirstAsync(); if (task == null) return DataResult.FailedWithDesc(nameof(MultiLanguageConst.EmptyData)); + if (task.TaskStatus == TaskStatusEnum.Complete) + return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TaskCompleted)); + if (task.TaskStatus == TaskStatusEnum.Cancel) + return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TaskCancelled)); + //触发任务状态变更通知 if (task.TaskStatus != request.TaskStatus) await OnTaskStatusChanged(request); + //更新当前任务状态 task.TaskStatus = request.TaskStatus; if (task.TaskType == TaskBaseTypeEnum.WAIT_ORDER_AUDIT) task.FlowId = null; @@ -306,8 +391,24 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction public virtual async Task UpdateReceiverAsync(MakerChangedCallback callback) { ArgumentNullException.ThrowIfNull(callback, nameof(callback)); - + if (callback.NextUserId == null) + return; + + var users = await GetRecvUsers(callback.NextUserId.Value); + var result = await ManagerService.TransferTask(callback.BusinessId, TaskBaseTypeEnum.WAIT_ORDER_AUDIT, users); + if (!result.Succeeded) + { + //记录日志 + await new ApplicationException("任务API调用失败:" + result.Message).LogAsync(Db); + return; + } + + string recvUser = callback.NextUserId.Value.ToString(); + await TenantDb.Updateable().Where(x => x.BusinessId == callback.BusinessId && + x.BusinessType == callback.BusinessType && x.TaskType == TaskBaseTypeEnum.WAIT_ORDER_AUDIT) + .SetColumns(x => x.RecvUsers == recvUser) + .ExecuteCommandAsync(); } /// @@ -320,25 +421,26 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction { ArgumentNullException.ThrowIfNull(callback, nameof(callback)); - //更新任务状态为完成 + //根据审批结果更新任务状态 await SetTaskStatusAsync(new TaskUpdateRequest { BusinessId = callback.BusinessId, BusinessType = callback.BusinessType.GetValueOrDefault(), TaskType = TaskBaseTypeEnum.WAIT_ORDER_AUDIT, - TaskStatus = TaskStatusEnum.Complete + TaskStatus = callback.FlowStatus == FlowStatusEnum.Approve ? TaskStatusEnum.Complete : TaskStatusEnum.Pending, + AutoCreateNext = callback.FlowStatus == FlowStatusEnum.Approve }); if (callback.FlowStatus == FlowStatusEnum.Reject) { //创建审单驳回任务以进行通知 - var task = await GetTaskAsync(callback.BusinessId, callback.BusinessType.GetValueOrDefault(), TaskBaseTypeEnum.WAIT_ORDER_AUDIT); + var task = await GetQuery(callback.BusinessId, callback.BusinessType.GetValueOrDefault(), TaskBaseTypeEnum.WAIT_ORDER_AUDIT).FirstAsync(); await CreateTaskAsync(new TaskCreationRequest { BusinessId = callback.BusinessId, BusinessType = callback.BusinessType.GetValueOrDefault(), TaskType = TaskBaseTypeEnum.ORDER_AUDIT_REJECTED, - RecvUserIdList = task.RecvUserIdArray + RecvUserIdList = [task.CreateBy] //通知任务发起人 }); } } @@ -350,29 +452,12 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction /// 业务类型 /// 任务类型 /// - protected internal async Task GetTaskAsync(long id, BusinessType businessType, TaskBaseTypeEnum taskType) + protected internal ISugarQueryable GetQuery(long id, BusinessType businessType, TaskBaseTypeEnum taskType) { - return await TenantDb.Queryable().FirstAsync(x => + return TenantDb.Queryable().Where(x => x.BusinessId == id && x.BusinessType == businessType && x.TaskType == taskType); } - /// - /// 获取给定任务的下一任务类型 - /// - /// 任务信息 - /// - public static TaskBaseTypeEnum? GetNextType(BusinessTask current) - { - if (current.TaskType == TaskBaseTypeEnum.WAIT_CHECKOUT_BILL) //流程的最后一步 - return null; - - int currentTypeVal = (int)current.TaskType; - if (currentTypeVal >= 300) //300开始的枚举值为可选服务项目,不存在前后关联性 - return null; - - return (TaskBaseTypeEnum)currentTypeVal++; - } - /// /// 获取任务接收用户列表 ///