jianghaiqing 6 months ago
commit d99835386d

@ -0,0 +1,785 @@
using Furion;
using Furion.Logging;
using Furion.RemoteRequest.Extensions;
using Myshipping.Application.Entity;
using Myshipping.Core;
using Myshipping.Core.Entity;
using Myshipping.Core.Service;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics.Metrics;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace Myshipping.Application.EDI
{
/// <summary>
/// EMCAPI订舱
/// </summary>
public static class EMCSoApiHelper
{
public async static Task<KeyValuePair<bool, string>> DoPost(long custOrderId)
{
var repCustOrder = App.GetService<SqlSugarRepository<BookingCustomerOrder>>();
var repOrder = App.GetService<SqlSugarRepository<BookingOrder>>();
var repCtn = App.GetService<SqlSugarRepository<BookingCtn>>();
var repCustomer = App.GetService<SqlSugarRepository<DjyCustomer>>();
var repContact = App.GetService<SqlSugarRepository<DjyCustomerContact>>();
var repTemplate = App.GetService<SqlSugarRepository<BookingSoTemplate>>();
var cache = App.GetService<ISysCacheService>();
var cacheService = App.GetService<ISysCacheService>();
//var order = await repOrder.AsQueryable().Filter(null, true).FirstAsync(o => o.Id == bookingId);
//if (order == null)
//{
// return new KeyValuePair<bool, string>(false, "订舱信息未找到");
//}
var custOrder = await repCustOrder.AsQueryable().Filter(null, true).FirstAsync(x => x.Id == custOrderId);
if (custOrder == null)
{
return new KeyValuePair<bool, string>(false, "客户订舱信息未找到");
}
var sysConfigList = await cache.GetAllSysConfig();
var sCfgSpiderUrl = sysConfigList.FirstOrDefault(x => x.Code == "EMCApiSpiderUrl" && x.GroupCode == "DJY_CONST");
if (sCfgSpiderUrl == null)
{
return new KeyValuePair<bool, string>(false, "EMC订舱API的爬虫URL地址未配置请联系管理员");
}
var sCfgUserKey = sysConfigList.FirstOrDefault(x => x.Code == "EMCApiSpiderKey" && x.GroupCode == "DJY_CONST");
var sCfgUserSecret = sysConfigList.FirstOrDefault(x => x.Code == "EMCApiSpiderSecret" && x.GroupCode == "DJY_CONST");
if (sCfgUserKey == null || sCfgUserSecret == null)
{
return new KeyValuePair<bool, string>(false, "EMC订舱API的KEY和密钥未配置请联系管理员");
}
BookingSoTemplate template = null;
DjyCustomerContact custContact = null;
var postModel = new EMCSoApiModel();
JObject extObj = null;
if (!string.IsNullOrEmpty(custOrder.ExtendData))
{
extObj = JObject.Parse(custOrder.ExtendData);
postModel.webAccount = extObj.GetStringValue("Account");
postModel.webPassword = extObj.GetStringValue("Password");
}
else
{
return new KeyValuePair<bool, string>(false, "未找到订舱账号信息");
}
//查找模板:
//1.根据客户订舱信息中的BookingUserId和BookingTenantId去客户信息中根据CustSysId查找客户公司及联系人员工信息
//2.根据找到的客户及联系人信息查找EMC订舱模板
if (custOrder.BookingUserId > 0 && custOrder.BookingTenantId > 0)
{
custContact = await repCustomer.AsQueryable().Filter(null, true)
.InnerJoin<DjyCustomerContact>((cust, contact) => cust.Id == contact.CustomerId)
.Where((cust, contact) => cust.CustSysId == custOrder.BookingTenantId && contact.CustSysId == custOrder.BookingUserId)
.Select((cust, contact) => contact)
.SingleAsync();
if (custContact == null)
{
return new KeyValuePair<bool, string>(false, "未找到客户及联系人信息");
}
//根据:用户+船司+船司账号+约号,找到启用的模板
template = await repTemplate.AsQueryable().Filter(null, true).FirstAsync(x => x.CarrierId == custOrder.CARRIERID && x.UserId == custContact.Id && x.ContractNO == custOrder.CONTRACTNO && x.BookingAccount == postModel.webAccount && x.IsEnable);
if (template == null)
{
return new KeyValuePair<bool, string>(false, "未找到订舱模板");
}
}
else
{
return new KeyValuePair<bool, string>(false, "未找到客户端公司和用户ID");
}
var mappingCtn = await cache.GetAllMappingCtn();
var mappingFrt = await cache.GetAllMappingFrt();
var mappingPortLoad = await cache.GetAllMappingPortLoad();
var mappingPort = await cache.GetAllMappingPort();
postModel.userKey = sCfgUserKey.Value;
postModel.userSecret = sCfgUserSecret.Value;
postModel.uploadType = template.Category; //DRAFT, TEMPLATE, BOOKING分别对应草稿, 模板, 订舱
//起运港
var mapPortLoad = mappingPortLoad.FirstOrDefault(x => x.Module == "DjyCustBooking" && x.CarrierCode == "EMC" && x.Code == custOrder.PORTLOADCODE);
if (mapPortLoad == null)
{
return new KeyValuePair<bool, string>(false, $"未找到起运港映射信息:{custOrder.PORTLOADCODE}");
}
//目的地
var mapPort = mappingPort.FirstOrDefault(x => x.Module == "DjyCustBooking" && x.CarrierCode == "EMC" && x.Code == custOrder.DESTINATIONCODE);
if (mapPort == null)
{
return new KeyValuePair<bool, string>(false, $"未找到目的地映射信息:{custOrder.DESTINATIONCODE}");
}
////运输条款
//var mappingService = await cacheService.GetAllMappingService();
//var mappService = mappingService.FirstOrDefault(x => x.Module == "DjyCustBooking" && x.CarrierCode == "EMC" && x.Code == custOrder.SERVICE);
//if (mappService == null)
//{
// return new KeyValuePair<bool, string>(false, $"未找到运输条款映射信息:{custOrder.SERVICE}");
//}
//if (!Regex.IsMatch(mappService.MapCode, "^[A-Za-z]+-[A-Za-z]+$"))
//{
// return new KeyValuePair<bool, string>(false, $"映射配置不正确:{mappService.MapCode}");
//}
//var mapServArr = mappService.MapCode.Split('-');
var startDay = template.StartDay.HasValue ? template.StartDay.Value : 1;
var endWeek = template.EndWeek.HasValue ? template.EndWeek.Value : 2;
postModel.routes = new EMCSoApiRoute()
{
searchConditionDate = custOrder.ETD.Value.AddDays(startDay).ToString("yyyy-MM-dd"),
originName = mapPortLoad.MapCode,
destinationName = mapPort.MapCode,
polPortName = extObj?.GetStringValue("PolPortName"),
podPortName = extObj?.GetStringValue("PodPortName"),
serviceType = extObj?.GetStringValue("YSFS"),
serviceMode = extObj?.GetStringValue("YSXT"),
};
//货物信息(箱信息)
var ctns = await repCtn.AsQueryable().Filter(null, true).Where(x => x.BILLID == custOrder.Id).ToListAsync();
postModel.cargoInfos = new List<EMCSoApiCargoInfo>();
foreach (var ctn in ctns)
{
if (!ctn.CTNNUM.HasValue || !ctn.KGS.HasValue)
{
return new KeyValuePair<bool, string>(false, $"所有箱的箱量和毛重都不能为空");
}
var mapCtn = mappingCtn.FirstOrDefault(x => x.Module == "DjyCustBooking" && x.CarrierCode == "EMC" && x.Code == ctn.CTNCODE);
if (mapCtn == null)
{
return new KeyValuePair<bool, string>(false, $"未找箱型映射信息:{ctn.CTNCODE}");
}
var apiBox = new EMCSoApiCargoInfo()
{
containerType = mapCtn.MapCode,
containerQuantity = ctn.CTNNUM.Value,
containerWeight = ctn.KGS.Value,
containerWeightUnit = "KGS",
number = ctn.PKGS,
packageUnit = ctn.KINDPKGS,
measurements = ctn.CBM,
measurementUnit = "CBM"
};
postModel.cargoInfos.Add(apiBox);
}
#region 收发通及货代
var telCountryCode = "";
var telAreaCode = "";
var telNumber = "";
//发货人
if (string.IsNullOrEmpty(template.ShipperName))
{
telCountryCode = custOrder.ShipperPhoneCountryCode;
telAreaCode = custOrder.ShipperPhoneCode;
telNumber = custOrder.ShipperPhone;
}
else
{
telCountryCode = template.ShipperPhoneCountryCode;
telAreaCode = template.ShipperPhoneCode;
telNumber = template.ShipperPhone;
}
postModel.shipperInfo = new EMCSoApiSFTInfo()
{
companyName = "",
contactTitle = "",
contactLName = string.IsNullOrEmpty(template.ShipperName) ? custOrder.ShipperFirstName : template.ShipperFirstName,
contactFName = string.IsNullOrEmpty(template.ShipperLastName) ? custOrder.ShipperLastName : template.ShipperLastName,
tel1 = telCountryCode,
tel2 = telAreaCode,
tel3 = telNumber,
};
//收货人
if (string.IsNullOrEmpty(template.ConsigneeName))
{
telCountryCode = custOrder.ConsigneePhoneCountryCode;
telAreaCode = custOrder.ConsigneePhoneCode;
telNumber = custOrder.ConsigneePhone;
}
else
{
telCountryCode = template.ConsigneePhoneCountryCode;
telAreaCode = template.ConsigneePhoneCode;
telNumber = template.ConsigneePhone;
}
postModel.consigneeInfo = new EMCSoApiSFTInfo()
{
companyName = "",
contactTitle = "",
contactLName = string.IsNullOrEmpty(template.ConsigneeFirstName) ? custOrder.ConsigneeFirstName : template.ConsigneeFirstName,
contactFName = string.IsNullOrEmpty(template.ConsigneeLastName) ? custOrder.ConsigneeLastName : template.ConsigneeLastName,
tel1 = telCountryCode,
tel2 = telAreaCode,
tel3 = telNumber,
};
//通知人
if (string.IsNullOrEmpty(template.NotifypartName))
{
telCountryCode = custOrder.NotifypartPhoneCountryCode;
telAreaCode = custOrder.NotifypartPhoneCode;
telNumber = custOrder.NotifypartPhone;
}
else
{
telCountryCode = template.NotifypartPhoneCountryCode;
telAreaCode = template.NotifypartPhoneCode;
telNumber = template.NotifypartPhone;
}
postModel.notifyInfo = new EMCSoApiSFTInfo()
{
companyName = "",
contactTitle = "",
contactLName = string.IsNullOrEmpty(template.NotifypartFirstName) ? custOrder.NotifypartFirstName : template.NotifypartFirstName,
contactFName = string.IsNullOrEmpty(template.NotifypartLastName) ? custOrder.NotifypartLastName : template.NotifypartLastName,
tel1 = telCountryCode,
tel2 = telAreaCode,
tel3 = telNumber,
};
//货代
if (string.IsNullOrEmpty(template.BookingName))
{
telCountryCode = custOrder.BookingPhoneCountryCode;
telAreaCode = custOrder.BookingPhoneCode;
telNumber = custOrder.BookingPhone;
}
else
{
telCountryCode = template.BookingPhoneCountryCode;
telAreaCode = template.BookingPhoneCode;
telNumber = template.BookingPhone;
}
postModel.forwarderInfo = new EMCSoApiSFTInfo()
{
companyName = "",
contactTitle = "",
contactLName = string.IsNullOrEmpty(template.BookingFirstName) ? custOrder.BookingFirstName : template.BookingFirstName,
contactFName = string.IsNullOrEmpty(template.BookingLastName) ? custOrder.BookingLastName : template.BookingLastName,
tel1 = telCountryCode,
tel2 = telAreaCode,
tel3 = telNumber,
};
#endregion
////大简云客户订舱接收BC邮箱
//var djyBookMail = sysConfigList.FirstOrDefault(x => x.Code == "DjyCustomerBookReceiveBcMail");
//var bcMail = custContact.Email;
//if (extObj != null) //优先使用东胜上传的邮箱
//{
// var opMail = extObj.GetStringValue("OpMail");
// if (!string.IsNullOrEmpty(opMail))
// {
// bcMail = opMail;
// }
//}
//if (djyBookMail != null)
//{
// bcMail += ";" + djyBookMail.Value;
//}
//postModel.special = new EMCSoApiSpecial()
//{
// emailAddresses = bcMail,
// remarksForEntireBooking = custOrder.SOREMARK
//};
Log.Information($"发送API数据给爬虫{sCfgSpiderUrl.Value}{postModel.ToJsonString()}");
var rtn = await sCfgSpiderUrl.Value.SetBody(postModel)
.PostAsStringAsync();
Log.Information($"爬虫返回:{rtn}");
var jobjRtn = JObject.Parse(rtn);
if (jobjRtn.GetIntValue("code") == 200)
{
return new KeyValuePair<bool, string>(true, "发送成功");
}
else
{
return new KeyValuePair<bool, string>(false, jobjRtn.GetStringValue("msg"));
}
}
}
/// <summary>
/// EMCAPI订舱传输对象
/// </summary>
public class EMCSoApiModel
{
/// <summary>
/// 用户key
/// </summary>
public string userKey { get; set; }
/// <summary>
/// 用户secret
/// </summary>
public string userSecret { get; set; }
/// <summary>
/// 网站账户
/// </summary>
public string webAccount { get; set; }
/// <summary>
/// 网站密码
/// </summary>
public string webPassword { get; set; }
/// <summary>
/// 上传类型
/// </summary>
public string uploadType { get; set; }
/// <summary>
/// 路线信息
/// </summary>
public EMCSoApiRoute routes { get; set; }
/// <summary>
/// 货物信息
/// </summary>
public List<EMCSoApiCargoInfo> cargoInfos { get; set; }
/// <summary>
/// 合约信息
/// </summary>
public EMCSoApiContractInfo contractInfo { get; set; }
/// <summary>
/// 船期数据
/// </summary>
public EMCSoApiShipInfo shipInfo { get; set; }
/// <summary>
/// 订舱公司详情
/// </summary>
public EMCSoApiCompanyInfo companyInfo { get; set; }
/// <summary>
/// 发货人
/// </summary>
public EMCSoApiSFTInfo shipperInfo { get; set; }
/// <summary>
/// 货代信息
/// </summary>
public EMCSoApiSFTInfo forwarderInfo { get; set; }
/// <summary>
/// 收货人信息
/// </summary>
public EMCSoApiSFTInfo consigneeInfo { get; set; }
/// <summary>
/// 通知人信息
/// </summary>
public EMCSoApiSFTInfo notifyInfo { get; set; }
/// <summary>
/// 已进场货柜均可装船
/// Y, N
/// </summary>
public string partialLoad { get; set; } = "Y";
/// <summary>
/// 复制的单数
/// </summary>
public int copyNum { get; set; }
/// <summary>
/// 是否同意: 在此提醒您,网络订舱需求仅为要约,本公司保留更新及修改权利,并以正式回复之"订舱确认通知"为准
/// </summary>
public bool isAgree { get; set; }
/// <summary>
/// 备注信息
/// </summary>
public string remark { get; set; }
}
/// <summary>
/// 路线信息
/// </summary>
public class EMCSoApiRoute
{
/// <summary>
/// 查询日期
/// </summary>
public string searchConditionDate { get; set; }
/// <summary>
/// 收货地, 去网站上应一致
/// </summary>
public string originName { get; set; }
/// <summary>
/// 交货地
/// </summary>
public string destinationName { get; set; }
/// <summary>
/// 装货港
/// </summary>
public string polPortName { get; set; }
/// <summary>
/// 卸货港
/// </summary>
public string podPortName { get; set; }
/// <summary>
/// 运送方式
/// </summary>
public string serviceType { get; set; }
/// <summary>
/// 运送形态
/// </summary>
public string serviceMode { get; set; }
}
/// <summary>
/// 货物信息
/// </summary>
public class EMCSoApiCargoInfo
{
/// <summary>
/// 箱量
/// </summary>
public int? containerQuantity { get; set; } = 1;
/// <summary>
/// 箱型, 注意当isReefer为Y时, 应选择冻柜的数据
/// </summary>
public string containerType { get; set; }
/// <summary>
/// 称重方式 E: 每个, T: 总和
/// </summary>
public string containerWeightMode { get; set; }
/// <summary>
/// 重量 最多两位小数
/// </summary>
public decimal? containerWeight { get; set; }
/// <summary>
/// 重量单位 KGS, LBS
/// </summary>
public string containerWeightUnit { get; set; } = "KGS";
/// <summary>
/// 品名
/// </summary>
public string commodityName { get; set; }
/// <summary>
/// Harmonized Tariff Schedule Code
/// </summary>
public string htCode { get; set; }
/// <summary>
/// 件数
/// </summary>
public int? number { get; set; }
/// <summary>
/// 包装单位
/// </summary>
public string packageUnit { get; set; }
/// <summary>
/// 体积
/// </summary>
public decimal? measurements { get; set; }
/// <summary>
/// 体积单位
/// </summary>
public string measurementUnit { get; set; } = "CBM";
/// <summary>
/// 特殊要求
/// </summary>
public string handling { get; set; }
}
/// <summary>
/// 合约信息
/// </summary>
public class EMCSoApiContractInfo
{
/// <summary>
/// 合约方案选择
/// 当合约类型为SC时, 这个参数生效,且合约号生效, 默认SC
/// SC, HT, LT, SQ, RS, HV, LM, HM, TV, LV, EM
/// </summary>
public string contractSelect { get; set; } = "SC";
/// <summary>
/// 合约类型
/// 当类型为TR时,合约号不生效
/// SC, TR
/// </summary>
public string contractType { get; set; }
/// <summary>
/// 合约号
/// </summary>
public string contractNo { get; set; }
/// <summary>
/// 签约方
/// Shipper, Forwarder, Consignee, Notify Party
/// </summary>
public string contractParty { get; set; }
/// <summary>
/// 订舱网点
/// </summary>
public string bookingOffice { get; set; }
/// <summary>
/// 提单签发地
/// </summary>
public string issuePlace { get; set; }
/// <summary>
/// 付款方式
/// P, C
/// </summary>
public string paymentMethod { get; set; }
/// <summary>
/// 付款地点
/// </summary>
public string paymentPlace { get; set; }
/// <summary>
/// PO号码
/// </summary>
public string purchase { get; set; }
/// <summary>
/// 提单数量
/// </summary>
public int? billNum { get; set; } = 1;
}
/// <summary>
/// 船期数据
/// 船期查询的结果总选择的数据集, 原样上传
/// </summary>
public class EMCSoApiShipInfo
{
/// <summary>
/// 收货地
/// </summary>
public string originName { get; set; }
/// <summary>
/// 交货地
/// </summary>
public string destinationName { get; set; }
/// <summary>
/// 本地截止时间
/// </summary>
public string cutOffLocalDate { get; set; }
/// <summary>
/// 开航时间
/// </summary>
public string departureDate { get; set; }
/// <summary>
/// 航线代码
/// </summary>
public string serviceCode { get; set; }
/// <summary>
/// 船名
/// </summary>
public string vesselName { get; set; }
/// <summary>
/// 航次
/// </summary>
public string voyageNumber { get; set; }
/// <summary>
/// 下一段航线代码
/// </summary>
public string nextServiceCode { get; set; }
/// <summary>
/// 总航程
/// </summary>
public string estimatedTransitTimeInDays { get; set; }
/// <summary>
/// 详情参数, 订舱时需要原样上传
/// </summary>
public string paramsText { get; set; }
/// <summary>
/// 后续请求需要使用, 原样上传即可
/// </summary>
public string buttonText { get; set; }
/// <summary>
/// 航线详情
/// </summary>
public EMCSoApiShipInfoOceanLegs oceanLegs { get; set; }
}
/// <summary>
/// 航线详情
/// </summary>
public class EMCSoApiShipInfoOceanLegs
{
/// <summary>
/// 起运港
/// </summary>
public string polPortName { get; set; }
/// <summary>
/// 目的港
/// </summary>
public string podPortName { get; set; }
/// <summary>
/// ETD
/// </summary>
public string polETD { get; set; }
/// <summary>
/// ETA
/// </summary>
public string podETA { get; set; }
/// <summary>
/// 航线代码
/// </summary>
public string serviceCode { get; set; }
/// <summary>
/// 船名航线字符
/// </summary>
public string vesselAndVoyage { get; set; }
/// <summary>
/// 航程
/// </summary>
public string days { get; set; }
}
/// <summary>
/// 订舱公司详情
/// </summary>
public class EMCSoApiCompanyInfo
{
/// <summary>
/// 是否收取订舱通知
/// Yes, No
/// </summary>
public string receiveBookingNotice { get; set; }
/// <summary>
/// 内参号码
/// </summary>
public string referenceNO { get; set; }
}
/// <summary>
/// 收发通信息
/// </summary>
public class EMCSoApiSFTInfo
{
/// <summary>
/// 公司名称
/// </summary>
public string companyName { get; set; }
/// <summary>
/// 联系人性别
/// MS, MR
/// </summary>
public string contactTitle { get; set; }
/// <summary>
/// 姓
/// </summary>
public string contactFName { get; set; }
/// <summary>
/// 名
/// </summary>
public string contactLName { get; set; }
/// <summary>
/// 国家代码
/// </summary>
public string tel1 { get; set; }
/// <summary>
/// 地区代码
/// </summary>
public string tel2 { get; set; }
/// <summary>
/// 电话号码
/// </summary>
public string tel3 { get; set; }
/// <summary>
/// 分机号码
/// </summary>
public string tel4 { get; set; }
/// <summary>
/// 内参号码
/// </summary>
public string referenceNO { get; set; }
/// <summary>
/// 邮箱
/// </summary>
public string email { get; set; }
}
}

@ -0,0 +1,75 @@
using Furion.EventBus;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Myshipping.Application.Entity;
using Myshipping.Application.MQ;
using Myshipping.Core;
using Myshipping.Core.Entity;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Myshipping.Application.Event
{
/// <summary>
/// 订舱自动化事件处理
/// </summary>
public class BookingAutoSubscriber : IEventSubscriber
{
private IServiceProvider _services { get; }
private readonly ILogger<BookingAutoSubscriber> _logger;
public BookingAutoSubscriber(IServiceProvider services, ILogger<BookingAutoSubscriber> logger)
{
_services = services;
_logger = logger;
}
//收到BC
[EventSubscribe("BookingAuto:BC")]
public async Task BookingAutoBC(EventHandlerExecutingContext context)
{
_logger.LogInformation($"收到订舱自动化BC消息{context.Source.Payload}");
var msgBC = context.Source.Payload as BookingAutoMessageBC;
var scope = _services.CreateScope();
var repoBooking = scope.ServiceProvider.GetRequiredService<SqlSugarRepository<BookingOrder>>();
var repoStatuslog = scope.ServiceProvider.GetRequiredService<SqlSugarRepository<BookingStatusLog>>();
var bookingfile = scope.ServiceProvider.GetRequiredService<SqlSugarRepository<BookingFile>>();
var booking = await repoBooking.AsQueryable().Filter(null, true).FirstAsync(x => x.CUSTNO == msgBC.BookingNO && x.TenantId == msgBC.TenantId);
if (booking != null)
{
booking.MBLNO = msgBC.MBLNO; //回写提单号
await repoBooking.AsUpdateable(booking).UpdateColumns(x => new { x.MBLNO }).ExecuteCommandAsync();
//货运动态
var bsl = new BookingStatusLog();
bsl.BookingId = booking.Id;
bsl.Status = $"收到BC";
bsl.OpTime = DateTime.Now;
bsl.Category = "ship";
bsl.MBLNO = booking.MBLNO;
await repoStatuslog.InsertAsync(bsl);
//挂载附件
var newFile = new BookingFile
{
FileName = Path.GetFileName(msgBC.AttachUrl),
FilePath = msgBC.AttachUrl,
TypeCode = "BC",
TypeName = ".pdf",
BookingId = booking.Id,
};
await bookingfile.InsertAsync(newFile);
}
}
}
}

@ -0,0 +1,78 @@
using Myshipping.Core;
using Myshipping.Core.Entity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Myshipping.Application.Helper
{
public static class PlaceToPortHelper
{
public static async Task<CodePortLoad> PlaceReceiptToPortload(string portEnName, List<CodePortLoad> cachePortLoad, Func<Task<List<MappingPortLoad>>> cacheMapPortLoadFunc)
{
if (string.IsNullOrEmpty(portEnName))
{
return null;
}
// 匹配方式1精准匹配
var portInfo = cachePortLoad.FirstOrDefault(x => x.EnName.Equals(portEnName, StringComparison.OrdinalIgnoreCase));
if (portInfo != null) return portInfo;
// 匹配方式2起始模糊匹配
portInfo = cachePortLoad.FirstOrDefault(x => x.EnName.StartsWith(portEnName, StringComparison.OrdinalIgnoreCase));
if (portInfo != null) return portInfo;
// 匹配方式3完整模糊匹配
portInfo = cachePortLoad.FirstOrDefault(x => x.EnName.Contains(portEnName, StringComparison.OrdinalIgnoreCase));
if (portInfo != null) return portInfo;
// 匹配方式4精准映射匹配
var mapCachePortLoad = await cacheMapPortLoadFunc();
var map = mapCachePortLoad.FirstOrDefault(x => x.Module == CommonConst.RECEIPT_TO_PORTLOAD
&& x.MapName.Equals(portEnName, StringComparison.OrdinalIgnoreCase));
if (map != null)
{
portInfo = cachePortLoad.FirstOrDefault(x => x.Code == map.Code);
if (portInfo != null) return portInfo;
}
return null;
}
public static async Task<CodePort> PlaceDeliveryToPort(string portEnName, List<CodePort> cachePort, Func<Task<List<MappingPort>>> cacheMapPortFunc)
{
if (string.IsNullOrEmpty(portEnName))
{
return null;
}
// 匹配方式1精准匹配
var portInfo = cachePort.FirstOrDefault(x => x.EnName.Equals(portEnName, StringComparison.OrdinalIgnoreCase));
if (portInfo != null) return portInfo;
// 匹配方式2起始模糊匹配
portInfo = cachePort.FirstOrDefault(x => x.EnName.StartsWith(portEnName, StringComparison.OrdinalIgnoreCase));
if (portInfo != null) return portInfo;
// 匹配方式3完整模糊匹配
portInfo = cachePort.FirstOrDefault(x => x.EnName.Contains(portEnName, StringComparison.OrdinalIgnoreCase));
if (portInfo != null) return portInfo;
// 匹配方式4精准映射匹配
var mapCachePort = await cacheMapPortFunc();
var map = mapCachePort.FirstOrDefault(x => x.Module == CommonConst.DELIVERY_TO_PORT
&& x.MapName.Equals(portEnName, StringComparison.OrdinalIgnoreCase));
if (map != null)
{
portInfo = cachePort.FirstOrDefault(x => x.Code == map.Code);
if (portInfo != null) return portInfo;
}
return null;
}
}
}

@ -0,0 +1,148 @@
using Furion.EventBus;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Myshipping.Core.Entity;
using Myshipping.Core;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
namespace Myshipping.Application.MQ
{
public class BookingAutoService : BackgroundService
{
private readonly IServiceScopeFactory _scopeFactory;
private readonly IServiceScope _serviceScope;
private readonly ILogger<BookingAutoService> _logger;
private readonly IEventPublisher _publisher;
private IConnection mqConn;
private IModel model;
public BookingAutoService(IServiceScopeFactory scopeFactory)
{
_scopeFactory = scopeFactory;
//通过这个注入DBContext
_serviceScope = _scopeFactory.CreateScope();
_logger = _serviceScope.ServiceProvider.GetService<ILogger<BookingAutoService>>();
_publisher = _serviceScope.ServiceProvider.GetService<IEventPublisher>();
}
protected override Task ExecuteAsync(CancellationToken stoppingToken)
{
_logger.LogInformation("BookingAutoService ExecuteAsync");
return Task.Run(() =>
{
_logger.LogInformation("BookingAutoService ExecuteAsync RunTask");
//绑定队列
BindMQ();
});
}
private void BindMQ()
{
string ExchangeName = "djy.booking.auto";
string QueueName = $"djy.booking.auto.{DateTime.Now.Ticks}";
ConnectionFactory factory = new ConnectionFactory();
var repoSysCfg = _serviceScope.ServiceProvider.GetService<SqlSugarRepository<SysConfig>>();
var mqUrl = repoSysCfg.FirstOrDefault(x => x.Code == "DjyBookingAutoMQUrl")?.Value;
if (string.IsNullOrEmpty(mqUrl))
{
_logger.LogError($"接收订舱自动化消息推送所需MQUrl未配置");
}
else
{
_logger.LogInformation($"准备连接订舱自动化消息队列:{mqUrl}");
factory.Uri = new Uri(mqUrl);
mqConn = factory.CreateConnection("大简云订舱平台");
model = mqConn.CreateModel();
model.ExchangeDeclare(ExchangeName, ExchangeType.Topic);
model.QueueDeclare(QueueName, false, false, true, null);
model.QueueBind(QueueName, ExchangeName, "*", null);
var consumer = new EventingBasicConsumer(model);
consumer.Received += (obj, arg) =>
{
var body = arg.Body;
var strBody = Encoding.UTF8.GetString(body.ToArray());
_logger.LogInformation($"收到订舱自动化消息队列:{strBody}");
if (arg.RoutingKey == "BC") //收到BC
{
var dto = JsonConvert.DeserializeObject<BookingAutoMessageBC>(strBody);
_publisher.PublishAsync(new ChannelEventSource("BookingAuto:BC", dto));
}
else if (arg.RoutingKey == "DraftDownloadOk") //DRAFT下载完成
{
}
};
model.BasicConsume(QueueName, true, consumer);
}
}
public override void Dispose()
{
base.Dispose();
_serviceScope.Dispose();
if (mqConn != null && mqConn.IsOpen)
mqConn.Close();
_logger.LogInformation("BookingAutoService Dispose");
}
}
/// <summary>
/// BC消息对象
/// </summary>
public class BookingAutoMessageBC
{
/// <summary>
/// 租户ID
/// </summary>
public long TenantId { get; set; }
/// <summary>
/// 大简云公司ID
/// </summary>
public string CompanyId { get; set; }
/// <summary>
/// 船司
/// </summary>
public string Carrier { get; set; }
/// <summary>
/// 提单号
/// </summary>
public string MBLNO { get; set; }
/// <summary>
/// 订舱号
/// </summary>
public string BookingNO { get; set; }
/// <summary>
/// 链接地址
/// </summary>
public string Url { get; set; }
/// <summary>
/// 附件地址
/// </summary>
public string AttachUrl { get; set; }
}
}

@ -1650,7 +1650,7 @@ namespace Myshipping.Application
custOrder.DESCRIPTION = data.Rows[idx]["description of goods"].ToString();
var portLoadCode = data.Rows[idx]["POL"].ToString();
var portLoad = portLoadList.FirstOrDefault(x => x.Code == portLoadCode);
var portLoad = portLoadList.FirstOrDefault(x => x.Code == portLoadCode || x.EnName == portLoadCode);
if (portLoad == null)
{
errList.Add($"第{idx + 1}行,未找到起运港:{portLoadCode}");
@ -1663,7 +1663,7 @@ namespace Myshipping.Application
}
var portCode = data.Rows[idx]["卸货港"].ToString();
var portDest = portDestList.FirstOrDefault(x => x.Code == portCode);
var portDest = portDestList.FirstOrDefault(x => x.Code == portCode || x.EnName == portCode);
if (portLoad == null)
{
errList.Add($"第{idx + 1}行,未找到卸货港:{portCode}");
@ -1676,7 +1676,7 @@ namespace Myshipping.Application
}
var destina = data.Rows[idx]["交货地"].ToString();
var destinaFind = portDestList.FirstOrDefault(x => x.Code == destina);
var destinaFind = portDestList.FirstOrDefault(x => x.Code == destina || x.EnName == destina);
if (portLoad == null)
{
errList.Add($"第{idx + 1}行,未找到交货地:{destina}");
@ -1712,7 +1712,7 @@ namespace Myshipping.Application
var ctns = new List<BookingCtn>();
if (arrCtn.Length == 2)
{
var ctn = ctnList.FirstOrDefault(x => x.Code == arrCtn[0]);
var ctn = ctnList.FirstOrDefault(x => x.Code == arrCtn[0] || x.Name == arrCtn[0]);
if (ctn == null)
{
errList.Add($"第{idx + 1}行,未找到箱型:{arrCtn[0]}");

@ -629,13 +629,9 @@ namespace Myshipping.Application
var portEnName = dto.DataObj.PLACERECEIPT.Split(',')[0]?.Trim();
if (!string.IsNullOrWhiteSpace(portEnName))
{
var cachePort = await _cache.GetAllCodePort();
var cachePortLoad = await _cache.GetAllCodePortLoad();
var portInfo = await PlaceToPortHelper.PlaceReceiptToPortload(portEnName, cachePortLoad, () => _cache.GetAllMappingPortLoad());
var portInfo = cachePort.FirstOrDefault(x => x.EnName.StartsWith(portEnName, StringComparison.OrdinalIgnoreCase));
if (portInfo == null)
{
portInfo = cachePort.FirstOrDefault(x => x.EnName.Contains(portEnName, StringComparison.OrdinalIgnoreCase));
}
if (portInfo == null)
{
_logger.LogInformation("通过收货地城市名称未匹配到港口信息,订舱编号:{SLOT_BOOKING_NO}", dto.DataObj.SLOT_BOOKING_NO);
@ -662,11 +658,8 @@ namespace Myshipping.Application
if (!string.IsNullOrWhiteSpace(portEnName))
{
var cachePort = await _cache.GetAllCodePort();
var portInfo = cachePort.FirstOrDefault(x => x.EnName.StartsWith(portEnName + ',', StringComparison.OrdinalIgnoreCase));
if (portInfo == null)
{
portInfo = cachePort.FirstOrDefault(x => x.EnName.Contains(portEnName, StringComparison.OrdinalIgnoreCase));
}
var portInfo = await PlaceToPortHelper.PlaceDeliveryToPort(portEnName, cachePort, () => _cache.GetAllMappingPort());
if (portInfo == null)
{
@ -1146,6 +1139,7 @@ namespace Myshipping.Application
var list = await _repBase.AsQueryable().Filter(null, true)
.Where(x => x.TenantId == telentId
&& x.IsDeleted == false
&& x.IS_CANCELLATION == false
&& !string.IsNullOrEmpty(x.PLACERECEIPT)
&& !string.IsNullOrEmpty(x.PLACEDELIVERY)
&& (string.IsNullOrEmpty(x.PORTLOADID) || string.IsNullOrEmpty(x.PORTDISCHARGEID)))
@ -1169,9 +1163,10 @@ namespace Myshipping.Application
{
// 解析收货地,得到装货港名称及五字码
var portEnName = item.PLACERECEIPT.Split(',')[0]?.Trim();
if (!string.IsNullOrWhiteSpace(portEnName))
if (!string.IsNullOrWhiteSpace(portEnName)
&& (string.IsNullOrEmpty(item.PORTLOADID) || string.IsNullOrEmpty(item.PORTLOAD)))
{
var portInfo = cachePortLoad.FirstOrDefault(x => x.EnName.Equals(portEnName, StringComparison.OrdinalIgnoreCase));
var portInfo = await PlaceToPortHelper.PlaceReceiptToPortload(portEnName, cachePortLoad, () => _cache.GetAllMappingPortLoad());
if (portInfo != null)
{
if (string.IsNullOrEmpty(item.PORTLOADID))
@ -1195,12 +1190,13 @@ namespace Myshipping.Application
var portEnName2 = item.PLACEDELIVERY.Split(',')[0]?.Trim();
if (!string.IsNullOrWhiteSpace(portEnName2))
{
var portInfo = cachePort.FirstOrDefault(x => x.EnName.StartsWith(portEnName2, StringComparison.OrdinalIgnoreCase));
if (portInfo == null)
{
portInfo = cachePort.FirstOrDefault(x => x.EnName.Contains(portEnName2, StringComparison.OrdinalIgnoreCase));
}
if (portInfo != null)
var portInfo = await PlaceToPortHelper.PlaceDeliveryToPort(portEnName2, cachePort, () => _cache.GetAllMappingPort());
if (portInfo != null
&& (string.IsNullOrEmpty(item.PORTDISCHARGEID)
|| string.IsNullOrEmpty(item.PORTDISCHARGE)
|| string.IsNullOrEmpty(item.PORTDISCHARGE_COUNTRY_CODE)
|| string.IsNullOrEmpty(item.PORTDISCHARGE_COUNTRY)))
{
if (string.IsNullOrEmpty(item.PORTDISCHARGEID))
{
@ -1243,38 +1239,38 @@ namespace Myshipping.Application
x.PORTDISCHARGE_COUNTRY,
}).ExecuteCommandAsync();
var group = updateList.Where(x => !string.IsNullOrEmpty(x.VESSEL)
&& !string.IsNullOrEmpty(x.VOYNO)
&& !string.IsNullOrEmpty(x.CONTRACT_NO)
&& !string.IsNullOrEmpty(x.BOOKING_SLOT_TYPE)
&& !string.IsNullOrEmpty(x.CARRIERID)
&& !string.IsNullOrEmpty(x.PORTLOADID)
&& !string.IsNullOrEmpty(x.PORTDISCHARGEID))
.GroupBy(x => new
{
x.VESSEL,
x.VOYNO,
x.CARRIERID,
x.BOOKING_SLOT_TYPE,
x.PORTDISCHARGEID,
x.PORTLOADID,
x.CONTRACT_NO
}).ToList();
foreach (var item in group)
{
await _publisher.PublishAsync(new ChannelEventSource("BookingSlotStock:Update", new BookingSlotStockUpdateModel
{
BOOKING_SLOT_TYPE = item.Key.BOOKING_SLOT_TYPE,
CARRIERID = item.Key.CARRIERID,
CONTRACT_NO = item.Key.CONTRACT_NO,
VESSEL = item.Key.VESSEL,
VOYNO = item.Key.VOYNO,
PORTLOADID = item.Key.PORTLOADID,
PORTDISCHARGEID = item.Key.PORTDISCHARGEID,
TenantId = UserManager.TENANT_ID
}));
}
//var group = updateList.Where(x => !string.IsNullOrEmpty(x.VESSEL)
// && !string.IsNullOrEmpty(x.VOYNO)
// && !string.IsNullOrEmpty(x.CONTRACT_NO)
// && !string.IsNullOrEmpty(x.BOOKING_SLOT_TYPE)
// && !string.IsNullOrEmpty(x.CARRIERID)
// && !string.IsNullOrEmpty(x.PORTLOADID)
// && !string.IsNullOrEmpty(x.PORTDISCHARGEID))
// .GroupBy(x => new
// {
// x.VESSEL,
// x.VOYNO,
// x.CARRIERID,
// x.BOOKING_SLOT_TYPE,
// x.PORTDISCHARGEID,
// x.PORTLOADID,
// x.CONTRACT_NO
// }).ToList();
//foreach (var item in group)
//{
// await _publisher.PublishAsync(new ChannelEventSource("BookingSlotStock:Update", new BookingSlotStockUpdateModel
// {
// BOOKING_SLOT_TYPE = item.Key.BOOKING_SLOT_TYPE,
// CARRIERID = item.Key.CARRIERID,
// CONTRACT_NO = item.Key.CONTRACT_NO,
// VESSEL = item.Key.VESSEL,
// VOYNO = item.Key.VOYNO,
// PORTLOADID = item.Key.PORTLOADID,
// PORTDISCHARGEID = item.Key.PORTDISCHARGEID,
// TenantId = UserManager.TENANT_ID
// }));
//}
}
}
#endregion

@ -260,6 +260,17 @@ public class CommonConst
public const string CACHE_KEY_BOOKING_LABEL = "BookingLabelList";
#endregion
#region 映射模块
/// <summary>
/// 收货地名称解析装货港港口
/// </summary>
public const string RECEIPT_TO_PORTLOAD = "ReceiptToPortLoad";
/// <summary>
/// 交货地名称解析卸货港港口
/// </summary>
public const string DELIVERY_TO_PORT = "DeliveryToPort";
#endregion
#region 系统运行方式
/// <summary>

@ -822,6 +822,16 @@
标签缓存键
</summary>
</member>
<member name="F:Myshipping.Core.CommonConst.RECEIPT_TO_PORTLOAD">
<summary>
收货地名称解析装货港港口
</summary>
</member>
<member name="F:Myshipping.Core.CommonConst.DELIVERY_TO_PORT">
<summary>
交货地名称解析卸货港港口
</summary>
</member>
<member name="F:Myshipping.Core.CommonConst.RUN_TYPE_HECHUAN">
<summary>
和川(会执行一些和川特有的逻辑)
@ -7340,6 +7350,16 @@
用户Id
</summary>
</member>
<member name="P:Myshipping.Core.Service.GetAuthorizationKeyInput.Authority">
<summary>
权限范围
</summary>
</member>
<member name="P:Myshipping.Core.Service.GetAuthorizationKeyInput.AuthorityType">
<summary>
权限类型(1用户,2公司)
</summary>
</member>
<member name="T:Myshipping.Core.Service.GetTokenByAuthorizationKeyInput">
<summary>
根据授权key 换取token

@ -24,6 +24,7 @@ using Newtonsoft.Json;
using Myshipping.Application.ConfigOption;
using Myshipping.Application.Event;
using Myshipping.Core.MQ;
using Myshipping.Application.MQ;
namespace Myshipping.Web.Core;
@ -147,6 +148,12 @@ public class Startup : AppStartup
builder.AddSubscriber<SyncTenantUserToDjyCustomerSubscriber>();
}
//自用订舱:处理订舱自动化
if (runType is CommonConst.RUN_TYPE_NORMAL)
{
builder.AddSubscriber<BookingAutoSubscriber>();
}
//扣费
builder.AddSubscriber<BookingFeeSubscriber>();
});
@ -157,6 +164,13 @@ public class Startup : AppStartup
// 公司员工变动消息队列服务
services.AddHostedService<RecCompanyUserChangeService>();
}
//自用订舱:处理订舱自动化
if (runType is CommonConst.RUN_TYPE_NORMAL)
{
// 订舱自动化消息队列服务
services.AddHostedService<BookingAutoService>();
}
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)

Loading…
Cancel
Save