Insights de concorrênciaCompetitor insightsInsights de competencia
A transação de escrita que envia ao backend um registro de ação da concorrência observada durante uma visita — empresa concorrente, atividade, período, descrição e fotos. Um único builder monta um payload JSON plano (sem variantes, sem arrays aninhados). É a única transação do app roteada para o destino competitor. Existe só na África do Sul.
The write transaction that sends the backend a competitor-action record observed during a visit — competitor company, activity, period, description and photos. A single builder assembles a flat JSON payload (no variants, no nested arrays). It's the only transaction in the app routed to the competitor destination. Exists in South Africa only.
La transacción de escritura que envía al backend un registro de acción de la competencia observada durante una visita — empresa competidora, actividad, período, descripción y fotos. Un único builder arma un payload JSON plano (sin variantes, sin arrays anidados). Es la única transacción de la app enrutada al destino competitor. Existe solo en Sudáfrica.
O que é e quando aconteceWhat it is and when it happensQué es y cuándo ocurre
Quando o representante de vendas registra uma ação da concorrência dentro de uma visita, o app envia esse registro ao backend por esta transação. É o momento em que o formulário de Insights de concorrência vira um registro de verdade: sai do dispositivo e passa a existir no sistema. O rep reporta o que viu no ponto de venda — uma promoção de um concorrente, uma troca de display, um combo de preço — informando a empresa, a atividade, o período, uma descrição e de 1 a 3 fotos. When the sales rep records a competitor action inside a visit, the app sends that record to the backend through this transaction. It's the moment the Competitor insights form becomes a real record: it leaves the device and starts to exist in the system. The rep reports what was seen at the point of sale — a competitor's promotion, a display swap, a price combo — providing the company, the activity, the period, a description and 1 to 3 photos. Cuando el representante de ventas registra una acción de la competencia dentro de una visita, la app envía ese registro al backend por esta transacción. Es el momento en que el formulario de Insights de competencia se convierte en un registro real: sale del dispositivo y pasa a existir en el sistema. El rep reporta lo que vio en el punto de venta — una promoción de un competidor, un cambio de display, un combo de precio — informando la empresa, la actividad, el período, una descripción y de 1 a 3 fotos.
Não há variantes: uma única forma de envio, sempre a mesma. Cada envio é um registro independente — o app não guarda histórico na tela nem edita um registro já enviado.There are no variants: a single send shape, always the same. Each send is an independent record — the app keeps no on-screen history and does not edit an already-sent record.No hay variantes: una única forma de envío, siempre la misma. Cada envío es un registro independiente — la app no guarda historial en pantalla ni edita un registro ya enviado.
Não confundirDon't confuseNo confundir Insights de concorrência (ZA) é uma feature distinta do tile Ações de concorrência do Brasil, que abre a tela de Pesquisas filtrada e usa outra transação. Aqui trata-se só do formulário sul-africano. Competitor insights (ZA) is a distinct feature from Brazil's Competitor actions tile, which opens the filtered Surveys screen and uses a different transaction. This doc is only about the South African form. Insights de competencia (ZA) es una feature distinta del tile Acciones de competencia de Brasil, que abre la pantalla de Encuestas filtrada y usa otra transacción. Este doc trata solo del formulario sudafricano.
Fluxo de telas que disparaScreen flow that fires itFlujo de pantallas que lo dispara
A transação é o último passo do registro de um insight. As telas do caminho pertencem à feature de Insights de concorrência; aqui só situamos onde o envio acontece:The transaction is the last step of recording an insight. The screens along the way belong to the Competitor insights feature; here we only place where the send happens:La transacción es el último paso del registro de un insight. Las pantallas del camino pertenecen a la feature de Insights de competencia; aquí solo situamos dónde ocurre el envío:
- Detalhe da visitaVisit detailDetalle de la visitaDa lista de Visitas, o rep entra no detalhe do varejo e toca no tile Competitor Insights na grade de ferramentas (só aparece na África do Sul). A visita precisa estar iniciada.From the Visits list, the rep opens the retail's detail and taps the Competitor Insights tile in the tools grid (shown only in South Africa). The visit must be started.Desde la lista de Visitas, el rep abre el detalle del punto de venta y toca el tile Competitor Insights en la grilla de herramientas (solo aparece en Sudáfrica). La visita debe estar iniciada.
- Formulário do insightInsight formFormulario del insightUma única tela em branco: escolhe a empresa concorrente e a atividade, define data inicial e final, escreve a descrição, captura de 1 a 3 fotos e pode marcar como Crítico.A single blank screen: picks the competitor company and the activity, sets start and end dates, writes the description, captures 1 to 3 photos and can flag it Critical.Una única pantalla en blanco: elige la empresa competidora y la actividad, define fecha inicial y final, escribe la descripción, captura de 1 a 3 fotos y puede marcarlo como Crítico.
- Enviar → esta transaçãoSend → this transactionEnviar → esta transacciónO botão Enviar só habilita com empresa, atividade, as duas datas, descrição não vazia e ao menos uma foto. Ao tocar, o app dispara esta transação — sem modal de confirmação.The Send button only enables with company, activity, both dates, a non-empty description and at least one photo. On tap, the app fires this transaction — with no confirmation modal.El botón Enviar solo se habilita con empresa, actividad, las dos fechas, descripción no vacía y al menos una foto. Al tocar, la app dispara esta transacción — sin modal de confirmación.
Depois do envioAfter sendingDespués del envío
- Confirmação ao repConfirmation to the repConfirmación al rep
- Quando o backend aceita, aparece um aviso verde e a tela volta automaticamente para o Detalhe da visita. Não fica histórico na tela — cada abertura é um formulário novo em branco.When the backend accepts it, a green notice appears and the screen returns automatically to the Visit detail. No on-screen history remains — each opening is a fresh blank form.Cuando el backend lo acepta, aparece un aviso verde y la pantalla vuelve automáticamente al Detalle de la visita. No queda historial en pantalla — cada apertura es un formulario nuevo en blanco.
- Sem internetOfflineSin internet
- Esta transação não entra na fila offline do app (que hoje só atende o envio de visita). Sem conexão, o envio falha na hora, aparece um aviso vermelho, a tela permanece com tudo preenchido e o registro fica marcado como erro — não como pendente. Não é reenviado sozinho quando a rede volta.This transaction does not enter the app's offline queue (which today serves only the visit upload). Offline, the send fails immediately, a red notice appears, the screen stays with everything filled, and the record is marked as an error — not as pending. It is not resent on its own when the connection returns.Esta transacción no entra en la cola offline de la app (que hoy solo atiende el envío de visita). Sin conexión, el envío falla al instante, aparece un aviso rojo, la pantalla queda con todo completado y el registro se marca como error — no como pendiente. No se reenvía solo cuando vuelve la red.
- Acompanhar / reenviarTracking / resendingSeguir / reenviar
- O status técnico do despacho (enviado, com erro) fica na Central de dados, de onde um envio com erro pode ser reenviado manualmente. O rep também pode simplesmente tocar em Enviar de novo na própria tela.The dispatch's technical status (sent, errored) lives in the Data Center, from which an errored send can be manually resent. The rep can also just tap Send again on the screen itself.El estado técnico del despacho (enviado, con error) está en el Centro de datos, desde donde un envío con error puede reenviarse manualmente. El rep también puede simplemente tocar Enviar de nuevo en la propia pantalla.
Visão técnicaTechnical overviewVisión técnica
Insights de concorrência é a transação de saída que persiste um registro de ação da concorrência no backend. É disparada pelo CompetitorInsightsNotifier quando o representante de vendas conclui o formulário dentro de uma visita. A leitura (listas de empresas e atividades) é cache-only e não faz parte desta transação — aqui só documentamos a escrita.
Competitor insights is the outbound transaction that persists a competitor-action record in the backend. It's fired by the CompetitorInsightsNotifier when the sales rep completes the form inside a visit. The read side (company and activity lists) is cache-only and is not part of this transaction — here we document only the write.
Insights de competencia es la transacción de salida que persiste un registro de acción de la competencia en el backend. Se dispara desde el CompetitorInsightsNotifier cuando el representante de ventas completa el formulario dentro de una visita. La lectura (listas de empresas y actividades) es cache-only y no forma parte de esta transacción — aquí documentamos solo la escritura.
Destino único competitorUnique competitor destinationDestino único competitor
É a única transação do app cujo DispatcherType.destination é competitor — todas as demais usam salesforce, sfbatchapi ou none. Isso vira o campo endpoint do request.It's the only transaction whose DispatcherType.destination is competitor — all others use salesforce, sfbatchapi or none. It becomes the request's endpoint field.Es la única transacción cuyo DispatcherType.destination es competitor — las demás usan salesforce, sfbatchapi o none. Se convierte en el campo endpoint del request.
Payload planoFlat payloadPayload plano
Um único objeto de 13 chaves, sem arrays aninhados de detalhe. Fotos e ids de marca são as únicas listas — e as de marca vão vazias hoje.A single object of 13 keys, with no nested detail arrays. Photos and brand ids are the only lists — and the brand ones ship empty today.Un único objeto de 13 claves, sin arrays anidados de detalle. Fotos e ids de marca son las únicas listas — y las de marca van vacías hoy.
RPC genéricoGeneric RPCRPC genérico
Não há RPC por transação: tudo passa pelo mesmo sendTransaction, com o JSON serializado em message e o serviceName como discriminador.There's no per-transaction RPC: everything goes through the same sendTransaction, with the JSON serialized into message and serviceName as the discriminator.No hay RPC por transacción: todo pasa por el mismo sendTransaction, con el JSON serializado en message y el serviceName como discriminador.
FontesSourcesFuentes
BuildCompetitorInsightsDispatcherPayloadUseCase + CompetitorInsightsDispatcherPayloadInput + DispatcherType.competitorInsights + DispatcherConectaRep.proto. O input carrega entities cruas de domínio (CLAUDE.md §36); o build() constrói todo o wire.
BuildCompetitorInsightsDispatcherPayloadUseCase + CompetitorInsightsDispatcherPayloadInput + DispatcherType.competitorInsights + DispatcherConectaRep.proto. The input carries raw domain entities (CLAUDE.md §36); build() constructs the entire wire.
BuildCompetitorInsightsDispatcherPayloadUseCase + CompetitorInsightsDispatcherPayloadInput + DispatcherType.competitorInsights + DispatcherConectaRep.proto. El input lleva entities crudas de dominio (CLAUDE.md §36); build() construye todo el wire.
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), o endpoint (destino) 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), the endpoint (destination) 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), el endpoint (destino) y el JSON dentro de message.
sendTransactionunaryrpc sendTransaction(InboxTransactionRequest) returns (InboxTransactionReply)
path /mn.bat.conectarep.dispatcher.DispatcherConectaRepService/sendTransaction
InboxTransactionRequestendpointstring· #1 · destino =type.destination.value→"competitor"(exclusivo desta transação)destination =type.destination.value→"competitor"(exclusive to this transaction)destino =type.destination.value→"competitor"(exclusivo de esta transacción)serviceNamestring· #2 · discriminador — sempreCompetitorInsightsUploadAPI(nunca leva prefixoPromo_:hasPromotion: false)discriminator — alwaysCompetitorInsightsUploadAPI(never carries thePromo_prefix:hasPromotion: false)discriminador — siempreCompetitorInsightsUploadAPI(nunca lleva prefijoPromo_:hasPromotion: false)dateReferencestring· #3 ·AAAA-MM-DDdo envio (submittedAt, formato defaultisoDate)YYYY-MM-DDof the submission (submittedAt, defaultisoDateformat)AAAA-MM-DDdel envío (submittedAt, formato defaultisoDate)transactionReferencestring· #4 ·input.accountSfid(correlação)input.accountSfid(correlation)input.accountSfid(correlación)usernamestring· #5 ·resource.usernameresource.usernameresource.usernamemessagestring· #6 · o payload JSON serializado (jsonEncode(envelope.payload)— a tabela da seção 07)the JSON payload serialized (jsonEncode(envelope.payload)— the table in section 07)el payload JSON serializado (jsonEncode(envelope.payload)— la tabla de la sección 07)manufacturerstring· #7 · dado do dispositivodevice datadato del dispositivomodelstring· #8 · dado do dispositivodevice datadato del dispositivodeviceUuidstring· #9 · literal"REP"no gateway (ver Pendências)"REP"literal in the gateway (see Pending)literal"REP"en el gateway (ver Pendientes)deviceVersionstring· #10 · versão do sistemasystem versionversión del sistematidint64· #11 · id de transação para idempotência/replay (envelope.tid, 0 por default)transaction id for idempotency/replay (envelope.tid, 0 by default)id de transacción para idempotencia/replay (envelope.tid, 0 por default)
InboxTransactionReplystatusint32· #1 · status do ack —0ou5= sucesso,1= duplicado, demais = erroack status —0or5= success,1= duplicate, else = errorstatus del ack —0o5= éxito,1= duplicado, demás = errormessagestring· #2 · mensagem do backendbackend messagemensaje del backendtransactionIdint32· #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, usa type.destination.value como endpoint, copia serviceName/dateReference/transactionReference, preenche os campos de dispositivo 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, uses type.destination.value as endpoint, copies serviceName/dateReference/transactionReference, fills in the device fields 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, usa type.destination.value como endpoint, copia serviceName/dateReference/transactionReference, completa los campos del dispositivo y el bearer token de auth, y llama al RPC.
Para esta transação, resendMayDuplicate == true: um reenvio (ex.: pela Central de dados) pode duplicar o registro no backend; a idempotência via tid é o que mitiga isso. Só notificationRead, answerTask e priceCheck são tratados como leves (sem risco de duplicação).For this transaction, resendMayDuplicate == true: a resend (e.g. from the Data Center) may duplicate the record on the backend; idempotency via tid is what mitigates it. Only notificationRead, answerTask and priceCheck are treated as lightweight (no duplication risk).Para esta transacción, resendMayDuplicate == true: un reenvío (p. ej. desde el Centro de datos) puede duplicar el registro en el backend; la idempotencia vía tid es lo que lo mitiga. Solo notificationRead, answerTask y priceCheck se tratan como livianos (sin riesgo de duplicación).
Como é disparadoHow it's firedCómo se dispara
A transação é orquestrada pelo CompetitorInsightsNotifier (remote-first, §36). O notifier apenas reúne entities cruas + valores injetados (resolve o accountSfid da visita e converte as fotos em base64); o builder é o dono único do rename, do trim(), da formatação de data e da derivação do repAccountId. A cascata:The transaction is orchestrated by CompetitorInsightsNotifier (remote-first, §36). The notifier only gathers raw entities + injected values (resolves the visit's accountSfid and converts photos to base64); the builder is the sole owner of the rename, the trim(), date formatting and the repAccountId derivation. The cascade:La transacción se orquesta desde el CompetitorInsightsNotifier (remote-first, §36). El notifier solo reúne entities crudas + valores inyectados (resuelve el accountSfid de la visita y convierte las fotos a base64); el builder es el dueño único del rename, del trim(), del formateo de fecha y de la derivación del repAccountId. La cascada:
- CompetitorInsightsNotifiersubmit()
- reúne entities cruas + injetadosgathers raw entities + injectedreúne entities crudas + inyectadosCompetitorInsightsDispatcherPayloadInput
- build()BuildCompetitorInsightsDispatcherPayloadUseCasemonta o wireassembles the wirearma el wire
- devolvereturnsdevuelveDispatcherEnvelope
- SubmitCompetitorInsightsUseCaseDispatcherOrchestratordispatch()
- _transport.sendDispatcherRepository
- serializa + authserialize + authserializa + authDispatcherGateway
- sendTransactionBackendgRPC
- serializa + authserialize + authserializa + authDispatcherGateway
- _transport.sendDispatcherRepository
- SubmitCompetitorInsightsUseCaseDispatcherOrchestratordispatch()
- devolvereturnsdevuelveDispatcherEnvelope
- build()BuildCompetitorInsightsDispatcherPayloadUseCasemonta o wireassembles the wirearma el wire
- reúne entities cruas + injetadosgathers raw entities + injectedreúne entities crudas + inyectadosCompetitorInsightsDispatcherPayloadInput
O input (entities cruas)The input (raw entities)El input (entities crudas)
CompetitorInsightsDispatcherPayloadInput (Freezed). Carrega o dado como existe no domínio; nada de formato wire. O relógio chega como submittedAt (via DateTimeUtils.now()); as fotos já chegam como base64 (I/O resolvido no notifier via fileCaptureService).CompetitorInsightsDispatcherPayloadInput (Freezed). Carries data as it exists in the domain; no wire shaping. The clock arrives as submittedAt (via DateTimeUtils.now()); photos already arrive as base64 (I/O resolved in the notifier via fileCaptureService).CompetitorInsightsDispatcherPayloadInput (Freezed). Lleva el dato como existe en el dominio; nada de formato wire. El reloj llega como submittedAt (vía DateTimeUtils.now()); las fotos ya llegan como base64 (I/O resuelto en el notifier vía fileCaptureService).
| CampoFieldCampo | TipoTypeTipo | PapelRoleRol |
|---|---|---|
resource | ResourceEntity | representante de vendas (cru — o builder deriva repAccountId)sales rep (raw — the builder derives repAccountId)representante de ventas (crudo — el builder deriva repAccountId) |
accountSfid | String | SFID do varejo (resolvido da visita) → retailerIdretail SFID (resolved from the visit) → retailerIdSFID del punto de venta (resuelto de la visita) → retailerId |
company | CompetitorCompanyEntity | empresa selecionada → companyId (.sfid)selected company → companyId (.sfid)empresa seleccionada → companyId (.sfid) |
activity | CompetitorActivityEntity | atividade selecionada → activityId (.sfid)selected activity → activityId (.sfid)actividad seleccionada → activityId (.sfid) |
description | String | texto livre → description (o builder aplica .trim())free text → description (builder applies .trim())texto libre → description (el builder aplica .trim()) |
startDate | DateTime | data inicial → startDate (dd/MM/yyyy)start date → startDate (dd/MM/yyyy)fecha inicial → startDate (dd/MM/yyyy) |
endDate | DateTime | data final → endDate (dd/MM/yyyy)end date → endDate (dd/MM/yyyy)fecha final → endDate (dd/MM/yyyy) |
imagesBase64 | List<String> | 1 a 3 fotos já em base64 → images1 to 3 photos already in base64 → images1 a 3 fotos ya en base64 → images |
isCritical | bool | toggle Crítico → isCriticalCritical toggle → isCriticaltoggle Crítico → isCritical |
submittedAt | DateTime | relógio (DateTimeUtils.now()) → dateReferenceclock (DateTimeUtils.now()) → dateReferencereloj (DateTimeUtils.now()) → dateReference |
Payload (message)
O JSON serializado no campo message do request. É um objeto plano, embrulhado sob a chave-serviço CompetitorInsightsUploadAPI. A tabela tem 4 colunas — Campo JSON · Tipo · Origem do Dado · Regra — e lista todas as 13 chaves que o build() emite. Campo, Tipo e Origem são código cru; só a Regra é prosa. Um exemplo completo está em transaction_example.json, ao lado deste doc.The JSON serialized into the request's message field. It's a flat object, wrapped under the service key CompetitorInsightsUploadAPI. The table has 4 columns — JSON field · Type · Data source · Rule — and lists all 13 keys that build() emits. Field, Type and Source are raw code; only Rule is prose. A full example sits in transaction_example.json, next to this doc.El JSON serializado en el campo message del request. Es un objeto plano, envuelto bajo la clave-servicio CompetitorInsightsUploadAPI. La tabla tiene 4 columnas — Campo JSON · Tipo · Origen del Dato · Regla — y lista todas las 13 claves que build() emite. Campo, Tipo y Origen son código crudo; solo la Regla es prosa. Un ejemplo completo está en transaction_example.json, junto a este doc.
Raiz do payloadPayload rootRaíz del payload
| Campo JSON | TipoTypeTipo | Origem do DadoData sourceOrigen del Dato | RegraRuleRegla |
|---|---|---|---|
CompetitorInsightsUploadAPI | object | data | chave-serviço única embrulhando o objeto de 13 campos abaixosingle service key wrapping the 13-field object belowclave-servicio única que envuelve el objeto de 13 campos abajo |
CompetitorInsightsUploadAPI objeto únicosingle objectobjeto único 13 camposfieldscampos
Campo JSON TipoTypeTipo Origem do DadoData sourceOrigen del Dato RegraRuleRegla repAccountIdstring Calculadoresource.isPrimaryResource ? primaryResourceSfid : secondaryResourceSfidresource.isPrimaryResource ? primaryResourceSfid : secondaryResourceSfidresource.isPrimaryResource ? primaryResourceSfid : secondaryResourceSfidretailerIdstring input.accountSfidSFID do varejo da visitathe visit's retail SFIDSFID del punto de venta de la visita companyIdstring input.company.sfidempresa concorrente selecionadaselected competitor companyempresa competidora seleccionada activityIdstring input.activity.sfidatividade observada selecionadaselected observed activityactividad observada seleccionada brandIdstring Fixo: ""seleção de marca não implementada (ver Pendências)brand selection not implemented (see Pending)selección de marca no implementada (ver Pendientes) brandVariantIdsarray Fixo: []sempre vazio (não implementado)always empty (not implemented)siempre vacío (no implementado) brandVersionIdsarray Fixo: []sempre vazio (não implementado)always empty (not implemented)siempre vacío (no implementado) descriptionstring input.description.trim()aplicado no builder.trim()applied in the builder.trim()aplicado en el builderstartDatestring input.startDateformato dd/MM/yyyy(dayMonthYearSlash)dd/MM/yyyyformat (dayMonthYearSlash)formatodd/MM/yyyy(dayMonthYearSlash)endDatestring input.endDateformato dd/MM/yyyy(dayMonthYearSlash)dd/MM/yyyyformat (dayMonthYearSlash)formatodd/MM/yyyy(dayMonthYearSlash)imagesarray<string> input.imagesBase641 a 3 fotos em base64 (I/O resolvido no notifier)1 to 3 photos in base64 (I/O resolved in the notifier)1 a 3 fotos en base64 (I/O resuelto en el notifier) answersarray Fixo: []respostas estruturadas não implementadas (ver Pendências)structured answers not implemented (see Pending)respuestas estructuradas no implementadas (ver Pendientes) isCriticalbool input.isCriticalmarcador Crítico do formuláriothe form's Critical flagmarcador Crítico del formulario
Regras de negócioBusiness rulesReglas de negocio
Identidade do repRep identityIdentidad del rep repAccountId
repAccountIdnão éresource.sfid: é o SFID primário (primaryResourceSfid) quandoisPrimaryResource, senão o secundário (secondaryResourceSfid). A derivação mora nobuild()(§36), não no notifier.repAccountIdis notresource.sfid: it's the primary SFID (primaryResourceSfid) whenisPrimaryResource, else the secondary one (secondaryResourceSfid). The derivation lives inbuild()(§36), not the notifier.repAccountIdno esresource.sfid: es el SFID primario (primaryResourceSfid) cuandoisPrimaryResource, si no el secundario (secondaryResourceSfid). La derivación vive enbuild()(§36), no en el notifier.
serviceName & endpoint CompetitorInsightsUploadAPI · competitor
serviceName:type.resolveServiceName(hasPromotion: false)→ sempreCompetitorInsightsUploadAPI. Esta transação nunca carrega promoção, então o prefixoPromo_jamais aparece.serviceName:type.resolveServiceName(hasPromotion: false)→ alwaysCompetitorInsightsUploadAPI. This transaction never carries a promotion, so thePromo_prefix never appears.serviceName:type.resolveServiceName(hasPromotion: false)→ siempreCompetitorInsightsUploadAPI. Esta transacción nunca lleva promoción, así que el prefijoPromo_jamás aparece.endpoint=DispatcherDestination.competitor.value→"competitor". É o únicoDispatcherTypecom esse destino; todos os outros roteiam parasalesforce(default),sfbatchapiounone. O destino é o que roteia a transação no gateway.endpoint=DispatcherDestination.competitor.value→"competitor". It's the onlyDispatcherTypewith that destination; every other routes tosalesforce(default),sfbatchapiornone. The destination is what routes the transaction in the gateway.endpoint=DispatcherDestination.competitor.value→"competitor". Es el únicoDispatcherTypecon ese destino; todos los demás enrutan asalesforce(default),sfbatchapionone. El destino es lo que enruta la transacción en el gateway.
Datas e trimDates & trimFechas y trim startDate · endDate · dateReference · description
startDateeendDatedo payload usamdd/MM/yyyy(DateFormatType.dayMonthYearSlash).startDateandendDatein the payload usedd/MM/yyyy(DateFormatType.dayMonthYearSlash).startDateyendDatedel payload usandd/MM/yyyy(DateFormatType.dayMonthYearSlash).dateReferencedo envelope (nível de transporte, não do payload) usa o formato defaultyyyy-MM-dd(isoDate), a partir desubmittedAt. Mesmos dados, formatos distintos — atenção ao comparar.The envelope'sdateReference(transport level, not payload) uses the defaultyyyy-MM-ddformat (isoDate), fromsubmittedAt. Same source, different formats — mind the comparison.EldateReferencedel envelope (nivel transporte, no del payload) usa el formato defaultyyyy-MM-dd(isoDate), a partir desubmittedAt. Mismo dato, formatos distintos — atención al comparar.description: o builder aplica.trim(). O formulário já garante descrição não vazia antes de habilitar o envio.description: the builder applies.trim(). The form already ensures a non-empty description before enabling the send.description: el builder aplica.trim(). El formulario ya garantiza descripción no vacía antes de habilitar el envío.
Envio, ack e offlineSend, ack & offlineEnvío, ack y offline DispatcherOrchestrator · resendMayDuplicate
- O envio passa pelo
DispatcherOrchestrator.dispatch(). A fila offline só registraDispatcherType.visit; esta transação vai direto ao transporte e, sem rede, o gateway lançaNetworkException→NetworkFailure(falha imediata, gravada como erro no histórico).The send goes throughDispatcherOrchestrator.dispatch(). The offline queue only recordsDispatcherType.visit; this transaction goes straight to transport and, offline, the gateway throwsNetworkException→NetworkFailure(immediate failure, stored as an error in history).El envío pasa porDispatcherOrchestrator.dispatch(). La cola offline solo registraDispatcherType.visit; esta transacción va directo al transporte y, sin red, el gateway lanzaNetworkException→NetworkFailure(falla inmediata, guardada como error en el historial). - Mapeamento do ack (
_statusForAck):status0ou5→ sucesso;1→ duplicado; qualquer outro → erro.Ack mapping (_statusForAck):status0or5→ success;1→ duplicate; anything else → error.Mapeo del ack (_statusForAck):status0o5→ éxito;1→ duplicado; cualquier otro → error. resendMayDuplicate == true: um reenvio manual (Central de dados) pode gerar duplicata no backend; a idempotência viatidmitiga.resendMayDuplicate == true: a manual resend (Data Center) may produce a backend duplicate; idempotency viatidmitigates it.resendMayDuplicate == true: un reenvío manual (Centro de datos) puede generar duplicado en el backend; la idempotencia víatidlo mitiga.
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 implementado / pendenteNot implemented / pendingNo implementado / pendiente
brandId(""),brandVariantIds([]) ebrandVersionIds([]): a seleção de marca/variante/versão não existe no formulário — o contrato wire tem os campos, mas o app nunca os popula.brandId(""),brandVariantIds([]) andbrandVersionIds([]): brand/variant/version selection doesn't exist in the form — the wire contract has the fields, but the app never populates them.brandId(""),brandVariantIds([]) ybrandVersionIds([]): la selección de marca/variante/versión no existe en el formulario — el contrato wire tiene los campos, pero la app nunca los completa.answers: sempre[]— respostas estruturadas (questionário do insight) não implementadas.answers: always[]— structured answers (insight questionnaire) not implemented.answers: siempre[]— respuestas estructuradas (cuestionario del insight) no implementadas.- Fila offline: esta transação não entra na fila offline (só o envio de visita entra hoje). Sem rede, falha na hora e o reenvio é manual pela Central de dados.Offline queue: this transaction does not enter the offline queue (only the visit upload does today). Offline, it fails immediately and the resend is manual via the Data Center.Cola offline: esta transacción no entra en la cola offline (solo el envío de visita lo hace hoy). Sin red, falla al instante y el reenvío es manual por el Centro de datos.
- Transporte:
deviceUuidvai como literal"REP"no gateway (pendência conhecida do Dispatcher, compartilhada por todas as transações).Transport:deviceUuidships as the literal"REP"in the gateway (known Dispatcher pending item, shared by all transactions).Transporte:deviceUuidva como literal"REP"en el gateway (pendiente conocido del Dispatcher, compartido por todas las transacciones).
MercadosMarketsMercados
A disponibilidade da transação vem de DispatcherType.competitorInsights.enabledMarkets = [ZA]. Existe só na África do Sul. BR, CL, AR, PY e PE não têm dispatcher de insights de concorrência.Transaction availability comes from DispatcherType.competitorInsights.enabledMarkets = [ZA]. It exists in South Africa only. BR, CL, AR, PY and PE have no competitor-insights dispatcher.La disponibilidad de la transacción viene de DispatcherType.competitorInsights.enabledMarkets = [ZA]. Existe solo en Sudáfrica. BR, CL, AR, PY y PE no tienen dispatcher de insights de competencia.
Só na África do SulSouth Africa onlySolo Sudáfrica O tile Competitor Insights aparece na grade de ferramentas da visita apenas na África do Sul, e a transação só é habilitada aqui. O envio é o mesmo em qualquer situação — não há variação de payload por sub-região. The Competitor Insights tile appears in the visit's tools grid only in South Africa, and the transaction is enabled only here. The send is the same in every situation — there's no per-sub-region payload variation. El tile Competitor Insights aparece en la grilla de herramientas de la visita solo en Sudáfrica, y la transacción se habilita solo aquí. El envío es el mismo en cualquier situación — no hay variación de payload por sub-región.
Não confundirDon't confuseNo confundir
O Brasil tem o tile Ações de concorrência (competitor_actions), que abre a tela de Pesquisas filtrada — é outra feature e outra transação, não esta. BR não dispara CompetitorInsightsUploadAPI.
Brazil has the Competitor actions tile (competitor_actions), which opens the filtered Surveys screen — a different feature and transaction, not this one. BR does not fire CompetitorInsightsUploadAPI.
Brasil tiene el tile Acciones de competencia (competitor_actions), que abre la pantalla de Encuestas filtrada — es otra feature y otra transacción, no esta. BR no dispara CompetitorInsightsUploadAPI.
CL · AR · PY · PE
Existem como mercados do app, mas não têm dispatcher de insights de concorrência — enabledMarkets lista só ZA. A feature não é renderizada nesses mercados.
They exist as app markets, but have no competitor-insights dispatcher — enabledMarkets lists only ZA. The feature is not rendered in these markets.
Existen como mercados de la app, pero no tienen dispatcher de insights de competencia — enabledMarkets lista solo ZA. La feature no se renderiza en estos mercados.