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

1797 lines
76 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 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;
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;
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,
SqlSugarRepository<BookingDeliveryRecordShipSchedule> bookingDeliveryRecordShipScheduleRep,
SqlSugarRepository<BookingDeliveryRecordCtn> bookingDeliveryRecordCtnRep)
{
_logger = logger;
_cache = cache;
_webAccountConfig = webAccountConfig;
_bookingDeliveryRecordRep = bookingDeliveryRecordRep;
_bookingDeliveryRecordCtnRep = bookingDeliveryRecordCtnRep;
_sysDataUserMenuService = sysDataUserMenuService;
_djyTenantParamService = djyTenantParamService;
_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>()
};
//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))
{
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")
{
/*
1、按照船期明细缓存并把ID作为缓存的KEY
2、对数据进行JSON串行化的文本提取MD5
3、写入缓存并返回ID
*/
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
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);
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,
bookingOfficeUNLocationCode = "CNTAO"
};
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
},
};
//排查怀疑这里是导致BC没有合约号胡的问题开启这个值看看
//if (model.isBookingPartOwnPrice)
//{
// bookingDto.bookingBody.mandatoryParties.isPriceOwnerFromServiceContractAccepted = true;
//}
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
//: model.placeOfReceiptUnLocCode,
//cityName = model.placeOfReceiptCityName,
},
placeOfDelivery = new MSKAPIBookingRouteDetailsBase
{
UNLocationCode = model.userPlaceOfDeliveryUnLocCode
//: model.placeOfDeliveryUnLocCode,
//cityName = model.placeOfDeliveryCityName,
},
selectedRoute = new MSKAPIBookingRoute
{
bookingSchedules = new List<MSKAPIBookingSchedules> {
new MSKAPIBookingSchedules
{
originDepartureDateTimeLocal = model.originDepartureDateTimeLocal.Value.ToString("yyyy-MM-ddTHH:mm:ss"),
destinationArrivalDateTimeLocal = model.destinationArrivalDateTimeLocal.Value.ToString("yyyy-MM-ddTHH:mm:ss"),
transportMode = new MSKAPIBookingTransportMode
{
vessel = new MSKAPIBookingTransportModeVessel
{
name = model.vesselName,
maerskVesselCode = model.carrierVesselCode,
},
exportVoyageNumber = model.exportVoyageNumber,
},
startLocation = new MSKAPIBookingRouteDetailsBase
{
//cityName = model.placeOfReceiptCityName,
UNLocationCode = model.userPlaceOfReceiptUnLocCode
//: model.placeOfReceiptUnLocCode
},
endLocation = new MSKAPIBookingRouteDetailsBase
{
//cityName = model.placeOfDeliveryCityName,
UNLocationCode = model.userPlaceOfDeliveryUnLocCode
//: model.placeOfDeliveryUnLocCode
},
transportModeCode = model.transportMode
}
}
},
}
};
//if(!model.isSendNoSchedule)
//{
// bookingDto.bookingBody.transport.routeDetails.selectedRoute.routeScheduleId = model.carrierProductId;
//}
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、持约方公司名称、代码、联系、邮箱必填
6、始发地城市名称、UNLOC、国家代码、服务模式
7、目的地城市名称、UNLOC、国家代码、服务模式
8、船名、航次、ETD、ETA
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();
}
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)}");
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 = GetCacheShipSailingSchedule(model.PId);
}
else
{
selectedShipSchedule = JSON.Deserialize<MSKAPISPOTSearchScheduleRateResultDataDto>(shipScheduleRecord.SHIP_JSON);
}
if (selectedShipSchedule == null)
throw Oops.Oh("船期数据校验失败,请重新查询船期信息");
}
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;
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();
});
}
}
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;
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);
});
}
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、如果待复制的单子里还有“托运人自己的集装箱”或“进口退货集装箱或者其他三角集运”需要做提醒是否继续复制。
2、如果是opType=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,
};
return dto;
}
#endregion
}
}