> Plantilla de partida de fernandorivera.es. Úsala y adáptala libremente; sin garantía; revisa los datos que tratas.

# Tickets de gasto con foto e IA en Make

Guía paso a paso para montar en Make el mismo flujo que la plantilla de n8n `n8n-tickets-de-gasto.json`: quien hace un gasto sube la foto del ticket desde el móvil, una IA lee los datos, una fórmula los comprueba, se guarda una fila en la hoja y, si algo no cuadra, avisa a quien revisa. Nada se aprueba solo.

Explicación completa en el artículo «Monta tu app: tickets de gasto con foto e IA» de fernandorivera.es.

> Es una plantilla de partida, no probada en tu cuenta. Revísala módulo a módulo y pruébala con tickets de prueba antes de usarla de verdad. Los nombres de los módulos de Make pueden cambiar un poco con las versiones: si no encuentras uno exacto, busca el más parecido dentro de la misma app.

## Lo que necesitas

- Una cuenta de Make.
- Una cuenta de Google (Forms, Drive, Sheets y Gmail). Mejor una cuenta de la tienda o de la empresa, no la personal de nadie.
- Una clave de API de un proveedor de IA que lea imágenes (OpenAI, Anthropic o Google), dada de alta a nombre del negocio.

## Prepara el formulario y la hoja

1. **Google Forms**: preguntas *Tienda* (desplegable), *Empleado* (respuesta corta), *Motivo* (desplegable) y *Foto del ticket* (subir archivo, solo imágenes, 1 archivo). Las preguntas de subir archivo obligan a iniciar sesión con Google: usa la cuenta del móvil de la tienda.
2. En *Respuestas*, vincula el formulario a una hoja nueva. Esa pestaña es la entrada del escenario.
3. En la misma hoja, crea una pestaña **Tickets** con estas columnas en la fila 1:

| ID | Recibido | Tienda | Empleado | Motivo | Fecha | Proveedor | NIF | Número | Base | Tipo IVA | Cuota IVA | Total | Tipo documento | Estado | Motivos de revisión | Foto | Registrado en Holded |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|

4. En la columna **Estado**, añade una validación de datos (desplegable) con: `Pendiente de aprobar`, `Revisar`, `Aprobado`, `Rechazado`.

## Los módulos, en orden

### Módulo 1 · Google Sheets › Watch New Rows
- Hoja y pestaña de respuestas del formulario. Con cabeceras.
- Límite: 5 filas por ejecución está bien para empezar.

### Módulo 2 · Google Drive › Download a File
- File ID: el enlace de la foto viene como `https://drive.google.com/open?id=XXXX`. Saca el ID con:
  `{{last(split(Foto del ticket; "id="))}}`
- Si tu formulario guarda el enlace con otro formato, ajusta el `split`.

### Módulo 3 · HTTP › Make a request
Llamada a la IA con la imagen. Ejemplo con el formato *chat/completions* de OpenAI (si usas Claude o Gemini, copia la URL, las cabeceras y el cuerpo de su documentación):

- URL: `https://api.openai.com/v1/chat/completions`
- Method: POST
- Headers: `Authorization` = `Bearer TU_CLAVE` (mejor en una conexión o variable, no escrita a la vista).
- Body type: Raw · Content type: JSON
- Request content:

```json
{
  "model": "TU_MODELO_CON_VISION",
  "temperature": 0,
  "response_format": { "type": "json_object" },
  "messages": [{
    "role": "user",
    "content": [
      { "type": "text", "text": "PEGA AQUÍ LA INSTRUCCIÓN DE ABAJO" },
      { "type": "image_url", "image_url": { "url": "data:image/jpeg;base64,{{base64(2.data)}}" } }
    ]
  }]
}
```

- Parse response: Yes.

**Instrucción para la IA:**

```
Lee la foto de este ticket o factura de gasto de un negocio en España. Devuelve SOLO un objeto JSON con estas claves: fecha (AAAA-MM-DD), proveedor, nif, numero, base, tipo_iva, cuota_iva, total, tipo_documento ("ticket", "factura simplificada" o "factura"), confianza ("alta", "media" o "baja") y dudas. Importes como número con punto decimal y sin símbolo de euro. Si hay varios tipos de IVA, pon en base y cuota_iva la suma, en tipo_iva "varios" y explícalo en dudas. Si un dato no aparece o no se lee con claridad, pon null y dilo en dudas. No adivines ni calcules ningún dato que no esté impreso. No copies nombres de personas, números de tarjeta ni otros datos personales que aparezcan en el ticket.
```

Dentro del JSON de Make, las comillas de la instrucción tienen que ir escapadas (`\"`). Si te da guerra, quita las comillas de la instrucción.

### Módulo 4 · JSON › Parse JSON
- JSON string: `{{3.data.choices[].message.content}}` (el primer elemento de `choices`).
- Para que Make te ofrezca los campos, crea la estructura con *Generate* pegando un ejemplo como este (inventado):

```json
{"fecha":"2026-11-03","proveedor":"Ferretería Ejemplo SL","nif":"B00000000","numero":"T-001","base":10.00,"tipo_iva":21,"cuota_iva":2.10,"total":12.10,"tipo_documento":"ticket","confianza":"alta","dudas":null}
```

### Módulo 5 · Tools › Set multiple variables (las comprobaciones)
Las comprobaciones las hace Make, no la IA:

- `cuadra`: `{{if(abs(4.base + 4.cuota_iva - 4.total) <= 0,02; "sí"; "no")}}`
- `faltan`: `{{if(4.fecha && 4.proveedor && 4.total; ""; "Faltan datos")}}`
- `motivos`: junta lo que falle, por ejemplo
  `{{trim(faltan + " " + if(cuadra = "no"; "Base + IVA no da el total"; "") + " " + if(4.total >= 150; "Importe alto"; "") + " " + if(4.confianza = "baja"; "La IA no lo ve claro"; "") + " " + if(4.nif; ""; "Sin NIF"))}}`
- `estado`: `{{if(motivos; "Revisar"; "Pendiente de aprobar")}}`

El 150 es un ejemplo: pon el importe a partir del cual quieres mirar siempre el ticket. Según la configuración regional de tu cuenta, el decimal puede ir con punto (0.02).

### Módulo 6 · Google Sheets › Add a Row
Pestaña **Tickets**. Mapea cada columna: datos del módulo 1 (Tienda, Empleado, Motivo, enlace de la foto), del módulo 4 (fecha, proveedor, NIF, importes) y del 5 (Estado y Motivos de revisión). ID: `{{formatDate(now; "YYYYMMDD-HHmmss")}}`.

### Filtro y Módulo 7 · Gmail › Send an email
- Filtro en la línea antes del módulo 7: `estado` igual a `Revisar`.
- Asunto: `Ticket por revisar: {{1.Tienda}} · {{4.proveedor}}`
- Texto: motivos, total, enlace a la foto y «Corrige los datos en la hoja y cambia el Estado a Aprobado o Rechazado».

## Segundo escenario: aprobados a Holded (opcional)

Solo si usas Holded y tu gestoría está de acuerdo.

1. **Schedule**: cada día a última hora.
2. **Google Sheets › Search Rows**: pestaña Tickets, `Estado` igual a `Aprobado` y `Registrado en Holded` vacío.
3. **HTTP › Make a request**: `POST https://api.holded.com/api/invoicing/v1/documents/purchase`, cabecera `key` con tu clave de API de Holded, cuerpo JSON con proveedor, NIF, fecha, `isReceipt: true` y una línea con base y tipo de IVA. Revisa los nombres exactos de los campos y el formato de la fecha en la referencia oficial «Create Document» de developers.holded.com antes de activarlo, y prueba con un solo ticket.
4. **Google Sheets › Update a Row**: escribe en `Registrado en Holded` el id que devuelve Holded.

Si Make te muestra una app de Holded con un módulo para crear documentos de compra, puedes usarla en lugar del módulo HTTP.

**Cadena con SAP u otro ERP:** no conectes nada al ERP. En lugar del segundo escenario, filtra la hoja por *Aprobado* y descarga un CSV con las columnas y el formato que pida administración, o deja que administración lo importe con su proceso habitual.

## Pruébalo

1. Sube tres tickets de prueba: uno nítido, uno movido y uno en el que tapes el total.
2. Pulsa **Run once** y comprueba la hoja: el nítido debe quedar en *Pendiente de aprobar*; los otros dos, en *Revisar* con su motivo y su correo.
3. Compara a mano los datos del ticket nítido con la fila. Si la IA confunde base y total, revisa la instrucción y la foto.
4. Cuando funcione, activa el escenario.

## Datos

Un ticket puede llevar nombres, parte de una tarjeta o datos de terceros. Pide al equipo que fotografíe solo el ticket, sin el resguardo de la tarjeta ni documentos personales. Usa la API con una cuenta del negocio y revisa las condiciones de uso de datos del proveedor de IA. La hoja y la carpeta de fotos, compartidas solo con quien las necesita.
