mirror of
https://github.com/valitydev/fistful-server.git
synced 2024-11-06 02:35:18 +00:00
[WIP] Add cancel op
This commit is contained in:
parent
afa14335c2
commit
f7a35e7612
@ -20,21 +20,28 @@
|
||||
|
||||
-export([prepare/2]).
|
||||
-export([commit/2]).
|
||||
-export([cancel/2]).
|
||||
|
||||
%%
|
||||
|
||||
-spec prepare(id(), [posting()]) ->
|
||||
affected().
|
||||
{ok, affected()}.
|
||||
|
||||
prepare(ID, Postings) ->
|
||||
hold(encode_plan_change(ID, Postings)).
|
||||
|
||||
-spec commit(id(), [posting()]) ->
|
||||
affected().
|
||||
{ok, affected()}.
|
||||
|
||||
commit(ID, Postings) ->
|
||||
commit_plan(encode_plan(ID, Postings)).
|
||||
|
||||
-spec cancel(id(), [posting()]) ->
|
||||
{ok, affected()}.
|
||||
|
||||
cancel(ID, Postings) ->
|
||||
rollback_plan(encode_plan(ID, Postings)).
|
||||
|
||||
%% Woody stuff
|
||||
|
||||
hold(PlanChange) ->
|
||||
@ -53,6 +60,14 @@ commit_plan(Plan) ->
|
||||
error(Unexpected)
|
||||
end.
|
||||
|
||||
rollback_plan(Plan) ->
|
||||
case call('RollbackPlan', [Plan]) of
|
||||
{ok, #accounter_PostingPlanLog{affected_accounts = Affected}} ->
|
||||
{ok, decode_affected(Affected)};
|
||||
{error, Unexpected} ->
|
||||
error(Unexpected)
|
||||
end.
|
||||
|
||||
call(Function, Args) ->
|
||||
Service = {dmsl_accounter_thrift, 'Accounter'},
|
||||
ff_woody_client:call(accounter, {Service, Function, Args}).
|
||||
|
@ -31,6 +31,12 @@
|
||||
status := status()
|
||||
}.
|
||||
|
||||
-type ev() ::
|
||||
{status_changed, status()}.
|
||||
|
||||
-type outcome() ::
|
||||
{[ev()], transfer()}.
|
||||
|
||||
-export_type([transfer/0]).
|
||||
-export_type([posting/0]).
|
||||
-export_type([status/0]).
|
||||
@ -42,6 +48,11 @@
|
||||
-export([create/2]).
|
||||
-export([prepare/1]).
|
||||
-export([commit/1]).
|
||||
-export([cancel/1]).
|
||||
|
||||
%% Event source
|
||||
|
||||
-export([apply_event/2]).
|
||||
|
||||
%% Pipeline
|
||||
|
||||
@ -116,29 +127,31 @@ validate_identities([W0 | Wallets]) ->
|
||||
%%
|
||||
|
||||
-spec prepare(transfer()) ->
|
||||
{ok, transfer()} |
|
||||
{ok, outcome()} |
|
||||
{error,
|
||||
status() |
|
||||
balance |
|
||||
{status, committed | cancelled} |
|
||||
{wallet, {inaccessible, blocked | suspended}}
|
||||
}.
|
||||
|
||||
prepare(Transfer = #{status := created}) ->
|
||||
do(fun () ->
|
||||
Postings = postings(Transfer),
|
||||
TrxID = trxid(Transfer),
|
||||
Postings = construct_trx_postings(postings(Transfer)),
|
||||
roll(Transfer, do(fun () ->
|
||||
accessible = unwrap(wallet, validate_accessible(gather_wallets(Postings))),
|
||||
Affected = ff_transaction:prepare(trxid(Transfer), construct_trx_postings(Postings)),
|
||||
Affected = unwrap(ff_transaction:prepare(TrxID, Postings)),
|
||||
case validate_balances(Affected) of
|
||||
{ok, valid} ->
|
||||
Transfer#{status := prepared};
|
||||
[{status_changed, prepared}];
|
||||
{error, invalid} ->
|
||||
_ = ff_transaction:cancel(TrxID, Postings),
|
||||
throw(balance)
|
||||
end
|
||||
end);
|
||||
end));
|
||||
prepare(Transfer = #{status := prepared}) ->
|
||||
{ok, Transfer};
|
||||
prepare(#{status := Status}) ->
|
||||
{error, Status}.
|
||||
{error, {status, Status}}.
|
||||
|
||||
validate_balances(Affected) ->
|
||||
% TODO
|
||||
@ -147,22 +160,60 @@ validate_balances(Affected) ->
|
||||
%%
|
||||
|
||||
-spec commit(transfer()) ->
|
||||
{ok, transfer()} |
|
||||
{error, status()}.
|
||||
{ok, outcome()} |
|
||||
{error, {status, created | cancelled}}.
|
||||
|
||||
commit(Transfer = #{status := prepared}) ->
|
||||
do(fun () ->
|
||||
Postings = postings(Transfer),
|
||||
_Affected = ff_transaction:commit(trxid(Transfer), construct_trx_postings(Postings)),
|
||||
Transfer#{status := committed}
|
||||
end);
|
||||
roll(Transfer, do(fun () ->
|
||||
Postings = construct_trx_postings(postings(Transfer)),
|
||||
_Affected = unwrap(ff_transaction:commit(trxid(Transfer), Postings)),
|
||||
[{status_changed, committed}]
|
||||
end));
|
||||
commit(Transfer = #{status := committed}) ->
|
||||
{ok, Transfer};
|
||||
{ok, roll(Transfer)};
|
||||
commit(#{status := Status}) ->
|
||||
{error, Status}.
|
||||
|
||||
%%
|
||||
|
||||
-spec cancel(transfer()) ->
|
||||
{ok, outcome()} |
|
||||
{error, {status, created | committed}}.
|
||||
|
||||
cancel(Transfer = #{status := prepared}) ->
|
||||
roll(Transfer, do(fun () ->
|
||||
Postings = construct_trx_postings(postings(Transfer)),
|
||||
_Affected = unwrap(ff_transaction:cancel(trxid(Transfer), Postings)),
|
||||
[{status_changed, cancelled}]
|
||||
end));
|
||||
cancel(Transfer = #{status := cancelled}) ->
|
||||
{ok, roll(Transfer)};
|
||||
cancel(#{status := Status}) ->
|
||||
{error, {status, Status}}.
|
||||
|
||||
%%
|
||||
|
||||
apply_event({status_changed, S}, Transfer) ->
|
||||
Transfer#{status := S}.
|
||||
|
||||
%% TODO
|
||||
|
||||
-type result(V, R) :: {ok, V} | {error, R}.
|
||||
|
||||
-spec roll(St, result(Evs, Reason)) ->
|
||||
result({Evs, St}, Reason) when
|
||||
Evs :: [_].
|
||||
|
||||
roll(St, {ok, Events}) when is_list(Events) ->
|
||||
{ok, {Events, lists:foldl(fun apply_event/2, St, Events)}};
|
||||
roll(_St, {error, _} = Error) ->
|
||||
Error.
|
||||
|
||||
roll(St) ->
|
||||
{[], St}.
|
||||
|
||||
%%
|
||||
|
||||
construct_trx_postings(Postings) ->
|
||||
[
|
||||
{ff_wallet:account(Source), ff_wallet:account(Destination), Body} ||
|
||||
|
Loading…
Reference in New Issue
Block a user