Skip to content

PRD: Hạch toán tài chính theo sự kiện (seam bán hàng → sổ cái)

ModuleTài chính (CORE-12)PRD IDPRD-EVT-001
Trạng tháiShippedChủ sở hữuFinance squad
Ngày2026-06-15Phiên bảnv1.0
Packages@nx/finance · @nx/coreURDEVT · VCH · WAL

TL;DR

Tài chính không ghi các dòng tiền thường nhật bằng tay và không chen vào đường găng của đơn bán. Thay vào đó, nó đăng ký nhận các sự kiện vận hành vốn đã xảy ra - một thanh toán bán hàng thành công, một đơn mua hàng được nhận, hàng xuất kho cho một đơn bán, một biến động giá trị tồn kho, một merchant được tạo - và hạch toán mỗi sự kiện thành một phiếu cân bằng qua luồng sự kiện, bất đồng bộ. Seam này là at-least-once: một sự kiện chỉ được xác nhận sau khi hạch toán của nó commit, nên một sự cố sẽ phát lại sự kiện thay vì làm mất nó; và mọi hạch toán đều idempotent - một sự kiện phát lại phát lại phiếu nó đã tạo thay vì hạch toán hai lần. Hành động bán, mua, hay kho gốc không bao giờ phải chờ sổ sách bắt kịp.

1. Bối cảnh & Vấn đề

Bộ máy phiếu (PRD-VCH-001) định nghĩa cái gì là một phiếu cân bằng và cách dựng sẵn tài khoản tiền. Nó không định nghĩa làm sao phần còn lại của hệ thống báo cho Tài chính biết có gì đó đã xảy ra. Nếu hạch toán là đồng bộ - đơn bán gọi Tài chính nội tuyến và chờ - thì một lượt ghi sổ chậm hoặc thất bại sẽ làm chậm hoặc chặn việc thu tiền của khách. Điều đó không chấp nhận được tại điểm bán.

Gắn sổ sách vào request thanh toán cũng khiến cả hai phía mong manh: một sự cố Tài chính sẽ làm đình trệ bán hàng, và một request thanh toán bị thử lại có nguy cơ hạch toán doanh thu hai lần. Merchant cần sổ sách đầy đủ và đúng về sau, chứ không phải đồng bộ và mong manh.

Bước tăng này đặc tả seam khép lại khoảng trống đó: các dịch vụ vận hành phát sự kiện, và một consumer Tài chính chuyên dụng đọc chúng ngoài luồng, phân giải mỗi sự kiện về tài khoản và đối tác của nó, rồi hạch toán phiếu tương ứng - một cách tin cậy (không sự kiện nào âm thầm mất), idempotent (không sự kiện nào hạch toán hai lần), và không bao giờ chặn hành động đã tạo ra nó.

2. Mục tiêu & Phi mục tiêu

Mục tiêu

  • Hạch toán phiếu tài chính bất đồng bộ từ sự kiện vận hành, không bao giờ trên đường găng của hành động gốc.
  • Đăng ký nhận đầy đủ các sự kiện liên quan tiền: thanh toán bán hàng thành công, nhận đơn mua hàng, xuất kho cho đơn bán, điều chỉnh tồn kho, tạo merchant.
  • Bảo đảm xử lý at-least-once: chỉ xác nhận một sự kiện sau khi hạch toán của nó commit; một handler thất bại để lại sự kiện cho phát lại.
  • Làm mọi hạch toán tự động idempotent - một sự kiện phát lại phát lại phiếu sẵn có thay vì tạo phiếu thứ hai.
  • Phân giải mỗi sự kiện - vốn chỉ mang định danh - về tài khoản, danh mục, đối tác, và tham chiếu nguồn đọc được trước khi hạch toán.
  • Ngắt sạch khi không có gì để ghi (không định tuyến tài chính, cơ sở giá vốn bằng 0, chênh lệch giá trị bằng 0, không có tiền thừa) - không phiếu rỗng hay không cân bằng.

Phi mục tiêu

  • Bản thân mô hình phiếu/sổ cái - cân bằng, loại tài khoản, đánh số, hủy bằng bút toán đảo - đặc tả trong PRD-VCH-001.
  • Hạch toán đồng bộ tại thời điểm request - bị bác bỏ rõ ràng; hạch toán là theo sự kiện.
  • Tính số lượng và định giá kho (Tồn kho) - Tài chính tiêu thụ cơ sở giá vốn kết quả, không tính nó.
  • Xử lý cổng thanh toán (Payment) - Tài chính phản ứng với một thanh toán đã thành công, không cấp phép thanh toán.
  • Sổ đối tác, phải thu/phải trả, và P&L (LDG) - một bước tăng riêng.

3. Chỉ số thành công

Chỉ sốMục tiêu / tín hiệu
Không chặnViệc thu tiền không bao giờ chờ một lượt ghi phiếu; đơn bán hoàn tất bất kể độ trễ Tài chính
Độ phủ hạch toánMọi sự kiện liên quan tiền cần ghi phiếu đều tạo đúng một phiếu
IdempotencyMột sự kiện phát lại không bao giờ tạo phiếu thứ hai - nó phát lại phiếu đầu
Độ bềnKhông sự kiện liên quan tiền nào mất khi handler sự cố; nó được phát lại và hạch toán
Truy vếtMọi phiếu tự hạch toán liên kết về chứng từ nguồn và sự kiện gốc của nó
Ngắt sạchSự kiện không có gì để ghi không để lại phiếu và không lỗi

4. Chân dung & Tình huống

Chân dungMục tiêu trong tính năng
Chủ / Kế toánTin rằng bán hàng, mua hàng, biến động kho lên sổ tự động và đầy đủ
Thu ngânThu tiền tức thì - việc sổ sách bắt kịp là vô hình và không bao giờ làm chậm đơn bán
Hệ thống (consumer Tài chính)Đọc mỗi sự kiện vận hành, phân giải nó, và hạch toán đúng phiếu đúng một lần
Vận hành / TrựcDựa vào phát lại cho lỗi nhất thời; xem các trường hợp bỏ qua cố ý trong log

Tình huống cốt lõi: thu ngân thu tiền → đơn bán phát một sự kiện thanh toán thành công và đơn hoàn tất ngay → consumer Tài chính đọc sự kiện khỏi luồng, phân giải tài khoản đã định tuyến và danh mục Sale, rồi hạch toán một phiếu thu cân bằng liên kết tới đơn → nếu consumer sự cố giữa chừng, sự kiện được phát lại và hạch toán một lần → nếu cùng sự kiện được giao hai lần, lần giao thứ hai phát lại phiếu sẵn có thay vì hạch toán hai lần.

5. User Story

  • thu ngân, tôi muốn thanh toán hoàn tất tức thì, để sổ chậm hay sập không bao giờ giữ chân khách.
  • kế toán, tôi muốn một đơn được thanh toán, một PO được nhận, và hàng xuất kho tự hạch toán phiếu, để sổ luôn đầy đủ mà không nhập tay.
  • chủ, tôi muốn một sự cố Tài chính nhất thời bắt kịp về sau thay vì làm mất bút toán, để sổ không bao giờ thiếu một đơn bán.
  • hệ thống, tôi muốn một sự kiện phát lại phát lại phiếu sẵn có, để một lần thử lại hay phát lại không bao giờ hạch toán doanh thu hay giá vốn hai lần.
  • trực, tôi muốn sự kiện không có gì để ghi được bỏ qua lặng lẽ và ghi log, để không bị gọi vì những phi-sự-kiện.
  • kế toán, tôi muốn mỗi phiếu tự hạch toán liên kết tới đơn, PO, hay biến động nguồn của nó, để truy vết bất kỳ hạch toán nào về nguyên nhân.

6. Yêu cầu chức năng

#Yêu cầuURD ref
FR-1Tài chính tiêu thụ sự kiện vận hành bất đồng bộ qua luồng sự kiện; hành động gốc không bao giờ bị chặn để chờ hạch toánURD-EVT-001
FR-2Đăng ký nhận: thanh toán bán hàng thành công, nhận đơn mua hàng, xuất kho cho đơn bán, điều chỉnh tồn kho, và tạo merchantURD-EVT-002
FR-3Một thanh toán bán hàng thành công hạch toán một phiếu thu; một phiếu chi trả lại tiền thừa khi tiền khách đưa vượt tổng đơnURD-EVT-003 · URD-VCH-003
FR-4Một đơn mua hàng được nhận hạch toán một phiếu chi cho nhà cung cấp, thêm vế tài sản tồn kho khi giá trị nhận dươngURD-EVT-004 · URD-VCH-004
FR-5Hàng xuất kho cho một đơn bán hạch toán một phiếu giá vốn (giá vốn so với tài khoản kiểm soát tồn kho) khi cơ sở giá vốn dươngURD-EVT-005 · URD-VCH-005
FR-6Một biến động giá trị tồn kho do người vận hành hạch toán một phiếu điều chỉnh tồn kho một dòng vào tài khoản kiểm soát tồn khoURD-EVT-006 · URD-VCH-005
FR-7Một merchant mới dựng sẵn tài khoản mặc định và tài khoản kiểm soát nội bộ từ sự kiện vòng đời merchantURD-EVT-007 · URD-WAL-003
FR-8Mọi hạch toán tự động đều idempotent - một sự kiện phát lại phát lại phiếu sẵn có, không bao giờ tạo phiếu thứ haiURD-EVT-008 · URD-VCH-006
FR-9Một sự kiện chỉ được xác nhận sau khi hạch toán của nó commit; một handler thất bại để lại sự kiện cho phát lại (at-least-once)URD-EVT-009
FR-10Sự kiện chỉ mang định danh; worker phân giải đầy đủ danh tính nguồn và đối tác (NCC, mã PO, tài khoản) trước khi hạch toánURD-EVT-010 · URD-VCH-007
FR-11Hạch toán ngắt sạch không tạo phiếu khi không có gì để ghi (không định tuyến tài chính, cơ sở giá vốn bằng 0, chênh lệch giá trị bằng 0, không có tiền thừa)URD-EVT-011
FR-12Consumer rút cạn công việc đang xử lý và đóng sạch khi nhận tín hiệu tắtURD-EVT-012

Toàn văn yêu cầu và tiêu chí chấp nhận nằm trong Finance URD - EVT. PRD này tham chiếu chúng thay vì lặp lại. Bản thân mô hình phiếu/sổ cái đặc tả trong PRD-VCH-001.

7. Yêu cầu phi chức năng

Khu vựcYêu cầu
Tách rờiHạch toán hoàn toàn bất đồng bộ qua luồng sự kiện; không hành động vận hành nào chờ một lượt ghi Tài chính
Đảm bảo giaoAt-least-once - một sự kiện chỉ được commit sau khi handler của nó thành công; một sự cố phát lại nó
IdempotencyHạch toán được khóa theo định danh duy nhất của sự kiện gốc (hoặc chứng từ nguồn của nó); một lần phát lại phát lại phiếu sẵn có
Toàn vẹn dữ liệuMột phiếu và các dòng sổ cái của nó được ghi cùng nhau và cân bằng; không hạch toán dở dang nào sống sót qua một sự cố
Tenancy & authzMọi hạch toán giới hạn theo merchant; worker phân giải tài khoản trong merchant của sự kiện
Kháng lỗiMột tài khoản kiểm soát thiếu hoặc nguồn chưa phân giải phát lỗi để sự kiện được phát lại, không âm thầm bỏ rơi
Độ chính xácSố học tiền tệ dùng float(value, 4); một loại tiền tệ mỗi phiếu, mặc định VND
i18nLý do phiếu và tên đối tác song ngữ ({ en, vi })

8. UX & Luồng

Hạch toán theo sự kiện, không theo màn hình. Bước tăng này không có UI Tài chính - seam chạy phía sau các hành động thường ngày của merchant.

Bản đồ chủ đề-tới-hạch toán:

9. Dữ liệu & Miền

Khái niệmVai trò trong seam
Sự kiện vận hànhMột sự thật được phát (thanh toán thành công, nhận PO, xuất kho, điều chỉnh tồn kho, tạo merchant) mang định danh, không mang bản ghi đầy đủ
Consumer Tài chínhBộ đăng ký chuyên dụng đọc mỗi sự kiện, định tuyến tới handler, hạch toán, rồi xác nhận
Tham chiếu nguồnLiên kết mà một phiếu đã hạch toán mang về chứng từ nguồn của nó (đơn bán, PO, biến động kho)
Khóa idempotency sự kiệnĐịnh danh duy nhất của sự kiện gốc dùng để phát hiện một lần phát lại và phát lại phiếu sẵn có
Voucher / LedgerLineChứng từ kế toán cân bằng và các dòng của nó mà handler phát hành - đặc tả trong PRD-VCH-001

Chỉ mang tính khái niệm - hợp đồng sự kiện, chủ đề, và đấu nối consumer nằm trong tài liệu dev finance; schema phiếu nằm trong mô hình miền finance.

10. Phụ thuộc & Giả định

Phụ thuộc

  • Bộ máy phiếu (PRD-VCH-001, VCH) - seam phát hành các phiếu mà bộ máy này cân bằng và đánh số.
  • Tài khoản (WAL) - tài khoản mặc định và kiểm soát phải được dựng trước khi hạch toán định tuyến; sự kiện merchant dựng chúng.
  • Payment (@nx/core) - phát sự kiện thanh-toán-thành-công dẫn động phiếu thu.
  • Inventory (@nx/inventory) - phát sự kiện nhận-PO, xuất-kho, và điều-chỉnh-tồn-kho.
  • Commerce / Merchant (@nx/commerce) - phát sự kiện vòng đời merchant kích hoạt dựng tài khoản.

Giả định

  • Các dịch vụ vận hành phát sự kiện của chúng một cách tin cậy; việc của seam là tiêu thụ chúng bền bỉ.
  • Mỗi sự kiện mang đủ định danh (merchant, chứng từ nguồn, tài khoản, số tiền/cơ sở giá vốn) để phân giải và hạch toán.
  • Tài khoản kiểm soát nội bộ của merchant tồn tại trước khi hạch toán giá vốn và điều chỉnh tồn kho được thực hiện.

11. Rủi ro & Câu hỏi mở

Rủi ro / câu hỏiGiảm thiểu / trạng thái
Một sự kiện phát lại có thể hạch toán hai lầnHạch toán idempotent - khóa theo id sự kiện; một lần phát lại phát lại phiếu sẵn có
Một sự cố handler có thể làm mất một sự kiện tiềnAt-least-once - sự kiện chỉ được xác nhận sau khi hạch toán commit, nên sự cố phát lại nó
Hạch toán đồng bộ sẽ chặn đơn bánBị bác bỏ theo thiết kế - hạch toán hoàn toàn bất đồng bộ qua luồng sự kiện
Một tài khoản kiểm soát thiếu khi sự kiện giá vốn/điều chỉnh đếnHandler phát lỗi thay vì âm thầm bỏ qua, nên sự kiện được phát lại khi tài khoản tồn tại
Sự kiện không có gì để ghiCố ý ngắt sạch (không định tuyến tài chính, giá vốn 0, chênh lệch 0, không tiền thừa) - ghi log, không phiếu, không lỗi
Sự kiện độc luôn thất bạiPhát lại được vận hành giới hạn; thất bại dai dẳng nổi lên trong log lỗi để xem xét

12. Kế hoạch phát hành & Tiêu chí ra mắt

Khía cạnhKế hoạch
PhaseP1 (nền tảng) - EVT trong danh mục tính năng URD, cùng VCHWAL
Triển khaiMọi merchant; không feature flag - seam luôn bật
Di trúKhông - consumer đăng ký nhận sự kiện vốn đã được bán hàng, payment, và tồn kho phát
Tiêu chí ra mắtMột đơn được thanh toán, một PO được nhận, và hàng xuất kho mỗi cái hạch toán phiếu của nó bất đồng bộ; một sự kiện phát lại hạch toán một lần; một sự cố handler phát lại và hạch toán một lần; sự kiện không có gì để ghi không để lại phiếu
Giám sátLượng hạch toán và tỷ lệ lỗi theo chủ đề, số lần phát-lại idempotent, số lần bỏ-qua cố ý, độ trễ consumer

13. FAQ

Việc thu tiền có chờ sổ sách cập nhật không? Không - đơn bán hoàn tất ngay và phát một sự kiện; Tài chính hạch toán phiếu về sau, qua luồng. Việc sổ bắt kịp là vô hình với thu ngân.

Điều gì xảy ra nếu Tài chính sập khi một đơn được thanh toán? Sự kiện chờ trên luồng. Khi Tài chính hồi phục nó đọc sự kiện và hạch toán phiếu - không mất gì, vì một sự kiện chỉ được xác nhận sau khi hạch toán commit.

Cùng một sự kiện có thể hạch toán hai lần không? Không - mọi hạch toán đều idempotent. Một sự kiện phát lại được phát hiện theo định danh và phát lại phiếu nó đã tạo thay vì hạch toán phiếu thứ hai.

Vì sao đôi khi một đơn bán bị "bỏ qua" trong log? Đó là phát lại idempotent - lần giao thứ hai tìm thấy phiếu sẵn có và phát lại thay vì hạch toán hai lần.

Sự kiện nào không tạo phiếu? Sự kiện không có gì để ghi - một thanh toán không định tuyến tài chính, một lần xuất kho cơ sở giá vốn 0, một biến động kho chênh lệch giá trị 0, hoặc một đơn bán không có tiền thừa. Chúng được ngắt sạch và ghi log, không phải lỗi.

Logic cân bằng và đánh số ở đâu? Trong bộ máy phiếu (PRD-VCH-001). PRD này phủ seam giao sự kiện tới bộ máy đó một cách tin cậy và đúng một lần.

Tham chiếu

Proprietary and Confidential. Unauthorized copying, distribution, or use of this software is strictly prohibited.