# Diseño: Visor de CFDI

**Fecha:** 2026-02-17
**Estado:** Aprobado

## Resumen

Agregar funcionalidad para visualizar facturas CFDI en formato PDF-like, recreando la representación visual desde el XML almacenado. Incluye descarga de PDF y XML.

## Decisiones de Diseño

- **Tipo de vista:** PDF-like (representación visual similar a factura impresa)
- **Acceso:** Botón "Ver" (icono ojo) en cada fila de la tabla
- **Acciones:** Descargar PDF, Descargar XML
- **Enfoque técnico:** Componente React + html2pdf.js para generación de PDF en cliente

## Arquitectura de Componentes

```
CfdiPage (existente)
├── Tabla de CFDIs
│   └── Botón "Ver" (Eye icon) → abre modal
│
└── CfdiViewerModal (NUEVO)
     ├── Header: Título + Botones (PDF, XML, Cerrar)
     └── CfdiInvoice (NUEVO)
          ├── Encabezado (Emisor + Receptor)
          ├── Datos del comprobante
          ├── Tabla de conceptos (parseados del XML)
          ├── Totales e impuestos
          └── Timbre fiscal (UUID, fechas)
```

## Componentes Nuevos

| Componente | Ubicación | Responsabilidad |
|------------|-----------|-----------------|
| `CfdiViewerModal` | `components/cfdi/cfdi-viewer-modal.tsx` | Modal con visor y botones de acción |
| `CfdiInvoice` | `components/cfdi/cfdi-invoice.tsx` | Renderiza la factura estilo PDF |

## Diseño Visual

```
┌──────────────────────────────────────────────────────────────┐
│  ┌─────────────────┐              FACTURA                   │
│  │     [LOGO]      │              Serie: A  Folio: 001      │
│  │   placeholder   │              Fecha: 15/Ene/2025        │
│  └─────────────────┘                                         │
├──────────────────────────────────────────────────────────────┤
│  EMISOR                          │  RECEPTOR                 │
│  Empresa Emisora SA de CV        │  Cliente SA de CV         │
│  RFC: XAXX010101000              │  RFC: XAXX010101001       │
│                                  │  Uso CFDI: G03            │
├──────────────────────────────────────────────────────────────┤
│  DATOS DEL COMPROBANTE                                       │
│  Tipo: Ingreso    Método: PUE    Forma: 03 - Transferencia  │
│  Moneda: MXN      Tipo Cambio: 1.00                         │
├──────────────────────────────────────────────────────────────┤
│  CONCEPTOS                                                   │
│  ┌──────────────────────────────────────────────────────┐   │
│  │ Descripción          │ Cant │ P. Unit  │ Importe    │   │
│  ├──────────────────────────────────────────────────────┤   │
│  │ Servicio consultoría │  1   │ 10,000   │ 10,000.00  │   │
│  └──────────────────────────────────────────────────────┘   │
├──────────────────────────────────────────────────────────────┤
│                                         Subtotal: $10,000.00 │
│                                         IVA 16%:  $1,600.00  │
│                                         TOTAL:   $11,600.00  │
├──────────────────────────────────────────────────────────────┤
│  TIMBRE FISCAL DIGITAL                                       │
│  UUID: 12345678-1234-1234-1234-123456789012                 │
│  Fecha Timbrado: 2025-01-15T12:30:45                        │
└──────────────────────────────────────────────────────────────┘
```

## Flujo de Datos

1. Usuario hace clic en "Ver" (Eye icon)
2. Se abre CfdiViewerModal con el CFDI seleccionado
3. Si existe xmlOriginal:
   - Parsear XML para extraer conceptos
   - Mostrar factura completa
4. Si no existe XML:
   - Mostrar factura con datos de BD (sin conceptos)
5. Acciones disponibles:
   - Descargar PDF (html2pdf genera PDF)
   - Descargar XML (si existe)

## Cambios en Backend

### Nuevo Endpoint

```
GET /api/cfdi/:id/xml
```

Retorna el XML original del CFDI.

### Modificar Endpoint Existente

```
GET /api/cfdi/:id
```

Agregar campo `xmlOriginal` a la respuesta.

## Dependencias

```json
{
  "html2pdf.js": "^0.10.1"
}
```

## Archivos a Crear/Modificar

### Nuevos
- `apps/web/components/cfdi/cfdi-viewer-modal.tsx`
- `apps/web/components/cfdi/cfdi-invoice.tsx`
- `apps/api/src/controllers/cfdi.controller.ts` (nuevo método getXml)

### Modificar
- `apps/web/app/(dashboard)/cfdi/page.tsx` (agregar botón Ver y modal)
- `apps/api/src/routes/cfdi.routes.ts` (agregar ruta /xml)
- `apps/api/src/services/cfdi.service.ts` (agregar método getXmlById)
- `packages/shared/src/types/cfdi.ts` (agregar xmlOriginal a Cfdi)
