{
  "name": "\ud83d\udd04 Sync Productos Supabase \u2192 Local (LISTO)",
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "minutes",
              "minutesInterval": 30
            }
          ]
        }
      },
      "id": "schedule-trigger",
      "name": "\u23f0 Cada 30 minutos",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        180,
        300
      ]
    },
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "sync-productos-manual",
        "responseMode": "lastNode",
        "options": {}
      },
      "id": "webhook-manual",
      "name": "\ud83d\udd17 Webhook Manual",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        180,
        500
      ]
    },
    {
      "parameters": {
        "operation": "getAll",
        "tableId": "products",
        "returnAll": true
      },
      "id": "fetch-supabase",
      "name": "\ud83d\udce5 Obtener Productos Supabase",
      "type": "n8n-nodes-base.supabase",
      "typeVersion": 1,
      "position": [
        460,
        400
      ],
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// Transformar productos de Supabase al formato local\nconst productos = [];\n\nfor (const item of $input.all()) {\n  const p = item.json;\n  \n  // Solo productos activos\n  if (p.is_active === false) continue;\n  \n  productos.push({\n    json: {\n      supabase_id: p.id || null,\n      name: p.name || 'Sin nombre',\n      slug: p.slug || null,\n      description: p.description || null,\n      price: parseFloat(p.price) || 0,\n      discount_price: p.discount_price ? parseFloat(p.discount_price) : null,\n      category_name: p.category?.name || p.category_name || null,\n      category_id: p.category_id || null,\n      main_image_url: p.main_image_url || p.image_url || null,\n      stock: parseInt(p.stock) || 100,\n      is_active: p.is_active !== false,\n      is_featured: p.is_featured === true,\n      unit: p.unit || 'kg',\n      min_quantity: p.min_quantity || 1,\n      has_variants: p.has_variants || false,\n      synced_from_supabase_at: new Date().toISOString()\n    }\n  });\n}\n\nconsole.log(`Transformados ${productos.length} productos`);\nreturn productos;"
      },
      "id": "transform-data",
      "name": "\ud83d\udd04 Transformar Datos",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        680,
        400
      ]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "DELETE FROM productos_tienda; SELECT 1 as limpiado;",
        "options": {}
      },
      "id": "clear-table",
      "name": "\ud83d\uddd1\ufe0f Limpiar Tabla Local",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.5,
      "position": [
        680,
        600
      ],
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "mode": "combine",
        "combinationMode": "multiplex",
        "options": {}
      },
      "id": "merge-node",
      "name": "\ud83d\udd00 Esperar Limpieza",
      "type": "n8n-nodes-base.merge",
      "typeVersion": 3,
      "position": [
        900,
        400
      ]
    },
    {
      "parameters": {
        "operation": "insert",
        "schema": {
          "value": "public"
        },
        "table": {
          "value": "productos_tienda"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "values": [
            {
              "column": "supabase_id",
              "value": "={{ $json.supabase_id }}"
            },
            {
              "column": "name",
              "value": "={{ $json.name }}"
            },
            {
              "column": "slug",
              "value": "={{ $json.slug }}"
            },
            {
              "column": "description",
              "value": "={{ $json.description }}"
            },
            {
              "column": "price",
              "value": "={{ $json.price }}"
            },
            {
              "column": "discount_price",
              "value": "={{ $json.discount_price }}"
            },
            {
              "column": "category_name",
              "value": "={{ $json.category_name }}"
            },
            {
              "column": "category_id",
              "value": "={{ $json.category_id }}"
            },
            {
              "column": "main_image_url",
              "value": "={{ $json.main_image_url }}"
            },
            {
              "column": "stock",
              "value": "={{ $json.stock }}"
            },
            {
              "column": "is_active",
              "value": "={{ $json.is_active }}"
            },
            {
              "column": "is_featured",
              "value": "={{ $json.is_featured }}"
            },
            {
              "column": "synced_from_supabase_at",
              "value": "={{ $json.synced_from_supabase_at }}"
            }
          ]
        },
        "options": {}
      },
      "id": "insert-products",
      "name": "\ud83d\udcbe Insertar Productos",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.5,
      "position": [
        1120,
        400
      ],
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "SELECT \n  COUNT(*) as total_productos,\n  COUNT(CASE WHEN is_active = true THEN 1 END) as activos,\n  COUNT(CASE WHEN discount_price IS NOT NULL THEN 1 END) as con_descuento,\n  MAX(synced_from_supabase_at) as ultima_sync\nFROM productos_tienda;",
        "options": {}
      },
      "id": "verify-count",
      "name": "\u2705 Verificar Sync",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.5,
      "position": [
        1340,
        400
      ],
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const stats = $input.first().json;\nconst now = new Date().toLocaleString('es-CO', { timeZone: 'America/Bogota' });\n\nreturn [{\n  json: {\n    success: true,\n    mensaje: `\u2705 Sincronizaci\u00f3n completada`,\n    timestamp: now,\n    estadisticas: {\n      total_productos: parseInt(stats.total_productos) || 0,\n      activos: parseInt(stats.activos) || 0,\n      con_descuento: parseInt(stats.con_descuento) || 0,\n      ultima_sync: stats.ultima_sync\n    }\n  }\n}];"
      },
      "id": "format-response",
      "name": "\ud83d\udcca Formatear Respuesta",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1560,
        400
      ]
    }
  ],
  "connections": {
    "\u23f0 Cada 30 minutos": {
      "main": [
        [
          {
            "node": "\ud83d\udce5 Obtener Productos Supabase",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udd17 Webhook Manual": {
      "main": [
        [
          {
            "node": "\ud83d\udce5 Obtener Productos Supabase",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udce5 Obtener Productos Supabase": {
      "main": [
        [
          {
            "node": "\ud83d\udd04 Transformar Datos",
            "type": "main",
            "index": 0
          },
          {
            "node": "\ud83d\uddd1\ufe0f Limpiar Tabla Local",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udd04 Transformar Datos": {
      "main": [
        [
          {
            "node": "\ud83d\udd00 Esperar Limpieza",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\uddd1\ufe0f Limpiar Tabla Local": {
      "main": [
        [
          {
            "node": "\ud83d\udd00 Esperar Limpieza",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "\ud83d\udd00 Esperar Limpieza": {
      "main": [
        [
          {
            "node": "\ud83d\udcbe Insertar Productos",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udcbe Insertar Productos": {
      "main": [
        [
          {
            "node": "\u2705 Verificar Sync",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\u2705 Verificar Sync": {
      "main": [
        [
          {
            "node": "\ud83d\udcca Formatear Respuesta",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": true,
  "settings": {
    "executionOrder": "v1"
  },
  "tags": [
    {
      "name": "Sync",
      "createdAt": "2026-01-07T00:00:00.000Z",
      "updatedAt": "2026-01-07T00:00:00.000Z"
    },
    {
      "name": "Productos",
      "createdAt": "2026-01-07T00:00:00.000Z",
      "updatedAt": "2026-01-07T00:00:00.000Z"
    }
  ],
  "meta": {
    "templateCredsSetupCompleted": true
  }
}