From 8a942cc64e028157a347020841ffb9268b0cbbc7 Mon Sep 17 00:00:00 2001 From: Toporkov Igor Date: Fri, 28 Aug 2020 14:54:19 +0300 Subject: [PATCH] FF-208: Implement GetAccountBalance operation (#285) * Implement GetAccountBalance * Fix wrong currency_ref marshaling * Get all events * Test getting account balance * Move getting account balance from handler, introduce relevant types * Get wallet from machine in handler * Remove redundant return type --- apps/ff_server/src/ff_wallet_codec.erl | 9 +++++++ apps/ff_server/src/ff_wallet_handler.erl | 11 ++++++++ .../test/ff_wallet_handler_SUITE.erl | 26 ++++++++++++++++++- apps/fistful/src/ff_account.erl | 11 ++++++++ apps/fistful/src/ff_wallet.erl | 16 ++++++++++++ 5 files changed, 72 insertions(+), 1 deletion(-) diff --git a/apps/ff_server/src/ff_wallet_codec.erl b/apps/ff_server/src/ff_wallet_codec.erl index 191cc1b..e039da2 100644 --- a/apps/ff_server/src/ff_wallet_codec.erl +++ b/apps/ff_server/src/ff_wallet_codec.erl @@ -69,6 +69,15 @@ marshal(wallet, Wallet) -> metadata = maybe_marshal(ctx, maps:get(metadata, Wallet, undefined)) }; +marshal(wallet_account_balance, AccountBalance) -> + #account_AccountBalance{ + id = marshal(id, maps:get(id, AccountBalance)), + currency = marshal(currency_ref, maps:get(currency, AccountBalance)), + expected_min = marshal(amount, maps:get(expected_min, AccountBalance)), + current = marshal(amount, maps:get(current, AccountBalance)), + expected_max = marshal(amount, maps:get(expected_max, AccountBalance)) + }; + marshal(ctx, Ctx) -> marshal(context, Ctx); diff --git a/apps/ff_server/src/ff_wallet_handler.erl b/apps/ff_server/src/ff_wallet_handler.erl index d3c5a49..6e29a71 100644 --- a/apps/ff_server/src/ff_wallet_handler.erl +++ b/apps/ff_server/src/ff_wallet_handler.erl @@ -61,4 +61,15 @@ handle_function_('GetContext', [ID], _Opts) -> {ok, Response}; {error, notfound} -> woody_error:raise(business, #fistful_WalletNotFound{}) + end; + +handle_function_('GetAccountBalance', [ID], _Opts) -> + case ff_wallet_machine:get(ID) of + {ok, Machine} -> + Wallet = ff_wallet_machine:wallet(Machine), + {ok, AccountBalance} = ff_wallet:get_account_balance(Wallet), + Response = ff_wallet_codec:marshal(wallet_account_balance, AccountBalance), + {ok, Response}; + {error, notfound} -> + woody_error:raise(business, #fistful_WalletNotFound{}) end. diff --git a/apps/ff_server/test/ff_wallet_handler_SUITE.erl b/apps/ff_server/test/ff_wallet_handler_SUITE.erl index 6f73325..550535e 100644 --- a/apps/ff_server/test/ff_wallet_handler_SUITE.erl +++ b/apps/ff_server/test/ff_wallet_handler_SUITE.erl @@ -18,6 +18,7 @@ -export([create_error_currency_not_found/1]). -export([create_error_party_blocked/1]). -export([create_error_party_suspended/1]). +-export([get_account_balance/1]). -type config() :: ct_helper:config(). -type test_case_name() :: ct_helper:test_case_name(). @@ -38,7 +39,8 @@ groups() -> create_error_identity_not_found, create_error_currency_not_found, create_error_party_blocked, - create_error_party_suspended + create_error_party_suspended, + get_account_balance ]} ]. @@ -85,6 +87,7 @@ end_per_testcase(_Name, _C) -> -spec create_error_currency_not_found(config()) -> test_return(). -spec create_error_party_blocked(config()) -> test_return(). -spec create_error_party_suspended(config()) -> test_return(). +-spec get_account_balance(config()) -> test_return(). create_ok(C) -> Party = create_party(C), @@ -147,6 +150,27 @@ create_error_party_suspended(C) -> Result = call_service('Create', [Params, #{}]), ?assertMatch({exception, #fistful_PartyInaccessible{}}, Result). +get_account_balance(C) -> + Party = create_party(C), + Currency = <<"RUB">>, + ID = genlib:unique(), + ExternalID = genlib:unique(), + IdentityID = create_person_identity(Party, C), + Ctx = #{<<"TEST_NS">> => {obj, #{ {str, <<"KEY">>} => {b, true}}}}, + Metadata = ff_entity_context_codec:marshal(#{<<"metadata">> => #{<<"some key">> => <<"some data">>}}), + Params = construct_wallet_params(ID, IdentityID, Currency, ExternalID, Metadata), + {ok, Wallet} = call_service('Create', [Params, Ctx]), + WalletID = Wallet#wlt_WalletState.id, + {ok, AccountBalance} = call_service('GetAccountBalance', [WalletID]), + CurrencyRef = AccountBalance#account_AccountBalance.currency, + Account = Wallet#wlt_WalletState.account, + AccountID = Account#account_Account.id, + ?assertMatch(AccountID, AccountBalance#account_AccountBalance.id), + ?assertMatch(Currency, CurrencyRef#'CurrencyRef'.symbolic_code), + ?assertMatch(0, AccountBalance#account_AccountBalance.expected_min), + ?assertMatch(0, AccountBalance#account_AccountBalance.current), + ?assertMatch(0, AccountBalance#account_AccountBalance.expected_max). + %%----------- %% Internal %%----------- diff --git a/apps/fistful/src/ff_account.erl b/apps/fistful/src/ff_account.erl index 683591d..e1f6b30 100644 --- a/apps/fistful/src/ff_account.erl +++ b/apps/fistful/src/ff_account.erl @@ -20,6 +20,16 @@ accounter_account_id := accounter_account_id() }. +-type amount() :: dmsl_domain_thrift:'Amount'(). + +-type account_balance() :: #{ + id := id(), + currency := ff_currency:id(), + expected_min := amount(), + current := amount(), + expected_max := amount() +}. + -type event() :: {created, account()}. @@ -32,6 +42,7 @@ -export_type([account/0]). -export_type([event/0]). -export_type([create_error/0]). +-export_type([account_balance/0]). -export([id/1]). -export([identity/1]). diff --git a/apps/fistful/src/ff_wallet.erl b/apps/fistful/src/ff_wallet.erl index 047f0e2..291bb7c 100644 --- a/apps/fistful/src/ff_wallet.erl +++ b/apps/fistful/src/ff_wallet.erl @@ -70,6 +70,7 @@ -export([create/1]). -export([is_accessible/1]). -export([close/1]). +-export([get_account_balance/1]). -export([apply_event/2]). @@ -204,3 +205,18 @@ check_accessible(Wallet) -> blocked -> {error, blocked} end. + +-spec get_account_balance(wallet_state()) -> + {ok, ff_account:account_balance()}. + +get_account_balance(Wallet) -> + Account = ff_wallet:account(Wallet), + {ok, {Amounts, Currency}} = ff_transaction:balance(Account, ff_clock:latest_clock()), + AccountBalance = #{ + id => ff_account:id(Account), + currency => Currency, + expected_min => ff_indef:expmin(Amounts), + current => ff_indef:current(Amounts), + expected_max => ff_indef:expmax(Amounts) + }, + {ok, AccountBalance}.