using DS.Module.Core; using DS.Module.Core.Condition; using DS.Module.Core.Constants; using DS.Module.Core.Data; using DS.Module.Core.Enums.TaskPlat; using DS.Module.Core.Extensions; using DS.Module.DjyServiceStatus; using DS.Module.SqlSugar; using DS.Module.UserModule; using DS.WMS.Core.Code.Dtos; using DS.WMS.Core.Flow.Entity; using DS.WMS.Core.Map.Dtos; using DS.WMS.Core.Op.Dtos; using DS.WMS.Core.Op.Entity; using DS.WMS.Core.Op.Interface; using DS.WMS.Core.Sys.Entity; using DS.WMS.Core.TaskInteraction.Entity; using DS.WMS.Core.TaskPlat.Dtos; using DS.WMS.Core.TaskPlat.Entity; using DS.WMS.Core.TaskPlat.Interface; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using SqlSugar; using System.Linq.Expressions; using System.Runtime.InteropServices; using System.Text; using System.Web; namespace DS.WMS.Core.TaskPlat.Method { /// /// 任务模块业务类的基类,封装了一些常用的方法 /// public class TaskManageBaseService : ITaskManageBaseService { // 实例化时构建 protected readonly IUser user; //protected readonly ILogger logger; protected readonly ILogger logger; protected readonly ISaasDbService saasDbService; protected readonly IServiceProvider serviceProvider; protected readonly IWebHostEnvironment environment; protected readonly ISqlSugarClient db; // 按需构建 protected Lazy allocationService; protected Lazy seaExportCommonService; protected Lazy djyServiceStatusService; protected static readonly string createStatusStr = TaskStatusEnum.Create.ToString(); protected static readonly string pendingStatusStr = TaskStatusEnum.Pending.ToString(); protected static readonly string completeStatusStr = TaskStatusEnum.Complete.ToString(); public TaskManageBaseService(IUser user, //ILogger logger, ISaasDbService saasDbService, IServiceProvider serviceProvider, IWebHostEnvironment environment) { this.user = user; //this.logger = logger; this.saasDbService = saasDbService; this.serviceProvider = serviceProvider; this.environment = environment; db = serviceProvider.GetRequiredService(); allocationService = new Lazy(serviceProvider.GetRequiredService()); seaExportCommonService = new Lazy(serviceProvider.GetRequiredService()); djyServiceStatusService = new Lazy(serviceProvider.GetRequiredService()); var loggerFactory = serviceProvider.GetRequiredService(); logger = loggerFactory.CreateLogger("TaskFlowLogger"); } /// /// 更新任务主表状态 /// /// 任务主键数组 /// 需要更新状态的列 public async Task SetTaskStatus(long[] taskIds, params Expression>[] columns) { logger.LogInformation($"taskIds={string.Join(",", taskIds ?? [])}"); SqlSugarScopeProvider tenantDb = saasDbService.GetBizDbScopeById(user.TenantId); //任务不考虑OrgId,这里去掉 tenantDb.QueryFilter.Clear(); var updateable = tenantDb.Updateable(); foreach (var item in columns) { updateable.SetColumns(item); } updateable.SetColumns(x => x.UpdateBy == long.Parse(user.UserId)) .SetColumns(x => x.UpdateTime == DateTime.Now) .SetColumns(x => x.UpdateUserName == user.UserName); await updateable.Where(x => taskIds.Contains(x.Id)) .ExecuteCommandAsync(); // 后面可以记录日志 } /// /// 设置任务处理人 /// /// 任务主键数组 /// 人员信息列表 public async Task SetTaskOwner(long[] taskIds, List userInfo) { logger.LogInformation($"taskIds={string.Join(",", taskIds ?? [])};userInfo={JsonConvert.SerializeObject(userInfo)}"); SqlSugarScopeProvider tenantDb = saasDbService.GetBizDbScopeById(user.TenantId); //任务不考虑OrgId,这里去掉 tenantDb.QueryFilter.Clear(); try { var taskList = await tenantDb.Queryable().Where(x => taskIds.Contains(x.Id)).ToListAsync(x => new { x.Id, x.STATUS, x.STATUS_NAME, x.TASK_TYPE, x.OUT_BS_NO, x.TASK_SOURCE }); var taskIdList = taskList.Select(x => x.Id).ToList(); var taskTypeList = taskList.Where(x => x.TASK_SOURCE == TaskSourceEnum.WORK_FLOW.ToString() && x.OUT_BS_NO != null).Select(x => x.TASK_TYPE).Distinct().ToList(); var taskCompleteStatusCodeList = taskTypeList.Count > 0 ? await tenantDb.Queryable() .Where(x => x.ModuleType == 2 && taskTypeList.Contains(x.TaskType)) .Select(x => new { x.TaskType, x.CompletedBusinessStatusCode }) .ToListAsync() : []; var userIdList = userInfo.Select(x => x.RecvUserId).Distinct().ToList(); var userWithOrgMap = await db.Queryable().Where(x => userIdList.Contains(x.Id)).Select(x => new { x.Id, x.DefaultOrgId }).ToListAsync(); List allocationList = new(); foreach (var item in taskList) { var config = taskCompleteStatusCodeList.FirstOrDefault(x => x.TaskType == item.TASK_TYPE); var allots = userInfo.Select(x => new TaskBaseAllocation { TaskId = item.Id, UserId = x.RecvUserId, UserName = x.RecvUserName, Status = item.STATUS, StatusName = item.STATUS_NAME, StatusTime = DateTime.Now, BusinessId = item.OUT_BS_NO, GoodStatusCode = config?.CompletedBusinessStatusCode, OrgId = userWithOrgMap.FirstOrDefault(m => m.Id == x.RecvUserId)?.DefaultOrgId ?? 0 }); allocationList.AddRange(allots); } // 用于更新工作流的任务 var userIdStr = string.Join(',', userInfo.Select(x => x.RecvUserId)); //await tenantDb.Ado.BeginTranAsync(); await tenantDb.AsTenant().BeginTranAsync(); var idList = await tenantDb.Queryable().Where(x => taskIdList.Contains(x.TaskId)).Select(x => x.Id).ToListAsync(); await tenantDb.Deleteable(x => idList.Contains(x.Id)).ExecuteCommandAsync(); await tenantDb.Insertable(allocationList).ExecuteCommandAsync(); await tenantDb.Updateable() .SetColumns(x => x.IS_PUBLIC == 0) .Where(x => taskIdList.Contains(x.Id)) .ExecuteCommandAsync(); foreach (var item in taskList) { if (item.OUT_BS_NO is not (null or 0) && Enum.TryParse(typeof(TaskBaseTypeEnum), item.TASK_TYPE, out object? taskType)) { var waitUpdateBusinessTaskIdList = await tenantDb.Queryable() .Where(x => x.BusinessId == item.OUT_BS_NO && x.TaskType == (TaskBaseTypeEnum)taskType) .Select(x => x.Id) .ToListAsync(); if (waitUpdateBusinessTaskIdList.Count > 0) { await tenantDb.Updateable() .SetColumns(x => x.RecvUsers == userIdStr) .Where(x => waitUpdateBusinessTaskIdList.Contains(x.Id)) .ExecuteCommandAsync(); } var waitUpdateFlowInstanceId = await db.Queryable() .ClearFilter(typeof(ITenantId)) .Where(y => y.BusinessId == item.OUT_BS_NO && y.AuditType == (TaskBaseTypeEnum)taskType) .OrderByDescending(y => y.Id) .Select(y => y.Id) .FirstAsync(); if (waitUpdateFlowInstanceId != 0) { await db.Updateable() .SetColumns(x => x.MakerList == userIdStr) .Where(x => x.Id == waitUpdateFlowInstanceId) .ExecuteCommandAsync(); } } } //await tenantDb.Ado.CommitTranAsync(); await tenantDb.AsTenant().CommitTranAsync(); } catch (Exception) { //await tenantDb.Ado.RollbackTranAsync(); await tenantDb.AsTenant().RollbackTranAsync(); throw; } } #region Tools /// /// 保存文件并返回文件完整路径 /// /// 追加文件夹 /// 文件二进制流 /// 批次号 /// 无拓展名的文件名 /// 文件类型 /// 附件类型 bcfiles-BC文件 sofile-订舱附件 /// 返回文件完整路径 protected async Task SaveFile(string fileDictKey, byte[] fileBytes, string batchNo, string fileNameNoSuffix, PrintFileTypeEnum printFileType, string attachFileType = "sofiles") { // 获取文件存盘时保存的物理文件名:fileName var fileType = string.Empty; if (printFileType == PrintFileTypeEnum.PDF) { fileType = ".pdf"; } else if (printFileType == PrintFileTypeEnum.XLSX) { fileType = ".xlsx"; } else if (printFileType == PrintFileTypeEnum.DOCX) { fileType = ".docx"; } else if (printFileType == PrintFileTypeEnum.XLS) { fileType = ".xls"; } else if (printFileType == PrintFileTypeEnum.DOC) { fileType = ".doc"; } var fileName = $"{fileNameNoSuffix}{fileType}"; // 文件存盘时保存的物理文件名 // 获取文件存库时保存的相对路径:fileInfoRelativePathWithName var fileInfoRelativeDic = string.Empty; if (!string.IsNullOrWhiteSpace(attachFileType)) fileInfoRelativeDic = Path.Combine(fileInfoRelativeDic, attachFileType); if (!string.IsNullOrWhiteSpace(fileDictKey)) fileInfoRelativeDic = Path.Combine(fileInfoRelativeDic, fileDictKey); // 文件存库时保存的相对路径 var fileInfoRelativePathWithName = Path.Combine(fileInfoRelativeDic, fileName); // 文件存库时保存的相对路径 // 获取文件存盘所需的绝对路径:absFilePath var absFilePath = string.Empty; var baseDicConfig = AppSetting.app(new string[] { "FileSettings", "BasePath" }); var relativeDicConfig = AppSetting.app(new string[] { "FileSettings", "RelativePath" }); if (string.IsNullOrEmpty(baseDicConfig)) { absFilePath = Path.Combine(environment.WebRootPath ?? "", relativeDicConfig, fileInfoRelativeDic); } else { absFilePath = Path.Combine(baseDicConfig, relativeDicConfig, fileInfoRelativeDic); } if (!Directory.Exists(absFilePath)) Directory.CreateDirectory(absFilePath); absFilePath = Path.Combine(absFilePath, fileName); if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { fileInfoRelativePathWithName = fileInfoRelativePathWithName.Replace("\\", "/"); absFilePath = absFilePath.Replace("\\", "/"); } await File.WriteAllBytesAsync(absFilePath, fileBytes); return fileInfoRelativePathWithName; } /// /// 获取文件类型 /// /// 文件完成路径 /// 返回文件类型枚举 protected PrintFileTypeEnum GetFileType(string fileName) { PrintFileTypeEnum fileType = PrintFileTypeEnum.PDF; switch (Path.GetExtension(fileName).ToLower()) { case ".pdf": fileType = PrintFileTypeEnum.PDF; break; case ".xlsx": fileType = PrintFileTypeEnum.XLSX; break; case ".docx": fileType = PrintFileTypeEnum.DOCX; break; case ".xls": fileType = PrintFileTypeEnum.XLS; break; case ".doc": fileType = PrintFileTypeEnum.DOC; break; } return fileType; } #endregion /// /// 根据任务ID获取附件信息 /// /// 任务Id /// 附件分类代码 public async Task<(string fileFullPath, string fileName)> GetTaskFileInfo(long taskId, string fileCategory) { var tenantDb = saasDbService.GetBizDbScopeById(user.TenantId); //任务不考虑OrgId,这里去掉 tenantDb.QueryFilter.Clear(); var bcTaskInfo = await tenantDb.Queryable().Where(u => u.Id == taskId).FirstAsync(); if (bcTaskInfo == null) { throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.DataQueryNoData))); } TaskFileCategoryEnum fileCategoryEnum = TaskFileCategoryEnum.NONE; System.Enum.TryParse(fileCategory, out fileCategoryEnum); if (fileCategoryEnum == TaskFileCategoryEnum.NONE) { // 附件分类代码错误,请提供正确的分类代码 throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.TaskFileCategoryError))); } string name = fileCategoryEnum.ToString(); var fileInfo = await tenantDb.Queryable().Where(u => u.TASK_PKID == taskId && u.FILE_CATEGORY == name).OrderByDescending(x => x.Id).FirstAsync(); if (fileInfo == null) { // 附件分类代码错误,请提供正确的分类代码 throw new Exception( string.Format(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.TaskFileEmpty)), taskId) ); } var baseDicConfig = AppSetting.app(new string[] { "FileSettings", "BasePath" }); var relativeDicConfig = AppSetting.app(new string[] { "FileSettings", "RelativePath" }); string absFilePath; if (string.IsNullOrEmpty(baseDicConfig)) { absFilePath = Path.Combine(environment.WebRootPath ?? "", relativeDicConfig, fileInfo.FILE_PATH); } else { absFilePath = Path.Combine(baseDicConfig, relativeDicConfig, fileInfo.FILE_PATH); } if (!File.Exists(absFilePath)) { logger.LogError("根据任务主键获取文件信息失败:文件不存在,fileFullPath={fileFullPath}", absFilePath); //任务主键{0} 附件下载请求失败,请确认文件是否存在 throw new Exception( string.Format(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.TaskFileNotExists)), taskId) ); } var fileName = HttpUtility.UrlEncode(fileInfo.FILE_NAME, Encoding.GetEncoding("UTF-8"))!; return (absFilePath, fileName); //return (new FileStream(fileFullPath, FileMode.Open), fileName); } /// /// 根据订单及配置,将所有或指定的公共任务匹配到个人 /// /// 任务Id列表(当传入时,则只匹配列表中指定的任务) /// 涉及当前登陆人的匹配结果 public async Task> MatchTask(List? taskIdList = null) { /* * * 测试库测试用Sql: SELECT t.SplitOrMergeFlag,t.OperatorId,t.OperatorName,t.Doc,t.DocName,t.CustomerService,t.CustomerServiceName,t.ForeignCustomerService,t.ForeignCustomerServiceName,t.Sale,t.SaleId,t. * FROM `op_sea_export` t where Deleted=0 and id In(1816649497120477184,1816779333432381440,1780891904372772864) order by id desc SELECT t.SplitOrMergeFlag,t.OperatorId,t.OperatorName,t.Doc,t.DocName,t.CustomerService,t.CustomerServiceName,t.ForeignCustomerService,t.ForeignCustomerServiceName,t.Sale,t.SaleId,t. * FROM `op_sea_export` t where Deleted=0 and id In(1813475270208917504,1813509723408961536,1816277472539447296) order by id desc */ MatchTaskResultDto result = new MatchTaskResultDto(); var tenantDb = saasDbService.GetBizDbScopeById(user.TenantId); //任务不考虑OrgId,这里去掉 tenantDb.QueryFilter.Clear(); var time = DateTime.Now.AddMonths(-3); var taskList = await tenantDb.Queryable() .Where(x => x.IS_PUBLIC == 1 && x.STATUS == TaskStatusEnum.Create.ToString() && !string.IsNullOrEmpty(x.MBL_NO) && x.CreateTime > time) .WhereIF(taskIdList != null && taskIdList.Count > 0, x => taskIdList!.Contains(x.Id)) //.Where(x => x.Id == 1813475270208917504 || x.Id == 1816277472539447296 || x.Id == 1813509723408961536) .ToListAsync(x => new TaskBaseInfo { Id = x.Id, MBL_NO = x.MBL_NO, TASK_TYPE = x.TASK_TYPE, TASK_TYPE_NAME = x.TASK_TYPE_NAME, //CARRIER_ID = x.CARRIER_ID, }); //logger.LogInformation($"MatchTask共查询出{taskList.Count}条待匹配的记录,taskList:{string.Join(',', taskList.Select(x => x.Id).Take(50))}"); var allotSetCache = await allocationService.Value.GetAllList(); if (!allotSetCache.Succeeded || (allotSetCache.Data?.Count ?? 0) == 0) { return DataResult.Success("操作成功!", result, MultiLanguageConst.DataUpdateSuccess); } var taskTypeStrList = taskList.Select(x => x.TASK_TYPE).Distinct().ToList(); var allotSetList = allotSetCache.Data.Where(x => taskTypeStrList.Contains(x.TaskTypeCode)).ToList(); if (allotSetList.Count == 0) { return DataResult.Success("操作成功!", result, MultiLanguageConst.DataUpdateSuccess); } //else //{ // allotSetList.Add(new TaskAllocationtSetDto() // { // IsAllotOperator = true, // TaskTypeCode = TaskBaseTypeEnum.TRNAS_PLAN_HAS_CHANGE.ToString(), // }); //} // 需要查询的订单的提单号的集合,用于一次性将需要查询的订单查询出来; // 后续如果需要查询舱位,可以再补充字段如List waitQuerySlotWithMblnoList = new(); HashSet waitQuerySeaExportWithMblnoList = new(); // 分配规则 Dictionary> allotTargetList = new(); foreach (var taskItem in taskList) { List taskItemAllotSetList = allotSetList.Where(x => x.TaskTypeCode == taskItem.TASK_TYPE).ToList(); foreach (var allotSetItem in taskItemAllotSetList) { // 这里先存下来,后面再统一查库,减少查询次数 // 如果配置的下面四种接收对象,则需要查询订单 if (allotSetItem.IsAllotCustomerService || allotSetItem.IsAllotSale || allotSetItem.IsAllotOperator || allotSetItem.IsAllotVouchingClerk) { waitQuerySeaExportWithMblnoList.Add(taskItem.MBL_NO!); } } } // 查出涉及到的订单 var seaExportList = await tenantDb.Queryable() .Where(x => x.ParentId == 0 && ( (x.SplitOrMergeFlag == 0 && waitQuerySeaExportWithMblnoList.Contains(x.MBLNO)) || (x.SplitOrMergeFlag == 1 && waitQuerySeaExportWithMblnoList.Contains(x.BookingNo)) )).Select().ToListAsync(); //seaExportList = seaExportList.Where(x=>x.MBLNO == "246019438").ToList(); List<(TaskBaseInfo, List)> allotData = new(); foreach (var taskItem in taskList) { var recvUserList = new List(); List taskItemAllotSetList = allotSetList.Where(x => x.TaskTypeCode == taskItem.TASK_TYPE).ToList(); var taskItemAllotList = new List(); foreach (var allotSetItem in taskItemAllotSetList) { // 验证条件 if (!string.IsNullOrEmpty(allotSetItem.Condition)) { var contitionContent = JsonConvert.DeserializeObject(allotSetItem.Condition!)!; TaskFlowDataContext dataContext = new(); if (allotSetItem.IsAllotCustomerService || allotSetItem.IsAllotSale || allotSetItem.IsAllotOperator || allotSetItem.IsAllotVouchingClerk) { var seaExport = seaExportList.FirstOrDefault(x => (x.SplitOrMergeFlag == 0 && taskItem.MBL_NO == x.MBLNO) || (x.SplitOrMergeFlag == 1 && taskItem.MBL_NO == x.BookingNo)); if (seaExport == null) continue; // 这里为了效率,设置为如果订单为空,则跳过;后面如果需要判断其他表,需要把这里注释掉 dataContext.Set(TaskFlowDataNameConst.Business, seaExport); } if (!ConditionHelper.IsPass(contitionContent, dataContext)) continue; } if (allotSetItem.IsAllotCustomerService || allotSetItem.IsAllotSale || allotSetItem.IsAllotOperator || allotSetItem.IsAllotVouchingClerk) { var order = seaExportList.FirstOrDefault(x => (x.SplitOrMergeFlag == 0 && taskItem.MBL_NO == x.MBLNO) || (x.SplitOrMergeFlag == 1 && taskItem.MBL_NO == x.BookingNo)); if (order == null) { continue; } /* * 操作Operator=订单里的:OperatorId+OperatorName * 单证VouchingClerk=订单里的:Doc+DocName * 销售Sale=订单里的:SaleId+Sale * 客服CustomerService=订单里的:CustomerService+CustomerServiceName / ForeignCustomerService+ForeignCustomerServiceName */ if (allotSetItem.IsAllotCustomerService) { if (order.CustomerService != 0 && !string.IsNullOrEmpty(order.CustomerServiceName)) { recvUserList.Add(new RecvUserInfo(order.CustomerService, order.CustomerServiceName)); } if (order.ForeignCustomerService != 0 && !string.IsNullOrEmpty(order.ForeignCustomerServiceName)) { recvUserList.Add(new RecvUserInfo(order.ForeignCustomerService, order.ForeignCustomerServiceName)); } } if (allotSetItem.IsAllotOperator && order.OperatorId != 0 && !string.IsNullOrEmpty(order.OperatorName)) { recvUserList.Add(new RecvUserInfo(order.OperatorId, order.OperatorName)); } if (allotSetItem.IsAllotSale && order.SaleId != 0 && !string.IsNullOrEmpty(order.Sale)) { recvUserList.Add(new RecvUserInfo(order.SaleId, order.Sale)); } if (allotSetItem.IsAllotVouchingClerk && order.Doc != 0 && !string.IsNullOrEmpty(order.DocName)) { recvUserList.Add(new RecvUserInfo(order.Doc, order.DocName)); } } } if (recvUserList.Count != 0) { recvUserList = recvUserList.DistinctBy(x => x.RecvUserId).ToList(); allotData.Add((taskItem, recvUserList)); await SetTaskOwner([taskItem.Id], recvUserList); } } return DataResult.Success("操作成功!", result, MultiLanguageConst.DataUpdateSuccess); } /// /// 通过任务主表主键设置任务状态(任务台使用) /// /// 任务主表主键 /// 业务状态 /// 状态发生时间 /// 业务主键 public async Task SetTaskStatus(long taskBaseId, TaskStatusEnum taskStatusEnum, DateTime? statusTime, long? bsno = null) { logger.LogInformation($"taskBaseId={taskBaseId};taskStatusEnum={taskStatusEnum};statusTime={statusTime};bsno={bsno}"); SqlSugarScopeProvider tenantDb = saasDbService.GetBizDbScopeById(user.TenantId); TaskBaseInfo taskInfo = await tenantDb.Queryable().ClearFilter(typeof(IOrgId)) .Where(t => t.Id == taskBaseId) .FirstAsync(); return await SetTaskStatus(taskInfo, taskStatusEnum, statusTime, false, bsno); } /// /// 通过任务主表对象设置任务状态(通用) /// /// 任务主表对象 /// 业务状态 /// 状态发生时间 /// 完成任务前是否检查所有子任务是否完成 /// 业务主键 /// 任务描述 public async Task SetTaskStatus(TaskBaseInfo taskInfo, TaskStatusEnum taskStatusEnum, DateTime? statusTime, bool isCheckAllChildTaskComplete, long? bsno = null, string? taskDesc = null) { if (taskInfo is null) { throw new ArgumentNullException(nameof(taskInfo)); } logger.LogInformation($"通用方法 taskInfo={JsonConvert.SerializeObject(taskInfo)};taskStatusEnum={taskStatusEnum};statusTime={statusTime};isCheckAllChildTaskComplete={isCheckAllChildTaskComplete};bsno={bsno};taskDesc={taskDesc}"); SqlSugarScopeProvider tenantDb = saasDbService.GetBizDbScopeById(user.TenantId); if (!taskInfo.IsChild && isCheckAllChildTaskComplete && taskStatusEnum == TaskStatusEnum.Complete) { if (await tenantDb.Queryable() .Where(x => x.IsChild == true && x.ParentTaskId == taskInfo.Id && (x.STATUS == createStatusStr || x.STATUS == pendingStatusStr)) .AnyAsync()) { return DataResult.Failed("任务设置完成前,需要所有子任务非待处理中或挂起中"); } } // 修改任务的状态 string taskStatusStr = taskStatusEnum.ToString(); string taskStatusNameStr = taskStatusEnum.EnumDescription(); taskInfo.STATUS = taskStatusStr; taskInfo.STATUS_NAME = taskStatusNameStr; taskInfo.RealUserId = long.Parse(user.UserId); taskInfo.RealUserName = user.UserName; if (!string.IsNullOrWhiteSpace(taskDesc)) { taskInfo.TASK_DESP = taskDesc; } if (taskStatusEnum == TaskStatusEnum.Complete) { taskInfo.IS_COMPLETE = 1; taskInfo.COMPLETE_DATE = statusTime; } // 任务状态为“完成” && 来源为工作流 && 非子任务 时要做的工作: if (taskStatusEnum == TaskStatusEnum.Complete && taskInfo.TASK_SOURCE == TaskSourceEnum.WORK_FLOW.ToString() && !taskInfo.IsChild) { long? orderId = bsno; if (orderId == null || orderId == 0) { if (long.TryParse(taskInfo.BOOK_ORDER_NO, out long temp)) { orderId = temp; } } if (orderId != null && orderId != 0) { string? statusCode = await tenantDb.Queryable().Where(x => x.ModuleType == 2 && x.TaskType == taskInfo.TASK_TYPE).Select(x => x.CompletedBusinessStatusCode).FirstAsync(); if (!string.IsNullOrEmpty(statusCode)) { try { // 1.设置相关订单的业务状态 await seaExportCommonService.Value.SetGoodsStatus(statusCode, (long)orderId, tenantDb); } catch (Exception ex) { logger.LogError(ex, "任务完成时,设置订单业务状态的过程中发生异常,orderId={0},taskType={1}", orderId, taskInfo.TASK_TYPE); throw; } try { // 2.设置货物状态为已完成 await djyServiceStatusService.Value.SaveServiceStatus(new EmbedServiceProjectStatusDto() { businessId = orderId.ToString()!, SourceType = 1, StatusCodes = [new() { StatusCode = statusCode }] }); } catch (Exception ex) { logger.LogError(ex, "任务完成时,设置订单的货物状态时发生异常,orderId={0},taskType={1}", orderId, taskInfo.TASK_TYPE); throw; } } } } try { var taskBaseAllocationList = await tenantDb.Queryable().Where(x => x.TaskId == taskInfo.Id && x.Status != taskStatusStr).ToListAsync(); List waitUpdateChildTaskIdList = []; if (!taskInfo.IsChild) { waitUpdateChildTaskIdList = await tenantDb.Queryable() .Where(x => x.IsChild == true && x.ParentTaskId == taskInfo.Id && x.STATUS != taskStatusStr) .Select(x => x.Id) .ToListAsync(); } await tenantDb.Ado.BeginTranAsync(); // 更新主任务的状态 await tenantDb.Updateable(taskInfo).UpdateColumns(x => new { x.UpdateBy, x.UpdateTime, x.UpdateUserName, x.COMPLETE_DATE, x.IS_COMPLETE, x.STATUS, x.STATUS_NAME, x.RealUserId, x.RealUserName }).UpdateColumnsIF(!string.IsNullOrWhiteSpace(taskDesc), x => new { x.TASK_DESP }).ExecuteCommandAsync(); // 更新主任务的任务接收人下的状态 if (taskBaseAllocationList.Count != 0) { taskBaseAllocationList.ForEach(x => { x.Status = taskStatusStr; x.StatusName = taskStatusNameStr; x.StatusTime = statusTime; }); await tenantDb.Updateable(taskBaseAllocationList).UpdateColumns(x => new { x.UpdateBy, x.UpdateTime, x.UpdateUserName, x.Status, x.StatusName, x.StatusTime }).ExecuteCommandAsync(); } if (!taskInfo.IsChild && waitUpdateChildTaskIdList.Count > 0) { // 更新子任务的状态 await tenantDb.Updateable() .SetColumns(x => new TaskBaseInfo() { UpdateBy = long.Parse(user.UserId), UpdateTime = DateTime.Now, UpdateUserName = user.UserName, IS_COMPLETE = taskInfo.IS_COMPLETE, COMPLETE_DATE = taskInfo.COMPLETE_DATE, STATUS = taskInfo.STATUS, STATUS_NAME = taskInfo.STATUS_NAME, RealUserId = taskInfo.RealUserId, RealUserName = taskInfo.RealUserName, }) .Where(x => waitUpdateChildTaskIdList.Contains(x.Id) && x.STATUS != taskStatusStr) .ExecuteCommandAsync(); // 更新子任务的任务接收人下的状态 await tenantDb.Updateable() .SetColumns(x => new TaskBaseAllocation() { UpdateBy = long.Parse(user.UserId), UpdateTime = DateTime.Now, UpdateUserName = user.UserName, Status = taskInfo.STATUS, StatusName = taskInfo.STATUS_NAME, StatusTime = statusTime, }) .Where(x => waitUpdateChildTaskIdList.Contains(x.TaskId) && x.Status != taskStatusStr) .ExecuteCommandAsync(); } await tenantDb.Ado.CommitTranAsync(); } catch (Exception) { await tenantDb.Ado.RollbackTranAsync(); throw; } return DataResult.Successed(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.DataUpdateSuccess))); } /// /// 是否具有指定任务列表的处理权限 /// /// 成功:全部具有处理权限;失败:存在不具有处理权限的任务,同时返回任务流水号列表 public async Task>> HasTaskHandleAuthorityWithBsno(IEnumerable<(long bsno, TaskBaseTypeEnum taskType)> businessTaskList) { if (businessTaskList == null || businessTaskList.Count() == 0) { return DataResult>.Success([]); } SqlSugarScopeProvider tenantDb = saasDbService.GetBizDbScopeById(user.TenantId); var userId = long.Parse(user.UserId); List taskIdList = []; foreach (var (bsno, taskType) in businessTaskList) { var taskTypeStr = taskType.ToString(); var taskId = await tenantDb.Queryable().Where(x => x.OUT_BS_NO == bsno && x.TASK_TYPE == taskTypeStr && x.STATUS != TaskStatusEnum.Cancel.ToString()).Select(x => x.Id).FirstAsync(); if (taskId != 0) { taskIdList.Add(taskId); } } return await HasTaskHandleAuthority(taskIdList); } /// /// 是否具有指定任务列表的处理权限 /// /// 成功:全部具有处理权限;失败:存在不具有处理权限的任务,同时返回任务流水号列表 public async Task>> HasTaskHandleAuthority(IEnumerable taskIdList) { if (taskIdList == null || taskIdList.Count() == 0) { return DataResult>.Success([]); } SqlSugarScopeProvider tenantDb = saasDbService.GetBizDbScopeById(user.TenantId); var userId = long.Parse(user.UserId); var taskList = await tenantDb.Queryable().Where(x => taskIdList.Contains(x.Id) && x.IS_PUBLIC == 0).Select(x => new { x.Id, x.TASK_NO }).ToListAsync(); var newTaskIdList = taskList.Select(x => x.Id); var hasAuthorityTaskIdList = await tenantDb.Queryable().Where(x => newTaskIdList.Contains(x.TaskId) && x.UserId == userId).Select(x => x.TaskId).ToListAsync(); var notHasAuthorityTaskIdList = newTaskIdList.Except(hasAuthorityTaskIdList); if (notHasAuthorityTaskIdList.Any()) { var taskNoList = taskList.Where(x => notHasAuthorityTaskIdList.Contains(x.Id)).Select(x => x.TASK_NO).ToList(); return DataResult>.FailedData(taskNoList); } else { return DataResult>.Success([]); } } /// /// 根据订单Id列表获取关联的任务流水号 /// public async Task>> GetSeaExportAllotTaskNo(IEnumerable seaExportIdList) { if (seaExportIdList == null || seaExportIdList.Count() == 0) { return DataResult>.Success([]); } var tenantDb = saasDbService.GetBizDbScopeById(user.TenantId); var taskNoList = await tenantDb.Queryable() .Where(x => x.OUT_BS_NO != null && seaExportIdList.Contains((long)x.OUT_BS_NO) && x.STATUS == TaskStatusEnum.Create.ToString()) .Select(x => x.TASK_NO) .ToListAsync(); return DataResult>.Success(taskNoList); } #region 根据收货地港口英文名解析出起始港对象 /// /// 根据收货地港口英文名解析出起始港对象 /// /// 收货地港口英文名 /// 起始港缓存 /// 起始港缓存映射 /// 起始港对象 protected async Task> PlaceReceiptToPortload(string portEnName, List cachePortLoad, Func>>> cacheMapPortLoadFunc) { CodePortRes? portInfo = null; if (string.IsNullOrEmpty(portEnName)) { return DataResult.FailedData(portInfo); } // 匹配方式1:精准匹配 portInfo = cachePortLoad.FirstOrDefault(x => x.PortName.Equals(portEnName, StringComparison.OrdinalIgnoreCase)); if (portInfo != null) return DataResult.Success(portInfo); // 匹配方式2:起始模糊匹配 portInfo = cachePortLoad.FirstOrDefault(x => x.PortName.StartsWith(portEnName, StringComparison.OrdinalIgnoreCase)); if (portInfo != null) return DataResult.Success(portInfo); // 匹配方式3:完整模糊匹配 portInfo = cachePortLoad.FirstOrDefault(x => x.PortName.Contains(portEnName, StringComparison.OrdinalIgnoreCase)); if (portInfo != null) return DataResult.Success(portInfo); // 匹配方式4:精准映射匹配 var mapCachePortLoad = await cacheMapPortLoadFunc(); var map = mapCachePortLoad?.Data?.FirstOrDefault(x => x.Module == MappingModuleConst.RECEIPT_TO_PORTLOAD && x.MapName.Equals(portEnName, StringComparison.OrdinalIgnoreCase)); if (map != null) { portInfo = cachePortLoad.FirstOrDefault(x => x.Id == map.LinkId); if (portInfo != null) return DataResult.Success(portInfo); } return DataResult.FailedData(portInfo); } #endregion #region 根据交货地港口英文名解析出目的港对象 /// /// 根据交货地港口英文名解析出目的港对象 /// /// 交货地港口英文名 /// 目的港缓存 /// 目的港缓存映射 /// 目的港对象 protected async Task> PlaceDeliveryToPort(string portEnName, List cachePort, Func>>> cacheMapPortFunc) { CodePortRes? portInfo = null; if (string.IsNullOrEmpty(portEnName)) { return DataResult.FailedData(portInfo); } // 匹配方式1:精准匹配 portInfo = cachePort.FirstOrDefault(x => x.PortName.Equals(portEnName, StringComparison.OrdinalIgnoreCase)); if (portInfo != null) return DataResult.Success(portInfo); // 匹配方式2:起始模糊匹配 portInfo = cachePort.FirstOrDefault(x => x.PortName.StartsWith(portEnName, StringComparison.OrdinalIgnoreCase)); if (portInfo != null) return DataResult.Success(portInfo); // 匹配方式3:完整模糊匹配 portInfo = cachePort.FirstOrDefault(x => x.PortName.Contains(portEnName, StringComparison.OrdinalIgnoreCase)); if (portInfo != null) return DataResult.Success(portInfo); // 匹配方式4:精准映射匹配 var mapCachePort = await cacheMapPortFunc(); var map = mapCachePort?.Data?.FirstOrDefault(x => x.Module == MappingModuleConst.DELIVERY_TO_PORT && x.MapName.Equals(portEnName, StringComparison.OrdinalIgnoreCase)); if (map != null) { portInfo = cachePort.FirstOrDefault(x => x.Id == map.LinkId); if (portInfo != null) return DataResult.Success(portInfo); } return DataResult.FailedData(portInfo); } #endregion /// /// 获取不创建任务的任务类型列表 /// public async Task> GetNotCreateTaskTypeList(SqlSugarScopeProvider? tenantDb = null) { SqlSugarScopeProvider thisTenantDb = tenantDb ?? saasDbService.GetBizDbScopeById(user.TenantId); var configTypeStr = TaskConfigTypeCodeEnum.NotCreateTask.ToString(); var notCreateTaskTypeList = await thisTenantDb.Queryable() .Where(x => x.ConfigTypeCode == configTypeStr && x.ConfigValue == "1") .Select(x => x.TaskType) .ToListAsync(); List result = []; var type = typeof(TaskBaseTypeEnum); foreach (var taskType in notCreateTaskTypeList) { if (Enum.TryParse(type, taskType, out object? temp)) { result.Add((TaskBaseTypeEnum)temp); } } return result; } } }