Skip to content

Latest commit

 

History

History
426 lines (167 loc) · 6.99 KB

order_control_rich_model_machine.rst

File metadata and controls

426 lines (167 loc) · 6.99 KB
.. only:: html

    .. note::
        :class: sphx-glr-download-link-note

        Click :ref:`here <sphx_glr_download_auto_examples_order_control_rich_model_machine.py>`
        to download the full example code

.. rst-class:: sphx-glr-example-title

Order control machine (rich model)

An StateMachine that demonstrates :ref:`Actions` being used on a rich model.

from statemachine import State
from statemachine import StateMachine
from statemachine.exceptions import AttrNotFound


class Order(object):
    def __init__(self):
        self.order_total = 0
        self.payments = []
        self.payment_received = False

    def payments_enough(self, amount):
        return sum(self.payments) + amount >= self.order_total

    def add_to_order(self, amount):
        self.order_total += amount
        return self.order_total

    def on_receive_payment(self, amount):
        self.payments.append(amount)
        return self.payments

    def after_receive_payment(self):
        self.payment_received = True

    def wait_for_payment(self):
        self.payment_received = False


class OrderControl(StateMachine):
    waiting_for_payment = State(
        "Waiting for payment", initial=True, enter="wait_for_payment"
    )
    processing = State("Processing")
    shipping = State("Shipping")
    completed = State("Completed", final=True)

    add_to_order = waiting_for_payment.to(waiting_for_payment, before="add_to_order")
    receive_payment = waiting_for_payment.to(
        processing, cond="payments_enough"
    ) | waiting_for_payment.to(waiting_for_payment, unless="payments_enough")
    process_order = processing.to(shipping, cond="payment_received")
    ship_order = shipping.to(completed)
.. image-sg:: /auto_examples/images/sphx_glr_order_control_rich_model_machine_001.svg
   :alt: order control rich model machine
   :srcset: /auto_examples/images/sphx_glr_order_control_rich_model_machine_001.svg
   :class: sphx-glr-single-img





Testing

Let's first try to create a statemachine instance, using the default dummy model that don't have the needed methods to complete the state machine. Since the required methods will not be found either in the state machine or in the model, an exception AttrNotFound will be raised.

try:
    control = OrderControl()
except AttrNotFound as e:
    assert str(e) == "Did not found name 'payment_received' from model or statemachine"

Now initializing with a proper order instance.

order = Order()
control = OrderControl(order)

Send events to add to order

assert control.send("add_to_order", 3) == 3
assert control.send("add_to_order", 7) == 10

Receive a payment of $4...

control.send("receive_payment", 4)
.. rst-class:: sphx-glr-script-out

 .. code-block:: none


    [4]



Since there's still $6 left to fulfill the payment, we cannot process the order.

try:
    control.send("process_order")
except StateMachine.TransitionNotAllowed as err:
    print(err)
.. rst-class:: sphx-glr-script-out

 .. code-block:: none

    Can't process_order when in Waiting for payment.




control
.. rst-class:: sphx-glr-script-out

 .. code-block:: none


    OrderControl(model=<__main__.Order object at 0x7fa3456ef2e0>, state_field='state', current_state='waiting_for_payment')



Now paying the left amount, we can proceed.

control.send("receive_payment", 6)
.. rst-class:: sphx-glr-script-out

 .. code-block:: none


    [4, 6]



control
.. rst-class:: sphx-glr-script-out

 .. code-block:: none


    OrderControl(model=<__main__.Order object at 0x7fa3456ef2e0>, state_field='state', current_state='processing')



control.send("process_order")
control
.. rst-class:: sphx-glr-script-out

 .. code-block:: none


    OrderControl(model=<__main__.Order object at 0x7fa3456ef2e0>, state_field='state', current_state='shipping')



control.send("ship_order")

Just checking the final expected state

order.order_total
.. rst-class:: sphx-glr-script-out

 .. code-block:: none


    10



order.payments
.. rst-class:: sphx-glr-script-out

 .. code-block:: none


    [4, 6]



control.completed.is_active
.. rst-class:: sphx-glr-script-out

 .. code-block:: none


    True



control
.. rst-class:: sphx-glr-script-out

 .. code-block:: none


    OrderControl(model=<__main__.Order object at 0x7fa3456ef2e0>, state_field='state', current_state='completed')



assert order.order_total == 10
assert order.payments == [4, 6]
assert control.completed.is_active
.. only:: html

  .. container:: sphx-glr-footer sphx-glr-footer-example


    .. container:: sphx-glr-download sphx-glr-download-python

      :download:`Download Python source code: order_control_rich_model_machine.py <order_control_rich_model_machine.py>`

    .. container:: sphx-glr-download sphx-glr-download-jupyter

      :download:`Download Jupyter notebook: order_control_rich_model_machine.ipynb <order_control_rich_model_machine.ipynb>`