|
| 1 | +import enum |
1 | 2 | import json |
2 | 3 | from typing import Iterable |
| 4 | +from typing import Optional |
3 | 5 | from typing import Union |
4 | 6 | from uuid import uuid4 |
5 | 7 |
|
@@ -36,6 +38,60 @@ def __setattr__(self, key, value): |
36 | 38 | self._payment.extra_data = json.dumps(data) |
37 | 39 |
|
38 | 40 |
|
| 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 | + |
39 | 95 | class BasePayment(models.Model): |
40 | 96 | """ |
41 | 97 | Represents a single transaction. Each instance has one or more PaymentItem. |
@@ -144,6 +200,33 @@ def get_success_url(self) -> str: |
144 | 200 | def get_process_url(self) -> str: |
145 | 201 | return reverse("process_payment", kwargs={"token": self.token}) |
146 | 202 |
|
| 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 | + |
147 | 230 | def capture(self, amount=None): |
148 | 231 | if self.status != PaymentStatus.PREAUTH: |
149 | 232 | raise ValueError("Only pre-authorized payments can be captured.") |
|
0 commit comments