Modelo del dominio

Para qué sirve esta página

Es la mirada conceptual del sistema: explica cómo “piensa” por dentro cuando alguien paga, cancela o se anota. No reemplaza a los manuales de cada sección (Inscripciones, Compras, Cupones), sino que muestra cómo encajan entre sí. Si querés el detalle operativo de una pantalla, seguí los enlaces a cada sección.

La idea central: cuatro conceptos, no un solo estado

Es tentador pensar que “el estado de una compra” es un solo dato. En realidad, una misma compra mezcla cuatro preguntas independientes. Separarlas es lo que hace que el sistema sea predecible.

ConceptoPregunta que respondeDónde vive
Pago¿El dinero entró, está en camino o se devolvió?Estado de la orden
Asistencia / fulfillment¿En qué punto del ciclo de la actividad está la persona?Estado de la inscripción
Cupones de promoción¿Esta compra debería haber generado cupones promocionales?Derivado de (medio de pago × pago × producto)
Cupones de reembolso¿Una cancelación generó un crédito de devolución?Derivado de un evento de cancelación
flowchart LR
    Compra["Una compra"] --> Pago["¿Se pagó?<br/>(estado de la orden)"]
    Compra --> Participacion["¿Participa?<br/>(estado de la inscripción)"]
    Pago --> Promo["Cupones de promoción<br/>(proyección)"]
    Producto["¿El producto es promo?"] --> Promo
    Cancelacion["Evento de cancelación<br/>+ política"] --> Reembolso["Cupones de reembolso"]

La clave

Pago y participación son dos hechos distintos que cambian por su cuenta. Los cupones no son un tercer estado que se prende y apaga a mano: son una consecuencia que el sistema recalcula a partir de los otros dos.

El ciclo del pago (según el medio de pago)

Cada medio de pago arranca la orden en un estado distinto y la lleva hacia adelante a medida que ocurren hechos del mundo real (se acredita una transferencia, se cobra el efectivo, etc.). El camino “hacia adelante” es el único camino feliz; cualquier cosa hacia atrás es una corrección (ver más abajo).

Medio de pagoCiclo hacia adelante”El dinero entró” significa
Tarjeta (Debi)pendiente → procesando → completadaprocesando (cobro en curso) y completada
Transferenciapendiente → en espera → completadacompletada (transferencia confirmada)
Efectivo (contra entrega)pendiente → procesando → completadacompletada (efectivo cobrado)
Cupón (pago 100% con cupón)→ completadan/a — lo cubre el cupón aplicado
stateDiagram-v2
    direction LR
    [*] --> pendiente
    pendiente --> en_espera: transferencia
    pendiente --> procesando: efectivo / tarjeta
    en_espera --> completada: transferencia confirmada
    procesando --> completada: efectivo cobrado / cobro acreditado
    completada --> [*]

Por qué importa el medio de pago

El mismo estado puede significar cosas distintas según el medio: en efectivo, procesando es “inscripto, todavía no cobramos”; en tarjeta, procesando ya es “el cobro está en curso y es bueno”. Por eso cada medio de pago declara explícitamente cuándo se considera pagado, y todo el resto del sistema (cupones, cancelaciones) lee esa única definición.

El ciclo de la inscripción

La inscripción es el lado de la participación. Su recorrido completo (estado final: confirmada):

stateDiagram-v2
    direction LR
    [*] --> lista_de_espera
    lista_de_espera --> por_pagar
    lista_de_espera --> confirmada
    lista_de_espera --> cancelada
    por_pagar --> confirmada
    por_pagar --> cancelada
    confirmada --> por_pagar
    confirmada --> cancelada
    cancelada --> [*]

La cama no es un estado

Asignar habitación/cama es editar campos de la inscripción (por PATCH o en el mapa de camas), sin cambiar el estado. Se permite en cualquier estado salvo lista de espera y cancelada, y al cancelar se libera la cama.

El detalle de cada estado y de quién lo cambia está en Estados y ciclo de vida de una Inscripción.

Confirmar requiere evidencia de pago

Se puede pasar de lista de espera directo a confirmada, pero sólo cuando hay una orden pagada que lo respalda (el checkout con cupón deja la orden completada; tarjeta/efectivo la dejan procesando). Lo que el sistema bloquea es confirmar a mano a alguien que nunca pasó por el checkout: sin orden pagada, no hay confirmación. Así se evita el viejo bug de “confirmar sin saber cómo va a pagar”.

Cómo el pago empuja a la inscripción (la cascada)

Cuando cambia el estado de la orden, la inscripción vinculada lo sigue hacia adelante:

Estado de la ordenInscripción pasa a
pendiente, en esperaesperando pago
procesando, completadaconfirmada

La cascada es de una sola dirección

El pago empuja la inscripción hacia adelante, pero no la cancela hacia atrás. Que una orden termine cancelada o reembolsada no cancela sola a la inscripción: el estado de la orden es una consecuencia de cancelar la inscripción, nunca la causa. La única forma de cancelar es el flujo de cancelación de la inscripción (ver abajo).

Cupones como proyección (no como interruptor)

En lugar de “emití el cupón en tal transición y borralo en tal otra” (frágil y lleno de casos especiales), el sistema define qué cupones deberían existir y los reconcilia después de cada evento relevante.

Un producto de promoción debería tener cupones cuando: es promo y la orden está pagada y la inscripción no está cancelada.

flowchart TD
    Evento["Cambió algo<br/>(pago, cancelación...)"] --> Recalcular["Recalcular cupones deseados"]
    Recalcular --> Deberia{"¿Debería existir<br/>el cupón?"}
    Deberia -->|"Sí y falta"| Emitir["Emitir cupón"]
    Deberia -->|"No y existe (sin usar)"| Borrar["Borrar cupón"]
    Deberia -->|"Ya fue canjeado"| Dejar["No tocar nunca"]

Esto vuelve imposible por diseño toda una familia de bugs: ya no hay que enumerar transiciones, sólo preguntar “¿esta compra está hoy en un estado que amerita cupón?“.

  • Cupones de promoción: derivados del pago de un producto promo. Si la inscripción se cancela, sus cupones promo no usados se borran. Detalle en Cupones de promoción.
  • Cupones de reembolso: no son una proyección del pago; nacen sólo de un evento de cancelación con política aplicable, y su valor es el porcentaje del tier de la política. Detalle en Cupones de reembolso y en el Flujo de cancelación.

El modelo de comandos: intenciones con nombre

Los efectos del sistema se enganchan a acciones con nombre (intenciones de negocio), no a “mover un estado en un dropdown”. El estado es el resultado de la acción, no la acción en sí.

Acciones hacia adelante

AcciónQué hace
CheckoutCrea la orden en el estado inicial del medio de pago; crea o redime una inscripción de lista de espera.
Confirmar pagoLleva la orden a “pagada”, confirma la inscripción y recalcula cupones promo.
Asignar camaSetea habitación/cama de la inscripción (dato, no estado): no cambia el estado y se permite salvo en lista de espera / cancelada.

Acciones correctivas (reemplazan al dropdown libre)

Antes, el dropdown de estado de la orden dejaba hacer casi cualquier cosa (incluso saltos sin sentido). Hoy las correcciones son comandos explícitos y auditados:

AcciónCuándo se usaEfecto
Cancelar inscripciónÚnica salida de cancelación, disponible para admin y para el pagadorCancela la inscripción y, en consecuencia, decide el destino de la orden (cancelada si no estaba pagada; reembolsada si estaba pagada).
Anular pagoEl dinero nunca entró o se marcó “pagado” por error. Sólo medios manuales (transferencia, efectivo)Devuelve la orden a su estado pre-pago. No emite cupón de reembolso. Exige un motivo.
Registrar devoluciónEl dinero entró y se devolvió por fuera (efectivo/transferencia)Marca la orden como reembolsada con una nota interna obligatoria. No emite cupón. Requiere que la inscripción ya esté cancelada.

Anulación ≠ Devolución

  • Anular pago: el pago nunca fue real → no hay nada que devolver. La orden vuelve a “no pagada” y no se emite cupón.
  • Devolución: el dinero entró y se está devolviendo → la orden pasa a reembolsada. Puede resolverse con un cupón (% del tier de la política) o con plata (efectivo/transferencia, caso por caso, con nota interna obligatoria).

Tarjeta es de sólo lectura

El estado de una orden de tarjeta (Debi) no se edita a mano: lo gobiernan los avisos automáticos (webhooks) del proveedor de pago. Cualquier reverso de un cobro de tarjeta llega por esa vía, no desde el panel.

Por qué este modelo evita bugs

Problema viejoCómo lo resuelve el modelo
Cupones que no se limpiaban en ciertas combinaciones de estadoLos cupones se recalculan desde un estado deseado, no por transición.
La misma inscripción se cancelaba dos vecesHay una sola puerta de cancelación; la orden ya no cancela en cascada.
Confirmar a alguien sin saber cómo iba a pagarGuarda de evidencia: confirmar exige una orden pagada vinculada.
Dropdown que permitía cualquier saltoEl dropdown se restringe a transiciones válidas; las correcciones son comandos con nombre y motivo.

Para desarrolladores

Esta página es la versión legible de un documento de diseño más técnico. Los puntos de implementación principales:

  • Predicado de pago por medio: helper único de estado de pago de la orden, consumido por la proyección de cupones y por el flujo de cancelación.
  • Máquina de estados de inscripción: transiciones con guardas de evidencia (TransitionStatus), cancelación idempotente.
  • Redención de lista de espera: el checkout empareja por email y, como red, por usuario, y pisa los datos con los del checkout (evita inscripciones duplicadas).
  • Reconciliación de cupones: emite/borra cupones promo según el estado deseado, respetando los ya canjeados y los de reembolso.
  • Cancelación: orquestador único CancelRegistration; el bridge orden→inscripción ya no cancela en cascada.
  • Comandos correctivos: endpoints dedicados de “anular pago” y “registrar devolución” (admin-only, con motivo/nota obligatoria).

0 artículos en esta carpeta.