From cf303d0be44e10dd2da7a93d57f367f9315c6390 Mon Sep 17 00:00:00 2001 From: jianghaiqing Date: Fri, 7 Jun 2024 15:53:33 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=88=AA=E6=AD=A2=E6=97=B6?= =?UTF-8?q?=E9=97=B4=E5=8F=98=E6=9B=B4=E9=82=AE=E4=BB=B6=E8=BD=AC=E5=8F=91?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TaskCutDateChangeDetailInfo.cs | 62 ++ .../TaskManagePlat/TaskCutDateChangeInfo.cs | 24 + .../BookingOrder/BookingOrderService.cs | 2 +- .../CutDateChange/TaskCutDateChangeDto.cs | 52 ++ .../CutDateChange/TaskCutDateChangeShowDto.cs | 30 + .../TaskManagePlat/Dtos/TaskManageMapper.cs | 22 +- .../ITaskManageCutDateChangeService.cs | 21 + .../TaskManageCutDateChangeService.cs | 637 +++++++++++++++++- .../TaskManagePlat/TaskManageService.cs | 2 +- 9 files changed, 844 insertions(+), 8 deletions(-) diff --git a/Myshipping.Application/Entity/TaskManagePlat/TaskCutDateChangeDetailInfo.cs b/Myshipping.Application/Entity/TaskManagePlat/TaskCutDateChangeDetailInfo.cs index b8a59337..b596142d 100644 --- a/Myshipping.Application/Entity/TaskManagePlat/TaskCutDateChangeDetailInfo.cs +++ b/Myshipping.Application/Entity/TaskManagePlat/TaskCutDateChangeDetailInfo.cs @@ -3,6 +3,7 @@ using SqlSugar; using System; using System.Collections.Generic; using System.ComponentModel; +using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -110,5 +111,66 @@ namespace Myshipping.Application /// 订舱ID /// public Nullable BOOKING_ID { get; set; } + + /// + /// 舱位主键 + /// + public Nullable BOOKING_SLOT_ID { get; set; } + + /// + /// 是否已发通知 1-已发送 0-未发送 + /// + public bool IS_NOTICE { get; set; } + + /// + /// 发送通知时间 + /// + public Nullable NOTICE_DATE { get; set; } + + /// + /// 状态 + /// + public string STATUS { get; set; } + + /// + /// 状态名称 + /// + public string STATUS_NAME { get; set; } + + /// + /// 委托单位名称 + /// + public string CUSTOM_NAME { get; set; } + + /// + /// 原因 + /// + public string REASON { get; set; } + + /// + /// 集装箱号 + /// + public string CONTA_NO { get; set; } + + /// + /// 截补料时间 + /// + public Nullable VOUCHER_CUT_DATE { get; set; } + + /// + /// 装货港 + /// + public string LOAD_PORT { get; set; } + + /// + /// 预计到港 + /// + public Nullable ETD { get; set; } + + /// + /// 预计靠泊 + /// + public Nullable ETB { get; set; } + } } diff --git a/Myshipping.Application/Entity/TaskManagePlat/TaskCutDateChangeInfo.cs b/Myshipping.Application/Entity/TaskManagePlat/TaskCutDateChangeInfo.cs index e6f607b7..7a194f11 100644 --- a/Myshipping.Application/Entity/TaskManagePlat/TaskCutDateChangeInfo.cs +++ b/Myshipping.Application/Entity/TaskManagePlat/TaskCutDateChangeInfo.cs @@ -41,5 +41,29 @@ namespace Myshipping.Application /// public Nullable NOTICE_DATE { get; set; } + /// + /// 订舱ID + /// + public Nullable BOOKING_ID { get; set; } + + /// + /// 舱位主键 + /// + public Nullable BOOKING_SLOT_ID { get; set; } + + /// + /// 主单号 + /// + public string MBL_NO { get; set; } + + /// + /// 装货港区域 NORTH_PORT-华北港口 SOUTH-华南港口 + /// + public string PORTLOAD_AREA { get; set; } + + /// + /// 原因 + /// + public string REASON { get; set; } } } diff --git a/Myshipping.Application/Service/BookingOrder/BookingOrderService.cs b/Myshipping.Application/Service/BookingOrder/BookingOrderService.cs index 5203950a..20cf9081 100644 --- a/Myshipping.Application/Service/BookingOrder/BookingOrderService.cs +++ b/Myshipping.Application/Service/BookingOrder/BookingOrderService.cs @@ -7549,7 +7549,7 @@ namespace Myshipping.Application order.BOOKINGNO = flowno; await _rep.AsUpdateable(order).UpdateColumns(x => new { x.BOOKINGNO }).ExecuteCommandAsync(); - _logger.LogInformation("批次={no} INTTRA 判断业务编号长度不能大于14,重新生成 MBLNO={mblno} custno={custno} 新单号{flowno}", batchNo, primaryModel.MBLNO, order.BOOKINGNO, flowno); + _logger.LogInformation("批次={no} INTTRA 判断业务编号长度不能大于14,重新生成 MBLNO={mblno} BOOKINGNO={BOOKINGNO} 新单号{flowno}", batchNo, primaryModel.MBLNO, order.BOOKINGNO, flowno); } } } diff --git a/Myshipping.Application/Service/TaskManagePlat/Dtos/CutDateChange/TaskCutDateChangeDto.cs b/Myshipping.Application/Service/TaskManagePlat/Dtos/CutDateChange/TaskCutDateChangeDto.cs index b7610c6d..2c37df72 100644 --- a/Myshipping.Application/Service/TaskManagePlat/Dtos/CutDateChange/TaskCutDateChangeDto.cs +++ b/Myshipping.Application/Service/TaskManagePlat/Dtos/CutDateChange/TaskCutDateChangeDto.cs @@ -45,6 +45,22 @@ namespace Myshipping.Application.Service.TaskManagePlat.Dtos /// 生成时间 /// public DateTime CreateTime { get; set; } + + /// + /// 原因 + /// + public string Reason { get; set; } + + /// + /// 装货港区域 NORTH_PORT-华北港口 SOUTH-华南港口 + /// + public string PortLoadArea { get; set; } + + /// + /// 提单号 + /// + public string MBLNo { get; set; } + } /// @@ -136,5 +152,41 @@ namespace Myshipping.Application.Service.TaskManagePlat.Dtos /// 截关时间文本 海关放行截止时间(Customs Clearance Deadline) /// public string ClosingDateTxt { get; set; } + + /// + /// 提单补料截止时间 + /// + public Nullable VoucherCutoffTime { get; set; } + + /// + /// 提单补料截止时间文本 + /// + + public string VoucherCutoffTimeTxt { get; set; } + /// + /// 装货港 + /// + public string LoadPort { get; set; } + + /// + /// 预计到港 + /// + public Nullable ETD { get; set; } + + /// + /// 预计靠泊 + /// + public Nullable ETB { get; set; } + + /// + /// 集装箱号 + /// + + public string ContaNo { get; set; } + + /// + /// 原因 + /// + public string Reason { get; set; } } } diff --git a/Myshipping.Application/Service/TaskManagePlat/Dtos/CutDateChange/TaskCutDateChangeShowDto.cs b/Myshipping.Application/Service/TaskManagePlat/Dtos/CutDateChange/TaskCutDateChangeShowDto.cs index 33b37bf6..c14803cf 100644 --- a/Myshipping.Application/Service/TaskManagePlat/Dtos/CutDateChange/TaskCutDateChangeShowDto.cs +++ b/Myshipping.Application/Service/TaskManagePlat/Dtos/CutDateChange/TaskCutDateChangeShowDto.cs @@ -105,5 +105,35 @@ namespace Myshipping.Application /// 通知接收时间 /// public Nullable NoticeDate { get; set; } + + /// + /// 原因 + /// + public string Reason { get; set; } + + /// + /// 集装箱号 + /// + public string ContaNo { get; set; } + + /// + /// 装货港 + /// + public string LoadPort { get; set; } + + /// + /// 预计离港时间 + /// + public Nullable ETD { get; set; } + + /// + /// 预计靠泊时间 + /// + public Nullable ETB { get; set; } + + /// + /// 截补料时间 + /// + public Nullable VoucherCutoffTime { get; set; } } } diff --git a/Myshipping.Application/Service/TaskManagePlat/Dtos/TaskManageMapper.cs b/Myshipping.Application/Service/TaskManagePlat/Dtos/TaskManageMapper.cs index fafa4f61..ecabc6a2 100644 --- a/Myshipping.Application/Service/TaskManagePlat/Dtos/TaskManageMapper.cs +++ b/Myshipping.Application/Service/TaskManagePlat/Dtos/TaskManageMapper.cs @@ -988,7 +988,10 @@ namespace Myshipping.Application .Map(dest => dest.VESSEL, src => src.Vessel) .Map(dest => dest.VOYNO, src => src.VoyNo) .Map(dest => dest.NOTICE_DATE, src => src.CreateTime) - .Map(dest => dest.VESSEL, src => src.Vessel); + .Map(dest => dest.VESSEL, src => src.Vessel) + .Map(dest => dest.MBL_NO, src => src.MBLNo) + .Map(dest => dest.PORTLOAD_AREA, src => src.PortLoadArea) + .Map(dest => dest.REASON, src => src.Reason); config.ForType() @@ -1008,8 +1011,13 @@ namespace Myshipping.Application .Map(dest => dest.VGM_CUT, src => src.VGMCutoffTime) .Map(dest => dest.VGM_CUT_TXT, src => src.VGMCutoffTimeTxt) .Map(dest => dest.CLOSING_DATE, src => src.ClosingDate) - .Map(dest => dest.CLOSING_DATE_TXT, src => src.ClosingDateTxt); - + .Map(dest => dest.CLOSING_DATE_TXT, src => src.ClosingDateTxt) + .Map(dest => dest.VOUCHER_CUT_DATE, src => src.VoucherCutoffTime) + .Map(dest => dest.LOAD_PORT, src => src.LoadPort) + .Map(dest => dest.ETD, src => src.ETD) + .Map(dest => dest.ETB, src => src.ETB) + .Map(dest => dest.REASON, src => src.Reason) + .Map(dest => dest.CONTA_NO, src => src.ContaNo); config.ForType() .Map(dest => dest.MBLNo, src => src.MBL_NO) @@ -1028,8 +1036,12 @@ namespace Myshipping.Application .Map(dest => dest.VGMCutoffTime, src => src.VGM_CUT) .Map(dest => dest.VGMCutoffTimeTxt, src => src.VGM_CUT_TXT) .Map(dest => dest.ClosingDate, src => src.CLOSING_DATE) - .Map(dest => dest.ClosingDateTxt, src => src.CLOSING_DATE_TXT); - + .Map(dest => dest.ClosingDateTxt, src => src.CLOSING_DATE_TXT) + .Map(dest => dest.ContaNo, src => src.CONTA_NO) + .Map(dest => dest.LoadPort, src => src.LOAD_PORT) + .Map(dest => dest.ETB, src => src.ETB) + .Map(dest => dest.ETD, src => src.ETD) + .Map(dest => dest.VoucherCutoffTime, src => src.VOUCHER_CUT_DATE); config.ForType() .Map(dest => dest.MBL_NO, src => src.MblNo) diff --git a/Myshipping.Application/Service/TaskManagePlat/Interface/ITaskManageCutDateChangeService.cs b/Myshipping.Application/Service/TaskManagePlat/Interface/ITaskManageCutDateChangeService.cs index 3b61f13f..a0c43563 100644 --- a/Myshipping.Application/Service/TaskManagePlat/Interface/ITaskManageCutDateChangeService.cs +++ b/Myshipping.Application/Service/TaskManagePlat/Interface/ITaskManageCutDateChangeService.cs @@ -36,5 +36,26 @@ namespace Myshipping.Application /// 截止时间变更任务主键 /// 返回回执 Task SendInstantMessage(string taskPkId); + + /// + /// 自动转发截止时间变更 + /// + /// 截止时间变更任务主键 + /// 返回回执 + Task AutoTransferNotice(string taskPKId); + + /// + /// 检索对应的订舱订单 + /// + /// 截止时间变更任务主键 + /// 返回回执 + Task QueryBookingOrder(string taskPKId); + + /// + /// 发送邮件通知给客户 + /// + /// 截止时间变更主键 + /// 返回回执 + Task SendEmailToCustomer(string taskPKId); } } diff --git a/Myshipping.Application/Service/TaskManagePlat/TaskManageCutDateChangeService.cs b/Myshipping.Application/Service/TaskManagePlat/TaskManageCutDateChangeService.cs index f46e5172..24a5faa1 100644 --- a/Myshipping.Application/Service/TaskManagePlat/TaskManageCutDateChangeService.cs +++ b/Myshipping.Application/Service/TaskManagePlat/TaskManageCutDateChangeService.cs @@ -1,17 +1,30 @@ -using Furion.DynamicApiController; +using Furion; +using Furion.DynamicApiController; using Furion.FriendlyException; +using Furion.JsonSerialization; +using Furion.RemoteRequest.Extensions; +using HtmlAgilityPack; using Mapster; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using Myshipping.Application.ConfigOption; using Myshipping.Application.Entity; +using Myshipping.Application.Enum; +using Myshipping.Application.Helper; using Myshipping.Core; +using Myshipping.Core.Entity; using Myshipping.Core.Helper; +using Myshipping.Core.Service; +using Newtonsoft.Json; using Npoi.Mapper; using NPOI.OpenXmlFormats.Wordprocessing; using Org.BouncyCastle.Crypto; using SqlSugar; using System; using System.Collections.Generic; +using System.IO; using System.Linq; +using System.Net.Http; using System.Text; using System.Threading.Tasks; @@ -27,16 +40,35 @@ namespace Myshipping.Application private readonly SqlSugarRepository _taskCutDateChangeDetailInfoRepository; private readonly SqlSugarRepository _taskBaseRepository; private readonly SqlSugarRepository _bookingOrderRepository; + private readonly ILogger _logger; + private readonly SqlSugarRepository _bookingOrderContactRepository; + private readonly SqlSugarRepository _sysUserRepository; + private readonly SqlSugarRepository _djyUserMailAccount; + private readonly SqlSugarRepository _repPrintTemplate; + private readonly ISysCacheService _cache; public TaskManageCutDateChangeService(SqlSugarRepository taskCutDateChangeInfoRepository, SqlSugarRepository taskCutDateChangeDetailInfoRepository, + SqlSugarRepository bookingOrderContactRepository, SqlSugarRepository taskBaseRepository, + SqlSugarRepository sysUserRepository, + SqlSugarRepository djyUserMailAccount, + SqlSugarRepository repPrintTemplate, + ILogger logger, + ISysCacheService cache, SqlSugarRepository bookingOrderRepository) { _taskCutDateChangeInfoRepository = taskCutDateChangeInfoRepository; _taskCutDateChangeDetailInfoRepository = taskCutDateChangeDetailInfoRepository; _taskBaseRepository = taskBaseRepository; _bookingOrderRepository = bookingOrderRepository; + _bookingOrderContactRepository = bookingOrderContactRepository; + _sysUserRepository = sysUserRepository; + _djyUserMailAccount = djyUserMailAccount; + _repPrintTemplate = repPrintTemplate; + + _logger = logger; + _cache = cache; } #region 获取截止时间变更详情 @@ -259,5 +291,608 @@ namespace Myshipping.Application return result; } #endregion + + + #region 自动转发截止时间变更通知 + /// + /// 自动转发截止时间变更通知 + /// + /// 截止时间变更通知任务主键 + /// 返回回执 + [HttpGet("/TaskManageCutDate/AutoTransferNotice")] + public async Task AutoTransferNotice(string taskPKId) + { + TaskManageOrderResultDto result = new TaskManageOrderResultDto(); + + try + { + var queryRlt = QueryBookingOrder(taskPKId); + + _logger.LogInformation($"taskPKId={taskPKId} 检索对应的订舱记录完成,结果:{JSON.Serialize(queryRlt)}"); + + + //_logger.LogInformation($"taskPKId={taskPKId} 当前租户未开启货物运输计划已变更是否同批次同客户合并邮件通知,按照单票推送邮件处理"); + + //如果没有配置批量,则按单票发送邮件 + var rlt = SendEmailToCustomer(taskPKId); + + _logger.LogInformation($"taskPKId={taskPKId} 推送邮件完成,结果:{JSON.Serialize(rlt)}"); + + } + catch (Exception ex) + { + result.succ = false; + result.msg = $"自动转发截止时间变更失败,原因:{ex.Message}"; + + _logger.LogInformation($"taskPKId={taskPKId} 自动转发截止时间变更失败,原因:{ex.Message}"); + } + + return result; + } + #endregion + + #region 检索对应的订舱订单 + /// + /// 检索对应的订舱订单 + /// + /// 截止时间变更任务主键 + /// 返回回执 + [HttpGet("/TaskManageCutDate/QueryBookingOrder")] + public async Task QueryBookingOrder(string taskPKId) + { + TaskManageOrderResultDto result = new TaskManageOrderResultDto(); + + try + { + var taskBase = _taskBaseRepository.AsQueryable().Filter(null, true).First(a => a.PK_ID == taskPKId); + + if (taskBase == null) + throw Oops.Oh($"任务主键{taskPKId}无法获取业务信息"); + + var entityInfo = _taskCutDateChangeInfoRepository.AsQueryable().Filter(null, true).First(a => a.TASK_ID == taskBase.PK_ID); + + if (entityInfo == null) + throw Oops.Oh($"起运港未提箱主键{taskPKId}无法获取业务信息"); + + //通过船名航次取是主单的订舱记录列表 + var bookingInfo = _bookingOrderRepository.AsQueryable().Filter(null, true).First(a => a.MBLNO == entityInfo.MBL_NO + && a.IsDeleted == false && (a.ParentId == null || a.ParentId == 0) && a.TenantId == UserManager.TENANT_ID); + + if (bookingInfo != null) + { + entityInfo.BOOKING_ID = bookingInfo.Id; + + entityInfo.UpdatedTime = DateTime.Now; + entityInfo.UpdatedUserId = UserManager.UserId; + entityInfo.UpdatedUserName = UserManager.Name; + + await _taskCutDateChangeInfoRepository.AsUpdateable(entityInfo).UpdateColumns(x => new { + x.BOOKING_ID, + x.UpdatedTime, + x.UpdatedUserId, + x.UpdatedUserName + }).ExecuteCommandAsync(); + + var list = _taskCutDateChangeDetailInfoRepository.AsQueryable().Filter(null, true).Where(a => a.P_ID == entityInfo.PK_ID).ToList(); + + if(list != null && list.Count > 0) + { + list.ForEach(async p => + { + if (p.MBL_NO.Equals(entityInfo.MBL_NO, StringComparison.OrdinalIgnoreCase)) + { + p.BOOKING_ID = bookingInfo.Id; + p.UpdatedTime = DateTime.Now; + p.UpdatedUserId = UserManager.UserId; + p.UpdatedUserName = UserManager.Name; + + await _taskCutDateChangeDetailInfoRepository.AsUpdateable(p).UpdateColumns(x => new { + x.BOOKING_ID, + x.UpdatedTime, + x.UpdatedUserId, + x.UpdatedUserName + }).ExecuteCommandAsync(); + } + }); + } + + result.succ = true; + result.msg = "检索对应成功"; + } + else + { + result.succ = false; + result.msg = $"检索对应失败,提单号:{entityInfo.MBL_NO} 没有对应的订舱记录"; + } + } + catch (Exception ex) + { + result.succ = false; + result.msg = $"检索失败,原因:{ex.Message}"; + + _logger.LogInformation($"taskPKId={taskPKId} 检索起运港未提箱订舱记录 处理异常,原因:{ex.Message}"); + } + + return result; + } + #endregion + + #region 发送邮件通知给客户 + /// + /// 发送邮件通知给客户 + /// + /// 起运港未提箱通知主键 + /// 返回回执 + [HttpGet("/TaskManageCutDate/SendEmailToCustomer")] + public async Task SendEmailToCustomer(string taskPKId) + { + TaskManageOrderResultDto result = new TaskManageOrderResultDto(); + + try + { + var entityInfo = _taskCutDateChangeInfoRepository.AsQueryable().Filter(null, true).First(a => a.TASK_ID == taskPKId); + + var list = _taskCutDateChangeDetailInfoRepository.AsQueryable().Filter(null, true).Where(a => a.P_ID == entityInfo.PK_ID).ToList(); + + if (!entityInfo.BOOKING_ID.HasValue) + { + new EmailNoticeHelper().SendEmailNotice($"taskid={taskPKId} mblno={entityInfo.MBL_NO} 起运港未提箱 转发通知邮件失败", $"taskid={taskPKId} mblno={entityInfo.MBL_NO} 当前任务没有对应的订舱订单,不能转发邮件,请先检索对应的订舱订单", App.Configuration["EmailNoticeDefaultUser"].GetUserEmailList()); + + throw Oops.Oh($"当前任务没有对应的订舱订单,不能转发邮件,请先检索对应的订舱订单"); + } + + var bookingOrderList = _bookingOrderRepository.AsQueryable().Filter(null, true).Where(a => a.Id == entityInfo.BOOKING_ID.Value && a.IsDeleted == false && a.TenantId == UserManager.TENANT_ID).ToList(); + + if (bookingOrderList.Count == 0) + { + new EmailNoticeHelper().SendEmailNotice($"taskid={taskPKId} mblno={entityInfo.MBL_NO} 起运港未提箱 转发通知邮件失败", $"taskid={taskPKId} mblno={entityInfo.MBL_NO} 当前任务对应的订舱订单不存在或已作废", App.Configuration["EmailNoticeDefaultUser"].GetUserEmailList()); + + throw Oops.Oh($"当前任务对应的订舱订单不存在或已作废"); + } + + var bookingId = entityInfo.BOOKING_ID.Value; + + var bookingContactList = _bookingOrderContactRepository.AsQueryable().Filter(null, true) + .Where(a => bookingId == a.BookingId.Value && a.IsDeleted == false).ToList(); + + result = await GenerateSendEmail(entityInfo, list, bookingOrderList, bookingContactList); + + list.ForEach(async p => + { + var model = _taskCutDateChangeDetailInfoRepository.AsQueryable().Filter(null, true).First(a => a.PK_ID == p.PK_ID); + + if (model != null) + { + model.IS_NOTICE = true; + model.STATUS = result.succ ? "SUCC" : "FAILURE"; + model.STATUS_NAME = result.succ ? "成功" : "失败"; + model.NOTICE_DATE = DateTime.Now; + + await _taskCutDateChangeDetailInfoRepository.AsUpdateable(model).UpdateColumns(x => new + { + x.IS_NOTICE, + x.STATUS, + x.STATUS_NAME, + x.NOTICE_DATE, + }).ExecuteCommandAsync(); + } + + }); + } + catch (Exception ex) + { + result.succ = false; + result.msg = $"发送邮件失败,原因:{ex.Message}"; + } + + return result; + } + #endregion + + #region 生成并转发通知邮件 + /// + /// 生成并转发通知邮件 + /// + /// + /// + /// + /// + /// + [NonAction] + private async Task GenerateSendEmail(TaskCutDateChangeInfo model, List rowList, List bookingOrderList, List bookingContactList) + { + TaskManageOrderResultDto result = new TaskManageOrderResultDto(); + + try + { + //TO 邮件接收人 + string toEmail = string.Empty; + //订舱OP的邮箱 + string opEmail = string.Empty; + + //去重客户联系人的邮箱 + toEmail = string.Join(";", bookingContactList.Select(x => x.Email.Trim()).Distinct().ToArray()); + + List opEmailList = new List(); + + SysUser opUserInfo = null; + + bookingOrderList.ForEach(bk => + { + //获取操作OP的邮箱 + if (!string.IsNullOrWhiteSpace(bk.OPID)) + { + var opId = long.Parse(bk.OPID); + var opUser = _sysUserRepository.AsQueryable().Filter(null, true).First(a => a.Id == opId); + + if (opUser != null) + { + if (opUserInfo == null) + opUserInfo = opUser; + + if (!string.IsNullOrWhiteSpace(opUser.Email)) + { + opEmailList.Add(opUser.Email.Trim()); + + _logger.LogInformation($"id={bk.Id} mblno={bk.MBLNO} 获取操作OP的邮箱,opEmail={opEmail} opid={opId} name={opUser.Name}"); + } + else + { + _logger.LogInformation($"id={bk.Id} mblno={bk.MBLNO} 获取操作OP的邮箱失败,opEmail={opUser.Email} opid={opId} name={opUser.Name}"); + } + } + else + { + _logger.LogInformation($"id={bk.Id} mblno={bk.MBLNO} 检索操作OP信息失败,opid={opId} name={opUser.Name}"); + } + } + + //获取客服的邮箱 + if (!string.IsNullOrWhiteSpace(bk.CUSTSERVICEID)) + { + var opId = long.Parse(bk.CUSTSERVICEID); + var opUser = _sysUserRepository.AsQueryable().Filter(null, true).First(a => a.Id == opId); + + if (opUser != null) + { + if (!string.IsNullOrWhiteSpace(opUser.Email)) + { + opEmailList.Add(opUser.Email.Trim()); + + _logger.LogInformation($"id={bk.Id} mblno={bk.MBLNO} 获取客服的邮箱,opEmail={opEmail} opid={opId} name={opUser.Name}"); + } + else + { + _logger.LogInformation($"id={bk.Id} mblno={bk.MBLNO} 获取客服的邮箱失败,opEmail={opUser.Email} opid={opId} name={opUser.Name}"); + } + } + else + { + _logger.LogInformation($"id={bk.Id} mblno={bk.MBLNO} 检索客服信息失败,opid={opId} name={opUser.Name}"); + } + } + }); + if (opEmailList.Count > 0) + opEmail = string.Join(";", opEmailList.Distinct().ToArray()); + + string emailTitle = $"{model.MBL_NO}-{model.VESSEL}/{model.VOYNO}/ 未提箱订舱取消确认"; + + //提取当前公共邮箱的配置 + DjyUserMailAccount publicMailAccount = _djyUserMailAccount.AsQueryable().Filter(null, true).First(x => x.TenantId == UserManager.TENANT_ID && x.ShowName == "PublicSend" + && x.SmtpPort > 0 && x.SmtpServer != null && x.SmtpServer != ""); + + _logger.LogInformation($"提取当前公共邮箱的配置完成,id={publicMailAccount.Id}"); + + if (publicMailAccount == null) + { + throw Oops.Oh($"提取公共邮箱配置失败,请在用户邮箱账号管理增加配置显示名为PublicSend或者配置个人邮箱"); + } + + //获取邮件模板 + var printTemplate = _repPrintTemplate.AsQueryable().Filter(null, true).First(x => x.CateCode.Contains("for_information_cutoff_detail")); + + if (printTemplate == null) + { + throw Oops.Bah(BookingErrorCode.BOOK115); + } + + //读取邮件模板并填充数据 + string emailHtml = GenerateSendEmailHtml(model, rowList, bookingOrderList, printTemplate.FilePath, opUserInfo, UserManager.TENANT_NAME).GetAwaiter().GetResult(); + + 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() + }; + + _logger.LogInformation($"生成请求邮件参数,结果:{JSON.Serialize(emailApiUserDefinedDto)}"); + + //推送邮件 + var emailRlt = await PushEmail(emailApiUserDefinedDto); + + _logger.LogInformation($"推送邮件完成,结果:{JSON.Serialize(emailRlt)}"); + + + if (emailRlt.succ) + { + result.succ = true; + result.msg = "成功"; + } + else + { + result.succ = false; + result.msg = emailRlt.msg; + + new EmailNoticeHelper().SendEmailNotice($"taskid={model.TASK_ID} 截止时间变更 转发通知邮件失败", $"taskid={model.TASK_ID} 转发通知邮件失败,原因:{emailRlt.msg}", App.Configuration["EmailNoticeDefaultUser"].GetUserEmailList()); + } + } + catch (Exception ex) + { + result.succ = false; + result.msg = $"失败,原因:{ex.Message}"; + + new EmailNoticeHelper().SendEmailNotice($"taskid={model.TASK_ID} 截止时间变更 转发通知邮件失败", $"taskid={model.TASK_ID} 转发通知邮件失败,原因:{ex.Message}", App.Configuration["EmailNoticeDefaultUser"].GetUserEmailList()); + } + + return result; + } + #endregion + + #region 通过邮件模板生成HTML + /// + /// 通过邮件模板生成HTML + /// + /// + /// + /// + /// + /// + /// + [NonAction] + private async Task GenerateSendEmailHtml(TaskCutDateChangeInfo model,List rowList, List bookingOrderList, + string filePath, SysUser opUserInfo, string tenantName) + { + string result = string.Empty; + string baseHtml = string.Empty; + + try + { + var opt = App.GetOptions(); + var dirAbs = opt.basePath; + if (string.IsNullOrEmpty(dirAbs)) + { + dirAbs = App.WebHostEnvironment.WebRootPath; + } + + var fileAbsPath = Path.Combine(dirAbs, filePath); + _logger.LogInformation($"查找模板文件:{fileAbsPath}"); + + if (!File.Exists(fileAbsPath)) + { + throw Oops.Bah(BookingErrorCode.BOOK115); + } + + baseHtml = File.ReadAllText(fileAbsPath); + + if (opUserInfo != null && !string.IsNullOrWhiteSpace(opUserInfo.Name)) + { + baseHtml = baseHtml.Replace("#opname#", opUserInfo.Name); + } + 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#", ""); + } + + if (!string.IsNullOrWhiteSpace(model.MBL_NO)) + { + baseHtml = baseHtml.Replace("#BillNo#", model.MBL_NO); + } + else + { + baseHtml = baseHtml.Replace("#BillNo#", ""); + } + + if (!string.IsNullOrWhiteSpace(model.VESSEL)) + { + string s = $"{model.VESSEL}/{model.VOYNO}"; + baseHtml = baseHtml.Replace("#VesselVoyno#", s); + } + else + { + baseHtml = baseHtml.Replace("#VesselVoyno#", ""); + } + + var detailInfo = rowList.FirstOrDefault(); + + if (detailInfo.SI_CUTOFF.HasValue) + { + baseHtml = baseHtml.Replace("#SICutDate#", detailInfo.SI_CUTOFF.Value.ToString("yyyy-MM-dd HH:mm")); + } + else + { + baseHtml = baseHtml.Replace("#SICutDate#", ""); + } + + if (detailInfo.VGM_CUT.HasValue) + { + baseHtml = baseHtml.Replace("#VGMCutDate#", detailInfo.VGM_CUT.Value.ToString("yyyy-MM-dd HH:mm")); + } + else + { + baseHtml = baseHtml.Replace("#VGMCutDate#", ""); + } + + if (detailInfo.CY_CUTOFF.HasValue) + { + baseHtml = baseHtml.Replace("#CYCutDate#", detailInfo.CY_CUTOFF.Value.ToString("yyyy-MM-dd HH:mm")); + } + else + { + baseHtml = baseHtml.Replace("#CYCutDate#", ""); + } + + if (detailInfo.VOUCHER_CUT_DATE.HasValue) + { + baseHtml = baseHtml.Replace("#VoucherCutDate#", detailInfo.VOUCHER_CUT_DATE.Value.ToString("yyyy-MM-dd HH:mm")); + } + else + { + baseHtml = baseHtml.Replace("#VoucherCutDate#", ""); + } + + if (detailInfo.CY_OPEN.HasValue) + { + baseHtml = baseHtml.Replace("#CYOpenDate#", detailInfo.CY_OPEN.Value.ToString("yyyy-MM-dd")); + } + else + { + baseHtml = baseHtml.Replace("#CYOpenDate#", ""); + } + + if (!string.IsNullOrWhiteSpace(detailInfo.REASON)) + { + baseHtml = baseHtml.Replace("#Reason#", model.REASON); + } + else + { + baseHtml = baseHtml.Replace("#Reason#", ""); + } + + if (!string.IsNullOrWhiteSpace(tenantName)) + { + baseHtml = baseHtml.Replace("#TenantCompanyName#", tenantName); + } + else + { + baseHtml = baseHtml.Replace("#TenantCompanyName#", ""); + } + + HtmlDocument html = new HtmlDocument(); + html.LoadHtml(baseHtml); + + var tableNode = html.DocumentNode.SelectSingleNode(".//table[@id='show-table']"); + + if (tableNode != null) + { + StringBuilder tableBuilder = new StringBuilder(); + + for (int i = 0; i < rowList.Count; i++) + { + tableBuilder.Append($"{rowList[i].MBL_NO}{rowList[i].CONTA_NO}{rowList[i].LOAD_PORT}{(rowList[i].ETB.HasValue? rowList[i].ETB.Value.ToString("yyyy-MM-dd HH:mm"):"")}{(rowList[i].ETD.HasValue ? rowList[i].ETD.Value.ToString("yyyy-MM-dd HH:mm") : "")}"); + } + + //生成From Vessel的table列表 + tableNode.ChildNodes.Add(HtmlNode.CreateNode(tableBuilder.ToString())); + } + + + result = html.DocumentNode.OuterHtml; + + + } + catch (Exception ex) + { + _logger.LogInformation($"生成截止时间变更正文失败,原因:{ex.Message}"); + + throw Oops.Bah($"生成截止时间变更正文失败,原因:{ex.Message}"); + } + + return result; + } + #endregion + + #region 推送邮件 + /// + /// 推送邮件 + /// + /// 自定义邮件详情 + /// 文件路径 + /// 返回回执 + [NonAction] + private async Task PushEmail(EmailApiUserDefinedDto emailApiUserDefinedDto) + { + CommonWebApiResult result = new CommonWebApiResult { succ = true }; + + List emailList = new List(); + + var emailUrl = _cache.GetAllDictData().GetAwaiter().GetResult() + .FirstOrDefault(x => x.TypeCode == "url_set" && x.Code == "email_api_url")?.Value; + + if (emailUrl == null) + throw Oops.Bah("字典未配置 url_set->email_api_url 请联系管理员"); + + + + 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.LogInformation($"发送邮件异常:{ex.Message}"); + } + + DateTime eDate = DateTime.Now; + TimeSpan ts = eDate.Subtract(bDate); + var timeDiff = ts.TotalMilliseconds; + + _logger.LogInformation($"发送邮件返回:{JSON.Serialize(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.succ = respObj.Success; + result.msg = respObj.Message; + } + + return result; + } + #endregion } } diff --git a/Myshipping.Application/Service/TaskManagePlat/TaskManageService.cs b/Myshipping.Application/Service/TaskManagePlat/TaskManageService.cs index 3f2ae775..f3a2ab9f 100644 --- a/Myshipping.Application/Service/TaskManagePlat/TaskManageService.cs +++ b/Myshipping.Application/Service/TaskManagePlat/TaskManageService.cs @@ -1066,7 +1066,7 @@ namespace Myshipping.Application if (info.Main.CutDateChange.Details != null && info.Main.CutDateChange.Details.Count > 0) { - //异步写入集装箱 + //异步写入明细 info.Main.CutDateChange.Details.ForEach(detail => { var cutDetail = detail.Adapt();