You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

814 lines
27 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using Furion;
using Furion.FriendlyException;
using Furion.Logging;
using Furion.RemoteRequest.Extensions;
using Myshipping.Application.EDI.Dtos;
using Myshipping.Application.Entity;
using Myshipping.Application.Helper;
using Myshipping.Core;
using Myshipping.Core.Entity;
using Myshipping.Core.Service;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics.Contracts;
using System.Diagnostics.Metrics;
using System.Linq;
using System.Text;
using System.Text.Encodings.Web;
using System.Text.Json;
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 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 == "BookingPostApiServerAddr" && x.GroupCode == "DJY_CONST");
if (sCfgSpiderUrl == null)
{
return new KeyValuePair<bool, string>(false, "订舱API的爬虫URL地址未配置请联系管理员");
}
var sCfgUserKey = sysConfigList.FirstOrDefault(x => x.Code == "BookingPostApiKey" && x.GroupCode == "DJY_CONST");
var sCfgUserSecret = sysConfigList.FirstOrDefault(x => x.Code == "BookingPostApiSecret" && x.GroupCode == "DJY_CONST");
if (sCfgUserKey == null || sCfgUserSecret == null)
{
return new KeyValuePair<bool, string>(false, "订舱API的KEY和密钥未配置请联系管理员");
}
BookingSoTemplate template = null;
DjyCustomerContact custContact = null;
var postModel = new EMCSoApiModel();
postModel.webAccount = custOrder.BookingAccount;
postModel.webPassword = custOrder.BookingPassword;
postModel.mark = new
{
BookingCustomerOrderId = custOrder.Id,
BookingNo = custOrder.BOOKINGNO,
BookingId = custOrder.BookingId,
};
//查找模板:
//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.IsDeleted == false && x.CarrierId == custOrder.CARRIERID && x.UserId == custContact.Id && 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 mapPlaceReceipt = mappingPortLoad.FirstOrDefault(x => x.Module == "DjyCustBooking" && x.CarrierCode == CarrierCodeConst.EMC && x.Code == custOrder.PLACERECEIPTCODE);
if (mapPlaceReceipt == null)
{
throw Oops.Bah($"未找到收货地映射信息:{custOrder.PLACERECEIPTCODE}");
}
//起运港
var mapPortLoad = mappingPortLoad.FirstOrDefault(x => x.Module == "DjyCustBooking" && x.CarrierCode == CarrierCodeConst.EMC && x.Code == custOrder.PORTLOADCODE);
if (mapPortLoad == null)
{
throw Oops.Bah($"未找到起运港映射信息:{custOrder.PORTLOADCODE}");
}
//卸货港
var mapPort = mappingPort.FirstOrDefault(x => x.Module == "DjyCustBooking" && x.CarrierCode == CarrierCodeConst.EMC && x.Code == custOrder.PORTDISCHARGECODE);
if (mapPort == null)
{
throw Oops.Bah($"未找到卸货港映射信息:{custOrder.PORTDISCHARGECODE}");
}
//目的地
var mapDestination = mappingPort.FirstOrDefault(x => x.Module == "DjyCustBooking" && x.CarrierCode == CarrierCodeConst.EMC && x.Code == custOrder.DESTINATIONCODE);
if (mapPort == null)
{
throw Oops.Bah($"未找到目的地映射信息:{custOrder.DESTINATIONCODE}");
}
////运输条款
//var mappingService = await cacheService.GetAllMappingService();
//var mappService = mappingService.FirstOrDefault(x => x.Module == "DjyCustBooking" && x.CarrierCode == CarrierCodeConst.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('-');
postModel.routes = new EMCSoApiRoute()
{
searchConditionDate = custOrder.ETD.Value.ToString("yyyy-MM-dd"),
originName = mapPlaceReceipt.MapCode,
destinationName = mapDestination.MapCode,
polPortName = mapPortLoad.MapCode,
podPortName = mapPort.MapCode,
serviceType = custOrder.ServiceType,
serviceMode = custOrder.ServiceMode,
};
//货物信息(箱信息)
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 == CarrierCodeConst.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",
commodityName = custOrder.DESCRIPTION
};
postModel.cargoInfos.Add(apiBox);
}
//合约信息
postModel.contractInfo = new EMCSoApiContractInfo()
{
bookingOffice = custOrder.BookingAddr,
issuePlace = custOrder.BillSignLoc,
billNum = custOrder.BillCount,
contractNo = custOrder.CONTRACTNO,
contractSelect = custOrder.ContractType,
contractParty = custOrder.SignType
};
var mapFrt = mappingFrt.FirstOrDefault(x => x.Module == "DjyCustBooking" && x.CarrierCode == CarrierCodeConst.EMC && x.Code == custOrder.FRTCODE);
if (mapFrt == null)
{
return new KeyValuePair<bool, string>(false, $"未找到付款方式映射信息:{custOrder.FRTCODE}");
}
postModel.contractInfo.paymentMethod = mapFrt.MapCode;
//船期数据
if (string.IsNullOrEmpty(custOrder.ExtendData))
{
return new KeyValuePair<bool, string>(false, $"船期数据信息不存在");
}
var extData = JObject.Parse(custOrder.ExtendData);
postModel.shipInfo = extData.GetJObjectValue("shipInfo");
//订舱公司详情
postModel.companyInfo = new EMCSoApiCompanyInfo()
{
receiveBookingNotice = custOrder.AcceptNotify ? "Yes" : "No",
referenceNO = custOrder.CustomerInnerCode
};
#region 收发通及货代
var companyName = "";
var telCountryCode = "";
var telAreaCode = "";
var telNumber = "";
//发货人
companyName = custOrder.ShipperName;
telCountryCode = custOrder.ShipperPhoneCountryCode;
telAreaCode = custOrder.ShipperPhoneCode;
telNumber = custOrder.ShipperPhone;
var bcMail = "";
if (!string.IsNullOrEmpty(custOrder.OpMail)) //优先使用东胜上传的邮箱
{
bcMail = custOrder.OpMail;
}
else if (!string.IsNullOrEmpty(custContact.Email))
{
bcMail = custContact.Email;
}
else
{
bcMail = template.BcReceiveEmail;
}
postModel.shipperInfo = new EMCSoApiSFTInfo()
{
companyName = companyName,
contactTitle = custOrder.ShipperSex,
contactLName = custOrder.ShipperFirstName,
contactFName = custOrder.ShipperLastName,
tel1 = telCountryCode,
tel2 = telAreaCode,
tel3 = telNumber,
referenceNO = custOrder.ShipperInnerCode,
email = bcMail
};
//收货人
companyName = custOrder.ConsigneeName;
telCountryCode = custOrder.ConsigneePhoneCountryCode;
telAreaCode = custOrder.ConsigneePhoneCode;
telNumber = custOrder.ConsigneePhone;
if (!string.IsNullOrEmpty(companyName))
{
postModel.consigneeInfo = new EMCSoApiSFTInfo()
{
companyName = companyName,
contactTitle = custOrder.ConsigneeSex,
contactLName = custOrder.ConsigneeFirstName,
contactFName = custOrder.ConsigneeLastName,
tel1 = telCountryCode,
tel2 = telAreaCode,
tel3 = telNumber,
referenceNO = custOrder.ConsigneeInnerCode
};
}
//通知人
companyName = custOrder.NotifypartName;
telCountryCode = custOrder.NotifypartPhoneCountryCode;
telAreaCode = custOrder.NotifypartPhoneCode;
telNumber = custOrder.NotifypartPhone;
if (!string.IsNullOrEmpty(companyName))
{
postModel.notifyInfo = new EMCSoApiSFTInfo()
{
companyName = companyName,
contactTitle = custOrder.NotifypartSex,
contactLName = custOrder.NotifypartFirstName,
contactFName = custOrder.NotifypartLastName,
tel1 = telCountryCode,
tel2 = telAreaCode,
tel3 = telNumber,
referenceNO = custOrder.NotifypartInnerCode
};
}
//货代
companyName = custOrder.BookingName;
telCountryCode = custOrder.BookingPhoneCountryCode;
telAreaCode = custOrder.BookingPhoneCode;
telNumber = custOrder.BookingPhone;
var djyBookMail = sysConfigList.FirstOrDefault(x => x.Code == "DjyCustomerBookReceiveBcMail");
postModel.forwarderInfo = new EMCSoApiSFTInfo()
{
companyName = companyName,
contactTitle = custOrder.BookingSex,
contactLName = custOrder.BookingFirstName,
contactFName = custOrder.BookingLastName,
tel1 = telCountryCode,
tel2 = telAreaCode,
tel3 = telNumber,
referenceNO = custOrder.BookingInnerCode,
email = djyBookMail.Value
};
#endregion
postModel.remark = custOrder.SOREMARK;
postModel.copyNum = custOrder.CopyNum;
var apiUrl = sCfgSpiderUrl.Value;
if (!apiUrl.EndsWith("/"))
{
apiUrl += "/";
}
apiUrl += "v1/emc/booking/auto";
var jsonStr = JsonConvert.SerializeObject(postModel, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore });
Log.Information($"发送API数据给爬虫custOrder.BookingId:{custOrder.BookingId}custOrder.BOOKINGNO:{custOrder.BOOKINGNO}custOrder.BookingId{custOrder.BookingId}{apiUrl}{jsonStr}");
var rtn = await apiUrl.SetBody(jsonStr, "application/json")
.PostAsStringAsync();
Log.Information($"爬虫返回:{rtn}");
var jobjRtn = JObject.Parse(rtn);
if (jobjRtn.GetIntValue("code") == 200)
{
var jdata = jobjRtn.GetJObjectValue("data");
if (jdata != null)
{
JObject extObj = null;
if (!string.IsNullOrEmpty(custOrder.ExtendData))
{
extObj = JObject.Parse(custOrder.ExtendData);
}
else
{
extObj = new JObject();
}
var bookingNoArr = jdata.GetJArrayValue("bookingNo");
extObj["CustNO"] = bookingNoArr;
custOrder.ExtendData = extObj.ToJsonString();
await repCustOrder.AsUpdateable(custOrder).UpdateColumns(x => new { x.ExtendData }).ExecuteCommandAsync();
Log.Information($"回写CC号 {custOrder.Id} {custOrder.BOOKINGNO}");
}
return new KeyValuePair<bool, string>(true, "发送成功");
}
else
{
return new KeyValuePair<bool, string>(false, jobjRtn.GetStringValue("msg"));
}
}
}
/// <summary>
/// EMCAPI订舱传输对象
/// </summary>
public class EMCSoApiModel : BookingHelperBaseModel
{
/// <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 dynamic 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 object mark { 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; }
/// <summary>
/// 合约类型
/// 当类型为TR时,合约号不生效
/// SC, TR
/// </summary>
public string contractType { get; set; } = "SC";
/// <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 List<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; }
}
}