519 lines
22 KiB
C#
519 lines
22 KiB
C#
using Oms.Application.Dtos.Channels;
|
|
using Oms.Application.Dtos.Orders;
|
|
using Oms.Application.Dtos.Shared;
|
|
using Oms.Application.Shared;
|
|
using Oms.Domain.ChannelsAggregate.Consts;
|
|
using Oms.Domain.ChannelsAggregate.Entities;
|
|
using Oms.Domain.Shared;
|
|
using Oms.Domain.Shared.Enums;
|
|
|
|
namespace Oms.Application.Services.Channels;
|
|
|
|
public partial class SalesProductService
|
|
{
|
|
/// <summary>
|
|
/// 校验产品编码唯一性。
|
|
/// </summary>
|
|
private async Task ValidateProductCodeAsync(string productCode, int? id)
|
|
{
|
|
var existed = await SalesProductRepository.GetByProductCodeAsync(productCode);
|
|
if (existed != null && existed.Id != id)
|
|
{
|
|
throw new Fake.Application.BusinessException("产品编码已存在");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取销售产品,不存在时直接抛异常。
|
|
/// </summary>
|
|
private async Task<SalesProduct> GetProductOrThrowAsync(int? id)
|
|
{
|
|
if (!id.HasValue || id.Value <= 0)
|
|
{
|
|
throw new Fake.Application.BusinessException("销售产品不存在");
|
|
}
|
|
|
|
var entity = await SalesProductRepository.FirstOrDefaultAsync(x => x.Id == id.Value);
|
|
if (entity == null)
|
|
{
|
|
throw new Fake.Application.BusinessException("销售产品不存在");
|
|
}
|
|
|
|
return entity;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取价格项,不存在时直接抛异常。
|
|
/// </summary>
|
|
private async Task<SalesProductPrice> GetPriceOrThrowAsync(int? id)
|
|
{
|
|
if (!id.HasValue || id.Value <= 0)
|
|
{
|
|
throw new Fake.Application.BusinessException("价格项不存在");
|
|
}
|
|
|
|
var entity = await SalesProductRepository.GetPriceByIdAsync(id.Value);
|
|
if (entity == null)
|
|
{
|
|
throw new Fake.Application.BusinessException("价格项不存在");
|
|
}
|
|
|
|
return entity;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 一次性装配价格项、因子和明细,避免接口层 N+1 查询。
|
|
/// </summary>
|
|
private async Task<List<SalesProductPriceListOutput>> GetPriceOutputsAsync(int salesProductId)
|
|
{
|
|
var prices = await SalesProductRepository.GetPricesAsync(salesProductId);
|
|
var priceIds = prices.Select(x => x.Id).ToArray();
|
|
var factorMap = (await SalesProductRepository.GetPriceFactorsAsync(priceIds))
|
|
.GroupBy(x => x.PriceId)
|
|
.ToDictionary(x => x.Key, x => x.OrderBy(item => item.SerialNumber).ToList());
|
|
var detailMap = (await SalesProductRepository.GetPriceDetailsAsync(priceIds))
|
|
.GroupBy(x => x.PriceId)
|
|
.ToDictionary(x => x.Key, x => x.OrderBy(item => item.Id).ToList());
|
|
|
|
var auditUserNameMap = await UserDisplayNameResolver.ResolveManyAsync(
|
|
prices.SelectMany(x => new[] { x.CreateUserId, x.UpdateUserId }));
|
|
|
|
return prices.Select(price => new SalesProductPriceListOutput
|
|
{
|
|
Id = price.Id,
|
|
SalesProductId = price.SalesProductId,
|
|
SerialNumber = price.SerialNumber,
|
|
Status = (byte)price.Status,
|
|
PriceName = price.PriceName,
|
|
CostItem = price.CostItem,
|
|
CostUnit = price.CostUnit,
|
|
Currency = price.Currency,
|
|
ChargingCondition = price.ChargingCondition,
|
|
Factors = factorMap.TryGetValue(price.Id, out var factors) ? factors.Select(MapPriceFactorOutput).ToList() : [],
|
|
Details = detailMap.TryGetValue(price.Id, out var details) ? details.Select(MapPriceDetailOutput).ToList() : [],
|
|
CreateTime = price.CreateTime,
|
|
CreateBy = OmsRbacUserDisplayNameResolver.FormatUserId(price.CreateUserId, auditUserNameMap),
|
|
UpdateTime = OmsDocHelper.NullIfDefault(price.UpdateTime),
|
|
UpdateBy = OmsRbacUserDisplayNameResolver.FormatUserId(price.UpdateUserId, auditUserNameMap)
|
|
}).ToList();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取排货方案,并补充服务渠道名称。
|
|
/// </summary>
|
|
private async Task<SalesProductAllocationOutput> GetAllocationCoreAsync(int salesProductId)
|
|
{
|
|
var product = await GetProductOrThrowAsync(salesProductId);
|
|
var providers = await SalesProductRepository.GetAllocationProvidersAsync(salesProductId);
|
|
var channelIds = providers.Where(x => x.ServiceChannelId.HasValue).Select(x => x.ServiceChannelId!.Value).Distinct().ToArray();
|
|
var channels = channelIds.Length == 0
|
|
? []
|
|
: await ServiceChannelRepository.GetListAsync(x => channelIds.Contains(x.Id));
|
|
var channelMap = channels.ToDictionary(x => x.Id, x => x.ChannelName);
|
|
|
|
return new SalesProductAllocationOutput
|
|
{
|
|
SalesProductId = salesProductId,
|
|
Scheme = product.Scheme,
|
|
Providers = providers.Select(provider => new SalesProductAllocationProviderOutput
|
|
{
|
|
Id = provider.Id,
|
|
SalesProductId = provider.SalesProductId,
|
|
SerialNumber = provider.SerialNumber,
|
|
ProviderName = provider.ProviderName,
|
|
ServiceChannelId = provider.ServiceChannelId,
|
|
ServiceChannelName = provider.ServiceChannelId.HasValue && channelMap.TryGetValue(provider.ServiceChannelId.Value, out var name) ? name : null,
|
|
Weight = provider.Weight,
|
|
CustomerIds = OmsDocHelper.DeserializeJson<List<int>>(provider.CustomerIds) ?? [],
|
|
CreateTime = provider.CreateTime,
|
|
UpdateTime = OmsDocHelper.NullIfDefault(provider.UpdateTime)
|
|
}).ToList()
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取指定类型的发布记录。
|
|
/// </summary>
|
|
private async Task<OmsPageResult<SalesProductPublishRecordOutput>> GetPublishListAsync(SalesProductPublishListInput input, string operatorType)
|
|
{
|
|
await GetProductOrThrowAsync(input.SalesProductId);
|
|
var pageIndex = OmsDocHelper.NormalizePage(input.Page);
|
|
var pageSize = OmsDocHelper.NormalizePageSize(input.PageSize);
|
|
var entities = await SalesProductRepository.GetPublishRecordsAsync(input.SalesProductId, operatorType, pageIndex, pageSize);
|
|
var total = await SalesProductRepository.CountPublishRecordsAsync(input.SalesProductId, operatorType);
|
|
return new OmsPageResult<SalesProductPublishRecordOutput>
|
|
{
|
|
Items = entities.Select(entity => new SalesProductPublishRecordOutput
|
|
{
|
|
Id = entity.Id,
|
|
SalesProductId = entity.SalesProductId,
|
|
Version = entity.Version,
|
|
OperatorType = entity.OperatorType,
|
|
Status = EnumDisplayNames.Of(entity.Status),
|
|
PublishUser = entity.PublishUser,
|
|
PublishTime = entity.PublishTime,
|
|
Description = entity.Description,
|
|
Content = operatorType == PriceOperatorType
|
|
? OmsDocHelper.ParseSalesProductPricePublishContentForApi(entity.Content)
|
|
: OmsDocHelper.ToSnapshotApiContent(OmsDocHelper.DeserializeRulesSnapshot(entity.Content)),
|
|
CreateTime = entity.CreateTime
|
|
}).ToList(),
|
|
Total = total
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// 组装规则发布快照(不落库),含黑名单/偏远/计重/进位明细。
|
|
/// </summary>
|
|
private async Task<SalesProductRulesPublishSnapshotDto> BuildRulesPublishSnapshotAsync(int salesProductId)
|
|
{
|
|
var product = await GetProductOrThrowAsync(salesProductId);
|
|
var rulesSnapshot = new SalesProductRulesPublishSnapshot
|
|
{
|
|
Product = MapProductToRulesSaveInput(product),
|
|
Providers = (await GetAllocationCoreAsync(salesProductId)).Providers
|
|
.Select(PublishSnapshotSlimmer.SlimAllocationProvider)
|
|
.ToList()
|
|
};
|
|
await RulesSnapshotHelper.ApplyRulesToSnapshotAsync(
|
|
rulesSnapshot,
|
|
product,
|
|
KpiAreaRepository,
|
|
WeightRuleRepository,
|
|
WeightRoundingRepository);
|
|
await AllocationProviderSnapshotEnricher.EnrichAsync(rulesSnapshot.Providers);
|
|
return rulesSnapshot;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 组装价格发布快照(不落库)。
|
|
/// </summary>
|
|
private async Task<SalesProductPricePublishSnapshotDto> BuildPricePublishSnapshotAsync(int salesProductId)
|
|
{
|
|
var product = await GetProductOrThrowAsync(salesProductId);
|
|
var priceSnapshot = new SalesProductPricePublishSnapshot
|
|
{
|
|
SalesProductId = salesProductId,
|
|
Prices = (await GetPriceOutputsAsync(salesProductId)).Select(PublishSnapshotSlimmer.SlimPrice).ToList()
|
|
};
|
|
await PriceAreaSnapshotHelper.ApplyPriceAreaToSnapshotAsync(priceSnapshot, product, KpiAreaRepository);
|
|
return priceSnapshot;
|
|
}
|
|
|
|
private static SalesProductSaveInput MapProductToRulesSaveInput(SalesProduct product) =>
|
|
new()
|
|
{
|
|
Id = product.Id,
|
|
ProductCode = product.ProductCode,
|
|
ProductName = product.ProductName,
|
|
ProductGroup = product.ProductGroup,
|
|
MinTimeliness = product.MinTimeliness,
|
|
MaxTimeliness = product.MaxTimeliness,
|
|
CustomerWaybill = product.CustomerWaybill,
|
|
LabelTemplateId = product.LabelTemplateId,
|
|
BlacklistAreaId = product.BlacklistAreaId,
|
|
RemoteAreaId = product.RemoteAreaId,
|
|
PriceAreaId = product.PriceAreaId,
|
|
WeightRuleId = product.WeightRuleId,
|
|
WeightRoundingId = product.WeightRoundingId,
|
|
ProductDescription = product.ProductDescription,
|
|
PreStorageScript = product.PreStorageScript,
|
|
CustomerGuideMarkdown = product.CustomerGuideMarkdown,
|
|
IsActive = product.IsActive,
|
|
Scheme = product.Scheme
|
|
};
|
|
|
|
/// <summary>
|
|
/// 为当前配置生成发布快照。
|
|
/// </summary>
|
|
private async Task CreatePublishRecordAsync(int salesProductId, string operatorType, string? description)
|
|
{
|
|
object snapshot = operatorType == PriceOperatorType
|
|
? await BuildPricePublishSnapshotAsync(salesProductId)
|
|
: await BuildRulesPublishSnapshotAsync(salesProductId);
|
|
|
|
// Content 中保存完整快照,回滚时直接从快照恢复,避免依赖当前库内状态。
|
|
await SalesProductRepository.InsertPublishRecordAsync(new SalesProductPublishRecord
|
|
{
|
|
SalesProductId = salesProductId,
|
|
Version = DateTime.Now.ToString("yyyyMMddHHmmss"),
|
|
OperatorType = operatorType,
|
|
Status = EsSnapshotStatus.Active,
|
|
PublishUser = string.IsNullOrWhiteSpace(CurrentUser.UserName) ? CurrentUser.GetId<int>().ToString() : CurrentUser.UserName!,
|
|
PublishTime = DateTime.Now,
|
|
Description = description,
|
|
Content = OmsDocHelper.SerializeSnapshotJson(snapshot)
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// 按发布记录回滚价格或规则配置。
|
|
/// </summary>
|
|
private async Task RollbackCoreAsync(SalesProductRollbackInput input)
|
|
{
|
|
var operatorType = NormalizeOperatorType(input.OperatorType);
|
|
await GetProductOrThrowAsync(input.SalesProductId);
|
|
var record = await SalesProductRepository.GetPublishRecordByIdAsync(input.RecordId);
|
|
if (record == null || record.SalesProductId != input.SalesProductId || !string.Equals(record.OperatorType, operatorType, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
throw new Fake.Application.BusinessException("发布记录不存在");
|
|
}
|
|
|
|
if (operatorType == PriceOperatorType)
|
|
{
|
|
var snapshot = OmsDocHelper.DeserializePriceSnapshot(record.Content);
|
|
if (snapshot == null)
|
|
{
|
|
throw new Fake.Application.BusinessException("发布快照无效");
|
|
}
|
|
|
|
// 价格回滚直接恢复完整价格树。
|
|
await SavePriceAsync(new SalesProductPriceSaveAllInput
|
|
{
|
|
SalesProductId = input.SalesProductId,
|
|
Prices = snapshot.Prices.Select(price => MapPriceSaveInput(price, input.SalesProductId)).ToList()
|
|
});
|
|
return;
|
|
}
|
|
|
|
var rulesSnapshot = OmsDocHelper.DeserializeRulesSnapshot(record.Content);
|
|
if (rulesSnapshot == null)
|
|
{
|
|
throw new Fake.Application.BusinessException("发布快照无效");
|
|
}
|
|
|
|
// 规则回滚既恢复产品配置,也恢复排货服务商列表。
|
|
var product = await GetProductOrThrowAsync(input.SalesProductId);
|
|
if (rulesSnapshot.Product == null)
|
|
{
|
|
throw new Fake.Application.BusinessException("发布快照缺少产品配置");
|
|
}
|
|
|
|
ApplyProductInput(product, rulesSnapshot.Product);
|
|
await SalesProductRepository.UpdateAsync(product);
|
|
|
|
var providers = rulesSnapshot.Providers.Select(provider => new SalesProductAllocationProvider
|
|
{
|
|
SalesProductId = input.SalesProductId,
|
|
SerialNumber = provider.SerialNumber,
|
|
ProviderName = provider.ProviderName,
|
|
ServiceChannelId = provider.ServiceChannelId,
|
|
Weight = provider.Weight,
|
|
CustomerIds = OmsDocHelper.SerializeJson(provider.CustomerIds)
|
|
}).ToList();
|
|
await SalesProductRepository.ReplaceAllocationProvidersAsync(input.SalesProductId, providers);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 将保存入参映射到销售产品实体。
|
|
/// </summary>
|
|
private static void ApplyProductInput(SalesProduct entity, SalesProductSaveInput input)
|
|
{
|
|
entity.ProductCode = input.ProductCode;
|
|
entity.ProductName = input.ProductName;
|
|
entity.ProductGroup = input.ProductGroup;
|
|
entity.MinTimeliness = input.MinTimeliness;
|
|
entity.MaxTimeliness = input.MaxTimeliness;
|
|
entity.CustomerWaybill = input.CustomerWaybill;
|
|
entity.LabelTemplateId = input.LabelTemplateId;
|
|
entity.BlacklistAreaId = input.BlacklistAreaId;
|
|
entity.RemoteAreaId = input.RemoteAreaId;
|
|
entity.PriceAreaId = input.PriceAreaId;
|
|
entity.WeightRuleId = input.WeightRuleId;
|
|
entity.WeightRoundingId = input.WeightRoundingId;
|
|
entity.ProductDescription = input.ProductDescription;
|
|
entity.PreStorageScript = input.PreStorageScript;
|
|
entity.CustomerGuideMarkdown = input.CustomerGuideMarkdown;
|
|
entity.IsActive = input.IsActive;
|
|
entity.Scheme = string.IsNullOrWhiteSpace(input.Scheme) ? AllocationSchemeCodes.CostLowest : input.Scheme;
|
|
}
|
|
|
|
private static SalesProductListOutput MapListOutput(SalesProduct entity)
|
|
{
|
|
return new SalesProductListOutput
|
|
{
|
|
Id = entity.Id,
|
|
ProductCode = entity.ProductCode,
|
|
ProductName = entity.ProductName,
|
|
ProductGroup = entity.ProductGroup,
|
|
MinTimeliness = entity.MinTimeliness,
|
|
MaxTimeliness = entity.MaxTimeliness,
|
|
CustomerWaybill = entity.CustomerWaybill,
|
|
LabelTemplateId = entity.LabelTemplateId,
|
|
BlacklistAreaId = entity.BlacklistAreaId,
|
|
RemoteAreaId = entity.RemoteAreaId,
|
|
PriceAreaId = entity.PriceAreaId,
|
|
WeightRuleId = entity.WeightRuleId,
|
|
WeightRoundingId = entity.WeightRoundingId,
|
|
ProductDescription = entity.ProductDescription,
|
|
IsActive = (byte)entity.IsActive,
|
|
Scheme = entity.Scheme,
|
|
CreateTime = entity.CreateTime,
|
|
UpdateTime = OmsDocHelper.NullIfDefault(entity.UpdateTime)
|
|
};
|
|
}
|
|
|
|
private static SalesProductDetailOutput MapDetailOutput(
|
|
SalesProduct entity,
|
|
IReadOnlyDictionary<int, string> auditUserNameMap)
|
|
{
|
|
return new SalesProductDetailOutput
|
|
{
|
|
Id = entity.Id,
|
|
ProductCode = entity.ProductCode,
|
|
ProductName = entity.ProductName,
|
|
ProductGroup = entity.ProductGroup,
|
|
MinTimeliness = entity.MinTimeliness,
|
|
MaxTimeliness = entity.MaxTimeliness,
|
|
CustomerWaybill = entity.CustomerWaybill,
|
|
LabelTemplateId = entity.LabelTemplateId,
|
|
BlacklistAreaId = entity.BlacklistAreaId,
|
|
RemoteAreaId = entity.RemoteAreaId,
|
|
PriceAreaId = entity.PriceAreaId,
|
|
WeightRuleId = entity.WeightRuleId,
|
|
WeightRoundingId = entity.WeightRoundingId,
|
|
ProductDescription = entity.ProductDescription,
|
|
PreStorageScript = entity.PreStorageScript,
|
|
CustomerGuideMarkdown = entity.CustomerGuideMarkdown,
|
|
IsActive = (byte)entity.IsActive,
|
|
Scheme = entity.Scheme,
|
|
CreateTime = entity.CreateTime,
|
|
CreateBy = OmsRbacUserDisplayNameResolver.FormatUserId(entity.CreateUserId, auditUserNameMap),
|
|
UpdateTime = OmsDocHelper.NullIfDefault(entity.UpdateTime),
|
|
UpdateBy = OmsRbacUserDisplayNameResolver.FormatUserId(entity.UpdateUserId, auditUserNameMap)
|
|
};
|
|
}
|
|
|
|
private static ChannelPriceFactorOutput MapPriceFactorOutput(SalesProductPriceFactor entity)
|
|
{
|
|
return new ChannelPriceFactorOutput
|
|
{
|
|
Id = entity.Id,
|
|
PriceId = entity.PriceId,
|
|
SerialNumber = entity.SerialNumber,
|
|
Factor = entity.Factor,
|
|
FactorValues = OmsDocHelper.DeserializeJson<List<string>>(entity.FactorValues) ?? []
|
|
};
|
|
}
|
|
|
|
private static ChannelPriceDetailOutput MapPriceDetailOutput(SalesProductPriceDetail entity)
|
|
{
|
|
return new ChannelPriceDetailOutput
|
|
{
|
|
Id = entity.Id,
|
|
PriceId = entity.PriceId,
|
|
FactorValuesJson = OmsDocHelper.DeserializeJsonObject(entity.FactorValuesJson),
|
|
CalculationFormula = entity.CalculationFormula,
|
|
CalculatedValue = entity.CalculatedValue,
|
|
CustomerGroupValues = OmsDocHelper.DeserializeJsonObject(entity.CustomerGroupValues)
|
|
};
|
|
}
|
|
|
|
private static List<SalesProductPriceFactor> BuildSalesProductPriceFactors(IEnumerable<ChannelPriceFactorInput> inputs, int? priceId = null)
|
|
{
|
|
return inputs.Select(input => new SalesProductPriceFactor
|
|
{
|
|
PriceId = priceId ?? 0,
|
|
SerialNumber = input.SerialNumber,
|
|
Factor = input.Factor,
|
|
FactorValues = OmsDocHelper.SerializeJson(input.FactorValues)
|
|
}).ToList();
|
|
}
|
|
|
|
private static List<SalesProductPriceDetail> BuildSalesProductPriceDetails(IEnumerable<ChannelPriceDetailInput> inputs, int? priceId = null)
|
|
{
|
|
return inputs.Select(input => new SalesProductPriceDetail
|
|
{
|
|
PriceId = priceId ?? 0,
|
|
FactorValuesJson = OmsDocHelper.SerializeJson(input.FactorValuesJson),
|
|
CalculationFormula = input.CalculationFormula,
|
|
CalculatedValue = input.CalculatedValue,
|
|
CustomerGroupValues = OmsDocHelper.SerializeJson(input.CustomerGroupValues)
|
|
}).ToList();
|
|
}
|
|
|
|
private static SalesProductPriceSaveInput MapPriceSaveInput(SalesProductPriceListOutput output) =>
|
|
MapPriceSaveInput(output, output.SalesProductId);
|
|
|
|
private static SalesProductPriceSaveInput MapPriceSaveInput(SalesProductPriceSnapshotItemDto output, int salesProductId)
|
|
{
|
|
return new SalesProductPriceSaveInput
|
|
{
|
|
Id = output.Id,
|
|
SalesProductId = salesProductId,
|
|
SerialNumber = output.SerialNumber,
|
|
Status = (EnableStatus)output.Status,
|
|
PriceName = output.PriceName,
|
|
CostItem = output.CostItem,
|
|
CostUnit = output.CostUnit,
|
|
Currency = output.Currency,
|
|
ChargingCondition = output.ChargingCondition,
|
|
Factors = output.Factors.Select(item => new ChannelPriceFactorInput
|
|
{
|
|
Id = item.Id,
|
|
SerialNumber = item.SerialNumber,
|
|
Factor = item.Factor,
|
|
FactorValues = item.FactorValues
|
|
}).ToList(),
|
|
Details = output.Details.Select(item => new ChannelPriceDetailInput
|
|
{
|
|
Id = item.Id,
|
|
FactorValuesJson = item.FactorValuesJson,
|
|
CalculationFormula = item.CalculationFormula,
|
|
CalculatedValue = item.CalculatedValue,
|
|
CustomerGroupValues = item.CustomerGroupValues
|
|
}).ToList()
|
|
};
|
|
}
|
|
|
|
private static SalesProductPriceSaveInput MapPriceSaveInput(SalesProductPriceListOutput output, int salesProductId)
|
|
{
|
|
return new SalesProductPriceSaveInput
|
|
{
|
|
Id = output.Id,
|
|
SalesProductId = salesProductId,
|
|
SerialNumber = output.SerialNumber,
|
|
Status = (EnableStatus)output.Status,
|
|
PriceName = output.PriceName,
|
|
CostItem = output.CostItem,
|
|
CostUnit = output.CostUnit,
|
|
Currency = output.Currency,
|
|
ChargingCondition = output.ChargingCondition,
|
|
Factors = output.Factors.Select(item => new ChannelPriceFactorInput
|
|
{
|
|
Id = item.Id,
|
|
SerialNumber = item.SerialNumber,
|
|
Factor = item.Factor,
|
|
FactorValues = item.FactorValues
|
|
}).ToList(),
|
|
Details = output.Details.Select(item => new ChannelPriceDetailInput
|
|
{
|
|
Id = item.Id,
|
|
FactorValuesJson = item.FactorValuesJson,
|
|
CalculationFormula = item.CalculationFormula,
|
|
CalculatedValue = item.CalculatedValue,
|
|
CustomerGroupValues = item.CustomerGroupValues
|
|
}).ToList()
|
|
};
|
|
}
|
|
|
|
private static string NormalizeOperatorType(string? operatorType)
|
|
{
|
|
var normalized = operatorType?.Trim().ToLowerInvariant();
|
|
return normalized switch
|
|
{
|
|
PriceOperatorType => PriceOperatorType,
|
|
RulesOperatorType => RulesOperatorType,
|
|
_ => throw new Fake.Application.BusinessException("不支持的发布类型")
|
|
};
|
|
}
|
|
|
|
private sealed class SalesProductPricePublishSnapshot : SalesProductPricePublishSnapshotDto
|
|
{
|
|
}
|
|
|
|
private sealed class SalesProductRulesPublishSnapshot : SalesProductRulesPublishSnapshotDto
|
|
{
|
|
}
|
|
}
|