@tonder.io/ionic-full-sdk 0.0.9 → 0.0.11-beta

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.
@@ -1,554 +1,554 @@
1
- import { Card, cardItemsTemplate, cardTemplate, CollectorIds } from '../helpers/template'
2
- import { LiteCheckout } from '@tonder.io/ionic-lite-sdk';
3
- import {
4
- showError,
5
- showMessage,
6
- mapCards
7
- } from '../helpers/utils';
8
- import { initSkyflow } from '../helpers/skyflow'
9
- import { ThreeDSHandler } from './3dsHandler';
10
- import { ErrorResponse } from '@tonder.io/ionic-lite-sdk/dist/classes/errorResponse';
11
- import { Business, Customer, PaymentData, OrderItem } from '@tonder.io/ionic-lite-sdk/dist/types/commons';
12
- import { CustomerRegisterResponse, StartCheckoutResponse } from '@tonder.io/ionic-lite-sdk/dist/types/responses';
13
- import { StartCheckoutRequest, CreatePaymentRequest, CreateOrderRequest } from '@tonder.io/ionic-lite-sdk/dist/types/requests';
14
- import { InCollectorContainer } from '../helpers/skyflow';
15
-
16
- export type InlineCheckoutConstructor = {
17
- returnUrl: string,
18
- apiKey: string,
19
- successUrl?: string,
20
- renderPaymentButton: boolean,
21
- callBack?: (params: any) => void,
22
- styles?: any,
23
- containerId?: string,
24
- collectorIds?: CollectorIds,
25
- isOpenPaySandbox?: boolean
26
- }
27
-
28
- export class InlineCheckout {
29
- paymentData = {}
30
- items = []
31
- baseUrl = "https://stage.tonder.io";
32
- collectContainer: InCollectorContainer | null = null;
33
- cartTotal?: string | null | number
34
- apiKeyTonder: string
35
- returnUrl?: string
36
- successUrl?: string
37
- renderPaymentButton: boolean
38
- callBack: (params: any) => void
39
- customStyles: any
40
- abortController: AbortController
41
- process3ds: ThreeDSHandler
42
- cb?: () => void
43
- firstName?: string
44
- lastName?: string
45
- country?: string
46
- address?: string
47
- city?: string
48
- state?: string
49
- postCode?: string
50
- email?: string
51
- phone?: string
52
- merchantData?: Business | ErrorResponse
53
- cartItems?: any
54
- injectInterval: any
55
- containerId: string
56
- injected: boolean
57
- cardsInjected: boolean
58
- collectorIds: CollectorIds
59
- platforms?: string[]
60
- liteCheckout: LiteCheckout
61
- clientCards: Card[]
62
- radioChecked: string | null
63
- fetchingPayment: boolean
64
- isOpenPaySandbox: boolean = true
65
-
66
- constructor ({
67
- apiKey,
68
- returnUrl,
69
- successUrl,
70
- renderPaymentButton = false,
71
- callBack = () => {},
72
- styles,
73
- containerId,
74
- collectorIds,
75
- isOpenPaySandbox
76
- }: InlineCheckoutConstructor) {
77
- this.apiKeyTonder = apiKey;
78
- this.returnUrl = returnUrl;
79
- this.successUrl = successUrl;
80
- this.renderPaymentButton = renderPaymentButton;
81
- this.callBack = callBack;
82
- this.customStyles = styles
83
-
84
- this.abortController = new AbortController()
85
-
86
- this.liteCheckout = new LiteCheckout({
87
- apiKeyTonder: apiKey,
88
- baseUrlTonder: this.baseUrl,
89
- signal: this.abortController.signal
90
- })
91
-
92
- this.process3ds = new ThreeDSHandler({
93
- apiKey: apiKey,
94
- baseUrl: this.baseUrl,
95
- successUrl: successUrl
96
- })
97
- this.containerId = containerId ? containerId : "tonder-checkout"
98
- this.injected = false;
99
- this.cardsInjected = false;
100
- this.collectorIds = collectorIds ? collectorIds : {
101
- cardsListContainer: "cardsListContainer",
102
- holderName: "collectCardholderName",
103
- cardNumber: "collectCardNumber",
104
- expirationMonth: "collectExpirationMonth",
105
- expirationYear: "collectExpirationYear",
106
- cvv: "collectCvv",
107
- tonderPayButton: "tonderPayButton",
108
- msgError: "msgError",
109
- msgNotification: "msgNotification"
110
- }
111
- this.clientCards = []
112
- this.radioChecked = "new"
113
- this.collectContainer = null;
114
-
115
- this.fetchingPayment = false;
116
-
117
- this.isOpenPaySandbox = isOpenPaySandbox === undefined ? true : isOpenPaySandbox
118
- }
119
-
120
- #mountPayButton() {
121
- if (!this.renderPaymentButton) return;
122
-
123
- const payButton: HTMLElement | null = document.querySelector(`#${this.collectorIds.tonderPayButton}`);
124
-
125
- if (!payButton) {
126
- console.error("Pay button not found");
127
- return;
128
- }
129
-
130
- const LOCALE_MONEY = "en-Latn-US";
131
-
132
- payButton.style.display = "block";
133
-
134
- const inCartTotal = Intl.NumberFormat(LOCALE_MONEY, { minimumFractionDigits: 2 }).format(this.cartTotal as number);
135
-
136
- payButton.textContent = `Pagar $${inCartTotal}`;
137
-
138
- payButton.onclick = async (event) => {
139
- event.preventDefault();
140
- await this.#handlePaymentClick(payButton);
141
- };
142
-
143
- }
144
-
145
- async #handlePaymentClick(payButton: any) {
146
- const prevButtonContent = payButton.innerHTML;
147
- payButton.innerHTML = `<div class="lds-dual-ring"></div>`;
148
- try {
149
- const response = await this.payment(this.paymentData);
150
- this.callBack(response);
151
- } catch (error) {
152
- console.error("Payment error:", error);
153
- } finally {
154
- payButton.innerHTML = prevButtonContent;
155
- }
156
- }
157
-
158
- payment(data: any) {
159
- return new Promise(async (resolve, reject) => {
160
- try {
161
- this.#handleCustomer(data.customer)
162
- this.setCartTotal(data.cart?.total)
163
- this.setCartItems(data.cart?.items)
164
- const response: ErrorResponse | StartCheckoutResponse | false | undefined = await this.#checkout()
165
- if (response) {
166
- const process3ds = new ThreeDSHandler({
167
- payload: response,
168
- baseUrl: this.baseUrl,
169
- apiKey: this.apiKeyTonder,
170
- successUrl: this.successUrl
171
- });
172
- this.callBack(response);
173
- if (!process3ds.redirectTo3DS()) {
174
- resolve(response);
175
- } else {
176
- resolve(response);
177
- }
178
- }
179
- } catch (error) {
180
- reject(error);
181
- }
182
- });
183
- }
184
-
185
- #mountRadioButtons () {
186
- const radioButtons: NodeListOf<HTMLElement> = document.getElementsByName(`card_selected`);
187
- for (const radio of radioButtons) {
188
- radio.style.display = "block";
189
- radio.onclick = async (event) => {
190
- //event.preventDefault();
191
- await this.#handleRadioButtonClick(radio);
192
- };
193
- }
194
- }
195
-
196
- async #handleRadioButtonClick (radio: HTMLElement) {
197
- const containerForm: HTMLElement | null = document.querySelector(".container-form");
198
- if(containerForm) {
199
- containerForm.style.display = radio.id === "new" ? "block" : "none";
200
- }
201
- if(radio.id === "new") {
202
- await this.#mountForm();
203
- } else {
204
- this.#unmountForm();
205
- }
206
- this.radioChecked = radio.id;
207
- }
208
-
209
- #handleCustomer(customer: Customer) {
210
- if (!customer) return
211
-
212
- this.firstName = customer?.firstName
213
- this.lastName = customer?.lastName
214
- this.country = customer?.country
215
- this.address = customer?.street
216
- this.city = customer?.city
217
- this.state = customer?.state
218
- this.postCode = customer?.postCode
219
- this.email = customer?.email
220
- this.phone = customer?.phone
221
- }
222
-
223
- setCartItems (items: OrderItem[]) {
224
- this.cartItems = items
225
- }
226
-
227
- setCustomerEmail (email: string) {
228
- this.email = email
229
- }
230
-
231
- setPaymentData (data?: PaymentData) {
232
- if (!data) return
233
- this.paymentData = data
234
- }
235
-
236
- setCartTotal (total: string | number) {
237
- this.cartTotal = total
238
- this.#updatePayButton()
239
- }
240
-
241
- #updatePayButton() {
242
- const payButton = document.querySelector(`#${this.collectorIds.tonderPayButton}`);
243
- if (!payButton) return
244
- payButton.textContent = `Pagar $${this.cartTotal}`;
245
- }
246
-
247
- setCallback (cb: any) {
248
- this.cb = cb
249
- }
250
-
251
- injectCheckout() {
252
- if (this.injected) return
253
- this.process3ds.verifyTransactionStatus()
254
- const injectInterval = setInterval(() => {
255
- const queryElement = document.querySelector(`#${this.containerId}`)
256
- if (queryElement) {
257
- queryElement.innerHTML = cardTemplate(this.customStyles ? true : false, this.collectorIds)
258
- this.#mountTonder();
259
- clearInterval(injectInterval);
260
- this.injected = true
261
- }
262
- }, 500);
263
- }
264
-
265
- loadCardsList (cards: Card[]) {
266
- if(this.cardsInjected) return;
267
- const injectInterval = setInterval(() => {
268
- const queryElement = document.querySelector(`#${this.collectorIds.cardsListContainer}`);
269
- if (queryElement && this.injected) {
270
- queryElement.innerHTML = cardItemsTemplate(this.customStyles ? true : false, cards)
271
- clearInterval(injectInterval)
272
- this.#mountRadioButtons()
273
- this.cardsInjected = true
274
- }
275
- }, 500);
276
- }
277
-
278
- async #fetchMerchantData() {
279
- this.merchantData = await this.liteCheckout.getBusiness();
280
- return this.merchantData
281
- }
282
-
283
- async getCustomer(email: string) {
284
- return await this.liteCheckout.customerRegister(email);
285
- }
286
-
287
- async #mountTonder() {
288
-
289
- this.#mountPayButton()
290
-
291
- const result = await this.#fetchMerchantData();
292
-
293
- if(result && "vault_id" in result) {
294
-
295
- const { vault_id, vault_url } = result;
296
-
297
- if(this.email) {
298
-
299
- const customerResponse : CustomerRegisterResponse | ErrorResponse = await this.getCustomer(this.email);
300
-
301
- if("auth_token" in customerResponse) {
302
-
303
- const { auth_token } = customerResponse
304
-
305
- const cards = await this.liteCheckout.getCustomerCards(auth_token);
306
-
307
- if("cards" in cards) {
308
-
309
- const cardsMapped: Card[] = cards.cards.map(mapCards)
310
-
311
- this.loadCardsList(cardsMapped)
312
-
313
- }
314
-
315
- }
316
-
317
- }
318
-
319
- this.collectContainer = await initSkyflow(
320
- vault_id,
321
- vault_url,
322
- this.baseUrl,
323
- this.abortController.signal,
324
- this.customStyles,
325
- this.collectorIds,
326
- this.apiKeyTonder
327
- );
328
-
329
- }
330
-
331
- }
332
-
333
- removeCheckout() {
334
-
335
- this.injected = false
336
- this.cardsInjected = false
337
- // Cancel all requests
338
- this.abortController.abort();
339
- this.abortController = new AbortController();
340
- clearInterval(this.injectInterval);
341
- console.log("InlineCheckout removed from DOM and cleaned up.");
342
-
343
- }
344
-
345
- #unmountForm () {
346
-
347
- this.injected = false
348
-
349
- if(this.collectContainer) {
350
- if("unmount" in this.collectContainer.elements.cardHolderNameElement) this.collectContainer.elements.cardHolderNameElement.unmount()
351
- if("unmount" in this.collectContainer.elements.cardNumberElement) this.collectContainer.elements.cardNumberElement.unmount()
352
- if("unmount" in this.collectContainer.elements.expiryYearElement) this.collectContainer.elements.expiryYearElement.unmount()
353
- if("unmount" in this.collectContainer.elements.expiryMonthElement) this.collectContainer.elements.expiryMonthElement.unmount()
354
- if("unmount" in this.collectContainer.elements.cvvElement) this.collectContainer.elements.cvvElement.unmount()
355
- }
356
-
357
- }
358
-
359
- async #mountForm () {
360
-
361
- const result = await this.#fetchMerchantData();
362
-
363
- if(result && "vault_id" in result) {
364
-
365
- const { vault_id, vault_url } = result;
366
-
367
- this.collectContainer = await initSkyflow(
368
- vault_id,
369
- vault_url,
370
- this.baseUrl,
371
- this.abortController.signal,
372
- this.customStyles,
373
- this.collectorIds,
374
- this.apiKeyTonder
375
- );
376
-
377
- }
378
-
379
- }
380
-
381
- async #checkout() {
382
-
383
- try {
384
-
385
- try {
386
-
387
- const selector: any = document.querySelector(`#${this.collectorIds.tonderPayButton}`);
388
-
389
- if(selector){
390
- selector.disabled = true;
391
- selector.innerHTML = "Cargando..."
392
- }
393
-
394
- } catch (error) { }
395
-
396
- if(this.merchantData) {
397
-
398
- if("openpay_keys" in this.merchantData) {
399
-
400
- const { openpay_keys, reference, business } = this.merchantData
401
-
402
- const total = Number(this.cartTotal)
403
-
404
- let cardTokensSkyflowTonder: any = null;
405
-
406
- if(this.radioChecked === "new") {
407
-
408
- if(this.collectContainer && "container" in this.collectContainer && "collect" in this.collectContainer.container) {
409
- try {
410
- const collectResponseSkyflowTonder: any = await this.collectContainer?.container.collect();
411
- cardTokensSkyflowTonder = await collectResponseSkyflowTonder["records"][0]["fields"];
412
- } catch (error) {
413
- showError("Por favor, verifica todos los campos de tu tarjeta", this.collectorIds.msgError, this.collectorIds.tonderPayButton)
414
- throw error;
415
- }
416
- } else {
417
- showError("Por favor, verifica todos los campos de tu tarjeta", this.collectorIds.msgError, this.collectorIds.tonderPayButton)
418
- }
419
-
420
- } else {
421
-
422
- cardTokensSkyflowTonder = {
423
- skyflow_id: this.radioChecked
424
- }
425
-
426
- }
427
-
428
- let deviceSessionIdTonder: any;
429
-
430
- if (openpay_keys.merchant_id && openpay_keys.public_key) {
431
- deviceSessionIdTonder = await this.liteCheckout.getOpenpayDeviceSessionID(
432
- openpay_keys.merchant_id,
433
- openpay_keys.public_key,
434
- this.isOpenPaySandbox
435
- );
436
- }
437
-
438
- if(this.email) {
439
-
440
- const customerResponse : CustomerRegisterResponse | ErrorResponse = await this.getCustomer(this.email);
441
-
442
- if("auth_token" in customerResponse) {
443
-
444
- const { auth_token } = customerResponse;
445
-
446
- const saveCard: HTMLElement | null = document.getElementById("save-checkout-card");
447
-
448
- if(saveCard && "checked" in saveCard && saveCard.checked) {
449
-
450
- await this.liteCheckout.registerCustomerCard(auth_token, { skyflow_id: cardTokensSkyflowTonder.skyflow_id });
451
-
452
- this.cardsInjected = false;
453
-
454
- const cards = await this.liteCheckout.getCustomerCards(auth_token);
455
-
456
- if("cards" in cards) {
457
-
458
- const cardsMapped: Card[] = cards.cards.map((card) => mapCards(card))
459
-
460
- this.loadCardsList(cardsMapped)
461
-
462
- }
463
-
464
- showMessage("Tarjeta registrada con éxito", this.collectorIds.msgNotification);
465
-
466
- }
467
-
468
- const orderItems: CreateOrderRequest = {
469
- business: this.apiKeyTonder,
470
- client: auth_token,
471
- billing_address_id: null,
472
- shipping_address_id: null,
473
- amount: total,
474
- status: "A",
475
- reference: reference,
476
- is_oneclick: true,
477
- items: this.cartItems,
478
- };
479
-
480
- const jsonResponseOrder = await this.liteCheckout.createOrder(
481
- orderItems
482
- );
483
-
484
- // Create payment
485
- const now = new Date();
486
- const dateString = now.toISOString();
487
-
488
- if("id" in jsonResponseOrder) {
489
-
490
- const paymentItems: CreatePaymentRequest = {
491
- business_pk: business.pk,
492
- amount: total,
493
- date: dateString,
494
- order: jsonResponseOrder.id
495
- };
496
-
497
- const jsonResponsePayment = await this.liteCheckout.createPayment(
498
- paymentItems
499
- );
500
-
501
- // Checkout router
502
- const routerItems: StartCheckoutRequest = {
503
- card: cardTokensSkyflowTonder,
504
- name: cardTokensSkyflowTonder.cardholder_name,
505
- last_name: "",
506
- email_client: this.email,
507
- phone_number: this.phone,
508
- return_url: this.returnUrl,
509
- id_product: "no_id",
510
- quantity_product: 1,
511
- id_ship: "0",
512
- instance_id_ship: "0",
513
- amount: total,
514
- title_ship: "shipping",
515
- description: "transaction",
516
- device_session_id: deviceSessionIdTonder ? deviceSessionIdTonder : null,
517
- token_id: "",
518
- order_id: ("id" in jsonResponseOrder) && jsonResponseOrder.id,
519
- business_id: business.pk,
520
- payment_id: ("pk" in jsonResponsePayment) && jsonResponsePayment.pk,
521
- source: 'sdk',
522
- };
523
-
524
- const jsonResponseRouter = await this.liteCheckout.startCheckoutRouter(
525
- routerItems
526
- );
527
- if (jsonResponseRouter) {
528
- try {
529
- const selector: any = document.querySelector(`#${this.collectorIds.tonderPayButton}`);
530
- if(selector) {
531
- selector.disabled = false;
532
- }
533
- } catch {}
534
- return jsonResponseRouter;
535
- } else {
536
- showError("No se ha podido procesar el pago", this.collectorIds.msgError, this.collectorIds.tonderPayButton)
537
- return false;
538
- }
539
- }
540
- }
541
- }
542
- }
543
- } else {
544
- showError("No se han configurado los datos del proveedor de servicio", this.collectorIds.msgError, this.collectorIds.tonderPayButton)
545
- }
546
- } catch (error) {
547
- console.log(error);
548
- showError("Ha ocurrido un error", this.collectorIds.msgError, this.collectorIds.tonderPayButton)
549
- throw error;
550
- } finally {
551
- this.fetchingPayment = false;
552
- }
553
- };
1
+ import { Card, cardItemsTemplate, cardTemplate, CollectorIds } from '../helpers/template'
2
+ import { LiteCheckout } from '@tonder.io/ionic-lite-sdk';
3
+ import {
4
+ showError,
5
+ showMessage,
6
+ mapCards
7
+ } from '../helpers/utils';
8
+ import { initSkyflow } from '../helpers/skyflow'
9
+ import { ThreeDSHandler } from './3dsHandler';
10
+ import { ErrorResponse } from '@tonder.io/ionic-lite-sdk/dist/classes/errorResponse';
11
+ import { Business, Customer, PaymentData, OrderItem } from '@tonder.io/ionic-lite-sdk/dist/types/commons';
12
+ import { CustomerRegisterResponse, StartCheckoutResponse } from '@tonder.io/ionic-lite-sdk/dist/types/responses';
13
+ import { StartCheckoutRequest, CreatePaymentRequest, CreateOrderRequest } from '@tonder.io/ionic-lite-sdk/dist/types/requests';
14
+ import { InCollectorContainer } from '../helpers/skyflow';
15
+
16
+ export type InlineCheckoutConstructor = {
17
+ returnUrl: string,
18
+ apiKey: string,
19
+ successUrl?: string,
20
+ renderPaymentButton: boolean,
21
+ callBack?: (params: any) => void,
22
+ styles?: any,
23
+ containerId?: string,
24
+ collectorIds?: CollectorIds,
25
+ isOpenPaySandbox?: boolean
26
+ }
27
+
28
+ export class InlineCheckout {
29
+ paymentData = {}
30
+ items = []
31
+ baseUrl = "https://stage.tonder.io";
32
+ collectContainer: InCollectorContainer | null = null;
33
+ cartTotal?: string | null | number
34
+ apiKeyTonder: string
35
+ returnUrl?: string
36
+ successUrl?: string
37
+ renderPaymentButton: boolean
38
+ callBack: (params: any) => void
39
+ customStyles: any
40
+ abortController: AbortController
41
+ process3ds: ThreeDSHandler
42
+ cb?: () => void
43
+ firstName?: string
44
+ lastName?: string
45
+ country?: string
46
+ address?: string
47
+ city?: string
48
+ state?: string
49
+ postCode?: string
50
+ email?: string
51
+ phone?: string
52
+ merchantData?: Business | ErrorResponse
53
+ cartItems?: any
54
+ injectInterval: any
55
+ containerId: string
56
+ injected: boolean
57
+ cardsInjected: boolean
58
+ collectorIds: CollectorIds
59
+ platforms?: string[]
60
+ liteCheckout: LiteCheckout
61
+ clientCards: Card[]
62
+ radioChecked: string | null
63
+ fetchingPayment: boolean
64
+ isOpenPaySandbox: boolean = true
65
+
66
+ constructor ({
67
+ apiKey,
68
+ returnUrl,
69
+ successUrl,
70
+ renderPaymentButton = false,
71
+ callBack = () => {},
72
+ styles,
73
+ containerId,
74
+ collectorIds,
75
+ isOpenPaySandbox
76
+ }: InlineCheckoutConstructor) {
77
+ this.apiKeyTonder = apiKey;
78
+ this.returnUrl = returnUrl;
79
+ this.successUrl = successUrl;
80
+ this.renderPaymentButton = renderPaymentButton;
81
+ this.callBack = callBack;
82
+ this.customStyles = styles
83
+
84
+ this.abortController = new AbortController()
85
+
86
+ this.liteCheckout = new LiteCheckout({
87
+ apiKeyTonder: apiKey,
88
+ baseUrlTonder: this.baseUrl,
89
+ signal: this.abortController.signal
90
+ })
91
+
92
+ this.process3ds = new ThreeDSHandler({
93
+ apiKey: apiKey,
94
+ baseUrl: this.baseUrl,
95
+ successUrl: successUrl
96
+ })
97
+ this.containerId = containerId ? containerId : "tonder-checkout"
98
+ this.injected = false;
99
+ this.cardsInjected = false;
100
+ this.collectorIds = collectorIds ? collectorIds : {
101
+ cardsListContainer: "cardsListContainer",
102
+ holderName: "collectCardholderName",
103
+ cardNumber: "collectCardNumber",
104
+ expirationMonth: "collectExpirationMonth",
105
+ expirationYear: "collectExpirationYear",
106
+ cvv: "collectCvv",
107
+ tonderPayButton: "tonderPayButton",
108
+ msgError: "msgError",
109
+ msgNotification: "msgNotification"
110
+ }
111
+ this.clientCards = []
112
+ this.radioChecked = "new"
113
+ this.collectContainer = null;
114
+
115
+ this.fetchingPayment = false;
116
+
117
+ this.isOpenPaySandbox = isOpenPaySandbox === undefined ? true : isOpenPaySandbox
118
+ }
119
+
120
+ #mountPayButton() {
121
+ if (!this.renderPaymentButton) return;
122
+
123
+ const payButton: HTMLElement | null = document.querySelector(`#${this.collectorIds.tonderPayButton}`);
124
+
125
+ if (!payButton) {
126
+ console.error("Pay button not found");
127
+ return;
128
+ }
129
+
130
+ const LOCALE_MONEY = "en-Latn-US";
131
+
132
+ payButton.style.display = "block";
133
+
134
+ const inCartTotal = Intl.NumberFormat(LOCALE_MONEY, { minimumFractionDigits: 2 }).format(this.cartTotal as number);
135
+
136
+ payButton.textContent = `Pagar $${inCartTotal}`;
137
+
138
+ payButton.onclick = async (event) => {
139
+ event.preventDefault();
140
+ await this.#handlePaymentClick(payButton);
141
+ };
142
+
143
+ }
144
+
145
+ async #handlePaymentClick(payButton: any) {
146
+ const prevButtonContent = payButton.innerHTML;
147
+ payButton.innerHTML = `<div class="lds-dual-ring"></div>`;
148
+ try {
149
+ const response = await this.payment(this.paymentData);
150
+ this.callBack(response);
151
+ } catch (error) {
152
+ console.error("Payment error:", error);
153
+ } finally {
154
+ payButton.innerHTML = prevButtonContent;
155
+ }
156
+ }
157
+
158
+ payment(data: any) {
159
+ return new Promise(async (resolve, reject) => {
160
+ try {
161
+ this.#handleCustomer(data.customer)
162
+ this.setCartTotal(data.cart?.total)
163
+ this.setCartItems(data.cart?.items)
164
+ const response: ErrorResponse | StartCheckoutResponse | false | undefined = await this.#checkout()
165
+ if (response) {
166
+ const process3ds = new ThreeDSHandler({
167
+ payload: response,
168
+ baseUrl: this.baseUrl,
169
+ apiKey: this.apiKeyTonder,
170
+ successUrl: this.successUrl
171
+ });
172
+ this.callBack(response);
173
+ if (!process3ds.redirectTo3DS()) {
174
+ resolve(response);
175
+ } else {
176
+ resolve(response);
177
+ }
178
+ }
179
+ } catch (error) {
180
+ reject(error);
181
+ }
182
+ });
183
+ }
184
+
185
+ #mountRadioButtons () {
186
+ const radioButtons: NodeListOf<HTMLElement> = document.getElementsByName(`card_selected`);
187
+ for (const radio of radioButtons) {
188
+ radio.style.display = "block";
189
+ radio.onclick = async (event) => {
190
+ //event.preventDefault();
191
+ await this.#handleRadioButtonClick(radio);
192
+ };
193
+ }
194
+ }
195
+
196
+ async #handleRadioButtonClick (radio: HTMLElement) {
197
+ const containerForm: HTMLElement | null = document.querySelector(".container-form");
198
+ if(containerForm) {
199
+ containerForm.style.display = radio.id === "new" ? "block" : "none";
200
+ }
201
+ if(radio.id === "new") {
202
+ await this.#mountForm();
203
+ } else {
204
+ this.#unmountForm();
205
+ }
206
+ this.radioChecked = radio.id;
207
+ }
208
+
209
+ #handleCustomer(customer: Customer) {
210
+ if (!customer) return
211
+
212
+ this.firstName = customer?.firstName
213
+ this.lastName = customer?.lastName
214
+ this.country = customer?.country
215
+ this.address = customer?.street
216
+ this.city = customer?.city
217
+ this.state = customer?.state
218
+ this.postCode = customer?.postCode
219
+ this.email = customer?.email
220
+ this.phone = customer?.phone
221
+ }
222
+
223
+ setCartItems (items: OrderItem[]) {
224
+ this.cartItems = items
225
+ }
226
+
227
+ setCustomerEmail (email: string) {
228
+ this.email = email
229
+ }
230
+
231
+ setPaymentData (data?: PaymentData) {
232
+ if (!data) return
233
+ this.paymentData = data
234
+ }
235
+
236
+ setCartTotal (total: string | number) {
237
+ this.cartTotal = total
238
+ this.#updatePayButton()
239
+ }
240
+
241
+ #updatePayButton() {
242
+ const payButton = document.querySelector(`#${this.collectorIds.tonderPayButton}`);
243
+ if (!payButton) return
244
+ payButton.textContent = `Pagar $${this.cartTotal}`;
245
+ }
246
+
247
+ setCallback (cb: any) {
248
+ this.cb = cb
249
+ }
250
+
251
+ injectCheckout() {
252
+ if (this.injected) return
253
+ this.process3ds.verifyTransactionStatus()
254
+ const injectInterval = setInterval(() => {
255
+ const queryElement = document.querySelector(`#${this.containerId}`)
256
+ if (queryElement) {
257
+ queryElement.innerHTML = cardTemplate(this.customStyles ? true : false, this.collectorIds)
258
+ this.#mountTonder();
259
+ clearInterval(injectInterval);
260
+ this.injected = true
261
+ }
262
+ }, 500);
263
+ }
264
+
265
+ loadCardsList (cards: Card[]) {
266
+ if(this.cardsInjected) return;
267
+ const injectInterval = setInterval(() => {
268
+ const queryElement = document.querySelector(`#${this.collectorIds.cardsListContainer}`);
269
+ if (queryElement && this.injected) {
270
+ queryElement.innerHTML = cardItemsTemplate(this.customStyles ? true : false, cards)
271
+ clearInterval(injectInterval)
272
+ this.#mountRadioButtons()
273
+ this.cardsInjected = true
274
+ }
275
+ }, 500);
276
+ }
277
+
278
+ async #fetchMerchantData() {
279
+ this.merchantData = await this.liteCheckout.getBusiness();
280
+ return this.merchantData
281
+ }
282
+
283
+ async getCustomer(email: string) {
284
+ return await this.liteCheckout.customerRegister(email);
285
+ }
286
+
287
+ async #mountTonder() {
288
+
289
+ this.#mountPayButton()
290
+
291
+ const result = await this.#fetchMerchantData();
292
+
293
+ if(result && "vault_id" in result) {
294
+
295
+ const { vault_id, vault_url } = result;
296
+
297
+ if(this.email) {
298
+
299
+ const customerResponse : CustomerRegisterResponse | ErrorResponse = await this.getCustomer(this.email);
300
+
301
+ if("auth_token" in customerResponse) {
302
+
303
+ const { auth_token } = customerResponse
304
+
305
+ const cards = await this.liteCheckout.getCustomerCards(auth_token);
306
+
307
+ if("cards" in cards) {
308
+
309
+ const cardsMapped: Card[] = cards.cards.map(mapCards)
310
+
311
+ this.loadCardsList(cardsMapped)
312
+
313
+ }
314
+
315
+ }
316
+
317
+ }
318
+
319
+ this.collectContainer = await initSkyflow(
320
+ vault_id,
321
+ vault_url,
322
+ this.baseUrl,
323
+ this.abortController.signal,
324
+ this.customStyles,
325
+ this.collectorIds,
326
+ this.apiKeyTonder
327
+ );
328
+
329
+ }
330
+
331
+ }
332
+
333
+ removeCheckout() {
334
+
335
+ this.injected = false
336
+ this.cardsInjected = false
337
+ // Cancel all requests
338
+ this.abortController.abort();
339
+ this.abortController = new AbortController();
340
+ clearInterval(this.injectInterval);
341
+ console.log("InlineCheckout removed from DOM and cleaned up.");
342
+
343
+ }
344
+
345
+ #unmountForm () {
346
+
347
+ this.injected = false
348
+
349
+ if(this.collectContainer) {
350
+ if("unmount" in this.collectContainer.elements.cardHolderNameElement) this.collectContainer.elements.cardHolderNameElement.unmount()
351
+ if("unmount" in this.collectContainer.elements.cardNumberElement) this.collectContainer.elements.cardNumberElement.unmount()
352
+ if("unmount" in this.collectContainer.elements.expiryYearElement) this.collectContainer.elements.expiryYearElement.unmount()
353
+ if("unmount" in this.collectContainer.elements.expiryMonthElement) this.collectContainer.elements.expiryMonthElement.unmount()
354
+ if("unmount" in this.collectContainer.elements.cvvElement) this.collectContainer.elements.cvvElement.unmount()
355
+ }
356
+
357
+ }
358
+
359
+ async #mountForm () {
360
+
361
+ const result = await this.#fetchMerchantData();
362
+
363
+ if(result && "vault_id" in result) {
364
+
365
+ const { vault_id, vault_url } = result;
366
+
367
+ this.collectContainer = await initSkyflow(
368
+ vault_id,
369
+ vault_url,
370
+ this.baseUrl,
371
+ this.abortController.signal,
372
+ this.customStyles,
373
+ this.collectorIds,
374
+ this.apiKeyTonder
375
+ );
376
+
377
+ }
378
+
379
+ }
380
+
381
+ async #checkout() {
382
+
383
+ try {
384
+
385
+ try {
386
+
387
+ const selector: any = document.querySelector(`#${this.collectorIds.tonderPayButton}`);
388
+
389
+ if(selector){
390
+ selector.disabled = true;
391
+ selector.innerHTML = "Cargando..."
392
+ }
393
+
394
+ } catch (error) { }
395
+
396
+ if(this.merchantData) {
397
+
398
+ if("openpay_keys" in this.merchantData) {
399
+
400
+ const { openpay_keys, reference, business } = this.merchantData
401
+
402
+ const total = Number(this.cartTotal)
403
+
404
+ let cardTokensSkyflowTonder: any = null;
405
+
406
+ if(this.radioChecked === "new") {
407
+
408
+ if(this.collectContainer && "container" in this.collectContainer && "collect" in this.collectContainer.container) {
409
+ try {
410
+ const collectResponseSkyflowTonder: any = await this.collectContainer?.container.collect();
411
+ cardTokensSkyflowTonder = await collectResponseSkyflowTonder["records"][0]["fields"];
412
+ } catch (error) {
413
+ showError("Por favor, verifica todos los campos de tu tarjeta", this.collectorIds.msgError, this.collectorIds.tonderPayButton)
414
+ throw error;
415
+ }
416
+ } else {
417
+ showError("Por favor, verifica todos los campos de tu tarjeta", this.collectorIds.msgError, this.collectorIds.tonderPayButton)
418
+ }
419
+
420
+ } else {
421
+
422
+ cardTokensSkyflowTonder = {
423
+ skyflow_id: this.radioChecked
424
+ }
425
+
426
+ }
427
+
428
+ let deviceSessionIdTonder: any;
429
+
430
+ if (openpay_keys.merchant_id && openpay_keys.public_key) {
431
+ deviceSessionIdTonder = await this.liteCheckout.getOpenpayDeviceSessionID(
432
+ openpay_keys.merchant_id,
433
+ openpay_keys.public_key,
434
+ this.isOpenPaySandbox
435
+ );
436
+ }
437
+
438
+ if(this.email) {
439
+
440
+ const customerResponse : CustomerRegisterResponse | ErrorResponse = await this.getCustomer(this.email);
441
+
442
+ if("auth_token" in customerResponse) {
443
+
444
+ const { auth_token } = customerResponse;
445
+
446
+ const saveCard: HTMLElement | null = document.getElementById("save-checkout-card");
447
+
448
+ if(saveCard && "checked" in saveCard && saveCard.checked) {
449
+
450
+ await this.liteCheckout.registerCustomerCard(auth_token, { skyflow_id: cardTokensSkyflowTonder.skyflow_id });
451
+
452
+ this.cardsInjected = false;
453
+
454
+ const cards = await this.liteCheckout.getCustomerCards(auth_token);
455
+
456
+ if("cards" in cards) {
457
+
458
+ const cardsMapped: Card[] = cards.cards.map((card) => mapCards(card))
459
+
460
+ this.loadCardsList(cardsMapped)
461
+
462
+ }
463
+
464
+ showMessage("Tarjeta registrada con éxito", this.collectorIds.msgNotification);
465
+
466
+ }
467
+
468
+ const orderItems: CreateOrderRequest = {
469
+ business: this.apiKeyTonder,
470
+ client: auth_token,
471
+ billing_address_id: null,
472
+ shipping_address_id: null,
473
+ amount: total,
474
+ status: "A",
475
+ reference: reference,
476
+ is_oneclick: true,
477
+ items: this.cartItems,
478
+ };
479
+
480
+ const jsonResponseOrder = await this.liteCheckout.createOrder(
481
+ orderItems
482
+ );
483
+
484
+ // Create payment
485
+ const now = new Date();
486
+ const dateString = now.toISOString();
487
+
488
+ if("id" in jsonResponseOrder) {
489
+
490
+ const paymentItems: CreatePaymentRequest = {
491
+ business_pk: business.pk,
492
+ amount: total,
493
+ date: dateString,
494
+ order: jsonResponseOrder.id
495
+ };
496
+
497
+ const jsonResponsePayment = await this.liteCheckout.createPayment(
498
+ paymentItems
499
+ );
500
+
501
+ // Checkout router
502
+ const routerItems: StartCheckoutRequest = {
503
+ card: cardTokensSkyflowTonder,
504
+ name: cardTokensSkyflowTonder.cardholder_name,
505
+ last_name: "",
506
+ email_client: this.email,
507
+ phone_number: this.phone,
508
+ return_url: this.returnUrl,
509
+ id_product: "no_id",
510
+ quantity_product: 1,
511
+ id_ship: "0",
512
+ instance_id_ship: "0",
513
+ amount: total,
514
+ title_ship: "shipping",
515
+ description: "transaction",
516
+ device_session_id: deviceSessionIdTonder ? deviceSessionIdTonder : null,
517
+ token_id: "",
518
+ order_id: ("id" in jsonResponseOrder) && jsonResponseOrder.id,
519
+ business_id: business.pk,
520
+ payment_id: ("pk" in jsonResponsePayment) && jsonResponsePayment.pk,
521
+ source: 'sdk',
522
+ };
523
+
524
+ const jsonResponseRouter = await this.liteCheckout.startCheckoutRouter(
525
+ routerItems
526
+ );
527
+ if (jsonResponseRouter) {
528
+ try {
529
+ const selector: any = document.querySelector(`#${this.collectorIds.tonderPayButton}`);
530
+ if(selector) {
531
+ selector.disabled = false;
532
+ }
533
+ } catch {}
534
+ return jsonResponseRouter;
535
+ } else {
536
+ showError("No se ha podido procesar el pago", this.collectorIds.msgError, this.collectorIds.tonderPayButton)
537
+ return false;
538
+ }
539
+ }
540
+ }
541
+ }
542
+ }
543
+ } else {
544
+ showError("No se han configurado los datos del proveedor de servicio", this.collectorIds.msgError, this.collectorIds.tonderPayButton)
545
+ }
546
+ } catch (error) {
547
+ console.log(error);
548
+ showError("Ha ocurrido un error", this.collectorIds.msgError, this.collectorIds.tonderPayButton)
549
+ throw error;
550
+ } finally {
551
+ this.fetchingPayment = false;
552
+ }
553
+ };
554
554
  }