diff --git a/src/pretix/api/serializers/event.py b/src/pretix/api/serializers/event.py index ac766fd640..3ca522ae89 100644 --- a/src/pretix/api/serializers/event.py +++ b/src/pretix/api/serializers/event.py @@ -613,6 +613,7 @@ class EventSettingsSerializer(serializers.Serializer): 'cancel_allow_user_paid_keep_percentage', 'cancel_allow_user_paid_adjust_fees', 'cancel_allow_user_paid_refund_as_giftcard', + 'cancel_allow_user_paid_require_approval', ] def __init__(self, *args, **kwargs): diff --git a/src/pretix/base/migrations/0148_cancellationrequest.py b/src/pretix/base/migrations/0148_cancellationrequest.py new file mode 100644 index 0000000000..44690003b2 --- /dev/null +++ b/src/pretix/base/migrations/0148_cancellationrequest.py @@ -0,0 +1,24 @@ +# Generated by Django 3.0.4 on 2020-03-25 10:05 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('pretixbase', '0147_user_session_token'), + ] + + operations = [ + migrations.CreateModel( + name='CancellationRequest', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False)), + ('created', models.DateTimeField(auto_now_add=True)), + ('cancellation_fee', models.DecimalField(decimal_places=2, max_digits=10)), + ('refund_as_giftcard', models.BooleanField(default=False)), + ('order', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='cancellation_requests', to='pretixbase.Order')), + ], + ), + ] diff --git a/src/pretix/base/models/orders.py b/src/pretix/base/models/orders.py index 9931cbecda..11924c4ce3 100644 --- a/src/pretix/base/models/orders.py +++ b/src/pretix/base/models/orders.py @@ -470,6 +470,8 @@ class Order(LockModel, LoggedModel): """ from .checkin import Checkin + if self.cancellation_requests.exists(): + return False positions = list( self.positions.all().annotate( has_checkin=Exists(Checkin.objects.filter(position_id=OuterRef('pk'))) @@ -2208,6 +2210,13 @@ class CachedCombinedTicket(models.Model): created = models.DateTimeField(auto_now_add=True) +class CancellationRequest(models.Model): + order = models.ForeignKey(Order, on_delete=models.CASCADE, related_name='cancellation_requests') + created = models.DateTimeField(auto_now_add=True) + cancellation_fee = models.DecimalField(max_digits=10, decimal_places=2) + refund_as_giftcard = models.BooleanField(default=False) + + @receiver(post_delete, sender=CachedTicket) def cachedticket_delete(sender, instance, **kwargs): if instance.file: diff --git a/src/pretix/base/services/orders.py b/src/pretix/base/services/orders.py index d9114108f0..77cba45de4 100644 --- a/src/pretix/base/services/orders.py +++ b/src/pretix/base/services/orders.py @@ -404,6 +404,7 @@ def _cancel_order(order, user=None, send_mail: bool=True, api_token=None, device order.log_action('pretix.event.order.canceled', user=user, auth=api_token or oauth_application or device, data={'cancellation_fee': cancellation_fee}) + order.cancellation_requests.all().delete() if send_mail: email_template = order.event.settings.mail_text_order_canceled diff --git a/src/pretix/base/settings.py b/src/pretix/base/settings.py index 6a27202673..26449ff77f 100644 --- a/src/pretix/base/settings.py +++ b/src/pretix/base/settings.py @@ -917,6 +917,16 @@ DEFAULTS = { help_text=_("With this option enabled, your customers can choose to get a smaller refund to support you.") ) }, + 'cancel_allow_user_paid_require_approval': { + 'default': 'False', + 'type': bool, + 'form_class': forms.BooleanField, + 'serializer_class': serializers.BooleanField, + 'form_kwargs': dict( + label=_("Customers can only request a cancellation that needs to be approved by the event organizer " + "before the order is canceled and a refund is issued."), + ) + }, 'cancel_allow_user_paid_refund_as_giftcard': { 'default': 'off', 'type': str, diff --git a/src/pretix/control/forms/event.py b/src/pretix/control/forms/event.py index 5fdf5770c8..3c7981b739 100644 --- a/src/pretix/control/forms/event.py +++ b/src/pretix/control/forms/event.py @@ -567,6 +567,7 @@ class CancelSettingsForm(SettingsForm): 'cancel_allow_user_paid_keep_percentage', 'cancel_allow_user_paid_adjust_fees', 'cancel_allow_user_paid_refund_as_giftcard', + 'cancel_allow_user_paid_require_approval', ] diff --git a/src/pretix/control/forms/filter.py b/src/pretix/control/forms/filter.py index 58c12f4938..3af060b3b2 100644 --- a/src/pretix/control/forms/filter.py +++ b/src/pretix/control/forms/filter.py @@ -220,6 +220,7 @@ class EventOrderFilterForm(OrderFilterForm): ('underpaid', _('Underpaid')), ('pendingpaid', _('Pending (but fully paid)')), ('testmode', _('Test mode')), + ('rc', _('Cancellation requested')), ), required=False, ) @@ -305,6 +306,10 @@ class EventOrderFilterForm(OrderFilterForm): Q(~Q(status=Order.STATUS_CANCELED) & Q(pending_sum_t__lt=0)) | Q(Q(status=Order.STATUS_CANCELED) & Q(pending_sum_rc__lt=0)) ) + elif fdata.get('status') == 'rc': + qs = qs.filter( + cancellation_requests__isnull=False + ) elif fdata.get('status') == 'pendingpaid': qs = Order.annotate_overpayments(qs, refunds=False, results=False, sums=True) qs = qs.filter( diff --git a/src/pretix/control/logdisplay.py b/src/pretix/control/logdisplay.py index 2ff4845363..bd923bb910 100644 --- a/src/pretix/control/logdisplay.py +++ b/src/pretix/control/logdisplay.py @@ -189,6 +189,7 @@ def pretixcontrol_logentry_display(sender: Event, logentry: LogEntry, **kwargs): 'pretix.event.order.expirychanged': _('The order\'s expiry date has been changed.'), 'pretix.event.order.expired': _('The order has been marked as expired.'), 'pretix.event.order.paid': _('The order has been marked as paid.'), + 'pretix.event.order.cancellationrequest.deleted': _('The cancellation request has been deleted.'), 'pretix.event.order.refunded': _('The order has been refunded.'), 'pretix.event.order.canceled': _('The order has been canceled.'), 'pretix.event.order.reactivated': _('The order has been reactivated.'), diff --git a/src/pretix/control/templates/pretixcontrol/event/cancel.html b/src/pretix/control/templates/pretixcontrol/event/cancel.html index 1550eafe7d..48be7ccc21 100644 --- a/src/pretix/control/templates/pretixcontrol/event/cancel.html +++ b/src/pretix/control/templates/pretixcontrol/event/cancel.html @@ -15,6 +15,7 @@