from django.contrib.sites.models import Site
from django.core.urlresolvers import reverse
from django.utils import timezone
-from paypalrestsdk import BillingPlan, BillingAgreement, ResourceNotFound
from django.conf import settings
-from .models import BillingPlan as BillingPlanModel, BillingAgreement as BillingAgreementModel
+from .models import BillingPlan, BillingAgreement
paypalrestsdk.configure(settings.PAYPAL_CONFIG)
def create_plan(amount):
- billing_plan = BillingPlan({
+ billing_plan = paypalrestsdk.BillingPlan({
"name": "Cykliczna darowizna na Wolne Lektury: %s zł" % amount,
"description": "Cykliczna darowizna na wsparcie Wolnych Lektur",
"merchant_preferences": {
raise PaypalError(billing_plan.error)
if not billing_plan.activate():
raise PaypalError(billing_plan.error)
- plan, created = BillingPlanModel.objects.get_or_create(amount=amount, defaults={'plan_id': billing_plan.id})
+ plan, created = BillingPlan.objects.get_or_create(amount=amount, defaults={'plan_id': billing_plan.id})
return plan.plan_id
def create_agreement(amount, app=False):
try:
- plan = BillingPlanModel.objects.get(amount=amount)
- except BillingPlanModel.DoesNotExist:
+ plan = BillingPlan.objects.get(amount=amount)
+ except BillingPlan.DoesNotExist:
plan_id = create_plan(amount)
else:
plan_id = plan.plan_id
start = (timezone.now() + timedelta(0, 3600*24)).astimezone(pytz.utc).strftime('%Y-%m-%dT%H:%M:%SZ')
- billing_agreement = BillingAgreement({
+ billing_agreement = paypalrestsdk.BillingAgreement({
"name": u"Subskrypcja klubu WL",
"description": u"Stałe wsparcie Wolnych Lektur kwotą %s złotych" % amount,
"start_date": start,
def get_agreement(agreement_id):
try:
- return BillingAgreement.find(agreement_id)
- except ResourceNotFound:
+ return paypalrestsdk.BillingAgreement.find(agreement_id)
+ except paypalrestsdk.ResourceNotFound:
return None
def user_is_subscribed(user):
- agreements = BillingAgreementModel.objects.filter(user=user)
+ agreements = BillingAgreement.objects.filter(user=user)
return any(agreement.check_agreement() for agreement in agreements)
def execute_agreement(token):
- return BillingAgreement.execute(token)
+ return paypalrestsdk.BillingAgreement.execute(token)
--- /dev/null
+# -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
+from django.contrib.auth.models import User
+from mock import Mock, patch, DEFAULT
+from catalogue.test_utils import WLTestCase
+from .models import BillingPlan
+
+
+BillingAgreementMock = Mock(
+ execute=Mock(
+ return_value=Mock(
+ plan=Mock(
+ payment_definitions=[
+ Mock(
+ amount={'value': '100'}
+ )
+ ]
+ )
+ )
+ )
+)
+
+
+class PaypalTests(WLTestCase):
+ @classmethod
+ def setUpClass(cls):
+ cls.user = User(username='test')
+ cls.user.set_password('test')
+ cls.user.save()
+
+ @classmethod
+ def tearDownClass(cls):
+ cls.user.delete()
+
+ def test_paypal_form(self):
+ response = self.client.get('/paypal/form/')
+ self.assertEqual(response.status_code, 200)
+
+ def test_paypal_form_unauthorized(self):
+ """Legacy flow: only allow payment for logged-in users."""
+ response = self.client.post('/paypal/form/', {"amount": "0"})
+ self.assertEqual(response.status_code, 403)
+
+ def test_paypal_form_invalid(self):
+ """Paypal form: error on bad input."""
+ self.client.login(username='test', password='test')
+
+ response = self.client.post('/paypal/form/', {"amount": "0"})
+ self.assertEqual(response.status_code, 200)
+ self.assertEqual(
+ len(response.context['form'].errors['amount']),
+ 1)
+
+ @patch.multiple('paypalrestsdk',
+ BillingPlan=DEFAULT,
+ BillingAgreement=DEFAULT
+ )
+ def test_paypal_form_valid(self, BillingPlan, BillingAgreement):
+ self.client.login(username='test', password='test')
+ response = self.client.post('/paypal/form/', {"amount": "100"})
+ self.assertEqual(response.status_code, 302)
+ # Assert: BillingPlan created? BillingAgreement created?
+ # Models created?
+
+ @patch.multiple('paypalrestsdk',
+ BillingPlan=DEFAULT,
+ BillingAgreement=DEFAULT,
+ )
+ def test_paypal_form_valid(self, BillingPlan, BillingAgreement):
+ self.client.login(username='test', password='test')
+ response = self.client.post('/paypal/app-form/', {"amount": "100"})
+ self.assertEqual(response.status_code, 302)
+
+ @patch.multiple('paypalrestsdk',
+ BillingAgreement=BillingAgreementMock
+ )
+ def test_paypal_return(self):
+ self.client.login(username='test', password='test')
+ BillingPlan.objects.create(amount=100)
+ response = self.client.get('/paypal/return/?token=secret-token')
+
+ def test_paypal_cancel(self):
+ response = self.client.get('/paypal/cancel/')
+ self.assertEqual(response.status_code, 200)
from api.piston_patch import HttpResponseAppRedirect
from paypal.forms import PaypalSubscriptionForm
from paypal.rest import execute_agreement, check_agreement, agreement_approval_url, PaypalError
-from paypal.models import BillingAgreement as BillingAgreementModel, BillingPlan
+from paypal.models import BillingAgreement, BillingPlan
def paypal_form(request, app=False):
token = request.GET.get('token')
if not token:
raise Http404
- if not BillingAgreementModel.objects.filter(token=token):
+ if not BillingAgreement.objects.filter(token=token):
resource = execute_agreement(token)
if resource.id:
amount = int(Decimal(resource.plan.payment_definitions[0].amount['value']))
plan = BillingPlan.objects.get(amount=amount)
active = check_agreement(resource.id)
- BillingAgreementModel.objects.create(
+ BillingAgreement.objects.create(
agreement_id=resource.id, user=request.user, plan=plan, active=active, token=token)
else:
resource = None