;; lib/commerce/nettax.sx — discount-aware tax (alternative policy). ;; ;; price.sx / quote.sx tax the GROSS per-line amounts (discount reduces payable ;; but not the tax base). This module is the alternative explicit policy: tax the ;; NET (post-discount) base. The basket-level discount is allocated across lines ;; in proportion to each line's extended price, with a deterministic ;; largest-remainder pass so per-line shares sum EXACTLY to the discount; tax is ;; then charged on each line's net at its class rate. ;; ;; Both policies are reproducible from (ctx, cart, ruleset, exclusions); pick the ;; one the jurisdiction requires. cart-quote-net mirrors cart-quote's shape. (define ct-sum (fn (xs) (reduce (fn (a x) (+ a x)) 0 xs))) ;; Add 1 to the first `rem` elements (deterministic remainder distribution). (define ct-add-rem (fn (xs rem) (cond ((empty? xs) (list)) ((> rem 0) (cons (+ (first xs) 1) (ct-add-rem (rest xs) (- rem 1)))) (:else xs)))) ;; Per-line discount allocation (parallel to cart), summing exactly to ;; total-discount, proportional to line-extended share. (define allocate-discount (fn (cat cart total-discount) (let ((sub (cart-subtotal cat cart))) (if (= sub 0) (map (fn (l) 0) cart) (let ((floors (map (fn (l) (quotient (* total-discount (line-extended cat l)) sub)) cart))) (ct-add-rem floors (- total-discount (ct-sum floors)))))))) ;; Tax on one line's net (extended - allocated discount), clamped at 0. (define net-line-tax (fn (ctx line alloc) (let ((cat (ctx-catalog ctx))) (let ((net (- (line-extended cat line) alloc))) (apply-bps (if (< net 0) 0 net) (rate-bps (get ctx :tax-rules) (get ctx :jurisdiction) (catalog-class cat (line-sku line)) (get ctx :customer))))))) (define net-tax (fn (ctx cart allocations) (ct-sum (map (fn (line alloc) (net-line-tax ctx line alloc)) cart allocations)))) ;; Discount-aware quote: tax computed on the net (post-discount) base. (define cart-quote-net (fn (ctx cart ruleset exclusions) (let ((cat (ctx-catalog ctx))) (let ((sub (cart-subtotal cat cart)) (disc (best-promo-discount ctx cart ruleset exclusions)) (codes (best-promo-codes ctx cart ruleset exclusions))) (let ((tax (net-tax ctx cart (allocate-discount cat cart disc)))) {:codes codes :subtotal sub :discount disc :total (+ (- sub disc) tax) :tax tax})))))