Pular para conteúdo

GOOGLE_SHEETS - Integração com Planilhas do Google

O que é este Node?

O GOOGLE_SHEETS é o node responsável por integrar com o Google Sheets, permitindo ler, escrever, anexar e limpar dados em planilhas do Google de forma automatizada.

Por que este Node existe?

Planilhas são essenciais para armazenamento e análise de dados. O GOOGLE_SHEETS existe para:

  1. Armazenar dados estruturados: Salvar respostas de formulários, pedidos, leads
  2. Consultar informações: Ler preços, catálogos, dados de clientes
  3. Gerar relatórios: Exportar dados para análise em tempo real
  4. Integração universal: Google Sheets é acessível por toda equipe
  5. Automatização: Eliminar entrada manual de dados

Como funciona internamente?

Quando o GOOGLE_SHEETS é executado, o sistema:

  1. Autentica via OAuth2 com Google (access_token e refresh_token)
  2. Conecta à API do Google Sheets v4
  3. Executa operação solicitada (read, write, append, clear)
  4. Processa range especificado (ex: "Sheet1!A1:Z1000")
  5. Retorna dados ou confirmação da operação
  6. Se erro: Retorna mensagem de erro detalhada

Código interno (google-executors.service.ts:738-818):

async executeGoogleSheets(data: any, variables: Record<string, any>): Promise<any> {
  try {
    this.logger.log('📊 [GOOGLE SHEETS] Executing operation');

    const oauth2Client = new OAuth2Client(
      process.env.GOOGLE_CLIENT_ID,
      process.env.GOOGLE_CLIENT_SECRET,
      process.env.GOOGLE_REDIRECT_URI
    );

    oauth2Client.setCredentials({
      access_token: data.accessToken,
      refresh_token: data.refreshToken,
    });

    const sheets = google.sheets({ version: 'v4', auth: oauth2Client });

    switch (data.operation) {
      case 'read':
        const readResult = await sheets.spreadsheets.values.get({
          spreadsheetId: data.spreadsheetId,
          range: data.range || 'Sheet1!A1:Z1000',
        });

        return {
          success: true,
          data: readResult.data.values,
          rowCount: readResult.data.values?.length || 0,
        };

      case 'write':
        const writeResult = await sheets.spreadsheets.values.update({
          spreadsheetId: data.spreadsheetId,
          range: data.range || 'Sheet1!A1',
          valueInputOption: 'USER_ENTERED',
          requestBody: {
            values: data.values,
          },
        });

        return {
          success: true,
          updatedCells: writeResult.data.updatedCells,
          updatedRows: writeResult.data.updatedRows,
        };

      case 'append':
        const appendResult = await sheets.spreadsheets.values.append({
          spreadsheetId: data.spreadsheetId,
          range: data.range || 'Sheet1!A1',
          valueInputOption: 'USER_ENTERED',
          requestBody: {
            values: data.values,
          },
        });

        return {
          success: true,
          updatedCells: appendResult.data.updates?.updatedCells,
          updatedRows: appendResult.data.updates?.updatedRows,
        };

      case 'clear':
        await sheets.spreadsheets.values.clear({
          spreadsheetId: data.spreadsheetId,
          range: data.range || 'Sheet1!A1:Z1000',
        });

        return {
          success: true,
          message: 'Range cleared successfully',
        };

      default:
        throw new Error(`Unknown Google Sheets operation: ${data.operation}`);
    }
  } catch (error) {
    this.logger.error('Google Sheets execution error:', error);
    throw error;
  }
}

Quando você DEVE usar este Node?

Use GOOGLE_SHEETS sempre que precisar integrar com planilhas do Google:

Casos de uso

  1. Salvar leads: "Registrar nome, email e telefone de cada lead"
  2. Consultar catálogo: "Buscar preço de produto na planilha"
  3. Registro de atendimentos: "Logar todas as conversas com timestamp"
  4. Formulários dinâmicos: "Salvar respostas de pesquisa"
  5. Dashboard em tempo real: "Alimentar planilha para dashboards"
  6. Exportar relatórios: "Gerar relatório de vendas diário"

Quando NÃO usar GOOGLE_SHEETS

  • Dados sensíveis sem criptografia: Use banco de dados seguro
  • Altíssimo volume (>1000 req/min): Use banco de dados dedicado
  • Processamento complexo: Use BigQuery para análise pesada

Parâmetros

Campo Tipo Obrigatório Descrição
operation string Sim read, write, append, clear
spreadsheetId string Sim ID da planilha (da URL)
range string Não Range A1 notation (padrão: Sheet1!A1:Z1000)
values array Condicional Dados para write/append (array de arrays)
accessToken string Sim Token OAuth2 do Google
refreshToken string Sim Refresh token OAuth2 do Google

Operações Disponíveis

1. read - Ler dados da planilha

O que faz: Lê dados de um range específico da planilha.

Parâmetros obrigatórios: - spreadsheetId - accessToken - refreshToken

Parâmetros opcionais: - range (padrão: "Sheet1!A1:Z1000")

2. write - Escrever dados (sobrescrever)

O que faz: Sobrescreve dados em um range específico.

Parâmetros obrigatórios: - spreadsheetId - values - accessToken - refreshToken

Parâmetros opcionais: - range (padrão: "Sheet1!A1")

3. append - Anexar dados (adicionar no final)

O que faz: Adiciona dados no final da planilha automaticamente.

Parâmetros obrigatórios: - spreadsheetId - values - accessToken - refreshToken

Parâmetros opcionais: - range (padrão: "Sheet1!A1")

4. clear - Limpar dados

O que faz: Limpa todos os dados de um range específico.

Parâmetros obrigatórios: - spreadsheetId - accessToken - refreshToken

Parâmetros opcionais: - range (padrão: "Sheet1!A1:Z1000")

Exemplo 1: Salvar Lead em Planilha

Objetivo: Capturar nome e email e salvar na planilha automaticamente.

JSON para Importar

{
  "name": "Salvar Lead no Google Sheets",
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "position": { "x": 100, "y": 100 },
      "data": { "label": "Início" }
    },
    {
      "id": "input_1",
      "type": "input",
      "position": { "x": 300, "y": 100 },
      "data": {
        "label": "Pedir Nome",
        "parameters": {
          "message": "Qual é o seu nome?",
          "variable": "nome"
        }
      }
    },
    {
      "id": "email_1",
      "type": "email",
      "position": { "x": 500, "y": 100 },
      "data": {
        "label": "Pedir Email",
        "parameters": {
          "message": "Qual é o seu email?",
          "variable": "email"
        }
      }
    },
    {
      "id": "google_sheets_1",
      "type": "google_sheets",
      "position": { "x": 700, "y": 100 },
      "data": {
        "label": "Salvar na Planilha",
        "parameters": {
          "operation": "append",
          "spreadsheetId": "1ABC123...XYZ",
          "range": "Leads!A:B",
          "values": [
            ["{{nome}}", "{{email}}"]
          ],
          "accessToken": "{{google_access_token}}",
          "refreshToken": "{{google_refresh_token}}"
        }
      }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 900, "y": 100 },
      "data": {
        "label": "Confirmar",
        "parameters": {
          "message": "✅ Dados salvos com sucesso!\n\nNome: {{nome}}\nEmail: {{email}}"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 1100, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "input_1" },
    { "source": "input_1", "target": "email_1" },
    { "source": "email_1", "target": "google_sheets_1" },
    { "source": "google_sheets_1", "target": "message_1" },
    { "source": "message_1", "target": "end_1" }
  ]
}

Saída esperada:

Sistema: Qual é o seu nome?
Usuário: João Silva
Sistema: Qual é o seu email?
Usuário: joao@example.com
Sistema: ✅ Dados salvos com sucesso!

Nome: João Silva
Email: joao@example.com

Resultado na planilha: | Nome | Email | |------|-------| | João Silva | joao@example.com |

Exemplo 2: Ler Preços de Produtos

Objetivo: Consultar preço de produto na planilha.

JSON para Importar

{
  "name": "Consultar Preço no Google Sheets",
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "position": { "x": 100, "y": 100 },
      "data": { "label": "Início" }
    },
    {
      "id": "input_1",
      "type": "input",
      "position": { "x": 300, "y": 100 },
      "data": {
        "label": "Pedir Produto",
        "parameters": {
          "message": "Qual produto você deseja consultar?",
          "variable": "produto"
        }
      }
    },
    {
      "id": "google_sheets_1",
      "type": "google_sheets",
      "position": { "x": 500, "y": 100 },
      "data": {
        "label": "Ler Preços",
        "parameters": {
          "operation": "read",
          "spreadsheetId": "1ABC123...XYZ",
          "range": "Produtos!A2:C100",
          "accessToken": "{{google_access_token}}",
          "refreshToken": "{{google_refresh_token}}"
        }
      }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 700, "y": 100 },
      "data": {
        "label": "Mostrar Resultado",
        "parameters": {
          "message": "📊 Dados carregados da planilha!\n\nTotal de produtos: {{rowCount}}"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 900, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "input_1" },
    { "source": "input_1", "target": "google_sheets_1" },
    { "source": "google_sheets_1", "target": "message_1" },
    { "source": "message_1", "target": "end_1" }
  ]
}

Exemplo 3: Registro de Atendimento Completo

Objetivo: Salvar log completo de atendimento com timestamp.

JSON para Importar

{
  "name": "Registrar Atendimento no Google Sheets",
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "position": { "x": 100, "y": 100 },
      "data": { "label": "Início" }
    },
    {
      "id": "input_1",
      "type": "input",
      "position": { "x": 300, "y": 100 },
      "data": {
        "label": "Nome",
        "parameters": {
          "message": "Nome do cliente:",
          "variable": "cliente_nome"
        }
      }
    },
    {
      "id": "phone_1",
      "type": "phone",
      "position": { "x": 500, "y": 100 },
      "data": {
        "label": "Telefone",
        "parameters": {
          "message": "Telefone:",
          "variable": "cliente_telefone"
        }
      }
    },
    {
      "id": "input_2",
      "type": "input",
      "position": { "x": 700, "y": 100 },
      "data": {
        "label": "Assunto",
        "parameters": {
          "message": "Qual o assunto do atendimento?",
          "variable": "assunto"
        }
      }
    },
    {
      "id": "variable_1",
      "type": "variable",
      "position": { "x": 900, "y": 100 },
      "data": {
        "label": "Timestamp",
        "parameters": {
          "operation": "set",
          "name": "timestamp",
          "value": "{{$now}}"
        }
      }
    },
    {
      "id": "google_sheets_1",
      "type": "google_sheets",
      "position": { "x": 1100, "y": 100 },
      "data": {
        "label": "Salvar Atendimento",
        "parameters": {
          "operation": "append",
          "spreadsheetId": "1ABC123...XYZ",
          "range": "Atendimentos!A:D",
          "values": [
            ["{{timestamp}}", "{{cliente_nome}}", "{{cliente_telefone}}", "{{assunto}}"]
          ],
          "accessToken": "{{google_access_token}}",
          "refreshToken": "{{google_refresh_token}}"
        }
      }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 1300, "y": 100 },
      "data": {
        "label": "Confirmar",
        "parameters": {
          "message": "✅ Atendimento registrado!\n\nCliente: {{cliente_nome}}\nTelefone: {{cliente_telefone}}\nAssunto: {{assunto}}\nData/Hora: {{timestamp}}"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 1500, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "input_1" },
    { "source": "input_1", "target": "phone_1" },
    { "source": "phone_1", "target": "input_2" },
    { "source": "input_2", "target": "variable_1" },
    { "source": "variable_1", "target": "google_sheets_1" },
    { "source": "google_sheets_1", "target": "message_1" },
    { "source": "message_1", "target": "end_1" }
  ]
}

Resposta do Node

Operação read

{
  "success": true,
  "data": [
    ["Nome", "Email", "Telefone"],
    ["João Silva", "joao@example.com", "11999999999"],
    ["Maria Santos", "maria@example.com", "11888888888"]
  ],
  "rowCount": 3
}

Operação write/append

{
  "success": true,
  "updatedCells": 2,
  "updatedRows": 1
}

Operação clear

{
  "success": true,
  "message": "Range cleared successfully"
}

Como obter o spreadsheetId

O spreadsheetId está na URL da planilha:

https://docs.google.com/spreadsheets/d/1ABC123...XYZ/edit
                                      ^^^^^^^^^^^^^^
                                      Este é o spreadsheetId

Formato A1 Notation (Range)

Exemplos de ranges válidos:

Range Descrição
Sheet1!A1 Célula A1 da Sheet1
Sheet1!A1:B10 Células A1 até B10
Sheet1!A:A Coluna A inteira
Sheet1!1:1 Linha 1 inteira
Sheet1!A:C Colunas A até C
Leads!A2:D Da linha 2 até última linha (colunas A-D)

Formato de values (dados)

O parâmetro values deve ser um array de arrays:

// Uma linha com 3 colunas
[["João", "joao@email.com", "11999999999"]]

// Três linhas com 2 colunas cada
[
  ["Nome", "Email"],
  ["João", "joao@email.com"],
  ["Maria", "maria@email.com"]
]

Autenticação OAuth2

Para usar o Google Sheets, você precisa:

  1. Criar projeto no Google Cloud Console
  2. Habilitar Google Sheets API
  3. Criar credenciais OAuth2
  4. Obter tokens via fluxo OAuth2
  5. Salvar access_token e refresh_token

Os tokens podem ser armazenados em variáveis globais ou no contexto.

Boas Práticas

SIM:

  • Use append para adicionar dados incrementalmente
  • Especifique range exato para melhor performance
  • Valide dados antes de salvar na planilha
  • Use headers na primeira linha (ex: Nome, Email, Telefone)
  • Armazene tokens com segurança

NÃO:

  • Não exponha tokens em logs ou mensagens
  • Não use write quando quer append (sobrescreve dados)
  • Não faça múltiplas chamadas rápidas (rate limit)
  • Não salve dados sensíveis sem criptografia
  • Não use planilhas para dados ultra-críticos

Dicas

💡 Performance: Use ranges específicos ao invés de ler planilha inteira

💡 Append automático: append detecta automaticamente a próxima linha vazia

💡 USER_ENTERED: valueInputOption "USER_ENTERED" interpreta fórmulas automaticamente

💡 Rate Limits: Google Sheets API tem limite de 100 requisições/100 segundos por usuário

💡 Refresh Token: Salve o refresh_token para renovar access_token automaticamente

Troubleshooting

Erro: "The caller does not have permission"

Causa: Token sem permissões ou planilha não compartilhada

Solução: 1. Verifique se o token tem scope https://www.googleapis.com/auth/spreadsheets 2. Compartilhe a planilha com a conta de serviço

Erro: "Requested entity was not found"

Causa: spreadsheetId ou range inválido

Solução: Verifique o ID da planilha na URL e o range A1

Erro: "Invalid values"

Causa: Formato de values incorreto

Solução: Use array de arrays: [["valor1", "valor2"]]

Próximo Node

GOOGLE_DRIVE - Gerenciar arquivos no Google Drive → GOOGLE_CALENDAR - Integrar com Google Calendar → GOOGLE_DOCS - Manipular documentos do Google