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/TaskDraftCompareService.cs

526 lines
21 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.Extensions;
using Furion.FriendlyException;
using Furion.JsonSerialization;
using Furion.RemoteRequest.Extensions;
using Mapster;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Myshipping.Application.Entity;
using Myshipping.Core;
using Myshipping.Core.Entity;
using Myshipping.Core.Service;
using Org.BouncyCastle.Asn1.X9;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using Yitter.IdGenerator;
namespace Myshipping.Application
{
/// <summary>
/// 请求Draft比对
/// </summary>
[ApiDescriptionSettings("Application", Name = "TaskDraftCompare", Order = 10)]
public class TaskDraftCompareService : ITaskDraftCompareService, IDynamicApiController, ITransient
{
private readonly ISysCacheService _cache;
private readonly ILogger<TaskDraftCompareService> _logger;
private readonly SqlSugarRepository<BookingOrder> _bookingOrderRepository;
private readonly SqlSugarRepository<BookingCtn> _bookingOrderContaRepository;
private readonly SqlSugarRepository<BookingFile> _bookingFileRepository;
private readonly SqlSugarRepository<SysUser> _sysUserRepository;
const string CONST_DRAFT_FILE_CODE = "draft";
const string CONST_DRAFT_FILE_NAME = "格式单";
public TaskDraftCompareService(ISysCacheService cache, ILogger<TaskDraftCompareService> logger,
SqlSugarRepository<BookingOrder> bookingOrderRepository, SqlSugarRepository<BookingCtn> bookingOrderContaRepository,
SqlSugarRepository<BookingFile> bookingFileRepository, SqlSugarRepository<SysUser> sysUserRepository)
{
_cache = cache;
_logger = logger;
_bookingOrderRepository = bookingOrderRepository;
_bookingOrderContaRepository = bookingOrderContaRepository;
_bookingFileRepository = bookingFileRepository;
_sysUserRepository = sysUserRepository;
}
#region 执行邮件Draft比对
/// <summary>
/// 执行邮件Draft比对
/// </summary>
/// <param name="file">请求文件</param>
/// <param name="jsonData">邮件Draft比对请求报文</param>
/// <returns>返回回执</returns>
[AllowAnonymous,HttpPost("/TaskDraftCompare/ExcuteEmailDraftCompare")]
public async Task<TaskManageExcuteResultDto> ExcuteEmailDraftCompareAsync(IFormFile file, [FromForm] string jsonData)
{
string batchNo = IDGen.NextID().ToString();
TaskManageExcuteResultDto result = new TaskManageExcuteResultDto();
DateTime nowDate = DateTime.Now;
/*
1、接收报文里的文件信息优先写入本地文件暂存。
2、请求解析Draft文件解析并等待解析结果。
3、判断对应的订舱提单号。如果没有对应的订舱提单号则写入任务表失败记录。
4、写入任务表。
5、异步请求格式单比对接口。
6、接收比对结果更新任务表。
7、更新订舱表并更新状态。
*/
try
{
var model = GetJsonMessageInfo(jsonData, batchNo);
TaskDraftCompareMessageInfo readFileMessageInfo = new TaskDraftCompareMessageInfo
{
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",
}
};
//附件暂存
var fileFullName = await FileAttachHelper.TempSaveWebFile(model.Head.GID, file, batchNo, CONST_DRAFT_FILE_CODE);
//Draft文件解析
NameValueCollection par = new NameValueCollection();
par.Add("jsonMessage", JSON.Serialize(readFileMessageInfo));
byte[] bytes = file.ToByteArray();
DateTime bDate = DateTime.Now;
var readResult = await ExcuteReadPDF(par, new
{
file = "file",
fileName = file.FileName,
fileBytes = bytes
});
DateTime eDate = DateTime.Now;
TimeSpan ts = eDate.Subtract(bDate);
var timeDiff = ts.TotalMilliseconds;
_logger.LogInformation("批次={no} 请求Draft文件解析完成,耗时:{timeDiff}ms. 结果{msg} 报文={message}", batchNo, timeDiff,
readResult.succ ? "成功" : "失败",
JSON.Serialize(readResult));
if(!readResult.succ)
{
_logger.LogInformation("批次={no} 请求Draft文件解析失败 原因={reason}", batchNo, readResult.msg);
throw Oops.Oh($"请求Draft文件解析失败 原因={readResult.msg}");
}
//通过解析提单号匹配订舱的详情
var readModel = JSON.Deserialize<CompareDraftDataInfo>(JSON.Serialize(readResult.extra));
string billNo = string.Empty;
if(!string.IsNullOrWhiteSpace(readModel.MasterBlNo))
{
billNo = readModel.MasterBlNo;
}
if(string.IsNullOrWhiteSpace(billNo))
{
_logger.LogInformation("批次={no} 请求Draft文件解析未获取到有效提单号", batchNo);
throw Oops.Oh($"请求Draft文件解析未获取到有效提单号");
}
var bookingOrder = _bookingOrderRepository.AsQueryable().Filter(null, true)
.First(a => a.MBLNO.Equals(billNo));
if (bookingOrder == null)
{
_logger.LogInformation("批次={no} 提单号{billNo}无法获取业务信息", batchNo, billNo);
throw Oops.Oh($"提单号{billNo}无法获取业务信息");
}
_logger.LogInformation("批次={no}获取订舱数据完成", batchNo);
TaskDraftCompareMessageInfo msgModel = new TaskDraftCompareMessageInfo {
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 TaskDraftMessageMainInfo()
};
//请求格式单比对接口
var mainInfo = bookingOrder.Adapt<BusinessInfo>();
var userInfo = _sysUserRepository.AsQueryable().First(a => a.Id == bookingOrder.CreatedUserId);
mainInfo.BusiPKId = bookingOrder.Id.ToString();
mainInfo.UserId = bookingOrder.CreatedUserId.ToString();
mainInfo.UserName = bookingOrder.CreatedUserName;
mainInfo.UserEmail = userInfo?.Email;
var contaList = _bookingOrderContaRepository.AsQueryable().Filter(null,true)
.Where(x => x.BILLID == bookingOrder.Id).ToList();
_logger.LogInformation("批次={no} 提取箱完成 数量={total}", batchNo, contaList.Count);
if (contaList.Count > 0)
{
mainInfo.ContaList = contaList.Adapt<List<TaskDraftMessageCtnInfo>>();
}
msgModel.Main.BusinessInfo = mainInfo;
msgModel.Main.DraftInfo = readModel;
//推送Draft比对
DateTime bCompareDate = DateTime.Now;
var compareResult = await ExcuteDraftCompare(msgModel);
DateTime eCompareDate = DateTime.Now;
TimeSpan tsCompare = bCompareDate.Subtract(eCompareDate);
var timeDiffCompare = tsCompare.TotalMilliseconds;
_logger.LogInformation("批次={no} 请求Draft比对完成,耗时:{timeDiff}ms. 结果{msg} 报文={message}", batchNo, timeDiffCompare,
compareResult.succ ? "成功" : "失败",
JSON.Serialize(compareResult));
_logger.LogInformation("批次={no} 对应请求报文完成 msg={msg}", batchNo, JSON.Serialize(msgModel));
var entity = _bookingOrderRepository.AsQueryable().Filter(null, true)
.First(a => a.Id == bookingOrder.Id);
entity.LstDraftCompareRlt = compareResult.extra2.Any(a => a.IsDiff) ? "DIFF" : "";
entity.LstDraftCompareDate = nowDate;
//更新订舱相关
await _bookingOrderRepository.AsUpdateable(entity).UpdateColumns(it => new
{
it.LstDraftCompareDate,
it.LstDraftCompareRlt
}).ExecuteCommandAsync();
//如果确认文件读取成功
var bookFilePath = await FileAttachHelper.MoveFile(bookingOrder.Id.ToString(), fileFullName, batchNo);
//将格式单附件写入订舱的附件
await SaveEDIFile(bookingOrder.Id, bookFilePath, new System.IO.FileInfo(fileFullName).Name, CONST_DRAFT_FILE_CODE, CONST_DRAFT_FILE_NAME);
result = compareResult;
}
catch (Exception ex)
{
result.succ = false;
result.msg = $"请求Draft比对异常,{ex.Message}";
}
return result;
}
#endregion
#region 反序列化请求参数报文
/// <summary>
/// 反序列化请求参数报文
/// </summary>
/// <param name="jsonMessage">请求参数报文</param>
/// <param name="batchNo">批次号</param>
/// <returns>返回反序列化结果</returns>
private TaskEmailDraftCompareMessageInfo GetJsonMessageInfo(string jsonMessage, string batchNo)
{
try
{
return JSON.Deserialize<TaskEmailDraftCompareMessageInfo>(jsonMessage);
}
catch
{
_logger.LogInformation("批次号{0} jsonMessage请求参数转换失败", batchNo);
throw Oops.Oh($"jsonMessage请求参数转换失败");
}
}
#endregion
#region 解析格式单文件
/// <summary>
/// 解析格式单文件
/// </summary>
/// <param name="nameValueCollection">请求参数</param>
/// <param name="fileInfo">文件</param>
/// <param name="contentType">请求类型</param>
/// <returns>返回回执</returns>
[NonAction]
private async Task<TaskManageExcuteCommonResultDto> ExcuteReadPDF(NameValueCollection nameValueCollection, dynamic fileInfo,
string contentType = "application/json")
{
TaskManageExcuteCommonResultDto model = null;
var result = string.Empty;
using (var httpClient = new HttpClient())
{
try
{
using (var reduceAttach = new MultipartFormDataContent())
{
string[] allKeys = nameValueCollection.AllKeys;
foreach (string key in allKeys)
{
var dataContent = new ByteArrayContent(Encoding.UTF8.GetBytes(nameValueCollection[key]));
dataContent.Headers.ContentDisposition = new ContentDispositionHeaderValue($"form-data")
{
Name = key
};
reduceAttach.Add(dataContent);
}
#region 文件参数
if (fileInfo != null)
{
var Content = new ByteArrayContent(fileInfo.fileBytes);
//Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
//{
// Name = fileInfo.file.ToString(),
// FileName = fileInfo.fileName.ToString(),
//};
Content.Headers.Add("Content-Type", contentType);
reduceAttach.Add(Content, fileInfo.file.ToString(), HttpUtility.UrlEncode(fileInfo.fileName.ToString()));
}
#endregion
//请求
var response = httpClient.PostAsync(App.Configuration["DraftReadUrl"], reduceAttach).Result;
result = response.Content.ReadAsStringAsync().Result;
model = JSON.Deserialize<TaskManageExcuteCommonResultDto>(result);
}
}
catch (Exception ex)
{
_logger.LogInformation("请求Draft比对异常原因{error}", ex.Message);
throw Oops.Oh($"请求Draft比对异常原因{ex.Message}");
}
}
return model;
}
#endregion
#region 请求格式单比对
/// <summary>
/// 请求格式单比对
/// </summary>
/// <param name="info">请求报文</param>
/// <returns></returns>
private async Task<TaskManageExcuteResultDto> ExcuteDraftCompare(TaskDraftCompareMessageInfo info)
{
TaskManageExcuteResultDto model = null;
var url = App.Configuration["DraftCompareUrl"];
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
#region 异步写入订舱附件表
/// <summary>
/// 异步写入订舱附件表
/// </summary>
/// <param name="boookId">订舱ID</param>
/// <param name="FilePath">文件路径</param>
/// <param name="fileName">文件名</param>
/// <param name="fileTypeCode">附件类型代码</param>
/// <param name="fileTypeName">附件类型名称</param>
/// <returns></returns>
[NonAction]
private async Task SaveEDIFile(long boookId, string FilePath, string fileName, string fileTypeCode = "bc", string fileTypeName = "Booking Confirmation")
{
/*
直接将附件信息写入附件表
*/
//EDI文件
var bookFile = new BookingFile
{
Id = YitIdHelper.NextId(),
FileName = fileName,
FilePath = FilePath,
TypeCode = fileTypeCode,
TypeName = fileTypeName,
BookingId = boookId,
};
await _bookingFileRepository.InsertAsync(bookFile);
}
#endregion
#region 获取Draft比对结果详情
/// <summary>
/// 获取Draft比对结果详情
/// </summary>
/// <param name="bookingId">订舱主键</param>
/// <returns>返回回执</returns>
[HttpPost("/TaskDraftCompare/GetDraftCompareResultInfo")]
public async Task<TaskManageExcuteResultDto> GetDraftCompareResultInfo([FromQuery] long bookingId)
{
string batchNo = IDGen.NextID().ToString();
TaskManageExcuteResultDto result = new TaskManageExcuteResultDto();
try
{
DateTime nowDate = DateTime.Now;
TaskDraftCompareMessageInfo msgModel = new TaskDraftCompareMessageInfo
{
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 TaskDraftMessageMainInfo {
BusinessInfo = new BusinessInfo {
BusiPKId = bookingId.ToString()
}
}
};
_logger.LogInformation($"开始请求查询 msg={JSON.Serialize(msgModel)}");
result = await GetDraftCompareResult(msgModel);
var lastFileInfo = _bookingFileRepository.AsQueryable().Filter(null,true).Where(a=>a.BookingId == bookingId &&
a.TypeCode.Equals(CONST_DRAFT_FILE_CODE))
.OrderByDescending(a=>a.CreatedTime).First();
if (lastFileInfo != null)
result.extra3 = lastFileInfo.Id;
}
catch(Exception ex)
{
_logger.LogInformation("获取Draft比对结果异常原因{error}", ex.Message);
throw Oops.Oh($"获取Draft比对结果异常原因{ex.Message}");
}
return result;
}
#endregion
#region 获取Draft比对结果
/// <summary>
/// 获取Draft比对结果
/// </summary>
/// <param name="info">请求报文</param>
/// <returns>返回回执</returns>
[NonAction]
private async Task<TaskManageExcuteResultDto> GetDraftCompareResult(TaskDraftCompareMessageInfo info)
{
TaskManageExcuteResultDto model = null;
var url = App.Configuration["GetDraftCompareUrl"];
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
}
}