ADR-0002. Ghi sổ theo sự kiện; ghi nhận finance tại lúc thanh toán, không phải lúc checkout
| Field | Value |
|---|---|
| Status | Accepted |
| Date | 2026-04-28 |
| Deciders | Phat Nguyen |
| Supersedes | - |
Bối cảnh
- Finance không được nằm trên luồng quan trọng của quy trình checkout POS - một sự cố của finance không được phép chặn việc thu tiền.
- Doanh thu chỉ có thật khi tiền thực sự về tài khoản. Ghi nhận tại lúc checkout (trước khi thanh toán) sẽ ghi nhận doanh thu cho cả những đơn về sau bị bỏ dở hoặc thanh toán thất bại.
- Giá trị giá vốn (COGS) và tài sản tồn kho thuộc quyền của
@nx/inventory, vốn chỉ biết được giá vốn sau khi xuất kho - finance không thể tự tính. - Tài khoản/danh mục thanh toán được chọn là một quyết định tại thời điểm phục vụ khách hàng, đi kèm trong payload thanh toán của sale (
payment.attempt.finance), không biết được tại lúc checkout.
Quyết định
Chúng tôi sẽ để finance phản ứng theo Kafka event, không bao giờ gọi nó đồng bộ từ luồng checkout. Finance lắng nghe năm topic và ghi sổ các phiếu như một tác động phụ:
| Sự kiện đầu vào | Phiếu |
|---|---|
PAYMENT_SUCCESS (sale) | RECEIPT trên tài khoản tại attempt.finance.source.id |
PURCHASE_ORDER_RECEIVED (inventory) | PAYMENT cho nhà cung cấp (+ vế 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 + tài khoản kiểm soát |
Doanh thu được ghi nhận khi có PAYMENT_SUCCESS, không phải tại lúc checkout. Nếu payload thanh toán không mang theo tài khoản được chọn (attempt.finance.source.id), finance ghi log INFO rồi bỏ qua thay vì đoán.
Hệ quả
| Ưu | Nhược |
|---|---|
| Sự cố finance không bao giờ chặn checkout | Việc ghi sổ là nhất quán cuối cùng, không đồng bộ |
| Doanh thu phản ánh tiền đã về tài khoản, không phải ý định | Cần idempotent cho cơ chế gửi ít nhất một lần (xem ADR-0003) |
| Ghi sổ giá vốn/tài sản dùng đúng giá vốn chính thống từ inventory | Finance phụ thuộc vào tính đầy đủ của payload từ thượng nguồn (account id) |
| Tách bạch rõ trách nhiệm giữa các service | Việc gỡ lỗi trải qua nhiều service + broker |
Các phương án đã cân nhắc
| Phương án | Ưu | Nhược | Lý do loại bỏ |
|---|---|---|---|
| Gọi HTTP đồng bộ từ luồng checkout của sale | Đơn giản, tức thì | Buộc độ trễ/khả dụng của checkout phụ thuộc finance | Vi phạm nguyên tắc "finance nằm ngoài luồng quan trọng" |
| Ghi nhận tại lúc checkout (theo ý định) | Tín hiệu sớm nhất | Ghi nhận doanh thu cho cả đơn chưa trả/bỏ dở | Hạch toán sai |
| Finance tự tính giá vốn | Ít event hơn | Finance sẽ lặp lại logic tính giá vốn của inventory | Giá vốn thuộc phạm vi 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