"""Exact fixed point arithmetic shared by persistence, forms and PDF output.""" from decimal import Decimal, InvalidOperation, ROUND_HALF_UP ZERO = Decimal('0') CENT = Decimal('0.01') UNIT = Decimal('0.0001') MAX_VALUE = Decimal('999999999') MAX_TOTAL = Decimal('999999999999.99') def number(value, label='数值', allow_zero=True): try: result = Decimal(str(value if value not in (None, '') else 0).strip()) except (InvalidOperation, ValueError): raise ValueError('%s必须是有效数字' % label) if not result.is_finite() or result < 0 or result > MAX_VALUE: raise ValueError('%s必须在 0 到 %s 之间' % (label, MAX_VALUE)) if result != result.quantize(UNIT): raise ValueError('%s最多保留四位小数' % label) if not allow_zero and result == 0: raise ValueError('%s必须大于零' % label) return result.quantize(UNIT) def money(value): return Decimal(str(value or 0)).quantize(CENT, rounding=ROUND_HALF_UP) def line_amount(qty, price): amount = money(number(qty, '数量') * number(price, '单价')) if amount > MAX_TOTAL: raise ValueError('明细金额过大') return amount def format_price(value): return format(Decimal(str(value or 0)), '.4f').rstrip('0').rstrip('.') or '0'