using DS.Module.Core; using DS.Module.RedisModule; using DS.Module.SqlSugar; using DS.Module.UserModule; using DS.WMS.Core.Code.Interface; using DS.WMS.Core.Code.Method; using DS.WMS.Core.Map.Interface; using DS.WMS.Core.Map.Method; using DS.WMS.Core.Sys.Interface; using DS.WMS.Core.Sys.Method; using DS.WMS.Core.TaskPlat.Dtos; using DS.WMS.Core.TaskPlat.Entity; using DS.WMS.Core.TaskPlat.Interface; using Microsoft.Extensions.DependencyInjection; using SqlSugar; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Mapster; using DS.Module.DjyServiceStatus; using Microsoft.AspNetCore.Identity; using DS.WMS.Core.Op.Interface; using Masuit.Tools; using DS.WMS.Core.Op.Dtos; using DS.WMS.Core.Sys.Entity; using HtmlAgilityPack; using Microsoft.AspNetCore.Mvc; using Amazon.Runtime.Internal.Util; using Newtonsoft.Json; using NLog; using DS.Module.Core.Helpers; using System.Text.Json.Nodes; using LanguageExt.Pipes; using DS.WMS.Core.Op.Entity; using Org.BouncyCastle.Asn1.X9; using DS.WMS.Core.Op.EDI; using DS.WMS.Core.Sys.Dtos; using DS.WMS.Core.Code.Dtos; using DS.Module.Core.Data; using DS.WMS.Core.Op.Entity.TaskInteraction; using Microsoft.Extensions.Hosting; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Logging; using DS.WMS.Core.Op.Interface.TaskInteraction; using DS.WMS.Core.Op.Method.TaskInteraction; namespace DS.WMS.Core.TaskPlat.Method { /// /// 截止时间变更 /// public class TaskManageCutDateChangeService: TaskManageBaseService,ITaskManageCutDateChangeService { private readonly ISeaExportService _seaExportService; private readonly IConfigService _configService; private readonly IUserService _userService; private readonly ITaskLogService _logService; private readonly ITaskMailService _taskMailService; private readonly ITaskAllocationService _taskAllocationService; private readonly ISeaExportCommonService _seaExportCommonService; private readonly IBookingSlotService _bookingSlotService; public TaskManageCutDateChangeService(IUser user, ILogger logger, ISaasDbService saasDbService, IServiceProvider serviceProvider, IWebHostEnvironment environment) : base(user, logger, saasDbService, serviceProvider, environment) { user = serviceProvider.GetRequiredService(); _seaExportService = serviceProvider.GetRequiredService(); _configService = serviceProvider.GetRequiredService(); _userService = serviceProvider.GetRequiredService(); _taskMailService = serviceProvider.GetRequiredService(); _taskAllocationService = serviceProvider.GetRequiredService(); _seaExportCommonService = serviceProvider.GetRequiredService(); _bookingSlotService = serviceProvider.GetRequiredService(); } #region 通过任务主键获取截止时间变更详情 /// /// 通过任务主键获取截止时间变更详情 /// /// 截止时间变更任务主键 /// 返回回执 public async Task>> GetInfoByTaskId(long taskPKId) { List list = new List(); var tenantDb = saasDbService.GetBizDbScopeById(user.TenantId); //任务不考虑OrgId,这里去掉 tenantDb.QueryFilter.Clear(); var queryList = await tenantDb.Queryable() .InnerJoin((a, b) => a.Id == b.TASK_ID) .Where((a, b) => a.Id == taskPKId) .Select((a, b) => new { Base = a, Cut = b }) .ToListAsync(); //任务主键{taskPkId}无法获取业务信息 if (queryList.Count == 0) throw new Exception(string.Format(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.TaskBaseInfoFromTaskIdNull)), taskPKId)); var parentIdList = queryList.Select(a => a.Cut.Id).ToList(); var detailList = await tenantDb.Queryable() .Where(a => parentIdList.Contains(a.P_ID)).ToListAsync(); if (queryList.Count > 0) { list = detailList.OrderBy(p => p.MBL_NO).Select(p => { TaskCutDateChangeShowDto model = p.Adapt(); model.NoticeDate = queryList.FirstOrDefault().Cut.NOTICE_DATE; model.Carrier = queryList.FirstOrDefault().Cut.CARRIER; return model; }).ToList(); } return DataResult>.Success(list); } #endregion #region 检索对应的订舱订单并保存订舱ID /// /// 检索对应的订舱订单并保存订舱ID /// /// 截止时间变更任务主键 /// 返回回执 public async Task> SearchAndMarkBookingOrder(long taskPKId) { SeaExportOrderExtension orderInfo = null; try { var tenantDb = saasDbService.GetBizDbScopeById(user.TenantId); //任务不考虑OrgId,这里去掉 tenantDb.QueryFilter.Clear(); var queryList = await tenantDb.Queryable() .InnerJoin((a, b) => a.Id == b.TASK_ID) .Where((a, b) => a.Id == taskPKId) .Select((a, b) => new { Base = a, Cut = b }) .ToListAsync(); //任务主键{taskPkId}无法获取业务信息 if (queryList.Count == 0) throw new Exception(string.Format(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.TaskBaseInfoFromTaskIdNull)), taskPKId)); string mblNo = queryList.FirstOrDefault().Base.MBL_NO; var orderRlt = await _seaExportService.SearchOrderInfo(mblNo); if (!orderRlt.Succeeded) { // 提单号 {0} 检索海运出口订单失败 throw new Exception(string.Format(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.TaskBaseSearchOrderFailMBLNo)), mblNo)); } orderInfo = orderRlt.Data; foreach (var item in queryList.Select(a => a.Cut).ToList()) { item.BOOKING_ID = orderInfo.currOrder.Id; item.UpdateTime = DateTime.Now; item.UpdateBy = long.Parse(user.UserId); item.UpdateUserName = user.UserName; tenantDb.Updateable(item).UpdateColumns(x => new { x.BOOKING_ID, x.UpdateTime, x.UpdateBy, x.UpdateUserName }).ExecuteCommand(); var list = tenantDb.Queryable().Where(a => a.P_ID == item.Id).ToList(); if (list != null && list.Count > 0) { list.ForEach(async p => { if (p.MBL_NO.Equals(item.MBL_NO, StringComparison.OrdinalIgnoreCase)) { p.BOOKING_ID = orderInfo.currOrder.Id; p.UpdateTime = DateTime.Now; p.UpdateBy = long.Parse(user.UserId); p.UpdateUserName = user.UserName; await tenantDb.Updateable(p).UpdateColumns(x => new { x.BOOKING_ID, x.UpdateTime, x.UpdateBy, x.UpdateUserName }).ExecuteCommandAsync(); } }); } } } catch (Exception ex) { logger.LogError($"taskPKId={taskPKId} 检索截止时间变更订舱记录 处理异常,原因:{ex.Message}"); return DataResult.FailedData(orderInfo,$"检索失败,原因:{ex.Message}", MultiLanguageConst.Operation_Failed); } return DataResult.Success(orderInfo); } #endregion #region 更新订舱截单时间 /// /// 更新订舱截单时间 /// /// 任务主键 /// 返回回执 private async Task UpdateBookingOrderCutDate(long taskPKId) { var tenantDb = saasDbService.GetBizDbScopeById(user.TenantId); tenantDb.QueryFilter.Clear(); try { var entity = tenantDb.Queryable().Filter(null, true).First(a => a.TASK_ID == taskPKId); var cutDetail = await tenantDb.Queryable().FirstAsync(a => a.P_ID == entity.Id); var queryRlt = await _seaExportService.SearchOrderInfo(entity.MBL_NO); if (!queryRlt.Succeeded) { logger.LogInformation($"匹配订单信息失败 mblno={entity.MBL_NO},原因:{queryRlt.Message}"); return DataResult.Failed($"匹配订单信息失败 mblno={entity.MBL_NO},原因:{queryRlt.Message}"); } var orderInfo = queryRlt.Data; if (orderInfo.currOrder.SplitOrMergeFlag == 1) { List orderIdList = new List { orderInfo.currOrder.Id }; if (orderInfo.otherOrderList != null && orderInfo.otherOrderList.Count > 0) orderIdList.AddRange(orderInfo.otherOrderList.Select(t => t.Id).ToList()); var orderList = tenantDb.Queryable().Filter(null, true).Where(a => orderIdList.Contains(a.Id)).ToList(); foreach (var id in orderIdList) { var currOrder = orderList.FirstOrDefault(b => b.Id == id); SeaExportOpenEditReq bkModel = new SeaExportOpenEditReq { Id = id, }; StringBuilder doBuilder = new StringBuilder(); if (cutDetail.VGM_CUT.HasValue) { doBuilder.Append($"VGM CUT 原:{currOrder.VGMCloseDate} 新:{cutDetail.VGM_CUT.Value}"); bkModel.VGMCloseDate = cutDetail.VGM_CUT.Value; } if (cutDetail.CY_CUTOFF.HasValue) { doBuilder.Append($"CY CUT 原:{currOrder.ClosingDate} 新:{cutDetail.CY_CUTOFF.Value}"); bkModel.ClosingDate = cutDetail.CY_CUTOFF.Value; } if (cutDetail.SI_CUTOFF.HasValue) { doBuilder.Append($"SI CUT 原:{currOrder.CloseDocDate} 新:{cutDetail.SI_CUTOFF.Value}"); bkModel.CloseDocDate = cutDetail.SI_CUTOFF.Value; } var bkRlt = await _seaExportCommonService.SeaExportOpenEdit(bkModel); if (bkRlt.Succeeded) { logger.LogInformation($"taskPkId={taskPKId} 提单号{currOrder.MBLNO} 更新订舱数据成功 {doBuilder.ToString()}"); } } } else { SeaExportOpenEditReq bkModel = new SeaExportOpenEditReq { Id = orderInfo.currOrder.Id, }; StringBuilder doBuilder = new StringBuilder(); if (cutDetail.VGM_CUT.HasValue) { doBuilder.Append($"VGM CUT 原:{orderInfo.currOrder.VGMCloseDate} 新:{cutDetail.VGM_CUT.Value}"); bkModel.VGMCloseDate = cutDetail.VGM_CUT.Value; } if (cutDetail.CY_CUTOFF.HasValue) { doBuilder.Append($"CY CUT 原:{orderInfo.currOrder.ClosingDate} 新:{cutDetail.CY_CUTOFF.Value}"); bkModel.ClosingDate = cutDetail.CY_CUTOFF.Value; } if (cutDetail.SI_CUTOFF.HasValue) { doBuilder.Append($"SI CUT 原:{orderInfo.currOrder.CloseDocDate} 新:{cutDetail.SI_CUTOFF.Value}"); bkModel.CloseDocDate = cutDetail.SI_CUTOFF.Value; } var bkRlt = await _seaExportCommonService.SeaExportOpenEdit(bkModel); if (bkRlt.Succeeded) { logger.LogInformation($"taskPkId={taskPKId} 提单号{entity.MBL_NO} 更新订舱数据成功 {doBuilder.ToString()}"); } } } catch (Exception ex) { logger.LogInformation($"taskPKId={taskPKId} 更新订单截止时间异常,原因:{ex.Message}"); return DataResult.Failed($"更新订单截止时间异常,原因:{ex.Message}", MultiLanguageConst.OperationSuccess); } return DataResult.Successed("更新成功", MultiLanguageConst.OperationSuccess); } #endregion #region 更新舱位的截止时间 /// /// 更新舱位的截止时间 /// /// 任务主键 /// 相关海运出口订舱详情 /// 返回回执 private async Task UpdateBookingSlotCutDate(long taskPKId) { var tenantDb = saasDbService.GetBizDbScopeById(user.TenantId); //任务不考虑OrgId,这里去掉 tenantDb.QueryFilter.Clear(); try { var entity = tenantDb.Queryable().Filter(null, true).First(a => a.TASK_ID == taskPKId); var cutDetail = await tenantDb.Queryable().FirstAsync(a => a.P_ID == entity.Id); var slotOrder = await tenantDb.Queryable().FirstAsync(a => a.SlotBookingNo == entity.MBL_NO); var slotModel = new BookingSlotOpenEditReq { Id = slotOrder.Id, }; StringBuilder doBuilder = new StringBuilder(); if (slotOrder != null) { if (cutDetail.VGM_CUT.HasValue) { doBuilder.Append($"VGM CUT 原:{slotOrder.VGMSubmissionCutDate} 新:{cutDetail.VGM_CUT.Value}"); slotModel.VGMSubmissionCutDate = cutDetail.VGM_CUT.Value; } if (cutDetail.CY_CUTOFF.HasValue) { doBuilder.Append($"CY CUT 原:{slotOrder.CYCutDate} 新:{cutDetail.CY_CUTOFF.Value}"); slotModel.CYCutDate = cutDetail.CY_CUTOFF.Value; } if (cutDetail.SI_CUTOFF.HasValue) { doBuilder.Append($"SI CUT 原:{slotOrder.SICutDate} 新:{cutDetail.SI_CUTOFF.Value}"); slotModel.SICutDate = cutDetail.SI_CUTOFF.Value; } if (cutDetail.MANIFEST_CUT.HasValue) { doBuilder.Append($"MANIFEST CUT 原:{slotOrder.ManifestCutDate} 新:{cutDetail.MANIFEST_CUT.Value}"); slotModel.ManifestCutDate = cutDetail.MANIFEST_CUT.Value; } var bkRlt = await _bookingSlotService.BookingSlotOpenEdit(slotModel); if (bkRlt.Succeeded) { logger.LogInformation($"taskPkId={taskPKId} 提单号{entity.MBL_NO} 更新舱位数据成功 {doBuilder.ToString()}"); } } } catch (Exception ex) { logger.LogInformation($"taskPKId={taskPKId} 更新舱位截止时间异常,原因:{ex.Message}"); return DataResult.Failed($"更新舱位截止时间异常,原因:{ex.Message}", MultiLanguageConst.OperationSuccess); } return DataResult.Successed("更新成功", MultiLanguageConst.OperationSuccess); } #endregion #region 更新订单和舱位的截止时间 /// /// 更新订单和舱位的截止时间 /// /// 数据上下文 /// public async Task ModifyBookingOrderOrSlotTask(TaskFlowDataContext dataContext) { var taskPKId = dataContext.Get(TaskFlowDataNameConst.TaskPKId); if (taskPKId == 0) throw new ArgumentException($"缺少参数:{nameof(TaskFlowDataNameConst.TaskPKId)}"); //更新订舱 await UpdateBookingOrderCutDate(taskPKId); //更新舱位 await UpdateBookingSlotCutDate(taskPKId); return DataResult.Successed("更细成功"); } #endregion #region 发送邮件通知给客户 /// /// 发送邮件通知给客户 /// /// 起运港未提箱主键 /// 邮件模板主键 /// 返回回执 public async Task> InnerSendEmailToCustomer(long taskPKId, long businessTaskMailId) { /* 1、先匹配订单。这里可能关联的是拆票订单,如果是拆票订单需要所有拆票记录都要发邮件通知) 2、有订单,调取任务规则补全相关人(如果当票已经有了人员表记录 task_base_allocation则不再处理人员) 3、调取发送模板。 4、填充模板数据。 5、发送邮件。 6、成功后置任务为完成状态。 */ var tenantDb = saasDbService.GetBizDbScopeById(user.TenantId); var entity = tenantDb.Queryable().Filter(null, true).First(a => a.TASK_ID == taskPKId); var cutDetail = tenantDb.Queryable().Filter(null, true).First(a => a.P_ID == entity.Id); var baseInfo = tenantDb.Queryable().Filter(null, true).First(a => a.Id == taskPKId); var queryRlt = await _seaExportService.SearchOrderInfo(entity.MBL_NO); if (!queryRlt.Succeeded) { logger.LogInformation($"匹配订单信息失败 mblno={entity.MBL_NO},原因:{queryRlt.Message}"); return DataResult.Failed($"匹配订单信息失败 mblno={entity.MBL_NO},原因:{queryRlt.Message}"); } var taskInfo = cutDetail.Adapt(); taskInfo.PortloadArea = entity.PORTLOAD_AREA; taskInfo.TenantCompanyName = user.TenantName; //生成标题 if (!string.IsNullOrWhiteSpace(taskInfo.PortloadArea) && taskInfo.PortloadArea.Equals("NORTH_PORT", StringComparison.OrdinalIgnoreCase)) { taskInfo.EmailTitle = $"{taskInfo.MBLNo} 截止时间变更 {taskInfo.Vessel}/{taskInfo.VoyNo}/"; } else { taskInfo.EmailTitle = $"{taskInfo.MBLNo} Cut-off Details {taskInfo.Vessel}/{taskInfo.VoyNo}/"; } BusinessTaskMail? mailConfig = _taskMailService.GetAsync(businessTaskMailId).GetAwaiter().GetResult().Data; if (mailConfig == null) { await _logService.WriteLogAsync(new Op.Dtos.TaskInteraction.TaskUpdateRequest { BusinessId = taskPKId, BusinessType = BusinessType.OceanShippingExport, AutoCreateNext = true, TaskTypeName = TaskBaseTypeEnum.CUT_MODIFY.ToString(), }, $"未能根据任务配置值获取邮件模板设置"); return DataResult.Failed("未能根据任务配置值获取邮件模板设置"); } var orderInfo = queryRlt.Data; logger.LogInformation($"获取订单详情成功 bookid={orderInfo.currOrder.Id}"); DateTime nowDate = DateTime.Now; List orderIdList = new List { orderInfo.currOrder.Id }; if (orderInfo.otherOrderList != null && orderInfo.otherOrderList.Count > 0) orderIdList.AddRange(orderInfo.otherOrderList.Select(t => t.Id).ToList()); //如果是拆票需要处理,处理所以分票记录 if (orderInfo.currOrder.SplitOrMergeFlag == 1) { bool isHasAlloc = false; foreach (var id in orderIdList) { var taskAllocList = tenantDb.Queryable().Where(a => a.TaskId == taskPKId).ToList(); var searchAllotUserRlt = _taskAllocationService.GetAllotUserBySeaExportId(TaskBaseTypeEnum.CUT_MODIFY, id, new TaskFlowDataContext()).GetAwaiter().GetResult(); if (searchAllotUserRlt.Succeeded && searchAllotUserRlt.Data?.Count > 0) { isHasAlloc = true; var addUserList = searchAllotUserRlt.Data.GroupJoin(taskAllocList, l => l.RecvUserId, r => r.UserId, (l, r) => { if (r.ToList().Count == 0) return new { add = true, obl = l }; return new { add = false, obl = l }; }).Where(a => a.add).Select(a => a.obl).ToList(); if (addUserList.Count > 0) { //写入 addUserList.ForEach(b => { var alloc = new TaskBaseAllocation { Status = baseInfo.STATUS, StatusName = baseInfo.STATUS_NAME, TaskId = taskPKId, StatusTime = nowDate, UserId = b.RecvUserId, UserName = b.RecvUserName }; tenantDb.Insertable(alloc).ExecuteCommand(); }); } } } if (isHasAlloc && baseInfo.IS_PUBLIC == 1) { await tenantDb.Updateable(baseInfo).UpdateColumns(x => new { x.IS_PUBLIC }).ExecuteCommandAsync(); } } else { var taskAllocList = tenantDb.Queryable().Where(a => a.TaskId == taskPKId).ToList(); if (taskAllocList.Count == 0) { var searchAllotUserRlt = _taskAllocationService.GetAllotUserBySeaExportId(TaskBaseTypeEnum.CUT_MODIFY, orderInfo.currOrder.Id, new TaskFlowDataContext()).GetAwaiter().GetResult(); if (searchAllotUserRlt.Succeeded && searchAllotUserRlt.Data?.Count > 0) { //写入 searchAllotUserRlt.Data.ForEach(b => { var alloc = new TaskBaseAllocation { Status = baseInfo.STATUS, StatusName = baseInfo.STATUS_NAME, TaskId = taskPKId, StatusTime = nowDate, UserId = b.RecvUserId, UserName = b.RecvUserName }; tenantDb.Insertable(alloc).ExecuteCommand(); }); if (baseInfo.IS_PUBLIC == 1) { baseInfo.IS_PUBLIC = 0; await tenantDb.Updateable(baseInfo).UpdateColumns(x => new { x.IS_PUBLIC }).ExecuteCommandAsync(); } } } } TaskTransferMsgDto resultDto = new TaskTransferMsgDto { ExcuteDate = nowDate, Detail = new List() }; Dictionary> dict = new Dictionary>(); foreach (var id in orderIdList) { TaskTransferMsgDataDto detail = new TaskTransferMsgDataDto { BusinessId = id, }; var model = new MailTemplateModel(taskInfo) { BusinessId = id, BusinessType = BusinessType.OceanShippingExport, }; MailService mailService = new MailService(serviceProvider); var result = await mailService.SendAsync(mailConfig, model); if (!result.Succeeded) { await _logService.WriteLogAsync(new Op.Dtos.TaskInteraction.TaskUpdateRequest { BusinessId = taskPKId, BusinessType = BusinessType.OceanShippingExport, AutoCreateNext = true, TaskTypeName = TaskBaseTypeEnum.CUT_MODIFY.ToString(), }, result.Message); //return DataResult.Failed(result.Message); } detail.Status = result.Succeeded ? "SUCC" : "FAILURE"; detail.Message = result.Message; detail.MBlNo = entity.MBL_NO; resultDto.Detail.Add(detail); dict.Add(id, new Tuple(result.Succeeded, result.Message, entity.MBL_NO)); } //如果存在失败记录,不能置完成状态 if (!dict.Any(t => !t.Value.Item1)) { entity.IS_TRANSFER_USER = true; entity.LST_TRANSFER_USER_DATE = DateTime.Now; entity.LST_STATUS = "SUCC"; entity.LST_STATUS_NAME = "发送成功"; await tenantDb.Updateable(entity).UpdateColumns(x => new { x.IS_TRANSFER_USER, x.LST_TRANSFER_USER_DATE, x.LST_STATUS, x.LST_STATUS_NAME }).ExecuteCommandAsync(); //发送完邮件,自动标记任务状态为完成 await SetTaskStatus(taskPKId, TaskBaseTypeEnum.CUT_MODIFY, TaskStatusEnum.Complete, DateTime.Now, null); } return DataResult.Success(resultDto); } #endregion #region 发送邮件通知给客户(任务自动机调取) /// /// 发送邮件通知给客户(任务自动机调取) /// /// 数据上下文 /// 返回回执 public async Task> SendEmailToCustomerTask(TaskFlowDataContext dataContext) { var taskPKId = dataContext.Get(TaskFlowDataNameConst.TaskPKId); if (taskPKId == 0) throw new ArgumentException($"缺少参数:{nameof(TaskFlowDataNameConst.TaskPKId)}"); var businessTaskMailId = dataContext.Get($"{nameof(BusinessTaskMail)}.{nameof(BusinessTaskMail.Id)}"); if (businessTaskMailId == 0) throw new ArgumentException($"缺少参数:{nameof(BusinessTaskMail)}.{nameof(BusinessTaskMail.Id)}"); if (businessTaskMailId == 0) { await _logService.WriteLogAsync(new Op.Dtos.TaskInteraction.TaskUpdateRequest { BusinessId = taskPKId, BusinessType = BusinessType.OceanShippingExport, AutoCreateNext = true, TaskTypeName = TaskBaseTypeEnum.CUT_MODIFY.ToString(), }, $"缺少参数:{nameof(BusinessTaskMail)}.{nameof(BusinessTaskMail.Id)}"); return DataResult.Failed($"缺少参数:{nameof(BusinessTaskMail)}.{nameof(BusinessTaskMail.Id)}"); } return await InnerSendEmailToCustomer(taskPKId, businessTaskMailId); } #endregion #region 手工发送邮件通知给客户 /// /// 手工发送邮件通知给客户 /// /// 起运港未提箱任务主键 /// 返回回执 public async Task> ManualSendEmailToCustomer(long taskPKId) { var paramConfig = _configService.GetConfig("CutDateChangeEmailTemplateID", long.Parse(user.TenantId), false).GetAwaiter().GetResult()?.Data?.Value; long businessTaskMailId = 0; if (!string.IsNullOrWhiteSpace(paramConfig)) { businessTaskMailId = long.Parse(paramConfig); } else { return DataResult.Failed($"缺少系统参数参数:截止时间变更邮件模板ID-\tCutDateChangeEmailTemplateID"); } return await InnerSendEmailToCustomer(taskPKId, businessTaskMailId); } #endregion } }