ipagos-js-sdk 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +150 -0
- package/dist/client.d.ts +531 -0
- package/dist/client.js +698 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +18 -0
- package/dist/types.d.ts +31 -0
- package/dist/types.js +2 -0
- package/package.json +24 -0
package/dist/client.js
ADDED
|
@@ -0,0 +1,698 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.iPagosCSClient = void 0;
|
|
7
|
+
const axios_1 = __importDefault(require("axios"));
|
|
8
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
9
|
+
class iPagosCSClient {
|
|
10
|
+
config;
|
|
11
|
+
client;
|
|
12
|
+
constructor(config) {
|
|
13
|
+
this.config = config;
|
|
14
|
+
let baseURL = config.environment === 'sandbox'
|
|
15
|
+
? 'https://apitest.cybersource.com'
|
|
16
|
+
: 'https://api.cybersource.com';
|
|
17
|
+
this.client = axios_1.default.create({
|
|
18
|
+
baseURL,
|
|
19
|
+
headers: {
|
|
20
|
+
'Content-Type': 'application/json',
|
|
21
|
+
'v-c-merchant-id': config.merchantId
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
handleError(err) {
|
|
26
|
+
const error = err;
|
|
27
|
+
if (error.response?.data) {
|
|
28
|
+
return {
|
|
29
|
+
success: false,
|
|
30
|
+
status: error.response.status,
|
|
31
|
+
error: error.response.data
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
success: false,
|
|
36
|
+
error: { message: error.message }
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Firma CyberSource
|
|
41
|
+
*/
|
|
42
|
+
sign(method, path, body) {
|
|
43
|
+
const date = new Date().toUTCString();
|
|
44
|
+
let digest;
|
|
45
|
+
if (body) {
|
|
46
|
+
const hash = crypto_1.default
|
|
47
|
+
.createHash('sha256')
|
|
48
|
+
.update(JSON.stringify(body))
|
|
49
|
+
.digest('base64');
|
|
50
|
+
digest = `SHA-256=${hash}`;
|
|
51
|
+
}
|
|
52
|
+
const host = new URL(this.client.defaults.baseURL).host;
|
|
53
|
+
const signatureHeaders = [
|
|
54
|
+
`(request-target): ${method.toLowerCase()} ${path}`,
|
|
55
|
+
`host: ${host}`,
|
|
56
|
+
`date: ${date}`
|
|
57
|
+
];
|
|
58
|
+
if (digest) {
|
|
59
|
+
signatureHeaders.push(`digest: ${digest}`);
|
|
60
|
+
}
|
|
61
|
+
signatureHeaders.push(`v-c-merchant-id: ${this.config.merchantId}`);
|
|
62
|
+
const signatureString = signatureHeaders.join('\n');
|
|
63
|
+
const signature = crypto_1.default
|
|
64
|
+
.createHmac('sha256', Buffer.from(this.config.secretKey, 'base64'))
|
|
65
|
+
.update(signatureString)
|
|
66
|
+
.digest('base64');
|
|
67
|
+
return {
|
|
68
|
+
date,
|
|
69
|
+
digest,
|
|
70
|
+
signature: `keyid="${this.config.keyId}", algorithm="HmacSHA256", headers="(request-target) host date${digest ? ' digest' : ''} v-c-merchant-id", signature="${signature}"`
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* POST CyberSource
|
|
75
|
+
*/
|
|
76
|
+
async post(path, body) {
|
|
77
|
+
try {
|
|
78
|
+
const signed = this.sign('POST', path, body);
|
|
79
|
+
const headers = {
|
|
80
|
+
Date: signed.date,
|
|
81
|
+
Signature: signed.signature
|
|
82
|
+
};
|
|
83
|
+
if (signed.digest) {
|
|
84
|
+
headers.Digest = signed.digest;
|
|
85
|
+
}
|
|
86
|
+
const response = await this.client.post(path, body, { headers });
|
|
87
|
+
return {
|
|
88
|
+
success: true,
|
|
89
|
+
data: response.data
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
return this.handleError(err);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* GET CyberSource
|
|
98
|
+
*/
|
|
99
|
+
async get(path) {
|
|
100
|
+
try {
|
|
101
|
+
const signed = this.sign('GET', path);
|
|
102
|
+
const headers = {
|
|
103
|
+
Date: signed.date,
|
|
104
|
+
Signature: signed.signature
|
|
105
|
+
};
|
|
106
|
+
const response = await this.client.get(path, { headers });
|
|
107
|
+
return {
|
|
108
|
+
success: true,
|
|
109
|
+
data: response.data
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
catch (err) {
|
|
113
|
+
return this.handleError(err);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* getPaymentDetails
|
|
118
|
+
* -------------------------------------------------------
|
|
119
|
+
* Obtiene los detalles del pago asociados a un
|
|
120
|
+
* transientToken generado por Flex (Microform).
|
|
121
|
+
*
|
|
122
|
+
* ⚠️ Este método NO realiza ningún cobro.
|
|
123
|
+
* Solo recupera información contenida en el token
|
|
124
|
+
* de transición.
|
|
125
|
+
*
|
|
126
|
+
* -------------------------------------------------------
|
|
127
|
+
* ¿Para qué sirve?
|
|
128
|
+
*
|
|
129
|
+
* - Validar información antes de procesar el pago.
|
|
130
|
+
* - Obtener últimos 4 dígitos de tarjeta.
|
|
131
|
+
* - Verificar marca (VISA, MASTERCARD, etc.).
|
|
132
|
+
* - Aplicar reglas antifraude previas al cobro.
|
|
133
|
+
* - Mostrar resumen de pago al usuario.
|
|
134
|
+
*
|
|
135
|
+
* -------------------------------------------------------
|
|
136
|
+
* FLUJO TÍPICO:
|
|
137
|
+
*
|
|
138
|
+
* 1️⃣ Backend genera sesión (createSession).
|
|
139
|
+
* 2️⃣ Frontend usa Flex para capturar tarjeta.
|
|
140
|
+
* 3️⃣ Flex genera transientToken.
|
|
141
|
+
* 4️⃣ Backend recibe transientToken.
|
|
142
|
+
* 5️⃣ Se llama getPaymentDetails() para inspección.
|
|
143
|
+
* 6️⃣ Luego se decide si ejecutar createPaymentToken().
|
|
144
|
+
*
|
|
145
|
+
* -------------------------------------------------------
|
|
146
|
+
* @param transientToken
|
|
147
|
+
* Token de transición (JWT) generado por Flex.
|
|
148
|
+
*
|
|
149
|
+
* ⚠️ Es de un solo uso.
|
|
150
|
+
* ⚠️ Tiene vigencia limitada.
|
|
151
|
+
* ⚠️ No representa un pago aún.
|
|
152
|
+
*
|
|
153
|
+
* -------------------------------------------------------
|
|
154
|
+
* @returns Promise<iPagosCSClientResponse<T>>
|
|
155
|
+
*
|
|
156
|
+
* Respuesta exitosa:
|
|
157
|
+
*
|
|
158
|
+
* {
|
|
159
|
+
* success: true,
|
|
160
|
+
* data: {
|
|
161
|
+
* paymentInformation: {
|
|
162
|
+
* card: {
|
|
163
|
+
* type: string,
|
|
164
|
+
* expirationMonth: string,
|
|
165
|
+
* expirationYear: string,
|
|
166
|
+
* bin: string,
|
|
167
|
+
* last4: string
|
|
168
|
+
* }
|
|
169
|
+
* }
|
|
170
|
+
* }
|
|
171
|
+
* }
|
|
172
|
+
*
|
|
173
|
+
* Respuesta de error:
|
|
174
|
+
*
|
|
175
|
+
* {
|
|
176
|
+
* success: false,
|
|
177
|
+
* status?: number,
|
|
178
|
+
* error: any
|
|
179
|
+
* }
|
|
180
|
+
*
|
|
181
|
+
* -------------------------------------------------------
|
|
182
|
+
* 🔐 SEGURIDAD
|
|
183
|
+
*
|
|
184
|
+
* Este método debe ejecutarse únicamente en backend.
|
|
185
|
+
*
|
|
186
|
+
* Aunque no realiza cobro, el transientToken es sensible
|
|
187
|
+
* y no debe exponerse innecesariamente.
|
|
188
|
+
*
|
|
189
|
+
* -------------------------------------------------------
|
|
190
|
+
* 🧠 Buenas Prácticas
|
|
191
|
+
*
|
|
192
|
+
* - No almacenar transientToken en base de datos.
|
|
193
|
+
* - Usarlo inmediatamente y descartarlo.
|
|
194
|
+
* - Validar coherencia antes de ejecutar el cobro.
|
|
195
|
+
*
|
|
196
|
+
* -------------------------------------------------------
|
|
197
|
+
*/
|
|
198
|
+
async getPaymentDetails(transientToken) {
|
|
199
|
+
try {
|
|
200
|
+
return await this.get(`/up/v1/payment-details/${transientToken}`);
|
|
201
|
+
}
|
|
202
|
+
catch (err) {
|
|
203
|
+
return this.handleError(err);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* refundsPayment
|
|
208
|
+
* -------------------------------------------------------
|
|
209
|
+
* Realiza un reembolso (refund) utilizando el paymentId
|
|
210
|
+
* de una transacción previamente capturada.
|
|
211
|
+
*
|
|
212
|
+
* ⚠️ Solo puede ejecutarse sobre pagos ya autorizados
|
|
213
|
+
* y capturados.
|
|
214
|
+
*
|
|
215
|
+
* -------------------------------------------------------
|
|
216
|
+
* ¿Qué hace este método?
|
|
217
|
+
*
|
|
218
|
+
* - Genera una transacción de tipo REFUND.
|
|
219
|
+
* - Devuelve el monto especificado al método de pago original.
|
|
220
|
+
* - Se asocia directamente al paymentId original.
|
|
221
|
+
*
|
|
222
|
+
* -------------------------------------------------------
|
|
223
|
+
* CONSIDERACIONES IMPORTANTES
|
|
224
|
+
*
|
|
225
|
+
* - amountDetails.totalAmount debe coincidir con:
|
|
226
|
+
* • El monto total original (para refund completo), o
|
|
227
|
+
* • Un monto menor (para refund parcial).
|
|
228
|
+
*
|
|
229
|
+
* - currency debe ser la misma moneda del cobro original.
|
|
230
|
+
*
|
|
231
|
+
* ⚠️ No se puede reembolsar más del monto capturado.
|
|
232
|
+
* ⚠️ No se puede cambiar la moneda.
|
|
233
|
+
*
|
|
234
|
+
* -------------------------------------------------------
|
|
235
|
+
* @param paymentId
|
|
236
|
+
* Identificador del pago original generado por CyberSource.
|
|
237
|
+
*
|
|
238
|
+
* Ejemplo:
|
|
239
|
+
* "7123456789012345678901"
|
|
240
|
+
*
|
|
241
|
+
* Este ID se obtiene al ejecutar createPaymentToken()
|
|
242
|
+
* o createCharge().
|
|
243
|
+
*
|
|
244
|
+
* -------------------------------------------------------
|
|
245
|
+
* @param amountDetails
|
|
246
|
+
* Información del monto a reembolsar.
|
|
247
|
+
*
|
|
248
|
+
* - totalAmount: string con 2 decimales.
|
|
249
|
+
* Ejemplo: "100.00"
|
|
250
|
+
*
|
|
251
|
+
* - currency: Código ISO 4217 en mayúsculas.
|
|
252
|
+
* Ejemplo: "MXN", "USD"
|
|
253
|
+
*
|
|
254
|
+
* ⚠️ Debe coincidir con la moneda del pago original.
|
|
255
|
+
*
|
|
256
|
+
* -------------------------------------------------------
|
|
257
|
+
* @returns Promise<iPagosCSClientResponse<T>>
|
|
258
|
+
*
|
|
259
|
+
* Respuesta exitosa:
|
|
260
|
+
*
|
|
261
|
+
* {
|
|
262
|
+
* success: true,
|
|
263
|
+
* data: {
|
|
264
|
+
* id: string,
|
|
265
|
+
* status: string,
|
|
266
|
+
* ...
|
|
267
|
+
* }
|
|
268
|
+
* }
|
|
269
|
+
*
|
|
270
|
+
* Respuesta de error:
|
|
271
|
+
*
|
|
272
|
+
* {
|
|
273
|
+
* success: false,
|
|
274
|
+
* status?: number,
|
|
275
|
+
* error: any
|
|
276
|
+
* }
|
|
277
|
+
*
|
|
278
|
+
* -------------------------------------------------------
|
|
279
|
+
* 🧠 CASOS DE USO COMUNES
|
|
280
|
+
*
|
|
281
|
+
* - Cancelación de pedido.
|
|
282
|
+
* - Devolución parcial.
|
|
283
|
+
* - Ajuste administrativo.
|
|
284
|
+
* - Reversión por error operativo.
|
|
285
|
+
*
|
|
286
|
+
* -------------------------------------------------------
|
|
287
|
+
* 🔐 SEGURIDAD Y CONTABILIDAD
|
|
288
|
+
*
|
|
289
|
+
* - Registrar internamente cada refund.
|
|
290
|
+
* - Asociar refund con orden interna.
|
|
291
|
+
* - No ejecutar reembolsos duplicados.
|
|
292
|
+
*
|
|
293
|
+
* Recomendado:
|
|
294
|
+
* Implementar control interno de idempotencia.
|
|
295
|
+
*
|
|
296
|
+
* -------------------------------------------------------
|
|
297
|
+
*/
|
|
298
|
+
async refundsPayment({ paymentId, amountDetails }) {
|
|
299
|
+
try {
|
|
300
|
+
const payload = {
|
|
301
|
+
clientReferenceInformation: {
|
|
302
|
+
code: `refund_${paymentId}_${Date.now()}`
|
|
303
|
+
},
|
|
304
|
+
orderInformation: {
|
|
305
|
+
amountDetails
|
|
306
|
+
}
|
|
307
|
+
};
|
|
308
|
+
return await this.post(`/pts/v2/payments/${paymentId}/refunds`, payload);
|
|
309
|
+
}
|
|
310
|
+
catch (err) {
|
|
311
|
+
return this.handleError(err);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* createPaymentToken
|
|
316
|
+
* -------------------------------------------------------
|
|
317
|
+
* Procesa un pago utilizando un transientToken generado
|
|
318
|
+
* desde el SDK de Flex (Microform).
|
|
319
|
+
*
|
|
320
|
+
* Este método permite:
|
|
321
|
+
*
|
|
322
|
+
* 1️⃣ Realizar únicamente el cobro (sin tokenización).
|
|
323
|
+
* 2️⃣ Realizar cobro y crear token permanente.
|
|
324
|
+
* 3️⃣ Solo tokenizar sin capturar fondos (capture = false).
|
|
325
|
+
*
|
|
326
|
+
* 🔹 COMPORTAMIENTO SEGÚN CONFIGURACIÓN:
|
|
327
|
+
*
|
|
328
|
+
* • Cobro sin tokenizar:
|
|
329
|
+
* actionList = []
|
|
330
|
+
* actionTokenTypes = []
|
|
331
|
+
*
|
|
332
|
+
* • Cobro + tokenización (por defecto):
|
|
333
|
+
* actionList = ["TOKEN_CREATE"]
|
|
334
|
+
* actionTokenTypes = ["customer", "paymentInstrument"]
|
|
335
|
+
*
|
|
336
|
+
* • Solo tokenización (sin captura):
|
|
337
|
+
* capture = false
|
|
338
|
+
*
|
|
339
|
+
* -------------------------------------------------------
|
|
340
|
+
* @param transientToken
|
|
341
|
+
* Token de transición (JWT) generado desde el SDK de Flex.
|
|
342
|
+
* Este token representa la tarjeta del cliente de forma segura.
|
|
343
|
+
*
|
|
344
|
+
* ⚠️ Es de un solo uso y expira rápidamente.
|
|
345
|
+
*
|
|
346
|
+
* @param internalId
|
|
347
|
+
* Identificador interno único del comercio.
|
|
348
|
+
* Se envía como clientReferenceInformation.code.
|
|
349
|
+
*
|
|
350
|
+
* ⚠️ Debe ser único por transacción (recomendado usar UUID).
|
|
351
|
+
*
|
|
352
|
+
* @param amountDetails
|
|
353
|
+
* Información del monto del pago.
|
|
354
|
+
*
|
|
355
|
+
* - totalAmount: Número con máximo 2 decimales.
|
|
356
|
+
* Ejemplo válido: 100.00
|
|
357
|
+
*
|
|
358
|
+
* - currency: Código de moneda ISO 4217 en mayúsculas.
|
|
359
|
+
* Ejemplo: "MXN", "USD"
|
|
360
|
+
*
|
|
361
|
+
* ⚠️ Currency debe ser de 3 caracteres.
|
|
362
|
+
*
|
|
363
|
+
* @param billTo
|
|
364
|
+
* Información de facturación del cliente.
|
|
365
|
+
* Debe cumplir con la estructura requerida por CyberSource.
|
|
366
|
+
*
|
|
367
|
+
* @param actionList (Opcional)
|
|
368
|
+
* Define acciones adicionales a ejecutar.
|
|
369
|
+
*
|
|
370
|
+
* - ["TOKEN_CREATE"] → Crea token permanente.
|
|
371
|
+
* - [] → No crea token.
|
|
372
|
+
*
|
|
373
|
+
* @param actionTokenTypes (Opcional)
|
|
374
|
+
* Define qué tipos de token se crearán.
|
|
375
|
+
*
|
|
376
|
+
* Valores comunes:
|
|
377
|
+
* - "customer"
|
|
378
|
+
* - "paymentInstrument"
|
|
379
|
+
*
|
|
380
|
+
* @param capture (Opcional)
|
|
381
|
+
* Define si la transacción se captura inmediatamente.
|
|
382
|
+
*
|
|
383
|
+
* - true → Autorización + captura inmediata.
|
|
384
|
+
* - false → Solo autorización.
|
|
385
|
+
*
|
|
386
|
+
* -------------------------------------------------------
|
|
387
|
+
* @returns Promise<iPagosCSClientResponse<T>>
|
|
388
|
+
*
|
|
389
|
+
* Respuesta estandarizada:
|
|
390
|
+
*
|
|
391
|
+
* {
|
|
392
|
+
* success: true,
|
|
393
|
+
* data: ...
|
|
394
|
+
* }
|
|
395
|
+
*
|
|
396
|
+
* o
|
|
397
|
+
*
|
|
398
|
+
* {
|
|
399
|
+
* success: false,
|
|
400
|
+
* status?: number,
|
|
401
|
+
* error: any
|
|
402
|
+
* }
|
|
403
|
+
*
|
|
404
|
+
* -------------------------------------------------------
|
|
405
|
+
* 🔐 SEGURIDAD
|
|
406
|
+
*
|
|
407
|
+
* Este método debe ejecutarse únicamente en backend.
|
|
408
|
+
* Nunca expongas secretKey en frontend.
|
|
409
|
+
*
|
|
410
|
+
* -------------------------------------------------------
|
|
411
|
+
*/
|
|
412
|
+
async createPaymentToken({ transientToken, internalId, amountDetails, billTo, actionTokenTypes = ["customer", "paymentInstrument"], actionList = ["TOKEN_CREATE"], capture = true, }) {
|
|
413
|
+
try {
|
|
414
|
+
const payload = {
|
|
415
|
+
clientReferenceInformation: {
|
|
416
|
+
code: internalId,
|
|
417
|
+
},
|
|
418
|
+
processingInformation: {
|
|
419
|
+
capture,
|
|
420
|
+
actionList,
|
|
421
|
+
actionTokenTypes
|
|
422
|
+
},
|
|
423
|
+
paymentInformation: {
|
|
424
|
+
tokenizedCard: {
|
|
425
|
+
transientTokenJwt: transientToken
|
|
426
|
+
}
|
|
427
|
+
},
|
|
428
|
+
tokenInformation: {
|
|
429
|
+
transientTokenJwt: transientToken,
|
|
430
|
+
},
|
|
431
|
+
orderInformation: {
|
|
432
|
+
amountDetails,
|
|
433
|
+
billTo,
|
|
434
|
+
},
|
|
435
|
+
};
|
|
436
|
+
return await this.post('/pts/v2/payments', payload);
|
|
437
|
+
}
|
|
438
|
+
catch (err) {
|
|
439
|
+
return this.handleError(err);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
/**
|
|
443
|
+
* createSession
|
|
444
|
+
* -------------------------------------------------------
|
|
445
|
+
* Genera un token de sesión (contexto) para inicializar
|
|
446
|
+
* el SDK de Flex (Microform).
|
|
447
|
+
*
|
|
448
|
+
* Esta sesión permite que el frontend:
|
|
449
|
+
*
|
|
450
|
+
* 1️⃣ Inicialice el formulario seguro de tarjeta.
|
|
451
|
+
* 2️⃣ Capture datos sensibles de tarjeta de forma segura.
|
|
452
|
+
* 3️⃣ Genere un transientToken (token de transición).
|
|
453
|
+
*
|
|
454
|
+
* 🔹 Flujo típico:
|
|
455
|
+
*
|
|
456
|
+
* Backend:
|
|
457
|
+
* → createSession()
|
|
458
|
+
*
|
|
459
|
+
* Frontend:
|
|
460
|
+
* → Inicializa Flex con el sessionToken
|
|
461
|
+
* → Captura datos de tarjeta
|
|
462
|
+
* → Genera transientToken
|
|
463
|
+
*
|
|
464
|
+
* Backend:
|
|
465
|
+
* → Usa transientToken para crear el pago
|
|
466
|
+
*
|
|
467
|
+
* -------------------------------------------------------
|
|
468
|
+
* @param targetOrigins
|
|
469
|
+
* Dominio autorizado para inicializar Flex.
|
|
470
|
+
*
|
|
471
|
+
* Ejemplo:
|
|
472
|
+
* "https://micomercio.com"
|
|
473
|
+
*
|
|
474
|
+
* ⚠️ Debe coincidir exactamente con el dominio donde
|
|
475
|
+
* se ejecutará el SDK de Flex.
|
|
476
|
+
*
|
|
477
|
+
* ⚠️ No usar comodines (*).
|
|
478
|
+
*
|
|
479
|
+
* -------------------------------------------------------
|
|
480
|
+
* @param allowedCardNetworks (Opcional)
|
|
481
|
+
* Define las marcas de tarjeta permitidas.
|
|
482
|
+
*
|
|
483
|
+
* Valores comunes:
|
|
484
|
+
* - "VISA"
|
|
485
|
+
* - "MASTERCARD"
|
|
486
|
+
* - "AMEX"
|
|
487
|
+
*
|
|
488
|
+
* Si no se especifica, por defecto:
|
|
489
|
+
* ["VISA", "MASTERCARD", "AMEX"]
|
|
490
|
+
*
|
|
491
|
+
* -------------------------------------------------------
|
|
492
|
+
* @param allowedPaymentTypes (Opcional)
|
|
493
|
+
* Define el tipo de método de pago permitido.
|
|
494
|
+
*
|
|
495
|
+
* Valor común:
|
|
496
|
+
* - "CARD"
|
|
497
|
+
*
|
|
498
|
+
* Si no se especifica, por defecto:
|
|
499
|
+
* ["CARD"]
|
|
500
|
+
*
|
|
501
|
+
* -------------------------------------------------------
|
|
502
|
+
* @returns Promise<iPagosCSClientResponse<T>>
|
|
503
|
+
*
|
|
504
|
+
* Respuesta exitosa:
|
|
505
|
+
*
|
|
506
|
+
* {
|
|
507
|
+
* success: true,
|
|
508
|
+
* data: {
|
|
509
|
+
* id: string,
|
|
510
|
+
* clientVersion: string,
|
|
511
|
+
* ...
|
|
512
|
+
* }
|
|
513
|
+
* }
|
|
514
|
+
*
|
|
515
|
+
* El ID retornado se usa en el frontend para
|
|
516
|
+
* inicializar Flex.
|
|
517
|
+
*
|
|
518
|
+
* -------------------------------------------------------
|
|
519
|
+
* 🔐 SEGURIDAD
|
|
520
|
+
*
|
|
521
|
+
* Este método debe ejecutarse únicamente en backend.
|
|
522
|
+
* Nunca expongas secretKey ni firmes requests desde frontend.
|
|
523
|
+
*
|
|
524
|
+
* El sessionToken tiene vigencia limitada.
|
|
525
|
+
*
|
|
526
|
+
* -------------------------------------------------------
|
|
527
|
+
* 🧠 Buenas Prácticas
|
|
528
|
+
*
|
|
529
|
+
* - Generar sesión por cada intento de pago.
|
|
530
|
+
* - No reutilizar sesiones antiguas.
|
|
531
|
+
* - Validar que targetOrigins coincida con tu dominio real.
|
|
532
|
+
*
|
|
533
|
+
* -------------------------------------------------------
|
|
534
|
+
*/
|
|
535
|
+
async createSession({ targetOrigins, allowedCardNetworks = [
|
|
536
|
+
"VISA",
|
|
537
|
+
"MASTERCARD",
|
|
538
|
+
"AMEX"
|
|
539
|
+
], allowedPaymentTypes = ["CARD"] }) {
|
|
540
|
+
try {
|
|
541
|
+
const payload = {
|
|
542
|
+
"clientVersion": "v2",
|
|
543
|
+
"targetOrigins": [
|
|
544
|
+
targetOrigins
|
|
545
|
+
],
|
|
546
|
+
allowedCardNetworks,
|
|
547
|
+
allowedPaymentTypes,
|
|
548
|
+
"transientTokenResponseOptions": {
|
|
549
|
+
"includeCardPrefix": false
|
|
550
|
+
}
|
|
551
|
+
};
|
|
552
|
+
return await this.post('/microform/v2/sessions', payload);
|
|
553
|
+
}
|
|
554
|
+
catch (err) {
|
|
555
|
+
return this.handleError(err);
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
/**
|
|
559
|
+
* createCharge
|
|
560
|
+
* -------------------------------------------------------
|
|
561
|
+
* Realiza un cobro utilizando un customer_id y
|
|
562
|
+
* paymentInstrument_id previamente generados mediante
|
|
563
|
+
* tokenización.
|
|
564
|
+
*
|
|
565
|
+
* Este método se utiliza cuando:
|
|
566
|
+
*
|
|
567
|
+
* 1️⃣ Ya se tokenizó una tarjeta previamente.
|
|
568
|
+
* 2️⃣ Se desea realizar cobros recurrentes.
|
|
569
|
+
* 3️⃣ Se ejecutan cargos automáticos (suscripciones).
|
|
570
|
+
* 4️⃣ Se realizan cobros manuales administrativos.
|
|
571
|
+
*
|
|
572
|
+
* 🔹 No requiere transientToken.
|
|
573
|
+
* 🔹 No requiere interacción del cliente.
|
|
574
|
+
*
|
|
575
|
+
* -------------------------------------------------------
|
|
576
|
+
* FLUJO TÍPICO:
|
|
577
|
+
*
|
|
578
|
+
* 1) Cliente ingresa tarjeta (Flex).
|
|
579
|
+
* 2) Se genera transientToken.
|
|
580
|
+
* 3) Se ejecuta createPaymentToken() con TOKEN_CREATE.
|
|
581
|
+
* 4) Se obtiene:
|
|
582
|
+
* - customer_id
|
|
583
|
+
* - paymentInstrument_id
|
|
584
|
+
* 5) En futuros cobros se usa createCharge().
|
|
585
|
+
*
|
|
586
|
+
* -------------------------------------------------------
|
|
587
|
+
* @param internalId
|
|
588
|
+
* Identificador único interno del comercio.
|
|
589
|
+
* Se envía como clientReferenceInformation.code.
|
|
590
|
+
*
|
|
591
|
+
* ⚠️ Debe ser único por transacción.
|
|
592
|
+
* Recomendado: UUID o ID de orden interno.
|
|
593
|
+
*
|
|
594
|
+
* -------------------------------------------------------
|
|
595
|
+
* @param amountDetails
|
|
596
|
+
* Información del monto del pago.
|
|
597
|
+
*
|
|
598
|
+
* - totalAmount: Número con máximo 2 decimales.
|
|
599
|
+
* Ejemplo válido: 499.99
|
|
600
|
+
*
|
|
601
|
+
* - currency: Código de moneda ISO 4217 en mayúsculas.
|
|
602
|
+
* Ejemplo: "MXN", "USD"
|
|
603
|
+
*
|
|
604
|
+
* ⚠️ Currency debe ser de 3 caracteres.
|
|
605
|
+
*
|
|
606
|
+
* -------------------------------------------------------
|
|
607
|
+
* @param customer_id
|
|
608
|
+
* Identificador del cliente generado al tokenizar.
|
|
609
|
+
*
|
|
610
|
+
* Representa al cliente almacenado en CyberSource.
|
|
611
|
+
*
|
|
612
|
+
* -------------------------------------------------------
|
|
613
|
+
* @param paymentInstrument_id
|
|
614
|
+
* Identificador del método de pago tokenizado.
|
|
615
|
+
*
|
|
616
|
+
* Representa la tarjeta tokenizada asociada al customer_id.
|
|
617
|
+
*
|
|
618
|
+
* -------------------------------------------------------
|
|
619
|
+
* @param capture (Opcional)
|
|
620
|
+
* Define si la transacción se captura inmediatamente.
|
|
621
|
+
*
|
|
622
|
+
* - true → Autorización + captura inmediata.
|
|
623
|
+
* - false → Solo autorización (capture posterior).
|
|
624
|
+
*
|
|
625
|
+
* Por defecto: true
|
|
626
|
+
*
|
|
627
|
+
* -------------------------------------------------------
|
|
628
|
+
* @returns Promise<iPagosCSClientResponse<T>>
|
|
629
|
+
*
|
|
630
|
+
* Respuesta exitosa:
|
|
631
|
+
*
|
|
632
|
+
* {
|
|
633
|
+
* success: true,
|
|
634
|
+
* data: {
|
|
635
|
+
* id: string,
|
|
636
|
+
* status: string,
|
|
637
|
+
* ...
|
|
638
|
+
* }
|
|
639
|
+
* }
|
|
640
|
+
*
|
|
641
|
+
* Respuesta de error:
|
|
642
|
+
*
|
|
643
|
+
* {
|
|
644
|
+
* success: false,
|
|
645
|
+
* status?: number,
|
|
646
|
+
* error: any
|
|
647
|
+
* }
|
|
648
|
+
*
|
|
649
|
+
* -------------------------------------------------------
|
|
650
|
+
* 🧠 CASOS DE USO COMUNES
|
|
651
|
+
*
|
|
652
|
+
* - Suscripciones mensuales
|
|
653
|
+
* - Membresías
|
|
654
|
+
* - Financiamiento en parcialidades
|
|
655
|
+
* - Renovaciones automáticas
|
|
656
|
+
* - Reintentos de cobro
|
|
657
|
+
*
|
|
658
|
+
* -------------------------------------------------------
|
|
659
|
+
* 🔐 SEGURIDAD
|
|
660
|
+
*
|
|
661
|
+
* Este método debe ejecutarse únicamente en backend.
|
|
662
|
+
*
|
|
663
|
+
* No expone datos sensibles de tarjeta.
|
|
664
|
+
* Utiliza únicamente identificadores tokenizados.
|
|
665
|
+
*
|
|
666
|
+
* Ideal para arquitecturas PCI SAQ-A.
|
|
667
|
+
*
|
|
668
|
+
* -------------------------------------------------------
|
|
669
|
+
*/
|
|
670
|
+
async createCharge({ internalId, amountDetails, customer_id, paymentInstrument_id, capture = true, }) {
|
|
671
|
+
try {
|
|
672
|
+
const payload = {
|
|
673
|
+
clientReferenceInformation: {
|
|
674
|
+
code: internalId,
|
|
675
|
+
},
|
|
676
|
+
processingInformation: {
|
|
677
|
+
capture,
|
|
678
|
+
},
|
|
679
|
+
paymentInformation: {
|
|
680
|
+
customer: {
|
|
681
|
+
id: customer_id,
|
|
682
|
+
},
|
|
683
|
+
paymentInstrument: {
|
|
684
|
+
id: paymentInstrument_id,
|
|
685
|
+
},
|
|
686
|
+
},
|
|
687
|
+
orderInformation: {
|
|
688
|
+
amountDetails
|
|
689
|
+
},
|
|
690
|
+
};
|
|
691
|
+
return await this.post('/pts/v2/payments', payload);
|
|
692
|
+
}
|
|
693
|
+
catch (err) {
|
|
694
|
+
return this.handleError(err);
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
exports.iPagosCSClient = iPagosCSClient;
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./client"), exports);
|
|
18
|
+
__exportStar(require("./types"), exports);
|