From b0dcbe31fa76c054e94290526464c847e8789210 Mon Sep 17 00:00:00 2001 From: Raphael Michel Date: Wed, 15 Apr 2020 12:54:57 +0200 Subject: [PATCH] Fix incorrect quota error when changing subevent and item of a position --- src/pretix/base/services/orders.py | 21 +++++++++++++++++++++ src/pretix/control/views/orders.py | 13 +++++++++++-- src/tests/base/test_orders.py | 20 ++++++++++++++++++++ 3 files changed, 52 insertions(+), 2 deletions(-) diff --git a/src/pretix/base/services/orders.py b/src/pretix/base/services/orders.py index 0a71703156..11aeb4f328 100644 --- a/src/pretix/base/services/orders.py +++ b/src/pretix/base/services/orders.py @@ -1224,6 +1224,27 @@ class OrderChangeManager: self._quotadiff.subtract(position.quotas) self._operations.append(self.SubeventOperation(position, subevent)) + def change_item_and_subevent(self, position: OrderPosition, item: Item, variation: Optional[ItemVariation], + subevent: SubEvent): + if (not variation and item.has_variations) or (variation and variation.item_id != item.pk): + raise OrderError(self.error_messages['product_without_variation']) + + price = get_price(item, variation, voucher=position.voucher, subevent=subevent, + invoice_address=self._invoice_address) + + if price is None: # NOQA + raise OrderError(self.error_messages['product_invalid']) + + new_quotas = (variation.quotas.filter(subevent=subevent) + if variation else item.quotas.filter(subevent=subevent)) + if not new_quotas: + raise OrderError(self.error_messages['quota_missing']) + + self._quotadiff.update(new_quotas) + self._quotadiff.subtract(position.quotas) + self._operations.append(self.ItemOperation(position, item, variation)) + self._operations.append(self.SubeventOperation(position, subevent)) + def regenerate_secret(self, position: OrderPosition): self._operations.append(self.RegenerateSecretOperation(position)) diff --git a/src/pretix/control/views/orders.py b/src/pretix/control/views/orders.py index dd4cf874a7..50ce6d59fe 100644 --- a/src/pretix/control/views/orders.py +++ b/src/pretix/control/views/orders.py @@ -1487,6 +1487,7 @@ class OrderChange(OrderView): ocm.cancel(p) continue + change_item = None if p.form.cleaned_data['itemvar']: if '-' in p.form.cleaned_data['itemvar']: itemid, varid = p.form.cleaned_data['itemvar'].split('-') @@ -1499,10 +1500,18 @@ class OrderChange(OrderView): else: variation = None if item != p.item or variation != p.variation: - ocm.change_item(p, item, variation) + change_item = (item, variation) + change_subevent = None if self.request.event.has_subevents and p.form.cleaned_data['subevent'] and p.form.cleaned_data['subevent'] != p.subevent: - ocm.change_subevent(p, p.form.cleaned_data['subevent']) + change_subevent = (p.form.cleaned_data['subevent'],) + + if change_item is not None and change_subevent is not None: + ocm.change_item_and_subevent(p, *change_item, *change_subevent) + elif change_item is not None: + ocm.change_item(p, *change_item) + elif change_subevent is not None: + ocm.change_subevent(p, *change_subevent) if p.seat and p.form.cleaned_data['seat'] and p.form.cleaned_data['seat'] != p.seat.seat_guid: ocm.change_seat(p, p.form.cleaned_data['seat']) diff --git a/src/tests/base/test_orders.py b/src/tests/base/test_orders.py index 2066cfe309..b4ca533e7d 100644 --- a/src/tests/base/test_orders.py +++ b/src/tests/base/test_orders.py @@ -827,6 +827,26 @@ class OrderChangeManagerTests(TestCase): with self.assertRaises(OrderError): self.ocm.change_subevent(self.op1, se2) + @classscope(attr='o') + def test_change_subevent_and_product(self): + self.event.has_subevents = True + self.event.save() + se1 = self.event.subevents.create(name="Foo", date_from=now()) + se2 = self.event.subevents.create(name="Bar", date_from=now()) + self.op1.subevent = se1 + self.op1.save() + self.quota.subevent = se1 + self.quota.save() + self.quota.items.remove(self.shirt) + q2 = self.event.quotas.create(name="Q2", size=None, subevent=se2) + q2.items.add(self.shirt) + self.ocm.change_item_and_subevent(self.op1, self.shirt, None, se2) + self.ocm.commit() + self.op1.refresh_from_db() + self.order.refresh_from_db() + assert self.op1.subevent == se2 + assert self.op1.item == self.shirt + @classscope(attr='o') def test_change_subevent_success(self): self.event.has_subevents = True