- Given Có một khoá học
- When Thêm các gói học phí (loại, tên, giá, số buổi, số tháng có hiệu lực, số lần trả góp, mức VAT, tài liệu mặc định)
- Then Các gói xuất hiện trong wizard chuyển đổi và biểu mẫu nhập học; một khoá học có thể có nhiều gói; các gói đã ngừng hoạt động vẫn được giữ trên các hoá đơn cũ.
PRD 05 · Học phí và tài chính
Gói học phí và gói buổi, hoá đơn và phiếu thu, thanh toán tiền mặt và chuyển khoản có đối soát qua SePay, giảm giá và mã giảm giá, công nợ theo tuổi nợ, hoàn tiền và phiếu giảm, phiếu chi, điểm kết nối hoá đơn điện tử, và báo cáo doanh thu. Tái sử dụng các đối tượng Tuition, GroupInvoice, Course, tài khoản ngân hàng và công ty đã có sẵn.
Xuất xứ / Prompt / Giới hạn
Tài liệu do trợ lý AI soạn trong một phiên làm việc ngày 10/09/2026, theo yêu cầu gốc được trích nguyên văn ở trang mục lục; mục Thiết kế đề xuất được bổ sung ngày 16/09/2026. Đây là bản đề xuất để đội thảo luận, chưa phải quyết định của đội sản phẩm.
Nguồn
- Nghiên cứu công khai về đối thủ cạnh tranh (PSE ONE, pse4.one), mã nguồn
center-crm-frontendvà đặc tả OpenAPI/v3trên staging (182 endpoint), tính đến ngày 10/09/2026. - Nhãn existing / extend / new trong trang được xác định bằng cách đối chiếu với đặc tả
/v3trên staging tại thời điểm trên.
Giới hạn
- Cần xác minh khi khảo sát trực tiếp trong ứng dụng, vì đăng nhập tự động vào sản phẩm tham chiếu chưa được cấp phép trong phiên soạn:
- Luồng học phí của đối thủ "đăng ký gói học, nộp tiền, đặt lịch" và "chốt số buổi còn": cách gói buổi và số buổi còn lại được mô hình hoá.
- Các trường, cách đánh số và phân nhóm của phiếu thu và phiếu chi.
- Các trường của mã giảm giá: theo phần trăm hay số tiền, dùng một lần hay nhiều lần, phạm vi áp dụng.
- Liệu có tự động khớp chuyển khoản hay chỉ ghi nhận thủ công.
- Cách "công nợ" được hiển thị (theo học viên, theo hoá đơn) và liệu có phân loại theo tuổi nợ hay không.
- Liệu đã có tích hợp hoá đơn điện tử hay chưa, và với nhà cung cấp nào.
Thiết kế đề xuất
Bảy màn hình dùng chung khung School OS: danh sách hoá đơn với KPI và tuổi nợ, biểu mẫu tạo hoá đơn dạng ngăn kéo, chi tiết hoá đơn với bảng thanh toán, hộp thoại thu tiền có đối soát SePay, công nợ theo nhóm tuổi nợ, sổ quỹ với phiếu chi và cấu hình gói học phí. Điều quan trọng nhất: mọi ngoại lệ về tiền (vượt hạn mức giảm giá, vượt ngưỡng phiếu chi, quá hạn) đều hiện thành trạng thái Chờ duyệt hoặc chip đỏ ngay trong danh sách, không giấu trong chi tiết.







1Mục đích
Các trung tâm bán việc học theo ba hình thức: một khoá học trả một lần (hoặc trả góp), một mức học phí theo tháng, hoặc một gói N buổi học được trừ dần theo điểm danh. Trung tâm thu tiền qua chuyển khoản kèm mã QR, tiền mặt tại quầy, và đôi khi qua thẻ. Trung tâm cần một phiếu thu khiến phụ huynh tin tưởng, một danh sách công nợ mà bộ phận lễ tân có thể xử lý, và một bức tranh hằng tháng về doanh thu, số tiền đã thu và chi phí theo từng chi nhánh. Backend hiện đã có đối tượng Tuition với chi phí, giảm giá, VAT, trạng thái thanh toán, các giao dịch (tiền mặt và chuyển khoản) và tài khoản ngân hàng đã xác thực qua SePay, một hoá đơn nhóm (group invoice) cho việc lập hoá đơn hàng loạt theo tháng, một hồ sơ pháp lý công ty và tính năng tạo mã QR thanh toán. PRD này bổ sung các gói học phí, gói buổi có số dư, thanh toán một phần và đánh số phiếu thu, mã giảm giá, hoàn tiền, phiếu chi và điểm kết nối hoá đơn điện tử.
Trong phạm vi
- Gói học phí theo từng khoá học: trọn khoá, trả góp, theo tháng, gói buổi; tài liệu là dòng mục riêng trên hoá đơn.
- Tạo hoá đơn (học phí) đơn lẻ và theo lô; giảm giá có phê duyệt; mã giảm giá.
- Thanh toán: tiền mặt, chuyển khoản (tự động khớp qua SePay), thẻ/POS ghi nhận thủ công; thanh toán một phần; phiếu thu có đánh số và bản PDF; mã QR thanh toán.
- Số dư gói buổi, hạn sử dụng, nạp thêm, chuyển đổi, đóng băng khi bảo lưu.
- Danh sách công nợ và phân loại tuổi nợ, nhắc học phí (PRD 07), kế hoạch trả góp.
- Hoàn tiền và phiếu giảm; phiếu chi theo nhóm; sổ quỹ.
- Điểm kết nối hoá đơn điện tử với một nhà cung cấp tại Việt Nam (ở P1 chỉ có giao diện kết nối).
- Báo cáo doanh thu, số tiền đã thu, doanh thu hoãn lại.
Ngoài phạm vi
- Sổ cái tổng hợp, khai thuế VAT, kế toán bảng lương (chỉ xuất dữ liệu).
- Tích hợp cổng thanh toán thẻ; thanh toán qua POS được ghi nhận thủ công.
- Hoa hồng cho nhân viên bán hàng.
2Hiện trạng
| Đối tượng / endpoint | Trường và hành vi | Tái sử dụng |
|---|---|---|
Tuition (/v3/teacher/school-finance/tuitions) | student, class_id, course, title, description, note, cost, amount, discount_pct, vat_pct, payment_status UNPAID|PAID, overdue, notification_status, paid_amount, payment_code, bank_account_id, due_date, paid_at, teacher; chi tiết bổ sung bank_account, qr_url, transactions[] | Là hoá đơn (invoice). Mở rộng thêm fee_plan, dòng mục, trạng thái PARTIAL, phiếu thu |
POST .../tuitions (CreateTuitionRequest) | students[{student_id, cost, amount, discount_pct, note}], class_id, course_id, title, description, vat_pct, bank_account_id, due_date | Tạo theo lô cho từng lớp; giữ nguyên |
POST .../tuitions/{id}/pay (PayTuitionRequest) | amount, method CASH|BANK_TRANSFER, note → TuitionTransaction (sepay_transaction_id khi khớp được) | Là khoản thanh toán (payment). Mở rộng thêm phương thức CARD, số phiếu thu, người thu tiền (cashier) |
GroupInvoice | title, course_id, classes[], totals, notify_app/zalo/email | Lượt lập hoá đơn hàng tháng |
tuitions/stats, classes/{id}/students/tuitions (month groups), students/{id}/tuitions, students/{id}/stats | tổng số liệu, theo lớp, theo học viên | Báo cáo và hồ sơ |
tuitions/{id}/notify, tuitions/notify (batch) | kênh app, email, zalo kèm kết quả theo từng kênh và lý do bỏ qua | Nhắc học phí |
SchoolBankAccount, link-token, manual accounts | Kết nối SePay hoặc thủ công; cờ đang hoạt động | Tài khoản nhận tiền theo từng chi nhánh |
SchoolCompany | legal_name, type ENTERPRISE|INDIVIDUAL, tax_id or citizen_id, address, issued info, sepay_company_xid | Đơn vị phát hành phiếu thu và hoá đơn điện tử |
POST /v3/payment/qr | account, bank id, amount, add_info → QR | Mã QR thanh toán kèm payment_code |
Course | price, pricing_method ONE_TIME|MONTHLY, split_payment_count | Nền tảng cho các gói học phí |
/v3/parent/tuitions, /overview | giao diện phụ huynh xem hoá đơn theo từng con | Cổng phụ huynh |
CRM packages, customers/{id}/packages | danh mục bán hàng và giá trị dự kiến trên một lead | Chỉ dùng trước khi bán; không phải gói học phí |
3Khái niệm và các loại gói học phí
| Loại gói học phí | VI | Cách lập hoá đơn | Số dư | Ví dụ |
|---|---|---|---|---|
one_time | Trọn khoá | Một hoá đơn khi nhập học; có thể trả góp (n phần với ngày đến hạn) | không có; quyền học kết thúc khi lớp kết thúc | Movers 2 · 48 buổi · 9.600.000 |
monthly | Theo tháng | Lập hoá đơn mỗi tháng qua lượt lập hoá đơn (GroupInvoice), tháng đầu tính theo tỷ lệ số buổi học | không có | 1.200.000 / tháng |
session_package | Gói buổi | Lập hoá đơn khi mua; số buổi được cộng vào số dư của học viên, có hạn sử dụng | sessions_remaining | Gói 24 buổi · 6.000.000 · hạn 6 tháng |
material | Tài liệu / phí khác | Dòng mục trên bất kỳ hoá đơn nào (sách, đồng phục, phí thi) | không có | Sách Family and Friends 2 · 180.000 |
Một hoá đơn (đối tượng Tuition đã có) có các dòng mục, một khoản giảm giá, VAT, một ngày đến hạn, một trạng thái thanh toán unpaid | partial | paid | void và các khoản thanh toán. Một phiếu thu được phát hành cho mỗi lần thanh toán, đánh số tuần tự theo từng chi nhánh. Một phiếu giảm hoàn lại một phần giá trị của hoá đơn; một khoản hoàn tiền là một khoản chi gắn với một phiếu giảm. Một phiếu chi là một khoản chi không gắn với học viên. Sổ quỹ liệt kê toàn bộ các khoản thu và chi theo từng tài khoản (quầy tiền mặt hoặc tài khoản ngân hàng).
4User story và tiêu chí chấp nhận
- Given Có một học viên và quyền
finance.invoice.create - When Chọn gói học phí hoặc các dòng tự do, số lượng, giảm giá (theo phần trăm hoặc số tiền, kèm lý do), mã giảm giá, ngày đến hạn, tài khoản nhận tiền
- Then Một hoá đơn được tạo (dùng chức năng tạo Tuition hiện có) với các dòng mục, tổng tiền, VAT, payment_code và mã QR; giảm giá vượt hạn mức của người dùng đặt trạng thái pending_approval và thông báo cho quản lý chi nhánh; một gói buổi được cộng số buổi khi thanh toán đủ (hoặc ngay khi tạo hoá đơn nếu cấu hình tenant "cấp buổi khi tạo hoá đơn" được bật).
- Given Có các lớp dùng gói học phí theo tháng
- When Chạy "Lập hoá đơn tháng 10" cho các lớp đã chọn
- Then Một GroupInvoice được tạo với một Tuition cho mỗi lượt ghi danh đang hoạt động, tính theo tỷ lệ cho học viên bắt đầu học giữa tháng dựa trên số buổi còn lại trên tổng số buổi trong tháng, bỏ qua các học viên đang bảo lưu trong toàn bộ tháng đó, kèm bảng xem trước trước khi xác nhận và thông báo theo kênh đã chọn.
- Given Có một hoá đơn chưa thanh toán hoặc thanh toán một phần
- When Ghi nhận số tiền, phương thức Tiền mặt, tên người thanh toán
- Then Một khoản thanh toán được tạo (dùng endpoint thanh toán hiện có, đã mở rộng), số phiếu thu
PT-<branch>-YYYYMM-####được cấp, một bản PDF phiếu thu được tạo kèm thông tin pháp lý của công ty, và phụ huynh nhận được phiếu qua Zalo nếu đã đồng ý; hoá đơn chuyển sang trạng thái thanh toán một phần hoặc đã thanh toán.
- Given Có một tài khoản đã liên kết SePay và một hoá đơn có payment_code trong mã QR
- When Khi giao dịch chuyển khoản đến với mã trong nội dung chuyển khoản
- Then Khoản thanh toán được tạo tự động kèm sepay_transaction_id, phiếu thu được phát hành, phụ huynh được thông báo; các giao dịch chuyển khoản không khớp được mã sẽ vào mục "Chưa đối soát" để đối soát thủ công với một hoá đơn hoặc số dư của học viên; số tiền chuyển một phần được chấp nhận là thanh toán một phần.
- Given Có các hoá đơn đã quá ngày đến hạn
- When Mở Công nợ
- Then Xem được danh sách học viên còn nợ, phân theo nhóm tuổi nợ (0–7, 8–30, 31–60, trên 60 ngày), ngày nhắc gần nhất, ngày hẹn thanh toán; có thể gửi nhắc theo lô (dùng chức năng gửi thông báo theo lô hiện có) với một mẫu tin, ghi lại cuộc gọi, hoặc đặt một kế hoạch trả góp (chia thành các phần theo ngày).
- Given Học viên có 24 buổi đã được cộng vào số dư
- When Khi điểm danh ghi nhận có mặt, muộn hoặc vắng (theo chính sách)
- Then Số dư bị trừ theo nguyên tắc FIFO giữa các gói theo hạn sử dụng; khi còn 3 buổi, phụ huynh và lễ tân được thông báo "Sắp hết buổi"; khi còn 0 buổi, học viên xuất hiện trong mục "Hết buổi" và danh sách lớp hiển thị chip màu đỏ; bảo lưu sẽ đóng băng hạn sử dụng.
- Given Học viên đã nghỉ học còn buổi chưa dùng hoặc tháng chưa dùng
- When Tạo một phiếu giảm (đề xuất tính tự động: số buổi chưa dùng nhân đơn giá, trừ phí xử lý theo chính sách, có thể chỉnh sửa kèm lý do) và một khoản thanh toán hoàn tiền (tiền mặt hoặc chuyển khoản)
- Then Hoá đơn hiển thị khoản giảm, khoản hoàn tiền xuất hiện trong sổ quỹ như một khoản chi, số dư được đặt về 0, và cần quản lý chi nhánh phê duyệt nếu vượt ngưỡng cấu hình của tenant.
- Given Có một nhóm mã giảm giá
- When Tạo các mã (dùng một lần hoặc nhiều lần, theo phần trăm hoặc số tiền, số tiền tối thiểu, khoá học áp dụng, chi nhánh, thời hạn hiệu lực, số lần dùng tối đa)
- Then Các mã có thể được áp dụng khi tạo hoá đơn, có kiểm tra hợp lệ và theo dõi số lần sử dụng theo từng học viên.
- Given Có quyền
finance.expense.create - When Tạo một phiếu chi với nhóm chi phí, số tiền, người nhận, tài khoản (quầy tiền mặt hoặc ngân hàng), ngày, tệp đính kèm
- Then Phiếu chi xuất hiện trong sổ quỹ; các khoản chi vượt ngưỡng cần được phê duyệt; việc chốt quỹ hằng ngày so sánh số dư thực tế trong quầy với số tiền đã ghi nhận.
- Given Có một hoá đơn đã thanh toán và một nhà cung cấp đã được cấu hình (giao diện adapter; nhà cung cấp đầu tiên được chọn ở P2)
- When Chọn Xuất hoá đơn điện tử và nhập thông tin người mua
- Then Yêu cầu được gửi đến nhà cung cấp, số hoá đơn và mã tra cứu trả về được lưu trên hoá đơn, và liên kết PDF sẽ có sẵn; nếu thất bại, thông báo lỗi từ nhà cung cấp được hiển thị kèm tuỳ chọn thử lại.
- Given Có một khoảng thời gian và chi nhánh
- When Mở Báo cáo tài chính
- Then Xem được số tiền đã lập hoá đơn, đã thu, còn phải thu, quá hạn, hoàn tiền, chi phí, tiền mặt thực còn, tỷ lệ thu tiền, doanh thu theo khoá học và theo loại gói học phí, doanh thu hoãn lại (giá trị các buổi chưa sử dụng), có thể xem chi tiết từng hoá đơn và xuất file.
5Màn hình
Các ô KPI: Đã lập tháng này, Đã thu, Còn phải thu, Quá hạn. Các tab: Tất cả · Chưa thanh toán · Thanh toán một phần · Quá hạn · Chờ duyệt · Đã thanh toán · Đã huỷ. Bộ lọc: chi nhánh, lớp, khoá học, loại gói học phí, khoảng ngày đến hạn, khoảng ngày tạo, q (học viên, mã, payment code). Nút: + Tạo hoá đơn, Lập hoá đơn tháng, Xuất Excel.
| Cột | Ghi chú |
|---|---|
| Mã HĐ | payment_code |
| Học viên | tên + chip lớp |
| Nội dung | title (tên gói học phí) |
| Tổng tiền | amount sau khi giảm giá và VAT |
| Đã thu | paid_amount |
| Còn lại | amount - paid; màu đỏ khi quá hạn |
| Hạn | due_date; chip số ngày quá hạn |
| Trạng thái | chip |
| Nhắc gần nhất | ngày + kênh |
| Thao tác | Thu tiền · Gửi nhắc · In |
| Trường | Kiểu dữ liệu | Ràng buộc |
|---|---|---|
| Học viên | tìm kiếm | bắt buộc |
| Lớp | chọn từ các lớp của học viên | không bắt buộc |
| Dòng | có thể lặp lại: gói học phí hoặc tài liệu hoặc dòng tự do; số lượng; đơn giá; giảm giá theo dòng | ≥ 1 dòng; giá ≥ 0 |
| Giảm giá | theo phần trăm hoặc số tiền + lý do + mã giảm giá | ≤ hạn mức, nếu vượt cần phê duyệt |
| VAT | phần trăm theo từng dòng, mặc định lấy từ gói | 0–10 |
| Hạn thanh toán | ngày | mặc định hôm nay + 7 ngày |
| Trả góp | công tắc: chia thành n phần kèm ngày và số tiền | tổng các phần bằng tổng hoá đơn |
| Tài khoản nhận | chọn từ các tài khoản ngân hàng đang hoạt động của chi nhánh | bắt buộc để tạo QR |
| Ghi chú | văn bản | |
| Gửi thông báo | kênh app / Zalo / email | mặc định lấy từ cấu hình |
Phần chân hiển thị tạm tính, giảm giá, VAT, tổng tiền; sau khi lưu hiển thị mã QR và nút "Thu tiền ngay".
Phần đầu: mã hoá đơn, học viên, chip trạng thái, tổng tiền, đã thu, còn lại, hạn thanh toán. Các phần: dòng mục; bảng thanh toán (ngày, phương thức, số tiền, số phiếu thu, người thu tiền, mã SePay, PDF); phiếu giảm; nhật ký nhắc; khối hoá đơn điện tử; nhật ký thay đổi. Nút: Thu tiền, Gửi nhắc, In hoá đơn, Tạo phiếu giảm, Huỷ (chỉ khi chưa có thanh toán nào), Xuất HĐĐT.
Các trường: số tiền (mặc định là số còn lại), phương thức (Tiền mặt / Chuyển khoản / Thẻ), tài khoản (quầy tiền mặt của chi nhánh hoặc tài khoản ngân hàng), tên người thanh toán, ngày (mặc định là hiện tại, không được chọn ngày trong tương lai), ghi chú, công tắc "Gửi biên lai Zalo". Kết quả: số phiếu thu, xem trước PDF, in.
Các ô tổng hợp theo tuổi nợ; bảng theo từng học viên: học viên, số điện thoại phụ huynh, số hoá đơn, tổng nợ, ngày đến hạn xa nhất, nhóm tuổi nợ, lần nhắc gần nhất, ngày hẹn trả, người phụ trách chăm sóc; thao tác theo dòng: Gửi nhắc, Ghi cuộc gọi, Kế hoạch trả, Thu tiền. Theo lô: Gửi nhắc (chọn mẫu tin).
Bộ lọc: chi nhánh, tài khoản, khoảng ngày, loại (thu/chi), nhóm. Bảng: ngày, mã (PT/PC), loại, nhóm, đối tượng giao dịch, số tiền thu, số tiền chi, tài khoản, người tạo, tệp đính kèm. Nút: + Phiếu chi, Chốt quỹ ngày (hiển thị số dự kiến so với số đã kiểm với chênh lệch và ghi chú). Tab Chưa đối soát liệt kê các giao dịch SePay chưa khớp, kèm nút "Gán vào hoá đơn".
Nhóm theo khoá học. Biểu mẫu: tên, loại, giá, số buổi (đối với gói buổi), số tháng hiệu lực, số lần trả góp và quy tắc, VAT, tài liệu mặc định, đang hoạt động. Nhóm mã giảm giá và các mã nằm ở /settings/vouchers; nhóm chi phí nằm ở /settings/expense-categories; đánh số phiếu thu và thông tin công ty nằm ở /settings/finance.
6Quy tắc nghiệp vụ
- Tổng hoá đơn = Σ(qty × unit_price - line_discount) - invoice_discount + VAT. Làm tròn đến VND nguyên.
- Trạng thái thanh toán: unpaid (đã thu 0), partial (0 < đã thu < tổng), paid (đã thu ≥ tổng), void (không có thanh toán, đã huỷ). Thanh toán vượt quá số cần thu bị từ chối; phần vượt chỉ trở thành số dư của học viên qua luồng xử lý chuyển khoản chưa đối soát.
- Phiếu thu được đánh số theo từng chi nhánh, theo từng tháng, tuần tự và không tái sử dụng; huỷ một khoản thanh toán vẫn giữ nguyên số phiếu với trạng thái void và yêu cầu một lý do.
- Số buổi từ một gói được cộng khi thanh toán đủ theo mặc định; tenant có thể chọn cộng ngay khi tạo. Hạn sử dụng = ngày cộng buổi + thời hạn hiệu lực, được kéo dài theo các lần bảo lưu.
- Thứ tự trừ buổi: gói có hạn sử dụng gần nhất bị trừ trước; việc trừ một buổi từ gói đã hết hạn bị từ chối và học viên hiển thị "Hết hạn gói".
- Hạn mức giảm giá theo từng vai trò (mặc định: tư vấn tuyển sinh 10%, giáo vụ 5%, kế toán 15%, quản lý chi nhánh 30%, chủ trung tâm không giới hạn) là cấu hình của tenant; vượt hạn mức cần phê duyệt.
- Mã giảm giá: mỗi hoá đơn chỉ dùng một mã; không kết hợp được với giảm giá theo phần trăm lớn hơn 0, trừ khi được đánh dấu có thể kết hợp (stackable).
- Phiếu giảm không được vượt quá tổng hoá đơn trừ đi các khoản giảm trước đó; hoàn tiền không được vượt quá số đã thu trừ đi các khoản hoàn tiền trước đó.
- Phiếu chi và hoàn tiền vượt ngưỡng cấu hình của tenant (mặc định 5.000.000) cần quản lý chi nhánh hoặc chủ trung tâm phê duyệt.
- Quầy tiền mặt được quản lý theo từng chi nhánh; chốt quỹ hằng ngày khoá các khoản thanh toán trong ngày đó khỏi việc chỉnh sửa (chỉ được huỷ/void).
- Mọi thay đổi liên quan đến tiền đều được ghi nhật ký với trạng thái trước/sau (PRD 12).
7Mô hình dữ liệu
| Thực thể | Trường | Ghi chú |
|---|---|---|
| fee_plan | id uuid; tenant_id; course_id null; name; type enum(one_time, monthly, session_package, material); price; sessions int null; validity_months null; instalments jsonb null [{pct, days_after}]; vat_pct; default_material_ids uuid[]; is_active | new |
| tuition (existing Tuition) | + fee_plan_id; status enum extends PAID/UNPAID with PARTIAL, VOID, PENDING_APPROVAL; discount_amount; discount_reason; voucher_id; approved_by; instalment_of uuid null; einvoice jsonb {provider, number, lookup_code, pdf_url, issued_at} | extend |
| tuition_line | id; tuition_id; type enum(fee, material, other); fee_plan_id null; inventory_item_id null; description; qty; unit_price; discount; vat_pct; amount | new |
| payment (existing TuitionTransaction) | + method CARD; receipt_no; account_id (cash drawer or bank); payer_name; paid_at; cashier_staff_id; status enum(valid, void); void_reason; receipt_pdf_file_id | extend |
| session_package | id; student_id; tuition_id; fee_plan_id; sessions_total; sessions_used; credited_at; expires_on; frozen_days; status enum(pending, active, exhausted, expired, refunded) | new |
| session_consumption | id; package_id; attendance_record_id; consumed_at; reversed_at null | new |
| credit_note | id; tuition_id; amount; reason; created_by; approved_by; created_at | new |
| refund | id; credit_note_id; amount; method; account_id; paid_to; paid_at; receipt_no (PC); status | new (khoản chi) |
| expense | id; school_id; code PC-; category_id; amount; payee; account_id; date; note; file_id; created_by; approved_by; status | new |
| cash_account | id; school_id; type enum(cash_drawer, bank); bank_account_id null; name; is_active | new; các dòng ngân hàng ánh xạ theo SchoolBankAccount |
| cash_close | id; cash_account_id; date; expected; counted; difference; note; closed_by | new |
| voucher_group, voucher, voucher_use | group: name, type percent|amount, value, min_amount, course_ids, school_ids, valid_from, valid_to, max_uses; voucher: code, single_use; use: voucher_id, tuition_id, student_id, used_at | new |
| unmatched_transaction | id; bank_account_id; sepay_transaction_id; amount; description; received_at; matched_tuition_id null; matched_by | new |
| finance_settings | receipt_prefix; numbering_scope; credit_on_create bool; discount_limits {role: pct}; approval_thresholds; einvoice_provider config (encrypted) | cấu hình tenant |
8Hợp đồng API
| Method | Path | Request / response | Status |
|---|---|---|---|
| GET/POST/PUT/DELETE | /v3/teacher/school-finance/course/courses[...] | thông tin cơ bản của khoá học | existing |
| GET/POST/PATCH | /v3/school/fee-plans[/{id}] | lọc theo course_id | new |
| GET | /v3/teacher/school-finance/tuitions | bộ lọc như hiện tại, cộng thêm fee_plan_type, status gồm cả PARTIAL, aging_bucket | extend |
| POST | /v3/teacher/school-finance/tuitions | như hiện tại, cộng thêm lines[], discount_amount, discount_reason, voucher_code, instalments[] → 202 PENDING_APPROVAL khi vượt hạn mức | extend |
| GET | /v3/teacher/school-finance/tuitions/{id} | + lines, credit_notes, reminders, einvoice, package | extend |
| POST | /v3/teacher/school-finance/tuitions/{id}/pay | {amount, method CASH|BANK_TRANSFER|CARD, account_id, payer_name, paid_at?, note, send_receipt} → khoản thanh toán kèm receipt_no, pdf | extend |
| POST | /v3/school/payments/{id}/void | {reason} | new |
| GET | /v3/school/payments/{id}/receipt.pdf | đường dẫn đã ký (signed URL) | new |
| POST | /v3/school/tuitions/{id}/approve | /reject | {note} | new |
| POST | /v3/school/tuitions/{id}/void | {reason}; chỉ khi chưa có thanh toán hợp lệ nào | new |
| POST | /v3/teacher/school-finance/tuitions/{id}/notify, /tuitions/notify | nhắc học phí; bổ sung template_id | extend |
| GET/POST | /v3/teacher/school-finance/group-invoices | bổ sung POST với {title, month, class_ids[], fee_plan_id?, prorate: bool, notify: {app, zalo, email}, dry_run} | extend |
| GET | /v3/school/debt | school_id, bucket, class_id, q → số liệu tổng hợp theo từng học viên | new |
| POST | /v3/school/tuitions/{id}/payment-plan | {parts: [{amount, due_date}]} | new |
| GET | /v3/school/students/{id}/packages | danh sách gói buổi kèm lịch sử tiêu thụ | new |
| POST | /v3/school/packages/{id}/adjust | {sessions_delta, reason} cộng/trừ buổi thủ công (cần phê duyệt) | new |
| POST | /v3/school/tuitions/{id}/credit-notes | {amount, reason} → phiếu giảm (cần phê duyệt nếu vượt ngưỡng) | new |
| POST | /v3/school/credit-notes/{id}/refund | {amount, method, account_id, paid_to} | new |
| GET | /v3/school/refund-estimate?student_id= | đề xuất tính theo chính sách | new |
| GET/POST/PATCH | /v3/school/expenses[/{id}]; POST /approve | new | |
| GET/POST | /v3/school/expense-categories | new | |
| GET | /v3/school/cashbook | school_id, account_id, from, to, type, category → danh sách; format=xlsx | new |
| GET/POST | /v3/school/cash-accounts; POST /v3/school/cash-accounts/{id}/close | {date, counted, note} | new |
| GET/POST | /v3/school/unmatched-transactions; POST /{id}/match | {tuition_id | student_id (ghi vào số dư)} | new |
| GET/POST/PATCH | /v3/school/voucher-groups, /vouchers; POST /vouchers/validate | {code, student_id, course_id, amount} → giá trị giảm hoặc lỗi | new |
| POST | /v3/school/tuitions/{id}/einvoice | {buyer: {name, tax_id?, address, email}} → kết quả từ nhà cung cấp | new |
| GET | /v3/school/finance/report | school_id, from, to, group_by → billed, collected, outstanding, overdue, refunds, expenses, deferred; series | new |
| GET/POST/PUT/DELETE | /v3/teacher/school-finance/bank-accounts[...], /company, /link-token | không thay đổi | existing |
| POST | /v3/payment/qr | không thay đổi | existing |
| GET | /v3/parent/tuitions, /{id}, /overview | giao diện phụ huynh; bổ sung phiếu thu và số dư gói buổi | extend |
9Phân quyền
| Mã quyền | owner | branch_manager | accountant | academic_admin | admissions | teacher | parent |
|---|---|---|---|---|---|---|---|
finance.view | tất cả | chi nhánh | chi nhánh | chi nhánh (số dư) | hoá đơn của các lead mình phụ trách | không | con của mình |
finance.invoice.create | có | có | có | có | qua chuyển đổi | không | không |
finance.invoice.void | có | có | có | không | không | không | không |
finance.payment.create | có | có | có | tiền mặt nếu được cấp quyền | không | không | không |
finance.payment.void | có | có | có | không | không | không | không |
finance.discount.approve | có | có | không | không | không | không | không |
finance.refund | có | phê duyệt | tạo | không | không | không | không |
finance.expense | có | phê duyệt | tạo | không | không | không | không |
finance.cashbook, finance.close | có | chỉ xem | có | không | không | không | không |
finance.reminders | có | có | có | có | không | không | không |
finance.vouchers, finance.settings, finance.einvoice | có | không | cấu hình, hoá đơn điện tử | không | không | không | không |
finance.report, finance.export | có | chi nhánh | có | không | không | không | không |
10Sự kiện phân tích
| Sự kiện | Thuộc tính |
|---|---|
| invoice_created | fee_plan_type, lines, discount_pct_bucket, voucher, approval_required, via (wizard|form|bulk) |
| billing_run_created | classes, invoices, prorated_count |
| payment_recorded | method, partial, auto_matched, receipt_sent |
| transfer_unmatched / transfer_matched | age_hours |
| reminder_sent | channel, bucket, bulk |
| package_low / package_exhausted | |
| credit_note_created / refund_paid | amount_bucket, approval |
| expense_created / cash_closed | category, difference_nonzero |
| einvoice_issued / einvoice_failed | provider |
| finance_report_viewed | period, group_by |
11Trường hợp biên
- Giảm giá anh chị em: được triển khai dưới dạng lý do giảm giá trên hoá đơn "Anh chị em"; phần trăm giảm tự động cho anh chị em là cấu hình tenant được áp dụng trong wizard.
- Chuyển khoản đến trước khi hoá đơn được tạo (phụ huynh thanh toán trước): giao dịch chưa đối soát trở thành số dư của học viên; hoá đơn tiếp theo có tuỳ chọn "Dùng số dư".
- Hai khoản thanh toán cho cùng một hoá đơn trong vòng vài giây (do SePay webhook gửi lại): loại trùng dựa trên sepay_transaction_id.
- Phụ huynh chuyển một lần cho hai con: luồng xử lý giao dịch chưa đối soát cho phép chia khoản tiền vào nhiều hoá đơn.
- Gói buổi mua tại chi nhánh A, sử dụng tại chi nhánh B sau khi học viên chuyển chi nhánh: gói buổi đi theo học viên; doanh thu vẫn ghi nhận tại chi nhánh A; báo cáo hiển thị ghi chú liên chi nhánh.
- Học phí được miễn VAT tại Việt Nam đối với dịch vụ giáo dục; VAT áp dụng cho tài liệu. VAT mặc định theo loại gói học phí: học phí 0%, tài liệu 5% (có thể cấu hình).
- Đơn vị tiền tệ: chỉ dùng VND ở v1; trường currency hiện có của Course phải là VND.
- Hoá đơn trả góp đã thanh toán một phần rồi học viên nghỉ học: lập phiếu giảm cho các phần trả góp còn lại, chỉ hoàn tiền phần đã thanh toán.
12Câu hỏi còn mở
- Chọn nhà cung cấp hoá đơn điện tử nào trước (MISA meInvoice, Viettel SInvoice, VNPT)? Thiết kế adapter giả định dùng REST kèm token; quyết định sau khi phỏng vấn thử với kế toán.
- Số buổi của gói có nên được cộng ngay khi tạo hoá đơn theo mặc định không (nhiều trung tâm cho học viên học trước khi đóng tiền)?
- Có cần một đối tượng "đặt cọc" trước khi nhập học không, hay thanh toán một phần trên hoá đơn là đủ?
Trường Số (truongso.net) · Nội bộ FLYER