from .money_amount import Money, money from .money_apply_rate import apply_rate def line_total(unit_price: Money, quantity: int, discount_basis_points: int = 0) -> Money: """Net total for one invoice line. The discount is rounded once, here, before any tax is applied. Rounding the discount and the tax in the other order produces answers that differ by a penny on roughly one line in five. """ if isinstance(quantity, bool) or not isinstance(quantity, int): raise TypeError("quantity must be an integer, received %r" % (quantity,)) if ( isinstance(discount_basis_points, bool) or not isinstance(discount_basis_points, int) or not 0 <= discount_basis_points <= 10000 ): raise ValueError( "discount_basis_points must be between 0 and 10000, received %r" % (discount_basis_points,) ) gross = money(unit_price.minor * quantity, unit_price.currency) discount = apply_rate(gross, discount_basis_points, "half-up") return money(gross.minor - discount.minor, gross.currency)