добавил тест для большого deposit;
код для проверки лимитов кошелька убрал в ff_party
	изменено:      apps/ff_cth/src/ct_payment_system.erl
	новый файл:    apps/ff_server/rebar.config
	изменено:      apps/ff_server/src/ff_server.erl
	изменено:      apps/ff_transfer/rebar.config
	изменено:      apps/ff_transfer/src/ff_deposit.erl
	изменено:      apps/ff_transfer/src/ff_withdrawal.erl
	изменено:      apps/ff_transfer/test/ff_transfer_SUITE.erl
	изменено:      apps/fistful/rebar.config
	изменено:      apps/fistful/src/ff_party.erl
This commit is contained in:
0x42 2018-12-17 16:18:47 +03:00
parent 4bb7bec5e9
commit 21bb7e71e6
9 changed files with 120 additions and 43 deletions

View File

@ -64,7 +64,16 @@ start_processing_apps(Options) ->
client => ff_woody_client:new(<<"http://machinegun:8022/v1/automaton">>)
}},
{StartedApps, _StartupCtx} = ct_helper:start_apps([
lager,
{lager, [
{error_logger_hwm, 600},
% {log_root, "/var/log/fistful-server"},
{crash_log, "crash.log"},
{handlers, [
{lager_console_backend, [
{level, warning}
]}
]}
]},
scoper,
woody,
dmt_client,

View File

@ -0,0 +1,3 @@
{erl_opts, [
{parse_transform, lager_transform}
]}.

View File

@ -0,0 +1,3 @@
{erl_opts, [
{parse_transform, lager_transform}
]}.

View File

@ -220,8 +220,16 @@ create_p_transfer(Deposit) ->
-spec finish_transfer(deposit()) ->
{ok, {ff_transfer_machine:action(), [ff_transfer_machine:event(ff_transfer:event())]}} |
{error, _Reason}.
finish_transfer(_Deposit) ->
{ok, {continue, [{status_changed, succeeded}]}}.
finish_transfer(Deposit) ->
Body = body(Deposit),
#{
wallet_id := WalletID,
wallet_account := WalletAccount
} = params(Deposit),
do(fun () ->
valid = ff_party:validate_wallet_limits(WalletID, Body, WalletAccount),
{continue, [{status_changed, succeeded}]}
end).
-spec construct_p_transfer_id(id()) -> id().
construct_p_transfer_id(ID) ->

View File

@ -62,16 +62,13 @@
-type id() :: ff_transfer_machine:id().
-type body() :: ff_transfer:body().
-type wallet() :: ff_wallet:wallet().
-type account() :: ff_account:account().
-type provider() :: ff_withdrawal_provider:provider().
-type wallet_id() :: ff_wallet:id().
-type timestamp() :: ff_time:timestamp_ms().
-type cash_flow_plan() :: ff_cash_flow:cash_flow_plan().
-type destination_id() :: ff_destination:id().
-type process_result() :: {ff_transfer_machine:action(), [event()]}.
-type final_cash_flow() :: ff_cash_flow:final_cash_flow().
-type withdrawal_terms() :: dmsl_domain_thrift:'WithdrawalServiceTerms'().
%% Accessors
@ -121,7 +118,7 @@ create(ID, #{wallet_id := WalletID, destination_id := DestinationID, body := Bod
unwrap(destination, ff_destination:get_machine(DestinationID))
),
ok = unwrap(destination, valid(authorized, ff_destination:status(Destination))),
Terms = unwrap(contract, get_contract_terms(Wallet, Body, ff_time:now())),
Terms = unwrap(contract, ff_party:get_contract_terms(Wallet, Body, ff_time:now())),
valid = unwrap(terms, ff_party:validate_withdrawal_creation(Terms, Body, WalletAccount)),
CashFlowPlan = unwrap(cash_flow_plan, ff_party:get_withdrawal_cash_flow_plan(Terms)),
@ -271,7 +268,7 @@ create_session(Withdrawal) ->
destination_account := DestinationAccount
} = params(Withdrawal),
do(fun () ->
valid = validate_wallet_limits(WalletID, Body, WalletAccount),
valid = ff_party:validate_wallet_limits(WalletID, Body, WalletAccount),
#{provider_id := ProviderID} = route(Withdrawal),
SenderSt = unwrap(ff_identity_machine:get(ff_account:identity(WalletAccount))),
ReceiverSt = unwrap(ff_identity_machine:get(ff_account:identity(DestinationAccount))),
@ -316,29 +313,6 @@ poll_session_completion(Withdrawal) ->
end
end).
-spec get_contract_terms(wallet(), body(), timestamp()) -> Result when
Result :: {ok, withdrawal_terms()} | {error, Error},
Error ::
{party_not_found, id()} |
{party_not_exists_yet, id()} |
{exception, any()}.
get_contract_terms(Wallet, Body, Timestamp) ->
WalletID = ff_wallet:id(Wallet),
IdentityID = ff_wallet:identity(Wallet),
do(fun() ->
IdentityMachine = unwrap(ff_identity_machine:get(IdentityID)),
Identity = ff_identity_machine:identity(IdentityMachine),
ContractID = ff_identity:contract(Identity),
PartyID = ff_identity:party(Identity),
{_Amount, CurrencyID} = Body,
TermVarset = #{
amount => Body,
wallet_id => WalletID,
currency_id => CurrencyID
},
unwrap(ff_party:get_contract_terms(PartyID, ContractID, TermVarset, Timestamp))
end).
-spec get_route_provider(route()) -> {ok, provider()}.
get_route_provider(#{provider_id := ProviderID}) ->
ff_withdrawal_provider:get(ProviderID).
@ -364,11 +338,6 @@ finalize_cash_flow(CashFlowPlan, WalletAccount, DestinationAccount, SystemAccoun
}),
ff_cash_flow:finalize(CashFlowPlan, Accounts, Constants).
validate_wallet_limits(WalletID, Body, Account) ->
Wallet = ff_wallet_machine:wallet(unwrap(wallet, ff_wallet_machine:get(WalletID))),
Terms = unwrap(contract, get_contract_terms(Wallet, Body, ff_time:now())),
unwrap(wallet_limit, ff_party:validate_wallet_limits(Account, Terms)).
-spec maybe_migrate(ff_transfer:event() | ff_transfer:legacy_event()) ->
ff_transfer:event().
maybe_migrate(Ev) ->

View File

@ -15,6 +15,7 @@
-export([get_missing_fails/1]).
-export([deposit_via_admin_ok/1]).
-export([deposit_via_admin_bad/1]).
-export([deposit_withdrawal_ok/1]).
-type config() :: ct_helper:config().
@ -34,6 +35,7 @@ groups() ->
{default, [parallel], [
get_missing_fails,
deposit_via_admin_ok,
deposit_via_admin_bad,
deposit_withdrawal_ok
]}
].
@ -80,6 +82,7 @@ end_per_testcase(_Name, _C) ->
-spec get_missing_fails(config()) -> test_return().
-spec deposit_via_admin_ok(config()) -> test_return().
-spec deposit_via_admin_bad(config()) -> test_return().
-spec deposit_withdrawal_ok(config()) -> test_return().
get_missing_fails(_C) ->
@ -131,6 +134,55 @@ deposit_via_admin_ok(C) ->
),
ok = await_wallet_balance({20000, <<"RUB">>}, WalID).
deposit_via_admin_bad(C) ->
Party = create_party(C),
IID = create_person_identity(Party, C),
WalID = create_wallet(IID, <<"HAHA NO">>, <<"RUB">>, C),
ok = await_wallet_balance({0, <<"RUB">>}, WalID),
% Create source
{ok, Src1} = admin_call('CreateSource', [#fistful_SourceParams{
name = <<"HAHA NO">>,
identity_id = IID,
currency = #'CurrencyRef'{symbolic_code = <<"RUB">>},
resource = #fistful_SourceResource{details = <<"Infinite source of cash">>}
}]),
unauthorized = Src1#fistful_Source.status,
SrcID = Src1#fistful_Source.id,
authorized = ct_helper:await(
authorized,
fun () ->
{ok, Src} = admin_call('GetSource', [SrcID]),
Src#fistful_Source.status
end
),
% Process deposit
% dbg:tracer(),
% dbg:tp(ff_transfer_machine, []),
% dbg:tp(ff_deposit, process_transfer, 1, []),
% dbg:p(all, c),
{ok, Dep1} = admin_call('CreateDeposit', [#fistful_DepositParams{
source = SrcID,
destination = WalID,
body = #'Cash'{
amount = 10000002,
currency = #'CurrencyRef'{symbolic_code = <<"RUB">>}
}
}]),
DepID = Dep1#fistful_Deposit.id,
{pending, _} = Dep1#fistful_Deposit.status,
failed = ct_helper:await(
failed,
fun () ->
{ok, Dep} = admin_call('GetDeposit', [DepID]),
{Status, _} = Dep#fistful_Deposit.status,
Status
end,
genlib_retry:linear(15, 1000)
),
ok = await_wallet_balance({0, <<"RUB">>}, WalID).
deposit_withdrawal_ok(C) ->
Party = create_party(C),
IID = create_person_identity(Party, C),

View File

@ -0,0 +1,3 @@
{erl_opts, [
{parse_transform, lager_transform}
]}.

View File

@ -43,12 +43,13 @@
-export([validate_account_creation/2]).
-export([validate_withdrawal_creation/3]).
-export([validate_wallet_limits/2]).
-export([validate_wallet_limits/3]).
-export([get_contract_terms/3]).
-export([get_contract_terms/4]).
-export([get_withdrawal_cash_flow_plan/1]).
%% Internal types
-type body() :: ff_transfer:body().
-type cash() :: ff_transaction:body().
-type terms() :: dmsl_domain_thrift:'TermSet'().
-type wallet_terms() :: dmsl_domain_thrift:'WalletServiceTerms'() | undefined.
@ -58,6 +59,7 @@
-type domain_cash() :: dmsl_domain_thrift:'Cash'().
-type cash_range() :: dmsl_domain_thrift:'CashRange'().
-type timestamp() :: ff_time:timestamp_ms().
-type wallet() :: ff_wallet:wallet().
-type currency_validation_error() :: {terms_violation, {not_allowed_currency, _Details}}.
-type withdrawal_currency_error() :: {invalid_withdrawal_currency, currency_id(), {wallet_currency, currency_id()}}.
@ -65,7 +67,7 @@
%% Pipeline
-import(ff_pipeline, [do/1, unwrap/1]).
-import(ff_pipeline, [do/1, unwrap/1, unwrap/2]).
%%
@ -133,7 +135,28 @@ change_contractor_level(ID, ContractID, ContractorLevel) ->
ok
end).
%%
-spec get_contract_terms(wallet(), body(), timestamp()) -> Result when
Result :: {ok, wallet_terms()} | {error, Error},
Error ::
{party_not_found, id()} |
{party_not_exists_yet, id()} |
{exception, any()}.
get_contract_terms(Wallet, Body, Timestamp) ->
WalletID = ff_wallet:id(Wallet),
IdentityID = ff_wallet:identity(Wallet),
do(fun() ->
IdentityMachine = unwrap(ff_identity_machine:get(IdentityID)),
Identity = ff_identity_machine:identity(IdentityMachine),
ContractID = ff_identity:contract(Identity),
PartyID = ff_identity:party(Identity),
{_Amount, CurrencyID} = Body,
TermVarset = #{
amount => Body,
wallet_id => WalletID,
currency_id => CurrencyID
},
unwrap(get_contract_terms(PartyID, ContractID, TermVarset, Timestamp))
end).
-spec get_contract_terms(id(), contract_id(), term_varset(), timestamp()) -> Result when
Result :: {ok, terms()} | {error, Error},
@ -448,6 +471,13 @@ validate_wallet_limits(Account, #domain_TermSet{wallets = WalletTerms}) ->
valid = unwrap(validate_cash_range(ExpMaxCash, CashRange))
end).
-spec validate_wallet_limits(machinery:id(), body(), ff_account:account()) ->
valid | {error, cash_range_validation_error()}.
validate_wallet_limits(WalletID, Body, Account) ->
Wallet = ff_wallet_machine:wallet(unwrap(wallet, ff_wallet_machine:get(WalletID))),
Terms = unwrap(contract, get_contract_terms(Wallet, Body, ff_time:now())),
unwrap(wallet_limit, validate_wallet_limits(Account, Terms)).
-spec validate_wallet_limits_terms_is_reduced(wallet_terms()) ->
{ok, valid} | {error, {invalid_terms, _Details}}.
validate_wallet_limits_terms_is_reduced(Terms) ->