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 · Novo varejoFeature · New retailFeature · Nuevo punto de venta

Cadastro de novo varejoNew retail registrationRegistro de nuevo punto de venta

O assistente de 9 telas em que o representante de vendas cadastra um varejo novo: tipo, documento, fotos de início de atividade, dados cadastrais, endereço, dados operacionais, equipe e resumo. Ao finalizar, tudo vira uma transação de escrita enviada ao Salesforce pelo Dispatcher. Cada campo visível, obrigatório e editável vem da configuração do mercado — não há if (market == …) no fluxo. The 9-screen wizard where the sales rep registers a brand-new retail: type, tax document, start-of-activity photos, legal data, address, operational data, team and summary. On finish, everything becomes one write transaction sent to Salesforce through the Dispatcher. Every visible, required and editable field comes from market configuration — there is no if (market == …) in the flow. El asistente de 9 pantallas donde el representante de ventas registra un punto de venta nuevo: tipo, documento, fotos de inicio de actividad, datos legales, dirección, datos operativos, equipo y resumen. Al finalizar, todo se convierte en una transacción de escritura enviada a Salesforce por el Dispatcher. Cada campo visible, obligatorio y editable viene de la configuración del mercado — no hay if (market == …) en el flujo.

PúblicoAudiencePúblico
Representante · QA · Suporte · DevRep · QA · Support · DevRepresentante · QA · Soporte · Dev
Onde ficaWhereDónde
Home → Ações do representante → Criar varejoHome → Rep actions → Create retailHome → Acciones del representante → Crear PDV
Escreve viaWrites viaEscribe vía
AccountContactUploadAPI
AtualizadoUpdatedActualizado
29/07/20262026-07-29
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 Cadastro de novo varejo é o único caminho no app para criar um varejo que ainda não existe no Salesforce. O representante de vendas percorre um assistente, preenche os dados exigidos pelo seu mercado, fotografa os documentos de início de atividade, cadastra as pessoas do varejo e envia. Não é uma edição: para alterar um varejo já existente existe outra tela (Lista de varejos) e outra transação. The New retail registration is the only path in the app to create a retail that does not exist yet in Salesforce. The sales rep walks a wizard, fills the data their market requires, photographs the start-of-activity documents, registers the retail's people and submits. It is not an edit: changing an existing retail lives on another screen (Retail list) and another transaction. El Registro de nuevo punto de venta es el único camino en la app para crear un PDV que aún no existe en Salesforce. El representante de ventas recorre un asistente, completa los datos que su mercado exige, fotografía los documentos de inicio de actividad, registra a las personas del PDV y envía. No es una edición: modificar un PDV existente vive en otra pantalla (Lista de PDV) y otra transacción.

Que tipo de cliente?Which customer type?¿Qué tipo de cliente?

O mercado decide os tipos oferecidos: no Brasil, pessoa física ou jurídica; no Chile e na África do Sul, um tipo único.The market decides the offered types: in Brazil, individual or business; in Chile and South Africa, a single generic type.El mercado decide los tipos ofrecidos: en Brasil, persona natural o jurídica; en Chile y Sudáfrica, un tipo único.

Que provas anexar?Which evidence to attach?¿Qué pruebas adjuntar?

A lista de documentos exigidos e os espaços de foto vêm da configuração do mercado — de 1 (Chile) a 4 fotos (Brasil, pessoa jurídica).The required-document list and the photo slots come from market configuration — from 1 (Chile) to 4 photos (Brazil, business).La lista de documentos exigidos y los espacios de foto vienen de la configuración del mercado — de 1 (Chile) a 4 fotos (Brasil, jurídica).

O que acontece ao enviar?What happens on submit?¿Qué pasa al enviar?

Um único envio leva varejo, contatos, classificações e fotos ao Salesforce. O varejo só aparece na lista depois que o backend o processa.A single submission carries retail, contacts, classifications and photos to Salesforce. The retail only shows up in the list after the backend processes it.Un único envío lleva PDV, contactos, clasificaciones y fotos a Salesforce. El PDV solo aparece en la lista después de que el backend lo procesa.

Fluxo de escrita, sem rascunho salvoWrite flow, no saved draftFlujo de escritura, sin borrador guardado Tudo o que o representante digita vive só na memória do app até o envio. Sair do assistente descarta os dados e apaga as fotos capturadas. Não existe "continuar depois". Everything the rep types lives only in the app's memory until submission. Leaving the wizard discards the data and deletes the captured photos. There is no "continue later". Todo lo que el representante escribe vive solo en la memoria de la app hasta el envío. Salir del asistente descarta los datos y borra las fotos capturadas. No existe "continuar después".

02

Como acessarHow to openCómo acceder

  1. Pela HomeFrom HomeDesde el HomeNo módulo Ações do representante, toque no atalho Criar varejo (Brasil: "Criar Varejo"; Chile: "Crear PDV"; África do Sul: "Create Retail"). É o único ponto de entrada ativo — a lista de varejos não abre este fluxo.In the Rep actions module, tap the Create retail tile (Brazil: "Criar Varejo"; Chile: "Crear PDV"; South Africa: "Create Retail"). It is the only active entry point — the retail list does not open this flow.En el módulo Acciones del representante, toque el atajo Crear PDV (Brasil: "Criar Varejo"; Chile: "Crear PDV"; Sudáfrica: "Create Retail"). Es el único punto de entrada activo — la lista de PDV no abre este flujo.
  2. Escolha o tipoPick the typeElija el tipoA primeira tela mostra os tipos habilitados no mercado. Tocar num tipo já define quais campos e documentos o resto do assistente vai pedir.The first screen shows the types enabled in the market. Tapping a type already decides which fields and documents the rest of the wizard will ask for.La primera pantalla muestra los tipos habilitados en el mercado. Tocar un tipo ya define qué campos y documentos pedirá el resto del asistente.
  3. Brasil: valide o documento primeiroBrazil: validate the document firstBrasil: valide el documento primeroNo Brasil o app abre uma tela extra para checar o CPF/CNPJ no CRM antes de deixar você começar. Sem internet o fluxo não avança — aparece um aviso e a tela não abre. Chile e África do Sul pulam esta etapa.In Brazil the app opens an extra screen to check the CPF/CNPJ against the CRM before letting you start. Without internet the flow does not advance — a notice appears and the screen does not open. Chile and South Africa skip this step.En Brasil la app abre una pantalla extra para verificar el CPF/CNPJ en el CRM antes de dejarle empezar. Sin internet el flujo no avanza — aparece un aviso y la pantalla no abre. Chile y Sudáfrica omiten este paso.
  4. O assistente abreThe wizard opensEl asistente abreTodas as telas compartilham o mesmo cabeçalho, com o título do fluxo e a data da última sincronização dos dados de apoio (listas de opções).All screens share the same header, with the flow title and the last-sync date of the supporting data (option lists).Todas las pantallas comparten el mismo encabezado, con el título del flujo y la fecha de última sincronización de los datos de apoyo (listas de opciones).

Atalho do menu lateralSide-menu shortcutAtajo del menú lateral O app tem código para abrir o fluxo também pelo menu lateral, mas nenhum mercado declara esse item hoje na configuração — na prática o caminho é apenas a Home. The app also has code to open the flow from the side menu, but no market declares that item today in configuration — in practice the only path is Home. La app también tiene código para abrir el flujo desde el menú lateral, pero ningún mercado declara ese ítem hoy en la configuración — en la práctica el único camino es el Home.

03

Estrutura do fluxoFlow structureEstructura del flujo

Nove telas, sempre na mesma ordem. A segunda existe só no Brasil; a de cadastro de colaborador é aberta e fechada quantas vezes o representante quiser.Nine screens, always in the same order. The second one exists only in Brazil; the contact-registration screen is opened and closed as many times as the rep wants.Nueve pantallas, siempre en el mismo orden. La segunda existe solo en Brasil; la de registro de colaborador se abre y cierra tantas veces como el representante quiera.

1 · Seleção de tipo1 · Type selection1 · Selección de tipo
Grade de cartões com os tipos do mercado (pessoa física / pessoa jurídica / tipo único). Puxar para baixo recarrega as listas de apoio.Card grid with the market's types (individual / business / single generic). Pull down to reload the supporting lists.Grilla de tarjetas con los tipos del mercado (persona natural / jurídica / tipo único). Deslizar hacia abajo recarga las listas de apoyo.
2 · Validação do documento (só Brasil)2 · Document validation (Brazil only)2 · Validación del documento (solo Brasil)
Um campo de CPF ou CNPJ, o texto explicando a checagem no CRM e o botão Validar. Documento bloqueado ou já cadastrado impede o avanço.One CPF or CNPJ field, the text explaining the CRM check and the Validate button. A blocked or already-registered document stops the flow.Un campo de CPF o CNPJ, el texto que explica la verificación en el CRM y el botón Validar. Un documento bloqueado o ya registrado impide avanzar.
3 · Início3 · Start3 · Inicio
Acordeões com "os documentos necessários são:" (um por perfil de cliente) e a seção Início da Atividade, onde as fotos são capturadas e listadas com o rótulo do documento.Accordions with "the required documents are:" (one per customer profile) and the Start of Activity section, where photos are captured and listed with the document label.Acordeones con "los documentos requeridos son:" (uno por perfil de cliente) y la sección Inicio de Actividad, donde las fotos se capturan y se listan con la etiqueta del documento.
4 · Dados do varejo4 · Retail data4 · Datos del comercio
Documento (CNPJ/CPF/RUT/VAT), Inscrição Estadual (só Brasil, pessoa jurídica, opcional), Razão Social e Nome Fantasia. No Brasil o documento chega pronto da tela anterior e não é editável.Tax document (CNPJ/CPF/RUT/VAT), state registration (Brazil only, business, optional), legal name and trade name. In Brazil the document arrives ready from the previous screen and is read-only.Documento (CNPJ/CPF/RUT/VAT), inscripción estatal (solo Brasil, jurídica, opcional), razón social y nombre de fantasía. En Brasil el documento llega listo de la pantalla anterior y no es editable.
5 · Endereço5 · Address5 · Dirección
A ordem e o tipo de cada campo mudam por mercado: Brasil parte do CEP e preenche rua/bairro/cidade/estado automaticamente; Chile começa por uma busca de endereço (mapa) e usa texto livre para região e comuna; África do Sul usa listas de estado e cidade.The order and the type of each field change per market: Brazil starts from the postal code and auto-fills street/district/city/state; Chile starts with an address search (maps) and uses free text for region and comuna; South Africa uses state and city dropdowns.El orden y el tipo de cada campo cambian por mercado: Brasil parte del código postal y completa calle/barrio/ciudad/estado automáticamente; Chile comienza con una búsqueda de dirección (mapas) y usa texto libre para región y comuna; Sudáfrica usa listas de estado y ciudad.
6 · Dados operacionais6 · Operational data6 · Datos operacionales
Contato do varejo (celular, telefone, e-mail), subtipo de ponto, categorias vendidas, dias e horários de funcionamento, intervalo, dia de visita e de entrega, e os campos comerciais do mercado (Banner, Tipo de Propriedade, Giro, Canal, Cuenta Clave, Classificação Local, Cliente B2B, Venda Direta, Matriz de rede).Retail contact (mobile, phone, e-mail), outlet subtype, categories sold, operating days and hours, break, visit and delivery day, plus the market's commercial fields (Banner, Property type, Business type, Channel, Key account type, Local classification, B2B customer, Direct sales, Network parent).Contacto del PDV (celular, teléfono, correo), subtipo de punto, categorías vendidas, días y horarios de funcionamiento, intervalo, día de visita y de entrega, y los campos comerciales del mercado (Banner, Tipo de propiedad, Giro, Canal, Cuenta clave, Clasificación local, Cliente B2B, Venta directa, Matriz de red).
7 · Equipe do varejo7 · Retail team7 · Equipo del comercio
Lista de cartões de contato já cadastrados (celular, nome, função) e o cartão Adicionar contato. Para prosseguir é preciso ao menos um contato marcado como principal.List of already-registered contact cards (mobile, name, role) and the Add contact card. To move on you need at least one contact marked as main.Lista de tarjetas de contacto ya registradas (celular, nombre, función) y la tarjeta Agregar contacto. Para seguir hace falta al menos un contacto marcado como principal.
8 · Cadastro de colaborador8 · Contact registration8 · Registro de colaborador
Formulário da pessoa: pronome, idioma preferido, nome (completo no Brasil; primeiro e último nos demais), função, contato principal, celular, e-mail e data de nascimento (18 anos ou mais). Editando um contato existente, aparece também Remover contato.The person's form: pronoun, preferred language, name (full name in Brazil; first and last elsewhere), role, main contact, mobile, e-mail and date of birth (18+). When editing an existing contact, Remove contact also appears.Formulario de la persona: pronombre, idioma preferido, nombre (completo en Brasil; primero y último en los demás), función, contacto principal, celular, correo y fecha de nacimiento (18 años o más). Al editar un contacto existente, aparece también Eliminar contacto.
9 · Resumo do cadastro9 · Registration summary9 · Resumen del registro
Cinco cartões de revisão (Dados do varejo, Endereço, Dados operacionais, Equipe, Início da atividade), cada um com Editar, e a barra fixa com Voltar e Finalizar.Five review cards (Retail data, Address, Operational data, Team, Start of activity), each with Edit, plus the fixed bar with Come back and Finish.Cinco tarjetas de revisión (Datos del comercio, Dirección, Datos operacionales, Equipo, Inicio de actividad), cada una con Editar, y la barra fija con Volver y Finalizar.
Em todas as telasOn every screenEn todas las pantallas
Cabeçalho com título e data de sincronização, o aviso *Campos obrigatórios nos formulários, e a dupla de botões Voltar / Continuar — que vira um único Salvar alterações quando você chegou ali pelo Editar do resumo.Header with title and sync date, the *Mandatory fields note on forms, and the Come back / Next button pair — which becomes a single Save changes when you arrived from the summary's Edit.Encabezado con título y fecha de sincronización, el aviso *Campos obligatorios en los formularios, y el par de botones Volver / Continuar — que se convierte en un único Guardar cambios cuando llegó desde el Editar del resumen.

Limites de tamanhoLength limitsLímites de longitud Três campos têm limite fixo, igual em todos os mercados: e-mail 80, rua 150 e bairro 35 caracteres. O limite corta na digitação e também truncа o que vem do preenchimento automático do CEP. Three fields have a fixed limit, the same in every market: e-mail 80, street 150 and district 35 characters. The limit clips typing and also truncates what comes from postal-code auto-fill. Tres campos tienen límite fijo, igual en todos los mercados: correo 80, calle 150 y barrio 35 caracteres. El límite recorta al escribir y también trunca lo que llega del autocompletado del código postal.

04

Estados e validaçõesStates & validationsEstados y validaciones

O fluxo não tem "status" de negócio como um pedido — tem quatro máquinas de estado que decidem se o representante pode seguir. Todas bloqueiam o avanço, nunca escondem o erro.The flow has no business "status" like an order — it has four state machines that decide whether the rep may move on. All of them block progress; none hides the error.El flujo no tiene "estado" de negocio como un pedido — tiene cuatro máquinas de estado que deciden si el representante puede seguir. Todas bloquean el avance; ninguna oculta el error.

Validação do documento (Brasil)Document validation (Brazil)Validación del documento (Brasil)

ResultadoOutcomeResultadoQuando aconteceWhen it happensCuándo ocurreO que o representante vêWhat the rep seesQué ve el representante
VazioEmptyVacíocampo sem dígitosfield has no digitscampo sin dígitos"Insira o documento." — sem chamada ao CRM."Enter the document." — no CRM call."Ingresa el documento." — sin llamada al CRM.
Formato inválidoInvalid formatFormato inválidoCPF ≠ 11 dígitos, CNPJ ≠ 14CPF ≠ 11 digits, CNPJ ≠ 14CPF ≠ 11 dígitos, CNPJ ≠ 14"Documento inválido. Verifique e tente novamente.""Invalid document. Please check and try again.""Documento inválido. Verifica e inténtalo de nuevo."
Sem conexãoOfflineSin conexiónapp offline (antes ou durante)app offline (before or during)app offline (antes o durante)"Sem conexão. Conecte-se à internet para validar o documento.""No connection. Connect to the internet to validate the document.""Sin conexión. Conéctate a internet para validar el documento."
BloqueadoBlockedBloqueadodocumento em lista de bloqueiodocument on the block listdocumento en lista de bloqueo"Documento bloqueado." + o motivo enviado pelo backend."Document blocked." + the reason sent by the backend."Documento bloqueado." + el motivo enviado por el backend.
Já cadastradoAlready registeredYa registradodocumento já existe no CRMdocument already exists in the CRMdocumento ya existe en el CRM"Este documento já está cadastrado e não pode ser usado.""This document is already registered and cannot be used.""Este documento ya está registrado y no puede usarse."
ErroErrorErrorqualquer outra falhaany other failurecualquier otra falla"Não foi possível validar o documento. Tente novamente.""Could not validate the document. Please try again.""No fue posible validar el documento. Inténtalo de nuevo."
LiberadoClearedLiberadonem bloqueado nem em usoneither blocked nor in useni bloqueado ni en usonenhuma mensagem — o app já avança para a tela de Início.no message — the app moves straight to the Start screen.ningún mensaje — la app avanza directo a la pantalla de Inicio.

E-mail já cadastradoE-mail already registeredCorreo ya registrado

No Chile e na África do Sul o app consulta o Salesforce antes de deixar o representante seguir, em dois momentos: no Continuar dos dados operacionais (e-mail do varejo) e no Registrar/Salvar do colaborador (e-mail do contato). No Brasil essa checagem está desligada.In Chile and South Africa the app queries Salesforce before letting the rep proceed, at two moments: on Next in operational data (retail e-mail) and on Register/Save for a contact (contact e-mail). In Brazil this check is off.En Chile y Sudáfrica la app consulta Salesforce antes de dejar avanzar al representante, en dos momentos: en Continuar de los datos operacionales (correo del PDV) y en Registrar/Guardar del colaborador (correo del contacto). En Brasil esta verificación está apagada.

ResultadoOutcomeResultadoO que apareceWhat appearsQué apareceAvança?Proceeds?¿Avanza?
DisponívelAvailableDisponiblenada — segue diretonothing — goes straight onnada — sigue directosimyes
E-mail do varejo em usoRetail e-mail in useCorreo del PDV en usoerro no campo ("Altere este e-mail.") e um aviso: "Este e-mail já está cadastrado para outro varejo…" + o motivo do backend, quando houver.field error ("Change this e-mail address.") and an alert: "This e-mail address is already registered for another retailer…" + the backend reason, when present.error en el campo ("Modifica este correo electrónico.") y un aviso: "Este correo ya está registrado para otro comercio…" + el motivo del backend, si viene.nãonono
E-mail do contato em usoContact e-mail in useCorreo del contacto en usomesmo par (erro no campo + aviso), com o texto "…para outro contato".same pair (field error + alert), with the "…for another contact" text.mismo par (error en el campo + aviso), con el texto "…para otro contacto".nãonono
Sem conexãoOfflineSin conexión"Sem conexão com a internet não é possível validar o e-mail. Conecte-se para continuar.""Without an internet connection the e-mail address cannot be validated. Connect to continue.""Sin conexión a internet no es posible validar el correo electrónico. Conéctate para continuar."nãonono
ErroErrorError"Não foi possível validar o e-mail. Tente novamente.""The e-mail address could not be validated. Try again.""No fue posible validar el correo electrónico. Inténtalo de nuevo."nãonono

Duas economias importantes: e-mail vazio não gera consulta, e ao editar um contato sem mudar o e-mail o app não consulta de novo.Two important savings: an empty e-mail triggers no query, and when editing a contact without changing the e-mail the app does not query again.Dos ahorros importantes: un correo vacío no genera consulta, y al editar un contacto sin cambiar el correo la app no consulta de nuevo.

Busca de CEP (Brasil)Postal-code lookup (Brazil)Búsqueda de código postal (Brasil)

parado — CEP incompletoidle — postal code incompleteinactivo — código incompleto buscandoloadingbuscando resolvido — endereço preenchidoresolved — address filledresuelto — dirección completada digitação manual (falhou por rede)manual entry (network failure)entrada manual (falla de red) erro — não encontrado ou fora da áreaerror — not found or out of areaerror — no encontrado o fuera del área

Com 8 dígitos digitados o app consulta o CEP. Se a cidade encontrada não estiver na área de atuação do representante, aparece "Este CEP não está dentro da sua área de atuação" e os campos de endereço são limpos. Se a busca falhar por falta de rede, o app libera a digitação manual. Enquanto o CEP não resolve, o botão Continuar fica desabilitado.With 8 digits typed the app looks the postal code up. If the returned city is not in the rep's operating area, "This postal code is not within your operating area" appears and the address fields are cleared. If the lookup fails for lack of network, the app unlocks manual entry. Until the postal code resolves, the Next button stays disabled.Con 8 dígitos escritos la app consulta el código postal. Si la ciudad devuelta no está en el área de actuación del representante, aparece "Este código postal no está dentro de su área de actuación" y los campos de dirección se limpian. Si la búsqueda falla por falta de red, la app habilita la entrada manual. Mientras el código no se resuelve, el botón Continuar permanece deshabilitado.

Envio do cadastroSubmissionEnvío del registro

parado — modal de confirmaçãoidle — confirmation modalinactivo — modal de confirmación enviando — modal travadosubmitting — modal lockedenviando — modal bloqueado sucesso — só o botão Fecharsuccess — Close button onlyéxito — solo el botón Cerrar falha — Voltar / Tentar novamentefailure — Come back / Try againfalla — Volver / Intentar de nuevo

Enquanto envia, o modal não pode ser fechado nem dispensado (nem pelo botão do sistema). No sucesso, "Sua solicitação de criação de varejo foi enviada com sucesso" e o único caminho é Fechar, que volta à primeira tela do fluxo e zera tudo — impossível reenviar o mesmo cadastro por engano. Na falha, a mensagem do erro real aparece e é possível tentar de novo. Offline o envio falha: este cadastro não entra em fila de reenvio automático.While submitting, the modal cannot be closed or dismissed (not even with the system button). On success, "Your request to create a retail has been successfully submitted" and the only way out is Close, which returns to the flow's first screen and wipes everything — resubmitting the same registration by mistake is impossible. On failure, the real error message shows and you may retry. Offline the submission fails: this registration does not enter the automatic resend queue.Mientras envía, el modal no puede cerrarse ni descartarse (ni con el botón del sistema). En éxito, "Tu solicitud de creación de comercio se envió con éxito" y la única salida es Cerrar, que vuelve a la primera pantalla del flujo y borra todo — reenviar el mismo registro por error es imposible. En falla, aparece el mensaje real del error y se puede reintentar. Offline el envío falla: este registro no entra en la cola de reenvío automático.

05

AçõesActionsAcciones

Fotografar os documentosPhotograph the documentsFotografiar los documentos

  1. Tocar em "Tirar foto"Tap "Take Photo"Tocar "Tomar foto"Abre um modal perguntando "Pronto para tirar a foto de {documento}?", com o rótulo do próximo espaço a preencher.Opens a modal asking "Ready to take a photo of {document}?", naming the next slot to fill.Abre un modal preguntando "¿Listo para tomar la foto de {documento}?", nombrando el próximo espacio a completar.
  2. RevisarReviewRevisarA foto aparece grande e o modal pergunta se ficou boa: "Sim, ficou ótima!" confirma; "Prefiro tirar outra foto" descarta e reabre a câmera.The photo shows large and the modal asks whether it turned out well: "Yes, it looks great!" confirms; "I prefer to take another photo" discards and reopens the camera.La foto se muestra grande y el modal pregunta si quedó bien: "¡Sí, quedó excelente!" confirma; "Prefiero tomar otra foto" descarta y reabre la cámara.
  3. Mínimo e máximoMinimum and maximumMínimo y máximoO mercado define os espaços: alcançado o mínimo obrigatório, o botão Continuar aparece ao lado da câmera; no máximo, só resta Continuar. Remover uma foto libera o espaço de novo.The market defines the slots: once the mandatory minimum is met, the Next button appears next to the camera; at the maximum, only Next remains. Removing a photo frees the slot again.El mercado define los espacios: alcanzado el mínimo obligatorio, el botón Continuar aparece junto a la cámara; en el máximo, solo queda Continuar. Quitar una foto libera el espacio otra vez.
  4. Ciclo de vida do arquivoFile lifecycleCiclo de vida del archivoAs fotos são comprimidas na captura (JPEG, teto de 300 KB) e vivem só na sessão do fluxo. Abandonar o assistente apaga todas.Photos are compressed at capture (JPEG, 300 KB cap) and live only in the flow's session. Abandoning the wizard deletes them all.Las fotos se comprimen al capturar (JPEG, techo de 300 KB) y viven solo en la sesión del flujo. Abandonar el asistente las borra todas.

Gerenciar a equipe do varejoManage the retail teamGestionar el equipo del comercio

AdicionarAddAgregar
O cartão Adicionar contato abre o formulário sempre em branco. Ao registrar, o app pergunta "Deseja adicionar outro contato?" — Sim salva e limpa o formulário para o próximo; Não salva e volta à lista; dispensar o modal não salva nada.The Add contact card always opens a blank form. On register, the app asks "Do you want to add another contact?" — Yes saves and clears the form for the next one; No saves and returns to the list; dismissing the modal saves nothing.La tarjeta Agregar contacto abre siempre un formulario en blanco. Al registrar, la app pregunta "¿Deseas agregar otro contacto?" — guarda y limpia el formulario; No guarda y vuelve a la lista; descartar el modal no guarda nada.
EditarEditEditar
Tocar num cartão carrega a pessoa no formulário; o botão vira Salvar e não há pergunta de "outro contato".Tapping a card loads the person into the form; the button becomes Save and there is no "another contact" question.Tocar una tarjeta carga a la persona en el formulario; el botón pasa a Guardar y no hay pregunta de "otro contacto".
RemoverRemoveEliminar
Só em edição: o botão vermelho Remover contato pede confirmação e, ao confirmar, apaga a pessoa e volta à lista.Only while editing: the red Remove contact button asks for confirmation and, once confirmed, deletes the person and returns to the list.Solo en edición: el botón rojo Eliminar contacto pide confirmación y, al confirmar, borra a la persona y vuelve a la lista.
Contato principal (só um)Main contact (only one)Contacto principal (solo uno)
Ligar o interruptor quando já existe outro principal abre a pergunta "Já existe um contato marcado como principal. Deseja tornar este novo contato o principal?". Confirmando, o anterior deixa de ser. Sem nenhum principal, a tela de equipe não deixa prosseguir (aviso "Marque pelo menos um contato como principal antes de finalizar") — e o Finalizar do resumo também exige isso.Turning the switch on while another main exists opens "There is already a contact marked as main. Do you want to make this new contact the main one?". Confirming demotes the previous one. With no main contact the team screen refuses to move on (notice "Mark at least one contact as the main contact before finishing") — and the summary's Finish requires it too.Activar el interruptor cuando ya existe otro principal abre "Ya existe un contacto marcado como principal. ¿Deseas hacer principal a este nuevo contacto?". Al confirmar, el anterior deja de serlo. Sin ningún principal la pantalla de equipo no deja avanzar (aviso "Marca al menos un contacto como principal antes de finalizar") — y el Finalizar del resumen también lo exige.
Porta de "Cliente B2B" (África do Sul)"B2B customer" gate (South Africa)Puerta de "Cliente B2B" (Sudáfrica)
Na África do Sul não é possível cadastrar contatos enquanto o varejo não estiver marcado como Cliente B2B nos dados operacionais — o app avisa: "Marque 'Cliente B2B' como Sim nos dados operacionais antes de cadastrar contatos".In South Africa contacts cannot be registered until the retail is flagged as a B2B customer in operational data — the app warns: "Set 'B2B customer' to Yes on the operational data before registering contacts".En Sudáfrica no se pueden registrar contactos hasta que el PDV esté marcado como Cliente B2B en los datos operacionales — la app avisa: "Marca 'Cliente B2B' como Sí en los datos operativos antes de registrar contactos".

Isenção de Inscrição Estadual (Brasil)State-registration exemption (Brazil)Exención de inscripción estatal (Brasil)

Deixar a Inscrição Estadual em branco no Brasil (pessoa jurídica) faz o app perguntar, ao tocar em Continuar: "Este varejo é isento de Inscrição Estadual?". Só o Sim segue para o endereço. Se preenchida, o número é validado contra as regras do(s) estado(s) atendido(s) pelo representante.Leaving the state registration blank in Brazil (business) makes the app ask, on Next: "Is this retailer exempt from state registration?". Only Yes moves on to the address. When filled, the number is validated against the rules of the state(s) the rep serves.Dejar la inscripción estatal en blanco en Brasil (jurídica) hace que la app pregunte, al tocar Continuar: "¿Este comercio está exento de inscripción estatal?". Solo el avanza a la dirección. Si se completa, el número se valida contra las reglas del estado o los estados que atiende el representante.

Revisar, editar e finalizarReview, edit and finishRevisar, editar y finalizar

Cada cartão do resumo tem Editar, que reabre a tela correspondente em modo de edição: um único botão Salvar alterações que devolve ao resumo. Campos vazios aparecem como "—", e um cartão sem nenhum campo visível no mercado simplesmente não é renderizado. O Finalizar só habilita quando os três formulários estão válidos, existe um contato principal e o mínimo de fotos foi atingido.Each summary card has Edit, which reopens the matching screen in editing mode: a single Save changes button that returns to the summary. Empty fields show as "—", and a card with no field visible in the market is simply not rendered. Finish only enables when the three forms are valid, a main contact exists and the photo minimum is met.Cada tarjeta del resumen tiene Editar, que reabre la pantalla correspondiente en modo edición: un único botón Guardar cambios que devuelve al resumen. Los campos vacíos se muestran como "—", y una tarjeta sin ningún campo visible en el mercado simplemente no se renderiza. Finalizar solo se habilita cuando los tres formularios son válidos, existe un contacto principal y se alcanzó el mínimo de fotos.

06

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

Clean Architecture + Riverpod + Freezed + gRPC + ObjectBox. O fluxo tem três caminhos de dados independentes: (a) leitura de apoio — as listas de opções (ReferenceData) e a configuração do mercado (EndMarketConfiguration), que hidratam o State no build(); (b) checagens sob demandataxNumberCheck e emailCheck, disparadas por botão, sem cache e sem Model; (c) escrita — um envelope do Dispatcher com o cadastro inteiro.Clean Architecture + Riverpod + Freezed + gRPC + ObjectBox. The flow has three independent data paths: (a) supporting reads — the option lists (ReferenceData) and market configuration (EndMarketConfiguration), which hydrate the State in build(); (b) on-demand checkstaxNumberCheck and emailCheck, fired by a button, with no cache and no Model; (c) write — one Dispatcher envelope with the whole registration.Clean Architecture + Riverpod + Freezed + gRPC + ObjectBox. El flujo tiene tres caminos de datos independientes: (a) lecturas de apoyo — las listas de opciones (ReferenceData) y la configuración del mercado (EndMarketConfiguration), que hidratan el State en el build(); (b) verificaciones a demandataxNumberCheck y emailCheck, disparadas por botón, sin caché y sin Model; (c) escritura — un envelope del Dispatcher con el registro completo.

(a) Leitura — listas de apoio e configuração(a) Read — supporting lists and configuration(a) Lectura — listas de apoyo y configuración

  • ReferenceDataReplygRPC proto
    • toDTOReferenceDataDTODTO · Freezed
      • toDomainReferenceDataEntitydomain · enums tipados
        • toModelReferenceDataModelObjectBox
          • toDomainReferenceDataEntitydomain · cache
            • GetReferenceDataUseCaseNewRetailFlowNotifier._load()+ marketConfigurationProvider
              • → StateNewRetailFlowState
                • → UI9 pages do assistente

O build() pede source: local (cache primeiro); o pull-to-refresh da primeira tela repete com source: remote. Em paralelo, marketConfigurationProvider entrega o NewRetailConfig (JSON do EMC → DTO → Entity, sem proto e sem ObjectBox), que define tipos, campos, obrigatoriedade, edição e as quatro flags de comportamento.build() asks for source: local (cache first); the first screen's pull-to-refresh repeats with source: remote. In parallel, marketConfigurationProvider delivers NewRetailConfig (EMC JSON → DTO → Entity, no proto and no ObjectBox), which defines types, fields, requiredness, editability and the four behavior flags.El build() pide source: local (caché primero); el pull-to-refresh de la primera pantalla repite con source: remote. En paralelo, marketConfigurationProvider entrega el NewRetailConfig (JSON del EMC → DTO → Entity, sin proto y sin ObjectBox), que define tipos, campos, obligatoriedad, edición y las cuatro flags de comportamiento.

(b) Checagens sob demanda — documento e e-mail(b) On-demand checks — document and e-mail(b) Verificaciones a demanda — documento y correo

  • Botão do repValidar · Continuar · Registrar
    • CheckTaxNumberUseCase / CheckEmailUseCaseReferenceDataRepositoryImploffline → NetworkFailure
      • gRPCtaxNumberCheck / emailCheckRemote · sem cache
        • toDTOTaxNumberCheckResultDTO
          EmailCheckResultDTO
          • toDomain…ResultEntitycanProceed
            • → outcomebloqueia ou libera o avanço

Nenhuma das duas checagens tem Model, cache ou fromMap de JSON real — o mock resolve por listas dentro do próprio asset de reference_data. Offline, o repository devolve NetworkFailure antes de tocar a rede.Neither check has a Model, a cache or a real JSON fromMap — the mock resolves them from lists inside the reference_data asset itself. Offline, the repository returns NetworkFailure before touching the network.Ninguna de las dos verificaciones tiene Model, caché ni fromMap de JSON real — el mock las resuelve con listas dentro del propio asset de reference_data. Offline, el repository devuelve NetworkFailure antes de tocar la red.

(c) Escrita — a transação do cadastro(c) Write — the registration transaction(c) Escritura — la transacción del registro

  • NewRetailFlowStatetudo em memória + fotos
    • submitNewRetail()NewRetailUploadDispatcherPayloadInputdado cru de domínio
      • BuildNewRetailUploadDispatcherPayloadUseCase.build()DispatcherEnvelopeserviceName AccountContactUploadAPI
        • SubmitNewRetailUploadUseCase.submit()DispatcherOrchestratorretailNew não entra em fila offline
          • send()DispatcherRepositoryImpl → DispatcherGatewayjsonEncode(payload)
            • gRPCsendTransaction(InboxTransactionRequest)
              • → ackDispatcherAckstatus 0|5 = sucesso

Regra travada do projeto: o Input carrega dado cru de domínio (entities, nomes de domínio) e toda a construção wire — rename, concatenação, formatação de data, digitsOnly, campos fixos, derivação do sfid do representante — mora no build() do builder. O que o notifier injeta é o que o builder puro não obtém: relógio (submittedAt), ResourceEntity, GPS, customerCode gerado e as fotos já em base64.Locked project rule: the Input carries raw domain data (entities, domain names) and all wire construction — rename, concatenation, date formatting, digitsOnly, fixed fields, deriving the rep sfid — lives only inside the builder's build(). What the notifier injects is what a pure builder cannot obtain: the clock (submittedAt), ResourceEntity, GPS, the generated customerCode and the photos already base64-encoded.Regla fija del proyecto: el Input lleva dato crudo de dominio (entities, nombres de dominio) y toda la construcción wire — rename, concatenación, formato de fecha, digitsOnly, campos fijos, derivación del sfid del representante — vive solo en el build() del builder. Lo que el notifier inyecta es lo que un builder puro no puede obtener: el reloj (submittedAt), ResourceEntity, GPS, el customerCode generado y las fotos ya en base64.

07

Modelo de dadosData modelModelo de datos

O dado de leitura deste fluxo (as listas de opções) existe em quatro representações ao longo das camadas — Proto (wire gRPC) → DTO (Freezed) → Model (ObjectBox) → Entity (domínio) — e cada fronteira é atravessada por um mapper. O fetch é write-through: todo retorno remoto é gravado no ObjectBox (registro único, regravado por inteiro) e a UI passa a ler do cache. Os nomes dos campos se mantêm em todas as camadas; muda pouco (enums tipados na Entity, relações ToMany/ToOne no Model).This flow's read data (the option lists) exists in four representations across the layers — Proto (gRPC wire) → DTO (Freezed) → Model (ObjectBox) → Entity (domain) — and each boundary is crossed by a mapper. Fetch is write-through: every remote response is written to ObjectBox (single row, fully rewritten) and the UI then reads from cache. Field names stay the same across layers; little changes (enums typed in the Entity, ToMany/ToOne relations in the Model).El dato de lectura de este flujo (las listas de opciones) existe en cuatro representaciones a lo largo de las capas — Proto (wire gRPC) → DTO (Freezed) → Model (ObjectBox) → Entity (dominio) — y cada frontera se cruza con un mapper. El fetch es write-through: toda respuesta remota se graba en ObjectBox (registro único, regrabado completo) y la UI lee del caché. Los nombres se mantienen en todas las capas; cambia poco (enums tipados en la Entity, relaciones ToMany/ToOne en el Model).

Nem tudo aqui percorre as quatro camadas. As duas checagens (EmailCheckResult, TaxNumberCheckResult) param na Entity — não têm Model nem cache. A configuração do mercado (NewRetailConfig e filhos) nasce de JSON e vai a DTO → Entity, sem proto e sem ObjectBox. E o rascunho do cadastro (NewRetailContact, PostalCodeAddress, NewRetailUploadDispatcherPayloadInput) é só domínio: existe em memória e morre no envio. Nas tabelas abaixo, camada inexistente aparece como . A seguir, na ordem: o proto, as estruturas de dados campo-a-campo, o payload da transação, os mappers e os deltas.Not everything here crosses the four layers. The two checks (EmailCheckResult, TaxNumberCheckResult) stop at the Entity — no Model, no cache. The market configuration (NewRetailConfig and children) is born from JSON and goes to DTO → Entity, with no proto and no ObjectBox. And the registration draft (NewRetailContact, PostalCodeAddress, NewRetailUploadDispatcherPayloadInput) is domain only: it lives in memory and dies on submit. In the tables below, a non-existent layer shows as . Next, in order: the proto, the field-by-field data structures, the transaction payload, the mappers and the deltas.No todo aquí recorre las cuatro capas. Las dos verificaciones (EmailCheckResult, TaxNumberCheckResult) paran en la Entity — sin Model ni caché. La configuración del mercado (NewRetailConfig e hijos) nace de JSON y va a DTO → Entity, sin proto y sin ObjectBox. Y el borrador del registro (NewRetailContact, PostalCodeAddress, NewRetailUploadDispatcherPayloadInput) es solo dominio: vive en memoria y muere en el envío. En las tablas de abajo, una capa inexistente aparece como . A continuación, en orden: el proto, las estructuras de datos campo a campo, el payload de la transacción, los mappers y los deltas.

Proto

ReferenceDataConectaRep.proto · proto3 · package mn.bat.conectarep.streambridge · importaimportsimporta CommonConectaRep.proto. Um serviço (ReferenceDataConectaRepService) com três métodos unários — o fluxo usa os três.One service (ReferenceDataConectaRepService) with three unary methods — the flow uses all three.Un servicio (ReferenceDataConectaRepService) con tres métodos unarios — el flujo usa los tres.

getReferenceDataunary
MétodoMethodMétodo

rpc getReferenceData(ReferenceDataRequest) returns (ReferenceDataReply)

path /mn.bat.conectarep.streambridge.ReferenceDataConectaRepService/getReferenceData

Request · ReferenceDataRequest
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 · só é enviado quando não-vazioonly sent when non-emptysolo se envía cuando no está vacío
Reply · ReferenceDataReply

19 campos de listas de apoio (o fluxo consome 11 deles). Detalhados nas Estruturas de dados abaixo.19 supporting-list fields (the flow consumes 11 of them). Detailed in Data structures below.19 campos de listas de apoyo (el flujo consume 11). Detallados en Estructuras de datos abajo.

taxNumberCheckunary
MétodoMethodMétodo

rpc taxNumberCheck(TaxNumberCheckRequest) returns (TaxNumberCheckReply)

path /mn.bat.conectarep.streambridge.ReferenceDataConectaRepService/taxNumberCheck

Request · TaxNumberCheckRequest
resourceSfid
string · #1 · primaryResourceSfid ou secondaryResourceSfid, conforme a sessãoprimaryResourceSfid or secondaryResourceSfid, per the sessionprimaryResourceSfid o secondaryResourceSfid, según la sesión
taxId
string · #2 · dígitos do CNPJ quando o tipo é business; vazio nos outrosCNPJ digits when the type is business; empty otherwisedígitos del CNPJ cuando el tipo es business; vacío en los demás
taxNumber
string · #3 · dígitos do CPF/documento individual; vazio quando business (mutuamente exclusivo com taxId)CPF/individual document digits; empty when business (mutually exclusive with taxId)dígitos del CPF/documento individual; vacío cuando business (mutuamente exclusivo con taxId)
Reply · TaxNumberCheckReply

bool hasTaxNumber · bool isBlackListed · string blackListMessagedetalhado em TaxNumberCheckResult nas Estruturas.detailed as TaxNumberCheckResult in Data structures.detallado como TaxNumberCheckResult en Estructuras.

emailCheckunary
MétodoMethodMétodo

rpc emailCheck(EmailCheckRequest) returns (EmailCheckReply)

path /mn.bat.conectarep.streambridge.ReferenceDataConectaRepService/emailCheck

Request · EmailCheckRequest
resourceSfid
string · #1 · mesmo sfid do taxNumberCheck, por simetriathe same sfid as taxNumberCheck, for symmetryel mismo sfid que taxNumberCheck, por simetría
email
string · #2 · enviado com trim(), sem normalizar caixasent with trim(), case not normalizedenviado con trim(), sin normalizar mayúsculas
target
string · #3 · "account" | "contact" · valores fechados no app pelo enum EmailCheckTargetvalues closed in the app by the EmailCheckTarget enumvalores cerrados en la app por el enum EmailCheckTarget
Reply · EmailCheckReply

bool hasEmail · string messagemessage só é lido quando hasEmail = true; vazio é aceitável. Detalhado em EmailCheckResult nas Estruturas.message is only read when hasEmail = true; empty is acceptable. Detailed as EmailCheckResult in Data structures.message solo se lee cuando hasEmail = true; vacío es aceptable. Detallado como EmailCheckResult en Estructuras.

Pendência de backend — emailCheckBackend pendency — emailCheckPendiente de backend — emailCheck O RPC existe no .proto e na stack completa do app, mas ainda não está implementado no backend. Enquanto não estiver, a chamada real cai em UNIMPLEMENTED (code 12) → caminho de erro → o representante não avança. Para liberar antes da implementação, basta manter checksAccountEmailUniqueness e checksContactEmailUniqueness em false (é o que o Brasil já faz). Confirmações pedidas ao backend: se resourceSfid é necessário, se a busca é case-insensitive e se contas/contatos inativos contam como "em uso". Fonte: docs_old/pendencies/proto-changes-2026-07-24.md §9. The RPC exists in the .proto and in the app's full stack, but is not implemented in the backend yet. Until it is, the real call lands on UNIMPLEMENTED (code 12) → error path → the rep cannot proceed. To unblock before implementation, keep checksAccountEmailUniqueness and checksContactEmailUniqueness at false (which is what Brazil already does). Confirmations requested from the backend: whether resourceSfid is needed, whether the search is case-insensitive and whether inactive accounts/contacts count as "in use". Source: docs_old/pendencies/proto-changes-2026-07-24.md §9. El RPC existe en el .proto y en toda la stack de la app, pero aún no está implementado en el backend. Hasta entonces, la llamada real cae en UNIMPLEMENTED (code 12) → camino de error → el representante no avanza. Para desbloquear antes de la implementación, basta mantener checksAccountEmailUniqueness y checksContactEmailUniqueness en false (lo que Brasil ya hace). Confirmaciones pedidas al backend: si resourceSfid es necesario, si la búsqueda es case-insensitive y si cuentas/contactos inactivos cuentan como "en uso". Fuente: docs_old/pendencies/proto-changes-2026-07-24.md §9.

Estruturas de dadosData structuresEstructuras de datos

Um dropdown por estrutura, aninhados pela hierarquia. Cada tabela tem uma coluna por camada — Proto · DTO · Model · Entity; o texto em destaque marca onde o tipo primeiro muda (relação no Model, enum na Entity). = a camada não existe para aquela estrutura. ¹ = optional no proto.One dropdown per structure, nested by hierarchy. Each table has one column per layer — Proto · DTO · Model · Entity; accent text marks where the type first changes (relation in the Model, enum in the Entity). = that layer does not exist for the structure. ¹ = optional in the proto.Un dropdown por estructura, anidados por jerarquía. Cada tabla tiene una columna por capa — Proto · DTO · Model · Entity; el texto destacado marca dónde primero cambia el tipo (relación en el Model, enum en la Entity). = la capa no existe para esa estructura. ¹ = optional en el proto.

  • ReferenceData raiz · listas de apoioroot · supporting listsraíz · listas de apoyo 20 campos
    CampoProtoDTOModelEntity
    lastSyncAtDateTimeDateTimeDateTime
    deliveryCancelReasonsrepeated DeliveryCancelReasonList<…DTO>ToMany<…Model>List<…Entity>
    geographicalHierarchyGeographicalHierarchy…DTOToOne<…Model>…Entity
    outletSubtypesrepeated SfidNamePairList<…DTO>ToMany<…Model>List<…Entity>
    categoriesForSalerepeated stringList<String>List<String>List<CategoryForSale>
    bannersrepeated SfidNamePairList<…DTO>ToMany<…Model>List<…Entity>
    propertyTypesrepeated stringList<String>List<String>List<String>
    keyAccountTypesrepeated stringList<String>List<String>List<String>
    giroOptionsrepeated SfidNamePairList<…DTO>ToMany<…Model>List<…Entity>
    canalOptionsrepeated SfidNamePairList<…DTO>ToMany<…Model>List<…Entity>
    localClassificationDefinitionsrepeated LocalClassificationDefinitionList<…DTO>ToMany<…Model>List<…Entity>
    contactRolesrepeated stringList<String>List<String>List<ContactRole>
    languagePreferencesrepeated stringList<String>List<String>List<LanguagePreference>
    buybackReasonsrepeated BuybackReasonList<…DTO>ToMany<…Model>List<…Entity>
    moduleMasterModuleMaster…DTOToOne<…Model>…Entity
    accountInactiveReasonsrepeated stringList<String>List<String>List<AccountInactiveReason>
    pdvTypesrepeated PdvTypeList<…DTO>ToMany<…Model>List<…Entity>
    holidaysrepeated HolidayList<…DTO>ToMany<…Model>List<…Entity>
    visitCancelReasonsrepeated VisitReasonList<…DTO>ToMany<VisitCancelReasonModel>List<VisitReasonEntity>
    visitNoBuyReasonsrepeated VisitReasonList<…DTO>ToMany<VisitNoBuyReasonModel>List<VisitReasonEntity>

    O cadastro de varejo consome 11 campos: geographicalHierarchy, outletSubtypes, categoriesForSale, banners, propertyTypes, keyAccountTypes, giroOptions, canalOptions, localClassificationDefinitions, contactRoles, languagePreferences (+ lastSyncAt para o DataLoadInfo). Os demais pertencem a outras features. pdvTypes existe fim-a-fim mas nenhum código o lê hoje.New retail consumes 11 fields: geographicalHierarchy, outletSubtypes, categoriesForSale, banners, propertyTypes, keyAccountTypes, giroOptions, canalOptions, localClassificationDefinitions, contactRoles, languagePreferences (+ lastSyncAt for DataLoadInfo). The rest belong to other features. pdvTypes exists end-to-end but no code reads it today.El registro de PDV consume 11 campos: geographicalHierarchy, outletSubtypes, categoriesForSale, banners, propertyTypes, keyAccountTypes, giroOptions, canalOptions, localClassificationDefinitions, contactRoles, languagePreferences (+ lastSyncAt para el DataLoadInfo). Los demás pertenecen a otras features. pdvTypes existe de punta a punta pero ningún código lo lee hoy.

    • GeographicalHierarchy ReferenceData.geographicalHierarchy 2 campos
      CampoProtoDTOModelEntity
      countrySfidstringStringStringString
      statesrepeated StateList<GeoStateDTO>ToMany<GeoStateModel>List<GeoStateEntity>
      • GeoState GeographicalHierarchy.states[] · protoprotoproto State 4 campos
        CampoProtoDTOModelEntity
        sfidstringStringStringString
        namestringStringStringString
        codestringStringStringString
        citiesrepeated CityList<GeoCityDTO>ToMany<GeoCityModel>List<GeoCityEntity>
        • GeoCity GeoState.cities[] · City 2 campos
          CampoProtoDTOModelEntity
          sfidstringStringStringString
          namestringStringStringString
    • LocalClassificationDefinition ReferenceData.localClassificationDefinitions[] 4 campos
      CampoProtoDTOModelEntity
      sfidstringStringStringString
      namestringStringStringString
      typestringStringStringLocalClassificationType
      optionsrepeated SfidNamePairList<SfidNamePairDTO>ToMany<SfidNamePairModel>List<SfidNamePairEntity>
      • SfidNamePair compartilhado ·shared ·compartido · CommonConectaRep.proto 2 campos
        CampoProtoDTOModelEntity
        sfidstringStringStringString
        namestringStringStringString

        Alimenta outletSubtypes, banners, giroOptions, canalOptions e as opções de classificação local.Feeds outletSubtypes, banners, giroOptions, canalOptions and the local-classification options.Alimenta outletSubtypes, banners, giroOptions, canalOptions y las opciones de clasificación local.

  • EmailCheckResult raiz · sem Model, sem cacheroot · no Model, no cacheraíz · sin Model, sin caché 2 campos
    CampoProtoDTOModelEntity
    hasEmailboolboolbool
    messagestringStringString

    Getter da Entity: bool get canProceed => !hasEmail;. O message é o motivo do backend, exibido no modal abaixo da mensagem traduzida.Entity getter: bool get canProceed => !hasEmail;. message is the backend reason, shown in the modal below the translated message.Getter de la Entity: bool get canProceed => !hasEmail;. message es el motivo del backend, mostrado en el modal debajo del mensaje traducido.

  • TaxNumberCheckResult raiz · sem Model, sem cacheroot · no Model, no cacheraíz · sin Model, sin caché 3 campos
    CampoProtoDTOModelEntity
    hasTaxNumberboolboolbool
    isBlackListedboolboolbool
    blackListMessagestringStringString

    Getter da Entity: bool get canProceed => !hasTaxNumber && !isBlackListed; — o notifier da tela reimplementa a mesma regra em dois passos para escolher a mensagem certa.Entity getter: bool get canProceed => !hasTaxNumber && !isBlackListed; — the screen's notifier reimplements the same rule in two steps to pick the right message.Getter de la Entity: bool get canProceed => !hasTaxNumber && !isBlackListed; — el notifier de la pantalla reimplementa la misma regla en dos pasos para elegir el mensaje correcto.

  • PostalCodeAddress raiz · serviço de CEP (só domínio)root · postal-code service (domain only)raíz · servicio de código postal (solo dominio) 4 campos
    CampoProtoDTOModelEntity
    streetString
    neighborhoodString
    cityString
    stateCodeString
  • NewRetailContact raiz · rascunho em memóriaroot · in-memory draftraíz · borrador en memoria 9 campos
    CampoProtoDTOModelEntity
    firstNameString
    lastNameString
    pronounPronoun
    preferredLanguageLanguagePreference
    roleContactRole
    cellPhoneString
    emailString
    dateOfBirthDateTime?
    isMainContactbool

    Getter: String get fullName => "$firstName $lastName".trim();. No Brasil o formulário coleta o nome completo e o notifier o divide em primeiro/último ao salvar.Getter: String get fullName => "$firstName $lastName".trim();. In Brazil the form collects the full name and the notifier splits it into first/last on save.Getter: String get fullName => "$firstName $lastName".trim();. En Brasil el formulario recoge el nombre completo y el notifier lo divide en primero/último al guardar.

  • NewRetailConfig raiz · EMC (JSON → DTO → Entity)root · EMC (JSON → DTO → Entity)raíz · EMC (JSON → DTO → Entity) 14 campos
    CampoProtoDTOModelEntity
    documentRequirementsByTypeMap<String, List<…DTO>>Map<NewRetailType, List<…>>
    startOfActivityDocumentsByTypeMap<String, List<…DTO>>Map<NewRetailType, List<…>>
    legalEntityFieldsByTypeMap<String, List<…DTO>>Map<NewRetailType, List<…>>
    addressFieldsByTypeMap<String, List<…DTO>>Map<NewRetailType, List<…>>
    operationalDataFieldsByTypeMap<String, List<…DTO>>Map<NewRetailType, List<…>>
    contactFieldsByTypeMap<String, List<…DTO>>Map<NewRetailType, List<…>>
    postalCodeAutoCompleteboolbool
    wireConfigNewRetailWireConfigDTONewRetailWireConfig
    requiresDocumentValidationboolbool
    retailTypesList<String>List<NewRetailType>
    checksAccountEmailUniquenessboolbool
    checksContactEmailUniquenessboolbool
    requiresB2bCustomerForContactsboolbool
    allowsStateRegistrationExemptionboolbool

    As chaves do JSON são idênticas aos nomes dos campos. As chaves de tipo ("individual"/"business"/"generic") viram NewRetailType por fromKey, com fallback silencioso para generic. Métodos: documentRequirementsFor, startOfActivityDocumentsFor, legalEntityFieldsFor, addressFieldsFor, operationalDataFieldsFor, contactFieldsFor — todos com lista vazia como padrão.The JSON keys are identical to the field names. Type keys ("individual"/"business"/"generic") become NewRetailType via fromKey, with a silent fallback to generic. Methods: documentRequirementsFor, startOfActivityDocumentsFor, legalEntityFieldsFor, addressFieldsFor, operationalDataFieldsFor, contactFieldsFor — all defaulting to an empty list.Las claves del JSON son idénticas a los nombres de los campos. Las claves de tipo ("individual"/"business"/"generic") pasan a NewRetailType vía fromKey, con fallback silencioso a generic. Métodos: documentRequirementsFor, startOfActivityDocumentsFor, legalEntityFieldsFor, addressFieldsFor, operationalDataFieldsFor, contactFieldsFor — todos con lista vacía por defecto.

    • NewRetailWireConfig NewRetailConfig.wireConfig 20 campos
      CampoProtoDTOModelEntity
      accountRecordTypeIdStringString
      contactRecordTypeIdStringString
      locationHierarchyIdStringString
      paymentMethodStringString
      defaultPaymentMethodStringString
      currencyIsoCodeStringString
      languageStringString
      mailingCountryStringString
      contactPreferredLanguageStringString
      sendsVatRegistrationNoboolbool
      sendsTaxIdboolbool
      sendsDocumentDataboolbool
      collectsDirectSalesboolbool
      userQuotasStringString
      ownerShipTypeStringString
      totalSellInValPerAnnumStringString
      isTaxRequiredStringString
      contactB2bStatusStringString
      restrictedOrderEditStringString
      isPartialDeliveryStringString

      Note os bools textuais: isTaxRequired, restrictedOrderEdit e isPartialDelivery são String no Dart e "true"/"false" no JSON, porque vão crus para o payload. Defaults do mapper: sendsTaxId: true, sendsDocumentData: true, userQuotas: "50", totalSellInValPerAnnum: "1", isTaxRequired: "false", contactB2bStatus: "Inactive".Note the stringly-typed bools: isTaxRequired, restrictedOrderEdit and isPartialDelivery are String in Dart and "true"/"false" in JSON, because they go raw into the payload. Mapper defaults: sendsTaxId: true, sendsDocumentData: true, userQuotas: "50", totalSellInValPerAnnum: "1", isTaxRequired: "false", contactB2bStatus: "Inactive".Note los bools textuales: isTaxRequired, restrictedOrderEdit e isPartialDelivery son String en Dart y "true"/"false" en JSON, porque van crudos al payload. Defaults del mapper: sendsTaxId: true, sendsDocumentData: true, userQuotas: "50", totalSellInValPerAnnum: "1", isTaxRequired: "false", contactB2bStatus: "Inactive".

    • NewRetailDocumentRequirement documentRequirementsByType[type][] 4 campos
      CampoProtoDTOModelEntity
      idStringString
      titleKeyStringString
      subtitleKeyString?String?
      documentKeysList<String>List<String>

      É o acordeão "os documentos necessários são:" — puramente informativo, sem relação com os espaços de foto. subtitleKey só existe hoje no perfil individual_rsa_resident (África do Sul).This is the "the required documents are:" accordion — purely informative, unrelated to photo slots. subtitleKey today exists only on the individual_rsa_resident profile (South Africa).Es el acordeón "los documentos requeridos son:" — puramente informativo, sin relación con los espacios de foto. subtitleKey hoy solo existe en el perfil individual_rsa_resident (Sudáfrica).

    • NewRetailStartOfActivityDocument startOfActivityDocumentsByType[type][] 3 campos
      CampoProtoDTOModelEntity
      idStringString
      labelKeyStringString
      isMandatoryboolbool

      Tamanho da lista = máximo de fotos; quantidade de isMandatory: true = mínimo exigido. A ordem da lista casa com a ordem de captura e, no builder, com as posições do payload.List length = max photos; count of isMandatory: true = required minimum. The list order matches the capture order and, in the builder, the payload positions.Longitud de la lista = máximo de fotos; cantidad de isMandatory: true = mínimo exigido. El orden de la lista coincide con el orden de captura y, en el builder, con las posiciones del payload.

    • NewRetailLegalEntityFieldConfig legalEntityFieldsByType[type][] 4 campos
      CampoProtoDTOModelEntity
      fieldNamefieldString?NewRetailLegalEntityField
      isVisibleboolbool
      isRequiredboolbool
      isEditableboolbool
    • NewRetailAddressFieldConfig addressFieldsByType[type][] 5 campos
      CampoProtoDTOModelEntity
      fieldNamefieldString?NewRetailAddressField
      isVisibleboolbool
      isRequiredboolbool
      isFreeTextboolbool
      isEditableboolbool

      isFreeText troca lista por campo de texto (é o que o Chile usa em região e comuna) e muda o que vai no payload: nome em vez de sfid. isEditable é lido pelo mapper mas nenhum mercado o declara hoje na lista de endereço.isFreeText swaps the dropdown for a text field (what Chile uses for region and comuna) and changes what goes on the wire: name instead of sfid. isEditable is parsed by the mapper but no market declares it in the address list today.isFreeText cambia la lista por un campo de texto (lo que Chile usa en región y comuna) y cambia lo que va en el payload: nombre en vez de sfid. isEditable lo lee el mapper pero ningún mercado lo declara hoy en la lista de dirección.

    • NewRetailOperationalDataFieldConfig operationalDataFieldsByType[type][] 3 campos
      CampoProtoDTOModelEntity
      fieldNamefieldString?NewRetailOperationalDataField
      isVisibleboolbool
      isRequiredboolbool

      A obrigatoriedade efetiva é isVisible && isRequired — é assim que a Classificação Local só é exigida na África do Sul, onde está visível e obrigatória.Effective requiredness is isVisible && isRequired — that is how Local classification is only enforced in South Africa, where it is both visible and required.La obligatoriedad efectiva es isVisible && isRequired — así la Clasificación Local solo se exige en Sudáfrica, donde está visible y obligatoria.

    • NewRetailContactFieldConfig contactFieldsByType[type][] 3 campos
      CampoProtoDTOModelEntity
      fieldNamefieldString?NewRetailContactField
      isVisibleboolbool
      isRequiredboolbool
  • NewRetailUploadDispatcherPayloadInput raiz · entrada do builder (só domínio)root · builder input (domain only)raíz · entrada del builder (solo dominio) 46 campos
    CampoProtoDTOModelEntity
    retailTypeNewRetailType
    vatNumberString
    stateRegistrationString
    outletNameString
    commercialNameString
    countrySfidString
    stateCodeString
    cityString
    districtString
    addressLineString
    numberString
    addressContinueString
    postalCodeString
    cellPhoneString
    phoneString
    emailString
    outletSubtypeSfidString
    categoriesSoldList<CategoryForSale>
    operatingDaysList<String>
    openingTimeString
    closingTimeString
    breakStartString
    breakEndString
    bannerString
    propertyTypeString
    keyAccountTypeString
    giroString
    channelString
    isB2BCustomerbool
    isDirectSalesbool
    isNetworkParentbool
    localClassificationNameString
    localClassificationOptionSfidString
    localClassificationDefinitionSfidString
    localClassificationDefinitionTypeString
    contactsList<NewRetailContactEntity>
    wireConfigNewRetailWireConfig
    resourceResourceEntity
    marketEndMarket
    customerCodeString
    imagesBase64List<String>
    latitudedouble
    longitudedouble
    submittedAtDateTime
    deliveryDayWeekDay?
    salesmanVisitDayWeekDay?

    Freezed, nomes de domínio (giro, channel, vatNumber) — o rename para o wire acontece no builder. stateCode e city carregam sfid ou nome, conforme isFreeText; localClassificationOptionSfid carrega o sfid da opção (picklist) ou o valor digitado (número/texto).Freezed, domain names (giro, channel, vatNumber) — the wire rename happens in the builder. stateCode and city carry sfid or name, per isFreeText; localClassificationOptionSfid carries the option sfid (picklist) or the typed value (number/text).Freezed, nombres de dominio (giro, channel, vatNumber) — el rename al wire ocurre en el builder. stateCode y city llevan sfid o nombre, según isFreeText; localClassificationOptionSfid lleva el sfid de la opción (picklist) o el valor escrito (número/texto).

Payload da transaçãoTransaction payloadPayload de la transacción

O BuildNewRetailUploadDispatcherPayloadUseCase monta um Map com 7 chaves de topo (a última condicional), serializado com jsonEncode no campo message do InboxTransactionRequest. Um dropdown por seção; colunas Campo JSON · Tipo · Origem do dado · Regra.BuildNewRetailUploadDispatcherPayloadUseCase assembles a Map with 7 top-level keys (the last one conditional), serialized with jsonEncode into the message field of InboxTransactionRequest. One dropdown per section; columns JSON field · Type · Data source · Rule.El BuildNewRetailUploadDispatcherPayloadUseCase arma un Map con 7 claves de nivel superior (la última condicional), serializado con jsonEncode en el campo message del InboxTransactionRequest. Un dropdown por sección; columnas Campo JSON · Tipo · Origen del dato · Regla.

EnvelopeEnvelopeEnvelopeValorValueValor
DispatcherTyperetailNew
serviceName"AccountContactUploadAPI" (nunca com prefixo Promo_)(never with the Promo_ prefix)(nunca con prefijo Promo_)
endpoint"salesforce"
transactionReferencecustomerCode — código temporário gerado no app: yyMMddHHmmss + sigla do mercado + 4 dígitos aleatórios— temporary code generated in the app: yyMMddHHmmss + market code + 4 random digits— código temporal generado en la app: yyMMddHHmmss + sigla del mercado + 4 dígitos aleatorios
dateReferencesubmittedAt formatado comoformatted asformateado como yyyy-MM-dd
accountsapCode: customerCode · name: outletName
tid0
AccountData[0] 1 elemento · 55 chaves (2 condicionais por EMC + 2 condicionais por valor)1 element · 55 keys (2 EMC-conditional + 2 value-conditional)1 elemento · 55 claves (2 condicionales por EMC + 2 por valor)
Campo JSONJSON fieldCampo JSONTipoTypeTipoOrigem do dadoData sourceOrigen del datoRegraRuleRegla
VATRegistrationNoStringInput.vatNumbersó existe se wireConfig.sendsVatRegistrationNo; vazio quando o tipo é individualonly present if wireConfig.sendsVatRegistrationNo; empty when the type is individualsolo existe si wireConfig.sendsVatRegistrationNo; vacío cuando el tipo es individual
taxIdStringInput.vatNumbersó existe se wireConfig.sendsTaxId; vazio quando individualonly present if wireConfig.sendsTaxId; empty when individualsolo existe si wireConfig.sendsTaxId; vacío cuando individual
taxNumber2StringInput.vatNumberrecebe o documento só quando o tipo é individual (CPF); vazio para pessoa jurídicacarries the document only when the type is individual (CPF); empty for a legal entityrecibe el documento solo cuando el tipo es individual (CPF); vacío para persona jurídica
taxNumber3StringInput.stateRegistrationInscrição Estadual, só dígitos (replaceAll(RegExp(r"\D"), "")). Vazio quando o campo não é visível no mercado/tipo ou o varejo é isentostate registration, digits only (replaceAll(RegExp(r"\D"), "")). Empty when the field is not visible for the market/type or the retail is exemptinscripción estatal, solo dígitos (replaceAll(RegExp(r"\D"), "")). Vacío cuando el campo no es visible en el mercado/tipo o el PDV está exento
nameStringInput.outletNamerazão sociallegal namerazón social
commercialNameStringInput.commercialNamenome fantasiatrade namenombre de fantasía
postCodeStringInput.postalCodePostalCodeUtils.format por mercado (BR #####-###, demais só dígitos)per market (BR #####-###, others digits only)por mercado (BR #####-###, demás solo dígitos)
addressLine1StringInput.addressLine + Input.numberconcatena "rua número"; sem número, envia só a ruaconcatenates "street number"; with no number, sends the street aloneconcatena "calle número"; sin número, envía solo la calle
addressLine2StringInput.addressContinuecomplementocomplementcomplemento
districtStringInput.districtbairro/comuna (máx. 35)district/comuna (max 35)barrio/comuna (máx. 35)
cityStringInput.citysfid quando a cidade vem de lista; nome quando o campo é texto livre (Chile)sfid when the city comes from a dropdown; name when the field is free text (Chile)sfid cuando la ciudad viene de lista; nombre cuando el campo es texto libre (Chile)
CountryStringInput.countrySfidsfid do país, da hierarquia geográficacountry sfid, from the geographical hierarchysfid del país, de la jerarquía geográfica
stateCodeStringInput.stateCodesfid ou nome, mesma regra da cidadesfid or name, same rule as the citysfid o nombre, misma regla que la ciudad
categoriesSoldStringInput.categoriesSoldlabels unidos por ; (ex. "FMC;Vapour Devices")labels joined by ; (e.g. "FMC;Vapour Devices")labels unidos por ; (ej. "FMC;Vapour Devices")
outletSubtypeStringInput.outletSubtypeSfidsfid
preferredDeliveryDayStringInput.deliveryDayabreviação de 3 letras em maiúsculas ("MON"); vazio quando não escolhido3-letter uppercase abbreviation ("MON"); empty when not chosenabreviatura de 3 letras en mayúsculas ("MON"); vacío cuando no se elige
PreferredDayForVisitStringInput.salesmanVisitDaynome completo ("Monday"); vazio quando não escolhidofull name ("Monday"); empty when not chosennombre completo ("Monday"); vacío cuando no se elige
daysOpenForBusinessStringInput.operatingDaysdias unidos por ;days joined by ;días unidos por ;
openingTimeStringInput.openingTimeHH:mm (padrão 07:30)HH:mm (default 07:30)HH:mm (por defecto 07:30)
closingTimeStringInput.closingTimeHH:mm (padrão 18:30)HH:mm (default 18:30)HH:mm (por defecto 18:30)
breakStartTimeStringInput.breakStarta chave só existe se preenchida (paridade com o legado)the key only exists when filled (legacy parity)la clave solo existe si está completa (paridad con el legado)
breakEndTimeStringInput.breakEndidemsameídem
mobileStringInput.cellPhonesó dígitosdigits onlysolo dígitos
telephone1StringInput.phonesó dígitosdigits onlysolo dígitos
contactEmailStringInput.emaile-mail do varejo (o que a checagem de unicidade valida)the retail's e-mail (the one the uniqueness check validates)correo del PDV (el que valida la verificación de unicidad)
sapCustomerIdStringFixo: ""o SAP é atribuído pelo backendSAP is assigned by the backendel SAP lo asigna el backend
recordTypeIdStringEMC.wireConfig.accountRecordTypeIdrecord type do Salesforce, por mercadoSalesforce record type, per marketrecord type de Salesforce, por mercado
statusStringFixo: "Active"
activeStringFixo: "Yes"
marketIsoStringInput.marketBR | CL | ZA
locationHierarchyStringEMC.wireConfig.locationHierarchyId
createdByIdStringFixo: ""
isB2BCustomerStringInput.isB2BCustomerbool → "true"/"false"bool → "true"/"false"bool → "true"/"false"
restrictedOrderEditStringEMC.wireConfig.restrictedOrderEdit
isBillTo · isShipTo · isSoldTo · isPayerStringFixo: "true"quatro chaves separadas, todas fixasfour separate keys, all fixedcuatro claves separadas, todas fijas
isPartialDeliveryStringEMC.wireConfig.isPartialDelivery
languageStringEMC.wireConfig.language
salesTerritoryStringResource.locationHierarchyIdhierarquia do representantethe rep's hierarchyjerarquía del representante
deliveryTerritoryStringResource.deliveryTerritory
deliveryLeadTimeStringFixo: "1"
paymentMethodStringEMC.wireConfig.paymentMethodcódigos separados por ;codes separated by ;códigos separados por ;
defaultPaymentMethodStringEMC.wireConfig.defaultPaymentMethod
currencyIsoCodeStringEMC.wireConfig.currencyIsoCode
userQuotasStringEMC.wireConfig.userQuotasBR/CL "50", ZA "5"BR/CL "50", ZA "5"BR/CL "50", ZA "5"
bannerStringInput.bannersfid do banner (Chile)banner sfid (Chile)sfid del banner (Chile)
ownerShipTypeStringInput.propertyTypese vazio, cai para EMC.wireConfig.ownerShipTypeif empty, falls back to EMC.wireConfig.ownerShipTypesi está vacío, cae a EMC.wireConfig.ownerShipType
emlov1StringInput.gironome de wire do Giro (sfid)wire name of Business type (sfid)nombre de wire del Giro (sfid)
emlov2StringInput.channelnome de wire do Canal (sfid)wire name of Channel (sfid)nombre de wire del Canal (sfid)
keyAccountTypeStringInput.keyAccountType
customerCodeStringCalculado no notifierCalculated in the notifierCalculado en el notifiermesmo valor do transactionReferencesame value as transactionReferencemismo valor que transactionReference
istaxrequiredStringEMC.wireConfig.isTaxRequired
isdirectsalesStringInput.isDirectSalessó respeita a resposta do representante se wireConfig.collectsDirectSales; senão fixo "true"only honors the rep's answer if wireConfig.collectsDirectSales; otherwise fixed "true"solo respeta la respuesta del representante si wireConfig.collectsDirectSales; si no, fijo "true"
routeID · routeFrqStringFixo: ""duas chaves separadastwo separate keysdos claves separadas
latitude · longitudeStringLocationService.currentPositionduas chaves; 0.0 quando não há posiçãotwo keys; 0.0 when there is no positiondos claves; 0.0 cuando no hay posición

Não existe chave taxNumber1 — a trinca de documento é taxId/VATRegistrationNo (pessoa jurídica), taxNumber2 (pessoa física) e taxNumber3 (Inscrição Estadual).There is no taxNumber1 key — the document trio is taxId/VATRegistrationNo (legal entity), taxNumber2 (individual) and taxNumber3 (state registration).No existe la clave taxNumber1 — el trío del documento es taxId/VATRegistrationNo (persona jurídica), taxNumber2 (persona natural) y taxNumber3 (inscripción estatal).

ContactData[] 1 elemento por contato · 22 chaves1 element per contact · 22 keys1 elemento por contacto · 22 claves
Campo JSONJSON fieldCampo JSONTipoTypeTipoOrigem do dadoData sourceOrigen del datoRegraRuleRegla
firstNameStringContact.firstNameno Brasil, primeira palavra do nome completoin Brazil, the first word of the full nameen Brasil, la primera palabra del nombre completo
lastNameStringContact.lastNameno Brasil, o resto do nome completoin Brazil, the rest of the full nameen Brasil, el resto del nombre completo
recordTypeIdStringEMC.wireConfig.contactRecordTypeIdvazio no Brasil hojeempty in Brazil todayvacío en Brasil hoy
mobilePhoneStringContact.cellPhonesó dígitosdigits onlysolo dígitos
salutationStringContact.pronoun"Mr." | "Mrs." | "Miss"
contactPositionStringCalculadoCalculatedCalculado"Manager" quando o varejo é matriz de rede e este é o contato principal; "" em qualquer outro caso"Manager" when the retail is a network parent and this is the main contact; "" in every other case"Manager" cuando el PDV es matriz de red y este es el contacto principal; "" en cualquier otro caso
roleStringContact.rolelabel em inglês do ContactRole ("Clerk", "Owner"…)English label of ContactRole ("Clerk", "Owner"…)label en inglés de ContactRole ("Clerk", "Owner"…)
isPrimaryContactStringContact.isMainContact"true"/"false"
birthdateStringContact.dateOfBirthyyyy/MM/dd ou "" quando não informadoor "" when absento "" cuando no se informa
mailingCountryStringEMC.wireConfig.mailingCountry
PreferedLangStringEMC.wireConfig.contactPreferredLanguagenome de wire com grafia legadawire name keeps the legacy misspellingnombre de wire con grafía legada
PreferedMethodtoContactStringFixo: "mobile"
b2bStatusStringEMC.wireConfig.contactB2bStatusCL "Active"; BR/ZA "Inactive"CL "Active"; BR/ZA "Inactive"CL "Active"; BR/ZA "Inactive"
emailStringContact.emailé o e-mail que a checagem de contato validathe e-mail the contact check validatesel correo que valida la verificación de contacto
customerCodeStringCalculado no notifierCalculated in the notifierCalculado en el notifierliga o contato ao varejo do mesmo envelopelinks the contact to the retail in the same envelopevincula el contacto al PDV del mismo envelope
istaxrequiredStringFixo: "true"
isdirectsalesStringFixo: "true"
routeID · routeFrqStringFixo: ""duas chaves separadastwo separate keysdos claves separadas
latitude · longitudeStringLocationService.currentPositionduas chaves, mesmas do varejotwo keys, the same as the retail'sdos claves, las mismas del PDV
languagePreferenceStringContact.preferredLanguagecódigo ISO ("pt", "es"…); fallback "en_US"ISO code ("pt", "es"…); fallback "en_US"código ISO ("pt", "es"…); fallback "en_US"
territoryStoreMapping[0] 6 chaveskeysclaves
Campo JSONJSON fieldCampo JSONTipoTypeTipoOrigem do dadoData sourceOrigen del datoRegraRuleRegla
CustomerCodeStringCalculado no notifierCalculated in the notifierCalculado en el notifier
LocationIDStringResource.locationHierarchyId
MarketISOStringInput.market
assignTempResStringFixo: ""
FromDateStringFixo: ""
ToDateStringFixo: ""
globalClassification[0] 13 chaveskeysclaves
Campo JSONJSON fieldCampo JSONTipoTypeTipoOrigem do dadoData sourceOrigen del datoRegraRuleRegla
RecordTypeIDStringInput.categoriesSoldlabels unidos por : e espaços trocados por _ (ex. "FMC:Vapour_Devices") — formato legadolabels joined by : with spaces replaced by _ (e.g. "FMC:Vapour_Devices") — legacy formatlabels unidos por : y espacios cambiados por _ (ej. "FMC:Vapour_Devices") — formato legado
CustomerCodeStringCalculado no notifierCalculated in the notifierCalculado en el notifier
TotalsellinValperAnnumStringEMC.wireConfig.totalSellInValPerAnnumCL/ZA "1"; BR ""CL/ZA "1"; BR ""CL/ZA "1"; BR ""
MarketingAttractivenessStringFixo: ""
sellinValperAnnumStringFixo: ""
FacingCapacityStringFixo: ""
TotalfacingCapacityStringFixo: ""
categoryStringFixo: ""
costofBusinessStringFixo: ""
InStoreOppStringFixo: ""
priceSegLowStringFixo: ""
priceSegValueStringFixo: ""
priceSegPremiumStringFixo: ""
localClassification[0] 5 chaveskeysclaves
Campo JSONJSON fieldCampo JSONTipoTypeTipoOrigem do dadoData sourceOrigen del datoRegraRuleRegla
currencyIsoCodeStringEMC.wireConfig.currencyIsoCode
customerCodeStringCalculado no notifierCalculated in the notifierCalculado en el notifier
localClassNameStringInput.localClassificationNamenome da definição escolhida; "" onde o campo não é usadoname of the chosen definition; "" where the field is unusednombre de la definición elegida; "" donde el campo no se usa
localClassOptIdStringInput.localClassificationOptionSfidsfid da opção quando picklist; o valor digitado quando número/textooption sfid when picklist; the typed value when number/textsfid de la opción cuando picklist; el valor escrito cuando número/texto
localClassDefIdStringInput.localClassificationDefinitionSfid
localClassificationDefination[0] 4 chaves · grafia legada preservadakeys · legacy spelling keptclaves · grafía legada preservada
Campo JSONJSON fieldCampo JSONTipoTypeTipoOrigem do dadoData sourceOrigen del datoRegraRuleRegla
localClassDefNameStringInput.localClassificationName
isActiveStringFixo: "true"
isMandatoryStringFixo: "true"
typeStringInput.localClassificationDefinitionType"Picklist" | "Number" | "Text" | ""

O nome da chave (Defination) está errado de propósito: é o contrato do legado e mudá-lo quebraria a integração.The key name (Defination) is misspelled on purpose: it is the legacy contract and changing it would break the integration.El nombre de la clave (Defination) está mal escrito a propósito: es el contrato legado y cambiarlo rompería la integración.

DocumentData[0] 8 chaves · só quando sendsDocumentData8 keys · only when sendsDocumentData8 claves · solo cuando sendsDocumentData
Campo JSONJSON fieldCampo JSONTipoTypeTipoOrigem do dadoData sourceOrigen del datoRegraRuleRegla
nameStringInput.outletName
taxStringInput.vatNumberdocumento como digitadodocument as typeddocumento tal como se escribió
docFrontString (base64)Input.imagesBase64[0]1ª foto capturada1st captured photo1ª foto capturada
docBackString (base64)Input.imagesBase64[1]2ª foto2nd photo2ª foto
imageCNPJString (base64)Input.imagesBase64[2]só quando o tipo não é individual; senão ""only when the type is not individual; otherwise ""solo cuando el tipo no es individual; si no, ""
addressProofString (base64)Input.imagesBase64[3] ouoro [2]índice 3 para pessoa jurídica, 2 para pessoa físicaindex 3 for a legal entity, 2 for an individualíndice 3 para persona jurídica, 2 para persona natural
customerCodeStringCalculado no notifierCalculated in the notifierCalculado en el notifier
dateCreateStringInput.submittedAttimestamp completo (yyyy-MM-dd HH:mm:ss.mmm)full timestamp (yyyy-MM-dd HH:mm:ss.mmm)timestamp completo (yyyy-MM-dd HH:mm:ss.mmm)

O mapeamento é posicional: a ordem de captura define qual foto vira qual chave. Índice fora do alcance vira "". A África do Sul tem sendsDocumentData: falsea seção inteira não é enviada, embora as fotos sejam capturadas.The mapping is positional: capture order decides which photo becomes which key. An out-of-range index becomes "". South Africa has sendsDocumentData: falsethe whole section is not sent, even though photos are captured.El mapeo es posicional: el orden de captura decide qué foto es cada clave. Un índice fuera de rango es "". Sudáfrica tiene sendsDocumentData: falsela sección entera no se envía, aunque las fotos se capturen.

Mappers

Todas as conversões são extension. O fluxo usa cinco direções, mas nenhuma estrutura usa as cinco:All conversions are extensions. The flow uses five directions, but no single structure uses all five:Todas las conversiones son extension. El flujo usa cinco direcciones, pero ninguna estructura usa las cinco:

DireçãoDirectionDirecciónMétodoMethodMétodoUsada porUsed byUsada por
JSON → DTOstatic fromMap(Map)mock de reference_data e toda a configuração do mercadoreference_data mock and all market configurationmock de reference_data y toda la configuración del mercado
Proto → DTOtoDTO()ReferenceDataReply · TaxNumberCheckReply · EmailCheckReply
DTO → EntitytoDomain()todas — é onde os enums são resolvidos (fromValue/fromLabel/fromWire/fromKey)all of them — this is where enums are resolved (fromValue/fromLabel/fromWire/fromKey)todas — es donde se resuelven los enums (fromValue/fromLabel/fromWire/fromKey)
Entity → ModeltoModel()ReferenceData e filhos (enums → .label/.value; popula ToMany/ToOne)only ReferenceData and children (enums → .label/.value; fills ToMany/ToOne)solo ReferenceData e hijos (enums → .label/.value; llena ToMany/ToOne)
Model → EntitytoDomain()ReferenceData e filhos (leitura do cache)only ReferenceData and children (cache read)solo ReferenceData e hijos (lectura del caché)

Os únicos deltasThe only deltasLos únicos deltas

  • enums tipados só na Entity (String nas outras camadas): CategoryForSale, ContactRole, LanguagePreference, AccountInactiveReason, LocalClassificationTypeenums typed only in the Entity (String elsewhere): CategoryForSale, ContactRole, LanguagePreference, AccountInactiveReason, LocalClassificationTypeenums tipados solo en la Entity (String en las demás): CategoryForSale, ContactRole, LanguagePreference, AccountInactiveReason, LocalClassificationType
  • relações viram ToMany/ToOne no Model; visitCancelReasons e visitNoBuyReasons compartilham a Entity mas têm Models distintosrelations become ToMany/ToOne in the Model; visitCancelReasons and visitNoBuyReasons share the Entity but have distinct Modelslas relaciones pasan a ToMany/ToOne en el Model; visitCancelReasons y visitNoBuyReasons comparten la Entity pero tienen Models distintos
  • lastSyncAt não existe no proto — é gerado no mapper com DateTimeUtils.now(); no mock, lido do JSONdoes not exist in the proto — generated in the mapper with DateTimeUtils.now(); in the mock, read from the JSONno existe en el proto — se genera en el mapper con DateTimeUtils.now(); en el mock, se lee del JSON
  • a configuração de campo renomeia fieldName (String) para field (enum) na Entityfield configuration renames fieldName (String) to field (enum) in the Entityla configuración de campo renombra fieldName (String) a field (enum) en la Entity
  • EmailCheckResult · TaxNumberCheckResult param na Entity: sem Model, sem cache, sem fromMapstop at the Entity: no Model, no cache, no fromMapparan en la Entity: sin Model, sin caché, sin fromMap
  • a configuração do mercado não tem proto nem ObjectBox (JSON → DTO → Entity)market configuration has neither proto nor ObjectBox (JSON → DTO → Entity)la configuración del mercado no tiene proto ni ObjectBox (JSON → DTO → Entity)
  • o rename para o wire (giroemlov1, channelemlov2, propertyTypeownerShipType, stateRegistrationtaxNumber3) acontece só no builder, nunca no Inputthe wire rename (giroemlov1, channelemlov2, propertyTypeownerShipType, stateRegistrationtaxNumber3) happens only in the builder, never in the Inputel rename al wire (giroemlov1, channelemlov2, propertyTypeownerShipType, stateRegistrationtaxNumber3) ocurre solo en el builder, nunca en el Input
08

Repository

O fluxo fala com dois repositories. O ReferenceDataRepositoryImpl (implementa ReferenceDataRepositoryInterface) injeta os 3 datasources + ConnectivityService + a flag useMockData + Ref, e responde por leitura e pelas duas checagens. O DispatcherRepositoryImpl responde pela escrita. Um dropdown por método — assinatura, retorno e comportamento; quem tem árvore de decisão a carrega dentro do próprio detalhe.The flow talks to two repositories. ReferenceDataRepositoryImpl (implements ReferenceDataRepositoryInterface) injects the 3 datasources + ConnectivityService + the useMockData flag + Ref, and answers for reads and the two checks. DispatcherRepositoryImpl answers for the write. One dropdown per method — signature, return and behavior; whoever has a decision tree carries it inside its own detail.El flujo habla con dos repositories. El ReferenceDataRepositoryImpl (implementa ReferenceDataRepositoryInterface) inyecta los 3 datasources + ConnectivityService + la flag useMockData + Ref, y responde por la lectura y las dos verificaciones. El DispatcherRepositoryImpl responde por la escritura. Un dropdown por método — firma, retorno y comportamiento; quien tiene árbol de decisión lo lleva dentro de su propio detalle.

ReferenceDataRepositoryImpl

getReferenceData({source = local}) mock / local / remote

RetornaReturnsDevuelve Result<ReferenceDataEntity, Failure>

Ponto de entrada das listas de apoio: decide a fonte, mapeia e grava no cache (write-through). O build() do notifier pede local; o pull-to-refresh pede remote.Entry point for the supporting lists: picks the source, maps and writes to cache (write-through). The notifier's build() asks for local; pull-to-refresh asks for remote.Punto de entrada de las listas de apoyo: elige la fuente, mapea y graba en caché (write-through). El build() del notifier pide local; el pull-to-refresh pide remote.

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

  1. useMockData == true ouoro source == mock_fetchFromMock(): lê o asset do mercado, mapeia, grava no cache. A flag global tem precedência máxima._fetchFromMock(): reads the market asset, maps, writes to cache. The global flag has top precedence._fetchFromMock(): lee el asset del mercado, mapea, graba en caché. La flag global tiene máxima precedencia.
  2. source == local ou offlineor offlineu offline_fetchFromCacheOrFail(): cache vazio devolve Error(NetworkFailure)._fetchFromCacheOrFail(): an empty cache returns Error(NetworkFailure)._fetchFromCacheOrFail(): caché vacío devuelve Error(NetworkFailure).
  3. senão (remoto + conectado)otherwise (remote + connected)si no (remoto + conectado)_fetchFromRemoteWithFallback(): lê currentResourceProvider; se null, cai pro cache; senão chama o remoto com locationHierarchyId, mapeia, grava no cache; em erro, fallback pro cache._fetchFromRemoteWithFallback(): reads currentResourceProvider; if null, falls back to cache; else calls remote with locationHierarchyId, maps, writes to cache; on error, falls back to cache._fetchFromRemoteWithFallback(): lee currentResourceProvider; si es null, cae al caché; si no llama al remoto con locationHierarchyId, mapea, graba en caché; en error, fallback al caché.

O locationHierarchySfid é resolvido aqui (§25 do CLAUDE.md), nunca no notifier.locationHierarchySfid is resolved here (CLAUDE.md §25), never in the notifier.El locationHierarchySfid se resuelve aquí (§25 del CLAUDE.md), nunca en el notifier.

checkEmail({email, target}) sem cache · offline falhano cache · fails offlinesin caché · falla offline

RetornaReturnsDevuelve Result<EmailCheckResultEntity, Failure>

Consulta se um e-mail já existe no Salesforce, para varejo (target: account) ou contato (target: contact). Não lê nem grava cache.Asks whether an e-mail already exists in Salesforce, for a retail (target: account) or a contact (target: contact). Neither reads nor writes cache.Consulta si un correo ya existe en Salesforce, para PDV (target: account) o contacto (target: contact). No lee ni graba caché.

Árvore de decisãoDecision treeÁrbol de decisión

  1. useMockData→ mock resolve por lista dentro do asset de reference_data; erro vira CacheFailure.→ the mock resolves from a list inside the reference_data asset; an error becomes CacheFailure.→ el mock resuelve desde una lista dentro del asset de reference_data; un error pasa a CacheFailure.
  2. offlineofflineofflineError(NetworkFailure()) sem tocar a rede; a UI traduz isso em "conecte-se para continuar".Error(NetworkFailure()) without touching the network; the UI turns that into "connect to continue".Error(NetworkFailure()) sin tocar la red; la UI lo traduce en "conéctate para continuar".
  3. sem representante em sessãono rep in sessionsin representante en sesiónError(UnknownFailure()).Error(UnknownFailure()).Error(UnknownFailure()).
  4. senãootherwisesi no→ remoto com resourceSfid (primaryResourceSfid ou secondaryResourceSfid, conforme a sessão) e target.wireValue; falha vira Failure mapeada e logada com traceId.→ remote with resourceSfid (primaryResourceSfid or secondaryResourceSfid, per the session) and target.wireValue; a failure becomes a mapped Failure, logged with its traceId.→ remoto con resourceSfid (primaryResourceSfid o secondaryResourceSfid, según la sesión) y target.wireValue; una falla pasa a Failure mapeada y registrada con traceId.
checkTaxNumber({taxId, taxNumber}) sem cache · offline falhano cache · fails offlinesin caché · falla offline

RetornaReturnsDevuelve Result<TaxNumberCheckResultEntity, Failure>

Mesma árvore do checkEmail, passo a passo (mock → offline → sem representante → remoto). Os dois parâmetros são mutuamente exclusivos: pessoa jurídica preenche taxId, os outros tipos preenchem taxNumber. Sem cache, sem Model.The same tree as checkEmail, step for step (mock → offline → no rep → remote). The two parameters are mutually exclusive: a legal entity fills taxId, other types fill taxNumber. No cache, no Model.El mismo árbol que checkEmail, paso a paso (mock → offline → sin representante → remoto). Los dos parámetros son mutuamente exclusivos: persona jurídica llena taxId, los otros tipos llenan taxNumber. Sin caché, sin Model.

getCachedReferenceData() local

RetornaReturnsDevuelve Result<ReferenceDataEntity?, Failure>

Só cache. null vira Success(null), não erro.Cache only. null becomes Success(null), not an error.Solo caché. null es Success(null), no error.

getCachedReferenceDataLastSyncAt() local

RetornaReturnsDevuelve DateTime? (sem Result)(no Result)(sin Result)

Timestamp da última sincronização das listas. Erros são apenas logados e devolvem null.Last-sync timestamp of the lists. Errors are logged only and return null.Timestamp de la última sincronización de las listas. Los errores solo se registran y devuelven null.

saveReferenceData({referenceData}) local

RetornaReturnsDevuelve Result<void, Failure>

Destrutivo: limpa as boxes e regrava o registro único. É o cache-writer chamado após cada fetch bem-sucedido.Destructive: clears the boxes and rewrites the single row. It is the cache-writer called after each successful fetch.Destructivo: limpia las boxes y regraba el registro único. Es el cache-writer llamado tras cada fetch exitoso.

DispatcherRepositoryImpl

send({envelope}) remote-only

RetornaReturnsDevuelve Result<DispatcherAck, Failure>

Único método da interface. Envolve o DispatcherGateway.send com breadcrumbs e converte qualquer exceção em Error(NetworkFailure(category: LogCategory.dispatch)). Não há gravação local para esta transação: o cadastro de varejo não é persistido antes nem depois — o que sobra no histórico do dispatcher é o registro do envio.The interface's only method. Wraps DispatcherGateway.send with breadcrumbs and converts any exception into Error(NetworkFailure(category: LogCategory.dispatch)). There is no local write for this transaction: the retail registration is not persisted before or after — what remains is the dispatcher's history row.Único método de la interfaz. Envuelve DispatcherGateway.send con breadcrumbs y convierte cualquier excepción en Error(NetworkFailure(category: LogCategory.dispatch)). No hay escritura local para esta transacción: el registro del PDV no se persiste antes ni después — lo que queda es el registro del historial del dispatcher.

09

Datasources

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

Remote ReferenceDataRemoteDataSource gRPC · 3 métodosmethodsmétodos

Tratamento de erro, idêntico nos três métodos: GrpcErrorGrpcExceptionHandler.handle (que lança NetworkException em unavailable/deadlineExceeded/cancelled e ServerException com status code nos demais); qualquer outra coisa → ServerException com mensagem própria.Error handling, identical in all three methods: GrpcErrorGrpcExceptionHandler.handle (which throws NetworkException on unavailable/deadlineExceeded/cancelled and ServerException with a status code otherwise); anything else → ServerException with its own message.Manejo de errores, idéntico en los tres métodos: GrpcErrorGrpcExceptionHandler.handle (que lanza NetworkException en unavailable/deadlineExceeded/cancelled y ServerException con status code en los demás); cualquier otra cosa → ServerException con su propio mensaje.

getReferenceData({locationHierarchySfid, lastModifiedDate?})
EnvioSendsEnvío
monta ReferenceDataRequest (só inclui lastModifiedDate quando não-vazio) e chama _client.getReferenceData(request).builds ReferenceDataRequest (only includes lastModifiedDate when non-empty) and calls _client.getReferenceData(request).arma ReferenceDataRequest (solo incluye lastModifiedDate cuando no está vacío) y llama _client.getReferenceData(request).
RetornoReturnRetorno
ReferenceDataDTO (via response.toDTO())(via response.toDTO())(vía response.toDTO())
Fluxo de usoUsage flowFlujo de uso
caminho remoto do repository; o resultado é gravado no cache.the repository's remote path; the result is written to cache.camino remoto del repository; el resultado se graba en caché.
Tratamento de erroError handlingManejo de errores
"Failed to fetch ReferenceData from gRPC" · o repository faz fallback pro cache.the repository falls back to cache.el repository hace fallback al caché.
checkTaxNumber({resourceSfid, taxId, taxNumber})
EnvioSendsEnvío
TaxNumberCheckRequest com os três campos → _client.taxNumberCheck(request).with the three fields → _client.taxNumberCheck(request).con los tres campos → _client.taxNumberCheck(request).
RetornoReturnRetorno
TaxNumberCheckResultDTO
Fluxo de usoUsage flowFlujo de uso
só na tela de validação de documento (Brasil), ao tocar em Validar.only on the document-validation screen (Brazil), on Validate.solo en la pantalla de validación de documento (Brasil), al tocar Validar.
Tratamento de erroError handlingManejo de errores
"Failed to run tax number check on gRPC"
checkEmail({resourceSfid, email, target}) novonewnuevo
EnvioSendsEnvío
EmailCheckRequest com resourceSfid, email e target como String crua (o enum é convertido no repository) → _client.emailCheck(request).with resourceSfid, email and target as a raw String (the enum is converted in the repository) → _client.emailCheck(request).con resourceSfid, email y target como String cruda (el enum se convierte en el repository) → _client.emailCheck(request).
RetornoReturnRetorno
EmailCheckResultDTO
Fluxo de usoUsage flowFlujo de uso
no Continuar dos dados operacionais e no Registrar/Salvar do colaborador, apenas nos mercados com a checagem ligada.on Next in operational data and on Register/Save for a contact, only in markets with the check on.en Continuar de los datos operacionales y en Registrar/Guardar del colaborador, solo en mercados con la verificación activa.
Tratamento de erroError handlingManejo de errores
"Failed to run email check on gRPC" · enquanto o backend não implementar o RPC, o retorno real é UNIMPLEMENTEDServerException → o representante não avança.until the backend implements the RPC, the real answer is UNIMPLEMENTEDServerException → the rep cannot proceed.mientras el backend no implemente el RPC, la respuesta real es UNIMPLEMENTEDServerException → el representante no avanza.
Mock ReferenceDataMockDataSource JSON · 3 métodosmethodsmétodos

Envio / fluxo: os três métodos carregam o mesmo asset — assets/mocks/reference_data/jsons/{mercado}_reference_data.json, ou {mercado}_real_reference_data.json quando useRealMockData está ligado (arquivo ausente devolve {}). Sem rede. Erro: qualquer falha vira CacheException.Sends / flow: all three methods load the same asset — assets/mocks/reference_data/jsons/{market}_reference_data.json, or {market}_real_reference_data.json when useRealMockData is on (a missing file yields {}). No network. Error: any failure becomes a CacheException.Envío / flujo: los tres métodos cargan el mismo asset — assets/mocks/reference_data/jsons/{mercado}_reference_data.json, o {mercado}_real_reference_data.json cuando useRealMockData está activo (archivo ausente devuelve {}). Sin red. Error: cualquier falla pasa a CacheException.

getReferenceData()
RetornoReturnRetorno
ReferenceDataDTO (via fromMap)(via fromMap)(vía fromMap)
ComportamentoBehaviorComportamiento
grava no cache como um fetch normal. Atenção ao mock do Chile: a hierarquia geográfica ainda tem dados brasileiros de exemplo (São Paulo/Rio) — irrelevante hoje porque o Chile usa texto livre, mas errado se algum dia voltar a usar listas.writes to cache like a normal fetch. Careful with the Chile mock: the geographical hierarchy still has Brazilian sample data (São Paulo/Rio) — irrelevant today because Chile uses free text, but wrong if dropdowns ever come back.graba en caché como un fetch normal. Atención al mock de Chile: la jerarquía geográfica aún tiene datos brasileños de ejemplo (São Paulo/Rio) — irrelevante hoy porque Chile usa texto libre, pero incorrecto si algún día vuelve a usar listas.
checkTaxNumber({taxId, taxNumber})
RetornoReturnRetorno
TaxNumberCheckResultDTO
ComportamentoBehaviorComportamiento
lê o bloco taxNumberCheck do asset: escolhe taxId se não-vazio, senão taxNumber, e compara com blackListedDocuments e documentsInUse; blackListMessage só volta quando bloqueado. O bloco existe em br_real_reference_data.json — no mock padrão o resultado é sempre "liberado".reads the asset's taxNumberCheck block: picks taxId when non-empty, else taxNumber, and compares against blackListedDocuments and documentsInUse; blackListMessage only comes back when blocked. The block exists only in br_real_reference_data.json — in the standard mock the answer is always "cleared".lee el bloque taxNumberCheck del asset: elige taxId si no está vacío, si no taxNumber, y compara con blackListedDocuments y documentsInUse; blackListMessage solo vuelve cuando está bloqueado. El bloque existe solo en br_real_reference_data.json — en el mock estándar el resultado es siempre "liberado".
checkEmail({email, target}) novonewnuevo
RetornoReturnRetorno
EmailCheckResultDTO
ComportamentoBehaviorComportamiento
lê o bloco emailCheck do asset e escolhe a lista pelo target: accountEmailsInUse ou contactEmailsInUse. Comparação case-insensitive com trim(); message só volta quando há acerto. Recebe o enum EmailCheckTarget (o remoto recebe String).reads the asset's emailCheck block and picks the list by target: accountEmailsInUse or contactEmailsInUse. Case-insensitive comparison with trim(); message only comes back on a hit. Takes the EmailCheckTarget enum (the remote takes a String).lee el bloque emailCheck del asset y elige la lista por target: accountEmailsInUse o contactEmailsInUse. Comparación case-insensitive con trim(); message solo vuelve al acertar. Recibe el enum EmailCheckTarget (el remoto recibe String).
Dados de mockMock dataDatos de mock
BR varejo.existente@conectarep.com.br / contato.existente@conectarep.com.br; CL varejo.existente@conectarep.cl / contacto.existente@conectarep.cl; ZA retail.existing@conectarep.co.za / contact.existing@conectarep.co.za. AR/PY/PE não têm o bloco → sempre "disponível".BR varejo.existente@conectarep.com.br / contato.existente@conectarep.com.br; CL varejo.existente@conectarep.cl / contacto.existente@conectarep.cl; ZA retail.existing@conectarep.co.za / contact.existing@conectarep.co.za. AR/PY/PE have no block → always "available".BR varejo.existente@conectarep.com.br / contato.existente@conectarep.com.br; CL varejo.existente@conectarep.cl / contacto.existente@conectarep.cl; ZA retail.existing@conectarep.co.za / contact.existing@conectarep.co.za. AR/PY/PE no tienen el bloque → siempre "disponible".
Local ReferenceDataLocalDataSource ObjectBox · 4 métodos síncronossynchronous methodsmétodos sincrónicos

Envio / fluxo: persistência local via ObjectBox — registro único de ReferenceDataModel mais as boxes filhas; sem rede. Alimenta os caminhos de cache do repository. Erro: toda falha vira CacheException (nunca engolida). Não há método de checagem aqui — nem e-mail nem documento são cacheados.Sends / flow: local persistence via ObjectBox — a single ReferenceDataModel row plus the child boxes; no network. Feeds the repository's cache paths. Error: every failure becomes a CacheException (never swallowed). There is no check method here — neither e-mail nor document is cached.Envío / flujo: persistencia local vía ObjectBox — registro único de ReferenceDataModel más las boxes hijas; sin red. Alimenta los caminos de caché del repository. Error: toda falla pasa a CacheException (nunca tragada). No hay método de verificación aquí — ni el correo ni el documento se cachean.

getReferenceData()
RetornoReturnRetorno
ReferenceDataEntity?
ComportamentoBehaviorComportamiento
models.first.toDomain() ou null se o cache está vazio.or null if the cache is empty.o null si el caché está vacío.
getReferenceDataLastSyncAt()
RetornoReturnRetorno
DateTime?
ComportamentoBehaviorComportamiento
models.first.lastSyncAté o valor exibido no DataLoadInfo de todas as 9 telas.the value shown in the DataLoadInfo on all 9 screens.el valor mostrado en el DataLoadInfo de las 9 pantallas.
saveReferenceData({entity})
RetornoReturnRetorno
void
ComportamentoBehaviorComportamiento
clearReferenceData() + _box.put(entity.toModel()) — grava as boxes filhas em cascata.clearReferenceData() + _box.put(entity.toModel()) — writes child boxes in cascade.clearReferenceData() + _box.put(entity.toModel()) — graba las boxes hijas en cascada.
clearReferenceData()
RetornoReturnRetorno
void
ComportamentoBehaviorComportamiento
limpa as boxes na ordem filhas→raiz. As duas boxes de motivos de visita não são limpas — resíduo conhecido, sem efeito neste fluxo.clears boxes children→root. The two visit-reason boxes are not cleared — a known leftover, harmless to this flow.limpia las boxes hijas→raíz. Las dos boxes de motivos de visita no se limpian — residuo conocido, sin efecto en este flujo.
Gateway DispatcherGateway gRPC · escritawriteescritura
send({envelope})
EnvioSendsEnvío
serializa o payload com jsonEncode e monta InboxTransactionRequest (endpoint, serviceName, dateReference, transactionReference, username, message, dados do dispositivo, deviceUuid: "REP", tid), com authorization: Bearer nos metadados → sendTransaction.serializes the payload with jsonEncode and builds InboxTransactionRequest (endpoint, serviceName, dateReference, transactionReference, username, message, device data, deviceUuid: "REP", tid), with authorization: Bearer in the metadata → sendTransaction.serializa el payload con jsonEncode y arma InboxTransactionRequest (endpoint, serviceName, dateReference, transactionReference, username, message, datos del dispositivo, deviceUuid: "REP", tid), con authorization: Bearer en los metadatos → sendTransaction.
RetornoReturnRetorno
DispatcherAck (status, transactionId, message) — sucesso quando status é 0 ou 5; 1 é duplicado.(status, transactionId, message) — success when status is 0 or 5; 1 means duplicate.(status, transactionId, message) — éxito cuando status es 0 o 5; 1 es duplicado.
Fluxo de usoUsage flowFlujo de uso
chamado pelo orchestrator. Em useMockData há curto-circuito; offline lança NetworkException; um 401 tenta uma vez com token renovado.called by the orchestrator. Under useMockData it short-circuits; offline it throws NetworkException; a 401 retries once with a refreshed token.llamado por el orchestrator. Con useMockData hace corto-circuito; offline lanza NetworkException; un 401 reintenta una vez con token renovado.
Tratamento de erroError handlingManejo de errores
exceções sobem para o repository, que devolve NetworkFailure. A mensagem crua do backend é logada, nunca exibida; a UI usa trFailure com a mensagem genérica do fluxo como fallback.exceptions bubble to the repository, which returns NetworkFailure. The backend's raw message is logged, never shown; the UI uses trFailure with the flow's generic message as fallback.las excepciones suben al repository, que devuelve NetworkFailure. El mensaje crudo del backend se registra, nunca se muestra; la UI usa trFailure con el mensaje genérico del flujo como fallback.

Log com base64Log with base64Log con base64 O gateway registra o request inteiro em log formatado — incluindo as fotos em base64. Vale saber antes de coletar logs deste fluxo. The gateway logs the entire pretty-printed request — including the base64 photos. Worth knowing before collecting logs from this flow. El gateway registra el request completo en log formateado — incluyendo las fotos en base64. Vale saberlo antes de recolectar logs de este flujo.

Serviços apoio ao fluxoflow supportapoyo al flujo 4
FileCaptureService fotos de início de atividadestart-of-activity photosfotos de inicio de actividad
newSessionId()
cria a sessão de arquivos no build() do notifier.creates the file session in the notifier's build().crea la sesión de archivos en el build() del notifier.
captureImage({source, sessionId})
Future<CapturedFileEntity?> · comprime na captura: escada de 6 passos (1600/80 → 640/40), JPEG, para no primeiro resultado ≤ 300 KB.compresses at capture: a 6-step ladder (1600/80 → 640/40), JPEG, stopping at the first result ≤ 300 KB.comprime al capturar: escalera de 6 pasos (1600/80 → 640/40), JPEG, se detiene en el primer resultado ≤ 300 KB.
readAsBase64({file})
Future<String> · base64Encode puro, sem prefixo data: — chamado no envio, foto por foto.plain base64Encode, no data: prefix — called on submit, photo by photo.base64Encode puro, sin prefijo data: — llamado en el envío, foto por foto.
deleteFile({file})
apaga uma foto descartada ou removida da lista.deletes a discarded or removed photo.borra una foto descartada o quitada de la lista.
cleanupSession({sessionId})
no ref.onDispose do notifier: apaga todas as fotos ao sair do fluxo.in the notifier's ref.onDispose: deletes every photo when leaving the flow.en el ref.onDispose del notifier: borra todas las fotos al salir del flujo.
PostalCodeLookupService CEP (Brasil)postal code (Brazil)código postal (Brasil)
lookup({postalCode})
Future<Result<PostalCodeAddressEntity, Failure>> · devolve rua, bairro, cidade e sigla do estado. NetworkFailure libera digitação manual; qualquer outra falha vira "CEP não encontrado".returns street, district, city and state code. NetworkFailure unlocks manual entry; any other failure becomes "postal code not found".devuelve calle, barrio, ciudad y sigla del estado. NetworkFailure habilita la entrada manual; cualquier otra falla es "código postal no encontrado".
Google Places + geocoding busca de endereço (Chile)address search (Chile)búsqueda de dirección (Chile)
AutocompleteAutocompleteAutocompletado
GooglePlaceAutoCompleteTextField com a chave de GoogleMapsConfig.apiKey (vem do .env), debounce 600 ms, país e idioma do mercado ativo.GooglePlaceAutoCompleteTextField with the key from GoogleMapsConfig.apiKey (loaded from .env), 600 ms debounce, country and language of the active market.GooglePlaceAutoCompleteTextField con la clave de GoogleMapsConfig.apiKey (del .env), debounce de 600 ms, país e idioma del mercado activo.
ResoluçãoResolutionResolución
a sugestão devolve latitude/longitude; placemarkFromCoordinates preenche estado (região), cidade (comuna), bairro, rua e número. Erro é apenas logado — o representante segue digitando à mão.the suggestion returns latitude/longitude; placemarkFromCoordinates fills state (region), city (comuna), district, street and number. An error is only logged — the rep keeps typing manually.la sugerencia devuelve latitud/longitud; placemarkFromCoordinates completa estado (región), ciudad (comuna), barrio, calle y número. El error solo se registra — el representante sigue escribiendo a mano.
LocationService GPS
currentPosition
Position? · lido no envio; sem posição, o payload leva 0.0 em latitude e longitude.read on submit; with no position, the payload carries 0.0 for latitude and longitude.leído en el envío; sin posición, el payload lleva 0.0 en latitud y longitud.
10

Enums e labelsEnums & labelsEnums y labels

Um dropdown por enum, com todos os valores. Os enums de campo (NewRetail*Field) são o vocabulário fechado que a configuração do mercado pode usar — chave desconhecida cai em unknown e o campo simplesmente não é renderizado.One dropdown per enum, with every value. The field enums (NewRetail*Field) are the closed vocabulary market configuration may use — an unknown key falls to unknown and the field is simply not rendered.Un dropdown por enum, con todos los valores. Los enums de campo (NewRetail*Field) son el vocabulario cerrado que la configuración del mercado puede usar — una clave desconocida cae en unknown y el campo simplemente no se renderiza.

EmailCheckTarget 2 · novonewnuevo
casewireValueo que consultawhat it queriesqué consulta
account"account"e-mail já usado por algum varejoe-mail already used by a retailcorreo ya usado por algún PDV
contact"contact"e-mail já usado por algum contatoe-mail already used by a contactcorreo ya usado por algún contacto

Sem unknown e sem fromWire — o enum só vai para o wire, nunca volta.No unknown and no fromWire — the enum only goes to the wire, never comes back.Sin unknown y sin fromWire — el enum solo va al wire, nunca vuelve.

NewRetailEmailCheckOutcome 5 · novonewnuevo
casei18n keycanProceed
availablenenhumanoneningunatrue
accountTakennew_retail_account_email_in_use_messagefalse
contactTakennew_retail_contact_email_in_use_messagefalse
offlinenew_retail_email_check_offline_messagefalse
errornew_retail_email_check_error_messagefalse
NewRetailType 3
casechave no EMCEMC keyclave en el EMCi18n keyíconeiconicono
generic"generic"new_retail_type_generic_labeldrawerRetailsShop
individual"individual"new_retail_type_individual_labelnewRetailIndividual
business"business"new_retail_type_business_labeldrawerRetailsShop

Chave desconhecida cai em generic silenciosamente — um erro de digitação no EMC não quebra, mas muda o comportamento.An unknown key falls to generic silently — a typo in the EMC does not crash, but changes behavior.Una clave desconocida cae en generic silenciosamente — un error de tipeo en el EMC no rompe, pero cambia el comportamiento.

NewRetailLegalEntityField 5
casewireValuecampo na telascreen fieldcampo en la pantalla
document"document"CNPJ / CPF / RUT / VATCNPJ / CPF / RUT / VATCNPJ / CPF / RUT / VAT
stateRegistration"state_registration"Inscrição Estadualstate registrationinscripción estatal
legalName"legal_name"Razão Sociallegal namerazón social
tradeName"trade_name"Nome Fantasiatrade namenombre de fantasía
unknown""não renderizarenders nothingno renderiza
NewRetailAddressField 9
casewireValuecampo na telascreen fieldcampo en la pantalla
addressSearch"address_search"busca de endereço (Places)address search (Places)búsqueda de dirección (Places)
postalCode"postal_code"CEP / código postalpostal codecódigo postal
street"street"endereço / ruaaddress / streetdirección / calle
number"number"númeronumbernúmero
complement"complement"complementocomplementcomplemento
neighborhood"neighborhood"bairro / comunadistrict / comunabarrio / comuna
city"city"cidadecityciudad
state"state"estado / regiãostate / regionestado / región
unknown""não renderizarenders nothingno renderiza
NewRetailOperationalDataField 19
casewireValuetipo de controlecontrol typetipo de control
cellPhone"cell_phone"texto (telefone)text (phone)texto (teléfono)
phone"phone"texto (telefone)text (phone)texto (teléfono)
email"email"texto (e-mail, máx. 80)text (e-mail, max 80)texto (correo, máx. 80)
outletSubtype"outlet_subtype"lista únicasingle dropdownlista única
categoriesForSale"categories_for_sale"lista múltiplamulti dropdownlista múltiple
operatingDays"operating_days"editor de dias + horáriosdays + hours editoreditor de días + horarios
salesmanVisitDay"salesman_visit_day"lista única (dia da semana)single dropdown (weekday)lista única (día de la semana)
deliveryDay"delivery_day"lista única (dia da semana)single dropdown (weekday)lista única (día de la semana)
localClassification"local_classification"lista + campo dependentedropdown + dependent fieldlista + campo dependiente
banner"banner"lista únicasingle dropdownlista única
propertyType"property_type"lista únicasingle dropdownlista única
keyAccountType"key_account_type"lista únicasingle dropdownlista única
giro"giro"lista única (wire emlov1)single dropdown (wire emlov1)lista única (wire emlov1)
channel"channel"lista única (wire emlov2)single dropdown (wire emlov2)lista única (wire emlov2)
businessInterval"business_interval"dois seletores de horatwo time pickersdos selectores de hora
b2bCustomer"b2b_customer"interruptortoggleinterruptor
directSales"direct_sales"interruptortoggleinterruptor
networkParent"network_parent"interruptortoggleinterruptor
unknown""não renderizarenders nothingno renderiza
NewRetailContactField 11
casewireValuetipo de controlecontrol typetipo de control
pronoun"pronoun"lista únicasingle dropdownlista única
languagePreference"language_preference"lista únicasingle dropdownlista única
fullName"full_name"texto (dividido em primeiro/último ao salvar)text (split into first/last on save)texto (dividido en primero/último al guardar)
firstName"first_name"textotexttexto
lastName"last_name"textotexttexto
role"role"lista únicasingle dropdownlista única
mainContact"main_contact"interruptor (com modal de troca)toggle (with a replace modal)interruptor (con modal de reemplazo)
cellPhone"cell_phone"texto (telefone)text (phone)texto (teléfono)
email"email"texto (e-mail, máx. 80)text (e-mail, max 80)texto (correo, máx. 80)
dateOfBirth"date_of_birth"calendário (limite de 18 anos)calendar (18-year bound)calendario (límite de 18 años)
unknown""não renderizarenders nothingno renderiza
NewRetailAddressLookupStatus 5
casesignificadomeaningsignificado
idlenenhuma busca em andamento (estado inicial e a cada dígito do CEP)no lookup running (initial state, and on every postal-code keystroke)ninguna búsqueda en curso (estado inicial y en cada dígito del código)
loadingconsultando o CEPlooking the postal code upconsultando el código postal
resolvedendereço preenchido e cidade dentro da área de atuaçãoaddress filled and city inside the operating areadirección completada y ciudad dentro del área de actuación
manualEntryfalhou por rede — libera digitação manual e permite avançarfailed for network reasons — unlocks manual entry and allows moving onfalló por red — habilita entrada manual y permite avanzar
errornão encontrado ou fora da área — bloqueia e limpa camposnot found or out of area — blocks and clears fieldsno encontrado o fuera del área — bloquea y limpia campos
NewRetailFieldLength 3
casevalueonde se aplicawhere it appliesdónde se aplica
email80e-mail do varejo e do contato (via EmailUtils, compartilhado)retail and contact e-mail (via shared EmailUtils)correo del PDV y del contacto (vía EmailUtils, compartido)
street150campo de rua + truncagem do retorno do CEPstreet field + truncation of the postal-code resultcampo de calle + truncado del resultado del código postal
district35campo de bairro + truncagem do retorno do CEPdistrict field + truncation of the postal-code resultcampo de barrio + truncado del resultado del código postal

Valores fixos no código, iguais em todos os mercados — não vêm do EMC.Hardcoded values, the same in every market — they do not come from the EMC.Valores fijos en el código, iguales en todos los mercados — no vienen del EMC.

Pronoun 3
casewireValuei18n key
mr"Mr."pronoun_mr
mrs"Mrs."pronoun_mrs
miss"Miss"pronoun_miss

Lista fixa no app (não vem de dados de apoio) — pendência conhecida de dado hardcoded.A hardcoded list (it does not come from reference data) — a known hardcoded-data pendency.Lista fija en la app (no viene de datos de apoyo) — pendencia conocida de dato hardcoded.

ContactRole 8
caselabel (wire)i18n key
clerk"Clerk"contact_role_clerk
supervisor"Supervisor"contact_role_supervisor
manager"Manager"contact_role_manager
attendant"Attendant"contact_role_attendant
owner"Owner"contact_role_owner
primaryContact"Primary Contact"contact_role_primary_contact
staff"Staff"contact_role_staff
unknown""texto cru de fallbackraw fallback texttexto crudo de fallback

A lista oferecida na tela vem dos dados de apoio (contactRoles), resolvida por fromLabel (sem distinção de caixa). O label é o que vai no payload; manager é reutilizado como contactPosition do contato principal de uma matriz de rede.The list offered on screen comes from reference data (contactRoles), resolved via fromLabel (case-insensitive). label is what goes on the wire; manager is reused as the contactPosition of a network parent's main contact.La lista ofrecida en pantalla viene de los datos de apoyo (contactRoles), resuelta vía fromLabel (sin distinguir mayúsculas). El label es lo que va en el payload; manager se reutiliza como contactPosition del contacto principal de una matriz de red.

LocalClassificationType 4
casewireValuetransactionValuecampo dependentedependent fieldcampo dependiente
picklist"picklist""Picklist"lista das options da definiçãodropdown of the definition's optionslista de las options de la definición
number"number""Number"campo numériconumeric fieldcampo numérico
text"text""Text"campo de textotext fieldcampo de texto
unknown""""nenhumnoneninguno

fromWire compara em minúsculas — os mocks trazem tanto "Picklist" quanto "picklist". O transactionValue (capitalizado) é o que vai no payload.fromWire compares lowercase — the mocks carry both "Picklist" and "picklist". transactionValue (capitalized) is what goes on the wire.fromWire compara en minúsculas — los mocks traen tanto "Picklist" como "picklist". El transactionValue (capitalizado) es lo que va en el payload.

WeekDay 7
casewireValuewireAbbreviationi18n key
monday"Monday""MON"weekday_monday
tuesday"Tuesday""TUE"weekday_tuesday
wednesday"Wednesday""WED"weekday_wednesday
thursday"Thursday""THU"weekday_thursday
friday"Friday""FRI"weekday_friday
saturday"Saturday""SAT"weekday_saturday
sunday"Sunday""SUN"weekday_sunday

O dia de entrega vai no payload como abreviação; o dia de visita, como nome completo; os dias de funcionamento, como wireValue unidos por ;.The delivery day goes on the wire as the abbreviation; the visit day, as the full name; operating days, as wireValues joined by ;.El día de entrega va en el payload como abreviatura; el día de visita, como nombre completo; los días de funcionamiento, como wireValue unidos por ;.

CategoryForSale 17
casewireValuelabel
fmc"fmc""FMC"
thpDevices"thp_devices""THP Devices"
thpSticks"thp_sticks""THP Sticks"
vapourDevices"vapour_devices""Vapour Devices"
vapourLiquids"vapour_liquids""Vapour Liquids"
oral"oral""Oral"
ryo"ryo""RYO"
myo"myo""MYO"
otp"otp""OTP"
otpAccessories"otp_accessories""OTP Accessories"
otherEa"other_ea""Other EA"
otherUnit"other_unit""Other UNIT"
otherPce"other_pce""Other PCE"
vuse"vuse""VUSE"
partnership"partnership""Partnership"
nc"nc""NC"
unknown""""

fromValue aceita o wireValue ou o label, sem distinção de caixa — por isso os mocks podem trazer "FMC" ou "fmc". O payload usa o label.fromValue accepts either the wireValue or the label, case-insensitive — which is why mocks may carry "FMC" or "fmc". The payload uses the label.fromValue acepta el wireValue o el label, sin distinguir mayúsculas — por eso los mocks pueden traer "FMC" o "fmc". El payload usa el label.

LanguagePreference 30
caselabelisoCode
english"English""en_US"
afrikaans"Afrikaans""af"
xhosa"Xhosa""xh"
zulu"Zulu""zu"
sesotho"Sesotho""st"
tsonga"Tsonga""ts"
portuguese"Portuguese""pt"
spanish"Spanish""es"
mandarin"Mandarin""zh"
french"French""fr"
russian"Russian""ru"
ukrainian"Ukrainian""uk"
german"German""de"
italian"Italian""it"
polish"Polish""pl"
chinese"Chinese""zh"
dutch"Dutch""nl"
romanian"Romanian""ro"
arabic"Arabic""ar"
cantonese"Cantonese""yue"
korean"Korean""ko"
vietnamese"Vietnamese""vi"
bengaliBangladesh"Bengali (Bangladesh)""bn"
tamil"Tamil""ta"
malay"Malay""ms"
hindi"Hindi""hi"
urduPakistan"Urdu (Pakistan)""ur"
englishAustralian"English_Australian""en_AU"
estonian"Estonia""et"
unknown""""

A lista oferecida vem dos dados de apoio (languagePreferences), resolvida por fromLabel. No payload vai o isoCode, com fallback "en_US" quando o valor é desconhecido.The offered list comes from reference data (languagePreferences), resolved via fromLabel. The wire carries the isoCode, falling back to "en_US" when the value is unknown.La lista ofrecida viene de los datos de apoyo (languagePreferences), resuelta vía fromLabel. En el payload va el isoCode, con fallback "en_US" cuando el valor es desconocido.

SubmissionStatus 4 · compartilhadosharedcompartido
caseo que o modal mostrawhat the modal showsqué muestra el modal
idlepergunta de confirmação (Não / Sim)confirmation question (No / Yes)pregunta de confirmación (No / Sí)
submittingbotão em carregamento; fechar e dispensar bloqueadosloading button; close and dismiss blockedbotón cargando; cerrar y descartar bloqueados
successmensagem de sucesso + único botão Fecharsuccess message + a single Close buttonmensaje de éxito + un único botón Cerrar
failuremensagem do erro real (trFailure) + Voltar / Tentar novamentereal error message (trFailure) + Come back / Try againmensaje del error real (trFailure) + Volver / Intentar de nuevo
CaptureSource 2
caseuso neste fluxouse in this flowuso en este flujo
cameraé o único usado — capturar e refazer sempre abrem a câmerathe only one used — capture and retake always open the camerael único usado — capturar y rehacer siempre abren la cámara
gallerydisponível no serviço, não usado aquiavailable in the service, not used heredisponible en el servicio, no usado aquí
11

UseCases

Cinco UseCases servem o fluxo — dois de leitura/checagem, um de leitura das listas e dois de escrita. Um dropdown por UseCase, com Método · Retorna · Uso.Five UseCases serve the flow — two checks, one list read and two writes. One dropdown per UseCase, with Method · Returns · Use.Cinco UseCases sirven al flujo — dos verificaciones, uno de lectura de listas y dos de escritura. Un dropdown por UseCase, con Método · Devuelve · Uso.

CheckEmailUseCase 1 · novonewnuevo
MétodoMethodMétodoRetornaReturnsDevuelveUsoUseUso
execute({email, target})Result<EmailCheckResultEntity, Failure>Aplica trim() no e-mail e delega ao repository com o EmailCheckTarget. Chamado pelos dois métodos de checagem do notifier.Applies trim() to the e-mail and delegates to the repository with the EmailCheckTarget. Called by the notifier's two check methods.Aplica trim() al correo y delega al repository con el EmailCheckTarget. Llamado por los dos métodos de verificación del notifier.
CheckTaxNumberUseCase 1
MétodoMethodMétodoRetornaReturnsDevuelveUsoUseUso
execute({document, type})Result<TaxNumberCheckResultEntity, Failure>Reduz o documento a dígitos e decide o campo: pessoa jurídica → taxId; qualquer outro tipo → taxNumber. É a regra de domínio que separa CNPJ de CPF.Reduces the document to digits and picks the field: legal entity → taxId; any other type → taxNumber. This is the domain rule separating CNPJ from CPF.Reduce el documento a dígitos y elige el campo: persona jurídica → taxId; cualquier otro tipo → taxNumber. Es la regla de dominio que separa CNPJ de CPF.
GetReferenceDataUseCase 3
MétodoMethodMétodoRetornaReturnsDevuelveUsoUseUso
execute({source = local})Result<ReferenceDataEntity, Failure>Fonte das 11 listas que o fluxo usa. local no build(), remote no refresh.Source of the 11 lists the flow uses. local in build(), remote on refresh.Fuente de las 11 listas que usa el flujo. local en el build(), remote en el refresh.
getCached()Result<ReferenceDataEntity?, Failure>Só cache; não usado por este fluxo.Cache only; not used by this flow.Solo caché; no usado por este flujo.
getCachedLastSyncAt()DateTime?Timestamp de sincronização; aqui o valor chega junto com a entity.Sync timestamp; here the value arrives with the entity itself.Timestamp de sincronización; aquí el valor llega junto con la entity.
BuildNewRetailUploadDispatcherPayloadUseCase 1 · puropurepuro
MétodoMethodMétodoRetornaReturnsDevuelveUsoUseUso
build({input})DispatcherEnvelopeImplementa DispatcherPayloadBuilder<NewRetailUploadDispatcherPayloadInput>. Função pura: monta as 7 seções do payload por métodos privados (_buildAccountData, _buildContactData, _buildTerritoryStoreMapping, _buildGlobalClassification, _buildLocalClassification, _buildLocalClassificationDefinition, _buildDocumentData) + utilitários (_digitsOnly, _formatBirthdate, _imageAt, _languagePreferenceCode, _salesTerritory). Sem I/O, sem relógio próprio.Implements DispatcherPayloadBuilder<NewRetailUploadDispatcherPayloadInput>. A pure function: assembles the 7 payload sections through private methods (_buildAccountData, _buildContactData, _buildTerritoryStoreMapping, _buildGlobalClassification, _buildLocalClassification, _buildLocalClassificationDefinition, _buildDocumentData) + helpers (_digitsOnly, _formatBirthdate, _imageAt, _languagePreferenceCode, _salesTerritory). No I/O, no clock of its own.Implementa DispatcherPayloadBuilder<NewRetailUploadDispatcherPayloadInput>. Función pura: arma las 7 secciones del payload con métodos privados (_buildAccountData, _buildContactData, _buildTerritoryStoreMapping, _buildGlobalClassification, _buildLocalClassification, _buildLocalClassificationDefinition, _buildDocumentData) + utilitarios (_digitsOnly, _formatBirthdate, _imageAt, _languagePreferenceCode, _salesTerritory). Sin I/O, sin reloj propio.
SubmitNewRetailUploadUseCase 1
MétodoMethodMétodoRetornaReturnsDevuelveUsoUseUso
submit({envelope})Result<DispatcherAck, Failure>Repasse puro para DispatcherOrchestrator.dispatch — sem estado, sem chamada ao builder, sem divisão em vários envelopes.A pure pass-through to DispatcherOrchestrator.dispatch — no state, no builder call, no splitting into multiple envelopes.Paso directo a DispatcherOrchestrator.dispatch — sin estado, sin llamada al builder, sin división en varios envelopes.

Fila offline não cobre este cadastroThe offline queue does not cover this registrationLa cola offline no cubre este registro O DispatcherOrchestrator só enfileira transações de visita quando offline. Um cadastro de varejo enviado sem rede segue para o gateway, lança NetworkException e entra no histórico como erro. O reenvio manual existe, mas retailNew é marcado como reenvio pode duplicar. DispatcherOrchestrator only queues visit transactions when offline. A retail registration submitted with no network goes to the gateway, throws NetworkException and lands in history as an error. Manual resend exists, but retailNew is flagged as resend may duplicate. El DispatcherOrchestrator solo encola transacciones de visita cuando está offline. Un registro de PDV enviado sin red va al gateway, lanza NetworkException y entra en el historial como error. El reenvío manual existe, pero retailNew está marcado como el reenvío puede duplicar.

12

Notifier & State

O fluxo tem dois notifiers. O NewRetailFlowNotifier (@riverpod, with AsyncGuard<NewRetailFlowState>) é o cérebro das 9 telas: o build() cria a sessão de arquivos, registra a limpeza no ref.onDispose e devolve _load(source: local); o State (NewRetailFlowState, Freezed, 74 campos) é a fonte única de verdade de todo o assistente — configuração do mercado, listas de apoio, valores digitados, fotos, rascunho de contato e status do envio. O NewRetailDocumentValidationNotifier é um notifier síncrono e local da tela de validação de documento (Brasil). Toda validação de formulário acontece nos métodos privados _updateLegalEntity, _updateAddress, _updateOperationalData e _updateContactDraft, que recalculam erro e validade a cada tecla.The flow has two notifiers. NewRetailFlowNotifier (@riverpod, with AsyncGuard<NewRetailFlowState>) is the brain of the 9 screens: build() creates the file session, registers cleanup on ref.onDispose and returns _load(source: local); the State (NewRetailFlowState, Freezed, 74 fields) is the wizard's single source of truth — market configuration, supporting lists, typed values, photos, contact draft and submission status. NewRetailDocumentValidationNotifier is a synchronous, local notifier for the document-validation screen (Brazil). All form validation happens in the private methods _updateLegalEntity, _updateAddress, _updateOperationalData and _updateContactDraft, which recompute error and validity on every keystroke.El flujo tiene dos notifiers. El NewRetailFlowNotifier (@riverpod, with AsyncGuard<NewRetailFlowState>) es el cerebro de las 9 pantallas: el build() crea la sesión de archivos, registra la limpieza en ref.onDispose y devuelve _load(source: local); el State (NewRetailFlowState, Freezed, 74 campos) es la fuente única de verdad de todo el asistente — configuración del mercado, listas de apoyo, valores escritos, fotos, borrador de contacto y estado del envío. El NewRetailDocumentValidationNotifier es un notifier sincrónico y local de la pantalla de validación de documento (Brasil). Toda validación de formulario ocurre en los métodos privados _updateLegalEntity, _updateAddress, _updateOperationalData y _updateContactDraft, que recalculan error y validez en cada tecla.

Métodos — NewRetailFlowNotifierMethods — NewRetailFlowNotifierMétodos — NewRetailFlowNotifier

build() ciclo de vidalifecycleciclo de vida

RetornoReturnRetorno FutureOr<NewRetailFlowState>

Cria o sessionId de captura, registra cleanupSession no ref.onDisposeaqui que as fotos são apagadas ao abandonar o fluxo) e delega a montagem ao _load(source: local) via guardedBuild.Creates the capture sessionId, registers cleanupSession on ref.onDispose (this is where photos get deleted when the flow is abandoned) and delegates assembly to _load(source: local) through guardedBuild.Crea el sessionId de captura, registra cleanupSession en ref.onDispose (es aquí donde se borran las fotos al abandonar el flujo) y delega el armado a _load(source: local) vía guardedBuild.

_load({source}) private

RetornoReturnRetorno Future<NewRetailFlowState>

Dono único da montagem do State: lê a configuração do mercado e as listas de apoio (falha tolerada — as listas viram vazias), copia as 13 chaves do newRetailConfig para o State, semeia horário 07:30/18:30 e, quando o mercado tem preenchimento por CEP e um único estado atendido, já seleciona esse estado.Sole owner of building the State: reads market configuration and the supporting lists (failure tolerated — lists become empty), copies the 13 newRetailConfig keys into the State, seeds 07:30/18:30 hours and, when the market has postal-code auto-fill and a single served state, pre-selects that state.Dueño único del armado del State: lee la configuración del mercado y las listas de apoyo (falla tolerada — las listas quedan vacías), copia las 13 claves del newRetailConfig al State, siembra horario 07:30/18:30 y, cuando el mercado tiene autocompletado por código postal y un único estado atendido, ya selecciona ese estado.

refresh() pull-to-refresh

RetornoReturnRetorno Future<void>

Recarrega com source: remote e preserva tudo o que o representante já digitou: só as 23 chaves de configuração e listas são substituídas por copyWith. Não seta AsyncValue.loading. Disponível apenas na primeira tela.Reloads with source: remote and preserves everything the rep already typed: only the 23 configuration/list keys are replaced via copyWith. Does not set AsyncValue.loading. Available on the first screen only.Recarga con source: remote y preserva todo lo que el representante ya escribió: solo las 23 claves de configuración y listas se reemplazan con copyWith. No setea AsyncValue.loading. Disponible solo en la primera pantalla.

selectType({type}) · clearSelection()

RetornoReturnRetorno void

Definem/limpam o selectedType — a chave que resolve todas as listas de campos por tipo. Ambos saem cedo se o valor não muda.Set/clear selectedType — the key that resolves every per-type field list. Both early-return when the value does not change.Definen/limpian el selectedType — la clave que resuelve todas las listas de campos por tipo. Ambos salen temprano si el valor no cambia.

toggleDocumentRequirementExpansion({id})

RetornoReturnRetorno void

Abre/fecha um acordeão de documentos exigidos. A expansão vive no State (um Set de ids), então sobrevive a rebuilds.Opens/closes a required-documents accordion. Expansion lives in the State (a Set of ids), so it survives rebuilds.Abre/cierra un acordeón de documentos exigidos. La expansión vive en el State (un Set de ids), así que sobrevive a los rebuilds.

captureStartOfActivityPhotoForReview({source})

RetornoReturnRetorno Future<void>

Abre a câmera e coloca o resultado em pendingStartOfActivityPhoto (o que muda a interface do modal para pré-visualização). Sai cedo se já está capturando, se há foto pendente ou se o máximo foi atingido.Opens the camera and puts the result in pendingStartOfActivityPhoto (which switches the modal to preview). Early-returns if already capturing, if a pending photo exists or if the maximum was reached.Abre la cámara y pone el resultado en pendingStartOfActivityPhoto (lo que cambia el modal a previsualización). Sale temprano si ya está capturando, si hay foto pendiente o si se alcanzó el máximo.

confirmPendingStartOfActivityPhoto()

RetornoReturnRetorno void

Move a foto pendente para o fim de confirmedStartOfActivityPhotosa posição na lista é o que define a chave do payload.Moves the pending photo to the end of confirmedStartOfActivityPhotosthe position in the list decides the payload key.Mueve la foto pendiente al final de confirmedStartOfActivityPhotosla posición en la lista define la clave del payload.

retakePendingStartOfActivityPhoto({source})

RetornoReturnRetorno Future<void>

Descarta a pendente, apaga o arquivo do disco e reabre a câmera.Discards the pending one, deletes the file from disk and reopens the camera.Descarta la pendiente, borra el archivo del disco y reabre la cámara.

removeConfirmedStartOfActivityPhotoAt({index})

RetornoReturnRetorno Future<void>

Remove a foto do índice e apaga o arquivo. Como o mapeamento do payload é posicional, remover a 2ª foto promove as seguintes.Removes the photo at that index and deletes the file. Since payload mapping is positional, removing the 2nd photo shifts the following ones up.Quita la foto del índice y borra el archivo. Como el mapeo del payload es posicional, quitar la 2ª foto promueve las siguientes.

Setters — dados do varejoretail datadatos del comercio 4
MétodoMethodMétodoRetornaReturnsDevuelveO que fazWhat it doesQué hace
setVatNumber({value})voidgrava o documento; no Brasil é chamado pela tela de validação, não pelo formuláriostores the document; in Brazil it is called by the validation screen, not the formguarda el documento; en Brasil lo llama la pantalla de validación, no el formulario
setStateRegistration({value})voidInscrição Estadual; dispara a validação por estado atendido e rejeita valor só com zerosstate registration; triggers per-served-state validation and rejects an all-zeros valueinscripción estatal; dispara la validación por estado atendido y rechaza un valor de solo ceros
setOutletName({value})voidrazão sociallegal namerazón social
setCommercialName({value})voidnome fantasiatrade namenombre de fantasía

Todos passam por _updateLegalEntity, que recalcula: formato do documento (só quando o campo é editável — por isso o Brasil não revalida), formato da Inscrição Estadual, quais obrigatórios estão preenchidos e a isLegalEntityFormValid.All go through _updateLegalEntity, which recomputes: document format (only when the field is editable — which is why Brazil does not revalidate), state-registration format, which required fields are filled and isLegalEntityFormValid.Todos pasan por _updateLegalEntity, que recalcula: formato del documento (solo cuando el campo es editable — por eso Brasil no revalida), formato de la inscripción estatal, cuáles obligatorios están completos y la isLegalEntityFormValid.

Setters — endereçoaddressdirección 10
MétodoMethodMétodoRetornaReturnsDevuelveO que fazWhat it doesQué hace
selectState({geoState})voidescolhe o estado da lista e limpa a cidadepicks the state from the dropdown and clears the cityelige el estado de la lista y limpia la ciudad
selectCity({geoCity})voidescolhe a cidade da lista do estadopicks the city from the state's listelige la ciudad de la lista del estado
setStateText({value})voidestado/região como texto livre (Chile)state/region as free text (Chile)estado/región como texto libre (Chile)
setCityText({value})voidcidade/comuna como texto livre (Chile)city/comuna as free text (Chile)ciudad/comuna como texto libre (Chile)
setDistrict({value})voidbairro (máx. 35)district (max 35)barrio (máx. 35)
setAddressLine({value})voidrua (máx. 150)street (max 150)calle (máx. 150)
setNumber({value})voidnúmero (concatenado à rua no payload)number (concatenated to the street on the wire)número (concatenado a la calle en el payload)
setAddressContinue({value})voidcomplementocomplementcomplemento
setPostalCode({value})voidCEP; volta o status da busca para idle a cada dígitopostal code; resets lookup status to idle on every keystrokecódigo postal; vuelve el estado de la búsqueda a idle en cada dígito
applyAddressSearch({latitude, longitude})Future<void>geocodifica a sugestão do Places e preenche estado, cidade, bairro, rua e número; erro é só logadogeocodes the Places suggestion and fills state, city, district, street and number; an error is only loggedgeocodifica la sugerencia de Places y completa estado, ciudad, barrio, calle y número; el error solo se registra

Todos passam por _updateAddress: valida o formato do código postal por mercado, checa os obrigatórios visíveis, exige que a busca por CEP tenha resolvido (ou caído em digitação manual) e escreve isAddressFormValid. Um código postal vazio não invalida o formulário quando o campo é opcional.All go through _updateAddress: validates the postal-code format per market, checks visible required fields, requires the postal-code lookup to have resolved (or fallen to manual entry) and writes isAddressFormValid. An empty postal code does not invalidate the form when the field is optional.Todos pasan por _updateAddress: valida el formato del código postal por mercado, revisa los obligatorios visibles, exige que la búsqueda haya resuelto (o caído en entrada manual) y escribe isAddressFormValid. Un código postal vacío no invalida el formulario cuando el campo es opcional.

lookupPostalCode() CEP · Brasilpostal code · Brazilcódigo postal · Brasil

RetornoReturnRetorno Future<void>

Sai cedo se o mercado não usa preenchimento automático, se não há 8 dígitos ou se já está buscando. Em sucesso, cruza a cidade retornada com as cidades atendidas (comparação sem acento e sem caixa): casou → preenche estado, cidade, rua e bairro (truncados em 150/35) e marca resolved; não casou → erro "fora da área" e limpa cidade, rua e bairro. Em falha de rede → manualEntry (libera o avanço); em qualquer outra falha → "CEP não encontrado" e limpa o endereço. Um resultado atrasado é descartado se o CEP no campo já mudou.Early-returns if the market has no auto-fill, if there are not 8 digits or if a lookup is running. On success, it matches the returned city against the served cities (accent- and case-insensitive): match → fills state, city, street and district (truncated at 150/35) and marks resolved; no match → "out of area" error and clears city, street and district. On a network failure → manualEntry (unblocks progress); on any other failure → "postal code not found" and clears the address. A late result is discarded if the field's postal code already changed.Sale temprano si el mercado no usa autocompletado, si no hay 8 dígitos o si ya está buscando. En éxito, cruza la ciudad devuelta con las ciudades atendidas (sin acentos ni distinción de mayúsculas): coincide → completa estado, ciudad, calle y barrio (truncados en 150/35) y marca resolved; no coincide → error "fuera del área" y limpia ciudad, calle y barrio. En falla de red → manualEntry (permite avanzar); en cualquier otra falla → "código postal no encontrado" y limpia la dirección. Un resultado tardío se descarta si el código del campo ya cambió.

Setters — dados operacionaisoperational datadatos operacionales 20
MétodoMethodMétodoRetornaReturnsDevuelveO que fazWhat it doesQué hace
setCellPhone({value})voidcelular do varejo (obrigatório em todos os mercados)retail mobile (required in every market)celular del PDV (obligatorio en todos los mercados)
setPhone({value})voidtelefone fixo; vazio é aceito, preenchido tem de ser válidolandline; empty is accepted, filled must be validteléfono fijo; vacío se acepta, completo debe ser válido
setEmail({value})voide-mail do varejo (máx. 80); é o valor que a checagem de unicidade consultaretail e-mail (max 80); the value the uniqueness check queriescorreo del PDV (máx. 80); el valor que consulta la verificación de unicidad
selectOutletSubtype({outletSubtype})voidsubtipo de ponto (sfid vai no payload)outlet subtype (its sfid goes on the wire)subtipo de punto (su sfid va en el payload)
setSelectedCategoriesForSale({categories})voidseleção múltipla de categoriasmulti-selection of categoriesselección múltiple de categorías
toggleOperatingDay({dayWireValue})voidliga/desliga um dia de funcionamentotoggles an operating dayactiva/desactiva un día de funcionamiento
setOpeningTime({value})voidhorário de aberturaopening timehorario de apertura
setClosingTime({value})voidhorário de fechamentoclosing timehorario de cierre
setBreakStart({value})voidinício do intervalo; a chave só vai no payload se preenchidabreak start; the key only goes on the wire when filledinicio del intervalo; la clave solo va al payload si está completa
setBreakEnd({value})voidfim do intervalo; idembreak end; samefin del intervalo; ídem
selectSalesmanVisitDay({day})voiddia de visita do vendedorsalesman visit daydía de visita del vendedor
selectDeliveryDay({day})voiddia de entrega preferidopreferred delivery daydía de entrega preferido
selectLocalClassification({classification})voidescolhe a definição e limpa opção e texto anteriorespicks the definition and clears the previous option and textelige la definición y limpia la opción y el texto anteriores
selectLocalClassificationOption({option})voidopção quando a definição é listaoption when the definition is a picklistopción cuando la definición es lista
setLocalClassificationInputValue({value})voidvalor quando a definição é número ou textovalue when the definition is number or textvalor cuando la definición es número o texto
selectBanner({banner})voidbanner (sfid)banner (sfid)banner (sfid)
selectPropertyType({propertyType})voidtipo de propriedade; vira ownerShipType no payloadproperty type; becomes ownerShipType on the wiretipo de propiedad; pasa a ownerShipType en el payload
selectKeyAccountType({keyAccountType})voidtipo de conta clave; nunca entra na validade do formuláriokey account type; never counted for form validitytipo de cuenta clave; nunca entra en la validez del formulario
selectGiro({giro})voidgiro (sfid) → emlov1business type (sfid) → emlov1giro (sfid) → emlov1
selectChannel({channel})voidcanal (sfid) → emlov2channel (sfid) → emlov2canal (sfid) → emlov2
setB2BCustomer({value})voidinterruptor Cliente B2B — na África do Sul é o que libera o cadastro de contatosB2B customer toggle — in South Africa it is what unlocks contact registrationinterruptor Cliente B2B — en Sudáfrica es lo que habilita el registro de contactos
setDirectSales({value})voidinterruptor Venda Direta; só chega ao payload onde o mercado coletaDirect sales toggle; only reaches the wire where the market collects itinterruptor Venta Directa; solo llega al payload donde el mercado lo recoge
setNetworkParent({value})voidinterruptor "é matriz de rede" — alimenta a regra do contactPosition"is a network parent" toggle — feeds the contactPosition ruleinterruptor "es matriz de red" — alimenta la regla del contactPosition

Todos passam por _updateOperationalData: valida celular/telefone/e-mail por mercado, checa os obrigatórios visíveis, exige a classificação local completa só quando ela é visível e obrigatória, e escreve isOperationalDataFormValid.All go through _updateOperationalData: validates mobile/phone/e-mail per market, checks visible required fields, requires a complete local classification only when it is both visible and required, and writes isOperationalDataFormValid.Todos pasan por _updateOperationalData: valida celular/teléfono/correo por mercado, revisa los obligatorios visibles, exige la clasificación local completa solo cuando es visible y obligatoria, y escribe isOperationalDataFormValid.

checkAccountEmailAvailability() novo · CL/ZAnew · CL/ZAnuevo · CL/ZA

RetornoReturnRetorno Future<NewRetailEmailCheckOutcome>

Devolve available sem consultar nada quando a checagem está desligada no mercado ou o e-mail está vazio. Senão liga isCheckingEmail (que desabilita o botão), chama o UseCase com target: account e: e-mail livreavailable; em uso → guarda o motivo do backend em emailCheckDetail, marca o erro no campo e zera isOperationalDataFormValidaccountTaken; falhaoffline (se for falha de rede) ou error.Returns available without querying anything when the check is off in the market or the e-mail is empty. Otherwise it sets isCheckingEmail (which disables the button), calls the UseCase with target: account and: e-mail freeavailable; in use → stores the backend reason in emailCheckDetail, sets the field error and clears isOperationalDataFormValidaccountTaken; failureoffline (on a network failure) or error.Devuelve available sin consultar nada cuando la verificación está apagada en el mercado o el correo está vacío. Si no, activa isCheckingEmail (que deshabilita el botón), llama al UseCase con target: account y: correo libreavailable; en uso → guarda el motivo del backend en emailCheckDetail, marca el error en el campo y pone isOperationalDataFormValid en falsoaccountTaken; fallaoffline (si es falla de red) o error.

checkContactEmailAvailability() novo · CL/ZAnew · CL/ZAnuevo · CL/ZA

RetornoReturnRetorno Future<NewRetailEmailCheckOutcome>

Mesma lógica com target: contact, mais uma economia: se está editando um contato e o e-mail não mudou (comparação sem caixa), devolve available sem consultar. Em conflito, guarda contactEmailCheckDetail, marca o erro no campo e zera isContactFormValidcontactTaken.Same logic with target: contact, plus one saving: if editing a contact and the e-mail did not change (case-insensitive), it returns available without querying. On conflict it stores contactEmailCheckDetail, sets the field error and clears isContactFormValidcontactTaken.Misma lógica con target: contact, más un ahorro: si está editando un contacto y el correo no cambió (sin distinguir mayúsculas), devuelve available sin consultar. En conflicto guarda contactEmailCheckDetail, marca el error en el campo y pone isContactFormValid en falsocontactTaken.

Setters — rascunho de contatocontact draftborrador de contacto 10
MétodoMethodMétodoRetornaReturnsDevuelveO que fazWhat it doesQué hace
setContactFullName({value})voidnome completo (Brasil)full name (Brazil)nombre completo (Brasil)
setContactFirstName({value})voidprimeiro nome (CL/ZA)first name (CL/ZA)primer nombre (CL/ZA)
setContactLastName({value})voidúltimo nome (CL/ZA)last name (CL/ZA)apellido (CL/ZA)
selectContactPronoun({pronoun})voidpronome → salutationpronoun → salutationpronombre → salutation
selectContactPreferredLanguage({language})voididioma preferido → código ISO no payloadpreferred language → ISO code on the wireidioma preferido → código ISO en el payload
selectContactRole({role})voidfunção da pessoathe person's rolefunción de la persona
setContactCellPhone({value})voidcelular do contato (validado por mercado)contact mobile (validated per market)celular del contacto (validado por mercado)
setContactEmail({value})voide-mail do contato (máx. 80)contact e-mail (max 80)correo del contacto (máx. 80)
setContactDateOfBirth({value})voiddata de nascimento (o calendário já limita a 18+)date of birth (the calendar already bounds it to 18+)fecha de nacimiento (el calendario ya limita a 18+)
setContactIsMainContact({value})voidmarca como contato principal (a confirmação de troca é da UI)marks as main contact (the replace confirmation belongs to the UI)marca como contacto principal (la confirmación de reemplazo es de la UI)

Todos passam por _updateContactDraft: valida celular e e-mail, checa os obrigatórios visíveis do mercado e escreve isContactFormValid. O interruptor de principal nunca conta como campo a preencher.All go through _updateContactDraft: validates mobile and e-mail, checks the market's visible required fields and writes isContactFormValid. The main-contact toggle never counts as a field to fill.Todos pasan por _updateContactDraft: valida celular y correo, revisa los obligatorios visibles del mercado y escribe isContactFormValid. El interruptor de principal nunca cuenta como campo a completar.

saveContactDraft()

RetornoReturnRetorno void

Sai cedo se o formulário não é válido. Monta o contato (no Brasil, dividindo o nome completo em primeiro/resto), rebaixa todos os outros principais se este é o principal, substitui no índice em edição ou adiciona ao fim, e limpa o rascunho.Early-returns if the form is invalid. Assembles the contact (in Brazil, splitting the full name into first/rest), demotes every other main contact if this one is main, replaces at the editing index or appends, and clears the draft.Sale temprano si el formulario no es válido. Arma el contacto (en Brasil, dividiendo el nombre completo en primero/resto), degrada a todos los demás principales si este es el principal, reemplaza en el índice en edición o agrega al final, y limpia el borrador.

clearContactDraft() · startContactEdit({index}) · removeContactAt({index})

RetornoReturnRetorno void · void · Future<void>

clearContactDraft zera os 10 campos do rascunho, o índice em edição e a validade, e incrementa contactDraftVersion — é esse contador que força o formulário a recriar seus controladores. startContactEdit carrega a pessoa no rascunho (também incrementando a versão) e marca o índice. removeContactAt remove da lista e limpa o rascunho. Todos ignoram índice fora do alcance.clearContactDraft resets the draft's 10 fields, the editing index and validity, and increments contactDraftVersion — that counter is what forces the form to rebuild its controllers. startContactEdit loads the person into the draft (also bumping the version) and marks the index. removeContactAt removes from the list and clears the draft. All ignore out-of-range indexes.clearContactDraft resetea los 10 campos del borrador, el índice en edición y la validez, e incrementa contactDraftVersion — ese contador es lo que fuerza al formulario a recrear sus controladores. startContactEdit carga a la persona en el borrador (también incrementando la versión) y marca el índice. removeContactAt quita de la lista y limpia el borrador. Todos ignoran índices fuera de rango.

submitNewRetail() escritawriteescritura

RetornoReturnRetorno Future<void> (o resultado vive no State, lido pelo modal)(the result lives in the State, read by the modal)(el resultado vive en el State, leído por el modal)

Sequência: guarda contra envio duplo; falha imediata se não há tipo escolhido ou representante em sessão; marca submitting; lê mercado, configuração, serviço de arquivos e GPS; codifica cada foto confirmada em base64; pega o relógio e gera o customerCode; resolve a classificação local (sfid da opção ou valor digitado); monta o Input aplicando as regras de visibilidade (Inscrição Estadual, matriz de rede, texto livre de estado/cidade); chama o builder; envia; e grava success ou failure + a Failure real no State.Sequence: guards against double submission; fails immediately if there is no chosen type or no rep in session; marks submitting; reads market, configuration, file service and GPS; base64-encodes every confirmed photo; takes the clock and generates the customerCode; resolves the local classification (option sfid or typed value); assembles the Input applying the visibility rules (state registration, network parent, free-text state/city); calls the builder; submits; and writes success or failure + the real Failure into the State.Secuencia: protege contra envío doble; falla de inmediato si no hay tipo elegido o representante en sesión; marca submitting; lee mercado, configuración, servicio de archivos y GPS; codifica cada foto confirmada en base64; toma el reloj y genera el customerCode; resuelve la clasificación local (sfid de la opción o valor escrito); arma el Input aplicando las reglas de visibilidad (inscripción estatal, matriz de red, texto libre de estado/ciudad); llama al builder; envía; y escribe success o failure + la Failure real en el State.

resetSubmissionStatus() · resetFlow()

RetornoReturnRetorno void

resetSubmissionStatus volta o status para idle — o resumo chama antes de abrir o modal, para nunca abrir com um status velho. resetFlow invalida o próprio provider: State novo, vazio, e o onDispose apaga os arquivos da sessão. É a única exceção documentada do projeto ao uso de invalidateSelf, chamada ao fechar o modal de sucesso.resetSubmissionStatus returns the status to idle — the summary calls it before opening the modal, so the modal never opens with a stale status. resetFlow invalidates the provider itself: a brand-new, empty State, and onDispose deletes the session files. It is the project's one documented exception to using invalidateSelf, called when the success modal closes.resetSubmissionStatus vuelve el estado a idle — el resumen lo llama antes de abrir el modal, para nunca abrirlo con un estado viejo. resetFlow invalida el propio provider: State nuevo y vacío, y el onDispose borra los archivos de la sesión. Es la única excepción documentada del proyecto al uso de invalidateSelf, llamada al cerrar el modal de éxito.

Métodos — NewRetailDocumentValidationNotifierMethods — NewRetailDocumentValidationNotifierMétodos — NewRetailDocumentValidationNotifier

build() · updateDocument({value})

RetornoReturnRetorno NewRetailDocumentValidationState · void

O build() é síncrono e devolve o State vazio (não há fetch ao abrir a tela). updateDocument guarda o texto e limpa os três resultados (erro de campo, chave de resultado e detalhe) — qualquer tecla apaga a mensagem anterior.build() is synchronous and returns the empty State (there is no fetch when the screen opens). updateDocument stores the text and clears the three results (field error, result key and detail) — any keystroke wipes the previous message.El build() es sincrónico y devuelve el State vacío (no hay fetch al abrir la pantalla). updateDocument guarda el texto y limpia los tres resultados (error de campo, clave de resultado y detalle) — cualquier tecla borra el mensaje anterior.

validate({type})

RetornoReturnRetorno Future<bool> (true = pode seguir)(true = may proceed)(true = puede seguir)

Quatro portas em sequência, cada uma com sua mensagem: vazio → erro de campo; formato inválido (regra de CNPJ ou CPF conforme o tipo) → erro de campo; offline → resultado sem nenhuma chamada; e então o UseCase. Do retorno: bloqueado → mensagem + o motivo do backend; já cadastrado → mensagem própria; livre → limpa tudo e devolve true. Falha de rede no meio da chamada cai na mensagem de offline; outra falha, na de erro genérico. Os métodos privados _handleResult e _handleFailure concentram essa tradução.Four gates in sequence, each with its own message: empty → field error; invalid format (CNPJ or CPF rule per type) → field error; offline → a result with no call at all; and then the UseCase. From the response: blocked → message + the backend reason; already registered → its own message; free → clears everything and returns true. A network failure mid-call lands on the offline message; any other failure, on the generic error. The private _handleResult and _handleFailure concentrate that translation.Cuatro puertas en secuencia, cada una con su mensaje: vacío → error de campo; formato inválido (regla de CNPJ o CPF según el tipo) → error de campo; offline → resultado sin ninguna llamada; y luego el UseCase. De la respuesta: bloqueado → mensaje + el motivo del backend; ya registrado → mensaje propio; libre → limpia todo y devuelve true. Una falla de red a mitad de camino cae en el mensaje de offline; otra falla, en el de error genérico. Los privados _handleResult y _handleFailure concentran esa traducción.

State disponível para as PagesState available to the PagesState disponible para las Pages

NewRetailFlowState 74 campos + 26 gettersfields + 26 getterscampos + 26 getters
GrupoGroupGrupoCamposFieldsCampos
Tipo e configuraçãoType and configurationTipo y configuraciónavailableTypes · selectedType · requiresDocumentValidation · postalCodeAutoComplete · checksAccountEmailUniqueness · checksContactEmailUniqueness · requiresB2bCustomerForContacts · allowsStateRegistrationExemption · legalEntityFieldsByType · addressFieldsByType · operationalDataFieldsByType · contactFieldsByType · documentRequirementsByType · startOfActivityDocumentsByType
Documentos e fotosDocuments and photosDocumentos y fotosexpandedDocumentRequirementIds · confirmedStartOfActivityPhotos · pendingStartOfActivityPhoto · isCapturingStartOfActivityPhoto
Dados do varejoRetail dataDatos del comerciovatNumber · outletName · commercialName · stateRegistration · vatErrorKey · stateRegistrationErrorKey · isLegalEntityFormValid
EndereçoAddressDireccióngeographicalHierarchy · selectedState · selectedCity · stateText · cityText · district · addressLine · addressContinue · number · postalCode · postalCodeErrorKey · addressLookupStatus · isAddressFormValid
Listas de apoioSupporting listsListas de apoyooutletSubtypes · categoriesForSale · localClassificationDefinitions · contactRoles · languagePreferences · banners · giroOptions · canalOptions · propertyTypes · keyAccountTypes · referenceDataLastSyncAt
Dados operacionaisOperational dataDatos operacionalescellPhone · phone · email · cellPhoneErrorKey · phoneErrorKey · emailErrorKey · selectedOutletSubtype · selectedCategoriesForSale · operatingDays · openingTime · closingTime · breakStart · breakEnd · salesmanVisitDay · deliveryDay · selectedLocalClassification · localClassificationSelectedOption · localClassificationInputValue · selectedBanner · selectedPropertyType · selectedKeyAccountType · selectedGiro · selectedChannel · isB2BCustomer · isDirectSales · isNetworkParent · isOperationalDataFormValid
Checagem de e-mailE-mail checkVerificación de correoisCheckingEmail · emailCheckDetail · isCheckingContactEmail · contactEmailCheckDetail
Equipe e rascunhoTeam and draftEquipo y borradorcontacts · contactFirstName · contactLastName · contactFullName · contactPronoun · contactPreferredLanguage · contactRole · contactCellPhone · contactEmail · contactDateOfBirth · contactIsMainContact · contactCellPhoneErrorKey · contactEmailErrorKey · isContactFormValid · editingContactIndex · contactDraftVersion
EnvioSubmissionEnvíosubmissionStatus · submissionFailure

Getters de configuração: hasSelection, isSelected, documentRequirements, isDocumentRequirementExpanded, startOfActivityDocuments, legalEntityFields, legalEntityField, isLegalEntityFieldVisible, addressFields, addressField, isAddressFieldVisible, isAddressFieldFreeText, operationalDataFields, isOperationalDataFieldVisible, isOperationalDataFieldRequired, contactFields, isContactFieldVisible. Getters de fotos: maxStartOfActivityPhotos, minRequiredStartOfActivityPhotos, canCaptureMoreStartOfActivityPhotos, hasReachedMinStartOfActivityPhotos, hasPendingStartOfActivityPhoto, labelKeyForStartOfActivityPhotoAt. Getters de endereço: availableStates, availableCities, allServedCities, servedStateCodes, isStateFixed, isAddressResolved. Getters de regra: isLocalClassificationComplete, requiresStateRegistrationExemptionConfirmation, isContactRegistrationBlockedByB2b, hasContacts, hasMainContact, isEditingContact, hasOtherMainContact.Configuration getters: hasSelection, isSelected, documentRequirements, isDocumentRequirementExpanded, startOfActivityDocuments, legalEntityFields, legalEntityField, isLegalEntityFieldVisible, addressFields, addressField, isAddressFieldVisible, isAddressFieldFreeText, operationalDataFields, isOperationalDataFieldVisible, isOperationalDataFieldRequired, contactFields, isContactFieldVisible. Photo getters: maxStartOfActivityPhotos, minRequiredStartOfActivityPhotos, canCaptureMoreStartOfActivityPhotos, hasReachedMinStartOfActivityPhotos, hasPendingStartOfActivityPhoto, labelKeyForStartOfActivityPhotoAt. Address getters: availableStates, availableCities, allServedCities, servedStateCodes, isStateFixed, isAddressResolved. Rule getters: isLocalClassificationComplete, requiresStateRegistrationExemptionConfirmation, isContactRegistrationBlockedByB2b, hasContacts, hasMainContact, isEditingContact, hasOtherMainContact.Getters de configuración: hasSelection, isSelected, documentRequirements, isDocumentRequirementExpanded, startOfActivityDocuments, legalEntityFields, legalEntityField, isLegalEntityFieldVisible, addressFields, addressField, isAddressFieldVisible, isAddressFieldFreeText, operationalDataFields, isOperationalDataFieldVisible, isOperationalDataFieldRequired, contactFields, isContactFieldVisible. Getters de fotos: maxStartOfActivityPhotos, minRequiredStartOfActivityPhotos, canCaptureMoreStartOfActivityPhotos, hasReachedMinStartOfActivityPhotos, hasPendingStartOfActivityPhoto, labelKeyForStartOfActivityPhotoAt. Getters de dirección: availableStates, availableCities, allServedCities, servedStateCodes, isStateFixed, isAddressResolved. Getters de regla: isLocalClassificationComplete, requiresStateRegistrationExemptionConfirmation, isContactRegistrationBlockedByB2b, hasContacts, hasMainContact, isEditingContact, hasOtherMainContact.

NewRetailDocumentValidationState 5 camposfieldscampos
campofieldcampotipotypetipodefault
documentString""
isValidatingboolfalse
inputErrorTranslationConstants?null
resultKeyTranslationConstants?null
resultDetailString""

O inputError tem precedência sobre o resultKey na tela, e o resultDetail é concatenado ao texto traduzido. O documento validado é passado ao fluxo principal por setVatNumber — este State não é lido por nenhuma outra tela.inputError takes precedence over resultKey on screen, and resultDetail is appended to the translated text. The validated document is handed to the main flow via setVatNumber — this State is not read by any other screen.El inputError tiene precedencia sobre el resultKey en pantalla, y el resultDetail se concatena al texto traducido. El documento validado se pasa al flujo principal vía setVatNumber — este State no lo lee ninguna otra pantalla.

13

Pages e widgetsPages & widgetsPages y widgets

As 9 pages são ConsumerWidget (a de validação de documento é ConsumerStatefulWidget, porque tem controlador próprio) e todas envolvem o corpo em AppPageShell(displayBackButton: true). Oito delas observam o newRetailFlowProvider com o tripé when(data/loading/error): carregando mostra CustomLoadingIndicator, erro mostra o texto da falha. Nenhuma page recebe dado por rota — o único parâmetro em todo o fluxo é isEditing. Os modais aparecem dentro da árvore, sob o widget que os abre.The 9 pages are ConsumerWidgets (the document-validation one is a ConsumerStatefulWidget, since it owns a controller) and all wrap their body in AppPageShell(displayBackButton: true). Eight of them watch newRetailFlowProvider with the when(data/loading/error) triad: loading shows CustomLoadingIndicator, error shows the failure text. No page receives data through the route — the only parameter in the whole flow is isEditing. Modals appear inside the tree, under the widget that opens them.Las 9 pages son ConsumerWidget (la de validación de documento es ConsumerStatefulWidget, porque tiene su propio controlador) y todas envuelven el cuerpo en AppPageShell(displayBackButton: true). Ocho observan el newRetailFlowProvider con el trío when(data/loading/error): cargando muestra CustomLoadingIndicator, error muestra el texto de la falla. Ninguna page recibe dato por ruta — el único parámetro de todo el flujo es isEditing. Los modales aparecen dentro del árbol, bajo el widget que los abre.

  • NewRetailTypeSelectionPage /new-retail/type-selection · entrada do fluxoflow entryentrada del flujo
    • CustomPullToRefresh → refresh()
      • NewRetailHeaderWidget DataLoadInfo + título (nas 9 telas)title (on all 9 screens)título (en las 9 pantallas)
      • NewRetailWelcomeWidget boas-vindas + instruçãowelcome + instructionbienvenida + instrucción
      • NewRetailTypeGridWidget MenuActionGrid · um item por tipo do mercadoone item per market typeun ítem por tipo del mercado
        • → selectType() sem validação de documento → Start; com validação, offline → aviso e para; senão → tela de documentono document validation → Start; with validation, offline → notice and stop; else → document screensin validación de documento → Start; con validación, offline → aviso y detiene; si no → pantalla de documento
  • NewRetailDocumentValidationPage /new-retail/document-validation · só BrasilBrazil onlysolo Brasil
    • NewRetailHeaderWidget
    • CustomText subtítulo + rótulo do documento (CPF ou CNPJ interpolado)subtitle + document label (CPF or CNPJ interpolated)subtítulo + etiqueta del documento (CPF o CNPJ interpolado)
    • CustomInput máscara por tipo e mercado → updateDocument()mask per type and market → updateDocument()máscara por tipo y mercado → updateDocument()
    • CustomText mensagem do resultado (sempre em vermelho; sucesso apenas navega)result message (always red; success just navigates)mensaje del resultado (siempre en rojo; el éxito solo navega)
    • CustomButton → validate() · em sucesso: setVatNumber() + Starton success: setVatNumber() + Starten éxito: setVatNumber() + Start
  • NewRetailStartPage /new-retail/start · isEditing
    • NewRetailHeaderWidget
    • NewRetailStartIntroWidget título + descrição + "os documentos necessários são:"title + description + "the required documents are:"título + descripción + "los documentos requeridos son:"
    • NewRetailDocumentRequirementsListWidget
      • NewRetailDocumentRequirementCardWidget acordeão animado (350 ms) · um por perfil · toque → toggleDocumentRequirementExpansion()animated accordion (350 ms) · one per profile · tap → toggleDocumentRequirementExpansion()acordeón animado (350 ms) · uno por perfil · toque → toggleDocumentRequirementExpansion()
    • NewRetailActivitySectionWidget título "Início da Atividade""Start of Activity" titletítulo "Inicio de Actividad"
    • NewRetailCapturedDocumentsListWidget
      • NewRetailCapturedDocumentRowWidget CustomFileThumbnail + rótulo do documento + removerdocument label + removeetiqueta del documento + quitar
    • NewRetailStartActionsWidget abaixo do mínimo: só a câmera; a partir do mínimo: câmera redonda + Continuar; no máximo: só Continuarbelow the minimum: camera only; from the minimum: round camera + Next; at the maximum: Next onlybajo el mínimo: solo la cámara; desde el mínimo: cámara redonda + Continuar; en el máximo: solo Continuar
      • NewRetailTakePhotoButtonWidget botão cheio de "Tirar foto"full-width "Take Photo" buttonbotón completo de "Tomar foto"
      • NewRetailTakePhotoModalContent modal · duas interfaces: pré-visualização (confirmar / refazer) ou lista + "pronto para {documento}?" — devolve nada, muta o Statetwo interfaces: preview (confirm / retake) or list + "ready for {document}?" — returns nothing, mutates the Statedos interfaces: previsualización (confirmar / rehacer) o lista + "¿listo para {documento}?" — no devuelve nada, muta el State
  • NewRetailLegalEntityPage /new-retail/legal-entity · isEditing
    • NewRetailHeaderWidget
    • NewRetailLegalEntityFormWidget itera a lista de campos do tipo, na ordem do EMCiterates the type's field list, in EMC orderitera la lista de campos del tipo, en el orden del EMC
      • CustomInput document · rótulo dinâmico (CNPJ/CPF/VAT), máscara por mercado, somente leitura quando não editáveldynamic label (CNPJ/CPF/VAT), per-market mask, read-only when not editableetiqueta dinámica (CNPJ/CPF/VAT), máscara por mercado, solo lectura cuando no es editable
      • CustomInput state_registration · só dígitos · validação por estado atendidodigits only · validated per served statesolo dígitos · validación por estado atendido
      • CustomInput legal_name · trade_name
    • NewRetailWizardActionsWidget Voltar / Continuar — em edição, um único "Salvar alterações"Come back / Next — in editing, a single "Save changes"Volver / Continuar — en edición, un único "Guardar cambios"
      • NewRetailStateRegistrationExemptModalContent modal · só quando o mercado permite isenção e o campo está vazio · devolve bool? — só "Sim" avançaonly when the market allows exemption and the field is empty · returns bool? — only "Yes" proceedssolo cuando el mercado permite exención y el campo está vacío · devuelve bool? — solo "Sí" avanza
  • NewRetailAddressPage /new-retail/address · isEditing
    • NewRetailHeaderWidget
    • NewRetailAddressFormWidget 11 controladores + foco próprio; ordem e tipo dos campos vêm do EMC11 controllers + its own focus node; field order and type come from the EMC11 controladores + foco propio; orden y tipo de los campos vienen del EMC
      • GooglePlaceAutoCompleteTextField address_search · sugestões → applyAddressSearch()suggestions → applyAddressSearch()sugerencias → applyAddressSearch()
      • CustomInput postal_code · 8 dígitos disparam a busca de CEP8 digits trigger the postal-code lookup8 dígitos disparan la búsqueda
      • CustomInput street (150) · number · complement · neighborhood (35)
      • CustomDropdown / CustomInput city · três variantes: texto livre, somente leitura após o CEP, ou lista dependente do estadothree variants: free text, read-only after the postal code, or a dropdown depending on the statetres variantes: texto libre, solo lectura tras el código postal, o lista dependiente del estado
      • CustomDropdown / CustomInput state · texto livre, fixo (mercado com um estado só) ou listafree text, fixed (market with a single state) or dropdowntexto libre, fijo (mercado con un solo estado) o lista
    • NewRetailWizardActionsWidget habilita só com o endereço válido (e o CEP resolvido, no Brasil)enabled only with a valid address (and a resolved postal code, in Brazil)se habilita solo con la dirección válida (y el código resuelto, en Brasil)
  • NewRetailOperationalDataPage /new-retail/operational-data · isEditing
    • NewRetailHeaderWidget
    • NewRetailOperationalDataFormWidget até 18 campos, na ordem do EMCup to 18 fields, in EMC orderhasta 18 campos, en el orden del EMC
      • CustomInput cell_phone · phone · email (80) · erro em linha, inclusive "Altere este e-mail."inline error, including "Change this e-mail address."error en línea, incluyendo "Modifica este correo electrónico."
      • CustomDropdown.single / .multi outlet_subtype · categories_for_sale · salesman_visit_day · delivery_day · banner · property_type · key_account_type · giro · channel
      • CustomOperatingHoursEditor operating_days · dias + abertura/fechamentodays + opening/closingdías + apertura/cierre
      • _BreakTimeColumn business_interval · cartão com início e término do intervalocard with break start and endtarjeta con inicio y fin del intervalo
        • CustomTimePickerModalContent modal · devolve DateTime? → setBreakStart / setBreakEndreturns DateTime? → setBreakStart / setBreakEnddevuelve DateTime? → setBreakStart / setBreakEnd
      • _LocalClassificationDependentField local_classification · recriado a cada troca de definiçãorebuilt on every definition changerecreado en cada cambio de definición
        • CustomDropdown / CustomInput lista de opções, campo numérico ou de texto, conforme o tipo da definiçãooptions dropdown, numeric or text field, per the definition typelista de opciones, campo numérico o de texto, según el tipo de la definición
      • _YesNoToggleRow b2b_customer · direct_sales · network_parent
    • NewRetailWizardActionsWidget desabilitado enquanto a checagem de e-mail está em cursodisabled while the e-mail check is runningdeshabilitado mientras corre la verificación de correo
      • showNewRetailEmailCheckAlert modal · checkAccountEmailAvailability() falhou → mensagem traduzida + motivo do backend · não devolve nada e a navegação paracheckAccountEmailAvailability() failed → translated message + backend reason · returns nothing and navigation stopscheckAccountEmailAvailability() falló → mensaje traducido + motivo del backend · no devuelve nada y la navegación se detiene
  • NewRetailRetailTeamPage /new-retail/retail-team · isEditing
    • NewRetailHeaderWidget + NewRetailRetailTeamTitleWidget
    • NewRetailContactsListWidget
      • NewRetailContactCardWidget celular / nome / função · toque → startContactEdit() + tela de cadastromobile / name / role · tap → startContactEdit() + registration screencelular / nombre / función · toque → startContactEdit() + pantalla de registro
    • NewRetailRetailTeamDescriptionWidget
    • MenuActionCard "Adicionar contato" → clearContactDraft() + tela de cadastro"Add contact" → clearContactDraft() + registration screen"Agregar contacto" → clearContactDraft() + pantalla de registro
    • NewRetailWizardActionsWidget habilita com ≥ 1 contatoenabled with ≥ 1 contactse habilita con ≥ 1 contacto
      • ConectaModal.showAlert modal · sem contato principal → "marque pelo menos um contato como principal" e bloqueia (todos os mercados)no main contact → "mark at least one contact as the main contact" and blocks (all markets)sin contacto principal → "marca al menos un contacto como principal" y bloquea (todos los mercados)
  • NewRetailContactRegistrationPage /new-retail/contact-registration · modo edição inferido do Stateedit mode inferred from the Statemodo edición inferido del State
    • NewRetailHeaderWidget
    • NewRetailContactFormWidget re-chaveado por contactDraftVersion; pares lado a lado (pronome+idioma, função+principal)re-keyed by contactDraftVersion; side-by-side pairs (pronoun+language, role+main)re-clavado por contactDraftVersion; pares lado a lado (pronombre+idioma, función+principal)
      • CustomDropdown pronoun · language_preference · role
      • CustomInput full_name ouoro first_name + last_name · cell_phone · email (80)
      • CustomSwitch main_contact
        • ConectaModal.showConfirmation modal · já existe outro principal → devolve bool?; só "Sim" aplicaanother main already exists → returns bool?; only "Yes" appliesya existe otro principal → devuelve bool?; solo "Sí" aplica
      • CustomInput date_of_birth · somente leitura + ícone de calendárioread-only + calendar iconsolo lectura + icono de calendario
        • CustomCalendarModalContent modal · data máxima = hoje menos 18 anos → devolve DateTime?last date = today minus 18 years → returns DateTime?fecha máxima = hoy menos 18 años → devuelve DateTime?
    • NewRetailRemoveContactButtonWidget só em edição · botão vermelhoonly while editing · red buttonsolo en edición · botón rojo
      • ConectaModal.showConfirmation modal · confirma remoção → removeContactAt() + voltaconfirms removal → removeContactAt() + backconfirma la eliminación → removeContactAt() + volver
    • NewRetailWizardActionsWidget "Registrar" ou "Salvar"; desabilitado durante a checagem de e-mail"Register" or "Save"; disabled during the e-mail check"Registrar" o "Guardar"; deshabilitado durante la verificación de correo
      • ConectaModal.showAlert modal · porta de Cliente B2B (África do Sul) → bloqueia antes de qualquer checagemB2B customer gate (South Africa) → blocks before any checkpuerta de Cliente B2B (Sudáfrica) → bloquea antes de cualquier verificación
      • showNewRetailEmailCheckAlert modal · checkContactEmailAvailability() falhou → bloqueia o registrocheckContactEmailAvailability() failed → blocks the registrationcheckContactEmailAvailability() falló → bloquea el registro
      • ConectaModal.showConfirmation modal · "deseja adicionar outro contato?" → true salva e limpa; false salva e volta; dispensar não salva"do you want to add another contact?" → true saves and clears; false saves and goes back; dismissing saves nothing"¿deseas agregar otro contacto?" → true guarda y limpia; false guarda y vuelve; descartar no guarda
  • NewRetailSummaryPage /new-retail/summary
    • NewRetailHeaderWidget + título do resumosummary titletítulo del resumen
    • _SummarySection 5 cartões (varejo, endereço, operacional, equipe, fotos), cada um com "Editar" → a mesma page com isEditing: true; cartão sem campo visível não é renderizado5 cards (retail, address, operational, team, photos), each with "Edit" → the same page with isEditing: true; a card with no visible field is not rendered5 tarjetas (comercio, dirección, operacional, equipo, fotos), cada una con "Editar" → la misma page con isEditing: true; una tarjeta sin campo visible no se renderiza
      • LabelValueField uma linha por campo visível; vazio vira "—"one row per visible field; empty becomes "—"una fila por campo visible; vacío es "—"
      • CustomFileThumbnail faixa horizontal das fotos, só visualizaçãohorizontal photo strip, view onlyfranja horizontal de fotos, solo visualización
    • _BottomBar barra fixa: Voltar + Finalizar (habilita só com os 3 formulários válidos, contato principal e mínimo de fotos)fixed bar: Come back + Finish (enabled only with the 3 valid forms, a main contact and the photo minimum)barra fija: Volver + Finalizar (se habilita solo con los 3 formularios válidos, contacto principal y el mínimo de fotos)
      • NewRetailSubmitConfirmationModalContent modal · não dispensável · CustomSubmissionModalContent dirigido pelo status: confirmar → submitNewRetail(); ao fechar no sucesso → volta à primeira tela + resetFlow()non-dismissible · CustomSubmissionModalContent driven by the status: confirm → submitNewRetail(); closing on success → back to the first screen + resetFlow()no descartable · CustomSubmissionModalContent dirigido por el estado: confirmar → submitNewRetail(); al cerrar en éxito → vuelve a la primera pantalla + resetFlow()

Todas as rotas são empurradas por métodos do AppRouter (goToNewRetail e os oito goToNewRetail…); o fechamento do modal de sucesso usa backToNewRetailTypeSelection, que descarta a pilha até a primeira tela — é o que impede reenviar o mesmo cadastro.Every route is pushed by AppRouter methods (goToNewRetail and the eight goToNewRetail…); closing the success modal uses backToNewRetailTypeSelection, which drops the stack down to the first screen — that is what prevents resubmitting the same registration.Todas las rutas se empujan con métodos del AppRouter (goToNewRetail y los ocho goToNewRetail…); al cerrar el modal de éxito se usa backToNewRetailTypeSelection, que descarta la pila hasta la primera pantalla — es lo que impide reenviar el mismo registro.

Notas por mercadoMarket notesNotas por mercado

Este é o fluxo mais dirigido por configuração do app: não existe um único if de mercado no código de new_retail. Tipos, campos, obrigatoriedade, edição, texto livre, documentos, fotos e as quatro flags de comportamento vêm todos do newRetailConfig da End Market Configuration. O acesso ao fluxo é dirigido por outra chave do EMC — o atalho new_account no módulo de ações do representante, na Home:This is the app's most configuration-driven flow: there is not a single market if in the new_retail code. Types, fields, requiredness, editability, free text, documents, photos and the four behavior flags all come from newRetailConfig in the End Market Configuration. Access to the flow is driven by another EMC key — the new_account tile in the Home rep-actions module:Este es el flujo más dirigido por configuración de la app: no existe un solo if de mercado en el código de new_retail. Tipos, campos, obligatoriedad, edición, texto libre, documentos, fotos y las cuatro flags de comportamiento vienen todos del newRetailConfig de la End Market Configuration. El acceso al flujo lo dirige otra clave del EMC — el atajo new_account en el módulo de acciones del representante, en el Home:

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

Comportamento do fluxo por mercadoFlow behavior per marketComportamiento del flujo por mercado

Chave do newRetailConfignewRetailConfig keyClave del newRetailConfigBRCLZAARPYPE
retailTypesindividual · businessgenericgeneric
requiresDocumentValidationxfalsefalse
checksAccountEmailUniquenessfalsexx
checksContactEmailUniquenessfalsexx
requiresB2bCustomerForContactsfalsefalsex
allowsStateRegistrationExemptionxfalsefalse
postalCodeAutoCompletexfalsefalse
documentRequirementsByType1 perfil por tipo1 profile per type1 perfil por tipo1 perfil1 profile1 perfil4 perfis4 profiles4 perfiles
startOfActivityDocumentsByType3 (física) / 4 (jurídica), todas obrigatórias3 (individual) / 4 (business), all mandatory3 (natural) / 4 (jurídica), todas obligatorias1, obrigatória1, mandatory1, obligatoria3, só a 1ª obrigatória3, only the 1st mandatory3, solo la 1ª obligatoria
legalEntityFieldsByType3 (física) / 4 (jurídica)3 (individual) / 4 (business)3 (natural) / 4 (jurídica)33
addressFieldsByType786
operationalDataFieldsByType91711
contactFieldsByType799
wireConfig20 chaves20 keys20 claves20 chaves20 keys20 claves20 chaves20 keys20 claves3 chaves3 keys3 claves3 chaves3 keys3 claves3 chaves3 keys3 claves
homeConfigrep_actionsnew_accountxxx
menuConfignew_account

Configuração de wire por mercadoWire configuration per marketConfiguración de wire por mercado

Uma linha por chave. Chave ausente cai no padrão do mapper (indicado entre parênteses no rodapé de cada célula relevante).One row per key. A missing key falls back to the mapper default.Una fila por clave. Una clave ausente cae en el valor por defecto del mapper.

ChaveKeyClaveBRCLZAARPYPE
accountRecordTypeId0121t000000HzMFAA00120Y000000BOrCQAW0120Y000000BOrCQAW
contactRecordTypeId""0120Y000000BOrEQAW0120Y000000BOrEQAW
locationHierarchyIda0D1t00000276uAEAQa0B1n00000Rla8EEARa0B4J000009ZhRKUA0
paymentMethodZG;Z9;ZXZE;ZB;ZC;ZI;Z9ZH;ZM
defaultPaymentMethodZGZEZH
currencyIsoCodeBRLCLPZARARSPYGPEN
languagePTESENESESES
mailingCountrybrazilCHILESOUTH AFRICAargentinaparaguayperu
contactPreferredLanguagePortugueseSpanishEnglish
sendsVatRegistrationNofalsefalsex
sendsTaxIdxxfalse
sendsDocumentDataxxfalse
collectsDirectSalesfalsefalsex
userQuotas"50""50""5"
ownerShipType""""Independent
totalSellInValPerAnnum"""1""1"
isTaxRequired"false""true""false"
contactB2bStatusInactiveActiveInactive
restrictedOrderEdit"true""false""false"
isPartialDelivery"true""false""true"

Campos por mercado e tipoFields per market and typeCampos por mercado y tipo

Uma linha por campo, em todas as tabelas. O ponto marca a presença na configuração; o código ao lado diz como o campo se comporta: req visível e obrigatório · opt visível e opcional · free texto livre (envia nome, não sfid) · ro somente leitura · off presente mas invisível. AR, PY e PE não têm nenhuma dessas listas — por isso não têm coluna: o fluxo abriria vazio.One row per field, in every table. The dot marks presence in the configuration; the code next to it says how the field behaves: req visible and required · opt visible and optional · free free text (sends the name, not the sfid) · ro read-only · off present but invisible. AR, PY and PE have none of these lists — hence no column: the flow would open empty.Una fila por campo, en todas las tablas. El punto marca la presencia en la configuración; el código al lado dice cómo se comporta el campo: req visible y obligatorio · opt visible y opcional · free texto libre (envía el nombre, no el sfid) · ro solo lectura · off presente pero invisible. AR, PY y PE no tienen ninguna de estas listas — de ahí que no tengan columna: el flujo abriría vacío.

Dados do varejoRetail dataDatos del comercio 4 camposfieldscampos
CampoFieldCampoBR · individualBR · businessCL · genericZA · generic
documentx req rox req rox reqx req
state_registrationx opt
legal_namex reqx reqx reqx req
trade_namex reqx reqx reqx req

Só o Brasil marca o documento como não editável — é o valor que veio validado da tela anterior, exibido formatado. Chile valida RUT (módulo 11) e África do Sul valida VAT (10 dígitos começando em 4).Only Brazil marks the document as non-editable — it is the value validated on the previous screen, shown formatted. Chile validates RUT (mod 11) and South Africa validates VAT (10 digits starting with 4).Solo Brasil marca el documento como no editable — es el valor validado en la pantalla anterior, mostrado formateado. Chile valida RUT (módulo 11) y Sudáfrica valida VAT (10 dígitos que empiezan con 4).

EndereçoAddressDirección 8 camposfieldscampos
CampoFieldCampoBR · individualBR · businessCL · genericZA · generic
address_searchx opt
postal_codex reqx reqx optx req
streetx reqx reqx reqx req
numberx reqx reqx opt
complementx optx optx optx opt
neighborhoodx reqx reqx optx opt
cityx reqx reqx req freex req
statex reqx reqx req freex req

A ordem também é de configuração: Brasil postal_code, street, number, complement, neighborhood, city, state; Chile address_search, street, number, neighborhood, city, state, complement, postal_code; África do Sul state, city, neighborhood, street, complement, postal_code. Nota de ambiente: no arquivo de UAT o postal_code do Chile é obrigatório; em produção e pré-produção é opcional.The order is configuration too: Brazil postal_code, street, number, complement, neighborhood, city, state; Chile address_search, street, number, neighborhood, city, state, complement, postal_code; South Africa state, city, neighborhood, street, complement, postal_code. Environment note: in the UAT file Chile's postal_code is required; in production and pre-production it is optional.El orden también es de configuración: Brasil postal_code, street, number, complement, neighborhood, city, state; Chile address_search, street, number, neighborhood, city, state, complement, postal_code; Sudáfrica state, city, neighborhood, street, complement, postal_code. Nota de ambiente: en el archivo de UAT el postal_code de Chile es obligatorio; en producción y preproducción es opcional.

Dados operacionaisOperational dataDatos operacionales 18 camposfieldscampos
CampoFieldCampoBR · individualBR · businessCL · genericZA · generic
cell_phonex reqx reqx reqx req
phonex optx optx optx opt
emailx reqx reqx reqx req
outlet_subtypex reqx reqx reqx req
categories_for_salex reqx reqx optx opt
operating_daysx reqx reqx optx opt
business_intervalx opt
salesman_visit_dayx optx optx optx opt
delivery_dayx reqx reqx optx opt
local_classificationfalse offx req
bannerx req
property_typex req
key_account_typex opt
girox req
channelx req
b2b_customerx optx opt
direct_salesfalse offx opt
network_parentx optx opt

Duas leituras importantes: a classificação local só é exigida na África do Sul (no Chile a chave existe mas está invisível, e no Brasil não existe); e o interruptor de matriz de rede só existe no Brasil — é o que faz a regra do contactPosition ser, na prática, brasileira.Two important readings: local classification is only enforced in South Africa (in Chile the key exists but is invisible, and in Brazil it does not exist); and the network-parent toggle only exists in Brazil — which makes the contactPosition rule, in practice, a Brazilian one.Dos lecturas importantes: la clasificación local solo se exige en Sudáfrica (en Chile la clave existe pero está invisible, y en Brasil no existe); y el interruptor de matriz de red solo existe en Brasil — lo que hace que la regla del contactPosition sea, en la práctica, brasileña.

ContatoContactContacto 10 camposfieldscampos
CampoFieldCampoBR · individualBR · businessCL · genericZA · generic
pronounx reqx reqx reqx req
language_preferencex reqx req
full_namex reqx req
first_namex reqx req
last_namex reqx req
rolex reqx reqx reqx req
main_contactx optx optx optx opt
cell_phonex reqx reqx reqx req
emailx reqx reqx reqx req
date_of_birthx reqx reqx optx opt

Mesmo marcado como opcional na configuração, o contato principal é obrigatório por regra do fluxo: sem nenhum, a tela de equipe não avança. E o main_contact nunca conta como campo a preencher na validade do formulário.Even flagged optional in configuration, a main contact is required by flow rule: with none, the team screen does not advance. And main_contact never counts as a field to fill for form validity.Aunque esté marcado como opcional en la configuración, el contacto principal es obligatorio por regla del flujo: sin ninguno, la pantalla de equipo no avanza. Y main_contact nunca cuenta como campo a completar para la validez del formulario.

BR

BrasilBrazilBrasil Único mercado com dois tipos (pessoa física e jurídica) e com a tela de validação de documento (CPF 11 dígitos / CNPJ 14) — que exige internet para começar. Único com Inscrição Estadual (opcional, com modal de isenção e validação por estado atendido) e com o preenchimento por CEP (que bloqueia o avanço até resolver e recusa cidade fora da área). Único com matriz de rede — e é essa combinação que produz o contactPosition: "Manager". Contato usa nome completo e exige data de nascimento. Envia taxId e DocumentData; não faz checagem de e-mail. The only market with two types (individual and business) and with the document-validation screen (CPF 11 digits / CNPJ 14) — which requires internet to start. The only one with a state registration (optional, with an exemption modal and per-served-state validation) and with postal-code auto-fill (which blocks progress until it resolves and refuses a city outside the area). The only one with a network parent — and that combination is what produces contactPosition: "Manager". Contacts use a full name and require a date of birth. Sends taxId and DocumentData; does not run the e-mail check. Único mercado con dos tipos (persona natural y jurídica) y con la pantalla de validación de documento (CPF 11 dígitos / CNPJ 14) — que exige internet para empezar. Único con inscripción estatal (opcional, con modal de exención y validación por estado atendido) y con autocompletado por código postal (que bloquea el avance hasta resolver y rechaza ciudad fuera del área). Único con matriz de red — y esa combinación es la que produce el contactPosition: "Manager". El contacto usa nombre completo y exige fecha de nacimiento. Envía taxId y DocumentData; no hace la verificación de correo.

CL

ChileChileChile Tipo único, sem validação de documento — o RUT é validado no próprio formulário (módulo 11). É o único mercado com busca de endereço por mapa e com região e comuna em texto livre (o payload leva o nome, não o sfid), e o único com os cinco campos comerciais: Banner, Tipo de Propriedade, Giro (emlov1), Canal (emlov2) e Cuenta Clave — os quatro primeiros obrigatórios. Também o único com intervalo de funcionamento. Classificação local e Venda Direta estão presentes mas desligados. Faz as duas checagens de e-mail. Contato: primeiro e último nome, idioma preferido obrigatório, data de nascimento opcional. Single type, no document validation — the RUT is validated in the form itself (mod 11). It is the only market with map-based address search and with free-text region and comuna (the wire carries the name, not the sfid), and the only one with the five commercial fields: Banner, Property type, Business type (emlov1), Channel (emlov2) and Key account type — the first four required. Also the only one with a business break. Local classification and Direct sales are present but off. Runs both e-mail checks. Contact: first and last name, required preferred language, optional date of birth. Tipo único, sin validación de documento — el RUT se valida en el propio formulario (módulo 11). Es el único mercado con búsqueda de dirección por mapa y con región y comuna en texto libre (el payload lleva el nombre, no el sfid), y el único con los cinco campos comerciales: Banner, Tipo de Propiedad, Giro (emlov1), Canal (emlov2) y Cuenta Clave — los primeros cuatro obligatorios. También el único con intervalo de funcionamiento. Clasificación local y Venta Directa están presentes pero apagados. Hace las dos verificaciones de correo. Contacto: primer nombre y apellido, idioma preferido obligatorio, fecha de nacimiento opcional.

ZA

África do SulSouth AfricaSudáfrica Tipo único, mas com quatro perfis de documentos exigidos (residente, não residente, sociedade, empresa) — e o único perfil com subtítulo em todo o EMC. Fotos: 3 espaços, só o primeiro obrigatório. É o único mercado com a porta de Cliente B2B antes de cadastrar contatos e o único onde a classificação local é obrigatória. No wire, o único que envia VATRegistrationNo em vez de taxId, o único que não envia DocumentData (as fotos são capturadas mas não transmitidas) e o único que respeita a resposta de Venda Direta. Faz as duas checagens de e-mail. Cota de usuários 5, contra 50 nos outros. Single type, but with four required-document profiles (resident, non-resident, partnership, company) — and the only profile with a subtitle in the whole EMC. Photos: 3 slots, only the first mandatory. It is the only market with the B2B customer gate before registering contacts and the only one where local classification is required. On the wire, the only one sending VATRegistrationNo instead of taxId, the only one that does not send DocumentData (photos are captured but not transmitted) and the only one honoring the Direct sales answer. Runs both e-mail checks. User quota 5, against 50 elsewhere. Tipo único, pero con cuatro perfiles de documentos exigidos (residente, no residente, sociedad, empresa) — y el único perfil con subtítulo en todo el EMC. Fotos: 3 espacios, solo el primero obligatorio. Es el único mercado con la puerta de Cliente B2B antes de registrar contactos y el único donde la clasificación local es obligatoria. En el wire, el único que envía VATRegistrationNo en vez de taxId, el único que no envía DocumentData (las fotos se capturan pero no se transmiten) y el único que respeta la respuesta de Venta Directa. Hace las dos verificaciones de correo. Cuota de usuarios 5, contra 50 en los demás.

AR · PY · PE

  • Não têm o atalho new_account na Home — o fluxo é inalcançável.They have no new_account tile on Home — the flow is unreachable.No tienen el atajo new_account en el Home — el flujo es inalcanzable.
  • O newRetailConfig existe, mas só com 3 chaves de wireConfig (moeda, idioma, país de correspondência) — sem tipos e sem nenhuma lista de campos.newRetailConfig exists, but with only 3 wireConfig keys (currency, language, mailing country) — no types and no field lists at all.El newRetailConfig existe, pero solo con 3 claves de wireConfig (moneda, idioma, país de correspondencia) — sin tipos y sin ninguna lista de campos.
  • Se o atalho fosse habilitado hoje, a primeira tela abriria sem nenhum tipo para escolher, e nada mais aconteceria.If the tile were enabled today, the first screen would open with no type to pick, and nothing else would happen.Si el atajo se habilitara hoy, la primera pantalla abriría sin ningún tipo para elegir, y nada más ocurriría.
  • A transação retailNew está habilitada apenas para BR, CL e ZA.The retailNew transaction is enabled for BR, CL and ZA only.La transacción retailNew está habilitada solo para BR, CL y ZA.
  • Os mocks de dados de apoio desses mercados são stubs e não têm bloco de checagem de e-mail — a checagem sempre responderia "disponível".Their reference-data mocks are stubs and have no e-mail-check block — the check would always answer "available".Sus mocks de datos de apoyo son stubs y no tienen bloque de verificación de correo — la verificación siempre responderría "disponible".

Pendências / roadmapPendencies / roadmapPendientes / roadmap

  • RPC emailCheck não implementado no backend. A stack do app está completa; a chamada real responde UNIMPLEMENTED e bloqueia o representante nos mercados com a checagem ligada. Confirmações pendentes: necessidade do resourceSfid, busca case-insensitive, e se registros inativos contam como "em uso".The emailCheck RPC is not implemented in the backend. The app stack is complete; the real call answers UNIMPLEMENTED and blocks the rep in markets with the check on. Pending confirmations: whether resourceSfid is needed, case-insensitive search, and whether inactive records count as "in use".El RPC emailCheck no está implementado en el backend. La stack de la app está completa; la llamada real responde UNIMPLEMENTED y bloquea al representante en los mercados con la verificación activa. Confirmaciones pendientes: necesidad del resourceSfid, búsqueda case-insensitive, y si los registros inactivos cuentan como "en uso".
  • Sem doc de transação. A transação AccountContactUploadAPI ainda não tem documento próprio no setor de transações — o mapeamento completo do payload vive, por ora, na seção 07 deste documento.No transaction doc yet. The AccountContactUploadAPI transaction has no dedicated document in the transactions sector — the full payload mapping lives, for now, in section 07 of this document.Sin doc de transacción. La transacción AccountContactUploadAPI aún no tiene documento propio en el sector de transacciones — el mapeo completo del payload vive, por ahora, en la sección 07 de este documento.
  • Mocks incompletos. O bloco de validação de documento existe só no mock "real" do Brasil — no mock padrão todo documento passa. O bloco de checagem de e-mail existe no Brasil, onde as duas flags estão desligadas (dado morto). O arquivo anotado de configuração está desatualizado: descreve o esquema antigo, sem nenhuma das chaves novas.Incomplete mocks. The document-validation block exists only in Brazil's "real" mock — in the standard mock every document passes. The e-mail-check block exists for Brazil, where both flags are off (dead data). The annotated configuration file is stale: it describes the old schema, without any of the new keys.Mocks incompletos. El bloque de validación de documento existe solo en el mock "real" de Brasil — en el mock estándar todo documento pasa. El bloque de verificación de correo existe en Brasil, donde ambas flags están apagadas (dato muerto). El archivo anotado de configuración está desactualizado: describe el esquema antiguo, sin ninguna de las claves nuevas.
  • Hierarquia geográfica do Chile. O mock ainda traz estados e cidades do Brasil. Inofensivo hoje (o Chile usa texto livre), errado se as listas voltarem a ser usadas.Chile's geographical hierarchy. The mock still carries Brazilian states and cities. Harmless today (Chile uses free text), wrong if dropdowns come back into use.Jerarquía geográfica de Chile. El mock aún trae estados y ciudades de Brasil. Inofensivo hoy (Chile usa texto libre), incorrecto si las listas vuelven a usarse.
  • Dados fixos no app. A lista de pronomes é hardcoded (não vem de dados de apoio) — pendência conhecida do inventário de dados fixos.Hardcoded data. The pronoun list is hardcoded (not from reference data) — a known item on the hardcoded-data inventory.Datos fijos en la app. La lista de pronombres es hardcoded (no viene de datos de apoyo) — pendencia conocida del inventario de datos fijos.
  • Atalho do menu lateral inerte. O código existe, mas nenhum mercado declara new_account no menu — decidir se entra ou se o código sai.Inert side-menu shortcut. The code exists, but no market declares new_account in the menu — decide whether it goes in or the code comes out.Atajo del menú lateral inerte. El código existe, pero ningún mercado declara new_account en el menú — decidir si entra o si el código sale.
  • Cobertura de testes. Há testes de configuração por mercado e do builder de payload (inclusive das regras de Inscrição Estadual e de contactPosition), mas nenhum cobrindo o caso de uso de checagem de e-mail, o caminho do repository ou o mapper novo.Test coverage. There are per-market configuration tests and payload-builder tests (including the state-registration and contactPosition rules), but none covering the e-mail-check use case, its repository path or the new mapper.Cobertura de pruebas. Hay pruebas de configuración por mercado y del builder de payload (incluidas las reglas de inscripción estatal y de contactPosition), pero ninguna que cubra el caso de uso de verificación de correo, su camino en el repository ni el mapper nuevo.
  • Sem rascunho e sem fila offline. Abandonar o assistente perde tudo, e um envio offline falha sem entrar em fila de reenvio automático (o reenvio manual pode duplicar).No draft and no offline queue. Abandoning the wizard loses everything, and an offline submission fails without entering the automatic resend queue (manual resend may duplicate).Sin borrador y sin cola offline. Abandonar el asistente pierde todo, y un envío offline falla sin entrar en la cola de reenvío automático (el reenvío manual puede duplicar).