diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 3233b185587b003f4550625059d08bd80eb0eaba..32dbe404414d0a0f687a2c026266bf263e8996a7 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -6,6 +6,20 @@ All notable changes to this project will be documented in this file.
 The format is based on `Keep a Changelog`_,
 and this project adheres to `Semantic Versioning`_.
 
+`1.2`_ - 2022-03-20
+-------------------
+
+Added
+-----
+
+* Update django-payments to 1.0
+* Update invoice if person changes
+
+Changed
+-------
+
+* Always set person on Invoice objects
+
 `1.1.1`_ - 2022-03-15
 ---------------------
 
@@ -72,3 +86,4 @@ Added
 .. _1.0.2: https://edugit.org/AlekSIS/onboarding//AlekSIS-App-Tezor/-/tags/1.0.2
 .. _1.1: https://edugit.org/AlekSIS/onboarding//AlekSIS-App-Tezor/-/tags/1.1
 .. _1.1.1: https://edugit.org/AlekSIS/onboarding//AlekSIS-App-Tezor/-/tags/1.1.1
+.. _1.2 https://edugit.org/AlekSIS/onboarding//AlekSIS-App-Tezor/-/tags/1.2
diff --git a/aleksis/apps/tezor/apps.py b/aleksis/apps/tezor/apps.py
index 0515dd4192e5a90a82a44e53a30920c1bc3cfd85..e66d87b96dc1ededc9efdc7f98ecb805a7d3aa77 100644
--- a/aleksis/apps/tezor/apps.py
+++ b/aleksis/apps/tezor/apps.py
@@ -1,8 +1,4 @@
-from django.apps import apps
-from django.db import OperationalError
-
 from aleksis.core.util.apps import AppConfig
-from aleksis.core.util.core_helpers import get_site_preferences
 
 
 class DefaultConfig(AppConfig):
@@ -20,57 +16,4 @@ class DefaultConfig(AppConfig):
     )
 
     def ready(self):
-        from django.conf import settings  # noqa
-
-        settings.PAYMENT_VARIANTS = {}
-
-        for app_config in apps.app_configs.values():
-            if hasattr(app_config, "get_payment_variants"):
-                try:
-                    variants = app_config.get_payment_variants()
-                except OperationalError:
-                    # Non-fatal, database is not yet ready
-                    continue
-                for name, config in variants.items():
-                    if name not in settings.PAYMENT_VARIANTS:
-                        settings.PAYMENT_VARIANTS[name] = config
-
-    def get_payment_variants(self):
-        prefs = get_site_preferences()
-        variants = {}
-
-        if prefs["payments__sofort_api_id"]:
-            variants["sofort"] = (
-                "payments.sofort.SofortProvider",
-                {
-                    "id": prefs["payments__sofort_api_id"],
-                    "key": prefs["payments__sofort_api_key"],
-                    "project_id": prefs["payments__sofort_project_id"],
-                    "endpoint": "https://api.sofort.com/api/xml",
-                },
-            )
-
-        if prefs["payments__paypal_client_id"]:
-            variants["paypal"] = (
-                "payments.paypal.PaypalProvider",
-                {
-                    "client_id": prefs["payments__paypal_client_id"],
-                    "secret": prefs["payments__paypal_secret"],
-                    "capture": not prefs["payments__paypal_capture"],
-                    "endpoint": "https://api.paypal.com",
-                },
-            )
-
-        if prefs["payments__pledge_enabled"]:
-            variants["pledge"] = ("djp_sepa.providers.PaymentPledgeProvider", {})
-
-        if prefs["payments__sdd_creditor_identifier"]:
-            variants["sdd"] = (
-                "djp_sepa.providers.DirectDebitProvider",
-                {
-                    "creditor": prefs["payments__sdd_creditor"],
-                    "creditor_identifier": prefs["payments__sdd_creditor_identifier"],
-                },
-            )
-
-        return variants
+        from .signals import update_on_person_change  # noqa
diff --git a/aleksis/apps/tezor/filters.py b/aleksis/apps/tezor/filters.py
index 397883fff0a581ef936fa06d31d268070923ebdc..2afa6361751917dfdb75ee5c723cb01669e7469a 100644
--- a/aleksis/apps/tezor/filters.py
+++ b/aleksis/apps/tezor/filters.py
@@ -8,14 +8,12 @@ from .models.invoice import Invoice
 class InvoicesFilter(FilterSet):
     variant = ChoiceFilter(choices=Invoice.get_variant_choices())
     status = ChoiceFilter(choices=PaymentStatus.CHOICES)
-   
-    
+
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
         self.form.layout = Layout(
             Row("variant", "status"),
         )
-        
 
     class Meta:
         models = Invoice
diff --git a/aleksis/apps/tezor/forms.py b/aleksis/apps/tezor/forms.py
index 71b304dbd3060a47536de47a2b09763725dd3a8d..1d2799c5b747abd0dbc35be32618179db2fbf246 100644
--- a/aleksis/apps/tezor/forms.py
+++ b/aleksis/apps/tezor/forms.py
@@ -1,6 +1,6 @@
 from django.utils.translation import gettext as _
 
-from material import Layout, Row
+from material import Fieldset, Layout, Row
 
 from aleksis.core.forms import ActionForm
 from aleksis.core.mixins import ExtensibleForm
@@ -27,7 +27,29 @@ class InvoicesActionForm(ActionForm):
 class EditClientForm(ExtensibleForm):
     """Form to create or edit clients."""
 
-    layout = Layout("name", "email")
+    layout = Layout(
+        Row("name", "email"),
+        Fieldset(
+            _("Payment pledge"),
+            Row("pledge_enabled"),
+        ),
+        Fieldset(
+            _("Sofort / Klarna"),
+            "sofort_enabled",
+            Row("sofort_api_id", "sofort_api_key", "sofort_project_id"),
+        ),
+        Fieldset(
+            _("PayPal"),
+            "paypal_enabled",
+            Row("paypal_client_id", "paypal_secret", "paypal_capture"),
+        ),
+        Fieldset(
+            _("Debit"),
+            "sdd_enabled",
+            Row("sdd_creditor", "sdd_creditor_identifier"),
+            Row("sdd_iban", "sdd_bic"),
+        ),
+    )
 
     class Meta:
         model = Client
diff --git a/aleksis/apps/tezor/migrations/0007_client_payment_variants.py b/aleksis/apps/tezor/migrations/0007_client_payment_variants.py
new file mode 100644
index 0000000000000000000000000000000000000000..26e258ef53333dc9644b69f289b2d54f6947e9a1
--- /dev/null
+++ b/aleksis/apps/tezor/migrations/0007_client_payment_variants.py
@@ -0,0 +1,134 @@
+# Generated by Django 3.2.12 on 2022-03-19 22:21
+
+import warnings
+
+import django.core.validators
+from django.db import migrations, models
+import localflavor.generic.models
+
+
+def configure_clients(apps, schema_editor):
+    db_alias = schema_editor.connection.alias
+
+    Client = apps.get_model("tezor", "Client")
+    SitePreferenceModel = apps.get_model("core", "SitePreferenceModel")
+
+    fields = ["sofort_api_id", "sofort_api_key", "sofort_project_id", "paypal_client_id", "paypal_secret", "paypal_capture", "pledge_enabled", "sdd_creditor", "sdd_creditor_identifier"]
+    values = {}
+    for field in fields:
+        try:
+            pref = SitePreferenceModel.objects.using(db_alias).get(section="payments", name=field)
+        except SitePreferenceModel.DoesNotExist:
+            continue
+
+        value = pref.raw_value
+        if value == "True":
+            value = True
+        elif value == "False":
+            value = False
+
+        values[field] = value
+        if not "enabled" in field:
+            provider = field.split("_")[0]
+            values[f"{provider}_enabled"] = True
+
+    for variant in ("sdd", "pledge", "paypal", "sofort"):
+        if values.get(f"{variant}_enabled", False):
+            for field in Client._meta.fields:
+                if field.name.startswith(f"{variant}_") and values.get(field.name, "") == "":
+                    values[f"{variant}_enabled"] = False
+                    warnings.warn(f"Payment variant {variant} enabled but {field.name} not configured!")
+
+    Client.objects.update(**values)
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('tezor', '0006_invoice_constraints'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='client',
+            name='paypal_capture',
+            field=models.BooleanField(default=False, verbose_name='Use PayPal Authorize & Capture'),
+        ),
+        migrations.AddField(
+            model_name='client',
+            name='paypal_client_id',
+            field=models.CharField(blank=True, max_length=255, verbose_name='PayPal client ID'),
+        ),
+        migrations.AddField(
+            model_name='client',
+            name='paypal_enabled',
+            field=models.BooleanField(default=False, verbose_name='PayPal enabled'),
+        ),
+        migrations.AddField(
+            model_name='client',
+            name='paypal_secret',
+            field=models.CharField(blank=True, max_length=255, verbose_name='PayPal secret'),
+        ),
+        migrations.AddField(
+            model_name='client',
+            name='pledge_enabled',
+            field=models.BooleanField(default=False, verbose_name='Pledge enabled'),
+        ),
+        migrations.AddField(
+            model_name='client',
+            name='sdd_bic',
+            field=localflavor.generic.models.BICField(blank=True, max_length=11, verbose_name='BIC/SWIFT code of bank'),
+        ),
+        migrations.AddField(
+            model_name='client',
+            name='sdd_creditor',
+            field=models.CharField(blank=True, max_length=255, verbose_name='SEPA Direct Debit - Creditor name'),
+        ),
+        migrations.AddField(
+            model_name='client',
+            name='sdd_creditor_identifier',
+            field=models.CharField(blank=True, max_length=35, validators=[django.core.validators.RegexValidator('^[A-Z]{2}[0-9]{2}[A-Z0-9]{1,31}$')], verbose_name='SEPA Direct Debit - Creditor identifier'),
+        ),
+        migrations.AddField(
+            model_name='client',
+            name='sdd_enabled',
+            field=models.BooleanField(default=False, verbose_name='Debit enabled'),
+        ),
+        migrations.AddField(
+            model_name='client',
+            name='sdd_iban',
+            field=localflavor.generic.models.IBANField(blank=True, include_countries=None, max_length=34, use_nordea_extensions=False, verbose_name='IBAN of bank account'),
+        ),
+        migrations.AddField(
+            model_name='client',
+            name='sofort_api_id',
+            field=models.CharField(blank=True, max_length=255, verbose_name='Sofort / Klarna API ID'),
+        ),
+        migrations.AddField(
+            model_name='client',
+            name='sofort_api_key',
+            field=models.CharField(blank=True, max_length=255, verbose_name='Sofort / Klarna API key'),
+        ),
+        migrations.AddField(
+            model_name='client',
+            name='sofort_enabled',
+            field=models.BooleanField(default=False, verbose_name='Sofort / Klarna enabled'),
+        ),
+        migrations.AddField(
+            model_name='client',
+            name='sofort_project_id',
+            field=models.CharField(blank=True, max_length=255, verbose_name='Sofort / Klarna Project ID'),
+        ),
+        migrations.AddConstraint(
+            model_name='client',
+            constraint=models.CheckConstraint(check=models.Q(models.Q(('sofort_enabled', True), models.Q(('sofort_api_id', ''), _negated=True), models.Q(('sofort_api_key', ''), _negated=True), models.Q(('sofort_project_id', ''), _negated=True)), ('sofort_enabled', False), _connector='OR'), name='sofort_enabled_configured'),
+        ),
+        migrations.AddConstraint(
+            model_name='client',
+            constraint=models.CheckConstraint(check=models.Q(models.Q(('sdd_enabled', True), models.Q(('sdd_creditor', ''), _negated=True), models.Q(('sdd_creditor_identifier', ''), _negated=True), models.Q(('sdd_iban', ''), _negated=True), models.Q(('sdd_bic', ''), _negated=True)), ('sdd_enabled', False), _connector='OR'), name='sdd_enabled_configured'),
+        ),
+        migrations.AddConstraint(
+            model_name='client',
+            constraint=models.CheckConstraint(check=models.Q(models.Q(('paypal_enabled', True), models.Q(('paypal_client_id', ''), _negated=True), models.Q(('paypal_secret', ''), _negated=True)), ('paypal_enabled', False), _connector='OR'), name='paypal_enabled_configured'),
+        ),
+        migrations.RunPython(configure_clients),
+    ]
diff --git a/aleksis/apps/tezor/migrations/0008_always_set_person.py b/aleksis/apps/tezor/migrations/0008_always_set_person.py
new file mode 100644
index 0000000000000000000000000000000000000000..b6fcebb0e43bfd354cb8b8d5f9809fc2a7fda70d
--- /dev/null
+++ b/aleksis/apps/tezor/migrations/0008_always_set_person.py
@@ -0,0 +1,27 @@
+# Generated by Django 3.2.12 on 2022-03-20 19:29
+
+from django.db import migrations
+
+
+def set_person_on_invoices(apps, schema_editor):
+
+    Invoice = apps.get_model("tezor", "Invoice")
+
+    for invoice in Invoice.objects.filter(person__isnull=True, for_object_id__isnull=False):
+        person = invoice.for_object.get_person()
+        invoice.person=person
+        invoice.save()
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('tezor', '0007_client_payment_variants'),
+    ]
+
+    operations = [
+        migrations.RemoveConstraint(
+            model_name='invoice',
+            name='object_or_person',
+        ),
+        migrations.RunPython(set_person_on_invoices),
+    ]
diff --git a/aleksis/apps/tezor/migrations/0009_invoice_billing_phone.py b/aleksis/apps/tezor/migrations/0009_invoice_billing_phone.py
new file mode 100644
index 0000000000000000000000000000000000000000..650e565495e7f88cdfea8b0a8ca254267c238d69
--- /dev/null
+++ b/aleksis/apps/tezor/migrations/0009_invoice_billing_phone.py
@@ -0,0 +1,19 @@
+# Generated by Django 3.2.12 on 2022-03-20 21:51
+
+from django.db import migrations
+import phonenumber_field.modelfields
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('tezor', '0008_always_set_person'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='invoice',
+            name='billing_phone',
+            field=phonenumber_field.modelfields.PhoneNumberField(blank=True, max_length=128, region=None),
+        ),
+    ]
diff --git a/aleksis/apps/tezor/models/base.py b/aleksis/apps/tezor/models/base.py
index 85f85ccf9f3d67cc362c6704852c81602f958101..d44902ea81627a68c07197a309bd8592c6800dc0 100644
--- a/aleksis/apps/tezor/models/base.py
+++ b/aleksis/apps/tezor/models/base.py
@@ -1,17 +1,102 @@
+from django.core.validators import RegexValidator
 from django.db import models
+from django.db.models import Q
 from django.utils.translation import gettext_lazy as _
 
+from localflavor.generic.models import BICField, IBANField
+
 from aleksis.core.mixins import ExtensibleModel
 
 
 class Client(ExtensibleModel):
+    VARIANT_DISPLAY = {
+        "paypal": (_("PayPal"), "logos:paypal"),
+        "sofort": (_("Klarna / Sofort"), "simple-icons:klarna"),
+        "pledge": (_("Payment pledge / manual payment"), "mdi:hand-coin"),
+        "sdd": (_("SEPA Direct Debit"), "mdi:bank-transfer"),
+    }
     name = models.CharField(verbose_name=_("Name"), max_length=255)
     email = models.EmailField(verbose_name=_("Email"))
 
+    sofort_enabled = models.BooleanField(verbose_name=_("Sofort / Klarna enabled"), default=False)
+    sofort_api_id = models.CharField(
+        verbose_name=_("Sofort / Klarna API ID"), blank=True, max_length=255
+    )
+    sofort_api_key = models.CharField(
+        verbose_name=_("Sofort / Klarna API key"), blank=True, max_length=255
+    )
+    sofort_project_id = models.CharField(
+        verbose_name=_("Sofort / Klarna Project ID"), blank=True, max_length=255
+    )
+
+    paypal_enabled = models.BooleanField(verbose_name=_("PayPal enabled"), default=False)
+    paypal_client_id = models.CharField(
+        verbose_name=_("PayPal client ID"), blank=True, max_length=255
+    )
+    paypal_secret = models.CharField(verbose_name=_("PayPal secret"), blank=True, max_length=255)
+    paypal_capture = models.BooleanField(
+        verbose_name=_("Use PayPal Authorize & Capture"), default=False
+    )
+
+    sdd_enabled = models.BooleanField(verbose_name=_("Debit enabled"), default=False)
+    sdd_creditor = models.CharField(
+        verbose_name=_("SEPA Direct Debit - Creditor name"), blank=True, max_length=255
+    )
+    sdd_creditor_identifier = models.CharField(
+        verbose_name=_("SEPA Direct Debit - Creditor identifier"),
+        blank=True,
+        max_length=35,
+        validators=[RegexValidator("^[A-Z]{2}[0-9]{2}[A-Z0-9]{1,31}$")],
+    )
+    sdd_iban = IBANField(verbose_name=_("IBAN of bank account"), blank=True)
+    sdd_bic = BICField(verbose_name=_("BIC/SWIFT code of bank"), blank=True)
+
+    pledge_enabled = models.BooleanField(verbose_name=_("Pledge enabled"), default=False)
+
     class Meta:
         constraints = [
-            models.UniqueConstraint(fields=["name", "site"], name="uniq_client_per_site")
+            models.UniqueConstraint(fields=["name", "site"], name="uniq_client_per_site"),
+            models.CheckConstraint(
+                check=(
+                    (
+                        Q(sofort_enabled=True)
+                        & ~Q(sofort_api_id="")
+                        & ~Q(sofort_api_key="")
+                        & ~Q(sofort_project_id="")
+                    )
+                    | Q(sofort_enabled=False)
+                ),
+                name="sofort_enabled_configured",
+            ),
+            models.CheckConstraint(
+                check=(
+                    (
+                        Q(sdd_enabled=True)
+                        & ~Q(sdd_creditor="")
+                        & ~Q(sdd_creditor_identifier="")
+                        & ~Q(sdd_iban="")
+                        & ~Q(sdd_bic="")
+                    )
+                    | Q(sdd_enabled=False)
+                ),
+                name="sdd_enabled_configured",
+            ),
+            models.CheckConstraint(
+                check=(
+                    (Q(paypal_enabled=True) & ~Q(paypal_client_id="") & ~Q(paypal_secret=""))
+                    | Q(paypal_enabled=False)
+                ),
+                name="paypal_enabled_configured",
+            ),
         ]
 
     def __str__(self) -> str:
         return self.name
+
+    def get_variant_choices(self=None):
+        choices = []
+        for variant in Client.VARIANT_DISPLAY.keys():
+            if self and not getattr(self, f"{variant}_enabled"):
+                continue
+            choices.append((variant, Client.VARIANT_DISPLAY[variant][0]))
+        return choices
diff --git a/aleksis/apps/tezor/models/invoice.py b/aleksis/apps/tezor/models/invoice.py
index 08805fedd809dcd57ae2d0bf507e863bc7d51426..8e786ac4f4157736cb8fec25e7eb7d860c4742c3 100644
--- a/aleksis/apps/tezor/models/invoice.py
+++ b/aleksis/apps/tezor/models/invoice.py
@@ -1,8 +1,6 @@
-from django.conf import settings
 from django.contrib.contenttypes.fields import GenericForeignKey
 from django.contrib.contenttypes.models import ContentType
 from django.db import models
-from django.db.models import Q
 from django.shortcuts import reverse
 from django.utils.translation import gettext_lazy as _
 
@@ -33,6 +31,12 @@ class InvoiceGroup(ExtensibleModel):
     def __str__(self) -> str:
         return self.name
 
+    def get_variant_choices(self=None):
+        if self and self.client:
+            return self.client.get_variant_choices()
+        else:
+            return Client.get_variant_choices()
+
     class Meta:
         constraints = [
             models.UniqueConstraint(fields=["client", "name"], name="group_uniq_per_client")
@@ -40,12 +44,6 @@ class InvoiceGroup(ExtensibleModel):
 
 
 class Invoice(BasePayment, PureDjangoModel):
-    VARIANT_DISPLAY = {
-        "paypal": (_("PayPal"), "logos:paypal"),
-        "sofort": (_("Klarna / Sofort"), "simple-icons:klarna"),
-        "pledge": (_("Payment pledge / manual payment"), "mdi:hand-coin"),
-        "sdd": (_("SEPA Direct Debit"), "mdi:bank-transfer"),
-    }
     STATUS_ICONS = {
         PaymentStatus.WAITING: "mdi:cash-lock-open",
         PaymentStatus.INPUT: "mdi:cash-lock-open",
@@ -86,12 +84,13 @@ class Invoice(BasePayment, PureDjangoModel):
     def save(self, *args, **kwargs):
         if self.person:
             person = self.person
-        elif self.for_object and getattr(self.for_object, "person", None):
-            person = self.for_object.person
+        elif self.for_object and getattr(self.for_object, "get_person", None):
+            person = self.for_object.get_person()
         else:
             person = None
 
         if person:
+            self.person = person
             if not self.billing_last_name:
                 self.billing_last_name = person.last_name
             if not self.billing_first_name:
@@ -105,18 +104,17 @@ class Invoice(BasePayment, PureDjangoModel):
 
         super().save(*args, **kwargs)
 
-    @classmethod
-    def get_variant_choices(cls):
-        choices = []
-        for variant in settings.PAYMENT_VARIANTS.keys():
-            choices.append((variant, cls.VARIANT_DISPLAY[variant][0]))
-        return choices
+    def get_variant_choices(self=None):
+        if self and self.group:
+            return self.group.get_variant_choices()
+        else:
+            return InvoiceGroup.get_variant_choices()
 
     def get_variant_name(self):
-        return self.__class__.VARIANT_DISPLAY[self.variant][0]
+        return Client.VARIANT_DISPLAY[self.variant][0]
 
     def get_variant_icon(self):
-        return self.__class__.VARIANT_DISPLAY[self.variant][1]
+        return Client.VARIANT_DISPLAY[self.variant][1]
 
     def get_status_icon(self):
         return self.__class__.STATUS_ICONS[self.status]
@@ -142,13 +140,6 @@ class Invoice(BasePayment, PureDjangoModel):
     class Meta:
         constraints = [
             models.UniqueConstraint(fields=["number", "group"], name="number_uniq_per_group"),
-            models.CheckConstraint(
-                check=(
-                    (Q(for_object_id__isnull=True) & Q(person__isnull=False))
-                    | (Q(for_object_id__isnull=False) & Q(person__isnull=True))
-                ),
-                name="object_or_person",
-            ),
         ]
         permissions = (("send_invoice_email", _("Can send invoice by email")),)
 
diff --git a/aleksis/apps/tezor/preferences.py b/aleksis/apps/tezor/preferences.py
index 2535a9be0ede9596c46d69af9e942fbf7a2f4567..6a69eefda418246355c4f931ae647ed08d035ace 100644
--- a/aleksis/apps/tezor/preferences.py
+++ b/aleksis/apps/tezor/preferences.py
@@ -1,7 +1,7 @@
 from django.utils.translation import gettext_lazy as _
 
 from dynamic_preferences.preferences import Section
-from dynamic_preferences.types import BooleanPreference, StringPreference
+from dynamic_preferences.types import BooleanPreference
 
 from aleksis.core.registries import site_preferences_registry
 
@@ -23,72 +23,6 @@ class PublicPayments(BooleanPreference):
     required = False
 
 
-@site_preferences_registry.register
-class SofortAPIID(StringPreference):
-    """Sofort payment backend - API ID."""
-
-    section = payments
-    name = "sofort_api_id"
-    verbose_name = _("Sofort / Klarna - API ID")
-    default = ""
-    required = False
-
-
-@site_preferences_registry.register
-class SofortAPIKey(StringPreference):
-    """Sofort payment backend - API key."""
-
-    section = payments
-    name = "sofort_api_key"
-    verbose_name = _("Sofort / Klarna - API Key")
-    default = ""
-    required = False
-
-
-@site_preferences_registry.register
-class SofortProjectID(StringPreference):
-    """Sofort payment backend - project ID."""
-
-    section = payments
-    name = "sofort_project_id"
-    verbose_name = _("Sofort / Klarna - Project ID")
-    default = ""
-    required = False
-
-
-@site_preferences_registry.register
-class PaypalClientID(StringPreference):
-    """PayPal payment backend - client ID."""
-
-    section = payments
-    name = "paypal_client_id"
-    verbose_name = _("PayPal - Client ID")
-    default = ""
-    required = False
-
-
-@site_preferences_registry.register
-class PaypalSecret(StringPreference):
-    """PayPal payment backend - secret."""
-
-    section = payments
-    name = "paypal_secret"
-    verbose_name = _("PayPal - Secret")
-    default = ""
-    required = False
-
-
-@site_preferences_registry.register
-class PaypalCapture(BooleanPreference):
-    """PayPal payment backend - use Authorize & Capture."""
-
-    section = payments
-    name = "paypal_capture"
-    verbose_name = _("PayPal - Use Authorize & Capture")
-    default = False
-    required = False
-
-
 @site_preferences_registry.register
 class EnablePledge(BooleanPreference):
     """Payment pledge payment backend - enable or not."""
@@ -101,22 +35,11 @@ class EnablePledge(BooleanPreference):
 
 
 @site_preferences_registry.register
-class SDDCreditor(StringPreference):
-    """SEPA direct debit backend - creditor name."""
+class UpdateOnPersonChange(BooleanPreference):
+    """Update Invoices if person data changes."""
 
     section = payments
-    name = "sdd_creditor"
-    verbose_name = _("SEPA Direct Debit - Creditor name")
-    default = ""
-    required = False
-
-
-@site_preferences_registry.register
-class SDDCreditorIdentifier(StringPreference):
-    """SEPA direct debit backend - creditor identifier."""
-
-    section = payments
-    name = "sdd_creditor_identifier"
-    verbose_name = _("SEPA Direct Debit - Creditor identifier")
-    default = ""
+    name = "update_on_person_change"
+    verbose_name = _("Update Invoices if person data changes")
+    default = True
     required = False
diff --git a/aleksis/apps/tezor/settings.py b/aleksis/apps/tezor/settings.py
index e7277712f384d2170c04e46ce10634a01ac71785..f3580c25dc797424edfa408c87f75d0b4370830e 100644
--- a/aleksis/apps/tezor/settings.py
+++ b/aleksis/apps/tezor/settings.py
@@ -1,5 +1,6 @@
 INSTALLED_APPS = ["payments", "djp_sepa"]
 
 PAYMENT_MODEL = "tezor.Invoice"
+PAYMENT_VARIANT_FACTORY = "aleksis.apps.tezor.util.invoice.provider_factory"
 
-overrides = ["PAYMENT_MODEL"]
+overrides = ["PAYMENT_MODEL", "PAYMENT_VARIANT_FACTORY"]
diff --git a/aleksis/apps/tezor/signals.py b/aleksis/apps/tezor/signals.py
new file mode 100644
index 0000000000000000000000000000000000000000..a5750b7ae2a982b8b7276267c6236b9204cd4801
--- /dev/null
+++ b/aleksis/apps/tezor/signals.py
@@ -0,0 +1,21 @@
+from django.db.models.signals import post_save
+from django.dispatch import receiver
+
+from aleksis.core.models import Person
+from aleksis.core.util.core_helpers import get_site_preferences
+
+from .models.invoice import Invoice
+
+
+@receiver(post_save, sender=Person)
+def update_on_person_change(sender, instance, **kwargs):
+
+    if get_site_preferences()["payments__update_on_person_change"]:
+        Invoice.objects.filter(person=instance, status__in=("waiting", "input", "preauth")).update(
+            billing_email=instance.email,
+            billing_first_name=instance.first_name,
+            billing_last_name=instance.last_name,
+            billing_address_1=f"{instance.street} {instance.housenumber}",
+            billing_postcode=instance.postal_code,
+            billing_city=instance.place,
+        )
diff --git a/aleksis/apps/tezor/util/__init__.py b/aleksis/apps/tezor/util/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/aleksis/apps/tezor/util/invoice.py b/aleksis/apps/tezor/util/invoice.py
new file mode 100644
index 0000000000000000000000000000000000000000..d8f58820406653376a3dc0609f87bfe2bf57d520
--- /dev/null
+++ b/aleksis/apps/tezor/util/invoice.py
@@ -0,0 +1,43 @@
+def provider_factory(variant, payment=None):
+    from djp_sepa.providers import DirectDebitProvider, PaymentPledgeProvider  # noqa
+    from payments.paypal import PaypalProvider  # noqa
+    from payments.sofort import SofortProvider  # noqa
+
+    if not payment:
+        raise KeyError("Could not configure payment provider without a payment.")
+    if not payment.group:
+        raise KeyError(
+            "Could not configure payment provider for a payment without an invoice group."
+        )
+    if not payment.group.client:
+        raise KeyError(
+            "Could not configure payment provider for an invoice group without a client."
+        )
+
+    client = payment.group.client
+
+    if variant == "sofort" and client.sofort_enabled:
+        return SofortProvider(
+            key=client.sofort_api_key, id=client.sofort_api_id, project_id=client.sofort_project_id
+        )
+
+    if variant == "paypal" and client.paypal_enabled:
+        return PaypalProvider(
+            client_id=client.paypal_client_id,
+            secret=client.paypal_secret,
+            capture=client.paypal_capture,
+            endpoint="https://api.paypal.com",
+        )
+
+    if variant == "pledge" and client.pledge_enabled:
+        return PaymentPledgeProvider()
+
+    if variant == "sdd" and client.sdd_enabled:
+        return DirectDebitProvider(
+            creditor=client.sdd_creditor,
+            creditor_identifier=client.sdd_creditor_identifier,
+            iban=client.sdd_iban,
+            bic=client.sdd_bic,
+        )
+
+    return KeyError("Provider not found or not configured for client.")
diff --git a/aleksis/apps/tezor/views.py b/aleksis/apps/tezor/views.py
index 981b5dd7d6459b7b40ea250d0f28af336fadfb24..c7c52c455d16f77e68e284376411db6a4965bd96 100644
--- a/aleksis/apps/tezor/views.py
+++ b/aleksis/apps/tezor/views.py
@@ -1,4 +1,3 @@
-from django.conf import settings
 from django.core.exceptions import PermissionDenied, SuspiciousOperation
 from django.shortcuts import get_object_or_404, redirect, render
 from django.urls import reverse, reverse_lazy
@@ -48,7 +47,7 @@ class DoPaymentView(PermissionRequiredMixin, View):
         new_variant = request.GET.get("variant", None)
         if new_variant:
             if request.user.has_perm("tezor.change_payment_variant", self.object):
-                if new_variant in settings.PAYMENT_VARIANTS:
+                if new_variant in dict(self.object.get_variant_choices()).keys():
                     self.object.variant = new_variant
                     self.object.save()
                 else:
@@ -145,7 +144,9 @@ class InvoiceGroupDetailView(PermissionRequiredMixin, DetailView):
     def post(self, request, *args, **kwargs):
         r = super().get(request, *args, **kwargs)
         if self.invoices_action_form.is_valid():
-            action = self.invoices_action_form._get_actions_dict()[self.invoices_action_form.cleaned_data["action"]]
+            action = self.invoices_action_form._get_actions_dict()[
+                self.invoices_action_form.cleaned_data["action"]
+            ]
             if request.user.has_perm(action.permission):
                 self.invoices_action_form.execute()
         return r
@@ -162,7 +163,9 @@ class InvoiceGroupDetailView(PermissionRequiredMixin, DetailView):
         RequestConfig(self.request).configure(invoices_table)
         context["invoices_table"] = invoices_table
 
-        self.invoices_action_form = InvoicesActionForm(self.request, self.request.POST or None, queryset=invoices)
+        self.invoices_action_form = InvoicesActionForm(
+            self.request, self.request.POST or None, queryset=invoices
+        )
         context["action_form"] = self.invoices_action_form
 
         return context
diff --git a/pyproject.toml b/pyproject.toml
index 52fcef9c1c803d42532ece3621ae08a3e39eedd2..e888291ee7889b3902944b3e8dd57b9cbba38633 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
 [tool.poetry]
 name = "AlekSIS-App-Tezor"
-version = "1.1.1"
+version = "1.2.1.dev0"
 packages = [
     { include = "aleksis" }
 ]
@@ -31,7 +31,7 @@ secondary = true
 [tool.poetry.dependencies]
 python = "^3.9"
 aleksis-core = "^2.8.1.dev0"
-django-payments = { version = "^0.15.1", extras = ["sofort"] }
+django-payments = { version = "^1.0.0", extras = ["sofort"] }
 django-payments-sepa = "^1.0.1"
 
 [tool.poetry.dev-dependencies]