prevent abstract from flowing around cover
[wolnelektury.git] / src / paypal / rest.py
1 # -*- coding: utf-8 -*-
2 # This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
3 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
4 #
5 from datetime import timedelta
6
7 import paypalrestsdk
8 import pytz
9 from django.contrib.sites.models import Site
10 from django.core.urlresolvers import reverse
11 from django.utils import timezone
12 from paypalrestsdk import BillingPlan, BillingAgreement, ResourceNotFound
13 from django.conf import settings
14 from .models import BillingPlan as BillingPlanModel
15
16 paypalrestsdk.configure(settings.PAYPAL_CONFIG)
17
18
19 class PaypalError(Exception):
20     pass
21
22
23 def absolute_url(url_name):
24     return "http://%s%s" % (Site.objects.get_current().domain, reverse(url_name))
25
26
27 def create_plan(amount):
28     billing_plan = BillingPlan({
29         "name": "Cykliczna darowizna na Wolne Lektury: %s zł" % amount,
30         "description": "Cykliczna darowizna na wsparcie Wolnych Lektur",
31         "merchant_preferences": {
32             "auto_bill_amount": "yes",
33             "return_url": absolute_url('paypal_return'),
34             "cancel_url": absolute_url('paypal_cancel'),
35             # "initial_fail_amount_action": "continue",
36             "max_fail_attempts": "3",
37         },
38         "payment_definitions": [
39             {
40                 "amount": {
41                     "currency": "PLN",
42                     "value": str(amount),
43                 },
44                 "cycles": "0",
45                 "frequency": "MONTH",
46                 "frequency_interval": "1",
47                 "name": "Cykliczna darowizna",
48                 "type": "REGULAR",
49             }
50         ],
51         "type": "INFINITE",
52     })
53
54     if not billing_plan.create():
55         raise PaypalError(billing_plan.error)
56     if not billing_plan.activate():
57         raise PaypalError(billing_plan.error)
58     plan, created = BillingPlanModel.objects.get_or_create(amount=amount, defaults={'plan_id': billing_plan.id})
59     return plan.plan_id
60
61
62 def get_link(links, rel):
63     for link in links:
64         if link.rel == rel:
65             return link.href
66
67
68 def create_agreement(amount):
69     try:
70         plan = BillingPlanModel.objects.get(amount=amount)
71     except BillingPlanModel.DoesNotExist:
72         plan_id = create_plan(amount)
73     else:
74         plan_id = plan.plan_id
75     start = (timezone.now() + timedelta(0, 3600*24)).astimezone(pytz.utc).strftime('%Y-%m-%dT%H:%M:%SZ')
76     billing_agreement = BillingAgreement({
77         "name": "Subskrypcja klubu WL",
78         "description": "Cykliczne wspieranie Wolnych Lektur kwotą %s złotych" % amount,
79         "start_date": start,
80         "plan": {
81             "id": plan_id,
82         },
83         "payer": {
84             "payment_method": "paypal"
85         },
86     })
87
88     response = billing_agreement.create()
89     if response:
90         return billing_agreement
91     else:
92         raise PaypalError(billing_agreement.error)
93
94
95 def agreement_approval_url(amount):
96     agreement = create_agreement(amount)
97     return get_link(agreement.links, 'approval_url')
98
99
100 def get_agreement(agreement_id):
101     try:
102         return BillingAgreement.find(agreement_id)
103     except ResourceNotFound:
104         return None
105
106
107 def check_agreement(agreement_id):
108     a = get_agreement(agreement_id)
109     if a:
110         return a.state == 'Active'
111
112
113 def execute_agreement(token):
114     return BillingAgreement.execute(token)