Nâng cấp addon lên Odoo 20 - tổng hợp thay đổi kỹ thuật
Tut 23: Nâng cấp addon lên Odoo 20 - tổng hợp thay đổi kỹ thuật

Odoo Tut 23: Nâng cấp addon lên Odoo 20 - tổng hợp thay đổi kỹ thuật
Phần lớn thay đổi của framework không tập trung tại bản 20.0 mà được đưa vào dần qua các bản Odoo Online 19.1 đến 19.4. Vì vậy, một lần nâng cấp trực tiếp từ Odoo community 19.0 lên 20.0 tiếp nhận toàn bộ các thay đổi đó cùng lúc. Addon chưa được điều chỉnh phù hợp sẽ không khởi động được trên phiên bản mới.
Tổng quan: bảng xếp hạng mức độ rủi ro
Bảng dưới đây gom mức độ rủi ro, phạm vi ảnh hưởng và định danh cần xử lý cho từng nhóm thay đổi.
| # | Nhóm thay đổi | Phạm vi ảnh hưởng và cách xử lý |
|---|---|---|
| 1 | Nền tảng: Python 3.12, PostgreSQL 16, máy chủ HTTP h11 | Cài đặt Odoo trực tiếp trên host phải nâng cấp phiên bản Python và PostgreSQL, với Docker Compose chỉ cần chọn đúng image. |
| 2 | Bảo mật: Gộp ir.model.access và ir.rule thành ir.access | Mọi addon có tệp phân quyền phải cập nhật. Nếu không sẽ báo lỗi. |
| 3 | External API: dịch vụ db bị loại bỏ, API key bắt buộc phạm vi rpc | Hệ thống tích hợp, trình kết nối chuyển sang JSON-2 /json/2/<model>/<method>; cấp lại key với scope='rpc', thu hồi key cũ. |
| 4 | Trường binary thành BinaryValue | Ứng dụng khách đọc tệp qua RPC. Đọc dict {"content","filename","size"} thay vì base64, datas thành raw. |
| 5 | Đổi tên và loại bỏ model, field | Tự kiểm tra khi báo lỗi và sửa cho phù hợp. Ví dụ: product_uom* thành uom_id, hr.leave.type thành hr.work.entry.type. |
| 6 | ORM framework: odoo.osv, tham số định kiểu, bộ nhớ đệm, request | Mã nguồn Python phía máy chủ. odoo.osv thành odoo.fields.Domain; get_param thành get_str/get_int/get_bool; Registry.clear_cache() thành transaction.invalidate_ormcache(); request thành env.website. |
| 7 | Web client: Owl 3, Material Symbols, QWeb t-out | Thành phần JavaScript, bố cục view, báo cáo PDF. static props thành useProps, thêm this., useState thành proxy; t-esc/t-raw thành t-out; fa fa-* thành Material Symbols. |
| 8 | Module gộp hoặc loại bỏ, manifest 20.0.x.y.z | Kiểm tra dependencies trong __manifest__.py trỏ tới module còn tồn tại trong Odoo 20 không. Cập nhật version thành 20.0.x.y.z; base_vat, base_iban vào base, stock_picking_batch vào stock, industry_fsm* thành planning_field_service. |
| 9 | Các điều chỉnh nhỏ | Tiện ích bổ sung như populate, compute_sql, tên record khi duplicate, … |
1. Nền tảng: Python 3.12 và PostgreSQL 16
Trong odoo/release.py của nhánh 20.0 đặc tả rõ:
MIN_PY_VERSION = (3, 12) # Odoo 19: (3, 10)
MIN_PG_VERSION = 16 # Odoo 19: 13
| Yêu cầu | Odoo 19 | Odoo 20 |
|---|---|---|
Python (MIN_PY_VERSION) | 3.10 | 3.12 |
PostgreSQL (MIN_PG_VERSION) | 13 | 16 |
| Máy chủ HTTP | werkzeug | h11 |
- Phạm vi ảnh hưởng: yêu cầu này tác động trực tiếp đến các triển khai cài đặt Odoo trên host.
- Với Docker Compose: đây không phải trở ngại lớn khi image Odoo 20 đã đóng gói Python 3.12 và image PostgreSQL 16 đáp ứng mức tối thiểu.
Các lệnh kiểm tra:
python3 --version # yêu cầu >= 3.12
psql --version # yêu cầu >= 16
2. ir.access thay cho ir.model.access và ir.rule
Odoo 20 loại bỏ model của access right (ir.model.access) và access rule (ir.rule), thay vào đó gộp thành một model duy nhất ir.access. Giờ đây mỗi addon chỉ còn một tệp security/ir.access.csv với các cột id, name, model_id, group_id/id, operation, domain.
group_idrỗng là restriction áp cho mọi người dùng;operationlà tập con củacrud(r,ru,crud) và không có giá trị mặc định;- Quyền được gộp theo biểu thức
OR(permissions) & AND(restrictions).
Ví dụ chuyển đổi đơn giản ở Odoo 19, quyền đọc riêng đơn hàng của nhân viên kinh doanh cần một dòng ACL và một record rule như sau:
security/ir.model.access.csv
# Odoo 19:
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_my_order_user,my.order user,model_my_order,sales_team.group_sale_salesman,1,0,0,0
security/my.xml
<!-- Odoo 19 -->
<record id="rule_my_order_own" model="ir.rule">
<field name="name">my.order own</field>
<field name="model_id" ref="model_my_order"/>
<field name="domain_force">[('user_id', '=', user.id)]</field>
<field name="groups" eval="[(4, ref('sales_team.group_sale_salesman'))]"/>
</record>
Ở Odoo 20, cả hai gộp thành một dòng gọn hơn nhiều:
security/ir.access.csv
# Odoo 20
id,name,model_id,group_id/id,operation,domain
access_my_order_own,my.order own,my.order,sales_team.group_sale_salesman,r,"[('user_id', '=', user.id)]"
Lưu ý: nếu chuyển đổi không đúng logic sẽ gây sai quyền người dùng (right) và dữ liệu người dùng được nhìn thấy (rule).
3. External API: dịch vụ db bị loại bỏ, API key bắt buộc phạm vi rpc
- XML-RPC và JSON-RPC tại
/xmlrpc,/xmlrpc/2,/jsonrpcđược đánh dấu là DEPRECATED - Dịch vụ
dbbị loại bỏ trong Odoo 20,commonvàobjectdự kiến loại bỏ ở Odoo 22 (năm 2028).
Cách nâng cấp:
- Chuyển tích hợp sang chuẩn mới JSON-2 API có từ 19.0
- Cấp lại key cho từng tài khoản tích hợp với phạm vi
scope='rpc'trên môi trường thử nghiệm, kiểm thử rồi thu hồi key cũ tại thời điểm chuyển đổi
Ví dụ một mẫu truy vấn:
POST /json/2/res.partner/search_read HTTP/1.1
Host: mycompany.example.com
Authorization: bearer <rpc-api-key>
Content-Type: application/json; charset=utf-8
{"domain": [["is_company", "=", true]], "fields": ["name"]}
4. Trường binary thành BinaryValue và định dạng RPC mới
Phương thức fields.Binary.convert_to_read() trả về dict với các key {"content", "filename", "size"} thay vì chuỗi base64, áp dụng cho read, search_read và web_read. Client gọi base64.b64decode(record["image_1920"]) (lệnh này rất hay dùng) sẽ gây lỗi TypeError
Chiều ghi giá trị (write) vào field vẫn nhận base64 lẫn dict. ir.attachment.datas bị loại bỏ, thay bằng raw.
Ta có thể dùng hàm sau để tương thích cả 2 phiên bản Odoo 19 và Odoo 20:
import base64
def binary_bytes(value):
if not value: # trường binary rỗng đọc là False
return None
if isinstance(value, dict): # 20.0: {"content", "filename"?, "size"}
value = value["content"]
return base64.b64decode(value)
5. Đổi tên và loại bỏ model, field
| Odoo 19 | Odoo 20 |
|---|---|
ir.model.access, ir.rule | ir.access |
get_param / set_param | get_str, get_int, get_bool, get_float và set_* |
ir.attachment.datas | raw |
product_uom* trên stock, purchase, mrp | uom_id |
stock.scrap | stock.move với is_scrap, scrap_reason_tag_ids |
hr.leave.type, hr.contract.type | hr.work.entry.type, hr.employee.type |
account.group, res.bank, mrp.bom.consumption | loại bỏ |
| … | … |
Cách nâng cấp lên Odoo 20: Rà soát, cập nhật các model và wizard bị gộp hoặc loại bỏ.
Một vài method đổi tên:
check_access_rights(...) -> check_access(...)
toggle_active() -> action_archive()
_check_recursion() -> _has_cycle()
6. ORM
Các điểm đánh dấu lỗi thời từ Odoo 19 nay chính thức bị loại bỏ:
odoo.osvthànhodoo.fields.DomainModel._table_querybị gỡRegistry.clear_cache()thànhtransaction.invalidate_ormcache()requesttrong model code thànhenv.website- Từ 19.4,
create()vàwrite()sắp xếp field theo(field.write_sequence, field_index), nên hook phụ thuộc thứ tự có thể đổi hành vi.
Ví dụ:
# Odoo 19:
env['ir.config_parameter'].get_param('my.key')
# Odoo 20:
env['ir.config_parameter'].get_str('my.key') # get_str / get_int / get_bool / get_float
env['ir.config_parameter'].set_str('my.key', value)
Khai báo ràng buộc bằng models.Constraint, UniqueIndex, Index thay _sql_constraints (đã đề cập ở Tut 21).
7. Frontend
OWL chuyển phiên bản từ 2.8.4 lên 3.0.0-alpha.49, Font Awesome bị thay bằng Material Symbols.
static propsthànhuseProps()useStatethànhproxy, thêmthis.trong templatet-escvàt-rawthànht-outt-settrong thânt-callchuyển thành thuộc tính củat-call- Biểu tượng
fa fa-*đổi sangoi/data-icon - Bỏ
start_month,end_month,start_year,end_yeartrên filter kiểudate.
Ví dụ:
<!-- Odoo 20: tham số truyền qua thuộc tính t-call, xuất nội dung bằng t-out -->
<t t-call="my.template" title="'Hello'"/>
<t t-out="this.state.value"/>
8. Module bị gộp, loại bỏ và khai báo phiên bản trong manifest
Khoảng 50 module bị loại bỏ và 50 module mới, phần lớn module mất được gộp:
base_vatvàbase_ibanvàobasestock_picking_batchvàostockindustry_fsm*thànhplanning_field_service- wkhtmltopdf tách sang
base_report_wkhtmltox,base_report_paper_muncherlà tùy chọn.
Đổi version trong __manifest__.py từ 19.0.x.y.z thành 20.0.x.y.z.
9. Các điều chỉnh nhỏ
Các tiện ích mới, không yêu cầu sửa addon như:
populatesinh dữ liệu giả- Hàm sao chép mặc định thêm "(copy)" cho char field
name Field.compute_sqlcho phép nhóm và sắp xếp computed field bằng SQL, SQL builder APIModel.concatvàModel.uniongọn hơn, ghi nhiều bản dịch trong một lần write- …
Thứ tự nâng cấp khuyến nghị (checklist)
- Đảm bảo môi trường triển khai đáp ứng yêu cầu Python 3.12, PostgreSQL 16. Có thể dùng minhng92/odoo-20-docker-compose để triển khai Odoo 20.
- Viết lại
security/ir.access.csv, kiểm thử quyền truy cập sau khi chuyển đổi. - Cấp lại API key
scope='rpc', kiểm thử tích hợp trên môi trường thử nghiệm. - Cập nhật những đoạn code liên quan đến trường Binary.
- Nâng cấp code frontend qua Owl 3, các directive trong Qweb và dùng biểu tượng Material Symbols.
- Manifest > khai báo phiên bản
20.0.x.y.z, cập nhậtdependsđến các module tồn tại trong Odoo 20. - Cập nhật model, field và method đổi tên.
- Kiểm thử sau khi nâng cấp: phân quyền không dùng admin, tích hợp, báo cáo PDF, portal, có và không có dữ liệu demo.
Quy mô thay đổi Odoo 19 → 20
- Odoo 20 thêm hoặc loại bỏ 186 model (thêm 123 mới, xóa bớt 63)
- Thay đổi 194 ràng buộc, khoảng 50 module mất và 50 module mới, với 12 thay đổi gây lỗi không tương thích cho custom code và tích hợp.
- Odoo 18 lên 19 có 129 model và 207 ràng buộc thay đổi.
Các số liệu này cho phép ước lượng khối lượng công việc trước khi bắt đầu nâng cấp từ Odoo 19 lên Odoo 20.
Tham khảo
- Tài liệu Odoo 20.0: ORM Changelog
- Tài liệu Odoo 20.0: Security in Odoo và ir.access
- Tài liệu Odoo 20.0: External RPC API và lộ trình lỗi thời
- Tài liệu Odoo 20.0: External JSON-2 API
- Tài liệu Odoo 20.0: Source install, Python 3.12 và PostgreSQL 16
- Tài liệu Odoo 20.0: Upgrade utils
- OCA: Odoo 20, nội dung thực có trong bản Community
- Way4Tech: Odoo 20, tính năng mới và di trú từ bản 19
- Cybrosys: Những thay đổi trong ORM Odoo 20
- OWL 3: Ghi chú phát hành và hướng dẫn di trú
- Havi: Ghi chú kỹ thuật Odoo 20
- OCU: Tổng hợp thay đổi Odoo 20
Hãy tham gia group Facebook để trao đổi và học hỏi thêm về Odoo nhé các bạn => Khám phá Odoo: https://facebook.com/groups/odoo-dev
Tham gia wait-list Khóa học Lập trình Odoo 19: https://forms.gle/niDFrZxcoAcLU8qz6
Cài đặt Odoo:
- Docker Compose for Odoo 10
- Docker Compose for Odoo 11
- Docker Compose for Odoo 12
- Docker Compose for Odoo 13
- Docker Compose for Odoo 14
- Docker Compose for Odoo 15
- Docker Compose for Odoo 16
- Docker Compose for Odoo 17
- Docker Compose for Odoo 18
- Docker Compose for Odoo 19
- Docker Compose for Odoo 20
Danh sách bài viết series Odoo:
- Tut 0: Học lập trình Odoo - tutorials
- Tut 1: Odoo là gì?
- Tut 2: Hướng dẫn cài đặt Odoo version 10, 11, 12, 13, 14, 15, 16, 17, 18, 19
- Tut 3: Tạo model trong Odoo
- Tut 4: View trong Odoo
- Tut 5: Controller trong Odoo
- Tut 6: Thừa kế model trong Odoo
- Tut 7: Thừa kế view trong Odoo
- Tut 8: Thừa kế controller trong Odoo
- Tut 9: API trong Odoo - XML-RPC
- Tut 10: Hiện thực wizard trong Odoo
- Tut 11: Tạo widget trong Odoo
- Tut 12: Tạo settings trong Odoo cho custom addon
- Tut 13: Thêm button cho list/tree view trong Odoo
- Tut 14: Search, Filter, Group By trong Odoo
- Tut 15: Kết nối PostgreSQL database của Odoo bằng câu lệnh
- Tut 16: Kết nối pgAdmin vào PostgreSQL database của Odoo
- Tut 17: Tra cứu mã nguồn để lập trình Odoo
- Tut 18: Thêm button cho form view trong Odoo
- Tut 19: [App] JSON REST API trong Odoo
- Tut 20: Triển khai Odoo trên VPS
- Tut 21: Nâng cấp addon lên Odoo 19 - tổng hợp thay đổi kỹ thuật
- Tut 22: [App] Dark theme trong Odoo - Dark Islands Backend Theme
- Tut 23: Nâng cấp addon lên Odoo 20 - tổng hợp thay đổi kỹ thuật
Hãy tham gia group Khám phá Odoo để cùng trao đổi và học hỏi. 

