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 · VarejosFeature · RetailsFeature · Puntos de venta

Lista de varejosRetail listLista de puntos de venta

Os varejos sob a hierarquia do representante de vendas, num só lugar — com busca, criação de visita planejada e ad hoc. Cobre também o detalhe do varejo (cadastro completo, aberto pela visita) e a edição do cadastro — endereço, dias, entrega e outros campos que o mercado permite alterar. The retails under the sales rep's hierarchy, in one place — with search and planned and ad hoc visit creation. It also covers the retail detail (full profile, opened from the visit) and the editing of that profile — address, days, delivery and any other fields the market allows to change. Los puntos de venta bajo la jerarquía del representante de ventas, en un solo lugar — con búsqueda y creación de visita planificada y ad hoc. Cubre también el detalle del punto de venta (ficha completa, abierta desde la visita) y la edición de esa ficha — dirección, días, entrega y demás campos que el mercado permita cambiar.

PúblicoAudiencePúblico
Representante · QA · Suporte · DevRep · QA · Support · DevRepresentante · QA · Soporte · Dev
Onde ficaWhereDónde
Menu → VarejosDrawer → RetailsMenú → Puntos de venta
AtualizadoUpdatedActualizado
22/07/20262026-07-22
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 feature de Varejos tem duas telas irmãs que compartilham o mesmo domínio de "varejo" (account/PDV): a lista — os varejos da zona do representante de vendas, de onde ele cria visitas — e o detalhe — o cadastro completo de um varejo, aberto de dentro de uma visita, onde alguns campos podem ser editados. Responde três perguntas do dia a dia: The Retails feature has two sibling screens sharing the same "retail" domain (account/PDV): the list — the retails in the sales rep's zone, from which they create visits — and the detail — a retail's full profile, opened from inside a visit, where some fields can be edited. It answers three everyday questions: La feature de Puntos de venta tiene dos pantallas hermanas que comparten el mismo dominio de "punto de venta" (account/PDV): la lista — los puntos de venta de la zona del representante de ventas, desde donde crea visitas — y el detalle — la ficha completa de un punto de venta, abierta desde una visita, donde algunos campos pueden editarse. Responde tres preguntas del día a día:

Quais varejos existem?Which retails exist?¿Qué puntos de venta hay?

Um card por varejo da zona, com nome, SAP e endereço; busca por qualquer um deles.One card per retail in the zone, with name, SAP and address; search by any of them.Una tarjeta por punto de venta de la zona, con nombre, SAP y dirección; búsqueda por cualquiera.

Como criar uma visita?How to create a visit?¿Cómo crear una visita?

O card oferece Planejar (agenda futura) ou Ad Hoc (agora), quando o backend permite cada uma.The card offers Plan (future schedule) or Ad Hoc (now), when the backend allows each.La tarjeta ofrece Planificar (agenda futura) o Ad Hoc (ahora), cuando el backend lo permite.

O que dá para editar?What can be edited?¿Qué se puede editar?

No detalhe: nome, endereço, dias, entrega, categorias e mais — cada campo conforme o mercado.In the detail: name, address, days, delivery, categories and more — each field per market.En el detalle: nombre, dirección, días, entrega, categorías y más — cada campo según el mercado.

Duas telas, um domínioTwo screens, one domainDos pantallas, un dominio A lista (retails) e o detalhe (retail_detail) são pastas separadas, mas documentadas juntas por serem o par que fala do mesmo varejo. A lista trabalha com o dado enxuto do próprio serviço de Varejos; o detalhe lê o varejo de dentro de uma visita (Detalhe da visita). The list (retails) and the detail (retail_detail) are separate folders, documented together because they are the pair describing the same retail. The list uses the lean data from the Retails service itself; the detail reads the retail from inside a visit (Visit detail). La lista (retails) y el detalle (retail_detail) son carpetas separadas, documentadas juntas por ser el par que habla del mismo punto de venta. La lista usa el dato liviano del propio servicio de Puntos de venta; el detalle lee el punto de venta desde una visita (Detalle de visita).

02

Como acessarHow to openCómo acceder

  1. Lista — pelo menu lateralList — from the drawerLista — desde el menú lateralAbra o menu (drawer) e toque em Varejos. O item só aparece nos mercados que o habilitam no menu. É uma tela roteada (abre com seta de voltar), não uma aba base.Open the drawer and tap Retails. The item appears only in markets that enable it in the menu. It's a routed screen (opens with a back arrow), not a base tab.Abra el menú y toque Puntos de venta. El ítem aparece solo en los mercados que lo habilitan en el menú. Es una pantalla ruteada (abre con flecha de volver), no una pestaña base.
  2. Lista — pelo atalho da HomeList — from the Home shortcutLista — desde el atajo del HomeO módulo de ações do representante na Home também abre a lista de Varejos.The rep-actions module on Home also opens the Retails list.El módulo de acciones del representante en el Home también abre la lista de Puntos de venta.
  3. Detalhe — pela visitaDetail — from the visitDetalle — desde la visitaNo Detalhe da visita, toque no card do cliente. O detalhe abre pelo visitSfid — não pela lista de Varejos (tocar num card da lista não navega).In the Visit detail, tap the client card. The detail opens by visitSfid — not from the Retails list (tapping a list card doesn't navigate).En el Detalle de visita, toque la tarjeta del cliente. El detalle abre por visitSfid — no desde la lista de Puntos de venta (tocar una tarjeta de la lista no navega).
03

Estrutura da telaScreen structureEstructura de la pantalla

Lista de varejosRetail listLista de puntos de venta

CabeçalhoHeaderEncabezado
Título "Varejos" e a data da última sincronização dos dados (DataLoadInfo)."Retails" title and the data's last sync date (DataLoadInfo).Título "Puntos de venta" y la fecha de última sincronización (DataLoadInfo).
BuscaSearchBúsqueda
Campo que filtra por nome, SAP ou endereço enquanto você digita.A field filtering by name, SAP or address as you type.Campo que filtra por nombre, SAP o dirección mientras escribe.
Varejos na minha zonaRetails in my zonePuntos de venta en mi zona
Uma seção com um card por varejo: nome, SAP e — quando o backend permite — os botões Planejar e/ou Ad Hoc.A section with one card per retail: name, SAP and — when the backend allows — the Plan and/or Ad Hoc buttons.Una sección con una tarjeta por punto de venta: nombre, SAP y — cuando el backend lo permite — los botones Planificar y/o Ad Hoc.
Contador "X de Y""X of Y" counterContador "X de Y"
Mostra quantos varejos estão visíveis do total filtrado; a lista carrega mais ao rolar (20 por vez).Shows how many retails are visible of the filtered total; the list loads more as you scroll (20 at a time).Muestra cuántos puntos de venta están visibles del total filtrado; la lista carga más al desplazar (20 por vez).

Detalhe do varejoRetail detailDetalle del punto de venta

Uma coluna rolável (puxe para atualizar). Cada campo é uma seção que o mercado pode mostrar/ocultar e tornar editável ou não:A scrollable column (pull to refresh). Each field is a section the market can show/hide and make editable or not:Una columna desplazable (deslice para actualizar). Cada campo es una sección que el mercado puede mostrar/ocultar y hacer editable o no:

CabeçalhoHeaderEncabezado
Última sincronização, card do varejo (nome + SAP + selo de inadimplência) e o título "Detalhe do varejo".Last sync, retail card (name + SAP + overdue badge) and the "Retail detail" title.Última sincronización, tarjeta del punto de venta (nombre + SAP + sello de mora) y el título "Detalle del punto de venta".
IdentificaçãoIdentificationIdentificación
SAP, CNPJ/documento, inscrição estadual, nome (editável por modal), nome comercial e funcionários (abre Gerenciar equipe).SAP, tax ID, state registration, name (editable via modal), commercial name and employees (opens Manage staff).SAP, documento fiscal, inscripción estatal, nombre (editable por modal), nombre comercial y empleados (abre Gestionar equipo).
Endereço e classificaçãoAddress & classificationDirección y clasificación
Endereço (editável em página), classificação local, dias de funcionamento, categorias vendidas e subtipo de PDV.Address (editable in a page), local classification, operating days, categories sold and outlet subtype.Dirección (editable en página), clasificación local, días de operación, categorías vendidas y subtipo de PDV.
Comercial e rotaCommercial & routeComercial y ruta
Bandeira, key account, faixa de volume, classe de merchandising, frequências de pedido/visita, dia de visita, entrega (editável em página) e a solicitação de cadastro de rota.Banner, key account, volume range, merchandising class, order/visit frequencies, visit day, delivery (editable in a page) and the route registration request.Bandera, key account, rango de volumen, clase de merchandising, frecuencias de pedido/visita, día de visita, entrega (editable en página) y la solicitud de registro de ruta.
FinanceiroFinancialFinanciero
Lead time, limite de crédito, dias de crédito e formas de pagamento — somente leitura.Lead time, credit limit, credit days and payment methods — read-only.Lead time, límite de crédito, días de crédito y formas de pago — solo lectura.
04

Estados e disponibilidadeStates & availabilityEstados y disponibilidad

Varejos não tem um "status" como o pedido. O que muda de card para card é quais ações o backend permite e a condição do varejo:Retails has no "status" like an order. What varies card to card is which actions the backend allows and the retail's condition:Puntos de venta no tiene un "estado" como el pedido. Lo que cambia de tarjeta a tarjeta es qué acciones permite el backend y la condición del punto de venta:

Botão PlanejarPlan buttonBotón Planificar
Aparece só quando isPlannedVisitCreationAvailable é verdadeiro para aquele varejo.Shows only when isPlannedVisitCreationAvailable is true for that retail.Aparece solo cuando isPlannedVisitCreationAvailable es verdadero para ese punto de venta.
Botão Ad HocAd Hoc buttonBotón Ad Hoc
Aparece só quando isAdhocVisitCreationAvailable é verdadeiro; depois de criar, some (o cache marca o varejo). Durante a criação, mostra "Criando visita…".Shows only when isAdhocVisitCreationAvailable is true; after creating, it disappears (the cache flags the retail). While creating, it shows "Creating visit…".Aparece solo cuando isAdhocVisitCreationAvailable es verdadero; tras crear, desaparece (el caché marca el punto de venta). Durante la creación, muestra "Creando visita…".
InadimplênciaOverdueMora
No detalhe, o card do varejo mostra um selo quando isOverdue é verdadeiro.In the detail, the retail card shows a badge when isOverdue is true.En el detalle, la tarjeta muestra un sello cuando isOverdue es verdadero.
Editando / SalvandoEditing / SavingEditando / Guardando
Cada seção editável do detalhe entra em modo editando (rascunho) e, ao confirmar, em salvando até o envio terminar.Each editable detail section enters editing mode (draft) and, on confirm, saving until the submit finishes.Cada sección editable del detalle entra en modo editando (borrador) y, al confirmar, en guardando hasta terminar el envío.
05

Ações: visitas e ediçãoActions: visits & editingAcciones: visitas y edición

Criar visita (lista)Create visit (list)Crear visita (lista)

PlanejarPlanPlanificar
Abre um modal com um calendário. Escolhida a data futura, o app cria uma visita agendada (transação VisitUploadAPI) e confirma por um aviso verde.Opens a modal with a calendar. With a future date chosen, the app creates a scheduled visit (VisitUploadAPI transaction) and confirms with a green notice.Abre un modal con un calendario. Con la fecha futura elegida, la app crea una visita agendada (transacción VisitUploadAPI) y confirma con un aviso verde.
Ad HocAd HocAd Hoc
Abre um modal de confirmação; ao confirmar, cria uma visita imediata via RPC getAdhocVisit e baixa todo o pacote de dados do varejo. Detalhado na seção ◆ Visita Ad Hoc.Opens a confirmation modal; on confirm, creates an immediate visit via the getAdhocVisit RPC and downloads the retail's whole data package. Detailed in the ◆ Ad Hoc visit section.Abre un modal de confirmación; al confirmar, crea una visita inmediata vía el RPC getAdhocVisit y descarga todo el paquete de datos del punto de venta. Detallado en la sección ◆ Visita Ad Hoc.

Editar o cadastro (detalhe)Edit the profile (detail)Editar la ficha (detalle)

Cada campo editável tem um modo de edição definido pelo mercado: inline (edita na própria seção), modal (uma janela — ex.: nome) ou página (uma tela dedicada — endereço e entrega). A edição só é permitida com a visita iniciada (guarda de início de visita). Fluxo comum:Each editable field has an edit mode set by the market: inline (edits in the section itself), modal (a dialog — e.g. name) or page (a dedicated screen — address and delivery). Editing is only allowed with the visit started (a visit-start guard). Common flow:Cada campo editable tiene un modo de edición definido por el mercado: inline (edita en la propia sección), modal (una ventana — ej.: nombre) o página (una pantalla dedicada — dirección y entrega). La edición solo se permite con la visita iniciada (guarda de inicio de visita). Flujo común:

  1. Toque em editarTap editToque editarAbre o modal/página conforme o modo do campo, com os valores atuais.Opens the modal/page per the field's mode, prefilled with current values.Abre el modal/página según el modo del campo, con los valores actuales.
  2. Altere e confirmeChange and confirmCambie y confirmeO app envia primeiro ao backend (RetailerUploadAPI) e só então grava a alteração no cache local da visita.The app sends to the backend first (RetailerUploadAPI) and only then writes the change to the visit's local cache.La app envía primero al backend (RetailerUploadAPI) y solo entonces graba el cambio en el caché local de la visita.
  3. Solicitação de cadastro (rota)Registration request (route)Solicitud de registro (ruta)A tela de entrega envia uma solicitação de rota (com data de início) pela mesma transação, marcada como pedido de rota.The delivery screen submits a route request (with a start date) through the same transaction, flagged as a route request.La pantalla de entrega envía una solicitud de ruta (con fecha de inicio) por la misma transacción, marcada como pedido de ruta.
06

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

Clean Architecture + Riverpod + Freezed + gRPC + ObjectBox. São quatro fluxos distintos: a leitura da lista (um RPC próprio, write-through), a leitura do detalhe (só cache, a partir da visita), a escrita das edições (Dispatcher, remote-first) e a criação de visita ad hoc (RPC agregado + merge nos caches).Clean Architecture + Riverpod + Freezed + gRPC + ObjectBox. There are four distinct flows: the list read (its own RPC, write-through), the detail read (cache-only, from the visit), the edit writes (Dispatcher, remote-first) and the ad hoc visit creation (aggregate RPC + merge into caches).Clean Architecture + Riverpod + Freezed + gRPC + ObjectBox. Son cuatro flujos distintos: la lectura de la lista (un RPC propio, write-through), la lectura del detalle (solo caché, desde la visita), las escrituras de edición (Dispatcher, remote-first) y la creación de visita ad hoc (RPC agregado + merge en los cachés).

Leitura da lista · write-throughList read · write-throughLectura de la lista · write-through

Um único RPC (getRetails) traz os varejos da hierarquia; o dado atravessa Proto → DTO → Entity → Model → Entity, com cache write-through:A single RPC (getRetails) returns the hierarchy's retails; data crosses Proto → DTO → Entity → Model → Entity, with cache write-through:Un único RPC (getRetails) trae los puntos de venta de la jerarquía; el dato atraviesa Proto → DTO → Entity → Model → Entity, con cache write-through:

  • RetailsReplygRPC proto
    • toRetailsDTORetailsDTODTO · Freezed
      • toDomainRetailsEntitydomain
        • toModel / saveRetailsRetailsModelObjectBox
          • toDomainRetailsEntitydomain · cache
            • watchRetailsNotifier + State
              • → UIRetailsPage

Leitura do detalhe · só cache (via visita)Detail read · cache-only (via visit)Lectura del detalle · solo caché (vía visita)

O detalhe não usa a lista de Varejos nem o serviço getRetails. Ele lê a visita do cache pelo visitSfid e usa o AccountDataEntity que vive dentro dela (ver Detalhe da visita). Também busca config (EMC) e dados de referência para dirigir os campos:The detail does not use the Retails list nor the getRetails service. It reads the visit from cache by visitSfid and uses the AccountDataEntity living inside it (see Visit detail). It also fetches config (EMC) and reference data to drive the fields:El detalle no usa la lista de Puntos de venta ni el servicio getRetails. Lee la visita del caché por visitSfid y usa el AccountDataEntity que vive dentro (ver Detalle de visita). También busca config (EMC) y datos de referencia para dirigir los campos:

  • VisitModelObjectBox · cache
    • getCachedBySfidGetVisitsUseCasevisit.accountData
      • + EMC + ReferenceDataRetailDetailNotifier._load
        • buildRetailDetailStateaccount + draftAccount + config
          • → UIRetailDetailPage

Escrita das edições · Dispatcher (remote-first)Edit writes · Dispatcher (remote-first)Escrituras de edición · Dispatcher (remote-first)

Toda edição de campo despacha um envelope RetailerUploadAPI pelo Dispatcher e só grava no cache da visita depois do sucesso (§36):Every field edit dispatches a RetailerUploadAPI envelope through the Dispatcher and only writes to the visit cache after success (§36):Toda edición de campo despacha un sobre RetailerUploadAPI por el Dispatcher y solo graba en el caché de la visita tras el éxito (§36):

  • RetailDetail widget / edit pageUI
    • save*()RetailDetailNotifier
      • build(input)BuildRetailerUploadDispatcherPayloadUseCase→ DispatcherEnvelope
        • submit → dispatchSubmitRetailerUploadUseCaseDispatcherOrchestrator
          • on Ack successSaveAccountUpdateUseCase→ visit cache

Criação de visita ad hoc · RPC agregado + mergeAd hoc visit creation · aggregate RPC + mergeCreación de visita ad hoc · RPC agregado + merge

O botão Ad Hoc chama getAdhocVisit (que cria a visita no Salesforce e devolve todo o pacote de dados do varejo) e faz merge aditivo em 12 caches locais. Detalhado em ◆ Visita Ad Hoc:The Ad Hoc button calls getAdhocVisit (which creates the visit in Salesforce and returns the retail's whole data package) and does an additive merge into 12 local caches. Detailed in ◆ Ad Hoc visit:El botón Ad Hoc llama getAdhocVisit (que crea la visita en Salesforce y devuelve todo el paquete de datos del punto de venta) y hace un merge aditivo en 12 cachés locales. Detallado en ◆ Visita Ad Hoc:

  • _AdhocBadgeUI · retail card
    • create()AdhocVisitCreationprovider · keepAlive
      • executeCreateAdhocVisitUseCase
        • getAdhocVisitAdhocVisitRepositoryImpl→ AdhocVisitResultEntity
          • merge (12 caches)AdhocVisitMergeCoordinator
            • markAdhocVisitCreated · invalidateConectaNotice + Retails/Visits
07

Modelo de dadosData modelModelo de datos

São dois modelos independentes. (1) O da lista: um Retail enxuto (7 campos), próprio do serviço de Varejos, que existe em quatro representações Proto → DTO → Model → Entity ligadas por mappers, com cache write-through. (2) O do detalhe: o AccountDataEntity, que pertence ao agregado da Visita — o detalhe apenas o lê do cache e o edita; seu mapeamento cross-camada completo está em Detalhe da visita.There are two independent models. (1) The list one: a lean Retail (7 fields), owned by the Retails service, existing in four representations Proto → DTO → Model → Entity linked by mappers, with cache write-through. (2) The detail one: AccountDataEntity, which belongs to the Visit aggregate — the detail only reads it from cache and edits it; its full cross-layer mapping lives in Visit detail.Son dos modelos independientes. (1) El de la lista: un Retail liviano (7 campos), propio del servicio de Puntos de venta, que existe en cuatro representaciones Proto → DTO → Model → Entity unidas por mappers, con cache write-through. (2) El del detalle: el AccountDataEntity, que pertenece al agregado de la Visita — el detalle solo lo lee del caché y lo edita; su mapeo cross-capa completo está en Detalle de visita.

A lista chega num container RetailsEntity (lastSyncAt gerado no mapper + retails[]); cada item é um Retail de 7 campos, sem sub-estruturas. O modelo é plano e sem deltas de tipo — todos os campos são String/bool. A escrita (edição/adhoc/visita) não tem modelo próprio: a edição envia via RetailerUpload e o ad hoc devolve um agregado de 11 estruturas com 16 listas (ver ◆ Visita Ad Hoc).The list arrives in a RetailsEntity container (lastSyncAt generated in the mapper + retails[]); each item is a 7-field Retail, no sub-structures. The model is flat and delta-free — every field is String/bool. Writes (edit/adhoc/visit) have no model of their own: the edit submits via RetailerUpload and ad hoc returns an 11-structure aggregate with 16 lists (see ◆ Ad Hoc visit).La lista llega en un container RetailsEntity (lastSyncAt generado en el mapper + retails[]); cada ítem es un Retail de 7 campos, sin sub-estructuras. El modelo es plano y sin deltas de tipo — todos los campos son String/bool. Las escrituras (edición/adhoc/visita) no tienen modelo propio: la edición envía vía RetailerUpload y el ad hoc devuelve un agregado de 11 estructuras con 16 listas (ver ◆ Visita Ad Hoc).

Proto

RetailsConectaRep.proto · proto3 · package mn.bat.conectarep.streambridge. A lista usa o RetailsConectaRepService (um método unário). O detalhe não chama RPC (lê do cache da visita); o ad hoc usa um serviço próprio (AdhocVisitConectaRepService):The list uses RetailsConectaRepService (a single unary method). The detail calls no RPC (reads the visit cache); ad hoc uses its own service (AdhocVisitConectaRepService):La lista usa RetailsConectaRepService (un método unario). El detalle no llama RPC (lee del caché de la visita); el ad hoc usa un servicio propio (AdhocVisitConectaRepService):

getRetailsunary
MétodoMethodMétodo

rpc getRetails(RetailsRequest) returns (RetailsReply)

path /mn.bat.conectarep.streambridge.RetailsConectaRepService/getRetails

Request · RetailsRequest
locationHierarchySfid
string · #1 · hierarquia do representante de vendas (resolvida no repository via currentResourceProvider)sales rep hierarchy (resolved in the repository via currentResourceProvider)jerarquía del representante de ventas (resuelta en el repository vía currentResourceProvider)
dateReference
string · #2 · optional
lastModifiedDate
string · #3 · optional (não usado hoje)optional (not used today)optional (no usado hoy)
Reply · RetailsReply

repeated Retail retails (#1) — a lista de varejos. Os campos page/pageSize/totalItems (#2–#4) não são mapeados (paginação server-side não usada). Os 7 campos de Retail estão nas Estruturas de dados abaixo.— the list of retails. The page/pageSize/totalItems fields (#2–#4) are not mapped (server-side pagination unused). Retail's 7 fields are in Data structures below.— la lista de puntos de venta. Los campos page/pageSize/totalItems (#2–#4) no se mapean (paginación server-side no usada). Los 7 campos de Retail están en Estructuras de datos abajo.

getAdhocVisitunary · agregadounary · aggregateunary · agregado
MétodoMethodMétodo

rpc getAdhocVisit(AdhocVisitRequest) returns (AdhocVisitReply)

AdhocVisitConectaRep.proto · path /mn.bat.conectarep.streambridge.AdhocVisitConectaRepService/getAdhocVisit

Request · AdhocVisitRequest
username
string · #1 · do currentResourcefrom currentResourcedel currentResource
accountSfid
string · #2 · o varejo escolhidothe chosen retailel punto de venta elegido
repSfid
string · #3 · resource.sfid
geoLatitude / geoLongitude
double · #4/#5 · optional · LocationService.currentPositionLocationService.currentPositionLocationService.currentPosition
Reply · AdhocVisitReply

Diferente dos outros serviços, parte de username + accountSfid (não de locationHierarchySfid) e devolve 11 estruturas agregadas (visitas, tasks, surveys, stockControl, promoções, spots, pedidos, merchandising, marginCalculator, financeiro, catálogo). Detalhado em ◆ Visita Ad Hoc.Unlike other services it starts from username + accountSfid (not locationHierarchySfid) and returns 11 aggregated structures (visits, tasks, surveys, stockControl, promotions, spots, orders, merchandising, marginCalculator, financial, catalog). Detailed in ◆ Ad Hoc visit.A diferencia de otros servicios parte de username + accountSfid (no locationHierarchySfid) y devuelve 11 estructuras agregadas (visitas, tasks, surveys, stockControl, promociones, spots, pedidos, merchandising, marginCalculator, financiero, catálogo). Detallado en ◆ Visita Ad Hoc.

Estruturas de dadosData structuresEstructuras de datos

O modelo da lista tem só o Retail — uma coluna por camada (Proto · DTO · Model · Entity). O modelo do detalhe (AccountData) pertence à Visita; abaixo está a sua superfície editável (campos que o detalhe lê/edita) — o cross-camada completo é da Visita.The list model has only Retail — one column per layer (Proto · DTO · Model · Entity). The detail model (AccountData) belongs to the Visit; below is its editable surface (fields the detail reads/edits) — the full cross-layer is the Visit's.El modelo de la lista tiene solo Retail — una columna por capa (Proto · DTO · Model · Entity). El modelo del detalle (AccountData) pertenece a la Visita; abajo está su superficie editable (campos que el detalle lee/edita) — el cross-capa completo es de la Visita.

  • Retail raiz · listaroot · listraíz · lista 7 campos7 fields7 campos
    CampoProtoDTOModelEntity
    accountSfidstringStringStringString
    accountNamestringStringStringString
    accountSapCustomerIdstringStringStringString
    addressstringStringStringString
    isAdhocVisitCreationAvailableboolboolboolbool
    isPlannedVisitCreationAvailableboolboolboolbool
    taxIdstring¹String?String?String?
  • AccountData detalhe · da Visitadetail · from Visitdetalle · de la Visita superfície editáveleditable surfacesuperficie editable
    Campo (Entity)TipoEditável?Editable?¿Editable?
    sfid / customerCodeString
    nameStringmodal
    commercialNameString?
    taxCode / stateRegistrationString?
    addressAddressEntity?page
    operatingDaysList<String>inline
    openingTime / closingTimeString?inline
    categoriesSoldList<CategoryForSale>inline
    outletSubtypeSfidNamePairEntity?inline
    localClassificationLocalClassificationEntity?inline
    routeInfoRouteInfoEntity?page
    bannerName / keyAccountType / volumeRange / merchandisingClassString?
    creditLimit / baseCreditLimit / overdueAmountdouble?
    creditDays / totalStaffint?
    paymentMethodsList<String>
    supplierDataSupplierDataEntity?
    staffStaffEntitytela própriaown screenpantalla propia
    status / isOverdue / isBlockedToSales / isB2B / hasCompetitionString / bool?
    • AddressEntity AccountData.address 7 campos7 fields7 campos
      CampoTipo
      fullAddress / street / streetComplement / neighborhood / postalCodeString?
      city / stateSfidNamePairEntity?
    • RouteInfoEntity AccountData.routeInfo visit · order · delivery
      CampoTipo
      visit (RouteVisitEntity)sfid? · frequency? · day?
      order (RouteOrderEntity)sfid? · frequency?
      delivery (RouteDeliveryEntity)preferredDay? · isFlexible?

Mappers

Do modelo da lista (RetailMapper / RetailsMapper), 5 direções por extension:For the list model (RetailMapper / RetailsMapper), 5 directions via extension:Del modelo de la lista (RetailMapper / RetailsMapper), 5 direcciones por extension:

DireçãoDirectionDirecciónMétodoMethodMétodo
JSON → DTOstatic fromMap(Map) (container gera lastSyncAt com DateTimeUtils.now())(container generates lastSyncAt with DateTimeUtils.now())(el container genera lastSyncAt con DateTimeUtils.now())
Proto → DTOtoDTO() / toRetailsDTO() (taxId vazio → null; lastSyncAt = now)(empty taxIdnull; lastSyncAt = now)(taxId vacío → null; lastSyncAt = now)
DTO → EntitytoDomain()
Entity → ModeltoModel() (popula ToMany<RetailModel>)(fills ToMany<RetailModel>)(llena ToMany<RetailModel>)
Model → EntitytoDomain()

Os únicos deltasThe only deltasLos únicos deltas

  • Retail não tem delta de tipo — os 7 campos são idênticos em Proto/DTO/Model/Entity (String/bool)Retail has no type delta — the 7 fields are identical across Proto/DTO/Model/Entity (String/bool)Retail no tiene delta de tipo — los 7 campos son idénticos en Proto/DTO/Model/Entity (String/bool)
  • taxId string vazio no proto → null no DTO em diante (optional, ¹)empty proto stringnull from the DTO on (optional, ¹)string vacío en el proto → null del DTO en adelante (optional, ¹)
  • RetailsReply.page / pageSize / totalItems descartados (não mapeados)dropped (not mapped)descartados (no mapeados)
  • lastSyncAt gerado no mapper com DateTimeUtils.now() (o proto não envia)generated in the mapper with DateTimeUtils.now() (the proto doesn't send it)generado en el mapper con DateTimeUtils.now() (el proto no lo envía)
  • AccountData.categoriesSold enum CategoryForSale tipado só na Entity (mapeamento na Visita)enum CategoryForSale typed only in the Entity (mapping in the Visit)enum CategoryForSale tipado solo en la Entity (mapeo en la Visita)
08

Repository

Três repositórios entram em jogo: RetailRepository (a lista), RetailUpdateRepository (grava a edição no cache da visita) e AdhocVisitRepository (o RPC agregado + merge). Um dropdown por método — assinatura, retorno e comportamento.Three repositories are involved: RetailRepository (the list), RetailUpdateRepository (writes the edit to the visit cache) and AdhocVisitRepository (the aggregate RPC + merge). One dropdown per method — signature, return and behavior.Tres repositorios intervienen: RetailRepository (la lista), RetailUpdateRepository (graba la edición en el caché de la visita) y AdhocVisitRepository (el RPC agregado + merge). Un dropdown por método — firma, retorno y comportamiento.

RetailRepositoryImpl

getRetails({source}) mock / local / remote

RetornaReturnsDevuelve Result<RetailsEntity, Failure>

Árvore de decisão de fonteSource decision treeÁrbol de decisión de fuente

  1. useMock == true ouoro source == mock_fetchFromMock(): lê o mock por mercado, mapeia, grava no cache._fetchFromMock(): reads the per-market mock, maps, writes to cache._fetchFromMock(): lee el mock por mercado, mapea, graba en caché.
  2. source == local ou offlineor offlineu offline_fetchFromCacheOrFail(): cache; vazio → NetworkFailure._fetchFromCacheOrFail(): cache; empty → NetworkFailure._fetchFromCacheOrFail(): caché; vacío → NetworkFailure.
  3. senão (remoto + conectado)otherwise (remote + connected)si no (remoto + conectado)_fetchFromRemoteWithFallback(): lê currentResourceProvider; null → cache; senão chama o remoto com locationHierarchyId, mapeia, grava; em erro, fallback pro cache._fetchFromRemoteWithFallback(): reads currentResourceProvider; null → cache; else calls remote with locationHierarchyId, maps, writes; on error, falls back to cache._fetchFromRemoteWithFallback(): lee currentResourceProvider; null → caché; si no llama al remoto con locationHierarchyId, mapea, graba; en error, fallback al caché.
getCachedRetails() local

RetornaReturnsDevuelve Result<RetailsEntity?, Failure>

Só cache; null vira Success(null).Cache only; null becomes Success(null).Solo caché; null es Success(null).

getCachedRetailsLastSyncAt() local

RetornaReturnsDevuelve DateTime?

Timestamp da última sync do container, para o DataLoadInfo.The container's last-sync timestamp, for DataLoadInfo.Timestamp de última sincronización del container, para DataLoadInfo.

saveRetails({entity}) local

RetornaReturnsDevuelve Result<void, Failure>

Destrutivo: clearRetails() + regrava (boxes filhas em cascata). Cache-writer após cada fetch.Destructive: clearRetails() + rewrites (child boxes cascade). Cache-writer after each fetch.Destructivo: clearRetails() + regraba (boxes hijas en cascada). Cache-writer tras cada fetch.

markAdhocVisitCreated({accountSfid}) local

RetornaReturnsDevuelve Result<void, Failure>

Vira isAdhocVisitCreationAvailable = false naquele varejo no cache (esconde o botão Ad Hoc). Chamado após criar a visita ad hoc.Flips isAdhocVisitCreationAvailable = false for that retail in cache (hides the Ad Hoc button). Called after creating the ad hoc visit.Cambia isAdhocVisitCreationAvailable = false para ese punto de venta en caché (oculta el botón Ad Hoc). Llamado tras crear la visita ad hoc.

RetailUpdateRepositoryImpl

Persistência local apenas — grava a alteração dentro da visita no cache (delegando ao VisitLocalDataSource). É o passo "grava no local após o sucesso do remoto" do padrão remote-first (§36); o envio remoto é feito antes, no Notifier, via RetailerUpload.Local persistence only — writes the change inside the visit in cache (delegating to VisitLocalDataSource). It's the "write local after remote success" step of the remote-first pattern (§36); the remote submit happens first, in the Notifier, via RetailerUpload.Persistencia local solamente — graba el cambio dentro de la visita en caché (delegando al VisitLocalDataSource). Es el paso "grabar local tras el éxito remoto" del patrón remote-first (§36); el envío remoto ocurre antes, en el Notifier, vía RetailerUpload.

saveAccountUpdate({visitSfid, newAccount})
RetornoReturnRetorno
Result<AccountDataEntity, Failure>
ComportamentoBehaviorComportamiento
updateAccountInVisit no cache da visita e devolve o novo account.updateAccountInVisit in the visit cache and returns the new account.updateAccountInVisit en el caché de la visita y devuelve el nuevo account.
saveContactUpdate / removeContact / saveClerkUpdate staff

Upsert/remoção de contatos e clerks dentro da visita — usados pela feature de equipe (Gerenciar equipe), acessível pelo detalhe. Retornam Result<ContactEntity> / Result<void> / Result<ClerkEntity>.Upsert/removal of contacts and clerks inside the visit — used by the staff feature (Manage staff), reachable from the detail. Return Result<ContactEntity> / Result<void> / Result<ClerkEntity>.Upsert/eliminación de contactos y clerks dentro de la visita — usados por la feature de equipo (Gestionar equipo), accesible desde el detalle. Devuelven Result<ContactEntity> / Result<void> / Result<ClerkEntity>.

AdhocVisitRepositoryImpl

createAdhocVisit({accountSfid, geoLatitude?, geoLongitude?}) remote + merge

RetornaReturnsDevuelve Result<AdhocVisitResultEntity, Failure>

currentResource (nullUnknownFailure); chama getAdhocVisit (mock devolve vazio — online-only); se o reply não traz visita, retorna BusinessFailure; senão chama _mergeCoordinator.merge e devolve o agregado. Detalhado em ◆ Visita Ad Hoc.Reads currentResource (nullUnknownFailure); calls getAdhocVisit (mock returns empty — online-only); if the reply has no visit, returns BusinessFailure; else calls _mergeCoordinator.merge and returns the aggregate. Detailed in ◆ Ad Hoc visit.Lee currentResource (nullUnknownFailure); llama getAdhocVisit (mock devuelve vacío — online-only); si el reply no trae visita, devuelve BusinessFailure; si no llama _mergeCoordinator.merge y devuelve el agregado. Detallado en ◆ Visita Ad Hoc.

09

Datasources

Um card por datasource (dropdown). No corpo: método, envio, retorno, fluxo de uso e tratamento de erro.One card per datasource (dropdown). In the body: method, what it sends, return, usage flow and error handling.Un card por datasource (dropdown). En el cuerpo: método, envío, retorno, flujo de uso y manejo de errores.

Remote RetailRemoteDataSource gRPC
getRetails({locationHierarchySfid, dateReference?})
EnvioSendsEnvío
monta RetailsRequest e chama _client.getRetails(request) (RetailsConectaRepServiceClient).builds RetailsRequest and calls _client.getRetails(request) (RetailsConectaRepServiceClient).arma RetailsRequest y llama _client.getRetails(request) (RetailsConectaRepServiceClient).
RetornoReturnRetorno
RetailsDTO (via response.toRetailsDTO())(via response.toRetailsDTO())(vía response.toRetailsDTO())
Fluxo de usoUsage flowFlujo de uso
caminho remoto do repository; o resultado é gravado no cache.the repository's remote path; result is written to cache.camino remoto del repository; el resultado se graba en caché.
Tratamento de erroError handlingManejo de errores
GrpcErrorGrpcExceptionHandler; outros → ServerException. Repository faz fallback pro cache.GrpcErrorGrpcExceptionHandler; others → ServerException. Repository falls back to cache.GrpcErrorGrpcExceptionHandler; otros → ServerException. Repository hace fallback al caché.
Local RetailLocalDataSource ObjectBox

Envio / fluxo: persistência via ObjectBox, boxes RetailsModel e RetailModel — sem rede. Erro: falhas propagam como CacheException.Sends / flow: ObjectBox persistence, RetailsModel and RetailModel boxes — no network. Error: failures propagate as CacheException.Envío / flujo: persistencia vía ObjectBox, boxes RetailsModel y RetailModel — sin red. Error: fallos propagan como CacheException.

getRetails()
RetornoReturnRetorno
RetailsEntity?models.first.toDomain()
getRetailsLastSyncAt()
RetornoReturnRetorno
DateTime?models.first.lastSyncAt
saveRetails({entity})
ComportamentoBehaviorComportamiento
destrutivo: clearRetails() + _box.put(entity.toModel()).destructive: clearRetails() + _box.put(entity.toModel()).destructivo: clearRetails() + _box.put(entity.toModel()).
markAdhocVisitCreated({accountSfid})
ComportamentoBehaviorComportamiento
read-modify-write: copyWith(isAdhocVisitCreationAvailable:false) no varejo do accountSfid.read-modify-write: copyWith(isAdhocVisitCreationAvailable:false) on the accountSfid retail.read-modify-write: copyWith(isAdhocVisitCreationAvailable:false) en el punto de venta del accountSfid.
clearRetails()
ComportamentoBehaviorComportamiento
limpa RetailModel e RetailsModel (filhas→raiz).clears RetailModel and RetailsModel (children→root).limpia RetailModel y RetailsModel (hijas→raíz).
Mock RetailMockDataSource JSON
getRetails()
EnvioSendsEnvío
carrega o asset retails/retails por mercado (real vs sintético via useRealMockData) — sem rede.loads the retails/retails asset per market (real vs synthetic via useRealMockData) — no network.carga el asset retails/retails por mercado (real vs sintético vía useRealMockData) — sin red.
RetornoReturnRetorno
RetailsDTO (via RetailsDTOJsonMapper.fromMap)(via RetailsDTOJsonMapper.fromMap)(vía RetailsDTOJsonMapper.fromMap)
Remote AdhocVisitRemoteDataSource gRPC
getAdhocVisit({username, accountSfid, repSfid, geoLatitude?, geoLongitude?})
EnvioSendsEnvío
monta AdhocVisitRequest e chama _client.getAdhocVisit(request).builds AdhocVisitRequest and calls _client.getAdhocVisit(request).arma AdhocVisitRequest y llama _client.getAdhocVisit(request).
RetornoReturnRetorno
AdhocVisitResultDTO (via response.toDTO())(via response.toDTO())(vía response.toDTO())
Tratamento de erroError handlingManejo de errores
GrpcErrorGrpcExceptionHandler; outros → ServerException.GrpcErrorGrpcExceptionHandler; others → ServerException.GrpcErrorGrpcExceptionHandler; otros → ServerException.
Mock AdhocVisitMockDataSource vazio · online-onlyempty · online-onlyvacío · online-only

Retorna um AdhocVisitResultDTO vazio por decisão do usuário — o ad hoc é validado só online contra o streambridge real.Returns an empty AdhocVisitResultDTO by decision — ad hoc is validated online-only against the real streambridge.Devuelve un AdhocVisitResultDTO vacío por decisión — el ad hoc se valida solo online contra el streambridge real.

Local RetailUpdateLocalDataSource delega à Visitadelegates to Visitdelega a la Visita

Fino wrapper sobre o VisitLocalDataSource: updateAccountInVisit, upsertContactInVisit, removeContactFromVisit, upsertClerkInVisit. Não tem box própria — o cadastro do varejo mora na box da Visita.Thin wrapper over VisitLocalDataSource: updateAccountInVisit, upsertContactInVisit, removeContactFromVisit, upsertClerkInVisit. No box of its own — the retail profile lives in the Visit box.Wrapper fino sobre VisitLocalDataSource: updateAccountInVisit, upsertContactInVisit, removeContactFromVisit, upsertClerkInVisit. Sin box propia — la ficha del punto de venta vive en la box de la Visita.

10

Enums e labelsEnums & labelsEnums y labels

Os enums da feature. Retail não tem enum (7 campos String/bool); os enums abaixo governam a edição do detalhe, a config por mercado e o ad hoc.The feature's enums. Retail has none (7 String/bool fields); the enums below govern detail editing, per-market config and ad hoc.Los enums de la feature. Retail no tiene enum (7 campos String/bool); los enums abajo gobiernan la edición del detalle, la config por mercado y el ad hoc.

RetailDetailSection 7
caseo que editawhat it editsqué edita
accountNamenome (modal)name (modal)nombre (modal)
outletSubtypesubtipo de PDVoutlet subtypesubtipo de PDV
localClassificationclassificação locallocal classificationclasificación local
operatingDaysdias + horáriosdays + hoursdías + horarios
categoriesSoldcategorias vendidascategories soldcategorías vendidas
addressendereço (página)address (page)dirección (página)
registrationRequestrota/entrega (página, isRouteRequest)route/delivery (page, isRouteRequest)ruta/entrega (página, isRouteRequest)
EditMode 4 · value
casevaluenotanotenota
none"none"não editávelnot editableno editable
inline"inline"edita na própria seçãoedits in the sectionedita en la sección
modal"modal"janela (ex.: nome)dialog (e.g. name)ventana (ej.: nombre)
page"page"tela dedicada (endereço/entrega)dedicated screen (address/delivery)pantalla dedicada (dirección/entrega)
RetailerUploadModule 3 · value
casevalue
accountSnapshot"accountSnapshot"
address"address"
localClassification"localClassification"
GeoCallFrequency 4 · wire · i18n
casewireValuemultiplieri18n key
weekly"0001"1frequencyWeekly
biweekly"0002"2frequencyBiweekly
monthly"0004"4frequencyMonthly
bimonthly"0008"8frequencyBimonthly
CategoryForSale 17 · wire · label
casewireValuelabel
fmc"fmc"FMC
thpDevices"thp_devices"THP Devices
thpSticks"thp_sticks"THP Sticks
vapourDevices"vapour_devices"Vapour Devices
vapourLiquids"vapour_liquids"Vapour Liquids
oral"oral"Oral
ryo"ryo"RYO
myo"myo"MYO
otp"otp"OTP
otpAccessories"otp_accessories"OTP Accessories
otherEa"other_ea"Other EA
otherUnit"other_unit"Other UNIT
otherPce"other_pce"Other PCE
vuse"vuse"VUSE
partnership"partnership"Partnership
nc"nc"NC
unknown""
WeekDay 7 · wire
casewire
monday"Monday"
tuesday"Tuesday"
wednesday"Wednesday"
thursday"Thursday"
friday"Friday"
saturday"Saturday"
sunday"Sunday"
AdhocVisitCreationPhase 4
case
idle
creating
completed
failed
ModuleType (retail_*) 24 · seções do detalhe24 · detail sections24 · secciones del detalle
casevalue
retailSapCode"retail_sap_code"
retailAccountName"retail_account_name"
retailCommercialName"retail_commercial_name"
retailEmployees"retail_employees"
retailAddress"retail_address"
retailLocalClassification"retail_local_classification"
retailOperatingDays"retail_operating_days"
retailCategoriesSold"retail_categories_sold"
retailOutletSubtype"retail_outlet_subtype"
retailBanner"retail_banner"
retailOrderFrequency"retail_order_frequency"
retailSellerVisitFrequency"retail_seller_visit_frequency"
retailLeadTime"retail_lead_time"
retailCreditLimit"retail_credit_limit"
retailCreditLimitDays"retail_credit_limit_days"
retailPaymentMethod"retail_payment_method"
retailTaxId"retail_tax_id"
retailStateRegistration"retail_state_registration"
retailKeyAccount"retail_key_account"
retailVolumeRange"retail_volume_range"
retailMerchandising"retail_merchandising"
retailVisitDay"retail_visit_day"
retailPreferredDeliveryDay"retail_preferred_delivery_day"
retailStartDate"retail_start_date"
11

UseCases

Um dropdown por UseCase; dentro, cada método com assinatura, o que retorna e uso. Os da lista/ad hoc delegam ao repository; os de dispatcher (Build*/Submit*) montam e despacham o envelope.One dropdown per UseCase; inside, each method with its signature, return and use. List/ad hoc ones delegate to the repository; the dispatcher ones (Build*/Submit*) assemble and dispatch the envelope.Un dropdown por UseCase; dentro, cada método con su firma, qué devuelve y uso. Los de lista/ad hoc delegan al repository; los de dispatcher (Build*/Submit*) arman y despachan el sobre.

GetRetailsUseCase 3 · a listathe listla lista
MétodoMethodMétodoRetornaReturnsDevuelveUsoUseUso
execute({source})Result<RetailsEntity, Failure>Ponto de entrada da lista → repository.getRetails.List entry point → repository.getRetails.Punto de entrada de la lista → repository.getRetails.
getCached()Result<RetailsEntity?, Failure>Só cache; nullSuccess(null).Cache only; nullSuccess(null).Solo caché; nullSuccess(null).
getCachedLastSyncAt()DateTime?Timestamp para o DataLoadInfo.Timestamp for DataLoadInfo.Timestamp para DataLoadInfo.
SaveAccountUpdateUseCase 1
MétodoMethodMétodoRetornaReturnsDevuelveUsoUseUso
execute({visitSfid, newAccount})Result<AccountDataEntity, Failure>Grava a edição no cache da visita (passo local pós-sucesso remoto).Writes the edit to the visit cache (local step after remote success).Graba la edición en el caché de la visita (paso local tras éxito remoto).
BuildRetailerUploadDispatcherPayloadUseCase 1 · dispatcher1 · dispatcher1 · dispatcher
MétodoMethodMétodoRetornaReturnsDevuelveUsoUseUso
build({input: RetailerUploadDispatcherPayloadInput})DispatcherEnvelopeMonta o envelope RetailerUploadAPI a partir do account atual + novo, config e geo. Payload em 4 colunas: 06 · RetailerUploadAPI.Assembles the RetailerUploadAPI envelope from current + new account, config and geo. 4-column payload: 06 · RetailerUploadAPI.Arma el sobre RetailerUploadAPI desde el account actual + nuevo, config y geo. Payload en 4 columnas: 06 · RetailerUploadAPI.
SubmitRetailerUploadUseCase 1 · submit
MétodoMethodMétodoRetornaReturnsDevuelveUsoUseUso
submit({envelope})Result<DispatcherAck, Failure>Despacha via DispatcherOrchestrator.Dispatches via DispatcherOrchestrator.Despacha vía DispatcherOrchestrator.
CreateAdhocVisitUseCase 1
MétodoMethodMétodoRetornaReturnsDevuelveUsoUseUso
execute({accountSfid, geoLatitude?, geoLongitude?})Result<AdhocVisitResultEntity, Failure>repository.createAdhocVisit (RPC + merge). Ver ◆ Visita Ad Hoc.repository.createAdhocVisit (RPC + merge). See ◆ Ad Hoc visit.repository.createAdhocVisit (RPC + merge). Ver ◆ Visita Ad Hoc.
BuildVisitUploadDispatcherPayloadUseCase · SubmitVisitUploadUseCase visita planejadaplanned visitvisita planificada
MétodoMethodMétodoRetornaReturnsDevuelveUsoUseUso
build({input: VisitUploadDispatcherPayloadInput})DispatcherEnvelopeMonta o envelope VisitUploadAPI (status scheduled) para a visita planejada criada na lista.Assembles the VisitUploadAPI envelope (scheduled status) for the planned visit created in the list.Arma el sobre VisitUploadAPI (estado scheduled) para la visita planificada creada en la lista.
submit({envelope})Result<DispatcherAck, Failure>Despacha via orchestrator.Dispatches via orchestrator.Despacha vía orchestrator.
GetVisitsUseCase · GetEndMarketConfigurationUseCase · GetReferenceDataUseCase consumidos pelo detalheused by the detailusados por el detalle
UseCaseMétodo usadoMethod usedMétodo usadoPapelRoleRol
GetVisitsUseCasegetCachedBySfid · getCached · execute(remote)a visita (fonte do account) + lastSyncAt; execute(remote) no refresh.the visit (account source) + lastSyncAt; execute(remote) on refresh.la visita (fuente del account) + lastSyncAt; execute(remote) en el refresh.
GetEndMarketConfigurationUseCaseexecuteaccountEditionConfig (visibilidade/edição por campo) + retailerUploadConfig.accountEditionConfig (per-field visibility/editing) + retailerUploadConfig.accountEditionConfig (visibilidad/edición por campo) + retailerUploadConfig.
GetReferenceDataUseCaseexecutecategorias, classificações locais, subtipos e hierarquia geográfica (para os dropdowns de edição).categories, local classifications, subtypes and geo hierarchy (for the edit dropdowns).categorías, clasificaciones locales, subtipos y jerarquía geográfica (para los dropdowns de edición).
12

Notifier & State

Três peças de estado: o RetailsNotifier (lista), o RetailDetailNotifier (detalhe, family por visitSfid) e o AdhocVisitCreation — este é um Provider cross-page (§33), não um Notifier de tela: keepAlive, family por accountSfid, para o progresso da criação sobreviver à navegação.Three state pieces: RetailsNotifier (list), RetailDetailNotifier (detail, family by visitSfid) and AdhocVisitCreation — the latter is a cross-page Provider (§33), not a screen Notifier: keepAlive, family by accountSfid, so creation progress survives navigation.Tres piezas de estado: RetailsNotifier (lista), RetailDetailNotifier (detalle, family por visitSfid) y AdhocVisitCreation — este es un Provider cross-page (§33), no un Notifier de pantalla: keepAlive, family por accountSfid, para que el progreso de creación sobreviva a la navegación.

Métodos — RetailsNotifierMethods — RetailsNotifierMétodos — RetailsNotifier

build() / _load({source = local}) private

Return Future<RetailsState>

Observa os UseCases e retorna _load(), que busca a lista (default cache) e monta retails + lastSyncAt.Watches the UseCases and returns _load(), which fetches the list (default cache) and assembles retails + lastSyncAt.Observa los UseCases y retorna _load(), que busca la lista (default caché) y arma retails + lastSyncAt.

refresh({source = remote}) pull-to-refresh

Return Future<void>

Recarrega via _load(remote) e preserva a searchQuery. Sem AsyncValue.loading.Reloads via _load(remote) and preserves searchQuery. No AsyncValue.loading.Recarga vía _load(remote) y preserva searchQuery. Sin AsyncValue.loading.

setSearchQuery({query})

Atualiza a busca e reseta visibleCount para 20.Updates the search and resets visibleCount to 20.Actualiza la búsqueda y resetea visibleCount a 20.

loadMore()

Incrementa visibleCount em 20 (paginação só visual).Increments visibleCount by 20 (visual-only pagination).Incrementa visibleCount en 20 (paginación solo visual).

createPlannedVisit({retail, plannedDate})

Return Future<Result<void, Failure>>

Monta o input, chama Build/SubmitVisitUpload (status scheduled) e devolve o resultado do Ack (a page mostra o aviso).Assembles the input, calls Build/SubmitVisitUpload (scheduled status) and returns the Ack result (the page shows the notice).Arma el input, llama Build/SubmitVisitUpload (estado scheduled) y devuelve el resultado del Ack (la page muestra el aviso).

State — RetailsStateState — RetailsStateState — RetailsState

RetailsState campos + gettersfields + getterscampos + getters
campotipodefault
retailsList<RetailEntity>[]
lastSyncAtDateTime?null
searchQueryString""
visibleCountint20 (kRetailsPageSize)

Getters: filteredRetails (busca por nome/SAP/endereço), visibleRetails (recorte), totalFilteredRetails, hasMoreToLoad. Filtragem/paginação client-side.Getters: filteredRetails (search by name/SAP/address), visibleRetails (slice), totalFilteredRetails, hasMoreToLoad. Filtering/pagination client-side.Getters: filteredRetails (búsqueda por nombre/SAP/dirección), visibleRetails (recorte), totalFilteredRetails, hasMoreToLoad. Filtrado/paginación client-side.

Métodos — RetailDetailNotifierMethods — RetailDetailNotifierMétodos — RetailDetailNotifier

build({visitSfid}) / _load()

Busca em paralelo EMC + reference data + a visita (getCachedBySfid) + o container (lastSyncAt); monta o State com account=draftAccount=visit.accountData, os catálogos e os módulos visíveis.Fetches in parallel EMC + reference data + the visit (getCachedBySfid) + the container (lastSyncAt); builds the State with account=draftAccount=visit.accountData, the catalogs and the visible modules.Busca en paralelo EMC + reference data + la visita (getCachedBySfid) + el container (lastSyncAt); arma el State con account=draftAccount=visit.accountData, los catálogos y los módulos visibles.

refresh() pull-to-refresh

Faz getVisits(remote), recarrega via _load() e preserva editingSections/savingSections.Runs getVisits(remote), reloads via _load() and preserves editingSections/savingSections.Ejecuta getVisits(remote), recarga vía _load() y preserva editingSections/savingSections.

toggleEditMode({section}) · updateDraft({newDraft})

Liga/desliga o modo edição da seção (resetando o rascunho ao account) e atualiza o draftAccount conforme o usuário edita.Toggles the section's edit mode (resetting draft to account) and updates draftAccount as the user edits.Alterna el modo edición de la sección (reseteando el borrador a account) y actualiza draftAccount mientras el usuario edita.

saveAccountName / saveDraftSection / saveAddress / saveRegistrationRequest → envio→ submit→ envío

Return Future<Failure?>

Todos chamam o privado _submitAccountUpdate({section, newAccount, startDate}): marca saving, monta o RetailerUploadDispatcherPayloadInput (account novo + atual, resource, config, geo no caso de endereço, isRouteRequest no cadastro), despacha (remote) e, no Ack de sucesso, grava no cache via SaveAccountUpdate; em falha, restaura o draftAccount.All call private _submitAccountUpdate({section, newAccount, startDate}): marks saving, builds the RetailerUploadDispatcherPayloadInput (new + current account, resource, config, geo for address, isRouteRequest for registration), dispatches (remote) and, on success Ack, writes to cache via SaveAccountUpdate; on failure, restores draftAccount.Todos llaman al privado _submitAccountUpdate({section, newAccount, startDate}): marca saving, arma el RetailerUploadDispatcherPayloadInput (account nuevo + actual, resource, config, geo en dirección, isRouteRequest en el registro), despacha (remote) y, en el Ack de éxito, graba en caché vía SaveAccountUpdate; en fallo, restaura el draftAccount.

State — RetailDetailStateState — RetailDetailStateState — RetailDetailState

RetailDetailState campos + gettersfields + getterscampos + getters
campotipo
visitSfidString
account / draftAccountAccountDataEntity
availableCategoriesList<CategoryForSale>
localClassificationDefinitionsList<LocalClassificationDefinitionEntity>
outletSubtypesList<SfidNamePairEntity>
geographicalHierarchyGeographicalHierarchyEntity
visibleModulesList<ModuleConfig>
retailerUploadConfigRetailerUploadConfig
editingSections / savingSectionsSet<RetailDetailSection>
lastSyncAtDateTime?

Getters: isEditing/isSaving/hasChanges(section), isAnySaving, getModule/isModuleVisible/isModuleEditable/editModeFor(type), isFieldVisible/isFieldEditable(type,field), selectedOutletSubtype, selectedLocalClassificationDefinition/Option, availableStates, geoStateFor/geoCityFor.Getters: isEditing/isSaving/hasChanges(section), isAnySaving, getModule/isModuleVisible/isModuleEditable/editModeFor(type), isFieldVisible/isFieldEditable(type,field), selectedOutletSubtype, selectedLocalClassificationDefinition/Option, availableStates, geoStateFor/geoCityFor.Getters: isEditing/isSaving/hasChanges(section), isAnySaving, getModule/isModuleVisible/isModuleEditable/editModeFor(type), isFieldVisible/isFieldEditable(type,field), selectedOutletSubtype, selectedLocalClassificationDefinition/Option, availableStates, geoStateFor/geoCityFor.

Provider cross-page — AdhocVisitCreationCross-page Provider — AdhocVisitCreationProvider cross-page — AdhocVisitCreation

create({retailName, accountSapCustomerId}) keepAlive · family(accountSfid)

Guarda contra reentrância (creating); seta a fase creating; lê geo; chama CreateAdhocVisitUseCase.execute. Em sucesso: markAdhocVisitCreated, invalidate de retailsProvider e visitsProvider, fase completed e aviso verde "Visita ad hoc criada — {name} ({sap})" via AppRouter.navigatorKey. Em falha: fase failed + aviso de erro.Guards reentrancy (creating); sets creating phase; reads geo; calls CreateAdhocVisitUseCase.execute. On success: markAdhocVisitCreated, invalidate of retailsProvider and visitsProvider, completed phase and a green notice "Ad hoc visit created — {name} ({sap})" via AppRouter.navigatorKey. On failure: failed phase + error notice.Protege reentrancia (creating); setea la fase creating; lee geo; llama CreateAdhocVisitUseCase.execute. En éxito: markAdhocVisitCreated, invalidate de retailsProvider y visitsProvider, fase completed y un aviso verde "Visita ad hoc creada — {name} ({sap})" vía AppRouter.navigatorKey. En fallo: fase failed + aviso de error.

State (AdhocVisitCreationState): phase (AdhocVisitCreationPhase), retailName, accountSapCustomerId, failure.State (AdhocVisitCreationState): phase (AdhocVisitCreationPhase), retailName, accountSapCustomerId, failure.State (AdhocVisitCreationState): phase (AdhocVisitCreationPhase), retailName, accountSapCustomerId, failure.

13

Page e widgetsPage & widgetsPage y widgets

Lista — RetailsPageList — RetailsPageLista — RetailsPage

A RetailsPage (ConsumerWidget) observa o retailsProvider; loading e erro são globais (when). Os modais vivem sob o card que os abre:RetailsPage (ConsumerWidget) watches retailsProvider; loading and error are global (when). Modals live under the card that opens them:RetailsPage (ConsumerWidget) observa retailsProvider; loading y error son globales (when). Los modales viven bajo la tarjeta que los abre:

  • RetailsPage
    • AppPageShell displayBackButton · no drawer
      • CustomLoadingIndicator loading
      • FailureStateView error → invalidate
      • _RetailsBody data · scroll → loadMore()
        • RetailsHeaderWidget DataLoadInfo + título
        • CustomInput busca → setSearchQuery
        • RetailsInMyZoneSectionWidget
          • CustomEmptyState vazio
          • InfiniteScrollListView<RetailEntity> → loadMore()
            • RetailCardWidget nome · SAP
              • _PlannedBadge isPlanned… → CreatePlannedVisitModalContent (calendário) → createPlannedVisit
              • _AdhocBadge ConsumerWidget · isAdhoc… → CreateAdhocVisitModalContent → AdhocVisitCreation.create · "Criando visita…"
          • PaginationCountIndicator X de Y

Detalhe — RetailDetailPageDetail — RetailDetailPageDetalle — RetailDetailPage

A RetailDetailPage (family por visitSfid) observa o retailDetailProvider. Cada seção é um widget self-checking (some se o módulo não é visível). A edição passa pelo VisitStartGuard; endereço e entrega abrem páginas próprias; nome abre um modal:RetailDetailPage (family by visitSfid) watches retailDetailProvider. Each section is a self-checking widget (hides if its module isn't visible). Editing goes through VisitStartGuard; address and delivery open their own pages; name opens a modal:RetailDetailPage (family por visitSfid) observa retailDetailProvider. Cada sección es un widget self-checking (se oculta si su módulo no es visible). La edición pasa por VisitStartGuard; dirección y entrega abren páginas propias; nombre abre un modal:

  • RetailDetailPage
    • AppPageShell displayBackButton
      • CustomLoadingIndicator loading
      • FailureStateView error → invalidate
      • CustomPullToRefresh data → refresh()
        • DataLoadInfo lastSyncAt
        • AccountHeaderCard nome · SAP · overdue
        • RetailDetailFieldSection ×N SAP · taxId · reg. estadual · nome (modal) · nome comercial · bandeira · key account · volume · merch · frequências · dia visita · lead time · crédito · dias crédito
          • RetailDetailTextFieldModalContent modal · editar nome → saveAccountName
        • RetailDetailEmployeesWidget → VisitStartGuard → goToManageStaff
        • RetailDetailAddressSectionWidget EditMode.page → VisitStartGuard → goToEditAddress
          • EditAddressPage rua · complemento · bairro · CEP · estado/cidade (dropdowns) · geo → saveAddress
        • RetailDetailLocalClassificationWidget inline → saveDraftSection
        • RetailDetailOperatingDaysWidget inline · dias + horários → saveDraftSection
        • RetailDetailCategoriesWidget inline · CategoryForSale → saveDraftSection
        • RetailDetailOutletSubtypeWidget inline → saveDraftSection
        • RetailDetailDeliveryWidget retailPreferredDeliveryDay
        • RetailDetailRegistrationRequestButtonWidget → VisitStartGuard → goToEditVisitDelivery
          • EditVisitDeliveryPage freq. pedido/visita · dia visita/entrega · data início → saveRegistrationRequest (isRouteRequest)
        • RetailDetailPaymentMethodsWidget read-only

Visita Ad HocAd Hoc visitVisita Ad Hoc

A criação de visita ad hoc é um comportamento da tela de Varejos (não tem tela própria), por isso é documentada aqui. O botão AD HOC do card cria uma visita imediata para um varejo da zona e traz, num só RPC, todo o pacote de dados daquele varejo — que é fundido nos caches locais.Ad hoc visit creation is a behavior of the Retails screen (it has no screen of its own), so it's documented here. The card's AD HOC button creates an immediate visit for a zone retail and brings, in a single RPC, that retail's whole data package — which is merged into the local caches.La creación de visita ad hoc es un comportamiento de la pantalla de Puntos de venta (no tiene pantalla propia), por eso se documenta aquí. El botón AD HOC de la tarjeta crea una visita inmediata para un punto de venta de la zona y trae, en un solo RPC, todo el paquete de datos de ese punto de venta — que se fusiona en los cachés locales.

Não passa pelo DispatcherNot via the DispatcherNo pasa por el Dispatcher Diferente das edições e da visita planejada, o ad hoc não usa o Dispatcher (Ack-only): é um RPC read-style síncrono que já cria a visita no Salesforce e devolve os dados. Parte de username + accountSfid, não de locationHierarchySfid. Unlike edits and the planned visit, ad hoc does not use the Dispatcher (Ack-only): it's a synchronous read-style RPC that already creates the visit in Salesforce and returns the data. It starts from username + accountSfid, not locationHierarchySfid. A diferencia de las ediciones y la visita planificada, el ad hoc no usa el Dispatcher (Ack-only): es un RPC read-style síncrono que ya crea la visita en Salesforce y devuelve los datos. Parte de username + accountSfid, no de locationHierarchySfid.

Merge aditivo (crítico)Additive merge (critical)Merge aditivo (crítico)

O reply tem 11 estruturas (16 listas na Entity). O AdhocVisitMergeCoordinator aplica um merge aditivo e escopado ao account novo — nunca save*/clear* (que dariam wipe) — em 12 datasources locais, cada chamada isolada (best-effort). O lastSyncAt do root não é bumpado (só uma fatia foi atualizada). Duas famílias de merge:The reply has 11 structures (16 lists in the Entity). The AdhocVisitMergeCoordinator applies an additive, account-scoped merge — never save*/clear* (which would wipe) — into 12 local datasources, each call isolated (best-effort). The root lastSyncAt is not bumped (only a slice was updated). Two merge families:El reply tiene 11 estructuras (16 listas en la Entity). El AdhocVisitMergeCoordinator aplica un merge aditivo y acotado al account nuevo — nunca save*/clear* (que harían wipe) — en 12 datasources locales, cada llamada aislada (best-effort). El lastSyncAt del root no se bumpa (solo se actualizó una porción). Dos familias de merge:

Datasource · métodoDatasource · methodDatasource · métodoFamília / chaveFamily / keyFamilia / clave
visit · mergeAdhocVisitsA — item único por account (upsert no topo)A — one item per account (upsert on top)A — un ítem por account (upsert arriba)
task · mergeAdhocTasksA
order · mergeAdhocOrdersA · Orders
stockControl · mergeAdhocStockControlA · por sfid/accountIdA · by sfid/accountIdA · por sfid/accountId
financialManagement · mergeAdhocFinancialManagementA · debitOpenItems/payments/creditNotes; banks global preservadoA · debitOpenItems/payments/creditNotes; banks kept globalA · debitOpenItems/payments/creditNotes; banks global preservado
merchandisingImageAudits · mergeAdhocMerchandisingAuditsA · chave = accountCodeA · key = accountCodeA · clave = accountCode
merchandisingServiceOrders · mergeAdhocMerchandisingServiceOrdersA
surveys · mergeAdhocSurveysB — compartilhado (anexa .accountData)B — shared (appends .accountData)B — compartido (anexa .accountData)
promotion · mergeAdhocPromotionCatalogB · .accountDataList + .orderChoiceListB · .accountDataList + .orderChoiceListB · .accountDataList + .orderChoiceList
marginCalculator · mergeAdhocMarginCalculatorB · union em .accountSfidsB · union in .accountSfidsB · union en .accountSfids
productCatalog · mergeAdhocProductCatalogB · .soqByAccount + .salesHistoryB · .soqByAccount + .salesHistoryB · .soqByAccount + .salesHistory
merchandisingAssets · mergeAdhocMerchandisingAssetsB · .itemsB · .itemsB · .items

Pendências / roadmapPending / roadmapPendencias / roadmap Ad hoc é online-only: o mock retorna vazio (validação contra o streambridge real; testes no futuro). merchandising.digitalContent fica fora do merge (sem entity/model → lista vazia + TODO). Algumas estruturas ainda chegam vazias do backend (documentadas em missing-data), mas o merge já está implementado completo. Na lista, tocar num card não navega para o detalhe (o handler é no-op hoje) — o detalhe abre só pela visita. Ad hoc is online-only: the mock returns empty (validated against the real streambridge; tests later). merchandising.digitalContent is out of the merge (no entity/model → empty list + TODO). Some structures still arrive empty from the backend (tracked in missing-data), but the merge is already fully implemented. In the list, tapping a card does not navigate to the detail (the handler is a no-op today) — the detail opens only from the visit. Ad hoc es online-only: el mock devuelve vacío (validación contra el streambridge real; tests a futuro). merchandising.digitalContent queda fuera del merge (sin entity/model → lista vacía + TODO). Algunas estructuras aún llegan vacías del backend (documentadas en missing-data), pero el merge ya está implementado completo. En la lista, tocar una tarjeta no navega al detalle (el handler es no-op hoy) — el detalle abre solo desde la visita.

Notas por mercadoMarket notesNotas por mercado

Varejos é dirigido por configuração de mercado (End Market Configuration): o item de menu retails, o accountEditionConfig (quais campos aparecem e como editam) e o retailerUploadConfig (o que a transação envia). Está habilitado em três mercados:Retails is driven by market configuration (End Market Configuration): the retails menu item, the accountEditionConfig (which fields show and how they edit) and the retailerUploadConfig (what the transaction sends). It's enabled in three markets:Puntos de venta se rige por configuración de mercado (End Market Configuration): el ítem de menú retails, el accountEditionConfig (qué campos aparecen y cómo editan) y el retailerUploadConfig (qué envía la transacción). Está habilitado en tres mercados:

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

HabilitadoEnabledHabilitado O item retails está no menuConfig dos três, e cada um traz um accountEditionConfig. As transações da feature — RetailerUploadAPI (edição) e VisitUploadAPI (visita planejada) — têm enabledMarkets BR/CL/ZA; o RPC getAdhocVisit segue os mesmos mercados. Quais campos aparecem e como se editam (inline/modal/página) varia por mercado, pelo accountEditionConfig. The retails item is in all three menuConfigs, and each carries an accountEditionConfig. The feature's transactions — RetailerUploadAPI (edit) and VisitUploadAPI (planned visit) — have BR/CL/ZA enabledMarkets; the getAdhocVisit RPC follows the same markets. Which fields show and how they edit (inline/modal/page) varies per market, via accountEditionConfig. El ítem retails está en los tres menuConfig, y cada uno trae un accountEditionConfig. Las transacciones de la feature — RetailerUploadAPI (edición) y VisitUploadAPI (visita planificada) — tienen enabledMarkets BR/CL/ZA; el RPC getAdhocVisit sigue los mismos mercados. Qué campos aparecen y cómo se editan (inline/modal/página) varía por mercado, vía accountEditionConfig.

AR · PY · PE Existem como mercados do app (config mínima PANGEA), mas não têm retails no menu nem accountEditionConfig — a feature não é alcançável. Documentos e moeda são formatados por mercado quando os campos financeiros aparecem (BR/CL estilo 1.234,56; ZA estilo 1,234.56). They exist as app markets (PANGEA minimal config), but have no retails menu item nor accountEditionConfig — the feature is unreachable. Documents and currency are per-market when the financial fields show (BR/CL as 1.234,56; ZA as 1,234.56). Existen como mercados de la app (config mínima PANGEA), pero no tienen el ítem retails ni accountEditionConfig — la feature no es alcanzable. Documentos y moneda se formatean por mercado cuando aparecen los campos financieros (BR/CL como 1.234,56; ZA como 1,234.56).