New payment retry policy.
[wolnelektury.git] / src / club / payment_methods.py
1 # This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
2 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
3 #
4 from django.conf import settings
5 from django.urls import reverse
6 from django.utils.timezone import now
7 from paypal.rest import agreement_approval_url
8
9
10 class PaymentMethod(object):
11     is_onetime = False
12     is_recurring = False
13     expiration_reliable = False
14     cancellable = False
15     updateable = False
16
17     def initiate(self, request, schedule):
18         return reverse('club_dummy_payment', args=[schedule.key])
19
20
21 class PayU(PaymentMethod):
22     is_onetime = True
23     expiration_reliable = True
24     slug = 'payu'
25     name = 'PayU'
26     template_name = 'club/payment/payu.html'
27
28     def __init__(self, pos_id):
29         self.pos_id = pos_id
30
31     def initiate(self, request, schedule):
32         # Create Order at once.
33         from .models import PayUOrder
34         order = PayUOrder.objects.create(
35             pos_id=self.pos_id,
36             customer_ip=request.META['REMOTE_ADDR'],
37             schedule=schedule,
38         )
39         return order.put()
40
41
42 class PayURe(PaymentMethod):
43     slug = 'payu-re'
44     name = 'PayU recurring'
45     template_name = 'club/payment/payu-re.html'
46     is_recurring = True
47     expiration_reliable = True
48     cancellable = True
49     updateable = True
50
51     def __init__(self, pos_id):
52         self.pos_id = pos_id
53
54     def initiate(self, request, schedule):
55         return reverse('club_payu_rec_payment', args=[schedule.key])
56
57     def pay(self, request, schedule):
58         # Create order, put it and see what happens next.
59         from .models import PayUOrder
60         if request is not None:
61             ip = request.META['REMOTE_ADDR']
62         else:
63             ip = '127.0.0.1'
64
65         if request is None:
66             if not self.needs_retry(schedule):
67                 return
68             
69         order = PayUOrder.objects.create(
70             pos_id=self.pos_id,
71             customer_ip=ip,
72             schedule=schedule,
73         )
74         return order.put()
75
76     def needs_retry(self, schedule):
77         retry_last = schedule.payuorder_set.exclude(
78             created_at=None).order_by('-created_at').first()
79         if retry_last is None:
80             return True
81
82         n = now().date()
83         days_since_last = (n - retry_last.created_at.date()).days
84
85         retry_start = max(
86             schedule.expires_at.date(),
87             settings.CLUB_RETRIES_START
88         )
89         retry_days = (n - retry_start).days
90         
91         if retry_days > settings.CLUB_RETRY_DAYS_MAX:
92             print('expired')
93             return False
94         if retry_days > settings.CLUB_RETRY_DAYS_DAILY:
95             print('retry less often now')
96             return days_since_last > settings.CLUB_RETRY_LESS
97         return days_since_last > 0
98
99
100 class PayPal(PaymentMethod):
101     slug = 'paypal'
102     name = 'PayPal'
103     template_name = 'club/payment/paypal.html'
104     is_recurring = True
105     is_onetime = False
106
107     def initiate(self, request, schedule):
108         app = request.GET.get('app')
109         return agreement_approval_url(schedule.amount, schedule.key, app=app)
110
111     def pay(self, request, schedule):
112         from datetime import date, timedelta, datetime
113         from pytz import utc
114         tomorrow = datetime(*(date.today() + timedelta(2)).timetuple()[:3], tzinfo=utc)
115         any_active = False
116         for ba in schedule.billingagreement_set.all():
117             active = ba.check_agreement()
118             ba.active = active
119             ba.save()
120             if active:
121                 any_active = True
122         if any_active:
123             schedule.expires_at = tomorrow
124             schedule.save()
125
126
127 methods = []
128
129 pos = getattr(settings, 'CLUB_PAYU_RECURRING_POS', None)
130 if pos:
131     recurring_payment_method = PayURe(pos)
132     methods.append(recurring_payment_method)
133 else:
134     recurring_payment_method = None
135
136 pos = getattr(settings, 'CLUB_PAYU_POS', None)
137 if pos:
138     single_payment_method = PayU(pos)
139     methods.append(single_payment_method)
140 else:
141     single_payment_method = None
142
143
144
145 methods.append(
146     PayPal()
147 )