def test_dict_split(self, _call): data = self.data.copy() data["chains"] = ((13.4, "*****@*****.**"),) _call.return_value = {"payKey": "123", "paymentExecStatus": ""} paypal.get_paykey(data) eq_(_call.call_args[0][1]["receiverList.receiver(0).amount"], "10") eq_(_call.call_args[0][1]["receiverList.receiver(1).amount"], "1.34")
def test_preapproval_key(self, _call): _call.return_value = {'payKey': '123', 'paymentExecStatus': ''} paypal.get_paykey(self.get_pre_data()) called = _call.call_args[0][1] eq_(called['preapprovalKey'], 'xyz') assert 'receiverList.receiver(0).paymentType' not in called
def test_qs_passed(self, _call): data = self.data.copy() data['qs'] = {'foo': 'bar'} _call.return_value = {'payKey': '123', 'paymentExecStatus': ''} paypal.get_paykey(data) qs = _call.call_args[0][1]['returnUrl'].split('?')[1] eq_(dict(urlparse.parse_qsl(qs))['foo'], 'bar')
def test_qs_passed(self, _call): data = self.data.copy() data["qs"] = {"foo": "bar"} _call.return_value = {"payKey": "123", "paymentExecStatus": ""} paypal.get_paykey(data) qs = _call.call_args[0][1]["returnUrl"].split("?")[1] eq_(dict(urlparse.parse_qsl(qs))["foo"], "bar")
def test_preapproval_key(self, _call): _call.return_value = {"payKey": "123", "paymentExecStatus": ""} paypal.get_paykey(self.get_pre_data()) called = _call.call_args[0][1] eq_(called["preapprovalKey"], "xyz") assert "receiverList.receiver(0).paymentType" not in called
def test_dict_split(self, _call): data = self.data.copy() data['chains'] = ((13.4, '*****@*****.**'),) _call.return_value = {'payKey': '123', 'paymentExecStatus': ''} paypal.get_paykey(data) eq_(_call.call_args[0][1]['receiverList.receiver(0).amount'], '10') eq_(_call.call_args[0][1]['receiverList.receiver(1).amount'], '1.34')
def test_error_no_currency(self, opener): opener.return_value.text = other_error.replace('520001', '559044') try: data = self.data.copy() paypal.get_paykey(data) except paypal.PaypalError as error: eq_(error.id, '559044') else: raise ValueError('No PaypalError was raised')
def test_error_raised(self, opener): opener.return_value.text = other_error.replace('520001', '589023') try: paypal.get_paykey(self.data) except paypal.PaypalError as error: eq_(error.id, '589023') assert 'The amount is too small' in str(error) else: raise ValueError('No PaypalError was raised')
def test_preapproval_key_split(self, _call): _call.return_value = {'payKey': '123', 'paymentExecStatus': ''} data = self.get_pre_data() data['chains'] = ((13.4, '*****@*****.**'), ) paypal.get_paykey(data) called = _call.call_args[0][1] assert 'receiverList.receiver(0).paymentType' not in called assert 'receiverList.receiver(1).paymentType' not in called
def test_preapproval_key_split(self, _call): _call.return_value = {'payKey': '123', 'paymentExecStatus': ''} data = self.get_pre_data() data['chains'] = ((13.4, '*****@*****.**'),) paypal.get_paykey(data) called = _call.call_args[0][1] assert 'receiverList.receiver(0).paymentType' not in called assert 'receiverList.receiver(1).paymentType' not in called
def test_preapproval_key_split(self, _call): _call.return_value = {"payKey": "123", "paymentExecStatus": ""} data = self.get_pre_data() data["chains"] = ((13.4, "*****@*****.**"),) paypal.get_paykey(data) called = _call.call_args[0][1] assert "receiverList.receiver(0).paymentType" not in called assert "receiverList.receiver(1).paymentType" not in called
def test_error_raised(self, opener): opener.return_value = StringIO(other_error.replace("520001", "589023")) try: paypal.get_paykey(self.data) except paypal.PaypalError as error: eq_(error.id, "589023") assert "The amount is too small" in str(error) else: raise ValueError("No PaypalError was raised")
def test_error_no_currency(self, opener): opener.return_value = StringIO(other_error.replace("520001", "559044")) try: data = self.data.copy() paypal.get_paykey(data) except paypal.PaypalError as error: eq_(error.id, "559044") else: raise ValueError("No PaypalError was raised")
def test_error_one_currency(self, opener): opener.return_value = StringIO(other_error.replace("520001", "559044")) try: data = self.data.copy() data["currency"] = "BRL" paypal.get_paykey(data) except paypal.PaypalError as error: eq_(error.id, "559044") assert "Brazilian Real" in str(error) else: raise ValueError("No PaypalError was raised")
def test_error_one_currency(self, opener): opener.return_value.text = other_error.replace('520001', '559044') try: data = self.data.copy() data['currency'] = 'BRL' paypal.get_paykey(data) except paypal.PaypalError as error: eq_(error.id, '559044') assert 'Brazilian Real' in str(error) else: raise ValueError('No PaypalError was raised')
def test_error_one_currency(self, opener): opener.return_value.text = other_error.replace('520001', '559044') try: data = self.data.copy() data['currency'] = 'BRL' paypal.get_paykey(data) except paypal.PaypalError as error: eq_(error.id, '559044') assert 'Real' in str(error), str(error) else: raise ValueError('No PaypalError was raised')
def contribute(request, addon): contrib_type = request.GET.get('type', 'suggested') is_suggested = contrib_type == 'suggested' source = request.GET.get('source', '') comment = request.GET.get('comment', '') amount = { 'suggested': addon.suggested_amount, 'onetime': request.GET.get('onetime-amount', '')}.get(contrib_type, '') if not amount: amount = settings.DEFAULT_SUGGESTED_CONTRIBUTION contribution_uuid = hashlib.md5(str(uuid.uuid4())).hexdigest() if addon.charity: name, paypal_id = ('%s: %s' % (addon.name, addon.charity.name), addon.charity.paypal) else: name, paypal_id = addon.name, addon.paypal_id # l10n: {0} is the addon name contrib_for = _(u'Contribution for {0}').format(jinja2.escape(name)) paykey, error = '', '' try: 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'), pattern='addons.paypal')) except: 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, charity_id=addon.charity_id, amount=amount, source=source, source_locale=request.LANG, annoying=addon.annoying, uuid=str(contribution_uuid), is_suggested=is_suggested, suggested_amount=addon.suggested_amount, comment=comment, paykey=paykey) contrib.save() assert settings.PAYPAL_FLOW_URL, 'settings.PAYPAL_FLOW_URL is not defined' url = '%s?paykey=%s' % (settings.PAYPAL_FLOW_URL, paykey) if request.GET.get('result_type') == 'json' or request.is_ajax(): # If there was an error getting the paykey, then JSON will # not have a paykey and the JS can cope appropriately. return http.HttpResponse(json.dumps({'url': url, 'paykey': paykey, 'error': error}), content_type='application/json') return http.HttpResponseRedirect(url)
def purchase(request, addon): log.debug('Starting purchase of addon: %s by user: %s' % (addon.pk, request.amo_user.pk)) amount = addon.premium.get_price() source = request.GET.get('source', '') uuid_ = hashlib.md5(str(uuid.uuid4())).hexdigest() # l10n: {0} is the addon name contrib_for = _(u'Purchase of {0}').format(jinja2.escape(addon.name)) paykey, error = '', '' try: pattern = 'addons.purchase.finished' slug = addon.slug if addon.is_webapp(): pattern = 'apps.purchase.finished' slug = addon.app_slug paykey = paypal.get_paykey( dict(uuid=uuid_, slug=slug, amount=amount, memo=contrib_for, email=addon.paypal_id, ip=request.META.get('REMOTE_ADDR'), pattern=pattern, 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) error = _('There was an error communicating with PayPal.') if paykey: contrib = Contribution(addon_id=addon.id, amount=amount, source=source, source_locale=request.LANG, uuid=str(uuid_), type=amo.CONTRIB_PENDING, paykey=paykey, user=request.amo_user) log.debug('Storing contrib for uuid: %s' % uuid_) contrib.save() else: log.error('No paykey present for uuid: %s' % uuid_) log.debug('Got paykey for addon: %s by user: %s' % (addon.pk, request.amo_user.pk)) 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)
def test_preapproval_retry(self, _call): # Trigger an error on the preapproval and then pass. def error_if(*args, **kw): if 'preapprovalKey' in args[1]: raise paypal.PreApprovalError('some error') return {'payKey': '123', 'paymentExecStatus': ''} _call.side_effect = error_if res = paypal.get_paykey(self.get_pre_data()) eq_(_call.call_count, 2) eq_(res[0], '123')
def test_preapproval_retry(self, _call): # Trigger an error on the preapproval and then pass. def error_if(*args, **kw): if "preapprovalKey" in args[1]: raise paypal.PreApprovalError("some error") return {"payKey": "123", "paymentExecStatus": ""} _call.side_effect = error_if res = paypal.get_paykey(self.get_pre_data()) eq_(_call.call_count, 2) eq_(res[0], "123")
def test_preapproval_currency_retry(self, _call): # Trigger an error on the currency and then pass. def error_if(*args, **kw): if 'preapprovalKey' in args[1]: raise paypal.CurrencyError('some error') return {'payKey': '123', 'paymentExecStatus': ''} _call.side_effect = error_if data = self.get_pre_data() data['currency'] = 'BRL' res = paypal.get_paykey(data) eq_(_call.call_count, 2) eq_(res[0], '123')
def test_preapproval_currency_retry(self, _call): # Trigger an error on the currency and then pass. def error_if(*args, **kw): if "preapprovalKey" in args[1]: raise paypal.CurrencyError("some error") return {"payKey": "123", "paymentExecStatus": ""} _call.side_effect = error_if data = self.get_pre_data() data["currency"] = "BRL" res = paypal.get_paykey(data) eq_(_call.call_count, 2) eq_(res[0], "123")
def purchase(request, addon): log.debug('Starting purchase of addon: %s by user: %s' % (addon.pk, request.amo_user.pk)) amount = addon.premium.get_price() source = request.GET.get('source', '') uuid_ = hashlib.md5(str(uuid.uuid4())).hexdigest() # l10n: {0} is the addon name contrib_for = _(u'Purchase of {0}').format(jinja2.escape(addon.name)) paykey, error = '', '' try: pattern = 'addons.purchase.finished' slug = addon.slug if addon.is_webapp(): pattern = 'apps.purchase.finished' slug = addon.app_slug paykey = paypal.get_paykey(dict(uuid=uuid_, slug=slug, amount=amount, memo=contrib_for, email=addon.paypal_id, ip=request.META.get('REMOTE_ADDR'), pattern=pattern, 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) error = _('There was an error communicating with PayPal.') if paykey: contrib = Contribution(addon_id=addon.id, amount=amount, source=source, source_locale=request.LANG, uuid=str(uuid_), type=amo.CONTRIB_PENDING, paykey=paykey, user=request.amo_user) log.debug('Storing contrib for uuid: %s' % uuid_) contrib.save() else: log.error('No paykey present for uuid: %s' % uuid_) log.debug('Got paykey for addon: %s by user: %s' % (addon.pk, request.amo_user.pk)) 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)
def purchase(request, addon): log.debug("Starting purchase of addon: %s by user: %s" % (addon.pk, request.amo_user.pk)) amount = addon.premium.get_price() source = request.GET.get("source", "") uuid_ = hashlib.md5(str(uuid.uuid4())).hexdigest() # l10n: {0} is the addon name 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"), pattern="addons.purchase.finished", qs={"realurl": request.GET.get("realurl")}, ipn=False, ) ) except: log.error("Error getting paykey, purchase of addon: %s" % addon.pk, exc_info=True) error = _("There was an error communicating with PayPal.") if paykey: contrib = Contribution( addon_id=addon.id, amount=amount, source=source, source_locale=request.LANG, uuid=str(uuid_), type=amo.CONTRIB_PENDING, paykey=paykey, user=request.amo_user, ) contrib.save() log.debug("Got paykey for addon: %s by user: %s" % (addon.pk, request.amo_user.pk)) 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)
def test_paykey(self, data): """ Wraps get_paykey filling none optional data with test data. This should never ever be used for real purchases. The only things that you can set on this are: email: who the money is going to (required) amount: the amount of money (required) currency: valid paypal currency, defaults to USD (optional) """ data.update({ 'pattern': '', 'ip': '127.0.0.1', 'slug': 'foo', 'uuid': hashlib.md5(str(uuid.uuid4())).hexdigest() }) return paypal.get_paykey(data)
def embedded_contribute(request, addon): contrib_type = request.GET.get('type', 'suggested') is_suggested = contrib_type == 'suggested' source = request.GET.get('source', '') comment = request.GET.get('comment', '') amount = { 'suggested': addon.suggested_amount, 'onetime': request.GET.get('onetime-amount', '') }.get(contrib_type, '') if not amount: 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 else: name, paypal_id = addon.name, addon.paypal_id contrib_for = _(u'Contribution for {0}').format(jinja2.escape(name)) paykey, nice_error = None, None 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.')
def pay(request, signed_req, pay_req): amount = pay_req['request']['price'] currency = pay_req['request']['currency'] source = request.POST.get('source', '') product = pay_req['_config'].addon # L10n: {0} is the product name. {1} is the application name. contrib_for = ( _(u'Mozilla Marketplace in-app payment for {0} to {1}').format( pay_req['request']['name'], product.name)) uuid_ = hashlib.md5(str(uuid.uuid4())).hexdigest() paykey, status = '', '' preapproval = None if request.amo_user: preapproval = request.amo_user.get_preapproval() try: paykey, status = paypal.get_paykey( dict( amount=amount, chains=settings.PAYPAL_CHAINS, currency=currency, email=product.paypal_id, ip=request.META.get('REMOTE_ADDR'), memo=contrib_for, pattern='inapp_pay.pay_status', preapproval=preapproval, qs={'realurl': request.POST.get('realurl')}, slug=pay_req['_config']. pk, # passed to pay_done() via reverse() uuid=uuid_)) except paypal.PaypalError, exc: paypal.paypal_log_cef(request, product, uuid_, 'in-app PayKey Failure', 'PAYKEYFAIL', 'There was an error getting the paykey') log.error(u'Error getting paykey, in-app payment: %s' % pay_req['_config'].pk, exc_info=True) InappPayLog.log(request, 'PAY_ERROR', config=pay_req['_config']) return render_error(request, exc)
def pay(request, signed_req, pay_req): amount = pay_req["request"]["price"] currency = pay_req["request"]["currency"] source = request.POST.get("source", "") addon = pay_req["_config"].addon # L10n: {0} is the product name. {1} is the application name contrib_for = _(u"In-app payment for {0} to {1}").format( jinja2.escape(pay_req["request"]["name"]), jinja2.escape(addon.name) ) uuid_ = hashlib.md5(str(uuid.uuid4())).hexdigest() paykey, status = "", "" preapproval = None if waffle.flag_is_active(request, "allow-pre-auth") and request.amo_user: preapproval = request.amo_user.get_preapproval() try: paykey, status = paypal.get_paykey( dict( amount=amount, chains=settings.PAYPAL_CHAINS, currency=currency, email=addon.paypal_id, ip=request.META.get("REMOTE_ADDR"), memo=contrib_for, pattern="inapp_pay.pay_done", preapproval=preapproval, qs={"realurl": request.POST.get("realurl")}, slug=pay_req["_config"].pk, # passed to pay_done() via reverse() uuid=uuid_, ) ) except paypal.PaypalError, exc: paypal.paypal_log_cef( request, addon, uuid_, "in-app PayKey Failure", "PAYKEYFAIL", "There was an error getting the paykey" ) log.error(u"Error getting paykey, in-app payment: %s" % pay_req["_config"].pk, exc_info=True) InappPayLog.log(request, "PAY_ERROR", config=pay_req["_config"]) return render_error(request, exc)
def pay(request, signed_req, pay_req): paykey, status = '', '' preapproval = None if request.amo_user: preapproval = request.amo_user.get_preapproval() tier, price, currency = _get_price(pay_req, preapproval=preapproval) source = request.POST.get('source', '') product = pay_req['_config'].addon # L10n: {0} is the product name. {1} is the application name. contrib_for = (_(u'Mozilla Marketplace in-app payment for {0} to {1}') .format(pay_req['request']['name'], product.name)) uuid_ = hashlib.md5(str(uuid.uuid4())).hexdigest() try: paykey, status = paypal.get_paykey(dict( amount=price, chains=settings.PAYPAL_CHAINS, currency=currency, email=product.paypal_id, ip=request.META.get('REMOTE_ADDR'), memo=contrib_for, pattern='inapp_pay.pay_status', preapproval=preapproval, qs={'realurl': request.POST.get('realurl')}, slug=pay_req['_config'].pk, # passed to pay_done() via reverse() uuid=uuid_ )) except paypal.PaypalError, exc: paypal.paypal_log_cef(request, product, uuid_, 'in-app PayKey Failure', 'PAYKEYFAIL', 'There was an error getting the paykey') log.error(u'Error getting paykey, in-app payment: %s' % pay_req['_config'].pk, exc_info=True) InappPayLog.log(request, 'PAY_ERROR', config=pay_req['_config']) return render_error(request, exc)
def embedded_contribute(request, addon): contrib_type = request.GET.get('type', 'suggested') is_suggested = contrib_type == 'suggested' source = request.GET.get('source', '') comment = request.GET.get('comment', '') amount = { 'suggested': addon.suggested_amount, 'onetime': request.GET.get('onetime-amount', '')}.get(contrib_type, '') if not amount: 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 else: name, paypal_id = addon.name, addon.paypal_id contrib_for = _(u'Contribution for {0}').format(jinja2.escape(name)) paykey, nice_error = None, None 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.')
def test_ipn_skipped(self, _call): data = self.data.copy() data['ipn'] = False _call.return_value = {'payKey': '123'} paypal.get_paykey(data) assert 'ipnNotificationUrl' not in _call.call_args[0][1]
def test_ipn_asked(self, _call): data = self.data.copy() _call.return_value = {'payKey': '123'} paypal.get_paykey(data) assert 'ipnNotificationUrl' in _call.call_args[0][1]
def purchase(request, addon): log.debug('Starting purchase of addon: %s by user: %s' % (addon.pk, request.amo_user.pk)) amount = addon.premium.get_price() source = request.POST.get('source', '') uuid_ = hashlib.md5(str(uuid.uuid4())).hexdigest() # L10n: {0} is the addon name. contrib_for = (_(u'Mozilla Marketplace purchase of {0}').format( addon.name)) # Default is USD. amount, currency = addon.premium.get_price(), 'USD' # If tier is specified, then let's look it up. if waffle.switch_is_active('currencies'): form = PriceCurrencyForm(data=request.POST, addon=addon) if form.is_valid(): tier = form.get_tier() if tier: amount, currency = tier.price, tier.currency if not amount: # We won't write a contribution row for this because there # will not be a valid Paypal transaction. But we have to write the # Purchase row, something that writing to the contribution normally # does for us. AddonPurchase.objects.safer_get_or_create(addon=addon, user=request.amo_user) return http.HttpResponse(json.dumps({ 'url': '', 'paykey': '', 'error': '', 'status': 'COMPLETED' }), content_type='application/json') paykey, status, error = '', '', '' preapproval = None if request.amo_user: preapproval = request.amo_user.get_preapproval() # User the users default currency. if currency == 'USD' and preapproval and preapproval.currency: currency = preapproval.currency try: paykey, status = paypal.get_paykey( dict(amount=amount, chains=settings.PAYPAL_CHAINS, currency=currency, email=addon.paypal_id, ip=request.META.get('REMOTE_ADDR'), memo=contrib_for, pattern='purchase.done', preapproval=preapproval, qs={'realurl': request.POST.get('realurl')}, slug=addon.app_slug, uuid=uuid_)) except paypal.PaypalError as error: paypal.paypal_log_cef(request, addon, uuid_, 'PayKey Failure', 'PAYKEYFAIL', 'There was an error getting the paykey') log.error('Error getting paykey, purchase of addon: %s' % addon.pk, exc_info=True) if paykey: contrib = Contribution(addon_id=addon.id, amount=amount, source=source, source_locale=request.LANG, uuid=str(uuid_), type=amo.CONTRIB_PENDING, paykey=paykey, user=request.amo_user) log.debug('Storing contrib for uuid: %s' % uuid_) # If this was a pre-approval, it's completed already, we'll # double check this with PayPal, just to be sure nothing went wrong. if status == 'COMPLETED': paypal.paypal_log_cef(request, addon, uuid_, 'Purchase', 'PURCHASE', 'A user purchased using pre-approval') log.debug('Status is completed for uuid: %s' % uuid_) if paypal.check_purchase(paykey) == 'COMPLETED': log.debug('Check purchase is completed for uuid: %s' % uuid_) contrib.type = amo.CONTRIB_PURCHASE else: # In this case PayPal disagreed, we should not be trusting # what get_paykey said. Which is a worry. log.error('Check purchase failed on uuid: %s' % uuid_) status = 'NOT-COMPLETED' contrib.save() else: log.error('No paykey present for uuid: %s' % uuid_) log.debug('Got paykey for addon: %s by user: %s' % (addon.pk, request.amo_user.pk)) url = '%s?paykey=%s' % (settings.PAYPAL_FLOW_URL, paykey) if request.POST.get('result_type') == 'json' or request.is_ajax(): return http.HttpResponse(json.dumps({ 'url': url, 'paykey': paykey, 'error': str(error), 'status': status }), content_type='application/json') # This is the non-Ajax fallback. if status != 'COMPLETED': return redirect(url) messages.success(request, _('Purchase complete')) return redirect(addon.get_detail_url())
def test_get_key(self, opener): opener.return_value = StringIO(good_response) eq_(paypal.get_paykey(self.data), 'AP-9GD76073HJ780401K')
def contribute(request, addon): webapp = addon.is_webapp() contrib_type = request.POST.get('type', 'suggested') is_suggested = contrib_type == 'suggested' source = request.POST.get('source', '') comment = request.POST.get('comment', '') amount = { 'suggested': addon.suggested_amount, 'onetime': request.POST.get('onetime-amount', '') }.get(contrib_type, '') if not amount: amount = settings.DEFAULT_SUGGESTED_CONTRIBUTION # This is all going to get shoved into solitude. Temporary. form = ContributionForm({'amount': amount}) if not form.is_valid(): return http.HttpResponse(json.dumps({'error': 'Invalid data.', 'status': '', 'url': '', 'paykey': ''}), content_type='application/json') contribution_uuid = hashlib.md5(str(uuid.uuid4())).hexdigest() if addon.charity: # TODO(andym): Figure out how to get this in the addon authors # locale, rather than the contributors locale. name, paypal_id = (u'%s: %s' % (addon.name, addon.charity.name), addon.charity.paypal) else: name, paypal_id = addon.name, addon.paypal_id # l10n: {0} is the addon name contrib_for = _(u'Contribution for {0}').format(jinja2.escape(name)) preapproval = None if waffle.flag_is_active(request, 'allow-pre-auth') and request.amo_user: preapproval = request.amo_user.get_preapproval() paykey, error, status = '', '', '' try: paykey, status = paypal.get_paykey( dict(amount=amount, email=paypal_id, ip=request.META.get('REMOTE_ADDR'), memo=contrib_for, pattern='%s.paypal' % ('apps' if webapp else 'addons'), preapproval=preapproval, slug=addon.slug, uuid=contribution_uuid)) except paypal.PaypalError as error: paypal.paypal_log_cef(request, addon, contribution_uuid, 'PayKey Failure', 'PAYKEYFAIL', 'There was an error getting the paykey') log.error('Error getting paykey, contribution for addon: %s' % addon.pk, exc_info=True) if paykey: contrib = Contribution(addon_id=addon.id, charity_id=addon.charity_id, amount=amount, source=source, source_locale=request.LANG, annoying=addon.annoying, uuid=str(contribution_uuid), is_suggested=is_suggested, suggested_amount=addon.suggested_amount, comment=comment, paykey=paykey) contrib.save() url = '%s?paykey=%s' % (settings.PAYPAL_FLOW_URL, paykey) if request.GET.get('result_type') == 'json' or request.is_ajax(): # If there was an error getting the paykey, then JSON will # not have a paykey and the JS can cope appropriately. return http.HttpResponse(json.dumps({'url': url, 'paykey': paykey, 'error': str(error), 'status': status}), content_type='application/json') return http.HttpResponseRedirect(url)
def purchase(request, addon): amount, currency, uuid_, contrib_for = start_purchase(request, addon) if not amount: # We won't write a contribution row for this because there # will not be a valid Paypal transaction. But we have to write the # Purchase row, something that writing to the contribution normally # does for us. AddonPurchase.objects.safer_get_or_create(addon=addon, user=request.amo_user) return http.HttpResponse(json.dumps({'url': '', 'paykey': '', 'error': '', 'status': 'COMPLETED'}), content_type='application/json') paykey, status, error = '', '', '' # TODO(solitude): remove this, pre-approval and currency will be # stored in solitude. preapproval = None if (not waffle.flag_is_active(request, 'solitude-payments') and request.amo_user): preapproval = request.amo_user.get_preapproval() # User the users default currency. if currency == 'USD' and preapproval and preapproval.currency: currency = preapproval.currency if waffle.flag_is_active(request, 'solitude-payments'): # Now call the client. result = {} try: result = client.pay({'amount': amount, 'currency': currency, 'buyer': request.amo_user, 'seller': addon, 'memo': contrib_for}) except client.Error as error: # Note that by assigning this to error, it will go into the return # value for the json. General solitude errors will then be # reported back to the user. paypal.paypal_log_cef(request, addon, uuid_, 'PayKey Failure', 'PAYKEYFAIL', 'There was an error getting the paykey') log.error('Error getting paykey: %s' % addon.pk, exc_info=True) # TODO(solitude): just use the dictionary when solitude is live. paykey = result.get('pay_key', '') status = result.get('status', '') uuid_ = result.get('uuid', '') else: # TODO(solitude): remove this when solitude goes live. try: paykey, status = paypal.get_paykey(dict( amount=amount, chains=settings.PAYPAL_CHAINS, currency=currency, email=addon.paypal_id, ip=request.META.get('REMOTE_ADDR'), memo=contrib_for, pattern='purchase.done', preapproval=preapproval, qs={'realurl': request.POST.get('realurl')}, slug=addon.app_slug, uuid=uuid_ )) except paypal.PaypalError as error: paypal.paypal_log_cef(request, addon, uuid_, 'PayKey Failure', 'PAYKEYFAIL', 'There was an error getting the paykey') log.error('Error getting paykey, purchase of addon: %s' % addon.pk, exc_info=True) if paykey: # TODO(solitude): at some point we'll have to see what to do with # contributions. download_source = request.REQUEST.get('src', '') contrib = Contribution(addon_id=addon.id, amount=amount, source=download_source, source_locale=request.LANG, uuid=str(uuid_), type=amo.CONTRIB_PENDING, paykey=paykey, user=request.amo_user, price_tier=addon.premium.price, client_data=ClientData.get_or_create(request)) log.debug('Storing contrib for uuid: %s' % uuid_) # If this was a pre-approval, it's completed already, we'll # double check this with PayPal, just to be sure nothing went wrong. if status == 'COMPLETED': paypal.paypal_log_cef(request, addon, uuid_, 'Purchase', 'PURCHASE', 'A user purchased using pre-approval') log.debug('Status completed for uuid: %s' % uuid_) if waffle.flag_is_active(request, 'solitude-payments'): result = client.post_pay_check(data={'pay_key': paykey}) if result['status'] == 'COMPLETED': contrib.type = amo.CONTRIB_PURCHASE else: log.error('Check purchase failed on uuid: %s' % uuid_) status = 'NOT-COMPLETED' else: #TODO(solitude): remove this when solitude goes live. if paypal.check_purchase(paykey) == 'COMPLETED': log.debug('Check purchase completed for uuid: %s' % uuid_) contrib.type = amo.CONTRIB_PURCHASE else: # In this case PayPal disagreed, we should not be trusting # what get_paykey said. Which is a worry. log.error('Check purchase failed on uuid: %s' % uuid_) status = 'NOT-COMPLETED' contrib.save() else: log.error('No paykey present for uuid: %s' % uuid_) log.debug('Got paykey for addon: %s by user: %s' % (addon.pk, request.amo_user.pk)) url = '%s?paykey=%s' % (settings.PAYPAL_FLOW_URL, paykey) if request.POST.get('result_type') == 'json' or request.is_ajax(): return http.HttpResponse(json.dumps({'url': url, 'paykey': paykey, 'error': str(error), 'status': status}), content_type='application/json') # This is the non-Ajax fallback. if status != 'COMPLETED': return http.HttpResponseRedirect(url) messages.success(request, _('Purchase complete')) return http.HttpResponseRedirect(addon.get_detail_url())
def test_not_preapproval_key(self, _call): _call.return_value = {'payKey': '123', 'paymentExecStatus': ''} paypal.get_paykey(self.data) assert 'preapprovalKey' not in _call.call_args[0][1]
def _test_no_mock(self): # Remove _ and run if you'd like to try unmocked. data = self.data.copy() data['email'] = '*****@*****.**' return paypal.get_paykey(data)
def test_usd_default(self, _call): _call.return_value = {'payKey': '', 'paymentExecStatus': ''} paypal.get_paykey(self.data) eq_(_call.call_args[0][1]['currencyCode'], 'USD')
def contribute(request, addon): webapp = addon.is_webapp() contrib_type = request.GET.get('type', 'suggested') is_suggested = contrib_type == 'suggested' source = request.GET.get('source', '') comment = request.GET.get('comment', '') amount = { 'suggested': addon.suggested_amount, 'onetime': request.GET.get('onetime-amount', '') }.get(contrib_type, '') if not amount: amount = settings.DEFAULT_SUGGESTED_CONTRIBUTION contribution_uuid = hashlib.md5(str(uuid.uuid4())).hexdigest() if addon.charity: # TODO(andym): Figure out how to get this in the addon authors # locale, rather than the contributors locale. name, paypal_id = (u'%s: %s' % (addon.name, addon.charity.name), addon.charity.paypal) else: name, paypal_id = addon.name, addon.paypal_id # l10n: {0} is the addon name contrib_for = _(u'Contribution for {0}').format(jinja2.escape(name)) preapproval = None if waffle.flag_is_active(request, 'allow-pre-auth') and request.amo_user: preapproval = request.amo_user.get_preapproval() paykey, error, status = '', '', '' try: paykey, status = paypal.get_paykey( dict(amount=amount, email=paypal_id, ip=request.META.get('REMOTE_ADDR'), memo=contrib_for, pattern='%s.paypal' % ('apps' if webapp else 'addons'), preapproval=preapproval, slug=addon.slug, uuid=contribution_uuid)) except: paypal.paypal_log_cef(request, addon, contribution_uuid, 'PayKey Failure', 'PAYKEYFAIL', 'There was an error getting the paykey') 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, charity_id=addon.charity_id, amount=amount, source=source, source_locale=request.LANG, annoying=addon.annoying, uuid=str(contribution_uuid), is_suggested=is_suggested, suggested_amount=addon.suggested_amount, comment=comment, paykey=paykey) contrib.save() url = '%s?paykey=%s' % (settings.PAYPAL_FLOW_URL, paykey) if request.GET.get('result_type') == 'json' or request.is_ajax(): # If there was an error getting the paykey, then JSON will # not have a paykey and the JS can cope appropriately. return http.HttpResponse(json.dumps({ 'url': url, 'paykey': paykey, 'error': error, 'status': status }), content_type='application/json') return http.HttpResponseRedirect(url)
def test_other_currency(self, _call): _call.return_value = {'payKey': '', 'paymentExecStatus': ''} data = self.data.copy() data['currency'] = 'EUR' paypal.get_paykey(data) eq_(_call.call_args[0][1]['currencyCode'], 'EUR')
def test_get_key(self, opener): opener.return_value.text = good_response eq_(paypal.get_paykey(self.data), ('AP-9GD76073HJ780401K', 'CREATED'))
def purchase(request, addon): amount, currency, uuid_, contrib_for = start_purchase(request, addon) if not amount: # We won't write a contribution row for this because there # will not be a valid Paypal transaction. But we have to write the # Purchase row, something that writing to the contribution normally # does for us. AddonPurchase.objects.safer_get_or_create(addon=addon, user=request.amo_user) return http.HttpResponse(json.dumps({ 'url': '', 'paykey': '', 'error': '', 'status': 'COMPLETED' }), content_type='application/json') paykey, status, error = '', '', '' # TODO(solitude): remove this, pre-approval and currency will be # stored in solitude. preapproval = None if (not waffle.flag_is_active(request, 'solitude-payments') and request.amo_user): preapproval = request.amo_user.get_preapproval() # User the users default currency. if currency == 'USD' and preapproval and preapproval.currency: currency = preapproval.currency if waffle.flag_is_active(request, 'solitude-payments'): # Now call the client. result = {} try: result = client.pay({ 'amount': amount, 'currency': currency, 'buyer': request.amo_user, 'seller': addon, 'memo': contrib_for }) except client.Error as error: # Note that by assigning this to error, it will go into the return # value for the json. General solitude errors will then be # reported back to the user. paypal.paypal_log_cef(request, addon, uuid_, 'PayKey Failure', 'PAYKEYFAIL', 'There was an error getting the paykey') log.error('Error getting paykey: %s' % addon.pk, exc_info=True) # TODO(solitude): just use the dictionary when solitude is live. paykey = result.get('pay_key', '') status = result.get('status', '') uuid_ = result.get('uuid', '') else: # TODO(solitude): remove this when solitude goes live. try: paykey, status = paypal.get_paykey( dict(amount=amount, chains=settings.PAYPAL_CHAINS, currency=currency, email=addon.paypal_id, ip=request.META.get('REMOTE_ADDR'), memo=contrib_for, pattern='purchase.done', preapproval=preapproval, qs={'realurl': request.POST.get('realurl')}, slug=addon.app_slug, uuid=uuid_)) except paypal.PaypalError as error: paypal.paypal_log_cef(request, addon, uuid_, 'PayKey Failure', 'PAYKEYFAIL', 'There was an error getting the paykey') log.error('Error getting paykey, purchase of addon: %s' % addon.pk, exc_info=True) if paykey: # TODO(solitude): at some point we'll have to see what to do with # contributions. download_source = request.REQUEST.get('src', '') contrib = Contribution(addon_id=addon.id, amount=amount, source=download_source, source_locale=request.LANG, uuid=str(uuid_), type=amo.CONTRIB_PENDING, paykey=paykey, user=request.amo_user, price_tier=addon.premium.price, client_data=ClientData.get_or_create(request)) log.debug('Storing contrib for uuid: %s' % uuid_) # If this was a pre-approval, it's completed already, we'll # double check this with PayPal, just to be sure nothing went wrong. if status == 'COMPLETED': paypal.paypal_log_cef(request, addon, uuid_, 'Purchase', 'PURCHASE', 'A user purchased using pre-approval') log.debug('Status completed for uuid: %s' % uuid_) if waffle.flag_is_active(request, 'solitude-payments'): result = client.post_pay_check(data={'pay_key': paykey}) if result['status'] == 'COMPLETED': contrib.type = amo.CONTRIB_PURCHASE else: log.error('Check purchase failed on uuid: %s' % uuid_) status = 'NOT-COMPLETED' else: #TODO(solitude): remove this when solitude goes live. if paypal.check_purchase(paykey) == 'COMPLETED': log.debug('Check purchase completed for uuid: %s' % uuid_) contrib.type = amo.CONTRIB_PURCHASE else: # In this case PayPal disagreed, we should not be trusting # what get_paykey said. Which is a worry. log.error('Check purchase failed on uuid: %s' % uuid_) status = 'NOT-COMPLETED' contrib.save() else: log.error('No paykey present for uuid: %s' % uuid_) log.debug('Got paykey for addon: %s by user: %s' % (addon.pk, request.amo_user.pk)) url = '%s?paykey=%s' % (settings.PAYPAL_FLOW_URL, paykey) if request.POST.get('result_type') == 'json' or request.is_ajax(): return http.HttpResponse(json.dumps({ 'url': url, 'paykey': paykey, 'error': str(error), 'status': status }), content_type='application/json') # This is the non-Ajax fallback. if status != 'COMPLETED': return http.HttpResponseRedirect(url) messages.success(request, _('Purchase complete')) return http.HttpResponseRedirect(addon.get_detail_url())
def _test_no_mock(self): # Remove _ and run if you'd like to try unmocked. return paypal.get_paykey(self.data)
def test_get_key(self, opener): opener.return_value = StringIO(good_response) eq_(paypal.get_paykey(self.data), ("AP-9GD76073HJ780401K", "CREATED"))
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_dict_no_split(self, _call): data = self.data.copy() _call.return_value = {'payKey': '123', 'paymentExecStatus': ''} paypal.get_paykey(data) eq_(_call.call_args[0][1]['receiverList.receiver(0).amount'], '10')
def contribute(request, addon): commentlimit = 255 # Enforce paypal-imposed comment length limit contrib_type = request.POST.get('type', 'suggested') is_suggested = contrib_type == 'suggested' source = request.POST.get('source', '') comment = request.POST.get('comment', '') amount = { 'suggested': addon.suggested_amount, 'onetime': request.POST.get('onetime-amount', '') }.get(contrib_type, '') if not amount: amount = settings.DEFAULT_SUGGESTED_CONTRIBUTION form = ContributionForm({'amount': amount}) if len(comment) > commentlimit or not form.is_valid(): return http.HttpResponse(json.dumps({'error': 'Invalid data.', 'status': '', 'url': '', 'paykey': ''}), content_type='application/json') contribution_uuid = hashlib.md5(str(uuid.uuid4())).hexdigest() if addon.charity: # TODO(andym): Figure out how to get this in the addon authors # locale, rather than the contributors locale. name, paypal_id = (u'%s: %s' % (addon.name, addon.charity.name), addon.charity.paypal) else: name, paypal_id = addon.name, addon.paypal_id # l10n: {0} is the addon name contrib_for = _(u'Contribution for {0}').format(jinja2.escape(name)) paykey, error, status = '', '', '' try: paykey, status = paypal.get_paykey( dict(amount=amount, email=paypal_id, ip=request.META.get('REMOTE_ADDR'), memo=contrib_for, pattern='addons.paypal', slug=addon.slug, uuid=contribution_uuid)) except paypal.PaypalError as error: paypal.paypal_log_cef(request, addon, contribution_uuid, 'PayKey Failure', 'PAYKEYFAIL', 'There was an error getting the paykey') log.error('Error getting paykey, contribution for addon: %s' % addon.pk, exc_info=True) if paykey: contrib = Contribution(addon_id=addon.id, charity_id=addon.charity_id, amount=amount, source=source, source_locale=request.LANG, annoying=addon.annoying, uuid=str(contribution_uuid), is_suggested=is_suggested, suggested_amount=addon.suggested_amount, comment=comment, paykey=paykey) contrib.save() url = '%s?paykey=%s' % (settings.PAYPAL_FLOW_URL, paykey) if request.GET.get('result_type') == 'json' or request.is_ajax(): # If there was an error getting the paykey, then JSON will # not have a paykey and the JS can cope appropriately. return http.HttpResponse(json.dumps({'url': url, 'paykey': paykey, 'error': str(error), 'status': status}), content_type='application/json') return http.HttpResponseRedirect(url)
def _test_no_mock(self): # Remove _ and run if you'd like to try unmocked. data = self.data.copy() data['email'] = '*****@*****.**' #data['chains'] = ((13.4, '*****@*****.**'),) return paypal.get_paykey(data)
def purchase(request, addon): log.debug('Starting purchase of addon: %s by user: %s' % (addon.pk, request.amo_user.pk)) amount = addon.premium.get_price() source = request.POST.get('source', '') uuid_ = hashlib.md5(str(uuid.uuid4())).hexdigest() # L10n: {0} is the addon name. contrib_for = (_(u'Mozilla Marketplace purchase of {0}') .format(addon.name)) # Default is USD. amount, currency = addon.premium.get_price(), 'USD' # If tier is specified, then let's look it up. if waffle.switch_is_active('currencies'): form = PriceCurrencyForm(data=request.POST, addon=addon) if form.is_valid(): tier = form.get_tier() if tier: amount, currency = tier.price, tier.currency if not amount: # We won't write a contribution row for this because there # will not be a valid Paypal transaction. But we have to write the # Purchase row, something that writing to the contribution normally # does for us. AddonPurchase.objects.safer_get_or_create(addon=addon, user=request.amo_user) return http.HttpResponse(json.dumps({'url': '', 'paykey': '', 'error': '', 'status': 'COMPLETED'}), content_type='application/json') paykey, status, error = '', '', '' preapproval = None if request.amo_user: preapproval = request.amo_user.get_preapproval() # User the users default currency. if currency == 'USD' and preapproval and preapproval.currency: currency = preapproval.currency try: paykey, status = paypal.get_paykey(dict( amount=amount, chains=settings.PAYPAL_CHAINS, currency=currency, email=addon.paypal_id, ip=request.META.get('REMOTE_ADDR'), memo=contrib_for, pattern='purchase.done', preapproval=preapproval, qs={'realurl': request.POST.get('realurl')}, slug=addon.app_slug, uuid=uuid_ )) except paypal.PaypalError as error: paypal.paypal_log_cef(request, addon, uuid_, 'PayKey Failure', 'PAYKEYFAIL', 'There was an error getting the paykey') log.error('Error getting paykey, purchase of addon: %s' % addon.pk, exc_info=True) if paykey: contrib = Contribution(addon_id=addon.id, amount=amount, source=source, source_locale=request.LANG, uuid=str(uuid_), type=amo.CONTRIB_PENDING, paykey=paykey, user=request.amo_user) log.debug('Storing contrib for uuid: %s' % uuid_) # If this was a pre-approval, it's completed already, we'll # double check this with PayPal, just to be sure nothing went wrong. if status == 'COMPLETED': paypal.paypal_log_cef(request, addon, uuid_, 'Purchase', 'PURCHASE', 'A user purchased using pre-approval') log.debug('Status is completed for uuid: %s' % uuid_) if paypal.check_purchase(paykey) == 'COMPLETED': log.debug('Check purchase is completed for uuid: %s' % uuid_) contrib.type = amo.CONTRIB_PURCHASE else: # In this case PayPal disagreed, we should not be trusting # what get_paykey said. Which is a worry. log.error('Check purchase failed on uuid: %s' % uuid_) status = 'NOT-COMPLETED' contrib.save() else: log.error('No paykey present for uuid: %s' % uuid_) log.debug('Got paykey for addon: %s by user: %s' % (addon.pk, request.amo_user.pk)) url = '%s?paykey=%s' % (settings.PAYPAL_FLOW_URL, paykey) if request.POST.get('result_type') == 'json' or request.is_ajax(): return http.HttpResponse(json.dumps({'url': url, 'paykey': paykey, 'error': str(error), 'status': status}), content_type='application/json') # This is the non-Ajax fallback. if status != 'COMPLETED': return redirect(url) messages.success(request, _('Purchase complete')) return redirect(addon.get_detail_url())
def purchase(request, addon): log.debug('Starting purchase of addon: %s by user: %s' % (addon.pk, request.amo_user.pk)) amount = addon.premium.get_price() source = request.POST.get('source', '') uuid_ = hashlib.md5(str(uuid.uuid4())).hexdigest() # l10n: {0} is the addon name contrib_for = _(u'Purchase of {0}').format(jinja2.escape(addon.name)) # Default is USD. amount, currency = addon.premium.get_price(), 'USD' # If tier is specified, then let's look it up. form = PriceCurrencyForm(data=request.POST, addon=addon) if form.is_valid(): tier = form.get_tier() if tier: amount, currency = tier.price, tier.currency paykey, status, error = '', '', '' preapproval = None if waffle.flag_is_active(request, 'allow-pre-auth') and request.amo_user: preapproval = request.amo_user.get_preapproval() try: pattern = 'addons.purchase.finished' slug = addon.slug if addon.is_webapp(): pattern = 'apps.purchase.finished' slug = addon.app_slug paykey, status = paypal.get_paykey( dict(amount=amount, chains=settings.PAYPAL_CHAINS, currency=currency, email=addon.paypal_id, ip=request.META.get('REMOTE_ADDR'), memo=contrib_for, pattern=pattern, preapproval=preapproval, qs={'realurl': request.POST.get('realurl')}, slug=slug, uuid=uuid_)) except paypal.PaypalError as error: paypal.paypal_log_cef(request, addon, uuid_, 'PayKey Failure', 'PAYKEYFAIL', 'There was an error getting the paykey') log.error('Error getting paykey, purchase of addon: %s' % addon.pk, exc_info=True) if paykey: contrib = Contribution(addon_id=addon.id, amount=amount, source=source, source_locale=request.LANG, uuid=str(uuid_), type=amo.CONTRIB_PENDING, paykey=paykey, user=request.amo_user) log.debug('Storing contrib for uuid: %s' % uuid_) # If this was a pre-approval, it's completed already, we'll # double check this with PayPal, just to be sure nothing went wrong. if status == 'COMPLETED': paypal.paypal_log_cef(request, addon, uuid_, 'Purchase', 'PURCHASE', 'A user purchased using pre-approval') log.debug('Status is completed for uuid: %s' % uuid_) if paypal.check_purchase(paykey) == 'COMPLETED': log.debug('Check purchase is completed for uuid: %s' % uuid_) contrib.type = amo.CONTRIB_PURCHASE else: # In this case PayPal disagreed, we should not be trusting # what get_paykey said. Which is a worry. log.error('Check purchase failed on uuid: %s' % uuid_) status = 'NOT-COMPLETED' contrib.save() else: log.error('No paykey present for uuid: %s' % uuid_) log.debug('Got paykey for addon: %s by user: %s' % (addon.pk, request.amo_user.pk)) url = '%s?paykey=%s' % (settings.PAYPAL_FLOW_URL, paykey) if request.POST.get('result_type') == 'json' or request.is_ajax(): return http.HttpResponse(json.dumps({'url': url, 'paykey': paykey, 'error': str(error), 'status': status}), content_type='application/json') # This is the non-Ajax fallback. if status != 'COMPLETED': return http.HttpResponseRedirect(url) messages.success(request, _('Purchase complete')) return http.HttpResponseRedirect(shared_url('addons.detail', addon))
def pay(request, signed_req, pay_req): paykey, status = '', '' preapproval = None if request.amo_user: preapproval = request.amo_user.get_preapproval() tier, price, currency = _get_price(pay_req, preapproval=preapproval) source = request.POST.get('source', '') product = pay_req['_config'].addon # L10n: {0} is the product name. {1} is the application name. contrib_for = ( _(u'Firefox Marketplace in-app payment for {0} to {1}').format( pay_req['request']['name'], product.name)) # TODO(solitude): solitude lib will create these for us. uuid_ = hashlib.md5(str(uuid.uuid4())).hexdigest() if waffle.flag_is_active(request, 'solitude-payments'): # TODO(solitude): when the migration of data is completed, we # will be able to remove this. Seller data is populated in solitude # on submission or devhub changes. If those don't occur, you won't be # able to sell at all. client.create_seller_for_pay(product) complete = reverse('inapp_pay.pay_status', args=[pay_req['_config'].pk, 'complete']) cancel = reverse('inapp_pay.pay_status', args=[pay_req['_config'].pk, 'cancel']) # TODO(bug 748137): remove retry is False. try: result = client.pay( { 'amount': price, 'currency': currency, 'buyer': request.amo_user, 'seller': product, 'memo': contrib_for, 'complete': complete, 'cancel': cancel }, retry=False) except client.Error as exc: paypal.paypal_log_cef(request, product, uuid_, 'in-app PayKey Failure', 'PAYKEYFAIL', 'There was an error getting the paykey') log.error(u'Error getting paykey, in-app payment: %s' % pay_req['_config'].pk, exc_info=True) InappPayLog.log(request, 'PAY_ERROR', config=pay_req['_config']) return render_error(request, exc) #TODO(solitude): just use the dictionary when solitude is live. paykey = result.get('pay_key', '') status = result.get('status', '') uuid_ = result.get('uuid', '') else: try: paykey, status = paypal.get_paykey( dict( amount=price, chains=settings.PAYPAL_CHAINS, currency=currency, email=product.paypal_id, ip=request.META.get('REMOTE_ADDR'), memo=contrib_for, pattern='inapp_pay.pay_status', preapproval=preapproval, qs={'realurl': request.POST.get('realurl')}, slug=pay_req['_config'].pk, # passed to pay_done() # via reverse() uuid=uuid_)) except paypal.PaypalError, exc: paypal.paypal_log_cef(request, product, uuid_, 'in-app PayKey Failure', 'PAYKEYFAIL', 'There was an error getting the paykey') log.error(u'Error getting paykey, in-app payment: %s' % pay_req['_config'].pk, exc_info=True) InappPayLog.log(request, 'PAY_ERROR', config=pay_req['_config']) return render_error(request, exc)
def purchase(request, addon): log.debug('Starting purchase of addon: %s by user: %s' % (addon.pk, request.amo_user.pk)) amount = addon.premium.get_price() source = request.POST.get('source', '') uuid_ = hashlib.md5(str(uuid.uuid4())).hexdigest() # l10n: {0} is the addon name contrib_for = _(u'Purchase of {0}').format(jinja2.escape(addon.name)) # Default is USD. amount, currency = addon.premium.get_price(), 'USD' # If tier is specified, then let's look it up. form = PriceCurrencyForm(data=request.POST, addon=addon) if form.is_valid(): tier = form.get_tier() if tier: amount, currency = tier.price, tier.currency paykey, status, error = '', '', '' preapproval = None if waffle.flag_is_active(request, 'allow-pre-auth') and request.amo_user: preapproval = request.amo_user.get_preapproval() try: pattern = 'addons.purchase.finished' slug = addon.slug if addon.is_webapp(): pattern = 'apps.purchase.finished' slug = addon.app_slug paykey, status = paypal.get_paykey(dict( amount=amount, chains=settings.PAYPAL_CHAINS, currency=currency, email=addon.paypal_id, ip=request.META.get('REMOTE_ADDR'), memo=contrib_for, pattern=pattern, preapproval=preapproval, qs={'realurl': request.POST.get('realurl')}, slug=slug, uuid=uuid_)) except paypal.PaypalError as error: paypal.paypal_log_cef(request, addon, uuid_, 'PayKey Failure', 'PAYKEYFAIL', 'There was an error getting the paykey') log.error('Error getting paykey, purchase of addon: %s' % addon.pk, exc_info=True) if paykey: contrib = Contribution(addon_id=addon.id, amount=amount, source=source, source_locale=request.LANG, uuid=str(uuid_), type=amo.CONTRIB_PENDING, paykey=paykey, user=request.amo_user) log.debug('Storing contrib for uuid: %s' % uuid_) # If this was a pre-approval, it's completed already, we'll # double check this with PayPal, just to be sure nothing went wrong. if status == 'COMPLETED': paypal.paypal_log_cef(request, addon, uuid_, 'Purchase', 'PURCHASE', 'A user purchased using pre-approval') log.debug('Status is completed for uuid: %s' % uuid_) if paypal.check_purchase(paykey) == 'COMPLETED': log.debug('Check purchase is completed for uuid: %s' % uuid_) contrib.type = amo.CONTRIB_PURCHASE else: # In this case PayPal disagreed, we should not be trusting # what get_paykey said. Which is a worry. log.error('Check purchase failed on uuid: %s' % uuid_) status = 'NOT-COMPLETED' contrib.save() else: log.error('No paykey present for uuid: %s' % uuid_) log.debug('Got paykey for addon: %s by user: %s' % (addon.pk, request.amo_user.pk)) url = '%s?paykey=%s' % (settings.PAYPAL_FLOW_URL, paykey) if request.POST.get('result_type') == 'json' or request.is_ajax(): return http.HttpResponse(json.dumps({'url': url, 'paykey': paykey, 'error': str(error), 'status': status}), content_type='application/json') # This is the non-Ajax fallback. if status != 'COMPLETED': return http.HttpResponseRedirect(url) messages.success(request, _('Purchase complete')) return http.HttpResponseRedirect(shared_url('addons.detail', addon))