admin/src/Oms.Application/Services/Channels/ServiceChannelService.cs
2026-04-15 15:25:38 +08:00

292 lines
11 KiB
C#

using System.Linq.Expressions;
using Fake.Application;
using Microsoft.AspNetCore.Mvc;
using Oms.Application.Dtos.Channels;
using Oms.Application.Dtos.Shared;
using Oms.Application.Shared;
using Oms.Domain.ChannelsAggregate.Entities;
using Oms.Domain.ChannelsAggregate.Repositories;
namespace Oms.Application.Services.Channels;
[ApiExplorerSettings(GroupName = "OMS-Channel")]
public partial class ServiceChannelService : ApplicationService
{
private const string PriceOperatorType = "price";
private const string RulesOperatorType = "rules";
private IServiceChannelRepository ServiceChannelRepository => LazyServiceProvider.GetRequiredService<IServiceChannelRepository>();
/// <summary>
/// 获取服务渠道分页列表。
/// </summary>
[HttpGet("/channel/service-channel/list")]
public async Task<OmsPageResult<ServiceChannelListOutput>> GetListAsync([FromQuery] ServiceChannelListInput input)
{
var predicate = BuildListPredicate(input);
var pageIndex = OmsDocHelper.NormalizePage(input.Page);
var pageSize = OmsDocHelper.NormalizePageSize(input.PageSize);
var entities = await ServiceChannelRepository.GetPagedListAsync(
predicate,
pageIndex,
pageSize,
new Dictionary<string, bool> { [nameof(ServiceChannel.UpdateTime)] = false, [nameof(ServiceChannel.Id)] = false });
var total = await ServiceChannelRepository.CountAsync(predicate);
var groupMap = await GetGroupMapAsync();
return new OmsPageResult<ServiceChannelListOutput>
{
Items = entities.Select(entity => MapListOutput(entity, groupMap)).ToList(),
Total = total
};
}
/// <summary>
/// 获取服务渠道详情。
/// </summary>
[HttpGet("/channel/service-channel/detail")]
public async Task<ServiceChannelDetailOutput> GetDetailAsync([FromQuery] long id)
{
var entity = await GetEntityOrThrowAsync(id);
return MapDetailOutput(entity, await GetGroupMapAsync());
}
/// <summary>
/// 新增服务渠道。
/// </summary>
[HttpPost("/channel/service-channel/create")]
public async Task CreateAsync(ServiceChannelSaveInput input)
{
await ValidateChannelCodeAsync(input.ChannelCode, null);
var entity = new ServiceChannel
{
IsDeleted = false,
CreateTime = DateTime.Now,
CreateUserId = CurrentUser.GetId<int>()
};
ApplyInput(entity, input);
await ServiceChannelRepository.InsertAsync(entity);
}
/// <summary>
/// 更新服务渠道。
/// </summary>
[HttpPost("/channel/service-channel/update")]
public async Task UpdateAsync(ServiceChannelSaveInput input)
{
var entity = await GetEntityOrThrowAsync(input.Id);
await ValidateChannelCodeAsync(input.ChannelCode, entity.Id);
ApplyInput(entity, input);
entity.UpdateTime = DateTime.Now;
entity.UpdateUserId = CurrentUser.GetId<int>();
await ServiceChannelRepository.UpdateAsync(entity);
}
/// <summary>
/// 删除服务渠道。
/// </summary>
[HttpPost("/channel/service-channel/delete")]
public async Task DeleteAsync(IdInput input)
{
var entity = await GetEntityOrThrowAsync(input.Id);
entity.IsDeleted = true;
entity.UpdateTime = DateTime.Now;
entity.UpdateUserId = CurrentUser.GetId<int>();
await ServiceChannelRepository.UpdateAsync(entity);
}
/// <summary>
/// 保存服务渠道配置。
/// </summary>
[HttpPost("/channel/service-channel/config/save")]
public async Task SaveConfigAsync(ServiceChannelSaveInput input)
{
var entity = await GetEntityOrThrowAsync(input.Id);
await ValidateChannelCodeAsync(input.ChannelCode, entity.Id);
ApplyInput(entity, input);
entity.UpdateTime = DateTime.Now;
entity.UpdateUserId = CurrentUser.GetId<int>();
await ServiceChannelRepository.UpdateAsync(entity);
}
/// <summary>
/// 获取服务渠道买价项列表。
/// </summary>
[HttpGet("/channel/service-channel/price/list")]
public async Task<OmsItemsResult<ServiceChannelPriceListOutput>> GetPriceListAsync([FromQuery] long serviceChannelId)
{
await GetEntityOrThrowAsync(serviceChannelId);
return new OmsItemsResult<ServiceChannelPriceListOutput>
{
Items = await GetPriceOutputsAsync(serviceChannelId)
};
}
/// <summary>
/// 新增服务渠道买价项。
/// </summary>
[HttpPost("/channel/service-channel/price/create")]
public async Task CreatePriceAsync(ServiceChannelPriceSaveInput input)
{
await GetEntityOrThrowAsync(input.ServiceChannelId);
var now = DateTime.Now;
var userId = CurrentUser.GetId<int>();
await ServiceChannelRepository.InsertPriceAsync(
new ServiceChannelPrice
{
ServiceChannelId = input.ServiceChannelId,
SerialNumber = input.SerialNumber,
Status = input.Status,
PriceName = input.PriceName,
CostItem = input.CostItem,
CostUnit = input.CostUnit,
Currency = input.Currency,
ChargingTime = input.ChargingTime,
ChargingCondition = input.ChargingCondition,
IsDeleted = false,
CreateTime = now,
CreateUserId = userId
},
BuildPriceFactors(input.Factors, now, userId),
BuildPriceDetails(input.Details, now, userId));
}
/// <summary>
/// 更新服务渠道买价项。
/// </summary>
[HttpPost("/channel/service-channel/price/update")]
public async Task UpdatePriceAsync(ServiceChannelPriceSaveInput input)
{
var price = await GetPriceOrThrowAsync(input.Id);
if (price.ServiceChannelId != input.ServiceChannelId)
{
throw new BusinessException("买价项归属不匹配");
}
price.SerialNumber = input.SerialNumber;
price.Status = input.Status;
price.PriceName = input.PriceName;
price.CostItem = input.CostItem;
price.CostUnit = input.CostUnit;
price.Currency = input.Currency;
price.ChargingTime = input.ChargingTime;
price.ChargingCondition = input.ChargingCondition;
price.UpdateTime = DateTime.Now;
price.UpdateUserId = CurrentUser.GetId<int>();
await ServiceChannelRepository.UpdatePriceAsync(
price,
BuildPriceFactors(input.Factors, DateTime.Now, CurrentUser.GetId<int>()),
BuildPriceDetails(input.Details, DateTime.Now, CurrentUser.GetId<int>()));
}
/// <summary>
/// 删除服务渠道买价项。
/// </summary>
[HttpPost("/channel/service-channel/price/delete")]
public async Task DeletePriceAsync(IdInput input)
{
await GetPriceOrThrowAsync(input.Id);
await ServiceChannelRepository.DeletePriceAsync(input.Id);
}
/// <summary>
/// 切换服务渠道买价项状态。
/// </summary>
[HttpPost("/channel/service-channel/price/toggleStatus")]
public async Task TogglePriceStatusAsync(ToggleStatusInput input)
{
await GetPriceOrThrowAsync(input.Id);
await ServiceChannelRepository.UpdatePriceStatusAsync(input.Id, input.Status);
}
/// <summary>
/// 批量保存服务渠道买价项。
/// </summary>
[HttpPost("/channel/service-channel/price/save")]
public async Task SavePriceAsync(ServiceChannelPriceSaveAllInput input)
{
await GetEntityOrThrowAsync(input.ServiceChannelId);
var now = DateTime.Now;
var userId = CurrentUser.GetId<int>();
var prices = new List<ServiceChannelPrice>();
var factors = new List<ServiceChannelPriceFactor>();
var details = new List<ServiceChannelPriceDetail>();
var tempId = -1L;
// 使用临时负数 Id 保持买价项与子表数据在批量替换时的关联关系。
foreach (var priceInput in input.Prices.OrderBy(x => x.SerialNumber))
{
var currentTempId = tempId--;
prices.Add(new ServiceChannelPrice
{
Id = currentTempId,
ServiceChannelId = input.ServiceChannelId,
SerialNumber = priceInput.SerialNumber,
Status = priceInput.Status,
PriceName = priceInput.PriceName,
CostItem = priceInput.CostItem,
CostUnit = priceInput.CostUnit,
Currency = priceInput.Currency,
ChargingTime = priceInput.ChargingTime,
ChargingCondition = priceInput.ChargingCondition,
IsDeleted = false,
CreateTime = now,
CreateUserId = userId
});
factors.AddRange(BuildPriceFactors(priceInput.Factors, now, userId, currentTempId));
details.AddRange(BuildPriceDetails(priceInput.Details, now, userId, currentTempId));
}
await ServiceChannelRepository.ReplacePricesAsync(input.ServiceChannelId, prices, factors, details);
if (input.Publish)
{
await CreatePublishRecordAsync(input.ServiceChannelId, PriceOperatorType, "保存并发布买价");
}
}
/// <summary>
/// 获取服务渠道价格发布记录。
/// </summary>
[HttpGet("/channel/service-channel/publish/price/list")]
public Task<OmsPageResult<ServiceChannelPublishRecordOutput>> GetPricePublishListAsync([FromQuery] ServiceChannelPublishListInput input)
{
return GetPublishListAsync(input, PriceOperatorType);
}
/// <summary>
/// 获取服务渠道规则发布记录。
/// </summary>
[HttpGet("/channel/service-channel/publish/rules/list")]
public Task<OmsPageResult<ServiceChannelPublishRecordOutput>> GetRulesPublishListAsync([FromQuery] ServiceChannelPublishListInput input)
{
return GetPublishListAsync(input, RulesOperatorType);
}
/// <summary>
/// 发布当前服务渠道配置。
/// </summary>
[HttpPost("/channel/service-channel/publish")]
public async Task PublishAsync(ServiceChannelPublishInput input)
{
await CreatePublishRecordAsync(input.ServiceChannelId, NormalizeOperatorType(input.OperatorType), input.Description);
}
/// <summary>
/// 按发布记录回滚服务渠道配置。
/// </summary>
[HttpPost("/channel/service-channel/publish/rollback")]
public Task RollbackAsync(ServiceChannelRollbackInput input)
{
return RollbackCoreAsync(input);
}
private static Expression<Func<ServiceChannel, bool>> BuildListPredicate(ServiceChannelListInput input)
{
var keyword = input.Keyword?.Trim();
return entity =>
!entity.IsDeleted &&
(!input.GroupId.HasValue || entity.GroupId == input.GroupId.Value) &&
(string.IsNullOrWhiteSpace(keyword) || entity.ChannelCode.Contains(keyword) || entity.ChannelName.Contains(keyword)) &&
(!input.IsActive.HasValue || entity.IsActive == input.IsActive.Value);
}
}