Solicitação de recompraBuyback requestSolicitud de recompra
A transação de escrita que solicita a devolução de mercadoria de um varejo para a companhia. É o primeiro passo do ciclo de vida da Recompra: o representante de vendas escolhe produtos, data de coleta e motivo, e envia o pedido de recompra pelo Dispatcher. Toda a construção do contrato wire vive no builder. The write transaction that requests the return of goods from a retail back to the company. It's the first step of the Buyback lifecycle: the sales rep picks products, a collection date and a reason, and submits the buyback request through the Dispatcher. All wire-contract construction lives in the builder. La transacción de escritura que solicita la devolución de mercadería de un punto de venta a la compañía. Es el primer paso del ciclo de vida de la Recompra: el representante de ventas elige productos, fecha de recolección y motivo, y envía la solicitud de recompra por el Dispatcher. Toda la construcción del contrato wire vive en el builder.
O que é e quando aconteceWhat it is and when it happensQué es y cuándo ocurre
Quando o representante de vendas precisa devolver mercadoria de um varejo para a companhia — produto vencido, avariado ou fora de linha — ele abre uma solicitação de recompra. Esta transação é o que leva esse pedido de devolução ao backend: escolhidos os produtos, a data de coleta e o motivo, o app envia a solicitação e ela passa a existir no sistema como uma recompra à espera de coleta. When the sales rep needs to return goods from a retail back to the company — expired, damaged or discontinued product — they open a buyback request. This transaction is what carries that return request to the backend: once the products, the collection date and the reason are set, the app sends the request and it starts to exist in the system as a buyback awaiting collection. Cuando el representante de ventas necesita devolver mercadería de un punto de venta a la compañía — producto vencido, dañado o fuera de línea — abre una solicitud de recompra. Esta transacción es la que lleva ese pedido de devolución al backend: elegidos los productos, la fecha de recolección y el motivo, la app envía la solicitud y pasa a existir en el sistema como una recompra a la espera de recolección.
A solicitação é o primeiro dos dois lados do ciclo de recompra. O outro é a execução — aceitar, rejeitar ou reagendar a coleta já agendada — que é uma transação separada.The request is the first of the two sides of the buyback cycle. The other is execution — accepting, rejecting or rescheduling the already scheduled collection — which is a separate transaction.La solicitud es el primero de los dos lados del ciclo de recompra. El otro es la ejecución — aceptar, rechazar o reprogramar la recolección ya agendada — que es una transacción separada.
Produtos + quantidadesProducts + quantitiesProductos + cantidades
O rep escolhe o que o varejo vai devolver, por categoria, com a quantidade de cada item.The rep picks what the retail will return, by category, with the quantity of each item.El rep elige qué devolverá el punto de venta, por categoría, con la cantidad de cada ítem.
Data de coletaCollection dateFecha de recolección
A data em que a mercadoria será recolhida — só dias úteis, numa janela de 60 dias.The date when the goods will be uplifted — business days only, in a 60-day window.La fecha en que se recogerá la mercadería — solo días hábiles, en una ventana de 60 días.
MotivoReasonMotivo
O motivo da devolução, escolhido num dropdown; acompanha a solicitação até o backend.The reason for the return, chosen from a dropdown; travels with the request to the backend.El motivo de la devolución, elegido en un dropdown; acompaña la solicitud hasta el backend.
Sempre por varejo/visitaAlways per retail/visitSiempre por punto de venta/visita A recompra abre sempre no contexto de uma visita ao varejo. Não existe solicitação avulsa: ela nasce do detalhe da visita. Buyback always opens in the context of a visit to the retail. There's no standalone request: it starts from the visit detail. La recompra abre siempre en el contexto de una visita al punto de venta. No hay solicitud suelta: nace del detalle de la visita.
Fluxo de telas que disparaScreen flow that fires itFlujo de pantallas que lo dispara
A transação é o último passo da solicitação de recompra. As telas do caminho pertencem à feature de Recompra; aqui só situamos onde o envio acontece:The transaction is the last step of the buyback request. The screens along the way belong to the Buyback feature; here we only place where the send happens:La transacción es el último paso de la solicitud de recompra. Las pantallas del camino pertenecen a la feature de Recompra; aquí solo situamos dónde ocurre el envío:
- Detalhe da visitaVisit detailDetalle de la visitaO rep entra na visita do varejo e abre a ferramenta de recompra.The rep enters the retail's visit and opens the buyback tool.El rep entra a la visita del punto de venta y abre la herramienta de recompra.
- Menu da recompraBuyback menuMenú de la recompraEscolhe a opção Solicitar (a outra opção, Coleta, é a execução).Picks the Request option (the other option, Collection, is execution).Elige la opción Solicitar (la otra opción, Recolección, es la ejecución).
- Escolha de produtosProduct selectionSelección de productosSeleciona produtos e quantidades por categoria; a barra de resumo mostra itens + total.Selects products and quantities per category; the summary bar shows items + total.Selecciona productos y cantidades por categoría; la barra de resumen muestra ítems + total.
- ResumoSummaryResumenDefine a data de coleta (dias úteis, 60 dias) e o motivo (dropdown), e revê os itens.Sets the collection date (business days, 60 days) and the reason (dropdown), and reviews the items.Define la fecha de recolección (días hábiles, 60 días) y el motivo (dropdown), y revisa los ítems.
- Confirmar → esta transaçãoConfirm → this transactionConfirmar → esta transacciónAo tocar em Confirmar, o app dispara a Solicitação de recompra e limpa o rascunho. É este toque que aciona a transação.Tapping Confirm fires the Buyback request and clears the draft. This tap is what triggers the transaction.Al tocar Confirmar, la app dispara la Solicitud de recompra y limpia el borrador. Este toque es lo que activa la transacción.
Próximo passo do cicloNext step of the cyclePróximo paso del ciclo Depois da solicitação, a recompra fica agendada e volta ao rep pela tela de Coleta, onde é executada (aceitar/rejeitar/reagendar) — a transação 21 · Execução de recompra. After the request, the buyback is scheduled and comes back to the rep on the Collection screen, where it's executed (accept/reject/reschedule) — the 21 · Buyback execution transaction. Tras la solicitud, la recompra queda agendada y vuelve al rep por la pantalla de Recolección, donde se ejecuta (aceptar/rechazar/reprogramar) — la transacción 21 · Ejecución de recompra.
Depois do envioAfter sendingDespués del envío
- Confirmação ao repConfirmation to the repConfirmación al rep
- Ao confirmar, a solicitação é enviada e o rascunho é limpo. A recompra passa a constar como agendada e aparece na tela de coleta com status à espera.On confirm, the request is sent and the draft is cleared. The buyback becomes scheduled and shows up on the collection screen with a waiting status.Al confirmar, la solicitud se envía y el borrador se limpia. La recompra pasa a constar como agendada y aparece en la pantalla de recolección con estado en espera.
- Sem internetOfflineSin internet
- O envio pode entrar em fila e ser reenviado quando a conexão volta — o rep não perde a solicitação. Um reenvio pode, em tese, duplicar; o sistema usa um identificador de transação para evitar isso.The send may be queued and retried when the connection returns — the rep doesn't lose the request. A retry could, in theory, duplicate; the system uses a transaction id to avoid that.El envío puede quedar en cola y reintentarse cuando vuelve la conexión — el rep no pierde la solicitud. Un reenvío podría, en teoría, duplicar; el sistema usa un identificador de transacción para evitarlo.
- 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
Solicitação de recompra é a transação de saída que persiste um pedido de devolução no backend. Não tem RPC próprio: passa pelo Dispatcher com serviceName SalesReturnSEN. Um único builder monta o payload JSON — cabeçalho (SalesReturnHeader) + linhas de item (SalesReturnDetails) — a partir de entities cruas de domínio.
Buyback request is the outbound transaction that persists a return request in the backend. It has no proto of its own: it goes through the Dispatcher with serviceName SalesReturnSEN. A single builder assembles the JSON payload — header (SalesReturnHeader) + line items (SalesReturnDetails) — from raw domain entities.
Solicitud de recompra es la transacción de salida que persiste un pedido de devolución en el backend. No tiene RPC propio: pasa por el Dispatcher con serviceName SalesReturnSEN. Un único builder arma el payload JSON — encabezado (SalesReturnHeader) + líneas de ítem (SalesReturnDetails) — desde entities crudas de dominio.
Payload cabeçalho + linhasHeader + lines payloadPayload encabezado + líneas
Um único cabeçalho SalesReturnHeader e uma linha SalesReturnDetails por produto devolvido (quantidade > 0).A single SalesReturnHeader and one SalesReturnDetails line per returned product (quantity > 0).Un único SalesReturnHeader y una línea SalesReturnDetails por producto devuelto (cantidad > 0).
UoM + preço vigenteUoM + current priceUdM + precio vigente
Cada linha resolve unidade de medida (primária/secundária) e o preço vigente do produto no grupo de preço da conta.Each line resolves the unit of measure (primary/secondary) and the product's current price in the account's pricing group.Cada línea resuelve la unidad de medida (primaria/secundaria) y el precio vigente del producto en el grupo de precio de la cuenta.
RPC genéricoGeneric RPCRPC genérico
Não há RPC de recompra: tudo passa pelo mesmo sendTransaction, com o JSON no campo message e o serviceName como discriminador.There's no buyback RPC: everything goes through the same sendTransaction, with the JSON in the message field and serviceName as the discriminator.No hay RPC de recompra: todo pasa por el mismo sendTransaction, con el JSON en el campo message y el serviceName como discriminador.
FontesSourcesFuentes
BuildBuybackRequestDispatcherPayloadUseCase + BuybackRequestDispatcherPayloadInput + DispatcherType.buybackRequest + DispatcherConectaRep.proto. O input carrega entities cruas de domínio (CLAUDE.md §36); o build() constrói todo o wire.
BuildBuybackRequestDispatcherPayloadUseCase + BuybackRequestDispatcherPayloadInput + DispatcherType.buybackRequest + DispatcherConectaRep.proto. The input carries raw domain entities (CLAUDE.md §36); build() constructs the entire wire.
BuildBuybackRequestDispatcherPayloadUseCase + BuybackRequestDispatcherPayloadInput + DispatcherType.buybackRequest + 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, SalesReturnSEN aqui) 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, SalesReturnSEN here) 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, SalesReturnSEN aquí) 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 —SalesReturnSEN(sem prefixoPromo_: recompra não tem promoção)discriminator —SalesReturnSEN(noPromo_prefix: buyback has no promotion)discriminador —SalesReturnSEN(sin prefijoPromo_: la recompra no tiene promoción)dateReferencestring· #3 ·AAAA-MM-DDdo envio (submittedAt)YYYY-MM-DDof the submission (submittedAt)AAAA-MM-DDdel envío (submittedAt)transactionReferencestring· #4 · opurchaseOrderNumber(correlação)thepurchaseOrderNumber(correlation)elpurchaseOrderNumber(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: buybackRequest, serviceName: SalesReturnSEN, payload, account: DispatchAccountEntity(sfid: accountSfid), transactionReference: purchaseOrderNumber, dateReference = submittedAt como yyyy-MM-dd). O DispatcherGateway serializa payload em JSON para message, copia os campos do envelope, preenche dispositivo e bearer token, e chama o RPC.
The builder returns a DispatcherEnvelope (type: buybackRequest, serviceName: SalesReturnSEN, payload, account: DispatchAccountEntity(sfid: accountSfid), transactionReference: purchaseOrderNumber, dateReference = submittedAt as yyyy-MM-dd). The DispatcherGateway serializes payload to JSON into message, copies the envelope fields, fills in device and bearer token, and calls the RPC.
El builder devuelve un DispatcherEnvelope (type: buybackRequest, serviceName: SalesReturnSEN, payload, account: DispatchAccountEntity(sfid: accountSfid), transactionReference: purchaseOrderNumber, dateReference = submittedAt como yyyy-MM-dd). El DispatcherGateway serializa payload a JSON en message, copia los campos del envelope, completa dispositivo y bearer token, y llama al RPC.
Destino: DispatcherDestination.salesforce (default). resendMayDuplicate == true: um reenvío (ex.: recuperação de fila offline) pode duplicar a solicitação no backend; a idempotência via tid é o que mitiga isso.Destination: DispatcherDestination.salesforce (default). resendMayDuplicate == true: a resend (e.g. offline-queue recovery) may duplicate the request on the backend; idempotency via tid is what mitigates it.Destino: DispatcherDestination.salesforce (default). resendMayDuplicate == true: un reenvío (p. ej. recuperación de cola offline) puede duplicar la solicitud en el backend; la idempotencia vía tid es lo que lo mitiga.
Como é disparadoHow it's firedCómo se dispara
A transação é orquestrada pelo fluxo de recompra (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 buyback 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 recompra (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:
- BuybackRequestSummaryNotifiersubmit()
- reúne entities cruas + injetadosgathers raw entities + injectedreúne entities crudas + inyectadosBuybackRequestDispatcherPayloadInput
- build()BuildBuybackRequestDispatcherPayloadUseCasemonta o wireassembles the wirearma el wire
- devolvereturnsdevuelveDispatcherEnvelope
- SubmitBuybackRequestUseCaseDispatcherOrchestrator
- serializa + authserialize + authserializa + authDispatcherGateway
- sendTransactionBackendgRPC
- serializa + authserialize + authserializa + authDispatcherGateway
- SubmitBuybackRequestUseCaseDispatcherOrchestrator
- devolvereturnsdevuelveDispatcherEnvelope
- build()BuildBuybackRequestDispatcherPayloadUseCasemonta o wireassembles the wirearma el wire
- reúne entities cruas + injetadosgathers raw entities + injectedreúne entities crudas + inyectadosBuybackRequestDispatcherPayloadInput
O input (entities cruas)The input (raw entities)El input (entities crudas)
BuybackRequestDispatcherPayloadInput (Freezed). Carrega o dado como existe no domínio; nada de formato wire. O relógio chega como submittedAt (via DateTimeUtils.now()); a config vem do End Market Configuration.BuybackRequestDispatcherPayloadInput (Freezed). Carries data as it exists in the domain; no wire shaping. The clock arrives as submittedAt (via DateTimeUtils.now()); the config comes from the End Market Configuration.BuybackRequestDispatcherPayloadInput (Freezed). Lleva el dato como existe en el dominio; nada de formato wire. El reloj llega como submittedAt (vía DateTimeUtils.now()); la config viene del End Market Configuration.
| CampoFieldCampo | TipoTypeTipo | PapelRoleRol |
|---|---|---|
resource | ResourceEntity | representante de vendas (cru — o builder deriva ResId primary/secondary)sales rep (raw — the builder derives ResId primary/secondary)representante de ventas (crudo — el builder deriva ResId primary/secondary) |
accountSfid | String | → RetailerId · account do envelopeof the envelopedel envelope |
accountPricingGroupId | String | grupo de preço da conta — o builder resolve o preço vigente de cada produtoaccount pricing group — the builder resolves each product's current pricegrupo de precio de la cuenta — el builder resuelve el precio vigente de cada producto |
purchaseOrderNumber | String | PO gerado local (OrderIdentifierUtils.generatePurchaseOrderNumber: "R" + data compacta + 5 dígitos aleatórios) → uid (cabeçalho e linhas) · transactionReferencelocally generated PO (OrderIdentifierUtils.generatePurchaseOrderNumber: "R" + compact date + 5 random digits) → uid (header and lines) · transactionReferencePO generado local (OrderIdentifierUtils.generatePurchaseOrderNumber: "R" + fecha compacta + 5 dígitos aleatorios) → uid (encabezado y líneas) · transactionReference |
submittedAt | DateTime | relógio (DateTimeUtils.now()) → date_x, dateReference, data de preçoclock (DateTimeUtils.now()) → date_x, dateReference, pricing datereloj (DateTimeUtils.now()) → date_x, dateReference, fecha de precio |
collectionDate | DateTime | → upliftDate (data escolhida de coletachosen collection datefecha elegida de recolección) |
reasonCode | String | → ReasonCode (motivo escolhido no dropdown; opções de GetBuybackReasonsUseCase — reference data buybackReasonsreason chosen in the dropdown; options from GetBuybackReasonsUseCase — reference data buybackReasonsmotivo elegido en el dropdown; opciones de GetBuybackReasonsUseCase — reference data buybackReasons) |
market | EndMarket | → MarketISO (market.name.toUpperCase()) |
lines | List<BuybackRequestLineInput> | itens cru (product + quantity) → uma linha por item com quantity > 0raw items (product + quantity) → one line per item with quantity > 0ítems crudos (product + quantity) → una línea por ítem con quantity > 0 |
buybackData | BuybackDataEntity | limit + isSENApprovalActive (reference data) → gate de aprovação SEN e CreditLimitlimit + isSENApprovalActive (reference data) → SEN approval gate and CreditLimitlimit + isSENApprovalActive (reference data) → gate de aprobación SEN y CreditLimit |
buybackRequestConfig | BuybackRequestConfig · const() | config por mercado (EMC): fields (quais chaves opcionais preencher) + usesSecondaryUomForAllCategoriesper-market config (EMC): fields (which optional keys to fill) + usesSecondaryUomForAllCategoriesconfig por mercado (EMC): fields (qué claves opcionales completar) + usesSecondaryUomForAllCategories |
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 (2 raiz + 17 cabeçalho + 17 por linha). Todos os valores são emitidos como string (o builder usa .toString()). Campo, Tipo e Origem são código cru; só a Regra é prosa. Um exemplo completo (BR) 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 (2 root + 17 header + 17 per line). All values are emitted as strings (the builder uses .toString()). Field, Type and Source are raw code; only Rule is prose. A full example (BR) 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 (2 raíz + 17 encabezado + 17 por línea). Todos los valores se emiten como string (el builder usa .toString()). Campo, Tipo y Origen son código crudo; solo la Regla es prosa. Un ejemplo completo (BR) 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 |
|---|---|---|---|
SalesReturnHeader | array | _buildHeader | array de um único objeto (cabeçalho)single-element array (header)array de un solo objeto (encabezado) |
SalesReturnDetails | array | _buildDetail | uma entrada por linha com quantity > 0one entry per line with quantity > 0una entrada por línea con quantity > 0 |
SalesReturnHeader objeto únicosingle objectobjeto único 17 camposfieldscampos
Campo JSON TipoTypeTipo Origem do DadoData sourceOrigen del Dato RegraRuleRegla uidstring purchaseOrderNumberPO da solicitação (correlaciona cabeçalho ↔ linhas)request PO (correlates header ↔ lines)PO de la solicitud (correlaciona encabezado ↔ líneas) ResIdstring Calculadoresource.isPrimaryResource ? primaryResourceSfid : secondaryResourceSfidresource.isPrimaryResource ? primaryResourceSfid : secondaryResourceSfidresource.isPrimaryResource ? primaryResourceSfid : secondaryResourceSfidRetailerIdstring accountSfid— date_xstring submittedAtformato yyyy/MM/ddyyyy/MM/ddformatformatoyyyy/MM/ddReturnValuestring CalculadoΣ priceWithVat × quantityde todas as linhas (sem arredondar;.toString())ΣpriceWithVat × quantityover all lines (unrounded;.toString())ΣpriceWithVat × quantityde todas las líneas (sin redondear;.toString())MarketISOstring market.name.toUpperCase()(ex.:BR,CL).toUpperCase()(e.g.BR,CL).toUpperCase()(p. ej.BR,CL)ReasonCodestring reasonCodemotivo escolhido no dropdownreason chosen in the dropdownmotivo elegido en el dropdown tagNumberstring Fixo: ""contrato · inertecontract · inertcontrato · inerte upliftDatestring collectionDateformato yyyy/MM/dd(data da coleta)yyyy/MM/ddformat (collection date)formatoyyyy/MM/dd(fecha de recolección)CreditLimitstring buybackData.limitse config.includes(creditLimit)→limit.toInt().toString(); senão""ifconfig.includes(creditLimit)→limit.toInt().toString(); else""siconfig.includes(creditLimit)→limit.toInt().toString(); si no""DiscPercstring Fixo: ""contrato · inertecontract · inertcontrato · inerte CTLovIdstring Calculadose config.includes(ctLovId)→"Credit Note"; senão""ifconfig.includes(ctLovId)→"Credit Note"; else""siconfig.includes(ctLovId)→"Credit Note"; si no""LPValstring Fixo: ""contrato · inertecontract · inertcontrato · inerte TripIDstring Fixo: ""contrato · inertecontract · inertcontrato · inerte conversionMethodstring Calculadose config.includes(conversionMethod)→"Credit Note"; senão""ifconfig.includes(conversionMethod)→"Credit Note"; else""siconfig.includes(conversionMethod)→"Credit Note"; si no""returnGrantedPercentagestring Calculadose config.includes(returnGrantedPercentage)→"100"; senão""ifconfig.includes(returnGrantedPercentage)→"100"; else""siconfig.includes(returnGrantedPercentage)→"100"; si no""approvalStatusstring Calculadose config.includes(approvalStatus)→ gate SEN (ver Regras):"Pending Approval"ou"Ordered"; senão""ifconfig.includes(approvalStatus)→ SEN gate (see Rules):"Pending Approval"or"Ordered"; else""siconfig.includes(approvalStatus)→ gate SEN (ver Reglas):"Pending Approval"o"Ordered"; si no""SalesReturnDetails por linha (item)per line (item)por línea (ítem) 17 camposfieldscampos
Uma entrada por item com
quantity > 0. A UoM (primária/secundária) e os campos por tipo de unidade (pcs/case/outer) são resolvidos por linha — ver Regras de negócio.One entry per item withquantity > 0. The UoM (primary/secondary) and per-unit-type fields (pcs/case/outer) are resolved per line — see Business rules.Una entrada por ítem conquantity > 0. La UdM (primaria/secundaria) y los campos por tipo de unidad (pcs/case/outer) se resuelven por línea — ver Reglas de negocio.Campo JSON TipoTypeTipo Origem do DadoData sourceOrigen del Dato RegraRuleRegla ReturnUOMQtystring line.quantityquantidade devolvida (na UoM de retorno)returned quantity (in the return UoM)cantidad devuelta (en la UdM de retorno) ProductIdstring product.productSfid— uidstring purchaseOrderNumbermesmo uiddo cabeçalhosameuidas the headermismouiddel encabezadopcsUomstring Calculadouom1Nameseuom1Name == "PK"(pack); senão""uom1Nameifuom1Name == "PK"(pack); else""uom1Namesiuom1Name == "PK"(pack); si no""caseUomstring Calculadouom2Nameseuom2Name == "CT"(case); senão""uom2Nameifuom2Name == "CT"(case); else""uom2Namesiuom2Name == "CT"(case); si no""outerUomstring Calculadouom1Namese ∈{OUT, EA}; senão""uom1Nameif in{OUT, EA}; else""uom1Namesi ∈{OUT, EA}; si no""ReturnUOMstring CalculadoconsiderSecondary ? uom2Name : uom1NameconsiderSecondary ? uom2Name : uom1NameconsiderSecondary ? uom2Name : uom1NametotQtyUOM1string Calculadoquantidade total convertida para UoM1 ( splitHalfPackouquantity)total quantity converted to UoM1 (splitHalfPackorquantity)cantidad total convertida a UoM1 (splitHalfPackoquantity)totalamountstring CalculadopriceWithVat × quantity(sem arredondar)priceWithVat × quantity(unrounded)priceWithVat × quantity(sin redondear)ReturnUOMPricestring CalculadopriceWithVat(preço unitário vigente, com VAT)priceWithVat(current unit price, with VAT)priceWithVat(precio unitario vigente, con VAT)DiscPercstring Fixo: ""contrato · inertecontract · inertcontrato · inerte DiscAmountstring Fixo: ""contrato · inertecontract · inertcontrato · inerte batchidstring price.manufacturingSkuBatchIdbatch da entrada de preço vigentebatch of the current price entrybatch de la entrada de precio vigente outerQtystring Calculadouom1Quantityse outer/each; senão""uom1Quantityif outer/each; else""uom1Quantitysi outer/each; si no""caseQtystring Calculadouom2Quantityse case; senão""uom2Quantityif case; else""uom2Quantitysi case; si no""pcsQtystring Calculadouom1Quantityse pack; senão""uom1Quantityif pack; else""uom1Quantitysi pack; si no""UOMNumstring CalculadoconsiderSecondary ? "UOM 2" : "UOM 1"considerSecondary ? "UOM 2" : "UOM 1"considerSecondary ? "UOM 2" : "UOM 1"
Regras de negócioBusiness rulesReglas de negocio
Resolução de UoM (primária / secundária)UoM resolution (primary / secondary)Resolución de UdM (primaria / secundaria) considerSecondary · splitHalfPack
considerSecondary=ProductUomUtils.shouldConsiderSecondaryUom(category, config.usesSecondaryUomForAllCategories). Decide se a linha usa a unidade secundária (ex.: caixa) ou fica só na primária.considerSecondary=ProductUomUtils.shouldConsiderSecondaryUom(category, config.usesSecondaryUomForAllCategories). Decides whether the line uses the secondary unit (e.g. case) or stays on the primary.considerSecondary=ProductUomUtils.shouldConsiderSecondaryUom(category, config.usesSecondaryUomForAllCategories). Decide si la línea usa la unidad secundaria (p. ej. caja) o se queda en la primaria.- Com secundária:
splitHalfPack(quantity, conversionFactor, halfPack.allowed, halfPack.increment)devolveuom1Quantity,uom2QuantityetotalQuantityInUom1.UOMNum = "UOM 2".With secondary:splitHalfPack(quantity, conversionFactor, halfPack.allowed, halfPack.increment)returnsuom1Quantity,uom2QuantityandtotalQuantityInUom1.UOMNum = "UOM 2".Con secundaria:splitHalfPack(quantity, conversionFactor, halfPack.allowed, halfPack.increment)devuelveuom1Quantity,uom2QuantityytotalQuantityInUom1.UOMNum = "UOM 2". - Sem secundária:
uom1Quantity = quantity,uom2Quantity = 0,totalQuantityInUom1 = quantity.UOMNum = "UOM 1".Without secondary:uom1Quantity = quantity,uom2Quantity = 0,totalQuantityInUom1 = quantity.UOMNum = "UOM 1".Sin secundaria:uom1Quantity = quantity,uom2Quantity = 0,totalQuantityInUom1 = quantity.UOMNum = "UOM 1". - Os três campos de unidade são mutuamente exclusivos por linha, pela unidade do produto:
pcsUom/pcsQtyquandouom1 == PK;outerUom/outerQtyquandouom1 ∈ {OUT, EA};caseUom/caseQtyquandouom2 == CT. Os demais saem"".The three unit fields are mutually exclusive per line, by the product's unit:pcsUom/pcsQtywhenuom1 == PK;outerUom/outerQtywhenuom1 ∈ {OUT, EA};caseUom/caseQtywhenuom2 == CT. The others come out"".Los tres campos de unidad son mutuamente excluyentes por línea, por la unidad del producto:pcsUom/pcsQtycuandouom1 == PK;outerUom/outerQtycuandouom1 ∈ {OUT, EA};caseUom/caseQtycuandouom2 == CT. Los demás salen"".
Gate de aprovação SENSEN approval gateGate de aprobación SEN approvalStatus · senApprovalReached
senApprovalReached = buybackData.isSENApprovalActive && returnValue >= buybackData.limit: quando a aprovação SEN está ativa e o valor total da devolução atinge o limite, a solicitação precisa passar por aprovação.senApprovalReached = buybackData.isSENApprovalActive && returnValue >= buybackData.limit: when SEN approval is active and the total return value reaches the limit, the request must go through approval.senApprovalReached = buybackData.isSENApprovalActive && returnValue >= buybackData.limit: cuando la aprobación SEN está activa y el valor total de la devolución alcanza el límite, la solicitud debe pasar por aprobación.approvalStatussó é emitido seconfig.includes(approvalStatus): entãosenApprovalReached ? "Pending Approval" : "Ordered". Sem a config, sai"".approvalStatusis emitted only ifconfig.includes(approvalStatus): thensenApprovalReached ? "Pending Approval" : "Ordered". Without the config, it's"".approvalStatusse emite solo siconfig.includes(approvalStatus): entoncessenApprovalReached ? "Pending Approval" : "Ordered". Sin la config, sale"".buybackData(limit,isSENApprovalActive) vem do reference data do mercado. SEN = Sales-return Escalation/Notification: o teto de valor a partir do qual a devolução exige aprovação.buybackData(limit,isSENApprovalActive) comes from the market's reference data. SEN = the value ceiling above which the return requires approval.buybackData(limit,isSENApprovalActive) viene del reference data del mercado. SEN = el techo de valor a partir del cual la devolución exige aprobación.
Campos opcionais por config (EMC)Config-gated fields (EMC)Campos opcionales por config (EMC) BuybackRequestField · includes()
Cinco chaves do cabeçalho são ligadas por config (config.includes(field)). Cada mercado declara em BuybackRequestConfig.fields quais preenche; as ausentes saem "". Valores emitidos quando presentes:Five header keys are config-gated (config.includes(field)). Each market declares in BuybackRequestConfig.fields which ones it fills; absent ones come out "". Values emitted when present:Cinco claves del encabezado son activadas por config (config.includes(field)). Cada mercado declara en BuybackRequestConfig.fields cuáles completa; las ausentes salen "". Valores emitidos cuando están presentes:
| BuybackRequestField | Chave JSONJSON keyClave JSON | Valor quando presenteValue when presentValor cuando presente |
|---|---|---|
creditLimit | CreditLimit | buybackData.limit.toInt().toString() |
ctLovId | CTLovId | "Credit Note" |
conversionMethod | conversionMethod | "Credit Note" |
returnGrantedPercentage | returnGrantedPercentage | "100" |
approvalStatus | approvalStatus | "Pending Approval" / "Ordered" |
Preço vigente e filtro de linhasCurrent price & line filterPrecio vigente y filtro de líneas ResolveProductPricingUseCase · quantity > 0
- O preço de cada linha vem de
ResolveProductPricingUseCase.execute(product, accountPricingGroupId, pricingDate: submittedAt): entrada de preço vigente na data do grupo de preço da conta. Usa-sepriceWithVat(com imposto) emanufacturingSkuBatchId.Each line's price comes fromResolveProductPricingUseCase.execute(product, accountPricingGroupId, pricingDate: submittedAt): the price entry valid on that date in the account's pricing group. It usespriceWithVat(tax-inclusive) andmanufacturingSkuBatchId.El precio de cada línea viene deResolveProductPricingUseCase.execute(product, accountPricingGroupId, pricingDate: submittedAt): la entrada de precio vigente en esa fecha en el grupo de precio de la cuenta. UsapriceWithVat(con impuesto) ymanufacturingSkuBatchId. ReturnValue(cabeçalho) somapriceWithVat × quantitysobre todas aslinesdo input — inclusive as comquantity == 0(que não geram linha emSalesReturnDetails, mas contribuem 0 à soma).ReturnValue(header) sumspriceWithVat × quantityover all inputlines— including those withquantity == 0(which produce noSalesReturnDetailsrow, but add 0 to the sum).ReturnValue(encabezado) sumapriceWithVat × quantitysobre todas laslinesdel input — incluidas las conquantity == 0(que no generan fila enSalesReturnDetails, pero suman 0).SalesReturnDetailssó recebe linhas comquantity > 0.SalesReturnDetailsonly receives lines withquantity > 0.SalesReturnDetailssolo recibe líneas conquantity > 0.
Formatos de data e valoresDate & value formatsFormatos de fecha y valores yyyy/MM/dd · yyyy-MM-dd · toString()
- Datas do payload (
date_x,upliftDate):yyyy/MM/dd(DateFormatType.slashYearMonthDay).Payload dates (date_x,upliftDate):yyyy/MM/dd(DateFormatType.slashYearMonthDay).Fechas del payload (date_x,upliftDate):yyyy/MM/dd(DateFormatType.slashYearMonthDay). dateReferencedo envelope:yyyy-MM-dd(DateFormatType.isoDate), dosubmittedAt.EnvelopedateReference:yyyy-MM-dd(DateFormatType.isoDate), fromsubmittedAt.dateReferencedel envelope:yyyy-MM-dd(DateFormatType.isoDate), delsubmittedAt.- Todos os valores numéricos do payload vão como string via
.toString(), sem arredondamento monetário (nemReturnValue, nemtotalamount, nemReturnUOMPrice). Exceção de tipo:CreditLimitusa.toInt()antes do.toString().All numeric payload values go as strings via.toString(), with no monetary rounding (neitherReturnValue, nortotalamount, norReturnUOMPrice). Type exception:CreditLimituses.toInt()before.toString().Todos los valores numéricos del payload van como string vía.toString(), sin redondeo monetario (niReturnValue, nitotalamount, niReturnUOMPrice). Excepción de tipo:CreditLimitusa.toInt()antes del.toString().
Pendências / roadmapPending / roadmapPendientes / roadmap
O que o builder envia inerte ou depende de outra etapa, documentado fiel ao estado atual do código (nunca descrito como se já existisse):What the builder ships inert or depends on another step, documented faithfully to the current code state (never described as already existing):Lo que el builder envía inerte o depende de otra etapa, documentado fiel al estado actual del código (nunca descrito como si ya existiera):
Inerte / dependenteInert / dependentInerte / dependiente
- Cabeçalho:
tagNumber,DiscPerc,LPVal,TripIDsempre""— placeholders fixos do contrato, o app não os calcula.Header:tagNumber,DiscPerc,LPVal,TripIDalways""— fixed contract placeholders, the app computes none.Encabezado:tagNumber,DiscPerc,LPVal,TripIDsiempre""— placeholders fijos del contrato, la app no los calcula. - Linha:
DiscPerceDiscAmountsempre""— desconto por linha não implementado na recompra.Line:DiscPercandDiscAmountalways""— per-line discount not implemented for buyback.Línea:DiscPercyDiscAmountsiempre""— descuento por línea no implementado en la recompra. - Campos opcionais (
CreditLimit,CTLovId,conversionMethod,returnGrantedPercentage,approvalStatus) saem""em qualquer mercado cujoBuybackRequestConfig.fieldsnão os declare.Optional fields (CreditLimit,CTLovId,conversionMethod,returnGrantedPercentage,approvalStatus) come out""in any market whoseBuybackRequestConfig.fieldsdoesn't declare them.Campos opcionales (CreditLimit,CTLovId,conversionMethod,returnGrantedPercentage,approvalStatus) salen""en cualquier mercado cuyoBuybackRequestConfig.fieldsno los declare. returnGrantedPercentage, quando presente, é sempre"100"fixo — o app não calcula percentual parcial de devolução concedida.returnGrantedPercentage, when present, is always a fixed"100"— the app doesn't compute a partial granted-return percentage.returnGrantedPercentage, cuando está presente, es siempre un"100"fijo — la app no calcula porcentaje parcial de devolución concedida.- 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ção seguinteNext transactionTransacción siguiente
Depois da solicitação, a coleta agendada é executada (aceitar/rejeitar/reagendar) pela transação 21 · Execução de recompra (SalesReturnUplift) — a etapa seguinte do mesmo ciclo.
After the request, the scheduled collection is executed (accept/reject/reschedule) by the 21 · Buyback execution transaction (SalesReturnUplift) — the next step of the same cycle.
Tras la solicitud, la recolección agendada se ejecuta (aceptar/rechazar/reprogramar) por la transacción 21 · Ejecución de recompra (SalesReturnUplift) — el paso siguiente del mismo ciclo.
MercadosMarketsMercados
A disponibilidade da transação vem do DispatcherType.buybackRequest.enabledMarkets = BR e CL. ZA e os mercados PANGEA (AR/PY/PE) não têm dispatcher de recompra. O quê cada mercado preenche além do núcleo é dirigido por BuybackRequestConfig (End Market Configuration).Transaction availability comes from DispatcherType.buybackRequest.enabledMarkets = BR and CL. ZA and the PANGEA markets (AR/PY/PE) have no buyback dispatcher. What each market fills beyond the core is driven by BuybackRequestConfig (End Market Configuration).La disponibilidad de la transacción viene de DispatcherType.buybackRequest.enabledMarkets = BR y CL. ZA y los mercados PANGEA (AR/PY/PE) no tienen dispatcher de recompra. Qué completa cada mercado más allá del núcleo lo dirige BuybackRequestConfig (End Market Configuration).
Onde existeWhere it existsDónde existe
BR e CL têm o dispatcher de recompra. O núcleo do payload (cabeçalho + linhas, UoM, preço vigente, gate SEN) é idêntico; o que varia é o conjunto de campos opcionais ligados por BuybackRequestConfig.fields e o flag usesSecondaryUomForAllCategories, ambos definidos no EMC de cada mercado.
BR and CL have the buyback dispatcher. The payload core (header + lines, UoM, current price, SEN gate) is identical; what varies is the set of optional fields gated by BuybackRequestConfig.fields and the usesSecondaryUomForAllCategories flag, both defined in each market's EMC.
BR y CL tienen el dispatcher de recompra. El núcleo del payload (encabezado + líneas, UdM, precio vigente, gate SEN) es idéntico; lo que varía es el conjunto de campos opcionales activados por BuybackRequestConfig.fields y el flag usesSecondaryUomForAllCategories, ambos definidos en el EMC de cada mercado.
Matriz de BuybackRequestConfig por mercado (fonte: end_market_configuration.json). Só BR/CL disparam a transação; ZA aparece por completude do EMC:BuybackRequestConfig matrix per market (source: end_market_configuration.json). Only BR/CL fire the transaction; ZA is shown for EMC completeness:Matriz de BuybackRequestConfig por mercado (fuente: end_market_configuration.json). Solo BR/CL disparan la transacción; ZA se muestra por completitud del EMC:
| ConfigConfigConfig | BR | CL | ZA |
|---|---|---|---|
fields: creditLimit | x | x | — |
fields: ctLovId | — | x | — |
fields: conversionMethod | — | x | — |
fields: returnGrantedPercentage | — | x | — |
fields: approvalStatus | — | x | — |
usesSecondaryUomForAllCategories | false | false | true |
Gate SEN só no ChileSEN gate CL onlyGate SEN solo Chile
Só CL declara approvalStatus em fields, então o gate de aprovação SEN ("Pending Approval"/"Ordered") só é emitido no Chile; em BR a chave approvalStatus sai "". CL também preenche CTLovId, conversionMethod e returnGrantedPercentage; BR preenche apenas CreditLimit.
Only CL declares approvalStatus in fields, so the SEN approval gate ("Pending Approval"/"Ordered") is emitted only in Chile; in BR the approvalStatus key comes out "". CL also fills CTLovId, conversionMethod and returnGrantedPercentage; BR fills only CreditLimit.
Solo CL declara approvalStatus en fields, así que el gate de aprobación SEN ("Pending Approval"/"Ordered") se emite solo en Chile; en BR la clave approvalStatus sale "". CL también completa CTLovId, conversionMethod y returnGrantedPercentage; BR completa solo CreditLimit.
ZA · AR · PY · PE
Não têm dispatcher de recompra — buybackRequest.enabledMarkets não os lista. A solicitação de recompra não é disparada nesses mercados.
They have no buyback dispatcher — buybackRequest.enabledMarkets doesn't list them. The buyback request is not fired in these markets.
No tienen dispatcher de recompra — buybackRequest.enabledMarkets no los lista. La solicitud de recompra no se dispara en estos mercados.