using Furion; using Furion.DependencyInjection; using Furion.DistributedIDGenerator; using Furion.DynamicApiController; using Furion.FriendlyException; using Furion.JsonSerialization; using Furion.RemoteRequest.Extensions; using Mapster; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Myshipping.Application.Entity; using Myshipping.Core; using Myshipping.Core.Entity; using Myshipping.Core.Service; using StackExchange.Profiling.Internal; using System; using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Text; using System.Threading.Tasks; namespace Myshipping.Application { /// /// 请求下货纸比对 /// [ApiDescriptionSettings("Application", Name = "TaskShippingOrderCompare", Order = 9)] public class TaskShippingOrderCompareService : ITaskShippingOrderCompareService, IDynamicApiController, ITransient { private readonly ISysCacheService _cache; private readonly ILogger _logger; private readonly SqlSugarRepository _bookingOrderRepository; private readonly SqlSugarRepository _bookingOrderContaRepository; //private readonly SqlSugarRepository _userRepository; public TaskShippingOrderCompareService(ISysCacheService cache, ILogger logger, SqlSugarRepository bookingOrderRepository, SqlSugarRepository bookingOrderContaRepository) { _cache = cache; _logger = logger; _bookingOrderRepository = bookingOrderRepository; _bookingOrderContaRepository = bookingOrderContaRepository; } /// /// 执行下货纸比对 /// /// 订舱主键 /// 返回回执 [HttpGet("/TaskShippingOrderCompare/ExcuteShippingOrderCompare")] public async Task ExcuteShippingOrderCompareAsync(string bookingId) { string batchNo = IDGen.NextID().ToString(); _logger.LogInformation("批次={no}获取订舱数据请求规则 {id}", batchNo, bookingId); /* 处理逻辑 1、台账触发单票下货纸比对 2、调取订舱的详情。 3、对应请求报文。 4、请求比对接口。 5、返回回执。 */ return await InnerExcuteShippingOrderCompareAsync(bookingId); } private async Task InnerExcuteShippingOrderCompareAsync(string bookingId) { string batchNo = IDGen.NextID().ToString(); _logger.LogInformation("批次={no}获取订舱数据请求规则 {id}", batchNo, bookingId); /* 处理逻辑 1、台账触发单票下货纸比对 2、调取订舱的详情。 3、对应请求报文。 4、请求比对接口。 5、返回回执。 */ TaskManageExcuteResultDto result = new TaskManageExcuteResultDto(); try { DateTime nowDate = DateTime.Now; var model = _bookingOrderRepository.AsQueryable().InSingle(long.Parse(bookingId)); if (model == null) throw Oops.Oh($"订舱主键{bookingId}无法获取业务信息"); _logger.LogInformation("批次={no}获取订舱数据完成", batchNo); //附主信息 var mainInfo = model.Adapt(); mainInfo.BusiPKId = model.Id.ToString(); mainInfo.UserId = UserManager.UserId.ToString(); mainInfo.UserName = UserManager.Name; mainInfo.UserEmail = UserManager.Email; var contaList = await _bookingOrderContaRepository.AsQueryable().Where(x => x.BILLID == model.Id).ToListAsync(); _logger.LogInformation("批次={no} 提取箱完成 数量={total}", batchNo, contaList.Count); if (contaList.Count > 0) { mainInfo.ContaList = contaList.Adapt>(); } var msgModel = GetMessageInfo(batchNo, mainInfo); _logger.LogInformation("批次={no} 对应请求报文完成 msg={msg}", batchNo, JSON.Serialize(msgModel)); DateTime bDate = DateTime.Now; var compareResult = await ExcuteCompare(msgModel); DateTime eDate = DateTime.Now; TimeSpan ts = eDate.Subtract(bDate); var timeDiff = ts.TotalMilliseconds; _logger.LogInformation("批次={no} 请求完成,耗时:{timeDiff}ms. 结果{msg}", batchNo, timeDiff, compareResult.succ ? "成功" : "失败"); if (compareResult == null) throw Oops.Oh($"订舱主键{bookingId}请求下货纸比对失败,返回为空"); var orderInfo = _bookingOrderRepository.AsQueryable().First(x => x.Id == long.Parse(bookingId)); if (orderInfo != null) { orderInfo.LstShipOrderCompareDate = bDate; if (compareResult.succ) { orderInfo.LstShipOrderCompareMode = "MANUAL"; if (compareResult.extra.IsExistsDiff) { orderInfo.LstShipOrderCompareRlt = "DIFF"; orderInfo.LstShipOrderCompareRltName = "有差异"; } else { orderInfo.LstShipOrderCompareRlt = "NO_DIFF"; orderInfo.LstShipOrderCompareRltName = "正常"; } } else { orderInfo.LstShipOrderCompareRlt = "NO_YARD"; orderInfo.LstShipOrderCompareRltName = "无动态"; } if (compareResult.extra != null) orderInfo.LstShipOrderCompareId = compareResult.extra.TaskCompareId; //更新 await _bookingOrderRepository.AsUpdateable(orderInfo).UpdateColumns(it => new { it.LstShipOrderCompareId, it.LstShipOrderCompareDate, it.LstShipOrderCompareRlt, it.LstShipOrderCompareRltName, it.LstShipOrderCompareMode, }).ExecuteCommandAsync(); } result.succ = compareResult.succ; result.msg = compareResult.msg; result.extra = compareResult.extra; result.extra2 = compareResult.extra2; result.total = compareResult.total; _logger.LogInformation("批次={no} 请求下货纸比对返回结果{msg}", batchNo, JSON.Serialize(compareResult)); _logger.LogInformation("批次={no} 返回结果{msg}", batchNo, JSON.Serialize(result)); } catch (Exception ex) { result.succ = false; result.msg = $"请求下货纸比对异常,{ex.Message}"; } return result; } /// /// 批量执行下货纸比对 /// /// 订舱主键组 /// 返回回执 [HttpPost("/TaskShippingOrderCompare/ExcuteShippingOrderCompareBatch")] public async Task ExcuteShippingOrderCompareBatchAsync([FromBody] string[] bookingIds) { TaskManageExcuteResultDto result = new TaskManageExcuteResultDto(); try { var ids = bookingIds.Select(a => long.Parse(a)).Distinct().ToArray(); var list = _bookingOrderRepository.AsQueryable().Where(t => ids.Contains(t.Id)).ToList(); if (list.Count != ids.Length) { var noRecord = string.Join(",", ids.GroupJoin(list, l => l, r => r.Id, (l, r) => { var currList = r.ToList(); if (r.Count() > 0) return 0; return l; }).Where(t => t > 0).ToArray()); throw Oops.Oh($"以下主键信息 {noRecord} 检索失败或者已作废过"); } //这里单票下货纸比对时,等待结果返回 if(ids.Length == 1) { result = await InnerExcuteShippingOrderCompareAsync(list.FirstOrDefault().Id.ToString()); } else { List> listOfTasks = new List>(); list.ForEach(entity => { listOfTasks.Add(InnerExcuteShippingOrderCompareAsync(entity.Id.ToString())); }); await Task.WhenAll(listOfTasks); result.succ = true; result.msg = "比对完成"; string rltMsg = string.Empty; result.rows = listOfTasks.Select(a => { var origId = a.Result.extra.OrigPKId; var order = list.FirstOrDefault(x => x.Id == long.Parse(origId)); if (a.Result.succ) { if (a.Result.total > 0) { return new { MblNo = order.MBLNO, Msg = "比对异常", IsDiff = true, rlt = a.Result.succ }; } return new { MblNo = order.MBLNO, Msg = "比对一致", IsDiff = false, rlt = a.Result.succ }; } return new { MblNo = order?.MBLNO, Msg = "比对一致", IsDiff = false, rlt = a.Result.succ }; }).ToList(); } } catch (Exception ex) { result.succ = false; result.msg = $"请求下货纸比对异常,{ex.Message}"; } return result; } /// /// 下货纸自动比对回写状态 /// /// 比对回写详情 /// 返回回执 public async Task AutoTaskShippingOrderCompareCallBackAsync([FromBody] ShippingOrderCompareCallBackInfo model) { TaskManageExcuteResultDto result = new TaskManageExcuteResultDto(); try { if(string.IsNullOrWhiteSpace(model.reqBusiId)) throw Oops.Oh($"订舱主键{model.reqBusiId}不能为空"); if (string.IsNullOrWhiteSpace(model.compareId)) throw Oops.Oh($"比对ID{model.compareId}不能为空"); if (string.IsNullOrWhiteSpace(model.compareMode)) throw Oops.Oh($"下货纸比对方式不能为空{model.compareMode}不能为空"); if (string.IsNullOrWhiteSpace(model.compareRltCode)) throw Oops.Oh($"比对结果代码{model.compareRltCode}不能为空"); if (string.IsNullOrWhiteSpace(model.compareRltName)) throw Oops.Oh($"比对结果名称{model.compareId}不能为空"); var bookingOrder = await _bookingOrderRepository.AsQueryable() .FirstAsync(a => a.Id == long.Parse(model.reqBusiId)); } catch (Exception ex) { result.succ = false; result.msg = $"下货纸自动比对回写状态失败,{ex.Message}"; } return result; } /// /// 生成请求规则报文 /// /// 批次号 /// 订舱主业务信息 /// 返回请求报文类 [NonAction] private TaskMessageInfoDto GetMessageInfo(string batchNo, TaskMessageMain mainInfo) { DateTime nowDate = DateTime.Now; TaskMessageInfoDto msgModel = new TaskMessageInfoDto(); msgModel.Head = new TaskMessageHead { GID = batchNo, MessageType = "SHIP_ORDER_COMPARE", SenderId = App.Configuration["RulesEngineSender"], SenderName = App.Configuration["RulesEngineSenderName"], ReceiverId = "RulesEngine", ReceiverName = "大简云规则引擎", Version = "1.0", RequestDate = nowDate.ToString("yyyy-MM-dd HH:mm:ss"), RequestAction = "Compare", }; msgModel.Main = mainInfo; return msgModel; } #region 请求下货纸比对 /// /// 请求下货纸比对 /// /// /// [NonAction] private async Task ExcuteCompare(TaskMessageInfoDto info) { TaskManageExcuteResultDto model = null; /* 1、读取配置文件中的规则引擎URL 2、填充请求的类,并生成JSON报文 3、POST请求接口,并记录回执。 4、返回信息。 */ var url = App.Configuration["ShippingOrderCompareUrl"]; try { var res = await url.OnClientCreating(client => { // client 为 HttpClient 对象 client.Timeout = TimeSpan.FromMinutes(15); // 设置超时时间 15分钟 }).SetHttpMethod(HttpMethod.Post) .SetBody(JSON.Serialize(info), "application/json") .SetContentEncoding(Encoding.UTF8) .PostAsync(); _logger.LogInformation("批次={no} 对应请求报文完成 res={res}", info.Head.GID, JSON.Serialize(res)); if (res.StatusCode == System.Net.HttpStatusCode.OK) { var userResult = await res.Content.ReadAsStringAsync(); model = JSON.Deserialize(userResult); } } catch (Exception ex) { //写日志 if (ex is HttpRequestException) throw Oops.Oh(10000002); } return model; } #endregion } }