diff --git a/src/pretix/base/services/orders.py b/src/pretix/base/services/orders.py index de9abea346..1878e65612 100644 --- a/src/pretix/base/services/orders.py +++ b/src/pretix/base/services/orders.py @@ -266,7 +266,15 @@ def _create_order(event: Event, email: str, positions: List[CartPosition], now_d total = sum([c.price for c in positions]) payment_fee = payment_provider.calculate_fee(total) total += payment_fee - expires = [now_dt + timedelta(days=event.settings.get('payment_term_days', as_type=int))] + + exp_by_date = now_dt + timedelta(days=event.settings.get('payment_term_days', as_type=int)) + if event.settings.get('payment_term_weekdays'): + if exp_by_date.weekday() == 5: + exp_by_date += timedelta(days=2) + elif exp_by_date.weekday() == 6: + exp_by_date += timedelta(days=1) + + expires = [exp_by_date] if event.settings.get('payment_term_last'): expires.append(event.settings.get('payment_term_last', as_type=datetime)) order = Order.objects.create( diff --git a/src/pretix/base/settings.py b/src/pretix/base/settings.py index 86e9f58eac..ffa5e4630f 100644 --- a/src/pretix/base/settings.py +++ b/src/pretix/base/settings.py @@ -53,6 +53,10 @@ DEFAULTS = { 'default': None, 'type': datetime, }, + 'payment_term_weekdays': { + 'default': 'True', + 'type': bool + }, 'payment_term_expire_automatically': { 'default': 'True', 'type': bool diff --git a/src/pretix/control/forms/event.py b/src/pretix/control/forms/event.py index 9fd05275ea..e3a784b476 100644 --- a/src/pretix/control/forms/event.py +++ b/src/pretix/control/forms/event.py @@ -204,6 +204,13 @@ class PaymentSettingsForm(SettingsForm): required=False, widget=forms.DateTimeInput(attrs={'class': 'datetimepicker'}) ) + payment_term_weekdays = forms.BooleanField( + label=_('Only end payment terms on weekdays'), + help_text=_("If this is activated and the payment term of any order ends on a saturday or sunday, it will be " + "moved to the next monday instead. This is required in some countries by civil law. This will " + "not effect the last date of payments configured above."), + required=False, + ) payment_term_expire_automatically = forms.BooleanField( label=_('Automatically expire unpaid orders'), help_text=_("If checked, all unpaid orders will automatically go from 'pending' to 'expired' " diff --git a/src/pretix/control/templates/pretixcontrol/event/payment.html b/src/pretix/control/templates/pretixcontrol/event/payment.html index 892ed9562d..fddb1d529a 100644 --- a/src/pretix/control/templates/pretixcontrol/event/payment.html +++ b/src/pretix/control/templates/pretixcontrol/event/payment.html @@ -8,6 +8,7 @@ {% trans "Payment settings" %} {% bootstrap_field sform.payment_term_days layout="horizontal" %} {% bootstrap_field sform.payment_term_last layout="horizontal" %} + {% bootstrap_field sform.payment_term_weekdays layout="horizontal" %} {% bootstrap_field sform.payment_term_expire_automatically layout="horizontal" %} {% bootstrap_field sform.payment_term_accept_late layout="horizontal" %} {% bootstrap_field sform.tax_rate_default layout="horizontal" %} diff --git a/src/tests/base/test_orders.py b/src/tests/base/test_orders.py index f406a966ff..73ce2f36cd 100644 --- a/src/tests/base/test_orders.py +++ b/src/tests/base/test_orders.py @@ -1,17 +1,13 @@ -from datetime import timedelta +from datetime import datetime, timedelta from decimal import Decimal import pytest -from django.db import transaction from django.test import TestCase -from django.utils.timezone import now +from django.utils.timezone import make_aware, now from pretix.base.decimal import round_decimal -from pretix.base.models import ( - Event, Item, Order, OrderPosition, Organizer, Quota, -) +from pretix.base.models import Event, Item, Order, OrderPosition, Organizer from pretix.base.payment import FreeOrderProvider -from pretix.base.services import invoices from pretix.base.services.orders import ( OrderChangeManager, OrderError, _create_order, expire_orders, ) @@ -31,16 +27,37 @@ def event(): def test_expiry_days(event): today = now() event.settings.set('payment_term_days', 5) + event.settings.set('payment_term_weekdays', False) order = _create_order(event, email='dummy@example.org', positions=[], now_dt=today, payment_provider=FreeOrderProvider(event), locale='de') assert (order.expires - today).days == 5 +@pytest.mark.django_db +def test_expiry_weekdays(event): + today = make_aware(datetime(2016, 9, 20, 15, 0, 0, 0)) + event.settings.set('payment_term_days', 5) + event.settings.set('payment_term_weekdays', True) + order = _create_order(event, email='dummy@example.org', positions=[], + now_dt=today, payment_provider=FreeOrderProvider(event), + locale='de') + assert (order.expires - today).days == 6 + assert order.expires.weekday() == 0 + + today = make_aware(datetime(2016, 9, 19, 15, 0, 0, 0)) + order = _create_order(event, email='dummy@example.org', positions=[], + now_dt=today, payment_provider=FreeOrderProvider(event), + locale='de') + assert (order.expires - today).days == 7 + assert order.expires.weekday() == 0 + + @pytest.mark.django_db def test_expiry_last(event): today = now() event.settings.set('payment_term_days', 5) + event.settings.set('payment_term_weekdays', False) event.settings.set('payment_term_last', now() + timedelta(days=3)) order = _create_order(event, email='dummy@example.org', positions=[], now_dt=today, payment_provider=FreeOrderProvider(event),