Công nợ phải thu và DSO
Bạn sẽ học được
- Chia tuổi nợ phải thu theo nhóm ngày quá hạn.
- Tính DSO và đọc ý nghĩa của nó.
- Phân biệt DSO thực tế với DSO tốt nhất có thể.
- Tính tỷ lệ thu hồi và dự phòng nợ khó đòi.
- Viết truy vấn tuổi nợ bằng SQL.
Khái niệm cốt lõi
Phải thu là tiền khách đã mua nhưng chưa trả. Hai câu hỏi cần trả lời:
- Bao nhiêu tiền đang bị giữ? — số dư phải thu.
- Bao lâu thì thu được? — tuổi nợ và DSO.
Tuổi nợ chia số dư thành các nhóm theo số ngày quá hạn so với ngày đến hạn trên hóa đơn. Nhóm càng cũ, khả năng thu càng thấp.
Ví dụ tuổi nợ
Số dư phải thu cuối quý: 900 triệu đồng.
| Nhóm tuổi | Số tiền | Tỷ trọng | Tỷ lệ dự phòng | Dự phòng |
|---|---|---|---|---|
| 0–30 ngày | 400 | 44,4% | 1% | 4,0 |
| 31–60 ngày | 250 | 27,8% | 3% | 7,5 |
| 61–90 ngày | 160 | 17,8% | 10% | 16,0 |
| Trên 90 ngày | 90 | 10,0% | 40% | 36,0 |
| Tổng | 900 | 100% | 63,5 |
Hai điều đáng chú ý:
- Chỉ 10% số dư nằm trên 90 ngày nhưng chiếm hơn nửa dự phòng.
- Nếu nhóm trên 90 ngày tăng từ 90 lên 200 trong quý sau, đó là vấn đề nghiêm trọng hơn việc tổng phải thu tăng.
Nhìn tổng số dư không đủ. Cơ cấu tuổi nợ mới cho biết chất lượng.
DSO
DSO = số dư phải thu / doanh thu trong kỳ × số ngày của kỳVới doanh thu thuần quý 2.760 triệu (90 ngày) và phải thu cuối kỳ 900 triệu:
DSO = 900 / 2.760 × 90 = 29,3 ngàyNghĩa là trung bình mất khoảng 29 ngày để thu tiền sau khi ghi doanh thu.
Điều kiện thanh toán là 30 ngày, DSO 29,3 ngày là tốt. Nếu điều kiện 30 ngày mà DSO 55 ngày, khách đang trả chậm hơn thỏa thuận gần một tháng.
DSO quá thấp cũng đáng kiểm tra: có thể doanh thu bị ghi thiếu, hoặc phần lớn khách trả trước và đang nằm ở doanh thu chờ.
DSO tốt nhất có thể
DSO thực tế bị kéo lên bởi các hóa đơn quá hạn. DSO tốt nhất giả sử toàn bộ số dư chưa quá hạn:
DSO tốt nhất = số dư chưa quá hạn / doanh thu × số ngàyVới số dư chưa quá hạn 650 triệu (400 + 250):
DSO tốt nhất = 650 / 2.760 × 90 = 21,2 ngàyChênh lệch 29,3 − 21,2 = 8,1 ngày là phần do khách trả chậm. Con số này đo hiệu quả thu hồi, tách khỏi chính sách bán chịu.
Tỷ lệ thu hồi
Tỷ lệ thu hồi = tiền thu được / số phải thu đến hạnNếu trong quý phải thu đến hạn 1.000 triệu và thu được 940 triệu, tỷ lệ là 94%. Sáu phần trăm còn lại chuyển sang nhóm tuổi cao hơn ở quý sau.
Theo dõi tỷ lệ này theo tháng cho biết quy trình thu tiền đang tốt lên hay xấu đi, nhanh hơn DSO.
Truy vấn tuổi nợ
WITH da_thu AS (
SELECT invoice_id, SUM(amount) AS tong_thu
FROM payments
GROUP BY 1
)
SELECT
CASE
WHEN CURRENT_DATE <= i.due_date THEN 'chua_den_han'
WHEN CURRENT_DATE - i.due_date <= 30 THEN '0-30'
WHEN CURRENT_DATE - i.due_date <= 60 THEN '31-60'
WHEN CURRENT_DATE - i.due_date <= 90 THEN '61-90'
ELSE '90+'
END AS nhom_tuoi,
COUNT(*) AS so_hoa_don,
SUM(i.total - COALESCE(p.tong_thu, 0)) AS con_no
FROM invoices i
LEFT JOIN da_thu p ON p.invoice_id = i.id
WHERE i.status <> 'cancelled'
AND i.total - COALESCE(p.tong_thu, 0) > 0
GROUP BY 1
ORDER BY MIN(GREATEST(CURRENT_DATE - i.due_date, 0));Điểm cần chú ý:
- Dùng
LEFT JOINđể hóa đơn chưa có thanh toán nào vẫn được tính. - Tách nhóm "chưa đến hạn" riêng, đừng gộp vào 0–30 ngày — gộp sẽ làm nhóm 0–30 trông xấu hơn thực tế.
- Điều kiện
con_no > 0loại hóa đơn đã thu đủ và hóa đơn thu thừa.
Truy vấn DSO
WITH phai_thu AS (
SELECT SUM(i.total - COALESCE(p.tong_thu, 0)) AS so_du
FROM invoices i
LEFT JOIN (
SELECT invoice_id, SUM(amount) AS tong_thu
FROM payments GROUP BY 1
) p ON p.invoice_id = i.id
WHERE i.status <> 'cancelled'
),
doanh_thu AS (
SELECT SUM(total - discount - refund) AS doanh_thu_thuan
FROM invoices
WHERE issued_at >= CURRENT_DATE - INTERVAL '90 days'
AND status <> 'cancelled'
)
SELECT
ROUND(a.so_du / NULLIF(r.doanh_thu_thuan, 0) * 90, 1) AS dso_ngay
FROM phai_thu a
CROSS JOIN doanh_thu r;NULLIF tránh chia cho 0 khi kỳ không có doanh thu. Không có nó, truy vấn lỗi hoặc trả NULL khó hiểu.
Dự phòng nợ khó đòi
Dự phòng là ước tính, không phải số thực. Cách làm phổ biến: gán tỷ lệ theo nhóm tuổi, nhân với số dư từng nhóm.
SELECT
nhom_tuoi,
con_no,
ROUND(con_no * ty_le_du_phong, 0) AS du_phong
FROM (
SELECT
CASE
WHEN CURRENT_DATE - due_date <= 30 THEN '0-30'
WHEN CURRENT_DATE - due_date <= 60 THEN '31-60'
WHEN CURRENT_DATE - due_date <= 90 THEN '61-90'
ELSE '90+'
END AS nhom_tuoi,
SUM(con_no) AS con_no,
CASE
WHEN CURRENT_DATE - due_date <= 30 THEN 0.01
WHEN CURRENT_DATE - due_date <= 60 THEN 0.03
WHEN CURRENT_DATE - due_date <= 90 THEN 0.10
ELSE 0.40
END AS ty_le_du_phong
FROM ar_aging_view
GROUP BY 1, 4
) t;Tỷ lệ phải dựa trên dữ liệu thu hồi thực tế của chính công ty, không sao chép từ nơi khác. Mỗi quý so sánh dự phòng với số thực sự mất để điều chỉnh.
Lỗi thường gặp
- Nhìn tổng phải thu, bỏ cơ cấu tuổi: số dư không đổi nhưng chất lượng xấu đi.
- Gộp chưa đến hạn vào 0–30: đánh giá sai.
- Dùng
INNER JOIN: bỏ hóa đơn chưa thu được đồng nào. - Tính DSO bằng doanh thu gộp: DSO bị thấp giả tạo.
- Dùng DSO một tháng bất thường: nhiễu mùa vụ.
- Không trừ hóa đơn huỷ: phải thu phồng.
- Dự phòng theo cảm tính: không phản ánh rủi ro thật.
Thực hành
- Lập bảng tuổi nợ từ số dư 900 triệu với bốn nhóm.
- Tính DSO với doanh thu quý 2.760 triệu.
- Tính DSO tốt nhất với số dư chưa quá hạn 650 triệu.
- Tính dự phòng theo bảng tỷ lệ.
- Viết truy vấn tuổi nợ có tách nhóm chưa đến hạn.
Lỗi thường gặp
| Triệu chứng | Nguyên nhân | Cách sửa |
|---|---|---|
| DSO tăng dần | Khách trả chậm | Xem nhóm tuổi cao |
| Phải thu không đổi, tiền mặt giảm | Cơ cấu tuổi xấu đi | Theo dõi tỷ lệ thu hồi |
| DSO thấp bất thường | Bỏ sót doanh thu | Kiểm tra doanh thu chờ |
| Nhóm 0–30 quá lớn | Gộp chưa đến hạn | Tách nhóm riêng |
| Phải thu cao hơn sổ cái | Hóa đơn huỷ | Lọc trạng thái |
| Dự phòng luôn thiếu | Tỷ lệ không từ dữ liệu thật | Hiệu chỉnh theo lịch sử |
Tóm tắt
- Tuổi nợ cho biết chất lượng phải thu, không chỉ số lượng.
- DSO = phải thu / doanh thu × số ngày.
- DSO tốt nhất tách phần chậm trả khỏi chính sách bán chịu.
- Tỷ lệ thu hồi phản ứng nhanh hơn DSO.
- Dự phòng dựa trên tỷ lệ mất thực tế theo nhóm tuổi.
Dùng ← → để chuyển bài