Направление работ: Mobile Код раздела: 5.8 Раздел: Профиль > Скидки Статус: черновик Ответственный: Панкова Л.А. Версия: 0.1 Обновлено: 29.07.26
1. Назначение
Раздел обеспечивает пользователю мобильного приложения интерфейс для просмотра доступных ему промокодов.
Пользователь видит активные скидки, срок и область их действия, размеры скидки на время и дополнительные позиции, а также условия активации.
Пользователь может скопировать промокод для последующего применения при оформлении заказа. Раздел зависит от Back 2.7.1 Объекты и предложения > Скидки > Акции и промокоды.
2. Ключевые понятия
Скидка — уменьшение стоимости заказа при выполнении заданных условий.
Промокод — доступный пользователю код ручной скидки, который можно скопировать из карточки для последующего применения при оформлении заказа.
Область действия промокода — партнерская зона, объекты и площадки, для заказов в которых доступен промокод.
Условия активации — отображаемые в карточке параметры заказа, при соблюдении которых может быть применен промокод.
Карточка промокода — представление промокода в разделе “Мои скидки” с данными партнера, областью и сроком действия, кодом, размерами скидки и доступными условиями активации.
3. Scope
Входит
S1: Просмотр списка активных скидок и промокодов, включая варианты карточек по области действия.
S2: Работа с карточкой промокода и условиями активации.
S3: Состояния загрузки и отсутствия доступных скидок.
Не входит
- Mobile 5.1 Профиль > Главный экран — отображение действия “Мои скидки” в профиле и переход в раздел.
- Mobile 2.6 Поиск > Итоговая информация о заказе — ввод и применение промокода при оформлении заказа.
- WebLk 4.6 Контент > Скидки и акции и Back 2.7.1 Объекты и предложения > Скидки > Акции и промокоды — создание, редактирование, назначение и расчет скидок и промокодов.
- Архивные и неактивные скидки.
4. BR
Указаны в пункте 4 раздела Back 2.7.1 Объекты и предложения > Скидки > Акции и промокоды.
5. Функциональные требования (UC + FR)
| ID | Сценарий | Функциональное требование | BR | Вес | Статус |
|---|---|---|---|---|---|
| S1: FR5.8-1 | Пользователь открывает раздел скидок. | Интерфейс открывает экран “Мои скидки” и отображает действие возврата, раздел “Активные” и доступные пользователю карточки промокодов. | 1 | Частично OQ5.8-4 | |
| S1: FR5.8-2 | Пользователь возвращается с экрана “Мои скидки”. | По действию возврата интерфейс закрывает экран “Мои скидки” и возвращает пользователя на предыдущий шаг. | 1 | Реализовано | |
| S1: FR5.8-3 | Пользователь просматривает активный промокод. | Интерфейс отображает в карточке данные партнера, срок и область действия промокода, код с действием копирования, размеры скидки “Время” и “Позиции”, а также действие “Подробнее”, если для промокода заданы условия активации. | 1 | Частично OQ5.8-8, OQ5.8-12 | |
| S1: FR5.8-4 | Пользователь просматривает промокод с разной областью действия. | Интерфейс адаптирует карточку к области действия промокода: показывает логотип партнерской зоны для промокода партнерской зоны, фотографию объекта для промокода одного объекта или фотографию площадки для промокода одной площадки. Интерфейс отображает признак действия на все объекты либо названия доступных объектов и площадок в соответствии с областью действия промокода. | 1 | Частично OQ5.8-4, OQ5.8-5, OQ5.8-6 | |
| S1: FR5.8-5 | Пользователь просматривает промокод для нескольких объектов или площадок. | Интерфейс позволяет раскрыть полный перечень объектов или площадок, на которые распространяется промокод, и повторным действием свернуть перечень. | 2 | Частично OQ5.8-6, OQ5.8-7 | |
| S2: FR5.8-6 | Пользователь копирует промокод. | По действию копирования интерфейс сохраняет код выбранного промокода в буфер обмена устройства. | 1 | Реализовано OQ5.8-15 | |
| S2: FR5.8-7 | Пользователь открывает условия активации промокода. | По действию “Подробнее” интерфейс раскрывает в карточке блок “Условия активации” и заменяет действие раскрытия действием сворачивания блока. | 2 | Реализовано OQ5.8-16 | |
| S2: FR5.8-8 | Пользователь просматривает условия активации промокода. | Интерфейс отображает только заданные для промокода условия: время действия, дни недели, опции заказа и их значения, минимальную длительность заказа и порядок действия “Заранее” или “День в день”. Несколько временных интервалов отображаются отдельными значениями. | 1 | Частично OQ5.8-1, OQ5.8-2, OQ5.8-3, OQ5.8-14 | |
| S2: FR5.8-9 | Пользователь сворачивает условия активации промокода. | По действию сворачивания интерфейс скрывает блок “Условия активации” и возвращает карточку в исходное состояние с действием “Подробнее”. | 2 | Реализовано OQ5.8-16 | |
| S2: FR5.8-10 | Пользователь просматривает промокод без условий активации. | Интерфейс не отображает в карточке пустой блок “Условия активации” и действие “Подробнее”. | 2 | Не реализовано OQ5.8-8 | |
| S2: FR5.8-11 | Пользователь открывает пояснение к порядку действия промокода. | По информационному действию рядом с условием “Порядок действия” интерфейс показывает нижнюю панель с пояснениями: “Заранее” — “Бронирование совершается за день или более до начала заказа”. ”День в день” — “Бронирование совершается в день начала заказа”. | 2 | Реализовано OQ5.8-9 | |
| S3: FR5.8-12 | Загружается список скидок. | До получения данных интерфейс отображает плейсхолдер заголовка раздела и плейсхолдеры карточек промокодов. | 2 | Не реализовано OQ5.8-10 | |
| S3: FR5.8-13 | У пользователя нет доступных скидок. | Интерфейс отображает пустое состояние с сообщениями “У вас пока нет скидок” и “Здесь будут отображаться все доступные скидки от партнеров”. | 2 | Реализовано OQ5.8-16 |
6. Открытые вопросы
Сверка с кодом: BRD 5.8 v0.1 · репозиторий
booking.mobile.flutter· commit2b93d4f/origin/main· 08.09.26 · якорьlib/src/feature/profile_page/personal_discounts/Сводка: 16 вопросов (Open 14 · Подтверждено 2) Маршрутизация без сверки с гайдбуком (гайдбук не передавался). Повторная сверка по итогам дейликов (08.09.26). Предыдущая сверка — 31.07.26, commitb44cfa2. Междуb44cfa2и2b93d4fякорьlib/src/feature/profile_page/personal_discounts/тронул только один коммит —0d2c5cb "dart format"(31.08.26) — это чисто форматирование (перенос строк/отступы), без изменения логики (git diff --ignore-all-space b44cfa2 2b93d4f -- lib/src/feature/profile_page/personal_discounts/не показывает содержательных изменений). Бэкенд-файлы, упомянутые в доказательствах (PromoDateRangeMapper.cs,GetMyPromocodesQuery.cs), также не менялись с 25.07.26. Все статусы и доказательства ниже перепроверены по актуальному коду точечно (см.5.8-mobile.changes.md) и оставлены без изменений.
| ID | Источник | Вопрос | Кому | Статус | Рекомендации | Итоговое решение |
|---|---|---|---|---|---|---|
| OQ5.8-1 | Код FR5.8-8 | Требование говорит: в условиях активации выводится порядок действия — «Заранее» или «День в день». В коде значение подставляется наоборот: серверный признак «день в день» приложение показывает как «Заранее», а его отсутствие — как «День в день». На сервере этот признак означает, что скидка действует только в день оформления заказа, и приложение сообщает пользователю ровно противоположное. То есть у промокода, который работает только при бронировании день в день, пользователь увидит «Заранее», и наоборот. \ personal_discounts_cubit.dart:124-127 (подстановка текста), PromoDateRangeMapper.cs:74-81 бэкенда (при истинном признаке период скидки обрезается до сегодняшнего дня) | Разработка | Open | Завести тикет в Bitrix: поменять ветки местами — истина «День в день», ложь «Заранее». Продуктового выбора нет: тексты пояснений уже согласованы в FR5.8-11 и подтверждают именно такую трактовку. | поменять ветки местами |
| OQ5.8-2 | Код FR5.8-8 | Требование говорит: среди условий активации показывается минимальная длительность заказа. В коде это условие собирается, но ни разу не выводится на экран: строка «Заказ от N ч.» формируется в логике экрана и дальше нигде не используется — блок условий рисует только время, дни недели, опции и порядок действия. Сервер значение отдаёт, то есть нехватка данных тут ни при чём. Дополнительно строка собирается всегда, даже когда значение не задано, и в этом случае в неё попадёт пустышка вместо числа. \ personal_discounts_cubit.dart:119-121 (строка собирается), promocode_tile.dart:242-316 (в разметке блока её нет), GetMyPromocodesQuery.cs:269 бэкенда (значение приходит с сервера) | Разработка | Open | Завести тикет в Bitrix: добавить блок «Заказ от» в разметку условий активации и не собирать его, когда значение пустое. | добавить блок «Заказ от» в разметку условий активации |
| OQ5.8-3 | Код FR5.8-8 | Требование говорит: в условиях активации показываются опции заказа и их значения. В коде название опции и количество выводятся только парой: если у промокода есть названия опций, но не задан диапазон количества, не показывается ничего, и наоборот. Названия всех опций склеиваются в одну строку с заголовком «Вид работ», а диапазон берётся только у первой опции, где он заполнен, — диапазоны остальных теряются. Заголовок второго блока жёстко зашит как «Кол-во человек», хотя опция может называться иначе, например «Количество детей». Есть и риск падения: если у опции обе границы диапазона равны нулю, экран уходит в ошибку. \ promocode_tile.dart:272-295 (показ только парой), personal_discounts_cubit.dart:62-86 (склейка названий и только первый диапазон), personal_discounts_cubit.dart:79-82 (принудительное разыменование пустого значения) | Разработка | Open | Завести тикет в Bitrix: выводить блок названий и блок количества независимо друг от друга, брать заголовок количества из названия опции и показывать диапазон по каждой опции. Заодно убрать принудительное разыменование, чтобы нулевой диапазон не ронял экран. | выводить блок названий и блок количества независимо друг от друга |
| OQ5.8-4 | Код FR5.8-1, FR5.8-4 | Проблема: промокод, выданный на всю партнёрскую зону без указания объектов, ломает весь экран скидок, а не одну карточку. Сервер в таком случае присылает пустой список объектов, а приложение ждёт либо непустой список, либо полное отсутствие поля, и сразу берёт из списка «первый объект» — на пустом списке это ошибка отрисовки. Ветка, в которой должен показываться признак действия на всю зону, написана на проверку отсутствия поля и с реальными данными не срабатывает никогда. В ней же вместо признака «все объекты» из требования выводится «Все площадки». \ base_and_rooms.dart:152 (обращение к первому объекту), base_and_rooms.dart:165-170 и :203-233 (недостижимая ветка и её текст), GetMyPromocodesQuery.cs:300-320 бэкенда (объекты отдаются пустым списком, а не отсутствием) | Разработка | Open | Завести тикет в Bitrix: трактовать пустой список объектов так же, как его отсутствие, и в этой ветке выводить признак действия на все объекты вместо «Все площадки». Проверять на промокоде, выданном на партнёрскую зону целиком. | трактовать пустой список объектов так же, как его отсутствие, и в этой ветке выводить признак действия на все объекты вместо «Все площадки». Проверять на промокоде, выданном на партнёрскую зону целиком. |
| OQ5.8-5 | Код FR5.8-4 | Требование говорит: карточка подстраивается под область действия — логотип партнёрской зоны, фотография объекта или фотография площадки. В коде такой логики нет: приложение берёт первый попавшийся файл из общего списка картинок промокода, никак не разбирая, чей это логотип. Сервер при этом складывает в один список логотипы всех объектов партнёрской зоны, затем логотип самой зоны и только в конце фотографии площадок, поэтому первой почти всегда оказывается картинка какого-то объекта, а фотография площадки не покажется никогда. Если картинок нет вовсе, вместо изображения выводится системная иконка «нет фото». \ promocode_tile.dart:60-64 (берётся первый файл с ссылкой), promocode_tile.dart:81-92 (заглушка при отсутствии картинок), GetMyPromocodesQuery.cs:232-259 бэкенда (состав и порядок списка картинок) | Разработка | Open | Завести тикет в Bitrix: согласовать с бэкендом признак принадлежности картинки и выбирать изображение по области действия промокода. Отдельно предусмотреть аккуратную заглушку вместо системной иконки. | Жду решения бизнеса, тут нужно с бэкэндом поговорить. |
| OQ5.8-6 | Код FR5.8-4, FR5.8-5 | Требование говорит: карточка показывает названия доступных объектов и площадок, а перечень можно раскрыть и свернуть. В коде у промокода, охватывающего больше одного объекта, названия площадок не выводятся вообще — под каждым объектом всегда стоит «Все площадки», даже если промокод ограничен конкретными площадками. Раскрытие добавляет остальные объекты, но площадки внутри них так и остаются скрытыми. Пользователь видит область действия шире реальной и при оформлении заказа может столкнуться с тем, что промокод не применяется. \ base_and_rooms.dart:106-131 (площадки скрываются, когда объектов больше одного), base_and_rooms.dart:154-160 (раскрытие работает только по объектам) | Разработка | Open | Завести тикет в Bitrix: выводить названия площадок независимо от количества объектов, а «Все площадки» показывать только тогда, когда площадки действительно не заданы. | выводить названия площадок независимо от количества объектов |
| OQ5.8-7 | Код FR5.8-5 | Проблема: управление раскрытием перечня объектов ведёт себя непоследовательно. Стрелка нарисована наоборот — в свёрнутом состоянии смотрит вверх, в раскрытом вниз, то есть подсказывает противоположное действие. Явная подпись появляется только когда перечень уже раскрыт, а в свёрнутом виде подсказки «показать ещё N объектов» нет — заготовка с таким счётчиком осталась закомментированной. Кроме того, перечень раскрывается и сворачивается нажатием на весь блок с названием партнёра, что в требованиях не описано и срабатывает случайно. \ base_and_rooms.dart:294-298 (перевёрнутая стрелка), base_and_rooms.dart:248-253 и :256-276 (подпись только в раскрытом виде, закомментированный счётчик), base_and_rooms.dart:172-173 (нажатие по всему блоку) | Разработка | Open | Завести тикет в Bitrix: развернуть иконку по состоянию, показывать управление и в свёрнутом виде и определиться с нажатием по всему блоку. Если счётчик «Ещё N» нужен продукту — вынести это отдельным вопросом к бизнесу. | развернуть иконку по состоянию |
| OQ5.8-8 | Код FR5.8-3, FR5.8-10 | Требование говорит: действие «Подробнее» показывается только при наличии условий активации, а пустой блок «Условия активации» не выводится. В коде «Подробнее» есть в каждой карточке без каких-либо проверок, а заголовок «Условия активации» рисуется всегда, как только блок раскрыт. У промокода без временных интервалов, без опций и без признака порядка действия пользователь раскроет блок и увидит один заголовок без содержимого. \ promocode_tile.dart:205-236 (действие показывается безусловно), promocode_tile.dart:242-254 (заголовок без проверки наполнения) | Разработка | Open | Завести тикет в Bitrix: скрывать «Подробнее» и заголовок, когда набор условий пуст. Учесть, что после исправления OQ5.8-2 минимальная длительность станет ещё одним условием и будет приходить почти всегда. | скрывать «Подробнее» и заголовок, когда набор условий пуст |
| OQ5.8-9 | Код FR5.8-11 | Проблема: в нижней панели с пояснениями к порядку действия между двумя абзацами выводится лишняя русская буква «я». Сами тексты пояснений совпадают с требованием дословно, но посреди панели пользователь видит одиночный посторонний символ. Похоже на случайно набранную букву, оставшуюся в вёрстке. \ conditions_sheet.dart:14 (одиночный символ между блоками текста) | Разработка | Open | Завести тикет в Bitrix: удалить лишний символ. Правка на одну строку, продуктового решения не требует. | удалить лишний символ |
| OQ5.8-10 | Код FR5.8-12 | Требование говорит: пока данные грузятся, показываются плейсхолдер заголовка раздела и плейсхолдеры карточек промокодов. В коде на время загрузки выводится анимированный индикатор по центру пустого экрана, а поверх него в отдельных случаях ещё и затемняющая подложка с такой же анимацией — ни заголовка, ни контуров карточек нет. Плейсхолдеры в приложении используются на других экранах, то есть механизм есть и просто не задействован здесь. \ personal_discounts_screen.dart:85-88 (индикатор вместо плейсхолдеров), personal_discounts_screen.dart:42-55 и :76-83 (вторая затемняющая подложка), animation_wait_lottie.dart:9-16 | Разработка | Open | Завести тикет в Bitrix: заменить индикатор на плейсхолдеры заголовка и карточек по образцу других экранов и убрать дублирующую затемняющую подложку. | заменить индикатор на плейсхолдеры заголовка и карточек по образцу других экранов и убрать дублирующую затемняющую подложку |
| OQ5.8-11 | Код (обратный проход) | Что нашли: если запрос за списком скидок не отвечает или падает, экран остаётся в бесконечной загрузке. Обращение к серверу вынесено за пределы обработки ошибок, поэтому сетевой сбой не переводит экран ни в состояние ошибки, ни в пустое состояние. Обработчик к тому же перехватывает не все виды сбоев и пропускает те, что возникают при разборе данных, — например падения из OQ5.8-3 и OQ5.8-4. Экран ошибки в разделе есть, но текст в него передаётся пустой, поэтому пользователь не поймёт, что произошло. \ personal_discounts_cubit.dart:34-40 (запрос вне обработки ошибок), personal_discounts_cubit.dart:135-137 (перехватывается только часть сбоев), personal_discounts_screen.dart:136-139 (пустой текст ошибки) | Разработка | Open | Завести тикет в Bitrix: перенести запрос внутрь обработки ошибок, перехватывать любые сбои и показывать экран ошибки с понятным текстом и возможностью повторить загрузку. | Добавить экран ошибки. |
| OQ5.8-12 | Код FR5.8-3 | Требование говорит: в карточке показывается срок действия промокода. В коде выводится дата окончания ровно в том виде, в каком её прислал сервер, — например «до 31.12.25». На сервере эта дата в период действия не входит: последний день, когда промокодом ещё можно воспользоваться, — предыдущий. Получается, что в последний показанный в карточке день промокод уже не сработает. Нужно решение бизнеса: показывать последний рабочий день или менять формулировку. \ base_and_rooms.dart:58, :100, :197 (вывод даты окончания), GetMyPromocodesQuery.cs:203-205 бэкенда (дата окончания не включается в период) | Бизнес | Open | (А) показывать последний день, когда промокод действует, сохранив формулировку «до» (рекоменд.). (Б) оставить дату как есть и сменить подпись на формулировку, из которой видно, что этот день в срок не входит. После выбора завести тикет в Bitrix. | Вопрос к бизнесу. Я бы это на беке поправил. |
| OQ5.8-13 | Код (обратный проход) | Что нашли: карточка всегда показывает только первую партнёрскую зону промокода. Сервер умеет отдавать промокод, выданный сразу на несколько партнёрских зон, и присылает их списком, но приложение берёт первый элемент, а остальные не отображает. Пользователь не узнает, что промокод действует ещё где-то. В требованиях этот случай не описан, поэтому неясно, бывает ли он на практике и как тогда должна выглядеть карточка. \ promocode_tile.dart:101-103 (берётся первый элемент списка), GetMyPromocodesQuery.cs:292-324 бэкенда (область действия группируется по партнёрским зонам) | Бизнес | Open | (А) подтвердить, что промокод всегда выдаётся в пределах одной партнёрской зоны, и зафиксировать это ограничение в BRD (рекоменд.). (Б) если несколько зон возможны — описать вид карточки для этого случая и завести тикет на отображение всех зон. | Вопрос к бизнесу. |
| OQ5.8-14 | Код (обратный проход) | Что нашли: три мелких дефекта в сборке условий активации, по отдельности безобидных. Первое — дни недели собираются из всех временных интервалов без удаления повторов, поэтому у промокода с двумя интервалами в один и тот же день этот день покажется дважды, а порядок дней берётся из ответа сервера и может не совпадать с порядком недели. Второе — заголовок блока с днями всегда во множественном числе, ветка с единственным написана, но недостижима. Третье — интервал подписывается как «круглосуточно» только когда начало и конец равны ровно «00:00», а запись вида «00:00-24:00» выведется как есть. \ personal_discounts_cubit.dart:91-99 (повторы дней и недостижимая ветка заголовка), personal_discounts_cubit.dart:101-117 (условие «круглосуточно») | Разработка | Open | Завести тикет в Bitrix на техуборку: убирать повторы дней и приводить их к порядку недели, починить или удалить ветку с единственным числом, расширить условие «круглосуточно». Продуктового выбора нет, поведение экрана не меняется. | Нужно исправить. |
| OQ5.8-15 | Код FR5.8-6 | Что подтверждено: копирование промокода работает так, как описано. Нажатие на иконку рядом с кодом кладёт код в буфер обмена устройства и показывает подтверждающее уведомление «Скопировано» с самим кодом. Дополнительно отправляется событие аналитики. \ promocode_tile.dart:135-152 (копирование, уведомление и событие аналитики) | — | Подтверждено | Расхождения нет. | — |
| OQ5.8-16 | Код FR5.8-7, FR5.8-9, FR5.8-13 | Что подтверждено: блок условий активации раскрывается и сворачивается одним и тем же действием с переключением стрелки, то есть повторное нажатие возвращает карточку в исходный вид. Пустое состояние выводит тексты «У вас пока нет скидок» и «Здесь будут отображаться все доступные скидки от партнеров» дословно как в требованиях. Заголовок раздела «Активные» и действие возврата на экране присутствуют. \ promocode_tile.dart:34-43 и :242 (переключение блока условий), personal_discounts_screen.dart:90-98 (пустое состояние), personal_discounts_screen.dart:70 и :105-109 (возврат и заголовок раздела) | — | Подтверждено | Расхождения нет. | — |