Направление работ: Back Код раздела: 2.6 Цены Версия: 0.4 Обновлено: 08.07.26

Назначение

Цены задают базовую стоимость аренды площадки или услуги за единицу времени. Back обеспечивает хранение цен, все операции (создание, изменение, архивирование, удаление) и валидацию, проверку конфликтов между ценами из-за пересечения условий применения.

Ключевые понятия

  • Цена — сущность, определяющая стоимость бронирования площадки/услуги в партнёрской зоне при заданных условиях применения. Каждая уникальная комбинация условий применения = отдельная цена.
  • Стоимость — числовое значение для расчёта бронирования временного слота.
  • Временной слот — промежуток в рамках режима работы площадки/объекта.
  • Условия применения: Партнёрская зона, Объект, Площадка (мин. одна), Период действия (нет = бессрочно), День недели (нет = все дни), Время действия/слот, Опция заказа/вид работ/услуга, Диапазон посетителей, Минимальная длительность заказа, Признак «День в день».
  • Доплата за превышение количества посетителей — фиксированная надбавка за каждого посетителя сверх диапазона, не отдельная цена.

Scope

Входит

  • S1 — Сущность цены
  • S2 — Параметры и данные
  • S3 — Создание и изменение
  • S4 — Архивация и восстановление
  • S5 — Удаление
  • S6 — Массовые операции
  • S7 — Валидация и ограничения

Требования

IDТребованиеКомментарийТип требованияВесСтатус
S1: BR2.6-1Цена относится только к одной партнёрской зоне. Не может быть создана вне партнёрской зоны и перенесена в другую.Бизнес1Реализовано
S2: BR2.6-2Цена должна содержать параметры применимости: партнёрская зона, объект, площадка, период действия, день недели, время действия (слот), опция заказа, диапазон посетителей, минимальная длительность заказа, признак «День в день».Бизнес1
S2: BR2.6-3Цена должна содержать набор значений стоимости для применимых временных слотов.Бизнес1Частично \ #OQ2.6-10
S2: BR2.6-4Если необязательное условие не задано — цена применяется ко всем допустимым значениям (день недели, опция, период, диапазон посетителей).Бизнес2Частично \ #OQ2.6-5
S2: BR2.6-5Доплата за превышение диапазона посетителей может быть задана только для цены с заданным диапазоном. Доплата не создаёт отдельную цену, меняет значения в матрице на фиксированное количество.Бизнес2Не реализовано \ #OQ2.6-4
S3: BR2.6-6Система должна поддерживать создание и изменение всех параметров и значений цены (условия применения и значения стоимости по слотам).Системное1Реализовано
S4: BR2.6-7Система должна поддерживать архивацию цены. Архивная цена перестаёт применяться к новым бронированиям.Системное1Реализовано
S4: BR2.6-8Восстановление архивной цены только при отсутствии конфликтов с активными ценами. Применяются проверки применимости как при создании/изменении.Бизнес2Реализовано
S5: BR2.6-9Удаление цены необратимо.Бизнес2Реализовано
S6: BR2.6-10Массовые операции только в рамках одной партнёрской зоны.Бизнес2
S6: BR2.6-11При массовой операции каждая цена обрабатывается по правилам одиночной операции.Системное2Реализовано
S6: BR2.6-12Результат массовой операции должен позволять определить, какие цены обработаны успешно, какие с ошибкой.Системное2Не реализовано \ #OQ2.6-12
S7: BR2.6-13Нельзя сохранить цену с пустыми обязательными параметрами (только площадка и стоимость).Системное1Частично \ #OQ2.6-11
S7: BR2.6-14Не допускается наличие нескольких цен, применимых к одному случаю бронирования в одной партнёрской зоне. Конфликт = совпадение/пересечение условий применения и временных слотов. Совпадение значений стоимости не конфликт. Только если совпадают все условия применения.Бизнес1Частично \ #OQ2.6-7 \ #OQ2.6-8 \ #OQ2.6-9 \ #OQ2.6-2
S7: BR2.6-15Нельзя оставить незаполненный временной слот в пределах режима работы площадки.Бизнес2Не реализовано \ #OQ2.6-3
S7: BR2.6-16Цена с признаком «День в день» не может существовать без цены «Заранее» с теми же условиями применения. «Заранее» может без «День в день». Условия совпадают кроме признака, стоимости могут отличаться.Бизнес2Не реализовано \ #OQ2.6-1

5. Открытые вопросы

IDИсточникВопросКомуСтатусРекомендацииИтоговое решение
#OQ2.6-1Код BR2.6-16Требование говорит: цену «День в день» нельзя создавать в одиночку — рядом обязательно должна быть парная цена «Заранее» с теми же условиями. В коде такой проверки нет вообще: «День в день» — просто галочка, и цену с ней можно сохранить одну, без пары (ни при создании, ни при изменении, ни при восстановлении система пару не требует). \ PriceAggregate.cs:78; CreatePriceCommandHandler.cs:70Бизнес (Герман)OpenВ гайдбуке 2.6 правила про обязательную пару вообще нет — подтвердить, что оно реально нужно, нечем. Решение бизнеса: (А) если правило нужно — добавить проверку и решить, где она живёт (Back или фронт), но одиночную «День в день» не сохранять; (Б) если «День в день» самодостаточна — убрать требование из BR2.6-16.Вариант Б
Нужен финальный ответ от бизнеса. Либо бэке проверяет наличие пары, либо убрать инвариант из BRD
isToday - простой флаг, пары “заранее” не требуется
#OQ2.6-2Код BR2.6-14Что делает система: при проверке конфликтов считает цену «День в день» и цену «Заранее» с одинаковыми прочими условиями двумя разными, непересекающимися ценами. То есть галочка «День в день» работает как разделитель цен, а не как обычное условие. Это не ошибка — так и должна вести себя модель пары, но нужно, чтобы бизнес это подтвердил письменно. \ PriceRepository.cs:270Бизнес (Герман)OpenРекомендация — оставить как есть, логика непротиворечива. Нужно только письменное «да, так задумано» от бизнеса.isToday = true/false разделяет цены при конфликт проверке. Стоит подтвердить вопрос с бизнесом
#OQ2.6-3Код BR2.6-15Требование говорит: у площадки не должно оставаться «дыр» в расписании — на каждый рабочий слот должна быть цена. Проблема: сервис цен вообще не знает график работы площадки (эти данные в него не приходят), поэтому проверить покрытие он физически не может. Заготовка под проверку в коде есть, но не используется — цену можно сохранить с дырой в расписании. \ OverLappingOffSchedulesException.cs:11Бизнес/РазработкаOpenПравило в сервисе цен в одиночку жить не может — нет данных о графике. Рекомендация: договориться, что покрытие проверяет фронт или сервис ресурсов при задании цены, а BR2.6-15 убрать из зоны Back-цен. Альтернатива (дороже): тянуть график в сервис цен. Решают продукт + архитектура.Лучше закрепить ответственность за клиентом, а не связывать сервис цен с графиком работы площадки
#OQ2.6-4Код BR2.6-5Требование говорит: доплату за лишних посетителей можно задать только если у цены указан диапазон посетителей. В коде такой проверки нет — доплату принимают всегда, даже без диапазона (проверяют лишь, что она не отрицательная). Готовая проверка в коде заготовлена, но её не вызывают. \ PriceInfo.cs:26РазработкаЗакрывает PMКод просто не соответствует требованию, продуктового вопроса нет. Закрываю сам: включить проверку «доплата только при заданном диапазоне» (готовое исключение под это уже есть) → тикет в Bitrix.доработка
#OQ2.6-5Код BR2.6-4Требование говорит: если условие не задано — цена действует на все его значения (не задан день недели → все дни, не задана опция → все опции). В коде это работает по-разному: для периода и опций пустое = «все» (верно), а для дня недели и слота пустое = «ни одного» (неверно). Причина — дни недавно перевели в список, и пустой список читается как «ничего». \ PriceRepository.cs:279-284РазработкаЗакрывает PMГайдбук 2.6 прямо говорит: «день недели не задан → все дни». Значит это баг, а не спорный вопрос. Закрываю сам: привести проверку по дням/слотам к «все» → тикет в Bitrix.доработка
#OQ2.6-6Код вне BRDЧто делает код сверх требований: запрещает две цены с одинаковым названием в одной партнёрской зоне (проверка уникальности имени). В требованиях 2.6 такого правила нет — код строже, чем BRD. \ PriceRepository.cs:157Бизнес (Герман)OpenВ гайдбуке 2.6 про уникальность имени тоже ничего нет — подтвердить нечем. Решение бизнеса: если уникальность имени — намеренное правило, внести его в требования; если нет — снять проверку или задокументировать как техническое ограничение.Метод уникальности имени есть, но вообще нигде не используется.
Формулировка в BRD не совсем точная. Активного ограничения нет, код не строже BRD. Это мертвый кусок, его надо либо удалить, либо подключить как бизнес-правило
#OQ2.6-7Код BR2.6-14Требование: в одной зоне не должно быть двух цен на один и тот же случай (конфликт). Проверка на это есть, но только в коде приложения — в самой базе запрета на дубли нет. Из-за этого при двух одновременных запросах обе конфликтующие цены могут пройти проверку каждая в своей операции и обе сохраниться (состояние гонки). \ ApplicationDbContext.cs:39-56Разработка (Влад)OpenПравило важное (вес 1), а держится только на проверке в приложении — этого мало. Вопрос к Владу: добавить страховку на уровне базы (уникальное ограничение или блокировку на время записи)? Проверку в приложении оставить для понятных сообщений об ошибке.Проверка конфликтов только прикладная; БД не страхует от одновременной записи двух конфликтующих цен.
Уникальный индекс здесь сложно выразить из-за диапазонов; практичнее сериализовать запись в пределах партнёрской зоны.
#OQ2.6-8Код BR2.6-14Проблема: проверка пересечения слотов написана с ошибкой — кусок кода с выбором верхней границы времени бессмысленный (обе ветки дают одно и то же). Из-за этого слот, заканчивающийся в 00:00 (круглосуточный), не распознаётся как «до конца суток», и пересечение с ним почти никогда не срабатывает. \ PriceRepository.cs:282Разработка (Влад)OpenПохоже на баг. Вопрос к Владу (подтвердить логику): трактовать конец в 00:00 как конец суток и убрать бессмысленный кусок? Или 00:00 намеренно значит «полночь начала» — тогда задокументировать и покрыть тестом.00:00 не трактуется как конец суток в проверке пересечения.
Нужно определить семантику 00:00, вероятнее — конец суток, и добавить тесты.
#OQ2.6-9Код BR2.6-14Требование: конфликт цен определяется по набору «условий применения». В коде в проверке конфликта не участвуют два поля — минимальная длительность заказа и приоритет. Из-за этого две цены, различающиеся только длительностью (или только приоритетом), система ошибочно считает конфликтующими. \ PriceRepository.cs:269-285Бизнес/РазработкаOpenГайдбук 2.6 подсказывает: приоритет — это способ обойти валидацию, а не условие (значит верно, что он не участвует), а минимальная длительность — полноценное условие применения (значит должна участвовать). Подтвердить и добавить длительность в проверку.доработка
#OQ2.6-10Код BR2.6-3Требование: у цены должны быть значения стоимости по слотам, стоимость — значимый параметр. Проблема: стоимость по факту вообще не проверяется — единственная проверка (на «не 0 и не отрицательное») висит на типе, который в коде нигде не создаётся, а рабочий путь создания цены проверок стоимости не имеет. Итог: цену можно сохранить с нулевой или отрицательной стоимостью. \ TimeWithWeekdaysPrice.cs:17-23РазработкаЗакрывает PMГайдбук 2.6 прямо говорит: «стоимость не может быть 0, нулевые суммы недопустимы». Значит правило есть, спорить не о чем. Закрываю сам: перенести проверку на рабочий тип цены → тикет в Bitrix.доработка
#OQ2.6-11Код BR2.6-13Требование: обязательны только площадка и стоимость, остальное — нет. В коде наоборот: имя, приоритет и минимальная длительность фактически обязательны (без них не сохранить) — это строже требования. А сама стоимость при этом не проверяется вообще (см. OQ2.6-10). \ PriceInfo.cs:24-27Бизнес (Герман)OpenРешение бизнеса: какие поля на самом деле обязательны при создании цены. От ответа — либо ослабляем код до «только площадка и стоимость», либо обновляем требование под фактический набор. Связать с OQ2.6-10.Доработка
Имя обязательно; Priority и MinOrderDuration не могут быть отрицательными, но могут быть равны 0.
Последние два поля не обязательны по смыслу, у них допустимо значение по умолчанию 0. Остаётся несоответствие по обязательности имени и отсутствие валидации стоимости.
#OQ2.6-12Код BR2.6-12Требование: после массовой операции должно быть видно, какие цены обработались успешно, а какие — с ошибкой. В коде массовое изменение/удаление идёт одной общей транзакцией: на первой же проблемной цене всё откатывается целиком, и списка «эти ок, эти нет» не возвращается. \ UpdatePriceCommandHandler.cs:134,148Бизнес/РазработкаOpenТребование прямо просит частичный результат, а его нет. Решение: (А) переделать на пообъектную обработку с результатом по каждой цене (сломает нынешнюю «всё или ничего»); (Б, как временное) оставить общую транзакцию, но в ошибке возвращать id всех проблемных цен. Финальный выбор — за продуктом.пока актуальнее наверное вариант б
#OQ2.6-13Код вне BRDЧто нашли: в коде есть мёртвые куски — один файл-репозиторий цен вообще не подключён к сборке и не используется, а два метода архивации/восстановления существуют, но их никто не вызывает (архивация идёт другим путём). На поведение системы сейчас не влияет, но путает при следующих сверках. \ Program.cs:186РазработкаЗакрывает PMЧисто техническая уборка, продуктового вопроса нет. Закрываю сам: удалить мёртвый/неиспользуемый код (или переключить архивацию на эти методы, если это целевой путь).заказываем клининг, но попозже

Вопросы по сверке с кодом

BRD 2.6 v0.4 · booking-monorepo · commit 326ea62/main · 2026-07-06 · якорь src/services/booking.prices Сводка: вопросов 13 (бизнесовых 6 / программных 7) · подтверждено без вопросов 6 (BR2.6-1, BR2.6-6, BR2.6-7, BR2.6-8, BR2.6-9, BR2.6-11) · отрезано находок обратного прохода 4 Под особым вниманием: BR2.6-14, BR2.6-15, BR2.6-16/8, BR2.6-5, BR2.6-13, массовые операции BR2.6-9..12. Переобход относительно c1fa925 (2026-06-23): снят вопрос по BR2.6-8 (восстановление теперь проверяет конфликты с активными ценами — требование выполнено); снят вопрос по BR2.6-7 (исключение архивных из расчёта подтверждено пруфами); углублена находка по BR2.6-3 (проверка стоимости на неиспользуемом типе); ссылки file:line перепроверены и актуализированы под текущий код.

Бизнесовые

Связано сЧто в BRDЧто в кодеГде в коде
Б1BR2.6-16Цена «День в день» не может существовать без парной цены «Заранее» с теми же условиями; «Заранее» допустима без «День в день» (асимметрия).Признак «День в день» (IsToday) — обычное поле без проверки парности. Ни при создании, ни при изменении, ни при восстановлении цены с IsToday=true нет проверки, требующей наличия парной цены «Заранее». Цену «День в день» можно создать в одиночку. Поиск по всему сервису логики парности/«заранее» дал ноль совпадений. — нужно решение: должна ли система блокировать одиночную «День в день» и где (Back/Front).PriceAggregate.cs:78 (Create без проверки парности); CreatePriceCommandHandler.cs:70
Б2BR2.6-14Признак «День в день» — часть условий применения; конфликтуют цены с совпадающими условиями.В проверке конфликта цены с IsToday=true и IsToday=false считаются непересекающимися (p.IsToday == isToday). «Заранее» и «День в день» с прочими одинаковыми условиями никогда не конфликтуют между собой — это согласуется с моделью пары, но означает, что IsToday трактуется как разделитель цен, а не как обычное условие. Та же логика в расчёте (p.IsToday != isToday). — нужно подтверждение бизнеса, что это намеренно.PriceRepository.cs:270; CalculateBookingCommandHandler.cs:289,361
Б3BR2.6-15Нельзя оставить незаполненный временной слот в пределах режима работы площадки.Проверки покрытия режима работы в сервисе цен нет. Заготовленное доменное исключение OverLappingOffSchedulesException определено, но нигде не выбрасывается; режим работы площадки в сервис цен не подгружается (поиск schedule/WorkTime/Regime по домену дал только using). Цену можно сохранить с «дырой» в расписании. — нужно решение: где должна жить проверка покрытия (Back цен / Front / сервис ресурсов).OverLappingOffSchedulesException.cs:11 (определён, не используется); по обходу домена цен ссылок на режим работы не найдено
Б4BR2.6-5Доплата за превышение диапазона может быть задана только для цены с заданным диапазоном посетителей.На бэкенде доплата (RangeOveragePricePerUnit) принимается всегда; проверки «диапазон задан» нет. Значение лишь проверяется на неотрицательность. Заготовленное RangeNotProvidedException определено, но никогда не выбрасывается. Можно сохранить доплату без диапазона.PriceInfo.cs:26 (только проверка ≥0); RangeNotProvidedException.cs (определён, не используется)
Б5BR2.6-4Незаданное необязательное условие → цена применяется ко всем допустимым значениям (день недели, опция, период, диапазон).Трактуется неоднородно. Пустой период → «все даты» (MinValue/MaxValue), пустой список опций → «любая опция». Но день недели теперь хранится массивом в слоте (миграция дней в массив), и пустой список дней/слотов в проверке конфликта означает «ни одного» (пустой Any() = ложь), а не «все дни». То есть по периоду и опциям пустое = «все», а по дню недели и слоту пустое = «ничего» — направления разные. — нужно решение: что значит пустой день недели/слот — «все» или «ни одного».PriceRepository.cs:202 (даты = все), :272 (опции = все), :279-284 (дни/слоты = ни одного); ConvertDaysToArray.cs (дни в массив)
Б6вне BRDВ BRD нет требования об уникальности названия цены.В коде есть отдельная проверка уникальности имени цены в паре с партнёрской зоной (IsNameUnique, регистронезависимо). В требованиях 2.6 такого условия применения или ограничения нет — код делает сверх BRD. — нужно решение: является ли уникальность названия бизнес-правилом; если да — внести в BRD, если нет — уточнить назначение проверки.PriceRepository.cs:157 (IsNameUnique)

Рекомендация / варианты решения

  • Пара «День в день» / «Заранее» (Б1) и трактовка IsToday как разделителя (Б2) — общая первопричина: признак «День в день» смоделирован как обычный флаг, а инвариант пары BRD нигде не обеспечивается. Вариант А (рекоменд.): согласовать с продуктом целевое поведение и добавить проверку наличия парной «Заранее» при создании/изменении/восстановлении «День в день» (где именно — Back или Front — решить отдельно, но одиночную «День в день» без пары не сохранять). Вариант Б: привести BRD к коду, если бизнес решает, что «День в день» самодостаточна — тогда убрать инвариант пары из BR2.6-16. Логику «IsToday как разделитель конфликта» (Б2) при этом оставить как есть — она непротиворечива при любом из вариантов; нужно лишь письменное подтверждение бизнеса.
  • Покрытие режима работы, «дыра» в расписании (Б3) — правило BRD в сервисе цен не живёт и жить в одиночку не может (нет данных о режиме работы). Вариант А (рекоменд.): согласовать, что проверка покрытия — ответственность фронта/сервиса ресурсов на этапе задания цены (у Back цен нет графика площадки), и явно вынести BR2.6-15 из зоны Back цен. Вариант Б: подтягивать режим работы в сервис цен и обеспечивать покрытие на Back — дороже, добавляет связанность с сервисом ресурсов.
  • Доплата за диапазон без диапазона (Б4) — заготовка под правило есть, но оно не включено. Вариант А (рекоменд.): включить проверку «доплата задаётся только при заданном диапазоне/опции» (бросать уже существующее RangeNotProvidedException). Вариант Б: если продукт допускает доплату без диапазона — скорректировать BR2.6-5 и удалить неиспользуемое исключение.
  • Неоднородная семантика пустых условий (Б5) — сейчас «пусто = все» для периода/опций и «пусто = ничего» для дня недели/слота. Вариант А (рекоменд.): согласовать с продуктом единую трактовку «пусто = все допустимые значения» (как в BR2.6-4) и привести проверку конфликта по дням/слотам к этой семантике. Вариант Б: если для дня недели/слота осознанно нужно «ничего при пустом» — отразить это исключение в BR2.6-4, чтобы правило не читалось как универсальное.
  • Уникальность названия цены (Б6) — код строже BRD. Согласовать с продуктом: если уникальность имени в партнёрской зоне — намеренное бизнес-правило, внести его в требования 2.6; иначе оценить, нужна ли проверка (и снять её либо задокументировать как техническое ограничение — тогда вопрос уходит в программный блок).

Программные

Связано сЧто в BRDЧто в кодеГде в коде
П1BR2.6-14Не допускается нескольких цен на один случай бронирования в одной зоне (конфликт по пересечению условий и слотов).Проверка реализована только в приложении (ArePropertiesUnique): пересечение дат, диапазонов опций, временных слотов и дней; результат — список пересекающихся цен, при непустом — исключение. Уникального ограничения в базе нет (все индексы неуникальны, по price_id; в OnModelCreating нет IsUnique). При параллельных запросах две конфликтующие цены могут пройти проверку каждая в своей транзакции и сохраниться (гонка).PriceRepository.cs:164; 20250804155738_Scopes.cs:136 (индексы не уникальны); ApplicationDbContext.cs:39-56 (нет unique-индекса)
П2BR2.6-14Проверка пересечения слотов должна корректно учитывать границы времени.Условие верхней границы слота — фактически бессмысленный тернарник: (existing.TimeTo == TimeOnly.MinValue ? TimeOnly.MinValue : existing.TimeTo) > newSlot.Time.From — обе ветки дают одно и то же значение. Для слота, заканчивающегося в 00:00 (круглосуточный), верхняя граница не разворачивается в 24:00, поэтому 00:00 > начало почти всегда ложно и пересечение не фиксируется. — нужно подтверждение логики слота, заканчивающегося в 00:00.PriceRepository.cs:282
П3BR2.6-14Конфликт определяется по набору «условий применения».В проверке конфликта ArePropertiesUnique не участвуют MinOrderDuration и Priority (не передаются в метод и не фигурируют в фильтре). Две цены, различающиеся только минимальной длительностью заказа (или только приоритетом), будут считаться конфликтующими. — нужно решение: входят ли мин. длительность и приоритет в набор условий применения для определения конфликта.PriceRepository.cs:164-172,269-285 (нет MinOrderDuration/Priority); PriceInfo.cs:11
П4BR2.6-3Цена должна содержать набор значений стоимости для слотов (стоимость как значимый параметр).Валидация стоимости фактически не срабатывает на рабочем пути. Единственная проверка (value < 0 с текстом «Price can’t be 0 or negative») живёт в PriceWeekdayInfo, но этот тип нигде не создаётся (ноль вхождений new PriceWeekdayInfo во всём коде). Реальный путь создания/изменения цены использует TimeWithWeekdaysPrice, у которого проверок стоимости нет вовсе. Итог: при создании цены стоимость не проверяется ни на ноль, ни на отрицательность, а сам текст проверки противоречит её условию (0 проходит). — нужно решение: допустима ли нулевая/отрицательная стоимость; включить проверку на рабочем типе и согласовать текст.PriceWeekdayInfo.cs:18 (не используется); TimeWithWeekdaysPrice.cs:17-23 (без проверок); CreatePriceCommand.cs:26
П5BR2.6-13Нельзя сохранить цену с пустыми обязательными параметрами (обязательны только площадка и стоимость).Строже BRD по одним полям и слабее по другим. Обязательность площадки/зоны обеспечивается (Create возвращает null без scope, в обработчике бросок при пустом scope), имя проверяется на непустоту, приоритет/мин.длительность/доплата — на неотрицательность. При этом Name, Priority, MinOrderDuration фактически обязательны — это строже BRD (BRD требует обязательными только площадку и стоимость). Одновременно сама «стоимость» по слоту не валидируется (см. П4). — нужно решение: считать ли название/приоритет/мин.длительность обязательными.PriceAggregate.cs:92 (scope обязателен); PriceInfo.cs:24 (Name), :25-27 (Priority/MinOrderDuration/доплата)
П6BR2.6-12Результат массовой операции должен позволять определить, какие цены обработаны успешно, какие — с ошибкой.Массовые Update/Delete выполняются в одной транзакции и бросают исключение на первой проблемной цене с откатом всего пакета — частичного результата «эти ок, эти нет» нет. Оба обработчика возвращают Unit; список успешных/ошибочных id не возвращается. — нужно решение: нужен ли частичный результат (тогда отказаться от общей транзакции в пользу пер-элементного результата).UpdatePriceCommandHandler.cs:134 (бросок на первом конфликте), :148 (откат всего пакета); DeletePriceCommandHandler.cs:72 (возврат Unit)
П7вне BRDВ BRD не описан «мёртвый»/дублирующий код и служебные пути архивации.Для навигации и доверия к последующим сверкам: src/Repositories/PriceRepository.cs (namespace PriceCalculator.Repositories) не входит ни в один проект и не используется — живой репозиторий цен другой (Prices.Persistence/Repositories/PriceRepository.cs, подключён в DI). Плюс методы ArchiveAsync/RestoreAsync живого репозитория (прямой ExecuteUpdate архивного флага) существуют, но обработчиками не вызываются — архивация идёт через PriceAggregate.Update по флагу. — нужно решение: удалить мёртвый код и/или неиспользуемые пути, чтобы не порождать ложные трактовки.Repositories/PriceRepository.cs (вне сборки); Prices.Persistence/Repositories/PriceRepository.cs:103-125 (Archive/RestoreAsync не вызываются); Program.cs:186 (DI живого репозитория)

Рекомендация / варианты решения

  • Гонка при проверке уникальности (П1) — инвариант BR2.6-14 держится только на проверке в приложении внутри транзакции, без ограничения в базе. Вариант А (рекоменд.): добавить запрет дублей в базе (уникальное ограничение/частичный уникальный индекс по нормализованному набору условий применения) как страховку от гонки, оставив проверку в приложении для дружелюбных сообщений. Вариант Б: если полноценное ограничение в базе невозможно из-за сложности набора условий (диапазоны, массивы дней) — сериализовать конкурентные записи по партнёрской зоне (блокировка/advisory-lock на время проверки+вставки) и это явно задокументировать. Голая проверка в приложении без страховки — недостаточна для правила веса 1.
  • Слот до полуночи (П2) и состав условий конфликта — мин. длительность/приоритет (П3) — оба про корректность самой проверки ArePropertiesUnique. По П2: вариант А (рекоменд.) — исправить обработку TimeTo == 00:00 (трактовать как конец суток) и убрать бессмысленный тернарник; вариант Б — если 00:00 намеренно означает «полночь начала», задокументировать и покрыть тестом. По П3: сначала бизнес-решение (входят ли мин. длительность и приоритет в условия применения — см. также природу BR2.6-14), затем привести список полей в ArePropertiesUnique в соответствие с этим решением.
  • Стоимость не валидируется (П4) — рекоменд.: перенести проверку стоимости на реально используемый тип TimeWithWeekdaysPrice (или в конструктор агрегата/обработчик), согласовав с продуктом допустимость нуля, и привести текст сообщения в соответствие с условием. Пока проверка стоит на неиспользуемом PriceWeekdayInfo, она не работает вовсе.
  • Обязательность полей строже BRD (П5) — упирается в бизнес-решение по BR2.6-13 (какие поля действительно обязательны). Вариант А (рекоменд.): согласовать перечень обязательных полей и привести код к нему (если название/приоритет/мин.длительность обязательны намеренно — обновить BR2.6-13, это вариант «привести BRD к коду»). Вариант Б: ослабить валидацию до «только площадка и стоимость», если BRD верен буквально. Связать с П4 (стоимость сейчас не проверяется вовсе).
  • Нет частичного результата массовой операции (П6) — упирается в бизнес-решение по BR2.6-12 (нужна ли частичность). Вариант А: если частичный результат обязателен — отказаться от «всё или ничего» в пользу пер-элементной обработки с возвратом статуса по каждой цене (ломает текущую транзакционную атомарность). Вариант Б (рекоменд. как временный): сохранить атомарность, но возвращать в ошибке идентификаторы всех проблемных цен, чтобы вызывающая сторона могла показать, что именно не прошло. Финальный выбор — за продуктом.
  • Мёртвый/дублирующий код (П7) — рекоменд.: удалить не входящий в сборку PriceCalculator.Repositories/PriceRepository.cs и неиспользуемые ArchiveAsync/RestoreAsync (или переключить архивацию на них, если это целевой путь). Снижает риск ложных выводов при будущих сверках; на поведение системы сейчас не влияет.

0 items under this folder.