diff --git a/docs/superpowers/specs/2026-06-19-g1-sp3c-full-requisites-frontend-design.md b/docs/superpowers/specs/2026-06-19-g1-sp3c-full-requisites-frontend-design.md new file mode 100644 index 00000000..d0939c83 --- /dev/null +++ b/docs/superpowers/specs/2026-06-19-g1-sp3c-full-requisites-frontend-design.md @@ -0,0 +1,136 @@ +# G1/SP3c — полные платёжные реквизиты (фронт) — дизайн + +**Дата:** 19.06.2026 +**Статус:** дизайн утверждён владельцем (брейншторм) +**Спринт:** G1/SP3c. Предшественники: SP1 (самозапись), SP2 (бэкенд реквизитов+гейт), SP3a (фронт входа), SP3b (лёгкая форма реквизитов + гейт). +**Граница:** только фронт. Бэкенд (поля + валидация) готов в SP2, не меняется. + +--- + +## 1. Цель + +Дать клиенту возможность дозаполнить **полные платёжные реквизиты** (КПП / ОГРН / +юр.адрес / банковские реквизиты) — для будущего этапа оплаты (счёт/договор). +Расширяет ту же вкладку «Реквизиты» из SP3b, добавляя блок ниже лёгких полей. + +`requisites_completed_at` бэкенд ставит при заполнении расчётного счёта +(`RequisitesService::upsert`). Пока этот флаг **не потребляется** никаким +гейтом оплаты (этап оплаты — будущее); в SP3c он используется только для +информативного чипа-статуса. + +--- + +## 2. Готовый бэкенд (контракт, не меняем) + +Все поля уже есть в таблице `tenant_requisites` (миграция SP2) и в +`RequisitesResource`. Эндпоинты — те же `GET/PUT /api/tenant/requisites` +(SP3b api-обёртка `getRequisites`/`updateRequisites` уже их покрывает; новых +api-функций не нужно). + +**Поля (nullable) и форматы валидации** (`UpdateRequisitesRequest`): +- `kpp` — `regex:/^\d{9}$/` +- `ogrn` — `regex:/^(\d{13}|\d{15})$/` +- `legal_address` — `string` (nullable) +- `bank_name` — `string` max:255 +- `bank_bik` — `regex:/^\d{9}$/` +- `bank_account` — `regex:/^\d{20}$/` +- `corr_account` — `regex:/^\d{20}$/` + +**`requisites_completed_at`**: ставится в `now()` если `bank_account` заполнен, +иначе `null` (`RequisitesService::upsert`). Возвращается в `RequisitesResource`. + +`Requisites`-интерфейс (`api/requisites.ts`, SP3b) **уже включает** все эти поля — +менять api-слой не нужно. + +--- + +## 3. Что добавляем во фронте + +Только расширение `app/resources/js/views/settings/RequisitesTab.vue`. Новых +файлов, роутов, api-функций, правок бэкенда — нет. + +### 3.1. Блок «Реквизиты для оплаты» + +Ниже лёгких полей (после строки контакт/ИНН) — отдельный блок: + +- Заголовок «Реквизиты для оплаты (для счёта и договора)». +- **Чип-статус** рядом с заголовком: + - 🟢 `color="success"` «Готово к оплате» — если `form.requisites_completed_at` заполнен; + - ⚪ `color="default"`/grey «Не заполнено» — иначе. +- Поясняющая подпись: «Нужны для выставления счёта и договора. Можно заполнить позже.» + +### 3.2. Поля по типу лица + +Видимость завязана на `form.subject_type` (computed-флаги): + +- **legal_entity (Юрлицо):** КПП · ОГРН · Юр.адрес · Наименование банка · БИК · Р/с · К/с +- **sole_proprietor (ИП):** ОГРНИП *(поле `ogrn`)* · Юр.адрес · Наименование банка · БИК · Р/с · К/с — **без КПП** +- **individual (Физлицо):** Наименование банка · БИК · Р/с · К/с — **без КПП/ОГРН/юр.адреса** + +Лейбл поля `ogrn`: «ОГРН» для ЮЛ, «ОГРНИП» для ИП. + +### 3.3. Валидация (клиент зеркалит бэкенд) + +Все платёжные поля **необязательные**. Проверка только если поле заполнено: +- `kpp` — ровно 9 цифр; +- `ogrn` — для ЮЛ ровно 13 цифр, для ИП ровно 15 цифр (UI-уточнение; бэкенд + принимает 13 или 15); +- `bank_bik` — ровно 9 цифр; +- `bank_account`, `corr_account` — ровно 20 цифр. + +Клиентская проверка добавляется в существующий `validateClient()` (SP3b) — он +по-прежнему сначала проверяет обязательные лёгкие поля, затем (если заполнены) +платёжные форматы. Серверные `422` раскладываются по полям (механизм SP3b). + +### 3.4. Данные / поведение + +- `GET` (onMounted, SP3b) уже предзаполняет все поля, включая платёжные. +- `PUT` (`save()`, SP3b) уже отправляет всю форму целиком — платёжные поля + уедут вместе с лёгкими. +- После сохранения `Object.assign(form, updated)` (SP3b) обновит + `requisites_completed_at` → чип перерисуется. + +--- + +## 4. Обработка ошибок + +- `422` с полевыми `errors` → раскладка по полям (готово в SP3b `save()`). +- Прочие → общий `saveError` через `extractErrorMessage` (готово в SP3b). +- Отдельной обработки SP3c не требует. + +--- + +## 5. Верификация + +vitest сломан (G8). Проверяем: + +- `npm --prefix app run type-check` (`vue-tsc`) = exit 0. +- eslint по `RequisitesTab.vue` = 0 ошибок. +- `npm --prefix app run build` = успех (перед Playwright обязательна пересборка). +- **Живой Playwright (обязательно):** + 1. Клиент из SP3b (лёгкие реквизиты есть) → вкладка реквизитов; чип «Не заполнено». + 2. Тип «ИП» → видны ОГРНИП + юр.адрес + банк, КПП скрыт; заполнить валидно + (ОГРНИП 15 цифр, БИК 9, р/с 20, к/с 20) → Сохранить → чип «Готово к оплате». + 3. Тип «Юрлицо» → появляется КПП (9 цифр); тип «Физлицо» → КПП/ОГРН/юр.адрес + скрыты, остаётся только банк (проверка видимости по типу). + 4. Негатив: БИК `8 цифр` → видимая ошибка под полем. + +--- + +## 6. YAGNI / границы + +- НЕ трогаем бэкенд (поля и валидация готовы в SP2). +- НЕ добавляем api-функции (SP3b обёртка уже шлёт всю форму). +- НЕ делаем кросс-полевую обязательность банковского набора (бэкенд этого не + требует; `requisites_completed_at` ставится по `bank_account`). Чип честно + отражает бэкенд-правило. +- НЕ делаем гейт оплаты (этап оплаты — будущий эпик). +- НЕ чиним сторонние находки (register-500, стейл-тест, NBSP-lint). + +--- + +## 7. Затрагиваемые файлы + +| Файл | Действие | +|---|---| +| `app/resources/js/views/settings/RequisitesTab.vue` | правка — +блок платёжных реквизитов, +чип-статус, +валидация платёжных полей |