[DRAFT] Метод POST /api/v1/webhooks/stores/receipt

Документация B2B API: Автоматическое добавление продуктов через вебхук для торговой сети Магазин

Author

Application & Simulation Services Framework Documentation

Published

July 1, 2026

WarningОграничение публичной документации

В открытом доступе представлена демонстрационная версия метода. В настоящей публичной документации отображены не все шаги, технические сценарии и приватные эндпоинты для системы цифровых симуляторов бизнес-процессов.

  • Полная спецификация метода: Будет доступна только во внутреннем контуре разработки (Confluence / Swagger Enterprise).

Functional Purpose / Функциональное назначение

ImportantDocumentation Under Development

This documentation section is currently under development and may contain incomplete data. Some technical descriptions, parameters, and system operation scenarios for the digital business process simulator are subject to change.

  • Stable documentation version: Will be published upon final completion and validation of the method code.

Метод представляет собой открытый B2B-эндпоинт (вебхук), предназначенный для автоматического пополнения холодильника пользователя товарами, приобретенными в розничной сети или магазине или у продавца с настроенной интеграцией.

Метод решает следующие задачи:

  1. Синхронный Direct-Inflow (Прямой импорт): В отличие от пользовательского контура (метод/ы распознавания OCR из мобильного приложения), “Вендор” передает серверу строго типизированный, подготовленный JSON-датасет. Это позволяет системе добавлять продукты в цифровой холодильник не используя промежуточные таблицы например: pending_receipts.
  2. Сквозная B2B-авторизация: Метод защищен протоколом OAuth2 Client Credentials либо выделенным статическим API-ключом, так как запрос инициируется сервером торговой сети, а не мобильным приложением.
  3. Связывание аккаунтов (User Mapping): Идентификация целевого холодильника (home_group_id) происходит по переданному в теле запроса loyalty_card_token (токен карты лояльности сети Магазин, которую пользователь привязал в своем профиле в приложении FoodLifeCycleApp).

Протокол взаимодействия (HTTP Контракт)

  • Метод: POST
  • Маршрут: /api/v1/webhooks/stores/receipt
  • Формат данных: application/json

Спецификация заголовков (HTTP Headers)

Заголовок Обязательный Описание Пример значения
Content-Type Да Указывает на передачу строго типизированного JSON-пакета application/json
X-Shop-Token Да Секретный статический ключ авторизации партнера (B2B API Key) shop_live_secret_abc123...
X-Request-ID Да Сквозной ID запроса, генерируемый шиной Магазина для трассировки shop-tr-44bb-99ff

Спецификация тела запроса (Request Body)

Структура данных повторяет фискальный срез чека Магазин. Поля количества товара (quantity) поддерживают тип float/double для корректного зачисления весовых позиций (например, бананов весом 1.695 кг).

Поле Тип Обязательный Описание Пример значения
loyalty_card_token String Да Уникальный токен карты, по которому бэкенд находит user_id и home_group_id shop-card-8822-fa
receipt_number String Да Фискальный номер чека для предотвращения дублирования CH-20260701-09
items Array Да Список приобретенных товарных позиций [..._name: "БАНАН", qty: 1.695]

Пример JSON-запроса (Payload):

{
  "loyalty_card_token": "shop-card-8822-fa",
  "receipt_number": "CH-20260701-09",
  "purchase_timestamp": "2026-07-01T23:10:00Z",
  "store_id": "shop-almaty-05",
  "items": [
    {
      "product_id": "2110310",
      "product_name": "БАНАН ЭКВАДОР КГ",
      "quantity": 1.6950,
      "price": 595.00,
      "unit": "кг"
    },
    {
      "product_id": "4001020",
      "product_name": "ХЛЕБ АКСАЙ БОРОДИНСКИЙ",
      "quantity": 1.0000,
      "price": 180.00,
      "unit": "шт"
    }
  ]
}

Диаграмма последовательности (Mermaid)

ImportantDocumentation Under Development

This documentation section is currently under development and may contain incomplete data. Some technical descriptions, parameters, and system operation scenarios for the digital business process simulator are subject to change.

  • Stable documentation version: Will be published upon final completion and validation of the method code.

На диаграмме представлена логика сквозной интеграции через B2B-вебхук: бэкенд идентифицирует пользователя по карте лояльности, проверяет чек на дубликаты и добавляет продукты напрямую в цифровой холодильник автоматически.

sequenceDiagram
    autonumber
    actor Partner as REST-клиент Торговой Сети
    participant Nginx as Nginx Proxy
    participant GW as FastAPI Gateway (backend-api)
    participant Store as store-service (INVENTORY)
    participant Auth as auth-service (SECURITY/IAD)
    participant K as Apache Kafka Cluster
    participant Fridge as fridge-service (INVENTORY)

    Partner->>Nginx: Шаг 1: POST /api/v1/webhooks/stores/receipt (Headers: X-Shop-Token)
    activate Nginx
    Nginx->>GW: Шаг 2: Внутренний прокси сырого JSON вебхука
    activate GW
    GW->>Store: Шаг 3: gRPC: ProcessB2BReceipt(ReceiptRequest)
    activate Store
    
    Store->>Auth: Шаг 4: gRPC: ResolveLoyaltyCard(CardRequest)
    activate Auth
    Auth-->>Store: Возврат user_id, home_group_id и статуса X-Shop-Token
    deactivate Auth
    
    alt Сценарий А: Токен НЕ валиден / Карта лояльности не найдена
        Store-->>GW: gRPC Error: UNAUTHENTICATED / NOT_FOUND
        GW-->>Partner: HTTP 401 Unauthorized / 404 Not Found
    else Сценарий Б: Успешная валидация и маппинг
        Store-->>GW: gRPC Response: ACCEPTED (OK)
        deactivate Store
        GW-->>Partner: Шаг 5: HTTP 200 OK (Контракт исполнен, Fire-and-Forget)
        deactivate GW
        deactivate Nginx
        
        %% АСИНХРОННЫЙ ХВОСТ ПРЯМОГО ЗАЧИСЛЕНИЯ
        Store->>K: Шаг 6: Пуш события в топик: store.inventory.in.receipt.imported
        activate K
        K->>Fridge: Шаг 7: Handler: ProcessTrustedB2BReceipt()
        deactivate K
        activate Fridge
        Note over Fridge: Шаг 8: Прямой транзакционный INSERT<br/>в PostgreSQL Fridge DB на баланс home_group_id
        deactivate Fridge
    end

Процесс автоматического пополнения холодильника через B2B-вебхук (Store-Receipt)


Расшифровка шагов

ImportantDocumentation Under Development

This documentation section is currently under development and may contain incomplete data. Some technical descriptions, parameters, and system operation scenarios for the digital business process simulator are subject to change.

  • Stable documentation version: Will be published upon final completion and validation of the method code.
Шаг Действие Параметры / Запросы Ошибки (Исключения / Статусы) и JSON Ответы
1 (Partner -> Nginx) Внешний сервер торговой сети отправляет JSON-датасет фискального чека на B2B-эндпоинт интеграции. HTTP POST /api/v1/webhooks/stores/receipt
Headers: X-Shop-Token
Входная точка запроса партнера. Транспортный уровень.
2 (Nginx -> GW) Прокси-сервер осуществляет добавление X-Request-ID и перенаправляет запрос вебхука на API-шлюз. HTTP POST /backend-api/...
Headers: X-Request-ID
Внутренняя маршрутизация шлюза.
3 (GW -> Store) Шлюз валидирует структуру чека и транслирует запрос в микросервис. Протокол: gRPC
Метод: ProcessB2BReceipt
Проверка синтаксиса контракта JSON шлюзом.
4 (Store -> Auth) Метод сервиса запрашивает у компонента безопасности проверку B2B-токена и конвертацию карты лояльности в ID пространства. Протокол: gRPC
Метод: ResolveLoyaltyCard
Сквозная B2B авторизация.
5.1 (Сценарий А) (Store -> Partner) Компонент безопасности отклоняет запрос. Сервис возвращает партнеру финальный статус отказа из-за сработавшей идемпотентности. Ответ по цепочке через GW и Nginx:
HTTP 409 Conflict
Бизнес-ошибка метода (Idempotency Trigger):
json\n{\n "error_code": "ERR-RECEIPT-DUPLICATE",\n "message": "Данный фискальный документ уже был успешно обработан и зачислен ранее.",\n "details": {\n "rejected_receipt_number": "CH-20260701-09",\n "partner_code": "MAGNUM",\n "action": "Idempotency trigger activated. No duplicate database writes executed."\n }\n}\n
5.1 (Сценарий Б) (Store -> Partner) Сервис фиксирует успешное прохождение проверок, закрывает транзакцию СУБД и возвращает успешный статус. Ответ по цепочке через GW и Nginx:
HTTP 200 OK
Успешный ответ (Success Response):
json\n{\n "status": "PROCESSED",\n "receipt_number": "CH-20260701-09",\n "loyalty_card_token": "shop-card-8822-fa",\n "metrics": {\n "items_processed_count": 2,\n "db_transaction_status": "COMMITTED"\n },\n "timestamp": "2026-07-01T23:10:02Z"\n}\n
6 (Store -> KAFKA) Инвентарный сервис асинхронно публикует событие успешного импорта B2B-чека в брокер сообщений для изоляции транзакционной нагрузки. Топик: store.inventory.in.receipt.imported Асинхронная публикация события в шину.
7 (KAFKA -> Fridge) Фоновый воркер сервиса холодильника вычитывает доверенное B2B-сообщение из топика и запускает процедуру зачисления позиций. Handler: ProcessTrustedB2BReceipt() Асинхронное чтение события воркером.
8 (Fridge -> DB_Fridge) Сервис проверяет фискальный номер чека в реестре обработанных документов для соблюдения идемпотентности на уровне БД. SQL: SELECT 1 FROM processed_b2b_receipts... Проверка дубликатов на уровне СУБД.
8.1 (Fridge -> DB_Fridge) В рамках единой транзакции воркер регистрирует факт обработки чека и выполняет bulk-insert весовой матрицы товаров на баланс группы. SQL: INSERT INTO processed_b2b_receipts...
INSERT INTO fridge_inventory...
Атомарная фиксация остатков.
8.2 (DB_Fridge -> Fridge) СУБД фиксирует транзакцию, обновляет складские остатки Multi-Tenancy контура и возвращает статус успешной записи. Статус: COMMIT Успешное завершение транзакции БД.
8.3 (Fridge -> KAFKA) Сервис отправляет системное бизнес-событие в шину данных для уведомления зависимых доменов бэкенда (аналитика, умные рецепты). Топик: fridge.inventory.events.stock_replenished Обогащение бизнес-событиями.
9 (Fridge -> App) Шлюз по сигналу воркера находит активный WebSocket-стрим семьи по home_group_id и отправляет пуш-ивент для реалтайм обновления UI. Эндпоинт: /ws/push-stream/{id} Смена стейта UI на клиенте.

Спецификация ответов (Response Body)

ImportantDocumentation Under Development

This documentation section is currently under development and may contain incomplete data. Some technical descriptions, parameters, and system operation scenarios for the digital business process simulator are subject to change.

  • Stable documentation version: Will be published upon final completion and validation of the method code.

Успешный ответ (Success Response)

HTTP 200 OK

Возвращается шине данных партнерской торговой сети Магазин в качестве успешного подтверждения запроса приема, и авторизации.

  • Заголовки ответа (Response Headers):
    • Content-Type: application/json
  • Тело ответа (Response Body):
{
  "status": "PROCESSED",
  "receipt_number": "CH-20260701-09",
  "loyalty_card_token": "shop-card-8822-fa",
  "metrics": {
    "items_processed_count": 2,
    "db_transaction_status": "COMMITTED"
  },
  "timestamp": "2026-07-01T23:10:02Z"
}

Спецификация ошибок (Error Responses)

Ошибка дублирования чека (HTTP 409 Conflict)

Вызывается, если переданный receipt_number уже присутствует в таблице. Это предотвращает повторное начисление веса продуктов при сбоях и ретраях на стороне Магазина.

{
  "error_code": "ERR-RECEIPT-DUPLICATE",
  "message": "Данный фискальный документ уже был успешно обработан и зачислен ранее.",
  "details": {
    "rejected_receipt_number": "CH-20260701-09",
    "partner_code": "MAGNUM",
    "action": "Idempotency trigger activated. No duplicate database writes executed."
  }
}

Ошибка: Карта лояльности не привязана к профилю (HTTP 422 Unprocessable Entity)

Вызывается, если loyalty_card_token верный по структуре, но отсутствует в таблице маппинга user_loyalty_cards. Система не может определить, в чей именно цифровой холодильник нужно положить продукты.

{
  "error_code": "ERR-LOYALTY-CARD-NOT-MAPPED",
  "message": "Карта лояльности партнера не связана ни с одним активным аккаунтом в экосистеме .",
  "details": {
    "unmapped_token": "mag-card-8822-fa",
    "action": "The user must physically link their Magnum card inside the Flutter mobile app profile."
  }
}

Ошибка B2B-авторизации партнера (HTTP 401 Unauthorized)

Вызывается бэкенд-шлюзом FastAPI, если заголовок X-Shop-Token отсутствует, заблокирован или содержит неверный API-ключ партнера.

{
  "error_code": "ERR-B2B-UNAUTHORIZED",
  "message": "B2B API токен партнера не прошел валидацию. Доступ к вебхуку отклонен.",
  "details": {
    "reason": "Invalid or revoked X-Shop-Token credential sequence."
  }
}