Skip to content
Snippets Groups Projects
Commit ac70f7f0 authored by Nik | Klampfradler's avatar Nik | Klampfradler
Browse files

Merge branch 'renovate/django-payments-1.x' into 'master'

Update dependency django-payments to v1

See merge request !15
parents 5a806de1 9449393b
No related branches found
No related tags found
1 merge request!15Update dependency django-payments to v1
Pipeline #60744 failed
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):
......@@ -18,59 +14,3 @@ class DefaultConfig(AppConfig):
([2022], "Dominik George", "dominik.george@teckids.org"),
([2022], "Tom Teichler", "tom.teichler@teckids.org"),
)
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
......@@ -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
from django.utils.translation import gettext as _
from material import Layout, Row
from material import Layout, Row, Fieldset
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
......
# 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),
]
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 IBANField, BICField
from aleksis.core.util.core_helpers import get_site_preferences
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
from django.conf import settings
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.db import models
......@@ -33,6 +32,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 +45,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",
......@@ -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]
......
......@@ -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."""
......@@ -98,25 +32,3 @@ class EnablePledge(BooleanPreference):
verbose_name = _("Enable pledged payments")
default = False
required = False
@site_preferences_registry.register
class SDDCreditor(StringPreference):
"""SEPA direct debit backend - creditor name."""
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 = ""
required = False
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"]
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.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
......
......@@ -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]
......
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