TarefasTasksTareas
A lista de tarefas do representante de vendas: as ações que o gerente de território atribuiu, por varejo ou por zona, com status, filtros e uma tela de detalhe onde a tarefa é concluída. Concluir dispara a transação de resposta (Answer Task) pelo Dispatcher. The sales rep's task list: the actions the area manager assigned, by retail or by zone, with status, filters and a detail screen where the task is completed. Completing fires the Answer Task transaction through the Dispatcher. La lista de tareas del representante de ventas: las acciones que el gerente de territorio asignó, por punto de venta o por zona, con estado, filtros y una pantalla de detalle donde la tarea se completa. Completar dispara la transacción de respuesta (Answer Task) por el Dispatcher.
O que é e para que serveWhat it is and what it's forQué es y para qué sirve
A tela de Tarefas reúne as ações que o gerente de território (GTV) distribuiu ao representante de vendas — coisas a executar num varejo específico (ex.: verificar uma promoção, auditar estoque, checar planograma) ou numa zona inteira, sem varejo definido. Cada tarefa tem um tipo, um status e um prazo, e é concluída na tela de detalhe. Responde três perguntas: The Tasks screen gathers the actions the area manager (GTV) handed to the sales rep — things to do at a specific retail (e.g. verify a promotion, audit stock, check a planogram) or across a whole zone, with no retail attached. Each task has a type, a status and a deadline, and is completed on the detail screen. It answers three questions: La pantalla de Tareas reúne las acciones que el gerente de territorio (GTV) distribuyó al representante de ventas — cosas a ejecutar en un punto de venta específico (ej.: verificar una promoción, auditar stock, revisar planograma) o en una zona entera, sin punto de venta definido. Cada tarea tiene un tipo, un estado y un plazo, y se completa en la pantalla de detalle. Responde tres preguntas:
Quais tarefas existem?Which tasks exist?¿Qué tareas hay?
Um card por tarefa, com tipo, título, descrição, varejo (ou zona) e prazo.One card per task, with type, title, description, retail (or zone) and deadline.Una tarjeta por tarea, con tipo, título, descripción, punto de venta (o zona) y plazo.
Em que status estão?What status are they in?¿En qué estado están?
Uma tag colorida por tarefa: pendente, futura, expirada ou concluída.A colored tag per task: pending, future, expired or completed.Una etiqueta de color por tarea: pendiente, futura, expirada o completada.
Como concluir uma?How to complete one?¿Cómo completar una?
Tocar num card abre o detalhe: escreve-se a descrição da execução e toca-se Finalizar.Tapping a card opens the detail: you write the completion note and tap End.Tocar una tarjeta abre el detalle: se escribe la nota de ejecución y se toca Finalizar.
Ler + concluirRead + completeLeer + completar A lista é somente leitura; a única escrita da feature é concluir uma tarefa no detalhe. Não se cria nem se edita tarefa aqui — quem cria é o gerente de território, no backend. The list is read-only; the feature's only write is completing a task in the detail. You don't create or edit tasks here — the area manager creates them in the backend. La lista es solo lectura; la única escritura de la feature es completar una tarea en el detalle. No se crea ni se edita tarea aquí — quien las crea es el gerente de territorio, en el backend.
Como acessarHow to openCómo acceder
- Pelo módulo de Ações na HomeFrom the Actions module on HomeDesde el módulo de Acciones del HomeNa Home, a grade de ações do representante tem um atalho Tarefas — ele abre esta lista. É o único ponto de entrada da tela cheia.On Home, the rep actions grid has a Tasks shortcut — it opens this list. It's the screen's only full-screen entry point.En el Home, la grilla de acciones del representante tiene un atajo Tareas — abre esta lista. Es el único punto de entrada de la pantalla completa.
- Pelo detalhe da visitaFrom the visit detailDesde el detalle de la visitaO detalhe da visita lista as tarefas daquele varejo; tocar numa abre direto o detalhe da tarefa (não passa por esta lista).The visit detail lists the tasks for that retail; tapping one opens the task detail directly (it doesn't go through this list).El detalle de la visita lista las tareas de ese punto de venta; tocar una abre directo el detalle de la tarea (no pasa por esta lista).
- A lista abreThe list opensLa lista abreOrdenada por status (pendentes primeiro) e prazo. Puxe para baixo para atualizar.Sorted by status (pending first) and deadline. Pull down to refresh.Ordenada por estado (pendientes primero) y plazo. Deslice hacia abajo para actualizar.
Estrutura da telaScreen structureEstructura de la pantalla
- CabeçalhoHeaderEncabezado
- Título "Tarefas" e a data da última sincronização dos dados."Tasks" title and the last sync date of the data.Título "Tareas" y la fecha de última sincronización.
- Dois filtrosTwo filtersDos filtros
- Filtrar por status (todas / pendente / futura / expirada / concluída) e filtrar por escopo (todas / por PDV / por zona), cada um num dropdown.Filter by status (all / pending / future / expired / completed) and filter by scope (all / retail / zone), each in a dropdown.Filtrar por estado (todas / pendiente / futura / expirada / completada) y filtrar por alcance (todas / por PDV / por zona), cada uno en un dropdown.
- CardsCardsTarjetas
- Um por tarefa: ícone e nome do tipo, tag de status, título e descrição, o varejo (código + nome) ou o rótulo Tarefa por zona, e o prazo.One per task: type icon and name, status tag, title and description, the retail (code + name) or the Zone Task label, and the deadline.Una por tarea: ícono y nombre del tipo, etiqueta de estado, título y descripción, el punto de venta (código + nombre) o la etiqueta Tarea por zona, y el plazo.
- Contador "X de Y""X of Y" counterContador "X de Y"
- Mostra quantas tarefas estão visíveis do total filtrado; a lista carrega mais (de 20 em 20) ao rolar.Shows how many tasks are visible out of the filtered total; the list loads more (20 at a time) as you scroll.Muestra cuántas tareas están visibles del total filtrado; la lista carga más (de 20 en 20) al desplazar.
- VazioEmptyVacío
- Quando nenhum resultado bate com os filtros, aparece "Nenhuma tarefa atende aos filtros."When no result matches the filters, it shows "No tasks match your filters."Cuando ningún resultado coincide con los filtros, muestra "Ninguna tarea coincide con los filtros."
Status e escopoStatus & scopeEstado y alcance
Cada tarefa tem um status, que define a cor da tag. As tarefas são ordenadas por status (pendentes primeiro, depois futuras, expiradas e concluídas) e, dentro do grupo, pelo prazo:Each task has a status, which sets the tag color. Tasks are sorted by status (pending first, then future, expired and completed) and, within the group, by deadline:Cada tarea tiene un estado, que define el color de la etiqueta. Las tareas se ordenan por estado (pendientes primero, luego futuras, expiradas y completadas) y, dentro del grupo, por plazo:
O escopo separa tarefas de varejo (têm um PDV vinculado) de tarefas de zona (sem PDV — mostram o rótulo laranja "Tarefa por zona"). O filtro de escopo permite ver só um grupo.The scope separates retail tasks (linked to a PDV) from zone tasks (no PDV — they show the orange "Zone Task" label). The scope filter lets you see just one group.El alcance separa tareas de punto de venta (con un PDV vinculado) de tareas de zona (sin PDV — muestran la etiqueta naranja "Tarea por zona"). El filtro de alcance permite ver solo un grupo.
Só concluir tarefas pendentesOnly pending tasks can be completedSolo se completan las pendientes Uma tarefa já concluída abre o detalhe em modo leitura (o botão vira "Concluída" e o campo de descrição fica travado). Tarefas futuras ainda não começaram; expiradas passaram do prazo. An already completed task opens the detail read-only (the button becomes "Completed" and the note field is locked). Future tasks haven't started yet; expired ones are past the deadline. Una tarea ya completada abre el detalle en modo lectura (el botón pasa a "Completada" y el campo de nota queda bloqueado). Las tareas futuras aún no empezaron; las expiradas pasaron del plazo.
Concluir uma tarefaComplete a taskCompletar una tarea
Tocar num card abre o detalhe da tarefa: repete o card, mostra a descrição do gerente de território (o que precisa ser feito) e traz um campo grande para o representante escrever como executou a tarefa.Tapping a card opens the task detail: it repeats the card, shows the area manager's description (what needs doing) and offers a large field for the rep to write how they executed the task.Tocar una tarjeta abre el detalle de la tarea: repite la tarjeta, muestra la descripción del gerente de territorio (qué hay que hacer) y ofrece un campo grande para que el representante escriba cómo ejecutó la tarea.
- Escreva a descriçãoWrite the noteEscriba la notaO campo exige no mínimo 50 caracteres. Um contador mostra o progresso (vermelho abaixo do mínimo, verde ao atingir).The field requires at least 50 characters. A counter shows progress (red below the minimum, green once reached).El campo exige mínimo 50 caracteres. Un contador muestra el progreso (rojo bajo el mínimo, verde al alcanzarlo).
- Toque em "Finalizar"Tap "End"Toque "Finalizar"O botão só habilita depois dos 50 caracteres. Ao tocar, ele fica em carregamento enquanto o app envia a resposta.The button only enables after 50 characters. On tap, it shows a loading state while the app submits the answer.El botón solo se habilita tras los 50 caracteres. Al tocar, muestra carga mientras la app envía la respuesta.
- ResultadoResultResultadoSucesso mostra um aviso verde "Tarefa concluída com sucesso" e a tarefa passa a concluída; falha mostra um aviso vermelho e mantém a tela editável. "Sair" volta sem enviar.Success shows a green "Task completed successfully" notice and the task turns completed; failure shows a red notice and keeps the screen editable. "Exit" goes back without submitting.Éxito muestra un aviso verde "Tarea completada con éxito" y la tarea pasa a completada; el fallo muestra un aviso rojo y mantiene la pantalla editable. "Salir" vuelve sin enviar.
Para onde vaiWhere it goesA dónde va "Finalizar" dispara a transação Answer Task pelo Dispatcher (23 · AnswerTaskAPI). Só depois do ack de sucesso a tarefa é marcada como concluída no cache local. "End" fires the Answer Task transaction through the Dispatcher (23 · AnswerTaskAPI). Only after the success ack is the task marked completed in the local cache. "Finalizar" dispara la transacción Answer Task por el Dispatcher (23 · AnswerTaskAPI). Solo tras el ack de éxito la tarea se marca como completada en el caché local.
Pendências / roadmapPending / roadmapPendientes / roadmap
- A descrição escrita (mín. 50 caracteres) é hoje só um gate de UI: ela não é enviada no payload da transação nem persistida — o payload manda apenas
answer: true.The written note (min. 50 chars) is today only a UI gate: it is not sent in the transaction payload nor persisted — the payload sends onlyanswer: true.La nota escrita (mín. 50 caract.) es hoy solo un gate de UI: no se envía en el payload de la transacción ni se persiste — el payload manda soloanswer: true. - A lista de respostas de ruptura (
oosAnswerList) sai vazia — o fluxo de out-of-stock ainda não foi portado.The out-of-stock answer list (oosAnswerList) is sent empty — the OOS flow hasn't been ported yet.La lista de respuestas de ruptura (oosAnswerList) sale vacía — el flujo de out-of-stock aún no fue portado.
Arquitetura e fluxo de dadosArchitecture & data flowArquitectura y flujo de datos
Clean Architecture + Riverpod + Freezed + gRPC + ObjectBox. Há dois fluxos distintos: a leitura da lista (um RPC getTasksGtv, com cache write-through) e a escrita (concluir uma tarefa, via Dispatcher). A lista e o detalhe leem a mesma TasksEntity do cache.Clean Architecture + Riverpod + Freezed + gRPC + ObjectBox. There are two distinct flows: the list read (a single getTasksGtv RPC, with cache write-through) and the write (completing a task, via the Dispatcher). List and detail both read the same cached TasksEntity.Clean Architecture + Riverpod + Freezed + gRPC + ObjectBox. Hay dos flujos distintos: la lectura de la lista (un RPC getTasksGtv, con cache write-through) y la escritura (completar una tarea, vía Dispatcher). La lista y el detalle leen la misma TasksEntity del caché.
Leitura · lista (write-through)Read · list (write-through)Lectura · lista (write-through)
- TasksGtvReplygRPC proto
- toTasksDTOTasksDTODTO · Freezed
- toDomainTasksEntitydomain
- toModelTasksModelObjectBox
- toDomainTasksEntitydomain · cache
- watchTasksNotifier / TaskDetailNotifier
- → UITasksPage · TaskDetailPage
- watchTasksNotifier / TaskDetailNotifier
- toDomainTasksEntitydomain · cache
- toModelTasksModelObjectBox
- toDomainTasksEntitydomain
- toTasksDTOTasksDTODTO · Freezed
Escrita · concluir via DispatcherWrite · complete via DispatcherEscritura · completar vía Dispatcher
O envio é remote-first: monta-se o envelope, despacha-se pelo Dispatcher e só após o ack de sucesso o cache local é atualizado (status → concluída).The write is remote-first: the envelope is built, dispatched through the Dispatcher, and only after the success ack is the local cache updated (status → completed).La escritura es remote-first: se arma el sobre, se despacha por el Dispatcher y solo tras el ack de éxito se actualiza el caché local (estado → completada).
- TaskDetailActionsWidgetUI
- submitCompletionTaskDetailNotifier
- build(input)BuildAnswerTaskDispatcherPayloadUseCase→ DispatcherEnvelope
- submit(envelope)SubmitAnswerTaskUseCase
- dispatchDispatcherOrchestratorAnswerTaskAPI · batchApi
- ack ok →ack ok →ack ok →SubmitTaskDetailsUseCasecache local: status → completedlocal cache: status → completedcaché local: status → completed
- dispatchDispatcherOrchestratorAnswerTaskAPI · batchApi
- submit(envelope)SubmitAnswerTaskUseCase
- build(input)BuildAnswerTaskDispatcherPayloadUseCase→ DispatcherEnvelope
- submitCompletionTaskDetailNotifier
Modelo de dadosData modelModelo de datos
A mesma tarefa existe em quatro representações quase idênticas ao longo das camadas — Proto (wire gRPC) → DTO (Freezed) → Model (ObjectBox) → Entity (domínio) — e cada fronteira é atravessada por um mapper. Os nomes se mantêm; muda muito pouco (dois enums tipados, duas datas parseadas, e o id renomeado no Model). O fetch é write-through: todo retorno é gravado no ObjectBox e a UI passa a ler do cache.The same task exists in four near-identical representations across the layers — Proto (gRPC wire) → DTO (Freezed) → Model (ObjectBox) → Entity (domain) — and each boundary is crossed by a mapper. Names stay the same; very little changes (two typed enums, two parsed dates, and id renamed in the Model). Fetch is write-through: every response is written to ObjectBox and the UI then reads from cache.La misma tarea existe en cuatro representaciones casi idénticas a lo largo de las capas — Proto (wire gRPC) → DTO (Freezed) → Model (ObjectBox) → Entity (dominio) — y cada frontera se cruza con un mapper. Los nombres se mantienen; cambia muy poco (dos enums tipados, dos fechas parseadas, y el id renombrado en el Model). El fetch es write-through: toda respuesta se graba en ObjectBox y la UI lee del caché.
A lista chega num container TasksEntity (lastSyncAt gerado no mapper + tasks[]); cada item é um Task de 10 campos, plano (sem sub-estruturas). Os enums só existem tipados na Entity (TaskType, TaskStatus); em Proto/DTO/Model trafegam como String. A seguir, na ordem: o proto, as estruturas de dados campo-a-campo por camada, e os mappers.The list arrives in a TasksEntity container (lastSyncAt generated in the mapper + tasks[]); each item is a 10-field, flat Task (no sub-structures). Enums are only typed in the Entity (TaskType, TaskStatus); in Proto/DTO/Model they travel as String. Next, in order: the proto, the field-by-field data structures per layer, and the mappers.La lista llega en un container TasksEntity (lastSyncAt generado en el mapper + tasks[]); cada ítem es un Task de 10 campos, plano (sin sub-estructuras). Los enums solo están tipados en la Entity (TaskType, TaskStatus); en Proto/DTO/Model viajan como String. A continuación, en orden: el proto, las estructuras de datos campo a campo por capa, y los mappers.
Proto
TasksConectaRep.proto · proto3 · package mn.bat.conectarep.streambridge. Um serviço (TasksConectaRepService), um método unário:One service (TasksConectaRepService), a single unary method:Un servicio (TasksConectaRepService), un método unario:
getTasksGtvunaryrpc getTasksGtv(TasksGtvRequest) returns (TasksGtvReply)
path /mn.bat.conectarep.streambridge.TasksConectaRepService/getTasksGtv
TasksGtvRequestlocationHierarchySfidstring· #1 · hierarquia do representante de vendas (resolvida no repository viacurrentResourceProvider)sales rep hierarchy (resolved in the repository viacurrentResourceProvider)jerarquía del representante de ventas (resuelta en el repository víacurrentResourceProvider)dateReferencestring· #2 · optionallastModifiedDatestring· #3 · optional (não usado hoje)optional (not used today)optional (no usado hoy)
TasksGtvReplyrepeated TaskGtv tasks — a lista de tarefas. Os 10 campos de TaskGtv estão detalhados nas Estruturas de dados abaixo.the list of tasks. TaskGtv's 10 fields are detailed in Data structures below.la lista de tareas. Los 10 campos de TaskGtv están detallados en Estructuras de datos abajo.
Estruturas de dadosData structuresEstructuras de datos
Um dropdown por estrutura. Cada tabela tem uma coluna por camada — Proto · DTO · Model · Entity; o texto azul marca onde o tipo primeiro muda (enum na Entity, parse de data e rename de id no Model). ¹ = optional no proto.One dropdown per structure. Each table has one column per layer — Proto · DTO · Model · Entity; the blue text marks where the type first changes (enum in the Entity, date parse and id rename in the Model). ¹ = optional in the proto.Un dropdown por estructura. Cada tabla tiene una columna por capa — Proto · DTO · Model · Entity; el texto azul marca dónde primero cambia el tipo (enum en la Entity, parse de fecha y rename de id en el Model). ¹ = optional en el proto.
Tasks container 2 camposfieldscampos
Campo Proto DTO Model Entity tasksrepeated TaskGtv List<TaskDTO> ToMany<TaskModel>List<TaskEntity> lastSyncAt— DateTime?DateTime DateTime? Task Tasks.tasks[] 10 camposfieldscampos
Campo Proto DTO Model Entity idstring String taskIdString taskTypestring String String TaskTypetaskTitlestring String String String descriptionstring String String String accountSfidstring String String String accountCodestring String String String accountNamestring String String String startDatestring String DateTime?DateTime? endDatestring String DateTime?DateTime? statusstring String String TaskStatus
Mappers
As conversões entre as camadas, todas como extension (5 direções, no par container/item):The conversions between layers, all as extensions (5 directions, over the container/item pair):Las conversiones entre capas, todas como extension (5 direcciones, sobre el par container/ítem):
| DireçãoDirectionDirección | MétodoMethodMétodo |
|---|---|
| JSON → DTO | static fromMap(Map) (container e item; carimba lastSyncAt com DateTimeUtils.now())(container and item; stamps lastSyncAt with DateTimeUtils.now())(container e ítem; sella lastSyncAt con DateTimeUtils.now()) |
| Proto → DTO | toTasksDTO() / toDTO() (carimba lastSyncAt)(stamps lastSyncAt)(sella lastSyncAt) |
| DTO → Entity | toDomain() (resolve enums via fromValue; parseia datas via DateTimeUtils.tryParse)(resolves enums via fromValue; parses dates via DateTimeUtils.tryParse)(resuelve enums vía fromValue; parsea fechas vía DateTimeUtils.tryParse) |
| Entity → Model | toModel() (enums → .value; popula ToMany; lança se lastSyncAt for nulo)(enums → .value; fills ToMany; throws if lastSyncAt is null)(enums → .value; llena ToMany; lanza si lastSyncAt es nulo) |
| Model → Entity | toDomain() |
Os únicos deltasThe only deltasLos únicos deltas
taskType·statustipados só na Entity (TaskType/TaskStatus;Stringnas outras)typed only in the Entity (TaskType/TaskStatus;Stringelsewhere)tipados solo en la Entity (TaskType/TaskStatus;Stringen las demás)startDate·endDateString→DateTime?(parse no mapper DTO→Entity viaDateTimeUtils.tryParse; persistido comoDateTime?no Model)(parsed in the DTO→Entity mapper viaDateTimeUtils.tryParse; persisted asDateTime?in the Model)(parse en el mapper DTO→Entity víaDateTimeUtils.tryParse; persistido comoDateTime?en el Model)idrenomeado parataskIdno Model (o@Id int iddo ObjectBox é separado)renamed totaskIdin the Model (ObjectBox's@Id int idis separate)renombrado ataskIden el Model (el@Id int idde ObjectBox es aparte)lastSyncAtgerado no mapper de fronteira (JSON e Proto) comDateTimeUtils.now()generated in the boundary mapper (JSON and Proto) withDateTimeUtils.now()generado en el mapper de frontera (JSON y Proto) conDateTimeUtils.now()
Repository
TaskRepositoryImpl implementaimplementsimplementa TaskRepositoryInterface e injeta os 3 datasources (mock/local/remote) + ConnectivityService + a flag useMockData + Ref. Método a método:and injects the 3 datasources (mock/local/remote) + ConnectivityService + the useMockData flag + Ref. Method by method:e inyecta los 3 datasources (mock/local/remote) + ConnectivityService + la flag useMockData + Ref. Método a método:
Um dropdown por método — assinatura, retorno e comportamento. O getTasks() traz a árvore de decisão de fonte dentro do próprio detalhe.One dropdown per method — signature, return and behavior. getTasks() carries the source decision tree inside its own detail.Un dropdown por método — firma, retorno y comportamiento. getTasks() trae el árbol de decisión de fuente dentro de su propio detalle.
getTasks({source}) mock / local / remote
RetornaReturnsDevuelve Result<TasksEntity, Failure>
Ponto de entrada da lista (source default = local): decide a fonte, mapeia e grava no cache (write-through). Chamado por GetTasksUseCase.List entry point (default source = local): picks the source, maps and writes to cache (write-through). Called by GetTasksUseCase.Punto de entrada de la lista (source por defecto = local): elige la fuente, mapea y graba en caché (write-through). Llamado por GetTasksUseCase.
Árvore de decisão de fonteSource decision treeÁrbol de decisión de fuente
useMockData== true ouorosource == mock→_fetchFromMock(): lê o mock por mercado, mapeia, grava no cache.→_fetchFromMock(): reads the per-market mock, maps, writes to cache.→_fetchFromMock(): lee el mock por mercado, mapea, graba en caché.source == localou offlineor offlineu offline→_fetchFromCacheOrFail(): lê o cache; se vazio, retornaNetworkFailure.→_fetchFromCacheOrFail(): reads the cache; if empty, returnsNetworkFailure.→_fetchFromCacheOrFail(): lee el caché; si vacío, retornaNetworkFailure.- senão (remoto + conectado)otherwise (remote + connected)si no (remoto + conectado)→
_fetchFromRemoteWithFallback(): lêcurrentResourceProvider; senullcai pro cache; senão chama o remoto comlocationHierarchyId, mapeia, grava no cache; em erro, fallback pro cache.→_fetchFromRemoteWithFallback(): readscurrentResourceProvider; ifnullfalls back to cache; else calls remote withlocationHierarchyId, maps, writes to cache; on error, falls back to cache.→_fetchFromRemoteWithFallback(): leecurrentResourceProvider; sinullcae al caché; si no llama al remoto conlocationHierarchyId, mapea, graba en caché; en error, fallback al caché.
getCachedTasksLastSyncAt() local
RetornaReturnsDevuelve Future<DateTime?>
Lê o lastSyncAt do cache (para o DataLoadInfo) sem materializar as tarefas; em erro, loga e retorna null.Reads the cached lastSyncAt (for DataLoadInfo) without materializing the tasks; on error, logs and returns null.Lee el lastSyncAt del caché (para el DataLoadInfo) sin materializar las tareas; en error, loguea y retorna null.
getTasksForAccount({accountSfid}) filtro por varejofilter by retailfiltro por PDV
RetornaReturnsDevuelve Result<List<TaskEntity>, Failure>
Chamado pelo detalhe da visita: accountSfid vazio → lista vazia; senão chama getTasks() e filtra in-memory as tarefas daquele varejo.Called by the visit detail: empty accountSfid → empty list; otherwise calls getTasks() and filters that retail's tasks in-memory.Llamado por el detalle de la visita: accountSfid vacío → lista vacía; si no llama getTasks() y filtra in-memory las tareas de ese punto de venta.
submitTaskDetails({taskId, completionDescription}) só cachecache onlysolo caché
RetornaReturnsDevuelve Result<void, Failure>
Atualiza só o cache local — marca a tarefa como completed (updateTaskStatus). Não faz rede: a escrita remota é a transação Answer Task (Dispatcher), disparada pelo Notifier antes desta chamada. O completionDescription é recebido mas hoje não é usado (ver Pendências).Updates only the local cache — marks the task completed (updateTaskStatus). Does no network: the remote write is the Answer Task transaction (Dispatcher), fired by the Notifier before this call. completionDescription is received but today unused (see Pending).Actualiza solo el caché local — marca la tarea completed (updateTaskStatus). No hace red: la escritura remota es la transacción Answer Task (Dispatcher), disparada por el Notifier antes de esta llamada. completionDescription se recibe pero hoy no se usa (ver Pendientes).
Datasources
Três datasources. A escrita das ações não passa por eles — vai pelo Dispatcher (ver UseCases); o único write local é updateTaskStatus.Three datasources. Action writes don't go through them — they go via the Dispatcher (see UseCases); the only local write is updateTaskStatus.Tres datasources. La escritura de las acciones no pasa por ellos — va por el Dispatcher (ver UseCases); el único write local es updateTaskStatus.
Remote · TaskRemoteDataSource
- EnvioSendsEnvío
TasksGtvRequest(locationHierarchySfid+dateReference?+lastModifiedDate?)- MétodoMethodMétodo
getTasks({locationHierarchySfid, dateReference?, lastModifiedDate?})→Future<TasksEntity>- FluxoFlowFlujo
- Chama o stub gRPC
getTasksGtv;TasksGtvReply.toTasksDTO().toDomain().Calls the gRPC stubgetTasksGtv;TasksGtvReply.toTasksDTO().toDomain().Llama el stub gRPCgetTasksGtv;TasksGtvReply.toTasksDTO().toDomain(). - ErroErrorError
GrpcError→GrpcExceptionHandler.handle; outros →ServerException.GrpcError→GrpcExceptionHandler.handle; others →ServerException.GrpcError→GrpcExceptionHandler.handle; otros →ServerException.
Local · TaskLocalDataSource ObjectBox
CRUD sobre TasksModel (container single-row) + TaskModel. Erros viram CacheException.CRUD over TasksModel (single-row container) + TaskModel. Errors become CacheException.CRUD sobre TasksModel (container single-row) + TaskModel. Errores viran CacheException.
getCachedTasks()TasksEntity?— primeira linha do box →toDomain();nullse vazio.first row of the box →toDomain();nullif empty.primera fila del box →toDomain();nullsi vacío.getTasksLastSyncAt()DateTime?— só o timestamp da primeira linha.just the first row's timestamp.solo el timestamp de la primera fila.saveTasks({entity})clearTasks()+put(substitui tudo).clearTasks()+put(replaces all).clearTasks()+put(reemplaza todo).mergeAdhocTasks({incoming, accountSfid})- merge aditivo das tarefas de uma visita ad-hoc (via
AdhocTasksMerge).additive merge of an ad-hoc visit's tasks (viaAdhocTasksMerge).merge aditivo de las tareas de una visita ad-hoc (víaAdhocTasksMerge). updateTaskStatus({taskId, newStatus})- acha o
TaskModelportaskIde grava o novostatus.value— usado ao concluir.finds theTaskModelbytaskIdand writes the newstatus.value— used on completion.encuentra elTaskModelportaskIdy graba el nuevostatus.value— usado al completar. clearTasks()- esvazia os dois boxes.empties both boxes.vacía ambos boxes.
Mock · TaskMockDataSource
- MétodoMethodMétodo
getTasks()→Future<TasksEntity>- FluxoFlowFlujo
- Carrega o JSON de
taskspor mercado (sintético ou_real_conformeuseRealMockData),fromMap().toDomain().Loads the per-markettasksJSON (synthetic or_real_peruseRealMockData),fromMap().toDomain().Carga el JSON detaskspor mercado (sintético o_real_segúnuseRealMockData),fromMap().toDomain().
Enums e labelsEnums & labelsEnums y labels
Dois enums de dado (tipados na Entity a partir da String de wire, via fromValue), dois enums de filtro (client-side) e um enum de estado de envio. Um dropdown por enum, todos os valores:Two data enums (typed in the Entity from the wire String, via fromValue), two filter enums (client-side) and one submission-status enum. One dropdown per enum, every value:Dos enums de dato (tipados en la Entity desde el String de wire, vía fromValue), dos enums de filtro (client-side) y un enum de estado de envío. Un dropdown por enum, todos los valores:
TaskType 11 · case · value · label
| case | value (wire) | label (EN) |
|---|---|---|
share | share | Share |
conectaPrime | conecta_prime | Conecta Prime |
promotionCampaign | promotion_campaign | Promotion Campaign |
objectiveAchievement | objective_achievement | Objective Achievement |
conectaVoce | conecta_voce | Conecta Voice |
tacticalActions | tactical_actions | Tactical Actions |
stockAudit | stock_audit | Stock Audit |
promoVerification | promo_verification | Promo Verification |
planogram | planogram | Planogram |
zoneActivation | zone_activation | Zone Activation |
unknown | unknown | Task (fallback) |
TaskStatus 5 · case · value · tag · sort
| case | value (wire) | label (EN) | tag | sort |
|---|---|---|---|---|
pending | pending | Pending | neutral (azul no card)(blue on card)(azul en la tarjeta) | 0 |
future | future | Future | warning | 1 |
expired | expired | Expired | negative | 2 |
completed | completed | Completed | positive | 3 |
unknown | unknown | Unknown | neutral | 4 |
TaskStatusFilter 5 · filtro client-sideclient-side filterfiltro client-side
| case | → status | label (EN) |
|---|---|---|
all | null (sem filtro)(no filter)(sin filtro) | All |
pending | TaskStatus.pending | Pending |
future | TaskStatus.future | Future |
expired | TaskStatus.expired | Expired |
completed | TaskStatus.completed | Completed |
TaskScopeFilter 3 · case · value · label
| case | value | label (EN) |
|---|---|---|
all | all | All |
byRetail | by_retail | Retail Tasks |
byZone | by_zone | Zone Tasks |
TaskDetailSubmissionStatus 4 · estado do envio (UI)submission state (UI)estado del envío (UI)
| case | significadomeaningsignificado |
|---|---|
idle | nada em andamentonothing in progressnada en curso |
submitting | enviando (botão em loading)submitting (button loading)enviando (botón cargando) |
success | enviado com sucesso → aviso verdesent successfully → green noticeenviado con éxito → aviso verde |
failure | falhou → aviso vermelho, tela editávelfailed → red notice, screen editablefalló → aviso rojo, pantalla editable |
Labels crus do backendRaw backend labelsLabels crudos del backend
Os labels de TaskType/TaskStatus são traduzidos por chave de i18n; os values (conecta_prime, pending…) são códigos de wire e ficam crus. Valor desconhecido cai em unknown.
TaskType/TaskStatus labels are translated via i18n keys; the values (conecta_prime, pending…) are wire codes and stay raw. An unknown value falls into unknown.
Los labels de TaskType/TaskStatus se traducen por clave i18n; los values (conecta_prime, pending…) son códigos de wire y quedan crudos. Un valor desconocido cae en unknown.
UseCases
LeituraReadLectura
GetTasksUseCase 2 métodosmethodsmétodos
| MétodoMethodMétodo | RetornaReturnsDevuelve | UsoUseUso |
|---|---|---|
execute({source}) | Result<TasksEntity, Failure> | delega a repository.getTasks. Usado pela lista e pelo detalhe.delegates to repository.getTasks. Used by list and detail.delega a repository.getTasks. Usado por lista y detalle. |
getCachedLastSyncAt() | Future<DateTime?> | timestamp do cache para o DataLoadInfo.cached timestamp for DataLoadInfo.timestamp del caché para el DataLoadInfo. |
GetTasksForAccountUseCase 1 métodomethodmétodo
| MétodoMethodMétodo | RetornaReturnsDevuelve | UsoUseUso |
|---|---|---|
execute({accountSfid}) | Result<List<TaskEntity>, Failure> | tarefas de um varejo — consumido pelo detalhe da visita, não por esta tela.a retail's tasks — consumed by the visit detail, not by this screen.tareas de un punto de venta — consumido por el detalle de la visita, no por esta pantalla. |
Escrita · concluirWrite · completeEscritura · completar
O trio de escrita segue o padrão §36 (builder puro) + §39 (disparo no Notifier). Ver a transação completa em Answer Task.The write trio follows §36 (pure builder) + §39 (dispatch in the Notifier). See the full transaction in Answer Task.El trío de escritura sigue §36 (builder puro) + §39 (disparo en el Notifier). Ver la transacción completa en Answer Task.
BuildAnswerTaskDispatcherPayloadUseCase builder
| MétodoMethodMétodo | RetornaReturnsDevuelve | UsoUseUso |
|---|---|---|
build({input: AnswerTaskDispatcherPayloadInput}) | DispatcherEnvelope | implements DispatcherPayloadBuilder (§36). Input cru (task, visitSfid, submittedAt). Monta answerTask[] com callTaskVisit=task.id, callTaskCode=task.taskType.value, answer:true, oosAnswerList vazio; type = DispatcherType.answerTask.implements DispatcherPayloadBuilder (§36). Raw input (task, visitSfid, submittedAt). Builds answerTask[] with callTaskVisit=task.id, callTaskCode=task.taskType.value, answer:true, empty oosAnswerList; type = DispatcherType.answerTask.implements DispatcherPayloadBuilder (§36). Input crudo (task, visitSfid, submittedAt). Arma answerTask[] con callTaskVisit=task.id, callTaskCode=task.taskType.value, answer:true, oosAnswerList vacío; type = DispatcherType.answerTask. |
SubmitAnswerTaskUseCase transporte finothin transporttransporte fino
| MétodoMethodMétodo | RetornaReturnsDevuelve | UsoUseUso |
|---|---|---|
submit({envelope}) | Result<DispatcherAck, Failure> | delega ao DispatcherOrchestrator.dispatch. Não decide o DispatcherType (isso é do builder).delegates to DispatcherOrchestrator.dispatch. Doesn't decide the DispatcherType (the builder does).delega al DispatcherOrchestrator.dispatch. No decide el DispatcherType (eso es del builder). |
SubmitTaskDetailsUseCase pós-ack: cachepost-ack: cachepost-ack: caché
| MétodoMethodMétodo | RetornaReturnsDevuelve | UsoUseUso |
|---|---|---|
execute({taskId, completionDescription}) | Result<void, Failure> | após o ack de sucesso, marca a tarefa como concluída no cache local (via repository). Ver Pendências sobre a descrição.after the success ack, marks the task completed in the local cache (via repository). See Pending about the description.tras el ack de éxito, marca la tarea completada en el caché local (vía repository). Ver Pendientes sobre la descripción. |
Notifier & State
Dois notifiers: TasksNotifier (lista) e TaskDetailNotifier (detalhe, família por taskId). Cada um expõe seu State Freezed como fonte única de verdade; a Page só lê via ref.watch.Two notifiers: TasksNotifier (list) and TaskDetailNotifier (detail, family by taskId). Each exposes its Freezed State as the single source of truth; the Page only reads via ref.watch.Dos notifiers: TasksNotifier (lista) y TaskDetailNotifier (detalle, familia por taskId). Cada uno expone su State Freezed como fuente única de verdad; la Page solo lee vía ref.watch.
ListaListLista
MétodosMethodsMétodos · TasksNotifier
build() / _load()
build() magro: assina o UseCase e delega a _load(all, all) sob AsyncGuard. _load busca TasksEntity (default cache) e monta o TasksState.Thin build(): watches the UseCase and delegates to _load(all, all) under AsyncGuard. _load fetches TasksEntity (default cache) and builds TasksState.Delgado build(): observa el UseCase y delega a _load(all, all) bajo AsyncGuard. _load busca TasksEntity (caché por defecto) y arma el TasksState.
setStatusFilter · setScopeFilter
Trocam o filtro no state e resetam visibleCount para 20. Não refazem fetch.Swap the filter in state and reset visibleCount to 20. No re-fetch.Cambian el filtro en el state y resetean visibleCount a 20. Sin re-fetch.
loadMore()
Incrementa visibleCount em 20 (clamp no total filtrado) — paginação visual sobre a lista já em cache.Increments visibleCount by 20 (clamped to the filtered total) — visual pagination over the already-cached list.Incrementa visibleCount en 20 (clamp al total filtrado) — paginación visual sobre la lista ya en caché.
refresh()
Pull-to-refresh: re-roda _load com source = remote, preservando os filtros atuais, sob runGuarded (sem AsyncValue.loading).Pull-to-refresh: re-runs _load with source = remote, preserving current filters, under runGuarded (no AsyncValue.loading).Pull-to-refresh: re-corre _load con source = remote, preservando los filtros actuales, bajo runGuarded (sin AsyncValue.loading).
State disponível para a PageState available to the PageState disponible para la Page
TasksState 4 camposfieldscampos + getters
| Campo / getterField / getterCampo / getter | Tipo / o que dáType / what it givesTipo / qué da |
|---|---|
tasks | AsyncValue<TasksEntity> |
statusFilter · scopeFilter | TaskStatusFilter · TaskScopeFilter |
visibleCount | int (padrão 20default 20por defecto 20) |
lastSyncAt | timestamp da TasksEntity (nunca do Resource — §23)TasksEntity's timestamp (never Resource — §23)timestamp de la TasksEntity (nunca del Resource — §23) |
filteredTasks | aplica status + escopo, ordena (status, depois endDate)applies status + scope, sorts (status, then endDate)aplica status + alcance, ordena (status, luego endDate) |
visibleTasks | filteredTasks.take(visibleCount) |
totalFilteredTasks · hasMoreToLoad | contagem e flag de paginaçãocount and pagination flagconteo y flag de paginación |
DetalheDetailDetalle
MétodosMethodsMétodos · TaskDetailNotifier(taskId)
build({taskId})
Cache-only: busca a TasksEntity (default local) e acha a tarefa por id; se não achar, StateError. Monta o TaskDetailState com a tarefa + lastSyncAt do container.Cache-only: fetches TasksEntity (default local) and finds the task by id; if not found, StateError. Builds TaskDetailState with the task + the container's lastSyncAt.Cache-only: busca la TasksEntity (local por defecto) y encuentra la tarea por id; si no la encuentra, StateError. Arma el TaskDetailState con la tarea + el lastSyncAt del container.
updateCompletionDescription({value})
Atualiza a descrição no state e limpa a mensagem de erro de envio.Updates the description in state and clears the submission error message.Actualiza la descripción en el state y limpia el mensaje de error de envío.
submitCompletion() remote-first
Guard canSubmit; marca submitting; resolve o visitSfid pela conta (getCachedByAccountSfid); monta o envelope (_buildAnswerTaskPayload) com submittedAt = DateTimeUtils.now(); despacha (_submitAnswerTaskUseCase). Só com ack de sucesso chama _submitTaskDetailsUseCase (cache) e vira o state para success com task.status = completed; qualquer falha → failure + chave de erro.Guards canSubmit; sets submitting; resolves visitSfid from the account (getCachedByAccountSfid); builds the envelope (_buildAnswerTaskPayload) with submittedAt = DateTimeUtils.now(); dispatches (_submitAnswerTaskUseCase). Only on a success ack calls _submitTaskDetailsUseCase (cache) and moves state to success with task.status = completed; any failure → failure + error key.Guard canSubmit; marca submitting; resuelve visitSfid por la cuenta (getCachedByAccountSfid); arma el sobre (_buildAnswerTaskPayload) con submittedAt = DateTimeUtils.now(); despacha (_submitAnswerTaskUseCase). Solo con ack de éxito llama _submitTaskDetailsUseCase (caché) y pasa el state a success con task.status = completed; cualquier fallo → failure + clave de error.
resetSubmissionStatus()
Volta o submissionStatus para idle (chamado pela Page após exibir o ConectaNotice).Resets submissionStatus to idle (called by the Page after showing the ConectaNotice).Vuelve el submissionStatus a idle (llamado por la Page tras mostrar el ConectaNotice).
State disponível para a PageState available to the PageState disponible para la Page
TaskDetailState 5 camposfieldscampos + getters
| Campo / getterField / getterCampo / getter | Tipo / o que dáType / what it givesTipo / qué da |
|---|---|
task | TaskEntity |
lastSyncAt | DateTime? |
completionDescription | String (default ""default ""default "") |
submissionStatus | TaskDetailSubmissionStatus |
submissionErrorMessage | String? (chave i18ni18n keyclave i18n) |
isCompleted | task.status == completed |
descriptionLength · hasReachedMinimumLength | contagem vs. mínimo 50count vs. minimum 50conteo vs. mínimo 50 |
isSubmitting · canSubmit | gate do botão (!isCompleted && ≥50 && !isSubmitting)button gate (!isCompleted && ≥50 && !isSubmitting)gate del botón (!isCompleted && ≥50 && !isSubmitting) |
Page e widgetsPage & widgetsPage y widgets
Duas Pages, ambas AppPageShell com .when(data/error/loading) (loading = CustomLoadingIndicator; erro = FailureStateView). Árvore de composição:Two Pages, both AppPageShell with .when(data/error/loading) (loading = CustomLoadingIndicator; error = FailureStateView). Composition tree:Dos Pages, ambas AppPageShell con .when(data/error/loading) (loading = CustomLoadingIndicator; error = FailureStateView). Árbol de composición:
TasksPage
- TasksPage
- CustomPullToRefresh → refresh()→ refresh()→ refresh()
- DataLoadInfo lastSyncAt
- TasksHeaderWidget ícone + títuloicon + titleícono + título
- TasksFiltersRowWidget 2 dropdowns (status/escopo)2 dropdowns (status/scope)2 dropdowns (status/alcance)
- TasksListWidget
- CustomEmptyState se vazioif emptysi vacío
- InfiniteScrollListView<TaskEntity>
- TaskCardWidget tipo · status · varejo/zona · prazo → goToTaskDetailtype · status · retail/zone · deadline → goToTaskDetailtipo · status · PDV/zona · plazo → goToTaskDetail
- PaginationCountIndicator "X / Y"
- CustomPullToRefresh → refresh()→ refresh()→ refresh()
TaskDetailPage
- TaskDetailPage(taskId) ref.listen → ConectaNotice em success/failureref.listen → ConectaNotice on success/failureref.listen → ConectaNotice en success/failure
- SingleChildScrollView
- DataLoadInfo
- TaskDetailHeaderWidget
- TaskDetailCardWidget repete o card da listarepeats the list cardrepite la tarjeta de la lista
- TaskDetailGtvDescriptionWidget descrição do gerente de territórioarea manager's descriptiondescripción del gerente de territorio
- TaskDetailDescriptionInputWidget textarea + contador ≥50 (readOnly se concluída)textarea + ≥50 counter (readOnly if completed)textarea + contador ≥50 (readOnly si completada)
- TaskDetailActionsWidget Sair (outlined) · Finalizar (filled) → submitCompletionExit (outlined) · End (filled) → submitCompletionSalir (outlined) · Finalizar (filled) → submitCompletion
- SingleChildScrollView
A Page do detalhe orquestra a UI (mostra ConectaNotice, chama resetSubmissionStatus, "Sair" via AppRouter.back); o disparo do envio vive no Notifier (§39).The detail Page orchestrates the UI (shows ConectaNotice, calls resetSubmissionStatus, "Exit" via AppRouter.back); the submit trigger lives in the Notifier (§39).La Page del detalle orquesta la UI (muestra ConectaNotice, llama resetSubmissionStatus, "Salir" vía AppRouter.back); el disparo del envío vive en el Notifier (§39).
Notas por mercadoMarket notesNotas por mercado
Tarefas está disponível nos três mercados ativos. O atalho vive no módulo rep_actions do End Market Configuration, e a escrita Answer Task (DispatcherType.answerTask) tem enabledMarkets = [BR, CL, ZA] — os dois sinais coincidem. AR/PY/PE (config PANGEA mínima) não têm a feature.Tasks is available in the three active markets. The shortcut lives in the End Market Configuration rep_actions module, and the Answer Task write (DispatcherType.answerTask) has enabledMarkets = [BR, CL, ZA] — both signals agree. AR/PY/PE (minimal PANGEA config) don't have the feature.Tareas está disponible en los tres mercados activos. El atajo vive en el módulo rep_actions del End Market Configuration, y la escritura Answer Task (DispatcherType.answerTask) tiene enabledMarkets = [BR, CL, ZA] — ambas señales coinciden. AR/PY/PE (config PANGEA mínima) no tienen la feature.
BR · CL · ZA Mesmo proto, mesmos tipos de tarefa e mesma transação em todos os três. O idioma dos labels segue a i18n do mercado; os values de wire são iguais. Same proto, same task types and same transaction across all three. Label language follows the market's i18n; wire values are identical. Mismo proto, mismos tipos de tarea y misma transacción en los tres. El idioma de los labels sigue la i18n del mercado; los values de wire son idénticos.
AR · PY · PE
Sem o módulo rep_actions.tasks no EMC e fora do enabledMarkets de answerTask, não há tela de Tarefas nesses mercados.
With no rep_actions.tasks module in the EMC and outside answerTask's enabledMarkets, there's no Tasks screen in these markets.
Sin el módulo rep_actions.tasks en el EMC y fuera del enabledMarkets de answerTask, no hay pantalla de Tareas en esos mercados.