{
  "name": "KALELE_TOOLS",
  "nodes": [
    {
      "parameters": {
        "inputSource": "passthrough"
      },
      "type": "n8n-nodes-base.executeWorkflowTrigger",
      "typeVersion": 1.1,
      "position": [
        -400,
        320
      ],
      "id": "trg-tools-001",
      "name": "When Executed by Another Workflow"
    },
    {
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "caseSensitive": false,
                  "leftValue": "",
                  "typeValidation": "loose",
                  "version": 2
                },
                "conditions": [
                  {
                    "id": "r-buscar",
                    "leftValue": "={{ $json.action }}",
                    "rightValue": "buscar_producto",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "buscar"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": false,
                  "leftValue": "",
                  "typeValidation": "loose",
                  "version": 2
                },
                "conditions": [
                  {
                    "id": "r-sim",
                    "leftValue": "={{ $json.action }}",
                    "rightValue": "productos_similares",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "similares"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": false,
                  "leftValue": "",
                  "typeValidation": "loose",
                  "version": 2
                },
                "conditions": [
                  {
                    "id": "r-der",
                    "leftValue": "={{ $json.action }}",
                    "rightValue": "derivar_encargada",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "derivar"
            }
          ]
        },
        "options": {
          "fallbackOutput": "extra",
          "renameFallbackOutput": "buscar_fallback"
        }
      },
      "type": "n8n-nodes-base.switch",
      "typeVersion": 3.2,
      "position": [
        -160,
        320
      ],
      "id": "router-tools-001",
      "name": "Router"
    },
    {
      "parameters": {
        "jsCode": "// BUSCAR: recibe { action, query }. Limpia conectores, detecta talla/color y arma el search.\nconst trg = $input.first().json || {};\nconst raw = (trg.query || '').toString().trim();\nconst lower = raw.toLowerCase();\n\nconst tallaMatch = lower.match(/\\b(xxl|xl|xs|[sml])\\b/i);\nconst talla = tallaMatch ? tallaMatch[1].toLowerCase() : '';\n\nconst coloresConocidos = ['negro','blanco','rojo','azul','verde','amarillo','rosa','rosado','morado','lila','beige','crema','cafe','caf\u00e9','marron','marr\u00f3n','gris','dorado','plateado','naranja','celeste','turquesa','vino','nude','floral','multi'];\nlet color = '';\nfor (const c of coloresConocidos) { if (lower.includes(c)) { color = c; break; } }\n\n// Quitamos talla, palabras de relleno y conectores para que el search de WooCommerce (que es tipo AND) no falle.\nconst stop = new Set(['talla','size','con','de','del','la','el','los','las','un','una','unos','unas','para','en','y','o','que','tienen','tiene','tenes','ten\u00e9s','hay','busco','quiero','color','un','algun','alg\u00fan']);\nconst searchQuery = raw\n  .replace(/\\b(xxl|xl|xs|[sml])\\b/ig, ' ')\n  .split(/\\s+/)\n  .filter(w => w && !stop.has(w.toLowerCase()))\n  .join(' ')\n  .trim();\n\nreturn [{ json: { query_original: raw, search: searchQuery, talla, color } }];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        120,
        80
      ],
      "id": "code-parse-buscar",
      "name": "Parsear buscar"
    },
    {
      "parameters": {
        "url": "https://kaleleboutique.com/wp-json/wc/store/v1/products",
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "search",
              "value": "={{ $json.search }}"
            },
            {
              "name": "per_page",
              "value": "20"
            },
            {
              "name": "orderby",
              "value": "popularity"
            }
          ]
        },
        "options": {
          "response": {
            "response": {
              "neverError": true
            }
          },
          "timeout": 15000
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        360,
        80
      ],
      "id": "http-buscar-001",
      "name": "WooCommerce Search"
    },
    {
      "parameters": {
        "jsCode": "// FIX CLAVE: el nodo HTTP Request entrega un ITEM por producto (parte el array de WooCommerce).\n// Por eso usamos $input.all(), no $input.first(). Antes esto devolv\u00eda siempre 'no_encontrado'.\nconst parsed = $('Parsear buscar').first().json;\nconst tallaPedida = (parsed.talla || '').toLowerCase();\nconst colorPedido = (parsed.color || '').toLowerCase();\nconst query = parsed.query_original || '';\n\nfunction extraerTallas(attrs) {\n  const a = (attrs || []).find(x => (x.name || '').toLowerCase() === 'talla');\n  return a ? a.terms.map(t => t.name.toLowerCase()) : [];\n}\nfunction extraerColores(attrs) {\n  const a = (attrs || []).find(x => (x.name || '').toLowerCase() === 'color');\n  return a ? a.terms.map(t => t.name.toLowerCase()) : [];\n}\nfunction limpiarPrecio(p) {\n  if (!p || !p.price) return '';\n  const symbol = p.currency_prefix || '\u20a1';\n  const minor = parseInt(p.currency_minor_unit || 0, 10);\n  let n = parseInt(p.price, 10);\n  if (isNaN(n)) return p.price;\n  if (minor > 0) n = n / Math.pow(10, minor);\n  return symbol + n.toLocaleString('es-CR');\n}\n\nlet __in = $input.all().map(i => i.json);\nlet productos = (__in.length === 1 && Array.isArray(__in[0])) ? __in[0] : __in;\nproductos = productos.filter(p => p && p.id);\n\nif (!productos.length) {\n  return [{ json: { status: 'no_encontrado', query, mensaje: 'No encontr\u00e9 ese producto en kaleleboutique.com. Prob\u00e1 otra b\u00fasqueda u ofrec\u00e9 alternativas con productos_similares.' } }];\n}\n\nconst mapeados = productos.map(p => {\n  const tallas = extraerTallas(p.attributes);\n  const colores = extraerColores(p.attributes);\n  const stockOk = p.is_in_stock && p.is_purchasable;\n  let disponibilidad;\n  if (!stockOk) disponibilidad = 'agotado';\n  else if (tallaPedida && tallas.length && !tallas.includes(tallaPedida)) disponibilidad = 'talla_no_disponible';\n  else if (colorPedido && colores.length && !colores.includes(colorPedido)) disponibilidad = 'color_no_disponible';\n  else disponibilidad = 'disponible';\n  return {\n    id: p.id,\n    sku: p.sku || '',\n    nombre: p.name,\n    categoria: (p.categories || []).map(c => c.name).join(', '),\n    precio: limpiarPrecio(p.prices),\n    en_oferta: p.on_sale === true,\n    tallas_disponibles: tallas,\n    colores_disponibles: colores,\n    foto: (p.images && p.images[0]) ? p.images[0].src : '',\n    link: p.permalink,\n    disponibilidad\n  };\n});\n\n// Si pidi\u00f3 color, priorizamos el producto que s\u00ed lo tiene como producto principal.\nif (colorPedido) {\n  mapeados.sort((a, b) => (a.colores_disponibles.includes(colorPedido) ? -1 : 0) - (b.colores_disponibles.includes(colorPedido) ? -1 : 0));\n}\n\nreturn [{\n  json: {\n    status: 'encontrado',\n    query,\n    talla_pedida: tallaPedida,\n    color_pedido: colorPedido,\n    producto: mapeados[0],\n    coincidencias_adicionales: mapeados.slice(1, 6),\n    total_resultados: mapeados.length\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        600,
        80
      ],
      "id": "code-format-buscar",
      "name": "Formatear resultado"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "out-buscar-1",
              "name": "respuesta",
              "value": "={{ JSON.stringify($json) }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        840,
        80
      ],
      "id": "set-buscar-001",
      "name": "Salida buscar"
    },
    {
      "parameters": {
        "jsCode": "// SIMILARES: recibe { action, query }. Parsea categor\u00eda / talla / color.\nconst trg = $input.first().json || {};\nconst raw = (trg.query || '').toString().trim();\nconst lower = raw.toLowerCase();\n\nconst mapaCategorias = {\n  'vestido gala': 'Vestidos Gala', 'vestidos gala': 'Vestidos Gala', 'gala': 'Vestidos Gala',\n  'vestido': 'Vestidos', 'vestidos': 'Vestidos',\n  'top': 'Tops', 'tops': 'Tops',\n  'blusa': 'Blusas', 'blusas': 'Blusas',\n  'pantalon': 'Pantalones', 'pantalones': 'Pantalones', 'pantal\u00f3n': 'Pantalones',\n  'falda short': 'Faldas Shorts', 'faldas shorts': 'Faldas Shorts',\n  'falda': 'Faldas', 'faldas': 'Faldas',\n  'short': 'Shorts', 'shorts': 'Shorts',\n  'enterizo': 'Enterizos', 'enterizos': 'Enterizos', 'mono': 'Enterizos',\n  'abrigo': 'Abrigos', 'abrigos': 'Abrigos', 'chaqueta': 'Abrigos', 'jacket': 'Abrigos',\n  'blazer': 'Blazers', 'blazers': 'Blazers',\n  'set': 'Sets', 'sets': 'Sets', 'conjunto': 'Sets',\n  'zapato': 'Zapatos', 'zapatos': 'Zapatos',\n  'bota': 'Botas', 'botas': 'Botas',\n  'bailarina': 'Bailarinas', 'bailarinas': 'Bailarinas',\n  'plataforma': 'Plataformas', 'plataformas': 'Plataformas', 'tacon': 'Plataformas', 'tac\u00f3n': 'Plataformas',\n  'accesorio': 'Accesorios', 'accesorios': 'Accesorios',\n  'chaleco': 'Chaleco',\n  'sale': 'SALE', 'oferta': 'SALE', 'descuento': 'SALE'\n};\nlet categoriaNombre = '';\nfor (const k of Object.keys(mapaCategorias).sort((a,b)=>b.length-a.length)) {\n  if (lower.includes(k)) { categoriaNombre = mapaCategorias[k]; break; }\n}\n\nconst tallaMatch = lower.match(/\\b(xxl|xl|xs|[sml])\\b/i);\nconst talla = tallaMatch ? tallaMatch[1].toLowerCase() : '';\n\nconst coloresConocidos = ['negro','blanco','rojo','azul','verde','amarillo','rosa','rosado','morado','lila','beige','crema','cafe','caf\u00e9','marron','marr\u00f3n','gris','dorado','plateado','naranja','celeste','turquesa','vino','nude','floral','multi'];\nlet color = '';\nfor (const c of coloresConocidos) { if (lower.includes(c)) { color = c; break; } }\n\nreturn [{ json: { query_original: raw, categoria: categoriaNombre, color, talla } }];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        120,
        320
      ],
      "id": "code-parse-sim",
      "name": "Parsear similares"
    },
    {
      "parameters": {
        "url": "https://kaleleboutique.com/wp-json/wc/store/v1/products/categories",
        "options": {
          "response": {
            "response": {
              "neverError": true
            }
          },
          "timeout": 15000
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        360,
        320
      ],
      "id": "http-cats-001",
      "name": "Listar categor\u00edas"
    },
    {
      "parameters": {
        "jsCode": "// Resuelve el ID de categor\u00eda. Usamos $input.all() porque el HTTP node parte el array.\nconst parsed = $('Parsear similares').first().json;\nconst nombreCat = (parsed.categoria || '').toLowerCase();\nlet __cin = $input.all().map(i => i.json);\nlet cats = (__cin.length === 1 && Array.isArray(__cin[0])) ? __cin[0] : __cin;\ncats = cats.filter(c => c && c.id);\n\nlet categoryId = '';\nif (nombreCat && cats.length) {\n  const match = cats.find(c => (c.name || '').toLowerCase() === nombreCat)\n             || cats.find(c => (c.name || '').toLowerCase().includes(nombreCat));\n  if (match) categoryId = match.id;\n}\n\nreturn [{\n  json: {\n    category: categoryId,\n    talla: (parsed.talla || '').toLowerCase(),\n    color: (parsed.color || '').toLowerCase(),\n    query_original: parsed.query_original\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        600,
        320
      ],
      "id": "code-resolve-sim",
      "name": "Resolver categor\u00eda"
    },
    {
      "parameters": {
        "url": "https://kaleleboutique.com/wp-json/wc/store/v1/products",
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "category",
              "value": "={{ $json.category }}"
            },
            {
              "name": "stock_status",
              "value": "instock"
            },
            {
              "name": "per_page",
              "value": "20"
            },
            {
              "name": "orderby",
              "value": "popularity"
            }
          ]
        },
        "options": {
          "response": {
            "response": {
              "neverError": true
            }
          },
          "timeout": 15000
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        840,
        320
      ],
      "id": "http-sim-001",
      "name": "WooCommerce Similares"
    },
    {
      "parameters": {
        "jsCode": "// FIX: $input.all() en vez de $input.first(). Filtra por color/talla del lado del c\u00f3digo\n// (el search ya no usa color, porque el color casi nunca est\u00e1 en el t\u00edtulo).\nconst parsed = $('Parsear similares').first().json;\nconst tallaPedida = (parsed.talla || '').toLowerCase();\nconst colorPedido = (parsed.color || '').toLowerCase();\n\nfunction extraerTallas(attrs) {\n  const a = (attrs || []).find(x => (x.name || '').toLowerCase() === 'talla');\n  return a ? a.terms.map(t => t.name.toLowerCase()) : [];\n}\nfunction extraerColores(attrs) {\n  const a = (attrs || []).find(x => (x.name || '').toLowerCase() === 'color');\n  return a ? a.terms.map(t => t.name.toLowerCase()) : [];\n}\nfunction limpiarPrecio(p) {\n  if (!p || !p.price) return '';\n  const symbol = p.currency_prefix || '\u20a1';\n  const minor = parseInt(p.currency_minor_unit || 0, 10);\n  let n = parseInt(p.price, 10);\n  if (isNaN(n)) return p.price;\n  if (minor > 0) n = n / Math.pow(10, minor);\n  return symbol + n.toLocaleString('es-CR');\n}\n\nlet __in = $input.all().map(i => i.json);\nlet productos = (__in.length === 1 && Array.isArray(__in[0])) ? __in[0] : __in;\nproductos = productos.filter(p => p && p.id);\n\nconst candidatos = productos\n  .filter(p => p.is_in_stock && p.is_purchasable)\n  .map(p => ({\n    id: p.id,\n    nombre: p.name,\n    precio: limpiarPrecio(p.prices),\n    categoria: (p.categories || []).map(c => c.name).join(', '),\n    tallas: extraerTallas(p.attributes),\n    colores: extraerColores(p.attributes),\n    foto: (p.images && p.images[0]) ? p.images[0].src : '',\n    link: p.permalink\n  }))\n  .filter(p => !tallaPedida || p.tallas.length === 0 || p.tallas.includes(tallaPedida))\n  .filter(p => !colorPedido || p.colores.length === 0 || p.colores.includes(colorPedido))\n  .slice(0, 5);\n\nreturn [{\n  json: {\n    status: candidatos.length > 0 ? 'ok' : 'sin_similares',\n    query: parsed.query_original,\n    total: candidatos.length,\n    similares: candidatos\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1080,
        320
      ],
      "id": "code-format-sim",
      "name": "Formatear similares"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "out-sim-1",
              "name": "respuesta",
              "value": "={{ JSON.stringify($json) }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        1320,
        320
      ],
      "id": "set-sim-001",
      "name": "Salida similares"
    },
    {
      "parameters": {
        "jsCode": "// DERIVAR: normaliza la entrada.\nconst trg = $input.first().json || {};\nreturn [{\n  json: {\n    subscriber_id: trg.subscriber_id ? String(trg.subscriber_id) : '0',\n    motivo: trg.motivo || 'derivaci\u00f3n general',\n    resumen: trg.resumen || 'sin resumen'\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        120,
        560
      ],
      "id": "code-norm-der",
      "name": "Normalizar input"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.manychat.com/fb/subscriber/addTag",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "keypair",
        "bodyParameters": {
          "parameters": [
            {
              "name": "subscriber_id",
              "value": "={{ Number($json.subscriber_id) }}"
            },
            {
              "name": "tag_name",
              "value": "ATENCION_HUMANA"
            }
          ]
        },
        "options": {
          "response": {
            "response": {
              "neverError": true
            }
          },
          "timeout": 15000
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        360,
        560
      ],
      "id": "http-der-001",
      "name": "Etiquetar en ManyChat",
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "der-out-1",
              "name": "respuesta",
              "value": "Clienta derivada a encargada. Tag ATENCION_HUMANA aplicado en ManyChat. Decile a la clienta: 'Te voy a comunicar con una encargada para ayudarte mejor \ud83d\ude0a'.",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        600,
        560
      ],
      "id": "set-der-001",
      "name": "Salida derivar"
    }
  ],
  "connections": {
    "When Executed by Another Workflow": {
      "main": [
        [
          {
            "node": "Router",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Router": {
      "main": [
        [
          {
            "node": "Parsear buscar",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Parsear similares",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Normalizar input",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Parsear buscar",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parsear buscar": {
      "main": [
        [
          {
            "node": "WooCommerce Search",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "WooCommerce Search": {
      "main": [
        [
          {
            "node": "Formatear resultado",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Formatear resultado": {
      "main": [
        [
          {
            "node": "Salida buscar",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parsear similares": {
      "main": [
        [
          {
            "node": "Listar categor\u00edas",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Listar categor\u00edas": {
      "main": [
        [
          {
            "node": "Resolver categor\u00eda",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Resolver categor\u00eda": {
      "main": [
        [
          {
            "node": "WooCommerce Similares",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "WooCommerce Similares": {
      "main": [
        [
          {
            "node": "Formatear similares",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Formatear similares": {
      "main": [
        [
          {
            "node": "Salida similares",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalizar input": {
      "main": [
        [
          {
            "node": "Etiquetar en ManyChat",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Etiquetar en ManyChat": {
      "main": [
        [
          {
            "node": "Salida derivar",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "tags": []
}