diff --git a/payments/__init__.py b/payments/__init__.py index 3ca8e04d9..443705a6b 100644 --- a/payments/__init__.py +++ b/payments/__init__.py @@ -61,6 +61,18 @@ class FraudStatus: ] +class WalletStatus: + PENDING = "pending" + ACTIVE = "active" + ERASED = "erased" + + CHOICES = [ + (PENDING, pgettext_lazy("wallet status", "Pending")), + (ACTIVE, pgettext_lazy("wallet status", "Active")), + (ERASED, pgettext_lazy("wallet status", "Erased")), + ] + + class RedirectNeeded(Exception): pass diff --git a/payments/core.py b/payments/core.py index 8b8ff0c97..5643141e9 100644 --- a/payments/core.py +++ b/payments/core.py @@ -143,25 +143,21 @@ def get_return_url( return url + "?" + qs return url - def autocomplete_with_subscription(self, payment): + def autocomplete_with_wallet(self, payment): """ - Complete the payment with subscription + Complete the payment with wallet If the provider uses workflow such that the payments are initiated from implementer's side. The users of django-payments will create a payment and call - Payment.autocomplete_with_subscription() right before the subscription end. + Payment.autocomplete_with_wallet(). Throws RedirectNeeded if there is problem with the payment that needs to be solved by user. """ raise NotImplementedError - def cancel_subscription(self, subscription): - """ - Cancel subscription - Used by providers, that use provider initiated cancellation workflow - """ + def erase_wallet(self, wallet): raise NotImplementedError def capture(self, payment, amount=None): diff --git a/payments/models.py b/payments/models.py index e26da1fbb..9ef439153 100644 --- a/payments/models.py +++ b/payments/models.py @@ -1,6 +1,5 @@ from __future__ import annotations -import enum import json from typing import Iterable from uuid import uuid4 @@ -13,6 +12,7 @@ from . import FraudStatus from . import PaymentStatus from . import PurchasedItem +from . import WalletStatus from .core import provider_factory @@ -40,58 +40,29 @@ def __setattr__(self, key, value): return None -class BaseSubscription(models.Model): +class BaseWallet(models.Model): token = models.CharField( - _("subscription token/id"), - help_text=_("Token/id used to identify subscription by provider"), + _("wallet token/id"), + help_text=_("Token/id used to identify wallet by provider"), max_length=255, default=None, null=True, blank=True, ) - payment_provider = models.CharField( - _("payment provider"), - help_text=_("Provider variant, that will be used for payment renewal"), - max_length=255, - default=None, - null=True, - blank=True, + status = models.CharField( + max_length=10, choices=WalletStatus.CHOICES, default=WalletStatus.PENDING ) - subscribtion_data = models.JSONField( - _("subscription data"), - help_text=_("Provider-specific data associated with subscription"), + extra_data = models.JSONField( + _("extra data"), + help_text=_("Provider-specific data associated with wallet"), default=dict, ) - class TimeUnit(enum.Enum): - year = "year" - month = "month" - day = "day" - - def set_recurrence(self, token: str, **kwargs): - """ - Sets token and other values associated with subscription recurrence - Kwargs can contain provider-specific values - """ - self.token = token - self.subscribtion_data = kwargs - - def get_period(self) -> int: - raise NotImplementedError - - def get_unit(self) -> TimeUnit: - raise NotImplementedError - - def cancel(self): + def payment_completed(self, payment): """ - Cancel the subscription by provider - Used by providers, that use provider initiated subscription workflow - Implementer is responsible for cancelling the subscription model - - Raises PaymentError if the cancellation didn't pass through + Concrete implementation specific logic called whenever a payment is completed + using this wallet. """ - provider = provider_factory(self.variant) - provider.cancel_subscription(self) class Meta: abstract = True @@ -251,30 +222,18 @@ def get_payment_url(self) -> str: """ raise NotImplementedError - def get_subscription(self) -> BaseSubscription | None: - """ - Returns subscription object associated with this payment - or None if the payment is not recurring - """ - return None - - def is_recurring(self) -> bool: - return self.get_subscription() is not None - - def autocomplete_with_subscription(self): + def autocomplete_with_wallet(self): """ - Complete the payment with subscription + Complete the payment with wallet If the provider uses workflow such that the payments are initiated from implementer's side. - Call this function right before the subscription end to - make a new subscription payment. Throws RedirectNeeded if there is problem with the payment that needs to be solved by user """ provider = provider_factory(self.variant) - provider.autocomplete_with_subscription(self) + provider.autocomplete_with_wallet(self) def capture(self, amount=None): """Capture a pre-authorized payment.