forked from erp-dev/erp
60 lines
2.0 KiB
Python
60 lines
2.0 KiB
Python
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
|