You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

326 lines
10 KiB
Python

from datetime import timedelta
from urllib.parse import parse_qs
from django.test import TestCase, RequestFactory
from django.http import HttpResponseRedirect
from django.contrib.auth.models import User
from payments.models import Payment, Subscription
from payments.backends import PaypalBackend
PAYPAL_IPN_TEST = '''\
mc_gross=3.00&\
protection_eligibility=Eligible&\
address_status=confirmed&\
payer_id=LPLWNMTBWMFAY&\
tax=0.00&\
address_street=1+Main+St&\
payment_date=20%3A12%3A59+Jan+13%2C+2009+PST&\
payment_status=Completed&\
charset=windows-1252&\
address_zip=95131&\
first_name=Test&\
mc_fee=0.88&\
address_country_code=US&\
address_name=Test+User&\
notify_version=2.6&\
custom=&\
payer_status=verified&\
address_country=United+States&\
address_city=San+Jose&\
quantity=1&\
payer_email=test_user@example.com&\
txn_id=61E67681CH3238416&\
payment_type=instant&\
last_name=User&\
address_state=CA&\
receiver_email=test_business@example.com&\
payment_fee=0.88&\
receiver_id=S8XGHLYDW9T3S&\
txn_type=express_checkout&\
item_name=&\
mc_currency=EUR&\
item_number=&\
residence_country=US&\
test_ipn=1&\
handling_amount=0.00&\
transaction_subject=&\
payment_gross=3.00&\
shipping=0.00'''
PAYPAL_IPN_SUBSCR_PAYMENT = '''\
transaction_subject=VPN+Payment&\
payment_date=11%3A19%3A00+Sep+04%2C+2016+PDT&\
txn_type=subscr_payment&\
subscr_id=I-1S262863X133&\
last_name=buyer&\
residence_country=FR&\
item_name=VPN+Payment&\
payment_gross=&\
mc_currency=EUR&\
business=test_business@example.com&\
payment_type=instant&\
protection_eligibility=Ineligible&\
payer_status=verified&\
test_ipn=1&\
payer_email=test_user@example.com&\
txn_id=097872679P963871Y&\
receiver_email=test_business@example.com&\
first_name=test&\
payer_id=APYYVSFLNPWUU&\
receiver_id=MGT8TQ8GC4944&\
payment_status=Completed&\
payment_fee=&\
mc_fee=0.56&\
mc_gross=9.00&\
charset=windows-1252&\
notify_version=3.8&\
ipn_track_id=546a4aa4300a0'''
PAYPAL_IPN_SUBSCR_CANCEL = '''\
txn_type=subscr_cancel&\
subscr_id=I-E5SCT6936H40&\
last_name=buyer&\
residence_country=FR&\
mc_currency=EUR&\
item_name=VPN+Payment&\
business=test_business@example.com&\
recurring=1&\
payer_status=verified&\
test_ipn=1&\
payer_email=test_user@example.com&\
first_name=test&\
receiver_email=test_business@example.com&\
payer_id=APYYVSFLNPWUU&\
reattempt=1&\
subscr_date=17%3A35%3A14+Sep+04%2C+2016+PDT&\
charset=windows-1252&\
notify_version=3.8&\
period3=3+M&\
mc_amount3=9.00&\
ipn_track_id=474870d13b375'''
PAYPAL_IPN_SUBSCR_SIGNUP = '''\
txn_type=subscr_signup&\
subscr_id=I-1S262863X133&\
last_name=buyer&\
residence_country=FR&\
mc_currency=EUR&\
item_name=VPN+Payment&\
business=test_business@example.com&\
recurring=1&\
payer_status=verified&\
test_ipn=1&\
payer_email=test_user@example.com&\
first_name=test&\
receiver_email=test_business@example.com&\
payer_id=APYYVSFLNPWUU&\
reattempt=1&\
subscr_date=11%3A18%3A57+Sep+04%2C+2016+PDT&\
charset=windows-1252&\
notify_version=3.8&\
period3=3+M&\
mc_amount3=9.00&\
ipn_track_id=546a4aa4300a0'''
class PaypalBackendTest(TestCase):
def setUp(self):
self.user = User.objects.create_user('test', 'test_user@example.com', None)
def test_paypal(self):
# TODO: This checks the most simple and perfect payment that could
# happen, but not errors or other/invalid IPN
payment = Payment.objects.create(
user=self.user,
time=timedelta(days=30),
backend_id='paypal',
amount=300
)
settings = dict(
test=True,
title='Test Title',
currency='EUR',
address='test_business@example.com',
)
with self.settings(ROOT_URL='root'):
backend = PaypalBackend(settings)
redirect = backend.new_payment(payment)
self.assertIsInstance(redirect, HttpResponseRedirect)
host, params = redirect.url.split('?', 1)
params = parse_qs(params)
expected_notify_url = 'root/payments/callback/paypal/%d' % payment.id
expected_return_url = 'root/payments/view/%d' % payment.id
expected_cancel_url = 'root/payments/cancel/%d' % payment.id
self.assertEqual(params['cmd'][0], '_xclick')
self.assertEqual(params['notify_url'][0], expected_notify_url)
self.assertEqual(params['return'][0], expected_return_url)
self.assertEqual(params['cancel_return'][0], expected_cancel_url)
self.assertEqual(params['business'][0], 'test_business@example.com')
self.assertEqual(params['currency_code'][0], 'EUR')
self.assertEqual(params['amount'][0], '3.00')
self.assertEqual(params['item_name'][0], 'Test Title')
# Replace PaypalBackend.verify_ipn to not call the PayPal API
# we will assume the IPN is authentic
backend.verify_ipn = lambda request: True
ipn_url = '/payments/callback/paypal/%d' % payment.id
ipn_request = RequestFactory().post(
ipn_url,
content_type='application/x-www-form-urlencoded',
data=PAYPAL_IPN_TEST)
r = backend.callback(payment, ipn_request)
self.assertTrue(r)
self.assertEqual(payment.status, 'confirmed')
self.assertEqual(payment.paid_amount, 300)
self.assertEqual(payment.backend_extid, '61E67681CH3238416')
def test_paypal_ipn_error(self):
payment = Payment.objects.create(
user=self.user,
time=timedelta(days=30),
backend_id='paypal',
amount=300
)
settings = dict(
test=True,
title='Test Title',
currency='EUR',
address='test_business@example.com',
)
with self.settings(ROOT_URL='root'):
backend = PaypalBackend(settings)
redirect = backend.new_payment(payment)
self.assertIsInstance(redirect, HttpResponseRedirect)
host, params = redirect.url.split('?', 1)
params = parse_qs(params)
# Replace PaypalBackend.verify_ipn to not call the PayPal API
# we will assume the IPN is authentic
backend.verify_ipn = lambda request: True
ipn_url = '/payments/callback/paypal/%d' % payment.id
ipn_request = RequestFactory().post(
ipn_url,
content_type='application/x-www-form-urlencoded',
data=PAYPAL_IPN_TEST)
r = backend.callback(payment, ipn_request)
self.assertTrue(r)
self.assertEqual(payment.status, 'confirmed')
self.assertEqual(payment.paid_amount, 300)
self.assertEqual(payment.backend_extid, '61E67681CH3238416')
def test_paypal_subscr(self):
subscription = Subscription.objects.create(
user=self.user,
backend_id='paypal',
period='3m'
)
settings = dict(
test=True,
title='Test Title',
currency='EUR',
address='test_business@example.com',
)
with self.settings(ROOT_URL='root'):
backend = PaypalBackend(settings)
redirect = backend.new_subscription(subscription)
self.assertIsInstance(redirect, HttpResponseRedirect)
host, params = redirect.url.split('?', 1)
params = parse_qs(params)
expected_notify_url = 'root/payments/callback/paypal_subscr/%d' % subscription.id
expected_return_url = 'root/payments/return_subscr/%d' % subscription.id
expected_cancel_url = 'root/account/'
self.assertEqual(params['cmd'][0], '_xclick-subscriptions')
self.assertEqual(params['notify_url'][0], expected_notify_url)
self.assertEqual(params['return'][0], expected_return_url)
self.assertEqual(params['cancel_return'][0], expected_cancel_url)
self.assertEqual(params['business'][0], 'test_business@example.com')
self.assertEqual(params['currency_code'][0], 'EUR')
self.assertEqual(params['a3'][0], '9.00')
self.assertEqual(params['p3'][0], '3')
self.assertEqual(params['t3'][0], 'M')
self.assertEqual(params['item_name'][0], 'Test Title')
# Replace PaypalBackend.verify_ipn to not call the PayPal API
# we will assume the IPN is authentic
backend.verify_ipn = lambda request: True
self.assertEqual(subscription.status, 'new')
# 1. the subscr_payment IPN
ipn_url = '/payments/callback/paypal_subscr/%d' % subscription.id
ipn_request = RequestFactory().post(
ipn_url,
content_type='application/x-www-form-urlencoded',
data=PAYPAL_IPN_SUBSCR_PAYMENT)
r = backend.callback_subscr(subscription, ipn_request)
self.assertTrue(r)
self.assertEqual(subscription.status, 'active')
self.assertEqual(subscription.backend_extid, 'I-1S262863X133')
payments = Payment.objects.filter(subscription=subscription).all()
self.assertEqual(len(payments), 1)
self.assertEqual(payments[0].amount, 900)
self.assertEqual(payments[0].paid_amount, 900)
self.assertEqual(payments[0].backend_extid, '097872679P963871Y')
# 2. the subscr_signup IPN
# We don't expect anything to happen here
ipn_url = '/payments/callback/paypal_subscr/%d' % subscription.id
ipn_request = RequestFactory().post(
ipn_url,
content_type='application/x-www-form-urlencoded',
data=PAYPAL_IPN_SUBSCR_SIGNUP)
r = backend.callback_subscr(subscription, ipn_request)
self.assertTrue(r)
self.assertEqual(subscription.status, 'active')
self.assertEqual(subscription.backend_extid, 'I-1S262863X133')
payments = Payment.objects.filter(subscription=subscription).all()
self.assertEqual(len(payments), 1)
self.assertEqual(payments[0].amount, 900)
self.assertEqual(payments[0].paid_amount, 900)
self.assertEqual(payments[0].backend_extid, '097872679P963871Y')
# 3. the subscr_cancel IPN
ipn_url = '/payments/callback/paypal_subscr/%d' % subscription.id
ipn_request = RequestFactory().post(
ipn_url,
content_type='application/x-www-form-urlencoded',
data=PAYPAL_IPN_SUBSCR_CANCEL)
r = backend.callback_subscr(subscription, ipn_request)
self.assertTrue(r)
self.assertEqual(subscription.status, 'cancelled')
self.assertEqual(subscription.backend_extid, 'I-1S262863X133')
payments = Payment.objects.filter(subscription=subscription).all()
self.assertEqual(len(payments), 1)