mirror of
https://github.com/valitydev/fistful-server.git
synced 2024-11-06 02:35:18 +00:00
TD-821: Add support for deposit negative amount (#78)
* added support for deposit negative amount * fixed * added adj tests
This commit is contained in:
parent
fe96a2148b
commit
26f859d9f7
@ -18,7 +18,7 @@ marshal_deposit_state(DepositState, Context) ->
|
||||
Adjustments = ff_deposit:adjustments(DepositState),
|
||||
#deposit_DepositState{
|
||||
id = marshal(id, ff_deposit:id(DepositState)),
|
||||
body = marshal(cash, ff_deposit:body(DepositState)),
|
||||
body = marshal(cash, ff_deposit:negative_body(DepositState)),
|
||||
status = maybe_marshal(status, ff_deposit:status(DepositState)),
|
||||
wallet_id = marshal(id, ff_deposit:wallet_id(DepositState)),
|
||||
source_id = marshal(id, ff_deposit:source_id(DepositState)),
|
||||
|
@ -56,7 +56,7 @@ marshal(revert_state, Revert) ->
|
||||
wallet_id = marshal(id, ff_deposit_revert:wallet_id(Revert)),
|
||||
source_id = marshal(id, ff_deposit_revert:source_id(Revert)),
|
||||
status = marshal(status, ff_deposit_revert:status(Revert)),
|
||||
body = marshal(cash, ff_deposit_revert:body(Revert)),
|
||||
body = marshal(cash, ff_deposit_revert:negative_body(Revert)),
|
||||
created_at = marshal(timestamp_ms, ff_deposit_revert:created_at(Revert)),
|
||||
domain_revision = marshal(domain_revision, ff_deposit_revert:domain_revision(Revert)),
|
||||
party_revision = marshal(party_revision, ff_deposit_revert:party_revision(Revert)),
|
||||
|
@ -30,13 +30,16 @@
|
||||
-export([create_source_notfound_test/1]).
|
||||
-export([create_wallet_notfound_test/1]).
|
||||
-export([create_ok_test/1]).
|
||||
-export([create_negative_ok_test/1]).
|
||||
-export([unknown_test/1]).
|
||||
-export([get_context_test/1]).
|
||||
-export([get_events_test/1]).
|
||||
-export([create_adjustment_ok_test/1]).
|
||||
-export([create_negative_adjustment_ok_test/1]).
|
||||
-export([create_adjustment_unavailable_status_error_test/1]).
|
||||
-export([create_adjustment_already_has_status_error_test/1]).
|
||||
-export([create_revert_ok_test/1]).
|
||||
-export([create_negative_revert_ok_test/1]).
|
||||
-export([create_revert_inconsistent_revert_currency_error_test/1]).
|
||||
-export([create_revert_insufficient_deposit_amount_error_test/1]).
|
||||
-export([create_revert_invalid_revert_amount_error_test/1]).
|
||||
@ -68,13 +71,16 @@ groups() ->
|
||||
create_source_notfound_test,
|
||||
create_wallet_notfound_test,
|
||||
create_ok_test,
|
||||
create_negative_ok_test,
|
||||
unknown_test,
|
||||
get_context_test,
|
||||
get_events_test,
|
||||
create_adjustment_ok_test,
|
||||
create_negative_adjustment_ok_test,
|
||||
create_adjustment_unavailable_status_error_test,
|
||||
create_adjustment_already_has_status_error_test,
|
||||
create_revert_ok_test,
|
||||
create_negative_revert_ok_test,
|
||||
create_revert_inconsistent_revert_currency_error_test,
|
||||
create_revert_insufficient_deposit_amount_error_test,
|
||||
create_revert_invalid_revert_amount_error_test,
|
||||
@ -238,6 +244,35 @@ create_ok_test(C) ->
|
||||
ff_codec:unmarshal(timestamp_ms, DepositState#deposit_DepositState.created_at)
|
||||
).
|
||||
|
||||
-spec create_negative_ok_test(config()) -> test_return().
|
||||
create_negative_ok_test(C) ->
|
||||
EnvBody = make_cash({100, <<"RUB">>}),
|
||||
#{
|
||||
wallet_id := WalletID,
|
||||
source_id := SourceID
|
||||
} = prepare_standard_environment(EnvBody, C),
|
||||
_ = process_deposit(WalletID, SourceID, EnvBody),
|
||||
Body = make_cash({-100, <<"RUB">>}),
|
||||
{DepositState, DepositID, ExternalID, _} = process_deposit(WalletID, SourceID, Body),
|
||||
Expected = get_deposit(DepositID),
|
||||
?assertEqual(DepositID, DepositState#deposit_DepositState.id),
|
||||
?assertEqual(WalletID, DepositState#deposit_DepositState.wallet_id),
|
||||
?assertEqual(SourceID, DepositState#deposit_DepositState.source_id),
|
||||
?assertEqual(ExternalID, DepositState#deposit_DepositState.external_id),
|
||||
?assertEqual(Body, DepositState#deposit_DepositState.body),
|
||||
?assertEqual(
|
||||
ff_deposit:domain_revision(Expected),
|
||||
DepositState#deposit_DepositState.domain_revision
|
||||
),
|
||||
?assertEqual(
|
||||
ff_deposit:party_revision(Expected),
|
||||
DepositState#deposit_DepositState.party_revision
|
||||
),
|
||||
?assertEqual(
|
||||
ff_deposit:created_at(Expected),
|
||||
ff_codec:unmarshal(timestamp_ms, DepositState#deposit_DepositState.created_at)
|
||||
).
|
||||
|
||||
-spec unknown_test(config()) -> test_return().
|
||||
unknown_test(_C) ->
|
||||
DepositID = <<"unknown_deposit">>,
|
||||
@ -303,6 +338,45 @@ create_adjustment_ok_test(C) ->
|
||||
AdjustmentState#deposit_adj_AdjustmentState.changes_plan
|
||||
).
|
||||
|
||||
-spec create_negative_adjustment_ok_test(config()) -> test_return().
|
||||
create_negative_adjustment_ok_test(C) ->
|
||||
#{
|
||||
wallet_id := WalletID,
|
||||
source_id := SourceID
|
||||
} = prepare_standard_environment_with_deposit(C),
|
||||
{_, DepositID, _, _} = process_deposit(WalletID, SourceID, make_cash({-50, <<"RUB">>})),
|
||||
AdjustmentID = generate_id(),
|
||||
ExternalID = generate_id(),
|
||||
Params = #deposit_adj_AdjustmentParams{
|
||||
id = AdjustmentID,
|
||||
change =
|
||||
{change_status, #deposit_adj_ChangeStatusRequest{
|
||||
new_status = {failed, #deposit_status_Failed{failure = #'fistful_base_Failure'{code = <<"Ooops">>}}}
|
||||
}},
|
||||
external_id = ExternalID
|
||||
},
|
||||
{ok, AdjustmentState} = call_deposit('CreateAdjustment', {DepositID, Params}),
|
||||
ExpectedAdjustment = get_adjustment(DepositID, AdjustmentID),
|
||||
|
||||
?assertEqual(AdjustmentID, AdjustmentState#deposit_adj_AdjustmentState.id),
|
||||
?assertEqual(ExternalID, AdjustmentState#deposit_adj_AdjustmentState.external_id),
|
||||
?assertEqual(
|
||||
ff_adjustment:created_at(ExpectedAdjustment),
|
||||
ff_codec:unmarshal(timestamp_ms, AdjustmentState#deposit_adj_AdjustmentState.created_at)
|
||||
),
|
||||
?assertEqual(
|
||||
ff_adjustment:domain_revision(ExpectedAdjustment),
|
||||
AdjustmentState#deposit_adj_AdjustmentState.domain_revision
|
||||
),
|
||||
?assertEqual(
|
||||
ff_adjustment:party_revision(ExpectedAdjustment),
|
||||
AdjustmentState#deposit_adj_AdjustmentState.party_revision
|
||||
),
|
||||
?assertEqual(
|
||||
ff_deposit_adjustment_codec:marshal(changes_plan, ff_adjustment:changes_plan(ExpectedAdjustment)),
|
||||
AdjustmentState#deposit_adj_AdjustmentState.changes_plan
|
||||
).
|
||||
|
||||
-spec create_adjustment_unavailable_status_error_test(config()) -> test_return().
|
||||
create_adjustment_unavailable_status_error_test(C) ->
|
||||
#{
|
||||
@ -374,6 +448,44 @@ create_revert_ok_test(C) ->
|
||||
RevertState#deposit_revert_RevertState.party_revision
|
||||
).
|
||||
|
||||
-spec create_negative_revert_ok_test(config()) -> test_return().
|
||||
create_negative_revert_ok_test(C) ->
|
||||
#{
|
||||
wallet_id := WalletID,
|
||||
source_id := SourceID
|
||||
} = prepare_standard_environment_with_deposit(make_cash({10000, <<"RUB">>}), C),
|
||||
Body = make_cash({-5000, <<"RUB">>}),
|
||||
{_, DepositID, _, _} = process_deposit(WalletID, SourceID, Body),
|
||||
RevertID = generate_id(),
|
||||
ExternalID1 = generate_id(),
|
||||
Reason = generate_id(),
|
||||
RevertParams = #deposit_revert_RevertParams{
|
||||
id = RevertID,
|
||||
body = Body,
|
||||
external_id = ExternalID1,
|
||||
reason = Reason
|
||||
},
|
||||
{ok, RevertState} = call_deposit('CreateRevert', {DepositID, RevertParams}),
|
||||
succeeded = await_final_revert_status(DepositID, RevertID),
|
||||
Expected = get_revert(DepositID, RevertID),
|
||||
|
||||
?assertEqual(RevertID, RevertState#deposit_revert_RevertState.id),
|
||||
?assertEqual(ExternalID1, RevertState#deposit_revert_RevertState.external_id),
|
||||
?assertEqual(Body, RevertState#deposit_revert_RevertState.body),
|
||||
?assertEqual(Reason, RevertState#deposit_revert_RevertState.reason),
|
||||
?assertEqual(
|
||||
ff_deposit_revert:created_at(Expected),
|
||||
ff_codec:unmarshal(timestamp_ms, RevertState#deposit_revert_RevertState.created_at)
|
||||
),
|
||||
?assertEqual(
|
||||
ff_deposit_revert:domain_revision(Expected),
|
||||
RevertState#deposit_revert_RevertState.domain_revision
|
||||
),
|
||||
?assertEqual(
|
||||
ff_deposit_revert:party_revision(Expected),
|
||||
RevertState#deposit_revert_RevertState.party_revision
|
||||
).
|
||||
|
||||
-spec create_revert_inconsistent_revert_currency_error_test(config()) -> test_return().
|
||||
create_revert_inconsistent_revert_currency_error_test(C) ->
|
||||
#{
|
||||
@ -586,19 +698,7 @@ prepare_standard_environment_with_deposit(Body, C) ->
|
||||
wallet_id := WalletID,
|
||||
source_id := SourceID
|
||||
} = Env = prepare_standard_environment(Body, C),
|
||||
DepositID = generate_id(),
|
||||
ExternalID = generate_id(),
|
||||
Context = #{<<"NS">> => #{generate_id() => generate_id()}},
|
||||
EncodedContext = ff_entity_context_codec:marshal(Context),
|
||||
Params = #deposit_DepositParams{
|
||||
id = DepositID,
|
||||
wallet_id = WalletID,
|
||||
source_id = SourceID,
|
||||
body = Body,
|
||||
external_id = ExternalID
|
||||
},
|
||||
{ok, _DepositState} = call_deposit('Create', {Params, EncodedContext}),
|
||||
succeeded = await_final_deposit_status(DepositID),
|
||||
{_, DepositID, ExternalID, Context} = process_deposit(WalletID, SourceID, Body),
|
||||
Env#{
|
||||
deposit_id => DepositID,
|
||||
external_id => ExternalID,
|
||||
@ -631,6 +731,22 @@ prepare_standard_environment_with_revert(Body, C) ->
|
||||
reason => Reason
|
||||
}.
|
||||
|
||||
process_deposit(WalletID, SourceID, Body) ->
|
||||
DepositID = generate_id(),
|
||||
ExternalID = generate_id(),
|
||||
Context = #{<<"NS">> => #{generate_id() => generate_id()}},
|
||||
EncodedContext = ff_entity_context_codec:marshal(Context),
|
||||
Params = #deposit_DepositParams{
|
||||
id = DepositID,
|
||||
wallet_id = WalletID,
|
||||
source_id = SourceID,
|
||||
body = Body,
|
||||
external_id = ExternalID
|
||||
},
|
||||
{ok, DepositState} = call_deposit('Create', {Params, EncodedContext}),
|
||||
succeeded = await_final_deposit_status(DepositID),
|
||||
{DepositState, DepositID, ExternalID, Context}.
|
||||
|
||||
get_deposit(DepositID) ->
|
||||
{ok, Machine} = ff_deposit_machine:get(DepositID),
|
||||
ff_deposit_machine:deposit(Machine).
|
||||
|
@ -12,6 +12,7 @@
|
||||
id := id(),
|
||||
transfer_type := deposit,
|
||||
body := body(),
|
||||
is_negative := is_negative(),
|
||||
params := transfer_params(),
|
||||
party_revision => party_revision(),
|
||||
domain_revision => domain_revision(),
|
||||
@ -148,6 +149,8 @@
|
||||
-export([source_id/1]).
|
||||
-export([id/1]).
|
||||
-export([body/1]).
|
||||
-export([negative_body/1]).
|
||||
-export([is_negative/1]).
|
||||
-export([status/1]).
|
||||
-export([external_id/1]).
|
||||
-export([party_revision/1]).
|
||||
@ -192,6 +195,7 @@
|
||||
-type revert() :: ff_deposit_revert:revert().
|
||||
-type revert_id() :: ff_deposit_revert:id().
|
||||
-type body() :: ff_accounting:body().
|
||||
-type is_negative() :: boolean().
|
||||
-type cash() :: ff_cash:cash().
|
||||
-type cash_range() :: ff_range:range(cash()).
|
||||
-type action() :: machinery:action() | undefined.
|
||||
@ -250,6 +254,18 @@ source_id(T) ->
|
||||
body(#{body := V}) ->
|
||||
V.
|
||||
|
||||
-spec negative_body(deposit_state()) -> body().
|
||||
negative_body(#{body := {Amount, Currency}, is_negative := true}) ->
|
||||
{-1 * Amount, Currency};
|
||||
negative_body(T) ->
|
||||
body(T).
|
||||
|
||||
-spec is_negative(deposit_state()) -> is_negative().
|
||||
is_negative(#{is_negative := V}) ->
|
||||
V;
|
||||
is_negative(_T) ->
|
||||
false.
|
||||
|
||||
-spec status(deposit_state()) -> status() | undefined.
|
||||
status(Deposit) ->
|
||||
maps:get(status, Deposit, undefined).
|
||||
@ -424,7 +440,7 @@ apply_event(Ev, T0) ->
|
||||
|
||||
-spec apply_event_(event(), deposit_state() | undefined) -> deposit_state().
|
||||
apply_event_({created, T}, undefined) ->
|
||||
T;
|
||||
apply_negative_body(T);
|
||||
apply_event_({status_changed, S}, T) ->
|
||||
maps:put(status, S, T);
|
||||
apply_event_({limit_check, Details}, T) ->
|
||||
@ -436,6 +452,11 @@ apply_event_({revert, _Ev} = Event, T) ->
|
||||
apply_event_({adjustment, _Ev} = Event, T) ->
|
||||
apply_adjustment_event(Event, T).
|
||||
|
||||
apply_negative_body(T = #{body := {Amount, Currency}}) when Amount < 0 ->
|
||||
T#{body => {-1 * Amount, Currency}, is_negative => true};
|
||||
apply_negative_body(T) ->
|
||||
T.
|
||||
|
||||
%% Internals
|
||||
|
||||
-spec do_start_revert(revert_params(), deposit_state()) ->
|
||||
@ -537,7 +558,7 @@ do_process_transfer(stop, _Deposit) ->
|
||||
|
||||
-spec create_p_transfer(deposit_state()) -> process_result().
|
||||
create_p_transfer(Deposit) ->
|
||||
FinalCashFlow = make_final_cash_flow(wallet_id(Deposit), source_id(Deposit), body(Deposit)),
|
||||
FinalCashFlow = make_final_cash_flow(Deposit),
|
||||
PTransferID = construct_p_transfer_id(id(Deposit)),
|
||||
{ok, PostingsTransferEvents} = ff_postings_transfer:create(PTransferID, FinalCashFlow),
|
||||
{continue, [{p_transfer, Ev} || Ev <- PostingsTransferEvents]}.
|
||||
@ -585,8 +606,11 @@ process_transfer_fail(limit_check, Deposit) ->
|
||||
Failure = build_failure(limit_check, Deposit),
|
||||
{undefined, [{status_changed, {failed, Failure}}]}.
|
||||
|
||||
-spec make_final_cash_flow(wallet_id(), source_id(), body()) -> final_cash_flow().
|
||||
make_final_cash_flow(WalletID, SourceID, Body) ->
|
||||
-spec make_final_cash_flow(deposit_state()) -> final_cash_flow().
|
||||
make_final_cash_flow(Deposit) ->
|
||||
WalletID = wallet_id(Deposit),
|
||||
SourceID = source_id(Deposit),
|
||||
Body = body(Deposit),
|
||||
{ok, WalletMachine} = ff_wallet_machine:get(WalletID),
|
||||
WalletAccount = ff_wallet:account(ff_wallet_machine:wallet(WalletMachine)),
|
||||
{ok, SourceMachine} = ff_source_machine:get(SourceID),
|
||||
@ -595,10 +619,19 @@ make_final_cash_flow(WalletID, SourceID, Body) ->
|
||||
Constants = #{
|
||||
operation_amount => Body
|
||||
},
|
||||
Accounts = #{
|
||||
{wallet, sender_source} => SourceAccount,
|
||||
{wallet, receiver_settlement} => WalletAccount
|
||||
},
|
||||
Accounts =
|
||||
case is_negative(Deposit) of
|
||||
true ->
|
||||
#{
|
||||
{wallet, sender_source} => WalletAccount,
|
||||
{wallet, receiver_settlement} => SourceAccount
|
||||
};
|
||||
false ->
|
||||
#{
|
||||
{wallet, sender_source} => SourceAccount,
|
||||
{wallet, receiver_settlement} => WalletAccount
|
||||
}
|
||||
end,
|
||||
CashFlowPlan = #{
|
||||
postings => [
|
||||
#{
|
||||
@ -777,7 +810,7 @@ validate_revert_start(Params, Deposit) ->
|
||||
validate_revert_body(Params, Deposit) ->
|
||||
do(fun() ->
|
||||
valid = unwrap(validate_revert_currency(Params, Deposit)),
|
||||
valid = unwrap(validate_revert_amount(Params)),
|
||||
valid = unwrap(validate_revert_amount(Params, Deposit)),
|
||||
valid = unwrap(validate_unreverted_amount(Params, Deposit))
|
||||
end).
|
||||
|
||||
@ -820,13 +853,15 @@ validate_unreverted_amount(Params, Deposit) ->
|
||||
{error, {insufficient_deposit_amount, {RevertBody, Unreverted}}}
|
||||
end.
|
||||
|
||||
-spec validate_revert_amount(revert_params()) ->
|
||||
-spec validate_revert_amount(revert_params(), deposit_state()) ->
|
||||
{ok, valid}
|
||||
| {error, {invalid_revert_amount, Revert :: body()}}.
|
||||
validate_revert_amount(Params) ->
|
||||
validate_revert_amount(Params, Desposit) ->
|
||||
#{body := {RevertAmount, _Currency} = RevertBody} = Params,
|
||||
case RevertAmount of
|
||||
Good when Good > 0 ->
|
||||
case {RevertAmount, is_negative(Desposit)} of
|
||||
{Good, false} when Good > 0 ->
|
||||
{ok, valid};
|
||||
{Good, true} when Good < 0 ->
|
||||
{ok, valid};
|
||||
_Other ->
|
||||
{error, {invalid_revert_amount, RevertBody}}
|
||||
@ -976,7 +1011,7 @@ make_change_status_params(succeeded, {failed, _} = NewStatus, Deposit) ->
|
||||
};
|
||||
make_change_status_params({failed, _}, succeeded = NewStatus, Deposit) ->
|
||||
CurrentCashFlow = effective_final_cash_flow(Deposit),
|
||||
NewCashFlow = make_final_cash_flow(wallet_id(Deposit), source_id(Deposit), body(Deposit)),
|
||||
NewCashFlow = make_final_cash_flow(Deposit),
|
||||
#{
|
||||
new_status => #{
|
||||
new_status => NewStatus
|
||||
|
@ -13,6 +13,7 @@
|
||||
version := ?ACTUAL_FORMAT_VERSION,
|
||||
id := id(),
|
||||
body := body(),
|
||||
is_negative := is_negative(),
|
||||
wallet_id := wallet_id(),
|
||||
source_id := source_id(),
|
||||
status := status(),
|
||||
@ -102,6 +103,8 @@
|
||||
-export([wallet_id/1]).
|
||||
-export([source_id/1]).
|
||||
-export([body/1]).
|
||||
-export([negative_body/1]).
|
||||
-export([is_negative/1]).
|
||||
-export([status/1]).
|
||||
-export([reason/1]).
|
||||
-export([external_id/1]).
|
||||
@ -135,6 +138,7 @@
|
||||
-type source_id() :: ff_source:id().
|
||||
-type p_transfer() :: ff_postings_transfer:transfer().
|
||||
-type body() :: ff_accounting:body().
|
||||
-type is_negative() :: boolean().
|
||||
-type action() :: machinery:action() | undefined.
|
||||
-type process_result() :: {action(), [event()]}.
|
||||
-type legacy_event() :: any().
|
||||
@ -191,6 +195,18 @@ source_id(#{source_id := V}) ->
|
||||
body(#{body := V}) ->
|
||||
V.
|
||||
|
||||
-spec negative_body(revert()) -> body().
|
||||
negative_body(#{body := {Amount, Currency}, is_negative := true}) ->
|
||||
{-1 * Amount, Currency};
|
||||
negative_body(T) ->
|
||||
body(T).
|
||||
|
||||
-spec is_negative(revert()) -> is_negative().
|
||||
is_negative(#{is_negative := V}) ->
|
||||
V;
|
||||
is_negative(_T) ->
|
||||
false.
|
||||
|
||||
-spec status(revert()) -> status().
|
||||
status(#{status := V}) ->
|
||||
V.
|
||||
@ -311,7 +327,7 @@ apply_event(Ev, T0) ->
|
||||
|
||||
-spec apply_event_(event(), revert() | undefined) -> revert().
|
||||
apply_event_({created, T}, undefined) ->
|
||||
T;
|
||||
apply_negative_body(T);
|
||||
apply_event_({status_changed, S}, T) ->
|
||||
T#{status => S};
|
||||
apply_event_({limit_check, Details}, T) ->
|
||||
@ -321,6 +337,11 @@ apply_event_({p_transfer, Ev}, T) ->
|
||||
apply_event_({adjustment, _Ev} = Event, T) ->
|
||||
apply_adjustment_event(Event, T).
|
||||
|
||||
apply_negative_body(T = #{body := {Amount, Currency}}) when Amount < 0 ->
|
||||
T#{body => {-1 * Amount, Currency}, is_negative => true};
|
||||
apply_negative_body(T) ->
|
||||
T.
|
||||
|
||||
-spec maybe_migrate(event() | legacy_event()) -> event().
|
||||
% Actual events
|
||||
maybe_migrate(Ev = {limit_check, {wallet_receiver, _Details}}) ->
|
||||
@ -397,7 +418,7 @@ do_process_transfer(adjustment, Revert) ->
|
||||
|
||||
-spec create_p_transfer(revert()) -> process_result().
|
||||
create_p_transfer(Revert) ->
|
||||
FinalCashFlow = make_final_cash_flow(wallet_id(Revert), source_id(Revert), body(Revert)),
|
||||
FinalCashFlow = make_final_cash_flow(Revert),
|
||||
PTransferID = construct_p_transfer_id(id(Revert)),
|
||||
{ok, PostingsTransferEvents} = ff_postings_transfer:create(PTransferID, FinalCashFlow),
|
||||
{continue, [{p_transfer, Ev} || Ev <- PostingsTransferEvents]}.
|
||||
@ -447,8 +468,11 @@ process_transfer_fail(limit_check, Revert) ->
|
||||
Failure = build_failure(limit_check, Revert),
|
||||
{undefined, [{status_changed, {failed, Failure}}]}.
|
||||
|
||||
-spec make_final_cash_flow(wallet_id(), source_id(), body()) -> final_cash_flow().
|
||||
make_final_cash_flow(WalletID, SourceID, Body) ->
|
||||
-spec make_final_cash_flow(revert()) -> final_cash_flow().
|
||||
make_final_cash_flow(Revert) ->
|
||||
WalletID = wallet_id(Revert),
|
||||
SourceID = source_id(Revert),
|
||||
Body = body(Revert),
|
||||
{ok, WalletMachine} = ff_wallet_machine:get(WalletID),
|
||||
WalletAccount = ff_wallet:account(ff_wallet_machine:wallet(WalletMachine)),
|
||||
{ok, SourceMachine} = ff_source_machine:get(SourceID),
|
||||
@ -457,10 +481,19 @@ make_final_cash_flow(WalletID, SourceID, Body) ->
|
||||
Constants = #{
|
||||
operation_amount => Body
|
||||
},
|
||||
Accounts = #{
|
||||
{wallet, sender_source} => SourceAccount,
|
||||
{wallet, receiver_settlement} => WalletAccount
|
||||
},
|
||||
Accounts =
|
||||
case is_negative(Revert) of
|
||||
true ->
|
||||
#{
|
||||
{wallet, sender_source} => WalletAccount,
|
||||
{wallet, receiver_settlement} => SourceAccount
|
||||
};
|
||||
false ->
|
||||
#{
|
||||
{wallet, sender_source} => SourceAccount,
|
||||
{wallet, receiver_settlement} => WalletAccount
|
||||
}
|
||||
end,
|
||||
CashFlowPlan = #{
|
||||
postings => [
|
||||
#{
|
||||
@ -608,7 +641,7 @@ make_change_status_params(succeeded, {failed, _} = NewStatus, Revert) ->
|
||||
};
|
||||
make_change_status_params({failed, _}, succeeded = NewStatus, Revert) ->
|
||||
CurrentCashFlow = effective_final_cash_flow(Revert),
|
||||
NewCashFlow = make_final_cash_flow(wallet_id(Revert), source_id(Revert), body(Revert)),
|
||||
NewCashFlow = make_final_cash_flow(Revert),
|
||||
#{
|
||||
new_status => #{
|
||||
new_status => NewStatus
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
-export([limit_check_fail_test/1]).
|
||||
-export([create_bad_amount_test/1]).
|
||||
-export([create_negative_amount_test/1]).
|
||||
-export([create_currency_validation_error_test/1]).
|
||||
-export([create_source_notfound_test/1]).
|
||||
-export([create_wallet_notfound_test/1]).
|
||||
@ -45,6 +46,7 @@ groups() ->
|
||||
{default, [parallel], [
|
||||
limit_check_fail_test,
|
||||
create_bad_amount_test,
|
||||
create_negative_amount_test,
|
||||
create_currency_validation_error_test,
|
||||
create_source_notfound_test,
|
||||
create_wallet_notfound_test,
|
||||
@ -136,6 +138,35 @@ create_bad_amount_test(C) ->
|
||||
Result = ff_deposit_machine:create(DepositParams, ff_entity_context:new()),
|
||||
?assertMatch({error, {bad_deposit_amount, {0, <<"RUB">>}}}, Result).
|
||||
|
||||
-spec create_negative_amount_test(config()) -> test_return().
|
||||
create_negative_amount_test(C) ->
|
||||
#{
|
||||
wallet_id := WalletID,
|
||||
source_id := SourceID
|
||||
} = prepare_standard_environment(<<"RUB">>, C),
|
||||
DepositID0 = generate_id(),
|
||||
DepositCash0 = {100, <<"RUB">>},
|
||||
DepositParams0 = #{
|
||||
id => DepositID0,
|
||||
body => DepositCash0,
|
||||
source_id => SourceID,
|
||||
wallet_id => WalletID,
|
||||
external_id => generate_id()
|
||||
},
|
||||
ok = ff_deposit_machine:create(DepositParams0, ff_entity_context:new()),
|
||||
succeeded = await_final_deposit_status(DepositID0),
|
||||
ok = await_wallet_balance(DepositCash0, WalletID),
|
||||
DepositID1 = generate_id(),
|
||||
DepositCash1 = {-100, <<"RUB">>},
|
||||
DepositParams1 = DepositParams0#{
|
||||
id => DepositID1,
|
||||
body => DepositCash1,
|
||||
external_id => generate_id()
|
||||
},
|
||||
ok = ff_deposit_machine:create(DepositParams1, ff_entity_context:new()),
|
||||
succeeded = await_final_deposit_status(DepositID1),
|
||||
ok = await_wallet_balance({0, <<"RUB">>}, WalletID).
|
||||
|
||||
-spec create_currency_validation_error_test(config()) -> test_return().
|
||||
create_currency_validation_error_test(C) ->
|
||||
#{
|
||||
|
@ -16,8 +16,10 @@
|
||||
%% Tests
|
||||
|
||||
-export([adjustment_can_change_status_to_failed_test/1]).
|
||||
-export([negative_adjustment_can_change_status_to_failed_test/1]).
|
||||
-export([adjustment_can_change_failure_test/1]).
|
||||
-export([adjustment_can_change_status_to_succeeded_test/1]).
|
||||
-export([negative_adjustment_can_change_status_to_succeeded_test/1]).
|
||||
-export([adjustment_can_not_change_status_to_pending_test/1]).
|
||||
-export([adjustment_can_not_change_status_to_same/1]).
|
||||
-export([adjustment_sequence_test/1]).
|
||||
@ -48,8 +50,10 @@ groups() ->
|
||||
[
|
||||
{default, [parallel], [
|
||||
adjustment_can_change_status_to_failed_test,
|
||||
negative_adjustment_can_change_status_to_failed_test,
|
||||
adjustment_can_change_failure_test,
|
||||
adjustment_can_change_status_to_succeeded_test,
|
||||
negative_adjustment_can_change_status_to_succeeded_test,
|
||||
adjustment_can_not_change_status_to_pending_test,
|
||||
adjustment_can_not_change_status_to_same,
|
||||
adjustment_sequence_test,
|
||||
@ -120,6 +124,32 @@ adjustment_can_change_status_to_failed_test(C) ->
|
||||
?assertEqual(?FINAL_BALANCE(0, <<"RUB">>), get_wallet_balance(WalletID)),
|
||||
?assertEqual(?FINAL_BALANCE(0, <<"RUB">>), get_source_balance(SourceID)).
|
||||
|
||||
-spec negative_adjustment_can_change_status_to_failed_test(config()) -> test_return().
|
||||
negative_adjustment_can_change_status_to_failed_test(C) ->
|
||||
#{
|
||||
wallet_id := WalletID,
|
||||
source_id := SourceID
|
||||
} = prepare_standard_environment({100, <<"RUB">>}, C),
|
||||
DepositID = process_deposit(#{
|
||||
source_id => SourceID,
|
||||
wallet_id => WalletID,
|
||||
body => {-50, <<"RUB">>}
|
||||
}),
|
||||
?assertEqual(?FINAL_BALANCE(50, <<"RUB">>), get_wallet_balance(WalletID)),
|
||||
?assertEqual(?FINAL_BALANCE(-50, <<"RUB">>), get_source_balance(SourceID)),
|
||||
Failure = #{code => <<"test">>},
|
||||
AdjustmentID = process_adjustment(DepositID, #{
|
||||
change => {change_status, {failed, Failure}},
|
||||
external_id => <<"true_unique_id">>
|
||||
}),
|
||||
?assertMatch(succeeded, get_adjustment_status(DepositID, AdjustmentID)),
|
||||
ExternalID = ff_adjustment:external_id(get_adjustment(DepositID, AdjustmentID)),
|
||||
?assertEqual(<<"true_unique_id">>, ExternalID),
|
||||
?assertEqual({failed, Failure}, get_deposit_status(DepositID)),
|
||||
assert_adjustment_same_revisions(DepositID, AdjustmentID),
|
||||
?assertEqual(?FINAL_BALANCE(100, <<"RUB">>), get_wallet_balance(WalletID)),
|
||||
?assertEqual(?FINAL_BALANCE(-100, <<"RUB">>), get_source_balance(SourceID)).
|
||||
|
||||
-spec adjustment_can_change_failure_test(config()) -> test_return().
|
||||
adjustment_can_change_failure_test(C) ->
|
||||
#{
|
||||
@ -172,6 +202,32 @@ adjustment_can_change_status_to_succeeded_test(C) ->
|
||||
?assertEqual(?FINAL_BALANCE(5000100, <<"RUB">>), get_wallet_balance(WalletID)),
|
||||
?assertEqual(?FINAL_BALANCE(-5000100, <<"RUB">>), get_source_balance(SourceID)).
|
||||
|
||||
-spec negative_adjustment_can_change_status_to_succeeded_test(config()) -> test_return().
|
||||
negative_adjustment_can_change_status_to_succeeded_test(C) ->
|
||||
#{
|
||||
wallet_id := WalletID,
|
||||
source_id := SourceID
|
||||
} = prepare_standard_environment({5000000, <<"RUB">>}, C),
|
||||
?assertEqual(?FINAL_BALANCE(5000000, <<"RUB">>), get_wallet_balance(WalletID)),
|
||||
?assertEqual(?FINAL_BALANCE(-5000000, <<"RUB">>), get_source_balance(SourceID)),
|
||||
DepositID = generate_id(),
|
||||
Params = #{
|
||||
id => DepositID,
|
||||
wallet_id => WalletID,
|
||||
source_id => SourceID,
|
||||
body => {-6000000, <<"RUB">>}
|
||||
},
|
||||
ok = ff_deposit_machine:create(Params, ff_entity_context:new()),
|
||||
?assertMatch({failed, _}, await_final_deposit_status(DepositID)),
|
||||
AdjustmentID = process_adjustment(DepositID, #{
|
||||
change => {change_status, succeeded}
|
||||
}),
|
||||
?assertMatch(succeeded, get_adjustment_status(DepositID, AdjustmentID)),
|
||||
?assertMatch(succeeded, get_deposit_status(DepositID)),
|
||||
assert_adjustment_same_revisions(DepositID, AdjustmentID),
|
||||
?assertEqual(?FINAL_BALANCE(-1000000, <<"RUB">>), get_wallet_balance(WalletID)),
|
||||
?assertEqual(?FINAL_BALANCE(1000000, <<"RUB">>), get_source_balance(SourceID)).
|
||||
|
||||
-spec adjustment_can_not_change_status_to_pending_test(config()) -> test_return().
|
||||
adjustment_can_not_change_status_to_pending_test(C) ->
|
||||
#{
|
||||
|
@ -16,6 +16,7 @@
|
||||
%% Tests
|
||||
|
||||
-export([revert_ok_test/1]).
|
||||
-export([negative_revert_ok_test/1]).
|
||||
-export([multiple_reverts_ok_test/1]).
|
||||
-export([multiple_parallel_reverts_ok_test/1]).
|
||||
-export([idempotency_test/1]).
|
||||
@ -50,6 +51,7 @@ groups() ->
|
||||
[
|
||||
{default, [parallel], [
|
||||
revert_ok_test,
|
||||
negative_revert_ok_test,
|
||||
multiple_reverts_ok_test,
|
||||
multiple_parallel_reverts_ok_test,
|
||||
idempotency_test,
|
||||
@ -126,6 +128,34 @@ revert_ok_test(C) ->
|
||||
{ok, PartyRevision} = ff_party:get_revision(PartyID),
|
||||
?assertEqual(PartyRevision, ff_deposit_revert:party_revision(Revert)).
|
||||
|
||||
-spec negative_revert_ok_test(config()) -> test_return().
|
||||
negative_revert_ok_test(C) ->
|
||||
#{
|
||||
party_id := PartyID,
|
||||
wallet_id := WalletID,
|
||||
source_id := SourceID
|
||||
} = prepare_standard_environment({10000, <<"RUB">>}, C),
|
||||
DepositID1 = process_deposit(#{
|
||||
source_id => SourceID,
|
||||
wallet_id => WalletID,
|
||||
body => {-5000, <<"RUB">>}
|
||||
}),
|
||||
RevertID = process_revert(DepositID1, #{
|
||||
body => {-5000, <<"RUB">>}
|
||||
}),
|
||||
?assertEqual(?FINAL_BALANCE(10000, <<"RUB">>), get_wallet_balance(WalletID)),
|
||||
?assertEqual(?FINAL_BALANCE(-10000, <<"RUB">>), get_source_balance(SourceID)),
|
||||
Revert = get_revert(RevertID, DepositID1),
|
||||
?assertEqual(undefined, ff_deposit_revert:reason(Revert)),
|
||||
?assertEqual(undefined, ff_deposit_revert:external_id(Revert)),
|
||||
?assertEqual({-5000, <<"RUB">>}, ff_deposit_revert:negative_body(Revert)),
|
||||
?assertEqual(SourceID, ff_deposit_revert:source_id(Revert)),
|
||||
?assertEqual(WalletID, ff_deposit_revert:wallet_id(Revert)),
|
||||
DomainRevision = ff_domain_config:head(),
|
||||
?assertEqual(DomainRevision, ff_deposit_revert:domain_revision(Revert)),
|
||||
{ok, PartyRevision} = ff_party:get_revision(PartyID),
|
||||
?assertEqual(PartyRevision, ff_deposit_revert:party_revision(Revert)).
|
||||
|
||||
-spec multiple_reverts_ok_test(config()) -> test_return().
|
||||
multiple_reverts_ok_test(C) ->
|
||||
#{
|
||||
|
@ -259,7 +259,7 @@ deposit_via_admin_amount_fails(C) ->
|
||||
source = SrcID,
|
||||
destination = WalID,
|
||||
body = #'fistful_base_Cash'{
|
||||
amount = -1,
|
||||
amount = 0,
|
||||
currency = #'fistful_base_CurrencyRef'{symbolic_code = <<"RUB">>}
|
||||
}
|
||||
}
|
||||
|
@ -390,7 +390,7 @@ validate_withdrawal_creation(Terms, {_, CurrencyID} = Cash, Method) ->
|
||||
-spec validate_deposit_creation(terms(), cash()) -> Result when
|
||||
Result :: {ok, valid} | {error, Error},
|
||||
Error :: validate_deposit_creation_error().
|
||||
validate_deposit_creation(_Terms, {Amount, _Currency} = Cash) when Amount < 1 ->
|
||||
validate_deposit_creation(_Terms, {Amount, _Currency} = Cash) when Amount == 0 ->
|
||||
{error, {bad_deposit_amount, Cash}};
|
||||
validate_deposit_creation(Terms, {_Amount, CurrencyID} = _Cash) ->
|
||||
do(fun() ->
|
||||
|
Loading…
Reference in New Issue
Block a user