Trên trang "Tài khoản của tôi", khách bấm vào một đơn hàng và thấy ô "Gửi tin nhắn" — họ hỏi một câu, và nhân viên thấy ngay câu đó trong chatter của đơn ở khu quản trị. Hai giao diện khác nhau (portal của khách, backend của nhân viên) nhưng cùng một luồng tin. Đằng sau nó là mail.thread và mail.message — hệ thống trao đổi/theo dõi gắn với mọi bản ghi trong Odoo. Bài này mổ xẻ: làm sao một model có chatter, message_post tạo ra gì, và portal cho khách gửi tin an toàn ra sao — bằng một tin thật đăng lên rồi xem nó hiện trong chatter Odoo 19.
mail.thread: thêm chatter cho model
Chatter không tự có. Một model chỉ có chatter khi kế thừa mail.thread — mixin thêm các trường message_ids (các tin), message_follower_ids (người theo dõi), và những phương thức như message_post.

Hình 1: _inherit = ['mail.thread'] cho model có chatter. message_post(body, message_type='comment', subtype_xmlid='mail.mt_comment') đăng một tin — tạo một mail.message gắn model + res_id của bản ghi. Phần dưới: template portal t-call="portal.message_thread" dựng khung chatter cho khách, và controller PortalChatter kiểm quyền trước khi cho khách gửi.
message_post: mỗi tin là một mail.message
Gọi message_post trên một thẻ thành viên, đây là bản ghi mail.message thật nó tạo ra:

Hình 2: message_post tạo mail.message id 4297 — model='quan.the.thanh.vien', res_id=47 (đúng thẻ VIP-0003), message_type='comment', subtype='Discussions', author_id là người gửi, body là nội dung. Đây là "viên gạch" của mọi chatter, dù hiện ở đâu.
Và tin đó hiện ngay trong chatter của bản ghi (ở đây là khu quản trị):

Hình 3: Chatter thật hiển thị tin vừa đăng — avatar + tên người gửi, thời gian, nội dung. Nút "Gửi tin" (comment, khách/đối tác thấy), "Ghi chú" (log note, chỉ nội bộ), "Hoạt động" (lịch việc). Cũng mail.message này, nếu bản ghi mở trên portal, khách sẽ thấy trong khung chatter của họ.
Portal chatter: cho khách gửi tin an toàn
Chatter backend là cho nhân viên. Để khách trao đổi ngay trên trang tài khoản của họ, portal dựng một khung chatter riêng bằng template portal.message_thread, truyền vào bản ghi (object) và token truy cập. Khi khách gõ và gửi, JS gọi controller PortalChatter (trong portal_thread.py, kế thừa ThreadController).
Điểm cốt lõi là bảo mật. Khách không đăng nhập đầy đủ như nhân viên; nếu để hở, người ta có thể đổi res_id để đọc/ghi chatter của bản ghi người khác. Vì vậy trước khi cho message_post, controller gọi _get_thread_with_access — kiểm chứng khách có quyền (qua access_token của portal.mixin ở phần 171, hoặc hash/pid). Chỉ khi hợp lệ, tin mới được đăng, và đăng dưới danh nghĩa đúng partner của khách. Đó là cách Odoo cho khách "chat" mà không mở lỗ hổng.
comment vs note: hai loại tin
Một chi tiết hay nhầm khi code chatter:
message_type='comment'+subtype='mail.mt_comment'— tin trao đổi, gửi cho follower (email thông báo), khách trên portal thấy được. Dùng cho đối thoại với khách.- Log note (
subtype='mail.mt_note') — ghi chú nội bộ, chỉ nhân viên thấy, khách không thấy trên portal. Dùng cho ghi chú riêng của team.
Đăng nhầm loại là hoặc làm phiền khách (gửi email ghi chú nội bộ), hoặc để lộ ghi chú nội bộ ra portal. Chọn message_type/subtype đúng theo đối tượng.
Ba ý mang về
- Kế thừa
mail.threadđể model có chatter (message_ids, follower,message_post); mỗi tin là mộtmail.messagegắnmodel+res_id— cùng dữ liệu hiện ở chatter backend lẫn portal. - Portal cho khách gửi tin qua template
portal.message_thread+ controllerPortalChatter; cốt lõi là_get_thread_with_accesskiểm quyền bằngaccess_token/hashtrước khi cho đăng — chống đọc/ghi chatter của người khác. - Phân biệt comment và note:
mt_commentlà tin trao đổi (khách thấy, gửi thông báo),mt_notelà ghi chú nội bộ (chỉ nhân viên) — chọn đúng để không làm phiền khách hay lộ nội bộ.
Hết mảng portal/website, phần sau bước sang một chủ đề lớn của front-end website: Phần sau mổ xẻ cấu trúc cơ bản của một website theme — module theme gồm gì, cách nó khai màu/font/bố cục, và cách Odoo áp theme lên toàn bộ trang.