using Furion; using Furion.DependencyInjection; using Furion.DistributedIDGenerator; using Furion.DynamicApiController; using Furion.FriendlyException; using Furion.JsonSerialization; using Furion.RemoteRequest.Extensions; using Mapster; using MathNet.Numerics.Distributions; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Myshipping.Core; using Myshipping.Core.Service; using System; using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Reflection.Emit; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using Yitter.IdGenerator; namespace Myshipping.Application { /// /// 内嵌运踪港后数据查询 /// [AllowAnonymous, ApiDescriptionSettings("Application", Name = "EmbedTraceProduct", Order = 20)] public class EmbedTraceProductService : IEmbedTraceProductService, IDynamicApiController, ITransient { private readonly ILogger _logger; private const string CONST_TRACE_API_URL = "embed_trace_flow_url"; private readonly ISysCacheService _cache; private readonly IDjyWebsiteAccountConfigService _webAccountConfig; /// /// /// /// public EmbedTraceProductService(ILogger logger, ISysCacheService cache, IDjyWebsiteAccountConfigService webAccountConfig) { _logger = logger; _cache = cache; _webAccountConfig = webAccountConfig; } #region 获取单票运踪流程详情 /// /// 获取单票运踪流程详情 /// /// 查询单票运踪流程详情 /// 返回回执 [AllowAnonymous, HttpPost("/EmbedTraceProduct/GetTraceFlowInfo"), ApiUser(ApiCode = "EmbedServiceTraceShow")] public async Task GetTraceFlowInfo(EmbedQueryTraceFlowDto model) { /* 1、调取运踪接口。 embed_trace_flow_url 2、根据返回结果组织暂时的JSON结果。 3、返回结果 */ EmbedTraceFlowResultDto result = null; string batchNo = IDGen.NextID().ToString(); string sendUrl = _cache.GetAllDictData().GetAwaiter().GetResult() .FirstOrDefault(x => x.TypeCode == "url_set" && x.Code == CONST_TRACE_API_URL)?.Value; if (string.IsNullOrWhiteSpace(sendUrl)) throw Oops.Oh("未配置发送订舱请求接口地址,请联系管理员"); var webAccountConfig = _webAccountConfig .GetAccountConfigByTenantId("seae_billtraceurl", UserManager.UserId, UserManager.TENANT_ID).GetAwaiter().GetResult(); if (webAccountConfig == null) throw Oops.Oh("未配置账户,请先配置公司或者个人账户 类型-运踪新增调用"); QueryTraceAfterPortDto queryDto = new QueryTraceAfterPortDto { user_key = webAccountConfig.Account, user_secret = webAccountConfig.Password, carriercd = model.carrier, referenceno = model.billNo, ctnrno = model.ctnNo }; var queryRlt = await QueryTraceAsync(queryDto, sendUrl); var statusDict = _cache.GetAllDictData().GetAwaiter().GetResult() .Where(t => t.TypeCode.Equals("after_port_trace_ctn_status", StringComparison.OrdinalIgnoreCase)).ToList(); //按顺序取状态配置字典 Dictionary> statusEnumDict = statusDict.Select(a => new { Key = a.Code, Val = new Tuple(a.Value, a.Remark, a.Sort), Sort = a.Sort }) .OrderBy(a => a.Sort).ToDictionary(a => a.Key, b => b.Val); string[] skipStatus = new string[] { "GIOI", "LOFV", "FVD", "FVA", "DFFV", "LOR", "DFR", "RA", "DIFR", "LOT", "DIFT", "ADI", "DIDI", "CGRL", "RFP", "ETD", "ETA", "LDI", "CDPOD", "BPOD" }; string[] transferStatus = new string[] { "AIP", "BIP", "ETDIP", "DIIP", "GOIP", "GIIP", "LIP", "EDIP", "DEIP", "EAIP" }; if (queryRlt.code == 200) { var queryResult = queryRlt.data.FirstOrDefault(); result = queryResult.Adapt(); if (result != null && result.resultData != null) { //这里需要翻译一下箱型 var ctnCodeMappingList = _cache.GetAllMappingCtn().GetAwaiter().GetResult().ToList(); var ctnCodeList = _cache.GetAllCodeCtn().GetAwaiter().GetResult().ToList(); Dictionary referToCtnDict = new Dictionary(); bool isTransfer = false; if (result.resultData.containerInfoList != null && result.resultData.containerInfoList.Count > 0) { result.resultData.containerInfoList.ForEach(s => { string ctnSize = s.size; if (!string.IsNullOrWhiteSpace(s.size)) { ctnSize = $"{Regex.Match(s.size, "[0-9]{2}")}{Regex.Match(s.size, "[a-zA-Z]{1,3}([0-9]{1})?")}"; } var ctnCode = ctnCodeList.FirstOrDefault(t => !string.IsNullOrWhiteSpace(t.EdiCode) && t.EdiCode.Equals(ctnSize)); if (ctnCode != null) { s.sizeName = ctnCode.Name?.Trim(); } else { var ctnMapping = ctnCodeMappingList.FirstOrDefault(t => !string.IsNullOrWhiteSpace(t.MapCode) && t.MapCode.Equals(ctnSize)); if (ctnMapping != null) { s.sizeName = ctnMapping.MapName?.Trim(); } } if (s.containerStatusInfoList != null && s.containerStatusInfoList.Count > 0) { referToCtnDict.Add(s.containerNo, s.containerStatusInfoList.Count); s.containerStatusInfoList = s.containerStatusInfoList.Select((a, idx) => { a.sortNo = idx + 1; if (statusEnumDict.Any(p => p.Key.Equals(a.statusCd, StringComparison.OrdinalIgnoreCase))) { a.statusCnName = statusEnumDict[a.statusCd].Item1; } else { a.statusCnName = a.statusCd; } return a; }).ToList(); } }); } //legType = "T" 标识当票有中转 if (result.resultData.routingInfoList.Any(t => t.legType.Equals("T", StringComparison.OrdinalIgnoreCase))) { isTransfer = true; } result.embedTraceFlowStatusList = new List(); var ctnNo = referToCtnDict.OrderByDescending(a => a.Value).FirstOrDefault().Key; var longContainerStatus = result.resultData.containerInfoList.FirstOrDefault(a => a.containerNo.Equals(ctnNo, StringComparison.OrdinalIgnoreCase)); if(longContainerStatus != null) { var longContainerStatusList = longContainerStatus.containerStatusInfoList; } var takeList = result.resultData.containerInfoList.SelectMany(p => p.containerStatusInfoList) .GroupBy(a => a.statusCd).Select(a => { var currArg = a.ToList(); EmbedTraceFlowStatusInfo currStatus = new EmbedTraceFlowStatusInfo { voy = a.FirstOrDefault().voy, statusDescription = a.FirstOrDefault().statusDescription, statusTime = a.FirstOrDefault().statusTime, vslName = a.FirstOrDefault().vslName, statusCd = a.FirstOrDefault().statusCd, statusPlace = a.FirstOrDefault().statusPlace, statusTerminal = a.FirstOrDefault().statusTerminal, statusCnName = a.FirstOrDefault().statusCnName, sortNo = a.FirstOrDefault().sortNo, }; if (!currArg.Any(a => !a.isEst.Equals("N", StringComparison.OrdinalIgnoreCase))) { currStatus.isComplete = true; currStatus.hasStatusCtnNum = currArg.Count; currStatus.noStatusCtnNum = 0; } else { currStatus.isComplete = false; currStatus.hasStatusCtnNum = currArg.Count(a => a.isEst.Equals("N", StringComparison.OrdinalIgnoreCase)); currStatus.noStatusCtnNum = currArg.Count(a => !a.isEst.Equals("N", StringComparison.OrdinalIgnoreCase)); } currStatus.statusCtnStatic = $"{currStatus.hasStatusCtnNum}/{(currStatus.hasStatusCtnNum + currStatus.noStatusCtnNum)}"; return currStatus; }).ToList(); var APODtotal = takeList.Where(p => p.statusCd.Equals("APOD", StringComparison.OrdinalIgnoreCase)).ToList(); bool isMoreAPOD = false; if (APODtotal.Count > 1 && APODtotal.Any(p => p.isComplete)) { isMoreAPOD = true; takeList = takeList.Select(a => { if (a.statusCd.Equals("APOD", StringComparison.OrdinalIgnoreCase) && !a.isComplete) return null; return a; }).Where(a => a != null).ToList(); } foreach (KeyValuePair> kvp in statusEnumDict) { if (!skipStatus.Contains(kvp.Key)) { //不是中转的需要把状态节点去掉 if (isTransfer || (!isTransfer && !transferStatus.Contains(kvp.Key))) { var currStatus = takeList.FirstOrDefault(p => p.statusCd.Equals(kvp.Key, StringComparison.OrdinalIgnoreCase)); if (currStatus == null) { currStatus = new EmbedTraceFlowStatusInfo { statusCd = kvp.Key, statusCnName = !string.IsNullOrWhiteSpace(kvp.Value.Item2) ? kvp.Value.Item2 : kvp.Value.Item1, sortNo = kvp.Value.Item3, statusCtnStatic = $"0/{referToCtnDict.Count}", }; } else { if (!string.IsNullOrWhiteSpace(kvp.Value.Item2)) currStatus.statusCnName = kvp.Value.Item2; } if (currStatus.statusCd.Equals("DPOL", StringComparison.OrdinalIgnoreCase)) currStatus.isSplitStart = true; if (currStatus.statusCd.Equals("APOD", StringComparison.OrdinalIgnoreCase)) currStatus.isSplitEnd = true; if (longContainerStatus != null && !string.IsNullOrWhiteSpace(longContainerStatus.currentNodeCd) && longContainerStatus.currentNodeCd.Equals(kvp.Key, StringComparison.OrdinalIgnoreCase)) { currStatus.isCurrentStatus = true; } result.embedTraceFlowStatusList.Add(currStatus); } } } result.resultData.containerInfoList.ForEach(b => { if (statusEnumDict.Any(k => !string.IsNullOrWhiteSpace(b.currentNodeCd) && k.Key.Equals(b.currentNodeCd, StringComparison.OrdinalIgnoreCase))) { b.currentNodeCnName = !string.IsNullOrWhiteSpace(statusEnumDict[b.currentNodeCd].Item2) ? statusEnumDict[b.currentNodeCd].Item2 : statusEnumDict[b.currentNodeCd].Item1; } b.containerStatusInfoList = b.containerStatusInfoList.Select(c => { if (!string.IsNullOrWhiteSpace(b.currentNodeCd) && b.currentNodeCd.Equals(c.statusCd, StringComparison.OrdinalIgnoreCase)) { c.isCurrentStatus = true; } if (!string.IsNullOrWhiteSpace(c.statusPlace)) c.statusPlace = c.statusPlace.ToUpper(); if (!string.IsNullOrWhiteSpace(c.statusCd) && c.statusCd.Equals("ETA", StringComparison.OrdinalIgnoreCase)) { return null; } if (!string.IsNullOrWhiteSpace(c.statusCd) && c.statusCd.Equals("APOD", StringComparison.OrdinalIgnoreCase) && !c.isEst.Equals("N", StringComparison.OrdinalIgnoreCase) && isMoreAPOD) { return null; } return c; }).Where(a => a != null).ToList(); }); _logger.LogInformation($"{JSON.Serialize(queryDto)} 查询成功"); } else { string msg = result != null ? result.resultMessage : "查询无结果"; _logger.LogInformation($"{JSON.Serialize(queryDto)} 查询失败,{msg}"); throw Oops.Oh(msg); } } else { _logger.LogInformation($"{JSON.Serialize(queryDto)} 查询失败,{queryRlt.msg}"); throw Oops.Oh((result != null && result.resultMessage != null && result.resultMessage.Contains("官网查询无数据")) ? "无查询结果" : queryRlt.msg); } return result; } #endregion #region 查询运踪 /// /// 查询运踪 /// /// 查询参数 /// 请求URL /// public async Task QueryTraceAsync(QueryTraceAfterPortDto query,string url) { QueryTraceAfterPortResultDto model = null; try { var res = await url.OnClientCreating(client => { // client 为 HttpClient 对象 client.Timeout = TimeSpan.FromMinutes(15); // 设置超时时间 15分钟 }).SetHttpMethod(HttpMethod.Post) .SetBody(JSON.Serialize(query), "application/json") .SetContentEncoding(Encoding.UTF8) .PostAsync(); _logger.LogInformation("单号={no} 对应请求报文完成 post={post} res={res}", query.referenceno, JSON.Serialize(query), JSON.Serialize(res)); if (res.StatusCode == System.Net.HttpStatusCode.OK) { var userResult = await res.Content.ReadAsStringAsync(); model = JSON.Deserialize(userResult); } } catch (Exception ex) { _logger.LogInformation($"请求运踪查询异常,原因:{ex.Message}"); throw Oops.Oh($"请求运踪查询异常,原因:{ex.Message}"); } return model; } #endregion } }