Tại sao một developer cần học kế toán?
Hầu hết developer khi nghe “kế toán” đều nghĩ đây là công việc của phòng tài vụ. Nhưng trong Core Banking, kế toán kép chính là business logic cốt lõi nhất mà code của bạn phải thực thi. Nếu code của bạn sai, sổ cái mất cân bằng, ngân hàng không thể báo cáo lên Ngân hàng Nhà nước và hậu quả pháp lý là vô cùng nghiêm trọng.
Nguyên lý Kế toán Kép (Double-Entry Bookkeeping)
Được phát minh từ thế kỷ 15 bởi nhà toán học người Ý Luca Pacioli, nguyên lý này chỉ có một quy tắc duy nhất:
Mọi giao dịch tài chính đều phải được ghi chép vào ít nhất hai tài khoản, một bên Nợ (Debit) và một bên Có (Credit), với tổng giá trị hai bên phải bằng nhau.
Ví dụ thực tế: Khách hàng A chuyển 1.000.000 VNĐ cho khách hàng B
Trong tư duy thông thường, developer hay nghĩ đơn giản:
account_A.balance -= 1_000_000
account_B.balance += 1_000_000
Đây là sai về mặt kế toán. Cách đúng là ghi vào bảng General Ledger (GL):
| ID | Tài khoản (Account) | Loại bút toán | Số tiền |
|---|---|---|---|
| TX1 | Tài khoản A | Nợ (Debit) | 1.000.000 |
| TX1 | Tài khoản B | Có (Credit) | 1.000.000 |
Tổng Nợ = Tổng Có = 1.000.000 → Sổ cái cân bằng ✅
Bảng General Ledger (GL) — Trái tim của Core Banking
Toàn bộ hệ thống Core Banking thực ra chỉ xoay quanh việc ghi dữ liệu vào bảng GL một cách chính xác. Đây là thiết kế cơ bản nhất của bảng GL:
CREATE TABLE ledger_entries (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
transaction_id UUID NOT NULL, -- Nhóm các bút toán cùng giao dịch
account_id UUID NOT NULL, -- Tài khoản nào bị ảnh hưởng
entry_type VARCHAR(6) NOT NULL, -- 'DEBIT' hoặc 'CREDIT'
amount BIGINT NOT NULL, -- Lưu theo đơn vị nhỏ nhất (VD: đồng, cents)
currency CHAR(3) NOT NULL, -- 'VND', 'USD', 'JPY'
balance_after BIGINT NOT NULL, -- Số dư sau bút toán này
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
description TEXT,
CONSTRAINT chk_amount_positive CHECK (amount > 0),
CONSTRAINT chk_entry_type CHECK (entry_type IN ('DEBIT', 'CREDIT'))
);
Lưu ý quan trọng: Luôn lưu tiền theo đơn vị nguyên (integer) — đồng, cents, satoshi. Không bao giờ dùng
FLOAThayDOUBLEđể lưu tiền vì lỗi làm tròn số thực (floating-point precision error) sẽ làm sổ cái mất cân bằng sau hàng nghìn giao dịch.
Kiểm tra sức khoẻ sổ cái: The Balance Invariant
Đây là câu query bạn phải có khả năng chạy bất kỳ lúc nào để xác nhận sổ cái không bị hỏng:
-- Tổng tất cả bút toán Nợ PHẢI LUÔN bằng tổng tất cả bút toán Có
SELECT
SUM(CASE WHEN entry_type = 'DEBIT' THEN amount ELSE 0 END) AS total_debits,
SUM(CASE WHEN entry_type = 'CREDIT' THEN amount ELSE 0 END) AS total_credits,
SUM(CASE WHEN entry_type = 'DEBIT' THEN amount ELSE 0 END) -
SUM(CASE WHEN entry_type = 'CREDIT' THEN amount ELSE 0 END) AS imbalance
FROM ledger_entries;
-- Kết quả mong đợi: imbalance = 0
Nếu imbalance ≠ 0, có nghĩa là code của bạn đã ghi thiếu một bút toán ở đâu đó — đây là lỗi nghiêm trọng nhất trong Core Banking.
Cấu trúc tài khoản trong ngân hàng
Không phải tài khoản nào cũng là tài khoản của khách hàng. Trong ngân hàng, có nhiều loại tài khoản nội bộ:
| Loại tài khoản | Ý nghĩa | Ví dụ |
|---|---|---|
| Asset (Tài sản) | Tiền ngân hàng đang nắm giữ | Tiền mặt tại quỹ, Cho vay KH |
| Liability (Nợ phải trả) | Tiền ngân hàng nợ khách hàng | Số dư tài khoản của KH |
| Income (Thu nhập) | Doanh thu của ngân hàng | Phí giao dịch, lãi vay thu |
| Expense (Chi phí) | Chi phí của ngân hàng | Lãi tiết kiệm phải trả |
| Equity (Vốn chủ sở hữu) | Vốn của cổ đông | Vốn điều lệ |
Khi khách hàng gửi 10 triệu vào tài khoản tiết kiệm, hệ thống phải ghi:
- Nợ Tài khoản Tiền Mặt (Asset tăng lên)
- Có Tài khoản Tiết Kiệm Khách Hàng (Liability tăng lên — ngân hàng đang nợ KH)
Bài học cốt lõi
- Không bao giờ chỉ cập nhật số dư trực tiếp (
UPDATE accounts SET balance = balance - X). Luôn ghi bút toán vào ledger, rồi tính số dư từ ledger. - Mỗi giao dịch là một đơn vị nguyên tử — tất cả các bút toán phải cùng thành công hoặc cùng thất bại (Database Transaction).
- Ledger là immutable — không bao giờ UPDATE hay DELETE một bút toán đã ghi. Để sửa lỗi, bạn ghi thêm bút toán đảo chiều (reversal entry).
Tiếp theo, chúng ta sẽ áp dụng tư duy kế toán kép vào các nghiệp vụ cụ thể nhất của ngân hàng. Đọc tiếp Phần 2 — Nghiệp vụ Ngân hàng Lõi: CIF, CASA & Lending.