using DS.Module.Core; using DS.Module.Core.Data; using DS.Module.Core.Helpers; using DS.Module.SqlSugar; using DS.Module.UserModule; using DS.WMS.Core.Code.Entity; using DS.WMS.Core.Map.Entity; using DS.WMS.Core.Op.Dtos; using DS.WMS.Core.Op.Dtos.Cargoo; using DS.WMS.Core.Op.Entity; using DS.WMS.Core.Op.Interface; using DS.WMS.Core.Sys.Interface; using DS.WMS.Core.Sys.Method; using Microsoft.Extensions.DependencyInjection; using Newtonsoft.Json; using SharpCompress.Common; using SqlSugar; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using NLog; using DS.Module.Core.Constants; using DS.WMS.Core.Map.Dtos; using DS.WMS.Core.Map.Interface; using Org.BouncyCastle.Ocsp; namespace DS.WMS.Core.Op.Method { public class CargooService : ICargooService { private readonly ISeaExportService _seaExportService; private readonly IServiceProvider _serviceProvider; private readonly ISqlSugarClient db; private readonly IUser user; private readonly ISaasDbService saasService; private readonly ISeaExportCommonService seaComService; private readonly IConfigService configService; private static readonly NLog.Logger Logger = LogManager.GetCurrentClassLogger(); private readonly IMappingCarrierService _mappingCarrierService; const string CONST_MAPPING_MODULE = "CARGOO_DATA"; public CargooService(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; db = _serviceProvider.GetRequiredService(); user = _serviceProvider.GetRequiredService(); saasService = _serviceProvider.GetRequiredService(); seaComService = _serviceProvider.GetRequiredService(); configService = _serviceProvider.GetRequiredService(); _mappingCarrierService = _serviceProvider.GetRequiredService(); } #region 发送Cargoo /// /// 发送Cargoo /// /// 请求详情 /// 返回回执 public async Task> SendCargoo(CargooShipmentReqDto model) { Logger.Log(NLog.LogLevel.Info, $"请求Cargoo API推送消息接收请求,{JsonConvert.SerializeObject(model)}"); if (model.bookingId <= 0) return DataResult.Failed("订单ID不能为空"); //读取订单详情 var tenantDb = saasService.GetBizDbScopeById(user.TenantId); //任务不考虑OrgId,这里去掉 tenantDb.QueryFilter.Clear(); var bookingInfo = await tenantDb.Queryable() .FirstAsync(a => a.Id == model.bookingId); if (bookingInfo == null) return DataResult.Failed("订单信息获取失败,订单ID错误或数据已作废"); if (!bookingInfo.SourceCode.Equals("FOB-WSL")) { return DataResult.Failed("Cargoo只支持业务来源是WSL指定货"); } if (string.IsNullOrWhiteSpace(bookingInfo.MBLNO)) { return DataResult.Failed("提单号不能为空"); } if (string.IsNullOrWhiteSpace(bookingInfo.CustomerNo)) { return DataResult.Failed("委托编号不能为空"); } if (string.IsNullOrWhiteSpace(bookingInfo.ContractNo)) { return DataResult.Failed("约号不能为空"); } var ctnList = tenantDb.Queryable().Where(a => a.BSNO == model.bookingId.ToString()).ToList(); try { //生成报文 var shipDtoRlt = GetCargooShipment(model.cargooStatusEnum, bookingInfo, ctnList).GetAwaiter().GetResult(); if (!shipDtoRlt.Succeeded) { return DataResult.Failed($"生成Cargoo报文失败,原因:{shipDtoRlt.Message}"); } var queryInfo = shipDtoRlt.Data; //发送报文至API接口 var queryUrl = configService.GetConfig("CargooAPI", long.Parse(user.TenantId), false).GetAwaiter().GetResult()?.Data?.Value; var cargooKey = configService.GetConfig("CarooAPIKey", long.Parse(user.TenantId), false).GetAwaiter().GetResult()?.Data?.Value; CargooShipmentResultDto resultInfo = null; var jsonBody = Newtonsoft.Json.JsonConvert.SerializeObject(queryInfo, Formatting.Indented, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); //var rlt = RequestHelper.Post(jsonBody, queryUrl); var rlt = await RequestHelper.PostAsyncWithHeaders(queryUrl, jsonBody, new Dictionary { { "Authorization", cargooKey } }); Logger.Log(NLog.LogLevel.Info, $"请求Cargoo API推送消息,{jsonBody}"); if (!string.IsNullOrWhiteSpace(rlt)) { try { Logger.Log(NLog.LogLevel.Info, $"请求Cargoo API推送消息结果,{rlt}"); resultInfo = JsonConvert.DeserializeObject(rlt); } catch (Exception ex) { Logger.Log(NLog.LogLevel.Info, $"请求Cargoo API推送消息异常,原因:{ex.Message}"); throw new Exception($"请求Cargoo API推送消息异常,原因:{ex.Message}"); } } if (resultInfo != null) { if (resultInfo.data.FirstOrDefault().code == 200) { // 记录日志 await seaComService.SaveSeaExportLogAsync(new SeaExportSaveLog() { OperateType = "Update", OldOrder = bookingInfo, NewOrder = bookingInfo, SourceCode = "SendCargoo", SourceName = $"发送Cargoo {model.cargooStatusEnum.ToString()}", }, tenantDb); return DataResult.Success("成功", resultInfo); } else { return DataResult.FailedData(resultInfo); } } } catch (Exception ex) { Logger.Log(NLog.LogLevel.Info, $"请求Cargoo API推送消息异常 ALL,原因:{ex.Message}"); return DataResult.Failed($"发送失败,原因:{ex.Message}"); } return DataResult.Failed("发送失败"); } #endregion #region 生成报文 /// /// 生成报文 /// /// 订单详情 /// 集装箱列表 /// private async Task> GetCargooShipment(CargooStatusEnum cargooStatusEnum, SeaExport order, List ctnList) { /* 1、需要确认incoterm的填写 2、FCL_FCL、LCL_FCL 3、 */ CargooShipmentDto dto = new CargooShipmentDto { bookingNumber = order.MBLNO, blNumber = order.MBLNO, incoterm = string.Empty, movementType = string.Empty, departureFrom = order.LoadPort, departureTo = order.DischargePort, carrierCode = order.Carrier, containerTypes = new List(), items = new List(), parties = new List() }; try { //ETD if (order.ETD.HasValue) { if (order.ETD.Value != DateTime.MinValue) { dto.etd = order.ETD.Value.ToString("yyyy-MM-dd"); } else { return DataResult.Failed("ETD格式错误"); } } else { return DataResult.Failed("ETD不能为空"); } //ETA if (order.ETA.HasValue) { if (order.ETA.Value != DateTime.MinValue) { dto.eta = order.ETA.Value.ToString("yyyy-MM-dd"); } else { return DataResult.Failed("ETA格式错误"); } } //这里默认对应 if (!string.IsNullOrWhiteSpace(order.MBLFrt)) { if (order.MBLFrt.IndexOf("COLLECT") >= 0) { dto.incoterm = "FOB"; } else if (order.MBLFrt.IndexOf("PREPAID") >= 0) { dto.incoterm = "CIF"; } } //默认整箱 dto.movementType = "FCL_FCL"; //起始港映射 var mapPortList = new List(); var portList = new List(); string loadPortCode = string.Empty; string dischargePortCode = string.Empty; #region 收货地 //收货地 if (order.ReceiptPlaceId > 0) { var portRlt = GetPortEDICode(order.ReceiptPlaceId, portList, mapPortList, order.CarrierId, CONST_MAPPING_MODULE, order.ReceiptPlace, "收货地"); if (portRlt.Succeeded) { dto.por = new CargooShipmentPortDto { type = "1", code = portRlt.Data }; } } #endregion #region 装货港 //装货港 if (order.LoadPortId > 0) { var portRlt = GetPortEDICode(order.LoadPortId, portList, mapPortList, order.CarrierId, CONST_MAPPING_MODULE, order.ReceiptPlace, "装货港"); if (portRlt.Succeeded) { dto.pol = new CargooShipmentPortDto { type = "1", code = portRlt.Data }; loadPortCode = portRlt.Data; } } #endregion #region 卸货港 //卸货港 if (order.DischargePortId > 0) { var portRlt = GetPortEDICode(order.DischargePortId, portList, mapPortList, order.CarrierId, CONST_MAPPING_MODULE, order.ReceiptPlace, "卸货港"); if (portRlt.Succeeded) { dto.pod = new CargooShipmentPortDto { type = "1", code = portRlt.Data }; dto.fnd = new CargooShipmentPortDto { type = "1", code = portRlt.Data }; dischargePortCode = portRlt.Data; } } #endregion if (order.CarrierId > 0) { var carrierRlt = GetCarrierEDICode(order.CarrierId); if (carrierRlt.Succeeded) { dto.carrierCode = carrierRlt.Data; } } List codeCtnList = new List(); List mapCtnList = new List(); List codePackageList = new List(); List mapPackageList = new List(); if (ctnList.Count > 0) { dto.containerTypes = ctnList.GroupBy(a => a.CtnCode).Select(a => { return new CargooShipmentContainerTypesDto { count = a.Sum(b => b.CtnNum.HasValue ? b.CtnNum.Value : 1), type = a.Key, weight = a.Sum(b => b.KGS.HasValue ? b.KGS.Value : 0), }; }).ToList(); foreach (var currCtn in dto.containerTypes) { var mapCtnRlt = GetCtnEDICode(currCtn.type, codeCtnList, mapCtnList, order.CarrierId, CONST_MAPPING_MODULE, ""); if (mapCtnRlt.Succeeded) { currCtn.type = mapCtnRlt.Data; } else { return DataResult.Failed($"箱型{currCtn.type} 的映射数据代码未找到"); } } } string kindPkgs = string.Empty; 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)) kindPkgs = codePackageList.FirstOrDefault(b => b.Id == packageId).PackageName; if (portRlt.Succeeded) { kindPkgs = portRlt.Data; } else { return DataResult.Failed($"包装{order.KindPkgs}的映射数据代码未找到"); } } else { return DataResult.Failed($"包装不能为空"); } var shipCargo = new CargooShipmentItemDto { commodityCode = order.Description, articleDescription = order.Description, packageType = kindPkgs, }; //件数 if (order.PKGS.HasValue && order.PKGS.Value > 0) { shipCargo.pieces = order.PKGS.Value; } if (order.PKGS.HasValue && order.PKGS.Value > 0) { shipCargo.packages = order.PKGS.Value; } //尺码 if (order.CBM.HasValue && order.CBM.Value > 0) { shipCargo.volume = order.CBM.Value; } //毛重 if (order.KGS.HasValue && order.KGS.Value > 0) { shipCargo.grossWeight = order.KGS.Value; } dto.items.Add(shipCargo); dto.transportPlan = new CargooShipmentTransportPlanDto { mainCarriage = new List() }; dto.transportPlan.mainCarriage.Add(new CargooShipmentMainCarriageDto { from = new CargooShipmentCarriagePortDto { code = loadPortCode }, to = new CargooShipmentCarriagePortDto { code = dischargePortCode }, etd = order.ETD.Value.ToString("yyyy-MM-dd"), transportMode = 50, transportMean = new CargooShipmentTransportMeanDto { name = order.Vessel }, conveyanceReferenceNumber = $"{order.InnerVoyno}" }); dto.parties.Add(new CargooShipmentPartyDto { type = "CN", name = "SUNNINESS LOGISTICS CO.,LTD." }); dto.currentStatus = new CargooShipmentCurrentStatusDto { code = (int)cargooStatusEnum, description = cargooStatusEnum.ToString() }; dto.integrationId = order.CustomerNo; dto.contractNumber = order.ContractNo; } catch (Exception ex) { return DataResult.Failed($"生成失败,原因:{ex.Message}"); } return DataResult.Success(dto); } #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 获取船公司映射 /// /// 获取船公司映射 /// /// 船公司ID /// private DataResult GetCarrierEDICode(long carrierId) { var tenantDb = saasService.GetBizDbScopeById(user.TenantId); var mapInfo = tenantDb.Queryable() .First(a => a.Module.Equals(CONST_MAPPING_MODULE, StringComparison.OrdinalIgnoreCase) && a.LinkId == carrierId); if (mapInfo != null) { if (!string.IsNullOrWhiteSpace(mapInfo.MapCode)) return DataResult.Success(mapInfo.MapCode); return DataResult.FailedData(mapInfo.MapCode); } else { var carrierRlt = seaComService.GetCarrierInfo(carrierId, tenantDb).GetAwaiter().GetResult(); if(carrierRlt.Succeeded) { return DataResult.Success(carrierRlt.Data.EdiCode); } return DataResult.FailedData(""); } } #endregion #region 检索集装箱型EDI代码 /// /// 检索集装箱型EDI代码 /// /// 集装箱型ID /// 集装箱基础表 /// 集装箱映射表 /// 船公司ID /// 模块代码 /// 集装箱名称 /// private DataResult GetCtnEDICode(string ctnCode, List codeCtnList, List mapCtnList, long carrierId, string moduleName , string ctnName) { 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; mapCtnInfo = tenantDb.Queryable() .First(a => a.Module.Equals(CONST_MAPPING_MODULE, StringComparison.OrdinalIgnoreCase) && 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 } }