[MERGE] payments: Add new payment form to e-commerce & online quote
- The generic form now support form & s2s payments. - The generic form is now implemented to pay on e-commerce and online quotation. - Added icons of supported credit cards for each payment acquirers. - Replaced e-commerce footer that was displaying payment acquirers by supported credit cards icons. - The payment form doesn't render s2s forms in python anymore. - The payment form now display an error when credit cards credentials are not filled. - Fixed a bug where paying with a registered token on e-commerce would crash. - Fixed errors not displaying on the payment form.
@@ -9,6 +9,7 @@
|
||||
'depends': ['account'],
|
||||
'data': [
|
||||
'data/account_data.xml',
|
||||
'data/payment_icon_data.xml',
|
||||
'data/payment_acquirer_data.xml',
|
||||
'views/payment_views.xml',
|
||||
'views/account_payment_views.xml',
|
||||
|
||||
@@ -8,17 +8,18 @@ from odoo.http import request
|
||||
class WebsitePayment(http.Controller):
|
||||
@http.route(['/my/payment_method'], type='http', auth="user", website=True)
|
||||
def payment_method(self, **kwargs):
|
||||
acquirers = list(request.env['payment.acquirer'].search([('website_published', '=', True), ('registration_view_template_id', '!=', False)]))
|
||||
acquirers = list(request.env['payment.acquirer'].search([('website_published', '=', True), ('registration_view_template_id', '!=', False), ('payment_flow', '=', 's2s')]))
|
||||
partner = request.env.user.partner_id
|
||||
payment_tokens = partner.payment_token_ids
|
||||
payment_tokens |= partner.commercial_partner_id.sudo().payment_token_ids
|
||||
return_url = request.params.get('redirect', '/my/payment_method')
|
||||
values = {
|
||||
'pms': payment_tokens,
|
||||
'acquirers': acquirers
|
||||
'acquirers': acquirers,
|
||||
'return_url': return_url,
|
||||
'bootstrap_formatting': True,
|
||||
'partner_id': partner.id
|
||||
}
|
||||
return_url = request.params.get('redirect', '/my/payment_method')
|
||||
for acquirer in acquirers:
|
||||
acquirer.form = acquirer.sudo()._registration_render(request.env.user.partner_id.id, {'error': {}, 'error_message': [], 'return_url': return_url, 'json': False, 'bootstrap_formatting': True})
|
||||
return request.render("payment.pay_methods", values)
|
||||
|
||||
@http.route(['/website_payment/pay'], type='http', auth='public', website=True)
|
||||
|
||||
@@ -2,20 +2,14 @@
|
||||
<odoo noupdate="1">
|
||||
|
||||
<template id="default_acquirer_button">
|
||||
<form t-if="acquirer" t-att-action="tx_url" method="post" target="_self">
|
||||
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
|
||||
<t t-if="return_url">
|
||||
<input type="hidden" name="return_url" t-att-value="return_url"/>
|
||||
</t>
|
||||
<input type="hidden" name="reference" t-att-value="reference"/>
|
||||
<input type="hidden" name="amount" t-att-value="amount"/>
|
||||
<input type="hidden" name="currency" t-att-value="currency.name"/>
|
||||
<!-- submit -->
|
||||
<button type="submit" width="100px" t-att-class="submit_class">
|
||||
<img t-if="not submit_txt" src="/payment_transfer/static/src/img/transfer_icon.png"/>
|
||||
<span t-if="submit_txt"><t t-esc="submit_txt"/> <span class="fa fa-long-arrow-right"/></span>
|
||||
</button>
|
||||
</form>
|
||||
<input type="hidden" name="data_set" t-att-data-action-url="tx_url"/>
|
||||
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
|
||||
<t t-if="return_url">
|
||||
<input type="hidden" name="return_url" t-att-value="return_url"/>
|
||||
</t>
|
||||
<input type="hidden" name="reference" t-att-value="reference"/>
|
||||
<input type="hidden" name="amount" t-att-value="amount"/>
|
||||
<input type="hidden" name="currency" t-att-value="currency.name"/>
|
||||
</template>
|
||||
|
||||
<record id="payment_acquirer_buckaroo" model="payment.acquirer">
|
||||
@@ -32,6 +26,12 @@
|
||||
<li><i class="fa fa-check"/>Payment Status Tracking</li>
|
||||
</ul>
|
||||
</field>
|
||||
<!-- https://www.buckaroo-payments.com/products/payment-methods/ -->
|
||||
<field name="payment_icon_ids" eval='[(6, 0, [ref("payment.payment_icon_cc_bancontact"),
|
||||
ref("payment.payment_icon_cc_maestro"),
|
||||
ref("payment.payment_icon_cc_mastercard"),
|
||||
ref("payment.payment_icon_cc_visa"),
|
||||
ref("payment.payment_icon_cc_american_express")])]'/>
|
||||
</record>
|
||||
|
||||
<record id="payment_acquirer_ogone" model="payment.acquirer">
|
||||
@@ -51,6 +51,11 @@
|
||||
<li><i class="fa fa-check"/>Save Cards</li>
|
||||
</ul>
|
||||
</field>
|
||||
<!-- https://payment-services.ingenico.com/~/media/files/130806_product_sheet_ingenico_collect_en.ashx?la=en -->
|
||||
<field name="payment_icon_ids" eval='[(6, 0, [ref("payment.payment_icon_cc_bancontact"),
|
||||
ref("payment.payment_icon_cc_maestro"),
|
||||
ref("payment.payment_icon_cc_mastercard"),
|
||||
ref("payment.payment_icon_cc_visa")])]'/>
|
||||
</record>
|
||||
|
||||
<record id="payment_acquirer_adyen" model="payment.acquirer">
|
||||
@@ -67,6 +72,15 @@
|
||||
<li><i class="fa fa-check"/>Payment Status Tracking</li>
|
||||
</ul>
|
||||
</field>
|
||||
<!-- https://www.adyen.com/payment-methods -->
|
||||
<field name="payment_icon_ids" eval='[(6, 0, [ref("payment.payment_icon_cc_bancontact"),
|
||||
ref("payment.payment_icon_cc_maestro"),
|
||||
ref("payment.payment_icon_cc_mastercard"),
|
||||
ref("payment.payment_icon_cc_visa"),
|
||||
ref("payment.payment_icon_cc_discover"),
|
||||
ref("payment.payment_icon_cc_diners_club_intl"),
|
||||
ref("payment.payment_icon_cc_jcb"),
|
||||
ref("payment.payment_icon_cc_unionpay")])]'/>
|
||||
</record>
|
||||
|
||||
<record id="payment_acquirer_authorize" model="payment.acquirer">
|
||||
@@ -87,6 +101,13 @@
|
||||
<li><i class="fa fa-check"/>Manual Capture</li>
|
||||
</ul>
|
||||
</field>
|
||||
<!-- https://www.authorize.net/solutions/merchantsolutions/onlinemerchantaccount/ -->
|
||||
<field name="payment_icon_ids" eval='[(6, 0, [ref("payment.payment_icon_cc_maestro"),
|
||||
ref("payment.payment_icon_cc_mastercard"),
|
||||
ref("payment.payment_icon_cc_discover"),
|
||||
ref("payment.payment_icon_cc_diners_club_intl"),
|
||||
ref("payment.payment_icon_cc_jcb"),
|
||||
ref("payment.payment_icon_cc_visa")])]'/>
|
||||
</record>
|
||||
|
||||
<record id="payment_acquirer_transfer" model="payment.acquirer">
|
||||
@@ -117,6 +138,16 @@
|
||||
<li><i class="fa fa-check"/>Payment Status Tracking</li>
|
||||
</ul>
|
||||
</field>
|
||||
<!-- http://sips.worldline.com/en-us/home/features/payment-types-and-acquirers.html -->
|
||||
<field name="payment_icon_ids" eval='[(6, 0, [ref("payment.payment_icon_cc_maestro"),
|
||||
ref("payment.payment_icon_cc_mastercard"),
|
||||
ref("payment.payment_icon_cc_discover"),
|
||||
ref("payment.payment_icon_cc_diners_club_intl"),
|
||||
ref("payment.payment_icon_cc_jcb"),
|
||||
ref("payment.payment_icon_cc_american_express"),
|
||||
ref("payment.payment_icon_cc_bancontact"),
|
||||
ref("payment.payment_icon_cc_unionpay"),
|
||||
ref("payment.payment_icon_cc_visa")])]'/>
|
||||
</record>
|
||||
|
||||
<record id="payment_acquirer_paypal" model="payment.acquirer">
|
||||
@@ -134,6 +165,15 @@
|
||||
<li><i class="fa fa-check"/>Payment Status Tracking</li>
|
||||
</ul>
|
||||
</field>
|
||||
<!-- https://www.paypal.com/us/selfhelp/article/Which-credit-cards-can-I-accept-with-PayPal-Merchant-Services-FAQ1525#business -->
|
||||
<field name="payment_icon_ids" eval='[(6, 0, [ref("payment.payment_icon_cc_maestro"),
|
||||
ref("payment.payment_icon_cc_mastercard"),
|
||||
ref("payment.payment_icon_cc_discover"),
|
||||
ref("payment.payment_icon_cc_diners_club_intl"),
|
||||
ref("payment.payment_icon_cc_jcb"),
|
||||
ref("payment.payment_icon_cc_american_express"),
|
||||
ref("payment.payment_icon_cc_unionpay"),
|
||||
ref("payment.payment_icon_cc_visa")])]'/>
|
||||
</record>
|
||||
|
||||
<record id="payment_acquirer_stripe" model="payment.acquirer">
|
||||
@@ -150,7 +190,17 @@
|
||||
<li><i class="fa fa-check"/>Payment Status Tracking</li>
|
||||
</ul>
|
||||
</field>
|
||||
|
||||
<!--
|
||||
https://stripe.com/payments/payment-methods-guide
|
||||
https://support.goteamup.com/hc/en-us/articles/115002089349-Which-cards-and-payment-types-can-I-accept-with-Stripe-
|
||||
-->
|
||||
<field name="payment_icon_ids" eval='[(6, 0, [ref("payment.payment_icon_cc_maestro"),
|
||||
ref("payment.payment_icon_cc_mastercard"),
|
||||
ref("payment.payment_icon_cc_discover"),
|
||||
ref("payment.payment_icon_cc_diners_club_intl"),
|
||||
ref("payment.payment_icon_cc_jcb"),
|
||||
ref("payment.payment_icon_cc_american_express"),
|
||||
ref("payment.payment_icon_cc_visa")])]'/>
|
||||
</record>
|
||||
|
||||
<record id="payment_acquirer_custom" model="payment.acquirer">
|
||||
@@ -182,6 +232,13 @@
|
||||
<li><i class="fa fa-check"/>Payment Status Tracking</li>
|
||||
</ul>
|
||||
</field>
|
||||
<!-- https://www.payumoney.com/selfcare.html?userType=seller
|
||||
> Banks & Cards > What options do you have in the Credit Card payment?
|
||||
-->
|
||||
<field name="payment_icon_ids" eval='[(6, 0, [ref("payment.payment_icon_cc_maestro"),
|
||||
ref("payment.payment_icon_cc_mastercard"),
|
||||
ref("payment.payment_icon_cc_american_express"),
|
||||
ref("payment.payment_icon_cc_visa")])]'/>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="payment_icon_cc_visa" model="payment.icon">
|
||||
<field name="name">VISA</field>
|
||||
<field name="image" type="base64" file="payment/static/img/visa.png"/>
|
||||
</record>
|
||||
|
||||
<record id="payment_icon_cc_american_express" model="payment.icon">
|
||||
<field name="name">American Express</field>
|
||||
<field name="image" type="base64" file="payment/static/img/american_express.png"/>
|
||||
</record>
|
||||
|
||||
<record id="payment_icon_cc_cirrus" model="payment.icon">
|
||||
<field name="name">Cirrus</field>
|
||||
<field name="image" type="base64" file="payment/static/img/cirrus.png"/>
|
||||
</record>
|
||||
|
||||
<record id="payment_icon_cc_diners_club_intl" model="payment.icon">
|
||||
<field name="name">Diners Club International</field>
|
||||
<field name="image" type="base64" file="payment/static/img/diners_club_intl.png"/>
|
||||
</record>
|
||||
|
||||
<record id="payment_icon_cc_diners_club_intl" model="payment.icon">
|
||||
<field name="name">Diners Club International</field>
|
||||
<field name="image" type="base64" file="payment/static/img/diners_club_intl.png"/>
|
||||
</record>
|
||||
|
||||
<record id="payment_icon_cc_discover" model="payment.icon">
|
||||
<field name="name">Discover</field>
|
||||
<field name="image" type="base64" file="payment/static/img/discover.png"/>
|
||||
</record>
|
||||
|
||||
<record id="payment_icon_cc_jcb" model="payment.icon">
|
||||
<field name="name">JCB</field>
|
||||
<field name="image" type="base64" file="payment/static/img/jcb.png"/>
|
||||
</record>
|
||||
|
||||
<record id="payment_icon_cc_maestro" model="payment.icon">
|
||||
<field name="name">Maestro</field>
|
||||
<field name="image" type="base64" file="payment/static/img/maestro.png"/>
|
||||
</record>
|
||||
|
||||
<record id="payment_icon_cc_mastercard" model="payment.icon">
|
||||
<field name="name">MasterCard</field>
|
||||
<field name="image" type="base64" file="payment/static/img/mastercard.png"/>
|
||||
</record>
|
||||
|
||||
<record id="payment_icon_cc_unionpay" model="payment.icon">
|
||||
<field name="name">UnionPay</field>
|
||||
<field name="image" type="base64" file="payment/static/img/unionpay.png"/>
|
||||
</record>
|
||||
|
||||
<record id="payment_icon_cc_bancontact" model="payment.icon">
|
||||
<field name="name">Bancontact</field>
|
||||
<field name="image" type="base64" file="payment/static/img/bancontact.png"/>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -5,7 +5,7 @@ import logging
|
||||
import datetime
|
||||
|
||||
from odoo import api, exceptions, fields, models, _
|
||||
from odoo.tools import consteq, float_round, image_resize_images, ustr
|
||||
from odoo.tools import consteq, float_round, image_resize_images, image_resize_image, ustr
|
||||
from odoo.addons.base.module import module
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
@@ -117,8 +117,8 @@ class PaymentAcquirer(models.Model):
|
||||
help='Message displayed, if error is occur during the payment process.')
|
||||
save_token = fields.Selection([
|
||||
('none', 'Never'),
|
||||
('ask', 'Let the customer decide (recommended for eCommerce)'),
|
||||
('always', 'Always (recommended for Subscriptions)')],
|
||||
('ask', 'Let the customer decide'),
|
||||
('always', 'Always')],
|
||||
string='Save Cards', default='none',
|
||||
help="This option allows customers to save their credit card as a payment token and to reuse it for a later purchase."
|
||||
"If you manage subscriptions (recurring invoicing), you need it to automatically charge the customer when you "
|
||||
@@ -150,6 +150,12 @@ class PaymentAcquirer(models.Model):
|
||||
"resized as a 64x64px image, with aspect ratio preserved. "
|
||||
"Use this field anywhere a small image is required.")
|
||||
|
||||
payment_icon_ids = fields.Many2many('payment.icon', string='Supported Payment Icons')
|
||||
payment_flow = fields.Selection(selection=[('s2s','The customer encode his payment details on the website.'),
|
||||
('form', 'The customer is redirected to the website of the acquirer.')],
|
||||
default='form', required=True, string='Payment flow',
|
||||
help="""Note: Subscriptions does not take this field in account, it uses server to server by default.""")
|
||||
|
||||
def _search_is_tokenized(self, operator, value):
|
||||
tokenized = self._get_feature_support()['tokenize']
|
||||
if (operator, value) in [('=', True), ('!=', False)]:
|
||||
@@ -344,16 +350,11 @@ class PaymentAcquirer(models.Model):
|
||||
|
||||
return self.view_template_id.render(values, engine='ir.qweb')
|
||||
|
||||
@api.multi
|
||||
def _registration_render(self, partner_id, qweb_context=None):
|
||||
if qweb_context is None:
|
||||
qweb_context = {}
|
||||
qweb_context.update(id=self.ids[0], partner_id=partner_id)
|
||||
method_name = '_%s_registration_form_generate_values' % (self.provider,)
|
||||
if hasattr(self, method_name):
|
||||
method = getattr(self, method_name)
|
||||
qweb_context.update(method(qweb_context))
|
||||
return self.registration_view_template_id.render(qweb_context, engine='ir.qweb')
|
||||
def get_s2s_form_xml_id(self):
|
||||
if self.registration_view_template_id:
|
||||
model_data = self.env['ir.model.data'].search([('model', '=', 'ir.ui.view'), ('res_id', '=', self.registration_view_template_id.id)])
|
||||
return ('%s.%s') % (model_data.module, model_data.name)
|
||||
return False
|
||||
|
||||
@api.multi
|
||||
def s2s_process(self, data):
|
||||
@@ -394,6 +395,32 @@ class PaymentAcquirer(models.Model):
|
||||
'context': context,
|
||||
}
|
||||
|
||||
class PaymentIcon(models.Model):
|
||||
_name = 'payment.icon'
|
||||
_description = 'Payment Icon'
|
||||
|
||||
name = fields.Char(string='Name')
|
||||
acquirer_ids = fields.Many2many('payment.acquirer', string="Acquirers", help="List of Acquirers supporting this payment icon.")
|
||||
image = fields.Binary(
|
||||
"Image", attachment=True,
|
||||
help="This field holds the image used for this payment icon, limited to 1024x1024px")
|
||||
|
||||
image_payment_form = fields.Binary(
|
||||
"Image displayed on the payment form", attachment=True)
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
if 'image' in vals:
|
||||
vals['image_payment_form'] = image_resize_image(vals['image'], size=(45,30))
|
||||
vals['image'] = image_resize_image(vals['image'], size=(64,64))
|
||||
return super(PaymentIcon, self).create(vals)
|
||||
|
||||
@api.multi
|
||||
def write(self, vals):
|
||||
if 'image' in vals:
|
||||
vals['image_payment_form'] = image_resize_image(vals['image'], size=(45,30))
|
||||
vals['image'] = image_resize_image(vals['image'], size=(64,64))
|
||||
return super(PaymentIcon, self).write(vals)
|
||||
|
||||
class PaymentTransaction(models.Model):
|
||||
""" Transaction Model. Each specific acquirer can extend the model by adding
|
||||
|
||||
@@ -9,3 +9,6 @@ payment_method_all,payment.token.all,model_payment_token,,1,0,0,0
|
||||
payment_method_user,payment.token.user,model_payment_token,base.group_user,1,1,1,1
|
||||
payment_method_portal,payment.token.portal,model_payment_token,base.group_portal,1,1,1,1
|
||||
payment_method_system,payment.token.system,model_payment_token,base.group_system,1,1,1,1
|
||||
payment_icon_all,payment.icon.all,model_payment_icon,,1,0,0,0
|
||||
payment_icon_user,payment.icon.user,model_payment_icon,base.group_user,1,1,1,0
|
||||
payment_icon_system,payment.icon.system,model_payment_icon,base.group_system,1,1,1,1
|
||||
|
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 6.9 KiB |
|
After Width: | Height: | Size: 6.6 KiB |
|
After Width: | Height: | Size: 8.7 KiB |
|
After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 7.8 KiB |
|
After Width: | Height: | Size: 8.8 KiB |
|
After Width: | Height: | Size: 9.3 KiB |
|
After Width: | Height: | Size: 4.8 KiB |
@@ -18,7 +18,6 @@ odoo.define('payment.payment_form', function (require){
|
||||
},
|
||||
|
||||
payEvent: function(ev) {
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
var form = this.el;
|
||||
var checked_radio = this.$('input[type="radio"]:checked');
|
||||
@@ -33,8 +32,28 @@ odoo.define('payment.payment_form', function (require){
|
||||
var acquirer_id = this.getAcquirerIdFromRadio(checked_radio);
|
||||
var acquirer_form = this.$('#o_payment_add_token_acq_' + acquirer_id);
|
||||
// we retrieve all the input inside the acquirer form and 'serialize' them to an indexed array
|
||||
var form_data = this.getFormData($('input', acquirer_form));
|
||||
var inputs_form = $('input', acquirer_form);
|
||||
var form_data = this.getFormData(inputs_form);
|
||||
var ds = $('input[name="data_set"]', acquirer_form)[0];
|
||||
var empty_inputs = false;
|
||||
|
||||
inputs_form.toArray().forEach(function(element) {
|
||||
if(element.dataset.isRequired) {
|
||||
if (element.value.length === 0) {
|
||||
$(element).closest('div.form-group').addClass('has-error');
|
||||
}
|
||||
else {
|
||||
$(element).closest('div.form-group').removeClass('has-error');
|
||||
}
|
||||
empty_inputs = true;
|
||||
}
|
||||
});
|
||||
|
||||
if(empty_inputs) {
|
||||
this.error(_t('Missing values'), _t('<p>Please fill all the inputs required.</p>'));
|
||||
return;
|
||||
}
|
||||
|
||||
$(button).attr('disabled', true);
|
||||
$(button).prepend('<span class="o_loader"><i class="fa fa-refresh fa-spin"></i> </span>');
|
||||
|
||||
@@ -59,7 +78,7 @@ odoo.define('payment.payment_form', function (require){
|
||||
}
|
||||
// if the server has returned false, we display an error
|
||||
else {
|
||||
self.error(_t('Error'),
|
||||
self.error(_t('Server Error'),
|
||||
_t("<p>We are not able to add your payment method at the moment.</p>"));
|
||||
}
|
||||
// here we remove the 'processing' icon from the 'add a new payment' button
|
||||
@@ -70,10 +89,62 @@ odoo.define('payment.payment_form', function (require){
|
||||
$(button).attr('disabled', false);
|
||||
$(button).find('span.o_loader').remove();
|
||||
|
||||
self.error(_t('Error'),
|
||||
self.error(_t('Server Error'),
|
||||
_t("<p>We are not able to add your payment method at the moment.</p>") + (core.debug ? data.data.message : ''));
|
||||
});
|
||||
}
|
||||
// if the user is going to pay with a form payment, then
|
||||
else if(this.isFormPaymentRadio(checked_radio))
|
||||
{
|
||||
var self = this;
|
||||
// we retrieve the acquirer id and its form
|
||||
var acquirer_id = this.getAcquirerIdFromRadio(checked_radio);
|
||||
var acquirer_form = this.$('#o_payment_form_acq_' + acquirer_id);
|
||||
var inputs_form = $('input', acquirer_form);
|
||||
var ds = $('input[name="data_set"]', acquirer_form)[0];
|
||||
var form_save_token = false;
|
||||
var $tx_url = this.$el.find('input[name="prepare_tx_url"]');
|
||||
|
||||
// if neither the dataset or the action url is defined, then we just stop the execution of the function
|
||||
if(!ds || !ds.dataset.actionUrl)
|
||||
return;
|
||||
|
||||
// if there's a prepare tx url set
|
||||
if($tx_url.length == 1)
|
||||
{
|
||||
// if the user wants to save his credit card info
|
||||
form_save_token = $('input[name="o_payment_form_save_token"]').checked === true;
|
||||
// then we call the route to prepare the transaction
|
||||
ajax.jsonRpc($tx_url[0].value, 'call', {
|
||||
'acquirer_id': parseInt(acquirer_id),
|
||||
'save_token': form_save_token
|
||||
}).then(function(result){
|
||||
if(result) {
|
||||
// if the server sent us the html form, we create a form element
|
||||
var newForm = document.createElement('form');
|
||||
newForm.setAttribute("method", "post"); // set it to post
|
||||
newForm.setAttribute("action", ds.dataset.actionUrl); // set the action url
|
||||
newForm.hidden = true; // hide it
|
||||
newForm.innerHTML = result; // put the html sent by the server inside the form
|
||||
document.getElementsByTagName('body')[0].appendChild(newForm); // append the form to the body
|
||||
$(newForm).find('input[data-remove-me]').remove(); // remove all the input that should be removed
|
||||
newForm.submit(); // and finally submit the form
|
||||
}
|
||||
else {
|
||||
self.error(_t('Server Error'),
|
||||
_t("<p>We are not able to redirect you to the payment form.</p>"));
|
||||
}
|
||||
}).fail(function(message, data){
|
||||
self.error(_t('Server Error'),
|
||||
_t("<p>We are not able to redirect you to the payment form.</p>") + (core.debug ? data.data.message : ''));
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
// we append the form to the body and send it.
|
||||
this.error(_t("Cannot set-up the payment"), _t("<p>We're unable to process your payment.</p>"));
|
||||
}
|
||||
}
|
||||
// if the user is using an old payment
|
||||
else {
|
||||
// then we just submit the form
|
||||
@@ -81,8 +152,8 @@ odoo.define('payment.payment_form', function (require){
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.error(_t('Error'),
|
||||
_t('<p>Please select a payment method</p>'));
|
||||
this.error(_t('No payment method selected'),
|
||||
_t('<p>Please select a payment method.</p>'));
|
||||
}
|
||||
},
|
||||
// event handler when clicking on the button to add a new payment method
|
||||
@@ -96,16 +167,35 @@ odoo.define('payment.payment_form', function (require){
|
||||
|
||||
// we check if the user has selected a 'add a new payment' option
|
||||
if(checked_radio.length == 1 && this.isNewPaymentRadio(checked_radio[0])) {
|
||||
// then we add a 'processing' icon into the 'add a new payment' button
|
||||
$(button).attr('disabled', true);
|
||||
$(button).prepend('<span class="o_loader"><i class="fa fa-refresh fa-spin"></i> </span>');
|
||||
// we retrieve which acquirer is used
|
||||
checked_radio = checked_radio[0];
|
||||
var acquirer_id = this.getAcquirerIdFromRadio(checked_radio);
|
||||
var acquirer_form = this.$('#o_payment_add_token_acq_' + acquirer_id);
|
||||
// we retrieve all the input inside the acquirer form and 'serialize' them to an indexed array
|
||||
var form_data = this.getFormData($('input', acquirer_form));
|
||||
var inputs_form = $('input', acquirer_form);
|
||||
var form_data = this.getFormData(inputs_form);
|
||||
var ds = $('input[name="data_set"]', acquirer_form)[0];
|
||||
var empty_inputs = false;
|
||||
|
||||
inputs_form.toArray().forEach(function(element) {
|
||||
if(element.dataset.isRequired) {
|
||||
if (element.value.length === 0) {
|
||||
$(element).closest('div.form-group').addClass('has-error');
|
||||
}
|
||||
else {
|
||||
$(element).closest('div.form-group').removeClass('has-error');
|
||||
}
|
||||
empty_inputs = true;
|
||||
}
|
||||
});
|
||||
|
||||
if(empty_inputs) {
|
||||
this.error(_t('Missing values'), _t('<p>Please fill all the inputs required.</p>'));
|
||||
return;
|
||||
}
|
||||
// We add a 'processing' icon into the 'add a new payment' button
|
||||
$(button).attr('disabled', true);
|
||||
$(button).prepend('<span class="o_loader"><i class="fa fa-refresh fa-spin"></i> </span>');
|
||||
|
||||
// we force the check when adding a card trough here
|
||||
form_data.verify_validity = true;
|
||||
@@ -132,7 +222,7 @@ odoo.define('payment.payment_form', function (require){
|
||||
}
|
||||
// if the server has returned false, we display an error
|
||||
else {
|
||||
self.error(_t('Error'),
|
||||
self.error(_t('Server Error'),
|
||||
_t("<p>We are not able to add your payment method at the moment.</p>"));
|
||||
}
|
||||
// here we remove the 'processing' icon from the 'add a new payment' button
|
||||
@@ -143,13 +233,13 @@ odoo.define('payment.payment_form', function (require){
|
||||
$(button).attr('disabled', false);
|
||||
$(button).find('span.o_loader').remove();
|
||||
|
||||
self.error(_t('Error'),
|
||||
self.error(_t('Server error'),
|
||||
_t("<p>We are not able to add your payment method at the moment.</p>") + (core.debug ? data.data.message : ''));
|
||||
});
|
||||
}
|
||||
else {
|
||||
this.error(_t('Error'),
|
||||
_t('<p>Please select the option to add a new payment method</p>'));
|
||||
this.error(_t('No payment method selected'),
|
||||
_t('<p>Please select the option to add a new payment method.</p>'));
|
||||
}
|
||||
},
|
||||
// event handler when clicking on a button to delete a payment method
|
||||
@@ -170,7 +260,7 @@ odoo.define('payment.payment_form', function (require){
|
||||
ev.target.closest('div').remove();
|
||||
}
|
||||
},function(type,err){
|
||||
self.error(_t('Error'),
|
||||
self.error(_t('Server Error'),
|
||||
_t("<p>We are not able to delete your payment method at the moment.</p>"));
|
||||
});
|
||||
};
|
||||
@@ -202,7 +292,7 @@ odoo.define('payment.payment_form', function (require){
|
||||
Delete();
|
||||
}
|
||||
}, function(type, err){
|
||||
self.error(_t('Error'),
|
||||
self.error(_t('Server Error'),
|
||||
_t("<p>We are not able to delete your payment method at the moment.</p>") + (core.debug ? err.data.message : ''));
|
||||
});
|
||||
},
|
||||
@@ -215,28 +305,43 @@ odoo.define('payment.payment_form', function (require){
|
||||
var checked_radio = this.$('input[type="radio"]:checked');
|
||||
// we hide all the acquirers form
|
||||
this.$('[id*="o_payment_add_token_acq_"]').addClass('hidden');
|
||||
this.$('[id*="o_payment_form_acq_"]').addClass('hidden');
|
||||
if(checked_radio.length != 1) {
|
||||
return;
|
||||
}
|
||||
checked_radio = checked_radio[0];
|
||||
// if we clicked on an add new payment radio
|
||||
if(checked_radio.length == 1 && this.isNewPaymentRadio(checked_radio[0]))
|
||||
if(this.isNewPaymentRadio(checked_radio))
|
||||
{
|
||||
// then we retrieve the acquirer name
|
||||
var acquirer_id = this.getAcquirerIdFromRadio(checked_radio[0]);
|
||||
var acquirer_id = this.getAcquirerIdFromRadio(checked_radio);
|
||||
// and display its form
|
||||
this.$('#o_payment_add_token_acq_' + acquirer_id).removeClass('hidden');
|
||||
}
|
||||
else if(this.isFormPaymentRadio(checked_radio))
|
||||
{
|
||||
// then we retrieve the acquirer name
|
||||
var acquirer_id = this.getAcquirerIdFromRadio(checked_radio);
|
||||
// and display its form
|
||||
this.$('#o_payment_form_acq_' + acquirer_id).removeClass('hidden');
|
||||
}
|
||||
},
|
||||
isNewPaymentRadio: function(element) {
|
||||
return $(element).data('acquirer-id') !== undefined;
|
||||
return $(element).data('s2s-payment') === 'True';
|
||||
},
|
||||
isFormPaymentRadio: function(element) {
|
||||
return $(element).data('form-payment') === 'True';
|
||||
},
|
||||
getAcquirerIdFromRadio: function(element) {
|
||||
return $(element).data('acquirer-id');
|
||||
},
|
||||
error: function(title, message, url) {
|
||||
return new Dialog(null, {
|
||||
title: title || "",
|
||||
$content: $(core.qweb.render('website.error_dialog', {
|
||||
message: message || "",
|
||||
})),
|
||||
}).open();
|
||||
title: _t('Error: ') + title,
|
||||
size: 'medium',
|
||||
$content: message || "",
|
||||
buttons: [
|
||||
{text: _t('Ok'), close: true}]}).open();
|
||||
},
|
||||
getFormData: function($form){
|
||||
var unindexed_array = $form.serializeArray();
|
||||
@@ -249,13 +354,18 @@ odoo.define('payment.payment_form', function (require){
|
||||
},
|
||||
start: function() {
|
||||
this.updateNewPaymentDisplayStatus();
|
||||
$('[data-toggle="tooltip"]').tooltip();
|
||||
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
|
||||
$(document).ready(function (){
|
||||
var form = new PaymentForm();
|
||||
form.attachTo($('.o_payment_form'));
|
||||
});
|
||||
require('web.dom_ready'); // only start this when dom is ready
|
||||
if (!$('.o_payment_form').length) {
|
||||
return $.Deferred().reject("DOM doesn't contain '.o_payment_form'");
|
||||
}
|
||||
var form = new PaymentForm();
|
||||
form.attachTo($('.o_payment_form'));
|
||||
|
||||
});
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
odoo.define('payment.transaction', function (require) {
|
||||
"use strict";
|
||||
|
||||
var ajax = require('web.ajax');
|
||||
|
||||
$(document).ready(function () {
|
||||
// When choosing an acquirer, display its Pay Now button
|
||||
var $payment = $("#payment_method");
|
||||
$payment.on("click", "input[name='acquirer'], a.btn_payment_token", function (ev) {
|
||||
var ico_off = 'fa-circle-o';
|
||||
var ico_on = 'fa-dot-circle-o';
|
||||
|
||||
var payment_id = $(ev.currentTarget).val() || $(this).data('acquirer');
|
||||
var token = $(ev.currentTarget).data('token') || '';
|
||||
|
||||
$("div.o_payment_acquirer_button[data-id='"+payment_id+"']", $payment).attr('data-token', token);
|
||||
$("div.js_payment a.list-group-item").removeClass("list-group-item-info");
|
||||
$('span.js_radio').switchClass(ico_on, ico_off, 0);
|
||||
if (token) {
|
||||
$("div.o_payment_acquirer_button div.token_hide").hide();
|
||||
$(ev.currentTarget).find('span.js_radio').switchClass(ico_off, ico_on, 0);
|
||||
$(ev.currentTarget).parents('li').find('input').prop("checked", true);
|
||||
$(ev.currentTarget).addClass("list-group-item-info");
|
||||
}
|
||||
else{
|
||||
$("div.o_payment_acquirer_button div.token_hide").show();
|
||||
}
|
||||
$("div.o_payment_acquirer_button[data-id]", $payment).addClass("hidden");
|
||||
$("div.o_payment_acquirer_button[data-id='"+payment_id+"']", $payment).removeClass("hidden");
|
||||
|
||||
})
|
||||
.find("input[name='acquirer']:checked").click();
|
||||
|
||||
// When clicking on payment button: create the tx using json then continue to the acquirer
|
||||
$payment.on("click", 'button[type="submit"], button[name="submit"]', function (ev) {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
var $form = $(ev.currentTarget).parents('form');
|
||||
var acquirer = $(ev.currentTarget).parents('div.o_payment_acquirer_button').first();
|
||||
var tx_data = acquirer.data();
|
||||
if (! tx_data.id || ! tx_data.callUrl) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var params = {"tx_type": tx_data.txType || acquirer.find('input[name="odoo_save_token"]').is(':checked') ? 'form_save': 'form'};
|
||||
var acquirer_token = acquirer.attr('data-token'); // !=data
|
||||
if (acquirer_token) {
|
||||
params.token = acquirer_token;
|
||||
}
|
||||
if (tx_data.access_token) {
|
||||
params.access_token = tx_data.access_token;
|
||||
}
|
||||
$form.off('submit');
|
||||
ajax.jsonRpc(tx_data.callUrl, 'call', params).then(function (data) {
|
||||
$(data).appendTo('body').submit();
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
$('div.oe_pay_token').on('click', 'a.js_btn_valid_tx', function() {
|
||||
$('div.js_token_load').toggle();
|
||||
|
||||
var $form = $(this).parents('form');
|
||||
ajax.jsonRpc($form.attr('action'), 'call', $.deparam($form.serialize())).then(function (data) {
|
||||
if (data.url) {
|
||||
window.location = data.url;
|
||||
}
|
||||
else {
|
||||
$('div.js_token_load').toggle();
|
||||
if (!data.success && data.error) {
|
||||
$('div.oe_pay_token div.panel-body p').html(data.error + "<br/><br/>" + _('Retry ? '));
|
||||
$('div.oe_pay_token div.panel-body').parents('div').removeClass('panel-info').addClass('panel-danger');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
@@ -1,10 +1,10 @@
|
||||
.o_payment_form {
|
||||
label > input[type="radio"]{
|
||||
label > input[type="radio"], input[type="checkbox"]{
|
||||
vertical-align: bottom;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
label {
|
||||
.payment_option_name {
|
||||
font-size: 14px;
|
||||
font-weight: normal !important;
|
||||
font-family: Helvetica Neue, sans-serif;
|
||||
@@ -12,6 +12,10 @@
|
||||
color: #4d4d4d;
|
||||
}
|
||||
|
||||
label {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.panel-body:first-child {
|
||||
border-top: 0px;
|
||||
}
|
||||
@@ -29,4 +33,18 @@
|
||||
border-top: 1px solid #ddd;
|
||||
padding: 1.14em !important;
|
||||
}
|
||||
|
||||
.payment_icon_list {
|
||||
li {
|
||||
padding-left: 5px !important;
|
||||
padding-right: 0px !important;
|
||||
}
|
||||
|
||||
.more_option {
|
||||
font-size:10px;
|
||||
}
|
||||
|
||||
margin-top: 0px !important;
|
||||
margin-bottom: -5px !important;
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,6 @@
|
||||
<xpath expr="." position="inside">
|
||||
<link rel='stylesheet' href='/payment/static/src/css/portal_payment.css'/>
|
||||
<script type="text/javascript" src="/payment/static/lib/jquery.payment/jquery.payment.js"></script>
|
||||
<script type="text/javascript" src="/payment/static/src/js/payment_transaction.js"></script>
|
||||
<script type="text/javascript" src="/payment/static/src/js/payment_portal.js"></script>
|
||||
<script type="text/javascript" src="/payment/static/src/js/payment_transaction_portal.js"></script>
|
||||
<script type="text/javascript" src="/payment/static/src/js/payment_form.js"></script>
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
<div class="col-sm-8">
|
||||
<h3>Manage your Payment Methods</h3>
|
||||
<t t-call="payment.payment_tokens_list">
|
||||
<t t-set="s2s_acquirers" t-value="acquirers"/>
|
||||
<t t-set="mode" t-value="'manage'"/>
|
||||
<t t-set="verify_validity" t-value="True"/>
|
||||
</t>
|
||||
|
||||
@@ -17,36 +17,100 @@
|
||||
- 'checked_pm_id' the payment token that should be checked (for radio buttons)
|
||||
- 'mode' can take two values, either 'payment' or 'manage'. 'manage' displays the add a new card and delete buttons. 'payment'
|
||||
display a form that is used to pay and send the information to the form action url.
|
||||
- 'acquirers' the list of the acquirers
|
||||
- 's2s_acquirers' the list of the server2server acquirers
|
||||
- 'form_acquirers' the list of the payment acquirers to pay with forms
|
||||
- 'verify_validity' if we need to verify if the payment method is valid when adding a new one
|
||||
- 'prepare_tx_url' the url of the route which will handle the creation of a transaction for a form base payment (handles if the transaction is form or form_save)
|
||||
-->
|
||||
<form method="post" t-att-action="form_action if form_action else '#'" class="o_payment_form">
|
||||
<form t-if="s2s_acquirers or pms or form_acquirers" method="post" t-att-action="form_action if form_action else '#'" class="o_payment_form">
|
||||
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
|
||||
<input type="hidden" t-if="verify_validity==True" name="verify_validity" value="1"/>
|
||||
<input type="hidden" t-if="prepare_tx_url" name="prepare_tx_url" t-att-value="prepare_tx_url"/>
|
||||
<div class="panel panel-default">
|
||||
<t t-foreach="acquirers" t-as="acq">
|
||||
<t t-set="acquirers_count" t-value="(len(s2s_acquirers) if s2s_acquirers else 0) + (len(form_acquirers) if form_acquirers else 0)"/>
|
||||
<t t-set="pms_count" t-value="len(pms) if pms else 0"/>
|
||||
<t t-foreach="s2s_acquirers" t-as="acq">
|
||||
<div class="panel-body">
|
||||
<label>
|
||||
<t t-if="mode == 'manage'">
|
||||
<input type="radio" t-att-data-acquirer-id="acq.id" name="pm_id" t-attf-value="new_{{acq.id}}" t-att-class="'hidden' if (len(acquirers)==1) else ''" t-att-checked="len(acquirers) == 1"/>
|
||||
<input type="radio" t-att-data-acquirer-id="acq.id"
|
||||
t-att-data-s2s-payment="true"
|
||||
t-att-data-provider="acq.provider"
|
||||
name="pm_id" t-attf-value="new_{{acq.id}}"
|
||||
t-att-class="'hidden' if acquirers_count==1 else ''"
|
||||
t-att-checked="acquirers_count == 1"/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<input type="radio" t-att-data-acquirer-id="acq.id" name="pm_id" t-attf-value="new_{{acq.id}}" t-att-class="'hidden' if (len(acquirers)==1 and len(pms)==0) else ''" t-att-checked="len(acquirers)==1 and len(pms)==0"/>
|
||||
<input type="radio" t-att-data-acquirer-id="acq.id"
|
||||
t-att-data-s2s-payment="true"
|
||||
t-att-data-provider="acq.provider"
|
||||
name="pm_id" t-attf-value="new_{{acq.id}}"
|
||||
t-att-class="'hidden' if (acquirers_count==1 and pms_count==0) else ''"
|
||||
t-att-checked="acquirers_count==1 and pms_count==0"/>
|
||||
</t>
|
||||
<t t-esc="acq.name"/>
|
||||
<span class="payment_option_name" t-esc="acq.name"/>
|
||||
</label>
|
||||
<ul class="pull-right list-inline payment_icon_list">
|
||||
<t t-set="i" t-value="0"/>
|
||||
<t t-foreach="acq.payment_icon_ids" t-as="pm_icon">
|
||||
<li t-if="i < 3">
|
||||
<span t-field="pm_icon.image_payment_form"
|
||||
t-options='{"widget": "image", "alt-field": "name"}' />
|
||||
</li>
|
||||
<li t-if="i==3" style="display:block;">
|
||||
<span class="pull-right more_option text-info">
|
||||
<a href="#" data-toggle="tooltip" t-att-title="', '.join([opt.name for opt in acq.payment_icon_ids[3:]])">and more</a>
|
||||
</span>
|
||||
</li>
|
||||
<t t-set="i" t-value="i+1"/>
|
||||
</t>
|
||||
</ul>
|
||||
</div>
|
||||
<div t-attf-id="o_payment_add_token_acq_{{acq.id}}" t-attf-class="panel-footer {{'hidden' if (len(acquirers)>1 and len(pms)==0 and acquirers[0]!=acq) else 'hidden' if len(pms)>0 else ''}}">
|
||||
<div t-attf-id="o_payment_add_token_acq_{{acq.id}}" t-attf-class="panel-footer {{'hidden' if (len(s2s_acquirers)>1 and len(pms)==0 and s2s_acquirers[0]!=acq) else 'hidden' if len(pms)>0 else ''}}">
|
||||
<div class="clearfix">
|
||||
<t t-raw="acq.form" t-att-data-acquirer-id="acquirer.id"/>
|
||||
<t t-call="{{acq.sudo().get_s2s_form_xml_id()}}">
|
||||
<t t-set="id" t-value="acq.id"/>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<t t-if="mode == 'payment'" t-foreach="form_acquirers" t-as="acq">
|
||||
<div class="panel-body">
|
||||
<label>
|
||||
<input type="radio" t-att-data-acquirer-id="acq.id"
|
||||
t-att-data-form-payment="true"
|
||||
t-att-data-provider="acq.provider"
|
||||
t-att-class="'hidden' if (acquirers_count==1 and pms_count==0) else ''"
|
||||
t-att-checked="acquirers_count==1 and pms_count==0"
|
||||
name="pm_id" t-attf-value="form_{{acq.id}}"/>
|
||||
<span class="payment_icon_name" t-esc="acq.name"/>
|
||||
</label>
|
||||
<ul class="pull-right list-inline payment_icon_list">
|
||||
<t t-set="i" t-value="0"/>
|
||||
<t t-foreach="acq.payment_icon_ids" t-as="pm_icon">
|
||||
<li t-if="i < 3">
|
||||
<span t-field="pm_icon.image_payment_form"
|
||||
t-options='{"widget": "image", "alt-field": "name"}' />
|
||||
</li>
|
||||
<li t-if="i==3" style="display:block;">
|
||||
<span class="pull-right more_option text-info">
|
||||
<a href="#" data-toggle="tooltip" t-att-title="', '.join([opt.name for opt in acq.payment_icon_ids[3:]])">and more</a>
|
||||
</span>
|
||||
</li>
|
||||
<t t-set="i" t-value="i+1"/>
|
||||
</t>
|
||||
</ul>
|
||||
</div>
|
||||
<div t-attf-id="o_payment_form_acq_{{acq.id}}" t-attf-class="hidden {{'panel-footer' if acq.save_token == 'ask' else ''}}">
|
||||
<label t-if="acq.save_token == 'ask'"><input type="checkbox" name="o_payment_form_save_token" data-remove-me=""/> Save my payment data</label>
|
||||
<t t-raw="acq.form"/>
|
||||
</div>
|
||||
</t>
|
||||
<t t-foreach="pms" t-as="pm">
|
||||
<div class="panel-body">
|
||||
<label>
|
||||
<input t-if="mode == 'payment'" type="radio" name="pm_id" t-att-value="pm.id" t-att-checked="checked_pm_id == pm.id"/>
|
||||
<t t-esc="pm.name"/>
|
||||
<span class="payment_option_name" t-esc="pm.name"/>
|
||||
<t t-if="pm.verified">
|
||||
<i class="fa fa-check text-success" title="This payment method is verified by our system."></i>
|
||||
</t>
|
||||
|
||||
@@ -112,6 +112,8 @@
|
||||
</div>
|
||||
</div>
|
||||
<field name="registration_view_template_id" groups="base.group_no_one"/>
|
||||
<field name="payment_icon_ids" widget="many2many_tags"/>
|
||||
<field name="payment_flow" widget="radio"/>
|
||||
</group>
|
||||
</page>
|
||||
</notebook>
|
||||
@@ -376,5 +378,45 @@
|
||||
parent='root_payment_menu'
|
||||
groups='base.group_no_one'/>
|
||||
|
||||
<!-- Payment icons -->
|
||||
<record model="ir.ui.view" id="payment_icon_form_view">
|
||||
<field name="name">payment.icon.form</field>
|
||||
<field name="model">payment.icon</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Payment Icon">
|
||||
<sheet>
|
||||
<field name="image" widget="image" class="oe_avatar" options='{"preview_image": "image_medium"}'/>
|
||||
<div class="oe_title">
|
||||
<h1><field name="name" placeholder="Name"/></h1>
|
||||
</div>
|
||||
<group group="base.group_no_one">
|
||||
<notebook>
|
||||
<page string="Acquirers list">
|
||||
<field nolabel="1" name="acquirer_ids"/>
|
||||
</page>
|
||||
</notebook>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_payment_icon" model="ir.actions.act_window">
|
||||
<field name="name">Payment Icons</field>
|
||||
<field name="res_model">payment.icon</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="help" type="html">
|
||||
<p class="oe_view_nocontent_create">
|
||||
Click to create a payment icon.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<menuitem
|
||||
action="action_payment_icon"
|
||||
id="payment_icon_menu"
|
||||
parent="root_payment_menu"
|
||||
groups="base.group_no_one"/>
|
||||
</data>
|
||||
</odoo>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<field name="image" type="base64" file="payment_adyen/static/src/img/adyen_icon.png"/>
|
||||
<field name="provider">adyen</field>
|
||||
<field name="company_id" ref="base.main_company"/>
|
||||
<field name="view_template_id" ref="adyen_acquirer_button"/>
|
||||
<field name="view_template_id" ref="adyen_form"/>
|
||||
<field name="environment">test</field>
|
||||
<field name="pre_msg"><![CDATA[
|
||||
<p>You will be redirected to the Adyen website after clicking on the payment button.</p>]]></field>
|
||||
|
||||
@@ -1,36 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
|
||||
<template id="adyen_acquirer_button">
|
||||
<form t-if="acquirer.adyen_merchant_account" t-att-action="tx_url" method="post" target="_self">
|
||||
<input type="hidden" name="merchantReference" t-att-value="merchantReference"/>
|
||||
<input type="hidden" name="paymentAmount" t-att-value="paymentAmount"/>
|
||||
<input type="hidden" name="currencyCode" t-att-value="currencyCode"/>
|
||||
<input type="hidden" name="shipBeforeDate" t-att-value="shipBeforeDate"/>
|
||||
<input type="hidden" name="skinCode" t-att-value="skinCode"/>
|
||||
<input type="hidden" name="merchantAccount" t-att-value="merchantAccount"/>
|
||||
<input type="hidden" name="shopperLocale" t-att-value="shopperLocale"/>
|
||||
<input type="hidden" name="sessionValidity" t-att-value="sessionValidity"/>
|
||||
<input type="hidden" name="merchantSig" t-att-value="merchantSig"/>
|
||||
<!-- URLs -->
|
||||
<input type='hidden' name='resURL'
|
||||
t-att-value="resURL"/>
|
||||
<!-- custom -->
|
||||
<input t-if="merchantReturnData" type='hidden' name='merchantReturnData'
|
||||
t-att-value="merchantReturnData"/>
|
||||
<!-- shopperEmail is not included for SHA-1. To avoid breaking compatibility,
|
||||
include only if filled in -->
|
||||
<input t-if="shopperEmail"
|
||||
type='hidden' name='shopperEmail' t-att-value="shopperEmail"/>
|
||||
<!-- submit -->
|
||||
<button type="submit" width="100px"
|
||||
t-att-class="submit_class">
|
||||
<img t-if="not submit_txt" src="/payment_adyen/static/src/img/adyen_icon.png"/>
|
||||
<span t-if="submit_txt"><t t-esc="submit_txt"/> <span class="fa fa-long-arrow-right"/></span>
|
||||
</button>
|
||||
</form>
|
||||
<template id="adyen_form">
|
||||
<input type="hidden" name="data_set" t-att-data-action-url="tx_url" data-remove-me=""/>
|
||||
<input type="hidden" name="merchantReference" t-att-value="merchantReference"/>
|
||||
<input type="hidden" name="paymentAmount" t-att-value="paymentAmount"/>
|
||||
<input type="hidden" name="currencyCode" t-att-value="currencyCode"/>
|
||||
<input type="hidden" name="shipBeforeDate" t-att-value="shipBeforeDate"/>
|
||||
<input type="hidden" name="skinCode" t-att-value="skinCode"/>
|
||||
<input type="hidden" name="merchantAccount" t-att-value="merchantAccount"/>
|
||||
<input type="hidden" name="shopperLocale" t-att-value="shopperLocale"/>
|
||||
<input type="hidden" name="sessionValidity" t-att-value="sessionValidity"/>
|
||||
<input type="hidden" name="merchantSig" t-att-value="merchantSig"/>
|
||||
<!-- URLs -->
|
||||
<input type='hidden' name='resURL'
|
||||
t-att-value="resURL"/>
|
||||
<!-- custom -->
|
||||
<input t-if="merchantReturnData" type='hidden' name='merchantReturnData'
|
||||
t-att-value="merchantReturnData"/>
|
||||
<!-- shopperEmail is not included for SHA-1. To avoid breaking compatibility,
|
||||
include only if filled in -->
|
||||
<input t-if="shopperEmail"
|
||||
type='hidden' name='shopperEmail' t-att-value="shopperEmail"/>
|
||||
</template>
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<field name="image" type="base64" file="payment_authorize/static/src/img/authorize_icon.png"/>
|
||||
<field name="provider">authorize</field>
|
||||
<field name="company_id" ref="base.main_company"/>
|
||||
<field name="view_template_id" ref="authorize_acquirer_button"/>
|
||||
<field name="view_template_id" ref="authorize_form"/>
|
||||
<field name="registration_view_template_id" ref="authorize_s2s_form"/>
|
||||
<field name="environment">test</field>
|
||||
<field name="pre_msg"><![CDATA[
|
||||
|
||||
@@ -89,10 +89,13 @@ class AuthorizeForm(AuthorizeCommon):
|
||||
res = self.authorize.render('SO004', 320.0, self.currency_usd.id, values=self.buyer_values)
|
||||
# check form result
|
||||
tree = objectify.fromstring(res)
|
||||
self.assertEqual(tree.get('action'), 'https://test.authorize.net/gateway/transact.dll', 'Authorize: wrong form POST url')
|
||||
|
||||
data_set = tree.xpath("//input[@name='data_set']")
|
||||
self.assertEqual(len(data_set), 1, 'Authorize: Found %d "data_set" input instead of 1' % len(data_set))
|
||||
self.assertEqual(data_set[0].get('data-action-url'), 'https://test.authorize.net/gateway/transact.dll', 'Authorize: wrong data-action-url POST url')
|
||||
for el in tree.iterfind('input'):
|
||||
values = list(el.attrib.values())
|
||||
if values[1] in ['submit', 'x_fp_hash', 'return_url', 'x_state', 'x_ship_to_state']:
|
||||
if values[1] in ['submit', 'x_fp_hash', 'return_url', 'x_state', 'x_ship_to_state', 'data_set']:
|
||||
continue
|
||||
self.assertEqual(
|
||||
values[2],
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
<template id="authorize_acquirer_button">
|
||||
<form t-if="acquirer" t-att-action="tx_url" method="post" target="_self">
|
||||
<template id="authorize_form">
|
||||
<div>
|
||||
<input type="hidden" name="data_set" t-att-data-action-url="tx_url" data-remove-me=""/>
|
||||
<input type='hidden' name='x_login' t-att-value='x_login'/>
|
||||
<input type='hidden' name='x_fp_hash' t-att-value='x_fp_hash'/>
|
||||
<input type='hidden' name='x_amount' t-att-value='x_amount'/>
|
||||
@@ -39,12 +40,7 @@
|
||||
<input type='hidden' name='x_ship_to_phone' t-att-value='phone'/>
|
||||
<input type='hidden' name='x_ship_to_email' t-att-value="email"/>
|
||||
<input type='hidden' name='x_ship_to_state' t-att-value="state"/>
|
||||
<!-- Submit-->
|
||||
<button type="submit" width="100px" t-att-class="submit_class">
|
||||
<img t-if="not submit_txt" src="/payment_authorize/static/src/img/authorize_icon.png"/>
|
||||
<span t-if="submit_txt"><t t-esc="submit_txt"/> <span class="fa fa-long-arrow-right"/></span>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id="payment_authorize_redirect" name="Payment Authorize">
|
||||
@@ -57,19 +53,19 @@
|
||||
<input type="hidden" name="data_set" data-create-route="/payment/authorize/s2s/create_json_3ds"/>
|
||||
<div class="mt8">
|
||||
<div t-att-class="'form-group col-md-12' if bootstrap_formatting else 'form-group'">
|
||||
<input type="tel" name="cc_number" id="cc_number" class="form-control" placeholder="Card number"/>
|
||||
<input type="tel" name="cc_number" id="cc_number" class="form-control" placeholder="Card number" data-is-required="true"/>
|
||||
<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-5' if bootstrap_formatting else 'form-group'">
|
||||
<input type="text" name="cc_holder_name" id="cc_holder_name" class="form-control" placeholder="Cardholder name"/>
|
||||
<input type="text" name="cc_holder_name" id="cc_holder_name" class="form-control" placeholder="Cardholder name" data-is-required="true"/>
|
||||
</div>
|
||||
<div t-att-class="'form-group col-md-3' if bootstrap_formatting else 'form-group'">
|
||||
<input type="text" name="cc_expiry" id="cc_expiry" class="form-control" maxlength="7" placeholder="Expires (MM / YY)"/>
|
||||
<input type="text" name="cc_expiry" id="cc_expiry" class="form-control" maxlength="7" placeholder="Expires (MM / YY)" data-is-required="true"/>
|
||||
</div>
|
||||
<div t-att-class="'form-group col-md-4' if bootstrap_formatting else 'form-group'">
|
||||
<input type="text" name="cc_cvc" id="cc_cvc" class="form-control" maxlength="4" placeholder="CVC"/>
|
||||
<input type="text" name="cc_cvc" id="cc_cvc" class="form-control" maxlength="4" placeholder="CVC" data-is-required="true"/>
|
||||
</div>
|
||||
</div>
|
||||
<input type="hidden" name="acquirer_id" t-att-value="id"/>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<field name="image" type="base64" file="payment_buckaroo/static/src/img/buckaroo_icon.png"/>
|
||||
<field name="provider">buckaroo</field>
|
||||
<field name="company_id" ref="base.main_company"/>
|
||||
<field name="view_template_id" ref="buckaroo_acquirer_button"/>
|
||||
<field name="view_template_id" ref="buckaroo_form"/>
|
||||
<field name="environment">test</field>
|
||||
<field name="pre_msg"><![CDATA[
|
||||
<p>You will be redirected to the Buckaroo website after clicking on the payment button.</p>]]></field>
|
||||
|
||||
@@ -1,34 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
|
||||
<template id="buckaroo_acquirer_button">
|
||||
<form t-if="acquirer.brq_websitekey" t-att-action="tx_url" method="post" target="_self">
|
||||
<input type="hidden" name="Brq_websitekey" t-att-value="Brq_websitekey"/>
|
||||
<input type="hidden" name="Brq_amount" t-att-value="Brq_amount"/>
|
||||
<input type="hidden" name="Brq_currency" t-att-value="Brq_currency"/>
|
||||
<input type="hidden" name="Brq_invoicenumber" t-att-value="Brq_invoicenumber"/>
|
||||
<input type="hidden" name="Brq_signature" t-att-value="Brq_signature"/>
|
||||
<input type="hidden" name="brq_test" t-att-value="brq_test"/>
|
||||
<input type="hidden" name="Brq_culture" t-att-value="Brq_culture"/>
|
||||
<!-- URLs -->
|
||||
<input t-if="Brq_return" type='hidden' name='Brq_return'
|
||||
t-att-value="Brq_return"/>
|
||||
<input t-if="Brq_returncancel" type='hidden' name='Brq_returncancel'
|
||||
t-att-value="Brq_returncancel"/>
|
||||
<input t-if="Brq_returnerror" type='hidden' name='Brq_returnerror'
|
||||
t-att-value="Brq_returnerror"/>
|
||||
<input t-if="Brq_returnreject" type='hidden' name='Brq_returnreject'
|
||||
t-att-value="Brq_returnreject"/>
|
||||
<input type='hidden' name='add_returndata' t-att-value="add_returndata"/>
|
||||
<!-- submit -->
|
||||
<button type="submit" width="100px"
|
||||
t-att-class="submit_class">
|
||||
<img t-if="not submit_txt" src="/payment_buckaroo/static/src/img/buckaroo_icon.png"/>
|
||||
<span t-if="submit_txt"><t t-esc="submit_txt"/> <span class="fa fa-long-arrow-right"/></span>
|
||||
</button>
|
||||
</form>
|
||||
<template id="buckaroo_form">
|
||||
<input type="hidden" name="data_set" t-att-data-action-url="tx_url" data-remove-me=""/>
|
||||
<input type="hidden" name="Brq_websitekey" t-att-value="Brq_websitekey"/>
|
||||
<input type="hidden" name="Brq_amount" t-att-value="Brq_amount"/>
|
||||
<input type="hidden" name="Brq_currency" t-att-value="Brq_currency"/>
|
||||
<input type="hidden" name="Brq_invoicenumber" t-att-value="Brq_invoicenumber"/>
|
||||
<input type="hidden" name="Brq_signature" t-att-value="Brq_signature"/>
|
||||
<input type="hidden" name="brq_test" t-att-value="brq_test"/>
|
||||
<input type="hidden" name="Brq_culture" t-att-value="Brq_culture"/>
|
||||
<!-- URLs -->
|
||||
<input t-if="Brq_return" type='hidden' name='Brq_return'
|
||||
t-att-value="Brq_return"/>
|
||||
<input t-if="Brq_returncancel" type='hidden' name='Brq_returncancel'
|
||||
t-att-value="Brq_returncancel"/>
|
||||
<input t-if="Brq_returnerror" type='hidden' name='Brq_returnerror'
|
||||
t-att-value="Brq_returnerror"/>
|
||||
<input t-if="Brq_returnreject" type='hidden' name='Brq_returnreject'
|
||||
t-att-value="Brq_returnreject"/>
|
||||
<input type='hidden' name='add_returndata' t-att-value="add_returndata"/>
|
||||
</template>
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<field name="image" type="base64" file="payment_ogone/static/src/img/ogone_icon.png"/>
|
||||
<field name="provider">ogone</field>
|
||||
<field name="company_id" ref="base.main_company"/>
|
||||
<field name="view_template_id" ref="ogone_acquirer_button"/>
|
||||
<field name="view_template_id" ref="ogone_form"/>
|
||||
<field name="registration_view_template_id" ref="ogone_s2s_form"/>
|
||||
<field name="environment">test</field>
|
||||
<field name="pre_msg"><![CDATA[
|
||||
|
||||
@@ -1,56 +1,38 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
|
||||
<template id="ogone_acquirer_button">
|
||||
<form t-if="acquirer" t-att-action="tx_url" method="post" target="_self">
|
||||
<!-- seller -->
|
||||
<input type='hidden' name='PSPID' t-att-value='PSPID'/>
|
||||
<input type='hidden' name='ORDERID' t-att-value='ORDERID'/>
|
||||
<!-- cart -->
|
||||
<input type='hidden' name='AMOUNT' t-att-value='AMOUNT or "0.0"'/>
|
||||
<input type='hidden' name='CURRENCY' t-att-value='CURRENCY'/>
|
||||
<!-- buyer -->
|
||||
<input type='hidden' name='LANGUAGE' t-att-value='LANGUAGE'/>
|
||||
<input type='hidden' name='CN' t-att-value='CN'/>
|
||||
<input type='hidden' name='EMAIL' t-att-value='EMAIL'/>
|
||||
<input type='hidden' name='OWNERZIP' t-att-value='OWNERZIP'/>
|
||||
<input type='hidden' name='OWNERADDRESS' t-att-value='OWNERADDRESS'/>
|
||||
<input type='hidden' name='OWNERCTY' t-att-value='OWNERCTY'/>
|
||||
<input type='hidden' name='OWNERTOWN' t-att-value='OWNERTOWN'/>
|
||||
<input type='hidden' name='OWNERTELNO' t-att-value='OWNERTELNO'/>
|
||||
<t t-if="acquirer.save_token in ['ask', 'always']">
|
||||
<input type='hidden' name='ALIAS' t-att-value='ALIAS'/>
|
||||
<input type='hidden' name='ALIASUSAGE' t-att-value='ALIASUSAGE'/>
|
||||
</t>
|
||||
<!-- before payment verification -->
|
||||
<input type='hidden' name='SHASIGN' t-att-value='SHASIGN'/>
|
||||
<!-- look and print -->
|
||||
<!-- <input type='hidden' name='TITLE' t-att-value='tx_dict["currency_name"]'/>
|
||||
<input type='hidden' name='BGCOLOR' t-att-value='tx_dict["currency_name"]'/>
|
||||
<input type='hidden' name='TXTCOLOR' t-att-value='tx_dict["currency_name"]'/>
|
||||
<input type='hidden' name='TBLBGCOLOR' t-att-value='tx_dict["currency_name"]'/>
|
||||
<input type='hidden' name='TBLTXTCOLOR' t-att-value='tx_dict["currency_name"]'/>
|
||||
<input type='hidden' name='BUTTONBGCOLOR' t-att-value='tx_dict["currency_name"]'/>
|
||||
<input type='hidden' name='BUTTONTXTCOLOR' t-att-value='tx_dict["currency_name"]'/>
|
||||
<input type='hidden' name='LOGO' t-att-value='tx_dict["currency_name"]'/>
|
||||
<input type='hidden' name='FONTTYPE' t-att-value='tx_dict["currency_name"]'/> -->
|
||||
<!-- after payment parameters -->
|
||||
<t t-if='PARAMPLUS'>
|
||||
<input type='hidden' name="PARAMPLUS" t-att-value='PARAMPLUS'/>
|
||||
</t>
|
||||
<!-- redirection -->
|
||||
<input type='hidden' name='ACCEPTURL' t-att-value='ACCEPTURL'/>
|
||||
<input type='hidden' name='DECLINEURL' t-att-value='DECLINEURL'/>
|
||||
<input type='hidden' name='EXCEPTIONURL' t-att-value='EXCEPTIONURL'/>
|
||||
<input type='hidden' name='CANCELURL' t-att-value='CANCELURL'/>
|
||||
<!-- submit -->
|
||||
<button type="submit" width="100px"
|
||||
t-att-class="submit_class">
|
||||
<img t-if="not submit_txt" src="/payment_ogone/static/src/img/ogone_icon.png"/>
|
||||
<span t-if="submit_txt"><t t-esc="submit_txt"/> <span class="fa fa-long-arrow-right"/></span>
|
||||
</button>
|
||||
</form>
|
||||
<template id="ogone_form">
|
||||
<input type="hidden" name="data_set" t-att-data-action-url="tx_url" data-remove-me=""/>
|
||||
<!-- seller -->
|
||||
<input type='hidden' name='PSPID' t-att-value='PSPID'/>
|
||||
<input type='hidden' name='ORDERID' t-att-value='ORDERID'/>
|
||||
<!-- cart -->
|
||||
<input type='hidden' name='AMOUNT' t-att-value='AMOUNT or "0.0"'/>
|
||||
<input type='hidden' name='CURRENCY' t-att-value='CURRENCY'/>
|
||||
<!-- buyer -->
|
||||
<input type='hidden' name='LANGUAGE' t-att-value='LANGUAGE'/>
|
||||
<input type='hidden' name='CN' t-att-value='CN'/>
|
||||
<input type='hidden' name='EMAIL' t-att-value='EMAIL'/>
|
||||
<input type='hidden' name='OWNERZIP' t-att-value='OWNERZIP'/>
|
||||
<input type='hidden' name='OWNERADDRESS' t-att-value='OWNERADDRESS'/>
|
||||
<input type='hidden' name='OWNERCTY' t-att-value='OWNERCTY'/>
|
||||
<input type='hidden' name='OWNERTOWN' t-att-value='OWNERTOWN'/>
|
||||
<input type='hidden' name='OWNERTELNO' t-att-value='OWNERTELNO'/>
|
||||
<t t-if="acquirer.save_token in ['ask', 'always']">
|
||||
<input type='hidden' name='ALIAS' t-att-value='ALIAS'/>
|
||||
<input type='hidden' name='ALIASUSAGE' t-att-value='ALIASUSAGE'/>
|
||||
</t>
|
||||
<!-- before payment verification -->
|
||||
<input type='hidden' name='SHASIGN' t-att-value='SHASIGN'/>
|
||||
<!-- after payment parameters -->
|
||||
<t t-if='PARAMPLUS'>
|
||||
<input type='hidden' name="PARAMPLUS" t-att-value='PARAMPLUS'/>
|
||||
</t>
|
||||
<!-- redirection -->
|
||||
<input type='hidden' name='ACCEPTURL' t-att-value='ACCEPTURL'/>
|
||||
<input type='hidden' name='DECLINEURL' t-att-value='DECLINEURL'/>
|
||||
<input type='hidden' name='EXCEPTIONURL' t-att-value='EXCEPTIONURL'/>
|
||||
<input type='hidden' name='CANCELURL' t-att-value='CANCELURL'/>
|
||||
</template>
|
||||
|
||||
<template id="ogone_s2s_form">
|
||||
@@ -60,19 +42,19 @@
|
||||
<input t-if="partner_id" type="hidden" name="partner_id" t-att-value="partner_id"/>
|
||||
<div class="mt8">
|
||||
<div t-att-class="'form-group col-md-12' if bootstrap_formatting else 'form-group'">
|
||||
<input type="tel" name="cc_number" id="cc_number" class="form-control" placeholder="Card number"/>
|
||||
<input type="tel" name="cc_number" id="cc_number" class="form-control" placeholder="Card number" data-is-required="true"/>
|
||||
<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-5' if bootstrap_formatting else 'form-group'">
|
||||
<input type="text" name="cc_holder_name" id="cc_holder_name" class="form-control" placeholder="Cardholder name"/>
|
||||
<input type="text" name="cc_holder_name" id="cc_holder_name" class="form-control" placeholder="Cardholder name" data-is-required="true"/>
|
||||
</div>
|
||||
<div t-att-class="'form-group col-md-3' if bootstrap_formatting else 'form-group'">
|
||||
<input type="text" name="cc_expiry" id="cc_expiry" class="form-control" maxlength="7" placeholder="Expires (MM / YY)"/>
|
||||
<input type="text" name="cc_expiry" id="cc_expiry" class="form-control" maxlength="7" placeholder="Expires (MM / YY)" data-is-required="true"/>
|
||||
</div>
|
||||
<div t-att-class="'form-group col-md-4' if bootstrap_formatting else 'form-group'">
|
||||
<input type="text" name="cc_cvc" id="cc_cvc" class="form-control" maxlength="4" placeholder="CVC"/>
|
||||
<input type="text" name="cc_cvc" id="cc_cvc" class="form-control" maxlength="4" placeholder="CVC" data-is-required="true"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<field name="image" type="base64" file="payment_paypal/static/src/img/paypal_icon.png"/>
|
||||
<field name="provider">paypal</field>
|
||||
<field name="company_id" ref="base.main_company"/>
|
||||
<field name="view_template_id" ref="paypal_acquirer_button"/>
|
||||
<field name="view_template_id" ref="paypal_form"/>
|
||||
<field name="environment">test</field>
|
||||
<field name="pre_msg"><![CDATA[
|
||||
<p>You will be redirected to the Paypal website after clicking on the payment button.</p>]]></field>
|
||||
|
||||
@@ -68,9 +68,12 @@ class PaypalForm(PaypalCommon):
|
||||
|
||||
# check form result
|
||||
tree = objectify.fromstring(res)
|
||||
self.assertEqual(tree.get('action'), 'https://www.sandbox.paypal.com/cgi-bin/webscr', 'paypal: wrong form POST url')
|
||||
|
||||
data_set = tree.xpath("//input[@name='data_set']")
|
||||
self.assertEqual(len(data_set), 1, 'paypal: Found %d "data_set" input instead of 1' % len(data_set))
|
||||
self.assertEqual(data_set[0].get('data-action-url'), 'https://www.sandbox.paypal.com/cgi-bin/webscr', 'paypal: wrong form POST url')
|
||||
for form_input in tree.input:
|
||||
if form_input.get('name') in ['submit']:
|
||||
if form_input.get('name') in ['submit', 'data_set']:
|
||||
continue
|
||||
self.assertEqual(
|
||||
form_input.get('value'),
|
||||
@@ -99,7 +102,10 @@ class PaypalForm(PaypalCommon):
|
||||
# check form result
|
||||
handling_found = False
|
||||
tree = objectify.fromstring(res)
|
||||
self.assertEqual(tree.get('action'), 'https://www.sandbox.paypal.com/cgi-bin/webscr', 'paypal: wrong form POST url')
|
||||
|
||||
data_set = tree.xpath("//input[@name='data_set']")
|
||||
self.assertEqual(len(data_set), 1, 'paypal: Found %d "data_set" input instead of 1' % len(data_set))
|
||||
self.assertEqual(data_set[0].get('data-action-url'), 'https://www.sandbox.paypal.com/cgi-bin/webscr', 'paypal: wrong form POST url')
|
||||
for form_input in tree.input:
|
||||
if form_input.get('name') in ['handling']:
|
||||
handling_found = True
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
|
||||
<template id="paypal_acquirer_button">
|
||||
<form t-if="acquirer.paypal_email_account" t-att-action="tx_url" method="post" target="_self">
|
||||
<template id="paypal_form">
|
||||
<div>
|
||||
<input type="hidden" name="data_set" t-att-data-action-url="tx_url" data-remove-me=""/>
|
||||
<input type="hidden" name="cmd" t-att-value="cmd"/>
|
||||
<input type="hidden" name="business" t-att-value="business"/>
|
||||
<input type="hidden" name="item_name" t-att-value="item_name"/>
|
||||
@@ -32,14 +32,7 @@
|
||||
t-att-value="notify_url"/>
|
||||
<input t-if="cancel_return" type="hidden" name="cancel_return"
|
||||
t-att-value="cancel_return"/>
|
||||
<!-- submit -->
|
||||
<button type="submit" width="100px"
|
||||
t-att-class="submit_class">
|
||||
<img t-if="not submit_txt" src="/payment_paypal/static/src/img/paypal_icon.png"/>
|
||||
<span t-if="submit_txt"><t t-esc="submit_txt"/> <span class="fa fa-long-arrow-right"/></span>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<field name="image" type="base64" file="payment_payumoney/static/src/img/payumoney_icon.png"/>
|
||||
<field name="provider">payumoney</field>
|
||||
<field name="company_id" ref="base.main_company"/>
|
||||
<field name="view_template_id" ref="payumoney_acquirer_button"/>
|
||||
<field name="view_template_id" ref="payumoney_form"/>
|
||||
<field name="environment">test</field>
|
||||
<field name="pre_msg"><![CDATA[
|
||||
<p>You will be redirected to the PayUmoney website after clicking on the payment button.</p>]]>
|
||||
|
||||
@@ -1,25 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<template id="payumoney_acquirer_button">
|
||||
<form t-if="acquirer.payumoney_merchant_key" t-att-action="tx_url" method="post" target="_self">
|
||||
<input type="hidden" name="key" t-att-value='key' />
|
||||
<input type="hidden" name="txnid" t-att-value='txnid' />
|
||||
<input type="hidden" name="amount" t-att-value='amount' />
|
||||
<input type="hidden" name="productinfo" t-att-value='productinfo' />
|
||||
<input type="hidden" name="firstname" t-att-value='firstname' />
|
||||
<input type="hidden" name="email" t-att-value='email' />
|
||||
<input type="hidden" name="phone" t-att-value='phone'/>
|
||||
<input type="hidden" name="service_provider" t-att-value='service_provider' />
|
||||
<input type="hidden" name="hash" t-att-value='hash' />
|
||||
<input type="hidden" name="surl" t-att-value='surl' />
|
||||
<input type="hidden" name="furl" t-att-value='furl' />
|
||||
<input type="hidden" name="curl" t-att-value='curl' />
|
||||
<input type="hidden" name="udf1" t-att-value='udf1'/>
|
||||
<!-- submit -->
|
||||
<button type="submit" width="100px" t-att-class="submit_class">
|
||||
<img t-if="not submit_txt" src="/payment_payumoney/static/src/img/payumoney_icon.png"/>
|
||||
<span t-if="submit_txt"><t t-esc="submit_txt"/> <span class="fa fa-long-arrow-right"/></span>
|
||||
</button>
|
||||
</form>
|
||||
<template id="payumoney_form">
|
||||
<input type="hidden" name="data_set" t-att-data-action-url="tx_url" data-remove-me=""/>
|
||||
<input type="hidden" name="key" t-att-value='key' />
|
||||
<input type="hidden" name="txnid" t-att-value='txnid' />
|
||||
<input type="hidden" name="amount" t-att-value='amount' />
|
||||
<input type="hidden" name="productinfo" t-att-value='productinfo' />
|
||||
<input type="hidden" name="firstname" t-att-value='firstname' />
|
||||
<input type="hidden" name="email" t-att-value='email' />
|
||||
<input type="hidden" name="phone" t-att-value='phone'/>
|
||||
<input type="hidden" name="service_provider" t-att-value='service_provider' />
|
||||
<input type="hidden" name="hash" t-att-value='hash' />
|
||||
<input type="hidden" name="surl" t-att-value='surl' />
|
||||
<input type="hidden" name="furl" t-att-value='furl' />
|
||||
<input type="hidden" name="curl" t-att-value='curl' />
|
||||
<input type="hidden" name="udf1" t-att-value='udf1'/>
|
||||
</template>
|
||||
</odoo>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<field name="image" type="base64" file="payment_sips/static/src/img/sips_icon.png"/>
|
||||
<field name="provider">sips</field>
|
||||
<field name="company_id" ref="base.main_company"/>
|
||||
<field name="view_template_id" ref="payment_sips.sips_acquirer_button"/>
|
||||
<field name="view_template_id" ref="payment_sips.sips_form"/>
|
||||
<field name="environment">test</field>
|
||||
<field name="pre_msg"><![CDATA[
|
||||
<p>You will be redirected to the Sips website after clicking on payment button.</p>]]></field>
|
||||
|
||||
@@ -1,20 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data noupdate="0">
|
||||
|
||||
<template id="sips_acquirer_button">
|
||||
<form t-att-action="tx_url" method="post" target="_self">
|
||||
<input type="hidden" name="Data" t-att-value="Data"/>
|
||||
<input type="hidden" name="InterfaceVersion" t-att-value="InterfaceVersion"/>
|
||||
<input type="hidden" name="Seal" t-att-value="Seal"/>
|
||||
<!-- submit -->
|
||||
<button type="submit" width="100px"
|
||||
t-att-class="submit_class">
|
||||
<img t-if="not submit_txt" src="/payment_sips/static/src/img/sips_icon.png"/>
|
||||
<span t-if="submit_txt"><t t-esc="submit_txt"/> <span class="fa fa-long-arrow-right"/></span>
|
||||
</button>
|
||||
</form>
|
||||
<template id="sips_form">
|
||||
<input type="hidden" name="data_set" t-att-data-action-url="tx_url" data-remove-me=""/>
|
||||
<input type="hidden" name="Data" t-att-value="Data"/>
|
||||
<input type="hidden" name="InterfaceVersion" t-att-value="InterfaceVersion"/>
|
||||
<input type="hidden" name="Seal" t-att-value="Seal"/>
|
||||
</template>
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<field name="image" type="base64" file="payment_stripe/static/src/img/stripe_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="view_template_id" ref="stripe_form"/>
|
||||
<field name="registration_view_template_id" ref="stripe_s2s_form"/>
|
||||
<field name="environment">test</field>
|
||||
<field name="pre_msg"><![CDATA[
|
||||
|
||||
@@ -17,9 +17,9 @@ STRIPE_HEADERS = {'Stripe-Version': '2016-03-07'}
|
||||
|
||||
# The following currencies are integer only, see https://stripe.com/docs/currencies#zero-decimal
|
||||
INT_CURRENCIES = [
|
||||
u'BIF', u'XAF', u'XPF', u'CLP', u'KMF', u'DJF', u'GNF', u'JPY', u'MGA', u'PYGí', u'RWF', u'KRW',
|
||||
u'BIF', u'XAF', u'XPF', u'CLP', u'KMF', u'DJF', u'GNF', u'JPY', u'MGA', u'PYG', u'RWF', u'KRW',
|
||||
u'VUV', u'VND', u'XOF'
|
||||
];
|
||||
]
|
||||
|
||||
|
||||
class PaymentAcquirerStripe(models.Model):
|
||||
|
||||
@@ -10,100 +10,124 @@ odoo.define('payment_stripe.stripe', function(require) {
|
||||
// The following currencies are integer only, see
|
||||
// https://stripe.com/docs/currencies#zero-decimal
|
||||
var int_currencies = [
|
||||
'BIF', 'XAF', 'XPF', 'CLP', 'KMF', 'DJF', 'GNF', 'JPY', 'MGA', 'PYGí',
|
||||
'BIF', 'XAF', 'XPF', 'CLP', 'KMF', 'DJF', 'GNF', 'JPY', 'MGA', 'PYG',
|
||||
'RWF', 'KRW', 'VUV', 'VND', 'XOF'
|
||||
];
|
||||
|
||||
var handler = StripeCheckout.configure({
|
||||
key: $("input[name='stripe_key']").val(),
|
||||
image: $("input[name='stripe_image']").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;
|
||||
}).fail(function(){
|
||||
var msg = arguments && arguments[1] && arguments[1].data && arguments[1].data.message;
|
||||
var wizard = $(qweb.render('stripe.error', {'msg': msg || _t('Payment error')}));
|
||||
wizard.appendTo($('body')).modal({'keyboard': true});
|
||||
});
|
||||
},
|
||||
});
|
||||
function getStripeHandler(parentElement)
|
||||
{
|
||||
var handler = StripeCheckout.configure({
|
||||
key: $("input[name='stripe_key']", parentElement).val(),
|
||||
image: $("input[name='stripe_image']", parentElement).val(),
|
||||
locale: 'auto',
|
||||
token: function(token, args) {
|
||||
handler.isTokenGenerate = true;
|
||||
ajax.jsonRpc("/payment/stripe/create_charge", 'call', {
|
||||
tokenid: token.id,
|
||||
email: token.email,
|
||||
amount: $("input[name='amount']", parentElement).val(),
|
||||
acquirer_id: $("#acquirer_stripe", parentElement).val(),
|
||||
currency: $("input[name='currency']", parentElement).val(),
|
||||
invoice_num: $("input[name='invoice_num']", parentElement).val(),
|
||||
return_url: $("input[name='return_url']", parentElement).val()
|
||||
}).done(function(data){
|
||||
handler.isTokenGenerate = false;
|
||||
window.location.href = data;
|
||||
}).fail(function(){
|
||||
var msg = arguments && arguments[1] && arguments[1].data && arguments[1].data.message;
|
||||
var wizard = $(qweb.render('stripe.error', {'msg': msg || _t('Payment error')}));
|
||||
wizard.appendTo($('body')).modal({'keyboard': true});
|
||||
});
|
||||
},
|
||||
});
|
||||
return handler;
|
||||
}
|
||||
|
||||
$('#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');
|
||||
|
||||
var $form = $(e.currentTarget).parents('form');
|
||||
var acquirer_id = $(e.currentTarget).closest('div.o_payment_acquirer_button,div.oe_quote_acquirer_button,div.o_website_payment_new_payment');
|
||||
acquirer_id = acquirer_id.data('id') || acquirer_id.data('acquirer_id');
|
||||
if (! acquirer_id) {
|
||||
return false;
|
||||
$(document).ready(function (){
|
||||
if (!$('.o_payment_form').length) {
|
||||
return $.Deferred().reject("DOM doesn't contain '.o_payment_form'");
|
||||
}
|
||||
|
||||
var access_token = $("input[name='token']").val();
|
||||
var so_id = $("input[name='return_url']").val().match(/quote\/([0-9]+)/) || undefined;
|
||||
if (so_id) {
|
||||
so_id = parseInt(so_id[1]);
|
||||
}
|
||||
$('#o_payment_form_pay').on('click', function(ev){
|
||||
// we retrieve the payment form
|
||||
var parent_form = ev.target.form;
|
||||
// then the checked radio
|
||||
var checked_radio = $('input[type="radio"]:checked', parent_form);
|
||||
// check if there's one checked radio
|
||||
if(checked_radio.length != 1) {
|
||||
return;
|
||||
}
|
||||
// if there's a checked radio, we retrieve the usefull data
|
||||
var acquirer_id = checked_radio.data('acquirerId');
|
||||
var provider = checked_radio.data('provider');
|
||||
var is_form_payment = checked_radio.data('form-payment') === "True";
|
||||
// now we check if the user has clicked on stripe radio button and wants to pay via the checkout form
|
||||
if(provider != "stripe" || is_form_payment !== true) {
|
||||
return;
|
||||
}
|
||||
// from here we retrieve the inputs that contains the data we need
|
||||
var provider_form = $("#o_payment_form_acq_" + acquirer_id, parent_form);
|
||||
|
||||
e.preventDefault();
|
||||
if ($('.o_website_payment').length !== 0) {
|
||||
var currency = $("input[name='currency']").val();
|
||||
var amount = parseFloat($("input[name='amount']").val() || '0.0');
|
||||
if (!_.contains(int_currencies, currency)) {
|
||||
amount = amount*100;
|
||||
var so_id = $("input[name='return_url']", provider_form).val().match(/quote\/([0-9]+)/) || undefined;
|
||||
var access_token = $("input[name='return_url']", provider_form).val().match(/quote\/([0-9]+)\/([0-9a-zA-Z\-]+)/) || undefined;
|
||||
if (so_id) {
|
||||
so_id = parseInt(so_id[1]);
|
||||
}
|
||||
if(access_token) {
|
||||
access_token = access_token[2];
|
||||
}
|
||||
|
||||
ajax.jsonRpc('/website_payment/transaction', 'call', {
|
||||
reference: $("input[name='invoice_num']").val(),
|
||||
amount: amount,
|
||||
currency_id: currency,
|
||||
acquirer_id: acquirer_id
|
||||
})
|
||||
handler.open({
|
||||
name: $("input[name='merchant']").val(),
|
||||
description: $("input[name='invoice_num']").val(),
|
||||
currency: currency,
|
||||
amount: amount,
|
||||
});
|
||||
} else {
|
||||
var currency = $("input[name='currency']").val();
|
||||
var amount = parseFloat($("input[name='amount']").val() || '0.0');
|
||||
if (!_.contains(int_currencies, currency)) {
|
||||
amount = amount*100;
|
||||
}
|
||||
if ($('.o_website_payment').length !== 0) {
|
||||
var currency = $("input[name='currency']", provider_form).val();
|
||||
var amount = parseFloat($("input[name='amount']", provider_form).val() || '0.0');
|
||||
if (!_.contains(int_currencies, currency)) {
|
||||
amount = amount*100;
|
||||
}
|
||||
|
||||
ajax.jsonRpc('/shop/payment/transaction/' + acquirer_id, 'call', {
|
||||
so_id: so_id,
|
||||
access_token: access_token
|
||||
}, {'async': false}).then(function (data) {
|
||||
$form.html(data);
|
||||
handler.open({
|
||||
name: $("input[name='merchant']").val(),
|
||||
description: $("input[name='invoice_num']").val(),
|
||||
currency: currency,
|
||||
amount: amount,
|
||||
ajax.jsonRpc('/website_payment/transaction', 'call', {
|
||||
reference: $("input[name='invoice_num']", provider_form).val(),
|
||||
amount: amount,
|
||||
currency_id: currency,
|
||||
acquirer_id: acquirer_id
|
||||
})
|
||||
var handler = getStripeHandler(provider_form);
|
||||
handler.open({
|
||||
name: $("input[name='merchant']", provider_form).val(),
|
||||
description: $("input[name='invoice_num']", provider_form).val(),
|
||||
currency: currency,
|
||||
amount: amount,
|
||||
});
|
||||
} else {
|
||||
var currency = $("input[name='currency']", provider_form).val();
|
||||
var amount = parseFloat($("input[name='amount']", provider_form).val() || '0.0');
|
||||
if (!_.contains(int_currencies, currency)) {
|
||||
amount = amount*100;
|
||||
}
|
||||
|
||||
var url = '/shop/payment/transaction/';
|
||||
if(so_id) {
|
||||
url += so_id + '/';
|
||||
if(access_token) {
|
||||
url += access_token;
|
||||
}
|
||||
}
|
||||
|
||||
ajax.jsonRpc(url, 'call', {
|
||||
acquirer_id: acquirer_id
|
||||
}, {'async': false}).then(function (data) {
|
||||
try {
|
||||
provider_form.html(data);
|
||||
}
|
||||
catch(err) { } // here it will catch an error saying that payment_stripe.stripe is already started
|
||||
var handler = getStripeHandler(provider_form);
|
||||
handler.open({
|
||||
name: $("input[name='merchant']", provider_form).val(),
|
||||
description: $("input[name='invoice_num']", provider_form).val(),
|
||||
currency: currency,
|
||||
amount: amount,
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,53 +1,47 @@
|
||||
<?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='stripe_image' t-att-value="acquirer.stripe_image_url"/>
|
||||
<input type='hidden' name='merchant' t-att-value='acquirer.company_id.name'/>
|
||||
<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'/>
|
||||
<input type='hidden' name='currency_id' t-att-value='currency_id'/>
|
||||
<!-- 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 id="stripe_form">
|
||||
<input type="hidden" name="data_set" t-att-data-action-url="tx_url" data-remove-me=""/>
|
||||
<script src="https://checkout.stripe.com/checkout.js"></script>
|
||||
<input type='hidden' name='stripe_image' t-att-value="acquirer.stripe_image_url"/>
|
||||
<input type='hidden' name='merchant' t-att-value='acquirer.company_id.name'/>
|
||||
<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'/>
|
||||
<input type='hidden' name='currency_id' t-att-value='currency_id'/>
|
||||
<!-- 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"/>
|
||||
<script type="text/javascript" src="/payment_stripe/static/src/js/stripe.js"></script>
|
||||
</template>
|
||||
|
||||
<template id="stripe_s2s_form">
|
||||
<input type="hidden" name="data_set" data-create-route="/payment/stripe/s2s/create_json_3ds"/>
|
||||
<div class="mt8">
|
||||
<div t-att-class="'form-group col-md-12' if bootstrap_formatting else 'form-group'">
|
||||
<input type="tel" name="cc_number" id="cc_number" class="form-control" placeholder="Card number"/>
|
||||
<input type="tel" name="cc_number" id="cc_number" class="form-control" placeholder="Card number" data-is-required="true"/>
|
||||
<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-5' if bootstrap_formatting else 'form-group'">
|
||||
<input type="text" name="cc_holder_name" id="cc_holder_name" class="form-control" placeholder="Cardholder name"/>
|
||||
<input type="text" name="cc_holder_name" id="cc_holder_name" class="form-control" placeholder="Cardholder name" data-is-required="true"/>
|
||||
</div>
|
||||
<div t-att-class="'form-group col-md-3' if bootstrap_formatting else 'form-group'">
|
||||
<input type="text" name="cc_expiry" id="cc_expiry" class="form-control" maxlength="7" placeholder="Expires (MM / YY)"/>
|
||||
<input type="text" name="cc_expiry" id="cc_expiry" class="form-control" maxlength="7" placeholder="Expires (MM / YY)" data-is-required="true"/>
|
||||
</div>
|
||||
<div t-att-class="'form-group col-md-4' if bootstrap_formatting else 'form-group'">
|
||||
<input type="text" name="cvc" id="cvc" class="form-control" maxlength="4" placeholder="CVC"/>
|
||||
<input type="text" name="cvc" id="cvc" class="form-control" maxlength="4" placeholder="CVC" data-is-required="true"/>
|
||||
</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"/>
|
||||
@@ -56,11 +50,5 @@
|
||||
<div class="clearfix"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id="payment_stripe_redirect" name="Payment Stripe">
|
||||
<script type="text/javascript">
|
||||
window.location.href = '<t t-esc="return_url"/>';
|
||||
</script>
|
||||
</template>
|
||||
</data>
|
||||
</odoo>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<field name="image" type="base64" file="payment_transfer/static/src/img/transfer_icon.png"/>
|
||||
<field name="provider">transfer</field>
|
||||
<field name="company_id" ref="base.main_company"/>
|
||||
<field name="view_template_id" ref="transfer_acquirer_button"/>
|
||||
<field name="view_template_id" ref="transfer_form"/>
|
||||
<field name="environment">test</field>
|
||||
<field name="website_published" eval="True"/>
|
||||
<field name="pre_msg"><![CDATA[
|
||||
|
||||
@@ -1,23 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
|
||||
<template id="transfer_acquirer_button">
|
||||
<form t-if="acquirer" t-att-action="tx_url" method="post" target="_self">
|
||||
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
|
||||
<t t-if="return_url">
|
||||
<input type='hidden' name='return_url' t-att-value='return_url'/>
|
||||
</t>
|
||||
<input type='hidden' name='reference' t-att-value='reference'/>
|
||||
<input type='hidden' name='amount' t-att-value='amount'/>
|
||||
<input type='hidden' name='currency' t-att-value='currency.name'/>
|
||||
<!-- submit -->
|
||||
<button type="submit" width="100px" t-att-class="submit_class">
|
||||
<img t-if="not submit_txt" src="/payment_transfer/static/src/img/transfer_icon.png"/>
|
||||
<span t-if="submit_txt"><t t-esc="submit_txt"/> <span class="fa fa-long-arrow-right"/></span>
|
||||
</button>
|
||||
</form>
|
||||
<template id="transfer_form">
|
||||
<input type="hidden" name="data_set" t-att-data-action-url="tx_url" data-remove-me=""/>
|
||||
<t t-if="return_url">
|
||||
<input type='hidden' name='return_url' t-att-value='return_url'/>
|
||||
</t>
|
||||
<input type='hidden' name='reference' t-att-value='reference'/>
|
||||
<input type='hidden' name='amount' t-att-value='amount'/>
|
||||
<input type='hidden' name='currency' t-att-value='currency.name'/>
|
||||
</template>
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
|
||||
@@ -128,7 +128,7 @@ class PaymentTransaction(models.Model):
|
||||
if (self and acquirer and self.acquirer_id != acquirer) or (self and self.sale_order_id != order):
|
||||
tx = False
|
||||
# new or distinct token
|
||||
if payment_token and tx.payment_token_id and payment_token != self.payment_token_id:
|
||||
if tx and payment_token and tx.payment_token_id and payment_token != self.payment_token_id:
|
||||
tx = False
|
||||
|
||||
# still draft tx, no more info -> rewrite on tx or create a new one depending on parameter
|
||||
|
||||
@@ -81,12 +81,13 @@ tour.register('event_buy_tickets', {
|
||||
},
|
||||
{
|
||||
content: "Select `Wire Transfer` payment method",
|
||||
trigger: '#payment_method label:contains(Wire Transfer) input',
|
||||
trigger: '#payment_method label:contains("Wire Transfer")',
|
||||
},
|
||||
{
|
||||
content: "Pay",
|
||||
extra_trigger: '#payment_method label:contains(Wire Transfer) input:checked',
|
||||
trigger: '.o_payment_acquirer_button .btn[type="submit"]:visible',
|
||||
//Either there are multiple payment methods, and one is checked, either there is only one, and therefore there are no radio inputs
|
||||
extra_trigger: '#payment_method label:contains("Wire Transfer") input:checked,#payment_method:not(:has("input:radio:visible"))',
|
||||
trigger: 'button[id="o_payment_form_pay"]:visible',
|
||||
},
|
||||
{
|
||||
content: "Last step",
|
||||
|
||||
@@ -8,5 +8,7 @@ class Website(models.Model):
|
||||
_inherit = "website"
|
||||
|
||||
@api.model
|
||||
def payment_acquirers(self):
|
||||
return list(self.env['payment.acquirer'].sudo().search([('website_published', '=', True)]))
|
||||
def payment_icons(self):
|
||||
""" This function returns the list of payment icons which are supported by payment acquirers that are published
|
||||
"""
|
||||
return self.env['payment.icon'].sudo().search([('acquirer_ids.website_published', '=', True)])
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<template id="header_footer_custom_payment" inherit_id="website.footer_default" customize_show="True" active="False" name="Payment Methods">
|
||||
<template id="header_footer_custom_payment" inherit_id="website.footer_default" customize_show="True" active="False" name="Payment Icons">
|
||||
<xpath expr="//div[@id='info']" position="inside">
|
||||
<h4 class="payment_method_title">Payment Methods</h4>
|
||||
<h4 class="payment_method_title">Payment Icons</h4>
|
||||
<ul class="payment_method_list list-inline">
|
||||
<t t-foreach="request.website.payment_acquirers()" t-as="acquirer">
|
||||
<t t-foreach="request.website.payment_icons()" t-as="icon">
|
||||
<li>
|
||||
<span t-field="acquirer.image_small" t-options='{"widget": "image", "alt-field": "name"}' />
|
||||
<span t-field="icon.image" t-options='{"widget": "image", "alt-field": "name"}' />
|
||||
</li>
|
||||
</t>
|
||||
</ul>
|
||||
|
||||
@@ -61,20 +61,22 @@ class sale_quote(http.Controller):
|
||||
'tx_post_msg': Transaction.acquirer_id.post_msg if Transaction else False,
|
||||
'need_payment': order_sudo.invoice_status == 'to invoice' and Transaction.state in ['draft', 'cancel', 'error'],
|
||||
'token': token,
|
||||
'return_url': '/shop/payment/validate',
|
||||
'bootstrap_formatting': True,
|
||||
'partner_id': order_sudo.partner_id.id,
|
||||
}
|
||||
|
||||
if order_sudo.require_payment or values['need_payment']:
|
||||
values['acquirers'] = list(request.env['payment.acquirer'].sudo().search([('website_published', '=', True), ('company_id', '=', order_sudo.company_id.id)]))
|
||||
extra_context = {
|
||||
'submit_class': 'btn btn-primary',
|
||||
'submit_txt': _('Pay & Confirm')
|
||||
}
|
||||
values['buttons'] = {}
|
||||
for acquirer in values['acquirers']:
|
||||
values['buttons'][acquirer.id] = acquirer.with_context(**extra_context).render(
|
||||
'/',
|
||||
order_sudo.amount_total,
|
||||
order_sudo.pricelist_id.currency_id.id,
|
||||
acquirers = request.env['payment.acquirer'].sudo().search([('website_published', '=', True), ('company_id', '=', order_sudo.company_id.id)])
|
||||
|
||||
values['form_acquirers'] = [acq for acq in acquirers if acq.payment_flow == 'form' and acq.view_template_id]
|
||||
values['s2s_acquirers'] = [acq for acq in acquirers if acq.payment_flow == 's2s' and acq.registration_view_template_id]
|
||||
values['pms'] = request.env['payment.token'].search(
|
||||
[('partner_id', '=', order_sudo.partner_id.id),
|
||||
('acquirer_id', 'in', [acq.id for acq in values['s2s_acquirers']])])
|
||||
|
||||
for acq in values['form_acquirers']:
|
||||
acq.form = acq.render('/', order_sudo.amount_total, order_sudo.pricelist_id.currency_id.id,
|
||||
values={
|
||||
'return_url': '/quote/%s/%s' % (order_id, token) if token else '/quote/%s' % order_id,
|
||||
'type': 'form',
|
||||
@@ -158,8 +160,8 @@ class sale_quote(http.Controller):
|
||||
return werkzeug.utils.redirect("/quote/%s/%s#pricing" % (Order.id, token))
|
||||
|
||||
# note dbo: website_sale code
|
||||
@http.route(['/quote/<int:order_id>/transaction/<int:acquirer_id>'], type='json', auth="public", website=True)
|
||||
def payment_transaction_token(self, acquirer_id, order_id, access_token=None, tx_type=None):
|
||||
@http.route(['/quote/<int:order_id>/transaction/'], type='json', auth="public", website=True)
|
||||
def payment_transaction_token(self, acquirer_id, order_id, save_token=False,access_token=None):
|
||||
""" Json method that creates a payment.transaction, used to create a
|
||||
transaction when the user clicks on 'pay now' button. After having
|
||||
created the transaction, the event continues and the user is redirected
|
||||
@@ -170,7 +172,7 @@ class sale_quote(http.Controller):
|
||||
"""
|
||||
order = request.env['sale.order'].sudo().browse(order_id)
|
||||
if not order or not order.order_line or acquirer_id is None:
|
||||
return request.redirect("/quote/%s" % order_id)
|
||||
return False
|
||||
|
||||
# find an already existing transaction
|
||||
acquirer = request.env['payment.acquirer'].browse(int(acquirer_id))
|
||||
@@ -189,3 +191,38 @@ class sale_quote(http.Controller):
|
||||
'type': order._get_payment_type(),
|
||||
'alias_usage': _('If we store your payment information on our server, subscription payments will be made automatically.'),
|
||||
})
|
||||
|
||||
@http.route('/quote/<int:order_id>/transaction/token', type='http', auth='public', website=True)
|
||||
def payment_token(self, order_id, pm_id=None, **kwargs):
|
||||
|
||||
order = request.env['sale.order'].sudo().browse(order_id)
|
||||
if not order or not order.order_line or pm_id is None:
|
||||
return request.redirect("/quote/%s" % order_id)
|
||||
|
||||
# try to convert pm_id into an integer, if it doesn't work redirect the user to the quote
|
||||
try:
|
||||
pm_id = int(pm_id)
|
||||
except ValueError:
|
||||
return request.redirect('/quote/%s' % order_id)
|
||||
|
||||
# retrieve the token from its id
|
||||
token = request.env['payment.token'].sudo().browse(pm_id)
|
||||
if not token:
|
||||
return request.redirect('/quote/%s' % order_id)
|
||||
|
||||
# find an already existing transaction
|
||||
tx = request.env['payment.transaction'].sudo().search([('reference', '=', order.name)], limit=1)
|
||||
# set the transaction type to server2server
|
||||
tx_type = 'server2server'
|
||||
# check if the transaction exists, if not then it create one
|
||||
tx = tx.check_or_create_sale_tx(order, token.acquirer_id, payment_token=token, tx_type=tx_type, add_tx_values={
|
||||
'callback_model_id': request.env['ir.model'].sudo().search([('model', '=', order._name)], limit=1).id,
|
||||
'callback_res_id': order.id,
|
||||
'callback_method': '_confirm_online_quote',
|
||||
})
|
||||
# set the transaction id into the session
|
||||
request.session['quote_%s_transaction_id' % order_id] = tx.id
|
||||
# proceed to the payment
|
||||
tx.confirm_sale_token()
|
||||
# redirect the user to the online quote
|
||||
return request.redirect('/quote/%s/%s' % (order_id, order.access_token))
|
||||
|
||||
@@ -306,7 +306,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<div t-if="not acquirers">
|
||||
<div t-if="not (pms or s2s_acquirers or form_acquirers)">
|
||||
<button type="submit" t-attf-class="btn btn-primary">Sign & Confirm</button>
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
|
||||
</div>
|
||||
@@ -327,48 +327,18 @@
|
||||
t-options='{"widget": "monetary", "display_currency": quotation.pricelist_id.currency_id}'/>
|
||||
<span>with payment terms: </span><b t-field="quotation.payment_term_id"/>.
|
||||
</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<!-- begin website_sale code -->
|
||||
<div t-if="acquirers" id="payment_method" class="row text-left">
|
||||
<div class="col-md-6">
|
||||
<h4>Payment Acquirer:</h4>
|
||||
<ul class="list-unstyled">
|
||||
<t t-set="payment_methods_available" t-value="False"/>
|
||||
<li t-foreach="acquirers or []" t-as="acquirer">
|
||||
<t t-if="not acquirer.country_ids or quotation and quotation.partner_id.country_id in acquirer.country_ids">
|
||||
<label t-if="buttons.get(acquirer.id)">
|
||||
<input t-att-value="acquirer.id" type="radio" name="acquirer" t-att-checked="acquirers[0] == acquirer"/>
|
||||
<img class="media-object" style="width: 60px; display: inline-block;"
|
||||
t-att-title="acquirer.name"
|
||||
t-att-src="'/payment_%s/static/src/img/%s_icon.png' % (acquirer.provider, acquirer.provider)"/>
|
||||
<span t-field="acquirer.name"/>
|
||||
</label>
|
||||
<t t-set="payment_methods_available" t-value="True"/>
|
||||
</t>
|
||||
</li>
|
||||
<li t-if="not payment_methods_available">
|
||||
<div class="alert alert-warning">
|
||||
<span>No payment gateway is available for your country</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<t t-foreach="acquirers or []" t-as="acquirer">
|
||||
<div class="o_payment_acquirer_button hidden pull-right"
|
||||
t-att-data-id="acquirer.id"
|
||||
t-att-data-access-token="token or ''"
|
||||
t-att-data-tx-type="form"
|
||||
t-att-data-call-url="'/quote/%s/transaction/%s' % (quotation.id, acquirer.id)">
|
||||
<div t-raw="buttons.get(acquirer.id)"/>
|
||||
<div t-field="acquirer.pre_msg"/>
|
||||
</div>
|
||||
</t>
|
||||
<button type="button" class="btn btn-link" data-dismiss="modal" style="padding: 0">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- end website_sale code -->
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<div t-if="pms or s2s_acquirers or form_acquirers" id="payment_method" class="text-left col-md-13">
|
||||
<h3 class="mb24">Pay with</h3>
|
||||
<t t-call="payment.payment_tokens_list">
|
||||
<t t-set="mode" t-value="'payment'"/>
|
||||
<t t-set="submit_txt" t-value="'Pay & Confirm'"/>
|
||||
<t t-set="icon_class" t-value="'fa-lock'"/>
|
||||
<t t-set="form_action" t-value="'/quote/' + str(quotation.id) + '/transaction/token'"/>
|
||||
<t t-set="prepare_tx_url" t-value="'/quote/' + str(quotation.id) + '/transaction/'"/>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -708,14 +708,22 @@ class WebsiteSale(http.Controller):
|
||||
partner=order.partner_id.id,
|
||||
order=order,
|
||||
payment_action_id=request.env.ref('payment.action_payment_acquirer').id,
|
||||
return_url= '/shop/payment/validate',
|
||||
bootstrap_formatting= True
|
||||
)
|
||||
|
||||
acquirers = request.env['payment.acquirer'].search(
|
||||
[('website_published', '=', True), ('company_id', '=', order.company_id.id)]
|
||||
)
|
||||
values['acquirers'] = []
|
||||
for acquirer in acquirers:
|
||||
acquirer_button = acquirer.with_context(submit_class='btn btn-primary', submit_txt=_('Pay Now')).sudo().render(
|
||||
|
||||
values['form_acquirers'] = [acq for acq in acquirers if acq.payment_flow == 'form' and acq.view_template_id]
|
||||
values['s2s_acquirers'] = [acq for acq in acquirers if acq.payment_flow == 's2s' and acq.registration_view_template_id]
|
||||
values['tokens'] = request.env['payment.token'].search(
|
||||
[('partner_id', '=', order.partner_id.id),
|
||||
('acquirer_id', 'in', [acq.id for acq in values['s2s_acquirers']])])
|
||||
|
||||
for acq in values['form_acquirers']:
|
||||
acq.form = acq.with_context(submit_class='btn btn-primary', submit_txt=_('Pay Now')).sudo().render(
|
||||
'/',
|
||||
order.amount_total,
|
||||
order.pricelist_id.currency_id.id,
|
||||
@@ -725,9 +733,6 @@ class WebsiteSale(http.Controller):
|
||||
'billing_partner_id': order.partner_invoice_id.id,
|
||||
}
|
||||
)
|
||||
acquirer.button = acquirer_button
|
||||
values['acquirers'].append(acquirer)
|
||||
values['tokens'] = request.env['payment.token'].search([('partner_id', '=', order.partner_id.id), ('acquirer_id', 'in', acquirers.ids)])
|
||||
|
||||
return values
|
||||
|
||||
@@ -776,8 +781,10 @@ class WebsiteSale(http.Controller):
|
||||
else:
|
||||
return request.redirect("/shop/payment?error=no_token_or_missmatch_tx")
|
||||
|
||||
@http.route(['/shop/payment/transaction/<int:acquirer_id>'], type='json', auth="public", website=True)
|
||||
def payment_transaction(self, acquirer_id, tx_type='form', token=None, **kwargs):
|
||||
@http.route(['/shop/payment/transaction/',
|
||||
'/shop/payment/transaction/<int:so_id>',
|
||||
'/shop/payment/transaction/<int:so_id>/<string:access_token>'], type='json', auth="public", website=True)
|
||||
def payment_transaction(self, acquirer_id, save_token=False, so_id=None, access_token=None, token=None, **kwargs):
|
||||
""" Json method that creates a payment.transaction, used to create a
|
||||
transaction when the user clicks on 'pay now' button. After having
|
||||
created the transaction, the event continues and the user is redirected
|
||||
@@ -786,10 +793,11 @@ class WebsiteSale(http.Controller):
|
||||
:param int acquirer_id: id of a payment.acquirer record. If not set the
|
||||
user is redirected to the checkout page
|
||||
"""
|
||||
tx_type = 'form'
|
||||
if save_token:
|
||||
tx_type = 'form_save'
|
||||
|
||||
# In case the route is called directly from the JS (as done in Stripe payment method)
|
||||
so_id = kwargs.get('so_id')
|
||||
access_token = kwargs.get('access_token')
|
||||
if so_id and access_token:
|
||||
order = request.env['sale.order'].sudo().search([('id', '=', so_id), ('access_token', '=', access_token)])
|
||||
elif so_id:
|
||||
@@ -797,7 +805,7 @@ class WebsiteSale(http.Controller):
|
||||
else:
|
||||
order = request.website.sale_get_order()
|
||||
if not order or not order.order_line or acquirer_id is None:
|
||||
return request.redirect("/shop/checkout")
|
||||
return False
|
||||
|
||||
assert order.partner_id.id != request.website.partner_id.id
|
||||
|
||||
@@ -808,11 +816,44 @@ class WebsiteSale(http.Controller):
|
||||
tx = tx.check_or_create_sale_tx(order, acquirer, payment_token=payment_token, tx_type=tx_type)
|
||||
request.session['sale_transaction_id'] = tx.id
|
||||
|
||||
if token:
|
||||
return request.env.ref('website_sale.payment_token_form').render(dict(tx=tx), engine='ir.qweb')
|
||||
|
||||
return tx.render_sale_button(order, '/shop/payment/validate')
|
||||
|
||||
@http.route('/shop/payment/token', type='http', auth='public', website=True)
|
||||
def payment_token(self, pm_id=None, **kwargs):
|
||||
""" Method that handles payment using saved tokens
|
||||
|
||||
:param int pm_id: id of the payment.token that we want to use to pay.
|
||||
"""
|
||||
order = request.website.sale_get_order()
|
||||
# do not crash if the user has already paid and try to pay again
|
||||
if not order:
|
||||
return request.redirect('/shop/?error=no_order')
|
||||
|
||||
assert order.partner_id.id != request.website.partner_id.id
|
||||
|
||||
try:
|
||||
pm_id = int(pm_id)
|
||||
except ValueError:
|
||||
return request.redirect('/shop/?error=invalid_token_id')
|
||||
|
||||
# We retrieve the token the user want to use to pay
|
||||
token = request.env['payment.token'].browse(pm_id)
|
||||
if not token:
|
||||
return request.redirect('/shop/?error=token_not_found')
|
||||
|
||||
# we retrieve an existing transaction (if it exists obviously)
|
||||
tx = request.website.sale_get_transaction() or request.env['payment.transaction'].sudo()
|
||||
# we check if the transaction is Ok, if not then we create it
|
||||
tx = tx.check_or_create_sale_tx(order, token.acquirer_id, payment_token=token, tx_type='server2server')
|
||||
# we set the transaction id into the session (so `sale_get_transaction` can retrieve it )
|
||||
request.session['sale_transaction_id'] = tx.id
|
||||
# we proceed the s2s payment
|
||||
res = tx.confirm_sale_token()
|
||||
# we then redirect to the page that validates the payment by giving it error if there's one
|
||||
if res is not True:
|
||||
return request.redirect('/shop/payment/validate?success=False&error=%s' % res)
|
||||
return request.redirect('/shop/payment/validate?success=True')
|
||||
|
||||
@http.route('/shop/payment/get_status/<int:sale_order_id>', type='json', auth="public", website=True)
|
||||
def payment_get_status(self, sale_order_id, **post):
|
||||
order = request.env['sale.order'].sudo().browse(sale_order_id).exists()
|
||||
|
||||
@@ -71,12 +71,13 @@ tour.register('shop_buy_product', {
|
||||
},
|
||||
{
|
||||
content: "select payment",
|
||||
trigger: '#payment_method label:contains("Wire Transfer") input',
|
||||
trigger: '#payment_method label:contains("Wire Transfer")',
|
||||
},
|
||||
{
|
||||
content: "Pay Now",
|
||||
extra_trigger: '#payment_method label:contains("Wire Transfer") input:checked',
|
||||
trigger: '.o_payment_acquirer_button .btn[type="submit"]:visible',
|
||||
//Either there are multiple payment methods, and one is checked, either there is only one, and therefore there are no radio inputs
|
||||
extra_trigger: '#payment_method label:contains("Wire Transfer") input:checked,#payment_method:not(:has("input:radio:visible"))',
|
||||
trigger: 'button[id="o_payment_form_pay"]:visible',
|
||||
},
|
||||
{
|
||||
content: "finish",
|
||||
|
||||
@@ -1324,71 +1324,26 @@
|
||||
</div>
|
||||
<div class="clearfix" />
|
||||
<div class="oe_structure" />
|
||||
<div class="js_payment mb64 col-md-12 row" t-if="acquirers and website_sale_order.amount_total" id="payment_method">
|
||||
<div class="col-lg-7 col-sm-8">
|
||||
<h4>Choose a payment acquirer</h4>
|
||||
<ul class="list-unstyled">
|
||||
<t t-set="payment_methods_available" t-value="False"/>
|
||||
<t t-set="partner_country" t-value="website_sale_order and website_sale_order.partner_invoice_id.country_id"/>
|
||||
<t t-foreach="acquirers or []" t-as="acquirer">
|
||||
<li t-if="not acquirer.country_ids or partner_country in acquirer.country_ids">
|
||||
<label t-if="acquirer.button">
|
||||
<input t-att-value="acquirer.id" type="radio" name="acquirer" t-att-checked="acquirers[0] == acquirer" />
|
||||
<span t-field="acquirer.image_small" t-att-title="acquirer.name" t-options='{"widget": "image", "style":"max-width: 60px; display: inline-block"}'/>
|
||||
<span t-field="acquirer.name" />
|
||||
<span t-if="acquirer.fees_active">(processing fees apply)</span>
|
||||
</label>
|
||||
<t t-set="payment_methods_available" t-value="True"/>
|
||||
</li>
|
||||
</t>
|
||||
<li t-if="not payment_methods_available">
|
||||
<div class="alert alert-warning">
|
||||
<span>No payment gateway is available for your country</span>
|
||||
</div>
|
||||
</li>
|
||||
<li t-if="any(token for token in tokens if not token.acquirer_id.country_ids or partner_country in token.acquirer_id.country_ids)">
|
||||
<label>
|
||||
<input type="radio" name="acquirer" />
|
||||
<span class='fa fa-2x fa-credit-card'/>
|
||||
Saved Cards
|
||||
</label>
|
||||
|
||||
<div class="list-group">
|
||||
<t t-foreach='tokens' t-as='token'>
|
||||
<a t-if="not token.acquirer_id.country_ids or partner_country in token.acquirer_id.country_ids" class="list-group-item btn_payment_token" t-att-data-acquirer="token.acquirer_id.id" t-att-data-token='token.id'>
|
||||
<span class="js_radio fa fa-circle-o"></span>&nbsp;
|
||||
<t t-esc="token.name" />
|
||||
<t t-if="len(set(tokens.mapped('acquirer_id')))>1">
|
||||
(<t t-esc='token.acquirer_id.name'/>)
|
||||
</t>
|
||||
<span t-if="token.acquirer_id.fees_active">(processing fees apply)</span>
|
||||
</a>
|
||||
</t>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<a class="btn btn-default btn-block"
|
||||
groups="base.group_system"
|
||||
t-attf-href="/web#return_label=Website&action=#{payment_action_id}">
|
||||
<div id="payment_method" class="mb64 col-md-12" t-if="(form_acquirers or s2s_acquirers or tokens) and website_sale_order.amount_total">
|
||||
<h3 class="mb24">Pay with </h3>
|
||||
<t t-call="payment.payment_tokens_list">
|
||||
<t t-set="mode" t-value="'payment'"/>
|
||||
<t t-set="submit_txt" t-value="'Pay Now'"/>
|
||||
<t t-set="icon_class" t-value="'fa-lock'"/>
|
||||
<t t-set="pms" t-value="tokens"/>
|
||||
<t t-set="form_action" t-value="'/shop/payment/token'"/>
|
||||
<t t-set="prepare_tx_url" t-value="'/shop/payment/transaction/'"/>
|
||||
<t t-set="partner_id" t-value="partner"/>
|
||||
</t>
|
||||
</div>
|
||||
|
||||
<div t-if="not (form_acquirers or s2s_acquirers)">
|
||||
<a class="btn btn-default btn-block"
|
||||
groups="base.group_system"
|
||||
t-attf-href="/web#return_label=Website&action=#{payment_action_id}">
|
||||
<i class="fa fa-plus-square" aria-hidden="true"></i> Configure payment acquirers
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-lg-5 col-sm-4 text-right">
|
||||
<t t-foreach="acquirers or []" t-as="acquirer" id="acquirers_list">
|
||||
<div class="o_payment_acquirer_button hidden pull-right"
|
||||
t-att-data-id="acquirer.id"
|
||||
t-att-data-call-url="'/shop/payment/transaction/%s' % (acquirer.id)">
|
||||
<div t-raw="acquirer.button" />
|
||||
<div class="token_hide">
|
||||
<div t-if="acquirer.save_token == 'ask'">
|
||||
<input type="checkbox" name="odoo_save_token" id="odoo_save_token"/>
|
||||
<label for="odoo_save_token">Save my payment data</label>
|
||||
</div>
|
||||
<div class="pre_msg" t-field="acquirer.pre_msg" />
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="js_payment mb64 row" t-if="not website_sale_order.amount_total" id="payment_method">
|
||||
<div class="col-sm-12">
|
||||
|
||||