track/src/SJZY.Track.Application/Services/TrackContents/TrackContentService.cs
hardstylewyl 97bee1e3d9 update: 推送行为下拉列表只显示推送映射配置中的轨迹
update: 新增/更新轨迹,增加强制推送标识,此标识会影响推送行为使其变为,
1.明确调用推送轨迹接口 2.不受推送映射的顺序限制
2024-12-20 17:05:57 +08:00

568 lines
23 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Linq.Expressions;
using Microsoft.Extensions.Localization;
using SJZY.Expand.ABP.Core.Localization;
using SJZY.Expand.ABP.Core.PublicMethords;
using SJZY.Expand.AliyunOSS;
using SJZY.Track.Application.Contract.Dtos.ProvideServices;
using SJZY.Track.Application.Contract.Dtos.TrackContents;
using SJZY.Track.Application.Contract.Services;
using SJZY.Track.Application.Localization;
using SJZY.Track.Domain.Aggregates.OrderAggregate;
using SJZY.Track.Domain.Aggregates.TrackContentAggregate;
using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
using SJZY.Track.Domain.Aggregates.TrackFlagAggregate;
using SJZY.Track.Domain.Aggregates.TrackStatusAggregate;
using SJZY.Track.Domain.Aggregates.TrackTemplateAggregate;
using SJZY.Track.Domain.Dtos.TrackContents;
using SJZY.Track.Domain.Enums;
using SJZY.Track.Domain.Queries;
namespace SJZY.Track.Application.Services.TrackContents;
/// <summary>
/// 轨迹内容服务
/// </summary>
[ApiExplorerSettings(GroupName = "轨迹内容")]
[Route("/Track/Content")]
public class TrackContentService : ApplicationService
{
private readonly IStringLocalizer<TrackLocalizationResource> _stringLocalizer;
private readonly ITrackContentRepository _trackContentRepository;
private readonly ITrackTemplateRepository _trackTemplateRepository;
private readonly IBasicQuery<TrackFlagEntity> _trackFlagBasicQuery;
private readonly IBasicQuery<TrackStatusEntity> _trackStatusBasicQuery;
private readonly IOrderRepository _orderRepository;
private readonly ITrackDetailsEsRepository _trackDetailsEsRepository;
private readonly ITrackPushCacheService _trackPushCacheService;
public TrackContentService(
IStringLocalizer<TrackLocalizationResource> stringLocalizer,
ITrackContentRepository trackContentRepository,
IBasicQuery<TrackStatusEntity> trackStatusBasicQuery,
IBasicQuery<TrackFlagEntity> trackFlagBasicQuery,
IOrderRepository orderRepository,
ITrackDetailsEsRepository trackDetailsEsRepository,
ITrackTemplateRepository trackTemplateRepository, ITrackPushCacheService trackPushCacheService)
{
_stringLocalizer = stringLocalizer;
_trackContentRepository = trackContentRepository;
_trackStatusBasicQuery = trackStatusBasicQuery;
_trackFlagBasicQuery = trackFlagBasicQuery;
_orderRepository = orderRepository;
_trackDetailsEsRepository = trackDetailsEsRepository;
_trackTemplateRepository = trackTemplateRepository;
_trackPushCacheService = trackPushCacheService;
}
/// <summary>
/// 轨迹内容编辑
/// </summary>
/// <returns></returns>
[HttpPost("Edit")]
public async Task<UnifyResultDto> EditAsync(EditTrackContentInput input)
{
if (input.TrackStatusId != null)
{
if (!await _trackStatusBasicQuery.IsAnyAsync(x =>
x.SubSystemId == input.SubSystemId && x.Id == input.TrackStatusId))
{
throw new BusinessException(message: "轨迹状态不存在");
}
}
if (!input.TrackFlagIds.IsNullOrEmpty())
{
var counter = await _trackFlagBasicQuery.CountAsync(x =>
x.SubSystemId == input.SubSystemId && input.TrackFlagIds!.Contains(x.Id));
if (counter != input.TrackFlagIds!.Length)
{
throw new BusinessException(message: "存在非法轨迹标记");
}
}
return input.Options switch
{
OptionType.新增 => await AddAsync(input),
OptionType.修改 => await UpdateAsync(input),
OptionType.删除 => await DeleteAsync(input),
_ => throw new BusinessException(message: "当前操作动作不合法")
};
}
/// <summary>
/// 根据内容id获取轨迹内容
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpGet("GetDetail")]
public async Task<UnifyResultDto<GetTrackContentDetailDto>> GetDetailAsync(int id)
{
var detailInfo = await _trackContentRepository.GetDetailAsync(id);
if (detailInfo == null)
{
return new UnifyResultDto<GetTrackContentDetailDto>(false, null!, "未查询到轨迹状态");
}
var dto = ObjectMapper.Map<GetTrackContentDetailVO, GetTrackContentDetailDto>(detailInfo);
return new UnifyResultDto<GetTrackContentDetailDto>(GlobalConst.SuccessCode, "", dto);
}
/// <summary>
/// 获取分页轨迹内容
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("GetList")]
public async Task<UnifyPageResultDto<GetTrackContentListDto>> GetPageTrackContent(GetPageTrackContentInput input)
{
var vo = ObjectMapper.Map<GetPageTrackContentInput, GetPageTrackContentVO>(input);
var resultDto = await _trackContentRepository.GetPageTrackContent(vo);
var pageResultDto =
ObjectMapper.Map<UnifyPageResultDto<GetTrackContentListVO>, UnifyPageResultDto<GetTrackContentListDto>>(
resultDto);
return pageResultDto;
}
/// <summary>
/// 轨迹内容映射列表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("GetMapPage")]
public async Task<UnifyPageResultDto<GetTrackContentMapPageOutputVO>> GetMapPageAsync(
[FromBody] GetTrackContentMapPageInputVO input)
{
return await _trackContentRepository.GetMapPageAsync(input);
}
/// <summary>
/// 轨迹内容映射详情
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpGet("GetMapDetail")]
public async Task<GetTrackContentMapDetailOutputVO> GetMapDetailAsync(int id)
{
return await _trackContentRepository.GetMapDetailAsync(id);
}
/// <summary>
/// 轨迹内容映射编辑
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("EditMap")]
public async Task<bool> EditMapAsync([FromBody] EditTrackContentMapInput input)
{
if (input.Options != OptionTypeNoNull.删除)
{
if (input.SubSystemId == input.MapSubSystemId)
throw new BusinessException(message: _stringLocalizer["NotAllowedToMapSubSystem"]);
Expression<Func<TrackContentMapEntity, bool>> isMapAnyExp = x =>
x.TrackContentId == input.TrackContentId && x.MapTrackContentId == input.MapTrackContentId;
if (input.Options == OptionTypeNoNull.修改) isMapAnyExp.And(x => x.Id != input.Id);
if (await _trackContentRepository.IsMapAnyAsync(isMapAnyExp))
throw new BusinessException(message: _stringLocalizer["IsTrackContentMapAny"]);
}
switch (input.Options)
{
case OptionTypeNoNull.新增:
var trackContentMapEntity = ObjectMapper.Map<EditTrackContentMapInput, TrackContentMapEntity>(input);
await _trackContentRepository.InsertMapAsync(trackContentMapEntity);
break;
case OptionTypeNoNull.修改:
var oldTrackContentMapEntity = await _trackContentRepository.GetMapByIdAsync(input.Id!.Value) ??
throw new BusinessException(message: _stringLocalizer["NotFindData"]);
ObjectMapper.Map(input, oldTrackContentMapEntity);
await _trackContentRepository.UpdateMapAsync(oldTrackContentMapEntity);
break;
case OptionTypeNoNull.删除:
await _trackContentRepository.SoftDeleteMapAsync(x => x.Id == input.Id);
break;
default:
throw new BusinessException(message: _stringLocalizer[SjzyBasicLocalization.Validation_IsInEnum,
nameof(EditTrackContentMapInput.Options)]);
}
return true;
}
/// <summary>
/// 根据轨迹内容code获取轨迹内容
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("GetTrackContentByCode")]
public async Task<UnifyResultDto<GetTrackContentByCodeOutput>> GetTrackContentByCodeAsync([FromBody] GetTrackContentByCodeInput input)
{
if (input.SystemId <= 0)
return new UnifyResultDto<GetTrackContentByCodeOutput>(false, "子系统Id必须大于等于0");
if (string.IsNullOrEmpty(input.Code))
return new UnifyResultDto<GetTrackContentByCodeOutput>(false, "轨迹内容code不能为空");
var content = await _trackContentRepository.GetByCodeAsync(input.SystemId, input.Code);
if (content == null)
return new UnifyResultDto<GetTrackContentByCodeOutput>(false, "在当前子系统中未找到指定code的轨迹内容");
var res = new UnifyResultDto<GetTrackContentByCodeOutput>(true)
{
Data = new GetTrackContentByCodeOutput
{
Content = content.Content,
EnContent = content.EnContent,
IsExternal = content.IsExternal
}
};
return res;
}
/// <summary>
/// 根据子系统id、单号、订单类型、轨迹发生时间、轨迹code获取轨迹内容
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("GetContentDetail")]
public async Task<UnifyResultDto<GetContentDetailOutput>> GetContentDetail([FromBody] GetContentDetailInput input)
{
if (input.SystemId <= 0)
return new UnifyResultDto<GetContentDetailOutput>(false, "子系统Id必须大于等于0");
if (string.IsNullOrEmpty(input.TrackCode))
return new UnifyResultDto<GetContentDetailOutput>(false, "轨迹内容code不能为空");
if (string.IsNullOrEmpty(input.OrderNumber))
return new UnifyResultDto<GetContentDetailOutput>(false, "订单code不能为空");
if (input.OrderType <= 0)
return new UnifyResultDto<GetContentDetailOutput>(false, "订单类型不能为空");
if (input.TrackTime == default)
return new UnifyResultDto<GetContentDetailOutput>(false, "轨迹发生时间不能为空");
var content = await _trackDetailsEsRepository.GetDetailAsync(input.OrderNumber, input.TrackCode, input.OrderType, input.SystemId, input.TrackTime);
if (content == default)
return new UnifyResultDto<GetContentDetailOutput>(false, "在当前子系统中未找到指定code的轨迹内容");
var res = new UnifyResultDto<GetContentDetailOutput>(true)
{
Data = ObjectMapper.Map<TrackDetailsIndex, GetContentDetailOutput>(content)
};
if (res.Data != default && res.Data.Files.Any())
{
foreach (var item in res.Data.Files)
{
item.Url = OSSHelper.GetUrlByKey(item.OssKey);
}
}
return res;
}
/// <summary>
/// 创建轨迹时获取可用的轨迹内容
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("GetAvailableContent")]
public async Task<UnifyResultDto<List<GetAvailableContentOutput>>> GetAvailableContent(GetAvailableContentInput input)
{
if (input.SystemId <= 0)
return new UnifyResultDto<List<GetAvailableContentOutput>>(false, "系统id需大于0!");
if (string.IsNullOrEmpty(input.OrderNo))
return new UnifyResultDto<List<GetAvailableContentOutput>>(false, "单号不能为空!");
//获取当前订单下已有的轨迹内容
var order = await _orderRepository.GetFirstAsync(x => x.OrderNo == input.OrderNo && x.SubSystemId == input.SystemId);
if (order == default)
throw new BusinessException(message: "订单不存在!");
var res = new UnifyResultDto<List<GetAvailableContentOutput>>(true)
{
Data = new List<GetAvailableContentOutput>()
};
//获取轨迹详情
var trackDetails = await _trackDetailsEsRepository.GetListAsync(order.Id);
// 删除时去除掉外部服务商轨迹
if (input.TrackOptionType == TrackOptionType.删除)
{
trackDetails = trackDetails.Where(m => m.Source != (int) TrackSourceEnum.ExternalServiceProvide).ToList();
}
//进行推送时,匹配订单类型一致的轨迹
if (input.TrackOptionType == TrackOptionType.推送)
{
var pushConfigs = await _trackPushCacheService.GetPushContentConfigsAsync(order.SubSystemId, order.CustomId);
//没有推送配置也不会展示任何下拉
if (pushConfigs == null || pushConfigs.Count == 0) return res;
//选订单类型和配置订单类型一致的配置的轨迹代码
var trackCodes = pushConfigs.Where(m => m.OrderType == order.OrderType)
.Select(x=>x.TrackCode)
.Distinct()
.ToHashSet();
//根据配置过滤轨迹
trackDetails = trackDetails.Where(m => trackCodes.Contains(m.TrackCode)).ToList();
}
//进行删除和推送行为无任何轨迹内容,直接返回为空即可
if (input.TrackOptionType is TrackOptionType.删除 or TrackOptionType.推送 && trackDetails.Count == 0)
{
return res;
}
//获取当前子系统下所有的轨迹内容
var contentList = await _trackContentRepository.GetListBySystemIdAsync(input.SystemId);
if (contentList == null)
throw new BusinessException(message: "当前子系统下未找到任何可用的轨迹内容!");
//如果订单给了获取模板code,则进一步根据模板code进行过滤
if (!string.IsNullOrEmpty(order.TemplateCodes))
{
var currentCodes = order.TemplateCodes.Split(",");
var template = await _trackTemplateRepository.GetContentByTemplateCodes(currentCodes, input.SystemId);
contentList = contentList.Where(m => template.Contains(m.Code)).ToList();
}
foreach (var item in contentList)
{
//新增时跳过已存在轨迹内容
if (input.TrackOptionType == TrackOptionType.创建 && !item.IsRepeatable && trackDetails?.Any(m => m.TrackCode == item.Code) == true)
continue;
// 修改时跳过不存在轨迹内容
if (input.TrackOptionType == TrackOptionType.修改 && trackDetails != null && trackDetails.All(m => m.TrackCode != item.Code))
continue;
if (!item.IsAllowManuallyCreate && input.TrackOptionType == TrackOptionType.创建) //跳过不允许手动创建的轨迹内容
continue;
if (!item.IsAllowManuallyUpdate && input.TrackOptionType == TrackOptionType.修改) //跳过不允许手动修改的轨迹内容
continue;
res.Data.Add(new GetAvailableContentOutput()
{
IsExternal = item.IsExternal,
EnContent = item.EnContent,
Content = item.Content,
Code = item.Code,
Id = item.Id
});
}
if (input.TrackOptionType == TrackOptionType.创建
|| trackDetails == null
|| trackDetails.Count == 0)
{
return res;
}
//修改/删除/推送 操作,查轨迹内容列表反映明细表数据,重新构造响应数据
var matchContent = new List<GetAvailableContentOutput>();
var contents = res.Data.Select(x => new
{
x.Id,
x.IsExternal,
x.Code
});
foreach (var content in contents)
{
var match = trackDetails
.Where(x => x.TrackCode == content.Code)
.Select(matchItem => new GetAvailableContentOutput
{
IsExternal = content.IsExternal,
Id = content.Id,
EnContent = matchItem.TrackEnContent,
Content = matchItem.TrackContent,
Code = matchItem.TrackCode,
TrackPlace = matchItem.TrackPlace,
TrackTime = matchItem.TrackTime,
TrackTimeZone = matchItem.TrackTimeZone,
Source = matchItem.Source,
DestinationTimeZone = matchItem.DestinationTimeZone,
EstimatedDeliveryDate = matchItem.EstimatedDeliveryDate,
TrackPlacePostcode = matchItem.TrackPlacePostcode,
TrackPlaceNation = matchItem.TrackPlaceNation,
TrackPlaceNationId = matchItem.TrackPlaceNationId,
TrackPlaceProvince = matchItem.TrackPlaceProvince,
TrackPlaceProvinceId = matchItem.TrackPlaceProvinceId,
TrackPlaceCity = matchItem.TrackPlaceCity,
TrackPlaceCityId = matchItem.TrackPlaceCityId,
Remarks = matchItem.Remarks,
TrackTimeZoneValue = matchItem.DestinationTimeZone,
IsVisibility = matchItem.IsVisibility,
FileItems = matchItem.Files?.Select(x => new FileItemDto
{
FileName = x.FileName,
OssKey = x.OssKey
}).ToList()
});
matchContent.AddRange(match);
}
res.Data = matchContent;
return res;
}
#region 私有方法
private async Task<UnifyResultDto> AddAsync(EditTrackContentInput input)
{
#region 业务逻辑校验
var trackContentEntitys = await _trackContentRepository.GetListAsync(a =>
a.SubSystemId == input.SubSystemId && (a.Code == input.Code ||
a.Content == input.Content || a.EnContent == input.EnContent));
if (trackContentEntitys.Any())
{
var codes = trackContentEntitys.FirstOrDefault(a => a.Code == input.Code);
if (codes != null)
{
throw new BusinessException(message: "该子系统下轨迹代码已存在");
}
var contents = trackContentEntitys.FirstOrDefault(a => a.Content == input.Content);
if (contents != null)
{
throw new BusinessException(message: "该子系统下轨迹内容已存在");
}
var contentEns = trackContentEntitys.FirstOrDefault(a => a.EnContent == input.EnContent);
if (contentEns != null)
{
throw new BusinessException(message: "该子系统下轨迹内容英文已存在");
}
}
#endregion 业务逻辑校验
var entity = ObjectMapper.Map<EditTrackContentInput, TrackContentEntity>(input);
entity.TrackFlagId = input.TrackFlagIds?.JoinAsString(",");
var isTrue = await _trackContentRepository.InsertAsync(entity);
return new UnifyResultDto(GlobalConst.SuccessCode, "新增成功", isTrue);
}
private async Task<UnifyResultDto> UpdateAsync(EditTrackContentInput input)
{
#region 业务逻辑校验
var trackContentEntities = await _trackContentRepository.GetListAsync(
a => a.Id != input.Id && a.SubSystemId == input.SubSystemId &&
(a.Code == input.Code || a.Content == input.Content || a.EnContent == input.EnContent));
if (trackContentEntities.Any())
{
var codes = trackContentEntities.FirstOrDefault(a => a.Code == input.Code);
if (codes != null)
{
throw new BusinessException(message: "该子系统下轨迹代码已存在");
}
var contents = trackContentEntities.FirstOrDefault(a => a.Content == input.Content);
if (contents != null)
{
throw new BusinessException(message: "该子系统下轨迹内容已存在");
}
var contentEns = trackContentEntities.FirstOrDefault(a => a.EnContent == input.EnContent);
if (contentEns != null)
{
throw new BusinessException(message: "该子系统下轨迹内容英文已存在");
}
}
#endregion 业务逻辑校验
//更新的时候需要覆盖内容映射轨迹代码
var trackContent = await _trackContentRepository.GetFirstAsync(a => a.Id == input.Id);
if (trackContent == null)
{
throw new BusinessException(message: "轨迹内容不存在");
}
bool isTrue;
using (var ts = TransactionScopeHelper.Create())
{
// 如果轨迹内容的子系统和code发生变化,同步到轨迹映射表
if (trackContent.SubSystemId != input.SubSystemId || trackContent.Code != input.Code)
{
await _trackContentRepository.UpdateMapAsync(
x => new TrackContentMapEntity
{
SubSystemId = input.SubSystemId,
TrackContentCode = input.Code
},
x => x.TrackContentId == input.Id);
await _trackContentRepository.UpdateMapAsync(
x => new TrackContentMapEntity
{
MapSubSystemId = input.SubSystemId,
MapTrackContentCode = input.Code
}, x => x.MapTrackContentId == input.Id);
}
ObjectMapper.Map(input, trackContent);
trackContent.TrackFlagId = input.TrackFlagIds?.JoinAsString(",");
isTrue = await _trackContentRepository.UpdateAsync(trackContent);
ts.Complete();
}
return new UnifyResultDto(GlobalConst.SuccessCode, "修改成功", isTrue);
}
private async Task<UnifyResultDto> DeleteAsync(EditTrackContentInput input)
{
#region 业务校验
//查询是否关联了轨迹模版内容
var isExistTemplate = await _trackContentRepository.GetTemplateIsExist(input.Id);
if (isExistTemplate)
{
throw new BusinessException(message: "该轨迹内容关联轨迹模板,禁止删除");
}
//var trackTemplateContents = await _trackTemplateContentBasicQuery.GetListAsync(a => a.TrackContentId == input.Id);
//if (trackTemplateContents.Any())
//{
// throw new BusinessException(message: "该轨迹内容关联轨迹模板,禁止删除");
//}
//需要加个判断,存在内容映射,则出提示
//var trackContentMapEntities = await _trackContentMapBasicQuery.GetListAsync(a => a.TrackContentId == input.Id || a.MapTrackContentId == input.Id);
//if (trackContentMapEntities.Any())
//{
// throw new BusinessException(message: "无法删除该内容,该轨迹内容已在轨迹内容映射中使用了,请检查");
//}
#endregion 业务校验
var isTrue = await _trackContentRepository.SoftDeleteAsync(x => x.Id == input.Id);
return new UnifyResultDto(GlobalConst.SuccessCode, "删除成功", isTrue);
}
#endregion 私有方法
}