POS (точка продажи)
Назначение
Кассовые операции: POS-терминалы, кассовые смены, чеки (продажи и возвраты). Учёт всех продаж в реальном времени — от открытия смены до приёмки итогов управляющим.
3 контроллера, ~12 эндпоинтов.
Сценарии
POS-терминалы
Актор: Управляющий / Администратор
Рабочее место кассира (физический терминал или планшет).
При создании: название (уникальное в корпорации), код, привязка к подразделению (опционально).
Кассовая смена
Жизненный цикл:
OPEN ─── закрытие ──► CLOSED ─── приёмка ──► ACCEPTED │ NOT_ACCEPTED └── проверка ──► REQUIRES_CHECK ──► ACCEPTED NOT_ACCEPTEDОткрытие
Актор: Кассир
- Выбор терминала, начальный баланс кассы
- Проверка: нет открытой смены на терминале
- Расчёт учётной даты:
- Если текущее время < начало учётного дня (напр. 06:00) → учётная дата = вчера
- Иначе → учётная дата = сегодня
- Генерация номера смены
- Статус → OPEN
Бизнес-правила (агрегат CashShiftAggregate, instance + static):
- Одна открытая смена на терминал (
validateNoOpenShift) - Начальный баланс ≥ 0
Закрытие
Актор: Кассир
- Проверка: все чеки закрыты (
validateAllReceiptsClosed) - Агрегация итогов: totalSales, totalReturns, totalCash, totalCard, totalCashless
- Указание closedBy
- Статус → CLOSED
Приёмка
Актор: Управляющий
Проверяет итоги и принимает решение:
- ACCEPTED — суммы сходятся
- NOT_ACCEPTED — расхождения (недостача, ошибки)
- REQUIRES_CHECK — нужно разобраться
Из REQUIRES_CHECK → ACCEPTED или NOT_ACCEPTED.
Правила: приёмка только из CLOSED или REQUIRES_CHECK (validateCanAccept).
Кассовый чек
Актор: Кассир / Официант
Типы операций:
- SALE — продажа
- RETURN — возврат (ссылается на оригинальный чек)
Структура:
Чек #42 (SALE)├── Официант: Иванов И.И.├── Кассир: Петрова А.А.├── Позиции:│ ├── Стейк Рибай × 2 — 3 200р (скидка 200р → 3 000р)│ ├── Цезарь × 1 — 650р│ └── Американо × 2 — 500р├── Итого: 4 350р − 200р = 4 150р└── Оплаты: ├── Карта — 3 000р └── Наличные — 1 150рСплит-оплата: один чек — несколько методов (наличные + карта + бонусы).
Возврат:
- Ссылка на оригинальный чек
- Нельзя возврат на самого себя
- В отчётах — суммы со знаком минус
Бизнес-правила (агрегат PosReceiptAggregate, static):
- Минимум одна позиция
- Количество > 0, цена ≥ 0
- Скидка ≥ 0
- Сумма оплаты > 0
- Все суммы неотрицательны
Учётная дата
Рестораны работают до 2–4 ночи. Настройка время начала учётного дня определяет, к какому дню относится операция.
Пример (начало = 06:00):
| Время | Учётная дата |
|---|---|
| 23:00 5 марта | 5 марта |
| 03:00 6 марта | 5 марта (до 06:00 — «вчера») |
| 07:00 6 марта | 6 марта |
Реализуется через calculateAccountingDate() с поддержкой timezone.
Связи с другими контекстами
| Направление | Что | Зачем |
|---|---|---|
| Организация → POS | Timezone, учётный день | Расчёт учётной даты смены |
| Организация → POS | Сотрудники | Проверка принадлежности к корпорации |
| Кадры → POS | Сотрудники | Кто открыл/закрыл смену, официант/кассир чека |
| Меню → POS | Номенклатура | Позиции чеков |
| Закупки → POS | Методы оплаты | Оплаты в чеках |
| POS → Отчётность | Чеки, позиции, оплаты | Источник для отчётов по выручке |
| Бухгалтерия → POS | Типы внесений/изъятий | Кассовые операции (инкассация, размен) |
Сущности
| Сущность | Описание |
|---|---|
| POS-терминал (PosTerminal) | Рабочее место кассира. Название, код, подразделение |
| Кассовая смена (CashShift) | Рабочий период: открытие → чеки → закрытие → приёмка. Итоги по продажам/возвратам/методам |
| Кассовый чек (PosReceipt) | Продажа или возврат. Позиции + оплаты. Привязан к смене и сотрудникам |
| Позиция чека (PosReceiptItem) | Номенклатура, количество, цена, скидка, итого |
| Оплата чека (PosPayment) | Метод, сумма, время, авторизовавший. Сплит — несколько оплат на чек |