diff --git a/src/pretix/base/datasync/datasync.py b/src/pretix/base/datasync/datasync.py index 8f8a5dbd4a..645fa0b636 100644 --- a/src/pretix/base/datasync/datasync.py +++ b/src/pretix/base/datasync/datasync.py @@ -148,9 +148,10 @@ class OutboundSyncProvider: raise TypeError('Call this method on a derived class that defines an "identifier" attribute.') OrderSyncQueue.objects.create( order=order, + event=order.event, sync_provider=cls.identifier, triggered_by=triggered_by, - not_before=not_before, + not_before=not_before or now(), ) @classmethod @@ -235,6 +236,11 @@ class OutboundSyncProvider: f"Could not sync order {sq.order.code} to {type(self).__name__} (unhandled exception)" ) sentry_sdk.capture_exception(e) + sq.order.log_action("pretix.event.order.data_sync.failed.internal", { + "provider": self.identifier, + "error": [], + "full_message": str(e), + }) sq.delete() else: sq.order.log_action("pretix.event.order.data_sync.success", { diff --git a/src/pretix/base/migrations/0280_ordersync.py b/src/pretix/base/migrations/0280_datasync.py similarity index 85% rename from src/pretix/base/migrations/0280_ordersync.py rename to src/pretix/base/migrations/0280_datasync.py index c3add1d801..093025a892 100644 --- a/src/pretix/base/migrations/0280_ordersync.py +++ b/src/pretix/base/migrations/0280_datasync.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.16 on 2025-04-01 14:52 +# Generated by Django 4.2.16 on 2025-05-07 13:01 import django.db.models.deletion from django.db import migrations, models @@ -11,33 +11,6 @@ class Migration(migrations.Migration): ] operations = [ - migrations.CreateModel( - name="OrderSyncQueue", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, primary_key=True, serialize=False - ), - ), - ("sync_provider", models.CharField(max_length=128)), - ("triggered_by", models.CharField(max_length=128)), - ("triggered", models.DateTimeField(auto_now_add=True)), - ("failed_attempts", models.PositiveIntegerField(default=0)), - ("not_before", models.DateTimeField(blank=True, null=True)), - ( - "order", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="queued_sync_jobs", - to="pretixbase.order", - ), - ), - ], - options={ - "unique_together": {("order", "sync_provider")}, - }, - ), migrations.CreateModel( name="OrderSyncResult", fields=[ @@ -79,9 +52,45 @@ class Migration(migrations.Migration): "indexes": [ models.Index( fields=["order", "sync_provider"], - name="pretixbase__order_i_23d278_idx", + name="pretixbase__order_i_3e3c84_idx", ) ], }, ), + migrations.CreateModel( + name="OrderSyncQueue", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, primary_key=True, serialize=False + ), + ), + ("sync_provider", models.CharField(max_length=128)), + ("triggered_by", models.CharField(max_length=128)), + ("triggered", models.DateTimeField(auto_now_add=True)), + ("failed_attempts", models.PositiveIntegerField(default=0)), + ("not_before", models.DateTimeField(db_index=True)), + ( + "event", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="queued_sync_jobs", + to="pretixbase.event", + ), + ), + ( + "order", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="queued_sync_jobs", + to="pretixbase.order", + ), + ), + ], + options={ + "ordering": ("triggered",), + "unique_together": {("order", "sync_provider")}, + }, + ), ] diff --git a/src/pretix/base/models/datasync.py b/src/pretix/base/models/datasync.py index 59e7bdada2..5e8af263d0 100644 --- a/src/pretix/base/models/datasync.py +++ b/src/pretix/base/models/datasync.py @@ -25,7 +25,7 @@ from functools import cached_property from django.db import models -from pretix.base.models import Order, OrderPosition +from pretix.base.models import Event, Order, OrderPosition logger = logging.getLogger(__name__) @@ -40,11 +40,14 @@ class OrderSyncQueue(models.Model): order = models.ForeignKey( Order, on_delete=models.CASCADE, related_name="queued_sync_jobs" ) + event = models.ForeignKey( + Event, on_delete=models.CASCADE, related_name="queued_sync_jobs" + ) sync_provider = models.CharField(blank=False, null=False, max_length=128) triggered_by = models.CharField(blank=False, null=False, max_length=128) triggered = models.DateTimeField(blank=False, null=False, auto_now_add=True) failed_attempts = models.PositiveIntegerField(default=0) - not_before = models.DateTimeField(blank=True, null=True) + not_before = models.DateTimeField(blank=False, null=False, db_index=True) class Meta: unique_together = (("order", "sync_provider"),) diff --git a/src/pretix/control/logdisplay.py b/src/pretix/control/logdisplay.py index d4a8fea744..bae8b15897 100644 --- a/src/pretix/control/logdisplay.py +++ b/src/pretix/control/logdisplay.py @@ -446,6 +446,7 @@ class OrderDataSyncLogEntryType(OrderLogEntryType): "pretix.event.order.data_sync.failed.config": _("Transferring data to {provider} failed due to invalid configuration:"), "pretix.event.order.data_sync.failed.exceeded": _("Maximum number of retries exceeded while transferring data to {provider}:"), "pretix.event.order.data_sync.failed.permanent": _("Error while transferring data to {provider}:"), + "pretix.event.order.data_sync.failed.internal": _("Internal error while transferring data to {provider}."), }) class OrderDataSyncErrorLogEntryType(OrderLogEntryType): def display(self, logentry, data): diff --git a/src/pretix/control/templates/pretixcontrol/datasync/control_order_info.html b/src/pretix/control/templates/pretixcontrol/datasync/control_order_info.html index 8b94e6b5ef..1eae1d76fc 100644 --- a/src/pretix/control/templates/pretixcontrol/datasync/control_order_info.html +++ b/src/pretix/control/templates/pretixcontrol/datasync/control_order_info.html @@ -14,7 +14,7 @@
{% csrf_token %} {% if pending %} - {% if pending.not_before %} + {% if pending.not_before > now %} {% endif %} @@ -35,7 +35,7 @@ Waiting until {{ datetime }} {% endblocktrans %} {% endif %} - {% elif pending.not_before %} + {% elif pending.not_before > now %} {% blocktrans trimmed with datetime=pending.not_before|date:"SHORT_DATETIME_FORMAT" %} Waiting until {{ datetime }} {% endblocktrans %} diff --git a/src/pretix/control/views/datasync.py b/src/pretix/control/views/datasync.py index 43268deed1..3c6436685a 100644 --- a/src/pretix/control/views/datasync.py +++ b/src/pretix/control/views/datasync.py @@ -27,6 +27,7 @@ from django.dispatch import receiver from django.http import HttpResponseNotAllowed from django.shortcuts import redirect from django.template.loader import get_template +from django.utils.timezone import now from django.utils.translation import gettext_lazy as _ from pretix.base.datasync.datasync import sync_targets @@ -55,6 +56,7 @@ def on_control_order_info(sender: Event, request, order: Order, **kwargs): "request": request, "event": sender, "providers": providers, + "now": now(), } return template.render(ctx, request=request) @@ -74,7 +76,7 @@ class ControlSyncJob(OrderView): messages.success(self.request, _('The sync job has been canceled.')) elif self.request.POST.get("run_job_now"): job = self.order.queued_sync_jobs.get(pk=self.request.POST.get("run_job_now")) - job.not_before = None + job.not_before = now() job.save() messages.success(self.request, _('The sync job has been set to run as soon as possible.'))