You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

732 lines
28 KiB
C#

2 months ago
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;
2 months ago
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
2 months ago
using NLog;
2 months ago
using DS.Module.Core.Constants;
using DS.WMS.Core.Map.Dtos;
using DS.WMS.Core.Map.Interface;
2 months ago
using Org.BouncyCastle.Ocsp;
2 months ago
2 months ago
namespace DS.WMS.Core.Op.Method
2 months ago
{
2 months ago
public class CargooService : ICargooService
2 months ago
{
2 months ago
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();
2 months ago
private readonly IMappingCarrierService _mappingCarrierService;
2 months ago
const string CONST_MAPPING_MODULE = "CARGOO_DATA";
public CargooService(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
db = _serviceProvider.GetRequiredService<ISqlSugarClient>();
2 months ago
user = _serviceProvider.GetRequiredService<IUser>();
saasService = _serviceProvider.GetRequiredService<ISaasDbService>();
2 months ago
seaComService = _serviceProvider.GetRequiredService<ISeaExportCommonService>();
configService = _serviceProvider.GetRequiredService<IConfigService>();
2 months ago
_mappingCarrierService = _serviceProvider.GetRequiredService<IMappingCarrierService>();
2 months ago
}
#region 发送Cargoo
/// <summary>
/// 发送Cargoo
/// </summary>
/// <param name="model">请求详情</param>
/// <returns>返回回执</returns>
public async Task<DataResult<CargooShipmentResultDto>> SendCargoo(CargooShipmentReqDto model)
{
2 months ago
Logger.Log(NLog.LogLevel.Info, $"请求Cargoo API推送消息接收请求{JsonConvert.SerializeObject(model)}");
2 months ago
if (model.bookingId <= 0)
return DataResult<CargooShipmentResultDto>.Failed("订单ID不能为空");
//读取订单详情
var tenantDb = saasService.GetBizDbScopeById(user.TenantId);
//任务不考虑OrgId,这里去掉
tenantDb.QueryFilter.Clear<IOrgId>();
var bookingInfo = await tenantDb.Queryable<SeaExport>()
.FirstAsync(a => a.Id == model.bookingId);
if (bookingInfo == null)
return DataResult<CargooShipmentResultDto>.Failed("订单信息获取失败订单ID错误或数据已作废");
2 months ago
if (!bookingInfo.SourceCode.Equals("FOB-WSL"))
{
return DataResult<CargooShipmentResultDto>.Failed("Cargoo只支持业务来源是WSL指定货");
}
2 months ago
2 months ago
if (string.IsNullOrWhiteSpace(bookingInfo.MBLNO))
2 months ago
{
2 months ago
return DataResult<CargooShipmentResultDto>.Failed("提单号不能为空");
2 months ago
}
2 months ago
if (string.IsNullOrWhiteSpace(bookingInfo.CustomerNo))
{
return DataResult<CargooShipmentResultDto>.Failed("委托编号不能为空");
}
2 months ago
2 months ago
if (string.IsNullOrWhiteSpace(bookingInfo.ContractNo))
{
return DataResult<CargooShipmentResultDto>.Failed("约号不能为空");
}
2 months ago
2 months ago
var ctnList = tenantDb.Queryable<OpCtn>().Where(a => a.BSNO == model.bookingId.ToString()).ToList();
2 months ago
2 months ago
try
2 months ago
{
2 months ago
//生成报文
var shipDtoRlt = GetCargooShipment(model.cargooStatusEnum, bookingInfo, ctnList).GetAwaiter().GetResult();
2 months ago
2 months ago
if (!shipDtoRlt.Succeeded)
{
return DataResult<CargooShipmentResultDto>.Failed($"生成Cargoo报文失败原因{shipDtoRlt.Message}");
}
2 months ago
2 months ago
var queryInfo = shipDtoRlt.Data;
2 months ago
2 months ago
//发送报文至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
2 months ago
{
2 months ago
NullValueHandling = NullValueHandling.Ignore
});
2 months ago
2 months ago
//var rlt = RequestHelper.Post(jsonBody, queryUrl);
var rlt = await RequestHelper.PostAsyncWithHeaders(queryUrl, jsonBody, new Dictionary<string, string> { { "Authorization", cargooKey } });
Logger.Log(NLog.LogLevel.Info, $"请求Cargoo API推送消息{jsonBody}");
if (!string.IsNullOrWhiteSpace(rlt))
2 months ago
{
2 months ago
try
{
Logger.Log(NLog.LogLevel.Info, $"请求Cargoo API推送消息结果{rlt}");
resultInfo = JsonConvert.DeserializeObject<CargooShipmentResultDto>(rlt);
}
catch (Exception ex)
{
Logger.Log(NLog.LogLevel.Info, $"请求Cargoo API推送消息异常原因{ex.Message}");
2 months ago
2 months ago
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<CargooShipmentResultDto>.Success("成功", resultInfo);
}
else
{
return DataResult<CargooShipmentResultDto>.FailedData(resultInfo);
}
2 months ago
}
}
2 months ago
catch (Exception ex)
{
Logger.Log(NLog.LogLevel.Info, $"请求Cargoo API推送消息异常 ALL原因{ex.Message}");
2 months ago
2 months ago
return DataResult<CargooShipmentResultDto>.Failed($"发送失败,原因:{ex.Message}");
}
return DataResult<CargooShipmentResultDto>.Failed("发送失败");
2 months ago
}
#endregion
#region 生成报文
/// <summary>
/// 生成报文
/// </summary>
/// <param name="order">订单详情</param>
/// <param name="ctnList">集装箱列表</param>
/// <returns></returns>
private async Task<DataResult<CargooShipmentDto>> GetCargooShipment(CargooStatusEnum cargooStatusEnum, SeaExport order, List<OpCtn> ctnList)
{
/*
1incoterm
2FCL_FCLLCL_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<CargooShipmentContainerTypesDto>(),
items = new List<CargooShipmentItemDto>(),
parties = new List<CargooShipmentPartyDto>()
};
try
{
//ETD
if (order.ETD.HasValue)
{
if (order.ETD.Value != DateTime.MinValue)
{
dto.etd = order.ETD.Value.ToString("yyyy-MM-dd");
}
else
{
return DataResult<CargooShipmentDto>.Failed("ETD格式错误");
}
}
else
{
return DataResult<CargooShipmentDto>.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<CargooShipmentDto>.Failed("ETA格式错误");
}
}
2 months ago
//这里默认对应
if (!string.IsNullOrWhiteSpace(order.MBLFrt))
{
if (order.MBLFrt.IndexOf("COLLECT") >= 0)
{
2 months ago
dto.incoterm = "FOB";
2 months ago
}
else if (order.MBLFrt.IndexOf("PREPAID") >= 0)
{
2 months ago
dto.incoterm = "CIF";
2 months ago
}
}
//默认整箱
dto.movementType = "FCL_FCL";
//起始港映射
2 months ago
var mapPortList = new List<MappingPort>();
var portList = new List<CodePort>();
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
2 months ago
if (order.CarrierId > 0)
{
var carrierRlt = GetCarrierEDICode(order.CarrierId);
if (carrierRlt.Succeeded)
{
dto.carrierCode = carrierRlt.Data;
}
}
List<CodeCtn> codeCtnList = new List<CodeCtn>();
List<MappingCtn> mapCtnList = new List<MappingCtn>();
List<CodePackage> codePackageList = new List<CodePackage>();
List<MappingPackage> mapPackageList = new List<MappingPackage>();
2 months ago
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,
2 months ago
weight = a.Sum(b => b.KGS.HasValue ? b.KGS.Value : 0),
2 months ago
};
}).ToList();
2 months ago
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<CargooShipmentDto>.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<CargooShipmentDto>.Failed($"包装{order.KindPkgs}的映射数据代码未找到");
}
}
else
{
return DataResult<CargooShipmentDto>.Failed($"包装不能为空");
2 months ago
}
var shipCargo = new CargooShipmentItemDto
{
commodityCode = order.Description,
articleDescription = order.Description,
2 months ago
packageType = kindPkgs,
2 months ago
};
//件数
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<CargooShipmentMainCarriageDto>()
};
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
},
2 months ago
conveyanceReferenceNumber = $"{order.InnerVoyno}"
2 months ago
});
dto.parties.Add(new CargooShipmentPartyDto {
type = "CN",
name = "SUNNINESS LOGISTICS CO.,LTD."
});
dto.currentStatus = new CargooShipmentCurrentStatusDto
{
2 months ago
code = (int)cargooStatusEnum,
description = cargooStatusEnum.ToString()
2 months ago
};
2 months ago
dto.integrationId = order.CustomerNo;
2 months ago
dto.contractNumber = order.ContractNo;
}
catch (Exception ex)
{
return DataResult<CargooShipmentDto>.Failed($"生成失败,原因:{ex.Message}");
}
return DataResult<CargooShipmentDto>.Success(dto);
}
#endregion
#region 检索港口的EDI代码
/// <summary>
/// 检索港口的EDI代码
/// </summary>
/// <param name="portId">港口ID</param>
/// <param name="codePortList">港口基础表</param>
/// <param name="mapPortList">港口映射表</param>
/// <param name="carrierId">船公司ID</param>
/// <param name="moduleName">模块代码</param>
/// <param name="portName">港口名称</param>
/// <param name="portCategory">港口分类(装货港、卸货港、交货地等)</param>
/// <param name="isNeedMapping">是否必需用映射</param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
private DataResult<string> GetPortEDICode(long portId, List<CodePort> codePortList, List<MappingPort> 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<string>.Success(edi);
return DataResult<string>.FailedData(edi);
}
var tenantDb = saasService.GetBizDbScopeById(user.TenantId);
string MappingModule = CONST_MAPPING_MODULE;
if (!string.IsNullOrWhiteSpace(needMappingModule))
{
MappingModule = needMappingModule;
}
var mapPortInfo = tenantDb.Queryable<MappingPort>()
.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<string>.Success(mapPortInfo.MapCode);
return DataResult<string>.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<string>.Success(edi);
return DataResult<string>.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<string>.Success(loadPortCodeRlt.Data?.EdiCode);
return DataResult<string>.FailedData(loadPortCodeRlt.Data?.EdiCode);
}
#endregion
2 months ago
#region 获取船公司映射
/// <summary>
/// 获取船公司映射
/// </summary>
/// <param name="carrierId">船公司ID</param>
/// <returns></returns>
private DataResult<string> GetCarrierEDICode(long carrierId)
{
var tenantDb = saasService.GetBizDbScopeById(user.TenantId);
var mapInfo = tenantDb.Queryable<MappingCarrier>()
.First(a => a.Module.Equals(CONST_MAPPING_MODULE, StringComparison.OrdinalIgnoreCase) && a.LinkId == carrierId);
if (mapInfo != null)
{
if (!string.IsNullOrWhiteSpace(mapInfo.MapCode))
return DataResult<string>.Success(mapInfo.MapCode);
return DataResult<string>.FailedData(mapInfo.MapCode);
}
else
{
var carrierRlt = seaComService.GetCarrierInfo(carrierId, tenantDb).GetAwaiter().GetResult();
if(carrierRlt.Succeeded)
{
return DataResult<string>.Success(carrierRlt.Data.EdiCode);
}
return DataResult<string>.FailedData("");
}
}
#endregion
#region 检索集装箱型EDI代码
/// <summary>
/// 检索集装箱型EDI代码
/// </summary>
/// <param name="ctnCode">集装箱型ID</param>
/// <param name="codeCtnList">集装箱基础表</param>
/// <param name="mapCtnList">集装箱映射表</param>
/// <param name="carrierId">船公司ID</param>
/// <param name="moduleName">模块代码</param>
/// <param name="ctnName">集装箱名称</param>
/// <returns></returns>
private DataResult<string> GetCtnEDICode(string ctnCode, List<CodeCtn> codeCtnList, List<MappingCtn> 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<CodeCtn>().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<string>.Success(edi);
return DataResult<string>.FailedData(edi);
}
MappingCtn mapCtnInfo = null;
mapCtnInfo = tenantDb.Queryable<MappingCtn>()
2 months ago
.First(a => a.Module.Equals(CONST_MAPPING_MODULE, StringComparison.OrdinalIgnoreCase) && a.LinkId == codeCtnInfo.Id);
2 months ago
if (mapCtnInfo != null)
{
mapCtnList.Add(mapCtnInfo);
if (!string.IsNullOrWhiteSpace(mapCtnInfo.MapCode))
return DataResult<string>.Success(mapCtnInfo.MapCode);
throw new Exception($"集装箱型 {ctnName}的映射代码未找到");
}
else
{
if (codeCtnInfo != null && !string.IsNullOrWhiteSpace(codeCtnInfo.EdiCode))
{
return DataResult<string>.Success(codeCtnInfo.EdiCode);
}
throw new Exception($"集装箱型 {ctnName}基础代码EDI 错误");
}
}
#endregion
#region 检索包装EDI代码
/// <summary>
/// 检索包装EDI代码
/// </summary>
/// <param name="packageCodeId">包装ID</param>
/// <param name="codePackageList">包装基础表</param>
/// <param name="mapPackageList">包装映射表</param>
/// <param name="carrierId">船公司ID</param>
/// <param name="moduleName">模块代码</param>
/// <param name="packageName">包装名称</param>
/// <returns></returns>
private DataResult<string> GetPackageEDICode(long packageCodeId, List<CodePackage> codePackageList, List<MappingPackage> mapPackageList, long carrierId, string moduleName)
{
var tenantDb = saasService.GetBizDbScopeById(user.TenantId);
if (!codePackageList.Any(b => b.Id == packageCodeId))
{
var codePackage = tenantDb.Queryable<CodePackage>().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<string>.Success(edi);
//return DataResult<string>.FailedData(edi);
}
//优先判断跟船公司设置包装映射,如果没有取默认映射
var mapPackageInfo = tenantDb.Queryable<MappingPackage>()
.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<string>.Success(mapPackageInfo.MapCode);
//return DataResult<string>.FailedData(mapPackageInfo.MapCode);
throw new Exception($"包装的映射代码未找到");
}
else
{
var codePackage = codePackageList.FirstOrDefault(b => b.Id == packageCodeId);
if (codePackage != null && !string.IsNullOrWhiteSpace(codePackage.EdiCode))
{
return DataResult<string>.Success(codePackage.EdiCode);
}
throw new Exception($"包装的基础信息EDI代码未找到");
}
//else
//{
//
//}
}
#endregion
2 months ago
}
}