Требования сформированы для обсуждения. Не начинать реализацию — сначала проходит /verify. Эталон структуры: BR 3.4.
Контекст
Кассиры в нашем ERP (employees в User Service) и в ЛК PayKeeper (user/operator) — это две разные сущности. Подробнее в трекере PK.
Реальный кейс: клиент уже использовал кассу 3-в-1 PayKeeper до подключения нашего ERP. У него в ЛК PK заведено 5–30 кассиров. При подключении ERP не хочется перебивать руками — нужна функция «Выгрузить из PK» по требованию владельца, чтобы достать существующих и связать/импортировать их в наш ERP.
POC API подтверждён (2026-04-27)
Endpoint GET /info/organization/users/ работает программно через Basic auth (те же pk_login/pk_password что используются для IMS API). Реальный пример ответа:
Дать владельцу франшизы кнопку «Выгрузить из PK» в админке. По нажатию — pull списка кассиров из ЛК PK, показ диффа с существующими employees, wizard дозаполнения недостающих полей, импорт пакетом.
Принцип: при подключении ERP к PK ничего не происходит автоматически. Импорт — только по явному действию владельца.
§1. Скоуп
1.1. Что синхронизируем
Из ЛК PK тянем только пользователей (raw response endpoint’а /info/organization/users/):
Поле PK
Тип
Куда идёт у нас
id
string
paykeeper_users.pk_user_id (mapping)
login
string
paykeeper_users.pk_login (для матча с user_login в чеках от PK)
email
string | null | ""
employees.email (если null/пусто — wizard просит ввод)
fio
string | null | ""
first_name + last_name (wizard разбирает по пробелу + ручная корректировка)
admin
”true”/“false”
информационно показываем владельцу, не маппим в наши permissions
refund
string число
не используем
invoices_only
bool
не используем
1.2. Что НЕ входит
❌ Auto-push «новый сотрудник у нас → создать в PK» — отдельная BR (3.6 если будет)
❌ Reverse-webhook от PK на изменение user в ЛК → к нам (PK не обещал такой webhook)
❌ Удаление user в PK при удалении employee у нас — отдельная BR
❌ Автоматический pull при подключении ERP к PK — только по нажатию кнопки
❌ Периодический cron-pull — на старте не нужен; добавим в P1 если будет запрос
❌ Двусторонний sync (PK правит → ERP обновляет и наоборот) — слишком сложно, конфликты, не нужно для MVP
§2. Сценарий использования
Владелец франшизы открывает раздел «Сотрудники» в админке
Видит кнопку «Выгрузить из PK» (рядом с «Добавить сотрудника»)
Нажимает → spinner → backend вызывает PK API → возвращается список кандидатов с предварительным матчингом
Wizard показывает таблицу:
Каждая строка — один пользователь PK
Колонки: login, email, fio, admin, статус матча, действие
Статус матча: 🟢 Match by email (есть наш employee с тем же email) / ⚪ New (нет совпадений)
Владелец per-row выбирает действие:
Для Match — 4 опции (см. §3)
Для New — открывается форма дозаполнения (см. §4)
Submit — пакетный импорт, отчёт о результатах:
N создано, M связано, K пропущено, L ошибок
История прогонов доступна по кнопке «Журнал импортов»
§3. Дубли email — 4 опции владельца
Когда pk_user.email совпадает с существующим employees.email (в рамках franchise_id):
Опция
Что происходит
Связать
Создаём mapping paykeeper_users(pk_user_id, employee_id). Existing employee не меняется.
Создать нового
Wizard просит ввести альтернативный email → POST /employees с новыми данными
Пропустить
Ничего не делаем; в журнал импорта пишется skipped: duplicate email, owner choice
Обновить
PATCH /employees/{id}: записываем login в mapping, fio → first/last_nameтолько если у нас эти поля пустые (не перезаписываем непустое)
§4. Дозаполнение полей (wizard для New)
PK даёт минимум — обязательные поля employees дозаполняет владелец:
Поле employee
Из PK
Wizard
first_name, last_name
split fio по пробелу
Можно скорректировать
email
прямой
Если пусто/null — обязательный ввод
password
—
Опции: «Сгенерировать + reset-link на email» / «Ввести вручную»
franchise_id
—
из JWT, автоматически
phone
—
Опционально, ручной ввод
pin (для POS)
—
Опционально
is_courier
—
Дефолт false
roles[] + role_store_mappings
—
Multi-select из активных permissions-ролей + per-role выбор ТТ
§5. Ролевая модель
Импорт сотрудников из PK — операция уровня владельца ЛК.
Действие
Владелец франшизы
Владелец партнёра
Менеджер ТТ
Кассир
Видеть кнопку «Выгрузить из PK»
✅
✅ (только по своим ЛК PK)
❌
❌
Запустить импорт
✅
✅
❌
❌
Видеть журнал импортов
✅
✅ (свои ЛК)
❌
❌
Permission: paykeeper.users.import (новый, только в наборах системной роли «Администратор» и владельца партнёра).
§6. Сущности (бизнес-уровень)
Технические таблицы — в 03-Services/Paykeeper Adapter/Data Model.md.
paykeeper_users — связь нашего employee с пользователем PK:
pk_user_id (id из PK)
pk_login (для матча с user_login в чеках от PK)
employee_id (FK)
account_id (какой ЛК PK)
UNIQUE (account_id, pk_user_id) — один pk_user в одном ЛК = одна запись
UNIQUE (account_id, employee_id) — один employee связан только с одним pk_user в данном ЛК
paykeeper_user_imports — история прогонов:
Когда запущено, кем, статус, сколько создано / связано / пропущено / ошибок
paykeeper_user_import_users_total{action} — кол-во импортированных по типу действия (created / linked / skipped / errored)
Алерт: PK API недоступен >5 мин при попытке импорта → admin notification
§8. Открытые вопросы
admin: true в PK — игнорировать или предложить владельцу галочкой «Выдать роль Администратор у нас»? Дефолт: игнорировать, наша permissions-модель глубже плоского флага PK. Решить на kick-off.
Системные пользователи PK (login: admin, login: user) — импортировать или пропускать? Дефолт: показываем с пометкой «системный пользователь PK», владелец сам решает.
Phone — PK не отдаёт. Дозаполнение через wizard — ОК, либо запросить у PK (низкий приоритет).
Пагинация — на практике ≤30 пользователей в ЛК. Если у крупной франшизы >100 → нужна постраничность wizard’а. Решим позже на основе реальных данных.
Match by login + email — что если у нас уже есть employee с тем же email и другим login в PK (могло сложиться при прошлом ручном дублировании)? Дефолт: по email, login остаётся как metadata в mapping.
Reverse — мы создаём employee → нужно ли тут же предлагать создать в PK? В §1.2 это вынесено в отдельную BR; но возможно стоит здесь добавить чек-бокс «также создать в ЛК PK» при создании employee — простая фича, экономит шаг владельцу.
07-Tasks/PayKeeper Integration/Требования к PayKeeper.md — зафиксировать GET /info/organization/users/ как подтверждённый рабочий (POC сделан 2026-04-27); добавить в открытые вопросы — отдаёт ли PK поле phone где-то ещё