Честный знак — Интеграция в ERP

Обзор

Честный знак (ГИС МТ) — государственная система маркировки и прослеживания товаров, оператор — ЦРПТ. Каждая единица маркированного товара получает уникальный DataMatrix-код, который отслеживается от производителя до конечного покупателя.

Для нашей франшизы общепита это обязательное требование MVP — кафе/фастфуд принимает, использует и продаёт маркированные товары (молоко, вода, напитки, пиво).

Статус на апрель 2026

Все основные категории уже обязательны. Штрафы: 50 000–300 000 руб. для ЮЛ, до 500 000 руб. для пива/алкоголя. Конфискация товара при серьёзных нарушениях.

Какие категории товаров затрагивают общепит

Уже обязательны (апрель 2026)

КатегорияРелевантность для франшизыПоэкземплярный учёт (ПЭУ)
Молочная продукцияВЫСОКАЯ — молоко, сливки, сыр, йогурт, маслоС июня 2025
Упакованная водаВЫСОКАЯ — бутилированная, минеральнаяС марта 2025
Пиво и слабоалкогольныеСРЕДНЕ-ВЫСОКАЯ — если продаётсяС сентября 2025 (упаковка), марта 2025 (кеги)
Безалкогольные напиткиВЫСОКАЯ — соки, лимонады, энергетикиС марта 2026
ТабакНЕТ — продажа в общепите запрещена (15-ФЗ)N/A

Скоро обязательны

КатегорияРегистрацияМаркировкаСканирование на кассе
ЧайАпрель 2026Июнь 2026
КофеИюнь 2026
Растительные маслаУжеС ноября 2025С ноября 2025
КонсервыС октября 2026
Мясо и колбасыМарт 2026Август 2026 (производители)
Кондитерские изделияДекабрь 2025Март–май 2026Июль 2027

Терминал и физическая архитектура

POS-терминал: Unitodi K10

Терминал Unitodi K10 — Android-устройство со встроенным ККТ-модулем.

ПараметрЗначение
ОСAndroid 13
Процессор8-ядер, 2.0 ГГц
Экран6.67”, 720x1600
Память16 ГБ ROM / 2 ГБ RAM (опция 32/4)
КамераЗадняя 5 Мп (опционально — 2D сканер штрих-кодов)
NFCДа (бесконтактная оплата)
КартридерМагнитный, EMV, NFC
Связь2G/3G/4G, Wi-Fi, Bluetooth
Док-станцияUSB-C, Ethernet, RS232, 2xUSB-A

Что внутри K10 — два независимых модуля

┌──────────────────── K10 (одна железка) ────────────────────┐
│                                                             │
│   Android 13                        ККТ-модуль (ФЯ)        │
│   ─────────────                     ──────────────────     │
│   Обычный Android.                  Отдельный                │
│   Тут наше POS-приложение.          сертифицированный модуль.│
│   Мы его пишем                      Мы его НЕ пишем.        │
│   и контролируем.                   Содержит ФН (фис. нак.) │
│                                                             │
│   Наше приложение ◄── HTTP :8088 ──► ФЯ (API012)           │
│                       localhost                              │
└─────────────────────────────────────────────────────────────┘
  • Наше POS-приложение — Android-приложение, которое мы разрабатываем. Показывает UI кассиру, управляет заказами, общается с бэкендом
  • ФЯ (Фискальное Ядро) — программно-аппаратный модуль ККТ. Запускается при старте K10 как HTTP-сервер на порту 8088. Ждёт команд от нашего приложения. Сертифицирован государством, мы не можем менять его логику

Словарь терминов

ТерминРасшифровкаЧто это
ККТКонтрольно-кассовая техникаФискальный модуль, записывает продажи, печатает чеки, отправляет в ОФД
ФЯФискальное ЯдроСофт ККТ — HTTP-сервер API012 на порту 8088 внутри K10
ФНФискальный накопительЗащищённый чип внутри ККТ, хранит все чеки. Версия 1.2 обязательна
ОФДОператор фискальных данныхОблачный посредник (Контур, Такском), пересылает чеки из ККТ в ФНС и ЧЗ
ФНСФедеральная налоговая службаПолучает данные обо всех продажах (54-ФЗ)
ОИСМОператор информационной системы маркировкиЧестный знак / ЦРПТ — проверяет и отслеживает коды маркировки
ФФДФормат фискальных документовСтандарт структуры чеков. Версия 1.2 обязательна для маркировки
УКЭПУсиленная квалифицированная электронная подписьЮридически значимая подпись для API Честного знака
ПИОТПроверка и ОтслеживаниеНовый протокол — проверка марок переезжает от ФЯ к кассовому приложению
ЕСПЕдиная Система ПроверкиМодуль проверки марок от ЧЗ (для ПИОТ)

Протокол API012 — взаимодействие с ФЯ (ККТ)

Взаимодействие нашего POS-приложения с ФЯ осуществляется по HTTP. Это прямо описано в документации API012.

ПараметрЗначение
ПротоколHTTP
Порт8088 (по умолчанию)
Базовый путь/api012/v1/
АвторизацияBasicAuth (логин/пароль кассира)
ФорматJSON

Валидный ответ: result = 0. Если result != 0 — код ошибки + поле message.

Ключевые эндпоинты API012

Авторизация и кассиры:

МетодЭндпоинтОписание
GETlogin.jsonАвторизация кассира, получение прав
GETloadcashiers.jsonСписок кассиров
POSTsavecashier.jsonСоздание/изменение кассира

Смены:

МетодЭндпоинтОписание
GET/POSTcycleopen.jsonОткрытие смены
GET/POSTcycleclose.jsonЗакрытие смены

Чеки и маркировка:

МетодЭндпоинтОписание
GETstartlabelschecksession.jsonОчистить таблицу проверки марок в ФН (перед чеком)
POSTlabelcheck.jsonПроверить код маркировки в ФН + ОИСМ
POSTreceipt.jsonСформировать и фискализировать чек
POSTcorrection.jsonЧек коррекции

Статус и отчёты:

МетодЭндпоинтОписание
GETcashboxstatus.jsonПолный статус ККТ
GETfscounters.jsonСчётчики ФН
GETxreport.jsonX-отчёт (статистика за смену, нефискальный)
GETfsreport.jsonСтатистика ФН

Прочее:

МетодЭндпоинтОписание
GETintroduction.jsonВнесение наличных (в копейках)
GETpayout.jsonИзъятие наличных (в копейках)
GET/POSTsaveofdcfg.jsonНастройки связи с ОФД
GETofflineNotifications.binВыгрузка сообщений ОИСМ для офлайн-режима

Три потока работы с маркировкой

Поток 1: Продажа маркированного товара на кассе

Бутылка воды, банка сока — покупатель берёт маркированный товар целиком. Наше приложение НЕ ходит в Честный знак. Всё делает ФЯ (ККТ).

sequenceDiagram
    participant Кассир
    participant POS as POS App (наше)
    participant ФЯ as ФЯ (API012 :8088)
    participant ОИСМ as Честный знак (ОИСМ)
    participant ОФД
    participant ФНС

    Кассир->>POS: Сканирует DataMatrix камерой K10
    POS->>POS: Парсит rawLabel
    
    Note over POS,ФЯ: Шаг 1: очистка сессии
    POS->>ФЯ: GET startlabelschecksession.json
    ФЯ-->>POS: { result: 0 }
    
    Note over POS,ОИСМ: Шаг 2: проверка каждой марки
    POS->>ФЯ: POST labelcheck.json { rawLabel, checkFlags, expectedStatus }
    ФЯ->>ОИСМ: Проверка кода (ФЯ сама ходит в ОИСМ)
    ОИСМ-->>ФЯ: Статус кода
    ФЯ-->>POS: { st2109: 1, reqResult: 5, ... }
    
    Note over POS,ФЯ: Шаг 3: чек с результатами проверок
    POS->>ФЯ: POST receipt.json { labledOperations: [{ labelCheckResult }] }
    ФЯ->>ФЯ: Запись в ФН
    ФЯ->>ОФД: Фискальный документ
    ОФД->>ФНС: Данные о продаже (54-ФЗ)
    ОФД->>ОИСМ: Автоматический вывод из оборота
    ФЯ-->>POS: { result: 0, document: { fiscalCode, docNumber, ... } }
    POS->>Кассир: Чек напечатан

При продаже на кассе наше приложение НЕ обращается в Честный знак напрямую и НЕ обращается в наш Marking Service. Всю проверку и вывод из оборота делает ФЯ (ККТ) → ОФД → Честный знак автоматически.

Последовательность запросов к API012 (из документации)

1. GET  startlabelschecksession.json     ← очистить таблицу проверок в ФН
2. POST labelcheck.json                  ← для каждого маркированного товара
   POST labelcheck.json                  ← (повторить N раз, макс 128 на чек)
3. POST receipt.json                     ← чек с результатами проверок

Структура POST receipt.json — два списка позиций

В чеке позиции разделяются на два массива:

  • operations — обычные товары (БЕЗ маркировки): капучино, круассан, бургер
  • labledOperations — маркированные товары: бутылка воды, пачка молока
{
  "document": {
    "cashier": "Иванов И.И.",
    "tax": 1,
    "paymentAttr": 1,
    "operations": [
      {
        "name": "Капучино",
        "price": "250.00",
        "quantity": "1.000",
        "type": 1,
        "vatRate": 1
      }
    ],
    "labledOperations": [
      {
        "name": "Вода Святой источник 0.5л",
        "price": "89.00",
        "quantity": "1.000",
        "type": 33,
        "vatRate": 1,
        "productCode": {
          "type": 1304,
          "data": "0104600000000013..."
        },
        "checkLabelFlags": 3,
        "labelCheckResult": { ... }
      }
    ],
    "cash": "339.00"
  }
}

Ключевые поля маркированной позиции (labledOperations)

ПолеТег ФФДОписание
productCode1163Объект { type, data }. Тип 1304 = GS1 DataMatrix (КТ GS1.0)
checkLabelFlags2106Результат проверки сведений о товаре
labelCheckResultЦеликом ответ от labelcheck.json. Не записывается в ФН целиком, используется при оформлении
fraction1291Дробное количество { nominator, denominator } — только для мерных маркированных товаров

POST labelcheck.json — проверка марки

Входные данные:

{
  "document": {
    "rawLabel": "010123456789012321M,7aL0JDGbJCWa...",
    "checkFlags": 0,
    "excpectedStatus": 2,
    "quantity": "1.000",
    "unit": 0,
    "fraction": { "nominator": 2, "denominator": 10 }
  }
}
ПолеОписание
rawLabelСырая строка DataMatrix как есть (UTF-8)
checkFlagsБитовая маска: флаги согласия покупателя продолжить при ошибке. 0 = не продолжать, 255 = решение на стороне нашего приложения
excpectedStatus1=штучный, 2=мерный, 3=возврат штучного, 4=возврат мерного, 5=штучный на стадии реализации, 6=мерный реализован, 255=не менять
quantityКоличество товара
unitЕдиница измерения: 0=шт, 10=грамм, 11=кг, 40=мл, 41=литр

Выходные данные:

ПолеОписание
st2109Ответ ОИСМ: 1=статус корректен, 2=некорректен, 3=оборот приостановлен
reqCode21050=формат корректный, 1=некорректный формат, 2=код не распознан
reqResultБитовая маска результата: бит 1 = проверка КП КМ, бит 3 = статус товара
clFlagsБитовая маска — то же что передано в checkFlags

Лимит: не более 128 маркированных позиций на один чек (ограничение таблицы проверки в ФН).

Поток 2: Использование для приготовления

Молоко для капучино, сыр для пиццы — маркированный товар используется как ингредиент. Чека нет, ФЯ не участвует. Тут нужен наш Marking Service → Честный знак API.

sequenceDiagram
    participant Сотрудник
    participant POS as POS App (наше)
    participant BFF as POS BFF :3022
    participant MS as Marking Service :3013
    participant ЧЗ as Честный знак API

    Сотрудник->>POS: Сканирует код при вскрытии упаковки
    POS->>BFF: POST /marking/withdrawal { rawLabel, reason }
    BFF->>MS: Проксирует запрос
    MS->>ЧЗ: POST /lk/documents/create?pg=milk { type: WITHDRAWAL }
    Note right of ЧЗ: reason: "собственные нужды"<br/>или "производственные цели"
    ЧЗ-->>MS: Документ принят
    MS-->>POS: OK
    Note over POS: Дедлайн: 3 рабочих дня<br/>с момента вскрытия

Коды причин вывода:

  • Код 1: “Использование для собственных нужд” — вода для персонала
  • Код 3: “Производственные цели, не связанные с реализацией” — молоко для латте

Поток 3: Приёмка товара от поставщика

ФЯ не участвует. Наш Marking Service.

sequenceDiagram
    participant Поставщик
    participant ЭДО
    participant MS as Marking Service :3013
    participant Сотрудник
    participant POS as POS App (наше)

    Поставщик->>ЭДО: Отправляет УПД с кодами маркировки
    ЭДО->>MS: Входящий УПД
    Сотрудник->>POS: Сканирует коды товаров
    POS->>MS: Отправляет отсканированные коды
    MS->>MS: Сверяет коды с УПД
    alt Совпадают
        MS->>ЭДО: Подтверждение приёмки (подпись УКЭП)
        Note over MS: Право собственности<br/>переходит в ЧЗ
    else Расхождение
        MS->>POS: Ошибка — несовпадение кодов
        POS->>Сотрудник: Показать расхождения
    end

Кто с кем разговаривает — общая схема

                         ИНТЕРНЕТ
              ┌────────────┬─────────────────────┐
              │            │                     │
              ▼            ▼                     ▼
         Наш сервер       ОФД              Честный знак
         (POS BFF,      (Контур,              (ЦРПТ)
          Marking        Такском)
          Service)         ▲                     ▲
              ▲            │                     │
              │            │      ФЯ сама ходит  │
              │            │      в ОФД и ОИСМ   │
              │            │      (мы не контролируем)
┌─────────────┼────────────┼─────────────────────┼────────┐
│ K10         │            │                     │        │
│             │            │                     │        │
│  Наше POS ──┘        ФЯ (API012 :8088) ───────┘        │
│  приложение    HTTP     ▲                               │
│       │      localhost  │                               │
│       └─────────────────┘                               │
│                                                         │
└─────────────────────────────────────────────────────────┘

Простая формула:

СценарийПуть данныхЧерез Marking Service?
ПродажаPOS App → ФЯ (localhost:8088) → ОФД → ЧЗНЕТ
ГотовкаPOS App → POS BFF → Marking Service → ЧЗ APIДА
ПриёмкаPOS App → POS BFF → Marking Service → ЧЗ API + ЭДОДА

Где нужен УКЭП

УКЭП (усиленная квалифицированная электронная подпись) нужен только на сервере в Marking Service. На кассе K10 его нет.

ОперацияГде выполняетсяУКЭП нужен?Почему
Сканирование DataMatrixK10 (камера)НетПросто чтение штрих-кода
Проверка кода перед продажейФЯ (API012) → ОИСМНетФЯ авторизуется сама
Формирование чекаФЯ (API012) → ФННетФН подписывает своим ключом
Отправка чека в ОФДФЯ → ОФДНетОФД авторизован сам
Вывод через продажуОФД → ЧЗНетОФД делает автоматически
Вывод для готовкиMarking Service → ЧЗ APIДАAuth токен + подпись документа
Приёмка (подпись УПД)Marking Service → ЭДОДАПодпись УПД
Списание просрочкиMarking Service → ЧЗ APIДАAuth токен + подпись документа

Как УКЭП работает на сервере

Один УКЭП-сертификат на ЮЛ, установлен в CryptoPro на сервере Marking Service:

1. Marking Service стартует, загружает УКЭП из CryptoPro keystore
2. GET /auth/key → { uuid, data: "случайная_строка" }
3. CryptoPro JCP подписывает "случайная_строка" → Base64
4. POST /auth/simpleSignIn { uuid, data: "подпись" }
   → { token: "abc...", life_time: 36000 }
5. Токен кэшируется в Redis (TTL 10 часов, idle 30 мин)
6. Все запросы от всех касс используют этот один токен

GS1 DataMatrix — формат кода

Структура

[FNC1] 01 [GTIN, 14 цифр] 21 [Серийный номер, до 13 символов] [GS] 93 [Код проверки, 4 символа]
AI (идентификатор)НазваниеДлинаТип
(01)GTIN (код товара)14 цифрФиксированная
(21)Серийный номерДо 13 символовПеременная (GS после)
(91)Ключ проверки4 символаПеременная
(92)Криптоподпись (крипто-хвост)44 символаПеременная
(93)Код проверки (краткая форма)4 символаПеременная

Спец-символы:

  • FNC1 (ASCII 232) — маркер GS1 DataMatrix (первая позиция)
  • GS (ASCII 29 / 0x1D) — разделитель полей переменной длины

Скобки вокруг AI — только для человека, в DataMatrix их НЕТ. Сканер возвращает сырые байты.

Полная длина кода: 31 символ (короткая часть GTIN + серийный) / 83–88 символов (с крипто-хвостом).

Агрегационные коды vs индивидуальные

ТипФорматГдеДля чего
КИ (SGTIN)GTIN + серийныйНа каждой единице товараСканирование на кассе, вывод из оборота
КИТУ (SSCC)18-значный SSCCНа транспортной упаковке (коробка, паллет)Упрощение приёмки — сканируешь коробку = принимаешь все единицы внутри

Фискальные требования (ФФД 1.2)

ФФД 1.2 обязательна для продажи маркированных товаров. ФН (фискальный накопитель) внутри K10 должен быть версии 1.2.

Ключевые теги в чеке

Чек
  └── Тег 1059 (Предмет расчёта / позиция)
        └── Тег 1163 (Код товара) — новый в ФФД 1.2
              ├── Тег 2100 (Тип кода маркировки)
              ├── Тег 2000 (Код маркировки)
              └── Тег 2106 (Результат проверки)
ТегНазваниеОписание
1162Код товара (legacy)Контейнер ФФД 1.05, первые 2 байта: 0x44 0x4D (“DM”), далее 31 байт кода
1163Код товара (new)ФФД 1.2, содержит вложенные теги по типу кода
2000Код маркировкиСам код маркировки
2003Планируемый статусСтатус товара (штучный/мерный)
2100Тип кода маркировкиИдентификатор типа кода
2106Результат проверкиКорректен / некорректен
2107Результаты проверки маркированных товаровОбщий результат проверки в чеке (тег уровня чека)

Типы кодов товаров (productCode.type)

ТипНазваниеКод ФФД
1300НераспознанныйКТ Н
1301EAN-8КТ EAN-8
1302EAN-13КТ EAN-13
1303ITF-14КТ ITF-14
1304GS1 DataMatrixКТ GS1.0 — основной для маркировки
1305GS1.MКТ GS1.M
1306КМК (короткий код)КТ КМК

Разрешительный режим

С марта 2026 — обязательная онлайн-проверка кода перед продажей. Если код невалиден — продажа блокируется.

Текущая схема (ФФД 1.2): ФЯ сама проверяет коды в ОИСМ через labelcheck.json.

Офлайн-фолбек: Локальный модуль Честного знака на кассе, синхронизируется каждые 3 дня. Если не синхронизирован — модуль блокируется.

Исключение для HoReCa

Заведения общепита (без розничной торговли) могут:

  • Не устанавливать Локальный модуль
  • Использовать агрегированные коды (GTIN) вместо индивидуальных в чеке
  • Использовать тег mode=horeca в фискальных документах

ПИОТ — будущий протокол (следить)

ПИОТ (Проверка и Отслеживание) — новый протокол, который меняет схему работы с маркировкой. Пока не обязателен, но нужно учитывать.

Текущая схема (ФФД 1.2): ФЯ делает всё сама

POS App ──► ФЯ ──► ОИСМ (Честный знак)
                   ФЯ сама проверяет марку

Наше приложение не знает про Честный знак при продаже. Мы просто шлём rawLabel в labelcheck.json и получаем ответ.

ПИОТ (новая схема): ответственность переезжает к кассовому приложению

POS App ──► модуль ЕСП ──► Честный знак (проверка марки)
    │           │
    │     результат проверки
    │           │
    ▼           ▼
POS App ──► ФЯ (только фискализация, без проверки марок)

Изменения:

  1. ФЯ перестаёт сама проверять марки в Честном знаке
  2. Наше приложение должно само проверять марки через модуль ЕСП (Единая Система Проверки)
  3. Результат проверки мы передаём обратно в ФЯ для записи в чек
  4. Нужен Локальный Модуль для офлайн-проверки (кэш кодов на устройстве, синхронизация каждые 3 дня)

Влияние на нашу архитектуру

АспектСейчас (ФФД 1.2)ПИОТ (будущее)
Кто проверяет марки при продажеФЯ (через API012 labelcheck.json)Наше приложение (через ЕСП)
Нужен ли Marking Service для продажиНетВозможно — как backend для ЕСП
Локальный МодульНе обязателен для HoReCaПотребуется
Сложность интеграцииНизкаяВысокая

Для MVP делаем на текущей схеме (ФФД 1.2, API012). ФЯ проверяет марки, мы просто шлём запросы. Когда ПИОТ станет обязательным — переделаем проверку на нашу сторону.

API Честного знака (True API)

Используется только нашим Marking Service для потоков готовки и приёмки. При продаже на кассе НЕ используется.

Среды

СредаURL
Productionhttps://markirovka.crpt.ru/api/v4/true-api/
Sandboxhttps://markirovka.sandbox.crptech.ru/api/v4/true-api/

Rate limit: 50 запросов/сек на участника. Sandbox бесплатный.

Аутентификация

Требуется УКЭП + CryptoPro CSP. См. секцию Где нужен УКЭП.

Ключевые эндпоинты

Проверка кодов:

МетодПутьОписание
POST/cises/infoПубличная информация о кодах
POST/cises/searchПоиск кодов по фильтрам (100/стр)

Документы (вывод из оборота, приёмка):

МетодПутьОписание
POST/lk/documents/create?pg={group}Создание документа (withdrawal, acceptance)
GET/lk/documents/{docId}Получение документа по ID
GET/lk/receiptsКвитанции обработки документов

Товарные группы (параметр pg): milk, water, beer, ncp (безалкогольные), tobacco

Типы документов:

  • WITHDRAWAL — вывод из оборота (стандартный)
  • WITHDRAWAL_OSU — вывод для собственных нужд / производства (для общепита)

Библиотеки / SDK

ЯзыкБиблиотекаПримечание
Javaborkli/CrptApiJava 11+, thread-safe, rate limiting
.NETFairMark/FairMarkClientTrue API + OMS + EDO Lite
PHPkilylabs/true-api-cliCLI для True API + СУЗ
Node.jsНет готовых SDK, прямые HTTP-вызовы

CryptoPro — главная сложность

Для Node.js нет нативной поддержки CryptoPro. Варианты: (1) Java-сервис с JCP, (2) sidecar-контейнер с CryptoPro, (3) отдельный signing-микросервис.

Архитектурное решение для нашей ERP

Общая схема

graph TB
    subgraph "K10 (терминал)"
        POS_APP["POS App (Android)"]
        FY["ФЯ (API012 :8088)"]
        POS_APP -->|"HTTP localhost"| FY
    end

    subgraph "Backend (наш сервер)"
        POS_BFF["POS BFF :3022"]
        MARKING["Marking Service :3013"]
        CATALOG["Catalog Service :3004"]
        WAREHOUSE["Warehouse Service :3008"]
    end

    subgraph "External"
        CRPT["Честный знак API"]
        OFD["ОФД"]
        EDO["ЭДО оператор"]
        FNS["ФНС"]
    end

    POS_APP -->|"HTTPS (готовка, приёмка)"| POS_BFF
    POS_BFF --> MARKING
    MARKING -->|"True API + УКЭП"| CRPT
    MARKING -->|"подпись УПД"| EDO
    FY -->|"чеки"| OFD
    OFD -->|"54-ФЗ"| FNS
    OFD -->|"авто-вывод при продаже"| CRPT
    FY -.->|"labelcheck"| CRPT
    MARKING -.->|"Kafka"| WAREHOUSE
    MARKING -.->|"Kafka"| CATALOG

    style MARKING fill:#e94560,stroke:#1a1a2e,color:#fff
    style FY fill:#0f3460,stroke:#1a1a2e,color:#fff
    style CRPT fill:#533483,stroke:#1a1a2e,color:#fff
    style OFD fill:#533483,stroke:#1a1a2e,color:#fff

Marking Service — зона ответственности

Marking Service НЕ участвует при продаже на кассе. Нужен только для готовки, приёмки и учёта.

ФункцияОписание
Аутентификация ЦРПТПолучение и кэширование токенов (УКЭП + CryptoPro)
Вывод из оборотаДокументы WITHDRAWAL / WITHDRAWAL_OSU для приготовления
ПриёмкаСверка кодов с УПД, подтверждение в ЭДО
Учёт кодовСтатусы кодов в БД, дедлайны вывода (3 дня)
СинхронизацияПериодическая синхронизация с ЧЗ

Tech Stack

ТехнологияНазначение
Java 21 + Spring BootОсновной сервис (нативная поддержка CryptoPro через JCP)
PostgreSQLХранение кодов, документов, истории
RedisКэш токенов, результатов проверки
CryptoPro JCPПодпись УКЭП для аутентификации в True API
KafkaСобытия жизненного цикла кодов

Модель данных

erDiagram
    marking_codes {
        uuid id PK
        uuid franchise_id FK
        uuid store_id FK
        varchar code "полный DataMatrix код"
        varchar gtin "14 цифр"
        varchar serial "до 13 символов"
        varchar product_group "milk, water, beer, ncp"
        varchar status "received, in_stock, withdrawn, sold"
        varchar withdrawal_reason "sale, own_needs, production, expired, damaged"
        uuid supplier_document_id FK
        timestamp received_at
        timestamp withdrawn_at
        timestamp withdrawal_deadline "received_at + 3 рабочих дня"
    }

    marking_documents {
        uuid id PK
        uuid franchise_id FK
        varchar doc_type "WITHDRAWAL, WITHDRAWAL_OSU, ACCEPTANCE"
        varchar product_group "milk, water, beer, ncp"
        varchar status "pending, submitted, accepted, rejected"
        varchar crpt_doc_id "ID в системе ЦРПТ"
        jsonb payload "тело документа"
        varchar error_message
        timestamp submitted_at
        timestamp processed_at
    }

    marking_products {
        uuid id PK
        varchar gtin UK "14 цифр"
        varchar product_name
        varchar product_group
        boolean requires_marking
        jsonb crpt_product_info "кэш из True API"
        timestamp synced_at
    }

    supplier_documents {
        uuid id PK
        uuid franchise_id FK
        uuid store_id FK
        varchar upd_number "номер УПД"
        varchar supplier_inn
        varchar status "pending, accepted, rejected, partial"
        integer total_codes
        integer scanned_codes
        timestamp received_at
        timestamp confirmed_at
    }

    marking_codes ||--o| supplier_documents : "принят по"
    marking_codes ||--o| marking_documents : "выведен через"
    marking_codes }o--|| marking_products : "GTIN"

Kafka-события

ТопикPublisherConsumerPayload
marking.code.receivedMarkingWarehouse{ code, gtin, store_id, supplier_document_id }
marking.code.withdrawnMarkingWarehouse, Catalog{ code, gtin, store_id, reason, document_id }
marking.code.soldMarkingWarehouse{ code, gtin, store_id, receipt_id }
marking.document.submittedMarking{ document_id, type, status }
marking.document.processedMarking{ document_id, type, status, crpt_doc_id }

API Marking Service (внутренний, для POS BFF)

Base: /api/v1

МетодПутьОписаниеAuth
POST/marking/withdrawalВывести коды из оборота (приготовление)franchise, franchisee, manager
POST/marking/codes/acceptПринять коды из УПД (приёмка)franchise, franchisee, manager
GET/marking/codes/{code}Статус конкретного кодаfranchise, franchisee, manager
GET/marking/codesСписок кодов (фильтры: store, status, product_group)franchise, franchisee, manager
GET/marking/products/{gtin}Требует ли товар маркировкиall
GET/marking/documentsСписок документовfranchise, franchisee, manager
GET/marking/documents/{id}Детали документаfranchise, franchisee, manager
POST/marking/supplier-documentsСоздать приёмку по УПДfranchise, franchisee, manager
PATCH/marking/supplier-documents/{id}Подтвердить/отклонить приёмкуfranchise, franchisee, manager

Что меняется в существующих сервисах

СервисИзменение
Catalog ServiceФлаг requires_marking + product_group (milk/water/beer/ncp) на товарах. Уже есть alcohol, tobacco, sugary_drink — расширяем
Store ServiceДобавить participant_id (ID участника ЧЗ) и kkt_settings на ТТ
Warehouse ServiceСлушать marking.code.received/withdrawn/sold для связи с остатками
POS BFFРоутинг к Marking Service для готовки/приёмки
POS AppИнтеграция с API012 (ФЯ), UI для сканирования, работа с labledOperations

Что нужно закупить / настроить

На каждую ТТ

ЧтоЗачемПримечание
Unitodi K10Терминал с Android + встроенной ККТУже выбран
ФН версии 1.2Фискальный накопительДолжен быть внутри K10
2D сканер (опция)Быстрое чтение DataMatrixКамера K10 тоже работает, но медленнее

Сервисы и подписки

ЧтоЗачем
УКЭП (КЭП)Электронная подпись для API (устанавливается на сервере Marking Service)
CryptoPro CSP 5+Криптопровайдер для подписи (на сервере)
ЭДО операторОбмен УПД с поставщиками (Контур.Диадок, СБИС, Такском)
ОФД с поддержкой маркировкиПередача чеков в ФНС + ЧЗ
Регистрация в ЧЗЛичный кабинет markirovka.crpt.ru, роль “Розница и Иное”

Приоритет реализации для MVP

Phase 1 (минимум для запуска POS)

  1. POS App — интеграция с API012: startlabelschecksessionlabelcheckreceipt с labledOperations
  2. Catalog Service — флаги requires_marking + product_group на товарах
  3. Marking Service (базовый) — вывод из оборота для готовки (УКЭП + True API)

Phase 2 (расширение)

  1. Приёмка — полная сверка с УПД через ЭДО
  2. Warehouse интеграция — автоматический учёт маркированных остатков
  3. Массовый вывод — batch-операции для кухни (списание ингредиентов)
  4. Дашборд — мониторинг просроченных дедлайнов вывода (3 дня)

Phase 3 (ПИОТ — когда станет обязательным)

  1. Интеграция модуля ЕСП в POS App
  2. Локальный Модуль для офлайн-проверки
  3. Перенос проверки марок с ФЯ на нашу сторону

Sandbox для разработки

ПараметрЗначение
URLhttps://markirovka.sandbox.crptech.ru/
APIhttps://markirovka.sandbox.crptech.ru/api/v4/true-api/
Loginhttps://markirovka.sandbox.crptech.ru/login-kep
СтоимостьБесплатно
ОграничениеТестовые коды невалидны в продакшене

Ссылки

Внешние источники

Документация API012

Файл: _assets/API012 (1).pdf — полная спецификация протокола взаимодействия с ККТ (версия V1).