ADR-0002. Hạch toán theo sự kiện; ghi nhận finance tại payment, không phải checkout
| Field | Value |
|---|---|
| Status | Accepted |
| Date | 2026-04-28 |
| Deciders | finance-team, sale-team |
| Supersedes | — |
Bối cảnh
- Finance không được nằm trên đường tới hạn của checkout POS — một sự cố finance không thể chặn việc thu tiền.
- Doanh thu chỉ là thật khi tiền thực sự settle. Ghi nhận tại checkout (trước payment) sẽ book thu nhập cho các đơn sau đó bị bỏ hoặc fail payment.
- Giá trị COGS và tài sản tồn kho do
@nx/inventorysở hữu, vốn chỉ biết cost basis sau khi xuất kho — finance không thể tính. - Tài khoản/danh mục thanh toán được chọn là một quyết định lúc-khách-hàng mang theo payload thanh toán bán hàng (
payment.attempt.finance), không biết tại checkout.
Quyết định
Chúng tôi sẽ làm finance phản ứng với Kafka event, không bao giờ gọi nó đồng bộ từ checkout. Finance subscribe năm topic và post phiếu như side effect:
| Sự kiện inbound | Phiếu |
|---|---|
PAYMENT_SUCCESS (sale) | RECEIPT trên tài khoản tại attempt.finance.source.id |
PURCHASE_ORDER_RECEIVED (inventory) | PAYMENT cho vendor (+ leg tài sản tồn kho) |
INVENTORY_ISSUED_FOR_SALE (inventory) | ADJUSTMENT — DEBIT COGS / CREDIT INVENTORY |
INVENTORY_ADJUSTED (inventory) | ADJUSTMENT một dòng trên INVENTORY |
MERCHANT CDC (commerce) | đối soát tài khoản mặc định + kiểm soát |
Thu nhập được book khi PAYMENT_SUCCESS, không tại checkout. Nếu payload thanh toán không mang tài khoản được chọn (attempt.finance.source.id), finance INFO-skip thay vì đoán.
Hệ quả
| Ưu | Nhược |
|---|---|
| Sự cố finance không bao giờ chặn checkout | Hạch toán nhất quán cuối cùng, không đồng bộ |
| Thu nhập phản ánh tiền đã settle, không phải ý định | Cần idempotency cho delivery at-least-once (xem ADR-0003) |
| Hạch toán COGS/tài sản dùng cost basis chính thống của inventory | Finance phụ thuộc vào sự đầy đủ của payload upstream (account id) |
| Tách bạch mối quan tâm rõ ràng giữa các service | Debug trải nhiều service + broker |
Các phương án đã cân nhắc
| Phương án | Ưu | Nhược | Lý do loại bỏ |
|---|---|---|---|
| HTTP đồng bộ từ checkout sale | Đơn giản, tức thì | Ghép latency/availability checkout với finance | Vi phạm "finance ngoài đường tới hạn" |
| Ghi nhận tại checkout (ý định) | Tín hiệu sớm nhất | Book doanh thu cho đơn chưa trả/bỏ | Kế toán sai |
| Finance tự tính COGS | Ít event hơn | Finance sẽ nhân đôi logic tính giá vốn của inventory | Cost basis là domain của inventory |
Tham chiếu
packages/finance/src/components/kafka/component.ts(SUBSCRIBED_TOPICS,_dispatchMessage)packages/finance/src/services/finance-worker.service.ts(mọi methodhandle*)- Sale ADR-0003 — payment via webhook
- Integration