Bài trước ta gắn một report action vào model. Giờ đi vào chính nội dung — cách viết cái template QWeb vẽ ra trang in. QWeb là ngôn ngữ template của Odoo: HTML thường, cộng vài thuộc tính bắt đầu bằng t-. Chỉ cần nắm năm directive — t-field, t-esc, t-if/t-else, t-foreach, t-set — là bạn dựng được một trang in có bảng, vòng lặp, và cả dòng tổng cộng tự tính. Bài này thêm một bảng lịch sử điểm vào report thẻ thành viên.

Năm directive cốt lõi

Ảnh chụp đoạn mã nền tối minh hoạ các directive QWeb: t-field trên span ngay_cap ra định dạng ngày, t-esc trên biểu thức Python name.upper in thô; t-if o.lich_su_ids vẽ bảng còn t-else báo chưa có lịch sử; khối t-foreach lặp o.lich_su_ids với t-as ls, mỗi dòng td t-field ngày điểm ghi chú, t-set tong t-value cộng dồn tong cộng diem_cong, cuối cùng dòng Tổng cộng t-esc tong; kèm chú thích t-foreach lặp recordset có biến ls và ls_index, t-set đặt và cộng biến, class table Bootstrap có sẵn, t-field tự format t-esc cho biểu thức tính

Hình 1: Năm directive. t-field in một field và tự format theo kiểu (ngày → dd/mm/yyyy). t-esc in một biểu thức Python thô. t-if/t-else rẽ nhánh. t-foreach/t-as lặp một recordset (có sẵn biến ls và chỉ số ls_index). t-set/t-value đặt/cộng một biến ngay trong template — dùng để cộng dồn tổng.

Vài điểm đáng nhớ:

  • t-field vs t-esc: t-field cần một field thật để biết cách format (ngày, tiền, selection ra nhãn); t-esc in bất kỳ biểu thức nào nhưng không format — hợp cho số tính toán, chuỗi ghép.
  • t-set cộng dồn: đặt tong=0 trước vòng lặp, mỗi vòng t-set tong t-value="tong + ...". Sau vòng lặp, tong là tổng — in bằng t-esc.
  • Class Bootstrap có sẵn: table, table-sm, table-bordered, text-end... dùng thẳng để bảng đẹp mà không cần CSS riêng.

Kết quả: bảng lịch sử có tổng

Thêm khối trên vào template, render report cho thẻ VIP-0001 (có 3 dòng lịch sử):

Ảnh chụp report Odoo thật đã render: khung công ty Cà Phê Việt ở đầu, tiêu đề Thẻ thành viên VIP-0001, bảng thông tin Khách hàng Nguyễn Văn An Hạng thẻ Bạc Điểm 150 Trạng thái Đang dùng Ngày cấp; tiếp theo là mục Lịch sử tích điểm với bảng có viền ba dòng 16 tháng 9 Giới thiệu bạn 40, Mua 5 ly cà phê 50, Đổi combo Tết 30, và dòng Tổng cộng in đậm 120; cuối là dòng cảm ơn và chân trang

Hình 2: Report render đầy đủ. Mục "Lịch sử tích điểm" là bảng do t-foreach vẽ: mỗi dòng lịch sử một hàng (t-field cho ngày/điểm/ghi chú). Dòng cuối "Tổng cộng 120" là biến tong cộng dồn qua vòng lặp (40+50+30) rồi t-esc. Nếu thẻ chưa có lịch sử, t-else sẽ hiện "Chưa có lịch sử tích điểm" thay vì bảng rỗng.

Đây là sức mạnh của QWeb: cùng một template chạy cho mọi thẻ, tự lặp đúng số dòng lịch sử của từng thẻ, tự tính tổng — không cần biết trước có bao nhiêu dòng.

Mẹo viết và soi template

  • Xem bản HTML để chỉnh nhanh: mở /report/html/<report_name>/<id> (ví dụ /report/html/quan_ca_phe.report_the_document/1) thấy ngay kết quả, không cần dựng PDF. Lỗi template hiện rõ ở HTML.
  • t-if cho tập rỗng: luôn nghĩ tới trường hợp không có dòng con — t-else báo "chưa có" đẹp hơn một bảng trống.
  • Đừng nhồi logic nặng vào template: tính toán phức tạp nên làm ở model (compute field) rồi chỉ t-field ra; QWeb hợp cho lặp/rẽ nhánh trình bày, không phải nơi viết nghiệp vụ.
  • ls_index (và ls_first, ls_last): t-foreach cấp sẵn chỉ số và cờ đầu/cuối, hữu ích để đánh số dòng hay tô màu xen kẽ.

Ba ý mang về

  1. Năm directive QWeb dựng nên trang in: t-field (in + tự format), t-esc (in biểu thức thô), t-if/t-else (rẽ nhánh), t-foreach/t-as (lặp recordset), t-set/t-value (đặt/cộng biến).
  2. t-foreach + t-set cho bảng có tổng: lặp dòng con, cộng dồn một biến qua các vòng, in tổng bằng t-esc sau vòng lặp; dùng class Bootstrap (table) cho bảng đẹp sẵn.
  3. Soi bằng /report/html/..., xử lý tập rỗng bằng t-else, giữ logic nặng ở model — template QWeb là nơi trình bày, không phải nơi viết nghiệp vụ.

Nội dung report đã đẹp. Nhưng nó đang in trên khổ A4 mặc định — nếu muốn khổ khác, lề khác thì sao? Phần sau về paperformat — khai khổ giấy, hướng dọc/ngang, lề, và gán cho report để bản in ra đúng kích thước mong muốn.