Bỏ qua để đến nội dung

Mô hình dữ liệu kế toán — Báo cáo kép IFRS + VAS

Kho sự kiện kinh tế chung với quy tắc ghi sổ kép: một bộ cho IFRS, một bộ cho VAS.

Một bảng AccountingEvents bất biến ghi nhận điều đã xảy ra (sự kiện kinh tế). Hai engine ghi sổ riêng biệt — một theo quy tắc ghi nhận IFRS, một theo quy tắc VAS Thông tư 200/Thông tư 133 — đọc sự kiện và ghi bút toán vào sổ cái tương ứng. Bút toán IFRS và VAS được lưu riêng biệt. Báo cáo được tạo từ mỗi sổ cái độc lập.


BPO ERP phải tạo ra:

  • Báo cáo tài chính IFRS (bảng cân đối kế toán, báo cáo lãi lỗ, lưu chuyển tiền tệ) làm đầu ra chính
  • Báo cáo theo pháp định VAS (Thông tư 200/2014/TT-BTC cho doanh nghiệp vừa và lớn, Thông tư 133/2016/TT-BTC cho doanh nghiệp nhỏ) để nộp cho cơ quan quản lý Việt Nam

IFRS và VAS không chỉ đơn giản là các định dạng báo cáo khác nhau trên cùng số liệu. Chúng có quy tắc ghi nhận, cơ sở đo lường và định dạng trình bày bắt buộc khác nhau. Cùng một sự kiện kinh tế có thể yêu cầu các bút toán khác nhau theo mỗi chuẩn mực.

Điều lệ dự án đánh giá độ phức tạp của yêu cầu báo cáo kép này là Tác động cao và yêu cầu chuyên gia lĩnh vực xem xét thiết kế trước khi schema được xác nhận. Tài liệu này ghi lại quyết định kiến trúc; bảng ánh xạ mã tài khoản chi tiết phải được xác nhận riêng.


Ba ví dụ cụ thể về sự khác biệt IFRS / VAS mà phương pháp đơn giản “thêm view báo cáo VAS” không thể xử lý:

Tình huốngXử lý theo IFRSXử lý theo VAS
Thuê tài sản vận hànhIFRS 16: tài sản quyền sử dụng + nợ thuê tài chính trên bảng cân đối; chi phí khấu hao + lãi vayKhông có quy định VAS tương đương — chỉ ghi chi phí thuê
Ghi nhận doanh thuIFRS 15: mô hình 5 bước; ghi nhận khi (hoặc khi) nghĩa vụ thực hiện được thỏa mãnĐơn giản hơn; thường ghi nhận tại thời điểm xuất hóa đơn hoặc giao hàng
Hệ thống tài khoảnKhông có mã tài khoản bắt buộc — đơn vị tự xác định cấu trúcMã bắt buộc theo Thông tư 200 (ví dụ: 111 Tiền mặt, 112 Tiền gửi, 131 Phải thu, 331 Phải trả)

Ví dụ về thuê tài sản: một bút toán IFRS ghi nợ tài sản quyền sử dụng (tài khoản IFRS) và có nợ thuê tài chính (tài khoản IFRS). Không có bút toán VAS tương đương — VAS chỉ ghi chi phí thuê khi tiền mặt được thanh toán. Phương pháp chuyển đổi (suy ra VAS từ bút toán IFRS) không thể tạo ra xử lý VAS đúng vì bút toán VAS không tương ứng với bất kỳ bút toán IFRS nào.


Phương án 1: IFRS Chính, Suy ra VAS bằng chuyển đổi

Phần tiêu đề “Phương án 1: IFRS Chính, Suy ra VAS bằng chuyển đổi”

Chỉ lưu bút toán IFRS. Tại thời điểm báo cáo, áp dụng bảng ánh xạ để chuyển đổi mã tài khoản IFRS sang VAS và tạo đầu ra VAS.

Lý do bị loại: Ánh xạ IFRS → VAS không phải là dịch thuật 1:1. Với các sự kiện ghi nhận khác nhau (thuê tài sản, một số dự phòng, doanh thu hoãn lại), bút toán VAS không tồn tại hoặc khác biệt đáng kể. Quy tắc chuyển đổi không thể tạo ra bút toán VAS không có đối tác IFRS. Phương pháp này tạo ra báo cáo pháp định VAS không chính xác cho bất kỳ tenant nào có hợp đồng thuê hoặc các khác biệt tương tự.

Phương án 2: Sổ cái song song (Ghi đồng thời cả hai)

Phần tiêu đề “Phương án 2: Sổ cái song song (Ghi đồng thời cả hai)”

Mỗi giao dịch ghi đồng thời vào sổ cái IFRS và sổ cái VAS. Mỗi module (AP, AR, Kho hàng, v.v.) phải triển khai hai bộ quy tắc ghi sổ.

Đã xem xét nhưng không chọn: Đây là kiến trúc hợp lý nhưng đặt logic ghi sổ kép vào mỗi module nghiệp vụ. Module AP phải biết quy tắc AP IFRS và quy tắc AP VAS. Lương phải biết quy tắc IFRS và VAS. Kiến thức quy tắc ghi sổ bị phân tán trong codebase thay vì được tập trung. Việc đồng bộ hai bộ quy tắc khi quy định thay đổi có rủi ro vận hành cao.

Phương án 3: Sự kiện kinh tế chung + Engine ghi sổ kép ✓ Được chọn

Phần tiêu đề “Phương án 3: Sự kiện kinh tế chung + Engine ghi sổ kép ✓ Được chọn”

Sự kiện kinh tế thô được ghi một lần, bất biến. Hai engine ghi sổ — chạy như domain service — đọc sự kiện và mỗi engine ghi bút toán theo bộ quy tắc riêng của mình. Engine IFRS áp dụng quy tắc ghi nhận IFRS; engine VAS áp dụng quy tắc VAS Thông tư 200. Cả hai ghi vào bảng bút toán riêng biệt phục vụ các bộ tạo báo cáo tương ứng.

Lý do được chọn:

  • Quy tắc ghi sổ được tập trung trong engine IFRS và engine VAS, không phân tán qua các module
  • Hai sổ cái được tạo từ cùng nguồn sự kiện — không cần đối chiếu giữa sự kiện và sổ cái
  • Khi quy định VAS thay đổi (ví dụ: thông tư mới), chỉ engine VAS cần cập nhật — kho sự kiện và engine IFRS không thay đổi
  • Xử lý ghi nhận khác nhau rõ ràng: engine IFRS tạo tài sản quyền sử dụng + nợ thuê tài chính; engine VAS không tạo gì (xử lý VAS đúng với thuê vận hành)
  • Kho sự kiện cung cấp audit trail sạch độc lập với lựa chọn chuẩn mực kế toán

Đây là phác thảo thiết kế. Tên cột, kiểu dữ liệu và chiến lược index phải được hoàn thiện với kế toán viên có chứng chỉ người Việt và lập trình viên EF Core cao cấp trước khi triển khai.

AccountingEvents (Sự kiện kế toán)
────────────────────────────────────────────────
EventId UNIQUEIDENTIFIER PK
TenantId UNIQUEIDENTIFIER NOT NULL (RLS bắt buộc)
EventType NVARCHAR(100) NOT NULL -- ví dụ: 'SupplierInvoiceReceived'
EventDate DATE NOT NULL
FiscalPeriodId UNIQUEIDENTIFIER NOT NULL FK → FiscalPeriods
SourceModule NVARCHAR(50) NOT NULL -- 'AP', 'AR', 'Inventory', 'Sales'
SourceDocumentId UNIQUEIDENTIFIER NOT NULL -- FK đến tài liệu gốc
CurrencyCode CHAR(3) NOT NULL
AmountFunctional DECIMAL(18,4) NOT NULL -- theo đồng tiền chức năng của tenant
ExchangeRate DECIMAL(18,6) NULL -- NULL nếu là đồng tiền chức năng
Payload NVARCHAR(MAX) NOT NULL -- JSON: các trường đặc thù của sự kiện
PostedAt DATETIMEOFFSET NOT NULL
PostedByUserId UNIQUEIDENTIFIER NOT NULL
IsReversed BIT NOT NULL DEFAULT 0
ReversalOfEventId UNIQUEIDENTIFIER NULL FK → AccountingEvents
JournalEntries (Bút toán IFRS)
────────────────────────────────────────────────
EntryId UNIQUEIDENTIFIER PK
TenantId UNIQUEIDENTIFIER NOT NULL (RLS bắt buộc)
EventId UNIQUEIDENTIFIER NOT NULL FK → AccountingEvents
AccountId UNIQUEIDENTIFIER NOT NULL FK → ChartOfAccounts
DebitAmount DECIMAL(18,4) NOT NULL DEFAULT 0
CreditAmount DECIMAL(18,4) NOT NULL DEFAULT 0
CurrencyCode CHAR(3) NOT NULL
Description NVARCHAR(500) NULL
FiscalPeriodId UNIQUEIDENTIFIER NOT NULL FK → FiscalPeriods
VasJournalEntries (Bút toán VAS)
────────────────────────────────────────────────
EntryId UNIQUEIDENTIFIER PK
TenantId UNIQUEIDENTIFIER NOT NULL (RLS bắt buộc)
EventId UNIQUEIDENTIFIER NOT NULL FK → AccountingEvents
VasAccountId UNIQUEIDENTIFIER NOT NULL FK → VasChartOfAccounts
DebitAmount DECIMAL(18,4) NOT NULL DEFAULT 0
CreditAmount DECIMAL(18,4) NOT NULL DEFAULT 0
CurrencyCode CHAR(3) NOT NULL
Description NVARCHAR(500) NULL
FiscalPeriodId UNIQUEIDENTIFIER NOT NULL FK → FiscalPeriods
ChartOfAccounts (Hệ thống tài khoản IFRS — tenant có thể tùy chỉnh trong nguyên tắc IFRS)
────────────────────────────────────────────────
AccountId UNIQUEIDENTIFIER PK
TenantId UNIQUEIDENTIFIER NOT NULL (RLS bắt buộc)
AccountCode NVARCHAR(50) NOT NULL
AccountName NVARCHAR(200) NOT NULL
AccountType NVARCHAR(50) NOT NULL -- Tài sản, Nợ phải trả, Vốn chủ, Doanh thu, Chi phí
ParentAccountId UNIQUEIDENTIFIER NULL FK → ChartOfAccounts (phân cấp)
IsSystemAccount BIT NOT NULL -- tài khoản hệ thống không thể xóa
VasChartOfAccounts (Hệ thống tài khoản VAS Thông tư 200 / 133 — mã bắt buộc được thực thi)
────────────────────────────────────────────────
VasAccountId UNIQUEIDENTIFIER PK
TenantId UNIQUEIDENTIFIER NOT NULL (RLS bắt buộc)
AccountCode NVARCHAR(10) NOT NULL -- ví dụ: '111', '112', '131', '331'
AccountName NVARCHAR(200) NOT NULL -- tên tiếng Việt theo Thông tư 200
AccountType NVARCHAR(50) NOT NULL
CircularVersion NVARCHAR(20) NOT NULL -- 'Circular200' hoặc 'Circular133'
ParentAccountId UNIQUEIDENTIFIER NULL FK → VasChartOfAccounts
IsSystemAccount BIT NOT NULL
FiscalPeriods (Kỳ kế toán)
────────────────────────────────────────────────
FiscalPeriodId UNIQUEIDENTIFIER PK
TenantId UNIQUEIDENTIFIER NOT NULL (RLS bắt buộc)
PeriodName NVARCHAR(50) NOT NULL -- ví dụ: '2026-03'
StartDate DATE NOT NULL
EndDate DATE NOT NULL
Status NVARCHAR(20) NOT NULL -- Mở, Đang đóng, Đã đóng
ClosedAt DATETIMEOFFSET NULL
ClosedByUserId UNIQUEIDENTIFIER NULL
ExchangeRates (Tỷ giá hối đoái)
────────────────────────────────────────────────
RateId UNIQUEIDENTIFIER PK
TenantId UNIQUEIDENTIFIER NOT NULL (RLS bắt buộc)
FromCurrency CHAR(3) NOT NULL
ToCurrency CHAR(3) NOT NULL
RateDate DATE NOT NULL
Rate DECIMAL(18,6) NOT NULL
Source NVARCHAR(100) NULL -- 'Thủ công', 'VCB', 'NHNN'

Mỗi engine ghi sổ là một domain service:

  1. Nhận một AccountingEvent
  2. Tra cứu quy tắc ghi sổ cho EventType (lưu trong bảng cấu hình)
  3. Phân giải mã tài khoản cho quy tắc (sử dụng hệ thống tài khoản của tenant)
  4. Ghi các bút toán kết quả vào JournalEntries (IFRS) hoặc VasJournalEntries (VAS)
  5. Cả hai engine được gọi trong cùng một transaction cơ sở dữ liệu với việc tạo sự kiện — hoặc cả hai thành công hoặc không cái nào

Quy tắc ghi sổ được lưu dưới dạng cấu hình (không hardcode), cho phép cập nhật quy định mà không cần deploy mã:

PostingRules (Quy tắc ghi sổ)
────────────────────────────────────────────────
RuleId UNIQUEIDENTIFIER PK
Standard NVARCHAR(10) NOT NULL -- 'IFRS' hoặc 'VAS'
EventType NVARCHAR(100) NOT NULL
DebitAccountCode NVARCHAR(50) NOT NULL -- mã tài khoản (có thể tham số hóa)
CreditAccountCode NVARCHAR(50) NOT NULL
AmountExpression NVARCHAR(200) NOT NULL -- cách tính số tiền từ payload sự kiện
EffectiveFrom DATE NOT NULL
EffectiveTo DATE NULL

Mỗi module tạo giao dịch tài chính phải phát sự kiện AccountingEvent — không ghi trực tiếp vào sổ cái.

ModuleLoại sự kiện được phát
Phải trả (AP)SupplierInvoiceReceived, SupplierInvoicePaid, SupplierCreditNoteReceived
Phải thu (AR)CustomerInvoiceIssued, CustomerPaymentReceived, CustomerCreditNoteIssued
Kho hàngStockPurchased, StockSold, StockAdjustment, StockTransfer
Mua hàng(sự kiện phát khi xác nhận nhận hàng — kích hoạt sự kiện AP)
Bán hàng(sự kiện phát khi xác nhận phiếu giao hàng — kích hoạt sự kiện AR)
Đối chiếu ngân hàngBankTransactionMatched, UnreconciledItemFlagged
HR & Lương (Giai đoạn 2)PayrollRun, SocialInsuranceContribution

Các vấn đề chưa giải quyết — Cần xem xét của chuyên gia lĩnh vực

Phần tiêu đề “Các vấn đề chưa giải quyết — Cần xem xét của chuyên gia lĩnh vực”

Những điều sau không thể hoàn thiện mà không có đầu vào từ kế toán viên có chứng chỉ người Việt và cố vấn kế toán của dự án:

  1. Bảng ánh xạ quy tắc ghi sổ — với mỗi EventType, các tài khoản ghi nợ/có IFRS đúng và các tài khoản ghi nợ/có VAS Thông tư 200 đúng. Đây là cốt lõi của hệ thống báo cáo kép và phải chính xác trước khi bất kỳ module kế toán nào ra mắt.

  2. Bút toán điều chỉnh cuối kỳ đặc thù VAS — một số bút toán cuối kỳ VAS (ví dụ: đánh giá lại ngoại tệ theo VAS 10, một số dự phòng theo Thông tư 200) không có đối tác IFRS. Các loại sự kiện này phải được xác định và quy tắc ghi sổ phải được định nghĩa.

  3. Đồng tiền chức năng vs. đồng tiền trình bày (IAS 21) — phương pháp chính xác cho các tenant có đồng tiền chức năng khác VND (ví dụ: doanh nghiệp xuất khẩu với đồng tiền chức năng USD báo cáo bằng VND). Bảng ExchangeRates ở trên chỉ là placeholder; cơ chế chuyển đổi cần được chỉ định.

  4. Sự khác biệt giữa Thông tư 133 và Thông tư 200 — một số quy tắc ghi sổ khác nhau giữa hai thông tư VAS. Cột VasChartOfAccounts.CircularVersion xử lý điều này, nhưng các quy tắc khác biệt cụ thể cần được lập danh mục.

  5. Dữ liệu seed Hệ thống tài khoản VAS — các mã tài khoản và tên bắt buộc từ Thông tư 200/Thông tư 133 phải được cung cấp bởi cố vấn kế toán và nạp như dữ liệu seed hệ thống.

Không được hoàn thiện schema hoặc bắt đầu triển khai module Kế toán mà không hoàn thành việc xem xét này.