diff --git a/doc/development/implementation/index.rst b/doc/development/implementation/index.rst index 9a050c02b8..64adb27867 100644 --- a/doc/development/implementation/index.rst +++ b/doc/development/implementation/index.rst @@ -19,3 +19,4 @@ Contents: permissions logging locking + timemachine diff --git a/doc/development/implementation/timemachine.rst b/doc/development/implementation/timemachine.rst new file mode 100644 index 0000000000..28dc8e5501 --- /dev/null +++ b/doc/development/implementation/timemachine.rst @@ -0,0 +1,36 @@ +Time machine mode +================= + +In test mode, pretix provides a time machine feature which allows event organizers +to test their shop as if it were a different date and time. This time machine mode +is implemented by calling our custom :py:meth:`time_machine_now()` function instead of +:py:meth:`django.utils.timezone.now()` in all places where the time should be +modifiable. If you add code that uses the current date and time for checking whether some +product can be bought, you should use :py:meth:`time_machine_now`. + +.. autofunction:: pretix.base.timemachine.time_machine_now + +Background tasks +---------------- + +The time machine datetime is passed through the request flow via a thread-local variable (ContextVar). +Therefore, if you call a background task in the order process, where time_machine_now should be +respected, you need to pass it through manually as shown in the example below: + +.. code-block:: python + + @app.task() + def my_task(self, override_now_dt: datetime=None) -> None: + with time_machine_now_assigned(override_now_dt): + # ...do something that uses time_machine_now() + + my_task.apply_async(kwargs={'override_now_dt': time_machine_now(default=None)}) + + + + + + + + + diff --git a/src/pretix/base/timemachine.py b/src/pretix/base/timemachine.py index d13a4a6ee4..9ed1cf986a 100644 --- a/src/pretix/base/timemachine.py +++ b/src/pretix/base/timemachine.py @@ -47,6 +47,12 @@ def time_machine_now_assigned_from_request(request): def time_machine_now(default=False): + """ + Return the datetime to use as current datetime for checking order restrictions in event + index and checkout flow. + + :param default: Value to return if time machine mode is disabled. By default the current datetime is used. + """ if default is False: default = now() return timemachine_now_var.get() or default