{
  "name": "SPEICEP WA - Panaderia (Evolution API)",
  "nodes": [
    {
      "parameters": {
        "content": "## Panaderia El Buen Pan - Pedidos WhatsApp (Evolution API)\n\nBot con las reglas de este negocio (horario, minimos, anticipacion, envio...). Valida el pago con SPEICEP.\n\n### Configura\n1. Evolution API: webhook al nodo *Mensaje entrante*, con media en base64.\n2. *Enviar WhatsApp*: TU_EVOLUTION_URL, TU_INSTANCIA, apikey.\n3. *Validar en SPEICEP*: tu API key.\n4. *Aplicar reglas* y *Datos de pago*: tu banco, CLABE, catalogo, precios y reglas.",
        "height": 380,
        "width": 470
      },
      "id": "panaderia-evo0-4000-8000-000000000001",
      "name": "Guia",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -180,
        10
      ]
    },
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "wa-panaderia-evo",
        "options": {}
      },
      "id": "panaderia-evo0-4000-8000-000000000002",
      "name": "Mensaje entrante",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        420,
        300
      ],
      "webhookId": "speicep-wa-panaderia-evo"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "f1",
              "name": "telefono",
              "value": "={{ $json.body?.data?.key?.remoteJid || '' }}",
              "type": "string"
            },
            {
              "id": "f2",
              "name": "texto",
              "value": "={{ ($json.body?.data?.message?.conversation || $json.body?.data?.message?.extendedTextMessage?.text || '').toString().trim() }}",
              "type": "string"
            },
            {
              "id": "f3",
              "name": "imagenBase64",
              "value": "={{ $json.body?.data?.message?.base64 || '' }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "id": "panaderia-evo0-4000-8000-000000000003",
      "name": "Extraer datos",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        640,
        300
      ]
    },
    {
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "caseSensitive": false,
                  "typeValidation": "loose"
                },
                "conditions": [
                  {
                    "leftValue": "={{ $json.imagenBase64 }}",
                    "rightValue": "",
                    "operator": {
                      "type": "string",
                      "operation": "notEmpty"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "comprobante"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": false,
                  "typeValidation": "loose"
                },
                "conditions": [
                  {
                    "leftValue": "={{ $json.texto }}",
                    "rightValue": "\\d+\\s*[xX]\\s*\\d+",
                    "operator": {
                      "type": "string",
                      "operation": "regex"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "pedido"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": false,
                  "typeValidation": "loose"
                },
                "conditions": [
                  {
                    "leftValue": "={{ $json.texto.toLowerCase() }}",
                    "rightValue": "menu|hola|buenas|pedido|ordenar",
                    "operator": {
                      "type": "string",
                      "operation": "regex"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "menu"
            }
          ]
        },
        "options": {
          "fallbackOutput": "extra",
          "renameFallbackOutput": "ayuda"
        }
      },
      "id": "panaderia-evo0-4000-8000-000000000004",
      "name": "Intencion",
      "type": "n8n-nodes-base.switch",
      "typeVersion": 3,
      "position": [
        880,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "const menu = {1:{nombre:\"Bolillo\",precio:3},2:{nombre:\"Concha\",precio:12},3:{nombre:\"Croissant\",precio:18},4:{nombre:\"Pan de muerto\",precio:25}};\nconst campos = [\"hora\"];\nconst cfg = {\"horario\":[6,14],\"delivery\":false,\"envio\":0,\"minDom\":0,\"gratisDesde\":null,\"anticipDias\":0,\"anticipoPct\":100,\"requeridos\":[],\"recetaItem\":0,\"recetaNombre\":\"\",\"toppingsExtra\":0};\nconst raw = ($json.texto || '').trim();\nconst partes = raw.split(';').map(s => s.trim());\nconst items = []; let subtotal = 0; let pideReceta = false;\nconst re = /(\\d+)\\s*[xX]\\s*(\\d+)/g; let m;\nwhile ((m = re.exec(partes[0])) !== null) {\n  const num = parseInt(m[1],10); const c = parseInt(m[2],10); const it = menu[num];\n  if (it && c > 0) { items.push(c + ' x ' + it.nombre); subtotal += it.precio * c; if (cfg.recetaItem && num === cfg.recetaItem) pideReceta = true; }\n}\nconst datos = {};\ncampos.forEach((k,i) => { datos[k] = (partes[i+1] || '').trim(); });\nlet ok = true; let motivo = \"\";\n// Regla: sin items validos\nif (ok && items.length === 0) { ok = false; motivo = \"No entendi tu pedido. Escribe \\\"menu\\\" para ver como ordenar.\"; }\n// Regla: horario de atencion\nif (ok && cfg.horario) { const h = new Date().getHours(); if (h < cfg.horario[0] || h >= cfg.horario[1]) { ok = false; motivo = \"Nuestro horario es de \" + cfg.horario[0] + \":00 a \" + cfg.horario[1] + \":00. Con gusto te atendemos en ese horario.\"; } }\n// Regla: a domicilio o recoger\nconst aDomicilio = cfg.delivery || (datos.entrega && /domicil/i.test(datos.entrega));\n// Regla: campos obligatorios\nif (ok) { for (const k of cfg.requeridos) { if (!datos[k]) { ok = false; motivo = \"Falta un dato para tu pedido. Usa el formato: \" + \"Manda: numero x cantidad ; hora de recogida. Ej: 2x3, 1x2 ; 6pm\"; break; } } }\n// Regla: pedido minimo a domicilio\nif (ok && cfg.minDom > 0 && aDomicilio && subtotal < cfg.minDom) { ok = false; motivo = \"El pedido minimo a domicilio es $\" + cfg.minDom + \". Agrega algo mas a tu pedido.\"; }\n// Regla: anticipacion minima (fecha dd/mm)\nif (ok && cfg.anticipDias > 0) {\n  const fm = (datos.fecha || \"\").match(/(\\d{1,2})[\\/\\-](\\d{1,2})/);\n  let valida = false;\n  if (fm) { const hoy = new Date(); const y = hoy.getFullYear(); let f = new Date(y, parseInt(fm[2],10)-1, parseInt(fm[1],10)); if (f < hoy) f = new Date(y+1, parseInt(fm[2],10)-1, parseInt(fm[1],10)); const dias = Math.ceil((f - hoy)/86400000); valida = dias >= cfg.anticipDias; }\n  if (!valida) { ok = false; motivo = \"Este pedido se agenda con minimo \" + cfg.anticipDias + \" dia(s) de anticipacion. Indica una fecha valida (dd/mm).\"; }\n}\n// Envio (gratis desde cierto monto)\nlet envioMonto = aDomicilio ? cfg.envio : 0;\nif (cfg.gratisDesde && subtotal >= cfg.gratisDesde) envioMonto = 0;\n// Toppings extra\nif (cfg.toppingsExtra && datos.toppings) subtotal += cfg.toppingsExtra;\nconst total = subtotal + envioMonto;\nconst aPagar = Math.round(total * cfg.anticipoPct / 100);\nconst folio = 'PED-' + Date.now().toString().slice(-6);\nconst resumen = items.length ? items.join(', ') : 'pedido';\nreturn [{ json: { ...$json, ok, motivo, subtotal, total, aPagar, envioMonto, resumen, datos, folio, pideReceta, anticipoPct: cfg.anticipoPct } }];"
      },
      "id": "panaderia-evo0-4000-8000-000000000005",
      "name": "Aplicar reglas",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1140,
        180
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "conditions": [
            {
              "leftValue": "={{ $json.ok }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "panaderia-evo0-4000-8000-000000000016",
      "name": "Cumple reglas?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        1360,
        180
      ]
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "v",
              "name": "respuesta",
              "value": "=Panaderia El Buen Pan - Menu\nHorario: 6:00 a 14:00.\n1. Bolillo - $3\n2. Concha - $12\n3. Croissant - $18\n4. Pan de muerto - $25\n\nComo pedir: Manda: numero x cantidad ; hora de recogida. Ej: 2x3, 1x2 ; 6pm",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "id": "panaderia-evo0-4000-8000-000000000006",
      "name": "Texto del menu",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        1140,
        360
      ]
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "v",
              "name": "respuesta",
              "value": "=Para ordenar escribe \"menu\". Cuando pagues, mandanos la foto de tu comprobante y lo validamos al instante.",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "id": "panaderia-evo0-4000-8000-000000000007",
      "name": "Texto de ayuda",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        1140,
        520
      ]
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "v",
              "name": "respuesta",
              "value": "=Pedido confirmado: {{ $json.resumen }}.\nRecoger a las: {{ $json.datos.hora }}\nTotal: ${{ $json.total }} MXN.\n\nPaga por SPEI a:\nBanco: TU BANCO\nCLABE: TU CLABE (18 digitos)\nMonto: ${{ $json.aPagar }}\nConcepto: {{ $json.folio }}\n\nCuando pagues, mandanos la FOTO de tu comprobante y lo validamos al instante.",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "id": "panaderia-evo0-4000-8000-000000000008",
      "name": "Datos de pago",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        1580,
        80
      ]
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "v",
              "name": "respuesta",
              "value": "={{ $json.motivo }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "id": "panaderia-evo0-4000-8000-000000000017",
      "name": "Regla no cumplida",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        1580,
        300
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://speicep.com/api/v1/validate",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer sk_live_TU_API_KEY"
            }
          ]
        },
        "contentType": "multipart-form-data",
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "parameterType": "formBinaryData",
              "name": "file",
              "inputDataFieldName": "comprobante"
            }
          ]
        },
        "options": {}
      },
      "id": "panaderia-evo0-4000-8000-000000000009",
      "name": "Validar en SPEICEP",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1560,
        700
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "conditions": [
            {
              "leftValue": "={{ $json.status }}",
              "rightValue": "valid",
              "operator": {
                "type": "string",
                "operation": "equals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "panaderia-evo0-4000-8000-000000000011",
      "name": "Pago valido?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        1780,
        700
      ]
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "v",
              "name": "respuesta",
              "value": "=Pago confirmado en Banxico. Tu pedido esta en proceso. Gracias por tu compra!",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "id": "panaderia-evo0-4000-8000-000000000012",
      "name": "Texto pago ok",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        2000,
        620
      ]
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "v",
              "name": "respuesta",
              "value": "=Aun no encontramos tu pago en Banxico. Verifica la transferencia a la CLABE indicada y reenvia el comprobante en un momento.",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "id": "panaderia-evo0-4000-8000-000000000013",
      "name": "Texto pago no",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        2000,
        780
      ]
    },
    {
      "parameters": {
        "operation": "toBinary",
        "sourceProperty": "imagenBase64",
        "options": {
          "fileName": "comprobante.jpg",
          "mimeType": "image/jpeg",
          "dataPropertyName": "comprobante"
        }
      },
      "id": "panaderia-evo0-4000-8000-000000000010",
      "name": "Base64 a archivo",
      "type": "n8n-nodes-base.convertToFile",
      "typeVersion": 1.1,
      "position": [
        1360,
        700
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "=TU_EVOLUTION_URL/message/sendText/TU_INSTANCIA",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "apikey",
              "value": "TU_APIKEY_EVOLUTION"
            }
          ]
        },
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "number",
              "value": "={{ $json.telefono }}"
            },
            {
              "name": "text",
              "value": "={{ $json.respuesta }}"
            }
          ]
        },
        "options": {}
      },
      "id": "panaderia-evo0-4000-8000-000000000014",
      "name": "Enviar WhatsApp",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        2260,
        700
      ]
    }
  ],
  "connections": {
    "Mensaje entrante": {
      "main": [
        [
          {
            "node": "Extraer datos",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extraer datos": {
      "main": [
        [
          {
            "node": "Intencion",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Intencion": {
      "main": [
        [
          {
            "node": "Base64 a archivo",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Aplicar reglas",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Texto del menu",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Texto de ayuda",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Base64 a archivo": {
      "main": [
        [
          {
            "node": "Validar en SPEICEP",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Aplicar reglas": {
      "main": [
        [
          {
            "node": "Cumple reglas?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Cumple reglas?": {
      "main": [
        [
          {
            "node": "Datos de pago",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Regla no cumplida",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Datos de pago": {
      "main": [
        [
          {
            "node": "Enviar WhatsApp",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Regla no cumplida": {
      "main": [
        [
          {
            "node": "Enviar WhatsApp",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Texto del menu": {
      "main": [
        [
          {
            "node": "Enviar WhatsApp",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Texto de ayuda": {
      "main": [
        [
          {
            "node": "Enviar WhatsApp",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Validar en SPEICEP": {
      "main": [
        [
          {
            "node": "Pago valido?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Pago valido?": {
      "main": [
        [
          {
            "node": "Texto pago ok",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Texto pago no",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Texto pago ok": {
      "main": [
        [
          {
            "node": "Enviar WhatsApp",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Texto pago no": {
      "main": [
        [
          {
            "node": "Enviar WhatsApp",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  },
  "active": false
}