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.

2245 lines
102 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.SqlSugar;
using DS.Module.UserModule;
using DS.WMS.Core.Code.Dtos;
using DS.WMS.Core.Code.Entity;
using DS.WMS.Core.Op.Dtos;
using DS.WMS.Core.Sys.Entity;
using Microsoft.Extensions.DependencyInjection;
using NPOI.SS.Formula.Functions;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DS.WMS.Core.Code.Interface;
using Newtonsoft.Json;
using DS.Module.Core.Helpers;
using NLog;
using DS.WMS.Core.Map.Interface;
using DS.Module.Core.Extensions;
using DS.WMS.Core.Sys.Dtos;
using DS.Module.RedisModule;
using System.Text.RegularExpressions;
using DS.WMS.Core.Sys.Interface;
using DS.WMS.Core.Sys.Method;
using DS.WMS.Core.Op.Entity;
using Mapster;
using System.Text.Json.Nodes;
using LanguageExt.Pipes;
using DS.WMS.Core.Op.Interface;
using DS.WMS.Core.Map.Method;
using Amazon.Runtime.Internal.Util;
using LogicExtensions;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using AngleSharp.Dom;
namespace DS.WMS.Core.Op.Method
{
public class SpaceBookingMSKSPOTAPIService : ISpaceBookingMSKSPOTAPIService
{
const string CONST_MSK_API_COMMODITY_URL = "MSKApiCommodity";
const string CONST_MSK_API_BOOKING_URL = "MSKApiBooking";
const string CONST_MSK_SPOT_API_QUERY_SCHEDULE_RATE_URL = "MSKSPOTScheduleRate";
const string CONST_MSK_SPOT_API_LOCATION_URL = "MSKSPOTApilocation";
private readonly IServiceProvider _serviceProvider;
private readonly ISqlSugarClient db;
private readonly IUser user;
private readonly ISaasDbService saasService;
private readonly ICodeThirdPartyService codeThirdPartyService;
private readonly string mskAPIUserKey;
private readonly string mskAPIUserSecret;
private readonly string mskAPIEnvironment;
private static readonly NLog.Logger Logger = LogManager.GetCurrentClassLogger();
private readonly IMappingCtnService mappingCtnService;
private readonly IRedisService redisService;
private readonly IConfigService configService;
public SpaceBookingMSKSPOTAPIService(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
db = _serviceProvider.GetRequiredService<ISqlSugarClient>();
user = _serviceProvider.GetRequiredService<IUser>();
saasService = _serviceProvider.GetRequiredService<ISaasDbService>();
codeThirdPartyService = _serviceProvider.GetRequiredService<ICodeThirdPartyService>();
mappingCtnService = _serviceProvider.GetRequiredService<IMappingCtnService>();
redisService = _serviceProvider.GetRequiredService<IRedisService>();
configService = _serviceProvider.GetRequiredService<IConfigService>();
mskAPIUserKey = AppSetting.app(new string[] { "MSKAPIService", "UserKey" });
mskAPIUserSecret = AppSetting.app(new string[] { "MSKAPIService", "UserSecret" });
mskAPIEnvironment = AppSetting.app(new string[] { "MSKAPIService", "Environment" });
}
#region 检索始发地、目的港口信息
/// <summary>
/// 检索始发地、目的港口信息
/// </summary>
/// <param name="model">请求详情</param>
/// <returns>返回检索结果</returns>
public async Task<DataResult<List<QueryLocationsResultDto>>> SearchLocations(QuerySPOTLocationsDto model)
{
List<QueryLocationsResultDto> list = new List<QueryLocationsResultDto>();
/*
MSKApiCommodity
*/
try
{
//港口或城市名称不能为空
if (string.IsNullOrWhiteSpace(model.cityName))
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPISPOTQueryLocCityNull)));
//服务船公司不能为空
if (string.IsNullOrWhiteSpace(model.serviceCarrierCode))
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPIVesselCarrierCodeNull)));
//船公司代码不能为空
if (string.IsNullOrWhiteSpace(model.carrierCode))
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPICarrierCodeNull)));
//港口或城市名称至少输入3个以上字符
if (model.cityName.Length < 3)
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPIQueryLocCityLeastThreeLNull)));
string queryUrl = string.Empty;
if (model.carrierCode.Equals("MSK", StringComparison.OrdinalIgnoreCase))
{
queryUrl = configService.GetConfig(CONST_MSK_SPOT_API_LOCATION_URL).GetAwaiter().GetResult()?.Data?.Value;
}
else
{
//当前船公司{0} 不支持 API 合约订舱查询港口
throw new Exception(string.Format(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPIQueryLocCityLeastThreeLNull)), model.carrierCode));
}
//未配置API SPOT查询港口请求接口地址 key={0},请联系管理员
if (string.IsNullOrWhiteSpace(queryUrl))
throw new Exception(string.Format(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPISpotSearchLocNoConfig)), CONST_MSK_SPOT_API_LOCATION_URL));
var webAccountConfig = codeThirdPartyService.GetCodeThirdPartyInfoWithCompany("MSKSpotApi").GetAwaiter().GetResult()?.Data;
//未配置公司或个人的第三方账户维护MSK API Spot请联系管理员
if (webAccountConfig == null)
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPIMSKSpotThirdPartySettingNull)));
MSKAPISPOTSearchLocationDto queryInfo = new MSKAPISPOTSearchLocationDto
{
userKey = mskAPIUserKey,
userSecret = mskAPIUserSecret,
operatingEnvironment = mskAPIEnvironment,
spot_api_key = webAccountConfig.AppKey,
brandScac = model.serviceCarrierCode,
originPrefix = model.cityName
};
MSKAPISPOTSearchLocationResultDto resultInfo = null;
//var rlt = await queryUrl.SetBody(queryInfo).PostAsStringAsync();
var rlt = RequestHelper.Post(JsonConvert.SerializeObject(queryInfo), queryUrl);
if (!string.IsNullOrWhiteSpace(rlt))
{
try
{
resultInfo = JsonConvert.DeserializeObject<MSKAPISPOTSearchLocationResultDto>(rlt);
}
catch (Exception ex)
{
Logger.Log(NLog.LogLevel.Error, $"请求MSK API SPOT 查询港口异常,原因,{ex.Message}");
throw new Exception($"请求MSK API SPOT 查询港口异常,原因,{ex.Message}");
}
}
if (resultInfo != null && resultInfo.code == 200
&& resultInfo.data != null && resultInfo.data.Count > 0)
{
list = resultInfo.data.Select(a =>
{
return new QueryLocationsResultDto
{
carrierGeoID = a.geoId,
cityName = a.cityName,
countryCode = a.countryCode,
countryName = a.countryName,
locationName = a.locationName,
UNRegionName = a.regionName,
UNLocationCode = a.unLocCode,
};
}).ToList();
}
}
catch (Exception ex)
{
Logger.Log(NLog.LogLevel.Error, $"请求MSK API SPOT 查询港口异常req={JsonConvert.SerializeObject(model)} 原因,{ex.Message}");
//throw new Exception($"请求MSK API SPOT 查询港口异常,原因,{ex.Message}");
return DataResult<List<QueryLocationsResultDto>>.Failed($"请求MSK API SPOT 查询港口异常,原因,{ex.Message}");
}
return DataResult<List<QueryLocationsResultDto>>.Success(list);
}
#endregion
#region 检索海运船期详情
/// <summary>
/// 检索海运船期详情
/// </summary>
/// <param name="model">请求船期详情</param>
/// <returns>返回船期结果</returns>
public async Task<DataResult<List<MSKAPISPOTScheduleRateResultShowDto>>> SearchShipSailingSchedule(QueryMSKSPOTShipDateDto query)
{
List<MSKAPISPOTScheduleRateResultShowDto> list = new List<MSKAPISPOTScheduleRateResultShowDto>();
try
{
var model = query.Adapt<QueryMSKSPOTScheduleDto>();
//始发地不能为空
if (string.IsNullOrWhiteSpace(model.originGeoId))
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPIOriginCityNameNull)));
//目的地不能为空
if (string.IsNullOrWhiteSpace(model.destinationGeoId))
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPIDestCityNameNull)));
//服务船公司不能为空
if (string.IsNullOrWhiteSpace(model.brandScac))
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPIVesselCarrierCodeNull)));
//船公司代码不能为空
if (string.IsNullOrWhiteSpace(model.carrierCode))
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPICarrierCodeNull)));
//预计离港日期不能为空
if (string.IsNullOrWhiteSpace(model.departureDate))
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPIETDNull)));
DateTime etd = DateTime.MinValue;
//预计离港日期格式错误
if (!DateTime.TryParse(model.departureDate, out etd))
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPIETDFormatError)));
//箱型不能为空
if (string.IsNullOrWhiteSpace(model.containerType))
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPICtnCodeNull)));
//箱型不能为空
if (!model.containerCount.HasValue || model.containerCount.Value <= 0)
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPICtnCodeNull)));
//箱内重量不能为空并且不能小于1
if (!model.containerWeight.HasValue || model.containerWeight.Value <= 0)
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPICtnSufferWeightLower)));
if (model.containerWeight.HasValue)
{
model.containerWeight = model.containerWeight.Value / 1000;
}
string queryUrl = string.Empty;
if (model.carrierCode.Equals("MSK", StringComparison.OrdinalIgnoreCase))
{
queryUrl = configService.GetConfig(CONST_MSK_SPOT_API_QUERY_SCHEDULE_RATE_URL).GetAwaiter().GetResult()?.Data?.Value;
}
else
{
//当前船公司{0} 不支持 API Spot 订舱查询船期
throw new Exception(string.Format(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPISportSearchShipNotSupport)), model.carrierId));
}
//未配置API SPOT 查询船期请求接口地址 key={0},请联系管理员
if (string.IsNullOrWhiteSpace(queryUrl))
throw new Exception(string.Format(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPISpotSearchShipNoConfig)), CONST_MSK_SPOT_API_QUERY_SCHEDULE_RATE_URL));
var webAccountConfig = codeThirdPartyService.GetCodeThirdPartyInfoWithCompany("MSKSpotApi").GetAwaiter().GetResult()?.Data;
//未配置公司或个人的第三方账户维护MSK API Spot请联系管理员
if (webAccountConfig == null)
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPIMSKSpotThirdPartySettingNull)));
MSKAPISPOTSearchScheduleRateDto queryInfo = new MSKAPISPOTSearchScheduleRateDto
{
userKey = mskAPIUserKey,
userSecret = mskAPIUserSecret,
operatingEnvironment = mskAPIEnvironment,
spot_api_key = webAccountConfig.AppKey,
originServiceMode = model.originServiceMode,
destinationServiceMode = model.destinationServiceMode,
originGeoId = model.originGeoId,
destinationGeoId = model.destinationGeoId,
brandScac = model.brandScac,
departureDate = etd.ToString("yyyy-MM-dd"),
};
//有时候船期需要带上箱型检索
if (!string.IsNullOrWhiteSpace(model.containerType))
{
//这里需要翻译一下箱型
//var ctnCodeMappingList = _cache.GetAllMappingCtn().GetAwaiter().GetResult().ToList();
//if (ctnCodeMappingList.Count > 0)
//ctnCodeMappingList = ctnCodeMappingList.Where(x => x.CarrierCode == "MSK" && x.Module == "BOOK_MSK_SPOT_API").ToList();
//var ctnMapping = ctnCodeMappingList.FirstOrDefault(t => t.Code.Equals(model.containerType));
var ctnMapping = mappingCtnService.QueryMappingCtn(model.carrierId, "BOOK_MSK_SPOT_API", model.containerType).GetAwaiter().GetResult().Data;
if (ctnMapping == null)
{
queryInfo.containerType = model.containerType;
}
else
{
queryInfo.containerType = ctnMapping.MapCode;
}
}
if (model.containerCount.HasValue)
{
queryInfo.containerCount = model.containerCount.Value;
}
if (model.containerWeight.HasValue)
{
queryInfo.containerWeight = model.containerWeight.Value;
}
MSKAPISPOTSearchScheduleRateResultDto 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 queryUrl.SetBody(jsonBody).PostAsStringAsync();
Logger.Log(NLog.LogLevel.Info, $"请求MSK SPOT API查询船期请求{jsonBody}");
if (!string.IsNullOrWhiteSpace(rlt))
{
try
{
Logger.Log(NLog.LogLevel.Info, $"请求MSK SPOT API查询船期结果{rlt}");
resultInfo = JsonConvert.DeserializeObject<MSKAPISPOTSearchScheduleRateResultDto>(rlt);
}
catch (Exception ex)
{
Logger.Log(NLog.LogLevel.Info, $"请求MSK SPOT API查询船期异常原因{ex.Message}");
throw new Exception(string.Format(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPISpotSearchShipException)), ex.Message));
}
}
if (resultInfo != null && resultInfo.code == 200
&& resultInfo.data != null && resultInfo.data.Count > 0)
{
foreach (var scheduleModel in resultInfo.data)
{
CacheShipSailingSchedule(scheduleModel).GetAwaiter().GetResult();
}
list = resultInfo.data.Select(a =>
{
return GetShipScheduleShow(a);
}).ToList();
}
else
{
//请求MSK API SPOT 查询船期异常,原因:{0}
throw new Exception(string.Format(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPISpotSearchShipException)), resultInfo.msg));
}
}
catch (Exception ex)
{
//Logger.Log(NLog.LogLevel.Error, $"检索海运船期详情异常req={JsonConvert.SerializeObject(query)} 原因:{ex.Message}");
//throw Oops.Bah($"检索海运船期详情失败,{ex.Message}");
}
return DataResult<List<MSKAPISPOTScheduleRateResultShowDto>>.Success(list);
}
#endregion
#region 组织返回船期数据
/// <summary>
/// 组织返回船期数据
/// </summary>
/// <param name="model">查询的船期详情</param>
/// <returns>返回显示的船期数据</returns>
private MSKAPISPOTScheduleRateResultShowDto GetShipScheduleShow(MSKAPISPOTSearchScheduleRateResultDataDto model)
{
MSKAPISPOTScheduleRateResultShowDto showDto = new MSKAPISPOTScheduleRateResultShowDto
{
priceID = model.priceID,
PId = model.PId,
MD5 = model.MD5,
totalAmount = model.totalAmount.HasValue ? (decimal)model.totalAmount.Value : 0,
TotalCurrency = model.totalCurrency,
orignCarrierCityGeoID = model.originGeoId,
orignUNLocationCode = model.originUnLocCode,
orignCityName = model.originCityName,
originRegionName = model.originRegionName,
originCountryName = model.originCountryName,
deliveryCarrierCityGeoID = model.destinationGeoId,
deliveryUNLocationCode = model.destinationUnLocCode,
deliveryCityName = model.destinationCityName,
deliveryRegionName = model.destinationRegionName,
deliveryCountryName = model.destinationCountryName,
vesselName = model.vesselName,
carrierDepartureVoyageNumber = model.voyageNumber,
Legs = new List<MSKAPISPOTScheduleRateResultShowLegsDto>()
};
if (model.totalAmount.HasValue)
showDto.totalAmountShow = string.Format("{0:N}", model.totalAmount.Value);
//ETD
if (!string.IsNullOrWhiteSpace(model.departureDate))
{
DateTime currDate = DateTime.MinValue;
if (DateTime.TryParse(model.departureDate, out currDate))
{
showDto.ETD = currDate;
}
else
{
//throw Oops.Bah($"查询船期错误priceID={model.priceID} pid={model.PId} 预计离港日期departureDate={model.departureDate} 格式解析错误");
}
}
//ETA
if (!string.IsNullOrWhiteSpace(model.arrivalDate))
{
DateTime currDate = DateTime.MinValue;
if (DateTime.TryParse(model.arrivalDate, out currDate))
{
showDto.ETA = currDate;
}
else
{
//throw Oops.Bah($"查询船期错误priceID={model.priceID} pid={model.PId} 预计到达日期 arrivalDate={model.arrivalDate} 格式解析错误");
}
}
//计算预计天数
if (showDto.ETD.HasValue && showDto.ETD.HasValue)
{
TimeSpan ts = showDto.ETA.Value.Subtract(showDto.ETD.Value);
var timeDiff = ts.TotalHours;
showDto.days = (int)Math.Ceiling(timeDiff / 24.0);
}
if (model.isTransfer.Equals("true", StringComparison.OrdinalIgnoreCase))
showDto.isTransfer = true;
//Legs
if (model.scheduleDetails != null && model.scheduleDetails.Count > 0)
{
if (model.scheduleDetails.Any(x => x.fromLocation.cityGeoId == model.originGeoId))
{
showDto.orignCountryCode = model.scheduleDetails.FirstOrDefault(x => x.fromLocation.cityGeoId == model.originGeoId).fromLocation.countryCode;
}
else if (model.scheduleDetails.Any(x => x.toLocation.cityGeoId == model.originGeoId))
{
showDto.orignCountryCode = model.scheduleDetails.FirstOrDefault(x => x.toLocation.cityGeoId == model.originGeoId).toLocation.countryCode;
}
if (model.scheduleDetails.Any(x => x.fromLocation.cityGeoId == model.destinationGeoId))
{
showDto.deliveryCountryCode = model.scheduleDetails.FirstOrDefault(x => x.fromLocation.cityGeoId == model.destinationGeoId).fromLocation.countryCode;
}
else if (model.scheduleDetails.Any(x => x.toLocation.cityGeoId == model.destinationGeoId))
{
showDto.deliveryCountryCode = model.scheduleDetails.FirstOrDefault(x => x.toLocation.cityGeoId == model.destinationGeoId).toLocation.countryCode;
}
var legs = model.scheduleDetails.Select(b =>
{
MSKAPISPOTScheduleRateResultShowLegsDto leg = new MSKAPISPOTScheduleRateResultShowLegsDto
{
vesselName = b.transport.vessel.longName,
VoyageNo = b.transport.voyageNumber,
From = new MSKAPISPOTScheduleRateResultShowLegsLocationDto
{
CityGeoId = b.fromLocation.cityGeoId,
CityName = b.fromLocation.cityName,
CountryCode = b.fromLocation.countryCode,
CountryName = b.fromLocation.countryName,
rkstCode = b.fromLocation.rkstCode,
SiteGeoId = b.fromLocation.siteGeoId,
LocationType = "From",
RegionName = b.fromLocation.regionName,
SiteName = b.fromLocation.siteName,
UnLocCode = b.fromLocation.unLocCode,
},
To = new MSKAPISPOTScheduleRateResultShowLegsLocationDto
{
CityGeoId = b.toLocation.cityGeoId,
CityName = b.toLocation.cityName,
CountryCode = b.toLocation.countryCode,
CountryName = b.toLocation.countryName,
rkstCode = b.toLocation.rkstCode,
SiteGeoId = b.toLocation.siteGeoId,
LocationType = "To",
RegionName = b.toLocation.regionName,
SiteName = b.toLocation.siteName,
UnLocCode = b.toLocation.unLocCode,
}
};
//ETD
if (!string.IsNullOrWhiteSpace(b.fromLocation.date))
{
DateTime currDate = DateTime.MinValue;
if (DateTime.TryParse($"{b.fromLocation.date} {b.fromLocation.time}", out currDate))
{
leg.ETD = currDate;
}
else
{
//throw Oops.Bah($"查询船期错误,航程明细 priceID={model.priceID} pid={model.PId} 预计离港日期fromLocation.date={b.fromLocation.date} {b.fromLocation.time} 格式解析错误");
}
}
//ETA
if (!string.IsNullOrWhiteSpace(b.toLocation.date))
{
DateTime currDate = DateTime.MinValue;
if (DateTime.TryParse(model.arrivalDate, out currDate))
{
leg.ETA = currDate;
}
else
{
// throw Oops.Bah($"查询船期错误,航程明细 priceID={model.priceID} pid={model.PId} 预计到达日期 toLocation.date={b.toLocation.date} {b.toLocation.time} 格式解析错误");
}
}
return leg;
}).ToList();
showDto.Legs = legs.OrderBy(t => t.ETD).Select((t, idx) =>
{
t.SortNo = idx + 1;
return t;
}).ToList();
}
return showDto;
}
#endregion
#region 缓存船期数据
/// <summary>
/// 缓存船期数据
/// </summary>
/// <param name="model">船期查询结果明细</param>
/// <param name="busiType">船期类型 MSKSPOT-马士基即期</param>
/// <returns>返回主键ID</returns>
private async Task CacheShipSailingSchedule(MSKAPISPOTSearchScheduleRateResultDataDto model, string busiType = "MSKSPOT")
{
/*
1、按照船期明细缓存并把ID作为缓存的KEY
2、对数据进行JSON串行化的文本提取MD5
3、写入缓存并返回ID
*/
var newModel = model.MapTo<MSKAPISPOTSearchScheduleRateResultDataDto, MSKAPISPOTSearchScheduleRateResultDataDto>();
//newModel.priceID = null;
var json = Newtonsoft.Json.JsonConvert.SerializeObject(newModel);
model.PId = SnowFlakeSingle.Instance.NextId();
//string md5 = json.ToMd5();
//model.MD5 = md5;
var shareKey = model.PId.ToString();
DateTime nowDate = DateTime.Now;
DateTime expireDateTime = DateTime.Now.AddHours(4);
var expireTimeSpan = expireDateTime.Subtract(nowDate).Duration();
if (!redisService.Exists($"{shareKey}_{busiType}"))
{
redisService.SetValue($"{shareKey}_{busiType}", Newtonsoft.Json.JsonConvert.SerializeObject(model), 4 * 3600);
}
}
#endregion
#region 获取缓存的船期数据
/// <summary>
/// 获取缓存的船期数据
/// </summary>
/// <param name="pid">船期Pid</param>
/// <param name="busiType">类型 MSKCON-合约船期</param>
/// <returns>返回船期详情</returns>
private MSKAPISPOTSearchScheduleRateResultDataDto GetCacheShipSailingSchedule(long pid, string busiType = "MSKSPOT")
{
if (redisService.Exists($"{pid}_{busiType}"))
{
return redisService.GetEntity<MSKAPISPOTSearchScheduleRateResultDataDto>($"{pid}_{busiType}");
}
return null;
}
#endregion
#region 发送马士基订舱请求
/// <summary>
/// 发送马士基订舱请求
/// </summary>
/// <param name="model">请求订舱详情</param>
/// <returns></returns>
public async Task<DataResult<MSKBookingResultDto>> SendMSKBooking(MSKSPOTBookingDto model)
{
return await InnerSendMSKBooking(model, 0);
}
#endregion
#region 发送马士基订舱请求(内部方法)
/// <summary>
/// 发送马士基订舱请求(内部方法)
/// </summary>
/// <param name="model">请求订舱详情</param>
/// <param name="currId">当前马士基订舱主键</param>
/// <param name="isDefaultSave">是否默认保存</param>
/// <returns></returns>
private async Task<DataResult<MSKBookingResultDto>> InnerSendMSKBooking(MSKSPOTBookingDto model, long currId, bool isDefaultSave = true)
{
MSKBookingResultDto result = new MSKBookingResultDto();
/*
MSKApiBooking
*/
try
{
var tenantDb = saasService.GetBizDbScopeById(user.TenantId);
//if (string.IsNullOrWhiteSpace(model.carrierCode))
// throw Oops.Oh($"服务船公司不能为空");
//if (string.IsNullOrWhiteSpace(model.carrierId))
// throw Oops.Oh("船公司代码不能为空");
string sendUrl = string.Empty;
if (model.carrierCode.Equals("MSK", StringComparison.OrdinalIgnoreCase))
{
sendUrl = configService.GetConfig(CONST_MSK_API_BOOKING_URL).GetAwaiter().GetResult()?.Data?.Value;
}
else
{
//当前船公司 {model.carrierId} 未配置相应的请求接口
throw new Exception(string.Format(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPIBookingNotSupport)), model.carrierId));
}
//未配置发送订舱请求接口地址,请联系管理员
if (string.IsNullOrWhiteSpace(sendUrl))
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPIBookingUrlNull)));
var webAccountConfig = codeThirdPartyService.GetCodeThirdPartyInfoWithCompany("MSKApi").GetAwaiter().GetResult()?.Data;
//未配置公司或个人的第三方账户维护MSK API合约请联系管理员
if (webAccountConfig == null)
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPIMSKConThirdPartySettingNull)));
//这里是校验必填项
ValidateMSKAPIData(model);
MSKAPISPOTSearchScheduleRateResultDataDto selectedShipSchedule = null;
SpaceBookingOrderShipSchedule shipScheduleRecord = null;
// 船期信息不能为空,请重新检索船期
if (model.PId == 0)
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPIShipScheduleNotNull)));
if (model.PId > 0)
{
if (model.id.HasValue && model.id.Value > 0)
{
var recordId = model.id.Value;
shipScheduleRecord = tenantDb.Queryable<SpaceBookingOrderShipSchedule>().First(a => a.RecordId == recordId && a.ShipRatePid != null &&
a.ShipRatePid.Value == model.PId && a.Deleted == false);
}
}
if (shipScheduleRecord == null)
{
selectedShipSchedule = GetCacheShipSailingSchedule(model.PId);
}
else
{
selectedShipSchedule = JsonConvert.DeserializeObject<MSKAPISPOTSearchScheduleRateResultDataDto>(shipScheduleRecord.ShipJson);
}
//if (selectedShipSchedule == null)
// throw Oops.Oh("船期数据校验失败,请重新查询船期信息");
//if (!selectedShipSchedule.priceID.Equals(model.priceID))
//{
// //_logger.LogInformation($"请求当前船期请求参数错误 priceID={model.priceID} 缓存priceID={selectedShipSchedule.priceID} PId={model.PId}");
// //throw Oops.Oh("船期数据校验失败,当前船期请求参数错误,请重新查询船期信息");
//}
//if (selectedShipSchedule.totalAmount.Value != model.ShipRateTotalAmount.Value)
//{
// //_logger.LogInformation($"请求当前船期请求参数错误 totalAmount={selectedShipSchedule.totalAmount.Value} 缓存totalAmount={model.ShipRateTotalAmount.Value} PId={model.PId}");
// //throw Oops.Oh("船期数据校验失败,当前船期请求参数错误,价格发生差异,请重新查询船期信息");
//}
DateTime nowDate = DateTime.Now;
var recordInfo = model.Adapt<SpaceBookingOrder>();
var recordCtnList = model.ctns.Adapt<List<SpaceBookingOrderCtn>>();
//var ctnCodeMappingList = _cache.GetAllMappingCtn().GetAwaiter().GetResult().ToList();
//if (ctnCodeMappingList.Count > 0)
// ctnCodeMappingList = ctnCodeMappingList.Where(x => x.CarrierCode == "MSK" && x.Module == "BOOK_MSK_API").ToList();
MSKAPIBookingDto bookingDto = new MSKAPIBookingDto
{
userKey = mskAPIUserKey,
userSecret = mskAPIUserSecret,
operatingEnvironment = mskAPIEnvironment,
mskAppKey = webAccountConfig.AppKey,
mskAppSecret = webAccountConfig.AppSecret,
bookingBody = new MSKAPIBookingBodyDto()
};
bookingDto.bookingBody.references = new MSKAPIBookingReferenceDto
{
priceReference = model.priceReference,
productCode = model.productCode,
sender = model.sender,
bookingOfficeUNLocationCode = "CNTAO",
isSpotTermsAndConditionsAccepted = true,
};
bookingDto.bookingBody.mandatoryParties = new MSKAPIBookingMandatoryParties
{
bookedByCompanyName = model.bookedByCompanyName,
bookedByMaerskPartyCode = model.bookedByMaerskPartyCode,
bookedByPartyContact = new MSKAPIBookingMandatoryPartyContact
{
name = model.bookedByCompanyContactName,
email = model.bookedByCompanyContactEmail
},
priceOwnerCompanyName = model.priceOwnerCompanyName,
priceOwnerMaerskPartyCode = model.priceOwnerMaerskPartyCode,
priceOwnerPartyContact = new MSKAPIBookingMandatoryPartyContact
{
name = model.priceOwnerContactName,
email = model.priceOwnerContactEmail
},
};
bookingDto.bookingBody.transport = new MSKAPIBookingTransport
{
carrierCode = model.carrierCode,
//earliestDepartureDate = model.earliestDepartureDate.Value.ToString("yyyy-MM-ddTHH:mm:ss"),
exportServiceMode = model.exportServiceMode,
importServiceMode = model.importServiceMode,
routeDetails = new MSKAPIBookingRouteDetails
{
placeOfReceipt = new MSKAPIBookingRouteDetailsBase
{
UNLocationCode = model.userPlaceOfReceiptUnLocCode,
maerskCityGeoId = selectedShipSchedule.originGeoId,
},
placeOfDelivery = new MSKAPIBookingRouteDetailsBase
{
UNLocationCode = model.userPlaceOfDeliveryUnLocCode,
maerskCityGeoId = selectedShipSchedule.destinationGeoId,
},
selectedRoute = new MSKAPIBookingRoute
{
bookingSchedules = new List<MSKAPIBookingSchedules>(),
},
}
};
//ETD
if (!string.IsNullOrWhiteSpace(selectedShipSchedule.scheduleDetails.FirstOrDefault().fromLocation.date))
{
DateTime currDate = DateTime.MinValue;
if (DateTime.TryParse($"{selectedShipSchedule.scheduleDetails.FirstOrDefault().fromLocation.date} {selectedShipSchedule.scheduleDetails.FirstOrDefault().fromLocation.time}", out currDate))
{
bookingDto.bookingBody.transport.earliestDepartureDate = currDate.ToString("yyyy-MM-ddTHH:mm:ss");
}
else
{
//throw Oops.Bah($"查询船期错误priceID={model.priceID} pid={model.PId} 预计离港日期departureDate={selectedShipSchedule.scheduleDetails.FirstOrDefault().fromLocation.date} {selectedShipSchedule.scheduleDetails.FirstOrDefault().fromLocation.time} 格式解析错误");
}
}
for (int i = 0; i < selectedShipSchedule.scheduleDetails.Count; i++)
{
var detail = selectedShipSchedule.scheduleDetails[i];
var currDto = new MSKAPIBookingSchedules();
//ETD
if (!string.IsNullOrWhiteSpace(detail.fromLocation.date))
{
DateTime currDate = DateTime.MinValue;
if (DateTime.TryParse($"{detail.fromLocation.date} {detail.fromLocation.time}", out currDate))
{
currDto.originDepartureDateTimeLocal = currDate.ToString("yyyy-MM-ddTHH:mm:ss");
}
else
{
//throw Oops.Bah($"查询船期错误priceID={model.priceID} pid={model.PId} 预计离港日期departureDate={detail.fromLocation.date} {detail.fromLocation.time} 格式解析错误");
}
}
//ETA
if (!string.IsNullOrWhiteSpace(detail.toLocation.date))
{
DateTime currDate = DateTime.MinValue;
if (DateTime.TryParse($"{detail.toLocation.date} {detail.toLocation.time}", out currDate))
{
currDto.destinationArrivalDateTimeLocal = currDate.ToString("yyyy-MM-ddTHH:mm:ss");
}
else
{
//throw Oops.Bah($"查询船期错误priceID={model.priceID} pid={model.PId} 预计离港日期ArrivalDate={detail.toLocation.date} {detail.toLocation.time} 格式解析错误");
}
}
currDto.transportMode = new MSKAPIBookingTransportMode
{
vessel = new MSKAPIBookingTransportModeVessel
{
name = detail.transport.vessel.name,
maerskVesselCode = detail.transport.vessel.code,
vesselIMONumber = detail.transport.vessel.imoNumber
},
exportVoyageNumber = detail.transport.voyageNumber,
};
currDto.serviceCode = detail.serviceCode;
currDto.transportModeCode = detail.transport.transportMode;
//首个
if (i == 0)
{
currDto.startLocation = new MSKAPIBookingRouteDetailsBase
{
cityName = detail.fromLocation.cityName,
ISOcountryCode = detail.fromLocation.countryCode,
UNLocationCode = detail.fromLocation.unLocCode,
maerskCityGeoId = detail.fromLocation.cityGeoId,
};
if (i == selectedShipSchedule.scheduleDetails.Count - 1)
{
currDto.endLocation = new MSKAPIBookingRouteDetailsBase
{
cityName = detail.toLocation.cityName,
ISOcountryCode = detail.toLocation.countryCode,
UNLocationCode = detail.toLocation.unLocCode,
maerskCityGeoId = detail.toLocation.cityGeoId,
};
}
else
{
currDto.endLocation = new MSKAPIBookingRouteDetailsBase
{
cityName = detail.toLocation.cityName,
ISOcountryCode = detail.toLocation.countryCode,
UNLocationCode = detail.toLocation.unLocCode,
maerskSiteGeoId = detail.toLocation.siteGeoId,
};
}
}
else if (i == selectedShipSchedule.scheduleDetails.Count - 1)
{
currDto.startLocation = new MSKAPIBookingRouteDetailsBase
{
cityName = detail.fromLocation.cityName,
ISOcountryCode = detail.fromLocation.countryCode,
UNLocationCode = detail.fromLocation.unLocCode,
maerskSiteGeoId = detail.fromLocation.siteGeoId,
};
currDto.endLocation = new MSKAPIBookingRouteDetailsBase
{
cityName = detail.toLocation.cityName,
ISOcountryCode = detail.toLocation.countryCode,
UNLocationCode = detail.toLocation.unLocCode,
maerskCityGeoId = detail.toLocation.cityGeoId,
};
}
else
{
currDto.startLocation = new MSKAPIBookingRouteDetailsBase
{
cityName = detail.fromLocation.cityName,
ISOcountryCode = detail.fromLocation.countryCode,
UNLocationCode = detail.fromLocation.unLocCode,
maerskSiteGeoId = detail.fromLocation.siteGeoId,
};
currDto.endLocation = new MSKAPIBookingRouteDetailsBase
{
cityName = detail.toLocation.cityName,
ISOcountryCode = detail.toLocation.countryCode,
UNLocationCode = detail.toLocation.unLocCode,
maerskSiteGeoId = detail.toLocation.siteGeoId,
};
}
bookingDto.bookingBody.transport.routeDetails.selectedRoute.bookingSchedules.Add(currDto);
}
bookingDto.bookingBody.cargo = new MSKAPIBookingCargo
{
commodityCode = model.commodityCode,
commodityCodeType = "MaerskCode",
cargoType = model.cargoType,
totalCargoWeight = model.totalCargoWeight
};
//是否冷冻处理
if (model.isReefer)
{
bookingDto.bookingBody.cargo.reeferSettings = new MSKAPIBookingCargoReeferSettings();
bookingDto.bookingBody.cargo.reeferSettings.temperatureDetails = model.temperature;
bookingDto.bookingBody.cargo.reeferSettings.temperatureMeasureUnit = "C";
bookingDto.bookingBody.cargo.reeferSettings.noOfProbes = model.noOfProbes;
//每小时需要的通风量,单位为立方米(0-285)
bookingDto.bookingBody.cargo.reeferSettings.ventilation = model.ventilation;
bookingDto.bookingBody.cargo.reeferSettings.humidity = model.humidity;
}
bookingDto.bookingBody.equipmentAndHaulage = new List<MSKAPIBookingEquipmentAndHaulage>();
if (model.ctns != null && model.ctns.Count > 0)
{
model.ctns.ForEach(ctn =>
{
var ctnMapping = mappingCtnService.QueryMappingCtn(model.carrierId, CONST_MSK_API_BOOKING_URL, ctn.ctnCode).GetAwaiter().GetResult()?.Data;
MSKAPIBookingEquipmentAndHaulage haulage = new MSKAPIBookingEquipmentAndHaulage
{
equipmentDetails = new MSKAPIBookingEquipmentAndHaulageItem(),
stuffingDetails = new List<MSKAPIBookingStuffingdetails>()
};
if (model.isShipperOwned)
haulage.equipmentDetails.isShipperOwned = model.isShipperOwned;
if (model.isImportReturned)
haulage.equipmentDetails.isImportReturned = model.isImportReturned;
haulage.equipmentDetails.ISOEquipmentCode = ctnMapping.MapCode;
haulage.equipmentDetails.equipmentQuantity = ctn.ctnNum;
haulage.stuffingDetails.Add(new MSKAPIBookingStuffingdetails
{
stuffingValue = (int)ctn.ctnSufferWeight.Value,
stuffingMeasurementType = "WEIGHT",
stuffingMeasurementUnit = "KGS"
});
bookingDto.bookingBody.equipmentAndHaulage.Add(haulage);
});
}
long id = 0;
if (isDefaultSave)
{
id = InnerSave(model, isSendApi: true).GetAwaiter().GetResult().Data;
}
else
{
id = currId;
}
result.id = id;
MSKAPIBookingResultDto resultInfo = null;
var jsonBody = Newtonsoft.Json.JsonConvert.SerializeObject(bookingDto, Formatting.Indented, new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore
});
//_logger.LogInformation($"开始请求MSK API订舱JSON={jsonBody}");
var rlt = RequestHelper.Post(jsonBody, sendUrl);
//_logger.LogInformation($"开始请求MSK API订舱返回结果 JSON={JSON.Serialize(rlt)}");
if (!string.IsNullOrWhiteSpace(rlt))
{
try
{
resultInfo = JsonConvert.DeserializeObject<MSKAPIBookingResultDto>(rlt);
}
catch (Exception ex)
{
//_logger.LogInformation($"请求MSK API订舱异常原因{ex.Message}");
//throw Oops.Bah($"请求MSK API订舱异常原因{ex.Message}");
}
}
MSKAPIBookingResultDataDto resultData = null;
if (resultInfo.code == 200)
{
resultData = JsonConvert.DeserializeObject<MSKAPIBookingResultDataDto>(JsonConvert.SerializeObject(resultInfo.data));
}
var entity = tenantDb.Queryable<SpaceBookingOrder>().First(a => a.Id == id);
if (resultInfo != null && resultInfo.code == 200
&& resultData != null)
{
entity.RequestAcknowledgementId = resultData.requestAcknowledgementId;
entity.BookingReference = resultData.bookingReference;
entity.Status = "SUCC";
entity.StatusName = "发送成功";
await tenantDb.Updateable(entity).UpdateColumns(x => new
{
x.RequestAcknowledgementId,
x.BookingReference,
x.Status,
x.StatusName
}).ExecuteCommandAsync();
}
else
{
entity.Status = "FAILURE";
entity.StatusName = "发送失败";
entity.Notes = resultInfo.msg.Length > 500 ? resultInfo.msg.Substring(0, 500) : resultInfo.msg;
await tenantDb.Updateable(entity).UpdateColumns(x => new
{
x.Status,
x.StatusName,
x.Notes
}).ExecuteCommandAsync();
//throw Oops.Bah(resultInfo.msg);
}
result.succ = true;
}
catch (Exception ex)
{
//_logger.LogError($"MSK API订舱异常req={JSON.Serialize(model)} 原因:{ex.Message}");
//throw Oops.Bah($"MSK API订舱失败{ex.Message}");
result.succ = false;
result.msg = $"MSK API SPOT 订舱失败,{ex.Message}";
//throw Oops.Bah($"MSK API订舱失败{ex.Message}");
}
return DataResult<MSKBookingResultDto>.Success(result);
}
#endregion
#region 校验马士基API订舱必填项
/// <summary>
/// 校验马士基API订舱必填项
/// </summary>
/// <param name="model"></param>
private void ValidateMSKAPIData(MSKSPOTBookingDto model)
{
/*
马士基API订舱内容校验
1、合约号必填
2、请求类别必填
3、服务船公司必填
4、订舱公司名称、代码、联系人、邮箱必填
5、持约方公司名称、代码、联系、邮箱必填
6、始发地城市名称、UNLOC、国家代码、服务模式
7、目的地城市名称、UNLOC、国家代码、服务模式
8、船名、航次、ETD、ETA
9、商品名称、代码必填
10、总重必填
11、货物标志必填
12、如果选择了冷冻处理至少要填个温度
13、箱型、箱量、重量必填
14、总重=箱量*单箱重量
15、预计离港日期必填
*/
//订舱合同惟一ID必填
if (string.IsNullOrWhiteSpace(model.priceReference))
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPIPriceReferNull)));
//订舱合同惟一ID格式错误 [a-zA-Z0-9_/,-]{1,50}
if (!Regex.IsMatch(model.priceReference, "[a-zA-Z0-9_/,-]{1,50}"))
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPIPriceReferFormatError)));
//请求类别必填
if (string.IsNullOrWhiteSpace(model.sender))
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPISenderNull)));
//服务船公司代码必填
if (string.IsNullOrWhiteSpace(model.carrierCode))
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPICarrierCodeNull)));
//订舱公司名称必填
if (string.IsNullOrWhiteSpace(model.bookedByCompanyName))
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPIBookCompanyNameNull)));
//订舱方ID必填
if (string.IsNullOrWhiteSpace(model.bookedByMaerskPartyCode))
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPIBookCompanyCodeNull)));
//订舱方公司联系人必填
if (string.IsNullOrWhiteSpace(model.bookedByCompanyContactName))
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPIBookCompanyContactNull)));
//订舱方公司邮箱必填
if (string.IsNullOrWhiteSpace(model.bookedByCompanyContactEmail))
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPIBookCompanyContactEmailNull)));
//持约方公司名称必填
if (string.IsNullOrWhiteSpace(model.priceOwnerCompanyName))
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPIPriceOwnerCompanyNameNull)));
//持约方ID必填
if (string.IsNullOrWhiteSpace(model.priceOwnerMaerskPartyCode))
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPIPriceOwnerCompanyCodeNull)));
//持约方公司联系人必填
if (string.IsNullOrWhiteSpace(model.priceOwnerContactName))
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPIPriceOwnerCompanyContactNull)));
//持约方公司邮箱必填
if (string.IsNullOrWhiteSpace(model.priceOwnerContactEmail))
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPIPriceOwnerCompanyContactEmailNull)));
//始发地城市名称必填
if (string.IsNullOrWhiteSpace(model.placeOfReceiptCityName))
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPIOriginCityNameNull)));
//始发地UN CODE必填
if (string.IsNullOrWhiteSpace(model.placeOfReceiptUnLocCode))
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPIOriginUnCodeNull)));
//始发地国家代码必填
if (string.IsNullOrWhiteSpace(model.placeOfReceiptCountryCode))
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPIOriginCountryCodeNull)));
//始发地服务模式必填
if (string.IsNullOrWhiteSpace(model.exportServiceMode))
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPIOriginServiceModeNull)));
//目的地城市名称必填
if (string.IsNullOrWhiteSpace(model.placeOfDeliveryCityName))
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPIDestCityNameNull)));
//目的地UN CODE必填
if (string.IsNullOrWhiteSpace(model.placeOfDeliveryUnLocCode))
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPIDestUnCodeNull)));
//目的地国家代码必填
if (string.IsNullOrWhiteSpace(model.placeOfDeliveryCountryCode))
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPIDestCountryCodeNull)));
//目的地服务模式必填
if (string.IsNullOrWhiteSpace(model.importServiceMode))
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPIDestServiceModeNull)));
//船名必填,请确认正确选择了船期
if (string.IsNullOrWhiteSpace(model.vesselName))
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPIVesselNameNull)));
//航次号必填,请确认正确选择了船期
if (string.IsNullOrWhiteSpace(model.exportVoyageNumber))
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPIVoynoNull)));
//ETD必填请确认正确选择了船期
if (!model.originDepartureDateTimeLocal.HasValue)
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPIOriginDepartureDateNull)));
//ETA必填请确认正确选择了船期
if (!model.destinationArrivalDateTimeLocal.HasValue)
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPIDestArrivalDateNull)));
//商品代码必填,请确认正确选择了商品
if (string.IsNullOrWhiteSpace(model.commodityCode))
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPICommodityNull)));
//商品名称必填,请确认正确选择了商品
if (string.IsNullOrWhiteSpace(model.commodityName))
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPICommodityNameNull)));
//总重必填
if (!model.totalCargoWeight.HasValue || model.totalCargoWeight.Value < 1)
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPITotalCargoWTNull)));
//货物标志必填
if (string.IsNullOrWhiteSpace(model.cargoType))
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPICargoTypeNull)));
//预计离港日期必填
if (!model.earliestDepartureDate.HasValue)
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPIEarliestDepartDateNull)));
if (model.isReefer)
{
//选择了冷冻处理,温度必填
if (!model.temperature.HasValue)
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPIIsReeferTempNull)));
}
//箱型箱量信息必填
if (model.ctns.Count == 0)
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPICtnAndNumNull)));
//箱型不能为空
if (model.ctns.Any(a => string.IsNullOrWhiteSpace(a.ctnCode)))
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPICtnCodeNull)));
//箱量不能为空并且不能小于1
if (model.ctns.Any(a => !a.ctnNum.HasValue || a.ctnNum.Value < 1))
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPICtnNumLower)));
//箱内重量不能为空并且不能小于1
if (model.ctns.Any(a => !a.ctnSufferWeight.HasValue || a.ctnSufferWeight.Value < 1))
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPICtnSufferWeightLower)));
//箱内重量合计不等于总重,请修改
if (model.totalCargoWeight.Value != model.ctns.Sum(b => b.ctnNum.Value * b.ctnSufferWeight.Value))
{
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPICtnWeightUnequalTotal)));
}
//当前订舱合同号是非订舱方合约持约方不能和订舱方ID信息一样请根据实际情况填写
if (!model.isBookingPartOwnPrice)
{
//当前订舱合同号是非订舱方合约持约方不能和订舱方ID信息一样请根据实际情况填写
if (model.bookedByMaerskPartyCode.Equals(model.priceOwnerMaerskPartyCode))
{
//throw Oops.Bah($"当前订舱合同号是非订舱方合约持约方不能和订舱方ID信息一样请根据实际情况填写");
}
//当前订舱合同号是非订舱方合约,持约方公司名称不能和订舱方公司名称信息一样,请根据实际情况填写
if (model.bookedByCompanyName.Equals(model.priceOwnerCompanyName))
{
//throw Oops.Bah($"当前订舱合同号是非订舱方合约,持约方公司名称不能和订舱方公司名称信息一样,请根据实际情况填写");
}
}
else
{
//当前订舱合同号是订舱方合约持约方ID必需和订舱方ID信息一致请根据实际情况填写
if (!model.bookedByMaerskPartyCode.Equals(model.priceOwnerMaerskPartyCode))
{
//throw Oops.Bah($"当前订舱合同号是订舱方合约持约方ID必需和订舱方ID信息一致请根据实际情况填写");
}
//当前订舱合同号是订舱方合约,持约方名称必需和订舱方名称信息一致,请根据实际情况填写
if (!model.bookedByCompanyName.Equals(model.priceOwnerCompanyName))
{
//throw Oops.Bah($"当前订舱合同号是订舱方合约,持约方名称必需和订舱方名称信息一致,请根据实际情况填写");
}
}
}
#endregion
#region 检索商品名称
/// <summary>
/// 检索商品名称
/// </summary>
/// <param name="model">请求详情</param>
/// <returns>返回检索结果</returns>
public async Task<DataResult<List<SearchCommodityResultDto>>> SearchCommodities(QueryCommoditiesDto model)
{
List<SearchCommodityResultDto> list = new List<SearchCommodityResultDto>();
/*
MSKApiCommodity
*/
try
{
//商品名称不能为空
if (string.IsNullOrWhiteSpace(model.commodityName))
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPICommodityNameQueryNull)));
//if (string.IsNullOrWhiteSpace(model.carrierId))
// throw Oops.Oh("船公司代码不能为空");
//if (model.commodityName.Length < 3)
// throw Oops.Oh("商品名称至少输入3个以上字符");
string queryUrl = string.Empty;
if (model.carrierCode.Equals("MSK", StringComparison.OrdinalIgnoreCase))
{
queryUrl = configService.GetConfig(CONST_MSK_API_COMMODITY_URL).GetAwaiter().GetResult()?.Data?.Value;
}
else
{
//throw Oops.Oh($"当前船公司 {model.carrierId} 未配置相应的请求接口");
}
//if (string.IsNullOrWhiteSpace(queryUrl))
// throw Oops.Oh("未配置商品请求接口地址,请联系管理员");
//var webAccountConfig = _webAccountConfig
// .GetAccountConfig("MSKApi", UserManager.UserId).GetAwaiter().GetResult();
var webAccountConfig = codeThirdPartyService.GetCodeThirdPartyInfoWithCompany("MSKApi").GetAwaiter().GetResult()?.Data;
//if (webAccountConfig == null)
// throw Oops.Oh("未配置个人账户,请先配置个人账户 类型-MSKApi");
MSKAPISearchCommodityDto queryInfo = new MSKAPISearchCommodityDto
{
userKey = mskAPIUserKey,
userSecret = mskAPIUserSecret,
operatingEnvironment = mskAPIEnvironment,
mskAppKey = webAccountConfig.AppKey
};
MSKAPISearchCommodityResultDto resultInfo = null;
var rlt = RequestHelper.Post(JsonConvert.SerializeObject(queryInfo), queryUrl);
if (!string.IsNullOrWhiteSpace(rlt))
{
try
{
resultInfo = JsonConvert.DeserializeObject<MSKAPISearchCommodityResultDto>(rlt);
}
catch (Exception ex)
{
//_logger.LogInformation($"请求MSK API检索商品异常原因{ex.Message}");
//throw Oops.Bah($"请求MSK API检索商品异常原因{ex.Message}");
}
}
if (resultInfo != null && resultInfo.code == 200
&& resultInfo.data != null && resultInfo.data.Count > 0)
{
list = resultInfo.data.Adapt<List<SearchCommodityResultDto>>();
}
}
catch (Exception ex)
{
//_logger.LogError($"检索商品名称异常req={JSON.Serialize(model)} 原因:{ex.Message}");
//throw Oops.Bah($"检索商品名称失败,{ex.Message}");
}
return DataResult<List<SearchCommodityResultDto>>.Success(list);
}
#endregion
#region 获取马士基API订舱详情
/// <summary>
/// 获取马士基API订舱详情
/// </summary>
/// <param name="id">马士基API订舱ID</param>
/// <returns>返回详情</returns>
public async Task<DataResult<MSKSPOTBookingDto>> GetInfo(long id)
{
MSKSPOTBookingDto model = null;
var tenantDb = saasService.GetBizDbScopeById(user.TenantId);
var entity = await tenantDb.Queryable<SpaceBookingOrder>().FirstAsync(a => a.Id == id);
//if (entity == null)
//throw Oops.Oh($"获取马士基API订舱详情失败不存在或已作废");
model = entity.Adapt<MSKSPOTBookingDto>();
var ctnList = tenantDb.Queryable<SpaceBookingOrderCtn>().Where(a => a.RecordId == id && a.Deleted == false).ToList();
if (ctnList.Count > 0)
{
model.ctns = ctnList.Select(a => new MSKBookingCtnInfo
{
id = a.Id,
ctnCode = a.CtnCode,
carrierCtnCode = a.CarrierCtnCode,
ctnNum = a.CtnNum,
ctnName = a.CtnName,
ctnSufferWeight = a.CtnSufferWeight,
stuffingMeasurementType = a.StuffingMeasurementType,
stuffingMeasurementUnit = a.StuffingMeasurementUnit
}).ToList();
}
MSKAPISPOTSearchScheduleRateResultDataDto selectedShipSchedule = null;
if (model.PId > 0)
{
var shipScheduleRecord = await tenantDb.Queryable<SpaceBookingOrderShipSchedule>()
.FirstAsync(a => a.ShipRatePid != null && a.ShipRatePid.Value == model.PId);
if (shipScheduleRecord != null)
{
selectedShipSchedule = JsonConvert.DeserializeObject<MSKAPISPOTSearchScheduleRateResultDataDto>(shipScheduleRecord.ShipJson);
if (selectedShipSchedule != null)
{
model.selectedShipScheduleShow = GetShipScheduleShow(selectedShipSchedule);
}
}
}
return DataResult<MSKSPOTBookingDto>.Success(model);
}
#endregion
#region 保存
/// <summary>
/// 保存
/// </summary>
/// <param name="model">请求订舱详情</param>
/// <returns>返回ID</returns>
public async Task<DataResult<long>> Save([FromBody] MSKSPOTBookingDto model)
{
return await InnerSave(model);
}
#endregion
#region 保存内部方法
/// <summary>
/// 保存内部方法
/// </summary>
/// <param name="model">API订舱详情</param>
/// <param name="isSendApi">是否发送APItrue-发送需要校验状态false-不校验状态</param>
/// <returns></returns>
private async Task<DataResult<long>> InnerSave(MSKSPOTBookingDto model, bool isSendApi = false)
{
DateTime nowDate = DateTime.Now;
string ctnStat = string.Empty;
var tenantDb = saasService.GetBizDbScopeById(user.TenantId);
//_logger.LogInformation($"获取请求马士基API订舱报文JSON={JSON.Serialize(model)}");
MSKAPISPOTSearchScheduleRateResultDataDto selectedShipSchedule = null;
SpaceBookingOrderShipSchedule shipScheduleRecord = null;
if (model.PId > 0)
{
if (model.id.HasValue && model.id.Value > 0)
{
var recordId = model.id.Value;
shipScheduleRecord = await tenantDb.Queryable<SpaceBookingOrderShipSchedule>()
.FirstAsync(a => a.RecordId == recordId && a.ShipRatePid != null &&
a.ShipRatePid.Value == model.PId && a.Deleted == false);
}
if (shipScheduleRecord == null)
{
selectedShipSchedule = GetCacheShipSailingSchedule(model.PId);
}
else
{
selectedShipSchedule = JsonConvert.DeserializeObject<MSKAPISPOTSearchScheduleRateResultDataDto>(shipScheduleRecord.ShipJson);
}
//if (selectedShipSchedule == null)
// throw Oops.Oh("船期数据校验失败,请重新查询船期信息");
//if (!selectedShipSchedule.priceID.Equals(model.priceID))
//{
// _logger.LogInformation($"请求当前船期请求参数错误 priceID={model.priceID} 缓存priceID={selectedShipSchedule.priceID} PId={model.PId}");
// throw Oops.Oh("船期数据校验失败,当前船期请求参数错误,请重新查询船期信息");
//}
//if (selectedShipSchedule.totalAmount.Value != model.ShipRateTotalAmount.Value)
//{
// _logger.LogInformation($"请求当前船期请求参数错误 totalAmount={selectedShipSchedule.totalAmount.Value} 缓存totalAmount={model.ShipRateTotalAmount.Value} PId={model.PId}");
// throw Oops.Oh("船期数据校验失败,当前船期请求参数错误,价格发生差异,请重新查询船期信息");
//}
model.placeOfReceiptCountryName = selectedShipSchedule.originCountryName;
model.placeOfReceiptRegionName = selectedShipSchedule.originRegionName;
model.carrierCollectionOriginGeoID = selectedShipSchedule.originGeoId;
model.placeOfDeliveryCountryName = selectedShipSchedule.destinationCountryName;
model.placeOfDeliveryRegionName = selectedShipSchedule.destinationRegionName;
model.carrierDeliveryDestinationGeoID = selectedShipSchedule.destinationGeoId;
}
if (model.ctns != null && model.ctns.Count > 0)
{
ctnStat = string.Join(",", model.ctns.GroupBy(a => a.ctnName)
.Select(a => $"{a.Key}*{a.ToList().Sum(b => b.ctnNum.HasValue ? b.ctnNum.Value : 0)}").ToArray());
}
if (model.id.HasValue && model.id.Value > 0)
{
var oldInfo = tenantDb.Queryable<SpaceBookingOrder>()
.First(a => a.Id == model.id);
//if (oldInfo == null)
//throw Oops.Oh("订舱数据不存在或已作废");
if (oldInfo.Status == "SUCC")
{
//if (isSendApi)
//throw Oops.Oh("订舱数据已发送成功,不能重复发送");
//throw Oops.Oh("订舱数据已发送成功,不能修改");
}
SpaceBookingOrder entity = model.Adapt<SpaceBookingOrder>();
entity.Id = model.id.Value;
entity.UpdateTime = nowDate;
entity.UpdateBy = long.Parse(user.UserId);
//entity.UpdatedUserName = UserManager.Name;
entity.CtnStat = ctnStat;
entity.BookingChannelType = "SPOT_API";
entity.BookingChannelTypeName = "SPOT订舱";
await tenantDb.Updateable<SpaceBookingOrder>(entity).IgnoreColumns(x => new
{
x.CreateTime,
x.CreateBy,
//x.CreatedUserName,
x.BookingReference,
x.BookingId,
x.RequestAcknowledgementId,
x.Status,
//x.TenantId,
x.IsRecvBC,
x.LstRecvBCDate,
x.IsRecvBKCancel,
x.LstRecvBKCancelDate
}).ExecuteCommandAsync();
if (model.ctns != null && model.ctns.Count > 0)
{
var ctnEntityList = tenantDb.Queryable<SpaceBookingOrderCtn>()
.Where(a => a.RecordId == entity.Id && a.Deleted == false).ToList();
model.ctns.ForEach(ctn =>
{
if (ctn.id.HasValue && ctn.id.Value > 0)
{
if (ctnEntityList.Any(x => x.Id == ctn.id.Value))
{
ctnEntityList.Remove(ctnEntityList.FirstOrDefault(x => x.Id == ctn.id.Value));
}
//更新
var ctnEntity = ctn.Adapt<SpaceBookingOrderCtn>();
ctnEntity.Id = ctn.id.Value;
ctnEntity.RecordId = entity.Id;
ctnEntity.UpdateTime = nowDate;
ctnEntity.UpdateBy = long.Parse(user.UserId);
//ctnEntity.UpdatedUserName = UserManager.Name;
tenantDb.Updateable<SpaceBookingOrderCtn>(ctnEntity).IgnoreColumns(x => new {
x.CreateBy,
//x.CreatedUserName,
x.CreateTime,
//x.TenantId,
x.StuffingMeasurementType,
x.StuffingMeasurementUnit,
x.CtnSufferWeight
}).ExecuteCommand();
}
else
{
var ctnEntity = new SpaceBookingOrderCtn
{
CtnCode = ctn.ctnCode,
CtnName = ctn.ctnName,
CtnNum = ctn.ctnNum.Value,
CtnSufferWeight = (int)ctn.ctnSufferWeight.Value,
};
ctnEntity.RecordId = entity.Id;
ctnEntity.CreateTime = nowDate;
ctnEntity.UpdateTime = nowDate;
ctnEntity.CreateBy = long.Parse(user.UserId);
//ctnEntity.CreatedUserName = UserManager.Name;
ctnEntity.StuffingMeasurementType = "WEIGHT";
ctnEntity.StuffingMeasurementUnit = "KGS";
tenantDb.Insertable<SpaceBookingOrderCtn>(ctnEntity).ExecuteCommand();
}
});
if (ctnEntityList.Count > 0)
{
ctnEntityList.ForEach(async ctn => {
ctn.Deleted = true;
ctn.DeleteTime = nowDate;
ctn.DeleteBy = long.Parse(user.UserId);
//ctn.UpdatedUserName = UserManager.Name;
await tenantDb.Updateable<SpaceBookingOrderCtn>(ctn).UpdateColumns(x => new {
x.Deleted,
x.DeleteTime,
x.DeleteBy,
//x.UpdatedUserName
}).ExecuteCommandAsync();
});
}
}
if (shipScheduleRecord == null)
{
if (model.PId > 0 && selectedShipSchedule != null)
{
shipScheduleRecord = new SpaceBookingOrderShipSchedule
{
Id = SnowFlakeSingle.Instance.NextId(),
RecordId = model.id.Value,
ShipRatePid = selectedShipSchedule.PId,
ShipRateMD5 = selectedShipSchedule.MD5,
ShipJson = Newtonsoft.Json.JsonConvert.SerializeObject(selectedShipSchedule),
CreateTime = nowDate,
UpdateTime = nowDate,
CreateBy = long.Parse(user.UserId),
//CreatedUserName = UserManager.Name
};
await tenantDb.Insertable<SpaceBookingOrderShipSchedule>(shipScheduleRecord).ExecuteCommandAsync();
}
}
return DataResult<long>.Success(model.id.Value);
}
else
{
SpaceBookingOrder entity = model.Adapt<SpaceBookingOrder>();
entity.CreateTime = nowDate;
entity.UpdateTime = nowDate;
entity.CreateBy = long.Parse(user.UserId);
//entity.CreatedUserName = UserManager.Name;
entity.Status = "TEMP";
entity.StatusName = "暂存";
entity.CtnStat = ctnStat;
entity.BookingChannelType = "SPOT_API";
entity.BookingChannelTypeName = "SPOT订舱";
await tenantDb.Insertable<SpaceBookingOrder>(entity).ExecuteReturnEntityAsync();
if (model.ctns != null && model.ctns.Count > 0)
{
model.ctns.ForEach(ctn =>
{
var ctnEntity = new SpaceBookingOrderCtn
{
CtnCode = ctn.ctnCode,
CtnName = ctn.ctnName,
CtnNum = ctn.ctnNum.Value,
CtnSufferWeight = (int)ctn.ctnSufferWeight.Value,
};
ctnEntity.RecordId = entity.Id;
ctnEntity.CreateTime = nowDate;
ctnEntity.UpdateTime = nowDate;
ctnEntity.CreateBy = long.Parse(user.UserId);
//ctnEntity.CreatedUserName = UserManager.Name;
ctnEntity.StuffingMeasurementType = "WEIGHT";
ctnEntity.StuffingMeasurementUnit = "KGS";
tenantDb.Insertable<SpaceBookingOrderCtn>(ctnEntity).ExecuteCommand();
});
}
if (shipScheduleRecord == null)
{
if (model.PId > 0 && selectedShipSchedule != null)
{
shipScheduleRecord = new SpaceBookingOrderShipSchedule
{
Id = SnowFlakeSingle.Instance.NextId(),
RecordId = entity.Id,
ShipRatePid = selectedShipSchedule.PId,
ShipRateMD5 = selectedShipSchedule.MD5,
ShipJson = Newtonsoft.Json.JsonConvert.SerializeObject(selectedShipSchedule),
CreateTime = nowDate,
UpdateTime = nowDate,
CreateBy = long.Parse(user.UserId),
//CreatedUserName = UserManager.Name
};
await tenantDb.Insertable<SpaceBookingOrderShipSchedule>(shipScheduleRecord).ExecuteCommandAsync();
}
}
else
{
//只有船期发生变化时才重新写入新的船期记录
if (model.PId != shipScheduleRecord.ShipRatePid.Value)
{
//_logger.LogInformation($"MSK CON id={model.id} 换了船期 原记录:{selectedShipSchedule.PId} 新记录:{model.PId} 作废原船期,插入新船期");
shipScheduleRecord.Deleted = true;
shipScheduleRecord.DeleteTime = nowDate;
shipScheduleRecord.DeleteBy = long.Parse(user.UserId);
//shipScheduleRecord.UpdatedUserName = UserManager.Name;
await tenantDb.Updateable<SpaceBookingOrderShipSchedule>(shipScheduleRecord).UpdateColumns(x => new {
x.Deleted,
x.DeleteTime,
x.DeleteBy,
//x.UpdatedTime
}).ExecuteCommandAsync();
shipScheduleRecord = new SpaceBookingOrderShipSchedule
{
Id = SnowFlakeSingle.Instance.NextId(),
RecordId = model.id.Value,
ShipRatePid = selectedShipSchedule.PId,
ShipRateMD5 = selectedShipSchedule.MD5,
ShipJson = Newtonsoft.Json.JsonConvert.SerializeObject(selectedShipSchedule),
CreateTime = nowDate,
UpdateTime = nowDate,
CreateBy = long.Parse(user.UserId),
//CreatedUserName = UserManager.Name
};
await tenantDb.Insertable<SpaceBookingOrderShipSchedule>(shipScheduleRecord).ExecuteCommandAsync();
}
else
{
//_logger.LogInformation($"MSK CON id={model.id} 船期没变化 model.PId={model.PId} shipScheduleRecord.SHIP_RATE_PID={shipScheduleRecord.SHIP_RATE_PID.Value}");
}
}
return DataResult<long>.Success(entity.Id);
}
}
#endregion
#region 删除
/// <summary>
/// 删除
/// </summary>
/// <param name="id">请求订舱ID</param>
/// <returns></returns>
public async Task<DataResult<string>> Delete(long id)
{
var tenantDb = saasService.GetBizDbScopeById(user.TenantId);
var info = tenantDb.Queryable<SpaceBookingOrder>().First(a => a.Id == id);
//删除失败,业务信息不存在或已作废
if (info == null)
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPIDeleteFailNoExists)));
info.Deleted = true;
info.DeleteTime = DateTime.Now;
info.DeleteBy = long.Parse(user.UserId);
//info.UpdatedUserName = UserManager.Name;
await tenantDb.Updateable<SpaceBookingOrder>(info).UpdateColumns(x => new {
x.Deleted,
x.DeleteTime,
x.DeleteBy
}).ExecuteCommandAsync();
return DataResult<string>.Success("成功");
}
#endregion
#region 批量发送
/// <summary>
/// 批量发送
/// </summary>
/// <param name="ids">马士基API订舱ID组</param>
/// <returns>返回执行结果消息</returns>
public async Task<DataResult<string>> BatchSend(long[] ids)
{
var tenantDb = saasService.GetBizDbScopeById(user.TenantId);
var list = await tenantDb.Queryable<SpaceBookingOrder>()
.Where(a => ids.Contains(a.Id)).ToListAsync();
//if (list.Count != ids.Length)
//throw Oops.Oh("订舱数据获取失败,请确认选中的记录是否存在");
List<string> msgList = new List<string>();
int totalNum = list.Count;
int succNum = 0;
int failNum = 0;
if (list.Count > 1)
{
list.ForEach(entity =>
{
MSKBookingResultDto result = null;
try
{
var model = GetInfo(entity.Id).GetAwaiter().GetResult().Data;
result = InnerSendMSKBooking(model, entity.Id, false).GetAwaiter().GetResult()?.Data;
succNum++;
}
catch (Exception ex)
{
msgList.Add(ex.Message);
failNum++;
}
Thread.Sleep(1000);
});
msgList.Add($"共计{totalNum} 条 成功{succNum}条 失败:{failNum}");
}
else
{
MSKBookingResultDto result = null;
try
{
var entity = list.FirstOrDefault();
var model = GetInfo(entity.Id).GetAwaiter().GetResult()?.Data;
result = InnerSendMSKBooking(model, entity.Id, false).GetAwaiter().GetResult()?.Data;
if (result.succ)
return DataResult<string>.Success("成功");
}
catch (Exception ex)
{
msgList.Add(ex.Message);
}
}
return DataResult<string>.Success(string.Join("#", msgList.ToArray()));
}
#endregion
#region 批量复制
/// <summary>
/// 批量复制
/// </summary>
/// <param name="model">马士基API批量复制指定数据</param>
/// <returns>返回执行结果消息</returns>
public async Task<DataResult<string>> BatchCopy(MSKAPISPOTBookingCopyDto model)
{
//if (model.copyNum < 1)
// throw Oops.Oh($"复制数量不能小于1");
//if (model.copyNum > 1000)
// throw Oops.Oh($"复制数量不能大于1000");
//if (string.IsNullOrWhiteSpace(model.opType))
// throw Oops.Oh($"请求的操作类型不能为空");
var tenantDb = saasService.GetBizDbScopeById(user.TenantId);
var entity = await tenantDb.Queryable<SpaceBookingOrder>().FirstAsync(a => a.Id == model.originalId);
//if (entity == null)
// throw Oops.Oh($"获取马士基API订舱详情失败不存在或已作废");
var ctnList = tenantDb.Queryable<SpaceBookingOrderCtn>()
.Where(a => a.RecordId == model.originalId && a.Deleted == false).ToList();
var numArg = "".PadLeft(model.copyNum, '0').Select((a, idx) => idx + 1).ToList();
DateTime nowDate = DateTime.Now;
//_logger.LogInformation("获取到批量复制功能");
//如果是指定的编辑信息需要先把编辑数据同步到实体类,再进行复制
if (model.opType == "copy_edit")
{
string ctnStat = string.Empty;
if (model.bookingDto.ctns != null && model.bookingDto.ctns.Count > 0)
{
ctnStat = string.Join(",", model.bookingDto.ctns.GroupBy(a => a.ctnName)
.Select(a => $"{a.Key}*{a.ToList().Sum(b => b.ctnNum.HasValue ? b.ctnNum.Value : 0)}").ToArray());
ctnList = new List<SpaceBookingOrderCtn>();
model.bookingDto.ctns.ForEach(ctn =>
{
var ctnEntity = new SpaceBookingOrderCtn
{
CtnCode = ctn.ctnCode,
CtnName = ctn.ctnName,
CtnNum = ctn.ctnNum.Value,
CtnSufferWeight = (int)ctn.ctnSufferWeight.Value,
};
ctnEntity.CreateTime = nowDate;
ctnEntity.UpdateTime = nowDate;
ctnEntity.CreateBy = long.Parse(user.UserId);
//ctnEntity.CreatedUserName = UserManager.Name;
ctnEntity.StuffingMeasurementType = "WEIGHT";
ctnEntity.StuffingMeasurementUnit = "KGS";
ctnList.Add(ctnEntity);
});
}
entity = model.bookingDto.Adapt<SpaceBookingOrder>();
entity.CreateTime = nowDate;
entity.UpdateTime = nowDate;
entity.CreateBy = long.Parse(user.UserId);
//entity.CreatedUserName = UserManager.Name;
entity.Status = "TEMP";
entity.StatusName = "暂存";
entity.CtnStat = ctnStat;
entity.BookingChannelType = "SPOT_API";
entity.BookingChannelTypeName = "SPOT订舱";
}
MSKAPISPOTSearchScheduleRateResultDataDto selectedShipSchedule = null;
if (entity.ShipRatePId > 0)
{
SpaceBookingOrderShipSchedule shipScheduleRecord = await tenantDb.Queryable<SpaceBookingOrderShipSchedule>()
.FirstAsync(a => a.RecordId == entity.Id && a.ShipRatePid != null &&
a.ShipRatePid.Value == entity.ShipRatePId && a.Deleted == false);
if (shipScheduleRecord != null)
{
selectedShipSchedule = JsonConvert.DeserializeObject<MSKAPISPOTSearchScheduleRateResultDataDto>(shipScheduleRecord.ShipJson);
}
}
int totalNum = 0;
foreach (var a in numArg)
{
var copyEntity = entity.Adapt<SpaceBookingOrder>();
copyEntity.Id = 0;
copyEntity.CreateTime = nowDate;
copyEntity.CreateBy = long.Parse(user.UserId);
//copyEntity.CreatedUserName = UserManager.Name;
copyEntity.UpdateTime = nowDate;
copyEntity.Status = "TEMP";
copyEntity.StatusName = "暂存";
copyEntity.IsRecvBC = false;
copyEntity.LstRecvBCDate = null;
copyEntity.IsRecvBKCancel = false;
copyEntity.LstRecvBKCancelDate = null;
copyEntity.RequestAcknowledgementId = null;
copyEntity.BookingReference = null;
copyEntity.Notes = $"COPY NO.{a} BY={model.originalId}";
await tenantDb.Insertable<SpaceBookingOrder>(copyEntity).ExecuteReturnEntityAsync();
totalNum++;
if (ctnList.Count > 0)
{
ctnList.ForEach(async ctn =>
{
var ctnEntity = ctn.Adapt<SpaceBookingOrderCtn>();
ctnEntity.Id = 0;
ctnEntity.RecordId = copyEntity.Id;
ctnEntity.CreateTime = nowDate;
ctnEntity.UpdateTime = nowDate;
ctnEntity.CreateBy = long.Parse(user.UserId);
//ctnEntity.CreatedUserName = UserManager.Name;
await tenantDb.Insertable<SpaceBookingOrderCtn>(ctnEntity).ExecuteReturnEntityAsync();
});
}
if (copyEntity.ShipRatePId > 0 && selectedShipSchedule != null)
{
var shipScheduleRecord = new SpaceBookingOrderShipSchedule
{
Id = SnowFlakeSingle.Instance.NextId(),
RecordId = copyEntity.Id,
PriceId = copyEntity.PriceId,
ShipRatePid = selectedShipSchedule.PId,
ShipRateMD5 = selectedShipSchedule.MD5,
ShipRateTotalAmount = selectedShipSchedule.totalAmount.HasValue ? selectedShipSchedule.totalAmount.Value : 0,
ShipRateTotalCurrency = selectedShipSchedule.totalCurrency,
ShipJson = Newtonsoft.Json.JsonConvert.SerializeObject(selectedShipSchedule),
CreateTime = nowDate,
UpdateTime = nowDate,
CreateBy = long.Parse(user.UserId),
//CreatedUserName = UserManager.Name
};
await tenantDb.Insertable<SpaceBookingOrderShipSchedule>(shipScheduleRecord).ExecuteReturnEntityAsync();
}
}
return DataResult<string>.Success(JsonConvert.SerializeObject(new { Total = totalNum }));
}
#endregion
#region 同步BC状态BC,Cancellation
/// <summary>
/// 同步BC状态BC,Cancellation
/// </summary>
/// <param name="mblno">提单号</param>
/// <param name="tenantId">租户ID</param>
/// <param name="opTypeName">操作类型 BC-同步BC状态 Cancellation-同步取消状态</param>
/// <returns>返回回执</returns>
public async Task<DataResult<MSKBookingResultDto>> SyncBCInfo(string mblno, long tenantId, string opTypeName = "BookingConfirmation")
{
MSKBookingResultDto result = new MSKBookingResultDto();
try
{
var tenantDb = saasService.GetBizDbScopeById(user.TenantId);
var model = await tenantDb.Queryable<SpaceBookingOrder>()
.FirstAsync(a => a.BookingReference == mblno && a.Deleted == false);
//预订舱数据不存在或已作废
if (model == null)
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPIOrderDeletedOrNoExists)));
DateTime nowDate = DateTime.Now;
if (opTypeName == "BookingConfirmation")
{
model.IsRecvBC = true;
model.LstRecvBCDate = nowDate;
model.UpdateTime = nowDate;
model.UpdateBy = long.Parse(user.UserId);
//model.UpdatedUserName = UserManager.Name;
await tenantDb.Updateable<SpaceBookingOrder>(model).UpdateColumns(x => new
{
x.IsRecvBC,
x.LstRecvBCDate,
x.UpdateTime,
x.UpdateBy,
//x.UpdatedUserName
}).ExecuteCommandAsync();
}
else if (opTypeName == "Cancellation")
{
model.IsRecvBKCancel = true;
model.LstRecvBKCancelDate = nowDate;
model.UpdateTime = nowDate;
model.UpdateBy = long.Parse(user.UserId);
//model.UpdatedUserName = UserManager.Name;
await tenantDb.Updateable<SpaceBookingOrder>(model).UpdateColumns(x => new
{
x.IsRecvBKCancel,
x.LstRecvBKCancelDate,
x.UpdateTime,
x.UpdateBy,
//x.UpdatedUserName
}).ExecuteCommandAsync();
}
result.succ = true;
}
catch (Exception ex)
{
result.succ = false;
result.msg = $"同步BC状态异常原因{ex.Message}";
}
return DataResult<MSKBookingResultDto>.Success(result);
}
#endregion
#region 批量复制前调取校验预警
/// <summary>
/// 批量复制前调取校验预警
/// </summary>
/// <param name="model">马士基API批量复制指定数据</param>
/// <returns>返回提示信息</returns>
public async Task<DataResult<string>> CheckWarningBatchCopy(MSKAPISPOTBookingCopyDto model)
{
/*
主要校验内容
1、如果待复制的单子里还有“托运人自己的集装箱”或“进口退货集装箱或者其他三角集运”需要做提醒是否继续复制。
2、如果是opType=copy_edit-复制使用提交的编辑信息,需要判断原始货物标志变化是否继续。
3、如果是冷冻处理的提示是否继续。
*/
var tenantDb = saasService.GetBizDbScopeById(user.TenantId);
var entity = await tenantDb.Queryable<SpaceBookingOrder>().FirstAsync(a => a.Id == model.originalId);
if (entity != null)
{
List<string> msgList = new List<string>();
if (entity.IsShipperOwner || (model.bookingDto != null && model.bookingDto.isShipperOwned))
{
//含有指定托运人自己的集装箱
msgList.Add(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPIIncludeShipperOwner)));
}
if (entity.IsImportReturned || (model.bookingDto != null && model.bookingDto.isImportReturned))
{
//含有指定进口退货集装箱或者其他三角集运
msgList.Add(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPIIncludeImportReturned)));
}
if (entity.IsReefer || (model.bookingDto != null && model.bookingDto.isReefer))
{
//含有是冷冻处理
msgList.Add(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPIIncludeReefer)));
}
if (model.bookingDto != null && model.bookingDto.cargoType != entity.CargoType)
{
//货物标志与被复制货物标志不一致
msgList.Add(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPICargoTypeWithCopyDiff)));
}
if (msgList.Count > 0)
throw new Exception(string.Join(",", msgList.ToArray()));
}
else
{
return DataResult<string>.Success(string.Empty);
}
return DataResult<string>.Success("校验成功");
}
#endregion
#region 批量发送API前调取校验预警
/// <summary>
/// 批量发送API前调取校验预警
/// </summary>
/// <param name="ids">马士基API订舱ID组</param>
/// <returns>返回提示信息</returns>
public async Task<DataResult<string>> CheckWarningBatchSend([FromBody] long[] ids)
{
var tenantDb = saasService.GetBizDbScopeById(user.TenantId);
var list = await tenantDb.Queryable<SpaceBookingOrder>().Where(a => ids.Contains(a.Id)).ToListAsync();
if (list.Count > 0)
{
List<string> msgList = new List<string>();
if (list.Any(a => a.IsShipperOwner))
{
//含有指定托运人自己的集装箱
msgList.Add(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPIIncludeShipperOwner)));
}
if (list.Any(a => a.IsImportReturned))
{
//含有指定进口退货集装箱或者其他三角集运
msgList.Add(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPIIncludeImportReturned)));
}
if (list.Any(a => a.IsReefer))
{
//含有是冷冻处理
msgList.Add(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPIIncludeReefer)));
}
if (msgList.Count > 0)
throw new Exception(string.Join(",", msgList.ToArray()));
}
return DataResult<string>.Success("校验成功");
}
#endregion
#region 获取初始化页面默认值
/// <summary>
/// 获取初始化页面默认值
/// </summary>
/// <returns>返回详情</returns>
public async Task<DataResult<MSKSPOTBookingInitDto>> GetInitInfo()
{
MSKSPOTBookingInitDto dto = null;
var webAccountConfig = codeThirdPartyService.GetCodeThirdPartyInfoWithCompany("MSKSpotApi").GetAwaiter().GetResult()?.Data;
//未配置公司或个人的第三方账户维护-MSK API合约请联系管理员
if (webAccountConfig == null)
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPIMSKConThirdPartySettingNull)));
if (string.IsNullOrWhiteSpace(webAccountConfig.RegistPartyCode)
|| string.IsNullOrWhiteSpace(webAccountConfig.RegistPartyName) || string.IsNullOrWhiteSpace(webAccountConfig.RegistContractName)
|| string.IsNullOrWhiteSpace(webAccountConfig.RegistContractEmail))
{
//第三方账户MSK API合约维护配置缺少备案代码、备案全称、联系人、邮箱必填请联系管理员
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SpaceBookingAPIMSKConThirdPartySettingShortage)));
}
dto = new MSKSPOTBookingInitDto
{
bookedByMaerskPartyCode = webAccountConfig.RegistPartyCode,
bookedByCompanyName = webAccountConfig.RegistPartyName,
priceOwnerMaerskPartyCode = webAccountConfig.RegistPartyCode,
priceOwnerCompanyName = webAccountConfig.RegistPartyName,
bookedByCompanyContactName = webAccountConfig.RegistContractName,
bookedByCompanyContactEmail = webAccountConfig.RegistContractEmail,
priceOwnerContactName = webAccountConfig.RegistContractName,
priceOwnerContactEmail = webAccountConfig.RegistContractEmail,
};
return DataResult<MSKSPOTBookingInitDto>.Success(dto);
#endregion
}
}
}