diff --git a/pyright.pyproject.toml b/pyright.pyproject.toml index 1343b5afcf..b02a0744c1 100644 --- a/pyright.pyproject.toml +++ b/pyright.pyproject.toml @@ -10,8 +10,6 @@ include = [ "src/openforms/dmn/registry.py", "src/openforms/formio/registry.py", "src/openforms/formio/rendering/registry.py", - "src/openforms/payments/base.py", - "src/openforms/payments/registry.py", "src/openforms/pre_requests/base.py", "src/openforms/pre_requests/registry.py", "src/openforms/prefill/base.py", @@ -29,10 +27,7 @@ include = [ # Core forms app "src/openforms/forms/api/serializers/logic/action_serializers.py", # Payments - "src/openforms/payments/models.py", - "src/openforms/payments/contrib/ogone/client.py", - "src/openforms/payments/contrib/ogone/plugin.py", - "src/openforms/payments/views.py", + "src/openforms/payments/", # Interaction with the outside world "src/openforms/contrib/zgw/service.py", "src/openforms/contrib/objects_api/", @@ -64,6 +59,10 @@ exclude = [ "src/openforms/contrib/objects_api/tests/", "src/openforms/contrib/objects_api/json_schema.py", "src/openforms/formio/formatters/tests/", + "src/openforms/payments/management/commands/checkpaymentemaildupes.py", + "src/openforms/payments/tests/", + "src/openforms/payments/contrib/demo/tests/", + "src/openforms/payments/contrib/ogone/tests/", "src/openforms/registrations/contrib/zgw_apis/tests/test_backend_partial_failure.py", "src/openforms/registrations/contrib/zgw_apis/tests/test_utils.py", ] diff --git a/src/openforms/forms/admin/form.py b/src/openforms/forms/admin/form.py index bd170f0628..efe14af5d6 100644 --- a/src/openforms/forms/admin/form.py +++ b/src/openforms/forms/admin/form.py @@ -12,7 +12,6 @@ from openforms.api.utils import underscore_to_camel from openforms.emails.models import ConfirmationEmailTemplate -from openforms.payments.admin import PaymentBackendChoiceFieldMixin from openforms.registrations.admin import RegistrationBackendFieldMixin from openforms.typing import StrOrPromise from openforms.utils.expressions import FirstNotBlank @@ -127,7 +126,6 @@ def expected_parameters(self): class FormAdmin( FormioConfigMixin, RegistrationBackendFieldMixin, - PaymentBackendChoiceFieldMixin, OrderedInlineModelAdminMixin, admin.ModelAdmin, ): diff --git a/src/openforms/payments/admin.py b/src/openforms/payments/admin.py index 3f1b71db2c..23654d0cc6 100644 --- a/src/openforms/payments/admin.py +++ b/src/openforms/payments/admin.py @@ -1,22 +1,8 @@ from django.contrib import admin -from .fields import PaymentBackendChoiceField from .models import SubmissionPayment -class PaymentBackendChoiceFieldMixin: - def formfield_for_dbfield(self, db_field, request, **kwargs): - if isinstance(db_field, PaymentBackendChoiceField): - assert not db_field.choices - _old = db_field.choices - db_field.choices = db_field._get_plugin_choices() - field = super().formfield_for_dbfield(db_field, request, **kwargs) - db_field.choices = _old - return field - - return super().formfield_for_dbfield(db_field, request, **kwargs) - - @admin.register(SubmissionPayment) class SubmissionPaymentAdmin(admin.ModelAdmin): fields = ( diff --git a/src/openforms/payments/api/fields.py b/src/openforms/payments/api/fields.py index 6cc7cdb92e..f82c9d70c0 100644 --- a/src/openforms/payments/api/fields.py +++ b/src/openforms/payments/api/fields.py @@ -1,5 +1,7 @@ from rest_framework import serializers +from openforms.forms.models import Form + from ..registry import register as payment_register from .serializers import PaymentOptionSerializer @@ -20,7 +22,8 @@ def __init__(self, *args, **kwargs): def to_internal_value(self, data): raise NotImplementedError("read only") - def to_representation(self, form): + def to_representation(self, value): + assert isinstance(value, Form) request = self.context["request"] - temp = payment_register.get_options(request, form) + temp = payment_register.get_options(request, value) return super().to_representation(temp) diff --git a/src/openforms/payments/api/serializers.py b/src/openforms/payments/api/serializers.py index 124fdcbe95..4d82f5f280 100644 --- a/src/openforms/payments/api/serializers.py +++ b/src/openforms/payments/api/serializers.py @@ -23,7 +23,7 @@ class PaymentPluginSerializer(PluginBaseSerializer): class PaymentOptionSerializer(serializers.Serializer): # serializer for form identifier = serializers.CharField(label=_("Identifier"), read_only=True) - label = serializers.CharField( + label = serializers.CharField( # pyright: ignore[reportAssignmentType] label=_("Button label"), help_text=_("Button label"), read_only=True ) @@ -34,7 +34,7 @@ class PaymentInfoSerializer(serializers.Serializer): label=_("Request type"), choices=PaymentRequestType.choices, read_only=True ) url = serializers.URLField(label=_("URL"), read_only=True) - data = serializers.DictField( + data = serializers.DictField( # pyright: ignore[reportAssignmentType,reportIncompatibleMethodOverride] label=_("Data"), child=serializers.CharField(label=_("Value"), read_only=True), read_only=True, diff --git a/src/openforms/payments/base.py b/src/openforms/payments/base.py index b21b92e2c7..33c35fd93a 100644 --- a/src/openforms/payments/base.py +++ b/src/openforms/payments/base.py @@ -81,7 +81,7 @@ def get_return_url(self, request: HttpRequest, payment: SubmissionPayment) -> st request=request, ) - def get_webhook_url(self, request: HttpRequest) -> str: + def get_webhook_url(self, request: HttpRequest | None) -> str: return reverse_plus( "payments:webhook", kwargs={"plugin_id": self.identifier}, diff --git a/src/openforms/payments/contrib/ogone/constants.py b/src/openforms/payments/contrib/ogone/constants.py index 817697dfce..d83b3ea5a0 100644 --- a/src/openforms/payments/contrib/ogone/constants.py +++ b/src/openforms/payments/contrib/ogone/constants.py @@ -1,5 +1,3 @@ -from typing import cast - from django.db import models from django.utils.translation import gettext_lazy as _ @@ -60,45 +58,42 @@ def as_payment_status(cls, ogone_status: str) -> str: return OGONE_TO_PAYMENT_STATUS[ogone_status] -OGONE_TO_PAYMENT_STATUS = cast( - dict[str, str], - { - OgoneStatus.invalid_or_incomplete: PaymentStatus.failed.value, - OgoneStatus.cancelled_by_customer: PaymentStatus.failed.value, - OgoneStatus.authorisation_declined: PaymentStatus.failed.value, - OgoneStatus.waiting_for_client_payment: PaymentStatus.processing.value, - OgoneStatus.waiting_authentication: PaymentStatus.processing.value, - OgoneStatus.authorised: PaymentStatus.processing.value, - OgoneStatus.authorised_waiting_external_result: PaymentStatus.processing.value, - OgoneStatus.authorisation_waiting: PaymentStatus.processing.value, - OgoneStatus.authorisation_not_known: PaymentStatus.processing.value, - OgoneStatus.standby: PaymentStatus.processing.value, - OgoneStatus.ok_with_scheduled_payments: PaymentStatus.processing.value, - OgoneStatus.not_ok_with_scheduled_payments: PaymentStatus.failed.value, - OgoneStatus.authorised_and_cancelled: PaymentStatus.failed.value, - OgoneStatus.author_deletion_waiting: PaymentStatus.failed.value, - OgoneStatus.author_deletion_uncertain: PaymentStatus.failed.value, - OgoneStatus.author_deletion_refused: PaymentStatus.failed.value, - OgoneStatus.payment_deleted: PaymentStatus.failed.value, - OgoneStatus.payment_deletion_pending: PaymentStatus.failed.value, - OgoneStatus.payment_deletion_uncertain: PaymentStatus.failed.value, - OgoneStatus.payment_deletion_refused: PaymentStatus.failed.value, - OgoneStatus.payment_deleted2: PaymentStatus.failed, # doubl.valuee - OgoneStatus.refund: PaymentStatus.failed.value, - OgoneStatus.refund_pending: PaymentStatus.failed.value, - OgoneStatus.refund_uncertain: PaymentStatus.failed.value, - OgoneStatus.refund_refused: PaymentStatus.failed.value, - OgoneStatus.payment_declined_by_the_acquirer: PaymentStatus.failed.value, - OgoneStatus.refund_processed_by_merchant: PaymentStatus.failed.value, - OgoneStatus.payment_requested: PaymentStatus.completed.value, - OgoneStatus.payment_processing: PaymentStatus.processing.value, - OgoneStatus.payment_uncertain: PaymentStatus.processing.value, - OgoneStatus.payment_refused: PaymentStatus.failed.value, - OgoneStatus.refund_declined_by_the_acquirer: PaymentStatus.failed.value, - OgoneStatus.payment_processed_by_merchant: PaymentStatus.failed.value, - OgoneStatus.being_processed: PaymentStatus.processing.value, - }, -) +OGONE_TO_PAYMENT_STATUS: dict[str, str] = { + OgoneStatus.invalid_or_incomplete.value: PaymentStatus.failed.value, + OgoneStatus.cancelled_by_customer.value: PaymentStatus.failed.value, + OgoneStatus.authorisation_declined.value: PaymentStatus.failed.value, + OgoneStatus.waiting_for_client_payment.value: PaymentStatus.processing.value, + OgoneStatus.waiting_authentication.value: PaymentStatus.processing.value, + OgoneStatus.authorised.value: PaymentStatus.processing.value, + OgoneStatus.authorised_waiting_external_result.value: PaymentStatus.processing.value, + OgoneStatus.authorisation_waiting.value: PaymentStatus.processing.value, + OgoneStatus.authorisation_not_known.value: PaymentStatus.processing.value, + OgoneStatus.standby.value: PaymentStatus.processing.value, + OgoneStatus.ok_with_scheduled_payments.value: PaymentStatus.processing.value, + OgoneStatus.not_ok_with_scheduled_payments.value: PaymentStatus.failed.value, + OgoneStatus.authorised_and_cancelled.value: PaymentStatus.failed.value, + OgoneStatus.author_deletion_waiting.value: PaymentStatus.failed.value, + OgoneStatus.author_deletion_uncertain.value: PaymentStatus.failed.value, + OgoneStatus.author_deletion_refused.value: PaymentStatus.failed.value, + OgoneStatus.payment_deleted.value: PaymentStatus.failed.value, + OgoneStatus.payment_deletion_pending.value: PaymentStatus.failed.value, + OgoneStatus.payment_deletion_uncertain.value: PaymentStatus.failed.value, + OgoneStatus.payment_deletion_refused.value: PaymentStatus.failed.value, + OgoneStatus.payment_deleted2.value: PaymentStatus.failed, # doubl.valuee + OgoneStatus.refund.value: PaymentStatus.failed.value, + OgoneStatus.refund_pending.value: PaymentStatus.failed.value, + OgoneStatus.refund_uncertain.value: PaymentStatus.failed.value, + OgoneStatus.refund_refused.value: PaymentStatus.failed.value, + OgoneStatus.payment_declined_by_the_acquirer.value: PaymentStatus.failed.value, + OgoneStatus.refund_processed_by_merchant.value: PaymentStatus.failed.value, + OgoneStatus.payment_requested.value: PaymentStatus.completed.value, + OgoneStatus.payment_processing.value: PaymentStatus.processing.value, + OgoneStatus.payment_uncertain.value: PaymentStatus.processing.value, + OgoneStatus.payment_refused.value: PaymentStatus.failed.value, + OgoneStatus.refund_declined_by_the_acquirer.value: PaymentStatus.failed.value, + OgoneStatus.payment_processed_by_merchant.value: PaymentStatus.failed.value, + OgoneStatus.being_processed.value: PaymentStatus.processing.value, +} assert set(OgoneStatus.values) == set( OGONE_TO_PAYMENT_STATUS.keys() diff --git a/src/openforms/payments/services.py b/src/openforms/payments/services.py index af8e0a0bec..f10626d2ac 100644 --- a/src/openforms/payments/services.py +++ b/src/openforms/payments/services.py @@ -10,9 +10,14 @@ def update_submission_payment_registration(submission: Submission): + if (registration_backend := submission.registration_backend) is None: + error = AttributeError("Submission has no registration backend") + logevent.registration_payment_update_failure(submission, error=error) + return + try: - plugin = register[submission.registration_backend.backend] - except (AttributeError, KeyError) as e: + plugin = register[registration_backend.backend] + except KeyError as e: logevent.registration_payment_update_failure(submission, error=e) return @@ -37,7 +42,8 @@ def update_submission_payment_registration(submission: Submission): try: plugin.update_payment_status(submission, options_serializer.validated_data) - payments.mark_registered() + # FIXME: pyright + custom querysets... + payments.mark_registered() # pyright: ignore[reportAttributeAccessIssue] except Exception as e: logevent.registration_payment_update_failure( submission, error=e, plugin=plugin