diff --git a/ecommerce/models.py b/ecommerce/models.py index 75799f3088..297b18e843 100644 --- a/ecommerce/models.py +++ b/ecommerce/models.py @@ -640,17 +640,25 @@ def _get_or_create( product_content_types.append(product.content_type_id) # Get or create a PendingOrder - orders = Order.objects.select_for_update().filter( - lines__purchased_object_id__in=product_object_ids, - lines__purchased_content_type_id__in=product_content_types, - lines__product_version__in=product_versions, - state=Order.STATE.PENDING, - purchaser=user, + orders = ( + Order.objects.select_for_update() + .prefetch_related("discounts") + .filter( + lines__purchased_object_id__in=product_object_ids, + lines__purchased_content_type_id__in=product_content_types, + lines__product_version__in=product_versions, + state=Order.STATE.PENDING, + purchaser=user, + ) ) # Previously, multiple PendingOrders could be created for a single user # for the same product, if multiple exist, grab the first. if orders: order = orders.first() + + for old_discount in order.discounts.all(): + old_discount.delete() + else: order = Order.objects.create( state=Order.STATE.PENDING, diff --git a/ecommerce/models_test.py b/ecommerce/models_test.py index b5b0dd4b66..c85b42c9e0 100644 --- a/ecommerce/models_test.py +++ b/ecommerce/models_test.py @@ -7,6 +7,7 @@ from django.core.exceptions import ValidationError from django.db import IntegrityError, transaction from mitol.common.utils import now_in_utc +from reversion.models import Version from ecommerce.constants import ( DISCOUNT_TYPE_DOLLARS_OFF, @@ -36,7 +37,6 @@ Transaction, ) from users.factories import UserFactory -from reversion.models import Version pytestmark = [pytest.mark.django_db] @@ -423,6 +423,43 @@ def test_pending_order_is_reused(basket): assert Order.objects.filter(state=Order.STATE.PENDING).count() == 1 +def test_pending_order_is_reused_but_discounts_cleared(basket, unlimited_discount): + """ + If a pending order is reused and had discounts, then we want those discounts + to clear. + """ + + with reversion.create_revision(): + product = ProductFactory.create() + + basket_item = BasketItem(product=product, basket=basket, quantity=1) + basket_item.save() + order = PendingOrder.create_from_basket(basket) + order.save() + assert Order.objects.filter(state=Order.STATE.PENDING).count() == 1 + + redemption = DiscountRedemption( + redeemed_discount=unlimited_discount, + redemption_date=now_in_utc(), + redeemed_order=order, + redeemed_by=order.purchaser, + ) + redemption.save() + + order.refresh_from_db() + assert order.discounts.count() == 1 + + order = PendingOrder.create_from_basket(basket) + order.save() + order.refresh_from_db() + + # Verify that the existing PendingOrder is reused and a duplicate is not created. + # This is to ensure that we also reuse the HubSpot Deal associated with Orders. + # Also ensure the discounts aren't reattached to the order + assert Order.objects.filter(state=Order.STATE.PENDING).count() == 1 + assert order.discounts.count() == 0 + + def test_new_pending_order_is_created_if_product_is_different(): """ Test that creating a second PendingOrder with a different associated Product