diff --git a/src/pretix/base/migrations/0280_cartposition_max_extend.py b/src/pretix/base/migrations/0280_cartposition_max_extend.py
new file mode 100644
index 000000000..16024151f
--- /dev/null
+++ b/src/pretix/base/migrations/0280_cartposition_max_extend.py
@@ -0,0 +1,18 @@
+# Generated by Django 4.2.20 on 2025-05-14 14:58
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('pretixbase', '0279_discount_event_date_from_discount_event_date_until'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='cartposition',
+ name='max_extend',
+ field=models.DateTimeField(null=True),
+ ),
+ ]
diff --git a/src/pretix/base/models/orders.py b/src/pretix/base/models/orders.py
index 7ac8beff1..9db278422 100644
--- a/src/pretix/base/models/orders.py
+++ b/src/pretix/base/models/orders.py
@@ -3098,7 +3098,10 @@ class CartPosition(AbstractPosition):
verbose_name=_("Expiration date"),
db_index=True
)
-
+ max_extend = models.DateTimeField(
+ verbose_name=_("Limit for extending expiration date"),
+ null=True
+ )
tax_rate = models.DecimalField(
max_digits=7, decimal_places=2, default=Decimal('0.00'),
verbose_name=_('Tax rate')
diff --git a/src/pretix/base/services/cart.py b/src/pretix/base/services/cart.py
index d3e359013..14099b8c1 100644
--- a/src/pretix/base/services/cart.py
+++ b/src/pretix/base/services/cart.py
@@ -45,6 +45,7 @@ from django.conf import settings
from django.core.exceptions import ValidationError
from django.db import DatabaseError, transaction
from django.db.models import Count, Exists, IntegerField, OuterRef, Q, Value
+from django.db.models.aggregates import Min
from django.dispatch import receiver
from django.utils.timezone import make_aware, now
from django.utils.translation import (
@@ -275,7 +276,10 @@ class CartManager:
}
def __init__(self, event: Event, cart_id: str, sales_channel: SalesChannel,
- invoice_address: InvoiceAddress=None, widget_data=None, expiry=None):
+ invoice_address: InvoiceAddress=None, widget_data=None, reservation_time: timedelta=None):
+ """
+ Creates a new CartManager for an event.
+ """
self.event = event
self.cart_id = cart_id
self.real_now_dt = now()
@@ -286,11 +290,17 @@ class CartManager:
self._subevents_cache = {}
self._variations_cache = {}
self._seated_cache = {}
- self._expiry = None
- self._explicit_expiry = expiry
self.invoice_address = invoice_address
self._widget_data = widget_data or {}
self._sales_channel = sales_channel
+ self.num_extended_positions = 0
+
+ if reservation_time:
+ self._reservation_time = reservation_time
+ else:
+ self._reservation_time = timedelta(minutes=self.event.settings.get('reservation_time', as_type=int))
+ self._expiry = self.real_now_dt + self._reservation_time
+ self._max_expiry_extend = self.real_now_dt + (self._reservation_time * 11)
@property
def positions(self):
@@ -305,14 +315,6 @@ class CartManager:
self._seated_cache[item, subevent] = item.seat_category_mappings.filter(subevent=subevent).exists()
return self._seated_cache[item, subevent]
- def _calculate_expiry(self):
- if self._explicit_expiry:
- self._expiry = self._explicit_expiry
- else:
- self._expiry = self.real_now_dt + timedelta(
- minutes=self.event.settings.get('reservation_time', as_type=int)
- )
-
def _check_presale_dates(self):
if self.event.presale_start and time_machine_now(self.real_now_dt) < self.event.presale_start:
raise CartError(error_messages['not_started'])
@@ -329,9 +331,27 @@ class CartManager:
raise CartError(error_messages['payment_ended'])
def _extend_expiry_of_valid_existing_positions(self):
+ # real_now_dt is initialized at CartManager instantiation, so it's slightly in the past. Add a small
+ # delta to reduce risk of extending already expired CartPositions.
+ padded_now_dt = self.real_now_dt + timedelta(seconds=5)
+
+ # Make sure we do not extend past the max_extend timestamp, allowing users to extend their valid positions up
+ # to 11 times the reservation time. If we add new positions to the cart while valid positions exist, the new
+ # positions' reservation will also be limited to max_extend of the oldest position.
+ # Only after all positions expire, an ExtendOperation may reset max_extend to another 11x reservation_time.
+ max_extend_existing = self.positions.filter(expires__gt=padded_now_dt).aggregate(m=Min('max_extend'))['m']
+ if max_extend_existing:
+ self._expiry = min(self._expiry, max_extend_existing)
+ self._max_expiry_extend = max_extend_existing
+
# Extend this user's cart session to ensure all items in the cart expire at the same time
# We can extend the reservation of items which are not yet expired without risk
- self.positions.filter(expires__gt=self.real_now_dt).update(expires=self._expiry)
+ if self._expiry > padded_now_dt:
+ self.num_extended_positions += self.positions.filter(
+ expires__gt=padded_now_dt, expires__lt=self._expiry,
+ ).update(
+ expires=self._expiry,
+ )
def _delete_out_of_timeframe(self):
err = None
@@ -1246,6 +1266,7 @@ class CartManager:
item=op.item,
variation=op.variation,
expires=self._expiry,
+ max_extend=self._max_expiry_extend,
cart_id=self.cart_id,
voucher=op.voucher,
addon_to=op.addon_to if op.addon_to else None,
@@ -1294,7 +1315,9 @@ class CartManager:
event=self.event,
item=b.item,
variation=b.variation,
- expires=self._expiry, cart_id=self.cart_id,
+ expires=self._expiry,
+ max_extend=self._max_expiry_extend,
+ cart_id=self.cart_id,
voucher=None,
addon_to=cp,
subevent=b.subevent,
@@ -1321,12 +1344,14 @@ class CartManager:
op.position.delete()
elif available_count == 1:
op.position.expires = self._expiry
+ op.position.max_extend = self._max_expiry_extend
op.position.listed_price = op.listed_price
op.position.price_after_voucher = op.price_after_voucher
# op.position.price will be updated by recompute_final_prices_and_taxes()
if op.position.pk not in deleted_positions:
try:
- op.position.save(force_update=True, update_fields=['expires', 'listed_price', 'price_after_voucher'])
+ op.position.save(force_update=True, update_fields=['expires', 'max_extend', 'listed_price', 'price_after_voucher'])
+ self.num_extended_positions += 1
except DatabaseError:
# Best effort... The position might have been deleted in the meantime!
pass
@@ -1416,14 +1441,11 @@ class CartManager:
def commit(self):
self._check_presale_dates()
self._check_max_cart_size()
- self._calculate_expiry()
err = self._delete_out_of_timeframe()
err = self.extend_expired_positions() or err
err = err or self._check_min_per_voucher()
- self.real_now_dt = now()
-
self._extend_expiry_of_valid_existing_positions()
err = self._perform_operations() or err
self.recompute_final_prices_and_taxes()
@@ -1632,6 +1654,31 @@ def clear_cart(self, event: Event, cart_id: str=None, locale='en', sales_channel
raise CartError(error_messages['busy'])
+@app.task(base=ProfiledEventTask, bind=True, max_retries=5, default_retry_delay=1, throws=(CartError,))
+def extend_cart_reservation(self, event: Event, cart_id: str=None, locale='en', sales_channel='web', override_now_dt: datetime=None) -> None:
+ """
+ Resets the expiry time of a cart to the configured reservation time of this event.
+ Limited to 11x the reservation time.
+
+ :param event: The event ID in question
+ :param cart_id: The cart ID of the cart to modify
+ """
+ with language(locale), time_machine_now_assigned(override_now_dt):
+ try:
+ sales_channel = event.organizer.sales_channels.get(identifier=sales_channel)
+ except SalesChannel.DoesNotExist:
+ raise CartError("Invalid sales channel.")
+ try:
+ try:
+ cm = CartManager(event=event, cart_id=cart_id, sales_channel=sales_channel)
+ cm.commit()
+ return cm.num_extended_positions
+ except LockTimeoutException:
+ self.retry()
+ except (MaxRetriesExceededError, LockTimeoutException):
+ raise CartError(error_messages['busy'])
+
+
@app.task(base=ProfiledEventTask, bind=True, max_retries=5, default_retry_delay=1, throws=(CartError,))
def set_cart_addons(self, event: Event, addons: List[dict], add_to_cart_items: List[dict], cart_id: str=None, locale='en',
invoice_address: int=None, sales_channel='web', override_now_dt: datetime=None) -> None:
diff --git a/src/pretix/presale/templates/pretixpresale/event/fragment_cart.html b/src/pretix/presale/templates/pretixpresale/event/fragment_cart.html
index c9dd89050..02cacd02c 100644
--- a/src/pretix/presale/templates/pretixpresale/event/fragment_cart.html
+++ b/src/pretix/presale/templates/pretixpresale/event/fragment_cart.html
@@ -492,15 +492,21 @@
{% if not cart.is_ordered %}
-
- {% if cart.minutes_left > 0 or cart.seconds_left > 0 %}
- {% blocktrans trimmed with minutes=cart.minutes_left %}
- The items in your cart are reserved for you for {{ minutes }} minutes.
- {% endblocktrans %}
- {% else %}
- {% trans "The items in your cart are no longer reserved for you. You can still complete your order as long as they’re available." %}
- {% endif %}
-
+
{% else %}
{% trans "Overview of your ordered products." %}
{% endif %}
diff --git a/src/pretix/presale/urls.py b/src/pretix/presale/urls.py
index 10e8a2f84..e47f5a84e 100644
--- a/src/pretix/presale/urls.py
+++ b/src/pretix/presale/urls.py
@@ -56,6 +56,7 @@ frame_wrapped_urls = [
re_path(r'^cart/remove$', pretix.presale.views.cart.CartRemove.as_view(), name='event.cart.remove'),
re_path(r'^cart/voucher$', pretix.presale.views.cart.CartApplyVoucher.as_view(), name='event.cart.voucher'),
re_path(r'^cart/clear$', pretix.presale.views.cart.CartClear.as_view(), name='event.cart.clear'),
+ re_path(r'^cart/extend$', pretix.presale.views.cart.CartExtendReservation.as_view(), name='event.cart.extend'),
re_path(r'^cart/answer/(?P
[^/]+)/$',
pretix.presale.views.cart.AnswerDownload.as_view(),
name='event.cart.download.answer'),
diff --git a/src/pretix/presale/views/cart.py b/src/pretix/presale/views/cart.py
index a823e6674..f99eac043 100644
--- a/src/pretix/presale/views/cart.py
+++ b/src/pretix/presale/views/cart.py
@@ -62,7 +62,7 @@ from pretix.base.models import (
)
from pretix.base.services.cart import (
CartError, add_items_to_cart, apply_voucher, clear_cart, error_messages,
- remove_cart_position,
+ extend_cart_reservation, remove_cart_position,
)
from pretix.base.timemachine import time_machine_now
from pretix.base.views.tasks import AsyncAction
@@ -537,6 +537,20 @@ class CartClear(EventViewMixin, CartActionMixin, AsyncAction, View):
request.sales_channel.identifier, time_machine_now(default=None))
+@method_decorator(allow_frame_if_namespaced, 'dispatch')
+class CartExtendReservation(EventViewMixin, CartActionMixin, AsyncAction, View):
+ task = extend_cart_reservation
+ known_errortypes = ['CartError']
+
+ def get_success_message(self, value):
+ if value > 0:
+ return _('Your cart timeout was extended.')
+
+ def post(self, request, *args, **kwargs):
+ return self.do(self.request.event.id, get_or_create_cart_id(self.request), translation.get_language(),
+ request.sales_channel.identifier, time_machine_now(default=None))
+
+
@method_decorator(allow_cors_if_namespaced, 'dispatch')
@method_decorator(allow_frame_if_namespaced, 'dispatch')
@method_decorator(iframe_entry_view_wrapper, 'dispatch')
diff --git a/src/pretix/static/pretixpresale/js/ui/cart.js b/src/pretix/static/pretixpresale/js/ui/cart.js
index 98a192558..bdb4b14c5 100644
--- a/src/pretix/static/pretixpresale/js/ui/cart.js
+++ b/src/pretix/static/pretixpresale/js/ui/cart.js
@@ -55,6 +55,7 @@ var cart = {
pad(diff_minutes.toString(), 2) + ':' + pad(diff_seconds.toString(), 2)
);
}
+ $("#cart-extend-button").toggle(diff_minutes < 3);
},
init: function () {
diff --git a/src/tests/presale/test_cart.py b/src/tests/presale/test_cart.py
index d1d7a901f..da78c4628 100644
--- a/src/tests/presale/test_cart.py
+++ b/src/tests/presale/test_cart.py
@@ -37,6 +37,7 @@ import json
from datetime import timedelta
from decimal import Decimal
+import freezegun
from bs4 import BeautifulSoup
from django.conf import settings
from django.test import TestCase
@@ -96,6 +97,8 @@ class CartTestMixin:
self.client.get('/%s/%s/' % (self.orga.slug, self.event.slug))
self.session_key = get_cart_session_key(self.client, self.event)
+ self.event.settings.set('reservation_time', 30)
+ self.cart_reservation_time = timedelta(minutes=self.event.settings.get('reservation_time', as_type=int))
class CartTest(CartTestMixin, TestCase):
@@ -989,7 +992,7 @@ class CartTest(CartTestMixin, TestCase):
with scopes_disabled():
CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
- price=23, expires=now() + timedelta(minutes=10)
+ price=23, expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
self.event.settings.max_items_per_order = 5
response = self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
@@ -1006,7 +1009,7 @@ class CartTest(CartTestMixin, TestCase):
with scopes_disabled():
CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
- price=23, expires=now() + timedelta(minutes=10)
+ price=23, expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
self.event.settings.max_items_per_order = settings.PRETIX_MAX_ORDER_SIZE + 100
response = self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
@@ -1023,7 +1026,7 @@ class CartTest(CartTestMixin, TestCase):
with scopes_disabled():
CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
- price=23, expires=now() + timedelta(minutes=10)
+ price=23, expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
self.event.settings.max_items_per_order = 5
response = self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
@@ -1084,7 +1087,7 @@ class CartTest(CartTestMixin, TestCase):
with scopes_disabled():
CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
- price=23, expires=now() + timedelta(minutes=10)
+ price=23, expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
response = self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
'item_%d' % self.ticket.id: '2',
@@ -1102,7 +1105,7 @@ class CartTest(CartTestMixin, TestCase):
with scopes_disabled():
CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
- price=23, expires=now() + timedelta(minutes=10)
+ price=23, expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
response = self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
'item_%d' % self.ticket.id: '2',
@@ -1225,22 +1228,102 @@ class CartTest(CartTestMixin, TestCase):
self.assertEqual(objs[0].price, 23)
def test_renew_in_time(self):
+ start_time = now() - timedelta(minutes=20)
+ expires = start_time + self.cart_reservation_time
+ max_extend = start_time + 11 * self.cart_reservation_time
with scopes_disabled():
cp = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
- price=23, expires=now() + timedelta(minutes=10)
+ price=23, expires=expires, max_extend=max_extend
)
self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
'variation_%d_%d' % (self.shirt.id, self.shirt_red.id): '1'
}, follow=True)
cp.refresh_from_db()
self.assertGreater(cp.expires, now() + timedelta(minutes=10))
+ self.assertEqual(cp.max_extend, max_extend)
+
+ def test_autorenew_with_max_extend(self):
+ start_time = datetime.datetime(2024, 1, 1, 10, 00, 00, tzinfo=datetime.timezone.utc)
+ with freezegun.freeze_time(start_time):
+ expires = start_time + self.cart_reservation_time
+ max_extend = start_time + 2 * self.cart_reservation_time
+ with scopes_disabled():
+ cp = CartPosition.objects.create(
+ event=self.event, cart_id=self.session_key, item=self.ticket,
+ price=23, expires=expires, max_extend=max_extend
+ )
+ with freezegun.freeze_time(start_time + timedelta(minutes=20)):
+ self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
+ 'item_%d' % (self.ticket.id,): '1'
+ }, follow=True)
+ cp.refresh_from_db()
+ with scopes_disabled():
+ positions = list(CartPosition.objects.filter(cart_id=cp.cart_id))
+ self.assertEqual(len(positions), 2)
+ for pos in positions:
+ self.assertEqual(pos.expires, start_time + timedelta(minutes=20) + self.cart_reservation_time)
+ self.assertEqual(pos.max_extend, max_extend)
+ with freezegun.freeze_time(start_time + timedelta(minutes=45)):
+ self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
+ 'item_%d' % (self.ticket.id,): '1'
+ }, follow=True)
+ cp.refresh_from_db()
+ with scopes_disabled():
+ positions = list(CartPosition.objects.filter(cart_id=cp.cart_id))
+ self.assertEqual(len(positions), 3)
+ for pos in positions:
+ self.assertEqual(pos.expires, max_extend)
+ self.assertEqual(pos.max_extend, max_extend)
+ with freezegun.freeze_time(start_time + timedelta(days=1)):
+ self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
+ 'item_%d' % (self.ticket.id,): '1'
+ }, follow=True)
+ cp.refresh_from_db()
+ with scopes_disabled():
+ positions = list(CartPosition.objects.filter(cart_id=cp.cart_id))
+ self.assertEqual(len(positions), 4)
+ for pos in positions:
+ self.assertEqual(pos.expires, start_time + timedelta(days=1) + self.cart_reservation_time)
+ self.assertEqual(pos.max_extend, start_time + timedelta(days=1) + 11 * self.cart_reservation_time)
+
+ def test_extend_with_max_extend(self):
+ start_time = datetime.datetime(2024, 1, 1, 10, 00, 00, tzinfo=datetime.timezone.utc)
+ with freezegun.freeze_time(start_time):
+ expires = start_time + self.cart_reservation_time
+ max_extend = start_time + 2 * self.cart_reservation_time
+ with scopes_disabled():
+ cp = CartPosition.objects.create(
+ event=self.event, cart_id=self.session_key, item=self.ticket,
+ price=23, expires=expires, max_extend=max_extend
+ )
+ with freezegun.freeze_time(start_time + timedelta(minutes=20)):
+ self.client.post('/%s/%s/cart/extend' % (self.orga.slug, self.event.slug), {
+ }, follow=True)
+ cp.refresh_from_db()
+ self.assertEqual(cp.expires, start_time + timedelta(minutes=20) + self.cart_reservation_time)
+ self.assertEqual(cp.max_extend, max_extend)
+ with freezegun.freeze_time(start_time + timedelta(minutes=45)):
+ self.client.post('/%s/%s/cart/extend' % (self.orga.slug, self.event.slug), {
+ }, follow=True)
+ cp.refresh_from_db()
+ self.assertEqual(cp.expires, max_extend)
+ self.assertEqual(cp.max_extend, max_extend)
+ with freezegun.freeze_time(start_time + timedelta(minutes=65)):
+ self.client.post('/%s/%s/cart/extend' % (self.orga.slug, self.event.slug), {
+ }, follow=True)
+ cp.refresh_from_db()
+ self.assertEqual(cp.expires, start_time + timedelta(minutes=65) + self.cart_reservation_time)
+ self.assertEqual(cp.max_extend, start_time + timedelta(minutes=65) + 11 * self.cart_reservation_time)
def test_renew_expired_successfully(self):
+ start_time = now() - timedelta(minutes=40)
+ expires = start_time + self.cart_reservation_time
+ 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=now() - timedelta(minutes=10)
+ price=23, expires=expires, max_extend=max_extend
)
self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
'variation_%d_%d' % (self.shirt.id, self.shirt_red.id): '1'
@@ -1250,13 +1333,14 @@ class CartTest(CartTestMixin, TestCase):
self.assertEqual(obj.item, self.ticket)
self.assertIsNone(obj.variation)
self.assertEqual(obj.price, 23)
- self.assertGreater(obj.expires, now())
+ self.assertGreater(obj.expires, now() + timedelta(minutes=10))
+ self.assertGreater(obj.max_extend, now() + 11 * self.cart_reservation_time - timedelta(minutes=10))
def test_renew_questions(self):
with scopes_disabled():
cr1 = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
- price=23, expires=now() - timedelta(minutes=10)
+ price=23, expires=now() - timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
q1 = Question.objects.create(
event=self.event, question='Age', type=Question.TYPE_NUMBER,
@@ -1279,7 +1363,7 @@ class CartTest(CartTestMixin, TestCase):
with scopes_disabled():
cp1 = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
- price=23, expires=now() - timedelta(minutes=10)
+ price=23, expires=now() - timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
response = self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
'item_%d' % self.ticket.id: '1',
@@ -1289,6 +1373,61 @@ class CartTest(CartTestMixin, TestCase):
with scopes_disabled():
self.assertFalse(CartPosition.objects.filter(id=cp1.id).exists())
+ def test_expired_renew_fails_partially_and_add_succeeds(self):
+ start_time = datetime.datetime(2024, 1, 1, 10, 00, 00, tzinfo=datetime.timezone.utc)
+ expires = start_time + self.cart_reservation_time
+ max_extend = start_time + 11 * self.cart_reservation_time
+ self.quota_tickets.size = 0
+ self.quota_tickets.save()
+ with scopes_disabled():
+ cp1 = CartPosition.objects.create(
+ event=self.event, cart_id=self.session_key, item=self.ticket,
+ price=23, expires=expires, max_extend=max_extend
+ )
+ cp2 = CartPosition.objects.create(
+ event=self.event, cart_id=self.session_key, item=self.shirt, variation=self.shirt_blue,
+ price=23, expires=expires, max_extend=max_extend
+ )
+ with freezegun.freeze_time(max_extend + timedelta(hours=1)):
+ response = self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
+ 'variation_%d_%d' % (self.shirt.id, self.shirt_red.id): '1',
+ }, follow=True)
+ doc = BeautifulSoup(response.rendered_content, "lxml")
+ self.assertIn('no longer available', doc.select('.alert-danger')[0].text)
+ with scopes_disabled():
+ self.assertFalse(CartPosition.objects.filter(id=cp1.id).exists())
+ cp2.refresh_from_db()
+ self.assertEqual(cp2.expires, now() + self.cart_reservation_time)
+ self.assertEqual(cp2.max_extend, now() + 11 * self.cart_reservation_time)
+ cp3 = CartPosition.objects.get(variation_id=self.shirt_red.id)
+ self.assertEqual(cp3.expires, now() + self.cart_reservation_time)
+ self.assertEqual(cp3.max_extend, now() + 11 * self.cart_reservation_time)
+
+ def test_expired_cart_extend_fails_partially(self):
+ start_time = datetime.datetime(2024, 1, 1, 10, 00, 00, tzinfo=datetime.timezone.utc)
+ max_extend = start_time + 11 * self.cart_reservation_time
+ self.quota_tickets.size = 0
+ self.quota_tickets.save()
+ 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
+ )
+ cp2 = CartPosition.objects.create(
+ event=self.event, cart_id=self.session_key, item=self.shirt, variation=self.shirt_blue,
+ price=23, expires=max_extend, max_extend=max_extend
+ )
+ 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('no longer available', doc.select('.alert-danger')[0].text)
+ with scopes_disabled():
+ self.assertFalse(CartPosition.objects.filter(id=cp1.id).exists())
+ cp2.refresh_from_db()
+ self.assertEqual(cp2.expires, now() + self.cart_reservation_time)
+ self.assertEqual(cp2.max_extend, now() + 11 * self.cart_reservation_time)
+
def test_subevent_renew_expired_successfully(self):
self.event.has_subevents = True
self.event.save()
@@ -1300,7 +1439,9 @@ class CartTest(CartTestMixin, TestCase):
self.quota_shirts.save()
cp1 = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
- price=23, expires=now() - timedelta(minutes=10), subevent=se
+ price=23,
+ expires=now() - timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time,
+ subevent=se
)
self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
'variation_%d_%d' % (self.shirt.id, self.shirt_red.id): '1',
@@ -1324,7 +1465,9 @@ class CartTest(CartTestMixin, TestCase):
self.quota_tickets.save()
cp1 = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
- price=23, expires=now() - timedelta(minutes=10), subevent=se
+ price=23,
+ expires=now() - timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time,
+ subevent=se
)
response = self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
'item_%d' % self.ticket.id: '1',
@@ -1339,7 +1482,7 @@ class CartTest(CartTestMixin, TestCase):
with scopes_disabled():
cp = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
- price=23, expires=now() + timedelta(minutes=10)
+ price=23, expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
response = self.client.post('/%s/%s/cart/remove' % (self.orga.slug, self.event.slug), {
'id': cp.pk
@@ -1355,15 +1498,15 @@ class CartTest(CartTestMixin, TestCase):
redeemed=1, min_usages=3, max_usages=10)
CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket, voucher=v,
- price=23, expires=now() + timedelta(minutes=10)
+ price=23, expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
cp2 = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket, voucher=v,
- price=23, expires=now() + timedelta(minutes=10)
+ price=23, expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
cp3 = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket, voucher=v,
- price=23, expires=now() + timedelta(minutes=10)
+ price=23, expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
self.client.post('/%s/%s/cart/remove' % (self.orga.slug, self.event.slug), {
'id': cp3.pk
@@ -1384,11 +1527,11 @@ class CartTest(CartTestMixin, TestCase):
with scopes_disabled():
CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
- price=23, expires=now() + timedelta(minutes=10)
+ price=23, expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
cp = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
- price=23, expires=now() + timedelta(minutes=10)
+ price=23, expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
response = self.client.post('/%s/%s/cart/remove' % (self.orga.slug, self.event.slug), {
'id': cp.pk
@@ -1402,7 +1545,7 @@ class CartTest(CartTestMixin, TestCase):
with scopes_disabled():
cp = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.shirt, variation=self.shirt_red,
- price=14, expires=now() + timedelta(minutes=10)
+ price=14, expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
response = self.client.post('/%s/%s/cart/remove' % (self.orga.slug, self.event.slug), {
'id': cp.pk
@@ -1416,7 +1559,7 @@ class CartTest(CartTestMixin, TestCase):
with scopes_disabled():
cp = CartPosition.objects.create(
event=self.event, cart_id='invalid', item=self.shirt, variation=self.shirt_red,
- price=14, expires=now() + timedelta(minutes=10)
+ price=14, expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
response = self.client.post('/%s/%s/cart/remove' % (self.orga.slug, self.event.slug), {
'id': cp.pk
@@ -1428,11 +1571,11 @@ class CartTest(CartTestMixin, TestCase):
with scopes_disabled():
cp = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
- price=23, expires=now() + timedelta(minutes=10)
+ price=23, expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
- price=23, expires=now() + timedelta(minutes=10)
+ price=23, expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
response = self.client.post('/%s/%s/cart/remove' % (self.orga.slug, self.event.slug), {
'id': cp.pk
@@ -1446,15 +1589,15 @@ class CartTest(CartTestMixin, TestCase):
with scopes_disabled():
CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
- price=23, expires=now() + timedelta(minutes=10)
+ price=23, expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
- price=23, expires=now() + timedelta(minutes=10)
+ price=23, expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.shirt, variation=self.shirt_red,
- price=14, expires=now() + timedelta(minutes=10)
+ price=14, expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
response = self.client.post('/%s/%s/cart/clear' % (self.orga.slug, self.event.slug), {}, follow=True)
doc = BeautifulSoup(response.rendered_content, "lxml")
@@ -1467,7 +1610,8 @@ class CartTest(CartTestMixin, TestCase):
v = Voucher.objects.create(item=self.ticket, event=self.event, valid_until=now() - timedelta(days=1))
cp = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
- price=23, expires=now() - timedelta(minutes=10), voucher=v
+ price=23, expires=now() - timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time,
+ voucher=v
)
self.client.post('/%s/%s/cart/remove' % (self.orga.slug, self.event.slug), {
'id': cp.pk
@@ -1495,7 +1639,8 @@ class CartTest(CartTestMixin, TestCase):
v = Voucher.objects.create(item=self.ticket, event=self.event, block_quota=True)
cp1 = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
- price=23, expires=now() - timedelta(minutes=10), voucher=v
+ price=23, expires=now() - timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time,
+ voucher=v
)
self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
'variation_%d_%d' % (self.shirt.id, self.shirt_red.id): '1',
@@ -2110,7 +2255,8 @@ class CartTest(CartTestMixin, TestCase):
v = Voucher.objects.create(item=self.ticket, value=Decimal('12.00'), event=self.event,
max_usages=2, redeemed=1)
CartPosition.objects.create(
- expires=now() - timedelta(minutes=10), item=self.ticket, voucher=v, price=Decimal('12.00'),
+ expires=now() - timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time,
+ item=self.ticket, voucher=v, price=Decimal('12.00'),
event=self.event, cart_id=self.session_key
)
response = self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
@@ -2128,7 +2274,8 @@ class CartTest(CartTestMixin, TestCase):
v = Voucher.objects.create(item=self.ticket, value=Decimal('12.00'), event=self.event,
max_usages=2, redeemed=1)
CartPosition.objects.create(
- expires=now() + timedelta(minutes=10), item=self.ticket, voucher=v, price=Decimal('12.00'),
+ expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time,
+ item=self.ticket, voucher=v, price=Decimal('12.00'),
event=self.event, cart_id='other'
)
response = self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
@@ -2146,7 +2293,8 @@ class CartTest(CartTestMixin, TestCase):
v = Voucher.objects.create(item=self.ticket, value=Decimal('12.00'), event=self.event,
max_usages=2, redeemed=1)
CartPosition.objects.create(
- expires=now() - timedelta(minutes=10), item=self.ticket, voucher=v, price=Decimal('12.00'),
+ expires=now() - timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time,
+ item=self.ticket, voucher=v, price=Decimal('12.00'),
event=self.event, cart_id='other'
)
self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
@@ -2161,11 +2309,13 @@ class CartTest(CartTestMixin, TestCase):
with scopes_disabled():
cp1 = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
- price=23, listed_price=23, price_after_voucher=23, expires=now() + timedelta(minutes=10)
+ price=23, listed_price=23, price_after_voucher=23,
+ expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
cp2 = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.shirt, variation=self.shirt_blue,
- price=15, listed_price=15, price_after_voucher=15, expires=now() + timedelta(minutes=10)
+ price=15, listed_price=15, price_after_voucher=15,
+ expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
v = Voucher.objects.create(
event=self.event, item=self.ticket, price_mode='set', value=Decimal('4.00')
@@ -2185,11 +2335,13 @@ class CartTest(CartTestMixin, TestCase):
with scopes_disabled():
cp1 = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
- price=23, listed_price=23, price_after_voucher=23, expires=now() + timedelta(minutes=10)
+ price=23, listed_price=23, price_after_voucher=23,
+ expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
cp2 = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.shirt, variation=self.shirt_blue,
- price=150, listed_price=150, price_after_voucher=150, expires=now() + timedelta(minutes=10)
+ price=150, listed_price=150, price_after_voucher=150,
+ expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
v = Voucher.objects.create(
event=self.event, price_mode='set', value=Decimal('4.00'), max_usages=100, redeemed=99
@@ -2210,11 +2362,13 @@ class CartTest(CartTestMixin, TestCase):
with scopes_disabled():
cp1 = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
- price=23, listed_price=23, price_after_voucher=23, expires=now() + timedelta(minutes=10)
+ price=23, listed_price=23, price_after_voucher=23,
+ expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
cp2 = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.shirt, variation=self.shirt_blue,
- price=150, listed_price=150, price_after_voucher=150, expires=now() + timedelta(minutes=10)
+ price=150, listed_price=150, price_after_voucher=150,
+ expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
v = Voucher.objects.create(
event=self.event, price_mode='set', quota=self.quota_all, value=Decimal('4.00'), max_usages=100
@@ -2235,11 +2389,13 @@ class CartTest(CartTestMixin, TestCase):
with scopes_disabled():
cp1 = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
- price=23, listed_price=23, price_after_voucher=23, expires=now() + timedelta(minutes=10)
+ price=23, listed_price=23, price_after_voucher=23,
+ expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
cp2 = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.shirt, variation=self.shirt_blue,
- price=150, listed_price=150, price_after_voucher=150, expires=now() + timedelta(minutes=10)
+ price=150, listed_price=150, price_after_voucher=150,
+ expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
v = Voucher.objects.create(
event=self.event, price_mode='set', quota=self.quota_all, value=Decimal('4.00'), max_usages=100,
@@ -2274,14 +2430,17 @@ class CartTest(CartTestMixin, TestCase):
with scopes_disabled():
cp1 = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
- price=23, listed_price=23, price_after_voucher=23, expires=now() + timedelta(minutes=10)
+ price=23, listed_price=23, price_after_voucher=23,
+ expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
v2 = Voucher.objects.create(
event=self.event, price_mode='set', quota=self.quota_all, value=Decimal('8.00'), max_usages=100
)
cp2 = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.shirt, variation=self.shirt_blue,
- price=8, expires=now() + timedelta(minutes=10), voucher=v2
+ price=8,
+ expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time,
+ voucher=v2
)
v = Voucher.objects.create(
event=self.event, price_mode='set', quota=self.quota_all, value=Decimal('4.00'), max_usages=100
@@ -2327,11 +2486,13 @@ class CartTest(CartTestMixin, TestCase):
with scopes_disabled():
cp1 = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
- price=23, listed_price=23, price_after_voucher=23, expires=now() + timedelta(minutes=10)
+ price=23, listed_price=23, price_after_voucher=23,
+ expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
cp2 = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.shirt, variation=self.shirt_blue,
- price=15, listed_price=15, price_after_voucher=15, expires=now() + timedelta(minutes=10)
+ price=15, listed_price=15, price_after_voucher=15,
+ expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
v = Voucher.objects.create(
event=self.event, price_mode='set', value=Decimal('40.00'), max_usages=100,
@@ -2351,11 +2512,13 @@ class CartTest(CartTestMixin, TestCase):
with scopes_disabled():
cp1 = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
- price=23, listed_price=23, price_after_voucher=23, expires=now() + timedelta(minutes=10)
+ price=23, listed_price=23, price_after_voucher=23,
+ expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
cp2 = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.shirt, variation=self.shirt_blue,
- price=15, listed_price=15, price_after_voucher=15, expires=now() + timedelta(minutes=10)
+ price=15, listed_price=15, price_after_voucher=15,
+ expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
v = Voucher.objects.create(
event=self.event, price_mode='set', value=Decimal('40.00'), max_usages=100, redeemed=100
@@ -2374,11 +2537,12 @@ class CartTest(CartTestMixin, TestCase):
with scopes_disabled():
CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
- price=23, listed_price=23, price_after_voucher=23, expires=now() + timedelta(minutes=10)
+ price=23, listed_price=23, price_after_voucher=23,
+ expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.shirt, variation=self.shirt_blue,
- price=8, expires=now() + timedelta(minutes=10),
+ price=8, expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time,
)
gc = self.orga.issued_gift_cards.create(secret="GIFTCARD", currency=self.event.currency)
gc.transactions.create(value=Decimal("12.24"), acceptor=self.orga)
@@ -2491,7 +2655,8 @@ class CartAddonTest(CartTestMixin, TestCase):
self.addon1.price_included = True
self.addon1.save()
cp1 = CartPosition.objects.create(
- expires=now() + timedelta(minutes=10), item=self.ticket, price=Decimal('23.00'),
+ 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
)
@@ -2512,11 +2677,13 @@ class CartAddonTest(CartTestMixin, TestCase):
self.addon1.price_included = True
self.addon1.save()
cp1 = CartPosition.objects.create(
- expires=now() - timedelta(minutes=10), item=self.ticket, price=Decimal('23.00'),
+ 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
)
cp2 = CartPosition.objects.create(
- expires=now() - timedelta(minutes=10), item=self.workshop1, price=Decimal('0.00'),
+ expires=now() - timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time,
+ item=self.workshop1, price=Decimal('0.00'),
event=self.event, cart_id=self.session_key, addon_to=cp1
)
self.cm.extend_expired_positions()
@@ -2533,11 +2700,13 @@ class CartAddonTest(CartTestMixin, TestCase):
self.quota_tickets.size = 0
self.quota_tickets.save()
cp1 = CartPosition.objects.create(
- expires=now() - timedelta(minutes=10), item=self.ticket, price=Decimal('23.00'),
+ 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
)
CartPosition.objects.create(
- expires=now() - timedelta(minutes=10), item=self.workshop1, price=Decimal('0.00'),
+ expires=now() - timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time,
+ item=self.workshop1, price=Decimal('0.00'),
event=self.event, cart_id=self.session_key, addon_to=cp1
)
self.cm.extend_expired_positions()
@@ -2550,7 +2719,8 @@ class CartAddonTest(CartTestMixin, TestCase):
self.addon1.price_included = True
self.addon1.save()
cp1 = CartPosition.objects.create(
- expires=now() + timedelta(minutes=10), item=self.ticket, price=Decimal('23.00'),
+ 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
)
@@ -2575,7 +2745,8 @@ class CartAddonTest(CartTestMixin, TestCase):
@classscope(attr='orga')
def test_cart_set_simple_addon(self):
cp1 = CartPosition.objects.create(
- expires=now() + timedelta(minutes=10), item=self.ticket, price=Decimal('23.00'),
+ 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
)
@@ -2599,7 +2770,8 @@ class CartAddonTest(CartTestMixin, TestCase):
self.workshopquota.subevent = se
self.workshopquota.save()
cp1 = CartPosition.objects.create(
- expires=now() + timedelta(minutes=10), item=self.ticket, price=Decimal('23.00'),
+ 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, subevent=se
)
@@ -2625,7 +2797,8 @@ class CartAddonTest(CartTestMixin, TestCase):
self.workshopquota.subevent = se2
self.workshopquota.save()
cp1 = CartPosition.objects.create(
- expires=now() + timedelta(minutes=10), item=self.ticket, price=Decimal('23.00'),
+ 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, subevent=se
)
@@ -2641,7 +2814,8 @@ class CartAddonTest(CartTestMixin, TestCase):
@classscope(attr='orga')
def test_wrong_category(self):
cp1 = CartPosition.objects.create(
- expires=now() + timedelta(minutes=10), item=self.ticket, price=Decimal('23.00'),
+ 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.workshop1.category = self.category
@@ -2658,7 +2832,8 @@ class CartAddonTest(CartTestMixin, TestCase):
@classscope(attr='orga')
def test_invalid_parent(self):
cp1 = CartPosition.objects.create(
- expires=now() + timedelta(minutes=10), item=self.ticket, price=Decimal('23.00'),
+ 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='other'
)
with self.assertRaises(CartError):
@@ -2674,7 +2849,8 @@ class CartAddonTest(CartTestMixin, TestCase):
def test_no_quota_for_addon(self):
self.workshopquota.delete()
cp1 = CartPosition.objects.create(
- expires=now() + timedelta(minutes=10), item=self.ticket, price=Decimal('23.00'),
+ 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
)
with self.assertRaises(CartError):
@@ -2689,7 +2865,8 @@ class CartAddonTest(CartTestMixin, TestCase):
@classscope(attr='orga')
def test_unknown_addon_item(self):
cp1 = CartPosition.objects.create(
- expires=now() + timedelta(minutes=10), item=self.ticket, price=Decimal('23.00'),
+ 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
)
with self.assertRaises(CartError):
@@ -2704,11 +2881,13 @@ class CartAddonTest(CartTestMixin, TestCase):
@classscope(attr='orga')
def test_duplicate_items_for_other_cp(self):
cp1 = CartPosition.objects.create(
- expires=now() + timedelta(minutes=10), item=self.ticket, price=Decimal('23.00'),
+ 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
)
cp2 = CartPosition.objects.create(
- expires=now() + timedelta(minutes=10), item=self.ticket, price=Decimal('23.00'),
+ 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.cm.set_addons([
@@ -2730,7 +2909,8 @@ class CartAddonTest(CartTestMixin, TestCase):
@classscope(attr='orga')
def test_multi_allowed(self):
cp1 = CartPosition.objects.create(
- expires=now() + timedelta(minutes=10), item=self.ticket, price=Decimal('23.00'),
+ 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.addon1.max_count = 2
@@ -2754,7 +2934,8 @@ class CartAddonTest(CartTestMixin, TestCase):
@classscope(attr='orga')
def test_number_exceeds_max(self):
cp1 = CartPosition.objects.create(
- expires=now() + timedelta(minutes=10), item=self.ticket, price=Decimal('23.00'),
+ 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.addon1.max_count = 2
@@ -2777,7 +2958,8 @@ class CartAddonTest(CartTestMixin, TestCase):
self.workshopquota.size = 1
self.workshopquota.save()
cp1 = CartPosition.objects.create(
- expires=now() + timedelta(minutes=10), item=self.ticket, price=Decimal('23.00'),
+ 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.addon1.max_count = 2
@@ -2800,7 +2982,8 @@ class CartAddonTest(CartTestMixin, TestCase):
self.workshop3.free_price = True
self.workshop3.save()
cp1 = CartPosition.objects.create(
- expires=now() + timedelta(minutes=10), item=self.ticket, price=Decimal('23.00'),
+ 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.addon1.max_count = 5
@@ -2838,7 +3021,8 @@ class CartAddonTest(CartTestMixin, TestCase):
@classscope(attr='orga')
def test_change_number(self):
cp1 = CartPosition.objects.create(
- expires=now() + timedelta(minutes=10), item=self.ticket, price=Decimal('23.00'),
+ 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.addon1.max_count = 5
@@ -2882,7 +3066,8 @@ class CartAddonTest(CartTestMixin, TestCase):
@classscope(attr='orga')
def test_no_duplicate_items_for_same_cp(self):
cp1 = CartPosition.objects.create(
- expires=now() + timedelta(minutes=10), item=self.ticket, price=Decimal('23.00'),
+ 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.addon1.max_count = 2
@@ -2917,7 +3102,8 @@ class CartAddonTest(CartTestMixin, TestCase):
@classscope(attr='orga')
def test_addon_max_count(self):
cp1 = CartPosition.objects.create(
- expires=now() + timedelta(minutes=10), item=self.ticket, price=Decimal('23.00'),
+ 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
)
with self.assertRaises(CartError):
@@ -2952,7 +3138,8 @@ class CartAddonTest(CartTestMixin, TestCase):
@classscope(attr='orga')
def test_addon_min_count(self):
cp1 = CartPosition.objects.create(
- expires=now() + timedelta(minutes=10), item=self.ticket, price=Decimal('23.00'),
+ 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.addon1.min_count = 2
@@ -2983,11 +3170,13 @@ class CartAddonTest(CartTestMixin, TestCase):
@classscope(attr='orga')
def test_remove_with_addons(self):
cp1 = CartPosition.objects.create(
- expires=now() + timedelta(minutes=10), item=self.ticket, price=Decimal('23.00'),
+ 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
)
cp2 = CartPosition.objects.create(
- expires=now() + timedelta(minutes=10), item=self.workshop1, price=Decimal('12.00'),
+ expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time,
+ item=self.workshop1, price=Decimal('12.00'),
event=self.event, cart_id=self.session_key, addon_to=cp1
)
self.cm.remove_item(cp1.pk)
@@ -2998,11 +3187,13 @@ class CartAddonTest(CartTestMixin, TestCase):
@classscope(attr='orga')
def test_remove_addons(self):
cp1 = CartPosition.objects.create(
- expires=now() + timedelta(minutes=10), item=self.ticket, price=Decimal('23.00'),
+ 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
)
cp2 = CartPosition.objects.create(
- expires=now() + timedelta(minutes=10), item=self.workshop1, price=Decimal('12.00'),
+ expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time,
+ item=self.workshop1, price=Decimal('12.00'),
event=self.event, cart_id=self.session_key, addon_to=cp1
)
self.cm.set_addons([])
@@ -3012,11 +3203,13 @@ class CartAddonTest(CartTestMixin, TestCase):
@classscope(attr='orga')
def test_remove_addons_below_min(self):
cp1 = CartPosition.objects.create(
- expires=now() + timedelta(minutes=10), item=self.ticket, price=Decimal('23.00'),
+ 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
)
cp2 = CartPosition.objects.create(
- expires=now() + timedelta(minutes=10), item=self.workshop1, price=Decimal('12.00'),
+ expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time,
+ item=self.workshop1, price=Decimal('12.00'),
event=self.event, cart_id=self.session_key, addon_to=cp1
)
self.addon1.min_count = 1
@@ -3029,11 +3222,13 @@ class CartAddonTest(CartTestMixin, TestCase):
@classscope(attr='orga')
def test_change_product(self):
cp1 = CartPosition.objects.create(
- expires=now() + timedelta(minutes=10), item=self.ticket, price=Decimal('23.00'),
+ 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
)
CartPosition.objects.create(
- expires=now() + timedelta(minutes=10), item=self.workshop1, price=Decimal('12.00'),
+ expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time,
+ item=self.workshop1, price=Decimal('12.00'),
event=self.event, cart_id=self.session_key, addon_to=cp1
)
self.cm.set_addons([
@@ -3051,11 +3246,13 @@ class CartAddonTest(CartTestMixin, TestCase):
@classscope(attr='orga')
def test_unchanged(self):
cp1 = CartPosition.objects.create(
- expires=now() + timedelta(minutes=10), item=self.ticket, price=Decimal('23.00'),
+ 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
)
CartPosition.objects.create(
- expires=now() + timedelta(minutes=10), item=self.workshop1, price=Decimal('12.00'),
+ expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time,
+ item=self.workshop1, price=Decimal('12.00'),
event=self.event, cart_id=self.session_key, addon_to=cp1
)
self.cm.set_addons([
@@ -3071,7 +3268,8 @@ class CartAddonTest(CartTestMixin, TestCase):
def test_exceed_max(self):
self.event.settings.max_items_per_order = 1
cp1 = CartPosition.objects.create(
- expires=now() + timedelta(minutes=10), item=self.ticket, price=Decimal('23.00'),
+ 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.cm.set_addons([
@@ -3086,7 +3284,8 @@ class CartAddonTest(CartTestMixin, TestCase):
@classscope(attr='orga')
def test_sold_out(self):
cp1 = CartPosition.objects.create(
- expires=now() + timedelta(minutes=10), item=self.ticket, price=Decimal('23.00'),
+ 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.workshopquota.size = 0
@@ -3104,11 +3303,13 @@ class CartAddonTest(CartTestMixin, TestCase):
@classscope(attr='orga')
def test_sold_out_unchanged(self):
cp1 = CartPosition.objects.create(
- expires=now() + timedelta(minutes=10), item=self.ticket, price=Decimal('23.00'),
+ 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
)
CartPosition.objects.create(
- expires=now() + timedelta(minutes=10), item=self.workshop1, price=Decimal('12.00'),
+ expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time,
+ item=self.workshop1, price=Decimal('12.00'),
event=self.event, cart_id=self.session_key, addon_to=cp1
)
self.workshopquota.size = 0
@@ -3125,19 +3326,23 @@ class CartAddonTest(CartTestMixin, TestCase):
@classscope(attr='orga')
def test_sold_out_swap_addons(self):
cp1 = CartPosition.objects.create(
- expires=now() + timedelta(minutes=10), item=self.ticket, price=Decimal('23.00'),
+ 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
)
CartPosition.objects.create(
- expires=now() + timedelta(minutes=10), item=self.workshop1, price=Decimal('12.00'),
+ expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time,
+ item=self.workshop1, price=Decimal('12.00'),
event=self.event, cart_id=self.session_key, addon_to=cp1
)
cp2 = CartPosition.objects.create(
- expires=now() + timedelta(minutes=10), item=self.ticket, price=Decimal('23.00'),
+ 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
)
CartPosition.objects.create(
- expires=now() + timedelta(minutes=10), item=self.workshop2, price=Decimal('12.00'),
+ expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time,
+ item=self.workshop2, price=Decimal('12.00'),
event=self.event, cart_id=self.session_key, addon_to=cp2
)
self.workshopquota.size = 0
@@ -3163,11 +3368,13 @@ class CartAddonTest(CartTestMixin, TestCase):
@classscope(attr='orga')
def test_expand_expired(self):
cp1 = CartPosition.objects.create(
- expires=now() - timedelta(minutes=10), item=self.ticket, price=Decimal('23.00'),
+ 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
)
cp2 = CartPosition.objects.create(
- expires=now() - timedelta(minutes=10), item=self.workshop1, price=Decimal('12.00'),
+ expires=now() - timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time,
+ item=self.workshop1, price=Decimal('12.00'),
event=self.event, cart_id=self.session_key, addon_to=cp1
)
self.cm.extend_expired_positions()
@@ -3183,7 +3390,8 @@ class CartAddonTest(CartTestMixin, TestCase):
v = Voucher.objects.create(item=self.ticket, value=Decimal('20.00'), event=self.event, price_mode='set',
valid_until=now() + timedelta(days=2), max_usages=999, redeemed=0)
cp1 = CartPosition.objects.create(
- expires=now() - timedelta(minutes=10), item=self.ticket, price=Decimal('21.50'),
+ expires=now() - timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time,
+ item=self.ticket, price=Decimal('21.50'),
event=self.event, cart_id=self.session_key, voucher=v
)
self.cm.extend_expired_positions()
@@ -3647,11 +3855,12 @@ class CartBundleTest(CartTestMixin, TestCase):
def test_extend_keep_price(self):
cp = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
- price=21.5, expires=now() - timedelta(minutes=10)
+ price=21.5, expires=now() - timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
b = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.trans, addon_to=cp,
- price=1.5, expires=now() - timedelta(minutes=10), is_bundled=True
+ price=1.5, expires=now() - timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time,
+ is_bundled=True
)
self.cm.commit()
cp.refresh_from_db()
@@ -3663,11 +3872,12 @@ class CartBundleTest(CartTestMixin, TestCase):
def test_extend_designated_price_changed(self):
cp = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
- price=21.5, expires=now() - timedelta(minutes=10)
+ price=21.5, expires=now() - timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
b = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.trans, addon_to=cp,
- price=1.5, expires=now() - timedelta(minutes=10), is_bundled=True
+ price=1.5, expires=now() - timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time,
+ is_bundled=True
)
self.bundle1.designated_price = Decimal('2.00')
self.bundle1.save()
@@ -3681,11 +3891,12 @@ class CartBundleTest(CartTestMixin, TestCase):
def test_extend_designated_price_changed_beyond_base_price(self):
cp = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
- price=21.5, expires=now() - timedelta(minutes=10)
+ price=21.5, expires=now() - timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
b = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.trans, addon_to=cp,
- price=1.5, expires=now() - timedelta(minutes=10), is_bundled=True
+ price=1.5, expires=now() - timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time,
+ is_bundled=True
)
self.bundle1.designated_price = Decimal('40.00')
self.bundle1.save()
@@ -3699,11 +3910,12 @@ class CartBundleTest(CartTestMixin, TestCase):
def test_voucher_apply_multiple(self):
cp = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
- price=21.5, expires=now() + timedelta(minutes=10)
+ price=21.5, expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
b = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.trans, addon_to=cp,
- price=1.5, expires=now() + timedelta(minutes=10), is_bundled=True
+ price=1.5, expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time,
+ is_bundled=True
)
v = Voucher.objects.create(
event=self.event, price_mode='set', value=Decimal('4.00'), max_usages=100
@@ -3720,11 +3932,12 @@ class CartBundleTest(CartTestMixin, TestCase):
def test_voucher_apply_multiple_reduce_beyond_designated_price(self):
cp = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
- price=21.5, expires=now() + timedelta(minutes=10)
+ price=21.5, expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
b = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.trans, addon_to=cp,
- price=1.5, expires=now() + timedelta(minutes=10), is_bundled=True
+ price=1.5, expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time,
+ is_bundled=True
)
v = Voucher.objects.create(
event=self.event, price_mode='set', value=Decimal('0.00'), max_usages=100
@@ -3745,11 +3958,12 @@ class CartBundleTest(CartTestMixin, TestCase):
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)
+ price=21.5, expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
b = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.trans, addon_to=cp,
- price=1.5, expires=now() + timedelta(minutes=10), is_bundled=True
+ price=1.5, expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time,
+ is_bundled=True
)
v = Voucher.objects.create(
event=self.event, price_mode='set', value=Decimal('0.00'), max_usages=100
@@ -3766,15 +3980,17 @@ class CartBundleTest(CartTestMixin, TestCase):
def test_voucher_apply_affect_bundled(self):
cp = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
- price=21.5, expires=now() + timedelta(minutes=10)
+ price=21.5, expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
a = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.trans, addon_to=cp,
- price=2.5, expires=now() + timedelta(minutes=10), is_bundled=False
+ price=2.5, expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time,
+ is_bundled=False
)
b = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.trans, addon_to=cp,
- price=1.5, expires=now() + timedelta(minutes=10), is_bundled=True
+ price=1.5, expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time,
+ is_bundled=True
)
v = Voucher.objects.create(
event=self.event, price_mode='set', value=Decimal('0.00'), max_usages=100,
@@ -3794,15 +4010,17 @@ class CartBundleTest(CartTestMixin, TestCase):
def test_voucher_apply_affect_addons(self):
cp = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
- price=21.5, expires=now() + timedelta(minutes=10)
+ price=21.5, expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
a = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.trans, addon_to=cp,
- price=1.5, expires=now() + timedelta(minutes=10), is_bundled=False
+ price=1.5, expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time,
+ is_bundled=False
)
b = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.trans, addon_to=cp,
- price=1.5, expires=now() + timedelta(minutes=10), is_bundled=True
+ price=1.5, expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time,
+ is_bundled=True
)
v = Voucher.objects.create(
event=self.event, price_mode='set', value=Decimal('0.00'), max_usages=100,
@@ -3822,11 +4040,12 @@ class CartBundleTest(CartTestMixin, TestCase):
def test_extend_base_price_changed(self):
cp = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
- price=21.5, expires=now() - timedelta(minutes=10)
+ price=21.5, expires=now() - timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
b = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.trans, addon_to=cp,
- price=1.5, expires=now() - timedelta(minutes=10), is_bundled=True
+ price=1.5, expires=now() - timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time,
+ is_bundled=True
)
self.ticket.default_price = Decimal('25.00')
self.ticket.save()
@@ -3840,15 +4059,17 @@ class CartBundleTest(CartTestMixin, TestCase):
def test_extend_bundled_and_addon(self):
cp = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
- price=21.5, expires=now() - timedelta(minutes=10)
+ price=21.5, expires=now() - timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
a = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.trans, addon_to=cp,
- price=1.5, expires=now() - timedelta(minutes=10), is_bundled=False
+ price=1.5, expires=now() - timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time,
+ is_bundled=False
)
b = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.trans, addon_to=cp,
- price=1.5, expires=now() - timedelta(minutes=10), is_bundled=True
+ price=1.5, expires=now() - timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time,
+ is_bundled=True
)
self.cm.commit()
cp.refresh_from_db()
@@ -3873,11 +4094,12 @@ class CartBundleTest(CartTestMixin, TestCase):
cp = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
- price=21.5, expires=now() - timedelta(minutes=10)
+ price=21.5, expires=now() - timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
a = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.trans, addon_to=cp,
- price=1.5, expires=now() - timedelta(minutes=10), is_bundled=True
+ price=1.5, expires=now() - timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time,
+ is_bundled=True
)
self.cm.invoice_address = ia
self.cm.recompute_final_prices_and_taxes()
@@ -3913,11 +4135,12 @@ class CartBundleTest(CartTestMixin, TestCase):
cp = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
- price=21.5, expires=now() - timedelta(minutes=10)
+ price=21.5, expires=now() - timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
a = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.trans, addon_to=cp,
- price=1.5, expires=now() - timedelta(minutes=10), is_bundled=True
+ price=1.5, expires=now() - timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time,
+ is_bundled=True
)
self.cm.invoice_address = ia
self.cm.recompute_final_prices_and_taxes()
@@ -4048,11 +4271,12 @@ class CartBundleTest(CartTestMixin, TestCase):
cp = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
- price=21.5, expires=now() - timedelta(minutes=10),
+ price=21.5, expires=now() - timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time,
)
a = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.trans, addon_to=cp,
- price=1.47, expires=now() - timedelta(minutes=10), is_bundled=True, tax_rate=Decimal('5.00')
+ price=1.47, expires=now() - timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time,
+ is_bundled=True, tax_rate=Decimal('5.00')
)
self.cm.invoice_address = ia
self.cm.recompute_final_prices_and_taxes()
@@ -4097,11 +4321,12 @@ class CartBundleTest(CartTestMixin, TestCase):
cp = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
- price=21.68, expires=now() - timedelta(minutes=10), tax_rate=Decimal('20.00')
+ price=21.68, expires=now() - timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time, tax_rate=Decimal('20.00')
)
a = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.trans, addon_to=cp,
- price=1.47, expires=now() - timedelta(minutes=10), is_bundled=True, tax_rate=Decimal('5.00')
+ price=1.47, expires=now() - timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time,
+ is_bundled=True, tax_rate=Decimal('5.00')
)
self.cm.invoice_address = ia
self.cm.recompute_final_prices_and_taxes()
@@ -4342,7 +4567,7 @@ class CartSeatingTest(CartTestMixin, TestCase):
def test_add_with_seat_to_cart_twice(self):
CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket, seat=self.seat_a1,
- price=23, expires=now() + timedelta(minutes=10)
+ price=23, expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
with scopes_disabled():
objs = list(CartPosition.objects.filter(cart_id=self.session_key, event=self.event))
@@ -4358,7 +4583,7 @@ class CartSeatingTest(CartTestMixin, TestCase):
def test_add_used_seat_to_cart(self):
CartPosition.objects.create(
event=self.event, cart_id='aaa', item=self.ticket, seat=self.seat_a1,
- price=23, expires=now() + timedelta(minutes=10)
+ price=23, expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
'seat_%d' % self.ticket.id: self.seat_a1.seat_guid,
@@ -4372,7 +4597,7 @@ class CartSeatingTest(CartTestMixin, TestCase):
with scopes_disabled():
cp = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket, seat=self.seat_a1,
- price=21.5, expires=now() - timedelta(minutes=10)
+ price=21.5, expires=now() - timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
self.cm.commit()
cp.refresh_from_db()
@@ -4383,11 +4608,11 @@ class CartSeatingTest(CartTestMixin, TestCase):
with scopes_disabled():
CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket, seat=self.seat_a1,
- price=21.5, expires=now() - timedelta(minutes=10)
+ price=21.5, expires=now() - timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
CartPosition.objects.create(
event=self.event, cart_id='secondcart', item=self.ticket, seat=self.seat_a1,
- price=21.5, expires=now() + timedelta(minutes=10)
+ price=21.5, expires=now() + timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time
)
with self.assertRaises(CartError):
self.cm.commit()