@swirepay-developer/swirepay-ach-sdk 2.0.0 → 2.0.1
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/package.json +1 -1
- package/web-component/swirepay-checkout.js +911 -272
package/package.json
CHANGED
|
@@ -3,7 +3,8 @@ import { isValidPhoneNumber } from "libphonenumber-js";
|
|
|
3
3
|
|
|
4
4
|
const SDK_CONFIG = {
|
|
5
5
|
elliptic: "https://cdnjs.cloudflare.com/ajax/libs/elliptic/6.3.1/elliptic.js",
|
|
6
|
-
crypto: "https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.2.0/crypto-js.min.js"
|
|
6
|
+
crypto: "https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.2.0/crypto-js.min.js",
|
|
7
|
+
plaid: "https://cdn.plaid.com/link/v2/stable/link-initialize.js"
|
|
7
8
|
};
|
|
8
9
|
class EventEmitter {
|
|
9
10
|
constructor() { this.events = {}; }
|
|
@@ -108,133 +109,8 @@ const USA_STATES = [
|
|
|
108
109
|
];
|
|
109
110
|
|
|
110
111
|
const COUNTRIES_LIST = [
|
|
111
|
-
{ "name": "Afghanistan", "code": "AF" },
|
|
112
|
-
{ "name": "Albania", "code": "AL" },
|
|
113
|
-
{ "name": "Algeria", "code": "DZ" },
|
|
114
|
-
{ "name": "Andorra", "code": "AD" },
|
|
115
|
-
{ "name": "Angola", "code": "AO" },
|
|
116
|
-
{ "name": "Antigua and Barbuda", "code": "AG" },
|
|
117
|
-
{ "name": "Argentina", "code": "AR" },
|
|
118
|
-
{ "name": "Armenia", "code": "AM" },
|
|
119
|
-
{ "name": "Australia", "code": "AU" },
|
|
120
|
-
{ "name": "Austria", "code": "AT" },
|
|
121
|
-
{ "name": "Azerbaijan", "code": "AZ" },
|
|
122
|
-
{ "name": "Bahamas", "code": "BS" },
|
|
123
|
-
{ "name": "Bahrain", "code": "BH" },
|
|
124
|
-
{ "name": "Bangladesh", "code": "BD" },
|
|
125
|
-
{ "name": "Barbados", "code": "BB" },
|
|
126
|
-
{ "name": "Belarus", "code": "BY" },
|
|
127
|
-
{ "name": "Belgium", "code": "BE" },
|
|
128
|
-
{ "name": "Belize", "code": "BZ" },
|
|
129
|
-
{ "name": "Benin", "code": "BJ" },
|
|
130
|
-
{ "name": "Bhutan", "code": "BT" },
|
|
131
|
-
{ "name": "Bolivia", "code": "BO" },
|
|
132
|
-
{ "name": "Bosnia and Herzegovina", "code": "BA" },
|
|
133
|
-
{ "name": "Botswana", "code": "BW" },
|
|
134
|
-
{ "name": "Brazil", "code": "BR" },
|
|
135
|
-
{ "name": "Brunei", "code": "BN" },
|
|
136
|
-
{ "name": "Bulgaria", "code": "BG" },
|
|
137
|
-
{ "name": "Burkina Faso", "code": "BF" },
|
|
138
|
-
{ "name": "Burundi", "code": "BI" },
|
|
139
|
-
{ "name": "Cambodia", "code": "KH" },
|
|
140
|
-
{ "name": "Cameroon", "code": "CM" },
|
|
141
|
-
{ "name": "Canada", "code": "CA" },
|
|
142
|
-
{ "name": "Cape Verde", "code": "CV" },
|
|
143
|
-
{ "name": "Central African Republic", "code": "CF" },
|
|
144
|
-
{ "name": "Chad", "code": "TD" },
|
|
145
|
-
{ "name": "Chile", "code": "CL" },
|
|
146
|
-
{ "name": "China", "code": "CN" },
|
|
147
|
-
{ "name": "Colombia", "code": "CO" },
|
|
148
|
-
{ "name": "Comoros", "code": "KM" },
|
|
149
|
-
{ "name": "Congo", "code": "CG" },
|
|
150
|
-
{ "name": "Costa Rica", "code": "CR" },
|
|
151
|
-
{ "name": "Croatia", "code": "HR" },
|
|
152
|
-
{ "name": "Cuba", "code": "CU" },
|
|
153
|
-
{ "name": "Cyprus", "code": "CY" },
|
|
154
|
-
{ "name": "Czech Republic", "code": "CZ" },
|
|
155
|
-
{ "name": "Denmark", "code": "DK" },
|
|
156
|
-
{ "name": "Djibouti", "code": "DJ" },
|
|
157
|
-
{ "name": "Dominica", "code": "DM" },
|
|
158
|
-
{ "name": "Dominican Republic", "code": "DO" },
|
|
159
|
-
{ "name": "Ecuador", "code": "EC" },
|
|
160
|
-
{ "name": "Egypt", "code": "EG" },
|
|
161
|
-
{ "name": "El Salvador", "code": "SV" },
|
|
162
|
-
{ "name": "Equatorial Guinea", "code": "GQ" },
|
|
163
|
-
{ "name": "Eritrea", "code": "ER" },
|
|
164
|
-
{ "name": "Estonia", "code": "EE" },
|
|
165
|
-
{ "name": "Ethiopia", "code": "ET" },
|
|
166
|
-
{ "name": "Fiji", "code": "FJ" },
|
|
167
|
-
{ "name": "Finland", "code": "FI" },
|
|
168
|
-
{ "name": "France", "code": "FR" },
|
|
169
|
-
{ "name": "Gabon", "code": "GA" },
|
|
170
|
-
{ "name": "Gambia", "code": "GM" },
|
|
171
|
-
{ "name": "Georgia", "code": "GE" },
|
|
172
|
-
{ "name": "Germany", "code": "DE" },
|
|
173
|
-
{ "name": "Ghana", "code": "GH" },
|
|
174
|
-
{ "name": "Greece", "code": "GR" },
|
|
175
|
-
{ "name": "Grenada", "code": "GD" },
|
|
176
|
-
{ "name": "Guatemala", "code": "GT" },
|
|
177
|
-
{ "name": "Guinea", "code": "GN" },
|
|
178
|
-
{ "name": "Guyana", "code": "GY" },
|
|
179
|
-
{ "name": "Haiti", "code": "HT" },
|
|
180
|
-
{ "name": "Honduras", "code": "HN" },
|
|
181
|
-
{ "name": "Hungary", "code": "HU" },
|
|
182
|
-
{ "name": "Iceland", "code": "IS" },
|
|
183
112
|
{ "name": "India", "code": "IN" },
|
|
184
|
-
{ "name": "Indonesia", "code": "ID" },
|
|
185
|
-
{ "name": "Iran", "code": "IR" },
|
|
186
|
-
{ "name": "Iraq", "code": "IQ" },
|
|
187
|
-
{ "name": "Ireland", "code": "IE" },
|
|
188
|
-
{ "name": "Israel", "code": "IL" },
|
|
189
|
-
{ "name": "Italy", "code": "IT" },
|
|
190
|
-
{ "name": "Jamaica", "code": "JM" },
|
|
191
|
-
{ "name": "Japan", "code": "JP" },
|
|
192
|
-
{ "name": "Jordan", "code": "JO" },
|
|
193
|
-
{ "name": "Kazakhstan", "code": "KZ" },
|
|
194
|
-
{ "name": "Kenya", "code": "KE" },
|
|
195
|
-
{ "name": "Korea, South", "code": "KR" },
|
|
196
|
-
{ "name": "Kuwait", "code": "KW" },
|
|
197
|
-
{ "name": "Laos", "code": "LA" },
|
|
198
|
-
{ "name": "Latvia", "code": "LV" },
|
|
199
|
-
{ "name": "Lebanon", "code": "LB" },
|
|
200
|
-
{ "name": "Libya", "code": "LY" },
|
|
201
|
-
{ "name": "Lithuania", "code": "LT" },
|
|
202
|
-
{ "name": "Luxembourg", "code": "LU" },
|
|
203
|
-
{ "name": "Malaysia", "code": "MY" },
|
|
204
|
-
{ "name": "Maldives", "code": "MV" },
|
|
205
|
-
{ "name": "Mexico", "code": "MX" },
|
|
206
|
-
{ "name": "Monaco", "code": "MC" },
|
|
207
|
-
{ "name": "Morocco", "code": "MA" },
|
|
208
|
-
{ "name": "Nepal", "code": "NP" },
|
|
209
|
-
{ "name": "Netherlands", "code": "NL" },
|
|
210
|
-
{ "name": "New Zealand", "code": "NZ" },
|
|
211
|
-
{ "name": "Nigeria", "code": "NG" },
|
|
212
|
-
{ "name": "Norway", "code": "NO" },
|
|
213
|
-
{ "name": "Oman", "code": "OM" },
|
|
214
|
-
{ "name": "Pakistan", "code": "PK" },
|
|
215
|
-
{ "name": "Panama", "code": "PA" },
|
|
216
|
-
{ "name": "Peru", "code": "PE" },
|
|
217
|
-
{ "name": "Philippines", "code": "PH" },
|
|
218
|
-
{ "name": "Poland", "code": "PL" },
|
|
219
|
-
{ "name": "Portugal", "code": "PT" },
|
|
220
|
-
{ "name": "Qatar", "code": "QA" },
|
|
221
|
-
{ "name": "Romania", "code": "RO" },
|
|
222
|
-
{ "name": "Russia", "code": "RU" },
|
|
223
|
-
{ "name": "Saudi Arabia", "code": "SA" },
|
|
224
|
-
{ "name": "Singapore", "code": "SG" },
|
|
225
|
-
{ "name": "South Africa", "code": "ZA" },
|
|
226
|
-
{ "name": "Spain", "code": "ES" },
|
|
227
|
-
{ "name": "Sri Lanka", "code": "LK" },
|
|
228
|
-
{ "name": "Sweden", "code": "SE" },
|
|
229
|
-
{ "name": "Switzerland", "code": "CH" },
|
|
230
|
-
{ "name": "Thailand", "code": "TH" },
|
|
231
|
-
{ "name": "Turkey", "code": "TR" },
|
|
232
|
-
{ "name": "Ukraine", "code": "UA" },
|
|
233
|
-
{ "name": "United Arab Emirates", "code": "AE" },
|
|
234
|
-
{ "name": "United Kingdom", "code": "GB" },
|
|
235
113
|
{ "name": "United States", "code": "US" },
|
|
236
|
-
{ "name": "Vietnam", "code": "VN" },
|
|
237
|
-
{ "name": "Zimbabwe", "code": "ZW" }
|
|
238
114
|
];
|
|
239
115
|
|
|
240
116
|
const DEFAULT_THEME = {
|
|
@@ -279,20 +155,175 @@ export class SwirepayCheckout extends HTMLElement {
|
|
|
279
155
|
this.theme = DEFAULT_THEME;
|
|
280
156
|
}
|
|
281
157
|
|
|
158
|
+
getEndpoints() {
|
|
159
|
+
if (this.test) {
|
|
160
|
+
return { gateway: 'https://staging-backend.swirepay.com' };
|
|
161
|
+
}
|
|
162
|
+
return { gateway: 'https://api.swirepay.com' };
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
async getSplitUpDetails(inventoryOrder) {
|
|
166
|
+
const payload = {
|
|
167
|
+
shopGid: inventoryOrder?.shopGid,
|
|
168
|
+
items: inventoryOrder?.inventoryOrderLineItems,
|
|
169
|
+
tipType: "AMOUNT",
|
|
170
|
+
tip: inventoryOrder?.totalTip
|
|
171
|
+
}
|
|
172
|
+
const gateway = this.getEndpoints().gateway;
|
|
173
|
+
let url = `${gateway}/v1/inventory/order/inventory-order-split-up`;
|
|
174
|
+
const response = await fetch(url, {
|
|
175
|
+
method: 'POST',
|
|
176
|
+
headers: {
|
|
177
|
+
'Content-Type': 'application/json',
|
|
178
|
+
'x-api-key': this.apiKey,
|
|
179
|
+
},
|
|
180
|
+
body: JSON.stringify(payload)
|
|
181
|
+
})
|
|
182
|
+
return await response.json();
|
|
183
|
+
}
|
|
184
|
+
|
|
282
185
|
async connectedCallback() {
|
|
283
186
|
this.amount = parseInt(this.getAttribute("amount")) || 0;
|
|
284
187
|
this.test = this.getAttribute("mode") === "test";
|
|
285
|
-
this.amount = parseInt(this.getAttribute("amount")) || 0;
|
|
286
188
|
this.currencyCode = this.getAttribute("currencyCode");
|
|
287
189
|
this.apiKey = this.getAttribute("api-key");
|
|
190
|
+
this.isAddressRequired = this.getAttribute("isAddressRequired") === "true";
|
|
191
|
+
this.inventory = this.getAttribute("inventory") === "true";
|
|
192
|
+
this.planGid = this.getAttribute("planGid");
|
|
193
|
+
this.productName = this.getAttribute("productName");
|
|
194
|
+
this.frequency = this.getAttribute("frequency");
|
|
195
|
+
this.description = this.getAttribute("description");
|
|
196
|
+
this.accountGid = this.getAttribute('accountGid');
|
|
197
|
+
this.totalPayments = this.getAttribute('totalPayments');
|
|
198
|
+
try {
|
|
199
|
+
const customerAttr = this.getAttribute("customer");
|
|
200
|
+
this.customer = customerAttr ? JSON.parse(customerAttr) : {};
|
|
201
|
+
const inventoryOrders = this.getAttribute("inventoryOrders");
|
|
202
|
+
this.inventoryOrder = inventoryOrders ? JSON.parse(inventoryOrders) : {};
|
|
203
|
+
if (this.inventory) {
|
|
204
|
+
const splitUpInfo = await this.getSplitUpDetails(this.inventoryOrder);
|
|
205
|
+
this.splitUp = splitUpInfo?.entity;
|
|
206
|
+
}
|
|
207
|
+
} catch (e) {
|
|
208
|
+
console.error("Invalid JSON", e);
|
|
209
|
+
this.customer = {};
|
|
210
|
+
this.inventoryOrder = {};
|
|
211
|
+
}
|
|
288
212
|
await Promise.all([
|
|
289
213
|
loadScript(SDK_CONFIG.elliptic),
|
|
290
|
-
loadScript(SDK_CONFIG.crypto)
|
|
214
|
+
loadScript(SDK_CONFIG.crypto),
|
|
215
|
+
loadScript(SDK_CONFIG.plaid)
|
|
291
216
|
]);
|
|
292
217
|
|
|
293
218
|
this.render();
|
|
294
219
|
}
|
|
295
220
|
|
|
221
|
+
static get observedAttributes() {
|
|
222
|
+
return [
|
|
223
|
+
"amount",
|
|
224
|
+
"mode",
|
|
225
|
+
"currencycode",
|
|
226
|
+
"api-key",
|
|
227
|
+
"isaddressrequired",
|
|
228
|
+
"inventory",
|
|
229
|
+
"plangid",
|
|
230
|
+
"productname",
|
|
231
|
+
"frequency",
|
|
232
|
+
"description",
|
|
233
|
+
"totalpayments",
|
|
234
|
+
"customer",
|
|
235
|
+
"inventoryorders"
|
|
236
|
+
];
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
attributeChangedCallback(name, oldValue, newValue) {
|
|
240
|
+
if (oldValue === newValue) return;
|
|
241
|
+
|
|
242
|
+
try {
|
|
243
|
+
switch (name) {
|
|
244
|
+
case "amount":
|
|
245
|
+
this.amount = parseInt(newValue) || 0;
|
|
246
|
+
break;
|
|
247
|
+
|
|
248
|
+
case "mode":
|
|
249
|
+
this.test = newValue === "test";
|
|
250
|
+
break;
|
|
251
|
+
|
|
252
|
+
case "currencycode":
|
|
253
|
+
this.currencyCode = newValue;
|
|
254
|
+
break;
|
|
255
|
+
|
|
256
|
+
case "api-key":
|
|
257
|
+
this.apiKey = newValue;
|
|
258
|
+
break;
|
|
259
|
+
|
|
260
|
+
case "isaddressrequired":
|
|
261
|
+
this.isAddressRequired = newValue === "true";
|
|
262
|
+
break;
|
|
263
|
+
|
|
264
|
+
case "inventory":
|
|
265
|
+
this.inventory = newValue === "true";
|
|
266
|
+
break;
|
|
267
|
+
|
|
268
|
+
case "plangid":
|
|
269
|
+
this.planGid = newValue;
|
|
270
|
+
break;
|
|
271
|
+
|
|
272
|
+
case "productname":
|
|
273
|
+
this.productName = newValue;
|
|
274
|
+
break;
|
|
275
|
+
|
|
276
|
+
case "frequency":
|
|
277
|
+
this.frequency = newValue;
|
|
278
|
+
break;
|
|
279
|
+
|
|
280
|
+
case "description":
|
|
281
|
+
this.description = newValue;
|
|
282
|
+
break;
|
|
283
|
+
|
|
284
|
+
case "totalpayments":
|
|
285
|
+
this.totalPayments = newValue;
|
|
286
|
+
break;
|
|
287
|
+
|
|
288
|
+
case "customer":
|
|
289
|
+
this.customer = newValue ? JSON.parse(newValue) : {};
|
|
290
|
+
break;
|
|
291
|
+
|
|
292
|
+
case "inventoryorders":
|
|
293
|
+
this.inventoryOrder = newValue ? JSON.parse(newValue) : {};
|
|
294
|
+
break;
|
|
295
|
+
|
|
296
|
+
default:
|
|
297
|
+
break;
|
|
298
|
+
}
|
|
299
|
+
if (this.shadowRoot) {
|
|
300
|
+
this.render();
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
} catch (e) {
|
|
304
|
+
console.error(`Invalid value for ${name}`, e);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
setError(id, message) {
|
|
309
|
+
const input = this.shadow.getElementById(id);
|
|
310
|
+
const errorEl = this.shadow.getElementById(`error-${id}`);
|
|
311
|
+
|
|
312
|
+
if (errorEl) errorEl.textContent = message || "";
|
|
313
|
+
|
|
314
|
+
if (input) {
|
|
315
|
+
if (message) input.classList.add("input-error");
|
|
316
|
+
else input.classList.remove("input-error");
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
clearErrors() {
|
|
321
|
+
this.shadow.querySelectorAll(".error").forEach(e => e.textContent = "");
|
|
322
|
+
this.shadow.querySelectorAll("input, select").forEach(el => {
|
|
323
|
+
el.classList.remove("input-error");
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
|
|
296
327
|
async encryptData(data, serverPublicKey, clientPrivateKey, keyId) {
|
|
297
328
|
try {
|
|
298
329
|
const EC = window.elliptic.ec;
|
|
@@ -347,13 +378,6 @@ export class SwirepayCheckout extends HTMLElement {
|
|
|
347
378
|
}
|
|
348
379
|
}
|
|
349
380
|
|
|
350
|
-
getEndpoints() {
|
|
351
|
-
if (this.test) {
|
|
352
|
-
return { gateway: 'https://staging-backend.swirepay.com' };
|
|
353
|
-
}
|
|
354
|
-
return { gateway: 'https://api.swirepay.com' };
|
|
355
|
-
}
|
|
356
|
-
|
|
357
381
|
async createCustomer(payload) {
|
|
358
382
|
const gateway = this.getEndpoints().gateway;
|
|
359
383
|
let url = `${gateway}/v3/customer`;
|
|
@@ -371,6 +395,31 @@ export class SwirepayCheckout extends HTMLElement {
|
|
|
371
395
|
return await response.json();
|
|
372
396
|
}
|
|
373
397
|
|
|
398
|
+
async initPlaid() {
|
|
399
|
+
const gateway = this.getEndpoints().gateway;
|
|
400
|
+
let url = `${gateway}/v1/integration/plaid/${this.accountGid}/create-secure-link-token?isTest=${!this.test}`;
|
|
401
|
+
const res = await fetch(url, {
|
|
402
|
+
method: 'POST',
|
|
403
|
+
headers: {
|
|
404
|
+
'Content-Type': 'application/json',
|
|
405
|
+
'x-api-key': this.apiKey,
|
|
406
|
+
},
|
|
407
|
+
body: JSON.stringify({})
|
|
408
|
+
})
|
|
409
|
+
const response = await res.json();
|
|
410
|
+
|
|
411
|
+
this.plaidHandler = Plaid.create({
|
|
412
|
+
token: response?.entity?.token,
|
|
413
|
+
|
|
414
|
+
onSuccess: async (public_token, metadata) => {
|
|
415
|
+
this.processorToken = public_token;
|
|
416
|
+
|
|
417
|
+
this.shadow.getElementById("bank-status").textContent =
|
|
418
|
+
`Connected: ${metadata.institution.name}`;
|
|
419
|
+
}
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
|
|
374
423
|
async addPaymentMethod(payload) {
|
|
375
424
|
const gateway = this.getEndpoints().gateway;
|
|
376
425
|
let url = `${gateway}/v3/payment-method`;
|
|
@@ -388,6 +437,109 @@ export class SwirepayCheckout extends HTMLElement {
|
|
|
388
437
|
return await response.json();
|
|
389
438
|
}
|
|
390
439
|
|
|
440
|
+
async createOrder() {
|
|
441
|
+
const gateway = this.getEndpoints().gateway;
|
|
442
|
+
let url = `${gateway}/v1/inventory/order`;
|
|
443
|
+
const response = await fetch(url, {
|
|
444
|
+
method: 'POST',
|
|
445
|
+
headers: {
|
|
446
|
+
'Content-Type': 'application/json',
|
|
447
|
+
'x-api-key': this.apiKey,
|
|
448
|
+
},
|
|
449
|
+
body: JSON.stringify(this.inventoryOrder)
|
|
450
|
+
})
|
|
451
|
+
return await response.json();
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
async getSubScription(payload) {
|
|
455
|
+
const gateway = this.getEndpoints().gateway;
|
|
456
|
+
let url = `${gateway}/v2/subscription`;
|
|
457
|
+
const response = await fetch(url, {
|
|
458
|
+
method: 'POST',
|
|
459
|
+
headers: {
|
|
460
|
+
'Content-Type': 'application/json',
|
|
461
|
+
'x-api-key': this.apiKey,
|
|
462
|
+
},
|
|
463
|
+
body: JSON.stringify(payload)
|
|
464
|
+
})
|
|
465
|
+
return await response.json();
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
async getPlan() {
|
|
469
|
+
const gateway = this.getEndpoints().gateway;
|
|
470
|
+
let url = `${gateway}/v2/plan?isInternal.EQ=false&name.EQ=Recurring%20Plan`;
|
|
471
|
+
const response = await fetch(url, {
|
|
472
|
+
method: 'GET',
|
|
473
|
+
headers: {
|
|
474
|
+
'Content-Type': 'application/json',
|
|
475
|
+
'x-api-key': this.apiKey,
|
|
476
|
+
}
|
|
477
|
+
})
|
|
478
|
+
return await response.json();
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
async addedPlanInfo() {
|
|
482
|
+
const payload = {
|
|
483
|
+
"currencyCode": this.currencyCode,
|
|
484
|
+
"name": "Recurring Plan",
|
|
485
|
+
"description": "Recurring Plan",
|
|
486
|
+
"note": "Recurring Plan",
|
|
487
|
+
"billingFrequency": this.frequency,
|
|
488
|
+
"billingPeriod": 1
|
|
489
|
+
}
|
|
490
|
+
const gateway = this.getEndpoints().gateway;
|
|
491
|
+
let url = `${gateway}/v2/plan`;
|
|
492
|
+
const response = await fetch(url, {
|
|
493
|
+
method: 'POST',
|
|
494
|
+
headers: {
|
|
495
|
+
'Content-Type': 'application/json',
|
|
496
|
+
'x-api-key': this.apiKey,
|
|
497
|
+
},
|
|
498
|
+
body: JSON.stringify(payload)
|
|
499
|
+
})
|
|
500
|
+
return await response.json();
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
async getItemInfo() {
|
|
504
|
+
const gateway = this.getEndpoints().gateway;
|
|
505
|
+
let url = `${gateway}/v1/inventory/item?name.EQ=Recurring%20item&priceType.EQ=VARIABLE&isRecurring.EQ=true`;
|
|
506
|
+
const response = await fetch(url, {
|
|
507
|
+
method: 'GET',
|
|
508
|
+
headers: {
|
|
509
|
+
'Content-Type': 'application/json',
|
|
510
|
+
'x-api-key': this.apiKey,
|
|
511
|
+
},
|
|
512
|
+
})
|
|
513
|
+
return await response.json();
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
async addedItemInfo() {
|
|
517
|
+
const payload = {
|
|
518
|
+
"name": "Recurring item",
|
|
519
|
+
"alternateName": "Recurring item",
|
|
520
|
+
"onlineName": "Recurring item",
|
|
521
|
+
"onlineEnabled": true,
|
|
522
|
+
"price": 100,
|
|
523
|
+
"priceType": "VARIABLE",
|
|
524
|
+
"includeTax": true,
|
|
525
|
+
"available": true,
|
|
526
|
+
"recurring": true,
|
|
527
|
+
"onKiosk": true
|
|
528
|
+
}
|
|
529
|
+
const gateway = this.getEndpoints().gateway;
|
|
530
|
+
let url = `${gateway}/v1/inventory/item`;
|
|
531
|
+
const response = await fetch(url, {
|
|
532
|
+
method: 'POST',
|
|
533
|
+
headers: {
|
|
534
|
+
'Content-Type': 'application/json',
|
|
535
|
+
'x-api-key': this.apiKey,
|
|
536
|
+
},
|
|
537
|
+
body: JSON.stringify(payload)
|
|
538
|
+
})
|
|
539
|
+
return await response.json();
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
|
|
391
543
|
async getServerEncription() {
|
|
392
544
|
try {
|
|
393
545
|
const gateway = this.getEndpoints().gateway;
|
|
@@ -443,9 +595,11 @@ export class SwirepayCheckout extends HTMLElement {
|
|
|
443
595
|
return v.replace(/\D/g, "").slice(0, 10);
|
|
444
596
|
}
|
|
445
597
|
handleCountryChange() {
|
|
446
|
-
const
|
|
598
|
+
const countryEl = this.shadow.getElementById("country");
|
|
447
599
|
const phoneCodeEl = this.shadow.getElementById("phone-code");
|
|
448
600
|
const stateEl = this.shadow.getElementById("state");
|
|
601
|
+
if (!countryEl || !phoneCodeEl || !stateEl) return;
|
|
602
|
+
const country = countryEl.value;
|
|
449
603
|
phoneCodeEl.value = COUNTRY_PHONE_MAP[country] || "";
|
|
450
604
|
const states = getStates(country);
|
|
451
605
|
stateEl.innerHTML = states.map(
|
|
@@ -453,52 +607,136 @@ export class SwirepayCheckout extends HTMLElement {
|
|
|
453
607
|
).join("");
|
|
454
608
|
}
|
|
455
609
|
|
|
610
|
+
detectCardType(number) {
|
|
611
|
+
const n = number.replace(/\s/g, "");
|
|
612
|
+
|
|
613
|
+
if (/^4/.test(n)) return "VISA";
|
|
614
|
+
if (/^5[1-5]/.test(n)) return "MASTERCARD";
|
|
615
|
+
if (/^3[47]/.test(n)) return "AMEX";
|
|
616
|
+
if (/^6(?:011|5)/.test(n)) return "DISCOVER";
|
|
617
|
+
|
|
618
|
+
return "";
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
getAddressFields() {
|
|
622
|
+
if (!this.isAddressRequired) return "";
|
|
623
|
+
|
|
624
|
+
return `
|
|
625
|
+
<div class="section">
|
|
626
|
+
<div class="section-title">Address</div>
|
|
627
|
+
|
|
628
|
+
<div class="field">
|
|
629
|
+
<input id="street" required placeholder=" " />
|
|
630
|
+
<label>Street *</label>
|
|
631
|
+
</div>
|
|
632
|
+
<div class="error" id="error-street"></div>
|
|
633
|
+
|
|
634
|
+
<div class="field">
|
|
635
|
+
<input id="city" required placeholder=" " />
|
|
636
|
+
<label>City *</label>
|
|
637
|
+
</div>
|
|
638
|
+
<div class="error" id="error-city"></div>
|
|
639
|
+
|
|
640
|
+
<div class="field">
|
|
641
|
+
<select id="state"></select>
|
|
642
|
+
<label class="floating">State *</label>
|
|
643
|
+
</div>
|
|
644
|
+
<div class="error" id="error-state"></div>
|
|
645
|
+
|
|
646
|
+
<div class="field">
|
|
647
|
+
<select id="country" required>
|
|
648
|
+
${COUNTRIES_LIST.map(c =>
|
|
649
|
+
`<option value="${c.code}" ${c.code === "US" ? "selected" : ""}>${c.name}</option>`
|
|
650
|
+
).join("")}
|
|
651
|
+
</select>
|
|
652
|
+
<label class="floating">Country *</label>
|
|
653
|
+
</div>
|
|
654
|
+
<div class="error" id="error-country"></div>
|
|
655
|
+
|
|
656
|
+
<div class="field">
|
|
657
|
+
<input id="zip" required placeholder=" " />
|
|
658
|
+
<label>ZIP Code *</label>
|
|
659
|
+
</div>
|
|
660
|
+
<div class="error" id="error-zip"></div>
|
|
661
|
+
|
|
662
|
+
</div>
|
|
663
|
+
`;
|
|
664
|
+
}
|
|
665
|
+
|
|
456
666
|
validate() {
|
|
457
|
-
|
|
667
|
+
this.clearErrors();
|
|
668
|
+
let isValid = true;
|
|
458
669
|
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
const country = get("country");
|
|
465
|
-
|
|
466
|
-
const accountName = get("account-name");
|
|
467
|
-
const accountNumber = get("account-number");
|
|
468
|
-
const routingNumber = get("routing-number");
|
|
469
|
-
const accountType = get("account-type");
|
|
470
|
-
const bankName = get("bank-name");
|
|
471
|
-
const businessType = get("business-type");
|
|
472
|
-
const street = get("street");
|
|
473
|
-
if (!name) return "Name required";
|
|
474
|
-
if (!email) return "Email required";
|
|
475
|
-
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) return "Invalid email address";
|
|
476
|
-
if (!accountName) return "Account holder name required";
|
|
477
|
-
|
|
478
|
-
if (!accountNumber || !/^\d{6,18}$/.test(accountNumber)) {
|
|
479
|
-
return "Invalid account number";
|
|
480
|
-
}
|
|
670
|
+
const get = id => this.shadow.getElementById(id)?.value?.trim();
|
|
671
|
+
if (!get("name")) {
|
|
672
|
+
this.setError("name", "Name required");
|
|
673
|
+
isValid = false;
|
|
674
|
+
}
|
|
481
675
|
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
676
|
+
const email = get("email");
|
|
677
|
+
if (!email) {
|
|
678
|
+
this.setError("email", "Email required");
|
|
679
|
+
isValid = false;
|
|
680
|
+
} else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
|
|
681
|
+
this.setError("email", "Invalid email");
|
|
682
|
+
isValid = false;
|
|
683
|
+
}
|
|
485
684
|
|
|
486
|
-
|
|
685
|
+
const phone = get("phone")?.replace(/\D/g, "");
|
|
686
|
+
const code = get("phone-code");
|
|
687
|
+
if (!phone || !code) {
|
|
688
|
+
this.setError("phone", "Phone number required");
|
|
689
|
+
isValid = false;
|
|
690
|
+
} else {
|
|
691
|
+
const fullNumber = `${code}${phone}`;
|
|
692
|
+
if (!isValidPhoneNumber(fullNumber)) {
|
|
693
|
+
this.setError("phone", "Invalid phone number");
|
|
694
|
+
isValid = false;
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
if (!this.processorToken) {
|
|
698
|
+
this.setError("bank", "Please link bank account");
|
|
699
|
+
isValid = false;
|
|
700
|
+
}
|
|
701
|
+
if (!get("business-type")) {
|
|
702
|
+
this.setError("business-type", "Select business type");
|
|
703
|
+
isValid = false;
|
|
704
|
+
}
|
|
705
|
+
if (this.isAddressRequired) {
|
|
706
|
+
if (!get("street")) {
|
|
707
|
+
this.setError("street", "Street required");
|
|
708
|
+
isValid = false;
|
|
709
|
+
}
|
|
487
710
|
|
|
488
|
-
if (!
|
|
711
|
+
if (!get("city")) {
|
|
712
|
+
this.setError("city", "City required");
|
|
713
|
+
isValid = false;
|
|
714
|
+
}
|
|
489
715
|
|
|
490
|
-
if (!
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
return "Invalid phone";
|
|
716
|
+
if (!get("state")) {
|
|
717
|
+
this.setError("state", "State required");
|
|
718
|
+
isValid = false;
|
|
494
719
|
}
|
|
495
|
-
|
|
496
|
-
|
|
720
|
+
|
|
721
|
+
if (!get("country")) {
|
|
722
|
+
this.setError("country", "Country required");
|
|
723
|
+
isValid = false;
|
|
497
724
|
}
|
|
498
725
|
|
|
499
|
-
|
|
726
|
+
const zip = get("zip");
|
|
727
|
+
|
|
728
|
+
if (!zip) {
|
|
729
|
+
this.setError("zip", "ZIP required");
|
|
730
|
+
isValid = false;
|
|
731
|
+
} else if (postalCodes.validate(get("country"), zip) !== true) {
|
|
732
|
+
this.setError("zip", "Invalid ZIP code");
|
|
733
|
+
isValid = false;
|
|
734
|
+
}
|
|
500
735
|
}
|
|
501
736
|
|
|
737
|
+
return isValid;
|
|
738
|
+
}
|
|
739
|
+
|
|
502
740
|
formatAccountNumber(v) {
|
|
503
741
|
return v.replace(/\D/g, "").slice(0, 18);
|
|
504
742
|
}
|
|
@@ -507,21 +745,7 @@ export class SwirepayCheckout extends HTMLElement {
|
|
|
507
745
|
return v.replace(/\D/g, "").slice(0, 9);
|
|
508
746
|
}
|
|
509
747
|
|
|
510
|
-
|
|
511
|
-
e.preventDefault();
|
|
512
|
-
|
|
513
|
-
const payButton = this.shadow.getElementById("form").querySelector(".btn");
|
|
514
|
-
payButton.disabled = true;
|
|
515
|
-
payButton.textContent = "Processing...";
|
|
516
|
-
|
|
517
|
-
const err = this.validate();
|
|
518
|
-
if (err) {
|
|
519
|
-
alert(err);
|
|
520
|
-
payButton.disabled = false;
|
|
521
|
-
payButton.textContent = `Pay $${(this.amount / 100).toFixed(2)}`;
|
|
522
|
-
return;
|
|
523
|
-
}
|
|
524
|
-
|
|
748
|
+
async oneTimePayment() {
|
|
525
749
|
try {
|
|
526
750
|
const values = await this.getServerEncription();
|
|
527
751
|
if (values?.public_key) {
|
|
@@ -533,11 +757,7 @@ export class SwirepayCheckout extends HTMLElement {
|
|
|
533
757
|
const phone = getVal("phone");
|
|
534
758
|
|
|
535
759
|
const bankDetails = {
|
|
536
|
-
|
|
537
|
-
accountNumber: getVal("account-number"),
|
|
538
|
-
routingNumber: getVal("routing-number"),
|
|
539
|
-
accountType: getVal("account-type"),
|
|
540
|
-
bankName: getVal("bank-name"),
|
|
760
|
+
plaidPublicToken: this.processorToken,
|
|
541
761
|
businessType: getVal("business-type"),
|
|
542
762
|
};
|
|
543
763
|
|
|
@@ -547,13 +767,17 @@ export class SwirepayCheckout extends HTMLElement {
|
|
|
547
767
|
phone: phone ? `${phoneCode}${phone}` : null
|
|
548
768
|
};
|
|
549
769
|
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
770
|
+
let address = null;
|
|
771
|
+
|
|
772
|
+
if (this.isAddressRequired) {
|
|
773
|
+
address = {
|
|
774
|
+
street: getVal("street"),
|
|
775
|
+
city: getVal("city"),
|
|
776
|
+
state: getVal("state"),
|
|
777
|
+
countryCode: getVal("country"),
|
|
778
|
+
postalCode: getVal("zip")
|
|
779
|
+
};
|
|
780
|
+
}
|
|
557
781
|
|
|
558
782
|
const encriptedData = await this.encryptData(JSON.stringify(customer), values.public_key, keys.privateKey, values.key_id);
|
|
559
783
|
const payload = {
|
|
@@ -568,7 +792,7 @@ export class SwirepayCheckout extends HTMLElement {
|
|
|
568
792
|
const pmPayload = {
|
|
569
793
|
type: 'ACH_LEGACY',
|
|
570
794
|
bank: bankDetails,
|
|
571
|
-
postalCode: address?.
|
|
795
|
+
postalCode: address?.postalCode,
|
|
572
796
|
paymentMethodBillingAddress: address,
|
|
573
797
|
customerGid: customerGid
|
|
574
798
|
};
|
|
@@ -614,20 +838,272 @@ export class SwirepayCheckout extends HTMLElement {
|
|
|
614
838
|
body: JSON.stringify({ data: payload2?.data })
|
|
615
839
|
});
|
|
616
840
|
const resData = await res.json();
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
841
|
+
return resData;
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
} catch (error) {
|
|
845
|
+
console.error("Payment Error:", error);
|
|
846
|
+
this.events.emit("error", error);
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
async recurringPayment () {
|
|
851
|
+
try {
|
|
852
|
+
const values = await this.getServerEncription();
|
|
853
|
+
if (values?.public_key) {
|
|
854
|
+
const keys = await this.generateClientKeyPair();
|
|
855
|
+
if (keys?.privateKey) {
|
|
856
|
+
const getVal = id => this.shadow.getElementById(id)?.value?.trim();
|
|
857
|
+
const phoneCode = getVal("phone-code") || "";
|
|
858
|
+
const phone = getVal("phone");
|
|
859
|
+
|
|
860
|
+
const bankDetails = {
|
|
861
|
+
plaidPublicToken: this.processorToken,
|
|
862
|
+
businessType: getVal("business-type"),
|
|
863
|
+
};
|
|
864
|
+
|
|
865
|
+
const customer = {
|
|
866
|
+
name: getVal("name"),
|
|
867
|
+
email: getVal("email"),
|
|
868
|
+
phone: phone ? `${phoneCode}${phone}` : null
|
|
869
|
+
};
|
|
870
|
+
|
|
871
|
+
let address = null;
|
|
872
|
+
|
|
873
|
+
if (this.isAddressRequired) {
|
|
874
|
+
address = {
|
|
875
|
+
street: getVal("street"),
|
|
876
|
+
city: getVal("city"),
|
|
877
|
+
state: getVal("state"),
|
|
878
|
+
countryCode: getVal("country"),
|
|
879
|
+
postalCode: getVal("zip")
|
|
880
|
+
};
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
const encriptedData = await this.encryptData(JSON.stringify(customer), values.public_key, keys.privateKey, values.key_id);
|
|
884
|
+
const payload = {
|
|
885
|
+
publicKey: keys?.publicKey,
|
|
886
|
+
keyId: encriptedData?.keyId,
|
|
887
|
+
iv: encriptedData?.iv,
|
|
888
|
+
data: encriptedData?.encryptedData,
|
|
889
|
+
}
|
|
890
|
+
const newCustomer = await this.createCustomer(payload);
|
|
891
|
+
const customerGid = newCustomer.entity?.gid;
|
|
892
|
+
let product;
|
|
893
|
+
const itemInfo = await this.getItemInfo();
|
|
894
|
+
if (itemInfo?.entity?.content[0]?.gid) {
|
|
895
|
+
product = itemInfo?.entity?.content[0];
|
|
896
|
+
} else {
|
|
897
|
+
const newItemInfo = await this.addedItemInfo();
|
|
898
|
+
product = newItemInfo?.entity;
|
|
899
|
+
}
|
|
900
|
+
let plan;
|
|
901
|
+
const planInfo = await this.getPlan();
|
|
902
|
+
if (planInfo?.entity?.content[0]?.gid) {
|
|
903
|
+
plan = planInfo?.entity?.content[0];
|
|
904
|
+
} else {
|
|
905
|
+
const newPlanInfo = await this.addedPlanInfo();
|
|
906
|
+
plan = newPlanInfo?.entity;
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
const subscriptionData = {
|
|
910
|
+
currencyCode: this.currencyCode,
|
|
911
|
+
customerGid: customerGid,
|
|
912
|
+
plan2Gid: plan?.gid,
|
|
913
|
+
plan2BillingPeriod: 1,
|
|
914
|
+
plan2BillingFrequency: this.frequency,
|
|
915
|
+
plan2StartDate: new Date().toISOString(),
|
|
916
|
+
plan2TotalPayments: this.totalPayments,
|
|
917
|
+
description: this.description,
|
|
918
|
+
notificationType: "ALL",
|
|
919
|
+
emailRecipientList: [
|
|
920
|
+
customer.email
|
|
921
|
+
],
|
|
922
|
+
canCustomerCancelOrPause: true,
|
|
923
|
+
subscription2LineItems: [
|
|
924
|
+
{
|
|
925
|
+
itemGid: product?.gid,
|
|
926
|
+
quantity: 1,
|
|
927
|
+
upfront: false,
|
|
928
|
+
currencyCode: this.currencyCode,
|
|
929
|
+
amount: this.amount
|
|
930
|
+
}
|
|
931
|
+
]
|
|
932
|
+
}
|
|
933
|
+
const subscriptionDetails = await this.getSubScription(subscriptionData);
|
|
934
|
+
const subscription = subscriptionDetails?.entity;
|
|
935
|
+
const sessionData = {
|
|
936
|
+
link: subscription?.subscription2Links[0]?.link,
|
|
937
|
+
customer: subscription?.customer,
|
|
938
|
+
type: 'ACH_LEGACY',
|
|
939
|
+
bank: bankDetails,
|
|
940
|
+
postalCode: address?.postalCode,
|
|
941
|
+
paymentMethodBillingAddress: address
|
|
942
|
+
}
|
|
943
|
+
const encriptedData4 = await this.encryptData(JSON.stringify(sessionData), values.public_key, keys.privateKey, values.key_id);
|
|
944
|
+
const payload2 = {
|
|
945
|
+
publicKey: keys?.publicKey,
|
|
946
|
+
keyId: encriptedData4?.keyId,
|
|
947
|
+
iv: encriptedData4?.iv,
|
|
948
|
+
data: encriptedData4?.encryptedData,
|
|
949
|
+
}
|
|
950
|
+
const gateway = this.getEndpoints().gateway;
|
|
951
|
+
const url = `${gateway}/v2/subscription-link/${subscription?.subscription2Links[0]?.gid}/payment-method`;
|
|
952
|
+
const res = await fetch(url, {
|
|
953
|
+
method: 'POST',
|
|
954
|
+
headers: {
|
|
955
|
+
'x-enc-public-key': payload2?.publicKey,
|
|
956
|
+
'x-enc-key-id': payload2?.keyId,
|
|
957
|
+
'x-enc-iv': payload2?.iv,
|
|
958
|
+
'Content-Type': 'application/json',
|
|
959
|
+
'x-api-key': this.apiKey,
|
|
960
|
+
},
|
|
961
|
+
body: JSON.stringify({ data: payload2?.data })
|
|
962
|
+
});
|
|
963
|
+
const resData = await res.json();
|
|
964
|
+
return resData;
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
} catch (error) {
|
|
968
|
+
console.error("Payment Error:", error);
|
|
969
|
+
this.events.emit("error", error);
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
|
|
974
|
+
async inventoryCharge() {
|
|
975
|
+
try {
|
|
976
|
+
const values = await this.getServerEncription();
|
|
977
|
+
if (values?.public_key) {
|
|
978
|
+
const keys = await this.generateClientKeyPair();
|
|
979
|
+
if (keys?.privateKey) {
|
|
980
|
+
const getVal = id => this.shadow.getElementById(id)?.value?.trim();
|
|
981
|
+
const phoneCode = getVal("phone-code") || "";
|
|
982
|
+
const phone = getVal("phone");
|
|
983
|
+
|
|
984
|
+
const bankDetails = {
|
|
985
|
+
plaidPublicToken: this.processorToken,
|
|
986
|
+
businessType: getVal("business-type"),
|
|
987
|
+
};
|
|
988
|
+
|
|
989
|
+
const customer = {
|
|
990
|
+
name: getVal("name"),
|
|
991
|
+
email: getVal("email"),
|
|
992
|
+
phone: phone ? `${phoneCode}${phone}` : null
|
|
993
|
+
};
|
|
994
|
+
|
|
995
|
+
let address = null;
|
|
996
|
+
|
|
997
|
+
if (this.isAddressRequired) {
|
|
998
|
+
address = {
|
|
999
|
+
street: getVal("street"),
|
|
1000
|
+
city: getVal("city"),
|
|
1001
|
+
state: getVal("state"),
|
|
1002
|
+
countryCode: getVal("country"),
|
|
1003
|
+
postalCode: getVal("zip")
|
|
1004
|
+
};
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
const encriptedData = await this.encryptData(JSON.stringify(customer), values.public_key, keys.privateKey, values.key_id);
|
|
1008
|
+
const payload = {
|
|
1009
|
+
publicKey: keys?.publicKey,
|
|
1010
|
+
keyId: encriptedData?.keyId,
|
|
1011
|
+
iv: encriptedData?.iv,
|
|
1012
|
+
data: encriptedData?.encryptedData,
|
|
1013
|
+
}
|
|
1014
|
+
const newCustomer = await this.createCustomer(payload);
|
|
1015
|
+
const customerGid = newCustomer.entity?.gid;
|
|
1016
|
+
const orderDetails = await this.createOrder();
|
|
1017
|
+
const order = orderDetails?.entity;
|
|
1018
|
+
const sessionData = {
|
|
1019
|
+
customer: customer,
|
|
1020
|
+
customerGid: customerGid,
|
|
1021
|
+
paymentMethod: {
|
|
1022
|
+
bank: bankDetails,
|
|
1023
|
+
postalCode: address?.postalCode,
|
|
1024
|
+
type: "ACH_LEGACY",
|
|
1025
|
+
paymentMethodBillingAddress: address,
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
const encriptedData1 = await this.encryptData(JSON.stringify(sessionData), values.public_key, keys.privateKey, values.key_id);
|
|
1029
|
+
const payload2 = {
|
|
1030
|
+
publicKey: keys?.publicKey,
|
|
1031
|
+
keyId: encriptedData1?.keyId,
|
|
1032
|
+
iv: encriptedData1?.iv,
|
|
1033
|
+
data: encriptedData1?.encryptedData,
|
|
1034
|
+
}
|
|
1035
|
+
const gateway = this.getEndpoints().gateway;
|
|
1036
|
+
const url = `${gateway}/v1/inventory/order-link/${order?.inventoryOrderLink?.gid}/charge`;
|
|
1037
|
+
const res = await fetch(url, {
|
|
1038
|
+
method: 'POST',
|
|
1039
|
+
headers: {
|
|
1040
|
+
'x-enc-public-key': payload2?.publicKey,
|
|
1041
|
+
'x-enc-key-id': payload2?.keyId,
|
|
1042
|
+
'x-enc-iv': payload2?.iv,
|
|
1043
|
+
'Content-Type': 'application/json',
|
|
1044
|
+
'x-api-key': this.apiKey,
|
|
1045
|
+
},
|
|
1046
|
+
body: JSON.stringify({ data: payload2?.data })
|
|
1047
|
+
});
|
|
1048
|
+
const resData = await res.json();
|
|
1049
|
+
return resData;
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
} catch (error) {
|
|
1054
|
+
console.error("Payment Error:", error);
|
|
1055
|
+
this.events.emit("error", error);
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
async handleSubmit(e) {
|
|
1060
|
+
e.preventDefault();
|
|
1061
|
+
|
|
1062
|
+
const payButton = this.shadow.getElementById("form").querySelector(".btn");
|
|
1063
|
+
payButton.disabled = true;
|
|
1064
|
+
payButton.textContent = "Processing...";
|
|
1065
|
+
|
|
1066
|
+
const isValid = this.validate();
|
|
1067
|
+
if (!isValid) {
|
|
1068
|
+
payButton.disabled = false;
|
|
1069
|
+
payButton.textContent = `Pay $${(this.amount / 100).toFixed(2)}`;
|
|
1070
|
+
return;
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1073
|
+
try {
|
|
1074
|
+
if (this.frequency === "ONE-TIME" && !this.inventory) {
|
|
1075
|
+
const resData = await this.oneTimePayment();
|
|
1076
|
+
if (resData?.entity?.errorCode === null) {
|
|
1077
|
+
this.events.emit("success", resData);
|
|
1078
|
+
this.close();
|
|
1079
|
+
} else {
|
|
1080
|
+
const errorMsg = resData?.entity?.errorDescription || "Payment failed";
|
|
1081
|
+
console.error("Payment Error:", errorMsg);
|
|
1082
|
+
this.events.emit("error", errorMsg);
|
|
1083
|
+
}
|
|
1084
|
+
} else if (this.frequency !== "ONE-TIME" && !this.inventory) {
|
|
1085
|
+
const resData = await this.recurringPayment();
|
|
1086
|
+
if (resData?.entity?.setupSession?.errorCode === null) {
|
|
1087
|
+
this.events.emit("success", resData);
|
|
1088
|
+
this.close();
|
|
1089
|
+
} else {
|
|
1090
|
+
const errorMsg = resData?.entity?.setupSession?.errorDescription || "Payment failed";
|
|
1091
|
+
console.error("Payment Error:", errorMsg);
|
|
1092
|
+
this.events.emit("error", errorMsg);
|
|
1093
|
+
}
|
|
1094
|
+
} else if (this.inventory) {
|
|
1095
|
+
const resData = await this.inventoryCharge();
|
|
1096
|
+
if (resData?.responseCode === 200) {
|
|
1097
|
+
this.events.emit("success", resData);
|
|
1098
|
+
this.close();
|
|
1099
|
+
} else {
|
|
1100
|
+
console.error("Payment Error:", resData?.message || 'Payment failed');
|
|
1101
|
+
this.events.emit("error", resData?.message);
|
|
625
1102
|
}
|
|
626
1103
|
}
|
|
627
1104
|
} catch (error) {
|
|
628
1105
|
console.error("Payment Error:", error);
|
|
629
1106
|
this.events.emit("error", error);
|
|
630
|
-
alert(error.message || "Payment failed");
|
|
631
1107
|
} finally {
|
|
632
1108
|
payButton.disabled = false;
|
|
633
1109
|
payButton.textContent = `Pay $${(this.amount / 100).toFixed(2)}`;
|
|
@@ -636,6 +1112,7 @@ export class SwirepayCheckout extends HTMLElement {
|
|
|
636
1112
|
render() {
|
|
637
1113
|
const t = this.theme;
|
|
638
1114
|
const amountText = (this.amount / 100).toFixed(2);
|
|
1115
|
+
const inventoryAmountText = ((this.splitUp?.netPayable) / 100).toFixed(2);
|
|
639
1116
|
this.shadow.innerHTML = `
|
|
640
1117
|
<style>
|
|
641
1118
|
:host {
|
|
@@ -656,26 +1133,44 @@ export class SwirepayCheckout extends HTMLElement {
|
|
|
656
1133
|
background:rgba(0,0,0,0.6);
|
|
657
1134
|
justify-content:center;
|
|
658
1135
|
align-items:center;
|
|
1136
|
+
z-index:9999;
|
|
659
1137
|
}
|
|
660
1138
|
|
|
661
1139
|
.modal {
|
|
662
|
-
width:
|
|
1140
|
+
width: 520px;
|
|
1141
|
+
height: auto;
|
|
1142
|
+
max-height: 650px;
|
|
663
1143
|
background:var(--bg);
|
|
664
1144
|
color:var(--text);
|
|
665
1145
|
border-radius:16px;
|
|
666
|
-
padding:
|
|
1146
|
+
padding:28px;
|
|
667
1147
|
font-family:sans-serif;
|
|
668
1148
|
}
|
|
669
1149
|
|
|
1150
|
+
.modal-body {
|
|
1151
|
+
overflow-y: auto;
|
|
1152
|
+
flex: 1;
|
|
1153
|
+
height: 530px;
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
form {
|
|
1157
|
+
display: flex;
|
|
1158
|
+
flex-direction: column;
|
|
1159
|
+
gap: 16px;
|
|
1160
|
+
}
|
|
1161
|
+
|
|
670
1162
|
input, select {
|
|
671
|
-
width:100%;
|
|
672
|
-
padding:
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
1163
|
+
width: 100%;
|
|
1164
|
+
padding: 12px;
|
|
1165
|
+
border: 1px solid var(--border);
|
|
1166
|
+
background: #ffffff;
|
|
1167
|
+
color: #000000;
|
|
1168
|
+
border-radius: 8px;
|
|
1169
|
+
outline: none;
|
|
1170
|
+
height: 44px;
|
|
1171
|
+
font-size: 14px;
|
|
1172
|
+
box-sizing: border-box;
|
|
1173
|
+
margin: 0 !important;
|
|
679
1174
|
}
|
|
680
1175
|
|
|
681
1176
|
input::placeholder {
|
|
@@ -698,7 +1193,7 @@ input::placeholder {
|
|
|
698
1193
|
select {
|
|
699
1194
|
width:100%;
|
|
700
1195
|
padding:10px;
|
|
701
|
-
margin:
|
|
1196
|
+
margin: 0;
|
|
702
1197
|
border:1px solid var(--border);
|
|
703
1198
|
border-radius:8px;
|
|
704
1199
|
|
|
@@ -714,94 +1209,238 @@ select option {
|
|
|
714
1209
|
color: #000000;
|
|
715
1210
|
}
|
|
716
1211
|
|
|
717
|
-
.row {
|
|
1212
|
+
.row {
|
|
1213
|
+
display: flex;
|
|
1214
|
+
gap: 16px;
|
|
1215
|
+
align-items: center;
|
|
1216
|
+
}
|
|
1217
|
+
.phone-code {
|
|
1218
|
+
flex: 0 0 70px !important;
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
.row input,
|
|
1222
|
+
.row select {
|
|
1223
|
+
flex: 1;
|
|
1224
|
+
}
|
|
718
1225
|
|
|
719
|
-
|
|
1226
|
+
input, select {
|
|
1227
|
+
box-sizing: border-box;
|
|
1228
|
+
height: 40px;
|
|
1229
|
+
padding: 10px;
|
|
1230
|
+
font-size: 14px;
|
|
1231
|
+
}
|
|
720
1232
|
|
|
721
1233
|
.btn {
|
|
722
|
-
background:var(--primary);
|
|
723
|
-
color
|
|
724
|
-
padding:
|
|
725
|
-
border:none;
|
|
726
|
-
border-radius:10px;
|
|
727
|
-
cursor:pointer;
|
|
728
|
-
width:100%;
|
|
1234
|
+
background: var(--primary);
|
|
1235
|
+
color: #fff;
|
|
1236
|
+
padding: 14px;
|
|
1237
|
+
border: none;
|
|
1238
|
+
border-radius: 10px;
|
|
1239
|
+
cursor: pointer;
|
|
1240
|
+
width: 100%;
|
|
1241
|
+
height: 48px;
|
|
1242
|
+
font-size: 15px;
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
.btn1 {
|
|
1246
|
+
background: var(--primary);
|
|
1247
|
+
color: #fff;
|
|
1248
|
+
padding: 14px;
|
|
1249
|
+
border: none;
|
|
1250
|
+
border-radius: 10px;
|
|
1251
|
+
cursor: pointer;
|
|
1252
|
+
width: 100%;
|
|
1253
|
+
height: 48px;
|
|
1254
|
+
font-size: 15px;
|
|
729
1255
|
}
|
|
730
1256
|
|
|
731
1257
|
.close {
|
|
732
1258
|
float:right;
|
|
733
1259
|
cursor:pointer;
|
|
734
1260
|
}
|
|
1261
|
+
|
|
1262
|
+
h3 {
|
|
1263
|
+
margin-bottom: 16px;
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
.section {
|
|
1267
|
+
display: flex;
|
|
1268
|
+
flex-direction: column;
|
|
1269
|
+
gap: 16px;
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
.section-title {
|
|
1273
|
+
font-size: 14px;
|
|
1274
|
+
font-weight: 600;
|
|
1275
|
+
margin: 0;
|
|
1276
|
+
}
|
|
1277
|
+
.error {
|
|
1278
|
+
font-size: 12px;
|
|
1279
|
+
color: #dc2626;
|
|
1280
|
+
margin-top: 0px;
|
|
1281
|
+
margin-bottom: 0px;
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
.field {
|
|
1285
|
+
position: relative;
|
|
1286
|
+
width: 100%;
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
.field input,
|
|
1290
|
+
.field select {
|
|
1291
|
+
width: 100%;
|
|
1292
|
+
padding: 14px 12px;
|
|
1293
|
+
border: 1px solid var(--border);
|
|
1294
|
+
border-radius: 8px;
|
|
1295
|
+
font-size: 14px;
|
|
1296
|
+
background: #fff;
|
|
1297
|
+
outline: none;
|
|
1298
|
+
}
|
|
1299
|
+
.field label {
|
|
1300
|
+
position: absolute;
|
|
1301
|
+
left: 0px;
|
|
1302
|
+
top: 50%;
|
|
1303
|
+
transform: translateY(-50%);
|
|
1304
|
+
padding: 0 4px;
|
|
1305
|
+
color: #6b7280;
|
|
1306
|
+
font-size: 14px;
|
|
1307
|
+
pointer-events: none;
|
|
1308
|
+
transition: 0.2s ease;
|
|
1309
|
+
}
|
|
1310
|
+
.field input:focus + label,
|
|
1311
|
+
.field input:not(:placeholder-shown) + label {
|
|
1312
|
+
top: -8px;
|
|
1313
|
+
font-size: 12px;
|
|
1314
|
+
color: var(--primary);
|
|
1315
|
+
}
|
|
1316
|
+
.field select {
|
|
1317
|
+
width: 100%;
|
|
1318
|
+
height: 44px;
|
|
1319
|
+
padding: 0 12px;
|
|
1320
|
+
border: 1px solid var(--border);
|
|
1321
|
+
border-radius: 8px;
|
|
1322
|
+
background: #fff;
|
|
1323
|
+
color: #000;
|
|
1324
|
+
font-size: 14px;
|
|
1325
|
+
outline: none;
|
|
1326
|
+
appearance: none;
|
|
1327
|
+
}
|
|
1328
|
+
.input-error {
|
|
1329
|
+
border-color: #dc2626 !important;
|
|
1330
|
+
}
|
|
1331
|
+
|
|
1332
|
+
.field input.input-error + label {
|
|
1333
|
+
color: #dc2626;
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
.field label.floating {
|
|
1337
|
+
top: -8px;
|
|
1338
|
+
font-size: 12px;
|
|
1339
|
+
color: var(--primary);
|
|
1340
|
+
}
|
|
735
1341
|
</style>
|
|
736
1342
|
|
|
737
1343
|
<div class="overlay" id="overlay">
|
|
738
1344
|
<div class="modal">
|
|
1345
|
+
<div class="modal-header">
|
|
739
1346
|
<span class="close" id="close">✕</span>
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
1347
|
+
<h3>Pay By Bank</h3>
|
|
1348
|
+
</div>
|
|
1349
|
+
<div class="modal-body">
|
|
743
1350
|
<form id="form">
|
|
744
|
-
|
|
745
|
-
|
|
1351
|
+
<div class="section">
|
|
1352
|
+
<div class="section-title">Customer Details</div>
|
|
1353
|
+
<div class="field">
|
|
1354
|
+
<input id="name" required placeholder=" " />
|
|
1355
|
+
<label>Name *</label>
|
|
1356
|
+
</div>
|
|
1357
|
+
<div class="error" id="error-name"></div>
|
|
1358
|
+
<div class="field">
|
|
1359
|
+
<input id="email" required placeholder=" " />
|
|
1360
|
+
<label>Email *</label>
|
|
1361
|
+
</div>
|
|
1362
|
+
<div class="error" id="error-email"></div>
|
|
746
1363
|
|
|
747
1364
|
<div class="row">
|
|
748
|
-
<
|
|
749
|
-
|
|
1365
|
+
<div class="field phone-code">
|
|
1366
|
+
<input id="phone-code" placeholder=" " />
|
|
1367
|
+
<label>Code</label>
|
|
1368
|
+
</div>
|
|
1369
|
+
<div class="field">
|
|
1370
|
+
<input id="phone" required placeholder=" " />
|
|
1371
|
+
<label>Phone *</label>
|
|
1372
|
+
</div>
|
|
750
1373
|
</div>
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
<
|
|
754
|
-
<
|
|
755
|
-
|
|
756
|
-
<
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
<option value="SAVINGS">Savings</option>
|
|
760
|
-
</select>
|
|
761
|
-
|
|
762
|
-
<input id="bank-name" placeholder="Bank Name"/>
|
|
763
|
-
|
|
1374
|
+
<div class="error" id="error-phone"></div>
|
|
1375
|
+
</div>
|
|
1376
|
+
<div class="section">
|
|
1377
|
+
<div class="section-title">Bank Details</div>
|
|
1378
|
+
<button id="link-bank" class="btn1">Add Bank Account</button>
|
|
1379
|
+
<div id="bank-status"></div>
|
|
1380
|
+
<div class="error" id="error-bank"></div>
|
|
1381
|
+
<div class="field">
|
|
764
1382
|
<select id="business-type">
|
|
765
1383
|
<option value="">Business Type</option>
|
|
766
1384
|
<option value="INDIVIDUAL">Individual</option>
|
|
767
1385
|
<option value="BUSINESS">Business</option>
|
|
768
1386
|
</select>
|
|
1387
|
+
<label class="floating">Business Type *</label>
|
|
1388
|
+
</div>
|
|
1389
|
+
<div class="error" id="error-business-type"></div>
|
|
1390
|
+
</div>
|
|
769
1391
|
|
|
770
|
-
|
|
771
|
-
<
|
|
772
|
-
|
|
773
|
-
<!-- STATE FIRST -->
|
|
774
|
-
<select id="state"></select>
|
|
775
|
-
|
|
776
|
-
<!-- COUNTRY AFTER -->
|
|
777
|
-
<select id="country">
|
|
778
|
-
${COUNTRIES_LIST.map(c =>
|
|
779
|
-
`<option value="${c.code}" ${c.code === "US" ? "selected" : ""}>
|
|
780
|
-
${c.name}
|
|
781
|
-
</option>`
|
|
782
|
-
).join("")}
|
|
783
|
-
</select>
|
|
784
|
-
|
|
785
|
-
<input id="zip" placeholder="ZIP Code"/>
|
|
786
|
-
|
|
787
|
-
<button class="btn">Pay $${amountText}</button>
|
|
1392
|
+
${this.getAddressFields()}
|
|
1393
|
+
<button class="btn">Pay $${this.inventory ? inventoryAmountText : amountText}</button>
|
|
1394
|
+
</div>
|
|
788
1395
|
</form>
|
|
789
1396
|
</div>
|
|
790
1397
|
</div>
|
|
791
1398
|
`;
|
|
792
1399
|
|
|
793
1400
|
const $ = id => this.shadow.getElementById(id);
|
|
1401
|
+
if (this.customer) {
|
|
1402
|
+
if (this.customer.name) $("name").value = this.customer.name;
|
|
1403
|
+
if (this.customer.email) $("email").value = this.customer.email;
|
|
1404
|
+
|
|
1405
|
+
if (this.customer.phone) {
|
|
1406
|
+
let phone = this.customer.phone;
|
|
1407
|
+
let code = "";
|
|
1408
|
+
let number = phone;
|
|
1409
|
+
|
|
1410
|
+
if (phone.startsWith("+")) {
|
|
1411
|
+
if (phone.startsWith("+1")) {
|
|
1412
|
+
code = "+1";
|
|
1413
|
+
number = phone.slice(2);
|
|
1414
|
+
} else if (phone.startsWith("+91")) {
|
|
1415
|
+
code = "+91";
|
|
1416
|
+
number = phone.slice(3);
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1420
|
+
if ($("phone-code")) $("phone-code").value = code;
|
|
1421
|
+
if ($("phone")) $("phone").value = number;
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
this.shadow.getElementById("link-bank").onclick = async () => {
|
|
1425
|
+
if (!this.plaidHandler) await this.initPlaid();
|
|
1426
|
+
this.plaidHandler.open();
|
|
1427
|
+
};
|
|
794
1428
|
|
|
795
1429
|
$("close").onclick = () => this.close();
|
|
796
1430
|
$("form").onsubmit = e => this.handleSubmit(e);
|
|
797
1431
|
|
|
798
|
-
$("country").onchange = () => this.handleCountryChange();
|
|
799
|
-
|
|
800
1432
|
const countryEl = $("country");
|
|
801
|
-
countryEl
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
1433
|
+
if (countryEl) {
|
|
1434
|
+
countryEl.onchange = () => this.handleCountryChange();
|
|
1435
|
+
if (!this.customer?.countryCode) {
|
|
1436
|
+
countryEl.value = "US";
|
|
1437
|
+
}
|
|
1438
|
+
this.handleCountryChange();
|
|
1439
|
+
}
|
|
1440
|
+
const phoneCodeEl = $("phone-code");
|
|
1441
|
+
if (phoneCodeEl) {
|
|
1442
|
+
phoneCodeEl.dataset.auto = "true";
|
|
1443
|
+
}
|
|
805
1444
|
$("phone").oninput = e => e.target.value = this.formatPhone(e.target.value);
|
|
806
1445
|
}
|
|
807
1446
|
}
|