club fixes.
[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 hashlib import sha256
5 from django.conf import settings
6 from django.urls import reverse
7 from django.utils.timezone import now
8 from django.utils.translation import get_language
9 from paypal.rest import agreement_approval_url
10 from django.template.loader import render_to_string
11 from .payu import POSS
12
13
14 class PaymentMethod(object):
15     is_onetime = False
16     is_recurring = False
17     expiration_reliable = False
18     cancellable = False
19     updateable = False
20
21     def initiate(self, request, schedule):
22         return reverse('club_dummy_payment', args=[schedule.key])
23
24
25 class PayU(PaymentMethod):
26     is_onetime = True
27     expiration_reliable = True
28     slug = 'payu'
29     name = 'PayU'
30     template_name = 'club/payment/payu.html'
31
32     def __init__(self, pos_id):
33         self.pos_id = pos_id
34
35     def invite_widget(self, schedule, request):
36         return render_to_string(
37             'club/payment/payu_invite.html',
38             {
39                 'schedule': schedule,
40             },
41             request=request
42         )
43
44     def initiate(self, request, schedule):
45         # Create Order at once.
46         from .models import PayUOrder
47         order = PayUOrder.objects.create(
48             pos_id=self.pos_id,
49             customer_ip=request.META['REMOTE_ADDR'],
50             schedule=schedule,
51         )
52         return order.put()
53
54
55 class PayURe(PaymentMethod):
56     slug = 'payu-re'
57     name = 'PayU recurring'
58     template_name = 'club/payment/payu-re.html'
59     is_recurring = True
60     expiration_reliable = True
61     cancellable = True
62     updateable = True
63
64     def __init__(self, pos_id):
65         self.pos_id = pos_id
66
67     def initiate(self, request, schedule):
68         return reverse('club_payu_rec_payment', args=[schedule.key])
69
70     def invite_widget(self, schedule, request):
71         from . import forms
72         pos = POSS[self.pos_id]
73         widget_args = {
74             'merchant-pos-id': pos.pos_id,
75             'shop-name': "SHOW NAME",
76             'total-amount': str(int(schedule.amount * 100)),
77             'currency-code': pos.currency_code,
78             'customer-language': get_language(), # filter to pos.languages
79             'customer-email': schedule.email,
80             'store-card': 'true',
81             'recurring-payment': 'true',
82         }
83         widget_sig = sha256(
84             (
85                 "".join(v for (k, v) in sorted(widget_args.items())) +
86                 pos.secondary_key
87             ).encode('utf-8')
88         ).hexdigest()
89         
90         return render_to_string(
91             'payu/rec_widget.html',
92             {
93                 'form': forms.PayUCardTokenForm(),
94                 'pos': POSS[self.pos_id],
95                 'widget_args': widget_args,
96                 'widget_sig': widget_sig,
97             },
98             request=request
99         )
100
101     def pay(self, request, schedule):
102         # Create order, put it and see what happens next.
103         from .models import PayUOrder
104         if request is not None:
105             ip = request.META['REMOTE_ADDR']
106         else:
107             ip = '127.0.0.1'
108
109         if request is None:
110             if not self.needs_retry(schedule):
111                 return
112             
113         order = PayUOrder.objects.create(
114             pos_id=self.pos_id,
115             customer_ip=ip,
116             schedule=schedule,
117         )
118         return order.put()
119
120     def needs_retry(self, schedule):
121         retry_last = schedule.payuorder_set.exclude(
122             created_at=None).order_by('-created_at').first()
123         if retry_last is None:
124             return True
125
126         n = now().date()
127         days_since_last = (n - retry_last.created_at.date()).days
128
129         retry_start = max(
130             schedule.expires_at.date(),
131             settings.CLUB_RETRIES_START
132         )
133         retry_days = (n - retry_start).days
134         
135         if retry_days > settings.CLUB_RETRY_DAYS_MAX:
136             print('expired')
137             return False
138         if retry_days > settings.CLUB_RETRY_DAYS_DAILY:
139             print('retry less often now')
140             return days_since_last > settings.CLUB_RETRY_LESS
141         return days_since_last > 0
142
143
144 class PayPal(PaymentMethod):
145     slug = 'paypal'
146     name = 'PayPal'
147     template_name = 'club/payment/paypal.html'
148     is_recurring = True
149     is_onetime = False
150
151     def invite_widget(self, schedule, request):
152         return render_to_string(
153             'club/payment/paypal_invite.html',
154             {
155                 'schedule': schedule,
156             },
157             request=request
158         )
159     
160     def initiate(self, request, schedule):
161         app = request.GET.get('app')
162         return agreement_approval_url(schedule.amount, schedule.key, app=app)
163
164     def pay(self, request, schedule):
165         from datetime import date, timedelta, datetime, timezone
166         tomorrow = datetime(*(date.today() + timedelta(2)).timetuple()[:3], tzinfo=timezone.utc)
167         any_active = False
168         for ba in schedule.billingagreement_set.all():
169             active = ba.check_agreement()
170             ba.active = active
171             ba.save()
172             if active:
173                 any_active = True
174         if any_active:
175             schedule.expires_at = tomorrow
176             schedule.save()
177
178
179 methods = []
180
181 pos = getattr(settings, 'CLUB_PAYU_RECURRING_POS', None)
182 if pos:
183     recurring_payment_method = PayURe(pos)
184     methods.append(recurring_payment_method)
185 else:
186     recurring_payment_method = None
187
188 pos = getattr(settings, 'CLUB_PAYU_POS', None)
189 if pos:
190     single_payment_method = PayU(pos)
191     methods.append(single_payment_method)
192 else:
193     single_payment_method = None
194
195
196
197 methods.append(
198     PayPal()
199 )