{
 "name": "Tracción · bot de Telegram",
 "nodes": [
  {
   "id": "6681416a-e304-4fa7-babc-f285c369a640",
   "name": "Nota bc11",
   "type": "n8n-nodes-base.stickyNote",
   "typeVersion": 1,
   "position": [
    -40,
    -400
   ],
   "parameters": {
    "content": "## Bot de Telegram del taller\nEl cliente le escribe al bot como a una persona. La IA entiende qué pide (precio, turno, estado del auto, horario u otra cosa) y saca la medida; los precios y horarios salen del código, no los inventa la IA. Los pedidos de turno quedan anotados y le avisan al taller. Aparte, cuando el taller marca una orden como terminada, el bot le escribe solo al cliente: «tu auto está listo».",
    "width": 640,
    "height": 220,
    "color": 2
   }
  },
  {
   "id": "bd487b71-4da0-4f30-aff8-0e5361a5a295",
   "name": "Mensaje al bot",
   "type": "n8n-nodes-base.telegramTrigger",
   "typeVersion": 1.2,
   "position": [
    0,
    0
   ],
   "parameters": {
    "updates": [
     "message"
    ],
    "additionalFields": {}
   },
   "webhookId": "de063f4a-35c0-467f-8e88-5ca541ec5399",
   "credentials": {
    "telegramApi": {
     "id": "",
     "name": "Telegram (simulador)"
    }
   }
  },
  {
   "id": "564580a9-e154-4f47-871a-0140e3ea21d2",
   "name": "Leer el mensaje",
   "type": "n8n-nodes-base.code",
   "typeVersion": 2,
   "position": [
    240,
    0
   ],
   "parameters": {
    "mode": "runOnceForEachItem",
    "jsCode": "\n// Lo que importa del mensaje de Telegram: quién escribe, qué dice y si es un comando.\nconst m = $json.message || {};\nconst texto = String(m.text || '').trim();\nreturn { chat_id: String(m.chat?.id ?? ''), nombre: m.from?.first_name || '', texto, comando: texto.startsWith('/') ? texto.split(/\\s/)[0].toLowerCase() : '' };\n"
   }
  },
  {
   "id": "595af8ae-7e67-4daf-9b1c-2c2ac09072b3",
   "name": "¿Es /start?",
   "type": "n8n-nodes-base.if",
   "typeVersion": 2.3,
   "position": [
    480,
    0
   ],
   "parameters": {
    "conditions": {
     "options": {
      "caseSensitive": true,
      "leftValue": "",
      "typeValidation": "loose",
      "version": 2
     },
     "conditions": [
      {
       "id": "8d91da22-e7c7-4dbc-a303-af4908b36c56",
       "leftValue": "={{ $json.comando }}",
       "rightValue": "/start",
       "operator": {
        "type": "string",
        "operation": "equals"
       }
      }
     ],
     "combinator": "and"
    },
    "options": {}
   }
  },
  {
   "id": "c46d7754-0301-40ce-a586-0c5d24a35c17",
   "name": "Bienvenida",
   "type": "n8n-nodes-base.telegram",
   "typeVersion": 1.2,
   "position": [
    720,
    -140
   ],
   "parameters": {
    "resource": "message",
    "operation": "sendMessage",
    "chatId": "={{ $json.chat_id }}",
    "text": "={{ '¡Hola, ' + $json.nombre + '! Soy el asistente de <b>Tracción</b>. Puedo cotizarte neumáticos (pásame la medida), anotarte un turno, contarte cómo va tu auto o decirte el horario. ¿Qué necesitas?' }}",
    "additionalFields": {
     "parse_mode": "HTML",
     "appendAttribution": false
    }
   },
   "credentials": {
    "telegramApi": {
     "id": "",
     "name": "Telegram (simulador)"
    }
   }
  },
  {
   "id": "f0795c84-f6b2-4580-8c36-4cace795ca3a",
   "name": "La IA entiende el mensaje",
   "type": "@n8n/n8n-nodes-langchain.informationExtractor",
   "typeVersion": 1.2,
   "position": [
    720,
    60
   ],
   "parameters": {
    "text": "={{ $json.texto }}",
    "schemaType": "fromAttributes",
    "attributes": {
     "attributes": [
      {
       "name": "intencion",
       "type": "string",
       "description": "Uno de: precio, turno, estado, horario, otra",
       "required": true
      },
      {
       "name": "rodado",
       "type": "number",
       "description": "Rodado de la medida (el número después de la R, ej. 16 en 195/55 R16); 0 si no lo dice",
       "required": false
      },
      {
       "name": "cantidad",
       "type": "number",
       "description": "Cuántos neumáticos; 4 si no lo dice",
       "required": false
      },
      {
       "name": "dia_preferido",
       "type": "string",
       "description": "Día u horario que pide para el turno, como lo dice; vacío si no dice",
       "required": false
      },
      {
       "name": "orden",
       "type": "string",
       "description": "Número de orden si lo menciona; vacío si no",
       "required": false
      },
      {
       "name": "respuesta",
       "type": "string",
       "description": "Sólo para «otra»: respuesta breve con los datos del taller; si no sabes, di que le pasas el mensaje al taller. Nunca inventes precios.",
       "required": true
      }
     ]
    },
    "options": {
     "systemPromptTemplate": "Atiendes el chat de Telegram de un taller de neumáticos. Datos del taller: Tracción, centro de neumáticos en Av. Libertador Gral. San Martín 1850 (O), Rivadavia, San Juan. Horario: lunes a viernes de 8:00 a 19:00 y sábados de 8:30 a 13:30. Servicios: montaje desde $ 9.000, balanceo desde $ 6.500, alineación 3D desde $ 12.000. Cambiando los 4 neumáticos, la alineación va de regalo. 6 cuotas sin interés con crédito, 10 % de descuento en efectivo o transferencia."
    }
   }
  },
  {
   "id": "e754a084-32c2-4964-a275-69ff4a2a838a",
   "name": "Claude",
   "type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
   "typeVersion": 1.6,
   "position": [
    740,
    280
   ],
   "parameters": {
    "model": {
     "__rl": true,
     "mode": "id",
     "value": "claude-sonnet-5-5"
    },
    "options": {
     "maxTokensToSample": 1200,
     "thinkingMode": "adaptive",
     "effort": "low"
    }
   },
   "credentials": {
    "anthropicApi": {
     "id": "",
     "name": "Claude (demos)"
    }
   }
  },
  {
   "id": "2f38ee1c-4311-4ffe-813b-38674304eaba",
   "name": "Armar la respuesta",
   "type": "n8n-nodes-base.code",
   "typeVersion": 2,
   "position": [
    960,
    60
   ],
   "parameters": {
    "mode": "runOnceForEachItem",
    "jsCode": "\n// Los PRECIOS y los horarios salen de acá (no los inventa la IA): rodado → precio por neumático en tres líneas.\nconst RODADOS = { 13: 62000, 14: 71000, 15: 82000, 16: 98000, 17: 124000, 18: 152000 };\nconst LINEAS = [['Económica', 0.82], ['Intermedia', 1], ['Premium', 1.38]];\nconst $$ = n => '$ ' + Math.round(n).toLocaleString('es-AR');\nconst m = $('Leer el mensaje').first().json;\nconst d = $json.output || {};\nconst rodado = Math.round(Number(d.rodado) || 0);\nconst cant = Math.max(1, Math.min(8, Math.round(Number(d.cantidad) || 4)));\nlet respuesta = d.respuesta || 'Te paso con alguien del taller.';\nif (d.intencion === 'precio') {\n  respuesta = RODADOS[rodado]\n    ? `Precio por neumático rodado ${rodado} (sin montaje):\\n` + LINEAS.map(([l, k]) => `• ${l}: ${$$(RODADOS[rodado] * k)} c/u · ${cant} = ${$$(RODADOS[rodado] * k * cant)}`).join('\\n') +\n      (cant >= 4 ? '\\nCambiando los 4, la alineación va de regalo.' : '') + '\\n6 cuotas sin interés o 10 % menos en efectivo.'\n    : 'Para cotizarte necesito la medida: está en el costado del neumático, por ejemplo 195/55 R16. ¿Me la pasas?';\n}\nif (d.intencion === 'horario') respuesta = 'Atendemos de lunes a viernes de 8:00 a 19:00 y los sábados de 8:30 a 13:30, en Av. Libertador 1850 (O), Rivadavia.';\nif (d.intencion === 'turno') respuesta = `¡Listo, ${m.nombre || ''}! Anoté tu pedido de turno${d.dia_preferido ? ' para ' + d.dia_preferido : ''}. En un rato el taller te confirma el horario por acá.`;\nreturn { ...m, intencion: d.intencion, rodado, cantidad: cant, dia_preferido: d.dia_preferido || '', orden: String(d.orden || ''), respuesta };\n"
   }
  },
  {
   "id": "7291e0f2-9930-4062-84a0-6f82e9397240",
   "name": "Según lo que pide",
   "type": "n8n-nodes-base.switch",
   "typeVersion": 3.2,
   "position": [
    1200,
    60
   ],
   "parameters": {
    "rules": {
     "values": [
      {
       "conditions": {
        "options": {
         "caseSensitive": false,
         "leftValue": "",
         "typeValidation": "loose",
         "version": 2
        },
        "conditions": [
         {
          "id": "af40eab8-0d2e-42a7-8664-16962ee7ca39",
          "leftValue": "={{ $json.intencion }}",
          "rightValue": "turno",
          "operator": {
           "type": "string",
           "operation": "equals"
          }
         }
        ],
        "combinator": "and"
       },
       "renameOutput": true,
       "outputKey": "turno"
      },
      {
       "conditions": {
        "options": {
         "caseSensitive": false,
         "leftValue": "",
         "typeValidation": "loose",
         "version": 2
        },
        "conditions": [
         {
          "id": "1ef4b43d-7fe8-448a-8bb1-ebaf43936506",
          "leftValue": "={{ $json.intencion }}",
          "rightValue": "estado",
          "operator": {
           "type": "string",
           "operation": "equals"
          }
         }
        ],
        "combinator": "and"
       },
       "renameOutput": true,
       "outputKey": "estado"
      }
     ]
    },
    "options": {
     "fallbackOutput": "extra",
     "renameFallbackOutput": "el resto"
    }
   }
  },
  {
   "id": "0aac97dc-d081-4ed1-ac84-95befccb2595",
   "name": "Pedidos de turno",
   "type": "n8n-nodes-base.dataTable",
   "typeVersion": 1.1,
   "position": [
    1440,
    -100
   ],
   "parameters": {
    "resource": "row",
    "operation": "insert",
    "dataTableId": {
     "__rl": true,
     "mode": "id",
     "value": ""
    },
    "columns": {
     "mappingMode": "defineBelow",
     "value": {
      "fecha": "={{ $now.toISODate() }}",
      "chat_id": "={{ $json.chat_id }}",
      "nombre": "={{ $json.nombre }}",
      "rodado": "={{ $json.rodado }}",
      "cantidad": "={{ $json.cantidad }}",
      "dia_preferido": "={{ $json.dia_preferido }}",
      "estado": "a confirmar"
     },
     "matchingColumns": [],
     "schema": [
      {
       "id": "fecha",
       "displayName": "fecha",
       "required": false,
       "defaultMatch": false,
       "display": true,
       "type": "string",
       "canBeUsedToMatch": true
      },
      {
       "id": "chat_id",
       "displayName": "chat_id",
       "required": false,
       "defaultMatch": false,
       "display": true,
       "type": "string",
       "canBeUsedToMatch": true
      },
      {
       "id": "nombre",
       "displayName": "nombre",
       "required": false,
       "defaultMatch": false,
       "display": true,
       "type": "string",
       "canBeUsedToMatch": true
      },
      {
       "id": "rodado",
       "displayName": "rodado",
       "required": false,
       "defaultMatch": false,
       "display": true,
       "type": "number",
       "canBeUsedToMatch": true
      },
      {
       "id": "cantidad",
       "displayName": "cantidad",
       "required": false,
       "defaultMatch": false,
       "display": true,
       "type": "number",
       "canBeUsedToMatch": true
      },
      {
       "id": "dia_preferido",
       "displayName": "dia_preferido",
       "required": false,
       "defaultMatch": false,
       "display": true,
       "type": "string",
       "canBeUsedToMatch": true
      },
      {
       "id": "estado",
       "displayName": "estado",
       "required": false,
       "defaultMatch": false,
       "display": true,
       "type": "string",
       "canBeUsedToMatch": true
      }
     ]
    },
    "options": {}
   }
  },
  {
   "id": "d25c6583-7721-4a40-b587-4c50ff9e8c08",
   "name": "Aviso al taller",
   "type": "n8n-nodes-base.telegram",
   "typeVersion": 1.2,
   "position": [
    1680,
    -100
   ],
   "parameters": {
    "resource": "message",
    "operation": "sendMessage",
    "chatId": "5550500",
    "text": "={{ '<b>Pedido de turno</b> · ' + $('Armar la respuesta').first().json.nombre + '\\n«' + $('Armar la respuesta').first().json.texto + '»' + ($('Armar la respuesta').first().json.dia_preferido ? '\\nPrefiere: ' + $('Armar la respuesta').first().json.dia_preferido : '') }}",
    "additionalFields": {
     "parse_mode": "HTML",
     "appendAttribution": false
    }
   },
   "credentials": {
    "telegramApi": {
     "id": "",
     "name": "Telegram (simulador)"
    }
   }
  },
  {
   "id": "f0ae8947-2d73-46c7-83d0-5c0379a2bf8e",
   "name": "Buscar su orden",
   "type": "n8n-nodes-base.dataTable",
   "typeVersion": 1.1,
   "position": [
    1440,
    80
   ],
   "parameters": {
    "resource": "row",
    "operation": "get",
    "dataTableId": {
     "__rl": true,
     "mode": "id",
     "value": ""
    },
    "matchType": "allConditions",
    "returnAll": true
   }
  },
  {
   "id": "da7611fd-88be-46bd-acc1-f493ec0c4147",
   "name": "Estado de la orden",
   "type": "n8n-nodes-base.code",
   "typeVersion": 2,
   "position": [
    1680,
    80
   ],
   "parameters": {
    "mode": "runOnceForAllItems",
    "jsCode": "\n// Busca la orden por número o por el chat de quien escribe y cuenta en qué está.\nconst m = $('Armar la respuesta').first().json;\nconst ordenes = $input.all().map(i => i.json).filter(o => o.orden);\nconst o = ordenes.find(x => m.orden && x.orden === m.orden) || ordenes.find(x => x.chat_id === m.chat_id);\nreturn { chat_id: m.chat_id, respuesta: o ? `Tu ${o.vehiculo} (orden ${o.orden}, ${o.trabajo}) está: ${o.estado}.` + (o.estado === 'listo para retirar' ? ' ¡Te esperamos!' : ' Te aviso por acá apenas esté listo.')\n  : 'No encuentro una orden con este chat. ¿Me pasas el número de orden que figura en tu comprobante?' };\n"
   }
  },
  {
   "id": "6638e30a-ab20-46d7-a507-4b08a1dd83b3",
   "name": "Respuesta al cliente",
   "type": "n8n-nodes-base.telegram",
   "typeVersion": 1.2,
   "position": [
    1920,
    60
   ],
   "parameters": {
    "resource": "message",
    "operation": "sendMessage",
    "chatId": "={{ $('Armar la respuesta').first().json.chat_id }}",
    "text": "={{ $json.respuesta || $('Armar la respuesta').first().json.respuesta }}",
    "additionalFields": {
     "parse_mode": "HTML",
     "appendAttribution": false
    }
   },
   "credentials": {
    "telegramApi": {
     "id": "",
     "name": "Telegram (simulador)"
    }
   }
  },
  {
   "id": "06a61fff-8710-4a67-9e5b-4b334533d0aa",
   "name": "Orden terminada",
   "type": "n8n-nodes-base.webhook",
   "typeVersion": 2.1,
   "position": [
    0,
    440
   ],
   "parameters": {
    "httpMethod": "POST",
    "path": "orden-terminada-traccion",
    "responseMode": "onReceived",
    "options": {}
   },
   "webhookId": "e574d4a5-1158-48f3-be6b-eb58eb8479ab"
  },
  {
   "id": "dae3c48f-8661-4a30-9101-7b8c8a33d2e0",
   "name": "Buscar la orden",
   "type": "n8n-nodes-base.dataTable",
   "typeVersion": 1.1,
   "position": [
    240,
    440
   ],
   "parameters": {
    "resource": "row",
    "operation": "get",
    "dataTableId": {
     "__rl": true,
     "mode": "id",
     "value": ""
    },
    "matchType": "allConditions",
    "returnAll": true,
    "filters": {
     "conditions": [
      {
       "keyName": "orden",
       "condition": "eq",
       "keyValue": "={{ String($json.body.orden) }}"
      }
     ]
    }
   }
  },
  {
   "id": "257da1d1-131e-4d7f-aaa7-bdac440ddb51",
   "name": "Avisar que está listo",
   "type": "n8n-nodes-base.telegram",
   "typeVersion": 1.2,
   "position": [
    480,
    440
   ],
   "parameters": {
    "resource": "message",
    "operation": "sendMessage",
    "chatId": "={{ $json.chat_id }}",
    "text": "={{ '¡Hola, ' + $json.nombre + '! Tu ' + $json.vehiculo + ' ya está listo para retirar (' + $json.trabajo + '). Te esperamos hasta las 19 h.' }}",
    "additionalFields": {
     "parse_mode": "HTML",
     "appendAttribution": false
    }
   },
   "credentials": {
    "telegramApi": {
     "id": "",
     "name": "Telegram (simulador)"
    }
   }
  },
  {
   "id": "a93ea7ec-e40b-4d27-bce7-c59be40ae9f3",
   "name": "Marcar como avisado",
   "type": "n8n-nodes-base.dataTable",
   "typeVersion": 1.1,
   "position": [
    720,
    440
   ],
   "parameters": {
    "resource": "row",
    "operation": "update",
    "dataTableId": {
     "__rl": true,
     "mode": "id",
     "value": ""
    },
    "columns": {
     "mappingMode": "defineBelow",
     "value": {
      "estado": "avisado: listo para retirar"
     },
     "matchingColumns": [],
     "schema": [
      {
       "id": "estado",
       "displayName": "estado",
       "required": false,
       "defaultMatch": false,
       "display": true,
       "type": "string",
       "canBeUsedToMatch": true
      }
     ]
    },
    "options": {},
    "filters": {
     "conditions": [
      {
       "keyName": "orden",
       "condition": "eq",
       "keyValue": "={{ $('Buscar la orden').item.json.orden }}"
      }
     ]
    }
   }
  }
 ],
 "connections": {
  "Mensaje al bot": {
   "main": [
    [
     {
      "node": "Leer el mensaje",
      "type": "main",
      "index": 0
     }
    ]
   ]
  },
  "Leer el mensaje": {
   "main": [
    [
     {
      "node": "¿Es /start?",
      "type": "main",
      "index": 0
     }
    ]
   ]
  },
  "¿Es /start?": {
   "main": [
    [
     {
      "node": "Bienvenida",
      "type": "main",
      "index": 0
     }
    ],
    [
     {
      "node": "La IA entiende el mensaje",
      "type": "main",
      "index": 0
     }
    ]
   ]
  },
  "Claude": {
   "ai_languageModel": [
    [
     {
      "node": "La IA entiende el mensaje",
      "type": "ai_languageModel",
      "index": 0
     }
    ]
   ]
  },
  "La IA entiende el mensaje": {
   "main": [
    [
     {
      "node": "Armar la respuesta",
      "type": "main",
      "index": 0
     }
    ]
   ]
  },
  "Armar la respuesta": {
   "main": [
    [
     {
      "node": "Según lo que pide",
      "type": "main",
      "index": 0
     }
    ]
   ]
  },
  "Según lo que pide": {
   "main": [
    [
     {
      "node": "Pedidos de turno",
      "type": "main",
      "index": 0
     }
    ],
    [
     {
      "node": "Buscar su orden",
      "type": "main",
      "index": 0
     }
    ],
    [
     {
      "node": "Respuesta al cliente",
      "type": "main",
      "index": 0
     }
    ]
   ]
  },
  "Pedidos de turno": {
   "main": [
    [
     {
      "node": "Aviso al taller",
      "type": "main",
      "index": 0
     }
    ]
   ]
  },
  "Aviso al taller": {
   "main": [
    [
     {
      "node": "Respuesta al cliente",
      "type": "main",
      "index": 0
     }
    ]
   ]
  },
  "Buscar su orden": {
   "main": [
    [
     {
      "node": "Estado de la orden",
      "type": "main",
      "index": 0
     }
    ]
   ]
  },
  "Estado de la orden": {
   "main": [
    [
     {
      "node": "Respuesta al cliente",
      "type": "main",
      "index": 0
     }
    ]
   ]
  },
  "Orden terminada": {
   "main": [
    [
     {
      "node": "Buscar la orden",
      "type": "main",
      "index": 0
     }
    ]
   ]
  },
  "Buscar la orden": {
   "main": [
    [
     {
      "node": "Avisar que está listo",
      "type": "main",
      "index": 0
     }
    ]
   ]
  },
  "Avisar que está listo": {
   "main": [
    [
     {
      "node": "Marcar como avisado",
      "type": "main",
      "index": 0
     }
    ]
   ]
  }
 },
 "settings": {
  "executionOrder": "v1",
  "timezone": "America/Argentina/Buenos_Aires",
  "saveManualExecutions": true
 }
}