using Furion; using Furion.DependencyInjection; using Furion.DistributedIDGenerator; using Furion.DynamicApiController; using Furion.Extensions; using Furion.FriendlyException; using Furion.JsonSerialization; using Furion.Localization; using Furion.RemoteRequest; using Furion.RemoteRequest.Extensions; using Mapster; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.Extensions.Logging; using Myshipping.Application.EDI; using Myshipping.Application.Entity; using Myshipping.Application.Helper; using Myshipping.Core; using Myshipping.Core.Const; using Myshipping.Core.Entity; using Myshipping.Core.Helper; using Myshipping.Core.Service; using MySqlX.XDevAPI.Common; using NetTaste; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Npoi.Mapper; using NPOI.HPSF; using NPOI.HSSF.UserModel; using NPOI.OpenXmlFormats; using NPOI.OpenXmlFormats.Wordprocessing; using NPOI.POIFS.Crypt.Dsig; using NPOI.SS.Formula.Atp; using NPOI.SS.Formula.Eval; using NPOI.SS.Formula.Functions; using NPOI.SS.UserModel; using NPOI.Util; using NPOI.XSSF.Model; using Org.BouncyCastle.Asn1.Tsp; using Org.BouncyCastle.Asn1.X500; using Org.BouncyCastle.Asn1.X9; using SixLabors.ImageSharp.Processing.Processors.Transforms; using SqlSugar; using StackExchange.Profiling.Internal; using System; using System.Collections.Generic; using System.ComponentModel; using System.DirectoryServices.ActiveDirectory; using System.Dynamic; using System.IO; using System.Linq; using System.Net; using System.Net.Http; using System.Reflection.Metadata.Ecma335; using System.Runtime.InteropServices; using System.Security.Policy; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Xml.Linq; using static Aliyun.OSS.Model.CreateSelectObjectMetaInputFormatModel; using static Aliyun.OSS.Model.ListPartsResult; namespace Myshipping.Application { /// /// 任务管理 /// [ApiDescriptionSettings("Application", Name = "TaskManage", Order = 10)] public class TaskManageService : ITaskManageService, IDynamicApiController, ITransient { private readonly SqlSugarRepository _taskBaseInfoRepository; private readonly SqlSugarRepository _taskSIFeedBackInfoRepository; private readonly SqlSugarRepository _taskSIFeedBackContaInfoRepository; private readonly SqlSugarRepository _taskBillFeeDetailInfoRepository; private readonly SqlSugarRepository _taskFileInfoRepository; private readonly SqlSugarRepository _taskEmailInfoRepository; private readonly SqlSugarRepository _taskVGMFeedBackInfoRepository; private readonly SqlSugarRepository _sysUserRepository; private readonly SqlSugarRepository _taskStatManageInfoRepository; private readonly SqlSugarRepository _taskOriginalDownloadHisInfoRepository; private readonly SqlSugarRepository _taskChargesHisInfoRepository; private readonly SqlSugarRepository _taskLARAPaperInfoRepository; private readonly SqlSugarRepository _taskPerBillBaseInfoRepository; private readonly SqlSugarRepository _taskStoreMsgInfoRepository; private readonly SqlSugarRepository _taskChangeShipHisInfoRepository; private readonly SqlSugarRepository _taskBCInfoRepository; private readonly SqlSugarRepository _taskBCCTNInfoRepository; private readonly SqlSugarRepository _bookingOrderRepository; private readonly SqlSugarRepository _bookingOrderContaRepository; private readonly SqlSugarRepository _bookingOrderContaCargoRepository; private readonly SqlSugarRepository _bookingStatusRepository; private readonly SqlSugarRepository _bookingOrderContactRepository; private readonly SqlSugarRepository _djyUserMailAccountRepository; private readonly SqlSugarRepository _taskTruckInfoRepository; private readonly SqlSugarRepository _taskTruckCtnRepository; private readonly IDjyWebsiteAccountConfigService _webAccountConfig; private readonly ISysCacheService _cache; private readonly ILogger _logger; private readonly ISysDataUserMenu _sysDataUserMenuService; private readonly INamedServiceProvider _namedBookingOrderServiceProvider; const string CONST_WEB_ACCOUNT_TYPE = "CmaWeb"; const string CONST_BOOK_ORIGINAL_DOWN_URL_CODE = "bookOriginalDownUrl"; const string CONST_WEB_LARA_ACCOUNT_TYPE = "LaraWeb"; const string CONST_LARA_DOWN_URL_CODE = "LaraPaperPostUrl"; const string CONST_MAPPING_MODULE = "YunJia"; //LARA纸计算常量 const int LARA_PARER_DRAFT_VAR = 3; public TaskManageService(SqlSugarRepository taskBaseInfoRepository, SqlSugarRepository taskSIFeedBackInfoRepository, SqlSugarRepository taskSIFeedBackContaInfoRepository, SqlSugarRepository taskBillFeeDetailInfoRepository, SqlSugarRepository taskFileInfoRepository, SqlSugarRepository taskEmailInfoRepository, SqlSugarRepository taskVGMFeedBackInfoRepository, SqlSugarRepository sysUserRepository, SqlSugarRepository taskStatManageInfoRepository, SqlSugarRepository taskOriginalDownloadHisInfoRepository, SqlSugarRepository taskChargesHisInfoRepository, SqlSugarRepository bookingOrderRepository, SqlSugarRepository taskLARAPaperInfoRepository, SqlSugarRepository bookingOrderContaRepository, SqlSugarRepository bookingOrderContaCargoRepository, SqlSugarRepository bookingStatusRepository, SqlSugarRepository djyUserMailAccountRepository, SqlSugarRepository taskPerBillBaseInfoRepository, SqlSugarRepository taskStoreMsgInfoRepository, SqlSugarRepository taskChangeShipHisInfoRepository, SqlSugarRepository bookingOrderContactRepository, SqlSugarRepository taskTruckInfoRepository, SqlSugarRepository taskTruckCtnRepository, SqlSugarRepository taskBCInfoRepository, SqlSugarRepository taskBCCTNInfoRepository, INamedServiceProvider namedBookingOrderServiceProvider, IDjyWebsiteAccountConfigService webAccountConfig, ISysCacheService cache, ISysDataUserMenu sysDataUserMenuService, ILogger logger) { _taskBaseInfoRepository = taskBaseInfoRepository; _taskSIFeedBackInfoRepository = taskSIFeedBackInfoRepository; _taskSIFeedBackContaInfoRepository = taskSIFeedBackContaInfoRepository; _taskBillFeeDetailInfoRepository = taskBillFeeDetailInfoRepository; _taskFileInfoRepository = taskFileInfoRepository; _taskEmailInfoRepository = taskEmailInfoRepository; _taskVGMFeedBackInfoRepository = taskVGMFeedBackInfoRepository; _sysUserRepository = sysUserRepository; _taskStatManageInfoRepository = taskStatManageInfoRepository; _taskOriginalDownloadHisInfoRepository = taskOriginalDownloadHisInfoRepository; _taskChargesHisInfoRepository = taskChargesHisInfoRepository; _bookingOrderRepository = bookingOrderRepository; _taskLARAPaperInfoRepository = taskLARAPaperInfoRepository; _bookingOrderContaRepository = bookingOrderContaRepository; _bookingOrderContaCargoRepository = bookingOrderContaCargoRepository; _bookingStatusRepository = bookingStatusRepository; _djyUserMailAccountRepository = djyUserMailAccountRepository; _taskPerBillBaseInfoRepository = taskPerBillBaseInfoRepository; _taskStoreMsgInfoRepository = taskStoreMsgInfoRepository; _taskChangeShipHisInfoRepository = taskChangeShipHisInfoRepository; _bookingOrderContactRepository = bookingOrderContactRepository; _taskTruckInfoRepository = taskTruckInfoRepository; _taskTruckCtnRepository = taskTruckCtnRepository; _taskBCInfoRepository = taskBCInfoRepository; _taskBCCTNInfoRepository = taskBCCTNInfoRepository; _namedBookingOrderServiceProvider = namedBookingOrderServiceProvider; _sysDataUserMenuService = sysDataUserMenuService; _webAccountConfig = webAccountConfig; _cache = cache; _logger = logger; } #region 创建任务 /// /// 创建任务 /// /// 任务详情 /// 返回回执 [AllowAnonymous, HttpPost("/TaskManage/CreateTaskJob")] public async Task CreateTaskJob(TaskManageOrderMessageInfo info) { TaskManageOrderResultDto result = new TaskManageOrderResultDto(); string batchNo = IDGen.NextID().ToString(); _logger.LogInformation("批次={no} 接收到创建任务报文 报文={msg}", batchNo, JSON.Serialize(info)); try { result = await InitTaskJob(info, batchNo); } catch (Exception ex) { result.succ = false; result.msg = $"请求任务异常,{ex.Message}"; } return result; } #endregion #region 新增任务 /// /// 新增任务 /// /// 任务详情 /// 批次号 /// 文件 /// 返回回执 [SqlSugarUnitOfWork] private async Task InitTaskJob(TaskManageOrderMessageInfo info,string batchNo, IFormFile file = null) { TaskManageOrderResultDto result = new TaskManageOrderResultDto(); try { _logger.LogInformation("批次={no} 接收到创建任务报文 开始查询任务 OUT_BUSI_NO={out}", batchNo, $"{info.Head.SenderId}_{info.Head.GID}"); var taskInfo = _taskBaseInfoRepository.AsQueryable().OrderByDescending(a=>a.CreatedTime) .First(t => t.OUT_BUSI_NO == $"{info.Head.SenderId}_{info.Head.GID}"); _logger.LogInformation("批次={no} 接收到创建任务报文 结束查询任务 {msg}", batchNo, taskInfo == null ? "不存在" : "存在"); /* 只要任务最后一次处理任务的状态是已取消、已完成,就可以重入新的任务 */ if (taskInfo != null && taskInfo.STATUS != TaskStatusEnum.Cancel.ToString() && taskInfo.STATUS != TaskStatusEnum.Complete.ToString()) { _logger.LogInformation("批次={no} 状态已存在,不能重复创建任务 status={status}", batchNo, taskInfo.STATUS); throw Oops.Oh($"状态已存在,不能重复创建任务"); } taskInfo = new TaskBaseInfo { PK_ID = IDGen.NextID().ToString(), STATUS = TaskStatusEnum.Create.ToString(), IsDeleted = false, IS_EXCEPT = 0, IS_COMPLETE = 0, MBL_NO = info.Main.MBlNo, TASK_BASE_TYPE = info.Main.TaskType.ToString(), CARRIER_ID = info.Main.CarrierId?.Trim(), IS_PUBLIC = string.IsNullOrWhiteSpace(info.Main.TaskUserId) ? 1 : 0, BOOK_ORDER_NO = info.Main.BookingOrderNo, OUT_BUSI_NO = $"{info.Head.SenderId}_{info.Head.GID}", TASK_TITLE = info.Main.TaskTitle, TASK_DESP = info.Main.TaskDesp, TASK_SOURCE = info.Main.TaskSource.ToString(), TASK_TYPE = info.Main.TaskType.ToString(), VESSEL_VOYNO = info.Main.VesselVoyno?.Trim(), CONTA_INFO = info.Main.ContaInfo, TASK_REQ_USERNAME = info.Main.TaskUserName, YARD_NAME = info.Main.YardName, ETD = info.Main.ETD, CUSTOMER_ID = info.Main.CustomerId, CUSTOMER_NAME = info.Main.CustomerName }; long taskReqUserId = 0; if (!string.IsNullOrWhiteSpace(info.Main.TaskUserId)) { if(long.TryParse(info.Main.TaskUserId,out taskReqUserId)) { taskInfo.TASK_REQ_USERID = taskReqUserId; } } UserTendDto userTendInfo = null; //如果大简云用户ID不为空,接收人为空时,通过大简云用户ID关联订舱人ID if (!string.IsNullOrWhiteSpace(info.Main.DJYRecvUserId) && string.IsNullOrWhiteSpace(info.Main.TaskUserId)) { userTendInfo = GetUserTendInfoByDJYUserId(info.Main.DJYRecvUserId, info.Main.DJYRecvUserEmail); if(userTendInfo != null) { taskInfo.IS_PUBLIC = 0; } } else { userTendInfo = GetUserTendInfo(info.Main.RecvUserId); } taskInfo.CreatedUserId = userTendInfo.userId; taskInfo.CreatedUserName = userTendInfo.userName; taskInfo.TenantId = userTendInfo.tendId; taskInfo.TenantName = userTendInfo.tenantName; _logger.LogInformation("批次={no} 获取登录人详情 userid={userid} userinfo={userinfo}", batchNo, info.Main.RecvUserId, JSON.Serialize(userTendInfo)); taskInfo.CreatedTime = DateTime.Now; taskInfo.UpdatedTime = taskInfo.CreatedTime; if (!string.IsNullOrWhiteSpace(taskInfo.CARRIER_ID) && taskInfo.CARRIER_ID == "MSC") { if (TaskBaseTypeEnum.BC.ToString() == taskInfo.TASK_BASE_TYPE) taskInfo.TASK_TYPE = TaskBusiTypeEnum.MSC_BC.ToString(); if (taskInfo.IS_EXCEPT == 1) taskInfo.TASK_TYPE = TaskBusiTypeEnum.MSC_EXCEPT.ToString(); } //新增 _taskBaseInfoRepository.Insert(taskInfo); if (file != null) { var bytes = file.ToByteArray(); var fileFullName = await FileAttachHelper.SaveFile(taskInfo.PK_ID, bytes, batchNo, file.FileName, GetFileType(file.FileName), "bcfiles"); if (!string.IsNullOrWhiteSpace(fileFullName)) { if (info.Main.FileList == null) { info.Main.FileList = new List(); } info.Main.FileList.Add(new TaskManageOrderFileInfo { PKId = IDGen.NextID().ToString(), FileName = file.FileName, FileType = Path.GetExtension(file.FileName).ToLower(), FilePath = fileFullName }); } } #region 附件 //附件 if (info.Main.FileList != null && info.Main.FileList.Count > 0) { info.Main.FileList.ForEach(async file => { var fileInfo = new TaskFileInfo(); fileInfo.PK_ID = IDGen.NextID().ToString(); fileInfo.TASK_PKID = taskInfo.PK_ID; fileInfo.CreatedTime = taskInfo.CreatedTime; fileInfo.UpdatedTime = taskInfo.CreatedTime; fileInfo.CreatedUserId = taskInfo.CreatedUserId; fileInfo.CreatedUserName = taskInfo.CreatedUserName; fileInfo.TenantId = taskInfo.TenantId; fileInfo.TenantName = taskInfo.TenantName; fileInfo.FILE_PATH = file.FilePath; fileInfo.FILE_NAME = file.FileName; fileInfo.FILE_TYPE = file.FileType; if (TaskBaseTypeEnum.BC.ToString() == taskInfo.TASK_BASE_TYPE) { fileInfo.FILE_CATEGORY = TaskFileCategoryEnum.BC.ToString(); fileInfo.FILE_CATEGORY_NAME = TaskFileCategoryEnum.BC.GetDescription(); } if (string.IsNullOrWhiteSpace(fileInfo.FILE_NAME)) { var fileModel = new FileInfo(file.FilePath); fileInfo.FILE_NAME = fileModel.Name; fileInfo.FILE_TYPE = fileModel.Extension?.Replace(".", ""); } await _taskFileInfoRepository.InsertAsync(fileInfo); }); } #endregion #region 邮件 //邮件 if (info.Main.EmailList != null && info.Main.EmailList.Count > 0) { info.Main.EmailList.ForEach(async email => { var emailInfo = new TaskEmailInfo(); emailInfo.PK_ID = IDGen.NextID().ToString(); emailInfo.TASK_PKID = taskInfo.PK_ID; emailInfo.CreatedTime = taskInfo.CreatedTime; emailInfo.UpdatedTime = taskInfo.CreatedTime; emailInfo.CreatedUserId = taskInfo.CreatedUserId; emailInfo.CreatedUserName = taskInfo.CreatedUserName; emailInfo.TenantId = taskInfo.TenantId; emailInfo.TenantName = taskInfo.TenantName; emailInfo.MAIL_PATH = email.MailPath; await _taskEmailInfoRepository.InsertAsync(emailInfo); }); } #endregion #region SI反馈入库 //SI反馈入库 if (info.Main.TaskType == TaskBaseTypeEnum.SI_FEEDBACK) { if (info.Main.SIFeedBack == null) throw Oops.Oh($"任务类型={info.Main.TaskType.ToString()} SIFeedBack信息必传"); TaskSIFeedBackInfo taskSIFeedBackInfo = info.Main.SIFeedBack.Adapt(); taskSIFeedBackInfo.PK_ID = IDGen.NextID().ToString(); taskSIFeedBackInfo.TASK_PKID = taskInfo.PK_ID; taskSIFeedBackInfo.CreatedTime = taskInfo.CreatedTime; taskSIFeedBackInfo.UpdatedTime = taskInfo.CreatedTime; taskSIFeedBackInfo.CreatedUserId = taskInfo.CreatedUserId; taskSIFeedBackInfo.CreatedUserName = taskInfo.CreatedUserName; taskSIFeedBackInfo.TenantId = taskInfo.TenantId; taskSIFeedBackInfo.TenantName = taskInfo.TenantName; await _taskSIFeedBackInfoRepository.InsertAsync(taskSIFeedBackInfo); //SI反馈箱信息入库 if (info.Main.SIFeedBack.ContaList != null && info.Main.SIFeedBack.ContaList.Count > 0) { info.Main.SIFeedBack.ContaList.ForEach(async ctn => { var contaInfo = ctn.Adapt(); contaInfo.PK_ID = IDGen.NextID().ToString(); contaInfo.P_PKID = taskSIFeedBackInfo.PK_ID; contaInfo.CreatedTime = taskInfo.CreatedTime; contaInfo.UpdatedTime = taskInfo.CreatedTime; contaInfo.CreatedUserId = taskInfo.CreatedUserId; contaInfo.CreatedUserName = taskInfo.CreatedUserName; contaInfo.TenantId = taskInfo.TenantId; contaInfo.TenantName = taskInfo.TenantName; await _taskSIFeedBackContaInfoRepository.InsertAsync(contaInfo); }); } } #endregion #region 费用明细 //费用明细 if (info.Main.TaskType == TaskBaseTypeEnum.INVOICE_BILL_MAIL) { if (info.Main.FeeList != null && info.Main.FeeList.Count > 0) { info.Main.FeeList.ForEach(async fee => { var feeInfo = fee.Adapt(); feeInfo.PK_ID = IDGen.NextID().ToString(); feeInfo.TASK_PKID = taskInfo.PK_ID; feeInfo.CreatedTime = taskInfo.CreatedTime; feeInfo.UpdatedTime = taskInfo.CreatedTime; feeInfo.CreatedUserId = taskInfo.CreatedUserId; feeInfo.CreatedUserName = taskInfo.CreatedUserName; feeInfo.TenantId = taskInfo.TenantId; feeInfo.TenantName = taskInfo.TenantName; await _taskBillFeeDetailInfoRepository.InsertAsync(feeInfo); }); } } #endregion #region 单票账单 if (info.Main.TaskType == TaskBaseTypeEnum.PER_BILL) { TaskPerBillBaseInfo taskPerBillBaseInfo = info.Main.PerBillInfo.Adapt(); //写入 await _taskPerBillBaseInfoRepository.InsertAsync(taskPerBillBaseInfo); if (info.Main.FeeList != null && info.Main.FeeList.Count > 0) { info.Main.FeeList.ForEach(async fee => { var feeInfo = fee.Adapt(); feeInfo.PK_ID = IDGen.NextID().ToString(); feeInfo.TASK_PKID = taskInfo.PK_ID; feeInfo.CreatedTime = taskInfo.CreatedTime; feeInfo.UpdatedTime = taskInfo.CreatedTime; feeInfo.CreatedUserId = taskInfo.CreatedUserId; feeInfo.CreatedUserName = taskInfo.CreatedUserName; feeInfo.TenantId = taskInfo.TenantId; feeInfo.TenantName = taskInfo.TenantName; await _taskBillFeeDetailInfoRepository.InsertAsync(feeInfo); }); } } #endregion #region VGM反馈入库 //VGM反馈入库 if (info.Main.VGMFeedBackList != null && info.Main.VGMFeedBackList.Count > 0) { info.Main.VGMFeedBackList.ForEach(async vgm => { var vgmInfo = vgm.Adapt(); vgmInfo.PK_ID = IDGen.NextID().ToString(); vgmInfo.TASK_PKID = taskInfo.PK_ID; vgmInfo.CreatedTime = taskInfo.CreatedTime; vgmInfo.UpdatedTime = taskInfo.CreatedTime; vgmInfo.CreatedUserId = taskInfo.CreatedUserId; vgmInfo.CreatedUserName = taskInfo.CreatedUserName; vgmInfo.TenantId = taskInfo.TenantId; vgmInfo.TenantName = taskInfo.TenantName; await _taskVGMFeedBackInfoRepository.InsertAsync(vgmInfo); }); } #endregion #region 派车任务 if (info.Main.TaskType == TaskBaseTypeEnum.TRUCK_DISPATCH) { //派车任务 if (info.Main.TruckInfo == null) { throw Oops.Oh($"派车任务主信息不能为空,请查看请求报文"); } var truckInfo = info.Main.TruckInfo.Adapt(); truckInfo.PK_ID = IDGen.NextID().ToString(); truckInfo.TASK_ID = taskInfo.PK_ID; truckInfo.BookingTruckId = info.Main.TruckInfo.Id; truckInfo.CreatedTime = taskInfo.CreatedTime; truckInfo.UpdatedTime = taskInfo.CreatedTime; truckInfo.CreatedUserId = taskInfo.CreatedUserId; truckInfo.CreatedUserName = taskInfo.CreatedUserName; truckInfo.TenantId = taskInfo.TenantId; truckInfo.TenantName = taskInfo.TenantName; truckInfo.Status = BookingTruckStatus.TEMP.ToString(); //异步写入 await _taskTruckInfoRepository.InsertAsync(truckInfo); if(info.Main.TruckInfo.ContaList != null && info.Main.TruckInfo.ContaList.Count > 0) { var contaList = info.Main.TruckInfo.ContaList.Adapt>(); contaList.ForEach(async x => { x.P_ID = truckInfo.PK_ID; x.PK_ID = IDGen.NextID().ToString(); x.CreatedTime = taskInfo.CreatedTime; x.UpdatedTime = taskInfo.CreatedTime; x.CreatedUserId = taskInfo.CreatedUserId; x.CreatedUserName = taskInfo.CreatedUserName; x.TenantId = taskInfo.TenantId; x.TenantName = taskInfo.TenantName; await _taskTruckCtnRepository.InsertAsync(x); }); } } #endregion #region BC 任务 if (info.Main.TaskType == TaskBaseTypeEnum.BC) { //异步写入 var bcInfo = info.Main.BCInfo.Adapt(); bcInfo.PK_ID = IDGen.NextID().ToString(); bcInfo.TASK_ID = taskInfo.PK_ID; bcInfo.CreatedTime = taskInfo.CreatedTime; bcInfo.UpdatedTime = taskInfo.CreatedTime; bcInfo.CreatedUserId = taskInfo.CreatedUserId; bcInfo.CreatedUserName = taskInfo.CreatedUserName; bcInfo.TenantId = taskInfo.TenantId; bcInfo.TenantName = taskInfo.TenantName; await _taskBCInfoRepository.InsertAsync(bcInfo); //异步写入集装箱 info.Main.BCInfo.CtnList.ForEach(async ctn => { var bcCtnInfo = ctn.Adapt(); bcCtnInfo.PK_ID = IDGen.NextID().ToString(); bcCtnInfo.P_ID = bcInfo.PK_ID; bcInfo.CreatedTime = taskInfo.CreatedTime; bcInfo.UpdatedTime = taskInfo.CreatedTime; bcInfo.CreatedUserId = taskInfo.CreatedUserId; bcInfo.CreatedUserName = taskInfo.CreatedUserName; bcInfo.TenantId = taskInfo.TenantId; bcInfo.TenantName = taskInfo.TenantName; await _taskBCCTNInfoRepository.InsertAsync(bcCtnInfo); }); } #endregion if (info.Main.SerialMsgInfo != null) { var storeInfo = new TaskStoreMsgInfo { PK_ID = IDGen.NextID().ToString(), TASK_PKID = taskInfo.PK_ID, MSG_JSON = info.Main.SerialMsgInfo.SerialMsg, MSG_TYPE = info.Main.SerialMsgInfo.SerialType, CreatedTime = taskInfo.CreatedTime, UpdatedTime = taskInfo.CreatedTime, CreatedUserId = taskInfo.CreatedUserId, CreatedUserName = taskInfo.CreatedUserName, TenantId = taskInfo.TenantId, TenantName = taskInfo.TenantName, }; await _taskStoreMsgInfoRepository.InsertAsync(storeInfo); } result.succ = true; result.msg = "新增任务成功"; var md = _taskBaseInfoRepository.AsQueryable().First(a => a.PK_ID == taskInfo.PK_ID); //回写任务号 result.ext = md?.TASK_NO; } catch (Exception ex) { throw Oops.Oh($"{ex.Message}"); } return result; } #endregion #region 查询订舱表查询用户和租户信息 /// /// 查询订舱表查询用户和租户信息 /// /// 用户ID /// 返回用户和租户信息 private UserTendDto GetUserTendInfo(string userId) { UserTendDto userTendDto = null; //这里因为接口是不做授权验证的,所以这里直接写的动态sql提取了用户和租户信息 var userTendInfo = _sysUserRepository.EntityContext.Queryable("user").AS("sys_user") .AddJoinInfo("sys_tenant", "ten", "user.TenantId=ten.Id") .Where("user.Id=@id", new { id = long.Parse(userId) }) .Select("user.Id as UserId,user.Name as UserName,ten.Id as TendId,ten.Name as TendName").First(); if (userTendInfo == null || userTendInfo.TendId == null) throw Oops.Oh("当前用户详情获取失败,请确认{0}赋值是否准确", nameof(TaskManageOrderMessageInfo.Main.TaskUserId)); userTendDto = new UserTendDto { userId = long.Parse(userTendInfo.UserId.ToString()), userName = userTendInfo.UserName.ToString(), tendId = long.Parse(userTendInfo.TendId.ToString()), tenantName = userTendInfo.TendName.ToString() }; return userTendDto; } #endregion #region 查询订舱表查询用户和租户信息 /// /// 查询订舱表查询用户和租户信息 /// /// 大简云用户ID /// 大简云用户邮箱 /// 返回用户和租户信息 private UserTendDto GetUserTendInfoByDJYUserId(string djyUserId,string djyUserEmail) { UserTendDto userTendDto = null; //这里因为接口是不做授权验证的,所以这里直接写的动态sql提取了用户和租户信息 var userTendInfo = _sysUserRepository.EntityContext.Queryable("user").AS("sys_user") .AddJoinInfo("sys_tenant", "ten", "user.TenantId=ten.Id") .Where("user.DjyUserId=@id and user.Email like '%"+ djyUserEmail + "%'", new { id = djyUserId}) .Select("user.Id as UserId,user.Name as UserName,ten.Id as TendId,ten.Name as TendName").First(); if (userTendInfo == null || userTendInfo.TendId == null) throw Oops.Oh("当前用户详情获取失败,请确认{0}赋值是否准确", nameof(TaskManageOrderMessageInfo.Main.TaskUserId)); userTendDto = new UserTendDto { userId = long.Parse(userTendInfo.UserId.ToString()), userName = userTendInfo.UserName.ToString(), tendId = long.Parse(userTendInfo.TendId.ToString()), tenantName = userTendInfo.TendName.ToString() }; return userTendDto; } #endregion #region 获取查询参数 /// /// 获取查询参数 /// /// 参数类型 STATUS-任务状态;TASK_TYPE-任务类型;SOURCE-任务来源 CATEGORY-分类 /// 返回回执 /// TASK_TYPE [HttpGet("/TaskManage/GetParaInfo")] public async Task GetParaInfo([QueryString] string ParaType) { TaskManageOrderResultDto result = new TaskManageOrderResultDto(); try { Dictionary dict = new Dictionary(); if (ParaType == "STATUS") { dict = EnumUtil.GetEnumDictionaryWithKey(typeof(TaskStatusEnum)); } else if (ParaType == "TASK_TYPE") { dict = EnumUtil.GetEnumDictionaryWithKey(typeof(TaskBusiTypeEnum)); } else if (ParaType == "SOURCE") { dict = EnumUtil.GetEnumDictionaryWithKey(typeof(TaskSourceEnum)); } else if (ParaType == "CATEGORY") { dict = EnumUtil.GetEnumDictionaryWithKey(typeof(TaskStatLevelEnum)); } result.succ = true; result.rows = dict.Select(t => new { Code = t.Key, Name = t.Value }).ToList(); } catch (Exception ex) { result.succ = false; result.msg = ex.Message; } return result; } #endregion #region 获取登陆人相关的任务统计信息 /// /// 获取登陆人相关的任务统计信息 /// /// 是否强制计算 /// 返回回执 [HttpGet("/TaskManage/GetCurrentTotalStat")] public async Task GetCurrentTotalStat([FromQuery] bool isReCalc = false) { TaskUserStatResultInfo resultInfo = new TaskUserStatResultInfo { LevelTop = new List(), LevelNext = new List(), LevelTree = new List() }; /* 1、首先判断当前登陆人是否有统计记录,如果没有触发统计生成统计记录。 2、如果isReCalc=true,表示强制重新统计数据,并重新更新统计数据。 3、按照统计类型(个人/公共)、任务状态、是否异常分组汇总,并写入统计表。 */ try { var userTendInfo = await _sysUserRepository.AsQueryable() .LeftJoin((usr, ten) => usr.TenantId == ten.Id) .Where(usr => usr.Id == UserManager.UserId) .Select((usr, ten) => new { User = usr, Tend = ten }).FirstAsync(); if (userTendInfo == null) throw Oops.Oh($"当前用户关联租户信息获取失败"); //var statList = _taskStatManageInfoRepository.AsQueryable().Where(t => (t.USER_ID == userTendInfo.User.Id //&& t.STAT_TYPE == TaskStatLevelEnum.PERSON.ToString()) || (t.COMP_ID == userTendInfo.Tend.Id && t.STAT_TYPE == TaskStatLevelEnum.PUBLIC.ToString())).ToList(); //菜单375504048771141=我的任务台账 List userlist = await _sysDataUserMenuService.GetDataScopeList(MenuConst.MenuTaskManage); bool isAdmin = userlist == null; //任务列表分组统计 var groupList = _taskBaseInfoRepository.AsQueryable() .Where(t => isAdmin || (userlist.Contains(t.CreatedUserId) && t.IS_PUBLIC == 0) || (t.TenantId == userTendInfo.Tend.Id && t.IS_PUBLIC == 1)) .GroupBy(p => new { p.TASK_TYPE, p.STATUS, p.IS_EXCEPT, p.IS_PUBLIC }) .Select(p => new { Total = SqlFunc.AggregateCount(p.PK_ID), TaskType = p.TASK_TYPE, Status = p.STATUS, IsExcept = p.IS_EXCEPT, IsPublic = p.IS_PUBLIC }).ToList(); var exceptList = groupList .Where(t => t.IsExcept == 1).ToList(); var personList = groupList .Where(t => t.IsExcept == 0 && t.IsPublic == 0).ToList(); var publicList = groupList .Where(t => t.IsExcept == 0 && t.IsPublic == 1).ToList(); #region 异常 if (exceptList.Count > 0) { resultInfo.LevelTop.Add(new TaskUserStatItem { Key = TaskStatLevelEnum.EXCPTION.ToString(), Name = TaskStatLevelEnum.EXCPTION.GetDescription(), Total = exceptList.Sum(t => t.Total), SortNo = (int)TaskStatLevelEnum.EXCPTION, ActionKey = TaskStatLevelEnum.EXCPTION.ToString() }); var nextList = new List(); exceptList.GroupBy(t => t.Status) .Select(t => new { Key = t.Key, Total = t.ToList().Sum(p => p.Total) }) .ToList().ForEach(t => { TaskStatusEnum currEnum = (TaskStatusEnum)System.Enum.Parse(typeof(TaskStatusEnum), t.Key); nextList.Add(new TaskUserStatItemNext { TopKey = TaskStatLevelEnum.EXCPTION.ToString(), Key = currEnum.ToString(), Name = currEnum.GetDescription(), Total = t.Total, SortNo = (int)currEnum, ActionKey = $"{TaskStatLevelEnum.EXCPTION.ToString()}#{currEnum.ToString()}" }); }); if (nextList.Count > 0) resultInfo.LevelNext.AddRange(nextList.OrderBy(t => t.SortNo).ToList()); exceptList.GroupBy(t => new { t.Status, t.TaskType }) .Select(t => new { Key = t.Key, Total = t.ToList().Sum(p => p.Total) }) .ToList().ForEach(t => { TaskBusiTypeEnum currEnum = (TaskBusiTypeEnum)System.Enum.Parse(typeof(TaskBusiTypeEnum), t.Key.TaskType); resultInfo.LevelTree.Add(new TaskUserStatItemTree { TopKey = TaskStatLevelEnum.EXCPTION.ToString(), NextKey = t.Key.Status, Key = currEnum.ToString(), Name = currEnum.GetDescription(), Total = t.Total, SortNo = (int)currEnum, ActionKey = $"{TaskStatLevelEnum.EXCPTION.ToString()}#{t.Key.Status}#{currEnum.ToString()}" }); }); } #endregion #region 个人 if (personList.Count > 0) { resultInfo.LevelTop.Add(new TaskUserStatItem { Key = TaskStatLevelEnum.PERSON.ToString(), Name = TaskStatLevelEnum.PERSON.GetDescription(), Total = personList.Sum(t => t.Total), SortNo = (int)TaskStatLevelEnum.PERSON, ActionKey = TaskStatLevelEnum.PERSON.ToString() }); var nextList = new List(); personList.GroupBy(t => t.Status) .Select(t => new { Key = t.Key, Total = t.ToList().Sum(p => p.Total) }) .ToList().ForEach(t => { TaskStatusEnum currEnum = (TaskStatusEnum)System.Enum.Parse(typeof(TaskStatusEnum), t.Key); nextList.Add(new TaskUserStatItemNext { TopKey = TaskStatLevelEnum.PERSON.ToString(), Key = currEnum.ToString(), Name = currEnum.GetDescription(), Total = t.Total, SortNo = (int)currEnum, ActionKey = $"{TaskStatLevelEnum.PERSON.ToString()}#{currEnum.ToString()}" }); }); if (nextList.Count > 0) resultInfo.LevelNext.AddRange(nextList.OrderBy(t => t.SortNo).ToList()); personList.GroupBy(t => new { t.Status, t.TaskType }) .Select(t => new { Key = t.Key, Total = t.ToList().Sum(p => p.Total) }) .ToList().ForEach(t => { TaskBusiTypeEnum currEnum = (TaskBusiTypeEnum)System.Enum.Parse(typeof(TaskBusiTypeEnum), t.Key.TaskType); resultInfo.LevelTree.Add(new TaskUserStatItemTree { TopKey = TaskStatLevelEnum.PERSON.ToString(), NextKey = t.Key.Status, Key = currEnum.ToString(), Name = currEnum.GetDescription(), Total = t.Total, SortNo = (int)currEnum, ActionKey = $"{TaskStatLevelEnum.PERSON.ToString()}#{t.Key.Status}#{currEnum.ToString()}" }); }); } #endregion #region 公共 if (publicList.Count > 0) { resultInfo.LevelTop.Add(new TaskUserStatItem { Key = TaskStatLevelEnum.PUBLIC.ToString(), Name = TaskStatLevelEnum.PUBLIC.GetDescription(), Total = publicList.Sum(t => t.Total), SortNo = (int)TaskStatLevelEnum.PUBLIC, ActionKey = TaskStatLevelEnum.PUBLIC.ToString() }); var nextList = new List(); publicList.GroupBy(t => t.Status) .Select(t => new { Key = t.Key, Total = t.ToList().Sum(p => p.Total) }) .ToList().ForEach(t => { TaskStatusEnum currEnum = (TaskStatusEnum)System.Enum.Parse(typeof(TaskStatusEnum), t.Key); nextList.Add(new TaskUserStatItemNext { TopKey = TaskStatLevelEnum.PUBLIC.ToString(), Key = currEnum.ToString(), Name = currEnum.GetDescription(), Total = t.Total, SortNo = (int)currEnum, ActionKey = $"{TaskStatLevelEnum.PUBLIC.ToString()}#{currEnum.ToString()}" }); }); if (nextList.Count > 0) resultInfo.LevelNext.AddRange(nextList.OrderBy(t => t.SortNo).ToList()); publicList.GroupBy(t => new { t.Status, t.TaskType }) .Select(t => new { Key = t.Key, Total = t.ToList().Sum(p => p.Total) }) .ToList().ForEach(t => { TaskBusiTypeEnum currEnum = (TaskBusiTypeEnum)System.Enum.Parse(typeof(TaskBusiTypeEnum), t.Key.TaskType); resultInfo.LevelTree.Add(new TaskUserStatItemTree { TopKey = TaskStatLevelEnum.PUBLIC.ToString(), NextKey = t.Key.Status, Key = currEnum.ToString(), Name = currEnum.GetDescription(), Total = t.Total, SortNo = (int)currEnum, ActionKey = $"{TaskStatLevelEnum.PUBLIC.ToString()}#{t.Key.Status}#{currEnum.ToString()}" }); }); } #endregion } catch (Exception ex) { throw Oops.Bah("获取登录人相关的任务统计信息异常,{0}", ex.Message); } return resultInfo; } #endregion #region 任务台账查询 /// /// 任务台账查询 /// /// 任务台账查询请求 /// 返回结果 [HttpPost("/TaskManage/GetPage")] public async Task> GetPageAsync(QueryTaskManageDto QuerySearch) { List mblList = new List(); if (!string.IsNullOrWhiteSpace(QuerySearch.MBlNo)) { if (Regex.IsMatch(QuerySearch.MBlNo, "(\\t|\\n\\r|\\n)")) { mblList = Regex.Replace(QuerySearch.MBlNo, "(\\t |\\n\\r |\\n)", "#").Split(new char[] { '#' }).Select(t => t?.Trim()).ToList(); } else { mblList.Add(QuerySearch.MBlNo.Trim().ToUpper()); } } DateTime etdBegin = DateTime.MinValue; DateTime etdEnd = DateTime.MinValue; DateTime taskDateBegin = DateTime.MinValue; DateTime taskDateEnd = DateTime.MinValue; if (!string.IsNullOrWhiteSpace(QuerySearch.ETDBegin)) { if (!DateTime.TryParse(QuerySearch.ETDBegin, out etdBegin)) throw Oops.Oh($"开船起始日期格式错误,{QuerySearch.ETDBegin}"); } if (!string.IsNullOrWhiteSpace(QuerySearch.ETDEnd)) { if (!DateTime.TryParse(QuerySearch.ETDEnd, out etdEnd)) throw Oops.Oh($"开船结束日期格式错误,{QuerySearch.ETDEnd}"); etdEnd = etdEnd.AddDays(1); } if (!string.IsNullOrWhiteSpace(QuerySearch.TaskDateBegin)) { if (!DateTime.TryParse(QuerySearch.TaskDateBegin, out taskDateBegin)) throw Oops.Oh($"任务起始日期格式错误,{QuerySearch.TaskDateBegin}"); } if (!string.IsNullOrWhiteSpace(QuerySearch.TaskDateEnd)) { if (!DateTime.TryParse(QuerySearch.TaskDateEnd, out taskDateEnd)) throw Oops.Oh($"任务结束日期格式错误,{QuerySearch.TaskDateEnd}"); etdEnd = etdEnd.AddDays(1); } string entityOrderCol = "CreatedTime"; //这里因为返回给前端的台账数据是DTO,所以这里排序时候需要转换成Entity对应的字段 if (!string.IsNullOrWhiteSpace(QuerySearch.SortField)) entityOrderCol = MapsterExtHelper.GetAdaptProperty(QuerySearch.SortField); //菜单375504048771141=我的任务台账 List userlist = await _sysDataUserMenuService.GetDataScopeList(MenuConst.MenuTaskManage); if (userlist == null) userlist = new List { UserManager.UserId }; if (userlist.Count > 0) userlist = userlist.Distinct().ToList(); _logger.LogInformation("任务台账权限范围 {list}", userlist); var entities = await _taskBaseInfoRepository.AsQueryable() .Where(t=> userlist.Contains(t.CreatedUserId)) .WhereIF(!string.IsNullOrWhiteSpace(QuerySearch.MBlNo), t => mblList.Contains(t.MBL_NO)) .WhereIF(!string.IsNullOrWhiteSpace(QuerySearch.TaskRecvName), t => t.CreatedUserName.Contains(QuerySearch.TaskRecvName.Trim())) .WhereIF(etdBegin != DateTime.MinValue, t => t.ETD.HasValue && t.ETD.Value >= etdBegin) .WhereIF(etdEnd != DateTime.MinValue, t => t.ETD.HasValue && t.ETD.Value < etdEnd) .WhereIF(taskDateBegin != DateTime.MinValue, t => t.CreatedTime >= taskDateBegin) .WhereIF(taskDateEnd != DateTime.MinValue, t => t.CreatedTime < taskDateEnd) .WhereIF(!string.IsNullOrWhiteSpace(QuerySearch.TaskType), t => t.TASK_TYPE.Equals(QuerySearch.TaskType)) .WhereIF(!string.IsNullOrWhiteSpace(QuerySearch.TaskSource), t => t.TASK_SOURCE.Equals(QuerySearch.TaskSource)) .WhereIF(!string.IsNullOrWhiteSpace(QuerySearch.TaskCategory) && QuerySearch.TaskCategory == TaskStatLevelEnum.EXCPTION.ToString(), t => t.IS_EXCEPT == 1) .WhereIF(!string.IsNullOrWhiteSpace(QuerySearch.TaskCategory) && QuerySearch.TaskCategory == TaskStatLevelEnum.PUBLIC.ToString(), t => t.IS_PUBLIC == 1) .WhereIF(!string.IsNullOrWhiteSpace(QuerySearch.TaskCategory) && QuerySearch.TaskCategory == TaskStatLevelEnum.PERSON.ToString(), t => t.IS_PUBLIC == 0 && t.IS_EXCEPT == 0) .WhereIF(!string.IsNullOrWhiteSpace(QuerySearch.Status), t => t.STATUS.Equals(QuerySearch.Status)) .WhereIF(!string.IsNullOrWhiteSpace(QuerySearch.PKId), t => t.PK_ID.Equals(QuerySearch.PKId)) .OrderBy(entityOrderCol + (QuerySearch.descSort ? " desc " : " asc ")) .ToPagedListAsync(QuerySearch.PageNo, QuerySearch.PageSize); return entities.Adapt>(); } #endregion #region 下载正本提单(可批量) /// /// 下载正本提单(可批量) /// /// 任务主键数组 /// 返回结果 [HttpPost("/TaskManage/DownloadOriginalTask")] public async Task DownloadOriginalTask(string[] PKIds) { TaskManageOrderResultDto result = new TaskManageOrderResultDto(); string batchNo = IDGen.NextID().ToString(); _logger.LogInformation("批次={no} ids={ids} 下载正本提单开始", batchNo, string.Join(",", PKIds)); try { var taskList = _taskBaseInfoRepository.AsQueryable().Where(t => PKIds.Contains(t.PK_ID)).ToList(); _logger.LogInformation("批次={no} 获取任务完成,Num={Num}", batchNo, taskList.Count); //获取个人对应的账户,这里GetAccountConfig逻辑优先取个人,个人没有配置取公司对应配置 var userWebAccountConfig = _webAccountConfig.GetAccountConfig(CONST_WEB_ACCOUNT_TYPE, UserManager.UserId).GetAwaiter().GetResult(); _logger.LogInformation("批次={no} 获取获取网站的账户完成,result={Num}", batchNo, JSON.Serialize(userWebAccountConfig)); if (userWebAccountConfig == null) throw Oops.Bah($"个人/公司网站【{CONST_WEB_ACCOUNT_TYPE}】获取失败,请维护个人/公司网站账户信息"); taskList.ForEach(async tsk => { await InnerDownloadOriginalTask(batchNo, tsk, userWebAccountConfig); }); } catch (Exception ex) { throw Oops.Bah("下载正本提单异常,{0}", ex.Message); } return result; } #endregion #region 单票正本下载 /// /// 单票正本下载 /// /// 批次号 /// 任务详情 /// 网站账户配置 /// 返回回执 private async Task InnerDownloadOriginalTask(string batchNo, TaskBaseInfo taskBaseInfo, DjyWebsiteAccountConfig webAccountConfig) { var result = new TaskManageOrderResultDto(); /* 1、TaskOriginalDownloadHisInfo表中处理任务是succ/temp不允许重复下载。failure/timeout的记录可以再次发起下载。 2、从任务表提取RESULT_NOTE回执信息,里面包含了JSON数据 {"pageUrl":"http://www.cnc-ebusiness.com/ebusiness/bl/detail/AASM104300"} 3、异步请求正本下载的链接,有超时时间。 4、下载完成后写入记录 */ //正本下载URL string originalUrl = string.Empty; try { var hisList = _taskOriginalDownloadHisInfoRepository .Where(t => t.TASK_ID == taskBaseInfo.PK_ID).ToList(); if (hisList.Any(t => new string[] { "succ", "temp" }.Contains(t.STATUS))) throw Oops.Bah("下载URL不存在,请用最新任务数据"); if (string.IsNullOrWhiteSpace(taskBaseInfo.RESULT_NOTE)) throw Oops.Bah("下载URL不存在,请用最新任务数据"); var resultObj = JSON.Deserialize(taskBaseInfo.RESULT_NOTE); originalUrl = resultObj.pageUrl.ToString(); if (string.IsNullOrWhiteSpace(originalUrl)) throw Oops.Bah("解析下载URL不存在,请用最新任务数据"); DateTime startDate = DateTime.Now; var downloadUrl = _cache.GetAllDictData().GetAwaiter().GetResult() .First(t => t.Code.Equals(CONST_BOOK_ORIGINAL_DOWN_URL_CODE, StringComparison.OrdinalIgnoreCase))?.Value; if (string.IsNullOrWhiteSpace(downloadUrl)) throw Oops.Bah($"正本下载URL不存在,请确认字典是否配置 code={CONST_BOOK_ORIGINAL_DOWN_URL_CODE}"); TaskOriginalDownloadHisInfo taskOriginalDownloadHisInfo = new TaskOriginalDownloadHisInfo { PK_ID = IDGen.NextID().ToString(), TASK_ID = taskBaseInfo.PK_ID, REQUEST_URL = originalUrl, CreatedUserId = UserManager.UserId, CreatedUserName = UserManager.Name, STATUS = "temp", IS_TIMEOUT = 0, START_DATE = startDate, TenantId = UserManager.TENANT_ID, TenantName = UserManager.TENANT_NAME }; //写入记录 _taskOriginalDownloadHisInfoRepository.Insert(taskOriginalDownloadHisInfo); //请求远程链接 Dictionary formDict = new Dictionary { {"bno", taskBaseInfo.MBL_NO }, {"page_url", downloadUrl }, {"web_user", webAccountConfig.Account }, {"web_pwd", webAccountConfig.Password }, {"web_pwd", "myshipping_task" }, {"web_pwd", "" } }; //请求下载正本 var postResult = await InnerRemoteDownOriginal(batchNo, downloadUrl, formDict); //重新获取下载历史 var downloadHisInfo = _taskOriginalDownloadHisInfoRepository.AsQueryable() .First(t => t.PK_ID == taskOriginalDownloadHisInfo.PK_ID); //更新任务状态 var taskModel = _taskBaseInfoRepository.AsQueryable().First(t => t.PK_ID == taskBaseInfo.PK_ID); downloadHisInfo.END_DATE = (DateTime)postResult.ext; downloadHisInfo.RESULT_NOTE = postResult.msg; bool isDownSucc = false; //下载返回成功后,更新记录并生成扣费记录 if (postResult.succ) { downloadHisInfo.STATUS = "succ"; downloadHisInfo.RESULT_URL = postResult.msg; taskModel.COMPLETE_DEAL = TaskCompleteDealEnum.MANUAL.ToString(); taskModel.COMPLETE_DEAL_NAME = TaskCompleteDealEnum.MANUAL.GetDescription(); taskModel.COMPLETE_DATE = DateTime.Now; taskModel.STATUS = TaskStatusEnum.Complete.ToString(); taskModel.IS_COMPLETE = 1; isDownSucc = true; } else { if (postResult.isTimeout) { downloadHisInfo.STATUS = "timeout"; } else { downloadHisInfo.STATUS = "failure"; } } //更新下载历史 await _taskOriginalDownloadHisInfoRepository.AsUpdateable(downloadHisInfo).IgnoreColumns(it => new { it.TenantId, it.CreatedUserId, it.CreatedUserName }).ExecuteCommandAsync(); //异步扣费,这里不管是否失败都生成扣费记录,只在状态上做标识。 var chargeResult = await InnerChargeFee(taskBaseInfo, isDownSucc); _taskBaseInfoRepository.AsUpdateable(taskModel).UpdateColumns(it => new { it.COMPLETE_DATE, it.COMPLETE_DEAL, it.COMPLETE_DEAL_NAME }).ExecuteCommand(); } catch (Exception ex) { result.succ = false; result.msg = ex.Message; } return result; } #endregion #region 远程请求正本下载 /// /// 远程请求正本下载 /// /// 批次号 /// 请求URL /// 请求参数 /// private async Task InnerRemoteDownOriginal(string batchNo, string url, Dictionary dic) { var result = new TaskManageOrderResultDto(); DateTime bDate = DateTime.Now; try { _logger.LogInformation("批次={no} 请求报文开始", batchNo); var res = await url.SetHttpMethod(HttpMethod.Post) .SetBody(dic, "application/x-www-form-urlencoded") .SetContentEncoding(Encoding.UTF8) .PostAsync(); DateTime eDate = DateTime.Now; TimeSpan ts = eDate.Subtract(bDate); var timeDiff = ts.TotalMilliseconds; _logger.LogInformation("批次={no} 请求完成,耗时:{timeDiff}ms. 结果{msg}", batchNo, timeDiff, JSON.Serialize(res)); if (res.StatusCode == System.Net.HttpStatusCode.OK) { var userResult = await res.Content.ReadAsStringAsync(); var downResult = JSON.Deserialize(userResult); //返回详情 result.msg = downResult.message.ToString(); //返回代码 if (downResult.status.ToString() == "1") { result.succ = true; } else { result.succ = false; } } result.ext = eDate; } catch (Exception ex) { //如果有异常直接抛出错误 throw Oops.Bah(ex.Message); } return result; } #endregion #region 扣费 /// /// 扣费 /// /// 任务信息 /// 是否执行扣费 true-执行扣费 false-不执行扣费(主要是符合扣费条件但是由于超时没有得到准确回执) /// 返回回执 private async Task InnerChargeFee(TaskBaseInfo taskBaseInfo, bool isCharge = true) { TaskManageOrderResultDto result = new TaskManageOrderResultDto { succ = false }; try { decimal balance = 0; decimal price = 0; decimal total = 0; TaskChargesHisInfo model = new TaskChargesHisInfo { PK_ID = IDGen.NextID().ToString(), TASK_ID = taskBaseInfo.PK_ID, BEFORE_BALANCE = balance, PRICE = price, BUSI_TYPE = "21", BUSI_TYPE_NAME = String.Empty, SEND_TYPE = "1001", SEND_TYPE_NAME = String.Empty, REMARK = "正本下载", QTY = 1, TOTAL_AMOUNT = total, }; if (!isCharge) { model.STATUS = TaskChargeStatusEnum.UNKNOW_RESULT.ToString(); model.STATUS_NAME = TaskChargeStatusEnum.UNKNOW_RESULT.GetDescription(); } //写入记录 await _taskChargesHisInfoRepository.InsertAsync(model); result.succ = false; result.msg = "扣费失败"; } catch (Exception ex) { result.succ = false; result.msg = ex.Message; } return result; } #endregion #region 完成任务(可批量) /// /// 完成任务(可批量) /// /// 任务主键数组 /// 返回结果 [HttpPost("/TaskManage/CompleteTask")] public async Task CompleteTask([FromBody] string[] PKIds) { TaskManageOrderResultDto result = new TaskManageOrderResultDto(); List taskRunList = new List(); string batchNo = IDGen.NextID().ToString(); _logger.LogInformation("批次={no} ids={ids} 完成任务开始", batchNo, string.Join(",", PKIds)); try { var taskList = _taskBaseInfoRepository.AsQueryable().Where(t => PKIds.Contains(t.PK_ID)).ToList(); _logger.LogInformation("批次={no} 获取任务完成,Num={Num}", batchNo, taskList.Count); var noList = PKIds.Select((a, idx) => new { no = idx + 1, id = a }).ToList(); foreach (var bk in taskList) { var sortNo = noList.FirstOrDefault(a => a.id == bk.PK_ID).no; taskRunList.Add(InnerManualTask(batchNo,bk, TaskOperTypeEnum.COMPLETE_TASK, sortNo).GetAwaiter().GetResult()); } //Task.WaitAll(taskRunList.ToArray()); result.succ = true; result.msg = "执行成功"; var downResultList = taskRunList.Select(x => x).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) { result.batchTotal = succ.ToString(); } else { result.batchTotal = "- "; } if (fail > 0) { result.batchTotal += "/" + fail.ToString(); } else { result.batchTotal += " -"; } } catch (Exception ex) { result.succ = false; result.msg = $"执行异常,原因:{ex.Message}"; } return result; } #endregion #region 单票执行任务 /// /// 单票执行任务 /// /// 批次号 /// 任务详情 /// 操作类型 /// 顺序号 /// 返回回执 private async Task InnerManualTask(string batchNo, TaskBaseInfo model, TaskOperTypeEnum taskOperTypeEnum, int sortNo) { TaskManageOrderResultDto result = new TaskManageOrderResultDto(); result.bno = model.TASK_NO; try { //var model = _taskBaseInfoRepository.Context.CopyNew().Queryable().First(t => t.PK_ID == taskBaseInfo.PK_ID); if (taskOperTypeEnum == TaskOperTypeEnum.COMPLETE_TASK) { if(model.TASK_TYPE == TaskBusiTypeEnum.TRUCK_DISPATCH.ToString()) { if(model.STATUS == TaskStatusEnum.Cancel.ToString()) { throw Oops.Bah($"当前状态是{TaskStatusEnum.Cancel.GetDescription()} 不能执行完成"); } } if (model.TASK_TYPE == TaskBusiTypeEnum.CANCELLATION.ToString()) { //收到订舱已被取消邮件后生成的任务,如果点击完成,(订舱状态变为【退舱】,注意这里还需要确认) } model.COMPLETE_DATE = DateTime.Now; model.COMPLETE_DEAL = TaskCompleteDealEnum.MANUAL.ToString(); model.COMPLETE_DEAL = TaskCompleteDealEnum.MANUAL.GetDescription(); model.IS_COMPLETE = 1; model.STATUS = TaskStatusEnum.Complete.ToString(); model.STATUS_NAME = TaskStatusEnum.Complete.GetDescription(); await _taskBaseInfoRepository.AsUpdateable(model).UpdateColumns(it => new { it.COMPLETE_DATE, it.COMPLETE_DEAL, it.COMPLETE_DEAL_NAME, it.IS_COMPLETE, it.STATUS, it.STATUS_NAME }).ExecuteCommandAsync(); } else if (taskOperTypeEnum == TaskOperTypeEnum.CANCEL_TASK) { if (model.TASK_TYPE == TaskBusiTypeEnum.CHANGE_SHIP.ToString()) { model.STATUS = TaskStatusEnum.Cancel.ToString(); model.STATUS_NAME = TaskStatusEnum.Cancel.GetDescription(); await _taskBaseInfoRepository.AsUpdateable(model).UpdateColumns(it => new { it.COMPLETE_DATE, it.COMPLETE_DEAL, it.COMPLETE_DEAL_NAME, it.IS_COMPLETE, it.STATUS, it.STATUS_NAME }).ExecuteCommandAsync(); } else if (model.TASK_TYPE == TaskBusiTypeEnum.ABORT_CHANGE_SHIP.ToString()) { /* 1.如果原换船通知已经接受,需要把原船名航次恢复并通知客户取消换船。 2.如果原换船通知未作处理,点击接受或者结束任务时提示:本票货存在未处理换船通知,请先结束原换船任务然后结束本任务。 3.如果原换船任务为结束任务,在取消换船任务点接受时,提示未做换船,请点击结束任务。 */ //查询同票主单的是否有未处理的换船通知 //_taskBaseInfoRepository.AsQueryable().Where(t=>t.MBL_NO.Equals(taskBaseInfo.MBL_NO) && ) } else { model.STATUS = TaskStatusEnum.Cancel.ToString(); model.STATUS_NAME = TaskStatusEnum.Cancel.GetDescription(); model.UpdatedTime = DateTime.Now; model.UpdatedUserId = UserManager.UserId; model.UpdatedUserName = UserManager.Name; await _taskBaseInfoRepository.AsUpdateable(model).UpdateColumns(it => new { it.UpdatedTime, it.UpdatedUserId, it.UpdatedUserName, it.STATUS, it.STATUS_NAME }).ExecuteCommandAsync(); } } result.succ = true; result.msg = "执行成功"; } catch (Exception ex) { result.succ = false; result.msg = ex.Message; } return result; } #endregion #region 取消任务(可批量) /// /// 取消任务(可批量) /// /// 任务主键数组 /// 返回结果 [HttpPost("/TaskManage/CancelTask")] public async Task CancelTask([FromBody] string[] PKIds) { TaskManageOrderResultDto result = new TaskManageOrderResultDto(); string batchNo = IDGen.NextID().ToString(); List taskRunList = new List(); _logger.LogInformation("批次={no} ids={ids} 取消任务开始", batchNo, string.Join(",", PKIds)); try { var taskList = _taskBaseInfoRepository.AsQueryable().Where(t => PKIds.Contains(t.PK_ID)).ToList(); _logger.LogInformation("批次={no} 获取任务完成,Num={Num}", batchNo, taskList.Count); var noList = PKIds.Select((a, idx) => new { no = idx + 1, id = a }).ToList(); foreach (var bk in taskList) { var sortNo = noList.FirstOrDefault(a => a.id == bk.PK_ID).no; taskRunList.Add(InnerManualTask(batchNo, bk, TaskOperTypeEnum.CANCEL_TASK, sortNo).GetAwaiter().GetResult()); } //Task.WaitAll(taskRunList.ToArray()); result.succ = true; result.msg = "执行成功"; var downResultList = taskRunList.Select(x => x).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) { result.batchTotal = succ.ToString(); } else { result.batchTotal = "- "; } if (fail > 0) { result.batchTotal += "/" + fail.ToString(); } else { result.batchTotal += " -"; } } catch (Exception ex) { throw Oops.Bah("执行异常,{0}", ex.Message); } return result; } #endregion #region 挂起任务(可批量) /// /// 挂起任务(可批量) /// /// 任务主键数组 /// 返回结果 [HttpPost("/TaskManage/PendingTask")] public async Task PendingTask(string[] PKIds) { TaskManageOrderResultDto result = new TaskManageOrderResultDto(); string batchNo = IDGen.NextID().ToString(); _logger.LogInformation("批次={no} ids={ids} 挂起任务开始", batchNo, string.Join(",", PKIds)); List taskRunList = new List(); try { var taskList = _taskBaseInfoRepository.AsQueryable().Where(t => PKIds.Contains(t.PK_ID)).ToList(); _logger.LogInformation("批次={no} 获取任务完成,Num={Num}", batchNo, taskList.Count); var noList = PKIds.Select((a, idx) => new { no = idx + 1, id = a }).ToList(); foreach (var bk in taskList) { var sortNo = noList.FirstOrDefault(a => a.id == bk.PK_ID).no; taskRunList.Add(InnerManualTask(batchNo, bk, TaskOperTypeEnum.PENDING_TASK, sortNo).GetAwaiter().GetResult()); } //Task.WaitAll(taskRunList.ToArray()); result.succ = true; result.msg = "执行成功"; var downResultList = taskRunList.Select(x => x).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) { result.batchTotal = succ.ToString(); } else { result.batchTotal = "- "; } if (fail > 0) { result.batchTotal += "/" + fail.ToString(); } else { result.batchTotal += " -"; } } catch (Exception ex) { throw Oops.Bah("完成任务异常,{0}", ex.Message); } return result; } #endregion #region 提单纸页数计算 /// /// 提单纸页数计算 /// /// 任务主键数组 /// 返回结果 [HttpPost("/TaskManage/LaraPaperCalc")] public async Task> LaraPaperCalc(string[] PKIds) { List list = new List(); string batchNo = IDGen.NextID().ToString(); _logger.LogInformation("批次={no} ids={ids} 提单纸页数计算开始", batchNo, string.Join(",", PKIds)); try { //根据任务主键获取所有主单号列表 var mblnoList = _taskBaseInfoRepository.AsQueryable().Where(t => PKIds.Contains(t.PK_ID) && !string.IsNullOrWhiteSpace(t.MBL_NO)) .Select(t => t.MBL_NO).Distinct().ToList(); if (mblnoList.Count > 0) { //根据主单号获取任务类型是DRAFT的任务,取时间最新的 var fileList = _taskBaseInfoRepository.EntityContext.Queryable() .InnerJoin((tsk, file) => tsk.PK_ID == file.TASK_PKID) .Where((tsk, file) => tsk.TASK_TYPE == TaskBusiTypeEnum.DRAFT.ToString() && mblnoList.Contains(tsk.MBL_NO)) .Select((tsk, file) => new { tsk = tsk, file = file }).ToList(); var calcList = fileList.GroupBy(t => t.tsk.PK_ID) .Select(a => { var currList = a.ToList(); return new { tsk = currList.FirstOrDefault().tsk, clist = a.Select(x => x.file).ToList() }; }).OrderByDescending(t => t.tsk.CreatedTime).ToList(); list = mblnoList.Select((mbl, idx) => { var calcInfo = new LaraPaperCalcInfo(); calcInfo.MBLNo = mbl; calcInfo.Indx = idx + 1; var files = calcList.FirstOrDefault(t => t.tsk.MBL_NO.Equals(mbl, StringComparison.OrdinalIgnoreCase)); if (files != null) { calcInfo.DraftNum = files.clist.Select(t => t.FILE_NAME.GetPageNum()).Sum(); } calcInfo.PaperNum = calcInfo.DraftNum * 3; return calcInfo; }).ToList(); } } catch (Exception ex) { throw Oops.Bah("提单纸页数计算异常,{0}", ex.Message); } return list; } #endregion #region 请求提单纸登记 /// /// 请求提单纸登记 /// /// 提单纸登记请求参数列表 /// 返回结果 [HttpPost("/TaskManage/LaraPaperRegistPost")] public async Task LaraPaperRegistPost(List laraPaperList) { TaskManageOrderResultDto result = new TaskManageOrderResultDto(); string batchNo = IDGen.NextID().ToString(); _logger.LogInformation("批次={no} num={num} LARA提单纸登记开始", batchNo, laraPaperList.Count); /* 1、读取LARA网站的配置账户。 2、读取字典的URL。 3、组织请求参数。 4、写入TASK_LARA_PAPER。 5、远程请求。 6、更新状态 */ try { var taskArg = laraPaperList.Select(t => t.TaskId).Distinct().ToArray(); var taskList = _taskBaseInfoRepository.AsQueryable().Where(t => taskArg.Contains(t.PK_ID)).ToList(); _logger.LogInformation("批次={no} 获取任务完成", batchNo); //获取个人对应的账户,这里GetAccountConfig逻辑优先取个人,个人没有配置取公司对应配置 var userWebAccountConfig = _webAccountConfig.GetAccountConfig(CONST_WEB_LARA_ACCOUNT_TYPE, UserManager.UserId).GetAwaiter().GetResult(); _logger.LogInformation("批次={no} 获取获取网站的账户完成,result={Num}", batchNo, JSON.Serialize(userWebAccountConfig)); if (userWebAccountConfig == null) throw Oops.Bah($"个人/公司网站【{CONST_WEB_LARA_ACCOUNT_TYPE}】获取失败,请维护个人/公司网站账户信息"); var downloadUrl = _cache.GetAllDictData().GetAwaiter().GetResult() .First(t => t.Code.Equals(CONST_LARA_DOWN_URL_CODE, StringComparison.OrdinalIgnoreCase))?.Value; if (string.IsNullOrWhiteSpace(downloadUrl)) throw Oops.Bah($"LARA纸下载URL不存在,请确认字典是否配置 code={CONST_LARA_DOWN_URL_CODE}"); JObject jobjPost = new JObject(); jobjPost.Add("customer_user", "myshipping"); jobjPost.Add("customer_pwd", ""); JArray jarr = new JArray(); jobjPost.Add("lara_list", jarr); laraPaperList.ForEach(async lara => { TaskLARAPaperInfo taskLARAPaperInfo = new TaskLARAPaperInfo { PK_ID = IDGen.NextID().ToString(), TASK_ID = lara.TaskId, BOOKING_ORDER_NO = "", CreatedUserId = UserManager.UserId, CreatedUserName = UserManager.Name, STATUS = "temp", IS_TIMEOUT = 0, START_DATE = DateTime.Now, TenantId = UserManager.TENANT_ID, TenantName = UserManager.TENANT_NAME, PAGE_NUMBERS = lara.PageNumbers, PAGE_SUM = lara.PageSum, ISSUE_TYPE = lara.ISSUETYPE, MBL_NO = lara.MBLNO, NUMBER_FROM = lara.NumberFrom, NUMBER_TO = lara.NumberTo, DRAFT_NUM = lara.DraftNum, }; //写入记录 await _taskLARAPaperInfoRepository.InsertAsync(taskLARAPaperInfo); JObject jobjItem = new JObject(); jobjItem.Add("customer_user", "myshipping"); jobjItem.Add("customer_pwd", ""); jobjItem.Add("web_user", userWebAccountConfig.Account); jobjItem.Add("web_pwd", userWebAccountConfig.Password); jobjItem.Add("bno", lara.MBLNO); jobjItem.Add("num_from", lara.NumberFrom); jobjItem.Add("num_to", lara.NumberTo); jobjItem.Add("numbers", lara.PageNumbers); jobjItem.Add("vessel_code", ""); jobjItem.Add("voyage_code", ""); jobjItem.Add("bl_status", "All"); jobjItem.Add("bl_type", "Original Bill"); jobjItem.Add("issue_code", "ALL"); jarr.Add(jobjItem); }); //await InnerDownloadOriginalTask(batchNo, taskInfo, userWebAccountConfig); var postResult = await InnerRemoteDownLaraPaper(batchNo, downloadUrl, JSON.Serialize(jobjPost)); if (postResult.succ) { result.succ = true; result.msg = "成功"; } else { result.succ = false; result.msg = postResult.msg; } } catch (Exception ex) { throw Oops.Bah("请求提单纸登记异常,{0}", ex.Message); } return result; } #endregion #region 远程请求请求提单纸登记 /// /// 远程请求请求提单纸登记 /// /// 批次号 /// 请求URL /// 请求参数 /// private async Task InnerRemoteDownLaraPaper(string batchNo, string url, string jsonMsg) { var result = new TaskManageOrderResultDto(); DateTime bDate = DateTime.Now; try { _logger.LogInformation("批次={no} 请求报文开始", batchNo); var res = await url.SetHttpMethod(HttpMethod.Post) .SetBody(jsonMsg, "application/json") .SetContentEncoding(Encoding.UTF8) .PostAsync(); DateTime eDate = DateTime.Now; TimeSpan ts = eDate.Subtract(bDate); var timeDiff = ts.TotalMilliseconds; _logger.LogInformation("批次={no} 请求完成,耗时:{timeDiff}ms. 结果{msg}", batchNo, timeDiff, JSON.Serialize(res)); if (res.StatusCode == System.Net.HttpStatusCode.OK) { var userResult = await res.Content.ReadAsStringAsync(); var downResult = JSON.Deserialize(userResult); //返回详情 result.msg = downResult.message.ToString(); //返回代码 if (downResult.status.ToString() == "1") { result.succ = true; } else { result.succ = false; } } result.ext = eDate; } catch (Exception ex) { //如果有异常直接抛出错误 throw Oops.Bah(ex.Message); } return result; } #endregion #region LARA提单纸登记 /// /// LARA提单纸登记 /// /// 任务主键数组 /// 返回结果 [HttpPost("/TaskManage/LaraPaperRegist")] public async Task LaraPaperRegist([FromQuery]string[] PKIds) { LaraPaperRegistDto result = new LaraPaperRegistDto(); List list = new List(); string batchNo = IDGen.NextID().ToString(); _logger.LogInformation("批次={no} ids={ids} LARA提单纸登记开始", batchNo, string.Join(",", PKIds)); /* 1、通过任务主键记录关联所有相同订舱主键相同并且任务类型是(DRAFT)的记录。 2、关联任务正本下载运行表(结束时间) 问题:提单纸页数计算是通过主单号来最新记录提取文件页数,为什么LARA提单纸登记没有用这个模式。(没理解) */ try { // var List = _taskBaseInfoRepository.EntityContext.Queryable() .InnerJoin((tsk, tsk2) => tsk.BOOK_ORDER_NO == tsk2.BOOK_ORDER_NO) .Where((tsk, tsk2) => PKIds.Contains(tsk.PK_ID) && tsk2.TASK_TYPE == TaskBusiTypeEnum.DRAFT.ToString()) .Select((tsk, tsk2) => new { tsk = tsk, tsk2 = tsk2 }).ToList(); var list2 = List.GroupBy(t => t.tsk.PK_ID).Select(t => { var curList = t.ToList(); if (curList.Count > 0) { return new { tsk = curList.FirstOrDefault().tsk, tsk2 = curList.OrderByDescending(a => a.tsk2.CreatedTime).FirstOrDefault().tsk2 }; } return null; }).Where(t => t != null).ToList(); if (list2.Count > 0) { var taskPKIdList = list2.Select(t => t.tsk2.PK_ID).Distinct().ToArray(); var originalDownloadHisInfo = _taskOriginalDownloadHisInfoRepository.AsQueryable() .Where(t => taskPKIdList.Contains(t.TASK_ID)) .OrderByDescending(t => t.END_DATE) .First(); var fileList = _taskBaseInfoRepository.EntityContext.Queryable() .InnerJoin((tsk, file) => tsk.PK_ID == file.TASK_PKID) .Where((tsk, file) => tsk.TASK_TYPE == TaskBusiTypeEnum.DRAFT.ToString() && taskPKIdList.Contains(tsk.PK_ID)) .Select((tsk, file) => new { tsk = tsk, file = file }).ToList(); var calcList = fileList.GroupBy(t => t.tsk.PK_ID) .Select(a => { var currList = a.ToList(); return new { tsk = currList.FirstOrDefault().tsk, clist = a.Select(x => x.file).ToList() }; }).OrderByDescending(t => t.tsk.CreatedTime).ToList(); var bookingNoList = list2.Select(t => !string.IsNullOrWhiteSpace(t.tsk.BOOK_ORDER_NO) ?long.Parse(t.tsk.BOOK_ORDER_NO):0) .Where(t=>t > 0).Distinct().ToList(); var orderList = _bookingOrderRepository.AsQueryable().Where(t => bookingNoList.Contains(t.Id)).ToList(); list2.ForEach(t => { LaraPaperRegistDetailDto laraInfo = new LaraPaperRegistDetailDto(); laraInfo.OrderNo = t.tsk.BOOK_ORDER_NO; laraInfo.TaskId = t.tsk.PK_ID; laraInfo.MBLNo = t.tsk.MBL_NO; var files = calcList.FirstOrDefault(a => a.tsk.PK_ID.Equals(t.tsk2.PK_ID)); if (files != null) { laraInfo.DraftNum = files.clist.Select(t => t.FILE_NAME.GetPageNum()).Sum(); } laraInfo.OriginalDownTime = originalDownloadHisInfo?.END_DATE; var orderInfo = orderList.FirstOrDefault(a => a.Id == long.Parse(t.tsk.BOOK_ORDER_NO)); laraInfo.IssueType = orderInfo?.ISSUETYPE; //laraInfo.IssueTypeName = t.tsk2.issu; list.Add(laraInfo); }); result.DetailList = list; } var laraPaperInfo = _taskLARAPaperInfoRepository.AsQueryable() .Where(t => t.CreatedUserId == UserManager.UserId) .OrderByDescending(t => t.NUMBER_TO).First(); result.NumberTo = laraPaperInfo != null ? laraPaperInfo.NUMBER_TO : "1".PadLeft(9, '0'); ; result.CalcList = InnerCalcLaraPageNumbers(new CalcLaraPageNumbersDto { numberTo = result.NumberTo, paperList = result.DetailList.Select((t, idx) => { return new LaraPaperRegistPostDto { DraftNum = t.DraftNum, ISSUETYPE = t.IssueType, MBLNO = t.MBLNo, TaskId = t.TaskId, ORDNO = t.OrderNo, SortNo = idx + 1, }; }).ToList() },true); } catch (Exception ex) { throw Oops.Bah("LARA提单纸登记异常,{0}", ex.Message); } return result; } #endregion #region 下载任务附件 /// /// 下载任务附件 /// /// /// 返回文件流 [HttpGet("/TaskManage/DownloadTaskAttach")] public async Task DownloadTaskAttach([FromQuery] string taskPKId) { FileStreamResult result = null; string batchNo = IDGen.NextID().ToString(); var fileList = _taskFileInfoRepository.AsQueryable().Where(t => t.TASK_PKID == taskPKId).OrderByDescending(t=>t.CreatedTime).ToList(); var fileInfo = fileList.FirstOrDefault(); if (fileInfo.FILE_PATH.StartsWith("http://")) { var fileStream = await InnerGetDownloadFile(fileInfo.FILE_PATH, taskPKId, batchNo); result = new FileStreamResult(fileStream, "application/octet-stream") { FileDownloadName = fileInfo.FILE_NAME }; } else if (System.IO.File.Exists(fileInfo.FILE_PATH)) { result = new FileStreamResult(new FileStream(fileInfo.FILE_PATH, FileMode.Open), "application/octet-stream") { FileDownloadName = fileInfo.FILE_NAME }; } return result; } #endregion #region 异步下载文件 /// /// 异步下载文件 /// /// 文件请求URL /// 任务主键 /// 批次号 /// 返回文件流 private async Task InnerGetDownloadFile(string fileUrl,string taskPKId,string batchNo) { Stream stream = null; try { DateTime bDate = DateTime.Now; stream = await fileUrl.GetAsStreamAsync(); DateTime eDate = DateTime.Now; TimeSpan ts = eDate.Subtract(bDate); var timeDiff = ts.TotalMilliseconds; _logger.LogInformation("批次={no} url={url} 请求完成,耗时:{timeDiff}ms.", batchNo, fileUrl, timeDiff); } catch (Exception ex) { _logger.LogInformation("批次={no} url={url} 下载文件异常, 结果{msg}", batchNo, fileUrl, ex.Message); throw Oops.Bah(nameof(InnerGetDownloadFile)+"下载文件异常,{0}", ex.Message); } return stream; } #endregion #region 正本附件批量打印 /// /// 正本附件批量打印 /// /// 任务主键数组 /// 返回文件流 [HttpPost("/TaskManage/PrintBatch")] public async Task PrintBatch(string[] PKIds) { FileStreamResult result = null; /* 1、通过任务主键获取所有的文件列表。只合并PDF文件,其他的文件不处理。 2、创建临时文件存放目录。 3、如果是http://开头的文档,需要使用下载文件,并变更为本地文件 4、PDF合成所有文件。 5、写入下载记录表。 6、返回文件流。 */ try { var fileList = _taskBaseInfoRepository.EntityContext.Queryable() .InnerJoin((tsk, file) => tsk.PK_ID == file.TASK_PKID) .Where((tsk, file) => PKIds.Contains(tsk.PK_ID) && file.FILE_TYPE.Equals(".pdf")) .Select((tsk, file) => new { tsk = tsk, file = file }).ToList(); var calcList = fileList.GroupBy(t => t.tsk.PK_ID) .Select(a => { var currList = a.ToList(); return new { tsk = currList.FirstOrDefault().tsk, clist = a.Select(x => x.file).ToList() }; }).OrderByDescending(t => t.tsk.CreatedTime).ToList(); var pdfList = calcList.SelectMany(t => t.clist).Select((t, idx) => new { Idx = idx, file = t }).ToList(); if (pdfList.Count == 0) throw Oops.Oh($"没有可以合并的PDF文件"); string filePath = string.Empty; string tempFileName = IDGen.NextID().ToString(); var opt = App.GetOptions().Path; filePath = $"{Path.Combine(App.WebHostEnvironment.WebRootPath, opt)}\\TempPDFMerge\\";//服务器路径 if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { filePath = filePath.Replace("\\", "/"); } //预先创建目录 if (!Directory.Exists(filePath)) { Directory.CreateDirectory(filePath); } var mergePdfPath = Path.Combine(filePath, $"{tempFileName}.pdf"); /* Document document = null; PdfCopy copy = null; pdfList.ForEach(t => { if(t.Idx == 0) { if(t.file.FILE_PATH.IndexOf("http://") >=0) { //var dw = InnerRemoteDownFile(t.file.FILE_PATH).GetAwaiter().GetResult(); WebClient wc = new WebClient(); wc.DownloadFile(t.file.FILE_PATH, Path.Combine(filePath, $"{tempFileName}abc.pdf")); //document = new Document(new PdfReader(dw).GetPageSize(1)); } else { document = new Document(new PdfReader(t.file.FILE_PATH).GetPageSize(1)); } copy = new PdfCopy(document, new FileStream(mergePdfPath, FileMode.Create)); } else { PdfReader reader = null; if (t.file.FILE_PATH.IndexOf("http://") >= 0) { var dw = InnerRemoteDownFile(t.file.FILE_PATH).GetAwaiter().GetResult(); reader = new PdfReader(dw); } else { reader = new PdfReader(t.file.FILE_PATH); } int n = reader.NumberOfPages; for (int j = 1; j <= n; j++) { document.NewPage(); PdfImportedPage page = copy.GetImportedPage(reader, j); copy.AddPage(page); } reader.Close(); } }); document.Close(); */ result = new FileStreamResult(new FileStream(mergePdfPath, FileMode.Open), "application/octet-stream") { FileDownloadName = $"{tempFileName}.pdf" }; } catch (Exception ex) { throw Oops.Bah("LARA提单纸登记异常,{0}", ex.Message); } return result; } #endregion #region 下载文件 private async Task InnerRemoteDownFile(string filePath) { using (HttpClient client = new HttpClient()) { HttpResponseMessage response = await client.GetAsync(filePath); if (response.IsSuccessStatusCode) { System.Net.Http.HttpContent content = response.Content; var contentStream = await content.ReadAsStreamAsync(); // get the actual content stream return contentStream; } else { throw new FileNotFoundException($"{filePath} 文件下载失败"); } } } #endregion #region 接收换船 /// /// 接收换船 /// /// 任务主键 /// 返回结果 [HttpGet("/TaskManage/AcceptChangeShip")] public async Task AcceptChangeShip([FromQuery]string taskPKId) { TaskManageOrderResultDto result = new TaskManageOrderResultDto(); string batchNo = IDGen.NextID().ToString(); try { var taskInfo = _taskBaseInfoRepository.AsQueryable().First(t => t.PK_ID == taskPKId); if (taskInfo == null) Oops.Oh($"任务信息获取失败"); _logger.LogInformation("批次={no} ids={ids} 获取任务完成", batchNo, taskPKId); if (taskInfo.TASK_TYPE != TaskBusiTypeEnum.CHANGE_SHIP.ToString()) Oops.Oh($"当前任务类型不是{TaskBusiTypeEnum.CHANGE_SHIP.GetDescription()},不能接收换船"); if (string.IsNullOrWhiteSpace(taskInfo.BOOK_ORDER_NO)) Oops.Oh($"任务信息的订舱主键不存在"); if (taskInfo.STATUS != TaskStatusEnum.Create.ToString()) Oops.Oh($"任务状态不是{0},不能【接收换船】", TaskStatusEnum.Create.GetDescription()); var orderInfo = _bookingOrderRepository.AsQueryable() .First(t => t.Id == long.Parse(taskInfo.BOOK_ORDER_NO)); if (orderInfo == null) { orderInfo = _bookingOrderRepository.AsQueryable().First(t => t.MBLNO == taskInfo.MBL_NO); _logger.LogInformation("批次={no} 订舱主键{id}获取任务失败,通过主单号{mblno}提取完成", batchNo, taskInfo.BOOK_ORDER_NO, taskInfo.MBL_NO); } if (orderInfo == null) Oops.Oh($"订舱信息获取失败"); var userMail = _djyUserMailAccountRepository.AsQueryable().First(x => x.CreatedUserId == orderInfo.CreatedUserId); if (userMail == null || string.IsNullOrWhiteSpace(userMail.SmtpServer) || userMail.SmtpPort == 0) { Oops.Oh($"发件邮箱未配置,或者配置不完整"); } _logger.LogInformation("批次={no} 获取用户邮箱配置完成", batchNo); if (!string.IsNullOrWhiteSpace(taskInfo.RESULT_NOTE)) Oops.Oh($"获取换船任务详情失败"); _logger.LogInformation("批次={no} 获取换船任务详情,{note}", batchNo, taskInfo.RESULT_NOTE); var jsonObj = JSON.Deserialize(taskInfo.RESULT_NOTE); var taskChangeShipModel = new TaskChangeShipHisInfo { PK_ID = IDGen.NextID().ToString(), TASK_PKID = taskInfo.PK_ID, BOOK_ORDER_NO = orderInfo.Id.ToString(), MBL_NO = orderInfo.MBLNO, VESSEL_TO = jsonObj.vessel.ToString(), VOYNO_TO = jsonObj.voyno.ToString(), SHIP_AGENCY_TO = jsonObj.shipagency != null ? jsonObj.shipagency : "", VESSEL_SRC = orderInfo.VESSEL, VOYNO_SRC = orderInfo.VOYNO, SHIP_AGENCY_SRC = orderInfo.SHIPAGENCY, CreatedTime = DateTime.Now, CreatedUserId = UserManager.UserId, CreatedUserName = UserManager.Name }; //写入换船历史表 await _taskChangeShipHisInfoRepository.InsertAsync(taskChangeShipModel); _logger.LogInformation("批次={no} 写入换船历史表完成{id}", batchNo, taskChangeShipModel.PK_ID); //更新任务状态 orderInfo = _bookingOrderRepository.AsQueryable().First(t => t.Id == orderInfo.Id); orderInfo.VESSEL = taskChangeShipModel.VESSEL_TO; orderInfo.VOYNO = taskChangeShipModel.VOYNO_TO; orderInfo.SHIPAGENCY = taskChangeShipModel.SHIP_AGENCY_TO; orderInfo.CreatedTime = DateTime.Now; orderInfo.CreatedUserId = UserManager.UserId; orderInfo.CreatedUserName = UserManager.Name; //更新订舱详情 await _bookingOrderRepository.AsUpdateable(orderInfo).UpdateColumns(it => new { it.UpdatedTime, it.UpdatedUserId, it.UpdatedUserName, it.VESSEL, it.VOYNO }).ExecuteCommandAsync(); _logger.LogInformation("批次={no} 更新订舱完成", batchNo); taskInfo.STATUS = TaskStatusEnum.Complete.ToString(); taskInfo.STATUS_NAME = TaskStatusEnum.Complete.GetDescription(); taskInfo.COMPLETE_DATE = DateTime.Now; taskInfo.COMPLETE_DEAL = TaskCompleteDealEnum.MANUAL.ToString(); taskInfo.COMPLETE_DEAL_NAME = TaskCompleteDealEnum.MANUAL.GetDescription(); taskInfo.UpdatedTime = DateTime.Now; taskInfo.UpdatedUserId = UserManager.UserId; taskInfo.UpdatedUserName = UserManager.Name; //更新任务表 await _taskBaseInfoRepository.AsUpdateable(taskInfo).UpdateColumns(it => new { it.STATUS, it.STATUS_NAME, it.COMPLETE_DATE, it.COMPLETE_DEAL, it.COMPLETE_DEAL_NAME, it.UpdatedTime, it.UpdatedUserId, it.UpdatedUserName }).ExecuteCommandAsync(); _logger.LogInformation("批次={no} 更新任务完成", batchNo); //提取订舱相关联系的邮箱信息 var bookContactEmailList = _bookingOrderContactRepository.AsQueryable().Where(t => t.BookingId == orderInfo.Id && !string.IsNullOrWhiteSpace(t.Email)) .Select(t => t.Email).Distinct().ToList(); if(bookContactEmailList.Count > 0) { string sendTo = string.Join(";", bookContactEmailList.ToArray()); string emailSubject = $"换船通知-{orderInfo.MBLNO}"; string emailBody = $"提单号为{orderInfo.MBLNO}的订舱已换船
"; var sendResult = await MailSendHelper.SendMail(userMail, emailSubject, emailBody, sendTo); _logger.LogInformation("批次={no} 发送邮件完成 {rlt}", batchNo,JSON.Serialize(sendResult)); //接受之后重新发送放舱 } result.succ = true; result.msg = "操作成功"; } catch (Exception ex) { throw Oops.Bah("接收换船异常,{0}", ex.Message); } return result; } #endregion #region 取消换船 /// /// 取消换船 /// /// 任务主键 /// 返回结果 [HttpGet("/TaskManage/AcceptCancelChangeShip")] public async Task AcceptCancelChangeShip([FromQuery] string taskPKId) { TaskManageOrderResultDto result = new TaskManageOrderResultDto(); string batchNo = IDGen.NextID().ToString(); try { var taskInfo = _taskBaseInfoRepository.AsQueryable().First(t => t.PK_ID == taskPKId); if (taskInfo == null) Oops.Oh($"任务信息获取失败"); _logger.LogInformation("批次={no} ids={ids} 获取任务完成", batchNo, taskPKId); if (taskInfo.TASK_TYPE != TaskBusiTypeEnum.ABORT_CHANGE_SHIP.ToString()) Oops.Oh($"当前任务类型不是{TaskBusiTypeEnum.ABORT_CHANGE_SHIP.GetDescription()},不能取消换船"); if (string.IsNullOrWhiteSpace(taskInfo.BOOK_ORDER_NO)) Oops.Oh($"任务信息的订舱主键不存在"); if (taskInfo.STATUS != TaskStatusEnum.Create.ToString()) Oops.Oh($"任务状态不是{0},不能【取消换船】", TaskStatusEnum.Create.GetDescription()); var orderInfo = _bookingOrderRepository.AsQueryable() .First(t => t.Id == long.Parse(taskInfo.BOOK_ORDER_NO)); if (orderInfo == null) Oops.Oh($"订舱信息获取失败"); _logger.LogInformation("批次={no} 订舱主键{id}获取订舱完成", batchNo, taskInfo.BOOK_ORDER_NO); var userMail = _djyUserMailAccountRepository.AsQueryable().First(x => x.CreatedUserId == orderInfo.CreatedUserId); if (userMail == null || string.IsNullOrWhiteSpace(userMail.SmtpServer) || userMail.SmtpPort == 0) { Oops.Oh($"发件邮箱未配置,或者配置不完整"); } if (!string.IsNullOrWhiteSpace(taskInfo.RESULT_NOTE)) Oops.Oh($"获取换船任务详情失败"); _logger.LogInformation("批次={no} 获取换船任务详情,{note}", batchNo, taskInfo.RESULT_NOTE); var jsonObj = JSON.Deserialize(taskInfo.RESULT_NOTE); //获取任务历史 var lastChangShipTask = await _taskBaseInfoRepository.AsQueryable().Where(t=>t.BOOK_ORDER_NO == taskInfo.BOOK_ORDER_NO && t.TASK_TYPE == TaskBusiTypeEnum.CHANGE_SHIP.ToString()) .OrderByDescending(t=>t.CreatedTime).FirstAsync(); if(lastChangShipTask != null) { if (lastChangShipTask.STATUS == TaskStatusEnum.Create.ToString()) //原换船通知未作处理 { throw Oops.Bah("本票货存在未处理换船通知,请先结束原换船任务然后结束本任务。"); } if (lastChangShipTask.STATUS == TaskStatusEnum.Cancel.ToString()) //原换船任务为结束任务 { throw Oops.Bah("未做换船,请点击结束任务。"); } if (lastChangShipTask.STATUS == TaskStatusEnum.Complete.ToString()) //原换船通知已经接受 { //查询换船历史,恢复换船 var lastChangeShip = await _taskChangeShipHisInfoRepository.AsQueryable().Where(t => t.BOOK_ORDER_NO == orderInfo.Id.ToString()) .OrderByDescending(t => t.CreatedTime).FirstAsync(); if (lastChangeShip == null) throw Oops.Bah("查询换船历史失败"); //更新任务状态 orderInfo = _bookingOrderRepository.AsQueryable().First(t => t.Id == orderInfo.Id); orderInfo.VESSEL = lastChangeShip.VESSEL_SRC; orderInfo.VOYNO = lastChangeShip.VOYNO_SRC; orderInfo.SHIPAGENCY = lastChangeShip.SHIP_AGENCY_SRC; _logger.LogInformation($"{orderInfo.MBLNO}接受取消换船,从{orderInfo.VESSEL}/{orderInfo.VOYNO} 到 {jsonObj.vessel.ToString()}/{jsonObj.voyno.ToString()}"); orderInfo.CreatedTime = DateTime.Now; orderInfo.CreatedUserId = UserManager.UserId; orderInfo.CreatedUserName = UserManager.Name; //更新订舱详情 await _bookingOrderRepository.AsUpdateable(orderInfo).UpdateColumns(it => new { it.UpdatedTime, it.UpdatedUserId, it.UpdatedUserName, it.VESSEL, it.VOYNO }).ExecuteCommandAsync(); _logger.LogInformation("批次={no} 更新订舱完成", batchNo); taskInfo.STATUS = TaskStatusEnum.Complete.ToString(); taskInfo.STATUS_NAME = TaskStatusEnum.Complete.GetDescription(); taskInfo.COMPLETE_DATE = DateTime.Now; taskInfo.COMPLETE_DEAL = TaskCompleteDealEnum.MANUAL.ToString(); taskInfo.COMPLETE_DEAL_NAME = TaskCompleteDealEnum.MANUAL.GetDescription(); taskInfo.UpdatedTime = DateTime.Now; taskInfo.UpdatedUserId = UserManager.UserId; taskInfo.UpdatedUserName = UserManager.Name; //更新任务表 await _taskBaseInfoRepository.AsUpdateable(taskInfo).UpdateColumns(it => new { it.STATUS, it.STATUS_NAME, it.COMPLETE_DATE, it.COMPLETE_DEAL, it.COMPLETE_DEAL_NAME, it.UpdatedTime, it.UpdatedUserId, it.UpdatedUserName }).ExecuteCommandAsync(); _logger.LogInformation("批次={no} 更新任务完成", batchNo); //提取订舱相关联系的邮箱信息 var bookContactEmailList = _bookingOrderContactRepository.AsQueryable().Where(t => t.BookingId == orderInfo.Id && !string.IsNullOrWhiteSpace(t.Email)) .Select(t => t.Email).Distinct().ToList(); if (bookContactEmailList.Count > 0) { string sendTo = string.Join(";", bookContactEmailList.ToArray()); string emailSubject = $"取消换船通知-{orderInfo.MBLNO}"; string emailBody = $"取消换船通知-{orderInfo.MBLNO}\", $\"提单号为{orderInfo.MBLNO}的订舱已取消换船
"; var sendResult = await MailSendHelper.SendMail(userMail, emailSubject, emailBody, sendTo); _logger.LogInformation("批次={no} 发送邮件完成 {rlt}", batchNo, JSON.Serialize(sendResult)); //接受之后重新发送放舱 } } } result.succ = true; result.msg = "操作成功"; } catch (Exception ex) { throw Oops.Bah("取消换船异常,{0}", ex.Message); } return result; } #endregion #region 转发电放邮件 /// /// 转发电放邮件 /// /// 任务主键 /// 指定邮件地址 /// 返回结果 [HttpGet("/TaskManage/SendTelexEmail")] public async Task SendTelexEmail([FromQuery] string taskPKId, [FromQuery] string toMail) { TaskManageOrderResultDto result = new TaskManageOrderResultDto(); try { var taskInfo = _taskBaseInfoRepository.AsQueryable().First(t => t.PK_ID == taskPKId); if (taskInfo == null) Oops.Oh($"任务信息获取失败"); if (taskInfo.TASK_TYPE != TaskBusiTypeEnum.TELEX_NOTICE.ToString() || taskInfo.TASK_TYPE != TaskBusiTypeEnum.SEAWAYBILL_DOWN.ToString()) Oops.Oh($"当前任务类型不是{TaskBusiTypeEnum.TELEX_NOTICE.GetDescription()}、{TaskBusiTypeEnum.SEAWAYBILL_DOWN.GetDescription()},不能转发邮件"); if (string.IsNullOrWhiteSpace(taskInfo.BOOK_ORDER_NO)) Oops.Oh($"任务信息的订舱主键不存在"); var orderInfo = _bookingOrderRepository.AsQueryable() .First(t => t.Id == long.Parse(taskInfo.BOOK_ORDER_NO)); if (orderInfo == null) Oops.Oh($"订舱信息获取失败"); var userMail = _djyUserMailAccountRepository.AsQueryable().First(x => x.CreatedUserId == orderInfo.CreatedUserId); if (userMail == null || string.IsNullOrWhiteSpace(userMail.SmtpServer) || userMail.SmtpPort == 0) { Oops.Oh($"发件邮箱未配置,或者配置不完整"); } string emailSubject = string.Empty; string emailBody = string.Empty; var sendResult = await MailSendHelper.SendMail(userMail, emailSubject, emailBody, toMail); if (!sendResult.Key) { Oops.Oh(sendResult.Value); } } catch(Exception ex) { throw Oops.Bah("获取发送下货纸异常,{0}", ex.Message); } return result; } #endregion #region 发送下货纸 /// /// 发送下货纸 /// /// 任务主键 /// 文件功能 (9原始) /// 返回结果 [HttpGet("/TaskManage/SendShippingOrder")] public async Task SendShippingOrder([FromQuery] string taskPKId, [FromQuery] string fileRole = "9") { TaskManageOrderResultDto result = new TaskManageOrderResultDto(); string batchNo = IDGen.NextID().ToString(); /* 1、查询任务关联的订舱信息。 2、触发下货纸发送。 3、发送成功更新任务状态为成功。 4、查看用户公司是否配置了反馈地址,如果有配置则触发反馈推送,否则显示反馈失败提示。 5、触发扣费 */ try { var taskInfo = _taskBaseInfoRepository.AsQueryable().First(t => t.PK_ID == taskPKId); if (taskInfo == null) Oops.Oh($"任务信息获取失败"); if(taskInfo.TASK_TYPE != TaskBusiTypeEnum.SHIPPING_ORDER.ToString()) Oops.Oh($"当前任务类型不是{TaskBusiTypeEnum.SHIPPING_ORDER.GetDescription()},不能发送下货纸"); if (string.IsNullOrWhiteSpace(taskInfo.BOOK_ORDER_NO)) Oops.Oh($"任务信息的订舱主键不存在"); var orderInfo = _bookingOrderRepository.AsQueryable() .First(t => t.Id == long.Parse(taskInfo.BOOK_ORDER_NO)); if (orderInfo == null) Oops.Oh($"订舱信息获取失败"); //推送下货纸业务 var rtn = await XiahuozhiHelpler.Send(orderInfo.Id, fileRole); if (!rtn.Key) { throw Oops.Bah($"发送失败:{rtn.Value}"); } //订舱状态写入 await SaveBookingStatus(orderInfo.Id, "sta_xhz", "下货纸"); taskInfo.STATUS = TaskStatusEnum.Complete.ToString(); taskInfo.STATUS_NAME = TaskStatusEnum.Complete.GetDescription(); taskInfo.COMPLETE_DATE = DateTime.Now; taskInfo.COMPLETE_DEAL = TaskCompleteDealEnum.MANUAL.ToString(); taskInfo.COMPLETE_DEAL_NAME = TaskCompleteDealEnum.MANUAL.GetDescription(); taskInfo.UpdatedTime = DateTime.Now; taskInfo.UpdatedUserId = UserManager.UserId; taskInfo.UpdatedUserName = UserManager.Name; //更新任务表 await _taskBaseInfoRepository.AsUpdateable(taskInfo).UpdateColumns(it => new { it.STATUS, it.STATUS_NAME, it.COMPLETE_DATE, it.COMPLETE_DEAL, it.COMPLETE_DEAL_NAME, it.UpdatedTime, it.UpdatedUserId, it.UpdatedUserName }).ExecuteCommandAsync(); await InnerChargeFeeShippingOrder(taskInfo); //反馈用户(这里预留,主要考虑是否通过用户配置确定是否需要推送回执) await FeedbackXiaHuoZhi(""); } catch(Exception ex) { throw Oops.Bah("发送下货纸异常,{0}", ex.Message); } return result; } #endregion #region 更新订舱的状态 /// /// 更新订舱的状态 /// /// 订舱主键 /// 状态代码 /// 状态名称 /// private async Task SaveBookingStatus(long bookingId, string code, string name) { var bookSta = _bookingStatusRepository.FirstOrDefault(x => x.BookingId == bookingId && x.StaCode == code); if (bookSta == null) { //记录状态 bookSta = new BookingStatus(); bookSta.BookingId = bookingId; bookSta.StaCode = code; bookSta.StaName = name; bookSta.StaTime = DateTime.Now; await _bookingStatusRepository.InsertAsync(bookSta); } else { bookSta.StaTime = DateTime.Now; await _bookingStatusRepository.UpdateAsync(bookSta); } } #endregion #region 扣费 /// /// 扣费 /// /// 任务信息 /// 是否执行扣费 true-执行扣费 false-不执行扣费(主要是符合扣费条件但是由于超时没有得到准确回执) /// 返回回执 private async Task InnerChargeFeeShippingOrder(TaskBaseInfo taskBaseInfo, bool isCharge = true) { TaskManageOrderResultDto result = new TaskManageOrderResultDto { succ = false }; try { decimal balance = 0; decimal price = 0; decimal total = 0; TaskChargesHisInfo model = new TaskChargesHisInfo { PK_ID = IDGen.NextID().ToString(), TASK_ID = taskBaseInfo.PK_ID, BEFORE_BALANCE = balance, PRICE = price, BUSI_TYPE = "21", BUSI_TYPE_NAME = String.Empty, SEND_TYPE = "1001", SEND_TYPE_NAME = String.Empty, REMARK = "下货纸", QTY = 1, TOTAL_AMOUNT = total, }; if (!isCharge) { model.STATUS = TaskChargeStatusEnum.UNKNOW_RESULT.ToString(); model.STATUS_NAME = TaskChargeStatusEnum.UNKNOW_RESULT.GetDescription(); } //写入记录 await _taskChargesHisInfoRepository.InsertAsync(model); result.succ = false; result.msg = "扣费失败"; } catch (Exception ex) { result.succ = false; result.msg = ex.Message; } return result; } #endregion #region 获取订舱详情 /// /// 获取订舱详情 /// /// 任务主键 /// 返回结果 [HttpGet("/TaskManage/GetBookingOrderInfo")] public async Task GetBookingOrderInfo([FromQuery]string taskPKId) { TaskBookingOrderDto model = new TaskBookingOrderDto(); string batchNo = IDGen.NextID().ToString(); try { var taskInfo = _taskBaseInfoRepository.AsQueryable().First(t => t.PK_ID == taskPKId); if (taskInfo == null) Oops.Oh($"任务信息获取失败"); if (string.IsNullOrWhiteSpace(taskInfo.BOOK_ORDER_NO)) Oops.Oh($"任务信息的订舱主键不存在"); var orderInfo = _bookingOrderRepository.AsQueryable() .First(t => t.Id == long.Parse(taskInfo.BOOK_ORDER_NO)); if(orderInfo != null) { //订舱 model = orderInfo.Adapt(); var contaList = await _bookingOrderContaRepository.AsQueryable().Where(x => x.BILLID == orderInfo.Id).ToListAsync(); //获取集装箱的主键 var ctnArg = contaList.Select(t => t.Id).ToArray(); //查询集装箱所有的货物信息 var cargoList = await _bookingOrderContaCargoRepository.AsQueryable() .Where(x => ctnArg.Contains(x.CTNID.Value)).ToListAsync(); _logger.LogInformation("批次={no} 提取货物明细完成 数量={total}", batchNo, cargoList.Count); if (cargoList.Count > 0) { model.ContaList = contaList.GroupJoin(cargoList, l => l.Id, r => r.CTNID, (l, r) => { var currList = r.ToList(); if (currList.Count > 0) { var info = l.Adapt(); info.CargoList = currList.Adapt>(); return info; } return l.Adapt(); }).ToList(); } else { model.ContaList = contaList.Adapt>(); } //任务 model.TaskBaseInfo = taskInfo.Adapt(); } } catch (Exception ex) { throw Oops.Bah("获取订舱详情异常,{0}", ex.Message); } return model; } #endregion #region 下货纸反馈 /// /// 下货纸反馈 /// /// /// private async Task FeedbackXiaHuoZhi(string bsno) { /* var para = commonData.ParamValues.AsNoTracking().FirstOrDefault(x => x.CompId == compid && x.ParaCode == "XHZ_FEEDBACK_URL"); if (para == null || string.IsNullOrEmpty(para.ItemCode)) { msg = "下货纸反馈地址未配置"; return false; } var feedbask = new BackgroundTaskCommon(); feedbask.GID = Guid.NewGuid().ToString(); feedbask.Status = BackgroundTaskCommon.StatusCreate; feedbask.Type = BackgroundTaskCommon.TypeHttpFeedback; feedbask.CreateTime = DateTime.Now; feedbask.ParamData = JsonConvert.SerializeObject(new { url = para.ItemCode, method = "POST", json = JsonConvert.SerializeObject(new { bsno, status }) }); commonData.BackgroundTaskCommon.Add(feedbask); msg = "成功"; return true; */ } #endregion #region 获取航次账单详情 /// /// 获取航次账单详情 /// /// 任务主键 /// 返回结果 [HttpGet("/TaskManage/GetInvoiceBillInfo")] public async Task GetInvoiceBillInfo([FromQuery] string taskPKId) { TaskInvoiceBillBaseInfo model = new TaskInvoiceBillBaseInfo(); string batchNo = IDGen.NextID().ToString(); try { var taskInfo = _taskBaseInfoRepository.AsQueryable().First(t => t.PK_ID == taskPKId); if (taskInfo == null) Oops.Oh($"任务信息获取失败"); if (string.IsNullOrWhiteSpace(taskInfo.BOOK_ORDER_NO)) Oops.Oh($"任务信息的订舱主键不存在"); if(taskInfo.TASK_TYPE != TaskBusiTypeEnum.INVOICE_BILL_MAIL.ToString()) Oops.Oh($"当前任务类型不是{TaskBusiTypeEnum.INVOICE_BILL_MAIL.GetDescription()}"); var orderInfo = _bookingOrderRepository.AsQueryable() .First(t => t.Id == long.Parse(taskInfo.BOOK_ORDER_NO)); model.TaskId = taskInfo.PK_ID; if (orderInfo != null) { //订舱 model.BookingOrder = orderInfo.Adapt(); } //获取文件 var fileList = _taskFileInfoRepository.AsQueryable().Where(t => t.TASK_PKID == taskInfo.PK_ID).ToList(); model.TaskFile = fileList.Adapt>(); var feeList = _taskBillFeeDetailInfoRepository.AsQueryable().Where(t => t.TASK_PKID == taskInfo.PK_ID).ToList(); model.FeeList = feeList.Where(t => t.IS_TOTAL == 0).Select(t=>t.Adapt()).ToList(); var totalUSD = feeList.FirstOrDefault(t => t.IS_TOTAL == 1 && t.FEE_NAME == "TotalUSD" && t.CURRENCY == "USD"); model.TotalAmountUSD = totalUSD != null ? totalUSD.TOTAL_AMOUNT : 0; var totalCNY = feeList.FirstOrDefault(t => t.IS_TOTAL == 1 && t.FEE_NAME == "TotalCNY" && t.CURRENCY == "CNY"); model.TotalAmountCNY = totalCNY != null ? totalCNY.TOTAL_AMOUNT : 0; model.InvoiceBillSendList = new List(); } catch (Exception ex) { throw Oops.Bah("获取获取航次账单详情异常,{0}", ex.Message); } return model; } #endregion #region 获取单票账单详情 /// /// 获取单票账单详情 /// /// 任务主键 /// 返回结果 [HttpGet("/TaskManage/GetTaskPerBillInfo")] public async Task GetTaskPerBillInfo([FromQuery] string taskPKId) { TaskPerBillResultInfo model = new TaskPerBillResultInfo(); string batchNo = IDGen.NextID().ToString(); try { var taskInfo = _taskBaseInfoRepository.AsQueryable().First(t => t.PK_ID == taskPKId); if (taskInfo == null) Oops.Oh($"任务信息获取失败"); if (string.IsNullOrWhiteSpace(taskInfo.BOOK_ORDER_NO)) Oops.Oh($"任务信息的订舱主键不存在"); if (taskInfo.TASK_TYPE != TaskBusiTypeEnum.PER_BILL.ToString()) Oops.Oh($"当前任务类型不是{TaskBusiTypeEnum.PER_BILL.GetDescription()}"); var orderInfo = _bookingOrderRepository.AsQueryable() .First(t => t.Id == long.Parse(taskInfo.BOOK_ORDER_NO)); model.TaskId = taskInfo.PK_ID; var perBillInfo = _taskPerBillBaseInfoRepository.AsQueryable().First(t => t.TASK_PKID == taskInfo.PK_ID); if (perBillInfo == null) Oops.Oh($"单票账单不存在"); model.TaskPerBillBaseInfoDto = perBillInfo.Adapt(); if (orderInfo != null) { //订舱 model.BookingOrder = orderInfo.Adapt(); } //获取文件 var fileList = _taskFileInfoRepository.AsQueryable().Where(t => t.TASK_PKID == taskInfo.PK_ID).ToList(); model.TaskFile = fileList.Adapt>(); var feeList = _taskBillFeeDetailInfoRepository.AsQueryable().Where(t => t.TASK_PKID == taskInfo.PK_ID).ToList(); model.FeeList = feeList.Where(t => t.IS_TOTAL == 0).Select(t => t.Adapt()).ToList(); } catch (Exception ex) { throw Oops.Bah("获取获取单票账单详情异常,{0}", ex.Message); } return model; } #endregion #region 获取提单纸登记记录 /// /// 获取提单纸登记记录 /// /// 查询条件 /// 返回结果 [HttpPost("/TaskManage/GetLaraPaperRecordPage")] public async Task> GetLaraPaperRecordPageAsync(QueryTaskManageBaseDto querySearch) { string entityOrderCol = "CreatedTime"; //这里因为返回给前端的台账数据是DTO,所以这里排序时候需要转换成Entity对应的字段 if (!string.IsNullOrWhiteSpace(querySearch.SortField)) entityOrderCol = MapsterExtHelper.GetAdaptProperty(querySearch.SortField); var entities = await _taskLARAPaperInfoRepository.AsQueryable() .OrderBy(entityOrderCol + (querySearch.descSort ? " asc " : " desc ")) .ToPagedListAsync(querySearch.PageNo, pageSize: querySearch.PageSize); return entities.Adapt>(); } #endregion #region 导出LARA提单纸登记记录 /// /// 导出LARA提单纸登记记录 /// /// 排序字段 /// 当前页码 /// 页码容量 /// 排序方法,默认降序 /// 返回结果 [HttpGet("/TaskManage/LaraPaperRecordExport")] public async Task LaraPaperRecordExport([FromQuery] string sortField,[FromQuery] int pageNo = 1, [FromQuery] int pageSize = 30, [FromQuery] bool descSort = true) { QueryTaskManageBaseDto querySearch = new QueryTaskManageBaseDto { SortField = sortField, PageNo = pageNo, PageSize = pageSize, descSort = descSort }; string entityOrderCol = "CreatedTime"; var entities = await _taskLARAPaperInfoRepository.AsQueryable() .OrderBy(entityOrderCol + (querySearch.descSort ? " asc " : " desc ")) .ToPagedListAsync(querySearch.PageNo, pageSize: querySearch.PageSize); if(entities.Items.Count() == 0) { throw Oops.Oh($"没有可以导出的数据"); } var list = entities.Items.Adapt>(); //导出Excel文件流 var ms = ExportXlsLaraPaperRecord(list); return new FileStreamResult(ms, "application/vnd.ms-excel") { FileDownloadName = $"{DateTime.Now.ToString("yyyyMMddHHmmss")}_LaraPaperRecord.xls" }; } #endregion #region 导出提单纸登记记录生成Excel /// /// 导出提单纸登记记录生成Excel /// /// LARA提单纸登记记录列表 /// 返回Excel文件流 private MemoryStream ExportXlsLaraPaperRecord(List list) { MemoryStream ms = new MemoryStream(); try { IWorkbook workbook = new HSSFWorkbook(); ISheet sheet = workbook.CreateSheet(); IRow headerRow = sheet.CreateRow(0); var headers = new string[] { "打印日期", "提单号", "Paper Number From", "Paper Number To", "Sum", "签单方式", "LARA登记时间", "LARA登记人" }; for (int i = 0; i < headers.Length; i++) { string head = headers[i]; var headCell = headerRow.CreateCell(i); headCell.SetCellValue(head); } int rowIndex = 1; foreach (var item in list) { IRow dataRow = sheet.CreateRow(rowIndex); var cell0 = dataRow.CreateCell(0); cell0.SetCellValue(item.OriginalDownTime); var cell1 = dataRow.CreateCell(1); cell1.SetCellValue(item.MBLNo); var cell2 = dataRow.CreateCell(2); cell2.SetCellValue(item.NumberFrom); var cell3 = dataRow.CreateCell(3); cell3.SetCellValue(item.NumberTo); var cell4 = dataRow.CreateCell(4); cell4.SetCellValue(item.PageSum); var cell5 = dataRow.CreateCell(5); cell5.SetCellValue(item.IssueTypeName); var cell6 = dataRow.CreateCell(6); cell6.SetCellValue(item.CreatedTime); var cell7 = dataRow.CreateCell(7); cell7.SetCellValue(item.CreatedUserName); rowIndex++; } workbook.Write(ms, true); ms.Flush(); ms.Position = 0; } catch (Exception ex) { throw Oops.Bah("导出提单纸登记记录生成Excel异常,{0}", ex.Message); } return ms; } #endregion #region 保存SI信息 /// /// 保存SI信息 /// /// 订舱信息 /// 返回结果 [HttpPost("/TaskManage/SaveBookingSI")] public async Task SaveBookingSI(TaskBookingOrderDto model) { TaskManageOrderResultDto result = new TaskManageOrderResultDto(); /* 1、比较原始数据和修改数据内容,记录差异。 2、更新订舱主信息和集装箱信息。 3、写入本地历史记录表。 */ try { if (string.IsNullOrWhiteSpace(model.TaskBaseInfo.PKId)) throw Oops.Oh($"任务主键TaskBaseInfo.PKId不能为空"); var taskInfo = _taskBaseInfoRepository.AsQueryable().First(t => t.PK_ID == model.TaskBaseInfo.PKId); if (taskInfo == null) throw Oops.Oh($"任务信息获取失败"); if (string.IsNullOrWhiteSpace(taskInfo.BOOK_ORDER_NO)) throw Oops.Oh($"任务信息的订舱主键不存在"); if (taskInfo.TASK_TYPE != TaskBusiTypeEnum.SI_FEEDBACK.ToString()) throw Oops.Oh($"当前任务类型不是{TaskBusiTypeEnum.SI_FEEDBACK.GetDescription()}"); //取订舱详情(包含集装箱) var bookOrderList = _bookingOrderRepository.EntityContext.Queryable() .LeftJoin(_bookingOrderRepository.EntityContext.Queryable(),(bk, ctn) => bk.Id == ctn.BILLID) .Where((bk, ctn) => bk.Id == long.Parse(taskInfo.BOOK_ORDER_NO) && bk.TenantId == UserManager.TENANT_ID) .Select((bk, ctn) => new { bk = bk, ctn = ctn }).ToList(); var orderInfo = bookOrderList.FirstOrDefault().bk; List orderCtnList = new List(); //这里是左连接查询,解决集装箱为空的情况 if(bookOrderList.Any(t=>t.ctn.Id > 0)) orderCtnList = bookOrderList.Select(t => t.ctn).ToList(); var mdBookingOrder = model.Adapt(); mdBookingOrder.Id = orderInfo.Id; mdBookingOrder.UpdatedTime = DateTime.Now; mdBookingOrder.UpdatedUserId = UserManager.UserId; mdBookingOrder.UpdatedUserName = UserManager.Name; //比对主订舱信息 var orderDiff = InnerCompare(orderInfo, mdBookingOrder); //比对箱信息 var contaList = model.ContaList.Select(x => x.Adapt()).ToList(); /**/ //这里参考原有的更新逻辑,只更新了SI回执有的字段信息,其他字段不更新,如果后期有调整可以自行增加更新字段 await _bookingOrderRepository.AsUpdateable(mdBookingOrder).UpdateColumns(it => new { it.UpdatedTime, it.UpdatedUserId, it.UpdatedUserName, it.SHIPPER, it.CONSIGNEE, it.NOTIFYPARTY, it.MARKS, it.DESCRIPTION, it.BLFRT, it.SERVICE, it.ISSUETYPE, it.PORTLOADID, it.PORTLOAD, it.PORTDISCHARGEID, it.PORTDISCHARGE, it.TRANSPORTID, it.TRANSPORT, it.DESTINATIONID, it.DESTINATION, it.PKGS, it.KINDPKGS, it.KGS, it.CBM, it.THIRDPAYADDR, it.SIREMARK }).ExecuteCommandAsync(); var ctnlist = await _bookingOrderContaRepository.AsQueryable().Where(x => x.BILLID == mdBookingOrder.Id).ToListAsync(); var si2orderCtnList = contaList.GroupJoin(ctnlist, l => l.CNTRNO?.Trim(), r => r.CNTRNO?.Trim(), (l, r) => { var currInfo = r.FirstOrDefault(); if(currInfo == null) { l.BILLID = orderInfo.Id; l.CreatedTime = DateTime.Now; l.CreatedUserId = UserManager.UserId; l.CreatedUserName = UserManager.Name; l.UpdatedTime = l.CreatedTime; l.UpdatedUserId = UserManager.UserId; l.UpdatedUserName = UserManager.Name; return new { OperType = "insert", obj = l }; } else { currInfo.Id = l.Id; currInfo.BILLID = l.BILLID; currInfo.UpdatedTime = DateTime.Now; currInfo.UpdatedUserId = UserManager.UserId; currInfo.UpdatedUserName = UserManager.Name; return new { OperType = "update", obj = currInfo }; } }).ToList(); var delList = ctnlist.GroupJoin(contaList, l => l.CNTRNO?.Trim(), r => r.CNTRNO?.Trim(), (l, r) => { var currInfo = r.FirstOrDefault(); if (currInfo == null) { l.UpdatedTime = DateTime.Now; l.UpdatedUserId = UserManager.UserId; l.UpdatedUserName = UserManager.Name; return new { OperType = "delete", obj = l }; } return new { OperType = string.Empty, obj = l }; }).Where(t=>t.OperType != string.Empty).ToList(); if (delList.Count > 0) si2orderCtnList.AddRange(delList); if (si2orderCtnList.Count > 0) { si2orderCtnList.ForEach(async ctn => { if (ctn.OperType == "insert") { //插入 await _bookingOrderContaRepository.InsertAsync(ctn.obj); } else if (ctn.OperType == "update") { //更新 await _bookingOrderContaRepository.AsUpdateable(ctn.obj).UpdateColumns(it => new { it.CTNALL, it.SEALNO, it.PKGS, it.KGS, it.CBM, it.UpdatedTime, it.UpdatedUserId, it.UpdatedUserName, }).ExecuteCommandAsync(); } else if (ctn.OperType == "delete") { await _bookingOrderContaRepository.DeleteAsync(x => x.Id == ctn.obj.Id); } }); } result.succ = true; result.msg = "保存SI信息成功"; } catch(Exception ex) { throw Oops.Bah("保存SI信息异常,{0}", ex.Message); } return result; } #endregion #region 获取SI反馈信息 /// /// 获取SI反馈信息 /// /// 任务主键 /// 返回结果 [HttpGet("/TaskManage/GetSIFeedBackInfo")] public async Task GetSIFeedBackInfo(string taskPKId) { TaskSIFeedBackResultDto model = new TaskSIFeedBackResultDto(); try { var taskInfo = _taskBaseInfoRepository.AsQueryable().First(t => t.PK_ID == taskPKId); if (taskInfo == null) throw Oops.Oh($"任务信息获取失败"); if (string.IsNullOrWhiteSpace(taskInfo.BOOK_ORDER_NO)) throw Oops.Oh($"任务信息的订舱主键不存在"); if (taskInfo.TASK_TYPE != TaskBusiTypeEnum.SI_FEEDBACK.ToString()) throw Oops.Oh($"当前任务类型不是{TaskBusiTypeEnum.SI_FEEDBACK.GetDescription()}"); var bookOrderList = _bookingOrderRepository.EntityContext.Queryable() .InnerJoin((bk, ctn) => bk.Id == ctn.BILLID) .Where((bk, ctn) => bk.Id == long.Parse(taskInfo.BOOK_ORDER_NO) && bk.TenantId == UserManager.TENANT_ID) .Select((bk, ctn) => new { bk = bk, ctn = ctn }).ToList(); var orderInfo = bookOrderList.FirstOrDefault().bk; model.TaskId = taskInfo.PK_ID; var siFeedBackList = _taskSIFeedBackInfoRepository.EntityContext.Queryable() .InnerJoin((si, ctn) => si.PK_ID == ctn.P_PKID) .Where((si, ctn) => si.TASK_PKID == model.TaskId && si.TenantId == UserManager.TENANT_ID) .Select((si, ctn) => new { si = si, ctn = ctn }).ToList(); if (siFeedBackList.Count == 0) throw Oops.Oh($"SI反馈信息不存在"); var siFeedBackInfo = siFeedBackList.FirstOrDefault().si; var resultInfo = siFeedBackInfo.Adapt(); resultInfo.ContaList = siFeedBackList.Select(t => t.ctn.Adapt()).ToList(); model.BusiInfo = resultInfo; if (orderInfo != null) { //订舱 model.BookingOrder = orderInfo.Adapt(); } //进行数据比对确认差异字段KEY var mainDiff = await InnerCompareMainInfoDiff(orderInfo, siFeedBackInfo); model.SICompareOrderKeyList = mainDiff; var contaDiff = await InnerCompareContaInfoDiff(bookOrderList.Select(t=>t.ctn).ToList(), siFeedBackList.Select(t=>t.ctn).ToList()); model.SICompareOrderContaKeyList = contaDiff; } catch (Exception ex) { throw Oops.Bah("获取获取单票账单详情异常,{0}", ex.Message); } return model; } #endregion private List InnerCompare(object srcModel,object targetModel) { List list = new List(); if(srcModel is BookingOrder) { var srcBK = (BookingOrder)srcModel; var targetBK = (BookingOrder)targetModel; var bookProps = typeof(BookingOrder).GetProperties(); list = bookProps.Select(prop => { var bk1Val = prop.GetValue(srcBK); var bk2Val = prop.GetValue(targetBK); if (prop.PropertyType == typeof(string)) { string st1 = (bk1Val as string).AdjustString(); string st2 = (bk2Val as string).AdjustString(); if (st1 != st2) { return new TaskCompareResultDto { Code = prop.Name, SrcVal = bk1Val, TargetVal = bk2Val, IsDiff = true, ValType = prop.PropertyType }; } return new TaskCompareResultDto { Code = prop.Name, SrcVal = bk1Val, TargetVal = bk2Val, IsDiff = false, ValType = prop.PropertyType }; } else if (prop.PropertyType == typeof(int?)) { var dt1 = bk1Val as int?; var dt2 = bk2Val as int?; if (dt1 != dt2) { return new TaskCompareResultDto { Code = prop.Name, SrcVal = bk1Val, TargetVal = bk2Val, IsDiff = true, ValType = prop.PropertyType }; } return new TaskCompareResultDto { Code = prop.Name, SrcVal = bk1Val, TargetVal = bk2Val, IsDiff = true, ValType = prop.PropertyType }; } else if (prop.PropertyType == typeof(decimal?)) { var dt1 = bk1Val as decimal?; var dt2 = bk2Val as decimal?; if (dt1 != dt2) { return new TaskCompareResultDto { Code = prop.Name, SrcVal = bk1Val, TargetVal = bk2Val, IsDiff = true, ValType = prop.PropertyType }; } return new TaskCompareResultDto { Code = prop.Name, SrcVal = bk1Val, TargetVal = bk2Val, IsDiff = true, ValType = prop.PropertyType }; } if (bk1Val != bk2Val) return new TaskCompareResultDto { Code = prop.Name, SrcVal = bk1Val, TargetVal = bk2Val, IsDiff = true, ValType = prop.PropertyType }; return new TaskCompareResultDto { Code = prop.Name, SrcVal = bk1Val, TargetVal = bk2Val, IsDiff = false, ValType = prop.PropertyType }; }).ToList(); } return list; } #region 比较主信息 /// /// 比较主信息 /// /// 订舱详情 /// SI反馈详情 /// 返回差异 private async Task> InnerCompareMainInfoDiff(BookingOrder bookingOrder, TaskSIFeedBackInfo taskSIFeedBackInfo) { List resultList = new List(); //需要比对的字段 var compareField = new string[] { "SHIPPER", "CONSIGNEE", "NOTIFYPARTY", "MARKS", "DESCRIPTION", "BLFRT", "SERVICE", "ISSUETYPE", "PORTLOAD", "PORTDISCHARGE", "TRANSPORT", "DESTINATION", "PKGS", "KGS", "CBM", "KINDPKGS", "THIRDPAYADDR" }; var bookProps = typeof(BookingOrder).GetProperties(); var feedProps = typeof(TaskSIFeedBackInfo).GetProperties(); resultList = bookProps.GroupJoin(feedProps, l => l.Name.ToUpper(), r => r.Name.ToUpper(), (l, r) => { if (compareField.Any(x => x.Equals(l.Name, StringComparison.OrdinalIgnoreCase))) { var currList = r.ToList(); if (currList.Count > 0) { var si = r.FirstOrDefault(); var bkVal = l.GetValue(bookingOrder); var siVal = si.GetValue(taskSIFeedBackInfo); if (l.PropertyType == typeof(string)) { string st1 = (bkVal as string).AdjustString(); string st2 = (siVal as string).AdjustString(); if (!st1.Equals(st2)) { return l.Name.ToUpper(); } return string.Empty; } else if (l.PropertyType == typeof(int?)) { var dt1 = bkVal as int?; var dt2 = siVal as int?; if (!dt1.Equals(dt2)) { return l.Name.ToUpper(); } return string.Empty; } else if (l.PropertyType == typeof(decimal?)) { var dt1 = bkVal as decimal?; var dt2 = siVal as decimal?; if (!dt1.Equals(dt2)) { return l.Name.ToUpper(); } return string.Empty; } } return string.Empty; } return string.Empty; }).Where(t => !string.IsNullOrWhiteSpace(t)).ToList(); return resultList; } #endregion #region 比较箱信息 /// /// 比较箱信息 /// /// 订舱箱信息 /// SI反馈箱信息 /// 返回差异 private async Task> InnerCompareContaInfoDiff(List bookContaList,List siContaList) { List resultList = new List(); var bookProps = typeof(BookingCtn).GetProperties(); var feedProps = typeof(TaskSIFeedBackContaInfo).GetProperties(); resultList = siContaList.GroupJoin(bookContaList, l => l.CONTA_NO, r => r.CNTRNO, (l, r) => { var currList = r.ToList(); if (currList.Count > 0) { var bkCtn = currList.FirstOrDefault(); if (!l.KGS.Equals(bkCtn.KGS) || !l.PKGS.Equals(bkCtn.PKGS) || !l.SEAL_NO.Equals(bkCtn.SEALNO) || !l.CONTA_TYPE.Equals(bkCtn.CTNALL) || !l.CBM.Equals(bkCtn.CBM)) { return l.CONTA_NO; } return String.Empty; } return l.CONTA_NO; }).Where(t => !string.IsNullOrWhiteSpace(t)).ToList(); return resultList; } #endregion #region 获取VGM比较结果 /// /// 获取VGM比较结果 /// /// 任务主键 /// 返回结果 [HttpGet("/TaskManage/GetVGMCompareResult")] public async Task GetVGMCompareResult(string taskPKId) { TaskVgmCompareResultDto model = new TaskVgmCompareResultDto(); List list = new List(); List list2 = new List(); try { var taskInfo = _taskBaseInfoRepository.AsQueryable().First(t => t.PK_ID == taskPKId); if (taskInfo == null) throw Oops.Oh($"任务信息获取失败"); if (string.IsNullOrWhiteSpace(taskInfo.BOOK_ORDER_NO)) throw Oops.Oh($"任务信息的订舱主键不存在"); if (taskInfo.TASK_TYPE != TaskBusiTypeEnum.VGM_COMPARE.ToString()) throw Oops.Oh($"当前任务类型不是{TaskBusiTypeEnum.VGM_COMPARE.GetDescription()}"); var vgmList = _taskVGMFeedBackInfoRepository.AsQueryable().Where(t => t.TASK_PKID == taskInfo.PK_ID) .ToList(); if(vgmList.Count == 0) throw Oops.Oh($"VGM反馈信息不存在"); var contaList = _bookingOrderContaRepository.AsQueryable().Where(t => t.BILLID == long.Parse(taskInfo.BOOK_ORDER_NO)).ToList(); list = contaList.GroupJoin(vgmList, l => l.CNTRNO?.Trim(), r => r.CONTA_NO?.Trim(), (l, r) => { var currInfo = r.FirstOrDefault(); TaskVgmCompareDto md = l.Adapt(); md.compareDiffList = new List(); if (currInfo != null) { if(l.SEALNO != currInfo.SEAL_NO) { md.compareDiffList.Add(nameof(TaskVgmCompareDto.SealNo)); } if (l.CTNCODE != currInfo.CONTA_TYPE) { md.compareDiffList.Add(nameof(TaskVgmCompareDto.ContaType)); } if (l.CTNALL != currInfo.CONTA_TYPE_NAME) { md.compareDiffList.Add(nameof(TaskVgmCompareDto.ContaTypeName)); } if (l.KGS != currInfo.KGS) { md.compareDiffList.Add(nameof(TaskVgmCompareDto.KGS)); } if (l.TAREWEIGHT != currInfo.TAREWEIGHT) { md.compareDiffList.Add(nameof(TaskVgmCompareDto.TareWeight)); } if (l.WEIGHKGS != currInfo.WEIGHKGS) { md.compareDiffList.Add(nameof(TaskVgmCompareDto.WeighKGs)); } if (l.WEIGHTYPE != currInfo.WEIGHTYPE) { md.compareDiffList.Add(nameof(TaskVgmCompareDto.WeighType)); } } else { md.compareDiffList = new List { nameof(TaskVgmCompareDto.ContaNo), nameof(TaskVgmCompareDto.SealNo), nameof(TaskVgmCompareDto.ContaType), nameof(TaskVgmCompareDto.ContaTypeName), nameof(TaskVgmCompareDto.KGS), nameof(TaskVgmCompareDto.TareWeight), nameof(TaskVgmCompareDto.WeighKGs), nameof(TaskVgmCompareDto.WeighType), }; } return md; }).ToList(); model.bookOrderCompareList = list; list2 = vgmList.GroupJoin(contaList, l => l.CONTA_NO?.Trim(), r => r.CNTRNO?.Trim(), (l, r) => { var currInfo = r.FirstOrDefault(); TaskVgmCompareDto md = l.Adapt(); md.compareDiffList = new List(); if (currInfo != null) { if (l.SEAL_NO != currInfo.SEALNO) { md.compareDiffList.Add(nameof(TaskVgmCompareDto.SealNo)); } if (l.CONTA_TYPE != currInfo.CTNCODE) { md.compareDiffList.Add(nameof(TaskVgmCompareDto.ContaType)); } if (l.CONTA_TYPE_NAME != currInfo.CTNALL) { md.compareDiffList.Add(nameof(TaskVgmCompareDto.ContaTypeName)); } if (l.KGS != currInfo.KGS) { md.compareDiffList.Add(nameof(TaskVgmCompareDto.KGS)); } if (l.TAREWEIGHT != currInfo.TAREWEIGHT) { md.compareDiffList.Add(nameof(TaskVgmCompareDto.TareWeight)); } if (l.WEIGHKGS != currInfo.WEIGHKGS) { md.compareDiffList.Add(nameof(TaskVgmCompareDto.WeighKGs)); } if (l.WEIGHTYPE != currInfo.WEIGHTYPE) { md.compareDiffList.Add(nameof(TaskVgmCompareDto.WeighType)); } } else { md.compareDiffList = new List { nameof(TaskVgmCompareDto.ContaNo), nameof(TaskVgmCompareDto.SealNo), nameof(TaskVgmCompareDto.ContaType), nameof(TaskVgmCompareDto.ContaTypeName), nameof(TaskVgmCompareDto.KGS), nameof(TaskVgmCompareDto.TareWeight), nameof(TaskVgmCompareDto.WeighKGs), nameof(TaskVgmCompareDto.WeighType), }; } return md; }).ToList(); model.vgmCompareList = list2; } catch (Exception ex) { throw Oops.Bah("获取VGM比较结果异常,{0}", ex.Message); } return model; } #endregion #region 更新订舱(VGM比较更新) /// /// 更新订舱(VGM比较更新) /// /// 任务主键 /// 返回结果 [HttpPost("/TaskManage/SaveBookingVGM")] public async Task SaveBookingVGM(string taskPKId) { TaskManageOrderResultDto result = new TaskManageOrderResultDto(); try { var taskInfo = _taskBaseInfoRepository.AsQueryable().First(t => t.PK_ID == taskPKId); if (taskInfo == null) throw Oops.Oh($"任务信息获取失败"); if (string.IsNullOrWhiteSpace(taskInfo.BOOK_ORDER_NO)) throw Oops.Oh($"任务信息的订舱主键不存在"); if (taskInfo.TASK_TYPE != TaskBusiTypeEnum.VGM_COMPARE.ToString()) throw Oops.Oh($"当前任务类型不是{TaskBusiTypeEnum.VGM_COMPARE.GetDescription()}"); //取订舱详情(包含集装箱) var bookOrderList = _bookingOrderRepository.EntityContext.Queryable() .LeftJoin(_bookingOrderRepository.EntityContext.Queryable(), (bk, ctn) => bk.Id == ctn.BILLID) .Where((bk, ctn) => bk.Id == long.Parse(taskInfo.BOOK_ORDER_NO) && bk.TenantId == UserManager.TENANT_ID) .Select((bk, ctn) => new { bk = bk, ctn = ctn }).ToList(); var orderInfo = bookOrderList.FirstOrDefault().bk; List orderCtnList = new List(); //这里是左连接查询,解决集装箱为空的情况 if (bookOrderList.Any(t => t.ctn.Id > 0)) orderCtnList = bookOrderList.Select(t => t.ctn).ToList(); var contaList = _taskVGMFeedBackInfoRepository.AsQueryable().Where(t => t.TASK_PKID == taskInfo.PK_ID).ToList(); var si2orderCtnList = contaList.GroupJoin(orderCtnList, l => l.CONTA_NO?.Trim(), r => r.CNTRNO?.Trim(), (l, r) => { var currInfo = r.FirstOrDefault(); var contaInfo = l.Adapt(); if (currInfo == null) { contaInfo.BILLID = orderInfo.Id; contaInfo.CreatedTime = DateTime.Now; contaInfo.CreatedUserId = UserManager.UserId; contaInfo.CreatedUserName = UserManager.Name; contaInfo.UpdatedTime = contaInfo.CreatedTime; contaInfo.UpdatedUserId = UserManager.UserId; contaInfo.UpdatedUserName = UserManager.Name; return new { OperType = "insert", obj = contaInfo }; } else { currInfo.Id = contaInfo.Id; currInfo.BILLID = contaInfo.BILLID; currInfo.UpdatedTime = DateTime.Now; currInfo.UpdatedUserId = UserManager.UserId; currInfo.UpdatedUserName = UserManager.Name; return new { OperType = "update", obj = currInfo }; } }).ToList(); var delList = orderCtnList.GroupJoin(contaList, l => l.CNTRNO?.Trim(), r => r.CONTA_NO?.Trim(), (l, r) => { var currInfo = r.FirstOrDefault(); if (currInfo == null) { l.UpdatedTime = DateTime.Now; l.UpdatedUserId = UserManager.UserId; l.UpdatedUserName = UserManager.Name; return new { OperType = "delete", obj = l }; } return new { OperType = string.Empty, obj = l }; }).Where(t => t.OperType != string.Empty).ToList(); if (delList.Count > 0) si2orderCtnList.AddRange(delList); if (si2orderCtnList.Count > 0) { si2orderCtnList.ForEach(async ctn => { if (ctn.OperType == "insert") { //插入 await _bookingOrderContaRepository.InsertAsync(ctn.obj); } else if (ctn.OperType == "update") { //更新 await _bookingOrderContaRepository.AsUpdateable(ctn.obj).UpdateColumns(it => new { it.CTNALL, it.SEALNO, it.PKGS, it.KGS, it.CBM, it.UpdatedTime, it.UpdatedUserId, it.UpdatedUserName, }).ExecuteCommandAsync(); } else if (ctn.OperType == "delete") { await _bookingOrderContaRepository.DeleteAsync(x => x.Id == ctn.obj.Id); } }); } result.succ = true; result.msg = "更新订舱成功"; } catch(Exception ex) { throw Oops.Bah("更新订舱(VGM比较更新)异常,{0}", ex.Message); } return result; } #endregion #region 获取换船详情 /// /// 获取换船详情 /// /// 任务主键 /// 返回结果 [HttpGet("/TaskManage/GetChangeShipInfo")] public async Task GetChangeShipInfo(string taskPKId) { TaskChangeShipResultDto model = new TaskChangeShipResultDto(); try { var taskInfo = _taskBaseInfoRepository.AsQueryable().First(t => t.PK_ID == taskPKId); if (taskInfo == null) throw Oops.Oh($"任务信息获取失败"); if (string.IsNullOrWhiteSpace(taskInfo.BOOK_ORDER_NO)) throw Oops.Oh($"任务信息的订舱主键不存在"); if (taskInfo.TASK_TYPE != TaskBusiTypeEnum.CHANGE_SHIP.ToString()) throw Oops.Oh($"当前任务类型不是{TaskBusiTypeEnum.CHANGE_SHIP.GetDescription()}"); BookingOrder bookingOrder = null; if (!string.IsNullOrWhiteSpace(taskInfo.BOOK_ORDER_NO)) bookingOrder = _bookingOrderRepository.AsQueryable().First(t=>t.Id == long.Parse(taskInfo.BOOK_ORDER_NO)); //这里参考源程序,如果任务没有对应订舱数据则通过主单号匹配一条订舱数据 if(bookingOrder == null) bookingOrder = _bookingOrderRepository.AsQueryable().First(t => t.MBLNO == taskInfo.MBL_NO && !t.ParentId.HasValue); if (bookingOrder == null) throw Oops.Oh($"订舱信息获取失败,MBLNO={taskInfo.MBL_NO}"); if (string.IsNullOrWhiteSpace(taskInfo.RESULT_NOTE)) throw Oops.Oh($"任务反馈详情不存在"); var rtl = Newtonsoft.Json.JsonConvert.DeserializeObject(taskInfo.RESULT_NOTE); model.TaskId = taskInfo.PK_ID; model.TaskStatus = taskInfo.STATUS; model.TaskStatusName = taskInfo.STATUS_NAME; model.Vessel = rtl.vessel.ToString(); model.Voyno = rtl.voyno.ToString(); model.ShipAgency = rtl.shipagency == null? rtl.shipagency.ToString():""; model.MailUrl = rtl.mail_url.ToString(); model.OriginalVessel = bookingOrder.VESSEL; model.OriginalVoyno = bookingOrder.VOYNO; model.MBlNo = bookingOrder.MBLNO; //获得未处理的任务数量 model.TotalTask = await _taskBaseInfoRepository.AsQueryable().Where(t => t.CreatedTime < taskInfo.CreatedTime && t.STATUS == TaskStatusEnum.Create.ToString() && (t.TASK_TYPE == TaskBusiTypeEnum.CHANGE_SHIP.ToString() || t.TASK_TYPE == TaskBusiTypeEnum.ABORT_CHANGE_SHIP.ToString())).CountAsync(); } catch (Exception ex) { throw Oops.Bah("获取换船详情异常,{0}", ex.Message); } return model; } #endregion #region 获取取消换船详情 /// /// 获取取消换船详情 /// /// 任务主键 /// 返回结果 [HttpGet("/TaskManage/GetAbortChangeShipInfo")] public async Task GetAbortChangeShipInfo(string taskPKId) { TaskChangeShipResultDto model = new TaskChangeShipResultDto(); try { var taskInfo = _taskBaseInfoRepository.AsQueryable().First(t => t.PK_ID == taskPKId); if (taskInfo == null) throw Oops.Oh($"任务信息获取失败"); if (string.IsNullOrWhiteSpace(taskInfo.BOOK_ORDER_NO)) throw Oops.Oh($"任务信息的订舱主键不存在"); if (taskInfo.TASK_TYPE != TaskBusiTypeEnum.ABORT_CHANGE_SHIP.ToString()) throw Oops.Oh($"当前任务类型不是{TaskBusiTypeEnum.ABORT_CHANGE_SHIP.GetDescription()}"); BookingOrder bookingOrder = null; if (!string.IsNullOrWhiteSpace(taskInfo.BOOK_ORDER_NO)) bookingOrder = _bookingOrderRepository.AsQueryable().First(t => t.Id == long.Parse(taskInfo.BOOK_ORDER_NO)); //这里参考源程序,如果任务没有对应订舱数据则通过主单号匹配一条订舱数据 if (bookingOrder == null) bookingOrder = _bookingOrderRepository.AsQueryable().First(t => t.MBLNO == taskInfo.MBL_NO && !t.ParentId.HasValue); if (bookingOrder == null) throw Oops.Oh($"订舱信息获取失败,MBLNO={taskInfo.MBL_NO}"); if (string.IsNullOrWhiteSpace(taskInfo.RESULT_NOTE)) throw Oops.Oh($"任务反馈详情不存在"); var rtl = Newtonsoft.Json.JsonConvert.DeserializeObject(taskInfo.RESULT_NOTE); model.TaskId = taskInfo.PK_ID; model.TaskStatus = taskInfo.STATUS; model.TaskStatusName = taskInfo.STATUS_NAME; model.Vessel = rtl.vessel.ToString(); model.Voyno = rtl.voyno.ToString(); model.ShipAgency = rtl.shipagency == null ? rtl.shipagency.ToString() : ""; model.MailUrl = rtl.mail_url.ToString(); model.OriginalVessel = bookingOrder.VESSEL; model.OriginalVoyno = bookingOrder.VOYNO; model.MBlNo = bookingOrder.MBLNO; //获得未处理的任务数量 model.TotalTask = await _taskBaseInfoRepository.AsQueryable().Where(t => t.CreatedTime < taskInfo.CreatedTime && t.STATUS == TaskStatusEnum.Create.ToString() && (t.TASK_TYPE == TaskBusiTypeEnum.CHANGE_SHIP.ToString() || t.TASK_TYPE == TaskBusiTypeEnum.ABORT_CHANGE_SHIP.ToString())).CountAsync(); } catch (Exception ex) { throw Oops.Bah("获取取消换船详情异常,{0}", ex.Message); } return model; } #endregion #region 手工批量重新比对BC /// /// 手工批量重新比对BC /// /// 任务主键数组 /// 返回结果 [HttpPost("/TaskManage/ManualReCompareBC")] public async Task ManualReCompareBC(string[] PKIds) { TaskManageOrderResultDto result = new TaskManageOrderResultDto(); string batchNo = IDGen.NextID().ToString(); _logger.LogInformation("批次={no} ids={ids} 手工批量重新比对BC开始", batchNo, string.Join(",", PKIds)); try { var taskList = _taskBaseInfoRepository.AsQueryable().Where(t => PKIds.Contains(t.PK_ID)).ToList(); _logger.LogInformation("批次={no} 获取任务完成,Num={Num}", batchNo, taskList.Count); var list = new List(); taskList.ForEach(async tsk => { var rlt = await InnerSingleManualReCompareBC(tsk); list.Add(rlt); }); if (list.Any(t => !t.succ)) { result.msg = "失败"; result.succ = false; } else { result.msg = "成功"; result.succ = true; } } catch (Exception ex) { throw Oops.Bah("手工批量重新比对BC异常,{0}", ex.Message); } return result; } #endregion #region 手工单票重新比对BC /// /// 手工单票重新比对BC /// /// 任务详情 /// 返回结果 private async Task InnerSingleManualReCompareBC(TaskBaseInfo model) { TaskManageOrderResultDto result = new TaskManageOrderResultDto(); /* 1、通过任务的报文表获取BC的报文。 */ try { var storeInfo = await _taskStoreMsgInfoRepository.AsQueryable() .Where(t => t.TASK_PKID == model.PK_ID && t.MSG_TYPE == TaskStoreMsgTypeEnum.BC_MSG.ToString()).FirstAsync(); if(storeInfo == null) throw Oops.Oh("MBL_NO={0},获取{1}报文失败", model.MBL_NO,TaskStoreMsgTypeEnum.BC_MSG.GetDescription()); var rtl = Newtonsoft.Json.JsonConvert.DeserializeObject(storeInfo.MSG_JSON); string msg = string.Empty; //2023-02-02 测试过程中发现JSON数据格式有了变化,这里增加兼容 if(rtl.mesage != null) { msg = JSON.Serialize(rtl.mesage); } else { msg = storeInfo.MSG_JSON; } if (string.IsNullOrWhiteSpace(msg)) throw Oops.Oh("MBL_NO={0},解析{1}报文详情异常", model.MBL_NO, TaskStoreMsgTypeEnum.BC_MSG.GetDescription()); var bookOrderList = _bookingOrderRepository.EntityContext.Queryable() .InnerJoin((bk, ctn) => bk.Id == ctn.BILLID) .Where((bk, ctn) => bk.Id == long.Parse(model.BOOK_ORDER_NO) && bk.TenantId == UserManager.TENANT_ID) .Select((bk, ctn) => new { bk = bk, ctn = ctn }).ToList(); //获取订舱详情与BC进行比对 var orderInfo = bookOrderList.FirstOrDefault().bk; List ctnList = new List(); if (bookOrderList.Any(t => t.ctn != null)) ctnList = bookOrderList.Select(t => t.ctn).ToList(); if (orderInfo == null) throw Oops.Oh("MBL_NO={0},获取订舱详情失败", model.MBL_NO); TaskBCStoreResultInfo bcStoreInfo = JSON.Deserialize(msg); //BC比较 var compareResult = InnerCompareBC(bcStoreInfo,orderInfo, ctnList); if(!compareResult.succ) { //更新任务的反馈结果 model.RESULT_NOTE = compareResult.msg; model.UpdatedTime = DateTime.Now; model.UpdatedUserId = UserManager.UserId; model.UpdatedUserName = UserManager.Name; await _taskBaseInfoRepository.AsUpdateable(model).UpdateColumns(it => new { it.UpdatedTime, it.UpdatedUserId, it.UpdatedUserName, it.RESULT_NOTE, }).ExecuteCommandAsync(); } else { //置任务状态为完成 model.STATUS = TaskStatusEnum.Complete.ToString(); model.STATUS_NAME = TaskStatusEnum.Complete.GetDescription(); model.COMPLETE_DATE = DateTime.Now; model.COMPLETE_DEAL = TaskCompleteDealEnum.MANUAL.ToString(); model.COMPLETE_DEAL_NAME = TaskCompleteDealEnum.MANUAL.GetDescription(); model.UpdatedTime = DateTime.Now; model.UpdatedUserId = UserManager.UserId; model.UpdatedUserName = UserManager.Name; await _taskBaseInfoRepository.AsUpdateable(model).UpdateColumns(it => new { it.UpdatedTime, it.UpdatedUserId, it.UpdatedUserName, it.STATUS, it.STATUS_NAME, it.COMPLETE_DATE, it.COMPLETE_DEAL, it.COMPLETE_DEAL_NAME }).ExecuteCommandAsync(); //更新订舱的ETD(记个日志) if (!string.IsNullOrWhiteSpace(bcStoreInfo.ETD)) { DateTime etd = DateTime.MinValue; if(DateTime.TryParse(bcStoreInfo.ETD,out etd)) { orderInfo.ETD = etd; orderInfo.UpdatedTime = DateTime.Now; orderInfo.UpdatedUserId = UserManager.UserId; orderInfo.UpdatedUserName = UserManager.Name; await _bookingOrderRepository.AsUpdateable(orderInfo).UpdateColumns(it => new { it.UpdatedTime, it.UpdatedUserId, it.UpdatedUserName, it.ETD }).ExecuteCommandAsync(); } } //【预留】异步推送后台任务(订舱自动放舱-BookingFangCang) //【预留】异步推送后台任务(下货纸-Xiahuozhi) } result.succ = true; result.msg = "处理成功"; } catch (Exception ex) { result.succ = false; result.msg = $"手工重新比对BC异常,{ex.Message}"; //throw Oops.Bah("手工重新比对BC异常,{0}", ex.Message); } return result; } #endregion #region 单票比对BC /// /// 单票比对BC /// /// BC回执详情 /// 订舱详情 /// 订舱集装箱列表 /// 返回结果 private TaskManageOrderResultDto InnerCompareBC(TaskBCStoreResultInfo bcStoreInfo,BookingOrder orderInfo,List ctnList) { TaskManageOrderResultDto result = new TaskManageOrderResultDto { succ = true}; try { List> rltTupleList = new List>(); /* 迁移过来的注释 2021-9-28,需求再变,BC需要再次比对约号 2021-7-19 需求修改:BC不需要再对比约号 */ //约号 if (!string.IsNullOrWhiteSpace(orderInfo.CONTRACTNO)) { if ((string.IsNullOrWhiteSpace(bcStoreInfo.BJH) || !Regex.IsMatch(orderInfo.CONTRACTNO, $"\\b{bcStoreInfo.BJH.Trim()}\\b")) && (string.IsNullOrWhiteSpace(bcStoreInfo.FWHT) || !Regex.IsMatch(orderInfo.CONTRACTNO, $"\\b{bcStoreInfo.FWHT.Trim()}\\b"))) { rltTupleList.Add(new Tuple(false, "约号不一致")); } } else { if (!string.IsNullOrWhiteSpace(bcStoreInfo.BJH) || !string.IsNullOrWhiteSpace(bcStoreInfo.FWHT)) { rltTupleList.Add(new Tuple(false, "约号不一致")); } } #region 集装箱 //集装箱 if (bcStoreInfo.CntrTotal != orderInfo.CNTRTOTAL) { //集装箱型 var ediCtnList = _cache.GetAllMappingCtn().GetAwaiter().GetResult() .Where(t => t.Module.Equals(CONST_MAPPING_MODULE, StringComparison.OrdinalIgnoreCase) && !string.IsNullOrWhiteSpace(t.CarrierCode) && t.CarrierCode.Equals(orderInfo.CARRIERID, StringComparison.OrdinalIgnoreCase)).ToList(); var storeCtnList = bcStoreInfo.CntrTotal.Split(new char[] { ';' }).Select(t => { var currArg = t.Split(new char[] { 'x' }); return new { Code = currArg[1]?.Trim(), Num = int.Parse(currArg[0]?.Trim()) }; }).GroupBy(t => t.Code) .Select(t => { return new { Code = t.Key, Num = t.Sum(x => x.Num) }; }).ToList(); var orderCtnListctnList = ctnList.Select(t => { var mapCtn = ediCtnList.FirstOrDefault(x => x.Code.Equals(t.CTNCODE)); if (mapCtn != null && !string.IsNullOrWhiteSpace(mapCtn.MapCode)) return new { Code = mapCtn.MapCode, Num = t.CTNNUM.HasValue ? t.CTNNUM.Value : 1 }; return new { Code = t.CTNCODE, Num = t.CTNNUM.HasValue ? t.CTNNUM.Value : 1 }; }).GroupBy(t => t.Code) .Select(t => { return new { Code = t.Key, Num = t.Sum(x => x.Num) }; }).ToList(); if (storeCtnList.Count != orderCtnListctnList.Count) { rltTupleList.Add(new Tuple(false, "箱型箱量不一致")); } else { var totalList = storeCtnList.GroupJoin(orderCtnListctnList, l => l.Code, r => r.Code, (l, r) => { var rModel = r.FirstOrDefault(); if (rModel == null) { return false; } else { if (l.Num != rModel.Num) return false; } return true; }).ToList(); if (totalList.Any(t => !t)) { rltTupleList.Add(new Tuple(false, "箱型箱量不一致")); } } } #endregion //船名 if (bcStoreInfo.Vessel != orderInfo.VESSEL?.Trim()) { rltTupleList.Add(new Tuple(false, "船名不一致")); } //航次 if (bcStoreInfo.Voyno?.Replace("1MA", "") != orderInfo.VOYNO?.Trim() && bcStoreInfo.Voyno2 != orderInfo.VOYNO?.Trim() && bcStoreInfo.Voyno3 != orderInfo.VOYNO?.Trim()) { rltTupleList.Add(new Tuple(false, "航次不一致")); } /* //2021-10-12,增加最小、最大、运输温度,湿度,通风 的比较 //2021-11-23,备注中含有NOR,不比较温度湿度等信息 2023-02-02 这里补充了一下EDIREMARK的判断,用正则匹配NOR信息。NOR(冻代干集装箱) */ if (orderInfo.CARGOID == "R" && (string.IsNullOrWhiteSpace(orderInfo.SOREMARK) || !Regex.IsMatch(orderInfo.SOREMARK, "\\bNOR\\b"))) { //最低温度 var compareReult = CompareTemperatureNum(orderInfo.TEMPMIN, bcStoreInfo.TempMin, "temp"); if (!compareReult.Item1) rltTupleList.Add(compareReult); //最高温度 compareReult = CompareTemperatureNum(orderInfo.TEMPMAX, bcStoreInfo.TempMax, "temp", "最高温度"); if (!compareReult.Item1) rltTupleList.Add(compareReult); //运输温度 compareReult = CompareTemperatureNum(orderInfo.TEMPSET, bcStoreInfo.TempTransport, "temp", "运输温度"); if (!compareReult.Item1) rltTupleList.Add(compareReult); //湿度 compareReult = CompareTemperatureNum(orderInfo.HUMIDITY, bcStoreInfo.Humidity, "humidity", "湿度"); if (!compareReult.Item1) rltTupleList.Add(compareReult); //通风 compareReult = CompareTemperatureNum(orderInfo.REEFERF, bcStoreInfo.VentilationCubicMeter, "vent", "通风"); if (!compareReult.Item1) rltTupleList.Add(compareReult); } /* * 2021-12-3,捷丰要求加卸货港和目的地校验,规则: * A:大简云里卸货港字段‘,’之前的字符和BC里卸货港‘,’之前的字段。 * 1.一致,自动发送下货纸 * 2.不一致,生成待处理下货纸任务。 * B:bc如果有最终交货地 那么要和系统目的港对比;最终交货地空白 就不用对比这个地方 */ string orderPortDischarge = orderInfo.PORTDISCHARGE.Split(new char[] { ',' }).FirstOrDefault()?.Trim(); string storePortDischarge = bcStoreInfo.PortDischargeEName.Split(new char[] { ',' }).FirstOrDefault()?.Trim(); if (orderPortDischarge != storePortDischarge) rltTupleList.Add(new Tuple(false, "卸货港不一致")); string orderDest = orderInfo.DESTINATION.Split(new char[] { ',' }).FirstOrDefault()?.Trim(); string storeDest = bcStoreInfo.ZZJHD.Split(new char[] { ',' }).FirstOrDefault()?.Trim(); if (orderDest != storeDest) rltTupleList.Add(new Tuple(false, "目的地不一致")); if (rltTupleList.Any(t => !t.Item1)) { result.succ = false; result.msg = string.Join(";", rltTupleList.Select(t => t.Item2).ToArray()); } } catch(Exception ex) { throw Oops.Bah("{0}单票比对BC异常,{1}",nameof(InnerCompareBC), ex.Message); } return result; } #endregion #region 对比温度 /// /// 对比温度 /// /// 订舱数值 /// 回执数值 /// 操作类型 temp-温度 humidity-湿度 vent-通风 /// 显示名称 /// 返回结果 private Tuple CompareTemperatureNum(string orderTemperature,string storeTemperature,string operType = "temp",string showName = "最低温度") { decimal orderTemp = int.MaxValue; decimal storeTemp = int.MaxValue; decimal.TryParse(orderTemperature, out orderTemp); if (!string.IsNullOrWhiteSpace(storeTemperature)) { if (operType == "temp") { decimal.TryParse(Regex.Match(storeTemperature, "(\\-?([0-9]?|[0-9]+)\\.?[0-9]+)(?=C)").Value, out storeTemp); } else if (operType == "humidity") { decimal.TryParse(Regex.Match(storeTemperature, "\\[0-9]+").Value, out storeTemp); } else if (operType == "vent") { decimal.TryParse(storeTemperature, out storeTemp); } } if (storeTemp != int.MaxValue && orderTemp != int.MaxValue) { if (storeTemp != orderTemp) return new Tuple(false, $"{showName}不一致"); } else { if (storeTemp != int.MaxValue || orderTemp != int.MaxValue) return new Tuple(false, $"{showName}不一致"); } return new Tuple(true, ""); } #endregion #region 下载截单EDI /// /// 下载截单EDI /// /// 任务主键 /// 订单号 /// 是否使用货代代码 /// 货代代码 /// 货代称呼 /// 文件功能 (9原始,1 更新,5 退舱 ) /// 发送类型 E-截单 /// 返回结果 [HttpGet("/TaskManage/DownloadClosingEDI")] public async Task DownloadClosingEDI([FromQuery] string taskPKId, [FromQuery] string orderNo, [FromQuery] bool useForwarderCode, [FromQuery] string forwarderCode, [FromQuery] string forwarderName, [FromQuery] string fileRole, [FromQuery] string sendType) { if (sendType?.ToUpper() != "E") throw Oops.Oh($"sendType只接收E-截单"); var taskInfo = _taskBaseInfoRepository.AsQueryable().First(t => t.PK_ID == taskPKId); if (taskInfo == null) throw Oops.Oh($"任务信息获取失败"); if (string.IsNullOrWhiteSpace(taskInfo.BOOK_ORDER_NO)) throw Oops.Oh($"任务信息的订舱主键不存在"); if (taskInfo.TASK_TYPE != TaskBusiTypeEnum.SI_FEEDBACK.ToString()) throw Oops.Oh($"当前任务类型不是{TaskBusiTypeEnum.SI_FEEDBACK.GetDescription()}"); BookingOrder bookingOrder = null; if (!string.IsNullOrWhiteSpace(taskInfo.BOOK_ORDER_NO)) bookingOrder = _bookingOrderRepository.AsQueryable().First(t => t.Id == long.Parse(taskInfo.BOOK_ORDER_NO)); if (bookingOrder == null) throw Oops.Oh($"订舱信息获取失败,MBLNO={taskInfo.MBL_NO}"); var model = new BookingOrClosingEDIOrderDto { Id = bookingOrder.Id, orderNo = orderNo, useForwarderCode = useForwarderCode, forwarderCode = forwarderCode, forwarderName = forwarderName, fileRole = fileRole, send = false, sendType = sendType }; var bookingOrderService = _namedBookingOrderServiceProvider.GetService(nameof(BookingOrderService)); var filePath = await bookingOrderService.InnerBookingOrClosingEDI(model); var fileInfo = new FileInfo(filePath); var result = new FileStreamResult(new FileStream(filePath, FileMode.Open), "application/octet-stream") { FileDownloadName = fileInfo.Name }; return result; } #endregion #region 发送截单EDI /// /// 发送截单EDI /// /// 任务主键 /// 订单号 /// 是否使用货代代码 /// 货代代码 /// 货代称呼 /// 文件功能 (9原始,1 更新,5 退舱 ) /// 发送类型 E-截单 /// 返回结果 [HttpGet("/TaskManage/SendClosingEDI")] public async Task SendClosingEDI([FromQuery] string taskPKId, [FromQuery] string orderNo, [FromQuery] bool useForwarderCode, [FromQuery] string forwarderCode, [FromQuery] string forwarderName, [FromQuery] string fileRole, [FromQuery] string sendType) { if (sendType?.ToUpper() != "E") throw Oops.Oh($"sendType只接收E-截单"); var taskInfo = _taskBaseInfoRepository.AsQueryable().First(t => t.PK_ID == taskPKId); if (taskInfo == null) throw Oops.Oh($"任务信息获取失败"); if (string.IsNullOrWhiteSpace(taskInfo.BOOK_ORDER_NO)) throw Oops.Oh($"任务信息的订舱主键不存在"); if (taskInfo.TASK_TYPE != TaskBusiTypeEnum.SI_FEEDBACK.ToString()) throw Oops.Oh($"当前任务类型不是{TaskBusiTypeEnum.SI_FEEDBACK.GetDescription()}"); BookingOrder bookingOrder = null; if (!string.IsNullOrWhiteSpace(taskInfo.BOOK_ORDER_NO)) bookingOrder = _bookingOrderRepository.AsQueryable().First(t => t.Id == long.Parse(taskInfo.BOOK_ORDER_NO)); if (bookingOrder == null) throw Oops.Oh($"订舱信息获取失败,MBLNO={taskInfo.MBL_NO}"); var model = new BookingOrClosingEDIOrderDto { Id = bookingOrder.Id, orderNo = orderNo, useForwarderCode = useForwarderCode, forwarderCode = forwarderCode, forwarderName = forwarderName, fileRole = fileRole, send = true, sendType = sendType }; var bookingOrderService = _namedBookingOrderServiceProvider.GetService(nameof(BookingOrderService)); return await bookingOrderService.InnerBookingOrClosingEDI(model); } #endregion #region 计算LARA纸计算页数 /// /// 计算LARA纸计算页数 /// /// 请求LARA纸详情 /// 返回结果 [HttpPost("/TaskManage/CalcLaraPageNumbers")] public async Task> CalcLaraPageNumbers(CalcLaraPageNumbersDto model) { List list = new List(); /* LARA计算方法 1、判断是否为首次加载,model.moveType为空时表示首次加载,触发InitCalcLaraPageNumbers方法。 2、如果 model.moveType有值时,判断是调整行位置,根据指定的行位置重新计算编号。 */ try { if(string.IsNullOrWhiteSpace(model.moveType)) { list = InnerCalcLaraPageNumbers(model,true); } else { list = InnerCalcLaraPageNumbers(model); } } catch (Exception ex) { throw Oops.Bah("计算LARA纸计算页数异常,{0}", ex.Message); } return list; } #endregion #region 计算LARA纸 /// /// 计算LARA纸 /// /// 请求LARA纸详情 /// 是否初始化 true-初始化 /// private List InnerCalcLaraPageNumbers(CalcLaraPageNumbersDto model,bool isInit = false) { List list = new List(); //如果判断不是首次加载,需要将移动的行从列表移动到指定位置后,重新计算。 if(!isInit) { model.paperList = model.paperList.Select(t => { if (t.SortNo == model.origIndex.Value) { //up if(model.currIndex < model.origIndex) { t.SortNo = (decimal)model.currIndex.Value - 0.1m; } else { t.SortNo = (decimal)model.currIndex.Value + 0.1m; } } return t; }).OrderBy(t => t.SortNo) .Select((t, idx) => { t.SortNo = (decimal)idx + 1; return t; }).ToList(); } var mNumberTo = model.numberTo.TrimStart('0') == "" ? 0 : int.Parse(model.numberTo.TrimStart('0')); if (mNumberTo > 0) { int lastNumberTo = 0; int lastNumberFrom = 0; model.paperList.OrderBy(t => t.SortNo).ToList().ForEach(t => { LaraPaperRegistPostDto info = new LaraPaperRegistPostDto(); info.SortNo = t.SortNo; info.DraftNum = t.DraftNum; info.TaskId = t.TaskId; info.ORDNO = t.ORDNO; info.MBLNO = t.MBLNO; info.ISSUETYPE = t.ISSUETYPE; if (t.SortNo == 1) { lastNumberFrom = mNumberTo + 1; info.NumberFrom = (lastNumberFrom).ToString().PadLeft(9, '0'); var currNumberTo = (t.DraftNum * LARA_PARER_DRAFT_VAR) + mNumberTo; info.NumberTo = currNumberTo.ToString().PadLeft(9, '0'); info.PageSum = currNumberTo - lastNumberFrom + 1; lastNumberTo = currNumberTo; } else { lastNumberFrom = lastNumberTo + 1; info.NumberFrom = (lastNumberFrom).ToString().PadLeft(9, '0'); var currNumberTo = (t.DraftNum * LARA_PARER_DRAFT_VAR) + lastNumberTo; info.NumberTo = currNumberTo.ToString().PadLeft(9, '0'); info.PageSum = currNumberTo - lastNumberFrom + 1; lastNumberTo = currNumberTo; } list.Add(info); }); } return list; } #endregion /// /// 撤销任务 /// /// 任务详情 /// 返回回执 public async Task CancelTaskJob(TaskManageOrderMessageInfo info) { TaskManageOrderResultDto result = new TaskManageOrderResultDto(); /* 1、通过Head.GID检索任务表。 2、任务不存在提示检索失败。 3、任务存在判断当前状态已完成、已取消、已挂起不能撤销。 4、派车任务业务状态是SEND_DISPATCH不能撤销。 5、更新任务状态、更新派车任务状态。 6、返回结果 */ try { var taskInfo = _taskBaseInfoRepository.AsQueryable().OrderByDescending(a => a.CreatedTime) .First(t => t.OUT_BUSI_NO == $"{info.Head.SenderId}_{info.Head.GID}"); if (taskInfo == null) throw Oops.Oh($"任务不存在"); if(new string[] { TaskStatusEnum.Pending.ToString(),TaskStatusEnum.Cancel.ToString() } .Contains(taskInfo.STATUS)) throw Oops.Oh($"任务状态是已挂起/已取消的不能撤销"); var truckInfo = _taskTruckInfoRepository.AsQueryable().First(a => a.TASK_ID == taskInfo.PK_ID); if (truckInfo == null) throw Oops.Oh($"派车任务不存在"); //if(truckInfo.Status == BookingTruckStatus.SEND_DISPATCH.ToString()) // throw Oops.Oh($"派车任务状态是已派车不能撤销"); DateTime nowDate = DateTime.Now; truckInfo.Status = BookingTruckStatus.CANCELED.ToString(); UserTendDto userTendInfo = GetUserTendInfo(info.Main.TaskUserId); truckInfo.UpdatedUserId = userTendInfo.userId; truckInfo.UpdatedUserName = userTendInfo.userName; truckInfo.UpdatedTime = nowDate; //更新派车任务 await _taskTruckInfoRepository.AsUpdateable(truckInfo).UpdateColumns(it => new { it.UpdatedUserId, it.Status, it.UpdatedUserName, it.UpdatedTime }).ExecuteCommandAsync(); taskInfo.UpdatedUserId = userTendInfo.userId; taskInfo.UpdatedUserName = userTendInfo.userName; taskInfo.UpdatedTime = nowDate; taskInfo.STATUS = TaskStatusEnum.Cancel.ToString(); //更新任务 await _taskBaseInfoRepository.AsUpdateable(taskInfo).UpdateColumns(it => new { it.UpdatedUserId, it.STATUS, it.UpdatedUserName, it.UpdatedTime }).ExecuteCommandAsync(); result.succ = true; result.msg = "撤销成功"; } catch (Exception ex) { _logger.LogError("撤销任务异常,原因:{error}", ex.Message); throw Oops.Oh($"{ex.Message}"); } return result; } #region 创建BC任务 /// /// 创建BC任务 /// /// 文件 /// BC任务详情JSON /// 返回回执 [AllowAnonymous, HttpPost("/TaskManage/CreateBCTaskJob")] public async Task CreateBCTaskJob(IFormFile file, [FromForm] string jsonData) { TaskManageOrderResultDto result = new TaskManageOrderResultDto(); string batchNo = IDGen.NextID().ToString(); _logger.LogInformation("批次={no} 接收到创建任务报文 报文={msg}", batchNo, jsonData); try { TaskManageOrderMessageInfo info = JSON.Deserialize(jsonData); if(info == null) throw Oops.Bah("jsonData请求内容错误,无法反序列化报文"); result = await InitTaskJob(info, batchNo, file); } catch (Exception ex) { result.succ = false; result.msg = $"请求任务异常,{ex.Message}"; } return result; } #endregion #region 获取文件类型 /// /// 获取文件类型 /// /// 文件完成路径 /// 返回文件类型枚举 private PrintFileTypeEnum GetFileType(string fileName) { PrintFileTypeEnum fileType = PrintFileTypeEnum.PDF; switch (Path.GetExtension(fileName).ToLower()) { case ".pdf": fileType = PrintFileTypeEnum.PDF; break; case ".xlsx": fileType = PrintFileTypeEnum.XLSX; break; case ".docx": fileType = PrintFileTypeEnum.DOCX; break; case ".xls": fileType = PrintFileTypeEnum.XLS; break; case ".doc": fileType = PrintFileTypeEnum.DOC; break; } return fileType; } #endregion } #region 样本业务提取帮助类 /// /// 样本业务提取帮助类 /// public static class DraftPaperExtension { public static int GetPageNum(this string Name) { try { if (string.IsNullOrWhiteSpace(Name)) return 0; string s = Regex.Replace(Name.Substring(Name.LastIndexOf('-') + 1), "\\.[a-zA-Z]+", ""); return int.Parse(s); } catch(Exception ex) { throw Oops.Bah("文件名{0} 取页数异常,{1}", Name, ex.Message); } } } #endregion #region 整理文本数据 public static class CompareObjExtension { /// /// 整理文本数据 /// /// 文本 /// public static string AdjustString(this string str) { if (string.IsNullOrWhiteSpace(str)) return str; var rtn = str.Replace("\r\n", "\n").Trim(); if (rtn.EndsWith("\n")) { rtn = rtn.Substring(0, rtn.Length - 1); } return rtn; } /// /// 文本转换成日期 /// /// 文本 /// 字段名称 /// 返回日期 public static Nullable GetDateTime(this string str,string MemberName) { if (string.IsNullOrWhiteSpace(str)) return null; DateTime currDate = DateTime.MinValue; if (!DateTime.TryParse(str, out currDate)) throw Oops.Oh("字段{0}={1}转换日期失败,请检查日期格式", MemberName, str); return currDate; } } #endregion }