nets-service-sdk 1.1.18 → 1.1.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +144 -19
  2. package/package.json +5 -3
package/dist/index.js CHANGED
@@ -280,6 +280,17 @@ var require_hexRequest = __commonJS({
280
280
  console.log("buffer", buffer);
281
281
  return { buffer, ecn: body.ecn, hexString };
282
282
  };
283
+ module2.exports.generateFunction56Request = () => {
284
+ const date = moment().format("DDMMYYHHmmss");
285
+ const paddedValue = padWithLeadingZeros(date, "12");
286
+ const hexValue = paddedValue.toHexString();
287
+ const calculated = `0018${hexValue}35363031301C03`;
288
+ const calculatedXor = xorCalculation(calculated);
289
+ const hexString = `02${calculated}` + calculatedXor;
290
+ console.log("Recovery Function 56 Request:", hexString);
291
+ const buffer = Buffer.from(hexString, "hex");
292
+ return { buffer, ecn: date };
293
+ };
283
294
  }
284
295
  });
285
296
 
@@ -502,13 +513,19 @@ var require_parser = __commonJS({
502
513
  const data = { ...obj };
503
514
  const keys = Object.keys(data);
504
515
  const translatedJson = {};
516
+ const ecnError = CheckECNERROR(obj["ECN"]);
517
+ if (ecnError) {
518
+ translatedJson.status = ecnError.status;
519
+ translatedJson.description = ecnError.detail;
520
+ translatedJson.category = ecnError.category;
521
+ }
505
522
  keys.forEach((key) => {
506
523
  if (key == "01") {
507
524
  translatedJson["approvalCode"] = obj[key];
508
525
  }
509
526
  if (key == "02") {
510
527
  const statusResponse = statusCheck(obj[key]);
511
- if (statusResponse) {
528
+ if (statusResponse && !translatedJson.status) {
512
529
  translatedJson.status = statusResponse.status;
513
530
  translatedJson.description = statusResponse.detail;
514
531
  translatedJson.category = statusResponse.category;
@@ -516,12 +533,6 @@ var require_parser = __commonJS({
516
533
  translatedJson["balance"] = statusResponse.balance;
517
534
  }
518
535
  }
519
- const ecnnError = CheckECNERROR(obj["ECN"]);
520
- if (ecnnError) {
521
- translatedJson.status = ecnnError.status;
522
- translatedJson.description = ecnnError.detail;
523
- translatedJson.category = ecnnError.category;
524
- }
525
536
  translatedJson["responsetext"] = obj[key];
526
537
  }
527
538
  if (key == "03") {
@@ -602,7 +613,7 @@ var require_parser = __commonJS({
602
613
  if (key == "HC") {
603
614
  translatedJson["hostResponseCode"] = obj[key];
604
615
  const mapped = getResponseFromCode(obj[key]);
605
- if (mapped) {
616
+ if (mapped && !translatedJson.status) {
606
617
  translatedJson.status = mapped.status;
607
618
  translatedJson.description = mapped.detail;
608
619
  translatedJson.category = mapped.category;
@@ -648,6 +659,11 @@ var require_parser = __commonJS({
648
659
  translatedJson["receiptTextFormat"] = obj[key];
649
660
  }
650
661
  });
662
+ if (!translatedJson.status) {
663
+ translatedJson.status = "UNKNOWN";
664
+ translatedJson.description = "NO_RESPONSE_CODE";
665
+ translatedJson.category = "RETRY";
666
+ }
651
667
  logger.log({ level: "info", message: "jsonProcessor translated terminal response into JSON format." });
652
668
  return { translated: translatedJson, raw: obj };
653
669
  };
@@ -680,6 +696,9 @@ var require_parser = __commonJS({
680
696
  if (data?.indexOf("DECLINED") > -1) {
681
697
  return { status: "DECLINED", detail: "Transaction Declined", category: "HARD_FAIL" };
682
698
  }
699
+ if (data?.indexOf("CANCELLED") > -1) {
700
+ return { status: "USER_CANCELLED", detail: "USER_CANCELLED", category: "HARD_FAIL" };
701
+ }
683
702
  if (data?.indexOf("CARD NOT SUPPORTED") > -1) {
684
703
  return { status: "CARD_NOT_SUPPORTED", detail: "Card not supported", category: "HARD_FAIL" };
685
704
  }
@@ -922,6 +941,32 @@ var require_responseHandler = __commonJS({
922
941
  }
923
942
  return isMatch;
924
943
  };
944
+ module2.exports.terminalRecovery = (hexFrame) => {
945
+ const ecn = activePaymentEcn;
946
+ const parsedValue = netsPaymentParser(hexFrame, ecn);
947
+ const response = jsonProcessor(parsedValue);
948
+ if (response.translated) {
949
+ activePaymentEcn = null;
950
+ }
951
+ if (response.translated && (response.translated.category == "SUCCESS" || response.translated.status == "APPROVED")) {
952
+ logger.log({ level: "info", message: "\u2705 Recovery SUCCESS: Last transaction was APPROVED." });
953
+ sendMessage2("clientRoom", "PAYMENT_MESSAGE", {
954
+ success: true,
955
+ status: "SUCCESS",
956
+ response,
957
+ action: "COMPLETED"
958
+ });
959
+ sendPaymentResponseToCloud(response.translated);
960
+ } else {
961
+ logger.log({ level: "warn", message: "\u26A0\uFE0F Recovery FAILED: Transaction status could not be confirmed as APPROVED." });
962
+ sendMessage2("clientRoom", "PAYMENT_MESSAGE", {
963
+ status: "FAILED",
964
+ action: "CANCELLED",
965
+ message: "Payment needs verification / Failed",
966
+ reason: "RECOVERY_NOT_CONFIRMED"
967
+ });
968
+ }
969
+ };
925
970
  }
926
971
  });
927
972
 
@@ -951,13 +996,14 @@ var require_communication = __commonJS({
951
996
  var { initialiseRequest } = require_httpRequest();
952
997
  var requestType;
953
998
  var calculated;
954
- var MAX_COUNT = 3;
999
+ var MAX_COUNT = 2;
955
1000
  var WRONG_LRC_MAX_COUNT = 3;
956
1001
  var count = MAX_COUNT;
957
1002
  var lrcCount = WRONG_LRC_MAX_COUNT;
958
1003
  var ackOrNack = null;
959
1004
  var requestPayload = null;
960
1005
  var ackTimeout = null;
1006
+ var dataTimeout = null;
961
1007
  var ACK = Buffer.alloc(1, 6, "hex");
962
1008
  var NACK = Buffer.alloc(1, 21, "hex");
963
1009
  var dataBuffer = Buffer.alloc(0);
@@ -973,6 +1019,10 @@ var require_communication = __commonJS({
973
1019
  clearTimeout(ackTimeout);
974
1020
  ackTimeout = null;
975
1021
  }
1022
+ if (dataTimeout) {
1023
+ clearTimeout(dataTimeout);
1024
+ dataTimeout = null;
1025
+ }
976
1026
  };
977
1027
  module2.exports.checkACKorNACK = () => {
978
1028
  if (ackTimeout) clearTimeout(ackTimeout);
@@ -992,12 +1042,12 @@ var require_communication = __commonJS({
992
1042
  message: `On ACK/NACK Listener: Terminal did not respond with ACK/NACK after max ${count} retries. Sending TERMINAL_ERROR to client.`
993
1043
  });
994
1044
  sendMessage2("clientRoom", "PAYMENT_MESSAGE", {
995
- success: true,
1045
+ status: "FAILED",
996
1046
  action: "TERMINAL_ERROR"
997
1047
  });
998
1048
  }
999
1049
  }
1000
- }, 4e3);
1050
+ }, 2e3);
1001
1051
  };
1002
1052
  var resendData = () => {
1003
1053
  if (requestType == "STATUS_CHECK") {
@@ -1097,6 +1147,7 @@ var require_communication = __commonJS({
1097
1147
  clearTimeout(ackTimeout);
1098
1148
  ackTimeout = null;
1099
1149
  }
1150
+ exports2.startDataTimeout();
1100
1151
  if (byte === 21) {
1101
1152
  count--;
1102
1153
  if (count >= 0) {
@@ -1107,7 +1158,7 @@ var require_communication = __commonJS({
1107
1158
  level: "error",
1108
1159
  message: `Terminal responded with NACK multiple times. Max retries reached. Sending TERMINAL_ERROR.`
1109
1160
  });
1110
- sendMessage2("clientRoom", "PAYMENT_MESSAGE", { success: true, action: "TERMINAL_ERROR" });
1161
+ sendMessage2("clientRoom", "PAYMENT_MESSAGE", { status: "FAILED", action: "TERMINAL_ERROR" });
1111
1162
  }
1112
1163
  }
1113
1164
  continue;
@@ -1163,18 +1214,37 @@ var require_communication = __commonJS({
1163
1214
  }
1164
1215
  }
1165
1216
  };
1217
+ module2.exports.triggerRecovery = () => {
1218
+ const { generateFunction56Request } = require_hexRequest();
1219
+ exports2.reset();
1220
+ lrcCount = WRONG_LRC_MAX_COUNT;
1221
+ count = MAX_COUNT;
1222
+ const req = generateFunction56Request();
1223
+ requestType = "RECOVERY";
1224
+ calculated = req;
1225
+ logger.log({ level: "info", message: "\u{1F680} Triggering Recovery (Function 56) due to LRC failures..." });
1226
+ global.port.write(req.buffer);
1227
+ exports2.checkACKorNACK();
1228
+ };
1166
1229
  module2.exports.handleFullMessage = (fullFrame) => {
1167
- const { checkLrc: checkLrc2, terminalStatus: terminalStatus2, terminalLogon: terminalLogon2, terminalPayment: terminalPayment2, terminalCreditPayment: terminalCreditPayment2 } = require_responseHandler();
1230
+ const { checkLrc: checkLrc2, terminalStatus: terminalStatus2, terminalLogon: terminalLogon2, terminalPayment: terminalPayment2, terminalCreditPayment: terminalCreditPayment2, terminalRecovery } = require_responseHandler();
1168
1231
  if (ackTimeout) {
1169
1232
  clearTimeout(ackTimeout);
1170
1233
  ackTimeout = null;
1171
1234
  }
1235
+ if (dataTimeout) {
1236
+ clearTimeout(dataTimeout);
1237
+ dataTimeout = null;
1238
+ }
1172
1239
  ackOrNack = Buffer.from([6]);
1173
1240
  const hexFrame = fullFrame.toString("hex").toUpperCase();
1174
1241
  logger.log({ level: "info", message: `Full frame processed: ${hexFrame}` });
1175
- if (checkLrc2(hexFrame)) {
1242
+ const isLrcCorrect = checkLrc2(hexFrame);
1243
+ if (isLrcCorrect) {
1176
1244
  logger.log({ level: "info", message: `LRC Correct. Sending ACK (0x06).` });
1177
1245
  global.port.write(ACK);
1246
+ lrcCount = WRONG_LRC_MAX_COUNT;
1247
+ count = MAX_COUNT;
1178
1248
  logger.log({ level: "info", message: `requestType: ${requestType}` });
1179
1249
  if (requestType === "STATUS_CHECK") {
1180
1250
  terminalStatus2(calculated?.ecn, hexFrame);
@@ -1184,12 +1254,65 @@ var require_communication = __commonJS({
1184
1254
  terminalPayment2(hexFrame, calculated?.ecn);
1185
1255
  } else if (requestType === "CREDIT_PAYMENT") {
1186
1256
  terminalCreditPayment2(hexFrame, calculated?.ecn);
1257
+ } else if (requestType === "RECOVERY") {
1258
+ terminalRecovery(hexFrame);
1187
1259
  }
1188
1260
  } else {
1189
- logger.log({ level: "error", message: `LRC Incorrect. Sending NACK (0x15).` });
1190
- global.port.write(NACK);
1261
+ lrcCount--;
1262
+ if (lrcCount > 0) {
1263
+ logger.log({ level: "error", message: `LRC Incorrect. Sending NACK (0x15). Retries left: ${lrcCount}` });
1264
+ global.port.write(NACK);
1265
+ } else {
1266
+ if (hexFrame.indexOf("415050524F564544") > -1) {
1267
+ logger.log({ level: "info", message: "\u2705 LRC Incorrect 3 times, but APPROVED found in hex payload. Accepting with ACK." });
1268
+ global.port.write(ACK);
1269
+ lrcCount = WRONG_LRC_MAX_COUNT;
1270
+ count = MAX_COUNT;
1271
+ if (requestType === "PAYMENT") terminalPayment2(hexFrame, calculated?.ecn);
1272
+ else if (requestType === "CREDIT_PAYMENT") terminalCreditPayment2(hexFrame, calculated?.ecn);
1273
+ else if (requestType === "RECOVERY") terminalRecovery(hexFrame);
1274
+ else if (requestType === "LOGON") terminalLogon2(calculated?.ecn, hexFrame);
1275
+ else if (requestType === "STATUS_CHECK") terminalStatus2(calculated?.ecn, hexFrame);
1276
+ } else {
1277
+ logger.log({ level: "warn", message: `LRC Incorrect 3 times and NO approval found. Stopping.` });
1278
+ global.port.write(NACK);
1279
+ if (ackTimeout) {
1280
+ clearTimeout(ackTimeout);
1281
+ ackTimeout = null;
1282
+ }
1283
+ if (requestType !== "RECOVERY") {
1284
+ sendMessage2("clientRoom", "PAYMENT_MESSAGE", {
1285
+ status: "UNKNOWN",
1286
+ action: "VERIFYING_STATUS",
1287
+ message: "Payment status uncertain. Please wait while we verify...",
1288
+ reason: "LRC_FAILURE"
1289
+ });
1290
+ setTimeout(() => exports2.triggerRecovery(), 2e3);
1291
+ } else {
1292
+ sendMessage2("clientRoom", "PAYMENT_MESSAGE", {
1293
+ status: "FAILED",
1294
+ action: "CANCELLED",
1295
+ message: "Payment needs manual verification / Recovery failed.",
1296
+ reason: "RECOVERY_LRC_FAILURE"
1297
+ });
1298
+ }
1299
+ }
1300
+ }
1191
1301
  }
1192
1302
  };
1303
+ module2.exports.startDataTimeout = () => {
1304
+ if (dataTimeout) clearTimeout(dataTimeout);
1305
+ dataTimeout = setTimeout(() => {
1306
+ dataTimeout = null;
1307
+ logger.error({ level: "error", message: `Terminal response time out (60 seconds) after ACK.` });
1308
+ sendMessage2("clientRoom", "PAYMENT_MESSAGE", {
1309
+ status: "FAILED",
1310
+ action: "TERMINAL_ERROR",
1311
+ message: "Terminal response time out (60 seconds)"
1312
+ });
1313
+ exports2.reset();
1314
+ }, 6e4);
1315
+ };
1193
1316
  module2.exports.checkPortConnection = async () => {
1194
1317
  const portPath = config.simulation ? config.simulationPort : config.com;
1195
1318
  try {
@@ -1292,7 +1415,7 @@ var require_package = __commonJS({
1292
1415
  "package.json"(exports2, module2) {
1293
1416
  module2.exports = {
1294
1417
  name: "nets-service-sdk",
1295
- version: "1.1.18",
1418
+ version: "1.1.20",
1296
1419
  description: "Utility functions for Nets Service",
1297
1420
  source: "src/index.js",
1298
1421
  main: "dist/index.js",
@@ -1301,7 +1424,7 @@ var require_package = __commonJS({
1301
1424
  scripts: {
1302
1425
  build: "esbuild src/index.js --bundle --platform=node --packages=external --outfile=dist/index.js",
1303
1426
  watch: "microbundle watch",
1304
- test: 'echo "Error: no test specified" && exit 1'
1427
+ test: "jest"
1305
1428
  },
1306
1429
  keywords: [
1307
1430
  "nets",
@@ -1327,10 +1450,12 @@ var require_package = __commonJS({
1327
1450
  request: "^2.88.2",
1328
1451
  serialport: "^10.5.0",
1329
1452
  "socket.io-client": "^4.7.2",
1330
- winston: "^3.8.2"
1453
+ winston: "^3.8.2",
1454
+ "winston-daily-rotate-file": "^5.0.0"
1331
1455
  },
1332
1456
  devDependencies: {
1333
1457
  esbuild: "^0.27.0",
1458
+ jest: "^30.3.0",
1334
1459
  microbundle: "^0.15.1"
1335
1460
  }
1336
1461
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nets-service-sdk",
3
- "version": "1.1.18",
3
+ "version": "1.1.20",
4
4
  "description": "Utility functions for Nets Service",
5
5
  "source": "src/index.js",
6
6
  "main": "dist/index.js",
@@ -9,7 +9,7 @@
9
9
  "scripts": {
10
10
  "build": "esbuild src/index.js --bundle --platform=node --packages=external --outfile=dist/index.js",
11
11
  "watch": "microbundle watch",
12
- "test": "echo \"Error: no test specified\" && exit 1"
12
+ "test": "jest"
13
13
  },
14
14
  "keywords": [
15
15
  "nets",
@@ -35,10 +35,12 @@
35
35
  "request": "^2.88.2",
36
36
  "serialport": "^10.5.0",
37
37
  "socket.io-client": "^4.7.2",
38
- "winston": "^3.8.2"
38
+ "winston": "^3.8.2",
39
+ "winston-daily-rotate-file": "^5.0.0"
39
40
  },
40
41
  "devDependencies": {
41
42
  "esbuild": "^0.27.0",
43
+ "jest": "^30.3.0",
42
44
  "microbundle": "^0.15.1"
43
45
  }
44
46
  }