@@ -112,4 +112,20 @@
|
||||
</ul>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="payment_acquirer_stripe" model="payment.acquirer">
|
||||
<field name="name">Stripe</field>
|
||||
<field name="view_template_id" ref="default_acquirer_button"/>
|
||||
<field name="image" type="base64" file="payment_stripe/static/description/icon.png"/>
|
||||
<field name="module_id" ref="base.module_payment_stripe"/>
|
||||
<field name="description" type="html">
|
||||
<p>
|
||||
A payment gateway to accept online payments via credit cards.
|
||||
</p>
|
||||
<ul>
|
||||
<li><i class="fa fa-check"/>eCommerce</li>
|
||||
</ul>
|
||||
</field>
|
||||
|
||||
</record>
|
||||
</odoo>
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import models
|
||||
import controllers
|
||||
@@ -0,0 +1,19 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
{
|
||||
'name': 'Stripe Payment Acquirer',
|
||||
'category': 'Hidden',
|
||||
'summary': 'Payment Acquirer: Stripe Implementation',
|
||||
'version': '1.0',
|
||||
'description': """Stripe Payment Acquirer""",
|
||||
'depends': ['payment'],
|
||||
'data': [
|
||||
'views/stripe.xml',
|
||||
'views/payment_acquirer.xml',
|
||||
'views/payment_stripe_template.xml',
|
||||
'data/payment_stripe_data.xml',
|
||||
],
|
||||
'images': ['static/description/icon.png'],
|
||||
'installable': True,
|
||||
'license': 'OEEL-1',
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import main
|
||||
@@ -0,0 +1,51 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import logging
|
||||
import pprint
|
||||
import werkzeug
|
||||
|
||||
from odoo import http
|
||||
from odoo.http import request
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class StripeController(http.Controller):
|
||||
|
||||
@http.route(['/payment/stripe/s2s/create_json'], type='json', auth='public')
|
||||
def stripe_s2s_create_json(self, **kwargs):
|
||||
acquirer_id = int(kwargs.get('acquirer_id'))
|
||||
acquirer = request.env['payment.acquirer'].browse(acquirer_id)
|
||||
return acquirer.s2s_process(kwargs)
|
||||
|
||||
@http.route(['/payment/stripe/s2s/create'], type='http', auth='public')
|
||||
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', '/'))
|
||||
|
||||
@http.route(['/payment/stripe/create_charge'], type='json', auth='public')
|
||||
def stripe_create_charge(self, **post):
|
||||
""" Create a payment transaction
|
||||
|
||||
Expects the result from the user input from checkout.js popup"""
|
||||
acquirer = request.env['payment.acquirer'].browse(int(post.get('acquirer_id')))
|
||||
order = request.env['sale.order'].sudo().browse(int(request.session.get('sale_order_id')))
|
||||
tx = request.env['payment.transaction'].sudo().create({
|
||||
'acquirer_id': acquirer.id,
|
||||
'reference': str(post.get('invoice_num')),
|
||||
'amount': float(post.get('amount')),
|
||||
'currency_id': request.env['res.currency'].search([('name', '=', post.get('currency'))], limit=1).id,
|
||||
'partner_id': request.env.user.partner_id.id,
|
||||
'sale_order_id': order.id
|
||||
})
|
||||
order.write({
|
||||
'payment_acquirer_id': acquirer.id,
|
||||
'payment_tx_id': tx.id
|
||||
})
|
||||
request.session['sale_transaction_id'] = tx.id
|
||||
response = tx._create_stripe_charge(tokenid=post['tokenid'])
|
||||
_logger.info('Stripe: entering form_feedback with post data %s', pprint.pformat(response))
|
||||
if response:
|
||||
request.env['payment.transaction'].sudo().form_feedback(response, 'stripe')
|
||||
return post.pop('return_url', '/')
|
||||
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
<record id="payment.payment_acquirer_stripe" model="payment.acquirer">
|
||||
<field name="name">Stripe</field>
|
||||
<field name="image" type="base64" file="payment_stripe/static/description/icon.png"/>
|
||||
<field name="provider">stripe</field>
|
||||
<field name="company_id" ref="base.main_company"/>
|
||||
<field name="view_template_id" ref="stripe_acquirer_button"/>
|
||||
<field name="registration_view_template_id" ref="stripe_s2s_form"/>
|
||||
<field name="environment">test</field>
|
||||
<field name="pre_msg"><![CDATA[
|
||||
<p>You will be prompt with Stripe Payment page for payment information.</p>]]></field>
|
||||
<field name="stripe_secret_key">dummy</field>
|
||||
<field name="stripe_publishable_key">dummy</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -0,0 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import payment_transaction
|
||||
import payment_acquirer
|
||||
import payment_method
|
||||
@@ -0,0 +1,68 @@
|
||||
# -*- coding: utf-'8' "-*-"
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
# Force the API version to avoid breaking in case of update on Stripe side
|
||||
# cf https://stripe.com/docs/api#versioning
|
||||
# changelog https://stripe.com/docs/upgrades#api-changelog
|
||||
STRIPE_HEADERS = {'Stripe-Version': '2016-03-07'}
|
||||
|
||||
|
||||
class PaymentAcquirerStripe(models.Model):
|
||||
_inherit = 'payment.acquirer'
|
||||
|
||||
stripe_secret_key = fields.Char(required_if_provider='stripe')
|
||||
stripe_publishable_key = fields.Char(required_if_provider='stripe')
|
||||
|
||||
@api.model
|
||||
def _get_providers(self):
|
||||
providers = super(PaymentAcquirerStripe, self)._get_providers()
|
||||
providers.append(['stripe', 'Stripe'])
|
||||
return providers
|
||||
|
||||
@api.multi
|
||||
def stripe_form_generate_values(self, tx_values):
|
||||
self.ensure_one()
|
||||
stripe_tx_values = dict(tx_values)
|
||||
temp_stripe_tx_values = {
|
||||
'amount': tx_values.get('amount'),
|
||||
'currency': tx_values.get('currency') and tx_values.get('currency').name or '',
|
||||
'address_line1': tx_values['partner_address'],
|
||||
'address_city': tx_values['partner_city'],
|
||||
'address_country': tx_values['partner_country'] and tx_values['partner_country'].name or '',
|
||||
'email': tx_values['partner_email'],
|
||||
'address_zip': tx_values['partner_zip'],
|
||||
'name': tx_values['partner_name'],
|
||||
'phone': tx_values['partner_phone'],
|
||||
}
|
||||
|
||||
temp_stripe_tx_values['returndata'] = stripe_tx_values.pop('return_url', '')
|
||||
stripe_tx_values.update(temp_stripe_tx_values)
|
||||
return stripe_tx_values
|
||||
|
||||
@api.model
|
||||
def _get_stripe_api_url(self):
|
||||
return 'api.stripe.com/v1'
|
||||
|
||||
@api.model
|
||||
def stripe_s2s_form_process(self, data):
|
||||
payment_method = self.env['payment.method'].sudo().create({
|
||||
'cc_number': data['cc_number'],
|
||||
'cc_holder_name': data['cc_holder_name'],
|
||||
'cc_expiry': data['cc_expiry'],
|
||||
'cc_brand': data['cc_brand'],
|
||||
'cvc': data['cvc'],
|
||||
'acquirer_id': int(data['acquirer_id']),
|
||||
'partner_id': int(data['partner_id'])
|
||||
})
|
||||
return payment_method.id
|
||||
|
||||
@api.multi
|
||||
def stripe_s2s_form_validate(self, data):
|
||||
self.ensure_one()
|
||||
|
||||
# mandatory fields
|
||||
for field_name in ["cc_number", "cvc", "cc_holder_name", "cc_expiry", "cc_brand"]:
|
||||
if not data.get(field_name):
|
||||
return False
|
||||
return True
|
||||
@@ -0,0 +1,50 @@
|
||||
# -*- coding: utf-'8' "-*-"
|
||||
|
||||
import requests
|
||||
|
||||
from odoo import api, models
|
||||
from odoo.exceptions import UserError
|
||||
from . import payment_acquirer as pa
|
||||
|
||||
|
||||
class PaymentMethodStripe(models.Model):
|
||||
_inherit = 'payment.method'
|
||||
|
||||
@api.model
|
||||
def stripe_create(self, values):
|
||||
res = 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()
|
||||
if values['cc_number']:
|
||||
payment_params = {
|
||||
'card[number]': values['cc_number'].replace(' ', ''),
|
||||
'card[exp_month]': str(values['cc_expiry'][:2]),
|
||||
'card[exp_year]': str(values['cc_expiry'][-2:]),
|
||||
'card[cvc]': values['cvc'],
|
||||
}
|
||||
r = requests.post(url_token,
|
||||
auth=(payment_acquirer.stripe_secret_key, ''),
|
||||
params=payment_params,
|
||||
headers=pa.STRIPE_HEADERS)
|
||||
token = r.json()
|
||||
if token.get('id'):
|
||||
customer_params = {
|
||||
'source': token['id']
|
||||
}
|
||||
r = requests.post(url_customer,
|
||||
auth=(payment_acquirer.stripe_secret_key, ''),
|
||||
params=customer_params,
|
||||
headers=pa.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'])
|
||||
|
||||
# pop credit card info to info sent to create
|
||||
for field_name in ["cc_number", "cvc", "cc_holder_name", "cc_expiry", "cc_brand"]:
|
||||
values.pop(field_name)
|
||||
return res
|
||||
@@ -0,0 +1,101 @@
|
||||
# -*- coding: utf-'8' "-*-"
|
||||
|
||||
import json
|
||||
import logging
|
||||
import requests
|
||||
import urllib
|
||||
|
||||
from odoo import api, fields, models, _
|
||||
from odoo.addons.payment.models.payment_acquirer import ValidationError
|
||||
from odoo.tools.safe_eval import safe_eval
|
||||
from . import payment_acquirer as pa
|
||||
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class PaymentTransactionStripe(models.Model):
|
||||
_inherit = 'payment.transaction'
|
||||
|
||||
def _create_stripe_charge(self, acquirer_ref=None, tokenid=None):
|
||||
api_url_charge = 'https://%s/charges' % (self.acquirer_id._get_stripe_api_url())
|
||||
charge_params = {
|
||||
'amount': int(self.amount*100), # Stripe takes amount in cents (https://support.stripe.com/questions/which-zero-decimal-currencies-does-stripe-support)
|
||||
'currency': self.currency_id.name,
|
||||
'metadata[reference]': self.reference
|
||||
}
|
||||
if acquirer_ref:
|
||||
charge_params['customer'] = acquirer_ref
|
||||
if tokenid:
|
||||
charge_params['card'] = str(tokenid)
|
||||
r = requests.post(api_url_charge,
|
||||
auth=(self.acquirer_id.stripe_secret_key, ''),
|
||||
params=charge_params,
|
||||
headers=pa.STRIPE_HEADERS)
|
||||
return r.json()
|
||||
|
||||
@api.multi
|
||||
def stripe_s2s_do_transaction(self, **kwargs):
|
||||
self.ensure_one()
|
||||
result = self._create_stripe_charge(acquirer_ref=self.payment_method_id.acquirer_ref)
|
||||
return self._stripe_s2s_validate_tree(result)
|
||||
|
||||
@api.model
|
||||
def _stripe_form_get_tx_from_data(self, data):
|
||||
""" Given a data dict coming from stripe, verify it and find the related
|
||||
transaction record. """
|
||||
reference = data['metadata']['reference']
|
||||
if not reference:
|
||||
error_msg = _('Stripe: invalid reply received from provider, missing reference')
|
||||
_logger.error(error_msg, data['metadata'])
|
||||
raise ValidationError(error_msg)
|
||||
tx = self.search([('reference', '=', reference)])
|
||||
if not tx:
|
||||
error_msg = (_('Stripe: no order found for reference %s') % reference)
|
||||
_logger.error(error_msg)
|
||||
raise ValidationError(error_msg)
|
||||
elif len(tx) > 1:
|
||||
error_msg = (_('Stripe: %s orders found for reference %s') % (len(tx), reference))
|
||||
_logger.error(error_msg)
|
||||
raise ValidationError(error_msg)
|
||||
return tx[0]
|
||||
|
||||
@api.multi
|
||||
def _stripe_s2s_validate_tree(self, tree):
|
||||
self.ensure_one()
|
||||
if self.state not in ('draft', 'pending'):
|
||||
_logger.info('Stripe: trying to validate an already validated tx (ref %s)', self.reference)
|
||||
return True
|
||||
|
||||
status = tree.get('status')
|
||||
if status == 'succeeded':
|
||||
self.write({
|
||||
'state': 'done',
|
||||
'date_validate': fields.datetime.now(),
|
||||
'acquirer_reference': tree.get('id'),
|
||||
})
|
||||
if self.callback_eval:
|
||||
safe_eval(self.callback_eval, {'self': self})
|
||||
return True
|
||||
else:
|
||||
error = tree['error']['message']
|
||||
_logger.warn(error)
|
||||
self.sudo().write({
|
||||
'state': 'error',
|
||||
'state_message': error,
|
||||
'acquirer_reference': tree.get('id'),
|
||||
'date_validate': fields.datetime.now(),
|
||||
})
|
||||
return False
|
||||
|
||||
@api.model
|
||||
def _stripe_form_get_invalid_parameters(self, tx, data):
|
||||
invalid_parameters = []
|
||||
reference = data['metadata']['reference']
|
||||
if reference != tx.reference:
|
||||
invalid_parameters.append(('Reference', reference, tx.reference))
|
||||
return invalid_parameters
|
||||
|
||||
@api.model
|
||||
def _stripe_form_validate(self, tx, data):
|
||||
return tx._stripe_s2s_validate_tree(data)
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 6.2 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 3.2 KiB |
@@ -0,0 +1,39 @@
|
||||
odoo.define('payment_stripe.stripe', function(require) {
|
||||
"use strict";
|
||||
var ajax = require('web.ajax');
|
||||
var handler = StripeCheckout.configure({
|
||||
key: $("input[name='stripe_key']").val(),
|
||||
locale: 'auto',
|
||||
closed: function() {
|
||||
if (!handler.isTokenGenerate) {
|
||||
$('#pay_stripe')
|
||||
.removeAttr('disabled')
|
||||
.find('i').remove();
|
||||
}
|
||||
},
|
||||
token: function(token, args) {
|
||||
handler.isTokenGenerate = true;
|
||||
ajax.jsonRpc("/payment/stripe/create_charge", 'call', {
|
||||
tokenid: token.id,
|
||||
email: token.email,
|
||||
amount: $("input[name='amount']").val(),
|
||||
acquirer_id: $("#acquirer_stripe").val(),
|
||||
currency: $("input[name='currency']").val(),
|
||||
invoice_num: $("input[name='invoice_num']").val(),
|
||||
return_url: $("input[name='return_url']").val()
|
||||
}).done(function(data){
|
||||
handler.isTokenGenerate = false;
|
||||
window.location.href = data;
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
$('#pay_stripe').on('click', function(e) {
|
||||
// Open Checkout with further options
|
||||
if(!$(this).find('i').length)
|
||||
$(this).append('<i class="fa fa-spinner fa-spin"/>');
|
||||
$(this).attr('disabled','disabled');
|
||||
handler.open();
|
||||
e.preventDefault();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,2 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import test_stripe
|
||||
@@ -0,0 +1,174 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import odoo
|
||||
from odoo import fields
|
||||
from odoo.addons.payment.tests.common import PaymentAcquirerCommon
|
||||
from odoo.tools import mute_logger
|
||||
|
||||
|
||||
@odoo.tests.common.at_install(True)
|
||||
@odoo.tests.common.post_install(True)
|
||||
class StripeCommon(PaymentAcquirerCommon):
|
||||
|
||||
def setUp(self):
|
||||
super(StripeCommon, self).setUp()
|
||||
self.currency_euro = self.env['res.currency'].search([('name', '=', 'EUR')], limit=1)
|
||||
# get the stripe account
|
||||
self.stripe_id = self.env.ref('payment.payment_acquirer_stripe').id
|
||||
|
||||
|
||||
@odoo.tests.common.at_install(True)
|
||||
@odoo.tests.common.post_install(True)
|
||||
class StripeTest(StripeCommon):
|
||||
|
||||
def test_10_stripe_s2s(self):
|
||||
stripe = self.env['payment.acquirer'].browse(self.stripe_id)
|
||||
self.assertEqual(stripe.environment, 'test', 'test without test environment')
|
||||
|
||||
# Add Stripe credentials
|
||||
stripe.write({
|
||||
'stripe_secret_key': 'sk_test_bldAlqh1U24L5HtRF9mBFpK7',
|
||||
'stripe_publishable_key': 'pk_test_0TKSyYSZS9AcS4keZ2cxQQCW',
|
||||
})
|
||||
|
||||
# Create payment meethod for Stripe
|
||||
payment_method = self.env['payment.method'].create({
|
||||
'acquirer_id': self.stripe_id,
|
||||
'partner_id': self.buyer_id,
|
||||
'cc_number': '4242424242424242',
|
||||
'cc_expiry': '02 / 26',
|
||||
'cc_brand': 'visa',
|
||||
'cvc': '111',
|
||||
'cc_holder_name': 'Johndoe',
|
||||
})
|
||||
|
||||
# Create transaction
|
||||
tx = self.env['payment.transaction'].create({
|
||||
'reference': 'test_ref_%s' % fields.date.today(),
|
||||
'currency_id': self.currency_euro.id,
|
||||
'acquirer_id': self.stripe_id,
|
||||
'partner_id': self.buyer_id,
|
||||
'payment_method_id': payment_method.id,
|
||||
'type': 'server2server',
|
||||
'amount': 115.0
|
||||
})
|
||||
tx.stripe_s2s_do_transaction()
|
||||
|
||||
# Check state
|
||||
self.assertEqual(tx.state, 'done', 'Stripe: Transcation has been discarded.')
|
||||
|
||||
def test_20_stripe_form_render(self):
|
||||
stripe = self.env['payment.acquirer'].browse(self.stripe_id)
|
||||
self.assertEqual(stripe.environment, 'test', 'test without test environment')
|
||||
|
||||
# ----------------------------------------
|
||||
# Test: button direct rendering
|
||||
# ----------------------------------------
|
||||
form_values = {
|
||||
'amount': 320.0,
|
||||
'currency': 'EUR',
|
||||
'address_line1': 'Huge Street 2/543',
|
||||
'address_city': 'Sin City',
|
||||
'address_country': 'Belgium',
|
||||
'email': 'norbert.buyer@example.com',
|
||||
'address_zip': '1000',
|
||||
'name': 'Norbert Buyer',
|
||||
'phone': '0032 12 34 56 78'
|
||||
}
|
||||
|
||||
# render the button
|
||||
res = stripe.render('SO404', 320.0, self.currency_euro.id, values=self.buyer_values)
|
||||
post_url = "https://checkout.stripe.com/checkout.js"
|
||||
email = "norbert.buyer@example.com"
|
||||
# check form result
|
||||
if "https://checkout.stripe.com/checkout.js" in res[0]:
|
||||
self.assertEqual(post_url, 'https://checkout.stripe.com/checkout.js', 'Stripe: wrong form POST url')
|
||||
# Generated and received
|
||||
if email in res[0]:
|
||||
self.assertEqual(
|
||||
email, form_values.get('email'),
|
||||
'Stripe: wrong value for input %s: received %s instead of %s' % (email, email, form_values.get('email'))
|
||||
)
|
||||
|
||||
def test_30_stripe_form_management(self):
|
||||
stripe = self.env['payment.acquirer'].browse(self.stripe_id)
|
||||
self.assertEqual(stripe.environment, 'test', 'test without test environment')
|
||||
|
||||
# typical data posted by Stripe after client has successfully paid
|
||||
stripe_post_data = {
|
||||
u'amount': 4700,
|
||||
u'amount_refunded': 0,
|
||||
u'application_fee': None,
|
||||
u'balance_transaction': u'txn_172xfnGMfVJxozLwssrsQZyT',
|
||||
u'captured': True,
|
||||
u'created': 1446529775,
|
||||
u'currency': u'eur',
|
||||
u'customer': None,
|
||||
u'description': None,
|
||||
u'destination': None,
|
||||
u'dispute': None,
|
||||
u'failure_code': None,
|
||||
u'failure_message': None,
|
||||
u'fraud_details': {},
|
||||
u'id': u'ch_172xfnGMfVJxozLwEjSfpfxD',
|
||||
u'invoice': None,
|
||||
u'livemode': False,
|
||||
u'metadata': {u'reference': u'SO100'},
|
||||
u'object': u'charge',
|
||||
u'paid': True,
|
||||
u'receipt_email': None,
|
||||
u'receipt_number': None,
|
||||
u'refunded': False,
|
||||
u'refunds': {u'data': [],
|
||||
u'has_more': False,
|
||||
u'object': u'list',
|
||||
u'total_count': 0,
|
||||
u'url': u'/v1/charges/ch_172xfnGMfVJxozLwEjSfpfxD/refunds'},
|
||||
u'shipping': None,
|
||||
u'source': {u'address_city': None,
|
||||
u'address_country': None,
|
||||
u'address_line1': None,
|
||||
u'address_line1_check': None,
|
||||
u'address_line2': None,
|
||||
u'address_state': None,
|
||||
u'address_zip': None,
|
||||
u'address_zip_check': None,
|
||||
u'brand': u'Visa',
|
||||
u'country': u'US',
|
||||
u'customer': None,
|
||||
u'cvc_check': u'pass',
|
||||
u'dynamic_last4': None,
|
||||
u'exp_month': 2,
|
||||
u'exp_year': 2022,
|
||||
u'fingerprint': u'9tJA9bUEuvEb3Ell',
|
||||
u'funding': u'credit',
|
||||
u'id': u'card_172xfjGMfVJxozLw1QO6gYNM',
|
||||
u'last4': u'4242',
|
||||
u'metadata': {},
|
||||
u'name': u'norbert.buyer@example.com',
|
||||
u'object': u'card',
|
||||
u'tokenization_method': None},
|
||||
u'statement_descriptor': None,
|
||||
u'status': u'succeeded'}
|
||||
|
||||
tx = self.env['payment.transaction'].create({
|
||||
'amount': 4700,
|
||||
'acquirer_id': self.stripe_id,
|
||||
'currency_id': self.currency_euro.id,
|
||||
'reference': 'SO100',
|
||||
'partner_name': 'Norbert Buyer',
|
||||
'partner_country_id': self.country_france_id})
|
||||
|
||||
# validate it
|
||||
tx.form_feedback(stripe_post_data, 'stripe')
|
||||
self.assertEqual(tx.state, 'done', 'Stripe: validation did not put tx into done state')
|
||||
self.assertEqual(tx.acquirer_reference, stripe_post_data.get('id'), 'Stripe: validation did not update tx id')
|
||||
# reset tx
|
||||
tx.write({'state': 'draft', 'date_validate': False, 'acquirer_reference': False})
|
||||
# simulate an error
|
||||
stripe_post_data['status'] = 'error'
|
||||
stripe_post_data.update({u'error': {u'message': u"Your card's expiration year is invalid.", u'code': u'invalid_expiry_year', u'type': u'card_error', u'param': u'exp_year'}})
|
||||
with mute_logger('openerp.addons.payment_stripe.models.payment_transaction'):
|
||||
tx.form_feedback(stripe_post_data, 'stripe')
|
||||
# check state
|
||||
self.assertEqual(tx.state, 'error', 'Stipe: erroneous validation did not put tx into error state')
|
||||
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="acquirer_form_stripe" model="ir.ui.view">
|
||||
<field name="name">payment.acquirer.form.inherit</field>
|
||||
<field name="model">payment.acquirer</field>
|
||||
<field name="inherit_id" ref="payment.acquirer_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr='//group[@name="acquirer"]' position='after'>
|
||||
<group attrs="{'invisible': [('provider', '!=', 'stripe')]}">
|
||||
<field name="stripe_secret_key" password="True"/>
|
||||
<field name="stripe_publishable_key" password="True"/>
|
||||
</group>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<template id="payment_stripe_redirect" name="Payment Stripe">
|
||||
<script type="text/javascript">
|
||||
window.location.href = '<t t-esc="return_url"/>';
|
||||
</script>
|
||||
</template>
|
||||
</odoo>
|
||||
@@ -0,0 +1,66 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<template id="stripe_acquirer_button">
|
||||
<form t-if="acquirer" method="post" target="_self">
|
||||
<script src="https://checkout.stripe.com/checkout.js"></script>
|
||||
<input type='hidden' name='amount' t-att-value="amount"/>
|
||||
<input type="hidden" name='return_url' t-att-value='returndata'/>
|
||||
<!--Order Information -->
|
||||
<input type='hidden' name='invoice_num' t-att-value='reference'/>
|
||||
<input type='hidden' name='currency' t-att-value='currency'/>
|
||||
<!-- Billing Information-->
|
||||
<input type='hidden' name='name' t-att-value='name'/>
|
||||
<input type='hidden' name='address_line1' t-att-value='address_line1'/>
|
||||
<input type='hidden' name='address_city' t-att-value='address_city'/>
|
||||
<input type='hidden' name='address_zip' t-att-value='address_zip'/>
|
||||
<input type='hidden' name='address_country' t-att-value='address_country'/>
|
||||
<input type='hidden' name='phone' t-att-value='phone'/>
|
||||
<input type='hidden' name='email' t-att-value='email'/>
|
||||
<input id="acquirer_stripe" type='hidden' name="acquirer" t-att-value="acquirer.id"/>
|
||||
<input type='hidden' name="stripe_key" t-att-value="acquirer.stripe_publishable_key"/>
|
||||
<!-- Submit-->
|
||||
<button id="pay_stripe" width="100px" t-att-class="submit_class">
|
||||
<img t-if="not submit_txt" src="/payment_stripe/static/src/img/stripe_icon.png"/>
|
||||
<span t-if="submit_txt"><t t-esc="submit_txt"/> <span class="fa fa-long-arrow-right"/></span>
|
||||
</button>
|
||||
<script type="text/javascript" src="/payment_stripe/static/src/js/stripe.js"></script>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<template id="stripe_s2s_form">
|
||||
<form method="post" t-att-action="'/payment/stripe/s2s/create' if not json else '/payment/stripe/s2s/create_json'">
|
||||
<div t-att-class="'row' if bootstrap_formatting else ''">
|
||||
<div t-att-class="'form-group col-md-8' if bootstrap_formatting else 'form-group'">
|
||||
<label class="control-label" for="cc_number">Card Number</label>
|
||||
<input type="tel" name="cc_number" id="cc_number" class="form-control" placeholder="•••• •••• •••• •••• "/>
|
||||
<div class="card_placeholder"></div>
|
||||
<div class="visa"></div>
|
||||
<input type="hidden" name="cc_brand" value=""/>
|
||||
</div>
|
||||
<div t-att-class="'form-group col-md-4' if bootstrap_formatting else 'form-group'">
|
||||
<label class="control-label" for="cvc">CVC</label>
|
||||
<input type="text" name="cvc" id="cvc" class="form-control" maxlength="4" placeholder="CVC"/>
|
||||
</div>
|
||||
<div t-att-class="'form-group col-md-7' if bootstrap_formatting else 'form-group'">
|
||||
<label class="control-label" for="cc_holder_name">Card Holder Name</label>
|
||||
<input type="text" name="cc_holder_name" id="cc_holder_name" class="form-control"/>
|
||||
</div>
|
||||
<div t-att-class="'form-group col-md-5' if bootstrap_formatting else 'form-group'">
|
||||
<label class="control-label" for="cc_expires_mm">Expiration Date</label>
|
||||
<input type="text" name="cc_expiry" id="cc_expiry" class="form-control" maxlength="7" placeholder="MM / YY"/>
|
||||
</div>
|
||||
<input type="hidden" name="acquirer_id" t-att-value="id"/>
|
||||
<input t-if="return_url" type="hidden" name="return_url" t-att-value="return_url"/>
|
||||
<input t-if="partner_id" type="hidden" name="partner_id" t-att-value="partner_id"/>
|
||||
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
|
||||
<div class="clearfix"/>
|
||||
</div>
|
||||
<button t-att-class="submit_class" class="btn btn-primary" type="submit">
|
||||
<span t-if="not submit_txt">Confirm <span class="fa fa-long-arrow-right"></span></span>
|
||||
<span t-if="submit_txt"><t t-esc="submit_txt"/></span>
|
||||
</button>
|
||||
</form>
|
||||
</template>
|
||||
</data>
|
||||
</odoo>
|
||||
Reference in New Issue
Block a user