Skip to content

Commit

Permalink
Replace the subscription logic with a wallet logic as per #217 (comment)
Browse files Browse the repository at this point in the history
  • Loading branch information
radekholy24 committed Jun 4, 2024
1 parent 4f9df42 commit e4585a5
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 65 deletions.
12 changes: 12 additions & 0 deletions payments/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
16 changes: 7 additions & 9 deletions payments/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
from django.core.exceptions import ImproperlyConfigured
from django.utils.module_loading import import_string

from . import WalletStatus

if TYPE_CHECKING:
from django.http import HttpRequest

Expand Down Expand Up @@ -143,26 +145,22 @@ 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
"""
raise NotImplementedError
def erase_wallet(self, wallet):
wallet.status = WalletStatus.ERASED

def capture(self, payment, amount=None):
raise NotImplementedError
Expand Down
71 changes: 15 additions & 56 deletions payments/models.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from __future__ import annotations

import enum
import json
from typing import Iterable
from uuid import uuid4
Expand All @@ -13,6 +12,7 @@
from . import FraudStatus
from . import PaymentStatus
from . import PurchasedItem
from . import WalletStatus
from .core import provider_factory


Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down

0 comments on commit e4585a5

Please sign in to comment.