INTRODUÇÃO
Post anterior: Do Caos ao Prompt T4E03: Desenvolvimento do App AG2P – Evento "Recebeu lista de tarefas a fazer"
Evento “Iniciou tarefa do negócio”
Link da conversa com o Gemini:
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
- Dados:
O estado da aba RDM deve estar igual a "RDM Ativa".
Passos do diálogo 3 entre o usuário e o agente
- 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. - Usuário:
O usuário deve selecionar a tarefa a executar, conforme o fluxo do processo. - 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!". - 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
- Usuário:
O usuário deve clicar no botão cujo rótulo é "Tarefa em execução!", para interromper. (R51) - 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. - 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) - 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
- Na
aba RDM, a célula T1 deve conter o estado "RDM Ativa".
Ações em Caso de Problema
- Revisar
o que foi feito no contexto desta Ação.
- Solicitar
ajuda à pessoa responsável pelo Suporte na Organização.
Atenção Especial
- Atenção
especial para as tarefas pendentes há mais de 2 dias.
- O
estado da aba RDM deve estar igual a "RDM Ativa".
Dados acessados na Planilha GPS
- Na
aba GPS, a coluna R(Plano do Dia)
- 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).
- Na
aba GPS, a coluna E(Data Hora Início).
- Na
aba GPS, a coluna F(Data Hora Fim).
- Na
aba GPS, a coluna G(Duração).
- 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:
- Abra o
Editor de Script:
- Abra
sua planilha do Google Sheets.
- Vá em
"Extensões" > "Apps Script".
- 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:
Próximo post: Do Caos ao Prompt T4E05: Desenvolvimento do App AG2P – Evento "Terminou tarefa do negócio"
Nenhum comentário:
Postar um comentário