TD-264: Move to accounter (#22)

* TD-264: Move to accounter

* Hadofix

* Hadofix 2

* Review fixes

* Review fix
This commit is contained in:
ndiezel0 2022-04-20 19:59:06 +03:00 committed by GitHub
parent 2586e6df84
commit b2aec027fd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 207 additions and 507 deletions

View File

@ -2,6 +2,7 @@ ARG OTP_VERSION
# Build the release
FROM docker.io/library/erlang:${OTP_VERSION} AS builder
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
# Install thrift compiler
ARG THRIFT_VERSION
@ -16,8 +17,8 @@ COPY . /build/
# Build the release
WORKDIR /build
RUN rebar3 compile
RUN rebar3 as prod release
RUN rebar3 compile && \
rebar3 as prod release
# Make a runner image
FROM docker.io/library/erlang:${OTP_VERSION}-slim
@ -28,13 +29,15 @@ ARG SERVICE_NAME
ENV CHARSET=UTF-8
ENV LANG=C.UTF-8
# Expose SERVICE_NAME as env so CMD expands properly on start
ENV SERVICE_NAME=${SERVICE_NAME}
# Set runtime
WORKDIR /opt/${SERVICE_NAME}
COPY --from=builder /build/_build/prod/rel/${SERVICE_NAME} /opt/${SERVICE_NAME}
RUN echo "#!/bin/sh" >> /entrypoint.sh && \
echo "exec /opt/${SERVICE_NAME}/bin/${SERVICE_NAME} foreground" >> /entrypoint.sh && \
chmod +x /entrypoint.sh
ENTRYPOINT []
CMD /opt/${SERVICE_NAME}/bin/${SERVICE_NAME} foreground
CMD ["/entrypoint.sh"]
EXPOSE 8022

View File

@ -1,6 +1,7 @@
ARG OTP_VERSION
FROM docker.io/library/erlang:${OTP_VERSION}
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
ARG BUILDARCH
@ -15,4 +16,4 @@ ENV CHARSET=UTF-8
ENV LANG=C.UTF-8
# Set runtime
CMD /bin/bash
CMD ["/bin/bash"]

View File

@ -16,29 +16,29 @@
-export([proxy/2]).
-export([proxy/3]).
-export([proxy/4]).
-export([system_account_set/4]).
-export([external_account_set/4]).
-export([system_account_set/3]).
-export([external_account_set/3]).
-export([term_set_hierarchy/1]).
-export([term_set_hierarchy/2]).
-export([term_set_hierarchy/3]).
-export([timed_term_set/1]).
-export([globals/2]).
-export([withdrawal_provider/4]).
-export([withdrawal_provider/3]).
-export([withdrawal_terminal/1]).
%%
-include_lib("ff_cth/include/ct_domain.hrl").
-include_lib("shumpune_proto/include/shumpune_shumpune_thrift.hrl").
-include_lib("damsel/include/dmsl_accounter_thrift.hrl").
-define(DTP(Type), dmsl_domain_thrift:Type()).
-type object() ::
dmsl_domain_thrift:'DomainObject'().
-spec withdrawal_provider(?DTP('ProviderRef'), ?DTP('ProxyRef'), binary(), ct_helper:config()) -> object().
withdrawal_provider(?prv(16) = Ref, ProxyRef, IdentityID, C) ->
AccountID = account(<<"RUB">>, C),
-spec withdrawal_provider(?DTP('ProviderRef'), ?DTP('ProxyRef'), binary()) -> object().
withdrawal_provider(?prv(16) = Ref, ProxyRef, IdentityID) ->
{ok, AccountID} = ct_helper:create_account(<<"RUB">>),
{provider, #domain_ProviderObject{
ref = Ref,
data = #domain_Provider{
@ -59,8 +59,8 @@ withdrawal_provider(?prv(16) = Ref, ProxyRef, IdentityID, C) ->
]}
}
}};
withdrawal_provider(Ref, ProxyRef, IdentityID, C) ->
AccountID = account(<<"RUB">>, C),
withdrawal_provider(Ref, ProxyRef, IdentityID) ->
{ok, AccountID} = ct_helper:create_account(<<"RUB">>),
{provider, #domain_ProviderObject{
ref = Ref,
data = #domain_Provider{
@ -400,10 +400,10 @@ proxy(Ref, Name, URL, Opts) ->
}
}}.
-spec system_account_set(?DTP('SystemAccountSetRef'), binary(), ?DTP('CurrencyRef'), ct_helper:config()) -> object().
system_account_set(Ref, Name, ?cur(SymCode), C) ->
AccountID1 = account(SymCode, C),
AccountID2 = account(SymCode, C),
-spec system_account_set(?DTP('SystemAccountSetRef'), binary(), ?DTP('CurrencyRef')) -> object().
system_account_set(Ref, Name, ?cur(SymCode)) ->
{ok, AccountID1} = ct_helper:create_account(SymCode),
{ok, AccountID2} = ct_helper:create_account(SymCode),
{system_account_set, #domain_SystemAccountSetObject{
ref = Ref,
data = #domain_SystemAccountSet{
@ -418,11 +418,11 @@ system_account_set(Ref, Name, ?cur(SymCode), C) ->
}
}}.
-spec external_account_set(?DTP('ExternalAccountSetRef'), binary(), ?DTP('CurrencyRef'), ct_helper:config()) ->
-spec external_account_set(?DTP('ExternalAccountSetRef'), binary(), ?DTP('CurrencyRef')) ->
object().
external_account_set(Ref, Name, ?cur(SymCode), C) ->
AccountID1 = account(SymCode, C),
AccountID2 = account(SymCode, C),
external_account_set(Ref, Name, ?cur(SymCode)) ->
{ok, AccountID1} = ct_helper:create_account(SymCode),
{ok, AccountID2} = ct_helper:create_account(SymCode),
{external_account_set, #domain_ExternalAccountSetObject{
ref = Ref,
data = #domain_ExternalAccountSet{
@ -472,21 +472,3 @@ globals(EASRef, PIRefs) ->
payment_institutions = ?ordset(PIRefs)
}
}}.
-spec account(binary(), ct_helper:config()) -> shumpune_shumpune_thrift:'AccountID'().
account(SymCode, C) ->
Client = ff_woody_client:new(maps:get('accounter', ct_helper:cfg(services, C))),
WoodyCtx = ct_helper:get_woody_ctx(C),
Prototype = #shumpune_AccountPrototype{
currency_sym_code = SymCode,
description = <<>>,
creation_time = timestamp()
},
Request = {{shumpune_shumpune_thrift, 'Accounter'}, 'CreateAccount', {Prototype}},
case woody_client:call(Request, Client, WoodyCtx) of
{ok, ID} ->
ID
end.
timestamp() ->
genlib_rfc3339:format(genlib_time:daytime_to_unixtime(calendar:universal_time()), second).

View File

@ -23,6 +23,8 @@
-export([await/2]).
-export([await/3]).
-export([create_account/1]).
-type test_case_name() :: atom().
-type group_name() :: atom().
-type config() :: [{atom(), term()}].
@ -245,3 +247,10 @@ await(Expect, Compute, Retry0) ->
error({'await failed', NotYet})
end
end.
-spec create_account(dmsl_accounter_thrift:'PlanID'()) ->
{ok, ff_account:accounter_account_id()}
| {error, {exception, any()}}.
create_account(CurrencyCode) ->
Description = <<"ff_test">>,
ff_accounting:create_account(CurrencyCode, Description).

View File

@ -61,7 +61,7 @@ do_setup(Options0, C0) ->
{ok, Processing0} = start_processing_apps(Options),
C1 = ct_helper:makeup_cfg([ct_helper:woody_ctx()], [{services, services(Options)} | C0]),
ok = ct_helper:set_context(C1),
ok = setup_dominant(Options, C1),
ok = setup_dominant(Options),
ok = configure_processing_apps(Options),
ok = ct_helper:unset_context(),
[{payment_system, Processing0} | C1].
@ -136,8 +136,8 @@ start_optional_apps(#{optional_apps := Apps}) ->
start_optional_apps(_) ->
[].
setup_dominant(Options, C) ->
DomainConfig = domain_config(Options, C),
setup_dominant(Options) ->
DomainConfig = domain_config(Options),
_ = ct_domain_config:upsert(DomainConfig),
ok.
@ -229,7 +229,7 @@ services(Options) ->
ff_withdrawal_adapter_host => "http://fistful-server:8022/v1/ff_withdrawal_adapter_host",
eventsink => "http://machinegun:8022/v1/event_sink",
automaton => "http://machinegun:8022/v1/automaton",
accounter => "http://shumway:8022/shumpune",
accounter => "http://shumway:8022/accounter",
partymgmt => "http://party-management:8022/v1/processing/partymgmt",
binbase => "http://localhost:8222/binbase"
},
@ -251,7 +251,7 @@ dummy_payment_inst_identity_id(Options) ->
dummy_provider_identity_id(Options) ->
maps:get(dummy_provider_identity_id, Options).
domain_config(Options, C) ->
domain_config(Options) ->
WithdrawalDecision1 =
{delegates, [
delegate(condition(party, <<"12345">>), ?ruleset(2)),
@ -279,7 +279,7 @@ domain_config(Options, C) ->
Default = [
ct_domain:globals(?eas(1), [?payinst(1)]),
ct_domain:external_account_set(?eas(1), <<"Default">>, ?cur(<<"RUB">>), C),
ct_domain:external_account_set(?eas(1), <<"Default">>, ?cur(<<"RUB">>)),
routing_ruleset(?ruleset(1), <<"WithdrawalRuleset#1">>, WithdrawalDecision1),
routing_ruleset(?ruleset(2), <<"WithdrawalRuleset#2">>, WithdrawalDecision2),
@ -553,7 +553,7 @@ domain_config(Options, C) ->
}
}},
ct_domain:system_account_set(?sas(1), <<"System">>, ?cur(<<"RUB">>), C),
ct_domain:system_account_set(?sas(1), <<"System">>, ?cur(<<"RUB">>)),
ct_domain:inspector(?insp(1), <<"Low Life">>, ?prx(1), #{<<"risk_score">> => <<"low">>}),
ct_domain:proxy(?prx(1), <<"Inspector proxy">>),
@ -563,19 +563,19 @@ domain_config(Options, C) ->
ct_domain:proxy(?prx(7), <<"Another down proxy">>, <<"http://localhost:8222/downbank2">>),
ct_domain:proxy(?prx(8), <<"Sleep proxy">>, <<"http://localhost:8222/sleepybank">>),
ct_domain:withdrawal_provider(?prv(1), ?prx(2), provider_identity_id(Options), C),
ct_domain:withdrawal_provider(?prv(2), ?prx(2), provider_identity_id(Options), C),
ct_domain:withdrawal_provider(?prv(3), ?prx(3), dummy_provider_identity_id(Options), C),
ct_domain:withdrawal_provider(?prv(4), ?prx(6), provider_identity_id(Options), C),
ct_domain:withdrawal_provider(?prv(5), ?prx(2), provider_identity_id(Options), C),
ct_domain:withdrawal_provider(?prv(6), ?prx(6), provider_identity_id(Options), C),
ct_domain:withdrawal_provider(?prv(7), ?prx(6), provider_identity_id(Options), C),
ct_domain:withdrawal_provider(?prv(8), ?prx(2), provider_identity_id(Options), C),
ct_domain:withdrawal_provider(?prv(9), ?prx(7), provider_identity_id(Options), C),
ct_domain:withdrawal_provider(?prv(10), ?prx(6), provider_identity_id(Options), C),
ct_domain:withdrawal_provider(?prv(11), ?prx(8), provider_identity_id(Options), C),
ct_domain:withdrawal_provider(?prv(16), ?prx(2), provider_identity_id(Options), C),
ct_domain:withdrawal_provider(?prv(17), ?prx(2), provider_identity_id(Options), C),
ct_domain:withdrawal_provider(?prv(1), ?prx(2), provider_identity_id(Options)),
ct_domain:withdrawal_provider(?prv(2), ?prx(2), provider_identity_id(Options)),
ct_domain:withdrawal_provider(?prv(3), ?prx(3), dummy_provider_identity_id(Options)),
ct_domain:withdrawal_provider(?prv(4), ?prx(6), provider_identity_id(Options)),
ct_domain:withdrawal_provider(?prv(5), ?prx(2), provider_identity_id(Options)),
ct_domain:withdrawal_provider(?prv(6), ?prx(6), provider_identity_id(Options)),
ct_domain:withdrawal_provider(?prv(7), ?prx(6), provider_identity_id(Options)),
ct_domain:withdrawal_provider(?prv(8), ?prx(2), provider_identity_id(Options)),
ct_domain:withdrawal_provider(?prv(9), ?prx(7), provider_identity_id(Options)),
ct_domain:withdrawal_provider(?prv(10), ?prx(6), provider_identity_id(Options)),
ct_domain:withdrawal_provider(?prv(11), ?prx(8), provider_identity_id(Options)),
ct_domain:withdrawal_provider(?prv(16), ?prx(2), provider_identity_id(Options)),
ct_domain:withdrawal_provider(?prv(17), ?prx(2), provider_identity_id(Options)),
ct_domain:contract_template(?tmpl(1), ?trms(1)),
ct_domain:term_set_hierarchy(?trms(1), [ct_domain:timed_term_set(default_termset(Options))]),

View File

@ -3,7 +3,6 @@
-include_lib("stdlib/include/assert.hrl").
-include_lib("damsel/include/dmsl_domain_thrift.hrl").
-include_lib("fistful_proto/include/ff_proto_deposit_thrift.hrl").
-include_lib("shumpune_proto/include/shumpune_shumpune_thrift.hrl").
%% Common test API
@ -718,17 +717,8 @@ get_wallet_balance(ID) ->
{ok, Machine} = ff_wallet_machine:get(ID),
get_account_balance(ff_wallet:account(ff_wallet_machine:wallet(Machine))).
%% NOTE: This function can flap tests after switch to shumpune
%% because of potentially wrong Clock. In common case it should be passed
%% from caller after applying changes to account balance.
%% This will work fine with shumway because it return LatestClock on any
%% balance changes, therefore it will broke tests with shumpune
%% because of proper clocks.
get_account_balance(Account) ->
{ok, {Amounts, Currency}} = ff_transaction:balance(
Account,
ff_clock:latest_clock()
),
{ok, {Amounts, Currency}} = ff_accounting:balance(Account),
{ff_indef:current(Amounts), ff_indef:to_range(Amounts), Currency}.
generate_id() ->

View File

@ -2,7 +2,6 @@
-include_lib("stdlib/include/assert.hrl").
-include_lib("fistful_proto/include/ff_proto_w2w_transfer_thrift.hrl").
-include_lib("shumpune_proto/include/shumpune_shumpune_thrift.hrl").
-export([all/0]).
-export([groups/0]).
@ -307,10 +306,7 @@ get_wallet_balance(ID) ->
get_account_balance(ff_wallet:account(ff_wallet_machine:wallet(Machine))).
get_account_balance(Account) ->
{ok, {Amounts, Currency}} = ff_transaction:balance(
Account,
ff_clock:latest_clock()
),
{ok, {Amounts, Currency}} = ff_accounting:balance(Account),
{ff_indef:current(Amounts), ff_indef:to_range(Amounts), Currency}.
set_wallet_balance({Amount, Currency}, ID) ->
@ -319,31 +315,12 @@ set_wallet_balance({Amount, Currency}, ID) ->
Account = ff_wallet:account(ff_wallet_machine:wallet(Machine)),
AccounterID = ff_account:accounter_account_id(Account),
{CurrentAmount, _, Currency} = get_account_balance(Account),
{ok, AnotherAccounterID} = create_account(Currency),
{ok, AnotherAccounterID} = ct_helper:create_account(Currency),
Postings = [{AnotherAccounterID, AccounterID, {Amount - CurrentAmount, Currency}}],
{ok, _} = ff_transaction:prepare(TransactionID, Postings),
{ok, _} = ff_transaction:commit(TransactionID, Postings),
{ok, _} = ff_accounting:prepare_trx(TransactionID, Postings),
{ok, _} = ff_accounting:commit_trx(TransactionID, Postings),
ok.
create_account(CurrencyCode) ->
Description = <<"ff_test">>,
case call_accounter('CreateAccount', {construct_account_prototype(CurrencyCode, Description)}) of
{ok, Result} ->
{ok, Result};
{exception, Exception} ->
{error, {exception, Exception}}
end.
construct_account_prototype(CurrencyCode, Description) ->
#shumpune_AccountPrototype{
currency_sym_code = CurrencyCode,
description = Description
}.
call_accounter(Function, Args) ->
Service = {shumpune_shumpune_thrift, 'Accounter'},
ff_woody_client:call(accounter, {Service, Function, Args}, woody_context:new()).
create_identity(Party, C) ->
create_identity(Party, <<"good-two">>, C).

View File

@ -3,7 +3,6 @@
-include_lib("stdlib/include/assert.hrl").
-include_lib("damsel/include/dmsl_domain_thrift.hrl").
-include_lib("fistful_proto/include/ff_proto_withdrawal_thrift.hrl").
-include_lib("shumpune_proto/include/shumpune_shumpune_thrift.hrl").
-export([all/0]).
-export([groups/0]).
@ -642,10 +641,7 @@ get_wallet_balance(ID) ->
get_account_balance(ff_wallet:account(ff_wallet_machine:wallet(Machine))).
get_account_balance(Account) ->
{ok, {Amounts, Currency}} = ff_transaction:balance(
Account,
ff_clock:latest_clock()
),
{ok, {Amounts, Currency}} = ff_accounting:balance(Account),
{ff_indef:current(Amounts), ff_indef:to_range(Amounts), Currency}.
generate_id() ->
@ -708,31 +704,12 @@ set_wallet_balance({Amount, Currency}, ID) ->
Account = ff_wallet:account(ff_wallet_machine:wallet(Machine)),
AccounterID = ff_account:accounter_account_id(Account),
{CurrentAmount, _, Currency} = get_account_balance(Account),
{ok, AnotherAccounterID} = create_account(Currency),
{ok, AnotherAccounterID} = ct_helper:create_account(Currency),
Postings = [{AnotherAccounterID, AccounterID, {Amount - CurrentAmount, Currency}}],
{ok, _} = ff_transaction:prepare(TransactionID, Postings),
{ok, _} = ff_transaction:commit(TransactionID, Postings),
{ok, _} = ff_accounting:prepare_trx(TransactionID, Postings),
{ok, _} = ff_accounting:commit_trx(TransactionID, Postings),
ok.
create_account(CurrencyCode) ->
Description = <<"ff_test">>,
case call_accounter('CreateAccount', {construct_account_prototype(CurrencyCode, Description)}) of
{ok, Result} ->
{ok, Result};
{exception, Exception} ->
{error, {exception, Exception}}
end.
construct_account_prototype(CurrencyCode, Description) ->
#shumpune_AccountPrototype{
currency_sym_code = CurrencyCode,
description = Description
}.
call_accounter(Function, Args) ->
Service = {shumpune_shumpune_thrift, 'Accounter'},
ff_woody_client:call(accounter, {Service, Function, Args}, woody_context:new()).
make_cash({Amount, Currency}) ->
#'fistful_base_Cash'{
amount = Amount,

View File

@ -40,7 +40,7 @@
-type identdoc_token() ::
binary().
-type cash() :: ff_transaction:body().
-type cash() :: ff_accounting:body().
-type withdrawal() :: #{
id => binary(),

View File

@ -40,7 +40,7 @@
-type params() :: #{
id := id(),
body := ff_transaction:body(),
body := ff_accounting:body(),
source_id := ff_source:id(),
wallet_id := ff_wallet:id(),
external_id => external_id()
@ -191,7 +191,7 @@
-type wallet() :: ff_wallet:wallet_state().
-type revert() :: ff_deposit_revert:revert().
-type revert_id() :: ff_deposit_revert:id().
-type body() :: ff_transaction:body().
-type body() :: ff_accounting:body().
-type cash() :: ff_cash:cash().
-type cash_range() :: ff_range:range(cash()).
-type action() :: machinery:action() | undefined.
@ -209,7 +209,6 @@
-type domain_revision() :: ff_domain_config:revision().
-type identity() :: ff_identity:identity_state().
-type terms() :: ff_party:terms().
-type clock() :: ff_transaction:clock().
-type metadata() :: ff_entity_context:md().
-type transfer_params() :: #{
@ -563,9 +562,8 @@ process_limit_check(Deposit) ->
domain_revision => DomainRevision,
varset => Varset
}),
Clock = ff_postings_transfer:clock(p_transfer(Deposit)),
Events =
case validate_wallet_limits(Terms, Wallet, Clock) of
case validate_wallet_limits(Terms, Wallet) of
{ok, valid} ->
[{limit_check, {wallet_receiver, ok}}];
{error, {terms_violation, {wallet_limit, {cash_range, {Cash, Range}}}}} ->
@ -746,11 +744,11 @@ is_limit_check_ok({wallet_receiver, ok}) ->
is_limit_check_ok({wallet_receiver, {failed, _Details}}) ->
false.
-spec validate_wallet_limits(terms(), wallet(), clock()) ->
-spec validate_wallet_limits(terms(), wallet()) ->
{ok, valid}
| {error, {terms_violation, {wallet_limit, {cash_range, {cash(), cash_range()}}}}}.
validate_wallet_limits(Terms, Wallet, Clock) ->
case ff_party:validate_wallet_limits(Terms, Wallet, Clock) of
validate_wallet_limits(Terms, Wallet) ->
case ff_party:validate_wallet_limits(Terms, Wallet) of
{ok, valid} = Result ->
Result;
{error, {terms_violation, {cash_range, {Cash, CashRange}}}} ->

View File

@ -134,7 +134,7 @@
-type wallet() :: ff_wallet:wallet_state().
-type source_id() :: ff_source:id().
-type p_transfer() :: ff_postings_transfer:transfer().
-type body() :: ff_transaction:body().
-type body() :: ff_accounting:body().
-type action() :: machinery:action() | undefined.
-type process_result() :: {action(), [event()]}.
-type legacy_event() :: any().
@ -150,7 +150,6 @@
-type domain_revision() :: ff_domain_config:revision().
-type identity() :: ff_identity:identity_state().
-type terms() :: ff_party:terms().
-type clock() :: ff_transaction:clock().
-type wrapped_adjustment_event() :: ff_adjustment_utils:wrapped_event().
@ -425,9 +424,8 @@ process_limit_check(Revert) ->
varset => Varset
}),
Clock = ff_postings_transfer:clock(p_transfer(Revert)),
Events =
case validate_wallet_limits(Terms, Wallet, Clock) of
case validate_wallet_limits(Terms, Wallet) of
{ok, valid} ->
[{limit_check, {wallet_receiver, ok}}];
{error, {terms_violation, {wallet_limit, {cash_range, {Cash, Range}}}}} ->
@ -688,11 +686,11 @@ is_limit_check_ok({wallet_receiver, ok}) ->
is_limit_check_ok({wallet_receiver, {failed, _Details}}) ->
false.
-spec validate_wallet_limits(terms(), wallet(), clock()) ->
-spec validate_wallet_limits(terms(), wallet()) ->
{ok, valid}
| {error, validation_error()}.
validate_wallet_limits(Terms, Wallet, Clock) ->
case ff_party:validate_wallet_limits(Terms, Wallet, Clock) of
validate_wallet_limits(Terms, Wallet) ->
case ff_party:validate_wallet_limits(Terms, Wallet) of
{ok, valid} = Result ->
Result;
{error, {terms_violation, {cash_range, {Cash, CashRange}}}} ->

View File

@ -8,7 +8,6 @@
-include_lib("damsel/include/dmsl_withdrawals_provider_adapter_thrift.hrl").
-type id() :: binary().
-type clock() :: ff_transaction:clock().
-define(ACTUAL_FORMAT_VERSION, 4).
@ -86,7 +85,7 @@
wallet_id := ff_wallet_machine:id(),
currency_from := ff_currency:id(),
currency_to := ff_currency:id(),
body := ff_transaction:body(),
body := ff_accounting:body(),
destination_id => ff_destination:id(),
external_id => id()
}.
@ -239,7 +238,7 @@
%% Internal types
-type body() :: ff_transaction:body().
-type body() :: ff_accounting:body().
-type identity() :: ff_identity:identity_state().
-type party_id() :: ff_party:id().
-type wallet_id() :: ff_wallet:id().
@ -844,9 +843,8 @@ process_limit_check(Withdrawal) ->
domain_revision => DomainRevision,
varset => build_party_varset(VarsetParams)
}),
Clock = ff_postings_transfer:clock(p_transfer(Withdrawal)),
Events =
case validate_wallet_limits(Terms, Wallet, Clock) of
case validate_wallet_limits(Terms, Wallet) of
{ok, valid} ->
[{limit_check, {wallet_sender, ok}}];
{error, {terms_violation, {wallet_limit, {cash_range, {Cash, Range}}}}} ->
@ -1456,11 +1454,11 @@ is_limit_check_ok({wallet_sender, ok}) ->
is_limit_check_ok({wallet_sender, {failed, _Details}}) ->
false.
-spec validate_wallet_limits(terms(), wallet(), clock()) ->
-spec validate_wallet_limits(terms(), wallet()) ->
{ok, valid}
| {error, {terms_violation, {wallet_limit, {cash_range, {cash(), cash_range()}}}}}.
validate_wallet_limits(Terms, Wallet, Clock) ->
case ff_party:validate_wallet_limits(Terms, Wallet, Clock) of
validate_wallet_limits(Terms, Wallet) ->
case ff_party:validate_wallet_limits(Terms, Wallet) of
{ok, valid} = Result ->
Result;
{error, {terms_violation, {cash_range, {Cash, CashRange}}}} ->

View File

@ -78,7 +78,7 @@
-type data() :: #{
id := id(),
cash := ff_transaction:body(),
cash := ff_accounting:body(),
sender := ff_identity:identity_state(),
receiver := ff_identity:identity_state(),
quote_data => ff_adapter_withdrawal:quote_data()

View File

@ -321,17 +321,8 @@ get_wallet_balance(ID) ->
{ok, Machine} = ff_wallet_machine:get(ID),
get_account_balance(ff_wallet:account(ff_wallet_machine:wallet(Machine))).
%% NOTE: This function can flap tests after switch to shumpune
%% because of potentially wrong Clock. In common case it should be passed
%% from caller after applying changes to account balance.
%% This will work fine with shumway because it return LatestClock on any
%% balance changes, therefore it will broke tests with shumpune
%% because of proper clocks.
get_account_balance(Account) ->
{ok, {Amounts, Currency}} = ff_transaction:balance(
Account,
ff_clock:latest_clock()
),
{ok, {Amounts, Currency}} = ff_accounting:balance(Account),
{ff_indef:current(Amounts), ff_indef:to_range(Amounts), Currency}.
generate_id() ->

View File

@ -432,10 +432,7 @@ get_source_balance(ID) ->
get_account_balance(ff_source:account(Source)).
get_account_balance(Account) ->
{ok, {Amounts, Currency}} = ff_transaction:balance(
Account,
ff_clock:latest_clock()
),
{ok, {Amounts, Currency}} = ff_accounting:balance(Account),
{ff_indef:current(Amounts), ff_indef:to_range(Amounts), Currency}.
generate_id() ->

View File

@ -1,7 +1,6 @@
-module(ff_deposit_revert_SUITE).
-include_lib("stdlib/include/assert.hrl").
-include_lib("shumpune_proto/include/shumpune_shumpune_thrift.hrl").
%% Common test API
@ -435,17 +434,14 @@ set_wallet_balance({Amount, Currency}, ID) ->
Account = ff_wallet:account(ff_wallet_machine:wallet(Machine)),
AccounterID = ff_account:accounter_account_id(Account),
{CurrentAmount, _, Currency} = get_account_balance(Account),
{ok, AnotherAccounterID} = create_account(Currency),
{ok, AnotherAccounterID} = ct_helper:create_account(Currency),
Postings = [{AccounterID, AnotherAccounterID, {CurrentAmount - Amount, Currency}}],
{ok, _} = ff_transaction:prepare(TransactionID, Postings),
{ok, _} = ff_transaction:commit(TransactionID, Postings),
{ok, _} = ff_accounting:prepare_trx(TransactionID, Postings),
{ok, _} = ff_accounting:commit_trx(TransactionID, Postings),
ok.
get_account_balance(Account) ->
{ok, {Amounts, Currency}} = ff_transaction:balance(
Account,
ff_clock:latest_clock()
),
{ok, {Amounts, Currency}} = ff_accounting:balance(Account),
{ff_indef:current(Amounts), ff_indef:to_range(Amounts), Currency}.
generate_id() ->
@ -465,22 +461,3 @@ create_source(IID, _C) ->
end
),
ID.
create_account(CurrencyCode) ->
Description = <<"ff_test">>,
case call_accounter('CreateAccount', {construct_account_prototype(CurrencyCode, Description)}) of
{ok, Result} ->
{ok, Result};
{exception, Exception} ->
{error, {exception, Exception}}
end.
construct_account_prototype(CurrencyCode, Description) ->
#shumpune_AccountPrototype{
currency_sym_code = CurrencyCode,
description = Description
}.
call_accounter(Function, Args) ->
Service = {shumpune_shumpune_thrift, 'Accounter'},
ff_woody_client:call(accounter, {Service, Function, Args}, woody_context:new()).

View File

@ -1,7 +1,6 @@
-module(ff_deposit_revert_adjustment_SUITE).
-include_lib("stdlib/include/assert.hrl").
-include_lib("shumpune_proto/include/shumpune_shumpune_thrift.hrl").
%% Common test API
@ -484,17 +483,14 @@ set_wallet_balance({Amount, Currency}, ID) ->
Account = ff_wallet:account(ff_wallet_machine:wallet(Machine)),
AccounterID = ff_account:accounter_account_id(Account),
{CurrentAmount, _, Currency} = get_account_balance(Account),
{ok, AnotherAccounterID} = create_account(Currency),
{ok, AnotherAccounterID} = ct_helper:create_account(Currency),
Postings = [{AccounterID, AnotherAccounterID, {CurrentAmount - Amount, Currency}}],
{ok, _} = ff_transaction:prepare(TransactionID, Postings),
{ok, _} = ff_transaction:commit(TransactionID, Postings),
{ok, _} = ff_accounting:prepare_trx(TransactionID, Postings),
{ok, _} = ff_accounting:commit_trx(TransactionID, Postings),
ok.
get_account_balance(Account) ->
{ok, {Amounts, Currency}} = ff_transaction:balance(
Account,
ff_clock:latest_clock()
),
{ok, {Amounts, Currency}} = ff_accounting:balance(Account),
{ff_indef:current(Amounts), ff_indef:to_range(Amounts), Currency}.
generate_id() ->
@ -514,22 +510,3 @@ create_source(IID, _C) ->
end
),
ID.
create_account(CurrencyCode) ->
Description = <<"ff_test">>,
case call_accounter('CreateAccount', {construct_account_prototype(CurrencyCode, Description)}) of
{ok, Result} ->
{ok, Result};
{exception, Exception} ->
{error, {exception, Exception}}
end.
construct_account_prototype(CurrencyCode, Description) ->
#shumpune_AccountPrototype{
currency_sym_code = CurrencyCode,
description = Description
}.
call_accounter(Function, Args) ->
Service = {shumpune_shumpune_thrift, 'Accounter'},
ff_woody_client:call(accounter, {Service, Function, Args}, woody_context:new()).

View File

@ -444,10 +444,7 @@ get_destination_balance(ID) ->
get_account_balance(ff_destination:account(Destination)).
get_account_balance(Account) ->
{ok, {Amounts, Currency}} = ff_transaction:balance(
Account,
ff_clock:latest_clock()
),
{ok, {Amounts, Currency}} = ff_accounting:balance(Account),
{ff_indef:current(Amounts), ff_indef:to_range(Amounts), Currency}.
create_source(IdentityID, Name, Currency, Resource) ->

View File

@ -5,7 +5,6 @@
-include_lib("damsel/include/dmsl_domain_thrift.hrl").
-include_lib("fistful_proto/include/ff_proto_withdrawal_session_thrift.hrl").
-include_lib("fistful_proto/include/ff_proto_withdrawal_thrift.hrl").
-include_lib("shumpune_proto/include/shumpune_shumpune_thrift.hrl").
%% Common test API
@ -897,10 +896,7 @@ get_wallet_balance(ID) ->
get_account_balance(ff_wallet:account(ff_wallet_machine:wallet(Machine))).
get_account_balance(Account) ->
{ok, {Amounts, Currency}} = ff_transaction:balance(
Account,
ff_clock:latest_clock()
),
{ok, {Amounts, Currency}} = ff_accounting:balance(Account),
{ff_indef:current(Amounts), ff_indef:to_range(Amounts), Currency}.
generate_id() ->
@ -984,31 +980,12 @@ set_wallet_balance({Amount, Currency}, ID) ->
Account = ff_wallet:account(ff_wallet_machine:wallet(Machine)),
AccounterID = ff_account:accounter_account_id(Account),
{CurrentAmount, _, Currency} = get_account_balance(Account),
{ok, AnotherAccounterID} = create_account(Currency),
{ok, AnotherAccounterID} = ct_helper:create_account(Currency),
Postings = [{AnotherAccounterID, AccounterID, {Amount - CurrentAmount, Currency}}],
{ok, _} = ff_transaction:prepare(TransactionID, Postings),
{ok, _} = ff_transaction:commit(TransactionID, Postings),
{ok, _} = ff_accounting:prepare_trx(TransactionID, Postings),
{ok, _} = ff_accounting:commit_trx(TransactionID, Postings),
ok.
create_account(CurrencyCode) ->
Description = <<"ff_test">>,
case call_accounter('CreateAccount', {construct_account_prototype(CurrencyCode, Description)}) of
{ok, Result} ->
{ok, Result};
{exception, Exception} ->
{error, {exception, Exception}}
end.
construct_account_prototype(CurrencyCode, Description) ->
#shumpune_AccountPrototype{
currency_sym_code = CurrencyCode,
description = Description
}.
call_accounter(Function, Args) ->
Service = {shumpune_shumpune_thrift, 'Accounter'},
ff_woody_client:call(accounter, {Service, Function, Args}, woody_context:new()).
make_dummy_party_change(PartyID) ->
{ok, _ContractID} = ff_party:create_contract(PartyID, #{
payinst => #domain_PaymentInstitutionRef{id = 1},

View File

@ -1,7 +1,6 @@
-module(ff_withdrawal_adjustment_SUITE).
-include_lib("stdlib/include/assert.hrl").
-include_lib("shumpune_proto/include/shumpune_shumpune_thrift.hrl").
%% Common test API
@ -434,10 +433,7 @@ get_destination_balance(ID) ->
get_account_balance(ff_destination:account(Destination)).
get_account_balance(Account) ->
{ok, {Amounts, Currency}} = ff_transaction:balance(
Account,
ff_clock:latest_clock()
),
{ok, {Amounts, Currency}} = ff_accounting:balance(Account),
{ff_indef:current(Amounts), ff_indef:to_range(Amounts), Currency}.
generate_id() ->
@ -464,27 +460,8 @@ set_wallet_balance({Amount, Currency}, ID) ->
Account = ff_wallet:account(ff_wallet_machine:wallet(Machine)),
AccounterID = ff_account:accounter_account_id(Account),
{CurrentAmount, _, Currency} = get_account_balance(Account),
{ok, AnotherAccounterID} = create_account(Currency),
{ok, AnotherAccounterID} = ct_helper:create_account(Currency),
Postings = [{AnotherAccounterID, AccounterID, {Amount - CurrentAmount, Currency}}],
{ok, _} = ff_transaction:prepare(TransactionID, Postings),
{ok, _} = ff_transaction:commit(TransactionID, Postings),
{ok, _} = ff_accounting:prepare_trx(TransactionID, Postings),
{ok, _} = ff_accounting:commit_trx(TransactionID, Postings),
ok.
create_account(CurrencyCode) ->
Description = <<"ff_test">>,
case call_accounter('CreateAccount', {construct_account_prototype(CurrencyCode, Description)}) of
{ok, Result} ->
{ok, Result};
{exception, Exception} ->
{error, {exception, Exception}}
end.
construct_account_prototype(CurrencyCode, Description) ->
#shumpune_AccountPrototype{
currency_sym_code = CurrencyCode,
description = Description
}.
call_accounter(Function, Args) ->
Service = {shumpune_shumpune_thrift, 'Accounter'},
ff_woody_client:call(accounter, {Service, Function, Args}, woody_context:new()).

View File

@ -18,7 +18,6 @@
-include_lib("stdlib/include/assert.hrl").
-include_lib("damsel/include/dmsl_domain_thrift.hrl").
-include_lib("shumpune_proto/include/shumpune_shumpune_thrift.hrl").
%% Common test API
@ -332,10 +331,7 @@ get_wallet_balance(ID) ->
get_account_balance(ff_wallet:account(ff_wallet_machine:wallet(Machine))).
get_account_balance(Account) ->
{ok, {Amounts, Currency}} = ff_transaction:balance(
Account,
ff_clock:latest_clock()
),
{ok, {Amounts, Currency}} = ff_accounting:balance(Account),
{ff_indef:current(Amounts), ff_indef:to_range(Amounts), Currency}.
create_destination(IID, Currency, C) ->
@ -364,27 +360,8 @@ set_wallet_balance({Amount, Currency}, ID) ->
Account = ff_wallet:account(ff_wallet_machine:wallet(Machine)),
AccounterID = ff_account:accounter_account_id(Account),
{CurrentAmount, _, Currency} = get_account_balance(Account),
{ok, AnotherAccounterID} = create_account(Currency),
{ok, AnotherAccounterID} = ct_helper:create_account(Currency),
Postings = [{AnotherAccounterID, AccounterID, {Amount - CurrentAmount, Currency}}],
{ok, _} = ff_transaction:prepare(TransactionID, Postings),
{ok, _} = ff_transaction:commit(TransactionID, Postings),
{ok, _} = ff_accounting:prepare_trx(TransactionID, Postings),
{ok, _} = ff_accounting:commit_trx(TransactionID, Postings),
ok.
create_account(CurrencyCode) ->
Description = <<"ff_test">>,
case call_accounter('CreateAccount', {construct_account_prototype(CurrencyCode, Description)}) of
{ok, Result} ->
{ok, Result};
{exception, Exception} ->
{error, {exception, Exception}}
end.
construct_account_prototype(CurrencyCode, Description) ->
#shumpune_AccountPrototype{
currency_sym_code = CurrencyCode,
description = Description
}.
call_accounter(Function, Args) ->
Service = {shumpune_shumpune_thrift, 'Accounter'},
ff_woody_client:call(accounter, {Service, Function, Args}, woody_context:new()).

View File

@ -9,10 +9,10 @@
-module(ff_account).
-include_lib("shumpune_proto/include/shumpune_shumpune_thrift.hrl").
-include_lib("damsel/include/dmsl_accounter_thrift.hrl").
-type id() :: binary().
-type accounter_account_id() :: shumpune_shumpune_thrift:'AccountID'().
-type accounter_account_id() :: dmsl_accounter_thrift:'AccountID'().
-type account() :: #{
id := id(),
identity := identity_id(),
@ -104,7 +104,9 @@ create(ID, Identity, Currency) ->
}),
CurrencyID = ff_currency:id(Currency),
valid = unwrap(terms, ff_party:validate_account_creation(Terms, CurrencyID)),
{ok, AccounterID} = create_account(ID, Currency),
CurrencyCode = ff_currency:symcode(Currency),
Description = ff_string:join($/, [<<"ff/account">>, ID]),
{ok, AccounterID} = ff_accounting:create_account(CurrencyCode, Description),
[
{created, #{
id => ID,
@ -133,28 +135,3 @@ get_identity(Account) ->
-spec apply_event(event(), ff_maybe:maybe(account())) -> account().
apply_event({created, Account}, undefined) ->
Account.
%% Accounter client
-spec create_account(id(), currency()) ->
{ok, accounter_account_id()}
| {error, {exception, any()}}.
create_account(ID, Currency) ->
CurrencyCode = ff_currency:symcode(Currency),
Description = ff_string:join($/, [<<"ff/account">>, ID]),
case call_accounter('CreateAccount', {construct_prototype(CurrencyCode, Description)}) of
{ok, Result} ->
{ok, Result};
{exception, Exception} ->
{error, {exception, Exception}}
end.
construct_prototype(CurrencyCode, Description) ->
#shumpune_AccountPrototype{
currency_sym_code = CurrencyCode,
description = Description
}.
call_accounter(Function, Args) ->
Service = {shumpune_shumpune_thrift, 'Accounter'},
ff_woody_client:call(accounter, {Service, Function, Args}).

View File

@ -1,111 +1,118 @@
%%%
%%% Financial transaction between accounts
%%%
%%% - Rename to `ff_posting_plan`?
%%%
-module(ff_accounting).
-module(ff_transaction).
-include_lib("shumpune_proto/include/shumpune_shumpune_thrift.hrl").
-include_lib("damsel/include/dmsl_accounter_thrift.hrl").
%%
-type id() :: shumpune_shumpune_thrift:'PlanID'().
-type id() :: dmsl_accounter_thrift:'PlanID'().
-type account() :: ff_account:account().
-type account_id() :: ff_account:accounter_account_id().
-type clock() :: ff_clock:clock().
-type currency_code() :: dmsl_domain_thrift:'CurrencySymbolicCode'().
-type amount() :: dmsl_domain_thrift:'Amount'().
-type body() :: ff_cash:cash().
-type posting() :: {account_id(), account_id(), body()}.
-type balance() :: {ff_indef:indef(amount()), ff_currency:id()}.
-type posting_plan_log() :: dmsl_accounter_thrift:'PostingPlanLog'().
-export_type([id/0]).
-export_type([body/0]).
-export_type([account/0]).
-export_type([posting/0]).
-export_type([clock/0]).
%% TODO
%% - Module name is misleading then
-export([balance/2]).
-export([balance/1]).
-export([create_account/2]).
-export([prepare/2]).
-export([commit/2]).
-export([cancel/2]).
-export([prepare_trx/2]).
-export([commit_trx/2]).
-export([cancel_trx/2]).
%%
-spec balance(account(), clock()) -> {ok, balance()}.
balance(Account, Clock) ->
-spec balance(account()) -> {ok, balance()}.
balance(Account) ->
AccountID = ff_account:accounter_account_id(Account),
Currency = ff_account:currency(Account),
{ok, Balance} = get_balance_by_id(AccountID, Clock),
{ok, build_account_balance(Balance, Currency)}.
{ok, ThriftAccount} = get_account_by_id(AccountID),
{ok, build_account_balance(ThriftAccount, Currency)}.
-spec prepare(id(), [posting()]) -> {ok, clock()}.
prepare(ID, Postings) ->
-spec create_account(currency_code(), binary() | undefined) ->
{ok, account_id()}
| {error, {exception, any()}}.
create_account(CurrencyCode, Description) ->
case call('CreateAccount', {construct_prototype(CurrencyCode, Description)}) of
{ok, Result} ->
{ok, Result};
{exception, Exception} ->
{error, {exception, Exception}}
end.
-spec prepare_trx(id(), [posting()]) -> {ok, posting_plan_log()}.
prepare_trx(ID, Postings) ->
hold(encode_plan_change(ID, Postings)).
-spec commit(id(), [posting()]) -> {ok, clock()}.
commit(ID, Postings) ->
-spec commit_trx(id(), [posting()]) -> {ok, posting_plan_log()}.
commit_trx(ID, Postings) ->
commit_plan(encode_plan(ID, Postings)).
-spec cancel(id(), [posting()]) -> {ok, clock()}.
cancel(ID, Postings) ->
-spec cancel_trx(id(), [posting()]) -> {ok, posting_plan_log()}.
cancel_trx(ID, Postings) ->
rollback_plan(encode_plan(ID, Postings)).
%% Woody stuff
get_balance_by_id(ID, Clock) ->
case call('GetBalanceByID', {ID, ff_clock:marshal(shumpune, Clock)}) of
{ok, Balance} ->
{ok, Balance};
get_account_by_id(ID) ->
case call('GetAccountByID', {ID}) of
{ok, Account} ->
{ok, Account};
{exception, Unexpected} ->
error(Unexpected)
end.
hold(PlanChange) ->
case call('Hold', {PlanChange}) of
{ok, Clock} ->
{ok, ff_clock:unmarshal(shumpune, Clock)};
{ok, PostingPlanLog} ->
{ok, PostingPlanLog};
{exception, Unexpected} ->
error(Unexpected)
end.
commit_plan(Plan) ->
case call('CommitPlan', {Plan}) of
{ok, Clock} ->
{ok, ff_clock:unmarshal(shumpune, Clock)};
{ok, PostingPlanLog} ->
{ok, PostingPlanLog};
{exception, Unexpected} ->
error(Unexpected)
end.
rollback_plan(Plan) ->
case call('RollbackPlan', {Plan}) of
{ok, Clock} ->
{ok, ff_clock:unmarshal(shumpune, Clock)};
{ok, PostingPlanLog} ->
{ok, PostingPlanLog};
{exception, Unexpected} ->
error(Unexpected)
end.
call(Function, Args) ->
Service = {shumpune_shumpune_thrift, 'Accounter'},
Service = {dmsl_accounter_thrift, 'Accounter'},
ff_woody_client:call(accounter, {Service, Function, Args}).
encode_plan_change(ID, Postings) ->
#shumpune_PostingPlanChange{
#accounter_PostingPlanChange{
id = ID,
batch = encode_batch(Postings)
}.
encode_plan(ID, Postings) ->
#shumpune_PostingPlan{
#accounter_PostingPlan{
id = ID,
batch_list = [encode_batch(Postings)]
}.
encode_batch(Postings) ->
#shumpune_PostingBatch{
#accounter_PostingBatch{
% TODO
id = 1,
postings = [
@ -115,7 +122,7 @@ encode_batch(Postings) ->
}.
encode_posting(Source, Destination, {Amount, Currency}) ->
#shumpune_Posting{
#accounter_Posting{
from_id = Source,
to_id = Destination,
amount = Amount,
@ -124,7 +131,7 @@ encode_posting(Source, Destination, {Amount, Currency}) ->
}.
build_account_balance(
#shumpune_Balance{
#accounter_Account{
own_amount = Own,
max_available_amount = MaxAvail,
min_available_amount = MinAvail
@ -132,3 +139,9 @@ build_account_balance(
Currency
) ->
{ff_indef:new(MinAvail, Own, MaxAvail), Currency}.
construct_prototype(CurrencyCode, Description) ->
#accounter_AccountPrototype{
currency_sym_code = CurrencyCode,
description = Description
}.

View File

@ -108,7 +108,7 @@
-import(ff_pipeline, [do/1, unwrap/1, unwrap/2]).
%% Internal types
-type cash() :: ff_transaction:body().
-type cash() :: ff_accounting:body().
-type account() :: ff_account:account().
-type finalize_error() :: {postings, posting_finalize_error()}.

View File

@ -1,7 +1,6 @@
-module(ff_clock).
-include_lib("fistful_proto/include/ff_proto_transfer_thrift.hrl").
-include_lib("shumpune_proto/include/shumpune_shumpune_thrift.hrl").
-define(VERSION, 1).
-define(TYPE_LATEST, latest).
@ -9,7 +8,7 @@
-type type() :: ?TYPE_LATEST | ?TYPE_VECTOR.
-type version() :: non_neg_integer().
-type kind() :: transfer | shumpune.
-type kind() :: transfer.
-opaque clock() :: #{
version := version(),
@ -31,31 +30,17 @@ latest_clock() ->
new(?TYPE_LATEST).
-spec marshal(kind(), clock()) ->
ff_proto_transfer_thrift:'Clock'()
| shumpune_shumpune_thrift:'Clock'().
ff_proto_transfer_thrift:'Clock'().
marshal(transfer, #{type := ?TYPE_LATEST = Type}) ->
{Type, #transfer_LatestClock{}};
marshal(transfer, #{type := ?TYPE_VECTOR = Type, state := State}) ->
{Type, #transfer_VectorClock{state = State}};
marshal(shumpune, #{type := ?TYPE_LATEST = Type}) ->
{Type, #shumpune_LatestClock{}};
marshal(shumpune, #{type := ?TYPE_VECTOR = Type, state := State}) ->
{Type, #shumpune_VectorClock{state = State}}.
{Type, #transfer_VectorClock{state = State}}.
-spec unmarshal(kind(), Clock) -> clock() when
Clock ::
ff_proto_transfer_thrift:'Clock'()
| shumpune_shumpune_thrift:'Clock'().
Clock :: ff_proto_transfer_thrift:'Clock'().
unmarshal(transfer, {?TYPE_LATEST = Type, #transfer_LatestClock{}}) ->
new(Type);
unmarshal(transfer, {?TYPE_VECTOR = Type, #transfer_VectorClock{state = State}}) ->
Clock = new(Type),
Clock#{
state => State
};
unmarshal(shumpune, {?TYPE_LATEST = Type, #shumpune_LatestClock{}}) ->
new(Type);
unmarshal(shumpune, {?TYPE_VECTOR = Type, #shumpune_VectorClock{state = State}}) ->
Clock = new(Type),
Clock#{
state => State

View File

@ -13,7 +13,6 @@
-type id() :: dmsl_domain_thrift:'PartyID'().
-type contract_id() :: dmsl_domain_thrift:'ContractID'().
-type wallet_id() :: dmsl_domain_thrift:'WalletID'().
-type clock() :: ff_transaction:clock().
-type revision() :: dmsl_domain_thrift:'PartyRevision'().
-type terms() :: dmsl_domain_thrift:'TermSet'().
-type attempt_limit() :: integer().
@ -84,7 +83,7 @@
-export([validate_withdrawal_creation/3]).
-export([validate_deposit_creation/2]).
-export([validate_w2w_transfer_creation/2]).
-export([validate_wallet_limits/3]).
-export([validate_wallet_limits/2]).
-export([get_contract_terms/6]).
-export([compute_payment_institution/3]).
-export([compute_routing_ruleset/3]).
@ -725,11 +724,11 @@ validate_wallet_terms_currency(CurrencyID, Terms) ->
} = Terms,
validate_currency(CurrencyID, Currencies).
-spec validate_wallet_limits(terms(), wallet(), clock()) ->
-spec validate_wallet_limits(terms(), wallet()) ->
{ok, valid}
| {error, invalid_wallet_terms_error()}
| {error, cash_range_validation_error()}.
validate_wallet_limits(Terms, Wallet, Clock) ->
validate_wallet_limits(Terms, Wallet) ->
do(fun() ->
#domain_TermSet{wallets = WalletTerms} = Terms,
valid = unwrap(validate_wallet_limits_terms_is_reduced(WalletTerms)),
@ -737,7 +736,7 @@ validate_wallet_limits(Terms, Wallet, Clock) ->
wallet_limit = {value, CashRange}
} = WalletTerms,
Account = ff_wallet:account(Wallet),
valid = unwrap(validate_account_balance(Account, CashRange, Clock))
valid = unwrap(validate_account_balance(Account, CashRange))
end).
-spec validate_wallet_limits_terms_is_reduced(wallet_terms()) -> {ok, valid} | {error, {invalid_terms, _Details}}.
@ -826,17 +825,12 @@ validate_currency(CurrencyID, Currencies) ->
{error, {terms_violation, {not_allowed_currency, {CurrencyRef, Currencies}}}}
end.
-spec validate_account_balance(ff_account:account(), domain_cash_range(), clock()) ->
-spec validate_account_balance(ff_account:account(), domain_cash_range()) ->
{ok, valid}
| {error, cash_range_validation_error()}.
validate_account_balance(Account, CashRange, Clock) ->
validate_account_balance(Account, CashRange) ->
do(fun() ->
{Amounts, CurrencyID} = unwrap(
ff_transaction:balance(
Account,
Clock
)
),
{Amounts, CurrencyID} = unwrap(ff_accounting:balance(Account)),
ExpMinCash = ff_dmsl_codec:marshal(cash, {ff_indef:expmin(Amounts), CurrencyID}),
ExpMaxCash = ff_dmsl_codec:marshal(cash, {ff_indef:expmax(Amounts), CurrencyID}),
valid = unwrap(validate_cash_range(ExpMinCash, CashRange)),

View File

@ -14,7 +14,6 @@
-module(ff_postings_transfer).
-type final_cash_flow() :: ff_cash_flow:final_cash_flow().
-type clock() :: ff_clock:clock().
-type status() ::
created
@ -25,13 +24,11 @@
-type transfer() :: #{
id := id(),
final_cash_flow := final_cash_flow(),
status => status(),
clock => clock()
status => status()
}.
-type event() ::
{created, transfer()}
| {clock_updated, clock()}
| {status_changed, status()}.
-export_type([transfer/0]).
@ -42,7 +39,6 @@
-export([id/1]).
-export([final_cash_flow/1]).
-export([status/1]).
-export([clock/1]).
-export([create/2]).
-export([prepare/1]).
@ -60,7 +56,7 @@
%% Internal types
-type id() :: ff_transaction:id().
-type id() :: ff_accounting:id().
-type account() :: ff_account:account().
%%
@ -68,7 +64,6 @@
-spec id(transfer()) -> id().
-spec final_cash_flow(transfer()) -> final_cash_flow().
-spec status(transfer()) -> status().
-spec clock(transfer()) -> clock().
id(#{id := V}) ->
V.
@ -79,11 +74,6 @@ final_cash_flow(#{final_cash_flow := V}) ->
status(#{status := V}) ->
V.
clock(#{clock := V}) ->
V;
clock(_) ->
ff_clock:latest_clock().
%%
-spec create(id(), final_cash_flow()) ->
@ -139,8 +129,8 @@ prepare(Transfer = #{status := created}) ->
ID = id(Transfer),
CashFlow = final_cash_flow(Transfer),
do(fun() ->
Clock = unwrap(ff_transaction:prepare(ID, construct_trx_postings(CashFlow))),
[{clock_updated, Clock}, {status_changed, prepared}]
_PostingPlanLog = unwrap(ff_accounting:prepare_trx(ID, construct_trx_postings(CashFlow))),
[{status_changed, prepared}]
end);
prepare(#{status := prepared}) ->
{ok, []};
@ -160,8 +150,8 @@ commit(Transfer = #{status := prepared}) ->
ID = id(Transfer),
CashFlow = final_cash_flow(Transfer),
do(fun() ->
Clock = unwrap(ff_transaction:commit(ID, construct_trx_postings(CashFlow))),
[{clock_updated, Clock}, {status_changed, committed}]
_PostingPlanLog = unwrap(ff_accounting:commit_trx(ID, construct_trx_postings(CashFlow))),
[{status_changed, committed}]
end);
commit(#{status := committed}) ->
{ok, []};
@ -177,8 +167,8 @@ cancel(Transfer = #{status := prepared}) ->
ID = id(Transfer),
CashFlow = final_cash_flow(Transfer),
do(fun() ->
Clock = unwrap(ff_transaction:cancel(ID, construct_trx_postings(CashFlow))),
[{clock_updated, Clock}, {status_changed, cancelled}]
_PostingPlanLog = unwrap(ff_accounting:cancel_trx(ID, construct_trx_postings(CashFlow))),
[{status_changed, cancelled}]
end);
cancel(#{status := cancelled}) ->
{ok, []};
@ -190,18 +180,16 @@ cancel(#{status := Status}) ->
-spec apply_event(event(), ff_maybe:maybe(account())) -> account().
apply_event({created, Transfer}, undefined) ->
Transfer;
apply_event({clock_updated, Clock}, Transfer) ->
Transfer#{clock => Clock};
apply_event({status_changed, S}, Transfer) ->
Transfer#{status => S}.
%%
-spec construct_trx_postings(final_cash_flow()) -> [ff_transaction:posting()].
-spec construct_trx_postings(final_cash_flow()) -> [ff_accounting:posting()].
construct_trx_postings(#{postings := Postings}) ->
lists:map(fun construct_trx_posting/1, Postings).
-spec construct_trx_posting(ff_cash_flow:final_posting()) -> ff_transaction:posting().
-spec construct_trx_posting(ff_cash_flow:final_posting()) -> ff_accounting:posting().
construct_trx_posting(Posting) ->
#{
sender := #{account := Sender},

View File

@ -196,7 +196,7 @@ check_accessible(Wallet) ->
-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()),
{ok, {Amounts, Currency}} = ff_accounting:balance(Account),
AccountBalance = #{
id => ff_account:id(Account),
currency => Currency,

View File

@ -15,7 +15,6 @@
uuid,
damsel,
dmt_client,
shumpune_proto,
party_client,
binbase_proto
]},

View File

@ -90,7 +90,7 @@ create_ok(C) ->
Wallet = ff_wallet_machine:wallet(unwrap(ff_wallet_machine:get(ID))),
Accessibility = unwrap(ff_wallet:is_accessible(Wallet)),
Account = ff_wallet:account(Wallet),
{Amount, <<"RUB">>} = unwrap(ff_transaction:balance(Account, ff_clock:latest_clock())),
{Amount, <<"RUB">>} = unwrap(ff_accounting:balance(Account)),
CurrentAmount = ff_indef:current(Amount),
?assertMatch(ok, CreateResult),
?assertMatch(accessible, Accessibility),

View File

@ -40,7 +40,7 @@
-type params() :: #{
id := id(),
body := ff_transaction:body(),
body := ff_accounting:body(),
wallet_from_id := wallet_id(),
wallet_to_id := wallet_id(),
external_id => external_id(),
@ -160,7 +160,7 @@
-type process_result() :: {action(), [event()]}.
-type wallet_id() :: ff_wallet:id().
-type wallet() :: ff_wallet:wallet_state().
-type body() :: ff_transaction:body().
-type body() :: ff_accounting:body().
-type cash() :: ff_cash:cash().
-type cash_range() :: ff_range:range(cash()).
-type action() :: machinery:action() | undefined.
@ -176,7 +176,6 @@
-type domain_revision() :: ff_domain_config:revision().
-type identity() :: ff_identity:identity_state().
-type terms() :: ff_party:terms().
-type clock() :: ff_transaction:clock().
-type metadata() :: ff_entity_context:md().
-type activity() ::
@ -615,8 +614,7 @@ process_wallet_limit_check(WalletID, W2WTransferState) ->
domain_revision => DomainRevision,
varset => Varset
}),
Clock = ff_postings_transfer:clock(p_transfer(W2WTransferState)),
case validate_wallet_limits(Terms, Wallet, Clock) of
case validate_wallet_limits(Terms, Wallet) of
{ok, valid} ->
ok;
{error, {terms_violation, {wallet_limit, {cash_range, {Cash, Range}}}}} ->
@ -657,11 +655,11 @@ is_limit_check_ok({wallet_sender, {failed, _Details}}) ->
is_limit_check_ok({wallet_receiver, {failed, _Details}}) ->
false.
-spec validate_wallet_limits(terms(), wallet(), clock()) ->
-spec validate_wallet_limits(terms(), wallet()) ->
{ok, valid}
| {error, {terms_violation, {wallet_limit, {cash_range, {cash(), cash_range()}}}}}.
validate_wallet_limits(Terms, Wallet, Clock) ->
case ff_party:validate_wallet_limits(Terms, Wallet, Clock) of
validate_wallet_limits(Terms, Wallet) ->
case ff_party:validate_wallet_limits(Terms, Wallet) of
{ok, valid} = Result ->
Result;
{error, {terms_violation, {cash_range, {Cash, CashRange}}}} ->

View File

@ -1,7 +1,6 @@
-module(w2w_adjustment_SUITE).
-include_lib("stdlib/include/assert.hrl").
-include_lib("shumpune_proto/include/shumpune_shumpune_thrift.hrl").
%% Common test API
@ -439,10 +438,7 @@ get_wallet_balance(ID) ->
get_account_balance(ff_wallet:account(ff_wallet_machine:wallet(Machine))).
get_account_balance(Account) ->
{ok, {Amounts, Currency}} = ff_transaction:balance(
Account,
ff_clock:latest_clock()
),
{ok, {Amounts, Currency}} = ff_accounting:balance(Account),
{ff_indef:current(Amounts), ff_indef:to_range(Amounts), Currency}.
set_wallet_balance({Amount, Currency}, ID) ->
@ -451,30 +447,11 @@ set_wallet_balance({Amount, Currency}, ID) ->
Account = ff_wallet:account(ff_wallet_machine:wallet(Machine)),
AccounterID = ff_account:accounter_account_id(Account),
{CurrentAmount, _, Currency} = get_account_balance(Account),
{ok, AnotherAccounterID} = create_account(Currency),
{ok, AnotherAccounterID} = ct_helper:create_account(Currency),
Postings = [{AnotherAccounterID, AccounterID, {Amount - CurrentAmount, Currency}}],
{ok, _} = ff_transaction:prepare(TransactionID, Postings),
{ok, _} = ff_transaction:commit(TransactionID, Postings),
{ok, _} = ff_accounting:prepare_trx(TransactionID, Postings),
{ok, _} = ff_accounting:commit_trx(TransactionID, Postings),
ok.
generate_id() ->
ff_id:generate_snowflake_id().
create_account(CurrencyCode) ->
Description = <<"ff_test">>,
case call_accounter('CreateAccount', {construct_account_prototype(CurrencyCode, Description)}) of
{ok, Result} ->
{ok, Result};
{exception, Exception} ->
{error, {exception, Exception}}
end.
construct_account_prototype(CurrencyCode, Description) ->
#shumpune_AccountPrototype{
currency_sym_code = CurrencyCode,
description = Description
}.
call_accounter(Function, Args) ->
Service = {shumpune_shumpune_thrift, 'Accounter'},
ff_woody_client:call(accounter, {Service, Function, Args}, woody_context:new()).

View File

@ -2,7 +2,6 @@
-include_lib("stdlib/include/assert.hrl").
-include_lib("damsel/include/dmsl_payment_processing_thrift.hrl").
-include_lib("shumpune_proto/include/shumpune_shumpune_thrift.hrl").
%% Common test API
@ -338,17 +337,8 @@ get_wallet_balance(ID) ->
{ok, Machine} = ff_wallet_machine:get(ID),
get_account_balance(ff_wallet:account(ff_wallet_machine:wallet(Machine))).
%% NOTE: This function can flap tests after switch to shumpune
%% because of potentially wrong Clock. In common case it should be passed
%% from caller after applying changes to account balance.
%% This will work fine with shumway because it return LatestClock on any
%% balance changes, therefore it will broke tests with shumpune
%% because of proper clocks.
get_account_balance(Account) ->
{ok, {Amounts, Currency}} = ff_transaction:balance(
Account,
ff_clock:latest_clock()
),
{ok, {Amounts, Currency}} = ff_accounting:balance(Account),
{ff_indef:current(Amounts), ff_indef:to_range(Amounts), Currency}.
set_wallet_balance({Amount, Currency}, ID) ->
@ -357,30 +347,11 @@ set_wallet_balance({Amount, Currency}, ID) ->
Account = ff_wallet:account(ff_wallet_machine:wallet(Machine)),
AccounterID = ff_account:accounter_account_id(Account),
{CurrentAmount, _, Currency} = get_account_balance(Account),
{ok, AnotherAccounterID} = create_account(Currency),
{ok, AnotherAccounterID} = ct_helper:create_account(Currency),
Postings = [{AnotherAccounterID, AccounterID, {Amount - CurrentAmount, Currency}}],
{ok, _} = ff_transaction:prepare(TransactionID, Postings),
{ok, _} = ff_transaction:commit(TransactionID, Postings),
{ok, _} = ff_accounting:prepare_trx(TransactionID, Postings),
{ok, _} = ff_accounting:commit_trx(TransactionID, Postings),
ok.
generate_id() ->
ff_id:generate_snowflake_id().
create_account(CurrencyCode) ->
Description = <<"ff_test">>,
case call_accounter('CreateAccount', {construct_account_prototype(CurrencyCode, Description)}) of
{ok, Result} ->
{ok, Result};
{exception, Exception} ->
{error, {exception, Exception}}
end.
construct_account_prototype(CurrencyCode, Description) ->
#shumpune_AccountPrototype{
currency_sym_code = CurrencyCode,
description = Description
}.
call_accounter(Function, Args) ->
Service = {shumpune_shumpune_thrift, 'Accounter'},
ff_woody_client:call(accounter, {Service, Function, Args}, woody_context:new()).

View File

@ -78,7 +78,7 @@
{services, #{
'eventsink' => "http://machinegun:8022/v1/event_sink",
'automaton' => "http://machinegun:8022/v1/automaton",
'accounter' => "http://shumway:8022/shumpune"
'accounter' => "http://shumway:8022/accounter"
}}
]},

View File

@ -40,8 +40,7 @@
{dmt_client, {git, "https://github.com/valitydev/dmt_client.git", {branch, master}}},
{fistful_proto, {git, "https://github.com/valitydev/fistful-proto.git", {branch, "master"}}},
{binbase_proto, {git, "https://github.com/valitydev/binbase-proto.git", {branch, "master"}}},
{party_client, {git, "https://github.com/valitydev/party_client_erlang.git", {branch, "master"}}},
{shumpune_proto, {git, "https://github.com/valitydev/shumaich-proto.git", {ref, "4c87f03"}}}
{party_client, {git, "https://github.com/valitydev/party-client-erlang.git", {branch, "master"}}}
]}.
{xref_checks, [

View File

@ -52,7 +52,7 @@
{<<"mimerl">>,{pkg,<<"mimerl">>,<<"1.2.0">>},2},
{<<"parse_trans">>,{pkg,<<"parse_trans">>,<<"3.3.1">>},2},
{<<"party_client">>,
{git,"https://github.com/valitydev/party_client_erlang.git",
{git,"https://github.com/valitydev/party-client-erlang.git",
{ref,"8fc5595c4c61c0fe3d2dc29a61f48ba94e9bdef7"}},
0},
{<<"prometheus">>,{pkg,<<"prometheus">>,<<"4.8.1">>},0},
@ -68,10 +68,6 @@
{git,"https://github.com/valitydev/scoper.git",
{ref,"7f3183df279bc8181efe58dafd9cae164f495e6f"}},
0},
{<<"shumpune_proto">>,
{git,"https://github.com/valitydev/shumaich-proto.git",
{ref,"4c87f03591cae3dad41504eb463d962af536b1ab"}},
0},
{<<"snowflake">>,
{git,"https://github.com/valitydev/snowflake.git",
{ref,"de159486ef40cec67074afe71882bdc7f7deab72"}},