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; using Myshipping.Core.Const; using System.Reflection.Metadata; using Org.BouncyCastle.Crypto; using Yitter.IdGenerator; using MySqlX.XDevAPI.Common; using NPOI.OpenXmlFormats.Wordprocessing; using Newtonsoft.Json; using StackExchange.Profiling.Internal; using SqlSugar; using static Aliyun.OSS.Model.InventoryConfigurationModel; using System.Threading; using System.Collections; using MathNet.Numerics; using Myshipping.Core.Entity; using HtmlAgilityPack; using System.Security.Cryptography; using Myshipping.Application.ConfigOption; using System.IO; using System.Net.Http; using DocumentFormat.OpenXml.Office2010.Excel; using DocumentFormat.OpenXml.EMMA; using Microsoft.AspNetCore.Authorization; 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 SqlSugarRepository _bookingDeliveryRecordShipScheduleRep; private readonly SqlSugarRepository _bookingDeliveryRecordJobRunScheduleRep; private readonly SqlSugarRepository _djyUserMailAccount; private readonly SqlSugarRepository _sysUserRepository; private readonly ISysCacheService _cache; private readonly IDjyWebsiteAccountConfigService _webAccountConfig; private readonly ILogger _logger; private readonly ISysDataUserMenu _sysDataUserMenuService; 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, ISysDataUserMenu sysDataUserMenuService, SqlSugarRepository bookingDeliveryRecordCtnRep, SqlSugarRepository bookingDeliveryRecordShipScheduleRep, SqlSugarRepository djyUserMailAccount, SqlSugarRepository bookingDeliveryRecordJobRunScheduleRep, SqlSugarRepository sysUserRepository) { _logger = logger; _cache = cache; _webAccountConfig = webAccountConfig; _bookingDeliveryRecordRep = bookingDeliveryRecordRep; _bookingDeliveryRecordCtnRep = bookingDeliveryRecordCtnRep; _sysDataUserMenuService = sysDataUserMenuService; _bookingDeliveryRecordShipScheduleRep = bookingDeliveryRecordShipScheduleRep; _djyUserMailAccount = djyUserMailAccount; _bookingDeliveryRecordJobRunScheduleRep = bookingDeliveryRecordJobRunScheduleRep; _sysUserRepository = sysUserRepository; } #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, cargoType = model.cargoType, exportServiceMode = model.exportServiceMode, importServiceMode = model.importServiceMode, vesselOperatorCarrierCode = model.vesselOperatorCarrierCode, startDate = etd.ToString("yyyy-MM-dd"), startDateType = "D", }; if(!string.IsNullOrWhiteSpace(model.carrierCollectionOriginGeoID) && !string.IsNullOrWhiteSpace(model.carrierDeliveryDestinationGeoID)) { queryInfo.carrierCollectionOriginGeoID = model.carrierCollectionOriginGeoID; queryInfo.carrierDeliveryDestinationGeoID = model.carrierDeliveryDestinationGeoID; } else { queryInfo.collectionOriginCityName = model.collectionOriginCityName; queryInfo.collectionOriginCountryCode = model.collectionOriginCountryCode; queryInfo.deliveryDestinationCityName = model.deliveryDestinationCityName; queryInfo.deliveryDestinationCountryCode = model.deliveryDestinationCountryCode; } //有时候船期需要带上箱型检索 if (!string.IsNullOrWhiteSpace(model.ISOEquipmentCode)) { //这里需要翻译一下箱型 var ctnCodeMappingList = _cache.GetAllMappingCtn().GetAwaiter().GetResult().ToList(); if (ctnCodeMappingList.Count > 0) ctnCodeMappingList = ctnCodeMappingList.Where(x => x.CarrierCode == "MSK" && x.Module == "BOOK_MSK_API").ToList(); var ctnMapping = ctnCodeMappingList.FirstOrDefault(t => t.Code.Equals(model.ISOEquipmentCode)); if (ctnMapping == null) { queryInfo.ISOEquipmentCode = model.ISOEquipmentCode; } else { queryInfo.ISOEquipmentCode = ctnMapping.MapCode; } } if (!string.IsNullOrWhiteSpace(model.stuffingWeight)) { queryInfo.stuffingWeight = model.stuffingWeight; } if (model.stuffingVolume > 0) { queryInfo.stuffingVolume = model.stuffingVolume; } MSKAPISearchPoint2PointScheduleResultDto 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 API查询船期请求,{jsonBody}"); if (!string.IsNullOrWhiteSpace(rlt)) { try { _logger.LogInformation($"请求MSK API查询船期结果,{rlt}"); 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(t => { t.transportSchedules.ForEach(a => { a.originGeoId = model.carrierCollectionOriginGeoID; a.originUnLocCode = model.collectionOriginUNLocationCode; a.originRegionName = model.collectionOriginUNRegionName; a.originCityName = model.collectionOriginCityName; a.originCountryName = model.collectionOriginCountryName; a.destinationGeoId = model.carrierDeliveryDestinationGeoID; a.destinationUnLocCode = model.deliveryDestinationUNLocationCode; a.destinationRegionName = model.deliveryDestinationUNRegionName; a.destinationCityName = model.deliveryDestinationCityName; a.destinationCountryName = model.deliveryDestinationCountryName; CacheShipSailingSchedule(a).GetAwaiter().GetResult(); }); var currList = t.transportSchedules.Select(a => { return GetShipScheduleShow(a); }).ToList(); if (currList.Count > 0) list.AddRange(currList); }); } } catch (Exception ex) { _logger.LogError($"检索海运船期详情异常,req={JSON.Serialize(model)} 原因:{ex.Message}"); throw Oops.Bah($"检索海运船期详情失败,{ex.Message}"); } return list; } #endregion #region 组织返回船期数据 /// /// 组织返回船期数据 /// /// 查询的船期详情 /// 返回显示的船期数据 private SearchShipSailingScheduleResultDto GetShipScheduleShow(MSKAPISearchTransportSchedules model) { SearchShipSailingScheduleResultDto showDto = new SearchShipSailingScheduleResultDto { PId = model.PId, MD5 = model.MD5, orignCarrierCityGeoID = model.originGeoId, orignUNLocationCode = model.originUnLocCode, orignCityName = model.originCityName, originRegionName = model.originRegionName, originCountryName = model.originCountryName, deliveryCarrierCityGeoID = model.destinationGeoId, deliveryUNLocationCode = model.destinationUnLocCode, deliveryCityName = model.destinationCityName, deliveryRegionName = model.destinationRegionName, deliveryCountryName = model.destinationCountryName, vesselName = model.firstDepartureVessel.vesselName, carrierDepartureVoyageNumber = model.transportLegs.FirstOrDefault().transport.carrierDepartureVoyageNumber, Legs = new List() }; //ETD if (model.departureDateTime.HasValue) { showDto.ETD = model.departureDateTime.Value; } else { throw Oops.Bah($"查询船期错误,预计离港日期查询为空"); } //ETA if (model.arrivalDateTime.HasValue) { showDto.ETA = model.arrivalDateTime.Value; } else { throw Oops.Bah($"查询船期错误,预计到港日期查询为空"); } //计算预计天数 if (showDto.ETD.HasValue && showDto.ETD.HasValue) { TimeSpan ts = showDto.ETA.Value.Subtract(showDto.ETD.Value); var timeDiff = ts.TotalHours; showDto.days = (int)Math.Ceiling(timeDiff / 24.0); } if (model.transportLegs.Count > 1) showDto.isTransfer = true; //Legs if (model.facilities != null) { showDto.orignCountryCode = model.facilities.collectionOrigin.countryCode; showDto.deliveryCountryCode = model.facilities.deliveryDestination.countryCode; var legs = new List(); for (int i = 0; i < model.transportLegs.Count; i++) { var b = model.transportLegs[i]; MSKAPISPOTScheduleRateResultShowLegsDto leg = new MSKAPISPOTScheduleRateResultShowLegsDto { vesselName = b.transport.vessel?.vesselName, VoyageNo = b.transport?.carrierDepartureVoyageNumber, From = new MSKAPISPOTScheduleRateResultShowLegsLocationDto { CityName = b.facilities.startLocation.cityName, CountryCode = b.facilities.startLocation.countryCode, SiteGeoId = b.facilities.startLocation.carrierSiteGeoID, LocationType = "From", }, To = new MSKAPISPOTScheduleRateResultShowLegsLocationDto { CityName = b.facilities.endLocation.cityName, CountryCode = b.facilities.endLocation.countryCode, SiteGeoId = b.facilities.endLocation.carrierSiteGeoID, LocationType = "To", } }; //ETD if (b.departureDateTime.HasValue) { leg.ETD = b.departureDateTime.Value; } else { throw Oops.Bah($"查询船期错误,预计离港日期查询为空"); } //ETA if (b.arrivalDateTime.HasValue) { leg.ETA = b.arrivalDateTime.Value; } else { throw Oops.Bah($"查询船期错误,预计到港日期查询为空"); } leg.SortNo = i + 1; leg.From.SiteGeoId = b.facilities.startLocation.carrierSiteGeoID; leg.From.CityName = b.facilities.startLocation.cityName; leg.From.CountryCode = b.facilities.startLocation.countryCode; leg.From.UnLocCode = b.facilities.startLocation.UNLocationCode; leg.To.SiteGeoId = b.facilities.endLocation.carrierSiteGeoID; leg.To.CityName = b.facilities.endLocation.cityName; leg.To.CountryCode = b.facilities.endLocation.countryCode; leg.To.UnLocCode = b.facilities.endLocation.UNLocationCode; if (i == 0 && i == model.transportLegs.Count - 1) { leg.From.CityGeoId = model.originGeoId; leg.From.CountryName = model.originCountryName; leg.From.RegionName = model.originRegionName; leg.To.CityGeoId= model.destinationGeoId; leg.To.CountryName = model.destinationCountryName; leg.To.RegionName = model.destinationRegionName; } else { if(i == 0) { leg.From.CityGeoId = model.originGeoId; leg.From.CountryName = model.originCountryName; leg.From.RegionName = model.originRegionName; leg.From.UnLocCode = model.originUnLocCode; } else if(i == model.transportLegs.Count - 1) { leg.To.CityGeoId = model.destinationGeoId; leg.To.CountryName = model.destinationCountryName; leg.To.RegionName = model.destinationRegionName; leg.To.UnLocCode = model.destinationUnLocCode; } } legs.Add(leg); } showDto.Legs = legs.OrderBy(t => t.ETD).Select((t, idx) => { t.SortNo = idx + 1; return t; }).ToList(); } return showDto; } #endregion #region 缓存船期数据 /// /// 缓存船期数据 /// /// 船期查询结果明细 /// 船期类型 MSKSPOT-马士基即期 /// 返回主键ID private async Task CacheShipSailingSchedule(MSKAPISearchTransportSchedules model, string busiType = "MSKCON") { /* 1、按照船期明细缓存,并把ID作为缓存的KEY 2、对数据进行JSON串行化的文本提取MD5 3、写入缓存,并返回ID */ var newModel = model.Adapt(); //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(4); var expireTimeSpan = expireDateTime.Subtract(nowDate).Duration(); if (!_cache.Exists($"{shareKey}_{busiType}")) { await _cache.SetTimeoutAsync($"{shareKey}_{busiType}", Newtonsoft.Json.JsonConvert.SerializeObject(model), expireTimeSpan); } } #endregion private MSKAPISearchTransportSchedules GetCacheShipSailingSchedule(long pid, string busiType = "MSKCON") { if (_cache.Exists($"{pid}_{busiType}")) { return _cache.Get($"{pid}_{busiType}"); } return null; } #region 发送马士基订舱请求 /// /// 发送马士基订舱请求 /// /// 请求订舱详情 /// [HttpPost("/BookingMSKAPI/SendMSKBooking")] public async Task SendMSKBooking(MSKBookingDto model) { MSKBookingResultDto result = await InnerSendMSKBooking(model, 0); return result; } #endregion #region 发送马士基订舱请求(内部方法) /// /// 发送马士基订舱请求(内部方法) /// /// 请求订舱详情 /// 当前马士基订舱主键 /// 是否默认保存 /// private async Task InnerSendMSKBooking(MSKBookingDto 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); BookingDeliveryRecordShipSchedule shipScheduleRecord = null; MSKAPISearchTransportSchedules selectedShipSchedule = 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().Filter(null, true) .FirstAsync(a => a.RECORD_ID == recordId && a.SHIP_RATE_PID != null && a.SHIP_RATE_PID.Value == model.PId && a.IsDeleted == false && a.TenantId == UserManager.TENANT_ID); } if (shipScheduleRecord == null) { selectedShipSchedule = GetCacheShipSailingSchedule(model.PId); } else { selectedShipSchedule = JSON.Deserialize(shipScheduleRecord.SHIP_JSON); } if (selectedShipSchedule == null) throw Oops.Oh("船期数据校验失败,请重新查询船期信息"); } 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_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 }, }; bookingDto.bookingBody.transport = new MSKAPIBookingTransport { carrierCode = model.carrierCode, earliestDepartureDate = model.earliestDepartureDate.Value.ToString("yyyy-MM-ddTHH:mm:ss"), exportServiceMode = model.exportServiceMode, importServiceMode = model.importServiceMode, routeDetails = new MSKAPIBookingRouteDetails { placeOfReceipt = new MSKAPIBookingRouteDetailsBase { UNLocationCode = model.userPlaceOfReceiptUnLocCode, maerskCityGeoId = selectedShipSchedule.originGeoId, }, placeOfDelivery = new MSKAPIBookingRouteDetailsBase { UNLocationCode = model.userPlaceOfDeliveryUnLocCode, maerskCityGeoId = selectedShipSchedule.destinationGeoId, }, selectedRoute = new MSKAPIBookingRoute { bookingSchedules = new List(), }, } }; //ETD if (selectedShipSchedule.departureDateTime.HasValue) { bookingDto.bookingBody.transport.earliestDepartureDate = selectedShipSchedule.departureDateTime.Value.ToString("yyyy-MM-ddTHH:mm:ss"); } else { throw Oops.Bah($"查询船期错误,pid={model.PId} 预计离港日期departureDate 格式解析错误"); } for (int i = 0; i < selectedShipSchedule.transportLegs.Count; i++) { var detail = selectedShipSchedule.transportLegs[i]; var currDto = new MSKAPIBookingSchedules(); //ETD if (detail.departureDateTime.HasValue) { currDto.originDepartureDateTimeLocal = detail.departureDateTime.Value.ToString("yyyy-MM-ddTHH:mm:ss"); } else { throw Oops.Bah($"查询船期错误,pid={model.PId} 预计离港日期departureDate 格式解析错误"); } //ETA if (detail.arrivalDateTime.HasValue) { currDto.destinationArrivalDateTimeLocal = detail.arrivalDateTime.Value.ToString("yyyy-MM-ddTHH:mm:ss"); } else { throw Oops.Bah($"查询船期错误,pid={model.PId} 预计到港日期arrivalDateTime 格式解析错误"); } if(detail.transport.vessel != null) { currDto.transportMode = new MSKAPIBookingTransportMode { vessel = new MSKAPIBookingTransportModeVessel { name = detail.transport.vessel.vesselName, maerskVesselCode = detail.transport.vessel.carrierVesselCode, vesselIMONumber = detail.transport.vessel.vesselIMONumber }, exportVoyageNumber = detail.transport.carrierDepartureVoyageNumber, }; } currDto.serviceCode = detail.transport.carrierServiceCode; currDto.transportModeCode = detail.transport.transportMode; //首个 if (i == 0) { currDto.startLocation = new MSKAPIBookingRouteDetailsBase { cityName = detail.facilities.startLocation.cityName, ISOcountryCode = detail.facilities.startLocation.countryCode, UNLocationCode = detail.facilities.startLocation.UNLocationCode, maerskCityGeoId = selectedShipSchedule.originGeoId, }; if (i == selectedShipSchedule.transportLegs.Count - 1) { currDto.endLocation = new MSKAPIBookingRouteDetailsBase { cityName = detail.facilities.endLocation.cityName, ISOcountryCode = detail.facilities.endLocation.countryCode, UNLocationCode = detail.facilities.endLocation.UNLocationCode, maerskCityGeoId = selectedShipSchedule.destinationGeoId, }; } else { currDto.endLocation = new MSKAPIBookingRouteDetailsBase { cityName = detail.facilities.endLocation.cityName, ISOcountryCode = detail.facilities.endLocation.countryCode, UNLocationCode = detail.facilities.endLocation.UNLocationCode, maerskSiteGeoId = detail.facilities.endLocation.carrierSiteGeoID, }; } } else if (i == selectedShipSchedule.transportLegs.Count - 1) { currDto.startLocation = new MSKAPIBookingRouteDetailsBase { cityName = detail.facilities.startLocation.cityName, ISOcountryCode = detail.facilities.startLocation.countryCode, UNLocationCode = detail.facilities.startLocation.UNLocationCode, maerskSiteGeoId = detail.facilities.startLocation.carrierSiteGeoID, }; currDto.endLocation = new MSKAPIBookingRouteDetailsBase { cityName = detail.facilities.endLocation.cityName, ISOcountryCode = detail.facilities.endLocation.countryCode, UNLocationCode = detail.facilities.endLocation.UNLocationCode, maerskCityGeoId = selectedShipSchedule.destinationGeoId, }; } else { currDto.startLocation = new MSKAPIBookingRouteDetailsBase { cityName = detail.facilities.startLocation.cityName, ISOcountryCode = detail.facilities.startLocation.countryCode, UNLocationCode = detail.facilities.startLocation.UNLocationCode, maerskSiteGeoId = detail.facilities.startLocation.carrierSiteGeoID, }; currDto.endLocation = new MSKAPIBookingRouteDetailsBase { cityName = detail.facilities.endLocation.cityName, ISOcountryCode = detail.facilities.endLocation.countryCode, UNLocationCode = detail.facilities.endLocation.UNLocationCode, maerskSiteGeoId = detail.facilities.endLocation.carrierSiteGeoID, }; } 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(); 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); }); } long id = 0; if (isDefaultSave) { id = InnerSave(model, isSendApi: true).GetAwaiter().GetResult(); } else { id = currId; } result.id = id; MSKAPIBookingResultDto resultInfo = null; var jsonBody = Newtonsoft.Json.JsonConvert.SerializeObject(bookingDto); _logger.LogInformation($"开始请求MSK API订舱,JSON={jsonBody}"); DateTime sendTime = DateTime.Now; 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.AsQueryable().Filter(null,true) .First(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 = "发送成功"; entity.SEND_TIME = sendTime; await _bookingDeliveryRecordRep.AsUpdateable(entity).UpdateColumns(x => new { x.REQUEST_ACKNOWLEDGEMENT_ID, x.BOOKING_REFERENCE, x.STATUS, x.STATUS_NAME, x.SEND_TIME }).ExecuteCommandAsync(); } else { entity.STATUS = "FAILURE"; entity.STATUS_NAME = "发送失败"; entity.NOTES = resultInfo.msg.Length > 500 ? resultInfo.msg.Substring(0, 500) : resultInfo.msg; entity.SEND_TIME = sendTime; await _bookingDeliveryRecordRep.AsUpdateable(entity).UpdateColumns(x => new { x.STATUS, x.STATUS_NAME, x.NOTES, x.SEND_TIME }).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订舱必填项 /// /// 校验马士基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.priceOwnerCompanyName)) 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($"箱内重量合计不等于总重,请修改"); } if (!model.isBookingPartOwnPrice) { if (model.bookedByMaerskPartyCode.Equals(model.priceOwnerMaerskPartyCode)) { throw Oops.Bah($"当前订舱合同号是非订舱方合约,持约方不能和订舱方ID信息一样,请根据实际情况填写"); } if (model.bookedByCompanyName.Equals(model.priceOwnerCompanyName)) { throw Oops.Bah($"当前订舱合同号是非订舱方合约,持约方公司名称不能和订舱方公司名称信息一样,请根据实际情况填写"); } } else { if (!model.bookedByMaerskPartyCode.Equals(model.priceOwnerMaerskPartyCode)) { throw Oops.Bah($"当前订舱合同号是订舱方合约,持约方ID必需和订舱方ID信息一致,请根据实际情况填写"); } if (!model.bookedByCompanyName.Equals(model.priceOwnerCompanyName)) { 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); //菜单375504048771141=我的任务台账 List userlist = await _sysDataUserMenuService.GetDataScopeList(MenuConst.MenuMSKApi); bool isAdmin = false; if(userlist == null) { isAdmin = true; userlist = new List(); } else if (userlist != null && userlist.Count > 0) { userlist.Add(UserManager.UserId); userlist = userlist.Distinct().ToList(); } _logger.LogInformation("任务台账权限范围 {list}", userlist); var entities = await _bookingDeliveryRecordRep.AsQueryable() .Where(t => isAdmin || userlist.Contains(t.CreatedUserId.Value)) .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.TotalAmountStart), t => t.SHIP_RATE_TOTAL_AMOUNT != null && t.SHIP_RATE_TOTAL_AMOUNT.Value >= decimal.Parse(QuerySearch.TotalAmountStart)) .WhereIF(!string.IsNullOrWhiteSpace(QuerySearch.TotalAmountEnd), t => t.SHIP_RATE_TOTAL_AMOUNT != null && t.SHIP_RATE_TOTAL_AMOUNT.Value <= decimal.Parse(QuerySearch.TotalAmountEnd)) .WhereIF(!string.IsNullOrWhiteSpace(QuerySearch.BookingChannelType), t => t.BOOKING_CHANNEL_TYPE == QuerySearch.BookingChannelType) .WhereIF(!string.IsNullOrWhiteSpace(QuerySearch.TotalCurrency), t => t.SHIP_RATE_TOTAL_CURRENCY == QuerySearch.TotalCurrency) .WhereIF(!string.IsNullOrWhiteSpace(QuerySearch.Carrier), t => t.CARRIERID.Equals(QuerySearch.Carrier)) .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)) .WhereIF(!string.IsNullOrWhiteSpace(QuerySearch.BookingReference), t => t.BOOKING_REFERENCE.Contains(QuerySearch.BookingReference)) .WhereIF(!string.IsNullOrWhiteSpace(QuerySearch.BookingCreator), t => t.CreatedUserName.Contains(QuerySearch.BookingCreator) || t.UpdatedUserName.Contains(QuerySearch.BookingCreator)) .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().Filter(null,true) .FirstAsync(a => a.Id == id && a.TenantId == UserManager.TENANT_ID); if(entity == null) throw Oops.Oh($"获取马士基API订舱详情失败,不存在或已作废"); model = entity.Adapt(); var ctnList = _bookingDeliveryRecordCtnRep.AsQueryable().Filter(null, true) .Where(a => a.RECORD_ID == id && a.IsDeleted == false && a.TenantId == UserManager.TENANT_ID).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(); } MSKAPISearchTransportSchedules selectedShipSchedule = null; if (model.PId > 0) { var shipScheduleRecord = await _bookingDeliveryRecordShipScheduleRep.AsQueryable().Filter(null, true) .FirstAsync(a => a.SHIP_RATE_PID != null && a.SHIP_RATE_PID.Value == model.PId && a.TenantId == UserManager.TENANT_ID); if (shipScheduleRecord != null) { selectedShipSchedule = JSON.Deserialize(shipScheduleRecord.SHIP_JSON); if (selectedShipSchedule != null) { model.selectedShipScheduleShow = GetShipScheduleShow(selectedShipSchedule); } } } return model; } #endregion #region 保存 /// /// 保存 /// /// 请求订舱详情 /// 返回ID [HttpPost("/BookingMSKAPI/Save")] public async Task Save([FromBody] MSKBookingDto model) { return await InnerSave(model); } #endregion #region 保存内部方法 /// /// 保存内部方法 /// /// 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)}"); BookingDeliveryRecordShipSchedule shipScheduleRecord = null; MSKAPISearchTransportSchedules selectedShipSchedule = null; if (model.PId > 0) { if (model.id.HasValue && model.id.Value > 0) { var recordId = model.id.Value; shipScheduleRecord = await _bookingDeliveryRecordShipScheduleRep.AsQueryable().Filter(null, true) .FirstAsync(a => a.RECORD_ID == recordId && a.SHIP_RATE_PID != null && a.SHIP_RATE_PID.Value == model.PId && a.IsDeleted == false && a.TenantId == UserManager.TENANT_ID); } if (shipScheduleRecord == null) { selectedShipSchedule = GetCacheShipSailingSchedule(model.PId); } else { selectedShipSchedule = JSON.Deserialize(shipScheduleRecord.SHIP_JSON); } if (selectedShipSchedule == null) throw Oops.Oh("船期数据校验失败,请重新查询船期信息"); model.placeOfReceiptCountryName = selectedShipSchedule.originCountryName; model.placeOfReceiptRegionName = selectedShipSchedule.originRegionName; model.carrierCollectionOriginGeoID = selectedShipSchedule.originGeoId; model.placeOfDeliveryCountryName = selectedShipSchedule.destinationCountryName; model.placeOfDeliveryRegionName = selectedShipSchedule.destinationRegionName; model.carrierDeliveryDestinationGeoID = selectedShipSchedule.destinationGeoId; } if (model.ctns != null && model.ctns.Count > 0) { ctnStat = string.Join(",", model.ctns.GroupBy(a => a.ctnName) .Select(a => $"{a.Key}*{a.ToList().Sum(b => b.ctnNum.HasValue ? b.ctnNum.Value : 0)}").ToArray()); } if (model.id.HasValue && model.id.Value > 0) { var oldInfo = _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; entity.BOOKING_CHANNEL_TYPE = "CON_API"; entity.BOOKING_CHANNEL_TYPE_NAME = "合约订舱"; 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, x.IS_JOB, x.JOB_TIME, x.TIMER_PLAN_ID, x.TIMER_PLAN_NAME }).ExecuteCommandAsync(); if (model.ctns != null && model.ctns.Count > 0) { var ctnEntityList = _bookingDeliveryRecordCtnRep.AsQueryable().Filter(null, true) .Where(a => a.RECORD_ID == entity.Id && a.IsDeleted == false && a.TenantId == UserManager.TENANT_ID).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, 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(); }); } } if (shipScheduleRecord == null) { if (model.PId > 0 && selectedShipSchedule != null) { shipScheduleRecord = new BookingDeliveryRecordShipSchedule { Id = YitIdHelper.NextId(), RECORD_ID = model.id.Value, SHIP_RATE_PID = selectedShipSchedule.PId, SHIP_RATE_MD5 = selectedShipSchedule.MD5, 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(); 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 = "CON_API"; entity.BOOKING_CHANNEL_TYPE_NAME = "合约订舱"; 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); }); } if (shipScheduleRecord == null) { if (model.PId > 0 && selectedShipSchedule != null) { shipScheduleRecord = new BookingDeliveryRecordShipSchedule { Id = YitIdHelper.NextId(), RECORD_ID = entity.Id, SHIP_RATE_PID = selectedShipSchedule.PId, SHIP_RATE_MD5 = selectedShipSchedule.MD5, 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 CON 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, SHIP_RATE_PID = selectedShipSchedule.PId, SHIP_RATE_MD5 = selectedShipSchedule.MD5, 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 CON id={model.id} 船期没变化 model.PId={model.PId} shipScheduleRecord.SHIP_RATE_PID={shipScheduleRecord.SHIP_RATE_PID.Value}"); } } return entity.Id; } } #endregion #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 #region 批量发送 /// /// 批量发送 /// /// 马士基API订舱ID组 /// 返回执行结果消息 [HttpPost("/BookingMSKAPI/BatchSend")] public async Task 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 msgList = new List(); 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++; } Thread.Sleep(1000); }); 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 批量复制 /// /// 批量复制 /// /// 马士基API批量复制指定数据 /// 返回执行结果消息 [HttpPost("/BookingMSKAPI/BatchCopy")] public async Task BatchCopy(MSKAPIBookingCopyDto 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 shipScheduleRecord = await _bookingDeliveryRecordShipScheduleRep.AsQueryable() .FirstAsync(a => a.RECORD_ID == model.originalId && a.SHIP_RATE_PID != null && a.SHIP_RATE_PID.Value == entity.SHIP_RATE_PID && a.IsDeleted == false); 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(); 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(); 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 = "CON_API"; entity.BOOKING_CHANNEL_TYPE_NAME = "合约订舱"; } int totalNum = 0; foreach (var a in numArg) { var copyEntity = entity.Adapt(); 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(); 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); }); } if (shipScheduleRecord != null) { var currShipScheduleRecord = shipScheduleRecord.Adapt(); currShipScheduleRecord.Id = 0; currShipScheduleRecord.RECORD_ID = copyEntity.Id; currShipScheduleRecord.CreatedTime = nowDate; currShipScheduleRecord.UpdatedTime = nowDate; currShipScheduleRecord.CreatedUserId = UserManager.UserId; currShipScheduleRecord.CreatedUserName = UserManager.Name; await _bookingDeliveryRecordShipScheduleRep.InsertAsync(currShipScheduleRecord); } } return JSON.Serialize(new { Total = totalNum }); } #endregion #region 同步BC状态(BC,Cancellation) /// /// 同步BC状态(BC,Cancellation) /// /// 提单号 /// 租户ID /// 操作类型 BC-同步BC状态 Cancellation-同步取消状态 /// 返回回执 [HttpGet("/BookingMSKAPI/SyncBCInfo")] public async Task 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 批量复制前调取校验预警 /// /// 批量复制前调取校验预警 /// /// 马士基API批量复制指定数据 /// 返回提示信息 [HttpPost("/BookingMSKAPI/CheckWarningBatchCopy")] public async Task CheckWarningBatchCopy(MSKAPIBookingCopyDto model) { /* 主要校验内容 1、如果待复制的单子里还有“托运人自己的集装箱”或“进口退货集装箱或者其他三角集运”需要做提醒是否继续复制。 2、如果是opType=copy_edit-复制使用提交的编辑信息,需要判断原始货物标志变化是否继续。 3、如果是冷冻处理的提示是否继续。 */ var entity = await _bookingDeliveryRecordRep.AsQueryable() .FirstAsync(a => a.Id == model.originalId); if (entity != null) { List msgList = new List(); 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前调取校验预警 /// /// 批量发送API前调取校验预警 /// /// 马士基API订舱ID组 /// 返回提示信息 [HttpPost("/BookingMSKAPI/CheckWarningBatchSend")] public async Task CheckWarningBatchSend([FromBody] long[] ids) { var list = await _bookingDeliveryRecordRep.AsQueryable().Where(a => ids.Contains(a.Id)).ToListAsync(); if (list.Count > 0) { List msgList = new List(); 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 获取初始化页面默认值 /// /// 获取初始化页面默认值 /// /// 返回详情 [HttpGet("/BookingMSKAPI/GetInitInfo")] public async Task GetInitInfo() { MSKSPOTBookingInitDto dto = null; var webAccountConfig = await _webAccountConfig.GetAccountConfigByTenantId("MSKApi", 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 { bookedByMaerskPartyCode = webAccountConfig.RegistPartyCode, bookedByCompanyName = webAccountConfig.RegistPartyName, priceOwnerMaerskPartyCode = webAccountConfig.RegistPartyCode, priceOwnerCompanyName = webAccountConfig.RegistPartyName, bookedByCompanyContactName = webAccountConfig.RegistContractName, bookedByCompanyContactEmail = webAccountConfig.RegistContractEmail, priceOwnerContactName = webAccountConfig.RegistContractName, priceOwnerContactEmail = webAccountConfig.RegistContractEmail, }; return dto; } #endregion #region 批量设定定时订舱时间 /// /// 批量设定定时订舱时间 /// /// 请求详情 /// 返回回执 [HttpPost("/BookingMSKAPI/BatchSetupTimerBooking")] public async Task BatchSetupTimerBooking([FromBody] MSKAPITimerBookingDto model) { /* 1、校验当前预订舱是否存在。 2、更新定时时间和设置。 3、判断当前定时是否已有记录,没有新增加定时。 4、 */ string result = string.Empty; var list = await _bookingDeliveryRecordRep.AsQueryable() .Where(a => model.ids.Contains(a.Id)).ToListAsync(); if (list.Count != model.ids.Length) throw Oops.Oh("订舱数据获取失败,请确认选中的记录是否存在"); StringBuilder msgBuilder = new StringBuilder(); foreach (var item in list) { var bookingOrder = GetInfo(item.Id).GetAwaiter().GetResult(); try { if (item.STATUS == "SUCC") { throw Oops.Bah($"当前状态是已发送成功,不能重复发送"); } ValidateMSKAPIData(bookingOrder); var runInfo = _bookingDeliveryRecordJobRunScheduleRep.AsQueryable().Filter(null, true) .First(a => a.RECORD_ID == item.Id && a.IsDeleted == false); if (runInfo != null) { throw Oops.Bah($"当前记录已开始定时发送不能修改"); } item.IS_JOB = true; DateTime jobTime = DateTime.MinValue; if (DateTime.TryParse(model.StartTime, out jobTime)) { item.JOB_TIME = jobTime; } item.TIMER_PLAN_ID = model.TimerSchemeType; item.TIMER_PLAN_NAME = string.Format(((MSKAPITimerSchemeTypeEnum)System.Enum.Parse(typeof(MSKAPITimerSchemeTypeEnum), model.TimerSchemeType)).GetDescription(), model.StartTime); item.UpdatedTime = DateTime.Now; item.UpdatedUserId = UserManager.UserId; item.UpdatedUserName = UserManager.Name; _bookingDeliveryRecordRep.AsUpdateable(item).UpdateColumns(x => new { x.IS_JOB, x.JOB_TIME, x.TIMER_PLAN_ID, x.TIMER_PLAN_NAME, x.UpdatedTime, x.UpdatedUserId, x.UpdatedUserName }).ExecuteCommand(); } catch (Exception ex) { msgBuilder.Append(ex.Message); } } var msg = msgBuilder.ToString(); if (!string.IsNullOrWhiteSpace(msg)) throw Oops.Oh(msg); return msg; } #endregion /// /// 获取定时订舱方案列表 /// /// [HttpGet("/BookingMSKAPI/GetTimerSchemeList")] public async Task> GetTimerSchemeList() { List list = new List(); list.Add(new MSKAPITimerSchemeDto { code = MSKAPITimerSchemeTypeEnum.SpecificTimeDoOnce.ToString(), name = MSKAPITimerSchemeTypeEnum.SpecificTimeDoOnce.GetDescription() }); return list; } #region 发送马士基订舱请求 /// /// 发送马士基订舱请求 /// /// 请求订舱ID /// 返回检索结果 [HttpGet("/BookingMSKAPI/SendMSKBookingById"), AllowAnonymous, ApiUser(ApiCode = "BCTaskManage")] public async Task SendMSKBookingById(long id) { var model = await GetInfo(id); if (model != null) { if (model.Status == "SUCC") { return new MSKBookingResultDto { succ = false, msg = "订舱数据已发送成功,不能重复发送" }; } return await InnerSendMSKBooking(model, id, false); } return new MSKBookingResultDto { succ = false, msg = "预订舱信息不存在" }; } #endregion #region 生成订舱报告邮件并自动转发 /// /// 生成订舱报告邮件并自动转发 /// /// [HttpGet("/BookingMSKAPI/GenerateTimerReportEmail")] public async Task GenerateTimerReportEmail() { DateTime nowDate = DateTime.Now; DateTime startDate = new DateTime(nowDate.Year, nowDate.Month, nowDate.Day); var runList = _bookingDeliveryRecordJobRunScheduleRep.AsQueryable().Filter(null, true) .Where(a => a.SEND_TIME >= startDate && a.IsDeleted == false && a.IS_SEND_REPORT == false).ToList(); if (runList.Count > 0) { var idList = runList.Select(a => a.RECORD_ID).ToList(); var orderList = _bookingDeliveryRecordRep.AsQueryable().Filter(null, true) .Where(a => a.IsDeleted == false && idList.Contains(a.Id)).ToList(); _logger.LogInformation($"获取相关预订舱记录,{string.Join(",", idList.ToArray())}"); orderList.GroupBy(a => a.CreatedUserId.Value).ToList().ForEach(b => { var nextJobTime = DateTime.MinValue; var waitList = _bookingDeliveryRecordRep.AsQueryable().Filter(null, true) .Where(a => a.IsDeleted == false && a.JOB_TIME != null && a.JOB_TIME.Value >= nowDate && a.CreatedUserId == b.Key && a.STATUS == "TEMP").OrderBy(a=>a.JOB_TIME.Value).ToList(); if (waitList.Count > 0) nextJobTime = waitList.FirstOrDefault().JOB_TIME.Value; _logger.LogInformation($"获取完待订舱的记录"); var opUser = _sysUserRepository.AsQueryable().Filter(null, true).First(a => a.Id == b.Key); DjyUserMailAccount publicMailAccount = _djyUserMailAccount.AsQueryable().Filter(null, true).First(x => x.TenantId == opUser.TenantId && x.ShowName == "PublicSend" && x.SmtpPort > 0 && x.SmtpServer != null && x.SmtpServer != ""); if (publicMailAccount == null) { _logger.LogInformation($"提取公共邮箱配置失败,请在用户邮箱账号管理增加配置显示名为PublicSend或者配置个人邮箱"); } _logger.LogInformation($"取完邮箱配置"); string emailHtml = string.Empty; var currList = b.OrderBy(t=> t.SEND_TIME.Value).ToList(); string templatePath = App.Configuration["EmailTemplateFilePath"]; var opt = App.GetOptions(); var dirAbs = opt.basePath; if (string.IsNullOrEmpty(dirAbs)) { dirAbs = App.WebHostEnvironment.WebRootPath; } templatePath = $"{dirAbs}{templatePath}\\MSKAPITimerReportTemplate.html"; _logger.LogInformation($"取完模板"); string baseHtml = File.ReadAllText(templatePath); baseHtml = baseHtml.Replace("#ReportTime#", nowDate.ToString("yyyy-MM-dd HH:mm:ss")); baseHtml = baseHtml.Replace("#total#", currList.Count.ToString()); baseHtml = baseHtml.Replace("#succ#", currList.Count(x=>x.STATUS == "SUCC").ToString()); baseHtml = baseHtml.Replace("#failure#", currList.Count(x => x.STATUS == "FAILURE").ToString()); if(waitList.Count > 0) { baseHtml = baseHtml.Replace("#wait#", currList.Count().ToString()); } else { baseHtml = baseHtml.Replace("#wait#", "0"); } if (nextJobTime != DateTime.MinValue) { baseHtml = baseHtml.Replace("#NextTime#", nextJobTime.ToString("yyyy-MM-dd HH:mm")); } else { baseHtml = baseHtml.Replace("#NextTime#", ""); } HtmlDocument html = new HtmlDocument(); html.LoadHtml(baseHtml); var tableNode = html.DocumentNode.SelectSingleNode(".//table[@id='show-table']"); if (tableNode != null) { for (int i = 0; i < currList.Count; i++) { StringBuilder tableBuilder = new StringBuilder(); tableBuilder.Append($"{i+1}{(currList[i].SEND_TIME.HasValue ? currList[i].SEND_TIME.Value.ToString("yyyy-MM-dd HH:mm:ss") : "")}"); tableBuilder.Append($"{currList[i].STATUS_NAME}{currList[i].BOOKING_REFERENCE}{currList[i].PLACERECEIPT_CITY}{currList[i].PLACEDELIVERY_CITY}"); tableBuilder.Append($"{currList[i].CTN_STAT}{(currList[i].ETD.HasValue ? currList[i].ETD.Value.ToString("yyyy-MM-dd HH:mm") : "")}"); tableBuilder.Append($"{(currList[i].TOTAL_CARGO_WEIGHT.HasValue? currList[i].TOTAL_CARGO_WEIGHT.Value.ToString():"")}{currList[i].PRICE_REFERENCE}"); tableBuilder.Append($"{(currList[i].IS_RECV_BC ? "1" : "")}{(currList[i].IS_RECV_BK_CANCEL ? "1" : "")}{(currList[i].JOB_TIME.HasValue ? currList[i].JOB_TIME.Value.ToString("yyyy-MM-dd HH:mm") : "")}"); tableNode.ChildNodes.Add(HtmlNode.CreateNode(tableBuilder.ToString())); } } emailHtml = html.DocumentNode.OuterHtml; _logger.LogInformation($"填充完邮件正文"); EmailApiUserDefinedDto emailApiUserDefinedDto = new EmailApiUserDefinedDto { SendTo = opUser.Email, CCTo = string.Join(";", App.Configuration["EmailNoticeDefaultUser"].GetUserEmailList().ToArray()), Title = $"马士基API定时订舱统计报告 {nowDate.ToString("yyyy-MM-dd HH:mm:ss")}", Body = emailHtml, Account = publicMailAccount.MailAccount?.Trim(), Password = publicMailAccount.Password?.Trim(), Server = publicMailAccount.SmtpServer?.Trim(), Port = publicMailAccount.SmtpPort.HasValue ? publicMailAccount.SmtpPort.Value : 465, UseSSL = publicMailAccount.SmtpSSL.HasValue ? publicMailAccount.SmtpSSL.Value : true, Attaches = new List() }; List emailList = new List(); var emailUrl = _cache.GetAllDictData().GetAwaiter().GetResult() .FirstOrDefault(x => x.TypeCode == "url_set" && x.Code == "email_api_url")?.Value; _logger.LogInformation($"获取完邮件API地址"); if (emailUrl == null) _logger.LogInformation("字典未配置 url_set->email_api_url 请联系管理员"); emailList.Add(emailApiUserDefinedDto); //string strJoin = System.IO.File.ReadAllText(filePath); DateTime bDate = DateTime.Now; HttpResponseMessage res = null; try { res = emailUrl.SetBody(emailList, "application/json").PostAsync().GetAwaiter().GetResult(); } catch (Exception ex) { _logger.LogInformation($"发送邮件异常:{ex.Message}"); } DateTime eDate = DateTime.Now; TimeSpan ts = eDate.Subtract(bDate); var timeDiff = ts.TotalMilliseconds; _logger.LogInformation($"发送邮件返回:{JSON.Serialize(res)}"); if (res != null && res.StatusCode == System.Net.HttpStatusCode.OK) { var userResult = res.Content.ReadAsStringAsync().GetAwaiter().GetResult(); var respObj = JsonConvert.DeserializeAnonymousType(userResult, new { Success = false, Message = string.Empty, Code = -9999, }); if(respObj.Success) { var updateList = currList.Join(runList, l => l.Id, r => r.RECORD_ID, (l, r) => { return r; }).ToList(); foreach (var update in updateList) { update.IS_SEND_REPORT = true; update.REPORT_TIME = DateTime.Now; _bookingDeliveryRecordJobRunScheduleRep.AsUpdateable(update).UpdateColumns(x => new { x.IS_SEND_REPORT, x.REPORT_TIME }).ExecuteCommand(); }; } } }); } else { _logger.LogInformation($"自动订舱报告失败,没有可执行的记录"); } return ""; } #endregion #region 批量取消定时订舱时间 /// /// 批量取消定时订舱时间 /// /// 马士基API订舱ID组 /// 返回回执 [HttpPost("/BookingMSKAPI/BatchCancelTimerBooking")] public async Task BatchCancelTimerBooking([FromBody] long[] ids) { string result = string.Empty; var list = await _bookingDeliveryRecordRep.AsQueryable() .Where(a => ids.Contains(a.Id)).ToListAsync(); if (list.Count != ids.Length) throw Oops.Oh("订舱数据获取失败,请确认选中的记录是否存在"); StringBuilder msgBuilder = new StringBuilder(); foreach (var item in list) { var bookingOrder = GetInfo(item.Id).GetAwaiter().GetResult(); try { if (item.STATUS == "SUCC") { throw Oops.Bah($"当前状态是已发送成功,不能取消"); } var runInfo = _bookingDeliveryRecordJobRunScheduleRep.AsQueryable().Filter(null, true) .First(a => a.RECORD_ID == item.Id && a.IsDeleted == false); if (runInfo != null) { throw Oops.Bah($"当前记录已开始定时发送不能修改"); } item.IS_JOB = false; item.JOB_TIME = null; item.TIMER_PLAN_ID = null; item.TIMER_PLAN_NAME = null; item.UpdatedTime = DateTime.Now; item.UpdatedUserId = UserManager.UserId; item.UpdatedUserName = UserManager.Name; _bookingDeliveryRecordRep.AsUpdateable(item).UpdateColumns(x => new { x.IS_JOB, x.JOB_TIME, x.TIMER_PLAN_ID, x.TIMER_PLAN_NAME, x.UpdatedTime, x.UpdatedUserId, x.UpdatedUserName }).ExecuteCommand(); } catch (Exception ex) { msgBuilder.Append(ex.Message); } } var msg = msgBuilder.ToString(); if(!string.IsNullOrWhiteSpace(msg)) throw Oops.Oh(msg); return msg; } #endregion } }