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.
| Concepto | Pregunta que responde | Dó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 pago | Ciclo hacia adelante | ”El dinero entró” significa |
|---|---|---|
| Tarjeta (Debi) | pendiente → procesando → completada | procesando (cobro en curso) y completada |
| Transferencia | pendiente → en espera → completada | completada (transferencia confirmada) |
| Efectivo (contra entrega) | pendiente → procesando → completada | completada (efectivo cobrado) |
| Cupón (pago 100% con cupón) | → completada | n/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,
procesandoes “inscripto, todavía no cobramos”; en tarjeta,procesandoya 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 esperaycancelada, 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 dejanprocesando). 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 orden | Inscripción pasa a |
|---|---|
pendiente, en espera | esperando pago |
procesando, completada | confirmada |
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
canceladaoreembolsadano 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ón | Qué hace |
|---|---|
| Checkout | Crea la orden en el estado inicial del medio de pago; crea o redime una inscripción de lista de espera. |
| Confirmar pago | Lleva la orden a “pagada”, confirma la inscripción y recalcula cupones promo. |
| Asignar cama | Setea 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ón | Cuándo se usa | Efecto |
|---|---|---|
| Cancelar inscripción | Única salida de cancelación, disponible para admin y para el pagador | Cancela la inscripción y, en consecuencia, decide el destino de la orden (cancelada si no estaba pagada; reembolsada si estaba pagada). |
| Anular pago | El 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ón | El dinero sí 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 viejo | Cómo lo resuelve el modelo |
|---|---|
| Cupones que no se limpiaban en ciertas combinaciones de estado | Los cupones se recalculan desde un estado deseado, no por transición. |
| La misma inscripción se cancelaba dos veces | Hay una sola puerta de cancelación; la orden ya no cancela en cascada. |
| Confirmar a alguien sin saber cómo iba a pagar | Guarda de evidencia: confirmar exige una orden pagada vinculada. |
| Dropdown que permitía cualquier salto | El 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).