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.
BookingHeChuan/Myshipping.Application/Service/BookingOrder/BookingMSKSPOTAPIService.cs

1989 lines
86 KiB
C#

using Microsoft.Extensions.Logging;
using Myshipping.Application.Entity;
using Myshipping.Core.Service;
using Myshipping.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Furion.FriendlyException;
using Furion.JsonSerialization;
using Furion.RemoteRequest.Extensions;
using Furion;
using Mapster;
using Microsoft.AspNetCore.Mvc;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using System.Text.RegularExpressions;
using Myshipping.Application.Helper;
using Myshipping.Core.Const;
using Yitter.IdGenerator;
using System.Diagnostics;
using Newtonsoft.Json;
5 months ago
using StackExchange.Profiling.Internal;
namespace Myshipping.Application.Service.BookingOrder
{
/// <summary>
/// 马士基 SPOT
/// </summary>
[ApiDescriptionSettings("Application", Name = "BookingMSKSPOTAPI", Order = 10)]
public class BookingMSKSPOTAPIService: IBookingMSKSPOTAPIService, IDynamicApiController, ITransient
{
private readonly SqlSugarRepository<BookingDeliveryRecord> _bookingDeliveryRecordRep;
private readonly SqlSugarRepository<BookingDeliveryRecordCtn> _bookingDeliveryRecordCtnRep;
5 months ago
private readonly SqlSugarRepository<BookingDeliveryRecordShipSchedule> _bookingDeliveryRecordShipScheduleRep;
private readonly ISysCacheService _cache;
private readonly IDjyWebsiteAccountConfigService _webAccountConfig;
private readonly ILogger<BookingMSKSPOTAPIService> _logger;
private readonly ISysDataUserMenu _sysDataUserMenuService;
private readonly IDjyTenantParamService _djyTenantParamService;
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";
public BookingMSKSPOTAPIService(ILogger<BookingMSKSPOTAPIService> logger, ISysCacheService cache,
IDjyWebsiteAccountConfigService webAccountConfig, SqlSugarRepository<BookingDeliveryRecord> bookingDeliveryRecordRep,
ISysDataUserMenu sysDataUserMenuService,
IDjyTenantParamService djyTenantParamService,
5 months ago
SqlSugarRepository<BookingDeliveryRecordShipSchedule> bookingDeliveryRecordShipScheduleRep,
SqlSugarRepository<BookingDeliveryRecordCtn> bookingDeliveryRecordCtnRep)
{
_logger = logger;
_cache = cache;
_webAccountConfig = webAccountConfig;
_bookingDeliveryRecordRep = bookingDeliveryRecordRep;
_bookingDeliveryRecordCtnRep = bookingDeliveryRecordCtnRep;
_sysDataUserMenuService = sysDataUserMenuService;
_djyTenantParamService = djyTenantParamService;
5 months ago
_bookingDeliveryRecordShipScheduleRep = bookingDeliveryRecordShipScheduleRep;
}
#region 检索始发地、目的港口信息
/// <summary>
/// 检索始发地、目的港口信息
/// </summary>
/// <param name="model">请求详情</param>
/// <returns>返回检索结果</returns>
[HttpPost("/BookingMSKSPOTAPI/SearchLocations")]
public async Task<List<QueryLocationsResultDto>> SearchLocations(QuerySPOTLocationsDto model)
{
List<QueryLocationsResultDto> list = new List<QueryLocationsResultDto>();
/*
MSKApiCommodity
*/
try
{
if (string.IsNullOrWhiteSpace(model.cityName))
throw Oops.Oh("港口或城市名称不能为空");
if (string.IsNullOrWhiteSpace(model.carrierCode))
throw Oops.Oh("服务船公司不能为空");
if (string.IsNullOrWhiteSpace(model.carrierId))
throw Oops.Oh("船公司代码不能为空");
if (model.cityName.Length < 3)
throw Oops.Oh("港口或城市名称至少输入3个以上字符");
string queryUrl = string.Empty;
if (model.carrierId.Equals("MSK", StringComparison.OrdinalIgnoreCase))
{
queryUrl = _cache.GetAllDictData().GetAwaiter().GetResult()
.FirstOrDefault(x => x.TypeCode == "url_set" && x.Code == CONST_MSK_SPOT_API_LOCATION_URL)?.Value;
}
else
{
throw Oops.Oh($"当前船公司 {model.carrierId} 未配置相应的请求接口");
}
if (string.IsNullOrWhiteSpace(queryUrl))
throw Oops.Oh("未配置商品请求接口地址,请联系管理员");
var webAccountConfig = _webAccountConfig
.GetAccountConfig("MSKSpotApi", UserManager.UserId).GetAwaiter().GetResult();
if (webAccountConfig == null)
throw Oops.Oh("未配检索始发地、目的港口,请先配置个人账户 类型-MSKApi");
MSKAPISPOTSearchLocationDto queryInfo = new MSKAPISPOTSearchLocationDto
{
userKey = App.Configuration["MSKAPIDjyUserKey"],
userSecret = App.Configuration["MSKAPIDjyUserSecret"],
operatingEnvironment = "PRODUCTION",//App.Configuration["MSKAPIOPEnvironment"],
spot_api_key = webAccountConfig.Account,
brandScac = model.carrierCode,
originPrefix = model.cityName
};
MSKAPISPOTSearchLocationResultDto resultInfo = null;
var rlt = await queryUrl.SetBody(queryInfo)
.PostAsStringAsync();
if (!string.IsNullOrWhiteSpace(rlt))
{
try
{
resultInfo = JSON.Deserialize<MSKAPISPOTSearchLocationResultDto>(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.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.LogError($"检索始发地、目的港口异常req={JSON.Serialize(model)} 原因:{ex.Message}");
throw Oops.Bah($"检索始发地、目的港口失败,{ex.Message}");
}
return list;
}
#endregion
#region 检索海运船期详情
/// <summary>
/// 检索海运船期详情
/// </summary>
/// <param name="model">请求船期详情</param>
/// <returns>返回船期结果</returns>
[HttpPost("/BookingMSKSPOTAPI/SearchShipSailingSchedule")]
public async Task<List<MSKAPISPOTScheduleRateResultShowDto>> SearchShipSailingSchedule(QueryMSKSPOTShipDateDto query)
{
List<MSKAPISPOTScheduleRateResultShowDto> list = new List<MSKAPISPOTScheduleRateResultShowDto>();
try
{
var model = query.Adapt<QueryMSKSPOTScheduleDto>();
if (string.IsNullOrWhiteSpace(model.originGeoId))
throw Oops.Oh($"起运地不能为空");
if (string.IsNullOrWhiteSpace(model.destinationGeoId))
throw Oops.Oh($"目的地不能为空");
if (string.IsNullOrWhiteSpace(model.brandScac))
throw Oops.Oh($"服务船公司不能为空");
if (string.IsNullOrWhiteSpace(model.carrierId))
throw Oops.Oh("船公司代码不能为空");
if (string.IsNullOrWhiteSpace(model.departureDate))
throw Oops.Oh($"预计离港日期不能为空");
DateTime etd = DateTime.MinValue;
if (!DateTime.TryParse(model.departureDate, out etd))
throw Oops.Oh($"预计离港日期格式错误");
if (string.IsNullOrWhiteSpace(model.containerType))
throw Oops.Oh($"箱型不能为空");
if (!model.containerCount.HasValue || model.containerCount.Value <= 0)
throw Oops.Oh($"箱型不能为空");
if (!model.containerWeight.HasValue || model.containerWeight.Value <= 0)
throw Oops.Oh($"箱重不能为空");
if (model.containerWeight.HasValue)
{
model.containerWeight = model.containerWeight.Value / 1000;
}
string queryUrl = string.Empty;
if (model.carrierId.Equals("MSK", StringComparison.OrdinalIgnoreCase))
{
queryUrl = _cache.GetAllDictData().GetAwaiter().GetResult()
.FirstOrDefault(x => x.TypeCode == "url_set" && x.Code == CONST_MSK_SPOT_API_QUERY_SCHEDULE_RATE_URL)?.Value;
}
else
{
throw Oops.Oh($"当前船公司 {model.carrierId} 未配置相应的请求接口");
}
if (string.IsNullOrWhiteSpace(queryUrl))
throw Oops.Oh("未配置查询船期请求接口地址,请联系管理员");
var webAccountConfig = _webAccountConfig
.GetAccountConfig("MSKSpotApi", UserManager.UserId).GetAwaiter().GetResult();
if (webAccountConfig == null)
throw Oops.Oh("未配置个人账户,请先配置个人账户 类型-MSKApi");
MSKAPISPOTSearchScheduleRateDto queryInfo = new MSKAPISPOTSearchScheduleRateDto
{
userKey = App.Configuration["MSKAPIDjyUserKey"],
userSecret = App.Configuration["MSKAPIDjyUserSecret"],
operatingEnvironment = "PRODUCTION",//App.Configuration["MSKAPIOPEnvironment"],
spot_api_key = webAccountConfig.Account,
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));
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 = await queryUrl.SetBody(jsonBody)
.PostAsStringAsync();
_logger.LogInformation($"请求MSK SPOT API查询船期请求{jsonBody}");
if (!string.IsNullOrWhiteSpace(rlt))
{
try
{
_logger.LogInformation($"请求MSK SPOT API查询船期结果{rlt}");
resultInfo = JSON.Deserialize<MSKAPISPOTSearchScheduleRateResultDto>(rlt);
}
catch (Exception ex)
{
_logger.LogInformation($"请求MSK SPOT API查询船期异常原因{ex.Message}");
throw Oops.Bah($"请求MSK API查询船期异常原因{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 =>
{
MSKAPISPOTScheduleRateResultShowDto showDto = new MSKAPISPOTScheduleRateResultShowDto
{
priceID = a.priceID,
PId = a.PId,
MD5 = a.MD5,
totalAmount = a.totalAmount.HasValue ? (decimal)a.totalAmount.Value : 0,
TotalCurrency = a.totalCurrency,
orignCarrierCityGeoID = a.originGeoId,
orignUNLocationCode = a.originUnLocCode,
orignCityName = a.originCityName,
originRegionName = a.originRegionName,
originCountryName = a.originCountryName,
deliveryCarrierCityGeoID = a.destinationGeoId,
deliveryUNLocationCode = a.destinationUnLocCode,
deliveryCityName = a.destinationCityName,
deliveryRegionName = a.destinationRegionName,
deliveryCountryName = a.destinationCountryName,
vesselName = a.vesselName,
carrierDepartureVoyageNumber = a.voyageNumber,
Legs = new List<MSKAPISPOTScheduleRateResultShowLegsDto>()
};
5 months ago
if (a.totalAmount.HasValue)
showDto.totalAmountShow = string.Format("{0:N}", a.totalAmount.Value);
//ETD
if (!string.IsNullOrWhiteSpace(a.departureDate))
{
DateTime currDate = DateTime.MinValue;
if (DateTime.TryParse(a.departureDate, out currDate))
{
showDto.ETD = currDate;
}
else
{
throw Oops.Bah($"查询船期错误priceID={a.priceID} pid={a.PId} 预计离港日期departureDate={a.departureDate} 格式解析错误");
}
}
//ETA
if (!string.IsNullOrWhiteSpace(a.arrivalDate))
{
DateTime currDate = DateTime.MinValue;
if (DateTime.TryParse(a.arrivalDate, out currDate))
{
showDto.ETA = currDate;
}
else
{
throw Oops.Bah($"查询船期错误priceID={a.priceID} pid={a.PId} 预计到达日期 arrivalDate={a.arrivalDate} 格式解析错误");
}
}
//计算预计天数
if (showDto.ETD.HasValue && showDto.ETA.HasValue)
{
TimeSpan ts = showDto.ETA.Value.Subtract(showDto.ETD.Value);
var timeDiff = ts.TotalHours;
showDto.days = (int)Math.Ceiling(timeDiff / 24.0);
}
if (a.isTransfer.Equals("true", StringComparison.OrdinalIgnoreCase))
showDto.isTransfer = true;
//Legs
if (a.scheduleDetails != null && a.scheduleDetails.Count > 0)
{
var legs = a.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={a.priceID} pid={a.PId} 预计离港日期fromLocation.date={b.fromLocation.date} {b.fromLocation.time} 格式解析错误");
}
}
//ETA
if (!string.IsNullOrWhiteSpace(b.toLocation.date))
{
DateTime currDate = DateTime.MinValue;
if (DateTime.TryParse(a.arrivalDate, out currDate))
{
5 months ago
leg.ETA = currDate;
}
else
{
throw Oops.Bah($"查询船期错误,航程明细 priceID={a.priceID} pid={a.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;
}).ToList();
}
else
{
throw Oops.Bah($"检索海运船期详情失败,{resultInfo.msg}");
}
}
catch (Exception ex)
{
_logger.LogError($"检索海运船期详情异常req={JSON.Serialize(query)} 原因:{ex.Message}");
throw Oops.Bah($"检索海运船期详情失败,{ex.Message}");
}
return list;
}
#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")
{
/*
1IDKEY
2JSONMD5
3ID
*/
var newModel = model.Adapt<MSKAPISPOTSearchScheduleRateResultDataDto>();
newModel.priceID = null;
var json = Newtonsoft.Json.JsonConvert.SerializeObject(newModel);
model.PId = YitIdHelper.NextId();
string md5 = json.ToMd5();
model.MD5 = md5;
var shareKey = model.PId.ToString();
DateTime nowDate = DateTime.Now;
DateTime expireDateTime = DateTime.Now.AddHours(1);
var expireTimeSpan = expireDateTime.Subtract(nowDate).Duration();
if (!_cache.Exists($"{shareKey}_{busiType}"))
{
await _cache.SetTimeoutAsync($"{shareKey}_{busiType}", Newtonsoft.Json.JsonConvert.SerializeObject(model), expireTimeSpan);
}
}
#endregion
5 months ago
private MSKAPISPOTSearchScheduleRateResultDataDto GetCacheShipSailingSchedule(long pid, string busiType = "MSKSPOT")
{
if (_cache.Exists($"{pid}_{busiType}"))
{
return _cache.Get<MSKAPISPOTSearchScheduleRateResultDataDto>($"{pid}_{busiType}");
}
return null;
}
#region 发送马士基订舱请求
/// <summary>
/// 发送马士基订舱请求
/// </summary>
/// <param name="model">请求订舱详情</param>
/// <returns></returns>
[HttpPost("/BookingMSKSPOTAPI/SendMSKBooking")]
public async Task<MSKBookingResultDto> SendMSKBooking(MSKSPOTBookingDto model)
{
MSKBookingResultDto result = await InnerSendMSKBooking(model, 0);
return result;
}
#endregion
#region 发送马士基订舱请求(内部方法)
/// <summary>
/// 发送马士基订舱请求(内部方法)
/// </summary>
/// <param name="model">请求订舱详情</param>
/// <param name="currId">当前马士基订舱主键</param>
/// <param name="isDefaultSave">是否默认保存</param>
/// <returns></returns>
private async Task<MSKBookingResultDto> InnerSendMSKBooking(MSKSPOTBookingDto model, long currId, bool isDefaultSave = true)
{
MSKBookingResultDto result = new MSKBookingResultDto();
/*
MSKApiBooking
*/
try
{
if (string.IsNullOrWhiteSpace(model.carrierCode))
throw Oops.Oh($"服务船公司不能为空");
if (string.IsNullOrWhiteSpace(model.carrierId))
throw Oops.Oh("船公司代码不能为空");
string sendUrl = string.Empty;
if (model.carrierId.Equals("MSK", StringComparison.OrdinalIgnoreCase))
{
sendUrl = _cache.GetAllDictData().GetAwaiter().GetResult()
.FirstOrDefault(x => x.TypeCode == "url_set" && x.Code == CONST_MSK_API_BOOKING_URL)?.Value;
}
else
{
throw Oops.Oh($"当前船公司 {model.carrierId} 未配置相应的请求接口");
}
if (string.IsNullOrWhiteSpace(sendUrl))
throw Oops.Oh("未配置发送订舱请求接口地址,请联系管理员");
var webAccountConfig = _webAccountConfig
.GetAccountConfig("MSKApi", UserManager.UserId).GetAwaiter().GetResult();
if (webAccountConfig == null)
throw Oops.Oh("未配置个人账户,请先配置个人账户 类型-MSKApi");
//这里是校验必填项
ValidateMSKAPIData(model);
5 months ago
MSKAPISPOTSearchScheduleRateResultDataDto selectedShipSchedule = null;
BookingDeliveryRecordShipSchedule shipScheduleRecord = null;
if (model.PId == 0)
throw Oops.Oh("船期信息不能为空,请重新检索船期");
if (model.PId > 0)
{
if (model.id.HasValue && model.id.Value > 0)
{
var recordId = model.id.Value;
shipScheduleRecord = await _bookingDeliveryRecordShipScheduleRep.AsQueryable()
.FirstAsync(a => a.RECORD_ID == recordId && a.SHIP_RATE_PID != null &&
a.SHIP_RATE_PID.Value == model.PId && a.IsDeleted == false);
}
if (shipScheduleRecord == null)
{
selectedShipSchedule = GetCacheShipSailingSchedule(model.PId);
}
else
{
selectedShipSchedule = JSON.Deserialize<MSKAPISPOTSearchScheduleRateResultDataDto>(shipScheduleRecord.SHIP_JSON);
}
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<BookingDeliveryRecord>();
var recordCtnList = model.ctns.Adapt<List<BookingDeliveryRecordCtn>>();
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 = App.Configuration["MSKAPIDjyUserKey"],
userSecret = App.Configuration["MSKAPIDjyUserSecret"],
operatingEnvironment = App.Configuration["MSKAPIOPEnvironment"],
mskAppKey = webAccountConfig.Account,
mskAppSecret = webAccountConfig.Password,
bookingBody = new MSKAPIBookingBodyDto()
};
bookingDto.bookingBody.references = new MSKAPIBookingReferenceDto
{
priceReference = model.priceReference,
productCode = model.productCode,
sender = model.sender,
5 months ago
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
{
5 months ago
UNLocationCode = model.userPlaceOfReceiptUnLocCode,
maerskCityGeoId = selectedShipSchedule.originGeoId,
},
placeOfDelivery = new MSKAPIBookingRouteDetailsBase
{
5 months ago
UNLocationCode = model.userPlaceOfDeliveryUnLocCode,
maerskCityGeoId = selectedShipSchedule.destinationGeoId,
},
selectedRoute = new MSKAPIBookingRoute
{
5 months ago
bookingSchedules = new List<MSKAPIBookingSchedules>(),
},
}
};
5 months ago
foreach (var detail in selectedShipSchedule.scheduleDetails)
{
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} 格式解析错误");
}
}
//ETD
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.startLocation = new MSKAPIBookingRouteDetailsBase {
cityName = selectedShipSchedule.scheduleDetails.FirstOrDefault().fromLocation.cityName,
ISOcountryCode = selectedShipSchedule.scheduleDetails.FirstOrDefault().fromLocation.countryCode,
UNLocationCode = selectedShipSchedule.scheduleDetails.FirstOrDefault().fromLocation.unLocCode,
maerskCityGeoId = selectedShipSchedule.scheduleDetails.FirstOrDefault().fromLocation.cityGeoId,
};
currDto.endLocation = new MSKAPIBookingRouteDetailsBase
{
cityName = selectedShipSchedule.scheduleDetails.FirstOrDefault().toLocation.cityName,
ISOcountryCode = selectedShipSchedule.scheduleDetails.FirstOrDefault().toLocation.countryCode,
UNLocationCode = selectedShipSchedule.scheduleDetails.FirstOrDefault().toLocation.unLocCode,
maerskCityGeoId = selectedShipSchedule.scheduleDetails.FirstOrDefault().toLocation.cityGeoId,
};
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 = ctnCodeMappingList.FirstOrDefault(t => t.Code.Equals(ctn.ctnCode));
if (ctnMapping == null)
throw Oops.Oh($"未配置相应的箱型对应{ctn.ctnName},请联系管理员");
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();
}
else
{
id = currId;
}
result.id = id;
MSKAPIBookingResultDto resultInfo = null;
_logger.LogInformation($"开始请求MSK API订舱JSON={JSON.Serialize(bookingDto)}");
var jsonBody = Newtonsoft.Json.JsonConvert.SerializeObject(bookingDto);
var rlt = await sendUrl.SetBody(jsonBody)
.PostAsStringAsync();
_logger.LogInformation($"开始请求MSK API订舱返回结果 JSON={JSON.Serialize(rlt)}");
if (!string.IsNullOrWhiteSpace(rlt))
{
try
{
resultInfo = JSON.Deserialize<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 = JSON.Deserialize<MSKAPIBookingResultDataDto>(JSON.Serialize(resultInfo.data));
}
var entity = _bookingDeliveryRecordRep
.FirstOrDefault(a => a.Id == id);
if (resultInfo != null && resultInfo.code == 200
&& resultData != null)
{
entity.REQUEST_ACKNOWLEDGEMENT_ID = resultData.requestAcknowledgementId;
entity.BOOKING_REFERENCE = resultData.bookingReference;
entity.STATUS = "SUCC";
entity.STATUS_NAME = "发送成功";
await _bookingDeliveryRecordRep.AsUpdateable(entity).UpdateColumns(x => new
{
x.REQUEST_ACKNOWLEDGEMENT_ID,
x.BOOKING_REFERENCE,
x.STATUS,
x.STATUS_NAME
}).ExecuteCommandAsync();
}
else
{
entity.STATUS = "FAILURE";
entity.STATUS_NAME = "发送失败";
entity.NOTES = resultInfo.msg.Length > 500 ? resultInfo.msg.Substring(0, 500) : resultInfo.msg;
await _bookingDeliveryRecordRep.AsUpdateable(entity).UpdateColumns(x => new
{
x.STATUS,
x.STATUS_NAME,
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订舱失败{ex.Message}";
throw Oops.Bah($"MSK API订舱失败{ex.Message}");
}
return result;
}
#endregion
#region 校验马士基API订舱必填项
/// <summary>
/// 校验马士基API订舱必填项
/// </summary>
/// <param name="model"></param>
private void ValidateMSKAPIData(MSKSPOTBookingDto model)
{
/*
API
1
2
3
4
5
6UNLOC
7UNLOC
8ETDETA
9
10
11
12
13
14=*
15
*/
if (string.IsNullOrWhiteSpace(model.priceReference))
throw Oops.Bah($"订舱合同惟一ID必填");
if (!Regex.IsMatch(model.priceReference, "[a-zA-Z0-9_/,-]{1,50}"))
throw Oops.Bah($"订舱合同惟一ID格式错误 [a-zA-Z0-9_/,-]{{1,50}}");
if (string.IsNullOrWhiteSpace(model.sender))
throw Oops.Bah($"请求类别必填");
if (string.IsNullOrWhiteSpace(model.carrierCode))
throw Oops.Bah($"服务船公司必填");
if (string.IsNullOrWhiteSpace(model.bookedByCompanyName))
throw Oops.Bah($"订舱公司名称必填");
if (string.IsNullOrWhiteSpace(model.bookedByMaerskPartyCode))
throw Oops.Bah($"订舱方ID必填");
if (string.IsNullOrWhiteSpace(model.bookedByCompanyContactName))
throw Oops.Bah($"订舱方公司联系人必填");
if (string.IsNullOrWhiteSpace(model.bookedByCompanyContactEmail))
throw Oops.Bah($"订舱方公司邮箱必填");
if (string.IsNullOrWhiteSpace(model.priceOwnerContactName))
throw Oops.Bah($"持约方公司名称必填");
if (string.IsNullOrWhiteSpace(model.priceOwnerMaerskPartyCode))
throw Oops.Bah($"持约方ID必填");
if (string.IsNullOrWhiteSpace(model.priceOwnerContactName))
throw Oops.Bah($"持约方公司联系人必填");
if (string.IsNullOrWhiteSpace(model.priceOwnerContactEmail))
throw Oops.Bah($"持约方公司邮箱必填");
if (string.IsNullOrWhiteSpace(model.placeOfReceiptCityName))
throw Oops.Bah($"始发地城市名称必填");
if (string.IsNullOrWhiteSpace(model.placeOfReceiptUnLocCode))
throw Oops.Bah($"始发地UN CODE必填");
if (string.IsNullOrWhiteSpace(model.placeOfReceiptCountryCode))
throw Oops.Bah($"始发地国家代码必填");
if (string.IsNullOrWhiteSpace(model.exportServiceMode))
throw Oops.Bah($"始发地服务模式必填");
if (string.IsNullOrWhiteSpace(model.placeOfDeliveryCityName))
throw Oops.Bah($"目的地城市名称必填");
if (string.IsNullOrWhiteSpace(model.placeOfDeliveryUnLocCode))
throw Oops.Bah($"目的地UN CODE必填");
if (string.IsNullOrWhiteSpace(model.placeOfDeliveryCountryCode))
throw Oops.Bah($"目的地国家代码必填");
if (string.IsNullOrWhiteSpace(model.importServiceMode))
throw Oops.Bah($"目的地服务模式必填");
if (string.IsNullOrWhiteSpace(model.vesselName))
throw Oops.Bah($"船名必填,请确认正确选择了船期");
if (string.IsNullOrWhiteSpace(model.exportVoyageNumber))
throw Oops.Bah($"航次号必填,请确认正确选择了船期");
if (!model.originDepartureDateTimeLocal.HasValue)
throw Oops.Bah($"ETD必填请确认正确选择了船期");
if (!model.destinationArrivalDateTimeLocal.HasValue)
throw Oops.Bah($"ETA必填请确认正确选择了船期");
if (string.IsNullOrWhiteSpace(model.commodityCode))
throw Oops.Bah($"商品代码必填,请确认正确选择了商品");
if (string.IsNullOrWhiteSpace(model.commodityName))
throw Oops.Bah($"商品名称必填,请确认正确选择了商品");
if (!model.totalCargoWeight.HasValue || model.totalCargoWeight.Value < 1)
throw Oops.Bah($"总重必填");
if (string.IsNullOrWhiteSpace(model.cargoType))
throw Oops.Bah($"货物标志必填");
if (!model.earliestDepartureDate.HasValue)
throw Oops.Bah($"预计离港日期必填");
if (string.IsNullOrWhiteSpace(model.userPlaceOfReceiptUnLocCode))
throw Oops.Bah($"始发地必填");
if (string.IsNullOrWhiteSpace(model.userPlaceOfDeliveryUnLocCode))
throw Oops.Bah($"目的地必填");
//if (!model.isSendNoSchedule && string.IsNullOrWhiteSpace(model.carrierProductId))
// throw Oops.Bah($"船期信息不能为空,请查询船期信息");
if (model.isReefer)
{
if (!model.temperature.HasValue)
throw Oops.Bah($"选择了冷冻处理,温度必填");
}
if (model.ctns.Count == 0)
throw Oops.Bah($"箱型箱量信息必填");
if (model.ctns.Any(a => string.IsNullOrWhiteSpace(a.ctnCode)))
throw Oops.Bah($"箱型不能为空");
if (model.ctns.Any(a => !a.ctnNum.HasValue || a.ctnNum.Value < 1))
throw Oops.Bah($"箱量不能为空并且不能小于1");
if (model.ctns.Any(a => !a.ctnSufferWeight.HasValue || a.ctnSufferWeight.Value < 1))
throw Oops.Bah($"箱内重量不能为空并且不能小于1");
if (model.totalCargoWeight.Value != model.ctns.Sum(b => b.ctnNum.Value * b.ctnSufferWeight.Value))
{
throw Oops.Bah($"箱内重量合计不等于总重,请修改");
}
}
#endregion
#region 检索商品名称
/// <summary>
/// 检索商品名称
/// </summary>
/// <param name="model">请求详情</param>
/// <returns>返回检索结果</returns>
[HttpPost("/BookingMSKSPOTAPI/SearchCommodities")]
public async Task<List<SearchCommodityResultDto>> SearchCommodities(QueryCommoditiesDto model)
{
List<SearchCommodityResultDto> list = new List<SearchCommodityResultDto>();
/*
MSKApiCommodity
*/
try
{
if (string.IsNullOrWhiteSpace(model.commodityName))
throw Oops.Oh("商品名称不能为空");
if (string.IsNullOrWhiteSpace(model.carrierId))
throw Oops.Oh("船公司代码不能为空");
if (model.commodityName.Length < 3)
throw Oops.Oh("商品名称至少输入3个以上字符");
string queryUrl = string.Empty;
if (model.carrierId.Equals("MSK", StringComparison.OrdinalIgnoreCase))
{
queryUrl = _cache.GetAllDictData().GetAwaiter().GetResult()
.FirstOrDefault(x => x.TypeCode == "url_set" && x.Code == CONST_MSK_API_COMMODITY_URL)?.Value;
}
else
{
throw Oops.Oh($"当前船公司 {model.carrierId} 未配置相应的请求接口");
}
if (string.IsNullOrWhiteSpace(queryUrl))
throw Oops.Oh("未配置商品请求接口地址,请联系管理员");
var webAccountConfig = _webAccountConfig
.GetAccountConfig("MSKApi", UserManager.UserId).GetAwaiter().GetResult();
if (webAccountConfig == null)
throw Oops.Oh("未配置个人账户,请先配置个人账户 类型-MSKApi");
MSKAPISearchCommodityDto queryInfo = new MSKAPISearchCommodityDto
{
userKey = App.Configuration["MSKAPIDjyUserKey"],
userSecret = App.Configuration["MSKAPIDjyUserSecret"],
operatingEnvironment = App.Configuration["MSKAPIOPEnvironment"],
commodityName = model.commodityName,
mskAppKey = webAccountConfig.Account
};
MSKAPISearchCommodityResultDto resultInfo = null;
var rlt = await queryUrl.SetBody(queryInfo)
.PostAsStringAsync();
if (!string.IsNullOrWhiteSpace(rlt))
{
try
{
resultInfo = JSON.Deserialize<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 list;
}
#endregion
#region 获取马士基API订舱详情
/// <summary>
/// 获取马士基API订舱详情
/// </summary>
/// <param name="id">马士基API订舱ID</param>
/// <returns>返回详情</returns>
[HttpGet("/BookingMSKSPOTAPI/GetInfo")]
public async Task<MSKSPOTBookingDto> GetInfo(long id)
{
MSKSPOTBookingDto model = null;
var entity = await _bookingDeliveryRecordRep.AsQueryable()
.FirstAsync(a => a.Id == id);
if (entity == null)
throw Oops.Oh($"获取马士基API订舱详情失败不存在或已作废");
model = entity.Adapt<MSKSPOTBookingDto>();
var ctnList = _bookingDeliveryRecordCtnRep.AsQueryable()
.Where(a => a.RECORD_ID == id && a.IsDeleted == false).ToList();
if (ctnList.Count > 0)
{
model.ctns = ctnList.Select(a => new MSKBookingCtnInfo
{
id = a.Id,
ctnCode = a.CTN_CODE,
carrierCtnCode = a.CARRIER_CTN_CODE,
ctnNum = a.CTN_NUM,
ctnName = a.CTN_NAME,
ctnSufferWeight = a.CTN_SUFFER_WEIGHT,
stuffingMeasurementType = a.STUFFING_MEASUREMENT_TYPE,
stuffingMeasurementUnit = a.STUFFING_MEASUREMENT_UNIT
}).ToList();
}
5 months ago
MSKAPISPOTSearchScheduleRateResultDataDto selectedShipSchedule = null;
if (model.PId > 0)
{
var shipScheduleRecord = await _bookingDeliveryRecordShipScheduleRep.AsQueryable()
.FirstAsync(a => a.SHIP_RATE_PID != null && a.SHIP_RATE_PID.Value == model.PId);
if (shipScheduleRecord != null)
{
selectedShipSchedule = JSON.Deserialize<MSKAPISPOTSearchScheduleRateResultDataDto>(shipScheduleRecord.SHIP_JSON);
}
}
return model;
}
#endregion
#region 保存
/// <summary>
/// 保存
/// </summary>
/// <param name="model">请求订舱详情</param>
/// <returns>返回ID</returns>
[HttpPost("/BookingMSKSPOTAPI/Save")]
public async Task<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<long> InnerSave(MSKSPOTBookingDto model, bool isSendApi = false)
{
DateTime nowDate = DateTime.Now;
string ctnStat = string.Empty;
_logger.LogInformation($"获取请求马士基API订舱报文JSON={JSON.Serialize(model)}");
5 months ago
MSKAPISPOTSearchScheduleRateResultDataDto selectedShipSchedule = null;
5 months ago
BookingDeliveryRecordShipSchedule shipScheduleRecord = null;
5 months ago
if (model.PId > 0)
{
5 months ago
if (model.id.HasValue && model.id.Value > 0)
{
var recordId = model.id.Value;
shipScheduleRecord = await _bookingDeliveryRecordShipScheduleRep.AsQueryable()
.FirstAsync(a => a.RECORD_ID == recordId && a.SHIP_RATE_PID != null &&
a.SHIP_RATE_PID.Value == model.PId && a.IsDeleted == false);
}
5 months ago
if (shipScheduleRecord == null)
{
selectedShipSchedule = GetCacheShipSailingSchedule(model.PId);
}
else
{
selectedShipSchedule = JSON.Deserialize<MSKAPISPOTSearchScheduleRateResultDataDto>(shipScheduleRecord.SHIP_JSON);
}
if (selectedShipSchedule == null)
throw Oops.Oh("船期数据校验失败,请重新查询船期信息");
5 months ago
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.placeOfReceiptGeoId = selectedShipSchedule.originGeoId;
model.placeOfDeliveryRegionName = selectedShipSchedule.destinationCountryName;
model.placeOfDeliveryCountryName = selectedShipSchedule.destinationCountryName;
model.placeOfReceiptRegionName = selectedShipSchedule.destinationGeoId;
5 months ago
}
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 = _bookingDeliveryRecordRep.AsQueryable()
.First(a => a.Id == model.id);
if (oldInfo == null)
throw Oops.Oh("订舱数据不存在或已作废");
if (oldInfo.STATUS == "SUCC")
{
if (isSendApi)
throw Oops.Oh("订舱数据已发送成功,不能重复发送");
throw Oops.Oh("订舱数据已发送成功,不能修改");
}
BookingDeliveryRecord entity = model.Adapt<BookingDeliveryRecord>();
entity.Id = model.id.Value;
entity.UpdatedTime = nowDate;
entity.UpdatedUserId = UserManager.UserId;
entity.UpdatedUserName = UserManager.Name;
entity.CTN_STAT = ctnStat;
5 months ago
entity.BOOKING_CHANNEL_TYPE = "SPOT_API";
entity.BOOKING_CHANNEL_TYPE_NAME = "SPOT订舱";
await _bookingDeliveryRecordRep.AsUpdateable(entity).IgnoreColumns(x => new
{
x.CreatedTime,
x.CreatedUserId,
x.CreatedUserName,
x.BOOKING_REFERENCE,
x.BookingId,
x.REQUEST_ACKNOWLEDGEMENT_ID,
x.STATUS,
x.TenantId,
x.IS_RECV_BC,
x.LST_RECV_BC_DATE,
x.IS_RECV_BK_CANCEL,
x.LST_RECV_BK_CANCEL_DATE
}).ExecuteCommandAsync();
if (model.ctns != null && model.ctns.Count > 0)
{
var ctnEntityList = _bookingDeliveryRecordCtnRep.AsQueryable()
.Where(a => a.RECORD_ID == entity.Id && a.IsDeleted == 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<BookingDeliveryRecordCtn>();
ctnEntity.Id = ctn.id.Value;
ctnEntity.RECORD_ID = entity.Id;
ctnEntity.UpdatedTime = nowDate;
ctnEntity.UpdatedUserId = UserManager.UserId;
ctnEntity.UpdatedUserName = UserManager.Name;
_bookingDeliveryRecordCtnRep.AsUpdateable(ctnEntity).IgnoreColumns(x => new {
x.CreatedUserId,
x.CreatedUserName,
x.CreatedTime,
x.TenantId,
x.STUFFING_MEASUREMENT_TYPE,
x.STUFFING_MEASUREMENT_UNIT,
x.CTN_SUFFER_WEIGHT
}).ExecuteCommand();
}
else
{
var ctnEntity = new BookingDeliveryRecordCtn
{
CTN_CODE = ctn.ctnCode,
CTN_NAME = ctn.ctnName,
CTN_NUM = ctn.ctnNum.Value,
CTN_SUFFER_WEIGHT = (int)ctn.ctnSufferWeight.Value,
};
ctnEntity.RECORD_ID = entity.Id;
ctnEntity.CreatedTime = nowDate;
ctnEntity.UpdatedTime = nowDate;
ctnEntity.CreatedUserId = UserManager.UserId;
ctnEntity.CreatedUserName = UserManager.Name;
ctnEntity.STUFFING_MEASUREMENT_TYPE = "WEIGHT";
ctnEntity.STUFFING_MEASUREMENT_UNIT = "KGS";
_bookingDeliveryRecordCtnRep.Insert(ctnEntity);
}
});
if (ctnEntityList.Count > 0)
{
ctnEntityList.ForEach(async ctn => {
ctn.IsDeleted = true;
ctn.UpdatedTime = nowDate;
ctn.UpdatedUserId = UserManager.UserId;
ctn.UpdatedUserName = UserManager.Name;
await _bookingDeliveryRecordCtnRep.AsUpdateable(ctn).UpdateColumns(x => new {
x.IsDeleted,
x.UpdatedTime,
x.UpdatedUserId,
x.UpdatedUserName
}).ExecuteCommandAsync();
});
}
}
5 months ago
if(shipScheduleRecord == null)
{
if(model.PId > 0 && selectedShipSchedule != null)
{
shipScheduleRecord = new BookingDeliveryRecordShipSchedule
{
Id = YitIdHelper.NextId(),
RECORD_ID = model.id.Value,
PRICE_ID = model.priceID,
SHIP_RATE_PID = selectedShipSchedule.PId,
SHIP_RATE_MD5 = selectedShipSchedule.MD5,
SHIP_RATE_TOTAL_AMOUNT = selectedShipSchedule.totalAmount.HasValue ? selectedShipSchedule.totalAmount.Value : 0,
SHIP_RATE_TOTAL_CURRENCY = selectedShipSchedule.totalCurrency,
SHIP_JSON = Newtonsoft.Json.JsonConvert.SerializeObject(selectedShipSchedule),
CreatedTime = nowDate,
UpdatedTime = nowDate,
CreatedUserId = UserManager.UserId,
CreatedUserName = UserManager.Name
};
await _bookingDeliveryRecordShipScheduleRep.InsertAsync(shipScheduleRecord);
}
}
return model.id.Value;
}
else
{
BookingDeliveryRecord entity = model.Adapt<BookingDeliveryRecord>();
entity.CreatedTime = nowDate;
entity.UpdatedTime = nowDate;
entity.CreatedUserId = UserManager.UserId;
entity.CreatedUserName = UserManager.Name;
entity.STATUS = "TEMP";
entity.STATUS_NAME = "暂存";
entity.CTN_STAT = ctnStat;
5 months ago
entity.BOOKING_CHANNEL_TYPE = "SPOT_API";
entity.BOOKING_CHANNEL_TYPE_NAME = "SPOT订舱";
await _bookingDeliveryRecordRep.InsertAsync(entity);
if (model.ctns != null && model.ctns.Count > 0)
{
model.ctns.ForEach(ctn =>
{
var ctnEntity = new BookingDeliveryRecordCtn
{
CTN_CODE = ctn.ctnCode,
CTN_NAME = ctn.ctnName,
CTN_NUM = ctn.ctnNum.Value,
CTN_SUFFER_WEIGHT = (int)ctn.ctnSufferWeight.Value,
};
ctnEntity.RECORD_ID = entity.Id;
ctnEntity.CreatedTime = nowDate;
ctnEntity.UpdatedTime = nowDate;
ctnEntity.CreatedUserId = UserManager.UserId;
ctnEntity.CreatedUserName = UserManager.Name;
ctnEntity.STUFFING_MEASUREMENT_TYPE = "WEIGHT";
ctnEntity.STUFFING_MEASUREMENT_UNIT = "KGS";
_bookingDeliveryRecordCtnRep.Insert(ctnEntity);
});
}
5 months ago
if (shipScheduleRecord == null)
{
if (model.PId > 0 && selectedShipSchedule != null)
{
shipScheduleRecord = new BookingDeliveryRecordShipSchedule
{
Id = YitIdHelper.NextId(),
RECORD_ID = model.id.Value,
PRICE_ID = model.priceID,
SHIP_RATE_PID = selectedShipSchedule.PId,
SHIP_RATE_MD5 = selectedShipSchedule.MD5,
SHIP_RATE_TOTAL_AMOUNT = selectedShipSchedule.totalAmount.HasValue ? selectedShipSchedule.totalAmount.Value : 0,
SHIP_RATE_TOTAL_CURRENCY = selectedShipSchedule.totalCurrency,
SHIP_JSON = Newtonsoft.Json.JsonConvert.SerializeObject(selectedShipSchedule),
CreatedTime = nowDate,
UpdatedTime = nowDate,
CreatedUserId = UserManager.UserId,
CreatedUserName = UserManager.Name
};
await _bookingDeliveryRecordShipScheduleRep.InsertAsync(shipScheduleRecord);
}
}
else
{
//只有船期发生变化时才重新写入新的船期记录
if (model.PId != shipScheduleRecord.SHIP_RATE_PID.Value)
{
_logger.LogInformation($"MSK SPOT id={model.id} 换了船期 原记录:{selectedShipSchedule.PId} 新记录:{model.PId} 作废原船期,插入新船期");
shipScheduleRecord.IsDeleted = true;
shipScheduleRecord.UpdatedTime = nowDate;
shipScheduleRecord.UpdatedUserId = UserManager.UserId;
shipScheduleRecord.UpdatedUserName = UserManager.Name;
await _bookingDeliveryRecordShipScheduleRep.AsUpdateable(shipScheduleRecord).UpdateColumns(x=>new {
x.IsDeleted,
x.UpdatedUserId,
x.UpdatedUserName,
x.UpdatedTime
}).ExecuteCommandAsync();
shipScheduleRecord = new BookingDeliveryRecordShipSchedule
{
Id = YitIdHelper.NextId(),
RECORD_ID = model.id.Value,
PRICE_ID = model.priceID,
SHIP_RATE_PID = selectedShipSchedule.PId,
SHIP_RATE_MD5 = selectedShipSchedule.MD5,
SHIP_RATE_TOTAL_AMOUNT = selectedShipSchedule.totalAmount.HasValue ? selectedShipSchedule.totalAmount.Value : 0,
SHIP_RATE_TOTAL_CURRENCY = selectedShipSchedule.totalCurrency,
SHIP_JSON = Newtonsoft.Json.JsonConvert.SerializeObject(selectedShipSchedule),
CreatedTime = nowDate,
UpdatedTime = nowDate,
CreatedUserId = UserManager.UserId,
CreatedUserName = UserManager.Name
};
await _bookingDeliveryRecordShipScheduleRep.InsertAsync(shipScheduleRecord);
}
else
{
_logger.LogInformation($"MSK SPOT id={model.id} 船期没变化 model.PId={model.PId} shipScheduleRecord.SHIP_RATE_PID={shipScheduleRecord.SHIP_RATE_PID.Value}");
}
}
return entity.Id;
}
}
#endregion
#region 删除
/// <summary>
/// 删除
/// </summary>
/// <param name="id">请求订舱ID</param>
/// <returns></returns>
[HttpGet("/BookingMSKSPOTAPI/Delete")]
public async Task Delete(long id)
{
var info = _bookingDeliveryRecordRep.AsQueryable().First(a => a.Id == id);
if (info == null)
throw Oops.Bah($"删除失败,业务信息不存在或已作废");
info.IsDeleted = true;
info.UpdatedTime = DateTime.Now;
info.UpdatedUserId = UserManager.UserId;
info.UpdatedUserName = UserManager.Name;
await _bookingDeliveryRecordRep.AsUpdateable(info).UpdateColumns(x => new {
x.IsDeleted,
x.UpdatedTime,
x.UpdatedUserId,
x.UpdatedUserName
}).ExecuteCommandAsync();
}
#endregion
#region 批量发送
/// <summary>
/// 批量发送
/// </summary>
/// <param name="ids">马士基API订舱ID组</param>
/// <returns>返回执行结果消息</returns>
[HttpPost("/BookingMSKSPOTAPI/BatchSend")]
public async Task<string> BatchSend([FromBody] long[] ids)
{
var list = await _bookingDeliveryRecordRep.AsQueryable()
.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();
result = InnerSendMSKBooking(model, entity.Id, false).GetAwaiter().GetResult();
succNum++;
}
catch (Exception ex)
{
msgList.Add(ex.Message);
failNum++;
}
});
msgList.Add($"共计{totalNum} 条 成功{succNum}条 失败:{failNum}");
}
else
{
MSKBookingResultDto result = null;
try
{
var entity = list.FirstOrDefault();
var model = GetInfo(entity.Id).GetAwaiter().GetResult();
result = InnerSendMSKBooking(model, entity.Id, false).GetAwaiter().GetResult();
if (result.succ)
return string.Empty;
}
catch (Exception ex)
{
msgList.Add(ex.Message);
}
}
return string.Join("#", msgList.ToArray());
}
#endregion
#region 批量复制
/// <summary>
/// 批量复制
/// </summary>
/// <param name="model">马士基API批量复制指定数据</param>
/// <returns>返回执行结果消息</returns>
[HttpPost("/BookingMSKSPOTAPI/BatchCopy")]
public async Task<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 entity = await _bookingDeliveryRecordRep.AsQueryable()
.FirstAsync(a => a.Id == model.originalId);
if (entity == null)
throw Oops.Oh($"获取马士基API订舱详情失败不存在或已作废");
var ctnList = _bookingDeliveryRecordCtnRep.AsQueryable()
.Where(a => a.RECORD_ID == model.originalId && a.IsDeleted == 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<BookingDeliveryRecordCtn>();
model.bookingDto.ctns.ForEach(ctn =>
{
var ctnEntity = new BookingDeliveryRecordCtn
{
CTN_CODE = ctn.ctnCode,
CTN_NAME = ctn.ctnName,
CTN_NUM = ctn.ctnNum.Value,
CTN_SUFFER_WEIGHT = (int)ctn.ctnSufferWeight.Value,
};
ctnEntity.CreatedTime = nowDate;
ctnEntity.UpdatedTime = nowDate;
ctnEntity.CreatedUserId = UserManager.UserId;
ctnEntity.CreatedUserName = UserManager.Name;
ctnEntity.STUFFING_MEASUREMENT_TYPE = "WEIGHT";
ctnEntity.STUFFING_MEASUREMENT_UNIT = "KGS";
ctnList.Add(ctnEntity);
});
}
entity = model.bookingDto.Adapt<BookingDeliveryRecord>();
entity.CreatedTime = nowDate;
entity.UpdatedTime = nowDate;
entity.CreatedUserId = UserManager.UserId;
entity.CreatedUserName = UserManager.Name;
entity.STATUS = "TEMP";
entity.STATUS_NAME = "暂存";
entity.CTN_STAT = ctnStat;
}
int totalNum = 0;
foreach (var a in numArg)
{
var copyEntity = entity.Adapt<BookingDeliveryRecord>();
copyEntity.Id = 0;
copyEntity.CreatedTime = nowDate;
copyEntity.CreatedUserId = UserManager.UserId;
copyEntity.CreatedUserName = UserManager.Name;
copyEntity.UpdatedTime = nowDate;
copyEntity.STATUS = "TEMP";
copyEntity.STATUS_NAME = "暂存";
copyEntity.IS_RECV_BC = false;
copyEntity.LST_RECV_BC_DATE = null;
copyEntity.IS_RECV_BK_CANCEL = false;
copyEntity.LST_RECV_BK_CANCEL_DATE = null;
copyEntity.REQUEST_ACKNOWLEDGEMENT_ID = null;
copyEntity.BOOKING_REFERENCE = null;
copyEntity.NOTES = $"COPY NO.{a} BY={model.originalId}";
await _bookingDeliveryRecordRep.InsertAsync(copyEntity);
totalNum++;
if (ctnList.Count > 0)
{
ctnList.ForEach(async ctn =>
{
var ctnEntity = ctn.Adapt<BookingDeliveryRecordCtn>();
ctnEntity.Id = 0;
ctnEntity.RECORD_ID = copyEntity.Id;
ctnEntity.CreatedTime = nowDate;
ctnEntity.UpdatedTime = nowDate;
ctnEntity.CreatedUserId = UserManager.UserId;
ctnEntity.CreatedUserName = UserManager.Name;
await _bookingDeliveryRecordCtnRep.InsertAsync(ctnEntity);
});
}
}
return JSON.Serialize(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>
[HttpGet("/BookingMSKSPOTAPI/SyncBCInfo")]
public async Task<MSKBookingResultDto> SyncBCInfo(string mblno, long tenantId, string opTypeName = "BookingConfirmation")
{
MSKBookingResultDto result = new MSKBookingResultDto();
try
{
var model = await _bookingDeliveryRecordRep.AsQueryable().Filter(null, true)
.FirstAsync(a => a.BOOKING_REFERENCE == mblno && a.IsDeleted == false && a.TenantId == tenantId);
if (model == null)
throw Oops.Oh("订舱数据不存在或已作废");
if (opTypeName == "BookingConfirmation")
{
model.IS_RECV_BC = true;
model.LST_RECV_BC_DATE = DateTime.Now;
model.UpdatedTime = model.LST_RECV_BC_DATE;
model.UpdatedUserId = UserManager.UserId;
model.UpdatedUserName = UserManager.Name;
await _bookingDeliveryRecordRep.AsUpdateable(model).UpdateColumns(x => new {
x.IS_RECV_BC,
x.LST_RECV_BC_DATE,
x.UpdatedTime,
x.UpdatedUserId,
x.UpdatedUserName
}).ExecuteCommandAsync();
}
else if (opTypeName == "Cancellation")
{
model.IS_RECV_BK_CANCEL = true;
model.LST_RECV_BK_CANCEL_DATE = DateTime.Now;
model.UpdatedTime = model.LST_RECV_BC_DATE;
model.UpdatedUserId = UserManager.UserId;
model.UpdatedUserName = UserManager.Name;
await _bookingDeliveryRecordRep.AsUpdateable(model).UpdateColumns(x => new {
x.IS_RECV_BK_CANCEL,
x.LST_RECV_BK_CANCEL_DATE,
x.UpdatedTime,
x.UpdatedUserId,
x.UpdatedUserName
}).ExecuteCommandAsync();
}
result.succ = true;
}
catch (Exception ex)
{
result.succ = false;
result.msg = $"同步BC状态异常原因{ex.Message}";
}
return result;
}
#endregion
#region 批量复制前调取校验预警
/// <summary>
/// 批量复制前调取校验预警
/// </summary>
/// <param name="model">马士基API批量复制指定数据</param>
/// <returns>返回提示信息</returns>
[HttpPost("/BookingMSKSPOTAPI/CheckWarningBatchCopy")]
public async Task<string> CheckWarningBatchCopy(MSKAPISPOTBookingCopyDto model)
{
/*
1退
2opType=copy_edit-使
3
*/
var entity = await _bookingDeliveryRecordRep.AsQueryable()
.FirstAsync(a => a.Id == model.originalId);
if (entity != null)
{
List<string> msgList = new List<string>();
if (entity.IS_SHIPPER_OWNED || (model.bookingDto != null && model.bookingDto.isShipperOwned))
{
msgList.Add("含有指定托运人自己的集装箱");
}
if (entity.IS_IMPORT_RETURNED || (model.bookingDto != null && model.bookingDto.isImportReturned))
{
msgList.Add("含有指定进口退货集装箱或者其他三角集运");
}
if (entity.IS_REEFER || (model.bookingDto != null && model.bookingDto.isReefer))
{
msgList.Add("含有是冷冻处理");
}
if (model.bookingDto != null && model.bookingDto.cargoType != entity.CARGO_TYPE)
{
msgList.Add("货物标志与被复制货物标志不一致");
}
if (msgList.Count > 0)
throw Oops.Oh(string.Join(",", msgList.ToArray()));
}
else
{
return string.Empty;
}
return "校验成功";
}
#endregion
#region 批量发送API前调取校验预警
/// <summary>
/// 批量发送API前调取校验预警
/// </summary>
/// <param name="ids">马士基API订舱ID组</param>
/// <returns>返回提示信息</returns>
[HttpPost("/BookingMSKSPOTAPI/CheckWarningBatchSend")]
public async Task<string> CheckWarningBatchSend([FromBody] long[] ids)
{
var list = await _bookingDeliveryRecordRep.AsQueryable().Where(a => ids.Contains(a.Id)).ToListAsync();
if (list.Count > 0)
{
List<string> msgList = new List<string>();
if (list.Any(a => a.IS_SHIPPER_OWNED))
{
msgList.Add("含有指定托运人自己的集装箱");
}
if (list.Any(a => a.IS_IMPORT_RETURNED))
{
msgList.Add("含有指定进口退货集装箱或者其他三角集运");
}
if (list.Any(a => a.IS_REEFER))
{
msgList.Add("含有是冷冻处理");
}
if (msgList.Count > 0)
throw Oops.Oh(string.Join("#", msgList.ToArray()));
}
return "校验成功";
}
#endregion
#region 获取初始化页面默认值
/// <summary>
/// 获取初始化页面默认值
/// </summary>
/// <returns>返回详情</returns>
[HttpGet("/BookingMSKSPOTAPI/GetInitInfo")]
public async Task<MSKSPOTBookingInitDto> GetInitInfo()
{
MSKSPOTBookingInitDto dto = null;
var webAccountConfig = await _webAccountConfig.GetAccountConfigByTenantId("MSKSpotApi", UserManager.UserId, UserManager.TENANT_ID);
if (webAccountConfig == null)
throw Oops.Oh("未配置公司账户维护-MSK即期请联系管理员");
if (string.IsNullOrWhiteSpace(webAccountConfig.RegistPartyCode)
|| string.IsNullOrWhiteSpace(webAccountConfig.RegistPartyName) || string.IsNullOrWhiteSpace(webAccountConfig.RegistContractName)
|| string.IsNullOrWhiteSpace(webAccountConfig.RegistContractEmail))
{
throw Oops.Oh("账户维护-MSK即期,未配置完整注册信息(备案代码、备案全称、联系人、邮箱必填),请联系管理员");
}
dto = new MSKSPOTBookingInitDto
{
bookedMaerskByPartyCode = webAccountConfig.RegistPartyCode,
bookedByCompanyName = webAccountConfig.RegistPartyName,
priceOwnerMaerskPartyCode = webAccountConfig.RegistPartyCode,
priceOwnerCompanyName = webAccountConfig.RegistPartyName,
bookedByPartyContactName = webAccountConfig.RegistContractName,
bookedByPartyContactEmail = webAccountConfig.RegistContractEmail,
5 months ago
priceOwnerContactName = webAccountConfig.RegistContractName,
priceOwnerContactEmail = webAccountConfig.RegistContractEmail,
};
return dto;
}
#endregion
}
}