KEPLIN Docs

Lógica e automação

Escrever o script Python que resume o pipeline comercial, corrê-lo à mão e agendá-lo para todas as manhãs.

A app já mostra dados e deixa editá-los. Falta a parte que trabalha sozinha: um script que, todas as manhãs, olha para o pipeline, conta o que está aberto e regista os fechos previstos para a semana.

Nesta etapa escreves esse script em Python, corre-lo à mão para ver o resultado, e marcas-lhe uma hora — todos os dias às 07:00.

O que o script vai fazer

O atualizar_indicadores responde a três perguntas, e devolve-as num resultado que fica no histórico:

Pergunta O que devolve
Quantas oportunidades estão abertas? oportunidades_abertas
Quanto vale o pipeline? valor_pipeline
Quantos fechos estão previstos para os próximos 7 dias? fechos_proximos_7_dias

Além do resultado, escreve logs — uma linha por fecho da semana — para quem abrir o histórico perceber, sem contas, o que estava marcado naquele dia.

Criar o script

  1. Escolhe o painel Código na barra lateral.
  2. Na linha Scripts, clica no + (Novo script). Abre o diálogo Novo script — "Escolhe o runtime e cria — o código edita-se a seguir, com o contrato à vista."
  3. Em Nome, escreve atualizar_indicadores. O nome identifica o script em todo o lado — nos agendamentos, nos passos de API, nas dependências de outros scripts.
  4. Runtime está fixo em Python.
  5. Em Descrição, escreve Recalcula os indicadores comerciais e avisa quando há fechos para esta semana.
  6. Em Tempo limite, deixa 1 minuto. É o tecto da execução: passado esse tempo, a plataforma corta.
  7. Clica em Criar script. O editor abre com o main.py pronto.

O diálogo Novo script — nome, runtime, descrição e tempo limite.
O diálogo Novo script — nome, runtime, descrição e tempo limite.

Dica

Um tempo limite generoso não é gentileza: se este script for usado como passo de uma API, os clientes ficam à espera esse tempo no pior caso. Um minuto chega e sobra para o que vamos fazer.

Escrever o main.py

O contrato de um script é curto: uma função main(input) que devolve alguma coisa. O que devolves fica no histórico de execuções e, se o script for chamado por uma API, é a resposta dela.

Escreve isto no editor:

from datetime import date, timedelta

from api_manager import db, log


def main(input):
    """Recalcula os indicadores do painel comercial.

    Corre todos os dias às 7h00 (agendamento "Indicadores diários") e
    devolve o resumo — o histórico de execuções fica com um registo
    legível por dia.
    """
    crm = db("Dados CRM")

    abertas = crm.query(
        "select count(*) as n, coalesce(sum(valor), 0) as total "
        "from oportunidades where fase not in ('fechada_ganha', 'fechada_perdida')"
    )[0]

    limite = (date.today() + timedelta(days=7)).isoformat()
    fechos_semana = crm.query(
        "select titulo, data_fecho from oportunidades "
        "where fase not in ('fechada_ganha', 'fechada_perdida') "
        "and data_fecho <= ? order by data_fecho",
        [limite],
    )

    log("pipeline:", abertas["n"], "oportunidades /", abertas["total"], "EUR")
    for op in fechos_semana:
        log("fecho esta semana:", op["titulo"], "(", op["data_fecho"], ")")

    return {
        "oportunidades_abertas": abertas["n"],
        "valor_pipeline": abertas["total"],
        "fechos_proximos_7_dias": len(fechos_semana),
    }

O editor do script atualizar_indicadores — o main.py e, em baixo, o painel Resultado da execução.
O editor do script atualizar_indicadores — o main.py e, em baixo, o painel Resultado da execução.

Quatro coisas para reter deste código:

Linha O que faz
from api_manager import db, log O acesso da plataforma: db abre bases de dados, log escreve no histórico.
db("Dados CRM") A base de dados pelo nome interno do datasource — o mesmo que registaste na etapa do modelo. Muda o nome ali e esta linha deixa de funcionar.
crm.query(sql, [valores]) Consulta parametrizada. Os valores vão sempre à parte da query — nunca colados ao texto.
return { … } O resultado da execução. Fica no histórico e é o que uma API devolveria.

O input que a função recebe traz os argumentos da execução — os de uma API, os de um agendamento ou os que escreveres à mão a seguir. Aqui não usamos nenhum.

Nota

Não há botão de gravar: o editor grava sozinho. O interruptor Activo no canto superior direito é outra coisa — um script inactivo continua a existir mas não corre, nem à mão nem por agendamento.

Correr o script à mão

  1. No topo do editor, clica em Executar agora.
  2. Abre o diálogo — "Define os argumentos desta execução (opcional). Os valores chegam ao script como texto." Não precisamos de nenhum.
  3. Clica em Executar.

O diálogo Executar agora — argumentos opcionais desta execução, entregues ao script como texto.
O diálogo Executar agora — argumentos opcionais desta execução, entregues ao script como texto.

O painel Resultado da execução, em baixo, enche-se: o selo Sucesso com a duração, o valor devolvido em JSON e o bloco Logs com as linhas que o log() escreveu.

O painel Resultado da execução, com o valor devolvido e os logs.
O painel Resultado da execução, com o valor devolvido e os logs.

Dica

A primeira execução de um script Python é sempre a mais lenta — o ambiente é preparado nesse momento. As seguintes correm em milissegundos.

O histórico de execuções

O resultado no editor é só o da sessão actual. O histórico completo está no botão Execuções, ao lado do Executar agora:

O histórico Execuções do script — início, origem, estado e duração de cada corrida.
O histórico Execuções do script — início, origem, estado e duração de cada corrida.

Cada linha diz Início, Origem (Manual, quando foste tu; Agendamento, quando foi a hora marcada), Estado e Duração, e o link Detalhes abre a execução: os argumentos, o resultado devolvido e os logs daquela corrida em concreto. É por aqui que se percebe, três semanas depois, o que o script viu na manhã em que ninguém estava a ver.

Agendar para todas as manhãs

Um script que só corre quando alguém carrega no botão não é automação. É altura de lhe marcar uma hora.

  1. Na árvore do painel Código, expande o nó do script atualizar_indicadores. Aparecem três secções: Ficheiros, Dependências e Agendamentos.
  2. Passa o rato sobre Agendamentos e clica no + (Novo agendamento).
  3. Dá-lhe o nome Indicadores diários e cria. O editor do agendamento abre num separador.
  4. Em Frequência, escolhe Em momentos certos — "Numa hora do dia, nos dias que escolheres."
  5. Em Repete, escolhe Todos os dias (nos dias escolhidos).
  6. Em À hora, escreve 07:00.
  7. Em Dias, deixa os sete seleccionados (ou clica em Úteis se o fim-de-semana não interessar).
  8. Em Fuso horário, escolhe Europe/Lisbon. É o fuso que decide o que são "sete da manhã" — sem ele, a hora certa muda com a mudança da hora.
  9. Em Se ficar por correr, escolhe Ignorar.
  10. Confirma que o interruptor Activo está ligado e clica em Gravar.

O agendamento Indicadores diários — todos os dias às 07:00 (Europe/Lisbon), com o painel Execuções à direita.
O agendamento Indicadores diários — todos os dias às 07:00 (Europe/Lisbon), com o painel Execuções à direita.

As três frequências

Frequência Quando usar
Repetir A cada N minutos ou horas, sem parar. Sincronizações, sondagens.
Em momentos certos Numa hora do dia, nos dias escolhidos. É o nosso caso — e o mais comum.
Janela de vigilância Sonda de N em N minutos entre duas horas e pára quando o trabalho do dia estiver feito. Para esperar por um ficheiro que chega "de manhã, a horas variáveis".

Quem preferir escrever a expressão de agendamento à mão tem o link Escrever a expressão à mão por baixo das três opções.

O que fazer com o que ficou por correr

O servidor esteve em baixo às sete da manhã. Quando voltar, o que acontece à ocorrência falhada? É o que Se ficar por correr decide:

Opção O que faz
Ignorar Não recupera. Fica registado que se perdeu.
Só a mais recente Recupera a última que ficou por fazer; as anteriores ficam registadas como perdidas.
Todas Recupera todas as que ficaram por fazer, pela ordem em que estavam marcadas.

Para um resumo diário, Ignorar é o certo: correr o resumo de terça na quinta-feira não serve a ninguém. Para uma facturação mensal, Todas faz todo o sentido.

O painel de execuções do agendamento

À direita do editor fica o painel Execuções, com as horas previstas e o que aconteceu a cada uma: Feita, Por fazer, Perdida ou Saltada.

Atenção

Se este painel avisar que "o agendador não está a correr nesta instalação — nada será executado", as horas marcadas ficam à espera e nada corre. O agendador liga-se na instalação, não na app — fala com quem administra a plataforma.

E a seguir?

O script fica pronto para mais do que a hora marcada: pode ser um passo de uma API (para o resumo ser calculado a pedido), pode chamar outros scripts como dependência, e pode instalar packages de Python que precise. O capítulo Scripts percorre tudo isso, e o SDK dos scripts documenta o api_manager — base de dados, ficheiros, secrets, notificações e chamadas HTTP.

Porque não…?

  • Porque é que o script falha com "datasource não encontrado"? O nome em db("…") tem de ser exactamente o Nome interno do datasource, maiúsculas incluídas.
  • Porque não vejo o botão Executar agora? O script está inactivo — liga o interruptor no topo.
  • Porque é que a execução foi cortada a meio? Bateu no Tempo limite. Ou o script demora mesmo, e aumentas o limite, ou está a fazer trabalho a mais para o sítio onde é chamado.
  • Porque é que o agendamento nunca correu? Vê, por ordem: o agendamento está Activo? O script está Activo? O agendador está a correr nesta instalação? E o Fuso horário é o que pensas que é?

O CRM está completo. Falta pô-lo no ar: publicar e usar.