diff --git a/aleksis/apps/paweljong/filters.py b/aleksis/apps/paweljong/filters.py
index d8783fcb6b0285101b723fbc1059ffdc543cf7c3..15b5df5a74773f918bbfdb48436edaab847809e3 100644
--- a/aleksis/apps/paweljong/filters.py
+++ b/aleksis/apps/paweljong/filters.py
@@ -9,16 +9,23 @@ from .models import Event, EventRegistration, Terms, Voucher
 
 
 class EventRegistrationFilter(FilterSet):
+    person = MultipleCharFilter(
+        [
+            "person__first_name__icontains",
+            "person__last_name__icontains",
+        ],
+        label=_("Search by name"),
+    )
+
     class Meta:
         model = EventRegistration
-        fields = ["person", "event", "date_registered", "states", "retracted"]
+        fields = ["states", "retracted"]
 
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
 
         self.form.layout = Layout(
-            Row("person", "event", "states", "retracted"),
-            Row("date_registered"),
+            Row("person", "states", "retracted"),
         )
 
 
diff --git a/aleksis/apps/paweljong/migrations/0020_check_in.py b/aleksis/apps/paweljong/migrations/0020_check_in.py
new file mode 100644
index 0000000000000000000000000000000000000000..4f092f7d06a8a95b009b392a5d091b0ebbb4214a
--- /dev/null
+++ b/aleksis/apps/paweljong/migrations/0020_check_in.py
@@ -0,0 +1,23 @@
+# Generated by Django 3.2.13 on 2022-06-22 19:11
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('paweljong', '0019_retractions'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='eventregistration',
+            name='checked_in',
+            field=models.BooleanField(default=False, verbose_name='Checked in'),
+        ),
+        migrations.AddField(
+            model_name='eventregistration',
+            name='checked_in_date',
+            field=models.DateTimeField(blank=True, null=True, verbose_name='Checked in at'),
+        ),
+    ]
diff --git a/aleksis/apps/paweljong/models.py b/aleksis/apps/paweljong/models.py
index 57c1dc3ab9bb2f61d725be959fb665e615b280d8..0e4cd37e18abfacaa9c8014070cb2c9a720c906b 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
@@ -285,6 +286,17 @@ class EventRegistration(ExtensibleModel):
     retracted = models.BooleanField(verbose_name=_("Retracted"), default=False)
     retracted_date = models.DateField(verbose_name=_("Retracted at"), null=True, blank=True)
 
+    checked_in = models.BooleanField(verbose_name=_("Checked in"), default=False)
+    checked_in_date = models.DateTimeField(verbose_name=_("Checked in at"), null=True, blank=True)
+
+    def mark_checked_in(self):
+        if not self.checked_in:
+            self.checked_in = True
+            self.checked_in_date = now()
+            self.save()
+        else:
+            raise ValidationError(_("Person is already checked in!"))
+
     def retract(self):
         # Remove person from group
         self.event.linked_group.members.remove(self.person)
diff --git a/aleksis/apps/paweljong/rules.py b/aleksis/apps/paweljong/rules.py
index 5f0ee3bfddf8898d8b52f5806a2df47d7dba49bd..b524f2c3bd30cb59f5b37f2309fabb2239184393 100644
--- a/aleksis/apps/paweljong/rules.py
+++ b/aleksis/apps/paweljong/rules.py
@@ -1,4 +1,4 @@
-import rules;
+import rules
 
 from aleksis.core.util.predicates import (
     has_any_object,
@@ -8,7 +8,13 @@ from aleksis.core.util.predicates import (
 )
 
 from .models import Event, EventRegistration, Terms, Voucher
-from .predicates import is_event_published, is_organiser, is_own_registration, is_own_voucher, is_participant
+from .predicates import (
+    is_event_published,
+    is_organiser,
+    is_own_registration,
+    is_own_voucher,
+    is_participant,
+)
 
 ## Vouchers
 
@@ -66,7 +72,7 @@ view_event_predicate = (
 rules.add_perm("paweljong.view_event_rule", view_event_predicate)
 
 # Event organiser view
-view_event_detail_predicate = (has_person & is_organiser)
+view_event_detail_predicate = has_person & is_organiser
 rules.add_perm("paweljong.view_event_detail_rule", view_event_detail_predicate)
 
 # Delete event
@@ -110,6 +116,7 @@ rules.add_perm("paweljong.delete_registration_rule", delete_registration_predica
 change_registration_predicate = has_person & (
     has_global_perm("paweljong.change_eventregistration")
     | has_object_perm("paweljong.change_eventregistration")
+    | is_organiser
 )
 rules.add_perm("paweljong.change_registration_rule", change_registration_predicate)
 
diff --git a/aleksis/apps/paweljong/tables.py b/aleksis/apps/paweljong/tables.py
index f380dc94318e707a320407873fd7ccc54c40b59e..b93ff3ce92c4fbb75b37cd44c47b788d15539a70 100644
--- a/aleksis/apps/paweljong/tables.py
+++ b/aleksis/apps/paweljong/tables.py
@@ -63,9 +63,8 @@ class EventRegistrationsTable(tables.Table):
         attrs = {"class": "responsive-table highlight"}
 
     person = tables.Column()
-    event = tables.Column()
-    date_registered = tables.Column()
     states = tables.Column()
+    checked_in_date = tables.Column()
     retracted = tables.Column()
     view = tables.LinkColumn(
         "registration_by_pk",
@@ -73,6 +72,12 @@ class EventRegistrationsTable(tables.Table):
         verbose_name=_("View registration"),
         text=_("View"),
     )
+    check_in = tables.LinkColumn(
+        "check_in_registration_by_pk",
+        args=[A("pk")],
+        verbose_name=_("Check in"),
+        text=_("Check in"),
+    )
     edit = tables.LinkColumn(
         "edit_registration_by_pk",
         args=[A("pk")],
diff --git a/aleksis/apps/paweljong/templates/paweljong/event/detail.html b/aleksis/apps/paweljong/templates/paweljong/event/detail.html
index 1adf1eb19146dbd5e621ee7b7aadb28936c8a262..f553959001486dc0e850f2a090d0a614c02cb880 100644
--- a/aleksis/apps/paweljong/templates/paweljong/event/detail.html
+++ b/aleksis/apps/paweljong/templates/paweljong/event/detail.html
@@ -65,12 +65,6 @@
             {% endfor %}
             </td>
           </tr>
-          <tr>
-            <td>{% trans "Description" %}</td>
-            <td colspan="3">
-              {{ event.information|add_class_to_el:"ul, browser-default"|safe }}
-            </td>
-          </tr>
         </table>
       </div>
     </div>
@@ -89,6 +83,15 @@
   </div>
 
   <h5>{% blocktrans %}Registrations{% endblocktrans %}</h5>
+  <form method="get">
+    {% form form=registrations_filter.form %}{% endform %}
+    {% trans "Search" as caption %}
+    {% include "core/partials/save_button.html" with caption=caption icon="search" %}
+    <button type="reset" class="btn red waves-effect waves-light">
+      <i class="material-icons left">clear</i>
+      {% trans "Clear" %}
+    </button>
+  </form>
   {% render_table registrations_table %}
 
 {% endblock %}
diff --git a/aleksis/apps/paweljong/templates/paweljong/event_registration/full.html b/aleksis/apps/paweljong/templates/paweljong/event_registration/full.html
index 64b19ce5f0c9c54423224b362a69c15232e57cc4..a077f759dbc303df89ce9fd60607c1f7e585ec38 100644
--- a/aleksis/apps/paweljong/templates/paweljong/event_registration/full.html
+++ b/aleksis/apps/paweljong/templates/paweljong/event_registration/full.html
@@ -24,6 +24,10 @@
           <i class="material-icons left iconify" data-icon="mdi:edit"></i>
           {% trans "Edit" %}
         </a>
+        <a href="{% url 'check_in_registration_by_pk' registration.pk %}" class="btn waves-effect waves-light">
+          <i class="material-icons left iconify" data-icon="akar-icons:check-in"></i>
+          {% trans "Check in" %}
+        </a>
       {% endif %}
       {% if can_retract_registration %}
         <a href="{% url 'retract_registration_by_pk' registration.pk %}" class="btn waves-effect waves-light">
@@ -215,10 +219,99 @@
             </td>
           </tr>
         </tr>
+        <tr>
+          <tr>
+            <td>
+              <i class="material-icons iconify" data-icon="akar-icons:check-in"></i>
+            </td>
+            <td>
+              {% if registration.checked_in %}
+                {{ registration.checked_in_date }}
+              {% else %}
+                {% trans "No checked in yet." %}
+              {% endif %}
+            </td>
+          </tr>
+        </tr>
       </table>
     </div>
   </div>
 
+  <h5>{% trans "Invoice details" %}</h5>
+  <div class="col s12 m8">
+    <div class="row">
+      <div class="col s12 m6">
+        <div class="card">
+          <div class="card-content">
+            <span class="card-title">{% trans "Billing information" %}</span>
+            <table class="highlight">
+              <tr>
+                <td>
+                  <i class="material-icons small iconify" data-icon="mdi:account-outline"></i>
+                </td>
+                <td>{{ invoice.billing_first_name }} {{invoice.billing_last_name }}</td>
+              </tr>
+              <tr>
+                <td rowspan="2">
+                  <i class="material-icons small iconify" data-icon="mdi:map-marker-outline"></i>
+                </td>
+                <td>{{ invoice.billing_address_1 }} {{ invoice.billing_address_2 }}</td>
+              </tr>
+              <tr>
+                <td>{{ invoice.billing_postcode }} {{ invoice.billing_city}}</td>
+              </tr>
+              <tr>
+                <td>
+                  <i class="material-icons small iconify" data-icon="mdi:email-outline"></i>
+                </td>
+                <td>
+                  <a href="mailto:{{ invoice.billing_email }}">{{ invoice.billing_email }}</a>
+                </td>
+              </tr>
+            </table>
+          </div>
+        </div>
+      </div>
+      <div class="col s12 m6">
+        <div class="card">
+          <div class="card-content">
+            <span class="card-title">{% trans "Payment" %}</span>
+            <table class="highlight">
+              <tr>
+                <td>
+                  <i class="material-icons iconify" data-icon="{{ invoice.get_variant_icon }}"></i>
+                </td>
+                <td>
+                  <select name="variant" disabled>
+                    {% for choice in invoice.get_variant_choices %}
+                      <option value="{{ choice.0 }}" {% if invoice.variant == choice.0 %}selected{% endif %}>{{ choice.1 }}</option>
+                    {% endfor %}
+                  </select>
+                </td>
+              </tr>
+              <tr>
+                <td>
+                  <i class="material-icons iconify" data-icon="{{ invoice.get_status_icon }}"></i>
+                </td>
+                <td>
+                  {{ invoice.get_status_display }}
+                </td>
+              </tr>
+              <tr>
+                <td>
+                  <i class="material-icons iconify" data-icon="mdi:calendar-end"></i>
+                </td>
+                <td>
+                  {{ invoice.due_date }}
+                </td>
+              </tr>
+            </table>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+
   {% if registration.person.guardians.all %}
   <h5>{% trans "Guardians / Parents "%}</h5>
   {% for person in registration.person.guardians.all %}
diff --git a/aleksis/apps/paweljong/urls.py b/aleksis/apps/paweljong/urls.py
index 361c2424ea7fde61338543959d69b584e2c5e6ac..a47f695f70ac5c038d3c0e4e16b795a3e1627fad 100644
--- a/aleksis/apps/paweljong/urls.py
+++ b/aleksis/apps/paweljong/urls.py
@@ -78,6 +78,11 @@ urlpatterns = [
     path("vouchers/<int:pk>/print", views.print_voucher, name="print_voucher_by_pk"),
     path("vouchers/", views.vouchers, name="vouchers"),
     path("event/lists/generate", views.generate_lists, name="generate_lists"),
+    path(
+        "event/registrations/<int:pk>/check_in",
+        views.CheckInRegistration.as_view(),
+        name="check_in_registration_by_pk",
+    ),
     path(
         "event/registrations/<int:pk>/retract",
         views.RetractRegistration.as_view(),
diff --git a/aleksis/apps/paweljong/views.py b/aleksis/apps/paweljong/views.py
index c7b240f5f485624bead3635b33517e9b4f7a0e78..3b1f54228b131fe5ce8cdce5d6d6b771ff3016e9 100644
--- a/aleksis/apps/paweljong/views.py
+++ b/aleksis/apps/paweljong/views.py
@@ -3,6 +3,7 @@ from typing import Optional
 from django.conf import settings
 from django.contrib.auth import get_user_model
 from django.contrib.syndication.views import Feed
+from django.core.exceptions import ValidationError
 from django.http import HttpRequest, HttpResponse
 from django.shortcuts import redirect, render
 from django.urls import reverse, reverse_lazy
@@ -28,7 +29,7 @@ from aleksis.core.models import Activity, Group, Person
 from aleksis.core.util import messages
 from aleksis.core.util.core_helpers import get_site_preferences, objectgetter_optional
 
-from .filters import EventFilter, VoucherFilter
+from .filters import EventFilter, EventRegistrationFilter, VoucherFilter
 from .forms import (
     EditEventForm,
     EditEventRegistrationForm,
@@ -208,6 +209,14 @@ class EventRegistrationDetailView(PermissionRequiredMixin, DetailView):
     def get_queryset(self):
         return EventRegistration.objects.all()
 
+    def get_context_data(self, *args, **kwargs):
+        context = super().get_context_data(*args, **kwargs)
+
+        invoice = self.get_object().get_invoice()
+        context["invoice"] = invoice
+
+        return context
+
 
 class EventRegistrationDeleteView(PermissionRequiredMixin, AdvancedDeleteView):
     """Delete view for registrations."""
@@ -891,7 +900,7 @@ class RetractRegistration(PermissionRequiredMixin, View):
         registration.retract()
         messages.success(self.request, _("Registration successfully retracted."))
 
-        return redirect("registrations")
+        return redirect("event_detail_by_name", slug=registration.event.slug)
 
 
 class EventDetailView(PermissionRequiredMixin, DetailView):
@@ -910,9 +919,12 @@ class EventDetailView(PermissionRequiredMixin, DetailView):
 
         context = super().get_context_data(**kwargs)
 
-        # Registrations table
         registrations = EventRegistration.objects.filter(event=self.object)
-        registrations_table = EventRegistrationsTable(registrations)
+        registrations_filter = EventRegistrationFilter(self.request.GET, queryset=registrations)
+        context["registrations_filter"] = registrations_filter
+
+        # Registrations table
+        registrations_table = EventRegistrationsTable(registrations_filter.qs)
         RequestConfig(self.request).configure(registrations_table)
         context["registrations_table"] = registrations_table
 
@@ -961,3 +973,19 @@ class ViewTerms(PermissionRequiredMixin, DetailView):
     permission_required = "paweljong.can_view_terms_rule"
     model = Event
     slug_field = "slug"
+
+
+class CheckInRegistration(PermissionRequiredMixin, View):
+
+    permission_required = "paweljong.change_registration_rule"
+
+    def get(self, *args, **kwargs):
+        registration = EventRegistration.objects.get(id=self.kwargs["pk"])
+
+        try:
+            registration.mark_checked_in()
+            messages.success(self.request, _("Successfully checked in."))
+        except ValidationError:
+            messages.error(self.request, _("Person is already checked in!"))
+
+        return redirect("event_detail_by_name", slug=registration.event.slug)