DHDataHọc
TheoryLesson 3/86 min read+10 XP

Kiểm soát đối soát

Bạn sẽ học được

  • Ba nguồn cần đối soát: cổng thanh toán, ngân hàng, sổ cái.
  • Phân loại chênh lệch: phí, hoàn tiền, thời điểm, lỗi thật.
  • Viết truy vấn đối soát bằng FULL OUTER JOIN.
  • Thiết kế sổ theo dõi ngoại lệ.
  • Xây thói quen đối soát hằng ngày thay vì cuối tháng.

Khái niệm cốt lõi

Đối soát là quá trình chứng minh ba nguồn số liệu khớp nhau:

code
Cổng thanh toán (gross, phí, hoàn tiền)
        ↓
Sao kê ngân hàng (tiền thực vào)
        ↓
Sổ cái / kho dữ liệu (doanh thu, phải thu)

Ba nguồn luôn lệch nhau ở một mức nào đó. Mục tiêu không phải "không có chênh lệch" mà là mọi chênh lệch đều được giải thích và ghi lại.

Ví dụ một ngày

KhoảnSố tiền (triệu đồng)
Giao dịch gộp trên cổng1.000
Phí cổng 2,5%−25
Hoàn tiền−30
Cổng chuyển về ngân hàng945
Sao kê ngân hàng945
Chênh lệch0

Nếu chỉ so "doanh thu 1.000" với "tiền vào 945", sẽ tưởng thiếu 55 triệu. Thực ra 25 triệu là phí và 30 triệu là hoàn tiền — cả hai đều hợp lệ.

Phân loại chênh lệch

LoạiVí dụXử lý
Phí cổng2,5% mỗi giao dịchGhi nhận chi phí, không phải thiếu tiền
Hoàn tiềnKhách trả lại hàngGiảm doanh thu, giảm tiền
Thời điểmCổng chuyển tiền T+1Chênh lệch tạm thời, tự khớp hôm sau
Tiền tệThanh toán USD, hạch toán VNDDùng tỷ giá ngày giao dịch
Lỗi thậtGiao dịch mất, ghi trùngĐiều tra, điều chỉnh
Gian lậnChargebackTranh chấp, dự phòng

Chỉ hai loại cuối cần hành động ngay. Bốn loại đầu là bình thường và phải được mô hình hoá, không phải "sửa" bằng tay mỗi tháng.

Truy vấn đối soát

code
WITH cong AS (
  SELECT
    gateway_txn_id AS ma,
    SUM(amount) AS gross,
    SUM(fee) AS phi,
    SUM(refund_amount) AS hoan
  FROM gateway_transactions
  WHERE settled_date = CURRENT_DATE - 1
  GROUP BY 1
),
ngan_hang AS (
  SELECT
    reference AS ma,
    SUM(amount) AS tien_vao
  FROM bank_statement
  WHERE value_date = CURRENT_DATE - 1
  GROUP BY 1
)
SELECT
  COALESCE(c.ma, n.ma) AS ma,
  c.gross,
  c.phi,
  c.hoan,
  COALESCE(c.gross, 0) - COALESCE(c.phi, 0) - COALESCE(c.hoan, 0) AS du_kien,
  n.tien_vao,
  COALESCE(n.tien_vao, 0)
    - (COALESCE(c.gross, 0) - COALESCE(c.phi, 0) - COALESCE(c.hoan, 0)) AS chenh_lech
FROM cong c
FULL OUTER JOIN ngan_hang n USING (ma)
WHERE COALESCE(n.tien_vao, 0)
      - (COALESCE(c.gross, 0) - COALESCE(c.phi, 0) - COALESCE(c.hoan, 0)) <> 0
ORDER BY ABS(chenh_lech) DESC;

Truy vấn chỉ trả về các dòng lệch — đó là danh sách việc cần làm. FULL OUTER JOIN bắt được cả hai chiều: giao dịch có trên cổng nhưng chưa về ngân hàng, và tiền về ngân hàng nhưng không có giao dịch tương ứng.

Đối soát với sổ cái

Bước thứ ba: sổ cái ghi doanh thu và phải thu. Đối soát ba chiều:

code
SELECT
  (SELECT SUM(amount) FROM payments WHERE paid_at::date = CURRENT_DATE - 1) AS tien_thu_so_cai,
  (SELECT SUM(tien_vao) FROM bank_statement WHERE value_date = CURRENT_DATE - 1) AS tien_vao_ngan_hang,
  (SELECT SUM(gross - phi - hoan) FROM gateway_transactions WHERE settled_date = CURRENT_DATE - 1) AS du_kien_cong;

Ba con số phải bằng nhau, trừ chênh lệch thời điểm đã biết. Nếu không, tìm nguồn nào sai trước khi điều chỉnh bất kỳ bên nào.

Nguyên tắc: không sửa số liệu để khớp. Nếu lệch, tìm nguyên nhân; chỉ điều chỉnh khi đã hiểu vì sao.

Sổ ngoại lệ

Mỗi chênh lệch chưa giải thích cần một dòng trong sổ ngoại lệ:

code
CREATE TABLE reconciliation_exceptions (
  id            bigserial PRIMARY KEY,
  ngay          date NOT NULL,
  ma_giao_dich  text,
  so_tien       numeric(14,2) NOT NULL,
  loai          text NOT NULL,   -- 'phi' | 'hoan' | 'thoi_diem' | 'loi' | 'chargeback'
  mo_ta         text NOT NULL,
  trang_thai    text NOT NULL DEFAULT 'mo',  -- 'mo' | 'da_xu_ly'
  nguoi_xu_ly   text,
  xu_ly_luc     timestamptz
);

Mỗi tuần xem sổ này. Ngoại lệ tồn đọng quá 30 ngày là dấu hiệu quy trình đang hỏng, không phải "chuyện nhỏ".

Tần suất và dung sai

  • Hằng ngày: đối soát cổng ↔ ngân hàng cho ngày hôm trước. Chênh lệch nhỏ dễ tìm hơn nhiều.
  • Hằng tuần: đối soát sổ cái, xem ngoại lệ tồn đọng.
  • Cuối tháng: khoá sổ, đối chiếu tổng với báo cáo tài chính.

Dung sai: với khối lượng lớn, cho phép sai số do làm tròn (ví dụ 1.000 đồng mỗi giao dịch). Nhưng dung sai phải được định nghĩa trước, không phải "thấy lệch nhỏ thì bỏ qua".

Lỗi thường gặp

  • Đối soát mỗi tháng: hàng nghìn giao dịch, không tìm được nguyên nhân.
  • So tổng doanh thu với tiền vào ngân hàng: bỏ phí và hoàn tiền, luôn thấy thiếu.
  • Dùng INNER JOIN: bỏ mất giao dịch chỉ có ở một bên — chính là các trường hợp cần tìm.
  • Điều chỉnh số liệu cho khớp: che mất lỗi thật.
  • Bỏ qua T+1: chênh lệch thời điểm bị coi là lỗi.
  • Không ghi ngoại lệ: cùng một vấn đề lặp lại mỗi tháng.
  • Bỏ qua chargeback: mất tiền thật nhưng không được ghi nhận.

Thực hành

  1. Tính số tiền cổng phải chuyển về với gross 1.000, phí 2,5%, hoàn 30.
  2. Viết truy vấn FULL OUTER JOIN chỉ trả các dòng lệch.
  3. Phân loại năm chênh lệch giả định vào bảng loại.
  4. Thiết kế cột cho sổ ngoại lệ.
  5. Viết quy trình xử lý một chargeback.

Lỗi thường gặp

Triệu chứngNguyên nhânCách sửa
Ngân hàng thiếu so với doanh thuPhí và hoàn tiềnTính tiền ròng dự kiến
Lệch đúng một ngàyT+1Đối soát theo ngày quyết toán
Giao dịch mất tíchINNER JOINDùng FULL OUTER JOIN
Chênh lệch lặp lạiKhông ghi ngoại lệSổ ngoại lệ, xử lý gốc
Số liệu bị sửa tayĐiều chỉnh để khớpTìm nguyên nhân trước
Cuối tháng mới phát hiệnĐối soát thángChuyển sang hằng ngày

Tóm tắt

  • Ba nguồn: cổng, ngân hàng, sổ cái — phải khớp sau khi trừ phí và hoàn tiền.
  • Phân loại chênh lệch trước khi xử lý.
  • FULL OUTER JOIN là công cụ đúng để tìm giao dịch lệch một bên.
  • Mọi chênh lệch chưa giải thích vào sổ ngoại lệ.
  • Đối soát hằng ngày rẻ hơn nhiều so với đối soát cuối tháng.

Use ← → to move between lessons