Skip to content

Commit

Permalink
refactor: Improves project structure
Browse files Browse the repository at this point in the history
  • Loading branch information
luis-herasme committed May 4, 2024
1 parent 25f0e87 commit ec51990
Show file tree
Hide file tree
Showing 9 changed files with 663 additions and 431 deletions.
420 changes: 0 additions & 420 deletions src/api.ts

This file was deleted.

84 changes: 84 additions & 0 deletions src/azul-api/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { PostSchema, PostSchemaInput } from './schemas';
import AzulRequester, { Config } from './request';
import DataVault from './data-vault/data-vault';
import ProcessPayment from './process-payment/process-payment ';
import { ProcessPaymentResponse } from './process-payment/schemas';

class AzulAPI {
private requester: AzulRequester;

public valut: DataVault;
public payments: ProcessPayment;

constructor(config: Config) {
this.requester = new AzulRequester(config);
this.valut = new DataVault(this.requester);
this.payments = new ProcessPayment(this.requester);
}

/**
* ### Transacción para anular venta, post o hold
* Las transacciones de venta o post se pueden anular antes de los 20 minutos de haber
* recibido la respuesta de aprobación.
* Las transacciones de hold que no han sido posteadas no tienen límite de tiempo para
* anularse.
*/
async void(azulOrderId: string): Promise<ProcessPaymentResponse> {
return await this.requester.safeRequest({
url: this.requester.url + '?ProcessVoid',
body: {
azulOrderId
}
});
}

/**
* ### Transacción para hacer captura o posteo del Hold
* El método “Post” permite capturar un “Hold” realizado previamente para su liquidación.
* El monto del “Post” puede ser igual o menor al monto del “Hold”. En caso de que el
* monto del Post sea menor al Hold, se envía un mensaje de reverso para liberar los
* fondos retenidos a la tarjeta.
*/
async post(input: PostSchemaInput): Promise<ProcessPaymentResponse> {
return await this.requester.safeRequest({
url: this.requester.url + '?ProcessPost',
body: {
...PostSchema.parse(input)
}
});
}

/**
* Método VerifyPayment
* Este método permite verificar la respuesta enviada por el webservice de una
* transacción anterior (procesada por el método ProccesPayment), identificada por el
* campo CustomOrderId.
* Si existe más de una transacción con este identificador este método devolverá los
* valores de la última transacción (más reciente) de ellas.
*/
async verifyPayment(customOrderId: string): Promise<ProcessPaymentResponse> {
return await this.requester.safeRequest({
url: this.requester.url + '?VerifyPayment',
body: {
customOrderId
}
});
}

/**
* Este método permite extraer los detalles de una o varias transacciones
* vía Webservices, anteriormente procesadas de un rango de fechas
* previamente seleccionado.
*/
async search({ from, to }: { from: string; to: string }): Promise<ProcessPaymentResponse> {
return await this.requester.safeRequest({
url: this.requester.url + '?SearchPayments',
body: {
dateFrom: from,
dateTo: to
}
});
}
}

export default AzulAPI;
46 changes: 46 additions & 0 deletions src/azul-api/data-vault/data-vault.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import AzulRequester from '../request';
import { Create, CreateInput, Delete, DeleteInput, DataVaultResponse } from './shemas';

enum DataVaultTransaction {
CREATE = 'CREATE',
DELETE = 'DELETE'
}

class DataVault {
private readonly requester: AzulRequester;

constructor(requester: AzulRequester) {
this.requester = requester;
}

/**
* ### Create: Creación de Token con Bóveda de Datos (DataVault)
* Con esta transacción se solicita un token para ser utilizado en sustitución de la tarjeta,
* sin necesidad de realizar una venta.
*/
async create(input: CreateInput): Promise<DataVaultResponse> {
return await this.requester.safeRequest({
url: this.requester.url + '?ProcessDatavault',
body: {
...Create.parse(input),
trxType: DataVaultTransaction.CREATE
}
});
}

/**
* ### Delete: Eliminación de Token de Bóveda de Datos (DataVault)
* Con esta transacción se solicita la eliminación de un token de la Bóveda de Datos.
*/
async delete(input: DeleteInput): Promise<DataVaultResponse> {
return await this.requester.safeRequest({
url: this.requester.url + '?ProcessDatavault',
body: {
...Delete.parse(input),
trxType: DataVaultTransaction.DELETE
}
});
}
}

export default DataVault;
70 changes: 70 additions & 0 deletions src/azul-api/data-vault/shemas.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { z } from 'zod';
import { CVC, cardNumber, expiration } from '../schemas';

export const Create = z.object({
/**
* Número de tarjeta a la cual se le ha de cargar la
* transacción.
* La longitud del campo se determina por la tarjeta,
* no se debe rellenar con ceros (0), espacios, ni
* caracteres especiales
*/
cardNumber,
/**
* Fecha expiración/vencimiento de la tarjeta
* Formato YYYYMM Ej.: 201502
*/
expiration,
/**
* Código de seguridad de la tarjeta (CVV2 o CVC).
*/
CVC
});

export const Delete = z.object({
/**
* Token generado por Azul.
*/
dataVaultToken: z.string()
});

export type DataVaultResponse = Partial<{
/**
* Marca de la tarjeta.
*/
Brand: string;
/**
* Número de tarjeta enmascarada (ej. XXXXXX…XXXX).
*/
CardNumber: string;
/**
* Token generado por SDP.
*/
DataVaultToken: string;
/**
* Descripción del error.
* Valor sólo presente si la transacción produjo un error. En caso
* de no presentar error ese campo viaja en blanco
*/
ErrorDescription: string;
/**
* Fecha expiración del token. Formato YYYYMM
*/
Expiration: string;
/**
* Indica si el Token fue creado con CVV.
*/
HasCVV: boolean;
/**
* Código ISO-8583 recibido de respuesta.
* Cuando la transacción es exitosa se recibe el valor “00”
*/
ISOCode: string;
/**
* Mensaje de respuesta
*/
ReponseMessage: string;
}>;

export type CreateInput = z.input<typeof Create>;
export type DeleteInput = z.input<typeof Delete>;
89 changes: 89 additions & 0 deletions src/azul-api/process-payment/process-payment .ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import AzulRequester from '../request';
import { ProcessPaymentResponse, ProcessPaymentSchemaInput, ProcessPaymentSchema } from './schemas';

enum ProcessPaymentTransaction {
SALE = 'Sale',
HOLD = 'Hold',
REFUND = 'Refund'
}

class ProcessPayment {
private readonly requester: AzulRequester;

constructor(requester: AzulRequester) {
this.requester = requester;
}

/**
* ### SALE: Transacción de venta
* Esta es la transacción principal utilizada para someter una autorización de una tarjeta
* por la venta de un bien o servicio.
* Las ventas realizadas con la transacción “Sale” son capturadas automáticamente para
* su liquidación, por lo que sólo pueden ser anuladas con una transacción de “Void” en
* un lapso de no más de 20 minutos luego de recibir respuesta de aprobación.
*
* Luego de transcurridos estos 20 minutos, la transacción será liquidada y se debe realizar
* una transacción de “Refund” o devolución para devolver los fondos a la tarjeta.
*/
async sale(input: ProcessPaymentSchemaInput): Promise<ProcessPaymentResponse> {
return await this.requester.safeRequest({
body: {
...ProcessPaymentSchema.parse(input),
trxType: ProcessPaymentTransaction.SALE
}
});
}

/**
* ### Refund: Transacción Devolución
* La devolución o “Refund” permite reembolsarle los fondos a una tarjeta luego de haberse
* liquidado la transacción.
*
* Para poder realizar una devolución se debe haber procesado exitosamente una
* transacción de Venta o Post, y se deben utilizar los datos de la transacción original
* para enviar la devolución.
* 1. El monto a devolver puede ser el mismo o menor.
* 2. Se permite hacer una devolución, múltiples devoluciones o devoluciones
*
* parciales para cada transacción realizada.
* El límite de tiempo para procesar una devolución es de 6 meses transcurridos
* después de la transacción original.
*/
async refund(input: ProcessPaymentSchemaInput): Promise<ProcessPaymentResponse> {
return await this.requester.safeRequest({
body: {
...ProcessPaymentSchema.parse(input),
trxType: ProcessPaymentTransaction.REFUND
}
});
}

/**
* ### Hold: Transacción para retención o reserva de fondos en la tarjeta
* Se puede separar la autorización del posteo o captura en dos mensajes distintos:
* 1. Hold: pre-autorización y reserva de los fondos en la tarjeta del cliente.
* 2. Post: se hace la captura o el “posteo” de la transacción.
*
* Al utilizar el Hold y Post se deben considerar los siguientes puntos:
* 1. Para evitar que el banco emisor elimine la pre-autorización, el Post debe ser
* realizado antes de 7 días de haber hecho el Hold.
* 2. Luego de realizado el Hold, el comercio no va a recibir la liquidación de los
* fondos hasta que someta el Post.
* 3. El Post solamente se puede hacer una vez por cada Hold realizado. Si se
* desea dividir el posteo en múltiples capturas, se debe usar la
* funcionalidad de Captura Múltiple o Split Shipment.
* 4. El Post puede ser igual, menor o mayor al monto original. El posteo por un
* monto mayor no debe sobrepasar el 15% del monto original.
* 5. El Void libera o cancela los fondos retenidos.
*/
async hold(input: ProcessPaymentSchemaInput): Promise<ProcessPaymentResponse> {
return await this.requester.safeRequest({
body: {
...ProcessPaymentSchema.parse(input),
trxType: ProcessPaymentTransaction.HOLD
}
});
}
}

export default ProcessPayment;
Loading

0 comments on commit ec51990

Please sign in to comment.