DocumentaçãoDocumentationDocumentaciónOne Conecta
ÍndiceIndexÍndice
Baixar .mdDownload .mdBajar .md
Você está vendo esta documentação online. No topo você também pode baixar o PDF (mesmo conteúdo desta página, no idioma e modo atuais) e o Markdown (Funcional ou Técnica).You are viewing this documentation online. At the top you can also download the PDF (same content as this page, in the current language and mode) and the Markdown (Functional or Technical).Está viendo esta documentación en línea. Arriba también puede bajar el PDF (mismo contenido de esta página, en el idioma y modo actuales) y el Markdown (Funcional o Técnica).
Feature · Central de dadosFeature · Data centerFeature · Centro de datos

Central de dadosData centerCentro de datos

O console de sincronização do app: o que o aparelho enviou ao backend, o que ele recebeu do backend e — no Chile — os pagamentos ainda não sincronizados. Cada linha traz status, horário e, quando falhou, um código de erro e um botão para reenviar. The app's sync console: what the device has sent to the backend, what it has received from the backend and — in Chile — the payments not yet synced. Each row carries a status, a timestamp and, when it failed, an error code and a button to send it again. La consola de sincronización de la app: lo que el dispositivo envió al backend, lo que recibió del backend y — en Chile — los pagos aún no sincronizados. Cada fila trae estado, hora y, cuando falló, un código de error y un botón para reenviar.

PúblicoAudiencePúblico
Suporte · QA · Dev · RepresentanteSupport · QA · Dev · RepSoporte · QA · Dev · Representante
Onde ficaWhereDónde
Menu lateral → Central de dadosSide menu → Data centerMenú lateral → Centro de datos
RelacionadoRelatedRelacionado
Jornada · Criação de pagamentos · TransaçõesJourney · Payment creation · TransactionsJornada · Creación de pagos · Transacciones
AtualizadoUpdatedActualizado
30/07/20262026-07-30
Disponível emAvailable inDisponible en BR CL ZA
01

O que é e para que serveWhat it is and what it's forQué es y para qué sirve

A Central de dados é a tela onde se vê o tráfego de dados do aplicativo — não os dados em si, mas o transporte deles. Ela existe porque o app trabalha offline-first: telas abrem do cache local, e o envio ao backend acontece em segundo plano. Quando algo não chega, é aqui que se descobre o quê, quando e por quê. The Data center is the screen that shows the app's data traffic — not the data itself, but its transport. It exists because the app is offline-first: screens open from the local cache, and sending to the backend happens in the background. When something doesn't arrive, this is where you find out what, when and why. El Centro de datos es la pantalla donde se ve el tráfico de datos de la aplicación — no los datos en sí, sino su transporte. Existe porque la app trabaja offline-first: las pantallas abren del caché local, y el envío al backend ocurre en segundo plano. Cuando algo no llega, aquí se descubre qué, cuándo y por qué.

EnviosSentEnvíos

Toda transação que o app mandou ao backend — pedido, visita, pesquisa, contagem de estoque — com o resultado de cada uma.Every transaction the app sent to the backend — order, visit, survey, stock count — with the outcome of each one.Toda transacción que la app envió al backend — pedido, visita, encuesta, conteo de stock — con el resultado de cada una.

RecebimentosReceivedRecepción

Uma linha por estrutura de dados que o app baixa (pedidos, varejos, catálogo…), com a hora da última sincronização bem-sucedida.One row per data structure the app downloads (orders, retails, catalog…), with the time of the last successful sync.Una fila por estructura de datos que la app descarga (pedidos, puntos de venta, catálogo…), con la hora de la última sincronización exitosa.

Pagamentos (só CL)Payments (CL only)Pagos (solo CL)

Pagamentos registrados no aparelho que ainda esperam algo do backend para poderem ser enviados.Payments registered on the device still waiting on something from the backend before they can be sent.Pagos registrados en el dispositivo que aún esperan algo del backend para poder enviarse.

Tudo localAll localTodo local A tela não consulta o backend para se montar: ela lê três registros gravados no próprio aparelho. Isso significa que ela funciona offline — e também que ela mostra o que o app acredita ter acontecido, não o que o servidor confirma agora. The screen does not query the backend to build itself: it reads three journals stored on the device. That means it works offline — and also that it shows what the app believes happened, not what the server confirms right now. La pantalla no consulta el backend para armarse: lee tres registros guardados en el propio dispositivo. Eso significa que funciona offline — y también que muestra lo que la app cree que pasó, no lo que el servidor confirma ahora.

02

Como acessarHow to openCómo acceder

quatro caminhos, e todos abrem a mesma tela:There are four ways in, and they all open the same screen:Hay cuatro caminos, y todos abren la misma pantalla:

  1. Pelo menu lateralFrom the side menuDesde el menú lateralAbra o menu (ícone de gaveta) e toque em Central de dados. É o caminho principal, e o item é declarado na configuração de mercado — não está fixo no código.Open the drawer and tap Data center. This is the main route, and the item is declared in market configuration — it isn't hardcoded.Abra el menú lateral y toque Centro de datos. Es el camino principal, y el ítem se declara en la configuración de mercado — no está fijo en el código.
  2. Pelo encerramento da jornadaFrom the end of the journeyDesde el cierre de jornadaNa tela de pendências de fim de dia (Jornada), a categoria transações não sincronizadas leva direto para cá — tanto pela linha da categoria quanto por cada item listado.On the end-of-day pendings screen (Journey), the unsynced transactions category leads straight here — both from the category row and from each listed item.En la pantalla de pendientes de fin de día (Jornada), la categoría transacciones no sincronizadas lleva directo aquí — tanto desde la fila de la categoría como desde cada ítem listado.
  3. Pelo encerramento da visitaFrom the visit wrap-upDesde el cierre de la visitaO cartão de pendências ao finalizar uma visita tem um botão Ver Central de Dados na categoria de transações não sincronizadas.The pendings card shown when finishing a visit has an Open Data Center button on the unsynced-transactions category.La tarjeta de pendientes al finalizar una visita tiene un botón Ver Centro de Datos en la categoría de transacciones no sincronizadas.
  4. A tela abreThe screen opensLa pantalla abreSempre na primeira aba (Envios). Puxe para baixo para recarregar. Não há atalho na Home nem no menu de configurações.Always on the first tab (Sent). Pull down to reload. There is no Home shortcut and no settings entry.Siempre en la primera pestaña (Envíos). Deslice hacia abajo para recargar. No hay atajo en el Home ni en configuración.
03

Estrutura da telaScreen structureEstructura de la pantalla

CabeçalhoHeaderEncabezado
Ícone de banco de dados + título "Central de dados". Não há indicador de última sincronização geral — cada linha traz o seu próprio horário.A database icon + the "Data center" title. There is no overall last-sync indicator — each row carries its own timestamp.Ícono de base de datos + el título "Centro de datos". No hay indicador de última sincronización general — cada fila trae su propia hora.
AbasTabsPestañas
Envios e Recebimentos em todos os mercados; Pagamentos apenas no Chile. As abas vêm da configuração de mercado, e a barra só aparece quando há mais de uma.Sent and Received in every market; Payments only in Chile. Tabs come from market configuration, and the bar only shows when there is more than one.Envíos y Recepción en todos los mercados; Pagos solo en Chile. Las pestañas vienen de la configuración de mercado, y la barra solo aparece cuando hay más de una.
Caixas de contagemCount boxesCajas de conteo
Três atalhos no topo (Enviados / Erros / Pendentes; em Recebimentos o primeiro é Recebidos). Cada um mostra a contagem e funciona como filtro: tocar filtra a lista por aquele grupo, tocar de novo limpa.Three shortcuts at the top (Sent / Errors / Pending; on Received the first is Received). Each shows a count and acts as a filter: tapping filters the list by that group, tapping again clears it.Tres atajos arriba (Enviados / Errores / Pendientes; en Recepción el primero es Recibidos). Cada uno muestra el conteo y funciona como filtro: tocar filtra la lista por ese grupo, tocar de nuevo limpia.
BuscaSearchBúsqueda
Um campo único, com a dica "Busque por SAP do varejo ou código de erro".A single field, hinted "Search by retail SAP or error code".Un campo único, con la pista "Busca por SAP del comercio o código de error".
Ordenar e FiltrarSort and FilterOrdenar y Filtrar
Dois botões alinhados à direita, cada um abrindo um modal. Ficam realçados quando há ordenação ou filtro ativo.Two right-aligned buttons, each opening a modal. They highlight when a sort or a filter is active.Dos botones alineados a la derecha, cada uno abriendo un modal. Se resaltan cuando hay orden o filtro activo.
Cartão "Sincronizar todos""Sync all" cardTarjeta "Sincronizar todos"
Aparece somente na aba Recebimentos, acima da lista, e baixa tudo de novo.Appears only on the Received tab, above the list, and re-downloads everything.Aparece solo en la pestaña Recepción, arriba de la lista, y descarga todo de nuevo.
Cartões da listaList cardsTarjetas de la lista
Um por item: ícone colorido do grupo, etiqueta de status, contador de tentativas (quando maior que 1), título, código de erro quando houver, e um rodapé com data/hora e o botão de ação.One per item: colored group icon, status tag, attempts counter (when above 1), title, error code when present, and a footer with date/time and the action button.Una por ítem: ícono de color del grupo, etiqueta de estado, contador de intentos (cuando es mayor que 1), título, código de error cuando exista, y un pie con fecha/hora y el botón de acción.
Estado vazioEmpty stateEstado vacío
Mensagem própria por aba ("Nenhum envio no momento" / "Nenhum recebimento no momento").A per-tab message ("No sends at the moment" / "No received data at the moment").Un mensaje por pestaña ("Sin envíos por el momento" / "Sin recepciones por el momento").
04

Status e caixasStatuses & boxesEstados y cajas

Cada aba tem o seu próprio conjunto de status, mas todos caem em três grupos visuais — e é o grupo que define a cor, o ícone e a caixa de contagem:Each tab has its own set of statuses, but they all fall into three visual groups — and it's the group that sets the color, the icon and the count box:Cada pestaña tiene su propio conjunto de estados, pero todos caen en tres grupos visuales — y es el grupo el que define el color, el ícono y la caja de conteo:

Enviado / Recebido / DuplicadoSent / Received / DuplicatedEnviado / Recibido / Duplicado ErroErrorError PendentePendingPendiente
AbaTabPestañaStatus exibidoDisplayed statusEstado mostradoGrupo / caixaGroup / boxGrupo / cajaO que significaWhat it meansQué significa
EnviosSentEnvíosEnviadoSentEnviadoEnviadosSentEnviadosO backend aceitou. O conteúdo enviado é descartado do aparelho.The backend accepted it. The sent content is discarded from the device.El backend lo aceptó. El contenido enviado se descarta del dispositivo.
EnviosSentEnvíosDuplicadoDuplicatedDuplicadoEnviadosSentEnviadosO backend reconheceu que já tinha essa transação. Conta como sucesso — não precisa reenviar.The backend recognised it already had this transaction. Counts as success — no need to resend.El backend reconoció que ya tenía esa transacción. Cuenta como éxito — no hay que reenviar.
EnviosSentEnvíosErroErrorErrorErrosErrorsErroresFalhou — de rede ou recusado pelo backend. É o único status que pode ser reenviado à mão.It failed — network, or rejected by the backend. It's the only status that can be resent by hand.Falló — de red o rechazado por el backend. Es el único estado que se puede reenviar a mano.
EnviosSentEnvíosPendentePendingPendientePendentesPendingPendientesGuardado na fila offline para ir sozinho quando a conexão voltar. Só visitas chegam a esse status (ver Pendências).Queued offline to go on its own once the connection returns. Only visits ever reach this status (see Pending items).Guardado en la cola offline para irse solo cuando vuelva la conexión. Solo las visitas llegan a ese estado (ver Pendientes).
RecebimentosReceivedRecepciónRecebidoReceivedRecibidoRecebidosReceivedRecibidosA última tentativa de baixar aquela estrutura deu certo.The last attempt to download that structure succeeded.El último intento de bajar esa estructura salió bien.
RecebimentosReceivedRecepciónErroErrorErrorErrosErrorsErroresA última tentativa falhou. O aparelho continua com o dado antigo em cache.The last attempt failed. The device still holds the older cached data.El último intento falló. El dispositivo sigue con el dato antiguo en caché.
RecebimentosReceivedRecepciónPendentePendingPendientePendentesPendingPendientesAquela estrutura nunca foi sincronizada neste aparelho — não existe registro dela.That structure has never been synced on this device — there is no record of it.Esa estructura nunca se sincronizó en este dispositivo — no existe registro de ella.
PagamentosPaymentsPagosSincronizadoSyncedSincronizadoEnviadosSentEnviadosO pagamento já foi despachado ao backend.The payment has already been dispatched to the backend.El pago ya fue despachado al backend.
PagamentosPaymentsPagosPronto para sincronizarReady to syncListo para sincronizarPendentesPendingPendientesJá tem tudo o que precisa. É o único status com botão Sincronizar.It has everything it needs. It's the only status with a Sync button.Ya tiene todo lo que necesita. Es el único estado con botón Sincronizar.
PagamentosPaymentsPagosAguardando débito do pedidoAwaiting order debitEsperando el débito del pedidoPendentesPendingPendientesEspera o título financeiro correspondente aparecer numa sincronização.Waiting for the matching financial item to show up in a sync.Espera que el título financiero correspondiente aparezca en una sincronización.
PagamentosPaymentsPagosAguardando aprovação do pedidoAwaiting order approvalEsperando aprobación del pedidoPendentesPendingPendientesO pedido de origem ainda não foi aprovado.The originating order hasn't been approved yet.El pedido de origen aún no fue aprobado.

Contagens não seguem os filtrosCounts ignore the filtersLos conteos ignoran los filtros As três caixas contam sempre o total da aba, não o que está visível depois da busca e dos filtros. Isso é de propósito: elas são os botões de filtro, então precisam mostrar quanto existe em cada grupo. The three boxes always count the whole tab, not what's visible after search and filters. That's on purpose: they are the filter buttons, so they have to show how much exists in each group. Las tres cajas cuentan siempre el total de la pestaña, no lo visible tras la búsqueda y los filtros. Es a propósito: ellas son los botones de filtro, así que deben mostrar cuánto existe en cada grupo.

05

AçõesActionsAcciones

Reenviar um envio que falhouResend a failed sendReenviar un envío que falló

Cartões em Erro na aba Envios trazem um botão Reenviar — no cartão e também dentro do detalhe. Ele abre uma confirmação, e o texto dessa confirmação muda conforme o risco: para transações leves diz apenas que será enviada de novo; para todas as outras avisa que pode duplicar no servidor. Só três tipos são considerados leves (leitura de notificação, resposta de tarefa e checagem de preço); os outros 39 recebem o aviso. Cards in Error on the Sent tab carry a Resend button — on the card and inside the detail. It opens a confirmation whose wording changes with the risk: for lightweight transactions it just says it will be sent again; for all others it warns it may duplicate on the server. Only three types count as lightweight (notification read, task answer and price check); the other 39 get the warning. Las tarjetas en Error de la pestaña Envíos traen un botón Reenviar — en la tarjeta y también dentro del detalle. Abre una confirmación cuyo texto cambia según el riesgo: para transacciones livianas solo dice que se enviará de nuevo; para todas las demás avisa que puede duplicarse en el servidor. Solo tres tipos se consideran livianos (lectura de notificación, respuesta de tarea y chequeo de precio); los otros 39 reciben el aviso.

O reenvio reaproveita exatamente o mesmo conteúdo e a mesma referência da primeira tentativa — nada é regerado. O contador de tentativas do cartão sobe a cada reenvio. A resend reuses exactly the same content and the same reference as the first attempt — nothing is regenerated. The card's attempt counter goes up on each resend. El reenvío reutiliza exactamente el mismo contenido y la misma referencia del primer intento — nada se regenera. El contador de intentos de la tarjeta sube en cada reenvío.

Sincronizar dadosSync dataSincronizar datos

Na aba Recebimentos há duas formas: o botão Sincronizar de cada cartão, que baixa só aquela estrutura, e o cartão Sincronizar todos os dados, no topo, que refaz a carga completa. Enquanto a carga completa roda, os botões individuais também aparecem carregando. On the Received tab there are two ways: each card's Sync button, which downloads only that structure, and the Sync all data card at the top, which redoes the full load. While the full load runs, the individual buttons also show as loading. En la pestaña Recepción hay dos formas: el botón Sincronizar de cada tarjeta, que baja solo esa estructura, y la tarjeta Sincronizar todos los datos, arriba, que rehace la carga completa. Mientras la carga completa corre, los botones individuales también aparecen cargando.

Sincronizar um pagamento (CL)Sync a payment (CL)Sincronizar un pago (CL)

Só os pagamentos Pronto para sincronizar têm botão. Diferente do reenvio, ele não pede confirmação: envia na hora. Um pagamento entra em "pronto" sozinho, quando o app abre ou recarrega esta tela e encontra no cache o título financeiro que faltava. Only payments in Ready to sync have a button. Unlike a resend, it asks for no confirmation: it sends right away. A payment becomes "ready" on its own, when the app opens or reloads this screen and finds the missing financial item in the cache. Solo los pagos en Listo para sincronizar tienen botón. A diferencia del reenvío, no pide confirmación: envía al instante. Un pago pasa a "listo" por su cuenta, cuando la app abre o recarga esta pantalla y encuentra en el caché el título financiero que faltaba.

Buscar, ordenar, filtrarSearch, sort, filterBuscar, ordenar, filtrar

A busca aceita várias palavras e exige que todas apareçam. Em Envios ela procura no nome e no código SAP do varejo, no tipo da transação, no código de erro e no tipo de visita; em Recebimentos, no nome da estrutura, no código de erro e no nome interno do tipo; em Pagamentos, só no status e no código de erro. The search accepts several words and requires all of them to appear. On Sent it looks at the retail's name and SAP code, the transaction type, the error code and the visit kind; on Received, at the structure name, the error code and the type's internal name; on Payments, only at the status and the error code. La búsqueda acepta varias palabras y exige que todas aparezcan. En Envíos busca en el nombre y el código SAP del punto de venta, el tipo de transacción, el código de error y el tipo de visita; en Recepción, en el nombre de la estructura, el código de error y el nombre interno del tipo; en Pagos, solo en el estado y el código de error.

A ordenação tem quatro opções fixas: mais recentes (padrão), mais antigos, por tipo e por status. Os filtros mudam por aba e vêm da configuração de mercado — em Envios são status, tipo de transação, número de tentativas (1 ou mais de 1) e período (última 1h, 2h, 4h ou 6h); em Recebimentos, status e estrutura; em Pagamentos, status e meio de pagamento. Os filtros valem só depois de tocar em Aplicar. The sort has four fixed options: newest first (default), oldest first, by type and by status. The filters change per tab and come from market configuration — on Sent they are status, transaction type, attempt count (1 or more than 1) and period (last 1h, 2h, 4h or 6h); on Received, status and structure; on Payments, status and payment method. Filters only apply after you tap Apply. El orden tiene cuatro opciones fijas: más recientes (por defecto), más antiguos, por tipo y por estado. Los filtros cambian por pestaña y vienen de la configuración de mercado — en Envíos son estado, tipo de transacción, cantidad de intentos (1 o más de 1) y período (última 1h, 2h, 4h o 6h); en Recepción, estado y estructura; en Pagos, estado y medio de pago. Los filtros valen solo tras tocar Aplicar.

Abrir o detalhe e copiar o código de suporteOpen the detail and copy the support codeAbrir el detalle y copiar el código de soporte

Tocar num cartão de Envios abre o detalhe da transação (tipo, status, varejo, serviço, referência, identificador do backend, horários, tentativas, código e mensagem de erro). Tocar num cartão de Recebimentos abre o detalhe da estrutura. Cartões de Pagamentos não abrem nada — o toque não leva a nenhuma tela. Tapping a Sent card opens the transaction detail (type, status, retail, service, reference, backend id, timestamps, attempts, error code and message). Tapping a Received card opens the structure detail. Payment cards open nothing — the tap leads to no screen. Tocar una tarjeta de Envíos abre el detalle de la transacción (tipo, estado, punto de venta, servicio, referencia, identificador del backend, horas, intentos, código y mensaje de error). Tocar una tarjeta de Recepción abre el detalle de la estructura. Las tarjetas de Pagos no abren nada — el toque no lleva a ninguna pantalla.

No detalhe de um envio com erro há o botão Copiar código de suporte: ele copia um bloco completo de diagnóstico — tipo, serviço, status, varejo, referências, mercado, ambiente, versão do app, dados do representante, horários e todos os campos de erro. É o que se cola num ticket. On the detail of a failed send there's a Copy support code button: it copies a full diagnostic block — type, service, status, retail, references, market, environment, app version, rep data, timestamps and every error field. That's what you paste into a ticket. En el detalle de un envío con error hay un botón Copiar código de soporte: copia un bloque completo de diagnóstico — tipo, servicio, estado, punto de venta, referencias, mercado, ambiente, versión de la app, datos del representante, horas y todos los campos de error. Es lo que se pega en un ticket.

06

Arquitetura e fluxo de dadosArchitecture & data flowArquitectura y flujo de datos

Clean Architecture + Riverpod + Freezed + ObjectBox. A Central de dados é puramente leitora e 100% local: ela não tem RPC próprio nem datasource remoto. O que ela lê são três diários gravados no ObjectBox por outros subsistemas — o orquestrador de despachos, o orquestrador de sincronia e o orquestrador de pagamentos. Por isso a arquitetura se descreve como três fluxos de escrita que desembocam num único leitor. Clean Architecture + Riverpod + Freezed + ObjectBox. The Data center is purely a reader and 100% local: it has no RPC of its own and no remote datasource. What it reads are three journals written to ObjectBox by other subsystems — the dispatch orchestrator, the sync orchestrator and the payment orchestrator. Hence the architecture is described as three write flows feeding a single reader. Clean Architecture + Riverpod + Freezed + ObjectBox. El Centro de datos es puramente lector y 100% local: no tiene RPC propio ni datasource remoto. Lo que lee son tres registros grabados en ObjectBox por otros subsistemas — el orquestador de despachos, el de sincronización y el de pagos. Por eso la arquitectura se describe como tres flujos de escritura que desembocan en un único lector.

A — Envios (escrita de transações)A — Sent (transaction writes)A — Envíos (escritura de transacciones)

  • Notifiera feature que enviathe sending featurela feature que envía
    • buildBuild{X}DispatcherPayloadUseCase36 builders · monta o JSON36 builders · builds the JSON36 builders · arma el JSON
      • DispatcherEnvelopeSubmit{X}UseCase34 wrappers finos34 thin wrappers34 wrappers finos
        • dispatchDispatcherOrchestratorguarda offline · interpreta o ackoffline guard · reads the ackguarda offline · interpreta el ack
          • sendDispatcherRepositoryImpl DispatcherGateway · gRPC
            • sendTransactionInboxTransactionReplystatus · transactionIdstatus · transactionIdstatus · transactionId
              • saveDispatchTransactionModelObjectBox
                • toDomainDispatchTransactionEntitydomain
                  • getAllDataCenterNotifieraba EnviosSent tabpestaña Envíos

B — Recebimentos (sincronia de leitura)B — Received (read sync)B — Recepción (sincronización de lectura)

  • DataSyncOrchestratortimer auto-reagendável · TTL por estruturaself-rescheduling timer · per-structure TTLtimer auto-reagendable · TTL por estructura
    • sweepDataSyncTarget26 alvos · refreshFromSource26 targets · refreshFromSource26 objetivos · refreshFromSource
      • Get{X}UseCaseRepositoryremoto → cache da featureremote → feature cacheremoto → caché de la feature
        • _recordSyncOutcomeDataSyncRecordModelObjectBox · 1 linha por tipoObjectBox · 1 row per typeObjectBox · 1 fila por tipo
          • toDomainDataSyncRecordEntitydomain
            • getAll ⨝ forMarketDataCenterNotifieraba RecebimentosReceived tabpestaña Recepción

C — Pagamentos (só CL)C — Payments (CL only)C — Pagos (solo CL)

  • PaymentSubmissionOrchestratorsubmit diferidodeferred submitsubmit diferido
    • _saveRegistersPaymentRegisterModelObjectBox · ORDER_PA / CREATED
      • executeResolvePendingPaymentRegistersUseCasecasa com o título financeiro → READYmatches the financial item → READYcruza con el título financiero → READY
        • botão SincronizarSync buttonbotón SincronizarSyncPaymentRegisterUseCasesyncRegister
          • 1..3 envelopesDispatcherOrchestratorvolta ao fluxo Aback into flow Avuelve al flujo A
07

Modelo de dadosData modelModelo de datos

Esta feature é a exceção do molde: os dados que ela exibe não vêm do wire, então não existem as quatro representações habituais. Cada um dos três diários tem exatamente duas camadas — Model (ObjectBox) e Entity (domínio) — ligadas por um mapper de duas direções. Não há Proto e não há DTO para nenhum dos três, porque nenhum deles é recebido do backend: os três são gerados pelo próprio app. This feature is the template's exception: the data it shows doesn't come from the wire, so the usual four representations don't exist. Each of the three journals has exactly two layers — Model (ObjectBox) and Entity (domain) — linked by a two-way mapper. There is no Proto and no DTO for any of the three, because none of them is received from the backend: all three are generated by the app itself. Esta feature es la excepción del molde: los datos que muestra no vienen del wire, así que no existen las cuatro representaciones habituales. Cada uno de los tres registros tiene exactamente dos capas — Model (ObjectBox) y Entity (dominio) — unidas por un mapper de dos direcciones. No hay Proto ni DTO para ninguno de los tres, porque ninguno se recibe del backend: los tres los genera la propia app.

O único proto envolvido é o do Dispatcher, e ele é do lado da escrita: é por ele que sai toda transação cujo resultado a aba Envios depois exibe. A seguir, na ordem: o proto de saída, as três estruturas campo-a-campo por camada, e os mappers. The only proto involved is the Dispatcher's, and it belongs to the write side: it's the pipe every transaction leaves through, whose outcome the Sent tab later displays. Next, in order: the outbound proto, the three structures field-by-field per layer, and the mappers. El único proto involucrado es el del Dispatcher, y es del lado de la escritura: es por él que sale toda transacción cuyo resultado la pestaña Envíos muestra después. A continuación, en orden: el proto de salida, las tres estructuras campo a campo por capa, y los mappers.

Proto

DispatcherConectaRep.proto · proto3 · package mn.bat.conectarep.dispatcher. Um serviço (DispatcherConectaRepService) e um único RPC genérico — não há mensagem por transação. O discriminador é a string serviceName e o JSON da transação viaja em message:One service (DispatcherConectaRepService) and a single generic RPC — there is no per-transaction message. The discriminator is the serviceName string and the transaction JSON travels in message:Un servicio (DispatcherConectaRepService) y un único RPC genérico — no hay mensaje por transacción. El discriminador es la string serviceName y el JSON de la transacción viaja en message:

sendTransactionunary
MétodoMethodMétodo

rpc sendTransaction(InboxTransactionRequest) returns (InboxTransactionReply)

path /mn.bat.conectarep.dispatcher.DispatcherConectaRepService/sendTransaction

Request · InboxTransactionRequest
endpoint
string · #1 · destino do tipo (salesforce / sfbatchapi / competitor / vazio)the type's destination (salesforce / sfbatchapi / competitor / empty)destino del tipo (salesforce / sfbatchapi / competitor / vacío)
serviceName
string · #2 · o discriminador, com prefixo Promo_ quando há promoçãothe discriminator, prefixed Promo_ when a promotion is presentel discriminador, con prefijo Promo_ cuando hay promoción
dateReference
string · #3
transactionReference
string · #4 · identificador de domínio; é a chave de deduplicação dos tipos de pedidodomain identifier; the dedup key for order typesidentificador de dominio; la clave de deduplicación de los tipos de pedido
username
string · #5 · resource?.username ?? ""
message
string · #6 · o payload inteiro como JSON (jsonEncode)the whole payload as JSON (jsonEncode)el payload completo como JSON (jsonEncode)
manufacturer
string · #7
model
string · #8
deviceUuid
string · #9 · literal fixo "REP" — não é um UUID de aparelhohardcoded literal "REP" — not a device UUIDliteral fijo "REP" — no es un UUID de dispositivo
deviceVersion
string · #10
tid
int64 · #11 · 0 na primeira tentativa; no reenvio recebe o transactionId guardado (replay idempotente)0 on the first attempt; on resend it carries the stored transactionId (idempotent replay)0 en el primer intento; en el reenvío lleva el transactionId guardado (replay idempotente)
Reply · InboxTransactionReply

int32 status · string message · int32 transactionIdo único retorno do servidor. status 0 ou 5 = sucesso, 1 = duplicado (registrado como sucesso), qualquer outro = erro. Não existe RPC para consultar o histórico: o app nunca reconcilia o que gravou com o que o servidor tem.the server's only response. status 0 or 5 = success, 1 = duplicate (recorded as success), anything else = error. There is no RPC to query history: the app never reconciles what it stored against what the server holds.la única respuesta del servidor. status 0 o 5 = éxito, 1 = duplicado (registrado como éxito), cualquier otro = error. No existe RPC para consultar el historial: la app nunca reconcilia lo que grabó con lo que el servidor tiene.

Estruturas de dadosData structuresEstructuras de datos

Um dropdown por estrutura, aninhados pela hierarquia. Cada tabela tem uma coluna por camada — Model · Entity (não há Proto nem DTO, ver acima); as células com texto em destaque marcam onde o tipo muda entre as duas.One dropdown per structure, nested by hierarchy. Each table has one column per layer — Model · Entity (there is no Proto and no DTO, see above); highlighted cells mark where the type changes between the two.Un dropdown por estructura, anidados por jerarquía. Cada tabla tiene una columna por capa — Model · Entity (no hay Proto ni DTO, ver arriba); las celdas con texto destacado marcan dónde cambia el tipo entre las dos.

  • DispatchTransaction diário de enviossent journalregistro de envíos 21 camposfieldscampos · 25 colunascolumnscolumnas
    CampoModel (ObjectBox)Entity
    localId / idint · @Id()int
    typeStringDispatcherType
    serviceNameStringString
    transactionReferenceStringString
    dateReferenceStringString
    statusString · @Index()DispatchTransactionStatus
    marketStringEndMarket
    submittedAtDateTime · @Index()DateTime
    resolvedAtDateTime?DateTime?
    payload / payloadGzipList<int> byteVectorMap<String, dynamic>?
    backendTransactionIdintint
    attemptCountintint
    stableCodeStringString
    appErrorCodeStringString
    categoryStringString
    traceIdStringString
    errorCodeStringString
    errorMessageStringString
    originalErrorStringString
    ackStatusintint
    ackMessageStringString
    accountaccountSfid + accountSapCode + accountNameDispatchAccountEntity?
    visitDispatchKindStringVisitDispatchKind?
    • DispatchAccountEntity DispatchTransaction.account 3 camposfieldscampos
      CampoModel (ObjectBox)Entity
      sfidaccountSfid StringString
      sapCodeaccountSapCode StringString
      nameaccountName StringString

      Não é uma relação ObjectBox: os três campos são achatados no próprio model. Getter isEmpty. Na volta a conta só é reconstruída se ao menos um dos três estiver preenchido — uma conta presente mas totalmente vazia volta como null.Not an ObjectBox relation: the three fields are flattened into the model itself. Getter isEmpty. On the way back the account is only rebuilt if at least one of the three is filled — an account that was present but entirely empty comes back as null.No es una relación ObjectBox: los tres campos se achatan en el propio model. Getter isEmpty. En la vuelta la cuenta solo se reconstruye si al menos uno de los tres está lleno — una cuenta presente pero totalmente vacía vuelve como null.

  • DataSyncRecord diário de recebimentosreceived journalregistro de recepción 6 camposfieldscampos
    CampoModel (ObjectBox)Entity
    localId / idint · @Id()int
    typeString · @Index()DataSyncType
    statusStringDataSyncRecordStatus
    marketStringEndMarket
    lastSyncAtDateTime?DateTime?
    errorMessageStringString

    Sem getters. É um upsert por tipo: existe no máximo uma linha por DataSyncType, e a chave de busca é só o type — o market não entra no predicado.No getters. It's an upsert by type: at most one row per DataSyncType, and the lookup key is only typemarket is not in the predicate.Sin getters. Es un upsert por tipo: existe como máximo una fila por DataSyncType, y la clave de búsqueda es solo typemarket no entra en el predicado.

  • PaymentRegister diário de pagamentos · CLpayment journal · CLregistro de pagos · CL 30 camposfieldscampos · 32 colunascolumnscolumnas
    CampoModel (ObjectBox)Entity
    localId / idint · @Id()int
    groupIdString · @Index()String
    paymentIdMobileString · @Index()String
    originStringPaymentCreationOrigin
    statusString · @Index()PaymentRegisterStatus
    accountSfidString · @Index()String
    accountSapCodeStringString
    accountNameStringString
    debitOpenItemSfidString · @Index()String
    debitOpenItemNameStringString
    invoiceLegalNumberStringString
    orderSfidStringString
    purchaseOrderNumberStringString
    methodString (.code)PaymentMethod
    bankSfidStringString
    bankBranchSfidStringString
    collectionReferenceStringString
    creditNotes3 listas paralelasList<PaymentCreditNoteSelectionEntity>
    documentAmountdoubledouble
    payedAmountdoubledouble
    creditPerioddoubledouble
    orderAmountdoubledouble
    paymentDateDateTime?DateTime?
    documentDateDateTime?DateTime?
    createdAtDateTimeDateTime
    evidenceImageBase64StringString
    evidenceFileBase64StringString
    evidenceFileNameStringString
    evidenceStatusStringPaymentEvidenceStatus
    errorMessageStringString

    Getters: isPending, isSyncable, hasError, hasEvidence, isWaitingDebitOpenItem; e toDraft(), que reconstrói um PaymentDraftEntity de um débito e um método para poder reenviar.Getters: isPending, isSyncable, hasError, hasEvidence, isWaitingDebitOpenItem; plus toDraft(), which rebuilds a single-debit, single-method PaymentDraftEntity so it can be sent again.Getters: isPending, isSyncable, hasError, hasEvidence, isWaitingDebitOpenItem; y toDraft(), que reconstruye un PaymentDraftEntity de un débito y un método para poder reenviar.

Mappers

Só existem duas das cinco direções habituais, para cada um dos três diários — não há fronteira de wire a atravessar:Only two of the usual five directions exist, for each of the three journals — there is no wire boundary to cross:Solo existen dos de las cinco direcciones habituales, para cada uno de los tres registros — no hay frontera de wire que cruzar:

DireçãoDirectionDirecciónMétodoMethodMétodoO que aconteceWhat happensQué pasa
JSON → DTOnão existe (sem DTO)doesn't exist (no DTO)no existe (sin DTO)
Proto → DTOnão existe (sem proto de leitura)doesn't exist (no read proto)no existe (sin proto de lectura)
DTO → Entitynão existedoesn't existno existe
Entity → ModeltoModel()enums → .name/.value/.key/.code; conta achatada em 3 colunas; payload → gzip do JSON; notas de crédito → 3 listas paralelasenums → .name/.value/.key/.code; account flattened into 3 columns; payload → gzipped JSON; credit notes → 3 parallel listsenums → .name/.value/.key/.code; cuenta achatada en 3 columnas; payload → gzip del JSON; notas de crédito → 3 listas paralelas
Model → EntitytoDomain()resolve os enums com fallback silencioso em todos os casos (ver os deltas abaixo); descomprime o payloadresolves the enums with a silent fallback in every case (see the deltas below); decompresses the payloadresuelve los enums con fallback silencioso en todos los casos (ver los deltas abajo); descomprime el payload

Os únicos deltasThe only deltasLos únicos deltas

  • enums tipados só na Entity — no Model são String, gravados por .name (DispatcherType, EndMarket), .value (status, VisitDispatchKind), .key (DataSyncType) ou .code (PaymentMethod)enums typed only in the Entity — in the Model they are String, written by .name (DispatcherType, EndMarket), .value (statuses, VisitDispatchKind), .key (DataSyncType) or .code (PaymentMethod)enums tipados solo en la Entity — en el Model son String, grabados por .name (DispatcherType, EndMarket), .value (estados, VisitDispatchKind), .key (DataSyncType) o .code (PaymentMethod)
  • payload MapList<int> no Model: JSON serializado e comprimido com GZipCodec num byteVector. É descartado (null) quando o envio dá certo — por isso um envio bem-sucedido não pode ser reenviado.in the Model: JSON serialized and gzipped into a byteVector. It is discarded (null) when the send succeeds — which is why a successful send cannot be resent.en el Model: JSON serializado y comprimido con GZipCodec en un byteVector. Se descarta (null) cuando el envío tiene éxito — por eso un envío exitoso no puede reenviarse.
  • DispatchAccountEntity achatada em três colunas no Model; volta como null se as três estiverem vaziasflattened into three columns in the Model; comes back as null if all three are emptyachatada en tres columnas en el Model; vuelve como null si las tres están vacías
  • creditNotes quebrada em três listas paralelas (sfids, referenceNumbers, amounts) e recomposta por índice, com defaults defensivos quando as listas divergem de tamanhosplit into three parallel lists (sfids, referenceNumbers, amounts) and zipped back by index, with defensive defaults when the lists differ in lengthpartida en tres listas paralelas (sfids, referenceNumbers, amounts) y recompuesta por índice, con defaults defensivos cuando las listas difieren de largo
  • todo parse de volta tem fallback silencioso, e nenhum deles registra o valor não mapeado: type desconhecido → DispatcherType.visit / DataSyncType.resource; market desconhecido → EndMarket.BR; status desconhecido → error (envios), pending (recebimentos), unknown (pagamentos)every parse back has a silent fallback, and none of them logs the unmapped value: unknown typeDispatcherType.visit / DataSyncType.resource; unknown marketEndMarket.BR; unknown statuserror (sent), pending (received), unknown (payments)todo parseo de vuelta tiene fallback silencioso, y ninguno registra el valor no mapeado: type desconocido → DispatcherType.visit / DataSyncType.resource; market desconocido → EndMarket.BR; status desconocido → error (envíos), pending (recepción), unknown (pagos)
  • nenhum dos três diários tem lastSyncAt próprio nem DataLoadInfo — os relógios são submittedAt/resolvedAt (envios), lastSyncAt da estrutura (recebimentos) e createdAt (pagamentos)none of the three journals has its own lastSyncAt or a DataLoadInfo — the clocks are submittedAt/resolvedAt (sent), the structure's lastSyncAt (received) and createdAt (payments)ninguno de los tres registros tiene lastSyncAt propio ni DataLoadInfo — los relojes son submittedAt/resolvedAt (envíos), el lastSyncAt de la estructura (recepción) y createdAt (pagos)
08

Repositories

A tela depende de quatro repositories. Três são diários locais puros — cada um injeta só o datasource local, sem mock, sem remoto, sem ConnectivityService e sem Ref, e todos seguem o mesmo molde de três passos (chama o datasource síncrono, embrulha em Success; em qualquer exceção mapeia para Failure, loga e devolve Error). O quarto é o transporte do Dispatcher, o único que fala com a rede. The screen depends on four repositories. Three are pure local journals — each injects only the local datasource, no mock, no remote, no ConnectivityService and no Ref, and all follow the same three-step template (call the synchronous datasource, wrap in Success; on any exception map to a Failure, log it and return Error). The fourth is the Dispatcher's transport, the only one that talks to the network. La pantalla depende de cuatro repositories. Tres son registros locales puros — cada uno inyecta solo el datasource local, sin mock, sin remoto, sin ConnectivityService y sin Ref, y todos siguen el mismo molde de tres pasos (llama al datasource síncrono, envuelve en Success; en cualquier excepción mapea a Failure, loguea y devuelve Error). El cuarto es el transporte del Dispatcher, el único que habla con la red.

Um dropdown por método — assinatura, retorno e comportamento.One dropdown per method — signature, return and behavior.Un dropdown por método — firma, retorno y comportamiento.

DispatchTransactionRepositoryImpl

getAll() local

RetornaReturnsDevuelve Result<List<DispatchTransactionEntity>, Failure>

Lê a caixa inteira, ordenada por submittedAt decrescente. É o que alimenta a aba Envios e também as contagens do orquestrador. Descomprime o payload de toda linha, sempre.Reads the whole box, sorted by submittedAt descending. It feeds the Sent tab and also the orchestrator's counters. It decompresses every row's payload, every time.Lee la caja entera, ordenada por submittedAt descendente. Alimenta la pestaña Envíos y también los conteos del orquestador. Descomprime el payload de toda fila, siempre.

getById({localId}) local

RetornaReturnsDevuelve Result<DispatchTransactionEntity?, Failure>

Busca por chave primária. Linha ausente vira Success(null), não erro. É o primeiro passo do reenvio.Primary-key lookup. A missing row becomes Success(null), not an error. It's the first step of a resend.Búsqueda por clave primaria. Fila ausente es Success(null), no error. Es el primer paso del reenvío.

getPendingVisits() local · fila offlinelocal · offline queuelocal · cola offline

RetornaReturnsDevuelve Result<List<DispatchTransactionEntity>, Failure>

Filtra em memória por type == visit e status == pending, ordenado por submittedAt crescente (FIFO). É a fila que o flush() consome — e a razão pela qual só visitas são reenviadas automaticamente.Filters in memory by type == visit and status == pending, sorted by submittedAt ascending (FIFO). This is the queue flush() consumes — and the reason only visits are retried automatically.Filtra en memoria por type == visit y status == pending, ordenado por submittedAt ascendente (FIFO). Es la cola que consume flush() — y la razón por la que solo las visitas se reintentan automáticamente.

getByTypeForAccount({type, accountSfid, dateReference}) local

RetornaReturnsDevuelve Result<List<DispatchTransactionEntity>, Failure>

Filtro triplo em memória, ordenado por data desc. Não é exposto no DispatchHistoryUseCase: o único consumidor é o cálculo de pendências de encerramento de visita, que o usa como um "já despachei isso hoje?".Triple in-memory filter, sorted by date desc. Not exposed on DispatchHistoryUseCase: its only consumer is the visit-end pendings calculation, which uses it as a "did I already dispatch this today?".Filtro triple en memoria, ordenado por fecha desc. No se expone en DispatchHistoryUseCase: el único consumidor es el cálculo de pendientes de cierre de visita, que lo usa como un "¿ya despaché esto hoy?".

save({entity}) local · upsert

RetornaReturnsDevuelve Result<int, Failure>

Devolve o id da linha. localId == 0 insere; qualquer outro valor sobrescreve — por isso um reenvio atualiza a mesma linha em vez de criar outra, e o contador de tentativas cresce monotonicamente.Returns the row id. localId == 0 inserts; any other value overwrites — which is why a resend updates the same row instead of creating another, and the attempt counter grows monotonically.Devuelve el id de la fila. localId == 0 inserta; cualquier otro valor sobrescribe — por eso un reenvío actualiza la misma fila en vez de crear otra, y el contador de intentos crece monotónicamente.

remove({localId}) local · sem chamadorlocal · no callerlocal · sin llamador

RetornaReturnsDevuelve Result<void, Failure>

Existe nas quatro camadas (usecase, interface, impl, datasource) e não tem nenhum chamador. Consequência: o diário de envios nunca é podado — ver Pendências.It exists in all four layers (usecase, interface, impl, datasource) and has no caller at all. Consequence: the sent journal is never pruned — see Pending items.Existe en las cuatro capas (usecase, interface, impl, datasource) y no tiene ningún llamador. Consecuencia: el registro de envíos nunca se poda — ver Pendientes.

DataSyncRecordRepositoryImpl

getAll() local

RetornaReturnsDevuelve Result<List<DataSyncRecordEntity>, Failure>

Devolve todas as linhas da caixa, sem filtrar por mercado nem por tipo. Quem cruza com os tipos do mercado é o Notifier.Returns every row in the box, filtering by neither market nor type. It's the Notifier that joins against the market's types.Devuelve todas las filas de la caja, sin filtrar por mercado ni por tipo. Quien cruza con los tipos del mercado es el Notifier.

getByType({type}) local · sem chamadorlocal · no callerlocal · sin llamador

RetornaReturnsDevuelve Result<DataSyncRecordEntity?, Failure>

Único método do projeto que usa a query real do ObjectBox nesses diários. Está declarado nas quatro camadas e não é chamado de nenhum lugar — a tela de detalhe resolve o registro filtrando a lista já carregada.The only method in these journals that uses a real ObjectBox query. It is declared in all four layers and is called from nowhere — the detail screen resolves the record by filtering the already-loaded list.El único método de estos registros que usa la query real de ObjectBox. Está declarado en las cuatro capas y no se llama desde ningún lugar — la pantalla de detalle resuelve el registro filtrando la lista ya cargada.

save({entity}) local · upsert por tipolocal · upsert by typelocal · upsert por tipo

RetornaReturnsDevuelve Result<int, Failure>

Antes de gravar, procura uma linha existente com o mesmo type e reaproveita o id dela — garantindo uma linha por tipo. A busca ignora o mercado, então trocar de mercado sobrescreve o registro do anterior.Before writing, it looks for an existing row with the same type and reuses its id — guaranteeing one row per type. The lookup ignores the market, so switching market overwrites the previous one's record.Antes de grabar, busca una fila existente con el mismo type y reutiliza su id — garantizando una fila por tipo. La búsqueda ignora el mercado, así que cambiar de mercado sobrescribe el registro del anterior.

PaymentRegisterRepositoryImpl

getPaymentRegisters() local

RetornaReturnsDevuelve Result<List<PaymentRegisterEntity>, Failure>

Caixa inteira, ordenada por createdAt decrescente.The whole box, sorted by createdAt descending.La caja entera, ordenada por createdAt descendente.

savePaymentRegister({entity}) local

RetornaReturnsDevuelve Result<int, Failure>

Upsert de um registro. É o que promove READY → SENT depois do envio, e o que grava a mensagem de erro quando o envio falha (mantendo o status READY, para o botão continuar disponível).Upsert of a single register. It's what promotes READY → SENT after a send, and what stores the error message when the send fails (keeping the status READY, so the button stays available).Upsert de un registro. Es lo que promueve READY → SENT tras el envío, y lo que graba el mensaje de error cuando el envío falla (manteniendo el estado READY, para que el botón siga disponible).

savePaymentRegisters({entities}) local

RetornaReturnsDevuelve Result<void, Failure>

Gravação em lote. Usada pela promoção ORDER_PA/CREATED → READY e pela criação diferida, que insere um registro por combinação de método × débito.Batch write. Used by the ORDER_PA/CREATED → READY promotion and by deferred creation, which inserts one register per method × debit combination.Escritura en lote. Usada por la promoción ORDER_PA/CREATED → READY y por la creación diferida, que inserta un registro por combinación de método × débito.

removePaymentRegister({localId}) local · sem chamadorlocal · no callerlocal · sin llamador

RetornaReturnsDevuelve Result<void, Failure>

Sem chamador em produção. Como registros enviados carregam as evidências em base64, a caixa acumula esses blobs para sempre — ver Pendências.No production caller. Since sent registers carry their evidence as base64, the box accumulates those blobs forever — see Pending items.Sin llamador en producción. Como los registros enviados llevan las evidencias en base64, la caja acumula esos blobs para siempre — ver Pendientes.

DispatcherRepositoryImpl — o transporte— the transport— el transporte

send({envelope}) gRPC

RetornaReturnsDevuelve Result<DispatcherAck, Failure>

Deixa uma migalha de log, delega ao DispatcherGateway e devolve o ack cru — quem interpreta o status é o orquestrador. Error só em falha de transporte. Importante: o catch é sobre Object e converte tudo em NetworkFailure, inclusive respostas 4xx/5xx que o handler de gRPC já havia classificado como erro de servidor. Leaves a log breadcrumb, delegates to DispatcherGateway and returns the raw ack — it's the orchestrator that interprets status. Error only on transport failure. Important: the catch is over Object and turns everything into a NetworkFailure, including 4xx/5xx responses the gRPC handler had already classified as server errors. Deja una migaja de log, delega al DispatcherGateway y devuelve el ack crudo — quien interpreta el status es el orquestador. Error solo en fallo de transporte. Importante: el catch es sobre Object y convierte todo en NetworkFailure, incluidas respuestas 4xx/5xx que el handler de gRPC ya había clasificado como error de servidor.

09

Datasources

Um card por datasource (dropdown), com um dropdown aninhado por método. Os três diários têm só datasource local — não existe mock nem remoto para eles. O gateway do Dispatcher é o único que fala gRPC.One card per datasource (dropdown), with a nested dropdown per method. The three journals have only a local datasource — there is no mock and no remote for them. The Dispatcher gateway is the only one speaking gRPC.Un card por datasource (dropdown), con un dropdown anidado por método. Los tres registros tienen solo datasource local — no existe mock ni remoto para ellos. El gateway del Dispatcher es el único que habla gRPC.

Local DispatchTransactionLocalDataSource ObjectBox

Envio / fluxo: persistência local na box DispatchTransactionModel, sem rede. Todos os métodos são síncronos (não devolvem Future) e nenhum usa a query API do ObjectBox: toda leitura é getAll() seguido de .where()/.sort() em memória — os índices declarados em status e submittedAt não são usados. Erro: cada método embrulha qualquer exceção numa CacheException com mensagem própria e shouldLog: true. Sends / flow: local persistence in the DispatchTransactionModel box, no network. Every method is synchronous (no Future) and none uses the ObjectBox query API: every read is a getAll() followed by in-memory .where()/.sort() — the indexes declared on status and submittedAt go unused. Error: each method wraps any exception in a CacheException with its own message and shouldLog: true. Envío / flujo: persistencia local en la box DispatchTransactionModel, sin red. Todos los métodos son síncronos (no devuelven Future) y ninguno usa la query API de ObjectBox: toda lectura es getAll() seguido de .where()/.sort() en memoria — los índices declarados en status y submittedAt no se usan. Error: cada método envuelve cualquier excepción en una CacheException con mensaje propio y shouldLog: true.

getAll()
RetornoReturnRetorno
List<DispatchTransactionEntity>
ComportamentoBehaviorComportamiento
_box.getAll() + ordenação em memória por submittedAt desc. Descomprime o payload de cada linha; um blob corrompido derruba a leitura inteira._box.getAll() + in-memory sort by submittedAt desc. Decompresses each row's payload; a corrupt blob brings the whole read down._box.getAll() + orden en memoria por submittedAt desc. Descomprime el payload de cada fila; un blob corrupto tumba la lectura entera.
getById({localId})
RetornoReturnRetorno
DispatchTransactionEntity?
ComportamentoBehaviorComportamiento
_box.get(localId)?.toDomain()
getPendingVisits()
RetornoReturnRetorno
List<DispatchTransactionEntity>
ComportamentoBehaviorComportamiento
filtra por type == "visit" e status == "pending", ordena ascendente (o mais antigo sai primeiro no flush).filters by type == "visit" and status == "pending", sorts ascending (oldest goes first in the flush).filtra por type == "visit" y status == "pending", ordena ascendente (el más antiguo sale primero en el flush).
getByTypeForAccount({type, accountSfid, dateReference})
RetornoReturnRetorno
List<DispatchTransactionEntity>
ComportamentoBehaviorComportamiento
filtro triplo em memória (tipo + conta + data de referência), ordem desc. Não filtra por status.triple in-memory filter (type + account + date reference), desc order. It does not filter by status.filtro triple en memoria (tipo + cuenta + fecha de referencia), orden desc. No filtra por estado.
save({entity})
RetornoReturnRetorno
int
ComportamentoBehaviorComportamiento
_box.put(entity.toModel())insere ou sobrescreve conforme o id.inserts or overwrites depending on the id.inserta o sobrescribe según el id.
removeById({localId})
RetornoReturnRetorno
void
ComportamentoBehaviorComportamiento
_box.remove(localId)sem chamador em produção.no production caller.sin llamador en producción.
Local DataSyncRecordLocalDataSource ObjectBox

Envio / fluxo: box DataSyncRecordModel, síncrono, sem rede. É o único destes datasources que usa query real do ObjectBox — e apenas internamente, para achar a linha do tipo antes do upsert. Erro: CacheException por método. Não há delete, clear nem poda; a caixa é limitada a 26 linhas só pelo upsert por tipo. Sends / flow: DataSyncRecordModel box, synchronous, no network. It's the only one of these datasources using a real ObjectBox query — and only internally, to find the type's row before the upsert. Error: a CacheException per method. There is no delete, clear or prune; the box is capped at 26 rows only by the upsert-by-type. Envío / flujo: box DataSyncRecordModel, síncrono, sin red. Es el único de estos datasources que usa query real de ObjectBox — y solo internamente, para hallar la fila del tipo antes del upsert. Error: CacheException por método. No hay delete, clear ni poda; la caja se limita a 26 filas solo por el upsert por tipo.

getAll()
RetornoReturnRetorno
List<DataSyncRecordEntity>
ComportamentoBehaviorComportamiento
todas as linhas, sem ordenação nem filtro.all rows, no sorting and no filtering.todas las filas, sin orden ni filtro.
getByType({type})
RetornoReturnRetorno
DataSyncRecordEntity?
ComportamentoBehaviorComportamiento
query type.equals(type.key) + findFirst(). Sem chamador externo.type.equals(type.key) query + findFirst(). No external caller.query type.equals(type.key) + findFirst(). Sin llamador externo.
save({entity})
RetornoReturnRetorno
int
ComportamentoBehaviorComportamiento
converte, procura a linha do mesmo type, copia o id dela quando existe, e grava — upsert por tipo, sem considerar o mercado.converts, looks for the row with the same type, copies its id when present, and writes — upsert by type, market not considered.convierte, busca la fila del mismo type, copia su id cuando existe, y graba — upsert por tipo, sin considerar el mercado.
Local PaymentRegisterLocalDataSource ObjectBox · CL

Envio / fluxo: box PaymentRegisterModel (5 índices declarados, nenhum usado em query), síncrono, sem rede. Erro: CacheException na leitura e na escrita. Sends / flow: PaymentRegisterModel box (5 indexes declared, none used in a query), synchronous, no network. Error: CacheException on read and write. Envío / flujo: box PaymentRegisterModel (5 índices declarados, ninguno usado en query), síncrono, sin red. Error: CacheException en la lectura y en la escritura.

getAll()
RetornoReturnRetorno
List<PaymentRegisterEntity>
ComportamentoBehaviorComportamiento
todas as linhas, ordenadas por createdAt desc em memória.all rows, sorted by createdAt desc in memory.todas las filas, ordenadas por createdAt desc en memoria.
save({entity}) · saveAll({entities}) · removeById({localId})
RetornoReturnRetorno
int · void · void
ComportamentoBehaviorComportamiento
put / putMany / remove. O retorno de putMany e de remove é descartado; removeById não tem chamador em produção.put / putMany / remove. The return of putMany and remove is discarded; removeById has no production caller.put / putMany / remove. El retorno de putMany y remove se descarta; removeById no tiene llamador en producción.
Remote DispatcherGateway gRPC
send({envelope})
EnvioSendsEnvío
monta o InboxTransactionRequest (11 campos, ver §07) e chama sendTransaction no DispatcherConectaRepServiceClient. É o único cliente no endpoint dispatcher — todos os outros ~27 usam o streambridge. O token vem de um serviço de autenticação próprio e vai no metadata authorization: Bearer … por chamada. builds the InboxTransactionRequest (11 fields, see §07) and calls sendTransaction on DispatcherConectaRepServiceClient. It's the only client on the dispatcher endpoint — all the other ~27 use streambridge. The token comes from a dedicated auth service and travels in the per-call authorization: Bearer … metadata. arma el InboxTransactionRequest (11 campos, ver §07) y llama sendTransaction en DispatcherConectaRepServiceClient. Es el único cliente en el endpoint dispatcher — todos los otros ~27 usan streambridge. El token viene de un servicio de autenticación propio y va en el metadata authorization: Bearer … por llamada.
RetornoReturnRetorno
DispatcherAck (status, transactionId, message)(status, transactionId, message)(status, transactionId, message)
Fluxo de usoUsage flowFlujo de uso
em modo mock devolve um ack fixo de sucesso sem tocar a rede; offline lança antes de tentar. Não há deadline no lado do cliente para este RPC — por decisão explícita, para não cortar uma escrita em voo e arriscar duplicá-la no retry; só o interceptor de conectividade impõe 15 s quando a conexão está instável. in mock mode it returns a fixed success ack without touching the network; offline it throws before trying. There is no client-side deadline for this RPC — a deliberate decision, so an in-flight write is never cut and risked as a duplicate on retry; only the connectivity interceptor imposes 15 s while the connection is unstable. en modo mock devuelve un ack fijo de éxito sin tocar la red; offline lanza antes de intentar. No hay deadline del lado del cliente para este RPC — por decisión explícita, para no cortar una escritura en vuelo y arriesgar duplicarla en el retry; solo el interceptor de conectividad impone 15 s cuando la conexión está inestable.
Tratamento de erroError handlingManejo de errores
unauthenticateduma reautenticação e um único retry; outros GrpcErrorGrpcExceptionHandler; o resto → ServerException. Tudo isso volta ao repository, que colapsa em NetworkFailure. unauthenticatedone re-auth and a single retry; other GrpcErrors → GrpcExceptionHandler; anything else → ServerException. All of it returns to the repository, which collapses it into NetworkFailure. unauthenticateduna reautenticación y un único retry; otros GrpcErrorGrpcExceptionHandler; el resto → ServerException. Todo eso vuelve al repository, que lo colapsa en NetworkFailure.
10

Enums e labelsEnums & labelsEnums y labels

Os enums só existem tipados na Entity; no Model trafegam como String. Onze enums governam esta tela — dois deles são os catálogos que dão nome a cada linha das abas Envios e Recebimentos. Lista completa de valores:Enums are only typed in the Entity; in the Model they travel as String. Eleven enums govern this screen — two of them are the catalogs that name every row of the Sent and Received tabs. Full value list:Los enums solo están tipados en la Entity; en el Model viajan como String. Once enums gobiernan esta pantalla — dos de ellos son los catálogos que dan nombre a cada fila de las pestañas Envíos y Recepción. Lista completa de valores:

DispatcherType 42 valores · o catálogo de Enviosvalues · the Sent catalogvalores · el catálogo de Envíos

Uma linha por valor, sem truncar. serviceName é o discriminador que vai no wire; builder diz se o tipo é realmente despachável hoje; reenvio marca os que não avisam risco de duplicata (os três "leves"). A coluna doc aponta a documentação da transação quando ela existe.One row per value, nothing truncated. serviceName is the discriminator that goes on the wire; builder says whether the type is actually dispatchable today; resend marks the ones that do not warn about duplication risk (the three "lightweight" ones). The doc column points to the transaction's documentation where it exists.Una fila por valor, sin truncar. serviceName es el discriminador que va en el wire; builder dice si el tipo es realmente despachable hoy; reenvío marca los que no avisan riesgo de duplicado (los tres "livianos"). La columna doc apunta a la documentación de la transacción cuando existe.

caseserviceNamemercadosmarketsmercadosbuilderreenvioresendreenvíodoc
orderMobileorderAPIBR/CL/ZApode duplicarmay duplicatepuede duplicar01 · 02
orderIndirectIndirectOrderAPIZApode duplicarmay duplicatepuede duplicar01
orderApprovalOrderApprovalUploadAPIBR/CL/ZApode duplicarmay duplicatepuede duplicar01
orderInvoiceInvoiceuploadBR/CL— sem builder— no builder— sin builderpode duplicarmay duplicatepuede duplicar
visitVisitUploadAPIBR/CL/ZApode duplicarmay duplicatepuede duplicar04
smartInvestmentAnswerSmartInvestmentAnswerBRpode duplicarmay duplicatepuede duplicar
deliveryRescheduleTripsheetUploadAPIBR/CLpode duplicarmay duplicatepuede duplicar03
retailNewAccountContactUploadAPIBR/CL/ZApode duplicarmay duplicatepuede duplicar05
retailUpdateRetailerUploadAPIBR/CL/ZApode duplicarmay duplicatepuede duplicar06 · 07
contactClerkUpdateContactConectaVoceBRpode duplicarmay duplicatepuede duplicar08
contactClerkStatusContactUpdateStatusBRpode duplicarmay duplicatepuede duplicar09
cvRequestActionCVRequestActionBRpode duplicarmay duplicatepuede duplicar10
cvRequestActionReportCVRequestActionReportBRpode duplicarmay duplicatepuede duplicar11
notificationReadNotificationReadBR/CL/ZAlevelightweightliviano12
competitorInsightsCompetitorInsightsUploadAPIZApode duplicarmay duplicatepuede duplicar13
priceCheckProductPriceCheckZAlevelightweightliviano14
surveySurveyResultUploadAPIBR/CL/ZApode duplicarmay duplicatepuede duplicar15
financialProofOfPaymentFinancialProofPaymentAPIBR/CL/ZApode duplicarmay duplicatepuede duplicar16
paymentPaymentCollectionAPIBR/CLpode duplicarmay duplicatepuede duplicar
cashPaymentReportCashPaymentReportAPIBR/CLpode duplicarmay duplicatepuede duplicar
merchandisingImageAuditImageAuditBRpode duplicarmay duplicatepuede duplicar17
imageRecognitionAuditServiceMerchanAuditBRpode duplicarmay duplicatepuede duplicar
merchandisingCreationCreateMerchanBRpode duplicarmay duplicatepuede duplicar18
merchandisingAuditUnitAuditUnitReportZApode duplicarmay duplicatepuede duplicar19
merchandisingAssetItemTrackingAssetItemTrackingUploadAPIZA/CLpode duplicarmay duplicatepuede duplicar20
merchandisingAnnotationCreateMerchanAnnotationBRpode duplicarmay duplicatepuede duplicar21
merchandisingServiceOrderBPOneServiceOrderUpsertBRpode duplicarmay duplicatepuede duplicar22
answerTaskAnswerTaskAPIBR/CL/ZAlevelightweightliviano23
createTaskCreateTaskAPIBR/CL/ZA— sem builder— no builder— sin builderpode duplicarmay duplicatepuede duplicar
helpSupportSupportRequestAPIBR/CL/ZApode duplicarmay duplicatepuede duplicar24
caseUploadCaseUploadAPIBRpode duplicarmay duplicatepuede duplicar25
clueClueUploadAPICLpode duplicarmay duplicatepuede duplicar
notesNoteUploadAPICLpode duplicarmay duplicatepuede duplicar
stockCountLocationStockUploadAPIBR/CL/ZApode duplicarmay duplicatepuede duplicar26
stockReconciliationStockReconciliationAPIBR/CL— sem builder— no builder— sin builderpode duplicarmay duplicatepuede duplicar
stockRequestStockProposalUploadAPIBR/CL— sem builder— no builder— sin builderpode duplicarmay duplicatepuede duplicar
stockAllocationExecutionStockAllocationUploadAPIBR/CL— sem builder— no builder— sin builderpode duplicarmay duplicatepuede duplicar
stockUnloadVanUnloadAPIBR/CL— sem builder— no builder— sin builderpode duplicarmay duplicatepuede duplicar
buybackRequestSalesReturnSENBR/CLpode duplicarmay duplicatepuede duplicar27
buybackExecutionSalesReturnUpliftBR/CLpode duplicarmay duplicatepuede duplicar28
odometerJourneyOdometerAPIBR/CL/ZApode duplicarmay duplicatepuede duplicar29
odometerCarPlateCarLicensePlateBRpode duplicarmay duplicatepuede duplicar30

36 tipos têm builder e 6 não têm (orderInvoice, createTask, stockReconciliation, stockRequest, stockAllocationExecution, stockUnload) — esses seis não são referenciados em nenhum lugar do código além da própria declaração, logo nunca aparecem na tela. Dois valores são produzidos por dois builders cada: order (envio de pedido e atualização de status de entrega) e retailUpdate (edição de varejo e contato de equipe) — os docs cruzados estão na coluna doc. Os tipos sem doc numerada (smartInvestmentAnswer, imageRecognitionAudit, notes, clue, payment, cashPaymentReport) são builders novos, ainda sem documentação de transação própria. O campo enabledMarkets da coluna "mercados" é declarado e nunca lido — ver Pendências. 36 types have a builder and 6 don't (orderInvoice, createTask, stockReconciliation, stockRequest, stockAllocationExecution, stockUnload) — those six are referenced nowhere in the code beyond their own declaration, so they never appear on the screen. Two values are produced by two builders each: order (order placement and delivery status update) and retailUpdate (retail edit and staff contact) — the crossing docs are in the doc column. The types without a numbered doc (smartInvestmentAnswer, imageRecognitionAudit, notes, clue, payment, cashPaymentReport) are new builders, still without their own transaction documentation. The enabledMarkets field behind the "markets" column is declared and never read — see Pending items. 36 tipos tienen builder y 6 no (orderInvoice, createTask, stockReconciliation, stockRequest, stockAllocationExecution, stockUnload) — esos seis no se referencian en ningún lugar del código más allá de su declaración, así que nunca aparecen en la pantalla. Dos valores son producidos por dos builders cada uno: order (envío de pedido y actualización de estado de entrega) y retailUpdate (edición de punto de venta y contacto de equipo) — los docs cruzados están en la columna doc. Los tipos sin doc numerada (smartInvestmentAnswer, imageRecognitionAudit, notes, clue, payment, cashPaymentReport) son builders nuevos, aún sin documentación de transacción propia. El campo enabledMarkets de la columna "mercados" está declarado y nunca se lee — ver Pendientes.

O enum não tem fromString. A única leitura de values é o mapper, que casa pelo nome Dart e cai em visit quando não encontra. O nome exibido no cartão é composto dinamicamente como dispatcher_type_<nome>.The enum has no fromString. The only read of values is the mapper, which matches by Dart name and falls back to visit when it doesn't find one. The name shown on the card is composed dynamically as dispatcher_type_<name>.El enum no tiene fromString. La única lectura de values es el mapper, que casa por el nombre Dart y cae en visit cuando no encuentra. El nombre mostrado en la tarjeta se compone dinámicamente como dispatcher_type_<nombre>.

DataSyncType 26 valores · o catálogo de Recebimentosvalues · the Received catalogvalores · el catálogo de Recepción

Uma linha por valor. O key é o que se persiste e o que aparece na configuração de TTL; enabledMarkets decide quais linhas a aba Recebimentos mostra naquele mercado — e é o único uso desse campo em todo o app. A coluna TTL vem da configuração de mercado (idêntica em BR/CL/ZA).One row per value. The key is what gets persisted and what appears in the TTL configuration; enabledMarkets decides which rows the Received tab shows in that market — and it's the only use of that field in the whole app. The TTL column comes from market configuration (identical in BR/CL/ZA).Una fila por valor. El key es lo que se persiste y lo que aparece en la configuración de TTL; enabledMarkets decide qué filas muestra la pestaña Recepción en ese mercado — y es el único uso de ese campo en toda la app. La columna TTL viene de la configuración de mercado (idéntica en BR/CL/ZA).

case / keymercadosmarketsmercadosTTLlote inicialinitial batchlote inicial
homeKpiBR/CL/ZA300 score
visitsBR/CL/ZA600 score
ordersBR/CL/ZA600 score
retailsBR/CL/ZA1800 srest
financialManagementBR/CL/ZA900 srest
tasksBR/CL/ZA600 srest
casesBR300 s (default)rest
conectaVoceBR300 s (default)rest
stockControlBR/CL/ZA900 srest
productCatalogBR/CL/ZA86400 srest
promotionBR/CL/ZA300 srest
surveysBR/CL/ZA3600 srest
competitorInsightsZA86400 srest
merchandisingBR/CL/ZA86400 srest
merchandisingOptionsBR/CL/ZA300 s (default)rest
merchandisingImageAuditsBR300 s (default)rest
merchandisingServiceOrdersBR/CL300 s (default)rest
marginCalculatorZA86400 srest
primeManagementBR300 s (default)rest
buybackBR/CL300 s (default)rest
reportBR/CL300 s (default)rest
notificationsBR/CL/ZA300 srest
communicationsBR/CL/ZA3600 srest
faqBR/CL/ZA86400 srest
referenceDataBR/CL/ZA86400 srest
resourceBR/CL/ZA3600 sconfig

Contagem de linhas visíveis por mercado: BR 24 · CL 20 · ZA 19; AR/PY/PE nenhuma (nenhum valor lista esses mercados). As 8 células em destaque são tipos sem TTL declarado — caem no default de 300 s, o mais agressivo de todos. fromKey devolve null quando não reconhece (não há valor sentinela) e não registra o valor não mapeado. Visible rows per market: BR 24 · CL 20 · ZA 19; AR/PY/PE none (no value lists those markets). The 8 highlighted cells are types with no declared TTL — they fall back to the 300 s default, the most aggressive tier of all. fromKey returns null when it doesn't recognise a key (there is no sentinel value) and does not log the unmapped value. Filas visibles por mercado: BR 24 · CL 20 · ZA 19; AR/PY/PE ninguna (ningún valor lista esos mercados). Las 8 celdas destacadas son tipos sin TTL declarado — caen en el default de 300 s, el más agresivo de todos. fromKey devuelve null cuando no reconoce (no hay valor centinela) y no registra el valor no mapeado.

DispatchTransactionStatus 4
casevaluegrupo / caixagroup / boxgrupo / cajai18n keyquem produzwho produces itquién lo produce
success"success"successdata_center_status_successack com status 0 ou 5ack with status 0 or 5ack con status 0 o 5
error"error"errordata_center_status_errorack recusado, falha de transporte, e o fallback do parserejected ack, transport failure, and the parse fallbackack rechazado, fallo de transporte, y el fallback del parseo
pending"pending"pendingdata_center_status_pendingsó a fila offline de visitasonly the offline visit queuesolo la cola offline de visitas
duplicate"duplicate"successdata_center_status_duplicateack com status 1ack with status 1ack con status 1

Getters: isPending, isSuccessEquivalent (success ou duplicate), isError e isResendable — que é exatamente isError. Ou seja: pending não é reenviável à mão (é a fila automática) e duplicate conta como sucesso. fromValue cai em error, sem tratar vazio à parte. Getters: isPending, isSuccessEquivalent (success or duplicate), isError and isResendable — which is exactly isError. So: pending is not hand-resendable (it's the automatic queue) and duplicate counts as success. fromValue falls back to error, with no special handling for empty. Getters: isPending, isSuccessEquivalent (success o duplicate), isError e isResendable — que es exactamente isError. O sea: pending no es reenviable a mano (es la cola automática) y duplicate cuenta como éxito. fromValue cae en error, sin tratar el vacío aparte.

DataSyncRecordStatus 3
casevaluegrupo / caixagroup / boxgrupo / cajai18n key
received"received"successdata_center_status_received
error"error"errordata_center_status_error
pending"pending"pendingdata_center_status_pending

Getters isReceived/isError/isPending e o bucket, que mora no próprio enum (não na extensão). fromValue cai em pending. O orquestrador nunca grava pending: esse status aparece apenas como ausência de linha para um tipo do mercado. Getters isReceived/isError/isPending plus bucket, which lives on the enum itself (not on the extension). fromValue falls back to pending. The orchestrator never writes pending: that status only shows up as the absence of a row for a market type. Getters isReceived/isError/isPending y el bucket, que vive en el propio enum (no en la extensión). fromValue cae en pending. El orquestador nunca graba pending: ese estado aparece solo como ausencia de fila para un tipo del mercado.

PaymentRegisterStatus 5 · CL
casevalue (wire)grupo / caixagroup / boxgrupo / cajai18n keyopção de filtrofilter optionopción de filtro
awaitingOrderApproval"ORDER_PA"pendingpayment_status_awaiting_order_approval
awaitingDebitOpenItem"CREATED"pendingpayment_status_awaiting_debit_open_item
readyToSync"READY"pendingpayment_status_ready_to_sync
sent"SENT"successpayment_status_sent
unknown"unknown"unknownpayment_status_sent— não existe— none— no existe

Getters isPending (os dois primeiros), isSyncable (só readyToSync) e isSent. fromString apara e passa para maiúsculas antes de comparar, e registra o valor não mapeado antes de cair em unknown. As quatro opções de filtro configuradas casam byte a byte com os quatro primeiros valores; unknown é o único sem opção — e ele reusa o rótulo de sent, ver Pendências. Getters isPending (the first two), isSyncable (only readyToSync) and isSent. fromString trims and uppercases before comparing, and logs the unmapped value before falling back to unknown. The four configured filter options match the first four values byte for byte; unknown is the only one without an option — and it reuses sent's label, see Pending items. Getters isPending (los dos primeros), isSyncable (solo readyToSync) e isSent. fromString recorta y pasa a mayúsculas antes de comparar, y registra el valor no mapeado antes de caer en unknown. Las cuatro opciones de filtro configuradas casan byte a byte con los cuatro primeros valores; unknown es el único sin opción — y reutiliza la etiqueta de sent, ver Pendientes.

DataCenterTabType 5
casevaluequem declaradeclared byquién lo declara
dispatch"dispatch"BR · CL · ZA
dataSync"dataSync"BR · CL · ZA
payment"payment"CL
integration"integration"nenhum mercadono marketningún mercado
unknown"unknown"— filtrado de visibleTabs— filtered out of visibleTabs— filtrado de visibleTabs

fromString é sensível a maiúsculas ("datasync" não casaria com "dataSync"), registra o valor não mapeado e cai em unknown. integration existe no enum, tem página, rota e chave de tradução — mas nenhum mercado o declara, então é código inalcançável hoje; ver Pendências. fromString is case-sensitive ("datasync" would not match "dataSync"), logs the unmapped value and falls back to unknown. integration exists in the enum, has a page, a route and a translation key — but no market declares it, so it is unreachable code today; see Pending items. fromString es sensible a mayúsculas ("datasync" no casaría con "dataSync"), registra el valor no mapeado y cae en unknown. integration existe en el enum, tiene página, ruta y clave de traducción — pero ningún mercado lo declara, así que hoy es código inalcanzable; ver Pendientes.

DataCenterBoxBucket 4
casevaluecorcolorcoloríconeiconícono
success"success"successnoticeSuccess
error"error"errornoticeError
pending"pending"warninghomeHourglass
unknown"unknown"onSurfaceTertiarynoticeSuccess

O ícone e a cor vêm desta tabela no código, não da configuração: o campo icon declarado em cada caixa do mercado é lido, guardado na entity e nunca usado. Hoje os valores coincidem, então a divergência é invisível. Note que unknown reusa o ícone de sucesso (um "certo" cinza). The icon and the color come from this table in code, not from configuration: the icon field declared on each market box is parsed, stored on the entity and never used. Today the values coincide, so the divergence is invisible. Note that unknown reuses the success icon (a grey "tick"). El ícono y el color vienen de esta tabla en el código, no de la configuración: el campo icon declarado en cada caja del mercado se lee, se guarda en la entity y nunca se usa. Hoy los valores coinciden, así que la divergencia es invisible. Nótese que unknown reutiliza el ícono de éxito (un "tilde" gris).

DataCenterSort 4
casei18n keycritériocriterioncriterio
newestdata_center_sort_newesttimestamp desc — padrãotimestamp desc — defaulttimestamp desc — por defecto
oldestdata_center_sort_oldesttimestamp asctimestamp asctimestamp asc
byTypedata_center_sort_by_typecompara a chave de tradução do título, não o texto traduzidocompares the title's translation key, not the translated textcompara la clave de traducción del título, no el texto traducido
byStatusdata_center_sort_by_statuscompara o value do statuscompares the status valuecompara el value del estado

Sem valor de wire e sem configuração por mercado: as quatro opções aparecem sempre, e o padrão é sempre newest. Em newest/oldest, itens sem timestamp vão para o começo e o fim respectivamente.No wire value and no per-market configuration: all four options always show, and the default is always newest. Under newest/oldest, items with no timestamp go to the start and the end respectively.Sin valor de wire y sin configuración por mercado: las cuatro opciones aparecen siempre, y el default es siempre newest. En newest/oldest, los ítems sin timestamp van al comienzo y al final respectivamente.

VisitDispatchKind 2
casevaluei18n keyorigemsourceorigen
start"start"data_center_visit_kind_startVisitStatus.started
finish"finish"data_center_visit_kind_finishVisitStatus.completed

Só as visitas o carregam; é o que faz o título do cartão virar "Visita (Início)" ou "Visita (Finalização)". fromValue devolve null — e o vazio gravado nas linhas não-visita volta corretamente como null.Only visits carry it; it's what turns the card title into "Visit (Start)" or "Visit (Completion)". fromValue returns null — and the empty string stored on non-visit rows correctly comes back as null.Solo las visitas lo llevan; es lo que hace que el título de la tarjeta sea "Visita (Inicio)" o "Visita (Finalización)". fromValue devuelve null — y el vacío grabado en las filas no-visita vuelve correctamente como null.

DispatcherDestination 4
casevaluequantos tipos usamhow many types use itcuántos tipos lo usan
salesforce"salesforce"26 (o default)(the default)(el default)
batchApi"sfbatchapi"5
competitor"competitor"1
none""10

Vai no campo endpoint do request. É o único campo do DispatcherType, além de serviceName, que chega ao wire.It travels in the request's endpoint field. It is the only DispatcherType field besides serviceName that reaches the wire.Va en el campo endpoint del request. Es el único campo del DispatcherType, además de serviceName, que llega al wire.

PaymentMethod → label 15 · CL

Extensão própria da Central de dados, usada só para nomear as opções do filtro de tipo na aba Pagamentos. Todas as chaves são reaproveitadas do fluxo de pedido.A Data-center-specific extension, used only to name the type filter options on the Payments tab. All keys are reused from the order flow.Extensión propia del Centro de datos, usada solo para nombrar las opciones del filtro de tipo en la pestaña Pagos. Todas las claves se reutilizan del flujo de pedido.

casei18n key
cashorder_payment_method_cash
bankSliporder_payment_method_bank_slip
mobilePaymentorder_payment_method_mobile_money
electronicFundsTransferorder_payment_method_eft
creditNoteorder_payment_method_credit_note
bankDepositorder_payment_method_bank_deposit
paymentButtonorder_payment_method_payment_button
chequeorder_payment_method_cheque
promissoryNoteorder_payment_method_promissory_note
pixorder_payment_method_pix
creditCardorder_payment_method_credit_card
debitCardorder_payment_method_debit_card
paymentOrderorder_payment_method_payment_order
directDebitorder_payment_method_direct_debit
unknowndata_center_tab_payments

O último caso é uma troca infeliz: um meio de pagamento não reconhecido recebe o rótulo da própria aba ("Pagamentos"), então a opção do filtro apareceria escrita "Pagos". Ver Pendências.The last case is an unfortunate swap: an unrecognised payment method gets the tab's own label ("Payments"), so the filter option would read "Pagos". See Pending items.El último caso es un cambio desafortunado: un medio de pago no reconocido recibe la etiqueta de la propia pestaña ("Pagos"), así que la opción del filtro aparecería escrita "Pagos". Ver Pendientes.

11

UseCases

Um dropdown por UseCase; dentro, cada método com assinatura, o que retorna e uso. Todos os providers desta seção são keepAlive. Os dois orquestradores aparecem aqui porque é deles que a tela depende para agir — eles vivem em domain/application/orchestrators/, não em usecases/. One dropdown per UseCase; inside, each method with its signature, what it returns and use. Every provider in this section is keepAlive. The two orchestrators appear here because they are what the screen depends on to act — they live in domain/application/orchestrators/, not in usecases/. Un dropdown por UseCase; dentro, cada método con su firma, qué devuelve y uso. Todos los providers de esta sección son keepAlive. Los dos orquestadores aparecen aquí porque de ellos depende la pantalla para actuar — viven en domain/application/orchestrators/, no en usecases/.

DispatchHistoryUseCase 5 · o diário de enviosthe sent journalel registro de envíos
MétodoMethodMétodoRetornaReturnsDevuelveUsoUseUso
getAll()Result<List<DispatchTransactionEntity>, Failure>Alimenta a aba Envios e o recálculo de contagens do orquestrador.Feeds the Sent tab and the orchestrator's counter recalculation.Alimenta la pestaña Envíos y el recálculo de conteos del orquestador.
getById({localId})Result<DispatchTransactionEntity?, Failure>Primeiro passo do reenvio.First step of a resend.Primer paso del reenvío.
getPendingVisits()Result<List<DispatchTransactionEntity>, Failure>A fila offline consumida pelo flush().The offline queue consumed by flush().La cola offline consumida por flush().
save({entity})Result<int, Failure>O único escritor do diário; chamado só pelo orquestrador.The journal's only writer; called only by the orchestrator.El único escritor del registro; llamado solo por el orquestador.
remove({localId})Result<void, Failure>Sem chamador.No caller.Sin llamador.

É um repasse 1:1 para o repository, sem lógica — e sem método execute, quebrando de propósito a convenção do projeto. Não expõe getByTypeForAccount: quem precisa dele fala direto com a interface do repository.It's a 1:1 pass-through to the repository, with no logic — and with no execute method, deliberately breaking the project convention. It does not expose getByTypeForAccount: whoever needs it talks to the repository interface directly.Es un repase 1:1 al repository, sin lógica — y sin método execute, rompiendo a propósito la convención del proyecto. No expone getByTypeForAccount: quien lo necesita habla directo con la interfaz del repository.

DataSyncRecordUseCase 3 · o diário de recebimentosthe received journalel registro de recepción
MétodoMethodMétodoRetornaReturnsDevuelveUsoUseUso
getAll()Result<List<DataSyncRecordEntity>, Failure>Alimenta a aba Recebimentos. É o único leitor do diário em todo o app.Feeds the Received tab. It is the only reader of the journal in the whole app.Alimenta la pestaña Recepción. Es el único lector del registro en toda la app.
save({entity})Result<int, Failure>Chamado só pelo DataSyncOrchestrator, ao fim de cada tentativa de sincronia.Called only by DataSyncOrchestrator, at the end of each sync attempt.Llamado solo por el DataSyncOrchestrator, al final de cada intento de sincronización.
getByType({type})Result<DataSyncRecordEntity?, Failure>Sem chamador.No caller.Sin llamador.
ResolvePendingPaymentRegistersUseCase 1 · CL
MétodoMethodMétodoRetornaReturnsDevuelveUsoUseUso
execute()Result<List<PaymentRegisterEntity>, Failure>Lê os registros, separa os pendentes, e para cada um tenta casar um título financeiro do cache — primeiro pelo pedido (usando o número da ordem de compra quando o sfid não está gravado), depois pelo número da nota. Casou: promove a pronto para sincronizar, copiando sfid, nome, valor, prazo e nota. Grava os promovidos em lote e relê a lista antes de devolver. É o único consumidor deste UseCase, e é chamado no _load do Notifier. Reads the registers, separates the pending ones, and for each tries to match a cached financial item — first by order (using the purchase order number when the sfid isn't stored), then by invoice number. On a match it promotes to ready to sync, copying sfid, name, amount, term and invoice. It batch-writes the promoted ones and re-reads the list before returning. It is this UseCase's only consumer, and it's called from the Notifier's _load. Lee los registros, separa los pendientes, y para cada uno intenta cruzar un título financiero del caché — primero por el pedido (usando el número de orden de compra cuando el sfid no está grabado), después por el número de factura. Si cruza, promueve a listo para sincronizar, copiando sfid, nombre, monto, plazo y factura. Graba los promovidos en lote y relee la lista antes de devolver. Es el único consumidor de este UseCase, y se llama en el _load del Notifier.

Atenção ao contrato: em falha de leitura dos registros ou do cache financeiro ele lança a Failure em vez de devolvê-la — é o único caminho pelo qual a Central de dados pode entrar em estado de erro. Falha na leitura de pedidos, ao contrário, é engolida (lista vazia). E ele roda em todos os mercados, mesmo onde não existe aba de pagamentos. Mind the contract: on a failure reading the registers or the financial cache it throws the Failure instead of returning it — it is the only path by which the Data center can enter an error state. A failure reading orders, by contrast, is swallowed (empty list). And it runs in every market, even where there is no payments tab. Atención al contrato: en fallo de lectura de los registros o del caché financiero lanza la Failure en vez de devolverla — es el único camino por el cual el Centro de datos puede entrar en estado de error. Un fallo leyendo pedidos, en cambio, se traga (lista vacía). Y corre en todos los mercados, incluso donde no existe pestaña de pagos.

SyncPaymentRegisterUseCase 1 · CL
MétodoMethodMétodoRetornaReturnsDevuelveUsoUseUso
execute({register})Result<PaymentRegisterEntity, Failure>Guarda: recusa qualquer registro que não esteja pronto para sincronizar. Resolve o representante da sessão, e depois o título financeiro, o pedido e a visita — cada um do cache, cada um caindo para null em erro ou sfid vazio. Delega ao PaymentSubmissionOrchestrator.syncRegister. Guard: it refuses any register that isn't ready to sync. It resolves the session's rep, then the financial item, the order and the visit — each from the cache, each degrading to null on error or empty sfid. Delegates to PaymentSubmissionOrchestrator.syncRegister. Guarda: rechaza cualquier registro que no esté listo para sincronizar. Resuelve el representante de la sesión, y luego el título financiero, el pedido y la visita — cada uno del caché, cada uno cayendo a null en error o sfid vacío. Delega al PaymentSubmissionOrchestrator.syncRegister.

O syncRegister dispara até três transações: o pagamento em si (obrigatória — se falhar, grava a mensagem de erro e para, mantendo o status pronto), o comprovante de pagamento (só quando há evidência anexada e um título resolvido) e o relatório de caixa (só quando a origem do pagamento o exige). Entre elas, marca notas de crédito como usadas e aplica as alocações no cache financeiro. Ao fim, promove o registro a enviado. syncRegister fires up to three transactions: the payment itself (mandatory — if it fails, it stores the error message and stops, keeping the ready status), the proof of payment (only when evidence is attached and an item was resolved) and the cash report (only when the payment's origin requires it). In between, it marks credit notes as used and applies the allocations to the financial cache. At the end, it promotes the register to sent. syncRegister dispara hasta tres transacciones: el pago en sí (obligatoria — si falla, graba el mensaje de error y se detiene, manteniendo el estado listo), el comprobante de pago (solo cuando hay evidencia adjunta y un título resuelto) y el reporte de caja (solo cuando el origen del pago lo exige). Entre ellas, marca notas de crédito como usadas y aplica las asignaciones al caché financiero. Al final, promueve el registro a enviado.

GetPaymentRegistersUseCase 3 · fora desta telaoutside this screenfuera de esta pantalla
MétodoMethodMétodoRetornaReturnsDevuelveUsoUseUso
execute()Result<List<PaymentRegisterEntity>, Failure>Lista crua, sem resolução.Raw list, no resolution.Lista cruda, sin resolución.
getByDebitOpenItemSfid({debitOpenItemSfid})Result<List<PaymentRegisterEntity>, Failure>Usado pelo detalhe do título em Gestão financeira — é lá, não aqui, que se veem banco, agência, referência e valor pago de cada registro.Used by the item detail in Financial management — that's where bank, branch, reference and paid amount of each register are visible, not here.Usado por el detalle del título en Gestión financiera — es allí, no aquí, donde se ven banco, sucursal, referencia y monto pagado de cada registro.
getUnsettled()Result<List<PaymentRegisterEntity>, Failure>Sem chamador — o mesmo filtro é reescrito à mão no cálculo de pendências da jornada.No caller — the same filter is hand-rewritten in the journey pendings calculation.Sin llamador — el mismo filtro se reescribe a mano en el cálculo de pendientes de la jornada.
DispatcherOrchestrator orquestrador · dono do diário de enviosorchestrator · owner of the sent journalorquestador · dueño del registro de envíos

Notifier keepAlive cujo state são as três contagens (enviados, erros, pendentes). No build() escuta a conectividade para esvaziar a fila na virada offline→online, e dispara uma contagem e um flush iniciais.A keepAlive Notifier whose state is the three counters (sent, errors, pending). On build() it listens to connectivity to drain the queue on the offline→online edge, and fires an initial count and flush.Notifier keepAlive cuyo state son los tres conteos (enviados, errores, pendientes). En el build() escucha la conectividad para vaciar la cola en el cambio offline→online, y dispara un conteo y un flush iniciales.

MétodoMethodMétodoRetornaReturnsDevuelveUsoUseUso
dispatch({envelope})Future<Result<DispatcherAck, Failure>>Porta de entrada de toda escrita. Se estiver offline E for uma visita, grava como pendente e devolve erro de rede (sem tentar). Qualquer outro tipo segue para o transporte — e, offline, cai como error.The entry door for every write. If offline AND it's a visit, it stores it as pending and returns a network error (without trying). Any other type goes on to the transport — and, offline, lands as error.La puerta de entrada de toda escritura. Si está offline Y es una visita, graba como pendiente y devuelve error de red (sin intentar). Cualquier otro tipo sigue al transporte — y, offline, cae como error.
resend({localId})Future<Result<DispatcherAck, Failure>>Lê a linha; se não existir ou não tiver mais o conteúdo, devolve erro de negócio. Senão reconstrói o envelope idêntico (mesma referência, mesma data, mesmo tid guardado), reusa o localId — sobrescrevendo a mesma linha — e soma 1 às tentativas, preservando o submittedAt original. Reads the row; if it doesn't exist or no longer holds the content, returns a business error. Otherwise it rebuilds the identical envelope (same reference, same date, same stored tid), reuses the localId — overwriting the same row — and adds 1 to the attempts, preserving the original submittedAt. Lee la fila; si no existe o ya no tiene el contenido, devuelve error de negocio. Si no, reconstruye el envelope idéntico (misma referencia, misma fecha, mismo tid guardado), reutiliza el localId — sobrescribiendo la misma fila — y suma 1 a los intentos, preservando el submittedAt original.
flush()Future<void>Reenvio automático. Guarda de reentrância, aborta se offline, percorre só as visitas pendentes em ordem FIFO e interrompe o laço inteiro na primeira falha de rede. Chamado em exatamente dois lugares: na virada offline→online e uma vez ao nascer. Automatic retry. Re-entrancy guard, aborts if offline, walks only the pending visits in FIFO order and breaks the whole loop on the first network failure. Called in exactly two places: on the offline→online edge and once at construction. Reenvío automático. Guarda de reentrancia, aborta si está offline, recorre solo las visitas pendientes en orden FIFO e interrumpe el bucle entero en el primer fallo de red. Llamado en exactamente dos lugares: en el cambio offline→online y una vez al nacer.
dispatchAll({envelopes})Future<List<Result<DispatcherAck, Failure>>>Sem chamador — três UseCases reescrevem o mesmo leque em paralelo à mão.No caller — three UseCases hand-rewrite the same parallel fan-out.Sin llamador — tres UseCases reescriben el mismo abanico paralelo a mano.

A tradução do status do ack é: 0 (ou 5) = sucesso, 1 = duplicado (tratado como sucesso), qualquer outro = erro. No sucesso o conteúdo é apagado da linha; no erro, é mantido — e é isso que torna o reenvio possível. Em rejeição de negócio, o erro também vai ao Crashlytics com uma impressão digital de oito campos (código estável, código de erro do app, categoria, trace, código, mensagem, erro original e o ack). The ack status translation is: 0 (or 5) = success, 1 = duplicate (treated as success), anything else = error. On success the content is wiped from the row; on error it is kept — and that's what makes the resend possible. On a business rejection, the error also goes to Crashlytics with an eight-field fingerprint (stable code, app error code, category, trace, code, message, original error and the ack). La traducción del status del ack es: 0 (o 5) = éxito, 1 = duplicado (tratado como éxito), cualquier otro = error. En el éxito el contenido se borra de la fila; en el error se mantiene — y eso es lo que hace posible el reenvío. En rechazo de negocio, el error también va a Crashlytics con una huella de ocho campos (código estable, código de error de la app, categoría, trace, código, mensaje, error original y el ack).

DataSyncOrchestrator orquestrador · dono do diário de recebimentosorchestrator · owner of the received journalorquestador · dueño del registro de recepción

Notifier keepAlive que observa o ciclo de vida do app e mantém um timer que se reagenda a cada volta. Ele registra 26 alvos — um por estrutura — e é o único lugar do app onde o TTL é comparado.A keepAlive Notifier that observes the app lifecycle and keeps a timer that reschedules itself each round. It registers 26 targets — one per structure — and is the only place in the app where the TTL is compared.Notifier keepAlive que observa el ciclo de vida de la app y mantiene un timer que se reagenda en cada vuelta. Registra 26 objetivos — uno por estructura — y es el único lugar de la app donde el TTL se compara.

MétodoMethodMétodoRetornaReturnsDevuelveUsoUseUso
sweep()Future<void>A varredura por TTL. Seis guardas antes de começar (já varrendo, sincronia inicial pendente, modo mock, sem sessão, offline, configuração indisponível). Depois adota a cadência da configuração, lê o lastSyncAt de todas as 26 estruturas em série, monta a lista das obsoletas e refresca todas em paralelo. No fim, incrementa uma revisão por estrutura que deu certo — é o canal que faz Home, Pedidos, Visitas e Varejos re-lerem o cache sozinhos. The TTL sweep. Six guards before starting (already sweeping, initial sync pending, mock mode, no session, offline, configuration unavailable). It then adopts the cadence from configuration, reads lastSyncAt for all 26 structures serially, builds the stale list and refreshes all of them in parallel. At the end it bumps one revision per structure that succeeded — the channel that makes Home, Orders, Visits and Retails re-read the cache on their own. El barrido por TTL. Seis guardas antes de empezar (ya barriendo, sincronización inicial pendiente, modo mock, sin sesión, offline, configuración no disponible). Luego adopta la cadencia de la configuración, lee el lastSyncAt de las 26 estructuras en serie, arma la lista de las obsoletas y refresca todas en paralelo. Al final, incrementa una revisión por estructura exitosa — el canal que hace que Home, Pedidos, Visitas y Puntos de venta relean el caché solos.
syncType({type})Future<bool>O botão de cada cartão de Recebimentos: refresca uma estrutura e incrementa a revisão dela. Sem guarda de reentrância — quem controla o estado "sincronizando" é a tela.Each Received card's button: refreshes one structure and bumps its revision. No re-entrancy guard — the screen is what tracks the "syncing" state.El botón de cada tarjeta de Recepción: refresca una estructura e incrementa su revisión. Sin guarda de reentrancia — quien controla el estado "sincronizando" es la pantalla.
resyncAll()Future<void>O cartão "Sincronizar todos". Se já houver sincronia rodando ou pendente, retorna em silêncio. Senão marca "rodando", roda o lote de configuração (que é um portão duro), depois o núcleo e o resto em sequência, incrementa as revisões e marca "concluído". The "Sync all" card. If a sync is already running or pending, it returns silently. Otherwise it marks "running", runs the config batch (a hard gate), then core and rest in sequence, bumps the revisions and marks "completed". La tarjeta "Sincronizar todos". Si ya hay sincronización corriendo o pendiente, retorna en silencio. Si no, marca "corriendo", corre el lote de configuración (que es una puerta dura), después el núcleo y el resto en secuencia, incrementa las revisiones y marca "completado".
startInitialSync() · retry()Future<void>A carga do login, em três lotes (configuração → núcleo → resto), com um piso de 3 s para o splash não piscar. Falha no lote de configuração deixa a sincronia pendente e a tela de carregamento oferece o retry.The login load, in three batches (config → core → rest), with a 3 s floor so the splash doesn't flash. A failure in the config batch leaves the sync pending and the loading screen offers the retry.La carga del login, en tres lotes (configuración → núcleo → resto), con un piso de 3 s para que el splash no parpadee. Un fallo en el lote de configuración deja la sincronización pendiente y la pantalla de carga ofrece el retry.

Cada tentativa termina gravando o registro daquele tipo, com o lastSyncAt lido do cache da própria feature (nunca o relógio do momento). Nada aqui propaga exceção: falha ao refrescar, falha ao gravar o registro e falha ao ler a configuração são todas absorvidas. Every attempt ends by writing that type's record, with lastSyncAt read from the feature's own cache (never the current clock). Nothing here propagates an exception: a refresh failure, a record-write failure and a configuration-read failure are all absorbed. Cada intento termina grabando el registro de ese tipo, con el lastSyncAt leído del caché de la propia feature (nunca el reloj del momento). Nada aquí propaga excepción: fallo al refrescar, fallo al grabar el registro y fallo al leer la configuración son todos absorbidos.

12

Notifier & State

O DataCenterNotifier (@riverpod, provider dataCenterProvider, autoDispose) é o cérebro das quatro telas da feature — a lista e os três detalhes leem todos o mesmo provider, e os detalhes acham o seu item filtrando a lista já carregada. O build() observa o mercado ativo e aguarda a configuração de mercado, e delega tudo a _load(). O State (DataCenterState, Freezed) é a fonte única de verdade: guarda os três diários crus, a configuração das abas e todo o estado de cliente (aba ativa, busca, ordenação, filtros por aba e os conjuntos de "está em andamento"). Toda filtragem, ordenação e contagem é client-side, calculada em getters do State. DataCenterNotifier (@riverpod, provider dataCenterProvider, autoDispose) is the brain of the feature's four screens — the list and the three details all read the same provider, and the details find their item by filtering the already-loaded list. build() watches the active market and awaits market configuration, then delegates everything to _load(). The State (DataCenterState, Freezed) is the single source of truth: it holds the three raw journals, the tab configuration and all client state (active tab, search, sort, per-tab filters and the "in progress" sets). All filtering, sorting and counting is client-side, computed in State getters. El DataCenterNotifier (@riverpod, provider dataCenterProvider, autoDispose) es el cerebro de las cuatro pantallas de la feature — la lista y los tres detalles leen todos el mismo provider, y los detalles encuentran su ítem filtrando la lista ya cargada. El build() observa el mercado activo y espera la configuración de mercado, y delega todo a _load(). El State (DataCenterState, Freezed) es la fuente única de verdad: guarda los tres registros crudos, la configuración de las pestañas y todo el estado de cliente (pestaña activa, búsqueda, orden, filtros por pestaña y los conjuntos de "en curso"). Todo el filtrado, orden y conteo es client-side, calculado en getters del State.

MétodosMethodsMétodos

_load({current}) private

RetornoReturnRetorno Future<DataCenterState>

Dono único da montagem do State. Lê a configuração e o mercado, então busca três fontes em sequência — histórico de envios, registros de sincronia e a resolução dos pagamentos pendentes — e monta o State com a configuração das abas, os três diários e a lista de estruturas filtrada pelo mercado. Recebe o State atual por parâmetro e sobrescreve só os campos de servidor, preservando todo o estado de cliente (§37). Sole owner of building the State. It reads the configuration and the market, then fetches three sources in sequence — send history, sync records and the pending-payment resolution — and assembles the State with the tab configuration, the three journals and the structure list filtered by market. It takes the current State as a parameter and overwrites only the server fields, preserving all client state (§37). Dueño único del armado del State. Lee la configuración y el mercado, luego busca tres fuentes en secuencia — historial de envíos, registros de sincronización y la resolución de los pagos pendientes — y arma el State con la configuración de las pestañas, los tres registros y la lista de estructuras filtrada por el mercado. Recibe el State actual por parámetro y sobrescribe solo los campos de servidor, preservando todo el estado de cliente (§37).

Contrato de erro: falha nos dois primeiros é degradada para lista vazia — a tela mostra "nada aqui" em vez de um erro. Só a terceira pode derrubar a tela, porque o UseCase de pagamentos lança em vez de devolver. Error contract: a failure in the first two is degraded to an empty list — the screen shows "nothing here" instead of an error. Only the third can bring the screen down, because the payments UseCase throws instead of returning. Contrato de error: un fallo en los dos primeros se degrada a lista vacía — la pantalla muestra "nada aquí" en vez de un error. Solo el tercero puede tumbar la pantalla, porque el UseCase de pagos lanza en vez de devolver.

refresh() pull-to-refresh

RetornoReturnRetorno Future<void>

Molde canônico do §37: guarda de nulo, recarrega via _load() passando o State atual, e captura Failure para o estado de erro. Não seta AsyncValue.loading. É chamado pelo pull-to-refresh e também depois de toda ação (reenvio, sincronia de tipo, sincronia total, sincronia de pagamento). The canonical §37 shape: null guard, reload via _load() passing the current State, and catch Failure for the error state. It doesn't set AsyncValue.loading. It's called by pull-to-refresh and also after every action (resend, type sync, full sync, payment sync). El molde canónico del §37: guarda de nulo, recarga vía _load() pasando el State actual, y captura Failure para el estado de error. No setea AsyncValue.loading. Lo llama el pull-to-refresh y también después de toda acción (reenvío, sincronización de tipo, sincronización total, sincronización de pago).

setTab({index})

RetornoReturnRetorno void

Troca a aba ativa. Não reseta busca nem filtros — cada aba guarda os seus próprios filtros, mas a busca e a ordenação são compartilhadas entre as abas.Switches the active tab. It does not reset search or filters — each tab keeps its own filters, but search and sort are shared across tabs.Cambia la pestaña activa. No resetea búsqueda ni filtros — cada pestaña guarda sus propios filtros, pero la búsqueda y el orden son compartidos entre pestañas.

setSearchQuery({query})

RetornoReturnRetorno void

Atualiza o termo, com guarda de idempotência (termo igual não emite estado). Sem debounce: cada tecla remonta e refiltra a lista inteira.Updates the term, with an idempotence guard (an identical term emits no state). No debounce: every keystroke remaps and refilters the whole list.Actualiza el término, con guarda de idempotencia (término igual no emite estado). Sin debounce: cada tecla rearma y refiltra la lista entera.

setSort({sort})

RetornoReturnRetorno void

Define a ordenação. Vale para todas as abas.Sets the sort. It applies to every tab.Define el orden. Vale para todas las pestañas.

applyFilters({tabType, filters}) · clearFilters({tabType})

RetornoReturnRetorno void

Grava o mapa de filtros daquela aba, substituindo o anterior por inteiro. clearFilters é literalmente applyFilters com um mapa vazio.Writes that tab's filter map, replacing the previous one wholesale. clearFilters is literally applyFilters with an empty map.Graba el mapa de filtros de esa pestaña, sustituyendo el anterior por completo. clearFilters es literalmente applyFilters con un mapa vacío.

toggleStatusFilter({tabType, statusValues}) as caixasthe boxeslas cajas

RetornoReturnRetorno void

O que as caixas de contagem chamam. Se o conjunto pedido já é exatamente o selecionado, limpa; se vem vazio (caixa com zero itens), também limpa; senão substitui. Compartilha o mesmo espaço do filtro de status do modal, então um sobrescreve o outro. What the count boxes call. If the requested set already is exactly the selected one, it clears; if it comes in empty (a box with zero items), it also clears; otherwise it replaces. It shares the same slot as the modal's status filter, so one overwrites the other. Lo que llaman las cajas de conteo. Si el conjunto pedido ya es exactamente el seleccionado, limpia; si viene vacío (caja con cero ítems), también limpia; si no, sustituye. Comparte el mismo espacio que el filtro de estado del modal, así que uno sobrescribe al otro.

resend({localId})

RetornoReturnRetorno Future<Result<DispatcherAck, Failure>>

Marca o id como "reenviando" (é o que faz o botão daquele cartão girar, sem travar os outros), delega ao DispatcherOrchestrator.resend, recarrega, e depois desmarca. Devolve o resultado cru para o widget escolher o aviso. Marks the id as "resending" (that's what spins that card's button without freezing the others), delegates to DispatcherOrchestrator.resend, reloads, then unmarks. It returns the raw result so the widget can pick the notice. Marca el id como "reenviando" (es lo que hace girar el botón de esa tarjeta sin trabar los otros), delega al DispatcherOrchestrator.resend, recarga, y luego desmarca. Devuelve el resultado crudo para que el widget elija el aviso.

syncType({type})

RetornoReturnRetorno Future<bool>

Mesmo padrão, com o conjunto de chaves de estrutura em andamento. Delega ao DataSyncOrchestrator.syncType e devolve se deu certo.Same pattern, using the set of in-progress structure keys. Delegates to DataSyncOrchestrator.syncType and returns whether it succeeded.Mismo patrón, con el conjunto de claves de estructura en curso. Delega al DataSyncOrchestrator.syncType y devuelve si tuvo éxito.

syncAll()

RetornoReturnRetorno Future<bool>

Chama resyncAll(), lê o status resultante do orquestrador, recarrega, e devolve true se o status for "concluído". Não usa conjunto de ids: o giro do botão vem direto do orquestrador. Calls resyncAll(), reads the resulting status from the orchestrator, reloads, and returns true when the status is "completed". It uses no id set: the button's spinner comes straight from the orchestrator. Llama resyncAll(), lee el estado resultante del orquestador, recarga, y devuelve true si el estado es "completado". No usa conjunto de ids: el giro del botón viene directo del orquestador.

syncPayment({localId}) CL

RetornoReturnRetorno Future<Result<PaymentRegisterEntity, Failure>>

Acha o registro pelo id no State (erro genérico se não achar), marca como "sincronizando", delega ao SyncPaymentRegisterUseCase, recarrega e desmarca.Finds the register by id in the State (a generic error if not found), marks it "syncing", delegates to SyncPaymentRegisterUseCase, reloads and unmarks.Encuentra el registro por id en el State (error genérico si no lo halla), marca como "sincronizando", delega al SyncPaymentRegisterUseCase, recarga y desmarca.

State disponível para a PageState available to the PageState disponible para la Page

DataCenterState 12 campos + getters12 fields + getters12 campos + getters
campotipodefault
configDataCenterConfigDataCenterConfig()
activeTabIndexint0
dispatchesList<DispatchTransactionEntity>[]
dataSyncRecordsList<DataSyncRecordEntity>[]
dataSyncTypesList<DataSyncType>[]
paymentRegistersList<PaymentRegisterEntity>[]
selectedFiltersMap<String, Map<String, Set<String>>>{}
sortDataCenterSortnewest
resendingIdsSet<int>{}
syncingTypeKeysSet<String>{}
syncingPaymentIdsSet<int>{}
searchQueryString""

selectedFilters é aninhado em dois níveis: a chave externa é o tipo da aba, a interna é o código do filtro (status, type, attempts, period). Não há campo lastSyncAt — esta tela não tem DataLoadInfo. selectedFilters nests two levels: the outer key is the tab type, the inner one is the filter code (status, type, attempts, period). There is no lastSyncAt field — this screen has no DataLoadInfo. selectedFilters está anidado en dos niveles: la clave externa es el tipo de pestaña, la interna es el código del filtro (status, type, attempts, period). No hay campo lastSyncAt — esta pantalla no tiene DataLoadInfo.

Getters: tabs (só as visíveis e conhecidas), activeTab, activeFilters, hasActiveFilters, hasActiveSort, typeFilterOptions (dinâmico por aba), activeItemsAll, bucketCount, statusValuesForBucket, isBucketSelected, visibleItems, isResending, isSyncing, isSyncingPayment. O coração é o _itemsForTab, que normaliza os três diários numa única forma de linha (DataCenterItem: título, timestamp, grupo, status, valor de filtro, código de erro, tentativas, e os identificadores da aba) — é isso que permite um só cartão servir as três abas. Note que em Envios uma linha é uma transação, em Recebimentos é um tipo do mercado (o registro é só um enfeite que pode faltar) e em Pagamentos é um registro. Getters: tabs (only visible and known ones), activeTab, activeFilters, hasActiveFilters, hasActiveSort, typeFilterOptions (dynamic per tab), activeItemsAll, bucketCount, statusValuesForBucket, isBucketSelected, visibleItems, isResending, isSyncing, isSyncingPayment. The heart is _itemsForTab, which normalises the three journals into a single row shape (DataCenterItem: title, timestamp, group, status, filter value, error code, attempts, and the tab's identifiers) — that's what lets one card serve all three tabs. Note that on Sent a row is one transaction, on Received it is one market type (the record is just a garnish that may be missing) and on Payments it is one register. Getters: tabs (solo las visibles y conocidas), activeTab, activeFilters, hasActiveFilters, hasActiveSort, typeFilterOptions (dinámico por pestaña), activeItemsAll, bucketCount, statusValuesForBucket, isBucketSelected, visibleItems, isResending, isSyncing, isSyncingPayment. El corazón es _itemsForTab, que normaliza los tres registros en una única forma de fila (DataCenterItem: título, timestamp, grupo, estado, valor de filtro, código de error, intentos, y los identificadores de la pestaña) — eso es lo que permite que una sola tarjeta sirva las tres pestañas. Nótese que en Envíos una fila es una transacción, en Recepción es un tipo del mercado (el registro es solo un adorno que puede faltar) y en Pagos es un registro.

A busca recebe a função de tradução de fora (do widget), para poder casar o texto traduzido do título. O filtro de período pega a janela mais larga entre as opções marcadas e descarta itens sem timestamp. O activeItemsAll não é memoizado: um único build da aba o recalcula uma vez por caixa e mais uma para a lista. The search receives the translation function from outside (from the widget), so it can match the title's translated text. The period filter takes the widest window among the ticked options and drops items with no timestamp. activeItemsAll is not memoized: a single tab build recomputes it once per box plus once for the list. La búsqueda recibe la función de traducción de fuera (del widget), para poder casar el texto traducido del título. El filtro de período toma la ventana más amplia entre las opciones marcadas y descarta ítems sin timestamp. activeItemsAll no está memoizado: un único build de la pestaña lo recalcula una vez por caja y una más para la lista.

13

Page e widgetsPage & widgetsPage y widgets

A DataCenterPage (ConsumerWidget, sem parâmetros) observa o dataCenterProvider e monta os filhos. Loading e erro são globais; o conteúdo existe só no ramo data. A barra de abas só aparece com mais de uma aba visível. A lista é um for dentro de uma Columnnão um ListView, então todos os cartões são construídos de uma vez. Árvore de composição: DataCenterPage (ConsumerWidget, no parameters) watches dataCenterProvider and composes the children. Loading and error are global; content exists only in the data branch. The tab bar only shows with more than one visible tab. The list is a for inside a Columnnot a ListView, so every card is built at once. Composition tree: La DataCenterPage (ConsumerWidget, sin parámetros) observa el dataCenterProvider y compone los hijos. Loading y error son globales; el contenido existe solo en la rama data. La barra de pestañas solo aparece con más de una pestaña visible. La lista es un for dentro de una Columnno un ListView, así que todas las tarjetas se construyen de una vez. Árbol de composición:

  • DataCenterPage
    • AppPageShell displayBackButton · drawer
      • CustomLoadingIndicator loading
      • FailureStateView error → ref.invalidate(dataCenterProvider)
      • CustomPullToRefresh data → refresh()
        • CustomIcon + CustomText ícone de banco de dados + data_center_title
        • CustomTabBar só se tabs.length > 1 · labels da config → setTab
        • DataCenterTabView ConsumerStatefulWidget · dono do controller de busca
          • DataCenterBoxesWidget esconde-se sem caixas
            • CustomToolTile 1 por caixa · contagem + isSelected → toggleStatusFilter
          • CustomInput busca · só se activeTab.hasFilter → setSearchQuery
          • DataCenterActionsWidget esconde-se se !hasFilter (leva sort junto)
            • DataCenterSortModalContent modal · ConectaSortModalContent<DataCenterSort> → setSort
            • DataCenterFiltersModalContent modal · pills + dropdown de tipo · draft local → applyFilters / clearFilters
          • DataCenterSyncAllCardWidget só na aba dataSync → syncAll + ConectaNotice
          • _EmptyState CustomEmptyState · mensagem por aba
          • DataCenterCardWidget 1 por item · tap → _navigate
            • _badge + _statusPill + _attemptsPill cor e ícone do grupo · tentativas só se > 1
            • _dateLine data + hora com segundos, ou data_center_never_synced
            • _actionButton Reenviar (erro em Envios) · Sincronizar (Recebimentos) · Sincronizar pagamento (só READY)
              • DispatchResendConfirmModalContent modal · texto muda por resendMayDuplicate → resend

O toque no cartão roteia por aba: EnviosDispatcherDetailPage(localId), RecebimentosDataSyncDetailPage(typeKey), Pagamentos → nada (retorna sem navegar, embora o cartão continue com o efeito de toque). Os dois detalhes são ConsumerWidgets que reusam o dataCenterProvider e acham o item por id/chave; item ausente vira CustomErrorState. Só o detalhe de envio tem ações (copiar código de suporte + reenviar), e só quando o status é de erro. Existe ainda a IntegrationDetailPage — uma casca com ícone e "Em breve", hoje inalcançável. Tapping a card routes per tab: SentDispatcherDetailPage(localId), ReceivedDataSyncDetailPage(typeKey), Payments → nothing (it returns without navigating, though the card keeps its tap ripple). Both details are ConsumerWidgets reusing dataCenterProvider and finding the item by id/key; a missing item becomes a CustomErrorState. Only the send detail has actions (copy support code + resend), and only when the status is an error. There is also an IntegrationDetailPage — a shell with an icon and "Coming soon", unreachable today. El toque en la tarjeta rutea por pestaña: EnvíosDispatcherDetailPage(localId), RecepciónDataSyncDetailPage(typeKey), Pagos → nada (retorna sin navegar, aunque la tarjeta mantiene el efecto de toque). Los dos detalles son ConsumerWidgets que reutilizan el dataCenterProvider y encuentran el ítem por id/clave; ítem ausente es un CustomErrorState. Solo el detalle de envío tiene acciones (copiar código de soporte + reenviar), y solo cuando el estado es de error. Existe además la IntegrationDetailPage — una cáscara con ícono y "Próximamente", hoy inalcanzable.

Duas assimetrias de shell valem nota: a lista usa FailureStateView no erro, mas os dois detalhes imprimem o erro cru; e "não encontrado" usa CustomErrorState nos detalhes contra CustomEmptyState na lista. Two shell asymmetries are worth noting: the list uses FailureStateView on error, but both details print the raw error; and "not found" uses CustomErrorState on the details against CustomEmptyState on the list. Dos asimetrías de shell merecen nota: la lista usa FailureStateView en el error, pero los dos detalles imprimen el error crudo; y "no encontrado" usa CustomErrorState en los detalles contra CustomEmptyState en la lista.

Notas por mercadoMarket notesNotas por mercado

A Central de dados é dirigida por configuração de mercado (End Market Configuration), não por código fixo — as abas, as caixas e os filtros todos vêm de lá. O portão de entrada é duplo: o bloco dataCenterConfig (que dá as abas) e o item data_center do menu lateral (que dá o caminho). Os dois existem nos mesmos três mercados: The Data center is driven by market configuration (End Market Configuration), not hardcoded — the tabs, the boxes and the filters all come from there. The entry gate is twofold: the dataCenterConfig block (which supplies the tabs) and the drawer's data_center item (which supplies the route). Both exist in the same three markets: El Centro de datos se rige por configuración de mercado (End Market Configuration), no por código fijo — las pestañas, las cajas y los filtros vienen todos de allí. La puerta de entrada es doble: el bloque dataCenterConfig (que da las pestañas) y el ítem data_center del menú lateral (que da el camino). Ambos existen en los mismos tres mercados:

BRx CLx ZAx AR PY PE
disponívelavailabledisponible presente, desligadopresent, offpresente, apagado ausenteabsentausente

Chaves de dataCenterConfigdataCenterConfig keysClaves de dataCenterConfig

Uma linha por chave, sem truncar. As linhas indentadas são filhas da aba imediatamente acima. Em AR/PY/PE o bloco dataCenterConfig inteiro não existe — por isso todas as chaves aparecem como ausentes. Os três arquivos de ambiente (produção, UAT e pré-produção) têm este bloco idêntico: não há variação por ambiente a documentar. One row per key, nothing truncated. Indented rows are children of the tab immediately above. In AR/PY/PE the whole dataCenterConfig block doesn't exist — hence every key shows as absent. The three environment files (production, UAT and pre-production) carry this block identically: there is no per-environment variation to document. Una fila por clave, sin truncar. Las filas indentadas son hijas de la pestaña inmediatamente arriba. En AR/PY/PE el bloque dataCenterConfig completo no existe — por eso todas las claves aparecen como ausentes. Los tres archivos de ambiente (producción, UAT y preproducción) traen este bloque idéntico: no hay variación por ambiente que documentar.

ChaveKeyClaveBRCLZAARPYPE
dataCenterConfigxxx
tabs[dispatch]xxx
isVisiblexxx
labelKey = data_center_tab_dispatchesxxx
hasFilterxxx
boxes[success] = data_center_box_sentxxx
boxes[error] = data_center_box_errorsxxx
boxes[pending] = data_center_box_pendingxxx
filters[status] · multi · 4 opçõesoptionsopcionesxxx
filters[type] · single · sem opções (dinâmico)no options (dynamic)sin opciones (dinámico)xxx
filters[attempts] · multi · 2 opçõesoptionsopcionesxxx
filters[period] · single · 4 opçõesoptionsopcionesxxx
tabs[dataSync]xxx
isVisiblexxx
labelKey = data_center_tab_datasyncsxxx
hasFilterxxx
boxes[success] = data_center_box_receivedxxx
boxes[error] = data_center_box_errorsxxx
boxes[pending] = data_center_box_pendingxxx
filters[status] · multi · 3 opçõesoptionsopcionesxxx
filters[type] · single · sem opções (dinâmico)no options (dynamic)sin opciones (dinámico)xxx
tabs[payment]x
isVisiblex
labelKey = data_center_tab_paymentsx
hasFilterx
boxes[success] = data_center_box_sentx
boxes[pending] = data_center_box_pendingx
filters[status] · multi · 4 opçõesoptionsopcionesx
filters[type] · single · sem opções (dinâmico)no options (dynamic)sin opciones (dinámico)x
tabs[integration]

Nenhuma aba é declarada com isVisible: false em mercado algum — o desligamento aqui é sempre por ausência. A aba de pagamentos é a única sem caixa de erro: ela declara só sucesso e pendente. E tabs[integration] está na tabela justamente porque o enum a conhece e nenhum mercado a declara. No tab is declared with isVisible: false in any market — switching off here is always by absence. The payments tab is the only one without an error box: it declares only success and pending. And tabs[integration] is in the table precisely because the enum knows it and no market declares it. Ninguna pestaña se declara con isVisible: false en ningún mercado — apagar aquí es siempre por ausencia. La pestaña de pagos es la única sin caja de error: declara solo éxito y pendiente. Y tabs[integration] está en la tabla precisamente porque el enum la conoce y ningún mercado la declara.

Chaves de dataFreshnessConfigdataFreshnessConfig keysClaves de dataFreshnessConfig

É a configuração que a aba Recebimentos obedece. Uma linha por chave; os valores são segundos. As 8 últimas linhas são estruturas sem TTL declarado em nenhum mercado — caem no default. Em AR/PY/PE o bloco todo não existe, então tudo vira o default de 300 s com varredura de 60 s. This is the configuration the Received tab obeys. One row per key; values are seconds. The last 8 rows are structures with no TTL declared in any market — they fall back to the default. In AR/PY/PE the whole block doesn't exist, so everything becomes the 300 s default with a 60 s sweep. Es la configuración que la pestaña Recepción obedece. Una fila por clave; los valores son segundos. Las últimas 8 filas son estructuras sin TTL declarado en ningún mercado — caen en el default. En AR/PY/PE el bloque completo no existe, así que todo se vuelve el default de 300 s con barrido de 60 s.

ChaveKeyClaveBRCLZAARPYPE
defaultTtlSeconds300300300
sweepIntervalSeconds606060
ttlSecondsByType.homeKpi300300300
ttlSecondsByType.visits600600600
ttlSecondsByType.orders600600600
ttlSecondsByType.retails180018001800
ttlSecondsByType.financialManagement900900900
ttlSecondsByType.tasks600600600
ttlSecondsByType.stockControl900900900
ttlSecondsByType.productCatalog864008640086400
ttlSecondsByType.promotion300300300
ttlSecondsByType.surveys360036003600
ttlSecondsByType.competitorInsights 1864008640086400
ttlSecondsByType.merchandising864008640086400
ttlSecondsByType.marginCalculator 1864008640086400
ttlSecondsByType.notifications300300300
ttlSecondsByType.communications360036003600
ttlSecondsByType.faq864008640086400
ttlSecondsByType.referenceData864008640086400
ttlSecondsByType.resource360036003600
ttlSecondsByType.cases 2
ttlSecondsByType.conectaVoce 2
ttlSecondsByType.merchandisingOptions 2
ttlSecondsByType.merchandisingImageAudits 2
ttlSecondsByType.merchandisingServiceOrders 2
ttlSecondsByType.primeManagement 2
ttlSecondsByType.buyback 2
ttlSecondsByType.report 2

1 TTL declarado em BR e CL para estruturas que só existem em ZA — configuração morta nesses dois mercados. 2 Estrutura sem TTL declarado em mercado algum: cai no default de 300 s, a faixa mais agressiva, ainda que algumas sejam catálogos pesados. Chave de TTL que o app não reconhece é descartada em silêncio pelo mapper. 1 TTL declared in BR and CL for structures that only exist in ZA — dead configuration in those two markets. 2 Structure with no declared TTL in any market: it falls back to the 300 s default, the most aggressive tier, even though some are heavy catalogs. A TTL key the app doesn't recognise is silently dropped by the mapper. 1 TTL declarado en BR y CL para estructuras que solo existen en ZA — configuración muerta en esos dos mercados. 2 Estructura sin TTL declarado en ningún mercado: cae en el default de 300 s, la franja más agresiva, aunque algunas sean catálogos pesados. Una clave de TTL que la app no reconoce es descartada en silencio por el mapper.

Caminhos de entradaEntry pointsCaminos de entrada

Uma linha por chave de configuração que abre a tela. A coluna bloqueia diz se aquela categoria impede o fluxo de seguir.One row per configuration key that opens the screen. The blocks column says whether that category prevents the flow from proceeding.Una fila por clave de configuración que abre la pantalla. La columna bloquea dice si esa categoría impide que el flujo siga.

ChaveKeyClaveBRCLZAARPYPE
menuConfigdata_centerxxx
endJourneyConfigunsynced_transactionsxxx
isBlockingfalsetruefalse
visitEndConfigunsynced_transactionsxxx
isBlockingfalsefalsefalse
homeConfigrep_actionsdata_center

A última linha está aqui para deixar registrado que não existe atalho na Home em nenhum mercado — a grade de ações do representante nunca declara a Central de dados. The last row is here to put on record that there is no Home shortcut in any market — the rep action grid never declares the Data center. La última fila está aquí para dejar registrado que no existe atajo en el Home en ningún mercado — la grilla de acciones del representante nunca declara el Centro de datos.

CL

A terceira aba e o encerramento bloqueanteThe third tab and the blocking wrap-upLa tercera pestaña y el cierre bloqueante O Chile é o único mercado com a aba Pagamentos, e isso é coerente com o resto da configuração: a criação de pagamentos também é exclusiva do Chile (o módulo financial_management_payment_creation só existe lá), então é o único mercado onde pode nascer um registro de pagamento. É também o único onde unsynced_transactions bloqueia o encerramento da jornada — em BR e ZA a categoria aparece mas deixa passar. E a etiqueta do status "enviado" de pagamento é "Sincronizado", enquanto a caixa que o agrupa se chama "Enviados": mesma coisa, duas palavras. Chile is the only market with the Payments tab, and that is coherent with the rest of the configuration: payment creation is Chile-exclusive too (the financial_management_payment_creation module only exists there), so it's the only market where a payment register can be born. It's also the only one where unsynced_transactions blocks the end of the journey — in BR and ZA the category shows but lets you through. And a payment's "sent" status label reads "Synced" while the box grouping it is called "Sent": same thing, two words. Chile es el único mercado con la pestaña Pagos, y eso es coherente con el resto de la configuración: la creación de pagos también es exclusiva de Chile (el módulo financial_management_payment_creation solo existe allí), así que es el único mercado donde puede nacer un registro de pago. Es también el único donde unsynced_transactions bloquea el cierre de la jornada — en BR y ZA la categoría aparece pero deja pasar. Y la etiqueta del estado "enviado" de pago dice "Sincronizado", mientras la caja que lo agrupa se llama "Enviados": lo mismo, dos palabras.

BRZA

Duas abas, e uma resolução que roda à toaTwo tabs, and a resolution that runs for nothingDos pestañas, y una resolución que corre en vano Brasil e África do Sul têm exatamente as mesmas duas abas, com caixas e filtros byte a byte idênticos. Diferem no número de estruturas que a aba Recebimentos lista — 24 em BR contra 19 em ZA — porque sete estruturas existem só em BR e duas só em ZA (delta líquido de cinco). Mesmo sem aba de pagamentos, os dois executam a resolução de pagamentos pendentes a cada abertura e a cada recarga da tela, porque o carregamento não consulta a configuração antes de chamá-la. Brazil and South Africa have exactly the same two tabs, with byte-identical boxes and filters. They differ in how many structures the Received tab lists — 24 in BR against 19 in ZA — because seven structures exist only in BR and two only in ZA (a net delta of five). Even with no payments tab, both run the pending-payment resolution on every open and every reload of the screen, because the load doesn't consult the configuration before calling it. Brasil y Sudáfrica tienen exactamente las mismas dos pestañas, con cajas y filtros byte a byte idénticos. Difieren en cuántas estructuras lista la pestaña Recepción — 24 en BR contra 19 en ZA — porque siete estructuras existen solo en BR y dos solo en ZA (delta neto de cinco). Incluso sin pestaña de pagos, ambos ejecutan la resolución de pagos pendientes en cada apertura y cada recarga de la pantalla, porque la carga no consulta la configuración antes de llamarla.

ARPYPE

AR · PY · PE — sem a featureAR · PY · PE — feature absentAR · PY · PE — sin la feature Existem como mercados do app, mas com configuração mínima: só quatro blocos de topo, e nenhum deles é dataCenterConfig, dataFreshnessConfig, menuConfig, endJourneyConfig ou visitEndConfig. Ou seja: não há caminho nenhum para chegar à tela — nem item no menu lateral, nem categoria de encerramento. A rota e a página continuam existindo no código e renderizariam um cabeçalho com nenhuma aba se fossem alcançadas. Além disso, nenhum valor de DataSyncType lista esses três mercados, então a aba Recebimentos não teria linha alguma. Curiosamente, as 84 chaves de tradução da feature estão completas nos três — texto traduzido para uma tela inalcançável. They exist as app markets, but with minimal configuration: only four top-level blocks, and none of them is dataCenterConfig, dataFreshnessConfig, menuConfig, endJourneyConfig or visitEndConfig. So: there is no route at all to reach the screen — no drawer item, no wrap-up category. The route and the page still exist in code and would render a header with no tabs if reached. On top of that, no DataSyncType value lists those three markets, so the Received tab would have no rows at all. Curiously, the feature's 84 translation keys are complete in all three — translated text for an unreachable screen. Existen como mercados de la app, pero con configuración mínima: apenas cuatro bloques de tope, y ninguno de ellos es dataCenterConfig, dataFreshnessConfig, menuConfig, endJourneyConfig o visitEndConfig. O sea: no hay ningún camino para llegar a la pantalla — ni ítem en el menú lateral, ni categoría de cierre. La ruta y la página siguen existiendo en el código y renderizarían un encabezado sin ninguna pestaña si se alcanzaran. Además, ningún valor de DataSyncType lista esos tres mercados, así que la pestaña Recepción no tendría ninguna fila. Curiosamente, las 84 claves de traducción de la feature están completas en los tres — texto traducido para una pantalla inalcanzable.

Pendências / roadmapPending items / roadmapPendientes / roadmap

  • Só visitas têm fila offline; todo o resto vira erro definitivo. O dispatch() só enfileira quando o tipo é visit; qualquer outra transação feita offline atravessa até o gateway, é recusada pela guarda de offline e é gravada como error. E o flush()apenas as visitas pendentes, então essas linhas nunca são reenviadas sozinhas — dependem de alguém abrir esta tela e tocar em Reenviar. É a razão de existir do botão manual, e o maior candidato a evolução do subsistema. Only visits have an offline queue; everything else becomes a permanent error. dispatch() only enqueues when the type is visit; any other transaction made offline travels down to the gateway, is refused by the offline guard and is stored as error. And flush() reads only the pending visits, so those rows are never retried on their own — they depend on someone opening this screen and tapping Resend. It's the reason the manual button exists, and the subsystem's biggest candidate for evolution. Solo las visitas tienen cola offline; todo lo demás se vuelve error definitivo. El dispatch() solo encola cuando el tipo es visit; cualquier otra transacción hecha offline atraviesa hasta el gateway, es rechazada por la guarda de offline y se graba como error. Y el flush() lee solo las visitas pendientes, así que esas filas nunca se reenvían solas — dependen de que alguien abra esta pantalla y toque Reenviar. Es la razón de ser del botón manual, y el mayor candidato a evolución del subsistema.
  • Os dois contadores de "não sincronizado" contam coisas diferentes — e o que bloqueia é o mais cego. O encerramento da visita conta tudo o que não é sucesso (inclui os erros); o encerramento da jornada conta só o que está pendente. Como só visitas chegam a pendente, o contador da jornada não vê nenhum erro de despacho — e é justamente ele que, no Chile, impede o rep de fechar o dia. Resultado: a tela que enxerga os erros não bloqueia, e a que bloqueia não enxerga os erros. The two "unsynced" counters count different things — and the blocking one is the blinder. The visit wrap-up counts everything that isn't a success (errors included); the journey wrap-up counts only what is pending. Since only visits ever become pending, the journey counter sees no dispatch error at all — and it is exactly the one that, in Chile, stops the rep from closing the day. Net result: the screen that sees the errors doesn't block, and the one that blocks doesn't see the errors. Los dos contadores de "no sincronizado" cuentan cosas distintas — y el que bloquea es el más ciego. El cierre de la visita cuenta todo lo que no es éxito (incluye los errores); el cierre de la jornada cuenta solo lo pendiente. Como solo las visitas llegan a pendiente, el contador de la jornada no ve ningún error de despacho — y es justamente el que, en Chile, impide al rep cerrar el día. Resultado: la pantalla que ve los errores no bloquea, y la que bloquea no ve los errores.
  • Uma falha de rede no reenvio apaga a chave de idempotência. Quando o backend recusa, o identificador da transação dele é guardado e o próximo reenvio o repete — replay idempotente. Mas o ramo de falha de transporte reescreve a linha sem preservar esse identificador, que volta a zero. Sequência real: envia → backend recusa com um id → reenvia → dá timeout → o id se perde → todos os reenvios seguintes vão com zero e o servidor os trata como transações novas. A network failure during a resend erases the idempotency key. When the backend rejects, its transaction id is stored and the next resend repeats it — idempotent replay. But the transport-failure branch rewrites the row without preserving that id, which goes back to zero. Real sequence: send → backend rejects with an id → resend → it times out → the id is lost → every later resend goes with zero and the server treats them as new transactions. Un fallo de red en el reenvío borra la clave de idempotencia. Cuando el backend rechaza, su identificador de transacción se guarda y el próximo reenvío lo repite — replay idempotente. Pero la rama de fallo de transporte reescribe la fila sin preservar ese identificador, que vuelve a cero. Secuencia real: envía → el backend rechaza con un id → reenvía → da timeout → el id se pierde → todos los reenvíos siguientes van con cero y el servidor los trata como transacciones nuevas.
  • Todo erro de servidor é reportado como erro de rede. O repository de transporte captura Object e converte tudo em falha de rede, apagando a classificação que o tratador de gRPC já tinha feito (400, 401, 404, 409, 500…). Duas consequências concretas: o flush() interrompe a fila inteira ao ver uma recusa de servidor numa visita, como se o aparelho estivesse offline; e o fluxo de visita relata "enfileirado para depois" numa rejeição real do backend — quando nada foi enfileirado. Every server error is reported as a network error. The transport repository catches Object and turns everything into a network failure, erasing the classification the gRPC handler had already made (400, 401, 404, 409, 500…). Two concrete consequences: flush() breaks the whole queue on seeing a server rejection on one visit, as if the device were offline; and the visit flow reports "queued for later" on a genuine backend rejection — when nothing was queued. Todo error de servidor se reporta como error de red. El repository de transporte captura Object y convierte todo en fallo de red, borrando la clasificación que el manejador de gRPC ya había hecho (400, 401, 404, 409, 500…). Dos consecuencias concretas: el flush() interrumpe la cola entera al ver un rechazo de servidor en una visita, como si el dispositivo estuviera offline; y el flujo de visita reporta "encolado para después" en un rechazo real del backend — cuando nada se encoló.
  • Três tipos de transação aparecem sem nome traduzido. O título do cartão é montado como dispatcher_type_<nome> e o resolvedor de traduções devolve a chave crua quando não a encontra. Faltam exatamente três chaves, nos seis mercados: smartInvestmentAnswer, imageRecognitionAudit e notes — e os três têm builder, logo são despacháveis de verdade. Um despacho de qualquer um deles mostra literalmente dispatcher_type_notes como título do cartão, no dropdown de filtro e no detalhe. No caminho inverso sobra uma chave órfã, dispatcher_type_merchandisingAudit, sem valor correspondente no enum. Three transaction types show up with no translated name. The card title is composed as dispatcher_type_<name> and the translation resolver returns the raw key when it can't find it. Exactly three keys are missing, in all six markets: smartInvestmentAnswer, imageRecognitionAudit and notes — and all three have a builder, so they really are dispatchable. A dispatch of any of them shows literally dispatcher_type_notes as the card title, in the filter dropdown and in the detail. In the opposite direction there's a leftover orphan key, dispatcher_type_merchandisingAudit, with no matching enum value. Tres tipos de transacción aparecen sin nombre traducido. El título de la tarjeta se compone como dispatcher_type_<nombre> y el resolvedor de traducciones devuelve la clave cruda cuando no la encuentra. Faltan exactamente tres claves, en los seis mercados: smartInvestmentAnswer, imageRecognitionAudit y notes — y los tres tienen builder, así que son despachables de verdad. Un despacho de cualquiera de ellos muestra literalmente dispatcher_type_notes como título de la tarjeta, en el dropdown de filtro y en el detalle. En el camino inverso sobra una clave huérfana, dispatcher_type_merchandisingAudit, sin valor correspondiente en el enum.
  • Uma falha "leve" de sincronia deixa o cartão vermelho e sem explicação. Quando a estrutura devolve falha sem lançar exceção — o caminho mais comum — o registro é gravado com mensagem de erro vazia; só o caminho de exceção carrega texto. E a linha de detalhe do erro só aparece se a mensagem não estiver vazia. O resultado é um status "Erro" sem código, sem descrição e sem nada para buscar. O identificador de rastreio da falha existe no repository e não é levado para o registro. A "soft" sync failure leaves the card red and unexplained. When the structure returns a failure without throwing — the commonest path — the record is written with an empty error message; only the exception path carries text. And the error detail row only shows when the message is non-empty. The result is an "Error" status with no code, no description and nothing to search for. The failure's trace identifier exists in the repository and is not carried into the record. Un fallo "blando" de sincronización deja la tarjeta roja y sin explicación. Cuando la estructura devuelve fallo sin lanzar excepción — el camino más común — el registro se graba con mensaje de error vacío; solo el camino de excepción lleva texto. Y la fila de detalle del error solo aparece si el mensaje no está vacío. El resultado es un estado "Error" sin código, sin descripción y sin nada que buscar. El identificador de rastreo del fallo existe en el repository y no se lleva al registro.
  • Um registro com erro exibe o horário do último acerto. A gravação do resultado lê o lastSyncAt do cache da feature depois da tentativa, inclusive quando ela falhou — e o cache continua com o valor da última sincronização bem-sucedida. O cartão então diz "Erro" ao lado de uma hora que não é a da falha. Não existe distinção entre "última tentativa" e "último sucesso" na estrutura. An errored record displays the timestamp of the last success. Writing the outcome reads the feature cache's lastSyncAt after the attempt, including when it failed — and the cache still holds the value of the last successful sync. The card then reads "Error" next to a time that isn't the failure's. There is no distinction between "last attempt" and "last success" in the structure. Un registro con error muestra la hora del último acierto. La grabación del resultado lee el lastSyncAt del caché de la feature después del intento, incluso cuando falló — y el caché sigue con el valor de la última sincronización exitosa. La tarjeta entonces dice "Error" al lado de una hora que no es la del fallo. No existe distinción entre "último intento" y "último éxito" en la estructura.
  • A varredura sincroniza estruturas que o mercado não tem, e grava registros que ninguém vê. O campo enabledMarkets do DataSyncType tem um único consumidor em todo o app: a montagem das linhas desta aba. O registro de alvos e os lotes da carga inicial não o consultam, então em ZA a varredura busca sete estruturas exclusivas de outros mercados a cada volta, e grava um registro para cada — registros que a aba filtra fora e que nada no app pode apagar. The sweep syncs structures the market doesn't have, and writes records nobody sees. DataSyncType's enabledMarkets field has a single consumer in the whole app: building this tab's rows. The target registry and the initial-load batches don't consult it, so in ZA the sweep fetches seven structures exclusive to other markets on every round, and writes a record for each — records the tab filters out and that nothing in the app can delete. El barrido sincroniza estructuras que el mercado no tiene, y graba registros que nadie ve. El campo enabledMarkets del DataSyncType tiene un único consumidor en toda la app: el armado de las filas de esta pestaña. El registro de objetivos y los lotes de la carga inicial no lo consultan, así que en ZA el barrido busca siete estructuras exclusivas de otros mercados en cada vuelta, y graba un registro para cada una — registros que la pestaña filtra fuera y que nada en la app puede borrar.
  • O mercado é gravado no registro de sincronia e nunca lido. A busca do upsert casa só pelo tipo, então trocar de mercado sobrescreve a linha do anterior em vez de conviver com ela — e, até ser sobrescrita, uma linha de outro mercado é exibida como se fosse do atual. O campo é peso morto, e o seu valor pode ainda ser silenciosamente trocado por BR pelo fallback de leitura. The market is written on the sync record and never read. The upsert's lookup matches by type only, so switching market overwrites the previous one's row instead of coexisting with it — and, until it is overwritten, another market's row is displayed as if it were the current one's. The field is dead weight, and its value can still be silently swapped for BR by the read fallback. El mercado se graba en el registro de sincronización y nunca se lee. La búsqueda del upsert casa solo por el tipo, así que cambiar de mercado sobrescribe la fila del anterior en vez de convivir con ella — y, hasta ser sobrescrita, una fila de otro mercado se muestra como si fuera de la actual. El campo es peso muerto, y su valor puede aún ser silenciosamente cambiado por BR por el fallback de lectura.
  • Nenhum dos três diários é podado. O de envios tem remoção nas quatro camadas e nenhum chamador; o de pagamentos tem nas três camadas de dados, sem UseCase e sem chamador; o de sincronia não tem remoção em camada alguma. Em nenhum dos três há retenção, limite ou expurgo. O de envios é o mais custoso: cresce sem limite, e toda leitura descomprime o conteúdo de todas as linhas — inclusive no recálculo de contagens, que roda depois de cada despacho. Os índices declarados em status e data não são usados, porque nenhuma leitura usa a API de consulta. O de pagamentos guarda as evidências em base64 para sempre. E uma única linha corrompida faz a leitura inteira falhar, esvaziando a aba. None of the three journals is pruned. The sent journal has removal in all four layers and no caller; the payments one has it in the three data layers, with no UseCase and no caller; the sync one has no removal in any layer. None of the three has retention, a cap or a purge. The sent one is the costliest: it grows without bound, and every read decompresses every row's content — including the counter recalculation, which runs after each dispatch. The indexes declared on status and date go unused, because no read uses the query API. The payments one keeps its evidence in base64 forever. And a single corrupt row makes the whole read fail, emptying the tab. Ninguno de los tres registros se poda. Los tres tienen método de eliminación declarado en las cuatro capas y ningún llamador; no hay retención, límite ni purga. El de envíos es el más costoso: crece sin límite, y toda lectura descomprime el contenido de todas las filas — incluido el recálculo de conteos, que corre después de cada despacho. Los índices declarados en estado y fecha no se usan, porque ninguna lectura usa la API de consulta. El de pagos guarda las evidencias en base64 para siempre. Y una única fila corrupta hace fallar la lectura entera, vaciando la pestaña.
  • Renomear um valor de enum corrompe o histórico em silêncio. O tipo é persistido pelo nome Dart, e a leitura de volta cai em visit (envios) ou resource (recebimentos) quando não reconhece — sem log. Um rename de refatoração transformaria linhas antigas em "Visita" ou numa segunda linha de "Recurso" com dados alheios. Renaming an enum value silently corrupts history. The type is persisted by its Dart name, and reading back falls to visit (sent) or resource (received) when unrecognised — with no log. A refactoring rename would turn old rows into "Visit" or into a second "Resource" row holding someone else's data. Renombrar un valor de enum corrompe el historial en silencio. El tipo se persiste por el nombre Dart, y la lectura de vuelta cae en visit (envíos) o resource (recepción) cuando no reconoce — sin log. Un rename de refactorización convertiría filas antiguas en "Visita" o en una segunda fila de "Recurso" con datos ajenos.
  • O botão "Sincronizar todos" pode avisar sucesso sem ter sincronizado nada. A rotina de sincronia completa retorna em silêncio se já houver uma sincronia rodando ou a inicial pendente, sem tocar o status — e o status nasce como "concluído". Quem chamou lê esse valor e mostra o aviso verde "Dados atualizados". O caso realista é tocar no botão logo depois do login, enquanto a carga inicial ainda corre. Há um segundo caminho, pior: o status olha o lote de configuração — se ele passa e todas as 26 estruturas falham, o aviso verde aparece igual. The "Sync all" button can report success without having synced anything. The full-sync routine returns silently if a sync is already running or the initial one is pending, without touching the status — and the status starts out as "completed". The caller reads that value and shows the green "Data updated" notice. The realistic case is tapping the button right after login, while the initial load is still running. There is a second, worse path: the status looks only at the configuration batch — if it passes and all 26 structures fail, the green notice shows up just the same. El botón "Sincronizar todos" puede avisar éxito sin haber sincronizado nada. La rutina de sincronización completa retorna en silencio si ya hay una sincronización corriendo o la inicial pendiente, sin tocar el estado — y el estado nace como "completado". Quien llamó lee ese valor y muestra el aviso verde "Datos actualizados". El caso realista es tocar el botón justo después del login, mientras la carga inicial aún corre. Hay un segundo camino, peor: el estado mira solo el lote de configuración — si pasa y todas las 26 estructuras fallan, el aviso verde aparece igual.
  • O cartão de pagamento repete o status no lugar do título, e não é clicável. O título da linha é a própria etiqueta de status, então cada cartão mostra o mesmo texto duas vezes e nunca o varejo, o valor ou o meio de pagamento — que existem no registro. Como o toque não navega para nenhum detalhe, não há superfície alguma na Central de dados para inspecionar esses campos (eles aparecem no detalhe do título em Gestão financeira). Efeitos colaterais: ordenar "por tipo" nessa aba ordena por status, e a busca — apesar de o cartão carregar a conta — não procura por nome nem por SAP, porque esse trecho é restrito à aba de Envios. The payment card repeats the status in place of the title, and isn't tappable. The row's title is the status label itself, so each card shows the same text twice and never the retail, the amount or the payment method — all of which exist on the register. Since tapping navigates to no detail, there is no surface at all in the Data center to inspect those fields (they show up on the item detail in Financial management). Side effects: sorting "by type" on that tab sorts by status, and the search — even though the card carries the account — does not look at name or SAP, because that block is restricted to the Sent tab. La tarjeta de pago repite el estado en lugar del título, y no es clicable. El título de la fila es la propia etiqueta de estado, así que cada tarjeta muestra el mismo texto dos veces y nunca el punto de venta, el monto o el medio de pago — que existen en el registro. Como el toque no navega a ningún detalle, no hay ninguna superficie en el Centro de datos para inspeccionar esos campos (aparecen en el detalle del título en Gestión financiera). Efectos colaterales: ordenar "por tipo" en esa pestaña ordena por estado, y la búsqueda — aunque la tarjeta lleve la cuenta — no busca por nombre ni por SAP, porque ese trecho está restringido a la pestaña de Envíos.
  • Uma falha no relatório de caixa desaparece. Ao sincronizar um pagamento, a linha final preserva a mensagem de erro anterior quando o relatório de caixa falha — e ela normalmente está vazia. O registro é promovido a enviado de todo modo, perde o botão, e nada indica que uma das três transações não saiu. O mesmo vale para o comprovante: a falha dele marca um campo de estado de evidência que nenhuma tela exibe, e não há caminho para reenviar só a evidência. A cash-report failure disappears. When syncing a payment, the final row preserves the previous error message when the cash report fails — and that is normally empty. The register is promoted to sent anyway, loses its button, and nothing indicates that one of the three transactions didn't go out. The same holds for the proof of payment: its failure sets an evidence-status field no screen displays, and there is no path to resend the evidence alone. Un fallo en el reporte de caja desaparece. Al sincronizar un pago, la fila final preserva el mensaje de error anterior cuando el reporte de caja falla — y normalmente está vacío. El registro se promueve a enviado de todos modos, pierde el botón, y nada indica que una de las tres transacciones no salió. Lo mismo vale para el comprobante: su fallo marca un campo de estado de evidencia que ninguna pantalla muestra, y no hay camino para reenviar solo la evidencia.
  • Um pagamento com status desconhecido se disfarça de sincronizado. O valor unknown reusa a etiqueta de sent, cai num grupo que a aba não declara caixa (logo não é contado em nenhuma) e não tem opção de filtro — então qualquer filtro o esconde. Pior: o encerramento da jornada o conta como pagamento pendente, enquanto esta tela o mostra como "Sincronizado". Duas telas, duas leituras opostas do mesmo registro. A payment with an unknown status disguises itself as synced. The unknown value reuses sent's label, lands in a group the tab declares no box for (so it is counted in none) and has no filter option — so any filter hides it. Worse: the journey wrap-up counts it as a pending payment, while this screen shows it as "Synced". Two screens, two opposite readings of the same register. Un pago con estado desconocido se disfraza de sincronizado. El valor unknown reutiliza la etiqueta de sent, cae en un grupo para el que la pestaña no declara caja (así que no se cuenta en ninguna) y no tiene opción de filtro — así que cualquier filtro lo esconde. Peor: el cierre de la jornada lo cuenta como pago pendiente, mientras esta pantalla lo muestra como "Sincronizado". Dos pantallas, dos lecturas opuestas del mismo registro.
  • A aba de "serviços" existe inteira e é inalcançável. O tipo integration tem valor no enum, página própria (uma casca com "Em breve"), rota, método de navegação e chave de tradução — mas nenhum mercado o declara, e o único caminho para a página exige um cartão de uma aba que nunca é montada. É andaime de uma funcionalidade não entregue; ou se configura, ou se remove. The "services" tab exists in full and is unreachable. The integration type has an enum value, its own page (a shell with "Coming soon"), a route, a navigation method and a translation key — but no market declares it, and the only path to the page requires a card from a tab that is never built. It's scaffolding for an unshipped feature; either configure it or remove it. La pestaña de "servicios" existe entera y es inalcanzable. El tipo integration tiene valor en el enum, página propia (una cáscara con "Próximamente"), ruta, método de navegación y clave de traducción — pero ningún mercado lo declara, y el único camino a la página exige una tarjeta de una pestaña que nunca se arma. Es andamio de una funcionalidad no entregada; o se configura, o se quita.
  • Configuração declarada e não obedecida. O ícone de cada caixa é lido da configuração, guardado na entity e nunca usado — o ícone real vem de uma tabela fixa no código (hoje os valores coincidem, então a divergência é invisível). Os códigos de filtro são configuráveis, mas só quatro têm efeito (status, type, attempts, period): um código novo renderiza os chips e não filtra nada. A ordenação não é configurável de forma alguma. E desligar hasFilter numa aba esconderia também a busca e a ordenação, não só o botão de filtro — nenhuma aba faz isso hoje, então esse caminho nunca foi exercitado. Configuration declared and not obeyed. Each box's icon is read from configuration, stored on the entity and never used — the real icon comes from a fixed table in code (today the values coincide, so the divergence is invisible). Filter codes are configurable, but only four have any effect (status, type, attempts, period): a new code renders the chips and filters nothing. Sorting isn't configurable at all. And switching hasFilter off on a tab would also hide the search and the sort, not just the filter button — no tab does that today, so that path has never been exercised. Configuración declarada y no obedecida. El ícono de cada caja se lee de la configuración, se guarda en la entity y nunca se usa — el ícono real viene de una tabla fija en el código (hoy los valores coinciden, así que la divergencia es invisible). Los códigos de filtro son configurables, pero solo cuatro tienen efecto (status, type, attempts, period): un código nuevo renderiza los chips y no filtra nada. El orden no es configurable en absoluto. Y apagar hasFilter en una pestaña esconderia también la búsqueda y el orden, no solo el botón de filtro — ninguna pestaña lo hace hoy, así que ese camino nunca se ejercitó.
  • Uma falha de leitura de dados deixa a tela vazia em vez de avisar. O carregamento degrada as falhas dos dois primeiros diários para lista vazia, então um problema de cache aparece como "nenhum envio no momento". Só a resolução de pagamentos lança de verdade — e é a única capaz de levar a tela ao estado de erro, mesmo nos mercados sem aba de pagamentos, onde ela roda igual. A data-read failure leaves the screen empty instead of warning. The load degrades failures of the first two journals to an empty list, so a cache problem shows up as "no sends at the moment". Only the payment resolution actually throws — and it is the only one able to take the screen to the error state, even in markets with no payments tab, where it runs all the same. Un fallo de lectura de datos deja la pantalla vacía en vez de avisar. La carga degrada los fallos de los dos primeros registros a lista vacía, así que un problema de caché aparece como "sin envíos por el momento". Solo la resolución de pagos lanza de verdad — y es la única capaz de llevar la pantalla al estado de error, incluso en los mercados sin pestaña de pagos, donde corre igual.
  • Diagnóstico que não chega ao suporte. O código estável e o identificador de rastreio são gravados em cada linha com erro e não aparecem em lugar algum — nem na tela de detalhe, nem no bloco de "copiar código de suporte", que leva o código de erro, o código de erro do app e a categoria, mas não esses dois. Esse bloco, aliás, é escrito com 27 rótulos fixos em inglês, o que é deliberado (é artefato de suporte, não texto de produto). O andamento da varredura em segundo plano também é registrado no estado e nunca mostrado — o rep não tem como saber que uma sincronia está correndo. Diagnostics that never reach support. The stable code and the trace identifier are written on every errored row and appear nowhere — not on the detail screen, not in the "copy support code" block, which carries the error code, the app error code and the category, but not those two. That block, incidentally, is written with 27 hardcoded English labels, which is deliberate (it's a support artifact, not product copy). The background sweep's progress is likewise recorded in state and never shown — the rep has no way to know a sync is running. Diagnóstico que no llega al soporte. El código estable y el identificador de rastreo se graban en cada fila con error y no aparecen en ningún lugar — ni en la pantalla de detalle, ni en el bloque de "copiar código de soporte", que lleva el código de error, el código de error de la app y la categoría, pero no esos dos. Ese bloque, por cierto, está escrito con 27 rótulos fijos en inglés, lo cual es deliberado (es artefacto de soporte, no texto de producto). El avance del barrido en segundo plano también se registra en el estado y nunca se muestra — el rep no tiene cómo saber que una sincronización está corriendo.
  • Sem reconciliação com o servidor. O contrato só oferece o envio: não existe RPC para consultar o histórico. A única verdade que o app recebe é o retorno síncrono de cada envio, então uma linha que ficou pendente ou com erro nunca é confrontada com o estado real no backend. É o limite de desenho desta tela, e vale registrar para não se esperar dela o que ela não pode fazer. No reconciliation with the server. The contract only offers sending: there is no RPC to query history. The only truth the app receives is each send's synchronous response, so a row left pending or errored is never checked against the backend's real state. It's this screen's design boundary, and worth recording so nobody expects from it what it cannot do. Sin reconciliación con el servidor. El contrato solo ofrece el envío: no existe RPC para consultar el historial. La única verdad que la app recibe es la respuesta síncrona de cada envío, así que una fila que quedó pendiente o con error nunca se confronta con el estado real en el backend. Es el límite de diseño de esta pantalla, y vale registrarlo para no esperar de ella lo que no puede hacer.
  • Pontas soltas menores. O limite de cinco tentativas do reenvio automático nunca é alcançado: uma linha pendente sempre tem zero tentativas, porque sair da fila é definitivo. A fila offline não deduplica — repetir a mesma ação offline cria uma linha por repetição, e todas são enviadas. O leque paralelo de envelopes do orquestrador não tem chamador (três UseCases o reescrevem à mão). O status 5 é aceito como sucesso, embora a varredura do backend tenha concluído que ele não existe. Dez chaves de tradução da feature não têm nenhum consumidor. E dois parsers de status caem em fallback sem log: um status de envio não reconhecido vira error — o que também habilita o botão Reenviar numa linha cujo estado real é desconhecido — e um de sincronia vira pending. Smaller loose ends. The automatic retry's five-attempt cap is never reached: a pending row always has zero attempts, because leaving the queue is final. The offline queue does not deduplicate — repeating the same offline action creates one row per repetition, and all of them are sent. The orchestrator's parallel envelope fan-out has no caller (three UseCases hand-rewrite it). Status 5 is accepted as success, although the backend sweep concluded it doesn't exist. Ten of the feature's translation keys have no consumer at all. And two status parsers fall back without logging: an unrecognised dispatch status becomes error — which also enables the Resend button on a row whose real state is unknown — and a sync one becomes pending. Puntas sueltas menores. El límite de cinco intentos del reenvío automático nunca se alcanza: una fila pendiente siempre tiene cero intentos, porque salir de la cola es definitivo. La cola offline no deduplica — repetir la misma acción offline crea una fila por repetición, y todas se envían. El abanico paralelo de envelopes del orquestador no tiene llamador (tres UseCases lo reescriben a mano). El estado 5 se acepta como éxito, aunque el barrido del backend concluyó que no existe. Diez claves de traducción de la feature no tienen ningún consumidor. Y dos parsers de estado caen en fallback sin log: un estado de envío no reconocido se vuelve error — lo que además habilita el botón Reenviar en una fila cuyo estado real es desconocido — y uno de sincronía se vuelve pending.
  • A configuração anotada do EMC ignora esta feature. O arquivo comentado de referência do End Market Configuration não menciona dataCenterConfig uma única vez — nem o README da pasta —, embora documente fielmente o dataFreshnessConfig. Toda a configuração desta tela, inclusive a aba de pagamentos do Chile, existe apenas nos arquivos reais. The EMC's annotated configuration ignores this feature. The commented End Market Configuration reference file doesn't mention dataCenterConfig even once — nor does the folder's README — although it documents dataFreshnessConfig faithfully. All of this screen's configuration, including Chile's payments tab, exists only in the real files. La configuración anotada del EMC ignora esta feature. El archivo comentado de referencia del End Market Configuration no menciona dataCenterConfig ni una vez — ni el README de la carpeta —, aunque documenta fielmente el dataFreshnessConfig. Toda la configuración de esta pantalla, incluida la pestaña de pagos de Chile, existe solo en los archivos reales.

Onde continuar lendoWhere to read nextDónde seguir leyendo Os dois caminhos de entrada estão em Jornada (encerramento do dia) e em Visitas / Detalhe da visita (encerramento da visita). As transações que mais aparecem na aba Envios têm doc própria: envio de pedido (do carrinho), visita, pesquisa, resposta de tarefa, contagem de estoque e leitura de notificação. A aba Pagamentos se explica em Criação de pagamentos e em Gestão financeira; a cobrança na entrega, em Entregas do dia. E as estruturas que a aba Recebimentos lista têm cada uma o seu doc — de Lista de pedidos e Varejos a Notificações, Pesquisas e Promoções. The two entry points live in Journey (end of day) and in Visits / Visit detail (visit wrap-up). The transactions that show up most on the Sent tab have their own docs: order placement (from the cart), visit, survey, task answer, stock count and notification read. The Payments tab is explained in Payment creation and Financial management; collection at delivery, in Deliveries of the day. And the structures the Received tab lists each have their own doc — from Order list and Retails to Notifications, Surveys and Promotions. Los dos caminos de entrada están en Jornada (cierre del día) y en Visitas / Detalle de la visita (cierre de la visita). Las transacciones que más aparecen en la pestaña Envíos tienen doc propia: envío de pedido (del carrito), visita, encuesta, respuesta de tarea, conteo de stock y lectura de notificación. La pestaña Pagos se explica en Creación de pagos y en Gestión financiera; la cobranza en la entrega, en Entregas del día. Y las estructuras que lista la pestaña Recepción tienen cada una su doc — de Lista de pedidos y Puntos de venta a Notificaciones, Encuestas y Promociones.