Pular para conteúdo

SHEETS_WRITE - Escrever Dados no Google Sheets

O que é este Node?

O SHEETS_WRITE é o node responsável por escrever ou substituir dados em células específicas do Google Sheets com autenticação OAuth2. Atualiza valores em um range definido, sobrescrevendo o conteúdo existente.

Por que este Node existe?

Muitas automações precisam atualizar planilhas com novos dados ou modificar informações existentes. O SHEETS_WRITE existe para:

  1. Atualização de Registros: Modificar dados de clientes, produtos ou vendas em tempo real
  2. Sincronização de Dados: Manter planilhas atualizadas com informações de outros sistemas
  3. Registro de Operações: Gravar resultados de processos automatizados
  4. Controle de Status: Atualizar campos como "Status do Pedido", "Data de Processamento"

Como funciona internamente?

Quando o SHEETS_WRITE é executado, o sistema:

  1. Valida autenticação: Verifica tokens OAuth2 válidos
  2. Conecta ao Google Sheets API: Autentica com OAuth2Client
  3. Identifica o destino: Extrai spreadsheetId e valida o range
  4. Prepara os dados: Converte values em formato array de arrays
  5. Executa escrita: Chama spreadsheets.values.update() com valueInputOption='USER_ENTERED'
  6. Retorna resultado: Informa quantas células/linhas foram atualizadas
  7. Se erro: Lança exceção com detalhes do problema

Código interno (google-executors.service.ts:768-782):

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,
  };

Quando você DEVE usar este Node?

Use SHEETS_WRITE sempre que precisar atualizar ou substituir dados em células específicas:

Casos de uso

  1. Atualizar Status: "Marcar pedido como 'Enviado' na planilha de vendas"
  2. Registrar Atendimento: "Gravar data/hora do último contato com cliente"
  3. Sincronizar Estoque: "Atualizar quantidade disponível após venda"
  4. Dashboard Manual: "Escrever KPIs calculados em células específicas para visualização"
  5. Controle de Qualidade: "Atualizar campo 'Revisado' após verificação"

Quando NÃO usar SHEETS_WRITE

  • Adicionar novas linhas: Use NODE SHEETS_APPEND para inserir ao final
  • Limpar dados: Use NODE SHEETS_CLEAR para apagar conteúdo
  • Múltiplas operações: Use NODE SHEETS_BATCH_UPDATE para eficiência

Parâmetros Detalhados

spreadsheetId (string, obrigatório)

O que é: ID único da planilha Google Sheets a ser modificada.

Como obter: Extraia da URL: https://docs.google.com/spreadsheets/d/SPREADSHEET_ID/edit

Flow completo para testar:

{
  "name": "Teste Sheets Write - SpreadsheetId",
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "position": { "x": 100, "y": 100 },
      "data": { "label": "Início" }
    },
    {
      "id": "sheets_1",
      "type": "google_sheets",
      "position": { "x": 300, "y": 100 },
      "data": {
        "label": "Escrever Dados",
        "parameters": {
          "operation": "write",
          "spreadsheetId": "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms",
          "range": "Sheet1!A1",
          "values": [["Hello", "World"]],
          "accessToken": "{{google_access_token}}",
          "refreshToken": "{{google_refresh_token}}"
        }
      }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 500, "y": 100 },
      "data": {
        "label": "Confirmar",
        "parameters": {
          "message": "✅ Atualizado {{sheets_1.updatedCells}} células"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 700, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "sheets_1" },
    { "source": "sheets_1", "target": "message_1" },
    { "source": "message_1", "target": "end_1" }
  ]
}

Teste: Configure os tokens OAuth2. O sistema deve escrever "Hello" em A1 e "World" em B1.

range (string, opcional)

O que é: Range inicial onde começar a escrita em notação A1. Define o ponto de partida.

Padrão: "Sheet1!A1"

Comportamento: Os dados em values são escritos a partir deste ponto, expandindo para direita e para baixo conforme necessário.

Exemplos: - A1 - Escreve a partir da célula A1 - Vendas!D5 - Escreve a partir de D5 na aba Vendas - B2:D4 - Escreve no range B2 até D4 (deve corresponder ao tamanho de values)

Flow completo para testar:

{
  "name": "Teste Sheets Write - Range",
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "position": { "x": 100, "y": 100 },
      "data": { "label": "Início" }
    },
    {
      "id": "sheets_1",
      "type": "google_sheets",
      "position": { "x": 300, "y": 100 },
      "data": {
        "label": "Escrever em B2",
        "parameters": {
          "operation": "write",
          "spreadsheetId": "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms",
          "range": "Sheet1!B2",
          "values": [
            ["Produto", "Preço"],
            ["Notebook", "2500"],
            ["Mouse", "50"]
          ],
          "accessToken": "{{google_access_token}}",
          "refreshToken": "{{google_refresh_token}}"
        }
      }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 500, "y": 100 },
      "data": {
        "label": "Resultado",
        "parameters": {
          "message": "Escritas {{sheets_1.updatedRows}} linhas a partir de B2"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 700, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "sheets_1" },
    { "source": "sheets_1", "target": "message_1" },
    { "source": "message_1", "target": "end_1" }
  ]
}

Teste: O sistema deve escrever a tabela começando em B2 (ocupará B2:C4).

values (array, obrigatório)

O que é: Array de arrays contendo os dados a serem escritos. Cada sub-array representa uma linha.

Formato:

[
  ["Célula A1", "Célula B1", "Célula C1"],  // Linha 1
  ["Célula A2", "Célula B2", "Célula C2"],  // Linha 2
  ["Célula A3", "Célula B3", "Célula C3"]   // Linha 3
]

Tipos suportados: Strings, números, booleanos, fórmulas (começando com =)

Flow completo para testar:

{
  "name": "Teste Sheets Write - Values",
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "position": { "x": 100, "y": 100 },
      "data": { "label": "Início" }
    },
    {
      "id": "variable_1",
      "type": "variable",
      "position": { "x": 300, "y": 100 },
      "data": {
        "label": "Preparar Dados",
        "parameters": {
          "variableName": "dados_tabela",
          "value": [
            ["Nome", "Email", "Status"],
            ["José", "jose@email.com", "Ativo"],
            ["Maria", "maria@email.com", "Ativo"]
          ]
        }
      }
    },
    {
      "id": "sheets_1",
      "type": "google_sheets",
      "position": { "x": 500, "y": 100 },
      "data": {
        "label": "Escrever Tabela",
        "parameters": {
          "operation": "write",
          "spreadsheetId": "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms",
          "range": "Clientes!A1",
          "values": "{{dados_tabela}}",
          "accessToken": "{{google_access_token}}",
          "refreshToken": "{{google_refresh_token}}"
        }
      }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 700, "y": 100 },
      "data": {
        "label": "Confirmar",
        "parameters": {
          "message": "✅ Tabela escrita: {{sheets_1.updatedRows}} linhas, {{sheets_1.updatedCells}} células"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 900, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "variable_1" },
    { "source": "variable_1", "target": "sheets_1" },
    { "source": "sheets_1", "target": "message_1" },
    { "source": "message_1", "target": "end_1" }
  ]
}

Teste: O sistema deve escrever 3 linhas com 3 colunas cada, totalizando 9 células.

accessToken (string, obrigatório)

O que é: Token de acesso OAuth2 do Google para autenticação da operação de escrita.

Permissões necessárias: Escopo https://www.googleapis.com/auth/spreadsheets

Flow completo para testar:

{
  "name": "Teste Sheets Write - AccessToken",
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "position": { "x": 100, "y": 100 },
      "data": { "label": "Início" }
    },
    {
      "id": "sheets_1",
      "type": "google_sheets",
      "position": { "x": 300, "y": 100 },
      "data": {
        "label": "Escrever Timestamp",
        "parameters": {
          "operation": "write",
          "spreadsheetId": "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms",
          "range": "Log!A1",
          "values": [["Última atualização:", "2025-01-15 10:30:00"]],
          "accessToken": "{{google_access_token}}",
          "refreshToken": "{{google_refresh_token}}"
        }
      }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 500, "y": 100 },
      "data": {
        "label": "Confirmar",
        "parameters": {
          "message": "Timestamp registrado com sucesso!"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 700, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "sheets_1" },
    { "source": "sheets_1", "target": "message_1" },
    { "source": "message_1", "target": "end_1" }
  ]
}

Teste: Com token válido, o sistema deve gravar a data/hora na célula especificada.

refreshToken (string, obrigatório)

O que é: Token OAuth2 de longa duração para renovar accessToken quando expirar.

Validade: Geralmente válido indefinidamente (até revogação manual)

Flow completo para testar:

{
  "name": "Teste Sheets Write - RefreshToken",
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "position": { "x": 100, "y": 100 },
      "data": { "label": "Início" }
    },
    {
      "id": "sheets_1",
      "type": "google_sheets",
      "position": { "x": 300, "y": 100 },
      "data": {
        "label": "Atualizar Status",
        "parameters": {
          "operation": "write",
          "spreadsheetId": "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms",
          "range": "Status!A1",
          "values": [["Sistema", "Operacional"]],
          "accessToken": "{{google_access_token}}",
          "refreshToken": "{{google_refresh_token}}"
        }
      }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 500, "y": 100 },
      "data": {
        "label": "Confirmar",
        "parameters": {
          "message": "Status atualizado"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 700, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "sheets_1" },
    { "source": "sheets_1", "target": "message_1" },
    { "source": "message_1", "target": "end_1" }
  ]
}

Teste: O refreshToken garante operação contínua mesmo com accessToken expirado.

Parâmetros

Campo Tipo Obrigatório Descrição
operation string Sim Deve ser "write" para escrita
spreadsheetId string Sim ID da planilha Google Sheets
range string Não Range inicial em notação A1 (padrão: Sheet1!A1)
values array Sim Array de arrays com dados a escrever
accessToken string Sim Token OAuth2 de acesso
refreshToken string Sim Token OAuth2 de atualização

Exemplo 1: Atualizar Status de Pedido

Objetivo: Marcar pedido como processado na planilha de controle

JSON para Importar

{
  "name": "E-commerce - Atualizar Status Pedido",
  "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": "Número do Pedido",
        "parameters": {
          "prompt": "Digite o número do pedido:",
          "variableName": "numero_pedido"
        }
      }
    },
    {
      "id": "variable_1",
      "type": "variable",
      "position": { "x": 500, "y": 100 },
      "data": {
        "label": "Preparar Atualização",
        "parameters": {
          "variableName": "dados_atualizacao",
          "value": [
            ["Processado", "2025-01-15", "Sistema Automático"]
          ]
        }
      }
    },
    {
      "id": "sheets_1",
      "type": "google_sheets",
      "position": { "x": 700, "y": 100 },
      "data": {
        "label": "Gravar Status",
        "parameters": {
          "operation": "write",
          "spreadsheetId": "1ABC_Pedidos_XYZ",
          "range": "Pedidos!D{{numero_pedido}}",
          "values": "{{dados_atualizacao}}",
          "accessToken": "{{google_access_token}}",
          "refreshToken": "{{google_refresh_token}}"
        }
      }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 900, "y": 100 },
      "data": {
        "label": "Confirmar",
        "parameters": {
          "message": "✅ Pedido {{numero_pedido}} atualizado para 'Processado'"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 1100, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "input_1" },
    { "source": "input_1", "target": "variable_1" },
    { "source": "variable_1", "target": "sheets_1" },
    { "source": "sheets_1", "target": "message_1" },
    { "source": "message_1", "target": "end_1" }
  ]
}

Saída esperada:

Sistema: Digite o número do pedido:
Usuário: 1234
Sistema: ✅ Pedido 1234 atualizado para 'Processado'

Exemplo 2: Registrar Atendimento de Cliente

Objetivo: Gravar data/hora e notas do atendimento na planilha CRM

JSON para Importar

{
  "name": "CRM - Registrar Atendimento",
  "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 Cliente",
        "parameters": {
          "prompt": "Nome do cliente:",
          "variableName": "nome_cliente"
        }
      }
    },
    {
      "id": "input_2",
      "type": "input",
      "position": { "x": 500, "y": 100 },
      "data": {
        "label": "Notas",
        "parameters": {
          "prompt": "Resumo do atendimento:",
          "variableName": "notas"
        }
      }
    },
    {
      "id": "variable_1",
      "type": "variable",
      "position": { "x": 700, "y": 100 },
      "data": {
        "label": "Timestamp",
        "parameters": {
          "variableName": "data_hora",
          "value": "{{NOW}}"
        }
      }
    },
    {
      "id": "sheets_1",
      "type": "google_sheets",
      "position": { "x": 900, "y": 100 },
      "data": {
        "label": "Gravar Atendimento",
        "parameters": {
          "operation": "write",
          "spreadsheetId": "1CRM_Database_XYZ",
          "range": "Atendimentos!A2",
          "values": [
            ["{{data_hora}}", "{{nome_cliente}}", "{{notas}}", "WhatsApp"]
          ],
          "accessToken": "{{google_access_token}}",
          "refreshToken": "{{google_refresh_token}}"
        }
      }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 1100, "y": 100 },
      "data": {
        "label": "Confirmar",
        "parameters": {
          "message": "✅ Atendimento de {{nome_cliente}} registrado com sucesso!"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 1300, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "input_1" },
    { "source": "input_1", "target": "input_2" },
    { "source": "input_2", "target": "variable_1" },
    { "source": "variable_1", "target": "sheets_1" },
    { "source": "sheets_1", "target": "message_1" },
    { "source": "message_1", "target": "end_1" }
  ]
}

Saída esperada:

Sistema: Nome do cliente:
Usuário: José Silva
Sistema: Resumo do atendimento:
Usuário: Cliente solicitou orçamento de 10 unidades
Sistema: ✅ Atendimento de José Silva registrado com sucesso!

Exemplo 3: Atualizar Dashboard de KPIs

Objetivo: Escrever métricas calculadas em células específicas de dashboard

JSON para Importar

{
  "name": "Dashboard - Atualizar KPIs",
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "position": { "x": 100, "y": 100 },
      "data": { "label": "Início" }
    },
    {
      "id": "variable_1",
      "type": "variable",
      "position": { "x": 300, "y": 100 },
      "data": {
        "label": "Calcular Métricas",
        "parameters": {
          "variableName": "kpis",
          "value": [
            ["Vendas Hoje", "45", "Meta: 50"],
            ["Clientes Ativos", "320", "+15 hoje"],
            ["Taxa Conversão", "23%", "+2%"]
          ]
        }
      }
    },
    {
      "id": "sheets_1",
      "type": "google_sheets",
      "position": { "x": 500, "y": 100 },
      "data": {
        "label": "Atualizar Dashboard",
        "parameters": {
          "operation": "write",
          "spreadsheetId": "1Dashboard_KPI_XYZ",
          "range": "Dashboard!B2:D4",
          "values": "{{kpis}}",
          "accessToken": "{{google_access_token}}",
          "refreshToken": "{{google_refresh_token}}"
        }
      }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 700, "y": 100 },
      "data": {
        "label": "Confirmar",
        "parameters": {
          "message": "📊 Dashboard atualizado! {{sheets_1.updatedCells}} células modificadas"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 900, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "variable_1" },
    { "source": "variable_1", "target": "sheets_1" },
    { "source": "sheets_1", "target": "message_1" },
    { "source": "message_1", "target": "end_1" }
  ]
}

Saída esperada:

Sistema: 📊 Dashboard atualizado! 9 células modificadas

Resposta do Node

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

Boas Práticas

SIM:

  • Use valueInputOption='USER_ENTERED' para que fórmulas sejam interpretadas
  • Valide estrutura de dados antes de escrever (arrays consistentes)
  • Use range específico que corresponda ao tamanho dos dados
  • Faça backup antes de operações de escrita em massa
  • Verifique permissões de edição na planilha antes
  • Use fórmulas começando com = para cálculos automáticos

NÃO:

  • Não escreva em ranges muito grandes desnecessariamente
  • Não sobrescreva dados sem confirmar primeiro
  • Não esqueça que write SUBSTITUI conteúdo existente
  • Não misture tipos de dados inconsistentes nas colunas
  • Não use write quando deveria usar append (adicionar ao final)
  • Não exponha tokens em logs ou mensagens

Dicas

💡 Dica 1 - ValueInputOption: O sistema usa 'USER_ENTERED', o que significa: - Números são interpretados como números, não strings - Fórmulas começando com = são calculadas - Datas são reconhecidas automaticamente - Strings permanecem como texto

💡 Dica 2 - Write vs Append: - WRITE: Substitui dados em posição específica - APPEND: Adiciona ao final da tabela existente - Use write quando souber a posição exata - Use append para novos registros em sequência

💡 Dica 3 - Fórmulas: Você pode escrever fórmulas:

values: [
  ["Item", "Preço", "IVA", "Total"],
  ["Produto A", 100, 0.23, "=B2*C2"],
  ["Produto B", 200, 0.23, "=B3*C3"]
]

💡 Dica 4 - Performance: - Uma operação write com múltiplas linhas é mais eficiente que várias operações separadas - Agrupe atualizações quando possível - Para múltiplas áreas, considere SHEETS_BATCH_UPDATE

💡 Dica 5 - Permissões: A conta Google precisa ter permissão de "Editor" ou superior na planilha. "Visualizar" não é suficiente para write.

Próximo Node

SHEETS_APPEND - Adicionar linhas ao final → SHEETS_UPDATE - Atualizar células específicas → SHEETS_CLEAR - Limpar conteúdo