邮件发送拆分为独立单元

usertest
嵇文龙 4 months ago
parent d8c604c989
commit 915e9830d8

@ -10,36 +10,41 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction.ActionExecutor
{ {
internal const TaskBaseTypeEnum Booking_TaskType = TaskBaseTypeEnum.WAIT_BOOKING; internal const TaskBaseTypeEnum Booking_TaskType = TaskBaseTypeEnum.WAIT_BOOKING;
protected ISeaExportTaskService taskService; /// <summary>
protected ITaskLogService logService; /// 任务服务
/// </summary>
protected ISeaExportTaskService TaskService;
/// <summary>
/// 日志服务
/// </summary>
protected ITaskLogService LogService;
public override Task ExecuteAsync(ActionExecutionContext context) public override Task ExecuteAsync(ActionExecutionContext context)
{ {
taskService = context.ServiceProvider.GetRequiredService<ISeaExportTaskService>(); TaskService = context.ServiceProvider.GetRequiredService<ISeaExportTaskService>();
logService = context.ServiceProvider.GetRequiredService<ITaskLogService>(); LogService = context.ServiceProvider.GetRequiredService<ITaskLogService>();
return Task.CompletedTask; return Task.CompletedTask;
} }
protected async Task<DataResult> CreateTask(ActionExecutionContext context) protected async Task<DataResult> CreateTask(ActionExecutionContext context)
{ {
var result1 = await taskService.Exists(context.TaskInfo.BusinessId, context.TaskInfo.BusinessType, Booking_TaskType); var result = await TaskService.Exists(context.TaskInfo.BusinessId, context.TaskInfo.BusinessType, Booking_TaskType);
if (!result1.Data) //任务已存在,跳过创建步骤
{ if (result.Data)
return await taskService.CreateTaskAsync(new TaskCreationRequest return DataResult.Success;
{
BusinessId = context.TaskInfo.BusinessId,
BusinessType = context.TaskInfo.BusinessType,
TaskTypeName = Booking_TaskType.ToString()
});
}
return DataResult.Success; return await TaskService.CreateTaskAsync(new TaskCreationRequest
{
BusinessId = context.TaskInfo.BusinessId,
BusinessType = context.TaskInfo.BusinessType,
TaskTypeName = Booking_TaskType.ToString()
});
} }
protected async Task CompleteTask(ActionExecutionContext context) protected async Task SetTaskComplete(ActionExecutionContext context)
{ {
var result = await taskService.SetTaskStatusAsync(new TaskUpdateRequest var result = await TaskService.SetTaskStatusAsync(new TaskUpdateRequest
{ {
BusinessId = context.TaskInfo.BusinessId, BusinessId = context.TaskInfo.BusinessId,
BusinessType = context.TaskInfo.BusinessType, BusinessType = context.TaskInfo.BusinessType,
@ -48,7 +53,7 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction.ActionExecutor
AutoCreateNext = true AutoCreateNext = true
}); });
if (!result.Succeeded) if (!result.Succeeded)
await logService.WriteLogAsync(context.TaskInfo, $"未能设置任务【{Booking_TaskType.GetDescription()}】完成,返回结果:{result.Message}"); await LogService.WriteLogAsync(context.TaskInfo, $"未能设置任务【{Booking_TaskType.GetDescription()}】完成,返回结果:{result.Message}");
} }
} }
} }

@ -19,7 +19,7 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction.ActionExecutor
var result = await CreateTask(context); var result = await CreateTask(context);
if (!result.Succeeded) if (!result.Succeeded)
{ {
await logService.WriteLogAsync(context.TaskInfo, $"创建任务【{Booking_TaskType.GetDescription()}】失败,返回结果:{result.Message}"); await LogService.WriteLogAsync(context.TaskInfo, $"创建任务【{Booking_TaskType.GetDescription()}】失败,返回结果:{result.Message}");
return; return;
} }
@ -38,11 +38,11 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction.ActionExecutor
//订舱未成功 //订舱未成功
if (!result2.Succeeded) if (!result2.Succeeded)
{ {
await logService.WriteLogAsync(context.TaskInfo, "EDI返回结果失败自动订舱未成功"); await LogService.WriteLogAsync(context.TaskInfo, "EDI返回结果失败自动订舱未成功");
return; return;
} }
await CompleteTask(context); await SetTaskComplete(context);
} }
} }
} }

@ -1,21 +1,9 @@
using DS.Module.PrintModule; using DS.WMS.Core.Op.Dtos.TaskInteraction;
using DS.Module.SqlSugar;
using DS.Module.UserModule;
using DS.WMS.Core.Code.Entity;
using DS.WMS.Core.Info.Entity;
using DS.WMS.Core.Op.Dtos.TaskInteraction;
using DS.WMS.Core.Op.Entity.TaskInteraction; using DS.WMS.Core.Op.Entity.TaskInteraction;
using DS.WMS.Core.Op.Interface;
using DS.WMS.Core.Op.Interface.TaskInteraction; using DS.WMS.Core.Op.Interface.TaskInteraction;
using DS.WMS.Core.Sys.Entity;
using HtmlAgilityPack;
using Mapster;
using Masuit.Tools; using Masuit.Tools;
using Masuit.Tools.Systems; using Masuit.Tools.Systems;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using RazorEngineCore;
using SqlSugar; using SqlSugar;
namespace DS.WMS.Core.Op.Method.TaskInteraction.ActionExecutor namespace DS.WMS.Core.Op.Method.TaskInteraction.ActionExecutor
@ -32,210 +20,52 @@ namespace DS.WMS.Core.Op.Method.TaskInteraction.ActionExecutor
/// <returns></returns> /// <returns></returns>
public async override Task ExecuteAsync(ActionExecutionContext context) public async override Task ExecuteAsync(ActionExecutionContext context)
{ {
var db = context.ServiceProvider.GetRequiredService<ISqlSugarClient>(); await base.ExecuteAsync(context);
var saasService = context.ServiceProvider.GetRequiredService<ISaasDbService>(); var result = await CreateTask(context);
var user = context.ServiceProvider.GetRequiredService<IUser>(); if (!result.Succeeded)
var tenantDb = saasService.GetBizDbScopeById(user.TenantId); {
await LogService.WriteLogAsync(context.TaskInfo, $"创建任务【{Booking_TaskType.GetDescription()}】失败,返回结果:{result.Message}");
var service = context.ServiceProvider.GetRequiredService<ITaskMailService>(); return;
var logService = context.ServiceProvider.GetRequiredService<ITaskLogService>(); }
var seService = context.ServiceProvider.GetRequiredService<ISeaExportService>();
var config = context.ServiceProvider.GetRequiredService<IConfiguration>();
var taskMailService = context.ServiceProvider.GetRequiredService<ITaskMailService>();
MailService mailService = new(context.ServiceProvider);
BusinessTaskMail? mailConfig = null; BusinessTaskMail? mailConfig = null;
if (context.AdditionalData.TryGetValue(nameof(BusinessTaskMail.Id), out var id)) if (context.AdditionalData.TryGetValue(nameof(BusinessTaskMail.Id), out var id))
{ {
if (id == null) if (id == null)
{ {
await logService.WriteLogAsync(context.TaskInfo, $"未配置【{context.TaskInfo.TaskType.GetDescription()}】任务的邮件设置"); await LogService.WriteLogAsync(context.TaskInfo, $"未配置【{context.TaskInfo.TaskType.GetDescription()}】任务的邮件设置");
return; return;
} }
var idVal = (long)Convert.ChangeType(id, typeof(long)); var idVal = (long)Convert.ChangeType(id, typeof(long));
mailConfig = (await service.GetAsync(idVal)).Data; mailConfig = (await taskMailService.GetAsync(idVal)).Data;
} }
else if (context.AdditionalData.TryGetValue(nameof(BusinessTaskMail.Name), out var name)) else if (context.AdditionalData.TryGetValue(nameof(BusinessTaskMail.Name), out var name))
{ {
var mailName = name as string; var mailName = name as string;
if (mailName.IsNullOrEmpty()) if (mailName.IsNullOrEmpty())
{ {
await logService.WriteLogAsync(context.TaskInfo, $"未配置【{context.TaskInfo.TaskType.GetDescription()}】任务的邮件设置"); await LogService.WriteLogAsync(context.TaskInfo, $"未配置【{context.TaskInfo.TaskType.GetDescription()}】任务的邮件设置");
return; return;
} }
mailConfig = await service.GetAsync(mailName); mailConfig = await taskMailService.GetAsync(mailName);
} }
if (mailConfig == null) if (mailConfig == null)
{ {
await logService.WriteLogAsync(context.TaskInfo, $"未能根据任务配置值获取邮件模板设置"); await LogService.WriteLogAsync(context.TaskInfo, $"未能根据任务配置值获取邮件模板设置");
return; return;
} }
var result = seService.GetSeaExportInfo(context.TaskInfo.BusinessId.ToString()); result = await mailService.SendAsync(mailConfig, context.TaskInfo.BusinessId, context.TaskInfo.BusinessType);
if (!result.Succeeded || result.Data == null) if (!result.Succeeded)
{ {
await logService.WriteLogAsync(context.TaskInfo, $"未能获取Id={context.TaskInfo.BusinessId}的{context.TaskInfo.BusinessType.GetDescription()}数据"); await LogService.WriteLogAsync(context.TaskInfo, result.Message);
return; return;
} }
string title, content = string.Empty; await SetTaskComplete(context);
var templateModel = new MailTemplateModel<SeaExportOrder> { Primary = result.Data.Adapt<SeaExportOrder>() };
IRazorEngine razorEngine = new RazorEngine();
try
{
var titleTemplate = razorEngine.Compile<RazorEngineTemplateBase<MailTemplateModel<SeaExportOrder>>>(mailConfig.Title);
title = await titleTemplate.RunAsync(x =>
{
x.Model = templateModel;
});
var contentTemplate = razorEngine.Compile<RazorEngineTemplateBase<MailTemplateModel<SeaExportOrder>>>(mailConfig.Content);
content = await contentTemplate.RunAsync(x =>
{
x.Model = templateModel;
});
}
catch (Exception ex)
{
await ex.LogAsync(db);
await logService.WriteLogAsync(context.TaskInfo, $"渲染邮件模板({mailConfig.Id})时出错,请检查模板是否有语法错误");
return;
}
//设置发件人
long senderId = 0;
if (mailConfig.Sender.IsSale)
senderId = templateModel.Primary.SaleId;
else if (mailConfig.Sender.IsOperator)
senderId = templateModel.Primary.OperatorId;
else if (mailConfig.Sender.IsCustomerService)
senderId = templateModel.Primary.CustomerService;
else if (mailConfig.Sender.IsVouchingClerk)
senderId = templateModel.Primary.Doc;
var sender = await db.Queryable<SysUser>().Where(x => x.Id == senderId).Select(
x => new { x.UserName, x.SignatureHtml }).FirstAsync();
if (sender == null)
{
await logService.WriteLogAsync(context.TaskInfo, "未设置发件人");
return;
}
var senderConfig = await tenantDb.Queryable<CodeUserEmail>().FirstAsync(x => x.CreateBy == senderId);
if (senderConfig == null)
{
await logService.WriteLogAsync(context.TaskInfo, $"发件人用户:{sender.UserName} 未设置SMTP发件信息");
return;
}
//插入发件人签名
var htmlDoc = new HtmlDocument();
htmlDoc.LoadHtml(content);
var node = htmlDoc.GetElementbyId("sign");
if (node != null)
node.InnerHtml = sender.SignatureHtml;
StringWriter writer = new();
htmlDoc.Save(writer);
content = writer.ToString();
writer.Close();
//设置收件人
List<long> receiverIds = [];
if (mailConfig.Receiver.IsCarrier)
receiverIds.Add(templateModel.Primary.CarrierId);
if (mailConfig.Receiver.IsBooking)
receiverIds.Add(templateModel.Primary.ForwarderId);
if (mailConfig.Receiver.IsYard)
receiverIds.Add(templateModel.Primary.YardId);
if (mailConfig.Receiver.IsTruck)
receiverIds.Add(templateModel.Primary.TruckerId);
if (mailConfig.Receiver.IsController)
receiverIds.Add(templateModel.Primary.CustomerId);
var receiverList = await tenantDb.Queryable<InfoClient>().Where(x => receiverIds.Contains(x.Id) && x.Email != null && x.Email != string.Empty)
.Select(x => new { x.ShortName, x.EnShortName, x.Email }).ToListAsync();
var attachmentList = mailConfig.Attachments == null ? [] : new List<Tuple<string, string>>(mailConfig.Attachments.Count);
try
{
//需要上传附件
if (mailConfig.Attachments?.Count > 0)
{
if (Api.DefaultHeaders.Contains("Authorization"))
Api.DefaultHeaders.Remove("Authorization");
Api.DefaultHeaders.Add("Authorization", "Bearer " + user.GetToken());
long tenantId = long.Parse(user.TenantId);
string requestUrl = config["TaskMail:FileBaseUrl"] + config["TaskMail:SQLPrint"];
foreach (var item in mailConfig.Attachments)
{
var req = new OpenPrintReq
{
ParamJsonStr = JsonConvert.SerializeObject(new { Id = context.TaskInfo.BusinessId }),
PrintType = ((int)FileFormat.PDF).ToString(),
TemplateId = item.TemplateId,
TenantId = tenantId
};
var reqResult = await Api.PostAsync<PrintResult>(requestUrl, req);
if (!reqResult.Succeeded)
{
await logService.WriteLogAsync(context.TaskInfo, $"未能获取打印API生成的文件请求地址{requestUrl}");
return;
}
string url = config["TaskMail:FileBaseUrl"] + @"/PrintTempFile/" + reqResult.Data.Data;
var fileResult = await Api.SendRequestAsync(HttpMethod.Get, url);
if (!fileResult.Succeeded)
{
await logService.WriteLogAsync(context.TaskInfo, $"未能获取打印API生成的文件附件地址{url}");
return;
}
string fileName = item.FileName.IsNullOrEmpty() ? Path.GetFileName(reqResult.Data.Data) : item.FileName;
var bytes = await fileResult.Data.Content.ReadAsByteArrayAsync();
string base64Str = Convert.ToBase64String(bytes);
attachmentList.Add(new Tuple<string, string>(fileName, base64Str));
}
}
dynamic[] mailParams = [new
{
SendTo = string.Join(",", receiverList.Select(x => x.Email)),
Title = title,
Body = content,
ShowName = senderConfig.ShowName.IsNullOrEmpty() ? sender.UserName : senderConfig.ShowName,
Account = senderConfig.MailAccount,
senderConfig.Password,
Server = senderConfig.SmtpServer,
Port = senderConfig.SmtpPort.GetValueOrDefault(),
UseSSL = senderConfig.SmtpSSL.GetValueOrDefault(),
Attaches = attachmentList.Select(x => new
{
AttachName = x.Item1,
AttachContent = x.Item2
}).ToList()
}];
var mailResult = await Api.SendRequestAsync(HttpMethod.Post, config["TaskMail:MailApiUrl"], mailParams);
if (mailResult.Data.IsSuccessStatusCode)
{
await logService.WriteLogAsync(context.TaskInfo, $"已发邮件(委托单:{templateModel.Primary.CustomerNo}),收件人:"
+ string.Join(",", receiverList.Select(x => x.Email)) + "发件人:" + senderConfig.MailAccount);
}
else
{
await logService.WriteLogAsync(context.TaskInfo, $"邮件发送失败(委托单:{templateModel.Primary.CustomerNo}),收件人:"
+ string.Join(",", receiverList.Select(x => x.Email)) + "发件人:" + senderConfig.MailAccount);
}
}
catch (Exception ex)
{
await ex.LogAsync(db);
}
} }
} }

@ -0,0 +1,208 @@
using DS.Module.PrintModule;
using DS.WMS.Core.Code.Entity;
using DS.WMS.Core.Info.Entity;
using DS.WMS.Core.Op.Dtos.TaskInteraction;
using DS.WMS.Core.Op.Entity.TaskInteraction;
using DS.WMS.Core.Op.Interface.TaskInteraction;
using DS.WMS.Core.Op.Interface;
using DS.WMS.Core.Op.Method.TaskInteraction.ActionExecutor;
using DS.WMS.Core.Sys.Entity;
using HtmlAgilityPack;
using Newtonsoft.Json;
using RazorEngineCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Mapster;
using DS.Module.Core;
using Masuit.Tools;
using Masuit.Tools.Systems;
using DS.WMS.Core.Op.Entity;
namespace DS.WMS.Core.Op.Method.TaskInteraction
{
/// <summary>
/// 业务邮件发送服务
/// </summary>
public class MailService : ServiceBase
{
ITaskMailService service;
ISeaExportService seService;
IConfiguration config;
ApiFox Api = DefaultActionExecutor.Api;
/// <summary>
/// 初始化
/// </summary>
/// <param name="provider"></param>
public MailService(IServiceProvider provider) : base(provider)
{
service = provider.GetRequiredService<ITaskMailService>();
seService = provider.GetRequiredService<ISeaExportService>();
config = provider.GetRequiredService<IConfiguration>();
}
/// <summary>
/// 发送业务邮件
/// </summary>
/// <param name="mailConfig">邮件配置</param>
/// <param name="businessId">业务ID</param>
/// <param name="businessType">业务类型</param>
/// <returns></returns>
public async Task<DataResult> SendAsync(BusinessTaskMail mailConfig,
long businessId, BusinessType businessType = BusinessType.OceanShippingExport)
{
ArgumentNullException.ThrowIfNull(mailConfig, nameof(mailConfig));
var result = seService.GetSeaExportInfo(businessId.ToString());
if (!result.Succeeded || result.Data == null)
return DataResult.Failed($"未能获取Id={businessId}的{businessType.GetDescription()}数据");
string title, content = string.Empty;
var templateModel = new MailTemplateModel<SeaExportOrder> { Primary = result.Data.Adapt<SeaExportOrder>() };
IRazorEngine razorEngine = new RazorEngine();
try
{
var titleTemplate = razorEngine.Compile<RazorEngineTemplateBase<MailTemplateModel<SeaExportOrder>>>(mailConfig.Title);
title = await titleTemplate.RunAsync(x =>
{
x.Model = templateModel;
});
var contentTemplate = razorEngine.Compile<RazorEngineTemplateBase<MailTemplateModel<SeaExportOrder>>>(mailConfig.Content);
content = await contentTemplate.RunAsync(x =>
{
x.Model = templateModel;
});
}
catch (Exception ex)
{
await ex.LogAsync(Db);
return DataResult.Failed($"渲染邮件模板({mailConfig.Id})时出错,请检查模板是否有语法错误");
}
//设置发件人
long senderId = 0;
if (mailConfig.Sender.IsSale)
senderId = templateModel.Primary.SaleId;
else if (mailConfig.Sender.IsOperator)
senderId = templateModel.Primary.OperatorId;
else if (mailConfig.Sender.IsCustomerService)
senderId = templateModel.Primary.CustomerService;
else if (mailConfig.Sender.IsVouchingClerk)
senderId = templateModel.Primary.Doc;
var sender = await Db.Queryable<SysUser>().Where(x => x.Id == senderId).Select(x => new { x.UserName, x.SignatureHtml }).FirstAsync();
if (sender == null)
return DataResult.Failed("未设置发件人");
var senderConfig = await TenantDb.Queryable<CodeUserEmail>().FirstAsync(x => x.CreateBy == senderId);
if (senderConfig == null)
return DataResult.Failed($"发件人用户:{sender.UserName} 未设置SMTP发件信息");
//插入发件人签名
var htmlDoc = new HtmlDocument();
htmlDoc.LoadHtml(content);
var node = htmlDoc.GetElementbyId("sign");
if (node != null)
node.InnerHtml = sender.SignatureHtml;
StringWriter writer = new();
htmlDoc.Save(writer);
content = writer.ToString();
writer.Close();
//设置收件人
List<long> receiverIds = [];
if (mailConfig.Receiver.IsCarrier)
receiverIds.Add(templateModel.Primary.CarrierId);
if (mailConfig.Receiver.IsBooking)
receiverIds.Add(templateModel.Primary.ForwarderId);
if (mailConfig.Receiver.IsYard)
receiverIds.Add(templateModel.Primary.YardId);
if (mailConfig.Receiver.IsTruck)
receiverIds.Add(templateModel.Primary.TruckerId);
if (mailConfig.Receiver.IsController)
receiverIds.Add(templateModel.Primary.CustomerId);
var receiverList = await TenantDb.Queryable<InfoClient>().Where(x => receiverIds.Contains(x.Id) && x.Email != null && x.Email != string.Empty)
.Select(x => new { x.ShortName, x.EnShortName, x.Email }).ToListAsync();
var attachmentList = mailConfig.Attachments == null ? [] : new List<Tuple<string, string>>(mailConfig.Attachments.Count);
try
{
//需要上传附件
if (mailConfig.Attachments?.Count > 0)
{
if (Api.DefaultHeaders.Contains("Authorization"))
Api.DefaultHeaders.Remove("Authorization");
Api.DefaultHeaders.Add("Authorization", "Bearer " + User.GetToken());
long tenantId = long.Parse(User.TenantId);
string requestUrl = config["TaskMail:FileBaseUrl"] + config["TaskMail:SQLPrint"];
foreach (var item in mailConfig.Attachments)
{
var req = new OpenPrintReq
{
ParamJsonStr = JsonConvert.SerializeObject(new { Id = businessId }),
PrintType = ((int)FileFormat.PDF).ToString(),
TemplateId = item.TemplateId,
TenantId = tenantId
};
var reqResult = await Api.PostAsync<PrintResult>(requestUrl, req);
if (!reqResult.Succeeded)
return DataResult.Failed($"未能获取打印API生成的文件请求地址{requestUrl}");
string url = config["TaskMail:FileBaseUrl"] + @"/PrintTempFile/" + reqResult.Data.Data;
var fileResult = await Api.SendRequestAsync(HttpMethod.Get, url);
if (!fileResult.Succeeded)
return DataResult.Failed($"未能获取打印API生成的文件附件地址{url}");
string fileName = item.FileName.IsNullOrEmpty() ? Path.GetFileName(reqResult.Data.Data) : item.FileName;
var bytes = await fileResult.Data.Content.ReadAsByteArrayAsync();
string base64Str = Convert.ToBase64String(bytes);
attachmentList.Add(new Tuple<string, string>(fileName, base64Str));
}
}
dynamic[] mailParams = [new
{
SendTo = string.Join(",", receiverList.Select(x => x.Email)),
Title = title,
Body = content,
ShowName = senderConfig.ShowName.IsNullOrEmpty() ? sender.UserName : senderConfig.ShowName,
Account = senderConfig.MailAccount,
senderConfig.Password,
Server = senderConfig.SmtpServer,
Port = senderConfig.SmtpPort.GetValueOrDefault(),
UseSSL = senderConfig.SmtpSSL.GetValueOrDefault(),
Attaches = attachmentList.Select(x => new
{
AttachName = x.Item1,
AttachContent = x.Item2
}).ToList()
}];
var mailResult = await Api.SendRequestAsync(HttpMethod.Post, config["TaskMail:MailApiUrl"], mailParams);
if (mailResult.Data.IsSuccessStatusCode)
{
return DataResult.Successed($"已发邮件(委托单:{templateModel.Primary.CustomerNo}),收件人:"
+ string.Join(",", receiverList.Select(x => x.Email)) + "发件人:" + senderConfig.MailAccount);
}
return DataResult.Failed($"邮件发送失败API返回状态为{(int)mailResult.Data.StatusCode} {mailResult.Data.StatusCode}"
+"(委托单:{templateModel.Primary.CustomerNo}),收件人:"
+ string.Join(",", receiverList.Select(x => x.Email))
+ "发件人:" + senderConfig.MailAccount);
}
catch (Exception ex)
{
await ex.LogAsync(Db);
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.HttpRequestFailed));
}
}
}
}
Loading…
Cancel
Save