using DotNetCore.CAP; using InterfaceForward.Domain.Shared.Helpers; using TrackCenter.Application.Dtos.ProvideServices; using TrackCenter.Domain.Aggregates.OrderAggregate; using TrackCenter.Domain.Aggregates.TrackDetailsAggregate; using SqlSugar; using TrackCenter.Application.Services.Warning.Handlers; using TrackCenter.Repository.Aggregates.OrderAggregate; namespace TrackCenter.Application.Services.ProvideServices; /// /// 订单服务 /// [ApiExplorerSettings(GroupName = "提供接口")] [Route("/ProviderService")] public partial class OrderService : ApplicationServiceBase { private readonly IOrderOperationRecordEsRepository _orderOperationRecordEsRepository; private readonly IOrderRepository _orderRepository; private readonly IServiceProvider _serviceProvider; public OrderService( IOrderRepository orderRepository, ICapPublisher capPublisher, ITrackDetailsEsRepository trackDetailsEsRepository, IOrderOperationRecordEsRepository orderOperationRecordEsRepository, IServiceProvider serviceProvider ) { _orderRepository = orderRepository; _orderOperationRecordEsRepository = orderOperationRecordEsRepository; _serviceProvider = serviceProvider; _trackDetailsEsRepository = trackDetailsEsRepository; _capPublisher = capPublisher; } /// /// 新增、更新订单(存在就更新) /// /// /// [HttpPost("Order/Upsert")] public async Task UpsertAsync(UpsertOrderInput input) { // 校验预计到达时间是否不是同时存在或同时不存在 if ((input.EstimatedDeliveryDate.HasValue && input.DestinationTimeZone.HasValue == false) || (input.EstimatedDeliveryDate.HasValue == false && input.DestinationTimeZone.HasValue)) { throw new BusinessException(message: "【预计签收时间】和【签收地时区】必须同时输入"); } // 校验订单是否已存在,存在则更新 var order = await _orderRepository.GetFirstAsync(x => x.AppKey == input.AppKey && x.OrderType == input.OrderType && x.OrderNo == input.OrderNo); if (order != null) { // 订单已存在则视为更新 await UpdateOrderAsync(input, order); var index = new OrderOperationRecordIndex { OrderId = order.Id, OrderNo = input.OrderNo, OptionType = OrderOperationType.修改订单.ToString(), Content = input.ToJson(), CreateUserId = CurrentUser.Id ?? Guid.Empty, CreateUserName = CurrentUser.UserName ?? string.Empty, }; _ = _orderOperationRecordEsRepository.AddAsync(index); return new IdBaseDto { Id = order.Id }; } order = ObjectMapper.Map(input); order.OrderFlights = ObjectMapper.Map, List>(input.FlightInfos); order.OrderPullStatus = BuiltOrderPullStatus(input.PullConfigInfos); order.SetThirdPartyOrderNumber(order.OrderPullStatus); var orderId = await _orderRepository.CreateOrderAsync(order); // 写入操作日志 var indexForAdd = new OrderOperationRecordIndex { OrderId = orderId, OrderNo = input.OrderNo, OptionType = nameof(OrderOperationType.创建订单), Content = input.ToJson(), CreateUserId = CurrentUser.Id ?? Guid.Empty, CreateUserName = CurrentUser.UserName ?? string.Empty, CreateTime = DateTime.Now }; _ = _orderOperationRecordEsRepository.AddAsync(indexForAdd); return new IdBaseDto { Id = orderId }; } /// /// 批量创建/新增 轨迹订单 /// /// /// /// [HttpPost("Order/BatchUpsert")] public async Task BatchUpsertAsync(BatchUpsertOrderInput input) { if (input.OrderInputs.Any(x => (x.EstimatedDeliveryDate.HasValue && x.DestinationTimeZone.HasValue == false) || (x.EstimatedDeliveryDate.HasValue == false && x.DestinationTimeZone.HasValue))) { throw new BusinessException(message: "【预计签收时间】和【签收地时区】必须同时输入"); } var exp = Expressionable.Create(); foreach (var order in input.OrderInputs) exp.Or(x => x.OrderType == order.OrderType && x.AppKey == order.AppKey && x.OrderNo == order.OrderNo); // 获取已存在的订单 var existsOrders = await _orderRepository.GetListAsync(exp.ToExpression()); var updateOrders = existsOrders.Count > 0 ? new List(existsOrders.Count) : Empty.List; var updateRecords = existsOrders.Count > 0 ? new List(existsOrders.Count) : Empty.List; if (existsOrders.Count > 0) { foreach (var order in existsOrders) { var input2 = input.OrderInputs.First(x => x.OrderType == order.OrderType && x.AppKey == order.AppKey && x.OrderNo == order.OrderNo); var order2 = ObjectMapper.Map(input2, order); order2.OrderFlights = ObjectMapper.Map, List>(input2.FlightInfos); order2.OrderPullStatus = BuiltOrderPullStatus(input2.PullConfigInfos); order2.SetThirdPartyOrderNumber(order.OrderPullStatus); updateOrders.Add(order2); updateRecords.Add(new OrderOperationRecordIndex { OrderId = order.Id, OrderNo = order.OrderNo, OptionType = nameof(OrderOperationType.修改订单), Content = input2.ToJson(), CreateUserId = CurrentUser.Id ?? Guid.Empty, CreateUserName = CurrentUser.UserName ?? string.Empty, CreateTime = DateTime.Now }); } await _orderRepository.UpdateBatchOrderAsync(updateOrders); _ = _orderOperationRecordEsRepository.AddManyAsync(updateRecords); } // 如果全部操作为修改 if (existsOrders.Count == input.OrderInputs.Count) return; // 新增订单 var existsOrderNos = existsOrders.Select(x => x.OrderNo).ToHashSet(); var insertInputs = input.OrderInputs .WhereIf(existsOrderNos.Count > 0, x => !existsOrderNos.Contains(x.OrderNo)) .ToList(); var insertOrders = new List(insertInputs.Count); var createRecords = new List(insertInputs.Count); foreach (var insertInput in insertInputs) { var order = ObjectMapper.Map(insertInput); order.OrderFlights = ObjectMapper.Map, List>(insertInput.FlightInfos); order.OrderPullStatus = BuiltOrderPullStatus(insertInput.PullConfigInfos); order.SetThirdPartyOrderNumber(order.OrderPullStatus); insertOrders.Add(order); createRecords.Add(new OrderOperationRecordIndex { //OrderId = default, //稍后补充 OrderNo = order.OrderNo, OptionType = OrderOperationType.创建订单.ToString(), Content = insertInput.ToJson(), CreateUserId = CurrentUser.Id ?? Guid.Empty, CreateUserName = CurrentUser.UserName ?? string.Empty, CreateTime = DateTime.Now }); } // 创建订单,创建操作记录 var orderNoIdDict = await _orderRepository.CreateBatchOrderAsync(insertOrders); foreach (var record in createRecords) { var orderId = orderNoIdDict[record.OrderNo]; record.OrderId = orderId; } _ = _orderOperationRecordEsRepository.AddManyAsync(createRecords); } /// /// 删除订单 /// /// /// /// [HttpPost("Order/Delete")] public async Task DeleteOrderAsync(DeleteOrderInput input) { var order = await _orderRepository.GetFirstAsync(x => x.AppKey == input.AppKey && x.OrderType == input.OrderType && x.OrderNo == input.OrderNo); if (order == null) { throw new BusinessException(message: $"订单:{input.OrderNo}不存在"); } await _orderRepository.DeleteOrderAsync(order.Id); // 预警计算 WarningCalc_OrderDeletedOrCompleted(order); return new IdBaseDto { Id = order.Id }; } private async Task UpdateOrderAsync(UpdateOrderInput input, OrderEntity order) { order = ObjectMapper.Map(input, order); order.OrderFlights = ObjectMapper.Map, List>(input.FlightInfos); order.OrderPullStatus = BuiltOrderPullStatus(input.PullConfigInfos); order.SetThirdPartyOrderNumber(order.OrderPullStatus); await _orderRepository.UpdateOrderAsync(order); } private static List BuiltOrderPullStatus(List? pullConfigInfos) { if (pullConfigInfos == null) return new List(); return pullConfigInfos.Select(x => { var status = new OrderPullStatusEntity { ServiceProviderCode = x.ServiceCode, OrderNo = x.OrderNo, PullStatus = TrackPullStatus.Init, StartTrackCode = x.StartCode ?? GlobalConst.EmptyString, EndTrackCode = x.EndCode ?? GlobalConst.EmptyString, SilenceBeforeStart = x.SilenceTime, SilenceAfterEnd = x.StopTime, StartTime = GlobalConst.MaxDateTime, EndTime = GlobalConst.MaxDateTime, }; // 没有开始轨迹则立即进入拉取前静默期 if (x.StartCode == null) { status.PullStatus = TrackPullStatus.SilenceBeforeStart; // 会被定时任务扫描到并启动 status.StartTime = DateTime.Now.AddHours(x.SilenceTime); } return status; }).ToList(); } private void WarningCalc_OrderDeletedOrCompleted(OrderEntity order) { order.IsDeleted = true; _ = Task.Run(async () => { var scope = _serviceProvider.CreateAsyncScope(); try { var handler = scope.ServiceProvider.GetRequiredService(); await handler.HandleOrderDeletedOrCompletedAsync(order); } catch (Exception ex) { LogHelper.Error(ex); } finally { await scope.DisposeAsync(); } }); } }