diff --git a/addons/payment_stripe/controllers/main.py b/addons/payment_stripe/controllers/main.py index edfb59dda9f..08ca184455d 100644 --- a/addons/payment_stripe/controllers/main.py +++ b/addons/payment_stripe/controllers/main.py @@ -21,8 +21,18 @@ class StripeController(http.Controller): def stripe_s2s_create(self, **post): acquirer_id = int(post.get('acquirer_id')) acquirer = request.env['payment.acquirer'].browse(acquirer_id) - acquirer.s2s_process(post) - return werkzeug.utils.redirect(post.get('return_url', '/')) + error = None + try: + acquirer.s2s_process(post) + except Exception as e: + error = e.message + + return_url = post.get('return_url', '/') + if error: + separator = '?' if werkzeug.urls.url_parse(return_url).query == '' else '&' + return_url += '{}{}'.format(separator, werkzeug.urls.url_encode({'error': error})) + + return werkzeug.utils.redirect(return_url) @http.route(['/payment/stripe/create_charge'], type='json', auth='public') def stripe_create_charge(self, **post): @@ -39,7 +49,19 @@ class StripeController(http.Controller): tx = TX.sudo().browse(int(tx_id)) if not tx: raise werkzeug.exceptions.NotFound() - response = tx._create_stripe_charge(tokenid=post['tokenid'], email=post['email']) + + stripe_token = post['token'] + response = None + if tx.type == 'form_save' and tx.partner_id: + payment_token_id = request.env['payment.token'].sudo().create({ + 'acquirer_id': tx.acquirer_id.id, + 'partner_id': tx.partner_id.id, + 'stripe_token': stripe_token + }) + tx.payment_token_id = payment_token_id + response = tx._create_stripe_charge(acquirer_ref=payment_token_id.acquirer_ref, email=stripe_token['email']) + else: + response = tx._create_stripe_charge(tokenid=stripe_token['id'], email=stripe_token['email']) _logger.info('Stripe: entering form_feedback with post data %s', pprint.pformat(response)) if response: request.env['payment.transaction'].sudo().with_context(lang=None).form_feedback(response, 'stripe') diff --git a/addons/payment_stripe/models/payment.py b/addons/payment_stripe/models/payment.py index c7dfc226512..adfcbb1d2f2 100644 --- a/addons/payment_stripe/models/payment.py +++ b/addons/payment_stripe/models/payment.py @@ -2,6 +2,7 @@ import logging import requests +import pprint from odoo import api, fields, models, _ from odoo.addons.payment.models.payment_acquirer import ValidationError @@ -186,11 +187,12 @@ class PaymentTokenStripe(models.Model): @api.model def stripe_create(self, values): - res = {} + token = values.get('stripe_token') + description = None payment_acquirer = self.env['payment.acquirer'].browse(values.get('acquirer_id')) - url_token = 'https://%s/tokens' % payment_acquirer._get_stripe_api_url() - url_customer = 'https://%s/customers' % payment_acquirer._get_stripe_api_url() + # when asking to create a token on Stripe servers if values.get('cc_number'): + url_token = 'https://%s/tokens' % payment_acquirer._get_stripe_api_url() payment_params = { 'card[number]': values['cc_number'].replace(' ', ''), 'card[exp_month]': str(values['cc_expiry'][:2]), @@ -203,27 +205,53 @@ class PaymentTokenStripe(models.Model): params=payment_params, headers=STRIPE_HEADERS) token = r.json() - if token.get('id'): - customer_params = { - 'source': token['id'], - 'description': values['cc_holder_name'] - } - if values.get('partner_id'): - partner = self.env['res.partner'].browse(values['partner_id']) - customer_params['email'] = partner.email and partner.email.strip() - r = requests.post(url_customer, - auth=(payment_acquirer.stripe_secret_key, ''), - params=customer_params, - headers=STRIPE_HEADERS) - customer = r.json() - res = { - 'acquirer_ref': customer['id'], - 'name': 'XXXXXXXXXXXX%s - %s' % (values['cc_number'][-4:], values['cc_holder_name']) - } - elif token.get('error'): - raise UserError(token['error']['message']) + description = values['cc_holder_name'] + + if not token: + raise Exception('stripe_create: No token provided!') + + res = self._stripe_create_customer(token, description, payment_acquirer.id) # pop credit card info to info sent to create - for field_name in ["cc_number", "cvc", "cc_holder_name", "cc_expiry", "cc_brand"]: + for field_name in ["cc_number", "cvc", "cc_holder_name", "cc_expiry", "cc_brand", "stripe_token"]: values.pop(field_name, None) return res + + + def _stripe_create_customer(self, token, description=None, acquirer_id=None): + if token['object'] != 'token': + _logger.error('payment.token.stripe_create_customer: Cannot create a customer for object type "%s"', token.get('object')) + raise Exception('We are unable to process your credit card information.') + + if token['type'] != 'card': + _logger.error('payment.token.stripe_create_customer: Cannot create a customer for token type "%s"', token.get('type')) + raise Exception('We are unable to process your credit card information.') + + if token.get('error'): + _logger.error('payment.token.stripe_create_customer: Token error:\n%s', pprint.pformat(token['error'])) + raise Exception(token['error']['message']) + + payment_acquirer = self.env['payment.acquirer'].browse(acquirer_id or self.acquirer_id.id) + url_customer = 'https://%s/customers' % payment_acquirer._get_stripe_api_url() + + customer_params = { + 'source': token['id'], + 'description': description or 'Partner: {} (id: {})'.format(self.partner_id.name, self.partner_id.id) + } + + r = requests.post(url_customer, + auth=(payment_acquirer.stripe_secret_key, ''), + params=customer_params, + headers=STRIPE_HEADERS) + customer = r.json() + + if customer.get('error'): + _logger.error('payment.token.stripe_create_customer: Customer error:\n%s', pprint.pformat(customer['error'])) + raise Exception(customer['error']['message']) + + values = { + 'acquirer_ref': customer['id'], + 'name': 'XXXXXXXXXXXX%s - %s' % (token['card']['last4'], token['email']) + } + + return values diff --git a/addons/payment_stripe/static/src/js/stripe.js b/addons/payment_stripe/static/src/js/stripe.js index b74601a172b..5c239582419 100644 --- a/addons/payment_stripe/static/src/js/stripe.js +++ b/addons/payment_stripe/static/src/js/stripe.js @@ -44,8 +44,9 @@ odoo.define('payment_stripe.stripe', function(require) { }); } ajax.jsonRpc("/payment/stripe/create_charge", 'call', { - tokenid: token.id, - email: token.email, + tokenid: token.id, // TBE TODO: for backward compatibility, remove on master + email: token.email, // TBE TODO: for backward compatibility, remove on master + token: token, amount: $("input[name='amount']").val(), acquirer_id: $("#acquirer_stripe").val(), currency: $("input[name='currency']").val(), diff --git a/addons/website_payment/controllers/main.py b/addons/website_payment/controllers/main.py index 31244b87cda..627412b8b71 100644 --- a/addons/website_payment/controllers/main.py +++ b/addons/website_payment/controllers/main.py @@ -14,7 +14,8 @@ class WebsitePayment(http.Controller): payment_tokens |= partner.commercial_partner_id.sudo().payment_token_ids values = { 'pms': payment_tokens, - 'acquirers': acquirers + 'acquirers': acquirers, + 'error_message': [kwargs.get('error')], } return_url = request.params.get('redirect', '/my/payment_method') for acquirer in acquirers: