Bài trước là server action — chạy logic ở máy chủ. Giờ sang phía ngược lại: client action (ir.actions.client) là một màn hình do JavaScript (OWL) tự vẽ ngay trên trình duyệt. Khi list/kanban/form đều không dựng nổi thứ bạn muốn — một dashboard số liệu, một màn hình quy trình riêng — client action là lối ra. Bài này viết một Component OWL thật, cắm vào Odoo, và nó lấy dữ liệu thật để hiển thị.

Component OWL + đăng ký vào registry

Một client action gồm hai mảnh: một Component OWL (JS) và một bản ghi ir.actions.client có tag trỏ tới Component đó. Component đăng ký vào registry.category("actions"):

Ảnh chụp đoạn mã nền tối gồm file dashboard.js khai module odoo, import Component useState onWillStart từ owl, registry và useService từ web core; class QuanDashboard kế thừa Component với static template quan_ca_phe.Dashboard, hàm setup dùng useService orm, useState với tong diem loading, onWillStart async gọi orm.searchRead lấy thẻ rồi tính tong và diem là dữ liệu thật; dòng cuối registry category actions add đăng ký component; phần client_action.xml khai record ir.actions.client với field tag quan_ca_phe.dashboard khớp key registry và một menuitem gắn action

Hình 1: dashboard.js định nghĩa QuanDashboard (OWL Component). Trong setup(), useService("orm") cho phép gọi ORM; onWillStart chạy trước khi vẽ để lấy dữ liệu thật (searchRead). Cuối file: registry.category("actions").add("quan_ca_phe.dashboard", QuanDashboard). Bản ghi ir.actions.client có tag khớp đúng key đó.

Ba điểm cốt lõi của Odoo 19 OWL:

  • registry.category("actions").add(tag, Component) — cách "công bố" Component để action tìm thấy nó qua tag.
  • useService("orm") + onWillStart — lấy dữ liệu từ máy chủ trước khi render, không cần view.
  • useState — state phản ứng: đổi state.tong là giao diện tự vẽ lại.

Màn hình tự vẽ chạy thật

Template QWeb-OWL (.xml) và file JS đều khai vào web.assets_backend. Mở action qua menu, đây là kết quả:

Ảnh chụp giao diện Odoo thật hiển thị một màn hình dashboard tự vẽ tiêu đề Bảng điều khiển Thẻ thành viên kèm biểu tượng ly cà phê, bên dưới là ba thẻ số liệu: số 4 màu nâu nhãn Tổng số thẻ, số 385 màu xanh lá nhãn Tổng điểm tích luỹ, số 1 màu vàng nhãn Thẻ hạng Vàng

Hình 2: Client action đang chạy — một màn hình không phải list/kanban/form nào cả, do OWL tự vẽ. Ba con số là thật, lấy từ ORM: 4 thẻ, tổng 385 điểm (150+150+85+0), 1 thẻ Vàng. Đổi dữ liệu dưới CSDL rồi mở lại là số tự cập nhật.

Cái hay: bạn có toàn quyền trên HTML/CSS/JS của màn hình này, mà vẫn ở trong Odoo — dùng chung ORM, service, session, điều hướng. Đây là cách các dashboard tuỳ biến, màn hình POS, trình xử lý đặc thù được xây.

Khi nào cần client action

  • Cần khi giao diện không map vào một model/record theo kiểu view: dashboard tổng hợp nhiều nguồn, một wizard nhiều bước phức tạp, một màn hình đồ hoạ riêng.
  • Không cần khi list/kanban/form/pivot đã đủ — đừng viết JS chỉ để hiện một danh sách; view chuẩn rẻ hơn và bền hơn.
  • Cân nhắc chi phí bảo trì: JS/OWL cần build asset, dễ vỡ khi nâng cấp hơn view khai bằng XML. Chỉ dùng khi thật sự cần.

Vài lưu ý

  • Lỗi JS chỉ hiện ở trình duyệt. Như bài kanban, -u có thể xanh nhưng Component vẫn nổ OwlError lúc render — kiểm bằng DevTools/console (hoặc Playwright bắt pageerror).
  • tag phải khớp tuyệt đối giữa registry...add(tag, ...) và <field name="tag"> — lệch một ký tự là action mở ra màn hình trống.
  • Import từ đúng module: @odoo/owl cho OWL, @web/core/... cho hạ tầng Odoo. Sai đường dẫn import là không build được.
  • Template QWeb-OWL khai trong assets dưới dạng file .xml; static template = "..." của Component phải trỏ đúng t-name.

Ba ý mang về

  1. Client action (ir.actions.client) là màn hình do OWL tự vẽ ở trình duyệt — dùng khi list/kanban/form không đủ; gồm một Component đăng ký vào registry.category("actions") và một action có tag khớp key.
  2. Component OWL lấy dữ liệu thật qua useService("orm") + onWillStart, dùng useState cho state phản ứng — toàn quyền HTML/CSS/JS mà vẫn trong Odoo.
  3. Cân nhắc trước khi dùng: chỉ khi giao diện không map vào view chuẩn; nhớ lỗi JS chỉ hiện ở trình duyệt và tag phải khớp tuyệt đối.

Action mở view, chạy code, vẽ màn hình JS. Còn một loại nữa đơn giản mà hữu ích: Phần sau về URL action — action chỉ mở một đường link (trang ngoài, tài liệu, báo cáo) trong tab mới, không cần view hay code.