- v1.1 · actual
- v1 · anterior
Estás viendo el contrato actual (v1.1) de
order.opened. v1.1 agrega data.fiscalRepresentation: la numeración fiscal que el punto de venta obtuvo antes de inyectar la orden. Viaja siempre: en null cuando no se intentó numerar, y con contenido cuando sí —numberingStatus dice cómo terminó—. Que traiga contenido no significa que el comprobante esté autorizado. Solo aditivo — nada de lo que ya leías cambió.El bloque lleva el documento fiscal vigente de la orden: los campos que significan lo mismo en todo país arriba, los identificadores del ente dentro de countryData con el vocabulario de su país, y los documentos anteriores en history. Cuando una anulación numera, la nota de crédito pasa arriba y la factura baja al histórico — con compensates apuntando a ella.order.opened se dispara cuando una orden se inyecta ya abierta: existe en Fire, la cocina puede arrancar, pero no hay ningún pago confirmado. Lleva el mismo snapshot V4 que order.completed, así que todo lo que podés hacer sobre una orden completada también podés hacerlo acá.
Este es el evento que hace posible el pago diferido. Sin él, una orden impaga sería invisible para tus integraciones hasta que llegara el dinero.
Condición de disparo
Fire emiteorder.opened una vez, al inyectar, cuando:
order.status === "OPEN"
order.completed, no hay guarda de pago — paymentStatus normalmente viene en "PENDING" y eso es lo esperado.
La vida de la orden después de este evento
order.opened es el primero de hasta tres eventos de la misma orden. Conocer la secuencia importa, porque esa orden va a llegar a tu endpoint más de una vez:
order.cancelled en vez de order.completed.
Si tu flujo emite un documento fiscal en
order.opened, la misma orden va a pasar de nuevo por tu nodo fiscal en order.completed. Ese segundo paso es esperado e inofensivo: Fire detecta el documento existente y devuelve un resultado idempotente de “ya facturada” en vez de emitir otro. Ver Política de pago diferido más abajo.Qué trae trigger.data
trigger.data es el snapshot V4 — exactamente la misma estructura que lleva order.completed, con dos diferencias que conviene esperar:
Esa última fila es la que sorprende a los integradores. Leela con cuidado.
El medio declarado no es el medio cobrado
Enorder.opened nadie pagó, así que payments.paymentMethods[] lleva el medio que el POS anunció al crear la orden — muchas veces el marketplace (IFOOD, RAPPI) o un placeholder. transactionStatus viene en "PENDING" y transactionId normalmente vacío.
Cuando entra el cobro, Fire sobreescribe ese arreglo con los tenders reales y emite order.completed. Misma orden, mismo campo, significado distinto:
order.opened — declarado
order.completed — realmente cobrado
Política de pago diferido
data.policy.deferredPayment es la razón de ser de este evento. Te dice si esta orden puede ser trabajada antes del pago: cocinada, facturada, despachada.
La política se resuelve una sola vez, al inyectar la orden, a partir de la combinación canal × servicio × medio de pago declarado. Después se estampa de forma inmutable en la orden, y todos los eventos posteriores la repiten sin recalcularla. Dos eventos de la misma orden siempre llevan una policy idéntica.
¿Por qué inmutable? Porque la decisión tiene que quedar auditable. Si la configuración de la tienda cambia una hora después, una orden ya en vuelo debe seguir comportándose como se le indicó — y vos tenés que poder demostrar por qué. Mismo patrón que
store.storeFiscalConfig.
policy está presente en todos los eventos de orden (order.opened, order.completed, order.invoiced, order.cancelled), no solo en este. Una orden con eligible: false también lleva el bloque — simplemente dice que la respuesta fue no.Último estado conocido
data.lastKnown es una foto orientativa de lo que Fire sabía del estado de cocina y fiscal de la orden en el momento de emitir el evento.
Valores posibles de
fiscal.status: pending, processing, authorized, contingency, cancelling, cancelled, rejected, denied, error. Fire además lleva dos estados internos para órdenes sin documento todavía — esos se reportan acá como null, para no filtrar contabilidad interna dentro de tu contrato.
Todo lo demás
Los bloques restantes —store, client, channel, orderLines, fulfillment, kds, device, operator, marketing, metadata, payments.totals — son idénticos a order.completed. En vez de duplicarlos, mirá la referencia de campos de order.completed.
Errores comunes
Tratar order.opened como una venta
Tratar order.opened como una venta
No lo es. Nadie pagó. Contar
order.opened en reportes de facturación infla los números y duplica cuando llegue order.completed de la misma orderId.Esperar order.opened para toda orden
Esperar order.opened para toda orden
Las órdenes pre-pagas (kiosco, checkout web) se inyectan ya
COMPLETED y nunca lo emiten. Si tu integración depende de que order.opened llegue primero, va a saltear esas órdenes en silencio. Suscribite a los dos.Leer el medio de pago como definitivo
Leer el medio de pago como definitivo
Ver más arriba. En
order.opened es lo que el POS declaró, no lo que se cobró.Procesar la misma orden dos veces
Procesar la misma orden dos veces
La misma
orderId te llega en order.opened y otra vez en order.completed. Es por diseño. Hacé tu handler idempotente por (orderId, acción), no por orderId.Siguiente
order.completed— la misma orden, cuando entra la plataorder.cancelled— si muere antes del pago- Confirmar pago — el endpoint que salda una orden abierta
- Get order — leé
settlementpara ver cuánto se recaudó de verdad
data.fiscalRepresentation
La numeración fiscal que el punto de venta obtuvo antes de inyectar la orden:
cobra, pide los identificadores, imprime el comprobante y recién después inyecta.
Por eso viaja en la orden y no en un evento fiscal aparte — cuando la orden nace,
esto ya ocurrió.
La clave viaja siempre. Llega en null cuando no se intentó numerar
—agregadores, países sin representación fiscal, o comercios con la numeración
desactivada— y con el bloque cuando sí se intentó.
Que traiga bloque significa que se intentó numerar, no que se numeró:
numberingStatus dice cómo terminó el intento, y failure por qué cuando no
terminó bien.
Ramificá por valor, no por presencia de la clave:
lastKnown.fiscal, que es lo que sí se mueve.
Lo que sí lo reemplaza es un documento nuevo. El bloque lleva el documento
fiscal vigente de la orden. Mientras solo hubo uno, era siempre la factura;
cuando una anulación produce una nota de crédito, arriba queda la nota —
documentType dice cuál es— y la factura baja a history, entera y con sus
propios identificadores del ente. No se pierde: se mueve. compensates apunta a
ella por su número, así que la relación entre los dos queda explícita.
Cuando la numeración falla
Una venta puede cobrarse y quedarse sin comprobante fiscal. Ese caso también viaja, y hay que contemplarlo: los identificadores vienen ennull y el motivo
en failure.
failure.scope:
TECHNICAL— imprimí “en trámite” y seguí. Puede resolverse solo.FUNCTIONAL— hay un dato mal y reintentar no lo arregla. Requiere corrección.
lastKnown.fiscal.sourceEvent ahora informa la procedencia real. Antes se
deducía del estado, y un processing sembrado al inyectar se reportaba como
fiscal.callback sin que ningún callback hubiera ocurrido. Ahora ese caso dice
order.injected. Si ramificás por este campo, contemplá el valor nuevo.
