|
|
using Furion.FriendlyException;
|
|
|
using Furion.JsonSerialization;
|
|
|
using Furion;
|
|
|
using System;
|
|
|
using System.Collections.Generic;
|
|
|
using System.Linq;
|
|
|
using System.Net.Http;
|
|
|
using System.Text;
|
|
|
using System.Threading.Tasks;
|
|
|
using Furion.RemoteRequest.Extensions;
|
|
|
using Furion.DependencyInjection;
|
|
|
using Microsoft.AspNetCore.Mvc;
|
|
|
using System.Xml.Linq;
|
|
|
using Furion.DynamicApiController;
|
|
|
using Microsoft.AspNetCore.Authorization;
|
|
|
using Myshipping.Application.Entity;
|
|
|
using Myshipping.Core;
|
|
|
using Furion.DistributedIDGenerator;
|
|
|
using Mapster;
|
|
|
using Furion.DataValidation;
|
|
|
using Newtonsoft.Json.Linq;
|
|
|
using Myshipping.Core.Service;
|
|
|
using Myshipping.Core.Entity;
|
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
|
|
namespace Myshipping.Application
|
|
|
{
|
|
|
/// <summary>
|
|
|
/// 请求规则平台
|
|
|
/// </summary>
|
|
|
[ApiDescriptionSettings("Application", Name = "RulesEngineClient", Order = 9)]
|
|
|
public class RulesEngineClientService: IRulesEngineClientService, IDynamicApiController, ITransient
|
|
|
{
|
|
|
private readonly SqlSugarRepository<BookingOrder> _bookingOrderRepository;
|
|
|
private readonly SqlSugarRepository<BookingCtn> _bookingOrderContaRepository;
|
|
|
private readonly SqlSugarRepository<BookingCtnDetail> _bookingOrderContaCargoRepository;
|
|
|
private readonly ISysCacheService _cache;
|
|
|
private readonly SqlSugarRepository<RelaPortCarrierLane> _relaPortCarrierLaneRep;
|
|
|
private readonly ILogger<BookingOrderService> _logger;
|
|
|
|
|
|
const string CONST_MAPPING_MODULE = "RULE_ENGINE_CHECK";
|
|
|
|
|
|
/// <summary>
|
|
|
///
|
|
|
/// </summary>
|
|
|
public RulesEngineClientService(SqlSugarRepository<BookingOrder> bookingOrderRepository,
|
|
|
SqlSugarRepository<BookingCtn> bookingOrderContaRepository,
|
|
|
SqlSugarRepository<BookingCtnDetail> bookingOrderContaCargoRepository,
|
|
|
ISysCacheService cache,
|
|
|
SqlSugarRepository<RelaPortCarrierLane> relaPortCarrierLaneRep,
|
|
|
ILogger<BookingOrderService> logger)
|
|
|
{
|
|
|
_bookingOrderRepository = bookingOrderRepository;
|
|
|
_bookingOrderContaRepository = bookingOrderContaRepository;
|
|
|
_bookingOrderContaCargoRepository = bookingOrderContaCargoRepository;
|
|
|
_cache = cache;
|
|
|
_relaPortCarrierLaneRep = relaPortCarrierLaneRep;
|
|
|
_logger = logger;
|
|
|
}
|
|
|
|
|
|
#region 海运订舱请求规则引擎校验
|
|
|
/// <summary>
|
|
|
/// 海运订舱请求规则引擎校验
|
|
|
/// </summary>
|
|
|
/// <param name="model">海运订舱请求业务</param>
|
|
|
/// <returns>返回用户信息</returns>
|
|
|
[HttpPost("/RulesEngineClient/ExcuteRulesOceanBookingByMsg")]
|
|
|
public async Task<RulesEngineExcuteResultDto> ExcuteRulesOceanBookingByMsg(RulesEngineOrderBookingMessageInfo model)
|
|
|
{
|
|
|
RulesEngineExcuteResultDto result = new RulesEngineExcuteResultDto();
|
|
|
|
|
|
var ruleResult = await ExcuteRulesEngine(model);
|
|
|
|
|
|
if (ruleResult == null)
|
|
|
throw Oops.Oh($"订舱请求规则失败,返回为空");
|
|
|
|
|
|
var innerRlt = JSON.Deserialize<RemoteRulesEngineExcuteResultDto>(ruleResult.extra.ToString());
|
|
|
|
|
|
var ruleDetailList = innerRlt.DetailList;
|
|
|
|
|
|
result.succ = ruleResult.succ;
|
|
|
result.msg = ruleResult.msg;
|
|
|
|
|
|
if (ruleDetailList.Count > 0)
|
|
|
{
|
|
|
result.rows = ruleDetailList;
|
|
|
}
|
|
|
|
|
|
return result;
|
|
|
}
|
|
|
#endregion
|
|
|
|
|
|
#region 海运订舱请求规则引擎校验
|
|
|
/// <summary>
|
|
|
/// 海运订舱请求规则引擎校验
|
|
|
/// </summary>
|
|
|
/// <param name="bookingId">海运订舱主键</param>
|
|
|
/// <returns>返回用户信息</returns>
|
|
|
[HttpGet("/RulesEngineClient/ExcuteRulesOceanBooking")]
|
|
|
public async Task<RulesEngineExcuteResultDto> ExcuteRulesOceanBooking(string bookingId)
|
|
|
{
|
|
|
string batchNo = IDGen.NextID().ToString();
|
|
|
|
|
|
_logger.LogInformation("批次={no}获取订舱数据请求规则 {id}", batchNo, bookingId);
|
|
|
|
|
|
/*
|
|
|
处理逻辑
|
|
|
1、订单保存后触发调取此方法,传入海运订舱主键。
|
|
|
2、调取订舱的详情。
|
|
|
3、对应请求报文。
|
|
|
4、请求规则接口。
|
|
|
5、返回回执。
|
|
|
*/
|
|
|
|
|
|
RulesEngineExcuteResultDto result = new RulesEngineExcuteResultDto();
|
|
|
|
|
|
try
|
|
|
{
|
|
|
DateTime nowDate = DateTime.Now;
|
|
|
|
|
|
var model = _bookingOrderRepository.AsQueryable().InSingle(long.Parse(bookingId));
|
|
|
|
|
|
if (model == null)
|
|
|
throw Oops.Oh($"订舱主键{bookingId}无法获取业务信息");
|
|
|
|
|
|
_logger.LogInformation("批次={no}获取订舱数据完成", batchNo);
|
|
|
|
|
|
var mainInfo = model.Adapt<RulesEngineOrderBookingMainBusinessInfo>();
|
|
|
|
|
|
var contaList = await _bookingOrderContaRepository.AsQueryable().Where(x => x.BILLID == model.Id).ToListAsync();
|
|
|
|
|
|
_logger.LogInformation("批次={no} 提取箱完成 数量={total}", batchNo, contaList.Count);
|
|
|
|
|
|
if (contaList.Count > 0)
|
|
|
{
|
|
|
mainInfo.ContaList = contaList.Adapt<List<RulesEngineOrderBookingContaInfo>>();
|
|
|
|
|
|
var ctnArg = contaList.Select(t => t.Id).ToArray();
|
|
|
|
|
|
var cargoList = await _bookingOrderContaCargoRepository.AsQueryable()
|
|
|
.Where(x => ctnArg.Contains(x.CTNID.Value)).ToListAsync();
|
|
|
|
|
|
_logger.LogInformation("批次={no} 提取货物明细完成 数量={total}", batchNo, cargoList.Count);
|
|
|
|
|
|
if (cargoList.Count > 0)
|
|
|
{
|
|
|
mainInfo.ContaList = contaList.GroupJoin(cargoList, l => l.Id, r => r.CTNID, (l, r) => {
|
|
|
var currList = r.ToList();
|
|
|
|
|
|
if (currList.Count > 0)
|
|
|
{
|
|
|
var info = l.Adapt<RulesEngineOrderBookingContaInfo>();
|
|
|
info.CargoList = currList.Adapt<List<RulesEngineOrderBookingContaCargoInfo>>();
|
|
|
|
|
|
return info;
|
|
|
}
|
|
|
|
|
|
return l.Adapt<RulesEngineOrderBookingContaInfo>();
|
|
|
|
|
|
}).ToList();
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
mainInfo.ContaList = contaList.Adapt<List<RulesEngineOrderBookingContaInfo>>();
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
var msgModel = GetMessageInfo(batchNo, mainInfo);
|
|
|
|
|
|
_logger.LogInformation("批次={no} 对应请求报文完成 msg={msg}", batchNo, JSON.Serialize(msgModel));
|
|
|
|
|
|
DateTime bDate = DateTime.Now;
|
|
|
|
|
|
var ruleResult = await ExcuteRulesEngine(msgModel);
|
|
|
|
|
|
DateTime eDate = DateTime.Now;
|
|
|
TimeSpan ts = eDate.Subtract(bDate);
|
|
|
var timeDiff = ts.TotalMilliseconds;
|
|
|
|
|
|
_logger.LogInformation("批次={no} 请求完成,耗时:{timeDiff}ms. 结果{msg}", batchNo, timeDiff, ruleResult.succ ? "成功" : "失败");
|
|
|
|
|
|
if (ruleResult == null)
|
|
|
throw Oops.Oh($"订舱主键{bookingId}请求规则失败,返回为空");
|
|
|
|
|
|
var innerRlt = JSON.Deserialize<RemoteRulesEngineExcuteResultDto>(ruleResult.extra.ToString());
|
|
|
|
|
|
var ruleDetailList = innerRlt.DetailList;
|
|
|
|
|
|
result.succ = ruleResult.succ;
|
|
|
result.msg = ruleResult.msg;
|
|
|
|
|
|
if (ruleDetailList != null && ruleDetailList.Count > 0)
|
|
|
{
|
|
|
result.rows = ruleDetailList;
|
|
|
}
|
|
|
|
|
|
_logger.LogInformation("批次={no} 返回结果{msg}", batchNo,JSON.Serialize(result));
|
|
|
}
|
|
|
catch(Exception ex)
|
|
|
{
|
|
|
result.succ = false;
|
|
|
result.msg = "请求规则异常";
|
|
|
}
|
|
|
|
|
|
return result;
|
|
|
}
|
|
|
#endregion
|
|
|
|
|
|
#region 海运订舱请求规则引擎校验
|
|
|
/// <summary>
|
|
|
/// 海运订舱请求规则引擎校验
|
|
|
/// </summary>
|
|
|
/// <param name="model">海运订舱报文类</param>
|
|
|
/// <returns>返回回执</returns>
|
|
|
[HttpPost("/RulesEngineClient/ExcuteRulesOceanBookingByModel")]
|
|
|
public async Task<RulesEngineExcuteResultDto> ExcuteRulesOceanBookingByModel(BookingOrderDto model)
|
|
|
{
|
|
|
string batchNo = IDGen.NextID().ToString();
|
|
|
/*
|
|
|
处理逻辑
|
|
|
1、前台将保存报文推送过来。
|
|
|
2、如果有订舱主键调取数据库内的订舱的详情,已推送的数据为准。
|
|
|
3、对应请求报文。
|
|
|
4、请求规则接口。
|
|
|
5、返回回执。
|
|
|
*/
|
|
|
|
|
|
RulesEngineExcuteResultDto result = new RulesEngineExcuteResultDto();
|
|
|
|
|
|
try
|
|
|
{
|
|
|
DateTime nowDate = DateTime.Now;
|
|
|
|
|
|
var mainInfo = model.Adapt<RulesEngineOrderBookingMainBusinessInfo>();
|
|
|
|
|
|
RulesEngineOrderBookingMessageInfo msgModel = GetMessageInfo(batchNo, mainInfo);
|
|
|
|
|
|
var ruleResult = await ExcuteRulesEngine(msgModel);
|
|
|
|
|
|
if (ruleResult == null)
|
|
|
throw Oops.Oh($"订舱主键{model.BOOKINGNO}请求规则失败,返回为空");
|
|
|
|
|
|
var innerRlt = JSON.Deserialize<RemoteRulesEngineExcuteResultDto>(ruleResult.extra.ToString());
|
|
|
|
|
|
var ruleDetailList = innerRlt.DetailList;
|
|
|
|
|
|
result.succ = ruleResult.succ;
|
|
|
result.msg = ruleResult.msg;
|
|
|
|
|
|
if (ruleDetailList.Count > 0)
|
|
|
{
|
|
|
result.rows = ruleDetailList;
|
|
|
}
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
result.succ = false;
|
|
|
result.msg = "请求规则异常";
|
|
|
}
|
|
|
|
|
|
return result;
|
|
|
}
|
|
|
#endregion
|
|
|
|
|
|
/// <summary>
|
|
|
/// 生成请求规则报文
|
|
|
/// </summary>
|
|
|
/// <param name="batchNo">批次号</param>
|
|
|
/// <param name="mainInfo">订舱主业务信息</param>
|
|
|
/// <returns>返回请求报文类</returns>
|
|
|
[NonAction]
|
|
|
private RulesEngineOrderBookingMessageInfo GetMessageInfo(string batchNo,RulesEngineOrderBookingMainBusinessInfo mainInfo)
|
|
|
{
|
|
|
DateTime nowDate = DateTime.Now;
|
|
|
|
|
|
RulesEngineOrderBookingMessageInfo msgModel = new RulesEngineOrderBookingMessageInfo();
|
|
|
|
|
|
msgModel.Head = new RulesEngineWebAPIHeadBase
|
|
|
{
|
|
|
GID = batchNo,
|
|
|
MessageType = "BUSI_RULE",
|
|
|
SenderId = App.Configuration["RulesEngineSender"],
|
|
|
SenderName = App.Configuration["RulesEngineSenderName"],
|
|
|
SenderKey = App.Configuration["RulesEngineAuthKey"],
|
|
|
ReceiverId = "RulesEngine",
|
|
|
ReceiverName = "大简云规则引擎",
|
|
|
Version = "1.0",
|
|
|
RequestDate = nowDate.ToString("yyyy-MM-dd HH:mm:ss"),
|
|
|
RequestAction = "CheckRule",
|
|
|
};
|
|
|
|
|
|
msgModel.Main = new RulesEngineOrderBookingMainInfo
|
|
|
{
|
|
|
ProjectCode = App.Configuration["RulesEngineProjects"].Split(new char[] { ',' }).ToArray(),
|
|
|
};
|
|
|
|
|
|
msgModel.Main.BusinessInfo = mainInfo;
|
|
|
|
|
|
List<CodePort> codePortList = new List<CodePort>();
|
|
|
|
|
|
//根据卸货港翻译航线信息
|
|
|
if (!string.IsNullOrWhiteSpace(mainInfo.PortDischargeId))
|
|
|
{
|
|
|
var laneList = _cache.GetAllRelaPortCarrierLane().GetAwaiter().GetResult();
|
|
|
var laneInfo = laneList
|
|
|
.FirstOrDefault(p => !string.IsNullOrWhiteSpace(mainInfo.CarrierId) && !string.IsNullOrWhiteSpace(p.CarrierCode) &&
|
|
|
p.CarrierCode.Equals(mainInfo.CarrierId, StringComparison.OrdinalIgnoreCase) && p.PortCode.Equals(mainInfo.PortDischargeId, StringComparison.OrdinalIgnoreCase));
|
|
|
|
|
|
if (laneInfo == null)
|
|
|
laneInfo = laneList.FirstOrDefault(p => string.IsNullOrWhiteSpace(p.CarrierCode) && p.PortCode.Equals(mainInfo.PortDischargeId, StringComparison.OrdinalIgnoreCase));
|
|
|
|
|
|
_logger.LogInformation("批次={no} 港口对应航线完成 port={port} msg={msg}", batchNo, mainInfo.PortDischargeId, JSON.Serialize(laneInfo));
|
|
|
|
|
|
if (laneInfo != null)
|
|
|
{
|
|
|
var lineModel = _cache.GetAllCodeLane().GetAwaiter().GetResult().FirstOrDefault(t => t.Code.Equals(laneInfo.LaneCode, StringComparison.OrdinalIgnoreCase));
|
|
|
|
|
|
_logger.LogInformation("批次={no} 检索航线完成 lane={lane} msg={msg}", batchNo, laneInfo.LaneCode, JSON.Serialize(lineModel));
|
|
|
|
|
|
msgModel.Main.BusinessInfo.LaneCode = laneInfo.LaneCode;
|
|
|
msgModel.Main.BusinessInfo.LaneName = lineModel?.CnName;
|
|
|
}
|
|
|
|
|
|
codePortList = _cache.GetAllCodePort().GetAwaiter().GetResult();
|
|
|
|
|
|
//翻译卸货港对应的国家
|
|
|
var portInfo = codePortList.FirstOrDefault(t => t.Code.Equals(mainInfo.PortDischargeId, StringComparison.OrdinalIgnoreCase));
|
|
|
|
|
|
_logger.LogInformation("批次={no} 检索港口完成 lane={lane} msg={msg}", batchNo, mainInfo.PortDischargeId, JSON.Serialize(portInfo));
|
|
|
|
|
|
if (portInfo == null || string.IsNullOrWhiteSpace(portInfo.CountryCode))
|
|
|
throw Oops.Oh($"卸货港口代码{mainInfo.PortDischargeId}获取港口基础数据失败");
|
|
|
|
|
|
var countryInfo = _cache.GetAllCodeCountry().GetAwaiter().GetResult().FirstOrDefault(t => t.Code.Equals(portInfo.CountryCode, StringComparison.OrdinalIgnoreCase));
|
|
|
|
|
|
if (countryInfo == null || string.IsNullOrWhiteSpace(portInfo.EnName))
|
|
|
throw Oops.Oh($"国家代码{portInfo.CountryCode}获取国家基础数据失败");
|
|
|
|
|
|
msgModel.Main.BusinessInfo.PortDischargeCountryNo = countryInfo.Code;
|
|
|
msgModel.Main.BusinessInfo.PortDischargeEN = countryInfo.EnName;
|
|
|
msgModel.Main.BusinessInfo.PortDischargeCN = countryInfo.CnName;
|
|
|
|
|
|
}
|
|
|
|
|
|
//中转港
|
|
|
if (!string.IsNullOrWhiteSpace(mainInfo.TransportId))
|
|
|
{
|
|
|
if(codePortList.Count == 0)
|
|
|
{
|
|
|
codePortList = _cache.GetAllCodePort().GetAwaiter().GetResult();
|
|
|
}
|
|
|
|
|
|
//翻译中转港对应的国家
|
|
|
var portInfo = codePortList.FirstOrDefault(t => t.Code.Equals(mainInfo.TransportId, StringComparison.OrdinalIgnoreCase));
|
|
|
|
|
|
_logger.LogInformation("批次={no} 检索港口完成 port={lane} msg={msg}", batchNo, mainInfo.TransportId, JSON.Serialize(portInfo));
|
|
|
|
|
|
if (portInfo == null || string.IsNullOrWhiteSpace(portInfo.CountryCode))
|
|
|
throw Oops.Oh($"中转港口代码{mainInfo.TransportId}获取港口基础数据失败");
|
|
|
|
|
|
var countryInfo = _cache.GetAllCodeCountry().GetAwaiter().GetResult().FirstOrDefault(t => t.Code.Equals(portInfo.CountryCode, StringComparison.OrdinalIgnoreCase));
|
|
|
|
|
|
if (countryInfo == null || string.IsNullOrWhiteSpace(portInfo.EnName))
|
|
|
throw Oops.Oh($"国家代码{portInfo.CountryCode}获取国家基础数据失败");
|
|
|
|
|
|
msgModel.Main.BusinessInfo.TransportCountryNo = countryInfo.Code;
|
|
|
msgModel.Main.BusinessInfo.TransportEN = countryInfo.EnName;
|
|
|
msgModel.Main.BusinessInfo.TransportCN = countryInfo.CnName;
|
|
|
}
|
|
|
|
|
|
//对应签单方式
|
|
|
if (!string.IsNullOrWhiteSpace(mainInfo.IssueType))
|
|
|
{
|
|
|
var issueType = _cache.GetAllCodeIssueType().GetAwaiter().GetResult().FirstOrDefault(p => p.EnName.Equals(mainInfo.IssueType, StringComparison.OrdinalIgnoreCase));
|
|
|
|
|
|
_logger.LogInformation("批次={no} 提取签单方式完成 IssueType={issue} msg={msg}", batchNo, mainInfo.IssueType, JSON.Serialize(issueType));
|
|
|
|
|
|
//这里规则约定用了签单方式的代码大写
|
|
|
if (issueType != null)
|
|
|
msgModel.Main.BusinessInfo.IssueType = issueType.Code.ToUpper();
|
|
|
}
|
|
|
|
|
|
if (mainInfo.ContaList != null && mainInfo.ContaList.Count > 0)
|
|
|
{
|
|
|
//var contaList = _cache.GetAllMappingCtn().GetAwaiter().GetResult();
|
|
|
//mainInfo.ContaList.ForEach(t =>
|
|
|
//{
|
|
|
// var currContaType = contaList.FirstOrDefault(x => x.Module.Equals(CONST_MAPPING_MODULE, StringComparison.OrdinalIgnoreCase)
|
|
|
// && x.Code.Equals(t.ContaType, StringComparison.OrdinalIgnoreCase));
|
|
|
|
|
|
// if (currContaType != null)
|
|
|
// {
|
|
|
// t.ContaType = currContaType.MapCode?.ToUpper();
|
|
|
// }
|
|
|
//});
|
|
|
mainInfo.ContaList.ForEach(t =>
|
|
|
{
|
|
|
if (!string.IsNullOrWhiteSpace(t.ContaType))
|
|
|
{
|
|
|
var contaInfo = _cache.GetAllCodeCtn().GetAwaiter().GetResult().FirstOrDefault(p => p.Code.Equals(t.ContaType, StringComparison.OrdinalIgnoreCase));
|
|
|
|
|
|
if (contaInfo == null)
|
|
|
throw Oops.Oh($"箱型{t.ContaType} 基础数据没有指定大小箱");
|
|
|
|
|
|
t.ContaCategory = contaInfo.CtnCategory;
|
|
|
}
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return msgModel;
|
|
|
}
|
|
|
|
|
|
|
|
|
#region 请求规则平台
|
|
|
/// <summary>
|
|
|
/// 请求规则平台
|
|
|
/// </summary>
|
|
|
/// <param name="BusinessMsg"></param>
|
|
|
/// <returns></returns>
|
|
|
[NonAction]
|
|
|
private async Task<RulesEngineWebApiResult> ExcuteRulesEngine(RulesEngineOrderBookingMessageInfo info)
|
|
|
{
|
|
|
RulesEngineWebApiResult model = null;
|
|
|
/*
|
|
|
1、读取配置文件中的规则引擎URL
|
|
|
2、填充请求的类,并生成JSON报文
|
|
|
3、POST请求接口,并记录回执。
|
|
|
4、返回信息。
|
|
|
*/
|
|
|
|
|
|
var url = App.Configuration["RulesEngineUrl"];
|
|
|
|
|
|
try
|
|
|
{
|
|
|
var res = await url.SetHttpMethod(HttpMethod.Post)
|
|
|
.SetBody(JSON.Serialize(info), "application/json")
|
|
|
.SetContentEncoding(Encoding.UTF8)
|
|
|
.PostAsync();
|
|
|
|
|
|
_logger.LogInformation("批次={no} 对应请求报文完成 res={res}", info.Head.GID, JSON.Serialize(res));
|
|
|
|
|
|
if (res.StatusCode == System.Net.HttpStatusCode.OK)
|
|
|
{
|
|
|
var userResult = await res.Content.ReadAsStringAsync();
|
|
|
|
|
|
model = JSON.Deserialize<RulesEngineWebApiResult>(userResult);
|
|
|
}
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
//写日志
|
|
|
if (ex is HttpRequestException)
|
|
|
throw Oops.Oh(10000002);
|
|
|
}
|
|
|
|
|
|
return model;
|
|
|
}
|
|
|
#endregion
|
|
|
}
|
|
|
}
|