Update pricing model to include half-year pricing and enhance validation
- Introduced a new pricing field, `PricePerConfigPerHalfYear`, to the `PricingSettings` model, allowing for more flexible pricing options. - Updated the `UpdatePricingSettingsCommand` and its validator to include the new half-year pricing, ensuring proper validation against the quarterly and yearly rates. - Modified the `PricingSettingsDto` and related frontend components to accommodate the new half-year pricing field, including validation logic to prevent pricing discrepancies. - Enhanced API documentation and frontend forms to reflect the updated pricing structure and validation rules.
This commit is contained in:
@@ -20,7 +20,7 @@ public sealed class GetPricingSettingsQueryHandler(IAppDbContext dbContext)
|
||||
// Ещё не сидировано/не сохранено ни разу — цена не задана, а не ошибка.
|
||||
return Result.Success(
|
||||
settings is null
|
||||
? new PricingSettingsDto(null, null)
|
||||
? new PricingSettingsDto(null, null, null)
|
||||
: PricingSettingsDto.FromDomain(settings)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,8 +2,16 @@ using PnvPanel.Domain.Pricing;
|
||||
|
||||
namespace PnvPanel.Application.Admin.Pricing;
|
||||
|
||||
public sealed record PricingSettingsDto(int? PricePerConfigPerQuarter, int? PricePerConfigPerYear)
|
||||
public sealed record PricingSettingsDto(
|
||||
int? PricePerConfigPerQuarter,
|
||||
int? PricePerConfigPerHalfYear,
|
||||
int? PricePerConfigPerYear
|
||||
)
|
||||
{
|
||||
public static PricingSettingsDto FromDomain(PricingSettings settings) =>
|
||||
new(settings.PricePerConfigPerQuarter, settings.PricePerConfigPerYear);
|
||||
new(
|
||||
settings.PricePerConfigPerQuarter,
|
||||
settings.PricePerConfigPerHalfYear,
|
||||
settings.PricePerConfigPerYear
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,5 +5,6 @@ namespace PnvPanel.Application.Admin.Pricing;
|
||||
|
||||
public sealed record UpdatePricingSettingsCommand(
|
||||
int? PricePerConfigPerQuarter,
|
||||
int? PricePerConfigPerHalfYear,
|
||||
int? PricePerConfigPerYear
|
||||
) : ICommand<Result<PricingSettingsDto>>;
|
||||
|
||||
+5
-1
@@ -21,7 +21,11 @@ public sealed class UpdatePricingSettingsCommandHandler(IAppDbContext dbContext)
|
||||
dbContext.PricingSettings.Add(settings);
|
||||
}
|
||||
|
||||
settings.Update(command.PricePerConfigPerQuarter, command.PricePerConfigPerYear);
|
||||
settings.Update(
|
||||
command.PricePerConfigPerQuarter,
|
||||
command.PricePerConfigPerHalfYear,
|
||||
command.PricePerConfigPerYear
|
||||
);
|
||||
|
||||
return Result.Success(PricingSettingsDto.FromDomain(settings));
|
||||
}
|
||||
|
||||
+33
-5
@@ -10,14 +10,38 @@ public sealed class UpdatePricingSettingsCommandValidator
|
||||
RuleFor(x => x.PricePerConfigPerQuarter!.Value)
|
||||
.GreaterThanOrEqualTo(0)
|
||||
.When(x => x.PricePerConfigPerQuarter.HasValue);
|
||||
RuleFor(x => x.PricePerConfigPerHalfYear!.Value)
|
||||
.GreaterThanOrEqualTo(0)
|
||||
.When(x => x.PricePerConfigPerHalfYear.HasValue);
|
||||
RuleFor(x => x.PricePerConfigPerYear!.Value)
|
||||
.GreaterThanOrEqualTo(0)
|
||||
.When(x => x.PricePerConfigPerYear.HasValue);
|
||||
|
||||
// Обе ставки — цена за конфиг В МЕСЯЦ при соответствующем тарифе оплаты; итог за период =
|
||||
// ставка × число месяцев. Годовая ставка может быть ниже квартальной (скидка за годовую
|
||||
// оплату), но итог за год (ставка×12) не должен быть дешевле итога за квартал (ставка×3) —
|
||||
// иначе выгоднее купить "год" и не продлевать, чем платить за квартал.
|
||||
// Все три ставки — цена за конфиг В МЕСЯЦ при соответствующем тарифе оплаты; итог за период =
|
||||
// ставка × число месяцев. Более длинный период может быть дешевле "в пересчёте на месяц"
|
||||
// (скидка за предоплату), но итог за него не должен быть дешевле итога за более короткий
|
||||
// период — иначе выгоднее купить длинный тариф и не продлевать, чем платить за короткий.
|
||||
RuleFor(x => x.PricePerConfigPerHalfYear)
|
||||
.Must(
|
||||
(command, halfYear) =>
|
||||
!halfYear.HasValue
|
||||
|| !command.PricePerConfigPerQuarter.HasValue
|
||||
|| (decimal)halfYear.Value * 6 >= (decimal)command.PricePerConfigPerQuarter.Value * 3
|
||||
)
|
||||
.WithMessage("Цена за полгода (в пересчёте на 6 месяцев) не может быть меньше цены за 3 месяца.")
|
||||
.When(x => x.PricePerConfigPerQuarter.HasValue && x.PricePerConfigPerHalfYear.HasValue);
|
||||
|
||||
RuleFor(x => x.PricePerConfigPerYear)
|
||||
.Must(
|
||||
(command, year) =>
|
||||
!year.HasValue
|
||||
|| !command.PricePerConfigPerHalfYear.HasValue
|
||||
|| (decimal)year.Value * 12 >= (decimal)command.PricePerConfigPerHalfYear.Value * 6
|
||||
)
|
||||
.WithMessage("Цена за год (в пересчёте на 12 месяцев) не может быть меньше цены за полгода.")
|
||||
.When(x => x.PricePerConfigPerHalfYear.HasValue && x.PricePerConfigPerYear.HasValue);
|
||||
|
||||
// Если полугодовая ставка не задана, год всё равно не должен быть дешевле квартала.
|
||||
RuleFor(x => x.PricePerConfigPerYear)
|
||||
.Must(
|
||||
(command, year) =>
|
||||
@@ -26,6 +50,10 @@ public sealed class UpdatePricingSettingsCommandValidator
|
||||
|| (decimal)year.Value * 12 >= (decimal)command.PricePerConfigPerQuarter.Value * 3
|
||||
)
|
||||
.WithMessage("Цена за год (в пересчёте на 12 месяцев) не может быть меньше цены за 3 месяца.")
|
||||
.When(x => x.PricePerConfigPerQuarter.HasValue && x.PricePerConfigPerYear.HasValue);
|
||||
.When(x =>
|
||||
!x.PricePerConfigPerHalfYear.HasValue
|
||||
&& x.PricePerConfigPerQuarter.HasValue
|
||||
&& x.PricePerConfigPerYear.HasValue
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user