diff options
18 files changed, 641 insertions, 0 deletions
diff --git a/addons/payment/data/payment_acquirer.xml b/addons/payment/data/payment_acquirer.xml index bc95fbc2b5a..e7fec99c1ca 100644 --- a/addons/payment/data/payment_acquirer.xml +++ b/addons/payment/data/payment_acquirer.xml @@ -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> diff --git a/addons/payment_stripe/__init__.py b/addons/payment_stripe/__init__.py new file mode 100644 index 00000000000..5efbd253ebb --- /dev/null +++ b/addons/payment_stripe/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +import models +import controllers diff --git a/addons/payment_stripe/__openerp__.py b/addons/payment_stripe/__openerp__.py new file mode 100644 index 00000000000..80e5f5395c7 --- /dev/null +++ b/addons/payment_stripe/__openerp__.py @@ -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', +} diff --git a/addons/payment_stripe/controllers/__init__.py b/addons/payment_stripe/controllers/__init__.py new file mode 100644 index 00000000000..bbd183e955b --- /dev/null +++ b/addons/payment_stripe/controllers/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +import main diff --git a/addons/payment_stripe/controllers/main.py b/addons/payment_stripe/controllers/main.py new file mode 100644 index 00000000000..3075ec68399 --- /dev/null +++ b/addons/payment_stripe/controllers/main.py @@ -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', '/') diff --git a/addons/payment_stripe/data/payment_stripe_data.xml b/addons/payment_stripe/data/payment_stripe_data.xml new file mode 100644 index 00000000000..49ac0838a35 --- /dev/null +++ b/addons/payment_stripe/data/payment_stripe_data.xml @@ -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> diff --git a/addons/payment_stripe/models/__init__.py b/addons/payment_stripe/models/__init__.py new file mode 100644 index 00000000000..49cea96f9de --- /dev/null +++ b/addons/payment_stripe/models/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- + +import payment_transaction +import payment_acquirer +import payment_method diff --git a/addons/payment_stripe/models/payment_acquirer.py b/addons/payment_stripe/models/payment_acquirer.py new file mode 100644 index 00000000000..1a0f6f3ed6e --- /dev/null +++ b/addons/payment_stripe/models/payment_acquirer.py @@ -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 diff --git a/addons/payment_stripe/models/payment_method.py b/addons/payment_stripe/models/payment_method.py new file mode 100644 index 00000000000..8fb07704b2e --- /dev/null +++ b/addons/payment_stripe/models/payment_method.py @@ -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 diff --git a/addons/payment_stripe/models/payment_transaction.py b/addons/payment_stripe/models/payment_transaction.py new file mode 100644 index 00000000000..66409f0b942 --- /dev/null +++ b/addons/payment_stripe/models/payment_transaction.py @@ -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) diff --git a/addons/payment_stripe/static/description/icon.png b/addons/payment_stripe/static/description/icon.png Binary files differnew file mode 100644 index 00000000000..c16523f0a5c --- /dev/null +++ b/addons/payment_stripe/static/description/icon.png diff --git a/addons/payment_stripe/static/src/img/stripe_icon.png b/addons/payment_stripe/static/src/img/stripe_icon.png Binary files differnew file mode 100644 index 00000000000..79e4e3cbab8 --- /dev/null +++ b/addons/payment_stripe/static/src/img/stripe_icon.png diff --git a/addons/payment_stripe/static/src/js/stripe.js b/addons/payment_stripe/static/src/js/stripe.js new file mode 100644 index 00000000000..a2399f5ea25 --- /dev/null +++ b/addons/payment_stripe/static/src/js/stripe.js @@ -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(); + }); +}); diff --git a/addons/payment_stripe/tests/__init__.py b/addons/payment_stripe/tests/__init__.py new file mode 100644 index 00000000000..13c90c428f9 --- /dev/null +++ b/addons/payment_stripe/tests/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +import test_stripe diff --git a/addons/payment_stripe/tests/test_stripe.py b/addons/payment_stripe/tests/test_stripe.py new file mode 100644 index 00000000000..a29b4a84be2 --- /dev/null +++ b/addons/payment_stripe/tests/test_stripe.py @@ -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') diff --git a/addons/payment_stripe/views/payment_acquirer.xml b/addons/payment_stripe/views/payment_acquirer.xml new file mode 100644 index 00000000000..db3c2be5c45 --- /dev/null +++ b/addons/payment_stripe/views/payment_acquirer.xml @@ -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> diff --git a/addons/payment_stripe/views/payment_stripe_template.xml b/addons/payment_stripe/views/payment_stripe_template.xml new file mode 100644 index 00000000000..74a7d7e03e2 --- /dev/null +++ b/addons/payment_stripe/views/payment_stripe_template.xml @@ -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> diff --git a/addons/payment_stripe/views/stripe.xml b/addons/payment_stripe/views/stripe.xml new file mode 100644 index 00000000000..ea089287b22 --- /dev/null +++ b/addons/payment_stripe/views/stripe.xml @@ -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> |
