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.
BookingHeChuan/Myshipping.Application/Service/TaskManagePlat/TaskShippingOrderCompareSer...

715 lines
30 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.DependencyInjection;
using Furion.DistributedIDGenerator;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using Furion.JsonSerialization;
using Furion.RemoteRequest.Extensions;
using Mapster;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Myshipping.Application.Entity;
using Myshipping.Application.Entity.DraftCompare;
using Myshipping.Core;
using Myshipping.Core.Entity;
using Myshipping.Core.Service;
using Org.BouncyCastle.Asn1.X9;
using StackExchange.Profiling.Internal;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
namespace Myshipping.Application
{
/// <summary>
/// 请求下货纸比对
/// </summary>
[ApiDescriptionSettings("Application", Name = "TaskShippingOrderCompare", Order = 9)]
public class TaskShippingOrderCompareService : ITaskShippingOrderCompareService, IDynamicApiController, ITransient
{
private readonly ISysCacheService _cache;
private readonly ILogger<TaskShippingOrderCompareService> _logger;
private readonly SqlSugarRepository<BookingOrder> _bookingOrderRepository;
private readonly SqlSugarRepository<BookingCtn> _bookingOrderContaRepository;
private readonly SqlSugarRepository<DraftCompareFeedBackRecord> _draftCompareFeedBackRecordRepository;
//private readonly SqlSugarRepository<SysUser> _userRepository;
private readonly IBookingValueAddedService _bookingValueAddedService;
private readonly IBookingOrderService _bookingOrderService;
public TaskShippingOrderCompareService(ISysCacheService cache, ILogger<TaskShippingOrderCompareService> logger,
SqlSugarRepository<BookingOrder> bookingOrderRepository, SqlSugarRepository<BookingCtn> bookingOrderContaRepository,
IBookingValueAddedService bookingValueAddedService, IBookingOrderService bookingOrderService,
SqlSugarRepository<DraftCompareFeedBackRecord> draftCompareFeedBackRecordRepository)
{
_cache = cache;
_logger = logger;
_bookingOrderRepository = bookingOrderRepository;
_bookingOrderContaRepository = bookingOrderContaRepository;
_bookingValueAddedService = bookingValueAddedService;
_bookingOrderService = bookingOrderService;
_draftCompareFeedBackRecordRepository = draftCompareFeedBackRecordRepository;
}
/// <summary>
/// 执行下货纸比对
/// </summary>
/// <param name="bookingId">订舱主键</param>
/// <returns>返回回执</returns>
[HttpGet("/TaskShippingOrderCompare/ExcuteShippingOrderCompare")]
public async Task<TaskManageExcuteResultDto> ExcuteShippingOrderCompareAsync(string bookingId)
{
string batchNo = IDGen.NextID().ToString();
_logger.LogInformation("批次={no}获取订舱数据请求规则 {id}", batchNo, bookingId);
/*
处理逻辑
1、台账触发单票下货纸比对
2、调取订舱的详情。
3、对应请求报文。
4、请求比对接口。
5、返回回执。
*/
return await InnerExcuteShippingOrderCompareAsync(bookingId);
}
#region 执行下货纸比对
/// <summary>
/// 执行下货纸比对
/// </summary>
/// <param name="bookingId">订舱主键</param>
/// <param name="LstShipOrderCompareMode">比对模式MANUAL-手工 AUTO-自动)</param>
/// <returns>返回回执</returns>
private async Task<TaskManageExcuteResultDto> InnerExcuteShippingOrderCompareAsync(string bookingId,
string LstShipOrderCompareMode = "MANUAL")
{
string batchNo = IDGen.NextID().ToString();
_logger.LogInformation("批次={no}获取订舱数据请求规则 {id}", batchNo, bookingId);
/*
处理逻辑
1、台账触发单票下货纸比对
2、调取订舱的详情。
3、对应请求报文。
4、请求比对接口。
5、返回回执。
*/
TaskManageExcuteResultDto result = new TaskManageExcuteResultDto();
try
{
DateTime nowDate = DateTime.Now;
long id = long.Parse(bookingId);
var model = _bookingOrderRepository.AsQueryable().Filter(null, true)
.First(a => a.Id == id && !a.IsDeleted && a.TenantId == UserManager.TENANT_ID);
if (model == null)
throw Oops.Oh($"订舱主键{bookingId}无法获取业务信息");
_logger.LogInformation("批次={no}获取订舱数据完成", batchNo);
//附主信息
var mainInfo = model.Adapt<TaskMessageMain>();
mainInfo.BusiPKId = model.Id.ToString();
mainInfo.UserId = UserManager.UserId.ToString();
mainInfo.UserName = UserManager.Name;
mainInfo.UserEmail = UserManager.Email;
var contaList = await _bookingOrderContaRepository.AsQueryable().Filter(null, true)
.Where(x => x.BILLID == model.Id && x.TenantId == UserManager.TENANT_ID).ToListAsync();
_logger.LogInformation("批次={no} 提取箱完成 数量={total}", batchNo, contaList.Count);
if (contaList.Count > 0)
{
mainInfo.ContaList = contaList.Adapt<List<TaskMessageCtnInfo>>();
}
var msgModel = GetMessageInfo(batchNo, mainInfo);
_logger.LogInformation("批次={no} 对应请求报文完成 msg={msg}", batchNo, JSON.Serialize(msgModel));
DateTime bDate = DateTime.Now;
var compareResult = await ExcuteCompare(msgModel);
DateTime eDate = DateTime.Now;
TimeSpan ts = eDate.Subtract(bDate);
var timeDiff = ts.TotalMilliseconds;
_logger.LogInformation("批次={no} 请求完成,耗时:{timeDiff}ms. 结果{msg}", batchNo, timeDiff, compareResult.succ ? "成功" : "失败");
if (compareResult == null)
throw Oops.Oh($"订舱主键{bookingId}请求下货纸比对失败,返回为空");
var orderInfo = _bookingOrderRepository.AsQueryable().Filter(null, true)
.First(x => x.Id == id && x.TenantId == UserManager.TENANT_ID);
if (orderInfo != null)
{
var oldOrderInfo = orderInfo.Adapt<BookingOrder>();
orderInfo.LstShipOrderCompareDate = bDate;
if (compareResult.succ)
{
orderInfo.LstShipOrderCompareMode = LstShipOrderCompareMode;
/*
isComplete标记当票是否满足截至要求
1、场站返回的记录里所有箱都有了返场日期。
2、或者当票的实际开船日期或者预计开船日期已到也可以截至。
*/
bool isComplete = false;
bool isBefore = false;
//需要细分状态,返场前和返场后
if (compareResult.yardStatInfo != null)
{
var yardStatInfo = compareResult.yardStatInfo as YardStatInfo;
//如果场站集装箱都有了返场时间,即认为下货纸自动任务结束
if (yardStatInfo.LstReturnYardDate.HasValue && yardStatInfo.ContaNum >= 1 &&
yardStatInfo.ContaNum == yardStatInfo.ExistsReturnYardDateCtnNum)
{
isComplete = true;
}
//判断 有箱号的条数跟总计箱数量不一致 认为是反场前比对
if ((yardStatInfo.ExistsCtnNo < yardStatInfo.ContaNum))
isBefore = true;
}
DateTime etd = DateTime.MinValue;
if(model.ATD.HasValue)
{
etd = model.ATD.Value;
}
else if (model.ETD.HasValue)
{
etd = model.ETD.Value;
}
if (etd != DateTime.MinValue && etd <= DateTime.Now)
isComplete = true;
if (compareResult.extra.IsExistsDiff)
{
if(isComplete)
{
orderInfo.LstShipOrderCompareRlt = "DIFF";
orderInfo.LstShipOrderCompareRltName = "有差异";
}
else
{
bool isBeforeEqual = false;
var checkList = compareResult.extra.ShowDetailList.Where(b =>
(b.PCode == null || b.PCode == "") && b.IsDisplay &&
(b.FieldCode.ToUpper() != "PKGS" && b.FieldCode.ToUpper() != "KGS" && b.FieldCode.ToUpper() != "CBM"))
.ToList();
if (!checkList.Any(t => t.IsDiff))
{
isBeforeEqual = true;
}
if (isBefore)
{
if (isBeforeEqual)
{
orderInfo.LstShipOrderCompareRlt = "BEFORE_EQUAL";
orderInfo.LstShipOrderCompareRltName = "返场前比对正常";
}
else
{
orderInfo.LstShipOrderCompareRlt = "BEFORE_DIFF";
orderInfo.LstShipOrderCompareRltName = "返场前比对有差异";
}
}
else
{
orderInfo.LstShipOrderCompareRlt = "DIFF_U";
orderInfo.LstShipOrderCompareRltName = "有差异未结束";
}
}
}
else
{
if (isComplete)
{
orderInfo.LstShipOrderCompareRlt = "NO_DIFF";
orderInfo.LstShipOrderCompareRltName = "正常";
//比对成功后触发下货纸比对状态
var saveStatusRlt = await _bookingValueAddedService.SaveServiceStatus(new ModifyServiceProjectStatusDto
{
BookingId = long.Parse(bookingId),
SourceType = TrackingSourceTypeEnum.AUTO,
StatusCodes = new List<ModifyServiceProjectStatusDetailDto> {
new ModifyServiceProjectStatusDetailDto { StatusCode = "XHZBDCHG" } }
});
_logger.LogInformation("批次={no} 异步推送下货纸比对状态完成,结果={rlt}", batchNo, JSON.Serialize(saveStatusRlt));
}
else
{
if (isBefore)
{
orderInfo.LstShipOrderCompareRlt = "BEFORE_EQUAL";
orderInfo.LstShipOrderCompareRltName = "返场前比对正常";
}
else
{
orderInfo.LstShipOrderCompareRlt = "NO_DIFF_U";
orderInfo.LstShipOrderCompareRltName = "正常未结束";
//比对成功后触发下货纸比对状态
var saveStatusRlt = await _bookingValueAddedService.SaveServiceStatus(new ModifyServiceProjectStatusDto
{
BookingId = long.Parse(bookingId),
SourceType = TrackingSourceTypeEnum.AUTO,
StatusCodes = new List<ModifyServiceProjectStatusDetailDto> {
new ModifyServiceProjectStatusDetailDto { StatusCode = "XHZBDCHG" } }
});
_logger.LogInformation("批次={no} 异步推送下货纸比对状态完成,结果={rlt}", batchNo, JSON.Serialize(saveStatusRlt));
}
}
}
}
else
{
orderInfo.LstShipOrderCompareRlt = "NO_YARD";
orderInfo.LstShipOrderCompareRltName = "无动态";
}
if (compareResult.extra != null)
orderInfo.LstShipOrderCompareId = compareResult.extra.TaskCompareId;
//更新
await _bookingOrderRepository.AsUpdateable(orderInfo).UpdateColumns(it => new
{
it.LstShipOrderCompareId,
it.LstShipOrderCompareDate,
it.LstShipOrderCompareRlt,
it.LstShipOrderCompareRltName,
it.LstShipOrderCompareMode,
}).ExecuteCommandAsync();
// 记录日志
await _bookingOrderService.SaveLog(orderInfo, oldOrderInfo, "下货纸比对");
}
result.succ = compareResult.succ;
result.msg = compareResult.msg;
result.extra = compareResult.extra;
result.extra2 = compareResult.extra2;
result.total = compareResult.total;
result.yardStatInfo = compareResult.yardStatInfo;
_logger.LogInformation("批次={no} 请求下货纸比对返回结果{msg}", batchNo, JSON.Serialize(compareResult));
_logger.LogInformation("批次={no} 返回结果{msg}", batchNo, JSON.Serialize(result));
}
catch (Exception ex)
{
result.succ = false;
result.msg = $"请求下货纸比对异常,{ex.Message}";
}
return result;
}
#endregion
/// <summary>
/// 批量执行下货纸比对
/// </summary>
/// <param name="bookingIds">订舱主键组</param>
/// <returns>返回回执</returns>
[HttpPost("/TaskShippingOrderCompare/ExcuteShippingOrderCompareBatch")]
public async Task<TaskManageExcuteResultDto> ExcuteShippingOrderCompareBatchAsync([FromBody] string[] bookingIds)
{
TaskManageExcuteResultDto result = new TaskManageExcuteResultDto();
try
{
var ids = bookingIds.Select(a => long.Parse(a)).Distinct().ToArray();
var list = _bookingOrderRepository.AsQueryable().Where(t => ids.Contains(t.Id)).ToList();
if (list.Count != ids.Length)
{
var noRecord = string.Join(",", ids.GroupJoin(list, l => l, r => r.Id, (l, r) =>
{
var currList = r.ToList();
if (r.Count() > 0)
return 0;
return l;
}).Where(t => t > 0).ToArray());
throw Oops.Oh($"以下主键信息 {noRecord} 检索失败或者已作废过");
}
//这里单票下货纸比对时,等待结果返回
if(ids.Length == 1)
{
result = await InnerExcuteShippingOrderCompareAsync(list.FirstOrDefault().Id.ToString());
}
else
{
List<Task<TaskManageExcuteResultDto>> listOfTasks = new List<Task<TaskManageExcuteResultDto>>();
list.ForEach(entity =>
{
listOfTasks.Add(InnerExcuteShippingOrderCompareAsync(entity.Id.ToString()));
});
await Task.WhenAll<TaskManageExcuteResultDto>(listOfTasks);
result.succ = true;
result.msg = "比对完成";
string rltMsg = string.Empty;
result.rows = listOfTasks.Select(a =>
{
var origId = a.Result.extra.OrigPKId;
var order = list.FirstOrDefault(x => x.Id == long.Parse(origId));
if (a.Result.succ)
{
if (a.Result.total > 0)
{
return new { MblNo = order.MBLNO, Msg = "比对异常", IsDiff = true, rlt = a.Result.succ };
}
return new { MblNo = order.MBLNO, Msg = "比对一致", IsDiff = false, rlt = a.Result.succ };
}
return new { MblNo = order?.MBLNO, Msg = "比对一致", IsDiff = false, rlt = a.Result.succ };
}).ToList();
}
}
catch (Exception ex)
{
result.succ = false;
result.msg = $"请求下货纸比对异常,{ex.Message}";
}
return result;
}
/// <summary>
/// 下货纸自动比对回写状态
/// </summary>
/// <param name="model">比对回写详情</param>
/// <returns>返回回执</returns>
[AllowAnonymous, HttpPost("/TaskShippingOrderCompare/AutoTaskShippingOrderCompareCallBack")]
public async Task<TaskManageExcuteResultDto> AutoTaskShippingOrderCompareCallBackAsync([FromBody] ShippingOrderCompareCallBackInfo model)
{
TaskManageExcuteResultDto result = new TaskManageExcuteResultDto();
try
{
if(string.IsNullOrWhiteSpace(model.reqBusiId))
throw Oops.Oh($"订舱主键{model.reqBusiId}不能为空");
if (string.IsNullOrWhiteSpace(model.compareId))
throw Oops.Oh($"比对ID{model.compareId}不能为空");
if (string.IsNullOrWhiteSpace(model.compareMode))
throw Oops.Oh($"下货纸比对方式不能为空{model.compareMode}不能为空");
if (string.IsNullOrWhiteSpace(model.compareRltCode))
throw Oops.Oh($"比对结果代码{model.compareRltCode}不能为空");
if (string.IsNullOrWhiteSpace(model.compareRltName))
throw Oops.Oh($"比对结果名称{model.compareId}不能为空");
var bookingOrder = await _bookingOrderRepository.AsQueryable()
.FirstAsync(a => a.Id == long.Parse(model.reqBusiId));
if (bookingOrder == null)
{
throw Oops.Oh($"订舱信息检索失败ID={model.reqBusiId}");
}
var oldBookingOrder = bookingOrder.Adapt<BookingOrder>();
bookingOrder.LstShipOrderCompareId = model.compareId;
bookingOrder.LstShipOrderCompareDate = model.compareDate;
bookingOrder.LstShipOrderCompareRlt = model.compareRltCode;
bookingOrder.LstShipOrderCompareRltName = model.compareRltName;
bookingOrder.LstShipOrderCompareMode = model.compareMode;
//更新
await _bookingOrderRepository.AsUpdateable(bookingOrder).UpdateColumns(it => new
{
it.LstShipOrderCompareId,
it.LstShipOrderCompareDate,
it.LstShipOrderCompareRlt,
it.LstShipOrderCompareRltName,
it.LstShipOrderCompareMode,
}).ExecuteCommandAsync();
await _bookingOrderService.SaveLog(bookingOrder, oldBookingOrder, "下货纸自动比对回写状态");
result.succ = true;
result.msg = "更新完成";
}
catch (Exception ex)
{
result.succ = false;
result.msg = $"下货纸自动比对回写状态失败,{ex.Message}";
}
return result;
}
/// <summary>
/// 生成请求规则报文
/// </summary>
/// <param name="batchNo">批次号</param>
/// <param name="mainInfo">订舱主业务信息</param>
/// <returns>返回请求报文类</returns>
[NonAction]
private TaskMessageInfoDto GetMessageInfo(string batchNo, TaskMessageMain mainInfo)
{
DateTime nowDate = DateTime.Now;
TaskMessageInfoDto msgModel = new TaskMessageInfoDto();
msgModel.Head = new TaskMessageHead
{
GID = batchNo,
MessageType = "SHIP_ORDER_COMPARE",
SenderId = App.Configuration["RulesEngineSender"],
SenderName = App.Configuration["RulesEngineSenderName"],
ReceiverId = "RulesEngine",
ReceiverName = "大简云规则引擎",
Version = "1.0",
RequestDate = nowDate.ToString("yyyy-MM-dd HH:mm:ss"),
RequestAction = "Compare",
};
msgModel.Main = mainInfo;
return msgModel;
}
#region 请求下货纸比对
/// <summary>
/// 请求下货纸比对
/// </summary>
/// <param name="BusinessMsg"></param>
/// <returns></returns>
[NonAction]
private async Task<TaskManageExcuteResultDto> ExcuteCompare(TaskMessageInfoDto info)
{
TaskManageExcuteResultDto model = null;
/*
1、读取配置文件中的规则引擎URL
2、填充请求的类并生成JSON报文
3、POST请求接口并记录回执。
4、返回信息。
*/
var url = App.Configuration["ShippingOrderCompareUrl"];
try
{
var res = await url.OnClientCreating(client => {
// client 为 HttpClient 对象
client.Timeout = TimeSpan.FromMinutes(15); // 设置超时时间 15分钟
}).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<TaskManageExcuteResultDto>(userResult);
}
}
catch (Exception ex)
{
//写日志
if (ex is HttpRequestException)
throw Oops.Oh(10000002);
}
return model;
}
#endregion
#region 自动执行下货纸比对
/// <summary>
/// 自动执行下货纸比对
/// </summary>
/// <param name="bookingId">订舱主键</param>
/// <returns>返回回执</returns>
[AllowAnonymous, HttpGet("/TaskShippingOrderCompare/ExcuteAutoShippingOrderCompare"), ApiUser(ApiCode = "ExcuteAutoShippingOrderCompare")]
public async Task<TaskManageExcuteResultDto> ExcuteAutoShippingOrderCompareAsync(string bookingId)
{
string batchNo = IDGen.NextID().ToString();
_logger.LogInformation("批次={no}获取订舱数据请求规则 {id}", batchNo, bookingId);
/*
处理逻辑
1、台账触发单票下货纸比对
2、调取订舱的详情。
3、对应请求报文。
4、请求比对接口。
5、返回回执。
*/
return await InnerExcuteShippingOrderCompareAsync(bookingId, "AUTO");
}
#endregion
/// <summary>
/// 获取下货纸比对结果
/// </summary>
/// <param name="bookingId">订舱主键</param>
/// <returns>返回回执</returns>
[HttpGet("/TaskShippingOrderCompare/GetShippingOrderCompareResult")]
public async Task<TaskManageExcuteResultDto> GetShippingOrderCompareResult(long bookingId)
{
string batchNo = IDGen.NextID().ToString();
TaskManageExcuteResultDto result = new TaskManageExcuteResultDto();
try
{
var model = _bookingOrderRepository.AsQueryable().Filter(null, true)
.First(a => a.Id == bookingId && !a.IsDeleted && a.TenantId == UserManager.TENANT_ID);
DateTime nowDate = DateTime.Now;
TaskMessageInfoDto msgModel = new TaskMessageInfoDto
{
Head = new TaskMessageHead
{
GID = batchNo,
MessageType = "DRAFT_COMPARE",
SenderId = App.Configuration["RulesEngineSender"],
SenderName = App.Configuration["RulesEngineSenderName"],
ReceiverId = "RulesEngine",
ReceiverName = "大简云规则引擎",
Version = "1.0",
RequestDate = nowDate.ToString("yyyy-MM-dd HH:mm:ss"),
RequestAction = "Compare",
},
Main = new TaskMessageMain
{
BusiPKId = bookingId.ToString(),
TaskCompareId = model.LstShipOrderCompareId,
}
};
_logger.LogInformation($"开始请求查询 msg={JSON.Serialize(msgModel)}");
result = await GetCompareResult(msgModel);
if (result != null && result.extra != null && !string.IsNullOrWhiteSpace(result.extra.TaskCompareId))
{
var feedBack = _draftCompareFeedBackRecordRepository.AsQueryable().First(a => a.BOOKING_ID == bookingId
&& a.TASK_COMPARE_ID == result.extra.TaskCompareId);
if (feedBack != null)
{
result.extra.ManualFeedBackResult = new FeedBackResult
{
OperNote = feedBack.NOTES,
OperTime = feedBack.CreatedTime.Value,
OperUser = feedBack.CreatedUserName,
Reason = (feedBack.IS_OCR_ERROR ? "识别问题 " : "") + (feedBack.IS_EDIT_ERROR ? "录入问题 " : "") + (feedBack.IS_AGENT_ERROR ? "代理录入问题 " : "")
};
}
}
}
catch (Exception ex)
{
_logger.LogInformation("获取Draft比对结果异常原因{error}", ex.Message);
throw Oops.Oh($"获取Draft比对结果异常原因{ex.Message}");
}
return result;
}
#region 获取Draft比对结果
/// <summary>
/// 获取Draft比对结果
/// </summary>
/// <param name="info">请求报文</param>
/// <returns>返回回执</returns>
[NonAction]
private async Task<TaskManageExcuteResultDto> GetCompareResult(TaskMessageInfoDto info)
{
TaskManageExcuteResultDto model = null;
var url = App.Configuration["GetShippingOrderCompareUrl"];
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();
_logger.LogInformation("对应请求报文 userResult={userResult}", userResult);
model = JSON.Deserialize<TaskManageExcuteResultDto>(userResult);
}
}
catch (Exception ex)
{
//写日志
if (ex is HttpRequestException)
throw Oops.Oh(10000002);
}
return model;
}
#endregion
}
}