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

Envio de contato da equipeStaff contact uploadEnvío de contacto del equipo

A transação de escrita que envia ao backend o cadastro, a edição ou a exclusão de um contato (membro da equipe) de um varejo. Um único builder monta o payload ContactDetails para as três ações — criar, atualizar e excluir — que compartilham a mesma estrutura e divergem só em poucos campos. Toda a construção do contrato wire vive no builder. The write transaction that sends the backend the creation, edit or deletion of a contact (staff member) of a retail. A single builder assembles the ContactDetails payload for the three actions — create, update and delete — which share the same structure and differ only in a handful of fields. All wire-contract construction lives in the builder. La transacción de escritura que envía al backend el alta, la edición o la eliminación de un contacto (miembro del equipo) de un punto de venta. Un único builder arma el payload ContactDetails para las tres acciones — crear, actualizar y eliminar — que comparten la misma estructura y difieren solo en unos pocos campos. Toda la construcción del contrato wire vive en el builder.

PúblicoAudiencePúblico
QA · Suporte · Produto · DevQA · Support · Product · DevQA · Soporte · Producto · Dev
CamadaLayerCapa
Escrita · DispatcherWrite · DispatcherEscritura · Dispatcher
RelacionadoRelatedRelacionado
AtualizadoUpdatedActualizado
17/08/20262026-08-17
Disponível emAvailable inDisponible en BR CL ZA
01

O que é e quando aconteceWhat it is and when it happensQué es y cuándo ocurre

Quando o representante de vendas cadastra, edita ou exclui um contato de um varejo — o dono, um gerente, um balconista, o contato principal —, o app envia essa mudança ao backend por esta transação. É o momento em que a alteração feita na tela de equipe sai do dispositivo e passa a valer no sistema (Salesforce). O contato é uma pessoa ligada ao varejo: nome, telefone, e-mail, função, idioma preferido e se é o contato principal. When the sales rep registers, edits or deletes a contact of a retail — the owner, a manager, a clerk, the main contact —, the app sends that change to the backend through this transaction. It's the moment the change made on the staff screen leaves the device and takes effect in the system (Salesforce). A contact is a person tied to the retail: name, phone, email, role, preferred language and whether they are the main contact. Cuando el representante de ventas da de alta, edita o elimina un contacto de un punto de venta — el dueño, un gerente, un dependiente, el contacto principal —, la app envía ese cambio al backend por esta transacción. Es el momento en que el cambio hecho en la pantalla de equipo sale del dispositivo y pasa a valer en el sistema (Salesforce). Un contacto es una persona ligada al punto de venta: nombre, teléfono, correo, función, idioma preferido y si es el contacto principal.

Existem três ações, escolhidas automaticamente pelo que o rep faz na tela:There are three actions, chosen automatically by what the rep does on screen:Existen tres acciones, elegidas automáticamente por lo que el rep hace en pantalla:

CriarCreateCrear

Um contato novo é adicionado ao varejo. O envio vai sem identificador do contato — o backend cria o registro.A new contact is added to the retail. The send goes without a contact id — the backend creates the record.Se agrega un contacto nuevo al punto de venta. El envío va sin identificador del contacto — el backend crea el registro.

AtualizarUpdateActualizar

Um contato existente é editado. O envio identifica o contato e atualiza seus dados.An existing contact is edited. The send identifies the contact and updates its data.Se edita un contacto existente. El envío identifica el contacto y actualiza sus datos.

ExcluirDeleteEliminar

Um contato é removido/inativado. O envio marca o registro como inativo.A contact is removed/deactivated. The send marks the record as inactive.Se elimina/inactiva un contacto. El envío marca el registro como inactivo.

Escolha automáticaAutomatic choiceElección automática O rep não escolhe a ação por nome: ela é decidida pelo app — tocar em salvar num contato novo cria; salvar num contato existente atualiza; o botão de excluir exclui. O gesto é sempre o mesmo — preencher e salvar. The rep doesn't pick the action by name: the app decides it — tapping save on a new contact creates; saving an existing contact updates; the delete button deletes. The gesture is always the same — fill in and save. El rep no elige la acción por nombre: la decide la app — tocar guardar en un contacto nuevo crea; guardar un contacto existente actualiza; el botón de eliminar elimina. El gesto es siempre el mismo — completar y guardar.

02

Fluxo de telas que disparaScreen flow that fires itFlujo de pantallas que lo dispara

A transação é o último passo da edição de um contato. As telas pertencem à feature de Gerenciar equipe; aqui só situamos onde o envio acontece:The transaction is the last step of editing a contact. The screens belong to the Manage staff feature; here we only place where the send happens:La transacción es el último paso de la edición de un contacto. Las pantallas pertenecen a la feature de Gestionar equipo; aquí solo situamos dónde ocurre el envío:

  1. Detalhe da visita → Gerenciar equipeVisit detail → Manage staffDetalle de la visita → Gestionar equipoA partir de uma visita ao varejo, o rep abre a tela de equipe, que lista os contatos e os balconistas.From a retail visit, the rep opens the staff screen, which lists contacts and clerks.Desde una visita al punto de venta, el rep abre la pantalla de equipo, que lista los contactos y los dependientes.
  2. Adicionar ou tocar num contatoAdd or tap a contactAgregar o tocar un contactoTocar em adicionar abre o formulário em modo criação; tocar num contato da lista abre em modo edição.Tapping add opens the form in create mode; tapping a contact in the list opens it in edit mode.Tocar agregar abre el formulario en modo creación; tocar un contacto de la lista lo abre en modo edición.
  3. Preencher o formulário do contatoFill the contact formCompletar el formulario del contactoNome, telefone, e-mail, função, idioma, se é o contato principal — os campos visíveis variam por mercado.Name, phone, email, role, language, whether it's the main contact — the visible fields vary by market.Nombre, teléfono, correo, función, idioma, si es el contacto principal — los campos visibles varían por mercado.
  4. Salvar → confirmar → esta transaçãoSave → confirm → this transactionGuardar → confirmar → esta transacciónAo salvar, um modal pede confirmação; ao confirmar, o app dispara o Envio de contato. É este toque que aciona a transação (criação ou atualização).On save, a modal asks for confirmation; on confirm, the app fires the Staff contact upload. This tap is what triggers the transaction (create or update).Al guardar, un modal pide confirmación; al confirmar, la app dispara el Envío de contacto. Este toque es lo que activa la transacción (creación o actualización).
  5. Excluir → confirmar → esta transaçãoDelete → confirm → this transactionEliminar → confirmar → esta transacciónAo editar um contato existente, o botão de excluir (com confirmação) dispara a mesma transação, na ação de exclusão.When editing an existing contact, the delete button (with confirmation) fires the same transaction, in the delete action.Al editar un contacto existente, el botón de eliminar (con confirmación) dispara la misma transacción, en la acción de eliminación.

Visita precisa estar iniciadaVisit must be startedLa visita debe estar iniciada Criar, editar ou excluir um contato só é permitido com a visita iniciada — há uma checagem antes de abrir o formulário. Sem visita iniciada, o rep é avisado e a ação não segue. Creating, editing or deleting a contact is only allowed with the visit started — there's a check before opening the form. Without a started visit, the rep is warned and the action doesn't proceed. Crear, editar o eliminar un contacto solo se permite con la visita iniciada — hay una verificación antes de abrir el formulario. Sin visita iniciada, se avisa al rep y la acción no sigue.

03

Depois do envioAfter sendingDespués del envío

Confirmação ao repConfirmation to the repConfirmación al rep
Quando o backend aceita, o rep vê um aviso de sucesso e volta para a tela de equipe; o contato criado/editado/excluído reflete a mudança.When the backend accepts it, the rep sees a success notice and returns to the staff screen; the created/edited/deleted contact reflects the change.Cuando el backend lo acepta, el rep ve un aviso de éxito y vuelve a la pantalla de equipo; el contacto creado/editado/eliminado refleja el cambio.
Sem internetOfflineSin internet
Diferente do pedido, o envio de contato não é enfileirado quando offline: precisa de conexão para completar. Sem rede, o envio falha e o rep é avisado — a mudança pode ser reenviada quando a conexão voltar.Unlike an order, a contact upload is not queued when offline: it needs a connection to complete. Without network the send fails and the rep is warned — the change can be resent when the connection returns.A diferencia del pedido, el envío de contacto no se encola cuando está offline: necesita conexión para completar. Sin red el envío falla y se avisa al rep — el cambio puede reenviarse cuando vuelva la conexión.
Acompanhar o envioTracking the sendSeguir el envío
O status técnico do despacho (enviado, com erro) fica registrado no histórico de despachos / central de dados do app — útil para o suporte investigar um envio.The dispatch's technical status (sent, errored) is recorded in the app's dispatch history / data center — useful for support to investigate a send.El estado técnico del despacho (enviado, con error) queda registrado en el historial de despachos / centro de datos de la app — útil para que soporte investigue un envío.
04

Visão técnicaTechnical overviewVisión técnica

Envio de contato da equipe é a transação de saída que persiste um contato de varejo no backend (Salesforce). É disparada pelo fluxo de Gerenciar equipe (feature staff_details) quando o representante de vendas cria, edita ou exclui um contato. O único item enviado é o objeto ContactDetails. Staff contact upload is the outbound transaction that persists a retail contact in the backend (Salesforce). It's fired by the Manage staff flow (feature staff_details) when the sales rep creates, edits or deletes a contact. The only item sent is the ContactDetails object. Envío de contacto del equipo es la transacción de salida que persiste un contacto de punto de venta en el backend (Salesforce). Se dispara desde el flujo de Gestionar equipo (feature staff_details) cuando el representante de ventas crea, edita o elimina un contacto. El único ítem enviado es el objeto ContactDetails.

Um builder, 3 açõesOne builder, 3 actionsUn builder, 3 acciones

Um único builder cobre criar, atualizar e excluir. A ação chega no input como ContactUploadAction; não há variante de serviceName.A single builder covers create, update and delete. The action arrives on the input as ContactUploadAction; there's no serviceName variant.Un único builder cubre crear, actualizar y eliminar. La acción llega en el input como ContactUploadAction; no hay variante de serviceName.

Contrato dirigido por EMCEMC-driven contractContrato dirigido por EMC

Quais campos vão no payload é decidido por StaffConfig (End Market Configuration): CPID, método de contato preferido, designação e idioma são condicionais por mercado.Which fields go in the payload is decided by StaffConfig (End Market Configuration): CPID, preferred contact method, designation and language are conditional per market.Qué campos van en el payload lo decide StaffConfig (End Market Configuration): CPID, método de contacto preferido, designación e idioma son condicionales por mercado.

RPC genéricoGeneric RPCRPC genérico

Não há RPC por contato: tudo passa pelo mesmo sendTransaction, com o JSON serializado no campo message e o serviceName como discriminador.There's no per-contact RPC: everything goes through the same sendTransaction, with the JSON serialized into the message field and serviceName as the discriminator.No hay RPC por contacto: todo pasa por el mismo sendTransaction, con el JSON serializado en el campo message y el serviceName como discriminador.

FontesSourcesFuentes BuildAccountContactUploadDispatcherPayloadUseCase + AccountContactUploadDispatcherPayloadInput + DispatcherType.retailUpdate + DispatcherConectaRep.proto. O input carrega entities cruas de domínio (CLAUDE.md §36); o build() constrói todo o wire. BuildAccountContactUploadDispatcherPayloadUseCase + AccountContactUploadDispatcherPayloadInput + DispatcherType.retailUpdate + DispatcherConectaRep.proto. The input carries raw domain entities (CLAUDE.md §36); build() constructs the entire wire. BuildAccountContactUploadDispatcherPayloadUseCase + AccountContactUploadDispatcherPayloadInput + DispatcherType.retailUpdate + DispatcherConectaRep.proto. El input lleva entities crudas de dominio (CLAUDE.md §36); build() construye todo el wire.

05

Transporte gRPCgRPC transportTransporte gRPC

DispatcherConectaRep.proto · proto3 · package mn.bat.conectarep.dispatcher. O serviço expõe um único RPC genérico — não existe mensagem por transação. TODA transação de escrita do app usa este mesmo sendTransaction; o que muda é o serviceName (discriminador) e o JSON dentro de message.The service exposes a single generic RPC — there's no per-transaction message. EVERY write transaction in the app uses this same sendTransaction; what changes is the serviceName (discriminator) and the JSON inside message.El servicio expone un único RPC genérico — no existe mensaje por transacción. TODA transacción de escritura de la app usa este mismo sendTransaction; lo que cambia es el serviceName (discriminador) y el JSON dentro de message.

sendTransactionunary
MétodoMethodMétodo

rpc sendTransaction(InboxTransactionRequest) returns (InboxTransactionReply)

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

Request · InboxTransactionRequest
endpoint
string · #1 · endpoint alvo — type.destination.value (Salesforce)target endpoint — type.destination.value (Salesforce)endpoint destino — type.destination.value (Salesforce)
serviceName
string · #2 · discriminadorRetailerUploadAPIdiscriminatorRetailerUploadAPIdiscriminadorRetailerUploadAPI
dateReference
string · #3 · AAAA-MM-DD do envio (submittedAt)YYYY-MM-DD of the submission (submittedAt)AAAA-MM-DD del envío (submittedAt)
transactionReference
string · #4 · o sfid do varejo (correlação)the retail sfid (correlation)el sfid del punto de venta (correlación)
username
string · #5 · resource.username (sessão)resource.username (session)resource.username (sesión)
message
string · #6 · o payload JSON serializado (a tabela da seção 08)the JSON payload serialized (the table in section 08)el payload JSON serializado (la tabla de la sección 08)
manufacturer
string · #7 · dado do dispositivodevice datadato del dispositivo
model
string · #8 · dado do dispositivodevice datadato del dispositivo
deviceUuid
string · #9 · literal "REP" hoje (ver Pendências)"REP" literal today (see Pending)literal "REP" hoy (ver Pendientes)
deviceVersion
string · #10
tid
int64 · #11 · id de transação para idempotência/replay (0 num envio novo)transaction id for idempotency/replay (0 on a fresh send)id de transacción para idempotencia/replay (0 en un envío nuevo)
Reply · InboxTransactionReply
status
int32 · #1 · status do ack (0 = sucesso)ack status (0 = success)status del ack (0 = éxito)
message
string · #2 · mensagem do backendbackend messagemensaje del backend
transactionId
int32 · #3 · id atribuído pelo backend (correlação)backend-assigned id (correlation)id asignado por el backend (correlación)

Envelope → Request O builder devolve um DispatcherEnvelope (type, serviceName, payload, account, transactionReference, dateReference). O DispatcherGateway serializa payload em JSON para message, copia serviceName/dateReference/transactionReference, resolve o endpoint por type.destination, preenche os campos de dispositivo, o username e o bearer token de auth, e chama o RPC. The builder returns a DispatcherEnvelope (type, serviceName, payload, account, transactionReference, dateReference). The DispatcherGateway serializes payload to JSON into message, copies serviceName/dateReference/transactionReference, resolves the endpoint from type.destination, fills in the device fields, the username and the auth bearer token, and calls the RPC. El builder devuelve un DispatcherEnvelope (type, serviceName, payload, account, transactionReference, dateReference). El DispatcherGateway serializa payload a JSON en message, copia serviceName/dateReference/transactionReference, resuelve el endpoint por type.destination, completa los campos del dispositivo, el username y el bearer token de auth, y llama al RPC.

Para o contato, resendMayDuplicate == true: um reenvio pode duplicar o registro no backend; a idempotência via tid é o que mitiga isso.For the contact, resendMayDuplicate == true: a resend may duplicate the record on the backend; idempotency via tid is what mitigates it.Para el contacto, resendMayDuplicate == true: un reenvío puede duplicar el registro en el backend; la idempotencia vía tid es lo que lo mitiga.

06

serviceName e cruzamentosserviceName & crossoversserviceName y cruces

Uma única transação, sem variantes. O builder resolve type.resolveServiceName(hasPromotion: false)sempre false (contato não tem promoção), então nunca há prefixo Promo_. As três ações (criar/atualizar/excluir) usam o mesmo serviceName e o mesmo DispatcherType.A single transaction, no variants. The builder resolves type.resolveServiceName(hasPromotion: false)always false (a contact has no promotion), so there's never a Promo_ prefix. The three actions (create/update/delete) use the same serviceName and the same DispatcherType.Una única transacción, sin variantes. El builder resuelve type.resolveServiceName(hasPromotion: false)siempre false (un contacto no tiene promoción), así que nunca hay prefijo Promo_. Las tres acciones (crear/actualizar/eliminar) usan el mismo serviceName y el mismo DispatcherType.

DispatcherType serviceName MercadosMarketsMercados DestinoDestinationDestino
retailUpdateRetailerUploadAPIBR · CL · ZASalesforce (default)Salesforce (default)Salesforce (default)

Cross-service 06 ↔ 07Cross-service 06 ↔ 07Cross-service 06 ↔ 07 O serviceName RetailerUploadAPI (e o DispatcherType.retailUpdate) é compartilhado por dois builders: BuildRetailerUploadDispatcherPayloadUseCase — atualização dos dados do varejo, documentada em 06 · Retailer update — e BuildAccountContactUploadDispatcherPayloadUseCase (este doc). São payloads diferentes sob o mesmo serviceName: 06 envia AccountData; 07 envia ContactDetails. The RetailerUploadAPI serviceName (and DispatcherType.retailUpdate) is shared by two builders: BuildRetailerUploadDispatcherPayloadUseCase — retail master-data update, documented in 06 · Retailer update — and BuildAccountContactUploadDispatcherPayloadUseCase (this doc). They are different payloads under the same serviceName: 06 sends AccountData; 07 sends ContactDetails. El serviceName RetailerUploadAPI (y el DispatcherType.retailUpdate) es compartido por dos builders: BuildRetailerUploadDispatcherPayloadUseCase — actualización de los datos del punto de venta, documentada en 06 · Retailer update — y BuildAccountContactUploadDispatcherPayloadUseCase (este doc). Son payloads diferentes bajo el mismo serviceName: 06 envía AccountData; 07 envía ContactDetails.

Colisão de nomes 05 ↔ 07 (falso amigo)Naming collision 05 ↔ 07 (false friend)Colisión de nombres 05 ↔ 07 (falso amigo)

O token "account contact" aparece em dois lugares trocados — leia com atenção, porque o nome engana:The "account contact" token shows up in two swapped places — read carefully, because the name misleads:El token "account contact" aparece en dos lugares cruzados — lea con atención, porque el nombre engaña:

  • O serviceName AccountContactUploadAPI não é desta transação — pertence a DispatcherType.retailNew, o cadastro de novo varejo, documentado em 05 · New retail upload.The serviceName AccountContactUploadAPI is not this transaction — it belongs to DispatcherType.retailNew, the new-retail registration, documented in 05 · New retail upload.El serviceName AccountContactUploadAPI no es esta transacción — pertenece a DispatcherType.retailNew, el alta de nuevo punto de venta, documentado en 05 · New retail upload.
  • Este doc (07) tem o builder nomeado BuildAccountContactUploadDispatcherPayloadUseCase (o nome "account contact"), mas o serviceName real que ele emite é RetailerUploadAPInão AccountContactUploadAPI.This doc (07) has the builder named BuildAccountContactUploadDispatcherPayloadUseCase (the "account contact" name), but the actual serviceName it emits is RetailerUploadAPInot AccountContactUploadAPI.Este doc (07) tiene el builder nombrado BuildAccountContactUploadDispatcherPayloadUseCase (el nombre "account contact"), pero el serviceName real que emite es RetailerUploadAPIno AccountContactUploadAPI.
  • Regra prática: para este contato, o discriminador no fio é sempre RetailerUploadAPI. O nome do builder é histórico e não reflete o serviceName.Rule of thumb: for this contact, the on-the-wire discriminator is always RetailerUploadAPI. The builder name is historical and doesn't reflect the serviceName.Regla práctica: para este contacto, el discriminador en el hilo es siempre RetailerUploadAPI. El nombre del builder es histórico y no refleja el serviceName.
07

Como é disparadoHow it's firedCómo se dispara

A transação é orquestrada pelo fluxo de staff_details (remote-first, §36). O notifier apenas reúne entities cruas e valores injetados; o StaffOrchestrator escolhe a ação; o builder é o dono único de todo join, rename, formatação de data e derivação wire. A cascata:The transaction is orchestrated by the staff_details flow (remote-first, §36). The notifier only gathers raw entities and injected values; StaffOrchestrator picks the action; the builder is the sole owner of every join, rename, date formatting and wire derivation. The cascade:La transacción se orquesta desde el flujo de staff_details (remote-first, §36). El notifier solo reúne entities crudas y valores inyectados; StaffOrchestrator elige la acción; el builder es el dueño único de todo join, rename, formateo de fecha y derivación wire. La cascada:

  • StaffDetailsNotifiersaveContact · deleteContact
    • reúne entities + escolhe açãogathers entities + picks actionreúne entities + elige acciónStaffOrchestrator_sendContact
      • monta input crubuilds raw inputarma input crudoAccountContactUploadDispatcherPayloadInput
        • build()BuildAccountContactUploadDispatcherPayloadUseCasemonta o wireassembles the wirearma el wire
          • devolvereturnsdevuelveDispatcherEnvelope
            • SubmitAccountContactUploadUseCaseDispatcherOrchestratordispatch
              • sendDispatcherRepository
                • serializa + authserialize + authserializa + authDispatcherGateway
                  • sendTransactionBackendgRPC · Salesforce

O input (entities cruas)The input (raw entities)El input (entities crudas)

AccountContactUploadDispatcherPayloadInput (Freezed). Carrega o dado como existe no domínio; nada de formato wire. O relógio chega como submittedAt (via DateTimeUtils.now()); o CPID chega pré-gerado (StaffIdentifierUtils.generateContactCpid()) mas só é emitido sob condição de config.AccountContactUploadDispatcherPayloadInput (Freezed). Carries data as it exists in the domain; no wire shaping. The clock arrives as submittedAt (via DateTimeUtils.now()); the CPID arrives pre-generated (StaffIdentifierUtils.generateContactCpid()) but is only emitted under a config condition.AccountContactUploadDispatcherPayloadInput (Freezed). Lleva el dato como existe en el dominio; nada de formato wire. El reloj llega como submittedAt (vía DateTimeUtils.now()); el CPID llega pre-generado (StaffIdentifierUtils.generateContactCpid()) pero solo se emite bajo una condición de config.

CampoFieldCampoTipoTypeTipoPapelRoleRol
contactContactEntitycontato cru — nome (o builder faz o split), telefone, e-mail, função, idioma, designação, status, b2bPortalStatus, isMainContact, birthdateraw contact — name (the builder splits it), phone, email, role, language, designation, status, b2bPortalStatus, isMainContact, birthdatecontacto crudo — nombre (el builder lo divide), teléfono, correo, función, idioma, designación, status, b2bPortalStatus, isMainContact, birthdate
accountAccountDataEntityvarejo (cru — o builder deriva retailerID, transactionReference e o DispatchAccountEntity a partir de sfid/customerCode/name)retail (raw — the builder derives retailerID, transactionReference and the DispatchAccountEntity from sfid/customerCode/name)punto de venta (crudo — el builder deriva retailerID, transactionReference y el DispatchAccountEntity desde sfid/customerCode/name)
staffConfigStaffConfigflags wire por mercado (do EMC accountEditionConfig.staffConfig): CPID, método de contato, designação+idioma, desativação B2B, recordTypeId, idioma preferidoper-market wire flags (from EMC accountEditionConfig.staffConfig): CPID, contact method, designation+language, B2B deactivation, recordTypeId, preferred languageflags wire por mercado (del EMC accountEditionConfig.staffConfig): CPID, método de contacto, designación+idioma, desactivación B2B, recordTypeId, idioma preferido
actionContactUploadActioncreate · update · delete
mainContactCpidStringCPID pré-gerado; → CPID só quando config.generatesMainContactCpid && contact.isMainContactpre-generated CPID; → CPID only when config.generatesMainContactCpid && contact.isMainContactCPID pre-generado; → CPID solo cuando config.generatesMainContactCpid && contact.isMainContact
submittedAtDateTimerelógio (DateTimeUtils.now()) → dateReferenceclock (DateTimeUtils.now()) → dateReferencereloj (DateTimeUtils.now()) → dateReference
08

Payload (message)

O JSON serializado no campo message do request. Cada tabela abaixo tem 4 colunasCampo JSON · Tipo · Origem do Dado · Regra — e lista toda chave que o build() emite. Campo, Tipo e Origem são código cru; só a Regra é prosa. Um exemplo completo (ZA / atualização) está em transaction_example.json, ao lado deste doc.The JSON serialized into the request's message field. Each table below has 4 columnsJSON field · Type · Data source · Rule — and lists every key that build() emits. Field, Type and Source are raw code; only Rule is prose. A full example (ZA / update) sits in transaction_example.json, next to this doc.El JSON serializado en el campo message del request. Cada tabla abajo tiene 4 columnasCampo JSON · Tipo · Origen del Dato · Regla — y lista toda clave que build() emite. Campo, Tipo y Origen son código crudo; solo la Regla es prosa. Un ejemplo completo (ZA / actualización) está en transaction_example.json, junto a este doc.

Raiz do payloadPayload rootRaíz del payload

Campo JSONTipoTypeTipoOrigem do DadoData sourceOrigen del DatoRegraRuleRegla
ContactDetailsarray[contactDetails]array de um único objeto (o contato deste envio)single-element array (the contact of this send)array de un solo objeto (el contacto de este envío)
  • ContactDetails objeto únicosingle objectobjeto único 18 campos (16 fixos + 2 condicionais)fields (16 fixed + 2 conditional)campos (16 fijos + 2 condicionales)
    Campo JSONTipoTypeTipoOrigem do DadoData sourceOrigen del DatoRegraRuleRegla
    contactIdstringcontact.idcriação → ""; atualização/exclusão → contact.idcreate → ""; update/delete → contact.idcreación → ""; actualización/eliminación → contact.id
    retailerIDstringaccount.sfid
    contactnamestring_splitName(contact.name)primeiro token do nome (ver Regras)first token of the name (see Rules)primer token del nombre (ver Reglas)
    ContactName_LNamestring_splitName(contact.name)resto do nome (após o 1º token)rest of the name (after the 1st token)resto del nombre (tras el 1.º token)
    ContactNumberint | stringPhoneUtils.digitsOnly(contact.phone)só dígitos, como int; vazio ou não parseável → "" (tipo dinâmico)digits only, as int; empty or unparseable → "" (dynamic type)solo dígitos, como int; vacío o no parseable → "" (tipo dinámico)
    contact_titlestringFixo: ""inerte — não há campo de título/saudação no ContactEntityinert — no title/salutation field on ContactEntityinerte — no hay campo de título/saludo en ContactEntity
    CPIDstringinput.mainContactCpidconfig.generatesMainContactCpid && contact.isMainContact ? mainContactCpid : ""config.generatesMainContactCpid && contact.isMainContact ? mainContactCpid : ""config.generatesMainContactCpid && contact.isMainContact ? mainContactCpid : ""
    isPrimaryboolcontact.isMainContact
    DOBstringcontact.birthdateformato yyyy/MM/dd; null → ""yyyy/MM/dd format; null → ""formato yyyy/MM/dd; null → ""
    PreferedLanguagestringconfig.contactPreferredLanguagevalor do EMC (BR "Portuguese" · CL "Spanish" · ZA "English")EMC value (BR "Portuguese" · CL "Spanish" · ZA "English")valor del EMC (BR "Portuguese" · CL "Spanish" · ZA "English")
    PreferedCntMethodstringcontact.preferredMethodOfContact?.labelconfig.sendsPreferredContactMethod → label; senão ""config.sendsPreferredContactMethod → label; else ""config.sendsPreferredContactMethod → label; si no ""
    B2BRolestringcontact.role?.labellabel do ContactRole; null → ""ContactRole label; null → ""label del ContactRole; null → ""
    B2BStatusstring_b2bStatus(...)b2bPortalStatus.wireValue; exclusão + deactivatesB2bStatusOnDelete + ativo → "Inactive" (ver Regras)b2bPortalStatus.wireValue; delete + deactivatesB2bStatusOnDelete + active → "Inactive" (see Rules)b2bPortalStatus.wireValue; eliminación + deactivatesB2bStatusOnDelete + activo → "Inactive" (ver Reglas)
    Statusstringcontact.statusexclusão → "Inactive"; senão contact.status.titleCasedelete → "Inactive"; else contact.status.titleCaseeliminación → "Inactive"; si no contact.status.titleCase
    Emailstringcontact.emailnull → ""null → ""null → ""
    recordTypeIdstringconfig.contactRecordTypeIddo EMC (BR "" · CL/ZA preenchido)from EMC (BR "" · CL/ZA filled)del EMC (BR "" · CL/ZA completado)
    contactDesignationstringcontact.contactDesignation?.labelchave condicional — só quando config.sendsContactDesignationAndLanguagePreference (ZA); null → ""conditional key — only when config.sendsContactDesignationAndLanguagePreference (ZA); null → ""clave condicional — solo cuando config.sendsContactDesignationAndLanguagePreference (ZA); null → ""
    languagePreferencestringcontact.languagePreference?.isoCodechave condicional — só quando config.sendsContactDesignationAndLanguagePreference (ZA); null → LanguagePreference.fallbackIsoCode ("en_US")conditional key — only when config.sendsContactDesignationAndLanguagePreference (ZA); null → LanguagePreference.fallbackIsoCode ("en_US")clave condicional — solo cuando config.sendsContactDesignationAndLanguagePreference (ZA); null → LanguagePreference.fallbackIsoCode ("en_US")

ExemploExampleEjemplo Um payload completo (ZA / atualização, contato principal — mostra as 18 chaves, inclusive as 2 condicionais) está em docs/public/dispatcher/07_staff_contact_upload/transaction_example.json — a forma exata serializada em message (sem wrapper gRPC). A complete payload (ZA / update, main contact — shows all 18 keys, including the 2 conditional ones) is in docs/public/dispatcher/07_staff_contact_upload/transaction_example.json — the exact shape serialized into message (no gRPC wrapper). Un payload completo (ZA / actualización, contacto principal — muestra las 18 claves, incluidas las 2 condicionales) está en docs/public/dispatcher/07_staff_contact_upload/transaction_example.json — la forma exacta serializada en message (sin wrapper gRPC).

09

Regras de negócioBusiness rulesReglas de negocio

Split do nomeName splitDivisión del nombre _splitName → contactname · ContactName_LName
  • contact.name é dividido por espaços (trim + \s+, tokens vazios descartados).contact.name is split on whitespace (trim + \s+, empty tokens dropped).contact.name se divide por espacios (trim + \s+, tokens vacíos descartados).
  • 0 tokens → ("", ""); 1 token → (token, ""); 2+ → primeiro token em contactname, o resto (unido por espaço) em ContactName_LName.0 tokens → ("", ""); 1 token → (token, ""); 2+ → first token in contactname, the rest (space-joined) in ContactName_LName.0 tokens → ("", ""); 1 token → (token, ""); 2+ → primer token en contactname, el resto (unido por espacio) en ContactName_LName.
TelefonePhoneTeléfono ContactNumber
  • PhoneUtils.digitsOnly(contact.phone) remove tudo que não é dígito (null → "").PhoneUtils.digitsOnly(contact.phone) strips every non-digit (null → "").PhoneUtils.digitsOnly(contact.phone) quita todo lo que no sea dígito (null → "").
  • Se ficou vazio → ""; senão int.tryParse(digits) ?? "". O valor é dinâmico: sai como número (int) quando parseável, e como string vazia caso contrário (ex.: número longo demais para int).If empty → ""; else int.tryParse(digits) ?? "". The value is dynamic: it goes out as a number (int) when parseable, and as an empty string otherwise (e.g. a number too long for int).Si quedó vacío → ""; si no int.tryParse(digits) ?? "". El valor es dinámico: sale como número (int) cuando es parseable, y como string vacía en caso contrario (p. ej. número demasiado largo para int).
CPID do contato principalMain-contact CPIDCPID del contacto principal CPID · generatesMainContactCpid

CPID só é preenchido quando ambos: o mercado gera CPID (config.generatesMainContactCpid) e o contato é o principal (contact.isMainContact). Nesse caso vale input.mainContactCpid (gerado pelo StaffIdentifierUtils.generateContactCpid()); senão "". BR nunca gera (config false); CL e ZA geram.CPID is only filled when both: the market generates CPID (config.generatesMainContactCpid) and the contact is the main one (contact.isMainContact). Then it's input.mainContactCpid (generated by StaffIdentifierUtils.generateContactCpid()); otherwise "". BR never generates (config false); CL and ZA do.CPID solo se completa cuando ambos: el mercado genera CPID (config.generatesMainContactCpid) y el contacto es el principal (contact.isMainContact). En ese caso vale input.mainContactCpid (generado por StaffIdentifierUtils.generateContactCpid()); si no "". BR nunca genera (config false); CL y ZA sí.

Status B2B na exclusãoB2B status on deleteStatus B2B en la eliminación _b2bStatus → B2BStatus
  1. basebasebasecontact.b2bPortalStatus ?? unknown, emitido como wireValue (unknown"").contact.b2bPortalStatus ?? unknown, emitted as wireValue (unknown"").contact.b2bPortalStatus ?? unknown, emitido como wireValue (unknown"").
  2. override na exclusãodelete overrideoverride en eliminaciónse deactivatesB2bStatusOnDelete (só ZA) e ação é exclusão e status atual é activeB2bPortalStatus.inactive.wireValue ("Inactive").if deactivatesB2bStatusOnDelete (ZA only) and action is delete and current status is activeB2bPortalStatus.inactive.wireValue ("Inactive").si deactivatesB2bStatusOnDelete (solo ZA) y la acción es eliminación y el status actual es activeB2bPortalStatus.inactive.wireValue ("Inactive").

B2BStatus (status do portal B2B) é distinto de Status (status do registro do contato).B2BStatus (the B2B portal status) is distinct from Status (the contact record status).B2BStatus (status del portal B2B) es distinto de Status (status del registro del contacto).

Status do registroRecord statusStatus del registro Status
  • Exclusão → literal "Inactive".Delete → literal "Inactive".Eliminación → literal "Inactive".
  • Criação/atualização → contact.status.titleCase (status é uma String crua do backend; ex.: "active""Active").Create/update → contact.status.titleCase (status is a raw backend String; e.g. "active""Active").Creación/actualización → contact.status.titleCase (status es una String cruda del backend; p. ej. "active""Active").
Chaves condicionaisConditional keysClaves condicionales contactDesignation · languagePreference
  • As duas chaves só entram no objeto quando config.sendsContactDesignationAndLanguagePreference — hoje só ZA. Em BR e CL o objeto tem 16 chaves; em ZA, 18.Both keys only enter the object when config.sendsContactDesignationAndLanguagePreference — today ZA only. In BR and CL the object has 16 keys; in ZA, 18.Ambas claves solo entran en el objeto cuando config.sendsContactDesignationAndLanguagePreference — hoy solo ZA. En BR y CL el objeto tiene 16 claves; en ZA, 18.
  • languagePreference emite o isoCode do idioma do contato (ex.: "af", "zu"); ausente → "en_US" (fallbackIsoCode). Não confundir com PreferedLanguage, que é o rótulo por mercado do EMC.languagePreference emits the contact language's isoCode (e.g. "af", "zu"); absent → "en_US" (fallbackIsoCode). Not to be confused with PreferedLanguage, the per-market EMC label.languagePreference emite el isoCode del idioma del contacto (p. ej. "af", "zu"); ausente → "en_US" (fallbackIsoCode). No confundir con PreferedLanguage, el label por mercado del EMC.
10

Pendências / roadmapPending / roadmapPendientes / roadmap

O que o builder ainda não preenche ou envia inerte, documentado fiel ao estado atual do código (nunca descrito como se já existisse):What the builder does not yet fill, or ships inert, documented faithfully to the current code state (never described as already existing):Lo que el builder aún no completa, o envía inerte, documentado fiel al estado actual del código (nunca descrito como si ya existiera):

Não portado / pendenteNot ported / pendingNo portado / pendiente

  • contact_title: sempre "" — o ContactEntity do app não modela título/saudação (contraste com o salutation/contactPosition do ContactData em 05 · New retail upload).contact_title: always "" — the app's ContactEntity doesn't model title/salutation (contrast with salutation/contactPosition on the ContactData in 05 · New retail upload).contact_title: siempre "" — el ContactEntity de la app no modela título/saludo (contraste con salutation/contactPosition del ContactData en 05 · New retail upload).
  • ContactNumber: tipo dinâmico (int ou "") no mesmo campo — um número muito longo para int vira "" silenciosamente.ContactNumber: dynamic type (int or "") on the same field — a number too long for int silently becomes "".ContactNumber: tipo dinámico (int o "") en el mismo campo — un número demasiado largo para int pasa a "" silenciosamente.
  • Nomenclatura: o builder é BuildAccountContactUploadDispatcherPayloadUseCase, mas o serviceName emitido é RetailerUploadAPI — o nome do builder não reflete o serviceName (ver seção 06).Naming: the builder is BuildAccountContactUploadDispatcherPayloadUseCase, but the emitted serviceName is RetailerUploadAPI — the builder name doesn't reflect the serviceName (see section 06).Nomenclatura: el builder es BuildAccountContactUploadDispatcherPayloadUseCase, pero el serviceName emitido es RetailerUploadAPI — el nombre del builder no refleja el serviceName (ver sección 06).
  • Transporte: deviceUuid vai como literal "REP" no gateway (pendência conhecida do Dispatcher, comum a todas as transações).Transport: deviceUuid ships as the literal "REP" in the gateway (known Dispatcher pending item, common to all transactions).Transporte: deviceUuid va como literal "REP" en el gateway (pendiente conocido del Dispatcher, común a todas las transacciones).

MercadosMarketsMercados

A disponibilidade da transação vem do DispatcherType.retailUpdate.enabledMarkets — BR/CL/ZA. Não há dispatcher de contato em AR/PY/PE. O conteúdo do payload varia por mercado via StaffConfig (EMC): quais chaves entram e alguns valores fixos.Transaction availability comes from DispatcherType.retailUpdate.enabledMarkets — BR/CL/ZA. There's no contact dispatcher in AR/PY/PE. The payload content varies by market via StaffConfig (EMC): which keys enter and some fixed values.La disponibilidad de la transacción viene de DispatcherType.retailUpdate.enabledMarkets — BR/CL/ZA. No hay dispatcher de contacto en AR/PY/PE. El contenido del payload varía por mercado vía StaffConfig (EMC): qué claves entran y algunos valores fijos.

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

A matriz das flags de StaffConfig que dirigem o payload, por mercado (fonte: EMC):The StaffConfig flag matrix driving the payload, per market (source: EMC):La matriz de flags de StaffConfig que dirigen el payload, por mercado (fuente: EMC):

Flag do StaffConfigStaffConfig flagFlag de StaffConfig BR CL ZA
generatesMainContactCpidfalsexx
sendsPreferredContactMethodfalsefalsex
sendsContactDesignationAndLanguagePreferencefalsefalsex
deactivatesB2bStatusOnDeletefalsefalsex
contactRecordTypeId""xx
contactPreferredLanguagePortugueseSpanishEnglish
BR

Contrato enxutoLean contractContrato reducido 16 chaves (sem contactDesignation/languagePreference). CPID nunca é gerado, PreferedCntMethod vai "", recordTypeId é "", o status B2B não é forçado a Inactive na exclusão. PreferedLanguage = "Portuguese". 16 keys (no contactDesignation/languagePreference). CPID is never generated, PreferedCntMethod goes "", recordTypeId is "", B2B status isn't forced to Inactive on delete. PreferedLanguage = "Portuguese". 16 claves (sin contactDesignation/languagePreference). CPID nunca se genera, PreferedCntMethod va "", recordTypeId es "", el status B2B no se fuerza a Inactive en la eliminación. PreferedLanguage = "Portuguese".

CL

CPID + recordTypeIdCPID + recordTypeIdCPID + recordTypeId 16 chaves. Gera CPID para o contato principal e envia recordTypeId. Ainda sem designação/idioma nem método de contato preferido. PreferedLanguage = "Spanish". 16 keys. Generates CPID for the main contact and sends recordTypeId. Still no designation/language nor preferred contact method. PreferedLanguage = "Spanish". 16 claves. Genera CPID para el contacto principal y envía recordTypeId. Aún sin designación/idioma ni método de contacto preferido. PreferedLanguage = "Spanish".

ZA

Contrato completoFull contractContrato completo 18 chaves — as únicas que adicionam contactDesignation e languagePreference. Também envia PreferedCntMethod, gera CPID e desativa o status B2B na exclusão (deactivatesB2bStatusOnDelete). PreferedLanguage = "English". 18 keys — the only ones that add contactDesignation and languagePreference. Also sends PreferedCntMethod, generates CPID and deactivates the B2B status on delete (deactivatesB2bStatusOnDelete). PreferedLanguage = "English". 18 claves — las únicas que agregan contactDesignation y languagePreference. También envía PreferedCntMethod, genera CPID y desactiva el status B2B en la eliminación (deactivatesB2bStatusOnDelete). PreferedLanguage = "English".

AR · PY · PE Existem como mercados do app (config PANGEA mínima), mas não têm dispatcher de contatoretailUpdate.enabledMarkets não os lista. A edição de contato não é disparada nesses mercados. They exist as app markets (minimal PANGEA config), but have no contact dispatcherretailUpdate.enabledMarkets doesn't list them. Contact editing is not fired in these markets. Existen como mercados de la app (config PANGEA mínima), pero no tienen dispatcher de contactoretailUpdate.enabledMarkets no los lista. La edición de contacto no se dispara en estos mercados.