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

[FIX] [13.0] pos_payment_terminal: directly switch to 'waiting for card', prevent endless status polling #1

Open
wants to merge 2 commits into
base: 13.0
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 40 additions & 6 deletions pos_payment_terminal/static/src/js/payment_terminal.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ odoo.define("pos_payment_terminal.payment", function(require) {
},

_oca_payment_terminal_pay: function() {
var self = this;
var order = this.pos.get_order();
var pay_line = order.selected_paymentline;
var currency = this.pos.currency;
Expand Down Expand Up @@ -64,14 +65,18 @@ odoo.define("pos_payment_terminal.payment", function(require) {
);
// There was an error, let the user retry.
return false;
} else if (response instanceof Object && "transaction_id" in response) {
} else if (response instanceof Object && "transaction_id" in response && response.transaction_id) {
// The response has a terminal transaction identifier:
// return a promise that polls for transaction status.
pay_line.set_payment_status("waitingCard");
this._oca_update_payment_line_terminal_transaction_status(
pay_line,
response
);
// show the new 'waiting_card' status on screen
if (self.pos.chrome.gui.current_screen && self.pos.chrome.gui.current_screen.render_paymentlines) {
self.pos.chrome.gui.current_screen.render_paymentlines();
}
thomaspaulb marked this conversation as resolved.
Show resolved Hide resolved
return new Promise((resolve, reject) => {
this._oca_poll_for_transaction_status(
pay_line,
Expand All @@ -93,19 +98,39 @@ odoo.define("pos_payment_terminal.payment", function(require) {
},

_oca_poll_for_transaction_status: function(pay_line, resolve, reject) {
var retries = 0;
var got_response = false;
var timerId = setInterval(() => {
++retries;
if (retries > 300) {
// if the total card payment flow takes more than 5 minutes,
// consider it a dead end and don't keep polling (prevent endless polls)
clearInterval(timerId);
pay_line.set_payment_status("force_done");
reject();
return;
}
// Query the driver status more frequently than the regular POS
// proxy, to get faster feedback when the transaction is
// complete on the terminal.
var status_params = {};
if (this.payment_method.oca_payment_terminal_id) {
status_params.terminal_id = this.payment_method.oca_payment_terminal_id;
}
// if a user action already updated the transaction status, stop checking status
if ((pay_line.payment_status == 'done') || (pay_line.payment_status == 'retry')) {
clearInterval(timerId);
reject();
return;
}
thomaspaulb marked this conversation as resolved.
Show resolved Hide resolved
// otherwise check status
this.pos.proxy.connection
.rpc("/hw_proxy/status_json", status_params, {
shadow: true,
timeout: 1000,
})
.rpc(
// the parameter is just so that it stands out over the other network transactions
"/hw_proxy/status_json?for_transaction=" + pay_line.terminal_transaction_id,
status_params,
{shadow: true, timeout: 1000}
)
.then(drivers_status => {
for (var driver_name in drivers_status) {
// Look for a driver that is a payment terminal and has
Expand All @@ -120,21 +145,30 @@ odoo.define("pos_payment_terminal.payment", function(require) {
transaction.transaction_id ===
pay_line.terminal_transaction_id
) {
got_response = true;
// Look for the transaction corresponding to
// the payment line.
this._oca_update_payment_line_terminal_transaction_status(
pay_line,
transaction
);
if (
pay_line.terminal_transaction_success !== null
pay_line.terminal_transaction_success !== null &&
pay_line.terminal_transaction_success !== undefined
) {
resolve(pay_line.terminal_transaction_success);
// Stop the loop
clearInterval(timerId);
}
}
}
if (!got_response && retries > 30) {
// if after 30 seconds still no word about the status of the transaction,
// then consider it lost in space. Let user decide the status.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if this plays well with other drivers such as Telium, which may not return any status until there is a definite Approved or Cancelled - in that case 30 seconds may be too soon. Maybe this should be made configurable?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or we could just remove this, since the 'waiting for card' screen does show a 'Cancel' button, so the user is not stuck.

clearInterval(timerId);
pay_line.set_payment_status("force_done");
reject();
}
}
})
.catch(() => {
Expand Down