BR 3.3 — Admin Franchise web

Источники

Задачи

API клиенты

  • api/paykeeper.ts — функции listAccounts, getAccount, createAccount, updateAccount, suspendAccount, resumeAccount, deleteAccount, testConnection, getLogs, listTerminals, createTerminal, updateTerminal, deleteTerminal

Вкладка «PayKeeper» в карточке ЮЛ

Файл: pages/legal-entities/PaykeeperTab.tsx (или как сложится по структуре)

  • Роутинг — добавить вкладку в LegalEntityViewPage.tsx
  • Empty state — «Подключите PayKeeper»
  • Форма подключения (модалка):
    • Поля: pk_server_host, pk_login, pk_password (password input с «глазик»), informer_seed (password input), paykeeper_id (опц.)
    • Клиентская валидация regex для host
    • Submit: POST /api/v1/admin/paykeeper/accounts
    • При 422 PK_CONNECTION_FAILED — красная подсказка с текстом от PK
    • При 201 — модалка «Интеграция создана» с 3 webhook URL’ами и кнопками «Копировать»
  • Состояние «подключено» — карточка с данными + кнопки Webhook URLs, Журнал, Проверить, Редактировать, Приостановить, Удалить
  • Модалки подтверждения для Suspend / Delete
  • Подвкладка «Журнал» — таблица webhook_log с фильтрами + пагинация
  • Permission guards: integrations.read для просмотра, integrations.manage для действий

Секция «Терминал PayKeeper» в карточке ТТ

Файл: pages/stores/PaykeeperTerminalSection.tsx

  • Загрузка: GET /api/v1/admin/paykeeper/terminals?store_id=X
  • Если у ЮЛ нет активной PK-интеграции (GET /api/v1/admin/paykeeper/accounts/by-legal-entity/{legal_entity_id} возвращает status=not_configured/suspended) — секция скрыта
  • Empty state — «Терминал не привязан» + кнопка (при integrations.manage)
  • Форма привязки — модалка с pk_terminal_id, pk_mpos_merchant_id, label
  • Состояние «привязана» — блок с полями + кнопки Редактировать / Отвязать
  • Интеграция в StoreViewPage.tsx — добавить рендер <PaykeeperTerminalSection /> после <IntegrationsSection />

Секция «Фискальные атрибуты» в форме товара

Файл: pages/catalog/ProductEditPage.tsx (и Create)

  • Три <select>:
    • Ставка НДС (vat_rate) — 6 опций
    • Предмет расчёта (payment_subject) — 9 опций
    • Способ расчёта (payment_type) — 7 опций
  • Значения по умолчанию при создании: vat20, goods, full
  • В режиме view — отображение под секцией «Кухня»: строки «Ставка НДС: 20%», и т.д.
  • Включено в payload POST/PATCH
  • Translations для enum значений (catalog.vat_rate.none = «Без НДС», etc.)

Карточка заказа — PK-блоки

Файл: pages/orders/OrderDetailPage.tsx

  • Секция «Возвраты» — список refunds[] с бейджами статуса
  • Автообновление: polling GET /api/v1/admin/orders/:id каждые 10 сек пока есть refund со status=started
  • Кнопка «Вернуть» в шапке (видима по orders.refund + pk_payment_id != null)
  • Модалка возврата:
    • Radio: полный / частичный
    • Если частичный — список позиций с чекбоксами и qty
    • Поле «Причина» (textarea)
    • Кнопка «Вернуть» → POST /api/v1/admin/orders/{id}/refund
  • Секция «Фискальные данные» (если fiscal_data != null):
    • 6 строк: ФПД, ФД, ФН, РН ККТ, смена, чек
    • Ссылка «Открыть чек» — формирует URL из pk_server_host + pk_payment_id + fop_receipt_key
  • Бейдж «Фискализация не удалась» если fiscal_failed=true

Layout / меню

Нет новых пунктов меню — PK-интеграция вся embed’ится в существующие карточки.

Styling

  • Использовать токены Альфы (colors.red для акцентов, fonts.body, и т.д.) по skill /alfa-restyle — через импорт из lib/tokens.ts

Тесты

  • Smoke: вкладка «PayKeeper» открывается, форма работает, модалка «Интеграция создана» показывает URL’ы
  • Smoke: секция в карточке ТТ — привязка и отвязка
  • Manual e2e: полный flow создания PK-аккаунта → привязка ТТ → создание тестового заказа → оплата → видим фискалку

Критерии приёмки

  • Можно подключить PK-аккаунт через UI, получить 3 webhook URL
  • Можно привязать ТТ к терминалу через UI
  • Товар — все 3 фискальных поля редактируются
  • Карточка заказа — отображает фискальные данные и позволяет инициировать возврат
  • Все permission guards работают (менеджер ТТ не видит кнопок editировать, только статус)