[DRAFT] Асинхронная обработка B2B-чеков в billing-service

Документация контура финансовых транзакций: Расчет аналитики расходов на основе вебхука торговой сети Магазин

Author

Application & Simulation Services Framework Documentation

Published

July 1, 2026

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

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

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

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

Метод представляет собой асинхронный обработчик событий (Kafka Consumer) внутри финансового микросервиса billing-service. Он предназначен для ведения автоматического учета B2B-расходов пользователей и формирования аналитики трат на основе данных, поступающих из фискального вебхука торговой сети.

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

  1. Асинхронный финансовый аудит: Вычитывает доверенное событие успешного импорта чека из брокера сообщений, итерируется по массиву товаров и рассчитывает точную суммарную стоимость всей корзины с учетом дробного веса позиций.
  2. Ведение фискальной истории (Multi-Tenancy): Сохраняет агрегированные данные транзакции и сырой лог чека в изолированную базу данных PostgreSQL Billing DB. Это позволяет пользователям видеть прозрачную аналитику расходов в разрезе магазинов, категорий и дат, не нагружая транзакционные таблицы инвентаря физической еды.
  3. Обеспечение идемпотентности фин-контура: Защищает баланс аккаунта и исторические метрики от повторного начисления сумм при дублировании сообщений в брокере Kafka за счет жесткой проверки фискального номера чека на уникальность.

Схема обработки запроса (Диаграмма последовательности Mermaid)

На диаграмме представлена логика асинхронной обработки фискальных данных после закрытия синхронного периметра вебхука. Финансовый сервис изолирован от контура холодильника и гарантирует фиксацию транзакции расходов в ACID-режиме.

sequenceDiagram
    autonumber
    
    participant K as Apache Kafka Cluster
    participant Bill as billing-service (FINANCE)
    participant DB as DB_BILLING (PostgreSQL)

    K->>Bill: Шаг 1: Вычитка события из топика bpds.inventory.in.receipt.import
    activate Bill
    
    Bill->>DB: Шаг 2: SQL SELECT id FROM b2b_transactions WHERE receipt_number = ...
    activate DB
    DB-->>Bill: Шаг 3: Проверка уникальности (Записей нет / Токен чист)
    deactivate DB
    
    note over Bill: Шаг 4: Внутренний метод:<br/>CalculateReceiptTotal()<br/>Расчет суммы: ∑(quantity * price)
    
    Bill->>DB: Шаг 5: SQL INSERT INTO b2b_transactions (UUID, total_sum...)
    activate DB
    DB-->>Bill: Шаг 6: Транзакция успешно зафиксирована (COMMIT)
    deactivate DB
    
    deactivate Bill

Процесс асинхронного расчета финансовой аналитики чека (Billing B2B Sync)

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

Шаг Действие Параметры / Запросы Ошибки (Исключения / Статусы)
Шаг 1 (KAFKA -> Bill) Фоновый воркер финансового сервиса вычитывает доверенное сообщение об импорте B2B-чека из системного топика пополнения с префиксом bpds. Топик: bpds.inventory.in.receipt.import
Handler: ProcessB2BFinancials()
Kafka: CommitFailedException (сбой фиксации офсета сдвига в кластере Kafka)
Шаг 2 (Bill -> DB_Billing) Идемпотентность финансов: Сервис проверяет, не обрабатывался ли данный фискальный документ финансовым контуром ранее, чтобы избежать двойного учета сумм. SQL-запрос:
SELECT id FROM b2b_transactions WHERE store_id = 'shop-almaty-05' AND receipt_number = 'CH-20260701-09' LIMIT 1;
PostgreSQL Exception: ConnectionPoolTimeout (отказ пула соединений финансовой СУБД)
Шаг 3 (DB_Billing -> Bill) База данных возвращает пустой результат, подтверждая, что транзакция уникальна и обрабатывается впервые. Вилка исключений (Дубликат): Если строка найдена, воркер прерывает транзакцию с логом BILLING_DUPLICATE_IGNORE. metric: billing_idempotency_blocks_total (счетчик предотвращенных начислений-дубликатов)
Шаг 4 (Bill -> Bill) Расчет аналитики: Сервис итерируется по массиву позиций чека (items) и калькулирует общую сумму расходов с учетом дробного веса. Внутренний метод: CalculateReceiptTotal()
Формула: total = sum(item.quantity * item.price)
NumericOverflowException (ошибка переполнения типа данных при некорректных ценах вендора)
Шаг 5 (Bill -> DB_Billing) Запись транзакции: Сервис открывает атомарную транзакцию и сохраняет фискальную запись, связывая её с пространством пользователя и суммой трат. SQL-запрос:
INSERT INTO b2b_transactions (home_group_id, receipt_number, store_id, total_amount, currency) VALUES ('uuid-77', 'CH-20260701-09', 'shop-almaty-05', 1191.03, 'KZT');
PostgreSQL Exception: DeadlockDetected
PostgreSQL Exception: ForeignKeyViolation
Шаг 6 (DB_Billing -> Bill) Реляционная СУБД успешно фиксирует изменения в финансовой таблице и закрывает ACID-транзакцию. Ответ СУБД: Статус COMMIT (успешная запись финансового лога). PostgreSQL Exception: DatabaseIsShuttingDown