PRD: Mẫu biên lai
| Module | Commerce (CORE-03) | PRD ID | PRD-RCP-001 |
| Status | Shipped | Owner | Commerce squad |
| Date | 2026-06-15 | Version | v1.0 |
| Packages | @nx/commerce · @nx/core · apps/sale-renderer | URD | RCP |
TL;DR
Cho phép merchant thiết kế chính xác biên lai in của mình trông ra sao - theo từng merchant hoặc từng kênh bán, và theo từng ngôn ngữ. Một mẫu là một bố cục có tên, có thứ tự dựng từ bộ khối cố định (text, line, image, bảng dòng hàng, barcode, QR, và grid cho các hàng cạnh nhau), mỗi khối gắn với dữ liệu đơn hàng trực tiếp và mang style riêng. Bố cục được kiểm tra khi lưu dựa trên bộ khối, nên một biên lai sai định dạng không bao giờ tới được máy in. Đúng một mẫu là mặc định cho mỗi ngôn ngữ theo từng merchant hoặc kênh - đặt mặc định mới sẽ tự gỡ mặc định cũ - và khi in, mẫu được chọn render thành ảnh raster đơn sắc vừa khổ giấy in nhiệt 58mm hoặc 80mm.
1. Context & Problem
Mỗi lượt bán đều kết thúc bằng một biên lai in, nhưng không phải merchant nào cũng muốn cùng một mẫu. Quán cà phê muốn logo và mã QR cho chương trình loyalty; quầy bán lẻ muốn barcode và bảng dòng hàng gọn; địa điểm đa ngôn ngữ muốn biên lai tiếng Việt ở kênh này và tiếng Anh ở kênh khác. Cố định một bố cục biên lai duy nhất ép tất cả họ dùng chung một tờ.
Không có bề mặt mẫu, merchant không thể đổi phần đầu, sắp xếp lại các phần, thêm barcode hay in sang ngôn ngữ thứ hai mà không cần can thiệp kỹ thuật. Cũng không có nơi an toàn để lưu các bố cục này: một blob tự do sẽ để lọt một biên lai sai định dạng - một cột không có field, một grid không bao giờ kết thúc - và làm kẹt máy in đúng lúc tệ nhất, giữa lúc thanh toán.
Increment này trao cho Commerce một thực thể mẫu biên lai hạng nhất: có tên, theo phạm vi merchant hoặc kênh bán, theo ngôn ngữ, dựng từ bộ khối cố định và được kiểm tra, với một mặc định cho mỗi ngôn ngữ, và render đúng ảnh raster mà máy in nhiệt mong đợi.
2. Goals & Non-Goals
Goals
- Một mẫu biên lai có tên theo phạm vi merchant hoặc kênh bán, trong ngôn ngữ đã chọn.
- Bố cục dựng từ một bộ khối cố định - text, line, image, bảng dòng hàng, barcode, QR, và grid cho các hàng cạnh nhau.
- Kiểm tra bố cục ở mỗi lần lưu - một mẫu không hợp lệ với bộ khối bị từ chối trước khi lưu.
- Một mặc định cho mỗi (principal, locale) - đặt mặc định sẽ tự gỡ mặc định trước đó cho phạm vi và ngôn ngữ đó.
- Các khối gắn với dữ liệu đơn hàng trực tiếp (field, dòng hàng) được phân giải khi in, với định dạng số / tiền tệ / ngày theo từng field.
- Render mẫu thành ảnh raster đơn sắc vừa khổ giấy in nhiệt 58mm hoặc 80mm.
- Vòng đời đầy đủ - tạo, sửa, liệt kê/lọc, trạng thái (Activated / Deactivated / Archived), soft-delete - theo phạm vi merchant.
Non-Goals
- Một trình soạn thảo WYSIWYG kéo-thả - trình dựng mẫu là một bề mặt client; PRD này đặc tả hợp đồng mẫu và việc render, không phải canvas soạn thảo.
- Bố cục và phát hành hóa đơn điện tử / hóa đơn thuế pháp lý - hóa đơn tài khóa do Tax & Invoice chi phối, không phải các mẫu in này.
- Lựa chọn truyền tải / driver máy in (USB, Bluetooth, mạng) - mẫu tạo ra ảnh raster; đưa nó tới thiết bị là việc của renderer.
- Biên lai email / PDF - increment này nhắm in nhiệt.
- Chia sẻ mẫu giữa các merchant hay một chợ mẫu toàn cục.
3. Success Metrics
| Chỉ số | Mục tiêu / tín hiệu |
|---|---|
| An toàn bố cục | Một bố cục sai định dạng (thiếu field, sai loại khối) bị từ chối khi lưu - không mẫu sai nào tới máy in |
| Toàn vẹn mặc định | Mỗi (merchant-hoặc-kênh, locale) có tối đa một mẫu mặc định tại mọi thời điểm |
| Bao phủ phạm vi | Một mẫu gắn được với merchant hoặc một kênh bán cụ thể, trong ngôn ngữ đã chọn |
| Độ trung thực render | Một mẫu render thành raster đúng bề rộng theo khổ giấy (58mm hoặc 80mm) |
| Gắn dữ liệu | Field đơn hàng và dòng hàng xuất hiện trên tờ in qua binding field và định dạng đã khai báo |
4. Personas & Use Cases
| Persona | Mục tiêu trong tính năng này |
|---|---|
| Chủ / Quản lý | Thiết kế biên lai - thương hiệu, các phần, barcode/QR - và đặt mặc định theo từng ngôn ngữ |
| Người vận hành kênh | Cho một kênh bán cụ thể bố cục biên lai riêng |
| Thu ngân | In một biên lai đúng, dễ đọc khi thanh toán mà không cần cấu hình gì |
Kịch bản lõi: chủ thiết kế một biên lai 80mm cho merchant - một ảnh logo, tên cửa hàng căn giữa, một đường phân tách nét đứt, một bảng dòng hàng (tên · sl · giá), một grid tổng tiền, và một mã QR gắn với mã đơn hàng. Họ đặt nó làm mặc định cho tiếng Việt. Bố cục được kiểm tra và lưu lại. Khi thanh toán, thu ngân hoàn tất; hệ thống chọn mẫu tiếng Việt mặc định của merchant, gắn field và dòng hàng của đơn vào, và render một ảnh raster đơn sắc rộng 576px để máy in nhiệt in ra. Sau đó chủ thêm một mẫu tiếng Anh cho kênh take-away và đặt nó mặc định cho tiếng Anh - mặc định tiếng Anh trước đó của kênh đó tự được gỡ.
5. User Stories
- Là chủ, tôi thiết kế biên lai từ một bộ khối cố định (text, image, đường phân tách, bảng hàng, barcode, QR), để tờ in phản ánh thương hiệu mà không cần can thiệp kỹ thuật.
- Là chủ, tôi đặt một biên lai mặc định cho mỗi ngôn ngữ, để thanh toán luôn chọn được một bố cục hợp lý.
- Là người vận hành kênh, tôi cho một kênh bán bố cục biên lai riêng, để tờ giao hàng khác tờ dine-in.
- Là chủ, tôi gắn bảng hàng và tổng tiền với dữ liệu đơn trực tiếp, để mỗi biên lai in đúng đơn thật.
- Là chủ, tôi muốn một bố cục hỏng bị từ chối khi lưu, để không phát hiện sự cố tại máy in giữa lúc bán.
- Là thu ngân, tôi in một biên lai đúng mà không cần thiết lập, để thanh toán chỉ một chạm.
6. Functional Requirements
| # | Yêu cầu | URD ref |
|---|---|---|
| FR-1 | Một mẫu biên lai có tên gắn phạm vi merchant hoặc kênh bán, trong một locale đã chọn | URD-RCP-001 · URD-RCP-004 |
| FR-2 | Mỗi mẫu khai báo khổ giấy (58mm hoặc 80mm) và một cỡ chữ nền | URD-RCP-002 |
| FR-3 | Tên mẫu duy nhất theo (principal, locale) - cùng tên dùng lại được giữa các ngôn ngữ và nhận biết soft-delete | URD-RCP-003 |
| FR-4 | Bố cục là một danh sách khối có thứ tự từ bộ cố định: text, line, image, bảng dòng hàng, barcode, QR, grid | URD-RCP-006 |
| FR-5 | Bố cục được kiểm tra theo bộ khối khi tạo và cập nhật; một bố cục không hợp lệ bị từ chối | URD-RCP-007 |
| FR-6 | Khối text, dòng hàng, barcode, QR gắn với field đơn hàng động phân giải khi in | URD-RCP-008 |
| FR-7 | Bảng dòng hàng render các cột cấu hình được (field · header · width · align · format) với hàng tiêu đề tùy chọn | URD-RCP-009 |
| FR-8 | Một khối grid đặt các con vào cột tỉ lệ với canh / phân bố cho các hàng cạnh nhau (tối đa 5) | URD-RCP-010 |
| FR-9 | Các khối mang style trình bày - canh, độ đậm, biến đổi chữ, gạch, viền, màu, padding | URD-RCP-011 |
| FR-10 | Giá trị số, tiền tệ, ngày định dạng theo format đã khai báo trên khối hoặc cột | URD-RCP-012 |
| FR-11 | Đúng một mẫu mặc định cho mỗi (principal, locale); đặt mặc định gỡ mặc định trước đó một cách atomic | URD-RCP-005 |
| FR-12 | Một mẫu render thành ảnh raster đơn sắc vừa khổ giấy (58mm → 384px, 80mm → 576px) | URD-RCP-013 |
| FR-13 | Mẫu mang trạng thái vòng đời (Activated / Deactivated / Archived) và được soft-delete | URD-RCP-014 |
| FR-14 | Mọi thao tác theo phạm vi merchant (x-merchant-id) và được kiểm soát bởi quyền mẫu biên lai; mẫu liệt kê/lọc được theo principal, locale, trạng thái, cờ mặc định | URD-RCP-015 · URD-RCP-016 |
Nội dung yêu cầu đầy đủ và tiêu chí chấp nhận nằm tại Commerce URD - RCP. PRD này dẫn chiếu thay vì lặp lại.
7. Non-Functional Requirements
| Lĩnh vực | Yêu cầu |
|---|---|
| Toàn vẹn bố cục | Bố cục được parse nghiêm ngặt theo bộ khối cố định khi lưu; một bố cục không hợp lệ bị từ chối với lý do rõ ràng, không bao giờ lưu |
| Nhất quán mặc định | Đặt mặc định và gỡ mặc định trước đó cho cùng (principal, locale) diễn ra trong một transaction atomic |
| Tenancy & authz | Mọi thao tác theo phạm vi merchant (x-merchant-id); kiểm soát bởi quyền tạo / đọc / cập nhật / xóa mẫu biên lai dưới Commerce |
| Đa hình phạm vi | Một mẫu gắn merchant hoặc kênh bán qua một tham chiếu principal đa hình duy nhất |
| i18n | Mẫu theo từng locale; một merchant hoặc kênh giữ một bộ mẫu cho mỗi ngôn ngữ và một mặc định cho mỗi ngôn ngữ |
| Tính xác định khi render | Một mẫu + dữ liệu đơn cho ra một ảnh raster đơn sắc xác định đúng bề rộng theo khổ giấy |
| Soft-delete | Mẫu không bị xóa vật lý; tính duy nhất của tên và mặc định chỉ xét trên các hàng còn sống |
8. UX & Flows
Soạn thảo & phân giải mặc định
In khi thanh toán
Bề mặt soạn thảo (trong cài đặt máy in của apps/sale-renderer) cho phép chủ chọn phạm vi (merchant hoặc kênh) và ngôn ngữ, chọn khổ giấy, lắp các khối có thứ tự, gắn mỗi khối với field dữ liệu, xem trước tờ in render, và đánh dấu mẫu mặc định cho ngôn ngữ đó.
9. Data & Domain
| Thực thể | Vai trò |
|---|---|
ReceiptTemplate | Một bố cục có tên, theo locale, gắn phạm vi merchant hoặc kênh bán; mang khổ giấy, cỡ chữ nền, cờ mặc định, trạng thái, và bố cục khối |
| Bộ khối | Tập layout cố định - text, line, image, bảng dòng hàng, barcode, QR, và grid đệ quy - mỗi khối có style riêng và (nơi cần) binding dữ liệu |
| Tham chiếu principal | Liên kết đa hình duy nhất gắn một mẫu với merchant hoặc một kênh bán |
Chỉ ở mức khái niệm - bộ khối đầy đủ, binding field, và bất biến nằm trong commerce domain model. Bố cục khối được lưu dưới dạng tài liệu có cấu trúc và kiểm tra ở mỗi lần ghi.
10. Dependencies & Assumptions
Phụ thuộc vào
- Merchant & kênh bán (MER, SC) - principal của mẫu là một trong hai; phạm vi phải tồn tại trước.
- Permissions (Permissions) - tạo / đọc / cập nhật / xóa mẫu biên lai được kiểm soát dưới Commerce.
- Dữ liệu đơn / sale (Orders) - các khối gắn với field đơn và dòng hàng phân giải khi in.
@nx/core- thực thể mẫu, bộ khối, và tiện ích render.
Giả định
- Merchant hoặc kênh bán mà mẫu nhắm tới đã tồn tại.
- Renderer tại điểm bán in một ảnh raster đơn sắc ra máy in nhiệt 58mm hoặc 80mm.
- Merchant chọn một ngôn ngữ cho mỗi mẫu; một đơn mang đủ field và dòng hàng để điền vào các khối đã gắn.
11. Risks & Open Questions
| Rủi ro / câu hỏi | Giảm thiểu / trạng thái |
|---|---|
| Một bố cục sai làm kẹt máy in giữa lúc bán | Bố cục được kiểm tra nghiêm ngặt ở mỗi lần lưu theo bộ khối; một mẫu không hợp lệ bị từ chối trước khi lưu |
| Hai mặc định cho cùng phạm vi và ngôn ngữ | Đặt mặc định gỡ một cách atomic mặc định trước đó cho (principal, locale) đó |
| Sai bề rộng raster trên sai máy in | Mẫu khai báo khổ giấy; render định cỡ raster theo nó (58mm → 384px, 80mm → 576px) |
| Tên của một mẫu đã gỡ chặn việc dùng lại | Tính duy nhất của tên và mặc định nhận biết soft-delete - chỉ xét trên các hàng còn sống |
| Không đặc tả trình soạn thảo trực quan ở đây | Có chủ đích - trình dựng là một bề mặt client; PRD này cố định hợp đồng mẫu và render, không phải canvas |
12. Release Plan & Launch Criteria
| Khía cạnh | Kế hoạch |
|---|---|
| Phase | P2 - RCP trong URD feature catalog |
| Rollout | Mọi merchant; không feature flag |
| Migration | Không - thực thể mới; merchant chưa có mẫu sẽ dùng tờ mặc định dựng sẵn |
| Launch criteria | Mẫu tạo / sửa theo phạm vi merchant hoặc kênh theo từng ngôn ngữ; một bố cục sai bị từ chối khi lưu; đúng một mặc định cho mỗi (principal, locale); một mẫu render thành raster đúng bề rộng và in khi thanh toán với dữ liệu đơn đã gắn |
| Monitoring | Tỉ lệ từ chối khi lưu theo lý do (bố cục không hợp lệ), số lần xung đột mặc định, lỗi render theo merchant |
13. FAQ
Mỗi kênh bán có biên lai riêng được không? Có - một mẫu gắn phạm vi merchant hoặc một kênh bán cụ thể, nên kênh giao hàng in được tờ khác với dine-in.
Ngôn ngữ hoạt động ra sao? Mẫu theo từng locale. Một merchant hoặc kênh giữ một mẫu cho mỗi ngôn ngữ và một mặc định cho mỗi ngôn ngữ; thanh toán chọn mặc định theo ngôn ngữ của đơn.
Nếu bố cục của tôi bị hỏng thì sao? Nó bị từ chối khi bạn lưu - bố cục được kiểm tra theo bộ khối cố định, nên một cột thiếu field hay một loại khối lạ bị bắt trước khi có thể tới máy in.
Tôi có hai biên lai mặc định được không? Không cho cùng phạm vi và ngôn ngữ - đánh dấu một mẫu mặc định tự gỡ mặc định trước đó cho merchant-hoặc-kênh và locale đó.
Tôi đặt được gì lên biên lai? Text, đường phân tách (line), một ảnh (ví dụ logo), một bảng dòng hàng với cột cấu hình được, một barcode, một mã QR, và một grid cho các hàng cạnh nhau - mỗi thứ có canh, style, và binding dữ liệu riêng.
Cái này in hóa đơn thuế pháp lý chứ? Không - hóa đơn điện tử tài khóa do Tax & Invoice chi phối. Các mẫu này dành cho biên lai bán hàng in ra.
References
- URD: Commerce - RCP
- PRD liên quan: Organization & merchant · Sale channels · Categories
- Module: Commerce - tổng quan + capabilities
- Developer: @nx/commerce · @nx/core