Seguidores

quinta-feira, 24 de abril de 2025

Do Caos ao Prompt T4E04: Desenvolvimento do App AG2P – Evento "Iniciou tarefa do negócio"

INTRODUÇÃO

Post anterior: Do Caos ao Prompt T4E03: Desenvolvimento do App AG2P – Evento "Recebeu lista de tarefas a fazer"

    Este Post é o episódio 4 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 "Iniciou tarefa do negócio".


    Evento “Iniciou tarefa do negócio”

    Link da conversa com o Gemini:  https://g.co/gemini/share/96c8edbe0bea

     

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

    Escreva o código para implementação do evento "Iniciou tarefa do negócio", usando apenas ferramentas do Google Workspace, conforme as especificações abaixo, que utilizam Finite State Machine (FSM).

     

    Evento "Iniciou tarefa do negócio"

    Se o app estiver no estado "RDM Ativa";

    e se a pessoa disparar o evento “Iniciou tarefa do negócio";

    o app deverá executar a ação “Executar tarefa do negócio”;

    o app deverá acessar os dados necessários do próprio processo do negócio; 

    o app deverá ter o seu comportamento direcionado pelas regras do negócio"; 

    o app deverá manter o seu estado como "RDM Ativa".

     

    Após a execução, o agente AG2P deverá ficar esperando outro evento. 

     

    Mas, durante a execução, o usuário pode ter necessidade de interromper a tarefa do negócio, uma ou várias vezes.

     

    Essas interrupções causam distorções na medição do tempo de duração da tarefa do negócio, consequentemente, prejudicando o cálculo da produtividade.

     

    O agente AG2P, em parceria com o usuário, é capaz de administrar esse tempo de interrupções e, para isso, foram criados dois eventos que o usuário dispara a fim de parar ou reiniciar a medição do tempo de execução da tarefa.

     

    Esses eventos são identificados por:

    • Interrompeu a tarefa do negócio e
    • Reiniciou a tarefa do negócio.

     

    Ação "Executar tarefa do negócio"

    Preparação e Informações Necessárias

    1. Dados: O estado da aba RDM deve estar igual a "RDM Ativa".

    Passos do diálogo 3 entre o usuário e o agente

    1. Agente AG2P:
      O agente AG2P deve apresentar a lista de tarefas planejadas para o dia, para o usuário selecionar o código e o nome da tarefa a executar.
    2. Usuário:
      O usuário deve selecionar a tarefa a executar, conforme o fluxo do processo.
    3. Agente AG2P:
      O agente AG2P deve registrar na aba GPS, na coluna E(Data Hora Início), a data e hora de início da execução da tarefa.

      O agente AG2P deve zerar na aba GPS, a coluna H(Paradas (HH:MM:SS)), que conterá a duração total das paradas que ocorrerem durante a execução da tarefa.

      O agente AG2P deve mostrar na interface com o usuário um botão com o rótulo "Tarefa em execução!" e uma checkbox, desmarcada, com o rótulo "Tarefa concluída!". 
    4. Usuário:
      Quando não houver interrupção, o usuário deverá executar a tarefa até o fim e quando terminar, deverá marcar a checkbox "Tarefa concluída!". (R53) Neste caso:
      Agente AG2P:
      O agente AG2P deve desabilitar o botão "Tarefa em execução!", mudar o rótulo para "Tarefa Concluída!" e registrar a data hora de conclusão na aba GPS, na coluna F(Data Hora Fim).

      O agente AG2P deve calcular a duração da execução como coluna F(Data Hora Fim) menos E(Data Hora Início) menos H(Paradas(HH:MM:SS)) e registrar o resultado na coluna G(Duração (HH:MM:SS)).

      O agente AG2P deve voltar para o Passo 1, a fim de mostrar a lista de tarefas para o usuário escolher mais uma.

    Passos do diálogo 3 com interrupções da tarefa do negócio

    O objetivo dos eventos "Interrompeu a tarefa do negócio" e "Reiniciou a tarefa do negócio", é garantir ao usuário a medição precisa do tempo de duração da tarefa, dando-lhe liberdade de interromper a tarefa quantas vezes precisar, sem estresse.

     

    Para isso, o usuário precisa disparar os eventos citados acima, para que o agente AG2P execute as ações adequadas. Resumindo:

    • Evento "Interrompeu a tarefa do negócio" dispara Ação "Parar medição do tempo" e 
    • Evento "Reiniciou a tarefa do negócio" dispara Ação "Continuar medição do tempo".

    Passos com interrupções

    1. Usuário:
      O usuário deve clicar no botão cujo rótulo é "Tarefa em execução!", para interromper. (R51)
    2.  Agente AG2P:
      O agente AG2P deve mudar o rótulo do botão para "Tarefa interrompida!". (R51)

      O agente AG2P deve registrar a data e hora da interrupção da execução na variável interna  denominada HORA DA INTERRUPÇÃO.
    3. Usuário:
      Quando houver reinício, então o usuário deve clicar no botão cujo rótulo estará igual a "Tarefa interrompida!". (R52)
    4. Agente AG2P:
      O agente AG2P deve mudar o rótulo do botão para "Tarefa em execução!". (R52)

      O agente AG2P deve registrar a data e hora do reinício da execução na variável interna  denominada HORA DO REINÍCIO.

      O agente AG2P deve adicionar na aba GPS, na coluna H(Paradas (HH:MM:SS)) o valor que resulta do cálculo HORA DO REINÍCIO menos HORA DA INTERRUPÇÃO.

     

    O agente AG2P deve limpar as variáveis internas INTERRUPÇÃO e REINÍCIO.

     

    Usuário:

    Após uma ou várias interrupções, quando chegar ao fim da tarefa, o usuário deve ir para o Passo 4.

    Resultados Esperados

    1. Na aba RDM, a célula T1 deve conter o estado "RDM Ativa".

    Ações em Caso de Problema

    1. Revisar o que foi feito no contexto desta Ação.
    2. Solicitar ajuda à pessoa responsável pelo Suporte na Organização.

    Atenção Especial

    1. Atenção especial para as tarefas pendentes há mais de 2 dias.
    2. O estado da aba RDM deve estar igual a "RDM Ativa".

    Dados acessados na Planilha GPS

    1. Na aba GPS, a coluna R(Plano do Dia)
    2. Na aba GPS, a coluna B(Tarefa executável do negócio). Tarefa executável é aquela que tem o tamanho em pontos registrado na coluna C(Tamanho em Pontos).
    3. Na aba GPS, a coluna E(Data Hora Início).
    4. Na aba GPS, a coluna F(Data Hora Fim).
    5. Na aba GPS, a coluna G(Duração).
    6. Na aba GPS, a coluna H(Paradas).

    Regras para medição da duração da execução de uma tarefa do negócio

    Identificação das Regras: R51 a R54.

    R51: O botão "Tarefa em execução!" pode mudar para "Tarefa interrompida!", somente se o usuário clicar no mesmo.

    R52: O botão "Tarefa interrompida" pode mudar para "Tarefa em execução!", somente se o usuário clicar no mesmo.".

    R53: O botão "Tarefa em execução!" pode mudar para "Tarefa concluída!", somente se o usuário marcar a checkbox "Tarefa concluída".

    R54: O botão "Tarefa concluída!" pode mudar para "Tarefa em execução", somente se o usuário desmarcar a checkbox "Tarefa concluída".

    Resposta do Gemini

    Python

    import datetime

    from enum import Enum

     

    # --- Configurações (simulando acesso a dados do Google Sheets) ---

    SHEET_RDM_ID = "ID_DA_SUA_PLANILHA_RDM"

    ABA_RDM = "RDM"

    CELULA_ESTADO_RDM = "T1"

     

    SHEET_GPS_ID = "ID_DA_SUA_PLANILHA_GPS"

    ABA_GPS = "GPS"

    COLUNA_PLANO_DIA = "R"

    COLUNA_TAREFA_EXECUTAVEL = "B"

    COLUNA_TAMANHO_PONTOS = "C"

    COLUNA_DATA_HORA_INICIO = "E"

    COLUNA_DATA_HORA_FIM = "F"

    COLUNA_DURACAO = "G"

    COLUNA_PARADAS = "H"

     

    # --- Simulação de acesso a dados (substituir por Google Sheets API) ---

    dados_rdm = {ABA_RDM: {CELULA_ESTADO_RDM: "RDM Ativa"}}

    dados_gps = {

        ABA_GPS: [

            {"R": "Tarefa 1", "B": "Análise de Requisitos", "C": 5},

            {"R": "Tarefa 2", "B": "Desenvolvimento da Feature X", "C": 10},

            {"R": "Tarefa 3", "B": "Teste de Integração", "C": 8},

        ]

    }

     

    def ler_celula(sheet_id, aba, celula):

        """Simula a leitura de uma célula do Google Sheets."""

        if sheet_id == SHEET_RDM_ID and aba == ABA_RDM and celula == CELULA_ESTADO_RDM:

            return dados_rdm[aba][celula]

        # Implementar lógica para ler outras células se necessário

        return None

     

    def escrever_celula(sheet_id, aba, celula, valor):

        """Simula a escrita em uma célula do Google Sheets."""

        if sheet_id == SHEET_RDM_ID and aba == ABA_RDM and celula == CELULA_ESTADO_RDM:

            dados_rdm[aba][celula] = valor

        elif sheet_id == SHEET_GPS_ID and aba == ABA_GPS:

            # Lógica para encontrar a linha correta e atualizar a célula

            pass

        print(f"Escrevendo '{valor}' em {aba}!{celula} da planilha {sheet_id}")

     

    def obter_ultima_linha_vazia(sheet_id, aba, coluna):

        """Simula a obtenção da última linha vazia em uma coluna."""

        if sheet_id == SHEET_GPS_ID and aba == ABA_GPS:

            return len(dados_gps[aba]) + 1 # Simples simulação

        return None

     

    def adicionar_linha(sheet_id, aba, dados_linha):

        """Simula a adição de uma nova linha no Google Sheets."""

        if sheet_id == SHEET_GPS_ID and aba == ABA_GPS:

            dados_gps[aba].append(dados_linha)

            print(f"Adicionando linha em {aba}: {dados_linha}")

     

    # --- Finite State Machine para o Agente AG2P ---

    class EstadoAG2P(Enum):

        OCIOSO = 1

        RDM_ATIVA = 2

        TAREFA_EM_EXECUCAO = 3

        TAREFA_INTERROMPIDA = 4

        TAREFA_CONCLUIDA = 5

     

    class AgenteAG2P:

        def __init__(self):

            self.estado = EstadoAG2P.OCIOSO

            self.tarefa_atual = None

            self.hora_inicio = None

            self.hora_interrupcao = None

            self.total_paradas = datetime.timedelta(0)

            self.interface_usuario = InterfaceUsuario(self) # Simula a interface

     

        def iniciar_rdm(self):

            """Simula a ativação do estado RDM."""

            estado_rdm = ler_celula(SHEET_RDM_ID, ABA_RDM, CELULA_ESTADO_RDM)

            if estado_rdm == "RDM Ativa":

                self.estado = EstadoAG2P.RDM_ATIVA

                self.interface_usuario.mostrar_lista_tarefas()

            else:

                print("Erro: RDM não está ativa.")

     

        def iniciou_tarefa_negocio(self, codigo_tarefa):

            """Evento: Iniciou tarefa do negócio."""

            if self.estado == EstadoAG2P.RDM_ATIVA:

                # Ação: Executar tarefa do negócio

                self.executar_tarefa_negocio(codigo_tarefa)

                self.estado = EstadoAG2P.TAREFA_EM_EXECUCAO

                self.interface_usuario.atualizar_interface_tarefa_execucao()

            else:

                print("Aviso: O agente não está no estado 'RDM Ativa'.")

     

        def executar_tarefa_negocio(self, codigo_tarefa):

            """Ação: Executar tarefa do negócio."""

            # Acessar dados da tarefa

            for tarefa in dados_gps[ABA_GPS]:

                if tarefa["R"] == codigo_tarefa and tarefa["C"] is not None:

                    self.tarefa_atual = tarefa

                    break

            if not self.tarefa_atual:

                print(f"Erro: Tarefa com código '{codigo_tarefa}' não encontrada ou não executável.")

                return

     

            # Registrar data e hora de início

            self.hora_inicio = datetime.datetime.now()

            linha_gps = dados_gps[ABA_GPS].index(self.tarefa_atual) + 1

            escrever_celula(SHEET_GPS_ID, ABA_GPS, f"{COLUNA_DATA_HORA_INICIO}{linha_gps}", self.hora_inicio.strftime("%Y-%m-%d %H:%M:%S"))

     

            # Zerar paradas

            escrever_celula(SHEET_GPS_ID, ABA_GPS, f"{COLUNA_PARADAS}{linha_gps}", "00:00:00")

            self.total_paradas = datetime.timedelta(0)

     

            print(f"Tarefa '{self.tarefa_atual['B']}' iniciada.")

     

        def interrompeu_tarefa_negocio(self):

            """Evento: Interrompeu a tarefa do negócio."""

            if self.estado == EstadoAG2P.TAREFA_EM_EXECUCAO:

                # Ação: Parar medição do tempo

                self.parar_medicao_tempo()

                self.estado = EstadoAG2P.TAREFA_INTERROMPIDA

                self.interface_usuario.atualizar_interface_tarefa_interrompida()

            else:

                print("Aviso: Nenhuma tarefa em execução para interromper.")

     

        def parar_medicao_tempo(self):

            """Ação: Parar medição do tempo."""

            self.hora_interrupcao = datetime.datetime.now()

            print(f"Tarefa interrompida às {self.hora_interrupcao.strftime('%H:%M:%S')}.")

     

        def reiniciou_tarefa_negocio(self):

            """Evento: Reiniciou a tarefa do negócio."""

            if self.estado == EstadoAG2P.TAREFA_INTERROMPIDA:

                # Ação: Continuar medição do tempo

                self.continuar_medicao_tempo()

                self.estado = EstadoAG2P.TAREFA_EM_EXECUCAO

                self.interface_usuario.atualizar_interface_tarefa_execucao()

            else:

                print("Aviso: Nenhuma tarefa interrompida para reiniciar.")

     

        def continuar_medicao_tempo(self):

            """Ação: Continuar medição do tempo."""

            if self.hora_interrupcao:

                hora_reinicio = datetime.datetime.now()

                duracao_parada = hora_reinicio - self.hora_interrupcao

                self.total_paradas += duracao_parada

     

                linha_gps = dados_gps[ABA_GPS].index(self.tarefa_atual) + 1

                escrever_celula(SHEET_GPS_ID, ABA_GPS, f"{COLUNA_PARADAS}{linha_gps}", str(self.total_paradas))

     

                self.hora_interrupcao = None

                print(f"Tarefa reiniciada às {hora_reinicio.strftime('%H:%M:%S')}. Parada de {duracao_parada} registrada.")

            else:

                print("Erro: Nenhuma hora de interrupção registrada.")

     

        def tarefa_concluida(self):

            """Evento (via checkbox): Tarefa concluída."""

            if self.estado == EstadoAG2P.TAREFA_EM_EXECUCAO:

                # Ações ao concluir a tarefa

                hora_fim = datetime.datetime.now()

                duracao_execucao = hora_fim - self.hora_inicio - self.total_paradas

     

                linha_gps = dados_gps[ABA_GPS].index(self.tarefa_atual) + 1

                escrever_celula(SHEET_GPS_ID, ABA_GPS, f"{COLUNA_DATA_HORA_FIM}{linha_gps}", hora_fim.strftime("%Y-%m-%d %H:%M:%S"))

                escrever_celula(SHEET_GPS_ID, ABA_GPS, f"{COLUNA_DURACAO}{linha_gps}", str(duracao_execucao).split('.')[0]) # Remove microssegundos

     

                self.estado = EstadoAG2P.OCIOSO

                self.tarefa_atual = None

                self.hora_inicio = None

                self.hora_interrupcao = None

                self.total_paradas = datetime.timedelta(0)

                self.interface_usuario.atualizar_interface_tarefa_concluida()

                self.interface_usuario.mostrar_lista_tarefas()

                print(f"Tarefa concluída às {hora_fim.strftime('%H:%M:%S')}. Duração: {duracao_execucao}.")

            else:

                print("Aviso: Nenhuma tarefa em execução para marcar como concluída.")

     

    # --- Simulação da Interface do Usuário (usando Google Apps Script UI Service seria o real) ---

    class InterfaceUsuario:

        def __init__(self, agente):

            self.agente = agente

            self.tarefa_em_execucao_botao = None

            self.tarefa_concluida_checkbox = None

     

        def mostrar_lista_tarefas(self):

            print("\n--- Lista de Tarefas Planejadas ---")

            for tarefa in dados_gps[ABA_GPS]:

                if tarefa["C"] is not None: # Apenas tarefas executáveis

                    print(f"- Código: {tarefa['R']}, Nome: {tarefa['B']}")

            codigo_selecionado = input("Digite o código da tarefa para iniciar: ")

            self.agente.iniciou_tarefa_negocio(codigo_selecionado)

     

        def atualizar_interface_tarefa_execucao(self):

            self.tarefa_em_execucao_botao = "Tarefa em execução!"

            self.tarefa_concluida_checkbox = False

            print(f"\nBotão: '{self.tarefa_em_execucao_botao}', Checkbox 'Tarefa concluída!': {self.tarefa_concluida_checkbox}")

            acao = input("Digite 'interromper' ou 'concluir': ")

            if acao == "interromper":

                self.agente.interrompeu_tarefa_negocio()

            elif acao == "concluir":

                self.agente.tarefa_concluida()

     

        def atualizar_interface_tarefa_interrompida(self):

            if self.tarefa_em_execucao_botao == "Tarefa em execução!":

                self.tarefa_em_execucao_botao = "Tarefa interrompida!"

                print(f"Botão: '{self.tarefa_em_execucao_botao}'")

            acao = input("Digite 'reiniciar': ")

            if acao == "reiniciar":

                self.agente.reiniciou_tarefa_negocio()

     

        def atualizar_interface_tarefa_concluida(self):

            if self.tarefa_em_execucao_botao == "Tarefa em execução!" or self.tarefa_em_execucao_botao == "Tarefa interrompida!":

                self.tarefa_em_execucao_botao = "Tarefa Concluída!"

                self.tarefa_concluida_checkbox = True

                print(f"Botão: '{self.tarefa_em_execucao_botao}', Checkbox 'Tarefa concluída!': {self.tarefa_concluida_checkbox}")

     

    # --- Inicialização e Simulação ---

    if __name__ == "__main__":

        agente = AgenteAG2P()

        agente.iniciar_rdm()

     

        # Simulação de interrupções e conclusão

        # (A interação real seria via interface do usuário simulada)

        # agente.interrompeu_tarefa_negocio()

        # agente.reiniciou_tarefa_negocio()

        # agente.tarefa_concluida()

    Explicação do Código e Como Usar no Google Workspace (Google Apps Script):

    Este código foi estruturado em Python para facilitar a compreensão da lógica da Máquina de Estados Finita (FSM) e das ações do agente AG2P. Para implementá-lo no Google Workspace, você precisará usar o Google Apps Script, que é baseado em JavaScript.

    Passos para Implementação no Google Apps Script:

    1. Abra o Editor de Script:
      • Abra sua planilha do Google Sheets.
      • Vá em "Extensões" > "Apps Script".
    2. Copie e Adapte o Código:
      • Copie a lógica principal da classe AgenteAG2P e da enumeração EstadoAG2P.
      • Adapte a forma como os dados são acessados e modificados no Google Sheets usando as funções do SpreadsheetApp do Google Apps Script.
      • Crie uma interface de usuário usando o HtmlService ou o SpreadsheetApp.getUi() para interagir com o usuário (botões, checkboxes).

    Adaptações Específicas para Google Apps Script:

    • Acesso aos Dados do Google Sheets:
      • Substitua as funções de simulação (ler_celula, escrever_celula, obter_ultima_linha_vazia, adicionar_linha) pelas funções reais do Google Apps Script:
        • SpreadsheetApp.getActiveSpreadsheet().getSheetByName("NomeDaAba").getRange("Celula").getValue() para ler.
        • SpreadsheetApp.getActiveSpreadsheet().getSheetByName("NomeDaAba").getRange("Celula").setValue(valor) para escrever.
        • SpreadsheetApp.getActiveSpreadsheet().getSheetByName("NomeDaAba").getLastRow() + 1 para obter a próxima linha vazia (com cuidado para colunas específicas).
        • SpreadsheetApp.getActiveSpreadsheet().getSheetByName("NomeDaAba").appendRow([valor1, valor2, ...]) para adicionar uma nova linha.
    • Interface do Usuário:
      • Use SpreadsheetApp.getUi() para caixas de diálogo simples, alertas e prompts.
      • Para uma interface mais rica com botões e checkboxes dentro da planilha ou em uma sidebar/modal, use o HtmlService. Você precisará criar arquivos HTML e JavaScript para a interface e interagir com o código do Apps Script usando google.script.run.
    • Variáveis de Estado:
      • As variáveis de estado do agente (self.estado, self.tarefa_atual, self.hora_inicio, etc.) precisarão ser gerenciadas dentro do seu script do Apps Script. Você pode usar variáveis globais dentro do script ou armazenar informações de estado de forma mais persistente (por exemplo, em propriedades do usuário/documento/script).
    • Eventos (Triggers):
      • Os eventos ("Iniciou tarefa do negócio", "Interrompeu a tarefa do negócio", "Reiniciou a tarefa do negócio") serão acionados por interações do usuário na interface que você criar (cliques em botões, marcação de checkboxes). As funções correspondentes no seu script do Apps Script serão chamadas por essas interações.

    Exemplo Básico de Acesso ao Sheets no Apps Script:

    JavaScript

    function lerEstadoRDM() {

      var ss = SpreadsheetApp.getActiveSpreadsheet();

      var rdmSheet = ss.getSheetByName("RDM");

      return rdmSheet.getRange("T1").getValue();

    }

     

    function escreverDataInicioGPS(linha, dataHora) {

      var ss = SpreadsheetApp.getActiveSpreadsheet();

      var gpsSheet = ss.getSheetByName("GPS");

      gpsSheet.getRange("E" + linha).setValue(dataHora);

    }

     

    // ... outras funções de acesso ao Sheets ...

    Exemplo Básico de Interface com SpreadsheetApp.getUi():

    JavaScript

    function mostrarListaDeTarefas() {

      var ui = SpreadsheetApp.getUi();

      var result = ui.prompt(

          'Iniciar Tarefa',

          'Digite o código da tarefa para iniciar:',

          ui.ButtonSet.OK_CANCEL);

     

      if (result.getSelectedButton

     

    Comando para solicitar o código em Javascript

    Na implementação dos eventos anteriores, você escreveu o código em Javascript, portanto, vamos continuar nesta linguagem.

    Resposta do Gemini

    Excelente! Continuaremos a implementação do evento "Iniciou tarefa do negócio" utilizando Google Apps Script (JavaScript), conforme as especificações e mantendo a lógica da Máquina de Estados Finita (FSM).

    JavaScript

    // --- Configurações (IDs e nomes das abas/colunas) ---

    const SHEET_RDM_ID = SpreadsheetApp.getActiveSpreadsheet().getId();

    const ABA_RDM = "RDM";

    const CELULA_ESTADO_RDM = "T1";

     

    const SHEET_GPS_ID = SpreadsheetApp.getActiveSpreadsheet().getId();

    const ABA_GPS = "GPS";

    const COLUNA_PLANO_DIA = "R";

    const COLUNA_TAREFA_EXECUTAVEL = "B";

    const COLUNA_TAMANHO_PONTOS = "C";

    const COLUNA_DATA_HORA_INICIO = "E";

    const COLUNA_DATA_HORA_FIM = "F";

    const COLUNA_DURACAO = "G";

    const COLUNA_PARADAS = "H";

     

    // --- Enumeração para o Estado do Agente AG2P ---

    const EstadoAG2P = {

      OCIOSO: 1,

      RDM_ATIVA: 2,

      TAREFA_EM_EXECUCAO: 3,

      TAREFA_INTERROMPIDA: 4,

      TAREFA_CONCLUIDA: 5

    };

     

    // --- Variáveis Globais para o Estado do Agente ---

    let estadoAgente = EstadoAG2P.OCIOSO;

    let tarefaAtual = null;

    let horaInicio = null;

    let horaInterrupcao = null;

    let totalParadas = 0; // Armazenar em milissegundos para facilitar cálculos de tempo

     

    /**

     * Função para ler o estado da aba RDM.

     * @return {string} O valor da célula de estado da RDM.

     */

    function lerEstadoRDM() {

      const ss = SpreadsheetApp.getActiveSpreadsheet();

      const rdmSheet = ss.getSheetByName(ABA_RDM);

      return rdmSheet.getRange(CELULA_ESTADO_RDM).getValue();

    }

     

    /**

     * Função para escrever um valor em uma célula da aba GPS.

     * @param {number} linha O número da linha.

     * @param {string} coluna A letra da coluna.

     * @param {any} valor O valor a ser escrito.

     */

    function escreverCelulaGPS(linha, coluna, valor) {

      const ss = SpreadsheetApp.getActiveSpreadsheet();

      const gpsSheet = ss.getSheetByName(ABA_GPS);

      gpsSheet.getRange(coluna + linha).setValue(valor);

    }

     

    /**

     * Função para obter a lista de tarefas executáveis do dia.

     * @return {Array<Object>} Uma array de objetos contendo código e nome das tarefas.

     */

    function obterTarefasExecutaveis() {

      const ss = SpreadsheetApp.getActiveSpreadsheet();

      const gpsSheet = ss.getSheetByName(ABA_GPS);

      const lastRow = gpsSheet.getLastRow();

      const planoDoDia = gpsSheet.getRange(1, COLUNA_PLANO_DIA + "1:" + COLUNA_PLANO_DIA + lastRow).getValues().flat();

      const tarefasExecutaveis = gpsSheet.getRange(1, COLUNA_TAREFA_EXECUTAVEL + "1:" + COLUNA_TAREFA_EXECUTAVEL + lastRow).getValues().flat();

      const tamanhos = gpsSheet.getRange(1, COLUNA_TAMANHO_PONTOS + "1:" + COLUNA_TAMANHO_PONTOS + lastRow).getValues().flat();

      const listaTarefas = [];

     

      for (let i = 0; i < planoDoDia.length; i++) {

        if (planoDoDia[i] && tarefasExecutaveis[i] && tamanhos[i] !== null && tamanhos[i] !== undefined && tamanhos[i] !== '') {

          listaTarefas.push({ codigo: planoDoDia[i], nome: tarefasExecutaveis[i] });

        }

      }

      return listaTarefas;

    }

     

    /**

     * Função para apresentar a lista de tarefas planejadas ao usuário e iniciar uma.

     */

    function apresentarListaEIniciarTarefa() {

      const ui = SpreadsheetApp.getUi();

      const tarefas = obterTarefasExecutaveis();

      if (tarefas.length === 0) {

        ui.alert("Nenhuma tarefa planejada para o dia.");

        estadoAgente = EstadoAG2P.RDM_ATIVA; // Mantém o estado

        return;

      }

     

      let promptStr = "Selecione o código da tarefa para executar:\n";

      tarefas.forEach(tarefa => {

        promptStr += `- ${tarefa.codigo}: ${tarefa.nome}\n`;

      });

      const result = ui.prompt("Iniciar Tarefa", promptStr, ui.ButtonSet.OK_CANCEL);

     

      if (result.getSelectedButton() === ui.Button.OK) {

        const codigoTarefaSelecionada = result.getResponseText().trim();

        const tarefaEncontrada = tarefas.find(tarefa => tarefa.codigo === codigoTarefaSelecionada);

        if (tarefaEncontrada) {

          iniciouTarefaNegocio(tarefaEncontrada);

        } else {

          ui.alert(`Código de tarefa "${codigoTarefaSelecionada}" inválido.`);

          estadoAgente = EstadoAG2P.RDM_ATIVA; // Mantém o estado

        }

      } else {

        estadoAgente = EstadoAG2P.RDM_ATIVA; // Mantém o estado

      }

    }

     

    /**

     * Evento: "Iniciou tarefa do negócio".

     * @param {Object} tarefa A tarefa a ser iniciada (contendo código e nome).

     */

    function iniciouTarefaNegocio(tarefa) {

      if (estadoAgente === EstadoAG2P.RDM_ATIVA) {

        // Ação: "Executar tarefa do negócio"

        executarTarefaNegocio(tarefa);

        estadoAgente = EstadoAG2P.TAREFA_EM_EXECUCAO;

        atualizarInterfaceTarefaExecucao();

      } else {

        Logger.log("Aviso: O agente não está no estado 'RDM Ativa'. Estado atual: " + getEstadoAgenteString());

        SpreadsheetApp.getUi().alert("Aviso", "Não é possível iniciar a tarefa agora. O sistema não está pronto.", SpreadsheetApp.getUi().ButtonSet.OK);

        // Manter o estado como "RDM Ativa" conforme especificado

      }

      // Após a execução, o agente AG2P deverá ficar esperando outro evento. (Implícito no fluxo)

    }

     

    /**

     * Ação: "Executar tarefa do negócio".

     * @param {Object} tarefa A tarefa a ser executada (contendo código e nome).

     */

    function executarTarefaNegocio(tarefa) {

      tarefaAtual = tarefa;

     

      // Acessar os dados necessários do próprio processo do negócio (já feito ao obter a lista)

      // O comportamento será direcionado pelas regras de negócio (implementadas nas funções de evento/ação)

     

      // Registrar na aba GPS, na coluna E(Data Hora Início), a data e hora de início

      horaInicio = new Date();

      const linhaTarefa = encontrarLinhaTarefaGPS(tarefaAtual.codigo);

      if (linhaTarefa) {

        escreverCelulaGPS(linhaTarefa, COLUNA_DATA_HORA_INICIO, horaInicio);

     

        // Zerar na aba GPS, a coluna H(Paradas (HH:MM:SS))

        escreverCelulaGPS(linhaTarefa, COLUNA_PARADAS, formatTime(0));

        totalParadas = 0; // Reinicia o contador de paradas

     

        Logger.log(`Tarefa "${tarefaAtual.nome}" (código: ${tarefaAtual.codigo}) iniciada em ${horaInicio}.`);

      } else {

        SpreadsheetApp.getUi().alert("Erro", `Não foi possível encontrar a linha da tarefa "${tarefaAtual.codigo}" na aba GPS.`, SpreadsheetApp.getUi().ButtonSet.OK);

        estadoAgente = EstadoAG2P.RDM_ATIVA; // Volta para o estado anterior em caso de erro

        tarefaAtual = null;

        horaInicio = null;

      }

    }

     

    /**

     * Função auxiliar para encontrar a linha de uma tarefa na aba GPS pelo código.

     * @param {string} codigoTarefa O código da tarefa.

     * @return {number|null} O número da linha ou null se não encontrada.

     */

    function encontrarLinhaTarefaGPS(codigoTarefa) {

      const ss = SpreadsheetApp.getActiveSpreadsheet();

      const gpsSheet = ss.getSheetByName(ABA_GPS);

      const lastRow = gpsSheet.getLastRow();

      const planoDoDia = gpsSheet.getRange(1, COLUNA_PLANO_DIA + "1:" + COLUNA_PLANO_DIA + lastRow).getValues().flat();

      return planoDoDia.indexOf(codigoTarefa) + 1 || null;

    }

     

    /**

     * Função para formatar um tempo em milissegundos para o formato HH:MM:SS.

     * @param {number} milliseconds A duração em milissegundos.

     * @return {string} A duração formatada como HH:MM:SS.

     */

    function formatTime(milliseconds) {

      const totalSeconds = Math.floor(milliseconds / 1000);

      const seconds = totalSeconds % 60;

      const totalMinutes = Math.floor(totalSeconds / 60);

      const minutes = totalMinutes % 60;

      const hours = Math.floor(totalMinutes / 60);

      return `<span class="math-inline">\{pad\(hours\)\}\:</span>{pad(minutes)}:${pad(seconds)}`;

    }

     

    /**

     * Função auxiliar para adicionar um zero à esquerda de números menores que 10.

     * @param {number} num O número a ser formatado.

     * @return {string} O número formatado com zero à esquerda, se necessário.

     */

    function pad(num) {

      return num < 10 ? "0" + num : num;

    }

     

    /**

     * Função para obter a representação em string do estado do agente.

     * @return {string} O nome do estado atual do agente.

     */

    function getEstadoAgenteString() {

      switch (estadoAgente) {

        case EstadoAG2P.OCIOSO:

          return "OCIOSO";

        case EstadoAG2P.RDM_ATIVA:

          return "RDM_ATIVA";

        case EstadoAG2P.TAREFA_EM_EXECUCAO:

          return "TAREFA_EM_EXECUCAO";

        case EstadoAG2P.TAREFA_INTERROMPIDA:

          return "TAREFA_INTERROMPIDA";

        case EstadoAG2P.TAREFA_CONCLUIDA:

          return "TAREFA_CONCLUIDA";

        default:

          return "ESTADO DESCONHECIDO";

      }

    }

     

    /**

     * Função para inicializar o agente e verificar o estado da RDM.

     */

    function inicializarAgente() {

      if (lerEstadoRDM() === "RDM Ativa") {

        estadoAgente = EstadoAG2P.RDM_ATIVA;

        SpreadsheetApp.getUi().alert("Sistema", "RDM Ativa. Pronto para iniciar tarefas.", SpreadsheetApp.getUi().ButtonSet.OK);

        apresentarListaEIniciarTarefa(); // Já apresenta a lista ao iniciar

      } else {

        estadoAgente = EstadoAG2P.OCIOSO;

        SpreadsheetApp.getUi().alert("Aviso", "A RDM não está ativa. O sistema aguardará.", SpreadsheetApp.getUi().ButtonSet.OK);

      }

    }

     

    /**

     * Função para ser executada quando o usuário clica no botão "Tarefa em execução!" para interromper. (R51)

     */

    function interrompeuTarefaNegocio() {

      if (estadoAgente === EstadoAG2P.TAREFA_EM_EXECUCAO) {

        // Ação: Parar medição do tempo

        pararMedicaoTempo();

        estadoAgente = EstadoAG2P.TAREFA_INTERROMPIDA;

        atualizarInterfaceTarefaInterrompida();

      } else {

        SpreadsheetApp.getUi().alert("Aviso", "Nenhuma tarefa em execução para interromper.", SpreadsheetApp.getUi().ButtonSet.OK);

      }

    }

     

    /**

     * Ação: "Parar medição do tempo".

     */

    function pararMedicaoTempo() {

      horaInterrupcao = new Date();

      Logger.log(`Tarefa "${tarefaAtual.nome}" interrompida às ${horaInterrupcao}.`);

      SpreadsheetApp.getUi().alert("Tarefa", `Tarefa "${tarefaAtual.nome}" interrompida!`, SpreadsheetApp.getUi().ButtonSet.OK);

    }

     

    /**

     * Função para ser executada quando o usuário clica no botão "Tarefa interrompida!" para reiniciar. (R52)

     */

    function reiniciouTarefaNegocio() {

      if (estadoAgente === EstadoAG2P.TAREFA_INTERROMPIDA) {

        // Ação: Continuar medição do tempo

        continuarMedicaoTempo();

        estadoAgente = EstadoAG2P.TAREFA_EM_EXECUCAO;

        atualizarInterfaceTarefaExecucao();

      } else {

        SpreadsheetApp.getUi().alert("Aviso", "Nenhuma tarefa interrompida para reiniciar.", SpreadsheetApp.getUi().ButtonSet.OK);

      }

    }

     

    /**

     * Ação: "Continuar medição do tempo".

     */

    function continuarMedicaoTempo() {

      if (horaInterrupcao) {

        const horaReinicio = new Date();

        const duracaoParada = horaReinicio.getTime() - horaInterrupcao.getTime();

        totalParadas += duracaoParada;

     

        const linhaTarefa = encontrarLinhaTarefaGPS(tarefaAtual.codigo);

        if (linhaTarefa) {

          escreverCelulaGPS(linhaTarefa, COLUNA_PARADAS, formatTime(totalParadas));

        }

     

        horaInterrupcao = null;

        Logger.log(`Tarefa "${tarefaAtual.nome}" reiniciada às ${horaReinicio}. Parada de ${formatTime(duracaoParada)} registrada.`);

        SpreadsheetApp.getUi().alert("Tarefa", `Tarefa "${tarefaAtual.nome}" reiniciada!`, SpreadsheetApp.getUi().ButtonSet.OK);

      } else {

        SpreadsheetApp.getUi().alert("Erro", "Nenhuma hora de interrupção registrada.", SpreadsheetApp.getUi().ButtonSet.OK);

      }

    }

     

    /**

     * Função a ser chamada quando a checkbox "Tarefa concluída!" for marcada. (R53)

     */

    function tarefaConcluida() {

      if (estadoAgente === EstadoAG2P.TAREFA_EM_EXECUCAO) {

        // Ações ao concluir a tarefa

        const horaFim = new Date();

        const duracaoExecucaoMs = horaFim.getTime() - horaInicio.getTime() - totalParadas;

        const duracaoExecucaoFormatada = formatTime(duracaoExecucaoMs);

     

        const linhaTarefa = encontrarLinhaTarefaGPS(tarefaAtual.codigo);

        if (linhaTarefa) {

          escreverCelulaGPS(linhaTarefa, COLUNA_DATA_HORA_FIM, horaFim);

          escreverCelulaGPS(linhaTarefa, COLUNA_DURACAO, duracaoExecucaoFormatada);

        }

     

        estadoAgente = EstadoAG2P.RDM_ATIVA;

        tarefaAtual = null;

        horaInicio = null;

        horaInterrupcao = null;

        totalParadas = 0;

     

        atualizarInterfaceTarefaConcluida();

        SpreadsheetApp.getUi().alert("Tarefa", `Tarefa "${tarefaAtual.nome}" concluída! Duração: ${duracaoExecucaoFormatada}`, SpreadsheetApp.getUi().ButtonSet.OK);

        apresentarListaEIniciarTarefa(); // Volta para o Passo 1

      } else {

        SpreadsheetApp.getUi().alert("Aviso", "Nenhuma tarefa em execução para marcar como concluída.", SpreadsheetApp.getUi().ButtonSet.OK);

      }

    }

     

    /**

     * --- Funções de Interface do Usuário (Simulação com UI Prompts/Alerts) ---

     */

     

    /**

     * Função para atualizar a interface para o estado "Tarefa em execução!".

     */

    function atualizarInterfaceTarefaExecucao() {

      SpreadsheetApp.getUi().alert("Status da Tarefa", `Tarefa "${tarefaAtual.nome}" em execução!`, SpreadsheetApp.getUi().ButtonSet.OK);

      // Em uma implementação real com HtmlService, você atualizaria os elementos da tela.

    }

     

    /**

     * Função para atualizar a interface para o estado "Tarefa interrompida!".

     */

    function atualizarInterfaceTarefaInterrompida() {

      SpreadsheetApp.getUi().alert("Status da Tarefa", `Tarefa "${tarefaAtual.nome}" interrompida!`, SpreadsheetApp.getUi().ButtonSet.OK);

      // Em uma implementação real com HtmlService, você atualizaria os elementos da tela.

    }

     

    /**

     * Função para atualizar a interface para o estado "Tarefa concluída!".

     */

    function atualizarInterfaceTarefaConcluida() {

      SpreadsheetApp.getUi().alert("Status da Tarefa", `Tarefa "${tarefaAtual.nome}" concluída!`, SpreadsheetApp.getUi().ButtonSet.OK);

      // Em uma implementação real com HtmlService, você atualizaria os elementos da tela.

    }

     

    /**

     * --- Funções para serem atribuídas aos botões/checkboxes na interface do usuário (se usar HtmlService) ---

     *

     

    CONCLUSÃO

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

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

    Fiz dois comandos para obter o resultado esperado.

    Onde foi que eu errei?

    Faltou precisão no comando, pois eu pedi o código mas não especifiquei a linguagem de programação.

    Segue abaixo o post da temporada 3, que deu origem a este:

    Do Caos ao Prompt T3E05: Estrutura do Agente AG2P - Diálogo 3 Evento "Iniciou tarefa do negócio" dispara Ação "Executar tarefa do negócio"

    Próximo post: Do Caos ao Prompt T4E05: Desenvolvimento do App AG2P – Evento "Terminou tarefa do negócio"

    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...