Seguidores

sábado, 26 de abril de 2025

Do Caos ao Prompt T4E07: Desenvolvimento do App AG2P – Evento "Decidiu encerrar a jornada"

INTRODUÇÃO

Post anterior: Do Caos ao Prompt T4E06: Desenvolvimento do App AG2P – Evento "Ocorreu um incidente"

    Este Post é o episódio 7 da temporada 4 da série "Do Caos ao Prompt", que apresenta o desenvolvimento do Agente de Gestão de Processo Pessoal (AG2P), tendo como foco o evento "Decidiu encerrar a jornada".


    Evento “Decidiu encerrara a jornada”

    Link da conversa com o Gemini, na qual foi apresentado um Prompt contendo os itens Objetivo, Contexto, Ferramentas e Especificações, para geração do código para implementar o evento
    "Decidiu encerrar a jornada": https://g.co/gemini/share/187fff5e519c


    Comando ao Gemini para solicitar a implementação do evento

    Objetivo, Contexto e Ferramentas

    Clique aqui para  ver os itens Objetivo, Contexto e Ferramentas do Comando.

    Especificações

    Segue abaixo o post da temporada 3 desta série, que contém as especificações do evento "Decidiu encerrar a jornada", que faz parte deste comando:

    Do Caos ao Prompt T3E08: Estrutura do Agente AG2P - Diálogo 6 Evento "Decidiu encerrar a jornada" dispara Ação "Preparar transferência de totais"

    As especificações do evento foram feitas com Finite State Machine (FSM), de tal forma que cada evento pode ser automatizado e testado de forma independente.

    Resposta do Gemini


    /**
     * Automatiza o evento "Decidiu encerrar a jornada".
     *
     * Se o app estiver no estado "RDM Ativa";
     * e se a pessoa disparar o evento “Decidiu encerrar a jornada";
     * o app deverá executar a ação “Preparar transferência de totais”;
     * o app deverá acessar os dados necessários na aba "GPS", da planilha GPS;
     * o app deverá ter o seu comportamento direcionado pelas regras R32 a R34, R45;
     * o app deverá manter o seu estado como "RDM Antes do fim".
     *
     * Após a execução, o app deverá ficar esperando outro evento.
     */
    function decidiuEncerrarJornada() {
      // Nome da planilha principal (GPS) e das abas envolvidas
      const nomePlanilhaGPS = "GPS";
      const nomeAbaRDM = "RDM";
      const nomeAbaXmRP = "XmR P";
      const nomeAbaPareto = "Pareto";

      // Obtém a planilha ativa
      const ss = SpreadsheetApp.getActiveSpreadsheet();

      // Obtém as abas relevantes
      const abaGPS = ss.getSheetByName(nomePlanilhaGPS);
      const abaRDM = ss.getSheetByName(nomeAbaRDM);
      const abaXmRP = ss.getSheetByName(nomeAbaXmRP);
      const abaPareto = ss.getSheetByName(nomeAbaPareto);

      // Verifica o estado atual da RDM (R45)
      const estadoRDM = abaRDM.getRange("T1").getValue();
      if (estadoRDM !== "RDM Ativa") {
        Logger.log("A RDM não está no estado 'RDM Ativa'. O evento não pode ser processado.");
        return;
      }

      // Executa a ação "Preparar transferência de totais"
      prepararTransferenciaTotais(abaGPS, abaRDM, abaXmRP, abaPareto);

      // Mantém o estado da aba RDM como "RDM Antes do fim" (R45)
      abaRDM.getRange("T1").setValue("RDM Antes do fim");

      Logger.log("Evento 'Decidiu encerrar a jornada' processado.");
    }

    /**
     * Ação "Preparar transferência de totais".
     *
     * @param {GoogleAppsScript.Spreadsheet.Sheet} abaGPS Aba "GPS".
     * @param {GoogleAppsScript.Spreadsheet.Sheet} abaRDM Aba "RDM".
     * @param {GoogleAppsScript.Spreadsheet.Sheet} abaXmRP Aba "XmR P".
     * @param {GoogleAppsScript.Spreadsheet.Sheet} abaPareto Aba "Pareto".
     */
    function prepararTransferenciaTotais(abaGPS, abaRDM, abaXmRP, abaPareto) {
      // Verifica se o estado da aba RDM é "RDM Ativa" (R45)
      const estadoRDM = abaRDM.getRange("T1").getValue();
      if (estadoRDM !== "RDM Ativa") {
        Logger.log("Erro: O estado da aba RDM deve ser 'RDM Ativa' para esta ação.");
        return;
      }

      // --- Transferência para a aba XmR P (R32) ---
      transferirDadosXmRP(abaGPS, abaXmRP);

      // --- Transferência para a aba Pareto (R33 e R34) ---
      transferirDadosPareto(abaGPS, abaPareto);

      Logger.log("Ação 'Preparar transferência de totais' concluída.");
    }

    /**
     * Transfere os dados para a aba XmR P de acordo com a regra R32.
     *
     * @param {GoogleAppsScript.Spreadsheet.Sheet} abaGPS Aba "GPS".
     * @param {GoogleAppsScript.Spreadsheet.Sheet} abaXmRP Aba "XmR P".
     */
    function transferirDadosXmRP(abaGPS, abaXmRP) {
      const dadosGPS = abaGPS.getDataRange().getValues();
      const dadosParaXmRP = [];

      // Encontra o índice das colunas relevantes
      const indiceColunaB_GPS = abaGPS.getRange("1:1").getValues()[0].indexOf("Grupo de Processos do Serviço");
      const indiceColunaF_GPS = abaGPS.getRange("1:1").getValues()[0].indexOf("Data Hora Fim");
      const indiceColunaQ_GPS = abaGPS.getRange("1:1").getValues()[0].indexOf("INDICADOR DE PRODUTIVIDADE");

      if (indiceColunaB_GPS === -1 || indiceColunaF_GPS === -1 || indiceColunaQ_GPS === -1) {
        Logger.log("Erro: Colunas necessárias não encontradas na aba GPS para a aba XmR P.");
        return;
      }

      // Itera sobre as linhas da aba GPS (ignora a primeira linha de cabeçalho)
      for (let i = 1; i < dadosGPS.length; i++) {
        const indicadorProdutividade = dadosGPS[i][indiceColunaQ_GPS];
        if (typeof indicadorProdutividade === 'number' && indicadorProdutividade > 0) {
          const dataHoraFim = dadosGPS[i][indiceColunaF_GPS];
          const grupoProcesso = dadosGPS[i][indiceColunaB_GPS];

          // Opção 1 (default): De GPS!F concatenada com GPS!B e separadas com " - ", para XmR P!A e GPS!Q para XmR P!B
          dadosParaXmRP.push([Utilities.formatDate(dataHoraFim, Session.getTimeZone(), "yyyy-MM-dd HH:mm:ss") + " - " + grupoProcesso, indicadorProdutividade]);
          // As outras opções (2 e 3) poderiam ser implementadas aqui com uma interface de usuário para escolha.
          // Por padrão, a Opção 1 está sendo aplicada.
        }
      }

      // Limpa os dados existentes na aba XmR P e escreve os novos dados
      abaXmRP.clearContents();
      if (dadosParaXmRP.length > 0) {
        abaXmRP.getRange(1, 1, dadosParaXmRP.length, 2).setValues(dadosParaXmRP);
        abaXmRP.getRange("A1:B1").setValues([["Tarefa - Processo", "Produtividade"]]); // Adiciona cabeçalho
      } else {
        abaXmRP.getRange("A1").setValue("Nenhum dado de tarefa executável encontrado com produtividade maior que zero.");
      }
    }

    /**
     * Transfere os dados para a aba Pareto de acordo com as regras R33 e R34.
     *
     * @param {GoogleAppsScript.Spreadsheet.Sheet} abaGPS Aba "GPS".
     * @param {GoogleAppsScript.Spreadsheet.Sheet} abaPareto Aba "Pareto".
     */
    function transferirDadosPareto(abaGPS, abaPareto) {
      const dadosGPS = abaGPS.getDataRange().getValues();
      const linhaTotalDefeitos = encontrarLinhaTotalDefeitos(abaGPS);

      // Encontra o índice das colunas de registro de defeitos (K a P)
      const indiceColunaK_GPS = abaGPS.getRange("1:1").getValues()[0].indexOf("D1"); // Coluna K
      const indiceColunaP_GPS = abaGPS.getRange("1:1").getValues()[0].indexOf("D6"); // Coluna P

      if (indiceColunaK_GPS === -1 || indiceColunaP_GPS === -1 || linhaTotalDefeitos === -1) {
        Logger.log("Erro: Colunas de defeitos ou linha 'TOTAL DE DEFEITOS' não encontradas na aba GPS para a aba Pareto.");
        return;
      }

      const totalDefeitos = dadosGPS[linhaTotalDefeitos][indiceColunaK_GPS] !== undefined ? dadosGPS[linhaTotalDefeitos].slice(indiceColunaK_GPS, indiceColunaP_GPS + 1) : [];

      // Limpa os dados existentes na aba Pareto (exceto a linha 5 para o período)
      const numRowsPareto = abaPareto.getLastRow();
      if (numRowsPareto > 1) {
        abaPareto.getRange(2, 1, numRowsPareto - 1, abaPareto.getLastColumn()).clearContent();
      }

      // Transfere a linha TOTAL DE DEFEITOS para a aba Pareto
      if (totalDefeitos.length > 0) {
        abaPareto.getRange(2, 1, 1, totalDefeitos.length).setValues([totalDefeitos]);
        abaPareto.getRange(1, 1, 1, totalDefeitos.length).setValues([["Defeito 1", "Defeito 2", "Defeito 3", "Defeito 4", "Defeito 5", "Defeito 6"]]); // Adiciona cabeçalho
      } else {
        abaPareto.getRange("A2").setValue("Nenhum total de defeitos encontrado.");
      }

      // Define o período de referência na aba Pareto (R34) - Opção 1 (default)
      const primeiraDataGPS = encontrarPrimeiraDataGPS(abaGPS);
      const dataHoje = new Date();
      abaPareto.getRange("C5").setValue(primeiraDataGPS);
      abaPareto.getRange("D5").setValue(dataHoje);
      // A Opção 2 (período informado pelo usuário) exigiria uma interface de usuário para coletar as datas.
    }

    /**
     * Encontra a linha que contém "TOTAL DE DEFEITOS" na primeira coluna da aba GPS.
     *
     * @param {GoogleAppsScript.Spreadsheet.Sheet} abaGPS Aba "GPS".
     * @return {number} O número da linha ou -1 se não encontrado.
     */
    function encontrarLinhaTotalDefeitos(abaGPS) {
      const primeiraColunaGPS = abaGPS.getRange("A:A").getValues();
      for (let i = 0; i < primeiraColunaGPS.length; i++) {
        if (primeiraColunaGPS[i][0] === "TOTAL DE DEFEITOS") {
          return i;
        }
      }
      return -1;
    }

    /**
     * Encontra a primeira data válida na coluna F (Data Hora Fim) da aba GPS.
     *
     * @param {GoogleAppsScript.Spreadsheet.Sheet} abaGPS Aba "GPS".
     * @return {Date|null} A primeira data encontrada ou null se não houver datas válidas.
     */
    function encontrarPrimeiraDataGPS(abaGPS) {
      const colunaDataHoraFim = abaGPS.getRange("F:F").getValues();
      for (let i = 1; i < colunaDataHoraFim.length; i++) {
        const data = colunaDataHoraFim[i][0];
        if (data instanceof Date && !isNaN(data)) {
          return data;
        }
      }
      return null;
    }

    // Para testar a função (será executado no editor do Apps Script)
    // function testDecidiuEncerrarJornada() {
    //   decidiuEncerrarJornada();
    // }

    Explicação do Código:

    1. decidiuEncerrarJornada():

      • Esta é a função principal que representa o evento "Decidiu encerrar a jornada".
      • Define os nomes das planilhas e abas envolvidas.
      • Obtém referências para as abas usando SpreadsheetApp.getActiveSpreadsheet().getSheetByName().
      • Verifica o estado da RDM (R45): Lê o valor da célula "T1" da aba "RDM". Se não for "RDM Ativa", a função é interrompida.
      • Chama prepararTransferenciaTotais(): Executa a lógica para transferir os dados.
      • Atualiza o estado da RDM (R45): Define o valor da célula "T1" da aba "RDM" para "RDM Antes do fim".
      • Usa Logger.log() para registrar informações sobre a execução.
    2. prepararTransferenciaTotais(abaGPS, abaRDM, abaXmRP, abaPareto):

      • Esta função implementa a ação com o mesmo nome.
      • Verifica novamente o estado da RDM (R45) por segurança.
      • Chama as funções transferirDadosXmRP() e transferirDadosPareto() para realizar as transferências de dados para as respectivas abas.
    3. transferirDadosXmRP(abaGPS, abaXmRP):

      • Obtém todos os dados da aba "GPS".
      • Encontra os índices das colunas "Grupo de Processos do Serviço" (B), "Data Hora Fim" (F) e "INDICADOR DE PRODUTIVIDADE" (Q) na primeira linha (cabeçalho).
      • Itera pelas linhas de dados da aba "GPS" (começando da segunda linha para ignorar o cabeçalho).
      • Filtra por indicador de produtividade (R32): Verifica se o valor na coluna Q é um número e maior que zero.
      • Aplica a formatação (Opção 1 - default) (R32): Concatena a "Data Hora Fim" formatada com o "Grupo de Processos do Serviço" e adiciona o "INDICADOR DE PRODUTIVIDADE" a um array dadosParaXmRP.
      • Limpa e escreve os dados na aba "XmR P": Remove o conteúdo existente e, se houver dados a serem transferidos, escreve-os na aba, adicionando um cabeçalho.
    4. transferirDadosPareto(abaGPS, abaPareto):

      • Obtém todos os dados da aba "GPS".
      • Chama encontrarLinhaTotalDefeitos() para localizar a linha com "TOTAL DE DEFEITOS".
      • Encontra os índices das colunas de registro de defeitos (K a P).
      • Extrai os valores da linha "TOTAL DE DEFEITOS" para as colunas K a P.
      • Limpa e escreve os dados na aba "Pareto": Remove o conteúdo existente (exceto a linha 5) e escreve os totais de defeitos, adicionando um cabeçalho.
      • Define o período de referência (R34 - Opção 1): Encontra a primeira data na coluna "Data Hora Fim" da aba "GPS" usando encontrarPrimeiraDataGPS() e define as datas inicial e final na linha 5 da aba "Pareto" (colunas C e D).
    5. encontrarLinhaTotalDefeitos(abaGPS):

      • Itera pela primeira coluna da aba "GPS" para encontrar a célula com o valor "TOTAL DE DEFEITOS".
      • Retorna o número da linha ou -1 se não encontrado.
    6. encontrarPrimeiraDataGPS(abaGPS):

      • Itera pela coluna "Data Hora Fim" da aba "GPS" para encontrar a primeira célula que contém uma data válida.
      • Retorna a data ou null se nenhuma data válida for encontrada.

    Como Usar:

    1. Abra sua planilha do Google Sheets.
    2. Vá em "Ferramentas" > "Editor de script".
    3. Cole o código acima no editor.
    4. Salve o script (dê um nome a ele, por exemplo, AutomacaoGPS).
    5. Para executar a função decidiuEncerrarJornada (simulando o evento), você pode:
      • Executá-la diretamente do editor de script (selecione a função decidiuEncerrarJornada no menu suspenso de execução e clique no botão "Executar").
      • Você pode vincular essa função a um botão na sua planilha ou a um evento de menu personalizado para simular a interação do usuário com o "app".

    Observações Importantes:

    • Nomes das Abas e Colunas: Certifique-se de que os nomes das abas ("GPS", "RDM", "XmR P", "Pareto") e os cabeçalhos das colunas na aba "GPS" ("Grupo de Processos do Serviço", "Data Hora Fim", "INDICADOR DE PRODUTIVIDADE", "D1" a "D6") correspondam exatamente aos definidos no código. Caso contrário, o script não funcionará corretamente.
    • Estado da RDM: A lógica depende da célula "T1" na aba "RDM" conter o estado atual do "app".
    • Opções de Formatação e Período: O código implementa a Opção 1 (default) para a formatação da aba "XmR P" e para a definição do período na aba "Pareto". A implementação das Opções 2 e 3 exigiria a criação de uma interface de usuário (usando SpreadsheetApp.getUi()) para permitir que o usuário fizesse essas escolhas.
    • Tratamento de Erros: O código inclui alguns Logger.log() para registrar informações e erros. Em um ambiente de produção, você pode querer implementar um tratamento de erros mais robusto.
    • Linha "TOTAL DE DEFEITOS": O script assume que a linha com o total de defeitos contém a string "TOTAL DE DEFEITOS" na primeira

    Pedido de verificação da resposta ao Gemini

    Parece que a resposta anterior foi interrompida. 

    Verifique se há algum texto após este último: 

    Linha "TOTAL DE DEFEITOS": O script assume que a linha com o total de defeitos contém a string "TOTAL DE DEFEITOS" na primeira

    Resposta do Gemini


    Você tem razão! A resposta anterior foi interrompida abruptamente. Peço desculpas por isso. Vamos continuar de onde paramos:

    "... coluna da aba "GPS". Certifique-se de que essa string esteja presente na sua planilha para que o script possa identificar corretamente os dados de defeitos para a aba "Pareto"."

    Próximos Passos e Melhorias Possíveis:

    • Interface de Usuário: Para tornar a interação mais amigável, você pode criar um menu personalizado na planilha ou caixas de diálogo (SpreadsheetApp.getUi()) para:
      • Disparar o evento "Decidiu encerrar a jornada".
      • Permitir que o usuário escolha as opções de formatação para a aba "XmR P" (Opção 2 e 3 da regra R32).
      • Permitir que o usuário defina o período para a aba "Pareto" (Opção 2 da regra R33).
    • Tratamento de Erros Aprimorado: Implementar blocos try...catch para lidar com possíveis erros durante a execução do script (por exemplo, se as abas não forem encontradas) e fornecer mensagens de erro mais informativas ao usuário.
    • Validação de Dados: Adicionar verificações para garantir que os dados nas colunas esperadas da aba "GPS" estejam no formato correto.
    • Comentários Detalhados: Incluir mais comentários no código para explicar cada etapa da lógica, facilitando a manutenção e o entendimento.
    • Modularização: Se o script se tornar muito grande, considere dividi-lo em funções menores e mais focadas para melhorar a organização e a legibilidade.
    • Testes: Escrever funções de teste para verificar se cada parte do script está funcionando conforme o esperado.

    Espero que esta continuação seja útil! Se tiver mais alguma dúvida ou precisar de ajuda com alguma das melhorias sugeridas, me diga.

    CONCLUSÃO

    Neste episódio 7, da temporada 4 da série "Do Caos ao Prompt", foi apresentada a implementação do Evento "Decidiu encerrar a jornada", realizada pelo Chatbot de IA Gemini 2.0 Flash.

    As especificações do evento foram feitas em Finite State Machine (FSM).

    Próximo post: Do Caos ao Prompt T4E08: Desenvolvimento do App AG2P – Evento "Executou tarefa em hora extra"

    Veja a lista de Episódios da Temporada 4 da Série "Do Caos ao Prompt", no final do Episódio T4E01.

    Nenhum comentário:

    Postar um comentário

    Entendendo a Metáfora "Home Office é Moto Boy"

    Dashboard de Produtividade Pessoal T1E14: RESOLVIDO BugCT1-5 Erro 400 no login

    INTRODUÇÃO Post anterior:  Dashboard de Produtividade Pessoal T1E13: BugCT1-5 Erro 400 no login O objetivo deste post é apresentar um prompt...