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
[DRAFT] Асинхронная обработка B2B-чеков в billing-service
Документация контура финансовых транзакций: Расчет аналитики расходов на основе вебхука торговой сети Магазин
1 Функциональное назначение
Метод представляет собой асинхронный обработчик событий (Kafka Consumer) внутри финансового микросервиса billing-service. Он предназначен для ведения автоматического учета B2B-расходов пользователей и формирования аналитики трат на основе данных, поступающих из фискального вебхука торговой сети.
Метод решает следующие архитектурные задачи:
- Асинхронный финансовый аудит: Вычитывает доверенное событие успешного импорта чека из брокера сообщений, итерируется по массиву товаров и рассчитывает точную суммарную стоимость всей корзины с учетом дробного веса позиций.
- Ведение фискальной истории (Multi-Tenancy): Сохраняет агрегированные данные транзакции и сырой лог чека в изолированную базу данных
PostgreSQL Billing DB. Это позволяет пользователям видеть прозрачную аналитику расходов в разрезе магазинов, категорий и дат, не нагружая транзакционные таблицы инвентаря физической еды. - Обеспечение идемпотентности фин-контура: Защищает баланс аккаунта и исторические метрики от повторного начисления сумм при дублировании сообщений в брокере Kafka за счет жесткой проверки фискального номера чека на уникальность.
2 Схема обработки запроса (Диаграмма последовательности Mermaid)
На диаграмме представлена логика асинхронной обработки фискальных данных после закрытия синхронного периметра вебхука. Финансовый сервис изолирован от контура холодильника и гарантирует фиксацию транзакции расходов в ACID-режиме.
3 Расшифровка шагов
| Шаг | Действие | Параметры / Запросы | Ошибки (Исключения / Статусы) |
|---|---|---|---|
Шаг 1 (KAFKA -> Bill) |
Фоновый воркер финансового сервиса вычитывает доверенное сообщение об импорте B2B-чека из системного топика пополнения с префиксом bpds. |
Топик: bpds.inventory.in.receipt.importHandler: 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: DeadlockDetectedPostgreSQL Exception: ForeignKeyViolation |
Шаг 6 (DB_Billing -> Bill) |
Реляционная СУБД успешно фиксирует изменения в финансовой таблице и закрывает ACID-транзакцию. | Ответ СУБД: Статус COMMIT (успешная запись финансового лога). |
PostgreSQL Exception: DatabaseIsShuttingDown |