PRD: Báo cáo doanh thu theo khoảng thời gian
| Phân hệ | Báo cáo (CORE-11) | Mã PRD | PRD-SLS-002 |
| Trạng thái | Đề xuất | Đội ngũ phụ trách | Nhóm phát triển Báo cáo |
| Ngày lập | 2026-06-05 | Phiên bản | v0.1 |
| Gói mã nguồn | @nx/sale · apps/client · apps/bo | Tham chiếu URD | SLS · ACC |
TL;DR
Cung cấp khả năng tổng hợp và nhóm dữ liệu doanh thu linh hoạt theo các chu kỳ Ngày, Tháng, Năm trên bất kỳ khoảng thời gian nào được chọn, hỗ trợ biểu đồ xu hướng trực quan và đối chiếu số liệu chi tiết.
1. Bối cảnh & Vấn đề
Trong quá trình vận hành, chủ cửa hàng và quản lý không chỉ cần theo dõi doanh thu hằng ngày mà còn cần phân tích kết quả kinh doanh theo các giai đoạn dài hơn như tháng, quý hoặc năm để phục vụ việc đánh giá hiệu suất và lập kế hoạch kinh doanh.
Hiện tại, hệ thống chỉ hỗ trợ xem doanh thu theo từng ngày trong khoảng thời gian được chọn. Khi người dùng xem dữ liệu trong các khoảng thời gian dài (ví dụ 6 tháng, 1 năm hoặc nhiều năm), số lượng bản ghi tăng lên đáng kể, khiến bảng dữ liệu khó theo dõi và biểu đồ trở nên dày đặc, làm giảm khả năng nhận diện xu hướng doanh thu tổng quan.
Do đó, hệ thống cần hỗ trợ khả năng tổng hợp và trình bày dữ liệu doanh thu theo nhiều cấp độ thời gian khác nhau nhằm giúp người dùng phân tích hiệu quả kinh doanh ở cả góc độ chi tiết và tổng quan.
2. Mục tiêu & Không phải mục tiêu
Mục tiêu
- Bộ lọc khoảng thời gian linh hoạt: Hỗ trợ chọn nhanh các khoảng thời gian thông dụng (Hôm nay, Hôm qua, Tuần này, Tháng này, Tháng trước, Quý này, Năm nay, Năm trước) hoặc chọn khoảng ngày tùy chỉnh.
- Lựa chọn nhóm theo chu kỳ (Group By): Cho phép người dùng chuyển đổi linh hoạt cách tổng hợp dữ liệu theo Ngày (Day), Tháng (Month), hoặc Năm (Year).
- Biểu đồ trực quan hóa: Hiển thị biểu đồ cột hoặc biểu đồ đường thể hiện xu hướng doanh thu thuần và số lượng đơn hàng tương ứng với kiểu nhóm đã chọn.
- Bảng dữ liệu chi tiết: Bảng thống kê chi tiết tương ứng với các hàng dữ liệu đại diện cho từng chu kỳ gồm: Khoảng thời gian, Doanh thu gộp, Giảm giá/Chiết khấu, Thuế, Doanh thu thuần, Số lượng đơn hàng và dòng Tổng cộng cố định ở cuối bảng.
- Ràng buộc bảo mật & tính chính xác: Chỉ tổng hợp trên các đơn hàng đã hoàn tất (
status = 'completed'), giới hạn nghiêm ngặt theo merchant của người dùng đăng nhập (x-merchant-id), và xử lý múi giờ chính xác (mặc định GMT+7).
Không phải mục tiêu
- Phân tích chi tiết chi phí và biên lợi nhuận (thuộc về phân tích nâng cao
ADV). - Xuất file báo cáo sang định dạng Excel/PDF (thuộc về phân tích nâng cao
ADV).
3. Chỉ số thành công
| Chỉ số | Mục tiêu / Tín hiệu |
|---|---|
| Độ chính xác dữ liệu | 100% số liệu doanh thu khi nhóm theo Tháng hay Năm khớp hoàn toàn với tổng cộng cộng dồn của báo cáo ngày trong cùng khoảng thời gian |
| Thời gian phản hồi | API gộp dữ liệu chạy dưới 500ms đối với khoảng thời gian lên tới 2 năm dữ liệu đơn hàng |
| Trải nghiệm UI | Biểu đồ Recharts tự điều chỉnh giãn cách nhãn (interval spacing) và định dạng nhãn trục X tương ứng với kiểu nhóm được chọn để không bị chồng lấn chữ |
4. Đối tượng sử dụng & Kịch bản
| Đối tượng | Mục tiêu trong tính năng này |
|---|---|
| Chủ cửa hàng (Owner) | Xem doanh thu năm hiện tại nhóm theo Tháng để phân tích mùa cao điểm/thấp điểm và so sánh hiệu suất giữa các tháng |
| Quản lý (Manager) | Xem doanh thu của quý hiện tại nhóm theo Ngày/Tháng để đối chiếu số liệu và làm báo cáo định kỳ |
Kịch bản cốt lõi: Người dùng truy cập Dashboard Báo cáo -> Chọn khoảng thời gian lọc (ví dụ: 12 tháng qua) -> Click nút chọn nhóm theo Tháng -> Hệ thống gửi request API gộp -> Giao diện tải biểu đồ biểu diễn doanh số của 12 tháng và bảng dữ liệu chi tiết hiển thị 12 dòng tương ứng kèm dòng tổng cộng ở cuối.
5. Câu chuyện người dùng
- Là chủ cửa hàng, tôi muốn xem tổng hợp doanh thu theo từng tháng trong năm, để tôi nắm bắt được mùa cao điểm và thấp điểm của doanh nghiệp.
- Là quản lý, tôi muốn tùy chọn nhóm báo cáo theo ngày, tháng hoặc năm tùy theo khoảng thời gian tôi đang xem, để giao diện không bị tràn ngập dữ liệu chi tiết không cần thiết.
- Là nhà phát triển, tôi muốn backend thực hiện tính toán gộp (aggregation) trực tiếp dưới database và chỉ trả về dữ liệu gộp theo chu kỳ, để giảm tải băng thông mạng và tối ưu tốc độ tải trang.
6. Yêu cầu chức năng
| # | Yêu cầu | Tham chiếu URD |
|---|---|---|
| FR-1 | Bộ lọc khoảng thời gian trên UI hỗ trợ các khoảng chọn nhanh (Quick Presets) và khoảng tùy chỉnh (Custom Range) | URD-ACC-002 |
| FR-2 | Người dùng có thể tùy chọn kiểu gom nhóm dữ liệu (day, month, year) trên UI | URD-SLS-006 |
| FR-3 | API GET /v1/api/sale/reports/revenue-period hỗ trợ tham số query startDate, endDate, và groupBy | URD-SLS-006 |
| FR-4 | Dữ liệu phản hồi API trả về tổng gộp toàn bộ khoảng thời gian lọc và danh sách các chu kỳ con tương ứng với groupBy | URD-SLS-006 |
| FR-5 | Dữ liệu chỉ bao gồm đơn hàng hoàn tất (completed) của chính merchant đó | URD-ACC-001, URD-ACC-003 |
| FR-6 | Giao diện cập nhật biểu đồ cột/đường và bảng thống kê chi tiết theo chu kỳ được chọn | URD-SLS-006 |
| FR-7 | Dữ liệu trống hiển thị tổng bằng 0 thay vì trả về lỗi | URD-ACC-004 |
Quy tắc nghiệp vụ
- BR-01: Doanh thu được ghi nhận theo thời điểm
completedAt. - BR-02: Chỉ tính các đơn hàng có trạng thái
completed. - BR-03: Các chu kỳ không có dữ liệu vẫn phải hiển thị với giá trị 0.
- BR-04: Dữ liệu được sắp xếp tăng dần theo thời gian.
7. Yêu cầu phi chức năng
| Phân vùng | Yêu cầu |
|---|---|
| Đa chủ thể & Bảo mật (Tenancy & Security) | Phân quyền truy cập nghiêm ngặt theo Merchant ID, không bao giờ được phép rò rỉ dữ liệu chéo giữa các merchant |
| Hiệu năng (Performance) | Truy vấn cơ sở dữ liệu sử dụng index trên cột merchant_id, status và completed_at (hoặc created_at) để tránh quét toàn bảng (table scan) |
| Đa ngôn ngữ (i18n) | Nhãn hiển thị chu kỳ thời gian tự động dịch theo ngôn ngữ/locale hoạt động của người dùng (ví dụ: "Tháng 01/2026" vs "January 2026") |
| Múi giờ (Timezone) | Xử lý múi giờ GMT+7 thống nhất tại server để phân tách chu kỳ chính xác |
8. Trực quan giao diện & Luồng xử lý
9. Mô hình dữ liệu & Miền nghiệp vụ
| Thành phần | Vai trò |
|---|---|
SaleOrder | Thực thể đơn hàng bán được dùng để gộp dữ liệu doanh thu (grossAmount, discountAmount, taxAmount, netAmount, orderCount) dựa theo thời gian hoàn tất (completedAt) |
10. Phụ thuộc & Giả định
Phụ thuộc
- Đơn hàng (CORE-07) - Đơn hàng hoàn tất là nguồn dữ liệu duy nhất cho báo cáo doanh thu.
- Identity & Authz (CORE-02) - Trích xuất Merchant ID hợp lệ của người dùng từ ngữ cảnh yêu cầu (Request Context).
Giả định
- Mặc định toàn bộ hệ thống sử dụng múi giờ Việt Nam (GMT+7) để nhóm chu kỳ.
11. Rủi ro & Câu hỏi mở
| Rủi ro / Câu hỏi mở | Giải pháp / Trạng thái |
|---|---|
| Hiệu năng khi query tập dữ liệu đơn hàng cực lớn | Cần đảm bảo database có index thích hợp trên merchant_id + status + completed_at để tránh quét toàn bảng (table scan) |
| Trùng lặp/chồng chéo nhãn biểu đồ Recharts | Giao diện tự động tính toán thưa khoảng cách nhãn hiển thị (interval spacing) trên trục X tùy theo độ dài tập kết quả |
12. Kế hoạch phát hành & Tiêu chuẩn nghiệm thu
| Khía cạnh | Kế hoạch |
|---|---|
| Giai đoạn (Phase) | SLS P2 increment - báo cáo doanh thu chu kỳ |
| Phạm vi triển khai (Rollout) | Tất cả merchant |
| Chuyển đổi dữ liệu (Migration) | Không yêu cầu thay đổi cấu trúc bảng (chỉ sử dụng truy vấn gộp trên bảng hiện tại) |
| Tiêu chí nghiệm thu (Launch criteria) | API viết bằng Drizzle ORM chạy đúng các kiểu groupBy; giao diện hiển thị đúng dữ liệu trên Recharts và Data Table; zero lint errors trên cả backend và frontend |
13. Câu hỏi thường gặp
Báo cáo này có tính đơn hàng nháp hoặc đơn hủy không? Không, chỉ các đơn hàng có trạng thái completed mới được tính vào báo cáo doanh thu.
Nếu không có đơn hàng nào trong khoảng thời gian chọn thì sao? Hệ thống sẽ hiển thị các chỉ số tổng bằng 0 và vẽ biểu đồ trống, không báo lỗi.
Tài liệu tham khảo
- URD: Báo cáo - Báo cáo doanh số · Truy cập & Phạm vi
- Module: Báo cáo - tổng quan + truy vết
- Developer: @nx/sale