Một số tiền cần ba mẩu thông tin, không phải một: giá trị, đơn vị tiền tệ, và (nếu có quy đổi) tỷ giá tại thời điểm giao dịch.
create table payments (
id bigserial primary key,
amount_minor bigint not null, -- 1050 = 10.50 USD
currency char(3) not null, -- ISO 4217
fx_rate numeric(18,8), -- rate to base currency
base_amount_minor bigint, -- converted, for reporting
captured_at timestamptz not null
);Giá trị: dùng numeric/decimal hoặc số nguyên đơn vị nhỏ nhất (cent, đồng). Không dùng float/double vì nhị phân dấu phẩy động không biểu diễn chính xác 0.1 — cộng dồn nhiều dòng sẽ lệch xu.
Số chữ số thập phân khác nhau theo tiền tệ: USD 2 chữ số, VND và JPY 0 chữ số (zero-decimal), KWD 3 chữ số. Vì vậy amount_minor chỉ có nghĩa khi đi kèm currency — không được cộng hai dòng khác currency lại với nhau.
Tỷ giá phải snapshot. Báo cáo doanh thu quy đổi ra một đồng tiền gốc mà tra tỷ giá "hiện tại" thì số liệu tháng trước sẽ đổi mỗi ngày. Lưu fx_rate và số tiền đã quy đổi ngay tại thời điểm ghi nhận.
Một lưu ý khi phỏng vấn hay bị bắt: đừng đặt currency ở cấp giao dịch nhưng lại tổng hợp SUM(amount) toàn bảng — luôn GROUP BY currency hoặc cộng trên cột đã quy đổi.