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