Ordering Process - implementation

  startWhen {

    case _: ReservationConfirmed => New

  } andThen {

    case New => {

      case ReservationConfirmed(reservationId, customerId, totalAmount) =>
        WaitingForPayment {
          ⟶(CreateInvoice(sagaId, reservationId, customerId, totalAmount, now()))

          ⟵(PaymentExpired(sagaId, reservationId.value)) in 3.minutes
        }

    }

    case WaitingForPayment => {

      case PaymentExpired(invoiceId, orderId) =>
        ⟶(CancelInvoice(invoiceId, orderId))

      case OrderBilled(_, orderId, _, _) =>
        DeliveryInProgress {
          ⟶(CloseReservation(orderId))

          ⟶(CreateShipment(shipmentIdGen(), orderId))
        }

      case OrderBillingFailed(_, orderId) =>
        Failed {
          ⟶(CancelReservation(orderId))
        }
    }
  }

Source: OrderProcessManager.scala

An order is represented as a process that is triggered by the ReservationConfirmed event published by the Reservation Office. As soon as the order is created, the CreateInvoice command is issued to the Invoicing Office and the status of the order is changed to WaitingForPayment. If the payment succeeds (the OrderBilled event is received from the Invoicing office within 3 minutes) the CreateShipment command is issued to the Shipping Office and the status of the order is changed to DeliveryInProgress. But, if the scheduled timeout message PaymentExpired is received while the order is still not billed, the CancelInvoicecommands is issued to the Invoicing Office and eventually the process ends with a Failed status.

I hope you agree, that the logic of the Ordering Process is easy to grasp by looking at the code above. We simply declare a set of state transitions with associated triggering events and resulting commands. Please note that ⟵ (PaymentExpired(...)) in 3.minutes gets resolved to the following command: (⟶ ScheduleEvent(PaymentExpired(...), now + 3.minutes)) that will be issued to the specialized Scheduling Office.