split off some money, but for purchases only (bug 695508)
This commit is contained in:
Родитель
0e6dc46419
Коммит
039e737352
|
@ -259,6 +259,14 @@ class TestContributeEmbedded(amo.tests.TestCase):
|
|||
doc = pq(self.client.get(url).content)
|
||||
eq_(len(doc('#paypal-thanks')), 0)
|
||||
|
||||
@patch('paypal.get_paykey')
|
||||
def test_not_split(self, get_paykey):
|
||||
get_paykey.return_value = None
|
||||
self.client.get('%s?%s' % (
|
||||
reverse('addons.contribute', args=[self.addon.slug]),
|
||||
'result_type=json'))
|
||||
assert 'chains' not in get_paykey.call_args_list[0][0][0].keys()
|
||||
|
||||
|
||||
class TestPurchaseEmbedded(amo.tests.TestCase):
|
||||
fixtures = ['base/apps', 'base/addon_592', 'base/users', 'prices']
|
||||
|
@ -410,6 +418,14 @@ class TestPurchaseEmbedded(amo.tests.TestCase):
|
|||
eq_(doc('.trigger_app_install').attr('data-manifest-url'),
|
||||
self.addon.manifest_url)
|
||||
|
||||
@patch('paypal.get_paykey')
|
||||
def test_split(self, get_paykey):
|
||||
get_paykey.return_value = None
|
||||
self.client.get('%s?%s' % (
|
||||
reverse('addons.purchase', args=[self.addon.slug]),
|
||||
'result_type=json'))
|
||||
assert 'chains' in get_paykey.call_args_list[0][0][0].keys()
|
||||
|
||||
|
||||
class TestDeveloperPages(amo.tests.TestCase):
|
||||
fixtures = ['base/apps', 'base/addon_3615', 'base/addon_592',
|
||||
|
|
|
@ -488,7 +488,8 @@ def purchase(request, addon):
|
|||
amount=amount, memo=contrib_for, email=addon.paypal_id,
|
||||
ip=request.META.get('REMOTE_ADDR'),
|
||||
pattern='addons.purchase.finished',
|
||||
qs={'realurl': request.GET.get('realurl')}))
|
||||
qs={'realurl': request.GET.get('realurl')},
|
||||
chains=settings.PAYPAL_CHAINS))
|
||||
except:
|
||||
log.error('Error getting paykey, purchase of addon: %s' % addon.pk,
|
||||
exc_info=True)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import contextlib
|
||||
from decimal import Decimal
|
||||
import socket
|
||||
import urllib
|
||||
import urllib2
|
||||
|
@ -6,7 +7,7 @@ import urlparse
|
|||
import re
|
||||
|
||||
from django.conf import settings
|
||||
from django.utils.http import urlencode
|
||||
from django.utils.http import urlencode, urlquote
|
||||
|
||||
import commonware.log
|
||||
from statsd import statsd
|
||||
|
@ -35,6 +36,32 @@ def should_ignore_paypal():
|
|||
return settings.DEBUG and 'sandbox' not in settings.PAYPAL_PERMISSIONS_URL
|
||||
|
||||
|
||||
def add_receivers(chains, email, amount, uuid):
|
||||
"""
|
||||
Split a payment down into multiple receivers using the chains passed in.
|
||||
"""
|
||||
remainder = Decimal(str(amount))
|
||||
amount = float(amount)
|
||||
result = {}
|
||||
for number, chain in enumerate(chains, 1):
|
||||
percent, destination = chain
|
||||
this = Decimal(amount * (percent / 100.0)).quantize(Decimal('.01'))
|
||||
remainder = remainder - this
|
||||
result.update({
|
||||
'receiverList.receiver(%s).email' % number: destination,
|
||||
'receiverList.receiver(%s).amount' % number: str(this),
|
||||
'receiverList.receiver(%s).paymentType' % number: 'DIGITALGOODS',
|
||||
})
|
||||
result.update({
|
||||
'receiverList.receiver(0).email': email,
|
||||
'receiverList.receiver(0).amount': str(remainder),
|
||||
'receiverList.receiver(0).invoiceID': 'mozilla-%s' % uuid,
|
||||
'receiverList.receiver(0).primary': 'TRUE',
|
||||
'receiverList.receiver(0).paymentType': 'DIGITALGOODS',
|
||||
})
|
||||
return result
|
||||
|
||||
|
||||
def get_paykey(data):
|
||||
"""
|
||||
Gets a paykey from Paypal. Need to pass in the following in data:
|
||||
|
@ -56,18 +83,15 @@ def get_paykey(data):
|
|||
|
||||
paypal_data = {
|
||||
'actionType': 'PAY',
|
||||
'requestEnvelope.errorLanguage': 'US',
|
||||
'currencyCode': 'USD',
|
||||
'cancelUrl': absolutify('%s?%s' % (cancel, uuid_qs)),
|
||||
'returnUrl': absolutify('%s?%s' % (complete, uuid_qs)),
|
||||
'receiverList.receiver(0).email': data['email'],
|
||||
'receiverList.receiver(0).amount': data['amount'],
|
||||
'receiverList.receiver(0).invoiceID': 'mozilla-%s' % data['uuid'],
|
||||
'receiverList.receiver(0).primary': 'TRUE',
|
||||
'receiverList.receiver(0).paymentType': 'DIGITALGOODS',
|
||||
'trackingId': data['uuid'],
|
||||
'ipnNotificationUrl': absolutify(reverse('amo.paypal'))}
|
||||
|
||||
paypal_data.update(add_receivers(data.get('chains', ()), data['email'],
|
||||
data['amount'], data['uuid']))
|
||||
|
||||
if data.get('memo'):
|
||||
paypal_data['memo'] = data['memo']
|
||||
|
||||
|
@ -227,10 +251,15 @@ def _call(url, paypal_data, ip=None):
|
|||
if ip:
|
||||
request.add_header('X-PAYPAL-DEVICE-IPADDRESS', ip)
|
||||
|
||||
|
||||
# Warning, a urlencode will not work with chained payments, it must
|
||||
# be sorted and the key should not be escaped.
|
||||
data = '&'.join(['%s=%s' % (k, urlquote(v))
|
||||
for k, v in sorted(paypal_data.items())])
|
||||
opener = urllib2.build_opener()
|
||||
try:
|
||||
with socket_timeout(10):
|
||||
feeddata = opener.open(request, urlencode(paypal_data)).read()
|
||||
feeddata = opener.open(request, data).read()
|
||||
except Exception, error:
|
||||
paypal_log.error('HTTP Error: %s' % error)
|
||||
raise
|
||||
|
|
|
@ -61,15 +61,54 @@ class TestPayKey(amo.tests.TestCase):
|
|||
qs = _call.call_args[0][1]['returnUrl'].split('?')[1]
|
||||
eq_(dict(urlparse.parse_qsl(qs))['foo'], 'bar')
|
||||
|
||||
@mock.patch.object(settings, 'SITE_URL', 'http://foo.com')
|
||||
def _test_no_mock(self):
|
||||
# Remove _ and run if you'd like to try unmocked.
|
||||
return paypal.get_paykey(self.data)
|
||||
data = self.data.copy()
|
||||
data['email'] = 'andy_1318364497_biz@gmail.com'
|
||||
#data['chains'] = ((13.4, 'wtf_1315341929_biz@gmail.com'),)
|
||||
return paypal.get_paykey(data)
|
||||
|
||||
def _test_check_purchase_no_mock(self):
|
||||
# Remove _ and run if you'd like to try this unmocked.
|
||||
key = paypal.get_paykey(self.data)
|
||||
eq_(paypal.check_purchase(key), 'CREATED')
|
||||
|
||||
def test_split(self):
|
||||
chains = ((30, 'us@moz.com'),)
|
||||
res = paypal.add_receivers(chains, 'a@a.com', 1.99, '123')
|
||||
eq_(res['receiverList.receiver(1).amount'], '0.60')
|
||||
eq_(res['receiverList.receiver(1).email'], 'us@moz.com')
|
||||
eq_(res['receiverList.receiver(0).amount'], '1.39')
|
||||
eq_(res['receiverList.receiver(0).email'], 'a@a.com')
|
||||
|
||||
def test_multiple_split(self):
|
||||
chains = ((30, 'us@moz.com'), (10, 'me@moz.com'))
|
||||
res = paypal.add_receivers(chains, 'a@a.com', 1.99, '123')
|
||||
eq_(res['receiverList.receiver(2).amount'], '0.20')
|
||||
eq_(res['receiverList.receiver(1).amount'], '0.60')
|
||||
eq_(res['receiverList.receiver(0).amount'], '1.19')
|
||||
|
||||
def test_no_split(self):
|
||||
res = paypal.add_receivers((), 'a@a.com', 1.99, '123')
|
||||
eq_(res['receiverList.receiver(0).amount'], '1.99')
|
||||
|
||||
@mock.patch('paypal._call')
|
||||
def test_dict_no_split(self, _call):
|
||||
data = self.data.copy()
|
||||
_call.return_value = {'payKey': '123'}
|
||||
paypal.get_paykey(data)
|
||||
eq_(_call.call_args[0][1]['receiverList.receiver(0).amount'], '10')
|
||||
|
||||
@mock.patch('paypal._call')
|
||||
def test_dict_split(self, _call):
|
||||
data = self.data.copy()
|
||||
data['chains'] = ((13.4, 'us@moz.com'),)
|
||||
_call.return_value = {'payKey': '123'}
|
||||
paypal.get_paykey(data)
|
||||
eq_(_call.call_args[0][1]['receiverList.receiver(0).amount'], '8.66')
|
||||
eq_(_call.call_args[0][1]['receiverList.receiver(1).amount'], '1.34')
|
||||
|
||||
|
||||
class TestPurchase(amo.tests.TestCase):
|
||||
|
||||
|
|
|
@ -900,6 +900,10 @@ PAYPAL_JS_URL = 'https://www.paypalobjects.com/js/external/dg.js'
|
|||
PAYPAL_EMBEDDED_AUTH = {'USER': '', 'PASSWORD': '', 'SIGNATURE': ''}
|
||||
PAYPAL_EMAIL = ''
|
||||
|
||||
# PayPal split for Adaptive Payments.
|
||||
# A tuple of lists of % and destination.
|
||||
PAYPAL_CHAINS = ()
|
||||
|
||||
# Contribution limit, one time and monthly
|
||||
MAX_CONTRIBUTION = 1000
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче