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 · MerchandisingFeature · MerchandisingFeature · Merchandising

Merchandising

O ecossistema de execução de merchandising em campo durante uma visita: auditar o ponto de venda, auditar peças unidade a unidade, corrigir as peças já instaladas e abrir ordens de serviço. A navegação é dirigida pela configuração de mercado: uma única página de menu, parametrizada por grupo, monta os cartões e cada cartão declara o seu destino. São dois grupos (auditoria e ordem de serviço), seis agregados de leitura e sete transações de escrita pelo Dispatcher. The field merchandising execution ecosystem during a visit: auditing the store, auditing pieces unit by unit, fixing the pieces already installed and opening service orders. Navigation is driven by market configuration: a single menu page, parameterised by group, builds the cards and each card declares its own destination. There are two groups (audit and service order), six read aggregates and seven write transactions through the Dispatcher. El ecosistema de ejecución de merchandising en campo durante una visita: auditar el punto de venta, auditar piezas unidad por unidad, corregir las piezas ya instaladas y abrir órdenes de servicio. La navegación es dirigida por la configuración de mercado: una única página de menú, parametrizada por grupo, arma las tarjetas y cada tarjeta declara su destino. Son dos grupos (auditoría y orden de servicio), seis agregados de lectura y siete transacciones de escritura por el Dispatcher.

PúblicoAudiencePúblico
Representante · QA · Suporte · DevRep · QA · Support · DevRepresentante · QA · Soporte · Dev
Onde ficaWhereDónde
Detalhe da visita → ferramentas → MerchandisingVisit detail → tools → MerchandisingDetalle de la visita → herramientas → Merchandising
AtualizadoUpdatedActualizado
11/08/20262026-08-11
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

O Merchandising reúne, num só lugar, tudo o que o representante de vendas executa sobre material de ponto de venda durante uma visita — geladeiras, displays, peças de marca e outros ativos. É um ecossistema: um menu abre a partir da visita e ramifica em duas frentes de trabalho. Merchandising gathers, in one place, everything the sales rep does on point-of-sale material during a visit — coolers, displays, brand pieces and other assets. It's an ecosystem: a menu opens from the visit and branches into two lines of work. Merchandising reúne, en un solo lugar, todo lo que el representante de ventas ejecuta sobre material de punto de venta durante una visita — heladeras, exhibidores, piezas de marca y otros activos. Es un ecosistema: un menú abre desde la visita y se ramifica en dos frentes de trabajo.

AuditoriaAuditAuditoría

Fotografar o PDV para uma auditoria de imagem e consultar o resultado. Cada mercado usa um fornecedor diferente — e a África do Sul ainda audita peça por peça (código de barras + condição).Photograph the store for an image audit and review the result. Each market uses a different vendor — and South Africa also audits piece by piece (barcode + condition).Fotografiar el PDV para una auditoría de imagen y consultar el resultado. Cada mercado usa un proveedor distinto — y Sudáfrica además audita pieza por pieza (código de barras + condición).

Ordem de serviçoService orderOrden de servicio

Abrir uma OS de merchandising — instalar, remover, substituir ou fazer manutenção de peças (o fluxo log snag) — e consultar as OS abertas ou as peças já instaladas no varejo.Open a merchandising service order — install, remove, substitute or maintain pieces (the log snag flow) — and browse open SOs or the pieces already installed at the retail.Abrir una OS de merchandising — instalar, quitar, sustituir o dar mantenimiento a piezas (el flujo log snag) — y consultar las OS abiertas o las piezas ya instaladas en el punto de venta.

Conteúdo digitalDigital contentContenido digital

Na tela de peças instaladas: a campanha do varejo (nome, descrição e link de exemplo) e os atalhos globais — guia de instalação e informação da unidade — abertos no navegador.On the installed-pieces screen: the retail's campaign (name, description and example link) and the global shortcuts — installation guide and unit info — opened in the browser.En la pantalla de piezas instaladas: la campaña del punto de venta (nombre, descripción y enlace de ejemplo) y los atajos globales — guía de instalación e información de la unidad — abiertos en el navegador.

Dirigido por mercadoMarket-drivenDirigido por mercado Quais cartões aparecem, para onde cada cartão leva e qual transação o envio dispara é configuração de mercado (End Market Configuration), não código fixo. Os três mercados declaram os mesmos dois gruposaudit e service_order — e a diferença fica só nos destinos e na visibilidade. Which cards appear, where each card leads and which transaction a submission fires is market configuration (End Market Configuration), not hardcoded. All three markets declare the same two groupsaudit and service_order — and the difference lives only in the destinations and visibility. Qué tarjetas aparecen, a dónde lleva cada tarjeta y qué transacción dispara el envío es configuración de mercado (End Market Configuration), no código fijo. Los tres mercados declaran los mismos dos gruposaudit y service_order — y la diferencia queda solo en los destinos y la visibilidad.

02

Como acessarHow to openCómo acceder

  1. Entre numa visitaOpen a visitEntre en una visitaO Merchandising sempre acontece no contexto de um varejo, então parte do detalhe da visita.Merchandising always happens in a retail's context, so it starts from the visit detail.El Merchandising siempre ocurre en el contexto de un punto de venta, así que parte del detalle de la visita.
  2. Grade de ferramentas → MerchandisingTools grid → MerchandisingGrilla de herramientas → MerchandisingToque no cartão Merchandising na grade de ferramentas da visita. O menu abre já ligado àquele varejo (recebe o visitSfid).Tap the Merchandising card in the visit's tools grid. The menu opens already bound to that retail (it receives the visitSfid).Toque la tarjeta Merchandising en la grilla de herramientas de la visita. El menú abre ya vinculado a ese punto de venta (recibe el visitSfid).
  3. Menu raiz: os dois gruposRoot menu: the two groupsMenú raíz: los dos gruposMostra a última sincronização, o cartão do varejo e os cartões Auditoria e Ordem de Serviço.It shows the last sync, the retail card and the Audit and Service Order cards.Muestra la última sincronización, la tarjeta del punto de venta y las tarjetas Auditoría y Orden de Servicio.
  4. Submenu → destinoSubmenu → destinationSubmenú → destinoTocar num grupo abre a mesma tela de menu, agora com os filhos daquele grupo. Tocar num cartão-folha abre o destino declarado (formulário, lista, app externo).Tapping a group opens the same menu screen, now with that group's children. Tapping a leaf card opens the declared destination (form, list, external app).Tocar un grupo abre la misma pantalla de menú, ahora con los hijos de ese grupo. Tocar una tarjeta-hoja abre el destino declarado (formulario, lista, app externa).

Atalho na África do SulShortcut in South AfricaAtajo en Sudáfrica Na ZA o grupo Ordem de Serviço não tem filhos: o cartão é uma folha e abre direto o formulário de OS, sem passar por um submenu. In ZA the Service Order group has no children: the card is a leaf and opens the SO form directly, with no submenu in between. En ZA el grupo Orden de Servicio no tiene hijos: la tarjeta es una hoja y abre directo el formulario de OS, sin pasar por un submenú.

03

Estrutura do menu e dos destinosMenu and destination structureEstructura del menú y de los destinos

Raiz e submenus são a mesma tela, mudando só o parâmetro de grupo. A coluna é sempre igual: data de última sincronização, cartão do varejo (nome + código SAP + indicador de inadimplência), título (e subtítulo, quando o grupo tem) e a grade de cartões vinda da configuração. Cartão cujo destino o app não reconhece não é renderizado.Root and submenus are the same screen, only the group parameter changes. The column is always the same: last sync date, retail card (name + SAP code + overdue indicator), title (and subtitle, when the group has one) and the card grid from configuration. A card whose destination the app doesn't recognise is not rendered.Raíz y submenús son la misma pantalla, cambiando solo el parámetro de grupo. La columna es siempre igual: fecha de última sincronización, tarjeta del punto de venta (nombre + código SAP + indicador de morosidad), título (y subtítulo, cuando el grupo lo tiene) y la grilla de tarjetas de la configuración. Una tarjeta cuyo destino la app no reconoce no se renderiza.

Os destinos possíveis de um cartão, e o que cada um abre:A card's possible destinations, and what each one opens:Los destinos posibles de una tarjeta, y lo que abre cada uno:

SubmenuSubmenuSubmenú
Reabre a própria tela de menu com os filhos do grupo. É o destino dos cartões Auditoria e Ordem de Serviço.Reopens the menu screen itself with the group's children. It's the destination of the Audit and Service Order cards.Reabre la propia pantalla de menú con los hijos del grupo. Es el destino de las tarjetas Auditoría y Orden de Servicio.
Auditoria de imagem (nova / lista)Image audit (new / list)Auditoría de imagen (nueva / lista)
Formulário de fotos do PDV (com peça / sem peça, frente e verso) e a lista de resultados daquele fornecedor — peças detectadas, campanhas e pontos de contato, só leitura.The store photo form (with piece / without piece, front & back) and the results list for that vendor — detected pieces, campaigns and touchpoints, read-only.El formulario de fotos del PDV (con pieza / sin pieza, frente y dorso) y la lista de resultados de ese proveedor — piezas detectadas, campañas y puntos de contacto, solo lectura.
Reconhecimento de imagem (nova / lista)Image recognition (new / list)Reconocimiento de imagen (nueva / lista)
O outro fornecedor de auditoria de varejo: tira várias fotos, rotula cada uma e envia. A lista separa BAT e concorrência, com acertou/errou por auditoria.The other retail-audit vendor: take several photos, label each one and submit. The list splits BAT and competitor, with matched/missed per audit.El otro proveedor de auditoría de PDV: toma varias fotos, rotula cada una y envía. La lista separa BAT y competencia, con acertó/erró por auditoría.
ShelfWatch
Abre o app externo ShelfWatch por deep link, ou a tela de peças do ShelfWatch (lista de ativos da visita) quando o mercado a habilita.Opens the external ShelfWatch app via deep link, or the ShelfWatch pieces screen (the visit's asset list) where the market enables it.Abre la app externa ShelfWatch por deep link, o la pantalla de piezas de ShelfWatch (lista de activos de la visita) cuando el mercado la habilita.
Auditoria de unidadeUnit auditAuditoría de unidad
Formulário peça a peça: escolhe o ativo, escaneia o código de barras, tira até 3 fotos e marca a condição (bom, arranhado, danificado…).Piece-by-piece form: pick the asset, scan the barcode, take up to 3 photos and mark the condition (good, scuffed, damaged…).Formulario pieza por pieza: elige el activo, escanea el código de barras, toma hasta 3 fotos y marca la condición (bueno, rayado, dañado…).
OS: formulário e listaSO: form and listOS: formulario y lista
O log snag em 3 passos (especificações → peças → resumo) e a lista de ordens de serviço abertas/fechadas, com produtividade.The 3-step log snag (specifications → pieces → summary) and the list of open/closed service orders, with productivity.El log snag en 3 pasos (especificaciones → piezas → resumen) y la lista de órdenes de servicio abiertas/cerradas, con productividad.
Peças instaladasInstalled piecesPiezas instaladas
Lista das peças instaladas naquele varejo. Permite corrigir o código de barras e trocar a foto de cada peça, e mostra o conteúdo digital do varejo.List of the pieces installed at that retail. It allows fixing the barcode and replacing the photo of each piece, and shows the retail's digital content.Lista de las piezas instaladas en ese punto de venta. Permite corregir el código de barras y cambiar la foto de cada pieza, y muestra el contenido digital del punto de venta.
04

EstadosStatesEstados

Ao longo do ecossistema aparecem seis famílias de estado (a lista completa de valores está na seção técnica Enums):Across the ecosystem there are six state families (the full value lists are in the technical Enums section):A lo largo del ecosistema aparecen seis familias de estado (la lista completa de valores está en la sección técnica Enums):

EnvioSubmissionEnvío
Cada formulário tem um ciclo ocioso → enviando → sucesso / falha. O botão de envio só habilita quando o formulário está completo.Each form has an idle → submitting → success / failure cycle. The submit button only enables when the form is complete.Cada formulario tiene un ciclo inactivo → enviando → éxito / fallo. El botón de envío solo se habilita cuando el formulario está completo.
Condição da peçaPiece conditionCondición de la pieza
Na auditoria de unidade: bom, arranhado, danificado-reparável, danificado sem reparo. As opções vêm da configuração de mercado.On the unit audit: good, scuffed, damaged-repairable, damaged beyond repair. The options come from market configuration.En la auditoría de unidad: bueno, rayado, dañado-reparable, dañado sin reparación. Las opciones vienen de la configuración de mercado.
Status do ativoAsset statusEstado del activo
Cada peça carrega um status (instalação solicitada, instalada, remoção solicitada, em reparo, desinstalada). Na lista de peças instaladas ele ordena a lista e as desinstaladas não aparecem.Each piece carries a status (installation requested, installed, removal requested, under repair, uninstalled). On the installed-pieces list it sorts the list and uninstalled ones don't show.Cada pieza lleva un estado (instalación solicitada, instalada, remoción solicitada, en reparación, desinstalada). En la lista de piezas instaladas ordena la lista y las desinstaladas no aparecen.
Em processamentoProcessingEn proceso
Peça que acabou de receber uma correção fica marcada como em processamento e trava foto e código de barras até o próximo sincronismo trazer o registro atualizado.A piece that has just been corrected is flagged as processing and locks photo and barcode until the next sync brings the updated record.Una pieza que acaba de recibir una corrección queda marcada como en proceso y bloquea foto y código de barras hasta que el próximo sincronismo traiga el registro actualizado.
Resultado da auditoriaAudit resultResultado de la auditoría
No reconhecimento de imagem: acertou, errou ou em análise (quando o backend ainda não respondeu). Nos resultados do outro fornecedor: auditada ou em análise.On image recognition: matched, missed or in analysis (when the backend hasn't answered yet). On the other vendor's results: audited or in analysis.En el reconocimiento de imagen: acertó, erró o en análisis (cuando el backend aún no respondió). En los resultados del otro proveedor: auditada o en análisis.
Status da OSSO statusEstado de la OS
Na lista de ordens de serviço: aberta ou fechada (por data de fechamento), com produtividade (aprovada / improdutiva + motivo).On the service orders list: open or closed (by closing date), with productivity (approved / improductive + reason).En la lista de órdenes de servicio: abierta o cerrada (por fecha de cierre), con productividad (aprobada / improductiva + motivo).
05

Ações e enviosActions & submissionsAcciones y envíos

Toda escrita sai pelo Dispatcher (fila de envio idempotente). O que cada formulário dispara depende do mercado — a mesma ação de "OS" pode virar uma ou outra transação:Every write goes out through the Dispatcher (idempotent send queue). What each form fires depends on the market — the same "SO" action can become one transaction or another:Toda escritura sale por el Dispatcher (cola de envío idempotente). Lo que dispara cada formulario depende del mercado — la misma acción de "OS" puede volverse una u otra transacción:

Enviar auditoria de PDVSubmit retail auditEnviar auditoría de PDV
Até 10 peças (marca, foto frente/verso) → transação Image Audit. Confirmação por modal.Up to 10 pieces (brand, front/back photo) → Image Audit transaction. Modal confirmation.Hasta 10 piezas (marca, foto frente/dorso) → transacción Image Audit. Confirmación por modal.
Enviar reconhecimento de imagemSubmit image recognitionEnviar reconocimiento de imagen
N fotos rotuladas (rótulo opcional por foto) → transação Service Merchan Audit. Sair da tela com fotos pendentes pede confirmação.N labelled photos (label optional per photo) → Service Merchan Audit transaction. Leaving the screen with pending photos asks for confirmation.N fotos rotuladas (rótulo opcional por foto) → transacción Service Merchan Audit. Salir de la pantalla con fotos pendientes pide confirmación.
Enviar auditoria de unidadeSubmit unit auditEnviar auditoría de unidad
Ativo + condição + código de barras (+ foto) + fotos da unidade → transação Audit Unit Report. Confirmação por modal.Asset + condition + barcode (+ photo) + unit photos → Audit Unit Report transaction. Modal confirmation.Activo + condición + código de barras (+ foto) + fotos de la unidad → transacción Audit Unit Report. Confirmación por modal.
Enviar OS / log snagSubmit SO / log snagEnviar OS / log snag
Peças selecionadas com movimento (instalar/remover/substituir) + fotos/quantidade → uma transação de rastreio de item de ativo por item, ou um par criação + OS — o mercado decide.Selected pieces with movement (install/remove/substitute) + photos/quantity → one asset-item tracking transaction per item, or a creation + SO pair — the market decides.Piezas seleccionadas con movimiento (instalar/quitar/sustituir) + fotos/cantidad → una transacción de rastreo de ítem de activo por ítem, o un par creación + OS — el mercado decide.
Enviar mediçãoSubmit measurementEnviar medición
Quando a atividade é de medição, o log snag pede só uma anotação de texto → transação anotação de merchan.When the activity is a measurement, the log snag asks only for a text annotation → merchan annotation transaction.Cuando la actividad es de medición, el log snag pide solo una anotación de texto → transacción anotación de merchan.
Corrigir peça instaladaFix an installed pieceCorregir pieza instalada
Editar o código de barras ou trocar a foto envia um rastreio de item de ativo isolado, só para aquela peça, e atualiza o cache local em seguida. Cada ação é um envio.Editing the barcode or replacing the photo sends one isolated asset-item tracking, for that piece only, and updates the local cache afterwards. Each action is one submission.Editar el código de barras o cambiar la foto envía un rastreo de ítem de activo aislado, solo para esa pieza, y actualiza el caché local después. Cada acción es un envío.
Consultar (só leitura)Browse (read-only)Consultar (solo lectura)
Listas de resultados de auditoria, de reconhecimento de imagem, de ordens de serviço e de peças do ShelfWatch — expandem para mostrar detalhes; não enviam nada.Audit results, image recognition, service orders and ShelfWatch pieces lists — expand to show details; they submit nothing.Listas de resultados de auditoría, de reconocimiento de imagen, de órdenes de servicio y de piezas de ShelfWatch — se expanden para mostrar detalles; no envían nada.

Duas regras que surpreendemTwo rules that surpriseDos reglas que sorprenden

  • Duas rotas para "OS". O mesmo botão de envio do log snag segue uma de duas rotas, decidida pela flag usesInstalledAssetItems do mercado: onde é true (CL, ZA), envia rastreio de item de ativo — um envelope por peça; onde é false (BR, fluxo fora do CRM), envia um par criação + ordem de serviço.Two "SO" routes. The same log snag submit takes one of two routes, decided by the market's usesInstalledAssetItems flag: where it's true (CL, ZA), it sends asset-item tracking — one envelope per piece; where it's false (BR, workflow outside the CRM), it sends a creation + service-order pair.Dos rutas para "OS". El mismo envío del log snag toma una de dos rutas, decidida por la flag usesInstalledAssetItems del mercado: donde es true (CL, ZA), envía rastreo de ítem de activo — un sobre por pieza; donde es false (BR, flujo fuera del CRM), envía un par creación + orden de servicio.
  • Código de barras vazio apaga. Salvar o campo de código de barras em branco não é "não fazer nada": envia a palavra Delete ao backend, que remove o código da peça. Cancelar o modal, sim, não envia nada.An empty barcode deletes. Saving the barcode field blank is not "do nothing": it sends the word Delete to the backend, which clears the piece's barcode. Cancelling the modal, on the other hand, sends nothing.Un código vacío borra. Guardar el campo de código de barras en blanco no es "no hacer nada": envía la palabra Delete al backend, que borra el código de la pieza. Cancelar el modal, en cambio, no envía nada.

Formato do código de barrasBarcode formatFormato del código de barras Blocos de exatamente 5 caracteres separados por ponto e vírgula (;), no máximo 50 caracteres no total, e sem terminar em ;. Ex.: AB123;CD456. Blocks of exactly 5 characters separated by semicolons (;), at most 50 characters in total, and never ending in ;. E.g. AB123;CD456. Bloques de exactamente 5 caracteres separados por punto y coma (;), como máximo 50 caracteres en total, y sin terminar en ;. Ej.: AB123;CD456.

06

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

Clean Architecture + Riverpod + Freezed + gRPC + ObjectBox. Há três fluxos distintos: a navegação (o EMC decide o destino de cada cartão), a leitura (seis agregados cache-first, um RPC cada) e a escrita (sete transações via Dispatcher).Clean Architecture + Riverpod + Freezed + gRPC + ObjectBox. There are three distinct flows: navigation (the EMC decides each card's destination), the read (six cache-first aggregates, one RPC each) and the write (seven transactions via the Dispatcher).Clean Architecture + Riverpod + Freezed + gRPC + ObjectBox. Hay tres flujos distintos: la navegación (el EMC decide el destino de cada tarjeta), la lectura (seis agregados cache-first, un RPC cada uno) y la escritura (siete transacciones vía Dispatcher).

Navegação · dirigida por destinoNavigation · destination-drivenNavegación · dirigida por destino

Cada opção do EMC carrega um name (identidade do botão → ícone e label) e um destination (para onde vai). O mapper resolve o destino: o declarado vence; se o EMC não declarar, ele é derivado do name por compatibilidade. Destino não reconhecido vira unknown e o cartão não é renderizado.Each EMC option carries a name (the button's identity → icon and label) and a destination (where it goes). The mapper resolves the destination: the declared one wins; if the EMC doesn't declare it, it is derived from the name for compatibility. An unrecognised destination becomes unknown and the card is not rendered.Cada opción del EMC lleva un name (identidad del botón → ícono y label) y un destination (a dónde va). El mapper resuelve el destino: el declarado gana; si el EMC no lo declara, se deriva del name por compatibilidad. Un destino no reconocido pasa a unknown y la tarjeta no se renderiza.

  • merchandisingConfig.options[]End Market Configuration
    • fromMapMerchandisingOptionDTOname · destination · isVisible · isActive · options[]
      • toDomain · _resolveDestinationMerchandisingOptiontype + destination tipados
        • navigableOptionsMerchandisingMenuNotifierraiz ou filhos do group
          • optionsMerchandisingOptionCardsWidgetfiltra isMenuCard + isKnown
            • onOptionTapMerchandisingNavigator.openswitch por destination
              • Page / deep link / submenu

Leitura · cache-first (×6 agregados)Read · cache-first (×6 aggregates)Lectura · cache-first (×6 agregados)

Um único serviço gRPC (MerchandisingConectaRepService) expõe um RPC por agregado: Assets, Options, Service Orders, Audit Results, Digital Content e Image Recognition. Cada um segue a mesma cascata write-through — o padrão abaixo vale para os seis (mostrado com Assets):A single gRPC service (MerchandisingConectaRepService) exposes one RPC per aggregate: Assets, Options, Service Orders, Audit Results, Digital Content and Image Recognition. Each follows the same write-through cascade — the pattern below holds for all six (shown with Assets):Un único servicio gRPC (MerchandisingConectaRepService) expone un RPC por agregado: Assets, Options, Service Orders, Audit Results, Digital Content e Image Recognition. Cada uno sigue la misma cascada write-through — el patrón de abajo vale para los seis (mostrado con Assets):

  • MerchandisingAssetsReplygRPC proto
    • toDTOMerchandisingAssetsDTODTO · Freezed
      • toDomainMerchandisingAssetsEntitydomain
        • toModelMerchandisingAssetsModelObjectBox
          • toDomainMerchandisingAssetsEntitydomain · cache
            • get(source)GetMerchandising…UseCase
              • readNotifier + Statemenu / lista / form
                • → UIPage

Escrita · sete transações via DispatcherWrite · seven transactions via the DispatcherEscritura · siete transacciones vía Dispatcher

Cada formulário reúne um {X}DispatcherPayloadInput cru, o builder monta o JSON e o envelope (com o DispatcherType certo), e o Submit despacha. Envios múltiplos (log snag por item) vão em paralelo via Future.wait:Each form assembles a raw {X}DispatcherPayloadInput, the builder builds the JSON and the envelope (with the right DispatcherType), and the Submit dispatches. Multiple sends (per-item log snag) go in parallel via Future.wait:Cada formulario reúne un {X}DispatcherPayloadInput crudo, el builder arma el JSON y el sobre (con el DispatcherType correcto), y el Submit despacha. Envíos múltiples (log snag por ítem) van en paralelo vía Future.wait:

  • Form Notifieraudit unit · image audit · image recognition · log snag · asset items
    • {X}DispatcherPayloadInputBuild{X}DispatcherPayloadUseCase→ DispatcherEnvelope
      • submit(envelope[s])Submit{X}UseCase
        • dispatchDispatcherOrchestratorgRPC dispatcher
07

Modelo de dadosData modelModelo de datos

O Merchandising lê seis agregados independentes, cada um existindo em quatro representações — Proto (wire gRPC) → DTO (Freezed) → Model (ObjectBox) → Entity (domínio) — ligadas por mappers, com cache write-through. Os nomes dos campos se mantêm em todas as camadas; muda muito pouco (datas parseadas, enums tipados na Entity, relações ToMany/ToOne no Model).Merchandising reads six independent aggregates, each existing in four representations — Proto (gRPC wire) → DTO (Freezed) → Model (ObjectBox) → Entity (domain) — linked by mappers, with cache write-through. Field names stay the same across layers; very little changes (parsed dates, enums typed in the Entity, ToMany/ToOne relations in the Model).Merchandising lee seis agregados independientes, cada uno existiendo en cuatro representaciones — Proto (wire gRPC) → DTO (Freezed) → Model (ObjectBox) → Entity (dominio) — unidas por mappers, con cache write-through. Los nombres se mantienen en todas las capas; cambia muy poco (fechas parseadas, enums tipados en la Entity, relaciones ToMany/ToOne en el Model).

Cada agregado chega num container com lastSyncAt + a lista de itens: MerchandisingAssetsEntity (assets), MerchandisingOptionsEntity (activities), MerchandisingServiceOrdersEntity (items), MerchandisingAuditResultsEntity (audits), MerchandisingDigitalContentEntity (items) e ImageRecognitionAuditsEntity (audits). Os cinco primeiros vivem no MerchandisingRepository; o reconhecimento de imagem tem repository próprio. A seguir, na ordem: o proto, as estruturas de dados campo-a-campo por camada, e os mappers.Each aggregate arrives in a container with lastSyncAt + the item list: MerchandisingAssetsEntity (assets), MerchandisingOptionsEntity (activities), MerchandisingServiceOrdersEntity (items), MerchandisingAuditResultsEntity (audits), MerchandisingDigitalContentEntity (items) and ImageRecognitionAuditsEntity (audits). The first five live in the MerchandisingRepository; image recognition has its own repository. Next, in order: the proto, the field-by-field data structures per layer, and the mappers.Cada agregado llega en un container con lastSyncAt + la lista de ítems: MerchandisingAssetsEntity (assets), MerchandisingOptionsEntity (activities), MerchandisingServiceOrdersEntity (items), MerchandisingAuditResultsEntity (audits), MerchandisingDigitalContentEntity (items) e ImageRecognitionAuditsEntity (audits). Los cinco primeros viven en el MerchandisingRepository; el reconocimiento de imagen tiene repository propio. A continuación, en orden: el proto, las estructuras de datos campo a campo por capa, y los mappers.

Proto

MerchandisingConectaRep.proto · proto3 · package mn.bat.conectarep.streambridge. Um serviço (MerchandisingConectaRepService), seis RPCs unários — todos com o mesmo request MerchandisingRequest, e todos consumidos.One service (MerchandisingConectaRepService), six unary RPCs — all with the same MerchandisingRequest, and all consumed.Un servicio (MerchandisingConectaRepService), seis RPCs unarios — todos con el mismo MerchandisingRequest, y todos consumidos.

MerchandisingRequestrequest comum · unaryshared request · unaryrequest común · unary
Request · MerchandisingRequest
locationHierarchySfid
string · #1 · hierarquia do representante de vendas (resolvida no repository)sales rep hierarchy (resolved in the repository)jerarquía del representante de ventas (resuelta en el repository)
lastModifiedDate
string · #2 · optional · nunca preenchido pelo repository hojenever filled by the repository todaynunca completado por el repository hoy
RPCs
getMerchandisingAssets
→ MerchandisingAssetsReply · repeated MerchandisingAsset assets
getMerchandisingAuditResults
→ MerchandisingAuditResultsReply · repeated MerchandisingAuditResult audits
getMerchandisingDigitalContent
→ MerchandisingDigitalContentReply · repeated MerchandisingDigitalContentItem digitalContent
getMerchandisingOptions
→ MerchandisingOptionsReply · repeated MerchandisingOptionsActivity activities
getMerchandisingServiceOrders
→ MerchandisingServiceOrdersReply · repeated MerchandisingServiceOrder serviceOrders
getMerchandisingImageRecognitionAudits
→ MerchandisingImageRecognitionAuditsReply · repeated MerchandisingImageRecognitionAudit imageRecognitionAudits

Estruturas de dadosData structuresEstructuras de datos

Seis árvores (uma por agregado). Cada tabela tem uma coluna por camada — Proto · DTO · Model · Entity; o texto em destaque marca onde o tipo primeiro muda (data String→DateTime? no Model, enum na Entity, relação no Model, campo gerado no DTO). ¹ = optional no proto.Six trees (one per aggregate). Each table has one column per layer — Proto · DTO · Model · Entity; the highlighted text marks where the type first changes (date String→DateTime? in the Model, enum in the Entity, relation in the Model, generated field in the DTO). ¹ = optional in the proto.Seis árboles (uno por agregado). Cada tabla tiene una columna por capa — Proto · DTO · Model · Entity; el texto destacado marca dónde primero cambia el tipo (fecha String→DateTime? en el Model, enum en la Entity, relación en el Model, campo generado en el DTO). ¹ = optional en el proto.

1 · AssetsgetMerchandisingAssets

  • MerchandisingAssets container 2 campos2 fields2 campos
    CampoProtoDTOModelEntity
    lastSyncAtDateTimeDateTimeDateTime
    assetsrepeated MerchandisingAssetList<…DTO>ToMany<…Model>List<…Entity>
    • MerchandisingAsset assets[] 10 campos10 fields10 campos
      CampoProtoDTOModelEntity
      sfidstringStringStringString
      namestringStringStringString
      typestringStringStringString
      categorystring¹String?String?String?
      colorstring¹String?String?String?
      pieceCodestring¹String?String?String?
      itemsrepeated MerchandisingAssetItemList<…DTO>ToMany<…Model>List<…Entity>
      familyNamestring¹String?String?String
      isInstallationbool¹bool?bool?bool
      isMaintenancebool¹bool?bool?bool
      • MerchandisingAssetItem MerchandisingAsset.items[] 8 campos8 fields8 campos
        CampoProtoDTOModelEntity
        sfidstringStringStringString
        accountSfidstringStringStringString
        statusstringStringStringString
        barcodestring¹String?String?String?
        installedDatestring¹String?DateTime?DateTime?
        lastModifiedDatestring¹String?DateTime?DateTime?
        photoUrlstring¹String?String?String?
        isEditedbool¹bool?bool?bool?

2 · OptionsgetMerchandisingOptions

  • MerchandisingOptions container 2 campos2 fields2 campos
    CampoProtoDTOModelEntity
    lastSyncAtDateTimeDateTimeDateTime
    activitiesrepeated MerchandisingOptionsActivityList<…DTO>ToMany<…Model>List<…Entity>
    • MerchandisingActivity activities[] · proto MerchandisingOptionsActivity 4 campos4 fields4 campos
      CampoProtoDTOModelEntity
      codestringStringStringString
      labelstringStringStringString
      isMeasurementboolboolboolbool
      servicesrepeated MerchandisingOptionsServiceList<…DTO>ToMany<…Model>List<…Entity>
      • MerchandisingService MerchandisingActivity.services[] · proto MerchandisingOptionsService 6 campos6 fields6 campos
        CampoProtoDTOModelEntity
        codestringStringStringString
        labelstringStringStringString
        targetstring¹StringStringMerchandisingServiceTarget?
        assetItemStatusstring¹StringStringString
        reasonsrepeated MerchandisingOptionsReasonList<…DTO>ToMany<…Model>List<…Entity>
        fieldsMerchandisingOptionsServiceFields…DTOToOne<…Model>MerchandisingServiceFieldConfig
        • MerchandisingReason MerchandisingService.reasons[] · proto MerchandisingOptionsReason 2 campos2 fields2 campos
          CampoProtoDTOModelEntity
          codestringStringStringString
          labelstringStringStringString
        • MerchandisingServiceFieldConfig MerchandisingService.fields · proto MerchandisingOptionsServiceFields 5 regras5 rules5 reglas
          CampoProtoDTOModelEntity
          photoMerchandisingOptionsServiceFieldRule…DTOToOne<…Model>MerchandisingFieldRule
          barcodeMerchandisingOptionsServiceFieldRule…DTOToOne<…Model>MerchandisingFieldRule
          commentMerchandisingOptionsServiceFieldRule…DTOToOne<…Model>MerchandisingFieldRule
          colorMerchandisingOptionsServiceFieldRule…DTOToOne<…Model>MerchandisingFieldRule
          quantityMerchandisingOptionsServiceFieldRule…DTOToOne<…Model>MerchandisingFieldRule
          • MerchandisingFieldRule photo · barcode · comment · color · quantity 4 campos4 fields4 campos
            CampoProtoDTOModelEntity
            visibleboolboolboolbool
            isRequiredrequiredboolboolbool
            minCountint32intintint
            maxCountint32intintint

3 · Service OrdersgetMerchandisingServiceOrders

  • MerchandisingServiceOrders container 2 campos2 fields2 campos
    CampoProtoDTOModelEntity
    lastSyncAtDateTime?DateTime?DateTime?
    itemsrepeated MerchandisingServiceOrderList<…DTO>ToMany<…Model>List<…Entity>
    • MerchandisingServiceOrder items[] 11 campos11 fields11 campos
      CampoProtoDTOModelEntity
      sfidstringStringStringString
      accountSfidstringStringStringString
      orderIdstringStringStringString
      statusstringStringStringString
      activitystringStringStringString
      serviceTypestringStringStringString
      reasonstringStringStringString
      openingDatestringString?DateTime?DateTime?
      lastStatusDatestringString?DateTime?DateTime?
      closedDatestring¹String?DateTime?DateTime?
      productivityMerchandisingServiceOrderProductivity¹…DTO?ToOne<…Model>…Entity?
      • MerchandisingServiceOrderProductivity MerchandisingServiceOrder.productivity 4 campos4 fields4 campos
        CampoProtoDTOModelEntity
        isApprovedboolboolboolbool
        reasonstringStringStringString
        typestringStringStringString
        notestringStringStringString

4 · Audit ResultsgetMerchandisingAuditResults

  • MerchandisingAuditResults container 2 campos2 fields2 campos
    CampoProtoDTOModelEntity
    lastSyncAtDateTime?DateTime?DateTime?
    auditsrepeated MerchandisingAuditResultList<…DTO>ToMany<…Model>List<…Entity>
    • MerchandisingAuditResult audits[] 6 campos6 fields6 campos
      CampoProtoDTOModelEntity
      sfidstringStringStringString
      accountSfidstringStringStringString
      isAuditedboolboolboolbool
      createdAtstringStringDateTime?DateTime?
      auditedAtstringStringDateTime?DateTime?
      piecesrepeated MerchandisingAuditResultPieceList<…DTO>ToMany<…Model>List<…Entity>
      • MerchandisingAuditResultPiece MerchandisingAuditResult.pieces[] 6 campos6 fields6 campos
        CampoProtoDTOModelEntity
        statusboolboolboolbool
        errorstringStringStringString
        displaysrepeated stringList<String>List<String>List<String>
        primaryTouchpointsrepeated MerchandisingAuditResultTouchpointList<…DTO>ToMany<…Model>List<…Entity>
        secondaryTouchpointsrepeated MerchandisingAuditResultTouchpointList<…DTO>ToMany<…Model>List<…Entity>
        campaignsrepeated MerchandisingAuditResultCampaignList<…DTO>ToMany<…Model>List<…Entity>
        • MerchandisingAuditResultTouchpoint primaryTouchpoints[] · secondaryTouchpoints[] · campaign.touchpoints[] 4 campos4 fields4 campos
          CampoProtoDTOModelEntity
          namestringStringStringString
          areastringStringStringString
          classificationstringStringStringString
          inImageboolbool?bool?bool?
        • MerchandisingAuditResultCampaign MerchandisingAuditResultPiece.campaigns[] 3 campos3 fields3 campos
          CampoProtoDTOModelEntity
          namestringStringStringString
          statusboolboolboolbool
          touchpointsrepeated MerchandisingAuditResultTouchpointList<…DTO>ToMany<…Model>List<…Entity>

5 · Digital ContentgetMerchandisingDigitalContent

  • MerchandisingDigitalContent container 2 campos2 fields2 campos
    CampoProtoDTOModelEntity
    lastSyncAtDateTime?DateTime?DateTime?
    itemsdigitalContentList<…DTO>ToMany<…Model>List<…Entity>
    • MerchandisingDigitalContentItem items[] 5 campos5 fields5 campos
      CampoProtoDTOModelEntity
      sfidstringStringStringString
      namestringStringStringString
      descriptionstringStringStringString
      accountSfidstringStringStringString
      urlstringStringStringString

Um item com accountSfid vazio é global (atalho); com accountSfid preenchido é a campanha daquele varejo. A entity resolve os dois casos: itemForAccount(accountSfid:) e urlForName(name:) (só globais).An item with an empty accountSfid is global (a shortcut); with accountSfid filled it is that retail's campaign. The entity resolves both: itemForAccount(accountSfid:) and urlForName(name:) (globals only).Un ítem con accountSfid vacío es global (atajo); con accountSfid completo es la campaña de ese punto de venta. La entity resuelve ambos casos: itemForAccount(accountSfid:) y urlForName(name:) (solo globales).

6 · Image RecognitiongetMerchandisingImageRecognitionAudits

  • ImageRecognitionAudits container 2 campos2 fields2 campos
    CampoProtoDTOModelEntity
    lastSyncAtDateTime?DateTime?DateTime?
    auditsimageRecognitionAuditsList<…DTO>ToMany<…Model>List<…Entity>
    • ImageRecognitionAudit audits[] · proto MerchandisingImageRecognitionAudit 11 campos11 fields11 campos
      CampoProtoDTOModelEntity
      sfidstringStringStringString
      accountSfidstringStringStringString
      accountCodestringStringStringString
      uploadDatestringStringDateTime?DateTime?
      statusstringStringStringImageRecognitionStatus
      statusRawLabelStringString
      errorstringStringStringString
      imageUrlstringStringStringString
      piecesrepeated MerchandisingImageRecognitionPieceList<…DTO>ToMany<…Model>List<…Entity>
      campaignsrepeated stringList<String>List<String>List<String>
      elementsrepeated MerchandisingImageRecognitionElementList<…DTO>ToMany<…Model>List<…Entity>
      • ImageRecognitionPiece ImageRecognitionAudit.pieces[] 2 campos2 fields2 campos
        CampoProtoDTOModelEntity
        namestringStringStringString
        isCompetitorboolboolboolbool
      • ImageRecognitionElement ImageRecognitionAudit.elements[] 3 campos3 fields3 campos
        CampoProtoDTOModelEntity
        namestringStringStringString
        campaignstringStringStringString
        inImageboolboolboolbool

ImageRecognitionPhotoEntity (arquivo capturado + takenAt + rótulo) é só de escrita: existe no State do formulário e no payload, nunca é persistida.ImageRecognitionPhotoEntity (captured file + takenAt + label) is write-only: it lives in the form State and in the payload, and is never persisted.ImageRecognitionPhotoEntity (archivo capturado + takenAt + rótulo) es solo de escritura: existe en el State del formulario y en el payload, nunca se persiste.

Mappers

Cada tipo tem as conversões entre camadas como extension (as mesmas 5 direções por tipo), nos seis agregados.Each type has the cross-layer conversions as extensions (the same 5 directions per type), across the six aggregates.Cada tipo tiene las conversiones entre capas como extension (las mismas 5 direcciones por tipo), en los seis agregados.

DireçãoDirectionDirecciónMétodoMethodMétodo
JSON → DTOstatic fromMap(Map) (gera o lastSyncAt com DateTimeUtils.now())(generates lastSyncAt with DateTimeUtils.now())(genera el lastSyncAt con DateTimeUtils.now())
Proto → DTOtoDTO() (gera o lastSyncAt; renomeia digitalContent/imageRecognitionAuditsitems/audits)(generates lastSyncAt; renames digitalContent/imageRecognitionAuditsitems/audits)(genera el lastSyncAt; renombra digitalContent/imageRecognitionAuditsitems/audits)
DTO → EntitytoDomain() / toEntity() (parseia datas via DateTimeUtils.tryParse; resolve MerchandisingServiceTarget e ImageRecognitionStatus)(parses dates via DateTimeUtils.tryParse; resolves MerchandisingServiceTarget and ImageRecognitionStatus)(parsea fechas vía DateTimeUtils.tryParse; resuelve MerchandisingServiceTarget e ImageRecognitionStatus)
Entity → ModeltoModel() (popula ToMany/ToOne)(fills ToMany/ToOne)(llena ToMany/ToOne)
Model → EntitytoDomain() / toEntity()

Os únicos deltasThe only deltasLos únicos deltas

  • lastSyncAt nasce no DTO (não existe no proto nem no JSON): o mapper de fronteira o preenche com DateTimeUtils.now(). É DateTime em Assets/Options e DateTime? nos outros quatro.is born in the DTO (it exists neither in the proto nor in the JSON): the boundary mapper fills it with DateTimeUtils.now(). It is DateTime in Assets/Options and DateTime? in the other four.nace en el DTO (no existe ni en el proto ni en el JSON): el mapper de frontera lo completa con DateTimeUtils.now(). Es DateTime en Assets/Options y DateTime? en los otros cuatro.
  • datas StringDateTime? no Model (installed/lastModified/opening/lastStatus/closed/created/audited/upload), via DateTimeUtils.tryParse na entradadates StringDateTime? in the Model (installed/lastModified/opening/lastStatus/closed/created/audited/upload), via DateTimeUtils.tryParse on the way infechas StringDateTime? en el Model (installed/lastModified/opening/lastStatus/closed/created/audited/upload), vía DateTimeUtils.tryParse a la entrada
  • MerchandisingService.target StringMerchandisingServiceTarget? eandy ImageRecognitionAudit.status StringImageRecognitionStatustipados só na Entity; o rótulo cru é preservado em statusRawLabel para exibiçãotyped only in the Entity; the raw label is preserved in statusRawLabel for displaytipados solo en la Entity; el rótulo crudo se preserva en statusRawLabel para exhibición
  • renames de coleção no protocollection renames in the protorenames de colección en el proto: digitalContentitems, imageRecognitionAuditsaudits; eandy requiredisRequired (MerchandisingFieldRule), MerchandisingOptionsServiceFieldsMerchandisingServiceFieldConfig
  • relações viram ToMany/ToOne no Model; listas de String (displays, campaigns) permanecem primitivasrelations become ToMany/ToOne in the Model; String lists (displays, campaigns) stay primitiverelaciones pasan a ToMany/ToOne en el Model; listas de String (displays, campaigns) permanecen primitivas
  • MerchandisingAssetItem.status fica String na Entity; o enum MerchandisingAssetItemStatus é resolvido por fromWire na camada de estado, não no mapperstays String in the Entity; the MerchandisingAssetItemStatus enum is resolved by fromWire in the state layer, not the mapperqueda String en la Entity; el enum MerchandisingAssetItemStatus se resuelve por fromWire en la capa de estado, no en el mapper
  • campos opcionais do proto ganham default na Entity de Assets (familyName, isInstallation, isMaintenance); inImage do touchpoint faz o caminho inverso (bool no proto → bool? no DTO)optional proto fields gain a default in the Assets Entity (familyName, isInstallation, isMaintenance); the touchpoint's inImage goes the other way (bool in the proto → bool? in the DTO)campos opcionales del proto ganan default en la Entity de Assets (familyName, isInstallation, isMaintenance); el inImage del touchpoint hace el camino inverso (bool en el proto → bool? en el DTO)
08

Repository

São dois. MerchandisingRepositoryImpl implementa MerchandisingRepositoryInterface e cobre cinco agregados; ImageRecognitionRepositoryImpl cobre o sexto. Ambos injetam, por agregado, os 3 datasources (mock/local/remote) + ConnectivityService + a flag useMockData + Ref. A leitura é cache-first.There are two. MerchandisingRepositoryImpl implements MerchandisingRepositoryInterface and covers five aggregates; ImageRecognitionRepositoryImpl covers the sixth. Both inject, per aggregate, the 3 datasources (mock/local/remote) + ConnectivityService + the useMockData flag + Ref. The read is cache-first.Son dos. MerchandisingRepositoryImpl implementa MerchandisingRepositoryInterface y cubre cinco agregados; ImageRecognitionRepositoryImpl cubre el sexto. Ambos inyectan, por agregado, los 3 datasources (mock/local/remote) + ConnectivityService + la flag useMockData + Ref. La lectura es cache-first.

getMerchandising{X}({source}) árvore de decisão · idêntica nos seis agregadosdecision tree · identical across the six aggregatesárbol de decisión · idéntico en los seis agregados

Retorno: Future<Result<{X}Entity, Failure>>. O source default é DataSourceType.local — por isso o build inicial de toda tela é cache.Returns: Future<Result<{X}Entity, Failure>>. The default source is DataSourceType.local — that's why every screen's initial build is cache.Retorno: Future<Result<{X}Entity, Failure>>. El source default es DataSourceType.local — por eso el build inicial de toda pantalla es caché.

  1. useMockData == 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() (sem rede); cache vazio devolve Error(NetworkFailure())._fetchFromCacheOrFail() (no network); an empty cache returns Error(NetworkFailure())._fetchFromCacheOrFail() (sin red); un caché vacío devuelve Error(NetworkFailure()).
  3. senão (remoto + conectado)otherwise (remote + connected)si no (remoto + conectado)_fetchFromRemoteWithFallback(): lê o currentResourceProvider e usa resource.locationHierarchyId; se o resource for null, cai para o cache. Chama o RPC, mapeia, grava no cache; em erro, fallback pro cache. É o caminho do refresh()._fetchFromRemoteWithFallback(): reads currentResourceProvider and uses resource.locationHierarchyId; if the resource is null, it falls back to cache. Calls the RPC, maps, writes to cache; on error, falls back to cache. It's the refresh() path._fetchFromRemoteWithFallback(): lee el currentResourceProvider y usa resource.locationHierarchyId; si el resource es null, cae al caché. Llama al RPC, mapea, graba en caché; en error, fallback al caché. Es el camino del refresh().
Assets 4 métodosmethodsmétodos
MétodoMethodMétodoRetornoReturnRetorno
getMerchandisingAssets({source})Result<MerchandisingAssetsEntity, Failure>
getCachedMerchandisingAssets()Result<MerchandisingAssetsEntity?, Failure>
getCachedMerchandisingAssetsLastSyncAt()DateTime?
saveMerchandisingAssets({entity})Result<void, Failure> — usado pela correção de peça instalada— used by the installed-piece fix— usado por la corrección de pieza instalada
Options 4 métodosmethodsmétodos
MétodoMethodMétodoRetornoReturnRetorno
getMerchandisingOptions({source})Result<MerchandisingOptionsEntity, Failure>
getCachedMerchandisingOptions()Result<MerchandisingOptionsEntity?, Failure>
getCachedMerchandisingOptionsLastSyncAt()DateTime?
saveMerchandisingOptions({entity})Result<void, Failure>
Service Orders 4 métodosmethodsmétodos
MétodoMethodMétodoRetornoReturnRetorno
getMerchandisingServiceOrders({source})Result<MerchandisingServiceOrdersEntity, Failure>
getCachedMerchandisingServiceOrders()Result<MerchandisingServiceOrdersEntity?, Failure>
getCachedMerchandisingServiceOrdersLastSyncAt()DateTime?
saveMerchandisingServiceOrders({entity})Result<void, Failure>
Audit Results 4 métodosmethodsmétodos
MétodoMethodMétodoRetornoReturnRetorno
getMerchandisingAuditResults({source})Result<MerchandisingAuditResultsEntity, Failure>
getCachedMerchandisingAuditResults()Result<MerchandisingAuditResultsEntity?, Failure>
getCachedMerchandisingAuditResultsLastSyncAt()DateTime?
saveMerchandisingAuditResults({entity})Result<void, Failure>
Digital Content 4 métodosmethodsmétodos
MétodoMethodMétodoRetornoReturnRetorno
getMerchandisingDigitalContent({source})Result<MerchandisingDigitalContentEntity, Failure>
getCachedMerchandisingDigitalContent()Result<MerchandisingDigitalContentEntity?, Failure>
getCachedMerchandisingDigitalContentLastSyncAt()DateTime?
saveMerchandisingDigitalContent({entity})Result<void, Failure>
Image Recognition ImageRecognitionRepositoryInterface 3 métodosmethodsmétodos
MétodoMethodMétodoRetornoReturnRetorno
getImageRecognitionAudits({source})Result<ImageRecognitionAuditsEntity, Failure>
getCachedImageRecognitionAudits()Result<ImageRecognitionAuditsEntity?, Failure>
saveImageRecognitionAudits({entity})Result<void, Failure>

Não expõe …LastSyncAt() (a tela lê o lastSyncAt do próprio container). Particularidade: getCachedImageRecognitionAudits() hidrata pelo mock quando o cache está vazio e o app roda em modo mock.It exposes no …LastSyncAt() (the screen reads lastSyncAt off the container itself). Quirk: getCachedImageRecognitionAudits() hydrates from the mock when the cache is empty and the app runs in mock mode.No expone …LastSyncAt() (la pantalla lee el lastSyncAt del propio container). Particularidad: getCachedImageRecognitionAudits() hidrata por el mock cuando el caché está vacío y la app corre en modo mock.

09

Datasources

Cada agregado tem os 3 datasources. Remote chama o RPC do agregado e mapeia via toDTO(); Local persiste em ObjectBox (CRUD do container, singleton — o save limpa antes de gravar); Mock carrega JSON por mercado. Erro remoto: GrpcErrorGrpcExceptionHandler, demais → ServerException; erro local/mock → CacheException. O repository faz fallback pro cache.Each aggregate has the 3 datasources. Remote calls the aggregate RPC and maps via toDTO(); Local persists in ObjectBox (container CRUD, singletonsave clears before writing); Mock loads per-market JSON. Remote error: GrpcErrorGrpcExceptionHandler, others → ServerException; local/mock error → CacheException. The repository falls back to cache.Cada agregado tiene los 3 datasources. Remote llama el RPC del agregado y mapea vía toDTO(); Local persiste en ObjectBox (CRUD del container, singleton — el save limpia antes de grabar); Mock carga JSON por mercado. Error remoto: GrpcErrorGrpcExceptionHandler, demás → ServerException; error local/mock → CacheException. El repository hace fallback al caché.

Assets MerchandisingAssets{Remote|Local|Mock}DataSource
Remote
getMerchandisingAssets({locationHierarchySfid, lastModifiedDate})MerchandisingAssetsDTO
Local
ObjectBox MerchandisingAssetsModel · get…() / …LastSyncAt() / save…() / clear…()
Mock
assets/mocks/merchandising/assets/jsons/{market}_merchandising_assets.jsonfromMap
Options MerchandisingOptions{Remote|Local|Mock}DataSource
Remote
getMerchandisingOptions({locationHierarchySfid, lastModifiedDate})MerchandisingOptionsDTO
Local
ObjectBox MerchandisingOptionsModel
Mock
assets/mocks/merchandising/options/jsons/{market}_merchandising_options.json
Service Orders MerchandisingServiceOrders{Remote|Local|Mock}DataSource
Remote
getMerchandisingServiceOrders({locationHierarchySfid, lastModifiedDate})MerchandisingServiceOrdersDTO
Local
ObjectBox MerchandisingServiceOrdersModel
Mock
assets/mocks/merchandising/service_orders/jsons/{market}_merchandising_service_orders.json
Audit Results MerchandisingAuditResults{Remote|Local|Mock}DataSource
Remote
getMerchandisingAuditResults({locationHierarchySfid, lastModifiedDate})MerchandisingAuditResultsDTO
Local
ObjectBox MerchandisingAuditResultsModel · clear em cascata: touchpoints → campanhas → peças → auditorias → containerclear cascades: touchpoints → campaigns → pieces → audits → containerclear en cascada: touchpoints → campañas → piezas → auditorías → container
Mock
assets/mocks/merchandising/audit_results/jsons/{market}_merchandising_audit_results.json
Digital Content MerchandisingDigitalContent{Remote|Local|Mock}DataSource
Remote
getMerchandisingDigitalContent({locationHierarchySfid, lastModifiedDate})MerchandisingDigitalContentDTO
Local
ObjectBox MerchandisingDigitalContentModel
Mock
assets/mocks/merchandising/digital_content/jsons/{market}_merchandising_digital_content.json
Image Recognition ImageRecognitionAudits{Remote|Local|Mock}DataSource
Remote
getImageRecognitionAudits({locationHierarchySfid, lastModifiedDate})ImageRecognitionAuditsDTO
Local
ObjectBox ImageRecognitionAuditsModel
Mock
assets/mocks/merchandising/image_recognition/jsons/{market}_image_recognition_audits.json
10

Enums e labelsEnums & labelsEnums y labels

Os enums do domínio vivem em core/enums/merchandising/, core/enums/os_merchandising/ e core/enums/image_recognition/. Desde a unificação do menu, identidade e navegação são enums separados: MerchandisingOptionType responde por ícone/label/agrupamento, e MerchandisingDestination por para onde o cartão leva. Lista completa de valores:The domain enums live in core/enums/merchandising/, core/enums/os_merchandising/ and core/enums/image_recognition/. Since the menu was unified, identity and navigation are separate enums: MerchandisingOptionType answers for icon/label/grouping, and MerchandisingDestination for where the card leads. Full value list:Los enums del dominio viven en core/enums/merchandising/, core/enums/os_merchandising/ e core/enums/image_recognition/. Desde la unificación del menú, identidad y navegación son enums separados: MerchandisingOptionType responde por ícono/label/agrupación, y MerchandisingDestination por a dónde lleva la tarjeta. Lista completa de valores:

MerchandisingDestination 13 · value
casevalueAbreOpensAbre
submenu"submenu"MerchandisingMenuPage(group: option.type)
shelfWatchLaunch"shelfwatch_launch"ShelfWatchLaunchAction.run(deepLinkUrl)
shelfWatchAssets"shelfwatch_assets"ShelfWatchPage
imageAuditWithPiece"image_audit_with_piece"OsMerchandisingRetailAuditPage(withPiece)
imageAuditWithoutPiece"image_audit_without_piece"OsMerchandisingRetailAuditPage(withoutPiece)
imageRecognitionForm"image_recognition_form"ImageRecognitionAuditPage
imageRecognitionList"image_recognition_list"ImageRecognitionAuditsListPage
auditResultsList"audit_results_list"MerchandisingAuditResultsListPage
auditUnitForm"audit_unit_form"OsMerchandisingAuditPage
serviceOrderForm"service_order_form"OsMerchandisingLogSnagSpecificationsPage
serviceOrderList"service_order_list"OsMerchandisingServiceOrdersListPage
assetItemsList"asset_items_list"MerchandisingAssetItemsPage
unknown"unknown"nada (cartão não é renderizado)nothing (card is not rendered)nada (la tarjeta no se renderiza)
MerchandisingOptionType 18 · value
casevaluePapelRolePapel
audit"audit"grupogroupgrupo
serviceOrder"service_order"grupogroupgrupo
auditUnit"audit_unit"cartãocardtarjeta
assetItems"asset_items"cartãocardtarjeta
merchan"merchan"cartão · legadocard · legacytarjeta · legado
retailAudit"retail_audit"cartão · legadocard · legacytarjeta · legado
activity"activity"toggle de campofield toggletoggle de campo
service"service"toggle de campofield toggletoggle de campo
reason"reason"toggle de campofield toggletoggle de campo
newAudit"new_audit"cartãocardtarjeta
auditsList"audits_list"cartãocardtarjeta
newImageRecognitionAudit"new_image_recognition_audit"cartãocardtarjeta
imageRecognitionAuditsList"image_recognition_audits_list"cartãocardtarjeta
retailWithPiece"retail_with_piece"cartãocardtarjeta
retailWithoutPiece"retail_without_piece"cartãocardtarjeta
newServiceOrder"new_os"cartãocardtarjeta
serviceOrdersList"view_os"cartãocardtarjeta
unknown"unknown"descartadodiscardeddescartado
ImageRecognitionStatus 3 · wireValue
casewireValue
matched"Acertou"
missed"Errou"
pending""
MerchandisingAuditCondition 4 · code · wireLabel
casecodewireLabel
good"good""Good"
scuffed"scuffed""Scuffed"
damagedRepairable"damaged_repairable""Damaged-Repairable"
damagedBeyondRepair"damaged_beyond_repair""Damaged-Beyond Repair"
MerchandisingAssetItemStatus 6 · value
casevalue
installationRequested"installation_requested"
installed"installed"
removalRequested"removal_requested"
underRepair"under_repair"
uninstalled"uninstalled"
unknown""
MerchandisingActivityKind 4 · activityCode
caseactivityCode
installation"1"
maintenance"4"
substitution"2"
other""
MerchandisingMovement 4 · wireValue
casewireValue
none""
maintenance"M"
remove"R"
install"I"
MerchandisingServiceTarget 3 · value
casevalue
assets"assets"
items"items"
both"both"
MerchandisingDigitalContentKey 2 · name
casenamei18n key
installationGuide"CL_MERCHGUIDE"merchandising_digital_content_installation_guide
retailUnitInfo"CL_MERCHWEB"merchandising_digital_content_retail_unit_info
MerchandisingBarcodeError 2 · i18n key
casei18n key
trailingSeparatormerchandising_asset_item_barcode_invalid_trailing
segmentLengthmerchandising_asset_item_barcode_invalid_segment
MerchandisingPieceBrand 5 · value
casevalue
bat"BAT"
pmi"PMI"
jti"JTI"
ownPiece"Peça própria"
unknown"unknown"
RetailAuditMode 2
case
withPiece
withoutPiece
RetailAuditPhotoSlot 2
case
front
back
11

UseCases

Dois grupos: os de leitura (delegam ao repository) e os de escrita (build de payload + submit ao Dispatcher). Os …ForAccount filtram o agregado pelo varejo da visita, preservando o lastSyncAt do container.Two groups: the read ones (delegate to the repository) and the write ones (payload build + submit to the Dispatcher). The …ForAccount ones filter the aggregate by the visit's retail, preserving the container's lastSyncAt.Dos grupos: los de lectura (delegan al repository) y los de escritura (build de payload + submit al Dispatcher). Los …ForAccount filtran el agregado por el punto de venta de la visita, preservando el lastSyncAt del container.

Leitura 10 UseCases
UseCaseMétodo → RetornaMethod → ReturnsMétodo → Devuelve
GetMerchandisingAssetsUseCaseexecute({source}), getCached(), getCachedLastSyncAt()Result<MerchandisingAssetsEntity…> / DateTime?
GetMerchandisingAssetsForAccountUseCaseexecute({accountSfid, source})Result<MerchandisingAssetsEntity, Failure>
SaveMerchandisingAssetItemUseCaseexecute({item})Result<void, Failure> — substitui um item dentro do agregado cacheado— replaces one item inside the cached aggregate— sustituye un ítem dentro del agregado cacheado
GetMerchandisingOptionsUseCaseexecute({source}), getCached(), getCachedLastSyncAt()Result<MerchandisingOptionsEntity…>
GetMerchandisingServiceOrdersUseCaseexecute({source}), getCached(), getCachedLastSyncAt()Result<MerchandisingServiceOrdersEntity…>
GetMerchandisingServiceOrdersForAccountUseCaseexecute({accountSfid, source})Result<MerchandisingServiceOrdersEntity, Failure>
GetMerchandisingAuditResultsUseCaseexecute({source}), getCached(), getCachedLastSyncAt()Result<MerchandisingAuditResultsEntity…>
GetMerchandisingAuditResultsForAccountUseCaseexecute({accountSfid, source})Result<MerchandisingAuditResultsEntity, Failure>
GetMerchandisingDigitalContentUseCaseexecute({source}), getCached(), getCachedLastSyncAt()Result<MerchandisingDigitalContentEntity…> — sem variante por conta; o filtro mora na entity— no per-account variant; the filter lives in the entity— sin variante por cuenta; el filtro vive en la entity
GetImageRecognitionAuditsUseCaseexecute({source}), getCached()Result<ImageRecognitionAuditsEntity…>
Escrita · build + submit 7 transaçõestransactionstransacciones

Cada Build…UseCase implementa DispatcherPayloadBuilder (build({input})DispatcherEnvelope); o Submit…UseCase despacha pelo DispatcherOrchestrator. A última coluna liga à doc da transação.Each Build…UseCase implements DispatcherPayloadBuilder (build({input})DispatcherEnvelope); the Submit…UseCase dispatches via the DispatcherOrchestrator. The last column links to the transaction doc.Cada Build…UseCase implementa DispatcherPayloadBuilder (build({input})DispatcherEnvelope); el Submit…UseCase despacha vía DispatcherOrchestrator. La última columna enlaza a la doc de la transacción.

Builder → SubmitBuilder → SubmitBuilder → SubmitDispatcherType · serviceNameTransaçãoTransactionTransacción
BuildRetailAuditUploadDispatcherPayloadUseCaseSubmitRetailAuditUploadUseCasemerchandisingImageAudit · ImageAudit17_image_audit
BuildMerchandisingCreationDispatcherPayloadUseCaseSubmitMerchandisingServiceOrderUseCasemerchandisingCreation · CreateMerchan18_create_merchan
BuildMerchandisingAuditUnitDispatcherPayloadUseCaseSubmitMerchandisingAuditUnitUseCasemerchandisingAuditUnit · AuditUnitReport19_audit_unit_report
BuildLogSnagDispatcherPayloadUseCaseSubmitLogSnagUseCasemerchandisingAssetItemTracking · AssetItemTrackingUploadAPI20_asset_item_tracking
BuildMerchandisingAnnotationDispatcherPayloadUseCaseSubmitMerchandisingAnnotationUseCasemerchandisingAnnotation · CreateMerchanAnnotation21_create_merchan_annotation
BuildMerchandisingServiceOrderDispatcherPayloadUseCaseSubmitMerchandisingServiceOrderUseCasemerchandisingServiceOrder · BPOneServiceOrderUpsert22_bpone_service_order
BuildImageRecognitionAuditDispatcherPayloadUseCaseSubmitImageRecognitionAuditUseCaseimageRecognitionAudit · ServiceMerchanAuditsem doc dedicada aindano dedicated doc yetsin doc dedicada aún

SubmitLogSnagUseCase.submit({envelopes}) recebe uma lista e despacha em paralelo (Future.wait) — é o único que envia N envelopes; os demais enviam um só.SubmitLogSnagUseCase.submit({envelopes}) takes a list and dispatches in parallel (Future.wait) — it's the only one sending N envelopes; the others send just one.SubmitLogSnagUseCase.submit({envelopes}) recibe una lista y despacha en paralelo (Future.wait) — es el único que envía N sobres; los demás envían uno solo.

12

Notifiers & State

Dez notifiers @riverpod, todos family por visitSfid (o do menu também por group). Os de menu/lista usam AsyncGuard e um refresh() remoto; os formulários carregam config + agregados no build() e mutam o State a cada interação. Toda escrita mora no notifier (§39); a UI só chama seus métodos.Ten @riverpod notifiers, all family by visitSfid (the menu one also by group). Menu/list ones use AsyncGuard and a remote refresh(); the forms load config + aggregates in build() and mutate State on each interaction. Every write lives in the notifier (§39); the UI only calls its methods.Diez notifiers @riverpod, todos family por visitSfid (el del menú también por group). Los de menú/lista usan AsyncGuard y un refresh() remoto; los formularios cargan config + agregados en el build() y mutan el State en cada interacción. Toda escritura vive en el notifier (§39); la UI solo llama sus métodos.

MenuMenuMenú

MétodosMethodsMétodos

MerchandisingMenuNotifier family (visitSfid, group?)
build({visitSfid, group})
FutureOr<MerchandisingMenuState>resolve a visita (visitContextProvider) e o marketConfigurationProvider; carrega Assets + Options em paralelo só para o lastSyncAt (falha vira breadcrumb, não quebra a tela).resolves the visit (visitContextProvider) and marketConfigurationProvider; loads Assets + Options in parallel just for lastSyncAt (a failure becomes a breadcrumb, it doesn't break the screen).resuelve la visita (visitContextProvider) y el marketConfigurationProvider; carga Assets + Options en paralelo solo para el lastSyncAt (una falla se vuelve breadcrumb, no rompe la pantalla).
refresh()
Future<void>recarrega com DataSourceType.remote, preservando visitSfid e group do state atual.reloads with DataSourceType.remote, preserving the current state's visitSfid and group.recarga con DataSourceType.remote, preservando visitSfid y group del state actual.

O coração é privado: _resolveOptions devolve config.navigableOptions na raiz e config.optionFor(type: group)?.navigableOptions no submenu — grupo inexistente resulta em lista vazia (header sem grade).The core is private: _resolveOptions returns config.navigableOptions at the root and config.optionFor(type: group)?.navigableOptions in a submenu — a non-existent group yields an empty list (header with no grid).El corazón es privado: _resolveOptions devuelve config.navigableOptions en la raíz y config.optionFor(type: group)?.navigableOptions en el submenú — un grupo inexistente resulta en lista vacía (header sin grilla).

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

MerchandisingMenuState 6 campos · 1 getterfields · 1 gettercampos · 1 getter
CampoFieldCampoTipoTypeTipo
visitSfidString
accountAccountDataEntity
groupMerchandisingOptionType?
lastSyncAtDateTime?
shelfWatchDeepLinkUrlString?
optionsList<MerchandisingOption>
isRootboolgroup == null

Listas (só leitura)Lists (read-only)Listas (solo lectura)

MerchandisingAuditResultsListNotifier

build({visitSfid}) busca as auditorias do varejo via GetMerchandisingAuditResultsForAccountUseCase (cache) e ordena por createdAt desc. refresh()Future<Failure?>: refaz remoto e, em erro, devolve a falha sem alterar o state (a Page mostra um aviso). toggleExpanded({id}) permite vários cartões abertos ao mesmo tempo.build({visitSfid}) fetches the retail's audits via GetMerchandisingAuditResultsForAccountUseCase (cache) and sorts by createdAt desc. refresh()Future<Failure?>: refetches remote and, on error, returns the failure without touching the state (the Page shows a notice). toggleExpanded({id}) allows several cards open at once.build({visitSfid}) busca las auditorías del punto de venta vía GetMerchandisingAuditResultsForAccountUseCase (caché) y ordena por createdAt desc. refresh()Future<Failure?>: rehace remoto y, en error, devuelve la falla sin alterar el state (la Page muestra un aviso). toggleExpanded({id}) permite varios cartones abiertos a la vez.

State: visitSfid, account, lastSyncAt, audits: List<MerchandisingAuditResultEntity>, expandedAuditIds: Set<String> · getters isEmpty, isExpanded({id}).

ImageRecognitionAuditsListNotifier

build({visitSfid}) carrega do cache e filtra por accountCode do varejo. refresh()Future<Failure?>: se offline devolve NetworkFailure sem mexer no state; online, refaz remoto.build({visitSfid}) loads from cache and filters by the retail's accountCode. refresh()Future<Failure?>: if offline it returns NetworkFailure without touching the state; online, it refetches remote.build({visitSfid}) carga del caché y filtra por accountCode del punto de venta. refresh()Future<Failure?>: si está offline devuelve NetworkFailure sin tocar el state; online, rehace remoto.

State: visitSfid, account, lastSyncAt, audits · getters batAudits / competitorAudits (separados por isCompetitorSection, que só vale para auditorias após a data de corte), hasAudits, auditCount.

OsMerchandisingServiceOrdersListNotifier

Busca as OS do varejo via GetMerchandisingServiceOrdersForAccountUseCase; refresh() força remoto. Métodos: toggleExpanded({orderId}).Fetches the retail's SOs via GetMerchandisingServiceOrdersForAccountUseCase; refresh() forces remote. Methods: toggleExpanded({orderId}).Busca las OS del punto de venta vía GetMerchandisingServiceOrdersForAccountUseCase; refresh() fuerza remoto. Métodos: toggleExpanded({orderId}).

State: serviceOrders: List<MerchandisingServiceOrderEntity>, expandedOrderIds: Set<String>.

ShelfWatchNotifier

Lê os ativos do ShelfWatch de dentro da própria visita (visit.shelfWatch) — não é um agregado de merchandising. refresh()Future<Failure?> refaz a visita remota e invalida o visitContextProvider.Reads the ShelfWatch assets from the visit itself (visit.shelfWatch) — it is not a merchandising aggregate. refresh()Future<Failure?> refetches the visit remotely and invalidates visitContextProvider.Lee los activos de ShelfWatch de dentro de la propia visita (visit.shelfWatch) — no es un agregado de merchandising. refresh()Future<Failure?> rehace la visita remota e invalida el visitContextProvider.

State: visitSfid, account, lastSyncAt, deepLinkUrl: String?, assets: List<ShelfWatchAssetEntity> · getter isEmpty.

Formulários (escrita)Forms (write)Formularios (escritura)

MerchandisingAssetItemsNotifier → AssetItemTrackingUploadAPI

build() carrega os assets do varejo + o conteúdo digital (falha do conteúdo digital degrada em silêncio) e monta uma lista plana de peças, excluindo as desinstaladas. Cada ação envia um envelope isolado e, só em caso de sucesso, atualiza a lista em memória e o cache local.build() loads the retail's assets + the digital content (a digital-content failure degrades silently) and builds a flat list of pieces, excluding uninstalled ones. Each action sends one isolated envelope and, only on success, updates the in-memory list and the local cache.build() carga los assets del punto de venta + el contenido digital (una falla del contenido digital degrada en silencio) y arma una lista plana de piezas, excluyendo las desinstaladas. Cada acción envía un sobre aislado y, solo en caso de éxito, actualiza la lista en memoria y el caché local.

refresh()
Future<void>
submitBarcode({entry, barcode})
Future<MerchandisingAssetItemUpdate>valor vazio marca removesBarcode e o builder envia Delete.an empty value flags removesBarcode and the builder sends Delete.un valor vacío marca removesBarcode y el builder envía Delete.
submitPhoto({entry, source})
Future<MerchandisingAssetItemUpdate>captura pela câmera; cancelar não envia nada.camera capture; cancelling sends nothing.captura por cámara; cancelar no envía nada.

State: visitSfid, account, lastSyncAt, entries: List<MerchandisingAssetItemEntry>, digitalContent, submittingItemSfids: Set<String>, submissionStatus · getters isEmpty, isSubmitting({itemSfid}), campaign, digitalContentUrlFor({key}), availableDigitalContentKeys. MerchandisingAssetItemUpdate é o record ({bool didSubmit, Failure? failure}).

ImageRecognitionAuditNotifier → ServiceMerchanAudit

Sessão de captura criada no build() e limpa no onDispose. Métodos: capturePhoto(), updatePhotoLabel({filePath, label}), removePhoto({filePath}), submit() (converte cada foto em base64 e envia um envelope) e resetSubmissionStatus(). Sucesso limpa as fotos.Capture session created in build() and cleaned up in onDispose. Methods: capturePhoto(), updatePhotoLabel({filePath, label}), removePhoto({filePath}), submit() (converts each photo to base64 and sends one envelope) and resetSubmissionStatus(). Success clears the photos.Sesión de captura creada en el build() y limpiada en el onDispose. Métodos: capturePhoto(), updatePhotoLabel({filePath, label}), removePhoto({filePath}), submit() (convierte cada foto en base64 y envía un sobre) y resetSubmissionStatus(). El éxito limpia las fotos.

State: visitSfid, account, sessionId, lastSyncAt, photos: List<ImageRecognitionPhotoEntity>, submissionStatus · getters hasPhotos, photoCount, canSubmit.

OsMerchandisingAuditNotifier → AuditUnitReport

build(): carrega os assets do varejo e resolve as condições de merchandisingAuditConditions (EMC). Métodos: selectAsset, selectCondition, captureUnitPhoto (até 3), scanBarcode/captureBarcodePhoto, submitAudit().build(): loads the retail's assets and resolves conditions from merchandisingAuditConditions (EMC). Methods: selectAsset, selectCondition, captureUnitPhoto (up to 3), scanBarcode/captureBarcodePhoto, submitAudit().build(): carga los assets del punto de venta y resuelve las condiciones de merchandisingAuditConditions (EMC). Métodos: selectAsset, selectCondition, captureUnitPhoto (hasta 3), scanBarcode/captureBarcodePhoto, submitAudit().

State: availableAssets, availableConditions, selectedAsset, selectedCondition, unitPhotos (máx 3), barcodeValue, barcodePhoto, submissionStatus · getter canSubmit exige ativo + condição + código + foto do código + ≥1 foto de unidade.

OsMerchandisingRetailAuditNotifier → ImageAudit

Recebe mode (withPiece/withoutPiece). Gerencia até 10 peças (RetailAuditPieceEntry: marca, aéreo-com-porta, foto frente/verso). Métodos: adicionar/remover peça, definir marca, capturar foto por slot, submit().Receives mode (withPiece/withoutPiece). Manages up to 10 pieces (RetailAuditPieceEntry: brand, aerial-with-door, front/back photo). Methods: add/remove piece, set brand, capture photo per slot, submit().Recibe mode (withPiece/withoutPiece). Gestiona hasta 10 piezas (RetailAuditPieceEntry: marca, aéreo-con-puerta, foto frente/dorso). Métodos: agregar/quitar pieza, definir marca, capturar foto por slot, submit().

State: mode, pieces: List<RetailAuditPieceEntry> (máx 10 / 1 no modo sem peça), submissionStatus · canSubmit exige toda peça completa (foto frente + verso quando aéreo-com-porta).

OsMerchandisingLogSnagNotifier → AssetItemTracking / CreateMerchan+BPOne / Annotation

O mais complexo: 3 passos (especificações → peças → resumo) e três rotas de envio. build() carrega Options + Assets + config (usesInstalledAssetItems e o bloco fields). Seleção: selectActivity/Service/Reason/Asset/PieceType, quantidade, comentário, código, fotos por item (sessão de captura com cleanup no onDispose).The most complex: 3 steps (specifications → pieces → summary) and three submit routes. build() loads Options + Assets + config (usesInstalledAssetItems and the fields block). Selection: selectActivity/Service/Reason/Asset/PieceType, quantity, comment, barcode, per-item photos (capture session cleaned up in onDispose).El más complejo: 3 pasos (especificaciones → piezas → resumen) y tres rutas de envío. build() carga Options + Assets + config (usesInstalledAssetItems y el bloque fields). Selección: selectActivity/Service/Reason/Asset/PieceType, cantidad, comentario, código, fotos por ítem (sesión de captura con cleanup en el onDispose).

  • submitLogSnag() · usesInstalledAssetItems == true_submitAssetItemTracking: um envelope por item selecionado, enviados em paralelo.one envelope per selected item, sent in parallel.un sobre por ítem seleccionado, enviados en paralelo.
  • submitLogSnag() · false (usesWorkflowOutsideCrm) → _submitServiceOrder: dois envelopes sequenciais — CreateMerchan (falha só vira breadcrumb) + BPOneServiceOrderUpsert (é o que define sucesso/falha).two sequential envelopes — CreateMerchan (a failure only becomes a breadcrumb) + BPOneServiceOrderUpsert (this one decides success/failure).dos sobres secuenciales — CreateMerchan (una falla solo se vuelve breadcrumb) + BPOneServiceOrderUpsert (este define éxito/falla).
  • submitMeasurement() · isMeasurementsó uma anotação de texto → CreateMerchanAnnotation.just a text annotation → CreateMerchanAnnotation.solo una anotación de texto → CreateMerchanAnnotation.

State (parcial): availableActivities, availableAssets, selectedActivity/Service/Reason/Asset, selectedPieceType, selectedItemSfids, quantities, itemComments, itemPhotos, itemBarcodes, annotation, fields: MerchandisingFieldVisibility, submissionStatus · getters isActivityVisible/Active, isServiceVisible/Active, isReasonVisible/Active, usesWorkflowOutsideCrm; validação por campo deriva do MerchandisingServiceFieldConfig.

13

Telas e widgetsScreens & widgetsPantallas y widgets

Todo o módulo vive em lib/presentation/merchandising/. As telas são ConsumerWidget sobre AppPageShell com botão de voltar, abertas pela grade de ferramentas da visita. A mesma MerchandisingMenuPage serve raiz e submenus — o que muda é o parâmetro group. Os modais aparecem aninhados sob a tela que os abre. Árvore de navegação + composição:The whole module lives in lib/presentation/merchandising/. Screens are ConsumerWidgets over AppPageShell with a back button, opened from the visit's tools grid. The same MerchandisingMenuPage serves root and submenus — only the group parameter changes. Modals appear nested under the screen that opens them. Navigation + composition tree:Todo el módulo vive en lib/presentation/merchandising/. Las pantallas son ConsumerWidget sobre AppPageShell con botón de volver, abiertas desde la grilla de herramientas de la visita. La misma MerchandisingMenuPage sirve raíz y submenús — lo que cambia es el parámetro group. Los modales aparecen anidados bajo la pantalla que los abre. Árbol de navegación + composición:

  • VisitDetailToolsGridWidget visit_detail → goToOsMerchandising(visitSfid)
    • MerchandisingMenuPage group: null · raiz · DataLoadInfo · AccountHeaderCard · MerchandisingMenuHeaderWidget · MerchandisingOptionCardsWidget
      • MerchandisingMenuPage group: audit · submenu
        • ImageRecognitionAuditPage imageRecognitionForm → ServiceMerchanAudit
          • ImageRecognitionPhotoTileWidget miniatura · rótulo · remover
          • ImageRecognitionLabelModalContent modal → updatePhotoLabel()
          • ImageRecognitionAuditSubmitConfirmationModalContent modal → submit()
        • ImageRecognitionAuditsListPage imageRecognitionList · seções BAT / concorrência · só leitura
        • MerchandisingAuditResultsListPage auditResultsList · MerchandisingAuditResultCardWidget · só leitura
        • MerchandisingMenuPage group: newAudit · submenu (BR UAT)
          • OsMerchandisingRetailAuditPage imageAuditWithPiece / withoutPiece → ImageAudit
            • OsMerchandisingRetailAuditPieceCardWidget
            • OsMerchandisingRetailAuditNewPieceModalContent modal
            • OsMerchandisingRetailAuditSubmitConfirmationModalContent modal → submit()
        • ShelfWatchLaunchAction shelfWatchLaunch · deep link p/ app externo (sem tela)
        • ShelfWatchPage shelfWatchAssets
          • ShelfWatchAssetCardWidget + barra inferior que lança o app
        • OsMerchandisingAuditPage auditUnitForm → AuditUnitReport
          • OsMerchandisingAuditFormWidget barcode section · photos section
          • BarcodeScannerPage scan
          • OsMerchandisingAuditSubmitConfirmationModalContent modal → submitAudit()
      • MerchandisingMenuPage group: serviceOrder · submenu (BR/CL)
        • OsMerchandisingLogSnag (3 páginas) serviceOrderForm
          • OsMerchandisingLogSnagSpecificationsPage atividade · serviço · motivo (visibilidade pelo bloco fields) · medição → anotação
          • OsMerchandisingLogSnagPieceTypesPage tipos · quantidade · fotos · código · comentário
          • OsMerchandisingLogSnagSummaryPage
            • OsMerchandisingLogSnagSummaryListWidget
            • OsMerchandisingLogSnagSubmitConfirmationModalContent modal → submitLogSnag() / submitMeasurement()
        • OsMerchandisingServiceOrdersListPage serviceOrderList · OsMerchandisingServiceOrderCardWidget
        • MerchandisingAssetItemsPage assetItemsList → AssetItemTrackingUploadAPI (1 envio por ação)
          • MerchandisingDigitalContentWidget campanha do varejo + atalhos globais (abrem no navegador)
          • MerchandisingAssetItemCardWidget miniatura · código de barras · status
          • MerchandisingAssetItemBarcodeModalContent modal → submitBarcode()

A árvore mostra todos os destinos possíveis; nenhum mercado exibe todos ao mesmo tempo (ver ★ Mercados). Quando um grupo é declarado sem filhos — o caso da OS na ZA — o cartão deixa de ser submenu e abre o destino direto.The tree shows every possible destination; no market shows them all at once (see ★ Markets). When a group is declared with no children — the ZA service order case — the card stops being a submenu and opens the destination directly.El árbol muestra todos los destinos posibles; ningún mercado los exhibe todos a la vez (ver ★ Mercados). Cuando un grupo se declara sin hijos — el caso de la OS en ZA — la tarjeta deja de ser submenú y abre el destino directo.

Notas por mercadoMarket notesNotas por mercado

Merchandising é habilitado pela ferramenta merchandising na grade da visita e pelo merchandisingConfig do End Market Configuration — presente em três mercados. Os três declaram os mesmos dois grupos; o que muda são os destinos, a visibilidade e a flag usesInstalledAssetItems.Merchandising is enabled by the merchandising tool in the visit grid and by the End Market Configuration merchandisingConfig — present in three markets. All three declare the same two groups; what changes are the destinations, visibility and the usesInstalledAssetItems flag.Merchandising se habilita por la herramienta merchandising en la grilla de la visita y por el merchandisingConfig del End Market Configuration — presente en tres mercados. Los tres declaran los mismos dos grupos; lo que cambia son los destinos, la visibilidad y la flag usesInstalledAssetItems.

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

Os cartões declarados por mercado e ambiente — uma linha por opção. PROD e PREPROD são idênticos; só o grupo audit do BR muda em UAT.The cards declared per market and environment — one row per option. PROD and PREPROD are identical; only BR's audit group changes in UAT.Las tarjetas declaradas por mercado y ambiente — una fila por opción. PROD y PREPROD son idénticos; solo el grupo audit de BR cambia en UAT.

Mercado · ambienteMarket · envMercado · ambientenamedestinationVisívelVisibleVisible
BR · PROD/PREPRODauditsubmenux
BR · PROD/PREPRODaudit ▸ new_auditimage_recognition_formx
BR · PROD/PREPRODaudit ▸ audits_listimage_recognition_listx
BR · UATaudit ▸ new_auditsubmenux
BR · UATaudit ▸ new_audit ▸ retail_with_pieceimage_audit_with_piecex
BR · UATaudit ▸ new_audit ▸ retail_without_pieceimage_audit_without_piecex
BR · UATaudit ▸ audits_listaudit_results_listx
BR · todosalltodosservice_ordersubmenux
BR · todosalltodosservice_order ▸ new_osservice_order_formx
BR · todosalltodosservice_order ▸ view_osservice_order_listx
CL · todosalltodosauditsubmenux
CL · todosalltodosaudit ▸ new_auditshelfwatch_launchx
CL · todosalltodosaudit ▸ audits_listshelfwatch_assetsx
CL · todosalltodosservice_ordersubmenux
CL · todosalltodosservice_order ▸ new_osservice_order_formx
CL · todosalltodosservice_order ▸ asset_itemsasset_items_listx
ZA · todosalltodosauditsubmenux
ZA · todosalltodosaudit ▸ new_auditshelfwatch_launchx
ZA · todosalltodosaudit ▸ audits_listshelfwatch_assetsfalse
ZA · todosalltodosaudit ▸ audit_unitaudit_unit_formx
ZA · todosalltodosservice_orderservice_order_formx

O bloco fields do merchandisingConfig (visibilidade dos campos do log snag), idêntico nos três ambientes — uma linha por campo:The merchandisingConfig fields block (log snag field visibility), identical across the three environments — one row per field:El bloque fields del merchandisingConfig (visibilidad de los campos del log snag), idéntico en los tres ambientes — una fila por campo:

CampoFieldCampoBRCLZAARPYPE
activityxxx
servicexxx
reasonxfalsefalse

As sete transações de escrita, por mercado (DispatcherType.enabledMarkets) — uma linha por transação:The seven write transactions, per market (DispatcherType.enabledMarkets) — one row per transaction:Las siete transacciones de escritura, por mercado (DispatcherType.enabledMarkets) — una fila por transacción:

Transação · serviceNameTransaction · serviceNameTransacción · serviceNameBRCLZAARPYPE
ImageAudit · auditoria de PDVretail auditauditoría de PDVx
ServiceMerchanAudit · reconhecimento de imagemimage recognitionreconocimiento de imagenx
CreateMerchan · criaçãocreationcreaciónx
AuditUnitReport · auditoria de unidadeunit auditauditoría de unidadx
AssetItemTrackingUploadAPI · log snag + peças instaladasinstalled piecespiezas instaladasxx
CreateMerchanAnnotation · mediçãomeasurementmediciónx
BPOneServiceOrderUpsert · OSx
BR

Fluxo fora do CRM · fornecedor por ambienteWorkflow outside CRM · vendor per environmentFlujo fuera del CRM · proveedor por ambiente usesInstalledAssetItems = false: o log snag envia criação + OS (CreateMerchan + BPOneServiceOrderUpsert); medição envia CreateMerchanAnnotation. A auditoria de varejo tem dois fornecedores mutuamente exclusivos, alternados pelo destino de um único botão: reconhecimento de imagem em PROD/PREPROD e auditoria de imagem em UAT. A auditoria de unidade e as peças instaladas não rodam aqui. usesInstalledAssetItems = false: the log snag sends creation + SO (CreateMerchan + BPOneServiceOrderUpsert); measurement sends CreateMerchanAnnotation. The retail audit has two mutually exclusive vendors, switched by a single button's destination: image recognition in PROD/PREPROD and image audit in UAT. The unit audit and installed pieces do not run here. usesInstalledAssetItems = false: el log snag envía creación + OS (CreateMerchan + BPOneServiceOrderUpsert); la medición envía CreateMerchanAnnotation. La auditoría de PDV tiene dos proveedores mutuamente excluyentes, alternados por el destino de un único botón: reconocimiento de imagen en PROD/PREPROD y auditoría de imagen en UAT. La auditoría de unidad y las piezas instaladas no corren aquí.

CL

ShelfWatch + peças instaladasShelfWatch + installed piecesShelfWatch + piezas instaladas usesInstalledAssetItems = true: o log snag envia rastreio de item de ativo, um envelope por peça. Auditoria = ShelfWatch (lançar o app ou ver as peças — é o único mercado com shelfWatchConfig.hasAssetList = true). É também o único com a tela de peças instaladas e com conteúdo digital (as chaves são prefixadas CL_). O campo motivo do log snag fica oculto. usesInstalledAssetItems = true: the log snag sends asset-item tracking, one envelope per piece. Audit = ShelfWatch (launch the app or view the pieces — it's the only market with shelfWatchConfig.hasAssetList = true). It's also the only one with the installed pieces screen and with digital content (the keys are CL_-prefixed). The log snag's reason field is hidden. usesInstalledAssetItems = true: el log snag envía rastreo de ítem de activo, un sobre por pieza. Auditoría = ShelfWatch (lanzar la app o ver las piezas — es el único mercado con shelfWatchConfig.hasAssetList = true). Es también el único con la pantalla de piezas instaladas y con contenido digital (las claves están prefijadas CL_). El campo motivo del log snag queda oculto.

ZA

Auditoria de unidade · OS sem submenuUnit audit · SO without submenuAuditoría de unidad · OS sin submenú usesInstalledAssetItems = true: log snag envia rastreio de item de ativo. Único mercado com auditoria de unidade (AuditUnitReport). O ShelfWatch é só lançamento — o cartão de ver peças existe mas está desligado (isVisible: false), coerente com não haver shelfWatchConfig. E o grupo de OS é declarado sem filhos, abrindo o formulário direto. usesInstalledAssetItems = true: the log snag sends asset-item tracking. Only market with the unit audit (AuditUnitReport). ShelfWatch is launch-only — the view-pieces card exists but is off (isVisible: false), consistent with having no shelfWatchConfig. And the SO group is declared with no children, opening the form directly. usesInstalledAssetItems = true: el log snag envía rastreo de ítem de activo. Único mercado con auditoría de unidad (AuditUnitReport). ShelfWatch es solo lanzamiento — la tarjeta de ver piezas existe pero está apagada (isVisible: false), coherente con no haber shelfWatchConfig. Y el grupo de OS se declara sin hijos, abriendo el formulario directo.

ARPYPE

Sem merchandisingNo merchandisingSin merchandising Existem como mercados do app (config PANGEA mínima), mas não têm merchandisingConfig no End Market Configuration nem a ferramenta na grade da visita — o módulo não é renderizado. Os arquivos de mock existem, porém vazios. They exist as app markets (minimal PANGEA config), but have no merchandisingConfig in the End Market Configuration and no tool in the visit grid — the module isn't rendered. The mock files exist, but empty. Existen como mercados de la app (config PANGEA mínima), pero no tienen merchandisingConfig en el End Market Configuration ni la herramienta en la grilla de la visita — el módulo no se renderiza. Los archivos de mock existen, pero vacíos.

Pendências / roadmapPending / roadmapPendientes / roadmap

  • O EMC anotado está defasado. O end_market_configuration.detailed.jsonc ainda descreve o esquema anterior (opções retail_audit/merchan, sem destination, sem o bloco fields, com shelf_watch na grade da visita). Os três JSON ativos (PROD/UAT/PREPROD) são a fonte da verdade.The annotated EMC is out of date. end_market_configuration.detailed.jsonc still describes the previous schema (retail_audit/merchan options, no destination, no fields block, with shelf_watch in the visit grid). The three live JSONs (PROD/UAT/PREPROD) are the source of truth.El EMC anotado está desfasado. El end_market_configuration.detailed.jsonc aún describe el esquema anterior (opciones retail_audit/merchan, sin destination, sin el bloque fields, con shelf_watch en la grilla de la visita). Los tres JSON activos (PROD/UAT/PREPROD) son la fuente de la verdad.
  • Derivação legada mantida por compatibilidade. Quando o EMC não declara destination, o mapper ainda deriva o destino a partir do name. Nenhum mercado depende disso hoje — os três declaram o destino explicitamente — e os destinos shelfwatch_launch, shelfwatch_assets e audit_results_list só existem por declaração explícita.Legacy derivation kept for compatibility. When the EMC doesn't declare a destination, the mapper still derives it from the name. No market relies on that today — all three declare the destination explicitly — and the shelfwatch_launch, shelfwatch_assets and audit_results_list destinations only exist via explicit declaration.Derivación legada mantenida por compatibilidad. Cuando el EMC no declara destination, el mapper aún lo deriva del name. Ningún mercado depende de eso hoy — los tres declaran el destino explícitamente — y los destinos shelfwatch_launch, shelfwatch_assets y audit_results_list solo existen por declaración explícita.
  • ShelfWatch na visita é código morto. A ferramenta shelf_watch saiu da grade da visita em CL e ZA (agora se chega a ela pelo merchandising), mas o caso ainda existe no widget da grade, pronto para o dia em que algum EMC voltar a declará-la.ShelfWatch in the visit is dead code. The shelf_watch tool left the visit grid in CL and ZA (it is now reached through merchandising), but the case still exists in the grid widget, ready for the day some EMC declares it again.ShelfWatch en la visita es código muerto. La herramienta shelf_watch salió de la grilla de la visita en CL y ZA (ahora se llega a ella por merchandising), pero el caso aún existe en el widget de la grilla, listo para el día en que algún EMC vuelva a declararla.
  • A transação ServiceMerchanAudit (reconhecimento de imagem) ainda não tem doc dedicada no setor de transações.The ServiceMerchanAudit transaction (image recognition) still has no dedicated doc in the transactions sector.La transacción ServiceMerchanAudit (reconocimiento de imagen) aún no tiene doc dedicada en el sector de transacciones.