Số tiền không phải số thực bình thường. 123456.789 VND là vô nghĩa (không có 0.789 đồng), còn 99.999 USD phải thành 100.00. Mỗi loại tiền có quy tắc làm tròn riêng. Odoo có một kiểu trường chuyên cho tiền — Monetary — tự lo việc đó. Nối tiếp Selection, bài này bàn trường Monetary.
Monetary luôn đi kèm tiền tệ
Điểm bắt buộc: trường Monetary phải trỏ tới một trường tiền tệ qua currency_field:

Hình 1: Monetary bắt buộc khai currency_field='currency_id' trỏ tới một trường Many2one tới res.currency. Thiếu nó, Odoo báo lỗi lúc nạp module. Đây là lý do bạn luôn thấy cặp currency_id + trường tiền đi cùng nhau trong mọi model có tiền của Odoo.
Vì sao không dùng Float? Đo thật
Điểm khác biệt lớn nhất: Monetary tự làm tròn theo số chữ số thập phân của đúng loại tiền. Đây là output thật trên db blog19:

Hình 2: Output thật. VND có rounding=1.0 (0 chữ số) nên 123456.789 tự làm tròn về 123457 (đồng nguyên). USD có rounding=0.01 (2 chữ số) nên 99.999 thành 100.00. Cùng một con số nhưng tiền tệ khác → kết quả khác. Dùng Float thì bạn phải tự làm tròn đúng cho từng loại tiền — cực dễ sai. Monetary lo hết.
Ba việc Monetary làm cho bạn
1. Làm tròn theo tiền tệ
Như Hình 2: mỗi tiền tệ có decimal_places và rounding riêng; Monetary tự áp. Yên nữa (JPY) 0 chữ số, dinar (KWD) 3 chữ số — bạn không cần nhớ, chỉ chọn đúng currency_id.
2. Hiển thị đúng ký hiệu và vị trí
Giao diện hiện 1.000.000 ₫ (ký hiệu sau) hay $1,000.00 (ký hiệu trước) theo chuẩn từng tiền tệ, kèm dấu phân cách hàng nghìn — tự động, không cần format tay.
3. Cảnh báo khi cộng tiền khác loại
Cộng "100 USD + 50 VND" là vô nghĩa. Khi bạn read_group/sum các Monetary khác tiền tệ, Odoo cảnh báo hoặc yêu cầu quy đổi — tránh cộng bừa.
API làm tròn tiền tệ
Khi tính toán số tiền trong code, dùng currency.round() để làm tròn đúng chuẩn:
gia_sau_thue = currency.round(gia * 1.08) # làm tròn theo tiền tệ
# So sánh tiền phải qua compare_amounts để tránh sai số float:
if currency.compare_amounts(a, b) == 0: # a == b theo độ chính xác tiền tệ
...
compare_amounts quan trọng: so sánh trực tiếp hai Float tiền có thể sai vì sai số dấu phẩy động; compare_amounts so theo đúng số chữ số của tiền.
Lưu ý
currency_fieldmặc định tên'currency_id': nếu trường tiền tệ của bạn tên khác, phải khai rõ.- Nhiều tiền tệ trên một model: có thể có
currency_id(tiền giao dịch) vàcompany_currency_id(tiền công ty), mỗi Monetary trỏ tới cái phù hợp. - Đừng đổi tiền tệ sau khi có dữ liệu mà không quy đổi — số tiền cũ sẽ bị hiểu sai loại tiền.
Nhớ ba ý
- Monetary cho số tiền, bắt buộc khai
currency_fieldtrỏ tới trường Many2oneres.currency— thiếu là lỗi nạp module. - Monetary tự làm tròn theo tiền tệ: đo thật
123456.789VND → 123457 (0 chữ số),99.999USD → 100.00 (2 chữ số) — đừng dùngFloatcho tiền. - Tính toán tiền dùng
currency.round()và so sánh bằngcompare_amounts()để tránh sai số float; giao diện tự hiện đúng ký hiệu (₫/$) và vị trí.
Còn vài loại trường đặc biệt nữa cho nội dung phong phú. Phần sau đi vào Html, Binary, Image — lưu văn bản định dạng, tệp nhị phân, và ảnh; cùng cách chúng được làm sạch và tối ưu.