POS — Прикрепление клиента к заказу
Источники
- Бизнес: Клиенты § POS flow
- BR: BR 3.1
- API: Customer Service API, Order Service API
Об этом документе
POS-интерфейс (
erp-pos) находится в bootstrap-стадии. Этот документ описывает только flow прикрепления клиента к заказу — другие POS-экраны (сам экран заказа, оплата, смена) ещё не специфицированы. Когда появятся — связать через ссылки.
Flow в одну картинку
┌─── Экран заказа ────────────────────────────┐
│ [🧑 Клиент] ← кнопка если клиент не прикреплён
│ [🧑 Иван Петров · VIP · 🎂 скоро] ← если прикреплён
│ ... │
│ Позиции заказа │
└──────────────────────────────────────────────┘
│ клик «Клиент»
▼
┌─── Модалка «Найти клиента» ─────────────────┐
│ Телефон: [+7 (___) ___-__-__] │
│ │
│ [результаты поиска появляются по мере ввода] │
└──────────────────────────────────────────────┘
│ телефон введён (10 цифр)
▼
GET /pos/customers/search?phone=+7...
│
┌───┴───┐
│ │
найден не найден
│ │
▼ ▼
┌─ найден ─────────────────────────────────────┐
│ Иван Петров │
│ +7 (999) 123-45-67 │
│ Chips: VIP · Клуб ценителей │
│ LTV: 34 500 ₽ · Последний визит 3 дня назад │
│ 🎂 ДР через 5 дней │
│ [Прикрепить к заказу] │
└──────────────────────────────────────────────┘
┌─ не найден — форма quick-create ────────────┐
│ Клиент не найден. Создать нового? │
│ │
│ Телефон: +7 (999) 123-45-67 (уже введён) │
│ Имя: [____________________] │
│ Email (опц): [____________________] │
│ ДР (опц): [__.__.____] │
│ │
│ [Создать и прикрепить] │
└──────────────────────────────────────────────┘
│ после прикрепления
▼
┌─── Экран заказа ────────────────────────────┐
│ [🧑 Иван Петров · VIP] ← клиент прикреплён │
│ ... │
└──────────────────────────────────────────────┘
1. Кнопка «Клиент» на экране заказа
- Располагается в верхней части экрана заказа (деталь расположения в рамках BR по POS)
- Если клиент не прикреплён: иконка 🧑 + текст «Клиент»
- Если клиент прикреплён: иконка 🧑 + имя клиента + chips групп + бейдж «🎂 скоро» (если ДР в ±14 дней)
- Клик — открывает модалку «Найти клиента» (всегда, независимо от того прикреплён сейчас кто-то или нет)
- Рядом — крестик «×» для открепления (виден только если прикреплён)
Видимость кнопки: permission customers.create_quick. Без permission кнопка не отображается.
2. Модалка «Найти клиента»
Поле ввода телефона
- Маска:
+7 (___) ___-__-__ - Автозаполнение первой цифры
+7(или+7, если пользователь вводит8XXX) - Нормализация в E.164 на уровне запроса:
89991234567,79991234567,+7 (999) 123-45-67→+79991234567
Поведение
- Пока введено < 10 цифр номера — состояние
default(никаких запросов) - Как только введено 10 цифр (полный номер) — запускается
GET /pos/customers/search?phone=+7...- Debounce не требуется — запрос один раз после полного ввода
- Пока запрос идёт — состояние
searching(спиннер в области результатов)
Состояние found (клиент найден)
Показывается карточка-мини:
- Имя (крупно)
- Телефон
- Chips групп (максимум 4 видимых)
- LTV:
{total_spent} ₽ - Последний визит:
N дней назад/ «Впервые» - Бейдж «🎂 ДР через N дней» (если ДР в ±14 дней от сегодня)
- Кнопка «Прикрепить к заказу» (большая, основной акцент) → PATCH /pos/orders/{id}/customer
Состояние not_found (клиент не найден)
Показывается сообщение + форма quick-create:
- Заголовок: «Клиент не найден. Создать нового?»
- Поля формы:
- Телефон — readonly (уже введён выше), в виде серого chip «Телефон: +7 (999) …»
- Имя — text input, обязательное, placeholder «Например: Иван»
- Email — text input, опциональное
- ДР — date picker, опциональное
- Кнопка «Создать и прикрепить» → POST /pos/customers (с
registration_source='pos',registered_by_employee_idиз JWT кассира), затем PATCH /pos/orders/{id}/customer- Pre-flight валидация: если имя пустое — кнопка disabled
Состояние creating
- Кнопка «Создать и прикрепить» в loading
- Форма disabled
Состояние attached (успех)
- Toast «Клиент прикреплён: Иван Петров»
- Модалка закрывается автоматически
- Экран заказа перерисовывается с клиентом в шапке
3. Открепление клиента
- Иконка «×» рядом с именем клиента в шапке заказа
- Клик → DELETE /pos/orders/{id}/customer
- Без подтверждающей модалки (операция обратимая — можно тут же прикрепить снова)
- Toast «Клиент откреплён»
Ошибки
| API код | Отображение |
|---|---|
VALIDATION_ERROR (невалидный phone) | Inline под полем: «Неверный формат телефона» |
CUSTOMER_PHONE_TAKEN (при quick-create) | Редкий кейс: клиент создан параллельно в админке. Автоматически retry GET /customers/search, клиент найден → показываем ему. Без явной ошибки пользователю |
CUSTOMER_NOT_FOUND (при PATCH attach) | Toast «Клиент не найден. Обновите поиск» |
ORDER_FINALIZED | Toast «Заказ закрыт, клиента изменить нельзя» + модалка закрывается |
FORBIDDEN | Toast «Нет прав» (не должно происходить — кнопка скрыта без permission) |
| Сеть / 5xx | Toast «Не удалось. Проверьте соединение» + возможность повторить |
Подсказки после quick-create
После успешного создания через quick-form — на короткое время (3 сек) тост / снек-бар:
«Клиент Иван Петров создан. Убедитесь, что собрано согласие на обработку ПД (уточните в админке).»
Это compliance-напоминание — отметку о согласии ФЗ-152 ставит потом админ в админке.
Ролевой доступ
| Роль | Доступ |
|---|---|
Кассир с customers.create_quick | Полный flow — поиск, quick-create, прикрепление, открепление |
| Кассир без этого permission | Кнопка «Клиент» скрыта на экране заказа. Заказ остаётся анонимным |
Связь с сервером
| Действие UI | API endpoint |
|---|---|
| Поиск по телефону | GET /api/v1/pos/customers/search?phone=... |
| Quick-create | POST /api/v1/pos/customers (тело: phone, first_name, optional email/birthday) |
| Прикрепить | PATCH /api/v1/pos/orders/{order_id}/customer body: { customer_id } |
| Открепить | DELETE /api/v1/pos/orders/{order_id}/customer |
Все запросы идут через POS BFF (:3022), он проксирует в Customer Service (:3013) и Order Service (:3005). Authorization — JWT кассира.
Состояния экрана заказа (после прикрепления)
Когда клиент прикреплён — шапка экрана заказа показывает:
- Имя клиента
- Chips групп (max 3 видимых)
- Иконка «🎂» если ДР в ±14 дней
- Иконка «×» для открепления
Что кассир ПОКА НЕ видит (BR 3.2+):
- Баланс баллов клиента
- Применимые скидки
- Купоны / промокоды
Это намеренное ограничение BR 3.1 — только привязка клиента, без финансовой логики.