Skip to content
Snippets Groups Projects
Commit 143b60b2 authored by Tom Teichler's avatar Tom Teichler :beers:
Browse files

Merge branch 'master' into 8-add-my-invoices-view

parents a35d9457 5e691da5
No related branches found
No related tags found
1 merge request!14Resolve "Add "my invoices" view"
Showing
with 404 additions and 179 deletions
...@@ -6,6 +6,20 @@ All notable changes to this project will be documented in this file. ...@@ -6,6 +6,20 @@ All notable changes to this project will be documented in this file.
The format is based on `Keep a Changelog`_, The format is based on `Keep a Changelog`_,
and this project adheres to `Semantic Versioning`_. 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 `1.1.1`_ - 2022-03-15
--------------------- ---------------------
...@@ -72,3 +86,4 @@ Added ...@@ -72,3 +86,4 @@ Added
.. _1.0.2: https://edugit.org/AlekSIS/onboarding//AlekSIS-App-Tezor/-/tags/1.0.2 .. _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: 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.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
from django.apps import apps
from django.db import OperationalError
from aleksis.core.util.apps import AppConfig from aleksis.core.util.apps import AppConfig
from aleksis.core.util.core_helpers import get_site_preferences
class DefaultConfig(AppConfig): class DefaultConfig(AppConfig):
...@@ -20,57 +16,4 @@ class DefaultConfig(AppConfig): ...@@ -20,57 +16,4 @@ class DefaultConfig(AppConfig):
) )
def ready(self): def ready(self):
from django.conf import settings # noqa from .signals import update_on_person_change # 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
...@@ -8,14 +8,12 @@ from .models.invoice import Invoice ...@@ -8,14 +8,12 @@ from .models.invoice import Invoice
class InvoicesFilter(FilterSet): class InvoicesFilter(FilterSet):
variant = ChoiceFilter(choices=Invoice.get_variant_choices()) variant = ChoiceFilter(choices=Invoice.get_variant_choices())
status = ChoiceFilter(choices=PaymentStatus.CHOICES) status = ChoiceFilter(choices=PaymentStatus.CHOICES)
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.form.layout = Layout( self.form.layout = Layout(
Row("variant", "status"), Row("variant", "status"),
) )
class Meta: class Meta:
models = Invoice models = Invoice
from django.utils.translation import gettext as _ 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.forms import ActionForm
from aleksis.core.mixins import ExtensibleForm from aleksis.core.mixins import ExtensibleForm
...@@ -27,7 +27,29 @@ class InvoicesActionForm(ActionForm): ...@@ -27,7 +27,29 @@ class InvoicesActionForm(ActionForm):
class EditClientForm(ExtensibleForm): class EditClientForm(ExtensibleForm):
"""Form to create or edit clients.""" """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: class Meta:
model = Client model = Client
......
# 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),
]
# 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),
]
# 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),
),
]
from django.core.validators import RegexValidator
from django.db import models from django.db import models
from django.db.models import Q
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from localflavor.generic.models import BICField, IBANField
from aleksis.core.mixins import ExtensibleModel from aleksis.core.mixins import ExtensibleModel
class Client(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) name = models.CharField(verbose_name=_("Name"), max_length=255)
email = models.EmailField(verbose_name=_("Email")) 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: class Meta:
constraints = [ 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: def __str__(self) -> str:
return self.name 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
from django.conf import settings
from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.db import models from django.db import models
from django.db.models import Q
from django.shortcuts import reverse from django.shortcuts import reverse
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
...@@ -33,6 +31,12 @@ class InvoiceGroup(ExtensibleModel): ...@@ -33,6 +31,12 @@ class InvoiceGroup(ExtensibleModel):
def __str__(self) -> str: def __str__(self) -> str:
return self.name 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: class Meta:
constraints = [ constraints = [
models.UniqueConstraint(fields=["client", "name"], name="group_uniq_per_client") models.UniqueConstraint(fields=["client", "name"], name="group_uniq_per_client")
...@@ -40,12 +44,6 @@ class InvoiceGroup(ExtensibleModel): ...@@ -40,12 +44,6 @@ class InvoiceGroup(ExtensibleModel):
class Invoice(BasePayment, PureDjangoModel): 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 = { STATUS_ICONS = {
PaymentStatus.WAITING: "mdi:cash-lock-open", PaymentStatus.WAITING: "mdi:cash-lock-open",
PaymentStatus.INPUT: "mdi:cash-lock-open", PaymentStatus.INPUT: "mdi:cash-lock-open",
...@@ -86,12 +84,13 @@ class Invoice(BasePayment, PureDjangoModel): ...@@ -86,12 +84,13 @@ class Invoice(BasePayment, PureDjangoModel):
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
if self.person: if self.person:
person = self.person person = self.person
elif self.for_object and getattr(self.for_object, "person", None): elif self.for_object and getattr(self.for_object, "get_person", None):
person = self.for_object.person person = self.for_object.get_person()
else: else:
person = None person = None
if person: if person:
self.person = person
if not self.billing_last_name: if not self.billing_last_name:
self.billing_last_name = person.last_name self.billing_last_name = person.last_name
if not self.billing_first_name: if not self.billing_first_name:
...@@ -105,18 +104,17 @@ class Invoice(BasePayment, PureDjangoModel): ...@@ -105,18 +104,17 @@ class Invoice(BasePayment, PureDjangoModel):
super().save(*args, **kwargs) super().save(*args, **kwargs)
@classmethod def get_variant_choices(self=None):
def get_variant_choices(cls): if self and self.group:
choices = [] return self.group.get_variant_choices()
for variant in settings.PAYMENT_VARIANTS.keys(): else:
choices.append((variant, cls.VARIANT_DISPLAY[variant][0])) return InvoiceGroup.get_variant_choices()
return choices
def get_variant_name(self): 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): 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): def get_status_icon(self):
return self.__class__.STATUS_ICONS[self.status] return self.__class__.STATUS_ICONS[self.status]
...@@ -142,13 +140,6 @@ class Invoice(BasePayment, PureDjangoModel): ...@@ -142,13 +140,6 @@ class Invoice(BasePayment, PureDjangoModel):
class Meta: class Meta:
constraints = [ constraints = [
models.UniqueConstraint(fields=["number", "group"], name="number_uniq_per_group"), 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")),) permissions = (("send_invoice_email", _("Can send invoice by email")),)
......
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from dynamic_preferences.preferences import Section 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 from aleksis.core.registries import site_preferences_registry
...@@ -23,72 +23,6 @@ class PublicPayments(BooleanPreference): ...@@ -23,72 +23,6 @@ class PublicPayments(BooleanPreference):
required = False 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 @site_preferences_registry.register
class EnablePledge(BooleanPreference): class EnablePledge(BooleanPreference):
"""Payment pledge payment backend - enable or not.""" """Payment pledge payment backend - enable or not."""
...@@ -101,22 +35,11 @@ class EnablePledge(BooleanPreference): ...@@ -101,22 +35,11 @@ class EnablePledge(BooleanPreference):
@site_preferences_registry.register @site_preferences_registry.register
class SDDCreditor(StringPreference): class UpdateOnPersonChange(BooleanPreference):
"""SEPA direct debit backend - creditor name.""" """Update Invoices if person data changes."""
section = payments section = payments
name = "sdd_creditor" name = "update_on_person_change"
verbose_name = _("SEPA Direct Debit - Creditor name") verbose_name = _("Update Invoices if person data changes")
default = "" default = True
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 = ""
required = False required = False
INSTALLED_APPS = ["payments", "djp_sepa"] INSTALLED_APPS = ["payments", "djp_sepa"]
PAYMENT_MODEL = "tezor.Invoice" PAYMENT_MODEL = "tezor.Invoice"
PAYMENT_VARIANT_FACTORY = "aleksis.apps.tezor.util.invoice.provider_factory"
overrides = ["PAYMENT_MODEL"] overrides = ["PAYMENT_MODEL", "PAYMENT_VARIANT_FACTORY"]
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,
)
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.")
from django.conf import settings
from django.core.exceptions import PermissionDenied, SuspiciousOperation from django.core.exceptions import PermissionDenied, SuspiciousOperation
from django.shortcuts import get_object_or_404, redirect, render from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse, reverse_lazy from django.urls import reverse, reverse_lazy
...@@ -48,7 +47,7 @@ class DoPaymentView(PermissionRequiredMixin, View): ...@@ -48,7 +47,7 @@ class DoPaymentView(PermissionRequiredMixin, View):
new_variant = request.GET.get("variant", None) new_variant = request.GET.get("variant", None)
if new_variant: if new_variant:
if request.user.has_perm("tezor.change_payment_variant", self.object): 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.variant = new_variant
self.object.save() self.object.save()
else: else:
...@@ -145,7 +144,9 @@ class InvoiceGroupDetailView(PermissionRequiredMixin, DetailView): ...@@ -145,7 +144,9 @@ class InvoiceGroupDetailView(PermissionRequiredMixin, DetailView):
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
r = super().get(request, *args, **kwargs) r = super().get(request, *args, **kwargs)
if self.invoices_action_form.is_valid(): 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): if request.user.has_perm(action.permission):
self.invoices_action_form.execute() self.invoices_action_form.execute()
return r return r
...@@ -162,7 +163,9 @@ class InvoiceGroupDetailView(PermissionRequiredMixin, DetailView): ...@@ -162,7 +163,9 @@ class InvoiceGroupDetailView(PermissionRequiredMixin, DetailView):
RequestConfig(self.request).configure(invoices_table) RequestConfig(self.request).configure(invoices_table)
context["invoices_table"] = 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 context["action_form"] = self.invoices_action_form
return context return context
......
[tool.poetry] [tool.poetry]
name = "AlekSIS-App-Tezor" name = "AlekSIS-App-Tezor"
version = "1.1.1" version = "1.2.1.dev0"
packages = [ packages = [
{ include = "aleksis" } { include = "aleksis" }
] ]
...@@ -31,7 +31,7 @@ secondary = true ...@@ -31,7 +31,7 @@ secondary = true
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = "^3.9" python = "^3.9"
aleksis-core = "^2.8.1.dev0" 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" django-payments-sepa = "^1.0.1"
[tool.poetry.dev-dependencies] [tool.poetry.dev-dependencies]
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment