|
|
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.Dtos.TaskInteraction;
|
|
|
using DS.WMS.Core.Op.EDI;
|
|
|
using DS.WMS.Core.Op.Entity;
|
|
|
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.Method.TaskInteraction;
|
|
|
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.AspNetCore.Mvc;
|
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
|
using Microsoft.Extensions.Logging;
|
|
|
using Newtonsoft.Json;
|
|
|
using NLog;
|
|
|
using NPOI.SS.Formula.Functions;
|
|
|
using SqlSugar;
|
|
|
using System.Collections.Specialized;
|
|
|
using System.Net.Http.Headers;
|
|
|
using System.Text;
|
|
|
using System.Text.RegularExpressions;
|
|
|
using System.Web;
|
|
|
|
|
|
namespace DS.WMS.Core.TaskPlat.Method
|
|
|
{
|
|
|
/// <summary>
|
|
|
/// 任务台-BC子任务
|
|
|
/// </summary>
|
|
|
public class TaskManageBCService : TaskManageBaseService<TaskManageBCService>, ITaskManageBCService
|
|
|
{
|
|
|
// 实例化时构建
|
|
|
private readonly ISqlSugarClient db;
|
|
|
private readonly IWebHostEnvironment _environment;
|
|
|
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 ICodePortService _codePortService;
|
|
|
private readonly IMappingPortService _mappingPortService;
|
|
|
private readonly ICodeCountryService _codeCountryService;
|
|
|
private readonly ICommonService _commonService;
|
|
|
|
|
|
private readonly string bcCompareUrl;
|
|
|
private readonly string bcMSKReadUrl;
|
|
|
private readonly string bcMSKModifyFileUrl;
|
|
|
private readonly string bcCMAReadUrl;
|
|
|
|
|
|
// 按需构建
|
|
|
private Lazy<IBookingSlotService> bookingSlotService;
|
|
|
private Lazy<ISeaExportService> seaExportService;
|
|
|
private Lazy<ISeaExportCommonService> seaExportCommonService;
|
|
|
private Lazy<IDjyServiceStatusService> djyServiceStatusService;
|
|
|
private Lazy<ITaskAllocationService> taskAllocationService;
|
|
|
private Lazy<ICodeVesselService> codeVesselService;
|
|
|
private Lazy<ITaskMailService> _taskMailService;
|
|
|
private Lazy<ITaskLogService> _logService;
|
|
|
private Lazy<ISysFileService> _sysFileService;
|
|
|
|
|
|
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<TaskManageBCService> logger,
|
|
|
ISaasDbService saasDbService,
|
|
|
IServiceProvider serviceProvider,
|
|
|
IWebHostEnvironment environment,
|
|
|
IConfigService configService,
|
|
|
IClientInfoService clientInfoService,
|
|
|
IMappingCarrierService mappingCarrierService,
|
|
|
IOpFileService opFileService,
|
|
|
ICodeCtnService codeCtnService,
|
|
|
IUserService userService,
|
|
|
IUserEmailService userEmailService,
|
|
|
ICodePortService codePortService,
|
|
|
IMappingPortService mappingPortService,
|
|
|
ICodeCountryService codeCountryService,
|
|
|
ICommonService commonService)
|
|
|
: base(user, logger, saasDbService, serviceProvider, environment)
|
|
|
{
|
|
|
_userService = userService;
|
|
|
_userEmailService = userEmailService;
|
|
|
_environment = environment;
|
|
|
_configService = configService;
|
|
|
_clientInfoService = clientInfoService;
|
|
|
_mappingCarrierService = mappingCarrierService;
|
|
|
_opFileService = opFileService;
|
|
|
_codeCtnService = codeCtnService;
|
|
|
_codePortService = codePortService;
|
|
|
_mappingPortService = mappingPortService;
|
|
|
_commonService = commonService;
|
|
|
|
|
|
db = serviceProvider.GetRequiredService<ISqlSugarClient>();
|
|
|
|
|
|
bookingSlotService = new Lazy<IBookingSlotService>(serviceProvider.GetRequiredService<IBookingSlotService>);
|
|
|
seaExportService = new Lazy<ISeaExportService>(serviceProvider.GetRequiredService<ISeaExportService>);
|
|
|
djyServiceStatusService = new Lazy<IDjyServiceStatusService>(serviceProvider.GetRequiredService<IDjyServiceStatusService>);
|
|
|
taskAllocationService = new Lazy<ITaskAllocationService>(serviceProvider.GetRequiredService<ITaskAllocationService>);
|
|
|
seaExportCommonService = new Lazy<ISeaExportCommonService>(serviceProvider.GetRequiredService<ISeaExportCommonService>);
|
|
|
codeVesselService = new Lazy<ICodeVesselService>(serviceProvider.GetRequiredService<ICodeVesselService>);
|
|
|
_taskMailService = new Lazy<ITaskMailService>(serviceProvider.GetRequiredService<ITaskMailService>);
|
|
|
_logService = new Lazy<ITaskLogService>(serviceProvider.GetRequiredService<ITaskLogService>);
|
|
|
_sysFileService = new Lazy<ISysFileService>(serviceProvider.GetRequiredService<ISysFileService>);
|
|
|
|
|
|
tenantDb = saasDbService.GetBizDbScopeById(user.TenantId);
|
|
|
tenantDb.QueryFilter.Clear<IOrgId>();
|
|
|
|
|
|
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" });
|
|
|
_codeCountryService = codeCountryService;
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 通过任务信息(BC)生成订舱或舱位
|
|
|
/// </summary>
|
|
|
/// <param name="model">生成订舱或者舱位请求</param>
|
|
|
/// <returns>返回回执</returns>
|
|
|
public async Task<DataResult<TaskManageOrderResultDto>> 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<IOrgId>();
|
|
|
|
|
|
var bcTaskInfo = await tenantDb.Queryable<TaskBaseInfo>().Where(u => u.Id == model.BCTaskId).FirstAsync();
|
|
|
if (bcTaskInfo == null)
|
|
|
{
|
|
|
throw new Exception($"任务主键{model.BCTaskId}无法获取业务信息");
|
|
|
}
|
|
|
|
|
|
var bcOrder = await tenantDb.Queryable<TaskBCInfo>().Where(a => a.TASK_ID == bcTaskInfo.Id).FirstAsync();
|
|
|
|
|
|
if (bcOrder == null)
|
|
|
throw new Exception($"任务主键{model.BCTaskId}无法获取BC业务信息");
|
|
|
|
|
|
var bcCtnList = await tenantDb.Queryable<TaskBCCTNInfo>().Where(a => a.P_ID == bcOrder.Id).ToListAsync();
|
|
|
|
|
|
var fileList = await tenantDb.Queryable<TaskFileInfo>().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<IBookingSlotService>();
|
|
|
//}
|
|
|
|
|
|
//推送订舱订单
|
|
|
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<BookingSlotBaseWithCtnDto> slots = new List<BookingSlotBaseWithCtnDto>();
|
|
|
|
|
|
//检索舱位信息
|
|
|
|
|
|
var slotInfo = (await bookingSlotService.Value.Detail(bookingSlot.Id)).Data;
|
|
|
BookingSlotBaseWithCtnDto baseInfo = slotInfo.Adapt<BookingSlotBaseWithCtnDto>();
|
|
|
baseInfo.Id = bookingSlot.Id;
|
|
|
baseInfo.CtnList = slotInfo.CtnList.Adapt<List<BookingSlotCtnDto>>();
|
|
|
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<TaskBCInfo>().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<TaskBCInfo>(bcEntity).UpdateColumns(it => new
|
|
|
{
|
|
|
it.BOOKING_ORDER_ID,
|
|
|
it.BOOKING_SLOT_ID,
|
|
|
it.UpdateTime,
|
|
|
it.UpdateBy,
|
|
|
it.UpdateUserName
|
|
|
|
|
|
}).ExecuteCommandAsync();
|
|
|
|
|
|
var taskEntity = await tenantDb.Queryable<TaskBaseInfo>().FirstAsync(u => u.Id == bcEntity.TASK_ID);
|
|
|
|
|
|
if (taskEntity == null)
|
|
|
{
|
|
|
throw new Exception($"未获取有效任务记录,更新失败");
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//var currBCOrder = await tenantDb.Queryable<TaskBaseInfo>().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<BookingSlotBase>().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<IBookingSlotService>();
|
|
|
//}
|
|
|
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<BookingSlotBaseWithCtnDto> slots = new List<BookingSlotBaseWithCtnDto>();
|
|
|
|
|
|
//检索舱位信息
|
|
|
|
|
|
var slotInfo = (await bookingSlotService.Value.Detail(bookingSlot.Id)).Data;
|
|
|
BookingSlotBaseWithCtnDto baseInfo = slotInfo.Adapt<BookingSlotBaseWithCtnDto>();
|
|
|
baseInfo.Id = bookingSlot.Id;
|
|
|
baseInfo.CtnList = slotInfo.CtnList.Adapt<List<BookingSlotCtnDto>>();
|
|
|
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<TaskBCInfo>().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<TaskBCInfo>(bcEntity).UpdateColumns(it => new
|
|
|
{
|
|
|
it.BOOKING_ORDER_ID,
|
|
|
it.BOOKING_SLOT_ID,
|
|
|
it.UpdateTime,
|
|
|
it.UpdateBy,
|
|
|
it.UpdateUserName
|
|
|
|
|
|
}).ExecuteCommandAsync();
|
|
|
|
|
|
var taskEntity = await tenantDb.Queryable<TaskBaseInfo>().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<TaskBCInfo>().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<TaskBCInfo>(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<BookingSlotBase>().Where(x => x.Id == bookingSlotId).FirstAsync();
|
|
|
if (bookingSlot == null)
|
|
|
{
|
|
|
throw new Exception($"更新订舱订单失败,未找到id为{bookingSlotId}的舱位信息");
|
|
|
}
|
|
|
List<BookingSlotCtn> bookingSlotCtnList = await tenantDb.Queryable<BookingSlotCtn>().Where(x => x.Id == bookingSlotId).ToListAsync();
|
|
|
|
|
|
//推送订舱订单
|
|
|
var bookingOrderId = await UpdateBookingOrder((long)bcOrder.BOOKING_ORDER_ID, bookingSlot, bookingSlotCtnList, model, tenantDb);
|
|
|
|
|
|
var taskEntity = await tenantDb.Queryable<TaskBaseInfo>().FirstAsync(u => u.Id == bcOrder.TASK_ID);
|
|
|
|
|
|
if (taskEntity == null)
|
|
|
{
|
|
|
throw new Exception($"未获取有效任务记录,更新失败");
|
|
|
}
|
|
|
|
|
|
|
|
|
//var currBCOrder = await tenantDb.Queryable<TaskBaseInfo>().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<TaskBaseInfo>().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<TaskManageOrderResultDto>.Success(result);
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
result.succ = false;
|
|
|
result.msg = $"生成订舱或舱位失败,原因:{ex.Message}";
|
|
|
|
|
|
return DataResult<TaskManageOrderResultDto>.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)));
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 通过任务主键获取BC详情
|
|
|
/// </summary>
|
|
|
/// <param name="taskId">BC任务主键</param>
|
|
|
public async Task<DataResult<TaskManageOrderResultDto>> GetInfoByTaskId(long taskId)
|
|
|
{
|
|
|
TaskManageOrderResultDto result = new TaskManageOrderResultDto();
|
|
|
try
|
|
|
{
|
|
|
var tenantDb = saasDbService.GetBizDbScopeById(user.TenantId);
|
|
|
//任务不考虑OrgId,这里去掉
|
|
|
tenantDb.QueryFilter.Clear<IOrgId>();
|
|
|
|
|
|
var taskBase = await tenantDb.Queryable<TaskBaseInfo>().FirstAsync(a => a.Id == taskId);
|
|
|
|
|
|
if (taskBase == null)
|
|
|
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.TaskBaseEmpty)));
|
|
|
|
|
|
var bcOrder = await tenantDb.Queryable<TaskBCInfo>().FirstAsync(a => a.TASK_ID == taskId);
|
|
|
|
|
|
if (bcOrder == null)
|
|
|
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.TaskBCInfoEmpty)));
|
|
|
|
|
|
var bcCtnList = await tenantDb.Queryable<TaskBCCTNInfo>().Where(a => a.P_ID == bcOrder.Id).ToListAsync();
|
|
|
|
|
|
TaskBCShowBaseDto model = bcOrder.Adapt<TaskBCShowBaseDto>();
|
|
|
|
|
|
if (bcCtnList.Count > 0)
|
|
|
model.CtnList = bcCtnList.Adapt<List<TaskBCCTNInfoDto>>();
|
|
|
|
|
|
var fileList = await tenantDb.Queryable<TaskFileInfo>().Where(a => a.TASK_PKID == bcOrder.TASK_ID).ToListAsync();
|
|
|
|
|
|
if (fileList.Count > 0)
|
|
|
model.FileList = fileList.Adapt<List<TaskFileDto>>();
|
|
|
|
|
|
model.taskStatus = taskBase.STATUS;
|
|
|
|
|
|
#region 生成关键信息
|
|
|
model.Keywords = new List<TaskBCShowBaseKeywordDto>();
|
|
|
|
|
|
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<RecvUserInfo>()
|
|
|
//{
|
|
|
// 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<BookingOrderOutput>();
|
|
|
|
|
|
// var ctnList = await _bookingCtnRepository.AsQueryable().
|
|
|
// Where(a => a.BILLID == bkOrder.Id).ToListAsync();
|
|
|
|
|
|
// if (ctnList.Count > 0)
|
|
|
// showBKOrder.ctnInputs = ctnList.Adapt<List<BookingCtnDto>>();
|
|
|
|
|
|
// result.ext2 = showBKOrder;
|
|
|
// }
|
|
|
//}
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
result.succ = false;
|
|
|
result.msg = $"获取BC详情异常,原因:{ex.Message}";
|
|
|
}
|
|
|
|
|
|
return DataResult<TaskManageOrderResultDto>.Success(result);
|
|
|
}
|
|
|
|
|
|
|
|
|
#region 根据BC任务信息生成舱位
|
|
|
/// <summary>
|
|
|
/// 根据BC任务信息,生成舱位(调用的)
|
|
|
/// </summary>
|
|
|
/// <param name="taskBCInfo">BC任务详情</param>
|
|
|
/// <param name="taskBCCtnList">BC任务集装箱列表</param>
|
|
|
/// <param name="taskFileList">BC任务附件列表</param>
|
|
|
/// <returns>返回舱位ID</returns>
|
|
|
private async Task<BookingSlotBase?> GenerateBookingSlotByTaskBcInfo(TaskBCInfo taskBCInfo, List<TaskBCCTNInfo> taskBCCtnList, List<TaskFileInfo> 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<BookingSlotCtnSaveInput>()
|
|
|
},
|
|
|
OpType = "add"
|
|
|
};
|
|
|
if (int.TryParse(taskBCInfo.WEEK_AT, out int _weekat))
|
|
|
{
|
|
|
slotModel.DataObj.WeekAt = _weekat;
|
|
|
}
|
|
|
|
|
|
var ctnCodeList = (await _codeCtnService.GetAllList()).Data ?? new List<Code.Dtos.CodeCtnRes>();
|
|
|
|
|
|
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" });
|
|
|
var relativePath = AppSetting.app(new string[] { "FileSettings", "RelativePath" });
|
|
|
|
|
|
|
|
|
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, relativePath ?? "", 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, relativePath ?? "", 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<TaskBCInfo>().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>(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 更新订舱
|
|
|
/// <summary>
|
|
|
/// 更新订舱
|
|
|
/// </summary>
|
|
|
/// <returns>返回订舱ID</returns>
|
|
|
private async Task<long> UpdateBookingOrder(
|
|
|
//TaskBCInfo taskBCInfo,
|
|
|
//List<TaskBCCtnList> taskBCCtnList,
|
|
|
long bookingOrderId,
|
|
|
BookingSlotBase bookingSlotBase,
|
|
|
List<BookingSlotCtn> bookingSlotCtnList,
|
|
|
BookingOrSlotGenerateDto generateModel,
|
|
|
SqlSugarScopeProvider? tenantDb = null)
|
|
|
{
|
|
|
//long id = 0;
|
|
|
|
|
|
if (tenantDb == null)
|
|
|
{
|
|
|
tenantDb = saasDbService.GetBizDbScopeById(user.TenantId);
|
|
|
}
|
|
|
//任务不考虑OrgId,这里去掉
|
|
|
tenantDb.QueryFilter.Clear<IOrgId>();
|
|
|
|
|
|
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<OpCtnReq>()
|
|
|
};
|
|
|
|
|
|
//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<BusinessOrderContact>()
|
|
|
.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<BusinessOrderContact>(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<BusinessOrderContact>(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 获取当前比对结果
|
|
|
/// <summary>
|
|
|
/// 获取当前比对结果
|
|
|
/// </summary>
|
|
|
/// <param name="taskId">BC任务主键</param>
|
|
|
/// <returns>返回回执</returns>
|
|
|
public async Task<DataResult<List<CompareResultDetailInfo>>> GetCompareResult(long taskId)
|
|
|
{
|
|
|
var tenantDb = saasDbService.GetBizDbScopeById(user.TenantId);
|
|
|
//任务不考虑OrgId,这里去掉
|
|
|
tenantDb.QueryFilter.Clear<IOrgId>();
|
|
|
|
|
|
var queryList = await tenantDb.Queryable<TaskBaseInfo>()
|
|
|
.InnerJoin<TaskBCInfo>((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<List<CompareResultDetailInfo>>.Success(new List<CompareResultDetailInfo>());
|
|
|
}
|
|
|
}
|
|
|
#endregion
|
|
|
|
|
|
/// <summary>
|
|
|
/// 对比BC与海运出口订单(任务台使用)
|
|
|
/// </summary>
|
|
|
public async Task<DataResult<CompareResultInfo>> CompareBcWithSeaExportTask(TaskFlowDataContext dataContext)
|
|
|
{
|
|
|
var taskBcInfo = dataContext.Get<TaskBCInfo?>(TaskFlowDataNameConst.TaskBCInfo) ?? throw new ArgumentException($"缺少参数:{nameof(TaskFlowDataNameConst.TaskBCInfo)}");
|
|
|
var taskBcCtnList = dataContext.Get<List<TaskBCCTNInfo>?>(TaskFlowDataNameConst.TaskBCCtnList) ?? throw new ArgumentException($"缺少参数:{nameof(TaskFlowDataNameConst.TaskBCCtnList)}");
|
|
|
|
|
|
var seaExport = await tenantDb.Queryable<SeaExport>().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,
|
|
|
|
|
|
DischargePortId = x.DischargePortId,
|
|
|
DischargePortCode = x.DischargePortCode,
|
|
|
DischargePort = x.DischargePort,
|
|
|
|
|
|
LoadPortId = x.LoadPortId,
|
|
|
LoadPortCode = x.LoadPortCode,
|
|
|
LoadPort = x.LoadPort,
|
|
|
|
|
|
ReeferQuantity = x.ReeferQuantity,
|
|
|
TemperatureMin = x.TemperatureMin,
|
|
|
TemperatureMax = x.TemperatureMax,
|
|
|
TemperatureSet = x.TemperatureSet,
|
|
|
Humidity = x.Humidity,
|
|
|
}).FirstAsync();
|
|
|
if (seaExport == null)
|
|
|
{
|
|
|
return DataResult<CompareResultInfo>.Failed($"根据订单Id:【{taskBcInfo.BOOKING_ORDER_ID}】未查询到海运出口订单信息");
|
|
|
}
|
|
|
var seaExportCtnList = await tenantDb.Queryable<OpCtn>().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
|
|
|
};
|
|
|
CompareResultInfo result = await CompareBcWithSeaExport(compareDto);
|
|
|
|
|
|
if (result != null && result.ShowDetailList?.Count > 0)
|
|
|
{
|
|
|
// 将对比结果里的“收货地”替换为“装货港”,因为对比接口没有开启“装货港”对比
|
|
|
|
|
|
var c1 = result.ShowDetailList.FirstOrDefault(x => x.FieldCode == "placeReceipt");
|
|
|
if (c1 != null)
|
|
|
{
|
|
|
c1.FieldCode = "portLoad";
|
|
|
c1.FieldName = "装货港";
|
|
|
c1.Msg = c1.Msg.Replace("收货地", "装货港");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
dataContext.Set(TaskFlowDataNameConst.BcCompareWithSeaExportResult, result);
|
|
|
|
|
|
return DataResult<CompareResultInfo>.Success(result);
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 对比BC与海运出口订单
|
|
|
/// </summary>
|
|
|
public async Task<CompareResultInfo> 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(),
|
|
|
PlaceReceipt = taskBcInfo.PORTLOAD_CODE?.Split(',')?.FirstOrDefault()?.Trim(), // 对比接口没开启Portload这个字段,所以用收货地代替
|
|
|
PortDischarge = taskBcInfo.PORTDISCHARGE_CODE?.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(),
|
|
|
PlaceReceipt = seaExport.LoadPortCode?.Split(',')?.FirstOrDefault()?.Trim(), // 对比接口没开启Portload这个字段,所以用收货地代替
|
|
|
PortDischarge = seaExport.DischargePortCode?.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<BusinessCompareDiffRecord>().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<BusinessCompareDiffRecord>(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<BusinessCompareDiffRecord>(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
|
|
|
};
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 通过BC任务匹配订单(任务台使用)(如果订单提单号为空,则更新上提单号)
|
|
|
/// </summary>
|
|
|
public async Task<DataResult<SeaExportRes?>> BcMatchSeaExportTask(TaskFlowDataContext dataContext)
|
|
|
{
|
|
|
var taskBcInfo = dataContext.Get<TaskBCInfo?>(TaskFlowDataNameConst.TaskBCInfo) ?? throw new ArgumentException($"缺少参数:{nameof(TaskFlowDataNameConst.TaskBCInfo)}");
|
|
|
|
|
|
SeaExportRes? seaExport = null;
|
|
|
|
|
|
// 先从数据上下文中取,如果为null,再从库里查询
|
|
|
seaExport = dataContext.Get<SeaExportRes>(TaskFlowDataNameConst.Business);
|
|
|
if (seaExport == null)
|
|
|
{
|
|
|
var result = await BcMatchSeaExport(taskBcInfo);
|
|
|
|
|
|
if (result.Succeeded && result.Data != null && result.Data.Id != 0)
|
|
|
{
|
|
|
dataContext.Set(TaskFlowDataNameConst.Business, (SeaExportRes)result.Data);
|
|
|
seaExport = result.Data;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (seaExport != null)
|
|
|
{
|
|
|
// BC是否匹配到了海运出口订单=>true
|
|
|
dataContext.Set(TaskFlowDataNameConst.BcIsMatchSeaExport, true);
|
|
|
|
|
|
// 订单Id
|
|
|
dataContext.Set(TaskFlowDataNameConst.BusinessId, seaExport.Id);
|
|
|
|
|
|
await tenantDb.Updateable<TaskBCInfo>()
|
|
|
.SetColumns(x => x.BOOKING_ORDER_ID == seaExport.Id)
|
|
|
.Where(x => x.Id == taskBcInfo.Id)
|
|
|
.ExecuteCommandAsync();
|
|
|
|
|
|
await tenantDb.Updateable<TaskBaseInfo>()
|
|
|
.SetColumns(x => x.OUT_BS_NO == seaExport.Id)
|
|
|
.Where(x => x.Id == taskBcInfo.TASK_ID)
|
|
|
.ExecuteCommandAsync();
|
|
|
return DataResult<SeaExportRes?>.Success(seaExport, "订单已匹配");
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
return DataResult<SeaExportRes?>.Failed("匹配订单失败", MultiLanguageConst.BcMatchSeaExportFailed);
|
|
|
}
|
|
|
}
|
|
|
/// <summary>
|
|
|
/// 通过BC任务匹配订单
|
|
|
/// </summary>
|
|
|
private async Task<DataResult<SeaExportRes?>> BcMatchSeaExport(TaskBCInfo taskBcInfo)
|
|
|
{
|
|
|
var queryable = tenantDb.Queryable<SeaExport>();
|
|
|
|
|
|
if (taskBcInfo.BOOKING_ORDER_ID is not (null or 0))
|
|
|
{
|
|
|
queryable.Where(x => x.Id == taskBcInfo.BOOKING_ORDER_ID);
|
|
|
}
|
|
|
else if (!string.IsNullOrWhiteSpace(taskBcInfo.MBL_NO))
|
|
|
{
|
|
|
queryable.Where(x => x.ParentId == 0 && (taskBcInfo.MBL_NO == x.MBLNO || taskBcInfo.MBL_NO == x.BookingNo));
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
return DataResult<SeaExportRes?>.Failed("匹配订单失败", string.Format(MultiLanguageConst.BcMatchSeaExportFailed, ",订单Id及提单号都为空,无法匹配"));
|
|
|
}
|
|
|
List<SeaExport> seaExportList = await queryable.Select(x => new SeaExport()
|
|
|
{
|
|
|
Id = x.Id,
|
|
|
MBLNO = x.MBLNO,
|
|
|
SplitOrMergeFlag = x.SplitOrMergeFlag,
|
|
|
BookingNo = x.BookingNo,
|
|
|
OperatorId = x.OperatorId,
|
|
|
OperatorName = x.OperatorName,
|
|
|
Doc = x.Doc,
|
|
|
DocName = x.DocName,
|
|
|
SaleId = x.SaleId,
|
|
|
Sale = x.Sale,
|
|
|
Vessel = x.Vessel,
|
|
|
VesselId = x.VesselId,
|
|
|
Vessel2N = x.Vessel2N,
|
|
|
VesselId2N = x.VesselId2N,
|
|
|
Voyno = x.Voyno,
|
|
|
Voyno2N = x.Voyno2N,
|
|
|
InnerVoyno = x.InnerVoyno,
|
|
|
CloseDocDate = x.CloseDocDate,
|
|
|
CustomerService = x.CustomerService,
|
|
|
CustomerServiceName = x.CustomerServiceName,
|
|
|
ForeignCustomerService = x.ForeignCustomerService,
|
|
|
ForeignCustomerServiceName = x.ForeignCustomerServiceName
|
|
|
}).ToListAsync();
|
|
|
|
|
|
logger.LogInformation($"通过BC任务匹配订单(任务台使用):根据taskBcInfo.MBL_NO【{taskBcInfo.MBL_NO}】查询订单后,seaExportList结果为:{JsonConvert.SerializeObject(seaExportList)}");
|
|
|
|
|
|
var seaExport = seaExportList.FirstOrDefault();
|
|
|
if (seaExport != null)
|
|
|
{
|
|
|
taskBcInfo.BOOKING_ORDER_ID = seaExport.Id;
|
|
|
|
|
|
var result = seaExport.Adapt<SeaExportRes>();
|
|
|
|
|
|
return DataResult<SeaExportRes?>.Success("匹配订单成功", result, MultiLanguageConst.OperationSuccess);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
return DataResult<SeaExportRes?>.Failed("匹配订单失败", MultiLanguageConst.BcMatchSeaExportFailed);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// BC更新海运出口订单信息
|
|
|
/// </summary>
|
|
|
public async Task<DataResult> BCUpdateOrderInfo(TaskFlowDataContext dataContext)
|
|
|
{
|
|
|
SeaExportRes? seaExportRes = null;
|
|
|
|
|
|
// 先从数据上下文中取,如果为null,再尝试通过订单Id从库里查询
|
|
|
seaExportRes = dataContext.Get<SeaExportRes>(TaskFlowDataNameConst.Business);
|
|
|
if (seaExportRes == null)
|
|
|
{
|
|
|
var businessId = dataContext.Get<long?>(TaskFlowDataNameConst.BusinessId)
|
|
|
?? throw new ArgumentException($"缺少参数:{nameof(TaskFlowDataNameConst.Business)}且{nameof(TaskFlowDataNameConst.Business)}为空");
|
|
|
|
|
|
seaExportRes = await tenantDb.Queryable<SeaExport>().ClearFilter<IOrgId>().Where(x => x.Id == businessId).Select<SeaExportRes>().FirstAsync();
|
|
|
|
|
|
if (seaExportRes == null)
|
|
|
{
|
|
|
throw new ArgumentException($"通过businessId查询订单Id为null");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
var taskBcInfo = dataContext.Get<TaskBCInfo>(TaskFlowDataNameConst.TaskBCInfo) ?? throw new ArgumentException($"缺少参数:{nameof(TaskFlowDataNameConst.TaskBCInfo)}");
|
|
|
|
|
|
var taskBaseInfo = dataContext.Get<TaskBaseInfo>(TaskFlowDataNameConst.TaskBaseInfo) ?? throw new ArgumentException($"缺少参数:{nameof(TaskFlowDataNameConst.TaskBaseInfo)}");
|
|
|
|
|
|
var oldSeaExport = seaExportRes.Adapt<SeaExport>();
|
|
|
var seaExport = seaExportRes.Adapt<SeaExport>();
|
|
|
|
|
|
tenantDb.Tracking(seaExport);
|
|
|
|
|
|
var codeVesselList = await codeVesselService.Value.GetAllList();
|
|
|
|
|
|
if (!string.IsNullOrEmpty(taskBcInfo.MBL_NO) && seaExport.SplitOrMergeFlag == 0)
|
|
|
{
|
|
|
seaExport.MBLNO = taskBcInfo.MBL_NO;
|
|
|
}
|
|
|
if (!string.IsNullOrEmpty(taskBcInfo.VOYNO))
|
|
|
{
|
|
|
seaExport.Voyno = taskBcInfo.VOYNO;
|
|
|
}
|
|
|
if (!string.IsNullOrEmpty(taskBcInfo.CARRIER_VOYNO))
|
|
|
{
|
|
|
seaExport.InnerVoyno = taskBcInfo.CARRIER_VOYNO;
|
|
|
}
|
|
|
if (!string.IsNullOrEmpty(taskBcInfo.VESSEL))
|
|
|
{
|
|
|
long vesselId = 0;
|
|
|
if (codeVesselList.Succeeded && codeVesselList.Data?.Count > 0)
|
|
|
{
|
|
|
vesselId = codeVesselList.Data.FirstOrDefault(x => x.VesselName == taskBcInfo.VESSEL)?.Id ?? 0;
|
|
|
}
|
|
|
|
|
|
seaExport.Vessel = taskBcInfo.VESSEL;
|
|
|
seaExport.VesselId = vesselId;
|
|
|
}
|
|
|
if (!string.IsNullOrEmpty(taskBcInfo.SECOND_VESSEL))
|
|
|
{
|
|
|
long vessel2NId = 0;
|
|
|
if (codeVesselList.Succeeded && codeVesselList.Data?.Count > 0)
|
|
|
{
|
|
|
vessel2NId = codeVesselList.Data.FirstOrDefault(x => x.VesselName == taskBcInfo.SECOND_VESSEL)?.Id ?? 0;
|
|
|
}
|
|
|
seaExport.Vessel2N = taskBcInfo.SECOND_VESSEL;
|
|
|
seaExport.VesselId2N = vessel2NId;
|
|
|
}
|
|
|
if (taskBcInfo.SI_CUT_DATE != null)
|
|
|
{
|
|
|
seaExport.CloseDocDate = taskBcInfo.SI_CUT_DATE;
|
|
|
}
|
|
|
await tenantDb.Updateable(seaExport).ExecuteCommandAsync();
|
|
|
|
|
|
// 记录日志
|
|
|
await seaExportCommonService.Value.SaveSeaExportLogAsync(new SeaExportSaveLog()
|
|
|
{
|
|
|
OperateType = "Update",
|
|
|
OldOrder = oldSeaExport,
|
|
|
NewOrder = seaExport,
|
|
|
SourceCode = taskBaseInfo.TASK_SOURCE,
|
|
|
SourceName = taskBaseInfo.TASK_SOURCE_NAME,
|
|
|
}, tenantDb);
|
|
|
|
|
|
return DataResult.Successed("BC更新订单信息成功");
|
|
|
}
|
|
|
|
|
|
#region 生成并推送邮件
|
|
|
/// <summary>
|
|
|
/// 生成并推送邮件
|
|
|
/// </summary>
|
|
|
/// <param name="taskBCInfo">BC任务详情</param>
|
|
|
/// <param name="bcTaskInfo">主任务详情</param>
|
|
|
/// <param name="orderInfo">检索订舱相关</param>
|
|
|
/// <param name="usePersonalEmailSend">是否默认使用用户个人邮箱发送</param>
|
|
|
/// <returns>返回回执</returns>
|
|
|
private async Task<DataResult> 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<IOrgId>();
|
|
|
|
|
|
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>(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<BusinessOrderContact>()
|
|
|
.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<SysUser>().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<SysUser>().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<TaskFileInfo>().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<TaskFileInfo>().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<TaskFileInfo>().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<AttachesInfo>()
|
|
|
};
|
|
|
|
|
|
//如果配置了租户参数(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
|
|
|
/// <summary>
|
|
|
/// 通过邮件模板生成HTML
|
|
|
/// </summary>
|
|
|
/// <param name="taskBCInfo">BC任务详情</param>
|
|
|
/// <param name="opUserInfo">订舱OP详情</param>
|
|
|
/// <param name="tenantName">当前租户全称</param>
|
|
|
/// <returns>返回生成的HTML</returns>
|
|
|
public async Task<string> 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
|
|
|
/// <summary>
|
|
|
/// 通过邮件模板生成HTML
|
|
|
/// </summary>
|
|
|
/// <param name="taskBCInfo">BC任务详情</param>
|
|
|
/// <param name="opUserInfo">订舱OP详情</param>
|
|
|
/// <param name="tenantName">当前租户全称</param>
|
|
|
/// <returns>返回生成的HTML</returns>
|
|
|
public async Task<string> 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<CompareResultDetailInfo> compareList = GetCompareResult(taskBCInfo.TASK_ID).GetAwaiter().GetResult().Data;
|
|
|
|
|
|
if (taskBCInfo.CARRIERID.Equals("CMA", StringComparison.OrdinalIgnoreCase))
|
|
|
{
|
|
|
compareList = new List<CompareResultDetailInfo>();
|
|
|
}
|
|
|
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<string> nameList = new List<string>();
|
|
|
//船名
|
|
|
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("<tr><td class=\"ctn-label\" width=\"30%\">船名 变更为:</td><td class=\"pod-val\" width=\"160\">" + name + "</td></tr>"));
|
|
|
|
|
|
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("<tr><td class=\"ctn-label\" width=\"30%\">航次号 变更为:</td><td class=\"pod-val\" width=\"160\">" + name + "</td></tr>"));
|
|
|
|
|
|
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("<tr><td class=\"ctn-label\" width=\"30%\">ETD 变更为:</td><td class=\"pod-val\" width=\"160\">" + name + "</td></tr>"));
|
|
|
|
|
|
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("<tr><td class=\"ctn-label\" width=\"30%\">ETA 变更为:</td><td class=\"pod-val\" width=\"160\">" + name + "</td></tr>"));
|
|
|
|
|
|
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("<tr><td class=\"ctn-label\" width=\"30%\">样单截止日期 变更为:</td><td class=\"pod-val\" width=\"160\">" + name + "</td></tr>"));
|
|
|
|
|
|
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("<tr><td class=\"ctn-label\" width=\"30%\">截港时间 变更为:</td><td class=\"pod-val\" width=\"160\">" + name + "</td></tr>"));
|
|
|
|
|
|
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("<tr><td class=\"ctn-label\" width=\"30%\">舱单截止时间 变更为:</td><td class=\"pod-val\" width=\"160\">" + name + "</td></tr>"));
|
|
|
|
|
|
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("<tr><td class=\"ctn-label\" width=\"30%\">截VGM时间 变更为:</td><td class=\"pod-val\" width=\"160\">" + name + "</td></tr>"));
|
|
|
|
|
|
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("<tr><td class=\"ctn-label\" width=\"30%\">MDGF提交截止时间 变更为:</td><td class=\"pod-val\" width=\"160\">" + name + "</td></tr>"));
|
|
|
|
|
|
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("<tr><td class=\"ctn-label\" width=\"20%\">收货地 变更为:</td><td class=\"pod-val\" width=\"160\">" + name + "</td></tr>"));
|
|
|
|
|
|
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("<tr><td class=\"ctn-label\" width=\"20%\">交货地 变更为:</td><td class=\"pod-val\" width=\"160\">" + name + "</td></tr>"));
|
|
|
|
|
|
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 推送邮件
|
|
|
/// <summary>
|
|
|
/// 推送邮件
|
|
|
/// </summary>
|
|
|
/// <param name="emailApiUserDefinedDto">自定义邮件详情</param>
|
|
|
/// <param name="filePath">文件路径</param>
|
|
|
/// <returns>返回回执</returns>
|
|
|
private async Task<DataResult> PushEmail(EmailApiUserDefinedDto emailApiUserDefinedDto, string filePath)
|
|
|
{
|
|
|
List<EmailApiUserDefinedDto> emailList = new List<EmailApiUserDefinedDto>();
|
|
|
|
|
|
bool result = false;
|
|
|
string msg = string.Empty;
|
|
|
|
|
|
var emailUrl = db.Queryable<SysConfig>().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 发送邮件
|
|
|
/// <summary>
|
|
|
/// 发送邮件
|
|
|
/// </summary>
|
|
|
/// <param name="taskPKId">BC任务主键</param>
|
|
|
/// <param name="usePersonalEmailSend">是否默认使用用户个人邮箱发送</param>
|
|
|
/// <returns>返回回执</returns>
|
|
|
public async Task<TaskManageOrderResultDto> SendEmail(string taskPKId, bool usePersonalEmailSend = false)
|
|
|
{
|
|
|
return null;
|
|
|
}
|
|
|
#endregion
|
|
|
|
|
|
#region 同步舱位变更
|
|
|
/// <summary>
|
|
|
/// 同步舱位变更
|
|
|
/// </summary>
|
|
|
/// <param name="taskPKId">BC任务主键</param>
|
|
|
/// <returns>返回回执</returns>
|
|
|
public async Task<DataResult> 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<IOrgId>();
|
|
|
|
|
|
var queryList = await tenantDb.Queryable<TaskBaseInfo>()
|
|
|
.InnerJoin<TaskBCInfo>((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<long>();
|
|
|
|
|
|
splitOrderIds.Add(orderInfo.currOrder.Id);
|
|
|
splitOrderIds.Append(orderInfo.otherOrderList.Select(b => b.Id).ToList());
|
|
|
|
|
|
var bookList = tenantDb.Queryable<SeaExport>().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<SeaExport>().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
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
/// 同步舱位变更(任务自动)
|
|
|
/// </summary>
|
|
|
/// <param name="dataContext">上下文</param>
|
|
|
/// <returns>返回回执</returns>
|
|
|
public async Task<DataResult> SyncBookingSlotChangeTask(TaskFlowDataContext dataContext)
|
|
|
{
|
|
|
var taskBaseInfo = dataContext.Get<TaskBaseInfo?>(TaskFlowDataNameConst.TaskBCInfo);
|
|
|
if (taskBaseInfo == null)
|
|
|
{
|
|
|
logger.LogInformation($"执行ApiReceiveTask时,未获取到{TaskFlowDataNameConst.TaskBaseInfo}");
|
|
|
}
|
|
|
|
|
|
return await SyncBookingSlotChange(taskBaseInfo.Id);
|
|
|
}
|
|
|
|
|
|
#region 读取BC详情
|
|
|
/// <summary>
|
|
|
/// 读取BC详情
|
|
|
/// </summary>
|
|
|
/// <param name="carrierCode">船公司代码</param>
|
|
|
/// <param name="file">BC文件</param>
|
|
|
/// <returns>返回解析详情</returns>
|
|
|
public async Task<DataResult<ParserBCInfoDto>> 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<BCReadResultDto>(result);
|
|
|
|
|
|
if (model != null && model.succ)
|
|
|
{
|
|
|
var bcInfo = JsonConvert.DeserializeObject<ParserBCInfoDto>(JsonConvert.SerializeObject(model.extra));
|
|
|
|
|
|
return DataResult<ParserBCInfoDto>.Success(bcInfo);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
msg = model.msg;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
Logger.Log(NLog.LogLevel.Info, "请求BC读取详情异常,原因:{error}", ex.Message);
|
|
|
|
|
|
msg = $"请求BC读取详情异常,原因:{ex.Message}";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
return DataResult<ParserBCInfoDto>.Failed(msg);
|
|
|
}
|
|
|
}
|
|
|
#endregion
|
|
|
|
|
|
#region 读取BC擦写后文件流
|
|
|
/// <summary>
|
|
|
/// 读取BC擦写后文件流
|
|
|
/// </summary>
|
|
|
/// <param name="carrierCode">船公司代码</param>
|
|
|
/// <param name="file">BC文件</param>
|
|
|
/// <returns>返回解析详情</returns>
|
|
|
public async Task<DataResult<byte[]>> 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<byte[]>.Success(bytes);
|
|
|
}
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
Logger.Log(NLog.LogLevel.Info, "请求自动变更文件内容异常,原因:{error}", ex.Message);
|
|
|
|
|
|
result = $"请求自动变更文件内容异常,原因:{ex.Message}";
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return DataResult<byte[]>.Failed(result);
|
|
|
}
|
|
|
#endregion
|
|
|
|
|
|
/// <summary>
|
|
|
/// 上传BC文件并触发执行BC任务
|
|
|
/// </summary>
|
|
|
/// <param name="carrierCode">船公司代码</param>
|
|
|
/// <param name="taskId">任务主键</param>
|
|
|
/// <param name="file">BC文件</param>
|
|
|
public async Task<DataResult> UploadBcThenRunTask(string carrierCode, long taskId, IFormFile file)
|
|
|
{
|
|
|
//return DataResult.Failed("开发中...", MultiLanguageConst.Operation_Failed);
|
|
|
/*
|
|
|
解析BC文件,生成BC任务
|
|
|
生成Base任务
|
|
|
生成擦写后的文件
|
|
|
保存文件和擦写后的文件到硬盘
|
|
|
保存任务对象
|
|
|
文件信息存库
|
|
|
触发BC任务
|
|
|
*/
|
|
|
|
|
|
ArgumentNullException.ThrowIfNull(file, $"{nameof(file)}:文件不能为空");
|
|
|
|
|
|
string batchNo = Guid.NewGuid().ToString();
|
|
|
|
|
|
logger.LogInformation("批次={no} 接收到上传BC请求", batchNo);
|
|
|
|
|
|
List<string> supportCarrier = ["MSK", "CMA"];
|
|
|
if (!supportCarrier.Contains(carrierCode))
|
|
|
{
|
|
|
return DataResult.Failed(string.Format(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.BCParserNotSupportedCarrier)), carrierCode));
|
|
|
}
|
|
|
|
|
|
// 解析BC附件
|
|
|
var parserBcInfo = await GetReadBC(carrierCode, file);
|
|
|
if (!parserBcInfo.Succeeded || parserBcInfo.Data == null)
|
|
|
{
|
|
|
return DataResult.Failed(parserBcInfo.Message);
|
|
|
}
|
|
|
|
|
|
|
|
|
// 解析出BC任务
|
|
|
var taskBcInfo = parserBcInfo.Data.Adapt<TaskBCInfo>();
|
|
|
|
|
|
taskBcInfo.Id = SnowFlakeSingle.Instance.NextId();
|
|
|
|
|
|
var allPortCodeList = (await _codePortService.GetAllList()).Data ?? [];
|
|
|
|
|
|
// 解析收货地,得到装货港名称及五字码
|
|
|
if (string.IsNullOrWhiteSpace(taskBcInfo.PLACERECEIPT))
|
|
|
{
|
|
|
logger.LogInformation("手动上传BC后,通过收货地城市名称匹配港口信息时,收货地为空");
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
var portEnName = taskBcInfo.PLACERECEIPT.Split(',')[0].Trim();
|
|
|
|
|
|
//这里CMA的收货地全称放在了括号里面
|
|
|
if (taskBcInfo.PLACERECEIPT.Equals("CMA", StringComparison.OrdinalIgnoreCase))
|
|
|
{
|
|
|
taskBcInfo.PLACERECEIPT = taskBcInfo.PLACERECEIPT.Replace("(", "(").Replace(")", ")");
|
|
|
|
|
|
if (taskBcInfo.PLACERECEIPT.IndexOf("(") >= 0)
|
|
|
{
|
|
|
string? currStr = Regex.Match(taskBcInfo.PLACERECEIPT, "(?<=\\().*(?=\\))").Value?.Trim();
|
|
|
if (!string.IsNullOrEmpty(currStr))
|
|
|
{
|
|
|
portEnName = currStr.Split(',')[0].Trim();
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
var portInfo = await PlaceDeliveryToPort(portEnName, allPortCodeList, () => _mappingPortService.GetAllList());
|
|
|
|
|
|
if (!portInfo.Succeeded || portInfo.Data == null)
|
|
|
{
|
|
|
logger.LogInformation($"手动上传BC后,通过收货地城市名称未匹配到港口信息,BC对象主键:{taskBcInfo.Id}");
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
taskBcInfo.PORTLOAD = portInfo.Data.PortName;
|
|
|
taskBcInfo.PORTLOAD_CODE = portInfo.Data.EdiCode;
|
|
|
taskBcInfo.PORTLOAD_ID = portInfo.Data.Id;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 解析交货地,得到为卸货港名称及五字码, 以及国家信息
|
|
|
if (string.IsNullOrWhiteSpace(taskBcInfo.PLACEDELIVERY))
|
|
|
{
|
|
|
logger.LogInformation("手动上传BC后,通过交货地城市名称匹配港口信息时,交货地为空");
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
var portEnName = taskBcInfo.PLACEDELIVERY.Split(',')[0].Trim();
|
|
|
|
|
|
//这里CMA的收货地全称放在了括号里面
|
|
|
if (taskBcInfo.CARRIER?.Equals("CMA", StringComparison.OrdinalIgnoreCase) == true)
|
|
|
{
|
|
|
taskBcInfo.PLACEDELIVERY = taskBcInfo.PLACEDELIVERY.Replace("(", "(").Replace(")", ")");
|
|
|
|
|
|
if (taskBcInfo.PLACEDELIVERY.IndexOf("(") >= 0)
|
|
|
{
|
|
|
string? currStr = Regex.Match(taskBcInfo.PLACEDELIVERY, "(?<=\\().*(?=\\))")?.Value?.Trim();
|
|
|
if (!string.IsNullOrEmpty(currStr))
|
|
|
{
|
|
|
portEnName = currStr.Split(',')[0].Trim();
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
var portInfo = await PlaceDeliveryToPort(portEnName, allPortCodeList, () => _mappingPortService.GetAllList());
|
|
|
|
|
|
if (!portInfo.Succeeded || portInfo.Data == null)
|
|
|
{
|
|
|
logger.LogInformation($"手动上传BC后,通过交货地城市名称未匹配到港口信息,BC对象主键:{taskBcInfo.Id}");
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
taskBcInfo.PORTDISCHARGE = portInfo.Data.PortName;
|
|
|
taskBcInfo.PORTDISCHARGE_CODE = portInfo.Data.EdiCode;
|
|
|
taskBcInfo.PORTDISCHARGE_ID = portInfo.Data.Id;
|
|
|
|
|
|
var allCountryCodeList = (await _codeCountryService.GetAllList()).Data ?? [];
|
|
|
|
|
|
var countryInfo = allCountryCodeList.FirstOrDefault(p => p.Id == portInfo.Data.CountryId || p.CountryName == portInfo.Data.CountryName);
|
|
|
if (countryInfo != null)
|
|
|
{
|
|
|
taskBcInfo.PORTDISCHARGE_COUNTRY = countryInfo.CountryEnName;
|
|
|
taskBcInfo.PORTDISCHARGE_COUNTRY_CODE = countryInfo.CountryCode;
|
|
|
taskBcInfo.PORTDISCHARGE_COUNTRY_ID = countryInfo.Id;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 获取待收BC任务中的订单主键
|
|
|
var waitBcTask = await tenantDb.Queryable<TaskBaseInfo>()
|
|
|
.Where(x => x.Id == taskId)
|
|
|
.Select(x => new
|
|
|
{
|
|
|
x.Id,
|
|
|
x.OUT_BS_NO,
|
|
|
x.STATUS
|
|
|
}).FirstAsync();
|
|
|
if (waitBcTask == null)
|
|
|
{
|
|
|
return DataResult.Failed("未执行:当前任务不存在,请刷新页面");
|
|
|
}
|
|
|
//if (waitBcTask.STATUS == TaskStatusEnum.Complete.ToString())
|
|
|
//{
|
|
|
// return DataResult.Failed("未执行:当前任务状态为已完成,请重新查询");
|
|
|
//}
|
|
|
if (waitBcTask.OUT_BS_NO == null)
|
|
|
{
|
|
|
return DataResult.Failed("未执行:当前任务的业务主键为null");
|
|
|
}
|
|
|
taskBcInfo.BOOKING_ORDER_ID = waitBcTask.OUT_BS_NO;
|
|
|
|
|
|
// 获取订单信息
|
|
|
var seaExport = await BcMatchSeaExport(taskBcInfo);
|
|
|
if (!seaExport.Succeeded || seaExport.Data == null)
|
|
|
{
|
|
|
return DataResult.Failed("未执行:" + seaExport.Message);
|
|
|
}
|
|
|
//if (seaExport.Data.MBLNO != taskBcInfo.MBL_NO && seaExport.Data.BookingNo != taskBcInfo.MBL_NO)
|
|
|
//{
|
|
|
// return DataResult.Failed(string.Format(MultiLanguageConst.GetDescription(MultiLanguageConst.BCMblnoNotMatchSeaexport), seaExport.Data.MBLNO, taskBcInfo.MBL_NO));
|
|
|
//}
|
|
|
|
|
|
TaskFlowDataContext dataContext = new((TaskFlowDataNameConst.Business, seaExport.Data));
|
|
|
|
|
|
var sequence = await _commonService.GetSequenceNextAsync<TaskBaseInfo>(tenantDb, user);
|
|
|
//if (!sequence.Succeeded || sequence.Data is null)
|
|
|
//{
|
|
|
// return await Task.FromResult(DataResult.Failed(sequence.Message, MultiLanguageConst.SequenceSetNotExist));
|
|
|
//}
|
|
|
|
|
|
// 构建Base任务
|
|
|
var taskInfo = new TaskBaseInfo
|
|
|
{
|
|
|
Id = SnowFlakeSingle.Instance.NextId(),
|
|
|
TASK_NO = sequence?.Data ?? "",
|
|
|
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_TYPE_NAME = TaskBaseTypeEnum.BC.EnumDescription(),
|
|
|
//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,
|
|
|
//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,
|
|
|
BATCH_STATIC = batchNo,
|
|
|
//DJYUserId = info.Head.DJYUserId,
|
|
|
CreateTime = DateTime.Now,
|
|
|
CreateBy = long.Parse(user.UserId),
|
|
|
CreateUserName = user.UserName,
|
|
|
|
|
|
OUT_BS_NO = seaExport.Data.Id,
|
|
|
BOOK_ORDER_NO = seaExport.Data.Id.ToString(),
|
|
|
CARRIER_ID = seaExport.Data.CarrierId,
|
|
|
CARRIER_NAME = seaExport.Data.Carrier,
|
|
|
CUSTOMER_ID = seaExport.Data.CustomerId,
|
|
|
CUSTOMER_NAME = seaExport.Data.CustomerName,
|
|
|
};
|
|
|
taskInfo.TASK_DESP = taskInfo.TASK_TITLE;
|
|
|
|
|
|
taskBcInfo.TASK_ID = taskInfo.Id;
|
|
|
|
|
|
// 构建箱信息
|
|
|
var ctnCodeList = (await _codeCtnService.GetAllList()).Data ?? new List<Code.Dtos.CodeCtnRes>();
|
|
|
var ctnList = parserBcInfo.Data.CtnList?.Select(ctn =>
|
|
|
{
|
|
|
var bcCtnInfo = ctn.Adapt<TaskBCCTNInfo>();
|
|
|
bcCtnInfo.Id = SnowFlakeSingle.Instance.NextId();
|
|
|
bcCtnInfo.P_ID = taskBcInfo.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 : "";
|
|
|
}
|
|
|
|
|
|
bcCtnInfo.CreateBy = taskInfo.CreateBy;
|
|
|
bcCtnInfo.CreateTime = taskInfo.CreateTime;
|
|
|
return bcCtnInfo;
|
|
|
}).ToList();
|
|
|
|
|
|
// 获取任务分配关系
|
|
|
TaskFlowDataContext allotDataContext = new TaskFlowDataContext((TaskFlowDataNameConst.Business, seaExport.Data));
|
|
|
var allotUserList = await taskAllocationService.Value.GetAllotUserBySeaExportId(TaskBaseTypeEnum.BC, seaExport.Data.Id, allotDataContext);
|
|
|
List<TaskBaseAllocation> allocationList = [];
|
|
|
if (allotUserList.Succeeded && allotUserList.Data?.Count > 0)
|
|
|
{
|
|
|
var userIdList = allotUserList.Data.Select(x => x.RecvUserId).Distinct().ToList();
|
|
|
var userWithOrgMap = await db.Queryable<SysUser>().Where(x => userIdList.Contains(x.Id)).Select(x => new { x.Id, x.DefaultOrgId }).ToListAsync();
|
|
|
|
|
|
allocationList = allotUserList.Data.Select(x => new TaskBaseAllocation
|
|
|
{
|
|
|
TaskId = taskInfo.Id,
|
|
|
UserId = x.RecvUserId,
|
|
|
UserName = x.RecvUserName,
|
|
|
Status = TaskStatusEnum.Complete.ToString(),
|
|
|
StatusName = TaskStatusEnum.Complete.EnumDescription(),
|
|
|
StatusTime = DateTime.Now,
|
|
|
OrgId = userWithOrgMap.FirstOrDefault(m => m.Id == x.RecvUserId)?.DefaultOrgId ?? 0
|
|
|
}).ToList();
|
|
|
taskInfo.IS_PUBLIC = 0;
|
|
|
}
|
|
|
|
|
|
|
|
|
// 保存BC文件
|
|
|
string bcFileName = file.FileName;
|
|
|
var bcFileBytes = file.ToByteArray();
|
|
|
var bcNoExtensionFileName = Path.GetFileNameWithoutExtension(file.FileName);
|
|
|
var bcFileRelativePath = await SaveFile(taskInfo.Id.ToString()!,
|
|
|
bcFileBytes,
|
|
|
batchNo,
|
|
|
bcNoExtensionFileName,
|
|
|
GetFileType(file.FileName),
|
|
|
"bcfiles");
|
|
|
// 构建BC文件索引信息
|
|
|
var bcFileInfo = new TaskFileInfo
|
|
|
{
|
|
|
Id = SnowFlakeSingle.Instance.NextId(),
|
|
|
TASK_PKID = taskInfo.Id,
|
|
|
CreateBy = taskInfo.CreateBy,
|
|
|
CreateTime = taskInfo.CreateTime,
|
|
|
FILE_PATH = bcFileRelativePath,
|
|
|
FILE_NAME = bcFileName,
|
|
|
FILE_TYPE = Path.GetExtension(bcFileName).ToLower(),
|
|
|
FILE_CATEGORY = TaskFileCategoryEnum.BC.ToString(),
|
|
|
FILE_CATEGORY_NAME = TaskFileCategoryEnum.BC.EnumDescription()
|
|
|
};
|
|
|
|
|
|
// 保存BC擦写文件
|
|
|
string bcNotifyFileName = $"{bcNoExtensionFileName}_MODIFY{Path.GetExtension(bcFileName).ToLower()}";
|
|
|
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 bcNotifyFileRelativePath = await SaveFile(taskInfo.Id.ToString()!,
|
|
|
bcNotifyFileBytes.Data,
|
|
|
batchNo,
|
|
|
bcNotifyNoExtensionFileName,
|
|
|
GetFileType(bcNotifyFileName),
|
|
|
"bcnoticefiles");
|
|
|
// 构建BC文件擦写文件索引信息
|
|
|
var bcNotifyFileInfo = new TaskFileInfo
|
|
|
{
|
|
|
Id = SnowFlakeSingle.Instance.NextId(),
|
|
|
TASK_PKID = taskInfo.Id,
|
|
|
CreateBy = taskInfo.CreateBy,
|
|
|
CreateTime = taskInfo.CreateTime,
|
|
|
FILE_PATH = bcNotifyFileRelativePath,
|
|
|
FILE_NAME = bcNotifyFileName,
|
|
|
FILE_TYPE = Path.GetExtension(bcNotifyFileName).ToLower(),
|
|
|
FILE_CATEGORY = TaskFileCategoryEnum.BC_NOTICE.ToString(),
|
|
|
FILE_CATEGORY_NAME = TaskFileCategoryEnum.BC_NOTICE.EnumDescription()
|
|
|
};
|
|
|
|
|
|
// 用于挂载到订单的文件信息
|
|
|
var orderBcFileInfo = new OpFile
|
|
|
{
|
|
|
FileName = bcFileInfo.FILE_NAME,
|
|
|
FilePath = bcFileInfo.FILE_PATH,
|
|
|
TypeCode = bcFileInfo.FILE_CATEGORY,
|
|
|
TypeName = bcFileInfo.FILE_CATEGORY_NAME,
|
|
|
LinkId = seaExport.Data.Id,
|
|
|
FileSize = bcFileBytes.Length,
|
|
|
FileType = Path.GetExtension(bcFileName),
|
|
|
Extension = Path.GetExtension(bcFileName),
|
|
|
OrgId = user.OrgId
|
|
|
};
|
|
|
var orderBcNotifyFileInfo = new OpFile
|
|
|
{
|
|
|
FileName = bcNotifyFileInfo.FILE_NAME,
|
|
|
FilePath = bcNotifyFileInfo.FILE_PATH,
|
|
|
TypeCode = bcNotifyFileInfo.FILE_CATEGORY,
|
|
|
TypeName = bcNotifyFileInfo.FILE_CATEGORY_NAME,
|
|
|
LinkId = seaExport.Data.Id,
|
|
|
FileSize = bcNotifyFileBytes.Data.Length,
|
|
|
FileType = Path.GetExtension(bcNotifyFileName),
|
|
|
Extension = Path.GetExtension(bcNotifyFileName),
|
|
|
OrgId = user.OrgId
|
|
|
};
|
|
|
|
|
|
|
|
|
// 存库
|
|
|
try
|
|
|
{
|
|
|
await tenantDb.Ado.BeginTranAsync();
|
|
|
|
|
|
await tenantDb.Insertable(taskInfo).ExecuteCommandAsync();
|
|
|
await tenantDb.Insertable(taskBcInfo).ExecuteCommandAsync();
|
|
|
await tenantDb.Insertable(ctnList).ExecuteCommandAsync();
|
|
|
await tenantDb.Insertable(allocationList).ExecuteCommandAsync();
|
|
|
await tenantDb.Insertable(bcFileInfo).ExecuteCommandAsync();
|
|
|
await tenantDb.Insertable(bcNotifyFileInfo).ExecuteCommandAsync();
|
|
|
await tenantDb.Insertable(orderBcFileInfo).ExecuteCommandAsync();
|
|
|
await tenantDb.Insertable(orderBcNotifyFileInfo).ExecuteCommandAsync();
|
|
|
|
|
|
await tenantDb.Ado.CommitTranAsync();
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
await tenantDb.Ado.RollbackTranAsync();
|
|
|
logger.LogError(ex, "手动上传BC时,在存库的过程中发生异常");
|
|
|
throw;
|
|
|
}
|
|
|
|
|
|
var taskService = serviceProvider.GetRequiredService<ITaskService>();
|
|
|
var rlt = await taskService.SetTaskStatusAsync(new TaskUpdateRequest()
|
|
|
{
|
|
|
AutoCreateNext = false,
|
|
|
BusinessId = (long)waitBcTask.OUT_BS_NO,
|
|
|
BusinessType = BusinessType.OceanShippingExport,
|
|
|
TaskStatus = TaskStatusEnum.Complete,
|
|
|
TaskTypeName = TaskBaseTypeEnum.WAIT_BC.ToString()
|
|
|
});
|
|
|
if (!rlt.Succeeded)
|
|
|
{
|
|
|
logger.LogError("手动上传BC:设置收BC任务完成时失败,message:" + rlt.Message);
|
|
|
}
|
|
|
|
|
|
// 触发BC任务,执行自动化操作
|
|
|
TaskManageOrderBCInfo messageBcInfo = taskBcInfo.Adapt<TaskManageOrderBCInfo>();
|
|
|
messageBcInfo.CtnList = ctnList.Adapt<List<TaskManageOrderBCCTNInfo>>();
|
|
|
|
|
|
TaskManageOrderMessageInfo messageInfo = new TaskManageOrderMessageInfo()
|
|
|
{
|
|
|
Main = new TaskManageOrderMessageMainInfo()
|
|
|
{
|
|
|
BCInfo = messageBcInfo,
|
|
|
TaskType = TaskBaseTypeEnum.BC,
|
|
|
TaskBatchNo = batchNo,
|
|
|
},
|
|
|
Head = new TaskManageOrderMessageHeadInfo()
|
|
|
{
|
|
|
RequestAction = "add"
|
|
|
}
|
|
|
};
|
|
|
|
|
|
// 固定
|
|
|
dataContext.Set(TaskFlowDataNameConst.TaskBaseInfo, taskInfo);
|
|
|
dataContext.Set(TaskFlowDataNameConst.TaskManageOrderMessageInfo, messageInfo);
|
|
|
|
|
|
// BC任务特有
|
|
|
dataContext.Set(TaskFlowDataNameConst.BCFileInfo, new DynameFileInfo { FileBytes = file.ToByteArray(), FileName = file.FileName });
|
|
|
dataContext.Set(TaskFlowDataNameConst.BCNotifyFileInfo, new DynameFileInfo { FileBytes = bcFileBytes, FileName = bcNotifyFileName });
|
|
|
dataContext.Set(TaskFlowDataNameConst.TaskBCInfo, taskBcInfo);
|
|
|
dataContext.Set(TaskFlowDataNameConst.TaskBCCtnList, ctnList);
|
|
|
|
|
|
TaskFlowRuner taskFlow = new TaskFlowRuner(tenantDb, serviceProvider);
|
|
|
await taskFlow.Run(TaskBaseTypeEnum.BC, taskInfo.Id, dataContext);
|
|
|
|
|
|
return DataResult.Successed("上传完成,请查看相关任务状态", MultiLanguageConst.UploadBcThenRunTaskSuccess);
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 结束BC任务并创建下一步任务
|
|
|
/// </summary>
|
|
|
/// <param name="dataContext">数据上下文</param>
|
|
|
public async Task<DataResult> BCTaskCompleteThenNext(TaskFlowDataContext dataContext)
|
|
|
{
|
|
|
// 这里获取到的是获取BC任务的基础任务
|
|
|
var taskBaseInfo = dataContext.Get<TaskBaseInfo>(TaskFlowDataNameConst.TaskBaseInfo);
|
|
|
if (taskBaseInfo == null)
|
|
|
{
|
|
|
return DataResult.Failed("未获取到BC任务对象TaskBaseInfo");
|
|
|
}
|
|
|
|
|
|
await SetTaskStatus(taskBaseInfo, TaskStatusEnum.Complete, DateTime.Now);
|
|
|
|
|
|
if (taskBaseInfo.OUT_BS_NO is null or 0)
|
|
|
{
|
|
|
logger.LogError("BCTaskCompleteThenNext:BC任务对象TaskBaseInfo的OUT_BS_NO为空或0");
|
|
|
return DataResult.Failed("任务对象的业务主键为空");
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
var req = new TaskCreationRequest
|
|
|
{
|
|
|
BusinessId = (long)taskBaseInfo.OUT_BS_NO,
|
|
|
BusinessType = BusinessType.OceanShippingExport,
|
|
|
TaskTypeName = TaskBaseTypeEnum.WAIT_SPACE_RELEASE.ToString(),
|
|
|
};
|
|
|
|
|
|
CompareResultInfo? compareResult = dataContext.Get<CompareResultInfo>(TaskFlowDataNameConst.BcCompareWithSeaExportResult);
|
|
|
if (compareResult == null)
|
|
|
{
|
|
|
req.TaskDescription = $"未放舱原因:BC对比结果不存在";
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
if (compareResult.IsExistsDiff)
|
|
|
{
|
|
|
StringBuilder builder = new();
|
|
|
builder.AppendLine("未放舱原因:BC对比订单后存在差异,差异项:");
|
|
|
foreach (var item in compareResult.ShowDetailList)
|
|
|
{
|
|
|
builder.AppendLine($"{item.FieldName}: BC【{item.ReqVal}】订单【{item.TargetVal}】");
|
|
|
}
|
|
|
req.TaskDescription = builder.ToString();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
var taskService = serviceProvider.GetRequiredService<ITaskService>();
|
|
|
var result = await taskService.CreateTaskAsync(req, false);
|
|
|
if (!result.Succeeded)
|
|
|
return DataResult.Failed("创建下一任务时返回错误:" + result.Message, result.MultiCode);
|
|
|
}
|
|
|
return DataResult.Successed("BC任务已完成,并创建下一步任务");
|
|
|
}
|
|
|
|
|
|
|
|
|
#region 发送邮件通知给客户
|
|
|
/// <summary>
|
|
|
/// 发送邮件通知给客户
|
|
|
/// </summary>
|
|
|
/// <param name="taskPKId">起运港未提箱主键</param>
|
|
|
/// <param name="businessTaskMailId">邮件模板主键</param>
|
|
|
/// <returns>返回回执</returns>
|
|
|
public async Task<DataResult<TaskTransferMsgDto>> InnerSendEmailToCustomer(long taskPKId, long businessTaskMailId)
|
|
|
{
|
|
|
/*
|
|
|
1、先匹配订单。这里可能关联的是拆票订单,如果是拆票订单需要所有拆票记录都要发邮件通知)
|
|
|
2、有订单,调取任务规则补全相关人(如果当票已经有了人员表记录 task_base_allocation则不再处理人员)
|
|
|
3、调取发送模板。
|
|
|
4、填充模板数据。
|
|
|
5、发送邮件。
|
|
|
6、成功后置任务为完成状态。
|
|
|
*/
|
|
|
|
|
|
var tenantDb = saasDbService.GetBizDbScopeById(user.TenantId);
|
|
|
|
|
|
var entity = tenantDb.Queryable<TaskBCInfo>().Filter(null, true).First(a => a.TASK_ID == taskPKId);
|
|
|
|
|
|
var baseInfo = tenantDb.Queryable<TaskBaseInfo>().Filter(null, true).First(a => a.Id == taskPKId);
|
|
|
|
|
|
var queryRlt = await seaExportService.Value.SearchOrderInfo(entity.MBL_NO);
|
|
|
|
|
|
if (!queryRlt.Succeeded)
|
|
|
{
|
|
|
logger.LogInformation($"匹配订单信息失败 mblno={entity.MBL_NO},原因:{queryRlt.Message}");
|
|
|
|
|
|
return DataResult<TaskTransferMsgDto>.Failed($"匹配订单信息失败 mblno={entity.MBL_NO},原因:{queryRlt.Message}");
|
|
|
}
|
|
|
var taskInfo = entity.Adapt<TaskPOLContainerNotPickUpShowDto>();
|
|
|
|
|
|
BusinessTaskMail? mailConfig = _taskMailService.Value.GetAsync(businessTaskMailId).GetAwaiter().GetResult().Data;
|
|
|
|
|
|
if (mailConfig == null)
|
|
|
{
|
|
|
await _logService.Value.WriteLogAsync(new Op.Dtos.TaskInteraction.TaskUpdateRequest
|
|
|
{
|
|
|
BusinessId = taskPKId,
|
|
|
BusinessType = BusinessType.OceanShippingExport,
|
|
|
AutoCreateNext = true,
|
|
|
TaskTypeName = TaskBaseTypeEnum.BC_MODIFY.ToString(),
|
|
|
|
|
|
}, $"未能根据任务配置值获取邮件模板设置");
|
|
|
|
|
|
return DataResult<TaskTransferMsgDto>.Failed("未能根据任务配置值获取邮件模板设置");
|
|
|
}
|
|
|
var orderInfo = queryRlt.Data;
|
|
|
|
|
|
logger.LogInformation($"获取订单详情成功 bookid={orderInfo.currOrder.Id}");
|
|
|
|
|
|
DateTime nowDate = DateTime.Now;
|
|
|
|
|
|
List<long> orderIdList = new List<long> { orderInfo.currOrder.Id };
|
|
|
|
|
|
if (orderInfo.otherOrderList != null && orderInfo.otherOrderList.Count > 0)
|
|
|
orderIdList.AddRange(orderInfo.otherOrderList.Select(t => t.Id).ToList());
|
|
|
|
|
|
//如果是拆票需要处理,处理所以分票记录
|
|
|
if (orderInfo.currOrder.SplitOrMergeFlag == 1)
|
|
|
{
|
|
|
bool isHasAlloc = false;
|
|
|
|
|
|
foreach (var id in orderIdList)
|
|
|
{
|
|
|
var taskAllocList = tenantDb.Queryable<TaskBaseAllocation>().Where(a => a.TaskId == taskPKId).ToList();
|
|
|
|
|
|
var searchAllotUserRlt = taskAllocationService.Value.GetAllotUserBySeaExportId(TaskBaseTypeEnum.BC_MODIFY, id, new TaskFlowDataContext()).GetAwaiter().GetResult();
|
|
|
|
|
|
if (searchAllotUserRlt.Succeeded && searchAllotUserRlt.Data?.Count > 0)
|
|
|
{
|
|
|
isHasAlloc = true;
|
|
|
|
|
|
var addUserList = searchAllotUserRlt.Data.GroupJoin(taskAllocList, l => l.RecvUserId, r => r.UserId, (l, r) =>
|
|
|
{
|
|
|
if (r.ToList().Count == 0)
|
|
|
return new { add = true, obl = l };
|
|
|
|
|
|
return new { add = false, obl = l };
|
|
|
}).Where(a => a.add).Select(a => a.obl).ToList();
|
|
|
|
|
|
if (addUserList.Count > 0)
|
|
|
{
|
|
|
var userIdList = addUserList.Select(x => x.RecvUserId).Distinct().ToList();
|
|
|
var userWithOrgMap = await db.Queryable<SysUser>().Where(x => userIdList.Contains(x.Id)).Select(x => new { x.Id, x.DefaultOrgId }).ToListAsync();
|
|
|
|
|
|
//写入
|
|
|
var allotList = new List<TaskBaseAllocation>();
|
|
|
addUserList.ForEach(b =>
|
|
|
{
|
|
|
var alloc = new TaskBaseAllocation
|
|
|
{
|
|
|
Status = baseInfo.STATUS,
|
|
|
StatusName = baseInfo.STATUS_NAME,
|
|
|
TaskId = taskPKId,
|
|
|
StatusTime = nowDate,
|
|
|
UserId = b.RecvUserId,
|
|
|
UserName = b.RecvUserName,
|
|
|
OrgId = userWithOrgMap.FirstOrDefault(m => m.Id == b.RecvUserId)?.DefaultOrgId ?? 0
|
|
|
};
|
|
|
allotList.Add(alloc);
|
|
|
});
|
|
|
await tenantDb.Insertable<TaskBaseAllocation>(allotList).ExecuteCommandAsync();
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (isHasAlloc && baseInfo.IS_PUBLIC == 1)
|
|
|
{
|
|
|
await tenantDb.Updateable<TaskBaseInfo>(baseInfo).UpdateColumns(x => new
|
|
|
{
|
|
|
x.IS_PUBLIC
|
|
|
}).ExecuteCommandAsync();
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
var taskAllocList = tenantDb.Queryable<TaskBaseAllocation>().Where(a => a.TaskId == taskPKId).ToList();
|
|
|
|
|
|
if (taskAllocList.Count == 0)
|
|
|
{
|
|
|
var searchAllotUserRlt = taskAllocationService.Value.GetAllotUserBySeaExportId(TaskBaseTypeEnum.BC_MODIFY, orderInfo.currOrder.Id, new TaskFlowDataContext()).GetAwaiter().GetResult();
|
|
|
|
|
|
if (searchAllotUserRlt.Succeeded && searchAllotUserRlt.Data?.Count > 0)
|
|
|
{
|
|
|
var userIdList = searchAllotUserRlt.Data.Select(x => x.RecvUserId).Distinct().ToList();
|
|
|
var userWithOrgMap = await db.Queryable<SysUser>().Where(x => userIdList.Contains(x.Id)).Select(x => new { x.Id, x.DefaultOrgId }).ToListAsync();
|
|
|
|
|
|
var allotList = new List<TaskBaseAllocation>();
|
|
|
//写入
|
|
|
searchAllotUserRlt.Data.ForEach(b =>
|
|
|
{
|
|
|
var alloc = new TaskBaseAllocation
|
|
|
{
|
|
|
Status = baseInfo.STATUS,
|
|
|
StatusName = baseInfo.STATUS_NAME,
|
|
|
TaskId = taskPKId,
|
|
|
StatusTime = nowDate,
|
|
|
UserId = b.RecvUserId,
|
|
|
UserName = b.RecvUserName,
|
|
|
OrgId = userWithOrgMap.FirstOrDefault(m => m.Id == b.RecvUserId)?.DefaultOrgId ?? 0
|
|
|
};
|
|
|
allotList.Add(alloc);
|
|
|
});
|
|
|
await tenantDb.Insertable<TaskBaseAllocation>(allotList).ExecuteCommandAsync();
|
|
|
|
|
|
if (baseInfo.IS_PUBLIC == 1)
|
|
|
{
|
|
|
baseInfo.IS_PUBLIC = 0;
|
|
|
|
|
|
await tenantDb.Updateable<TaskBaseInfo>(baseInfo).UpdateColumns(x => new
|
|
|
{
|
|
|
x.IS_PUBLIC
|
|
|
}).ExecuteCommandAsync();
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
TaskTransferMsgDto resultDto = new TaskTransferMsgDto
|
|
|
{
|
|
|
ExcuteDate = nowDate,
|
|
|
Detail = new List<TaskTransferMsgDataDto>()
|
|
|
};
|
|
|
|
|
|
TaskBCTransferDto taskBCTransferDto = new TaskBCTransferDto();
|
|
|
|
|
|
Dictionary<long, Tuple<bool, string, string>> dict = new Dictionary<long, Tuple<bool, string, string>>();
|
|
|
|
|
|
foreach (var id in orderIdList)
|
|
|
{
|
|
|
TaskTransferMsgDataDto detail = new TaskTransferMsgDataDto
|
|
|
{
|
|
|
BusinessId = id,
|
|
|
};
|
|
|
|
|
|
var model = new MailTemplateModel<TaskBCTransferDto>(taskBCTransferDto)
|
|
|
{
|
|
|
BusinessId = id,
|
|
|
BusinessType = BusinessType.OceanShippingExport,
|
|
|
};
|
|
|
|
|
|
MailService mailService = new MailService(serviceProvider);
|
|
|
|
|
|
//如果是拆票,需要每票调用生成拆票的BC文件
|
|
|
var result = await mailService.SendAsync(mailConfig, model);
|
|
|
|
|
|
if (!result.Succeeded)
|
|
|
{
|
|
|
await _logService.Value.WriteLogAsync(new Op.Dtos.TaskInteraction.TaskUpdateRequest
|
|
|
{
|
|
|
BusinessId = taskPKId,
|
|
|
BusinessType = BusinessType.OceanShippingExport,
|
|
|
AutoCreateNext = true,
|
|
|
TaskTypeName = TaskBaseTypeEnum.BC_MODIFY.ToString(),
|
|
|
|
|
|
}, result.Message);
|
|
|
|
|
|
//return DataResult.Failed(result.Message);
|
|
|
}
|
|
|
|
|
|
detail.Status = result.Succeeded ? "SUCC" : "FAILURE";
|
|
|
detail.Message = result.Message;
|
|
|
detail.MBlNo = entity.MBL_NO;
|
|
|
|
|
|
resultDto.Detail.Add(detail);
|
|
|
|
|
|
dict.Add(id, new Tuple<bool, string, string>(result.Succeeded, result.Message, entity.MBL_NO));
|
|
|
}
|
|
|
|
|
|
//如果存在失败记录,不能置完成状态
|
|
|
if (!dict.Any(t => !t.Value.Item1))
|
|
|
{
|
|
|
entity.IS_TRANSFER_USER = true;
|
|
|
entity.LST_TRANSFER_USER_DATE = DateTime.Now;
|
|
|
entity.LST_STATUS = "SUCC";
|
|
|
entity.LST_STATUS_NAME = "发送成功";
|
|
|
|
|
|
await tenantDb.Updateable<TaskBCInfo>(entity).UpdateColumns(x => new
|
|
|
{
|
|
|
x.IS_TRANSFER_USER,
|
|
|
x.LST_TRANSFER_USER_DATE,
|
|
|
x.LST_STATUS,
|
|
|
x.LST_STATUS_NAME
|
|
|
}).ExecuteCommandAsync();
|
|
|
|
|
|
//发送完邮件,自动标记任务状态为完成
|
|
|
await SetTaskStatus(taskPKId, TaskStatusEnum.Complete, DateTime.Now, null);
|
|
|
}
|
|
|
|
|
|
return DataResult<TaskTransferMsgDto>.Success(resultDto);
|
|
|
}
|
|
|
#endregion
|
|
|
|
|
|
#region 发送邮件通知给客户(任务自动机调取)
|
|
|
/// <summary>
|
|
|
/// 发送邮件通知给客户(任务自动机调取)
|
|
|
/// </summary>
|
|
|
/// <param name="dataContext">数据上下文</param>
|
|
|
/// <returns>返回回执</returns>
|
|
|
public async Task<DataResult<TaskTransferMsgDto>> SendEmailToCustomerTask(TaskFlowDataContext dataContext)
|
|
|
{
|
|
|
var taskPKId = dataContext.Get<long>(TaskFlowDataNameConst.TaskPKId);
|
|
|
if (taskPKId == 0)
|
|
|
throw new ArgumentException($"缺少参数:{nameof(TaskFlowDataNameConst.TaskPKId)}");
|
|
|
|
|
|
var businessTaskMailId = dataContext.Get<long>($"{nameof(BusinessTaskMail)}.{nameof(BusinessTaskMail.Id)}");
|
|
|
if (businessTaskMailId == 0)
|
|
|
throw new ArgumentException($"缺少参数:{nameof(BusinessTaskMail)}.{nameof(BusinessTaskMail.Id)}");
|
|
|
|
|
|
if (businessTaskMailId == 0)
|
|
|
{
|
|
|
await _logService.Value.WriteLogAsync(new Op.Dtos.TaskInteraction.TaskUpdateRequest
|
|
|
{
|
|
|
BusinessId = taskPKId,
|
|
|
BusinessType = BusinessType.OceanShippingExport,
|
|
|
AutoCreateNext = true,
|
|
|
TaskTypeName = TaskBaseTypeEnum.BC_MODIFY.ToString(),
|
|
|
|
|
|
}, $"缺少参数:{nameof(BusinessTaskMail)}.{nameof(BusinessTaskMail.Id)}");
|
|
|
|
|
|
return DataResult<TaskTransferMsgDto>.Failed($"缺少参数:{nameof(BusinessTaskMail)}.{nameof(BusinessTaskMail.Id)}");
|
|
|
}
|
|
|
|
|
|
return await InnerSendEmailToCustomer(taskPKId, businessTaskMailId);
|
|
|
}
|
|
|
#endregion
|
|
|
|
|
|
#region 手工发送邮件通知给客户
|
|
|
/// <summary>
|
|
|
/// 手工发送邮件通知给客户
|
|
|
/// </summary>
|
|
|
/// <param name="taskPKId">起运港未提箱任务主键</param>
|
|
|
/// <returns>返回回执</returns>
|
|
|
public async Task<DataResult<TaskTransferMsgDto>> ManualSendEmailToCustomer(long taskPKId)
|
|
|
{
|
|
|
var paramConfig = _configService.GetConfig("BookingAmendMSKTransferEmailTemplateID", long.Parse(user.TenantId), false).GetAwaiter().GetResult()?.Data?.Value;
|
|
|
|
|
|
long businessTaskMailId = 0;
|
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(paramConfig))
|
|
|
{
|
|
|
businessTaskMailId = long.Parse(paramConfig);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
return DataResult<TaskTransferMsgDto>.Failed($"缺少系统参数参数:订舱变更自动转发邮件模板ID-BookingAmendMSKTransferEmailTemplateID");
|
|
|
}
|
|
|
|
|
|
return await InnerSendEmailToCustomer(taskPKId, businessTaskMailId);
|
|
|
}
|
|
|
#endregion
|
|
|
|
|
|
#region 重新获取生成BookingAmendment文件
|
|
|
/// <summary>
|
|
|
/// 重新获取生成BookingAmendment文件
|
|
|
/// </summary>
|
|
|
/// <param name="bookingOrder"></param>
|
|
|
/// <param name="ctnList"></param>
|
|
|
/// <param name="origFilePath"></param>
|
|
|
/// <returns></returns>
|
|
|
private async Task<DataResult<string>> ReGenerateBAFile(SeaExport bookingOrder, List<OpCtn> ctnList, string origFilePath)
|
|
|
{
|
|
|
DrawModifyBCConfig mConfig = new DrawModifyBCConfig
|
|
|
{
|
|
|
drawTypeArg = new DrawModifyBCConfigTypeEnum[] { DrawModifyBCConfigTypeEnum.ChangeToSplitBillNo, DrawModifyBCConfigTypeEnum.SplitBC },
|
|
|
origBillNo = bookingOrder.OrderNo,
|
|
|
newBillNo = bookingOrder.MBLNO,
|
|
|
newCtnNum = ctnList.Sum(a => a.CtnNum),
|
|
|
ctnAll = ctnList.FirstOrDefault().CtnAll
|
|
|
};
|
|
|
|
|
|
NameValueCollection modifyPar = new NameValueCollection();
|
|
|
modifyPar.Add("jsonMessage", JsonConvert.SerializeObject(mConfig));
|
|
|
|
|
|
DynameFileInfo dynameFile = null;
|
|
|
|
|
|
var fileName = Path.GetFileName(origFilePath);
|
|
|
|
|
|
var fileBytes = File.ReadAllBytes(origFilePath);
|
|
|
|
|
|
if (fileBytes.Length > 0)
|
|
|
{
|
|
|
dynameFile = new DynameFileInfo
|
|
|
{
|
|
|
FileName = fileName,
|
|
|
FileBytes = fileBytes
|
|
|
};
|
|
|
}
|
|
|
|
|
|
string batchNo = SnowFlakeSingle.Instance.NextId().ToString();
|
|
|
|
|
|
byte[] modifyBytes = ModifyFile(modifyPar, dynameFile).GetAwaiter().GetResult();
|
|
|
|
|
|
var noExtensionFileName = Path.GetFileNameWithoutExtension(fileName);
|
|
|
|
|
|
var fileRlt = await _sysFileService.Value.SaveFileDirect(bookingOrder.Id.ToString(), modifyBytes, batchNo, noExtensionFileName, "bcsplitnoticefiles");
|
|
|
|
|
|
if (fileRlt != null && fileRlt.Data != null && !string.IsNullOrWhiteSpace(fileRlt.Data.Item1))
|
|
|
{
|
|
|
return DataResult<string>.Success(fileRlt.Data.Item1);
|
|
|
}
|
|
|
|
|
|
return DataResult<string>.FailedData(string.Empty);
|
|
|
}
|
|
|
#endregion
|
|
|
|
|
|
#region 请求变更BookingAmendment后的文件
|
|
|
/// <summary>
|
|
|
/// 请求变更BookingAmendment后的文件
|
|
|
/// </summary>
|
|
|
/// <param name="nameValueCollection">请求参数</param>
|
|
|
/// <param name="fileInfo">文件</param>
|
|
|
/// <param name="contentType">请求类型</param>
|
|
|
/// <returns>返回回执</returns>
|
|
|
private async Task<byte[]> ModifyFile(NameValueCollection nameValueCollection, dynamic fileInfo,
|
|
|
string contentType = "application/json")
|
|
|
{
|
|
|
//Stream ms = null;
|
|
|
|
|
|
byte[] bytes;
|
|
|
var result = string.Empty;
|
|
|
|
|
|
using (var httpClient = new HttpClient())
|
|
|
{
|
|
|
try
|
|
|
{
|
|
|
using (var reduceAttach = new MultipartFormDataContent())
|
|
|
{
|
|
|
string[] allKeys = nameValueCollection.AllKeys;
|
|
|
foreach (string key in allKeys)
|
|
|
{
|
|
|
var dataContent = new ByteArrayContent(Encoding.UTF8.GetBytes(nameValueCollection[key]));
|
|
|
|
|
|
dataContent.Headers.ContentDisposition = new ContentDispositionHeaderValue($"form-data")
|
|
|
{
|
|
|
Name = key
|
|
|
};
|
|
|
|
|
|
reduceAttach.Add(dataContent);
|
|
|
}
|
|
|
|
|
|
#region 文件参数
|
|
|
if (fileInfo != null)
|
|
|
{
|
|
|
var Content = new ByteArrayContent(fileInfo.FileBytes);
|
|
|
|
|
|
//Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
|
|
|
//{
|
|
|
// Name = fileInfo.file.ToString(),
|
|
|
// FileName = fileInfo.fileName.ToString(),
|
|
|
|
|
|
//};
|
|
|
|
|
|
Content.Headers.Add("Content-Type", contentType);
|
|
|
|
|
|
reduceAttach.Add(Content, "file", HttpUtility.UrlEncode(fileInfo.FileName.ToString()));
|
|
|
}
|
|
|
#endregion
|
|
|
|
|
|
//httpClient.DefaultRequestHeaders.Add("USER_KEY", App.Configuration["ApiUserKey"]);
|
|
|
//httpClient.DefaultRequestHeaders.Add("USER_SECRET", App.Configuration["ApiUserSecret"]);
|
|
|
//请求
|
|
|
var response = httpClient.PostAsync(AppSetting.app(new string[] { "BookingAmend", "ModifyFileUrl" }), reduceAttach).Result;
|
|
|
bytes = response.Content.ReadAsByteArrayAsync().GetAwaiter().GetResult();
|
|
|
}
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
logger.LogInformation("请求自动变更BookingAmendment文件内容异常,原因:{error}", ex.Message);
|
|
|
|
|
|
throw new Exception($"请求自动变更BookingAmendment文件内容异常,原因:{ex.Message}");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
return bytes;
|
|
|
}
|
|
|
#endregion
|
|
|
}
|
|
|
}
|