using Furion; using Furion.DependencyInjection; 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; using Myshipping.Application.ConfigOption; using Myshipping.Application.Entity; using Myshipping.Application.Enum; using Myshipping.Application.Helper; using Myshipping.Application.Service.BookingSlot.Dto; using Myshipping.Application.Service.TaskManagePlat.Interface; 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 NPOI.SS.Formula.Functions; using Org.BouncyCastle.Asn1.Tsp; using Org.BouncyCastle.Crypto; using SqlSugar; using System; using System.Collections.Generic; using System.Drawing; using System.IO; using System.Linq; using System.Net.Http; using System.Text; using System.Threading.Tasks; namespace Myshipping.Application { /// /// 截止时间变更 /// [ApiDescriptionSettings("Application", Name = "TaskManageCutDateChange", Order = 10)] public class TaskManageCutDateChangeService : ITaskManageCutDateChangeService, IDynamicApiController, ITransient { private readonly SqlSugarRepository _taskCutDateChangeInfoRepository; 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; private readonly INamedServiceProvider _namedBookingOrderServiceProvider; private readonly SqlSugarRepository _bookingSlotBaseRepository; private readonly INamedServiceProvider _namedTaskCautionNoticeServiceProvider; private readonly IDjyTenantParamService _djyTenantParamService; public TaskManageCutDateChangeService(SqlSugarRepository taskCutDateChangeInfoRepository, SqlSugarRepository taskCutDateChangeDetailInfoRepository, SqlSugarRepository bookingOrderContactRepository, SqlSugarRepository taskBaseRepository, SqlSugarRepository sysUserRepository, SqlSugarRepository djyUserMailAccount, SqlSugarRepository repPrintTemplate, ILogger logger, ISysCacheService cache, INamedServiceProvider namedBookingOrderServiceProvider, INamedServiceProvider namedTaskCautionNoticeServiceProvider, SqlSugarRepository bookingSlotBaseRepository, SqlSugarRepository bookingOrderRepository, IDjyTenantParamService djyTenantParamService) { _taskCutDateChangeInfoRepository = taskCutDateChangeInfoRepository; _taskCutDateChangeDetailInfoRepository = taskCutDateChangeDetailInfoRepository; _taskBaseRepository = taskBaseRepository; _bookingOrderRepository = bookingOrderRepository; _bookingOrderContactRepository = bookingOrderContactRepository; _sysUserRepository = sysUserRepository; _djyUserMailAccount = djyUserMailAccount; _repPrintTemplate = repPrintTemplate; _namedBookingOrderServiceProvider = namedBookingOrderServiceProvider; _bookingSlotBaseRepository = bookingSlotBaseRepository; _namedTaskCautionNoticeServiceProvider = namedTaskCautionNoticeServiceProvider; _djyTenantParamService = djyTenantParamService; _logger = logger; _cache = cache; } #region 获取截止时间变更详情 /// /// 获取截止时间变更详情 /// /// 截止时间变更主键 /// 返回回执 [HttpGet("/TaskManageCutDate/GetInfo")] public async Task> GetInfo(string pkId) { List list = new List(); var cutChangeOrder = _taskCutDateChangeInfoRepository.AsQueryable().First(a => a.PK_ID == pkId); if (cutChangeOrder == null) throw Oops.Oh($"截止时间变更主键{pkId}无法获取业务信息"); var detailList = _taskCutDateChangeDetailInfoRepository.AsQueryable() .Where(a => a.P_ID == pkId).ToList(); if (detailList.Count > 0) { list = detailList.OrderBy(p => p.MBL_NO).Select(p => { TaskCutDateChangeShowDto model = p.Adapt(); model.NoticeDate = cutChangeOrder.NOTICE_DATE; model.Carrier = cutChangeOrder.CARRIER; return model; }).ToList(); } return list; } #endregion #region 通过任务主键获取截止时间变更详情 /// /// 通过任务主键获取截止时间变更详情 /// /// 截止时间变更任务主键 /// 返回回执 [HttpGet("/TaskManageCutDate/GetInfoByTaskId")] public async Task> GetInfoByTaskId(string taskPkId) { List list = new List(); var taskBase = _taskBaseRepository.AsQueryable().First(a => a.PK_ID == taskPkId); if (taskBase == null) throw Oops.Oh($"任务主键{taskPkId}无法获取业务信息"); var cutChangeOrder = _taskCutDateChangeInfoRepository.AsQueryable().First(a => a.TASK_ID == taskBase.PK_ID); if (cutChangeOrder == null) throw Oops.Oh($"截止时间变更主键{taskPkId}无法获取业务信息"); var detailList = _taskCutDateChangeDetailInfoRepository.AsQueryable() .Where(a => a.P_ID == cutChangeOrder.PK_ID).ToList(); if (detailList.Count > 0) { list = detailList.OrderBy(p => p.MBL_NO).Select(p => { TaskCutDateChangeShowDto model = p.Adapt(); model.NoticeDate = cutChangeOrder.NOTICE_DATE; model.Carrier = cutChangeOrder.CARRIER; return model; }).ToList(); } return list; } #endregion #region 重新处理截止时间变更任务 /// /// 重新处理截止时间变更任务 /// 对未匹配订舱订单的任务记录,重新对应订单订单 /// /// 截止时间变更任务主键 /// 返回回执 public async Task SearchAndConnectBookingInfo(string taskPkId) { TaskManageOrderResultDto result = new TaskManageOrderResultDto(); var taskBase = _taskBaseRepository.AsQueryable().First(a => a.PK_ID == taskPkId); if (taskBase == null) throw Oops.Oh($"任务主键{taskPkId}无法获取业务信息"); var cutDateChange = _taskCutDateChangeInfoRepository.AsQueryable().First(a => a.TASK_ID == taskBase.PK_ID); if (cutDateChange == null) throw Oops.Oh($"截止时间变更主键{taskPkId}无法获取业务信息"); var detailList = _taskCutDateChangeDetailInfoRepository.AsQueryable() .Where(a => a.P_ID == cutDateChange.PK_ID).ToList(); //如果都有订单订单记录,则提示错误不进行对应 if (!detailList.Any(t => !t.BOOKING_ID.HasValue)) { throw Oops.Oh($"当前截止时间变更已有匹配的订舱订单,不能执行操作"); } var mblList = detailList.Select(a => a.MBL_NO).Distinct().ToList(); var bookingList = _bookingOrderRepository.AsQueryable().Filter(null, true) .Where(a => mblList.Contains(a.MBLNO) && a.IsDeleted == false && (a.ParentId == null || a.ParentId == 0)).ToList(); if (bookingList.Count == 0) throw Oops.Oh($"提单号未提取有效的订舱订单"); List msgList = new List(); detailList.ForEach(async t => { //只处理没有订舱ID的记录 if (!t.BOOKING_ID.HasValue) { var currBook = bookingList.FirstOrDefault(p => p.MBLNO == t.MBL_NO); if (currBook != null) { t.BOOKING_ID = currBook.Id; t.UpdatedUserId = UserManager.UserId; t.UpdatedUserName = UserManager.Name; //更新任务BC await _taskCutDateChangeDetailInfoRepository.AsUpdateable(t).UpdateColumns(it => new { it.BOOKING_ID, it.UpdatedTime, it.UpdatedUserId, it.UpdatedUserName }).ExecuteCommandAsync(); } else { msgList.Add(t.MBL_NO); } } }); if (msgList.Count > 0) throw Oops.Oh($"提单号{(string.Join(",", msgList.ToArray()))}未提取有效的订舱订单"); result.succ = true; result.msg = "成功"; return result; } #endregion #region 推送及时消息 /// /// 推送及时消息 /// /// 截止时间任务主键 /// 返回回执 public async Task SendInstantMessage(string taskPkId) { TaskManageOrderResultDto result = new TaskManageOrderResultDto(); var taskBase = _taskBaseRepository.AsQueryable().First(a => a.PK_ID == taskPkId); if (taskBase == null) throw Oops.Oh($"任务主键{taskPkId}无法获取业务信息"); var cutDateChange = _taskCutDateChangeInfoRepository.AsQueryable().First(a => a.TASK_ID == taskBase.PK_ID); if (cutDateChange == null) throw Oops.Oh($"截止时间变更主键{taskPkId}无法获取业务信息"); var detailList = _taskCutDateChangeDetailInfoRepository.AsQueryable() .Where(a => a.P_ID == cutDateChange.PK_ID).ToList(); //如果都有订单订单记录,则提示错误不进行对应 if (!detailList.Any(t => t.BOOKING_ID.HasValue)) { throw Oops.Oh($"当前截止时间变更没有匹配的订舱订单,不能执行操作"); } var ids = detailList.Where(a => a.BOOKING_ID.HasValue).Select(a => a.BOOKING_ID.Value).ToList(); var bookingList = _bookingOrderRepository.AsQueryable().Filter(null, true) .Where(a => ids.Contains(a.Id) && a.IsDeleted == false && (a.ParentId == null || a.ParentId == 0)).ToList(); if (bookingList.Count == 0) throw Oops.Oh($"提单号未提取有效的订舱订单"); Dictionary> msgList = new Dictionary>(); msgList = bookingList.GroupBy(a => a.OP).Select(a => { var currList = a.ToList(); return new { Key = a.Key, list = currList.Select(a => a.MBLNO).ToList() }; }).ToDictionary(a => a.Key, b => b.list); if (msgList.Count > 0) { msgList.ForEach(t => { DingTalkGroupHelper.SendDingTalkGroupMessage("KangqianNotify", "截止时间变更消息", $"@{t.Key} 收到如下提单号{(string.Join(",", t.Value.ToArray()))}的截止时间变更消息"); }); } if (detailList.Any(t => !t.BOOKING_ID.HasValue)) throw Oops.Oh($"提单号{(string.Join(",", detailList.Where(t => !t.BOOKING_ID.HasValue).Select(t => t.MBL_NO).ToArray()))}未提取有效的订舱订单"); result.succ = true; result.msg = "成功"; return result; } #endregion #region 自动转发截止时间变更通知 /// /// 自动转发截止时间变更通知 /// /// 截止时间变更通知任务主键 /// 返回回执 [HttpGet("/TaskManageCutDate/AutoTransferNotice")] public async Task AutoTransferNotice(string taskPKId) { TaskManageOrderResultDto result = new TaskManageOrderResultDto(); try { var queryRlt = await QueryBookingOrder(taskPKId); _logger.LogInformation($"taskPKId={taskPKId} 检索对应的订舱记录完成,结果:{JSON.Serialize(queryRlt)}"); if (queryRlt.succ) { _logger.LogInformation($"taskPKId={taskPKId} 检索对应的订舱记录成功,触发订舱的截止时间更新"); //更新订舱的截单时间 await UpdateBookingOrderCutDate(taskPKId); } await UpdateBookingSlotCutDate(taskPKId); //如果没有配置批量,则按单票发送邮件 var rlt = await 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} Cut-off Details {model.VESSEL}/{model.VOYNO}/"; if (model.PORTLOAD_AREA.Equals("NORTH_PORT", StringComparison.OrdinalIgnoreCase)) { 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") && x.TenantId == UserManager.TENANT_ID); 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() }; //如果配置了租户参数(AUTO_TRANS_EMAIL_OP_CCTO-自动转发是否默认抄送操作=ENABLE)发送邮件时自动抄送操作 DjyTenantParamValueOutput paramConfig = _djyTenantParamService.GetParaCodeWithValue(new[] { "AUTO_TRANS_EMAIL_OP_CCTO" }).GetAwaiter().GetResult().FirstOrDefault(); if (paramConfig != null && paramConfig.ParaValue.Equals("ENABLE", StringComparison.OrdinalIgnoreCase)) { emailApiUserDefinedDto.CCTo = opEmail; } _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 (model.PORTLOAD_AREA.Equals("SOUTH_PORT", StringComparison.OrdinalIgnoreCase)) { 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())); } } else { var southPNodes = html.DocumentNode.SelectNodes(".//p[@class='south_port']"); foreach(var node in southPNodes) { node.Remove(); } tableNode.RemoveAllChildren(); var colArg = new string[] { "Shipment Number", "Vessel - voyage", "样单截止时间 SI Cut Off", "开港时间 CY Open", "截港时间 CY cut off", "舱单-入港清单截止时间", "MDGF提交截止时间 - 危险品货物", "船代VGM截止时间", "海关放行截止时间(Customs Clearance Deadline)" }; tableNode.ChildNodes.Add(HtmlNode.CreateNode($"{(string.Join("",colArg))}")); StringBuilder tableBuilder = new StringBuilder(); for (int i = 0; i < rowList.Count; i++) { tableBuilder.Append($"{rowList[i].MBL_NO}"); tableBuilder.Append($"{($"{rowList[i].VESSEL}/{rowList[i].VOYNO}")}"); tableBuilder.Append($"{(rowList[i].SI_CUTOFF.HasValue ? rowList[i].SI_CUTOFF.Value.ToString("yyyy-MM-dd HH:mm") : rowList[i].SI_CUTOFF_TXT)}"); tableBuilder.Append($"{(rowList[i].CY_OPEN.HasValue ? rowList[i].CY_OPEN.Value.ToString("yyyy-MM-dd HH:mm") : rowList[i].CY_OPEN_TXT)}"); tableBuilder.Append($"{(rowList[i].CY_CUTOFF.HasValue ? rowList[i].CY_CUTOFF.Value.ToString("yyyy-MM-dd HH:mm") : rowList[i].CY_CUTOFF_TXT)}"); tableBuilder.Append($"{(rowList[i].MANIFEST_CUT.HasValue ? rowList[i].MANIFEST_CUT.Value.ToString("yyyy-MM-dd HH:mm") : rowList[i].MANIFEST_CUT_TXT)}"); tableBuilder.Append($"{(rowList[i].MDGF_CUT.HasValue ? rowList[i].MDGF_CUT.Value.ToString("yyyy-MM-dd HH:mm") : rowList[i].MDGF_CUT_TXT)}"); tableBuilder.Append($"{(rowList[i].VGM_CUT.HasValue ? rowList[i].VGM_CUT.Value.ToString("yyyy-MM-dd HH:mm") : rowList[i].VGM_CUT_TXT)}"); tableBuilder.Append($"{(rowList[i].CLOSING_DATE.HasValue ? rowList[i].CLOSING_DATE.Value.ToString("yyyy-MM-dd HH:mm") : rowList[i].CLOSING_DATE_TXT)}"); tableBuilder.Append(""); } //生成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 #region 更新订舱截止时间 /// /// 更新订舱截止时间 /// /// 截止时间变更任务主键 /// private async Task UpdateBookingOrderCutDate(string taskPKId) { 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}无法获取业务信息"); if (!entityInfo.BOOKING_ID.HasValue) throw Oops.Oh($"截止时间变更主键{taskPKId} mblno={entityInfo.MBL_NO} 没有匹配的订舱记录,更新截止时间失败"); var bookingId = entityInfo.BOOKING_ID.Value; //通过船名航次取是主单的订舱记录列表 var bookingInfo = _bookingOrderRepository.AsQueryable().Filter(null, true).First(a => a.Id == bookingId); var detailInfo = _taskCutDateChangeDetailInfoRepository.AsQueryable().Filter(null, true).First(a => a.P_ID == entityInfo.PK_ID); var oldOrder = bookingInfo.Adapt(); _logger.LogInformation($"更新订舱相关的截单时间 JSON={JSON.Serialize(detailInfo)}"); if (detailInfo.VGM_CUT.HasValue) bookingInfo.CLOSEVGMDATE = detailInfo.VGM_CUT.Value; if (detailInfo.CY_CUTOFF.HasValue) bookingInfo.CLOSINGDATE = detailInfo.CY_CUTOFF.Value; if (detailInfo.SI_CUTOFF.HasValue) bookingInfo.CLOSEDOCDATE = detailInfo.SI_CUTOFF.Value; _bookingOrderRepository.AsUpdateable(bookingInfo).UpdateColumns(it => new { it.CLOSEVGMDATE, it.CLOSINGDATE, it.CLOSEDOCDATE }).ExecuteCommand(); // 保存日志 var bookingOrderService = _namedBookingOrderServiceProvider.GetService(nameof(BookingOrderService)); bookingOrderService.SaveLog(bookingInfo, oldOrder, "截止时间变更"); _logger.LogInformation($"截止时间变更主键{taskPKId} mblno={entityInfo.MBL_NO} 更新订舱完毕"); } catch (Exception ex) { _logger.LogInformation($"taskid={taskPKId} 截止时间变更更新订舱失败"); new EmailNoticeHelper().SendEmailNotice($"taskid={taskPKId} 截止时间变更更新订舱失败", $"taskid={taskPKId} 截止时间变更更新订舱失败,原因:{ex.Message}", App.Configuration["EmailNoticeDefaultUser"].GetUserEmailList()); } } #endregion #region 更新舱位截止时间 /// /// 更新舱位截止时间 /// /// 截止时间变更任务主键 /// private async Task UpdateBookingSlotCutDate(string taskPKId) { 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 detailInfo = _taskCutDateChangeDetailInfoRepository.AsQueryable().Filter(null, true).First(a => a.P_ID == entityInfo.PK_ID); //判断是否有舱位,需要更新舱位 var slotOrder = _bookingSlotBaseRepository.AsQueryable().Filter(null, true) .First(x => entityInfo.MBL_NO.Equals(x.SLOT_BOOKING_NO) && x.IsDeleted == false && x.TenantId == UserManager.TENANT_ID); var oldOrder = slotOrder.Adapt(); _logger.LogInformation($"更新订舱相关的截单时间 JSON={JSON.Serialize(entityInfo)}"); if (detailInfo.VGM_CUT.HasValue) slotOrder.VGM_SUBMISSION_CUT_DATE = detailInfo.VGM_CUT.Value; if (detailInfo.CY_CUTOFF.HasValue) slotOrder.CY_CUT_DATE = detailInfo.CY_CUTOFF; if (detailInfo.SI_CUTOFF.HasValue) slotOrder.SI_CUT_DATE = detailInfo.SI_CUTOFF; if (detailInfo.MDGF_CUT.HasValue) slotOrder.MDGF_CUT_DATE = detailInfo.MDGF_CUT; if (detailInfo.MANIFEST_CUT.HasValue) slotOrder.MANIFEST_CUT_DATE = detailInfo.MANIFEST_CUT; _bookingSlotBaseRepository.AsUpdateable(slotOrder).UpdateColumns(it => new { it.VGM_SUBMISSION_CUT_DATE, it.CY_CUT_DATE, it.SI_CUT_DATE, it.MDGF_CUT_DATE, it.MANIFEST_CUT_DATE }).ExecuteCommand(); await ComparePushCaucation(slotOrder, oldOrder); _logger.LogInformation($"截止时间变更主键{taskPKId} mblno={entityInfo.MBL_NO} 更新舱位完毕"); } catch (Exception ex) { _logger.LogInformation($"taskid={taskPKId} 截止时间变更更新舱位失败"); new EmailNoticeHelper().SendEmailNotice($"taskid={taskPKId} 截止时间变更更新舱位失败", $"taskid={taskPKId} 截止时间变更更新舱位失败,原因:{ex.Message}", App.Configuration["EmailNoticeDefaultUser"].GetUserEmailList()); } } #endregion #region 异步判断是否需要重要提醒,并发送钉钉通知 /// /// 异步判断是否需要重要提醒,并发送钉钉通知 /// /// 新修改舱位详情 /// 修改前舱位详情 /// private async Task ComparePushCaucation(BookingSlotBase slotInfo, BookingSlotBase oldSlotInfo) { try { CautionNoticeTaskWholeShipDto cautionNoticeTaskWholeShipDto = new CautionNoticeTaskWholeShipDto { Carrier = slotInfo.CARRIERID, MBLNo = slotInfo.SLOT_BOOKING_NO }; bool isDiff = false; string srcVesselVoyno = $"{oldSlotInfo.VESSEL}/{oldSlotInfo.VOYNO}"; string targetVesselVoyno = $"{slotInfo.VESSEL}/{slotInfo.VOYNO}"; if (!srcVesselVoyno.Equals(targetVesselVoyno, StringComparison.OrdinalIgnoreCase)) { cautionNoticeTaskWholeShipDto.VesselOldVal = oldSlotInfo.VESSEL; cautionNoticeTaskWholeShipDto.VesselNewVal = slotInfo.VESSEL; cautionNoticeTaskWholeShipDto.VoynoOldVal = oldSlotInfo.VOYNO; cautionNoticeTaskWholeShipDto.VoynoNewVal = slotInfo.VOYNO; cautionNoticeTaskWholeShipDto.IsVesselChange = true; isDiff = true; } else { cautionNoticeTaskWholeShipDto.VesselOldVal = oldSlotInfo.VESSEL; cautionNoticeTaskWholeShipDto.VoynoOldVal = oldSlotInfo.VOYNO; } string srcCarrierType = oldSlotInfo.CARRIAGE_TYPE ?? ""; string targetCarrierType = slotInfo.CARRIAGE_TYPE ?? ""; //如果原来是直航现在变成了中转需要做重要提醒 if (!srcCarrierType.Equals(targetCarrierType, StringComparison.OrdinalIgnoreCase) && srcCarrierType.Equals("DIRECT_SHIP", StringComparison.OrdinalIgnoreCase) && targetCarrierType.Equals("TRANSFER_SHIP", StringComparison.OrdinalIgnoreCase)) { cautionNoticeTaskWholeShipDto.DirectToTransOldVal = "直达"; cautionNoticeTaskWholeShipDto.DirectToTransNewVal = "中转"; cautionNoticeTaskWholeShipDto.IsTransfer = true; isDiff = true; } string srcVGMCut = oldSlotInfo.VGM_SUBMISSION_CUT_DATE.HasValue? oldSlotInfo.VGM_SUBMISSION_CUT_DATE.Value.ToString("yyyy-MM-dd HH:mm:ss"):""; string targeVGMCut = slotInfo.VGM_SUBMISSION_CUT_DATE.HasValue ? slotInfo.VGM_SUBMISSION_CUT_DATE.Value.ToString("yyyy-MM-dd HH:mm:ss") : ""; if (!string.IsNullOrWhiteSpace(srcVGMCut) && !string.IsNullOrWhiteSpace(targeVGMCut) && !srcVGMCut.Equals(targeVGMCut)) { DateTime srcVGMCutDate = DateTime.Parse(srcVGMCut); DateTime targeVGMCutDate = DateTime.Parse(targeVGMCut); if (srcVGMCutDate > targeVGMCutDate) { cautionNoticeTaskWholeShipDto.VGMCutOldVal = srcVGMCutDate.ToString("yyyy-MM-dd HH:mm"); cautionNoticeTaskWholeShipDto.VGMCutNewVal = targeVGMCutDate.ToString("yyyy-MM-dd HH:mm"); cautionNoticeTaskWholeShipDto.IsCutDateAdvanced = true; isDiff = true; } } string srcSICut = oldSlotInfo.SI_CUT_DATE.HasValue ? oldSlotInfo.SI_CUT_DATE.Value.ToString("yyyy-MM-dd HH:mm:ss") : ""; string targeSICut = slotInfo.SI_CUT_DATE.HasValue ? slotInfo.SI_CUT_DATE.Value.ToString("yyyy-MM-dd HH:mm:ss") : ""; if (!string.IsNullOrWhiteSpace(srcSICut) && !string.IsNullOrWhiteSpace(targeSICut) && !srcSICut.Equals(targeSICut)) { DateTime srcSICutDate = DateTime.Parse(srcSICut); DateTime targeSICutDate = DateTime.Parse(targeSICut); //如果新给的SI截止时间,需要推送通知 if (srcSICutDate > targeSICutDate) { cautionNoticeTaskWholeShipDto.SICutOldVal = srcSICutDate.ToString("yyyy-MM-dd HH:mm"); cautionNoticeTaskWholeShipDto.SICutNewVal = targeSICutDate.ToString("yyyy-MM-dd HH:mm"); cautionNoticeTaskWholeShipDto.IsCutDateAdvanced = true; isDiff = true; } } if (isDiff) { //这里增加判断是否截止时间提前,然后推送钉钉消息 var name = _namedTaskCautionNoticeServiceProvider .GetService(nameof(TaskCautionNoticeService)); var wholeShipRlt = await name.GenerateWholeShipCaucation(cautionNoticeTaskWholeShipDto, slotInfo); } } catch(Exception ex) { _logger.LogInformation($"MBLNO={slotInfo.SLOT_BOOKING_NO} 异步判断是否需要重要提醒,并发送钉钉通知异常,原因:{ex.Message}"); new EmailNoticeHelper().SendEmailNotice($"MBLNO={slotInfo.SLOT_BOOKING_NO} 异步判断是否需要重要提醒,并发送钉钉通知异常", $"MBLNO={slotInfo.SLOT_BOOKING_NO} 异步判断是否需要重要提醒,并发送钉钉通知异常,原因:{ex.Message}", App.Configuration["EmailNoticeDefaultUser"].GetUserEmailList()); } } #endregion } }