[IMP] website_quote/sale,payment: Support of the new payment form
- Online quotation and e-commerce now use the new payment form. - Added the ability to chose on an acquirer if it uses only form/s2s or both. (Still need some code cleaning)
This commit is contained in:
@@ -8,7 +8,7 @@ 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), ('prefered_payment_type', 'in', ['s2s', 'both'])]))
|
||||
partner = request.env.user.partner_id
|
||||
payment_tokens = partner.payment_token_ids
|
||||
payment_tokens |= partner.commercial_partner_id.sudo().payment_token_ids
|
||||
|
||||
@@ -151,6 +151,15 @@ class PaymentAcquirer(models.Model):
|
||||
"Use this field anywhere a small image is required.")
|
||||
|
||||
payment_option_ids = fields.Many2many('payment.option', string='Supported Payment Option')
|
||||
prefered_payment_type = fields.Selection(selection=[('s2s','Server to server'),
|
||||
('form', 'Form'),
|
||||
('both', 'Both')
|
||||
], default='form', required=True, string='Prefered payment type', help="""Which payment type you wish to use.
|
||||
- Form: Redirect the user to the payment acquirer website to pay.
|
||||
- Server to server: The user enter his credit card information on your website and is processed by Odoo.
|
||||
- Both: Both are displayed to the user.
|
||||
|
||||
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']
|
||||
|
||||
@@ -77,23 +77,55 @@ odoo.define('payment.payment_form', function (require){
|
||||
// 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"]');
|
||||
|
||||
// Here we take the values we need to send to the acquirer and generate a form with them
|
||||
var html_form = '<form method="post" action="' + ds.dataset.actionUrl + '" class="hidden">';
|
||||
var ignored_inputs = ['data_set', 'o_payment_form_save_token'];
|
||||
|
||||
for(var i = 0; i < inputs_form.length; i ++) {
|
||||
if(inputs_form[i].name != "data_set") {
|
||||
if(ignored_inputs.indexOf(inputs_form[i].name) == -1) {
|
||||
html_form +='<input name="' + inputs_form[i].name + '" value="' + inputs_form[i].value + '"/>';
|
||||
}
|
||||
else if(inputs_form[i].name == 'o_payment_form_save_token') {
|
||||
form_save_token = inputs_form[i].checked;
|
||||
}
|
||||
}
|
||||
html_form += '</form>';
|
||||
// we append the form to the body and send it.
|
||||
$(html_form).appendTo("body").submit();
|
||||
|
||||
// if there's a prepare tx url set
|
||||
if($tx_url.length == 1)
|
||||
{
|
||||
// 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) {
|
||||
// we append the form to the body and send it.
|
||||
$(html_form).appendTo("body").submit();
|
||||
}
|
||||
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.
|
||||
$(html_form).appendTo("body").submit();
|
||||
}
|
||||
}
|
||||
// if the user is using an old payment
|
||||
else {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -20,30 +20,44 @@
|
||||
- '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 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-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" t-att-data-s2s-payment="true" name="pm_id" t-attf-value="new_{{acq.id}}" t-att-class="'hidden' if (len(s2s_acquirers)==1) else ''" t-att-checked="len(s2s_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" t-att-data-s2s-payment="true" name="pm_id" t-attf-value="new_{{acq.id}}" t-att-class="'hidden' if (len(s2s_acquirers)==1 and len(pms)==0) else ''" t-att-checked="len(s2s_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">
|
||||
<!-- <ul class="pull-right list-inline">
|
||||
<t t-foreach="acq.payment_option_ids" t-as="pm_option">
|
||||
<li>
|
||||
<span t-field="pm_option.image_small"
|
||||
t-options='{"widget": "image", "alt-field": "name"}' />
|
||||
</li>
|
||||
</t>
|
||||
</ul>
|
||||
</ul> -->
|
||||
</div>
|
||||
<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">
|
||||
@@ -54,13 +68,18 @@
|
||||
<t tif="mode == 'payment'" t-foreach="form_acquirers" t-as="acq">
|
||||
<div class="panel-body">
|
||||
<label>
|
||||
<!-- TBE TODO: Tout le schmilblick du hidden et checked (pareil pour le s2s juste au dessus) -->
|
||||
<input type="radio" t-att-data-acquirer-id="acq.id" t-att-data-form-payment="true" name="pm_id" t-attf-value="form_{{acq.id}}"/>
|
||||
<t t-esc="acq.name"/>
|
||||
<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_option_name" t-esc="acq.name"/>
|
||||
</label>
|
||||
</div>
|
||||
<div t-attf-id="o_payment_form_acq_{{acq.id}}" class="panel-footer hidden">
|
||||
You'll be redirected to the <t t-esc="acq.provider"/> website after clicking on the payment button.
|
||||
<p>You'll be redirected to the <t t-esc="acq.provider"/> website after clicking on the payment button.</p>
|
||||
<label t-if="acq.save_token == 'ask'"><input type="checkbox" name="o_payment_form_save_token"/> Save my payment data</label>
|
||||
<t t-raw="acq.form"/>
|
||||
</div>
|
||||
</t>
|
||||
@@ -68,7 +87,7 @@
|
||||
<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>
|
||||
|
||||
@@ -113,6 +113,7 @@
|
||||
</div>
|
||||
<field name="registration_view_template_id" groups="base.group_no_one"/>
|
||||
<field name="payment_option_ids" widget="many2many_tags"/>
|
||||
<field name="prefered_payment_type"/>
|
||||
</group>
|
||||
</page>
|
||||
</notebook>
|
||||
|
||||
@@ -64,23 +64,29 @@ class sale_quote(http.Controller):
|
||||
}
|
||||
|
||||
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.prefered_payment_type in ['form', 'both'] and acq.view_template_id]
|
||||
values['s2s_acquirers'] = [acq for acq in acquirers if acq.prefered_payment_type in ['s2s', 'both'] 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',
|
||||
'alias_usage': _('If we store your payment information on our server, subscription payments will be made automatically.'),
|
||||
'partner_id': order_sudo.partner_id.id,
|
||||
})
|
||||
|
||||
for acq in values['s2s_acquirers']:
|
||||
acq.form = acq._registration_render(order_sudo.partner_id.id, {
|
||||
'return_url': '/shop/payment/validate',
|
||||
'bootstrap_formatting': True
|
||||
})
|
||||
|
||||
history = request.session.get('my_quotes_history', [])
|
||||
values.update(get_records_pager(history, order_sudo))
|
||||
return request.render('website_quote.so_quotation', values)
|
||||
@@ -158,8 +164,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 +176,8 @@ 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
|
||||
# return request.redirect("/quote/%s" % order_id)
|
||||
|
||||
# find an already existing transaction
|
||||
acquirer = request.env['payment.acquirer'].browse(int(acquirer_id))
|
||||
@@ -184,8 +191,44 @@ class sale_quote(http.Controller):
|
||||
})
|
||||
request.session['quote_%s_transaction_id' % order.id] = tx.id
|
||||
|
||||
return tx.render_sale_button(order, '/quote/%s/%s' % (order_id, token) if token else '/quote/%s' % order_id,
|
||||
submit_txt=_('Pay & Confirm'), render_values={
|
||||
'type': order._get_payment_type(),
|
||||
'alias_usage': _('If we store your payment information on our server, subscription payments will be made automatically.'),
|
||||
})
|
||||
return True
|
||||
# return tx.render_sale_button(order, '/quote/%s/%s' % (order_id, token) if token else '/quote/%s' % order_id,
|
||||
# submit_txt=_('Pay & Confirm'), render_values={
|
||||
# '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>
|
||||
|
||||
@@ -714,8 +714,11 @@ class WebsiteSale(http.Controller):
|
||||
[('website_published', '=', True), ('company_id', '=', order.company_id.id)]
|
||||
)
|
||||
|
||||
values['form_acquirers'] = [acq for acq in acquirers if acq.view_template_id]
|
||||
values['s2s_acquirers'] = [acq for acq in acquirers if acq.registration_view_template_id]
|
||||
values['form_acquirers'] = [acq for acq in acquirers if acq.prefered_payment_type in ['form', 'both'] and acq.view_template_id]
|
||||
values['s2s_acquirers'] = [acq for acq in acquirers if acq.prefered_payment_type in ['s2s', 'both'] 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(
|
||||
@@ -730,30 +733,11 @@ class WebsiteSale(http.Controller):
|
||||
)
|
||||
|
||||
for acq in values['s2s_acquirers']:
|
||||
acq.form = acq.sudo()._registration_render(order.partner_id.id, {
|
||||
acq.form = acq._registration_render(order.partner_id.id, {
|
||||
'return_url': '/shop/payment/validate',
|
||||
'bootstrap_formatting': True
|
||||
})
|
||||
|
||||
|
||||
values['acquirers'] = []
|
||||
for acquirer in acquirers:
|
||||
acquirer_button = acquirer.with_context(submit_class='btn btn-primary', submit_txt=_('Pay Now')).sudo().render(
|
||||
'/',
|
||||
order.amount_total,
|
||||
order.pricelist_id.currency_id.id,
|
||||
values={
|
||||
'return_url': '/shop/payment/validate',
|
||||
'partner_id': shipping_partner_id,
|
||||
'billing_partner_id': order.partner_invoice_id.id,
|
||||
}
|
||||
)
|
||||
acquirer.button = acquirer_button #TBE TODO: remove this line
|
||||
acquirer.form = 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
|
||||
|
||||
@http.route(['/shop/payment'], type='http', auth="public", website=True)
|
||||
@@ -801,8 +785,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
|
||||
@@ -811,10 +797,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:
|
||||
@@ -822,7 +809,8 @@ 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 request.redirect("/shop/checkout")
|
||||
return False
|
||||
|
||||
assert order.partner_id.id != request.website.partner_id.id
|
||||
|
||||
@@ -833,13 +821,14 @@ 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')
|
||||
# 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')
|
||||
return True
|
||||
# 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, **kw):
|
||||
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.
|
||||
@@ -854,13 +843,13 @@ class WebsiteSale(http.Controller):
|
||||
try:
|
||||
pm_id = int(pm_id)
|
||||
except ValueError:
|
||||
pm_id = False
|
||||
|
||||
if not pm_id:
|
||||
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
|
||||
|
||||
@@ -1333,10 +1333,12 @@
|
||||
<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>
|
||||
</div>
|
||||
|
||||
<div class="js_payment mb64 col-md-12 row" t-if="acquirers and website_sale_order.amount_total" id="payment_method">
|
||||
<!-- TBE TODO: Virer tout ce qu'il y a en bas et qui est inutile maintenant -->
|
||||
<!-- <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">
|
||||
@@ -1412,7 +1414,7 @@
|
||||
</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user