npm package: @paroz/epagos-echeckout
Description: Wrapper para integración con ePagos e-Checkout
Author: Paroz Labs
Latest version: 0.0.2

# @paroz/epagos-echeckout

Wrapper para integración con ePagos e-Checkout

## Instalación

```bash
npm install @paroz/epagos-echeckout
```

## Uso Básico

```typescript
import { createEpagosClient } from '@paroz/epagos-echeckout';

const client = createEpagosClient({
  userId: 'your-user-id',
  organismId: 'your-organism-id',
  password: 'your-password',
  hash: 'your-hash',
  environment: 'sandbox', // o 'production'
  webhookSecret: 'your-webhook-secret' // opcional
});

// Iniciar un pago
const paymentData = {
  numero_operacion: 'ORD-123',
  monto_operacion: 1500.00,
  detalle_operacion: 'Pago de servicios',
  ok_url: 'https://tuapp.com/pagos/ok',
  error_url: 'https://tuapp.com/pagos/error',
  convenio: 'tu-convenio'
};


```

## 🆕 HTML Auto-Submit

La librería soporta **HTML auto-submit** para redirigir a epagos:

```typescript
const result = await client.initiatePaymentHtml(paymentData);

if (result.kind === 'html') {
  // Enviar el HTML directamente al cliente
  res.set('Content-Type', result.contentType);
  res.send(result.body);
}
```

## 📋 Detalle de Operación

### El detalle de operación debe ser un JSON url-encoded. Para eso, el cliente tiene tres maneras de enviarlo según su caso:

#### Caso 1: Detalle simple
```typescript
const paymentData = {
  numero_operacion: 'ORD-001',
  monto_operacion: 100,
  detalle_operacion: 'Pago simple',
  // ... otros campos
};

const result = await client.initiatePaymentHtml(paymentData);
// Genera: [{"id_item":0,"desc_item":"Pago simple","monto_item":100,"cantidad_item":1}]
```

#### Caso 2: Pago con Detalle Estructurado
```typescript
import { DetalleItem } from '@paroz/epagos-echeckout';

const detalleItems: DetalleItem[] = [
  {
    id_item: 1,
    desc_item: 'Servicio de Consultoría',
    monto_item: 100,
    cantidad_item: 1
  },
  {
    id_item: 2,
    desc_item: 'Licencia de Software',
    monto_item: 25,
    cantidad_item: 2
  }
];

const result = await client.initiatePaymentHtml(paymentData, detalleItems);
// Genera: [{"id_item":1,"desc_item":"Servicio de Consultoría","monto_item":100,"cantidad_item":1},{"id_item":2,"desc_item":"Licencia de Software","monto_item":25,"cantidad_item":2}]
```

#### Caso 3: Sin Detalle
```typescript
const paymentData = {
  numero_operacion: 'ORD-003',
  monto_operacion: 100,
  // sin detalle_operacion
  // ... otros campos
};

const result = await client.initiatePaymentHtml(paymentData);
// No incluye el campo detalle_operacion
```

## 🔧 Utilidades de Detalle

```typescript
// Codificar detalle manualmente
const detalleCodificado = client.encodeDetalleOperacion(detalleItems);
const detalleBase64 = client.encodeDetalleOperacion(detalleItems, 'base64');

// Validar suma de items
const esValido = client.validateDetalleOperacion(detalleItems, montoTotal);
```

## API

### EpagosClient

#### `getToken()`
Obtiene un token de autenticación válido. No es necesario llamarlo antes de initaitie `initiatePaymentHtml(paymentData, detalleItems?)` ya que esa misma llamada se hace internamente. Sirve solamente en el caso de que el cliente necesite el Token por cualquier otro motivo.

#### `encodeDetalleOperacion(items, mode?)`
Codifica el detalle de operación como JSON para incluirlo en los params que se envían al initiatePaymentHtml.
- **items**: Array de DetalleItem
- **mode**: 'urlencode' (default) o 'base64'

#### `validateDetalleOperacion(items, montoTotal)`
Valida que la suma de los items coincida con el monto total.

#### `initiatePaymentHtml(paymentData, detalleItems?)`
Inicia un pago y retorna HTML auto-submit para ePagos.
- **paymentData**: Datos básicos del pago
- **detalleItems**: Items detallados (opcional)

#### `parseReturn(payload)`
Procesa la respuesta de retorno de ePagos.
####¿Para qué sirve?

**Filtrado:** Solo extrae los campos que necesitas
**Tipado:** Te da autocompletado y validación de tipos
**Estandarización:** Garantiza que siempre tengas los mismos campos
**Ignorar ruido:** Filtra campos extra que ePagos puede enviar

#### `handleWebhook(payload, secret?)`
Valida el secreto del webhook y devuelve el payload procesado.
- **payload**: Datos del webhook de ePagos
- **secret**: Secreto para validar (opcional)
- **Retorna**: Payload validado o lanza excepción si el secreto es inválido

## 🔔 Webhooks

### Configuración en ePagos

Para recibir notificaciones de ePagos, configura en tu panel:

```
URL de Webhook: https://tuapp.com/api/webhooks/epagos
Método: POST
Headers: X-Webhook-Secret: tu-secreto-webhook
```

### Implementación del Webhook

```typescript
// En tu controlador (NestJS, Express, etc.)
@Post('epagos')
async handleWebhook(
  @Body() webhookData: WebhookPayloadDto,
  @Headers('x-webhook-secret') secret?: string
) {
  try {
    // 1. Validar con la librería
    const result = client.handleWebhook(webhookData, secret);
    
    // 2. Procesar según el tipo
    if (result.tipo === 'P') {
      // Procesar pago
      await this.procesarPago(result);
    } else if (result.tipo === 'D') {
      // Procesar devolución
      await this.procesarDevolucion(result);
    }
    
    return { status: 'ok' };
  } catch (error) {
    if (error.message.includes('Invalid webhook secret')) {
      throw new UnauthorizedException('Secreto inválido');
    }
    throw error;
  }
}
```

### Formato del Webhook

ePagos envía webhooks con este formato:

```typescript
interface WebhookPayload {
  tipo: 'P' | 'D';              // P = Pago, D = Devolución
  id_transaccion: string;        // ID único de la transacción
  id_organismo: string;          // Tu ID de organismo
  convenio: string;              // Convenio usado
  numero_operacion: string;      // Tu número de operación
  fecha_pago: string;            // Fecha del pago (YYYY-MM-DD)
  monto_pagado: number;          // Monto pagado
  id_resp: string;               // Código de respuesta
  fp?: {                         // Forma de pago (opcional)
    nombre_fp: string;
    importe_fp: number;
  };
}
```

### Códigos de Respuesta

```typescript
const CODIGOS_RESPUESTA = {
  '02001': 'Pago acreditado',
  '02002': 'Pago rechazado', 
  '02003': 'Pago pendiente',
  '02004': 'Pago cancelado',
  '02005': 'Error en el pago'
};
```

### Flujo Completo

```
1. Usuario inicia pago → HTML auto-submit
2. Usuario paga en ePagos → ePagos procesa
3. ePagos envía webhook → Tu aplicación recibe notificación
4. Tu aplicación procesa → Actualiza estado en tu BD
5. Usuario regresa → Tu aplicación muestra resultado
```

## Tipos

```typescript
interface DetalleItem {
  id_item: number;
  desc_item: string;
  monto_item: number;
  cantidad_item: number;
}

interface PaymentData {
  numero_operacion: string;
  monto_operacion: number;
  detalle_operacion?: string;
  ok_url: string;
  error_url: string;
  convenio: string;
  detalle_operacion_visible?: 0 | 1;
}

interface CheckoutResponse {
  kind: 'html' | 'error';
  contentType?: string;
  body?: string;
  code?: string;
  message?: string;
  details?: unknown;
}
```

## 🧪 Cliente de Prueba

Este proyecto incluye un **cliente de prueba completo** desarrollado con **NestJS** que demuestra todas las funcionalidades del wrapper.

### Características del Cliente de Prueba

- ✅ **API REST completa** con documentación Swagger
- ✅ **Validación automática** de datos
- ✅ **Tests de integración** completos
- ✅ **Logging estructurado**
- ✅ **Manejo de webhooks**
- ✅ **Ejemplos de detalle flexible**

### Ejecutar el Cliente de Prueba

```bash
# Instalar dependencias
npm install

# Ejecutar cliente de prueba
npm run example:dev

# Ejecutar tests de integración
npm run example:test

# Ejecutar ejemplo de detalle flexible
npm run example:detalle
```

Una vez ejecutándose, visita:
- **API**: http://localhost:3000
- **Documentación**: http://localhost:3000/api/docs

### Endpoints Disponibles

- `POST /api/payments` - Iniciar un pago
- `POST /api/payments/return` - Procesar retorno
- `POST /api/webhooks/epagos` - Webhook de ePagos
- `GET /api/payments/status` - Estado del servicio

Ver `examples/README.md` para documentación completa del cliente de prueba.

## Desarrollo

```bash
# Instalar dependencias
npm install

# Ejecutar tests de la librería
npm test

# Ejecutar tests en modo watch
npm run test:watch

# Compilar
npm run build

# Ejecutar cliente de prueba
npm run example:dev

# Ejecutar ejemplo de detalle flexible
npm run example:detalle
```

## Testing

El proyecto usa Jest para testing con dos niveles:

### Tests de la Librería
```bash
npm test
npm run test:watch
```

### Tests de Integración (Cliente de Prueba)
```bash
npm run example:test
```

## Estructura del Proyecto

```
@paroz/epagos-echeckout/
├── src/                    # Librería principal
│   ├── index.ts
│   ├── client.ts
│   ├── types.ts
│   ├── checkout-types.ts   # Tipos específicos del checkout
│   ├── html.ts            # Generación de HTML
│   ├── utils.ts
│   └── constants.ts
├── tests/                  # Tests unitarios
├── examples/               # Cliente de prueba con NestJS
│   ├── main.ts
│   ├── app.module.ts
│   ├── payments/           # Módulo de pagos
│   ├── webhooks/          # Módulo de webhooks
│   ├── epagos/            # Servicio ePagos
│   ├── detalle-flexible-example.ts  # Ejemplo de detalle flexible
│   └── README.md
└── README.md
```