@aptos-scp/scp-component-rn-device-services 0.2.6 → 0.3.0
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.
- package/ios/AurusEnterpriseSDK.framework/AurusEnterpriseSDK +0 -0
- package/ios/AurusEnterpriseSDK.framework/Headers/AurusEnterpriseSDK.h +30 -36
- package/ios/SCPRNDeviceServices/AurusPaymentTerminal.m +33 -37
- package/lib/AurusDevice/AurusDevice.d.ts +24 -22
- package/lib/AurusDevice/AurusDevice.js +204 -245
- package/lib/AurusDevice/AurusDevice.js.map +1 -1
- package/lib/AurusDevice/constants.d.ts +6 -5
- package/lib/AurusDevice/constants.js +8 -7
- package/lib/AurusDevice/constants.js.map +1 -1
- package/lib/AurusDevice/sdk-interface/AurusPaymentSupport.d.ts +2 -2
- package/lib/AurusDevice/sdk-interface/AurusPaymentSupport.js +21 -18
- package/lib/AurusDevice/sdk-interface/AurusPaymentSupport.js.map +1 -1
- package/lib/AurusDevice/sdk-interface/Upgrade.d.ts +23 -0
- package/lib/AurusDevice/sdk-interface/Upgrade.js +9 -0
- package/lib/AurusDevice/sdk-interface/Upgrade.js.map +1 -0
- package/lib/PaymentDeviceFactory.d.ts +4 -4
- package/lib/PaymentDeviceFactory.js +3 -3
- package/lib/PaymentDeviceFactory.js.map +1 -1
- package/lib/PaymentDeviceService.d.ts +4 -3
- package/lib/PaymentDeviceService.js +47 -30
- package/lib/PaymentDeviceService.js.map +1 -1
- package/lib/ScannerDeviceFactory.d.ts +4 -4
- package/lib/ScannerDeviceFactory.js +3 -3
- package/lib/ScannerDeviceFactory.js.map +1 -1
- package/lib/ScannerDeviceService.d.ts +2 -2
- package/lib/ScannerDeviceService.js +6 -2
- package/lib/ScannerDeviceService.js.map +1 -1
- package/lib/configs/inversify/inversify.config.js +1 -6
- package/lib/configs/inversify/inversify.config.js.map +1 -1
- package/lib/constants/constants.d.ts +6 -8
- package/lib/constants/constants.js +6 -8
- package/lib/constants/constants.js.map +1 -1
- package/lib/interfaces/IDeviceStatus.d.ts +1 -0
- package/lib/interfaces/payment/IPayment.d.ts +4 -9
- package/lib/interfaces/scanner/IScanner.d.ts +2 -8
- package/package.json +1 -1
|
@@ -35,10 +35,14 @@ let AurusDevice = class AurusDevice {
|
|
|
35
35
|
* are created in the constructor, which only accepts JavaScript parameters.
|
|
36
36
|
*/
|
|
37
37
|
constructor() {
|
|
38
|
-
this.
|
|
38
|
+
this._initializeCalled = false;
|
|
39
39
|
this._listenersAdded = false;
|
|
40
|
-
this.
|
|
40
|
+
this._registrationInProgress = false; // EMV Config now happens during registration
|
|
41
|
+
this._waitingForDeviceConnected = false;
|
|
42
|
+
this._scannerEnabled = false;
|
|
41
43
|
this._paymentEnvironment = "Aurus"; // string representation of payment environment for trans object
|
|
44
|
+
this._requestInProgress = false;
|
|
45
|
+
this._requestQueue = [];
|
|
42
46
|
const entryMessage = logger.traceEntry("constructor");
|
|
43
47
|
this._devicePaymentTerminal = react_native_1.NativeModules.AurusPaymentTerminal;
|
|
44
48
|
this._nativeEventEmitter = new react_native_1.NativeEventEmitter(react_native_1.NativeModules.AurusPaymentTerminal);
|
|
@@ -49,15 +53,22 @@ let AurusDevice = class AurusDevice {
|
|
|
49
53
|
const entryMessage = logger.traceEntry("configurePaymentDevice", emitter, config);
|
|
50
54
|
this._paymentEmitter = emitter;
|
|
51
55
|
this._paymentConfig = config;
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
56
|
+
let payEnvDesc = "Unknown Aurus Environment";
|
|
57
|
+
let storeType = "";
|
|
58
|
+
let corpId = "";
|
|
59
|
+
let hostUrl = "";
|
|
60
|
+
if (config && config.vendorConfiguration) {
|
|
61
|
+
storeType = config.vendorConfiguration.storeType;
|
|
62
|
+
corpId = config.vendorConfiguration.corpId;
|
|
63
|
+
hostUrl = config.vendorConfiguration.hostUrl;
|
|
64
|
+
if (storeType === "PROD") {
|
|
65
|
+
payEnvDesc = "Aurus Production";
|
|
66
|
+
}
|
|
67
|
+
else if (storeType === "UAT") {
|
|
68
|
+
payEnvDesc = "Aurus UAT Sandbox";
|
|
69
|
+
}
|
|
60
70
|
}
|
|
71
|
+
this._paymentEnvironment = `${payEnvDesc} (StoreType: ${storeType}, CorpID: ${corpId}, HostUrl: ${hostUrl})`;
|
|
61
72
|
logger.traceExit(entryMessage);
|
|
62
73
|
});
|
|
63
74
|
}
|
|
@@ -66,6 +77,7 @@ let AurusDevice = class AurusDevice {
|
|
|
66
77
|
const entryMessage = logger.traceEntry("configureScannerDevice", emitter, config);
|
|
67
78
|
this._scannerEmitter = emitter;
|
|
68
79
|
this._scannerConfig = config;
|
|
80
|
+
this._scannerEnabled = config.initiallyEnabled;
|
|
69
81
|
logger.traceExit(entryMessage);
|
|
70
82
|
});
|
|
71
83
|
}
|
|
@@ -97,10 +109,18 @@ let AurusDevice = class AurusDevice {
|
|
|
97
109
|
logger.traceExit(entryMessage);
|
|
98
110
|
});
|
|
99
111
|
}
|
|
112
|
+
captureVoid(authRequest) {
|
|
113
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
114
|
+
const entryMessage = logger.traceEntry("captureVoid", authRequest);
|
|
115
|
+
yield this.authorize(Object.assign({}, authRequest, { requestType: _1.PaymentRequestType.Void }));
|
|
116
|
+
logger.traceExit(entryMessage);
|
|
117
|
+
});
|
|
118
|
+
}
|
|
100
119
|
enableScannerDevice() {
|
|
101
120
|
return __awaiter(this, void 0, void 0, function* () {
|
|
102
121
|
const entryMessage = logger.traceEntry("enableScannerDevice");
|
|
103
122
|
this._scannerEnabled = true;
|
|
123
|
+
this.sendUpgradeRequest(constants_1.UpgradeType.ENABLE_SCANNER);
|
|
104
124
|
logger.traceExit(entryMessage);
|
|
105
125
|
});
|
|
106
126
|
}
|
|
@@ -108,6 +128,7 @@ let AurusDevice = class AurusDevice {
|
|
|
108
128
|
return __awaiter(this, void 0, void 0, function* () {
|
|
109
129
|
const entryMessage = logger.traceEntry("disableScannerDevice");
|
|
110
130
|
this._scannerEnabled = false;
|
|
131
|
+
this.sendUpgradeRequest(constants_1.UpgradeType.DISABLE_SCANNER);
|
|
111
132
|
logger.traceExit(entryMessage);
|
|
112
133
|
});
|
|
113
134
|
}
|
|
@@ -139,9 +160,9 @@ let AurusDevice = class AurusDevice {
|
|
|
139
160
|
logger.traceExit(entryMessage);
|
|
140
161
|
});
|
|
141
162
|
}
|
|
142
|
-
|
|
163
|
+
giftcardVoid(authRequest) {
|
|
143
164
|
return __awaiter(this, void 0, void 0, function* () {
|
|
144
|
-
const entryMessage = logger.traceEntry("
|
|
165
|
+
const entryMessage = logger.traceEntry("giftcardVoid", authRequest);
|
|
145
166
|
yield this.authorize(Object.assign({}, authRequest, { requestType: _1.PaymentRequestType.Void }));
|
|
146
167
|
logger.traceExit(entryMessage);
|
|
147
168
|
});
|
|
@@ -175,9 +196,7 @@ let AurusDevice = class AurusDevice {
|
|
|
175
196
|
processTimeout() {
|
|
176
197
|
return __awaiter(this, void 0, void 0, function* () {
|
|
177
198
|
const entryMessage = logger.traceEntry("processTimeout");
|
|
178
|
-
|
|
179
|
-
sdk_interface_1.AurusSupport.authResponse.status = "TIMEOUT WAITING FOR RESPONSE";
|
|
180
|
-
this._paymentEmitter.emit(_1.EventResponseTypes.Authorization, sdk_interface_1.AurusSupport.authResponse);
|
|
199
|
+
this.emitAuthorizationResponse(_1.ResponseCodes.Timeout, "TIMEOUT WAITING FOR RESPONSE");
|
|
181
200
|
//Send cancel to aurus
|
|
182
201
|
this.sendCancelTranRequest();
|
|
183
202
|
logger.traceExit(entryMessage);
|
|
@@ -188,24 +207,15 @@ let AurusDevice = class AurusDevice {
|
|
|
188
207
|
const entryMessage = logger.traceEntry("authorize", authRequest);
|
|
189
208
|
sdk_interface_1.AurusSupport.authRequest = authRequest;
|
|
190
209
|
sdk_interface_1.AurusSupport.authResponse = Object.assign({ paymentEnvironment: this._paymentEnvironment }, authRequest);
|
|
191
|
-
if (
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
}
|
|
210
|
+
if (this._registrationInProgress) {
|
|
211
|
+
logger.debug("Payment is unavailalbe while device registration is in progress. Emitting error response.");
|
|
212
|
+
this.emitAuthorizationResponse(_1.ResponseCodes.Error, "Payment Unavailable. Device Registration in Progress");
|
|
213
|
+
}
|
|
214
|
+
else if (sdk_interface_1.AurusSupport.requireGetCard(authRequest)) {
|
|
215
|
+
this.sendGetCardBin(authRequest);
|
|
198
216
|
}
|
|
199
217
|
else {
|
|
200
|
-
|
|
201
|
-
if (this._initInProgress) {
|
|
202
|
-
sdk_interface_1.AurusSupport.authResponse.status = "EMV INIT IN PROGRESS";
|
|
203
|
-
}
|
|
204
|
-
else if (this._registrationInProgress) {
|
|
205
|
-
sdk_interface_1.AurusSupport.authResponse.status = "DEVICE REGISTRATION IN PROGRESS";
|
|
206
|
-
}
|
|
207
|
-
logger.debug(`Payment not initialized. Sending response: ${JSON.stringify(sdk_interface_1.AurusSupport.authResponse)}`);
|
|
208
|
-
this._paymentEmitter.emit(_1.EventResponseTypes.Authorization, sdk_interface_1.AurusSupport.authResponse);
|
|
218
|
+
this.sendCardTransRequest();
|
|
209
219
|
}
|
|
210
220
|
logger.traceExit(entryMessage);
|
|
211
221
|
});
|
|
@@ -214,17 +224,18 @@ let AurusDevice = class AurusDevice {
|
|
|
214
224
|
return __awaiter(this, void 0, void 0, function* () {
|
|
215
225
|
const entryMessage = logger.traceEntry("initializeNative");
|
|
216
226
|
if (!this._listenersAdded) {
|
|
227
|
+
this._listenersAdded = true;
|
|
217
228
|
let context = {};
|
|
218
229
|
this._nativeSubscriptions = [
|
|
219
230
|
this._nativeEventEmitter.addListener(native_onAESDKResponse, this.onAESDKResponse.bind(this), context),
|
|
220
231
|
this._nativeEventEmitter.addListener(native_onNotificationReceived, this.onNotificationReceived.bind(this), context),
|
|
221
232
|
this._nativeEventEmitter.addListener(native_onAESDKLogResponse, this.onAESDKLogResponse.bind(this), context)
|
|
222
233
|
];
|
|
223
|
-
this._listenersAdded = true;
|
|
224
234
|
}
|
|
225
|
-
if (!this.
|
|
235
|
+
if (!this._initializeCalled) {
|
|
236
|
+
this._initializeCalled = true;
|
|
237
|
+
this._waitingForDeviceConnected = true;
|
|
226
238
|
this._devicePaymentTerminal.initialize();
|
|
227
|
-
this._initialized = true;
|
|
228
239
|
}
|
|
229
240
|
logger.traceExit(entryMessage);
|
|
230
241
|
});
|
|
@@ -252,19 +263,14 @@ let AurusDevice = class AurusDevice {
|
|
|
252
263
|
// of events can be sent or just for safety.
|
|
253
264
|
let withResponse = args[0];
|
|
254
265
|
logger.debug(`In onAESDKResponse, withResponse: ${JSON.stringify(withResponse)}`);
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
this._paymentEmitter.emit(_1.EventResponseTypes.PaymentDeviceStatus, sdk_interface_1.AurusSupport.paymentStatus);
|
|
261
|
-
sdk_interface_1.AurusSupport.paymentStatus = { deviceAvailable: false };
|
|
262
|
-
}
|
|
263
|
-
if (returnServer & constants_1.ResponseType.AuthResponse) {
|
|
264
|
-
// If returnServer has AuthResponse, send IAuthorizationResponse to POS.
|
|
265
|
-
logger.debug(`In onAESDKResponse, publishing authResponse: ${JSON.stringify(sdk_interface_1.AurusSupport.authResponse)}`);
|
|
266
|
-
this._paymentEmitter.emit(_1.EventResponseTypes.Authorization, sdk_interface_1.AurusSupport.authResponse);
|
|
266
|
+
if (this._requestInProgress) {
|
|
267
|
+
this._requestInProgress = false;
|
|
268
|
+
if (this._requestQueue.length > 0) {
|
|
269
|
+
this.sendRequest(this._requestQueue.shift());
|
|
270
|
+
}
|
|
267
271
|
}
|
|
272
|
+
// Parse xml and determine next steps. Call back into native if needed.
|
|
273
|
+
this.handleAESDKResponse(withResponse);
|
|
268
274
|
}
|
|
269
275
|
else {
|
|
270
276
|
throw logger.throwing(new Error("Empty event received. withResponse data is missing"), entryMessage);
|
|
@@ -275,28 +281,28 @@ let AurusDevice = class AurusDevice {
|
|
|
275
281
|
const entryMessage = logger.traceEntry("sendCancelTranRequest");
|
|
276
282
|
sdk_interface_1.AurusSupport.requestType = constants_1.RequestTypes.CancelTransaction;
|
|
277
283
|
let xmlreq = sdk_interface_1.AurusSupport.createCancelTranRequest();
|
|
278
|
-
this.
|
|
284
|
+
this.sendRequest(xmlreq);
|
|
279
285
|
logger.traceExit(entryMessage);
|
|
280
286
|
}
|
|
281
287
|
sendCancelLastTranRequest() {
|
|
282
288
|
const entryMessage = logger.traceEntry("sendCancelLastTranRequest");
|
|
283
289
|
sdk_interface_1.AurusSupport.requestType = constants_1.RequestTypes.CancelTransaction;
|
|
284
290
|
let xmlreq = sdk_interface_1.AurusSupport.createCancelLastTranRequest();
|
|
285
|
-
this.
|
|
291
|
+
this.sendRequest(xmlreq);
|
|
286
292
|
logger.traceExit(entryMessage);
|
|
287
293
|
}
|
|
288
294
|
sendTransRequest(getCardBinResp) {
|
|
289
295
|
const entryMessage = logger.traceEntry("sendTransRequest", getCardBinResp);
|
|
290
296
|
sdk_interface_1.AurusSupport.requestType = constants_1.RequestTypes.Transaction;
|
|
291
297
|
let xmlreq = sdk_interface_1.AurusSupport.createCardTranRequest(getCardBinResp);
|
|
292
|
-
this.
|
|
298
|
+
this.sendRequest(xmlreq);
|
|
293
299
|
logger.traceExit(entryMessage);
|
|
294
300
|
}
|
|
295
301
|
sendCardTransRequest() {
|
|
296
302
|
const entryMessage = logger.traceEntry("sendCardTransRequest");
|
|
297
303
|
sdk_interface_1.AurusSupport.requestType = constants_1.RequestTypes.Transaction;
|
|
298
304
|
let xmlreq = sdk_interface_1.AurusSupport.createCardTranRequest();
|
|
299
|
-
this.
|
|
305
|
+
this.sendRequest(xmlreq);
|
|
300
306
|
logger.traceExit(entryMessage);
|
|
301
307
|
}
|
|
302
308
|
/**
|
|
@@ -307,44 +313,52 @@ let AurusDevice = class AurusDevice {
|
|
|
307
313
|
const entryMessage = logger.traceEntry("sendGetCardBin", authRequest);
|
|
308
314
|
sdk_interface_1.AurusSupport.requestType = constants_1.RequestTypes.GetCardBin;
|
|
309
315
|
let xmlreq = sdk_interface_1.AurusSupport.createGetCardBinRequest();
|
|
310
|
-
this.
|
|
316
|
+
this.sendRequest(xmlreq);
|
|
311
317
|
logger.traceExit(entryMessage);
|
|
312
318
|
}
|
|
313
319
|
/**
|
|
314
320
|
* Sends an AESDKRegistrationRequest to register the device
|
|
315
|
-
* @param authRequest
|
|
316
321
|
*/
|
|
317
|
-
sendAESDKRegistration(
|
|
318
|
-
const entryMessage = logger.traceEntry("sendAESDKRegistration"
|
|
322
|
+
sendAESDKRegistration() {
|
|
323
|
+
const entryMessage = logger.traceEntry("sendAESDKRegistration");
|
|
319
324
|
sdk_interface_1.AurusSupport.requestType = constants_1.RequestTypes.Registration;
|
|
320
|
-
let xmlreq = sdk_interface_1.AurusSupport.createAESDKRegistrationRequest();
|
|
325
|
+
let xmlreq = sdk_interface_1.AurusSupport.createAESDKRegistrationRequest(this._paymentConfig.storeNumber, this._paymentConfig.terminalNumber, this._paymentConfig.vendorConfiguration.storeType, this._paymentConfig.vendorConfiguration.corpId, this._paymentConfig.vendorConfiguration.hostUrl);
|
|
321
326
|
this._registrationInProgress = true;
|
|
322
|
-
this.
|
|
327
|
+
this.sendRequest(xmlreq);
|
|
328
|
+
logger.traceExit(entryMessage);
|
|
329
|
+
}
|
|
330
|
+
sendUpgradeRequest(upgradeType) {
|
|
331
|
+
const entryMessage = logger.traceEntry("sendUpgradeRequest");
|
|
332
|
+
if (upgradeType !== constants_1.UpgradeType.ENABLE_SCANNER && upgradeType !== constants_1.UpgradeType.DISABLE_SCANNER) {
|
|
333
|
+
// Enable/Disable scanner is fire and forget and may interrupt other calls. Don't update the request type.
|
|
334
|
+
sdk_interface_1.AurusSupport.requestType = constants_1.RequestTypes.Upgrade;
|
|
335
|
+
}
|
|
336
|
+
let xmlreq = sdk_interface_1.AurusSupport.createUpgradeRequest(this._paymentConfig.storeNumber, this._paymentConfig.terminalNumber, upgradeType);
|
|
337
|
+
this.sendRequest(xmlreq);
|
|
323
338
|
logger.traceExit(entryMessage);
|
|
324
339
|
}
|
|
325
340
|
handleAESDKResponse(xml) {
|
|
326
341
|
const entryMessage = logger.traceEntry("handleAESDKResponse", xml);
|
|
327
|
-
let returnServer = constants_1.ResponseType.None;
|
|
328
342
|
let xmlResponse = this.convertXmlToJs(xml);
|
|
329
343
|
if (!xmlResponse) {
|
|
330
344
|
logger.warn(`In handleAESDKResponse, unable to convert to JSON: ${xml}`);
|
|
331
345
|
}
|
|
332
346
|
else if (constants_1.AesdkResponseTypes.Registration in xmlResponse) {
|
|
333
|
-
|
|
347
|
+
this.processAESDKRegistration(xmlResponse[constants_1.AesdkResponseTypes.Registration]);
|
|
334
348
|
}
|
|
335
349
|
else if (constants_1.AesdkResponseTypes.GetCardBin in xmlResponse) {
|
|
336
|
-
|
|
350
|
+
this.processGetCardBin(xmlResponse[constants_1.AesdkResponseTypes.GetCardBin]);
|
|
337
351
|
}
|
|
338
352
|
else if (constants_1.AesdkResponseTypes.Transaction in xmlResponse) {
|
|
339
|
-
|
|
353
|
+
this.processTrans(xmlResponse[constants_1.AesdkResponseTypes.Transaction]);
|
|
340
354
|
}
|
|
341
355
|
else if (constants_1.AesdkResponseTypes.AESDK in xmlResponse) {
|
|
342
|
-
|
|
356
|
+
this.processAESDK(xmlResponse[constants_1.AesdkResponseTypes.AESDK]);
|
|
343
357
|
}
|
|
344
358
|
else if (constants_1.AesdkResponseTypes.CancelTransaction in xmlResponse) {
|
|
345
|
-
|
|
359
|
+
this.processCancelTrans(xmlResponse[constants_1.AesdkResponseTypes.CancelTransaction]);
|
|
346
360
|
}
|
|
347
|
-
|
|
361
|
+
logger.traceExit(entryMessage);
|
|
348
362
|
}
|
|
349
363
|
convertXmlToJs(xml) {
|
|
350
364
|
const entryMessage = logger.traceEntry("convertXmlToJs", xml);
|
|
@@ -358,11 +372,9 @@ let AurusDevice = class AurusDevice {
|
|
|
358
372
|
}
|
|
359
373
|
processTrans(response) {
|
|
360
374
|
const entryMessage = logger.traceEntry("processTrans", response);
|
|
361
|
-
let responseType = constants_1.ResponseType.AuthResponse;
|
|
362
375
|
let tranDetails = response.TransDetailsData.TransDetailData;
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
if (sdk_interface_1.AurusSupport.authResponse.responseCode === _1.ResponseCodes.Approved) {
|
|
376
|
+
const responseCode = this.mapAurusResponseCode(tranDetails.ResponseCode.value);
|
|
377
|
+
if (responseCode === _1.ResponseCodes.Approved) {
|
|
366
378
|
sdk_interface_1.AurusSupport.authResponse.approvedAmount = sdk_interface_1.AurusSupport.stringToMoney(tranDetails.TransactionAmount.value);
|
|
367
379
|
sdk_interface_1.AurusSupport.authResponse.cardNumber = tranDetails.CardNumber.value;
|
|
368
380
|
sdk_interface_1.AurusSupport.authResponse.cardType = this.mapAurusCardType(tranDetails.CardType.value);
|
|
@@ -373,7 +385,7 @@ let AurusDevice = class AurusDevice {
|
|
|
373
385
|
sdk_interface_1.AurusSupport.authResponse.EMVData = this.parseEMVData(tranDetails.EMVData.value);
|
|
374
386
|
sdk_interface_1.AurusSupport.authResponse.EMVData.receiptData = tranDetails.EMVData && tranDetails.EMVData.value &&
|
|
375
387
|
tranDetails.EMVData.value.replace(/~/g, ": ").split("[FS]");
|
|
376
|
-
// FIXME: AdditionalReceiptInfo should be parsed based on the format of the aurus response.
|
|
388
|
+
// FIXME: AdditionalReceiptInfo should be parsed based on the format of the aurus response.
|
|
377
389
|
// Resolve when we receive next sdk with correct format
|
|
378
390
|
sdk_interface_1.AurusSupport.authResponse.receiptData =
|
|
379
391
|
tranDetails.AdditionalReceiptInfo && [tranDetails.AdditionalReceiptInfo.value];
|
|
@@ -382,32 +394,27 @@ let AurusDevice = class AurusDevice {
|
|
|
382
394
|
this.mapAurusSignatureRequired(tranDetails.SignatureReceiptFlag.value);
|
|
383
395
|
sdk_interface_1.AurusSupport.authResponse.pinCaptured = this.mapAurusPinCaptured(tranDetails.SignatureReceiptFlag.value);
|
|
384
396
|
}
|
|
385
|
-
|
|
397
|
+
this.emitAuthorizationResponse(responseCode, tranDetails.TransactionResponseText.value);
|
|
398
|
+
logger.traceExit(entryMessage);
|
|
386
399
|
}
|
|
387
400
|
processGetCardBin(response) {
|
|
388
401
|
const entryMessage = logger.traceEntry("processGetCardBin", response);
|
|
389
|
-
let responseType = constants_1.ResponseType.None;
|
|
390
402
|
if (sdk_interface_1.AurusSupport.requestType === constants_1.RequestTypes.GetCardBin) {
|
|
391
403
|
if (response.ResponseCode.value === constants_1.ResponseCodes.Approved) {
|
|
392
404
|
this.sendTransRequest(response);
|
|
393
405
|
}
|
|
394
406
|
else {
|
|
395
|
-
|
|
396
|
-
sdk_interface_1.AurusSupport.authResponse.responseCode = this.mapAurusResponseCode(response.ResponseCode.value);
|
|
397
|
-
sdk_interface_1.AurusSupport.authResponse.status = response.ResponseText.value;
|
|
407
|
+
this.emitAuthorizationResponse(this.mapAurusResponseCode(response.ResponseCode.value), response.ResponseText.value);
|
|
398
408
|
}
|
|
399
409
|
}
|
|
400
410
|
else {
|
|
401
411
|
//handle additional request types with getcardbinresponses
|
|
402
|
-
|
|
403
|
-
sdk_interface_1.AurusSupport.authResponse.responseCode = _1.ResponseCodes.Error;
|
|
404
|
-
sdk_interface_1.AurusSupport.authResponse.status = response.ResponseText.value;
|
|
412
|
+
this.emitAuthorizationResponse(_1.ResponseCodes.Error, response.ResponseText.value);
|
|
405
413
|
}
|
|
406
|
-
|
|
414
|
+
logger.traceExit(entryMessage);
|
|
407
415
|
}
|
|
408
416
|
processCancelTrans(response) {
|
|
409
417
|
const entryMessage = logger.traceEntry("processCancelTrans", response);
|
|
410
|
-
let responseType = constants_1.ResponseType.None;
|
|
411
418
|
if (response.ResponseCode.value === constants_1.ResponseCodes.Approved) {
|
|
412
419
|
logger.debug(`processCancelTrans success: ${sdk_interface_1.AurusSupport.authResponse.posReference}`);
|
|
413
420
|
}
|
|
@@ -416,44 +423,39 @@ let AurusDevice = class AurusDevice {
|
|
|
416
423
|
logger.debug(`processCancelTrans failed, attempting CancelLastTrans: ${sdk_interface_1.AurusSupport.authRequest.transactionNumber}`);
|
|
417
424
|
this.sendCancelLastTranRequest();
|
|
418
425
|
}
|
|
419
|
-
|
|
426
|
+
logger.traceExit(entryMessage);
|
|
420
427
|
}
|
|
421
428
|
processAESDKRegistration(response) {
|
|
422
429
|
const entryMessage = logger.traceEntry("processAESDKRegistration", response);
|
|
423
|
-
let responseType = constants_1.ResponseType.None;
|
|
424
430
|
if (sdk_interface_1.AurusSupport.requestType === constants_1.RequestTypes.GetCardBin) {
|
|
425
|
-
responseType |= constants_1.ResponseType.AuthResponse;
|
|
426
|
-
sdk_interface_1.AurusSupport.authResponse.responseCode = _1.ResponseCodes.Error;
|
|
427
|
-
sdk_interface_1.AurusSupport.authResponse.status = response.ResponseText.value;
|
|
428
431
|
if (response.ResponseCode.value === constants_1.ResponseCodes.DeviceNotRegistered) {
|
|
429
|
-
this.sendAESDKRegistration(
|
|
432
|
+
this.sendAESDKRegistration();
|
|
430
433
|
}
|
|
434
|
+
this.emitAuthorizationResponse(_1.ResponseCodes.Error, response.ResponseText.value);
|
|
431
435
|
}
|
|
432
436
|
if (sdk_interface_1.AurusSupport.requestType === constants_1.RequestTypes.Registration) {
|
|
433
|
-
responseType |= constants_1.ResponseType.PaymentStatus;
|
|
434
|
-
sdk_interface_1.AurusSupport.paymentStatus.deviceAvailable = true;
|
|
435
|
-
sdk_interface_1.AurusSupport.paymentStatus.status = response.ResponseText.value;
|
|
436
|
-
sdk_interface_1.AurusSupport.paymentStatus.statusCode = _1.StatusCode.InitializationComplete;
|
|
437
437
|
this._registrationInProgress = false;
|
|
438
|
+
this.emitPaymentStatus(true, _1.StatusCode.InitializationComplete);
|
|
439
|
+
//enable/disable scanner
|
|
440
|
+
this._scannerEnabled ? this.enableScannerDevice() : this.disableScannerDevice();
|
|
438
441
|
}
|
|
439
|
-
|
|
442
|
+
logger.traceExit(entryMessage);
|
|
440
443
|
}
|
|
441
444
|
processAESDK(response) {
|
|
442
445
|
const entryMessage = logger.traceEntry("processAESDK", response);
|
|
443
|
-
let responseType = constants_1.ResponseType.None;
|
|
444
446
|
if (sdk_interface_1.AurusSupport.requestType === constants_1.RequestTypes.GetCardBin) {
|
|
445
|
-
|
|
446
|
-
sdk_interface_1.AurusSupport.authResponse.responseCode = _1.ResponseCodes.Error;
|
|
447
|
-
sdk_interface_1.AurusSupport.authResponse.status = response.ResponseText.value;
|
|
447
|
+
this.emitAuthorizationResponse(_1.ResponseCodes.Error, response.ResponseText.value);
|
|
448
448
|
}
|
|
449
|
+
// this scenario could happen if the registration request fails
|
|
449
450
|
if (sdk_interface_1.AurusSupport.requestType === constants_1.RequestTypes.Registration) {
|
|
450
|
-
responseType |= constants_1.ResponseType.PaymentStatus;
|
|
451
|
-
sdk_interface_1.AurusSupport.paymentStatus.deviceAvailable = true;
|
|
452
|
-
sdk_interface_1.AurusSupport.paymentStatus.status = response.ResponseText.value;
|
|
453
|
-
sdk_interface_1.AurusSupport.paymentStatus.statusCode = _1.StatusCode.InitializationComplete;
|
|
454
451
|
this._registrationInProgress = false;
|
|
452
|
+
// enable payment button or it will be permanately disabled without the user knowing why
|
|
453
|
+
// registration can be re-attempted when clicked and/or an error given to the user
|
|
454
|
+
this.emitPaymentStatus(true, _1.StatusCode.InitializationComplete);
|
|
455
|
+
//enable/disable scanner
|
|
456
|
+
this._scannerEnabled ? this.enableScannerDevice() : this.disableScannerDevice();
|
|
455
457
|
}
|
|
456
|
-
|
|
458
|
+
logger.traceExit(entryMessage);
|
|
457
459
|
}
|
|
458
460
|
mapAurusResponseCode(responseCode) {
|
|
459
461
|
const entryMessage = logger.traceEntry("mapAurusResponseCode", responseCode);
|
|
@@ -562,183 +564,140 @@ let AurusDevice = class AurusDevice {
|
|
|
562
564
|
catch (e) {
|
|
563
565
|
logger.error(e);
|
|
564
566
|
}
|
|
565
|
-
;
|
|
566
567
|
return logger.traceExit(entryMessage, emvData);
|
|
567
568
|
}
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
569
|
+
/**
|
|
570
|
+
* This method handles events published by the native components. This is an adapter between the native and JavaScript
|
|
571
|
+
* components for asynchronous events from the native layer.
|
|
572
|
+
*/
|
|
573
|
+
onNotificationReceived(...args) {
|
|
574
|
+
const entryMessage = logger.traceEntry("onNotificationReceived", args);
|
|
575
|
+
if (args.length >= 1 && args[0]) {
|
|
576
|
+
const userInfo = args[0];
|
|
577
|
+
logger.debug(`In onNotificationReceived, userInfo: ${JSON.stringify(userInfo)}`);
|
|
578
|
+
this.handleNotificationEvent(userInfo);
|
|
579
|
+
}
|
|
580
|
+
else {
|
|
581
|
+
throw logger.throwing(new Error("Empty event received. userInfo data is missing"), entryMessage);
|
|
582
|
+
}
|
|
583
|
+
logger.traceExit(entryMessage);
|
|
584
|
+
}
|
|
585
|
+
handleNotificationEvent(userInfo) {
|
|
586
|
+
if (userInfo && userInfo.CODE !== undefined) {
|
|
587
|
+
(({
|
|
588
|
+
[NotificationEvent.BarcodeInformation]: () => { this.handleBarcodeInformationEvent(userInfo.AE_BARCODE_INFO); },
|
|
589
|
+
[NotificationEvent.DeviceNotConnected]: () => { this.handleDeviceNotConnectedEvent(); },
|
|
590
|
+
[NotificationEvent.DeviceConnected]: () => { this.handleDeviceConnectedEvent(); },
|
|
591
|
+
[NotificationEvent.DeviceConfigurationStarted]: () => { this.handleDeviceConfigurationStartedEvent(); },
|
|
592
|
+
[NotificationEvent.DeviceConfigurationCompleted]: () => { this.handleDeviceConfigurationCompletedEvent(); },
|
|
593
|
+
[NotificationEvent.DeviceConfigurationFailed]: () => { this.handleDeviceConfigurationFailedEvent(); },
|
|
594
|
+
[NotificationEvent.DeviceAlreadyConfigured]: () => { this.handleDeviceAlreadyConfiguredEvent(); }
|
|
595
|
+
})[userInfo.CODE] || (() => { this.handleDefaultEvent(userInfo.CODE); }))();
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
handleBarcodeInformationEvent(xmlBarcodeInfo) {
|
|
599
|
+
const entryMessage = logger.traceEntry("handleBarcodeInformationEvent", xmlBarcodeInfo);
|
|
571
600
|
if (!this._scannerEnabled) {
|
|
572
601
|
logger.debug("Scanning is not enabled, not processing the scan.");
|
|
573
602
|
// todo: make a sound to indicate the scan failed due to not being enabled.
|
|
574
603
|
}
|
|
575
604
|
else {
|
|
576
|
-
let xmlResponse = this.convertXmlToJs(
|
|
605
|
+
let xmlResponse = this.convertXmlToJs(xmlBarcodeInfo);
|
|
577
606
|
if (!xmlResponse) {
|
|
578
|
-
logger.warn(`In
|
|
607
|
+
logger.warn(`In handleBarcodeInformationEvent, unable to convert to JSON: ${xmlBarcodeInfo}`);
|
|
579
608
|
}
|
|
580
609
|
else if (constants_1.AesdkResponseTypes.Barcode in xmlResponse) {
|
|
581
|
-
|
|
610
|
+
this.processBarcodeData(xmlResponse[constants_1.AesdkResponseTypes.Barcode]);
|
|
582
611
|
}
|
|
583
612
|
else {
|
|
584
|
-
logger.warn(`In
|
|
613
|
+
logger.warn(`In handleBarcodeInformationEvent, unexpected root element received, ignoring xml: ${xmlBarcodeInfo}`);
|
|
585
614
|
}
|
|
586
615
|
}
|
|
587
|
-
|
|
588
|
-
this._scannerEmitter.emit(_1.EventResponseTypes.Scan, scanDataNotification);
|
|
589
|
-
}
|
|
590
|
-
return logger.traceExit(entryMessage, scanDataNotification);
|
|
616
|
+
logger.traceExit(entryMessage);
|
|
591
617
|
}
|
|
592
618
|
processBarcodeData(barcode) {
|
|
593
619
|
const entryMessage = logger.traceEntry("processBarcodeData", barcode);
|
|
594
|
-
|
|
620
|
+
const scanDataNotification = {
|
|
595
621
|
data: barcode.Barcode.value,
|
|
596
622
|
encoding: sdk_interface_1.AurusSupport.getBarcodeType(barcode.BarcodeType.value)
|
|
597
|
-
}
|
|
623
|
+
};
|
|
624
|
+
logger.debug(`In processBarcodeData, publishing scanDataNotification: ${JSON.stringify(scanDataNotification)}`);
|
|
625
|
+
this._scannerEmitter.emit(_1.EventResponseTypes.Scan, scanDataNotification);
|
|
626
|
+
logger.traceExit(entryMessage);
|
|
598
627
|
}
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
const notificationUserInfo = args[0];
|
|
610
|
-
logger.debug(`In onNotificationReceived, notificationUserInfo: ${JSON.stringify(notificationUserInfo)}`);
|
|
611
|
-
switch (notificationUserInfo.CODE) {
|
|
612
|
-
// TODO: Determine if we want to use any the commented out events. (Status messages, logging, etc.)
|
|
613
|
-
// case NotificationEvent.ProcessingRequest: {
|
|
614
|
-
// break;
|
|
615
|
-
// }
|
|
616
|
-
// case NotificationEvent.SwipeOrInsertOrTap: {
|
|
617
|
-
// break;
|
|
618
|
-
// }
|
|
619
|
-
// case NotificationEvent.EnterManualCardEntry: {
|
|
620
|
-
// break;
|
|
621
|
-
// }
|
|
622
|
-
// case NotificationEvent.Processing: {
|
|
623
|
-
// break;
|
|
624
|
-
// }
|
|
625
|
-
// case NotificationEvent.CardAuthorization: {
|
|
626
|
-
// break;
|
|
627
|
-
// }
|
|
628
|
-
// case NotificationEvent.EnterPIN: {
|
|
629
|
-
// break;
|
|
630
|
-
// }
|
|
631
|
-
// case NotificationEvent.EnterZIP: {
|
|
632
|
-
// break;
|
|
633
|
-
// }
|
|
634
|
-
// case NotificationEvent.EnterSSN: {
|
|
635
|
-
// break;
|
|
636
|
-
// }
|
|
637
|
-
// case NotificationEvent.EnterSIN: {
|
|
638
|
-
// break;
|
|
639
|
-
// }
|
|
640
|
-
// case NotificationEvent.EnterAnnualDebitIncome: {
|
|
641
|
-
// break;
|
|
642
|
-
// }
|
|
643
|
-
// case NotificationEvent.EnterMonthlyDebitIncome: {
|
|
644
|
-
// break;
|
|
645
|
-
// }
|
|
646
|
-
// case NotificationEvent.EnterPhoneNumber: {
|
|
647
|
-
// break;
|
|
648
|
-
// }
|
|
649
|
-
// case NotificationEvent.EnterPasscode: {
|
|
650
|
-
// break;
|
|
651
|
-
// }
|
|
652
|
-
// case NotificationEvent.EnterExpiryDate: {
|
|
653
|
-
// break;
|
|
654
|
-
// }
|
|
655
|
-
// case NotificationEvent.EnterCVV: {
|
|
656
|
-
// break;
|
|
657
|
-
// }
|
|
658
|
-
// case NotificationEvent.EnterTIP: {
|
|
659
|
-
// break;
|
|
660
|
-
// }
|
|
661
|
-
// case NotificationEvent.Confirmation: {
|
|
662
|
-
// break;
|
|
663
|
-
// }
|
|
664
|
-
// case NotificationEvent.ProcessingTransaction: {
|
|
665
|
-
// break;
|
|
666
|
-
// }
|
|
667
|
-
case NotificationEvent.BarcodeInformation: {
|
|
668
|
-
//await this.handleBarcodeDataReceived(notificationUserInfo.AE_BARCODE_INFO);
|
|
669
|
-
this.handleBarcodeDataReceived(notificationUserInfo.AE_BARCODE_INFO);
|
|
670
|
-
break;
|
|
671
|
-
}
|
|
672
|
-
// case NotificationEvent.DeviceNotConnected: {
|
|
673
|
-
// break;
|
|
674
|
-
// }
|
|
675
|
-
// case NotificationEvent.DeviceConnecting: {
|
|
676
|
-
// break;
|
|
677
|
-
// }
|
|
678
|
-
// case NotificationEvent.DeviceConnected: {
|
|
679
|
-
// break;
|
|
680
|
-
// }
|
|
681
|
-
case NotificationEvent.DeviceConfigurationStarted: {
|
|
682
|
-
this._initInProgress = true;
|
|
683
|
-
break;
|
|
684
|
-
}
|
|
685
|
-
case NotificationEvent.DeviceConfigurationCompleted: {
|
|
686
|
-
this._initInProgress = false;
|
|
687
|
-
this.sendAESDKRegistration(sdk_interface_1.AurusSupport.authRequest);
|
|
688
|
-
break;
|
|
689
|
-
}
|
|
690
|
-
case NotificationEvent.DeviceConfigurationFailed: {
|
|
691
|
-
logger.debug("In onNotificationReceived, DeviceConfigurationFailed");
|
|
692
|
-
this._initInProgress = false;
|
|
693
|
-
break;
|
|
694
|
-
}
|
|
695
|
-
case NotificationEvent.DeviceAlreadyConfigured: {
|
|
696
|
-
this.sendAESDKRegistration(sdk_interface_1.AurusSupport.authRequest);
|
|
697
|
-
break;
|
|
698
|
-
}
|
|
699
|
-
// case NotificationEvent.FileDownloading: {
|
|
700
|
-
// break;
|
|
701
|
-
// }
|
|
702
|
-
// case NotificationEvent.FileDownloadFailed: {
|
|
703
|
-
// break;
|
|
704
|
-
// }
|
|
705
|
-
// case NotificationEvent.FileDownloadRetrying: {
|
|
706
|
-
// break;
|
|
707
|
-
// }
|
|
708
|
-
// case NotificationEvent.FileUpgradingToPED: {
|
|
709
|
-
// break;
|
|
710
|
-
// }
|
|
711
|
-
// case NotificationEvent.FileUpgradingToPEDFailed: {
|
|
712
|
-
// break;
|
|
713
|
-
// }
|
|
714
|
-
// case NotificationEvent.FileUpgradingToPEDCompleted: {
|
|
715
|
-
// break;
|
|
716
|
-
// }
|
|
717
|
-
// case NotificationEvent.FileTransferToPEDInfo: {
|
|
718
|
-
// break;
|
|
719
|
-
// }
|
|
720
|
-
// case NotificationEvent.FileTransferToPEDProgress: {
|
|
721
|
-
// break;
|
|
722
|
-
// }
|
|
723
|
-
// case NotificationEvent.None: {
|
|
724
|
-
// break;
|
|
725
|
-
// }
|
|
726
|
-
default: {
|
|
727
|
-
// logger.debug(`notificationUserInfo.CODE not handled: ${notificationUserInfo.CODE}`);
|
|
728
|
-
break;
|
|
729
|
-
}
|
|
730
|
-
}
|
|
628
|
+
handleDeviceNotConnectedEvent() {
|
|
629
|
+
const entryMessage = logger.traceEntry("handleDeviceNotConnectedEvent");
|
|
630
|
+
this.emitPaymentStatus(false, _1.StatusCode.DeviceDisconnected);
|
|
631
|
+
logger.traceExit(entryMessage);
|
|
632
|
+
}
|
|
633
|
+
handleDeviceConnectedEvent() {
|
|
634
|
+
const entryMessage = logger.traceEntry("handleDeviceConnectedEvent");
|
|
635
|
+
if (this._waitingForDeviceConnected) {
|
|
636
|
+
this._waitingForDeviceConnected = false;
|
|
637
|
+
this.sendAESDKRegistration();
|
|
731
638
|
}
|
|
732
639
|
else {
|
|
733
|
-
|
|
640
|
+
this.emitPaymentStatus(true, _1.StatusCode.DeviceReconnected);
|
|
641
|
+
//enable/disable scanner
|
|
642
|
+
this._scannerEnabled ? this.enableScannerDevice() : this.disableScannerDevice();
|
|
734
643
|
}
|
|
735
644
|
logger.traceExit(entryMessage);
|
|
736
645
|
}
|
|
646
|
+
handleDeviceConfigurationStartedEvent() {
|
|
647
|
+
const entryMessage = logger.traceEntry("handleDeviceConfigurationStartedEvent");
|
|
648
|
+
logger.traceExit(entryMessage);
|
|
649
|
+
}
|
|
650
|
+
handleDeviceConfigurationCompletedEvent() {
|
|
651
|
+
const entryMessage = logger.traceEntry("handleDeviceConfigurationCompletedEvent");
|
|
652
|
+
logger.traceExit(entryMessage);
|
|
653
|
+
}
|
|
654
|
+
handleDeviceConfigurationFailedEvent() {
|
|
655
|
+
const entryMessage = logger.traceEntry("handleDeviceConfigurationFailedEvent");
|
|
656
|
+
logger.traceExit(entryMessage);
|
|
657
|
+
}
|
|
658
|
+
handleDeviceAlreadyConfiguredEvent() {
|
|
659
|
+
const entryMessage = logger.traceEntry("handleDeviceAlreadyConfiguredEvent");
|
|
660
|
+
logger.traceExit(entryMessage);
|
|
661
|
+
}
|
|
662
|
+
handleDefaultEvent(userInfoCode) {
|
|
663
|
+
// Should we log this? If we do, we should convert the userInfoCode into readable text.
|
|
664
|
+
}
|
|
665
|
+
emitPaymentStatus(deviceAvailable, statusCode) {
|
|
666
|
+
const entryMessage = logger.traceEntry("emitPaymentStatus");
|
|
667
|
+
sdk_interface_1.AurusSupport.paymentStatus.deviceAvailable = deviceAvailable;
|
|
668
|
+
sdk_interface_1.AurusSupport.paymentStatus.statusCode = statusCode;
|
|
669
|
+
sdk_interface_1.AurusSupport.paymentStatus.paymentEnvironment = this._paymentEnvironment;
|
|
670
|
+
logger.debug(`In emitPaymentStatus, publishing paymentStatus: ${JSON.stringify(sdk_interface_1.AurusSupport.paymentStatus)}`);
|
|
671
|
+
this._paymentEmitter.emit(_1.EventResponseTypes.PaymentDeviceStatus, sdk_interface_1.AurusSupport.paymentStatus);
|
|
672
|
+
sdk_interface_1.AurusSupport.paymentStatus = { deviceAvailable: false };
|
|
673
|
+
logger.traceExit(entryMessage);
|
|
674
|
+
}
|
|
675
|
+
emitAuthorizationResponse(responseCode, status) {
|
|
676
|
+
const entryMessage = logger.traceEntry("emitAuthorizationResponse");
|
|
677
|
+
sdk_interface_1.AurusSupport.authResponse.responseCode = responseCode;
|
|
678
|
+
sdk_interface_1.AurusSupport.authResponse.status = status;
|
|
679
|
+
logger.debug(`In emitAuthorizationResponse, publishing authResponse: ${JSON.stringify(sdk_interface_1.AurusSupport.authResponse)}`);
|
|
680
|
+
this._paymentEmitter.emit(_1.EventResponseTypes.Authorization, sdk_interface_1.AurusSupport.authResponse);
|
|
681
|
+
logger.traceExit(entryMessage);
|
|
682
|
+
}
|
|
737
683
|
onAESDKLogResponse(...args) {
|
|
738
684
|
if (args.length >= 1 && args[0]) {
|
|
739
685
|
logger.debug(`onAESDKLogResponse: ${args[0]}`);
|
|
740
686
|
}
|
|
741
687
|
}
|
|
688
|
+
sendRequest(xmlRequest) {
|
|
689
|
+
logger.debug(`sendRequest: _requestInProgress = ${this._requestInProgress}`);
|
|
690
|
+
if (this._requestInProgress) {
|
|
691
|
+
// Note: This is being used to maintain order for rapid requests.
|
|
692
|
+
// It safeguards against enable/disable scanner from POS at the same time as other requests.
|
|
693
|
+
// If additional use cases are added, this should be revisted as well to maintain additional data.
|
|
694
|
+
this._requestQueue.push(xmlRequest);
|
|
695
|
+
}
|
|
696
|
+
else {
|
|
697
|
+
this._requestInProgress = true;
|
|
698
|
+
this._devicePaymentTerminal.OnAESDKProcessRequest(xmlRequest);
|
|
699
|
+
}
|
|
700
|
+
}
|
|
742
701
|
};
|
|
743
702
|
AurusDevice = __decorate([
|
|
744
703
|
inversify_1.injectable(),
|