using Furion.FriendlyException; using Furion.JsonSerialization; using Furion.RemoteRequest.Extensions; using Furion; using Mapster; using Microsoft.AspNetCore.Mvc; using Myshipping.Application.Entity; using Myshipping.Core; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Furion.DynamicApiController; using Furion.DependencyInjection; using Myshipping.Core.Service; using Microsoft.Extensions.Logging; using Myshipping.Application.Helper; using System.Text.RegularExpressions; using System.Globalization; namespace Myshipping.Application.Service.BookingOrder { /// /// 马士基API订舱 /// [ApiDescriptionSettings("Application", Name = "BookingMSKAPI", Order = 10)] public class BookingMSKAPIService: IBookingMSKAPIService, IDynamicApiController, ITransient { private readonly SqlSugarRepository _bookingDeliveryRecordRep; private readonly SqlSugarRepository _bookingDeliveryRecordCtnRep; private readonly ISysCacheService _cache; private readonly IDjyWebsiteAccountConfigService _webAccountConfig; private readonly ILogger _logger; const string CONST_MSK_API_COMMODITY_URL = "MSKApiCommodity"; const string CONST_MSK_API_BOOKING_URL = "MSKApiBooking"; const string CONST_MSK_API_Poing2P_SECD_URL = "MSKApiSailingSchedulePoint2Point"; const string CONST_MSK_API_LOCATION_URL = "MSKApilocation"; public BookingMSKAPIService(ILogger logger, ISysCacheService cache, IDjyWebsiteAccountConfigService webAccountConfig, SqlSugarRepository bookingDeliveryRecordRep, SqlSugarRepository bookingDeliveryRecordCtnRep) { _logger = logger; _cache = cache; _webAccountConfig = webAccountConfig; _bookingDeliveryRecordRep = bookingDeliveryRecordRep; _bookingDeliveryRecordCtnRep = bookingDeliveryRecordCtnRep; } #region 检索海运船期详情 /// /// 检索海运船期详情 /// /// 请求船期详情 /// 返回船期结果 [HttpPost("/BookingMSKAPI/SearchShipSailingSchedule")] public async Task> SearchShipSailingSchedule(QueryShipSailingScheduleDto model) { List list = new List(); /* MSKApiSailingSchedulePoint2Point */ try { if (string.IsNullOrWhiteSpace(model.collectionOriginCityName)) throw Oops.Oh($"始发地不能为空"); if (string.IsNullOrWhiteSpace(model.deliveryDestinationCityName)) throw Oops.Oh($"目的地不能为空"); if (string.IsNullOrWhiteSpace(model.vesselOperatorCarrierCode)) throw Oops.Oh($"服务船公司不能为空"); if (string.IsNullOrWhiteSpace(model.carrierId)) throw Oops.Oh("船公司代码不能为空"); if (string.IsNullOrWhiteSpace(model.startDate)) throw Oops.Oh($"预计离港日期不能为空"); DateTime etd = DateTime.MinValue; if (!DateTime.TryParse(model.startDate, out etd)) throw Oops.Oh($"预计离港日期格式错误"); 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_Poing2P_SECD_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"); MSKAPISearchPoint2PointScheduleDto queryInfo = new MSKAPISearchPoint2PointScheduleDto { userKey = App.Configuration["MSKAPIDjyUserKey"], userSecret = App.Configuration["MSKAPIDjyUserSecret"], operatingEnvironment = App.Configuration["MSKAPIOPEnvironment"], mskAppKey = webAccountConfig.Account, collectionOriginCityName = model.collectionOriginCityName, collectionOriginCountryCode = model.collectionOriginCountryCode, deliveryDestinationCityName = model.deliveryDestinationCityName, deliveryDestinationCountryCode = model.deliveryDestinationCountryCode, cargoType = model.cargoType, exportServiceMode = model.exportServiceMode, importServiceMode = model.importServiceMode, vesselOperatorCarrierCode = model.vesselOperatorCarrierCode, startDate = etd.ToString("yyyy-MM-dd"), startDateType = "D", }; MSKAPISearchPoint2PointScheduleResultDto resultInfo = null; var rlt = await queryUrl.SetBody(queryInfo) .PostAsStringAsync(); if (!string.IsNullOrWhiteSpace(rlt)) { try { resultInfo = JSON.Deserialize(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) { resultInfo.data.ForEach(a => { a.transportSchedules.ForEach(b => { SearchShipSailingScheduleResultDto info = new SearchShipSailingScheduleResultDto { carrierProductId = a.carrierProductId, carrierProductSequenceId = a.carrierProductSequenceId, ETD = b.departureDateTime, ATD = b.arrivalDateTime, vesselOperatorCarrierCode = b.vesselOperatorCarrierCode }; if (b.departureDateTime.HasValue && b.arrivalDateTime.HasValue) { TimeSpan ts = b.arrivalDateTime.Value.Subtract(b.departureDateTime.Value); var timeDiff = ts.TotalHours; info.days = (int)Math.Ceiling(timeDiff / 24.0); } if (b.facilities != null) { info.orignCityName = b.facilities.collectionOrigin?.cityName; info.orignCarrierSiteGeoID = b.facilities.collectionOrigin?.carrierSiteGeoID; info.orignLocationName = b.facilities.collectionOrigin?.locationName; info.orignCountryCode = b.facilities.collectionOrigin?.countryCode; info.orignLocationType = b.facilities.collectionOrigin?.locationType; info.orignUNLocationCode = b.facilities.collectionOrigin?.UNLocationCode; info.orignUNRegionCode = b.facilities.collectionOrigin?.UNRegionCode; info.deliveryCityName = b.facilities.deliveryDestination?.cityName; info.deliveryCarrierSiteGeoID = b.facilities.deliveryDestination?.carrierSiteGeoID; info.deliveryLocationName = b.facilities.deliveryDestination?.locationName; info.deliveryCountryCode = b.facilities.deliveryDestination?.countryCode; info.deliveryLocationType = b.facilities.deliveryDestination?.locationType; info.deliveryUNLocationCode = b.facilities.deliveryDestination?.UNLocationCode; info.deliveryUNRegionCode = b.facilities.deliveryDestination?.UNRegionCode; } info.vesselIMONumber = b.firstDepartureVessel?.vesselIMONumber; info.carrierVesselCode = b.firstDepartureVessel?.carrierVesselCode; info.vesselName = b.firstDepartureVessel?.vesselName; if (b.transportLegs != null && b.transportLegs.Count > 0) { var firstTransportLegs = b.transportLegs.FirstOrDefault(); if (firstTransportLegs.transport != null) { info.transportMode = firstTransportLegs.transport.transportMode; info.carrierDepartureVoyageNumber = firstTransportLegs.transport.carrierDepartureVoyageNumber; } } list.Add(info); }); }); } } catch (Exception ex) { _logger.LogError($"检索海运船期详情异常,req={JSON.Serialize(model)} 原因:{ex.Message}"); throw Oops.Bah($"检索海运船期详情失败,{ex.Message}"); } return list; } #endregion #region 发送马士基订舱请求 /// /// 发送马士基订舱请求 /// /// 请求订舱详情 /// [HttpPost("/BookingMSKAPI/SendMSKBooking")] public async Task SendMSKBooking(MSKBookingDto model) { 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(); var recordCtnList = model.ctns.Adapt>(); var ctnCodeMappingList = _cache.GetAllMappingCtn().GetAwaiter().GetResult().ToList(); if (ctnCodeMappingList.Count > 0) ctnCodeMappingList = ctnCodeMappingList.Where(x => x.CarrierCode == "MSK" && x.Module == "BOOK_OR_CLOSING").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 }, }; 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.placeOfReceiptUnLocCode, cityName = model.placeOfReceiptCityName, }, placeOfDelivery = new MSKAPIBookingRouteDetailsBase { UNLocationCode = model.placeOfDeliveryUnLocCode, cityName = model.placeOfDeliveryCityName, }, selectedRoute = new MSKAPIBookingRoute { bookingSchedules = new List { 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.placeOfReceiptUnLocCode }, endLocation = new MSKAPIBookingRouteDetailsBase { cityName = model.placeOfDeliveryCityName, UNLocationCode = model.placeOfDeliveryUnLocCode }, transportModeCode = model.transportMode } } }, } }; 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(); 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() }; 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); }); } var id = InnerSave(model, isSendApi: true).GetAwaiter().GetResult(); 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(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(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 }).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.NOTES }).ExecuteCommandAsync(); throw Oops.Bah(resultInfo.msg); } } catch (Exception ex) { _logger.LogError($"MSK API订舱异常,req={JSON.Serialize(model)} 原因:{ex.Message}"); throw Oops.Bah($"MSK API订舱失败,{ex.Message}"); } return result; } #endregion #region 校验马士基API订舱必填项 /// /// 校验马士基API订舱必填项 /// /// private void ValidateMSKAPIData(MSKBookingDto 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 (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 检索商品名称 /// /// 检索商品名称 /// /// 请求详情 /// 返回检索结果 [HttpPost("/BookingMSKAPI/SearchCommodities")] public async Task> SearchCommodities(QueryCommoditiesDto model) { List list = new List(); /* 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(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>(); } } catch (Exception ex) { _logger.LogError($"检索商品名称异常,req={JSON.Serialize(model)} 原因:{ex.Message}"); throw Oops.Bah($"检索商品名称失败,{ex.Message}"); } return list; } #endregion #region 检索始发地、目的港口信息 /// /// 检索始发地、目的港口信息 /// /// 请求详情 /// 返回检索结果 [HttpPost("/BookingMSKAPI/SearchLocations")] public async Task> SearchLocations(QueryLocationsDto model) { List list = new List(); /* 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_API_LOCATION_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"); MSKAPISearchLocationDto queryInfo = new MSKAPISearchLocationDto { userKey = App.Configuration["MSKAPIDjyUserKey"], userSecret = App.Configuration["MSKAPIDjyUserSecret"], operatingEnvironment = App.Configuration["MSKAPIOPEnvironment"], name = model.cityName, mskAppKey = webAccountConfig.Account, carrierCode = model.carrierCode }; MSKAPISearchLocationResultDto resultInfo = null; var rlt = await queryUrl.SetBody(queryInfo) .PostAsStringAsync(); if (!string.IsNullOrWhiteSpace(rlt)) { try { resultInfo = JSON.Deserialize(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>(); } } catch (Exception ex) { _logger.LogError($"检索始发地、目的港口异常,req={JSON.Serialize(model)} 原因:{ex.Message}"); throw Oops.Bah($"检索始发地、目的港口失败,{ex.Message}"); } return list; } #endregion #region 马士基API订舱台账 /// /// 马士基API订舱台账 /// /// 查询条件 /// 返回台账列表 [HttpPost("/BookingMSKAPI/GetPage")] public async Task> GetPageAsync([FromBody] QueryBookingDeliveryRecordDto QuerySearch) { //制单日期 DateTime createBegin = DateTime.MinValue; DateTime createEnd = DateTime.MinValue; //更新日期 DateTime updateBegin = DateTime.MinValue; DateTime updateEnd = DateTime.MinValue; //预计离港日期 DateTime edepartureBegin = DateTime.MinValue; DateTime edepartureEnd = DateTime.MinValue; //ETD日期 DateTime etdBegin = DateTime.MinValue; DateTime etdEnd = DateTime.MinValue; //ETA时间 DateTime etaBegin = DateTime.MinValue; DateTime etaEnd = DateTime.MinValue; //定时 DateTime jobBegin = DateTime.MinValue; DateTime jobEnd = DateTime.MinValue; #region 查询条件 //制单日期 if (!string.IsNullOrWhiteSpace(QuerySearch.CreateBegin)) { if (!DateTime.TryParse(QuerySearch.CreateBegin, out createBegin)) throw Oops.Oh($"创建起始日期格式错误,{QuerySearch.CreateBegin}"); } if (!string.IsNullOrWhiteSpace(QuerySearch.CreateEnd)) { if (!DateTime.TryParse(QuerySearch.CreateEnd, out createEnd)) throw Oops.Oh($"创建结束日期格式错误,{QuerySearch.CreateEnd}"); createEnd = createEnd.AddDays(1); } //更新日期 if (!string.IsNullOrWhiteSpace(QuerySearch.UpdateBegin)) { if (!DateTime.TryParse(QuerySearch.UpdateBegin, out updateBegin)) throw Oops.Oh($"更新起始日期开始格式错误,{QuerySearch.UpdateBegin}"); } if (!string.IsNullOrWhiteSpace(QuerySearch.UpdateEnd)) { if (!DateTime.TryParse(QuerySearch.UpdateEnd, out updateEnd)) throw Oops.Oh($"更新结束日期格式错误,{QuerySearch.UpdateEnd}"); updateEnd = updateEnd.AddDays(1); } //预计离港日期 if (!string.IsNullOrWhiteSpace(QuerySearch.EDepartureBegin)) { if (!DateTime.TryParse(QuerySearch.EDepartureBegin, out edepartureBegin)) throw Oops.Oh($"预计离港日期起始格式错误,{QuerySearch.EDepartureBegin}"); } if (!string.IsNullOrWhiteSpace(QuerySearch.EDepartureEnd)) { if (!DateTime.TryParse(QuerySearch.EDepartureEnd, out edepartureEnd)) throw Oops.Oh($"预计离港日期结束格式错误,{QuerySearch.EDepartureEnd}"); edepartureEnd = edepartureEnd.AddDays(1); } //ETD if (!string.IsNullOrWhiteSpace(QuerySearch.ETDBegin)) { if (!DateTime.TryParse(QuerySearch.ETDBegin, out etdBegin)) throw Oops.Oh($"ETD起始日期格式错误,{QuerySearch.ETDBegin}"); } if (!string.IsNullOrWhiteSpace(QuerySearch.ETDEnd)) { if (!DateTime.TryParse(QuerySearch.ETDEnd, out etdEnd)) throw Oops.Oh($"ETD结束日期格式错误,{QuerySearch.ETDEnd}"); etdEnd = etdEnd.AddDays(1); } //ETA if (!string.IsNullOrWhiteSpace(QuerySearch.ETDBegin)) { if (!DateTime.TryParse(QuerySearch.ETDBegin, out etaBegin)) throw Oops.Oh($"ETA起始日期格式错误,{QuerySearch.ETDBegin}"); } if (!string.IsNullOrWhiteSpace(QuerySearch.ETAEnd)) { if (!DateTime.TryParse(QuerySearch.ETAEnd, out etaEnd)) throw Oops.Oh($"ETA结束日期格式错误,{QuerySearch.ETAEnd}"); etaEnd = etaEnd.AddDays(1); } //定时 if (!string.IsNullOrWhiteSpace(QuerySearch.JOBBegin)) { if (!DateTime.TryParse(QuerySearch.JOBBegin, out jobBegin)) throw Oops.Oh($"返场起始日期格式错误,{QuerySearch.JOBBegin}"); } if (!string.IsNullOrWhiteSpace(QuerySearch.JOBEnd)) { if (!DateTime.TryParse(QuerySearch.JOBEnd, out jobEnd)) throw Oops.Oh($"返场结束日期格式错误,{QuerySearch.JOBEnd}"); jobEnd = jobEnd.AddDays(1); } #endregion string entityOrderCol = "CreatedTime"; //这里因为返回给前端的台账数据是DTO,所以这里排序时候需要转换成Entity对应的字段 if (!string.IsNullOrWhiteSpace(QuerySearch.SortField)) entityOrderCol = MapsterExtHelper.GetAdaptProperty(QuerySearch.SortField); var entities = await _bookingDeliveryRecordRep.AsQueryable() .WhereIF(createBegin != DateTime.MinValue, t => t.CreatedTime.HasValue && t.CreatedTime.Value >= createBegin) .WhereIF(createEnd != DateTime.MinValue, t => t.CreatedTime.HasValue && t.CreatedTime.Value < createEnd) .WhereIF(updateBegin != DateTime.MinValue, t => t.UpdatedTime.HasValue && t.UpdatedTime.Value >= updateBegin) .WhereIF(updateEnd != DateTime.MinValue, t => t.UpdatedTime.HasValue && t.UpdatedTime.Value < updateEnd) .WhereIF(edepartureBegin != DateTime.MinValue, t => t.EARLIEST_DEPARTURE_DATE.HasValue && t.EARLIEST_DEPARTURE_DATE.Value >= edepartureBegin) .WhereIF(edepartureEnd != DateTime.MinValue, t => t.EARLIEST_DEPARTURE_DATE.HasValue && t.EARLIEST_DEPARTURE_DATE.Value < edepartureEnd) .WhereIF(etdBegin != DateTime.MinValue, t => t.ETD.HasValue && t.ETD.Value >= etdBegin) .WhereIF(etdEnd != DateTime.MinValue, t => t.ETD.HasValue && t.ETA.Value < etdEnd) .WhereIF(etaBegin != DateTime.MinValue, t => t.ETA.HasValue && t.ETA.Value >= etaBegin) .WhereIF(etaEnd != DateTime.MinValue, t => t.ETA.HasValue && t.ETA.Value < etaEnd) .WhereIF(jobBegin != DateTime.MinValue, t => t.JOB_TIME.HasValue && t.JOB_TIME.Value >= jobBegin) .WhereIF(jobEnd != DateTime.MinValue, t => t.JOB_TIME.HasValue && t.JOB_TIME.Value < jobEnd) .WhereIF(!string.IsNullOrWhiteSpace(QuerySearch.PriceReference), t => t.PRICE_REFERENCE.Contains(QuerySearch.PriceReference)) .WhereIF(!string.IsNullOrWhiteSpace(QuerySearch.BookedByCompanyName), t => t.BOOKEDBY_COMPANY_NAME.Contains(QuerySearch.BookedByCompanyName)) .WhereIF(!string.IsNullOrWhiteSpace(QuerySearch.BookedByCompanyPartyCode), t => t.BOOKEDBY_COMPANY_PARTYCODE.Contains(QuerySearch.BookedByCompanyPartyCode)) .WhereIF(!string.IsNullOrWhiteSpace(QuerySearch.PriceOwnerCompanyName), t => t.PRICE_OWNER_COMPANY_NAME.Contains(QuerySearch.PriceOwnerCompanyName)) .WhereIF(!string.IsNullOrWhiteSpace(QuerySearch.PriceOwnerCompanyPartyCode), t => t.PRICE_OWNER_COMPANY_PARTYCODE.Contains(QuerySearch.PriceOwnerCompanyPartyCode)) .WhereIF(!string.IsNullOrWhiteSpace(QuerySearch.PlaceReceiptCity), t => t.PLACERECEIPT_CITY.Contains(QuerySearch.PlaceReceiptCity) || t.PLACERECEIPT_UNLOC_CODE.Contains(QuerySearch.PlaceReceiptCity)) .WhereIF(!string.IsNullOrWhiteSpace(QuerySearch.PlaceDeliveryCity), t => t.PLACEDELIVERY_CITY.Contains(QuerySearch.PlaceDeliveryCity) || t.PLACEDELIVERY_UNLOC_CODE.Contains(QuerySearch.PlaceDeliveryCity)) .OrderBy(entityOrderCol + (QuerySearch.descSort ? " desc " : " asc ")) .ToPagedListAsync(QuerySearch.PageNo, QuerySearch.PageSize); return entities.Adapt>(); } #endregion #region 获取马士基API订舱详情 /// /// 获取马士基API订舱详情 /// /// 马士基API订舱ID /// 返回详情 [HttpGet("/BookingMSKAPI/GetInfo")] public async Task GetInfo(long id) { MSKBookingDto model = null; var entity = await _bookingDeliveryRecordRep.AsQueryable() .FirstAsync(a => a.Id == id); if(entity == null) throw Oops.Oh($"获取马士基API订舱详情失败,不存在或已作废"); model = entity.Adapt(); 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(); } return model; } #endregion #region 保存 /// /// 保存 /// /// 请求订舱详情 /// 返回ID [HttpPost("/BookingMSKAPI/Save")] public async Task Save([FromBody] MSKBookingDto model) { return await InnerSave(model); } #endregion /// /// 保存内部方法 /// /// API订舱详情 /// 是否发送API,true-发送需要校验状态;false-不校验状态 /// private async Task InnerSave(MSKBookingDto model,bool isSendApi = false) { DateTime nowDate = DateTime.Now; string ctnStat = string.Empty; _logger.LogInformation($"获取请求马士基API订舱报文,JSON={JSON.Serialize(model)}"); 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(); entity.Id = model.id.Value; entity.UpdatedTime = nowDate; entity.UpdatedUserId = UserManager.UserId; entity.UpdatedUserName = UserManager.Name; entity.CTN_STAT = ctnStat; 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(); 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, }).ExecuteCommand(); } else { var ctnEntity = new BookingDeliveryRecordCtn { CTN_CODE = ctn.ctnCode, CTN_NAME = ctn.ctnName, CTN_NUM = ctn.ctnNum.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(); entity.CreatedTime = nowDate; entity.UpdatedTime = nowDate; entity.CreatedUserId = UserManager.UserId; entity.CreatedUserName = UserManager.Name; entity.STATUS = "TEMP"; entity.STATUS_NAME = "暂存"; entity.CTN_STAT = ctnStat; 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 }; 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; } } #region 删除 /// /// 删除 /// /// 请求订舱ID /// [HttpGet("/BookingMSKAPI/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 } }