[IMP] payment_stripe: Add support of form tokenization
- Added support of form based payment with tokenization to be able to pay Subscriptions and save a payment token for later payments
This commit is contained in:
@@ -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')
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user