4a596e45bf5d079f04eb6601163399519f4ffd41
[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                 'schedule': schedule,
94                 'form': forms.PayUCardTokenForm(),
95                 'pos': POSS[self.pos_id],
96                 'widget_args': widget_args,
97                 'widget_sig': widget_sig,
98             },
99             request=request
100         )
101
102     def pay(self, request, schedule):
103         # Create order, put it and see what happens next.
104         from .models import PayUOrder
105         if request is not None:
106             ip = request.META['REMOTE_ADDR']
107         else:
108             ip = '127.0.0.1'
109
110         if request is None:
111             if not self.needs_retry(schedule):
112                 return
113             
114         order = PayUOrder.objects.create(
115             pos_id=self.pos_id,
116             customer_ip=ip,
117             schedule=schedule,
118         )
119         return order.put()
120
121     def needs_retry(self, schedule):
122         retry_last = schedule.payuorder_set.exclude(
123             created_at=None).order_by('-created_at').first()
124         if retry_last is None:
125             return True
126
127         n = now().date()
128         days_since_last = (n - retry_last.created_at.date()).days
129
130         retry_start = max(
131             schedule.expires_at.date(),
132             settings.CLUB_RETRIES_START
133         )
134         retry_days = (n - retry_start).days
135         
136         if retry_days > settings.CLUB_RETRY_DAYS_MAX:
137             print('expired')
138             return False
139         if retry_days > settings.CLUB_RETRY_DAYS_DAILY:
140             print('retry less often now')
141             return days_since_last > settings.CLUB_RETRY_LESS
142         return days_since_last > 0
143
144
145 class PayPal(PaymentMethod):
146     slug = 'paypal'
147     name = 'PayPal'
148     template_name = 'club/payment/paypal.html'
149     is_recurring = True
150     is_onetime = False
151
152     def invite_widget(self, schedule, request):
153         if settings.PAYPAL_ENABLED:
154             return render_to_string(
155                 'club/payment/paypal_invite.html',
156                 {
157                     'schedule': schedule,
158                 },
159                 request=request
160             )
161         else:
162             return ''
163     
164     def initiate(self, request, schedule):
165         app = request.GET.get('app')
166         return agreement_approval_url(schedule.amount, schedule.key, app=app)
167
168     def pay(self, request, schedule):
169         from datetime import date, timedelta, datetime, timezone
170         tomorrow = datetime(*(date.today() + timedelta(2)).timetuple()[:3], tzinfo=timezone.utc)
171         any_active = False
172         for ba in schedule.billingagreement_set.all():
173             active = ba.check_agreement()
174             ba.active = active
175             ba.save()
176             if active:
177                 any_active = True
178         if any_active:
179             schedule.expires_at = tomorrow
180             schedule.save()
181
182
183 methods = []
184
185 pos = getattr(settings, 'CLUB_PAYU_RECURRING_POS', None)
186 if pos:
187     recurring_payment_method = PayURe(pos)
188     methods.append(recurring_payment_method)
189 else:
190     recurring_payment_method = None
191
192 pos = getattr(settings, 'CLUB_PAYU_POS', None)
193 if pos:
194     single_payment_method = PayU(pos)
195     methods.append(single_payment_method)
196 else:
197     single_payment_method = None
198
199
200
201 methods.append(
202     PayPal()
203 )