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