[FIX] payment: Payment form not implemented on /website_payment/pay
The generic payment form introduced in 11.0 has changed the way we collect payment and so does the code. The route /website_payment/pay hasn't been changed to support the new payment form. This commit fixes this. It also fixes a bug for when a customer tries to create two transactions with the same reference.
This commit is contained in:
@@ -31,49 +31,110 @@ class WebsitePayment(http.Controller):
|
||||
currency_id = currency_id and int(currency_id) or user.company_id.currency_id.id
|
||||
currency = env['res.currency'].browse(currency_id)
|
||||
|
||||
# Try default one then fallback on first
|
||||
acquirer_id = acquirer_id and int(acquirer_id) or \
|
||||
env['ir.default'].get('payment.transaction', 'acquirer_id', company_id=user.company_id.id) or \
|
||||
env['payment.acquirer'].search([('website_published', '=', True), ('company_id', '=', user.company_id.id)])[0].id
|
||||
|
||||
acquirer = env['payment.acquirer'].with_context(submit_class='btn btn-primary pull-right',
|
||||
submit_txt=_('Pay Now')).browse(acquirer_id)
|
||||
acquirers = None
|
||||
if acquirer_id:
|
||||
acquirers = env['payment.acquirer'].browse(int(acquirer_id))
|
||||
if not acquirers:
|
||||
acquirers = env['payment.acquirer'].search([('website_published', '=', True), ('company_id', '=', user.company_id.id)])
|
||||
# auto-increment reference with a number suffix if the reference already exists
|
||||
reference = request.env['payment.transaction'].get_next_reference(reference)
|
||||
|
||||
partner_id = user.partner_id.id if not user._is_public() else False
|
||||
|
||||
payment_form = acquirer.sudo().render(reference, float(amount), currency.id, values={'return_url': '/website_payment/confirm', 'partner_id': partner_id})
|
||||
values = {
|
||||
'reference': reference,
|
||||
'acquirer': acquirer,
|
||||
'currency': currency,
|
||||
'amount': float(amount),
|
||||
'payment_form': payment_form,
|
||||
'return_url': '/website_payment/confirm',
|
||||
'partner_id': partner_id,
|
||||
'bootstrap_formatting': True,
|
||||
'error_msg': kw.get('error_msg')
|
||||
}
|
||||
# TODO: remove return when payment is implemented with refactored payments, i.e. use of
|
||||
# payment.payment_tokens_list in the template.
|
||||
# return request.render('payment.pay', values)
|
||||
return request.render('website.404')
|
||||
|
||||
@http.route(['/website_payment/transaction'], type='json', auth="public", website=True)
|
||||
def transaction(self, reference, amount, currency_id, acquirer_id):
|
||||
values['s2s_acquirers'] = [acq for acq in acquirers if acq.payment_flow == 's2s']
|
||||
values['form_acquirers'] = [acq for acq in acquirers if acq.payment_flow == 'form']
|
||||
values['pms'] = request.env['payment.token'].search([('acquirer_id', 'in', [acq.id for acq in values['s2s_acquirers']])])
|
||||
|
||||
return request.render('payment.pay', values)
|
||||
|
||||
def _get_existing_transaction(self, reference, amount, partner_id, currency_id, acquirer_id, tx_id):
|
||||
PaymentTransaction = request.env['payment.transaction']
|
||||
tx = None
|
||||
if tx_id:
|
||||
tx = PaymentTransaction.sudo().browse(tx_id)
|
||||
if not tx.exists() or tx.reference != reference or tx.acquirer_id.id != acquirer_id:
|
||||
tx = None
|
||||
|
||||
if not tx:
|
||||
tx = PaymentTransaction.sudo().search([('reference', '=', reference), ('acquirer_id', '=', acquirer_id)])
|
||||
|
||||
if tx and (tx.state != 'draft' or tx.partner_id.id != partner_id or tx.amount != amount or tx.currency_id.id != currency_id):
|
||||
tx = None
|
||||
|
||||
return tx
|
||||
|
||||
@http.route(['/website_payment/transaction/<string:reference>/<string:amount>/<string:currency_id>',], type='json', auth='public')
|
||||
def transaction(self, acquirer_id, reference, amount, currency_id, **kwargs):
|
||||
partner_id = request.env.user.partner_id.id if not request.env.user._is_public() else False
|
||||
acquirer = request.env['payment.acquirer'].browse(acquirer_id)
|
||||
|
||||
tx = self._get_existing_transaction(reference, float(amount), partner_id,
|
||||
int(currency_id), int(acquirer_id), request.session.get('website_payment_tx_id'))
|
||||
|
||||
if not tx:
|
||||
values = {
|
||||
'acquirer_id': int(acquirer_id),
|
||||
'reference': reference,
|
||||
'amount': float(amount),
|
||||
'currency_id': currency_id,
|
||||
'partner_id': partner_id,
|
||||
}
|
||||
|
||||
tx = request.env['payment.transaction'].sudo().create(values)
|
||||
request.session['website_payment_tx_id'] = tx.id
|
||||
|
||||
render_values = {
|
||||
'return_url': '/website_payment/confirm?tx_id=%d' % tx.id,
|
||||
'partner_id': partner_id,
|
||||
}
|
||||
|
||||
return acquirer.sudo().render(reference, float(amount), int(currency_id), values=render_values)
|
||||
|
||||
@http.route(['/website_payment/token/<string:reference>/<float:amount>/<int:currency_id>'], type='http', auth='public', website=True)
|
||||
def payment_token(self, pm_id, reference, amount, currency_id, return_url=None, **kwargs):
|
||||
token = request.env['payment.token'].browse(int(pm_id))
|
||||
|
||||
if not token:
|
||||
return request.redirect('/website_payment/pay?error_msg=%s' % _('Cannot setup the payment.'))
|
||||
|
||||
partner_id = request.env.user.partner_id.id if not request.env.user._is_public() else False
|
||||
|
||||
values = {
|
||||
'acquirer_id': int(acquirer_id),
|
||||
'acquirer_id': token.acquirer_id.id,
|
||||
'reference': reference,
|
||||
'amount': float(amount),
|
||||
'currency_id': int(currency_id),
|
||||
'partner_id': partner_id,
|
||||
'payment_token_id': pm_id
|
||||
}
|
||||
|
||||
tx = request.env['payment.transaction'].sudo().create(values)
|
||||
request.session['website_payment_tx_id'] = tx.id
|
||||
return tx.id
|
||||
|
||||
try:
|
||||
res = tx.s2s_do_transaction()
|
||||
except Exception as e:
|
||||
return request.redirect('/website_payment/pay?error_msg=%s' % _('Payment transaction failed.'))
|
||||
|
||||
valid_state = 'authorized' if tx.acquirer_id.capture_manually else 'done'
|
||||
if not res or tx.state != valid_state:
|
||||
return request.redirect('/website_payment/pay?error_msg=%s' % _('Payment transaction failed.'))
|
||||
|
||||
return request.redirect(return_url if return_url else '/website_payment/confirm?tx_id=%d' % tx.id)
|
||||
|
||||
@http.route(['/website_payment/confirm'], type='http', auth='public', website=True)
|
||||
def confirm(self, **kw):
|
||||
tx_id = request.session.pop('website_payment_tx_id', False)
|
||||
tx_id = int(kw.get('tx_id', 0)) or request.session.pop('website_payment_tx_id', 0)
|
||||
if tx_id:
|
||||
tx = request.env['payment.transaction'].browse(tx_id)
|
||||
if tx.state == 'done':
|
||||
|
||||
@@ -1,24 +1,2 @@
|
||||
odoo.define('payment.website_payment', function (require) {
|
||||
"use strict";
|
||||
|
||||
require('web.dom_ready');
|
||||
var ajax = require('web.ajax');
|
||||
|
||||
if (!$('.o_website_payment').length) {
|
||||
return $.Deferred().reject("DOM doesn't contain '.o_website_payment'");
|
||||
}
|
||||
|
||||
// When clicking on payment button: create the tx using json then continue to the acquirer
|
||||
var $payment = $(".o_website_payment_form");
|
||||
$payment.on("click", 'button[type="submit"],button[name="submit"]', function (ev) {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
$(ev.currentTarget).attr('disabled', true);
|
||||
$(ev.currentTarget).prepend('<i class="fa fa-refresh fa-spin"></i> ');
|
||||
var $form = $(ev.currentTarget).parents('form');
|
||||
var data =$("div[class~='o_website_payment_new_payment']").data();
|
||||
ajax.jsonRpc('/website_payment/transaction/', 'call', data).then(function (result) {
|
||||
$form.submit();
|
||||
});
|
||||
});
|
||||
});
|
||||
// This file is kept to avoid breaking assets compilation on instance that didn't run "-u payment".
|
||||
// TBE TODO: Remove me in master
|
||||
@@ -46,32 +46,22 @@
|
||||
<div class="wrap">
|
||||
<div class="container o_website_payment">
|
||||
<h1>Payment</h1>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="oe_structure"></div>
|
||||
<div>
|
||||
<div class="form-horizontal row o_website_payment_new_payment" t-att-data-acquirer_id="acquirer.id" t-att-data-currency_id="currency.id" t-att-data-reference="reference" t-att-data-amount="amount">
|
||||
<div class="form-group">
|
||||
<label for="form_reference" class="col-sm-3 control-label">Reference</label>
|
||||
<div class="col-sm-9">
|
||||
<span name="form_reference" class="form-control" t-esc="reference"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="form_amount" class="col-sm-3 control-label">Amount</label>
|
||||
<div class="col-sm-9">
|
||||
<span name="form_amount" class="form-control" t-esc="amount" t-options="{'widget': 'monetary', 'display_currency': currency}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-9 col-sm-offset-3 text-muted mt16" t-raw="acquirer.pre_msg"/>
|
||||
<div class="col-sm-12 o_website_payment_form" t-raw="payment_form"/>
|
||||
<div class="col-sm-6 col-sm-offset-6 text-muted mt16">
|
||||
<span t-field="acquirer.image_small" t-att-title="acquirer.name" t-options='{"widget": "image", "style":"max-width: 60px; display: inline-block"}'/>
|
||||
<span>Processed by <t t-esc="acquirer.name"/>.</span>
|
||||
</div>
|
||||
</div>
|
||||
<div t-if="error_msg" class="alert alert-danger col-md-7">
|
||||
<t t-esc="error_msg"/>
|
||||
</div>
|
||||
<div class="row mt32 mb32">
|
||||
<div class="col-md-7">
|
||||
<p><b>Reference:</b> <t t-esc="reference"/></p>
|
||||
<p><b>Amount:</b> <t t-esc="amount" t-options="{'widget': 'monetary', 'display_currency': currency}"/></p>
|
||||
<t t-call="payment.payment_tokens_list" t-if="reference and amount and currency">
|
||||
<t t-set="mode" t-value="'payment'"/>
|
||||
<t t-set="prepare_tx_url" t-value="'/website_payment/transaction/' + reference + '/' + str(amount) + '/' + str(currency.id)"/>
|
||||
<t t-set="form_action" t-value="'/website_payment/token/' + reference + '/' + str(amount) + '/' + str(currency.id)"/>
|
||||
</t>
|
||||
<div t-if="not (s2s_acquirers or form_acquirers)" class="alert alert-danger">
|
||||
<p>No payment acquirer found.</p>
|
||||
<p>Please configure a payment acquirer.</p>
|
||||
</div>
|
||||
<div class="oe_structure"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -108,11 +108,14 @@ odoo.define('payment_stripe.stripe', function(require) {
|
||||
|
||||
|
||||
if ($('.o_website_payment').length !== 0) {
|
||||
var create_tx = ajax.jsonRpc('/website_payment/transaction', 'call', {
|
||||
reference: $("input[name='invoice_num']").val(),
|
||||
amount: amount, // exact amount, not stripe cents
|
||||
currency_id: currency_id,
|
||||
var invoice_num = $("input[name='invoice_num']").val();
|
||||
var url = _.str.sprintf("/website_payment/transaction/%s/%f/%s",
|
||||
invoice_num, amount, currency_id);
|
||||
|
||||
var create_tx = ajax.jsonRpc(url, 'call', {
|
||||
acquirer_id: acquirer_id
|
||||
}).then(function (data) {
|
||||
try { provider_form[0].innerHTML = data; } catch (e) {}
|
||||
});
|
||||
}
|
||||
else if ($('.o_website_quote').length !== 0) {
|
||||
|
||||
Reference in New Issue
Block a user