Suốt các bài trước, ta tạo mới model, view. Nhưng thường bạn không muốn viết lại từ đầu — bạn muốn thêm một chút vào thứ Odoo đã có sẵn: thêm một trường vào màn hình Khách hàng, thêm một nút vào đơn bán. Nếu sửa thẳng mã gốc của Odoo, lần cập nhật sau là mất hết. Giải pháp là kế thừa (inherit) — mở rộng từ module riêng của bạn, mã gốc nguyên vẹn. Đây là kỹ thuật khiến Odoo cực kỳ dễ mở rộng.

Ta làm ví dụ: thêm ô "Số thẻ thành viên" vào màn hình Liên hệ (res.partner) — một model lõi của Odoo.

Hai kiểu inherit: model và view

Mã nguồn kế thừa: phần 1 models/res_partner.py với class ResPartner có _inherit bằng res.partner, thêm trường tính so_the_thanh_vien và hàm _compute_so_the đếm số thẻ; phần 2 views/res_partner_views.xml với record ir.ui.view inherit_id trỏ base.view_partner_form, dùng xpath notebook position inside thêm page Thẻ thành viên chứa field so_the_thanh_vien

Hình 1: Hai mảnh kế thừa. (1) Model inherit — dùng _inherit = 'res.partner' (thay vì _name): class này không tạo model mới, mà thêm vào model res.partner sẵn có một trường so_the_thanh_vien (trường tính — đếm số thẻ của khách). (2) View inherit — bản ghi ir.ui.view có inherit_id trỏ tới form gốc base.view_partner_form, rồi dùng xpath để chèn một trang mới vào <notebook>. Cùng cơ chế sửa view ở bài 185, nhưng viết trong module.

Điểm cốt lõi:

  • _inherit (không có _name): "mở rộng model này". _name là tạo mới; _inherit là bồi thêm.
  • inherit_id + xpath: "chèn/sửa vào view gốc tại vị trí này" — không chép lại toàn bộ view.

Cài vào Odoo — trường mới nằm ngay trong màn hình gốc

Cập nhật module, mở một khách hàng có thẻ, sang tab mới:

Form Liên hệ Nguyễn Văn An trong Odoo với một tab mới Thẻ thành viên do module thêm vào, bên trong hiển thị Số thẻ thành viên bằng 1

Hình 2: Màn hình Liên hệ gốc của Odoo (Nguyễn Văn An) — giờ có thêm tab "Thẻ thành viên" với ô "Số thẻ thành viên: 1", do module quan_ca_phe thêm vào bằng inherit. Trường tính đúng: khách này có 1 thẻ (VIP-0001). Toàn bộ phần còn lại của form (tên, email, các tab Bán hàng, Hóa đơn...) nguyên vẹn của Odoo — ta chỉ bồi thêm, không đụng mã gốc.

Vì sao inherit quan trọng đến vậy?

  • Cập nhật an toàn: nâng cấp Odoo, mã gốc thay đổi, module của bạn vẫn "phủ" lên như cũ — không mất tùy biến.
  • Tách bạch: tùy biến của bạn nằm gọn trong module riêng, gỡ ra là sạch.
  • Đây là cách cả hệ sinh thái Odoo hoạt động: app Bán hàng thêm trường vào res.partner, app Kho thêm nút vào sản phẩm... tất cả bằng inherit. Studio và sửa view ở bài 185 cũng tạo ra chính các view inherit này.

Lưu ý khi kế thừa

  • _inherit không có _name = mở rộng tại chỗ. Nếu khai cả hai (_name khác + _inherit) là kiểu "sao chép sang model mới" — ít dùng, đừng nhầm.
  • View inherit cần inherit_id trỏ đúng view gốc và xpath khớp một phần tử có thật; sai xpath là bị bỏ qua (như bài 185 đã cảnh báo).
  • Trường tính (compute) không lưu cột nếu không store=True — tính lại mỗi lần đọc; cần lọc/sắp theo nó thì thêm store=True.
  • Cẩn thận hiệu năng với compute chạy search_count trên danh sách dài.

Nhớ ba ý

  1. Kế thừa (inherit) mở rộng model (_inherit, không _name) và view (inherit_id + xpath) của app khác — từ module riêng, không sửa mã gốc.
  2. Nhờ vậy nâng cấp Odoo không mất tùy biến, và tùy biến gỡ ra được sạch — đây là cách cả hệ sinh thái Odoo mở rộng lẫn nhau.
  3. _inherit = bồi thêm tại chỗ; view inherit cần xpath khớp phần tử thật; trường compute cần store=True nếu muốn lọc/sắp theo.

Đã đủ mọi mảnh để viết một module hoàn chỉnh. Phần cuối cùng của loạt khép lại: đóng gói, cài đặt và nâng cấp module tự viết — đưa nó lên hệ thống thật và bảo trì về sau.