T11 — Odoo 19 HR Model Field Gotchas (3 issues)
Tóm tắt
3 gotchas khi query HR models trên Odoo 19: (1)hr.version không có field state, (2) hr.job không có field state, (3) Many2one name fields có thể trả về False (boolean) thay vì string/None.
Chi tiết
Issue 1: hr.version không có field state
Odoo 17/18 có hr.contract với field state (draft/open/close/cancel). Odoo 19 dùng hr.version thay thế, và KHÔNG có field state. Chỉ có field active (boolean).
❌ SAI — gây ValueError
models.execute_kw(db, uid, api_key, 'hr.version', 'search_read', [
[('state', '=', 'open')] # → ValueError: Invalid field hr.version.state
], {'fields': ['name', 'state']})
✅ ĐÚNG — dùng active
models.execute_kw(db, uid, api_key, 'hr.version', 'search_read', [
[('active', '=', True)]
], {'fields': ['name', 'active', 'date_start', 'date_end']})
Cách phân biệt open/close: Dùng logic thủ công:
active=True + date_end=False hoặc date_end >= today → đang hoạt độngactive=True + date_end < today → đã hết hạn nhưng chưa archiveactive=False → đã archive (close)Issue 2: hr.job không có field state
hr.job trong Odoo 19 không có field state (ví dụ recruit/open). Field này không tồn tại.
❌ SAI
fields = ['name', 'state', 'no_of_recruitment'] # state gây lỗi
✅ ĐÚNG — bỏ state
fields = ['name', 'no_of_recruitment', 'no_of_hired_employee', 'department_id']
Để biết job đang recruit hay không → check no_of_recruitment > 0.
Issue 3: Many2one name field trả về False (boolean)
Một số records Odoo 19 có field name trả về Python False (kiểu boolean) thay vì string hoặc None. Nếu dùng string operations trực tiếp → TypeError: 'bool' object is not subscriptable.
❌ SAI — crash khi name=False
v.get('name', '?')[:25] # TypeError nếu name=False vì get() trả về False, không phải '?'
✅ ĐÚNG — wrap str() + or
str(v.get('name') or '?')[:25] # False → '?' → slice OK
Quy tắc: Với BẤT KỲ field nào có thể None/False trong Odoo → luôn dùng str(val or default) thay vì val.get('field', default) vì .get() chỉ dùng default khi key MISSING, không khi value=False.
Ảnh hưởng
hr.version, hr.job, hoặc bất kỳ model nào có field boolean-FalseCách xử lý / Phòng tránh
1. Trước khi query model mới: Dùng fields_get() để kiểm tra fields thực tế:
fields = models.execute_kw(db, uid, api_key, 'hr.version', 'fields_get', [], {'attributes': ['type', 'string']})
print([f for f in fields if 'state' in f.lower()])
2. Pattern an toàn cho string fields:
# Thay vì: record.get('name', '?')
# Dùng:
str(record.get('name') or '?')
3. Pattern an toàn cho domain filters:
# Thay vì: ('state', '=', 'open')
# Dùng: ('active', '=', True)
Bằng chứng / Tham khảo
scripts/hr_intelligence.py — 3 bugs fixed trong session 13/03/2026hr.version model replaces hr.contract (field list confirmed via fields_get())ValueError: Invalid field hr.version.state, TypeError: 'bool' object is not subscriptableLiên quan
hr.version thay thế hr.contract trong Odoo 19
📚 Published from Company Knowledge Base — T11
Last updated: 2026-03-13
Review by: 2026-06-11