using Amazon.Runtime.Internal.Util; using DS.Module.Core; using DS.Module.Core.Constants; using DS.Module.DjyServiceStatus; using DS.Module.SqlSugar; using DS.Module.UserModule; using DS.WMS.Core.Code.Dtos; using DS.WMS.Core.Code.Interface; using DS.WMS.Core.Info.Dtos; using DS.WMS.Core.Info.Interface; using DS.WMS.Core.Invoice.Dtos; using DS.WMS.Core.Map.Dtos; using DS.WMS.Core.Map.Interface; using DS.WMS.Core.Op.Dtos; using DS.WMS.Core.Op.EDI; using DS.WMS.Core.Op.Entity; using DS.WMS.Core.Op.Interface; using DS.WMS.Core.Op.Method; using DS.WMS.Core.Sys.Dtos; using DS.WMS.Core.Sys.Entity; 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 HtmlAgilityPack; using Mapster; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using NLog; using NPOI.XWPF.UserModel; using SqlSugar; using System.Security.Cryptography; using System.Text.RegularExpressions; namespace DS.WMS.Core.TaskPlat.Method { /// /// 任务台-BC子任务 /// public class TaskManageBCService : TaskManageBaseService, ITaskManageBCService { // 实例化时构建 private readonly IConfigService configService; private readonly IClientInfoService clientInfoService; private readonly IMappingCarrierService mappingCarrierService; private readonly IOpFileService opFileService; private readonly ICodeCtnService codeCtnService; private readonly IUserService _userService; private readonly IUserEmailService _userEmailService; // 按需构建 private Lazy bookingSlotService; private Lazy seaExportService; private Lazy djyServiceStatusService; private static readonly NLog.Logger Logger = LogManager.GetCurrentClassLogger(); //租户AMENDMENT默认转发KEY const string CONST_AMENDMENT_DEFAULT_PARAM = "AMENDMENT_TASK_AUTO_TRANSMIT"; //自动转发是否默认抄送操作 const string CONST_AUTO_TRANS_EMAIL_OP_CCTO = "AUTO_TRANS_EMAIL_OP_CCTO"; public TaskManageBCService(IUser user, ILogger logger, ISaasDbService saasDbService, IServiceProvider serviceProvider, IWebHostEnvironment environment, IConfigService configService, IClientInfoService clientInfoService, IMappingCarrierService mappingCarrierService, IOpFileService opFileService, ICodeCtnService codeCtnService, IUserService userService, IUserEmailService userEmailService) : base(user, logger, saasDbService, serviceProvider, environment) { this.configService = configService; this.clientInfoService = clientInfoService; this.mappingCarrierService = mappingCarrierService; this.opFileService = opFileService; this.codeCtnService = codeCtnService; _userService = userService; _userEmailService = userEmailService; bookingSlotService = new Lazy(serviceProvider.GetRequiredService); seaExportService = new Lazy(serviceProvider.GetRequiredService); djyServiceStatusService = new Lazy(serviceProvider.GetRequiredService); } /// /// 通过任务信息(BC)生成订舱或舱位 /// /// 生成订舱或者舱位请求 /// 返回回执 public async Task> CreateBookingAndSlot(BookingOrSlotGenerateDto model) { TaskManageOrderResultDto result = new TaskManageOrderResultDto(); logger.LogInformation($"接收生成订舱或舱位请求,参数{JsonConvert.SerializeObject(model)}"); try { /* 1、GEN_BOOKING_SLOT-生成舱位和订舱 (1)生成舱位 (2)生成海运订舱 (3)更新舱位库存 (4)更新BC任务 2、GEN_BOOKING-只生成订舱 (1)生成海运订舱 (4)更新BC任务 3、GEN_SLOT-只生成舱位 (1)生成舱位 (4)更新BC任务 3、GEN_SLOT-只生成舱位 (1)查找订舱记录 (3)更新舱位库存 (4)更新BC任务 */ if (model.BCTaskId == 0) throw new Exception($"BC任务主键不能为空"); //生成方式(GEN_BOOKING_SLOT-生成舱位和订舱;GEN_BOOKING-只生成订舱;GEN_SLOT-只生成舱位;GEN_EXIST_BOOKING-匹配指定的订舱) if (string.IsNullOrWhiteSpace(model.GenerateMethod)) throw new Exception($"生成方式不能为空,需要指定一种生成方式"); var tenantDb = saasDbService.GetBizDbScopeById(user.TenantId); var bcTaskInfo = await tenantDb.Queryable().Where(u => u.Id == model.BCTaskId).FirstAsync(); if (bcTaskInfo == null) { throw new Exception($"任务主键{model.BCTaskId}无法获取业务信息"); } var bcOrder = await tenantDb.Queryable().Where(a => a.TASK_ID == bcTaskInfo.Id).FirstAsync(); if (bcOrder == null) throw new Exception($"任务主键{model.BCTaskId}无法获取BC业务信息"); var bcCtnList = await tenantDb.Queryable().Where(a => a.P_ID == bcOrder.Id).ToListAsync(); var fileList = await tenantDb.Queryable().Where(a => a.TASK_PKID == bcTaskInfo.Id).ToListAsync(); if (model.GenerateMethod != "UPD_BOOKING") { if (bcOrder.BOOKING_ORDER_ID.HasValue && bcOrder.BOOKING_ORDER_ID.Value > 0) { throw new Exception($"当前BC任务已生成订舱订单,不能重复生成"); } } if (model.GenerateMethod == "GEN_BOOKING_SLOT") { #region 推送舱位、推送订舱 //推送舱位 //long bookingSlotId = 0; BookingSlotBase? bookingSlot = null; if (bcOrder.BOOKING_SLOT_ID.HasValue && bcOrder.BOOKING_SLOT_ID.Value > 0) { //bookingSlotId = bcOrder.BOOKING_SLOT_ID.Value; throw new Exception($"生成舱位失败,舱位已存在"); } //这里增加委托单位联系人的校验,重新从后台拉取了委托单位相关联系人,如果比对不一致跳出异常终止执行 ValidateContact(model); //触发生成舱位 bookingSlot = await GenerateBookingSlotByTaskBcInfo(bcOrder, bcCtnList, fileList); logger.LogInformation($"生成舱位完成,bookingSlotId={bookingSlot?.Id} taskid={bcOrder.TASK_ID}"); if (bookingSlot == null || bookingSlot.Id == 0) throw new Exception($"生成舱位失败"); var slotFileList = opFileService.GetOpFileList(bookingSlot.Id.ToString()).Data; //if (bookingSlotService == null) //{ // bookingSlotService = serviceProvider.GetRequiredService(); //} //推送订舱订单 var bookingOrderId = await bookingSlotService.Value.GenerateBookingOrder(bookingSlot, slotFileList, model, null); logger.LogInformation($"生成订舱订单完成,bookingOrderId={bookingOrderId} taskid={bcOrder.TASK_ID}"); if (bookingOrderId < 1) throw new Exception($"生成订舱订单失败"); List slots = new List(); //检索舱位信息 var slotInfo = (await bookingSlotService.Value.Detail(bookingSlot.Id)).Data; BookingSlotBaseWithCtnDto baseInfo = slotInfo.Adapt(); baseInfo.Id = bookingSlot.Id; baseInfo.CtnList = slotInfo.CtnList.Adapt>(); slots.Add(baseInfo); //对应订舱和舱位关系 ImportSlotsDto importSlotsDto = new() { bookingOrderId = bookingOrderId, slots = slots, isCheck = false }; var allocRlt = await bookingSlotService.Value.ImportSlots(importSlotsDto); logger.LogInformation($"生成订舱和舱位关系完成,allocRlt={JsonConvert.SerializeObject(allocRlt)} taskid={bcOrder.TASK_ID}"); if (!allocRlt.Succeeded) { throw new Exception($"生成订舱和舱位关系失败"); } var bcEntity = await tenantDb.Queryable().Where(a => a.Id == bcOrder.Id).FirstAsync(); if (bcEntity == null) { throw new Exception($"未获取有效任务BC失败,更新失败"); } bcEntity.BOOKING_ORDER_ID = bookingOrderId; bcEntity.BOOKING_SLOT_ID = slotInfo.Id; bcEntity.UpdateTime = DateTime.Now; bcEntity.UpdateBy = long.Parse(user.UserId); bcEntity.UpdateUserName = user.UserName; //更新任务BC await tenantDb.Updateable(bcEntity).UpdateColumns(it => new { it.BOOKING_ORDER_ID, it.BOOKING_SLOT_ID, it.UpdateTime, it.UpdateBy, it.UpdateUserName }).ExecuteCommandAsync(); var taskEntity = await tenantDb.Queryable().FirstAsync(u => u.Id == bcEntity.TASK_ID); if (taskEntity == null) { throw new Exception($"未获取有效任务记录,更新失败"); } #region 更新任务 //如果是公共任务,需要变成个人任务 RealUserId = 当前操作人 if (taskEntity.IS_PUBLIC == 1) { taskEntity.IS_PUBLIC = 0; taskEntity.RealUserId = long.Parse(user.UserId); taskEntity.RealUserName = user.UserName; taskEntity.UpdateTime = DateTime.Now; taskEntity.UpdateBy = taskEntity.RealUserId ?? 0; taskEntity.UpdateUserName = user.UserName; taskEntity.IS_COMPLETE = 1; taskEntity.COMPLETE_DATE = DateTime.Now; taskEntity.COMPLETE_DEAL = "MANUAL"; taskEntity.COMPLETE_DEAL = "手工"; await tenantDb.Updateable(taskEntity).UpdateColumns(it => new { it.IS_PUBLIC, it.UpdateTime, it.UpdateBy, it.UpdateUserName, it.RealUserId, it.RealUserName, it.IS_COMPLETE, it.COMPLETE_DATE, it.COMPLETE_DEAL, it.COMPLETE_DEAL_NAME }).ExecuteCommandAsync(); } else { taskEntity.UpdateTime = DateTime.Now; taskEntity.UpdateBy = long.Parse(user.UserId); taskEntity.UpdateUserName = user.UserName; taskEntity.IS_COMPLETE = 1; taskEntity.COMPLETE_DATE = DateTime.Now; taskEntity.COMPLETE_DEAL = "MANUAL"; taskEntity.COMPLETE_DEAL = "手工"; await tenantDb.Updateable(taskEntity).UpdateColumns(it => new { it.UpdateTime, it.UpdateBy, it.UpdateUserName, it.IS_COMPLETE, it.COMPLETE_DATE, it.COMPLETE_DEAL, it.COMPLETE_DEAL_NAME }).ExecuteCommandAsync(); } #endregion //var currBCOrder = await tenantDb.Queryable().Where(a => a.Id == bcEntity.Id).FirstAsync(); //if (currBCOrder != null && model.IsDirectSend) //{ // //异步推送邮件 // var mailRlt = await GenerateSendEmail(currBCOrder, bcTaskInfo, model.usePersonalEmailSend); // if (!mailRlt.succ) // { // throw Oops.Oh($"邮件推送失败,原因:{mailRlt.msg},可以任务编辑页面重新发送邮件"); // } //} #endregion } else if (model.GenerateMethod == "GEN_BOOKING") { #region 推送订舱 //bookingSlot = null; if (bcOrder.BOOKING_ORDER_ID.HasValue && bcOrder.BOOKING_ORDER_ID.Value > 0) { //bookingSlotId = bcOrder.BOOKING_SLOT_ID.Value; throw new Exception($"生成订舱订单失败,订舱订单已存在"); } if (!bcOrder.BOOKING_SLOT_ID.HasValue || bcOrder.BOOKING_SLOT_ID.Value < 1) { //bookingSlotId = bcOrder.BOOKING_SLOT_ID.Value; throw new Exception($"生成订舱订单失败,舱位未生成不能直接生成订舱订单"); } long bookingSlotId = bcOrder.BOOKING_SLOT_ID.Value; //这里增加委托单位联系人的校验,重新从后台拉取了委托单位相关联系人,如果比对不一致跳出异常终止执行 ValidateContact(model); BookingSlotBase? bookingSlot = await tenantDb.Queryable().Where(x => x.Id == bookingSlotId).FirstAsync(); if (bookingSlot == null) { throw new Exception($"生成订舱订单失败,舱位未生成不能直接生成订舱订单"); } var slotFileList = opFileService.GetOpFileList(bookingSlotId.ToString()).Data; //推送订舱订单 //if (bookingSlotService == null) //{ // bookingSlotService = serviceProvider.GetRequiredService(); //} var bookingOrderId = await bookingSlotService.Value.GenerateBookingOrder(bookingSlot, slotFileList, model, null); logger.LogInformation($"生成订舱订单完成,bookingOrderId={bookingOrderId} taskid={bcOrder.TASK_ID}"); if (bookingOrderId < 1) throw new Exception($"生成订舱订单失败"); List slots = new List(); //检索舱位信息 var slotInfo = (await bookingSlotService.Value.Detail(bookingSlot.Id)).Data; BookingSlotBaseWithCtnDto baseInfo = slotInfo.Adapt(); baseInfo.Id = bookingSlot.Id; baseInfo.CtnList = slotInfo.CtnList.Adapt>(); slots.Add(baseInfo); //对应订舱和舱位关系 ImportSlotsDto importSlotsDto = new() { bookingOrderId = bookingOrderId, slots = slots, isCheck = false }; var allocRlt = await bookingSlotService.Value.ImportSlots(importSlotsDto); logger.LogInformation($"生成订舱和舱位关系完成,allocRlt={JsonConvert.SerializeObject(allocRlt)} taskid={bcOrder.TASK_ID}"); if (!allocRlt.Succeeded) { throw new Exception($"生成订舱和舱位关系失败"); } var bcEntity = await tenantDb.Queryable().Where(a => a.Id == bcOrder.Id).FirstAsync(); if (bcEntity == null) { throw new Exception($"未获取有效任务BC失败,更新失败"); } bcEntity.BOOKING_ORDER_ID = bookingOrderId; bcEntity.BOOKING_SLOT_ID = slotInfo.Id; bcEntity.UpdateTime = DateTime.Now; bcEntity.UpdateBy = long.Parse(user.UserId); bcEntity.UpdateUserName = user.UserName; //更新任务BC await tenantDb.Updateable(bcEntity).UpdateColumns(it => new { it.BOOKING_ORDER_ID, it.BOOKING_SLOT_ID, it.UpdateTime, it.UpdateBy, it.UpdateUserName }).ExecuteCommandAsync(); var taskEntity = await tenantDb.Queryable().FirstAsync(u => u.Id == bcEntity.TASK_ID); if (taskEntity == null) { throw new Exception($"未获取有效任务记录,更新失败"); } #region 更新任务 //如果是公共任务,需要变成个人任务 RealUserId = 当前操作人 if (taskEntity.IS_PUBLIC == 1) { taskEntity.IS_PUBLIC = 0; taskEntity.RealUserId = long.Parse(user.UserId); taskEntity.RealUserName = user.UserName; taskEntity.UpdateTime = DateTime.Now; taskEntity.UpdateBy = taskEntity.RealUserId ?? 0; taskEntity.UpdateUserName = user.UserName; taskEntity.IS_COMPLETE = 1; taskEntity.COMPLETE_DATE = DateTime.Now; taskEntity.COMPLETE_DEAL = "MANUAL"; taskEntity.COMPLETE_DEAL = "手工"; await tenantDb.Updateable(taskEntity).UpdateColumns(it => new { it.IS_PUBLIC, it.UpdateTime, it.UpdateBy, it.UpdateUserName, it.RealUserId, it.RealUserName, it.IS_COMPLETE, it.COMPLETE_DATE, it.COMPLETE_DEAL, it.COMPLETE_DEAL_NAME }).ExecuteCommandAsync(); } else { taskEntity.UpdateTime = DateTime.Now; taskEntity.UpdateBy = long.Parse(user.UserId); taskEntity.UpdateUserName = user.UserName; taskEntity.IS_COMPLETE = 1; taskEntity.COMPLETE_DATE = DateTime.Now; taskEntity.COMPLETE_DEAL = "MANUAL"; taskEntity.COMPLETE_DEAL = "手工"; await tenantDb.Updateable(taskEntity).UpdateColumns(it => new { it.UpdateTime, it.UpdateBy, it.UpdateUserName, it.IS_COMPLETE, it.COMPLETE_DATE, it.COMPLETE_DEAL, it.COMPLETE_DEAL_NAME }).ExecuteCommandAsync(); } #endregion //var currBCOrder = _taskBCInfoRepository.AsQueryable().First(a => a.PK_ID == bcEntity.PK_ID); //if (currBCOrder != null && model.IsDirectSend) //{ // //异步推送邮件 // var mailRlt = await GenerateSendEmail(currBCOrder, bcTaskInfo, model.usePersonalEmailSend); // if (!mailRlt.succ) // { // throw Oops.Oh($"邮件推送失败,原因:{mailRlt.msg},可以任务编辑页面重新发送邮件"); // } //} #endregion } else if (model.GenerateMethod == "GEN_SLOT") { #region 推送舱位 BookingSlotBase? bookingSlot = null; if (bcOrder.BOOKING_SLOT_ID.HasValue && bcOrder.BOOKING_SLOT_ID.Value > 0) { //bookingSlotId = bcOrder.BOOKING_SLOT_ID.Value; throw new Exception($"生成舱位失败,舱位已存在"); } //触发生成舱位 bookingSlot = await GenerateBookingSlotByTaskBcInfo(bcOrder, bcCtnList, fileList); logger.LogInformation($"生成舱位完成,bookingSlotId={bookingSlot?.Id} taskid={bcOrder.TASK_ID}"); if (bookingSlot == null || bookingSlot.Id == 0) throw new Exception($"生成舱位失败"); var bcEntity = await tenantDb.Queryable().Where(a => a.Id == bcOrder.Id).FirstAsync(); if (bcEntity == null) { throw new Exception($"未获取有效任务BC失败,更新失败"); } bcEntity.BOOKING_SLOT_ID = bookingSlot.Id; bcEntity.UpdateTime = DateTime.Now; bcEntity.UpdateBy = long.Parse(user.UserId); bcEntity.UpdateUserName = user.UserName; //更新任务BC await tenantDb.Updateable(bcEntity).UpdateColumns(it => new { it.BOOKING_SLOT_ID, it.UpdateTime, it.UpdateBy, it.UpdateUserName }).ExecuteCommandAsync(); var taskEntity = await tenantDb.Queryable().FirstAsync(u => u.Id == bcEntity.TASK_ID); if (taskEntity == null) { throw new Exception($"未获取有效任务记录,更新失败"); } #region 更新任务 //如果是公共任务,需要变成个人任务 RealUserId = 当前操作人 if (taskEntity.IS_PUBLIC == 1) { taskEntity.IS_PUBLIC = 0; taskEntity.RealUserId = long.Parse(user.UserId); taskEntity.RealUserName = user.UserName; taskEntity.UpdateTime = DateTime.Now; taskEntity.UpdateBy = taskEntity.RealUserId ?? 0; taskEntity.UpdateUserName = user.UserName; await tenantDb.Updateable(taskEntity).UpdateColumns(it => new { it.IS_PUBLIC, it.UpdateTime, it.UpdateBy, it.UpdateUserName, it.RealUserId, it.RealUserName, }).ExecuteCommandAsync(); } else { taskEntity.UpdateTime = DateTime.Now; taskEntity.UpdateBy = long.Parse(user.UserId); taskEntity.UpdateUserName = user.UserName; await tenantDb.Updateable(taskEntity).UpdateColumns(it => new { it.UpdateTime, it.UpdateBy, it.UpdateUserName, }).ExecuteCommandAsync(); } #endregion #endregion } else if (model.GenerateMethod == "UPD_BOOKING") { #region 更新订舱 if (bcOrder.BOOKING_ORDER_ID == null || bcOrder.BOOKING_ORDER_ID.Value == 0) { throw new Exception($"更新订舱订单失败,舱位未关联到订单信息"); } //这里增加委托单位联系人的校验,重新从后台拉取了委托单位相关联系人,如果比对不一致跳出异常终止执行 ValidateContact(model); long bookingSlotId = bcOrder.BOOKING_SLOT_ID.Value; //这里增加委托单位联系人的校验,重新从后台拉取了委托单位相关联系人,如果比对不一致跳出异常终止执行 ValidateContact(model); BookingSlotBase? bookingSlot = await tenantDb.Queryable().Where(x => x.Id == bookingSlotId).FirstAsync(); if (bookingSlot == null) { throw new Exception($"更新订舱订单失败,未找到id为{bookingSlotId}的舱位信息"); } List bookingSlotCtnList = await tenantDb.Queryable().Where(x => x.Id == bookingSlotId).ToListAsync(); //推送订舱订单 var bookingOrderId = await UpdateBookingOrder((long)bcOrder.BOOKING_ORDER_ID, bookingSlot, bookingSlotCtnList, model, tenantDb); var taskEntity = await tenantDb.Queryable().FirstAsync(u => u.Id == bcOrder.TASK_ID); if (taskEntity == null) { throw new Exception($"未获取有效任务记录,更新失败"); } #region 更新任务 //如果是公共任务,需要变成个人任务 RealUserId = 当前操作人 if (taskEntity.IS_PUBLIC == 1) { taskEntity.IS_PUBLIC = 0; taskEntity.RealUserId = long.Parse(user.UserId); taskEntity.RealUserName = user.UserName; taskEntity.UpdateTime = DateTime.Now; taskEntity.UpdateBy = taskEntity.RealUserId ?? 0; taskEntity.UpdateUserName = user.UserName; taskEntity.IS_COMPLETE = 1; taskEntity.COMPLETE_DATE = DateTime.Now; taskEntity.COMPLETE_DEAL = "MANUAL"; taskEntity.COMPLETE_DEAL = "手工"; await tenantDb.Updateable(taskEntity).UpdateColumns(it => new { it.IS_PUBLIC, it.UpdateTime, it.UpdateBy, it.UpdateUserName, it.RealUserId, it.RealUserName, it.IS_COMPLETE, it.COMPLETE_DATE, it.COMPLETE_DEAL, it.COMPLETE_DEAL_NAME }).ExecuteCommandAsync(); } else { taskEntity.UpdateTime = DateTime.Now; taskEntity.UpdateBy = long.Parse(user.UserId); taskEntity.UpdateUserName = user.UserName; taskEntity.IS_COMPLETE = 1; taskEntity.COMPLETE_DATE = DateTime.Now; taskEntity.COMPLETE_DEAL = "MANUAL"; taskEntity.COMPLETE_DEAL = "手工"; await tenantDb.Updateable(taskEntity).UpdateColumns(it => new { it.UpdateTime, it.UpdateBy, it.UpdateUserName, it.IS_COMPLETE, it.COMPLETE_DATE, it.COMPLETE_DEAL, it.COMPLETE_DEAL_NAME }).ExecuteCommandAsync(); } #endregion //var currBCOrder = await tenantDb.Queryable().Where(a => a.Id == bcEntity.Id).FirstAsync(); //if (currBCOrder != null && model.IsDirectSend) //{ // //异步推送邮件 // var mailRlt = await GenerateSendEmail(currBCOrder, bcTaskInfo, model.usePersonalEmailSend); // if (!mailRlt.succ) // { // throw Oops.Oh($"邮件推送失败,原因:{mailRlt.msg},可以任务编辑页面重新发送邮件"); // } //} #endregion } result.succ = true; result.msg = "成功"; return DataResult.Success(result); } catch (Exception ex) { result.succ = false; result.msg = $"生成订舱或舱位失败,原因:{ex.Message}"; return DataResult.FailedData(result); } } private void ValidateContact(BookingOrSlotGenerateDto model) { var paramConfig = configService.GetConfig(TenantParamCode.CONST_CREATE_BOOKING_NEED_CONTACT, long.Parse(user.TenantId), false).GetAwaiter().GetResult()?.Data?.Value; if (model.CustomerContactList != null && model.CustomerContactList.Count > 0) { //取委托客户下面所有的联系人列表 var djyCustomerInfo = clientInfoService.GetClientInfoWithContact(new Info.Dtos.QueryClientInfo { ClientId = model.CustomerId.Value, IsController = true }).GetAwaiter().GetResult().Data; if (djyCustomerInfo == null) { logger.LogInformation($"委托单位{model.CustomerName} 获取失败,委托单位不存在或已作废 SlotId={model.SlotId.Value}"); //委托单位{0} 获取失败,委托单位不存在或已作废 throw new Exception(string.Format(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.BookingSlotCreateContaNull)), model.CustomerName)); } if (djyCustomerInfo.ClientContactList == null && djyCustomerInfo.ClientContactList.Count < 1) { logger.LogInformation($"委托单位{model.CustomerName} 获取相关联系人失败,委托单位相关联系人为空 SlotId={model.SlotId.Value}"); //委托单位{0} 获取相关联系人失败,委托单位相关联系人为空 throw new Exception(string.Format(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.BookingSlotCreateCustomerContractInfoNull)), model.CustomerName)); } model.CustomerContactList.ForEach(contact => { var djyCustomerContactMan = djyCustomerInfo.ClientContactList .FirstOrDefault(a => a.Id == contact.Id); if (djyCustomerContactMan == null) { logger.LogInformation($"委托单位{model.CustomerName} 联系人 {contact.Name}获取失败,联系人不存在或已作废 SlotId={model.SlotId}"); //委托单位 {0} 联系人 {1} 获取失败,联系人不存在或已作废 throw new Exception(string.Format(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.BookingSlotCreateCustomerContractDeletedOrNoExists)), model.CustomerName, contact.Name)); } }); } else { if (paramConfig != null && paramConfig.Equals("ENABLE", StringComparison.OrdinalIgnoreCase)) { //生成订舱时往来单位联系人必填,请修改 throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.BookingSlotCreateCustomerContractNotNull))); } } } /// /// 通过任务主键获取BC详情 /// /// BC任务主键 public async Task> GetInfoByTaskId(long taskId) { TaskManageOrderResultDto result = new TaskManageOrderResultDto(); try { var tenantDb = saasDbService.GetBizDbScopeById(user.TenantId); var taskBase = await tenantDb.Queryable().FirstAsync(a => a.Id == taskId); if (taskBase == null) throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.TaskBaseEmpty))); var bcOrder = await tenantDb.Queryable().FirstAsync(a => a.TASK_ID == taskId); if (bcOrder == null) throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.TaskBCInfoEmpty))); var bcCtnList = await tenantDb.Queryable().Where(a => a.P_ID == bcOrder.Id).ToListAsync(); TaskBCShowBaseDto model = bcOrder.Adapt(); if (bcCtnList.Count > 0) model.CtnList = bcCtnList.Adapt>(); var fileList = await tenantDb.Queryable().Where(a => a.TASK_PKID == bcOrder.TASK_ID).ToListAsync(); if (fileList.Count > 0) model.FileList = fileList.Adapt>(); model.taskStatus = taskBase.STATUS; #region 生成关键信息 model.Keywords = new List(); if (bcOrder.CARRIAGE_TYPE == "DIRECT_SHIP") { model.Keywords.Add(new TaskBCShowBaseKeywordDto() { Name = $"承运方式:{bcOrder.CARRIAGE_TYPE_NAME}", Background = "#FFFF80", Icon = "icon-yunshu1" }); } else if (bcOrder.CARRIAGE_TYPE == "TRANSFER_SHIP") { model.Keywords.Add(new TaskBCShowBaseKeywordDto() { Name = $"承运方式:{bcOrder.CARRIAGE_TYPE_NAME}", Background = "#CAF982", Icon = "icon-shuaxin" }); } if (bcOrder.BOOKING_SLOT_TYPE == "CONTRACT_ORDER") { model.Keywords.Add(new TaskBCShowBaseKeywordDto() { Name = $"订舱方式:{bcOrder.BOOKING_SLOT_TYPE_NAME}", Background = "#81D3F8", Icon = "icon-touzijilu" }); } else if (bcOrder.BOOKING_SLOT_TYPE == "SPOT_ORDER") { model.Keywords.Add(new TaskBCShowBaseKeywordDto() { Name = $"订舱方式:{bcOrder.BOOKING_SLOT_TYPE_NAME}", Background = "#FACD91", Icon = "icon-beizhu1" }); } #endregion //await SetTaskStatus([taskId], x => x.IS_PUBLIC == 1, x => x.IS_EXCEPT == 0); //await SetTaskOwner([taskId], new List() //{ // new RecvUserInfo(111,"231312321"), // new RecvUserInfo(222,"affsdfdsf"), //}); result.succ = true; result.ext = model; //如果当前BC有对应记录,则读取订舱详情 //0726:经确认页面上没有用到订舱详情,所以暂时不返回 //if (bcOrder.BOOKING_ORDER_ID.HasValue) //{ // var bkOrder = await _bookingOrderRepository.AsQueryable(). // FirstAsync(a => a.Id == bcOrder.BOOKING_ORDER_ID.Value); // if (bkOrder != null) // { // var showBKOrder = bkOrder.Adapt(); // var ctnList = await _bookingCtnRepository.AsQueryable(). // Where(a => a.BILLID == bkOrder.Id).ToListAsync(); // if (ctnList.Count > 0) // showBKOrder.ctnInputs = ctnList.Adapt>(); // result.ext2 = showBKOrder; // } //} } catch (Exception ex) { result.succ = false; result.msg = $"获取BC详情异常,原因:{ex.Message}"; } return DataResult.Success(result); } #region 根据BC任务信息生成舱位 /// /// 根据BC任务信息,生成舱位(调用的) /// /// BC任务详情 /// BC任务集装箱列表 /// BC任务附件列表 /// 返回舱位ID private async Task GenerateBookingSlotByTaskBcInfo(TaskBCInfo taskBCInfo, List taskBCCtnList, List taskFileList, string opType = "add") { //long id = 0; try { var allMapCarrierList = await mappingCarrierService.GetAllList(); MappingCarrierRes? carrierInfo = null; if (allMapCarrierList.Succeeded) { carrierInfo = allMapCarrierList.Data.Where(t => t.MapCode.Equals(taskBCInfo.CARRIERID, StringComparison.OrdinalIgnoreCase) && t.Module == MappingModuleConst.CONST_MAPPING_CARRIER_MODULE).FirstOrDefault(); } BookingSlotBaseApiDto slotModel = new BookingSlotBaseApiDto { DataObj = new BookingSlotBaseApiSaveDto { CarrierId = carrierInfo?.LinkId, CarrierCode = carrierInfo?.MapCode, Carrier = carrierInfo?.MapName, SlotBookingNo = taskBCInfo.MBL_NO, BookingParty = taskBCInfo.BOOKING_PARTY, BookingSlotType = taskBCInfo.BOOKING_SLOT_TYPE, BookingSlotTypeName = taskBCInfo.BOOKING_SLOT_TYPE_NAME, Vessel = taskBCInfo.VESSEL, Voyno = taskBCInfo.VOYNO, VGMSubmissionCutDate = taskBCInfo.VGM_CUTOFF_TIME, //WeekAt = taskBCInfoDto.WEEK_AT, CarriageType = taskBCInfo.CARRIAGE_TYPE, CarriageTypeName = taskBCInfo.CARRIAGE_TYPE_NAME, ContractNo = taskBCInfo.CONTRACTNO, CtnStat = taskBCInfo.CTN_STAT, CYCutDate = taskBCInfo.CY_CUTOFF_TIME, DetensionFreeDays = taskBCInfo.DETENSION_FREE_DAYS, ETD = taskBCInfo.ETD, ETA = taskBCInfo.ETA, LaneCode = taskBCInfo.LANECODE, LaneName = taskBCInfo.LANENAME, ManifestCutDate = taskBCInfo.MANIFEST_CUT_DATE, MDGFCutDate = taskBCInfo.MDGF_CUT_DATE, PlaceDelivery = taskBCInfo.PLACEDELIVERY, PlaceReceipt = taskBCInfo.PLACERECEIPT, PortDischarge = taskBCInfo.PORTDISCHARGE, PortLoad = taskBCInfo.PORTLOAD, SICutDate = taskBCInfo.SI_CUT_DATE, CustomSICutDate = taskBCInfo.CUSTOM_SI_CUT_DATE, TransferPort1 = taskBCInfo.TRANSFER_PORT_1, TransferPort2 = taskBCInfo.TRANSFER_PORT_2, PriceCalculationDate = taskBCInfo.PRICE_CALCULATION_DATE, CtnList = new List() }, OpType = "add" }; if (int.TryParse(taskBCInfo.WEEK_AT, out int _weekat)) { slotModel.DataObj.WeekAt = _weekat; } var ctnCodeList = (await codeCtnService.GetAllList()).Data ?? new List(); if (taskBCCtnList.Count > 0) { taskBCCtnList.ForEach(t => { if (string.IsNullOrEmpty(t.CTNCODE) && !string.IsNullOrEmpty(t.CTNALL)) { var ctnCode = ctnCodeList.FirstOrDefault(a => !string.IsNullOrWhiteSpace(a.CtnName) && a.CtnName.Equals(t.CTNALL, StringComparison.OrdinalIgnoreCase)); t.CTNCODE = ctnCode != null ? $"{ctnCode.CtnSize}{ctnCode.CtnType}" : "(箱型未收录)"; } BookingSlotCtnSaveInput ctn = new BookingSlotCtnSaveInput { CtnCode = t.CTNCODE, CtnAll = t.CTNALL, CtnNum = t.CTNNUM.HasValue ? t.CTNNUM.Value : 1 }; slotModel.DataObj.CtnList.Add(ctn); }); } var basePath = AppSetting.app(new string[] { "FileSettings", "BasePath" }); DynameFileInfo dynameFile = null; DynameFileInfo dynameNoticeFile = null; if (taskFileList.Any(t => t.FILE_CATEGORY == TaskFileCategoryEnum.BC.ToString())) { var fileInfo = taskFileList.FirstOrDefault(t => t.FILE_CATEGORY == TaskFileCategoryEnum.BC.ToString()); string fileFullPath; if (string.IsNullOrEmpty(basePath)) { fileFullPath = Path.Combine(environment.WebRootPath ?? "", fileInfo.FILE_PATH); } else { fileFullPath = Path.Combine(basePath, fileInfo.FILE_PATH); } dynameFile = new DynameFileInfo { FileBytes = File.ReadAllBytes(fileFullPath), FileName = Path.GetFileName(fileFullPath) }; } if (taskFileList.Any(t => t.FILE_CATEGORY == TaskFileCategoryEnum.BC_NOTICE.ToString())) { var fileInfo = taskFileList.FirstOrDefault(t => t.FILE_CATEGORY == TaskFileCategoryEnum.BC.ToString()); string fileFullPath; if (string.IsNullOrEmpty(basePath)) { fileFullPath = Path.Combine(environment.WebRootPath ?? "", fileInfo.FILE_PATH); } else { fileFullPath = Path.Combine(basePath, fileInfo.FILE_PATH); } dynameNoticeFile = new DynameFileInfo { FileBytes = File.ReadAllBytes(fileFullPath), FileName = Path.GetFileName(fileFullPath) }; } var result = await bookingSlotService.Value.InnerApiReceive(slotModel, dynameFile, dynameNoticeFile); if (result.Succeeded && result.Data != null) { var tenantDb = saasDbService.GetBizDbScopeById(user.TenantId); var taskBcInfo = await tenantDb.Queryable().Where(x => x.Id == taskBCInfo.Id).FirstAsync(); if (taskBcInfo != null && taskBcInfo.BOOKING_SLOT_ID == null) { taskBcInfo.BOOKING_SLOT_ID = result.Data.Id; await tenantDb.Updateable(taskBcInfo).UpdateColumns(x => new { x.BOOKING_SLOT_ID }).ExecuteCommandAsync(); } } return result.Data; } catch (Exception ex) { logger.LogError($"任务BC MBLNO:{taskBCInfo.MBL_NO} 生成舱位异常,原因:{ex.Message}"); throw new Exception($"MBLNO:{taskBCInfo.MBL_NO} 生成舱位异常,原因:{ex.Message}"); } } #endregion #region 更新订舱 /// /// 更新订舱 /// /// 返回订舱ID private async Task UpdateBookingOrder( //TaskBCInfo taskBCInfo, //List taskBCCtnList, long bookingOrderId, BookingSlotBase bookingSlotBase, List bookingSlotCtnList, BookingOrSlotGenerateDto generateModel, SqlSugarScopeProvider? tenantDb = null) { long id = 0; if (tenantDb == null) { tenantDb = saasDbService.GetBizDbScopeById(user.TenantId); } try { /* 1、新增订舱 2、推送服务项目 3、推送附件 */ var allMapCarrierList = await mappingCarrierService.GetAllList(); MappingCarrierRes carrierInfo = null; if (allMapCarrierList.Succeeded) { carrierInfo = allMapCarrierList.Data.FirstOrDefault(t => t.LinkId == bookingSlotBase.CarrierId.Value && t.Module == MappingModuleConst.CONST_MAPPING_CARRIER_MODULE); } SeaExportReq bkModel = new SeaExportReq { Id = bookingOrderId, CustomerId = generateModel.CustomerId.Value, CustomerName = generateModel.CustomerName, Carrier = carrierInfo?.MapName?.Trim(), CarrierId = bookingSlotBase.CarrierId.Value, BookingNo = bookingSlotBase.SlotBookingNo.Trim(), MBLNO = bookingSlotBase.SlotBookingNo.Trim(), ContractNo = !string.IsNullOrWhiteSpace(bookingSlotBase.ContractNo) ? bookingSlotBase.ContractNo : "", Vessel = bookingSlotBase.Vessel?.ToUpper()?.Trim(), Voyno = bookingSlotBase.Voyno?.ToUpper()?.Trim(), InnerVoyno = bookingSlotBase.Voyno?.ToUpper()?.Trim(), ETD = bookingSlotBase.ETD, ETA = bookingSlotBase.ETA, SaleId = generateModel.SaleId.HasValue ? generateModel.SaleId.Value : 0, Sale = generateModel.SaleName, OperatorId = generateModel.OpId.HasValue ? generateModel.OpId.Value : 0, OperatorName = generateModel.OpName, Doc = generateModel.DocId.HasValue ? generateModel.DocId.Value : 0, DocName = generateModel.DocName, //ROUTEID = generateModel.RouteID?.ToString(), //ROUTE = generateModel.Route, //CZRemark = generateModel.CZRemark, //ShenQingXiangShi = generateModel.ShenQingXiangShi, //LineManageID = generateModel.LineManageID?.ToString(), //LineName = generateModel.LineManage, VGMCloseDate = bookingSlotBase.VGMSubmissionCutDate, ClosingDate = bookingSlotBase.CYCutDate, CloseDocDate = bookingSlotBase.SICutDate, CustomerService = generateModel.CustServiceId.HasValue ? generateModel.CustServiceId.Value : 0, CustomerServiceName = generateModel.CustServiceName, LoadPort = bookingSlotBase.PortLoad, LoadPortId = bookingSlotBase.PortLoadId.HasValue ? bookingSlotBase.PortLoadId.Value : 0, DischargePortId = bookingSlotBase.PortDischargeId.HasValue ? bookingSlotBase.PortLoadId.Value : 0, DischargePort = bookingSlotBase.PortDischarge, ReceiptPlace = bookingSlotBase.PlaceReceipt, ReceiptPlaceId = bookingSlotBase.PlaceReceiptId.HasValue ? bookingSlotBase.PlaceReceiptId.Value : 0, DeliveryPlace = bookingSlotBase.PlaceDelivery, DeliveryPlaceId = bookingSlotBase.PlaceDeliveryId.HasValue ? bookingSlotBase.PlaceDeliveryId.Value : 0, BLType = "整箱", StlName = "票结", CtnInfo = new List() }; //var ctnCodeList = _cache.GetAllCodeCtn().GetAwaiter().GetResult().ToList(); if (bookingSlotCtnList != null && bookingSlotCtnList.Count > 0) { bookingSlotCtnList.Select(t => { OpCtnReq ctn = new OpCtnReq { CtnCode = t.CtnCode, CtnAll = t.CtnAll, CtnNum = t.CtnNum }; return ctn; }); } var bkRlt = await seaExportService.Value.EditSeaExport(bkModel); id = long.Parse(bkRlt.Data.ToString()); string batchNo = Guid.NewGuid().ToString(); //var hisList = _bookingOrderContactRepository.AsQueryable().Where(a => a.BookingId == id && a.IsDeleted == false).ToList(); //if (hisList.Count > 0) //{ // //批量作废 // hisList.ForEach(async a => // { // a.IsDeleted = true; // a.UpdatedTime = DateTime.Now; // a.UpdatedUserId = UserManager.UserId; // a.UpdatedUserName = UserManager.Name; // await _bookingOrderContactRepository.UpdateAsync(a); // }); //} //这里如果指定了委托单位的邮件联系人,则推送订舱联系人 if (generateModel.CustomerContactList != null && generateModel.CustomerContactList.Count > 0) { var bookingContactList = await tenantDb.Queryable() .Where(a => a.BusinessId == id && a.Deleted == false).ToListAsync(); var djyCustomerInfo = clientInfoService.GetClientInfoWithContact(new Info.Dtos.QueryClientInfo { ClientId = generateModel.CustomerId.Value, IsController = true }) .GetAwaiter().GetResult().Data; generateModel.CustomerContactList.ForEach(contact => { ClientContactRes djyCustomerContactMan = null; if (djyCustomerInfo.ClientContactList != null && djyCustomerInfo.ClientContactList.Count > 0) { djyCustomerContactMan = djyCustomerInfo.ClientContactList.FirstOrDefault(a => a.Id == contact.Id); } if (djyCustomerContactMan != null) { var bookingContact = bookingContactList .FirstOrDefault(x => x.Email.Equals(djyCustomerContactMan.Email, StringComparison.OrdinalIgnoreCase)); if (bookingContact == null) { bookingContact = new BusinessOrderContact { Name = djyCustomerContactMan.ShortName, BusinessId = id, Email = djyCustomerContactMan.Email, Note = djyCustomerContactMan.Note, CreateTime = DateTime.Now, CreateBy = long.Parse(user.UserId), CreateUserName = user.UserName }; tenantDb.Insertable(bookingContact).ExecuteCommand(); //_bookingOrderContactRepository.Insert(bookingContact); } else { bookingContact.Name = djyCustomerContactMan.ShortName; bookingContact.Email = djyCustomerContactMan.Email; bookingContact.Note = djyCustomerContactMan.Note; bookingContact.UpdateTime = DateTime.Now; bookingContact.UpdateBy = long.Parse(user.UserId); bookingContact.UpdateUserName = user.UserName; tenantDb.Updateable(bookingContact).UpdateColumns(it => new { it.Name, it.Email, it.Note, it.UpdateTime, it.UpdateBy, it.UpdateUserName }).ExecuteCommand(); } } }); } if (generateModel.ProjectList != null && generateModel.ProjectList.Count > 0) { //写入服务项目 var prjRlt = djyServiceStatusService.Value.SaveServiceProject(new EmbedServiceProjectDto { BusinessId = id.ToString(), ProjectCodes = generateModel.ProjectList.Distinct().ToArray(), }); logger.LogInformation($"推送订舱的服务项目完成 id={id} rlt={JsonConvert.SerializeObject(prjRlt)}"); } logger.LogInformation($"任务BC MBLNO:{bookingSlotBase.SlotBookingNo} 生成订舱成功 id={id}"); } catch (Exception ex) { logger.LogError($"任务BC MBLNO:{bookingSlotBase.SlotBookingNo} 生成订舱异常,原因:{ex.Message}"); } return id; } #endregion #region 获取当前比对结果 /// /// 获取当前比对结果 /// /// BC任务主键 /// 返回回执 public async Task>> GetCompareResult(long taskId) { var tenantDb = saasDbService.GetBizDbScopeById(user.TenantId); var queryList = await tenantDb.Queryable() .InnerJoin((a, b) => a.Id == b.TASK_ID) .Where((a, b) => a.Id == taskId) .Select((a, b) => new { Base = a, BC = b }) .ToListAsync(); //任务主键{taskPkId}无法获取业务信息 if (queryList.Count == 0) throw new Exception(string.Format(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.TaskBaseInfoFromTaskIdNull)), taskId)); var taskBCInfo = queryList.FirstOrDefault().BC; if (taskBCInfo.BOOKING_SLOT_ID.HasValue) { return await bookingSlotService.Value.GetSlotCompareResult(taskBCInfo.BOOKING_SLOT_ID.Value, taskBCInfo.BATCH_NO); } else { return DataResult>.FailedData(new List()); } } #endregion #region 生成并推送邮件 /// /// 生成并推送邮件 /// /// BC任务详情 /// 主任务详情 /// 检索订舱相关 /// 是否默认使用用户个人邮箱发送 /// 返回回执 private async Task GenerateSendEmail(TaskBCInfo taskBCInfo, TaskBaseInfo bcTaskInfo, SeaExportOrderExtension orderInfo, bool usePersonalEmailSend = false) { bool result = false; string msg = string.Empty; try { /* 1、提取邮件接收人、通过订舱的委托客户获取联系人信息(提取联系人中备注是BCNotice的邮箱) 2、提取当票订舱对应的操作人邮箱、通过订舱的委托客户获取操作OP的邮箱 3、读取用户邮箱配置,主要提取显示名称BCNotice的邮箱,用来作为公共邮箱来发送邮件。 4、读取邮件模板,填充详情。 5、推送邮件给邮件接收人 */ //if (bookingOrderEntity == null) //{ // var checkInfo = _bookingOrderRepository.AsQueryable().Filter(null, true) // .First(a => a.MBLNO == taskBCInfo.MBL_NO && a.IsDeleted == false && (a.ParentId == null || a.ParentId == 0)); // if (checkInfo != null) // { // throw Oops.Oh($"订舱详情获取失败,用提单号能检索到,但是没有ID关系,需要人工看看问题"); // } // else // { // throw Oops.Oh($"订舱详情获取失败,请确认订舱是否存在或已删除"); // } //} var tenantDb = saasDbService.GetBizDbScopeById(user.TenantId); var bookingOrderEntity = orderInfo.currOrder; Logger.Log(NLog.LogLevel.Info, $"获取订舱详情完成,bookid={bookingOrderEntity.Id}"); if (bookingOrderEntity.CustomerId == 0) { throw new Exception($"订舱的委托客户不能为空"); } var djyCustomerInfo = clientInfoService.GetClientInfoWithContact(new Info.Dtos.QueryClientInfo { ClientId = bookingOrderEntity.CustomerId}) .GetAwaiter().GetResult().Data; if (djyCustomerInfo == null) { throw new Exception($"委托单位详情获取失败,请确认委托单位是否存在或已删除"); } Logger.Log(NLog.LogLevel.Info, $"获取委托单位详情完成,djyCustomerId={djyCustomerInfo.Id}"); //DjyCustomerContactOutput djyCustomerContactMan = null; //TO 邮件接收人 string toEmail = string.Empty; //订舱OP的邮箱 string opEmail = string.Empty; var bookingContactList = tenantDb.Queryable() .Where(a => a.BusinessId == taskBCInfo.BOOKING_ORDER_ID).ToList(); if (bookingContactList == null || bookingContactList.Count == 0) { Logger.Log(NLog.LogLevel.Info, $"当前订舱未指定的联系人,toEmail={toEmail}"); } toEmail = string.Join(";", bookingContactList.Select(x => x.Email.Trim()).Distinct().ToArray()); //获取操作OP的邮箱 if (bookingOrderEntity.OperatorId > 0) { var opId = bookingOrderEntity.OperatorId; var opUser = _userService.GetUserInfo(opId.ToString()).Data; if (opUser != null && !string.IsNullOrWhiteSpace(opUser.Email)) { opEmail = opUser.Email.Trim(); Logger.Log(NLog.LogLevel.Info, $"获取操作OP的邮箱,opEmail={opEmail} id={opId} name={opUser.UserName}"); } } //提取当前公共邮箱的配置 CodeUserEmailRes publicMailAccount = null; if (usePersonalEmailSend) { publicMailAccount = _userEmailService.GetEmailSettings().GetAwaiter().GetResult().Data; //&& x.SmtpPort > 0 && x.SmtpServer != null && x.SmtpServer != ""); } else { //这个是公共邮箱配置 publicMailAccount = _userEmailService.GetEmailSettings("PublicSend").GetAwaiter().GetResult().Data; } if (publicMailAccount == null) { throw new Exception($"提取公共邮箱配置失败,请在用户邮箱账号管理增加配置显示名为PublicSend或者配置个人邮箱"); } Logger.Log(NLog.LogLevel.Info, $"提取当前公共邮箱的配置完成,id={publicMailAccount.Id}"); string emailTitle = $"Booking Confirmation : {taskBCInfo.MBL_NO}"; string filePath = string.Empty; UserViewModel opUserInfo = _userService.GetUserInfo(bookingOrderEntity.OperatorId.ToString()).Data; if (taskBCInfo.BUSI_TYPE == "BookingAmendment") { emailTitle = $"【变更】Booking Amendment : {taskBCInfo.MBL_NO}"; } //读取邮件模板并填充数据 string emailHtml = string.Empty; if (taskBCInfo.BUSI_TYPE == "BookingAmendment") { emailHtml = GenerateSendEmailHtmlAmendment(taskBCInfo, opUserInfo, user.TenantName).GetAwaiter().GetResult(); } else { emailHtml = GenerateSendEmailHtml(taskBCInfo, opUserInfo, user.TenantName).GetAwaiter().GetResult(); } Logger.Log(NLog.LogLevel.Info, $"生成邮件BODY,结果:{emailHtml}"); TaskFileInfo fileInfo = null; if (bcTaskInfo.TASK_TYPE == TaskBaseTypeEnum.BC.ToString()) { fileInfo = tenantDb.Queryable().Where(a => a.TASK_PKID == taskBCInfo.TASK_ID && a.FILE_CATEGORY.Contains("BC_NOTICE")) .OrderByDescending(a => a.CreateTime).First(); } else if (bcTaskInfo.TASK_TYPE == TaskBaseTypeEnum.BC_MODIFY.ToString()) { //CMA没有变更附件,所以转发邮件时默认用原文件转发 if (bcTaskInfo.CARRIER_ID.Equals("CMA", StringComparison.OrdinalIgnoreCase)) { fileInfo = tenantDb.Queryable().Where(a => a.TASK_PKID == taskBCInfo.TASK_ID && a.FILE_CATEGORY.Contains("BC_MODIFY")) .OrderByDescending(a => a.CreateTime).First(); } else { fileInfo = tenantDb.Queryable().Where(a => a.TASK_PKID == taskBCInfo.TASK_ID && a.FILE_CATEGORY.Contains("BC_MODIFY_NOTICE")) .OrderByDescending(a => a.CreateTime).First(); } } if (fileInfo == null) { throw new Exception($"提取变更文件失败,不能发送邮件"); } Logger.Log(NLog.LogLevel.Info, $"获取订舱附件地址,结果:{fileInfo.FILE_PATH}"); //var opt = App.GetOptions(); //var dirAbs = opt.basePath; //if (string.IsNullOrEmpty(dirAbs)) //{ // dirAbs = App.WebHostEnvironment.WebRootPath; //} filePath = "";//Path.Combine(dirAbs, fileInfo.FILE_PATH); EmailApiUserDefinedDto emailApiUserDefinedDto = new EmailApiUserDefinedDto { SendTo = toEmail, //CCTo = opEmail, Title = emailTitle, Body = emailHtml, Account = publicMailAccount.MailAccount?.Trim(), Password = publicMailAccount.Password?.Trim(), Server = publicMailAccount.SmtpServer?.Trim(), Port = publicMailAccount.SmtpPort.HasValue ? publicMailAccount.SmtpPort.Value : 465, UseSSL = publicMailAccount.SmtpSSL.HasValue ? publicMailAccount.SmtpSSL.Value : true, Attaches = new List() }; //如果配置了租户参数(AUTO_TRANS_EMAIL_OP_CCTO-自动转发是否默认抄送操作=ENABLE)发送邮件时自动抄送操作 var paramConfig = configService.GetConfig(CONST_AMENDMENT_DEFAULT_PARAM, long.Parse(user.TenantId), false).GetAwaiter().GetResult()?.Data?.Value; if (paramConfig != null && paramConfig.Equals("ENABLE", StringComparison.OrdinalIgnoreCase)) { emailApiUserDefinedDto.CCTo = opEmail; } Logger.Log(NLog.LogLevel.Info, $"生成请求邮件参数,结果:{JsonConvert.SerializeObject(emailApiUserDefinedDto)}"); //推送邮件 var emailRlt = await PushEmail(emailApiUserDefinedDto, filePath); Logger.Log(NLog.LogLevel.Info, $"推送邮件完成,结果:{JsonConvert.SerializeObject(emailRlt)}"); //var taskBcInfo = _taskBCInfoRepository.AsQueryable().Filter(null, true) //.First(a => a.PK_ID == taskBCInfo.PK_ID); if (emailRlt.Succeeded) { result = true; msg = "成功"; } else { result = false; msg = emailRlt.Message; //new EmailNoticeHelper().SendEmailNotice($"MBLNO={taskBCInfo.MBL_NO} 转发通知邮件失败", $"MBLNO={taskBCInfo.MBL_NO} 转发通知邮件失败,原因:{emailRlt.msg}", App.Configuration["EmailNoticeDefaultUser"].GetUserEmailList()); } } catch (Exception ex) { Logger.Log(NLog.LogLevel.Info, $"推送邮件失败,异常:{ex.Message}"); result = false; msg = $"推送邮件失败,{ex.Message}"; //new EmailNoticeHelper().SendEmailNotice($"MBLNO={taskBCInfo.MBL_NO} 转发通知邮件失败", $"MBLNO={taskBCInfo.MBL_NO} 转发通知邮件失败,原因:{ex.Message}", App.Configuration["EmailNoticeDefaultUser"].GetUserEmailList()); } if(!result) return DataResult.Failed(msg); return DataResult.Successed(msg); } #endregion #region 通过邮件模板生成HTML /// /// 通过邮件模板生成HTML /// /// BC任务详情 /// 订舱OP详情 /// 当前租户全称 /// 返回生成的HTML public async Task GenerateSendEmailHtml(TaskBCInfo taskBCInfo, UserViewModel opUserInfo, string tenantName) { string result = string.Empty; /* 1、加载模板文件,读取HTML 2、读取main、conta的tr行,替换业务数据 3、返回HTML的文本信息。 */ try { //string templatePath = App.Configuration["EmailTemplateFilePath"]; string templatePath = ""; //var opt = App.GetOptions(); //var dirAbs = opt.basePath; //if (string.IsNullOrEmpty(dirAbs)) //{ // dirAbs = App.WebHostEnvironment.WebRootPath; //} //templatePath = $"{dirAbs}{templatePath}\\BCEmailTemplate.html"; string baseHtml = File.ReadAllText(templatePath); if (string.IsNullOrWhiteSpace(baseHtml)) throw new Exception($"读取邮件模板失败"); if (opUserInfo != null && !string.IsNullOrWhiteSpace(opUserInfo.UserName)) { baseHtml = baseHtml.Replace("#opname#", opUserInfo.UserName); } else { baseHtml = baseHtml.Replace("#opname#", "操作"); } if (opUserInfo != null && !string.IsNullOrWhiteSpace(opUserInfo.Email)) { baseHtml = baseHtml.Replace("#opemail#", opUserInfo.Email); } else { baseHtml = baseHtml.Replace("#opemail#", ""); } if (opUserInfo != null && !string.IsNullOrWhiteSpace(opUserInfo.Phone)) { baseHtml = baseHtml.Replace("#optel#", opUserInfo.Phone); } else if (opUserInfo != null && !string.IsNullOrWhiteSpace(opUserInfo.Tel)) { baseHtml = baseHtml.Replace("#optel#", opUserInfo.Tel); } else { baseHtml = baseHtml.Replace("#optel#", ""); } HtmlDocument html = new HtmlDocument(); html.LoadHtml(baseHtml); HtmlNode baseTable = html.DocumentNode.SelectNodes("//table[@class='base-table']").FirstOrDefault(); if (baseTable == null) throw new Exception($"读取邮件模板格式错误,定位base-table失败"); var baseTrList = baseTable.SelectNodes(".//tr"); foreach (var baseTr in baseTrList) { var tdList = baseTr.SelectNodes(".//td"); foreach (var baseTd in tdList) { if (baseTd.Attributes["class"].Value == "billno-val") { baseTd.InnerHtml = taskBCInfo.MBL_NO; } else if (baseTd.Attributes["class"].Value == "takebillno-val") { baseTd.InnerHtml = taskBCInfo.MBL_NO; } else if (baseTd.Attributes["class"].Value == "pol-val") { baseTd.InnerHtml = taskBCInfo.PLACERECEIPT; } else if (baseTd.Attributes["class"].Value == "pod-val") { baseTd.InnerHtml = taskBCInfo.PLACEDELIVERY; } else if (baseTd.Attributes["class"].Value == "ctn-val") { baseTd.InnerHtml = taskBCInfo.CTN_STAT; } else if (baseTd.Attributes["class"].Value == "etd-val") { if (taskBCInfo.ETD.HasValue) { baseTd.InnerHtml = taskBCInfo.ETD.Value.ToString("yyyy-MM-dd"); } } else if (baseTd.Attributes["class"].Value == "eta-val") { if (taskBCInfo.ETA.HasValue) { baseTd.InnerHtml = taskBCInfo.ETA.Value.ToString("yyyy-MM-dd"); } } } } var noreplyTr = html.DocumentNode.SelectNodes("//tr[@class='email-noreply']").FirstOrDefault(); if (noreplyTr != null) { var currTd = noreplyTr.SelectNodes(".//td").FirstOrDefault(); if (currTd != null) { var currPList = currTd.SelectNodes(".//p"); foreach (var baseP in currPList) { if (baseP.Attributes["class"].Value == "notice-comp-val") { baseP.InnerHtml = tenantName; } } } } result = html.DocumentNode.OuterHtml; } catch (Exception ex) { Logger.Log(NLog.LogLevel.Info, $"通过邮件模板生成HTML异常,原因={ex.Message}"); throw ex; } return result; } #endregion #region 通过邮件模板生成HTML /// /// 通过邮件模板生成HTML /// /// BC任务详情 /// 订舱OP详情 /// 当前租户全称 /// 返回生成的HTML public async Task GenerateSendEmailHtmlAmendment(TaskBCInfo taskBCInfo, UserViewModel opUserInfo, string tenantName) { string result = string.Empty; /* 1、加载模板文件,读取HTML 2、读取main、conta的tr行,替换业务数据 3、返回HTML的文本信息。 */ try { string templatePath = ""; //App.Configuration["EmailTemplateFilePath"]; string dirAbs = ""; //var opt = App.GetOptions(); //var dirAbs = opt.basePath; //if (string.IsNullOrEmpty(dirAbs)) //{ // dirAbs = App.WebHostEnvironment.WebRootPath; //} templatePath = $"{dirAbs}{templatePath}\\BCModifyEmailTemplate.html"; string baseHtml = File.ReadAllText(templatePath); if (string.IsNullOrWhiteSpace(baseHtml)) throw new Exception($"读取邮件模板失败"); List compareList = GetCompareResult(taskBCInfo.TASK_ID).GetAwaiter().GetResult().Data; if (taskBCInfo.CARRIERID.Equals("CMA", StringComparison.OrdinalIgnoreCase)) { compareList = new List(); } else { if (compareList == null || compareList.Count == 0) throw new Exception($"读取变更数据失败,没有差异数据"); } if (opUserInfo != null && !string.IsNullOrWhiteSpace(opUserInfo.UserName)) { baseHtml = baseHtml.Replace("#opname#", opUserInfo.UserName); } else { baseHtml = baseHtml.Replace("#opname#", "操作"); } if (opUserInfo != null && !string.IsNullOrWhiteSpace(opUserInfo.Email)) { baseHtml = baseHtml.Replace("#opemail#", opUserInfo.Email); } else { baseHtml = baseHtml.Replace("#opemail#", ""); } if (opUserInfo != null && !string.IsNullOrWhiteSpace(opUserInfo.Phone)) { baseHtml = baseHtml.Replace("#optel#", opUserInfo.Phone); } else if (opUserInfo != null && !string.IsNullOrWhiteSpace(opUserInfo.Tel)) { baseHtml = baseHtml.Replace("#optel#", opUserInfo.Tel); } else { baseHtml = baseHtml.Replace("#optel#", ""); } HtmlDocument html = new HtmlDocument(); html.LoadHtml(baseHtml); HtmlNode baseTable = html.DocumentNode.SelectNodes("//table[@class='base-table']").FirstOrDefault(); if (baseTable == null) throw new Exception($"读取邮件模板格式错误,定位base-table失败"); var baseTrList = baseTable.SelectNodes(".//tr"); foreach (var baseTr in baseTrList) { var tdList = baseTr.SelectNodes(".//td"); foreach (var baseTd in tdList) { if (baseTd.Attributes["class"].Value == "billno-val") { baseTd.InnerHtml = taskBCInfo.MBL_NO; } else if (baseTd.Attributes["class"].Value == "takebillno-val") { baseTd.InnerHtml = taskBCInfo.MBL_NO; } else if (baseTd.Attributes["class"].Value == "pol-val") { baseTd.InnerHtml = taskBCInfo.PLACERECEIPT; } else if (baseTd.Attributes["class"].Value == "pod-val") { baseTd.InnerHtml = taskBCInfo.PLACEDELIVERY; } else if (baseTd.Attributes["class"].Value == "ctn-val") { baseTd.InnerHtml = taskBCInfo.CTN_STAT; } /* else if (baseTd.Attributes["class"].Value == "etd-val") { if (taskBCInfo.ETD.HasValue) { baseTd.InnerHtml = taskBCInfo.ETD.Value.ToString("yyyy-MM-dd"); } } else if (baseTd.Attributes["class"].Value == "eta-val") { if (taskBCInfo.ETA.HasValue) { baseTd.InnerHtml = taskBCInfo.ETA.Value.ToString("yyyy-MM-dd"); } }*/ } } bool isOnlyChangeOne = false; List nameList = new List(); //船名 if (compareList.Any(x => x.FieldCode.Equals("vessel", StringComparison.OrdinalIgnoreCase))) { var name = compareList.FirstOrDefault(x => x.FieldCode.Equals("vessel", StringComparison.OrdinalIgnoreCase)).TargetVal; baseTable.AppendChild(HtmlNode.CreateNode("船名 变更为:" + name + "")); nameList.Add("船名"); } //航次号 if (compareList.Any(x => x.FieldCode.Equals("voyNo", StringComparison.OrdinalIgnoreCase))) { var name = compareList.FirstOrDefault(x => x.FieldCode.Equals("voyNo", StringComparison.OrdinalIgnoreCase)).TargetVal; baseTable.AppendChild(HtmlNode.CreateNode("航次号 变更为:" + name + "")); nameList.Add("航次号"); } //ETD if (compareList.Any(x => x.FieldCode.Equals("ETD", StringComparison.OrdinalIgnoreCase))) { var name = compareList.FirstOrDefault(x => x.FieldCode.Equals("ETD", StringComparison.OrdinalIgnoreCase)).TargetVal; baseTable.AppendChild(HtmlNode.CreateNode("ETD 变更为:" + name + "")); nameList.Add("ETD"); } //ETA if (compareList.Any(x => x.FieldCode.Equals("ETA", StringComparison.OrdinalIgnoreCase))) { var name = compareList.FirstOrDefault(x => x.FieldCode.Equals("ETA", StringComparison.OrdinalIgnoreCase)).TargetVal; baseTable.AppendChild(HtmlNode.CreateNode("ETA 变更为:" + name + "")); nameList.Add("ETA"); } //CustomSICutDate 客户样单截止日期 if (compareList.Any(x => x.FieldCode.Equals("CustomSICutDate", StringComparison.OrdinalIgnoreCase))) { var name = compareList.FirstOrDefault(x => x.FieldCode.Equals("CustomSICutDate", StringComparison.OrdinalIgnoreCase)).TargetVal; baseTable.AppendChild(HtmlNode.CreateNode("样单截止日期 变更为:" + name + "")); nameList.Add("样单截止日期"); } //CYCutoffTime 截港时间 if (compareList.Any(x => x.FieldCode.Equals("CYCutoffTime", StringComparison.OrdinalIgnoreCase))) { var name = compareList.FirstOrDefault(x => x.FieldCode.Equals("CYCutoffTime", StringComparison.OrdinalIgnoreCase)).TargetVal; baseTable.AppendChild(HtmlNode.CreateNode("截港时间 变更为:" + name + "")); nameList.Add("截港时间"); } //ManifestCutDate 舱单截止时间 if (compareList.Any(x => x.FieldCode.Equals("ManifestCutDate", StringComparison.OrdinalIgnoreCase))) { var name = compareList.FirstOrDefault(x => x.FieldCode.Equals("ManifestCutDate", StringComparison.OrdinalIgnoreCase)).TargetVal; baseTable.AppendChild(HtmlNode.CreateNode("舱单截止时间 变更为:" + name + "")); nameList.Add("舱单截止时间"); } //VGMCutoffTime MDGF提交截止时间 if (compareList.Any(x => x.FieldCode.Equals("VGMCutoffTime", StringComparison.OrdinalIgnoreCase))) { var name = compareList.FirstOrDefault(x => x.FieldCode.Equals("VGMCutoffTime", StringComparison.OrdinalIgnoreCase)).TargetVal; baseTable.AppendChild(HtmlNode.CreateNode("截VGM时间 变更为:" + name + "")); nameList.Add("截VGM时间"); } //MDGFCutDate MDGF提交截止时间 if (compareList.Any(x => x.FieldCode.Equals("MDGFCutDate", StringComparison.OrdinalIgnoreCase))) { var name = compareList.FirstOrDefault(x => x.FieldCode.Equals("MDGFCutDate", StringComparison.OrdinalIgnoreCase)).TargetVal; baseTable.AppendChild(HtmlNode.CreateNode("MDGF提交截止时间 变更为:" + name + "")); nameList.Add("MDGF提交截止时间"); } //PlaceReceipt 收货地 if (compareList.Any(x => x.FieldCode.Equals("PlaceReceipt", StringComparison.OrdinalIgnoreCase))) { var name = compareList.FirstOrDefault(x => x.FieldCode.Equals("PlaceReceipt", StringComparison.OrdinalIgnoreCase)).TargetVal; baseTable.AppendChild(HtmlNode.CreateNode("收货地 变更为:" + name + "")); nameList.Add("收货地"); } //PlaceDelivery 交货地 if (compareList.Any(x => x.FieldCode.Equals("PlaceDelivery", StringComparison.OrdinalIgnoreCase))) { var name = compareList.FirstOrDefault(x => x.FieldCode.Equals("PlaceDelivery", StringComparison.OrdinalIgnoreCase)).TargetVal; baseTable.AppendChild(HtmlNode.CreateNode("交货地 变更为:" + name + "")); nameList.Add("交货地"); } var noreplyTr = html.DocumentNode.SelectNodes("//tr[@class='email-noreply']").FirstOrDefault(); if (noreplyTr != null) { var currTd = noreplyTr.SelectNodes(".//td").FirstOrDefault(); if (currTd != null) { var currPList = currTd.SelectNodes(".//p"); foreach (var baseP in currPList) { if (baseP.Attributes["class"].Value == "notice-comp-val") { baseP.InnerHtml = tenantName; } else if (baseP.Attributes["class"].Value == "dynamic-val") { if (nameList.Count > 0) { baseP.InnerHtml = $"请注意{(string.Join("、", nameList.ToArray()))} 变更,请您按相关的更新安排操作,谢谢!"; } } } } } result = html.DocumentNode.OuterHtml; } catch (Exception ex) { Logger.Log(NLog.LogLevel.Info, $"通过邮件模板生成HTML异常,原因={ex.Message}"); throw ex; } return result; } #endregion #region 推送邮件 /// /// 推送邮件 /// /// 自定义邮件详情 /// 文件路径 /// 返回回执 private async Task PushEmail(EmailApiUserDefinedDto emailApiUserDefinedDto, string filePath) { List emailList = new List(); bool result = false; string msg = string.Empty; var emailUrl = ""; if (emailUrl == null) throw new Exception("字典未配置 url_set->email_api_url 请联系管理员"); System.IO.FileStream file = new System.IO.FileStream(filePath, FileMode.Open, FileAccess.Read); int SplitSize = 5242880;//5M分片长度 int index = 1; //序号 第几片 long StartPosition = 5242880 * (index - 1); long lastLens = file.Length - StartPosition;//真不知道怎么起命了,就这样吧 if (lastLens < 5242880) { SplitSize = (int)lastLens; } byte[] heByte = new byte[SplitSize]; file.Seek(StartPosition, SeekOrigin.Begin); //第一个参数是 起始位置 file.Read(heByte, 0, SplitSize); //第三个参数是 读取长度(剩余长度) file.Close(); string base64Str = Convert.ToBase64String(heByte); emailApiUserDefinedDto.Attaches.Add(new AttachesInfo { AttachName = Path.GetFileName(filePath).Replace("_MODIFY", ""), AttachContent = base64Str }); emailList.Add(emailApiUserDefinedDto); //string strJoin = System.IO.File.ReadAllText(filePath); DateTime bDate = DateTime.Now; HttpResponseMessage res = null; try { //res = await emailUrl.SetBody(emailList, "application/json").PostAsync(); } catch (Exception ex) { Logger.Log(NLog.LogLevel.Info, $"发送邮件异常:{ex.Message}"); } DateTime eDate = DateTime.Now; TimeSpan ts = eDate.Subtract(bDate); var timeDiff = ts.TotalMilliseconds; Logger.Log(NLog.LogLevel.Info, $"邮件上传完成 上传文件大小:{heByte.Length} 用时:{timeDiff}ms.,"); Logger.Log(NLog.LogLevel.Info, $"发送邮件返回:{JsonConvert.SerializeObject(res)}"); if (res != null && res.StatusCode == System.Net.HttpStatusCode.OK) { var userResult = await res.Content.ReadAsStringAsync(); var respObj = JsonConvert.DeserializeAnonymousType(userResult, new { Success = false, Message = string.Empty, Code = -9999, }); result = respObj.Success; msg = respObj.Message; } return DataResult.Successed(""); } #endregion #region 发送邮件 /// /// 发送邮件 /// /// BC任务主键 /// 是否默认使用用户个人邮箱发送 /// 返回回执 public async Task SendEmail(string taskPKId, bool usePersonalEmailSend = false) { return null; } #endregion #region 同步舱位变更 /// /// 同步舱位变更 /// /// BC任务主键 /// 返回回执 public async Task SyncBookingSlotChange(long taskPKId) { /* * Amendment 1、需要先匹配舱位,如果没有舱位不能执行后续的步骤。 2、判断当前租户是否配置了自动转发客户邮件。 3、如果配置了自动转发,需要判断订舱是否已有,没有不能执行自动转发。 4、转发需要提取差异数据,如果没有差异数据也不能转发邮件。 5、默认通过钉钉通知操作收到了变更通知。 * Cancellation 1、需要先匹配舱位,如果没有舱位不能执行后续的步骤。 2、判断当前租户是否配置了自动转发客户邮件。 3、如果配置了自动转发,需要判断订舱是否已有,没有不能执行自动转发。 4、转发需要提取差异数据,如果没有差异数据也不能转发邮件。 */ try { var tenantDb = saasDbService.GetBizDbScopeById(user.TenantId); 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, BC = b }) .ToListAsync(); //任务主键{taskPkId}无法获取业务信息 if (queryList.Count == 0) throw new Exception(string.Format(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.TaskBaseInfoFromTaskIdNull)), taskPKId)); var paramConfig = configService.GetConfig(CONST_AMENDMENT_DEFAULT_PARAM, long.Parse(user.TenantId), false).GetAwaiter().GetResult()?.Data?.Value; Logger.Log(NLog.LogLevel.Info, $"taskPKId={taskPKId} 判断是否默认转发邮件 paramConfig={paramConfig}"); var taskBcInfo = queryList.FirstOrDefault().BC; var taskBaseInfo = queryList.FirstOrDefault().Base; var orderInfo = seaExportService.Value.SearchOrderInfo(taskBcInfo.MBL_NO).GetAwaiter().GetResult().Data; if (orderInfo != null && orderInfo.currOrder != null) { //更新订舱相关内容 if(paramConfig.Equals("ENABLE", StringComparison.OrdinalIgnoreCase)) { await GenerateSendEmail(taskBcInfo, taskBaseInfo, orderInfo); } } else { //终止执行 } } catch (Exception ex) { } return DataResult.Successed(""); } #endregion } }