You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
BookingHeChuan/Myshipping.Application/Service/TaskManagePlat/TaskPOLContainerNotPickUpSe...

633 lines
27 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Myshipping.Application.Entity;
using Myshipping.Core.Entity;
using Myshipping.Core.Service;
using Myshipping.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Furion.FriendlyException;
using NPOI.POIFS.Storage;
using Yitter.IdGenerator;
using Furion.DistributedIDGenerator;
using System.Text.RegularExpressions;
using Furion;
using Myshipping.Application.Helper;
using HtmlAgilityPack;
using Myshipping.Application.ConfigOption;
using Myshipping.Application.Enum;
using System.IO;
using StackExchange.Profiling.Internal;
using Furion.JsonSerialization;
using MySqlX.XDevAPI.Common;
using Furion.RemoteRequest.Extensions;
using Newtonsoft.Json;
using System.Net.Http;
using NPOI.Util;
using System.Numerics;
using SqlSugar;
using System.Reflection.Metadata.Ecma335;
using Microsoft.Extensions.Primitives;
using Myshipping.Core.Helper;
namespace Myshipping.Application
{
/// <summary>
/// 起运港未提箱通知服务
/// </summary>
[ApiDescriptionSettings("Application", Name = "TaskPOLContainerNotPickUp", Order = 10)]
public class TaskPOLContainerNotPickUpService : ITaskPOLContainerNotPickUpService, IDynamicApiController, ITransient
{
private readonly ISysCacheService _cache;
private readonly ILogger<TaskPOLContainerNotPickUpService> _logger;
private readonly SqlSugarRepository<TaskBaseInfo> _taskBaseRepository;
private readonly SqlSugarRepository<TaskPOLContainerNotPickUpInfo> _taskPOLContainerNotPickUpInfoRepository;
private readonly SqlSugarRepository<DjyUserMailAccount> _djyUserMailAccount;
private readonly SqlSugarRepository<BookingOrder> _bookingOrderRepository;
private readonly SqlSugarRepository<BookingOrderContact> _bookingOrderContactRepository;
private readonly SqlSugarRepository<SysUser> _sysUserRepository;
private readonly SqlSugarRepository<BookingPrintTemplate> _repPrintTemplate;
private readonly SqlSugarRepository<TaskFileInfo> _taskFileRepository;
private readonly IDjyTenantParamService _djyTenantParamService;
const string CONST_POL_CONTAINER_NOT_PICKUP_EMAIL = "POL_CONTAINER_NOT_PICKUP_ENAIL";
public TaskPOLContainerNotPickUpService(ISysCacheService cache, ILogger<TaskPOLContainerNotPickUpService> logger,
SqlSugarRepository<TaskBaseInfo> taskBaseRepository,
SqlSugarRepository<TaskPOLContainerNotPickUpInfo> taskPOLContainerNotPickUpInfoRepository,
SqlSugarRepository<DjyUserMailAccount> djyUserMailAccount,
SqlSugarRepository<BookingOrderContact> bookingOrderContactRepository,
SqlSugarRepository<SysUser> sysUserRepository,
SqlSugarRepository<BookingPrintTemplate> repPrintTemplate,
SqlSugarRepository<TaskFileInfo> taskFileRepository,
IDjyTenantParamService djyTenantParamService,
SqlSugarRepository<BookingOrder> bookingOrderRepository)
{
_cache = cache;
_logger = logger;
_taskBaseRepository = taskBaseRepository;
_taskPOLContainerNotPickUpInfoRepository = taskPOLContainerNotPickUpInfoRepository;
_djyUserMailAccount = djyUserMailAccount;
_bookingOrderRepository = bookingOrderRepository;
_bookingOrderContactRepository = bookingOrderContactRepository;
_sysUserRepository = sysUserRepository;
_repPrintTemplate = repPrintTemplate;
_taskFileRepository = taskFileRepository;
_djyTenantParamService = djyTenantParamService;
}
#region 获取起运港未提箱通知详情
/// <summary>
/// 获取起运港未提箱通知详情
/// </summary>
/// <param name="taskPkId">起运港未提箱通知任务主键</param>
/// <returns>返回详情</returns>
[HttpGet("/TaskPOLContainerNotPickUp/GetInfoByTaskId")]
public async Task<TaskPOLContainerNotPickUpShowDto> GetInfoByTaskId(string taskPkId)
{
TaskPOLContainerNotPickUpShowDto dto = new TaskPOLContainerNotPickUpShowDto();
var taskBase = _taskBaseRepository.AsQueryable().Filter(null, true).First(a => a.PK_ID == taskPkId);
if (taskBase == null)
throw Oops.Oh($"任务主键{taskPkId}无法获取业务信息");
var entityInfo = _taskPOLContainerNotPickUpInfoRepository.AsQueryable().Filter(null, true).First(a => a.TASK_ID == taskBase.PK_ID);
if (entityInfo == null)
throw Oops.Oh($"起运港未提箱通知主键{taskPkId}无法获取业务信息");
dto.TaskPkId = entityInfo.TASK_ID;
dto.PKId = entityInfo.PK_ID;
dto.MBlNo = entityInfo.MBL_NO;
dto.BookingCustomer = entityInfo.BOOKING_CUSTOMER;
dto.BookingReference = entityInfo.BOOKING_REFERENCE;
dto.BookingId = entityInfo.BOOKING_ID;
dto.Carrier = entityInfo.CARRIER;
dto.PriceOwnerName = entityInfo.PRICE_OWNER;
return dto;
}
#endregion
#region 自动转发起运港未提箱通知
/// <summary>
/// 自动转发起运港未提箱通知
/// </summary>
/// <param name="taskPKId">起运港未提箱通知任务主键</param>
/// <returns>返回回执</returns>
[HttpGet("/TaskPOLContainerNotPickUp/AutoTransferNotice")]
public async Task<TaskManageOrderResultDto> 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 检索对应的订舱订单
/// <summary>
/// 检索对应的订舱订单
/// </summary>
/// <param name="taskPKId">起运港未提箱通知任务主键</param>
/// <returns>返回回执</returns>
[HttpGet("/TaskPOLContainerNotPickUp/QueryBookingOrder")]
public async Task<TaskManageOrderResultDto> 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 = _taskPOLContainerNotPickUpInfoRepository.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 _taskPOLContainerNotPickUpInfoRepository.AsUpdateable(entityInfo).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 发送邮件通知给客户
/// <summary>
/// 发送邮件通知给客户
/// </summary>
/// <param name="taskPKId">起运港未提箱通知主键</param>
/// <returns>返回回执</returns>
[HttpGet("/TaskPOLContainerNotPickUp/SendEmailToCustomer")]
public async Task<TaskManageOrderResultDto> SendEmailToCustomer(string taskPKId)
{
TaskManageOrderResultDto result = new TaskManageOrderResultDto();
try
{
var entityInfo = _taskPOLContainerNotPickUpInfoRepository.AsQueryable().Filter(null, true).First(a => a.TASK_ID == taskPKId);
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, bookingOrderList, bookingContactList);
var model = _taskPOLContainerNotPickUpInfoRepository.AsQueryable().Filter(null, true).First(a => a.TASK_ID == taskPKId);
if (model != null)
{
model.IS_TRANSFER_USER = true;
model.LST_STATUS = result.succ ? "SUCC" : "FAILURE";
model.LST_STATUS_NAME = result.succ ? "成功" : "失败";
model.LST_TRANSFER_USER_DATE = DateTime.Now;
model.LST_TRANSFER_NOTES = result.msg;
await _taskPOLContainerNotPickUpInfoRepository.AsUpdateable(model).UpdateColumns(x => new
{
x.LST_TRANSFER_NOTES,
x.LST_TRANSFER_USER_DATE,
x.LST_STATUS,
x.LST_STATUS_NAME,
x.IS_TRANSFER_USER
}).ExecuteCommandAsync();
}
}
catch (Exception ex)
{
result.succ = false;
result.msg = $"发送邮件失败,原因:{ex.Message}";
}
return result;
}
#endregion
#region 生成并转发通知邮件
/// <summary>
/// 生成并转发通知邮件
/// </summary>
/// <param name="model"></param>
/// <param name="bookingOrderList"></param>
/// <param name="bookingContactList"></param>
/// <param name="taskBaskInfo"></param>
/// <returns></returns>
[NonAction]
private async Task<TaskManageOrderResultDto> GenerateSendEmail(TaskPOLContainerNotPickUpInfo model, List<BookingOrder> bookingOrderList, List<BookingOrderContact> 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<string> opEmailList = new List<string>();
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("pol_container_not_pickup") && x.TenantId == UserManager.TENANT_ID);
if (printTemplate == null)
{
throw Oops.Bah(BookingErrorCode.BOOK115);
}
//读取邮件模板并填充数据
string emailHtml = GenerateSendEmailHtml(model, 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<AttachesInfo>()
};
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
/// <summary>
/// 通过邮件模板生成HTML
/// </summary>
/// <param name="model"></param>
/// <param name="bookingOrderList"></param>
/// <param name="filePath"></param>
/// <param name="opUserInfo"></param>
/// <param name="tenantName"></param>
/// <returns></returns>
[NonAction]
private async Task<string> GenerateSendEmailHtml(TaskPOLContainerNotPickUpInfo model, List<BookingOrder> bookingOrderList, string filePath, SysUser opUserInfo, string tenantName)
{
string result = string.Empty;
string baseHtml = string.Empty;
try
{
var opt = App.GetOptions<PrintTemplateOptions>();
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#", "");
}
if (!string.IsNullOrWhiteSpace(tenantName))
{
baseHtml = baseHtml.Replace("#TenantCompanyName#", tenantName);
}
else
{
baseHtml = baseHtml.Replace("#TenantCompanyName#", "");
}
HtmlDocument html = new HtmlDocument();
html.LoadHtml(baseHtml);
result = html.DocumentNode.OuterHtml;
}
catch (Exception ex)
{
_logger.LogInformation($"生成起运港未提箱正文失败,原因:{ex.Message}");
throw Oops.Bah($"生成起运港未提箱正文失败,原因:{ex.Message}");
}
return result;
}
#endregion
#region 推送邮件
/// <summary>
/// 推送邮件
/// </summary>
/// <param name="emailApiUserDefinedDto">自定义邮件详情</param>
/// <param name="filePath">文件路径</param>
/// <returns>返回回执</returns>
[NonAction]
private async Task<CommonWebApiResult> PushEmail(EmailApiUserDefinedDto emailApiUserDefinedDto)
{
CommonWebApiResult result = new CommonWebApiResult { succ = true };
List<EmailApiUserDefinedDto> emailList = new List<EmailApiUserDefinedDto>();
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
}
}