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.

672 lines
25 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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;
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<ISqlSugarClient>();
seaComService = _serviceProvider.GetRequiredService<ISeaExportCommonService>();
configService = _serviceProvider.GetRequiredService<IConfigService>();
_mappingCarrierService = _serviceProvider.GetRequiredService<IMappingCarrierService>();
}
#region 发送Cargoo
/// <summary>
/// 发送Cargoo
/// </summary>
/// <param name="model">请求详情</param>
/// <returns>返回回执</returns>
public async Task<DataResult<CargooShipmentResultDto>> SendCargoo(CargooShipmentReqDto model)
{
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错误或数据已作废");
var ctnList = tenantDb.Queryable<OpCtn>().Where(a => a.BSNO == model.bookingId.ToString()).ToList();
//生成报文
var shipDtoRlt = GetCargooShipment(model.cargooStatusEnum, bookingInfo, ctnList).GetAwaiter().GetResult();
if (!shipDtoRlt.Succeeded)
{
return DataResult<CargooShipmentResultDto>.Failed($"生成Cargoo报文失败原因{shipDtoRlt.Message}");
}
var queryInfo = shipDtoRlt.Data;
//发送报文至API接口
var queryUrl = configService.GetConfig("CargooAPI", 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);
Logger.Log(NLog.LogLevel.Info, $"请求Cargoo API查询船期请求{jsonBody}");
if (!string.IsNullOrWhiteSpace(rlt))
{
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}");
throw new Exception(string.Format(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPISearchShipException)), ex.Message));
}
}
//记录返回结果
return DataResult<CargooShipmentResultDto>.Success("成功", null);
}
#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)
{
/*
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<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格式错误");
}
}
//这里默认对应
if (!string.IsNullOrWhiteSpace(order.MBLFrt))
{
if (order.MBLFrt.IndexOf("COLLECT") >= 0)
{
dto.incoterm = "CIF";
}
else if (order.MBLFrt.IndexOf("PREPAID") >= 0)
{
dto.incoterm = "FOB";
}
}
//默认整箱
dto.movementType = "FCL_FCL";
//起始港映射
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
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>();
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.WeightKGS.HasValue ? b.WeightKGS.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<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($"包装不能为空");
}
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<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
},
conveyanceReferenceNumber = $"{order.InnerVoyno}/{order.Voyno}"
});
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.Id.ToString();
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
#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>()
.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<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
}
}