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
{
///
/// 请求Draft比对
///
[ApiDescriptionSettings("Application", Name = "TaskDraftCompare", Order = 10)]
public class TaskDraftCompareService : ITaskDraftCompareService, IDynamicApiController, ITransient
{
private readonly ISysCacheService _cache;
private readonly ILogger _logger;
private readonly SqlSugarRepository _bookingOrderRepository;
private readonly SqlSugarRepository _bookingOrderContaRepository;
private readonly SqlSugarRepository _bookingFileRepository;
private readonly SqlSugarRepository _sysUserRepository;
const string CONST_DRAFT_FILE_CODE = "draft";
const string CONST_DRAFT_FILE_NAME = "格式单";
public TaskDraftCompareService(ISysCacheService cache, ILogger logger,
SqlSugarRepository bookingOrderRepository, SqlSugarRepository bookingOrderContaRepository,
SqlSugarRepository bookingFileRepository, SqlSugarRepository sysUserRepository)
{
_cache = cache;
_logger = logger;
_bookingOrderRepository = bookingOrderRepository;
_bookingOrderContaRepository = bookingOrderContaRepository;
_bookingFileRepository = bookingFileRepository;
_sysUserRepository = sysUserRepository;
}
#region 执行邮件Draft比对
///
/// 执行邮件Draft比对
///
/// 请求文件
/// 邮件Draft比对请求报文
/// 返回回执
[AllowAnonymous,HttpPost("/TaskDraftCompare/ExcuteEmailDraftCompare")]
public async Task 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(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();
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>();
}
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, entity.TenantId.Value,
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 反序列化请求参数报文
///
/// 反序列化请求参数报文
///
/// 请求参数报文
/// 批次号
/// 返回反序列化结果
private TaskEmailDraftCompareMessageInfo GetJsonMessageInfo(string jsonMessage, string batchNo)
{
try
{
return JSON.Deserialize(jsonMessage);
}
catch
{
_logger.LogInformation("批次号{0} jsonMessage请求参数转换失败", batchNo);
throw Oops.Oh($"jsonMessage请求参数转换失败");
}
}
#endregion
#region 解析格式单文件
///
/// 解析格式单文件
///
/// 请求参数
/// 文件
/// 请求类型
/// 返回回执
[NonAction]
private async Task 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(result);
}
}
catch (Exception ex)
{
_logger.LogInformation("请求Draft比对异常,原因:{error}", ex.Message);
throw Oops.Oh($"请求Draft比对异常,原因:{ex.Message}");
}
}
return model;
}
#endregion
#region 请求格式单比对
///
/// 请求格式单比对
///
/// 请求报文
///
private async Task 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(userResult);
}
}
catch (Exception ex)
{
//写日志
if (ex is HttpRequestException)
throw Oops.Oh(10000002);
}
return model;
}
#endregion
#region 异步写入订舱附件表
///
/// 异步写入订舱附件表
///
/// 订舱ID
/// 文件路径
/// 文件名
/// 租户ID
/// 附件类型代码
/// 附件类型名称
///
[NonAction]
private async Task SaveEDIFile(long boookId, string FilePath, string fileName, long tenantId,
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,
TenantId = tenantId
};
await _bookingFileRepository.InsertAsync(bookFile);
}
#endregion
#region 获取Draft比对结果详情
///
/// 获取Draft比对结果详情
///
/// 订舱主键
/// 返回回执
[HttpPost("/TaskDraftCompare/GetDraftCompareResultInfo")]
public async Task 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比对结果
///
/// 获取Draft比对结果
///
/// 请求报文
/// 返回回执
[NonAction]
private async Task 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(userResult);
}
}
catch (Exception ex)
{
//写日志
if (ex is HttpRequestException)
throw Oops.Oh(10000002);
}
return model;
}
#endregion
}
}