Contagem de estoqueStock countConteo de stock
A transação de escrita que envia ao backend o resultado da contagem de estoque feita pelo representante de vendas durante uma visita. Cada produto contado vira uma linha do payload, com a quantidade na unidade alta e na unidade baixa. Um único builder monta o payload; não há variantes. The write transaction that sends the backend the result of the stock count the sales rep does during a visit. Each counted product becomes a payload line, with the quantity in the high unit and the low unit. A single builder assembles the payload; there are no variants. La transacción de escritura que envía al backend el resultado del conteo de stock hecho por el representante de ventas durante una visita. Cada producto contado se vuelve una línea del payload, con la cantidad en la unidad alta y la unidad baja. Un único builder arma el payload; no hay variantes.
O que é e quando aconteceWhat it is and when it happensQué es y cuándo ocurre
Durante uma visita, o representante de vendas pode contar o estoque do varejo — quantas unidades de cada produto existem na prateleira/depósito. Ao concluir a contagem e enviar, o app dispara esta transação, que leva ao backend a lista de produtos contados com suas quantidades. É como o registro do estoque sai do dispositivo e passa a existir no sistema. During a visit, the sales rep can count the retail's stock — how many units of each product are on the shelf/back-store. When the count is finished and sent, the app fires this transaction, carrying the list of counted products with their quantities to the backend. It's how the stock record leaves the device and starts to exist in the system. Durante una visita, el representante de ventas puede contar el stock del punto de venta — cuántas unidades de cada producto hay en la góndola/bodega. Al terminar el conteo y enviar, la app dispara esta transacción, que lleva al backend la lista de productos contados con sus cantidades. Es cómo el registro de stock sale del dispositivo y pasa a existir en el sistema.
Uma linha por produtoOne line per productUna línea por producto
Só entram os produtos que o rep realmente contou. Produtos sem contagem não são enviados.Only the products the rep actually counted are included. Uncounted products aren't sent.Solo entran los productos que el rep realmente contó. Los productos sin conteo no se envían.
Unidade alta e baixaHigh and low unitUnidad alta y baja
A contagem tem duas colunas: Alta (ex.: caixa) e Baixa (ex.: unidade). As duas viajam no envio.The count has two columns: High (e.g. case) and Low (e.g. each). Both travel in the send.El conteo tiene dos columnas: Alta (p. ej. caja) y Baja (p. ej. unidad). Ambas viajan en el envío.
Sem variantesNo variantsSin variantes
Uma só forma de envio para todos os mercados. Para o rep, o gesto é sempre o mesmo — contar e enviar.One single send shape for all markets. For the rep, the gesture is always the same — count and send.Una sola forma de envío para todos los mercados. Para el rep, el gesto es siempre el mismo — contar y enviar.
Fluxo de telas que disparaScreen flow that fires itFlujo de pantallas que lo dispara
A transação é o último passo da contagem de estoque. As telas do caminho pertencem à feature de Contagem de estoque; aqui só situamos onde o envio acontece:The transaction is the last step of the stock count. The screens along the way belong to the Stock count feature; here we only place where the send happens:La transacción es el último paso del conteo de stock. Las pantallas del camino pertenecen a la feature de Conteo de stock; aquí solo situamos dónde ocurre el envío:
- Abrir a contagem na visitaOpen the count in the visitAbrir el conteo en la visitaA partir do detalhe da visita do varejo, o rep entra na tela de contagem de estoque.From the retail's visit detail, the rep opens the stock count screen.Desde el detalle de la visita del punto de venta, el rep entra a la pantalla de conteo de stock.
- Contar cada produtoCount each productContar cada productoPara cada produto, informa a quantidade em unidade Alta e/ou Baixa.For each product, enters the quantity in the High and/or Low unit.Para cada producto, ingresa la cantidad en unidad Alta y/o Baja.
- Enviar contagem → esta transaçãoSend count → this transactionEnviar conteo → esta transacciónAo tocar em enviar, o app dispara a Contagem de estoque. É este toque que aciona a transação.Tapping send fires Stock count. This tap is what triggers the transaction.Al tocar enviar, la app dispara el Conteo de stock. 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, a contagem é confirmada e as quantidades contadas são limpas da tela — pronto para uma próxima contagem.When the backend accepts it, the count is confirmed and the counted quantities are cleared from the screen — ready for a next count.Cuando el backend lo acepta, el conteo se confirma y las cantidades contadas se limpian de la pantalla — listo para un próximo conteo.
- Sem internetOfflineSin internet
- O envio pode entrar em fila e ser reenviado quando a conexão volta — o rep não perde a contagem. Um identificador de transação evita que um reenvio duplique o registro.The send may be queued and retried when the connection returns — the rep doesn't lose the count. A transaction id prevents a retry from duplicating the record.El envío puede quedar en cola y reintentarse cuando vuelve la conexión — el rep no pierde el conteo. Un identificador de transacción evita que un reenvío duplique el registro.
- 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
Contagem de estoque é a transação de saída que persiste no backend a contagem por produto feita numa visita. É disparada pelo notifier da feature de contagem de estoque. Um único DispatcherType (stockCount) e um único builder cobrem todos os mercados — não há variantes nem prefixo Promo_.
Stock count is the outbound transaction that persists a per-product count from a visit in the backend. It's fired by the stock-count feature's notifier. A single DispatcherType (stockCount) and a single builder cover all markets — no variants, no Promo_ prefix.
Conteo de stock es la transacción de salida que persiste en el backend el conteo por producto hecho en una visita. Se dispara desde el notifier de la feature de conteo de stock. Un único DispatcherType (stockCount) y un único builder cubren todos los mercados — sin variantes ni prefijo Promo_.
Payload planoFlat payloadPayload plano
O contrato wire é um único array — StockTrackingDeatils — de linhas de item. Sem cabeçalho, sem sub-blocos de pagamento ou promoção.The wire contract is a single array — StockTrackingDeatils — of item lines. No header, no payment or promotion sub-blocks.El contrato wire es un único array — StockTrackingDeatils — de líneas de ítem. Sin encabezado, sin sub-bloques de pago o promoción.
Alta e baixa (uom1/uom2)High and low (uom1/uom2)Alta y baja (uom1/uom2)
A contagem alta vai em uom1Quantity; a baixa em uom2Quantity. Os nomes das unidades saem do UoM do produto (primaryName/secondaryName).The high count goes in uom1Quantity; the low in uom2Quantity. The unit names come from the product's UoM (primaryName/secondaryName).El conteo alto va en uom1Quantity; el bajo en uom2Quantity. Los nombres de las unidades salen del UoM del producto (primaryName/secondaryName).
RPC genéricoGeneric RPCRPC genérico
Como toda transação, passa pelo mesmo sendTransaction, com o JSON serializado em message e serviceName = LocationStockUploadAPI como discriminador.Like every transaction, it goes through the same sendTransaction, with the JSON serialized into message and serviceName = LocationStockUploadAPI as the discriminator.Como toda transacción, pasa por el mismo sendTransaction, con el JSON serializado en message y serviceName = LocationStockUploadAPI como discriminador.
FontesSourcesFuentes
BuildStockCountDispatcherPayloadUseCase + StockCountDispatcherPayloadInput + DispatcherType.stockCount + DispatcherConectaRep.proto. O input carrega entities cruas de domínio (CLAUDE.md §36); o build() constrói todo o wire.
BuildStockCountDispatcherPayloadUseCase + StockCountDispatcherPayloadInput + DispatcherType.stockCount + DispatcherConectaRep.proto. The input carries raw domain entities (CLAUDE.md §36); build() constructs the entire wire.
BuildStockCountDispatcherPayloadUseCase + StockCountDispatcherPayloadInput + DispatcherType.stockCount + 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) e o JSON dentro de message.The service exposes a single generic RPC — there's no per-transaction message. EVERY write transaction in the app uses this same sendTransaction; what changes is the serviceName (discriminator) and the JSON inside message.El servicio expone un único RPC genérico — no existe mensaje por transacción. TODA transacción de escritura de la app usa este mismo sendTransaction; lo que cambia es el serviceName (discriminador) y el JSON dentro de message.
sendTransactionunaryrpc sendTransaction(InboxTransactionRequest) returns (InboxTransactionReply)
path /mn.bat.conectarep.dispatcher.DispatcherConectaRepService/sendTransaction
InboxTransactionRequestendpointstring· #1 · endpoint alvo (config de ambiente; destinationsalesforce)target endpoint (environment config;salesforcedestination)endpoint destino (config de ambiente; destinationsalesforce)serviceNamestring· #2 · discriminador —LocationStockUploadAPI(sem prefixoPromo_)discriminator —LocationStockUploadAPI(noPromo_prefix)discriminador —LocationStockUploadAPI(sin prefijoPromo_)dateReferencestring· #3 ·AAAA-MM-DDdo envio (submittedAt)YYYY-MM-DDof the submission (submittedAt)AAAA-MM-DDdel envío (submittedAt)transactionReferencestring· #4 · oaccountSfiddo varejo (correlação)the retail'saccountSfid(correlation)elaccountSfiddel punto de venta (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 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). 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). 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). 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.
A Contagem de estoque não está na lista lightweight de DispatcherType.resendMayDuplicate, logo resendMayDuplicate == true: um reenvio (ex.: recuperação de fila offline) pode duplicar o registro no backend; a idempotência via tid é o que mitiga isso.Stock count is not in the lightweight set of DispatcherType.resendMayDuplicate, so resendMayDuplicate == true: a resend (e.g. offline-queue recovery) may duplicate the record on the backend; idempotency via tid is what mitigates it.El Conteo de stock no está en el conjunto lightweight de DispatcherType.resendMayDuplicate, por lo que resendMayDuplicate == true: un reenvío (p. ej. recuperación de cola offline) puede duplicar el registro en el backend; la idempotencia vía tid es lo que lo mitiga.
serviceName
Há um único DispatcherType — stockCount — sem variantes e sem campo de tipo no input. O ponto de atenção é o nome cruzado: o tipo do app se chama stockCount, mas o serviceName do contrato wire é LocationStockUploadAPI. É esse nome que o backend usa para rotear a transação.There's a single DispatcherType — stockCount — with no variants and no type field on the input. The thing to watch is the name crossover: the app type is called stockCount, but the wire-contract serviceName is LocationStockUploadAPI. That's the name the backend uses to route the transaction.Hay un único DispatcherType — stockCount — sin variantes y sin campo de tipo en el input. El punto de atención es el nombre cruzado: el tipo de la app se llama stockCount, pero el serviceName del contrato wire es LocationStockUploadAPI. Ese es el nombre que el backend usa para enrutar la transacción.
DispatcherType |
serviceName |
DestinoDestinationDestino | MercadosMarketsMercados |
|---|---|---|---|
stockCount | LocationStockUploadAPI | salesforce | BR · CL · ZA |
Nome cruzadoName crossoverNombre cruzado
stockCount (tipo do app) ≠ LocationStockUploadAPI (nome wire). Ao procurar essa transação no backend/logs, use LocationStockUploadAPI; no código do app, DispatcherType.stockCount. Não confundir com as outras transações de estoque (stockReconciliation, stockRequest, stockAllocationExecution, stockUnload), que têm serviceName próprio.
stockCount (app type) ≠ LocationStockUploadAPI (wire name). When looking this transaction up on the backend/logs, use LocationStockUploadAPI; in the app code, DispatcherType.stockCount. Don't confuse it with the other stock transactions (stockReconciliation, stockRequest, stockAllocationExecution, stockUnload), which have their own serviceName.
stockCount (tipo de la app) ≠ LocationStockUploadAPI (nombre wire). Al buscar esta transacción en el backend/logs, use LocationStockUploadAPI; en el código de la app, DispatcherType.stockCount. No confundir con las otras transacciones de stock (stockReconciliation, stockRequest, stockAllocationExecution, stockUnload), que tienen su propio serviceName.
O serviceName é resolvido por type.resolveServiceName(hasPromotion: false) — sempre false aqui, então nunca há prefixo Promo_.The serviceName is resolved by type.resolveServiceName(hasPromotion: false) — always false here, so there's never a Promo_ prefix.El serviceName se resuelve por type.resolveServiceName(hasPromotion: false) — siempre false aquí, así que nunca hay prefijo Promo_.
Como é disparadoHow it's firedCómo se dispara
A transação é orquestrada pelo StockCountNotifier.submit() (remote-first, §36). O notifier apenas reúne entities cruas e valores injetados; o builder é o dono único de todo join, rename e derivação wire. A cascata:The transaction is orchestrated by StockCountNotifier.submit() (remote-first, §36). The notifier only gathers raw entities and injected values; the builder is the sole owner of every join, rename and wire derivation. The cascade:La transacción se orquesta desde StockCountNotifier.submit() (remote-first, §36). El notifier solo reúne entities crudas y valores inyectados; el builder es el dueño único de todo join, rename y derivación wire. La cascada:
- StockCountNotifiersubmit()
- reúne entities cruas + injetadosgathers raw entities + injectedreúne entities crudas + inyectadosStockCountDispatcherPayloadInput
- build()BuildStockCountDispatcherPayloadUseCasemonta o wireassembles the wirearma el wire
- devolvereturnsdevuelveDispatcherEnvelope
- SubmitStockCountUseCaseDispatcherOrchestrator
- serializa + authserialize + authserializa + authDispatcherGateway
- sendTransactionBackendgRPC
- serializa + authserialize + authserializa + authDispatcherGateway
- SubmitStockCountUseCaseDispatcherOrchestrator
- devolvereturnsdevuelveDispatcherEnvelope
- build()BuildStockCountDispatcherPayloadUseCasemonta o wireassembles the wirearma el wire
- reúne entities cruas + injetadosgathers raw entities + injectedreúne entities crudas + inyectadosStockCountDispatcherPayloadInput
O input (entities cruas)The input (raw entities)El input (entities crudas)
StockCountDispatcherPayloadInput (Freezed). Carrega o dado como existe no domínio; nada de formato wire. O relógio chega como submittedAt (via DateTimeUtils.now()); a visita é resolvida do cache por accountSfid e o resource/market vêm dos providers de sessão.StockCountDispatcherPayloadInput (Freezed). Carries data as it exists in the domain; no wire shaping. The clock arrives as submittedAt (via DateTimeUtils.now()); the visit is resolved from cache by accountSfid and resource/market come from the session providers.StockCountDispatcherPayloadInput (Freezed). Lleva el dato como existe en el dominio; nada de formato wire. El reloj llega como submittedAt (vía DateTimeUtils.now()); la visita se resuelve del cache por accountSfid y resource/market vienen de los providers de sesión.
| CampoFieldCampo | TipoTypeTipo | PapelRoleRol |
|---|---|---|
accountSfid | String | varejo alvo (→ transactionReference e account.sfid)target retail (→ transactionReference and account.sfid)punto de venta objetivo (→ transactionReference y account.sfid) |
entries | List<StockCountEntryEntity> | contagens do rep por productSfid (highUomCount/lowUomCount)rep's counts by productSfid (highUomCount/lowUomCount)conteos del rep por productSfid (highUomCount/lowUomCount) |
products | List<ProductEntity> | catálogo contável (UoM, SKUs) — dirige a ordem das linhascountable catalog (UoM, SKUs) — drives line ordercatálogo contable (UoM, SKUs) — dirige el orden de las líneas |
resource | ResourceEntity | representante de vendas (cru — o builder deriva resourceId e location)sales rep (raw — the builder derives resourceId and location)representante de ventas (crudo — el builder deriva resourceId y location) |
visit | VisitEntity? | visita do cache (→ visit, sapCustomerId, account.name); null quando não resolvidavisit from cache (→ visit, sapCustomerId, account.name); null when unresolvedvisita del cache (→ visit, sapCustomerId, account.name); null cuando no se resuelve |
market | EndMarket | → marketIso e currencyIsoCode→ marketIso and currencyIsoCode→ marketIso y currencyIsoCode |
submittedAt | DateTime | relógio do envio (→ dateReference em yyyy-MM-dd)submission clock (→ dateReference as yyyy-MM-dd)reloj del envío (→ dateReference en yyyy-MM-dd) |
Payload (message)
O JSON serializado no campo message do request. É um objeto com uma única chave — StockTrackingDeatils (typo do contrato, mantido verbatim) — cujo valor é um array de linhas de item. Cada linha tem 24 campos e a tabela abaixo lista todos, com 4 colunas — Campo JSON · Tipo · Origem do Dado · Regra. Campo, Tipo e Origem são código cru; só a Regra é prosa. Um exemplo completo (BR, 1 item) está em transaction_example.json, ao lado deste doc.The JSON serialized into the request's message field. It's an object with a single key — StockTrackingDeatils (contract typo, kept verbatim) — whose value is an array of item lines. Each line has 24 fields and the table below lists all of them, with 4 columns — JSON field · Type · Data source · Rule. Field, Type and Source are raw code; only Rule is prose. A full example (BR, 1 item) sits in transaction_example.json, next to this doc.El JSON serializado en el campo message del request. Es un objeto con una única clave — StockTrackingDeatils (typo del contrato, mantenido verbatim) — cuyo valor es un array de líneas de ítem. Cada línea tiene 24 campos y la tabla abajo lista todos, con 4 columnas — Campo JSON · Tipo · Origen del Dato · Regla. Campo, Tipo y Origen son código crudo; solo la Regla es prosa. Un ejemplo completo (BR, 1 ítem) está en transaction_example.json, junto a este doc.
StockTrackingDeatils array — 1 chave no topoarray — 1 top-level keyarray — 1 clave en el tope 1 campofieldcampo
Única chave do payload. O valor é o array
items: uma entrada por produto deinput.productscujoproductSfidtem umaentrycorrespondente com pelo menos uma contagem (entry.hasAnyCount). Produtos sem entrada, ou com entrada vazia, são pulados.The payload's only key. The value is theitemsarray: one entry per product ininput.productswhoseproductSfidhas a matchingentrywith at least one count (entry.hasAnyCount). Products without an entry, or with an empty entry, are skipped.La única clave del payload. El valor es el arrayitems: una entrada por producto deinput.productscuyoproductSfidtenga unaentrycorrespondiente con al menos un conteo (entry.hasAnyCount). Los productos sin entrada, o con entrada vacía, se omiten.StockTrackingDeatils[] por produto contadoper counted productpor producto contado 24 camposfieldscampos
highCount=entry.highUomCount ?? 0;lowCount=entry.lowUomCount ?? 0.sku=product.manufacturingSkus.first(ou null se vazio).sapCustomerId=visit?.accountData.customerCode ?? "";visitSfid=visit?.sfid ?? "";resourceSfid= primary/secondary conformeresource.isPrimaryResource.highCount=entry.highUomCount ?? 0;lowCount=entry.lowUomCount ?? 0.sku=product.manufacturingSkus.first(or null if empty).sapCustomerId=visit?.accountData.customerCode ?? "";visitSfid=visit?.sfid ?? "";resourceSfid= primary/secondary perresource.isPrimaryResource.highCount=entry.highUomCount ?? 0;lowCount=entry.lowUomCount ?? 0.sku=product.manufacturingSkus.first(o null si vacío).sapCustomerId=visit?.accountData.customerCode ?? "";visitSfid=visit?.sfid ?? "";resourceSfid= primary/secondary segúnresource.isPrimaryResource.Campo JSON TipoTypeTipo Origem do DadoData sourceOrigen del Dato RegraRuleRegla orderPoNumberstring Fixo: ""placeholder inerteinert placeholderplaceholder inerte stockIdstring Fixo: ""placeholder inerteinert placeholderplaceholder inerte isAvailablebool CalculadohighCount > 0 || lowCount > 0highCount > 0 || lowCount > 0highCount > 0 || lowCount > 0availableQuantityint highCountsó a contagem alta (ver Pendências)high count only (see Pending)solo el conteo alto (ver Pendientes) baseUOMstring product.uom.primaryNamenome da unidade altahigh unit namenombre de la unidad alta baseUOMQuatityint highCountchave com typo ( Quatity), verbatim; só a altamisspelled key (Quatity), verbatim; high onlyclave con typo (Quatity), verbatim; solo la altabatchIdstring sku?.batchId ?? ""1º SKU do produtoproduct's 1st SKU1er SKU del producto damageQuantitystring Fixo: ""placeholder inerte (string vazia, não 0)inert placeholder (empty string, not 0)placeholder inerte (string vacío, no 0) defaultUOMstring product.uom.primaryName= baseUOM=baseUOM=baseUOMdefaultUOMQuatityint highCountchave com typo ( Quatity), verbatim; só a altamisspelled key (Quatity), verbatim; high onlyclave con typo (Quatity), verbatim; solo la altalocationstring resource.locationSfid— productIdstring product.productSfid— SKUIdstring sku?.manufacturingSkuSfid ?? ""1º SKU do produtoproduct's 1st SKU1er SKU del producto uom1Quantitystring entry.highUomCount?.toString() ?? ""contagem alta como string; ""quando não contadahigh count as string;""when uncountedconteo alto como string;""cuando no contadouom2Quantitystring entry.lowUomCount?.toString() ?? ""contagem baixa como string; único campo que carrega a baixalow count as string; the only field carrying the low countconteo bajo como string; único campo que lleva la baja uom1Namestring product.uom.primaryNamenome da unidade altahigh unit namenombre de la unidad alta uom2Namestring product.uom.secondaryNamenome da unidade baixalow unit namenombre de la unidad baja currencyIsoCodestring CurrencyUtils.isoCode(market)BRL / CLP / ZAR conforme mercadoBRL / CLP / ZAR per marketBRL / CLP / ZAR según mercado typestring Fixo: "Stock Check"constante _stockCheckType_stockCheckTypeconstantconstante_stockCheckTypevisitstring visit?.sfid ?? """"se a visita não foi resolvida""if the visit wasn't resolved""si la visita no se resolviómarketIsostring market.nameBR/CL/ZABR/CL/ZABR/CL/ZAsellableQuantityint highCountsó a contagem alta (ver Pendências)high count only (see Pending)solo el conteo alto (ver Pendientes) sapCustomerIdstring visit?.accountData.customerCode ?? ""código SAP do varejoretail's SAP codecódigo SAP del punto de venta resourceIdstring resource.primaryResourceSfid/secondaryResourceSfidprimary se isPrimaryResource, senão secondaryprimary ifisPrimaryResource, else secondaryprimary siisPrimaryResource, si no secondary
ExemploExampleEjemplo
Um payload completo (BR, 1 item, alta 5 / baixa 12) está em docs/public/dispatcher/19_stock_count/transaction_example.json — a forma exata serializada em message (sem wrapper gRPC).
A complete payload (BR, 1 item, high 5 / low 12) is in docs/public/dispatcher/19_stock_count/transaction_example.json — the exact shape serialized into message (no gRPC wrapper).
Un payload completo (BR, 1 ítem, alta 5 / baja 12) está en docs/public/dispatcher/19_stock_count/transaction_example.json — la forma exacta serializada en message (sin wrapper gRPC).
Regras de negócioBusiness rulesReglas de negocio
Inclusão de linhaLine inclusionInclusión de línea entry != null · hasAnyCount
O builder itera input.products (não as entries), indexando as contagens por productSfid. Uma linha só é emitida quando:The builder iterates input.products (not the entries), indexing the counts by productSfid. A line is emitted only when:El builder itera input.products (no las entries), indexando los conteos por productSfid. Una línea solo se emite cuando:
- existe uma
entrypara oproduct.productSfid(senãocontinue);anentryexists forproduct.productSfid(elsecontinue);existe unaentryparaproduct.productSfid(si nocontinue); - e
entry.hasAnyCounté true — ou seja,highUomCountoulowUomCountnão é null (senãocontinue).andentry.hasAnyCountis true — i.e.highUomCountorlowUomCountis non-null (elsecontinue).yentry.hasAnyCountes true — o sea,highUomCountolowUomCountno es null (si nocontinue). - A ordem das linhas segue a ordem de
input.products, não a ordem em que o rep digitou.Line order followsinput.products, not the order the rep typed.El orden de las líneas sigueinput.products, no el orden en que el rep escribió.
Unidade alta e baixaHigh and low unitUnidad alta y baja uom1 = high · uom2 = low
A contagem tem duas colunas (memória do projeto: as antigas colunas Stock/Venda foram reinterpretadas como Alta/Baixa, sem mudança de proto):The count has two columns (project note: the old Stock/Sale columns were reinterpreted as High/Low, with no proto change):El conteo tiene dos columnas (nota del proyecto: las antiguas columnas Stock/Venta fueron reinterpretadas como Alta/Baja, sin cambio de proto):
- Alta →
uom1Quantity(string) +uom1Name=primaryName.High →uom1Quantity(string) +uom1Name=primaryName.Alta →uom1Quantity(string) +uom1Name=primaryName. - Baixa →
uom2Quantity(string) +uom2Name=secondaryName.Low →uom2Quantity(string) +uom2Name=secondaryName.Baja →uom2Quantity(string) +uom2Name=secondaryName. - As quantidades
uom1Quantity/uom2Quantitysaem deentry.*.toString()—""quando o campo é null (não contado). Os demais campos numéricos usam o fallback?? 0.Theuom1Quantity/uom2Quantitycome fromentry.*.toString()—""when the field is null (uncounted). The other numeric fields use the?? 0fallback.Las cantidadesuom1Quantity/uom2Quantitysalen deentry.*.toString()—""cuando el campo es null (no contado). Los demás campos numéricos usan el fallback?? 0.
resourceId primary/secondaryresourceId primary/secondaryresourceId primary/secondary isPrimaryResource
resourceId = resource.isPrimaryResource ? resource.primaryResourceSfid : resource.secondaryResourceSfid — mesma derivação de sfid do representante usada nas demais transações de escrita (§25/§36). O location vem de resource.locationSfid, direto.resourceId = resource.isPrimaryResource ? resource.primaryResourceSfid : resource.secondaryResourceSfid — the same rep-sfid derivation used in the other write transactions (§25/§36). location comes from resource.locationSfid, directly.resourceId = resource.isPrimaryResource ? resource.primaryResourceSfid : resource.secondaryResourceSfid — la misma derivación de sfid del representante usada en las demás transacciones de escritura (§25/§36). location viene de resource.locationSfid, directo.
Envelope e datasEnvelope & datesEnvelope y fechas dateReference · account · transactionReference
dateReference=DateTimeUtils.formatDate(dateTime: submittedAt)emyyyy-MM-dd(defaultDateFormatType.isoDate).dateReference=DateTimeUtils.formatDate(dateTime: submittedAt)asyyyy-MM-dd(defaultDateFormatType.isoDate).dateReference=DateTimeUtils.formatDate(dateTime: submittedAt)enyyyy-MM-dd(defaultDateFormatType.isoDate).transactionReference=input.accountSfid(correlação).transactionReference=input.accountSfid(correlation).transactionReference=input.accountSfid(correlación).account=DispatchAccountEntity(sfid: accountSfid, sapCode: sapCustomerId, name: visit?.accountData.name ?? "")— metadados do varejo para tracking.account=DispatchAccountEntity(sfid: accountSfid, sapCode: sapCustomerId, name: visit?.accountData.name ?? "")— retail metadata for tracking.account=DispatchAccountEntity(sfid: accountSfid, sapCode: sapCustomerId, name: visit?.accountData.name ?? "")— metadatos del punto de venta para tracking.
Pendências / roadmapPending / roadmapPendientes / roadmap
O que o builder envia inerte ou de forma parcial, documentado fiel ao estado atual do código (nunca descrito como se já existisse):What the builder ships inert or partially, documented faithfully to the current code state (never described as already existing):Lo que el builder envía inerte o de forma parcial, documentado fiel al estado actual del código (nunca descrito como si ya existiera):
Não portado / pendenteNot ported / pendingNo portado / pendiente
- Campos numéricos só carregam a contagem alta:
availableQuantity,baseUOMQuatity,defaultUOMQuatityesellableQuantitysão todoshighCount. A contagem baixa (lowCount) só viaja como string emuom2Quantity— nenhum campo numérico a carrega.Numeric fields carry only the high count:availableQuantity,baseUOMQuatity,defaultUOMQuatityandsellableQuantityare allhighCount. The low count (lowCount) only travels as a string inuom2Quantity— no numeric field carries it.Los campos numéricos solo llevan el conteo alto:availableQuantity,baseUOMQuatity,defaultUOMQuatityysellableQuantityson todoshighCount. El conteo bajo (lowCount) solo viaja como string enuom2Quantity— ningún campo numérico lo lleva. StockTrackingDeatilsebaseUOMQuatity/defaultUOMQuatity: chaves com typo (Deatils,Quatity) mantidas verbatim — contrato do backend.StockTrackingDeatilsandbaseUOMQuatity/defaultUOMQuatity: misspelled keys (Deatils,Quatity) kept verbatim — backend contract.StockTrackingDeatilsybaseUOMQuatity/defaultUOMQuatity: claves con typo (Deatils,Quatity) mantenidas verbatim — contrato del backend.orderPoNumber,stockId,damageQuantity: sempre""— placeholders inertes do contrato, o app não os popula.orderPoNumber,stockId,damageQuantity: always""— inert contract placeholders, the app doesn't populate them.orderPoNumber,stockId,damageQuantity: siempre""— placeholders inertes del contrato, la app no los completa.batchIdeSKUId: usam só o 1ºmanufacturingSkudo produto (.first). Produtos com múltiplos SKUs contam com apenas um representado;""quando o produto não tem SKU.batchIdandSKUId: use only the product's 1stmanufacturingSku(.first). Products with multiple SKUs have just one represented;""when the product has no SKU.batchIdySKUId: usan solo el 1ermanufacturingSkudel producto (.first). Los productos con múltiples SKUs tienen solo uno representado;""cuando el producto no tiene SKU.isAvailableé derivado da própria contagem (> 0), não de uma disponibilidade real de estoque.isAvailableis derived from the count itself (> 0), not from a real stock availability.isAvailablese deriva del propio conteo (> 0), no de una disponibilidad real de stock.- 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).
MercadosMarketsMercados
A disponibilidade da transação vem do DispatcherType.stockCount.enabledMarkets = BR/CL/ZA. O build() é market-agnostic: a estrutura do payload é idêntica nos três; só marketIso e currencyIsoCode variam por mercado. AR/PY/PE não têm dispatcher de contagem de estoque.Transaction availability comes from DispatcherType.stockCount.enabledMarkets = BR/CL/ZA. The build() is market-agnostic: the payload structure is identical across the three; only marketIso and currencyIsoCode vary per market. AR/PY/PE have no stock-count dispatcher.La disponibilidad de la transacción viene de DispatcherType.stockCount.enabledMarkets = BR/CL/ZA. El build() es market-agnostic: la estructura del payload es idéntica en los tres; solo marketIso y currencyIsoCode varían por mercado. AR/PY/PE no tienen dispatcher de conteo de stock.
Mesma forma nos trêsSame shape in all threeMisma forma en los tres
O builder não ramifica por mercado. A moeda (currencyIsoCode) e o ISO (marketIso) refletem o mercado ativo; os nomes de unidade (uom1Name/uom2Name) vêm do catálogo de cada mercado.
The builder doesn't branch per market. The currency (currencyIsoCode) and ISO (marketIso) reflect the active market; the unit names (uom1Name/uom2Name) come from each market's catalog.
El builder no ramifica por mercado. La moneda (currencyIsoCode) y el ISO (marketIso) reflejan el mercado activo; los nombres de unidad (uom1Name/uom2Name) vienen del catálogo de cada mercado.
AR · PY · PE
Existem como mercados do app (config PANGEA mínima), mas não têm dispatcher de contagem de estoque — stockCount.enabledMarkets não os lista. A contagem de estoque não é disparada nesses mercados.
They exist as app markets (minimal PANGEA config), but have no stock-count dispatcher — stockCount.enabledMarkets doesn't list them. Stock count is not fired in these markets.
Existen como mercados de la app (config PANGEA mínima), pero no tienen dispatcher de conteo de stock — stockCount.enabledMarkets no los lista. El conteo de stock no se dispara en estos mercados.