using DotNetCore.CAP; using SJZY.Track.Application.Contract.Dtos.ProvideServices; using SJZY.Track.Application.Contract.Events; using SJZY.Track.Application.Contract.Services.ProvideServices; using SJZY.Track.Domain.Aggregates.OrderAggregate; using SJZY.Track.Domain.Aggregates.TrackContentAggregate; using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate; using SJZY.Track.Domain.Enums; using SJZY.UserCenter.HttpApi.Services; using Volo.Abp.Http.Client.DynamicProxying; namespace SJZY.Track.Application.Services.ProvideServices; /// /// 轨迹服务 /// [ApiExplorerSettings(GroupName = "提供接口")] [Route("/ProviderService")] public partial class TrackService : ApplicationService, ITrackService { private readonly ICapPublisher _capPublisher; private readonly IOrderRepository _orderRepository; private readonly IHttpClientProxy _requestCurrentUserService; private readonly ITrackContentRepository _trackContentRepository; public TrackService(IOrderRepository orderRepository, ICapPublisher capPublisher, ITrackDetailsEsRepository trackDetailsEsRepository, ITrackContentRepository trackContentRepository, IHttpClientProxy requestCurrentUserService) { _orderRepository = orderRepository; _capPublisher = capPublisher; _trackContentRepository = trackContentRepository; _requestCurrentUserService = requestCurrentUserService; _trackDetailsEsRepository = trackDetailsEsRepository; } /// /// 新增、更新轨迹(存在就更新) /// /// /// /// [HttpPost("Track/Upsert")] public async Task UpsertTrackAsync(UpsertTrackInput input) { var order = await _orderRepository.GetFirstAsync(x => x.SubSystemId == input.SubSystemId && x.OrderType == input.OrderType && x.OrderNo == input.OrderNo, x => new { x.Id, x.CustomId }); if (order == default) { throw new BusinessException(message: $"订单:{input.OrderNo}不存在"); } if (!GlobalConst.SupportTrackSources.Contains(input.Source)) { throw new BusinessException(message: "轨迹来源是必须的"); } //要求时间在当前时间的前后100年之间内 bool ValidateTrackTime(DateTime? d) => (d != null && d < DateTime.Now.AddYears(-100) || d > DateTime.Now.AddYears(100)); if (ValidateTrackTime(input.TrackTime) || ValidateTrackTime(input.NewTrackTime) || ValidateTrackTime(input.EstimatedDeliveryDate)) { throw new BusinessException(message: "轨迹时间不合法"); } if ((input.EstimatedDeliveryDate.HasValue == false && input.DestinationTimeZone.HasValue) || (input.EstimatedDeliveryDate.HasValue && input.DestinationTimeZone.HasValue == false)) { throw new BusinessException(message: "【预计签收时间】和【签收地时区】必须同时输入"); } //当修改时,如果为来源为外部提供商则不允许修改 if (!input.IsAdd && input.Source == (int) TrackSourceEnum.ExternalServiceProvide) { throw new BusinessException(message: "来源为外部服务商轨迹不允许修改"); } var trackContent = await _trackContentRepository.GetByCodeAsync(input.SubSystemId, input.TrackCode); if (trackContent == default) { throw new BusinessException(message: $"轨迹代码:{input.TrackCode}轨迹内容不存在"); } //指示是否为手动操作 var manualOperation = input.Source == (int) TrackSourceEnum.Artificial; //不允许手动创建 if (manualOperation && input.IsAdd && !trackContent.IsAllowManuallyCreate) { throw new BusinessException(message: $"轨迹代码:{input.TrackCode}不允许手动创建"); } //不允许手动更新 if (manualOperation && !input.IsAdd && !trackContent.IsAllowManuallyUpdate) { throw new BusinessException(message: $"轨迹代码:{input.TrackCode}不允许手动更新"); } var tracks = (await _trackDetailsEsRepository.GetListAsync(new[] { order.Id }, input.TrackCode, true)) .Where(x => x.TrackTime == input.TrackTime) .ToList(); //当为更新操作时发现更新的数目为0进行重试操作 if (!input.IsAdd && tracks.Count == 0) { var curRetryCount = 0; var success = false; while (!success && curRetryCount < GlobalConst.MaxUpdateTrackRetryCount) { try { tracks = (await _trackDetailsEsRepository.GetListAsync(new[] { order.Id }, input.TrackCode, true)) .Where(x => x.TrackTime == input.TrackTime) .ToList(); if (tracks.Count > 0) success = true; await Task.Delay(300); } finally { curRetryCount++; } } if (tracks.Count == 0) { throw new BusinessException(message: $"订单:{input.OrderNo},轨迹代码:{input.TrackCode}没有要更新的记录"); } } //更新轨迹,同一时间存在多条轨迹记录,理由:不清晰到底要修改哪一条或是全部修改 if (!input.IsAdd && tracks.Count > 1) { throw new BusinessException(message: $"订单:{input.OrderNo},轨迹代码:{input.TrackCode}存在多条记录,不允许修改"); } var userInfo = await _requestCurrentUserService.Service.GetCurrentUserBasicInfoAsync(input.OptionUserId); if (userInfo.Code != GlobalConst.SuccessCode || userInfo.Data is null) { //TODO: log || ex throw new BusinessException(message: $"调用用户中心,获取用户信息失败:{userInfo.Msg}"); } var name = userInfo.Data.UserName; // 新增/更新轨迹 var @event = ObjectMapper.Map(input); @event.SubSystemId = input.SubSystemId; @event.CustomId = order.CustomId; @event.OrderIdentifiers = new[] { new OrderIdentifier { OrderId = order.Id, OrderNo = input.OrderNo, OrderType = input.OrderType, } }; @event.OperationMan = name; await _capPublisher.PublishAsync(GlobalConst.TrackUpsertSubscribe, @event); return new UnifyResultDto(true, true); } /// /// 删除轨迹 /// /// /// /// [HttpPost("Track/Delete")] public async Task DeleteTrackAsync(DeleteTrackInput input) { var orderId = await _orderRepository.GetFirstAsync( x => x.SubSystemId == input.SubSystemId && x.OrderType == input.OrderType && x.OrderNo == input.OrderNo, x => x.Id); if (orderId == default) { throw new BusinessException(message: $"订单:{input.OrderNo}不存在"); } var userInfo = await _requestCurrentUserService.Service.GetCurrentUserBasicInfoAsync(); if (userInfo.Code != GlobalConst.SuccessCode || userInfo.Data is null) { //TODO: log || ex throw new BusinessException(message: $"调用用户中心,获取用户信息失败:{userInfo.Msg}"); } var name = userInfo.Data.UserName; //删除轨迹约束,只要其中有一条来源是外部的就立即返回错误 var tracks = await _trackDetailsEsRepository .GetListAsync(new[] { orderId }, input.TrackIdentifiers.Select(x => x.TrackCode).ToList(), TrackSourceEnum.ExternalServiceProvide); //当要删除的轨迹标识出现交叉则不允许删除 var intersect = tracks.Select(x => $"{x.TrackCode}{x.TrackTime}") .Intersect(input.TrackIdentifiers.Select(y => $"{y.TrackCode}{y.TrackTime}")).ToList(); if (intersect.Count > 0) { throw new BusinessException(message: "存在来源于外部服务商的轨迹,不允许删除"); } // 删除轨迹 var @event = new TrackDeleteEvent { OrderIds = new[] { orderId }, TrackIdentifiers = input.TrackIdentifiers, SubSystemId = input.SubSystemId, OperationMan = name }; await _capPublisher.PublishAsync(GlobalConst.TrackDeleteSubscribe, @event); return new UnifyResultDto(true, true); } /// /// 根据esid删除轨迹内容 /// /// /// [HttpPost("Track/BatchDeleteByEsId")] public async Task BatchDeleteTrackByEsIdAsync(BatchDeleteTrackByEsIdInput input) { var tracks = await _trackDetailsEsRepository.GetDataByIds(input.TrackContentEsIds.ToArray()); if (tracks == null || tracks.Count == 0) return new UnifyResultDto(false, "未找到指定id下的轨迹内容"); if (tracks.Any(m => m.Source == TrackSourceEnum.ExternalServiceProvide.GetHashCode())) return new UnifyResultDto(false, "存在来源于外部服务商的轨迹,不允许删除"); if (tracks.GroupBy(m => m.SubSystemId).Count() > 1) return new UnifyResultDto(false, "暂不支持跨子系统批量删除"); // 获取用户name var userInfo = await _requestCurrentUserService.Service.GetCurrentUserBasicInfoAsync(); if (userInfo.Code != GlobalConst.SuccessCode || userInfo.Data is null) { throw new BusinessException(message: $"调用用户中心,获取用户信息失败:{userInfo.Msg}"); } // 删除轨迹 var currentUser = CurrentUserRequest.CurrentUser; var userName = userInfo.Data.UserName; if (string.IsNullOrEmpty(userName)) userName = (await _orderRepository.GetUserById(currentUser.UserId))?.Name; var @event = new TrackDeleteEvent { EsIds = input.TrackContentEsIds.ToArray(), SubSystemId = tracks.First().SubSystemId, OperationMan = userName, OperationManId = currentUser.UserId }; await _capPublisher.PublishAsync(GlobalConst.TrackDeleteSubscribe, @event); return new UnifyResultDto(true); } /// /// 批量删除轨迹 /// /// /// /// [HttpPost("Track/BatchDelete")] public async Task BatchDeleteTrackAsync(BatchDeleteTrackInput input) { input.OrderNos = input.OrderNos.Where(x => !x.IsNullOrWhiteSpace()).Distinct().ToList(); // 单号去重、去空 var orderIds = await _orderRepository.GetListAsync(x => x.SubSystemId == input.SubSystemId && x.OrderType == input.OrderType && input.OrderNos.Contains(x.OrderNo) , x => x.Id); if (orderIds.Count == 0) { throw new BusinessException(message: "订单一个都不存在"); } // 获取用户name var userInfo = await _requestCurrentUserService.Service.GetCurrentUserBasicInfoAsync(); if (userInfo.Code != GlobalConst.SuccessCode || userInfo.Data is null) { throw new BusinessException(message: $"调用用户中心,获取用户信息失败:{userInfo.Msg}"); } //删除轨迹约束,只要其中有一条来源是外部的就立即返回错误 var tracks = await _trackDetailsEsRepository .GetListAsync(orderIds.ToArray(), input.TrackIdentifiers.Select(x => x.TrackCode).ToList(), TrackSourceEnum.ExternalServiceProvide); //当要删除的轨迹标识出现交叉则不允许删除 var intersect = tracks.Select(x => $"{x.TrackCode}{x.TrackTime}") .Intersect(input.TrackIdentifiers.Select(y => $"{y.TrackCode}{y.TrackTime}")).ToList(); if (intersect.Count > 0) { throw new BusinessException(message: "存在来源于外部服务商的轨迹,不允许删除"); } // 删除轨迹 var @event = new TrackDeleteEvent { OrderIds = orderIds.ToArray(), TrackIdentifiers = input.TrackIdentifiers, SubSystemId = input.SubSystemId, OperationMan = userInfo.Data.UserName, }; await _capPublisher.PublishAsync(GlobalConst.TrackDeleteSubscribe, @event); return new UnifyResultDto(true, true); } /// /// 批量新增、更新轨迹 /// /// /// /// [HttpPost("Track/BatchUpsert")] public async Task BatchUpsertTrackAsync(BatchUpsertTrackInput input) { input.OrderNos = input.OrderNos.Where(x => !x.IsNullOrWhiteSpace()).Distinct().ToList(); // 单号去重、去空 var orders = await _orderRepository.GetListAsync(x => x.SubSystemId == input.SubSystemId && x.OrderType == input.OrderType && input.OrderNos.Contains(x.OrderNo), x => new { x.Id, x.OrderNo, x.CustomId }); if (orders.Count == 0) { throw new BusinessException(message: "订单一个都不存在"); } if (!GlobalConst.SupportTrackSources.Contains(input.Source)) { throw new BusinessException(message: "轨迹来源是必须的"); } //当修改时,如果为来源为外部提供商则不允许修改 if (!input.IsAdd && input.Source == (int) TrackSourceEnum.ExternalServiceProvide) { throw new BusinessException(message: "来源为外部服务商轨迹不允许修改"); } // 校验主体:批量新增只选取第一条订单进行校验 //【新增】存在指定轨迹的内容,进行更新覆盖(只处理一条的情况,并且决定权交给用户),不存在直接插入即可 //【更新】存在指定轨迹的内容(匹配到多条则不处理) var order = orders.First(); //要求时间在当前时间的前后100年之间内 bool ValidateTrackTime(DateTime? d) => (d != null && d < DateTime.Now.AddYears(-100) || d > DateTime.Now.AddYears(100)); if (ValidateTrackTime(input.TrackTime) || ValidateTrackTime(input.NewTrackTime) || ValidateTrackTime(input.EstimatedDeliveryDate)) { throw new BusinessException(message: "轨迹时间不合法"); } if ((input.EstimatedDeliveryDate.HasValue == false && input.DestinationTimeZone.HasValue) || (input.EstimatedDeliveryDate.HasValue && input.DestinationTimeZone.HasValue == false)) { throw new BusinessException(message: "【预计签收时间】和【签收地时区】必须同时输入"); } var trackContent = await _trackContentRepository.GetByCodeAsync(input.SubSystemId, input.TrackCode); if (trackContent == default) { throw new BusinessException(message: $"轨迹代码:{input.TrackCode}轨迹内容不存在"); } //指示是否为手动操作 var manualOperation = input.Source == (int) TrackSourceEnum.Artificial; //不允许手动创建 if (manualOperation && input.IsAdd && !trackContent.IsAllowManuallyCreate) { throw new BusinessException(message: $"轨迹代码:{input.TrackCode}不允许手动创建"); } //不允许手动更新 if (manualOperation && !input.IsAdd && !trackContent.IsAllowManuallyUpdate) { throw new BusinessException(message: $"轨迹代码:{input.TrackCode}不允许手动更新"); } var tracks = (await _trackDetailsEsRepository.GetListAsync(new[] { order.Id }, input.TrackCode, true)) .Where(x => x.TrackTime == input.TrackTime) .ToList(); //当为更新操作时发现更新的数目为0进行重试操作 if (!input.IsAdd && tracks.Count == 0) { var curRetryCount = 0; var success = false; while (!success && curRetryCount < GlobalConst.MaxUpdateTrackRetryCount) { try { tracks = (await _trackDetailsEsRepository.GetListAsync(new[] { order.Id }, input.TrackCode, true)) .Where(x => x.TrackTime == input.TrackTime) .ToList(); if (tracks.Count > 0) success = true; await Task.Delay(300); } finally { curRetryCount++; } } if (tracks.Count == 0) { throw new BusinessException(message: $"订单:[{string.Join(",", input.OrderNos)}],轨迹代码:{input.TrackCode}没有要更新的记录"); } } //更新轨迹,同一时间存在多条轨迹记录,理由:不清晰到底要修改哪一条或是全部修改 if (!input.IsAdd && tracks.Count > 1) { throw new BusinessException(message: $"订单:{order.OrderNo},轨迹代码:{input.TrackCode}存在多条记录,不允许修改"); } // 获取用户name var userInfo = await _requestCurrentUserService.Service.GetCurrentUserBasicInfoAsync(); if (userInfo.Code != GlobalConst.SuccessCode || userInfo.Data is null) { throw new BusinessException(message: $"调用用户中心,获取用户信息失败:{userInfo.Msg}"); } // 按客户新增/更新轨迹(为了推送轨迹时方便) foreach (var group in orders.GroupBy(x => x.CustomId)) { var @event = new TrackUpsertEvent { SubSystemId = input.SubSystemId, CustomId = group.Key, OrderIdentifiers = group.Select(o => new OrderIdentifier { OrderId = o.Id, OrderNo = o.OrderNo, OrderType = input.OrderType, }).ToArray(), IsAdd = input.IsAdd, TrackCode = input.TrackCode, TrackPlace = input.TrackPlace, TrackTime = input.TrackTime, NewTrackTime = input.NewTrackTime, TrackTimeZone = input.TrackTimeZone, OperationMan = userInfo.Data.UserName, OperationManId = userInfo.Data.UserId, IsVisibility = input.IsVisibility, Source = input.Source, Remarks = input.Remarks, Files = input.Files, Content = input.Content, EnStatus = input.EnStatus, TrackPlaceCity = input.TrackPlaceCity, TrackPlaceCityId = input.TrackPlaceCityId, TrackPlaceProvince = input.TrackPlaceProvince, TrackPlaceProvinceId = input.TrackPlaceProvinceId, TrackPlaceNation = input.TrackPlaceNation, TrackPlaceNationId = input.TrackPlaceNationId, TrackPlacePostcode = input.TrackPlacePostcode, EstimatedDeliveryDate = input.EstimatedDeliveryDate, DestinationTimeZone = input.DestinationTimeZone, Extra = input.Extra }; await _capPublisher.PublishAsync(GlobalConst.TrackUpsertSubscribe, @event); } return new UnifyResultDto(true, true); } }