Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[payment] bugfix v11 #21003

Closed
wants to merge 18 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
227c44c
[FIX] payment: hide payment flow field for non-s2s payment acquirers
jpr-odoo Nov 15, 2017
e37dbd2
[FIX] sale: show shipping address, when we have ticked 'customer addr…
jpr-odoo Nov 15, 2017
f761e89
[FIX] website_sale: if payment transaction is paid then hide 'Mark as…
jpr-odoo Nov 15, 2017
3cea1cc
[FIX] sale,sale_management: the button('create invoice') should be vi…
jpr-odoo Nov 15, 2017
bccc2c6
[FIX] portal: misc for button and update sign draw layout to validate…
jpr-odoo Nov 15, 2017
6166fd5
[FIX] payment: fixed card brand type icon position into s2s form if s…
jpr-odoo Nov 15, 2017
ca24e78
[FIX] payment: set default cursor/focus on cc_number if value exist, …
jpr-odoo Nov 15, 2017
965023d
[FIX] sale_payment,website_sale: Generate the invoice automatically w…
jpr-odoo Sep 20, 2017
70bad8b
[FIX] account_payment,sale_payment: user able to choose another payme…
jpr-odoo Nov 15, 2017
33a5b0f
[FIX] payment: removed full stop at the end of options from payment f…
jpr-odoo Nov 15, 2017
faefaf6
[FIX] payment: reduced margin(to have same height then options withou…
jpr-odoo Nov 21, 2017
fd0e4a4
[FIX/IMP] account,account_payment,sale,sale_payment: show payment not…
jpr-odoo Nov 16, 2017
59f1391
[FIX] website_sale: message doesn't show up in e-commerce if manual c…
jpr-odoo Nov 16, 2017
2808fcc
[FIX] payment: link ('Manage your payment methods') should be display…
jpr-odoo Nov 16, 2017
6cd0ef3
[FIX] payment: any error message show up in the form, not in a dialog
jpr-odoo Dec 1, 2017
80aae0f
[FIX] payment: fix layout only one icon should show up (it's loading …
jpr-odoo Dec 4, 2017
073da60
[FIX] payment: display Error message(if any) while adding payment met…
jpr-odoo Dec 4, 2017
ea0cb1b
[FIX/IMP] payment_authorize: clean message when some fields are reque…
jpr-odoo Dec 4, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 4 additions & 3 deletions addons/account/views/account_portal_templates.xml
Expand Up @@ -46,7 +46,7 @@
</td>
<td><span t-field="invoice.date_invoice"/></td>
<td class='hidden-xs'><span t-field="invoice.date_due"/></td>
<td>
<td id="tx_status">
<t t-if="invoice.state == 'open'">
<span class="label label-info"><i class="fa fa-fw fa-clock-o"></i><span class="hidden-xs"> Waiting for Payment</span></span>
</t>
Expand Down Expand Up @@ -96,6 +96,7 @@
<div class="panel-body">
<t t-if="error or warning" t-call="account.portal_invoice_error"/>
<t t-if="success and (not error and not warning)" t-call="account.portal_invoice_success"/>
<div id="payment_status"></div>
<t t-call="account.portal_invoice_report"/>
</div>
</div>
Expand Down Expand Up @@ -254,7 +255,7 @@

<template id="portal_invoice_error" name="Invoice error/warning display">
<div class="row">
<div t-att-class="'col-md-6 col-md-offset-3 text-center alert alert-dismissable %s' % ('alert-danger' if error else 'alert-warning')">
<div t-attf-class="'col-md-12 mr16 ml16 alert alert-dismissable' #{'alert-danger' if error else 'alert-warning'}">
<a href="#" class="close" data-dismiss="alert" aria-label="close" title="close">×</a>
<t t-if="error == 'generic'" name="generic">
There was an error processing this page.
Expand All @@ -265,7 +266,7 @@

<template id="portal_invoice_success" name="Invoice success display">
<div class="row">
<div class="col-md-6 col-md-offset-3 text-center alert alert-dismissable alert-success">
<div class="col-md-12 mr16 ml16 alert alert-dismissable alert-success">
<a href="#" class="close" data-dismiss="alert" aria-label="close" title="close">×</a>
</div>
</div>
Expand Down
41 changes: 32 additions & 9 deletions addons/account_payment/views/account_portal_templates.xml
Expand Up @@ -5,31 +5,50 @@
</xpath>
<xpath expr="//t[@t-foreach='invoices']/tr/td[last()]" position="before">
<td>
<a t-if="invoice.state == 'open'" t-att-href="'/my/invoices/%s#portal_pay' % invoice.id" alt="Pay Now" class="btn btn-xs btn-primary">
<t t-set="tx_ids" t-value="invoice.payment_tx_ids.filtered(lambda tx: tx.state in ('authorized', 'done'))"/>
<a t-if="not tx_ids and invoice.state == 'open'" t-att-href="'/my/invoices/%s#portal_pay' % invoice.id" alt="Pay Now" class="btn btn-xs btn-primary">
<i class="fa fa-arrow-circle-right"/><span class='hidden-xs'> Pay Now</span>
</a>
</td>
</xpath>
<xpath expr="//t[@t-foreach='invoices']/tr/td[@id='tx_status']" position="replace">
<td id="tx_status">
<t t-if="invoice.state == 'open' and invoice.payment_tx_id.state not in ['authorized', 'done', 'cancel']">
<span class="label label-info"><i class="fa fa-fw fa-clock-o"></i><span class="hidden-xs"> Waiting for Payment</span></span>
</t>
<t t-if="invoice.state == 'open' and invoice.payment_tx_id.state == 'authorized'">
<span class="label label-success"><i class="fa fa-fw fa-check"/><span class="hidden-xs"> Authorized</span></span>
</t>
<t t-if="invoice.state == 'paid' or invoice.payment_tx_id.state == 'done'">
<span class="label label-default"><i class="fa fa-fw fa-check"></i><span class="hidden-xs"> Paid</span></span>
</t>
<t t-if="invoice.state == 'cancel'">
<span class="label label-default"><i class="fa fa-fw fa-remove"></i><span class="hidden-xs"> Cancelled</span></span>
</t>
</td>
</xpath>
</template>

<template id="portal_invoice_page_inherit_payment" name="Payment on My Invoices" inherit_id="account.portal_invoice_page">
<xpath expr="//div[@id='o_portal_account_actions']/a" position="before">
<t t-set="tx_ids" t-value="invoice.payment_tx_ids.filtered(lambda tx: tx.state in ('pending', 'authorized', 'done'))"/>
<t t-set="tx_ids" t-value="invoice.payment_tx_ids.filtered(lambda tx: tx.state in ('done', 'authorized'))"/>
<a t-if="not tx_ids and invoice.state == 'open' and invoice.amount_total"
class="btn btn-primary pull-right ml8" href="#portal_pay">
<i class="fa fa-arrow-circle-right"/> Pay Now
</a>
<a t-if="tx_ids and invoice.state != 'paid'"
class="btn btn-warning ml8 pull-right" disabled="disabled">
<i class="fa fa-check-circle"/> Pending
</a>
<a t-if="tx_ids and invoice.state == 'paid'"
class="btn btn-success ml8 pull-right" disabled="disabled">
<i class="fa fa-check-circle"/> Paid
</a>
</xpath>
<xpath expr="//div[@id='payment_status']" position="inside">
<div t-if="invoice.payment_tx_ids and invoice.amount_total and not success and not error" class="o_account_payment_tx_status" t-att-data-invoice-id="invoice.id">
<t t-set="payment_tx_id" t-value="invoice.payment_tx_id"/>
<t t-call="payment.payment_confirmation_status"/>
</div>
</xpath>
<xpath expr="//div[hasclass('panel-body')]" position="after">
<div class="panel-body" t-if="not tx_ids and invoice.state == 'open' and invoice.amount_total" id="portal_pay">
<div class="panel-body" t-if="not invoice.payment_tx_ids.filtered(lambda tx: tx.state in ('done', 'authorized')) and invoice.state == 'open' and invoice.amount_total" id="portal_pay">
<div t-if="pms or s2s_acquirers or form_acquirers" id="payment_method" class="col-md-offset-3 col-md-6">
<h4 class="mb24">Pay with</h4>
<t t-call="payment.payment_tokens_list">
Expand Down Expand Up @@ -64,7 +83,10 @@
<t t-if="tx.state == 'done'">
<span class="label label-success orders_label_text_align"><i class="fa fa-fw fa-check"/> Done</span>
</t>
<t t-if="tx.state != 'done'">
<t t-if="tx.state == 'authorized'">
<span class="label label-success orders_label_text_align"><i class="fa fa-fw fa-check"/> Authorized</span>
</t>
<t t-if="tx.state not in ('done', 'authorized')">
<span class="label label-info orders_label_text_align"><i class="fa fa-fw fa-clock-o"/> Waiting</span>
<t t-if="tx.state_message"><br /><span t-esc="tx.state_message"/></t>
</t>
Expand Down Expand Up @@ -119,7 +141,8 @@
inherit_id="account.portal_invoice_success">
<xpath expr="//a[hasclass('close')]" position="after">
<t t-if="success == 'pay_invoice'">
Invoice successfully paid.
<span t-if='invoice.payment_acquirer_id.done_msg' t-raw="invoice.payment_acquirer_id.done_msg"/>
<span t-if='invoice.payment_acquirer_id.post_msg' t-raw="invoice.payment_acquirer_id.post_msg"/>
</t>
</xpath>
</template>
Expand Down
9 changes: 6 additions & 3 deletions addons/payment/models/payment_acquirer.py
Expand Up @@ -151,10 +151,12 @@ class PaymentAcquirer(models.Model):
"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',
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.""")
s2s_supported = fields.Boolean(compute="_compute_feature_support")

def _search_is_tokenized(self, operator, value):
tokenized = self._get_feature_support()['tokenize']
Expand All @@ -169,6 +171,7 @@ def _compute_feature_support(self):
acquirer.fees_implemented = acquirer.provider in feature_support['fees']
acquirer.authorize_implemented = acquirer.provider in feature_support['authorize']
acquirer.token_implemented = acquirer.provider in feature_support['tokenize']
acquirer.s2s_supported = hasattr(acquirer, '%s_s2s_form_process' % acquirer.provider)

@api.multi
def _check_required_if_provider(self):
Expand Down
9 changes: 9 additions & 0 deletions addons/payment/static/src/css/portal_payment.css
Expand Up @@ -14,6 +14,15 @@ div.card_placeholder {
transition: 0.4s cubic-bezier(0.455, 0.03, 0.515, 0.955);
pointer-events: none; }

/* if s2s form not in bootstrap_formatting */
div.o_card_brand_detail {
position: relative;
}

div.o_card_brand_detail div.card_placeholder {
right: 5px;
}

div.amex {
background-image: url("/website_payment/static/src/img/amex.png");
background-repeat: no-repeat; }
Expand Down
97 changes: 56 additions & 41 deletions addons/payment/static/src/js/payment_form.js
Expand Up @@ -57,31 +57,30 @@ odoo.define('payment.payment_form', function (require) {
console.warn('payment_form: unset partner_id when adding new token; things could go wrong');
}
var form_data = this.getFormData(inputs_form);
var empty_inputs = false;
var empty_inputs = [];

inputs_form.toArray().forEach(function (element) {
if (element.dataset.isRequired) {
if (element.value.length === 0) {
$(element).closest('div.form-group').addClass('has-error');
empty_inputs = true;
empty_inputs.push(element.placeholder);
}
else {
$(element).closest('div.form-group').removeClass('has-error');
}
}
});

if (empty_inputs) {
if (empty_inputs.length) {
this.updatePaymentBtn();
this.displayError(
_t('Missing values'),
_t('<p>Please fill all the inputs required.</p>')
_t('The following field(s) are invalid or missing'),
'<p>' + empty_inputs.join('<br/>') + '</p>'
);
return;
}

$(button).attr('disabled', true);
$(button).prepend('<span class="o_loader"><i class="fa fa-refresh fa-spin"></i>&nbsp;</span>');

this.updatePaymentBtn();
var verify_validity = this.$el.find('input[name="verify_validity"]');

if (verify_validity.length>0) {
Expand All @@ -102,20 +101,16 @@ odoo.define('payment.payment_form', function (require) {
form.submit();
}
}
// if the server has returned false, we display an error
else {
// if the server has returned false/error, we display an error
if (data.error || (!data.result && !data.error)) {
self.updatePaymentBtn();
self.displayError(
_t('Server Error'),
_t("<p>We are not able to add your payment method at the moment.</p>"));
_t(data.error ? data.error : 'e.g. Your credit card details are wrong. Please verify.')
);
}
// here we remove the 'processing' icon from the 'add a new payment' button
$(button).attr('disabled', false);
$(button).find('span.o_loader').remove();
}).fail(function (message, data) {
// if the rpc fails, pretty obvious
$(button).attr('disabled', false);
$(button).find('span.o_loader').remove();

self.updatePaymentBtn();
self.displayError(
_t('Server Error'),
_t("<p>We are not able to add your payment method at the moment.</p>") +
Expand Down Expand Up @@ -157,12 +152,14 @@ odoo.define('payment.payment_form', function (require) {
}
}
else {
self.updatePaymentBtn();
self.displayError(
_t('Server Error'),
_t("<p>We are not able to redirect you to the payment form.</p>")
);
}
}).fail(function (message, data) {
self.updatePaymentBtn();
self.displayError(
_t('Server Error'),
_t("<p>We are not able to redirect you to the payment form.</p>") +
Expand All @@ -174,6 +171,7 @@ odoo.define('payment.payment_form', function (require) {
}
else {
// we append the form to the body and send it.
this.updatePaymentBtn();
this.displayError(
_t("Cannot set-up the payment"),
_t("<p>We're unable to process your payment.</p>")
Expand All @@ -185,6 +183,7 @@ odoo.define('payment.payment_form', function (require) {
}
}
else {
this.updatePaymentBtn();
this.displayError(
_t('No payment method selected'),
_t('<p>Please select a payment method.</p>')
Expand All @@ -209,30 +208,30 @@ odoo.define('payment.payment_form', function (require) {
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;
var empty_inputs = [];

inputs_form.toArray().forEach(function (element) {
if (element.dataset.isRequired) {
if (element.value.length === 0) {
$(element).closest('div.form-group').addClass('has-error');
empty_inputs = true;
empty_inputs.push(element.placeholder);
}
else {
$(element).closest('div.form-group').removeClass('has-error');
}
}
});

if (empty_inputs) {
if (empty_inputs.length) {
this.updatePaymentBtn();
this.displayError(
_t('Missing values'),
_t('<p>Please fill all the inputs required.</p>')
_t('The following field(s) invalid or missing'),
'<p>' + empty_inputs.join('<br/>') + '</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>&nbsp;</span>');
this.updatePaymentBtn();

// we force the check when adding a card trough here
form_data.verify_validity = true;
Expand All @@ -257,21 +256,16 @@ odoo.define('payment.payment_form', function (require) {
}
}
}
// if the server has returned false, we display an error
else {
// if the server has returned false/error, we display an error
if (data.error || (!data.result && !data.error)) {
self.updatePaymentBtn();
self.displayError(
_t('Server Error'),
_t("<p>We are not able to add your payment method at the moment.</p>")
_t(data.error ? data.error : 'e.g. Your credit card details are wrong. Please verify.')
);
}
// here we remove the 'processing' icon from the 'add a new payment' button
$(button).attr('disabled', false);
$(button).find('span.o_loader').remove();
}).fail(function (message, data) {
// if the rpc fails, pretty obvious
$(button).attr('disabled', false);
$(button).find('span.o_loader').remove();

self.updatePaymentBtn();
self.displayError(
_t('Server error'),
_t("<p>We are not able to add your payment method at the moment.</p>") +
Expand All @@ -282,6 +276,7 @@ odoo.define('payment.payment_form', function (require) {
});
}
else {
this.updatePaymentBtn();
this.displayError(
_t('No payment method selected'),
_t('<p>Please select the option to add a new payment method.</p>')
Expand Down Expand Up @@ -390,13 +385,33 @@ odoo.define('payment.payment_form', function (require) {
getAcquirerIdFromRadio: function (element) {
return $(element).data('acquirer-id');
},
updatePaymentBtn: function (reset) {
var $button = this.$('button#o_payment_form_add_pm, button#o_payment_form_pay'),
$icon = $button.find('i');
if (!$button.length) {
return ;
}
$button.attr('disabled', !reset);
$icon.removeClass();
if (!reset) {
$icon.addClass('fa fa-refresh fa-spin');
} else if ($button.attr('id') === 'o_payment_form_add_pm') {
$icon.addClass('fa fa-plus-circle');
} else {
$icon.addClass('fa fa-lock');
}
},
displayError: function (title, message) {
return new Dialog(null, {
title: _t('Error: ') + title,
size: 'medium',
$content: message || "",
buttons: [
{text: _t('Ok'), close: true}]}).open();
var $checkedRadio = this.$('input[type="radio"]:checked'),
acquirerID = this.getAcquirerIdFromRadio($checkedRadio[0]),
$acquirerForm = this.$('#o_payment_add_token_acq_' + acquirerID);

// removed if exist error message
this.$('#payment_error').remove();
message = '<div class="alert alert-danger mb4" id="payment_error">' + '<b>' + title + ':</b></br>' + message + '</div>';
$acquirerForm.append(message);
// here we remove the 'processing' icon from the 'add a new payment/ pay now' button
this.updatePaymentBtn(true);
},
getFormData: function ($form) {
var unindexed_array = $form.serializeArray();
Expand Down