From b1db5dbb3e56d886394f7cbf83c7ff125a471b3e Mon Sep 17 00:00:00 2001 From: Martin Gross Date: Fri, 14 Jun 2019 12:41:07 +0200 Subject: [PATCH] Decrement voucher usage counter when deleting testmode orders (#1321) * Decrement voucher usage counter when deleting testmode orders * Only decrement voucher usage counter for uncancelled orders and on uncancelled positions * Have the tests actually test something --- src/pretix/base/models/orders.py | 10 ++++- src/tests/api/test_orders.py | 69 ++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 1 deletion(-) diff --git a/src/pretix/base/models/orders.py b/src/pretix/base/models/orders.py index bcd8c519b..280d06bfb 100644 --- a/src/pretix/base/models/orders.py +++ b/src/pretix/base/models/orders.py @@ -15,7 +15,7 @@ from django.db import models, transaction from django.db.models import ( Case, Exists, F, Max, OuterRef, Q, Subquery, Sum, Value, When, ) -from django.db.models.functions import Coalesce +from django.db.models.functions import Coalesce, Greatest from django.db.models.signals import post_delete from django.dispatch import receiver from django.urls import reverse @@ -195,6 +195,8 @@ class Order(LockModel, LoggedModel): return self.full_code def gracefully_delete(self, user=None, auth=None): + from . import Voucher + if not self.testmode: raise TypeError("Only test mode orders can be deleted.") self.event.log_action( @@ -203,6 +205,12 @@ class Order(LockModel, LoggedModel): 'code': self.code, } ) + + if self.status != Order.STATUS_CANCELED: + for position in self.positions.all(): + if position.voucher: + Voucher.objects.filter(pk=position.voucher.pk).update(redeemed=Greatest(0, F('redeemed') - 1)) + OrderPosition.all.filter(order=self, addon_to__isnull=False).delete() OrderPosition.all.filter(order=self).delete() OrderFee.all.filter(order=self).delete() diff --git a/src/tests/api/test_orders.py b/src/tests/api/test_orders.py index 0ed9bbd6e..077eb242c 100644 --- a/src/tests/api/test_orders.py +++ b/src/tests/api/test_orders.py @@ -2565,6 +2565,75 @@ def test_order_delete_test_mode(token_client, organizer, event, order): assert not Order.objects.filter(code=order.code).exists() +@pytest.mark.django_db +def test_order_delete_test_mode_voucher(token_client, organizer, event, order, item): + order.testmode = True + order.save() + q = event.quotas.create(name="Quota") + q.items.add(item) + voucher = event.vouchers.create(price_mode="set", value=15, quota=q, redeemed=1) + op = order.positions.first() + op.voucher = voucher + op.save() + + assert voucher.redeemed == 1 + + resp = token_client.delete( + '/api/v1/organizers/{}/events/{}/orders/{}/'.format( + organizer.slug, event.slug, order.code + ) + ) + assert resp.status_code == 204 + assert not Order.objects.filter(code=order.code).exists() + voucher.refresh_from_db() + assert voucher.redeemed == 0 + + +@pytest.mark.django_db +def test_order_delete_test_mode_voucher_cancelled_position(token_client, organizer, event, order, item): + order.testmode = True + order.save() + q = event.quotas.create(name="Quota") + q.items.add(item) + voucher = event.vouchers.create(price_mode="set", value=15, quota=q, redeemed=42) + op = order.all_positions.last() + op.voucher = voucher + op.save() + + resp = token_client.delete( + '/api/v1/organizers/{}/events/{}/orders/{}/'.format( + organizer.slug, event.slug, order.code + ) + ) + assert resp.status_code == 204 + assert not Order.objects.filter(code=order.code).exists() + voucher.refresh_from_db() + assert voucher.redeemed == 42 + + +@pytest.mark.django_db +def test_order_delete_test_mode_voucher_cancelled_order(token_client, organizer, event, order, item): + order.testmode = True + order.status = Order.STATUS_CANCELED + order.save() + q = event.quotas.create(name="Quota") + q.items.add(item) + voucher = event.vouchers.create(price_mode="set", value=15, quota=q, redeemed=42) + op = order.positions.first() + op.voucher = voucher + op.save() + + resp = token_client.delete( + '/api/v1/organizers/{}/events/{}/orders/{}/'.format( + organizer.slug, event.slug, order.code + ) + ) + assert resp.status_code == 204 + assert not Order.objects.filter(code=order.code).exists() + voucher.refresh_from_db() + assert voucher.redeemed == 42 + + @pytest.mark.django_db def test_order_update_ignore_fields(token_client, organizer, event, order): resp = token_client.patch(