Anotação de merchandisingMerchandising annotationAnotación de merchandising
A transação de escrita que registra uma anotação de campo feita durante uma atividade de merchandising de medição no ponto de venda, via o Dispatcher. Quando a atividade escolhida pelo representante de vendas é do tipo medição, a tela de merchandising abre um campo de texto livre; ao concluir, o app envia esse texto — junto com a atividade, o varejo e a visita. É o payload mais enxuto do domínio de merchandising: 7 chaves planas, sem itens, sem fotos, sem cálculo. The write transaction that records a field annotation taken during a measurement merchandising activity at the point of sale, through the Dispatcher. When the activity the sales rep picks is a measurement type, the merchandising screen opens a free-text field; on finishing, the app sends that text — together with the activity, the retail and the visit. It's the leanest payload of the merchandising domain: 7 flat keys, no items, no photos, no computation. La transacción de escritura que registra una anotación de campo tomada durante una actividad de merchandising de medición en el punto de venta, vía el Dispatcher. Cuando la actividad que elige el representante de ventas es del tipo medición, la pantalla de merchandising abre un campo de texto libre; al terminar, la app envía ese texto — junto con la actividad, el punto de venta y la visita. Es el payload más compacto del dominio de merchandising: 7 claves planas, sin ítems, sin fotos, sin cálculo.
O que é e quando aconteceWhat it is and when it happensQué es y cuándo ocurre
No merchandising, algumas atividades não instalam nem removem material — elas medem ou observam algo no ponto de venda (por exemplo, medir o espaço de um expositor ou anotar uma condição da loja). Nessas atividades de medição, em vez de peças e fotos, o representante de vendas escreve uma anotação de texto livre. Quando ele conclui, o app envia essa anotação ao backend por esta transação. É o momento em que uma observação de campo vira um registro no sistema. In merchandising, some activities neither install nor remove material — they measure or observe something at the point of sale (for example, measuring a display's space or noting a store condition). In these measurement activities, instead of pieces and photos, the sales rep writes a free-text annotation. When they finish, the app sends that annotation to the backend through this transaction. It's the moment a field observation becomes a record in the system. En merchandising, algunas actividades no instalan ni retiran material — miden u observan algo en el punto de venta (por ejemplo, medir el espacio de un exhibidor o anotar una condición de la tienda). En esas actividades de medición, en lugar de piezas y fotos, el representante de ventas escribe una anotación de texto libre. Cuando termina, la app envía esa anotación al backend por esta transacción. Es el momento en que una observación de campo se vuelve un registro en el sistema.
Cada envio carrega:Each send carries:Cada envío lleva:
A anotaçãoThe annotationLa anotación
O texto livre que o rep escreveu — o coração desta transação. É o único conteúdo que o rep digita.The free text the rep wrote — the heart of this transaction. It's the only content the rep types.El texto libre que el rep escribió — el corazón de esta transacción. Es el único contenido que el rep digita.
O contextoThe contextEl contexto
A atividade de merchandising escolhida, além do varejo e da visita em que a anotação foi feita.The chosen merchandising activity, plus the retail and the visit where the annotation was taken.La actividad de merchandising elegida, además del punto de venta y de la visita donde se tomó la anotación.
Sem variantesNo variantsSin variantes
Não há ramificações nem escolhas de tipo: o gesto é sempre o mesmo — escrever a anotação e enviar.There are no branches or type choices: the gesture is always the same — write the annotation and send.No hay ramificaciones ni elecciones de tipo: el gesto es siempre el mismo — escribir la anotación y enviar.
Medição vs. instalaçãoMeasurement vs. installationMedición vs. instalación A mesma tela de merchandising leva a dois caminhos: se a atividade é de medição, o rep escreve uma anotação e cai nesta transação; se a atividade instala/mantém material, o rep escolhe peças e fotos, e o envio segue por Criação de merchandising + Ordem de serviço. Quem decide o caminho é o tipo da atividade, não o rep. The same merchandising screen leads to two paths: if the activity is a measurement, the rep writes an annotation and lands on this transaction; if the activity installs/maintains material, the rep picks pieces and photos, and the send goes through Merchandising creation + Service order. The activity type decides the path, not the rep. La misma pantalla de merchandising lleva a dos caminos: si la actividad es de medición, el rep escribe una anotación y cae en esta transacción; si la actividad instala/mantiene material, el rep elige piezas y fotos, y el envío pasa por Creación de merchandising + Orden de servicio. El tipo de actividad decide el camino, no el rep.
Fluxo de telas que disparaScreen flow that fires itFlujo de pantallas que lo dispara
A transação é o último passo de uma ordem de serviço de merchandising de medição. As telas do caminho pertencem à feature de Merchandising; aqui só situamos onde o envio acontece:The transaction is the last step of a measurement merchandising service order. The screens along the way belong to the Merchandising feature; here we only place where the send happens:La transacción es el último paso de una orden de servicio de merchandising de medición. Las pantallas del camino pertenecen a la feature de Merchandising; aquí solo situamos dónde ocurre el envío:
- Menu de merchandisingMerchandising menuMenú de merchandisingDentro da visita, o rep abre o merchandising e escolhe a ordem de serviço.Inside the visit, the rep opens merchandising and chooses the service order.Dentro de la visita, el rep abre el merchandising y elige la orden de servicio.
- EspecificaçõesSpecificationsEspecificacionesO rep escolhe a atividade. Se ela é de medição, a tela mostra um campo de anotação (texto livre, até 3 linhas) no lugar da escolha de peças.The rep picks the activity. If it's a measurement one, the screen shows an annotation field (free text, up to 3 lines) instead of the piece selection.El rep elige la actividad. Si es de medición, la pantalla muestra un campo de anotación (texto libre, hasta 3 líneas) en lugar de la selección de piezas.
- Escrever a anotaçãoWrite the annotationEscribir la anotaciónO rep digita a observação. O botão de envio só habilita quando a anotação não está vazia.The rep types the observation. The send button only enables when the annotation is not empty.El rep digita la observación. El botón de envío solo se habilita cuando la anotación no está vacía.
- Confirmar → esta transaçãoConfirm → this transactionConfirmar → esta transacciónAo tocar em enviar e confirmar no modal, o app dispara a Anotação de merchandising. É este toque que aciona a transação.Tapping send and confirming in the modal fires Merchandising annotation. This tap is what triggers the transaction.Al tocar enviar y confirmar en el modal, la app dispara la Anotación de merchandising. Este toque es lo que activa la transacción.
Sempre dentro de uma visitaAlways inside a visitSiempre dentro de una visita A anotação só existe no contexto de uma visita a um varejo — é de lá que vêm o varejo e a visita anexados ao envio. Não há como criar uma anotação de merchandising fora de uma visita. The annotation only exists in the context of a visit to a retail — that's where the retail and visit attached to the send come from. There's no way to create a merchandising annotation outside a visit. La anotación solo existe en el contexto de una visita a un punto de venta — de ahí vienen el punto de venta y la visita adjuntos al envío. No hay forma de crear una anotación de merchandising fuera de una visita.
Depois do envioAfter sendingDespués del envío
- Confirmação ao repConfirmation to the repConfirmación al rep
- Quando o backend aceita, a anotação é registrada e a ordem de serviço de medição é concluída. O resultado do envio é mostrado no próprio modal de confirmação — sucesso encerra o fluxo; erro mantém o rep na tela para tentar de novo.When the backend accepts it, the annotation is recorded and the measurement service order is completed. The send result shows in the confirmation modal itself — success closes the flow; an error keeps the rep on the screen to try again.Cuando el backend lo acepta, la anotación queda registrada y la orden de servicio de medición se concluye. El resultado del envío se muestra en el propio modal de confirmación — el éxito cierra el flujo; un error mantiene al rep en la pantalla para reintentar.
- Sem internetOfflineSin internet
- Sem conexão, o envio não é aceito na hora: o app registra o despacho como erro e o rep vê a falha no modal. O reenvio automático acontece quando a conexão volta (a fila de despachos tenta de novo). Um reenvio pode, em tese, duplicar o registro; o sistema usa um identificador de transação para reduzir isso.Offline, the send is not accepted right away: the app records the dispatch as an error and the rep sees the failure in the modal. Automatic retry happens when the connection returns (the dispatch queue tries again). A retry could, in theory, duplicate the record; the system uses a transaction id to reduce that.Sin conexión, el envío no se acepta en el momento: la app registra el despacho como error y el rep ve la falla en el modal. El reenvío automático ocurre cuando vuelve la conexión (la cola de despachos reintenta). Un reenvío podría, en teoría, duplicar el registro; el sistema usa un identificador de transacción para reducir eso.
- Acompanhar o envioTracking the sendSeguir el envío
- O status técnico do despacho (enviado, em fila, com erro) pode ser acompanhado na central de dados / tracking de despachos do app — útil para suporte investigar um envio.The dispatch's technical status (sent, queued, errored) can be followed in the app's data center / dispatch tracking — useful for support to investigate a send.El estado técnico del despacho (enviado, en cola, con error) puede seguirse en el centro de datos / tracking de despachos de la app — útil para que soporte investigue un envío.
Visão técnicaTechnical overviewVisión técnica
Anotação de merchandising (DispatcherType.merchandisingAnnotation, serviceName CreateMerchanAnnotation) é a transação de saída que registra a anotação de texto livre de uma ordem de serviço de merchandising de medição. É disparada pelo notifier da ordem de serviço em submitMeasurement(), quando a atividade selecionada é de medição (selectedActivity.isMeasurement). Payload plano: 7 chaves, sem arrays, sem cálculo, sem campos inertes de contrato.
Merchandising annotation (DispatcherType.merchandisingAnnotation, serviceName CreateMerchanAnnotation) is the outbound transaction that records the free-text annotation of a measurement merchandising service order. It's fired by the service-order notifier in submitMeasurement(), when the selected activity is a measurement one (selectedActivity.isMeasurement). Flat payload: 7 keys, no arrays, no computation, no inert contract fields.
Anotación de merchandising (DispatcherType.merchandisingAnnotation, serviceName CreateMerchanAnnotation) es la transacción de salida que registra la anotación de texto libre de una orden de servicio de merchandising de medición. Se dispara desde el notifier de la orden de servicio en submitMeasurement(), cuando la actividad seleccionada es de medición (selectedActivity.isMeasurement). Payload plano: 7 claves, sin arrays, sin cálculo, sin campos inertes de contrato.
Payload planoFlat payloadPayload plano
7 chaves na raiz, nenhuma aninhada. Cada valor vem direto do input; o build() só renomeia e faz trim() na anotação.7 root keys, none nested. Each value comes straight from the input; build() only renames and trim()s the annotation.7 claves en la raíz, ninguna anidada. Cada valor viene directo del input; el build() solo renombra y hace trim() en la anotación.
Uma variante sóSingle variantUna sola variante
Um único DispatcherType, um único serviceName, sem prefixo Promo_ (hasPromotion: false fixo).A single DispatcherType, a single serviceName, no Promo_ prefix (hasPromotion: false fixed).Un único DispatcherType, un único serviceName, sin prefijo Promo_ (hasPromotion: false fijo).
RPC genéricoGeneric RPCRPC genérico
Como toda transação, passa pelo mesmo sendTransaction, com o JSON serializado em message e CreateMerchanAnnotation como discriminador.Like every transaction, it goes through the same sendTransaction, with the JSON serialized into message and CreateMerchanAnnotation as the discriminator.Como toda transacción, pasa por el mismo sendTransaction, con el JSON serializado en message y CreateMerchanAnnotation como discriminador.
FontesSourcesFuentes
BuildMerchandisingAnnotationDispatcherPayloadUseCase + MerchandisingAnnotationDispatcherPayloadInput + DispatcherType + DispatcherConectaRep.proto. O input carrega entities cruas de domínio (CLAUDE.md §36); o build() só renomeia, faz trim() e serializa.
BuildMerchandisingAnnotationDispatcherPayloadUseCase + MerchandisingAnnotationDispatcherPayloadInput + DispatcherType + DispatcherConectaRep.proto. The input carries raw domain entities (CLAUDE.md §36); build() only renames, trim()s and serializes.
BuildMerchandisingAnnotationDispatcherPayloadUseCase + MerchandisingAnnotationDispatcherPayloadInput + DispatcherType + DispatcherConectaRep.proto. El input lleva entities crudas de dominio (CLAUDE.md §36); el build() solo renombra, hace trim() y serializa.
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. Aqui o serviceName é CreateMerchanAnnotation.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. Here the serviceName is CreateMerchanAnnotation.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. Aquí el serviceName es CreateMerchanAnnotation.
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 —CreateMerchanAnnotation(sem prefixoPromo_)discriminator —CreateMerchanAnnotation(noPromo_prefix)discriminador —CreateMerchanAnnotation(sin prefijoPromo_)dateReferencestring· #3 ·AAAA-MM-DDdo envio (formatDate(submittedAt))YYYY-MM-DDof the submission (formatDate(submittedAt))AAAA-MM-DDdel envío (formatDate(submittedAt))transactionReferencestring· #4 · oaccountSfiddo varejo (correlação)the retailaccountSfid(correlation)elaccountSfiddel punto de venta (correlación)usernamestring· #5messagestring· #6 · o payload JSON serializado (a tabela da seção 07)the JSON payload serialized (the table in section 07)el payload JSON serializado (la tabla de la sección 07)manufacturerstring· #7 · dado do dispositivodevice datadato del dispositivomodelstring· #8 · dado do dispositivodevice datadato del dispositivodeviceUuidstring· #9 · literal provisório hoje (ver Pendências)provisional literal today (see Pending)literal provisional 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 DispatcherEnvelope (type, serviceName, payload, account, transactionReference, dateReference). Aqui account = DispatchAccountEntity(sfid: accountSfid), transactionReference = accountSfid, e tid fica no default do envelope. O DispatcherGateway serializa payload em JSON para message, 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). Here account = DispatchAccountEntity(sfid: accountSfid), transactionReference = accountSfid, and tid keeps the envelope default. The DispatcherGateway serializes payload to JSON into message, 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). Aquí account = DispatchAccountEntity(sfid: accountSfid), transactionReference = accountSfid, y tid queda en el default del envelope. El DispatcherGateway serializa payload a JSON en message, copia serviceName/dateReference/transactionReference, completa los campos del dispositivo y el bearer token de auth, y llama al RPC.
destination = none (sem roteamento externo específico) e resendMayDuplicate == true: um reenvio (ex.: recuperação de fila offline) pode duplicar o registro; a idempotência via tid é o que mitiga isso. Offline, o envio não é pré-enfileirado (só DispatcherType.visit tem esse atalho): o gateway lança NetworkException, o orquestrador persiste o despacho como error e o reenvio fica a cargo do flush() na volta da conexão (máx. 5 tentativas).destination = none (no specific external routing) and resendMayDuplicate == true: a resend (e.g. offline-queue recovery) may duplicate the record; idempotency via tid is what mitigates it. Offline, the send is not pre-queued (only DispatcherType.visit has that shortcut): the gateway throws NetworkException, the orchestrator persists the dispatch as error, and the resend is left to flush() on reconnect (max 5 attempts).destination = none (sin ruteo externo específico) y resendMayDuplicate == true: un reenvío (p. ej. recuperación de cola offline) puede duplicar el registro; la idempotencia vía tid es lo que lo mitiga. Sin conexión, el envío no se pre-encola (solo DispatcherType.visit tiene ese atajo): el gateway lanza NetworkException, el orquestador persiste el despacho como error, y el reenvío queda a cargo de flush() al reconectar (máx. 5 intentos).
Como é disparadoHow it's firedCómo se dispara
A transação é orquestrada pelo notifier da ordem de serviço de merchandising, em submitMeasurement(). O notifier apenas reúne a entity crua do representante de vendas (currentResourceProvider) e os valores já no State (rótulo da atividade, anotação, sfids da visita/varejo, relógio); o builder é o dono único do rename, do trim() e da serialização. A cascata:The transaction is orchestrated by the merchandising service-order notifier, in submitMeasurement(). The notifier only gathers the raw sales-rep entity (currentResourceProvider) and the values already in State (activity label, annotation, visit/retail sfids, clock); the builder is the sole owner of the rename, the trim() and the serialization. The cascade:La transacción se orquesta desde el notifier de la orden de servicio de merchandising, en submitMeasurement(). El notifier solo reúne la entity cruda del representante de ventas (currentResourceProvider) y los valores ya en el State (etiqueta de la actividad, anotación, sfids de la visita/punto de venta, reloj); el builder es el dueño único del rename, del trim() y la serialización. La cascada:
- MerchandisingServiceOrderNotifiersubmitMeasurement()
- reúne resource cru + Stategathers raw resource + Statereúne resource crudo + StateMerchandisingAnnotationDispatcherPayloadInput
- build()BuildMerchandisingAnnotationDispatcherPayloadUseCasemonta o wireassembles the wirearma el wire
- devolvereturnsdevuelveDispatcherEnvelope
- SubmitMerchandisingAnnotationUseCaseDispatcherOrchestrator
- DispatcherRepositoryDispatcherGatewayserializa + authserialize + authserializa + auth
- sendTransactionBackendgRPC
- DispatcherRepositoryDispatcherGatewayserializa + authserialize + authserializa + auth
- SubmitMerchandisingAnnotationUseCaseDispatcherOrchestrator
- devolvereturnsdevuelveDispatcherEnvelope
- build()BuildMerchandisingAnnotationDispatcherPayloadUseCasemonta o wireassembles the wirearma el wire
- reúne resource cru + Stategathers raw resource + Statereúne resource crudo + StateMerchandisingAnnotationDispatcherPayloadInput
O disparo é acionado pelo botão de envio da tela de especificações, que abre um modal de confirmação; ao confirmar, se state.isMeasurement, o notifier chama submitMeasurement(). Antes de montar o input, o método lê o currentResourceProvider e aborta com log (merchandisingSubmitAbortedNoResource) se não houver resource. Diferente do caminho de instalação (que envia dois envelopes), a medição envia um único envelope.The trigger is the specifications screen's send button, which opens a confirmation modal; on confirm, if state.isMeasurement, the notifier calls submitMeasurement(). Before building the input, the method reads currentResourceProvider and aborts with a log (merchandisingSubmitAbortedNoResource) if there's no resource. Unlike the installation path (which sends two envelopes), measurement sends a single envelope.El disparo lo acciona el botón de envío de la pantalla de especificaciones, que abre un modal de confirmación; al confirmar, si state.isMeasurement, el notifier llama submitMeasurement(). Antes de armar el input, el método lee currentResourceProvider y aborta con log (merchandisingSubmitAbortedNoResource) si no hay resource. A diferencia del camino de instalación (que envía dos envelopes), la medición envía un único envelope.
O input (entities cruas)The input (raw entities)El input (entities crudas)
MerchandisingAnnotationDispatcherPayloadInput (Freezed). Carrega o dado como existe no domínio; nada de formato wire. O rótulo da atividade (activityLabel) já vem resolvido do State (selectedActivity?.label ?? ""); a anotação como digitada (current.annotation); o relógio como submittedAt (DateTimeUtils.now()).MerchandisingAnnotationDispatcherPayloadInput (Freezed). Carries data as it exists in the domain; no wire shaping. The activity label (activityLabel) arrives already resolved from the State (selectedActivity?.label ?? ""); the annotation as typed (current.annotation); the clock as submittedAt (DateTimeUtils.now()).MerchandisingAnnotationDispatcherPayloadInput (Freezed). Lleva el dato como existe en el dominio; nada de formato wire. La etiqueta de la actividad (activityLabel) ya viene resuelta del State (selectedActivity?.label ?? ""); la anotación como se digitó (current.annotation); el reloj como submittedAt (DateTimeUtils.now()).
| CampoFieldCampo | TipoTypeTipo | PapelRoleRol |
|---|---|---|
resource | ResourceEntity | representante de vendas (cru — o builder usa resource.sfid)sales rep (raw — the builder uses resource.sfid)representante de ventas (crudo — el builder usa resource.sfid) |
visitSfid | String | → visitId |
accountSfid | String | → accountUuid, account.sfid e transactionReference (varejo da visita)→ accountUuid, account.sfid and transactionReference (visit's retail)→ accountUuid, account.sfid y transactionReference (punto de venta de la visita) |
activityLabel | String | → activityType (selectedActivity?.label ?? "")→ activityType (selectedActivity?.label ?? "")→ activityType (selectedActivity?.label ?? "") |
annotation | String | → annotation (texto livre; o builder aplica .trim())→ annotation (free text; the builder applies .trim())→ annotation (texto libre; el builder aplica .trim()) |
submittedAt | DateTime | → dateReference (DateTimeUtils.now())→ dateReference (DateTimeUtils.now())→ dateReference (DateTimeUtils.now()) |
Payload (message)
O JSON serializado no campo message do request. A tabela abaixo tem 4 colunas — Campo JSON · Tipo · Origem do Dado · Regra — e lista toda chave que o build() emite (7 no total, todas na raiz — sem arrays, sem objetos aninhados). 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. The table below has 4 columns — JSON field · Type · Data source · Rule — and lists every key that build() emits (7 total, all at the root — no arrays, no nested objects). 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. La tabla abajo tiene 4 columnas — Campo JSON · Tipo · Origen del Dato · Regla — y lista toda clave que el build() emite (7 en total, todas en la raíz — sin arrays, sin objetos anidados). 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 |
|---|---|---|---|
activityType | string | input.activityLabel | rótulo da atividade de medição selecionada (selectedActivity.label)selected measurement activity's label (selectedActivity.label)etiqueta de la actividad de medición seleccionada (selectedActivity.label) |
serviceType | string | Fixo: "" | contrato · sempre vazio nesta transação (ver Pendências)contract · always empty in this transaction (see Pending)contrato · siempre vacío en esta transacción (ver Pendientes) |
reasonType | string | Fixo: "" | contrato · sempre vazio nesta transação (ver Pendências)contract · always empty in this transaction (see Pending)contrato · siempre vacío en esta transacción (ver Pendientes) |
accountUuid | string | input.accountSfid | SFID do varejo (da VisitEntity.accountData.sfid)retail SFID (from VisitEntity.accountData.sfid)SFID del punto de venta (de VisitEntity.accountData.sfid) |
repSfid | string | input.resource.sfid | SFID do representante de vendas (de currentResourceProvider)sales rep SFID (from currentResourceProvider)SFID del representante de ventas (de currentResourceProvider) |
visitId | string | input.visitSfid | SFID da visita em que a anotação foi feitaSFID of the visit the annotation was taken inSFID de la visita en que se tomó la anotación |
annotation | string | input.annotation.trim() | o texto livre digitado pelo rep, aparado (.trim())the rep's typed free text, trimmed (.trim())el texto libre digitado por el rep, recortado (.trim()) |
Regras de negócioBusiness rulesReglas de negocio
Quando é disparadaWhen it firesCuándo se dispara isMeasurement · canSubmitMeasurement
A ordem de serviço de merchandising ramifica pelo tipo da atividade:The merchandising service order branches on the activity type:La orden de servicio de merchandising se ramifica por el tipo de actividad:
state.isMeasurement(=selectedActivity?.isMeasurement ?? false) → o modal de confirmação chamasubmitMeasurement(), que dispara esta Anotação de merchandising.state.isMeasurement(=selectedActivity?.isMeasurement ?? false) → the confirmation modal callssubmitMeasurement(), which fires this Merchandising annotation.state.isMeasurement(=selectedActivity?.isMeasurement ?? false) → el modal de confirmación llamasubmitMeasurement(), que dispara esta Anotación de merchandising.- atividade não-medição → o rep segue para peças/fotos e o envio vai por Criação de merchandising + Ordem de serviço (ou Asset item tracking); esta transação não é enviada.non-measurement activity → the rep proceeds to pieces/photos and the send goes through Merchandising creation + Service order (or Asset item tracking); this transaction is not sent.actividad no-medición → el rep sigue a piezas/fotos y el envío pasa por Creación de merchandising + Orden de servicio (o Asset item tracking); esta transacción no se envía.
- O botão de envio só habilita com
canSubmitMeasurement(=isMeasurement && annotation.trim().isNotEmpty): uma anotação vazia ou só com espaços não pode ser enviada.The send button only enables withcanSubmitMeasurement(=isMeasurement && annotation.trim().isNotEmpty): an empty or whitespace-only annotation cannot be sent.El botón de envío solo se habilita concanSubmitMeasurement(=isMeasurement && annotation.trim().isNotEmpty): una anotación vacía o solo con espacios no puede enviarse.
Rótulo, não códigoLabel, not codeEtiqueta, no código activityType
Como a Criação de merchandising (e diferente da Ordem de serviço, que envia activityCode), a anotação envia o rótulo legível da atividade (selectedActivity.label) em activityType — não o código. É um registro descritivo, não um comando estruturado. Se nenhuma atividade estiver selecionada, o rótulo cai para "" (mas o envio não chega a habilitar sem atividade de medição).Like Merchandising creation (and unlike the Service order, which sends activityCode), the annotation sends the activity's human-readable label (selectedActivity.label) in activityType — not the code. It's a descriptive record, not a structured command. If no activity is selected, the label falls to "" (but the send never enables without a measurement activity).Como la Creación de merchandising (y a diferencia de la Orden de servicio, que envía activityCode), la anotación envía la etiqueta legible de la actividad (selectedActivity.label) en activityType — no el código. Es un registro descriptivo, no un comando estructurado. Si ninguna actividad está seleccionada, la etiqueta cae a "" (pero el envío nunca se habilita sin actividad de medición).
Único trim(), sem cálculoSingle trim(), no computationÚnico trim(), sin cálculo build() 1:1
O build() é uma projeção direta de 7 chaves: nenhum arredondamento, nenhuma derivação, nenhum campo inerte de contrato. A única transformação é input.annotation.trim() (apara espaços das pontas do texto). Todos os demais valores passam crus do input. serviceType e reasonType são literais fixos "" — a anotação não os usa.build() is a direct projection of 7 keys: no rounding, no derivation, no inert contract field. The only transformation is input.annotation.trim() (strips edge whitespace from the text). Every other value passes raw from the input. serviceType and reasonType are fixed "" literals — the annotation doesn't use them.El build() es una proyección directa de 7 claves: sin redondeo, sin derivación, sin campo inerte de contrato. La única transformación es input.annotation.trim() (recorta espacios de los extremos del texto). Todos los demás valores pasan crudos del input. serviceType y reasonType son literales fijos "" — la anotación no los usa.
Pendências / roadmapPending / roadmapPendientes / roadmap
O que o builder envia inerte ou onde o fluxo limita, documentado fiel ao estado atual do código (nunca descrito como se já existisse):What the builder ships inert, or where the flow limits, documented faithfully to the current code state (never described as already existing):Lo que el builder envía inerte, o dónde el flujo limita, documentado fiel al estado actual del código (nunca descrito como si ya existiera):
Inerte / limitadoInert / limitedInerte / limitado
serviceTypeereasonType: sempre""— o contrato herda esses campos da Criação de merchandising, mas a anotação de medição não os preenche (só atividade + texto livre).serviceTypeandreasonType: always""— the contract inherits these fields from Merchandising creation, but the measurement annotation doesn't fill them (only activity + free text).serviceTypeyreasonType: siempre""— el contrato hereda esos campos de la Creación de merchandising, pero la anotación de medición no los completa (solo actividad + texto libre).activityTypevai como rótulo (.label), não como código. Se um dia o backend precisar do código da atividade para correlação, isso exigiria mudança de contrato/builder.activityTypeships as a label (.label), not a code. If the backend ever needs the activity code for correlation, that would require a contract/builder change.activityTypeva como etiqueta (.label), no como código. Si algún día el backend necesita el código de la actividad para correlación, eso exigiría un cambio de contrato/builder.accountSfidé capturado no State embuild()(viaVisitEntity.accountData.sfid) e reusado no envio — não é re-resolvido no momento do submit como faz o caminho de instalação. Ambos derivam do mesmo varejo da visita, então na prática coincidem.accountSfidis captured in State atbuild()(viaVisitEntity.accountData.sfid) and reused at send time — it's not re-resolved at submit like the installation path does. Both derive from the same visit's retail, so in practice they match.accountSfidse captura en el State enbuild()(víaVisitEntity.accountData.sfid) y se reutiliza al enviar — no se re-resuelve en el momento del submit como hace el camino de instalación. Ambos derivan del mismo punto de venta de la visita, así que en la práctica coinciden.- Transporte:
deviceUuidvai como literal provisório no gateway (pendência conhecida do Dispatcher).Transport:deviceUuidships as a provisional literal in the gateway (known Dispatcher pending item).Transporte:deviceUuidva como literal provisional en el gateway (pendiente conocido del Dispatcher).
Transações irmãsSister transactionsTransacciones hermanas
Domínio de merchandising: 12 · Image audit, 13 · Image recognition, 14 · Creation (compartilha o notifier e os campos activityType/serviceType/reasonType), 15 · Audit unit, 16 · Asset item tracking e 18 · Service order.
Merchandising domain: 12 · Image audit, 13 · Image recognition, 14 · Creation (shares the notifier and the activityType/serviceType/reasonType fields), 15 · Audit unit, 16 · Asset item tracking and 18 · Service order.
Dominio de merchandising: 12 · Image audit, 13 · Image recognition, 14 · Creation (comparte el notifier y los campos activityType/serviceType/reasonType), 15 · Audit unit, 16 · Asset item tracking y 18 · Service order.
MercadosMarketsMercados
A disponibilidade da transação vem do DispatcherType.merchandisingAnnotation.enabledMarkets = [BR]. É uma transação só do Brasil; os demais mercados não a listam e não a disparam.Transaction availability comes from DispatcherType.merchandisingAnnotation.enabledMarkets = [BR]. It's a Brazil-only transaction; the other markets don't list it and don't fire it.La disponibilidad de la transacción viene de DispatcherType.merchandisingAnnotation.enabledMarkets = [BR]. Es una transacción solo de Brasil; los demás mercados no la listan y no la disparan.
Só no BrasilBrazil onlySolo Brasil
As atividades de merchandising de medição fazem parte do fluxo de ordem de serviço exclusivo do Brasil. O destination é none (sem roteamento externo específico) — mesmo padrão das outras transações de merchandising BR.
Measurement merchandising activities are part of the Brazil-exclusive service-order flow. The destination is none (no specific external routing) — same pattern as the other BR merchandising transactions.
Las actividades de merchandising de medición forman parte del flujo de orden de servicio exclusivo de Brasil. El destination es none (sin ruteo externo específico) — mismo patrón de las otras transacciones de merchandising BR.
CL · ZA · AR · PY · PE
Existem como mercados do app, mas não têm a transação de Anotação de merchandising — enabledMarkets lista apenas BR. Nesses mercados a atividade de merchandising de medição não é disparada.
They exist as app markets, but don't have the Merchandising annotation transaction — enabledMarkets lists only BR. In these markets the measurement merchandising activity is not fired.
Existen como mercados de la app, pero no tienen la transacción de Anotación de merchandising — enabledMarkets lista solo BR. En estos mercados la actividad de merchandising de medición no se dispara.