diff --git a/src/pretix/base/services/orders.py b/src/pretix/base/services/orders.py index b48eec48d1..2e08f9316c 100644 --- a/src/pretix/base/services/orders.py +++ b/src/pretix/base/services/orders.py @@ -3152,7 +3152,7 @@ def signal_listener_issue_memberships(sender: Event, order: Order, **kwargs): if order.status != Order.STATUS_PAID or not order.customer: return for p in order.positions.all(): - if p.item.grant_membership_type_id: + if p.item.grant_membership_type_id and not p.granted_memberships.exists(): create_membership(order.customer, p) diff --git a/src/pretix/control/templates/pretixcontrol/order/change.html b/src/pretix/control/templates/pretixcontrol/order/change.html index 2d66c13b0c..92aa9bece7 100644 --- a/src/pretix/control/templates/pretixcontrol/order/change.html +++ b/src/pretix/control/templates/pretixcontrol/order/change.html @@ -151,6 +151,12 @@
{% bootstrap_field position.form.itemvar layout='inline' %} + {% if position.granted_memberships.all %} + + + {% trans "The sale of this position created a membership. Changing the product here will not affect the membership. Memberships can be managed in the customer account." %} + + {% endif %}
@@ -254,6 +260,12 @@ {% trans "–" %} {% bootstrap_field position.form.valid_until layout='inline' %} + {% if position.granted_memberships.all %} + + + {% trans "The sale of this position created a membership. Changing the validity of the ticket here will not affect the membership. Memberships can be managed in the customer account." %} + + {% endif %} diff --git a/src/pretix/control/views/orders.py b/src/pretix/control/views/orders.py index f5d13b13f2..e86fafc417 100644 --- a/src/pretix/control/views/orders.py +++ b/src/pretix/control/views/orders.py @@ -1900,7 +1900,7 @@ class OrderChange(OrderView): positions = list(self.order.positions.select_related( 'item', 'item__tax_rule', 'used_membership', 'used_membership__membership_type', 'tax_rule', 'seat', 'subevent', - )) + ).prefetch_related('granted_memberships')) for p in positions: p.form = OrderPositionChangeForm(prefix='op-{}'.format(p.pk), instance=p, items=self.items, initial={'seat': p.seat.seat_guid if p.seat else None}, diff --git a/src/tests/base/test_orders.py b/src/tests/base/test_orders.py index ad474182bd..fe1edf0e29 100644 --- a/src/tests/base/test_orders.py +++ b/src/tests/base/test_orders.py @@ -1662,7 +1662,7 @@ class OrderChangeManagerTests(TestCase): mt = self.event.organizer.membership_types.create(name="foo") customer = self.event.organizer.customers.create() self.order.customer = customer - self.o.save() + self.order.save() m = customer.memberships.create( membership_type=mt, date_start=now(), @@ -1674,6 +1674,37 @@ class OrderChangeManagerTests(TestCase): m.refresh_from_db() assert m.canceled + @classscope(attr='o') + def test_create_membership_after_change(self): + mt = self.event.organizer.membership_types.create(name="foo") + customer = self.event.organizer.customers.create() + self.ticket.grant_membership_type = mt + self.ticket.save() + self.ticket2.grant_membership_type = mt + self.ticket2.save() + self.order.customer = customer + self.order.status = Order.STATUS_PAID + self.order.save() + assert customer.memberships.count() == 0 + self.ocm.change_item(self.op1, item=self.ticket2, variation=None) + self.ocm.cancel(self.op2) + self.ocm.commit() + + self.order.refresh_from_db() + self.op1.refresh_from_db() + customer.refresh_from_db() + assert self.op1.granted_memberships.count() == 1 + assert customer.memberships.count() == 1 + + # But only once + self.ocm = OrderChangeManager(self.order, None) + self.ocm.change_item(self.op1, item=self.ticket, variation=None) + self.ocm.commit() + + customer.refresh_from_db() + assert self.op1.granted_memberships.count() == 1 + assert customer.memberships.count() == 1 + @classscope(attr='o') def test_cancel_issued_giftcard_used(self): gc = self.o.issued_gift_cards.create(currency="EUR", issued_in=self.op1)