588 lines
24 KiB
C#
588 lines
24 KiB
C#
using DotNetCore.CAP;
|
||
using Microsoft.AspNetCore.Http;
|
||
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.Aggregates.TrackTemplateAggregate;
|
||
using SJZY.Track.Domain.Enums;
|
||
using SJZY.Track.Domain.Extensions;
|
||
using SJZY.Track.Domain.Queries;
|
||
using SJZY.UserCenter.HttpApi.Services;
|
||
using SJZY.UserCenter.HttpApi.Services.User;
|
||
using Volo.Abp.Http.Client.DynamicProxying;
|
||
|
||
namespace SJZY.Track.Application.Services.ProvideServices;
|
||
|
||
/// <summary>
|
||
/// 轨迹服务
|
||
/// </summary>
|
||
[ApiExplorerSettings(GroupName = "提供接口")]
|
||
[Route("/ProviderService")]
|
||
public partial class TrackService : ApplicationService, ITrackService
|
||
{
|
||
private readonly ICapPublisher _capPublisher;
|
||
private readonly IOrderRepository _orderRepository;
|
||
private readonly IHttpClientProxy<IUserBaseInfoService> _requestCurrentUserService;
|
||
private readonly ITrackContentRepository _trackContentRepository;
|
||
|
||
public TrackService(IOrderRepository orderRepository,
|
||
ICapPublisher capPublisher,
|
||
ITrackDetailsEsRepository trackDetailsEsRepository,
|
||
ITrackContentRepository trackContentRepository,
|
||
IHttpClientProxy<IUserBaseInfoService> requestCurrentUserService,
|
||
ITrackTemplateRepository trackTemplateRepository,
|
||
IHttpContextAccessor contextAccessor,
|
||
IVSystemQueries vSystemQueries)
|
||
{
|
||
_orderRepository = orderRepository;
|
||
_capPublisher = capPublisher;
|
||
_trackContentRepository = trackContentRepository;
|
||
_requestCurrentUserService = requestCurrentUserService;
|
||
_vSystemQueries = vSystemQueries;
|
||
_contextAccessor = contextAccessor;
|
||
_trackTemplateRepository = trackTemplateRepository;
|
||
_trackDetailsEsRepository = trackDetailsEsRepository;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 删除轨迹
|
||
/// </summary>
|
||
/// <param name="input"></param>
|
||
/// <returns></returns>
|
||
/// <exception cref="BusinessException"></exception>
|
||
[HttpPost("Track/Delete")]
|
||
public async Task<UnifyResultDto> 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 == null)
|
||
{
|
||
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;
|
||
|
||
List<TrackDetailsIndex> tracks;
|
||
bool existsExternal;
|
||
var esIds = input.EsIds?.Distinct().ToArray();
|
||
//优先使用esId
|
||
if (esIds != null && esIds.Length > 0)
|
||
{
|
||
tracks = await _trackDetailsEsRepository.GetDataByIds(esIds);
|
||
existsExternal = tracks.Any(x => x.Source == (int) TrackSourceEnum.ExternalServiceProvide);
|
||
}
|
||
else
|
||
{
|
||
var trackCodes = input.TrackIdentifiers?.Select(x => x.TrackCode).ToList();
|
||
var trackIds = input.TrackIdentifiers?.Select(y => $"{y.TrackCode}{y.TrackTime}").ToHashSet();
|
||
//没有任何需要操作的轨迹
|
||
if (trackIds == null || trackIds.Count == 0)
|
||
{
|
||
throw new BusinessException(message: "没有任何轨迹要删除,请检查输入参数");
|
||
}
|
||
|
||
//删除轨迹约束,只要其中有一条来源是外部的就立即返回错误
|
||
tracks = await _trackDetailsEsRepository.GetListAsync(new[] { orderId }, trackCodes);
|
||
//检查删除的轨迹中是否包含外部轨迹
|
||
existsExternal = tracks
|
||
.Where(x => x.Source == (int) TrackSourceEnum.ExternalServiceProvide)
|
||
.WhereIf(!input.CompareFields.IsNullOrWhiteSpace(), y =>
|
||
{
|
||
if (string.IsNullOrWhiteSpace(y.Extra))
|
||
{
|
||
throw new BusinessException(message: "轨迹extra为空无法使用比较字段比较,请检查轨迹");
|
||
}
|
||
|
||
var extraDict = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, object>>(y.Extra);
|
||
if (extraDict!.TryGetValue(input.CompareFields!, out var compareValueJsonElement))
|
||
return TextJsonHelper.EqJsonElementAndObject(compareValueJsonElement, input.CompareValue);
|
||
|
||
return false;
|
||
})
|
||
.Select(x => $"{x.TrackCode}{x.TrackTime}")
|
||
.Any(x => trackIds.Contains(x));
|
||
}
|
||
|
||
if (existsExternal)
|
||
{
|
||
throw new BusinessException(message: "存在来源于外部服务商的轨迹,不允许删除");
|
||
}
|
||
|
||
if (tracks.Count == 0)
|
||
{
|
||
throw new BusinessException(message: "没有任何轨迹要删除,请检查输入参数");
|
||
}
|
||
|
||
// 删除轨迹
|
||
await _capPublisher.PublishAsync(GlobalConst.TrackDeleteSubscribe,
|
||
new TrackDeleteEvent
|
||
{
|
||
EsIds = input.EsIds?.ToArray(),
|
||
OrderIds = new[] { orderId },
|
||
CompareFields = input.CompareFields,
|
||
CompareValue = input.CompareValue,
|
||
Source = input.Source,
|
||
TrackIdentifiers = input.TrackIdentifiers,
|
||
SubSystemId = input.SubSystemId,
|
||
OperationMan = name
|
||
});
|
||
|
||
return new UnifyResultDto(true, true);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 根据esid删除轨迹内容
|
||
/// </summary>
|
||
/// <param name="input"></param>
|
||
/// <returns></returns>
|
||
[HttpPost("Track/BatchDeleteByEsId")]
|
||
public async Task<UnifyResultDto> 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,
|
||
Source = input.Source,
|
||
OperationMan = userName,
|
||
OperationManId = currentUser.UserId
|
||
};
|
||
await _capPublisher.PublishAsync(GlobalConst.TrackDeleteSubscribe, @event);
|
||
|
||
return new UnifyResultDto(true);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 批量删除轨迹
|
||
/// </summary>
|
||
/// <param name="input"></param>
|
||
/// <returns></returns>
|
||
/// <exception cref="BusinessException"></exception>
|
||
[HttpPost("Track/BatchDelete")]
|
||
public async Task<UnifyResultDto> 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
|
||
.WhereIf(!input.CompareFields.IsNullOrWhiteSpace(), y =>
|
||
{
|
||
if (string.IsNullOrWhiteSpace(y.Extra))
|
||
{
|
||
throw new BusinessException(message: "轨迹extra为空无法使用比较字段比较,请检查轨迹");
|
||
}
|
||
|
||
var extraDict = TextJsonHelper.DeserializeToDictionary(y.Extra);
|
||
if (extraDict!.TryGetValue(input.CompareFields!, out var compareValueJsonElement))
|
||
return TextJsonHelper.EqJsonElementAndObject(compareValueJsonElement, input.CompareValue);
|
||
|
||
return false;
|
||
})
|
||
.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(),
|
||
Source = input.Source,
|
||
TrackIdentifiers = input.TrackIdentifiers,
|
||
CompareFields = input.CompareFields,
|
||
CompareValue = input.CompareValue,
|
||
SubSystemId = input.SubSystemId,
|
||
OperationMan = userInfo.Data.UserName,
|
||
};
|
||
await _capPublisher.PublishAsync(GlobalConst.TrackDeleteSubscribe, @event);
|
||
|
||
return new UnifyResultDto(true, true);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 新增、更新轨迹(存在就更新)
|
||
/// </summary>
|
||
/// <param name="input"></param>
|
||
/// <returns></returns>
|
||
/// <exception cref="BusinessException"></exception>
|
||
[HttpPost("Track/Upsert")]
|
||
public async Task<UnifyResultDto> 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.OrderNo,
|
||
x.CustomId
|
||
});
|
||
if (order == null)
|
||
{
|
||
throw new BusinessException(message: $"订单:{input.OrderNo}不存在");
|
||
}
|
||
|
||
// 输入参数的静态规则检查
|
||
// 轨迹内容上的约束检查
|
||
// 更新轨迹时是否可以匹配到轨迹的检查
|
||
await TrackUpsertValidation(input.IsAdd,
|
||
input.SubSystemId,
|
||
order.Id,
|
||
order.OrderNo,
|
||
input.TrackCode,
|
||
input.Source,
|
||
input.TrackTime,
|
||
input.NewTrackTime,
|
||
input.EstimatedDeliveryDate,
|
||
input.DestinationTimeZone,
|
||
input.Extra,
|
||
input.CompareFields);
|
||
|
||
var userInfo = await _requestCurrentUserService.Service.GetCurrentUserBasicInfoAsync();
|
||
if (userInfo.Code != GlobalConst.SuccessCode || userInfo.Data is null)
|
||
{
|
||
//todo:保留之前的方式(FBA在用) 后续可能去除
|
||
userInfo = await _requestCurrentUserService.Service.GetCurrentUserBasicInfoAsync(input.OptionUserId);
|
||
|
||
if (userInfo.Code != GlobalConst.SuccessCode || userInfo.Data is null)
|
||
throw new BusinessException(message: $"调用用户中心,获取用户信息失败:{userInfo.Msg}");
|
||
}
|
||
|
||
var name = userInfo.Data.UserName;
|
||
|
||
// 新增/更新轨迹
|
||
var @event = ObjectMapper.Map<UpsertTrackInput, TrackUpsertEvent>(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);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 批量新增、更新轨迹
|
||
/// </summary>
|
||
/// <param name="input"></param>
|
||
/// <returns></returns>
|
||
/// <exception cref="BusinessException"></exception>
|
||
[HttpPost("Track/BatchUpsert")]
|
||
public async Task<UnifyResultDto> 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: "订单一个都不存在");
|
||
}
|
||
|
||
// 校验主体:批量新增只选取第一条订单进行校验
|
||
//【新增】存在指定轨迹的内容,进行更新覆盖(只处理一条的情况,并且决定权交给用户),不存在直接插入即可
|
||
//【更新】存在指定轨迹的内容(匹配到多条则不处理)
|
||
var order = orders.First();
|
||
|
||
// 输入参数的静态规则检查
|
||
// 轨迹内容上的约束检查
|
||
// 更新轨迹时是否可以匹配到轨迹的检查
|
||
await TrackUpsertValidation(input.IsAdd,
|
||
input.SubSystemId,
|
||
order.Id,
|
||
order.OrderNo,
|
||
input.TrackCode,
|
||
input.Source,
|
||
input.TrackTime,
|
||
input.NewTrackTime,
|
||
input.EstimatedDeliveryDate,
|
||
input.DestinationTimeZone,
|
||
input.Extra,
|
||
input.CompareFields);
|
||
|
||
// 获取用户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,
|
||
IsExternal = input.IsExternal,
|
||
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,
|
||
CompareFields = input.CompareFields,
|
||
Extra = input.Extra,
|
||
ForcedPush = input.ForcedPush,
|
||
IsToMq = input.IsToMq,
|
||
};
|
||
await _capPublisher.PublishAsync(GlobalConst.TrackUpsertSubscribe, @event);
|
||
}
|
||
|
||
return new UnifyResultDto(true, true);
|
||
}
|
||
|
||
//在轨迹更新主流程之前的前置检查
|
||
private async Task TrackUpsertValidation(
|
||
bool isAdd,
|
||
int subSystemId,
|
||
int orderId,
|
||
string orderNo,
|
||
string trackCode,
|
||
int source,
|
||
DateTime trackTime,
|
||
DateTime? newTrackTime,
|
||
DateTime? estimatedDeliveryDate,
|
||
float? destinationTimeZone,
|
||
string? extra,
|
||
string? compareFields
|
||
)
|
||
{
|
||
#region 静态规则检查
|
||
|
||
// 约束轨迹来源只能选取 1-外部 2-内部 3-手动
|
||
if (!GlobalConst.SupportTrackSources.Contains(source))
|
||
{
|
||
throw new BusinessException(message: "轨迹来源是必须的,1:外部服务商 2:内部系统 3:人工操作");
|
||
}
|
||
|
||
//当修改时,如果为来源为外部提供商则不允许修改
|
||
if (!isAdd && source == (int) TrackSourceEnum.ExternalServiceProvide)
|
||
{
|
||
throw new BusinessException(message: "来源为外部服务商轨迹不允许修改");
|
||
}
|
||
|
||
//要求时间在当前时间的前后100年之间内
|
||
bool ValidateTrackTime(DateTime? d) => (d != null && d < DateTime.Now.AddYears(-100) || d > DateTime.Now.AddYears(100));
|
||
if (ValidateTrackTime(trackTime) || ValidateTrackTime(newTrackTime) || ValidateTrackTime(estimatedDeliveryDate))
|
||
{
|
||
throw new BusinessException(message: "轨迹时间不合法");
|
||
}
|
||
|
||
if ((estimatedDeliveryDate.HasValue == false && destinationTimeZone.HasValue) ||
|
||
(estimatedDeliveryDate.HasValue && destinationTimeZone.HasValue == false))
|
||
{
|
||
throw new BusinessException(message: "【预计签收时间】和【签收地时区】必须同时输入");
|
||
}
|
||
|
||
if (!string.IsNullOrWhiteSpace(compareFields) && string.IsNullOrWhiteSpace(extra))
|
||
{
|
||
throw new BusinessException(message: "当输入了【轨迹对比字段】则轨迹扩展是必须的的");
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 轨迹内容中的配置规则检查
|
||
|
||
var trackContent = await _trackContentRepository.GetByCodeAsync(subSystemId, trackCode);
|
||
if (trackContent == null)
|
||
{
|
||
throw new BusinessException(message: $"轨迹代码:{trackCode}轨迹内容不存在");
|
||
}
|
||
|
||
//指示是否为手动操作
|
||
var manualOperation = source == (int) TrackSourceEnum.Artificial;
|
||
|
||
//不允许手动创建
|
||
if (manualOperation && isAdd && !trackContent.IsAllowManuallyCreate)
|
||
{
|
||
throw new BusinessException(message: $"轨迹代码:{trackCode}不允许手动创建");
|
||
}
|
||
|
||
//不允许手动更新
|
||
if (manualOperation && !isAdd && !trackContent.IsAllowManuallyUpdate)
|
||
{
|
||
throw new BusinessException(message: $"轨迹代码:{trackCode}不允许手动更新");
|
||
}
|
||
|
||
#endregion
|
||
|
||
//轨迹新增,不允许重复的轨迹提前拦截
|
||
if (isAdd)
|
||
{
|
||
//允许重复,跳过检查
|
||
if (trackContent.IsRepeatable) return;
|
||
//找到这个订单的这个轨迹code的所有轨迹
|
||
var tracks = await RetryQueryTrackAsync(orderId, trackCode, trackTime, extra, compareFields, trackContent.IsRepeatable);
|
||
if (tracks.Count > 0)
|
||
throw new BusinessException(message: $"订单:[{orderNo}],轨迹代码:{trackCode}不允许重复创建轨迹");
|
||
}
|
||
//针对于轨迹更新检查
|
||
else
|
||
{
|
||
//找到这个订单的这个轨迹code的所有轨迹,
|
||
var tracks = await RetryQueryTrackAsync(orderId, trackCode, trackTime, extra, compareFields, trackContent.IsRepeatable);
|
||
//不存在需要更新的轨迹
|
||
if (tracks.Count == 0)
|
||
throw new BusinessException(message: $"订单:[{orderNo}],轨迹代码:[{trackCode}]没有要更新的记录");
|
||
|
||
//更新轨迹,同一时间存在多条轨迹记录,理由:不清晰到底要修改哪一条或是全部修改
|
||
if (tracks.Count > 1)
|
||
throw new BusinessException(message: $"订单:{orderNo},轨迹代码:[{trackCode}]存在多条记录,不允许修改");
|
||
}
|
||
}
|
||
|
||
// 重试查询轨迹,直到存在符合要求的轨迹,或者超过最大重试次数
|
||
private async Task<List<TrackDetailsIndex>> RetryQueryTrackAsync(int orderId, string trackCode, DateTime trackTime, string? extra, string? compareFields, bool isRepeatable)
|
||
{
|
||
var tracks = await QueryAndFilterAsync(orderId, trackCode, trackTime, extra, compareFields, isRepeatable);
|
||
if (tracks.Count > 0)
|
||
return tracks;
|
||
|
||
//重试阶段
|
||
var curRetryCount = 0;
|
||
while (curRetryCount < GlobalConst.MaxUpdateTrackRetryCount) //tips:后续将最大重试次数提出到配置中
|
||
{
|
||
try
|
||
{
|
||
tracks = await QueryAndFilterAsync(orderId, trackCode, trackTime, extra, compareFields, isRepeatable);
|
||
if (tracks.Count > 0)
|
||
return tracks;
|
||
//指数退避等待
|
||
var delay = TimeSpan.FromMilliseconds(Math.Pow(2, curRetryCount) * 150); // 150ms, 300ms, 600ms, ...
|
||
await Task.Delay(delay);
|
||
}
|
||
finally
|
||
{
|
||
curRetryCount++;
|
||
}
|
||
}
|
||
|
||
//超过最大重试次数还没找到
|
||
return tracks;
|
||
}
|
||
|
||
//查询并按比较字段过滤轨迹,当比较字段为空时则使用轨迹发生时间过滤
|
||
//tips:后续进行投影缩参优化
|
||
private async Task<List<TrackDetailsIndex>> QueryAndFilterAsync(int orderId, string trackCode, DateTime trackTime, string? extra, string? compareFields, bool isRepeatable)
|
||
{
|
||
var tracks = await _trackDetailsEsRepository.GetListAsync(new[] { orderId }, trackCode, true);
|
||
// 如果不允许重复,则直接返回
|
||
if (!isRepeatable) return tracks;
|
||
|
||
//无比较字段时使用轨迹时间参与过滤(兼容老版本)
|
||
if (string.IsNullOrWhiteSpace(compareFields))
|
||
{
|
||
return tracks.Where(x => x.TrackTime == trackTime).ToList();
|
||
}
|
||
|
||
return tracks.Where(x =>
|
||
{
|
||
if (string.IsNullOrWhiteSpace(x.Extra))
|
||
throw new BusinessException(message: "轨迹extra为空无法使用比较字段比较,请检查轨迹");
|
||
|
||
var extraJsonElement = TextJsonHelper.DeserializeToJsonElement(x.Extra);
|
||
var inputExtraJsonElement = TextJsonHelper.DeserializeToJsonElement(extra);
|
||
|
||
return TextJsonHelper.EqByJsonElementField(extraJsonElement, inputExtraJsonElement, compareFields);
|
||
})
|
||
.ToList();
|
||
}
|
||
}
|