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"

    UCEM L-pI.219 (199) Revisão VI - Caso de uso da IA para estudar

      Lição 219  Eu não sou um corpo. Eu sou livre.  Pois ainda sou como Deus me criou. Lição anterior Escolher outra lição Próxima lição Texto ...