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/BookingOrder/BookingValueAddedService.cs

2007 lines
81 KiB
C#

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 MathNet.Numerics;
2 years ago
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Myshipping.Application.ConfigOption;
using Myshipping.Application.Entity;
using Myshipping.Core;
2 years ago
using Myshipping.Core.Entity;
using Myshipping.Core.Service;
using MySqlX.XDevAPI.Common;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Utilities;
2 years ago
using SqlSugar;
using StackExchange.Profiling.Internal;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Net.NetworkInformation;
2 years ago
using System.Reflection.Metadata.Ecma335;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions;
2 years ago
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using Ubiety.Dns.Core;
using Yitter.IdGenerator;
namespace Myshipping.Application
{
/// <summary>
/// 订舱增值类服务
/// </summary>
[ApiDescriptionSettings("Application", Name = "BookingValueAdded", Order = 9)]
public class BookingValueAddedService : IBookingValueAddedService, IDynamicApiController, ITransient
{
private readonly ISysCacheService _cache;
private readonly IBookingOrderService _bookingOrderService;
private readonly ILogger<BookingTruckService> _logger;
private readonly SqlSugarRepository<BookingOrder> _bookingOrderRepository;
private readonly SqlSugarRepository<BookingFile> _bookingfile;
2 years ago
private readonly SqlSugarRepository<DjyWebsiteAccountConfig> _djyWebsiteAccountConfigRepository;
private readonly SqlSugarRepository<SysUser> _sysUserRepository;
private readonly SqlSugarRepository<BookingLetteryard> _bookingLetteryardRepository;
private readonly SqlSugarRepository<TaskBCInfo> _taskBCInfoRepository;
2 years ago
const string CONST_MAPPING_BC_MODULE_ROUTE = "BC_DOWN_RT";
const string CONST_MAPPING_DRAFT_MODULE_ROUTE = "DRAFT_DOWN_RT";
2 years ago
const string CONST_MAPPING_MANIALLO_CHK_MODULE_ROUTE = "MANI_ALLOC_CHK_RT";
const string CONST_FORMAT_BC_URL = "{0}_bc_down_url";
const string CONST_FORMAT_DRAFT_URL = "{0}_draft_down_url";
2 years ago
const string CONST_FORMAT_MANIALLO_CHK_URL = "{0}_manialloc_chk_url";
2 years ago
const string CONST_FORMAT_WEB = "{0}Web";
const string CONST_BC_FILE_PARSE_URL = "bc_file_parse_url";
const string CONST_BC_FILE_READ_URL = "bc_file_pdf_read_url";
public BookingValueAddedService(ISysCacheService cache, ILogger<BookingTruckService> logger,
SqlSugarRepository<BookingOrder> bookingOrderRepository, SqlSugarRepository<BookingFile> bookingfile,
SqlSugarRepository<DjyWebsiteAccountConfig> djyWebsiteAccountConfigRepository, SqlSugarRepository<SysUser> sysUserRepository,
SqlSugarRepository<BookingLetteryard> bookingLetteryardRepository, IBookingOrderService bookingOrderService
, SqlSugarRepository<TaskBCInfo> taskBCInfoRepository)
{
_cache = cache;
_logger = logger;
_bookingOrderRepository = bookingOrderRepository;
_bookingfile = bookingfile;
2 years ago
_djyWebsiteAccountConfigRepository = djyWebsiteAccountConfigRepository;
_sysUserRepository = sysUserRepository;
_bookingLetteryardRepository = bookingLetteryardRepository;
_bookingOrderService = bookingOrderService;
_taskBCInfoRepository = taskBCInfoRepository;
}
/// <summary>
/// 批量BC下载
/// </summary>
/// <param name="bookingIds">订舱主键数组</param>
/// <returns>返回回执</returns>
[HttpPost("/BookingValueAdded/DownloadBookingConfirm")]
public async Task<TaskManageOrderResultDto> DownloadBookingConfirm([FromBody]long[] bookingIds)
{
TaskManageOrderResultDto result = new TaskManageOrderResultDto();
List<Task<TaskManageOrderResultDto>> taskList = new List<Task<TaskManageOrderResultDto>>();
string batchNo = IDGen.NextID().ToString();
try
{
/*
1
2
3
4
5
6
*/
var list = _bookingOrderRepository.AsQueryable()
.Where(a => bookingIds.Contains(a.Id)).ToList();
if (list.Count != bookingIds.Length)
throw Oops.Oh($"订舱信息获取失败,订舱信息不存在或已作废");
var noList = bookingIds.Select((a, idx) => new { no = idx + 1, id = a }).ToList();
foreach (var bk in list)
{
var sortNo = noList.FirstOrDefault(a=>a.id == bk.Id).no;
taskList.Add(Task.Run(() => InnerDownloadBookingConfirm(bk, batchNo, sortNo)));
}
Task.WaitAll(taskList.ToArray());
result.succ = true;
result.msg = "批量下载BC成功";
var downResultList = taskList.Select(x => x.Result).ToList();
if (downResultList.Any(x => !x.succ))
{
result.succ = false;
result.msg = "BC下载失败";
}
else
{
result.succ = true;
result.msg = downResultList.FirstOrDefault().msg;
}
result.ext = downResultList;
var succ = downResultList.Count(x => x.succ);
var fail = downResultList.Count(x => !x.succ);
if (succ > 0)
2 years ago
{
result.batchTotal = succ.ToString();
2 years ago
}
else
{
result.batchTotal = "- ";
}
if(fail > 0)
{
2 years ago
result.batchTotal += "/" + fail.ToString();
}
else
{
result.batchTotal += " -";
}
}
catch (Exception ex)
{
result.succ = false;
result.msg = $"批量BC下载异常原因{ex.Message}";
}
return result;
}
#region 单票下载BC
/// <summary>
/// 单票下载BC
/// </summary>
/// <param name="bookingOrder">订舱详情</param>
/// <param name="batchNo">批次号</param>
/// <param name="sortNo">请求顺序号</param>
/// <returns>返回回执</returns>
private async Task<TaskManageOrderResultDto> InnerDownloadBookingConfirm(BookingOrder bookingOrder,string batchNo, int sortNo)
{
TaskManageOrderResultDto result = new TaskManageOrderResultDto();
result.bno = bookingOrder.MBLNO;
try
{
/*
1
2BCDRAFT2
3
4
5
*/
if (string.IsNullOrWhiteSpace(bookingOrder.MBLNO))
{
if (!string.IsNullOrWhiteSpace(bookingOrder.CUSTNO))
{
result.bno = $"订 {bookingOrder.CUSTNO}";
}
else
{
result.bno = $"NO.{sortNo}";
}
throw Oops.Bah($"主提单号不能为空");
}
var bcOrDraftRouteCfg = _cache.GetAllMappingCarrier().GetAwaiter().GetResult()
.FirstOrDefault(t => t.Module.Equals(CONST_MAPPING_BC_MODULE_ROUTE, StringComparison.OrdinalIgnoreCase)
&& t.Code.Equals(bookingOrder.CARRIERID?.Trim(), StringComparison.OrdinalIgnoreCase));
_logger.LogInformation("提单号【{mbl}】根据订舱的船公司代码{ca} 提取船公司映射完成,结果={rlt}",
bookingOrder.MBLNO, bookingOrder.CARRIERID, bcOrDraftRouteCfg);
if (bcOrDraftRouteCfg == null)
{
_logger.LogInformation("提单号{mbl} 根据订舱的船公司代码{ca} 提取船公司映射失败",
bookingOrder.MBLNO, bookingOrder.CARRIERID);
throw Oops.Bah($"船公司={bookingOrder.CARRIERID} 暂不支持BC下载");
}
string urlKey = string.Format(CONST_FORMAT_BC_URL, bcOrDraftRouteCfg.MapCode.ToLower());
var bcUrl = _cache.GetAllDictData().GetAwaiter().GetResult()
.FirstOrDefault(x => x.TypeCode == "url_set" && x.Code.Equals(urlKey, StringComparison.OrdinalIgnoreCase))?.Value;
2 years ago
_logger.LogInformation("提单号{mbl} 根据订舱的船公司代码{ca} 提取BC下载URL完成结果={rlt}",
bookingOrder.MBLNO, bookingOrder.CARRIERID, bcUrl);
if (string.IsNullOrWhiteSpace(bcUrl))
{
_logger.LogInformation("提单号{0} 根据订舱的船公司代码{1} 提取BC下载URL失败未取到配置key={key}",
bookingOrder.MBLNO, bookingOrder.CARRIERID, urlKey);
throw Oops.Bah($"船公司={bookingOrder.CARRIERID} 未配置请求地址{urlKey} 请联系管理员");
}
2 years ago
string webKey = string.Format(CONST_FORMAT_WEB, bcOrDraftRouteCfg.MapCode);
//获取个人对应的账户,这里GetAccountConfig逻辑优先取个人个人没有配置取公司对应配置
2 years ago
var userWebAccountConfig = GetAccountConfig(webKey, UserManager.UserId,UserManager.TENANT_ID).GetAwaiter()
.GetResult();
_logger.LogInformation("批次={no} 获取获取网站的账户完成result={Num}", batchNo, JSON.Serialize(userWebAccountConfig));
if (userWebAccountConfig == null)
throw Oops.Oh($" 未配置个人或公司网站账户,网站{webKey}");
BCOrDraftRequestDto requestDto = new BCOrDraftRequestDto
{
user_key = App.Configuration["BCOrDraftUserKey"],
user_secret = App.Configuration["BCOrDraftUserSecret"],
web_user = userWebAccountConfig.Account?.Trim(),
web_psw = userWebAccountConfig.Password?.Trim(),
bno = bookingOrder.MBLNO,
is_parse = false
};
_logger.LogInformation("批次={no} json={json} 请求BC远端下载开始", batchNo, JSON.Serialize(requestDto));
DateTime bDate = DateTime.Now;
//开始请求BC
var rlt = await ExcuteBCDownload(bcUrl, requestDto, batchNo);
DateTime eDate = DateTime.Now;
TimeSpan ts = eDate.Subtract(bDate);
var timeDiff = ts.TotalMilliseconds;
_logger.LogInformation("批次={no} result={result} 请求BC远端下载结束 耗时:{timeDiff}ms. ", batchNo,
JSON.Serialize(rlt),timeDiff);
if (rlt.code == 200)
{
_logger.LogInformation("批次={no} 下载文件成功,转存本地", batchNo);
string currFilePath = rlt.data.FirstOrDefault().path;
string fileTypeCode = "bc";
string fileTypeName = "Booking Confirmation";
//读取文件配置
var fileCfg = App.GetOptions<BookingAttachOptions>();
string relativePath = $"{fileCfg.relativePath}\\bcfiles\\{bookingOrder.Id}";
string filePath = $"{(!string.IsNullOrWhiteSpace(fileCfg.basePath) ? fileCfg.basePath : App.WebHostEnvironment.WebRootPath)}\\{relativePath}";
string fileFullName = $"{filePath}\\{new System.IO.FileInfo(currFilePath).Name}";
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
relativePath = relativePath.Replace("\\", "/");
filePath = filePath.Replace("\\", "/");
fileFullName = fileFullName.Replace("\\", "/");
}
_logger.LogInformation("批次={no} 生成文件保存路径完成 路由={filePath} 服务器系统={system}", batchNo, filePath, RuntimeInformation.OSDescription);
//预先创建目录
if (!Directory.Exists(filePath))
{
Directory.CreateDirectory(filePath);
}
var bcStream = await currFilePath.GetAsStreamAsync();
using (var fileStream = File.Create(fileFullName))
{
await bcStream.CopyToAsync(fileStream);
}
_logger.LogInformation("批次={no} 完成文件保存 filepath={path}", batchNo, fileFullName);
string bookFilePath = string.Empty;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
bookFilePath = System.Text.RegularExpressions.Regex.Match(fileFullName, relativePath.Replace("/", "\\/") + ".*").Value;
}
else
{
bookFilePath = System.Text.RegularExpressions.Regex.Match(fileFullName, relativePath.Replace("\\", "\\\\") + ".*").Value;
}
//这里先写入附件表
2 years ago
await SaveEDIFile(bookingOrder.Id, bookFilePath, new System.IO.FileInfo(currFilePath).Name,
fileTypeCode, fileTypeName);
result.succ = true;
result.msg = "BC下载成功";
}
else
{
result.succ = false;
result.msg = $"BC下载失败{rlt.msg}";
}
}
catch (Exception ex)
{
result.succ = false;
result.msg = $"BC下载失败{ex.Message}";
}
return result;
}
#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 _bookingfile.InsertAsync(bookFile);
}
#endregion
/// <summary>
/// 批量Draft下载
/// </summary>
/// <param name="bookingIds">订舱主键数组</param>
/// <returns></returns>
[HttpPost("/BookingValueAdded/DownloadDraft")]
public async Task<TaskManageOrderResultDto> DownloadDraft([FromBody]long[] bookingIds)
{
TaskManageOrderResultDto result = new TaskManageOrderResultDto();
List<Task<TaskManageOrderResultDto>> taskList = new List<Task<TaskManageOrderResultDto>>();
string batchNo = IDGen.NextID().ToString();
try
{
/*
1
2
3
4
5
6
*/
var list = _bookingOrderRepository.AsQueryable()
.Where(a => bookingIds.Contains(a.Id)).ToList();
if (list.Count != bookingIds.Length)
throw Oops.Oh($"订舱信息获取失败,订舱信息不存在或已作废");
var noList = bookingIds.Select((a, idx) => new { no = idx + 1, id = a }).ToList();
foreach (var bk in list)
{
var sortNo = noList.FirstOrDefault(a=>a.id == bk.Id).no;
taskList.Add(Task.Run(() => InnerDownloadDraft(bk, batchNo, sortNo)));
}
Task.WaitAll(taskList.ToArray());
result.succ = true;
result.msg = "下载Draft成功";
var downResultList = taskList.Select(x => x.Result).ToList();
if (downResultList.Any(x => !x.succ))
{
result.succ = false;
result.msg = "Draft下载失败";
}
else
{
result.succ = true;
result.msg = downResultList.FirstOrDefault().msg;
}
result.ext = downResultList;
var succ = downResultList.Count(x => x.succ);
var fail = downResultList.Count(x => !x.succ);
if (succ > 0)
2 years ago
{
result.batchTotal = succ.ToString();
2 years ago
}
else
{
result.batchTotal = "- ";
}
if (fail > 0)
{
2 years ago
result.batchTotal += "/" + fail.ToString();
}
else
{
result.batchTotal += " -";
}
}
catch (Exception ex)
{
result.succ = false;
result.msg = $"下载Draft异常原因{ex.Message}";
}
return result;
}
#region 单票下载BC
/// <summary>
/// 单票下载BC
/// </summary>
/// <param name="bookingOrder">订舱详情</param>
/// <param name="batchNo">批次号</param>
/// <param name="sortNo">请求顺序号</param>
/// <returns>返回回执</returns>
private async Task<TaskManageOrderResultDto> InnerDownloadDraft(BookingOrder bookingOrder, string batchNo,int sortNo)
{
TaskManageOrderResultDto result = new TaskManageOrderResultDto();
result.bno = bookingOrder.MBLNO;
try
{
/*
1
2BCDRAFT2
3
4
5
*/
if(bookingOrder.CARRIERID.Equals("ESL", StringComparison.OrdinalIgnoreCase))
{
if(string.IsNullOrWhiteSpace(bookingOrder.TMBLNO))
{
if (!string.IsNullOrWhiteSpace(bookingOrder.CUSTNO))
{
result.bno = $"订 {bookingOrder.CUSTNO}";
}
else if (string.IsNullOrWhiteSpace(bookingOrder.MBLNO))
{
result.bno = $"NO.{sortNo}";
}
throw Oops.Bah($"EP号不能为空");
}
}
else
{
if (string.IsNullOrWhiteSpace(bookingOrder.MBLNO))
{
if (!string.IsNullOrWhiteSpace(bookingOrder.CUSTNO))
{
result.bno = $"订 {bookingOrder.CUSTNO}";
}
else
{
result.bno = $"NO.{sortNo}";
}
throw Oops.Bah($"主提单号不能为空");
}
}
var bcOrDraftRouteCfg = _cache.GetAllMappingCarrier().GetAwaiter().GetResult()
.FirstOrDefault(t => t.Module.Equals(CONST_MAPPING_DRAFT_MODULE_ROUTE, StringComparison.OrdinalIgnoreCase)
&& t.Code.Equals(bookingOrder.CARRIERID?.Trim(), StringComparison.OrdinalIgnoreCase));
_logger.LogInformation("提单号{mbl} 根据订舱的船公司代码{ca} 提取船公司映射完成,结果={rlt}",
bookingOrder.MBLNO, bookingOrder.CARRIERID, bcOrDraftRouteCfg);
if (bcOrDraftRouteCfg == null)
{
_logger.LogInformation("提单号{0} 根据订舱的船公司代码{1} 提取船公司映射失败",
bookingOrder.MBLNO, bookingOrder.CARRIERID);
throw Oops.Bah($"船公司={bookingOrder.CARRIERID} 暂不支持Draft下载");
}
string urlKey = string.Format(CONST_FORMAT_DRAFT_URL, bcOrDraftRouteCfg.MapCode.ToLower());
var bcUrl = _cache.GetAllDictData().GetAwaiter().GetResult()
.FirstOrDefault(x => x.TypeCode == "url_set" && x.Code.Equals(urlKey, StringComparison.OrdinalIgnoreCase))?.Value;
_logger.LogInformation("提单号{mbl} 根据订舱的船公司代码{ca} 提取DRAFT下载URL完成结果={rlt}",
bookingOrder.MBLNO, bookingOrder.CARRIERID, bcUrl);
if (string.IsNullOrWhiteSpace(bcUrl))
{
_logger.LogInformation("提单号{0} 根据订舱的船公司代码{1} 提取BC下载URL失败未取到配置key={key}",
bookingOrder.MBLNO, bookingOrder.CARRIERID, urlKey);
throw Oops.Bah($"船公司={bookingOrder.CARRIERID} 未配置请求地址{urlKey} 请联系管理员");
}
2 years ago
string webKey = string.Format(CONST_FORMAT_WEB, bcOrDraftRouteCfg.MapCode);
//获取个人对应的账户,这里GetAccountConfig逻辑优先取个人个人没有配置取公司对应配置
2 years ago
var userWebAccountConfig = GetAccountConfig(webKey, UserManager.UserId, UserManager.TENANT_ID).GetAwaiter()
.GetResult();
_logger.LogInformation("批次={no} 获取获取网站的账户完成result={Num}", batchNo, JSON.Serialize(userWebAccountConfig));
if (userWebAccountConfig == null)
throw Oops.Oh($" 未配置个人或公司网站账户,网站{webKey}");
string downloadFilePathRlt = string.Empty;
string erroMsg = string.Empty;
if(bcOrDraftRouteCfg.MapCode.Trim().Equals("ESL", StringComparison.OrdinalIgnoreCase))
{
ESLDraftRequestDto requestDto = new ESLDraftRequestDto
{
u = userWebAccountConfig.Account?.Trim(),
p = userWebAccountConfig.Password?.Trim(),
ep_code = bookingOrder.TMBLNO?.Trim().ToUpper(),
};
_logger.LogInformation("批次={no} json={json} 请求Draft远端下载开始", batchNo, JSON.Serialize(requestDto));
DateTime bDate = DateTime.Now;
//开始请求BC
var rlt = await ExcuteESLDraftDownload(bcUrl, requestDto, batchNo);
DateTime eDate = DateTime.Now;
TimeSpan ts = eDate.Subtract(bDate);
var timeDiff = ts.TotalMilliseconds;
_logger.LogInformation("批次={no} result={result} 请求Draft远端下载结束 耗时:{timeDiff}ms. ", batchNo,
JSON.Serialize(rlt), timeDiff);
if (rlt.status == 1)
{
downloadFilePathRlt = rlt.data.api_path;
}
else
{
erroMsg = rlt.message;
}
}
else
{
BCOrDraftRequestDto requestDto = new BCOrDraftRequestDto
{
user_key = App.Configuration["BCOrDraftUserKey"],
user_secret = App.Configuration["BCOrDraftUserSecret"],
web_user = userWebAccountConfig.Account?.Trim(),
web_psw = userWebAccountConfig.Password?.Trim(),
bno = bookingOrder.MBLNO,
is_parse = false
};
_logger.LogInformation("批次={no} json={json} 请求Draft远端下载开始", batchNo, JSON.Serialize(requestDto));
DateTime bDate = DateTime.Now;
//开始请求BC
var rlt = await ExcuteDraftDownload(bcUrl, requestDto, batchNo);
DateTime eDate = DateTime.Now;
TimeSpan ts = eDate.Subtract(bDate);
var timeDiff = ts.TotalMilliseconds;
_logger.LogInformation("批次={no} result={result} 请求Draft远端下载结束 耗时:{timeDiff}ms. ", batchNo,
JSON.Serialize(rlt), timeDiff);
if (rlt.code == 200)
{
downloadFilePathRlt = rlt.data.FirstOrDefault().path;
}
else
{
erroMsg = rlt.msg;
}
}
if (!string.IsNullOrWhiteSpace(downloadFilePathRlt))
{
_logger.LogInformation("批次={no} 下载文件成功,转存本地", batchNo);
string currFilePath = downloadFilePathRlt;
string fileTypeCode = "draft";
string fileTypeName = "Draft";
//读取文件配置
var fileCfg = App.GetOptions<BookingAttachOptions>();
string relativePath = $"{fileCfg.relativePath}\\draftfiles\\{bookingOrder.Id}";
string filePath = $"{(!string.IsNullOrWhiteSpace(fileCfg.basePath) ? fileCfg.basePath : App.WebHostEnvironment.WebRootPath)}\\{relativePath}";
string fileFullName = $"{filePath}\\{new System.IO.FileInfo(currFilePath).Name}";
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
relativePath = relativePath.Replace("\\", "/");
filePath = filePath.Replace("\\", "/");
fileFullName = fileFullName.Replace("\\", "/");
}
_logger.LogInformation("批次={no} 生成文件保存路径完成 路由={filePath} 服务器系统={system}", batchNo, filePath, RuntimeInformation.OSDescription);
//预先创建目录
if (!Directory.Exists(filePath))
{
Directory.CreateDirectory(filePath);
}
var bcStream = await currFilePath.GetAsStreamAsync();
using (var fileStream = File.Create(fileFullName))
{
await bcStream.CopyToAsync(fileStream);
}
_logger.LogInformation("批次={no} 完成文件保存 filepath={path}", batchNo, fileFullName);
string bookFilePath = string.Empty;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
bookFilePath = System.Text.RegularExpressions.Regex.Match(fileFullName, relativePath.Replace("/", "\\/") + ".*").Value;
}
else
{
bookFilePath = System.Text.RegularExpressions.Regex.Match(fileFullName, relativePath.Replace("\\", "\\\\") + ".*").Value;
}
//这里先写入附件表
await SaveEDIFile(bookingOrder.Id, bookFilePath, new System.IO.FileInfo(currFilePath).Name,
fileTypeCode, fileTypeName);
result.succ = true;
result.msg = "Draft下载成功";
}
else
{
result.succ = false;
result.msg = $"Draft下载失败原因={erroMsg}";
}
}
catch (Exception ex)
{
result.succ = false;
result.msg = $"Draft下载失败原因{ex.Message}";
}
return result;
}
#endregion
#region BC请求远端下载
/// <summary>
/// BC请求远端下载
/// </summary>
/// <param name="url">请求URL</param>
/// <param name="info">请求详情</param>
/// <param name="batchNo">批次号</param>
/// <returns>返回结果</returns>
[NonAction]
private async Task<BCAPIBaseResult> ExcuteBCDownload(string url, BCOrDraftRequestDto info, string batchNo)
{
BCAPIBaseResult model = null;
/*
1JSON
2POST
3
*/
try
{
_logger.LogInformation("批次={no} 对应请求报文 request={res}", batchNo, JSON.Serialize(info));
2 years ago
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}", batchNo, JSON.Serialize(res));
if (res.StatusCode == System.Net.HttpStatusCode.OK)
{
var userResult = await res.Content.ReadAsStringAsync();
System.Text.Json.JsonSerializerOptions jsonOptions = new JsonSerializerOptions();
jsonOptions.Converters.Add(new DateTimeJsonConverter("yyyy-MM-dd HH:mm:ss"));
model = JSON.Deserialize<BCAPIBaseResult>(userResult, jsonOptions);
}
}
catch (Exception ex)
{
//写日志
if (ex is HttpRequestException)
throw Oops.Oh(10000002);
}
return model;
}
#endregion
#region Draft请求远端下载
/// <summary>
/// Draft请求远端下载
/// </summary>
/// <param name="url">请求URL</param>
/// <param name="info">请求详情</param>
/// <param name="batchNo">批次号</param>
/// <returns>返回结果</returns>
[NonAction]
private async Task<DraftAPIBaseResult> ExcuteDraftDownload(string url, BCOrDraftRequestDto info, string batchNo)
{
DraftAPIBaseResult model = null;
/*
1JSON
2POST
3
*/
try
{
_logger.LogInformation("批次={no} 对应请求报文 request={res}", batchNo, JSON.Serialize(info));
2 years ago
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}", batchNo, JSON.Serialize(res));
if (res.StatusCode == System.Net.HttpStatusCode.OK)
{
var userResult = await res.Content.ReadAsStringAsync();
System.Text.Json.JsonSerializerOptions jsonOptions = new JsonSerializerOptions();
jsonOptions.Converters.Add(new DateTimeJsonConverter("yyyy-MM-dd HH:mm:ss"));
model = JSON.Deserialize<DraftAPIBaseResult>(userResult, jsonOptions);
}
}
catch (Exception ex)
{
//写日志
if (ex is HttpRequestException)
throw Oops.Oh(10000002);
}
return model;
}
#endregion
#region ESL Draft请求远端下载
/// <summary>
/// ESL Draft请求远端下载
/// 由于现有的ESL和TSL接口不一致需要提供单独的POST方法
/// </summary>
/// <param name="url">请求URL</param>
/// <param name="info">请求详情</param>
/// <param name="batchNo">批次号</param>
/// <returns>返回结果</returns>
[NonAction]
private async Task<ESLDraftAPIBaseResult> ExcuteESLDraftDownload(string url, ESLDraftRequestDto info, string batchNo)
{
ESLDraftAPIBaseResult model = null;
/*
1JSON
2POST
3
*/
try
{
_logger.LogInformation("批次={no} 对应请求报文 request={res}", batchNo, JSON.Serialize(info));
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}", batchNo, JSON.Serialize(res));
if (res.StatusCode == System.Net.HttpStatusCode.OK)
{
var userResult = await res.Content.ReadAsStringAsync();
model = JSON.Deserialize<ESLDraftAPIBaseResult>(userResult);
}
}
catch (Exception ex)
{
//写日志
if (ex is HttpRequestException)
throw Oops.Oh(10000002);
}
return model;
}
#endregion
#region ESL SO Ref.No搜索ESL号查询
/// <summary>
/// ESL SO Ref.No搜索ESL号查询
/// </summary>
/// <param name="url">请求URL</param>
/// <param name="info">请求详情</param>
/// <param name="batchNo">批次号</param>
/// <returns>返回结果</returns>
[NonAction]
private async Task<ESLManiAlloChkAPIBaseResult> ExcuteManiAllocCheckDownload(string url, ESLManiAlloChkRequestDto info, string batchNo)
{
ESLManiAlloChkAPIBaseResult model = null;
/*
1JSON
2POST
3
*/
try
{
_logger.LogInformation("批次={no} 对应请求报文 request={res}", batchNo, JSON.Serialize(info));
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}", batchNo, JSON.Serialize(res));
if (res.StatusCode == System.Net.HttpStatusCode.OK)
{
var userResult = await res.Content.ReadAsStringAsync();
model = JSON.Deserialize<ESLManiAlloChkAPIBaseResult>(userResult);
}
}
catch (Exception ex)
{
//写日志
if (ex is HttpRequestException)
throw Oops.Oh(10000002);
}
return model;
}
#endregion
/// <summary>
/// 舱位分配查询
/// </summary>
/// <param name="bookingIds">订舱主键数组</param>
/// <returns>返回回执</returns>
[HttpPost("/BookingValueAdded/CheckUpdateManifestNo")]
public async Task<TaskManageOrderResultDto> CheckUpdateManifestNo([FromBody] long[] bookingIds)
{
TaskManageOrderResultDto result = new TaskManageOrderResultDto();
List<Task<TaskManageOrderResultDto>> taskList = new List<Task<TaskManageOrderResultDto>>();
string batchNo = IDGen.NextID().ToString();
try
{
/*
ESL
1ESL
2ESL
3esl_no
4
5esl_no
6
*/
var list = _bookingOrderRepository.AsQueryable()
.Where(a => bookingIds.Contains(a.Id)).ToList();
if (list.Count != bookingIds.Length)
throw Oops.Oh($"订舱信息获取失败,订舱信息不存在或已作废");
var noList = bookingIds.Select((a, idx) => new { no = idx + 1, id = a }).ToList();
foreach (var bk in list)
{
var sortNo = noList.FirstOrDefault(a => a.id == bk.Id).no;
taskList.Add(Task.Run(() => InnerCheckUpdateManifestNo(bk, batchNo, sortNo)));
}
Task.WaitAll(taskList.ToArray());
result.succ = true;
result.msg = "批量执行成功";
var downResultList = taskList.Select(x => x.Result).ToList();
if (downResultList.Any(x => !x.succ))
{
result.succ = false;
result.msg = "批量执行失败";
}
else
{
result.succ = true;
result.msg = downResultList.FirstOrDefault().msg;
}
result.ext = downResultList;
var succ = downResultList.Count(x => x.succ);
var fail = downResultList.Count(x => !x.succ);
if (succ > 0)
2 years ago
{
result.batchTotal = succ.ToString();
2 years ago
}
else
{
result.batchTotal = "- ";
}
if (fail > 0)
{
2 years ago
result.batchTotal += "/" + fail.ToString();
}
else
{
result.batchTotal += " -";
}
}
catch (Exception ex)
{
result.succ = false;
result.msg = $"批量执行失败,原因:{ex.Message}";
}
return result;
}
#region 单票舱位分配查询
/// <summary>
/// 单票舱位分配查询
/// </summary>
/// <param name="bookingOrder">订舱详情</param>
/// <param name="batchNo">批次号</param>
/// <param name="sortNo">请求顺序号</param>
/// <returns>返回回执</returns>
private async Task<TaskManageOrderResultDto> InnerCheckUpdateManifestNo(BookingOrder bookingOrder, string batchNo, int sortNo)
{
TaskManageOrderResultDto result = new TaskManageOrderResultDto();
result.bno = bookingOrder.MBLNO;
try
{
/*
1
2BCDRAFT2
3
4
5
*/
//2023-07-06 按照最新要求,从订舱编号取单号
if (string.IsNullOrWhiteSpace(bookingOrder.CUSTNO))
{
if (!string.IsNullOrWhiteSpace(bookingOrder.MBLNO))
{
result.bno = $"订 {bookingOrder.MBLNO}";
}
else
{
result.bno = $"NO.{sortNo}";
}
throw Oops.Bah($"订舱编号不能为空");
}
2 years ago
else
{
if (Regex.IsMatch(bookingOrder.CUSTNO, "\\bESL\\w+"))
2 years ago
{
_logger.LogInformation("批次={no} id={id} 订舱编号没填写参考号,无法继续", batchNo, bookingOrder.Id);
2 years ago
throw Oops.Oh($"订舱编号不是有效的参考号");
2 years ago
}
}
var bcOrDraftRouteCfg = _cache.GetAllMappingCarrier().GetAwaiter().GetResult()
.FirstOrDefault(t => t.Module.Equals(CONST_MAPPING_MANIALLO_CHK_MODULE_ROUTE, StringComparison.OrdinalIgnoreCase)
&& t.Code.Equals(bookingOrder.CARRIERID?.Trim(), StringComparison.OrdinalIgnoreCase));
_logger.LogInformation("订舱编号【{mbl}】根据订舱的船公司代码{ca} 提取船公司映射完成,结果={rlt}",
bookingOrder.CUSTNO, bookingOrder.CARRIERID, bcOrDraftRouteCfg);
if (bcOrDraftRouteCfg == null)
{
_logger.LogInformation("订舱编号{mbl} 根据订舱的船公司代码{ca} 提取船公司映射失败",
bookingOrder.CUSTNO, bookingOrder.CARRIERID);
throw Oops.Bah($"船公司={bookingOrder.CARRIERID} 暂不支持舱位分配查询");
}
string urlKey = string.Format(CONST_FORMAT_MANIALLO_CHK_URL, bcOrDraftRouteCfg.MapCode.ToLower());
var bcUrl = _cache.GetAllDictData().GetAwaiter().GetResult()
.FirstOrDefault(x => x.TypeCode == "url_set" && x.Code.Equals(urlKey, StringComparison.OrdinalIgnoreCase))?.Value;
_logger.LogInformation("订舱编号{mbl} 根据订舱的船公司代码{ca} 提取舱位分配查询URL完成结果={rlt}",
bookingOrder.CUSTNO, bookingOrder.CARRIERID, bcUrl);
if (string.IsNullOrWhiteSpace(bcUrl))
{
_logger.LogInformation("订舱编号{0} 根据订舱的船公司代码{1} 提取舱位分配查询URL失败未取到配置key={key}",
bookingOrder.CUSTNO, bookingOrder.CARRIERID, urlKey);
throw Oops.Bah($"船公司={bookingOrder.CARRIERID} 未配置请求地址{urlKey} 请联系管理员");
}
2 years ago
string webKey = string.Format(CONST_FORMAT_WEB, bcOrDraftRouteCfg.MapCode);
//获取个人对应的账户,这里GetAccountConfig逻辑优先取个人个人没有配置取公司对应配置
2 years ago
var userWebAccountConfig = GetAccountConfig(webKey, UserManager.UserId, UserManager.TENANT_ID).GetAwaiter()
.GetResult();
_logger.LogInformation("批次={no} 获取获取网站的账户完成result={Num}", batchNo, JSON.Serialize(userWebAccountConfig));
if (userWebAccountConfig == null)
throw Oops.Oh($" 未配置个人或公司网站账户,网站{webKey}");
ESLManiAlloChkRequestDto requestDto = new ESLManiAlloChkRequestDto
{
u = userWebAccountConfig.Account?.Trim(),
p = userWebAccountConfig.Password?.Trim(),
so_no = bookingOrder.CUSTNO,
};
_logger.LogInformation("批次={no} json={json} 请求舱位分配查询远端下载开始", batchNo, JSON.Serialize(requestDto));
DateTime bDate = DateTime.Now;
//开始请求BC
var rlt = await ExcuteManiAllocCheckDownload(bcUrl, requestDto, batchNo);
DateTime eDate = DateTime.Now;
TimeSpan ts = eDate.Subtract(bDate);
var timeDiff = ts.TotalMilliseconds;
_logger.LogInformation("批次={no} result={result} 请求舱位分配查询远端下载结束 耗时:{timeDiff}ms. ", batchNo,
JSON.Serialize(rlt), timeDiff);
if (rlt.status == 1)
{
2 years ago
if(rlt.data == null || string.IsNullOrWhiteSpace(rlt.data.esl_no))
{
_logger.LogInformation("批次={no} 舱位分配查询失败ESL号不存在", batchNo);
throw Oops.Oh($"查询ESL号失败");
}
_logger.LogInformation("批次={no} 舱位分配查询成功", batchNo);
/*
esl_no
*/
var bkInfo = _bookingOrderRepository.AsQueryable().First(a => a.Id == bookingOrder.Id);
if(bkInfo == null)
{
_logger.LogInformation("批次={no} id={id} 订舱信息获取失败,无法更新", batchNo, bookingOrder.Id);
throw Oops.Oh($"订舱信息获取失败,无法更新");
}
/* //2023-07-06 按照最新要求,从订舱编号取单号,所以这里不判断了
if(Regex.IsMatch(bkInfo.MBLNO,"\\bESL\\w+"))
{
_logger.LogInformation("批次={no} id={id} 主提单号已变更,无法更新", batchNo, bookingOrder.Id);
throw Oops.Oh($"主提单号已变更,无法更新");
}*/
_logger.LogInformation("批次={no} 变更前记录 id={id} MBLNO={MBLNO} CUSTNO={CUSTNO} esl_no={eslno}",
batchNo, bookingOrder.Id, bkInfo.MBLNO, bkInfo.CUSTNO, rlt.data.esl_no);
//bkInfo.CUSTNO = bkInfo.MBLNO;
bkInfo.MBLNO = rlt.data.esl_no.Trim().ToUpper();
bkInfo.UpdatedTime = DateTime.Now;
bkInfo.UpdatedUserId = UserManager.UserId;
bkInfo.UpdatedUserName = UserManager.Name;
await _bookingOrderRepository.AsUpdateable(bkInfo).UpdateColumns(it => new
{
it.MBLNO,
it.UpdatedTime,
it.UpdatedUserId,
it.UpdatedUserName
}).ExecuteCommandAsync();
result.succ = true;
result.msg = "舱位分配查询成功";
}
else
{
result.succ = false;
result.msg = $"舱位分配查询失败,{rlt.message}";
}
}
catch (Exception ex)
{
result.succ = false;
result.msg = $"舱位分配查询失败,{ex.Message}";
}
return result;
}
#endregion
2 years ago
/// <summary>
/// 提交规则意见
/// </summary>
/// <param name="model">规则意见详情</param>
/// <returns>返回回执</returns>
[HttpPost("/BookingValueAdded/SubmitRuleOpinion")]
public async Task<TaskManageOrderResultDto> SubmitRuleOpinion([FromBody] RulesEngineUserFeedBackDto model)
{
TaskManageOrderResultDto result = new TaskManageOrderResultDto();
string batchNo = IDGen.NextID().ToString();
DateTime nowDate = DateTime.Now;
try
{
if(string.IsNullOrWhiteSpace(model.ruleName))
throw Oops.Oh($"规则名称不能为空");
if (string.IsNullOrWhiteSpace(model.opinionType))
throw Oops.Oh($"意见类型不能为空");
if (string.IsNullOrWhiteSpace(model.opinionContent))
throw Oops.Oh($"意见内容不能为空");
RulesEngineUserFeedBackMessageInfo msgModel = new RulesEngineUserFeedBackMessageInfo();
msgModel.Head = new RulesEngineUserFeedBackHead
{
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 = "Add",
};
msgModel.Main = new RulesEngineUserFeedBackMain
{
ruleName = model.ruleName,
opinionType = model.opinionType,
opinionContent = model.opinionContent,
ruleNotice = model.ruleNotice,
submitUser = UserManager.Name
};
DateTime bDate = DateTime.Now;
var rlt = await ExcuteRuleOpinion(App.Configuration["RulesEngineOpinionUrl"], msgModel, batchNo);
DateTime eDate = DateTime.Now;
TimeSpan ts = eDate.Subtract(bDate);
var timeDiff = ts.TotalMilliseconds;
_logger.LogInformation("批次={no} 请求完成,耗时:{timeDiff}ms. 结果{msg}", batchNo, timeDiff, rlt.succ ? "成功" : "失败");
if (!rlt.succ)
{
throw Oops.Oh($"请求失败,原因={rlt.msg}");
}
result.succ = true;
result.msg = "提交成功";
}
catch (Exception ex)
{
result.succ = false;
result.msg = $"提交规则意见失败,{ex.Message}";
_logger.LogInformation("批次={no} 异常,{msg}", batchNo, ex.Message);
}
return result;
}
/// <summary>
/// 查询规则意见历史
/// </summary>
/// <param name="model">规则意见详情</param>
/// <returns>返回回执</returns>
[HttpPost("/BookingValueAdded/GetRuleOpinionLog")]
public async Task<TaskManageOrderResultDto> GetRuleOpinionLog([FromBody] RulesEngineUserFeedBackDto model)
{
TaskManageOrderResultDto result = new TaskManageOrderResultDto();
string batchNo = IDGen.NextID().ToString();
DateTime nowDate = DateTime.Now;
try
{
RulesEngineUserFeedBackMessageInfo msgModel = new RulesEngineUserFeedBackMessageInfo();
msgModel.Head = new RulesEngineUserFeedBackHead
{
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 = "Add",
};
msgModel.Main = new RulesEngineUserFeedBackMain
{
ruleName = model.ruleName,
opinionType = model.opinionType,
opinionContent = model.opinionContent,
ruleNotice = model.ruleNotice,
submitUser = UserManager.Name
};
DateTime bDate = DateTime.Now;
var rlt = await ExcuteRuleOpinion(App.Configuration["RulesEngineQueryOpinionUrl"], msgModel, batchNo);
DateTime eDate = DateTime.Now;
TimeSpan ts = eDate.Subtract(bDate);
var timeDiff = ts.TotalMilliseconds;
_logger.LogInformation("批次={no} 请求完成,耗时:{timeDiff}ms. 结果{msg}", batchNo, timeDiff, rlt.succ ? "成功" : "失败");
if (!rlt.succ)
{
throw Oops.Oh($"请求失败,原因={rlt.msg}");
}
result.succ = true;
result.msg = "查询成功";
if (rlt.rows != null)
result.rows = JSON.Deserialize<List<RulesEngineUserFeedBackCollectionLogShowDto>>(JSON.Serialize(rlt.rows));
}
catch (Exception ex)
{
result.succ = false;
result.msg = $"查询规则意见历史失败,{ex.Message}";
_logger.LogInformation("批次={no} 异常,{msg}", batchNo, ex.Message);
}
return result;
}
#region 规则用户反馈请求远端
/// <summary>
/// 规则用户反馈请求远端
/// </summary>
/// <param name="url">请求URL</param>
/// <param name="info">请求详情</param>
/// <param name="batchNo">批次号</param>
/// <returns>返回结果</returns>
[NonAction]
private async Task<RulesEngineWebApiResult> ExcuteRuleOpinion(string url, RulesEngineUserFeedBackMessageInfo info, string batchNo)
{
RulesEngineWebApiResult model = null;
/*
1JSON
2POST
3
*/
try
{
_logger.LogInformation("批次={no} 对应请求报文 request={res}", batchNo, JSON.Serialize(info));
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}", batchNo, JSON.Serialize(res));
if (res.StatusCode == System.Net.HttpStatusCode.OK)
{
var userResult = await res.Content.ReadAsStringAsync();
_logger.LogInformation("批次={no} 对应请求报文完成 userResult={userResult}", batchNo, userResult);
model = JSON.Deserialize<RulesEngineWebApiResult>(userResult);
}
}
catch (Exception ex)
{
//写日志
if (ex is HttpRequestException)
throw Oops.Oh(10000002);
}
return model;
}
#endregion
2 years ago
/// <summary>
/// 获取个人或公司网站账户配置
/// </summary>
/// <param name="typeCode">账户类型代码</param>
/// <param name="userId">用户ID</param>
/// <param name="tendId">租户ID</param>
/// <returns>返回账户配置</returns>
private async Task<DjyWebsiteAccountConfig> GetAccountConfig(string typeCode,long userId,long tendId)
{
DjyWebsiteAccountConfig accountConfig = new DjyWebsiteAccountConfig();
accountConfig = await _djyWebsiteAccountConfigRepository.EntityContext.CopyNew().Queryable<DjyWebsiteAccountConfig>()
.FirstAsync(x => x.TypeCode == typeCode && x.CreatedUserId == userId);
if (accountConfig == null)
{
accountConfig = await _djyWebsiteAccountConfigRepository.EntityContext.CopyNew().Queryable<DjyWebsiteAccountConfig>()
.FirstAsync(x => x.TypeCode == typeCode && x.TenantId == tendId && x.IsTenant == true);
}
return accountConfig;
}
2 years ago
/// <summary>
/// 单票BC文件解析
/// </summary>
/// <param name="file">上传文件</param>
/// <param name="bookingOrderId">订舱主键</param>
2 years ago
/// <returns>返回回执</returns>
[HttpPost("/BookingValueAdded/SingleBCFileRead")]
public async Task<TaskManageOrderResultDto> SingleBCFileRead(IFormFile file, [FromForm] long bookingOrderId)
2 years ago
{
TaskManageOrderResultDto result = new TaskManageOrderResultDto();
string batchNo = IDGen.NextID().ToString();
SingleBCDto singleBCDto = null;
try
{
/*
1
2BC
*/
if(bookingOrderId < 0)
throw Oops.Oh($"订舱主键不能为空");
var bookingOrder = _bookingOrderRepository.AsQueryable().First(a => a.Id == bookingOrderId);
if(bookingOrder == null)
throw Oops.Oh($"订舱信息获取失败,订舱信息不存在或已作废");
//获取解析BC文件链接
var bcUrl = _cache.GetAllDictData().GetAwaiter().GetResult()
.FirstOrDefault(x => x.TypeCode == "url_set" && x.Code.Equals(CONST_BC_FILE_PARSE_URL, StringComparison.OrdinalIgnoreCase))?.Value;
_logger.LogInformation("提单号{mbl} 获取解析BC文件URL完成结果={rlt}",
bookingOrder.MBLNO, bcUrl);
if (string.IsNullOrWhiteSpace(bcUrl))
{
_logger.LogInformation("提单号{0} 获取解析BC文件URL失败未取到配置key={key}",
bookingOrder.MBLNO, CONST_BC_FILE_PARSE_URL);
throw Oops.Bah($"未配置请求地址{CONST_BC_FILE_PARSE_URL} 请联系管理员");
}
byte[] bytes = file.ToByteArray();
DateTime bDate = DateTime.Now;
//请求BC解析
var bcParseRlt = await TransmitFile(bcUrl, new
{
file = "file",
fileName = file.FileName,
fileBytes = bytes
});
DateTime eDate = DateTime.Now;
TimeSpan ts = eDate.Subtract(bDate);
var timeDiff = ts.TotalMilliseconds;
_logger.LogInformation("批次={no} result={result} 获取解析BC文件URL结束 耗时:{timeDiff}ms. ", batchNo,
JSON.Serialize(bcParseRlt), timeDiff);
if (bcParseRlt.status == 1)
{
var currBC = bcParseRlt.data.BCList.FirstOrDefault();
if(!string.IsNullOrWhiteSpace(currBC.Vessel) && Regex.IsMatch(currBC.Vessel, "\\(||\\)||\\n"))
{
if(Regex.IsMatch(currBC.Vessel, "\\(||\\)|"))
{
currBC.Vessel = Regex.Match(currBC.Vessel,"\\w+\\s?\\n?\\s?\\w+(?=\\()").Value;
}
if (Regex.IsMatch(currBC.Vessel, "\\n"))
{
currBC.Vessel = Regex.Replace(Regex.Replace(currBC.Vessel, "\\n", " "), "\\s{2,}", " ");
}
}
singleBCDto = new SingleBCDto
{
BookingOrderId = bookingOrderId,
BLNo = currBC.BLNo?.Trim().ToUpper(),
Vessel = currBC.Vessel?.Trim().ToUpper(),
Voyage = currBC.Voyage?.Trim().ToUpper(),
ClosingDate = currBC.CutSingleTime,
CYCutOffTime = currBC.CYCutOffTime,
2 years ago
VGMCutOffTime = currBC.VGMCutOffTime,
ETD = currBC.ETD
};
singleBCDto.BookingOrderBCDto = new BookingOrderBCDto {
MBLNO = bookingOrder.MBLNO,
CUSTNO = bookingOrder.CUSTNO,
CLOSEDOCDATE = bookingOrder.CLOSEDOCDATE,
CLOSEVGMDATE = bookingOrder.CLOSEVGMDATE,
CLOSINGDATE = bookingOrder.CLOSINGDATE,
ETD = bookingOrder.ETD,
VESSEL = bookingOrder.VESSEL,
VOYNO = bookingOrder.VOYNO,
};
2 years ago
/*
*/
//读取文件配置
2 years ago
var fileFullName = await FileAttachHelper.TempSaveWebFile(bookingOrder.Id.ToString(), file, batchNo);
2 years ago
_logger.LogInformation("批次={no} 完成文件保存 filepath={path}", batchNo, fileFullName);
singleBCDto.FileTempPath = fileFullName;
result.succ = true;
result.ext = singleBCDto;
}
else
{
result.succ = false;
result.msg = $"解析BC失败原因{bcParseRlt.message}";
}
}
catch(Exception ex)
{
_logger.LogInformation("批次={no} 解析BC异常原因{error} ", batchNo, ex.Message);
result.succ = false;
result.msg = $"解析BC异常原因{ex.Message}";
}
return result;
}
2 years ago
#region 请求BC解析
/// <summary>
/// 请求BC解析
/// </summary>
/// <param name="requestUrl">请求地址</param>
/// <param name="fileInfo">文件详情</param>
/// <returns>返回BC解析详情</returns>
private async Task<BCAPIBaseDataParse> TransmitFile(string requestUrl, dynamic fileInfo)
{
BCAPIBaseDataParse model = null;
try
{
var response = await requestUrl.SetContentType("multipart/form-data")
2 years ago
.SetBodyBytes((fileInfo.file.ToString(), fileInfo.fileBytes, HttpUtility.UrlEncode(fileInfo.fileName.ToString())))
.PostAsync();
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
var result = response.Content.ReadAsStringAsync().Result;
if (string.IsNullOrWhiteSpace(result))
{
throw Oops.Bah($"获取解析BC文件失败未获取到有效信息");
}
System.Text.Json.JsonSerializerOptions jsonOptions = new JsonSerializerOptions();
jsonOptions.Converters.Add(new DateTimeJsonConverter("yyyy-MM-dd HH:mm:ss"));
jsonOptions.Converters.Add(new IntegerJsonConverter());
jsonOptions.Converters.Add(new DecimalJsonConverter());
model = JSON.Deserialize<BCAPIBaseDataParse>(result, jsonOptions);
}
}
catch (Exception ex)
{
_logger.LogInformation("{name} 发送BC文件解析请求 url={url} 异常,原因={error}", nameof(TransmitFile),
requestUrl, ex.Message);
throw Oops.Bah($"{nameof(TransmitFile)} {requestUrl} 发送BC文件解析请求异常{ex.Message}");
}
return model;
2 years ago
}
2 years ago
#endregion
2 years ago
2 years ago
#region 单票BC更新订舱
2 years ago
/// <summary>
/// 单票BC更新订舱
/// </summary>
/// <param name="model">单票BC详情</param>
/// <returns>返回回执</returns>
[HttpPost("/BookingValueAdded/SingleBCUpdateBookingOrder")]
2 years ago
public async Task<TaskManageOrderResultDto> SingleBCUpdateBookingOrder(SingleBCDto model)
{
TaskManageOrderResultDto result = new TaskManageOrderResultDto();
string batchNo = IDGen.NextID().ToString();
try
{
/*
1BC
2
3
*/
var bookingOrder = _bookingOrderRepository.AsQueryable().First(a => a.Id == model.BookingOrderId);
if (bookingOrder == null)
throw Oops.Bah($"订舱信息获取失败,订舱信息不存在或已作废");
var updateRlt = InnerBCUpdateBookingOrder(model, bookingOrder, batchNo,1).GetAwaiter().GetResult();
if (!updateRlt.succ)
throw Oops.Bah($"订舱信息更新失败,{updateRlt.msg}");
if (model.IsLetterYard)
{
_logger.LogInformation("批次={no} id={id} 单票BC更新订舱后用户选择转为入货通知开始执行入货通知", batchNo
, bookingOrder.Id);
if (string.IsNullOrWhiteSpace(model.FileTempPath))
{
_logger.LogInformation("批次={no} id={id} 未提交文件路径,请求失败", batchNo
, bookingOrder.Id);
throw Oops.Bah($"未提交文件路径,执行放舱失败");
}
var letterYardDto = new UpdateBookingLetteryardInput();
letterYardDto = model.LetteryardDto.Adapt<UpdateBookingLetteryardInput>();
if (model.LetterYardId.HasValue && model.LetterYardId.Value > 0)
{
letterYardDto.Id = model.LetterYardId.Value;
_logger.LogInformation("批次={no} id={id} 单票BC更新订舱后存在放舱记录 LetterYardId={LetterYardId}", batchNo
, bookingOrder.Id, letterYardDto.Id);
}
else
{
var letterYardModel = _bookingLetteryardRepository.AsQueryable()
.First(x => x.BookingId == model.BookingOrderId);
if(letterYardModel != null)
letterYardDto.Id = letterYardModel.Id;
}
//放舱保存
var letterYardId = await _bookingOrderService.LetteryardSave(letterYardDto);
_logger.LogInformation("批次={no} id={id} 已完放舱记录保存 返回结果{rlt}", batchNo
, bookingOrder.Id, letterYardId);
_logger.LogInformation("批次={no} id={id} templateid={tempid} 开始发送放舱", batchNo
, bookingOrder.Id, model.TemplateId);
//发送放舱
await _bookingOrderService.SendLetterYard(model.BookingOrderId, model.TemplateId);
_logger.LogInformation("批次={no} id={id} templateid={tempid} 完成发送放舱", batchNo
, bookingOrder.Id, model.TemplateId);
string fileTypeCode = "bc";
string fileTypeName = "Booking Confirmation";
//重新将暂存文件写入正式路径
//读取文件配置
var bookFilePath = await FileAttachHelper.MoveFile(bookingOrder.Id.ToString(), model.FileTempPath,batchNo);
//将BC引入的文件写入订舱的附件
await SaveEDIFile(bookingOrder.Id, bookFilePath, new System.IO.FileInfo(bookFilePath).Name,
fileTypeCode, fileTypeName);
_logger.LogInformation("批次={no} id={id} 完成写入附件表 {filepath}", batchNo
, bookingOrder.Id, model.FileTempPath);
}
result.succ = true;
result.msg = "执行成功";
}
catch (Exception ex)
{
result.succ = false;
result.msg = ex.Message;
}
return result;
}
#endregion
#region 单票BC更新订舱信息
/// <summary>
/// 单票BC更新订舱信息
/// </summary>
/// <param name="model">BC详情</param>
/// <param name="bookingOrder">订舱详情</param>
/// <param name="batchNo">批次号</param>
/// <param name="sortNo">顺序号</param>
/// <returns>返回回执</returns>
private async Task<TaskManageOrderResultDto> InnerBCUpdateBookingOrder(SingleBCDto model, BookingOrder bookingOrder,
string batchNo,int sortNo)
{
TaskManageOrderResultDto result = new TaskManageOrderResultDto();
result.bno = bookingOrder.MBLNO;
try
{
if (string.IsNullOrWhiteSpace(result.bno))
{
if (!string.IsNullOrWhiteSpace(bookingOrder.CUSTNO))
{
result.bno = $"订 {bookingOrder.CUSTNO}";
}
else
{
result.bno = $"NO.{sortNo}";
}
}
2 years ago
//截单日期
if (model.ClosingDate.HasValue)
2 years ago
{
_logger.LogInformation("批次={no} id={id} 更新截单日期 原:{date1} 变更为 {date2}", batchNo, bookingOrder.Id,
bookingOrder.CLOSEDOCDATE, model.ClosingDate);
2 years ago
bookingOrder.CLOSEDOCDATE = model.ClosingDate;
}
//截VGM时间
if (model.VGMCutOffTime.HasValue)
2 years ago
{
_logger.LogInformation("批次={no} id={id} 更新截VGM日期 原:{date1} 变更为 {date2}", batchNo, bookingOrder.Id,
bookingOrder.CLOSEVGMDATE, model.VGMCutOffTime);
2 years ago
bookingOrder.CLOSEVGMDATE = model.VGMCutOffTime;
}
2 years ago
//截港日期
if (model.CYCutOffTime.HasValue)
2 years ago
{
_logger.LogInformation("批次={no} id={id} 更新截港日期 原:{date1} 变更为 {date2}", batchNo, bookingOrder.Id,
bookingOrder.CLOSINGDATE, model.CYCutOffTime);
2 years ago
bookingOrder.CLOSINGDATE = model.CYCutOffTime;
}
//开船日期
if (model.ETD.HasValue)
2 years ago
{
_logger.LogInformation("批次={no} id={id} 更新截港日期 原:{date1} 变更为 {date2}", batchNo, bookingOrder.Id,
2 years ago
bookingOrder.ETD, model.ETD);
2 years ago
bookingOrder.ETD = model.ETD;
}
2 years ago
//船名
if (!string.IsNullOrWhiteSpace(model.Vessel))
2 years ago
{
_logger.LogInformation("批次={no} id={id} 更新船名 原:{date1} 变更为 {date2}", batchNo, bookingOrder.Id,
bookingOrder.VESSEL, model.Vessel);
2 years ago
bookingOrder.VESSEL = model.Vessel;
}
2 years ago
//航次
if (!string.IsNullOrWhiteSpace(model.Voyage))
2 years ago
{
_logger.LogInformation("批次={no} id={id} 更新航次 原:{date1} 变更为 {date2}", batchNo, bookingOrder.Id,
bookingOrder.VOYNO, model.Voyage);
bookingOrder.VOYNO = model.Voyage;
2 years ago
}
2 years ago
//提单号
if (!string.IsNullOrWhiteSpace(model.BLNo))
{
_logger.LogInformation("批次={no} id={id} 更新提单号 原:{date1} 变更为 {date2}", batchNo, bookingOrder.Id,
bookingOrder.MBLNO, model.BLNo);
bookingOrder.MBLNO = model.BLNo;
}
bookingOrder.UpdatedTime = DateTime.Now;
bookingOrder.UpdatedUserId = UserManager.UserId;
bookingOrder.UpdatedUserName = UserManager.Name;
await _bookingOrderRepository.AsUpdateable(bookingOrder).UpdateColumns(it => new
2 years ago
{
it.UpdatedTime,
it.UpdatedUserId,
it.UpdatedUserName,
it.CLOSEDOCDATE,
it.CLOSEVGMDATE,
it.CLOSINGDATE,
it.ETD,
it.VESSEL,
it.VOYNO,
it.MBLNO
}).ExecuteCommandAsync();
2 years ago
_logger.LogInformation("批次={no} id={id} BC引入更新订舱完成", batchNo, bookingOrder.Id);
result.succ = true;
result.msg = "执行成功";
}
catch (Exception ex)
{
result.succ = false;
result.msg = ex.Message;
}
2 years ago
return result;
}
#endregion
2 years ago
#region 批量BC更新订舱
/// <summary>
/// 批量BC更新订舱
/// </summary>
/// <param name="batchBCList">批量BC更新列表</param>
/// <returns>返回回执</returns>
[HttpPost("/BookingValueAdded/BatchBCUpdate")]
public async Task<TaskManageOrderResultDto> BatchBCUpdate([FromBody]List<BatchBCDto> batchBCList)
{
TaskManageOrderResultDto result = new TaskManageOrderResultDto();
List<Task<TaskManageOrderResultDto>> taskList = new List<Task<TaskManageOrderResultDto>>();
string batchNo = IDGen.NextID().ToString();
2 years ago
try
{
var bcTaskList = batchBCList.Select(a=>a.bcPKId).Distinct().ToList();
var bkOrderList = batchBCList.Select(a => a.bkOrderId.Value).Distinct().ToList();
2 years ago
var bklist = _bookingOrderRepository.AsQueryable()
.Where(a => bkOrderList.Contains(a.Id)).ToList();
2 years ago
var bclist = _taskBCInfoRepository.AsQueryable()
.Where(a => bcTaskList.Contains(a.PK_ID)).ToList();
if (bklist.Count != bkOrderList.Count)
throw Oops.Oh($"订舱信息获取失败,订舱信息不存在或已作废");
var noList = bklist.Select((a, idx) => new { no = idx + 1, id = a.Id }).ToList();
foreach (var bk in bklist)
{
var sortNo = noList.FirstOrDefault(a => a.id == bk.Id).no;
2 years ago
var currBC = batchBCList.Join(bclist, l => l.bcPKId, r => r.PK_ID, (l, r) => {
return r;
}).FirstOrDefault();
SingleBCDto singleBCDto = new SingleBCDto {
BLNo = currBC.MBL_NO,
Vessel = currBC.VESSEL,
Voyage = currBC.VOYNO,
ETD = currBC.ETD,
CYCutOffTime = currBC.CY_CUTOFF_TIME,
VGMCutOffTime = currBC.VGM_CUTOFF_TIME,
ClosingDate = currBC.CUT_SINGLE_TIME
};
taskList.Add(Task.Run(() => InnerBCUpdateBookingOrder(singleBCDto,bk, batchNo, sortNo)));
}
2 years ago
Task.WaitAll(taskList.ToArray());
2 years ago
result.succ = true;
result.msg = "批量执行成功";
2 years ago
var downResultList = taskList.Select(x => x.Result).ToList();
2 years ago
if (downResultList.Any(x => !x.succ))
{
result.succ = false;
result.msg = "批量执行失败";
}
else
{
result.succ = true;
result.msg = downResultList.FirstOrDefault().msg;
}
2 years ago
result.ext = downResultList;
2 years ago
var succ = downResultList.Count(x => x.succ);
var fail = downResultList.Count(x => !x.succ);
2 years ago
if (succ > 0)
{
result.batchTotal = succ.ToString();
}
else
{
result.batchTotal = "- ";
}
2 years ago
if (fail > 0)
{
result.batchTotal += "/" + fail.ToString();
}
else
{
result.batchTotal += " -";
}
}
catch (Exception ex)
{
2 years ago
result.succ = false;
result.msg = $"批量执行失败,原因:{ex.Message}";
}
return result;
2 years ago
}
2 years ago
#endregion
}
public class DateTimeJsonConverter : System.Text.Json.Serialization.JsonConverter<Nullable<DateTime>>
{
private readonly string _dateFormatString;
public DateTimeJsonConverter()
{
_dateFormatString = "yyyy-MM-dd HH:mm:ss";
}
public DateTimeJsonConverter(string dateFormatString)
{
_dateFormatString = dateFormatString;
}
public override Nullable<DateTime> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
DateTime currDate = DateTime.MinValue;
if (DateTime.TryParse(reader.GetString(), out currDate))
return currDate;
return null;
}
public override void Write(Utf8JsonWriter writer, Nullable<DateTime> value, JsonSerializerOptions options)
{
if (value.HasValue)
writer.WriteStringValue(value.Value.ToUniversalTime().ToString(_dateFormatString));
else
writer.WriteNullValue();
}
}
public class IntegerJsonConverter : System.Text.Json.Serialization.JsonConverter<Int32>
{
public IntegerJsonConverter()
{
}
public override Int32 Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType == JsonTokenType.String)
{
var curStr = reader.GetString();
Int32 curVal = 0;
Int32.TryParse(curStr, out curVal);
return curVal;
}
else
{
return reader.GetInt32();
}
}
public override void Write(Utf8JsonWriter writer, Int32 value, JsonSerializerOptions options)
{
writer.WriteNumberValue(value);
}
}
public class DecimalJsonConverter : System.Text.Json.Serialization.JsonConverter<decimal>
{
public DecimalJsonConverter()
{
}
public override decimal Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType == JsonTokenType.String)
{
var curStr = reader.GetString();
decimal curVal = 0;
decimal.TryParse(curStr, out curVal);
return curVal;
}
else
{
return reader.GetDecimal();
}
}
public override void Write(Utf8JsonWriter writer, decimal value, JsonSerializerOptions options)
{
writer.WriteNumberValue(value);
}
}
}