On hold
The next step for our bank account is to place a hold on an account.
Using state functions, this is as simple as:
open({call, From}, place_hold, Data) -> {next_state, held, Data, [{reply, From, hold_placed}]}; ... open({call, From}, {deposit, Amount}, Data) -> handle_deposit(Amount, Data, From); ... held({call, From}, {deposit, Amount}, Data) -> handle_deposit(Amount, Data, From); held({call, From}, remove_hold, Data) -> {next_state, open, Data, [{reply, From, hold_removed}]}. handle_deposit(Amount, #{balance:=Balance} = Data, From) when is_number(Amount) andalso Amount > 0 -> NewBalance = Balance + Amount, {keep_state, Data#{balance:=NewBalance}, [{reply, From, deposit_made}]}.
Now any attempt to withdraw funds from a held account, will cause the gen_statem process to crash (hopefully having previously persisted any important data!).
And using handle event:
handle_event({call, From}, place_hold, open, Data) -> {next_state, held, Data, [{reply, From, hold_placed}]}; ... handle_event({call, From}, remove_hold, held, Data) -> {next_state, open, Data, [{reply, From, hold_removed}]}; ... handle_event({call, From}, {deposit, Amount}, open, Data) -> handle_deposit(Amount, Data, From); handle_event({call, From}, {deposit, Amount}, held, Data) -> handle_deposit(Amount, Data, From); ... handle_deposit(Amount, #{balance:=Balance} = Data, From) when is_number(Amount) andalso Amount > 0 -> NewBalance = Balance + Amount, {keep_state, Data#{balance:=NewBalance}, [{reply, From, deposit_made}]}.
Insufficient funds?
We can also add an availableToWithdraw
method, with different behaviour for held accounts, without too much hassle:
open({call, From}, available_to_withdraw, #{balance:=Balance} = Data) -> {keep_state, Data, [{reply, From, Balance}]}; ... held({call, From}, available_to_withdraw, Data) -> {keep_state, Data, [{reply, From, 0}]};
Or:
handle_event({call, From}, available_to_withdraw, open, #{balance:=Balance} = Data) -> {keep_state, Data, [{reply, From, Balance}]}; ... handle_event({call, From}, available_to_withdraw, held, Data) -> {keep_state, Data, [{reply, From, 0}]};