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;
///
/// 轨迹内容服务
///
[ApiExplorerSettings(GroupName = "轨迹内容")]
[Route("/Track/Content")]
public class TrackContentService : ApplicationService
{
private readonly IStringLocalizer _stringLocalizer;
private readonly ITrackContentRepository _trackContentRepository;
private readonly ITrackTemplateRepository _trackTemplateRepository;
private readonly IBasicQuery _trackFlagBasicQuery;
private readonly IBasicQuery _trackStatusBasicQuery;
private readonly IOrderRepository _orderRepository;
private readonly ITrackDetailsEsRepository _trackDetailsEsRepository;
private readonly ITrackPushCacheService _trackPushCacheService;
public TrackContentService(
IStringLocalizer stringLocalizer,
ITrackContentRepository trackContentRepository,
IBasicQuery trackStatusBasicQuery,
IBasicQuery 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;
}
///
/// 轨迹内容编辑
///
///
[HttpPost("Edit")]
public async Task 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: "当前操作动作不合法")
};
}
///
/// 根据内容id获取轨迹内容
///
///
///
[HttpGet("GetDetail")]
public async Task> GetDetailAsync(int id)
{
var detailInfo = await _trackContentRepository.GetDetailAsync(id);
if (detailInfo == null)
{
return new UnifyResultDto(false, null!, "未查询到轨迹状态");
}
var dto = ObjectMapper.Map(detailInfo);
return new UnifyResultDto(GlobalConst.SuccessCode, "", dto);
}
///
/// 获取分页轨迹内容
///
///
///
[HttpPost("GetList")]
public async Task> GetPageTrackContent(GetPageTrackContentInput input)
{
var vo = ObjectMapper.Map(input);
var resultDto = await _trackContentRepository.GetPageTrackContent(vo);
var pageResultDto =
ObjectMapper.Map, UnifyPageResultDto>(
resultDto);
return pageResultDto;
}
///
/// 轨迹内容映射列表
///
///
///
[HttpPost("GetMapPage")]
public async Task> GetMapPageAsync(
[FromBody] GetTrackContentMapPageInputVO input)
{
return await _trackContentRepository.GetMapPageAsync(input);
}
///
/// 轨迹内容映射详情
///
///
///
[HttpGet("GetMapDetail")]
public async Task GetMapDetailAsync(int id)
{
return await _trackContentRepository.GetMapDetailAsync(id);
}
///
/// 轨迹内容映射编辑
///
///
///
[HttpPost("EditMap")]
public async Task EditMapAsync([FromBody] EditTrackContentMapInput input)
{
if (input.Options != OptionTypeNoNull.删除)
{
if (input.SubSystemId == input.MapSubSystemId)
throw new BusinessException(message: _stringLocalizer["NotAllowedToMapSubSystem"]);
Expression> 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(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;
}
///
/// 根据轨迹内容code获取轨迹内容
///
///
///
[HttpPost("GetTrackContentByCode")]
public async Task> GetTrackContentByCodeAsync([FromBody] GetTrackContentByCodeInput input)
{
if (input.SystemId <= 0)
return new UnifyResultDto(false, "子系统Id必须大于等于0");
if (string.IsNullOrEmpty(input.Code))
return new UnifyResultDto(false, "轨迹内容code不能为空");
var content = await _trackContentRepository.GetByCodeAsync(input.SystemId, input.Code);
if (content == null)
return new UnifyResultDto(false, "在当前子系统中未找到指定code的轨迹内容");
var res = new UnifyResultDto(true)
{
Data = new GetTrackContentByCodeOutput
{
Content = content.Content,
EnContent = content.EnContent,
IsExternal = content.IsExternal
}
};
return res;
}
///
/// 根据子系统id、单号、订单类型、轨迹发生时间、轨迹code获取轨迹内容
///
///
///
[HttpPost("GetContentDetail")]
public async Task> GetContentDetail([FromBody] GetContentDetailInput input)
{
if (input.SystemId <= 0)
return new UnifyResultDto(false, "子系统Id必须大于等于0");
if (string.IsNullOrEmpty(input.TrackCode))
return new UnifyResultDto(false, "轨迹内容code不能为空");
if (string.IsNullOrEmpty(input.OrderNumber))
return new UnifyResultDto(false, "订单code不能为空");
if (input.OrderType <= 0)
return new UnifyResultDto(false, "订单类型不能为空");
if (input.TrackTime == default)
return new UnifyResultDto(false, "轨迹发生时间不能为空");
var content = await _trackDetailsEsRepository.GetDetailAsync(input.OrderNumber, input.TrackCode, input.OrderType, input.SystemId, input.TrackTime);
if (content == default)
return new UnifyResultDto(false, "在当前子系统中未找到指定code的轨迹内容");
var res = new UnifyResultDto(true)
{
Data = ObjectMapper.Map(content)
};
if (res.Data != null && res.Data.Files?.Count > 0)
{
var ossKeys = res.Data.Files
.Where(x => !string.IsNullOrWhiteSpace(x.OssKey))
.Select(x => x.OssKey)
.ToArray();
if (ossKeys.Length == 0) return res;
var ossKeyUrlDict = OSSHelper.GetUrlByKeys(ossKeys);
foreach (var item in res.Data.Files)
{
if (string.IsNullOrWhiteSpace(item.OssKey)) continue;
item.Url = ossKeyUrlDict.GetValueOrDefault(item.OssKey)!;
}
}
return res;
}
///
/// 创建轨迹时获取可用的轨迹内容
///
///
///
[HttpPost("GetAvailableContent")]
public async Task>> GetAvailableContent(GetAvailableContentInput input)
{
if (input.SystemId <= 0)
return new UnifyResultDto>(false, "系统id需大于0!");
if (string.IsNullOrEmpty(input.OrderNo))
return new UnifyResultDto>(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>(true)
{
Data = new List()
};
//获取轨迹详情
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();
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 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(input);
entity.TrackFlagId = input.TrackFlagIds?.JoinAsString(",");
var isTrue = await _trackContentRepository.InsertAsync(entity);
return new UnifyResultDto(GlobalConst.SuccessCode, "新增成功", isTrue);
}
private async Task 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 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 私有方法
}