+# This file is part of Wolne Lektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Wolne Lektury. See NOTICE for more information.
+#
+from hashlib import sha256
from django.conf import settings
from django.urls import reverse
+from django.utils.timezone import now
+from django.utils.translation import get_language
+from paypal.rest import agreement_approval_url
+from django.template.loader import render_to_string
+from .payu import POSS
class PaymentMethod(object):
+ is_onetime = False
is_recurring = False
+ expiration_reliable = False
+ cancellable = False
+ updateable = False
def initiate(self, request, schedule):
- return reverse('club_dummy_payment', args=[schedule.key])
+ raise NotImplementedError
class PayU(PaymentMethod):
+ is_onetime = True
+ expiration_reliable = True
slug = 'payu'
name = 'PayU'
- template_name = 'club/payment/payu.html'
def __init__(self, pos_id):
self.pos_id = pos_id
+ def invite_widget(self, schedule, request):
+ return render_to_string(
+ 'club/payment/payu_invite.html',
+ {
+ 'schedule': schedule,
+ },
+ request=request
+ )
+
def initiate(self, request, schedule):
# Create Order at once.
from .models import PayUOrder
class PayURe(PaymentMethod):
- slug='payu-re'
- name = 'PayU Recurring'
- template_name = 'club/payment/payu-re.html'
+ slug = 'payu-re'
+ name = 'PayU recurring'
is_recurring = True
+ expiration_reliable = True
+ cancellable = True
+ updateable = True
def __init__(self, pos_id):
self.pos_id = pos_id
def initiate(self, request, schedule):
return reverse('club_payu_rec_payment', args=[schedule.key])
+ def invite_widget(self, schedule, request):
+ from . import forms
+ pos = POSS[self.pos_id]
+ widget_args = {
+ 'merchant-pos-id': pos.pos_id,
+ 'shop-name': "SHOW NAME",
+ 'total-amount': str(int(schedule.amount * 100)),
+ 'currency-code': pos.currency_code,
+ 'customer-language': get_language(), # filter to pos.languages
+ 'customer-email': schedule.email,
+ 'store-card': 'true',
+ 'recurring-payment': 'true',
+ }
+ widget_sig = sha256(
+ (
+ "".join(v for (k, v) in sorted(widget_args.items())) +
+ pos.secondary_key
+ ).encode('utf-8')
+ ).hexdigest()
+
+ return render_to_string(
+ 'payu/rec_widget.html',
+ {
+ 'schedule': schedule,
+ 'form': forms.PayUCardTokenForm(),
+ 'pos': POSS[self.pos_id],
+ 'widget_args': widget_args,
+ 'widget_sig': widget_sig,
+ },
+ request=request
+ )
+
def pay(self, request, schedule):
# Create order, put it and see what happens next.
from .models import PayUOrder
+ if request is not None:
+ ip = request.META['REMOTE_ADDR']
+ else:
+ ip = '127.0.0.1'
+
+ if request is None:
+ if not self.needs_retry(schedule):
+ return
+
order = PayUOrder.objects.create(
pos_id=self.pos_id,
- customer_ip=request.META['REMOTE_ADDR'],
+ customer_ip=ip,
schedule=schedule,
)
return order.put()
-
-class PayPalRe(PaymentMethod):
- slug='paypal-re'
- name = 'PayPal Recurring'
- template_name = 'club/payment/paypal-re.html'
- is_recurring = True
+ def needs_retry(self, schedule):
+ retry_last = schedule.payuorder_set.exclude(
+ created_at=None).order_by('-created_at').first()
+ if retry_last is None:
+ return True
+
+ n = now().date()
+ days_since_last = (n - retry_last.created_at.date()).days
+ retry_start = max(
+ schedule.expires_at.date(),
+ settings.CLUB_RETRIES_START
+ )
+ retry_days = (n - retry_start).days
+
+ if retry_days > settings.CLUB_RETRY_DAYS_MAX:
+ print('expired')
+ return False
+ if retry_days > settings.CLUB_RETRY_DAYS_DAILY:
+ print('retry less often now')
+ return days_since_last > settings.CLUB_RETRY_LESS
+ return days_since_last > 0
+
+
+class PayPal(PaymentMethod):
+ slug = 'paypal'
+ name = 'PayPal'
+ is_recurring = True
+ is_onetime = False
+
+ def invite_widget(self, schedule, request):
+ if settings.PAYPAL_ENABLED:
+ return render_to_string(
+ 'club/payment/paypal_invite.html',
+ {
+ 'schedule': schedule,
+ },
+ request=request
+ )
+ else:
+ return ''
+
def initiate(self, request, schedule):
- return reverse('club_dummy_payment', args=[schedule.key])
+ app = request.GET.get('app')
+ return agreement_approval_url(schedule.amount, schedule.key, app=app)
+
+ def pay(self, request, schedule):
+ from datetime import date, timedelta, datetime, timezone
+ tomorrow = datetime(*(date.today() + timedelta(2)).timetuple()[:3], tzinfo=timezone.utc)
+ any_active = False
+ for ba in schedule.billingagreement_set.all():
+ active = ba.check_agreement()
+ ba.active = active
+ ba.save()
+ if active:
+ any_active = True
+ if any_active:
+ schedule.expires_at = tomorrow
+ schedule.save()
methods = []
-pos = getattr(settings, 'CLUB_PAYU_POS', None)
+pos = getattr(settings, 'CLUB_PAYU_RECURRING_POS', None)
if pos:
- payu_method = PayU(pos)
- methods.append(payu_method)
+ recurring_payment_method = PayURe(pos)
+ methods.append(recurring_payment_method)
else:
- payu_method = None
+ recurring_payment_method = None
-pos= getattr(settings, 'CLUB_PAYU_RECURRING_POS', None)
+pos = getattr(settings, 'CLUB_PAYU_POS', None)
if pos:
- payure_method = PayURe(pos)
- methods.append(payure_method)
+ single_payment_method = PayU(pos)
+ methods.append(single_payment_method)
else:
- payure_method = None
-
+ single_payment_method = None
-methods.append(PayPalRe())
-method_by_slug = {
- m.slug: m
- for m in methods
-}
+methods.append(
+ PayPal()
+)