Update pricing model to include half-year pricing and enhance validation
CI / Backend (build + test) (push) Successful in 1m24s
CI / Frontend (lint + typecheck + build) (push) Failing after 15s

- 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:
Leonid Pershin
2026-07-18 20:17:32 +03:00
parent 6dfd51ae7c
commit 32221af503
16 changed files with 1133 additions and 39 deletions
+3 -1
View File
@@ -175,9 +175,11 @@ export type RoleDto = {
isSystem: boolean
}
/** Глобальная справочная цена за конфиг (видна только админу) — одна на весь сервис, не per-роль. */
/** Глобальная справочная цена за конфиг (видна только админу) — одна на весь сервис, не per-роль.
* Все поля — цена за конфиг В МЕСЯЦ при данном тарифе; итог за период = ставка × месяцы. */
export type PricingSettingsDto = {
pricePerConfigPerQuarter: number | null
pricePerConfigPerHalfYear: number | null
pricePerConfigPerYear: number | null
}
+10 -2
View File
@@ -271,8 +271,12 @@ const resources = {
title: 'Справочная цена конфига',
pricePerConfigPerQuarter: 'Цена за конфиг в месяц / оплата раз в 3 мес',
pricePerConfigPerQuarterHint: 'Минимальный период оплаты. Видно только админу. Итог за период = ставка × число месяцев × квота роли.',
pricePerConfigPerHalfYear: 'Цена за конфиг в месяц / оплата раз в полгода',
pricePerConfigPerHalfYearHint: 'Может быть ниже квартальной (скидка за оплату на полгода вперёд), но итог за полгода не должен быть дешевле итога за квартал.',
halfYearCheaperThanQuarter: 'Цена за полгода (в пересчёте на 6 месяцев) не может быть меньше цены за 3 месяца.',
pricePerConfigPerYear: 'Цена за конфиг в месяц / оплата раз в год',
pricePerConfigPerYearHint: 'Может быть ниже квартальной (скидка за годовую оплату), но итог за год не должен быть дешевле итога за квартал.',
pricePerConfigPerYearHint: 'Может быть ниже полугодовой (скидка за годовую оплату), но итог за год не должен быть дешевле итога за полгода.',
yearCheaperThanHalfYear: 'Цена за год (в пересчёте на 12 месяцев) не может быть меньше цены за полгода.',
yearCheaperThanQuarter: 'Цена за год (в пересчёте на 12 месяцев) не может быть меньше цены за 3 месяца.',
updated: 'Цена обновлена.',
},
@@ -703,8 +707,12 @@ const resources = {
title: 'Reference config price',
pricePerConfigPerQuarter: 'Price per config per month / billed every 3 months',
pricePerConfigPerQuarterHint: 'Minimum billing period. Visible to admin only. Total for a period = rate × months × role quota.',
pricePerConfigPerHalfYear: 'Price per config per month / billed every 6 months',
pricePerConfigPerHalfYearHint: 'Can be lower than the quarterly rate (discount for a 6-month prepayment), but the 6-month total must not be cheaper than the 3-month total.',
halfYearCheaperThanQuarter: 'The 6-month price (over 6 months) cannot be lower than the 3-month price.',
pricePerConfigPerYear: 'Price per config per month / billed yearly',
pricePerConfigPerYearHint: 'Can be lower than the quarterly rate (annual discount), but the yearly total must not be cheaper than the quarterly total.',
pricePerConfigPerYearHint: 'Can be lower than the 6-month rate (annual discount), but the yearly total must not be cheaper than the 6-month total.',
yearCheaperThanHalfYear: 'The annual price (over 12 months) cannot be lower than the 6-month price.',
yearCheaperThanQuarter: 'The annual price (over 12 months) cannot be lower than the 3-month price.',
updated: 'Pricing updated.',
},