split off some money, but for purchases only (bug 695508)

This commit is contained in:
Andy McKay 2011-10-19 11:29:55 -07:00
Родитель 0e6dc46419
Коммит 039e737352
5 изменённых файлов: 99 добавлений и 10 удалений

Просмотреть файл

@ -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