"""商品中心服务:多单位换算等。 约定: - Product.base_unit 为基本单位;UnitConversion.rate 表示 1 个录入单位 = rate × 基本单位 - 单据行 quantity 恒存基本单位数量;录入单位/数量存 source_unit/source_quantity """ from __future__ import annotations from decimal import Decimal from .models import Product, UnitConversion class UnitConversionNotFound(Exception): """商品缺少该单位的换算率。""" def to_base(product: Product, unit, quantity: Decimal) -> Decimal: """把"录入单位数量"换算成基本单位数量。 unit 可以是 Unit 实例、pk 或 code;与基本单位相同(或未传)时原样返回。 """ if unit in (None, ""): return Decimal(str(quantity)) base = product.base_unit if base is not None and (unit == base or getattr(unit, "pk", None) == base.pk): return Decimal(str(quantity)) conv = UnitConversion.objects.filter(product=product, unit=unit).first() if conv is None: unit_code = getattr(unit, "code", str(unit)) raise UnitConversionNotFound( f"product {product.code} has no conversion for unit {unit_code}" ) return Decimal(str(quantity)) * conv.rate