Skip to content

Commit 307bd40

Browse files
committed
add common subscription methods
1 parent b3ef3d5 commit 307bd40

2 files changed

Lines changed: 99 additions & 0 deletions

File tree

payments/core.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,22 @@ def get_return_url(self, payment, extra_data=None):
119119
return url + "?" + qs
120120
return url
121121

122+
def autocomplete_with_subscription(self, payment):
123+
"""
124+
Complete the payment with subscription
125+
Used by providers, that use server initiated subscription workflow
126+
127+
Throws RedirectNeeded if there is problem with the payment that needs to be solved by user
128+
"""
129+
raise NotImplementedError()
130+
131+
def cancel_subscription(self, subscription):
132+
"""
133+
Cancel subscription
134+
Used by providers, that use provider initiated cancellation workflow
135+
"""
136+
raise NotImplementedError()
137+
122138
def capture(self, payment, amount=None):
123139
raise NotImplementedError()
124140

payments/models.py

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
import enum
12
import json
23
from typing import Iterable
4+
from typing import Optional
35
from typing import Union
46
from uuid import uuid4
57

@@ -36,6 +38,60 @@ def __setattr__(self, key, value):
3638
self._payment.extra_data = json.dumps(data)
3739

3840

41+
class BaseSubscription(models.Model):
42+
token = models.CharField(
43+
_("subscription token/id"),
44+
help_text=_("Token/id used to identify subscription by provider"),
45+
max_length=255,
46+
default=None,
47+
null=True,
48+
blank=True,
49+
)
50+
payment_provider = models.CharField(
51+
_("payment provider"),
52+
help_text=_("Provider variant, that will be used for payment renewal"),
53+
max_length=255,
54+
default=None,
55+
null=True,
56+
blank=True,
57+
)
58+
59+
class TimeUnit(enum.Enum):
60+
year = "year"
61+
month = "month"
62+
day = "day"
63+
64+
def get_token(self) -> str:
65+
return self.token
66+
67+
def set_recurrence(self, token: str, **kwargs):
68+
"""
69+
Sets token and other values associated with subscription recurrence
70+
Kwargs can contain provider-specific values
71+
"""
72+
self.token = token
73+
74+
def get_period(self) -> int:
75+
raise NotImplementedError()
76+
77+
def get_unit(self) -> TimeUnit:
78+
raise NotImplementedError()
79+
80+
def cancel(self):
81+
"""
82+
Cancel the subscription by provider
83+
Used by providers, that use provider initiated subscription workflow
84+
Implementer is responsible for cancelling the subscription model
85+
86+
Raises PaymentError if the cancellation didn't pass through
87+
"""
88+
provider = provider_factory(self.variant)
89+
provider.cancel_subscription(self)
90+
91+
class Meta:
92+
abstract = True
93+
94+
3995
class BasePayment(models.Model):
4096
"""
4197
Represents a single transaction. Each instance has one or more PaymentItem.
@@ -144,6 +200,33 @@ def get_success_url(self) -> str:
144200
def get_process_url(self) -> str:
145201
return reverse("process_payment", kwargs={"token": self.token})
146202

203+
def get_payment_url(self) -> str:
204+
"""
205+
Get the url the view that handles the payment (payment_details() in documentation)
206+
For now used only by PayU provider to redirect users back to CVV2 form
207+
"""
208+
raise NotImplementedError()
209+
210+
def get_subscription(self) -> Optional[BaseSubscription]:
211+
"""
212+
Returns subscription object associated with this payment
213+
or None if the payment is not recurring
214+
"""
215+
return None
216+
217+
def is_recurring(self) -> bool:
218+
return self.get_subscription() is not None
219+
220+
def autocomplete_with_subscription(self):
221+
"""
222+
Complete the payment with subscription
223+
Used by providers, that use server initiated subscription workflow
224+
225+
Throws RedirectNeeded if there is problem with the payment that needs to be solved by user
226+
"""
227+
provider = provider_factory(self.variant)
228+
provider.autocomplete_with_subscription(self)
229+
147230
def capture(self, amount=None):
148231
if self.status != PaymentStatus.PREAUTH:
149232
raise ValueError("Only pre-authorized payments can be captured.")

0 commit comments

Comments
 (0)