{
  "name": "An\u00e1lise OMIE - Melhor Fixo Auto",
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "triggerAtHour": 6
            }
          ]
        }
      },
      "id": "node-schedule",
      "name": "Diariamente",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        0,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "// Gera a lista de URLs OMIE para os \u00faltimos 30 dias\nconst dias = 30;\nconst hoje = new Date();\nconst items = [];\n\nfor (let i = dias; i >= 0; i--) {\n  const d = new Date(hoje);\n  d.setDate(d.getDate() - i);\n  const ano = d.getFullYear();\n  const mes = String(d.getMonth() + 1).padStart(2, '0');\n  const dia = String(d.getDate()).padStart(2, '0');\n  items.push({\n    json: {\n      url: `https://www.omie.es/en/file-download?parents=marginalpdbcpt&filename=marginalpdbcpt_${ano}${mes}${dia}.1`\n    }\n  });\n}\n\nreturn items;"
      },
      "id": "node-gerar-urls",
      "name": "Gerar URLs OMIE",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        220,
        300
      ]
    },
    {
      "parameters": {
        "url": "={{ $json.url }}",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "User-Agent",
              "value": "Mozilla/5.0"
            },
            {
              "name": "Referer",
              "value": "https://www.omie.es/"
            }
          ]
        },
        "options": {
          "allowUnauthorizedCerts": true,
          "response": {
            "response": {
              "responseFormat": "text"
            }
          },
          "timeout": 15000
        }
      },
      "id": "node-http-omie",
      "name": "HTTP Request OMIE",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        440,
        300
      ],
      "continueOnFail": true
    },
    {
      "parameters": {
        "jsCode": "// Agrega os 31 ficheiros OMIE num \u00fanico item com a m\u00e9dia\nconst todosPrecos = [];\n\nfor (const item of $input.all()) {\n  const texto = item.json.data;\n  if (!texto || typeof texto !== 'string') continue;\n  for (const linha of texto.split('\\n')) {\n    const partes = linha.trim().split(';');\n    // Formato OMIE: ANO;MES;DIA;HORA;PRECO_PT;PRECO_ES\n    if (partes.length >= 5 && /^\\d{4}$/.test(partes[0].trim())) {\n      const preco = parseFloat(partes[4].replace(',', '.'));\n      if (!isNaN(preco)) todosPrecos.push(preco);\n    }\n  }\n}\n\nif (todosPrecos.length === 0) {\n  return [{ json: { erro: 'Sem dados OMIE dispon\u00edveis' } }];\n}\n\nconst media = todosPrecos.reduce((a, b) => a + b, 0) / todosPrecos.length;\n\nreturn [{\n  json: {\n    media_omie_mwh: media,\n    num_precos: todosPrecos.length\n  }\n}];"
      },
      "id": "node-agregar-omie",
      "name": "Agregar OMIE",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        660,
        300
      ]
    },
    {
      "parameters": {
        "url": "https://huggingface.co/spaces/tiagofelicia/simulador-tarifarios-eletricidade/resolve/main/data/csv/Tarifarios_fixos.csv",
        "options": {
          "response": {
            "response": {
              "responseFormat": "text"
            }
          },
          "timeout": 30000
        }
      },
      "id": "node-http-csv",
      "name": "HTTP Request CSV Tarif\u00e1rios",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        880,
        300
      ],
      "continueOnFail": false
    },
    {
      "parameters": {
        "jsCode": "// \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557\n// \u2551                      \u2699\ufe0f  CONFIGURA\u00c7\u00c3O                            \u2551\n// \u2551              S\u00f3 precisas de editar esta sec\u00e7\u00e3o                   \u2551\n// \u255a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255d\n\nconst CONFIG = {\n\n  // \u2500\u2500 Consumo e contrato \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n  consumo_kwh:  700,    // kWh/m\u00eas\n  dias:          30,    // dias do per\u00edodo de fatura\u00e7\u00e3o\n  potencia_kva:  6.90,  // kVA contratados (filtra tarif\u00e1rios do CSV)\n  ciclo: \"Simples\",     // \"Simples\" | \"Bi-hor\u00e1rio\" | \"Tri-hor\u00e1rio\"\n\n  // \u2500\u2500 Tarif\u00e1rio FIXO \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n  // null  \u2192 escolhe automaticamente o mais barato do CSV do Tiago Fel\u00edcia\n  // {...} \u2192 usa estes valores directamente (ignora o CSV)\n  //\n  // ATEN\u00c7\u00c3O: os valores do CSV j\u00e1 incluem TAR (tar_incluida = true na maioria).\n  // Se colocares valores manuais, usa os valores FINAIS da tua fatura\n  // (ou seja, com TAR e TSE j\u00e1 inclu\u00eddas), e coloca tar_ja_incluida: true.\n  //\n  // Exemplo manual:\n  // fixo_manual: {\n  //   nome:           \"G9 | Vantagem+\",\n  //   energia_kwh:    0.1348,  // valor bruto do CSV (inclui TAR + TSE)\n  //   potencia_dia:   0.4498,  // valor bruto do CSV (inclui TAR)\n  //   tar_en_incluida:  true,\n  //   tar_pot_incluida: true,\n  //   tse_incluida:     true,\n  // },\n  fixo_manual: null,\n\n  // \u2500\u2500 Filtros para escolha autom\u00e1tica do melhor fixo \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n  // (irrelevante se fixo_manual estiver preenchido)\n  // Usa string vazia \"\" para ignorar esse filtro.\n  filtros: {\n    segmento:  \"Residencial\",     // \"Residencial\" | \"Empresarial\" | \"\"\n    faturacao: \"eletr\u00f3nica\",      // palavra parcial (ex: \"eletr\u00f3nica\", \"papel\")\n    pagamento: \"D\u00e9bito\",          // palavra parcial (ex: \"D\u00e9bito\", \"Multibanco\")\n  },\n\n  // \u2500\u2500 Tarif\u00e1rio INDEXADO (OMIE) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n  // Valores espec\u00edficos do contrato indexado.\n  // A TAR e TSE s\u00e3o SEMPRE adicionadas por cima no indexado (n\u00e3o est\u00e3o inclu\u00eddas).\n  indexado: {\n    nome:       \"G9 | Smart Index\",\n    // Margem do comercializador em \u20ac/kWh (G9_CGS + G9_AC do contrato)\n    margem_kwh: 0.0150,\n    // Fator de perdas de rede (G9_FA \u2014 tipicamente entre 1.0 e 1.20)\n    // Verifica no teu contrato. G9 usa ~1.16 no per\u00edodo de inverno.\n    // Se n\u00e3o souberes, usa 1.0 para estimativa conservadora.\n    fator_perdas: 1.0,\n  },\n\n  // \u2500\u2500 Tarifas reguladas ERSE 2026 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n  // Atualizar anualmente em Janeiro.\n  // Fonte: https://www.tiagofelicia.pt/tarifas-acesso-redes.html\n  tar: {\n    energia_kwh:  0.0607,   // \u20ac/kWh \u2014 tarifa simples BTN\n    potencia_dia: 0.3436,   // \u20ac/dia \u2014 para 6.9 kVA (alterar se mudares de pot\u00eancia)\n  },\n\n};\n\n// \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557\n// \u2551          N\u00c3O \u00c9 NECESS\u00c1RIO EDITAR ABAIXO DAQUI                   \u2551\n// \u255a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255d\n\n// Constantes reguladas ERSE 2026 (n\u00e3o mudam a meio do ano)\nconst TSE = 0.0026;  // \u20ac/kWh \u2014 financiamento Tarifa Social Electricidade\n\nconst r4 = (v) => Math.round(v * 10000) / 10000;\nconst r2 = (v) => Math.round(v * 100) / 100;\n\n// \u2500\u2500 Normaliza\u00e7\u00e3o de texto para compara\u00e7\u00f5es \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nconst norm = (s) => (s || '')\n  .toLowerCase()\n  .normalize('NFD')\n  .replace(/[\\u0300-\\u036f]/g, '')\n  .trim();\n\n// \u2500\u2500 Parser CSV robusto (lida com campos entre aspas) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nfunction parseCSVLine(linha) {\n  const cols = [];\n  let cur = '';\n  let inQ = false;\n  for (const ch of linha) {\n    if (ch === '\"') { inQ = !inQ; }\n    else if (ch === ',' && !inQ) { cols.push(cur.trim()); cur = ''; }\n    else { cur += ch; }\n  }\n  cols.push(cur.trim());\n  return cols;\n}\n\nconst parseBool = (v) => {\n  const s = (v || '').toLowerCase().trim();\n  return s === 'true' || s === 'sim' || s === '1';\n};\nconst parseNum = (v) => parseFloat((v || '0').replace(',', '.')) || 0;\n\n// \u2500\u2500 Leitura dos dados dos n\u00f3s anteriores \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nconst omieData = $('Agregar OMIE').first().json;\nif (omieData.erro) {\n  return [{ json: { erro: omieData.erro } }];\n}\n\nconst mediaOmie_MWh = omieData.media_omie_mwh; // \u20ac/MWh\nconst mediaOmie_kWh = mediaOmie_MWh / 1000;    // \u20ac/kWh\nconst csvTexto = $input.first().json.data;\n\n// \u2500\u2500 Parse do CSV e c\u00e1lculo do melhor fixo \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// L\u00f3gica id\u00eantica ao simulador do Tiago Fel\u00edcia (calculos.js):\n//\n// 1. L\u00ea preco_energia_simples e preco_potencia_dia do CSV (valores brutos)\n// 2. Se tar_incluida_energia=true \u2192 energia_comercial = bruto - TAR_en\n//    Se tar_incluida_energia=false \u2192 energia_comercial = bruto\n// 3. energia_final = energia_comercial + TAR_en + (tse_incluida ? 0 : TSE)\n// 4. Mesmo processo para pot\u00eancia\n// 5. Custo = energia_final * consumo + potencia_final * dias\n//\nfunction obterTarifarios(csvTexto) {\n  const linhas = csvTexto.split('\\n').map(l => l.trim()).filter(Boolean);\n  if (linhas.length < 2) throw new Error('CSV vazio ou inv\u00e1lido');\n\n  // Mapear cabe\u00e7alho \u2192 \u00edndice de coluna\n  const cab = parseCSVLine(linhas[0]).map(c => c.replace(/\"/g, '').trim().toLowerCase());\n  const col = (nome) => cab.findIndex(c => c.includes(nome.toLowerCase()));\n\n  // \u00cdndices das colunas relevantes (nomes do CSV do Tiago Fel\u00edcia)\n  const C = {\n    comercializador: col('comercializador'),\n    nome:            col('nome'),\n    tipo:            col('tipo'),\n    ciclo:           col('opcao_horaria'),\n    potKva:          col('potencia_kva'),\n    energia:         col('preco_energia_simples'),\n    potDia:          col('preco_potencia_dia'),\n    tarEnIncl:       col('tar_incluida_energia'),\n    tarPotIncl:      col('tar_incluida_potencia'),\n    tseIncl:         col('financiamento_tse'),\n    segmento:        col('segmento'),\n    faturacao:       col('faturacao'),\n    pagamento:       col('pagamento'),\n    descFatura:      col('desconto_fatura'),\n  };\n\n  const cicloChave = norm(CONFIG.ciclo).split('-')[0].split(' ')[0]; // \"simples\", \"bi\", \"tri\"\n\n  const fixos = [];\n\n  for (let i = 1; i < linhas.length; i++) {\n    const cols = parseCSVLine(linhas[i]);\n    if (cols.length < 10) continue;\n\n    const tipo    = (cols[C.tipo]    || '').replace(/\"/g, '').trim();\n    const ciclo   = norm(cols[C.ciclo]   || '');\n    const potKva  = parseNum(cols[C.potKva]);\n    const segmento  = norm(cols[C.segmento]  || '');\n    const faturacao = norm(cols[C.faturacao] || '');\n    const pagamento = norm(cols[C.pagamento] || '');\n\n    // \u2500\u2500 Filtros obrigat\u00f3rios \u2500\u2500\n    if (norm(tipo) !== 'fixo') continue;\n    if (Math.abs(potKva - CONFIG.potencia_kva) > 0.1) continue;\n    if (!ciclo.includes(cicloChave)) continue;\n\n    // \u2500\u2500 Filtros opcionais \u2500\u2500\n    const f = CONFIG.filtros;\n    if (f.segmento === 'Residencial' && !segmento.includes('domestico')) continue;\n    if (f.segmento === 'Empresarial' && !segmento.includes('nao domestico') && !segmento.includes('nao-domestico')) continue;\n    if (f.faturacao && !faturacao.includes(norm(f.faturacao))) continue;\n    if (f.pagamento && !pagamento.includes(norm(f.pagamento))) continue;\n\n    // \u2500\u2500 Leitura dos pre\u00e7os brutos \u2500\u2500\n    const energiaBruta = parseNum(cols[C.energia]);\n    const potDiaBruta  = parseNum(cols[C.potDia]);\n    if (energiaBruta <= 0 || potDiaBruta <= 0) continue;\n\n    const tarEnIncl  = parseBool(cols[C.tarEnIncl]);\n    const tarPotIncl = parseBool(cols[C.tarPotIncl]);\n    const tseIncl    = parseBool(cols[C.tseIncl]);\n\n    // \u2500\u2500 Normaliza\u00e7\u00e3o exacta (igual ao simulador) \u2500\u2500\n    // Extrai componente comercial (sem TAR)\n    const energiaComercial = tarEnIncl\n      ? energiaBruta - CONFIG.tar.energia_kwh\n      : energiaBruta;\n\n    const potComercial = tarPotIncl\n      ? potDiaBruta - CONFIG.tar.potencia_dia\n      : potDiaBruta;\n\n    // Re-adiciona TAR regulada + TSE se n\u00e3o inclu\u00edda\n    const energiaFinal = energiaComercial + CONFIG.tar.energia_kwh + (tseIncl ? 0 : TSE);\n    const potFinal     = potComercial     + CONFIG.tar.potencia_dia;\n\n    // Desconto de fatura (se existir)\n    const descFatura = parseNum(cols[C.descFatura] || '0');\n    const descTotal  = descFatura * (CONFIG.dias / 30); // proporcional\n\n    const custoEnergia = energiaFinal * CONFIG.consumo_kwh;\n    const custoPot     = potFinal     * CONFIG.dias;\n    const custoTotal   = custoEnergia + custoPot - descTotal;\n\n    fixos.push({\n      comercializador:  (cols[C.comercializador] || '').replace(/\"/g, '').trim(),\n      nome:             (cols[C.nome]            || '').replace(/\"/g, '').trim(),\n      energia_kwh:      r4(energiaFinal),\n      potencia_dia:     r4(potFinal),\n      energia_comercial_kwh: r4(energiaComercial),\n      pot_comercial_dia:     r4(potComercial),\n      desconto_mes:     descFatura,\n      custo_estimado:   r2(custoTotal),\n      tar_en_incl:      tarEnIncl,\n      tar_pot_incl:     tarPotIncl,\n      tse_incl:         tseIncl,\n    });\n  }\n\n  if (fixos.length === 0) {\n    throw new Error(\n      `Nenhum tarif\u00e1rio fixo encontrado para ${CONFIG.potencia_kva} kVA / ` +\n      `${CONFIG.ciclo} com filtros: ${JSON.stringify(CONFIG.filtros)}`\n    );\n  }\n\n  fixos.sort((a, b) => a.custo_estimado - b.custo_estimado);\n  return fixos;\n}\n\n// \u2500\u2500 Obter melhor fixo \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nlet melhorFixo;\nlet fonte;\n\nif (CONFIG.fixo_manual) {\n  // Manual: normaliza da mesma forma\n  const m = CONFIG.fixo_manual;\n  const tarEnIncl  = m.tar_en_incluida !== false;\n  const tarPotIncl = m.tar_pot_incluida !== false;\n  const tseIncl    = m.tse_incluida !== false;\n\n  const energiaComercial = tarEnIncl ? m.energia_kwh - CONFIG.tar.energia_kwh : m.energia_kwh;\n  const potComercial     = tarPotIncl ? m.potencia_dia - CONFIG.tar.potencia_dia : m.potencia_dia;\n  const energiaFinal     = energiaComercial + CONFIG.tar.energia_kwh + (tseIncl ? 0 : TSE);\n  const potFinal         = potComercial + CONFIG.tar.potencia_dia;\n\n  melhorFixo = {\n    nome:          m.nome,\n    comercializador: '',\n    energia_kwh:   r4(energiaFinal),\n    potencia_dia:  r4(potFinal),\n    custo_estimado: r2(energiaFinal * CONFIG.consumo_kwh + potFinal * CONFIG.dias),\n  };\n  fonte = 'manual';\n} else {\n  let todos;\n  try {\n    todos = obterTarifarios(csvTexto);\n  } catch (e) {\n    return [{ json: { erro: e.message } }];\n  }\n  melhorFixo = todos[0];\n  fonte = 'automatico (CSV Tiago Fel\u00edcia)';\n}\n\n// \u2500\u2500 C\u00e1lculo do custo indexado \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// L\u00f3gica do simulador para G9 Smart Index (e equivalentes):\n//   pre\u00e7o_kwh = OMIE_\u20ac/kWh * fator_perdas + margem + TAR_energia + TSE\n//   custo     = pre\u00e7o_kwh * consumo + TAR_potencia * dias\n//\n// A TAR e TSE s\u00e3o SEMPRE adicionadas no indexado (tar_e_incl = false no CSV)\n// O fator_perdas compensa as perdas de rede (varia ~1.10-1.20 conforme contrato)\n//\nconst precoKwhIndexado = (\n  mediaOmie_kWh * CONFIG.indexado.fator_perdas\n  + CONFIG.indexado.margem_kwh\n  + CONFIG.tar.energia_kwh\n  + TSE\n);\nconst custoIndexado = (\n  CONFIG.consumo_kwh * precoKwhIndexado\n  + CONFIG.dias * CONFIG.tar.potencia_dia\n);\n\n// \u2500\u2500 Break-even (a partir de que OMIE o fixo \u00e9 mais barato) \u2500\u2500\u2500\u2500\u2500\n//\n// Resolve: custo_fixo = custo_indexado\n// melhorFixo.custo = consumo * (OMIE_kWh * perdas + margem + TAR + TSE) + dias * TAR_pot\n// OMIE_kWh_breakeven = (custo_fixo/consumo - margem - TAR - TSE) / perdas\n//\nconst custoFixo = melhorFixo.custo_estimado;\nconst breakeven_kWh = (\n  (custoFixo - CONFIG.dias * CONFIG.tar.potencia_dia) / CONFIG.consumo_kwh\n  - CONFIG.indexado.margem_kwh\n  - CONFIG.tar.energia_kwh\n  - TSE\n) / CONFIG.indexado.fator_perdas;\nconst breakeven_MWh = r2(breakeven_kWh * 1000);\n\nconst poupanca   = r2(Math.abs(custoFixo - custoIndexado));\nconst fixoMaisBarato = custoFixo <= r2(custoIndexado);\nconst recomendacao   = fixoMaisBarato ? melhorFixo.nome : CONFIG.indexado.nome;\n\n// \u2500\u2500 Resumo formatado \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nconst data = new Date().toLocaleDateString('pt-PT');\nconst maisBaratoLabel = fixoMaisBarato\n  ? `\ud83c\udfc6 FIXO mais barato \u2014 poupa ${poupanca}\u20ac`\n  : `\ud83c\udfc6 INDEXADO mais barato \u2014 poupa ${poupanca}\u20ac`;\n\nlet resumo = `\ud83d\udcca *AN\u00c1LISE OMIE* (${data})\\n`;\nresumo += `\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\\n\\n`;\nresumo += `\u26a1 *MERCADO OMIE (\u00faltimos 30 dias):*\\n`;\nresumo += `\u2022 M\u00e9dia: *${r2(mediaOmie_MWh)} \u20ac/MWh*\\n`;\nresumo += `\u2022 Break-even: ${breakeven_MWh} \u20ac/MWh\\n\\n`;\nresumo += `\ud83d\udd12 *MELHOR FIXO (${fonte}):*\\n`;\nresumo += `\u2022 ${melhorFixo.nome}\\n`;\nresumo += `\u2022 Energia: ${melhorFixo.energia_kwh} \u20ac/kWh | Pot\u00eancia: ${melhorFixo.potencia_dia} \u20ac/dia\\n`;\nresumo += `\u2022 Custo estimado: *${custoFixo}\u20ac*\\n\\n`;\nresumo += `\ud83d\udcc8 *INDEXADO (${CONFIG.indexado.nome}):*\\n`;\nresumo += `\u2022 Pre\u00e7o kWh: ${r4(precoKwhIndexado)} \u20ac/kWh\\n`;\nresumo += `\u2022 Custo estimado: *${r2(custoIndexado)}\u20ac*\\n\\n`;\nresumo += `\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\\n`;\nresumo += `\ud83d\udca1 *${maisBaratoLabel}*\\n`;\nresumo += `   Recomenda\u00e7\u00e3o: *${recomendacao}*`;\n\nreturn [{\n  json: {\n    data_analise:              data,\n    media_omie_eur_mwh:        r2(mediaOmie_MWh),\n    breakeven_eur_mwh:         breakeven_MWh,\n    omie_acima_breakeven:      mediaOmie_MWh > breakeven_MWh,\n    // Melhor fixo\n    melhor_fixo_nome:          melhorFixo.nome,\n    melhor_fixo_comercializador: melhorFixo.comercializador || '',\n    melhor_fixo_fonte:         fonte,\n    melhor_fixo_energia_kwh:   melhorFixo.energia_kwh,\n    melhor_fixo_potencia_dia:  melhorFixo.potencia_dia,\n    custo_melhor_fixo_eur:     custoFixo,\n    // Indexado\n    indexado_nome:             CONFIG.indexado.nome,\n    indexado_preco_kwh:        r4(precoKwhIndexado),\n    custo_indexado_eur:        r2(custoIndexado),\n    // Compara\u00e7\u00e3o\n    poupanca_eur:              poupanca,\n    recomendacao:              recomendacao,\n    fixo_mais_barato:          fixoMaisBarato,\n    num_precos_omie:           omieData.num_precos,\n    resumo,\n  }\n}];"
      },
      "id": "node-calculos",
      "name": "C\u00e1lculos",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1100,
        300
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://example.com/webhook",
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "content",
              "value": "={{ $json.resumo }}"
            }
          ]
        },
        "options": {}
      },
      "id": "node-notificacao",
      "name": "Notifica\u00e7\u00e3o",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [
        1320,
        300
      ]
    }
  ],
  "connections": {
    "Diariamente": {
      "main": [
        [
          {
            "node": "Gerar URLs OMIE",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Gerar URLs OMIE": {
      "main": [
        [
          {
            "node": "HTTP Request OMIE",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTTP Request OMIE": {
      "main": [
        [
          {
            "node": "Agregar OMIE",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Agregar OMIE": {
      "main": [
        [
          {
            "node": "HTTP Request CSV Tarif\u00e1rios",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTTP Request CSV Tarif\u00e1rios": {
      "main": [
        [
          {
            "node": "C\u00e1lculos",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "C\u00e1lculos": {
      "main": [
        [
          {
            "node": "Notifica\u00e7\u00e3o",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  },
  "tags": []
}