using Amazon.Runtime.Internal.Util;
using DS.Module.Core;
using DS.Module.Core.Constants;
using DS.Module.Core.Data;
using DS.Module.Core.Helpers;
using DS.Module.DjyServiceStatus;
using DS.Module.SqlSugar;
using DS.Module.UserModule;
using DS.WMS.Core.Code.Dtos;
using DS.WMS.Core.Code.Interface;
using DS.WMS.Core.Info.Dtos;
using DS.WMS.Core.Info.Interface;
using DS.WMS.Core.Map.Dtos;
using DS.WMS.Core.Map.Interface;
using DS.WMS.Core.Op.Dtos;
using DS.WMS.Core.Op.EDI;
using DS.WMS.Core.Op.Entity;
using DS.WMS.Core.Op.Interface;
using DS.WMS.Core.Sys.Entity;
using DS.WMS.Core.Sys.Interface;
using DS.WMS.Core.TaskPlat.Dtos;
using DS.WMS.Core.TaskPlat.Dtos.BC;
using DS.WMS.Core.TaskPlat.Entity;
using DS.WMS.Core.TaskPlat.Interface;
using HtmlAgilityPack;
using Mapster;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using NLog;
using SqlSugar;
using System.Web;
using System.Net.Http.Headers;
using System.Text.RegularExpressions;
using System.Text;
using System.ComponentModel.DataAnnotations;
namespace DS.WMS.Core.TaskPlat.Method
{
///
/// 任务台-BC子任务
///
public class TaskManageBCService : TaskManageBaseService, ITaskManageBCService
{
// 实例化时构建
private readonly IConfigService configService;
private readonly IClientInfoService clientInfoService;
private readonly IMappingCarrierService mappingCarrierService;
private readonly IOpFileService opFileService;
private readonly ICodeCtnService codeCtnService;
private readonly IUserService _userService;
private readonly IUserEmailService _userEmailService;
private readonly IWebHostEnvironment _environment;
private readonly ISqlSugarClient db;
private readonly string bcCompareUrl;
private readonly string bcMSKReadUrl;
private readonly string bcMSKModifyFileUrl;
private readonly string bcCMAReadUrl;
// 按需构建
private Lazy bookingSlotService;
private Lazy seaExportService;
private Lazy djyServiceStatusService;
private static readonly NLog.Logger Logger = LogManager.GetCurrentClassLogger();
private readonly SqlSugarScopeProvider tenantDb;
//租户AMENDMENT默认转发KEY
const string CONST_AMENDMENT_DEFAULT_PARAM = "AMENDMENT_TASK_AUTO_TRANSMIT";
//自动转发是否默认抄送操作
const string CONST_AUTO_TRANS_EMAIL_OP_CCTO = "AUTO_TRANS_EMAIL_OP_CCTO";
public TaskManageBCService(IUser user,
ILogger logger,
ISaasDbService saasDbService,
IServiceProvider serviceProvider,
IWebHostEnvironment environment,
IConfigService configService,
IClientInfoService clientInfoService,
IMappingCarrierService mappingCarrierService,
IOpFileService opFileService,
ICodeCtnService codeCtnService,
IUserService userService,
IUserEmailService userEmailService)
: base(user, logger, saasDbService, serviceProvider, environment)
{
this.configService = configService;
this.clientInfoService = clientInfoService;
this.mappingCarrierService = mappingCarrierService;
this.opFileService = opFileService;
this.codeCtnService = codeCtnService;
_userService = userService;
_userEmailService = userEmailService;
_environment = environment;
db = serviceProvider.GetRequiredService();
bookingSlotService = new Lazy(serviceProvider.GetRequiredService);
seaExportService = new Lazy(serviceProvider.GetRequiredService);
djyServiceStatusService = new Lazy(serviceProvider.GetRequiredService);
tenantDb = saasDbService.GetBizDbScopeById(user.TenantId);
tenantDb.QueryFilter.Clear();
bcCompareUrl = AppSetting.app(new string[] { "BCCompare", "Url" });
bcMSKReadUrl = AppSetting.app(new string[] { "BCCompare", "MSKBCReadUrl" });
bcMSKModifyFileUrl = AppSetting.app(new string[] { "BCCompare", "MSKBCModifyFileUrl" });
bcCMAReadUrl = AppSetting.app(new string[] { "BCCompare", "CMABCReadUrl" });
}
///
/// 通过任务信息(BC)生成订舱或舱位
///
/// 生成订舱或者舱位请求
/// 返回回执
public async Task> CreateBookingAndSlot(BookingOrSlotGenerateDto model)
{
TaskManageOrderResultDto result = new TaskManageOrderResultDto();
logger.LogInformation($"接收生成订舱或舱位请求,参数{JsonConvert.SerializeObject(model)}");
try
{
/*
1、GEN_BOOKING_SLOT-生成舱位和订舱
(1)生成舱位
(2)生成海运订舱
(3)更新舱位库存
(4)更新BC任务
2、GEN_BOOKING-只生成订舱
(1)生成海运订舱
(4)更新BC任务
3、GEN_SLOT-只生成舱位
(1)生成舱位
(4)更新BC任务
3、GEN_SLOT-只生成舱位
(1)查找订舱记录
(3)更新舱位库存
(4)更新BC任务
*/
if (model.BCTaskId == 0)
throw new Exception($"BC任务主键不能为空");
//生成方式(GEN_BOOKING_SLOT-生成舱位和订舱;GEN_BOOKING-只生成订舱;GEN_SLOT-只生成舱位;GEN_EXIST_BOOKING-匹配指定的订舱)
if (string.IsNullOrWhiteSpace(model.GenerateMethod))
throw new Exception($"生成方式不能为空,需要指定一种生成方式");
var tenantDb = saasDbService.GetBizDbScopeById(user.TenantId);
//任务不考虑OrgId,这里去掉
tenantDb.QueryFilter.Clear();
var bcTaskInfo = await tenantDb.Queryable().Where(u => u.Id == model.BCTaskId).FirstAsync();
if (bcTaskInfo == null)
{
throw new Exception($"任务主键{model.BCTaskId}无法获取业务信息");
}
var bcOrder = await tenantDb.Queryable().Where(a => a.TASK_ID == bcTaskInfo.Id).FirstAsync();
if (bcOrder == null)
throw new Exception($"任务主键{model.BCTaskId}无法获取BC业务信息");
var bcCtnList = await tenantDb.Queryable().Where(a => a.P_ID == bcOrder.Id).ToListAsync();
var fileList = await tenantDb.Queryable().Where(a => a.TASK_PKID == bcTaskInfo.Id).ToListAsync();
if (model.GenerateMethod != "UPD_BOOKING")
{
if (bcOrder.BOOKING_ORDER_ID.HasValue && bcOrder.BOOKING_ORDER_ID.Value > 0)
{
throw new Exception($"当前BC任务已生成订舱订单,不能重复生成");
}
}
if (model.GenerateMethod == "GEN_BOOKING_SLOT")
{
#region 推送舱位、推送订舱
//推送舱位
//long bookingSlotId = 0;
BookingSlotBase? bookingSlot = null;
if (bcOrder.BOOKING_SLOT_ID.HasValue && bcOrder.BOOKING_SLOT_ID.Value > 0)
{
//bookingSlotId = bcOrder.BOOKING_SLOT_ID.Value;
throw new Exception($"生成舱位失败,舱位已存在");
}
//这里增加委托单位联系人的校验,重新从后台拉取了委托单位相关联系人,如果比对不一致跳出异常终止执行
ValidateContact(model);
//触发生成舱位
bookingSlot = await GenerateBookingSlotByTaskBcInfo(bcOrder, bcCtnList, fileList);
logger.LogInformation($"生成舱位完成,bookingSlotId={bookingSlot?.Id} taskid={bcOrder.TASK_ID}");
if (bookingSlot == null || bookingSlot.Id == 0)
throw new Exception($"生成舱位失败");
var slotFileList = opFileService.GetOpFileList(bookingSlot.Id.ToString()).Data;
//if (bookingSlotService == null)
//{
// bookingSlotService = serviceProvider.GetRequiredService();
//}
//推送订舱订单
model.SlotId = bookingSlot.Id;
var bookingOrderId = await bookingSlotService.Value.GenerateBookingOrder(bookingSlot, slotFileList, model, null);
logger.LogInformation($"生成订舱订单完成,bookingOrderId={bookingOrderId} taskid={bcOrder.TASK_ID}");
if (bookingOrderId < 1)
throw new Exception($"生成订舱订单失败");
List slots = new List();
//检索舱位信息
var slotInfo = (await bookingSlotService.Value.Detail(bookingSlot.Id)).Data;
BookingSlotBaseWithCtnDto baseInfo = slotInfo.Adapt();
baseInfo.Id = bookingSlot.Id;
baseInfo.CtnList = slotInfo.CtnList.Adapt>();
slots.Add(baseInfo);
//对应订舱和舱位关系
ImportSlotsDto importSlotsDto = new()
{
bookingOrderId = bookingOrderId,
slots = slots,
isCheck = false
};
var allocRlt = await bookingSlotService.Value.ImportSlots(importSlotsDto);
logger.LogInformation($"生成订舱和舱位关系完成,allocRlt={JsonConvert.SerializeObject(allocRlt)} taskid={bcOrder.TASK_ID}");
if (!allocRlt.Succeeded)
{
throw new Exception($"生成订舱和舱位关系失败");
}
var bcEntity = await tenantDb.Queryable().Where(a => a.Id == bcOrder.Id).FirstAsync();
if (bcEntity == null)
{
throw new Exception($"未获取有效任务BC失败,更新失败");
}
bcEntity.BOOKING_ORDER_ID = bookingOrderId;
bcEntity.BOOKING_SLOT_ID = slotInfo.Id;
bcEntity.UpdateTime = DateTime.Now;
bcEntity.UpdateBy = long.Parse(user.UserId);
bcEntity.UpdateUserName = user.UserName;
//更新任务BC
await tenantDb.Updateable(bcEntity).UpdateColumns(it => new
{
it.BOOKING_ORDER_ID,
it.BOOKING_SLOT_ID,
it.UpdateTime,
it.UpdateBy,
it.UpdateUserName
}).ExecuteCommandAsync();
var taskEntity = await tenantDb.Queryable().FirstAsync(u => u.Id == bcEntity.TASK_ID);
if (taskEntity == null)
{
throw new Exception($"未获取有效任务记录,更新失败");
}
//var currBCOrder = await tenantDb.Queryable().Where(a => a.Id == bcEntity.Id).FirstAsync();
//if (currBCOrder != null && model.IsDirectSend)
//{
// //异步推送邮件
// var mailRlt = await GenerateSendEmail(currBCOrder, bcTaskInfo, model.usePersonalEmailSend);
// if (!mailRlt.succ)
// {
// throw Oops.Oh($"邮件推送失败,原因:{mailRlt.msg},可以任务编辑页面重新发送邮件");
// }
//}
#endregion
}
else if (model.GenerateMethod == "GEN_BOOKING")
{
#region 推送订舱
//bookingSlot = null;
if (bcOrder.BOOKING_ORDER_ID.HasValue && bcOrder.BOOKING_ORDER_ID.Value > 0)
{
//bookingSlotId = bcOrder.BOOKING_SLOT_ID.Value;
throw new Exception($"生成订舱订单失败,订舱订单已存在");
}
if (!bcOrder.BOOKING_SLOT_ID.HasValue || bcOrder.BOOKING_SLOT_ID.Value < 1)
{
//bookingSlotId = bcOrder.BOOKING_SLOT_ID.Value;
throw new Exception($"生成订舱订单失败,舱位未生成不能直接生成订舱订单");
}
long bookingSlotId = bcOrder.BOOKING_SLOT_ID.Value;
//这里增加委托单位联系人的校验,重新从后台拉取了委托单位相关联系人,如果比对不一致跳出异常终止执行
ValidateContact(model);
BookingSlotBase? bookingSlot = await tenantDb.Queryable().Where(x => x.Id == bookingSlotId).FirstAsync();
if (bookingSlot == null)
{
throw new Exception($"生成订舱订单失败,舱位未生成不能直接生成订舱订单");
}
var slotFileList = opFileService.GetOpFileList(bookingSlotId.ToString()).Data;
//推送订舱订单
//if (bookingSlotService == null)
//{
// bookingSlotService = serviceProvider.GetRequiredService();
//}
model.SlotId = bookingSlot.Id;
var bookingOrderId = await bookingSlotService.Value.GenerateBookingOrder(bookingSlot, slotFileList, model, null);
logger.LogInformation($"生成订舱订单完成,bookingOrderId={bookingOrderId} taskid={bcOrder.TASK_ID}");
if (bookingOrderId < 1)
throw new Exception($"生成订舱订单失败");
List slots = new List();
//检索舱位信息
var slotInfo = (await bookingSlotService.Value.Detail(bookingSlot.Id)).Data;
BookingSlotBaseWithCtnDto baseInfo = slotInfo.Adapt();
baseInfo.Id = bookingSlot.Id;
baseInfo.CtnList = slotInfo.CtnList.Adapt>();
slots.Add(baseInfo);
//对应订舱和舱位关系
ImportSlotsDto importSlotsDto = new()
{
bookingOrderId = bookingOrderId,
slots = slots,
isCheck = false
};
var allocRlt = await bookingSlotService.Value.ImportSlots(importSlotsDto);
logger.LogInformation($"生成订舱和舱位关系完成,allocRlt={JsonConvert.SerializeObject(allocRlt)} taskid={bcOrder.TASK_ID}");
if (!allocRlt.Succeeded)
{
throw new Exception($"生成订舱和舱位关系失败");
}
var bcEntity = await tenantDb.Queryable().Where(a => a.Id == bcOrder.Id).FirstAsync();
if (bcEntity == null)
{
throw new Exception($"未获取有效任务BC失败,更新失败");
}
bcEntity.BOOKING_ORDER_ID = bookingOrderId;
bcEntity.BOOKING_SLOT_ID = slotInfo.Id;
bcEntity.UpdateTime = DateTime.Now;
bcEntity.UpdateBy = long.Parse(user.UserId);
bcEntity.UpdateUserName = user.UserName;
//更新任务BC
await tenantDb.Updateable(bcEntity).UpdateColumns(it => new
{
it.BOOKING_ORDER_ID,
it.BOOKING_SLOT_ID,
it.UpdateTime,
it.UpdateBy,
it.UpdateUserName
}).ExecuteCommandAsync();
var taskEntity = await tenantDb.Queryable().FirstAsync(u => u.Id == bcEntity.TASK_ID);
if (taskEntity == null)
{
throw new Exception($"未获取有效任务记录,更新失败");
}
//var currBCOrder = _taskBCInfoRepository.AsQueryable().First(a => a.PK_ID == bcEntity.PK_ID);
//if (currBCOrder != null && model.IsDirectSend)
//{
// //异步推送邮件
// var mailRlt = await GenerateSendEmail(currBCOrder, bcTaskInfo, model.usePersonalEmailSend);
// if (!mailRlt.succ)
// {
// throw Oops.Oh($"邮件推送失败,原因:{mailRlt.msg},可以任务编辑页面重新发送邮件");
// }
//}
#endregion
}
else if (model.GenerateMethod == "GEN_SLOT")
{
#region 推送舱位
BookingSlotBase? bookingSlot = null;
if (bcOrder.BOOKING_SLOT_ID.HasValue && bcOrder.BOOKING_SLOT_ID.Value > 0)
{
//bookingSlotId = bcOrder.BOOKING_SLOT_ID.Value;
throw new Exception($"生成舱位失败,舱位已存在");
}
//触发生成舱位
bookingSlot = await GenerateBookingSlotByTaskBcInfo(bcOrder, bcCtnList, fileList);
logger.LogInformation($"生成舱位完成,bookingSlotId={bookingSlot?.Id} taskid={bcOrder.TASK_ID}");
if (bookingSlot == null || bookingSlot.Id == 0)
throw new Exception($"生成舱位失败");
var bcEntity = await tenantDb.Queryable().Where(a => a.Id == bcOrder.Id).FirstAsync();
if (bcEntity == null)
{
throw new Exception($"未获取有效任务BC失败,更新失败");
}
bcEntity.BOOKING_SLOT_ID = bookingSlot.Id;
bcEntity.UpdateTime = DateTime.Now;
bcEntity.UpdateBy = long.Parse(user.UserId);
bcEntity.UpdateUserName = user.UserName;
//更新任务BC
await tenantDb.Updateable(bcEntity).UpdateColumns(it => new
{
it.BOOKING_SLOT_ID,
it.UpdateTime,
it.UpdateBy,
it.UpdateUserName
}).ExecuteCommandAsync();
#endregion
}
else if (model.GenerateMethod == "UPD_BOOKING")
{
#region 更新订舱
if (bcOrder.BOOKING_ORDER_ID == null || bcOrder.BOOKING_ORDER_ID.Value == 0)
{
throw new Exception($"更新订舱订单失败,舱位未关联到订单信息");
}
//这里增加委托单位联系人的校验,重新从后台拉取了委托单位相关联系人,如果比对不一致跳出异常终止执行
ValidateContact(model);
long bookingSlotId = bcOrder.BOOKING_SLOT_ID.Value;
//这里增加委托单位联系人的校验,重新从后台拉取了委托单位相关联系人,如果比对不一致跳出异常终止执行
ValidateContact(model);
BookingSlotBase? bookingSlot = await tenantDb.Queryable().Where(x => x.Id == bookingSlotId).FirstAsync();
if (bookingSlot == null)
{
throw new Exception($"更新订舱订单失败,未找到id为{bookingSlotId}的舱位信息");
}
List bookingSlotCtnList = await tenantDb.Queryable().Where(x => x.Id == bookingSlotId).ToListAsync();
//推送订舱订单
var bookingOrderId = await UpdateBookingOrder((long)bcOrder.BOOKING_ORDER_ID, bookingSlot, bookingSlotCtnList, model, tenantDb);
var taskEntity = await tenantDb.Queryable().FirstAsync(u => u.Id == bcOrder.TASK_ID);
if (taskEntity == null)
{
throw new Exception($"未获取有效任务记录,更新失败");
}
//var currBCOrder = await tenantDb.Queryable().Where(a => a.Id == bcEntity.Id).FirstAsync();
//if (currBCOrder != null && model.IsDirectSend)
//{
// //异步推送邮件
// var mailRlt = await GenerateSendEmail(currBCOrder, bcTaskInfo, model.usePersonalEmailSend);
// if (!mailRlt.succ)
// {
// throw Oops.Oh($"邮件推送失败,原因:{mailRlt.msg},可以任务编辑页面重新发送邮件");
// }
//}
#endregion
}
#region 更新任务
//var taskEntity = await tenantDb.Queryable().FirstAsync(u => u.Id == bcEntity.TASK_ID);
//if (taskEntity == null)
//{
// throw new Exception($"未获取有效任务记录,更新失败");
//}
////如果是公共任务,需要变成个人任务 RealUserId = 当前操作人
//if (taskEntity.IS_PUBLIC == 1)
//{
// taskEntity.IS_PUBLIC = 0;
// taskEntity.RealUserId = long.Parse(user.UserId);
// taskEntity.RealUserName = user.UserName;
// taskEntity.UpdateTime = DateTime.Now;
// taskEntity.UpdateBy = taskEntity.RealUserId ?? 0;
// taskEntity.UpdateUserName = user.UserName;
// taskEntity.IS_COMPLETE = 1;
// taskEntity.COMPLETE_DATE = DateTime.Now;
// taskEntity.COMPLETE_DEAL = "MANUAL";
// taskEntity.COMPLETE_DEAL = "手工";
// await tenantDb.Updateable(taskEntity).UpdateColumns(it => new
// {
// it.IS_PUBLIC,
// it.UpdateTime,
// it.UpdateBy,
// it.UpdateUserName,
// it.RealUserId,
// it.RealUserName,
// it.IS_COMPLETE,
// it.COMPLETE_DATE,
// it.COMPLETE_DEAL,
// it.COMPLETE_DEAL_NAME
// }).ExecuteCommandAsync();
//}
//else
//{
// taskEntity.UpdateTime = DateTime.Now;
// taskEntity.UpdateBy = long.Parse(user.UserId);
// taskEntity.UpdateUserName = user.UserName;
// taskEntity.IS_COMPLETE = 1;
// taskEntity.COMPLETE_DATE = DateTime.Now;
// taskEntity.COMPLETE_DEAL = "MANUAL";
// taskEntity.COMPLETE_DEAL = "手工";
// await tenantDb.Updateable(taskEntity).UpdateColumns(it => new
// {
// it.UpdateTime,
// it.UpdateBy,
// it.UpdateUserName,
// it.IS_COMPLETE,
// it.COMPLETE_DATE,
// it.COMPLETE_DEAL,
// it.COMPLETE_DEAL_NAME
// }).ExecuteCommandAsync();
//}
#endregion
result.succ = true;
result.msg = "成功";
return DataResult.Success(result);
}
catch (Exception ex)
{
result.succ = false;
result.msg = $"生成订舱或舱位失败,原因:{ex.Message}";
return DataResult.FailedData(result);
}
}
private void ValidateContact(BookingOrSlotGenerateDto model)
{
var paramConfig = configService.GetConfig(TenantParamCode.CONST_CREATE_BOOKING_NEED_CONTACT, long.Parse(user.TenantId), false).GetAwaiter().GetResult()?.Data?.Value;
if (model.CustomerContactList != null && model.CustomerContactList.Count > 0)
{
//取委托客户下面所有的联系人列表
var djyCustomerInfo = clientInfoService.GetClientInfoWithContact(new Info.Dtos.QueryClientInfo { ClientId = model.CustomerId.Value, IsController = true }).GetAwaiter().GetResult().Data;
if (djyCustomerInfo == null)
{
logger.LogInformation($"委托单位{model.CustomerName} 获取失败,委托单位不存在或已作废 SlotId={model.SlotId.Value}");
//委托单位{0} 获取失败,委托单位不存在或已作废
throw new Exception(string.Format(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.BookingSlotCreateContaNull)), model.CustomerName));
}
if (djyCustomerInfo.ClientContactList == null && djyCustomerInfo.ClientContactList.Count < 1)
{
logger.LogInformation($"委托单位{model.CustomerName} 获取相关联系人失败,委托单位相关联系人为空 SlotId={model.SlotId.Value}");
//委托单位{0} 获取相关联系人失败,委托单位相关联系人为空
throw new Exception(string.Format(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.BookingSlotCreateCustomerContractInfoNull)), model.CustomerName));
}
model.CustomerContactList.ForEach(contact =>
{
var djyCustomerContactMan = djyCustomerInfo.ClientContactList
.FirstOrDefault(a => a.Id == contact.Id);
if (djyCustomerContactMan == null)
{
logger.LogInformation($"委托单位{model.CustomerName} 联系人 {contact.Name}获取失败,联系人不存在或已作废 SlotId={model.SlotId}");
//委托单位 {0} 联系人 {1} 获取失败,联系人不存在或已作废
throw new Exception(string.Format(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.BookingSlotCreateCustomerContractDeletedOrNoExists)), model.CustomerName, contact.Name));
}
});
}
else
{
if (paramConfig != null && paramConfig.Equals("ENABLE", StringComparison.OrdinalIgnoreCase))
{
//生成订舱时往来单位联系人必填,请修改
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.BookingSlotCreateCustomerContractNotNull)));
}
}
}
///
/// 通过任务主键获取BC详情
///
/// BC任务主键
public async Task> GetInfoByTaskId(long taskId)
{
TaskManageOrderResultDto result = new TaskManageOrderResultDto();
try
{
var tenantDb = saasDbService.GetBizDbScopeById(user.TenantId);
//任务不考虑OrgId,这里去掉
tenantDb.QueryFilter.Clear();
var taskBase = await tenantDb.Queryable().FirstAsync(a => a.Id == taskId);
if (taskBase == null)
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.TaskBaseEmpty)));
var bcOrder = await tenantDb.Queryable().FirstAsync(a => a.TASK_ID == taskId);
if (bcOrder == null)
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.TaskBCInfoEmpty)));
var bcCtnList = await tenantDb.Queryable().Where(a => a.P_ID == bcOrder.Id).ToListAsync();
TaskBCShowBaseDto model = bcOrder.Adapt();
if (bcCtnList.Count > 0)
model.CtnList = bcCtnList.Adapt>();
var fileList = await tenantDb.Queryable().Where(a => a.TASK_PKID == bcOrder.TASK_ID).ToListAsync();
if (fileList.Count > 0)
model.FileList = fileList.Adapt>();
model.taskStatus = taskBase.STATUS;
#region 生成关键信息
model.Keywords = new List();
if (bcOrder.CARRIAGE_TYPE == "DIRECT_SHIP")
{
model.Keywords.Add(new TaskBCShowBaseKeywordDto() { Name = $"承运方式:{bcOrder.CARRIAGE_TYPE_NAME}", Background = "#FFFF80", Icon = "icon-yunshu1" });
}
else if (bcOrder.CARRIAGE_TYPE == "TRANSFER_SHIP")
{
model.Keywords.Add(new TaskBCShowBaseKeywordDto() { Name = $"承运方式:{bcOrder.CARRIAGE_TYPE_NAME}", Background = "#CAF982", Icon = "icon-shuaxin" });
}
if (bcOrder.BOOKING_SLOT_TYPE == "CONTRACT_ORDER")
{
model.Keywords.Add(new TaskBCShowBaseKeywordDto() { Name = $"订舱方式:{bcOrder.BOOKING_SLOT_TYPE_NAME}", Background = "#81D3F8", Icon = "icon-touzijilu" });
}
else if (bcOrder.BOOKING_SLOT_TYPE == "SPOT_ORDER")
{
model.Keywords.Add(new TaskBCShowBaseKeywordDto() { Name = $"订舱方式:{bcOrder.BOOKING_SLOT_TYPE_NAME}", Background = "#FACD91", Icon = "icon-beizhu1" });
}
#endregion
//await SetTaskStatus([taskId], x => x.IS_PUBLIC == 1, x => x.IS_EXCEPT == 0);
//await SetTaskOwner([taskId], new List()
//{
// new RecvUserInfo(111,"231312321"),
// new RecvUserInfo(222,"affsdfdsf"),
//});
result.succ = true;
result.ext = model;
//如果当前BC有对应记录,则读取订舱详情
//0726:经确认页面上没有用到订舱详情,所以暂时不返回
//if (bcOrder.BOOKING_ORDER_ID.HasValue)
//{
// var bkOrder = await _bookingOrderRepository.AsQueryable().
// FirstAsync(a => a.Id == bcOrder.BOOKING_ORDER_ID.Value);
// if (bkOrder != null)
// {
// var showBKOrder = bkOrder.Adapt();
// var ctnList = await _bookingCtnRepository.AsQueryable().
// Where(a => a.BILLID == bkOrder.Id).ToListAsync();
// if (ctnList.Count > 0)
// showBKOrder.ctnInputs = ctnList.Adapt>();
// result.ext2 = showBKOrder;
// }
//}
}
catch (Exception ex)
{
result.succ = false;
result.msg = $"获取BC详情异常,原因:{ex.Message}";
}
return DataResult.Success(result);
}
#region 根据BC任务信息生成舱位
///
/// 根据BC任务信息,生成舱位(调用的)
///
/// BC任务详情
/// BC任务集装箱列表
/// BC任务附件列表
/// 返回舱位ID
private async Task GenerateBookingSlotByTaskBcInfo(TaskBCInfo taskBCInfo, List taskBCCtnList, List taskFileList, string opType = "add")
{
//long id = 0;
try
{
var allMapCarrierList = await mappingCarrierService.GetAllList();
MappingCarrierRes? carrierInfo = null;
if (allMapCarrierList.Succeeded)
{
carrierInfo = allMapCarrierList.Data.Where(t => t.MapCode.Equals(taskBCInfo.CARRIERID, StringComparison.OrdinalIgnoreCase) && t.Module == MappingModuleConst.CONST_MAPPING_CARRIER_MODULE).FirstOrDefault();
}
BookingSlotBaseApiDto slotModel = new BookingSlotBaseApiDto
{
DataObj = new BookingSlotBaseApiSaveDto
{
CarrierId = carrierInfo?.LinkId,
CarrierCode = carrierInfo?.MapCode,
Carrier = carrierInfo?.MapName,
SlotBookingNo = taskBCInfo.MBL_NO,
BookingParty = taskBCInfo.BOOKING_PARTY,
BookingSlotType = taskBCInfo.BOOKING_SLOT_TYPE,
BookingSlotTypeName = taskBCInfo.BOOKING_SLOT_TYPE_NAME,
Vessel = taskBCInfo.VESSEL,
Voyno = taskBCInfo.VOYNO,
VGMSubmissionCutDate = taskBCInfo.VGM_CUTOFF_TIME,
//WeekAt = taskBCInfoDto.WEEK_AT,
CarriageType = taskBCInfo.CARRIAGE_TYPE,
CarriageTypeName = taskBCInfo.CARRIAGE_TYPE_NAME,
ContractNo = taskBCInfo.CONTRACTNO,
CtnStat = taskBCInfo.CTN_STAT,
CYCutDate = taskBCInfo.CY_CUTOFF_TIME,
DetensionFreeDays = taskBCInfo.DETENSION_FREE_DAYS,
ETD = taskBCInfo.ETD,
ETA = taskBCInfo.ETA,
LaneCode = taskBCInfo.LANECODE,
LaneName = taskBCInfo.LANENAME,
ManifestCutDate = taskBCInfo.MANIFEST_CUT_DATE,
MDGFCutDate = taskBCInfo.MDGF_CUT_DATE,
PlaceDelivery = taskBCInfo.PLACEDELIVERY,
PlaceReceipt = taskBCInfo.PLACERECEIPT,
PortDischarge = taskBCInfo.PORTDISCHARGE,
PortLoad = taskBCInfo.PORTLOAD,
SICutDate = taskBCInfo.SI_CUT_DATE,
CustomSICutDate = taskBCInfo.CUSTOM_SI_CUT_DATE,
TransferPort1 = taskBCInfo.TRANSFER_PORT_1,
TransferPort2 = taskBCInfo.TRANSFER_PORT_2,
PriceCalculationDate = taskBCInfo.PRICE_CALCULATION_DATE,
CtnList = new List()
},
OpType = "add"
};
if (int.TryParse(taskBCInfo.WEEK_AT, out int _weekat))
{
slotModel.DataObj.WeekAt = _weekat;
}
var ctnCodeList = (await codeCtnService.GetAllList()).Data ?? new List();
if (taskBCCtnList.Count > 0)
{
taskBCCtnList.ForEach(t =>
{
if (string.IsNullOrEmpty(t.CTNCODE) && !string.IsNullOrEmpty(t.CTNALL))
{
var ctnCode = ctnCodeList.FirstOrDefault(a => !string.IsNullOrWhiteSpace(a.CtnName) && a.CtnName.Equals(t.CTNALL, StringComparison.OrdinalIgnoreCase));
t.CTNCODE = ctnCode != null ? $"{ctnCode.CtnSize}{ctnCode.CtnType}" : "(箱型未收录)";
}
BookingSlotCtnSaveInput ctn = new BookingSlotCtnSaveInput
{
CtnCode = t.CTNCODE,
CtnAll = t.CTNALL,
CtnNum = t.CTNNUM.HasValue ? t.CTNNUM.Value : 1
};
slotModel.DataObj.CtnList.Add(ctn);
});
}
var basePath = AppSetting.app(new string[] { "FileSettings", "BasePath" });
DynameFileInfo dynameFile = null;
DynameFileInfo dynameNoticeFile = null;
if (taskFileList.Any(t => t.FILE_CATEGORY == TaskFileCategoryEnum.BC.ToString()))
{
var fileInfo = taskFileList.FirstOrDefault(t => t.FILE_CATEGORY == TaskFileCategoryEnum.BC.ToString());
string fileFullPath;
if (string.IsNullOrEmpty(basePath))
{
fileFullPath = Path.Combine(environment.WebRootPath ?? "", fileInfo.FILE_PATH);
}
else
{
fileFullPath = Path.Combine(basePath, fileInfo.FILE_PATH);
}
dynameFile = new DynameFileInfo
{
FileBytes = File.ReadAllBytes(fileFullPath),
FileName = Path.GetFileName(fileFullPath)
};
}
if (taskFileList.Any(t => t.FILE_CATEGORY == TaskFileCategoryEnum.BC_NOTICE.ToString()))
{
var fileInfo = taskFileList.FirstOrDefault(t => t.FILE_CATEGORY == TaskFileCategoryEnum.BC.ToString());
string fileFullPath;
if (string.IsNullOrEmpty(basePath))
{
fileFullPath = Path.Combine(environment.WebRootPath ?? "", fileInfo.FILE_PATH);
}
else
{
fileFullPath = Path.Combine(basePath, fileInfo.FILE_PATH);
}
dynameNoticeFile = new DynameFileInfo
{
FileBytes = File.ReadAllBytes(fileFullPath),
FileName = Path.GetFileName(fileFullPath)
};
}
var result = await bookingSlotService.Value.InnerApiReceive(slotModel, dynameFile, dynameNoticeFile);
if (result.Succeeded && result.Data != null)
{
var tenantDb = saasDbService.GetBizDbScopeById(user.TenantId);
var taskBcInfo = await tenantDb.Queryable().Where(x => x.Id == taskBCInfo.Id).FirstAsync();
if (taskBcInfo != null && taskBcInfo.BOOKING_SLOT_ID == null)
{
taskBcInfo.BOOKING_SLOT_ID = result.Data.Id;
await tenantDb.Updateable(taskBcInfo).UpdateColumns(x => new
{
x.BOOKING_SLOT_ID
}).ExecuteCommandAsync();
}
}
return result.Data;
}
catch (Exception ex)
{
logger.LogError($"任务BC MBLNO:{taskBCInfo.MBL_NO} 生成舱位异常,原因:{ex.Message}");
throw new Exception($"MBLNO:{taskBCInfo.MBL_NO} 生成舱位异常,原因:{ex.Message}");
}
}
#endregion
#region 更新订舱
///
/// 更新订舱
///
/// 返回订舱ID
private async Task UpdateBookingOrder(
//TaskBCInfo taskBCInfo,
//List taskBCCtnList,
long bookingOrderId,
BookingSlotBase bookingSlotBase,
List bookingSlotCtnList,
BookingOrSlotGenerateDto generateModel,
SqlSugarScopeProvider? tenantDb = null)
{
//long id = 0;
if (tenantDb == null)
{
tenantDb = saasDbService.GetBizDbScopeById(user.TenantId);
}
//任务不考虑OrgId,这里去掉
tenantDb.QueryFilter.Clear();
try
{
/*
1、新增订舱
2、推送服务项目
3、推送附件
*/
var allMapCarrierList = await mappingCarrierService.GetAllList();
MappingCarrierRes carrierInfo = null;
if (allMapCarrierList.Succeeded)
{
carrierInfo = allMapCarrierList.Data.FirstOrDefault(t => t.LinkId == bookingSlotBase.CarrierId.Value && t.Module == MappingModuleConst.CONST_MAPPING_CARRIER_MODULE);
}
SeaExportReq bkModel = new SeaExportReq
{
Id = bookingOrderId,
CustomerId = generateModel.CustomerId.Value,
CustomerName = generateModel.CustomerName,
Carrier = carrierInfo?.MapName?.Trim(),
CarrierId = bookingSlotBase.CarrierId.Value,
BookingNo = bookingSlotBase.SlotBookingNo.Trim(),
MBLNO = bookingSlotBase.SlotBookingNo.Trim(),
ContractNo = !string.IsNullOrWhiteSpace(bookingSlotBase.ContractNo) ? bookingSlotBase.ContractNo : "",
Vessel = bookingSlotBase.Vessel?.ToUpper()?.Trim(),
Voyno = bookingSlotBase.Voyno?.ToUpper()?.Trim(),
InnerVoyno = bookingSlotBase.Voyno?.ToUpper()?.Trim(),
ETD = bookingSlotBase.ETD,
ETA = bookingSlotBase.ETA,
SaleId = generateModel.SaleId.HasValue ? generateModel.SaleId.Value : 0,
Sale = generateModel.SaleName,
OperatorId = generateModel.OpId.HasValue ? generateModel.OpId.Value : 0,
OperatorName = generateModel.OpName,
Doc = generateModel.DocId.HasValue ? generateModel.DocId.Value : 0,
DocName = generateModel.DocName,
//ROUTEID = generateModel.RouteID?.ToString(),
//ROUTE = generateModel.Route,
//CZRemark = generateModel.CZRemark,
//ShenQingXiangShi = generateModel.ShenQingXiangShi,
//LineManageID = generateModel.LineManageID?.ToString(),
//LineName = generateModel.LineManage,
VGMCloseDate = bookingSlotBase.VGMSubmissionCutDate,
ClosingDate = bookingSlotBase.CYCutDate,
CloseDocDate = bookingSlotBase.SICutDate,
CustomerService = generateModel.CustServiceId.HasValue ? generateModel.CustServiceId.Value : 0,
CustomerServiceName = generateModel.CustServiceName,
LoadPort = bookingSlotBase.PortLoad,
LoadPortId = bookingSlotBase.PortLoadId.HasValue ? bookingSlotBase.PortLoadId.Value : 0,
DischargePortId = bookingSlotBase.PortDischargeId.HasValue ? bookingSlotBase.PortLoadId.Value : 0,
DischargePort = bookingSlotBase.PortDischarge,
ReceiptPlace = bookingSlotBase.PlaceReceipt,
ReceiptPlaceId = bookingSlotBase.PlaceReceiptId.HasValue ? bookingSlotBase.PlaceReceiptId.Value : 0,
DeliveryPlace = bookingSlotBase.PlaceDelivery,
DeliveryPlaceId = bookingSlotBase.PlaceDeliveryId.HasValue ? bookingSlotBase.PlaceDeliveryId.Value : 0,
BLType = "整箱",
StlName = "票结",
CtnInfo = new List()
};
//var ctnCodeList = _cache.GetAllCodeCtn().GetAwaiter().GetResult().ToList();
if (bookingSlotCtnList != null && bookingSlotCtnList.Count > 0)
{
bookingSlotCtnList.Select(t =>
{
OpCtnReq ctn = new OpCtnReq
{
CtnCode = t.CtnCode,
CtnAll = t.CtnAll,
CtnNum = t.CtnNum
};
return ctn;
});
}
var bkRlt = await seaExportService.Value.EditSeaExport(bkModel);
if (!bkRlt.Succeeded)
{
throw new Exception(MultiLanguageConst.GetDescription(MultiLanguageConst.DataUpdateFailed) + "," + bkRlt.Message);
}
string batchNo = Guid.NewGuid().ToString();
//var hisList = _bookingOrderContactRepository.AsQueryable().Where(a => a.BookingId == id && a.IsDeleted == false).ToList();
//if (hisList.Count > 0)
//{
// //批量作废
// hisList.ForEach(async a =>
// {
// a.IsDeleted = true;
// a.UpdatedTime = DateTime.Now;
// a.UpdatedUserId = UserManager.UserId;
// a.UpdatedUserName = UserManager.Name;
// await _bookingOrderContactRepository.UpdateAsync(a);
// });
//}
//这里如果指定了委托单位的邮件联系人,则推送订舱联系人
if (generateModel.CustomerContactList != null && generateModel.CustomerContactList.Count > 0)
{
var bookingContactList = await tenantDb.Queryable()
.Where(a => a.BusinessId == bookingOrderId && a.Deleted == false).ToListAsync();
var djyCustomerInfo = clientInfoService.GetClientInfoWithContact(new Info.Dtos.QueryClientInfo { ClientId = generateModel.CustomerId.Value, IsController = true })
.GetAwaiter().GetResult().Data;
generateModel.CustomerContactList.ForEach(contact =>
{
ClientContactRes djyCustomerContactMan = null;
if (djyCustomerInfo.ClientContactList != null && djyCustomerInfo.ClientContactList.Count > 0)
{
djyCustomerContactMan = djyCustomerInfo.ClientContactList.FirstOrDefault(a =>
a.Id == contact.Id);
}
if (djyCustomerContactMan != null)
{
var bookingContact = bookingContactList
.FirstOrDefault(x => x.Email.Equals(djyCustomerContactMan.Email, StringComparison.OrdinalIgnoreCase));
if (bookingContact == null)
{
bookingContact = new BusinessOrderContact
{
Name = djyCustomerContactMan.Name,
BusinessId = bookingOrderId,
Email = djyCustomerContactMan.Email,
Note = djyCustomerContactMan.Note,
CreateTime = DateTime.Now,
CreateBy = long.Parse(user.UserId),
CreateUserName = user.UserName
};
tenantDb.Insertable(bookingContact).ExecuteCommand();
//_bookingOrderContactRepository.Insert(bookingContact);
}
else
{
bookingContact.Name = djyCustomerContactMan.Name;
bookingContact.Email = djyCustomerContactMan.Email;
bookingContact.Note = djyCustomerContactMan.Note;
bookingContact.UpdateTime = DateTime.Now;
bookingContact.UpdateBy = long.Parse(user.UserId);
bookingContact.UpdateUserName = user.UserName;
tenantDb.Updateable(bookingContact).UpdateColumns(it => new
{
it.Name,
it.Email,
it.Note,
it.UpdateTime,
it.UpdateBy,
it.UpdateUserName
}).ExecuteCommand();
}
}
});
}
if (generateModel.ProjectList != null && generateModel.ProjectList.Count > 0)
{
//写入服务项目
var prjRlt = djyServiceStatusService.Value.SaveServiceProject(new EmbedServiceProjectDto
{
BusinessId = bookingOrderId.ToString(),
ProjectCodes = generateModel.ProjectList.Distinct().ToArray(),
});
logger.LogInformation($"推送订舱的服务项目完成 id={bookingOrderId} rlt={JsonConvert.SerializeObject(prjRlt)}");
}
logger.LogInformation($"任务BC MBLNO:{bookingSlotBase.SlotBookingNo} 生成订舱成功 id={bookingOrderId}");
}
catch (Exception ex)
{
logger.LogError($"任务BC MBLNO:{bookingSlotBase.SlotBookingNo} 生成订舱异常,原因:{ex.Message}");
}
return bookingOrderId;
}
#endregion
#region 获取当前比对结果
///
/// 获取当前比对结果
///
/// BC任务主键
/// 返回回执
public async Task>> GetCompareResult(long taskId)
{
var tenantDb = saasDbService.GetBizDbScopeById(user.TenantId);
//任务不考虑OrgId,这里去掉
tenantDb.QueryFilter.Clear();
var queryList = await tenantDb.Queryable()
.InnerJoin((a, b) => a.Id == b.TASK_ID)
.Where((a, b) => a.Id == taskId)
.Select((a, b) => new { Base = a, BC = b })
.ToListAsync();
//任务主键{taskPkId}无法获取业务信息
if (queryList.Count == 0)
throw new Exception(string.Format(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.TaskBaseInfoFromTaskIdNull)), taskId));
var taskBCInfo = queryList.FirstOrDefault().BC;
if (taskBCInfo.BOOKING_SLOT_ID.HasValue)
{
return await bookingSlotService.Value.GetSlotCompareResult(taskBCInfo.BOOKING_SLOT_ID.Value, taskBCInfo.BATCH_NO);
}
else
{
return DataResult>.Success(new List());
}
}
#endregion
///
/// 对比BC与海运出口订单(任务台使用)
///
public async Task> CompareBcWithSeaExportTask(TaskFlowDataContext dataContext)
{
var taskBcInfo = dataContext.Get(TaskFlowDataNameConst.TaskBCInfo) ?? throw new ArgumentException($"缺少参数:{nameof(TaskFlowDataNameConst.TaskBCInfo)}");
var taskBcCtnList = dataContext.Get?>(TaskFlowDataNameConst.TaskBCCtnList) ?? throw new ArgumentException($"缺少参数:{nameof(TaskFlowDataNameConst.TaskBCCtnList)}");
var seaExport = await tenantDb.Queryable().Where(x => x.Id == taskBcInfo.BOOKING_ORDER_ID).Select(x => new SeaExport()
{
Id = x.Id,
MBLNO = x.MBLNO,
ContractNo = x.ContractNo,
ETD = x.ETD,
Vessel = x.Vessel,
Voyno = x.Voyno,
DischargePort = x.DischargePort,
LoadPort = x.LoadPort,
ReeferQuantity = x.ReeferQuantity,
TemperatureMin = x.TemperatureMin,
TemperatureMax = x.TemperatureMax,
TemperatureSet = x.TemperatureSet,
Humidity = x.Humidity,
}).FirstAsync();
if (seaExport == null)
{
return DataResult.Failed($"根据订单Id:【{taskBcInfo.BOOKING_ORDER_ID}】未查询到海运出口订单信息");
}
var seaExportCtnList = await tenantDb.Queryable().Where(x => x.BSNO == seaExport.Id.ToString()).Select(x => new OpCtn()
{
Id = x.Id,
CtnAll = x.CtnAll,
CtnNum = x.CtnNum
}).ToListAsync();
var compareDto = new CompareBcWithSeaExportDto()
{
TaskBCInfo = taskBcInfo,
TaskBCCtnList = taskBcCtnList,
SeaExport = seaExport,
OpCtnList = seaExportCtnList
};
var result = await CompareBcWithSeaExport(compareDto);
dataContext.Set(TaskFlowDataNameConst.BcCompareWithSeaExportResult, result);
return DataResult.Success(result);
}
///
/// 对比BC与海运出口订单
///
public async Task CompareBcWithSeaExport(CompareBcWithSeaExportDto compareDto)
{
var taskBcInfo = compareDto.TaskBCInfo;
var taskBcCtnList = compareDto.TaskBCCtnList;
var seaExport = compareDto.SeaExport;
var seaExportCtnList = compareDto.OpCtnList;
var taskBcId = taskBcInfo.Id;
string batchNo = GuidHelper.GetSnowflakeId();
// BC信息
ParserBCInfoDto bcSrcDto = new ParserBCInfoDto()
{
ContractNo = taskBcInfo.CONTRACTNO,
Vessel = taskBcInfo.VESSEL,
VoyNo = taskBcInfo.VOYNO,
ETD = taskBcInfo.ETD?.ToString("yyyy-MM-dd"),
Portload = taskBcInfo.PORTLOAD?.Split(',').FirstOrDefault()?.Trim(),
DischargePort = taskBcInfo.PORTDISCHARGE?.Split(',').FirstOrDefault()?.Trim(),
CtnList = taskBcCtnList.GroupBy(x => x.CTNALL).Select(x => new ParserBCCTNInfoDto
{
CtnALL = x.Key,
CtnNum = x.ToList().Sum(a => a.CTNNUM)
}).ToList()
};
// 订单信息
ParserBCInfoDto bcTargetDto = new ParserBCInfoDto()
{
ContractNo = seaExport.ContractNo,
Vessel = seaExport.Vessel,
VoyNo = seaExport.Voyno,
ETD = seaExport.ETD?.ToString("yyyy-MM-dd"),
Portload = seaExport.LoadPort?.Split(',').FirstOrDefault()?.Trim(),
DischargePort = seaExport.DischargePort?.Split(',').FirstOrDefault()?.Trim(),
CtnList = seaExportCtnList.GroupBy(x => x.CtnAll).Select(x => new ParserBCCTNInfoDto
{
CtnALL = x.Key,
CtnNum = x.ToList().Sum(a => a.CtnNum)
}).ToList()
};
//2021-11-23,备注中含有NOR,不比较温度湿度等信息
//2023 - 02 - 02 这里补充了一下EDIREMARK的判断,用正则匹配NOR信息。NOR(冻代干集装箱)
if (seaExport.CargoId == "R" && (string.IsNullOrWhiteSpace(seaExport.SORemark) || !Regex.IsMatch(seaExport.SORemark, "\\bNOR\\b")))
{
bcSrcDto.TemperatureMin = taskBcInfo.TEMPERATURE_MIN;
bcSrcDto.TemperatureMax = taskBcInfo.TEMPERATURE_MAX;
bcSrcDto.TemperatureSet = taskBcInfo.TEMPERATURE_SET;
bcSrcDto.Humidity = taskBcInfo.HUMIDITY;
bcSrcDto.ReeferQuantity = taskBcInfo.REEFER_QUANTITY;
bcTargetDto.TemperatureMin = seaExport.TemperatureMin;
bcTargetDto.TemperatureMax = seaExport.TemperatureMax;
bcTargetDto.TemperatureSet = seaExport.TemperatureSet;
bcTargetDto.Humidity = seaExport.Humidity;
bcTargetDto.ReeferQuantity = seaExport.ReeferQuantity;
}
DateTime bDate = DateTime.Now;
logger.LogInformation($"批次={batchNo} taskBcInfo.id={taskBcInfo.Id} seaExport.id={seaExport.Id} 开始请求BC对比订单结果");
var compareResult = (await bookingSlotService.Value.ExcuteCompare(bcSrcDto, bcTargetDto)).Data;
DateTime eDate = DateTime.Now;
TimeSpan ts = eDate.Subtract(bDate);
var timeDiff = ts.TotalMilliseconds;
logger.LogInformation($"批次={batchNo} taskBcInfo.id={taskBcInfo.Id} seaExport.id={seaExport.Id} 请求BC对比订单结果完成,耗时:{timeDiff}ms,是否成功:{(compareResult?.succ == true ? "成功" : "失败")} ");
if (compareResult != null && compareResult?.succ == true)
{
logger.LogInformation($"批次={batchNo} BC对比订单结果={JsonConvert.SerializeObject(compareResult)}");
DateTime nowDate = DateTime.Now;
var hisInfo = await tenantDb.Queryable().FirstAsync(a => a.BUSI_ID == seaExport.Id.ToString() && a.TASK_ID == taskBcId);
if (hisInfo == null)
{
BusinessCompareDiffRecord entity = new BusinessCompareDiffRecord
{
BUSI_ID = seaExport.Id.ToString(),
TASK_ID = taskBcId,
BUSI_TYPE = "SEAEXPORT",
COMPARE_DIFF_NUM = compareResult.extra.IsExistsDiff ? compareResult.extra.ShowDetailList.Count : 0,
CreateTime = nowDate,
UpdateTime = nowDate,
CreateBy = long.Parse(user.UserId),
CreateUserName = user.UserName,
UpdateBy = long.Parse(user.UserId),
UpdateUserName = user.UserName,
COMPARE_TYPE = "BC-SEAEXPORT",
COMPARE_RLT = JsonConvert.SerializeObject(compareResult.extra.ShowDetailList),
};
await tenantDb.Insertable(entity).ExecuteCommandAsync();
}
else
{
hisInfo.COMPARE_DIFF_NUM = compareResult.extra.IsExistsDiff ? compareResult.extra.ShowDetailList.Count : 0;
hisInfo.UpdateTime = nowDate;
hisInfo.UpdateBy = long.Parse(user.UserId);
hisInfo.UpdateUserName = user.UserName;
hisInfo.COMPARE_RLT = JsonConvert.SerializeObject(compareResult.extra.ShowDetailList);
await tenantDb.Updateable(hisInfo).UpdateColumns(it =>
new
{
it.COMPARE_DIFF_NUM,
it.COMPARE_RLT,
it.UpdateTime,
it.UpdateBy,
it.UpdateUserName
}).ExecuteCommandAsync();
}
return new CompareResultInfo()
{
IsExistsDiff = compareResult.extra.IsExistsDiff,
ShowDetailList = compareResult.extra.ShowDetailList,
DetailList = compareResult.extra.DetailList,
IsSuccess = true
};
//return (compareResult.extra.IsExistsDiff, compareResult.extra.ShowDetailList);
}
else
{
logger.LogError($"批次={batchNo} BC对比订单结果为空");
return new CompareResultInfo()
{
IsSuccess = false
};
}
}
///
/// 通过BC任务匹配订单(任务台使用)
///
public async Task> BcMatchSeaExportTask(TaskFlowDataContext dataContext)
{
var taskBcInfo = dataContext.Get(TaskFlowDataNameConst.TaskBCInfo) ?? throw new ArgumentException($"缺少参数:{nameof(TaskFlowDataNameConst.TaskBCInfo)}");
var seaExportIdList = await tenantDb.Queryable().Where(x => x.ParentId == 0 && (taskBcInfo.MBL_NO == x.MBLNO || taskBcInfo.MBL_NO == x.OrderNo)).Select(x => x.Id).ToListAsync();
logger.LogInformation($"通过BC任务匹配订单(任务台使用):根据taskBcInfo.MBL_NO【{taskBcInfo.MBL_NO}】查询订单,seaExportIdList结果为:{string.Join(',', seaExportIdList)}");
var seaExportId = seaExportIdList.FirstOrDefault();
if (seaExportId != 0)
{
dataContext.Set(TaskFlowDataNameConst.BusinessId, seaExportId);
taskBcInfo.BOOKING_ORDER_ID = seaExportId;
await tenantDb.Updateable(taskBcInfo).UpdateColumns(x => new
{
x.BOOKING_ORDER_ID,
}).ExecuteCommandAsync();
return DataResult.Success("匹配成功", seaExportId, MultiLanguageConst.OperationSuccess);
}
else
{
return DataResult.Failed("匹配失败,未查询到订单", MultiLanguageConst.Operation_Failed);
}
}
#region 生成并推送邮件
///
/// 生成并推送邮件
///
/// BC任务详情
/// 主任务详情
/// 检索订舱相关
/// 是否默认使用用户个人邮箱发送
/// 返回回执
private async Task GenerateSendEmail(TaskBCInfo taskBCInfo, TaskBaseInfo bcTaskInfo, SeaExportOrderExtension orderInfo, SeaExport currSeaExportOrder,
bool saveBookingId = false,
bool usePersonalEmailSend = false)
{
bool result = false;
string msg = string.Empty;
try
{
/*
1、提取邮件接收人、通过订舱的委托客户获取联系人信息(提取联系人中备注是BCNotice的邮箱)
2、提取当票订舱对应的操作人邮箱、通过订舱的委托客户获取操作OP的邮箱
3、读取用户邮箱配置,主要提取显示名称BCNotice的邮箱,用来作为公共邮箱来发送邮件。
4、读取邮件模板,填充详情。
5、推送邮件给邮件接收人
*/
//if (bookingOrderEntity == null)
//{
// var checkInfo = _bookingOrderRepository.AsQueryable().Filter(null, true)
// .First(a => a.MBLNO == taskBCInfo.MBL_NO && a.IsDeleted == false && (a.ParentId == null || a.ParentId == 0));
// if (checkInfo != null)
// {
// throw Oops.Oh($"订舱详情获取失败,用提单号能检索到,但是没有ID关系,需要人工看看问题");
// }
// else
// {
// throw Oops.Oh($"订舱详情获取失败,请确认订舱是否存在或已删除");
// }
//}
var tenantDb = saasDbService.GetBizDbScopeById(user.TenantId);
//任务不考虑OrgId,这里去掉
tenantDb.QueryFilter.Clear();
var bookingOrderEntity = currSeaExportOrder;
Logger.Log(NLog.LogLevel.Info, $"获取订舱详情完成,bookid={bookingOrderEntity.Id}");
if (saveBookingId && taskBCInfo.BOOKING_ORDER_ID != currSeaExportOrder.Id)
{
taskBCInfo.BOOKING_ORDER_ID = currSeaExportOrder.Id;
taskBCInfo.UpdateTime = DateTime.Now;
taskBCInfo.UpdateBy = long.Parse(user.UserId);
taskBCInfo.UpdateUserName = user.UserName;
await tenantDb.Updateable(taskBCInfo).UpdateColumns(x => new
{
x.BOOKING_ORDER_ID,
x.UpdateTime,
x.UpdateBy,
x.UpdateUserName
}).ExecuteCommandAsync();
}
if (bookingOrderEntity.CustomerId == 0)
{
throw new Exception($"订舱的委托客户不能为空");
}
var djyCustomerInfo = clientInfoService.GetClientInfoWithContact(new Info.Dtos.QueryClientInfo { ClientId = bookingOrderEntity.CustomerId })
.GetAwaiter().GetResult().Data;
if (djyCustomerInfo == null)
{
throw new Exception($"委托单位详情获取失败,请确认委托单位是否存在或已删除");
}
Logger.Log(NLog.LogLevel.Info, $"获取委托单位详情完成,djyCustomerId={djyCustomerInfo.Id}");
//DjyCustomerContactOutput djyCustomerContactMan = null;
//TO 邮件接收人
string toEmail = string.Empty;
//订舱OP的邮箱
string opEmail = string.Empty;
var bookingContactList = tenantDb.Queryable()
.Where(a => a.BusinessId == currSeaExportOrder.Id).ToList();
if (bookingContactList == null || bookingContactList.Count == 0)
{
Logger.Log(NLog.LogLevel.Info, $"当前订舱未指定的联系人,toEmail={toEmail}");
}
toEmail = string.Join(";", bookingContactList.Select(x => x.Email.Trim()).Distinct().ToArray());
//获取操作OP的邮箱
if (bookingOrderEntity.OperatorId > 0)
{
var opId = bookingOrderEntity.OperatorId;
var opUser = db.Queryable().Filter(null, true).First(x => x.Id == bookingOrderEntity.OperatorId && x.TenantId == long.Parse(user.TenantId));
//var opUser = _userService.GetUserInfo(opId.ToString()).Data;
if (opUser != null && !string.IsNullOrWhiteSpace(opUser.Email))
{
opEmail = opUser.Email.Trim();
Logger.Log(NLog.LogLevel.Info, $"获取操作OP的邮箱,opEmail={opEmail} id={opId} name={opUser.UserName}");
}
}
//提取当前公共邮箱的配置
CodeUserEmailRes publicMailAccount = null;
if (usePersonalEmailSend)
{
publicMailAccount = _userEmailService.GetEmailSettings().GetAwaiter().GetResult().Data;
//&& x.SmtpPort > 0 && x.SmtpServer != null && x.SmtpServer != "");
}
else
{
//这个是公共邮箱配置
publicMailAccount = _userEmailService.GetEmailSettings("PublicSend").GetAwaiter().GetResult().Data;
}
if (publicMailAccount == null)
{
throw new Exception($"提取公共邮箱配置失败,请在用户邮箱账号管理增加配置显示名为PublicSend或者配置个人邮箱");
}
Logger.Log(NLog.LogLevel.Info, $"提取当前公共邮箱的配置完成,id={publicMailAccount.Id}");
string emailTitle = $"Booking Confirmation : {taskBCInfo.MBL_NO}";
string filePath = string.Empty;
var opUserInfo = db.Queryable().Filter(null, true).First(x => x.Id == bookingOrderEntity.OperatorId && x.TenantId == long.Parse(user.TenantId));
if (taskBCInfo.BUSI_TYPE == "BookingAmendment")
{
emailTitle = $"【变更】Booking Amendment : {taskBCInfo.MBL_NO}";
}
//读取邮件模板并填充数据
string emailHtml = string.Empty;
if (taskBCInfo.BUSI_TYPE == "BookingAmendment")
{
emailHtml = GenerateSendEmailHtmlAmendment(taskBCInfo, opUserInfo, user.TenantName).GetAwaiter().GetResult();
}
else
{
emailHtml = GenerateSendEmailHtml(taskBCInfo, opUserInfo, user.TenantName).GetAwaiter().GetResult();
}
Logger.Log(NLog.LogLevel.Info, $"生成邮件BODY,结果:{emailHtml}");
TaskFileInfo fileInfo = null;
if (bcTaskInfo.TASK_TYPE == TaskBaseTypeEnum.BC.ToString())
{
fileInfo = tenantDb.Queryable().Where(a => a.TASK_PKID == taskBCInfo.TASK_ID && a.FILE_CATEGORY.Contains("BC_NOTICE"))
.OrderByDescending(a => a.CreateTime).First();
}
else if (bcTaskInfo.TASK_TYPE == TaskBaseTypeEnum.BC_MODIFY.ToString())
{
//CMA没有变更附件,所以转发邮件时默认用原文件转发
if (bcTaskInfo.CARRIER_CODE.Equals("CMA", StringComparison.OrdinalIgnoreCase))
{
fileInfo = tenantDb.Queryable().Where(a => a.TASK_PKID == taskBCInfo.TASK_ID && a.FILE_CATEGORY.Contains("BC_MODIFY"))
.OrderByDescending(a => a.CreateTime).First();
}
else
{
if (orderInfo.splitOrMergeFlag == 1)
{
//这里需要按照箱量重新修改变更附件
}
else
{
fileInfo = tenantDb.Queryable().Where(a => a.TASK_PKID == taskBCInfo.TASK_ID && a.FILE_CATEGORY.Contains("BC_MODIFY_NOTICE"))
.OrderByDescending(a => a.CreateTime).First();
}
}
}
if (fileInfo == null)
{
throw new Exception($"提取变更文件失败,不能发送邮件");
}
Logger.Log(NLog.LogLevel.Info, $"获取订舱附件地址,结果:{fileInfo.FILE_PATH}");
string fileRoot = AppSetting.app(new string[] { "FileSettings", "BasePath" });
string? dirAbs;
if (string.IsNullOrEmpty(fileRoot))
{
dirAbs = Path.Combine(_environment.WebRootPath ?? "");
}
else
{
dirAbs = Path.Combine(fileRoot);
}
filePath = Path.Combine(dirAbs, fileInfo.FILE_PATH);
EmailApiUserDefinedDto emailApiUserDefinedDto = new EmailApiUserDefinedDto
{
SendTo = toEmail,
//CCTo = opEmail,
Title = emailTitle,
Body = emailHtml,
Account = publicMailAccount.MailAccount?.Trim(),
Password = publicMailAccount.Password?.Trim(),
Server = publicMailAccount.SmtpServer?.Trim(),
Port = publicMailAccount.SmtpPort.HasValue ? publicMailAccount.SmtpPort.Value : 465,
UseSSL = publicMailAccount.SmtpSSL.HasValue ? publicMailAccount.SmtpSSL.Value : true,
Attaches = new List()
};
//如果配置了租户参数(AUTO_TRANS_EMAIL_OP_CCTO-自动转发是否默认抄送操作=ENABLE)发送邮件时自动抄送操作
var paramConfig = configService.GetConfig(CONST_AMENDMENT_DEFAULT_PARAM, long.Parse(user.TenantId), false).GetAwaiter().GetResult()?.Data?.Value;
if (paramConfig != null && paramConfig.Equals("ENABLE", StringComparison.OrdinalIgnoreCase))
{
emailApiUserDefinedDto.CCTo = opEmail;
}
Logger.Log(NLog.LogLevel.Info, $"生成请求邮件参数,结果:{JsonConvert.SerializeObject(emailApiUserDefinedDto)}");
//推送邮件
var emailRlt = await PushEmail(emailApiUserDefinedDto, filePath);
Logger.Log(NLog.LogLevel.Info, $"推送邮件完成,结果:{JsonConvert.SerializeObject(emailRlt)}");
//var taskBcInfo = _taskBCInfoRepository.AsQueryable().Filter(null, true)
//.First(a => a.PK_ID == taskBCInfo.PK_ID);
if (emailRlt.Succeeded)
{
result = true;
msg = "成功";
}
else
{
result = false;
msg = emailRlt.Message;
//new EmailNoticeHelper().SendEmailNotice($"MBLNO={taskBCInfo.MBL_NO} 转发通知邮件失败", $"MBLNO={taskBCInfo.MBL_NO} 转发通知邮件失败,原因:{emailRlt.msg}", App.Configuration["EmailNoticeDefaultUser"].GetUserEmailList());
}
}
catch (Exception ex)
{
Logger.Log(NLog.LogLevel.Info, $"推送邮件失败,异常:{ex.Message}");
result = false;
msg = $"推送邮件失败,{ex.Message}";
//new EmailNoticeHelper().SendEmailNotice($"MBLNO={taskBCInfo.MBL_NO} 转发通知邮件失败", $"MBLNO={taskBCInfo.MBL_NO} 转发通知邮件失败,原因:{ex.Message}", App.Configuration["EmailNoticeDefaultUser"].GetUserEmailList());
}
if (!result)
return DataResult.Failed(msg);
return DataResult.Successed(msg);
}
#endregion
#region 通过邮件模板生成HTML
///
/// 通过邮件模板生成HTML
///
/// BC任务详情
/// 订舱OP详情
/// 当前租户全称
/// 返回生成的HTML
public async Task GenerateSendEmailHtml(TaskBCInfo taskBCInfo, SysUser opUserInfo, string tenantName)
{
string result = string.Empty;
/*
1、加载模板文件,读取HTML
2、读取main、conta的tr行,替换业务数据
3、返回HTML的文本信息。
*/
try
{
var basePath = AppSetting.app(new string[] { "EmailTemplate", "BasePath" });
var relativePath = AppSetting.app(new string[] { "EmailTemplate", "RelativePath" });
string dirAbs = string.Empty;
if (string.IsNullOrEmpty(basePath))
{
dirAbs = Path.Combine(_environment.WebRootPath, relativePath);
}
else
{
dirAbs = Path.Combine(basePath, relativePath);
}
string templatePath = $"{dirAbs}\\BCEmailTemplate.html";
string baseHtml = File.ReadAllText(templatePath);
if (string.IsNullOrWhiteSpace(baseHtml))
throw new Exception($"读取邮件模板失败");
if (opUserInfo != null && !string.IsNullOrWhiteSpace(opUserInfo.UserName))
{
baseHtml = baseHtml.Replace("#opname#", opUserInfo.UserName);
}
else
{
baseHtml = baseHtml.Replace("#opname#", "操作");
}
if (opUserInfo != null && !string.IsNullOrWhiteSpace(opUserInfo.Email))
{
baseHtml = baseHtml.Replace("#opemail#", opUserInfo.Email);
}
else
{
baseHtml = baseHtml.Replace("#opemail#", "");
}
if (opUserInfo != null && !string.IsNullOrWhiteSpace(opUserInfo.Phone))
{
baseHtml = baseHtml.Replace("#optel#", opUserInfo.Phone);
}
else if (opUserInfo != null && !string.IsNullOrWhiteSpace(opUserInfo.Tel))
{
baseHtml = baseHtml.Replace("#optel#", opUserInfo.Tel);
}
else
{
baseHtml = baseHtml.Replace("#optel#", "");
}
HtmlDocument html = new HtmlDocument();
html.LoadHtml(baseHtml);
HtmlNode baseTable = html.DocumentNode.SelectNodes("//table[@class='base-table']").FirstOrDefault();
if (baseTable == null)
throw new Exception($"读取邮件模板格式错误,定位base-table失败");
var baseTrList = baseTable.SelectNodes(".//tr");
foreach (var baseTr in baseTrList)
{
var tdList = baseTr.SelectNodes(".//td");
foreach (var baseTd in tdList)
{
if (baseTd.Attributes["class"].Value == "billno-val")
{
baseTd.InnerHtml = taskBCInfo.MBL_NO;
}
else if (baseTd.Attributes["class"].Value == "takebillno-val")
{
baseTd.InnerHtml = taskBCInfo.MBL_NO;
}
else if (baseTd.Attributes["class"].Value == "pol-val")
{
baseTd.InnerHtml = taskBCInfo.PLACERECEIPT;
}
else if (baseTd.Attributes["class"].Value == "pod-val")
{
baseTd.InnerHtml = taskBCInfo.PLACEDELIVERY;
}
else if (baseTd.Attributes["class"].Value == "ctn-val")
{
baseTd.InnerHtml = taskBCInfo.CTN_STAT;
}
else if (baseTd.Attributes["class"].Value == "etd-val")
{
if (taskBCInfo.ETD.HasValue)
{
baseTd.InnerHtml = taskBCInfo.ETD.Value.ToString("yyyy-MM-dd");
}
}
else if (baseTd.Attributes["class"].Value == "eta-val")
{
if (taskBCInfo.ETA.HasValue)
{
baseTd.InnerHtml = taskBCInfo.ETA.Value.ToString("yyyy-MM-dd");
}
}
}
}
var noreplyTr = html.DocumentNode.SelectNodes("//tr[@class='email-noreply']").FirstOrDefault();
if (noreplyTr != null)
{
var currTd = noreplyTr.SelectNodes(".//td").FirstOrDefault();
if (currTd != null)
{
var currPList = currTd.SelectNodes(".//p");
foreach (var baseP in currPList)
{
if (baseP.Attributes["class"].Value == "notice-comp-val")
{
baseP.InnerHtml = tenantName;
}
}
}
}
result = html.DocumentNode.OuterHtml;
}
catch (Exception ex)
{
Logger.Log(NLog.LogLevel.Info, $"通过邮件模板生成HTML异常,原因={ex.Message}");
throw ex;
}
return result;
}
#endregion
#region 通过邮件模板生成HTML
///
/// 通过邮件模板生成HTML
///
/// BC任务详情
/// 订舱OP详情
/// 当前租户全称
/// 返回生成的HTML
public async Task GenerateSendEmailHtmlAmendment(TaskBCInfo taskBCInfo, SysUser opUserInfo, string tenantName)
{
string result = string.Empty;
/*
1、加载模板文件,读取HTML
2、读取main、conta的tr行,替换业务数据
3、返回HTML的文本信息。
*/
try
{
var basePath = AppSetting.app(new string[] { "EmailTemplate", "BasePath" });
var relativePath = AppSetting.app(new string[] { "EmailTemplate", "RelativePath" });
string dirAbs = string.Empty;
if (string.IsNullOrEmpty(basePath))
{
dirAbs = Path.Combine(_environment.WebRootPath ?? "", relativePath);
}
else
{
dirAbs = Path.Combine(basePath, relativePath);
}
string templatePath = $"{dirAbs}\\BCModifyEmailTemplate.html";
string baseHtml = File.ReadAllText(templatePath);
if (string.IsNullOrWhiteSpace(baseHtml))
throw new Exception($"读取邮件模板失败");
List compareList = GetCompareResult(taskBCInfo.TASK_ID).GetAwaiter().GetResult().Data;
if (taskBCInfo.CARRIERID.Equals("CMA", StringComparison.OrdinalIgnoreCase))
{
compareList = new List();
}
else
{
if (compareList == null || compareList.Count == 0)
throw new Exception($"读取变更数据失败,没有差异数据");
}
if (opUserInfo != null && !string.IsNullOrWhiteSpace(opUserInfo.UserName))
{
baseHtml = baseHtml.Replace("#opname#", opUserInfo.UserName);
}
else
{
baseHtml = baseHtml.Replace("#opname#", "操作");
}
if (opUserInfo != null && !string.IsNullOrWhiteSpace(opUserInfo.Email))
{
baseHtml = baseHtml.Replace("#opemail#", opUserInfo.Email);
}
else
{
baseHtml = baseHtml.Replace("#opemail#", "");
}
if (opUserInfo != null && !string.IsNullOrWhiteSpace(opUserInfo.Phone))
{
baseHtml = baseHtml.Replace("#optel#", opUserInfo.Phone);
}
else if (opUserInfo != null && !string.IsNullOrWhiteSpace(opUserInfo.Tel))
{
baseHtml = baseHtml.Replace("#optel#", opUserInfo.Tel);
}
else
{
baseHtml = baseHtml.Replace("#optel#", "");
}
HtmlDocument html = new HtmlDocument();
html.LoadHtml(baseHtml);
HtmlNode baseTable = html.DocumentNode.SelectNodes("//table[@class='base-table']").FirstOrDefault();
if (baseTable == null)
throw new Exception($"读取邮件模板格式错误,定位base-table失败");
var baseTrList = baseTable.SelectNodes(".//tr");
foreach (var baseTr in baseTrList)
{
var tdList = baseTr.SelectNodes(".//td");
foreach (var baseTd in tdList)
{
if (baseTd.Attributes["class"].Value == "billno-val")
{
baseTd.InnerHtml = taskBCInfo.MBL_NO;
}
else if (baseTd.Attributes["class"].Value == "takebillno-val")
{
baseTd.InnerHtml = taskBCInfo.MBL_NO;
}
else if (baseTd.Attributes["class"].Value == "pol-val")
{
baseTd.InnerHtml = taskBCInfo.PLACERECEIPT;
}
else if (baseTd.Attributes["class"].Value == "pod-val")
{
baseTd.InnerHtml = taskBCInfo.PLACEDELIVERY;
}
else if (baseTd.Attributes["class"].Value == "ctn-val")
{
baseTd.InnerHtml = taskBCInfo.CTN_STAT;
}
/*
else if (baseTd.Attributes["class"].Value == "etd-val")
{
if (taskBCInfo.ETD.HasValue)
{
baseTd.InnerHtml = taskBCInfo.ETD.Value.ToString("yyyy-MM-dd");
}
}
else if (baseTd.Attributes["class"].Value == "eta-val")
{
if (taskBCInfo.ETA.HasValue)
{
baseTd.InnerHtml = taskBCInfo.ETA.Value.ToString("yyyy-MM-dd");
}
}*/
}
}
bool isOnlyChangeOne = false;
List nameList = new List();
//船名
if (compareList.Any(x => x.FieldCode.Equals("vessel", StringComparison.OrdinalIgnoreCase)))
{
var name = compareList.FirstOrDefault(x => x.FieldCode.Equals("vessel", StringComparison.OrdinalIgnoreCase)).TargetVal;
baseTable.AppendChild(HtmlNode.CreateNode("船名 变更为: | " + name + " |
"));
nameList.Add("船名");
}
//航次号
if (compareList.Any(x => x.FieldCode.Equals("voyNo", StringComparison.OrdinalIgnoreCase)))
{
var name = compareList.FirstOrDefault(x => x.FieldCode.Equals("voyNo", StringComparison.OrdinalIgnoreCase)).TargetVal;
baseTable.AppendChild(HtmlNode.CreateNode("航次号 变更为: | " + name + " |
"));
nameList.Add("航次号");
}
//ETD
if (compareList.Any(x => x.FieldCode.Equals("ETD", StringComparison.OrdinalIgnoreCase)))
{
var name = compareList.FirstOrDefault(x => x.FieldCode.Equals("ETD", StringComparison.OrdinalIgnoreCase)).TargetVal;
baseTable.AppendChild(HtmlNode.CreateNode("ETD 变更为: | " + name + " |
"));
nameList.Add("ETD");
}
//ETA
if (compareList.Any(x => x.FieldCode.Equals("ETA", StringComparison.OrdinalIgnoreCase)))
{
var name = compareList.FirstOrDefault(x => x.FieldCode.Equals("ETA", StringComparison.OrdinalIgnoreCase)).TargetVal;
baseTable.AppendChild(HtmlNode.CreateNode("ETA 变更为: | " + name + " |
"));
nameList.Add("ETA");
}
//CustomSICutDate 客户样单截止日期
if (compareList.Any(x => x.FieldCode.Equals("CustomSICutDate", StringComparison.OrdinalIgnoreCase)))
{
var name = compareList.FirstOrDefault(x => x.FieldCode.Equals("CustomSICutDate", StringComparison.OrdinalIgnoreCase)).TargetVal;
baseTable.AppendChild(HtmlNode.CreateNode("样单截止日期 变更为: | " + name + " |
"));
nameList.Add("样单截止日期");
}
//CYCutoffTime 截港时间
if (compareList.Any(x => x.FieldCode.Equals("CYCutoffTime", StringComparison.OrdinalIgnoreCase)))
{
var name = compareList.FirstOrDefault(x => x.FieldCode.Equals("CYCutoffTime", StringComparison.OrdinalIgnoreCase)).TargetVal;
baseTable.AppendChild(HtmlNode.CreateNode("截港时间 变更为: | " + name + " |
"));
nameList.Add("截港时间");
}
//ManifestCutDate 舱单截止时间
if (compareList.Any(x => x.FieldCode.Equals("ManifestCutDate", StringComparison.OrdinalIgnoreCase)))
{
var name = compareList.FirstOrDefault(x => x.FieldCode.Equals("ManifestCutDate", StringComparison.OrdinalIgnoreCase)).TargetVal;
baseTable.AppendChild(HtmlNode.CreateNode("舱单截止时间 变更为: | " + name + " |
"));
nameList.Add("舱单截止时间");
}
//VGMCutoffTime MDGF提交截止时间
if (compareList.Any(x => x.FieldCode.Equals("VGMCutoffTime", StringComparison.OrdinalIgnoreCase)))
{
var name = compareList.FirstOrDefault(x => x.FieldCode.Equals("VGMCutoffTime", StringComparison.OrdinalIgnoreCase)).TargetVal;
baseTable.AppendChild(HtmlNode.CreateNode("截VGM时间 变更为: | " + name + " |
"));
nameList.Add("截VGM时间");
}
//MDGFCutDate MDGF提交截止时间
if (compareList.Any(x => x.FieldCode.Equals("MDGFCutDate", StringComparison.OrdinalIgnoreCase)))
{
var name = compareList.FirstOrDefault(x => x.FieldCode.Equals("MDGFCutDate", StringComparison.OrdinalIgnoreCase)).TargetVal;
baseTable.AppendChild(HtmlNode.CreateNode("MDGF提交截止时间 变更为: | " + name + " |
"));
nameList.Add("MDGF提交截止时间");
}
//PlaceReceipt 收货地
if (compareList.Any(x => x.FieldCode.Equals("PlaceReceipt", StringComparison.OrdinalIgnoreCase)))
{
var name = compareList.FirstOrDefault(x => x.FieldCode.Equals("PlaceReceipt", StringComparison.OrdinalIgnoreCase)).TargetVal;
baseTable.AppendChild(HtmlNode.CreateNode("收货地 变更为: | " + name + " |
"));
nameList.Add("收货地");
}
//PlaceDelivery 交货地
if (compareList.Any(x => x.FieldCode.Equals("PlaceDelivery", StringComparison.OrdinalIgnoreCase)))
{
var name = compareList.FirstOrDefault(x => x.FieldCode.Equals("PlaceDelivery", StringComparison.OrdinalIgnoreCase)).TargetVal;
baseTable.AppendChild(HtmlNode.CreateNode("交货地 变更为: | " + name + " |
"));
nameList.Add("交货地");
}
var noreplyTr = html.DocumentNode.SelectNodes("//tr[@class='email-noreply']").FirstOrDefault();
if (noreplyTr != null)
{
var currTd = noreplyTr.SelectNodes(".//td").FirstOrDefault();
if (currTd != null)
{
var currPList = currTd.SelectNodes(".//p");
foreach (var baseP in currPList)
{
if (baseP.Attributes["class"].Value == "notice-comp-val")
{
baseP.InnerHtml = tenantName;
}
else if (baseP.Attributes["class"].Value == "dynamic-val")
{
if (nameList.Count > 0)
{
baseP.InnerHtml = $"请注意{(string.Join("、", nameList.ToArray()))} 变更,请您按相关的更新安排操作,谢谢!";
}
}
}
}
}
result = html.DocumentNode.OuterHtml;
}
catch (Exception ex)
{
Logger.Log(NLog.LogLevel.Info, $"通过邮件模板生成HTML异常,原因={ex.Message}");
throw ex;
}
return result;
}
#endregion
#region 推送邮件
///
/// 推送邮件
///
/// 自定义邮件详情
/// 文件路径
/// 返回回执
private async Task PushEmail(EmailApiUserDefinedDto emailApiUserDefinedDto, string filePath)
{
List emailList = new List();
bool result = false;
string msg = string.Empty;
var emailUrl = db.Queryable().Filter(null, true).Where(x => x.Code == "email_api_url" && x.TenantId == 1288018625843826688).First().Value;
if (emailUrl == null)
throw new Exception("字典未配置 url_set->email_api_url 请联系管理员");
System.IO.FileStream file = new System.IO.FileStream(filePath, FileMode.Open, FileAccess.Read);
int SplitSize = 5242880;//5M分片长度
int index = 1; //序号 第几片
long StartPosition = 5242880 * (index - 1);
long lastLens = file.Length - StartPosition;//真不知道怎么起命了,就这样吧
if (lastLens < 5242880)
{
SplitSize = (int)lastLens;
}
byte[] heByte = new byte[SplitSize];
file.Seek(StartPosition, SeekOrigin.Begin);
//第一个参数是 起始位置
file.Read(heByte, 0, SplitSize);
//第三个参数是 读取长度(剩余长度)
file.Close();
string base64Str = Convert.ToBase64String(heByte);
emailApiUserDefinedDto.Attaches.Add(new AttachesInfo
{
AttachName = Path.GetFileName(filePath).Replace("_MODIFY", ""),
AttachContent = base64Str
});
emailList.Add(emailApiUserDefinedDto);
//string strJoin = System.IO.File.ReadAllText(filePath);
DateTime bDate = DateTime.Now;
string res = string.Empty;
try
{
var jsonBody = JsonConvert.SerializeObject(emailList);
res = RequestHelper.Post(jsonBody, emailUrl);
//res = await emailUrl.SetBody(emailList, "application/json").PostAsync();
}
catch (Exception ex)
{
Logger.Log(NLog.LogLevel.Info, $"发送邮件异常:{ex.Message}");
}
DateTime eDate = DateTime.Now;
TimeSpan ts = eDate.Subtract(bDate);
var timeDiff = ts.TotalMilliseconds;
Logger.Log(NLog.LogLevel.Info, $"邮件上传完成 上传文件大小:{heByte.Length} 用时:{timeDiff}ms.,");
Logger.Log(NLog.LogLevel.Info, $"发送邮件返回:{res}");
if (!string.IsNullOrWhiteSpace(res))
{
//var userResult = await res.Content.ReadAsStringAsync();
var respObj = JsonConvert.DeserializeAnonymousType(res, new
{
Success = false,
Message = string.Empty,
Code = -9999,
});
result = respObj.Success;
msg = respObj.Message;
}
return DataResult.Successed("");
}
#endregion
#region 发送邮件
///
/// 发送邮件
///
/// BC任务主键
/// 是否默认使用用户个人邮箱发送
/// 返回回执
public async Task SendEmail(string taskPKId, bool usePersonalEmailSend = false)
{
return null;
}
#endregion
#region 同步舱位变更
///
/// 同步舱位变更
///
/// BC任务主键
/// 返回回执
public async Task SyncBookingSlotChange(long taskPKId)
{
/*
* Amendment
1、需要先匹配舱位,如果没有舱位不能执行后续的步骤。
2、判断当前租户是否配置了自动转发客户邮件。
3、如果配置了自动转发,需要判断订舱是否已有,没有不能执行自动转发。
4、转发需要提取差异数据,如果没有差异数据也不能转发邮件。
5、默认通过钉钉通知操作收到了变更通知。
* Cancellation
1、需要先匹配舱位,如果没有舱位不能执行后续的步骤。
2、判断当前租户是否配置了自动转发客户邮件。
3、如果配置了自动转发,需要判断订舱是否已有,没有不能执行自动转发。
4、转发需要提取差异数据,如果没有差异数据也不能转发邮件。
*/
try
{
var tenantDb = saasDbService.GetBizDbScopeById(user.TenantId);
//任务不考虑OrgId,这里去掉
tenantDb.QueryFilter.Clear();
var queryList = await tenantDb.Queryable()
.InnerJoin((a, b) => a.Id == b.TASK_ID)
.Where((a, b) => a.Id == taskPKId)
.Select((a, b) => new { Base = a, BC = b })
.ToListAsync();
//任务主键{taskPkId}无法获取业务信息
if (queryList.Count == 0)
throw new Exception(string.Format(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.TaskBaseInfoFromTaskIdNull)), taskPKId));
var paramConfig = configService.GetConfig(CONST_AMENDMENT_DEFAULT_PARAM, long.Parse(user.TenantId), false).GetAwaiter().GetResult()?.Data?.Value;
Logger.Log(NLog.LogLevel.Info, $"taskPKId={taskPKId} 判断是否默认转发邮件 paramConfig={paramConfig}");
var taskBcInfo = queryList.FirstOrDefault().BC;
var taskBaseInfo = queryList.FirstOrDefault().Base;
var orderInfo = seaExportService.Value.SearchOrderInfo(taskBcInfo.MBL_NO).GetAwaiter().GetResult().Data;
if (orderInfo != null && orderInfo.currOrder != null)
{
//更新订舱相关内容
if (!string.IsNullOrWhiteSpace(paramConfig) && paramConfig.Equals("ENABLE", StringComparison.OrdinalIgnoreCase))
{
//如果是拆票需要按照分票明细单个发送邮件
if (orderInfo.splitOrMergeFlag == 1)
{
var splitOrderIds = new List();
splitOrderIds.Add(orderInfo.currOrder.Id);
splitOrderIds.Append(orderInfo.otherOrderList.Select(b => b.Id).ToList());
var bookList = tenantDb.Queryable().Where(b => splitOrderIds.Contains(b.Id)).ToList();
foreach (var seaExportId in splitOrderIds)
{
var currSeaExport = bookList.FirstOrDefault(b => b.Id == seaExportId);
bool saveBookingId = currSeaExport.Id == orderInfo.currOrder.Id;
await GenerateSendEmail(taskBcInfo, taskBaseInfo, orderInfo, currSeaExport, saveBookingId);
}
}
else
{
var currSeaExport = tenantDb.Queryable().First(b => b.Id == orderInfo.currOrder.Id);
//普通和合票都按单票处理
await GenerateSendEmail(taskBcInfo, taskBaseInfo, orderInfo, currSeaExport, true);
}
}
else
{
//这里没有取到订舱信息,终止,并发出邮件通知
Logger.Log(NLog.LogLevel.Info, $"taskPKId={taskPKId} mblno={taskBcInfo.MBL_NO} 当前租户未配置自动转发邮件");
}
}
else
{
//这里没有取到订舱信息,终止,并发出邮件通知
Logger.Log(NLog.LogLevel.Info, $"taskPKId={taskPKId} mblno={taskBcInfo.MBL_NO} 没有找到订单");
}
}
catch (Exception ex)
{
Logger.Log(NLog.LogLevel.Info, $"执行SyncBookingSlotChange时,异常{ex.Message}");
return DataResult.Failed($"执行SyncBookingSlotChange时,异常{ex.Message}");
}
return DataResult.Successed(MultiLanguageConst.DataCreateSuccess);
}
#endregion
///
/// 同步舱位变更(任务自动)
///
/// 上下文
/// 返回回执
public async Task SyncBookingSlotChangeTask(TaskFlowDataContext dataContext)
{
var taskBaseInfo = dataContext.Get(TaskFlowDataNameConst.TaskBCInfo);
if (taskBaseInfo == null)
{
logger.LogInformation($"执行ApiReceiveTask时,未获取到{TaskFlowDataNameConst.TaskBaseInfo}");
}
return await SyncBookingSlotChange(taskBaseInfo.Id);
}
#region 读取BC详情
///
/// 读取BC详情
///
/// 船公司代码
/// BC文件
/// 返回解析详情
public async Task> GetReadBC(string carrierCode, IFormFile file)
{
DateTime nowDate = DateTime.Now;
string msg = string.Empty;
var messageInfo = new
{
Head = new
{
GID = SnowFlakeSingle.Instance.NextId().ToString(),
MessageType = "BOOKING_GAMENDMENT",
SenderId = AppSetting.app(new string[] { "ExcuteRuleService", "RulesEngineSender" }),
SenderName = AppSetting.app(new string[] { "ExcuteRuleService", "RulesEngineSenderName" }),
ReceiverId = "RulesEngine",
ReceiverName = "大简云规则引擎",
Version = "1.0",
RequestDate = nowDate.ToString("yyyy-MM-dd HH:mm:ss"),
RequestAction = "ReadFile",
},
Main = new
{
TenantId = user.TenantId.ToString()
}
};
using (var httpClient = new HttpClient())
{
try
{
using (var reduceAttach = new MultipartFormDataContent())
{
var dataContent = new ByteArrayContent(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(messageInfo)));
dataContent.Headers.ContentDisposition = new ContentDispositionHeaderValue($"form-data")
{
Name = "jsonData"
};
reduceAttach.Add(dataContent);
#region 文件参数
if (file != null)
{
var Content = new ByteArrayContent(file.ToByteArray());
Content.Headers.Add("Content-Type", "application/json");
reduceAttach.Add(Content, "file", HttpUtility.UrlEncode(file.FileName));
}
#endregion
var url = string.Empty;
if (carrierCode.Equals("MSK", StringComparison.OrdinalIgnoreCase))
url = bcMSKReadUrl;
if (carrierCode.Equals("CMA", StringComparison.OrdinalIgnoreCase))
url = bcCMAReadUrl;
//请求
var response = httpClient.PostAsync(url, reduceAttach).Result;
string result = response.Content.ReadAsStringAsync().Result;
var model = JsonConvert.DeserializeObject(result);
if (model != null && model.succ)
{
var bcInfo = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(model.extra));
return DataResult.Success(bcInfo);
}
else
{
msg = model.msg;
}
}
}
catch (Exception ex)
{
Logger.Log(NLog.LogLevel.Info, "请求BC读取详情异常,原因:{error}", ex.Message);
msg = $"请求BC读取详情异常,原因:{ex.Message}";
}
return DataResult.Failed(msg);
}
}
#endregion
#region 读取BC擦写后文件流
///
/// 读取BC擦写后文件流
///
/// 船公司代码
/// BC文件
/// 返回解析详情
public async Task> GetModifyBCFile(string carrierCode, IFormFile file)
{
byte[] bytes;
var result = string.Empty;
using (var httpClient = new HttpClient())
{
try
{
using (var reduceAttach = new MultipartFormDataContent())
{
var dataContent = new ByteArrayContent(Encoding.UTF8.GetBytes(""));
dataContent.Headers.ContentDisposition = new ContentDispositionHeaderValue($"form-data")
{
Name = "jsonData"
};
reduceAttach.Add(dataContent);
#region 文件参数
if (file != null)
{
var Content = new ByteArrayContent(file.ToByteArray());
Content.Headers.Add("Content-Type", "application/json");
reduceAttach.Add(Content, "file", HttpUtility.UrlEncode(file.FileName));
}
#endregion
//请求
var response = httpClient.PostAsync(bcMSKModifyFileUrl, reduceAttach).Result;
bytes = response.Content.ReadAsByteArrayAsync().GetAwaiter().GetResult();
return DataResult.Success(bytes);
}
}
catch (Exception ex)
{
Logger.Log(NLog.LogLevel.Info, "请求自动变更文件内容异常,原因:{error}", ex.Message);
result = $"请求自动变更文件内容异常,原因:{ex.Message}";
}
}
return DataResult.Failed(result);
}
#endregion
public async Task UploadBcThenRunTask([Required] string carrierCode, [Required] IFormFile file)
{
/*
解析BC附件,生成BC任务
生成擦写后的文件
保存文件和擦写后的文件到硬盘
保存任务对象
文件信息存库
触发BC任务
*/
//ArgumentNullException.ThrowIfNullOrWhiteSpace(carrierCode, nameof(carrierCode));
//ArgumentNullException.ThrowIfNull(file, nameof(file));
//ArgumentNullException.ThrowIfNull(taskBaseId, nameof(taskBaseId));
string batchNo = Guid.NewGuid().ToString();
logger.LogInformation("批次={no} 接收到上传BC请求", batchNo);
var parserBcInfo = await GetReadBC(carrierCode, file);
if (!parserBcInfo.Succeeded || parserBcInfo.Data == null)
{
return DataResult.Failed(parserBcInfo.Message);
}
var taskBcInfo = parserBcInfo.Adapt();
var taskInfo = new TaskBaseInfo
{
Id = SnowFlakeSingle.Instance.NextId(),
STATUS = TaskStatusEnum.Create.ToString(),
STATUS_NAME = TaskStatusEnum.Create.EnumDescription(),
IS_EXCEPT = 0,
IS_COMPLETE = 0,
MBL_NO = taskBcInfo.MBL_NO,
TASK_TYPE = TaskBaseTypeEnum.BC.ToString(),
//TASK_BASE_TYPE = info.Main.TaskType.ToString(),
//CARRIER_ID = info.Main.CarrierId?.Trim(),
//IS_PUBLIC = string.IsNullOrWhiteSpace(info.Main.TaskUserId) ? 1 : 0,
IS_PUBLIC = 1,
//BOOK_ORDER_NO = info.Main.BookingOrderNo,
//OUT_BUSI_NO = $"{info.Head.SenderId}_{info.Head.GID}",
TASK_TITLE = $"手动上传-BC {taskBcInfo.VESSEL}/{taskBcInfo.VOYNO} ETD:{taskBcInfo.ETD} BLNo:{taskBcInfo.MBL_NO}",
//TASK_DESP = info.Main.TaskDesp,
TASK_SOURCE = "ManualUploadBC",
TASK_SOURCE_NAME = "手动上传BC",
VESSEL_VOYNO = $"{taskBcInfo.VESSEL}/{taskBcInfo.VOYNO}"?.Trim(),
CONTA_INFO = taskBcInfo.CTN_STAT,
TASK_REQ_USERNAME = user.UserName,
YARD_NAME = taskBcInfo.YARD,
ETD = taskBcInfo.ETD,
//CUSTOMER_ID = ,
//CUSTOMER_NAME = ,
BATCH_STATIC = batchNo,
//DJYUserId = info.Head.DJYUserId,
//OUT_BS_NO = ,
CreateTime = DateTime.Now,
};
taskInfo.TASK_DESP = taskInfo.TASK_TITLE;
if (Enum.TryParse(typeof(TaskBaseTypeEnum), taskInfo.TASK_TYPE, out object? taskTypeTemp))
{
taskInfo.TASK_TYPE_NAME = ((TaskBaseTypeEnum)taskTypeTemp).EnumDescription();
}
//// 如果船公司主键不为空,则直接保存船公司主键、Code、Name等信息
//if (info.Main.CarrierPK != null)
//{
// taskInfo.CARRIER_ID = info.Main.CarrierPK;
// taskInfo.CARRIER_CODE = info.Main.CarrierId;
// taskInfo.CARRIER_NAME = info.Main.CarrierName;
//}
//// 如果船公司主键为空,但是Code不为空,则通过映射查出船公司信息并保存
//else if (!string.IsNullOrEmpty(info.Main.CarrierId))
//{
// // 船公司转换
// var allMapCarrierList = (await mappingCarrierService.GetAllList())?.Data ?? new List();
// MappingCarrierRes? carrierInfo = allMapCarrierList.Where(t => t.MapCode.Equals(info.Main.CarrierId, StringComparison.OrdinalIgnoreCase) && t.Module == MappingModuleConst.CONST_MAPPING_CARRIER_MODULE).FirstOrDefault();
// if (carrierInfo != null)
// {
// taskInfo.CARRIER_ID = carrierInfo.LinkId;
// taskInfo.CARRIER_CODE = carrierInfo.MapCode;
// taskInfo.CARRIER_NAME = carrierInfo.MapName;
// }
//}
//// 人员字段说明:
//// TaskBaseInfo.CreateBy 创建人:谁创建的,只有一个人(可能是某个租户的管理员,因为任务可以由外部(邮件)创建,无法为每个人创建接口授权信息)
//// TaskBaseInfo.TASK_REQ_USERID 制单人:只有一个人,使用任务创建报文中传入的TaskUserId
//// TaskBaseAllocation.UserId 任务关系:任务属于谁,谁能够查看并处理,可能是多个人(可能是多个人一起处理);取值优先级:info.Main.RecvUserInfoList>关联订单
//// TaskBaseInfo.RealUserId 实际操作人:谁实际处理的,只有一个人(但是工作流过来的任务会由多个人处理)
//// 创建人
//taskInfo.CreateBy = long.Parse(user.UserId);
//taskInfo.CreateUserName = user.UserName;
//// 制单人
//long taskReqUserId = 0;
//if (!string.IsNullOrWhiteSpace(info.Main.TaskUserId))
//{
// if (long.TryParse(info.Main.TaskUserId, out taskReqUserId))
// {
// taskInfo.TASK_REQ_USERID = taskReqUserId;
// taskInfo.TASK_REQ_USERNAME = info.Main.TaskUserName;
// }
// var ctnCodeList = (await codeCtnService.GetAllList()).Data ?? new List();
// var ctnList = info.Main.BCInfo.CtnList.Select(ctn =>
// {
// var bcCtnInfo = ctn.Adapt();
// bcCtnInfo.Id = SnowFlakeSingle.Instance.NextId();
// bcCtnInfo.P_ID = bcInfo.Id;
// if (string.IsNullOrEmpty(bcCtnInfo.CTNCODE))
// {
// var ctnCode = ctnCodeList.FirstOrDefault(a => !string.IsNullOrWhiteSpace(a.CtnName) && a.CtnName.Equals(bcCtnInfo.CTNALL, StringComparison.OrdinalIgnoreCase));
// bcCtnInfo.CTNCODE = ctnCode != null ? ctnCode.EdiCode : "";
// }
// bcInfo.CreateBy = taskInfo.CreateBy;
// bcInfo.CreateTime = taskInfo.CreateTime;
// return bcCtnInfo;
// }).ToList();
// // 保存BC文件
// string bcFileName = file.FileName;
// var bcFileBytes = file.ToByteArray();
// var bcNoExtensionFileName = Path.GetFileNameWithoutExtension(file.FileName);
// var bcFileFullName = await SaveFile(taskBaseId.ToString()!,
// bcFileBytes,
// batchNo,
// bcNoExtensionFileName,
// GetFileType(file.FileName),
// "bcfiles");
// // 保存BC擦写文件
// string bcNotifyFileName = file.FileName + "_MODIFY";
// var bcNotifyFileBytes = await GetModifyBCFile(carrierCode, file);
// if (!bcNotifyFileBytes.Succeeded || bcNotifyFileBytes.Data == null || bcNotifyFileBytes.Data.Length == 0)
// {
// return DataResult.Failed(bcNotifyFileBytes.Message);
// }
// var bcNotifyNoExtensionFileName = Path.GetFileNameWithoutExtension(bcNotifyFileName);
// var bcNotifyFileFullName = await SaveFile(taskBaseId.ToString()!,
// bcNotifyFileBytes.Data,
// batchNo,
// bcNotifyNoExtensionFileName,
// GetFileType(bcNotifyFileName),
// "bcnoticefiles");
// // 解析BC附件,生成BC任务,任务对象存库,文件信息存库
return default;
}
}
}