Направление работ: Back Код раздела: 2.7 Объекты и предложения > Скидки Статус: черновик Ответственный: Панкова Л.А. Версия: 0.1 Обновлено: 20.07.26
1. Назначение
Скидки уменьшают стоимость заказа или другого объекта оплаты по правилам конкретного вида скидки.
Текущий раздел задает общую модель скидок и доступные операции над ними. Параметры, условия применения и ограничения отдельных видов скидок описываются в дочерних разделах.
2. Ключевые понятия
Скидка — сущность, которая уменьшает стоимость объекта оплаты при выполнении заданных условий.
Вид скидки — отдельная модель скидки со своими параметрами и правилами применения: акция, промокод, горящее предложение, скидка баллами или скидка на погашение сборов.
Объект оплаты — сущность, для которой система рассчитывает сумму к оплате.
3. Scope
Входит
S1 Скидки: общая сущность и состав поддерживаемых видов скидок.
S2 Операции над скидками: создание, изменение, архивация и восстановление.
Не входит
- Back 2.7.1 Акции и промокоды — параметры автоматических и ручных скидок
- Back 2.7.2 Горящие предложения — скидки на незанятое время площадок и услуг
- Back 2.7.3 Скидки баллами — правила оплаты заказа М-баллами
- Back 2.7.4 Скидки на погашение сборов — скидки на оплату сборов
- Back 8.3 Тарифы — скидки на оплату тарифов
- Back 8.4.1 Сервисные промокоды — промокоды, применимые в разных партнерских зонах
- Back 4.2 Стоимость заказа и позиций — порядок расчета стоимости с учетом скидок
- Back 5.1.1 Объекты оплаты — состав и жизненный цикл объектов оплаты
4. Требования
Правила и ограничения бизнеса на уровне данных, источник истины в системе.
| ID | Требование | Комментарий | Тип требования | Вес | Статус |
|---|---|---|---|---|---|
| S1: BR2.7-1 | Скидка должна храниться как отдельная сущность, которая уменьшает стоимость объекта оплаты. | Объекты оплаты раскрываются в Back 5.1.1, а порядок расчета — в Back 4.2. | Бизнес | 1 | Частично OQ2.7-1 |
| S1: BR2.7-2 | Каждая скидка должна относиться к одному поддерживаемому виду скидки. | Поддерживаемые виды: - акция - промокод - горящее предложение - скидка баллами - скидка на погашение сборов Скидки на оплату тарифов относятся к Back 8.3. | Бизнес | 1 | Частично OQ2.7-2 |
| S2: BR2.7-3 | Система должна поддерживать создание и изменение скидок с учетом правил выбранного вида скидки. | Состав параметров и ограничения операций определяются в дочерних разделах 2.7.1-2.7.4. | Системное | 1 | Реализовано OQ2.7-4, OQ2.7-6 |
| S2: BR2.7-4 | Система должна поддерживать архивацию и восстановление скидок. | Системное | 1 | Частично OQ2.7-3, OQ2.7-5, OQ2.7-7 |
5. Открытые вопросы
Сверка с кодом: BRD 2.7 v0.1 · репозиторий
booking-monorepo· commit83423b21/main· 26.07.26 · якорьsrc/services/booking.discountsСводка: 7 вопросов (Open 5 · Подтверждено 2) Маршрутизация без сверки с гайдбуком (гайдбук не передавался).
| ID | Источник | Вопрос | Кому | Статус | Рекомендации | Итоговое решение |
|---|---|---|---|---|---|---|
| OQ2.7-1 | Код BR2.7-1 | Требование говорит: скидка хранится как отдельная сущность, которая уменьшает стоимость объекта оплаты. В коде единой сущности «Скидка» нет: есть три независимые сущности со своими таблицами и своим набором полей — акция, промокод и горящее предложение. Общего родителя, общего идентификатора и общего списка «все скидки заказа» не существует; то, что в расчёте выглядит как единый список скидок, собирается на лету из трёх разных запросов. Понятия «объект оплаты» в сервисе скидок тоже нет: скидка привязана к заказу и всегда разложена на две составляющие — «на время» и «на позиции», каждая со своей суммой или процентом. \ AutoDiscountAggregate.cs:28, ManualDiscountAggregate.cs, HotDiscountAggregate.cs (три сущности); GetDiscountsForOrderMultiQuery.cs:103, :168-175, :277-284 (сборка списка из трёх источников); AutoDiscountAggregate.cs:33-34 (две составляющие скидки) | Бизнес | Open | (А) Признать текущую модель целевой (рекоменд.) и переписать BR2.7-1 в терминах кода: скидка — не одна сущность, а семейство видов, и уменьшает она не «объект оплаты», а две составляющие заказа — время и позиции. Тогда же стоит внести в BRD вторую ось классификации «на время / на позиции»: она есть в коде, влияет на расчёт и сейчас в документе не описана вовсе. (Б) Настаивать на единой сущности — это крупная переработка сервиса скидок, оправданная только если планируются общие операции над всеми видами скидок сразу. | |
| OQ2.7-2 | Код BR2.7-2 | Требование говорит: каждая скидка относится к одному из пяти видов — акция, промокод, горящее предложение, скидка баллами, скидка на погашение сборов. В коде видов три: ручная (промокод), автоматическая (акция) и горячая (горящее предложение). Скидок баллами и скидок на погашение сборов в сервисе скидок нет вообще — баллы и сборы живут отдельными сущностями в сервисе клиентов и скидками не считаются: у них своя модель, свои операции и своя история начислений. Кроме того, «вид» — это не поле сущности: он существует только как признак в ответе расчёта, а при хранении вид определяется тем, в какой таблице лежит запись. \ DiscountType.cs:9-22 (три значения); booking.clients/…/PointsAggregate/, …/ForfeitAggregate/ (баллы и сборы вне скидок); признак вида проставляется только при чтении — DiscountCalculationReadRepository.cs:106, :260 | Бизнес | Open | (А) Привести BRD к коду (рекоменд.): описать в BR2.7-2 три вида скидок, а баллы и сборы вынести из перечня видов, оставив ссылки на их разделы (2.7.3, 2.7.4) как на смежные механизмы уменьшения суммы к оплате. (Б) Оставить пятивидовую модель как целевую — тогда нужно решение, планируется ли переносить баллы и сборы в сервис скидок; без этого дочерние разделы 2.7.3 и 2.7.4 будут сверяться против чужого сервиса, а требование останется нереализуемым в текущей архитектуре. Вопрос стоит закрыть до сверки 2.7.3. | |
| OQ2.7-3 | Код BR2.7-4 | Требование говорит: система поддерживает архивацию и восстановление скидок. В коде это верно для акций и промокодов, а у горящих предложений восстановления нет: изменение принимает только перевод в архив, обратный перевод не предусмотрен. Причина в том, что у горящих предложений архив означает не «скрыто», а «уже использовано»: при применении к заказу предложение само становится архивным, и снять этот признак можно только отменой использования. Дополнительно архивация горящего предложения — единственная из трёх, которая не публикует событие, поэтому смежные сервисы о ней не узнают. \ HotDiscountAggregate.cs:109-112 (только перевод в архив), :30 (комментарий «архивное = использовано»), :116-131 (применение архивирует), :133-144 (снятие использования — единственный путь назад), :146-151 (архивация без события) против AutoDiscountAggregate.cs:172-183 и ManualDiscountAggregate.cs:156-160, :282-286 | Разработка | Open | Завести тикет в Bitrix: развести у горящих предложений два разных смысла признака архивности — «использовано» и «убрано партнёром» — либо явно задокументировать, что к горящим предложениям BR2.7-4 не применяется. Отдельным пунктом — публиковать событие при архивации, как у остальных видов. Продуктового выбора здесь нет, но перед правкой стоит уточнить у бизнеса, нужна ли партнёру возможность убрать горящее предложение вручную (см. 2.7.2). | |
| OQ2.7-4 | Код BR2.7-3 | Проблема: создание акции с пустой областью действия (не выбран ни объект, ни площадка) завершается технической ошибкой вместо понятного отказа. Доменный метод создания в этом случае возвращает «ничего», обработчик этого не проверяет и сразу обращается к результату — получается обращение к пустой ссылке, транзакция откатывается, а наружу уходит системная ошибка без объяснения причины. \ AutoDiscountAggregate.cs:398-399 (возврат «ничего» при пустой области), CreateAutoDiscountCommandHandler.cs:79-106 (результат не проверяется) | Разработка | Open | Завести тикет в Bitrix: проверять результат создания и возвращать понятную ошибку «не выбран объект или площадка». Продуктового выбора нет. Заодно проверить симметричный путь у промокодов и горящих предложений — там проверка области действия устроена иначе. | |
| OQ2.7-5 | Код вне BRD | Что нашли: кроме архивации, у акций и промокодов есть физическое удаление — запись стирается из базы. Оно разрешено только если скидкой ещё ни разу не воспользовались; при попытке удалить использованную скидку возвращается отказ «Нельзя удалить скидку». В BRD такой операции нет: BR2.7-4 описывает только архивацию и восстановление. У горящих предложений удаления нет. \ DeleteAutoDiscountCommandHandler.cs:43-51, DeleteManualDiscountCommandHandler.cs | Бизнес | Open | (А) Признать удаление целевым (рекоменд.) и внести его в BR2.7-4 вместе с условием «только для неиспользованных скидок» — поведение осмысленное: ошибочно заведённую скидку логично удалить, а не хранить в архиве. (Б) Если удаление нежелательно (например, ради полноты аудита), ставить задачу на его отключение. Заодно уточните, нужно ли удаление у горящих предложений — сейчас их поведение отличается от остальных видов без описанной причины. | |
| OQ2.7-6 | Код BR2.7-3 | Что подтверждено: создание и изменение реализованы отдельно для каждого вида скидки, с учётом его правил. У акций при создании проверяется уникальность названия в партнёрской зоне и отсутствие пересечения с уже заведёнными скидками (по датам, времени, клиентам, позициям и области действия). У промокодов три отдельных пути создания — из кабинета партнёра, из сервисного кабинета и внутренний. У горящих предложений изменение запрещено после использования. \ CreateAutoDiscountCommandHandler.cs:52-77, CreateManualDiscountCommandHandler.cs (три варианта: LK / Service / Internal), HotDiscountAggregate.cs:91-94 | — | Подтверждено | Расхождения нет. | — |
| OQ2.7-7 | Код BR2.7-4 | Что подтверждено: у акций и промокодов архивация и восстановление реализованы полностью — обе операции меняют признак архивности, фиксируют, кто и когда изменил запись, и публикуют события для смежных сервисов; управлять ими можно через обычное изменение скидки. \ AutoDiscountAggregate.cs:172-183 и :362-369, ManualDiscountAggregate.cs:156-160, :282-286, :385 | — | Подтверждено | Расхождения нет. | — |