link up purchase button to paypal (bug 684408)
This commit is contained in:
Родитель
aabbd06a4e
Коммит
b0af79630f
|
@ -219,9 +219,10 @@ class InstallButton(object):
|
|||
url = urlparams(roadblock, eula='', version=self.version.version)
|
||||
|
||||
if self.can_be_purchased:
|
||||
# TODO(gkobes): Use the actual price!
|
||||
# TODO(andym): make this faster and less naff
|
||||
# L10n: {0} is a price
|
||||
text = _('Purchase for {0}').format('$123.45')
|
||||
text = _('Purchase for {0}').format(self.addon
|
||||
.premium.price.price)
|
||||
|
||||
return text, url, os
|
||||
|
||||
|
|
|
@ -9,8 +9,10 @@
|
|||
data-developers="{{ addon.meet_the_dev_url() }}"
|
||||
data-name="{{ addon.name }}"
|
||||
{{ b.attrs()|xmlattr }}
|
||||
{% if addon.can_be_purchased() %}
|
||||
data-cost="$123.45" {# TODO(gkoberger): Change This! #}
|
||||
{% if waffle.switch('marketplace') and addon.can_be_purchased() %}
|
||||
data-purchase="{{ url('addons.purchase', addon.slug) }}?"
|
||||
{# TODO(andym): make this faster and less naff #}
|
||||
data-cost="{{ addon.premium.price.price }}"
|
||||
data-login-url="{{ url('users.login_modal') }}"
|
||||
{% endif %}
|
||||
{% if compat %}
|
||||
|
|
|
@ -28,6 +28,7 @@ from addons import cron
|
|||
from addons.models import (Addon, AddonDependency, AddonUpsell, AddonUser,
|
||||
Charity, Category)
|
||||
from files.models import File
|
||||
from market.models import AddonPremium
|
||||
from paypal.tests import other_error
|
||||
from stats.models import Contribution
|
||||
from translations.helpers import truncate
|
||||
|
@ -214,6 +215,48 @@ class TestContributeEmbedded(amo.tests.TestCase):
|
|||
assert not json.loads(res.content)['paykey']
|
||||
|
||||
|
||||
class TestPurchaseEmbedded(amo.tests.TestCase):
|
||||
fixtures = ['base/apps', 'base/addon_592', 'prices']
|
||||
|
||||
def setUp(self):
|
||||
waffle.models.Switch.objects.create(name='marketplace', active=True)
|
||||
self.addon = Addon.objects.get(pk=592)
|
||||
self.addon.update(premium_type=amo.ADDON_PREMIUM,
|
||||
status=amo.STATUS_PUBLIC)
|
||||
AddonPremium.objects.create(addon=self.addon, price_id=1)
|
||||
self.purchase_url = reverse('addons.purchase', args=[self.addon.slug])
|
||||
|
||||
def test_premium_only(self):
|
||||
self.addon.update(premium_type=amo.ADDON_FREE)
|
||||
eq_(self.client.get(self.purchase_url).status_code, 404)
|
||||
|
||||
@patch('paypal.get_paykey')
|
||||
def test_redirect(self, get_paykey):
|
||||
get_paykey.return_value = 'some-pay-key'
|
||||
res = self.client.get(self.purchase_url)
|
||||
assert 'some-pay-key' in res['Location']
|
||||
|
||||
@patch('paypal.get_paykey')
|
||||
def test_ajax(self, get_paykey):
|
||||
get_paykey.return_value = 'some-pay-key'
|
||||
res = self.client.get_ajax(self.purchase_url)
|
||||
assert json.loads(res.content)['paykey'] == 'some-pay-key'
|
||||
|
||||
@patch('paypal.get_paykey')
|
||||
def test_paykey_amount(self, get_paykey):
|
||||
# Test the amount the paykey for is the price.
|
||||
get_paykey.return_value = 'some-pay-key'
|
||||
self.client.get_ajax(self.purchase_url)
|
||||
# wtf? Can we get any more [0]'s there?
|
||||
eq_(get_paykey.call_args_list[0][0][0]['amount'], Decimal('0.99'))
|
||||
|
||||
@patch('paypal.get_paykey')
|
||||
def test_paykey_error(self, get_paykey):
|
||||
get_paykey.side_effect = Exception('woah')
|
||||
res = self.client.get_ajax(self.purchase_url)
|
||||
assert json.loads(res.content)['error'].startswith('There was an')
|
||||
|
||||
|
||||
class TestDeveloperPages(amo.tests.TestCase):
|
||||
fixtures = ['base/apps', 'base/addon_3615', 'base/addon_592',
|
||||
'base/users', 'addons/eula+contrib-addon',
|
||||
|
|
|
@ -30,6 +30,7 @@ detail_patterns = patterns('',
|
|||
url('^contribute/(?P<status>cancel|complete)$', views.paypal_result,
|
||||
name='addons.paypal'),
|
||||
|
||||
url('^purchase/$', views.purchase, name='addons.purchase'),
|
||||
|
||||
url('^about$', lambda r, addon_id: redirect('addons.installed',
|
||||
addon_id, permanent=True),
|
||||
|
|
|
@ -10,7 +10,6 @@ from django.conf import settings
|
|||
from django.db.models import Q
|
||||
from django.shortcuts import get_list_or_404, get_object_or_404, redirect
|
||||
from django.utils.translation import trans_real as translation
|
||||
from django.utils import http as urllib
|
||||
from django.views.decorators.cache import cache_page, cache_control
|
||||
from django.views.decorators.vary import vary_on_headers
|
||||
|
||||
|
@ -28,7 +27,6 @@ from amo import messages
|
|||
from amo.decorators import login_required
|
||||
from amo.forms import AbuseForm
|
||||
from amo.utils import sorted_groupby, randslice
|
||||
from amo.helpers import absolutify
|
||||
from amo.models import manual_order
|
||||
from amo import urlresolvers
|
||||
from amo.urlresolvers import reverse
|
||||
|
@ -39,7 +37,7 @@ import paypal
|
|||
from reviews.forms import ReviewForm
|
||||
from reviews.models import Review, GroupedRating
|
||||
from sharing.views import share as share_redirect
|
||||
from stats.models import GlobalStat, Contribution
|
||||
from stats.models import Contribution
|
||||
from translations.query import order_by_translation
|
||||
from translations.helpers import truncate
|
||||
from versions.models import Version
|
||||
|
@ -462,6 +460,41 @@ def developers(request, addon, page):
|
|||
'version': version})
|
||||
|
||||
|
||||
# TODO(andym): remove this once we figure out how to process for
|
||||
# anonymous users. For now we are concentrating on logged in users.
|
||||
@login_required
|
||||
@addon_view
|
||||
def purchase(request, addon):
|
||||
if not waffle.switch_is_active('marketplace'):
|
||||
raise http.Http404
|
||||
|
||||
if (not addon.is_premium() or not addon.premium):
|
||||
raise http.Http404
|
||||
|
||||
amount = addon.premium.price.price
|
||||
uuid_ = hashlib.md5(str(uuid.uuid4())).hexdigest()
|
||||
contrib_for = _(u'Purchase of {0}').format(jinja2.escape(addon.name))
|
||||
|
||||
paykey, error = '', ''
|
||||
try:
|
||||
paykey = paypal.get_paykey(dict(uuid=uuid_, slug=addon.slug,
|
||||
amount=amount, memo=contrib_for,
|
||||
email=addon.paypal_id,
|
||||
ip=request.META.get('REMOTE_ADDR')))
|
||||
except Exception:
|
||||
log.error('Error getting paykey, purchase of addon: %s' % addon.pk,
|
||||
exc_info=True)
|
||||
error = _('There was an error communicating with PayPal.')
|
||||
|
||||
url = '%s?paykey=%s' % (settings.PAYPAL_FLOW_URL, paykey)
|
||||
if request.GET.get('result_type') == 'json' or request.is_ajax():
|
||||
return http.HttpResponse(json.dumps({'url': url,
|
||||
'paykey': paykey,
|
||||
'error': error}),
|
||||
content_type='application/json')
|
||||
return http.HttpResponseRedirect(url)
|
||||
|
||||
|
||||
@addon_view
|
||||
def contribute(request, addon):
|
||||
contrib_type = request.GET.get('type', 'suggested')
|
||||
|
@ -476,7 +509,6 @@ def contribute(request, addon):
|
|||
amount = settings.DEFAULT_SUGGESTED_CONTRIBUTION
|
||||
|
||||
contribution_uuid = hashlib.md5(str(uuid.uuid4())).hexdigest()
|
||||
uuid_qs = urllib.urlencode({'uuid': contribution_uuid})
|
||||
|
||||
if addon.charity:
|
||||
name, paypal_id = addon.charity.name, addon.charity.paypal
|
||||
|
@ -484,26 +516,16 @@ def contribute(request, addon):
|
|||
name, paypal_id = addon.name, addon.paypal_id
|
||||
contrib_for = _(u'Contribution for {0}').format(jinja2.escape(name))
|
||||
|
||||
paykey, nice_error = None, None
|
||||
paykey, error = '', ''
|
||||
try:
|
||||
paykey = paypal.get_paykey({
|
||||
'return_url': absolutify('%s?%s' % (reverse('addons.paypal',
|
||||
args=[addon.slug, 'complete']),
|
||||
uuid_qs)),
|
||||
'cancel_url': absolutify('%s?%s' % (reverse('addons.paypal',
|
||||
args=[addon.slug, 'cancel']),
|
||||
uuid_qs)),
|
||||
'uuid': contribution_uuid,
|
||||
'amount': str(amount),
|
||||
'email': paypal_id,
|
||||
'ip': request.META.get('REMOTE_ADDR'),
|
||||
'memo': contrib_for})
|
||||
except paypal.AuthError, error:
|
||||
paypal_log.error('Authentication error: %s' % error)
|
||||
nice_error = _('There was a problem communicating with Paypal.')
|
||||
except Exception, error:
|
||||
paypal_log.error('Error: %s' % error)
|
||||
nice_error = _('There was a problem with that contribution.')
|
||||
paykey = paypal.get_paykey(dict(uuid=contribution_uuid,
|
||||
slug=addon.slug, amount=amount,
|
||||
email=paypal_id, memo=contrib_for,
|
||||
ip=request.META.get('REMOTE_ADDR')))
|
||||
except Exception:
|
||||
log.error('Error getting paykey, contribution for addon: %s'
|
||||
% addon.pk, exc_info=True)
|
||||
error = _('There was an error communicating with PayPal.')
|
||||
|
||||
if paykey:
|
||||
contrib = Contribution(addon_id=addon.id,
|
||||
|
@ -527,7 +549,7 @@ def contribute(request, addon):
|
|||
# not have a paykey and the JS can cope appropriately.
|
||||
return http.HttpResponse(json.dumps({'url': url,
|
||||
'paykey': paykey,
|
||||
'error': nice_error}),
|
||||
'error': error}),
|
||||
content_type='application/json')
|
||||
return http.HttpResponseRedirect(url)
|
||||
|
||||
|
|
|
@ -29,20 +29,23 @@ paypal_log = commonware.log.getLogger('z.paypal')
|
|||
def get_paykey(data):
|
||||
"""
|
||||
Gets a paykey from Paypal. Need to pass in the following in data:
|
||||
return_url and cancel_url: where user goes back to (required)
|
||||
slug: addon, will form urls for where user goes back to (required)
|
||||
email: who the money is going to (required)
|
||||
amount: the amount of money (required)
|
||||
ip: ip address of end user (required)
|
||||
uuid: contribution_uuid (required)
|
||||
memo: any nice message
|
||||
"""
|
||||
complete = reverse('addons.paypal', args=[data['slug'], 'complete'])
|
||||
cancel = reverse('addons.paypal', args=[data['slug'], 'cancel'])
|
||||
uuid_qs = urllib.urlencode({'uuid': data['uuid']})
|
||||
|
||||
paypal_data = {
|
||||
'actionType': 'PAY',
|
||||
'requestEnvelope.errorLanguage': 'US',
|
||||
'currencyCode': 'USD',
|
||||
'cancelUrl': data['cancel_url'],
|
||||
'returnUrl': data['return_url'],
|
||||
'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'],
|
||||
|
@ -55,7 +58,12 @@ def get_paykey(data):
|
|||
paypal_data['memo'] = data['memo']
|
||||
|
||||
with statsd.timer('paypal.paykey.retrieval'):
|
||||
response = _call(settings.PAYPAL_PAY_URL, paypal_data, ip=data['ip'])
|
||||
try:
|
||||
response = _call(settings.PAYPAL_PAY_URL, paypal_data,
|
||||
ip=data['ip'])
|
||||
except AuthError, error:
|
||||
paypal_log.error('Authentication error: %s' % error)
|
||||
raise
|
||||
return response['payKey']
|
||||
|
||||
|
||||
|
|
|
@ -29,8 +29,7 @@ other_error = ('error(0).errorId=520001'
|
|||
|
||||
class TestPayPal(amo.tests.TestCase):
|
||||
def setUp(self):
|
||||
self.data = {'return_url': absolutify(reverse('home')),
|
||||
'cancel_url': absolutify(reverse('home')),
|
||||
self.data = {'slug': 'xx',
|
||||
'amount': 10,
|
||||
'email': 'someone@somewhere.com',
|
||||
'uuid': time.time(),
|
||||
|
|
|
@ -377,7 +377,8 @@ jQuery.fn.addPaypal = function(html, allowClick) {
|
|||
}));
|
||||
}
|
||||
paypal.append($("<button>", {'class': 'button prominent paypal',
|
||||
'html': gettext('Pay <small>with</small> Pay<em>Pal</em>')}));
|
||||
'href': $install.attr('data-purchase'),
|
||||
'html': gettext('Pay <small>with</small> Pay<em>Pal</em>')}));
|
||||
paypal.append($('<p>', {'text': gettext('Complete your purchase with PayPal. No account necessary.')}));
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ $(document).ready(function() {
|
|||
$("#contribute-why").popup("#contribute-more-info", {
|
||||
pointTo: "#contribute-more-info"
|
||||
});
|
||||
$('div.contribute a.suggested-amount').live('click', function(event) {
|
||||
$('div.contribute a.suggested-amount,button.paypal').live('click', function(event) {
|
||||
var el = this;
|
||||
$(el).addClass('ajax-loading');
|
||||
$.ajax({
|
||||
|
|
Загрузка…
Ссылка в новой задаче