Envio de resultado de pesquisaSurvey result uploadEnvío de resultado de encuesta
A transação de escrita que envia ao backend as respostas de uma pesquisa respondida pelo representante de vendas dentro de uma visita. Um único builder monta o payload JSON com o cabeçalho do resultado, o detalhe pergunta-a-pergunta e as evidências em foto/documento. Quando há muitas evidências, o envio é fatiado em vários envelopes (até três evidências por envelope), disparados em paralelo. The write transaction that sends to the backend the answers of a survey filled in by the sales rep during a visit. A single builder assembles the JSON payload with the result header, the question-by-question detail and the photo/document evidences. When there are many evidences, the send is split into several envelopes (up to three evidences each), fired in parallel. La transacción de escritura que envía al backend las respuestas de una encuesta respondida por el representante de ventas dentro de una visita. Un único builder arma el payload JSON con el encabezado del resultado, el detalle pregunta por pregunta y las evidencias en foto/documento. Cuando hay muchas evidencias, el envío se divide en varios envelopes (hasta tres evidencias cada uno), disparados en paralelo.
O que é e quando aconteceWhat it is and when it happensQué es y cuándo ocurre
Durante uma visita, o representante de vendas pode responder uma pesquisa sobre aquele varejo — um censo de concorrência, um checklist de encerramento, uma auditoria de preço, uma pesquisa de satisfação. Quando ele finaliza a resposta, o app envia esse resultado ao backend por esta transação. É o momento em que as respostas saem do dispositivo e passam a existir no sistema. During a visit, the sales rep can answer a survey about that retail — a competition census, a closing checklist, a price audit, a satisfaction survey. When they finish the answers, the app sends that result to the backend through this transaction. It's the moment the answers leave the device and start to exist in the system. Durante una visita, el representante de ventas puede responder una encuesta sobre ese punto de venta — un censo de competencia, un checklist de cierre, una auditoría de precio, una encuesta de satisfacción. Cuando termina las respuestas, la app envía ese resultado al backend por esta transacción. Es el momento en que las respuestas salen del dispositivo y pasan a existir en el sistema.
As respostasThe answersLas respuestas
Cada pergunta respondida vira uma linha do resultado — a opção escolhida, o texto digitado, o número ou a data.Each answered question becomes a result line — the chosen option, the typed text, the number or the date.Cada pregunta respondida se vuelve una línea del resultado — la opción elegida, el texto escrito, el número o la fecha.
As evidênciasThe evidencesLas evidencias
Algumas perguntas exigem foto ou documento. As evidências vão junto com o resultado, em blocos de até três arquivos.Some questions require a photo or document. Evidences go along with the result, in blocks of up to three files.Algunas preguntas exigen foto o documento. Las evidencias van junto con el resultado, en bloques de hasta tres archivos.
Completa ou em andamentoComplete or in progressCompleta o en curso
O resultado é marcado como concluído ou em andamento conforme a configuração da pesquisa — algumas fecham no primeiro envio, outras admitem envios parciais.The result is marked complete or in progress per the survey config — some close on the first send, others accept partial sends.El resultado se marca como completo o en curso según la config de la encuesta — algunas cierran en el primer envío, otras admiten envíos parciales.
Sempre dentro de uma visitaAlways inside a visitSiempre dentro de una visita Não existe pesquisa "solta": ela é sempre respondida a partir de uma visita, e o varejo vem dela. Enviar um pedido não está envolvido aqui — esta transação é só sobre pesquisas. There's no standalone survey: it's always answered from within a visit, and the retail comes from it. Sending an order isn't involved here — this transaction is only about surveys. No existe encuesta "suelta": siempre se responde a partir de una visita, y el punto de venta viene de ella. Enviar un pedido no está involucrado aquí — esta transacción es solo sobre encuestas.
Fluxo de telas que disparaScreen flow that fires itFlujo de pantallas que lo dispara
A transação é o último passo do fluxo de resposta de pesquisa. As telas do caminho pertencem à feature de Pesquisas; aqui só situamos onde o envio acontece:The transaction is the last step of the survey-answering flow. The screens along the way belong to the Surveys feature; here we only place where the send happens:La transacción es el último paso del flujo de respuesta de encuesta. Las pantallas del camino pertenecen a la feature de Encuestas; aquí solo situamos dónde ocurre el envío:
- Detalhe da visitaVisit detailDetalle de la visitaCom a visita iniciada, o rep abre a grade de ferramentas e toca em Pesquisas (no Brasil, também por Ações de concorrência ou pelas pendências de encerramento).With the visit started, the rep opens the tools grid and taps Surveys (in Brazil, also via Competition actions or the closing pending items).Con la visita iniciada, el rep abre la grilla de herramientas y toca Encuestas (en Brasil, también por Acciones de competencia o los pendientes de cierre).
- Lista de pesquisasSurvey listLista de encuestasMostra as pesquisas que se aplicam àquele varejo. O rep toca num card para abrir a resposta.Shows the surveys that apply to that retail. The rep taps a card to open the answering flow.Muestra las encuestas que aplican a ese punto de venta. El rep toca una tarjeta para abrir la respuesta.
- Fluxo de respostaAnswering flowFlujo de respuestaUma pergunta por página. Escolher uma opção pode revelar perguntas dependentes; algumas perguntas exigem foto ou documento.One question per page. Choosing an option may reveal dependent questions; some questions require a photo or document.Una pregunta por página. Elegir una opción puede revelar preguntas dependientes; algunas preguntas exigen foto o documento.
- Finalizar → esta transaçãoFinish → this transactionFinalizar → esta transacciónAo tocar em finalizar/enviar na última pergunta, o app dispara o Envio de resultado de pesquisa. É este toque que aciona a transação.Tapping finish/send on the last question fires the Survey result upload. This tap is what triggers the transaction.Al tocar finalizar/enviar en la última pregunta, la app dispara el Envío de resultado de encuesta. Este toque es lo que activa la transacción.
Depois do envioAfter sendingDespués del envío
- Confirmação ao repConfirmation to the repConfirmación al rep
- Quando o backend aceita, o app confirma o envio em tela. Uma pesquisa de resposta única só desaparece da lista quando a próxima sincronização traz o varejo atualizado — o envio em si não marca a pesquisa como respondida no dispositivo.When the backend accepts it, the app confirms the send on screen. A single-answer survey only leaves the list when the next sync brings the retail updated — the send itself does not mark the survey as answered on the device.Cuando el backend lo acepta, la app confirma el envío en pantalla. Una encuesta de respuesta única solo desaparece de la lista cuando la próxima sincronización trae el punto de venta actualizado — el envío en sí no marca la encuesta como respondida en el dispositivo.
- Muitas evidênciasMany evidencesMuchas evidencias
- Se a pesquisa tem muitas fotos/documentos, o envio é dividido em vários blocos (até três arquivos por bloco), enviados em paralelo. O rep não percebe a divisão — para ele é um único envio.If the survey has many photos/documents, the send is split into several blocks (up to three files each), sent in parallel. The rep doesn't notice the split — to them it's a single send.Si la encuesta tiene muchas fotos/documentos, el envío se divide en varios bloques (hasta tres archivos cada uno), enviados en paralelo. El rep no percibe la división — para él es un único envío.
- Sem internetOfflineSin internet
- O envio exige conexão; sem rede, o app bloqueia o despacho e avisa. O status técnico do despacho (enviado, com erro) pode ser acompanhado na central de dados / tracking de despachos — útil para suporte investigar um envio.The send requires a connection; offline, the app blocks the dispatch and warns. The dispatch's technical status (sent, errored) can be followed in the data center / dispatch tracking — useful for support to investigate a send.El envío exige conexión; sin red, la app bloquea el despacho y avisa. El estado técnico del despacho (enviado, con error) puede seguirse en el centro de datos / tracking de despachos — útil para que soporte investigue un envío.
Visão técnicaTechnical overviewVisión técnica
Envio de resultado de pesquisa é a transação de saída que persiste no backend as respostas de uma pesquisa. É disparada pelo SurveyAnswerNotifier quando o representante de vendas finaliza o fluxo de resposta. A leitura das pesquisas é cache-only (proto getSurveys); a escrita não usa esse proto — o resultado vai como JSON pelo Dispatcher. As respostas do rep vivem num sealed class escrito à mão (SurveyAnswerValue) e são convertidas direto em JSON no builder.
Survey result upload is the outbound transaction that persists a survey's answers in the backend. It's fired by SurveyAnswerNotifier when the sales rep finishes the answering flow. Reading surveys is cache-only (proto getSurveys); the write does not use that proto — the result goes as JSON through the Dispatcher. The rep's answers live in a hand-written sealed class (SurveyAnswerValue) and are converted straight to JSON in the builder.
Envío de resultado de encuesta es la transacción de salida que persiste en el backend las respuestas de una encuesta. La dispara SurveyAnswerNotifier cuando el representante de ventas finaliza el flujo de respuesta. La lectura de encuestas es cache-only (proto getSurveys); la escritura no usa ese proto — el resultado va como JSON por el Dispatcher. Las respuestas del rep viven en un sealed class escrito a mano (SurveyAnswerValue) y se convierten directo a JSON en el builder.
Três blocos de payloadThree payload blocksTres bloques de payload
O JSON tem surveyResult (cabeçalho), surveyResultdetails (uma linha por resposta) e evidenceList (arquivos). O builder é o dono único da montagem.The JSON has surveyResult (header), surveyResultdetails (one line per answer) and evidenceList (files). The builder is the sole owner of the assembly.El JSON tiene surveyResult (encabezado), surveyResultdetails (una línea por respuesta) y evidenceList (archivos). El builder es el dueño único del armado.
Split por evidênciasSplit by evidencesSplit por evidencias
buildAll fatia as evidências em blocos de três e devolve um DispatcherEnvelope por bloco — cabeçalho e detalhes repetidos em todos. Sem evidências (ou até três): um envelope só.buildAll slices evidences into blocks of three and returns one DispatcherEnvelope per block — header and details repeated in all. No evidences (or up to three): a single envelope.buildAll corta las evidencias en bloques de tres y devuelve un DispatcherEnvelope por bloque — encabezado y detalles repetidos en todos. Sin evidencias (o hasta tres): un solo envelope.
RPC genéricoGeneric RPCRPC genérico
Não há RPC por pesquisa: tudo passa pelo mesmo sendTransaction, com o JSON no campo message e serviceName = SurveyResultUploadAPI como discriminador.There's no per-survey RPC: everything goes through the same sendTransaction, with the JSON in the message field and serviceName = SurveyResultUploadAPI as the discriminator.No hay RPC por encuesta: todo pasa por el mismo sendTransaction, con el JSON en el campo message y serviceName = SurveyResultUploadAPI como discriminador.
FontesSourcesFuentes
BuildSurveyResultUploadDispatcherPayloadUseCase + SurveyResultUploadDispatcherPayloadInput + DispatcherType.survey + DispatcherConectaRep.proto. O input carrega entities cruas de domínio (CLAUDE.md §36) — SurveyEntity e VisitEntity inteiras; o build() constrói todo o wire.
BuildSurveyResultUploadDispatcherPayloadUseCase + SurveyResultUploadDispatcherPayloadInput + DispatcherType.survey + DispatcherConectaRep.proto. The input carries raw domain entities (CLAUDE.md §36) — whole SurveyEntity and VisitEntity; build() constructs the entire wire.
BuildSurveyResultUploadDispatcherPayloadUseCase + SurveyResultUploadDispatcherPayloadInput + DispatcherType.survey + DispatcherConectaRep.proto. El input lleva entities crudas de dominio (CLAUDE.md §36) — SurveyEntity y VisitEntity enteras; 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 (pedido, price check, survey, etc.) 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 (order, price check, survey, etc.) 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 (pedido, price check, survey, etc.) usa este mismo sendTransaction; lo que cambia es el serviceName (discriminador) y el JSON dentro de message.
sendTransactionunaryrpc sendTransaction(InboxTransactionRequest) returns (InboxTransactionReply)
path /mn.bat.conectarep.dispatcher.DispatcherConectaRepService/sendTransaction
InboxTransactionRequestendpointstring· #1 · endpoint alvo (config de ambiente)target endpoint (environment config)endpoint destino (config de ambiente)serviceNamestring· #2 · discriminador —SurveyResultUploadAPIdiscriminator —SurveyResultUploadAPIdiscriminador —SurveyResultUploadAPIdateReferencestring· #3 ·AAAA-MM-DDdo envio (submittedAt)YYYY-MM-DDof the submission (submittedAt)AAAA-MM-DDdel envío (submittedAt)transactionReferencestring· #4 · osurveyCode(correlação)thesurveyCode(correlation)elsurveyCode(correlación)usernamestring· #5messagestring· #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)manufacturerstring· #7 · dado do dispositivodevice datadato del dispositivomodelstring· #8 · dado do dispositivodevice datadato del dispositivodeviceUuidstring· #9 · literal"REP"hoje (ver Pendências)"REP"literal today (see Pending)literal"REP"hoy (ver Pendientes)deviceVersionstring· #10tidint64· #11 · id de transação para idempotência/replaytransaction id for idempotency/replayid de transacción para idempotencia/replay
InboxTransactionReplystatusint32· #1 · status do ack (0 = sucesso)ack status (0 = success)status del ack (0 = éxito)messagestring· #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 (ou vários) DispatcherEnvelope (type, serviceName, payload, account, transactionReference, dateReference). O DispatcherGateway serializa payload em JSON para message (jsonEncode), copia serviceName/dateReference/transactionReference, preenche os campos de dispositivo e o bearer token de auth, e chama o RPC.
The builder returns one (or several) DispatcherEnvelope (type, serviceName, payload, account, transactionReference, dateReference). The DispatcherGateway serializes payload to JSON into message (jsonEncode), copies serviceName/dateReference/transactionReference, fills in the device fields and the auth bearer token, and calls the RPC.
El builder devuelve uno (o varios) DispatcherEnvelope (type, serviceName, payload, account, transactionReference, dateReference). El DispatcherGateway serializa payload a JSON en message (jsonEncode), copia serviceName/dateReference/transactionReference, completa los campos del dispositivo y el bearer token de auth, y llama al RPC.
Para survey, resendMayDuplicate == true: um reenvio (ex.: recuperação de fila offline) pode duplicar o resultado no backend; a idempotência via tid é o que mitiga isso.For survey, resendMayDuplicate == true: a resend (e.g. offline-queue recovery) may duplicate the result on the backend; idempotency via tid is what mitigates it.Para survey, resendMayDuplicate == true: un reenvío (p. ej. recuperación de cola offline) puede duplicar el resultado en el backend; la idempotencia vía tid es lo que lo mitiga.
serviceName e splitsserviceName & splitsserviceName y splits
Uma única transação, sem variantes de tipo: o builder sempre emite DispatcherType.survey. O que se ramifica é o número de envelopes (por evidências) e o status do resultado (concluído vs. em andamento).A single transaction, with no type variants: the builder always emits DispatcherType.survey. What branches is the number of envelopes (by evidences) and the result status (complete vs. in progress).Una única transacción, sin variantes de tipo: el builder siempre emite DispatcherType.survey. Lo que se ramifica es el número de envelopes (por evidencias) y el status del resultado (completo vs. en curso).
DispatcherType |
serviceName |
MercadosMarketsMercados | DestinoDestinationDestino |
|---|---|---|---|
survey | SurveyResultUploadAPI | BR · CL · ZA | salesforce |
Prefixo Promo_ não usadoPromo_ prefix unusedPrefijo Promo_ no usado
O serviceName vem de type.resolveServiceName(hasPromotion: false) — o builder passa false hardcoded. Portanto o prefixo Promo_ (existente para transações com promoção) nunca é anexado aqui: o serviço é sempre SurveyResultUploadAPI. Ver Pendências.
The serviceName comes from type.resolveServiceName(hasPromotion: false) — the builder passes false hardcoded. So the Promo_ prefix (which exists for promotion transactions) is never prepended here: the service is always SurveyResultUploadAPI. See Pending.
El serviceName viene de type.resolveServiceName(hasPromotion: false) — el builder pasa false hardcoded. Por eso el prefijo Promo_ (existente para transacciones con promoción) nunca se antepone aquí: el servicio es siempre SurveyResultUploadAPI. Ver Pendientes.
Split multi-envelopeMulti-envelope splitSplit multi-envelope
buildAll(input) compara input.evidences.length com _maxEvidencesPerEnvelope = 3. Até três (inclusive zero) → um envelope (build(input)). Acima de três → um envelope por bloco de três, cada um via build(input.copyWith(evidences: sublist)). Cabeçalho e detalhes são repetidos em todos os envelopes; só a evidenceList difere. O SubmitSurveyResultUploadUseCase despacha os envelopes em paralelo (índice-alinhado); o Notifier trata a primeira falha como falha do envio inteiro.
buildAll(input) compares input.evidences.length against _maxEvidencesPerEnvelope = 3. Up to three (including zero) → one envelope (build(input)). Above three → one envelope per block of three, each via build(input.copyWith(evidences: sublist)). Header and details are repeated across all envelopes; only evidenceList differs. SubmitSurveyResultUploadUseCase dispatches the envelopes in parallel (index-aligned); the Notifier treats the first failure as failure of the whole send.
buildAll(input) compara input.evidences.length con _maxEvidencesPerEnvelope = 3. Hasta tres (incluido cero) → un envelope (build(input)). Más de tres → un envelope por bloque de tres, cada uno vía build(input.copyWith(evidences: sublist)). Encabezado y detalles se repiten en todos los envelopes; solo evidenceList difiere. SubmitSurveyResultUploadUseCase despacha los envelopes en paralelo (índice-alineado); el Notifier trata la primera falla como falla de todo el envío.
Como é disparadoHow it's firedCómo se dispara
A transação é orquestrada pelo fluxo de resposta de pesquisa (remote-first, §36). O notifier apenas reúne entities cruas e valores injetados; 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 survey-answering flow (remote-first, §36). The notifier only gathers raw entities and injected values; 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 respuesta de encuesta (remote-first, §36). El notifier solo reúne entities crudas y valores inyectados; el builder es el dueño único de todo join, rename, formateo de fecha y derivación wire. La cascada:
- SurveyAnswerNotifiersubmit()
- reúne entities cruas + injetadosgathers raw entities + injectedreúne entities crudas + inyectadosSurveyResultUploadDispatcherPayloadInput
- buildAll()BuildSurveyResultUploadDispatcherPayloadUseCasemonta o wireassembles the wirearma el wire
- devolve ≤3 evid./envelopereturns ≤3 evid./envelopedevuelve ≤3 evid./envelopeList<DispatcherEnvelope>
- SubmitSurveyResultUploadUseCaseDispatcherOrchestrator
- serializa + authserialize + authserializa + authDispatcherGateway
- sendTransactionBackendgRPC
- serializa + authserialize + authserializa + authDispatcherGateway
- SubmitSurveyResultUploadUseCaseDispatcherOrchestrator
- devolve ≤3 evid./envelopereturns ≤3 evid./envelopedevuelve ≤3 evid./envelopeList<DispatcherEnvelope>
- buildAll()BuildSurveyResultUploadDispatcherPayloadUseCasemonta o wireassembles the wirearma el wire
- reúne entities cruas + injetadosgathers raw entities + injectedreúne entities crudas + inyectadosSurveyResultUploadDispatcherPayloadInput
O input (entities cruas)The input (raw entities)El input (entities crudas)
SurveyResultUploadDispatcherPayloadInput (Freezed). Carrega o dado como existe no domínio; nada de formato wire. O relógio chega como submittedAt (via DateTimeUtils.now()); as evidências chegam com o arquivo já lido em base64.SurveyResultUploadDispatcherPayloadInput (Freezed). Carries data as it exists in the domain; no wire shaping. The clock arrives as submittedAt (via DateTimeUtils.now()); evidences arrive with the file already read as base64.SurveyResultUploadDispatcherPayloadInput (Freezed). Lleva el dato como existe en el dominio; nada de formato wire. El reloj llega como submittedAt (vía DateTimeUtils.now()); las evidencias llegan con el archivo ya leído en base64.
| CampoFieldCampo | TipoTypeTipo | PapelRoleRol |
|---|---|---|
survey | SurveyEntity | pesquisa respondida (crua). O builder lê survey.sfid → surveyID e percorre a árvore questions → answerOptions → dependentQuestion para resolver o questionAnswerOption de cada respostaanswered survey (raw). The builder reads survey.sfid → surveyID and walks the questions → answerOptions → dependentQuestion tree to resolve each answer's questionAnswerOptionencuesta respondida (cruda). El builder lee survey.sfid → surveyID y recorre el árbol questions → answerOptions → dependentQuestion para resolver el questionAnswerOption de cada respuesta |
visit | VisitEntity | visita anfitriã (crua). O builder deriva storeID (visit.accountData.sfid), visitID (visit.sfid) e o account do envelope (sfid/sapCode/name)host visit (raw). The builder derives storeID (visit.accountData.sfid), visitID (visit.sfid) and the envelope's account (sfid/sapCode/name)visita anfitriona (cruda). El builder deriva storeID (visit.accountData.sfid), visitID (visit.sfid) y el account del envelope (sfid/sapCode/name) |
answers | Map<String, SurveyAnswerValue> | questionSfid → resposta tipada (SurveyOptionAnswer / SurveyTextAnswer / SurveyNumericAnswer / SurveyDateAnswer). Uma ou mais linhas de surveyResultdetails por entradaquestionSfid → typed answer (SurveyOptionAnswer / SurveyTextAnswer / SurveyNumericAnswer / SurveyDateAnswer). One or more surveyResultdetails rows per entryquestionSfid → respuesta tipada (SurveyOptionAnswer / SurveyTextAnswer / SurveyNumericAnswer / SurveyDateAnswer). Una o más filas de surveyResultdetails por entrada |
evidences | List<SurveyResultUploadEvidence> | fotos/documentos anexados (questionSfid, base64, fileName). Alimenta a evidenceList e o split de envelopesattached photos/documents (questionSfid, base64, fileName). Feeds evidenceList and the envelope splitfotos/documentos adjuntos (questionSfid, base64, fileName). Alimenta la evidenceList y el split de envelopes |
completesResultOnUpload | bool | seleciona o surveyStatus: true → Complete; false → In Progressselects surveyStatus: true → Complete; false → In Progressselecciona el surveyStatus: true → Complete; false → In Progress |
surveyCode | String | código do resultado → surveyCode (raiz e cada detalhe) e transactionReference do enveloperesult code → surveyCode (header and each detail) and the envelope's transactionReferencecódigo del resultado → surveyCode (encabezado y cada detalle) y transactionReference del envelope |
submittedAt | DateTime | relógio → dateReference do envelope em yyyy-MM-ddclock → the envelope's dateReference in yyyy-MM-ddreloj → dateReference del envelope en yyyy-MM-dd |
SurveyResultUploadEvidence (Freezed, aninhado): questionSfid · base64 · fileName — todos String.SurveyResultUploadEvidence (Freezed, nested): questionSfid · base64 · fileName — all String.SurveyResultUploadEvidence (Freezed, anidado): questionSfid · base64 · fileName — todos String.
Payload (message)
O JSON serializado no campo message do request. Cada tabela abaixo tem 4 colunas — Campo JSON · Tipo · Origem do Dado · Regra — e lista toda chave que o build() emite (17 no total: 3 na raiz + 5 + 6 + 3). 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. Each table below has 4 columns — JSON field · Type · Data source · Rule — and lists every key that build() emits (17 total: 3 root + 5 + 6 + 3). 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. Cada tabla abajo tiene 4 columnas — Campo JSON · Tipo · Origen del Dato · Regla — y lista toda clave que build() emite (17 en total: 3 raíz + 5 + 6 + 3). 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 |
|---|---|---|---|
surveyResult | array | inlineinlineinline | array de um único objeto (cabeçalho do resultado)single-element array (result header)array de un solo objeto (encabezado del resultado) |
surveyResultdetails | array | _buildDetails | uma ou mais entradas por resposta (ver Regras)one or more entries per answer (see Rules)una o más entradas por respuesta (ver Reglas) |
evidenceList | array | input.evidences | uma entrada por evidência do envelope (≤ 3)one entry per envelope evidence (≤ 3)una entrada por evidencia del envelope (≤ 3) |
surveyResult objeto únicosingle objectobjeto único 5 camposfieldscampos
Campo JSON TipoTypeTipo Origem do DadoData sourceOrigen del Dato RegraRuleRegla surveyCodestring input.surveyCode— surveyIDstring input.survey.sfid— storeIDstring input.visit.accountData.sfidsfid do varejo da visitavisit retail's sfidsfid del punto de venta de la visita visitIDstring input.visit.sfid— surveyStatusstring status.valuecompletesResultOnUpload ? "Complete" : "In Progress"completesResultOnUpload ? "Complete" : "In Progress"completesResultOnUpload ? "Complete" : "In Progress"surveyResultdetails por respostaper answerpor respuesta 6 camposfieldscampos
Uma entrada por resposta em
input.answers— excetoSurveyOptionAnswer, que gera uma entrada por opção selecionada. Todas as entradas vêm de_detailRow.One entry per answer ininput.answers— exceptSurveyOptionAnswer, which yields one entry per selected option. All entries come from_detailRow.Una entrada por respuesta eninput.answers— exceptoSurveyOptionAnswer, que genera una entrada por opción seleccionada. Todas las entradas vienen de_detailRow.Campo JSON TipoTypeTipo Origem do DadoData sourceOrigen del Dato RegraRuleRegla surveyCodestring input.surveyCode— surveyQuestionstring questionSfida chave da entrada em input.answersthe entry key ininput.answersla clave de la entrada eninput.answersquestionAnswerOptionstring Calculadoopção → optionsBySfid[optionSfid].questionAnswerOptionSfid ?? ""; texto/número/data →_firstOptionSfid(1ª opção da pergunta) (ver Regras)option →optionsBySfid[optionSfid].questionAnswerOptionSfid ?? ""; text/number/date →_firstOptionSfid(question's 1st option) (see Rules)opción →optionsBySfid[optionSfid].questionAnswerOptionSfid ?? ""; texto/número/fecha →_firstOptionSfid(1ª opción de la pregunta) (ver Reglas)scorestring Fixo: "0"contrato · inertecontract · inertcontrato · inerte surveyResultstring Fixo: ""contrato · inertecontract · inertcontrato · inerte actualAnswerstring Calculadoopção → ""; texto →answer.text; número →answer.value.toString(); data →answer.dateemdd/MM/yyyyoption →""; text →answer.text; number →answer.value.toString(); date →answer.dateasdd/MM/yyyyopción →""; texto →answer.text; número →answer.value.toString(); fecha →answer.dateendd/MM/yyyyevidenceList por evidênciaper evidencepor evidencia 3 camposfieldscampos
Uma entrada por
SurveyResultUploadEvidenceeminput.evidences(já fatiado em ≤ 3 pelobuildAll).One entry perSurveyResultUploadEvidenceininput.evidences(already sliced to ≤ 3 bybuildAll).Una entrada porSurveyResultUploadEvidenceeninput.evidences(ya cortado a ≤ 3 porbuildAll).Campo JSON TipoTypeTipo Origem do DadoData sourceOrigen del Dato RegraRuleRegla base64string evidence.base64arquivo (foto/documento) já lido em base64 pelo notifierfile (photo/document) already read as base64 by the notifierarchivo (foto/documento) ya leído en base64 por el notifier questionSfidstring evidence.questionSfidpergunta a que a evidência pertencequestion the evidence belongs topregunta a la que pertenece la evidencia fileNamestring evidence.fileName.replaceAll("'", "")— apóstrofos removidos do nome.replaceAll("'", "")— apostrophes stripped from the name.replaceAll("'", "")— apóstrofos removidos del nombre
Regras de negócioBusiness rulesReglas de negocio
Status do resultadoResult statusStatus del resultado SurveyResultUploadStatus
status = completesResultOnUpload ? SurveyResultUploadStatus.complete : SurveyResultUploadStatus.inProgress. O surveyStatus emitido é o .value:status = completesResultOnUpload ? SurveyResultUploadStatus.complete : SurveyResultUploadStatus.inProgress. The emitted surveyStatus is the .value:status = completesResultOnUpload ? SurveyResultUploadStatus.complete : SurveyResultUploadStatus.inProgress. El surveyStatus emitido es el .value:
| SurveyResultUploadStatus | .value | QuandoWhenCuándo |
|---|---|---|
complete | Complete | completesResultOnUpload == true |
inProgress | In Progress | completesResultOnUpload == false |
Uma resposta → N linhas de detalheOne answer → N detail rowsUna respuesta → N filas de detalle _buildDetails · SurveyAnswerValue
Cada entrada de input.answers (questionSfid → SurveyAnswerValue) é convertida por tipo de resposta:Each input.answers entry (questionSfid → SurveyAnswerValue) is converted by answer type:Cada entrada de input.answers (questionSfid → SurveyAnswerValue) se convierte por tipo de respuesta:
| SurveyAnswerValue | LinhasRowsFilas | questionAnswerOption | actualAnswer |
|---|---|---|---|
SurveyOptionAnswer | uma por selectedOptionSfidsone per selectedOptionSfidsuna por selectedOptionSfids | optionsBySfid[optionSfid]?.questionAnswerOptionSfid ?? "" | "" |
SurveyTextAnswer | 1 | _firstOptionSfid(questionSfid) | answer.text |
SurveyNumericAnswer | 1 | _firstOptionSfid(questionSfid) | answer.value.toString() |
SurveyDateAnswer | 1 | _firstOptionSfid(questionSfid) | answer.date · dd/MM/yyyy |
Opção única e múltipla escolha compartilham SurveyOptionAnswer: múltipla simplesmente traz mais de um selectedOptionSfid, logo mais de uma linha.Single- and multi-choice share SurveyOptionAnswer: multi simply carries more than one selectedOptionSfid, hence more than one row.Opción única y opción múltiple comparten SurveyOptionAnswer: la múltiple simplemente trae más de un selectedOptionSfid, por eso más de una fila.
Resolução de questionAnswerOptionquestionAnswerOption resolutionResolución de questionAnswerOption _indexOptions · _firstOptionSfid
- Antes de montar os detalhes, o builder indexa recursivamente todas as opções da pesquisa:
optionsBySfid(opção pelo seusfid) eoptionsByQuestionSfid(opções por pergunta), descendo poroption.dependentQuestion.answerOptions(perguntas dependentes).Before building the details, the builder recursively indexes all survey options:optionsBySfid(option by itssfid) andoptionsByQuestionSfid(options per question), descending throughoption.dependentQuestion.answerOptions(dependent questions).Antes de armar los detalles, el builder indexa recursivamente todas las opciones de la encuesta:optionsBySfid(opción por susfid) yoptionsByQuestionSfid(opciones por pregunta), bajando poroption.dependentQuestion.answerOptions(preguntas dependientes). - Resposta de opção: o
questionAnswerOptionemitido é oquestionAnswerOptionSfidda opção selecionada (não osfidda opção). Se a opção não é encontrada no índice →"".Option answer: the emittedquestionAnswerOptionis the selected option'squestionAnswerOptionSfid(not the option'ssfid). If the option isn't found in the index →"".Respuesta de opción: elquestionAnswerOptionemitido es elquestionAnswerOptionSfidde la opción seleccionada (no elsfidde la opción). Si la opción no se encuentra en el índice →"". - Resposta de texto/número/data: como não há opção escolhida, usa-se o
questionAnswerOptionSfidda primeira opção da pergunta (_firstOptionSfid); se a pergunta não tem opções →"".Text/number/date answer: with no chosen option, it uses the question's first option'squestionAnswerOptionSfid(_firstOptionSfid); if the question has no options →"".Respuesta de texto/número/fecha: al no haber opción elegida, usa elquestionAnswerOptionSfidde la primera opción de la pregunta (_firstOptionSfid); si la pregunta no tiene opciones →"".
Split de evidênciasEvidence splitSplit de evidencias buildAll · _maxEvidencesPerEnvelope = 3
input.evidences.length <= 3(inclui zero) → um envelope,[build(input)].input.evidences.length <= 3(includes zero) → one envelope,[build(input)].input.evidences.length <= 3(incluye cero) → un envelope,[build(input)].- Acima de 3 → loop em passos de 3 sobre
evidences, cada bloco viabuild(input.copyWith(evidences: sublist)). Cada envelope carrega o mesmosurveyResultesurveyResultdetails; só aevidenceListmuda.Above 3 → loop in steps of 3 overevidences, each block viabuild(input.copyWith(evidences: sublist)). Each envelope carries the samesurveyResultandsurveyResultdetails; onlyevidenceListchanges.Más de 3 → loop en pasos de 3 sobreevidences, cada bloque víabuild(input.copyWith(evidences: sublist)). Cada envelope lleva el mismosurveyResultysurveyResultdetails; solo cambia laevidenceList. SubmitSurveyResultUploadUseCase.submit({envelopes})despacha em paralelo peloDispatcherOrchestrator, resultado índice-alinhado; o Notifier trata a primeira falha como falha do envio inteiro.SubmitSurveyResultUploadUseCase.submit({envelopes})dispatches in parallel viaDispatcherOrchestrator, index-aligned result; the Notifier treats the first failure as failure of the whole send.SubmitSurveyResultUploadUseCase.submit({envelopes})despacha en paralelo porDispatcherOrchestrator, resultado índice-alineado; el Notifier trata la primera falla como falla de todo el envío.
Datas e formatosDates & formatsFechas y formatos dateReference vs actualAnswer
- Envelope
dateReference:DateTimeUtils.formatDate(dateTime: submittedAt)— formato defaultisoDate=yyyy-MM-dd.EnvelopedateReference:DateTimeUtils.formatDate(dateTime: submittedAt)— defaultisoDateformat =yyyy-MM-dd.EnvelopedateReference:DateTimeUtils.formatDate(dateTime: submittedAt)— formato defaultisoDate=yyyy-MM-dd. - Resposta de data (
actualAnswer):DateFormatType.dayMonthYearSlash=dd/MM/yyyy— formato diferente dodateReference.Date answer (actualAnswer):DateFormatType.dayMonthYearSlash=dd/MM/yyyy— different format fromdateReference.Respuesta de fecha (actualAnswer):DateFormatType.dayMonthYearSlash=dd/MM/yyyy— formato distinto deldateReference.
Conta do envelopeEnvelope accountCuenta del envelope DispatchAccountEntity
Fora do payload JSON, o envelope leva um account (usado pelo Dispatcher/tracking): sfid = visit.accountData.sfid, sapCode = visit.accountData.customerCode, name = visit.accountData.name. Também: transactionReference = surveyCode.Outside the JSON payload, the envelope carries an account (used by Dispatcher/tracking): sfid = visit.accountData.sfid, sapCode = visit.accountData.customerCode, name = visit.accountData.name. Also: transactionReference = surveyCode.Fuera del payload JSON, el envelope lleva un account (usado por Dispatcher/tracking): sfid = visit.accountData.sfid, sapCode = visit.accountData.customerCode, name = visit.accountData.name. También: transactionReference = surveyCode.
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
serviceName: o builder chamaresolveServiceName(hasPromotion: false)comfalsehardcoded. Se uma pesquisa vier a fazer parte de um contexto promocional, o prefixoPromo_não seria anexado — hoje não há caminho que passetrue.serviceName: the builder callsresolveServiceName(hasPromotion: false)with a hardcodedfalse. If a survey were to belong to a promotional context, thePromo_prefix would not be prepended — there's no path passingtruetoday.serviceName: el builder llamaresolveServiceName(hasPromotion: false)confalsehardcoded. Si una encuesta llegara a formar parte de un contexto promocional, el prefijoPromo_no se antepondría — hoy no hay camino que pasetrue.score("0") esurveyResult("") do detalhe: placeholders inertes fixos do contrato — o app não calcula pontuação de pesquisa.score("0") andsurveyResult("") in the detail: fixed inert contract placeholders — the app computes no survey score.score("0") ysurveyResult("") del detalle: placeholders inertes fijos del contrato — la app no calcula puntuación de encuesta.questionAnswerOptionem respostas de texto/número/data cai na primeira opção da pergunta (_firstOptionSfid) — heurística; perguntas dessas naturezas normalmente não têm opção real associada, então o valor pode ser"".questionAnswerOptionfor text/number/date answers falls back to the question's first option (_firstOptionSfid) — a heuristic; questions of those kinds usually have no real option, so the value may be"".questionAnswerOptionen respuestas de texto/número/fecha cae en la primera opción de la pregunta (_firstOptionSfid) — heurística; preguntas de esas naturalezas normalmente no tienen opción real, así que el valor puede ser"".- Transporte:
deviceUuidvai como literal"REP"no gateway (pendência conhecida do Dispatcher, comum a 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, común a todas las transacciones).
Feature donaOwning featureFeature dueña As telas, os UseCases de leitura, os Notifiers e o modelo de dados das pesquisas estão documentados em Surveys (feature). The screens, read UseCases, Notifiers and data model of surveys are documented in Surveys (feature). Las pantallas, los UseCases de lectura, los Notifiers y el modelo de datos de las encuestas están documentados en Surveys (feature).
MercadosMarketsMercados
A disponibilidade da transação vem do DispatcherType.survey.enabledMarkets = [BR, CL, ZA]. AR/PY/PE não têm dispatcher de survey. O payload é o mesmo nos três mercados — não há ramificação por mercado no builder.Transaction availability comes from DispatcherType.survey.enabledMarkets = [BR, CL, ZA]. AR/PY/PE have no survey dispatcher. The payload is the same across the three markets — there's no per-market branching in the builder.La disponibilidad de la transacción viene de DispatcherType.survey.enabledMarkets = [BR, CL, ZA]. AR/PY/PE no tienen dispatcher de survey. El payload es el mismo en los tres mercados — no hay ramificación por mercado en el builder.
Mesmo contratoSame contractMismo contrato
A transação é idêntica em BR/CL/ZA: mesmo serviceName, mesma estrutura de payload, mesmo split por evidências. O que varia por mercado é quais pesquisas se aplicam e se completam no primeiro envio (completesResultOnUpload) — isso é configuração da pesquisa/mercado, resolvida na feature, não no builder.
The transaction is identical across BR/CL/ZA: same serviceName, same payload structure, same evidence split. What varies by market is which surveys apply and whether they complete on the first send (completesResultOnUpload) — that's survey/market config, resolved in the feature, not in the builder.
La transacción es idéntica en BR/CL/ZA: mismo serviceName, misma estructura de payload, mismo split por evidencias. Lo que varía por mercado es cuáles encuestas aplican y si se completan en el primer envío (completesResultOnUpload) — eso es config de la encuesta/mercado, resuelta en la feature, no en el builder.
AR · PY · PE
Existem como mercados do app (config PANGEA mínima), mas não têm dispatcher de survey — survey não os lista em enabledMarkets. O envio de resultado de pesquisa não é disparado nesses mercados.
They exist as app markets (minimal PANGEA config), but have no survey dispatcher — survey does not list them in enabledMarkets. Survey result upload is not fired in these markets.
Existen como mercados de la app (config PANGEA mínima), pero no tienen dispatcher de survey — survey no los lista en enabledMarkets. El envío de resultado de encuesta no se dispara en estos mercados.