diff --git a/Helcim/build.sh b/Helcim/build.sh index 027c906..06f86d4 100755 --- a/Helcim/build.sh +++ b/Helcim/build.sh @@ -9,7 +9,7 @@ rm Helcim.zip cd build -zip -r ../Helcim.v0.0.1.zip Helcim +zip -r ../Helcim.v0.0.2.zip Helcim cd .. diff --git a/Helcim/package-lock.json b/Helcim/package-lock.json index 1c54b54..08a2177 100644 --- a/Helcim/package-lock.json +++ b/Helcim/package-lock.json @@ -1,6 +1,6 @@ { "name": "postalpoint_helcim_plugin", - "version": "0.0.1", + "version": "0.0.2", "lockfileVersion": 3, "requires": true, "packages": { diff --git a/Helcim/package.json b/Helcim/package.json index ce7cdcf..8decb64 100644 --- a/Helcim/package.json +++ b/Helcim/package.json @@ -1,6 +1,6 @@ { "name": "postalpoint_helcim_plugin", - "version": "0.0.1", + "version": "0.0.2", "main": "plugin.js", "author": "PostalPortal LLC", "license": "BSD-3-Clause", diff --git a/Helcim/plugin.js b/Helcim/plugin.js index 2ad23b4..8efae0d 100644 --- a/Helcim/plugin.js +++ b/Helcim/plugin.js @@ -116,6 +116,10 @@ function getCardBrand(cardType) { return cardType; } +var currentReceiptID = null; + +var checkoutCancelled = false; + exports.init = function () { global.apis.pos.registerCardProcessor({ name: "Helcim", @@ -133,12 +137,15 @@ exports.init = function () { // it is assumed the payment was successful. const code = global.apis.settings.get(PLUGINID + ".devicecode", ""); const receiptID = global.apis.pos.getReceiptID(); + checkoutCancelled = false; + currentReceiptID = receiptID; try { + var transactionAmount = global.apis.i18n.moneyToFixed(amount / 100.0) * 1.0; // authorize, capture, add a ReceiptPayment to the receipt, and return boolean true. global.apis.pos.addOnscreenPaymentLog("Getting card payment..."); // Add a line to the onscreen card processing status log var purchaseResp = await apiRequest(`devices/${code}/payment/purchase`, { currency: global.apis.i18n.currency().toUpperCase(), - transactionAmount: global.apis.i18n.moneyToFixed(amount / 100.0) * 1.0, + transactionAmount: transactionAmount, invoiceNumber: receiptID }, "POST", "text"); if (purchaseResp.length > 0) { @@ -151,18 +158,28 @@ exports.init = function () { } var paymentID = ""; - + var purchaseResp; while (paymentID == "") { + if (checkoutCancelled) { + checkoutCancelled = false; + global.apis.pos.addOnscreenPaymentLog("Checkout cancelled. Warning: It's still possible for the payment to succeed on the reader but not be recognized in PostalPoint; cancel it on the reader too."); + return false; + } await global.apis.util.delay(1000); // Wait a second try { var pollResults = await global.apis.util.http.webhook.poll(WEBHOOK_SOURCE); for (var i = 0; i < pollResults.length; i++) { var resultBody = JSON.parse(pollResults[i].body); if (resultBody.type == "cardTransaction") { - paymentID = resultBody.id; + purchaseResp = await apiRequest(`card-transactions/${resultBody.id}`, null, "GET"); global.apis.util.http.webhook.ack(pollResults[i].id); + if (purchaseResp.invoiceNumber == currentReceiptID) { + console.log("Got transaction ID from Helcim webhook:", paymentID); + console.log("purchaseResp", purchaseResp); + paymentID = resultBody.id; + } } else if (resultBody.type == "terminalCancel") { - if (resultBody.data.deviceCode == code && resultBody.data.invoiceNumber == receiptID) { + if (resultBody.data.deviceCode == code && resultBody.data.invoiceNumber == currentReceiptID && resultBody.data.transactionAmount == transactionAmount) { paymentID = "CANCEL"; global.apis.util.http.webhook.ack(pollResults[i].id); } @@ -174,18 +191,17 @@ exports.init = function () { } if (paymentID == "CANCEL") { - global.apis.pos.addOnscreenPaymentLog("Helcim payment not completed."); - global.apis.alert("The card payment was canceled.", "Payment canceled"); + global.apis.pos.addOnscreenPaymentLog("Helcim payment not completed: cancelled on the card terminal."); + global.apis.alert("The card payment was cancelled on the card terminal.", "Payment cancelled"); + currentReceiptID = null; return false; } - console.log("Got transaction ID from Helcim webhook:", paymentID); - purchaseResp = await apiRequest(`card-transactions/${paymentID}`, null, "GET"); - console.log("purchaseResp", purchaseResp); if (typeof purchaseResp?.errors != "undefined" && purchaseResp.errors.length > 0) { global.apis.pos.addOnscreenPaymentLog("Helcim card payment error: " + purchaseResp.errors[0]); global.apis.alert("Could not finish card payment: " + purchaseResp.errors[0], "Card Payment Error"); + currentReceiptID = null; return false; } @@ -200,6 +216,7 @@ exports.init = function () { pstring ) ); + currentReceiptID = null; return true; } } else if (purchaseResp.status == "DECLINED") { @@ -209,6 +226,7 @@ exports.init = function () { } else { global.apis.alert("The customer's card was declined.", "Card Error"); } + currentReceiptID = null; return false; } @@ -220,6 +238,7 @@ exports.init = function () { global.apis.alert("The transaction didn't complete correctly (Helcim card plugin reached an undefined state)", "Card Error"); } + currentReceiptID = null; return false; } catch (ex) { global.apis.pos.addOnscreenPaymentLog(`Error: ${ex.message}`); @@ -235,6 +254,8 @@ exports.init = function () { }, cancelCheckout: async function () { // The user requested to cancel the payment. + // Stop the webhook wait loop. + checkoutCancelled = true; }, finishPayment: async function ( {checkoutResponse}) { // Finish a payment that was authorized but not captured because checkout was called with capture = false