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.
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".
Como acessarHow to openCómo acceder
- 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.
- 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.
- 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.
- 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.
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.
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)
| ResultadoOutcomeResultado | Quando aconteceWhen it happensCuándo ocurre | O que o representante vêWhat the rep seesQué ve el representante |
|---|---|---|
| VazioEmptyVacío | campo 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álido | CPF ≠ 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ón | app 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." |
| BloqueadoBlockedBloqueado | documento 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 registrado | documento 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." |
| ErroErrorError | qualquer 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." |
| LiberadoClearedLiberado | nem bloqueado nem em usoneither blocked nor in useni bloqueado ni en uso | nenhuma 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.
| ResultadoOutcomeResultado | O que apareceWhat appearsQué aparece | Avança?Proceeds?¿Avanza? |
|---|---|---|
| DisponívelAvailableDisponible | nada — segue diretonothing — goes straight onnada — sigue directo | simyessí |
| E-mail do varejo em usoRetail e-mail in useCorreo del PDV en uso | erro 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 uso | mesmo 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)
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
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.
AçõesActionsAcciones
Fotografar os documentosPhotograph the documentsFotografiar los documentos
- 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.
- 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.
- 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.
- 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?" — Sí 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 Sí 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.
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 demanda — taxNumberCheck 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 checks — taxNumberCheck 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 demanda — taxNumberCheck 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
- → StateNewRetailFlowState
- GetReferenceDataUseCaseNewRetailFlowNotifier._load()+ marketConfigurationProvider
- toDomainReferenceDataEntitydomain · cache
- toModelReferenceDataModelObjectBox
- toDomainReferenceDataEntitydomain · enums tipados
- toDTOReferenceDataDTODTO · Freezed
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
- toDomain…ResultEntitycanProceed
- toDTOTaxNumberCheckResultDTO
- gRPCtaxNumberCheck / emailCheckRemote · sem cache
- CheckTaxNumberUseCase / CheckEmailUseCaseReferenceDataRepositoryImploffline → NetworkFailure
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
- gRPCsendTransaction(InboxTransactionRequest)
- send()DispatcherRepositoryImpl → DispatcherGatewayjsonEncode(payload)
- SubmitNewRetailUploadUseCase.submit()DispatcherOrchestratorretailNew não entra em fila offline
- BuildNewRetailUploadDispatcherPayloadUseCase.build()DispatcherEnvelopeserviceName AccountContactUploadAPI
- submitNewRetail()NewRetailUploadDispatcherPayloadInputdado cru de domínio
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 só 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.
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.
getReferenceDataunaryrpc getReferenceData(ReferenceDataRequest) returns (ReferenceDataReply)
path /mn.bat.conectarep.streambridge.ReferenceDataConectaRepService/getReferenceData
ReferenceDataRequestlocationHierarchySfidstring· #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)lastModifiedDatestring· #2 · optional · só é enviado quando não-vazioonly sent when non-emptysolo se envía cuando no está vacío
ReferenceDataReply19 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.
taxNumberCheckunaryrpc taxNumberCheck(TaxNumberCheckRequest) returns (TaxNumberCheckReply)
path /mn.bat.conectarep.streambridge.ReferenceDataConectaRepService/taxNumberCheck
TaxNumberCheckRequestresourceSfidstring· #1 ·primaryResourceSfidousecondaryResourceSfid, conforme a sessãoprimaryResourceSfidorsecondaryResourceSfid, per the sessionprimaryResourceSfidosecondaryResourceSfid, según la sesióntaxIdstring· #2 · dígitos do CNPJ quando o tipo ébusiness; vazio nos outrosCNPJ digits when the type isbusiness; empty otherwisedígitos del CNPJ cuando el tipo esbusiness; vacío en los demástaxNumberstring· #3 · dígitos do CPF/documento individual; vazio quandobusiness(mutuamente exclusivo comtaxId)CPF/individual document digits; empty whenbusiness(mutually exclusive withtaxId)dígitos del CPF/documento individual; vacío cuandobusiness(mutuamente exclusivo contaxId)
TaxNumberCheckReplybool hasTaxNumber · bool isBlackListed · string blackListMessage — detalhado em TaxNumberCheckResult nas Estruturas.detailed as TaxNumberCheckResult in Data structures.detallado como TaxNumberCheckResult en Estructuras.
emailCheckunaryrpc emailCheck(EmailCheckRequest) returns (EmailCheckReply)
path /mn.bat.conectarep.streambridge.ReferenceDataConectaRepService/emailCheck
EmailCheckRequestresourceSfidstring· #1 · mesmo sfid dotaxNumberCheck, por simetriathe same sfid astaxNumberCheck, for symmetryel mismo sfid quetaxNumberCheck, por simetríaemailstring· #2 · enviado comtrim(), sem normalizar caixasent withtrim(), case not normalizedenviado contrim(), sin normalizar mayúsculastargetstring· #3 ·"account"|"contact"· valores fechados no app pelo enumEmailCheckTargetvalues closed in the app by theEmailCheckTargetenumvalores cerrados en la app por el enumEmailCheckTarget
EmailCheckReplybool hasEmail · string message — message 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
Campo Proto DTO Model Entity lastSyncAt— DateTimeDateTime DateTime deliveryCancelReasonsrepeated DeliveryCancelReason List<…DTO> ToMany<…Model>List<…Entity> geographicalHierarchyGeographicalHierarchy …DTO ToOne<…Model>…Entity outletSubtypesrepeated SfidNamePair List<…DTO> ToMany<…Model>List<…Entity> categoriesForSalerepeated string List<String> List<String> List<CategoryForSale>bannersrepeated SfidNamePair List<…DTO> ToMany<…Model>List<…Entity> propertyTypesrepeated string List<String> List<String> List<String> keyAccountTypesrepeated string List<String> List<String> List<String> giroOptionsrepeated SfidNamePair List<…DTO> ToMany<…Model>List<…Entity> canalOptionsrepeated SfidNamePair List<…DTO> ToMany<…Model>List<…Entity> localClassificationDefinitionsrepeated LocalClassificationDefinition List<…DTO> ToMany<…Model>List<…Entity> contactRolesrepeated string List<String> List<String> List<ContactRole>languagePreferencesrepeated string List<String> List<String> List<LanguagePreference>buybackReasonsrepeated BuybackReason List<…DTO> ToMany<…Model>List<…Entity> moduleMasterModuleMaster …DTO ToOne<…Model>…Entity accountInactiveReasonsrepeated string List<String> List<String> List<AccountInactiveReason>pdvTypesrepeated PdvType List<…DTO> ToMany<…Model>List<…Entity> holidaysrepeated Holiday List<…DTO> ToMany<…Model>List<…Entity> visitCancelReasonsrepeated VisitReason List<…DTO> ToMany<VisitCancelReasonModel>List<VisitReasonEntity> visitNoBuyReasonsrepeated VisitReason List<…DTO> ToMany<VisitNoBuyReasonModel>List<VisitReasonEntity> O cadastro de varejo consome 11 campos:
geographicalHierarchy,outletSubtypes,categoriesForSale,banners,propertyTypes,keyAccountTypes,giroOptions,canalOptions,localClassificationDefinitions,contactRoles,languagePreferences(+lastSyncAtpara oDataLoadInfo). Os demais pertencem a outras features.pdvTypesexiste 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(+lastSyncAtforDataLoadInfo). The rest belong to other features.pdvTypesexists 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(+lastSyncAtpara elDataLoadInfo). Los demás pertenecen a otras features.pdvTypesexiste de punta a punta pero ningún código lo lee hoy.GeographicalHierarchy ReferenceData.geographicalHierarchy 2 campos
Campo Proto DTO Model Entity countrySfidstring String String String statesrepeated State List<GeoStateDTO> ToMany<GeoStateModel>List<GeoStateEntity> GeoState GeographicalHierarchy.states[] · protoprotoproto
State4 camposCampo Proto DTO Model Entity sfidstring String String String namestring String String String codestring String String String citiesrepeated City List<GeoCityDTO> ToMany<GeoCityModel>List<GeoCityEntity> GeoCity GeoState.cities[] ·
City2 camposCampo Proto DTO Model Entity sfidstring String String String namestring String String String
LocalClassificationDefinition ReferenceData.localClassificationDefinitions[] 4 campos
Campo Proto DTO Model Entity sfidstring String String String namestring String String String typestring String String LocalClassificationTypeoptionsrepeated SfidNamePair List<SfidNamePairDTO> ToMany<SfidNamePairModel>List<SfidNamePairEntity> SfidNamePair compartilhado ·shared ·compartido · CommonConectaRep.proto 2 campos
Campo Proto DTO Model Entity sfidstring String String String namestring String String String Alimenta
outletSubtypes,banners,giroOptions,canalOptionse as opções de classificação local.FeedsoutletSubtypes,banners,giroOptions,canalOptionsand the local-classification options.AlimentaoutletSubtypes,banners,giroOptions,canalOptionsy las opciones de clasificación local.
EmailCheckResult raiz · sem Model, sem cacheroot · no Model, no cacheraíz · sin Model, sin caché 2 campos
Campo Proto DTO Model Entity hasEmailbool bool — bool messagestring String — String Getter da Entity:
bool get canProceed => !hasEmail;. Omessageé o motivo do backend, exibido no modal abaixo da mensagem traduzida.Entity getter:bool get canProceed => !hasEmail;.messageis the backend reason, shown in the modal below the translated message.Getter de la Entity:bool get canProceed => !hasEmail;.messagees 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
Campo Proto DTO Model Entity hasTaxNumberbool bool — bool isBlackListedbool bool — bool blackListMessagestring String — String 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
Campo Proto DTO Model Entity street— — — String neighborhood— — — String city— — — String stateCode— — — String NewRetailContact raiz · rascunho em memóriaroot · in-memory draftraíz · borrador en memoria 9 campos
Campo Proto DTO Model Entity firstName— — — String lastName— — — String pronoun— — — Pronoun preferredLanguage— — — LanguagePreference role— — — ContactRole cellPhone— — — String email— — — String dateOfBirth— — — DateTime? isMainContact— — — bool 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
Campo Proto DTO Model Entity documentRequirementsByType— Map<String, List<…DTO>> — Map<NewRetailType, List<…>>startOfActivityDocumentsByType— Map<String, List<…DTO>> — Map<NewRetailType, List<…>>legalEntityFieldsByType— Map<String, List<…DTO>> — Map<NewRetailType, List<…>>addressFieldsByType— Map<String, List<…DTO>> — Map<NewRetailType, List<…>>operationalDataFieldsByType— Map<String, List<…DTO>> — Map<NewRetailType, List<…>>contactFieldsByType— Map<String, List<…DTO>> — Map<NewRetailType, List<…>>postalCodeAutoComplete— bool — bool wireConfig— NewRetailWireConfigDTO — NewRetailWireConfig requiresDocumentValidation— bool — bool retailTypes— List<String> — List<NewRetailType>checksAccountEmailUniqueness— bool — bool checksContactEmailUniqueness— bool — bool requiresB2bCustomerForContacts— bool — bool allowsStateRegistrationExemption— bool — bool As chaves do JSON são idênticas aos nomes dos campos. As chaves de tipo (
"individual"/"business"/"generic") viramNewRetailTypeporfromKey, com fallback silencioso parageneric. 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") becomeNewRetailTypeviafromKey, with a silent fallback togeneric. 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 aNewRetailTypevíafromKey, con fallback silencioso ageneric. Métodos:documentRequirementsFor,startOfActivityDocumentsFor,legalEntityFieldsFor,addressFieldsFor,operationalDataFieldsFor,contactFieldsFor— todos con lista vacía por defecto.NewRetailWireConfig NewRetailConfig.wireConfig 20 campos
Campo Proto DTO Model Entity accountRecordTypeId— String — String contactRecordTypeId— String — String locationHierarchyId— String — String paymentMethod— String — String defaultPaymentMethod— String — String currencyIsoCode— String — String language— String — String mailingCountry— String — String contactPreferredLanguage— String — String sendsVatRegistrationNo— bool — bool sendsTaxId— bool — bool sendsDocumentData— bool — bool collectsDirectSales— bool — bool userQuotas— String — String ownerShipType— String — String totalSellInValPerAnnum— String — String isTaxRequired— String — String contactB2bStatus— String — String restrictedOrderEdit— String — String isPartialDelivery— String — String Note os bools textuais:
isTaxRequired,restrictedOrderEditeisPartialDeliverysãoStringno 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,restrictedOrderEditandisPartialDeliveryareStringin 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,restrictedOrderEditeisPartialDeliverysonStringen 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
Campo Proto DTO Model Entity id— String — String titleKey— String — String subtitleKey— String? — String? documentKeys— List<String> — List<String> É o acordeão "os documentos necessários são:" — puramente informativo, sem relação com os espaços de foto.
subtitleKeysó existe hoje no perfilindividual_rsa_resident(África do Sul).This is the "the required documents are:" accordion — purely informative, unrelated to photo slots.subtitleKeytoday exists only on theindividual_rsa_residentprofile (South Africa).Es el acordeón "los documentos requeridos son:" — puramente informativo, sin relación con los espacios de foto.subtitleKeyhoy solo existe en el perfilindividual_rsa_resident(Sudáfrica).NewRetailStartOfActivityDocument startOfActivityDocumentsByType[type][] 3 campos
Campo Proto DTO Model Entity id— String — String labelKey— String — String isMandatory— bool — bool 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 ofisMandatory: 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 deisMandatory: 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
Campo Proto DTO Model Entity fieldName→field— String? — NewRetailLegalEntityFieldisVisible— bool — bool isRequired— bool — bool isEditable— bool — bool NewRetailAddressFieldConfig addressFieldsByType[type][] 5 campos
Campo Proto DTO Model Entity fieldName→field— String? — NewRetailAddressFieldisVisible— bool — bool isRequired— bool — bool isFreeText— bool — bool isEditable— bool — bool isFreeTexttroca 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.isFreeTextswaps the dropdown for a text field (what Chile uses for region and comuna) and changes what goes on the wire: name instead of sfid.isEditableis parsed by the mapper but no market declares it in the address list today.isFreeTextcambia 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.isEditablelo lee el mapper pero ningún mercado lo declara hoy en la lista de dirección.NewRetailOperationalDataFieldConfig operationalDataFieldsByType[type][] 3 campos
Campo Proto DTO Model Entity fieldName→field— String? — NewRetailOperationalDataFieldisVisible— bool — bool isRequired— bool — bool 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 isisVisible && isRequired— that is how Local classification is only enforced in South Africa, where it is both visible and required.La obligatoriedad efectiva esisVisible && isRequired— así la Clasificación Local solo se exige en Sudáfrica, donde está visible y obligatoria.NewRetailContactFieldConfig contactFieldsByType[type][] 3 campos
Campo Proto DTO Model Entity fieldName→field— String? — NewRetailContactFieldisVisible— bool — bool isRequired— bool — bool
NewRetailUploadDispatcherPayloadInput raiz · entrada do builder (só domínio)root · builder input (domain only)raíz · entrada del builder (solo dominio) 46 campos
Campo Proto DTO Model Entity retailType— — — NewRetailType vatNumber— — — String stateRegistration— — — String outletName— — — String commercialName— — — String countrySfid— — — String stateCode— — — String city— — — String district— — — String addressLine— — — String number— — — String addressContinue— — — String postalCode— — — String cellPhone— — — String phone— — — String email— — — String outletSubtypeSfid— — — String categoriesSold— — — List<CategoryForSale> operatingDays— — — List<String> openingTime— — — String closingTime— — — String breakStart— — — String breakEnd— — — String banner— — — String propertyType— — — String keyAccountType— — — String giro— — — String channel— — — String isB2BCustomer— — — bool isDirectSales— — — bool isNetworkParent— — — bool localClassificationName— — — String localClassificationOptionSfid— — — String localClassificationDefinitionSfid— — — String localClassificationDefinitionType— — — String contacts— — — List<NewRetailContactEntity> wireConfig— — — NewRetailWireConfig resource— — — ResourceEntity market— — — EndMarket customerCode— — — String imagesBase64— — — List<String> latitude— — — double longitude— — — double submittedAt— — — DateTime deliveryDay— — — WeekDay? salesmanVisitDay— — — WeekDay? Freezed, nomes de domínio (
giro,channel,vatNumber) — o rename para o wire acontece no builder.stateCodeecitycarregam sfid ou nome, conformeisFreeText;localClassificationOptionSfidcarrega 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.stateCodeandcitycarry sfid or name, perisFreeText;localClassificationOptionSfidcarries 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.stateCodeycityllevan sfid o nombre, segúnisFreeText;localClassificationOptionSfidlleva 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.
| EnvelopeEnvelopeEnvelope | ValorValueValor |
|---|---|
DispatcherType | retailNew |
serviceName | "AccountContactUploadAPI" (nunca com prefixo Promo_)(never with the Promo_ prefix)(nunca con prefijo Promo_) |
endpoint | "salesforce" |
transactionReference | customerCode — 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 |
dateReference | submittedAt formatado comoformatted asformateado como yyyy-MM-dd |
account | sapCode: customerCode · name: outletName |
tid | 0 |
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 JSON | TipoTypeTipo | Origem do dadoData sourceOrigen del dato | RegraRuleRegla |
|---|---|---|---|
VATRegistrationNo | String | Input.vatNumber | só 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 |
taxId | String | Input.vatNumber | só existe se wireConfig.sendsTaxId; vazio quando individualonly present if wireConfig.sendsTaxId; empty when individualsolo existe si wireConfig.sendsTaxId; vacío cuando individual |
taxNumber2 | String | Input.vatNumber | recebe 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 |
taxNumber3 | String | Input.stateRegistration | Inscriçã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 |
name | String | Input.outletName | razão sociallegal namerazón social |
commercialName | String | Input.commercialName | nome fantasiatrade namenombre de fantasía |
postCode | String | Input.postalCode | PostalCodeUtils.format por mercado (BR #####-###, demais só dígitos)per market (BR #####-###, others digits only)por mercado (BR #####-###, demás solo dígitos) |
addressLine1 | String | Input.addressLine + Input.number | concatena "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 |
addressLine2 | String | Input.addressContinue | complementocomplementcomplemento |
district | String | Input.district | bairro/comuna (máx. 35)district/comuna (max 35)barrio/comuna (máx. 35) |
city | String | Input.city | sfid 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) |
Country | String | Input.countrySfid | sfid do país, da hierarquia geográficacountry sfid, from the geographical hierarchysfid del país, de la jerarquía geográfica |
stateCode | String | Input.stateCode | sfid ou nome, mesma regra da cidadesfid or name, same rule as the citysfid o nombre, misma regla que la ciudad |
categoriesSold | String | Input.categoriesSold | labels unidos por ; (ex. "FMC;Vapour Devices")labels joined by ; (e.g. "FMC;Vapour Devices")labels unidos por ; (ej. "FMC;Vapour Devices") |
outletSubtype | String | Input.outletSubtypeSfid | sfid |
preferredDeliveryDay | String | Input.deliveryDay | abreviaçã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 |
PreferredDayForVisit | String | Input.salesmanVisitDay | nome completo ("Monday"); vazio quando não escolhidofull name ("Monday"); empty when not chosennombre completo ("Monday"); vacío cuando no se elige |
daysOpenForBusiness | String | Input.operatingDays | dias unidos por ;days joined by ;días unidos por ; |
openingTime | String | Input.openingTime | HH:mm (padrão 07:30)HH:mm (default 07:30)HH:mm (por defecto 07:30) |
closingTime | String | Input.closingTime | HH:mm (padrão 18:30)HH:mm (default 18:30)HH:mm (por defecto 18:30) |
breakStartTime | String | Input.breakStart | a 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) |
breakEndTime | String | Input.breakEnd | idemsameídem |
mobile | String | Input.cellPhone | só dígitosdigits onlysolo dígitos |
telephone1 | String | Input.phone | só dígitosdigits onlysolo dígitos |
contactEmail | String | Input.email | e-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) |
sapCustomerId | String | Fixo: "" | o SAP é atribuído pelo backendSAP is assigned by the backendel SAP lo asigna el backend |
recordTypeId | String | EMC.wireConfig.accountRecordTypeId | record type do Salesforce, por mercadoSalesforce record type, per marketrecord type de Salesforce, por mercado |
status | String | Fixo: "Active" | — |
active | String | Fixo: "Yes" | — |
marketIso | String | Input.market | BR | CL | ZA |
locationHierarchy | String | EMC.wireConfig.locationHierarchyId | — |
createdById | String | Fixo: "" | — |
isB2BCustomer | String | Input.isB2BCustomer | bool → "true"/"false"bool → "true"/"false"bool → "true"/"false" |
restrictedOrderEdit | String | EMC.wireConfig.restrictedOrderEdit | — |
isBillTo · isShipTo · isSoldTo · isPayer | String | Fixo: "true" | quatro chaves separadas, todas fixasfour separate keys, all fixedcuatro claves separadas, todas fijas |
isPartialDelivery | String | EMC.wireConfig.isPartialDelivery | — |
language | String | EMC.wireConfig.language | — |
salesTerritory | String | Resource.locationHierarchyId | hierarquia do representantethe rep's hierarchyjerarquía del representante |
deliveryTerritory | String | Resource.deliveryTerritory | — |
deliveryLeadTime | String | Fixo: "1" | — |
paymentMethod | String | EMC.wireConfig.paymentMethod | códigos separados por ;codes separated by ;códigos separados por ; |
defaultPaymentMethod | String | EMC.wireConfig.defaultPaymentMethod | — |
currencyIsoCode | String | EMC.wireConfig.currencyIsoCode | — |
userQuotas | String | EMC.wireConfig.userQuotas | BR/CL "50", ZA "5"BR/CL "50", ZA "5"BR/CL "50", ZA "5" |
banner | String | Input.banner | sfid do banner (Chile)banner sfid (Chile)sfid del banner (Chile) |
ownerShipType | String | Input.propertyType | se vazio, cai para EMC.wireConfig.ownerShipTypeif empty, falls back to EMC.wireConfig.ownerShipTypesi está vacío, cae a EMC.wireConfig.ownerShipType |
emlov1 | String | Input.giro | nome de wire do Giro (sfid)wire name of Business type (sfid)nombre de wire del Giro (sfid) |
emlov2 | String | Input.channel | nome de wire do Canal (sfid)wire name of Channel (sfid)nombre de wire del Canal (sfid) |
keyAccountType | String | Input.keyAccountType | — |
customerCode | String | Calculado no notifierCalculated in the notifierCalculado en el notifier | mesmo valor do transactionReferencesame value as transactionReferencemismo valor que transactionReference |
istaxrequired | String | EMC.wireConfig.isTaxRequired | — |
isdirectsales | String | Input.isDirectSales | só 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 · routeFrq | String | Fixo: "" | duas chaves separadastwo separate keysdos claves separadas |
latitude · longitude | String | LocationService.currentPosition | duas 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 JSON | TipoTypeTipo | Origem do dadoData sourceOrigen del dato | RegraRuleRegla |
|---|---|---|---|
firstName | String | Contact.firstName | no Brasil, primeira palavra do nome completoin Brazil, the first word of the full nameen Brasil, la primera palabra del nombre completo |
lastName | String | Contact.lastName | no Brasil, o resto do nome completoin Brazil, the rest of the full nameen Brasil, el resto del nombre completo |
recordTypeId | String | EMC.wireConfig.contactRecordTypeId | vazio no Brasil hojeempty in Brazil todayvacío en Brasil hoy |
mobilePhone | String | Contact.cellPhone | só dígitosdigits onlysolo dígitos |
salutation | String | Contact.pronoun | "Mr." | "Mrs." | "Miss" |
contactPosition | String | CalculadoCalculatedCalculado | "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 |
role | String | Contact.role | label em inglês do ContactRole ("Clerk", "Owner"…)English label of ContactRole ("Clerk", "Owner"…)label en inglés de ContactRole ("Clerk", "Owner"…) |
isPrimaryContact | String | Contact.isMainContact | "true"/"false" |
birthdate | String | Contact.dateOfBirth | yyyy/MM/dd ou "" quando não informadoor "" when absento "" cuando no se informa |
mailingCountry | String | EMC.wireConfig.mailingCountry | — |
PreferedLang | String | EMC.wireConfig.contactPreferredLanguage | nome de wire com grafia legadawire name keeps the legacy misspellingnombre de wire con grafía legada |
PreferedMethodtoContact | String | Fixo: "mobile" | — |
b2bStatus | String | EMC.wireConfig.contactB2bStatus | CL "Active"; BR/ZA "Inactive"CL "Active"; BR/ZA "Inactive"CL "Active"; BR/ZA "Inactive" |
email | String | Contact.email | é o e-mail que a checagem de contato validathe e-mail the contact check validatesel correo que valida la verificación de contacto |
customerCode | String | Calculado no notifierCalculated in the notifierCalculado en el notifier | liga o contato ao varejo do mesmo envelopelinks the contact to the retail in the same envelopevincula el contacto al PDV del mismo envelope |
istaxrequired | String | Fixo: "true" | — |
isdirectsales | String | Fixo: "true" | — |
routeID · routeFrq | String | Fixo: "" | duas chaves separadastwo separate keysdos claves separadas |
latitude · longitude | String | LocationService.currentPosition | duas chaves, mesmas do varejotwo keys, the same as the retail'sdos claves, las mismas del PDV |
languagePreference | String | Contact.preferredLanguage | có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 JSON | TipoTypeTipo | Origem do dadoData sourceOrigen del dato | RegraRuleRegla |
|---|---|---|---|
CustomerCode | String | Calculado no notifierCalculated in the notifierCalculado en el notifier | — |
LocationID | String | Resource.locationHierarchyId | — |
MarketISO | String | Input.market | — |
assignTempRes | String | Fixo: "" | — |
FromDate | String | Fixo: "" | — |
ToDate | String | Fixo: "" | — |
globalClassification[0] 13 chaveskeysclaves
| Campo JSONJSON fieldCampo JSON | TipoTypeTipo | Origem do dadoData sourceOrigen del dato | RegraRuleRegla |
|---|---|---|---|
RecordTypeID | String | Input.categoriesSold | labels 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 |
CustomerCode | String | Calculado no notifierCalculated in the notifierCalculado en el notifier | — |
TotalsellinValperAnnum | String | EMC.wireConfig.totalSellInValPerAnnum | CL/ZA "1"; BR ""CL/ZA "1"; BR ""CL/ZA "1"; BR "" |
MarketingAttractiveness | String | Fixo: "" | — |
sellinValperAnnum | String | Fixo: "" | — |
FacingCapacity | String | Fixo: "" | — |
TotalfacingCapacity | String | Fixo: "" | — |
category | String | Fixo: "" | — |
costofBusiness | String | Fixo: "" | — |
InStoreOpp | String | Fixo: "" | — |
priceSegLow | String | Fixo: "" | — |
priceSegValue | String | Fixo: "" | — |
priceSegPremium | String | Fixo: "" | — |
localClassification[0] 5 chaveskeysclaves
| Campo JSONJSON fieldCampo JSON | TipoTypeTipo | Origem do dadoData sourceOrigen del dato | RegraRuleRegla |
|---|---|---|---|
currencyIsoCode | String | EMC.wireConfig.currencyIsoCode | — |
customerCode | String | Calculado no notifierCalculated in the notifierCalculado en el notifier | — |
localClassName | String | Input.localClassificationName | nome 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 |
localClassOptId | String | Input.localClassificationOptionSfid | sfid 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 |
localClassDefId | String | Input.localClassificationDefinitionSfid | — |
localClassificationDefination[0] 4 chaves · grafia legada preservadakeys · legacy spelling keptclaves · grafía legada preservada
| Campo JSONJSON fieldCampo JSON | TipoTypeTipo | Origem do dadoData sourceOrigen del dato | RegraRuleRegla |
|---|---|---|---|
localClassDefName | String | Input.localClassificationName | — |
isActive | String | Fixo: "true" | — |
isMandatory | String | Fixo: "true" | — |
type | String | Input.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 JSON | TipoTypeTipo | Origem do dadoData sourceOrigen del dato | RegraRuleRegla |
|---|---|---|---|
name | String | Input.outletName | — |
tax | String | Input.vatNumber | documento como digitadodocument as typeddocumento tal como se escribió |
docFront | String (base64) | Input.imagesBase64[0] | 1ª foto capturada1st captured photo1ª foto capturada |
docBack | String (base64) | Input.imagesBase64[1] | 2ª foto2nd photo2ª foto |
imageCNPJ | String (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, "" |
addressProof | String (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 |
customerCode | String | Calculado no notifierCalculated in the notifierCalculado en el notifier | — |
dateCreate | String | Input.submittedAt | timestamp 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: false — a 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: false — the 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: false — la 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ón | MétodoMethodMétodo | Usada porUsed byUsada por |
|---|---|---|
| JSON → DTO | static 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 → DTO | toDTO() | ReferenceDataReply · TaxNumberCheckReply · EmailCheckReply |
| DTO → Entity | toDomain() | 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 → Model | toModel() | só 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 → Entity | toDomain() | só 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 (
Stringnas outras camadas):CategoryForSale,ContactRole,LanguagePreference,AccountInactiveReason,LocalClassificationTypeenums typed only in the Entity (Stringelsewhere):CategoryForSale,ContactRole,LanguagePreference,AccountInactiveReason,LocalClassificationTypeenums tipados solo en la Entity (Stringen las demás):CategoryForSale,ContactRole,LanguagePreference,AccountInactiveReason,LocalClassificationType - relações viram
ToMany/ToOneno Model;visitCancelReasonsevisitNoBuyReasonscompartilham a Entity mas têm Models distintosrelations becomeToMany/ToOnein the Model;visitCancelReasonsandvisitNoBuyReasonsshare the Entity but have distinct Modelslas relaciones pasan aToMany/ToOneen el Model;visitCancelReasonsyvisitNoBuyReasonscomparten la Entity pero tienen Models distintos lastSyncAtnão existe no proto — é gerado no mapper comDateTimeUtils.now(); no mock, lido do JSONdoes not exist in the proto — generated in the mapper withDateTimeUtils.now(); in the mock, read from the JSONno existe en el proto — se genera en el mapper conDateTimeUtils.now(); en el mock, se lee del JSON- a configuração de campo renomeia
fieldName(String) parafield(enum) na Entityfield configuration renamesfieldName(String) tofield(enum) in the Entityla configuración de campo renombrafieldName(String) afield(enum) en la Entity EmailCheckResult·TaxNumberCheckResultparam na Entity: sem Model, sem cache, semfromMapstop at the Entity: no Model, no cache, nofromMapparan en la Entity: sin Model, sin caché, sinfromMap- 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 (
giro→emlov1,channel→emlov2,propertyType→ownerShipType,stateRegistration→taxNumber3) acontece só no builder, nunca no Inputthe wire rename (giro→emlov1,channel→emlov2,propertyType→ownerShipType,stateRegistration→taxNumber3) happens only in the builder, never in the Inputel rename al wire (giro→emlov1,channel→emlov2,propertyType→ownerShipType,stateRegistration→taxNumber3) ocurre solo en el builder, nunca en el Input
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
useMockData== true ouorosource == 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.source == localou offlineor offlineu offline→_fetchFromCacheOrFail(): cache vazio devolveError(NetworkFailure).→_fetchFromCacheOrFail(): an empty cache returnsError(NetworkFailure).→_fetchFromCacheOrFail(): caché vacío devuelveError(NetworkFailure).- senão (remoto + conectado)otherwise (remote + connected)si no (remoto + conectado)→
_fetchFromRemoteWithFallback(): lêcurrentResourceProvider; senull, cai pro cache; senão chama o remoto comlocationHierarchyId, mapeia, grava no cache; em erro, fallback pro cache.→_fetchFromRemoteWithFallback(): readscurrentResourceProvider; ifnull, falls back to cache; else calls remote withlocationHierarchyId, maps, writes to cache; on error, falls back to cache.→_fetchFromRemoteWithFallback(): leecurrentResourceProvider; si esnull, cae al caché; si no llama al remoto conlocationHierarchyId, 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
useMockData→ mock resolve por lista dentro do asset dereference_data; erro viraCacheFailure.→ the mock resolves from a list inside thereference_dataasset; an error becomesCacheFailure.→ el mock resuelve desde una lista dentro del asset dereference_data; un error pasa aCacheFailure.- offlineofflineoffline→
Error(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". - sem representante em sessãono rep in sessionsin representante en sesión→
Error(UnknownFailure()).→Error(UnknownFailure()).→Error(UnknownFailure()). - senãootherwisesi no→ remoto com
resourceSfid(primaryResourceSfidousecondaryResourceSfid, conforme a sessão) etarget.wireValue; falha viraFailuremapeada e logada comtraceId.→ remote withresourceSfid(primaryResourceSfidorsecondaryResourceSfid, per the session) andtarget.wireValue; a failure becomes a mappedFailure, logged with itstraceId.→ remoto conresourceSfid(primaryResourceSfidosecondaryResourceSfid, según la sesión) ytarget.wireValue; una falla pasa aFailuremapeada y registrada contraceId.
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.
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: GrpcError → GrpcExceptionHandler.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: GrpcError → GrpcExceptionHandler.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: GrpcError → GrpcExceptionHandler.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ó incluilastModifiedDatequando não-vazio) e chama_client.getReferenceData(request).buildsReferenceDataRequest(only includeslastModifiedDatewhen non-empty) and calls_client.getReferenceData(request).armaReferenceDataRequest(solo incluyelastModifiedDatecuando no está vacío) y llama_client.getReferenceData(request). - RetornoReturnRetorno
ReferenceDataDTO(viaresponse.toDTO())(viaresponse.toDTO())(víaresponse.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
TaxNumberCheckRequestcom 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
EmailCheckRequestcomresourceSfid,emailetargetcomo String crua (o enum é convertido no repository) →_client.emailCheck(request).withresourceSfid,emailandtargetas a raw String (the enum is converted in the repository) →_client.emailCheck(request).conresourceSfid,emailytargetcomo 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 éUNIMPLEMENTED→ServerException→ o representante não avança.until the backend implements the RPC, the real answer isUNIMPLEMENTED→ServerException→ the rep cannot proceed.mientras el backend no implemente el RPC, la respuesta real esUNIMPLEMENTED→ServerException→ 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(viafromMap)(viafromMap)(víafromMap)- 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
taxNumberCheckdo asset: escolhetaxIdse não-vazio, senãotaxNumber, e compara comblackListedDocumentsedocumentsInUse;blackListMessagesó volta quando bloqueado. O bloco existe só embr_real_reference_data.json— no mock padrão o resultado é sempre "liberado".reads the asset'staxNumberCheckblock: pickstaxIdwhen non-empty, elsetaxNumber, and compares againstblackListedDocumentsanddocumentsInUse;blackListMessageonly comes back when blocked. The block exists only inbr_real_reference_data.json— in the standard mock the answer is always "cleared".lee el bloquetaxNumberCheckdel asset: eligetaxIdsi no está vacío, si notaxNumber, y compara conblackListedDocumentsydocumentsInUse;blackListMessagesolo vuelve cuando está bloqueado. El bloque existe solo enbr_real_reference_data.json— en el mock estándar el resultado es siempre "liberado".
checkEmail({email, target}) novonewnuevo
- RetornoReturnRetorno
EmailCheckResultDTO- ComportamentoBehaviorComportamiento
- lê o bloco
emailCheckdo asset e escolhe a lista pelotarget:accountEmailsInUseoucontactEmailsInUse. Comparação case-insensitive comtrim();messagesó volta quando há acerto. Recebe o enumEmailCheckTarget(o remoto recebe String).reads the asset'semailCheckblock and picks the list bytarget:accountEmailsInUseorcontactEmailsInUse. Case-insensitive comparison withtrim();messageonly comes back on a hit. Takes theEmailCheckTargetenum (the remote takes a String).lee el bloqueemailCheckdel asset y elige la lista portarget:accountEmailsInUseocontactEmailsInUse. Comparación case-insensitive contrim();messagesolo vuelve al acertar. Recibe el enumEmailCheckTarget(el remoto recibe String). - Dados de mockMock dataDatos de mock
- BR
varejo.existente@conectarep.com.br/contato.existente@conectarep.com.br; CLvarejo.existente@conectarep.cl/contacto.existente@conectarep.cl; ZAretail.existing@conectarep.co.za/contact.existing@conectarep.co.za. AR/PY/PE não têm o bloco → sempre "disponível".BRvarejo.existente@conectarep.com.br/contato.existente@conectarep.com.br; CLvarejo.existente@conectarep.cl/contacto.existente@conectarep.cl; ZAretail.existing@conectarep.co.za/contact.existing@conectarep.co.za. AR/PY/PE have no block → always "available".BRvarejo.existente@conectarep.com.br/contato.existente@conectarep.com.br; CLvarejo.existente@conectarep.cl/contacto.existente@conectarep.cl; ZAretail.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()ounullse o cache está vazio.ornullif the cache is empty.onullsi el caché está vacío.
getReferenceDataLastSyncAt()
- RetornoReturnRetorno
DateTime?- ComportamentoBehaviorComportamiento
models.first.lastSyncAt— é o valor exibido noDataLoadInfode todas as 9 telas.the value shown in theDataLoadInfoon all 9 screens.el valor mostrado en elDataLoadInfode 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
jsonEncodee montaInboxTransactionRequest(endpoint,serviceName,dateReference,transactionReference,username,message, dados do dispositivo,deviceUuid: "REP",tid), comauthorization: Bearernos metadados →sendTransaction.serializes the payload withjsonEncodeand buildsInboxTransactionRequest(endpoint,serviceName,dateReference,transactionReference,username,message, device data,deviceUuid: "REP",tid), withauthorization: Bearerin the metadata →sendTransaction.serializa el payload conjsonEncodey armaInboxTransactionRequest(endpoint,serviceName,dateReference,transactionReference,username,message, datos del dispositivo,deviceUuid: "REP",tid), conauthorization: Beareren los metadatos →sendTransaction. - RetornoReturnRetorno
DispatcherAck(status,transactionId,message) — sucesso quandostatusé0ou5;1é duplicado.(status,transactionId,message) — success whenstatusis0or5;1means duplicate.(status,transactionId,message) — éxito cuandostatuses0o5;1es duplicado.- Fluxo de usoUsage flowFlujo de uso
- chamado pelo orchestrator. Em
useMockDatahá curto-circuito; offline lançaNetworkException; um401tenta uma vez com token renovado.called by the orchestrator. UnderuseMockDatait short-circuits; offline it throwsNetworkException; a401retries once with a refreshed token.llamado por el orchestrator. ConuseMockDatahace corto-circuito; offline lanzaNetworkException; un401reintenta 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 usatrFailurecom a mensagem genérica do fluxo como fallback.exceptions bubble to the repository, which returnsNetworkFailure. The backend's raw message is logged, never shown; the UI usestrFailurewith the flow's generic message as fallback.las excepciones suben al repository, que devuelveNetworkFailure. El mensaje crudo del backend se registra, nunca se muestra; la UI usatrFailurecon 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'sbuild().crea la sesión de archivos en elbuild()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>·base64Encodepuro, sem prefixodata:— chamado no envio, foto por foto.plainbase64Encode, nodata:prefix — called on submit, photo by photo.base64Encodepuro, sin prefijodata:— 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.onDisposedo notifier: apaga todas as fotos ao sair do fluxo.in the notifier'sref.onDispose: deletes every photo when leaving the flow.en elref.onDisposedel 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.NetworkFailurelibera digitação manual; qualquer outra falha vira "CEP não encontrado".returns street, district, city and state code.NetworkFailureunlocks manual entry; any other failure becomes "postal code not found".devuelve calle, barrio, ciudad y sigla del estado.NetworkFailurehabilita 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
GooglePlaceAutoCompleteTextFieldcom a chave deGoogleMapsConfig.apiKey(vem do.env), debounce 600 ms, país e idioma do mercado ativo.GooglePlaceAutoCompleteTextFieldwith the key fromGoogleMapsConfig.apiKey(loaded from.env), 600 ms debounce, country and language of the active market.GooglePlaceAutoCompleteTextFieldcon la clave deGoogleMapsConfig.apiKey(del.env), debounce de 600 ms, país e idioma del mercado activo.- ResoluçãoResolutionResolución
- a sugestão devolve latitude/longitude;
placemarkFromCoordinatespreenche estado (região), cidade (comuna), bairro, rua e número. Erro é apenas logado — o representante segue digitando à mão.the suggestion returns latitude/longitude;placemarkFromCoordinatesfills state (region), city (comuna), district, street and number. An error is only logged — the rep keeps typing manually.la sugerencia devuelve latitud/longitud;placemarkFromCoordinatescompleta estado (región), ciudad (comuna), barrio, calle y número. El error solo se registra — el representante sigue escribiendo a mano.
LocationService GPS
currentPositionPosition?· lido no envio; sem posição, o payload leva0.0em latitude e longitude.read on submit; with no position, the payload carries0.0for latitude and longitude.leído en el envío; sin posición, el payload lleva0.0en latitud y longitud.
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
| case | wireValue | o 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
| case | i18n key | canProceed |
|---|---|---|
available | nenhumanoneninguna | true |
accountTaken | new_retail_account_email_in_use_message | false |
contactTaken | new_retail_contact_email_in_use_message | false |
offline | new_retail_email_check_offline_message | false |
error | new_retail_email_check_error_message | false |
NewRetailType 3
| case | chave no EMCEMC keyclave en el EMC | i18n key | íconeiconicono |
|---|---|---|---|
generic | "generic" | new_retail_type_generic_label | drawerRetailsShop |
individual | "individual" | new_retail_type_individual_label | newRetailIndividual |
business | "business" | new_retail_type_business_label | drawerRetailsShop |
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
| case | wireValue | campo 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
| case | wireValue | campo 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
| case | wireValue | tipo 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
| case | wireValue | tipo 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
| case | significadomeaningsignificado |
|---|---|
idle | nenhuma 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) |
loading | consultando o CEPlooking the postal code upconsultando el código postal |
resolved | endereç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 |
manualEntry | falhou 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 |
error | nã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
| case | value | onde se aplicawhere it appliesdónde se aplica |
|---|---|---|
email | 80 | e-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) |
street | 150 | campo de rua + truncagem do retorno do CEPstreet field + truncation of the postal-code resultcampo de calle + truncado del resultado del código postal |
district | 35 | campo 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
| case | wireValue | i18n 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
| case | label (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
| case | wireValue | transactionValue | campo 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
| case | wireValue | wireAbbreviation | i18n 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
| case | wireValue | label |
|---|---|---|
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
| case | label | isoCode |
|---|---|---|
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
| case | o que o modal mostrawhat the modal showsqué muestra el modal |
|---|---|
idle | pergunta de confirmação (Não / Sim)confirmation question (No / Yes)pregunta de confirmación (No / Sí) |
submitting | botão em carregamento; fechar e dispensar bloqueadosloading button; close and dismiss blockedbotón cargando; cerrar y descartar bloqueados |
success | mensagem de sucesso + único botão Fecharsuccess message + a single Close buttonmensaje de éxito + un único botón Cerrar |
failure | mensagem do erro real (trFailure) + Voltar / Tentar novamentereal error message (trFailure) + Come back / Try againmensaje del error real (trFailure) + Volver / Intentar de nuevo |
CaptureSource 2
| case | uso 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 |
gallery | disponível no serviço, não usado aquiavailable in the service, not used heredisponible en el servicio, no usado aquí |
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étodo | RetornaReturnsDevuelve | UsoUseUso |
|---|---|---|
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étodo | RetornaReturnsDevuelve | UsoUseUso |
|---|---|---|
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étodo | RetornaReturnsDevuelve | UsoUseUso |
|---|---|---|
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étodo | RetornaReturnsDevuelve | UsoUseUso |
|---|---|---|
build({input}) | DispatcherEnvelope | Implementa 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étodo | RetornaReturnsDevuelve | UsoUseUso |
|---|---|---|
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.
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.onDispose (é aqui 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 confirmedStartOfActivityPhotos — a posição na lista é o que define a chave do payload.Moves the pending photo to the end of confirmedStartOfActivityPhotos — the position in the list decides the payload key.Mueve la foto pendiente al final de confirmedStartOfActivityPhotos — la 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étodo | RetornaReturnsDevuelve | O que fazWhat it doesQué hace |
|---|---|---|
setVatNumber({value}) | void | grava 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}) | void | Inscriçã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}) | void | razão sociallegal namerazón social |
setCommercialName({value}) | void | nome 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étodo | RetornaReturnsDevuelve | O que fazWhat it doesQué hace |
|---|---|---|
selectState({geoState}) | void | escolhe 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}) | void | escolhe a cidade da lista do estadopicks the city from the state's listelige la ciudad de la lista del estado |
setStateText({value}) | void | estado/região como texto livre (Chile)state/region as free text (Chile)estado/región como texto libre (Chile) |
setCityText({value}) | void | cidade/comuna como texto livre (Chile)city/comuna as free text (Chile)ciudad/comuna como texto libre (Chile) |
setDistrict({value}) | void | bairro (máx. 35)district (max 35)barrio (máx. 35) |
setAddressLine({value}) | void | rua (máx. 150)street (max 150)calle (máx. 150) |
setNumber({value}) | void | número (concatenado à rua no payload)number (concatenated to the street on the wire)número (concatenado a la calle en el payload) |
setAddressContinue({value}) | void | complementocomplementcomplemento |
setPostalCode({value}) | void | CEP; 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étodo | RetornaReturnsDevuelve | O que fazWhat it doesQué hace |
|---|---|---|
setCellPhone({value}) | void | celular do varejo (obrigatório em todos os mercados)retail mobile (required in every market)celular del PDV (obligatorio en todos los mercados) |
setPhone({value}) | void | telefone 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}) | void | e-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}) | void | subtipo 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}) | void | seleção múltipla de categoriasmulti-selection of categoriesselección múltiple de categorías |
toggleOperatingDay({dayWireValue}) | void | liga/desliga um dia de funcionamentotoggles an operating dayactiva/desactiva un día de funcionamiento |
setOpeningTime({value}) | void | horário de aberturaopening timehorario de apertura |
setClosingTime({value}) | void | horário de fechamentoclosing timehorario de cierre |
setBreakStart({value}) | void | iní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}) | void | fim do intervalo; idembreak end; samefin del intervalo; ídem |
selectSalesmanVisitDay({day}) | void | dia de visita do vendedorsalesman visit daydía de visita del vendedor |
selectDeliveryDay({day}) | void | dia de entrega preferidopreferred delivery daydía de entrega preferido |
selectLocalClassification({classification}) | void | escolhe 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}) | void | opção quando a definição é listaoption when the definition is a picklistopción cuando la definición es lista |
setLocalClassificationInputValue({value}) | void | valor 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}) | void | banner (sfid)banner (sfid)banner (sfid) |
selectPropertyType({propertyType}) | void | tipo de propriedade; vira ownerShipType no payloadproperty type; becomes ownerShipType on the wiretipo de propiedad; pasa a ownerShipType en el payload |
selectKeyAccountType({keyAccountType}) | void | tipo 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}) | void | giro (sfid) → emlov1business type (sfid) → emlov1giro (sfid) → emlov1 |
selectChannel({channel}) | void | canal (sfid) → emlov2channel (sfid) → emlov2canal (sfid) → emlov2 |
setB2BCustomer({value}) | void | interruptor 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}) | void | interruptor 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}) | void | interruptor "é 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 livre → available; em uso → guarda o motivo do backend em emailCheckDetail, marca o erro no campo e zera isOperationalDataFormValid → accountTaken; falha → offline (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 free → available; in use → stores the backend reason in emailCheckDetail, sets the field error and clears isOperationalDataFormValid → accountTaken; failure → offline (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 libre → available; en uso → guarda el motivo del backend en emailCheckDetail, marca el error en el campo y pone isOperationalDataFormValid en falso → accountTaken; falla → offline (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 isContactFormValid → contactTaken.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 isContactFormValid → contactTaken.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 falso → contactTaken.
Setters — rascunho de contatocontact draftborrador de contacto 10
| MétodoMethodMétodo | RetornaReturnsDevuelve | O que fazWhat it doesQué hace |
|---|---|---|
setContactFullName({value}) | void | nome completo (Brasil)full name (Brazil)nombre completo (Brasil) |
setContactFirstName({value}) | void | primeiro 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}) | void | pronome → salutationpronoun → salutationpronombre → salutation |
selectContactPreferredLanguage({language}) | void | idioma preferido → código ISO no payloadpreferred language → ISO code on the wireidioma preferido → código ISO en el payload |
selectContactRole({role}) | void | função da pessoathe person's rolefunción de la persona |
setContactCellPhone({value}) | void | celular do contato (validado por mercado)contact mobile (validated per market)celular del contacto (validado por mercado) |
setContactEmail({value}) | void | e-mail do contato (máx. 80)contact e-mail (max 80)correo del contacto (máx. 80) |
setContactDateOfBirth({value}) | void | data 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}) | void | marca 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
| GrupoGroupGrupo | CamposFieldsCampos |
|---|---|
| Tipo e configuraçãoType and configurationTipo y configuración | availableTypes · selectedType · requiresDocumentValidation · postalCodeAutoComplete · checksAccountEmailUniqueness · checksContactEmailUniqueness · requiresB2bCustomerForContacts · allowsStateRegistrationExemption · legalEntityFieldsByType · addressFieldsByType · operationalDataFieldsByType · contactFieldsByType · documentRequirementsByType · startOfActivityDocumentsByType |
| Documentos e fotosDocuments and photosDocumentos y fotos | expandedDocumentRequirementIds · confirmedStartOfActivityPhotos · pendingStartOfActivityPhoto · isCapturingStartOfActivityPhoto |
| Dados do varejoRetail dataDatos del comercio | vatNumber · outletName · commercialName · stateRegistration · vatErrorKey · stateRegistrationErrorKey · isLegalEntityFormValid |
| EndereçoAddressDirección | geographicalHierarchy · selectedState · selectedCity · stateText · cityText · district · addressLine · addressContinue · number · postalCode · postalCodeErrorKey · addressLookupStatus · isAddressFormValid |
| Listas de apoioSupporting listsListas de apoyo | outletSubtypes · categoriesForSale · localClassificationDefinitions · contactRoles · languagePreferences · banners · giroOptions · canalOptions · propertyTypes · keyAccountTypes · referenceDataLastSyncAt |
| Dados operacionaisOperational dataDatos operacionales | cellPhone · 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 correo | isCheckingEmail · emailCheckDetail · isCheckingContactEmail · contactEmailCheckDetail |
| Equipe e rascunhoTeam and draftEquipo y borrador | contacts · contactFirstName · contactLastName · contactFullName · contactPronoun · contactPreferredLanguage · contactRole · contactCellPhone · contactEmail · contactDateOfBirth · contactIsMainContact · contactCellPhoneErrorKey · contactEmailErrorKey · isContactFormValid · editingContactIndex · contactDraftVersion |
| EnvioSubmissionEnvío | submissionStatus · 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
| campofieldcampo | tipotypetipo | default |
|---|---|---|
document | String | "" |
isValidating | bool | false |
inputError | TranslationConstants? | null |
resultKey | TranslationConstants? | null |
resultDetail | String | "" |
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.
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
- CustomPullToRefresh → refresh()
- 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 · returnsbool?— only "Yes" proceedssolo cuando el mercado permite exención y el campo está vacío · devuelvebool?— solo "Sí" avanza
- NewRetailStateRegistrationExemptModalContent modal · só quando o mercado permite isenção e o campo está vazio · devolve
- 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 / setBreakEndreturnsDateTime?→ setBreakStart / setBreakEnddevuelveDateTime?→ setBreakStart / setBreakEnd
- CustomTimePickerModalContent modal · devolve
- _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 bycontactDraftVersion; side-by-side pairs (pronoun+language, role+main)re-clavado porcontactDraftVersion; 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 → returnsbool?; only "Yes" appliesya existe otro principal → devuelvebool?; solo "Sí" aplica
- ConectaModal.showConfirmation modal · já existe outro principal → devolve
- 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 → returnsDateTime?fecha máxima = hoy menos 18 años → devuelveDateTime?
- CustomCalendarModalContent modal · data máxima = hoje menos 18 anos → devolve
- 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?" →
truesalva e limpa;falsesalva e volta; dispensar não salva"do you want to add another contact?" →truesaves and clears;falsesaves and goes back; dismissing saves nothing"¿deseas agregar otro contacto?" →trueguarda y limpia;falseguarda 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 withisEditing: true; a card with no visible field is not rendered5 tarjetas (comercio, dirección, operacional, equipo, fotos), cada una con "Editar" → la misma page conisEditing: 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:
Comportamento do fluxo por mercadoFlow behavior per marketComportamiento del flujo por mercado
Chave do newRetailConfignewRetailConfig keyClave del newRetailConfig | BR | CL | ZA | AR | PY | PE |
|---|---|---|---|---|---|---|
retailTypes | individual · business | generic | generic | — | — | — |
requiresDocumentValidation | x | false | false | — | — | — |
checksAccountEmailUniqueness | false | x | x | — | — | — |
checksContactEmailUniqueness | false | x | x | — | — | — |
requiresB2bCustomerForContacts | false | false | x | — | — | — |
allowsStateRegistrationExemption | x | false | false | — | — | — |
postalCodeAutoComplete | x | false | false | — | — | — |
documentRequirementsByType | 1 perfil por tipo1 profile per type1 perfil por tipo | 1 perfil1 profile1 perfil | 4 perfis4 profiles4 perfiles | — | — | — |
startOfActivityDocumentsByType | 3 (física) / 4 (jurídica), todas obrigatórias3 (individual) / 4 (business), all mandatory3 (natural) / 4 (jurídica), todas obligatorias | 1, obrigatória1, mandatory1, obligatoria | 3, só a 1ª obrigatória3, only the 1st mandatory3, solo la 1ª obligatoria | — | — | — |
legalEntityFieldsByType | 3 (física) / 4 (jurídica)3 (individual) / 4 (business)3 (natural) / 4 (jurídica) | 3 | 3 | — | — | — |
addressFieldsByType | 7 | 8 | 6 | — | — | — |
operationalDataFieldsByType | 9 | 17 | 11 | — | — | — |
contactFieldsByType | 7 | 9 | 9 | — | — | — |
wireConfig | 20 chaves20 keys20 claves | 20 chaves20 keys20 claves | 20 chaves20 keys20 claves | 3 chaves3 keys3 claves | 3 chaves3 keys3 claves | 3 chaves3 keys3 claves |
homeConfig → rep_actions → new_account | x | x | x | — | — | — |
menuConfig → new_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.
| ChaveKeyClave | BR | CL | ZA | AR | PY | PE |
|---|---|---|---|---|---|---|
accountRecordTypeId | 0121t000000HzMFAA0 | 0120Y000000BOrCQAW | 0120Y000000BOrCQAW | — | — | — |
contactRecordTypeId | "" | 0120Y000000BOrEQAW | 0120Y000000BOrEQAW | — | — | — |
locationHierarchyId | a0D1t00000276uAEAQ | a0B1n00000Rla8EEAR | a0B4J000009ZhRKUA0 | — | — | — |
paymentMethod | ZG;Z9;ZX | ZE;ZB;ZC;ZI;Z9 | ZH;ZM | — | — | — |
defaultPaymentMethod | ZG | ZE | ZH | — | — | — |
currencyIsoCode | BRL | CLP | ZAR | ARS | PYG | PEN |
language | PT | ES | EN | ES | ES | ES |
mailingCountry | brazil | CHILE | SOUTH AFRICA | argentina | paraguay | peru |
contactPreferredLanguage | Portuguese | Spanish | English | — | — | — |
sendsVatRegistrationNo | false | false | x | — | — | — |
sendsTaxId | x | x | false | — | — | — |
sendsDocumentData | x | x | false | — | — | — |
collectsDirectSales | false | false | x | — | — | — |
userQuotas | "50" | "50" | "5" | — | — | — |
ownerShipType | "" | "" | Independent | — | — | — |
totalSellInValPerAnnum | "" | "1" | "1" | — | — | — |
isTaxRequired | "false" | "true" | "false" | — | — | — |
contactB2bStatus | Inactive | Active | Inactive | — | — | — |
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
| CampoFieldCampo | BR · individual | BR · business | CL · generic | ZA · generic |
|---|---|---|---|---|
document | x req ro | x req ro | x req | x req |
state_registration | — | x opt | — | — |
legal_name | x req | x req | x req | x req |
trade_name | x req | x req | x req | x 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
| CampoFieldCampo | BR · individual | BR · business | CL · generic | ZA · generic |
|---|---|---|---|---|
address_search | — | — | x opt | — |
postal_code | x req | x req | x opt | x req |
street | x req | x req | x req | x req |
number | x req | x req | x opt | — |
complement | x opt | x opt | x opt | x opt |
neighborhood | x req | x req | x opt | x opt |
city | x req | x req | x req free | x req |
state | x req | x req | x req free | x 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
| CampoFieldCampo | BR · individual | BR · business | CL · generic | ZA · generic |
|---|---|---|---|---|
cell_phone | x req | x req | x req | x req |
phone | x opt | x opt | x opt | x opt |
email | x req | x req | x req | x req |
outlet_subtype | x req | x req | x req | x req |
categories_for_sale | x req | x req | x opt | x opt |
operating_days | x req | x req | x opt | x opt |
business_interval | — | — | x opt | — |
salesman_visit_day | x opt | x opt | x opt | x opt |
delivery_day | x req | x req | x opt | x opt |
local_classification | — | — | false off | x req |
banner | — | — | x req | — |
property_type | — | — | x req | — |
key_account_type | — | — | x opt | — |
giro | — | — | x req | — |
channel | — | — | x req | — |
b2b_customer | — | — | x opt | x opt |
direct_sales | — | — | false off | x opt |
network_parent | x opt | x 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
| CampoFieldCampo | BR · individual | BR · business | CL · generic | ZA · generic |
|---|---|---|---|---|
pronoun | x req | x req | x req | x req |
language_preference | — | — | x req | x req |
full_name | x req | x req | — | — |
first_name | — | — | x req | x req |
last_name | — | — | x req | x req |
role | x req | x req | x req | x req |
main_contact | x opt | x opt | x opt | x opt |
cell_phone | x req | x req | x req | x req |
email | x req | x req | x req | x req |
date_of_birth | x req | x req | x opt | x 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.
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.
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.
Á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_accountna Home — o fluxo é inalcançável.They have nonew_accounttile on Home — the flow is unreachable.No tienen el atajonew_accounten el Home — el flujo es inalcanzable. - O
newRetailConfigexiste, mas só com 3 chaves dewireConfig(moeda, idioma, país de correspondência) — sem tipos e sem nenhuma lista de campos.newRetailConfigexists, but with only 3wireConfigkeys (currency, language, mailing country) — no types and no field lists at all.ElnewRetailConfigexiste, pero solo con 3 claves dewireConfig(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
retailNewestá habilitada apenas para BR, CL e ZA.TheretailNewtransaction is enabled for BR, CL and ZA only.La transacciónretailNewestá 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
emailChecknão implementado no backend. A stack do app está completa; a chamada real respondeUNIMPLEMENTEDe bloqueia o representante nos mercados com a checagem ligada. Confirmações pendentes: necessidade doresourceSfid, busca case-insensitive, e se registros inativos contam como "em uso".TheemailCheckRPC is not implemented in the backend. The app stack is complete; the real call answersUNIMPLEMENTEDand blocks the rep in markets with the check on. Pending confirmations: whetherresourceSfidis needed, case-insensitive search, and whether inactive records count as "in use".El RPCemailCheckno está implementado en el backend. La stack de la app está completa; la llamada real respondeUNIMPLEMENTEDy bloquea al representante en los mercados con la verificación activa. Confirmaciones pendientes: necesidad delresourceSfid, búsqueda case-insensitive, y si los registros inactivos cuentan como "en uso". - Sem doc de transação. A transação
AccountContactUploadAPIainda 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. TheAccountContactUploadAPItransaction 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ónAccountContactUploadAPIaú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_accountno menu — decidir se entra ou se o código sai.Inert side-menu shortcut. The code exists, but no market declaresnew_accountin 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 declaranew_accounten 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 andcontactPositionrules), 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 decontactPosition), 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).