diff --git a/src/pretix/base/services/orders.py b/src/pretix/base/services/orders.py index 80aa4d5080..8eac8ded08 100644 --- a/src/pretix/base/services/orders.py +++ b/src/pretix/base/services/orders.py @@ -815,12 +815,17 @@ class OrderChangeManager: self.notify = notify self._invoice_dirty = False - def change_item(self, position: OrderPosition, item: Item, variation: Optional[ItemVariation]): + def change_item(self, position: OrderPosition, item: Item, variation: Optional[ItemVariation], keep_price=False): 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=position.subevent, - invoice_address=self._invoice_address) + if keep_price: + price = TaxedPrice(gross=position.price, net=position.price - position.tax_value, + tax=position.tax_value, rate=position.tax_rate, + name=position.tax_rule.name) + else: + price = get_price(item, variation, voucher=position.voucher, subevent=position.subevent, + invoice_address=self._invoice_address) if price is None: # NOQA raise OrderError(self.error_messages['product_invalid']) diff --git a/src/pretix/control/forms/orders.py b/src/pretix/control/forms/orders.py index 1d1fd9cd60..78b441acd9 100644 --- a/src/pretix/control/forms/orders.py +++ b/src/pretix/control/forms/orders.py @@ -286,6 +286,7 @@ class OrderPositionChangeForm(forms.Form): ('secret', 'Regenerate secret'), ) ) + change_product_keep_price = forms.BooleanField(required=False) def __init__(self, *args, **kwargs): instance = kwargs.pop('instance') diff --git a/src/pretix/control/templates/pretixcontrol/order/change.html b/src/pretix/control/templates/pretixcontrol/order/change.html index 03c0338e69..9958d29c71 100644 --- a/src/pretix/control/templates/pretixcontrol/order/change.html +++ b/src/pretix/control/templates/pretixcontrol/order/change.html @@ -95,6 +95,10 @@ {% trans "Change product to" %} {% bootstrap_field position.form.itemvar layout='inline' %} + {% if request.event.has_subevents %}
diff --git a/src/pretix/control/views/orders.py b/src/pretix/control/views/orders.py index 864bca541d..3a91533d8c 100644 --- a/src/pretix/control/views/orders.py +++ b/src/pretix/control/views/orders.py @@ -1229,7 +1229,7 @@ class OrderChange(OrderView): variation = ItemVariation.objects.get(pk=varid, item=item) else: variation = None - ocm.change_item(p, item, variation) + ocm.change_item(p, item, variation, keep_price=p.form.cleaned_data['change_product_keep_price']) elif p.form.cleaned_data['operation'] == 'price': ocm.change_price(p, p.form.cleaned_data['price']) elif p.form.cleaned_data['operation'] == 'subevent': diff --git a/src/tests/base/test_orders.py b/src/tests/base/test_orders.py index 21dd5d24f4..749ec1c77d 100644 --- a/src/tests/base/test_orders.py +++ b/src/tests/base/test_orders.py @@ -678,6 +678,17 @@ class OrderChangeManagerTests(TestCase): with self.assertRaises(OrderError): self.ocm.change_item(self.op1, self.shirt, None) + def test_change_item_keep_price(self): + p = self.op1.price + tv = self.op1.tax_value + self.ocm.change_item(self.op1, self.shirt, None, keep_price=True) + self.ocm.commit() + self.op1.refresh_from_db() + self.order.refresh_from_db() + assert self.op1.item == self.shirt + assert self.op1.price == p + assert self.op1.tax_value == tv + def test_change_item_success(self): self.ocm.change_item(self.op1, self.shirt, None) self.ocm.commit()