using Furion.DependencyInjection; using Furion.DistributedIDGenerator; using Furion.DynamicApiController; using Furion.FriendlyException; using Furion.JsonSerialization; using Furion.RemoteRequest; using Furion.RemoteRequest.Extensions; using Mapster; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.Extensions.Logging; using Myshipping.Application.Entity; using Myshipping.Application.Helper; using Myshipping.Core; using Myshipping.Core.Entity; using Myshipping.Core.Service; using MySqlX.XDevAPI.Common; using Newtonsoft.Json.Linq; using NPOI.SS.Formula.Functions; using SqlSugar; using StackExchange.Profiling.Internal; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net.Http; using System.Reflection.Metadata.Ecma335; using System.Runtime.InteropServices; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Xml.Linq; using static Aliyun.OSS.Model.CreateSelectObjectMetaInputFormatModel; namespace Myshipping.Application { /// /// 任务管理 /// [ApiDescriptionSettings("Application", Name = "TaskManage", Order = 10)] public class TaskManageService : ITaskManageService, IDynamicApiController { 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 IDjyWebsiteAccountConfigService _webAccountConfig; private readonly ISysCacheService _cache; private readonly ILogger _logger; const string CONST_WEB_ACCOUNT_TYPE = "CmaWeb"; const string CONST_BOOK_ORIGINAL_DOWN_URL_CODE = "bookOriginalDownUrl"; public TaskManageService(SqlSugarRepository taskBaseInfoRepository, SqlSugarRepository taskSIFeedBackInfoRepository, SqlSugarRepository taskSIFeedBackContaInfoRepository, SqlSugarRepository taskBillFeeDetailInfoRepository, SqlSugarRepository taskFileInfoRepository, SqlSugarRepository taskEmailInfoRepository, SqlSugarRepository taskVGMFeedBackInfoRepository, SqlSugarRepository sysUserRepository, SqlSugarRepository taskStatManageInfoRepository, SqlSugarRepository taskOriginalDownloadHisInfoRepository, SqlSugarRepository taskChargesHisInfoRepository, IDjyWebsiteAccountConfigService webAccountConfig, ISysCacheService cache, ILogger logger) { _taskBaseInfoRepository = taskBaseInfoRepository; _taskSIFeedBackInfoRepository = taskSIFeedBackInfoRepository; _taskSIFeedBackContaInfoRepository = taskSIFeedBackContaInfoRepository; _taskBillFeeDetailInfoRepository = taskBillFeeDetailInfoRepository; _taskFileInfoRepository = taskFileInfoRepository; _taskEmailInfoRepository = taskEmailInfoRepository; _taskVGMFeedBackInfoRepository = taskVGMFeedBackInfoRepository; _sysUserRepository = sysUserRepository; _taskStatManageInfoRepository = taskStatManageInfoRepository; _taskOriginalDownloadHisInfoRepository = taskOriginalDownloadHisInfoRepository; _taskChargesHisInfoRepository = taskChargesHisInfoRepository; _webAccountConfig = webAccountConfig; _cache = cache; _logger = logger; } /// /// 创建任务 /// /// 任务详情 /// 返回回执 [AllowAnonymous,HttpPost("/TaskManage/CreateTaskJob")] public async Task CreateTaskJob(TaskManageOrderMessageInfo info) { TaskManageOrderResultDto result = new TaskManageOrderResultDto(); try { /* 创建任务 1、判断当前任务的主键是否已入库,已入库不允许重复,返回错误提示。 2、 */ result = await InitTaskJob(info); } catch (Exception ex) { result.succ = false; result.msg = $"请求任务异常,{ex.Message}"; } return result; } /// /// 新增任务 /// /// 任务详情 /// 返回回执 private async Task InitTaskJob(TaskManageOrderMessageInfo info) { TaskManageOrderResultDto result = new TaskManageOrderResultDto(); try { var taskInfo = _taskBaseInfoRepository.AsQueryable().First(t => t.OUT_BUSI_NO == info.Head.GID); if (taskInfo != null) throw Oops.Oh($"任务已经存在不能重复提交"); taskInfo = new TaskBaseInfo { PK_ID = IDGen.NextID().ToString(), TASK_NO = info.Head.GID, 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.GID, TASK_TITLE = info.Main.TaskTitle, TASK_DESP = info.Main.TaskDesp, TASK_SOURCE = info.Main.TaskSource.ToString(), TASK_TYPE = info.Main.TaskType.ToString(), }; 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(); } //新增 await _taskBaseInfoRepository.InsertAsync(taskInfo); //附件 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.FILE_PATH = file.FilePath; fileInfo.FILE_NAME = file.FileName; fileInfo.FILE_TYPE = file.FileType; 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); }); } //邮件 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.MAIL_PATH = email.MailPath; await _taskEmailInfoRepository.InsertAsync(emailInfo); }); } //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; 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; await _taskSIFeedBackContaInfoRepository.InsertAsync(contaInfo); }); } } //费用明细 if(info.Main.TaskType == TaskBaseTypeEnum.INVOICE_BILL_MAIL || info.Main.TaskType == TaskBaseTypeEnum.PER_BILL) { 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; await _taskBillFeeDetailInfoRepository.InsertAsync(feeInfo); }); } } //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; await _taskVGMFeedBackInfoRepository.InsertAsync(vgmInfo); }); } result.succ = true; result.msg = "新增任务成功"; } catch (Exception ex) { throw Oops.Oh($"{ex.Message}"); } return result; } /// /// 获取查询参数 /// /// 参数类型 STATUS-任务状态;TASK_TYPE-任务类型;SOURCE-任务来源 /// 返回回执 /// 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)); } 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; } #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(); if (isReCalc) { //任务列表分组统计 var groupList = _taskBaseInfoRepository.AsQueryable() .Where(t => (t.CreatedUserId == UserManager.UserId && 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 == 1 && 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() }); 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); resultInfo.LevelNext.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()}" }); }); 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() }); 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); resultInfo.LevelNext.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()}" }); }); 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() }); 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); resultInfo.LevelNext.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()}" }); }); 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 /// /// 任务台账查询 /// /// 任务台账查询请求 /// 返回结果 [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()); } } 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); var entities = await _taskBaseInfoRepository.AsQueryable().Filter(null, true) .WhereIF(!string.IsNullOrWhiteSpace(QuerySearch.MBlNo), t => mblList.Any(p => p.Contains(t.MBL_NO, StringComparison.OrdinalIgnoreCase))) .WhereIF(!string.IsNullOrWhiteSpace(QuerySearch.TaskRecvName), t => t.CreatedUserName.Contains(QuerySearch.TaskRecvName.Trim(), StringComparison.OrdinalIgnoreCase)) .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, StringComparison.OrdinalIgnoreCase)) .WhereIF(!string.IsNullOrWhiteSpace(QuerySearch.TaskSource), t => t.TASK_SOURCE.Equals(QuerySearch.TaskSource, StringComparison.OrdinalIgnoreCase)) .OrderBy(entityOrderCol + (QuerySearch.descSort ? " asc " : " desc ")) .ToPagedListAsync(QuerySearch.PageNo, QuerySearch.PageSize); return new { PageNo = entities.PageIndex, PageSize = entities.PageSize, TotalPage = entities.TotalPages, TotalRows = entities.TotalCount, Rows = entities.Items.Select(t => t.Adapt()).ToList() }; } #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 /// /// 单票正本下载 /// /// 批次号 /// 任务详情 /// 网站账户配置 /// 返回回执 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; } #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(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); taskList.ForEach(async tsk => { await InnerManualTask(batchNo, tsk, TaskOperTypeEnum.COMPLETE_TASK); }); } catch (Exception ex) { throw Oops.Bah($"完成任务异常,{0}", ex.Message); } return result; } #endregion private async Task InnerManualTask(string batchNo, TaskBaseInfo taskBaseInfo, TaskOperTypeEnum taskOperTypeEnum) { TaskManageOrderResultDto result = new TaskManageOrderResultDto(); try { var model = _taskBaseInfoRepository.AsQueryable().First(t => t.PK_ID == taskBaseInfo.PK_ID); if (taskOperTypeEnum == TaskOperTypeEnum.COMPLETE_TASK) { if (taskBaseInfo.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; _taskBaseInfoRepository.AsUpdateable(model).UpdateColumns(it => new { it.COMPLETE_DATE, it.COMPLETE_DEAL, it.COMPLETE_DEAL_NAME, it.IS_COMPLETE }).ExecuteCommand(); } else if (taskOperTypeEnum == TaskOperTypeEnum.CANCEL_TASK) { if (taskBaseInfo.TASK_TYPE == TaskBusiTypeEnum.CHANGE_SHIP.ToString()) { model.STATUS = TaskStatusEnum.Cancel.ToString(); } else if(taskBaseInfo.TASK_TYPE == TaskBusiTypeEnum.ABORT_CHANGE_SHIP.ToString()) { /* 1.如果原换船通知已经接受,需要把原船名航次恢复并通知客户取消换船。 2.如果原换船通知未作处理,点击接受或者结束任务时提示:本票货存在未处理换船通知,请先结束原换船任务然后结束本任务。 3.如果原换船任务为结束任务,在取消换船任务点接受时,提示未做换船,请点击结束任务。 */ //查询同票主单的是否有未处理的换船通知 //_taskBaseInfoRepository.AsQueryable().Where(t=>t.MBL_NO.Equals(taskBaseInfo.MBL_NO) && ) } } } catch (Exception ex) { result.succ = false; result.msg = $"异常,{ex.Message}"; } return result; } #region 取消任务(可批量) /// /// 取消任务(可批量) /// /// 任务主键数组 /// 返回结果 [HttpPost("/TaskManage/CancelTask")] public async Task CancelTask(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); taskList.ForEach(async tsk => { await InnerManualTask(batchNo, tsk, TaskOperTypeEnum.CANCEL_TASK); }); } 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)); try { var taskList = _taskBaseInfoRepository.AsQueryable().Where(t => PKIds.Contains(t.PK_ID)).ToList(); _logger.LogInformation("批次={no} 获取任务完成,Num={Num}", batchNo, taskList.Count); taskList.ForEach(async tsk => { await InnerManualTask(batchNo, tsk, TaskOperTypeEnum.PENDING_TASK); }); } catch (Exception ex) { throw Oops.Bah($"完成任务异常,{0}", ex.Message); } return result; } #endregion /// /// 提单纸页数计算 /// /// 任务主键数组 /// 返回结果 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 taskList = _taskBaseInfoRepository.AsQueryable() .LeftJoin(_taskFileInfoRepository.AsQueryable(), (tsk, file) => tsk.PK_ID == file.TASK_PKID) .Where((tsk, file) => PKIds.Contains(tsk.PK_ID) && tsk.TASK_TYPE == TaskBusiTypeEnum.DRAFT.ToString() && file != null) .OrderByDescending(tsk => tsk.CreatedTime) .Select((tsk, file) => new { tsk = tsk, file = file }).ToList(); list = mblnoList.Select((mbl,idx) => { var calcInfo = new LaraPaperCalcInfo(); calcInfo.Indx = idx + 1; return calcInfo; }).ToList(); } } catch (Exception ex) { throw Oops.Bah($"完成任务异常,{0}", ex.Message); } return list; } } }