diff --git a/aleksis/apps/paweljong/models.py b/aleksis/apps/paweljong/models.py
index 2840ef16fdb03b3722089d964abb5fd3294fb684..cac5b1f652180ea71b9b72adae7ad52a93158044 100644
--- a/aleksis/apps/paweljong/models.py
+++ b/aleksis/apps/paweljong/models.py
@@ -2,6 +2,7 @@ from datetime import datetime
 from decimal import Decimal
 
 from django.contrib.contenttypes.models import ContentType
+from django.core.exceptions import ValidationError
 from django.db import models
 from django.urls import reverse
 from django.utils.text import slugify
@@ -280,6 +281,26 @@ class EventRegistration(ExtensibleModel):
         RegistrationState, verbose_name=_("States"), related_name="registrations"
     )
 
+    retracted = models.BooleanField(verbose_name=_("Retracted"), default=False)
+
+    @property
+    def retractable(self):
+        return datetime.today() < self.event.date_retraction
+
+    def retract(self):
+        if self.retractable:
+            # Remove person from group
+            self.linked_group.members.remove(self.person)
+            # Invoice
+            inv = self.get_invoice()
+            inv.for_object = None
+            inv.for_object_class = None
+            inv.save()
+            self.retraced = True
+            self.save()
+        else:
+            return ValidationError(_("Registration is not retractable!"))
+
     def get_person(self):
         return self.person
 
diff --git a/aleksis/apps/paweljong/urls.py b/aleksis/apps/paweljong/urls.py
index 5568600668fe34105b8ceb8f5df8b8f51ef1d0b0..cedaf6a7c8ba1cd81792d0528975c40e05346e89 100644
--- a/aleksis/apps/paweljong/urls.py
+++ b/aleksis/apps/paweljong/urls.py
@@ -72,6 +72,11 @@ urlpatterns = [
     path("vouchers/", views.vouchers, name="vouchers"),
     path("event/lists/generate", views.generate_lists, name="generate_lists"),
     path("event/registrations/list", views.registrations, name="registrations"),
+    path(
+        "event/registrations/<int:pk>/retract",
+        views.registrations,
+        name="retract_registration_by_id",
+    ),
     path(
         "event/registrations/<int:pk>",
         views.EventRegistrationDetailView.as_view(),
diff --git a/aleksis/apps/paweljong/views.py b/aleksis/apps/paweljong/views.py
index a16c8f8f8ab446cadd4d5e4d3172900ac0a0a86f..da7936ef5f842c399268f6d4438e40918d87884e 100644
--- a/aleksis/apps/paweljong/views.py
+++ b/aleksis/apps/paweljong/views.py
@@ -899,3 +899,10 @@ class RegistrationStateEditView(PermissionRequiredMixin, AdvancedEditView):
     template_name = "paweljong/registration_state/edit.html"
     success_url = reverse_lazy("registration_states")
     success_message = _("The term has been saved.")
+
+
+class RetractRegistration(View):
+    def get(self):
+        registration = EventRegistration.objects.get(id=self.kwargs["pk"])
+
+        registration.retract()