mirror of
https://github.com/valitydev/fistful-server.git
synced 2024-11-06 02:35:18 +00:00
TD-330: Limiter (#35)
* bumped deps * added rebar plugin * added limiter support * bumped to valitydev/binbase-proto@6841072 valitydev/fistful-proto@a3e89bc valitydev/machinegun-proto@a411c7d * refactored withdrawal routing, fixed dialyzer, fixed fmt and lint * added limiter to compose, added limiter suite wip * finished tests * fixed dialyzer * fixed eunit * fixed tests * fixed services * added part of fixes * added new test case and some refactor * closed to finish * added rejected logging * added requested changes * fixed
This commit is contained in:
parent
e9e05cee92
commit
6ba2c49bbd
2
.env
2
.env
@ -4,4 +4,4 @@
|
||||
SERVICE_NAME=fistful-server
|
||||
OTP_VERSION=24.2.0
|
||||
REBAR_VERSION=3.18
|
||||
THRIFT_VERSION=0.14.2.2
|
||||
THRIFT_VERSION=0.14.2.3
|
||||
|
3
.github/workflows/erlang-checks.yml
vendored
3
.github/workflows/erlang-checks.yml
vendored
@ -29,10 +29,11 @@ jobs:
|
||||
run:
|
||||
name: Run checks
|
||||
needs: setup
|
||||
uses: valitydev/erlang-workflows/.github/workflows/erlang-parallel-build.yml@v1.0.2
|
||||
uses: valitydev/erlang-workflows/.github/workflows/erlang-parallel-build.yml@v1.0.3
|
||||
with:
|
||||
otp-version: ${{ needs.setup.outputs.otp-version }}
|
||||
rebar-version: ${{ needs.setup.outputs.rebar-version }}
|
||||
use-thrift: true
|
||||
thrift-version: ${{ needs.setup.outputs.thrift-version }}
|
||||
run-ct-with-compose: true
|
||||
cache-version: v2
|
||||
|
@ -1,10 +1,17 @@
|
||||
-ifndef(__ct_domain_hrl__).
|
||||
-define(__ct_domain_hrl__, 42).
|
||||
|
||||
-include_lib("damsel/include/dmsl_domain_config_thrift.hrl").
|
||||
-include_lib("damsel/include/dmsl_domain_conf_thrift.hrl").
|
||||
-include_lib("damsel/include/dmsl_domain_thrift.hrl").
|
||||
-include_lib("damsel/include/dmsl_base_thrift.hrl").
|
||||
|
||||
-define(ordset(Es), ordsets:from_list(Es)).
|
||||
|
||||
-define(LIMIT_TURNOVER_NUM_PAYTOOL_ID1, <<"ID1">>).
|
||||
-define(LIMIT_TURNOVER_NUM_PAYTOOL_ID2, <<"ID2">>).
|
||||
-define(LIMIT_TURNOVER_AMOUNT_PAYTOOL_ID1, <<"ID3">>).
|
||||
-define(LIMIT_TURNOVER_AMOUNT_PAYTOOL_ID2, <<"ID4">>).
|
||||
|
||||
-define(glob(), #domain_GlobalsRef{}).
|
||||
-define(cur(ID), #domain_CurrencyRef{symbolic_code = ID}).
|
||||
-define(pmt(C, T), #domain_PaymentMethodRef{id = {C, T}}).
|
||||
@ -23,6 +30,7 @@
|
||||
-define(insp(ID), #domain_InspectorRef{id = ID}).
|
||||
-define(payinst(ID), #domain_PaymentInstitutionRef{id = ID}).
|
||||
-define(ruleset(ID), #domain_RoutingRulesetRef{id = ID}).
|
||||
-define(trnvrlimit(ID, UpperBoundary), #domain_TurnoverLimit{id = ID, upper_boundary = UpperBoundary}).
|
||||
|
||||
-define(cash(Amount, SymCode), #domain_Cash{amount = Amount, currency = ?cur(SymCode)}).
|
||||
|
||||
@ -39,14 +47,14 @@
|
||||
|
||||
-define(share(P, Q, C),
|
||||
{share, #domain_CashVolumeShare{
|
||||
parts = #'Rational'{p = P, q = Q},
|
||||
parts = #'base_Rational'{p = P, q = Q},
|
||||
'of' = C
|
||||
}}
|
||||
).
|
||||
|
||||
-define(share(P, Q, C, RM),
|
||||
{share, #domain_CashVolumeShare{
|
||||
parts = #'Rational'{p = P, q = Q},
|
||||
parts = #'base_Rational'{p = P, q = Q},
|
||||
'of' = C,
|
||||
'rounding_method' = RM
|
||||
}}
|
||||
|
@ -30,6 +30,7 @@
|
||||
%%
|
||||
|
||||
-include_lib("ff_cth/include/ct_domain.hrl").
|
||||
-include_lib("damsel/include/dmsl_base_thrift.hrl").
|
||||
-include_lib("damsel/include/dmsl_accounter_thrift.hrl").
|
||||
|
||||
-define(DTP(Type), dmsl_domain_thrift:Type()).
|
||||
@ -133,8 +134,7 @@ category(Ref, Name, Type) ->
|
||||
}}.
|
||||
|
||||
-spec payment_method(?DTP('PaymentMethodRef')) -> object().
|
||||
payment_method(?pmt(_Type, Name) = Ref) when is_atom(Name) ->
|
||||
payment_method(erlang:atom_to_binary(Name, unicode), Ref);
|
||||
|
||||
payment_method(?pmt(?PAYMENT_METHOD_BANK_CARD(ID)) = Ref) when is_binary(ID) ->
|
||||
payment_method(ID, Ref);
|
||||
payment_method(?pmt(?PAYMENT_METHOD_DIGITAL_WALLET(ID)) = Ref) when is_binary(ID) ->
|
||||
@ -291,7 +291,7 @@ term_set_hierarchy(Ref, ParentRef, TermSets) ->
|
||||
-spec timed_term_set(?DTP('TermSet')) -> ?DTP('TimedTermSet').
|
||||
timed_term_set(TermSet) ->
|
||||
#domain_TimedTermSet{
|
||||
action_time = #'TimestampInterval'{},
|
||||
action_time = #'base_TimestampInterval'{},
|
||||
terms = TermSet
|
||||
}.
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
%%
|
||||
|
||||
-include_lib("damsel/include/dmsl_domain_config_thrift.hrl").
|
||||
-include_lib("damsel/include/dmsl_domain_conf_thrift.hrl").
|
||||
|
||||
-type revision() :: dmt_client:version().
|
||||
-type object() :: dmsl_domain_thrift:'DomainObject'().
|
||||
@ -28,7 +28,7 @@ head() ->
|
||||
|
||||
-spec all(revision()) -> dmsl_domain_thrift:'Domain'().
|
||||
all(Revision) ->
|
||||
#'Snapshot'{domain = Domain} = dmt_client:checkout(Revision),
|
||||
#'domain_conf_Snapshot'{domain = Domain} = dmt_client:checkout(Revision),
|
||||
Domain.
|
||||
|
||||
-spec commit(revision(), dmt_client:commit()) -> revision() | no_return().
|
||||
@ -61,9 +61,9 @@ reset(Revision) ->
|
||||
|
||||
-spec cleanup() -> revision() | no_return().
|
||||
cleanup() ->
|
||||
#'Snapshot'{domain = Domain} = dmt_client:checkout(latest),
|
||||
#'domain_conf_Snapshot'{domain = Domain} = dmt_client:checkout(latest),
|
||||
remove(maps:values(Domain)).
|
||||
|
||||
-spec bump_revision() -> revision() | no_return().
|
||||
bump_revision() ->
|
||||
dmt_client:commit(#'Commit'{ops = []}).
|
||||
dmt_client:commit(#'domain_conf_Commit'{ops = []}).
|
||||
|
@ -1,28 +1,29 @@
|
||||
-module(ct_eventsink).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_identity_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/ff_proto_wallet_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/ff_proto_withdrawal_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/ff_proto_withdrawal_session_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/ff_proto_destination_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/ff_proto_source_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/ff_proto_deposit_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/ff_proto_w2w_transfer_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_identity_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_wallet_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_wthd_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_wthd_session_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_destination_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_source_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_deposit_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_w2w_transfer_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_evsink_thrift.hrl").
|
||||
|
||||
-type sink() ::
|
||||
ff_services:service_name().
|
||||
|
||||
-type event() ::
|
||||
ff_proto_wallet_thrift:'SinkEvent'()
|
||||
| ff_proto_withdrawal_thrift:'SinkEvent'()
|
||||
| ff_proto_identity_thrift:'SinkEvent'()
|
||||
| ff_proto_destination_thrift:'SinkEvent'()
|
||||
| ff_proto_source_thrift:'SinkEvent'()
|
||||
| ff_proto_deposit_thrift:'SinkEvent'()
|
||||
| ff_proto_withdrawal_thrift:'SinkEvent'()
|
||||
| ff_proto_w2w_transfer_thrift:'SinkEvent'().
|
||||
fistful_wallet_thrift:'SinkEvent'()
|
||||
| fistful_wthd_thrift:'SinkEvent'()
|
||||
| fistful_identity_thrift:'SinkEvent'()
|
||||
| fistful_destination_thrift:'SinkEvent'()
|
||||
| fistful_source_thrift:'SinkEvent'()
|
||||
| fistful_deposit_thrift:'SinkEvent'()
|
||||
| fistful_wthd_thrift:'SinkEvent'()
|
||||
| fistful_w2w_transfer_thrift:'SinkEvent'().
|
||||
|
||||
-type event_id() :: ff_proto_eventsink_thrift:'EventID'().
|
||||
-type event_id() :: fistful_evsink_thrift:'EventID'().
|
||||
-type limit() :: non_neg_integer().
|
||||
|
||||
-export([last_id/1]).
|
||||
@ -73,11 +74,11 @@ get_max_event_id(Events) when is_list(Events) ->
|
||||
lists:foldl(fun(Ev, Max) -> erlang:max(get_event_id(Ev), Max) end, 0, Events).
|
||||
|
||||
-spec get_event_id(event()) -> event_id().
|
||||
get_event_id(#'wlt_SinkEvent'{id = ID}) -> ID;
|
||||
get_event_id(#'wallet_SinkEvent'{id = ID}) -> ID;
|
||||
get_event_id(#'wthd_SinkEvent'{id = ID}) -> ID;
|
||||
get_event_id(#'idnt_SinkEvent'{id = ID}) -> ID;
|
||||
get_event_id(#'dst_SinkEvent'{id = ID}) -> ID;
|
||||
get_event_id(#'src_SinkEvent'{id = ID}) -> ID;
|
||||
get_event_id(#'identity_SinkEvent'{id = ID}) -> ID;
|
||||
get_event_id(#'destination_SinkEvent'{id = ID}) -> ID;
|
||||
get_event_id(#'source_SinkEvent'{id = ID}) -> ID;
|
||||
get_event_id(#'deposit_SinkEvent'{id = ID}) -> ID;
|
||||
get_event_id(#'wthd_session_SinkEvent'{id = ID}) -> ID;
|
||||
get_event_id(#'w2w_transfer_SinkEvent'{id = ID}) -> ID.
|
||||
|
@ -89,30 +89,30 @@ start_processing_apps(Options) ->
|
||||
handlers => [
|
||||
{
|
||||
<<"/bank">>,
|
||||
{{dmsl_withdrawals_provider_adapter_thrift, 'Adapter'}, {ff_ct_provider_handler, []}}
|
||||
{{dmsl_wthd_provider_thrift, 'Adapter'}, {ff_ct_provider_handler, []}}
|
||||
},
|
||||
{
|
||||
<<"/quotebank">>,
|
||||
{{dmsl_withdrawals_provider_adapter_thrift, 'Adapter'}, {ff_ct_provider_handler, []}}
|
||||
{{dmsl_wthd_provider_thrift, 'Adapter'}, {ff_ct_provider_handler, []}}
|
||||
},
|
||||
{
|
||||
<<"/downbank">>,
|
||||
{
|
||||
{dmsl_withdrawals_provider_adapter_thrift, 'Adapter'},
|
||||
{dmsl_wthd_provider_thrift, 'Adapter'},
|
||||
{ff_ct_provider_handler, [{handler, ff_ct_fail_provider}]}
|
||||
}
|
||||
},
|
||||
{
|
||||
<<"/downbank2">>,
|
||||
{
|
||||
{dmsl_withdrawals_provider_adapter_thrift, 'Adapter'},
|
||||
{dmsl_wthd_provider_thrift, 'Adapter'},
|
||||
{ff_ct_provider_handler, [{handler, ff_ct_unknown_failure_provider}]}
|
||||
}
|
||||
},
|
||||
{
|
||||
<<"/sleepybank">>,
|
||||
{
|
||||
{dmsl_withdrawals_provider_adapter_thrift, 'Adapter'},
|
||||
{dmsl_wthd_provider_thrift, 'Adapter'},
|
||||
{ff_ct_provider_handler, [{handler, ff_ct_sleepy_provider}]}
|
||||
}
|
||||
},
|
||||
@ -232,7 +232,8 @@ services(Options) ->
|
||||
automaton => "http://machinegun:8022/v1/automaton",
|
||||
accounter => "http://shumway:8022/accounter",
|
||||
partymgmt => "http://party-management:8022/v1/processing/partymgmt",
|
||||
binbase => "http://localhost:8222/binbase"
|
||||
binbase => "http://localhost:8222/binbase",
|
||||
limiter => "http://limiter:8022/v1/limiter"
|
||||
},
|
||||
maps:get(services, Options, Default).
|
||||
|
||||
@ -365,6 +366,26 @@ domain_config(Options) ->
|
||||
condition(cost_in, {700700, <<"RUB">>}),
|
||||
?ruleset(?PAYINST1_ROUTING_POLICIES + 13)
|
||||
),
|
||||
delegate(
|
||||
condition(cost_in, {800800, <<"RUB">>}),
|
||||
?ruleset(?PAYINST1_ROUTING_POLICIES + 16)
|
||||
),
|
||||
delegate(
|
||||
condition(cost_in, {900900, <<"RUB">>}),
|
||||
?ruleset(?PAYINST1_ROUTING_POLICIES + 17)
|
||||
),
|
||||
delegate(
|
||||
condition(cost_in, {901000, <<"RUB">>}),
|
||||
?ruleset(?PAYINST1_ROUTING_POLICIES + 18)
|
||||
),
|
||||
delegate(
|
||||
condition(cost_in, {902000, <<"RUB">>}),
|
||||
?ruleset(?PAYINST1_ROUTING_POLICIES + 19)
|
||||
),
|
||||
delegate(
|
||||
condition(cost_in, {903000, <<"RUB">>}),
|
||||
?ruleset(?PAYINST1_ROUTING_POLICIES + 19)
|
||||
),
|
||||
delegate(
|
||||
{condition,
|
||||
{payment_tool,
|
||||
@ -466,6 +487,36 @@ domain_config(Options) ->
|
||||
]}
|
||||
),
|
||||
|
||||
routing_ruleset(
|
||||
?ruleset(?PAYINST1_ROUTING_POLICIES + 16),
|
||||
{candidates, [
|
||||
candidate({constant, true}, ?trm(1800))
|
||||
]}
|
||||
),
|
||||
|
||||
routing_ruleset(
|
||||
?ruleset(?PAYINST1_ROUTING_POLICIES + 17),
|
||||
{candidates, [
|
||||
candidate({constant, true}, ?trm(1900))
|
||||
]}
|
||||
),
|
||||
|
||||
routing_ruleset(
|
||||
?ruleset(?PAYINST1_ROUTING_POLICIES + 18),
|
||||
{candidates, [
|
||||
candidate({constant, true}, ?trm(2000), 1000),
|
||||
candidate({constant, true}, ?trm(1900), 4000)
|
||||
]}
|
||||
),
|
||||
|
||||
routing_ruleset(
|
||||
?ruleset(?PAYINST1_ROUTING_POLICIES + 19),
|
||||
{candidates, [
|
||||
candidate({constant, true}, ?trm(2200), 1000),
|
||||
candidate({constant, true}, ?trm(2100), 4000)
|
||||
]}
|
||||
),
|
||||
|
||||
routing_ruleset(
|
||||
?ruleset(?PAYINST1_ROUTING_PROHIBITIONS),
|
||||
<<"PayInst1 Withdrawal Prohibitions">>,
|
||||
@ -721,6 +772,82 @@ domain_config(Options) ->
|
||||
}
|
||||
),
|
||||
|
||||
ct_domain:withdrawal_terminal(
|
||||
?trm(1800),
|
||||
?prv(1),
|
||||
#domain_ProvisionTermSet{
|
||||
wallet = #domain_WalletProvisionTerms{
|
||||
withdrawals = #domain_WithdrawalProvisionTerms{
|
||||
currencies = {value, ?ordset([?cur(<<"RUB">>), ?cur(<<"BTC">>)])},
|
||||
turnover_limit =
|
||||
{value, [
|
||||
?trnvrlimit(?LIMIT_TURNOVER_NUM_PAYTOOL_ID1, 1000)
|
||||
]}
|
||||
}
|
||||
}
|
||||
}
|
||||
),
|
||||
|
||||
ct_domain:withdrawal_terminal(
|
||||
?trm(1900),
|
||||
?prv(1),
|
||||
#domain_ProvisionTermSet{
|
||||
wallet = #domain_WalletProvisionTerms{
|
||||
withdrawals = #domain_WithdrawalProvisionTerms{
|
||||
turnover_limit =
|
||||
{value, [
|
||||
?trnvrlimit(?LIMIT_TURNOVER_NUM_PAYTOOL_ID2, 0)
|
||||
]}
|
||||
}
|
||||
}
|
||||
}
|
||||
),
|
||||
|
||||
ct_domain:withdrawal_terminal(
|
||||
?trm(2000),
|
||||
?prv(1),
|
||||
#domain_ProvisionTermSet{
|
||||
wallet = #domain_WalletProvisionTerms{
|
||||
withdrawals = #domain_WithdrawalProvisionTerms{
|
||||
turnover_limit =
|
||||
{value, [
|
||||
?trnvrlimit(?LIMIT_TURNOVER_NUM_PAYTOOL_ID2, 1000)
|
||||
]}
|
||||
}
|
||||
}
|
||||
}
|
||||
),
|
||||
|
||||
ct_domain:withdrawal_terminal(
|
||||
?trm(2100),
|
||||
?prv(1),
|
||||
#domain_ProvisionTermSet{
|
||||
wallet = #domain_WalletProvisionTerms{
|
||||
withdrawals = #domain_WithdrawalProvisionTerms{
|
||||
turnover_limit =
|
||||
{value, [
|
||||
?trnvrlimit(?LIMIT_TURNOVER_AMOUNT_PAYTOOL_ID1, 1804000)
|
||||
]}
|
||||
}
|
||||
}
|
||||
}
|
||||
),
|
||||
|
||||
ct_domain:withdrawal_terminal(
|
||||
?trm(2200),
|
||||
?prv(1),
|
||||
#domain_ProvisionTermSet{
|
||||
wallet = #domain_WalletProvisionTerms{
|
||||
withdrawals = #domain_WithdrawalProvisionTerms{
|
||||
turnover_limit =
|
||||
{value, [
|
||||
?trnvrlimit(?LIMIT_TURNOVER_AMOUNT_PAYTOOL_ID2, 903000)
|
||||
]}
|
||||
}
|
||||
}
|
||||
}
|
||||
),
|
||||
|
||||
ct_domain:currency(?cur(<<"RUB">>)),
|
||||
ct_domain:currency(?cur(<<"USD">>)),
|
||||
ct_domain:currency(?cur(<<"EUR">>)),
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
-behaviour(ff_codec).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_cashflow_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_cashflow_thrift.hrl").
|
||||
|
||||
-export([marshal/2]).
|
||||
-export([unmarshal/2]).
|
||||
|
@ -1,9 +1,11 @@
|
||||
-module(ff_codec).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_base_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/ff_proto_repairer_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/ff_proto_account_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/ff_proto_msgpack_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_base_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_repairer_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_account_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_msgp_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_evsink_thrift.hrl").
|
||||
|
||||
-export([unmarshal/2]).
|
||||
-export([unmarshal/3]).
|
||||
@ -354,7 +356,7 @@ unmarshal(three_ds_verification, Value) when
|
||||
Value =:= authentication_could_not_be_performed
|
||||
->
|
||||
Value;
|
||||
unmarshal(complex_action, #ff_repairer_ComplexAction{
|
||||
unmarshal(complex_action, #repairer_ComplexAction{
|
||||
timer = TimerAction,
|
||||
remove = RemoveAction
|
||||
}) ->
|
||||
@ -363,13 +365,13 @@ unmarshal(timer_action, undefined) ->
|
||||
[];
|
||||
unmarshal(timer_action, {set_timer, SetTimerAction}) ->
|
||||
[{set_timer, unmarshal(set_timer_action, SetTimerAction)}];
|
||||
unmarshal(timer_action, {unset_timer, #ff_repairer_UnsetTimerAction{}}) ->
|
||||
unmarshal(timer_action, {unset_timer, #repairer_UnsetTimerAction{}}) ->
|
||||
[unset_timer];
|
||||
unmarshal(remove_action, undefined) ->
|
||||
[];
|
||||
unmarshal(remove_action, #ff_repairer_RemoveAction{}) ->
|
||||
unmarshal(remove_action, #repairer_RemoveAction{}) ->
|
||||
[remove];
|
||||
unmarshal(set_timer_action, #ff_repairer_SetTimerAction{
|
||||
unmarshal(set_timer_action, #repairer_SetTimerAction{
|
||||
timer = Timer
|
||||
}) ->
|
||||
unmarshal(timer, Timer);
|
||||
@ -614,7 +616,7 @@ bank_card_codec_test() ->
|
||||
auth_data => {session, #{session_id => <<"session_id">>}}
|
||||
}},
|
||||
{bank_card, MarshalledResourceBankCard} = marshal(resource, ResourceBankCard),
|
||||
Type = {struct, struct, {ff_proto_base_thrift, 'ResourceBankCard'}},
|
||||
Type = {struct, struct, {fistful_fistful_base_thrift, 'ResourceBankCard'}},
|
||||
Binary = ff_proto_utils:serialize(Type, MarshalledResourceBankCard),
|
||||
Decoded = ff_proto_utils:deserialize(Type, Binary),
|
||||
?assertEqual(
|
||||
@ -646,7 +648,7 @@ generic_resource_codec_test() ->
|
||||
provider => #{id => <<"foo">>},
|
||||
data => #{type => <<"type">>, data => <<"data">>}
|
||||
},
|
||||
Type = {struct, struct, {ff_proto_base_thrift, 'ResourceGenericData'}},
|
||||
Type = {struct, struct, {fistful_fistful_base_thrift, 'ResourceGenericData'}},
|
||||
Binary = ff_proto_utils:serialize(Type, marshal(generic_resource, GenericResource)),
|
||||
Decoded = ff_proto_utils:deserialize(Type, Binary),
|
||||
?assertEqual(
|
||||
@ -666,7 +668,7 @@ fees_codec_test() ->
|
||||
surplus => {200, <<"RUB">>}
|
||||
}
|
||||
},
|
||||
Type = {struct, struct, {ff_proto_base_thrift, 'Fees'}},
|
||||
Type = {struct, struct, {fistful_fistful_base_thrift, 'Fees'}},
|
||||
Binary = ff_proto_utils:serialize(Type, marshal(fees, Expected)),
|
||||
Decoded = ff_proto_utils:deserialize(Type, Binary),
|
||||
?assertEqual(Expected, unmarshal(fees, Decoded)).
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
-behaviour(ff_codec).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_deposit_adjustment_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_deposit_adj_thrift.hrl").
|
||||
|
||||
-export([marshal/2]).
|
||||
-export([unmarshal/2]).
|
||||
@ -11,13 +11,13 @@
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) -> ff_codec:encoded_value().
|
||||
marshal(change, {created, Adjustment}) ->
|
||||
{created, #dep_adj_CreatedChange{adjustment = marshal(adjustment, Adjustment)}};
|
||||
{created, #deposit_adj_CreatedChange{adjustment = marshal(adjustment, Adjustment)}};
|
||||
marshal(change, {status_changed, Status}) ->
|
||||
{status_changed, #dep_adj_StatusChange{status = marshal(status, Status)}};
|
||||
{status_changed, #deposit_adj_StatusChange{status = marshal(status, Status)}};
|
||||
marshal(change, {p_transfer, TransferChange}) ->
|
||||
{transfer, #dep_adj_TransferChange{payload = ff_p_transfer_codec:marshal(change, TransferChange)}};
|
||||
{transfer, #deposit_adj_TransferChange{payload = ff_p_transfer_codec:marshal(change, TransferChange)}};
|
||||
marshal(adjustment, Adjustment) ->
|
||||
#dep_adj_Adjustment{
|
||||
#deposit_adj_Adjustment{
|
||||
id = marshal(id, ff_adjustment:id(Adjustment)),
|
||||
status = maybe_marshal(status, ff_adjustment:status(Adjustment)),
|
||||
changes_plan = marshal(changes_plan, ff_adjustment:changes_plan(Adjustment)),
|
||||
@ -28,13 +28,13 @@ marshal(adjustment, Adjustment) ->
|
||||
external_id = maybe_marshal(id, ff_adjustment:external_id(Adjustment))
|
||||
};
|
||||
marshal(adjustment_params, Params) ->
|
||||
#dep_adj_AdjustmentParams{
|
||||
#deposit_adj_AdjustmentParams{
|
||||
id = marshal(id, maps:get(id, Params)),
|
||||
change = marshal(change_request, maps:get(change, Params)),
|
||||
external_id = maybe_marshal(id, maps:get(external_id, Params, undefined))
|
||||
};
|
||||
marshal(adjustment_state, Adjustment) ->
|
||||
#dep_adj_AdjustmentState{
|
||||
#deposit_adj_AdjustmentState{
|
||||
id = marshal(id, ff_adjustment:id(Adjustment)),
|
||||
status = maybe_marshal(status, ff_adjustment:status(Adjustment)),
|
||||
changes_plan = marshal(changes_plan, ff_adjustment:changes_plan(Adjustment)),
|
||||
@ -45,79 +45,79 @@ marshal(adjustment_state, Adjustment) ->
|
||||
external_id = maybe_marshal(id, ff_adjustment:external_id(Adjustment))
|
||||
};
|
||||
marshal(status, pending) ->
|
||||
{pending, #dep_adj_Pending{}};
|
||||
{pending, #deposit_adj_Pending{}};
|
||||
marshal(status, succeeded) ->
|
||||
{succeeded, #dep_adj_Succeeded{}};
|
||||
{succeeded, #deposit_adj_Succeeded{}};
|
||||
marshal(changes_plan, Plan) ->
|
||||
#dep_adj_ChangesPlan{
|
||||
#deposit_adj_ChangesPlan{
|
||||
new_cash_flow = maybe_marshal(cash_flow_change_plan, maps:get(new_cash_flow, Plan, undefined)),
|
||||
new_status = maybe_marshal(status_change_plan, maps:get(new_status, Plan, undefined))
|
||||
};
|
||||
marshal(cash_flow_change_plan, Plan) ->
|
||||
OldCashFLow = ff_cash_flow_codec:marshal(final_cash_flow, maps:get(old_cash_flow_inverted, Plan)),
|
||||
NewCashFlow = ff_cash_flow_codec:marshal(final_cash_flow, maps:get(new_cash_flow, Plan)),
|
||||
#dep_adj_CashFlowChangePlan{
|
||||
#deposit_adj_CashFlowChangePlan{
|
||||
old_cash_flow_inverted = OldCashFLow,
|
||||
new_cash_flow = NewCashFlow
|
||||
};
|
||||
marshal(status_change_plan, Plan) ->
|
||||
#dep_adj_StatusChangePlan{
|
||||
#deposit_adj_StatusChangePlan{
|
||||
new_status = ff_deposit_status_codec:marshal(status, maps:get(new_status, Plan))
|
||||
};
|
||||
marshal(change_request, {change_status, Status}) ->
|
||||
{change_status, #dep_adj_ChangeStatusRequest{
|
||||
{change_status, #deposit_adj_ChangeStatusRequest{
|
||||
new_status = ff_deposit_status_codec:marshal(status, Status)
|
||||
}};
|
||||
marshal(T, V) ->
|
||||
ff_codec:marshal(T, V).
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) -> ff_codec:decoded_value().
|
||||
unmarshal(change, {created, #dep_adj_CreatedChange{adjustment = Adjustment}}) ->
|
||||
unmarshal(change, {created, #deposit_adj_CreatedChange{adjustment = Adjustment}}) ->
|
||||
{created, unmarshal(adjustment, Adjustment)};
|
||||
unmarshal(change, {status_changed, #dep_adj_StatusChange{status = Status}}) ->
|
||||
unmarshal(change, {status_changed, #deposit_adj_StatusChange{status = Status}}) ->
|
||||
{status_changed, unmarshal(status, Status)};
|
||||
unmarshal(change, {transfer, #dep_adj_TransferChange{payload = TransferChange}}) ->
|
||||
unmarshal(change, {transfer, #deposit_adj_TransferChange{payload = TransferChange}}) ->
|
||||
{p_transfer, ff_p_transfer_codec:unmarshal(change, TransferChange)};
|
||||
unmarshal(adjustment, Adjustment) ->
|
||||
#{
|
||||
id => unmarshal(id, Adjustment#dep_adj_Adjustment.id),
|
||||
status => unmarshal(status, Adjustment#dep_adj_Adjustment.status),
|
||||
changes_plan => unmarshal(changes_plan, Adjustment#dep_adj_Adjustment.changes_plan),
|
||||
created_at => unmarshal(timestamp_ms, Adjustment#dep_adj_Adjustment.created_at),
|
||||
domain_revision => unmarshal(domain_revision, Adjustment#dep_adj_Adjustment.domain_revision),
|
||||
party_revision => unmarshal(party_revision, Adjustment#dep_adj_Adjustment.party_revision),
|
||||
operation_timestamp => unmarshal(timestamp_ms, Adjustment#dep_adj_Adjustment.operation_timestamp),
|
||||
external_id => maybe_unmarshal(id, Adjustment#dep_adj_Adjustment.external_id)
|
||||
id => unmarshal(id, Adjustment#deposit_adj_Adjustment.id),
|
||||
status => unmarshal(status, Adjustment#deposit_adj_Adjustment.status),
|
||||
changes_plan => unmarshal(changes_plan, Adjustment#deposit_adj_Adjustment.changes_plan),
|
||||
created_at => unmarshal(timestamp_ms, Adjustment#deposit_adj_Adjustment.created_at),
|
||||
domain_revision => unmarshal(domain_revision, Adjustment#deposit_adj_Adjustment.domain_revision),
|
||||
party_revision => unmarshal(party_revision, Adjustment#deposit_adj_Adjustment.party_revision),
|
||||
operation_timestamp => unmarshal(timestamp_ms, Adjustment#deposit_adj_Adjustment.operation_timestamp),
|
||||
external_id => maybe_unmarshal(id, Adjustment#deposit_adj_Adjustment.external_id)
|
||||
};
|
||||
unmarshal(adjustment_params, Params) ->
|
||||
genlib_map:compact(#{
|
||||
id => unmarshal(id, Params#dep_adj_AdjustmentParams.id),
|
||||
change => unmarshal(change_request, Params#dep_adj_AdjustmentParams.change),
|
||||
external_id => maybe_unmarshal(id, Params#dep_adj_AdjustmentParams.external_id)
|
||||
id => unmarshal(id, Params#deposit_adj_AdjustmentParams.id),
|
||||
change => unmarshal(change_request, Params#deposit_adj_AdjustmentParams.change),
|
||||
external_id => maybe_unmarshal(id, Params#deposit_adj_AdjustmentParams.external_id)
|
||||
});
|
||||
unmarshal(status, {pending, #dep_adj_Pending{}}) ->
|
||||
unmarshal(status, {pending, #deposit_adj_Pending{}}) ->
|
||||
pending;
|
||||
unmarshal(status, {succeeded, #dep_adj_Succeeded{}}) ->
|
||||
unmarshal(status, {succeeded, #deposit_adj_Succeeded{}}) ->
|
||||
succeeded;
|
||||
unmarshal(changes_plan, Plan) ->
|
||||
genlib_map:compact(#{
|
||||
new_cash_flow => maybe_unmarshal(cash_flow_change_plan, Plan#dep_adj_ChangesPlan.new_cash_flow),
|
||||
new_status => maybe_unmarshal(status_change_plan, Plan#dep_adj_ChangesPlan.new_status)
|
||||
new_cash_flow => maybe_unmarshal(cash_flow_change_plan, Plan#deposit_adj_ChangesPlan.new_cash_flow),
|
||||
new_status => maybe_unmarshal(status_change_plan, Plan#deposit_adj_ChangesPlan.new_status)
|
||||
});
|
||||
unmarshal(cash_flow_change_plan, Plan) ->
|
||||
OldCashFlow = Plan#dep_adj_CashFlowChangePlan.old_cash_flow_inverted,
|
||||
NewCashFlow = Plan#dep_adj_CashFlowChangePlan.new_cash_flow,
|
||||
OldCashFlow = Plan#deposit_adj_CashFlowChangePlan.old_cash_flow_inverted,
|
||||
NewCashFlow = Plan#deposit_adj_CashFlowChangePlan.new_cash_flow,
|
||||
#{
|
||||
old_cash_flow_inverted => ff_cash_flow_codec:unmarshal(final_cash_flow, OldCashFlow),
|
||||
new_cash_flow => ff_cash_flow_codec:unmarshal(final_cash_flow, NewCashFlow)
|
||||
};
|
||||
unmarshal(status_change_plan, Plan) ->
|
||||
Status = Plan#dep_adj_StatusChangePlan.new_status,
|
||||
Status = Plan#deposit_adj_StatusChangePlan.new_status,
|
||||
#{
|
||||
new_status => ff_deposit_status_codec:unmarshal(status, Status)
|
||||
};
|
||||
unmarshal(change_request, {change_status, Request}) ->
|
||||
Status = Request#dep_adj_ChangeStatusRequest.new_status,
|
||||
Status = Request#deposit_adj_ChangeStatusRequest.new_status,
|
||||
{change_status, ff_deposit_status_codec:unmarshal(status, Status)};
|
||||
unmarshal(T, V) ->
|
||||
ff_codec:unmarshal(T, V).
|
||||
|
@ -2,14 +2,16 @@
|
||||
|
||||
-behaviour(ff_codec).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_deposit_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_deposit_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_deposit_status_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_base_thrift.hrl").
|
||||
|
||||
-export([marshal_deposit_state/2]).
|
||||
-export([marshal/2]).
|
||||
-export([unmarshal/2]).
|
||||
|
||||
-spec marshal_deposit_state(ff_deposit:deposit_state(), ff_entity_context:context()) ->
|
||||
ff_proto_deposit_thrift:'DepositState'().
|
||||
fistful_deposit_thrift:'DepositState'().
|
||||
marshal_deposit_state(DepositState, Context) ->
|
||||
CashFlow = ff_deposit:effective_final_cash_flow(DepositState),
|
||||
Reverts = ff_deposit:reverts(DepositState),
|
||||
@ -188,7 +190,7 @@ deposit_symmetry_test() ->
|
||||
source_id = genlib:unique(),
|
||||
wallet_id = genlib:unique(),
|
||||
external_id = undefined,
|
||||
status = {pending, #dep_status_Pending{}},
|
||||
status = {pending, #deposit_status_Pending{}},
|
||||
id = genlib:unique(),
|
||||
domain_revision = 24500062,
|
||||
party_revision = 140028,
|
||||
@ -231,7 +233,7 @@ deposit_timestamped_change_codec_test() ->
|
||||
},
|
||||
Change = {created, Deposit},
|
||||
TimestampedChange = {ev, machinery_time:now(), Change},
|
||||
Type = {struct, struct, {ff_proto_deposit_thrift, 'TimestampedChange'}},
|
||||
Type = {struct, struct, {fistful_deposit_thrift, 'TimestampedChange'}},
|
||||
Binary = ff_proto_utils:serialize(Type, marshal(timestamped_change, TimestampedChange)),
|
||||
Decoded = ff_proto_utils:deserialize(Type, Binary),
|
||||
?assertEqual(TimestampedChange, unmarshal(timestamped_change, Decoded)).
|
||||
@ -255,7 +257,7 @@ deposit_change_revert_codec_test() ->
|
||||
},
|
||||
Change = {revert, Revert},
|
||||
TimestampedChange = {ev, machinery_time:now(), Change},
|
||||
Type = {struct, struct, {ff_proto_deposit_thrift, 'TimestampedChange'}},
|
||||
Type = {struct, struct, {fistful_deposit_thrift, 'TimestampedChange'}},
|
||||
Binary = ff_proto_utils:serialize(Type, marshal(timestamped_change, TimestampedChange)),
|
||||
Decoded = ff_proto_utils:deserialize(Type, Binary),
|
||||
?assertEqual(TimestampedChange, unmarshal(timestamped_change, Decoded)).
|
||||
@ -286,7 +288,7 @@ deposit_change_adjustment_codec_test() ->
|
||||
},
|
||||
Change = {adjustment, Adjustment},
|
||||
TimestampedChange = {ev, machinery_time:now(), Change},
|
||||
Type = {struct, struct, {ff_proto_deposit_thrift, 'TimestampedChange'}},
|
||||
Type = {struct, struct, {fistful_deposit_thrift, 'TimestampedChange'}},
|
||||
Binary = ff_proto_utils:serialize(Type, marshal(timestamped_change, TimestampedChange)),
|
||||
Decoded = ff_proto_utils:deserialize(Type, Binary),
|
||||
?assertEqual(TimestampedChange, unmarshal(timestamped_change, Decoded)).
|
||||
|
@ -4,13 +4,13 @@
|
||||
|
||||
-export([publish_events/1]).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_deposit_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/ff_proto_cashflow_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/ff_proto_base_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_deposit_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_cashflow_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_base_thrift.hrl").
|
||||
-include_lib("mg_proto/include/mg_proto_state_processing_thrift.hrl").
|
||||
|
||||
-type event() :: ff_eventsink_publisher:event(ff_deposit:event()).
|
||||
-type sinkevent() :: ff_eventsink_publisher:sinkevent(ff_proto_deposit_thrift:'SinkEvent'()).
|
||||
-type sinkevent() :: ff_eventsink_publisher:sinkevent(fistful_deposit_thrift:'SinkEvent'()).
|
||||
|
||||
%%
|
||||
%% Internals
|
||||
|
@ -2,7 +2,9 @@
|
||||
|
||||
-behaviour(ff_woody_wrapper).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_deposit_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_deposit_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_base_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_thrift.hrl").
|
||||
|
||||
%% ff_woody_wrapper callbacks
|
||||
-export([handle_function/3]).
|
||||
|
@ -3,7 +3,7 @@
|
||||
%% Storage schema behaviour
|
||||
-behaviour(machinery_mg_schema).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_deposit_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_deposit_thrift.hrl").
|
||||
-include_lib("mg_proto/include/mg_proto_state_processing_thrift.hrl").
|
||||
|
||||
-export([get_version/1]).
|
||||
@ -77,13 +77,13 @@ marshal_event(undefined = Version, TimestampedChange, Context) ->
|
||||
machinery_mg_schema_generic:marshal({event, Version}, TimestampedChange, Context);
|
||||
marshal_event(1, TimestampedChange, Context) ->
|
||||
ThriftChange = ff_deposit_codec:marshal(timestamped_change, TimestampedChange),
|
||||
Type = {struct, struct, {ff_proto_deposit_thrift, 'TimestampedChange'}},
|
||||
Type = {struct, struct, {fistful_deposit_thrift, 'TimestampedChange'}},
|
||||
{{bin, ff_proto_utils:serialize(Type, ThriftChange)}, Context}.
|
||||
|
||||
-spec unmarshal_event(machinery_mg_schema:version(), machinery_msgpack:t(), context()) -> {event(), context()}.
|
||||
unmarshal_event(1, EncodedChange, Context) ->
|
||||
{bin, EncodedThriftChange} = EncodedChange,
|
||||
Type = {struct, struct, {ff_proto_deposit_thrift, 'TimestampedChange'}},
|
||||
Type = {struct, struct, {fistful_deposit_thrift, 'TimestampedChange'}},
|
||||
ThriftChange = ff_proto_utils:deserialize(Type, EncodedThriftChange),
|
||||
{ff_deposit_codec:unmarshal(timestamped_change, ThriftChange), Context};
|
||||
unmarshal_event(undefined = Version, EncodedChange, Context0) ->
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
-export([handle_function/3]).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_fistful_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_thrift.hrl").
|
||||
|
||||
-type options() :: undefined.
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
-behaviour(ff_codec).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_deposit_revert_adjustment_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_deposit_revert_adj_thrift.hrl").
|
||||
|
||||
-export([marshal/2]).
|
||||
-export([unmarshal/2]).
|
||||
@ -11,13 +11,13 @@
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) -> ff_codec:encoded_value().
|
||||
marshal(change, {created, Adjustment}) ->
|
||||
{created, #dep_rev_adj_CreatedChange{adjustment = marshal(adjustment, Adjustment)}};
|
||||
{created, #deposit_revert_adj_CreatedChange{adjustment = marshal(adjustment, Adjustment)}};
|
||||
marshal(change, {status_changed, Status}) ->
|
||||
{status_changed, #dep_rev_adj_StatusChange{status = marshal(status, Status)}};
|
||||
{status_changed, #deposit_revert_adj_StatusChange{status = marshal(status, Status)}};
|
||||
marshal(change, {p_transfer, TransferChange}) ->
|
||||
{transfer, #dep_rev_adj_TransferChange{payload = ff_p_transfer_codec:marshal(change, TransferChange)}};
|
||||
{transfer, #deposit_revert_adj_TransferChange{payload = ff_p_transfer_codec:marshal(change, TransferChange)}};
|
||||
marshal(adjustment, Adjustment) ->
|
||||
#dep_rev_adj_Adjustment{
|
||||
#deposit_revert_adj_Adjustment{
|
||||
id = marshal(id, ff_adjustment:id(Adjustment)),
|
||||
status = maybe_marshal(status, ff_adjustment:status(Adjustment)),
|
||||
changes_plan = marshal(changes_plan, ff_adjustment:changes_plan(Adjustment)),
|
||||
@ -28,13 +28,13 @@ marshal(adjustment, Adjustment) ->
|
||||
external_id = maybe_marshal(id, ff_adjustment:external_id(Adjustment))
|
||||
};
|
||||
marshal(adjustment_params, Params) ->
|
||||
#dep_rev_adj_AdjustmentParams{
|
||||
#deposit_revert_adj_AdjustmentParams{
|
||||
id = marshal(id, maps:get(id, Params)),
|
||||
change = marshal(change_request, maps:get(change, Params)),
|
||||
external_id = maybe_marshal(id, maps:get(external_id, Params, undefined))
|
||||
};
|
||||
marshal(adjustment_state, Adjustment) ->
|
||||
#dep_rev_adj_AdjustmentState{
|
||||
#deposit_revert_adj_AdjustmentState{
|
||||
id = marshal(id, ff_adjustment:id(Adjustment)),
|
||||
status = maybe_marshal(status, ff_adjustment:status(Adjustment)),
|
||||
changes_plan = marshal(changes_plan, ff_adjustment:changes_plan(Adjustment)),
|
||||
@ -45,79 +45,79 @@ marshal(adjustment_state, Adjustment) ->
|
||||
external_id = maybe_marshal(id, ff_adjustment:external_id(Adjustment))
|
||||
};
|
||||
marshal(status, pending) ->
|
||||
{pending, #dep_rev_adj_Pending{}};
|
||||
{pending, #deposit_revert_adj_Pending{}};
|
||||
marshal(status, succeeded) ->
|
||||
{succeeded, #dep_rev_adj_Succeeded{}};
|
||||
{succeeded, #deposit_revert_adj_Succeeded{}};
|
||||
marshal(changes_plan, Plan) ->
|
||||
#dep_rev_adj_ChangesPlan{
|
||||
#deposit_revert_adj_ChangesPlan{
|
||||
new_cash_flow = maybe_marshal(cash_flow_change_plan, maps:get(new_cash_flow, Plan, undefined)),
|
||||
new_status = maybe_marshal(status_change_plan, maps:get(new_status, Plan, undefined))
|
||||
};
|
||||
marshal(cash_flow_change_plan, Plan) ->
|
||||
OldCashFLow = ff_cash_flow_codec:marshal(final_cash_flow, maps:get(old_cash_flow_inverted, Plan)),
|
||||
NewCashFlow = ff_cash_flow_codec:marshal(final_cash_flow, maps:get(new_cash_flow, Plan)),
|
||||
#dep_rev_adj_CashFlowChangePlan{
|
||||
#deposit_revert_adj_CashFlowChangePlan{
|
||||
old_cash_flow_inverted = OldCashFLow,
|
||||
new_cash_flow = NewCashFlow
|
||||
};
|
||||
marshal(status_change_plan, Plan) ->
|
||||
#dep_rev_adj_StatusChangePlan{
|
||||
#deposit_revert_adj_StatusChangePlan{
|
||||
new_status = ff_deposit_revert_status_codec:marshal(status, maps:get(new_status, Plan))
|
||||
};
|
||||
marshal(change_request, {change_status, Status}) ->
|
||||
{change_status, #dep_rev_adj_ChangeStatusRequest{
|
||||
{change_status, #deposit_revert_adj_ChangeStatusRequest{
|
||||
new_status = ff_deposit_revert_status_codec:marshal(status, Status)
|
||||
}};
|
||||
marshal(T, V) ->
|
||||
ff_codec:marshal(T, V).
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) -> ff_codec:decoded_value().
|
||||
unmarshal(change, {created, #dep_rev_adj_CreatedChange{adjustment = Adjustment}}) ->
|
||||
unmarshal(change, {created, #deposit_revert_adj_CreatedChange{adjustment = Adjustment}}) ->
|
||||
{created, unmarshal(adjustment, Adjustment)};
|
||||
unmarshal(change, {status_changed, #dep_rev_adj_StatusChange{status = Status}}) ->
|
||||
unmarshal(change, {status_changed, #deposit_revert_adj_StatusChange{status = Status}}) ->
|
||||
{status_changed, unmarshal(status, Status)};
|
||||
unmarshal(change, {transfer, #dep_rev_adj_TransferChange{payload = TransferChange}}) ->
|
||||
unmarshal(change, {transfer, #deposit_revert_adj_TransferChange{payload = TransferChange}}) ->
|
||||
{p_transfer, ff_p_transfer_codec:unmarshal(change, TransferChange)};
|
||||
unmarshal(adjustment, Adjustment) ->
|
||||
#{
|
||||
id => unmarshal(id, Adjustment#dep_rev_adj_Adjustment.id),
|
||||
status => unmarshal(status, Adjustment#dep_rev_adj_Adjustment.status),
|
||||
changes_plan => unmarshal(changes_plan, Adjustment#dep_rev_adj_Adjustment.changes_plan),
|
||||
created_at => unmarshal(timestamp_ms, Adjustment#dep_rev_adj_Adjustment.created_at),
|
||||
domain_revision => unmarshal(domain_revision, Adjustment#dep_rev_adj_Adjustment.domain_revision),
|
||||
party_revision => unmarshal(party_revision, Adjustment#dep_rev_adj_Adjustment.party_revision),
|
||||
operation_timestamp => unmarshal(timestamp_ms, Adjustment#dep_rev_adj_Adjustment.operation_timestamp),
|
||||
external_id => maybe_unmarshal(id, Adjustment#dep_rev_adj_Adjustment.external_id)
|
||||
id => unmarshal(id, Adjustment#deposit_revert_adj_Adjustment.id),
|
||||
status => unmarshal(status, Adjustment#deposit_revert_adj_Adjustment.status),
|
||||
changes_plan => unmarshal(changes_plan, Adjustment#deposit_revert_adj_Adjustment.changes_plan),
|
||||
created_at => unmarshal(timestamp_ms, Adjustment#deposit_revert_adj_Adjustment.created_at),
|
||||
domain_revision => unmarshal(domain_revision, Adjustment#deposit_revert_adj_Adjustment.domain_revision),
|
||||
party_revision => unmarshal(party_revision, Adjustment#deposit_revert_adj_Adjustment.party_revision),
|
||||
operation_timestamp => unmarshal(timestamp_ms, Adjustment#deposit_revert_adj_Adjustment.operation_timestamp),
|
||||
external_id => maybe_unmarshal(id, Adjustment#deposit_revert_adj_Adjustment.external_id)
|
||||
};
|
||||
unmarshal(adjustment_params, Params) ->
|
||||
genlib_map:compact(#{
|
||||
id => unmarshal(id, Params#dep_rev_adj_AdjustmentParams.id),
|
||||
change => unmarshal(change_request, Params#dep_rev_adj_AdjustmentParams.change),
|
||||
external_id => maybe_unmarshal(id, Params#dep_rev_adj_AdjustmentParams.external_id)
|
||||
id => unmarshal(id, Params#deposit_revert_adj_AdjustmentParams.id),
|
||||
change => unmarshal(change_request, Params#deposit_revert_adj_AdjustmentParams.change),
|
||||
external_id => maybe_unmarshal(id, Params#deposit_revert_adj_AdjustmentParams.external_id)
|
||||
});
|
||||
unmarshal(status, {pending, #dep_rev_adj_Pending{}}) ->
|
||||
unmarshal(status, {pending, #deposit_revert_adj_Pending{}}) ->
|
||||
pending;
|
||||
unmarshal(status, {succeeded, #dep_rev_adj_Succeeded{}}) ->
|
||||
unmarshal(status, {succeeded, #deposit_revert_adj_Succeeded{}}) ->
|
||||
succeeded;
|
||||
unmarshal(changes_plan, Plan) ->
|
||||
genlib_map:compact(#{
|
||||
new_cash_flow => maybe_unmarshal(cash_flow_change_plan, Plan#dep_rev_adj_ChangesPlan.new_cash_flow),
|
||||
new_status => maybe_unmarshal(status_change_plan, Plan#dep_rev_adj_ChangesPlan.new_status)
|
||||
new_cash_flow => maybe_unmarshal(cash_flow_change_plan, Plan#deposit_revert_adj_ChangesPlan.new_cash_flow),
|
||||
new_status => maybe_unmarshal(status_change_plan, Plan#deposit_revert_adj_ChangesPlan.new_status)
|
||||
});
|
||||
unmarshal(cash_flow_change_plan, Plan) ->
|
||||
OldCashFlow = Plan#dep_rev_adj_CashFlowChangePlan.old_cash_flow_inverted,
|
||||
NewCashFlow = Plan#dep_rev_adj_CashFlowChangePlan.new_cash_flow,
|
||||
OldCashFlow = Plan#deposit_revert_adj_CashFlowChangePlan.old_cash_flow_inverted,
|
||||
NewCashFlow = Plan#deposit_revert_adj_CashFlowChangePlan.new_cash_flow,
|
||||
#{
|
||||
old_cash_flow_inverted => ff_cash_flow_codec:unmarshal(final_cash_flow, OldCashFlow),
|
||||
new_cash_flow => ff_cash_flow_codec:unmarshal(final_cash_flow, NewCashFlow)
|
||||
};
|
||||
unmarshal(status_change_plan, Plan) ->
|
||||
Status = Plan#dep_rev_adj_StatusChangePlan.new_status,
|
||||
Status = Plan#deposit_revert_adj_StatusChangePlan.new_status,
|
||||
#{
|
||||
new_status => ff_deposit_revert_status_codec:unmarshal(status, Status)
|
||||
};
|
||||
unmarshal(change_request, {change_status, Request}) ->
|
||||
Status = Request#dep_rev_adj_ChangeStatusRequest.new_status,
|
||||
Status = Request#deposit_revert_adj_ChangeStatusRequest.new_status,
|
||||
{change_status, ff_deposit_revert_status_codec:unmarshal(status, Status)};
|
||||
unmarshal(T, V) ->
|
||||
ff_codec:unmarshal(T, V).
|
||||
|
@ -2,7 +2,11 @@
|
||||
|
||||
-behaviour(ff_codec).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_deposit_revert_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_deposit_revert_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_base_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_deposit_revert_status_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_deposit_revert_adj_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_cashflow_thrift.hrl").
|
||||
|
||||
-export([marshal/2]).
|
||||
-export([unmarshal/2]).
|
||||
@ -143,7 +147,7 @@ revert_symmetry_test() ->
|
||||
created_at = <<"2000-01-01T00:00:00Z">>,
|
||||
external_id = undefined,
|
||||
reason = <<"why not">>,
|
||||
status = {pending, #dep_rev_status_Pending{}},
|
||||
status = {pending, #deposit_revert_status_Pending{}},
|
||||
id = genlib:unique()
|
||||
},
|
||||
?assertEqual(Encoded, marshal(revert, unmarshal(revert, Encoded))).
|
||||
@ -167,12 +171,12 @@ change_adjustment_symmetry_test() ->
|
||||
{adjustment, #deposit_revert_AdjustmentChange{
|
||||
id = genlib:unique(),
|
||||
payload =
|
||||
{created, #dep_rev_adj_CreatedChange{
|
||||
adjustment = #dep_rev_adj_Adjustment{
|
||||
{created, #deposit_revert_adj_CreatedChange{
|
||||
adjustment = #deposit_revert_adj_Adjustment{
|
||||
id = genlib:unique(),
|
||||
status = {pending, #dep_rev_adj_Pending{}},
|
||||
changes_plan = #dep_rev_adj_ChangesPlan{
|
||||
new_cash_flow = #dep_rev_adj_CashFlowChangePlan{
|
||||
status = {pending, #deposit_revert_adj_Pending{}},
|
||||
changes_plan = #deposit_revert_adj_ChangesPlan{
|
||||
new_cash_flow = #deposit_revert_adj_CashFlowChangePlan{
|
||||
old_cash_flow_inverted = #cashflow_FinalCashFlow{postings = []},
|
||||
new_cash_flow = #cashflow_FinalCashFlow{postings = []}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
-behaviour(ff_codec).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_deposit_revert_status_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_deposit_revert_status_thrift.hrl").
|
||||
|
||||
-export([marshal/2]).
|
||||
-export([unmarshal/2]).
|
||||
@ -11,20 +11,20 @@
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) -> ff_codec:encoded_value().
|
||||
marshal(status, pending) ->
|
||||
{pending, #dep_rev_status_Pending{}};
|
||||
{pending, #deposit_revert_status_Pending{}};
|
||||
marshal(status, succeeded) ->
|
||||
{succeeded, #dep_rev_status_Succeeded{}};
|
||||
{succeeded, #deposit_revert_status_Succeeded{}};
|
||||
marshal(status, {failed, Failure}) ->
|
||||
{failed, #dep_rev_status_Failed{failure = marshal(failure, Failure)}};
|
||||
{failed, #deposit_revert_status_Failed{failure = marshal(failure, Failure)}};
|
||||
marshal(T, V) ->
|
||||
ff_codec:marshal(T, V).
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) -> ff_codec:decoded_value().
|
||||
unmarshal(status, {pending, #dep_rev_status_Pending{}}) ->
|
||||
unmarshal(status, {pending, #deposit_revert_status_Pending{}}) ->
|
||||
pending;
|
||||
unmarshal(status, {succeeded, #dep_rev_status_Succeeded{}}) ->
|
||||
unmarshal(status, {succeeded, #deposit_revert_status_Succeeded{}}) ->
|
||||
succeeded;
|
||||
unmarshal(status, {failed, #dep_rev_status_Failed{failure = Failure}}) ->
|
||||
unmarshal(status, {failed, #deposit_revert_status_Failed{failure = Failure}}) ->
|
||||
{failed, unmarshal(failure, Failure)};
|
||||
unmarshal(T, V) ->
|
||||
ff_codec:unmarshal(T, V).
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
-behaviour(ff_codec).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_deposit_status_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_deposit_status_thrift.hrl").
|
||||
|
||||
-export([marshal/2]).
|
||||
-export([unmarshal/2]).
|
||||
@ -11,20 +11,20 @@
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) -> ff_codec:encoded_value().
|
||||
marshal(status, pending) ->
|
||||
{pending, #dep_status_Pending{}};
|
||||
{pending, #deposit_status_Pending{}};
|
||||
marshal(status, succeeded) ->
|
||||
{succeeded, #dep_status_Succeeded{}};
|
||||
{succeeded, #deposit_status_Succeeded{}};
|
||||
marshal(status, {failed, Failure}) ->
|
||||
{failed, #dep_status_Failed{failure = marshal(failure, Failure)}};
|
||||
{failed, #deposit_status_Failed{failure = marshal(failure, Failure)}};
|
||||
marshal(T, V) ->
|
||||
ff_codec:marshal(T, V).
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) -> ff_codec:decoded_value().
|
||||
unmarshal(status, {pending, #dep_status_Pending{}}) ->
|
||||
unmarshal(status, {pending, #deposit_status_Pending{}}) ->
|
||||
pending;
|
||||
unmarshal(status, {succeeded, #dep_status_Succeeded{}}) ->
|
||||
unmarshal(status, {succeeded, #deposit_status_Succeeded{}}) ->
|
||||
succeeded;
|
||||
unmarshal(status, {failed, #dep_status_Failed{failure = Failure}}) ->
|
||||
unmarshal(status, {failed, #deposit_status_Failed{failure = Failure}}) ->
|
||||
{failed, unmarshal(failure, Failure)};
|
||||
unmarshal(T, V) ->
|
||||
ff_codec:unmarshal(T, V).
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
-behaviour(ff_codec).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_destination_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_destination_thrift.hrl").
|
||||
|
||||
-export([unmarshal_destination_params/1]).
|
||||
-export([marshal_destination_state/2]).
|
||||
@ -14,20 +14,20 @@
|
||||
|
||||
%% API
|
||||
|
||||
-spec unmarshal_destination_params(ff_proto_destination_thrift:'DestinationParams'()) -> ff_destination:params().
|
||||
-spec unmarshal_destination_params(fistful_destination_thrift:'DestinationParams'()) -> ff_destination:params().
|
||||
unmarshal_destination_params(Params) ->
|
||||
genlib_map:compact(#{
|
||||
id => unmarshal(id, Params#dst_DestinationParams.id),
|
||||
identity => unmarshal(id, Params#dst_DestinationParams.identity),
|
||||
name => unmarshal(string, Params#dst_DestinationParams.name),
|
||||
currency => unmarshal(string, Params#dst_DestinationParams.currency),
|
||||
resource => unmarshal(resource, Params#dst_DestinationParams.resource),
|
||||
external_id => maybe_unmarshal(id, Params#dst_DestinationParams.external_id),
|
||||
metadata => maybe_unmarshal(ctx, Params#dst_DestinationParams.metadata)
|
||||
id => unmarshal(id, Params#destination_DestinationParams.id),
|
||||
identity => unmarshal(id, Params#destination_DestinationParams.identity),
|
||||
name => unmarshal(string, Params#destination_DestinationParams.name),
|
||||
currency => unmarshal(string, Params#destination_DestinationParams.currency),
|
||||
resource => unmarshal(resource, Params#destination_DestinationParams.resource),
|
||||
external_id => maybe_unmarshal(id, Params#destination_DestinationParams.external_id),
|
||||
metadata => maybe_unmarshal(ctx, Params#destination_DestinationParams.metadata)
|
||||
}).
|
||||
|
||||
-spec marshal_destination_state(ff_destination:destination_state(), ff_entity_context:context()) ->
|
||||
ff_proto_destination_thrift:'DestinationState'().
|
||||
fistful_destination_thrift:'DestinationState'().
|
||||
marshal_destination_state(DestinationState, Context) ->
|
||||
Blocking =
|
||||
case ff_destination:is_accessible(DestinationState) of
|
||||
@ -36,7 +36,7 @@ marshal_destination_state(DestinationState, Context) ->
|
||||
_ ->
|
||||
blocked
|
||||
end,
|
||||
#dst_DestinationState{
|
||||
#destination_DestinationState{
|
||||
id = marshal(id, ff_destination:id(DestinationState)),
|
||||
name = marshal(string, ff_destination:name(DestinationState)),
|
||||
resource = maybe_marshal(resource, ff_destination:resource(DestinationState)),
|
||||
@ -49,9 +49,9 @@ marshal_destination_state(DestinationState, Context) ->
|
||||
context = maybe_marshal(ctx, Context)
|
||||
}.
|
||||
|
||||
-spec marshal_event(ff_destination_machine:event()) -> ff_proto_destination_thrift:'Event'().
|
||||
-spec marshal_event(ff_destination_machine:event()) -> fistful_destination_thrift:'Event'().
|
||||
marshal_event({EventID, {ev, Timestamp, Change}}) ->
|
||||
#dst_Event{
|
||||
#destination_Event{
|
||||
event_id = ff_codec:marshal(event_id, EventID),
|
||||
occured_at = ff_codec:marshal(timestamp, Timestamp),
|
||||
change = marshal(change, Change)
|
||||
@ -59,7 +59,7 @@ marshal_event({EventID, {ev, Timestamp, Change}}) ->
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) -> ff_codec:encoded_value().
|
||||
marshal(timestamped_change, {ev, Timestamp, Change}) ->
|
||||
#dst_TimestampedChange{
|
||||
#destination_TimestampedChange{
|
||||
change = marshal(change, Change),
|
||||
occured_at = ff_codec:marshal(timestamp, Timestamp)
|
||||
};
|
||||
@ -76,7 +76,7 @@ marshal(
|
||||
resource := Resource
|
||||
}
|
||||
) ->
|
||||
#dst_Destination{
|
||||
#destination_Destination{
|
||||
name = Name,
|
||||
resource = marshal(resource, Resource),
|
||||
created_at = maybe_marshal(timestamp_ms, maps:get(created_at, Destination, undefined)),
|
||||
@ -84,13 +84,13 @@ marshal(
|
||||
metadata = maybe_marshal(ctx, maps:get(metadata, Destination, undefined))
|
||||
};
|
||||
marshal(status, authorized) ->
|
||||
{authorized, #dst_Authorized{}};
|
||||
{authorized, #destination_Authorized{}};
|
||||
marshal(status, unauthorized) ->
|
||||
{unauthorized, #dst_Unauthorized{}};
|
||||
{unauthorized, #destination_Unauthorized{}};
|
||||
marshal(status_change, unauthorized) ->
|
||||
{changed, {unauthorized, #dst_Unauthorized{}}};
|
||||
{changed, {unauthorized, #destination_Unauthorized{}}};
|
||||
marshal(status_change, authorized) ->
|
||||
{changed, {authorized, #dst_Authorized{}}};
|
||||
{changed, {authorized, #destination_Authorized{}}};
|
||||
marshal(ctx, Ctx) ->
|
||||
marshal(context, Ctx);
|
||||
marshal(T, V) ->
|
||||
@ -99,15 +99,15 @@ marshal(T, V) ->
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) -> ff_codec:decoded_value().
|
||||
unmarshal({list, T}, V) ->
|
||||
[unmarshal(T, E) || E <- V];
|
||||
unmarshal(repair_scenario, {add_events, #dst_AddEventsRepair{events = Events, action = Action}}) ->
|
||||
unmarshal(repair_scenario, {add_events, #destination_AddEventsRepair{events = Events, action = Action}}) ->
|
||||
{add_events,
|
||||
genlib_map:compact(#{
|
||||
events => unmarshal({list, change}, Events),
|
||||
action => maybe_unmarshal(complex_action, Action)
|
||||
})};
|
||||
unmarshal(timestamped_change, TimestampedChange) ->
|
||||
Timestamp = ff_codec:unmarshal(timestamp, TimestampedChange#dst_TimestampedChange.occured_at),
|
||||
Change = unmarshal(change, TimestampedChange#dst_TimestampedChange.change),
|
||||
Timestamp = ff_codec:unmarshal(timestamp, TimestampedChange#destination_TimestampedChange.occured_at),
|
||||
Change = unmarshal(change, TimestampedChange#destination_TimestampedChange.change),
|
||||
{ev, Timestamp, Change};
|
||||
unmarshal(change, {created, Destination}) ->
|
||||
{created, unmarshal(destination, Destination)};
|
||||
@ -118,19 +118,19 @@ unmarshal(change, {status, StatusChange}) ->
|
||||
unmarshal(destination, Dest) ->
|
||||
genlib_map:compact(#{
|
||||
version => 3,
|
||||
resource => unmarshal(resource, Dest#dst_Destination.resource),
|
||||
name => unmarshal(string, Dest#dst_Destination.name),
|
||||
created_at => maybe_unmarshal(timestamp_ms, Dest#dst_Destination.created_at),
|
||||
external_id => maybe_unmarshal(id, Dest#dst_Destination.external_id),
|
||||
metadata => maybe_unmarshal(ctx, Dest#dst_Destination.metadata)
|
||||
resource => unmarshal(resource, Dest#destination_Destination.resource),
|
||||
name => unmarshal(string, Dest#destination_Destination.name),
|
||||
created_at => maybe_unmarshal(timestamp_ms, Dest#destination_Destination.created_at),
|
||||
external_id => maybe_unmarshal(id, Dest#destination_Destination.external_id),
|
||||
metadata => maybe_unmarshal(ctx, Dest#destination_Destination.metadata)
|
||||
});
|
||||
unmarshal(status, {authorized, #dst_Authorized{}}) ->
|
||||
unmarshal(status, {authorized, #destination_Authorized{}}) ->
|
||||
authorized;
|
||||
unmarshal(status, {unauthorized, #dst_Unauthorized{}}) ->
|
||||
unmarshal(status, {unauthorized, #destination_Unauthorized{}}) ->
|
||||
unauthorized;
|
||||
unmarshal(status_change, {changed, {unauthorized, #dst_Unauthorized{}}}) ->
|
||||
unmarshal(status_change, {changed, {unauthorized, #destination_Unauthorized{}}}) ->
|
||||
unauthorized;
|
||||
unmarshal(status_change, {changed, {authorized, #dst_Authorized{}}}) ->
|
||||
unmarshal(status_change, {changed, {authorized, #destination_Authorized{}}}) ->
|
||||
authorized;
|
||||
unmarshal(ctx, Ctx) ->
|
||||
maybe_unmarshal(context, Ctx);
|
||||
|
@ -4,10 +4,10 @@
|
||||
|
||||
-export([publish_events/1]).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_destination_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_destination_thrift.hrl").
|
||||
|
||||
-type event() :: ff_eventsink_publisher:event(ff_destination:event()).
|
||||
-type sinkevent() :: ff_eventsink_publisher:sinkevent(ff_proto_destination_thrift:'SinkEvent'()).
|
||||
-type sinkevent() :: ff_eventsink_publisher:sinkevent(fistful_destination_thrift:'SinkEvent'()).
|
||||
|
||||
-spec publish_events(list(event())) -> list(sinkevent()).
|
||||
publish_events(Events) ->
|
||||
@ -23,11 +23,11 @@ publish_event(#{
|
||||
{ev, EventDt, Payload}
|
||||
}
|
||||
}) ->
|
||||
#dst_SinkEvent{
|
||||
#destination_SinkEvent{
|
||||
id = marshal(event_id, ID),
|
||||
created_at = marshal(timestamp, Dt),
|
||||
source = marshal(id, SourceID),
|
||||
payload = #dst_EventSinkPayload{
|
||||
payload = #destination_EventSinkPayload{
|
||||
sequence = marshal(event_id, EventID),
|
||||
occured_at = marshal(timestamp, EventDt),
|
||||
changes = [marshal(change, Payload)]
|
||||
|
@ -2,7 +2,9 @@
|
||||
|
||||
-behaviour(ff_woody_wrapper).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_destination_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_destination_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_base_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_thrift.hrl").
|
||||
|
||||
%% ff_woody_wrapper callbacks
|
||||
-export([handle_function/3]).
|
||||
@ -24,7 +26,7 @@ handle_function(Func, Args, Opts) ->
|
||||
%% Internals
|
||||
%%
|
||||
handle_function_('Create', {Params, Ctx}, Opts) ->
|
||||
ID = Params#dst_DestinationParams.id,
|
||||
ID = Params#destination_DestinationParams.id,
|
||||
case
|
||||
ff_destination_machine:create(
|
||||
ff_destination_codec:unmarshal_destination_params(Params),
|
||||
|
@ -3,7 +3,7 @@
|
||||
%% Storage schema behaviour
|
||||
-behaviour(machinery_mg_schema).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_destination_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_destination_thrift.hrl").
|
||||
-include_lib("mg_proto/include/mg_proto_state_processing_thrift.hrl").
|
||||
|
||||
%% Constants
|
||||
@ -78,13 +78,13 @@ marshal_event(undefined = Version, TimestampedChange, Context) ->
|
||||
%%======
|
||||
marshal_event(1, TimestampedChange, Context) ->
|
||||
ThriftChange = ff_destination_codec:marshal(timestamped_change, TimestampedChange),
|
||||
Type = {struct, struct, {ff_proto_destination_thrift, 'TimestampedChange'}},
|
||||
Type = {struct, struct, {fistful_destination_thrift, 'TimestampedChange'}},
|
||||
{{bin, ff_proto_utils:serialize(Type, ThriftChange)}, Context}.
|
||||
|
||||
-spec unmarshal_event(machinery_mg_schema:version(), machinery_msgpack:t(), context()) -> {event(), context()}.
|
||||
unmarshal_event(1, EncodedChange, Context) ->
|
||||
{bin, EncodedThriftChange} = EncodedChange,
|
||||
Type = {struct, struct, {ff_proto_destination_thrift, 'TimestampedChange'}},
|
||||
Type = {struct, struct, {fistful_destination_thrift, 'TimestampedChange'}},
|
||||
ThriftChange = ff_proto_utils:deserialize(Type, EncodedThriftChange),
|
||||
{ff_destination_codec:unmarshal(timestamped_change, ThriftChange), Context};
|
||||
unmarshal_event(undefined = Version, EncodedChange, Context0) ->
|
||||
|
@ -1,6 +1,6 @@
|
||||
-module(ff_entity_context_codec).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_msgpack_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_msgp_thrift.hrl").
|
||||
|
||||
-type ctx() :: ff_entity_context:context().
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
-export([handle_function/3]).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_eventsink_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_evsink_thrift.hrl").
|
||||
|
||||
-type options() :: #{
|
||||
schema := module(),
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
-behaviour(ff_codec).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_identity_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_identity_thrift.hrl").
|
||||
|
||||
-export([unmarshal_identity_params/1]).
|
||||
|
||||
@ -13,8 +13,8 @@
|
||||
-export([unmarshal/2]).
|
||||
|
||||
%% This special functions hasn't got opposite functions.
|
||||
-spec unmarshal_identity_params(ff_proto_identity_thrift:'IdentityParams'()) -> ff_identity_machine:params().
|
||||
unmarshal_identity_params(#idnt_IdentityParams{
|
||||
-spec unmarshal_identity_params(fistful_identity_thrift:'IdentityParams'()) -> ff_identity_machine:params().
|
||||
unmarshal_identity_params(#identity_IdentityParams{
|
||||
id = ID,
|
||||
name = Name,
|
||||
party = PartyID,
|
||||
@ -32,18 +32,18 @@ unmarshal_identity_params(#idnt_IdentityParams{
|
||||
}).
|
||||
|
||||
-spec marshal_identity_event({integer(), ff_machine:timestamped_event(ff_identity:event())}) ->
|
||||
ff_proto_identity_thrift:'Event'().
|
||||
fistful_identity_thrift:'Event'().
|
||||
marshal_identity_event({ID, {ev, Timestamp, Ev}}) ->
|
||||
#idnt_Event{
|
||||
#identity_Event{
|
||||
sequence = marshal(event_id, ID),
|
||||
occured_at = marshal(timestamp, Timestamp),
|
||||
change = marshal(change, Ev)
|
||||
}.
|
||||
|
||||
-spec marshal_identity_state(ff_identity:identity_state(), ff_entity_context:context()) ->
|
||||
ff_proto_identity_thrift:'IdentityState'().
|
||||
fistful_identity_thrift:'IdentityState'().
|
||||
marshal_identity_state(IdentityState, Context) ->
|
||||
#idnt_IdentityState{
|
||||
#identity_IdentityState{
|
||||
id = maybe_marshal(id, ff_identity:id(IdentityState)),
|
||||
name = marshal(string, ff_identity:name(IdentityState)),
|
||||
party_id = marshal(id, ff_identity:party(IdentityState)),
|
||||
@ -60,14 +60,14 @@ marshal_identity_state(IdentityState, Context) ->
|
||||
marshal({list, T}, V) ->
|
||||
[marshal(T, E) || E <- V];
|
||||
marshal(timestamped_change, {ev, Timestamp, Change}) ->
|
||||
#idnt_TimestampedChange{
|
||||
#identity_TimestampedChange{
|
||||
change = marshal(change, Change),
|
||||
occured_at = ff_codec:marshal(timestamp, Timestamp)
|
||||
};
|
||||
marshal(change, {created, Identity}) ->
|
||||
{created, marshal(identity, Identity)};
|
||||
marshal(identity, Identity) ->
|
||||
#idnt_Identity{
|
||||
#identity_Identity{
|
||||
id = maybe_marshal(id, ff_identity:id(Identity)),
|
||||
name = maybe_marshal(string, ff_identity:name(Identity)),
|
||||
party = marshal(id, ff_identity:party(Identity)),
|
||||
@ -92,10 +92,10 @@ marshal(T, V) ->
|
||||
unmarshal({list, T}, V) ->
|
||||
[unmarshal(T, E) || E <- V];
|
||||
unmarshal(timestamped_change, TimestampedChange) ->
|
||||
Timestamp = ff_codec:unmarshal(timestamp, TimestampedChange#idnt_TimestampedChange.occured_at),
|
||||
Change = unmarshal(change, TimestampedChange#idnt_TimestampedChange.change),
|
||||
Timestamp = ff_codec:unmarshal(timestamp, TimestampedChange#identity_TimestampedChange.occured_at),
|
||||
Change = unmarshal(change, TimestampedChange#identity_TimestampedChange.change),
|
||||
{ev, Timestamp, Change};
|
||||
unmarshal(repair_scenario, {add_events, #idnt_AddEventsRepair{events = Events, action = Action}}) ->
|
||||
unmarshal(repair_scenario, {add_events, #identity_AddEventsRepair{events = Events, action = Action}}) ->
|
||||
{add_events,
|
||||
genlib_map:compact(#{
|
||||
events => unmarshal({list, change}, Events),
|
||||
@ -106,11 +106,11 @@ unmarshal(change, {created, Identity}) ->
|
||||
% We have to support this unmarshal cause mg contain identety's events with challenge
|
||||
unmarshal(change, {level_changed, LevelID}) ->
|
||||
{level_changed, unmarshal(id, LevelID)};
|
||||
unmarshal(change, {identity_challenge, #idnt_ChallengeChange{id = ID, payload = Payload}}) ->
|
||||
unmarshal(change, {identity_challenge, #identity_ChallengeChange{id = ID, payload = Payload}}) ->
|
||||
{{challenge, unmarshal(id, ID)}, unmarshal(challenge_payload, Payload)};
|
||||
unmarshal(change, {effective_challenge_changed, ChallengeID}) ->
|
||||
{effective_challenge_changed, unmarshal(id, ChallengeID)};
|
||||
unmarshal(identity, #idnt_Identity{
|
||||
unmarshal(identity, #identity_Identity{
|
||||
id = ID,
|
||||
name = Name,
|
||||
party = PartyID,
|
||||
@ -135,7 +135,7 @@ unmarshal(challenge_payload, {created, Challenge}) ->
|
||||
{created, unmarshal(challenge_payload_created, Challenge)};
|
||||
unmarshal(challenge_payload, {status_changed, ChallengeStatus}) ->
|
||||
{status_changed, unmarshal(challenge_payload_status_changed, ChallengeStatus)};
|
||||
unmarshal(challenge_payload_created, #idnt_Challenge{
|
||||
unmarshal(challenge_payload_created, #identity_Challenge{
|
||||
id = ID,
|
||||
cls = ChallengeClass,
|
||||
provider_id = ProviderID,
|
||||
@ -157,20 +157,20 @@ unmarshal(challenge_payload_created, #idnt_Challenge{
|
||||
};
|
||||
unmarshal(challenge_proofs, Proof) ->
|
||||
{
|
||||
unmarshal(proof_type, Proof#idnt_ChallengeProof.type),
|
||||
unmarshal(id, Proof#idnt_ChallengeProof.token)
|
||||
unmarshal(proof_type, Proof#identity_ChallengeProof.type),
|
||||
unmarshal(id, Proof#identity_ChallengeProof.token)
|
||||
};
|
||||
unmarshal(proof_type, rus_domestic_passport) ->
|
||||
rus_domestic_passport;
|
||||
unmarshal(proof_type, rus_retiree_insurance_cert) ->
|
||||
rus_retiree_insurance_cert;
|
||||
unmarshal(challenge_payload_status_changed, {pending, #idnt_ChallengePending{}}) ->
|
||||
unmarshal(challenge_payload_status_changed, {pending, #identity_ChallengePending{}}) ->
|
||||
pending;
|
||||
unmarshal(challenge_payload_status_changed, {cancelled, #idnt_ChallengeCancelled{}}) ->
|
||||
unmarshal(challenge_payload_status_changed, {cancelled, #identity_ChallengeCancelled{}}) ->
|
||||
cancelled;
|
||||
unmarshal(
|
||||
challenge_payload_status_changed,
|
||||
{completed, #idnt_ChallengeCompleted{
|
||||
{completed, #identity_ChallengeCompleted{
|
||||
resolution = Resolution,
|
||||
valid_until = ValidUntil
|
||||
}}
|
||||
@ -180,7 +180,7 @@ unmarshal(
|
||||
resolution => unmarshal(resolution, Resolution),
|
||||
valid_until => maybe_unmarshal(timestamp, ValidUntil)
|
||||
})};
|
||||
unmarshal(challenge_payload_status_changed, {failed, #idnt_ChallengeFailed{}}) ->
|
||||
unmarshal(challenge_payload_status_changed, {failed, #identity_ChallengeFailed{}}) ->
|
||||
% FIXME: Describe failures in protocol
|
||||
{failed, unknown};
|
||||
unmarshal(resolution, approved) ->
|
||||
|
@ -4,10 +4,10 @@
|
||||
|
||||
-export([publish_events/1]).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_identity_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_identity_thrift.hrl").
|
||||
|
||||
-type event() :: ff_eventsink_publisher:event(ff_identity:event()).
|
||||
-type sinkevent() :: ff_eventsink_publisher:sinkevent(ff_proto_identity_thrift:'SinkEvent'()).
|
||||
-type sinkevent() :: ff_eventsink_publisher:sinkevent(fistful_identity_thrift:'SinkEvent'()).
|
||||
|
||||
-spec publish_events(list(event())) -> list(sinkevent()).
|
||||
publish_events(Events) ->
|
||||
@ -23,11 +23,11 @@ publish_event(#{
|
||||
{ev, EventDt, Payload}
|
||||
}
|
||||
}) ->
|
||||
#idnt_SinkEvent{
|
||||
#identity_SinkEvent{
|
||||
id = marshal(event_id, ID),
|
||||
created_at = marshal(timestamp, Dt),
|
||||
source = marshal(id, SourceID),
|
||||
payload = #idnt_EventSinkPayload{
|
||||
payload = #identity_EventSinkPayload{
|
||||
sequence = marshal(event_id, EventID),
|
||||
occured_at = marshal(timestamp, EventDt),
|
||||
changes = [marshal(change, Payload)]
|
||||
|
@ -2,7 +2,9 @@
|
||||
|
||||
-behaviour(ff_woody_wrapper).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_identity_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_identity_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_base_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_thrift.hrl").
|
||||
|
||||
%% ff_woody_wrapper callbacks
|
||||
-export([handle_function/3]).
|
||||
|
@ -3,7 +3,7 @@
|
||||
%% Storage schema behaviour
|
||||
-behaviour(machinery_mg_schema).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_identity_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_identity_thrift.hrl").
|
||||
-include_lib("mg_proto/include/mg_proto_state_processing_thrift.hrl").
|
||||
|
||||
-export([get_version/1]).
|
||||
@ -28,8 +28,8 @@
|
||||
|
||||
-type legacy_change() :: any().
|
||||
|
||||
-type timestamped_change() :: ff_proto_identity_thrift:'TimestampedChange'().
|
||||
-type thrift_change() :: ff_proto_identity_thrift:'Change'().
|
||||
-type timestamped_change() :: fistful_identity_thrift:'TimestampedChange'().
|
||||
-type thrift_change() :: fistful_identity_thrift:'Change'().
|
||||
|
||||
-type data() ::
|
||||
aux_state()
|
||||
@ -83,7 +83,7 @@ marshal_event(undefined = Version, TimestampedChange, Context) ->
|
||||
machinery_mg_schema_generic:marshal({event, Version}, TimestampedChange, Context);
|
||||
marshal_event(Version, TimestampedChange, Context) when Version =:= 1; Version =:= 2 ->
|
||||
ThriftChange = ff_identity_codec:marshal(timestamped_change, TimestampedChange),
|
||||
Type = {struct, struct, {ff_proto_identity_thrift, 'TimestampedChange'}},
|
||||
Type = {struct, struct, {fistful_identity_thrift, 'TimestampedChange'}},
|
||||
{{bin, ff_proto_utils:serialize(Type, ThriftChange)}, Context}.
|
||||
|
||||
-spec unmarshal_event(machinery_mg_schema:version(), machinery_msgpack:t(), context()) -> {event(), context()}.
|
||||
@ -92,8 +92,8 @@ unmarshal_event(2, EncodedChange, Context) ->
|
||||
{ff_identity_codec:unmarshal(timestamped_change, ThriftChange), Context};
|
||||
unmarshal_event(1, EncodedChange, Context) ->
|
||||
ThriftChange = unmashal_thrift_change(EncodedChange),
|
||||
MigratedChange = ThriftChange#idnt_TimestampedChange{
|
||||
change = maybe_migrate_thrift_change(ThriftChange#idnt_TimestampedChange.change, Context)
|
||||
MigratedChange = ThriftChange#identity_TimestampedChange{
|
||||
change = maybe_migrate_thrift_change(ThriftChange#identity_TimestampedChange.change, Context)
|
||||
},
|
||||
{ff_identity_codec:unmarshal(timestamped_change, MigratedChange), Context};
|
||||
unmarshal_event(undefined = Version, EncodedChange, Context) ->
|
||||
@ -107,13 +107,13 @@ unmarshal_event(undefined = Version, EncodedChange, Context) ->
|
||||
-spec unmashal_thrift_change(machinery_msgpack:t()) -> timestamped_change().
|
||||
unmashal_thrift_change(EncodedChange) ->
|
||||
{bin, EncodedThriftChange} = EncodedChange,
|
||||
Type = {struct, struct, {ff_proto_identity_thrift, 'TimestampedChange'}},
|
||||
Type = {struct, struct, {fistful_identity_thrift, 'TimestampedChange'}},
|
||||
ff_proto_utils:deserialize(Type, EncodedThriftChange).
|
||||
|
||||
-spec maybe_migrate_thrift_change(thrift_change(), context()) -> thrift_change().
|
||||
maybe_migrate_thrift_change({created, #idnt_Identity{name = undefined} = Identity}, MigrateContext) ->
|
||||
Context = fetch_entity_context(Identity#idnt_Identity.id, MigrateContext),
|
||||
{created, Identity#idnt_Identity{name = get_legacy_name(Context)}};
|
||||
maybe_migrate_thrift_change({created, #identity_Identity{name = undefined} = Identity}, MigrateContext) ->
|
||||
Context = fetch_entity_context(Identity#identity_Identity.id, MigrateContext),
|
||||
{created, Identity#identity_Identity{name = get_legacy_name(Context)}};
|
||||
maybe_migrate_thrift_change(Change, _MigrateContext) ->
|
||||
Change.
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
-behaviour(ff_codec).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_limit_check_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_lim_check_thrift.hrl").
|
||||
|
||||
-export([marshal/2]).
|
||||
-export([unmarshal/2]).
|
||||
|
@ -1,6 +1,6 @@
|
||||
-module(ff_msgpack_codec).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_msgpack_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_msgp_thrift.hrl").
|
||||
|
||||
-export([unmarshal/2]).
|
||||
-export([marshal/2]).
|
||||
@ -17,7 +17,7 @@
|
||||
| {binary, binary()}
|
||||
| nil.
|
||||
|
||||
-type encoded_value() :: ff_proto_msgpack_thrift:'Value'().
|
||||
-type encoded_value() :: fistful_msgp_thrift:'Value'().
|
||||
|
||||
-export_type([type_name/0]).
|
||||
-export_type([encoded_value/0]).
|
||||
|
@ -2,9 +2,9 @@
|
||||
|
||||
-behaviour(ff_codec).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_base_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/ff_proto_transfer_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/ff_proto_cashflow_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_base_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_transfer_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_cashflow_thrift.hrl").
|
||||
|
||||
-export([marshal/2]).
|
||||
-export([unmarshal/2]).
|
||||
|
@ -2,7 +2,8 @@
|
||||
|
||||
-behaviour(ff_woody_wrapper).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_provider_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_provider_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_thrift.hrl").
|
||||
|
||||
%% ff_woody_wrapper callbacks
|
||||
-export([handle_function/3]).
|
||||
@ -37,11 +38,11 @@ handle_function_('ListProviders', _, _Opts) ->
|
||||
|
||||
%%
|
||||
|
||||
-spec marshal_providers([ff_provider:provider()]) -> [ff_proto_provider_thrift:'Provider'()].
|
||||
-spec marshal_providers([ff_provider:provider()]) -> [fistful_provider_thrift:'Provider'()].
|
||||
marshal_providers(Providers) when is_list(Providers) ->
|
||||
lists:map(fun(Provider) -> marshal_provider(Provider) end, Providers).
|
||||
|
||||
-spec marshal_provider(ff_provider:provider()) -> ff_proto_provider_thrift:'Provider'().
|
||||
-spec marshal_provider(ff_provider:provider()) -> fistful_provider_thrift:'Provider'().
|
||||
marshal_provider(Provider) ->
|
||||
ID = ff_provider:id(Provider),
|
||||
Name = ff_provider:name(Provider),
|
||||
|
@ -2,7 +2,8 @@
|
||||
|
||||
-behaviour(ff_woody_wrapper).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_fistful_admin_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_admin_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_thrift.hrl").
|
||||
|
||||
%% ff_woody_wrapper callbacks
|
||||
-export([handle_function/3]).
|
||||
@ -26,15 +27,15 @@ handle_function(Func, Args, Opts) ->
|
||||
%%
|
||||
|
||||
handle_function_('CreateSource', {Params}, Opts) ->
|
||||
SourceID = Params#ff_admin_SourceParams.id,
|
||||
SourceID = Params#admin_SourceParams.id,
|
||||
case
|
||||
ff_source_machine:create(
|
||||
#{
|
||||
id => SourceID,
|
||||
identity => Params#ff_admin_SourceParams.identity_id,
|
||||
name => Params#ff_admin_SourceParams.name,
|
||||
currency => ff_codec:unmarshal(currency_ref, Params#ff_admin_SourceParams.currency),
|
||||
resource => ff_source_codec:unmarshal(resource, Params#ff_admin_SourceParams.resource)
|
||||
identity => Params#admin_SourceParams.identity_id,
|
||||
name => Params#admin_SourceParams.name,
|
||||
currency => ff_codec:unmarshal(currency_ref, Params#admin_SourceParams.currency),
|
||||
resource => ff_source_codec:unmarshal(resource, Params#admin_SourceParams.resource)
|
||||
},
|
||||
ff_entity_context:new()
|
||||
)
|
||||
@ -57,12 +58,12 @@ handle_function_('GetSource', {ID}, _Opts) ->
|
||||
woody_error:raise(business, #fistful_SourceNotFound{})
|
||||
end;
|
||||
handle_function_('CreateDeposit', {Params}, Opts) ->
|
||||
DepositID = Params#ff_admin_DepositParams.id,
|
||||
DepositID = Params#admin_DepositParams.id,
|
||||
DepositParams = #{
|
||||
id => DepositID,
|
||||
source_id => Params#ff_admin_DepositParams.source,
|
||||
wallet_id => Params#ff_admin_DepositParams.destination,
|
||||
body => ff_codec:unmarshal(cash, Params#ff_admin_DepositParams.body)
|
||||
source_id => Params#admin_DepositParams.source,
|
||||
wallet_id => Params#admin_DepositParams.destination,
|
||||
body => ff_codec:unmarshal(cash, Params#admin_DepositParams.body)
|
||||
},
|
||||
case handle_create_result(ff_deposit_machine:create(DepositParams, ff_entity_context:new())) of
|
||||
ok ->
|
||||
@ -74,11 +75,11 @@ handle_function_('CreateDeposit', {Params}, Opts) ->
|
||||
{error, {wallet, notfound}} ->
|
||||
woody_error:raise(business, #fistful_DestinationNotFound{});
|
||||
{error, {terms_violation, {not_allowed_currency, _More}}} ->
|
||||
woody_error:raise(business, #ff_admin_DepositCurrencyInvalid{});
|
||||
woody_error:raise(business, #admin_DepositCurrencyInvalid{});
|
||||
{error, {inconsistent_currency, _Details}} ->
|
||||
woody_error:raise(business, #ff_admin_DepositCurrencyInvalid{});
|
||||
woody_error:raise(business, #admin_DepositCurrencyInvalid{});
|
||||
{error, {bad_deposit_amount, _Amount}} ->
|
||||
woody_error:raise(business, #ff_admin_DepositAmountInvalid{});
|
||||
woody_error:raise(business, #admin_DepositAmountInvalid{});
|
||||
{error, Error} ->
|
||||
woody_error:raise(system, {internal, result_unexpected, woody_error:format_details(Error)})
|
||||
end;
|
||||
|
@ -16,51 +16,51 @@
|
||||
|
||||
-spec get_service(service_name()) -> service().
|
||||
get_service(fistful_admin) ->
|
||||
{ff_proto_fistful_admin_thrift, 'FistfulAdmin'};
|
||||
{fistful_admin_thrift, 'FistfulAdmin'};
|
||||
get_service(fistful_provider) ->
|
||||
{ff_proto_provider_thrift, 'Management'};
|
||||
{fistful_provider_thrift, 'Management'};
|
||||
get_service(ff_withdrawal_adapter_host) ->
|
||||
{dmsl_withdrawals_provider_adapter_thrift, 'AdapterHost'};
|
||||
{dmsl_wthd_provider_thrift, 'AdapterHost'};
|
||||
get_service(deposit_event_sink) ->
|
||||
{ff_proto_deposit_thrift, 'EventSink'};
|
||||
{fistful_deposit_thrift, 'EventSink'};
|
||||
get_service(source_event_sink) ->
|
||||
{ff_proto_source_thrift, 'EventSink'};
|
||||
{fistful_source_thrift, 'EventSink'};
|
||||
get_service(destination_event_sink) ->
|
||||
{ff_proto_destination_thrift, 'EventSink'};
|
||||
{fistful_destination_thrift, 'EventSink'};
|
||||
get_service(identity_event_sink) ->
|
||||
{ff_proto_identity_thrift, 'EventSink'};
|
||||
{fistful_identity_thrift, 'EventSink'};
|
||||
get_service(wallet_event_sink) ->
|
||||
{ff_proto_wallet_thrift, 'EventSink'};
|
||||
{fistful_wallet_thrift, 'EventSink'};
|
||||
get_service(withdrawal_event_sink) ->
|
||||
{ff_proto_withdrawal_thrift, 'EventSink'};
|
||||
{fistful_wthd_thrift, 'EventSink'};
|
||||
get_service(withdrawal_session_event_sink) ->
|
||||
{ff_proto_withdrawal_session_thrift, 'EventSink'};
|
||||
{fistful_wthd_session_thrift, 'EventSink'};
|
||||
get_service(withdrawal_session_repairer) ->
|
||||
{ff_proto_withdrawal_session_thrift, 'Repairer'};
|
||||
{fistful_wthd_session_thrift, 'Repairer'};
|
||||
get_service(withdrawal_repairer) ->
|
||||
{ff_proto_withdrawal_thrift, 'Repairer'};
|
||||
{fistful_wthd_thrift, 'Repairer'};
|
||||
get_service(deposit_repairer) ->
|
||||
{ff_proto_deposit_thrift, 'Repairer'};
|
||||
{fistful_deposit_thrift, 'Repairer'};
|
||||
get_service(wallet_management) ->
|
||||
{ff_proto_wallet_thrift, 'Management'};
|
||||
{fistful_wallet_thrift, 'Management'};
|
||||
get_service(identity_management) ->
|
||||
{ff_proto_identity_thrift, 'Management'};
|
||||
{fistful_identity_thrift, 'Management'};
|
||||
get_service(destination_management) ->
|
||||
{ff_proto_destination_thrift, 'Management'};
|
||||
{fistful_destination_thrift, 'Management'};
|
||||
get_service(source_management) ->
|
||||
{ff_proto_source_thrift, 'Management'};
|
||||
{fistful_source_thrift, 'Management'};
|
||||
get_service(withdrawal_management) ->
|
||||
{ff_proto_withdrawal_thrift, 'Management'};
|
||||
{fistful_wthd_thrift, 'Management'};
|
||||
get_service(withdrawal_session_management) ->
|
||||
{ff_proto_withdrawal_session_thrift, 'Management'};
|
||||
{fistful_wthd_session_thrift, 'Management'};
|
||||
get_service(deposit_management) ->
|
||||
{ff_proto_deposit_thrift, 'Management'};
|
||||
{fistful_deposit_thrift, 'Management'};
|
||||
get_service(w2w_transfer_event_sink) ->
|
||||
{ff_proto_w2w_transfer_thrift, 'EventSink'};
|
||||
{fistful_w2w_transfer_thrift, 'EventSink'};
|
||||
get_service(w2w_transfer_repairer) ->
|
||||
{ff_proto_w2w_transfer_thrift, 'Repairer'};
|
||||
{fistful_w2w_transfer_thrift, 'Repairer'};
|
||||
get_service(w2w_transfer_management) ->
|
||||
{ff_proto_w2w_transfer_thrift, 'Management'}.
|
||||
{fistful_w2w_transfer_thrift, 'Management'}.
|
||||
|
||||
-spec get_service_spec(service_name()) -> service_spec().
|
||||
get_service_spec(Name) ->
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
-behaviour(ff_codec).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_source_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_source_thrift.hrl").
|
||||
|
||||
-export([unmarshal_source_params/1]).
|
||||
-export([marshal_source_state/2]).
|
||||
@ -13,20 +13,20 @@
|
||||
|
||||
%% API
|
||||
|
||||
-spec unmarshal_source_params(ff_proto_source_thrift:'SourceParams'()) -> ff_source:params().
|
||||
-spec unmarshal_source_params(fistful_source_thrift:'SourceParams'()) -> ff_source:params().
|
||||
unmarshal_source_params(Params) ->
|
||||
genlib_map:compact(#{
|
||||
id => unmarshal(id, Params#src_SourceParams.id),
|
||||
identity => unmarshal(id, Params#src_SourceParams.identity_id),
|
||||
name => unmarshal(string, Params#src_SourceParams.name),
|
||||
currency => unmarshal(currency_ref, Params#src_SourceParams.currency),
|
||||
resource => unmarshal(resource, Params#src_SourceParams.resource),
|
||||
external_id => maybe_unmarshal(id, Params#src_SourceParams.external_id),
|
||||
metadata => maybe_unmarshal(ctx, Params#src_SourceParams.metadata)
|
||||
id => unmarshal(id, Params#source_SourceParams.id),
|
||||
identity => unmarshal(id, Params#source_SourceParams.identity_id),
|
||||
name => unmarshal(string, Params#source_SourceParams.name),
|
||||
currency => unmarshal(currency_ref, Params#source_SourceParams.currency),
|
||||
resource => unmarshal(resource, Params#source_SourceParams.resource),
|
||||
external_id => maybe_unmarshal(id, Params#source_SourceParams.external_id),
|
||||
metadata => maybe_unmarshal(ctx, Params#source_SourceParams.metadata)
|
||||
}).
|
||||
|
||||
-spec marshal_source_state(ff_source:source_state(), ff_entity_context:context()) ->
|
||||
ff_proto_source_thrift:'SourceState'().
|
||||
fistful_source_thrift:'SourceState'().
|
||||
marshal_source_state(SourceState, Context) ->
|
||||
Blocking =
|
||||
case ff_source:is_accessible(SourceState) of
|
||||
@ -35,7 +35,7 @@ marshal_source_state(SourceState, Context) ->
|
||||
_ ->
|
||||
blocked
|
||||
end,
|
||||
#src_SourceState{
|
||||
#source_SourceState{
|
||||
id = maybe_marshal(id, ff_source:id(SourceState)),
|
||||
name = marshal(string, ff_source:name(SourceState)),
|
||||
resource = marshal(resource, ff_source:resource(SourceState)),
|
||||
@ -48,9 +48,9 @@ marshal_source_state(SourceState, Context) ->
|
||||
context = maybe_marshal(ctx, Context)
|
||||
}.
|
||||
|
||||
-spec marshal_event(ff_source_machine:event()) -> ff_proto_source_thrift:'Event'().
|
||||
-spec marshal_event(ff_source_machine:event()) -> fistful_source_thrift:'Event'().
|
||||
marshal_event({EventID, {ev, Timestamp, Change}}) ->
|
||||
#src_Event{
|
||||
#source_Event{
|
||||
event_id = ff_codec:marshal(event_id, EventID),
|
||||
occured_at = ff_codec:marshal(timestamp, Timestamp),
|
||||
change = marshal(change, Change)
|
||||
@ -58,7 +58,7 @@ marshal_event({EventID, {ev, Timestamp, Change}}) ->
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) -> ff_codec:encoded_value().
|
||||
marshal(timestamped_change, {ev, Timestamp, Change}) ->
|
||||
#src_TimestampedChange{
|
||||
#source_TimestampedChange{
|
||||
change = marshal(change, Change),
|
||||
occured_at = ff_codec:marshal(timestamp, Timestamp)
|
||||
};
|
||||
@ -67,7 +67,7 @@ marshal(change, {created, Source}) ->
|
||||
marshal(change, {account, AccountChange}) ->
|
||||
{account, marshal(account_change, AccountChange)};
|
||||
marshal(change, {status_changed, Status}) ->
|
||||
{status, #src_StatusChange{status = marshal(status, Status)}};
|
||||
{status, #source_StatusChange{status = marshal(status, Status)}};
|
||||
marshal(
|
||||
source,
|
||||
Source = #{
|
||||
@ -75,7 +75,7 @@ marshal(
|
||||
resource := Resource
|
||||
}
|
||||
) ->
|
||||
#src_Source{
|
||||
#source_Source{
|
||||
id = marshal(id, ff_source:id(Source)),
|
||||
status = maybe_marshal(status, ff_source:status(Source)),
|
||||
name = marshal(string, Name),
|
||||
@ -88,13 +88,13 @@ marshal(resource, #{type := internal} = Internal) ->
|
||||
{internal, marshal(internal, Internal)};
|
||||
marshal(internal, Internal) ->
|
||||
Details = maps:get(details, Internal, undefined),
|
||||
#src_Internal{
|
||||
#source_Internal{
|
||||
details = marshal(string, Details)
|
||||
};
|
||||
marshal(status, unauthorized) ->
|
||||
{unauthorized, #src_Unauthorized{}};
|
||||
{unauthorized, #source_Unauthorized{}};
|
||||
marshal(status, authorized) ->
|
||||
{authorized, #src_Authorized{}};
|
||||
{authorized, #source_Authorized{}};
|
||||
marshal(ctx, Ctx) ->
|
||||
marshal(context, Ctx);
|
||||
marshal(T, V) ->
|
||||
@ -103,23 +103,23 @@ marshal(T, V) ->
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) -> ff_codec:decoded_value().
|
||||
unmarshal({list, T}, V) ->
|
||||
[unmarshal(T, E) || E <- V];
|
||||
unmarshal(repair_scenario, {add_events, #src_AddEventsRepair{events = Events, action = Action}}) ->
|
||||
unmarshal(repair_scenario, {add_events, #source_AddEventsRepair{events = Events, action = Action}}) ->
|
||||
{add_events,
|
||||
genlib_map:compact(#{
|
||||
events => unmarshal({list, change}, Events),
|
||||
action => maybe_unmarshal(complex_action, Action)
|
||||
})};
|
||||
unmarshal(timestamped_change, TimestampedChange) ->
|
||||
Timestamp = ff_codec:unmarshal(timestamp, TimestampedChange#src_TimestampedChange.occured_at),
|
||||
Change = unmarshal(change, TimestampedChange#src_TimestampedChange.change),
|
||||
Timestamp = ff_codec:unmarshal(timestamp, TimestampedChange#source_TimestampedChange.occured_at),
|
||||
Change = unmarshal(change, TimestampedChange#source_TimestampedChange.change),
|
||||
{ev, Timestamp, Change};
|
||||
unmarshal(change, {created, Source}) ->
|
||||
{created, unmarshal(source, Source)};
|
||||
unmarshal(change, {account, AccountChange}) ->
|
||||
{account, unmarshal(account_change, AccountChange)};
|
||||
unmarshal(change, {status, #src_StatusChange{status = Status}}) ->
|
||||
unmarshal(change, {status, #source_StatusChange{status = Status}}) ->
|
||||
{status_changed, unmarshal(status, Status)};
|
||||
unmarshal(source, #src_Source{
|
||||
unmarshal(source, #source_Source{
|
||||
name = Name,
|
||||
resource = Resource,
|
||||
external_id = ExternalID,
|
||||
@ -134,14 +134,14 @@ unmarshal(source, #src_Source{
|
||||
created_at => maybe_unmarshal(timestamp_ms, CreatedAt),
|
||||
metadata => maybe_unmarshal(context, Metadata)
|
||||
});
|
||||
unmarshal(resource, {internal, #src_Internal{details = Details}}) ->
|
||||
unmarshal(resource, {internal, #source_Internal{details = Details}}) ->
|
||||
genlib_map:compact(#{
|
||||
type => internal,
|
||||
details => unmarshal(string, Details)
|
||||
});
|
||||
unmarshal(status, {unauthorized, #src_Unauthorized{}}) ->
|
||||
unmarshal(status, {unauthorized, #source_Unauthorized{}}) ->
|
||||
unauthorized;
|
||||
unmarshal(status, {authorized, #src_Authorized{}}) ->
|
||||
unmarshal(status, {authorized, #source_Authorized{}}) ->
|
||||
authorized;
|
||||
unmarshal(ctx, Ctx) ->
|
||||
maybe_unmarshal(context, Ctx);
|
||||
|
@ -4,10 +4,10 @@
|
||||
|
||||
-export([publish_events/1]).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_source_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_source_thrift.hrl").
|
||||
|
||||
-type event() :: ff_eventsink_publisher:event(ff_source:event()).
|
||||
-type sinkevent() :: ff_eventsink_publisher:sinkevent(ff_proto_source_thrift:'SinkEvent'()).
|
||||
-type sinkevent() :: ff_eventsink_publisher:sinkevent(fistful_source_thrift:'SinkEvent'()).
|
||||
|
||||
-spec publish_events(list(event())) -> list(sinkevent()).
|
||||
publish_events(Events) ->
|
||||
@ -23,11 +23,11 @@ publish_event(#{
|
||||
{ev, EventDt, Payload}
|
||||
}
|
||||
}) ->
|
||||
#src_SinkEvent{
|
||||
#source_SinkEvent{
|
||||
id = marshal(event_id, ID),
|
||||
created_at = marshal(timestamp, Dt),
|
||||
source = marshal(id, SourceID),
|
||||
payload = #src_EventSinkPayload{
|
||||
payload = #source_EventSinkPayload{
|
||||
sequence = marshal(event_id, EventID),
|
||||
occured_at = marshal(timestamp, EventDt),
|
||||
changes = [marshal(change, Payload)]
|
||||
|
@ -2,7 +2,9 @@
|
||||
|
||||
-behaviour(ff_woody_wrapper).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_source_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_source_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_base_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_thrift.hrl").
|
||||
|
||||
%% ff_woody_wrapper callbacks
|
||||
-export([handle_function/3]).
|
||||
@ -24,7 +26,7 @@ handle_function(Func, Args, Opts) ->
|
||||
%% Internals
|
||||
%%
|
||||
handle_function_('Create', {Params, Ctx}, Opts) ->
|
||||
ID = Params#src_SourceParams.id,
|
||||
ID = Params#source_SourceParams.id,
|
||||
ok = scoper:add_meta(#{id => ID}),
|
||||
case
|
||||
ff_source_machine:create(
|
||||
|
@ -3,7 +3,7 @@
|
||||
%% Storage schema behaviour
|
||||
-behaviour(machinery_mg_schema).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_source_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_source_thrift.hrl").
|
||||
-include_lib("mg_proto/include/mg_proto_state_processing_thrift.hrl").
|
||||
|
||||
-export([get_version/1]).
|
||||
@ -76,13 +76,13 @@ marshal_event(undefined = Version, TimestampedChange, Context) ->
|
||||
machinery_mg_schema_generic:marshal({event, Version}, TimestampedChange, Context);
|
||||
marshal_event(1, TimestampedChange, Context) ->
|
||||
ThriftChange = ff_source_codec:marshal(timestamped_change, TimestampedChange),
|
||||
Type = {struct, struct, {ff_proto_source_thrift, 'TimestampedChange'}},
|
||||
Type = {struct, struct, {fistful_source_thrift, 'TimestampedChange'}},
|
||||
{{bin, ff_proto_utils:serialize(Type, ThriftChange)}, Context}.
|
||||
|
||||
-spec unmarshal_event(machinery_mg_schema:version(), machinery_msgpack:t(), context()) -> {event(), context()}.
|
||||
unmarshal_event(1, EncodedChange, Context) ->
|
||||
{bin, EncodedThriftChange} = EncodedChange,
|
||||
Type = {struct, struct, {ff_proto_source_thrift, 'TimestampedChange'}},
|
||||
Type = {struct, struct, {fistful_source_thrift, 'TimestampedChange'}},
|
||||
ThriftChange = ff_proto_utils:deserialize(Type, EncodedThriftChange),
|
||||
{ff_source_codec:unmarshal(timestamped_change, ThriftChange), Context};
|
||||
unmarshal_event(undefined = Version, EncodedChange, Context0) ->
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
-behaviour(ff_codec).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_w2w_adjustment_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_w2w_adj_thrift.hrl").
|
||||
|
||||
-export([marshal/2]).
|
||||
-export([unmarshal/2]).
|
||||
|
@ -2,7 +2,9 @@
|
||||
|
||||
-behaviour(ff_codec).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_w2w_transfer_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_w2w_transfer_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_w2w_status_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_base_thrift.hrl").
|
||||
|
||||
-export([marshal_w2w_transfer_state/2]).
|
||||
-export([unmarshal_w2w_transfer_params/1]).
|
||||
@ -13,7 +15,7 @@
|
||||
%% API
|
||||
|
||||
-spec marshal_w2w_transfer_state(w2w_transfer:w2w_transfer_state(), ff_entity_context:context()) ->
|
||||
ff_proto_w2w_transfer_thrift:'W2WTransferState'().
|
||||
fistful_w2w_transfer_thrift:'W2WTransferState'().
|
||||
marshal_w2w_transfer_state(W2WTransferState, Ctx) ->
|
||||
CashFlow = w2w_transfer:effective_final_cash_flow(W2WTransferState),
|
||||
Adjustments = w2w_transfer:adjustments(W2WTransferState),
|
||||
@ -33,7 +35,7 @@ marshal_w2w_transfer_state(W2WTransferState, Ctx) ->
|
||||
context = marshal(ctx, Ctx)
|
||||
}.
|
||||
|
||||
-spec unmarshal_w2w_transfer_params(ff_proto_w2w_transfer_thrift:'W2WTransferParams'()) ->
|
||||
-spec unmarshal_w2w_transfer_params(fistful_w2w_transfer_thrift:'W2WTransferParams'()) ->
|
||||
w2w_transfer_machine:params().
|
||||
unmarshal_w2w_transfer_params(#w2w_transfer_W2WTransferParams{
|
||||
id = ID,
|
||||
|
@ -4,13 +4,13 @@
|
||||
|
||||
-export([publish_events/1]).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_w2w_transfer_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/ff_proto_cashflow_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/ff_proto_base_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_w2w_transfer_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_cashflow_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_base_thrift.hrl").
|
||||
-include_lib("mg_proto/include/mg_proto_state_processing_thrift.hrl").
|
||||
|
||||
-type event() :: ff_eventsink_publisher:event(w2w_transfer:event()).
|
||||
-type sinkevent() :: ff_eventsink_publisher:sinkevent(ff_proto_w2w_transfer_thrift:'SinkEvent'()).
|
||||
-type sinkevent() :: ff_eventsink_publisher:sinkevent(fistful_w2w_transfer_thrift:'SinkEvent'()).
|
||||
|
||||
%%
|
||||
%% Internals
|
||||
|
@ -2,8 +2,9 @@
|
||||
|
||||
-behaviour(ff_woody_wrapper).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_w2w_transfer_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/ff_proto_base_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_w2w_transfer_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_base_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_thrift.hrl").
|
||||
|
||||
%% ff_woody_wrapper callbacks
|
||||
-export([handle_function/3]).
|
||||
|
@ -3,7 +3,7 @@
|
||||
%% Storage schema behaviour
|
||||
-behaviour(machinery_mg_schema).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_w2w_transfer_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_w2w_transfer_thrift.hrl").
|
||||
-include_lib("mg_proto/include/mg_proto_state_processing_thrift.hrl").
|
||||
|
||||
-export([get_version/1]).
|
||||
@ -73,13 +73,13 @@ unmarshal(T, V, C) when
|
||||
-spec marshal_event(machinery_mg_schema:version(), event(), context()) -> {machinery_msgpack:t(), context()}.
|
||||
marshal_event(1, TimestampedChange, Context) ->
|
||||
ThriftChange = ff_w2w_transfer_codec:marshal(timestamped_change, TimestampedChange),
|
||||
Type = {struct, struct, {ff_proto_w2w_transfer_thrift, 'TimestampedChange'}},
|
||||
Type = {struct, struct, {fistful_w2w_transfer_thrift, 'TimestampedChange'}},
|
||||
{{bin, ff_proto_utils:serialize(Type, ThriftChange)}, Context}.
|
||||
|
||||
-spec unmarshal_event(machinery_mg_schema:version(), machinery_msgpack:t(), context()) -> {event(), context()}.
|
||||
unmarshal_event(1, EncodedChange, Context) ->
|
||||
{bin, EncodedThriftChange} = EncodedChange,
|
||||
Type = {struct, struct, {ff_proto_w2w_transfer_thrift, 'TimestampedChange'}},
|
||||
Type = {struct, struct, {fistful_w2w_transfer_thrift, 'TimestampedChange'}},
|
||||
ThriftChange = ff_proto_utils:deserialize(Type, EncodedThriftChange),
|
||||
{ff_w2w_transfer_codec:unmarshal(timestamped_change, ThriftChange), Context}.
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
-export([handle_function/3]).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_fistful_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_thrift.hrl").
|
||||
|
||||
-type options() :: undefined.
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
-behaviour(ff_codec).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_w2w_status_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_w2w_status_thrift.hrl").
|
||||
|
||||
-export([marshal/2]).
|
||||
-export([unmarshal/2]).
|
||||
|
@ -2,7 +2,8 @@
|
||||
|
||||
-behaviour(ff_codec).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_wallet_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_wallet_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_account_thrift.hrl").
|
||||
|
||||
-export([marshal_wallet_state/3]).
|
||||
-export([unmarshal_wallet_params/1]).
|
||||
@ -12,9 +13,9 @@
|
||||
|
||||
%% API
|
||||
-spec marshal_wallet_state(ff_wallet:wallet_state(), ff_wallet:id(), ff_entity_context:context()) ->
|
||||
ff_proto_wallet_thrift:'WalletState'().
|
||||
fistful_wallet_thrift:'WalletState'().
|
||||
marshal_wallet_state(WalletState, ID, Context) ->
|
||||
#wlt_WalletState{
|
||||
#wallet_WalletState{
|
||||
id = marshal(id, ID),
|
||||
name = marshal(string, ff_wallet:name(WalletState)),
|
||||
blocking = marshal(blocking, ff_wallet:blocking(WalletState)),
|
||||
@ -25,8 +26,8 @@ marshal_wallet_state(WalletState, ID, Context) ->
|
||||
context = marshal(ctx, Context)
|
||||
}.
|
||||
|
||||
-spec unmarshal_wallet_params(ff_proto_wallet_thrift:'WalletParams'()) -> ff_wallet_machine:params().
|
||||
unmarshal_wallet_params(#wlt_WalletParams{
|
||||
-spec unmarshal_wallet_params(fistful_wallet_thrift:'WalletParams'()) -> ff_wallet_machine:params().
|
||||
unmarshal_wallet_params(#wallet_WalletParams{
|
||||
id = ID,
|
||||
account_params = AccountParams,
|
||||
name = Name,
|
||||
@ -45,7 +46,7 @@ unmarshal_wallet_params(#wlt_WalletParams{
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) -> ff_codec:encoded_value().
|
||||
marshal(timestamped_change, {ev, Timestamp, Change}) ->
|
||||
#wlt_TimestampedChange{
|
||||
#wallet_TimestampedChange{
|
||||
change = marshal(change, Change),
|
||||
occured_at = ff_codec:marshal(timestamp, Timestamp)
|
||||
};
|
||||
@ -54,7 +55,7 @@ marshal(change, {created, Wallet}) ->
|
||||
marshal(change, {account, AccountChange}) ->
|
||||
{account, marshal(account_change, AccountChange)};
|
||||
marshal(wallet, Wallet) ->
|
||||
#wlt_Wallet{
|
||||
#wallet_Wallet{
|
||||
name = marshal(string, maps:get(name, Wallet, <<>>)),
|
||||
blocking = marshal(blocking, maps:get(blocking, Wallet)),
|
||||
external_id = maybe_marshal(id, maps:get(external_id, Wallet, undefined)),
|
||||
@ -78,10 +79,10 @@ marshal(T, V) ->
|
||||
unmarshal({list, T}, V) ->
|
||||
[unmarshal(T, E) || E <- V];
|
||||
unmarshal(timestamped_change, TimestampedChange) ->
|
||||
Timestamp = ff_codec:unmarshal(timestamp, TimestampedChange#wlt_TimestampedChange.occured_at),
|
||||
Change = unmarshal(change, TimestampedChange#wlt_TimestampedChange.change),
|
||||
Timestamp = ff_codec:unmarshal(timestamp, TimestampedChange#wallet_TimestampedChange.occured_at),
|
||||
Change = unmarshal(change, TimestampedChange#wallet_TimestampedChange.change),
|
||||
{ev, Timestamp, Change};
|
||||
unmarshal(repair_scenario, {add_events, #wlt_AddEventsRepair{events = Events, action = Action}}) ->
|
||||
unmarshal(repair_scenario, {add_events, #wallet_AddEventsRepair{events = Events, action = Action}}) ->
|
||||
{add_events,
|
||||
genlib_map:compact(#{
|
||||
events => unmarshal({list, change}, Events),
|
||||
@ -91,7 +92,7 @@ unmarshal(change, {created, Wallet}) ->
|
||||
{created, unmarshal(wallet, Wallet)};
|
||||
unmarshal(change, {account, AccountChange}) ->
|
||||
{account, unmarshal(account_change, AccountChange)};
|
||||
unmarshal(wallet, #wlt_Wallet{
|
||||
unmarshal(wallet, #wallet_Wallet{
|
||||
name = Name,
|
||||
blocking = Blocking,
|
||||
external_id = ExternalID,
|
||||
|
@ -4,10 +4,10 @@
|
||||
|
||||
-export([publish_events/1]).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_wallet_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_wallet_thrift.hrl").
|
||||
|
||||
-type event() :: ff_eventsink_publisher:event(ff_wallet:event()).
|
||||
-type sinkevent() :: ff_eventsink_publisher:sinkevent(ff_proto_wallet_thrift:'SinkEvent'()).
|
||||
-type sinkevent() :: ff_eventsink_publisher:sinkevent(fistful_wallet_thrift:'SinkEvent'()).
|
||||
|
||||
-spec publish_events(list(event())) -> list(sinkevent()).
|
||||
publish_events(Events) ->
|
||||
@ -23,11 +23,11 @@ publish_event(#{
|
||||
{ev, EventDt, Payload}
|
||||
}
|
||||
}) ->
|
||||
#wlt_SinkEvent{
|
||||
#wallet_SinkEvent{
|
||||
id = marshal(event_id, ID),
|
||||
created_at = marshal(timestamp, Dt),
|
||||
source = marshal(id, SourceID),
|
||||
payload = #wlt_Event{
|
||||
payload = #wallet_Event{
|
||||
sequence = marshal(event_id, EventID),
|
||||
occured_at = marshal(timestamp, EventDt),
|
||||
changes = [marshal(change, Payload)]
|
||||
|
@ -2,7 +2,9 @@
|
||||
|
||||
-behaviour(ff_woody_wrapper).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_wallet_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_wallet_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_base_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_thrift.hrl").
|
||||
|
||||
%% ff_woody_wrapper callbacks
|
||||
-export([handle_function/3]).
|
||||
@ -24,7 +26,7 @@ handle_function(Func, Args, Opts) ->
|
||||
%% Internals
|
||||
%%
|
||||
handle_function_('Create', {Params, Context}, Opts) ->
|
||||
WalletID = Params#wlt_WalletParams.id,
|
||||
WalletID = Params#wallet_WalletParams.id,
|
||||
case
|
||||
ff_wallet_machine:create(
|
||||
ff_wallet_codec:unmarshal_wallet_params(Params),
|
||||
|
@ -3,7 +3,7 @@
|
||||
%% Storage schema behaviour
|
||||
-behaviour(machinery_mg_schema).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_wallet_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_wallet_thrift.hrl").
|
||||
-include_lib("mg_proto/include/mg_proto_state_processing_thrift.hrl").
|
||||
|
||||
-export([get_version/1]).
|
||||
@ -75,13 +75,13 @@ marshal_event(undefined = Version, TimestampedChange, Context) ->
|
||||
machinery_mg_schema_generic:marshal({event, Version}, TimestampedChange, Context);
|
||||
marshal_event(1, TimestampedChange, Context) ->
|
||||
ThriftChange = ff_wallet_codec:marshal(timestamped_change, TimestampedChange),
|
||||
Type = {struct, struct, {ff_proto_wallet_thrift, 'TimestampedChange'}},
|
||||
Type = {struct, struct, {fistful_wallet_thrift, 'TimestampedChange'}},
|
||||
{{bin, ff_proto_utils:serialize(Type, ThriftChange)}, Context}.
|
||||
|
||||
-spec unmarshal_event(machinery_mg_schema:version(), machinery_msgpack:t(), context()) -> {event(), context()}.
|
||||
unmarshal_event(1, EncodedChange, Context) ->
|
||||
{bin, EncodedThriftChange} = EncodedChange,
|
||||
Type = {struct, struct, {ff_proto_wallet_thrift, 'TimestampedChange'}},
|
||||
Type = {struct, struct, {fistful_wallet_thrift, 'TimestampedChange'}},
|
||||
ThriftChange = ff_proto_utils:deserialize(Type, EncodedThriftChange),
|
||||
{ff_wallet_codec:unmarshal(timestamped_change, ThriftChange), Context};
|
||||
unmarshal_event(undefined = Version, EncodedChange, Context0) ->
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
-behaviour(ff_woody_wrapper).
|
||||
|
||||
-include_lib("damsel/include/dmsl_withdrawals_provider_adapter_thrift.hrl").
|
||||
-include_lib("damsel/include/dmsl_wthd_provider_thrift.hrl").
|
||||
|
||||
%% Exports
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
|
||||
%% Types
|
||||
|
||||
-type process_callback_result() :: dmsl_withdrawals_provider_adapter_thrift:'ProcessCallbackResult'().
|
||||
-type process_callback_result() :: dmsl_wthd_provider_thrift:'ProcessCallbackResult'().
|
||||
|
||||
%% Handler
|
||||
|
||||
@ -30,7 +30,7 @@ handle_function_('ProcessCallback', {Callback}, _Opts) ->
|
||||
{error, {session_already_finished, Context}} ->
|
||||
{ok, marshal(process_callback_result, {finished, Context})};
|
||||
{error, {unknown_session, _Ref}} ->
|
||||
woody_error:raise(business, #wthadpt_SessionNotFound{})
|
||||
woody_error:raise(business, #wthd_provider_SessionNotFound{})
|
||||
end.
|
||||
|
||||
%%
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
-behaviour(ff_codec).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_withdrawal_adjustment_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_wthd_adj_thrift.hrl").
|
||||
|
||||
-export([marshal/2]).
|
||||
-export([unmarshal/2]).
|
||||
|
@ -2,7 +2,11 @@
|
||||
|
||||
-behaviour(ff_codec).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_withdrawal_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_wthd_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_wthd_status_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_base_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_msgp_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_repairer_thrift.hrl").
|
||||
|
||||
-export([unmarshal_quote_params/1]).
|
||||
|
||||
@ -17,7 +21,7 @@
|
||||
|
||||
%% API
|
||||
|
||||
-spec unmarshal_quote_params(ff_proto_withdrawal_thrift:'QuoteParams'()) -> ff_withdrawal:quote_params().
|
||||
-spec unmarshal_quote_params(fistful_wthd_thrift:'QuoteParams'()) -> ff_withdrawal:quote_params().
|
||||
unmarshal_quote_params(Params) ->
|
||||
genlib_map:compact(#{
|
||||
wallet_id => unmarshal(id, Params#wthd_QuoteParams.wallet_id),
|
||||
@ -28,7 +32,7 @@ unmarshal_quote_params(Params) ->
|
||||
external_id => maybe_unmarshal(id, Params#wthd_QuoteParams.external_id)
|
||||
}).
|
||||
|
||||
-spec marshal_withdrawal_params(ff_withdrawal:params()) -> ff_proto_withdrawal_thrift:'WithdrawalParams'().
|
||||
-spec marshal_withdrawal_params(ff_withdrawal:params()) -> fistful_wthd_thrift:'WithdrawalParams'().
|
||||
marshal_withdrawal_params(Params) ->
|
||||
#wthd_WithdrawalParams{
|
||||
id = marshal(id, maps:get(id, Params)),
|
||||
@ -39,7 +43,7 @@ marshal_withdrawal_params(Params) ->
|
||||
metadata = maybe_marshal(ctx, maps:get(metadata, Params, undefined))
|
||||
}.
|
||||
|
||||
-spec unmarshal_withdrawal_params(ff_proto_withdrawal_thrift:'WithdrawalParams'()) -> ff_withdrawal:params().
|
||||
-spec unmarshal_withdrawal_params(fistful_wthd_thrift:'WithdrawalParams'()) -> ff_withdrawal:params().
|
||||
unmarshal_withdrawal_params(Params) ->
|
||||
genlib_map:compact(#{
|
||||
id => unmarshal(id, Params#wthd_WithdrawalParams.id),
|
||||
@ -52,7 +56,7 @@ unmarshal_withdrawal_params(Params) ->
|
||||
}).
|
||||
|
||||
-spec marshal_withdrawal_state(ff_withdrawal:withdrawal_state(), ff_entity_context:context()) ->
|
||||
ff_proto_withdrawal_thrift:'WithdrawalState'().
|
||||
fistful_wthd_thrift:'WithdrawalState'().
|
||||
marshal_withdrawal_state(WithdrawalState, Context) ->
|
||||
CashFlow = ff_withdrawal:effective_final_cash_flow(WithdrawalState),
|
||||
Adjustments = ff_withdrawal:adjustments(WithdrawalState),
|
||||
@ -77,7 +81,7 @@ marshal_withdrawal_state(WithdrawalState, Context) ->
|
||||
quote = maybe_marshal(quote_state, ff_withdrawal:quote(WithdrawalState))
|
||||
}.
|
||||
|
||||
-spec marshal_event(ff_withdrawal_machine:event()) -> ff_proto_withdrawal_thrift:'Event'().
|
||||
-spec marshal_event(ff_withdrawal_machine:event()) -> fistful_wthd_thrift:'Event'().
|
||||
marshal_event({EventID, {ev, Timestamp, Change}}) ->
|
||||
#wthd_Event{
|
||||
event_id = ff_codec:marshal(event_id, EventID),
|
||||
@ -436,9 +440,9 @@ unmarshal_repair_scenario_test() ->
|
||||
status = {pending, #wthd_status_Pending{}}
|
||||
}}
|
||||
],
|
||||
action = #ff_repairer_ComplexAction{
|
||||
action = #repairer_ComplexAction{
|
||||
timer =
|
||||
{set_timer, #ff_repairer_SetTimerAction{
|
||||
{set_timer, #repairer_SetTimerAction{
|
||||
timer = {timeout, 0}
|
||||
}}
|
||||
}
|
||||
|
@ -4,13 +4,13 @@
|
||||
|
||||
-export([publish_events/1]).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_withdrawal_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/ff_proto_cashflow_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/ff_proto_base_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_wthd_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_cashflow_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_base_thrift.hrl").
|
||||
-include_lib("mg_proto/include/mg_proto_state_processing_thrift.hrl").
|
||||
|
||||
-type event() :: ff_eventsink_publisher:event(ff_withdrawal:event()).
|
||||
-type sinkevent() :: ff_eventsink_publisher:sinkevent(ff_proto_withdrawal_thrift:'SinkEvent'()).
|
||||
-type sinkevent() :: ff_eventsink_publisher:sinkevent(fistful_wthd_thrift:'SinkEvent'()).
|
||||
|
||||
%%
|
||||
%% Internals
|
||||
|
@ -2,7 +2,9 @@
|
||||
|
||||
-behaviour(ff_woody_wrapper).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_withdrawal_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_wthd_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_base_thrift.hrl").
|
||||
|
||||
%% ff_woody_wrapper callbacks
|
||||
-export([handle_function/3]).
|
||||
|
@ -77,13 +77,13 @@ marshal_event(undefined = Version, TimestampedChange, Context) ->
|
||||
machinery_mg_schema_generic:marshal({event, Version}, TimestampedChange, Context);
|
||||
marshal_event(1, TimestampedChange, Context) ->
|
||||
ThriftChange = ff_withdrawal_codec:marshal(timestamped_change, TimestampedChange),
|
||||
Type = {struct, struct, {ff_proto_withdrawal_thrift, 'TimestampedChange'}},
|
||||
Type = {struct, struct, {fistful_wthd_thrift, 'TimestampedChange'}},
|
||||
{{bin, ff_proto_utils:serialize(Type, ThriftChange)}, Context}.
|
||||
|
||||
-spec unmarshal_event(machinery_mg_schema:version(), machinery_msgpack:t(), context()) -> {event(), context()}.
|
||||
unmarshal_event(1, EncodedChange, Context) ->
|
||||
{bin, EncodedThriftChange} = EncodedChange,
|
||||
Type = {struct, struct, {ff_proto_withdrawal_thrift, 'TimestampedChange'}},
|
||||
Type = {struct, struct, {fistful_wthd_thrift, 'TimestampedChange'}},
|
||||
ThriftChange = ff_proto_utils:deserialize(Type, EncodedThriftChange),
|
||||
{ff_withdrawal_codec:unmarshal(timestamped_change, ThriftChange), Context};
|
||||
unmarshal_event(undefined = Version, EncodedChange, Context) ->
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
-export([handle_function/3]).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_fistful_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_thrift.hrl").
|
||||
|
||||
-type options() :: undefined.
|
||||
|
||||
|
@ -2,8 +2,8 @@
|
||||
|
||||
-behaviour(ff_codec).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_withdrawal_session_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/ff_proto_base_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_wthd_session_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_base_thrift.hrl").
|
||||
|
||||
-export([marshal_state/3]).
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
|
||||
%% API
|
||||
-spec marshal_state(ff_withdrawal_session:session_state(), ff_withdrawal_session:id(), ff_entity_context:context()) ->
|
||||
ff_proto_withdrawal_session_thrift:'SessionState'().
|
||||
fistful_wthd_session_thrift:'SessionState'().
|
||||
marshal_state(State, ID, Context) ->
|
||||
#wthd_session_SessionState{
|
||||
id = marshal(id, ID),
|
||||
|
@ -4,13 +4,13 @@
|
||||
|
||||
-export([publish_events/1]).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_withdrawal_session_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_wthd_session_thrift.hrl").
|
||||
-include_lib("mg_proto/include/mg_proto_state_processing_thrift.hrl").
|
||||
|
||||
-type event() :: ff_eventsink_publisher:event(ff_withdrawal_session:event()).
|
||||
-type sinkevent() ::
|
||||
ff_eventsink_publisher:sinkevent(
|
||||
ff_proto_withdrawal_session_thrift:'SinkEvent'()
|
||||
fistful_wthd_session_thrift:'SinkEvent'()
|
||||
).
|
||||
|
||||
%%
|
||||
|
@ -2,7 +2,8 @@
|
||||
|
||||
-behaviour(ff_woody_wrapper).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_withdrawal_session_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_wthd_session_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_thrift.hrl").
|
||||
|
||||
%% ff_woody_wrapper callbacks
|
||||
-export([handle_function/3]).
|
||||
|
@ -3,7 +3,7 @@
|
||||
%% Storage schema behaviour
|
||||
-behaviour(machinery_mg_schema).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_withdrawal_session_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_wthd_session_thrift.hrl").
|
||||
-include_lib("mg_proto/include/mg_proto_state_processing_thrift.hrl").
|
||||
|
||||
-export([get_version/1]).
|
||||
@ -78,13 +78,13 @@ marshal_event(undefined = Version, TimestampedChange, Context) ->
|
||||
machinery_mg_schema_generic:marshal({event, Version}, TimestampedChange, Context);
|
||||
marshal_event(1, TimestampedChange, Context) ->
|
||||
ThriftChange = ff_withdrawal_session_codec:marshal(timestamped_change, TimestampedChange),
|
||||
Type = {struct, struct, {ff_proto_withdrawal_session_thrift, 'TimestampedChange'}},
|
||||
Type = {struct, struct, {fistful_wthd_session_thrift, 'TimestampedChange'}},
|
||||
{{bin, ff_proto_utils:serialize(Type, ThriftChange)}, Context}.
|
||||
|
||||
-spec unmarshal_event(machinery_mg_schema:version(), machinery_msgpack:t(), context()) -> {event(), context()}.
|
||||
unmarshal_event(1, EncodedChange, Context) ->
|
||||
{bin, EncodedThriftChange} = EncodedChange,
|
||||
Type = {struct, struct, {ff_proto_withdrawal_session_thrift, 'TimestampedChange'}},
|
||||
Type = {struct, struct, {fistful_wthd_session_thrift, 'TimestampedChange'}},
|
||||
ThriftChange = ff_proto_utils:deserialize(Type, EncodedThriftChange),
|
||||
{ff_withdrawal_session_codec:unmarshal(timestamped_change, ThriftChange), Context};
|
||||
unmarshal_event(undefined = Version, EncodedChange, Context0) ->
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
-export([handle_function/3]).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_fistful_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_thrift.hrl").
|
||||
|
||||
-type options() :: undefined.
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
-behaviour(ff_codec).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_withdrawal_status_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_wthd_status_thrift.hrl").
|
||||
|
||||
-export([marshal/2]).
|
||||
-export([unmarshal/2]).
|
||||
|
@ -2,7 +2,15 @@
|
||||
|
||||
-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("fistful_proto/include/fistful_cashflow_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_deposit_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_deposit_revert_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_deposit_revert_status_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_deposit_revert_adj_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_deposit_status_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_deposit_adj_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_base_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_thrift.hrl").
|
||||
|
||||
%% Common test API
|
||||
|
||||
@ -265,34 +273,34 @@ create_adjustment_ok_test(C) ->
|
||||
} = prepare_standard_environment_with_deposit(C),
|
||||
AdjustmentID = generate_id(),
|
||||
ExternalID = generate_id(),
|
||||
Params = #dep_adj_AdjustmentParams{
|
||||
Params = #deposit_adj_AdjustmentParams{
|
||||
id = AdjustmentID,
|
||||
change =
|
||||
{change_status, #dep_adj_ChangeStatusRequest{
|
||||
new_status = {failed, #dep_status_Failed{failure = #'fistful_base_Failure'{code = <<"Ooops">>}}}
|
||||
{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#dep_adj_AdjustmentState.id),
|
||||
?assertEqual(ExternalID, AdjustmentState#dep_adj_AdjustmentState.external_id),
|
||||
?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#dep_adj_AdjustmentState.created_at)
|
||||
ff_codec:unmarshal(timestamp_ms, AdjustmentState#deposit_adj_AdjustmentState.created_at)
|
||||
),
|
||||
?assertEqual(
|
||||
ff_adjustment:domain_revision(ExpectedAdjustment),
|
||||
AdjustmentState#dep_adj_AdjustmentState.domain_revision
|
||||
AdjustmentState#deposit_adj_AdjustmentState.domain_revision
|
||||
),
|
||||
?assertEqual(
|
||||
ff_adjustment:party_revision(ExpectedAdjustment),
|
||||
AdjustmentState#dep_adj_AdjustmentState.party_revision
|
||||
AdjustmentState#deposit_adj_AdjustmentState.party_revision
|
||||
),
|
||||
?assertEqual(
|
||||
ff_deposit_adjustment_codec:marshal(changes_plan, ff_adjustment:changes_plan(ExpectedAdjustment)),
|
||||
AdjustmentState#dep_adj_AdjustmentState.changes_plan
|
||||
AdjustmentState#deposit_adj_AdjustmentState.changes_plan
|
||||
).
|
||||
|
||||
-spec create_adjustment_unavailable_status_error_test(config()) -> test_return().
|
||||
@ -300,16 +308,16 @@ create_adjustment_unavailable_status_error_test(C) ->
|
||||
#{
|
||||
deposit_id := DepositID
|
||||
} = prepare_standard_environment_with_deposit(C),
|
||||
Params = #dep_adj_AdjustmentParams{
|
||||
Params = #deposit_adj_AdjustmentParams{
|
||||
id = generate_id(),
|
||||
change =
|
||||
{change_status, #dep_adj_ChangeStatusRequest{
|
||||
new_status = {pending, #dep_status_Pending{}}
|
||||
{change_status, #deposit_adj_ChangeStatusRequest{
|
||||
new_status = {pending, #deposit_status_Pending{}}
|
||||
}}
|
||||
},
|
||||
Result = call_deposit('CreateAdjustment', {DepositID, Params}),
|
||||
ExpectedError = #deposit_ForbiddenStatusChange{
|
||||
target_status = {pending, #dep_status_Pending{}}
|
||||
target_status = {pending, #deposit_status_Pending{}}
|
||||
},
|
||||
?assertEqual({exception, ExpectedError}, Result).
|
||||
|
||||
@ -318,16 +326,16 @@ create_adjustment_already_has_status_error_test(C) ->
|
||||
#{
|
||||
deposit_id := DepositID
|
||||
} = prepare_standard_environment_with_deposit(C),
|
||||
Params = #dep_adj_AdjustmentParams{
|
||||
Params = #deposit_adj_AdjustmentParams{
|
||||
id = generate_id(),
|
||||
change =
|
||||
{change_status, #dep_adj_ChangeStatusRequest{
|
||||
new_status = {succeeded, #dep_status_Succeeded{}}
|
||||
{change_status, #deposit_adj_ChangeStatusRequest{
|
||||
new_status = {succeeded, #deposit_status_Succeeded{}}
|
||||
}}
|
||||
},
|
||||
Result = call_deposit('CreateAdjustment', {DepositID, Params}),
|
||||
ExpectedError = #deposit_AlreadyHasStatus{
|
||||
deposit_status = {succeeded, #dep_status_Succeeded{}}
|
||||
deposit_status = {succeeded, #deposit_status_Succeeded{}}
|
||||
},
|
||||
?assertEqual({exception, ExpectedError}, Result).
|
||||
|
||||
@ -438,34 +446,35 @@ create_revert_adjustment_ok_test(C) ->
|
||||
} = prepare_standard_environment_with_revert(C),
|
||||
AdjustmentID = generate_id(),
|
||||
ExternalID = generate_id(),
|
||||
Params = #dep_rev_adj_AdjustmentParams{
|
||||
Params = #deposit_revert_adj_AdjustmentParams{
|
||||
id = AdjustmentID,
|
||||
change =
|
||||
{change_status, #dep_rev_adj_ChangeStatusRequest{
|
||||
new_status = {failed, #dep_rev_status_Failed{failure = #'fistful_base_Failure'{code = <<"Ooops">>}}}
|
||||
{change_status, #deposit_revert_adj_ChangeStatusRequest{
|
||||
new_status =
|
||||
{failed, #deposit_revert_status_Failed{failure = #'fistful_base_Failure'{code = <<"Ooops">>}}}
|
||||
}},
|
||||
external_id = ExternalID
|
||||
},
|
||||
{ok, AdjustmentState} = call_deposit('CreateRevertAdjustment', {DepositID, RevertID, Params}),
|
||||
ExpectedAdjustment = get_revert_adjustment(DepositID, RevertID, AdjustmentID),
|
||||
|
||||
?assertEqual(AdjustmentID, AdjustmentState#dep_rev_adj_AdjustmentState.id),
|
||||
?assertEqual(ExternalID, AdjustmentState#dep_rev_adj_AdjustmentState.external_id),
|
||||
?assertEqual(AdjustmentID, AdjustmentState#deposit_revert_adj_AdjustmentState.id),
|
||||
?assertEqual(ExternalID, AdjustmentState#deposit_revert_adj_AdjustmentState.external_id),
|
||||
?assertEqual(
|
||||
ff_adjustment:created_at(ExpectedAdjustment),
|
||||
ff_codec:unmarshal(timestamp_ms, AdjustmentState#dep_rev_adj_AdjustmentState.created_at)
|
||||
ff_codec:unmarshal(timestamp_ms, AdjustmentState#deposit_revert_adj_AdjustmentState.created_at)
|
||||
),
|
||||
?assertEqual(
|
||||
ff_adjustment:domain_revision(ExpectedAdjustment),
|
||||
AdjustmentState#dep_rev_adj_AdjustmentState.domain_revision
|
||||
AdjustmentState#deposit_revert_adj_AdjustmentState.domain_revision
|
||||
),
|
||||
?assertEqual(
|
||||
ff_adjustment:party_revision(ExpectedAdjustment),
|
||||
AdjustmentState#dep_rev_adj_AdjustmentState.party_revision
|
||||
AdjustmentState#deposit_revert_adj_AdjustmentState.party_revision
|
||||
),
|
||||
?assertEqual(
|
||||
ff_deposit_revert_adjustment_codec:marshal(changes_plan, ff_adjustment:changes_plan(ExpectedAdjustment)),
|
||||
AdjustmentState#dep_rev_adj_AdjustmentState.changes_plan
|
||||
AdjustmentState#deposit_revert_adj_AdjustmentState.changes_plan
|
||||
).
|
||||
|
||||
-spec create_revert_adjustment_unavailable_status_error_test(config()) -> test_return().
|
||||
@ -474,16 +483,16 @@ create_revert_adjustment_unavailable_status_error_test(C) ->
|
||||
deposit_id := DepositID,
|
||||
revert_id := RevertID
|
||||
} = prepare_standard_environment_with_revert(C),
|
||||
Params = #dep_rev_adj_AdjustmentParams{
|
||||
Params = #deposit_revert_adj_AdjustmentParams{
|
||||
id = generate_id(),
|
||||
change =
|
||||
{change_status, #dep_rev_adj_ChangeStatusRequest{
|
||||
new_status = {pending, #dep_rev_status_Pending{}}
|
||||
{change_status, #deposit_revert_adj_ChangeStatusRequest{
|
||||
new_status = {pending, #deposit_revert_status_Pending{}}
|
||||
}}
|
||||
},
|
||||
Result = call_deposit('CreateRevertAdjustment', {DepositID, RevertID, Params}),
|
||||
ExpectedError = #deposit_ForbiddenRevertStatusChange{
|
||||
target_status = {pending, #dep_rev_status_Pending{}}
|
||||
target_status = {pending, #deposit_revert_status_Pending{}}
|
||||
},
|
||||
?assertEqual({exception, ExpectedError}, Result).
|
||||
|
||||
@ -493,16 +502,16 @@ create_revert_adjustment_already_has_status_error_test(C) ->
|
||||
deposit_id := DepositID,
|
||||
revert_id := RevertID
|
||||
} = prepare_standard_environment_with_revert(C),
|
||||
Params = #dep_rev_adj_AdjustmentParams{
|
||||
Params = #deposit_revert_adj_AdjustmentParams{
|
||||
id = generate_id(),
|
||||
change =
|
||||
{change_status, #dep_rev_adj_ChangeStatusRequest{
|
||||
new_status = {succeeded, #dep_rev_status_Succeeded{}}
|
||||
{change_status, #deposit_revert_adj_ChangeStatusRequest{
|
||||
new_status = {succeeded, #deposit_revert_status_Succeeded{}}
|
||||
}}
|
||||
},
|
||||
Result = call_deposit('CreateRevertAdjustment', {DepositID, RevertID, Params}),
|
||||
ExpectedError = #deposit_RevertAlreadyHasStatus{
|
||||
revert_status = {succeeded, #dep_rev_status_Succeeded{}}
|
||||
revert_status = {succeeded, #deposit_revert_status_Succeeded{}}
|
||||
},
|
||||
?assertEqual({exception, ExpectedError}, Result).
|
||||
|
||||
@ -512,19 +521,20 @@ deposit_state_content_test(C) ->
|
||||
deposit_id := DepositID,
|
||||
revert_id := RevertID
|
||||
} = prepare_standard_environment_with_revert(C),
|
||||
AdjustmentParams = #dep_adj_AdjustmentParams{
|
||||
AdjustmentParams = #deposit_adj_AdjustmentParams{
|
||||
id = generate_id(),
|
||||
change =
|
||||
{change_status, #dep_adj_ChangeStatusRequest{
|
||||
new_status = {failed, #dep_status_Failed{failure = #'fistful_base_Failure'{code = <<"Ooops">>}}}
|
||||
{change_status, #deposit_adj_ChangeStatusRequest{
|
||||
new_status = {failed, #deposit_status_Failed{failure = #'fistful_base_Failure'{code = <<"Ooops">>}}}
|
||||
}}
|
||||
},
|
||||
{ok, _} = call_deposit('CreateAdjustment', {DepositID, AdjustmentParams}),
|
||||
RevertAdjustmentParams = #dep_rev_adj_AdjustmentParams{
|
||||
RevertAdjustmentParams = #deposit_revert_adj_AdjustmentParams{
|
||||
id = generate_id(),
|
||||
change =
|
||||
{change_status, #dep_rev_adj_ChangeStatusRequest{
|
||||
new_status = {failed, #dep_rev_status_Failed{failure = #'fistful_base_Failure'{code = <<"Ooops">>}}}
|
||||
{change_status, #deposit_revert_adj_ChangeStatusRequest{
|
||||
new_status =
|
||||
{failed, #deposit_revert_status_Failed{failure = #'fistful_base_Failure'{code = <<"Ooops">>}}}
|
||||
}}
|
||||
},
|
||||
{ok, _} = call_deposit('CreateRevertAdjustment', {DepositID, RevertID, RevertAdjustmentParams}),
|
||||
|
@ -1,6 +1,9 @@
|
||||
-module(ff_destination_handler_SUITE).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_destination_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_destination_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_base_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_account_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_thrift.hrl").
|
||||
|
||||
-export([all/0]).
|
||||
-export([groups/0]).
|
||||
@ -148,7 +151,7 @@ create_destination_forbidden_withdrawal_method_fail(C) ->
|
||||
IdentityID = create_identity(Party, C),
|
||||
Ctx = ff_entity_context_codec:marshal(#{<<"NS">> => #{}}),
|
||||
Metadata = ff_entity_context_codec:marshal(#{<<"metadata">> => #{<<"some key">> => <<"some data">>}}),
|
||||
Params = #dst_DestinationParams{
|
||||
Params = #destination_DestinationParams{
|
||||
id = ID,
|
||||
identity = IdentityID,
|
||||
name = DstName,
|
||||
@ -172,7 +175,7 @@ create_destination_ok(Resource, C) ->
|
||||
IdentityID = create_identity(Party, C),
|
||||
Ctx = ff_entity_context_codec:marshal(#{<<"NS">> => #{}}),
|
||||
Metadata = ff_entity_context_codec:marshal(#{<<"metadata">> => #{<<"some key">> => <<"some data">>}}),
|
||||
Params = #dst_DestinationParams{
|
||||
Params = #destination_DestinationParams{
|
||||
id = ID,
|
||||
identity = IdentityID,
|
||||
name = DstName,
|
||||
@ -182,31 +185,31 @@ create_destination_ok(Resource, C) ->
|
||||
metadata = Metadata
|
||||
},
|
||||
{ok, Dst} = call_service('Create', {Params, Ctx}),
|
||||
DstName = Dst#dst_DestinationState.name,
|
||||
ID = Dst#dst_DestinationState.id,
|
||||
Resource = Dst#dst_DestinationState.resource,
|
||||
ExternalId = Dst#dst_DestinationState.external_id,
|
||||
Metadata = Dst#dst_DestinationState.metadata,
|
||||
Ctx = Dst#dst_DestinationState.context,
|
||||
DstName = Dst#destination_DestinationState.name,
|
||||
ID = Dst#destination_DestinationState.id,
|
||||
Resource = Dst#destination_DestinationState.resource,
|
||||
ExternalId = Dst#destination_DestinationState.external_id,
|
||||
Metadata = Dst#destination_DestinationState.metadata,
|
||||
Ctx = Dst#destination_DestinationState.context,
|
||||
|
||||
Account = Dst#dst_DestinationState.account,
|
||||
Account = Dst#destination_DestinationState.account,
|
||||
IdentityID = Account#account_Account.identity,
|
||||
#'fistful_base_CurrencyRef'{symbolic_code = Currency} = Account#account_Account.currency,
|
||||
|
||||
{authorized, #dst_Authorized{}} = ct_helper:await(
|
||||
{authorized, #dst_Authorized{}},
|
||||
{authorized, #destination_Authorized{}} = ct_helper:await(
|
||||
{authorized, #destination_Authorized{}},
|
||||
fun() ->
|
||||
{ok, #dst_DestinationState{status = Status}} =
|
||||
{ok, #destination_DestinationState{status = Status}} =
|
||||
call_service('Get', {ID, #'fistful_base_EventRange'{}}),
|
||||
Status
|
||||
end,
|
||||
genlib_retry:linear(15, 1000)
|
||||
),
|
||||
|
||||
{ok, #dst_DestinationState{}} = call_service('Get', {ID, #'fistful_base_EventRange'{}}).
|
||||
{ok, #destination_DestinationState{}} = call_service('Get', {ID, #'fistful_base_EventRange'{}}).
|
||||
|
||||
call_service(Fun, Args) ->
|
||||
Service = {ff_proto_destination_thrift, 'Management'},
|
||||
Service = {fistful_destination_thrift, 'Management'},
|
||||
Request = {Service, Fun, Args},
|
||||
Client = ff_woody_client:new(#{
|
||||
url => <<"http://localhost:8022/v1/destination">>,
|
||||
|
@ -1,6 +1,8 @@
|
||||
-module(ff_eventsink_SUITE).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_withdrawal_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_wthd_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_evsink_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_transfer_thrift.hrl").
|
||||
|
||||
-export([all/0]).
|
||||
-export([groups/0]).
|
||||
|
@ -1,7 +1,9 @@
|
||||
-module(ff_identity_handler_SUITE).
|
||||
|
||||
-include_lib("stdlib/include/assert.hrl").
|
||||
-include_lib("fistful_proto/include/ff_proto_identity_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_identity_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_base_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_thrift.hrl").
|
||||
|
||||
-export([all/0]).
|
||||
-export([init_per_suite/1]).
|
||||
@ -70,19 +72,19 @@ create_identity_ok(_C) ->
|
||||
Ctx = #{<<"NS">> => #{<<"owner">> => PartyID}},
|
||||
Metadata = ff_entity_context_codec:marshal(#{<<"metadata">> => #{<<"some key">> => <<"some data">>}}),
|
||||
Identity0 = create_identity(EID, Name, PartyID, ProvID, Ctx, Metadata),
|
||||
IID = Identity0#idnt_IdentityState.id,
|
||||
IID = Identity0#identity_IdentityState.id,
|
||||
{ok, Identity1} = call_api('Get', {IID, #'fistful_base_EventRange'{}}),
|
||||
|
||||
ProvID = Identity1#idnt_IdentityState.provider_id,
|
||||
IID = Identity1#idnt_IdentityState.id,
|
||||
Name = Identity1#idnt_IdentityState.name,
|
||||
PartyID = Identity1#idnt_IdentityState.party_id,
|
||||
unblocked = Identity1#idnt_IdentityState.blocking,
|
||||
Metadata = Identity1#idnt_IdentityState.metadata,
|
||||
ProvID = Identity1#identity_IdentityState.provider_id,
|
||||
IID = Identity1#identity_IdentityState.id,
|
||||
Name = Identity1#identity_IdentityState.name,
|
||||
PartyID = Identity1#identity_IdentityState.party_id,
|
||||
unblocked = Identity1#identity_IdentityState.blocking,
|
||||
Metadata = Identity1#identity_IdentityState.metadata,
|
||||
Ctx0 = Ctx#{
|
||||
<<"com.rbkmoney.wapi">> => #{<<"name">> => Name}
|
||||
},
|
||||
Ctx0 = ff_entity_context_codec:unmarshal(Identity1#idnt_IdentityState.context),
|
||||
Ctx0 = ff_entity_context_codec:unmarshal(Identity1#identity_IdentityState.context),
|
||||
ok.
|
||||
|
||||
get_event_unknown_identity_ok(_C) ->
|
||||
@ -106,7 +108,7 @@ get_withdrawal_methods_ok(_C) ->
|
||||
Name = <<"Identity Name">>,
|
||||
ProvID = <<"good-one">>,
|
||||
Metadata = ff_entity_context_codec:marshal(#{<<"metadata">> => #{<<"some key">> => <<"some data">>}}),
|
||||
#idnt_IdentityState{id = ID} = create_identity(EID, Name, PID, ProvID, Ctx, Metadata),
|
||||
#identity_IdentityState{id = ID} = create_identity(EID, Name, PID, ProvID, Ctx, Metadata),
|
||||
{ok, [
|
||||
{bank_card, _},
|
||||
{crypto_currency, _},
|
||||
@ -121,7 +123,7 @@ get_withdrawal_methods_ok(_C) ->
|
||||
%%----------
|
||||
|
||||
create_identity(EID, Name, PartyID, ProvID, Ctx, Metadata) ->
|
||||
Params = #idnt_IdentityParams{
|
||||
Params = #identity_IdentityParams{
|
||||
id = genlib:unique(),
|
||||
name = Name,
|
||||
party = PartyID,
|
||||
@ -136,7 +138,7 @@ create_identity(EID, Name, PartyID, ProvID, Ctx, Metadata) ->
|
||||
IdentityState.
|
||||
|
||||
call_api(Fun, Args) ->
|
||||
Service = {ff_proto_identity_thrift, 'Management'},
|
||||
Service = {fistful_identity_thrift, 'Management'},
|
||||
Request = {Service, Fun, Args},
|
||||
Client = ff_woody_client:new(#{
|
||||
url => <<"http://localhost:8022/v1/identity">>,
|
||||
|
@ -1,7 +1,8 @@
|
||||
-module(ff_provider_handler_SUITE).
|
||||
|
||||
-include_lib("stdlib/include/assert.hrl").
|
||||
-include_lib("fistful_proto/include/ff_proto_provider_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_provider_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_thrift.hrl").
|
||||
|
||||
-export([all/0]).
|
||||
-export([groups/0]).
|
||||
|
@ -1,7 +1,10 @@
|
||||
-module(ff_source_handler_SUITE).
|
||||
|
||||
-include_lib("stdlib/include/assert.hrl").
|
||||
-include_lib("fistful_proto/include/ff_proto_source_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_source_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_account_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_base_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_thrift.hrl").
|
||||
|
||||
-export([all/0]).
|
||||
-export([groups/0]).
|
||||
@ -76,27 +79,27 @@ end_per_testcase(_Name, _C) ->
|
||||
-spec get_source_events_ok_test(config()) -> test_return().
|
||||
get_source_events_ok_test(C) ->
|
||||
Resource =
|
||||
{internal, #src_Internal{
|
||||
{internal, #source_Internal{
|
||||
details = <<"details">>
|
||||
}},
|
||||
State = create_source_ok(Resource, C),
|
||||
ID = State#src_SourceState.id,
|
||||
ID = State#source_SourceState.id,
|
||||
{ok, [_Event | _Rest]} = call_service('GetEvents', {ID, #'fistful_base_EventRange'{}}).
|
||||
|
||||
-spec get_source_context_ok_test(config()) -> test_return().
|
||||
get_source_context_ok_test(C) ->
|
||||
Resource =
|
||||
{internal, #src_Internal{
|
||||
{internal, #source_Internal{
|
||||
details = <<"details">>
|
||||
}},
|
||||
State = create_source_ok(Resource, C),
|
||||
ID = State#src_SourceState.id,
|
||||
ID = State#source_SourceState.id,
|
||||
{ok, _Context} = call_service('GetContext', {ID}).
|
||||
|
||||
-spec create_source_ok_test(config()) -> test_return().
|
||||
create_source_ok_test(C) ->
|
||||
Resource =
|
||||
{internal, #src_Internal{
|
||||
{internal, #source_Internal{
|
||||
details = <<"details">>
|
||||
}},
|
||||
create_source_ok(Resource, C).
|
||||
@ -121,7 +124,7 @@ create_source_ok(Resource, C) ->
|
||||
IdentityID = create_identity(Party, C),
|
||||
Ctx = ff_entity_context_codec:marshal(#{<<"NS">> => #{}}),
|
||||
Metadata = ff_entity_context_codec:marshal(#{<<"metadata">> => #{<<"some key">> => <<"some data">>}}),
|
||||
Params = #src_SourceParams{
|
||||
Params = #source_SourceParams{
|
||||
id = ID,
|
||||
identity_id = IdentityID,
|
||||
name = Name,
|
||||
@ -131,34 +134,34 @@ create_source_ok(Resource, C) ->
|
||||
metadata = Metadata
|
||||
},
|
||||
{ok, Src} = call_service('Create', {Params, Ctx}),
|
||||
Name = Src#src_SourceState.name,
|
||||
ID = Src#src_SourceState.id,
|
||||
Resource = Src#src_SourceState.resource,
|
||||
ExternalId = Src#src_SourceState.external_id,
|
||||
Metadata = Src#src_SourceState.metadata,
|
||||
Ctx = Src#src_SourceState.context,
|
||||
Name = Src#source_SourceState.name,
|
||||
ID = Src#source_SourceState.id,
|
||||
Resource = Src#source_SourceState.resource,
|
||||
ExternalId = Src#source_SourceState.external_id,
|
||||
Metadata = Src#source_SourceState.metadata,
|
||||
Ctx = Src#source_SourceState.context,
|
||||
|
||||
Account = Src#src_SourceState.account,
|
||||
Account = Src#source_SourceState.account,
|
||||
IdentityID = Account#account_Account.identity,
|
||||
#'fistful_base_CurrencyRef'{symbolic_code = Currency} = Account#account_Account.currency,
|
||||
|
||||
{unauthorized, #src_Unauthorized{}} = Src#src_SourceState.status,
|
||||
{unauthorized, #source_Unauthorized{}} = Src#source_SourceState.status,
|
||||
|
||||
{authorized, #src_Authorized{}} = ct_helper:await(
|
||||
{authorized, #src_Authorized{}},
|
||||
{authorized, #source_Authorized{}} = ct_helper:await(
|
||||
{authorized, #source_Authorized{}},
|
||||
fun() ->
|
||||
{ok, #src_SourceState{status = Status}} =
|
||||
{ok, #source_SourceState{status = Status}} =
|
||||
call_service('Get', {ID, #'fistful_base_EventRange'{}}),
|
||||
Status
|
||||
end,
|
||||
genlib_retry:linear(15, 1000)
|
||||
),
|
||||
|
||||
{ok, #src_SourceState{} = State} = call_service('Get', {ID, #'fistful_base_EventRange'{}}),
|
||||
{ok, #source_SourceState{} = State} = call_service('Get', {ID, #'fistful_base_EventRange'{}}),
|
||||
State.
|
||||
|
||||
call_service(Fun, Args) ->
|
||||
Service = {ff_proto_source_thrift, 'Management'},
|
||||
Service = {fistful_source_thrift, 'Management'},
|
||||
Request = {Service, Fun, Args},
|
||||
Client = ff_woody_client:new(#{
|
||||
url => <<"http://localhost:8022/v1/source">>,
|
||||
|
@ -1,7 +1,11 @@
|
||||
-module(ff_w2w_transfer_handler_SUITE).
|
||||
|
||||
-include_lib("stdlib/include/assert.hrl").
|
||||
-include_lib("fistful_proto/include/ff_proto_w2w_transfer_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_w2w_transfer_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_w2w_adj_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_w2w_status_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_base_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_thrift.hrl").
|
||||
|
||||
-export([all/0]).
|
||||
-export([groups/0]).
|
||||
|
@ -1,8 +1,10 @@
|
||||
-module(ff_wallet_handler_SUITE).
|
||||
|
||||
-include_lib("stdlib/include/assert.hrl").
|
||||
-include_lib("fistful_proto/include/ff_proto_wallet_thrift.hrl").
|
||||
-include_lib("damsel/include/dmsl_payment_processing_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_wallet_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_base_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_account_thrift.hrl").
|
||||
|
||||
-export([all/0]).
|
||||
-export([groups/0]).
|
||||
@ -97,14 +99,14 @@ create_ok(C) ->
|
||||
CreateResult = call_service('Create', {Params, Ctx}),
|
||||
GetResult = call_service('Get', {ID, #'fistful_base_EventRange'{}}),
|
||||
{ok, Wallet} = GetResult,
|
||||
Account = Wallet#wlt_WalletState.account,
|
||||
Account = Wallet#wallet_WalletState.account,
|
||||
CurrencyRef = Account#account_Account.currency,
|
||||
?assertMatch(CreateResult, GetResult),
|
||||
?assertMatch(<<"Valet">>, Wallet#wlt_WalletState.name),
|
||||
?assertMatch(unblocked, Wallet#wlt_WalletState.blocking),
|
||||
?assertMatch(ExternalID, Wallet#wlt_WalletState.external_id),
|
||||
?assertMatch(Metadata, Wallet#wlt_WalletState.metadata),
|
||||
?assertMatch(Ctx, Wallet#wlt_WalletState.context),
|
||||
?assertMatch(<<"Valet">>, Wallet#wallet_WalletState.name),
|
||||
?assertMatch(unblocked, Wallet#wallet_WalletState.blocking),
|
||||
?assertMatch(ExternalID, Wallet#wallet_WalletState.external_id),
|
||||
?assertMatch(Metadata, Wallet#wallet_WalletState.metadata),
|
||||
?assertMatch(Ctx, Wallet#wallet_WalletState.context),
|
||||
?assertMatch(IdentityID, Account#account_Account.identity),
|
||||
?assertMatch(Currency, CurrencyRef#'fistful_base_CurrencyRef'.symbolic_code).
|
||||
|
||||
@ -156,10 +158,10 @@ get_account_balance(C) ->
|
||||
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,
|
||||
WalletID = Wallet#wallet_WalletState.id,
|
||||
{ok, AccountBalance} = call_service('GetAccountBalance', {WalletID}),
|
||||
CurrencyRef = AccountBalance#account_AccountBalance.currency,
|
||||
Account = Wallet#wlt_WalletState.account,
|
||||
Account = Wallet#wallet_WalletState.account,
|
||||
AccountID = Account#account_Account.id,
|
||||
?assertMatch(AccountID, AccountBalance#account_AccountBalance.id),
|
||||
?assertMatch(Currency, CurrencyRef#'fistful_base_CurrencyRef'.symbolic_code),
|
||||
@ -171,7 +173,7 @@ get_account_balance(C) ->
|
||||
%% Internal
|
||||
%%-----------
|
||||
call_service(Fun, Args) ->
|
||||
Service = {ff_proto_wallet_thrift, 'Management'},
|
||||
Service = {fistful_wallet_thrift, 'Management'},
|
||||
Request = {Service, Fun, Args},
|
||||
Client = ff_woody_client:new(#{
|
||||
url => <<"http://localhost:8022/v1/wallet">>,
|
||||
@ -199,21 +201,21 @@ create_identity(Party, Name, ProviderID, _C) ->
|
||||
ID.
|
||||
|
||||
suspend_party(Party, C) ->
|
||||
Service = {dmsl_payment_processing_thrift, 'PartyManagement'},
|
||||
Service = {dmsl_payproc_thrift, 'PartyManagement'},
|
||||
Args = {Party},
|
||||
Request = {Service, 'Suspend', Args},
|
||||
_ = ff_woody_client:call(partymgmt, Request, ct_helper:get_woody_ctx(C)),
|
||||
ok.
|
||||
|
||||
block_party(Party, C) ->
|
||||
Service = {dmsl_payment_processing_thrift, 'PartyManagement'},
|
||||
Service = {dmsl_payproc_thrift, 'PartyManagement'},
|
||||
Args = {Party, <<"BECAUSE">>},
|
||||
Request = {Service, 'Block', Args},
|
||||
_ = ff_woody_client:call(partymgmt, Request, ct_helper:get_woody_ctx(C)),
|
||||
ok.
|
||||
|
||||
construct_wallet_params(ID, IdentityID, Currency) ->
|
||||
#wlt_WalletParams{
|
||||
#wallet_WalletParams{
|
||||
id = ID,
|
||||
name = <<"Valet">>,
|
||||
account_params = #account_AccountParams{
|
||||
@ -223,7 +225,7 @@ construct_wallet_params(ID, IdentityID, Currency) ->
|
||||
}.
|
||||
|
||||
construct_wallet_params(ID, IdentityID, Currency, ExternalID) ->
|
||||
#wlt_WalletParams{
|
||||
#wallet_WalletParams{
|
||||
id = ID,
|
||||
name = <<"Valet">>,
|
||||
external_id = ExternalID,
|
||||
@ -234,7 +236,7 @@ construct_wallet_params(ID, IdentityID, Currency, ExternalID) ->
|
||||
}.
|
||||
|
||||
construct_wallet_params(ID, IdentityID, Currency, ExternalID, Metadata) ->
|
||||
#wlt_WalletParams{
|
||||
#wallet_WalletParams{
|
||||
id = ID,
|
||||
name = <<"Valet">>,
|
||||
external_id = ExternalID,
|
||||
|
@ -2,7 +2,12 @@
|
||||
|
||||
-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("fistful_proto/include/fistful_wthd_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_wthd_adj_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_wthd_status_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_base_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_cashflow_thrift.hrl").
|
||||
|
||||
-export([all/0]).
|
||||
-export([groups/0]).
|
||||
|
@ -1,8 +1,9 @@
|
||||
-module(ff_withdrawal_session_repair_SUITE).
|
||||
|
||||
-include_lib("stdlib/include/assert.hrl").
|
||||
-include_lib("fistful_proto/include/ff_proto_withdrawal_session_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_wthd_session_thrift.hrl").
|
||||
-include_lib("damsel/include/dmsl_domain_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_base_thrift.hrl").
|
||||
|
||||
-export([all/0]).
|
||||
-export([groups/0]).
|
||||
@ -178,7 +179,8 @@ create_failed_session(IdentityID, DestinationID, _C) ->
|
||||
resource => DestinationResource,
|
||||
route => #{
|
||||
version => 1,
|
||||
provider_id => 1
|
||||
provider_id => 1,
|
||||
terminal_id => 1
|
||||
}
|
||||
},
|
||||
ok = ff_withdrawal_session_machine:create(ID, TransferData, SessionParams),
|
||||
@ -191,7 +193,7 @@ get_session_status(ID) ->
|
||||
ff_withdrawal_session:status(Session).
|
||||
|
||||
call_repair(Args) ->
|
||||
Service = {ff_proto_withdrawal_session_thrift, 'Repairer'},
|
||||
Service = {fistful_wthd_session_thrift, 'Repairer'},
|
||||
Request = {Service, 'Repair', Args},
|
||||
Client = ff_woody_client:new(#{
|
||||
url => <<"http://localhost:8022/v1/repair/withdrawal/session">>,
|
||||
|
@ -1,7 +1,7 @@
|
||||
%%% Client for adapter for withdrawal provider
|
||||
-module(ff_adapter_withdrawal).
|
||||
|
||||
-include_lib("damsel/include/dmsl_withdrawals_provider_adapter_thrift.hrl").
|
||||
-include_lib("damsel/include/dmsl_wthd_provider_thrift.hrl").
|
||||
|
||||
%% Accessors
|
||||
|
||||
@ -172,18 +172,18 @@ get_quote(Adapter, Params, AOpt) ->
|
||||
%%
|
||||
|
||||
call(Adapter, Function, Args) ->
|
||||
Request = {{dmsl_withdrawals_provider_adapter_thrift, 'Adapter'}, Function, Args},
|
||||
Request = {{dmsl_wthd_provider_thrift, 'Adapter'}, Function, Args},
|
||||
ff_woody_client:call(Adapter, Request).
|
||||
|
||||
-spec decode_result
|
||||
(dmsl_withdrawals_provider_adapter_thrift:'ProcessResult'()) -> {ok, process_result()};
|
||||
(dmsl_withdrawals_provider_adapter_thrift:'Quote'()) -> {ok, quote()};
|
||||
(dmsl_withdrawals_provider_adapter_thrift:'CallbackResult'()) -> {ok, handle_callback_result()}.
|
||||
decode_result(#wthadpt_ProcessResult{} = ProcessResult) ->
|
||||
(dmsl_wthd_provider_thrift:'ProcessResult'()) -> {ok, process_result()};
|
||||
(dmsl_wthd_provider_thrift:'Quote'()) -> {ok, quote()};
|
||||
(dmsl_wthd_provider_thrift:'CallbackResult'()) -> {ok, handle_callback_result()}.
|
||||
decode_result(#wthd_provider_ProcessResult{} = ProcessResult) ->
|
||||
{ok, unmarshal(process_result, ProcessResult)};
|
||||
decode_result(#wthadpt_Quote{} = Quote) ->
|
||||
decode_result(#wthd_provider_Quote{} = Quote) ->
|
||||
{ok, unmarshal(quote, Quote)};
|
||||
decode_result(#wthadpt_CallbackResult{} = CallbackResult) ->
|
||||
decode_result(#wthd_provider_CallbackResult{} = CallbackResult) ->
|
||||
{ok, unmarshal(callback_result, CallbackResult)}.
|
||||
|
||||
%% @doc
|
||||
@ -199,19 +199,19 @@ decode_result(#wthadpt_CallbackResult{} = CallbackResult) ->
|
||||
%%
|
||||
%% @todo Remove this code when adapter stops set TransactionInfo to field Success.trx_info
|
||||
|
||||
rebind_transaction_info(#wthadpt_ProcessResult{intent = Intent} = Result) ->
|
||||
{NewIntent, TransactionInfo} = extract_transaction_info(Intent, Result#wthadpt_ProcessResult.trx),
|
||||
Result#wthadpt_ProcessResult{intent = NewIntent, trx = TransactionInfo};
|
||||
rebind_transaction_info(#wthadpt_CallbackResult{intent = Intent} = Result) ->
|
||||
{NewIntent, TransactionInfo} = extract_transaction_info(Intent, Result#wthadpt_CallbackResult.trx),
|
||||
Result#wthadpt_CallbackResult{intent = NewIntent, trx = TransactionInfo}.
|
||||
rebind_transaction_info(#wthd_provider_ProcessResult{intent = Intent} = Result) ->
|
||||
{NewIntent, TransactionInfo} = extract_transaction_info(Intent, Result#wthd_provider_ProcessResult.trx),
|
||||
Result#wthd_provider_ProcessResult{intent = NewIntent, trx = TransactionInfo};
|
||||
rebind_transaction_info(#wthd_provider_CallbackResult{intent = Intent} = Result) ->
|
||||
{NewIntent, TransactionInfo} = extract_transaction_info(Intent, Result#wthd_provider_CallbackResult.trx),
|
||||
Result#wthd_provider_CallbackResult{intent = NewIntent, trx = TransactionInfo}.
|
||||
|
||||
extract_transaction_info({finish, #wthadpt_FinishIntent{status = {success, Success}}}, TransactionInfo) ->
|
||||
extract_transaction_info({finish, #wthd_provider_FinishIntent{status = {success, Success}}}, TransactionInfo) ->
|
||||
{
|
||||
{finish, #wthadpt_FinishIntent{status = {success, #wthadpt_Success{trx_info = undefined}}}},
|
||||
{finish, #wthd_provider_FinishIntent{status = {success, #wthd_provider_Success{trx_info = undefined}}}},
|
||||
case Success of
|
||||
#wthadpt_Success{trx_info = undefined} -> TransactionInfo;
|
||||
#wthadpt_Success{trx_info = LegacyTransactionInfo} -> LegacyTransactionInfo
|
||||
#wthd_provider_Success{trx_info = undefined} -> TransactionInfo;
|
||||
#wthd_provider_Success{trx_info = LegacyTransactionInfo} -> LegacyTransactionInfo
|
||||
end
|
||||
};
|
||||
extract_transaction_info(Intent, TransactionInfo) ->
|
||||
|
@ -1,7 +1,10 @@
|
||||
-module(ff_adapter_withdrawal_codec).
|
||||
|
||||
-include_lib("damsel/include/dmsl_withdrawals_provider_adapter_thrift.hrl").
|
||||
-include_lib("damsel/include/dmsl_wthd_domain_thrift.hrl").
|
||||
-include_lib("damsel/include/dmsl_wthd_provider_thrift.hrl").
|
||||
-include_lib("damsel/include/dmsl_domain_thrift.hrl").
|
||||
-include_lib("damsel/include/dmsl_base_thrift.hrl").
|
||||
-include_lib("damsel/include/dmsl_msgpack_thrift.hrl").
|
||||
|
||||
-export([marshal/2]).
|
||||
-export([unmarshal/2]).
|
||||
@ -32,12 +35,12 @@ marshal(adapter_state, ASt) ->
|
||||
marshal(body, {Amount, CurrencyID}) ->
|
||||
{ok, Currency} = ff_currency:get(CurrencyID),
|
||||
DomainCurrency = marshal(currency, Currency),
|
||||
#wthadpt_Cash{amount = Amount, currency = DomainCurrency};
|
||||
#wthd_provider_Cash{amount = Amount, currency = DomainCurrency};
|
||||
marshal(callback, #{
|
||||
tag := Tag,
|
||||
payload := Payload
|
||||
}) ->
|
||||
#wthadpt_Callback{
|
||||
#wthd_provider_Callback{
|
||||
tag = Tag,
|
||||
payload = Payload
|
||||
};
|
||||
@ -50,14 +53,14 @@ marshal(
|
||||
) ->
|
||||
NextState = genlib_map:get(next_state, Params),
|
||||
TransactionInfo = genlib_map:get(transaction_info, Params),
|
||||
#wthadpt_CallbackResult{
|
||||
#wthd_provider_CallbackResult{
|
||||
intent = marshal(intent, Intent),
|
||||
response = marshal(callback_response, Response),
|
||||
next_state = maybe_marshal(adapter_state, NextState),
|
||||
trx = maybe_marshal(transaction_info, TransactionInfo)
|
||||
};
|
||||
marshal(callback_response, #{payload := Payload}) ->
|
||||
#wthadpt_CallbackResponse{payload = Payload};
|
||||
#wthd_provider_CallbackResponse{payload = Payload};
|
||||
marshal(currency, #{
|
||||
name := Name,
|
||||
symcode := Symcode,
|
||||
@ -87,8 +90,9 @@ marshal(payment_service, #{id := Ref}) when is_binary(Ref) ->
|
||||
};
|
||||
marshal(identity, Identity) ->
|
||||
% TODO: Add real contact fields
|
||||
#wthdm_Identity{
|
||||
#wthd_domain_Identity{
|
||||
id = maps:get(id, Identity),
|
||||
owner_id = maps:get(owner_id, Identity, undefined),
|
||||
documents = marshal(identity_documents, Identity),
|
||||
contact = [{phone_number, <<"9876543210">>}]
|
||||
};
|
||||
@ -100,27 +104,27 @@ marshal(identity_documents, Identity) ->
|
||||
marshal(challenge_documents, Challenge)
|
||||
end;
|
||||
marshal(intent, {finish, success}) ->
|
||||
{finish, #wthadpt_FinishIntent{
|
||||
status = {success, #wthadpt_Success{}}
|
||||
{finish, #wthd_provider_FinishIntent{
|
||||
status = {success, #wthd_provider_Success{}}
|
||||
}};
|
||||
marshal(intent, {finish, {success, TrxInfo}}) ->
|
||||
{finish, #wthadpt_FinishIntent{
|
||||
{finish, #wthd_provider_FinishIntent{
|
||||
status =
|
||||
{success, #wthadpt_Success{
|
||||
{success, #wthd_provider_Success{
|
||||
trx_info = marshal(transaction_info, TrxInfo)
|
||||
}}
|
||||
}};
|
||||
marshal(intent, {finish, {failed, Failure}}) ->
|
||||
{finish, #wthadpt_FinishIntent{
|
||||
{finish, #wthd_provider_FinishIntent{
|
||||
status = {failure, ff_dmsl_codec:marshal(failure, Failure)}
|
||||
}};
|
||||
marshal(intent, {sleep, V = #{timer := Timer}}) ->
|
||||
{sleep, #wthadpt_SleepIntent{
|
||||
{sleep, #wthd_provider_SleepIntent{
|
||||
timer = ff_codec:marshal(timer, Timer),
|
||||
callback_tag = maps:get(tag, V, undefined)
|
||||
}};
|
||||
marshal(process_callback_result, {succeeded, CallbackResponse}) ->
|
||||
{succeeded, #wthadpt_ProcessCallbackSucceeded{
|
||||
{succeeded, #wthd_provider_ProcessCallbackSucceeded{
|
||||
response = marshal(callback_response, CallbackResponse)
|
||||
}};
|
||||
marshal(
|
||||
@ -131,7 +135,7 @@ marshal(
|
||||
opts := Options
|
||||
}}
|
||||
) ->
|
||||
{finished, #wthadpt_ProcessCallbackFinished{
|
||||
{finished, #wthd_provider_ProcessCallbackFinished{
|
||||
withdrawal = marshal(withdrawal, Withdrawal),
|
||||
state = marshal(adapter_state, AdapterState),
|
||||
opts = Options
|
||||
@ -147,7 +151,7 @@ marshal(
|
||||
ExternalID = maps:get(external_id, Params, undefined),
|
||||
{ok, CurrencyFrom} = ff_currency:get(CurrencyIDFrom),
|
||||
{ok, CurrencyTo} = ff_currency:get(CurrencyIDTo),
|
||||
#wthadpt_GetQuoteParams{
|
||||
#wthd_provider_GetQuoteParams{
|
||||
idempotency_id = ExternalID,
|
||||
currency_from = marshal(currency, CurrencyFrom),
|
||||
currency_to = marshal(currency, CurrencyTo),
|
||||
@ -160,7 +164,7 @@ marshal(quote, #{
|
||||
expires_on := ExpiresOn,
|
||||
quote_data := QuoteData
|
||||
}) ->
|
||||
#wthadpt_Quote{
|
||||
#wthd_provider_Quote{
|
||||
cash_from = marshal(body, CashFrom),
|
||||
cash_to = marshal(body, CashTo),
|
||||
created_at = CreatedAt,
|
||||
@ -232,7 +236,7 @@ marshal(
|
||||
} = Withdrawal
|
||||
) ->
|
||||
SesID = maps:get(session_id, Withdrawal, undefined),
|
||||
#wthadpt_Withdrawal{
|
||||
#wthd_provider_Withdrawal{
|
||||
id = ID,
|
||||
session_id = SesID,
|
||||
body = marshal(body, Cash),
|
||||
@ -245,7 +249,7 @@ marshal(transaction_info, TrxInfo) ->
|
||||
ff_dmsl_codec:marshal(transaction_info, TrxInfo).
|
||||
|
||||
try_encode_proof_document({rus_domestic_passport, Token}, Acc) ->
|
||||
[{rus_domestic_passport, #wthdm_RUSDomesticPassport{token = Token}} | Acc];
|
||||
[{rus_domestic_passport, #wthd_domain_RUSDomesticPassport{token = Token}} | Acc];
|
||||
try_encode_proof_document(_, Acc) ->
|
||||
Acc.
|
||||
|
||||
@ -254,18 +258,18 @@ try_encode_proof_document(_, Acc) ->
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) -> ff_codec:decoded_value().
|
||||
unmarshal(adapter_state, ASt) ->
|
||||
unmarshal_msgpack(ASt);
|
||||
unmarshal(body, #wthadpt_Cash{
|
||||
unmarshal(body, #wthd_provider_Cash{
|
||||
amount = Amount,
|
||||
currency = DomainCurrency
|
||||
}) ->
|
||||
CurrencyID = ff_currency:id(unmarshal(currency, DomainCurrency)),
|
||||
{Amount, CurrencyID};
|
||||
unmarshal(callback, #wthadpt_Callback{
|
||||
unmarshal(callback, #wthd_provider_Callback{
|
||||
tag = Tag,
|
||||
payload = Payload
|
||||
}) ->
|
||||
#{tag => Tag, payload => Payload};
|
||||
unmarshal(process_result, #wthadpt_ProcessResult{
|
||||
unmarshal(process_result, #wthd_provider_ProcessResult{
|
||||
intent = Intent,
|
||||
next_state = NextState,
|
||||
trx = TransactionInfo
|
||||
@ -275,7 +279,7 @@ unmarshal(process_result, #wthadpt_ProcessResult{
|
||||
next_state => maybe_unmarshal(adapter_state, NextState),
|
||||
transaction_info => maybe_unmarshal(transaction_info, TransactionInfo)
|
||||
});
|
||||
unmarshal(callback_result, #wthadpt_CallbackResult{
|
||||
unmarshal(callback_result, #wthd_provider_CallbackResult{
|
||||
intent = Intent,
|
||||
next_state = NextState,
|
||||
response = Response,
|
||||
@ -287,7 +291,7 @@ unmarshal(callback_result, #wthadpt_CallbackResult{
|
||||
next_state => maybe_unmarshal(adapter_state, NextState),
|
||||
transaction_info => maybe_unmarshal(transaction_info, TransactionInfo)
|
||||
});
|
||||
unmarshal(callback_response, #wthadpt_CallbackResponse{payload = Payload}) ->
|
||||
unmarshal(callback_response, #wthd_provider_CallbackResponse{payload = Payload}) ->
|
||||
#{payload => Payload};
|
||||
unmarshal(currency, #domain_Currency{
|
||||
name = Name,
|
||||
@ -316,13 +320,17 @@ unmarshal(identity, _NotImplemented) ->
|
||||
unmarshal(identity_documents, _NotImplemented) ->
|
||||
%@TODO
|
||||
erlang:error(not_implemented);
|
||||
unmarshal(intent, {finish, #wthadpt_FinishIntent{status = {success, #wthadpt_Success{trx_info = undefined}}}}) ->
|
||||
unmarshal(
|
||||
intent, {finish, #wthd_provider_FinishIntent{status = {success, #wthd_provider_Success{trx_info = undefined}}}}
|
||||
) ->
|
||||
{finish, success};
|
||||
unmarshal(intent, {finish, #wthadpt_FinishIntent{status = {success, #wthadpt_Success{trx_info = TrxInfo}}}}) ->
|
||||
unmarshal(
|
||||
intent, {finish, #wthd_provider_FinishIntent{status = {success, #wthd_provider_Success{trx_info = TrxInfo}}}}
|
||||
) ->
|
||||
{finish, {success, unmarshal(transaction_info, TrxInfo)}};
|
||||
unmarshal(intent, {finish, #wthadpt_FinishIntent{status = {failure, Failure}}}) ->
|
||||
unmarshal(intent, {finish, #wthd_provider_FinishIntent{status = {failure, Failure}}}) ->
|
||||
{finish, {failed, ff_dmsl_codec:unmarshal(failure, Failure)}};
|
||||
unmarshal(intent, {sleep, #wthadpt_SleepIntent{timer = Timer, callback_tag = Tag}}) ->
|
||||
unmarshal(intent, {sleep, #wthd_provider_SleepIntent{timer = Timer, callback_tag = Tag}}) ->
|
||||
{sleep,
|
||||
genlib_map:compact(#{
|
||||
timer => ff_codec:unmarshal(timer, Timer),
|
||||
@ -334,7 +342,7 @@ unmarshal(process_callback_result, _NotImplemented) ->
|
||||
unmarshal(quote_params, _NotImplemented) ->
|
||||
%@TODO
|
||||
erlang:error(not_implemented);
|
||||
unmarshal(quote, #wthadpt_Quote{
|
||||
unmarshal(quote, #wthd_provider_Quote{
|
||||
cash_from = CashFrom,
|
||||
cash_to = CashTo,
|
||||
created_at = CreatedAt,
|
||||
|
216
apps/ff_transfer/src/ff_limiter.erl
Normal file
216
apps/ff_transfer/src/ff_limiter.erl
Normal file
@ -0,0 +1,216 @@
|
||||
-module(ff_limiter).
|
||||
|
||||
-include_lib("damsel/include/dmsl_base_thrift.hrl").
|
||||
-include_lib("damsel/include/dmsl_domain_thrift.hrl").
|
||||
-include_lib("damsel/include/dmsl_wthd_domain_thrift.hrl").
|
||||
-include_lib("limiter_proto/include/limproto_limiter_thrift.hrl").
|
||||
-include_lib("limiter_proto/include/limproto_context_withdrawal_thrift.hrl").
|
||||
|
||||
-type turnover_selector() :: dmsl_domain_thrift:'TurnoverLimitSelector'().
|
||||
-type turnover_limit() :: dmsl_domain_thrift:'TurnoverLimit'().
|
||||
-type turnover_limit_upper_boundary() :: dmsl_domain_thrift:'Amount'().
|
||||
-type domain_withdrawal() :: dmsl_wthd_domain_thrift:'Withdrawal'().
|
||||
-type withdrawal() :: ff_withdrawal:withdrawal_state().
|
||||
-type route() :: ff_withdrawal_routing:route().
|
||||
|
||||
-type limit() :: limproto_limiter_thrift:'Limit'().
|
||||
-type limit_id() :: limproto_limiter_thrift:'LimitID'().
|
||||
-type limit_change() :: limproto_limiter_thrift:'LimitChange'().
|
||||
-type limit_amount() :: dmsl_domain_thrift:'Amount'().
|
||||
-type context() :: limproto_limiter_thrift:'LimitContext'().
|
||||
-type clock() :: limproto_limiter_thrift:'Clock'().
|
||||
|
||||
-export([get_turnover_limits/1]).
|
||||
-export([check_limits/2]).
|
||||
-export([marshal_withdrawal/1]).
|
||||
|
||||
-export([hold_withdrawal_limits/3]).
|
||||
-export([commit_withdrawal_limits/3]).
|
||||
-export([rollback_withdrawal_limits/3]).
|
||||
|
||||
-spec get_turnover_limits(turnover_selector() | undefined) -> [turnover_limit()].
|
||||
get_turnover_limits(undefined) ->
|
||||
[];
|
||||
get_turnover_limits({value, Limits}) ->
|
||||
Limits;
|
||||
get_turnover_limits(Ambiguous) ->
|
||||
error({misconfiguration, {'Could not reduce selector to a value', Ambiguous}}).
|
||||
|
||||
-spec check_limits([turnover_limit()], withdrawal()) ->
|
||||
{ok, [limit()]}
|
||||
| {error, {overflow, [{limit_id(), limit_amount(), turnover_limit_upper_boundary()}]}}.
|
||||
check_limits(TurnoverLimits, Withdrawal) ->
|
||||
Context = gen_limit_context(Withdrawal),
|
||||
case lists:foldl(fun(Limit, Acc) -> check_limits_(Limit, Acc, Context) end, {[], []}, TurnoverLimits) of
|
||||
{Limits, ErrorList} when length(ErrorList) =:= 0 ->
|
||||
{ok, Limits};
|
||||
{_, ErrorList} ->
|
||||
{error, {overflow, ErrorList}}
|
||||
end.
|
||||
|
||||
check_limits_(T, {Limits, Errors}, Context) ->
|
||||
#domain_TurnoverLimit{id = LimitID} = T,
|
||||
Clock = get_latest_clock(),
|
||||
Limit = get(LimitID, Clock, Context),
|
||||
#limiter_Limit{
|
||||
amount = LimitAmount
|
||||
} = Limit,
|
||||
UpperBoundary = T#domain_TurnoverLimit.upper_boundary,
|
||||
case LimitAmount =< UpperBoundary of
|
||||
true ->
|
||||
{[Limit | Limits], Errors};
|
||||
false ->
|
||||
{Limits, [{LimitID, LimitAmount, UpperBoundary} | Errors]}
|
||||
end.
|
||||
|
||||
-spec hold_withdrawal_limits([turnover_limit()], route(), withdrawal()) -> ok.
|
||||
hold_withdrawal_limits(TurnoverLimits, Route, Withdrawal) ->
|
||||
IDs = [T#domain_TurnoverLimit.id || T <- TurnoverLimits],
|
||||
LimitChanges = gen_limit_changes(IDs, Route, Withdrawal),
|
||||
Context = gen_limit_context(Withdrawal),
|
||||
hold(LimitChanges, get_latest_clock(), Context).
|
||||
|
||||
-spec commit_withdrawal_limits([turnover_limit()], route(), withdrawal()) -> ok.
|
||||
commit_withdrawal_limits(TurnoverLimits, Route, Withdrawal) ->
|
||||
IDs = [T#domain_TurnoverLimit.id || T <- TurnoverLimits],
|
||||
LimitChanges = gen_limit_changes(IDs, Route, Withdrawal),
|
||||
Context = gen_limit_context(Withdrawal),
|
||||
commit(LimitChanges, get_latest_clock(), Context).
|
||||
|
||||
-spec rollback_withdrawal_limits([turnover_limit()], route(), withdrawal()) -> ok.
|
||||
rollback_withdrawal_limits(TurnoverLimits, Route, Withdrawal) ->
|
||||
IDs = [T#domain_TurnoverLimit.id || T <- TurnoverLimits],
|
||||
LimitChanges = gen_limit_changes(IDs, Route, Withdrawal),
|
||||
Context = gen_limit_context(Withdrawal),
|
||||
rollback(LimitChanges, get_latest_clock(), Context).
|
||||
|
||||
-spec hold([limit_change()], clock(), context()) -> ok.
|
||||
hold(LimitChanges, Clock, Context) ->
|
||||
lists:foreach(
|
||||
fun(LimitChange) ->
|
||||
call_hold(LimitChange, Clock, Context)
|
||||
end,
|
||||
LimitChanges
|
||||
).
|
||||
|
||||
-spec commit([limit_change()], clock(), context()) -> ok.
|
||||
commit(LimitChanges, Clock, Context) ->
|
||||
lists:foreach(
|
||||
fun(LimitChange) ->
|
||||
call_commit(LimitChange, Clock, Context)
|
||||
end,
|
||||
LimitChanges
|
||||
).
|
||||
|
||||
-spec rollback([limit_change()], clock(), context()) -> ok.
|
||||
rollback(LimitChanges, Clock, Context) ->
|
||||
lists:foreach(
|
||||
fun(LimitChange) ->
|
||||
call_rollback(LimitChange, Clock, Context)
|
||||
end,
|
||||
LimitChanges
|
||||
).
|
||||
|
||||
gen_limit_context(Withdrawal) ->
|
||||
MarshaledWithdrawal = marshal_withdrawal(Withdrawal),
|
||||
#limiter_LimitContext{
|
||||
withdrawal_processing = #context_withdrawal_Context{
|
||||
op = {withdrawal, #context_withdrawal_OperationWithdrawal{}},
|
||||
withdrawal = #context_withdrawal_Withdrawal{withdrawal = MarshaledWithdrawal}
|
||||
}
|
||||
}.
|
||||
|
||||
gen_limit_changes(LimitIDs, Route, Withdrawal) ->
|
||||
[
|
||||
#limiter_LimitChange{
|
||||
id = ID,
|
||||
change_id = construct_limit_change_id(ID, Route, Withdrawal)
|
||||
}
|
||||
|| ID <- LimitIDs
|
||||
].
|
||||
|
||||
construct_limit_change_id(LimitID, #{terminal_id := TerminalID, provider_id := ProviderID}, Withdrawal) ->
|
||||
ComplexID = construct_complex_id([
|
||||
LimitID,
|
||||
genlib:to_binary(ProviderID),
|
||||
genlib:to_binary(TerminalID),
|
||||
ff_withdrawal:id(Withdrawal)
|
||||
]),
|
||||
genlib_string:join($., [<<"limiter">>, ComplexID]).
|
||||
|
||||
get_latest_clock() ->
|
||||
{latest, #limiter_LatestClock{}}.
|
||||
|
||||
-spec construct_complex_id([binary()]) -> binary().
|
||||
construct_complex_id(IDs) ->
|
||||
genlib_string:join($., IDs).
|
||||
|
||||
-spec marshal_withdrawal(withdrawal()) -> domain_withdrawal().
|
||||
marshal_withdrawal(Withdrawal) ->
|
||||
#{
|
||||
wallet_id := WalletID,
|
||||
destination_id := DestinationID
|
||||
} = ff_withdrawal:params(Withdrawal),
|
||||
{ok, WalletMachine} = ff_wallet_machine:get(WalletID),
|
||||
Wallet = ff_wallet_machine:wallet(WalletMachine),
|
||||
WalletAccount = ff_wallet:account(Wallet),
|
||||
|
||||
{ok, DestinationMachine} = ff_destination_machine:get(DestinationID),
|
||||
Destination = ff_destination_machine:destination(DestinationMachine),
|
||||
DestinationAccount = ff_destination:account(Destination),
|
||||
|
||||
{ok, SenderSt} = ff_identity_machine:get(ff_account:identity(WalletAccount)),
|
||||
{ok, ReceiverSt} = ff_identity_machine:get(ff_account:identity(DestinationAccount)),
|
||||
SenderIdentity = ff_identity_machine:identity(SenderSt),
|
||||
ReceiverIdentity = ff_identity_machine:identity(ReceiverSt),
|
||||
|
||||
Resource = ff_withdrawal:destination_resource(Withdrawal),
|
||||
MarshaledResource = ff_adapter_withdrawal_codec:marshal(resource, Resource),
|
||||
#wthd_domain_Withdrawal{
|
||||
created_at = ff_codec:marshal(timestamp_ms, ff_withdrawal:created_at(Withdrawal)),
|
||||
body = ff_dmsl_codec:marshal(cash, ff_withdrawal:body(Withdrawal)),
|
||||
destination = MarshaledResource,
|
||||
sender = ff_adapter_withdrawal_codec:marshal(identity, #{
|
||||
id => ff_identity:id(SenderIdentity),
|
||||
owner_id => ff_identity:party(SenderIdentity)
|
||||
}),
|
||||
receiver = ff_adapter_withdrawal_codec:marshal(identity, #{
|
||||
id => ff_identity:id(ReceiverIdentity),
|
||||
owner_id => ff_identity:party(SenderIdentity)
|
||||
})
|
||||
}.
|
||||
|
||||
-spec get(limit_id(), clock(), context()) -> limit() | no_return().
|
||||
get(LimitID, Clock, Context) ->
|
||||
Args = {LimitID, Clock, Context},
|
||||
case call('Get', Args) of
|
||||
{ok, Limit} ->
|
||||
Limit;
|
||||
{exception, #limiter_LimitNotFound{}} ->
|
||||
error({not_found, LimitID});
|
||||
{exception, #base_InvalidRequest{errors = Errors}} ->
|
||||
error({invalid_request, Errors})
|
||||
end.
|
||||
|
||||
-spec call_hold(limit_change(), clock(), context()) -> clock().
|
||||
call_hold(LimitChange, Clock, Context) ->
|
||||
Args = {LimitChange, Clock, Context},
|
||||
{ok, ClockUpdated} = call('Hold', Args),
|
||||
ClockUpdated.
|
||||
|
||||
-spec call_commit(limit_change(), clock(), context()) -> clock().
|
||||
call_commit(LimitChange, Clock, Context) ->
|
||||
Args = {LimitChange, Clock, Context},
|
||||
{ok, ClockUpdated} = call('Commit', Args),
|
||||
ClockUpdated.
|
||||
|
||||
-spec call_rollback(limit_change(), clock(), context()) -> clock().
|
||||
call_rollback(LimitChange, Clock, Context) ->
|
||||
Args = {LimitChange, Clock, Context},
|
||||
{ok, ClockUpdated} = call('Rollback', Args),
|
||||
ClockUpdated.
|
||||
|
||||
call(Func, Args) ->
|
||||
Service = {limproto_limiter_thrift, 'Limiter'},
|
||||
Request = {Service, Func, Args},
|
||||
ff_woody_client:call(limiter, Request).
|
@ -10,7 +10,8 @@
|
||||
machinery,
|
||||
machinery_extra,
|
||||
damsel,
|
||||
fistful
|
||||
fistful,
|
||||
limiter_proto
|
||||
]},
|
||||
{env, []},
|
||||
{modules, []},
|
||||
|
@ -4,8 +4,7 @@
|
||||
|
||||
-module(ff_withdrawal).
|
||||
|
||||
-include_lib("damsel/include/dmsl_payment_processing_thrift.hrl").
|
||||
-include_lib("damsel/include/dmsl_withdrawals_provider_adapter_thrift.hrl").
|
||||
-include_lib("damsel/include/dmsl_domain_thrift.hrl").
|
||||
|
||||
-type id() :: binary().
|
||||
|
||||
@ -211,6 +210,7 @@
|
||||
-export([domain_revision/1]).
|
||||
-export([destination_resource/1]).
|
||||
-export([metadata/1]).
|
||||
-export([params/1]).
|
||||
|
||||
%% API
|
||||
|
||||
@ -300,8 +300,8 @@
|
||||
| limit_check
|
||||
| {fail, fail_type()}
|
||||
| adjustment
|
||||
| rollback_routing
|
||||
% Legacy activity
|
||||
| stop
|
||||
| finish.
|
||||
|
||||
-type fail_type() ::
|
||||
@ -380,6 +380,10 @@ created_at(T) ->
|
||||
metadata(T) ->
|
||||
maps:get(metadata, T, undefined).
|
||||
|
||||
-spec params(withdrawal_state()) -> transfer_params().
|
||||
params(#{params := V}) ->
|
||||
V.
|
||||
|
||||
%% API
|
||||
|
||||
-spec gen(gen_args()) -> withdrawal().
|
||||
@ -596,10 +600,6 @@ do_start_adjustment(Params, Withdrawal) ->
|
||||
update_attempts(Attempts, T) ->
|
||||
maps:put(attempts, Attempts, T).
|
||||
|
||||
-spec params(withdrawal_state()) -> transfer_params().
|
||||
params(#{params := V}) ->
|
||||
V.
|
||||
|
||||
-spec p_transfer(withdrawal_state()) -> p_transfer() | undefined.
|
||||
p_transfer(Withdrawal) ->
|
||||
ff_withdrawal_route_attempt_utils:get_current_p_transfer(attempts(Withdrawal)).
|
||||
@ -708,15 +708,8 @@ do_pending_activity(#{p_transfer := cancelled, session := failed}) ->
|
||||
|
||||
do_finished_activity(#{active_adjustment := true}) ->
|
||||
adjustment;
|
||||
%% Legacy activity. Remove after first deployment
|
||||
do_finished_activity(#{status := {failed, _}, p_transfer := prepared}) ->
|
||||
p_transfer_cancel;
|
||||
do_finished_activity(#{status := succeeded, p_transfer := prepared}) ->
|
||||
p_transfer_commit;
|
||||
do_finished_activity(#{status := succeeded, p_transfer := committed}) ->
|
||||
stop;
|
||||
do_finished_activity(#{status := {failed, _}, p_transfer := cancelled}) ->
|
||||
stop.
|
||||
do_finished_activity(#{status := {failed, _}}) ->
|
||||
rollback_routing.
|
||||
|
||||
-spec do_process_transfer(activity(), withdrawal_state()) -> process_result().
|
||||
do_process_transfer(routing, Withdrawal) ->
|
||||
@ -724,14 +717,17 @@ do_process_transfer(routing, Withdrawal) ->
|
||||
do_process_transfer(p_transfer_start, Withdrawal) ->
|
||||
process_p_transfer_creation(Withdrawal);
|
||||
do_process_transfer(p_transfer_prepare, Withdrawal) ->
|
||||
ok = do_rollback_routing(route(Withdrawal), Withdrawal),
|
||||
Tr = ff_withdrawal_route_attempt_utils:get_current_p_transfer(attempts(Withdrawal)),
|
||||
{ok, Events} = ff_postings_transfer:prepare(Tr),
|
||||
{continue, [{p_transfer, Ev} || Ev <- Events]};
|
||||
do_process_transfer(p_transfer_commit, Withdrawal) ->
|
||||
ok = commit_routes_limits([route(Withdrawal)], Withdrawal),
|
||||
Tr = ff_withdrawal_route_attempt_utils:get_current_p_transfer(attempts(Withdrawal)),
|
||||
{ok, Events} = ff_postings_transfer:commit(Tr),
|
||||
{continue, [{p_transfer, Ev} || Ev <- Events]};
|
||||
do_process_transfer(p_transfer_cancel, Withdrawal) ->
|
||||
ok = rollback_routes_limits([route(Withdrawal)], Withdrawal),
|
||||
Tr = ff_withdrawal_route_attempt_utils:get_current_p_transfer(attempts(Withdrawal)),
|
||||
{ok, Events} = ff_postings_transfer:cancel(Tr),
|
||||
{continue, [{p_transfer, Ev} || Ev <- Events]};
|
||||
@ -747,45 +743,39 @@ do_process_transfer(finish, Withdrawal) ->
|
||||
process_transfer_finish(Withdrawal);
|
||||
do_process_transfer(adjustment, Withdrawal) ->
|
||||
process_adjustment(Withdrawal);
|
||||
do_process_transfer(stop, _Withdrawal) ->
|
||||
{undefined, []}.
|
||||
do_process_transfer(rollback_routing, Withdrawal) ->
|
||||
process_rollback_routing(Withdrawal).
|
||||
|
||||
-spec process_routing(withdrawal_state()) -> process_result().
|
||||
process_routing(Withdrawal) ->
|
||||
case do_process_routing(Withdrawal) of
|
||||
{ok, [Route | _]} ->
|
||||
{ok, [Route | _Rest]} ->
|
||||
{continue, [
|
||||
{route_changed, Route}
|
||||
]};
|
||||
{error, route_not_found} ->
|
||||
process_transfer_fail(route_not_found, Withdrawal);
|
||||
Events = process_transfer_fail(route_not_found, Withdrawal),
|
||||
{continue, Events};
|
||||
{error, {inconsistent_quote_route, _Data} = Reason} ->
|
||||
process_transfer_fail(Reason, Withdrawal)
|
||||
Events = process_transfer_fail(Reason, Withdrawal),
|
||||
{continue, Events}
|
||||
end.
|
||||
|
||||
-spec process_rollback_routing(withdrawal_state()) -> process_result().
|
||||
process_rollback_routing(Withdrawal) ->
|
||||
_ = do_rollback_routing(undefined, Withdrawal),
|
||||
{undefined, []}.
|
||||
|
||||
-spec do_process_routing(withdrawal_state()) -> {ok, [route()]} | {error, Reason} when
|
||||
Reason :: route_not_found | InconsistentQuote,
|
||||
InconsistentQuote :: {inconsistent_quote_route, {provider_id, provider_id()} | {terminal_id, terminal_id()}}.
|
||||
do_process_routing(Withdrawal) ->
|
||||
WalletID = wallet_id(Withdrawal),
|
||||
{ok, Wallet} = get_wallet(WalletID),
|
||||
DomainRevision = operation_domain_revision(Withdrawal),
|
||||
{ok, Destination} = get_destination(destination_id(Withdrawal)),
|
||||
Resource = destination_resource(Withdrawal),
|
||||
Identity = get_wallet_identity(Wallet),
|
||||
PartyID = ff_identity:party(get_wallet_identity(Wallet)),
|
||||
VarsetParams = genlib_map:compact(#{
|
||||
body => body(Withdrawal),
|
||||
wallet_id => WalletID,
|
||||
wallet => Wallet,
|
||||
party_id => PartyID,
|
||||
destination => Destination,
|
||||
resource => Resource
|
||||
}),
|
||||
|
||||
do(fun() ->
|
||||
Varset = build_party_varset(VarsetParams),
|
||||
Routes = unwrap(ff_withdrawal_routing:prepare_routes(Varset, Identity, DomainRevision)),
|
||||
{Varset, Context} = make_routing_varset_and_context(Withdrawal),
|
||||
GatherResult = ff_withdrawal_routing:gather_routes(Varset, Context),
|
||||
FilterResult = ff_withdrawal_routing:filter_limit_overflow_routes(GatherResult, Varset, Context),
|
||||
ff_withdrawal_routing:log_reject_context(FilterResult),
|
||||
Routes = unwrap(ff_withdrawal_routing:routes(FilterResult)),
|
||||
case quote(Withdrawal) of
|
||||
undefined ->
|
||||
Routes;
|
||||
@ -796,6 +786,57 @@ do_process_routing(Withdrawal) ->
|
||||
end
|
||||
end).
|
||||
|
||||
do_rollback_routing(ExcludeRoute, Withdrawal) ->
|
||||
{Varset, Context} = make_routing_varset_and_context(Withdrawal),
|
||||
{ok, Routes} = ff_withdrawal_routing:routes(ff_withdrawal_routing:gather_routes(Varset, Context)),
|
||||
RollbackRoutes =
|
||||
case ExcludeRoute of
|
||||
undefined ->
|
||||
Routes;
|
||||
#{terminal_id := TerminalID} ->
|
||||
lists:filter(
|
||||
fun(#{terminal_id := TID}) ->
|
||||
TerminalID =/= TID
|
||||
end,
|
||||
Routes
|
||||
)
|
||||
end,
|
||||
rollback_routes_limits(RollbackRoutes, Varset, Context).
|
||||
|
||||
rollback_routes_limits(Routes, Withdrawal) ->
|
||||
{Varset, Context} = make_routing_varset_and_context(Withdrawal),
|
||||
rollback_routes_limits(Routes, Varset, Context).
|
||||
|
||||
rollback_routes_limits(Routes, Varset, Context) ->
|
||||
ff_withdrawal_routing:rollback_routes_limits(Routes, Varset, Context).
|
||||
|
||||
commit_routes_limits(Routes, Withdrawal) ->
|
||||
{Varset, Context} = make_routing_varset_and_context(Withdrawal),
|
||||
ff_withdrawal_routing:commit_routes_limits(Routes, Varset, Context).
|
||||
|
||||
make_routing_varset_and_context(Withdrawal) ->
|
||||
DomainRevision = operation_domain_revision(Withdrawal),
|
||||
WalletID = wallet_id(Withdrawal),
|
||||
{ok, Wallet} = get_wallet(WalletID),
|
||||
{ok, Destination} = get_destination(destination_id(Withdrawal)),
|
||||
Resource = destination_resource(Withdrawal),
|
||||
PartyID = ff_identity:party(get_wallet_identity(Wallet)),
|
||||
VarsetParams = genlib_map:compact(#{
|
||||
body => body(Withdrawal),
|
||||
wallet_id => WalletID,
|
||||
wallet => Wallet,
|
||||
party_id => PartyID,
|
||||
destination => Destination,
|
||||
resource => Resource
|
||||
}),
|
||||
Identity = get_wallet_identity(Wallet),
|
||||
Context = #{
|
||||
domain_revision => DomainRevision,
|
||||
identity => Identity,
|
||||
withdrawal => Withdrawal
|
||||
},
|
||||
{build_party_varset(VarsetParams), Context}.
|
||||
|
||||
-spec validate_quote_route(route(), quote_state()) -> {ok, valid} | {error, InconsistentQuote} when
|
||||
InconsistentQuote :: {inconsistent_quote_route, {provider_id, provider_id()} | {terminal_id, terminal_id()}}.
|
||||
validate_quote_route(Route, #{route := QuoteRoute}) ->
|
||||
@ -932,10 +973,10 @@ process_session_sleep(Withdrawal) ->
|
||||
process_transfer_finish(_Withdrawal) ->
|
||||
{undefined, [{status_changed, succeeded}]}.
|
||||
|
||||
-spec process_transfer_fail(fail_type(), withdrawal_state()) -> process_result().
|
||||
-spec process_transfer_fail(fail_type(), withdrawal_state()) -> [event()].
|
||||
process_transfer_fail(FailType, Withdrawal) ->
|
||||
Failure = build_failure(FailType, Withdrawal),
|
||||
{undefined, [{status_changed, {failed, Failure}}]}.
|
||||
[{status_changed, {failed, Failure}}].
|
||||
|
||||
-spec handle_child_result(process_result(), withdrawal_state()) -> process_result().
|
||||
handle_child_result({undefined, Events} = Result, Withdrawal) ->
|
||||
@ -1238,6 +1279,7 @@ get_quote_(Params) ->
|
||||
} = Params,
|
||||
Resource = maps:get(resource, Params, undefined),
|
||||
|
||||
%% TODO: don't apply turnover limits here
|
||||
[Route | _] = unwrap(route, ff_withdrawal_routing:prepare_routes(Varset, Identity, DomainRevision)),
|
||||
{Adapter, AdapterOpts} = ff_withdrawal_session:get_adapter_with_opts(Route),
|
||||
GetQuoteParams = #{
|
||||
@ -1588,7 +1630,8 @@ process_route_change(Withdrawal, Reason) ->
|
||||
{ok, Providers} = do_process_routing(Withdrawal),
|
||||
do_process_route_change(Providers, Withdrawal, Reason);
|
||||
false ->
|
||||
process_transfer_fail(Reason, Withdrawal)
|
||||
Events = process_transfer_fail(Reason, Withdrawal),
|
||||
{undefined, Events}
|
||||
end.
|
||||
|
||||
-spec is_failure_transient(fail_type(), withdrawal_state()) -> boolean().
|
||||
@ -1663,10 +1706,12 @@ do_process_route_change(Routes, Withdrawal, Reason) ->
|
||||
]};
|
||||
{error, route_not_found} ->
|
||||
%% No more routes, return last error
|
||||
process_transfer_fail(Reason, Withdrawal);
|
||||
Events = process_transfer_fail(Reason, Withdrawal),
|
||||
{continue, Events};
|
||||
{error, attempt_limit_exceeded} ->
|
||||
%% Attempt limit exceeded, return last error
|
||||
process_transfer_fail(Reason, Withdrawal)
|
||||
Events = process_transfer_fail(Reason, Withdrawal),
|
||||
{continue, Events}
|
||||
end.
|
||||
|
||||
-spec handle_adjustment_changes(ff_adjustment:changes()) -> [event()].
|
||||
|
@ -2,32 +2,49 @@
|
||||
|
||||
-include_lib("damsel/include/dmsl_domain_thrift.hrl").
|
||||
|
||||
-export([prepare_routes/2]).
|
||||
-export([prepare_routes/3]).
|
||||
-export([gather_routes/2]).
|
||||
-export([filter_limit_overflow_routes/3]).
|
||||
-export([rollback_routes_limits/3]).
|
||||
-export([commit_routes_limits/3]).
|
||||
-export([make_route/2]).
|
||||
-export([get_provider/1]).
|
||||
-export([get_terminal/1]).
|
||||
-export([provision_terms/2]).
|
||||
-export([merge_withdrawal_terms/2]).
|
||||
-export([routes/1]).
|
||||
-export([log_reject_context/1]).
|
||||
|
||||
-import(ff_pipeline, [do/1, unwrap/1]).
|
||||
|
||||
-type route() :: #{
|
||||
version := 1,
|
||||
provider_id := provider_id(),
|
||||
terminal_id => terminal_id(),
|
||||
terminal_id := terminal_id(),
|
||||
provider_id_legacy => provider_id()
|
||||
}.
|
||||
|
||||
-type routing_context() :: #{
|
||||
domain_revision := domain_revision(),
|
||||
identity := identity(),
|
||||
withdrawal => withdrawal()
|
||||
}.
|
||||
|
||||
-type routing_state() :: #{
|
||||
routes := [routing_rule_route()],
|
||||
reject_context := reject_context()
|
||||
}.
|
||||
|
||||
-export_type([route/0]).
|
||||
-export_type([routing_context/0]).
|
||||
|
||||
-type identity() :: ff_identity:identity_state().
|
||||
-type withdrawal() :: ff_withdrawal:withdrawal_state().
|
||||
-type domain_revision() :: ff_domain_config:revision().
|
||||
-type party_varset() :: ff_varset:varset().
|
||||
|
||||
-type provider_ref() :: ff_payouts_provider:provider_ref().
|
||||
-type provider_id() :: ff_payouts_provider:id().
|
||||
|
||||
-type terminal_ref() :: ff_payouts_terminal:terminal_ref().
|
||||
-type terminal_id() :: ff_payouts_terminal:id().
|
||||
|
||||
-type routing_rule_route() :: ff_routing_rule:route().
|
||||
@ -36,27 +53,70 @@
|
||||
-type withdrawal_provision_terms() :: dmsl_domain_thrift:'WithdrawalProvisionTerms'().
|
||||
-type currency_selector() :: dmsl_domain_thrift:'CurrencySelector'().
|
||||
-type cash_limit_selector() :: dmsl_domain_thrift:'CashLimitSelector'().
|
||||
-type turnover_limit_selector() :: dmsl_domain_thrift:'TurnoverLimitSelector'().
|
||||
-type process_route_fun() :: fun(
|
||||
(withdrawal_provision_terms(), party_varset(), route(), routing_context()) ->
|
||||
ok
|
||||
| {ok, valid}
|
||||
| {error, Error :: term()}
|
||||
).
|
||||
|
||||
%%
|
||||
|
||||
-spec prepare_routes(party_varset(), identity(), domain_revision()) -> {ok, [route()]} | {error, route_not_found}.
|
||||
-spec prepare_routes(party_varset(), identity(), domain_revision()) ->
|
||||
{ok, [route()]} | {error, route_not_found}.
|
||||
prepare_routes(PartyVarset, Identity, DomainRevision) ->
|
||||
prepare_routes(PartyVarset, #{identity => Identity, domain_revision => DomainRevision}).
|
||||
|
||||
-spec prepare_routes(party_varset(), routing_context()) ->
|
||||
{ok, [route()]} | {error, route_not_found}.
|
||||
prepare_routes(PartyVarset, Context) ->
|
||||
State = gather_routes(PartyVarset, Context),
|
||||
log_reject_context(State),
|
||||
routes(State).
|
||||
|
||||
-spec gather_routes(party_varset(), routing_context()) ->
|
||||
routing_state().
|
||||
gather_routes(PartyVarset, Context = #{identity := Identity, domain_revision := DomainRevision}) ->
|
||||
{ok, PaymentInstitutionID} = ff_party:get_identity_payment_institution_id(Identity),
|
||||
{ok, PaymentInstitution} = ff_payment_institution:get(PaymentInstitutionID, PartyVarset, DomainRevision),
|
||||
{Routes, RejectContext0} = ff_routing_rule:gather_routes(
|
||||
{Routes, RejectContext} = ff_routing_rule:gather_routes(
|
||||
PaymentInstitution,
|
||||
withdrawal_routing_rules,
|
||||
PartyVarset,
|
||||
DomainRevision
|
||||
),
|
||||
{ValidatedRoutes, RejectContext1} = filter_valid_routes(Routes, RejectContext0, PartyVarset, DomainRevision),
|
||||
case ValidatedRoutes of
|
||||
[_ | _] ->
|
||||
{ok, ValidatedRoutes};
|
||||
[] ->
|
||||
ff_routing_rule:log_reject_context(RejectContext1),
|
||||
{error, route_not_found}
|
||||
end.
|
||||
filter_valid_routes(#{routes => Routes, reject_context => RejectContext}, PartyVarset, Context).
|
||||
|
||||
-spec filter_limit_overflow_routes(routing_state(), party_varset(), routing_context()) ->
|
||||
routing_state().
|
||||
filter_limit_overflow_routes(State, PartyVarset, RoutingContext) ->
|
||||
validate_routes_with(
|
||||
fun do_validate_limits/4,
|
||||
State,
|
||||
PartyVarset,
|
||||
RoutingContext
|
||||
).
|
||||
|
||||
-spec rollback_routes_limits([route()], party_varset(), routing_context()) ->
|
||||
ok.
|
||||
rollback_routes_limits(Routes, PartyVarset, RoutingContext) ->
|
||||
process_routes_with(
|
||||
fun do_rollback_limits/4,
|
||||
Routes,
|
||||
PartyVarset,
|
||||
RoutingContext
|
||||
).
|
||||
|
||||
-spec commit_routes_limits([route()], party_varset(), routing_context()) ->
|
||||
ok.
|
||||
commit_routes_limits(Routes, PartyVarset, RoutingContext) ->
|
||||
process_routes_with(
|
||||
fun do_commit_limits/4,
|
||||
Routes,
|
||||
PartyVarset,
|
||||
RoutingContext
|
||||
).
|
||||
|
||||
-spec make_route(provider_id(), terminal_id() | undefined) -> route().
|
||||
make_route(ProviderID, TerminalID) ->
|
||||
@ -74,21 +134,6 @@ get_provider(#{provider_id := ProviderID}) ->
|
||||
get_terminal(Route) ->
|
||||
maps:get(terminal_id, Route, undefined).
|
||||
|
||||
-spec provision_terms(route(), domain_revision()) -> ff_maybe:maybe(withdrawal_provision_terms()).
|
||||
provision_terms(Route, DomainRevision) ->
|
||||
ProviderID = get_provider(Route),
|
||||
{ok, Provider} = ff_payouts_provider:get(ProviderID, DomainRevision),
|
||||
ProviderTerms = ff_payouts_provider:provision_terms(Provider),
|
||||
TerminalTerms =
|
||||
case get_terminal(Route) of
|
||||
undefined ->
|
||||
undefined;
|
||||
TerminalID ->
|
||||
{ok, Terminal} = ff_payouts_terminal:get(TerminalID, DomainRevision),
|
||||
ff_payouts_terminal:provision_terms(Terminal)
|
||||
end,
|
||||
merge_withdrawal_terms(ProviderTerms, TerminalTerms).
|
||||
|
||||
-spec merge_withdrawal_terms(
|
||||
ff_payouts_provider:provision_terms() | undefined,
|
||||
ff_payouts_terminal:provision_terms() | undefined
|
||||
@ -116,58 +161,138 @@ merge_withdrawal_terms(
|
||||
merge_withdrawal_terms(ProviderTerms, TerminalTerms) ->
|
||||
ff_maybe:get_defined(TerminalTerms, ProviderTerms).
|
||||
|
||||
-spec routes(routing_state()) ->
|
||||
{ok, [route()]} | {error, route_not_found}.
|
||||
routes(#{routes := Routes = [_ | _]}) ->
|
||||
{ok, sort_routes(Routes)};
|
||||
routes(_) ->
|
||||
{error, route_not_found}.
|
||||
|
||||
-spec sort_routes([routing_rule_route()]) -> [route()].
|
||||
sort_routes(RoutingRuleRoutes) ->
|
||||
ProviderTerminalMap = lists:foldl(
|
||||
fun(#{provider_ref := ProviderRef, terminal_ref := TerminalRef, priority := Priority}, Acc0) ->
|
||||
TerminalID = TerminalRef#domain_TerminalRef.id,
|
||||
ProviderID = ProviderRef#domain_ProviderRef.id,
|
||||
Routes = maps:get(Priority, Acc0, []),
|
||||
Acc1 = maps:put(Priority, [{ProviderID, TerminalID} | Routes], Acc0),
|
||||
Acc1
|
||||
end,
|
||||
#{},
|
||||
RoutingRuleRoutes
|
||||
),
|
||||
lists:foldl(
|
||||
fun({_, Data}, Acc) ->
|
||||
SortedRoutes = [make_route(P, T) || {P, T} <- lists:sort(Data)],
|
||||
SortedRoutes ++ Acc
|
||||
end,
|
||||
[],
|
||||
lists:keysort(1, maps:to_list(ProviderTerminalMap))
|
||||
).
|
||||
|
||||
-spec log_reject_context(routing_state()) ->
|
||||
ok.
|
||||
log_reject_context(#{reject_context := RejectContext}) ->
|
||||
ff_routing_rule:log_reject_context(RejectContext).
|
||||
|
||||
%%
|
||||
|
||||
-spec filter_valid_routes([routing_rule_route()], reject_context(), party_varset(), domain_revision()) ->
|
||||
{[route()], reject_context()}.
|
||||
filter_valid_routes(Routes, RejectContext, PartyVarset, DomainRevision) ->
|
||||
filter_valid_routes_(Routes, PartyVarset, {#{}, RejectContext}, DomainRevision).
|
||||
-spec filter_valid_routes(routing_state(), party_varset(), routing_context()) ->
|
||||
routing_state().
|
||||
filter_valid_routes(State, PartyVarset, RoutingContext) ->
|
||||
validate_routes_with(
|
||||
fun do_validate_terms/4,
|
||||
State,
|
||||
PartyVarset,
|
||||
RoutingContext
|
||||
).
|
||||
|
||||
filter_valid_routes_([], _, {Acc, RejectContext}, _DomainRevision) when map_size(Acc) == 0 ->
|
||||
{[], RejectContext};
|
||||
filter_valid_routes_([], _, {Acc, RejectContext}, _DomainRevision) ->
|
||||
{convert_to_route(Acc), RejectContext};
|
||||
filter_valid_routes_([Route | Rest], PartyVarset, {Acc0, RejectContext0}, DomainRevision) ->
|
||||
Terminal = maps:get(terminal, Route),
|
||||
TerminalRef = maps:get(terminal_ref, Route),
|
||||
TerminalID = TerminalRef#domain_TerminalRef.id,
|
||||
ProviderRef = Terminal#domain_Terminal.provider_ref,
|
||||
ProviderID = ProviderRef#domain_ProviderRef.id,
|
||||
Priority = maps:get(priority, Route, undefined),
|
||||
{Acc, RejectContext} =
|
||||
case validate_terms(ProviderRef, TerminalRef, PartyVarset, DomainRevision) of
|
||||
{ok, valid} ->
|
||||
Terms = maps:get(Priority, Acc0, []),
|
||||
Acc1 = maps:put(Priority, [{ProviderID, TerminalID} | Terms], Acc0),
|
||||
{Acc1, RejectContext0};
|
||||
{error, RejectReason} ->
|
||||
RejectedRoutes0 = maps:get(rejected_routes, RejectContext0),
|
||||
RejectedRoutes1 = [{ProviderRef, TerminalRef, RejectReason} | RejectedRoutes0],
|
||||
RejectContext1 = maps:put(rejected_routes, RejectedRoutes1, RejectContext0),
|
||||
{Acc0, RejectContext1}
|
||||
-spec process_routes_with(process_route_fun(), [route()], party_varset(), routing_context()) ->
|
||||
ok.
|
||||
process_routes_with(Func, Routes, PartyVarset, RoutingContext) ->
|
||||
lists:foreach(
|
||||
fun(Route) ->
|
||||
ProviderID = maps:get(provider_id, Route),
|
||||
TerminalID = maps:get(terminal_id, Route),
|
||||
ProviderRef = #domain_ProviderRef{id = ProviderID},
|
||||
TerminalRef = #domain_TerminalRef{id = TerminalID},
|
||||
get_route_terms_and_process(Func, ProviderRef, TerminalRef, PartyVarset, RoutingContext)
|
||||
end,
|
||||
filter_valid_routes_(Rest, PartyVarset, {Acc, RejectContext}, DomainRevision).
|
||||
Routes
|
||||
).
|
||||
|
||||
-spec validate_terms(provider_ref(), terminal_ref(), party_varset(), domain_revision()) ->
|
||||
{ok, valid}
|
||||
| {error, Error :: term()}.
|
||||
validate_terms(ProviderRef, TerminalRef, PartyVarset, DomainRevision) ->
|
||||
-spec validate_routes_with(
|
||||
process_route_fun(), routing_state(), party_varset(), routing_context()
|
||||
) ->
|
||||
routing_state().
|
||||
validate_routes_with(Func, #{routes := Routes, reject_context := RejectContext}, PartyVarset, RoutingContext) ->
|
||||
lists:foldl(
|
||||
fun(Route, State = #{routes := ValidRoutes0, reject_context := RejectContext0}) ->
|
||||
ProviderRef = maps:get(provider_ref, Route),
|
||||
TerminalRef = maps:get(terminal_ref, Route),
|
||||
case get_route_terms_and_process(Func, ProviderRef, TerminalRef, PartyVarset, RoutingContext) of
|
||||
{ok, valid} ->
|
||||
ValidRoutes1 = [Route | ValidRoutes0],
|
||||
State#{routes => ValidRoutes1};
|
||||
{error, RejectReason} ->
|
||||
RejectedRoutes0 = maps:get(rejected_routes, RejectContext0),
|
||||
RejectedRoutes1 = [{ProviderRef, TerminalRef, RejectReason} | RejectedRoutes0],
|
||||
RejectContext1 = maps:put(rejected_routes, RejectedRoutes1, RejectContext0),
|
||||
State#{reject_context => RejectContext1}
|
||||
end
|
||||
end,
|
||||
#{routes => [], reject_context => RejectContext},
|
||||
Routes
|
||||
).
|
||||
|
||||
get_route_terms_and_process(
|
||||
Func, ProviderRef, TerminalRef, PartyVarset, RoutingContext = #{domain_revision := DomainRevision}
|
||||
) ->
|
||||
case ff_party:compute_provider_terminal_terms(ProviderRef, TerminalRef, PartyVarset, DomainRevision) of
|
||||
{ok, #domain_ProvisionTermSet{
|
||||
wallet = #domain_WalletProvisionTerms{
|
||||
withdrawals = WithdrawalProvisionTerms
|
||||
}
|
||||
}} ->
|
||||
do_validate_terms(WithdrawalProvisionTerms, PartyVarset);
|
||||
Route = make_route(ProviderRef#domain_ProviderRef.id, TerminalRef#domain_TerminalRef.id),
|
||||
Func(WithdrawalProvisionTerms, PartyVarset, Route, RoutingContext);
|
||||
{error, Error} ->
|
||||
%% TODO: test for provision_termset_undefined error after routing migration
|
||||
{error, Error}
|
||||
end.
|
||||
|
||||
-spec do_validate_terms(withdrawal_provision_terms(), party_varset()) ->
|
||||
-spec do_rollback_limits(withdrawal_provision_terms(), party_varset(), route(), routing_context()) ->
|
||||
ok.
|
||||
do_rollback_limits(CombinedTerms, _PartyVarset, Route, #{withdrawal := Withdrawal}) ->
|
||||
#domain_WithdrawalProvisionTerms{
|
||||
turnover_limit = TurnoverLimit
|
||||
} = CombinedTerms,
|
||||
Limits = ff_limiter:get_turnover_limits(TurnoverLimit),
|
||||
ff_limiter:rollback_withdrawal_limits(Limits, Route, Withdrawal).
|
||||
|
||||
-spec do_commit_limits(withdrawal_provision_terms(), party_varset(), route(), routing_context()) ->
|
||||
ok.
|
||||
do_commit_limits(CombinedTerms, _PartyVarset, Route, #{withdrawal := Withdrawal}) ->
|
||||
#domain_WithdrawalProvisionTerms{
|
||||
turnover_limit = TurnoverLimit
|
||||
} = CombinedTerms,
|
||||
Limits = ff_limiter:get_turnover_limits(TurnoverLimit),
|
||||
ff_limiter:commit_withdrawal_limits(Limits, Route, Withdrawal).
|
||||
|
||||
-spec do_validate_limits(withdrawal_provision_terms(), party_varset(), route(), routing_context()) ->
|
||||
{ok, valid}
|
||||
| {error, Error :: term()}.
|
||||
do_validate_terms(CombinedTerms, PartyVarset) ->
|
||||
do_validate_limits(CombinedTerms, PartyVarset, Route, RoutingContext) ->
|
||||
do(fun() ->
|
||||
#domain_WithdrawalProvisionTerms{
|
||||
turnover_limit = TurnoverLimits
|
||||
} = CombinedTerms,
|
||||
valid = unwrap(validate_turnover_limits(TurnoverLimits, PartyVarset, Route, RoutingContext))
|
||||
end).
|
||||
|
||||
-spec do_validate_terms(withdrawal_provision_terms(), party_varset(), route(), routing_context()) ->
|
||||
{ok, valid}
|
||||
| {error, Error :: term()}.
|
||||
do_validate_terms(CombinedTerms, PartyVarset, _Route, _RoutingContext) ->
|
||||
do(fun() ->
|
||||
#domain_WithdrawalProvisionTerms{
|
||||
currencies = CurrenciesSelector,
|
||||
@ -224,15 +349,21 @@ validate_cash_limit({value, CashRange}, #{cost := Cash}) ->
|
||||
validate_cash_limit(_NotReducedSelector, _VS) ->
|
||||
{error, {misconfiguration, {not_reduced_termset, cash_range}}}.
|
||||
|
||||
convert_to_route(ProviderTerminalMap) ->
|
||||
lists:foldl(
|
||||
fun({_, Data}, Acc) ->
|
||||
SortedRoutes = [make_route(P, T) || {P, T} <- lists:sort(Data)],
|
||||
SortedRoutes ++ Acc
|
||||
end,
|
||||
[],
|
||||
lists:keysort(1, maps:to_list(ProviderTerminalMap))
|
||||
).
|
||||
-spec validate_turnover_limits(turnover_limit_selector(), party_varset(), route(), routing_context()) ->
|
||||
{ok, valid}
|
||||
| {error, Error :: term()}.
|
||||
validate_turnover_limits(undefined, _VS, _Route, _RoutingContext) ->
|
||||
{ok, valid};
|
||||
validate_turnover_limits({value, TurnoverLimits}, _VS, Route, #{withdrawal := Withdrawal}) ->
|
||||
ok = ff_limiter:hold_withdrawal_limits(TurnoverLimits, Route, Withdrawal),
|
||||
case ff_limiter:check_limits(TurnoverLimits, Withdrawal) of
|
||||
{ok, _} ->
|
||||
{ok, valid};
|
||||
{error, Error} ->
|
||||
{error, {terms_violation, Error}}
|
||||
end;
|
||||
validate_turnover_limits(NotReducedSelector, _VS, _Route, _RoutingContext) ->
|
||||
{error, {misconfiguration, {'Could not reduce selector to a value', NotReducedSelector}}}.
|
||||
|
||||
%% TESTS
|
||||
|
||||
@ -245,7 +376,7 @@ convert_to_route(ProviderTerminalMap) ->
|
||||
convert_to_route_test() ->
|
||||
?assertEqual(
|
||||
[],
|
||||
convert_to_route(#{})
|
||||
sort_routes([])
|
||||
),
|
||||
?assertEqual(
|
||||
[
|
||||
@ -255,11 +386,33 @@ convert_to_route_test() ->
|
||||
#{provider_id => 200, terminal_id => 2101, version => 1},
|
||||
#{provider_id => 300, terminal_id => 2200, version => 1}
|
||||
],
|
||||
convert_to_route(#{
|
||||
1000 => [{100, 2000}, {100, 2001}],
|
||||
900 => [{200, 2100}, {200, 2101}],
|
||||
100 => [{300, 2200}]
|
||||
})
|
||||
sort_routes([
|
||||
#{
|
||||
provider_ref => #domain_ProviderRef{id = 100},
|
||||
terminal_ref => #domain_TerminalRef{id = 2000},
|
||||
priority => 1000
|
||||
},
|
||||
#{
|
||||
provider_ref => #domain_ProviderRef{id = 100},
|
||||
terminal_ref => #domain_TerminalRef{id = 2001},
|
||||
priority => 1000
|
||||
},
|
||||
#{
|
||||
provider_ref => #domain_ProviderRef{id = 200},
|
||||
terminal_ref => #domain_TerminalRef{id = 2100},
|
||||
priority => 900
|
||||
},
|
||||
#{
|
||||
provider_ref => #domain_ProviderRef{id = 200},
|
||||
terminal_ref => #domain_TerminalRef{id = 2101},
|
||||
priority => 900
|
||||
},
|
||||
#{
|
||||
provider_ref => #domain_ProviderRef{id = 300},
|
||||
terminal_ref => #domain_TerminalRef{id = 2200},
|
||||
priority => 100
|
||||
}
|
||||
])
|
||||
).
|
||||
|
||||
-endif.
|
||||
|
59
apps/ff_transfer/test/ff_ct_limiter_client.erl
Normal file
59
apps/ff_transfer/test/ff_ct_limiter_client.erl
Normal file
@ -0,0 +1,59 @@
|
||||
-module(ff_ct_limiter_client).
|
||||
|
||||
-include_lib("limiter_proto/include/limproto_limiter_thrift.hrl").
|
||||
|
||||
-export([get/3]).
|
||||
|
||||
-export([create_config/2]).
|
||||
-export([get_config/2]).
|
||||
|
||||
-type client() :: woody_context:ctx().
|
||||
|
||||
-type limit_id() :: limproto_limiter_thrift:'LimitID'().
|
||||
-type limit_context() :: limproto_limiter_thrift:'LimitContext'().
|
||||
-type clock() :: limproto_limiter_thrift:'Clock'().
|
||||
-type limit_config_params() :: limproto_config_thrift:'LimitConfigParams'().
|
||||
|
||||
%%% API
|
||||
|
||||
-spec get(limit_id(), limit_context(), client()) -> woody:result() | no_return().
|
||||
get(LimitID, Context, Client) ->
|
||||
call('Get', {LimitID, clock(), Context}, Client).
|
||||
|
||||
-spec create_config(limit_config_params(), client()) -> woody:result() | no_return().
|
||||
create_config(LimitCreateParams, Client) ->
|
||||
call_configurator('Create', {LimitCreateParams}, Client).
|
||||
|
||||
-spec get_config(limit_id(), client()) -> woody:result() | no_return().
|
||||
get_config(LimitConfigID, Client) ->
|
||||
call_configurator('Get', {LimitConfigID}, Client).
|
||||
|
||||
%%% Internal functions
|
||||
|
||||
-spec call(atom(), tuple(), client()) -> woody:result() | no_return().
|
||||
call(Function, Args, Client) ->
|
||||
Call = {{limproto_limiter_thrift, 'Limiter'}, Function, Args},
|
||||
Opts = #{
|
||||
url => <<"http://limiter:8022/v1/limiter">>,
|
||||
event_handler => scoper_woody_event_handler,
|
||||
transport_opts => #{
|
||||
max_connections => 10000
|
||||
}
|
||||
},
|
||||
woody_client:call(Call, Opts, Client).
|
||||
|
||||
-spec call_configurator(atom(), tuple(), client()) -> woody:result() | no_return().
|
||||
call_configurator(Function, Args, Client) ->
|
||||
Call = {{limproto_configurator_thrift, 'Configurator'}, Function, Args},
|
||||
Opts = #{
|
||||
url => <<"http://limiter:8022/v1/configurator">>,
|
||||
event_handler => scoper_woody_event_handler,
|
||||
transport_opts => #{
|
||||
max_connections => 10000
|
||||
}
|
||||
},
|
||||
woody_client:call(Call, Opts, Client).
|
||||
|
||||
-spec clock() -> clock().
|
||||
clock() ->
|
||||
{vector, #limiter_VectorClock{state = <<>>}}.
|
@ -1,7 +1,8 @@
|
||||
-module(ff_deposit_SUITE).
|
||||
|
||||
-include_lib("stdlib/include/assert.hrl").
|
||||
-include_lib("damsel/include/dmsl_payment_processing_thrift.hrl").
|
||||
-include_lib("damsel/include/dmsl_domain_thrift.hrl").
|
||||
-include_lib("damsel/include/dmsl_payproc_thrift.hrl").
|
||||
|
||||
%% Common test API
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
-module(ff_destination_SUITE).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_destination_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_destination_thrift.hrl").
|
||||
-include_lib("damsel/include/dmsl_domain_thrift.hrl").
|
||||
-include_lib("stdlib/include/assert.hrl").
|
||||
|
||||
|
89
apps/ff_transfer/test/ff_limiter_helper.erl
Normal file
89
apps/ff_transfer/test/ff_limiter_helper.erl
Normal file
@ -0,0 +1,89 @@
|
||||
-module(ff_limiter_helper).
|
||||
|
||||
-include_lib("limiter_proto/include/limproto_limiter_thrift.hrl").
|
||||
-include_lib("limiter_proto/include/limproto_context_withdrawal_thrift.hrl").
|
||||
-include_lib("limiter_proto/include/limproto_config_thrift.hrl").
|
||||
-include_lib("limiter_proto/include/limproto_timerange_thrift.hrl").
|
||||
-include_lib("damsel/include/dmsl_wthd_domain_thrift.hrl").
|
||||
-include_lib("ff_cth/include/ct_domain.hrl").
|
||||
|
||||
-export([init_per_suite/1]).
|
||||
-export([get_limit_amount/3]).
|
||||
-export([get_limit/3]).
|
||||
|
||||
-type withdrawal() :: ff_withdrawal:withdrawal_state() | dmsl_wthd_domain_thrift:'Withdrawal'().
|
||||
-type limit() :: limproto_limiter_thrift:'Limit'().
|
||||
-type config() :: ct_suite:ct_config().
|
||||
-type id() :: binary().
|
||||
|
||||
-spec init_per_suite(config()) -> _.
|
||||
init_per_suite(Config) ->
|
||||
{ok, #config_LimitConfig{}} = ff_ct_limiter_client:create_config(
|
||||
limiter_create_num_params(?LIMIT_TURNOVER_NUM_PAYTOOL_ID1),
|
||||
ct_helper:get_woody_ctx(Config)
|
||||
),
|
||||
{ok, #config_LimitConfig{}} = ff_ct_limiter_client:create_config(
|
||||
limiter_create_num_params(?LIMIT_TURNOVER_NUM_PAYTOOL_ID2),
|
||||
ct_helper:get_woody_ctx(Config)
|
||||
),
|
||||
{ok, #config_LimitConfig{}} = ff_ct_limiter_client:create_config(
|
||||
limiter_create_amount_params(?LIMIT_TURNOVER_AMOUNT_PAYTOOL_ID1),
|
||||
ct_helper:get_woody_ctx(Config)
|
||||
),
|
||||
{ok, #config_LimitConfig{}} = ff_ct_limiter_client:create_config(
|
||||
limiter_create_amount_params(?LIMIT_TURNOVER_AMOUNT_PAYTOOL_ID2),
|
||||
ct_helper:get_woody_ctx(Config)
|
||||
).
|
||||
|
||||
-spec get_limit_amount(id(), withdrawal(), config()) -> integer().
|
||||
get_limit_amount(LimitID, Withdrawal, Config) ->
|
||||
#limiter_Limit{amount = Amount} = get_limit(LimitID, Withdrawal, Config),
|
||||
Amount.
|
||||
|
||||
-spec get_limit(id(), withdrawal(), config()) -> limit().
|
||||
get_limit(LimitId, Withdrawal, Config) ->
|
||||
MarshaledWithdrawal = maybe_marshal_withdrawal(Withdrawal),
|
||||
Context = #limiter_LimitContext{
|
||||
withdrawal_processing = #context_withdrawal_Context{
|
||||
op = {withdrawal, #context_withdrawal_OperationWithdrawal{}},
|
||||
withdrawal = #context_withdrawal_Withdrawal{withdrawal = MarshaledWithdrawal}
|
||||
}
|
||||
},
|
||||
{ok, Limit} = ff_ct_limiter_client:get(LimitId, Context, ct_helper:get_woody_ctx(Config)),
|
||||
Limit.
|
||||
|
||||
maybe_marshal_withdrawal(Withdrawal = #wthd_domain_Withdrawal{}) ->
|
||||
Withdrawal;
|
||||
maybe_marshal_withdrawal(Withdrawal) ->
|
||||
ff_limiter:marshal_withdrawal(Withdrawal).
|
||||
|
||||
limiter_create_num_params(LimitID) ->
|
||||
#config_LimitConfigParams{
|
||||
id = LimitID,
|
||||
started_at = <<"2000-01-01T00:00:00Z">>,
|
||||
shard_size = 12,
|
||||
time_range_type = {calendar, {month, #timerange_TimeRangeTypeCalendarMonth{}}},
|
||||
context_type = {withdrawal_processing, #config_LimitContextTypeWithdrawalProcessing{}},
|
||||
type = {turnover, #config_LimitTypeTurnover{}},
|
||||
scope = {single, {payment_tool, #config_LimitScopeEmptyDetails{}}},
|
||||
description = <<"description">>,
|
||||
op_behaviour = #config_OperationLimitBehaviour{
|
||||
invoice_payment_refund = {subtraction, #config_Subtraction{}}
|
||||
}
|
||||
}.
|
||||
|
||||
limiter_create_amount_params(LimitID) ->
|
||||
#config_LimitConfigParams{
|
||||
id = LimitID,
|
||||
started_at = <<"2000-01-01T00:00:00Z">>,
|
||||
shard_size = 12,
|
||||
time_range_type = {calendar, {month, #timerange_TimeRangeTypeCalendarMonth{}}},
|
||||
context_type = {withdrawal_processing, #config_LimitContextTypeWithdrawalProcessing{}},
|
||||
type =
|
||||
{turnover, #config_LimitTypeTurnover{metric = {amount, #config_LimitTurnoverAmount{currency = <<"RUB">>}}}},
|
||||
scope = {single, {party, #config_LimitScopeEmptyDetails{}}},
|
||||
description = <<"description">>,
|
||||
op_behaviour = #config_OperationLimitBehaviour{
|
||||
invoice_payment_refund = {subtraction, #config_Subtraction{}}
|
||||
}
|
||||
}.
|
@ -1,6 +1,6 @@
|
||||
-module(ff_source_SUITE).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_source_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_source_thrift.hrl").
|
||||
-include_lib("damsel/include/dmsl_domain_thrift.hrl").
|
||||
-include_lib("stdlib/include/assert.hrl").
|
||||
|
||||
|
@ -1,7 +1,10 @@
|
||||
-module(ff_transfer_SUITE).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_fistful_admin_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/ff_proto_withdrawal_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_base_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_admin_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_wthd_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_source_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_deposit_thrift.hrl").
|
||||
|
||||
-export([all/0]).
|
||||
-export([groups/0]).
|
||||
@ -113,22 +116,22 @@ deposit_via_admin_ok(C) ->
|
||||
{ok, Src1} = call_admin(
|
||||
'CreateSource',
|
||||
{
|
||||
#ff_admin_SourceParams{
|
||||
#admin_SourceParams{
|
||||
id = SrcID,
|
||||
name = <<"HAHA NO">>,
|
||||
identity_id = IID,
|
||||
currency = #'fistful_base_CurrencyRef'{symbolic_code = <<"RUB">>},
|
||||
resource = {internal, #src_Internal{details = <<"Infinite source of cash">>}}
|
||||
resource = {internal, #source_Internal{details = <<"Infinite source of cash">>}}
|
||||
}
|
||||
}
|
||||
),
|
||||
|
||||
SrcID = Src1#src_Source.id,
|
||||
{authorized, #src_Authorized{}} = ct_helper:await(
|
||||
{authorized, #src_Authorized{}},
|
||||
SrcID = Src1#source_Source.id,
|
||||
{authorized, #source_Authorized{}} = ct_helper:await(
|
||||
{authorized, #source_Authorized{}},
|
||||
fun() ->
|
||||
{ok, Src} = call_admin('GetSource', {SrcID}),
|
||||
Src#src_Source.status
|
||||
Src#source_Source.status
|
||||
end
|
||||
),
|
||||
|
||||
@ -136,7 +139,7 @@ deposit_via_admin_ok(C) ->
|
||||
{ok, Dep1} = call_admin(
|
||||
'CreateDeposit',
|
||||
{
|
||||
#ff_admin_DepositParams{
|
||||
#admin_DepositParams{
|
||||
id = DepID,
|
||||
source = SrcID,
|
||||
destination = WalID,
|
||||
@ -171,29 +174,29 @@ deposit_via_admin_fails(C) ->
|
||||
{ok, Src1} = call_admin(
|
||||
'CreateSource',
|
||||
{
|
||||
#ff_admin_SourceParams{
|
||||
#admin_SourceParams{
|
||||
id = SrcID,
|
||||
name = <<"HAHA NO">>,
|
||||
identity_id = IID,
|
||||
currency = #'fistful_base_CurrencyRef'{symbolic_code = <<"RUB">>},
|
||||
resource = {internal, #src_Internal{details = <<"Infinite source of cash">>}}
|
||||
resource = {internal, #source_Internal{details = <<"Infinite source of cash">>}}
|
||||
}
|
||||
}
|
||||
),
|
||||
|
||||
SrcID = Src1#src_Source.id,
|
||||
{authorized, #src_Authorized{}} = ct_helper:await(
|
||||
{authorized, #src_Authorized{}},
|
||||
SrcID = Src1#source_Source.id,
|
||||
{authorized, #source_Authorized{}} = ct_helper:await(
|
||||
{authorized, #source_Authorized{}},
|
||||
fun() ->
|
||||
{ok, Src} = call_admin('GetSource', {SrcID}),
|
||||
Src#src_Source.status
|
||||
Src#source_Source.status
|
||||
end
|
||||
),
|
||||
|
||||
{ok, Dep1} = call_admin(
|
||||
'CreateDeposit',
|
||||
{
|
||||
#ff_admin_DepositParams{
|
||||
#admin_DepositParams{
|
||||
id = DepID,
|
||||
source = SrcID,
|
||||
destination = WalID,
|
||||
@ -230,28 +233,28 @@ deposit_via_admin_amount_fails(C) ->
|
||||
{ok, _Src1} = call_admin(
|
||||
'CreateSource',
|
||||
{
|
||||
#ff_admin_SourceParams{
|
||||
#admin_SourceParams{
|
||||
id = SrcID,
|
||||
name = <<"HAHA NO">>,
|
||||
identity_id = IID,
|
||||
currency = #'fistful_base_CurrencyRef'{symbolic_code = <<"RUB">>},
|
||||
resource = {internal, #src_Internal{details = <<"Infinite source of cash">>}}
|
||||
resource = {internal, #source_Internal{details = <<"Infinite source of cash">>}}
|
||||
}
|
||||
}
|
||||
),
|
||||
|
||||
{authorized, #src_Authorized{}} = ct_helper:await(
|
||||
{authorized, #src_Authorized{}},
|
||||
{authorized, #source_Authorized{}} = ct_helper:await(
|
||||
{authorized, #source_Authorized{}},
|
||||
fun() ->
|
||||
{ok, Src} = call_admin('GetSource', {SrcID}),
|
||||
Src#src_Source.status
|
||||
Src#source_Source.status
|
||||
end
|
||||
),
|
||||
|
||||
{exception, #ff_admin_DepositAmountInvalid{}} = call_admin(
|
||||
{exception, #admin_DepositAmountInvalid{}} = call_admin(
|
||||
'CreateDeposit',
|
||||
{
|
||||
#ff_admin_DepositParams{
|
||||
#admin_DepositParams{
|
||||
id = DepID,
|
||||
source = SrcID,
|
||||
destination = WalID,
|
||||
@ -275,29 +278,29 @@ deposit_via_admin_currency_fails(C) ->
|
||||
{ok, Src1} = call_admin(
|
||||
'CreateSource',
|
||||
{
|
||||
#ff_admin_SourceParams{
|
||||
#admin_SourceParams{
|
||||
id = SrcID,
|
||||
name = <<"HAHA NO">>,
|
||||
identity_id = IID,
|
||||
currency = #'fistful_base_CurrencyRef'{symbolic_code = <<"RUB">>},
|
||||
resource = {internal, #src_Internal{details = <<"Infinite source of cash">>}}
|
||||
resource = {internal, #source_Internal{details = <<"Infinite source of cash">>}}
|
||||
}
|
||||
}
|
||||
),
|
||||
|
||||
SrcID = Src1#src_Source.id,
|
||||
{authorized, #src_Authorized{}} = ct_helper:await(
|
||||
{authorized, #src_Authorized{}},
|
||||
SrcID = Src1#source_Source.id,
|
||||
{authorized, #source_Authorized{}} = ct_helper:await(
|
||||
{authorized, #source_Authorized{}},
|
||||
fun() ->
|
||||
{ok, Src} = call_admin('GetSource', {SrcID}),
|
||||
Src#src_Source.status
|
||||
Src#source_Source.status
|
||||
end
|
||||
),
|
||||
BadCurrency = <<"CAT">>,
|
||||
{exception, #ff_admin_DepositCurrencyInvalid{}} = call_admin(
|
||||
{exception, #admin_DepositCurrencyInvalid{}} = call_admin(
|
||||
'CreateDeposit',
|
||||
{
|
||||
#ff_admin_DepositParams{
|
||||
#admin_DepositParams{
|
||||
id = DepID,
|
||||
source = SrcID,
|
||||
destination = WalID,
|
||||
@ -466,7 +469,7 @@ generate_id() ->
|
||||
genlib:to_binary(genlib_time:ticks()).
|
||||
|
||||
call_admin(Fun, Args) ->
|
||||
Service = {ff_proto_fistful_admin_thrift, 'FistfulAdmin'},
|
||||
Service = {fistful_admin_thrift, 'FistfulAdmin'},
|
||||
Request = {Service, Fun, Args},
|
||||
Client = ff_woody_client:new(#{
|
||||
url => <<"http://localhost:8022/v1/admin">>,
|
||||
@ -602,7 +605,7 @@ process_withdrawal(WalID, DestID, Params) ->
|
||||
%%%
|
||||
|
||||
get_withdrawal_events(WdrID) ->
|
||||
Service = {{ff_proto_withdrawal_thrift, 'Management'}, <<"/v1/withdrawal">>},
|
||||
Service = {{fistful_wthd_thrift, 'Management'}, <<"/v1/withdrawal">>},
|
||||
{ok, Events} = call('GetEvents', Service, {WdrID, #'fistful_base_EventRange'{'after' = 0, limit = 1000}}),
|
||||
Events.
|
||||
|
||||
|
@ -1,10 +1,12 @@
|
||||
-module(ff_withdrawal_SUITE).
|
||||
|
||||
-include_lib("stdlib/include/assert.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_base_thrift.hrl").
|
||||
-include_lib("ff_cth/include/ct_domain.hrl").
|
||||
-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("fistful_proto/include/fistful_wthd_session_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_wthd_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_wthd_status_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_repairer_thrift.hrl").
|
||||
|
||||
%% Common test API
|
||||
|
||||
@ -651,9 +653,9 @@ force_status_change_test(C) ->
|
||||
}}
|
||||
}}
|
||||
],
|
||||
action = #ff_repairer_ComplexAction{
|
||||
action = #repairer_ComplexAction{
|
||||
timer =
|
||||
{set_timer, #ff_repairer_SetTimerAction{
|
||||
{set_timer, #repairer_SetTimerAction{
|
||||
timer = {timeout, 10000}
|
||||
}}
|
||||
}
|
||||
@ -1043,7 +1045,7 @@ repair_withdrawal_session(WithdrawalID) ->
|
||||
ok.
|
||||
|
||||
call_session_repair(SessionID, Scenario) ->
|
||||
Service = {ff_proto_withdrawal_session_thrift, 'Repairer'},
|
||||
Service = {fistful_wthd_session_thrift, 'Repairer'},
|
||||
Request = {Service, 'Repair', {SessionID, Scenario}},
|
||||
Client = ff_woody_client:new(#{
|
||||
url => <<"http://localhost:8022/v1/repair/withdrawal/session">>,
|
||||
@ -1052,7 +1054,7 @@ call_session_repair(SessionID, Scenario) ->
|
||||
ff_woody_client:call(Client, Request).
|
||||
|
||||
call_withdrawal_repair(SessionID, Scenario) ->
|
||||
Service = {ff_proto_withdrawal_thrift, 'Repairer'},
|
||||
Service = {fistful_wthd_thrift, 'Repairer'},
|
||||
Request = {Service, 'Repair', {SessionID, Scenario}},
|
||||
Client = ff_woody_client:new(#{
|
||||
url => <<"http://localhost:8022/v1/repair/withdrawal">>,
|
||||
|
375
apps/ff_transfer/test/ff_withdrawal_limits_SUITE.erl
Normal file
375
apps/ff_transfer/test/ff_withdrawal_limits_SUITE.erl
Normal file
@ -0,0 +1,375 @@
|
||||
-module(ff_withdrawal_limits_SUITE).
|
||||
|
||||
-include_lib("stdlib/include/assert.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_fistful_base_thrift.hrl").
|
||||
-include_lib("ff_cth/include/ct_domain.hrl").
|
||||
-include_lib("damsel/include/dmsl_wthd_domain_thrift.hrl").
|
||||
|
||||
%% Common test API
|
||||
|
||||
-export([all/0]).
|
||||
-export([groups/0]).
|
||||
-export([init_per_suite/1]).
|
||||
-export([end_per_suite/1]).
|
||||
-export([init_per_group/2]).
|
||||
-export([end_per_group/2]).
|
||||
-export([init_per_testcase/2]).
|
||||
-export([end_per_testcase/2]).
|
||||
|
||||
%% Tests
|
||||
-export([limit_success/1]).
|
||||
-export([limit_overflow/1]).
|
||||
-export([choose_provider_without_limit_overflow/1]).
|
||||
-export([provider_limits_exhaust_orderly/1]).
|
||||
|
||||
%% Internal types
|
||||
|
||||
-type config() :: ct_helper:config().
|
||||
-type test_case_name() :: ct_helper:test_case_name().
|
||||
-type group_name() :: ct_helper:group_name().
|
||||
-type test_return() :: _ | no_return().
|
||||
|
||||
%% API
|
||||
|
||||
-spec all() -> [test_case_name() | {group, group_name()}].
|
||||
all() ->
|
||||
[
|
||||
{group, default}
|
||||
].
|
||||
|
||||
-spec groups() -> [{group_name(), list(), [test_case_name()]}].
|
||||
groups() ->
|
||||
[
|
||||
{default, [sequence], [
|
||||
limit_success,
|
||||
limit_overflow,
|
||||
choose_provider_without_limit_overflow,
|
||||
provider_limits_exhaust_orderly
|
||||
]}
|
||||
].
|
||||
|
||||
-spec init_per_suite(config()) -> config().
|
||||
init_per_suite(C0) ->
|
||||
C1 = ct_helper:makeup_cfg(
|
||||
[
|
||||
ct_helper:test_case_name(init),
|
||||
ct_payment_system:setup()
|
||||
],
|
||||
C0
|
||||
),
|
||||
_ = ff_limiter_helper:init_per_suite(C1),
|
||||
C1.
|
||||
|
||||
-spec end_per_suite(config()) -> _.
|
||||
end_per_suite(C) ->
|
||||
ok = ct_payment_system:shutdown(C).
|
||||
|
||||
%%
|
||||
|
||||
-spec init_per_group(group_name(), config()) -> config().
|
||||
init_per_group(_, C) ->
|
||||
C.
|
||||
|
||||
-spec end_per_group(group_name(), config()) -> _.
|
||||
end_per_group(_, _) ->
|
||||
ok.
|
||||
|
||||
%%
|
||||
|
||||
-spec init_per_testcase(test_case_name(), config()) -> config().
|
||||
init_per_testcase(Name, C) ->
|
||||
C1 = ct_helper:makeup_cfg(
|
||||
[
|
||||
ct_helper:test_case_name(Name),
|
||||
ct_helper:woody_ctx()
|
||||
],
|
||||
C
|
||||
),
|
||||
ok = ct_helper:set_context(C1),
|
||||
C1.
|
||||
|
||||
-spec end_per_testcase(test_case_name(), config()) -> _.
|
||||
end_per_testcase(_Name, _C) ->
|
||||
ok = ct_helper:unset_context().
|
||||
|
||||
%% Tests
|
||||
|
||||
-spec limit_success(config()) -> test_return().
|
||||
limit_success(C) ->
|
||||
Cash = {800800, <<"RUB">>},
|
||||
#{
|
||||
wallet_id := WalletID,
|
||||
destination_id := DestinationID
|
||||
} = prepare_standard_environment(Cash, C),
|
||||
WithdrawalID = generate_id(),
|
||||
WithdrawalParams = #{
|
||||
id => WithdrawalID,
|
||||
destination_id => DestinationID,
|
||||
wallet_id => WalletID,
|
||||
body => Cash,
|
||||
external_id => WithdrawalID
|
||||
},
|
||||
PreviousAmount = get_limit_amount(Cash, WalletID, DestinationID, ?LIMIT_TURNOVER_NUM_PAYTOOL_ID1, C),
|
||||
ok = ff_withdrawal_machine:create(WithdrawalParams, ff_entity_context:new()),
|
||||
?assertEqual(succeeded, await_final_withdrawal_status(WithdrawalID)),
|
||||
Withdrawal = get_withdrawal(WithdrawalID),
|
||||
?assertEqual(
|
||||
PreviousAmount + 1, ff_limiter_helper:get_limit_amount(?LIMIT_TURNOVER_NUM_PAYTOOL_ID1, Withdrawal, C)
|
||||
).
|
||||
|
||||
-spec limit_overflow(config()) -> test_return().
|
||||
limit_overflow(C) ->
|
||||
Cash = {900900, <<"RUB">>},
|
||||
#{
|
||||
wallet_id := WalletID,
|
||||
destination_id := DestinationID
|
||||
} = prepare_standard_environment(Cash, C),
|
||||
WithdrawalID = generate_id(),
|
||||
WithdrawalParams = #{
|
||||
id => WithdrawalID,
|
||||
destination_id => DestinationID,
|
||||
wallet_id => WalletID,
|
||||
body => Cash,
|
||||
external_id => WithdrawalID
|
||||
},
|
||||
PreviousAmount = get_limit_amount(Cash, WalletID, DestinationID, ?LIMIT_TURNOVER_NUM_PAYTOOL_ID2, C),
|
||||
ok = ff_withdrawal_machine:create(WithdrawalParams, ff_entity_context:new()),
|
||||
Result = await_final_withdrawal_status(WithdrawalID),
|
||||
?assertMatch({failed, #{code := <<"no_route_found">>}}, Result),
|
||||
%% we get final withdrawal status before we rollback limits so wait for it some amount of time
|
||||
ok = timer:sleep(500),
|
||||
Withdrawal = get_withdrawal(WithdrawalID),
|
||||
?assertEqual(PreviousAmount, ff_limiter_helper:get_limit_amount(?LIMIT_TURNOVER_NUM_PAYTOOL_ID2, Withdrawal, C)).
|
||||
|
||||
-spec choose_provider_without_limit_overflow(config()) -> test_return().
|
||||
choose_provider_without_limit_overflow(C) ->
|
||||
Cash = {901000, <<"RUB">>},
|
||||
#{
|
||||
wallet_id := WalletID,
|
||||
destination_id := DestinationID
|
||||
} = prepare_standard_environment(Cash, C),
|
||||
WithdrawalID = generate_id(),
|
||||
WithdrawalParams = #{
|
||||
id => WithdrawalID,
|
||||
destination_id => DestinationID,
|
||||
wallet_id => WalletID,
|
||||
body => Cash,
|
||||
external_id => WithdrawalID
|
||||
},
|
||||
PreviousAmount = get_limit_amount(Cash, WalletID, DestinationID, ?LIMIT_TURNOVER_NUM_PAYTOOL_ID2, C),
|
||||
ok = ff_withdrawal_machine:create(WithdrawalParams, ff_entity_context:new()),
|
||||
?assertEqual(succeeded, await_final_withdrawal_status(WithdrawalID)),
|
||||
Withdrawal = get_withdrawal(WithdrawalID),
|
||||
?assertEqual(
|
||||
PreviousAmount + 1, ff_limiter_helper:get_limit_amount(?LIMIT_TURNOVER_NUM_PAYTOOL_ID2, Withdrawal, C)
|
||||
).
|
||||
|
||||
-spec provider_limits_exhaust_orderly(config()) -> test_return().
|
||||
provider_limits_exhaust_orderly(C) ->
|
||||
Currency = <<"RUB">>,
|
||||
Cash1 = {902000, Currency},
|
||||
Cash2 = {903000, Currency},
|
||||
%% we don't want to overflow wallet cash limit
|
||||
TotalCash = {3000000, Currency},
|
||||
#{
|
||||
wallet_id := WalletID,
|
||||
destination_id := DestinationID
|
||||
} = prepare_standard_environment(TotalCash, C),
|
||||
|
||||
%% First withdrawal goes to limit 1 and spents half of its amount
|
||||
WithdrawalID1 = generate_id(),
|
||||
WithdrawalParams1 = #{
|
||||
id => WithdrawalID1,
|
||||
destination_id => DestinationID,
|
||||
wallet_id => WalletID,
|
||||
body => Cash1,
|
||||
external_id => WithdrawalID1
|
||||
},
|
||||
0 = get_limit_amount(Cash1, WalletID, DestinationID, ?LIMIT_TURNOVER_AMOUNT_PAYTOOL_ID1, C),
|
||||
ok = ff_withdrawal_machine:create(WithdrawalParams1, ff_entity_context:new()),
|
||||
?assertEqual(succeeded, await_final_withdrawal_status(WithdrawalID1)),
|
||||
Withdrawal1 = get_withdrawal(WithdrawalID1),
|
||||
?assertEqual(902000, ff_limiter_helper:get_limit_amount(?LIMIT_TURNOVER_AMOUNT_PAYTOOL_ID1, Withdrawal1, C)),
|
||||
|
||||
%% Second withdrawal goes to limit 2 as limit 1 doesn't have enough and spents all its amount
|
||||
WithdrawalID2 = generate_id(),
|
||||
WithdrawalParams2 = #{
|
||||
id => WithdrawalID2,
|
||||
destination_id => DestinationID,
|
||||
wallet_id => WalletID,
|
||||
body => Cash2,
|
||||
external_id => WithdrawalID2
|
||||
},
|
||||
0 = get_limit_amount(Cash2, WalletID, DestinationID, ?LIMIT_TURNOVER_AMOUNT_PAYTOOL_ID2, C),
|
||||
ok = ff_withdrawal_machine:create(WithdrawalParams2, ff_entity_context:new()),
|
||||
?assertEqual(succeeded, await_final_withdrawal_status(WithdrawalID2)),
|
||||
Withdrawal2 = get_withdrawal(WithdrawalID2),
|
||||
?assertEqual(903000, ff_limiter_helper:get_limit_amount(?LIMIT_TURNOVER_AMOUNT_PAYTOOL_ID2, Withdrawal2, C)),
|
||||
|
||||
%% Third withdrawal goes to limit 1 and spents all its amount
|
||||
WithdrawalID3 = generate_id(),
|
||||
WithdrawalParams3 = #{
|
||||
id => WithdrawalID3,
|
||||
destination_id => DestinationID,
|
||||
wallet_id => WalletID,
|
||||
body => Cash1,
|
||||
external_id => WithdrawalID3
|
||||
},
|
||||
902000 = get_limit_amount(Cash1, WalletID, DestinationID, ?LIMIT_TURNOVER_AMOUNT_PAYTOOL_ID1, C),
|
||||
ok = ff_withdrawal_machine:create(WithdrawalParams3, ff_entity_context:new()),
|
||||
?assertEqual(succeeded, await_final_withdrawal_status(WithdrawalID3)),
|
||||
Withdrawal3 = get_withdrawal(WithdrawalID3),
|
||||
?assertEqual(1804000, ff_limiter_helper:get_limit_amount(?LIMIT_TURNOVER_AMOUNT_PAYTOOL_ID1, Withdrawal3, C)),
|
||||
|
||||
%% Last withdrawal can't find route cause all limits are drained
|
||||
WithdrawalID = generate_id(),
|
||||
WithdrawalParams = #{
|
||||
id => WithdrawalID,
|
||||
destination_id => DestinationID,
|
||||
wallet_id => WalletID,
|
||||
body => Cash1,
|
||||
external_id => WithdrawalID
|
||||
},
|
||||
ok = ff_withdrawal_machine:create(WithdrawalParams, ff_entity_context:new()),
|
||||
Result = await_final_withdrawal_status(WithdrawalID),
|
||||
?assertMatch({failed, #{code := <<"no_route_found">>}}, Result).
|
||||
|
||||
%% Utils
|
||||
|
||||
get_limit_amount(Cash, WalletID, DestinationID, LimitID, C) ->
|
||||
{ok, WalletMachine} = ff_wallet_machine:get(WalletID),
|
||||
Wallet = ff_wallet_machine:wallet(WalletMachine),
|
||||
WalletAccount = ff_wallet:account(Wallet),
|
||||
{ok, SenderSt} = ff_identity_machine:get(ff_account:identity(WalletAccount)),
|
||||
SenderIdentity = ff_identity_machine:identity(SenderSt),
|
||||
|
||||
Withdrawal = #wthd_domain_Withdrawal{
|
||||
created_at = ff_codec:marshal(timestamp_ms, ff_time:now()),
|
||||
body = ff_dmsl_codec:marshal(cash, Cash),
|
||||
destination = ff_adapter_withdrawal_codec:marshal(resource, get_destination_resource(DestinationID)),
|
||||
sender = ff_adapter_withdrawal_codec:marshal(identity, #{
|
||||
id => ff_identity:id(SenderIdentity),
|
||||
owner_id => ff_identity:party(SenderIdentity)
|
||||
})
|
||||
},
|
||||
ff_limiter_helper:get_limit_amount(LimitID, Withdrawal, C).
|
||||
|
||||
get_destination_resource(DestinationID) ->
|
||||
{ok, DestinationMachine} = ff_destination_machine:get(DestinationID),
|
||||
Destination = ff_destination_machine:destination(DestinationMachine),
|
||||
{ok, Resource} = ff_resource:create_resource(ff_destination:resource(Destination)),
|
||||
Resource.
|
||||
|
||||
prepare_standard_environment({_Amount, Currency} = WithdrawalCash, C) ->
|
||||
Party = create_party(C),
|
||||
IdentityID = create_person_identity(Party, C),
|
||||
WalletID = create_wallet(IdentityID, <<"My wallet">>, Currency, C),
|
||||
ok = await_wallet_balance({0, Currency}, WalletID),
|
||||
DestinationID = create_destination(IdentityID, Currency, C),
|
||||
ok = set_wallet_balance(WithdrawalCash, WalletID),
|
||||
#{
|
||||
identity_id => IdentityID,
|
||||
party_id => Party,
|
||||
wallet_id => WalletID,
|
||||
destination_id => DestinationID
|
||||
}.
|
||||
|
||||
get_withdrawal(WithdrawalID) ->
|
||||
{ok, Machine} = ff_withdrawal_machine:get(WithdrawalID),
|
||||
ff_withdrawal_machine:withdrawal(Machine).
|
||||
|
||||
get_withdrawal_status(WithdrawalID) ->
|
||||
Withdrawal = get_withdrawal(WithdrawalID),
|
||||
ff_withdrawal:status(Withdrawal).
|
||||
|
||||
await_final_withdrawal_status(WithdrawalID) ->
|
||||
finished = ct_helper:await(
|
||||
finished,
|
||||
fun() ->
|
||||
{ok, Machine} = ff_withdrawal_machine:get(WithdrawalID),
|
||||
Withdrawal = ff_withdrawal_machine:withdrawal(Machine),
|
||||
case ff_withdrawal:is_finished(Withdrawal) of
|
||||
false ->
|
||||
{not_finished, Withdrawal};
|
||||
true ->
|
||||
finished
|
||||
end
|
||||
end,
|
||||
genlib_retry:linear(20, 1000)
|
||||
),
|
||||
get_withdrawal_status(WithdrawalID).
|
||||
|
||||
create_party(_C) ->
|
||||
ID = genlib:bsuuid(),
|
||||
_ = ff_party:create(ID),
|
||||
ID.
|
||||
|
||||
create_person_identity(Party, C) ->
|
||||
create_identity(Party, <<"good-one">>, C).
|
||||
|
||||
create_identity(Party, ProviderID, C) ->
|
||||
create_identity(Party, <<"Identity Name">>, ProviderID, C).
|
||||
|
||||
create_identity(Party, Name, ProviderID, _C) ->
|
||||
ID = genlib:unique(),
|
||||
ok = ff_identity_machine:create(
|
||||
#{id => ID, name => Name, party => Party, provider => ProviderID},
|
||||
#{<<"com.rbkmoney.wapi">> => #{<<"name">> => Name}}
|
||||
),
|
||||
ID.
|
||||
|
||||
create_wallet(IdentityID, Name, Currency, _C) ->
|
||||
ID = genlib:unique(),
|
||||
ok = ff_wallet_machine:create(
|
||||
#{id => ID, identity => IdentityID, name => Name, currency => Currency},
|
||||
ff_entity_context:new()
|
||||
),
|
||||
ID.
|
||||
|
||||
await_wallet_balance({Amount, Currency}, ID) ->
|
||||
Balance = {Amount, {{inclusive, Amount}, {inclusive, Amount}}, Currency},
|
||||
Balance = ct_helper:await(
|
||||
Balance,
|
||||
fun() -> get_wallet_balance(ID) end,
|
||||
genlib_retry:linear(3, 500)
|
||||
),
|
||||
ok.
|
||||
|
||||
get_wallet_balance(ID) ->
|
||||
{ok, Machine} = ff_wallet_machine:get(ID),
|
||||
get_account_balance(ff_wallet:account(ff_wallet_machine:wallet(Machine))).
|
||||
|
||||
get_account_balance(Account) ->
|
||||
{ok, {Amounts, Currency}} = ff_accounting:balance(Account),
|
||||
{ff_indef:current(Amounts), ff_indef:to_range(Amounts), Currency}.
|
||||
|
||||
generate_id() ->
|
||||
ff_id:generate_snowflake_id().
|
||||
|
||||
create_destination(IID, Currency, C) ->
|
||||
ID = generate_id(),
|
||||
StoreSource = ct_cardstore:bank_card(<<"4150399999000900">>, {12, 2025}, C),
|
||||
Resource = {bank_card, #{bank_card => StoreSource}},
|
||||
Params = #{id => ID, identity => IID, name => <<"XDesination">>, currency => Currency, resource => Resource},
|
||||
ok = ff_destination_machine:create(Params, ff_entity_context:new()),
|
||||
authorized = ct_helper:await(
|
||||
authorized,
|
||||
fun() ->
|
||||
{ok, Machine} = ff_destination_machine:get(ID),
|
||||
Destination = ff_destination_machine:destination(Machine),
|
||||
ff_destination:status(Destination)
|
||||
end
|
||||
),
|
||||
ID.
|
||||
|
||||
set_wallet_balance({Amount, Currency}, ID) ->
|
||||
TransactionID = generate_id(),
|
||||
{ok, Machine} = ff_wallet_machine:get(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} = ct_helper:create_account(Currency),
|
||||
Postings = [{AnotherAccounterID, AccounterID, {Amount - CurrentAmount, Currency}}],
|
||||
{ok, _} = ff_accounting:prepare_trx(TransactionID, Postings),
|
||||
{ok, _} = ff_accounting:commit_trx(TransactionID, Postings),
|
||||
ok.
|
@ -1,7 +1,7 @@
|
||||
-module(ff_bin_data).
|
||||
|
||||
-include_lib("binbase_proto/include/binbase_binbase_thrift.hrl").
|
||||
-include_lib("binbase_proto/include/binbase_msgpack_thrift.hrl").
|
||||
-include_lib("msgpack_proto/include/msgp_msgpack_thrift.hrl").
|
||||
|
||||
-type token() :: binary().
|
||||
-type issuer_country() :: atom().
|
||||
@ -73,7 +73,7 @@ id(Data) ->
|
||||
%%
|
||||
|
||||
encode_msgpack(nil) ->
|
||||
{nl, #'binbase_Nil'{}};
|
||||
{nl, #'msgpack_Nil'{}};
|
||||
encode_msgpack(V) when is_boolean(V) ->
|
||||
{b, V};
|
||||
encode_msgpack(V) when is_integer(V) ->
|
||||
@ -115,7 +115,7 @@ decode_result(Token, #'binbase_ResponseData'{bin_data = Bindata, version = Versi
|
||||
})
|
||||
end).
|
||||
|
||||
decode_msgpack({nl, #'binbase_Nil'{}}) ->
|
||||
decode_msgpack({nl, #'msgpack_Nil'{}}) ->
|
||||
nil;
|
||||
decode_msgpack({b, V}) when is_boolean(V) ->
|
||||
V;
|
||||
|
@ -1,6 +1,8 @@
|
||||
-module(ff_cash_flow).
|
||||
|
||||
-include_lib("damsel/include/dmsl_payment_processing_thrift.hrl").
|
||||
-include_lib("damsel/include/dmsl_base_thrift.hrl").
|
||||
-include_lib("damsel/include/dmsl_domain_thrift.hrl").
|
||||
-include_lib("damsel/include/dmsl_payproc_thrift.hrl").
|
||||
|
||||
-export([make_empty_final/0]).
|
||||
-export([gather_used_accounts/1]).
|
||||
@ -195,7 +197,7 @@ decode_rounding_method(RoundingMethod) ->
|
||||
RoundingMethod.
|
||||
|
||||
-spec decode_rational(dmsl_base_thrift:'Rational'()) -> genlib_rational:t().
|
||||
decode_rational(#'Rational'{p = P, q = Q}) ->
|
||||
decode_rational(#'base_Rational'{p = P, q = Q}) ->
|
||||
genlib_rational:new(P, Q).
|
||||
|
||||
-spec compute_volume(plan_volume(), constant_mapping()) -> {ok, cash()} | {error, volume_finalize_error()}.
|
||||
|
@ -1,6 +1,6 @@
|
||||
-module(ff_clock).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_transfer_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/fistful_transfer_thrift.hrl").
|
||||
|
||||
-define(VERSION, 1).
|
||||
-define(TYPE_LATEST, latest).
|
||||
@ -30,14 +30,14 @@ latest_clock() ->
|
||||
new(?TYPE_LATEST).
|
||||
|
||||
-spec marshal(kind(), clock()) ->
|
||||
ff_proto_transfer_thrift:'Clock'().
|
||||
fistful_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}}.
|
||||
|
||||
-spec unmarshal(kind(), Clock) -> clock() when
|
||||
Clock :: ff_proto_transfer_thrift:'Clock'().
|
||||
Clock :: fistful_transfer_thrift:'Clock'().
|
||||
unmarshal(transfer, {?TYPE_LATEST = Type, #transfer_LatestClock{}}) ->
|
||||
new(Type);
|
||||
unmarshal(transfer, {?TYPE_VECTOR = Type, #transfer_VectorClock{state = State}}) ->
|
||||
|
@ -1,5 +1,6 @@
|
||||
-module(ff_dmsl_codec).
|
||||
|
||||
-include_lib("damsel/include/dmsl_base_thrift.hrl").
|
||||
-include_lib("damsel/include/dmsl_domain_thrift.hrl").
|
||||
-include_lib("damsel/include/dmsl_user_interaction_thrift.hrl").
|
||||
|
||||
@ -137,9 +138,12 @@ unmarshal(currency, #domain_Currency{
|
||||
numcode => Numcode,
|
||||
exponent => Exponent
|
||||
};
|
||||
unmarshal(user_interaction, {redirect, {get_request, #'BrowserGetRequest'{uri = URI}}}) ->
|
||||
unmarshal(user_interaction, {redirect, {get_request, #'user_interaction_BrowserGetRequest'{uri = URI}}}) ->
|
||||
{redirect, #{content => {get, URI}}};
|
||||
unmarshal(user_interaction, {redirect, {post_request, #'BrowserPostRequest'{uri = URI, form = Form}}}) ->
|
||||
unmarshal(
|
||||
user_interaction,
|
||||
{redirect, {post_request, #'user_interaction_BrowserPostRequest'{uri = URI, form = Form}}}
|
||||
) ->
|
||||
{redirect, #{content => {post, URI, Form}}};
|
||||
unmarshal(
|
||||
resource,
|
||||
@ -353,7 +357,7 @@ marshal(attempt_limit, Limit) ->
|
||||
attempts = Limit
|
||||
};
|
||||
marshal(content, #{type := Type, data := Data}) ->
|
||||
#'Content'{
|
||||
#'base_Content'{
|
||||
type = marshal(string, Type),
|
||||
data = Data
|
||||
};
|
||||
|
@ -9,7 +9,7 @@
|
||||
-export([head/0]).
|
||||
|
||||
-type revision() :: dmt_client:version().
|
||||
-type object_data() :: dmt_client:object_data().
|
||||
-type object_data() :: dmt_client:untagged_domain_object().
|
||||
-type object_ref() :: dmsl_domain_thrift:'Reference'().
|
||||
|
||||
-export_type([revision/0]).
|
||||
@ -18,7 +18,7 @@
|
||||
|
||||
%%
|
||||
|
||||
-include_lib("damsel/include/dmsl_domain_config_thrift.hrl").
|
||||
-include_lib("damsel/include/dmsl_domain_conf_thrift.hrl").
|
||||
|
||||
-spec object(object_ref()) -> {ok, object_data()} | {error, notfound}.
|
||||
object(ObjectRef) ->
|
||||
|
@ -8,7 +8,8 @@
|
||||
|
||||
-module(ff_party).
|
||||
|
||||
-include_lib("damsel/include/dmsl_payment_processing_thrift.hrl").
|
||||
-include_lib("damsel/include/dmsl_domain_thrift.hrl").
|
||||
-include_lib("damsel/include/dmsl_payproc_thrift.hrl").
|
||||
|
||||
-type id() :: dmsl_domain_thrift:'PartyID'().
|
||||
-type contract_id() :: dmsl_domain_thrift:'ContractID'().
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
-include_lib("damsel/include/dmsl_domain_thrift.hrl").
|
||||
|
||||
-export([new_reject_context/1]).
|
||||
-export([gather_routes/4]).
|
||||
-export([log_reject_context/1]).
|
||||
|
||||
@ -10,7 +11,6 @@
|
||||
-type provider_ref() :: dmsl_domain_thrift:'ProviderRef'().
|
||||
-type provider() :: dmsl_domain_thrift:'Provider'().
|
||||
-type terminal_ref() :: dmsl_domain_thrift:'TerminalRef'().
|
||||
-type terminal() :: dmsl_domain_thrift:'Terminal'().
|
||||
-type priority() :: integer().
|
||||
-type weight() :: integer().
|
||||
-type varset() :: ff_varset:varset().
|
||||
@ -20,16 +20,14 @@
|
||||
-type candidate_description() :: binary() | undefined.
|
||||
|
||||
-type route() :: #{
|
||||
provider_ref := provider_ref(),
|
||||
terminal_ref := terminal_ref(),
|
||||
terminal := terminal(),
|
||||
priority => priority(),
|
||||
weight => weight(),
|
||||
provider => provider()
|
||||
priority := priority(),
|
||||
weight => weight()
|
||||
}.
|
||||
|
||||
-export_type([route/0]).
|
||||
-export_type([provider/0]).
|
||||
-export_type([terminal/0]).
|
||||
-export_type([reject_context/0]).
|
||||
-export_type([rejected_route/0]).
|
||||
|
||||
@ -46,12 +44,16 @@
|
||||
|
||||
%%
|
||||
|
||||
-spec gather_routes(payment_institution(), routing_rule_tag(), varset(), revision()) -> {[route()], reject_context()}.
|
||||
gather_routes(PaymentInstitution, RoutingRuleTag, VS, Revision) ->
|
||||
RejectContext = #{
|
||||
-spec new_reject_context(varset()) -> reject_context().
|
||||
new_reject_context(VS) ->
|
||||
#{
|
||||
varset => VS,
|
||||
rejected_routes => []
|
||||
},
|
||||
}.
|
||||
|
||||
-spec gather_routes(payment_institution(), routing_rule_tag(), varset(), revision()) -> {[route()], reject_context()}.
|
||||
gather_routes(PaymentInstitution, RoutingRuleTag, VS, Revision) ->
|
||||
RejectContext = new_reject_context(VS),
|
||||
case do_gather_routes(PaymentInstitution, RoutingRuleTag, VS, Revision) of
|
||||
{ok, {AcceptedRoutes, RejectedRoutes}} ->
|
||||
{AcceptedRoutes, RejectContext#{rejected_routes => RejectedRoutes}};
|
||||
@ -117,13 +119,11 @@ filter_prohibited_candidates(Candidates, ProhibitedCandidates, Revision) ->
|
||||
lists:foldr(
|
||||
fun(C, {Accepted, Rejected}) ->
|
||||
Route = make_route(C, Revision),
|
||||
#{terminal_ref := TerminalRef} = Route,
|
||||
#{provider_ref := ProviderRef, terminal_ref := TerminalRef} = Route,
|
||||
case maps:find(TerminalRef, ProhibitionTable) of
|
||||
error ->
|
||||
{[Route | Accepted], Rejected};
|
||||
{ok, Description} ->
|
||||
#{terminal := Terminal} = Route,
|
||||
ProviderRef = Terminal#domain_Terminal.provider_ref,
|
||||
{Accepted, [{ProviderRef, TerminalRef, {'RoutingRule', Description}} | Rejected]}
|
||||
end
|
||||
end,
|
||||
@ -146,13 +146,11 @@ make_route(Candidate, Revision) ->
|
||||
Priority = Candidate#domain_RoutingCandidate.priority,
|
||||
Weight = Candidate#domain_RoutingCandidate.weight,
|
||||
ProviderRef = Terminal#domain_Terminal.provider_ref,
|
||||
{ok, Provider} = ff_domain_config:object(Revision, {provider, ProviderRef}),
|
||||
genlib_map:compact(#{
|
||||
provider_ref => ProviderRef,
|
||||
terminal_ref => TerminalRef,
|
||||
terminal => Terminal,
|
||||
priority => Priority,
|
||||
weight => Weight,
|
||||
provider => Provider
|
||||
weight => Weight
|
||||
}).
|
||||
|
||||
-spec log_reject_context(reject_context()) -> ok.
|
||||
|
@ -1,6 +1,7 @@
|
||||
-module(ff_varset).
|
||||
|
||||
-include_lib("damsel/include/dmsl_payment_processing_thrift.hrl").
|
||||
-include_lib("damsel/include/dmsl_domain_thrift.hrl").
|
||||
-include_lib("damsel/include/dmsl_payproc_thrift.hrl").
|
||||
|
||||
-export_type([varset/0]).
|
||||
-export_type([encoded_varset/0]).
|
||||
@ -23,7 +24,7 @@
|
||||
bin_data => dmsl_domain_thrift:'BinData'()
|
||||
}.
|
||||
|
||||
-type encoded_varset() :: dmsl_payment_processing_thrift:'Varset'().
|
||||
-type encoded_varset() :: dmsl_payproc_thrift:'Varset'().
|
||||
|
||||
-spec encode(varset()) -> encoded_varset().
|
||||
encode(Varset) ->
|
||||
@ -39,7 +40,7 @@ encode(Varset) ->
|
||||
bin_data = genlib_map:get(bin_data, Varset)
|
||||
}.
|
||||
|
||||
-spec encode_contract_terms_varset(varset()) -> dmsl_payment_processing_thrift:'ComputeContractTermsVarset'().
|
||||
-spec encode_contract_terms_varset(varset()) -> dmsl_payproc_thrift:'ComputeContractTermsVarset'().
|
||||
encode_contract_terms_varset(Varset) ->
|
||||
#payproc_ComputeContractTermsVarset{
|
||||
currency = genlib_map:get(currency, Varset),
|
||||
|
@ -13,11 +13,11 @@
|
||||
%% Internal types
|
||||
%%
|
||||
|
||||
-type destination() :: dmsl_withdrawals_domain_thrift:'Destination'().
|
||||
-type identity() :: dmsl_withdrawals_domain_thrift:'Identity'().
|
||||
-type destination() :: dmsl_wthd_domain_thrift:'Destination'().
|
||||
-type identity() :: dmsl_wthd_domain_thrift:'Identity'().
|
||||
-type cash() :: dmsl_domain_thrift:'Cash'().
|
||||
-type currency() :: dmsl_domain_thrift:'Currency'().
|
||||
-type domain_quote() :: dmsl_withdrawals_provider_adapter_thrift:'Quote'().
|
||||
-type domain_quote() :: dmsl_wthd_provider_thrift:'Quote'().
|
||||
|
||||
-type withdrawal() :: #{
|
||||
id => binary(),
|
||||
|
@ -1,6 +1,7 @@
|
||||
-module(ff_ct_provider).
|
||||
|
||||
-include_lib("damsel/include/dmsl_withdrawals_provider_adapter_thrift.hrl").
|
||||
-include_lib("damsel/include/dmsl_domain_thrift.hrl").
|
||||
-include_lib("damsel/include/dmsl_wthd_provider_thrift.hrl").
|
||||
|
||||
%% API
|
||||
-export([start/0]).
|
||||
@ -18,11 +19,11 @@
|
||||
%% Internal types
|
||||
%%
|
||||
|
||||
-type destination() :: dmsl_withdrawals_domain_thrift:'Destination'().
|
||||
-type identity() :: dmsl_withdrawals_domain_thrift:'Identity'().
|
||||
-type destination() :: dmsl_wthd_domain_thrift:'Destination'().
|
||||
-type identity() :: dmsl_wthd_domain_thrift:'Identity'().
|
||||
-type cash() :: dmsl_domain_thrift:'Cash'().
|
||||
-type currency() :: dmsl_domain_thrift:'Currency'().
|
||||
-type domain_quote() :: dmsl_withdrawals_provider_adapter_thrift:'Quote'().
|
||||
-type domain_quote() :: dmsl_wthd_provider_thrift:'Quote'().
|
||||
|
||||
-type withdrawal() :: #{
|
||||
id => binary(),
|
||||
@ -80,14 +81,14 @@ start(Opts) ->
|
||||
next_state => state(),
|
||||
transaction_info => transaction_info()
|
||||
}}.
|
||||
process_withdrawal(#{quote := #wthadpt_Quote{quote_data = QuoteData}}, State, _Options) when
|
||||
process_withdrawal(#{quote := #wthd_provider_Quote{quote_data = QuoteData}}, State, _Options) when
|
||||
QuoteData =:= ?DUMMY_QUOTE_ERROR
|
||||
->
|
||||
{ok, #{
|
||||
intent => {finish, {failed, #{code => <<"test_error">>}}},
|
||||
next_state => State
|
||||
}};
|
||||
process_withdrawal(#{quote := #wthadpt_Quote{quote_data = QuoteData}}, State, _Options) when
|
||||
process_withdrawal(#{quote := #wthd_provider_Quote{quote_data = QuoteData}}, State, _Options) when
|
||||
QuoteData =:= ?DUMMY_QUOTE
|
||||
->
|
||||
{ok, #{
|
||||
@ -107,7 +108,7 @@ get_quote(
|
||||
#{
|
||||
currency_from := CurrencyFrom,
|
||||
currency_to := CurrencyTo,
|
||||
exchange_cash := #wthadpt_Cash{amount = Amount, currency = Currency}
|
||||
exchange_cash := #wthd_provider_Cash{amount = Amount, currency = Currency}
|
||||
},
|
||||
_Options
|
||||
) ->
|
||||
@ -132,7 +133,7 @@ handle_callback(_Callback, _Withdrawal, _State, _Options) ->
|
||||
erlang:error(not_implemented).
|
||||
|
||||
calc_cash(Currency, Currency, Amount) ->
|
||||
#wthadpt_Cash{amount = Amount, currency = Currency};
|
||||
#wthd_provider_Cash{amount = Amount, currency = Currency};
|
||||
calc_cash(Currency, _, Amount) ->
|
||||
NewAmount = erlang:round(Amount / 2),
|
||||
#wthadpt_Cash{amount = NewAmount, currency = Currency}.
|
||||
#wthd_provider_Cash{amount = NewAmount, currency = Currency}.
|
||||
|
@ -2,7 +2,8 @@
|
||||
|
||||
-behaviour(woody_server_thrift_handler).
|
||||
|
||||
-include_lib("damsel/include/dmsl_withdrawals_provider_adapter_thrift.hrl").
|
||||
-include_lib("damsel/include/dmsl_domain_thrift.hrl").
|
||||
-include_lib("damsel/include/dmsl_wthd_provider_thrift.hrl").
|
||||
|
||||
%% woody_server_thrift_handler callbacks
|
||||
-export([handle_function/4]).
|
||||
@ -22,7 +23,7 @@ handle_function('ProcessWithdrawal', {Withdrawal, InternalState, Options}, _Cont
|
||||
#{intent := Intent} = ProcessResult,
|
||||
NewState = maps:get(next_state, ProcessResult, undefined),
|
||||
TransactionInfo = maps:get(transaction_info, ProcessResult, undefined),
|
||||
{ok, #wthadpt_ProcessResult{
|
||||
{ok, #wthd_provider_ProcessResult{
|
||||
intent = encode_intent(Intent),
|
||||
next_state = encode_state(NewState),
|
||||
trx = encode_trx(TransactionInfo)
|
||||
@ -43,7 +44,7 @@ handle_function('HandleCallback', {Callback, Withdrawal, InternalState, Options}
|
||||
#{intent := Intent, response := Response} = CallbackResult,
|
||||
NewState = maps:get(next_state, CallbackResult, undefined),
|
||||
TransactionInfo = maps:get(transaction_info, CallbackResult, undefined),
|
||||
{ok, #wthadpt_CallbackResult{
|
||||
{ok, #wthd_provider_CallbackResult{
|
||||
intent = encode_intent(Intent),
|
||||
next_state = encode_state(NewState),
|
||||
response = encode_callback_response(Response),
|
||||
@ -54,7 +55,7 @@ handle_function('HandleCallback', {Callback, Withdrawal, InternalState, Options}
|
||||
%% Internals
|
||||
%%
|
||||
|
||||
decode_withdrawal(#wthadpt_Withdrawal{
|
||||
decode_withdrawal(#wthd_provider_Withdrawal{
|
||||
id = Id,
|
||||
body = Body,
|
||||
destination = Destination,
|
||||
@ -71,7 +72,7 @@ decode_withdrawal(#wthadpt_Withdrawal{
|
||||
quote => Quote
|
||||
}.
|
||||
|
||||
decode_quote_params(#wthadpt_GetQuoteParams{
|
||||
decode_quote_params(#wthd_provider_GetQuoteParams{
|
||||
idempotency_id = IdempotencyID,
|
||||
currency_from = CurrencyFrom,
|
||||
currency_to = CurrencyTo,
|
||||
@ -90,7 +91,7 @@ decode_options(Options) ->
|
||||
decode_state(State) ->
|
||||
ff_adapter_withdrawal_codec:unmarshal(adapter_state, State).
|
||||
|
||||
decode_callback(#wthadpt_Callback{tag = Tag, payload = Payload}) ->
|
||||
decode_callback(#wthd_provider_Callback{tag = Tag, payload = Payload}) ->
|
||||
#{tag => Tag, payload => Payload}.
|
||||
|
||||
%%
|
||||
@ -111,7 +112,7 @@ encode_quote(#{
|
||||
expires_on := ExpiresOn,
|
||||
quote_data := QuoteData
|
||||
}) ->
|
||||
#wthadpt_Quote{
|
||||
#wthd_provider_Quote{
|
||||
cash_from = CashFrom,
|
||||
cash_to = CashTo,
|
||||
created_at = CreatedAt,
|
||||
@ -120,7 +121,7 @@ encode_quote(#{
|
||||
}.
|
||||
|
||||
encode_callback_response(#{payload := Payload}) ->
|
||||
#wthadpt_CallbackResponse{payload = Payload}.
|
||||
#wthd_provider_CallbackResponse{payload = Payload}.
|
||||
|
||||
get_handler(Opts) ->
|
||||
proplists:get_value(handler, Opts, ff_ct_provider).
|
||||
|
@ -16,7 +16,7 @@ init(Opts) ->
|
||||
ff_ct_provider_thrift_service_sup,
|
||||
#{
|
||||
handlers => [
|
||||
{Path, {{dmsl_withdrawals_provider_adapter_thrift, 'Adapter'}, {ff_ct_provider_thrift, []}}}
|
||||
{Path, {{dmsl_wthd_provider_thrift, 'Adapter'}, {ff_ct_provider_thrift, []}}}
|
||||
],
|
||||
event_handler => scoper_woody_event_handler,
|
||||
ip => proplists:get_value(ip, Opts, "::"),
|
||||
|
@ -1,6 +1,7 @@
|
||||
-module(ff_ct_sleepy_provider).
|
||||
|
||||
-include_lib("damsel/include/dmsl_withdrawals_provider_adapter_thrift.hrl").
|
||||
-include_lib("damsel/include/dmsl_domain_thrift.hrl").
|
||||
-include_lib("damsel/include/dmsl_wthd_provider_thrift.hrl").
|
||||
|
||||
%% API
|
||||
-export([start/0]).
|
||||
@ -15,11 +16,11 @@
|
||||
%% Internal types
|
||||
%%
|
||||
|
||||
-type destination() :: dmsl_withdrawals_domain_thrift:'Destination'().
|
||||
-type identity() :: dmsl_withdrawals_domain_thrift:'Identity'().
|
||||
-type destination() :: dmsl_wthd_domain_thrift:'Destination'().
|
||||
-type identity() :: dmsl_wthd_domain_thrift:'Identity'().
|
||||
-type cash() :: dmsl_domain_thrift:'Cash'().
|
||||
-type currency() :: dmsl_domain_thrift:'Currency'().
|
||||
-type domain_quote() :: dmsl_withdrawals_provider_adapter_thrift:'Quote'().
|
||||
-type domain_quote() :: dmsl_wthd_provider_thrift:'Quote'().
|
||||
|
||||
-type withdrawal() :: #{
|
||||
id => binary(),
|
||||
@ -109,7 +110,7 @@ get_quote(_Quote, _Options) ->
|
||||
next_state => state(),
|
||||
transaction_info => transaction_info()
|
||||
}}.
|
||||
handle_callback(_Callback, #{quote := #wthadpt_Quote{quote_data = QuoteData}}, _State, _Options) when
|
||||
handle_callback(_Callback, #{quote := #wthd_provider_Quote{quote_data = QuoteData}}, _State, _Options) when
|
||||
QuoteData =:= ?DUMMY_QUOTE_ERROR_FATAL
|
||||
->
|
||||
erlang:error(spanish_inquisition);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user