feat: 同一产品/渠道下卖价买价费用项唯一,禁止重复新增
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
1b6e91b09d
commit
79099776a5
@ -388,10 +388,11 @@ public partial class SalesProductService
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 保险/偏远费等附加费用项的计费条件校验。
|
/// 保险/偏远费等附加费用项的计费条件校验;同一提交批次内费用项不可重复。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static void ValidateBillingPriceItemRules(IReadOnlyList<SalesProductPriceSaveInput> prices)
|
private static void ValidateBillingPriceItemRules(IReadOnlyList<SalesProductPriceSaveInput> prices)
|
||||||
{
|
{
|
||||||
|
EnsureUniqueCostItemsInBatch(prices.Select(x => x.CostItem));
|
||||||
foreach (var price in prices)
|
foreach (var price in prices)
|
||||||
{
|
{
|
||||||
var costItem = price.CostItem?.Trim() ?? string.Empty;
|
var costItem = price.CostItem?.Trim() ?? string.Empty;
|
||||||
@ -417,6 +418,44 @@ public partial class SalesProductService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 同一销售产品下每种费用项只能有一条卖价配置。
|
||||||
|
/// </summary>
|
||||||
|
private async Task EnsureCostItemUniqueAsync(int salesProductId, string? costItem, int? excludePriceId)
|
||||||
|
{
|
||||||
|
var trimmed = costItem?.Trim() ?? string.Empty;
|
||||||
|
if (string.IsNullOrWhiteSpace(trimmed))
|
||||||
|
{
|
||||||
|
throw new Fake.Application.BusinessException("费用项不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
var existing = await SalesProductRepository.GetPricesAsync(salesProductId);
|
||||||
|
var duplicated = existing.Any(p =>
|
||||||
|
(!excludePriceId.HasValue || p.Id != excludePriceId.Value)
|
||||||
|
&& string.Equals(p.CostItem?.Trim(), trimmed, StringComparison.OrdinalIgnoreCase));
|
||||||
|
if (duplicated)
|
||||||
|
{
|
||||||
|
throw new Fake.Application.BusinessException(
|
||||||
|
$"该产品已存在费用项「{trimmed}」,同一产品下每种费用项只能有一条");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void EnsureUniqueCostItemsInBatch(IEnumerable<string?> costItems)
|
||||||
|
{
|
||||||
|
var duplicates = costItems
|
||||||
|
.Select(x => x?.Trim() ?? string.Empty)
|
||||||
|
.Where(x => !string.IsNullOrWhiteSpace(x))
|
||||||
|
.GroupBy(x => x, StringComparer.OrdinalIgnoreCase)
|
||||||
|
.Where(g => g.Count() > 1)
|
||||||
|
.Select(g => g.Key)
|
||||||
|
.ToList();
|
||||||
|
if (duplicates.Count > 0)
|
||||||
|
{
|
||||||
|
throw new Fake.Application.BusinessException(
|
||||||
|
$"同一产品下费用项不能重复:{string.Join("、", duplicates)}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static string? NormalizeAdditionalServices(string? raw)
|
private static string? NormalizeAdditionalServices(string? raw)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(raw))
|
if (string.IsNullOrWhiteSpace(raw))
|
||||||
|
|||||||
@ -159,6 +159,7 @@ public partial class SalesProductService : ApplicationService
|
|||||||
{
|
{
|
||||||
await GetProductOrThrowAsync(input.SalesProductId);
|
await GetProductOrThrowAsync(input.SalesProductId);
|
||||||
ValidateBillingPriceItemRules([input]);
|
ValidateBillingPriceItemRules([input]);
|
||||||
|
await EnsureCostItemUniqueAsync(input.SalesProductId, input.CostItem, excludePriceId: null);
|
||||||
await SalesProductRepository.InsertPriceAsync(
|
await SalesProductRepository.InsertPriceAsync(
|
||||||
new SalesProductPrice
|
new SalesProductPrice
|
||||||
{
|
{
|
||||||
@ -190,6 +191,7 @@ public partial class SalesProductService : ApplicationService
|
|||||||
}
|
}
|
||||||
|
|
||||||
ValidateBillingPriceItemRules([input]);
|
ValidateBillingPriceItemRules([input]);
|
||||||
|
await EnsureCostItemUniqueAsync(input.SalesProductId, input.CostItem, excludePriceId: price.Id);
|
||||||
price.SerialNumber = input.SerialNumber;
|
price.SerialNumber = input.SerialNumber;
|
||||||
price.Status = input.Status;
|
price.Status = input.Status;
|
||||||
price.PriceName = input.PriceName;
|
price.PriceName = input.PriceName;
|
||||||
|
|||||||
@ -329,10 +329,11 @@ public partial class ServiceChannelService
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 买价偏远费等附加费用项的计费条件校验。
|
/// 买价偏远费等附加费用项的计费条件校验;同一提交批次内费用项不可重复。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static void ValidateBillingPriceItemRules(IReadOnlyList<ServiceChannelPriceSaveInput> prices)
|
private static void ValidateBillingPriceItemRules(IReadOnlyList<ServiceChannelPriceSaveInput> prices)
|
||||||
{
|
{
|
||||||
|
EnsureUniqueCostItemsInBatch(prices.Select(x => x.CostItem));
|
||||||
foreach (var price in prices)
|
foreach (var price in prices)
|
||||||
{
|
{
|
||||||
var costItem = price.CostItem?.Trim() ?? string.Empty;
|
var costItem = price.CostItem?.Trim() ?? string.Empty;
|
||||||
@ -349,6 +350,44 @@ public partial class ServiceChannelService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 同一服务渠道下每种费用项只能有一条买价配置。
|
||||||
|
/// </summary>
|
||||||
|
private async Task EnsureCostItemUniqueAsync(int serviceChannelId, string? costItem, int? excludePriceId)
|
||||||
|
{
|
||||||
|
var trimmed = costItem?.Trim() ?? string.Empty;
|
||||||
|
if (string.IsNullOrWhiteSpace(trimmed))
|
||||||
|
{
|
||||||
|
throw new Fake.Application.BusinessException("费用项不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
var existing = await ServiceChannelRepository.GetPricesAsync(serviceChannelId);
|
||||||
|
var duplicated = existing.Any(p =>
|
||||||
|
(!excludePriceId.HasValue || p.Id != excludePriceId.Value)
|
||||||
|
&& string.Equals(p.CostItem?.Trim(), trimmed, StringComparison.OrdinalIgnoreCase));
|
||||||
|
if (duplicated)
|
||||||
|
{
|
||||||
|
throw new Fake.Application.BusinessException(
|
||||||
|
$"该渠道已存在费用项「{trimmed}」,同一渠道下每种费用项只能有一条");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void EnsureUniqueCostItemsInBatch(IEnumerable<string?> costItems)
|
||||||
|
{
|
||||||
|
var duplicates = costItems
|
||||||
|
.Select(x => x?.Trim() ?? string.Empty)
|
||||||
|
.Where(x => !string.IsNullOrWhiteSpace(x))
|
||||||
|
.GroupBy(x => x, StringComparer.OrdinalIgnoreCase)
|
||||||
|
.Where(g => g.Count() > 1)
|
||||||
|
.Select(g => g.Key)
|
||||||
|
.ToList();
|
||||||
|
if (duplicates.Count > 0)
|
||||||
|
{
|
||||||
|
throw new Fake.Application.BusinessException(
|
||||||
|
$"同一渠道下费用项不能重复:{string.Join("、", duplicates)}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static ServiceChannelGroupListOutput MapGroupListOutput(ServiceChannelGroup entity)
|
private static ServiceChannelGroupListOutput MapGroupListOutput(ServiceChannelGroup entity)
|
||||||
{
|
{
|
||||||
return new ServiceChannelGroupListOutput
|
return new ServiceChannelGroupListOutput
|
||||||
|
|||||||
@ -223,6 +223,7 @@ public partial class ServiceChannelService : ApplicationService
|
|||||||
{
|
{
|
||||||
await GetEntityOrThrowAsync(input.ServiceChannelId);
|
await GetEntityOrThrowAsync(input.ServiceChannelId);
|
||||||
ValidateBillingPriceItemRules([input]);
|
ValidateBillingPriceItemRules([input]);
|
||||||
|
await EnsureCostItemUniqueAsync(input.ServiceChannelId, input.CostItem, excludePriceId: null);
|
||||||
await ServiceChannelRepository.InsertPriceAsync(
|
await ServiceChannelRepository.InsertPriceAsync(
|
||||||
new ServiceChannelPrice
|
new ServiceChannelPrice
|
||||||
{
|
{
|
||||||
@ -254,6 +255,7 @@ public partial class ServiceChannelService : ApplicationService
|
|||||||
}
|
}
|
||||||
|
|
||||||
ValidateBillingPriceItemRules([input]);
|
ValidateBillingPriceItemRules([input]);
|
||||||
|
await EnsureCostItemUniqueAsync(input.ServiceChannelId, input.CostItem, excludePriceId: price.Id);
|
||||||
price.SerialNumber = input.SerialNumber;
|
price.SerialNumber = input.SerialNumber;
|
||||||
price.Status = input.Status;
|
price.Status = input.Status;
|
||||||
price.PriceName = input.PriceName;
|
price.PriceName = input.PriceName;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user