from decimal import Decimal, InvalidOperation, ROUND_HALF_UP from django.conf import settings AMOUNT_MODE_HAOBUYE_INTEGER = 'haobuye_integer_round_half_up' AMOUNT_MODE_STANDARD_DECIMAL_2 = 'standard_decimal_2' AMOUNT_MODES = { AMOUNT_MODE_HAOBUYE_INTEGER, AMOUNT_MODE_STANDARD_DECIMAL_2, } INTEGER_QUANT = Decimal('1') DECIMAL_2_QUANT = Decimal('0.01') def to_decimal(value, *, field_name: str = 'value') -> Decimal: try: return Decimal(str(value)) except (InvalidOperation, TypeError, ValueError) as exc: raise ValueError(f'{field_name} 必须是数字') from exc def normalize_money_amount(value, *, field_name: str = 'amount') -> Decimal: decimal_value = to_decimal(value, field_name=field_name) return decimal_value.quantize(_money_quant(), rounding=ROUND_HALF_UP) def calculate_line_amount(*, quantity, price, standard_quantity=None) -> Decimal: raw_quantity = quantity if _amount_mode() == AMOUNT_MODE_STANDARD_DECIMAL_2 and standard_quantity is not None: raw_quantity = standard_quantity quantity_value = to_decimal( raw_quantity, field_name='quantity', ) price_value = to_decimal(price, field_name='price') return (quantity_value * price_value).quantize(_money_quant(), rounding=ROUND_HALF_UP) def calculate_settlement_amount(*, amount, discount_amount=Decimal('0')) -> Decimal: return normalize_money_amount( normalize_money_amount(amount, field_name='amount') + normalize_money_amount(discount_amount or Decimal('0'), field_name='discount_amount'), field_name='settlement_amount', ) def _amount_mode() -> str: mode = getattr(settings, 'BUSINESS_AMOUNT_MODE', AMOUNT_MODE_HAOBUYE_INTEGER) if mode not in AMOUNT_MODES: raise ValueError(f'BUSINESS_AMOUNT_MODE 不合法: {mode}') return mode def _money_quant() -> Decimal: if _amount_mode() == AMOUNT_MODE_STANDARD_DECIMAL_2: return DECIMAL_2_QUANT return INTEGER_QUANT