using Amazon.Runtime.Internal.Util; using Autofac.Core; using DS.Module.Core; using DS.Module.Core.Extensions; using DS.Module.Core.Helpers; using DS.Module.DjyServiceStatus; using DS.WMS.Core.Code.Entity; using DS.WMS.Core.Info.Entity; using DS.WMS.Core.Invoice.Dtos; using DS.WMS.Core.Map.Entity; using DS.WMS.Core.Op.Dtos; using DS.WMS.Core.Op.EDI; using DS.WMS.Core.Op.Entity; using DS.WMS.Core.Sys.Entity; using LanguageExt; using LanguageExt.Common; using Mapster; using Microsoft.AspNet.SignalR; using Microsoft.AspNetCore.Connections; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore.Metadata; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using NPOI.HSSF.UserModel; using NPOI.OpenXmlFormats.Dml.Diagram; using NPOI.SS.UserModel; using Org.BouncyCastle.Ocsp; using System.Collections.Specialized; using System.Runtime.InteropServices; using System.Text; using System.Text.RegularExpressions; namespace DS.WMS.Core.Op.Method { /// /// 海运出口提箱小票相关接口 /// public partial class SeaExportService { const string CONST_AUTO_SYNC_DONGSHENG_BY_MQ = "AutoSyncBookingOrderToDongshengMQ"; /// /// 打印保函 /// /// /// public async Task PrintShippingOrderLetterPDF(string id) { var tenantDb = saasService.GetBizDbScopeById(user.TenantId); var book = await tenantDb.Queryable().FirstAsync(x => x.Id == long.Parse(id)); if (book == null) { return await Task.FromResult(DataResult.Failed("未找到订舱数据")); } var template = await db.Queryable().FirstAsync(x => x.TemplateCode == "bill_of_letter" && x.CarrierId == book.CarrierId); if (template == null) { return await Task.FromResult(DataResult.Failed("未找到当前船公司保函模板,模板代码:bill_of_letter")); } var url = AppSetting.Configuration["PrintService:LocalPrintUrl"]; if (url.IsNull()) return await Task.FromResult(DataResult.Failed("未配置本地打印地址")); var req = new Module.PrintModule.OpenJsonPrintReq { TemplateId = template.Id, PrintType = "1", JsonDataStr = JsonConvert.SerializeObject(book) }; var token = user.GetToken(); var res = await RequestHelper.PostJosnAsyncByToken(url, req.ToJson(), token); //var result = JsonConvert.DeserializeObject(res); var result = JObject.Parse(res); if (result.GetBooleanValue("succeeded")) { return await Task.FromResult(DataResult.Successed("打印保函成功", result.GetStringValue("data"), MultiLanguageConst.DataQuerySuccess)); } else { return await Task.FromResult(DataResult.Failed(result.GetStringValue("message"))); } } /// /// 打印托书 /// /// /// public async Task PrintShippingOrderPDF(string id) { var tenantDb = saasService.GetBizDbScopeById(user.TenantId); var book = await tenantDb.Queryable().FirstAsync(x => x.Id == long.Parse(id)); if (book == null) { return await Task.FromResult(DataResult.Failed("未找到订舱数据")); } var template = await db.Queryable().FirstAsync(x => x.TemplateCode == "bill_of_lading"); if (template == null) { return await Task.FromResult(DataResult.Failed("未找到托书模板")); } var url = AppSetting.Configuration["PrintService:LocalPrintUrl"]; if (url.IsNull()) return await Task.FromResult(DataResult.Failed("未配置本地打印地址")); var req = new Module.PrintModule.OpenJsonPrintReq { TemplateId = template.Id, PrintType = "1", JsonDataStr = JsonConvert.SerializeObject(book) }; var token = user.GetToken(); var res = await RequestHelper.PostJosnAsyncByToken(url, req.ToJson(),token); //var result = JsonConvert.DeserializeObject(res); var result = JObject.Parse(res); if (result.GetBooleanValue("succeeded")) { return await Task.FromResult(DataResult.Successed("打印托书成功",result.GetStringValue("data"),MultiLanguageConst.DataQuerySuccess)); } else { return await Task.FromResult(DataResult.Failed(result.GetStringValue("message"))); } } /// /// 发送托书 /// /// /// public async Task> SendShippingOrderEmail(SendShippingOrderReq req) { var tenantDb = saasService.GetBizDbScopeById(user.TenantId); var book = await tenantDb.Queryable().FirstAsync(x => x.Id == req.BookingId); if (book == null) { return await Task.FromResult(DataResult.Failed("未找到订舱数据")); } var userMail = await tenantDb.Queryable().FirstAsync(x => x.CreateBy ==long.Parse(user.UserId)); if (userMail == null) { return await Task.FromResult(DataResult.Failed("未配置发件邮箱")); } if (string.IsNullOrEmpty(userMail.SmtpServer) || userMail.SmtpPort == 25) { return await Task.FromResult(DataResult.Failed("请正确配置发件邮箱,且发件不能使用25端口")); } var emailUrl = db.Queryable().Filter(null, true).Where(x => x.Code == "email_api_url" && x.TenantId == 1288018625843826688).First().Value; if (emailUrl == null) { return await Task.FromResult(DataResult.Failed("系统参数未配置email_api_url 请联系管理员")); } //处理附件 var attPostArr = new List(); foreach (var file in req.FileList) { var basePath = AppSetting.app(new string[] { "FileSettings", "BasePath" }); var relativePath = AppSetting.app(new string[] { "FileSettings", "RelativePath" }); var dirAbs = string.Empty; var fileRelaPath = string.Empty; var fileAbsPath = string.Empty; if (string.IsNullOrEmpty(basePath)) { dirAbs = Path.Combine(_environment.WebRootPath, relativePath); } else { dirAbs = Path.Combine(basePath, relativePath); } var fileFullName = Path.Combine(dirAbs, file); //fileFullName = fileFullName.Replace(".OpApi", ".MainApi"); fileFullName = fileFullName.Replace("op-api", "main-api"); _logger.Info($"发送托书附件路径:{fileFullName}"); if (!File.Exists(fileFullName)) { return await Task.FromResult(DataResult.Failed("附件不存在,请检查")); } attPostArr.Add(new { AttachName = Path.GetFileName(file), AttachContent = Convert.ToBase64String(File.ReadAllBytes(fileFullName)) }); } var mailJson = new dynamic[]{ new { SendTo = req.SendTo, Title = req.Title, Body = req.Body, CCTo= req.CCTo, SmtpConfig = "", Account=userMail.MailAccount, Password=userMail.Password, Server=userMail.SmtpServer, Port=userMail.SmtpPort, UseSSL=userMail.SmtpSSL, Attaches=attPostArr } }; var mailStr = mailJson.ToJsonString(); _logger.Info($"准备发送托书邮件,订舱ID:{req.BookingId},邮箱:{userMail.MailAccount}"); var rtn = RequestHelper.Post(mailStr, emailUrl); _logger.Info($"发送托书邮件返回:{rtn}。订舱ID:{req.BookingId},邮箱:{userMail.MailAccount}"); var jRtn = JObject.Parse(rtn); if (!jRtn.GetBooleanValue("Success")) { //throw Oops.Bah(jRtn.GetStringValue("Message")); return await Task.FromResult(DataResult.Failed(jRtn.GetStringValue("Message"))); } return await Task.FromResult(DataResult.Success(jRtn.GetStringValue("Message"))); //处理添加联系人邮箱 //var forwarder = await _djycustomer.AsQueryable().FirstAsync(x => x.CodeName == book.FORWARDERID && x.ShortName == book.FORWARDER); //if (forwarder != null) //{ // var contactList = await _repCustomerContact.AsQueryable().Where(x => x.CustomerId == forwarder.Id).ToListAsync(); // var arrSendTo = dto.SendTo.Split(';'); // foreach (var emil in arrSendTo) // { // if (contactList.Count(x => x.Email == emil) == 0) // { // DjyCustomerContact contact = new DjyCustomerContact(); // contact.Email = emil; // contact.CustomerId = forwarder.Id; // contact.CarrierProp = book.CARRIERID; // await _repCustomerContact.InsertAsync(contact); // } // } //} } #region 订舱、截单EDI /// /// 发送订舱、截单EDI /// /// 订舱、截单EDI请求 /// 返回回执 public async Task> SendBookingOrClosingEDI(BookingOrClosingEDIOrderReq req) { var tenantDb = saasService.GetBizDbScopeById(user.TenantId); var dictValue = db.Queryable() .InnerJoin((a, b) => a.TypeId == b.Id).Where((a, b) => b.Code == "XiangManCang") .Select((a, b) => new { Value = a.Value, Name = a.Name }).First(); var order = tenantDb.Queryable().First(x => x.Id == req.Id); var Forwarder = seaComService.GetClientCode(order.ForwarderId, tenantDb); if (!string.IsNullOrEmpty(Forwarder) && dictValue != null && dictValue.Value == Forwarder) { return await XMCEXCEL(req.Id); } else { return await InnerBookingOrClosingEDI(req); } } #endregion /// /// 箱满仓生成excel文件 /// /// /// /// public async Task XMCEXCEL(long Id, bool flag = false) { var tenantDb = saasService.GetBizDbScopeById(user.TenantId); var order = tenantDb.Queryable().First(x => x.Id == Id); var edi = tenantDb.Queryable().First(x => x.BusinessId == Id); var ctn = tenantDb.Queryable().Where(x => x.BSNO == order.Id.ToString()).ToList(); #region 箱满仓生成excel文件 string fileName = String.Empty; //var opt = App.GetOptions(); var dirAbs = AppSetting.app(new string[] { "PrintTemplate", "BasePath" }); var relativePath = AppSetting.app(new string[] { "PrintTemplate", "RelativePath" }); if (string.IsNullOrEmpty(dirAbs)) { dirAbs = _environment.WebRootPath; } var fPath = "upload/printtemplate/箱满舱上传Excel模板.xls"; var fileAbsPath = Path.Combine(dirAbs, fPath); if (!File.Exists(fileAbsPath)) { return await Task.FromResult(DataResult.Failed("未配置箱满舱上传Excel模板!")); } _logger.Info($"准备调用EXCEL"); var file = new FileStream(fileAbsPath, FileMode.Open); var excelwork = new HSSFWorkbook(file); var sheet = excelwork.GetSheetAt(0); for (int i = 0; i < sheet.LastRowNum; i++) { ////获取行 var row = sheet.GetRow(i); if (i == 0) { //委托编号 ICell cell = row.GetCell(5); if (cell != null) { row.Cells[5].SetCellValue(order.CustomerNo); } else { row.CreateCell(5).SetCellValue(order.CustomerNo); } } if (i == 1) { //场站 var yardid = seaComService.GetClientCode(order.YardId, tenantDb); if (!string.IsNullOrEmpty(yardid)) { ICell cell = row.GetCell(5); var yard = tenantDb.Queryable() .Where(x => x.Status == StatusEnum.Enable && x.Module == "XiangManCangEDI" && x.Code == yardid) .Select(x => x.MapCode).First(); if (cell != null) { row.Cells[5].SetCellValue(yard); } else { row.CreateCell(5).SetCellValue(yard); } } } if (i == 2) { //指定业务员 ICell cell = row.GetCell(5); if (cell != null) { row.Cells[5].SetCellValue(edi.XMCYWY); } else { row.CreateCell(5).SetCellValue(edi.XMCYWY); } } if (i == 3) { //提单号 ICell cell = row.GetCell(5); if (cell != null) { if (string.IsNullOrEmpty(order.MBLNO)) { row.Cells[5].SetCellValue(order.CustomerNo); } else { row.Cells[5].SetCellValue(order.MBLNO); } } else { if (string.IsNullOrEmpty(order.MBLNO)) { row.CreateCell(5).SetCellValue(order.CustomerNo); } else { row.CreateCell(5).SetCellValue(order.MBLNO); } } } if (i == 8) { //发货人 ICell cell = row.GetCell(1); var shipper = tenantDb.Queryable() .Where(x => x.Status == 0 && x.Id == order.ShipperId).First(); if (cell != null) { row.Cells[1].SetCellValue(shipper.ShortName); } else { row.CreateCell(1).SetCellValue(shipper.ShortName); } } if (i == 10) { //发货人代码 ICell cell = row.GetCell(1); if (cell != null) { row.Cells[1].SetCellValue(order.Shipper); } else { row.CreateCell(1).SetCellValue(order.Shipper); } } if (i == 11) { //收货人 ICell cell = row.GetCell(1); if (cell != null) { row.Cells[1].SetCellValue(order.Consignee); } else { row.CreateCell(1).SetCellValue(order.Consignee); } } if (i == 14) { //通知人 ICell cell = row.GetCell(1); if (cell != null) { row.Cells[1].SetCellValue(order.NotifyParty); } else { row.CreateCell(1).SetCellValue(order.NotifyParty); } } if (i == 17) { //第二通知人 ICell cell = row.GetCell(1); if (cell != null) { row.Cells[1].SetCellValue(order.SecondNotifyParty); } else { row.CreateCell(1).SetCellValue(order.SecondNotifyParty); } } if (i == 18) { //起运港国际五字代码 ICell cell = row.GetCell(1); if (cell != null) { row.Cells[1].SetCellValue(order.LoadPort); } else { row.CreateCell(1).SetCellValue(order.LoadPort); } var service = order.Service; //运输方式 ICell cell5 = row.GetCell(5); var serviceMap = tenantDb.Queryable() .Where(x => x.Status == StatusEnum.Enable && x.Module == "XiangManCangEDI" && x.Code == service).Select(x => x.MapCode).First(); if (cell5 != null) { row.Cells[5].SetCellValue(serviceMap); } else { row.CreateCell(5).SetCellValue(serviceMap); } } if (i == 19) { //卸货港国际五字代码 ICell cell = row.GetCell(1); if (cell != null) { row.Cells[1].SetCellValue(order.DischargePort); } else { row.CreateCell(1).SetCellValue(order.DischargePort); } } if (i == 20) { //交货地国际五字代码 ICell cell = row.GetCell(1); if (cell != null) { row.Cells[1].SetCellValue(order.Destination); } else { row.CreateCell(1).SetCellValue(order.Destination); } } if (i == 21) { //ETD if (order.ETD != null) { ICell cell = row.GetCell(1); if (cell != null) { row.Cells[1].SetCellValue(Convert.ToDateTime(order.ETD).ToString("yyyy-MM-dd")); } else { row.CreateCell(1).SetCellValue(Convert.ToDateTime(order.ETD).ToString("yyyy-MM-dd")); } } //船名 ICell cell4 = row.GetCell(4); if (cell4 != null) { row.Cells[4].SetCellValue(order.Vessel); } else { row.CreateCell(4).SetCellValue(order.Vessel); } } if (i == 22) { //客户协约号 ICell cell = row.GetCell(1); if (cell != null) { row.Cells[1].SetCellValue(order.ContractNo); } else { row.CreateCell(1).SetCellValue(order.ContractNo); } } if (i == 23) { //航次 ICell cell = row.GetCell(4); if (cell != null) { row.Cells[4].SetCellValue(order.InnerVoyno); } else { row.CreateCell(4).SetCellValue(order.InnerVoyno); } } if (i == 26) { //唛头 ICell cell = row.GetCell(0); if (cell != null) { row.Cells[0].SetCellValue(order.Marks); } else { row.CreateCell(0).SetCellValue(order.Marks); } if (order.PKGS != null) { //件数 ICell cell1 = row.GetCell(1); if (cell1 != null) { row.Cells[1].SetCellValue(order.PKGS.ToString()); } else { row.CreateCell(1).SetCellValue(order.PKGS.ToString()); } } //包装 ICell cell2 = row.GetCell(2); if (cell2 != null) { row.Cells[2].SetCellValue(order.KindPkgs); } else { row.CreateCell(2).SetCellValue(order.KindPkgs); } //品名 ICell cell3 = row.GetCell(3); if (cell3 != null) { row.Cells[3].SetCellValue(order.Description); } else { row.CreateCell(3).SetCellValue(order.Description); } if (order.KGS != null) { //重量 ICell cell4 = row.GetCell(4); if (cell3 != null) { row.Cells[4].SetCellValue(order.KGS.ToString()); } else { row.CreateCell(4).SetCellValue(order.KGS.ToString()); } } if (order.CBM != null) { //尺码 ICell cell5 = row.GetCell(5); if (cell5 != null) { row.Cells[5].SetCellValue(order.CBM.ToString()); } else { row.CreateCell(5).SetCellValue(order.CBM.ToString()); } } } if (i == 39) { var c = ctn.DistinctBy(x => x.CtnAll).ToList(); var ctnAll = string.Empty; foreach (var item in c) { var ctnMap = tenantDb.Queryable() .Where(x => x.Status == StatusEnum.Enable && x.Module == "XiangManCangEDI" && x.Code == item.CtnCode).Select(x => x.MapCode).First(); ctnAll += $"{ctn.Where(x => x.CtnAll == item.CtnAll).Count()}*{ctnMap}+"; } ctnAll = ctnAll.Substring(0, ctnAll.Length - 1); //箱型箱量 ICell cell = row.GetCell(0); if (cell != null) { row.Cells[0].SetCellValue(ctnAll); } else { row.CreateCell(0).SetCellValue(ctnAll); } } if (i == 42) { //运费支付方式 var BLFRTCode = tenantDb.Queryable() .Where(x => x.Status == StatusEnum.Enable && x.FrtName == order.MBLFrt).Select(x => x.EdiCode).First(); var bl = string.Empty; if (!string.IsNullOrEmpty(BLFRTCode)) { bl = tenantDb.Queryable() .Where(x => x.Status == StatusEnum.Enable && x.Module == "XiangManCangEDI" && x.Code == BLFRTCode).Select(x => x.MapCode).First(); } ICell cell = row.GetCell(0); if (cell != null) { row.Cells[0].SetCellValue(bl); } else { row.CreateCell(0).SetCellValue(bl); } } if (i == 43) { //hscode ICell cell = row.GetCell(3); if (cell != null) { row.Cells[3].SetCellValue(order.HSCode); } else { row.CreateCell(3).SetCellValue(order.HSCode); } } if (i == 44) { var BLFRTCode = tenantDb.Queryable() .Where(x => x.Status == StatusEnum.Enable && x.FrtName == order.MBLFrt).Select(x => x.EdiCode).First(); var bl = string.Empty; if (!string.IsNullOrEmpty(BLFRTCode)) { bl = tenantDb.Queryable() .Where(x => x.Status == StatusEnum.Enable && x.Module == "XiangManCangEDI" && x.Code == BLFRTCode).Select(x => x.MapCode).First(); } if (bl == "预付") { //预付地点 ICell cell = row.GetCell(1); if (cell != null) { row.Cells[1].SetCellValue(order.PrepareAt); } else { row.CreateCell(1).SetCellValue(order.PrepareAt); } } else if ((bl == "到付")) { //预付地点 ICell cell = row.GetCell(1); if (cell != null) { row.Cells[1].SetCellValue(order.PayableAt); } else { row.CreateCell(1).SetCellValue(order.PayableAt); } } } if (i == 45) { //Name accout ICell cell = row.GetCell(1); if (cell != null) { row.Cells[1].SetCellValue(edi.EmcNameAccount); } else { row.CreateCell(1).SetCellValue(edi.EmcNameAccount); } ICell _cell = row.GetCell(4); if (_cell != null) { row.Cells[4].SetCellValue(edi.EmcNameAccount); } else { row.CreateCell(4).SetCellValue(edi.EmcNameAccount); } } if (i == 47) { //Name accout ICell cell = row.GetCell(1); if (cell != null) { row.Cells[1].SetCellValue(order.TemperatureSet); } else { row.CreateCell(1).SetCellValue(order.TemperatureSet); } //温度 ICell cell2 = row.GetCell(2); if (cell2 != null) { row.Cells[2].SetCellValue(order.ReeferQuantity); } else { row.CreateCell(2).SetCellValue(order.ReeferQuantity); } //湿度 ICell cell3 = row.GetCell(3); if (cell2 != null) { row.Cells[3].SetCellValue(order.Humidity); } else { row.CreateCell(3).SetCellValue(order.Humidity); } } if (i == 49) { //危险品编号 ICell cell = row.GetCell(1); if (cell != null) { row.Cells[1].SetCellValue(order.DangerNo); } else { row.CreateCell(1).SetCellValue(order.DangerNo); } } if (i == 50) { //订舱备注 ICell cell = row.GetCell(1); if (cell != null) { row.Cells[1].SetCellValue(order.BookingRemark); } else { row.CreateCell(1).SetCellValue(order.BookingRemark); } } } var fileFullPath = Path.Combine(_environment.WebRootPath, AppSetting.app(new string[] { "TempFile", "Path" }));//服务器路径 if (!Directory.Exists(fileFullPath)) { Directory.CreateDirectory(fileFullPath); } //2023-4-3,根据合川操作要求,文件名只带提单号 if (!string.IsNullOrEmpty(order.MBLNO)) { fileName = $"{DateTime.Now.Ticks}_{order.MBLNO}.xls";//名称 } else { fileName = $"{DateTime.Now.Ticks}_{order.MBLNO}.xls";//名称 } _logger.Info("导出excel:" + Path.Combine(fileFullPath, fileName)); var filestream = new FileStream(Path.Combine(fileFullPath, fileName), FileMode.OpenOrCreate, FileAccess.ReadWrite); excelwork.Write(filestream); #endregion if (flag) { filestream.Close(); filestream.Dispose(); var fpath = Path.Combine(fileFullPath, fileName); var fInfo = new FileInfo(fpath); _logger.Info("箱满仓文件地址:" + fpath + " " + fInfo); return new FileStreamResult(new FileStream(fpath, FileMode.Open), "application/octet-stream") { FileDownloadName = fInfo.Name }; } #region 调用爬虫接口 var url = db.Queryable().Filter(null, true).Where(x => x.Code == "xiangManCangPostUrl" && x.TenantId == 1288018625843826688).Select(x => x.Value).First(); if (string.IsNullOrEmpty(url)) { return await Task.FromResult(DataResult.Failed("未配置箱满仓请求地址[xiangManCangPostUrl],请联系管理员!")); } var account = seaComService.GetCodeThirdParty("XiangManCang", user.UserId, tenantDb, order.CarrierId); if (account == null) { return await Task.FromResult(DataResult.Failed("未配置箱满仓账号!")); } var key = db.Queryable().Filter(null, true).Where(x => x.Code == "billTraceNewUserKey" && x.TenantId == 1288018625843826688).Select(x => x.Value).First(); if (string.IsNullOrEmpty(key)) { return await Task.FromResult(DataResult.Failed("未获取到运踪相关KEY,请联系管理员!")); } var secret = db.Queryable().Filter(null, true).Where(x => x.Code == "billTraceNewUserSecret" && x.TenantId == 1288018625843826688).Select(x => x.Value).First(); if (string.IsNullOrEmpty(secret)) { return await Task.FromResult(DataResult.Failed("未获取到运踪相关SECRET,请联系管理员!")); } ////使用HttpClient方式上传文件 var carrier_code = db.Queryable().Where(x => x.Module == "HeChuan" && x.MapCode == order.Carrier).Select(x => x.Code).First(); string fn = string.Empty; using (var httpClient = new HttpClient()) { using (var request = new HttpRequestMessage(new HttpMethod("Post"), url)) { //request.Headers.TryAddWithoutValidation("Content-Type", "application/x-www-form-urlencoded"); var multipartContent = new MultipartFormDataContent(); multipartContent.Add(new StringContent("user_key"), key); multipartContent.Add(new StringContent("user_secret"), secret); multipartContent.Add(new StringContent("web_user"), account.AppKey); multipartContent.Add(new StringContent("web_psw"), account.AppSecret); multipartContent.Add(new StringContent("carrier_code"), carrier_code); multipartContent.Add(new StreamContent(filestream, (int)filestream.Length), "file", fileName); request.Content = multipartContent; var response = await httpClient.SendAsync(request); if (response.IsSuccessStatusCode) { var strRtn = response.Content.ReadAsStringAsync().Result; var jobj = strRtn.ToJObject(); if (jobj.GetIntValue("code") == 200) { fn = jobj.GetStringValue("msg"); } else { return await Task.FromResult(DataResult.Failed(jobj.GetStringValue("msg"))); } } } } //return fn; return await Task.FromResult(DataResult.Success(fn)); #endregion } #region 根据船公司ID获取EDI的路由枚举 /// /// 根据船公司ID获取EDI的路由枚举 /// /// 船公司ID /// /// 返回适用的路由枚举 private EDIRouteEnum GetEDIRoute(string carrierId, MappingCarrier ediRouteCfg) { EDIRouteEnum routeEnum = EDIRouteEnum.NULL; var tenantDb = saasService.GetBizDbScopeById(user.TenantId); //var ediRouteCfg = _cache.GetAllMappingCarrier().GetAwaiter().GetResult() // .FirstOrDefault(t => t.Module.Equals("BOOK_OR_CLOSING_RT", StringComparison.OrdinalIgnoreCase) // && t.Code.Equals(carrierId, StringComparison.OrdinalIgnoreCase)); if (ediRouteCfg != null && !string.IsNullOrWhiteSpace(ediRouteCfg.MapCode)) routeEnum = (EDIRouteEnum)System.Enum.Parse(typeof(EDIRouteEnum), ediRouteCfg.MapCode); //switch (carrierId.ToUpper()) //{ // case "PIL": // routeEnum = EDIRouteEnum.PIL; // break; // case "ONE": // routeEnum = EDIRouteEnum.YT; // break; // case "TSL": // routeEnum = EDIRouteEnum.TSL; // break; // case "YML": // routeEnum = EDIRouteEnum.YML; // break; // case "WY": // routeEnum = EDIRouteEnum.WY; // break; //} return routeEnum; } #endregion public async Task> InnerBookingOrClosingEDI(BookingOrClosingEDIOrderReq req) { var tenantDb = saasService.GetBizDbScopeById(user.TenantId); string batchNo = GuidHelper.NewGuidFormatN(); _logger.Info("批次={no}获取请求订舱、截单EDI {msg}", batchNo, JsonConvert.SerializeObject(req)); /* 发送订舱和截单EDI的流程 1、通过订单号获取订单信息。 2、检查订单的必填信息。 3、根据船公司ID获取对应的路由枚举。 4、获取EDI转换参数。(集装箱型号、包装方式) 5、读取EDI的配置信息,获取船公司相关的EDI配置。 6、检查详细信息。 7、生成订舱或者截单EDI报文,并返回文件保存绝对路径。 */ if (req.Id == 0) return DataResult.Failed($"订单Id不能为空"); var order = tenantDb.Queryable().First(x => x.Id == req.Id); if (order == null) return DataResult.Failed($"获取订单信息失败"); if (order.ParentId != 0) return DataResult.Failed($"获取当前订单为分单不能生成EDI信息"); var orderEDI = tenantDb.Queryable().First(x => x.BusinessId == req.Id); _logger.Info("批次={no}提取订单信息完成", batchNo); var ediExtModel = tenantDb.Queryable().First(x => x.BusinessId == req.Id); if (ediExtModel == null) return DataResult.Failed($"获取EDI信息失败"); _logger.Info("批次={no}提取订单EDI信息完成", batchNo); //箱信息 var contaList = tenantDb.Queryable().Where(x => x.BSNO == order.Id.ToString()).ToList(); var carrCode = seaComService.GetCarrierCode(order.CarrierId, tenantDb); var carrMap = tenantDb.Queryable().Where(t => t.Module.Equals("BOOK_OR_CLOSING_RT", StringComparison.OrdinalIgnoreCase) && t.Code == carrCode) .First(); EDIRouteEnum ediRouteEnum = GetEDIRoute(carrCode, carrMap); var check = CheckBookingOrClosingEDI(order, contaList, req.SendType, ediRouteEnum); if (!check.Succeeded) { return DataResult.Failed(check.Message); } if (ediRouteEnum == EDIRouteEnum.YT) { if (string.IsNullOrWhiteSpace(order.NoBill)) { return DataResult.Failed($"当前船公司{order.Carrier} EDI={ediRouteEnum.ToString()} 提单份数必填"); } } //部分船公司EDI需要填写操作英文名称,这里预先预警,其他船公司如果也需要可以再此追加 if (ediRouteEnum == EDIRouteEnum.TSL) { if (string.IsNullOrWhiteSpace(ediExtModel.OpEName)) return DataResult.Failed($"未填写(EDI并补充信息)操作英文名称"); } _logger.Info("批次={no} 获取EDI路由完成 路由={route}", batchNo, ediRouteEnum.ToString()); if (ediRouteEnum == EDIRouteEnum.NULL) return DataResult.Failed($"当前船公司没有对应的请求路由配置"); //这里船公司VOL的单子不能走此通道发送 if (ediRouteEnum == EDIRouteEnum.VOL) return DataResult.Failed($"当前船公司VOL不能执行标准发送"); ////集装箱型 //var ediCtnList = tenantDb.Queryable() // .Where(t => t.Module.Equals(CONST_MAPPING_MODULE, StringComparison.OrdinalIgnoreCase) // && t.CarrierId == order.CarrierId).ToList(); ////包装 //var ediPkgsList = tenantDb.Queryable() // .Where(t => t.Module.Equals(CONST_MAPPING_MODULE, StringComparison.OrdinalIgnoreCase) // && t.CarrierId == order.CarrierId).ToList(); ////包装基础数据 //var basePkgsList = tenantDb.Queryable().Where(x => x.Status == StatusEnum.Enable).ToList(); //EDI SO\SI代码 var ediSOSICfg = tenantDb.Queryable().First(t => t.Module.Equals(CONST_MAPPING_MODULE, StringComparison.OrdinalIgnoreCase) && t.Code == carrCode); if (ediSOSICfg == null || string.IsNullOrWhiteSpace(ediSOSICfg.MapCode)) return DataResult.Failed($"CARRIERID={carrCode} 发送SO(SI)的船公司EDI代码未找到"); string postSpiderUrl = string.Empty; CodeThirdParty userWebAccountConfig = null; if (ediRouteEnum == EDIRouteEnum.TSL && req.Send) { if (req.SendType.Equals("E", StringComparison.OrdinalIgnoreCase)) return DataResult.Failed($"暂未提供TSL的截单发送"); postSpiderUrl = db.Queryable().Filter(null, true).Where(x => x.Code == CONST_TSL_EDI_URL && x.TenantId == 1288018625843826688).First().Value; if (string.IsNullOrWhiteSpace(postSpiderUrl)) return DataResult.Failed($"系统参数未配置{CONST_TSL_EDI_URL} 请联系管理员"); //获取个人对应的账户,这里GetAccountConfig逻辑优先取个人,个人没有配置取公司对应配置 userWebAccountConfig = seaComService.GetCodeThirdParty(CONST_TSL_TYPE_CODE,user.UserId, tenantDb); _logger.Info("批次={no} 获取获取网站的账户完成,result={Num}", batchNo, JsonConvert.SerializeObject(userWebAccountConfig)); if (userWebAccountConfig == null) return DataResult.Failed($"未配置第三方账户,网站{CONST_TSL_TYPE_CODE}"); } var ediModel = new EDIBaseModel(); //2023-03-06 修改读取EDI配置方法,所有提取配置必须是已启用的EnableFlag=true,并且要根据SendType匹配发送类型,SendType=""表示使用订舱和截单,SO-订舱 SI-截单 var ftpSet = tenantDb.Queryable() .First(a => a.EdiTypeCode.Equals(ediRouteEnum.ToString(), StringComparison.OrdinalIgnoreCase) && a.CarrierId == order.CarrierId && a.Status == StatusEnum.Enable && (string.IsNullOrWhiteSpace(a.SendType) || (!string.IsNullOrWhiteSpace(a.SendType) && ((req.SendType == "B" && a.SendType == "SO") || (req.SendType == "E" && a.SendType == "SI"))))); if (ftpSet == null) return DataResult.Failed($"获取EDICODE={ediRouteEnum.ToString()}的EDI参数设置失败"); _logger.Info("批次={no} 获取EDI配置完成 路由={set}", batchNo, JsonConvert.SerializeObject(ftpSet)); ediModel.SENDCODE = ftpSet.SendCode; ediModel.SENDNAME = ftpSet.SendName; ediModel.RECEIVECODE = ftpSet.ReceiveCode; ediModel.SENDCOMPANYCODE = ftpSet.SendCompanyCode; ediModel.SENDSUBCOMPANYCODE = ftpSet.SendCompanyCode; ediModel.ALIASSENDCODE = ftpSet.AliasSendCode; ediModel.SENDSHIPPERCODE = ftpSet.SendShipperCode; ediModel.filetype = req.SendType; //订舱 ediModel.filerole = req.FileRole; //读取文件配置 //var fileCfg = App.GetOptions(); var basePath = AppSetting.app(new string[] { "FileSettings", "BasePath" }); string filePath = String.Empty; string relativePath = string.Empty; if (!req.Send) { var opt = AppSetting.app(new string[] { "TempFile", "Path" }); filePath = $"{Path.Combine(_environment.WebRootPath ?? "", opt)}\\{order.CustomerNo}";//服务器路径 } else { var cfgPath = AppSetting.app(new string[] { "FileSettings", "RelativePath" }); relativePath = $"{cfgPath}\\edifiles\\{order.CustomerNo}"; filePath = $"{(!string.IsNullOrWhiteSpace(basePath) ? basePath : _environment.WebRootPath)}\\{relativePath}"; } if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { relativePath = relativePath.Replace("\\", "/"); filePath = filePath.Replace("\\", "/"); } _logger.Info("批次={no} 生成文件保存路径完成 路由={filePath} 服务器系统={system}", batchNo, filePath, RuntimeInformation.OSDescription); //预先创建目录 if (!Directory.Exists(filePath)) { Directory.CreateDirectory(filePath); } ediModel.filerpath = filePath; /* * 2023-03-08 这里根据最新的要求,不通过前台读取了,直接从配置读取 ediModel.UseForWarderCode = model.useForwarderCode; ediModel.ForWarderCode = model.forwarderCode; ediModel.ForWarderName = model.forwarderName; */ ediModel.ForWarderCode = ftpSet.SendCode; ediModel.ForWarderName = ftpSet.SendName; ediModel.BSLIST = new List(); //TODO 数据映射 var primaryModel = order.Adapt(); //primaryModel = orderEDI.Adapt(); //航次取内部航次号 2023-04-03 合川操作确认这样调整 primaryModel.VOYNO = order.InnerVoyno; //航线信息直接取的航司航线(ESL用) primaryModel.ESLLINECODE = order.Lane; //起始港映射 var mapPortList = new List(); var portList = new List(); #region 收货地 //收货地 if (order.ReceiptPlaceId > 0) { var portRlt = GetPortEDICode(order.ReceiptPlaceId, portList, mapPortList, order.CarrierId, CONST_MAPPING_MODULE, order.ReceiptPlace, "收货地"); if (portRlt.Succeeded) primaryModel.PLACERECEIPTID = portRlt.Data; } #endregion #region 装货港 //装货港 if (order.LoadPortId > 0) { var portRlt = GetPortEDICode(order.LoadPortId, portList, mapPortList, order.CarrierId, CONST_MAPPING_MODULE, order.LoadPort, "装货港"); if (portRlt.Succeeded) primaryModel.PORTLOADID = portRlt.Data; } #endregion #region 签单地点 //签单地点 if (order.IssuePlaceId > 0) { var portRlt = GetPortEDICode(order.IssuePlaceId, portList, mapPortList, order.CarrierId, CONST_MAPPING_MODULE, order.IssuePlace, "签单地点"); if (portRlt.Succeeded) primaryModel.ISSUEPLACEID = portRlt.Data; } #endregion #region 预付地点 //预付地点 if (order.PrepareAtId > 0) { var portRlt = GetPortEDICode(order.PrepareAtId, portList, mapPortList, order.CarrierId, CONST_MAPPING_MODULE, order.PrepareAt, "预付地点"); if (portRlt.Succeeded) primaryModel.PREPARDATID = portRlt.Data; } #endregion string needMappingModule = string.Empty; if (ediRouteEnum == EDIRouteEnum.INTTRA) { needMappingModule = "INTTRA_EDI"; } #region 卸货港 //卸货港 if (order.DischargePortId > 0) { var portRlt = GetPortEDICode(order.DischargePortId, portList, mapPortList, order.CarrierId, CONST_MAPPING_MODULE, order.DischargePort, "卸货港", needMappingModule); if (portRlt.Succeeded) primaryModel.PORTDISCHARGEID = portRlt.Data; } #endregion #region 中转港 //中转港 if (order.TransPortId > 0) { var portRlt = GetPortEDICode(order.TransPortId, portList, mapPortList, order.CarrierId, CONST_MAPPING_MODULE, order.TransPort, "中转港", needMappingModule); if (portRlt.Succeeded) primaryModel.TRANSPORTID = portRlt.Data; } #endregion #region 交货地 //交货地 if (order.DeliveryPlaceId > 0) { var portRlt = GetPortEDICode(order.DeliveryPlaceId, portList, mapPortList, order.CarrierId, CONST_MAPPING_MODULE, order.DeliveryPlace, "交货地", needMappingModule); if (portRlt.Succeeded) primaryModel.PLACEDELIVERYID = portRlt.Data; } #endregion //INTTRA 订舱时改用交货地来填写到目的地 if (ediRouteEnum == EDIRouteEnum.INTTRA || ediRouteEnum == EDIRouteEnum.YT) { #region 目的地 //目的地 if (order.DeliveryPlaceId > 0) { var portRlt = GetPortEDICode(order.DeliveryPlaceId, portList, mapPortList, order.CarrierId, CONST_MAPPING_MODULE, order.DischargePort, "交货地", needMappingModule); if (portRlt.Succeeded) primaryModel.DESTINATIONID = portRlt.Data; } #endregion } else { #region 目的地 //目的地 if (order.DestinationId > 0) { var portRlt = GetPortEDICode(order.DestinationId, portList, mapPortList, order.CarrierId, CONST_MAPPING_MODULE, order.DischargePort, "目的地", needMappingModule); if (portRlt.Succeeded) primaryModel.DESTINATIONID = portRlt.Data; } #endregion } #region 到付地点 //到付地点 if (order.PayableAtId > 0) { var portRlt = GetPortEDICode(order.PayableAtId, portList, mapPortList, order.CarrierId, CONST_MAPPING_MODULE, order.PayableAt, "到付地点", needMappingModule); if (portRlt.Succeeded) primaryModel.PAYABLEATID = portRlt.Data; } #endregion //如果处理的是到付,需要把预付地点来对应到付地点 if (!string.IsNullOrWhiteSpace(order.MBLFrt) && order.MBLFrt.IndexOf("COLLECT") >= 0) { primaryModel.PAYABLEATID = primaryModel.PREPARDATID; primaryModel.PAYABLEAT = order.PrepareAt; primaryModel.PREPARDATID = string.Empty; primaryModel.PREPARDAT = string.Empty; } //起运港是CNTAO并且船公司是太平需要判断场站EDI if (ediRouteEnum == EDIRouteEnum.WY) { //场站 var ediYardList = tenantDb.Queryable() .Where(t => t.Module.Equals(CONST_MAPPING_MODULE, StringComparison.OrdinalIgnoreCase)).ToList(); var yardCode = seaComService.GetClientCode(order.YardId,tenantDb); if (!string.IsNullOrWhiteSpace(yardCode)) { var currYardInfo = ediYardList.FirstOrDefault(t => t.Code.Equals(yardCode, StringComparison.OrdinalIgnoreCase)); if (currYardInfo == null) return DataResult.Failed($"场站{order.Yard}的EDI代码未找到"); primaryModel.YARDEDICODE = currYardInfo.MapCode?.Trim(); primaryModel.YARD = currYardInfo.MapName?.Trim(); } } //ESL、PIL、WY、YML、YT 需要付费方式映射EDI代码 if (ediRouteEnum == EDIRouteEnum.ESL || ediRouteEnum == EDIRouteEnum.PIL || ediRouteEnum == EDIRouteEnum.WY || ediRouteEnum == EDIRouteEnum.YML || ediRouteEnum == EDIRouteEnum.YT || ediRouteEnum == EDIRouteEnum.INTTRA) { /* 1、先默认取映射,如果没有映射配置,默认取基础表EdiCode */ if (!string.IsNullOrWhiteSpace(order.MBLFrtCode)) { var codeInfo = tenantDb.Queryable().First(x => x.Status == StatusEnum.Enable && x.EdiCode == order.MBLFrtCode); if (codeInfo != null) { //primaryModel.BLFRTEDICODE = codeInfo.EdiCode; primaryModel.BLFRT = codeInfo.FrtName; var mapInfo = tenantDb.Queryable().First(t => t.Module.Equals(CONST_MAPPING_MODULE, StringComparison.OrdinalIgnoreCase) && t.CarrierId == order.CarrierId && t.LinkId == codeInfo.Id); if (mapInfo != null) { primaryModel.BLFRTEDICODE = mapInfo.MapCode?.Trim(); } else { primaryModel.BLFRTEDICODE = codeInfo.EdiCode; } } else { return DataResult.Failed($"付费方式{order.MBLFrt}的基础代码未找到"); } } else { return DataResult.Failed($"付费方式{order.MBLFrt}不能为空"); } } #region 运输条款EDI //运输条款EDI if (!string.IsNullOrWhiteSpace(order.ServiceCode)) { //long serviceId = long.Parse(order.Service); var codeInfo = tenantDb.Queryable().First(x => x.Status == StatusEnum.Enable && x.EdiCode == order.ServiceCode); if (codeInfo != null) { //primaryModel.BLFRTEDICODE = codeInfo.EdiCode; primaryModel.SERVICE = codeInfo.ServiceName; var mapInfo = tenantDb.Queryable().First(t => t.Module.Equals(CONST_MAPPING_MODULE, StringComparison.OrdinalIgnoreCase) && t.CarrierId == order.CarrierId && t.LinkId == codeInfo.Id); if (mapInfo != null) { primaryModel.SERVICEEDICODE = mapInfo.MapCode?.Trim(); } else { primaryModel.SERVICEEDICODE = codeInfo.EdiCode; } } else { return DataResult.Failed($"运输条款{order.MBLFrt}的基础代码未找到"); } } #endregion #region 签单方式EDI ////签单方式EDI if (!string.IsNullOrWhiteSpace(order.IssueTypeCode)) { //long issueTypeId = long.Parse(order.IssueType); var codeIssue = tenantDb.Queryable().First(t => t.EdiCode == order.IssueTypeCode); if (codeIssue == null) { return DataResult.Failed($"签单方式{order.IssueTypeCode}的基础代码未找到"); } var mapInfo = tenantDb.Queryable() .First(t => t.Module.Equals(CONST_MAPPING_MODULE, StringComparison.OrdinalIgnoreCase) && t.CarrierId == order.CarrierId && t.LinkId == codeIssue.Id); if (mapInfo != null) { primaryModel.ISSUETYPE = mapInfo.MapCode; } else { //签单方式EDI if (codeIssue != null && !string.IsNullOrWhiteSpace(codeIssue.EdiCode)) { primaryModel.ISSUETYPE = codeIssue.EdiCode; } else { return DataResult.Failed($"签单方式{order.Service}的基础代码 EdiCode 未配置"); } } } #endregion primaryModel.CARRIEREDICODE = ediSOSICfg.MapCode; //这里除了TSL,订舱编号默认都对应到业务编号(订舱保存时自动生成) if (ediRouteEnum == EDIRouteEnum.TSL) { if (string.IsNullOrWhiteSpace(order.CustomerNo)) return DataResult.Failed($"船公司是{order.CustomerNo} 订舱编号不能为空"); primaryModel.ORDERNO = order.CustomerNo; } else { if (ediRouteEnum == EDIRouteEnum.INTTRA) { primaryModel.ORDERNO = order.CustomerNo; } else { primaryModel.ORDERNO = order.BookingNo; } } if (ediRouteEnum != EDIRouteEnum.INTTRA) { //2023-06-15 按照沟通要求,如果主提单号为空,并且订舱编号不为空,可以去订舱编号填入主提单号 if (string.IsNullOrWhiteSpace(primaryModel.MBLNO)) { if (!string.IsNullOrWhiteSpace(order.CustomerNo)) { _logger.Info("批次={no} 主题单号为空 MBLNO={mblno} 取订舱编号补到主提单号 custno={custno}", batchNo, primaryModel.MBLNO, order.CustomerNo); if (req.SendType.Equals("B", StringComparison.OrdinalIgnoreCase)) { primaryModel.MBLNO = order.CustomerNo; } } } } List codeCtnList = new List(); List mapCtnList = new List(); List codePackageList = new List(); List mapPackageList = new List(); #region 包装方式EDI if (!string.IsNullOrWhiteSpace(order.KindPkgs)) { long packageId = long.Parse(order.KindPkgs); var portRlt = GetPackageEDICode(packageId, codePackageList, mapPackageList, order.CarrierId, CONST_MAPPING_MODULE); if (codePackageList.Any(b => b.Id == packageId)) primaryModel.KINDPKGS = codePackageList.FirstOrDefault(b => b.Id == packageId).PackageName; if (portRlt.Succeeded) { primaryModel.KINDPKGS_EDI_CODE = portRlt.Data; } else { return DataResult.Failed($"包装{order.KindPkgs}的映射数据代码未找到"); } } else { return DataResult.Failed($"包装不能为空"); } #endregion //这里是订舱时,默认取SOREMARK赋值到EDIREMARK if (req.SendType == "B") { primaryModel.EDIREMARK = order.BookingRemark; } else if (req.SendType == "E") { primaryModel.SIREMARK = order.CloseDocRemark; } primaryModel.S0CC0C = ediExtModel.S0CC0C; primaryModel.ACIHBL = ediExtModel.ACIHBL; primaryModel.MasterBOLIndicator = ediExtModel.MasterBolIndicator; primaryModel.ConsigneeEdiCode = ediExtModel.ConsigneeEdiCode; primaryModel.ShipperEdiCode = ediExtModel.ShipperEdiCode; primaryModel.SalesRepCode = ediExtModel.SalerCode; primaryModel.CNPTNo = ediExtModel.CNPTNo; //优先取订舱的EDI附属信息,为空取FTP配置 primaryModel.EDIATTN = ediExtModel.EDIAttn; if (string.IsNullOrWhiteSpace(primaryModel.EDIATTN)) { primaryModel.EDIATTN = ftpSet.SendAttn; } primaryModel.EDIATTNTEL = ediExtModel.EDIAttnTel; if (string.IsNullOrWhiteSpace(primaryModel.EDIATTNTEL)) { primaryModel.EDIATTNTEL = ftpSet.SendTel; } primaryModel.EDIATTNEMAIL = ediExtModel.EDIAttnMail; if (string.IsNullOrWhiteSpace(primaryModel.EDIATTNEMAIL)) { primaryModel.EDIATTNEMAIL = ftpSet.SendEmail; } primaryModel.AMSCONSIGNEE = ediExtModel.AMSConsignee; primaryModel.AMSNOTIFYPARTY = ediExtModel.AMSNotifyParty; primaryModel.OpEName = ediExtModel.OpEName; primaryModel.OpTel = ediExtModel.OpTel; primaryModel.OpEmail = ediExtModel.OpEmail; /* 2023-04-14 确认东胜流程后,这里调整商品名称取值,不从EDI扩展信息取,改为从主表的GOODS_CODE取代码经过品名翻译英文填写 注:仅限PIL //primaryModel.GOODSNAME = ediExtModel.GoodsName; */ if (ediRouteEnum == EDIRouteEnum.PIL) { if (req.SendType.Equals("E", StringComparison.OrdinalIgnoreCase)) { if (!string.IsNullOrWhiteSpace(order.GoodsName)) { if (order.GoodsId == 0) { return DataResult.Failed($"海运出口商品Id未回填!"); } var pGoods = tenantDb.Queryable().First(x => x.Id == order.GoodsId); if (pGoods == null) { _logger.Info("批次={no} 提取商品名称失败 GoodsName={code}", batchNo, order.GoodsName); return DataResult.Failed($"商品Id对应商品名称未找到!"); } else { primaryModel.GOODSNAME = pGoods.EnName; _logger.Info("批次={no} 提取商品名称失败 name={name}", batchNo, pGoods.GoodName); } } } else if (req.SendType.Equals("B", StringComparison.OrdinalIgnoreCase)) { //2023-05-17 PIL订舱时不提供GOODSNAME,这里默认赋空 primaryModel.GOODSNAME = string.Empty; } } primaryModel.cKHI = ediExtModel.CKHI; primaryModel.cNCM = ediExtModel.CNCM; primaryModel.wNCM = ediExtModel.WNCM; primaryModel.ORDERREMARK = ediExtModel.OrderRemark; //2023-05-10 (PIL)订舱的预抵日期不提供输入框,按照和川操作要求取开船日期填写到预抵日期 if (string.IsNullOrWhiteSpace(primaryModel.ETA) && !string.IsNullOrWhiteSpace(primaryModel.ETD) && ediRouteEnum == EDIRouteEnum.PIL) { primaryModel.ETA = primaryModel.ETD; } if (ediRouteEnum == EDIRouteEnum.INTTRA) { if (!string.IsNullOrWhiteSpace(ediExtModel.CustomerName)) primaryModel.WEITUO = ediExtModel.CustomerName; } primaryModel.KINGTAREWEIGHT = ediExtModel.KingTareweight.HasValue ? ediExtModel.KingTareweight.Value : 0; _logger.Info("批次={no} 提取箱完成 数量={total}", batchNo, contaList.Count); primaryModel.CTNLIST = new List(); //集装箱 foreach (var conta in contaList) { //TODO 转换 var contaModel = conta.Adapt(); var mapCtnRlt = GetCtnEDICode(conta.CtnCode, codeCtnList, mapCtnList, order.CarrierId, CONST_MAPPING_MODULE, conta.CtnAll, ediRouteEnum); if (mapCtnRlt.Succeeded) { contaModel.CTNALLCODE = mapCtnRlt.Data; } else { return DataResult.Failed($"箱型{conta.CtnAll}的映射数据代码未找到"); } //截单时箱的包装必填 if (string.IsNullOrWhiteSpace(conta.KindPkgs) && req.SendType.Equals("E",StringComparison.OrdinalIgnoreCase)) return DataResult.Failed($"集装箱包装不能为空!"); if (!string.IsNullOrWhiteSpace(conta.KindPkgs)) { long packageId = long.Parse(conta.KindPkgs); var mapRlt = GetPackageEDICode(packageId, codePackageList, mapPackageList, order.CarrierId, CONST_MAPPING_MODULE); if (codePackageList.Any(b => b.Id == packageId)) contaModel.KINDPKGS = codePackageList.FirstOrDefault(b => b.Id == packageId).PackageName; if (mapRlt.Succeeded) { contaModel.KINDPKGS_EDI_CODE = mapRlt.Data; } else { return DataResult.Failed($"集装箱【{conta.CntrNo}】包装{conta.KindPkgs}的映射数据代码未找到"); } } else { if(req.SendType.Equals("E", StringComparison.OrdinalIgnoreCase)) { return DataResult.Failed($"集装箱【{conta.CntrNo}】包装{conta.KindPkgs} 不能为空"); } } primaryModel.CTNLIST.Add(contaModel); } //多品名 var cargoList = tenantDb.Queryable().Where(t => contaList.Select(a => a.Id).ToArray().Contains(t.CtnId)).ToList(); _logger.Info("批次={no} 提取多品名完成 数量={total}", batchNo, cargoList.Count); primaryModel.CTNGOODSLIST = new List(); foreach (var cargo in cargoList) { //TODO 映射 var cargoModel = cargo.Adapt(); cargoModel.CNTRNO = contaList.FirstOrDefault(a => a.Id == cargo.CtnId).CntrNo; if (string.IsNullOrWhiteSpace(cargo.KindPkgs)) return DataResult.Failed($"多品名包装不能为空!"); long packageId = long.Parse(cargo.KindPkgs); var mapRlt = GetPackageEDICode(packageId, codePackageList, mapPackageList, order.CarrierId, CONST_MAPPING_MODULE); if (codePackageList.Any(b => b.Id == packageId)) cargoModel.KINDPKGS = codePackageList.FirstOrDefault(b => b.Id == packageId).PackageName; if (mapRlt.Succeeded) { cargoModel.KINDPKGS_EDI_CODE = mapRlt.Data; } else { return DataResult.Failed($"货明细的包装{order.KindPkgs}的映射数据代码未找到"); } primaryModel.CTNGOODSLIST.Add(cargoModel); } //这里增加NOR的判断 if (req.SendType == "B" && order.Carrier.Equals("MSK", StringComparison.OrdinalIgnoreCase) && ediRouteEnum == EDIRouteEnum.INTTRA) { //INTTRA 冻代干(箱型出现RF、RH并且是普货的,温度为空时,需要默认温度999) if (contaList.Any(p => p.Ctn.EndsWith("RF") || p.Ctn.EndsWith("RH")) && order.CargoId.Equals("S", StringComparison.OrdinalIgnoreCase) && string.IsNullOrWhiteSpace(order.TemperatureSet)) { primaryModel.TEMPSET = "999"; primaryModel.REEFERF = "999"; //是冻代干 primaryModel.IsNORCtn = true; } } ediModel.BSLIST.Add(primaryModel); var result = await InnerSendBookingOrClosingEDI(req, ediModel, ediRouteEnum, order.CarrierId); _logger.Info("批次={no} 生成EDI文件完成 结果={result}", batchNo, JsonConvert.SerializeObject(result)); if (!result.Succeeded) { return DataResult.Failed(result.Message); } if (order.Carrier.Equals("ONE", StringComparison.OrdinalIgnoreCase)) { //await PrintCarrierOneSOFileAsync(order); } if (req.Send) { /* 2023-05-24 这里新增TSL的判断,如果是走TSL则默认走吴广的外挂,需要提供个人账户 */ string currFilePath = string.Empty; if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { currFilePath = System.Text.RegularExpressions.Regex.Match(result.ExtraData1.ToString(), relativePath.Replace("/", "\\/") + ".*").Value; } else { currFilePath = System.Text.RegularExpressions.Regex.Match(result.ExtraData1.ToString(), relativePath.Replace("\\", "\\\\") + ".*").Value; } string fileTypeCode = "edi"; string fileTypeName = "EDI文件"; if (req.SendType.Equals("E", StringComparison.OrdinalIgnoreCase)) { fileTypeCode = "esi"; fileTypeName = "ESI文件"; } //这里先写入附件表 await SaveEDIFile(req.Id, currFilePath, new System.IO.FileInfo(currFilePath).Name, fileTypeCode, fileTypeName); _logger.Info("批次={no} 直接发送FTP 文件访问地址={filepath}", batchNo, result.ExtraData1.ToString()); DateTime bDate = DateTime.Now; //是否发送邮件,EDI这里主要分2种通道发送 默认是FTP,如果配置里指定了接收接收邮箱,就需要推送邮件 bool isSendEmail = false; //上传FTP EdiDataResult sendStatus = null; //TSL单独走接口 if (ediRouteEnum == EDIRouteEnum.TSL) { sendStatus = await InnerSendBookingOrClosingEDIToPOST(result.ExtraData1.ToString(), postSpiderUrl, userWebAccountConfig); } else { //是订舱并且FTP配置了订舱接收邮箱则触发邮箱发送 if (ftpSet.SendType.Equals("SO", StringComparison.OrdinalIgnoreCase) && req.SendType.Equals("B", StringComparison.OrdinalIgnoreCase) && !string.IsNullOrWhiteSpace(ftpSet.ReceiveEmail)) { isSendEmail = true; } else if (ftpSet.SendType.Equals("SI", StringComparison.OrdinalIgnoreCase) && req.SendType.Equals("E", StringComparison.OrdinalIgnoreCase) && !string.IsNullOrWhiteSpace(ftpSet.ReceiveEmail)) { isSendEmail = true; } else if (string.IsNullOrWhiteSpace(ftpSet.SendType) && !string.IsNullOrWhiteSpace(ftpSet.ReceiveEmail)) { isSendEmail = true; } if (isSendEmail) { //推送订舱邮件 sendStatus = await InnerSendBookingOrClosingEDIToEmail(order, result.ExtraData1.ToString(), req.SendType, result.ExtraData2.ToString(), ftpSet); } else { sendStatus = await InnerSendBookingOrClosingEDIToFTP(result.ExtraData1.ToString(), ftpSet); } } DateTime eDate = DateTime.Now; TimeSpan ts = eDate.Subtract(bDate); var timeDiff = ts.TotalMilliseconds; _logger.Info("批次={no} 发送完成,耗时:{timeDiff}ms. 结果{msg}", batchNo, timeDiff, sendStatus.Succeeded ? "成功" : "失败"); //var logId = await _bookinglog.InsertReturnSnowflakeIdAsync(new BookingLog //{ // Type = "Trace", // BookingId = model.Id, // TenantId = Convert.ToInt64(UserManager.TENANT_ID), // CreatedTime = DateTime.Now, // CreatedUserId = UserManager.UserId, // CreatedUserName = UserManager.Name //}); string sendTypeName = "FTP"; if (isSendEmail) { sendTypeName = "邮件"; } else if (ediRouteEnum == EDIRouteEnum.TSL) { sendTypeName = "POST"; } //await _bookinglogdetail.InsertReturnSnowflakeIdAsync(new BookingLogDetail //{ // PId = logId, // Field = String.Empty, // OldValue = String.Empty, // NewValue = $"发送 {order.CARRIERID} EDI 类型={model.sendType} 通过{sendTypeName} {(sendStatus.succ ? "成功" : "失败")}", //}); if (!sendStatus.Succeeded) { return DataResult.Failed($"发送失败,原因:{sendStatus.Message}"); } //截单 if (req.SendType.Equals("E", StringComparison.OrdinalIgnoreCase)) { //如果是截单需最后推送货物状态 await seaComService.SetGoodsStatus("JD", req.Id, tenantDb); //await SendBookingOrder(new long[] { req.Id }); } } return await Task.FromResult(DataResult.Success(result.ExtraData1.ToString())); //return result.ExtraData1.ToString(); } private async Task SaveEDIFile(long boookId, string FilePath, string fileName, string fileTypeCode = "edi", string fileTypeName = "EDI文件") { var tenantDb = saasService.GetBizDbScopeById(user.TenantId); /* 直接将附件信息写入附件表 */ //EDI文件 var bookFile = new OpFile { FileName = fileName, FilePath = FilePath, TypeCode = fileTypeCode, TypeName = fileTypeName, LinkId = boookId, }; await tenantDb.Insertable(bookFile).ExecuteCommandAsync(); } #region 下载订舱、截单EDI /// /// 下载订舱、截单EDI /// /// /// public async Task> DownloadBookingOrClosingEDI(BookingOrClosingEDIOrderReq req) { var tenantDb = saasService.GetBizDbScopeById(user.TenantId); var order = tenantDb.Queryable().First(x => x.Id == req.Id); var FORWARDER =seaComService.GetClientCode(order.ForwarderId, tenantDb); var dictvalue = db.Queryable().InnerJoin((a, b) => a.TypeId == b.Id) .Where((a, b) => b.Code == "XiangManCang").Select((a, b) => a.Value).First(); _logger.Info("FORWARDER:" + FORWARDER + "dictvalue:" + dictvalue); if (!string.IsNullOrEmpty(FORWARDER) && dictvalue == FORWARDER) { return await XMCEXCEL(req.Id, true); } var res = await InnerBookingOrClosingEDI(req); if (!res.Succeeded) { return await Task.FromResult(DataResult.Failed(res.Message)); } var filePath = res.Data; //var filePath = InnerBookingOrClosingEDI(req).GetAwaiter().GetResult().Data; var fileInfo = new FileInfo(filePath); //var result = new FileStreamResult(new FileStream(filePath, FileMode.Open), "application/octet-stream") { FileDownloadName = fileInfo.Name }; //return result; var data = new OpFileDownLoadRes() { FileName = fileInfo.Name, FilePath = filePath, }; return await Task.FromResult(DataResult.Success(data)); } #endregion #region 检查订舱、截单EDI订单信息 /// /// 检查订舱、截单EDI订单信息 /// /// 订舱详情 /// 集装箱列表 /// 发送类型 B-订舱 E-截单 /// EDI路由枚举 /// private DataResult CheckBookingOrClosingEDI(SeaExport order, List ctnList,string sendType, EDIRouteEnum ediRouteEnum) { if (string.IsNullOrWhiteSpace(order.Carrier)) return DataResult.Failed("船公司必须填写!"); //if (string.IsNullOrWhiteSpace(order.OPID)) // throw Oops.Bah("未填写操作人"); if (!(ediRouteEnum == EDIRouteEnum.INTTRA && sendType.Equals("B"))) { if (string.IsNullOrWhiteSpace(order.KindPkgs)) return DataResult.Failed("包装种类未填写!"); } //增加箱包装和主信息的包装是否一致校验 if (!string.IsNullOrWhiteSpace(order.KindPkgs) && ctnList.Any(a => !string.IsNullOrWhiteSpace(a.KindPkgs))) { if (ctnList.Any(a => a.KindPkgs != order.KindPkgs)) { return DataResult.Failed("集装箱包装和订舱包装不一致,请修改!"); } } //如果合同协议号不为空需要判断是否字符前、后有空格,不允许字符前后有空格,需要提示修改 if (!string.IsNullOrWhiteSpace(order.ContractNo)) { if (order.ContractNo.StartsWith(" ")) return DataResult.Failed("运费协议号前含有空格,请修改!"); if (order.ContractNo.EndsWith(" ")) return DataResult.Failed("运费协议号后含有空格,请修改!"); } //只有截单时验证箱明细的件重尺合计与总数一致 if (sendType.Equals("E")) { //增加件、重、尺比对 if (ctnList != null && ctnList.Count > 0) { if (ctnList.Sum(a => a.PKGS.HasValue ? a.PKGS.Value : 0) != (order.PKGS.HasValue ? order.PKGS.Value : 0)) { return DataResult.Failed("集装箱件数合计和订舱件数不一致,请修改!"); } if (ctnList.Sum(a => a.KGS.HasValue ? a.KGS.Value : 0) != (order.KGS.HasValue ? order.KGS.Value : 0)) { return DataResult.Failed("集装箱重量合计和订舱重量不一致,请修改!"); } if (ctnList.Sum(a => a.CBM.HasValue ? a.CBM.Value : 0) != (order.CBM.HasValue ? order.CBM.Value : 0)) { return DataResult.Failed("集装箱尺码合计和订舱尺码不一致,请修改!"); } } } return DataResult.Success("验证成功!"); } #endregion #region 上传邮件 /// /// 上传邮件 /// /// 订舱详情 /// 文件路径 /// 请求类型 /// EDI配置 /// 返回回执 private async Task InnerSendBookingOrClosingEDIToEmail(SeaExport bookingOrder, string filePath, string sendType, string emailTopic, CodeEdiSet ediCfg) { var result = new EdiDataResult { Succeeded = true }; var emailUrl = db.Queryable().Filter(null, true).Where(x => x.Code == "email_api_url" && x.TenantId == 1288018625843826688).First().Value; //var emailUrl = _cache.GetAllDictData().GetAwaiter().GetResult() // .FirstOrDefault(x => x.TypeCode == "url_set" && x.Code == "email_api_url")?.Value; if (emailUrl == null) { result.Succeeded = false; result.Message = "系统参数未配置email_api_url 请联系管理员"; return await Task.FromResult(result); } List emailList = new List(); EmailApiDto emailApiDto = new EmailApiDto { SendTo = ediCfg.ReceiveEmail, Title = emailTopic, Attaches = new List(), Body = emailTopic, }; 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); emailApiDto.Attaches.Add(new AttachesInfo { AttachName = Path.GetFileName(filePath), AttachContent = base64Str }); emailList.Add(emailApiDto); string strJoin = System.IO.File.ReadAllText(filePath); DateTime bDate = DateTime.Now; string res = null; try { res = RequestHelper.Post(JsonConvert.SerializeObject(emailList), emailUrl); //res = await emailUrl.SetBody(emailList, "application/json").PostAsync(); } catch (Exception ex) { _logger.Info($"发送邮件异常:{ex.Message}"); } DateTime eDate = DateTime.Now; TimeSpan ts = eDate.Subtract(bDate); var timeDiff = ts.TotalMilliseconds; _logger.Info($"邮件上传完成 上传文件大小:{heByte.Length} 用时:{timeDiff}ms.,{strJoin}"); _logger.Info($"发送邮件返回:{JsonConvert.SerializeObject(res)}"); //if (res != null && res.StatusCode == System.Net.HttpStatusCode.OK) //{ // var userResult = await res.Content.ReadAsStringAsync(); // var respObj = JsonConvert.DeserializeAnonymousType(userResult, new // { // Success = false, // Message = string.Empty, // Code = -9999, // }); // result.Succeeded = respObj.Success; // result.Message = respObj.Message; //} if (res != null) { var respObj = JsonConvert.DeserializeAnonymousType(res, new { Success = false, Message = string.Empty, Code = -9999, }); result.Succeeded = respObj.Success; result.Message = respObj.Message; } return await Task.FromResult(result); //return result; } #endregion #region 上传FTP /// /// 上传FTP /// /// EDI文件路径 /// FTP配置 /// 返回回执 private async Task InnerSendBookingOrClosingEDIToFTP(string filePath, CodeEdiSet ediCfg) { EdiDataResult result = new EdiDataResult { Succeeded = true }; CancellationTokenSource cts = new CancellationTokenSource(); string host = string.Empty; string port = string.Empty; if (ediCfg.ServerIp.IndexOf(":") >= 0) { host = ediCfg.ServerIp.Split(new char[] { ':' }).FirstOrDefault().Trim(); port = ediCfg.ServerIp.Split(new char[] { ':' }).Last()?.Trim(); } _logger.Info($"FTP参数:{JsonConvert.SerializeObject(ediCfg)}"); NameValueCollection par = new NameValueCollection(); par.Add("host", host); //这里如果配置没有指定端口号默认是21端口 par.Add("port", string.IsNullOrWhiteSpace(port) ? "21" : port); par.Add("username", ediCfg.UserName); par.Add("pwd", ediCfg.Password); par.Add("path", ediCfg.FolderName); var ftpSpiderUrl = db.Queryable().Filter(null, true).Where(x => x.Code == "booking_edi_ftp_server" && x.TenantId == 1288018625843826688).First().Value; if (ftpSpiderUrl == null) return await Task.FromResult(EdiDataResult.Failed("系统未配置booking_edi_ftp_server 请联系管理员!")); //var fileInfo = new FileInfo(filePath); _logger.Info($"准备请求发送ftp:{ftpSpiderUrl} ,参数:{JsonConvert.SerializeObject(par)},文件:{filePath}"); 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 strJoin = System.IO.File.ReadAllText(filePath); DateTime bDate = DateTime.Now; _logger.Info("FTP 开始上传"); var res = FTPHelper.TransmitFtpFile(ftpSpiderUrl, par, new { file = "file", fileName = Path.GetFileName(filePath), fileBytes = heByte }); DateTime eDate = DateTime.Now; TimeSpan ts = eDate.Subtract(bDate); var timeDiff = ts.TotalMilliseconds; _logger.Info($"FTP 上传完成 上传文件大小:{heByte.Length} 用时:{timeDiff}ms.,{strJoin}"); _logger.Info($"发送ftp返回:{res}"); var jobjRetn = JObject.Parse(res); if (jobjRetn.GetStringValue("status") != "1") { result.Succeeded = false; result.Message = jobjRetn.GetStringValue("message"); } return await Task.FromResult(result); //return result; } #endregion /// /// EDI发送POST请求 /// /// 文件路径 /// 请求URL /// 配置账户 /// 返回回执 private async Task InnerSendBookingOrClosingEDIToPOST(string filePath, string url, CodeThirdParty accountConfig) { CancellationTokenSource cts = new CancellationTokenSource(); var userKey = db.Queryable().Filter(null, true).Where(x => x.Code == "BCOrDraftUserKey" && x.TenantId == 1288018625843826688).First(); var userPwd = db.Queryable().Filter(null, true).Where(x => x.Code == "BCOrDraftUserSecret" && x.TenantId == 1288018625843826688).First(); if (userKey.IsNull()) { return await Task.FromResult(EdiDataResult.Failed("请配置相关账号!")); } if (userPwd.IsNull()) { return await Task.FromResult(EdiDataResult.Failed("请配置相关密钥!")); } NameValueCollection par = new NameValueCollection(); //par.Add("user_key", App.Configuration["BCOrDraftUserKey"]); //par.Add("user_secret", App.Configuration["BCOrDraftUserSecret"]); par.Add("user_key", userKey.Value); par.Add("user_secret", userPwd.Value); par.Add("web_user", accountConfig.AppKey?.Trim()); par.Add("web_psw", accountConfig.AppSecret?.Trim()); _logger.Info($"准备请求发送POST:{url} ,参数:{JsonConvert.SerializeObject(par)},文件:{filePath}"); 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 strJoin = System.IO.File.ReadAllText(filePath); DateTime bDate = DateTime.Now; _logger.Info("POST 开始上传"); var res = CommonFTPHelper.TransmitFtpFile(url, par, new { file = "file", fileName = Path.GetFileName(filePath), fileBytes = heByte }); DateTime eDate = DateTime.Now; TimeSpan ts = eDate.Subtract(bDate); var timeDiff = ts.TotalMilliseconds; _logger.Info($"请求POST 上传完成 上传文件大小:{heByte.Length} 用时:{timeDiff}ms.,{strJoin}"); _logger.Info($"发送POST返回:{res}"); var jobjRetn = JObject.Parse(res); if (jobjRetn.GetStringValue("code") != "200") { return await Task.FromResult(EdiDataResult.Failed(jobjRetn.GetStringValue("msg"))); } else { return await Task.FromResult(EdiDataResult.Success("请求成功!")); } } #region 触发订舱 /// /// 触发订舱 /// /// /// /// /// private async Task InnerSendBookingOrClosingEDI(BookingOrClosingEDIOrderReq req, EDIBaseModel ediModel, EDIRouteEnum ediRouteEnum,long carrierId) { var result = new EdiDataResult(); var tenantDb = saasService.GetBizDbScopeById(user.TenantId); try { if (ediRouteEnum == EDIRouteEnum.PIL) { #region PIL string strCheck = PILEdiHelper.IsCreatePILEDI(ediModel); _logger.Info($"调用SO(SI),校验:{strCheck},数据对象:{JsonConvert.SerializeObject(ediModel)}"); if (!string.IsNullOrWhiteSpace(strCheck)) { if (Regex.IsMatch(strCheck, "\\")) { strCheck = Regex.Replace(strCheck, "\\", "\n"); } throw new Exception($"发送{EDIRouteEnum.PIL.ToString()}校验失败,{strCheck}"); } var currRlt = PILEdiHelper.CreateEdiPIL(ediModel); #endregion result.Succeeded = currRlt.Succeeded; result.ExtraData1 = currRlt.Succeeded ? currRlt.ExtraData1.ToString() : ""; result.ExtraData2 = currRlt.Succeeded ? currRlt.ExtraData2.ToString() : ""; //return await Task.FromResult(currRlt); } else if (ediRouteEnum == EDIRouteEnum.TSL) { #region TSL string strCheck = TSLEdiHelper.IsCreateTSL(ediModel); _logger.Info($"调用SO(SI),校验:{strCheck},数据对象:{JsonConvert.SerializeObject(ediModel)}"); if (!string.IsNullOrWhiteSpace(strCheck)) { if (Regex.IsMatch(strCheck, "\\")) { strCheck = Regex.Replace(strCheck, "\\", "\n"); } throw new Exception($"发送{EDIRouteEnum.TSL.ToString()}校验失败,{strCheck}"); } var currRlt = new EdiDataResult(); if (req.SendType == "B") { currRlt = TSLEdiHelper.CreateEdiTSL(ediModel); } else if (req.SendType == "E") { currRlt = TSLEdiHelper.CreateEdiTSLSI(ediModel); } #endregion result.Succeeded = currRlt.Succeeded; result.ExtraData1 = currRlt.Succeeded ? currRlt.ExtraData1.ToString() : ""; } else if (ediRouteEnum == EDIRouteEnum.WY) { #region WY string strCheck = WYEdiHelper.IsCreateWYEDI(ediModel); _logger.Info($"调用SO(SI),校验:{strCheck},数据对象:{JsonConvert.SerializeObject(ediModel)}"); if (!string.IsNullOrWhiteSpace(strCheck)) { if (Regex.IsMatch(strCheck, "\\")) { strCheck = Regex.Replace(strCheck, "\\", "\n"); } throw new Exception($"发送{EDIRouteEnum.WY.ToString()}校验失败,{strCheck}"); } var currRlt = WYEdiHelper.CreateEdiWY(ediModel); #endregion result.Succeeded = currRlt.Succeeded; result.ExtraData1 = currRlt.Succeeded ? currRlt.ExtraData1.ToString() : ""; } else if (ediRouteEnum == EDIRouteEnum.YML) { #region YML string strCheck = YMLEdiHelper.IsCreateYMLEDI(ediModel); _logger.Info($"调用SO(SI),校验:{strCheck},数据对象:{JsonConvert.SerializeObject(ediModel)}"); if (!string.IsNullOrWhiteSpace(strCheck)) { if (Regex.IsMatch(strCheck, "\\")) { strCheck = Regex.Replace(strCheck, "\\", "\n"); } throw new Exception($"发送{EDIRouteEnum.YML.ToString()}校验失败,{strCheck}"); } var currRlt = new EdiDataResult(); if (req.SendType == "B") { currRlt = YMLEdiHelper.CreateEdiYML(ediModel); } else if (req.SendType == "E") { currRlt = YMLEdiHelper.CreateEdiYMLSI(ediModel); } #endregion result.Succeeded = currRlt.Succeeded; result.ExtraData1 = currRlt.Succeeded ? currRlt.ExtraData1.ToString() : ""; } else if (ediRouteEnum == EDIRouteEnum.YT) { #region YT string strCheck = YTEdiHelper.IsCreateYTEDI(ediModel); _logger.Info($"调用SO(SI),校验:{strCheck},数据对象:{JsonConvert.SerializeObject(ediModel)}"); if (!string.IsNullOrWhiteSpace(strCheck)) { if (Regex.IsMatch(strCheck, "\\")) { strCheck = Regex.Replace(strCheck, "\\", "\n"); } throw new Exception($"发送{EDIRouteEnum.YT.ToString()}校验失败,{strCheck}"); } var currRlt = YTEdiHelper.CreateEdiYT(ediModel); #endregion result.Succeeded = currRlt.Succeeded; result.ExtraData1 = currRlt.Succeeded ? currRlt.ExtraData1.ToString() : ""; } else if (ediRouteEnum == EDIRouteEnum.ESL) { #region ESL string strCheck = ESLEdiHelper.IsCreateESLEDI(ediModel); _logger.Info($"调用SO(SI),校验:{strCheck},数据对象:{JsonConvert.SerializeObject(ediModel)}"); if (!string.IsNullOrWhiteSpace(strCheck)) { if (Regex.IsMatch(strCheck, "\\")) { strCheck = Regex.Replace(strCheck, "\\", "\n"); } throw new Exception($"发送{EDIRouteEnum.ESL.ToString()}校验失败,{strCheck}"); } var currRlt = ESLEdiHelper.CreateEdiESL(ediModel); #endregion result.Succeeded = currRlt.Succeeded; result.ExtraData1 = currRlt.Succeeded ? currRlt.ExtraData1.ToString() : ""; } else if (ediRouteEnum == EDIRouteEnum.MELL) { #region MELL string strCheck = MellEdiHelper.IsCreatePILMELL(ediModel); _logger.Info($"调用SO(SI),校验:{strCheck},数据对象:{JsonConvert.SerializeObject(ediModel)}"); if (!string.IsNullOrWhiteSpace(strCheck)) { if (Regex.IsMatch(strCheck, "\\")) { strCheck = Regex.Replace(strCheck, "\\", "\n"); } throw new Exception($"发送{EDIRouteEnum.MELL.ToString()}校验失败,{strCheck}"); } var currRlt = MellEdiHelper.CreateEdiPILMELL(ediModel); #endregion result.Succeeded = currRlt.Succeeded; result.ExtraData1 = currRlt.Succeeded ? currRlt.ExtraData1.ToString() : ""; result.ExtraData2 = currRlt.Succeeded ? currRlt.ExtraData2.ToString() : ""; } else if (ediRouteEnum == EDIRouteEnum.INTTRA) { //这里INTTRA单独取了船公司 var ediSOSICfg = tenantDb.Queryable().First(t => t.Module.Equals(CONST_MAPPING_MODULE_INTTRA, StringComparison.OrdinalIgnoreCase) && t.LinkId == carrierId); if (ediSOSICfg == null || string.IsNullOrWhiteSpace(ediSOSICfg.MapCode)) throw new Exception($"CARRIERID={ediModel.BSLIST.FirstOrDefault().CARRIERID} INTTRA EDI订舱和截单 的船公司EDI代码未找到"); ediModel.BSLIST.FirstOrDefault().CARRIEREDICODE = ediSOSICfg.MapCode; #region INTTRA string strCheck = InttraEdiHelper.IsCreateINTTR(ediModel); _logger.Info($"调用SO(SI),校验:{strCheck},数据对象:{JsonConvert.SerializeObject(ediModel)}"); if (!string.IsNullOrWhiteSpace(strCheck)) { if (Regex.IsMatch(strCheck, "\\")) { strCheck = Regex.Replace(strCheck, "\\", "\n"); } throw new Exception($"发送{EDIRouteEnum.INTTRA.ToString()}校验失败,{strCheck}"); } var currRlt = new EdiDataResult(); if (req.SendType == "B") { currRlt = InttraEdiHelper.CreateEdiINTTR(ediModel); } else if (req.SendType == "E") { currRlt = InttraEdiHelper.CreateEdiINTTRSI(ediModel); } #endregion result.Succeeded = currRlt.Succeeded; result.ExtraData1 = currRlt.Succeeded ? currRlt.ExtraData1.ToString() : ""; } } catch (Exception ex) { result.Succeeded = false; result.Message = ex.Message; } return result; } #endregion #region 检索港口的EDI代码 /// /// 检索港口的EDI代码 /// /// 港口ID /// 港口基础表 /// 港口映射表 /// 船公司ID /// 模块代码 /// 港口名称 /// 港口分类(装货港、卸货港、交货地等) /// 是否必需用映射 /// /// private DataResult GetPortEDICode(long portId,List codePortList,List mapPortList, long carrierId, string moduleName, string portName,string portCategory,string needMappingModule = "") { //如果历史港口映射有记录直接返回 if (mapPortList.Any(a => a.LinkId == portId)) { var edi = mapPortList.FirstOrDefault(a => a.LinkId == portId).MapCode; if (!string.IsNullOrWhiteSpace(edi)) return DataResult.Success(edi); return DataResult.FailedData(edi); } var tenantDb = saasService.GetBizDbScopeById(user.TenantId); string MappingModule = CONST_MAPPING_MODULE; if (!string.IsNullOrWhiteSpace(needMappingModule)) { MappingModule = needMappingModule; } var mapPortInfo = tenantDb.Queryable() .First(a => a.Module.Equals(MappingModule, StringComparison.OrdinalIgnoreCase) && a.CarrierId == carrierId && a.LinkId == portId); if (mapPortInfo != null) { mapPortList.Add(mapPortInfo); if (!string.IsNullOrWhiteSpace(mapPortInfo.MapCode)) return DataResult.Success(mapPortInfo.MapCode); return DataResult.FailedData(mapPortInfo.MapCode); } //else //{ // if (!string.IsNullOrWhiteSpace(needMappingModule)) // throw new Exception($"{portCategory} {portName} 未配置模块{needMappingModule} 映射"); //} if (codePortList.Any(a => a.Id == portId)) { var edi = codePortList.FirstOrDefault(a => a.Id == portId).EdiCode; if (!string.IsNullOrWhiteSpace(edi)) return DataResult.Success(edi); return DataResult.FailedData(edi); } var loadPortCodeRlt = seaComService.GetPortInfo(portId, tenantDb).GetAwaiter().GetResult(); if (!loadPortCodeRlt.Succeeded) { throw new Exception($"{portCategory} {portName}的港口基础代码未找到"); } codePortList.Add(loadPortCodeRlt.Data); if (!string.IsNullOrWhiteSpace(loadPortCodeRlt.Data?.EdiCode)) return DataResult.Success(loadPortCodeRlt.Data?.EdiCode); return DataResult.FailedData(loadPortCodeRlt.Data?.EdiCode); } #endregion #region 检索集装箱型EDI代码 /// /// 检索集装箱型EDI代码 /// /// 集装箱型ID /// 集装箱基础表 /// 集装箱映射表 /// 船公司ID /// 模块代码 /// 集装箱名称 /// private DataResult GetCtnEDICode(string ctnCode, List codeCtnList, List mapCtnList, long carrierId, string moduleName , string ctnName, EDIRouteEnum ediRouteEnum) { CodeCtn codeCtnInfo = null; var tenantDb = saasService.GetBizDbScopeById(user.TenantId); if (codeCtnList.Any(a => a.EdiCode == ctnCode)) { codeCtnInfo = codeCtnList.FirstOrDefault(a => a.EdiCode == ctnCode); } if (codeCtnInfo == null) { codeCtnInfo = tenantDb.Queryable().First(a => a.EdiCode == ctnCode && a.Status == StatusEnum.Enable); if (codeCtnInfo != null) { codeCtnList.Add(codeCtnInfo); } else { throw new Exception($"集装箱 {ctnName} 基础代码未找到"); } } //如果历史港口映射有记录直接返回 if (mapCtnList.Any(a => a.LinkId == codeCtnInfo.Id)) { var edi = mapCtnList.FirstOrDefault(a => a.LinkId == codeCtnInfo.Id).MapCode; if (!string.IsNullOrWhiteSpace(edi)) return DataResult.Success(edi); return DataResult.FailedData(edi); } MappingCtn mapCtnInfo = null; //如果是亿通需要读映射表,如果映射表没配置则提示错误 if(ediRouteEnum == EDIRouteEnum.YT) { mapCtnInfo = tenantDb.Queryable() .First(a => a.Module.Equals("BOOK_OR_CLOSING_YT", StringComparison.OrdinalIgnoreCase) && a.CarrierId == carrierId && a.LinkId == codeCtnInfo.Id); if (mapCtnInfo == null) { throw new Exception($"集装箱型 {ctnName} 未配置订舱或截单EDT(亿通)的映射代码未找到"); } } else { mapCtnInfo = tenantDb.Queryable() .First(a => a.Module.Equals(CONST_MAPPING_MODULE, StringComparison.OrdinalIgnoreCase) && a.CarrierId == carrierId && a.LinkId == codeCtnInfo.Id); } if (mapCtnInfo != null) { mapCtnList.Add(mapCtnInfo); if (!string.IsNullOrWhiteSpace(mapCtnInfo.MapCode)) return DataResult.Success(mapCtnInfo.MapCode); throw new Exception($"集装箱型 {ctnName}的映射代码未找到"); } else { if (codeCtnInfo != null && !string.IsNullOrWhiteSpace(codeCtnInfo.EdiCode)) { return DataResult.Success(codeCtnInfo.EdiCode); } throw new Exception($"集装箱型 {ctnName}基础代码EDI 错误"); } } #endregion #region 检索包装EDI代码 /// /// 检索包装EDI代码 /// /// 包装ID /// 包装基础表 /// 包装映射表 /// 船公司ID /// 模块代码 /// 包装名称 /// private DataResult GetPackageEDICode(long packageCodeId, List codePackageList, List mapPackageList, long carrierId, string moduleName) { var tenantDb = saasService.GetBizDbScopeById(user.TenantId); if (!codePackageList.Any(b => b.Id == packageCodeId)) { var codePackage = tenantDb.Queryable().First(a => a.Id == packageCodeId); if (codePackage != null) codePackageList.Add(codePackage); } //如果历史港口映射有记录直接返回 if (mapPackageList.Any(a => a.LinkId == packageCodeId)) { var edi = mapPackageList.FirstOrDefault(a => a.LinkId == packageCodeId).MapCode; if (!string.IsNullOrWhiteSpace(edi)) return DataResult.Success(edi); //return DataResult.FailedData(edi); } //优先判断跟船公司设置包装映射,如果没有取默认映射 var mapPackageInfo = tenantDb.Queryable() .First(a => a.Module.Equals(CONST_MAPPING_MODULE, StringComparison.OrdinalIgnoreCase) && a.CarrierId == carrierId && a.LinkId == packageCodeId); if (mapPackageInfo != null) { mapPackageList.Add(mapPackageInfo); if (!string.IsNullOrWhiteSpace(mapPackageInfo.MapCode)) return DataResult.Success(mapPackageInfo.MapCode); //return DataResult.FailedData(mapPackageInfo.MapCode); throw new Exception($"包装的映射代码未找到"); } else { var codePackage = codePackageList.FirstOrDefault(b => b.Id == packageCodeId); if(codePackage != null && !string.IsNullOrWhiteSpace(codePackage.EdiCode)) { return DataResult.Success(codePackage.EdiCode); } throw new Exception($"包装的基础信息EDI代码未找到"); } //else //{ // //} } #endregion #region 推送东胜(MQ) /// /// 推送东胜(MQ) /// /// 海运订单主键数组 /// public async Task SendBookingOrder(long[] ids) { var logTitle = $"同步订舱数据,ids:{string.Join(',', ids.ToList())},"; _logger.Info($"开始{logTitle}"); var BookingOrderMQUri = AppSetting.app(new string[] { "SyncDongSheng7", "MQConfig" }); var paramConfig = _configService.GetConfig(CONST_AUTO_SYNC_DONGSHENG_BY_MQ, long.Parse(user.TenantId), false).GetAwaiter().GetResult()?.Data?.Value; _logger.Info($"{logTitle}订舱数据回推地址:{BookingOrderMQUri},{CONST_AUTO_SYNC_DONGSHENG_BY_MQ}:{paramConfig}"); var tenantDb = saasService.GetBizDbScopeById(user.TenantId); if (!string.IsNullOrEmpty(paramConfig) && paramConfig.Equals("ENABLE", StringComparison.OrdinalIgnoreCase)) { if (ids.Count() == 0) { _logger.Info($"{logTitle}请求参数错误,未提供上传订单的主键,结束"); throw new Exception("请求参数错误,未提供上传订单的主键"); } var order = await tenantDb.Queryable().Filter(null, true).Where(x => ids.Contains(x.Id) && x.Deleted == false).ToListAsync(); if (order.Count == 0) { _logger.Info($"{logTitle}未查到订舱数据,结束"); return DataResult.Failed($"{logTitle}未查到订舱数据,结束"); } foreach (var item in order) { //2023-9-8,增加校验,分单不能单独推送东胜,只能随主单推送 if (item.ParentId > 0) { _logger.Info($"Id:{item.Id},分单不能单独推送东胜,只能随主单推送,continue跳过"); continue; } //2023-9-26,添加校验:推送前通过Cache判断一下待推送的数据是否正在走删除逻辑 if (_redisBaseService.Exists($"DeletingBookingOrderId_{item.Id}")) { _logger.Info($"Id:{item.Id},正在走删除逻辑,continue跳过"); continue; } var dto = item.Adapt(); //if (syncTypeEnum != null) //{ // dto.SyncType = syncTypeEnum.ToString(); //} if (!string.IsNullOrWhiteSpace(dto.YARDREMARK)) { dto.YARDREMARK += "\\n" + item.BookingSlotTypeName; } else { dto.YARDREMARK = item.BookingSlotTypeName; } List statusList = new List(); EmbedQueryServiceProjectWithStatus queryInfo = new EmbedQueryServiceProjectWithStatus { BusinessId = item.Id.ToString(), QueryType = 2, TenantId = long.Parse(user.TenantId) }; var queryRlt = await _djyServiceStatusService.GetServiceStatusList(queryInfo); if (queryRlt.success) { statusList = JsonConvert.DeserializeObject>(JsonConvert.SerializeObject(queryRlt.data)); } if (statusList != null && statusList.Any(x => x.StatusSKUCode == "SQXS" && x.IsYield)) { dto.CtnDayNum = statusList.FirstOrDefault(x => x.StatusSKUCode == "SQXS" && x.IsYield)?.ActVal; } var ctn = await tenantDb.Queryable().Filter(null, true).Where(x => x.BSNO == item.Id.ToString() && x.Deleted == false).ToListAsync(); dto.ctnInputs = ctn.Adapt>(); foreach (var it in dto.ctnInputs) { var ctnDetailInputs = await tenantDb.Queryable().Filter(null, true).Where(x => x.CtnId == it.Id && x.Deleted == false).ToListAsync(); it.ctnDetailInputs = ctnDetailInputs.Adapt>(); } //2024-06-20 这里如果遇到拆票情况需要重新组织提单号 if (item.SplitOrMergeFlag == 1 || item.SplitOrMergeFlag == 2) { dto.MBLNO = $"{item.MBLNO}-{item.HBLNO}"; //如果当前是合票时,需要所有子票的箱型箱量合并到主票同步到东胜,子票的箱型箱量不同步东胜 if (item.SplitOrMergeFlag == 2) { //如果当前是主票 if (dto.CUSTNO.Equals(dto.HBLNO, StringComparison.OrdinalIgnoreCase)) { var allOrderList = await tenantDb.Queryable().Filter(null, true).Where(x => dto.HBLNO == x.HBLNO && (x.SplitOrMergeFlag == 2) && x.Deleted == false).ToListAsync(); if (allOrderList.Count > 0) { var allOrderIds = allOrderList.Select(x => x.Id).ToList(); var currCtn = await tenantDb.Queryable().Filter(null, true).Where(x => x.BSNO != null && allOrderIds.Contains(long.Parse(x.BSNO)) && x.Deleted == false).ToListAsync(); dto.ctnInputs = currCtn.Adapt>(); foreach (var it in dto.ctnInputs) { var ctnDetailInputs = await tenantDb.Queryable().Filter(null, true).Where(x => x.CtnId == it.Id && x.Deleted == false).ToListAsync(); it.ctnDetailInputs = ctnDetailInputs.Adapt>(); } dto.CNTRTOTAL = string.Join(",", dto.ctnInputs.GroupBy(x => x.CTNALL).Select(x => $"{x.Key}*{x.Sum(b => b.CTNNUM)}").ToArray()); } } else { dto.ctnInputs = new List(); dto.CNTRTOTAL = string.Empty; } } } //EDI var BookingEDIExt = await tenantDb.Queryable().Filter(null, true).Where(x => x.BusinessId == item.Id && x.Deleted == false).FirstAsync(); if (BookingEDIExt != null) { dto.BookingEDIExt = BookingEDIExt.Adapt(); } if (statusList != null && statusList.Any(x => x.IsYield)) { dto.GoodsStatus = statusList.Where(x => x.IsYield).OrderBy(x => x.SortNo).Select(x => new BookingGoodsStatusDto { StatusName = x.ShowName, FinishTime = x.ActDate, Remark = x.ActRemark, ExtData = x.ActVal }).ToList(); } else { dto.GoodsStatus = new List(); } //等拓展数据 var extData = await tenantDb.Queryable().Filter(null, true).FirstAsync(x => x.BusinessId == item.Id); if (extData != null) { dto.ExtendState = extData.Adapt(); } //提箱返场 var statusloglist = tenantDb.Queryable().Filter(null, true).Where(x => x.BusinessId == item.Id && x.Deleted == false && x.Group == "yunzong").ToList(); var statuslogId = statusloglist.Select(x => x.Id).ToList(); //运踪状态详情 var statuslogdetaillist = tenantDb.Queryable().Where(x => statuslogId.Contains(x.PId)).ToList(); var staLogListDto = statusloglist.Adapt>(); dto.StatusLogs = staLogListDto; foreach (var sl in dto.StatusLogs) { var detailList = statuslogdetaillist.Where(x => x.PId == sl.Id).ToList(); sl.Details = detailList.Adapt>(); } var childrens = await tenantDb.Queryable().Filter(null, true).Where(x => x.ParentId == item.Id && x.Deleted == false).ToListAsync(); dto.childrens = childrens.Adapt>(); var files = await tenantDb.Queryable().Filter(null, true).Where(x => x.LinkId == item.Id).ToListAsync(); dto.Files = files.Select(x => new DownloadFile() { Id = x.Id, FileName = x.FileName, FileType = x.TypeCode, FilePath = x.FilePath }).ToList(); foreach (var childitem in dto.childrens) { var ctnInputs = await tenantDb.Queryable().Filter(null, true).Where(x => x.BSNO == childitem.Id.ToString() && x.Deleted == false).ToListAsync(); childitem.ctnInputs = ctnInputs.Adapt>(); foreach (var it in childitem.ctnInputs) { var ctnDetailInputs = await tenantDb.Queryable().Filter(null, true).Where(x => x.CtnId == it.Id && x.Deleted == false).ToListAsync(); it.ctnDetailInputs = ctnDetailInputs.Adapt>(); } var childBookingEDIExt = await tenantDb.Queryable().Filter(null, true).Where(x => x.BusinessId == childitem.Id && x.Deleted == false).FirstAsync(); if (childBookingEDIExt != null) { childitem.BookingEDIExt = childBookingEDIExt.Adapt(); } } var json = dto.ToJsonString(); json = $"[{json}]"; _logger.Info($"Id:{item.Id},订舱数据回推,消息内容:{json}"); string MqActionExchangeName = AppSetting.app(new string[] { "SyncDongSheng7", "MQExchangeNameDingCang" }); //djy.output.dingcang.ds6 string MqActionQueueName = AppSetting.app(new string[] { "SyncDongSheng7", "MQQueueNameDingCang" }); //djy.output.dingcang.ds6 var mqRlt = await _rabbitMQService.PublishMessage(new Module.MQ.MQPublishMessageReqDto { BusinessId = item.Id.ToString(), IsZip = true, json = JsonConvert.SerializeObject(dto), mqUri = BookingOrderMQUri, mqExchangeName = MqActionExchangeName, mqQueueName = $"{MqActionQueueName}.{user.TenantId}" }); if (!mqRlt.Succeeded) { _logger.Info(mqRlt.Message); } await SendLetterYard(item.Id); } return DataResult.Successed("同步完成"); } else { _logger.Info($"当前未开启同步东胜功能,需要开通请在系统参数增加【自动同步订单到东胜7通过MQ】AutoSyncBookingOrderToDongshengMQ"); } return DataResult.Failed($"当前未开启同步东胜功能,需要开通请在系统参数增加【自动同步订单到东胜7通过MQ】AutoSyncBookingOrderToDongshengMQ"); } #endregion #region 放舱推送东胜 /// /// 放舱推送东胜 /// /// public async Task SendLetterYard(long bookingId) { var tenantDb = saasService.GetBizDbScopeById(user.TenantId); var entity = tenantDb.Queryable().Filter(null, true).First(x => x.BusinessId == bookingId && x.Deleted == false); if (entity != null) { var json = entity.ToJsonString(); var BookingOrderMQUri = AppSetting.app(new string[] { "SyncDongSheng7", "MQConfig" }); string MqActionExchangeName = AppSetting.app(new string[] { "SyncDongSheng7", "MQExchangeNameFangCang" }); //djy.output.dingcang.ds6 string MqActionQueueName = AppSetting.app(new string[] { "SyncDongSheng7", "MQQueueNameFangCang" }); //djy.output.dingcang.ds6 var mqRlt = await _rabbitMQService.PublishMessage(new Module.MQ.MQPublishMessageReqDto { BusinessId = entity.BusinessId.ToString(), IsZip = false, json = JsonConvert.SerializeObject(entity), mqUri = BookingOrderMQUri, mqExchangeName = MqActionExchangeName, mqQueueName = $"{MqActionQueueName}.{user.TenantId}" }); if (!mqRlt.Succeeded) { _logger.Info(mqRlt.Message); } _logger.Info($"放舱数据回推,已发送数据到消息队列【{BookingOrderMQUri}】,数据内容:【{json}】 结果={mqRlt.Message}"); return mqRlt; } else { return DataResult.Failed($"bookingId={bookingId} 放舱信息获取失败"); } } #endregion } }