Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add base Subscribtion/recurring payments support #217

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
19 changes: 19 additions & 0 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,6 +145,23 @@ def get_return_url(
return url + "?" + qs
return url

def autocomplete_with_wallet(self, payment):
"""
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_wallet().

Throws RedirectNeeded if there is problem with the payment
that needs to be solved by user.
"""
raise NotImplementedError

def erase_wallet(self, wallet):
wallet.status = WalletStatus.ERASED

def capture(self, payment, amount=None):
raise NotImplementedError

Expand Down
50 changes: 50 additions & 0 deletions payments/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from . import FraudStatus
from . import PaymentStatus
from . import PurchasedItem
from . import WalletStatus
from .core import provider_factory


Expand Down Expand Up @@ -39,6 +40,34 @@ def __setattr__(self, key, value):
return None


class BaseWallet(models.Model):
token = models.CharField(
_("wallet token/id"),
help_text=_("Token/id used to identify wallet by provider"),
max_length=255,
default=None,
null=True,
blank=True,
)
status = models.CharField(
max_length=10, choices=WalletStatus.CHOICES, default=WalletStatus.PENDING
)
extra_data = models.JSONField(
_("extra data"),
help_text=_("Provider-specific data associated with wallet"),
default=dict,
)

def payment_completed(self, payment):
"""
Concrete implementation specific logic called whenever a payment is completed
using this wallet.
"""

class Meta:
abstract = True


class BasePayment(models.Model):
"""
Represents a single transaction. Each instance has one or more PaymentItem.
Expand Down Expand Up @@ -185,6 +214,27 @@ def get_success_url(self) -> str:
def get_process_url(self) -> str:
return reverse("process_payment", kwargs={"token": self.token})

def get_payment_url(self) -> str:
"""
Get the url the view that handles the payment
(payment_details() in documentation)
For now used only by PayU provider to redirect users back to CVV2 form
"""
Comment on lines +217 to +222
Copy link
Contributor

@radekholy24 radekholy24 Apr 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

django-payments refers to payment_details as to the payment handling view. But are they really the same? Would it make sense to call it just a CVV2 URL? Wouldn't provide extra flexibility to the implementations?

raise NotImplementedError

def autocomplete_with_wallet(self):
"""
Complete the payment with wallet

If the provider uses workflow such that the payments are initiated from
implementer's side.

Throws RedirectNeeded if there is problem with the payment
that needs to be solved by user
"""
provider = provider_factory(self.variant)
provider.autocomplete_with_wallet(self)

def capture(self, amount=None):
"""Capture a pre-authorized payment.

Expand Down
Loading