fix: offer/auction cart charges agreed price, not list price

total_discounted_price_in_cents summed line items and ignored the
cart_offer / cart_auction override. is_discounted then reported True
(agreed ≠ list), so total_in_cents — what the charge path reads —
returned the list price. UI strikethroughed the agreed price and
charged the list price.

Short-circuit the discounted path on override, the same way
total_price_in_cents does. An offer/auction is a negotiated price,
not a discount, so coupons and gift-card balances do not stack on
top of it.

Extended both override tests to assert total_in_cents,
total_discounted_price_in_cents, and is_discounted — the gap that
let this ship.
This commit is contained in:
russell@unturf.com 2026-05-13 07:09:56 -04:00
parent 6119489c40
commit c58b6b27a7
No known key found for this signature in database
2 changed files with 24 additions and 0 deletions

View file

@ -395,7 +395,18 @@ class Cart(RBase, Base):
def total_discounted_price_in_cents(self):
"""
Calculate the total discounted price in cents, including handling cost and gift card purchases.
MPS-20 + MPS-21: an auction-won or offer-accepted cart pays the
agreed amount; coupons and gift-card balances do not stack on top
of a negotiated price.
"""
override = self.auction_offer_override_in_cents
if override is not None:
total = override
total += self.gift_card_purchases_total_in_cents
if self.handling_cost_in_cents:
total += self.handling_cost_in_cents
return total
total = sum(self.discounted_shop_totals_in_cents.values())
total += self.gift_card_purchases_total_in_cents
if self.handling_cost_in_cents:

View file

@ -4942,6 +4942,12 @@ class TestCartTotalOverride(DatabaseIntegrationTests):
# Override: $42 not $100.
self.assertEqual(cart.auction_offer_override_in_cents, 4200)
self.assertEqual(cart.total_price_in_cents, 4200)
# The charge path (total_in_cents) and the discounted path must
# both honor the override — otherwise the cart strikethroughs the
# agreed price and charges the list price.
self.assertEqual(cart.total_discounted_price_in_cents, 4200)
self.assertEqual(cart.total_in_cents, 4200)
self.assertFalse(cart.is_discounted)
def test_offer_override_uses_current_amount(self):
from ..models.cart import Cart
@ -4974,6 +4980,13 @@ class TestCartTotalOverride(DatabaseIntegrationTests):
# Override: $80 not $100.
self.assertEqual(cart.auction_offer_override_in_cents, 8000)
self.assertEqual(cart.total_price_in_cents, 8000)
# Cart logic was built for coupons (a discount on top of list
# price). Offers are a negotiated price, not a discount — both
# totals must agree, so is_discounted is False and the buyer is
# charged the offer amount, not the list price.
self.assertEqual(cart.total_discounted_price_in_cents, 8000)
self.assertEqual(cart.total_in_cents, 8000)
self.assertFalse(cart.is_discounted)
class TestAuctionTickIntegration(DatabaseIntegrationTests):