mirror of
https://github.com/pretix/pretix.git
synced 2026-05-05 15:14:04 +00:00
Refactor validation of cart contents, fix purchase of inactive subevent (Z#23217806) (#5715)
* Refactor validation of cart contents, fix purchase of inactive subevent (Z#23217806) * Apply suggestions from code review Co-authored-by: Richard Schreiber <schreiber@pretix.eu> * Review notes --------- Co-authored-by: Richard Schreiber <schreiber@pretix.eu>
This commit is contained in:
@@ -745,6 +745,8 @@ def test_use_membership(event, customer, membership, requiring_ticket):
|
||||
item=requiring_ticket, price=23, expires=now() + timedelta(days=1), event=event, cart_id="123",
|
||||
used_membership=membership
|
||||
)
|
||||
q = event.quotas.create(size=None, name="foo")
|
||||
q.items.add(requiring_ticket)
|
||||
order = _create_order(event, email='dummy@example.org', positions=[cp1],
|
||||
now_dt=now(),
|
||||
sales_channel=event.organizer.sales_channels.get(identifier="web"),
|
||||
@@ -767,6 +769,8 @@ def test_use_membership_invalid(event, customer, membership, requiring_ticket):
|
||||
membership.date_start -= timedelta(days=100)
|
||||
membership.date_end -= timedelta(days=100)
|
||||
membership.save()
|
||||
q = event.quotas.create(size=None, name="foo")
|
||||
q.items.add(requiring_ticket)
|
||||
cp1 = CartPosition.objects.create(
|
||||
item=requiring_ticket, price=23, expires=now() + timedelta(days=1), event=event, cart_id="123",
|
||||
used_membership=membership
|
||||
|
||||
@@ -1428,6 +1428,27 @@ class CartTest(CartTestMixin, TestCase):
|
||||
self.assertEqual(cp2.expires, now() + self.cart_reservation_time)
|
||||
self.assertEqual(cp2.max_extend, now() + 11 * self.cart_reservation_time)
|
||||
|
||||
def test_expired_cart_extend_price_change_note(self):
|
||||
start_time = datetime.datetime(2024, 1, 1, 10, 00, 00, tzinfo=datetime.timezone.utc)
|
||||
max_extend = start_time + 11 * self.cart_reservation_time
|
||||
with scopes_disabled():
|
||||
cp1 = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=23, expires=max_extend, max_extend=max_extend
|
||||
)
|
||||
cp1.update_listed_price_and_voucher()
|
||||
self.ticket.default_price = Decimal("25.00")
|
||||
self.ticket.save()
|
||||
with freezegun.freeze_time(max_extend + timedelta(hours=1)):
|
||||
response = self.client.post('/%s/%s/cart/extend' % (self.orga.slug, self.event.slug), {
|
||||
}, follow=True)
|
||||
doc = BeautifulSoup(response.rendered_content, "lxml")
|
||||
self.assertIn('some of the prices in your cart changed', doc.select('.alert-success')[0].text)
|
||||
with scopes_disabled():
|
||||
cp1.refresh_from_db()
|
||||
self.assertEqual(cp1.price, Decimal("25.00"))
|
||||
self.assertEqual(cp1.expires, now() + self.cart_reservation_time)
|
||||
|
||||
def test_expired_cart_extend_fails_partially_on_bundled(self):
|
||||
start_time = datetime.datetime(2024, 1, 1, 10, 00, 00, tzinfo=datetime.timezone.utc)
|
||||
max_extend = start_time + 11 * self.cart_reservation_time
|
||||
@@ -3408,6 +3429,22 @@ class CartAddonTest(CartTestMixin, TestCase):
|
||||
assert cp2.expires > now()
|
||||
assert cp2.addon_to_id == cp1.pk
|
||||
|
||||
@classscope(attr='orga')
|
||||
def test_expand_expired_price_change(self):
|
||||
cp1 = CartPosition.objects.create(
|
||||
expires=now() - timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time,
|
||||
item=self.ticket, price=Decimal('23.00'),
|
||||
event=self.event, cart_id=self.session_key
|
||||
)
|
||||
self.ticket.default_price = Decimal("25.00")
|
||||
self.ticket.save()
|
||||
self.cm.extend_expired_positions()
|
||||
self.cm.commit()
|
||||
cp1.refresh_from_db()
|
||||
assert cp1.expires > now()
|
||||
assert cp1.listed_price == Decimal("25.00")
|
||||
assert cp1.price == Decimal("25.00")
|
||||
|
||||
@classscope(attr='orga')
|
||||
def test_expand_expired_refresh_voucher(self):
|
||||
v = Voucher.objects.create(item=self.ticket, value=Decimal('20.00'), event=self.event, price_mode='set',
|
||||
@@ -4080,6 +4117,8 @@ class CartBundleTest(CartTestMixin, TestCase):
|
||||
|
||||
@classscope(attr='orga')
|
||||
def test_extend_bundled_and_addon(self):
|
||||
self.trans.require_bundling = False
|
||||
self.trans.save()
|
||||
cp = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=21.5, expires=now() - timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
|
||||
|
||||
@@ -2669,7 +2669,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
with scopes_disabled():
|
||||
se = self.event.subevents.create(name='Foo', date_from=now())
|
||||
se = self.event.subevents.create(name='Foo', date_from=now(), active=True)
|
||||
q = se.quotas.create(name="foo", size=None, event=self.event)
|
||||
q.items.add(self.ticket)
|
||||
cr1 = CartPosition.objects.create(
|
||||
@@ -2839,8 +2839,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
with scopes_disabled():
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
se = self.event.subevents.create(name='Foo', date_from=now())
|
||||
se2 = self.event.subevents.create(name='Foo', date_from=now())
|
||||
se = self.event.subevents.create(name='Foo', date_from=now(), active=True)
|
||||
se2 = self.event.subevents.create(name='Foo', date_from=now(), active=True)
|
||||
self.quota_tickets.size = 0
|
||||
self.quota_tickets.subevent = se2
|
||||
self.quota_tickets.save()
|
||||
@@ -2880,7 +2880,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
with scopes_disabled():
|
||||
se = self.event.subevents.create(name='Foo', date_from=now())
|
||||
se = self.event.subevents.create(name='Foo', date_from=now(), active=True)
|
||||
q = se.quotas.create(name="foo", size=None, event=self.event)
|
||||
q.items.add(self.ticket)
|
||||
SubEventItem.objects.create(subevent=se, item=self.ticket, price=24)
|
||||
@@ -2901,7 +2901,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
with scopes_disabled():
|
||||
se = self.event.subevents.create(name='Foo', date_from=now())
|
||||
se = self.event.subevents.create(name='Foo', date_from=now(), active=True)
|
||||
q = se.quotas.create(name="foo", size=None, event=self.event)
|
||||
q.items.add(self.ticket)
|
||||
SubEventItem.objects.create(subevent=se, item=self.ticket, price=24, disabled=True)
|
||||
@@ -2919,7 +2919,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
with scopes_disabled():
|
||||
se = self.event.subevents.create(name='Foo', date_from=now())
|
||||
se = self.event.subevents.create(name='Foo', date_from=now(), active=True)
|
||||
q = se.quotas.create(name="foo", size=None, event=self.event)
|
||||
q.items.add(self.workshop2)
|
||||
q.variations.add(self.workshop2b)
|
||||
@@ -2938,7 +2938,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
with scopes_disabled():
|
||||
se = self.event.subevents.create(name='Foo', date_from=now())
|
||||
se = self.event.subevents.create(name='Foo', date_from=now(), active=True)
|
||||
q = se.quotas.create(name="foo", size=None, event=self.event)
|
||||
q.items.add(self.ticket)
|
||||
SubEventItem.objects.create(subevent=se, item=self.ticket, price=24, available_until=now() - timedelta(days=1))
|
||||
@@ -2956,7 +2956,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
with scopes_disabled():
|
||||
se = self.event.subevents.create(name='Foo', date_from=now())
|
||||
se = self.event.subevents.create(name='Foo', date_from=now(), active=True)
|
||||
q = se.quotas.create(name="foo", size=None, event=self.event)
|
||||
q.items.add(self.workshop2)
|
||||
q.variations.add(self.workshop2b)
|
||||
@@ -3735,8 +3735,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
with scopes_disabled():
|
||||
se = self.event.subevents.create(name='Foo', date_from=now())
|
||||
se2 = self.event.subevents.create(name='Foo', date_from=now())
|
||||
se = self.event.subevents.create(name='Foo', date_from=now(), active=True)
|
||||
se2 = self.event.subevents.create(name='Foo', date_from=now(), active=True)
|
||||
self.quota_tickets.size = 10
|
||||
self.quota_tickets.subevent = se2
|
||||
self.quota_tickets.save()
|
||||
@@ -4165,7 +4165,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
with scopes_disabled():
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
se = self.event.subevents.create(name='Foo', date_from=now())
|
||||
se = self.event.subevents.create(name='Foo', date_from=now(), active=True)
|
||||
self.workshopquota.size = 1
|
||||
self.workshopquota.subevent = se
|
||||
self.workshopquota.save()
|
||||
@@ -4214,7 +4214,10 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
self.event.has_subevents = True
|
||||
self.event.settings.display_net_prices = True
|
||||
self.event.save()
|
||||
se = self.event.subevents.create(name='Foo', date_from=now(), presale_start=now() + datetime.timedelta(days=1))
|
||||
se = self.event.subevents.create(name='Foo', date_from=now(), presale_start=now() + datetime.timedelta(days=1),
|
||||
active=True)
|
||||
q = se.quotas.create(name="foo", size=None, event=self.event)
|
||||
q.items.add(self.ticket)
|
||||
CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=23, expires=now() + timedelta(minutes=10), subevent=se
|
||||
@@ -4224,7 +4227,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
response = self.client.post('/%s/%s/checkout/confirm/' % (self.orga.slug, self.event.slug), follow=True)
|
||||
doc = BeautifulSoup(response.content.decode(), "lxml")
|
||||
self.assertGreaterEqual(len(doc.select(".alert-danger")), 1)
|
||||
assert 'booking period for one of the events in your cart has not yet started.' in response.content.decode()
|
||||
assert 'booking period for this event has not yet started.' in response.content.decode()
|
||||
with scopes_disabled():
|
||||
assert not CartPosition.objects.filter(cart_id=self.session_key).exists()
|
||||
|
||||
@@ -4233,7 +4236,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
self.event.has_subevents = True
|
||||
self.event.settings.display_net_prices = True
|
||||
self.event.save()
|
||||
se = self.event.subevents.create(name='Foo', date_from=now(), presale_end=now() - datetime.timedelta(days=1))
|
||||
se = self.event.subevents.create(name='Foo', date_from=now(), presale_end=now() - datetime.timedelta(days=1), active=True)
|
||||
CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=23, expires=now() + timedelta(minutes=10), subevent=se
|
||||
@@ -4243,7 +4246,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
response = self.client.post('/%s/%s/checkout/confirm/' % (self.orga.slug, self.event.slug), follow=True)
|
||||
doc = BeautifulSoup(response.content.decode(), "lxml")
|
||||
self.assertGreaterEqual(len(doc.select(".alert-danger")), 1)
|
||||
assert 'booking period for one of the events in your cart has ended.' in response.content.decode()
|
||||
assert 'The booking period for this event has ended.' in response.content.decode()
|
||||
with scopes_disabled():
|
||||
assert not CartPosition.objects.filter(cart_id=self.session_key).exists()
|
||||
|
||||
@@ -4253,7 +4256,9 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
self.event.settings.display_net_prices = True
|
||||
self.event.save()
|
||||
self.event.settings.payment_term_last = 'RELDATE/1/23:59:59/date_from/'
|
||||
se = self.event.subevents.create(name='Foo', date_from=now())
|
||||
se = self.event.subevents.create(name='Foo', date_from=now(), active=True)
|
||||
q = se.quotas.create(name="foo", size=None, event=self.event)
|
||||
q.items.add(self.ticket)
|
||||
CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=23, expires=now() + timedelta(minutes=10), subevent=se
|
||||
@@ -4263,7 +4268,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
response = self.client.post('/%s/%s/checkout/confirm/' % (self.orga.slug, self.event.slug), follow=True)
|
||||
doc = BeautifulSoup(response.content.decode(), "lxml")
|
||||
self.assertGreaterEqual(len(doc.select(".alert-danger")), 1)
|
||||
assert 'booking period for one of the events in your cart has ended.' in response.content.decode()
|
||||
assert 'All payments for this event need to be confirmed already, so no new orders can be created.' in response.content.decode()
|
||||
with scopes_disabled():
|
||||
assert not CartPosition.objects.filter(cart_id=self.session_key).exists()
|
||||
|
||||
@@ -4272,7 +4277,10 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
self.event.date_to = now() - datetime.timedelta(days=1)
|
||||
self.event.save()
|
||||
with scopes_disabled():
|
||||
se = self.event.subevents.create(name='Foo', date_from=now(), presale_end=now() + datetime.timedelta(days=1))
|
||||
se = self.event.subevents.create(name='Foo', date_from=now(), presale_end=now() + datetime.timedelta(days=1),
|
||||
active=True)
|
||||
q = se.quotas.create(name="foo", size=None, event=self.event)
|
||||
q.items.add(self.ticket)
|
||||
CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=23, expires=now() + timedelta(minutes=10), subevent=se
|
||||
@@ -4283,6 +4291,25 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
doc = BeautifulSoup(response.content.decode(), "lxml")
|
||||
self.assertEqual(len(doc.select(".thank-you")), 1)
|
||||
|
||||
def test_confirm_subevent_disabled(self):
|
||||
with scopes_disabled():
|
||||
self.event.has_subevents = True
|
||||
self.event.settings.display_net_prices = True
|
||||
self.event.save()
|
||||
se = self.event.subevents.create(name='Foo', date_from=now(), active=False)
|
||||
CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=23, expires=now() + timedelta(minutes=10), subevent=se
|
||||
)
|
||||
|
||||
self._set_payment()
|
||||
response = self.client.post('/%s/%s/checkout/confirm/' % (self.orga.slug, self.event.slug), follow=True)
|
||||
doc = BeautifulSoup(response.content.decode(), "lxml")
|
||||
self.assertGreaterEqual(len(doc.select(".alert-danger")), 1)
|
||||
assert 'selected event date is not active.' in response.content.decode()
|
||||
with scopes_disabled():
|
||||
assert not CartPosition.objects.filter(cart_id=self.session_key).exists()
|
||||
|
||||
def test_before_presale_timemachine(self):
|
||||
self._login_with_permission(self.orga)
|
||||
self._enable_test_mode()
|
||||
@@ -4497,6 +4524,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
self.assertEqual(Order.objects.first().locale, 'de')
|
||||
|
||||
def test_variation_require_approval(self):
|
||||
self.workshop2.category = None
|
||||
self.workshop2.save()
|
||||
self.workshop2a.require_approval = True
|
||||
self.workshop2a.save()
|
||||
with scopes_disabled():
|
||||
@@ -4518,6 +4547,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
||||
|
||||
def test_item_with_variations_require_approval(self):
|
||||
self.workshop2.require_approval = True
|
||||
self.workshop2.category = None
|
||||
self.workshop2.save()
|
||||
with scopes_disabled():
|
||||
cr1 = CartPosition.objects.create(
|
||||
|
||||
Reference in New Issue
Block a user