diff --git a/README.rst b/README.rst
index 980a407509f9611440bf784f8c8a5afb27762781..f5598bb695ae306143d31639f53d742ff18ddd22 100644
--- a/README.rst
+++ b/README.rst
@@ -17,6 +17,7 @@ Licence
 ::
 
   Copyright © 2022 Dominik George <dominik.george@teckids.org>
+  Copyright © 2022 Tom Teichler <tom.teichler@teckids.org>
 
   Licenced under the EUPL, version 1.2 or later
 
diff --git a/aleksis/apps/tezor/apps.py b/aleksis/apps/tezor/apps.py
index 6662ddaa7da0a9637322d066c8d6237f1f16ef96..e3973c6b47d191e5ef33081dcab67b2aa65311ad 100644
--- a/aleksis/apps/tezor/apps.py
+++ b/aleksis/apps/tezor/apps.py
@@ -13,7 +13,7 @@ class DefaultConfig(AppConfig):
         "Repository": "https://edugit.org/AlekSIS/onboarding//AlekSIS-App-Tezor",
     }
     licence = "EUPL-1.2+"
-    copyright_info = (([2022], "Dominik George", "dominik.george@teckids.org"),)
+    copyright_info = (([2022], "Dominik George", "dominik.george@teckids.org"), ([2022], "Tom Teichler", "tom.teichler@teckids.org"),)
 
     def ready(self):
         from django.conf import settings  # noqa
diff --git a/aleksis/apps/tezor/models/invoice.py b/aleksis/apps/tezor/models/invoice.py
index d73515bcc09e89d6bba788f3bd0913c7c4aa7dd1..b7c1eb5418bde62776942ccd74b0564a86b82601 100644
--- a/aleksis/apps/tezor/models/invoice.py
+++ b/aleksis/apps/tezor/models/invoice.py
@@ -46,6 +46,14 @@ class Invoice(BasePayment, PureDjangoModel):
     def get_purchased_items(self):
         return self.for_object.get_purchased_items()
 
+    def get_person(self):
+        if hasattr(self.for_object, "person"):
+            return self.for_object.person
+        elif hasattr(self.for_object, "get_person"):
+            return self.for_object.get_person()
+
+        return None
+
     class Meta:
         constraints = [
             models.UniqueConstraint(fields=["transaction_id", "group"], name="number_uniq_per_group")
diff --git a/aleksis/apps/tezor/predicates.py b/aleksis/apps/tezor/predicates.py
new file mode 100644
index 0000000000000000000000000000000000000000..4980926acb10b6d12db668e2601b0cb0443857df
--- /dev/null
+++ b/aleksis/apps/tezor/predicates.py
@@ -0,0 +1,24 @@
+from django.contrib.auth import get_user_model
+
+from rules import predicate
+
+from .models.invoice import Invoice
+
+@predicate
+def is_own_invoice(user: User, obj: Invoice):
+    """Predicate which checks if the invoice is linked to the current user."""
+    return obj.get_person() == user.person
+
+@predicate
+def has_no_payment_variant(user: User, obj: Invoice):
+    """Predicate which checks that the invoice has no payment variant."""
+    return not obj.variant
+
+@predicate
+def is_in_payment_status(status: str):
+    """Predicate which checks whether the invoice is in a specific state."""
+
+    def _predicate(user: User, obj: Invoice):
+        return obj.status == status
+
+    return _predicate
diff --git a/aleksis/apps/tezor/preferences.py b/aleksis/apps/tezor/preferences.py
index 9cf77979b91a0dd5809f0b961532537a4f965299..8a25f34519a9b34394ec9b126aa6d67651a12049 100644
--- a/aleksis/apps/tezor/preferences.py
+++ b/aleksis/apps/tezor/preferences.py
@@ -8,6 +8,18 @@ from aleksis.core.registries import site_preferences_registry
 payments = Section("payments", verbose_name=_("Payments"))
 
 
+@site_preferences_registry.register
+class EnablePledge(BooleanPreference):
+    """Allow payments to be made by anyone, not only invoice recipient."""
+
+    section = payments
+    name = "public_payments"
+    verbose_name = _("Public payments")
+    help_text = _("Allow anyone (including guests) to make payments. Basic invoice information will be visible to anyone who knows the invoice token.")
+    default = True
+    required = False
+
+
 @site_preferences_registry.register
 class SofortAPIID(StringPreference):
     """Sofort payment backend - API ID."""
diff --git a/aleksis/apps/tezor/rules.py b/aleksis/apps/tezor/rules.py
index 98aa9de4d49b81646950b1704128336f68271a57..b82cc5b6d0cbfeb4d105f597231641f9740b6c3f 100644
--- a/aleksis/apps/tezor/rules.py
+++ b/aleksis/apps/tezor/rules.py
@@ -1,9 +1,11 @@
 import rules
+from payments import PaymentStatus
+
+from aleksis.core.util.predicates import has_person, has_global_perm, has_any_object, has_object_perm, is_site_preference_set
 
 from .models.base import Client
 from .models.invoice import Invoice, InvoiceGroup
-
-from aleksis.core.util.predicates import has_person, has_global_perm, has_any_object, has_object_perm
+from .predicates import has_no_payment_variant, is_own_invoice, is_in_payment_status
 
 # View clients
 view_clients_predicate = has_person & (
@@ -65,8 +67,22 @@ delete_invoice_groups_predicate = has_person & (
 )
 rules.add_perm("tezor.delete_invoice_groups_rule", delete_invoice_groups_predicate)
 
+# Display invoice billing information
+display_billing_predicate = has_person & (is_own_invoice | has_global_perm("tezor.display_billing") | has_object_perm("tezor.display_billing"))
+rules.add_perm("tezor.display_billing_rule", display_billing_predicate)
+
+# Display invoice purchased items
+display_purchased_items_predicate = has_person & (is_own_invoice | has_global_perm("tezor.display_purchased_items") | has_object_perm("tezor.display_purchased_items"))
+rules.add_perm("tezor.display_purchased_items_rule", display_purchased_items_predicate)
+
+# Change payment variant
+change_payment_variant_predicate = has_person & is_in_payment_status(PaymentStatus.WAITING) & ((is_own_invoice & has_no_payment_variant) | has_global_perm("tezor.change_payment_variant") | has_object_perm("tezor.change_payment_variant"))
+rules.add_perm("tezor.change_payment_variant", change_payment_variant_predicate)
+
+# Start payment
+do_payment_predicate = has_person & (is_in_payment_status(PaymentStatus.WAITING) | is_in_payment_status(PaymentStatus.INPUT) | is_in_payment_status(PaymentStatus.ERROR) | is_in_payment_status(PaymentStatus.REJECTED)) & ((is_own_invoice | is_site_preference_set("payments", "public_payments")) | has_global_perm("tezor.do_payment") | has_object_perm("tezor.do_payment"))
+rules.add_perm("tezor.do_payment", do_payment_predicate)
+
 # View invoice
-view_invoice_predicate = has_person & (
-    has_global_perm("tezor.view_invoice") | has_object_perm("tezor.view_invoice")
-)
+view_invoice_predicate = is_own_invoice | is_site_preference_set("payments", "public_payments") | has_global_perm("tezor.view_invoice") | has_object_perm("tezor.view_invoice")
 rules.add_perm("tezor.view_invoice_rule", view_invoice_predicate)
diff --git a/pyproject.toml b/pyproject.toml
index c0bd665b0a90645fa92c1f14eb33006cc054f903..155e9e96a0c2bffd77b41429360e194f04f27770 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -12,7 +12,7 @@ include = [
 ]
 
 description = "AlekSIS (School Information System) — App Tezor (account and payment system)"
-authors = ["Dominik George <dominik.george@teckids.org>"]
+authors = ["Dominik George <dominik.george@teckids.org>", "Tom Teichler <tom.teichler@teckids.org>"]
 license = "EUPL-1.2-or-later"
 homepage = "https://aleksis.org"
 repository = "https://edugit.org/AlekSIS/onboarding//AlekSIS-App-Tezor"