TD-273: Drop legacy routing facility (#23)

* Drop unused macros / includes

* Drop testcase relevant to legacy routing only

* Adapt SUT setup to work w/o legacy routing

While also ensuring that domain config does not spill into `ct_domain`
helper module.

* Sync Dockerfile w/ valitydev/erlang-templates

* Bump to valitydev/party-client-erlang@31850a6

* Switch to valitydev/party-management@f757b79 in testenv

* Add couple identity suite testcases
This commit is contained in:
Andrew Mayorov 2022-04-21 14:02:52 +03:00 committed by GitHub
parent b2aec027fd
commit 2a73c73d9b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 496 additions and 729 deletions

View File

@ -6,7 +6,6 @@ SHELL ["/bin/bash", "-o", "pipefail", "-c"]
# Install thrift compiler
ARG THRIFT_VERSION
ARG TARGETARCH
RUN wget -q -O- "https://github.com/valitydev/thrift/releases/download/${THRIFT_VERSION}/thrift-${THRIFT_VERSION}-linux-${TARGETARCH}.tar.gz" \
| tar -xvz -C /usr/local/bin/

View File

@ -3,12 +3,10 @@ ARG OTP_VERSION
FROM docker.io/library/erlang:${OTP_VERSION}
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
ARG BUILDARCH
# Install thrift compiler
ARG THRIFT_VERSION
RUN wget -q -O- "https://github.com/valitydev/thrift/releases/download/${THRIFT_VERSION}/thrift-${THRIFT_VERSION}-linux-${BUILDARCH}.tar.gz" \
ARG TARGETARCH
RUN wget -q -O- "https://github.com/valitydev/thrift/releases/download/${THRIFT_VERSION}/thrift-${THRIFT_VERSION}-linux-${TARGETARCH}.tar.gz" \
| tar -xvz -C /usr/local/bin/
# Set env

View File

@ -16,8 +16,6 @@
-define(prx(ID), #domain_ProxyRef{id = ID}).
-define(prv(ID), #domain_ProviderRef{id = ID}).
-define(trm(ID), #domain_TerminalRef{id = ID}).
-define(prv_trm(ID), #domain_ProviderTerminalRef{id = ID}).
-define(prv_trm(ID, P), #domain_ProviderTerminalRef{id = ID, priority = P}).
-define(tmpl(ID), #domain_ContractTemplateRef{id = ID}).
-define(trms(ID), #domain_TermSetHierarchyRef{id = ID}).
-define(sas(ID), #domain_SystemAccountSetRef{id = ID}).

View File

@ -23,8 +23,9 @@
-export([term_set_hierarchy/3]).
-export([timed_term_set/1]).
-export([globals/2]).
-export([withdrawal_provider/3]).
-export([withdrawal_terminal/1]).
-export([withdrawal_provider/4]).
-export([withdrawal_terminal/2]).
-export([withdrawal_terminal/3]).
%%
@ -36,214 +37,45 @@
-type object() ::
dmsl_domain_thrift:'DomainObject'().
-spec withdrawal_provider(?DTP('ProviderRef'), ?DTP('ProxyRef'), binary()) -> object().
withdrawal_provider(?prv(16) = Ref, ProxyRef, IdentityID) ->
-spec withdrawal_provider(
?DTP('ProviderRef'),
?DTP('ProxyRef'),
binary(),
?DTP('ProvisionTermSet') | undefined
) -> object().
withdrawal_provider(?prv(ID) = Ref, ProxyRef, IdentityID, TermSet) ->
{ok, AccountID} = ct_helper:create_account(<<"RUB">>),
{provider, #domain_ProviderObject{
ref = Ref,
data = #domain_Provider{
name = <<"WithdrawalProvider">>,
description = <<"Withdrawal provider">>,
name = genlib:format("Withdrawal provider #~B", [ID]),
description = <<>>,
proxy = #domain_Proxy{ref = ProxyRef, additional = #{}},
identity = IdentityID,
terms = undefined,
terms = TermSet,
accounts = #{
?cur(<<"RUB">>) => #domain_ProviderAccount{settlement = AccountID}
},
terminal =
{decisions, [
#domain_TerminalDecision{
if_ = {constant, true},
then_ = {value, [?prv_trm(6)]}
}
]}
}
}};
withdrawal_provider(Ref, ProxyRef, IdentityID) ->
{ok, AccountID} = ct_helper:create_account(<<"RUB">>),
{provider, #domain_ProviderObject{
ref = Ref,
data = #domain_Provider{
name = <<"WithdrawalProvider">>,
description = <<"Withdrawal provider">>,
proxy = #domain_Proxy{ref = ProxyRef, additional = #{}},
identity = IdentityID,
terms = #domain_ProvisionTermSet{
wallet = #domain_WalletProvisionTerms{
withdrawals = #domain_WithdrawalProvisionTerms{
currencies = {value, ?ordset([?cur(<<"RUB">>)])},
payout_methods = {value, ?ordset([])},
cash_limit =
{value,
?cashrng(
{inclusive, ?cash(0, <<"RUB">>)},
{exclusive, ?cash(10000000, <<"RUB">>)}
)},
cash_flow =
{decisions, [
#domain_CashFlowDecision{
if_ = {condition, {currency_is, ?cur(<<"RUB">>)}},
then_ =
{value, [
?cfpost(
{system, settlement},
{provider, settlement},
{product,
{min_of,
?ordset([
?fixed(10, <<"RUB">>),
?share(5, 100, operation_amount, round_half_towards_zero)
])}}
)
]}
}
]}
}
}
},
accounts = #{
?cur(<<"RUB">>) => #domain_ProviderAccount{settlement = AccountID}
},
terminal =
case Ref of
?prv(9) ->
{decisions, [
#domain_TerminalDecision{
if_ = {constant, true},
then_ = {value, [?prv_trm(1, 500)]}
}
]};
?prv(10) ->
{decisions, [
#domain_TerminalDecision{
if_ = {constant, true},
then_ = {value, [?prv_trm(1)]}
}
]};
?prv(11) ->
{decisions, [
#domain_TerminalDecision{
if_ = {constant, true},
then_ = {value, [?prv_trm(1)]}
}
]};
?prv(17) ->
{decisions, [
#domain_TerminalDecision{
if_ =
{condition,
{cost_in,
?cashrng(
{inclusive, ?cash(300, <<"RUB">>)},
{inclusive, ?cash(300, <<"RUB">>)}
)}},
then_ = {value, [?prv_trm(1)]}
},
#domain_TerminalDecision{
if_ =
{condition,
{cost_in,
?cashrng(
{inclusive, ?cash(301, <<"RUB">>)},
{inclusive, ?cash(301, <<"RUB">>)}
)}},
then_ = {value, [?prv_trm(8)]}
}
]};
_ ->
{decisions, [
#domain_TerminalDecision{
if_ =
{condition,
{cost_in,
?cashrng(
{inclusive, ?cash(0, <<"RUB">>)},
{exclusive, ?cash(1000000, <<"RUB">>)}
)}},
then_ = {value, [?prv_trm(1)]}
},
#domain_TerminalDecision{
if_ =
{condition,
{cost_in,
?cashrng(
{inclusive, ?cash(3000000, <<"RUB">>)},
{exclusive, ?cash(10000000, <<"RUB">>)}
)}},
then_ = {value, [?prv_trm(7)]}
}
]}
end
}
}}.
-spec withdrawal_terminal(?DTP('TerminalRef')) -> object().
withdrawal_terminal(?trm(N) = Ref) when N > 0, N < 6 ->
-spec withdrawal_terminal(?DTP('TerminalRef'), ?DTP('ProviderRef')) -> object().
withdrawal_terminal(Ref, ProviderRef) ->
withdrawal_terminal(Ref, ProviderRef, undefined).
-spec withdrawal_terminal(
?DTP('TerminalRef'),
?DTP('ProviderRef'),
?DTP('ProvisionTermSet') | undefined
) -> object().
withdrawal_terminal(?trm(ID) = Ref, ?prv(ProviderID) = ProviderRef, TermSet) ->
{terminal, #domain_TerminalObject{
ref = Ref,
data = #domain_Terminal{
name = <<"WithdrawalTerminal">>,
description = <<"Withdrawal terminal">>,
provider_ref = ?prv(1)
}
}};
withdrawal_terminal(?trm(6) = Ref) ->
{terminal, #domain_TerminalObject{
ref = Ref,
data = #domain_Terminal{
name = <<"WithdrawalTerminal">>,
description = <<"Withdrawal terminal">>
}
}};
withdrawal_terminal(?trm(7) = Ref) ->
{terminal, #domain_TerminalObject{
ref = Ref,
data = #domain_Terminal{
name = <<"Terminal7">>,
description = <<"Withdrawal terminal">>,
terms = #domain_ProvisionTermSet{
wallet = #domain_WalletProvisionTerms{
withdrawals = #domain_WithdrawalProvisionTerms{
currencies = {value, ?ordset([?cur(<<"BTC">>)])},
payout_methods = {value, ?ordset([])},
cash_limit =
{value,
?cashrng(
{inclusive, ?cash(1000000, <<"BTC">>)},
{exclusive, ?cash(10000000, <<"BTC">>)}
)},
cash_flow = {value, ?ordset([])}
}
}
}
}
}};
withdrawal_terminal(?trm(8) = Ref) ->
{terminal, #domain_TerminalObject{
ref = Ref,
data = #domain_Terminal{
name = <<"Terminal8">>,
description = <<"Override provider cashflow">>,
terms = #domain_ProvisionTermSet{
wallet = #domain_WalletProvisionTerms{
withdrawals = #domain_WithdrawalProvisionTerms{
cash_flow =
{decisions, [
#domain_CashFlowDecision{
if_ = {constant, true},
then_ =
{value, [
?cfpost(
{system, settlement},
{provider, settlement},
?fixed(16, <<"RUB">>)
)
]}
}
]}
}
}
}
name = genlib:format("Withdrawal Terminal #~B", [ID]),
description = genlib:format("Withdrawal Terminal @ Provider #~B", [ProviderID]),
provider_ref = ProviderRef,
terms = TermSet
}
}}.

View File

@ -239,6 +239,14 @@ services(Options) ->
-include_lib("ff_cth/include/ct_domain.hrl").
% NOTE
% Allocate those domain object identifiers at least 100 apart from each other.
% This space might be used to define additional object in place (see below).
-define(EMPTY_ROUTING_RULESET, 0).
-define(PAYINST1_ROUTING_POLICIES, 100).
-define(PAYINST1_ROUTING_PROHIBITIONS, 200).
-define(PAYINST2_ROUTING_POLICIES, 300).
payment_inst_identity_id(Options) ->
maps:get(payment_inst_identity_id, Options).
@ -252,40 +260,268 @@ dummy_provider_identity_id(Options) ->
maps:get(dummy_provider_identity_id, Options).
domain_config(Options) ->
WithdrawalDecision1 =
{delegates, [
delegate(condition(party, <<"12345">>), ?ruleset(2)),
delegate(condition(party, <<"67890">>), ?ruleset(4))
]},
WithdrawalDecision2 =
{delegates, [
delegate(condition(cost_in, {0, 1000, <<"RUB">>}), ?ruleset(3))
]},
WithdrawalDecision3 =
{candidates, [
candidate({constant, true}, ?trm(1)),
candidate({constant, true}, ?trm(2))
]},
WithdrawalDecision4 =
{candidates, [
candidate({constant, true}, ?trm(3)),
candidate({constant, true}, ?trm(4)),
candidate({constant, true}, ?trm(5))
]},
WithdrawalDecision5 =
{candidates, [
candidate({constant, true}, ?trm(4))
]},
ProviderTermSet = #domain_ProvisionTermSet{
wallet = #domain_WalletProvisionTerms{
withdrawals = #domain_WithdrawalProvisionTerms{
currencies = {value, ?ordset([?cur(<<"RUB">>)])},
payout_methods = {value, ?ordset([])},
cash_limit =
{value,
?cashrng(
{inclusive, ?cash(0, <<"RUB">>)},
{exclusive, ?cash(10000000, <<"RUB">>)}
)},
cash_flow =
{decisions, [
#domain_CashFlowDecision{
if_ = {condition, {currency_is, ?cur(<<"RUB">>)}},
then_ =
{value, [
?cfpost(
{system, settlement},
{provider, settlement},
{product,
{min_of,
?ordset([
?fixed(10, <<"RUB">>),
?share(5, 100, operation_amount, round_half_towards_zero)
])}}
)
]}
}
]}
}
}
},
Default = [
ct_domain:globals(?eas(1), [?payinst(1)]),
ct_domain:external_account_set(?eas(1), <<"Default">>, ?cur(<<"RUB">>)),
routing_ruleset(?ruleset(1), <<"WithdrawalRuleset#1">>, WithdrawalDecision1),
routing_ruleset(?ruleset(2), <<"WithdrawalRuleset#2">>, WithdrawalDecision2),
routing_ruleset(?ruleset(3), <<"WithdrawalRuleset#3">>, WithdrawalDecision3),
routing_ruleset(?ruleset(4), <<"WithdrawalRuleset#4">>, WithdrawalDecision4),
routing_ruleset(?ruleset(5), <<"WithdrawalRuleset#5">>, WithdrawalDecision5),
routing_ruleset(
?ruleset(?EMPTY_ROUTING_RULESET),
<<"Empty Ruleset">>,
{candidates, []}
),
routing_ruleset(
?ruleset(?PAYINST1_ROUTING_POLICIES),
<<"PayInst1 Withdrawal Ruleset">>,
{delegates, [
delegate(condition(party, <<"12345">>), ?ruleset(?PAYINST1_ROUTING_POLICIES + 1)),
delegate(condition(party, <<"67890">>), ?ruleset(?PAYINST1_ROUTING_POLICIES + 3)),
delegate({constant, true}, ?ruleset(?PAYINST1_ROUTING_POLICIES + 4))
]}
),
routing_ruleset(
?ruleset(?PAYINST1_ROUTING_POLICIES + 1),
{delegates, [
delegate(condition(cost_in, {0, 1000, <<"RUB">>}), ?ruleset(?PAYINST1_ROUTING_POLICIES + 2))
]}
),
routing_ruleset(
?ruleset(?PAYINST1_ROUTING_POLICIES + 2),
{candidates, [
candidate({constant, true}, ?trm(1)),
candidate({constant, true}, ?trm(2))
]}
),
routing_ruleset(
?ruleset(?PAYINST1_ROUTING_POLICIES + 3),
{candidates, [
candidate({constant, true}, ?trm(3)),
candidate({constant, true}, ?trm(4)),
candidate({constant, true}, ?trm(5))
]}
),
routing_ruleset(
?ruleset(?PAYINST1_ROUTING_POLICIES + 4),
{delegates, [
delegate(
condition(cost_in, {300, 302, <<"RUB">>}),
?ruleset(?PAYINST1_ROUTING_POLICIES + 5)
),
delegate(
condition(cost_in, {123123, <<"RUB">>}),
?ruleset(?PAYINST1_ROUTING_POLICIES + 6)
),
delegate(
condition(cost_in, {100500, <<"RUB">>}),
?ruleset(?PAYINST1_ROUTING_POLICIES + 10)
),
delegate(
condition(cost_in, {500100, <<"RUB">>}),
?ruleset(?PAYINST1_ROUTING_POLICIES + 11)
),
delegate(
condition(cost_in, {500500, <<"RUB">>}),
?ruleset(?PAYINST1_ROUTING_POLICIES + 12)
),
delegate(
condition(cost_in, {700700, <<"RUB">>}),
?ruleset(?PAYINST1_ROUTING_POLICIES + 13)
),
delegate(
{condition,
{payment_tool,
{bank_card, #domain_BankCardCondition{
definition = {issuer_country_is, 'rus'}
}}}},
?ruleset(?PAYINST1_ROUTING_POLICIES + 14)
),
delegate(
{condition, {payment_tool, {crypto_currency, #domain_CryptoCurrencyCondition{}}}},
?ruleset(?PAYINST1_ROUTING_POLICIES + 15)
),
delegate(
{condition,
{payment_tool,
{generic,
{payment_service_is, #domain_PaymentServiceRef{
id = <<"IND">>
}}}}},
?ruleset(?PAYINST1_ROUTING_POLICIES + 15)
)
]}
),
routing_ruleset(
?ruleset(?PAYINST1_ROUTING_POLICIES + 5),
{candidates, [
candidate(condition(cost_in, {300, <<"RUB">>}), ?trm(1701)),
candidate(condition(cost_in, {301, <<"RUB">>}), ?trm(1708))
]}
),
routing_ruleset(
?ruleset(?PAYINST1_ROUTING_POLICIES + 6),
{candidates, [
candidate({constant, true}, ?trm(6))
]}
),
routing_ruleset(
?ruleset(?PAYINST1_ROUTING_POLICIES + 10),
{candidates, [
% provider 4 will be discarded by proxy 6
candidate({constant, true}, ?trm(401)),
candidate({constant, true}, ?trm(501))
]}
),
routing_ruleset(
?ruleset(?PAYINST1_ROUTING_POLICIES + 11),
{candidates, [
candidate({constant, true}, ?trm(401)),
candidate({constant, true}, ?trm(601)),
candidate({constant, true}, ?trm(701)),
candidate({constant, true}, ?trm(801))
]}
),
routing_ruleset(
?ruleset(?PAYINST1_ROUTING_POLICIES + 12),
{candidates, [
candidate({constant, true}, ?trm(901), 500),
candidate({constant, true}, ?trm(1001), 1000)
]}
),
routing_ruleset(
?ruleset(?PAYINST1_ROUTING_POLICIES + 13),
{candidates, [
candidate({constant, true}, ?trm(1101))
]}
),
routing_ruleset(
?ruleset(?PAYINST1_ROUTING_POLICIES + 14),
{candidates, [
candidate(
condition(cost_in, {0, 1000000, <<"RUB">>}),
?trm(1)
),
candidate(
condition(cost_in, {3000000, 10000000, <<"RUB">>}),
?trm(307)
)
]}
),
routing_ruleset(
?ruleset(?PAYINST1_ROUTING_POLICIES + 15),
{candidates, [
candidate(
condition(cost_in, {0, 1000000, <<"RUB">>}),
?trm(201)
),
candidate(
condition(cost_in, {3000000, 10000000, <<"RUB">>}),
?trm(307)
)
]}
),
routing_ruleset(
?ruleset(?PAYINST1_ROUTING_PROHIBITIONS),
<<"PayInst1 Withdrawal Prohibitions">>,
{candidates, [
candidate({constant, true}, ?trm(4))
]}
),
routing_ruleset(
?ruleset(?PAYINST2_ROUTING_POLICIES),
<<"PayInst2 Withdrawal Ruleset">>,
{delegates, [
delegate(
condition(cost_in, {123, <<"RUB">>}),
?ruleset(?PAYINST2_ROUTING_POLICIES + 1)
),
delegate(
{condition,
{payment_tool,
{crypto_currency, #domain_CryptoCurrencyCondition{
definition = {crypto_currency_is_deprecated, litecoin}
}}}},
?ruleset(?PAYINST2_ROUTING_POLICIES + 1)
),
delegate(
{condition,
{payment_tool,
{digital_wallet, #domain_DigitalWalletCondition{
definition = {payment_service_is, ?pmtsrv(<<"webmoney">>)}
}}}},
?ruleset(?PAYINST2_ROUTING_POLICIES + 1)
),
delegate(
{condition,
{payment_tool,
{bank_card, #domain_BankCardCondition{
definition = {issuer_country_is, 'rus'}
}}}},
?ruleset(?PAYINST2_ROUTING_POLICIES + 1)
)
]}
),
routing_ruleset(
?ruleset(?PAYINST2_ROUTING_POLICIES + 1),
<<"PayInst2 Withdrawal Ruleset #1">>,
{candidates, [
candidate(
condition(cost_in, {0, 1000000, <<"RUB">>}),
?trm(301)
),
candidate(
condition(cost_in, {3000000, 10000000, <<"RUB">>}),
?trm(307)
)
]}
),
{payment_institution, #domain_PaymentInstitutionObject{
ref = ?payinst(1),
@ -295,134 +531,14 @@ domain_config(Options) ->
default_contract_template = {value, ?tmpl(1)},
providers = {value, ?ordset([])},
withdrawal_routing_rules = #domain_RoutingRules{
policies = ?ruleset(1),
prohibitions = ?ruleset(5)
policies = ?ruleset(?PAYINST1_ROUTING_POLICIES),
prohibitions = ?ruleset(?PAYINST1_ROUTING_PROHIBITIONS)
},
inspector = {value, ?insp(1)},
residences = ['rus'],
realm = live,
wallet_system_account_set = {value, ?sas(1)},
identity = payment_inst_identity_id(Options),
withdrawal_providers =
{decisions, [
#domain_ProviderDecision{
if_ =
{condition,
{cost_in,
?cashrng(
{inclusive, ?cash(300, <<"RUB">>)},
{inclusive, ?cash(301, <<"RUB">>)}
)}},
then_ = {value, [?prv(17)]}
},
#domain_ProviderDecision{
if_ =
{condition,
{cost_in,
?cashrng(
{inclusive, ?cash(123123, <<"RUB">>)},
{inclusive, ?cash(123123, <<"RUB">>)}
)}},
then_ = {value, [?prv(16)]}
},
#domain_ProviderDecision{
if_ =
{condition,
{cost_in, #domain_CashRange{
upper =
{inclusive, #domain_Cash{
amount = 100500,
currency = #domain_CurrencyRef{symbolic_code = <<"RUB">>}
}},
lower =
{inclusive, #domain_Cash{
amount = 100500,
currency = #domain_CurrencyRef{symbolic_code = <<"RUB">>}
}}
}}},
% provider 4 will be discarded by proxy 6
then_ = {value, [?prv(4), ?prv(5)]}
},
#domain_ProviderDecision{
if_ =
{condition,
{cost_in, #domain_CashRange{
upper =
{inclusive, #domain_Cash{
amount = 500100,
currency = #domain_CurrencyRef{symbolic_code = <<"RUB">>}
}},
lower =
{inclusive, #domain_Cash{
amount = 500100,
currency = #domain_CurrencyRef{symbolic_code = <<"RUB">>}
}}
}}},
then_ = {value, [?prv(4), ?prv(6), ?prv(7), ?prv(8)]}
},
#domain_ProviderDecision{
if_ =
{condition,
{cost_in, #domain_CashRange{
upper =
{inclusive, #domain_Cash{
amount = 500500,
currency = #domain_CurrencyRef{symbolic_code = <<"RUB">>}
}},
lower =
{inclusive, #domain_Cash{
amount = 500500,
currency = #domain_CurrencyRef{symbolic_code = <<"RUB">>}
}}
}}},
then_ = {value, [?prv(9), ?prv(10)]}
},
#domain_ProviderDecision{
if_ =
{condition,
{cost_in, #domain_CashRange{
upper =
{inclusive, #domain_Cash{
amount = 700700,
currency = #domain_CurrencyRef{symbolic_code = <<"RUB">>}
}},
lower =
{inclusive, #domain_Cash{
amount = 700700,
currency = #domain_CurrencyRef{symbolic_code = <<"RUB">>}
}}
}}},
then_ = {value, [?prv(11)]}
},
#domain_ProviderDecision{
if_ = {
condition,
{payment_tool,
{bank_card, #domain_BankCardCondition{
definition = {issuer_country_is, 'rus'}
}}}
},
then_ = {value, [?prv(1)]}
},
#domain_ProviderDecision{
if_ = {condition, {payment_tool, {crypto_currency, #domain_CryptoCurrencyCondition{}}}},
then_ = {value, [?prv(2)]}
},
#domain_ProviderDecision{
if_ =
{condition,
{payment_tool,
{generic,
{payment_service_is, #domain_PaymentServiceRef{
id = <<"IND">>
}}}}},
then_ = {value, [?prv(2)]}
},
#domain_ProviderDecision{
if_ = {constant, true},
then_ = {value, []}
}
]},
payment_system =
{decisions, [
#domain_PaymentSystemDecision{
@ -470,54 +586,10 @@ domain_config(Options) ->
realm = live,
wallet_system_account_set = {value, ?sas(1)},
identity = dummy_payment_inst_identity_id(Options),
withdrawal_providers =
{decisions, [
#domain_ProviderDecision{
if_ =
{condition,
{cost_in, #domain_CashRange{
upper =
{inclusive, #domain_Cash{
amount = 123,
currency = #domain_CurrencyRef{symbolic_code = <<"RUB">>}
}},
lower =
{inclusive, #domain_Cash{
amount = 123,
currency = #domain_CurrencyRef{symbolic_code = <<"RUB">>}
}}
}}},
then_ = {value, [?prv(3)]}
withdrawal_routing_rules = #domain_RoutingRules{
policies = ?ruleset(?PAYINST2_ROUTING_POLICIES),
prohibitions = ?ruleset(?EMPTY_ROUTING_RULESET)
},
#domain_ProviderDecision{
if_ =
{condition,
{payment_tool,
{crypto_currency, #domain_CryptoCurrencyCondition{
definition = {crypto_currency_is_deprecated, litecoin}
}}}},
then_ = {value, [?prv(3)]}
},
#domain_ProviderDecision{
if_ =
{condition,
{payment_tool,
{digital_wallet, #domain_DigitalWalletCondition{
definition = {payment_service_is, ?pmtsrv(<<"webmoney">>)}
}}}},
then_ = {value, [?prv(3)]}
},
#domain_ProviderDecision{
if_ = {
condition,
{payment_tool,
{bank_card, #domain_BankCardCondition{
definition = {issuer_country_is, 'rus'}
}}}
},
then_ = {value, [?prv(3)]}
}
]},
payment_system =
{decisions, [
#domain_PaymentSystemDecision{
@ -563,34 +635,90 @@ domain_config(Options) ->
ct_domain:proxy(?prx(7), <<"Another down proxy">>, <<"http://localhost:8222/downbank2">>),
ct_domain:proxy(?prx(8), <<"Sleep proxy">>, <<"http://localhost:8222/sleepybank">>),
ct_domain:withdrawal_provider(?prv(1), ?prx(2), provider_identity_id(Options)),
ct_domain:withdrawal_provider(?prv(2), ?prx(2), provider_identity_id(Options)),
ct_domain:withdrawal_provider(?prv(3), ?prx(3), dummy_provider_identity_id(Options)),
ct_domain:withdrawal_provider(?prv(4), ?prx(6), provider_identity_id(Options)),
ct_domain:withdrawal_provider(?prv(5), ?prx(2), provider_identity_id(Options)),
ct_domain:withdrawal_provider(?prv(6), ?prx(6), provider_identity_id(Options)),
ct_domain:withdrawal_provider(?prv(7), ?prx(6), provider_identity_id(Options)),
ct_domain:withdrawal_provider(?prv(8), ?prx(2), provider_identity_id(Options)),
ct_domain:withdrawal_provider(?prv(9), ?prx(7), provider_identity_id(Options)),
ct_domain:withdrawal_provider(?prv(10), ?prx(6), provider_identity_id(Options)),
ct_domain:withdrawal_provider(?prv(11), ?prx(8), provider_identity_id(Options)),
ct_domain:withdrawal_provider(?prv(16), ?prx(2), provider_identity_id(Options)),
ct_domain:withdrawal_provider(?prv(17), ?prx(2), provider_identity_id(Options)),
ct_domain:withdrawal_provider(?prv(1), ?prx(2), provider_identity_id(Options), ProviderTermSet),
ct_domain:withdrawal_provider(?prv(2), ?prx(2), provider_identity_id(Options), ProviderTermSet),
ct_domain:withdrawal_provider(?prv(3), ?prx(3), dummy_provider_identity_id(Options), ProviderTermSet),
ct_domain:withdrawal_provider(?prv(4), ?prx(6), provider_identity_id(Options), ProviderTermSet),
ct_domain:withdrawal_provider(?prv(5), ?prx(2), provider_identity_id(Options), ProviderTermSet),
ct_domain:withdrawal_provider(?prv(6), ?prx(6), provider_identity_id(Options), ProviderTermSet),
ct_domain:withdrawal_provider(?prv(7), ?prx(6), provider_identity_id(Options), ProviderTermSet),
ct_domain:withdrawal_provider(?prv(8), ?prx(2), provider_identity_id(Options), ProviderTermSet),
ct_domain:withdrawal_provider(?prv(9), ?prx(7), provider_identity_id(Options), ProviderTermSet),
ct_domain:withdrawal_provider(?prv(10), ?prx(6), provider_identity_id(Options), ProviderTermSet),
ct_domain:withdrawal_provider(?prv(11), ?prx(8), provider_identity_id(Options), ProviderTermSet),
ct_domain:withdrawal_provider(?prv(16), ?prx(2), provider_identity_id(Options), undefined),
ct_domain:withdrawal_provider(?prv(17), ?prx(2), provider_identity_id(Options), ProviderTermSet),
ct_domain:contract_template(?tmpl(1), ?trms(1)),
ct_domain:term_set_hierarchy(?trms(1), [ct_domain:timed_term_set(default_termset(Options))]),
ct_domain:contract_template(?tmpl(2), ?trms(2)),
ct_domain:term_set_hierarchy(?trms(2), [ct_domain:timed_term_set(company_termset(Options))]),
ct_domain:withdrawal_terminal(?trm(1)),
ct_domain:withdrawal_terminal(?trm(2)),
ct_domain:withdrawal_terminal(?trm(3)),
ct_domain:withdrawal_terminal(?trm(4)),
ct_domain:withdrawal_terminal(?trm(5)),
ct_domain:withdrawal_terminal(?trm(6)),
ct_domain:withdrawal_terminal(?trm(7)),
% Provider 17 satellite
ct_domain:withdrawal_terminal(?trm(8)),
ct_domain:withdrawal_terminal(?trm(1), ?prv(1)),
ct_domain:withdrawal_terminal(?trm(2), ?prv(1)),
ct_domain:withdrawal_terminal(?trm(3), ?prv(1)),
ct_domain:withdrawal_terminal(?trm(4), ?prv(1)),
ct_domain:withdrawal_terminal(?trm(5), ?prv(1)),
ct_domain:withdrawal_terminal(?trm(6), ?prv(16)),
ct_domain:withdrawal_terminal(?trm(201), ?prv(2)),
ct_domain:withdrawal_terminal(?trm(301), ?prv(3)),
ct_domain:withdrawal_terminal(
?trm(307),
?prv(3),
#domain_ProvisionTermSet{
wallet = #domain_WalletProvisionTerms{
withdrawals = #domain_WithdrawalProvisionTerms{
currencies = {value, ?ordset([?cur(<<"BTC">>)])},
payout_methods = {value, ?ordset([])},
cash_limit =
{value,
?cashrng(
{inclusive, ?cash(1000000, <<"BTC">>)},
{exclusive, ?cash(10000000, <<"BTC">>)}
)},
cash_flow = {value, ?ordset([])}
}
}
}
),
ct_domain:withdrawal_terminal(?trm(401), ?prv(4)),
ct_domain:withdrawal_terminal(?trm(501), ?prv(5)),
ct_domain:withdrawal_terminal(?trm(601), ?prv(6)),
ct_domain:withdrawal_terminal(?trm(701), ?prv(7)),
ct_domain:withdrawal_terminal(?trm(801), ?prv(8)),
ct_domain:withdrawal_terminal(?trm(901), ?prv(9)),
ct_domain:withdrawal_terminal(?trm(1001), ?prv(10)),
ct_domain:withdrawal_terminal(?trm(1101), ?prv(11)),
ct_domain:withdrawal_terminal(?trm(1701), ?prv(17)),
ct_domain:withdrawal_terminal(
?trm(1708),
?prv(17),
#domain_ProvisionTermSet{
wallet = #domain_WalletProvisionTerms{
withdrawals = #domain_WithdrawalProvisionTerms{
cash_flow =
{decisions, [
#domain_CashFlowDecision{
if_ = {constant, true},
then_ =
{value, [
?cfpost(
{system, settlement},
{provider, settlement},
?fixed(16, <<"RUB">>)
)
]}
}
]}
}
}
}
),
ct_domain:currency(?cur(<<"RUB">>)),
ct_domain:currency(?cur(<<"USD">>)),
@ -1036,6 +1164,9 @@ company_termset(Options) ->
},
maps:get(company_termset, Options, Default).
routing_ruleset(?ruleset(ID) = Ref, Decisions) ->
routing_ruleset(Ref, genlib:format("Withdrawal Ruleset #~B", [ID]), Decisions).
routing_ruleset(Ref, Name, Decisions) ->
{routing_rules, #domain_RoutingRulesObject{
ref = Ref,
@ -1045,26 +1176,38 @@ routing_ruleset(Ref, Name, Decisions) ->
}
}}.
condition(cost_in, {Min, Max, Cur}) ->
condition(cost_in, {CostExact, Currency}) ->
{condition,
{cost_in,
?cashrng(
{inclusive, ?cash(Min, Cur)},
{exclusive, ?cash(Max, Cur)}
{inclusive, ?cash(CostExact, Currency)},
{inclusive, ?cash(CostExact, Currency)}
)}};
condition(cost_in, {Min, Max, Currency}) ->
{condition,
{cost_in,
?cashrng(
{inclusive, ?cash(Min, Currency)},
{exclusive, ?cash(Max, Currency)}
)}};
condition(party, ID) ->
{condition, {party, #domain_PartyCondition{id = ID}}}.
delegate(Allowed, RuleSetRef) ->
#domain_RoutingDelegate{
description = <<"Delagate description">>,
allowed = Allowed,
ruleset = RuleSetRef
}.
candidate(Allowed, Terminal) ->
#domain_RoutingCandidate{
description = <<"Candidate description">>,
allowed = Allowed,
terminal = Terminal
}.
candidate(Allowed, Terminal, Prio) ->
#domain_RoutingCandidate{
allowed = Allowed,
terminal = Terminal,
priority = Prio
}.

View File

@ -34,7 +34,7 @@ handle_function_('Create', {IdentityParams, Context}, Opts) ->
woody_error:raise(business, #fistful_ProviderNotFound{});
{error, {party, notfound}} ->
woody_error:raise(business, #fistful_PartyNotFound{});
{error, {inaccessible, _}} ->
{error, {party, {inaccessible, _}}} ->
woody_error:raise(business, #fistful_PartyInaccessible{});
{error, exists} ->
handle_function_('Get', {IdentityID, #'fistful_base_EventRange'{}}, Opts);

View File

@ -1043,18 +1043,7 @@ compute_fees(Route, VS, DomainRevision) ->
compute_provider_terminal_terms(#{provider_id := ProviderID, terminal_id := TerminalID}, VS, DomainRevision) ->
ProviderRef = ff_payouts_provider:ref(ProviderID),
TerminalRef = ff_payouts_terminal:ref(TerminalID),
ff_party:compute_provider_terminal_terms(ProviderRef, TerminalRef, VS, DomainRevision);
% Backward compatibility legacy case for old withrawals without terminals
compute_provider_terminal_terms(#{provider_id := ProviderID}, VS, DomainRevision) ->
ProviderRef = ff_payouts_provider:ref(ProviderID),
case ff_party:compute_provider(ProviderRef, VS, DomainRevision) of
{ok, #domain_Provider{
terms = Terms
}} ->
{ok, Terms};
{error, Error} ->
{error, Error}
end.
ff_party:compute_provider_terminal_terms(ProviderRef, TerminalRef, VS, DomainRevision).
cash_flow_postings(CashFlowSelector) ->
case CashFlowSelector of

View File

@ -29,7 +29,6 @@
-type terminal_ref() :: ff_payouts_terminal:terminal_ref().
-type terminal_id() :: ff_payouts_terminal:id().
-type terminal_priority() :: ff_payouts_terminal:terminal_priority().
-type routing_rule_route() :: ff_routing_rule:route().
-type reject_context() :: ff_routing_rule:reject_context().
@ -52,21 +51,11 @@ prepare_routes(PartyVarset, Identity, DomainRevision) ->
),
{ValidatedRoutes, RejectContext1} = filter_valid_routes(Routes, RejectContext0, PartyVarset, DomainRevision),
case ValidatedRoutes of
[_ | _] ->
{ok, ValidatedRoutes};
[] ->
ff_routing_rule:log_reject_context(RejectContext1),
logger:log(info, "Fallback to legacy method of routes gathering"),
case ff_payment_institution:withdrawal_providers(PaymentInstitution) of
{ok, Providers} ->
filter_routes_legacy(Providers, PartyVarset, DomainRevision);
{error, {misconfiguration, _Details} = Error} ->
%% TODO: Do not interpret such error as an empty route list.
%% The current implementation is made for compatibility reasons.
%% Try to remove and follow the tests.
_ = logger:warning("Route search failed: ~p", [Error]),
{error, route_not_found}
end;
_ ->
{ok, ValidatedRoutes}
end.
-spec make_route(provider_id(), terminal_id() | undefined) -> route().
@ -159,71 +148,6 @@ filter_valid_routes_([Route | Rest], PartyVarset, {Acc0, RejectContext0}, Domain
end,
filter_valid_routes_(Rest, PartyVarset, {Acc, RejectContext}, DomainRevision).
-spec filter_routes_legacy([provider_id()], party_varset(), domain_revision()) ->
{ok, [route()]} | {error, route_not_found}.
filter_routes_legacy(Providers, PartyVarset, DomainRevision) ->
do(fun() ->
unwrap(filter_routes_legacy_(Providers, PartyVarset, DomainRevision, #{}))
end).
filter_routes_legacy_([], _PartyVarset, _DomainRevision, Acc) when map_size(Acc) == 0 ->
{error, route_not_found};
filter_routes_legacy_([], _PartyVarset, _DomainRevision, Acc) ->
{ok, convert_to_route(Acc)};
filter_routes_legacy_([ProviderID | Rest], PartyVarset, DomainRevision, Acc0) ->
ProviderRef = ff_payouts_provider:ref(ProviderID),
{ok, TerminalsWithPriority} = compute_withdrawal_terminals_with_priority(ProviderRef, PartyVarset, DomainRevision),
Acc =
case get_valid_terminals_with_priority(TerminalsWithPriority, ProviderRef, PartyVarset, DomainRevision, []) of
[] ->
Acc0;
TPL ->
lists:foldl(
fun({TerminalID, Priority}, Acc1) ->
Terms = maps:get(Priority, Acc1, []),
maps:put(Priority, [{ProviderID, TerminalID} | Terms], Acc1)
end,
Acc0,
TPL
)
end,
filter_routes_legacy_(Rest, PartyVarset, DomainRevision, Acc).
-spec compute_withdrawal_terminals_with_priority(provider_ref(), party_varset(), domain_revision()) ->
{ok, [{terminal_id(), terminal_priority()}]} | {error, term()}.
compute_withdrawal_terminals_with_priority(ProviderRef, VS, DomainRevision) ->
case ff_party:compute_provider(ProviderRef, VS, DomainRevision) of
{ok, Provider} ->
case Provider of
#domain_Provider{
terminal = {value, Terminals}
} ->
{ok, [
{TerminalID, Priority}
|| #domain_ProviderTerminalRef{id = TerminalID, priority = Priority} <- Terminals
]};
_ ->
Error = {misconfiguration, {missing, terminal_selector}},
_ = logger:warning("Provider terminal search failed: ~p", [Error]),
{ok, []}
end;
{error, Error} ->
{error, Error}
end.
get_valid_terminals_with_priority([], _ProviderRef, _PartyVarset, _DomainRevision, Acc) ->
Acc;
get_valid_terminals_with_priority([{TerminalID, Priority} | Rest], ProviderRef, PartyVarset, DomainRevision, Acc0) ->
TerminalRef = ff_payouts_terminal:ref(TerminalID),
Acc =
case validate_terms(ProviderRef, TerminalRef, PartyVarset, DomainRevision) of
{ok, valid} ->
[{TerminalID, Priority} | Acc0];
{error, _Error} ->
Acc0
end,
get_valid_terminals_with_priority(Rest, ProviderRef, PartyVarset, DomainRevision, Acc).
-spec validate_terms(provider_ref(), terminal_ref(), party_varset(), domain_revision()) ->
{ok, valid}
| {error, Error :: term()}.

View File

@ -2,7 +2,6 @@
-include_lib("fistful_proto/include/ff_proto_fistful_admin_thrift.hrl").
-include_lib("fistful_proto/include/ff_proto_withdrawal_thrift.hrl").
-include_lib("damsel/include/dmsl_domain_thrift.hrl").
-export([all/0]).
-export([groups/0]).
@ -380,7 +379,7 @@ deposit_quote_withdrawal_ok(C) ->
created_at => <<"2016-03-22T06:12:27Z">>,
expires_on => <<"2016-03-22T06:12:27Z">>,
quote_data => #{<<"test">> => <<"test">>},
route => ff_withdrawal_routing:make_route(3, 1),
route => ff_withdrawal_routing:make_route(3, 301),
domain_revision => DomainRevision,
party_revision => PartyRevision
}

View File

@ -179,7 +179,7 @@ session_fail_test(C) ->
cash_to => {2120, <<"USD">>},
created_at => <<"2016-03-22T06:12:27Z">>,
expires_on => <<"2016-03-22T06:12:27Z">>,
route => ff_withdrawal_routing:make_route(3, 1),
route => ff_withdrawal_routing:make_route(3, 301),
quote_data => #{<<"test">> => <<"error">>},
operation_timestamp => ff_time:now()
}
@ -704,7 +704,7 @@ session_repair_test(C) ->
cash_to => {700700, <<"RUB">>},
created_at => <<"2016-03-22T06:12:27Z">>,
expires_on => <<"2016-03-22T06:12:27Z">>,
route => ff_withdrawal_routing:make_route(11, 1),
route => ff_withdrawal_routing:make_route(11, 1101),
quote_data => #{<<"test">> => <<"fatal">>},
operation_timestamp => ff_time:now()
}
@ -748,8 +748,8 @@ provider_terminal_terms_merging_test(C) ->
end,
{Route1, VolumeEntries1} = ProduceWithdrawal({300, <<"RUB">>}),
{Route2, VolumeEntries2} = ProduceWithdrawal({301, <<"RUB">>}),
?assertMatch(#{provider_id := 17, terminal_id := 1}, Route1),
?assertMatch(#{provider_id := 17, terminal_id := 8}, Route2),
?assertMatch(#{provider_id := 17, terminal_id := 1701}, Route1),
?assertMatch(#{provider_id := 17, terminal_id := 1708}, Route2),
?assertEqual([300, 30, 30, 10], VolumeEntries1),
?assertEqual([301, 30, 30, 16], VolumeEntries2).

View File

@ -186,7 +186,7 @@ adapter_unreachable_quote_test(C) ->
cash_to => {2120, <<"USD">>},
created_at => <<"2020-03-22T06:12:27Z">>,
expires_on => <<"2020-03-22T06:12:27Z">>,
route => ff_withdrawal_routing:make_route(4, 1),
route => ff_withdrawal_routing:make_route(4, 401),
quote_data => #{<<"test">> => <<"test">>},
operation_timestamp => ff_time:now()
}

View File

@ -7,26 +7,19 @@
-export([cleanup/0]).
-export([get_woody_context/1]).
-export([set_woody_context/2]).
-export([get_user_identity/1]).
-export([set_user_identity/2]).
-export([get_party_client_context/1]).
-export([set_party_client_context/2]).
-export([get_party_client/1]).
-export([set_party_client/2]).
-opaque context() :: #{
woody_context := woody_context(),
party_client_context := party_client_context(),
party_client => party_client(),
user_identity => user_identity()
party_client => party_client()
}.
-type options() :: #{
party_client => party_client(),
user_identity => user_identity(),
woody_context => woody_context(),
party_client_context => party_client_context()
party_client_context => party_client_context(),
party_client => party_client()
}.
-export_type([context/0]).
@ -34,7 +27,6 @@
%% Internal types
-type user_identity() :: woody_user_identity:user_identity().
-type woody_context() :: woody_context:ctx().
-type party_client() :: party_client:client().
-type party_client_context() :: party_client:context().
@ -73,48 +65,19 @@ cleanup() ->
ok.
-spec get_woody_context(context()) -> woody_context().
get_woody_context(Context) ->
#{woody_context := WoodyContext} = ensure_woody_user_info_set(Context),
get_woody_context(#{woody_context := WoodyContext}) ->
WoodyContext.
-spec set_woody_context(woody_context(), context()) -> context().
set_woody_context(WoodyContext, #{party_client_context := PartyContext0} = Context) ->
PartyContext1 = party_client_context:set_woody_context(WoodyContext, PartyContext0),
Context#{
woody_context => WoodyContext,
party_client_context => PartyContext1
}.
-spec get_party_client(context()) -> party_client().
get_party_client(#{party_client := PartyClient}) ->
PartyClient;
get_party_client(Context) ->
error(no_party_client, [Context]).
-spec set_party_client(party_client(), context()) -> context().
set_party_client(PartyClient, Context) ->
Context#{party_client => PartyClient}.
-spec get_party_client_context(context()) -> party_client_context().
get_party_client_context(Context) ->
#{party_client_context := PartyContext} = ensure_party_user_info_set(Context),
get_party_client_context(#{party_client_context := PartyContext}) ->
PartyContext.
-spec set_party_client_context(party_client_context(), context()) -> context().
set_party_client_context(PartyContext, Context) ->
Context#{party_client_context := PartyContext}.
-spec get_user_identity(context()) -> user_identity() | no_return().
get_user_identity(#{user_identity := Identity}) ->
Identity;
get_user_identity(Context) ->
WoodyContext = get_woody_context(Context),
woody_user_identity:get(WoodyContext).
-spec set_user_identity(user_identity(), context()) -> context().
set_user_identity(Identity, Context) ->
Context#{user_identity => Identity}.
%% Internal functions
-spec ensure_woody_context_exists(options()) -> options().
@ -128,17 +91,3 @@ ensure_party_context_exists(#{party_client_context := _PartyContext} = Options)
Options;
ensure_party_context_exists(#{woody_context := WoodyContext} = Options) ->
Options#{party_client_context => party_client:create_context(#{woody_context => WoodyContext})}.
-spec ensure_woody_user_info_set(context()) -> context().
ensure_woody_user_info_set(#{user_identity := Identity, woody_context := WoodyContext} = Context) ->
NewWoodyContext = woody_user_identity:put(Identity, WoodyContext),
Context#{woody_context := NewWoodyContext};
ensure_woody_user_info_set(Context) ->
Context.
-spec ensure_party_user_info_set(context()) -> context().
ensure_party_user_info_set(#{user_identity := Identity, party_client_context := PartyContext} = Context) ->
NewPartyContext = party_client_context:set_user_info(Identity, PartyContext),
Context#{party_client_context := NewPartyContext};
ensure_party_user_info_set(Context) ->
Context.

View File

@ -73,8 +73,7 @@
-type create_error() ::
{provider, notfound}
| {party, notfound}
| ff_party:inaccessibility()
| {party, notfound | ff_party:inaccessibility()}
| invalid.
-type get_terms_params() :: #{

View File

@ -87,7 +87,6 @@
-export([get_contract_terms/6]).
-export([compute_payment_institution/3]).
-export([compute_routing_ruleset/3]).
-export([compute_provider/3]).
-export([compute_provider_terminal_terms/4]).
-export([get_withdrawal_cash_flow_plan/1]).
-export([get_w2w_cash_flow_plan/1]).
@ -114,7 +113,6 @@
-type provider_ref() :: dmsl_domain_thrift:'ProviderRef'().
-type terminal_ref() :: dmsl_domain_thrift:'TerminalRef'().
-type method_ref() :: dmsl_domain_thrift:'PaymentMethodRef'().
-type provider() :: dmsl_domain_thrift:'Provider'().
-type provision_term_set() :: dmsl_domain_thrift:'ProvisionTermSet'().
-type bound_type() :: 'exclusive' | 'inclusive'.
-type cash_range() :: {{bound_type(), cash()}, {bound_type(), cash()}}.
@ -165,7 +163,8 @@ create(ID, Params) ->
-spec is_accessible(id()) ->
{ok, accessible}
| {error, inaccessibility()}.
| {error, inaccessibility()}
| {error, notfound}.
is_accessible(ID) ->
case do_get_party(ID) of
#domain_Party{blocking = {blocked, _}} ->
@ -185,9 +184,7 @@ get_revision(ID) ->
{ok, Revision} ->
{ok, Revision};
{error, #payproc_PartyNotFound{}} ->
{error, {party_not_found, ID}};
{error, Unexpected} ->
error(Unexpected)
{error, {party_not_found, ID}}
end.
%%
@ -271,9 +268,7 @@ get_contract_terms(PartyID, ContractID, Varset, Timestamp, PartyRevision, Domain
{error, #payproc_ContractNotFound{}} ->
{error, {contract_not_found, ContractID}};
{error, #payproc_PartyNotExistsYet{}} ->
{error, {party_not_exists_yet, PartyID}};
{error, Unexpected} ->
erlang:error({unexpected, Unexpected})
{error, {party_not_exists_yet, PartyID}}
end.
-spec compute_payment_institution(PaymentInstitutionRef, Varset, DomainRevision) -> Result when
@ -320,28 +315,6 @@ compute_routing_ruleset(RoutingRulesetRef, Varset, DomainRevision) ->
{error, ruleset_not_found}
end.
-spec compute_provider(ProviderRef, Varset, DomainRevision) -> Result when
ProviderRef :: provider_ref(),
Varset :: ff_varset:varset(),
DomainRevision :: domain_revision(),
Result :: {ok, provider()} | {error, provider_not_found}.
compute_provider(ProviderRef, Varset, DomainRevision) ->
DomainVarset = ff_varset:encode(Varset),
{Client, Context} = get_party_client(),
Result = party_client_thrift:compute_provider(
ProviderRef,
DomainRevision,
DomainVarset,
Client,
Context
),
case Result of
{ok, Provider} ->
{ok, Provider};
{error, #payproc_ProviderNotFound{}} ->
{error, provider_not_found}
end.
-spec compute_provider_terminal_terms(ProviderRef, TerminalRef, Varset, DomainRevision) -> Result when
ProviderRef :: provider_ref(),
TerminalRef :: terminal_ref(),
@ -484,9 +457,7 @@ do_create_party(ID, Params) ->
ok ->
ok;
{error, #payproc_PartyExists{}} ->
{error, exists};
{error, Unexpected} ->
error(Unexpected)
{error, exists}
end.
do_get_party(ID) ->
@ -499,9 +470,7 @@ do_get_party(ID) ->
{ok, Party} ->
Party;
{error, #payproc_PartyNotFound{} = Reason} ->
Reason;
{error, Unexpected} ->
error(Unexpected)
Reason
end.
do_get_contract(ID, ContractID) ->
@ -512,9 +481,7 @@ do_get_contract(ID, ContractID) ->
{error, #payproc_PartyNotFound{}} ->
{error, {party_not_found, ID}};
{error, #payproc_ContractNotFound{}} ->
{error, {contract_not_found, ContractID}};
{error, Unexpected} ->
error(Unexpected)
{error, {contract_not_found, ContractID}}
end.
do_create_claim(ID, Changeset) ->
@ -527,9 +494,7 @@ do_create_claim(ID, Changeset) ->
}} ->
{error, invalid};
{error, #payproc_InvalidPartyStatus{status = Status}} ->
{error, construct_inaccessibilty(Status)};
{error, Unexpected} ->
error(Unexpected)
{error, construct_inaccessibilty(Status)}
end.
do_accept_claim(ID, Claim) ->
@ -543,31 +508,15 @@ do_accept_claim(ID, Claim) ->
ok ->
accepted;
{error, #payproc_InvalidClaimStatus{status = {accepted, _}}} ->
accepted;
{error, Unexpected} ->
error(Unexpected)
accepted
end.
get_party_client() ->
% TODO
% - Move auth logic from hellgate to capi the same way as it works
% in wapi & fistful. Then the following dirty user_identity hack
% will not be necessary anymore.
Context0 = ff_context:load(),
WoodyContextWithoutMeta = maps:without([meta], ff_context:get_woody_context(Context0)),
Context1 = ff_context:set_woody_context(WoodyContextWithoutMeta, Context0),
Context2 = ff_context:set_user_identity(construct_user_identity(), Context1),
Client = ff_context:get_party_client(Context2),
ClientContext = ff_context:get_party_client_context(Context2),
Context = ff_context:load(),
Client = ff_context:get_party_client(Context),
ClientContext = ff_context:get_party_client_context(Context),
{Client, ClientContext}.
-spec construct_user_identity() -> woody_user_identity:user_identity().
construct_user_identity() ->
#{
id => <<"fistful">>,
realm => <<"service">>
}.
construct_inaccessibilty({blocking, _}) ->
{inaccessible, blocked};
construct_inaccessibilty({suspension, _}) ->
@ -583,10 +532,6 @@ construct_inaccessibilty({suspension, _}) ->
{contract_modification, #payproc_ContractModificationUnit{id = ID, modification = Mod}}
).
-define(WALLET_MOD(ID, Mod),
{wallet_modification, #payproc_WalletModificationUnit{id = ID, modification = Mod}}
).
construct_party_params(#{email := Email}) ->
#payproc_PartyParams{
contact_info = #domain_PartyContactInfo{

View File

@ -11,7 +11,6 @@
id := id(),
system_accounts := dmsl_domain_thrift:'SystemAccountSetSelector'(),
identity := binary(),
withdrawal_providers := dmsl_domain_thrift:'ProviderSelector'(),
withdrawal_routing_rules := dmsl_domain_thrift:'RoutingRules'(),
payment_system => dmsl_domain_thrift:'PaymentSystemSelector'()
}.
@ -35,7 +34,6 @@
-export([ref/1]).
-export([get/3]).
-export([withdrawal_providers/1]).
-export([system_accounts/2]).
-export([payment_system/1]).
@ -86,17 +84,6 @@ payment_system(#{payment_system := PaymentSystem}) ->
payment_system(_PaymentInstitution) ->
{ok, undefined}.
-spec withdrawal_providers(payment_institution()) ->
{ok, [ff_payouts_provider:id()]}
| {error, term()}.
withdrawal_providers(#{withdrawal_providers := ProvidersSelector}) ->
case get_selector_value(withdrawal_providers, ProvidersSelector) of
{ok, Providers} ->
{ok, [ProviderID || #domain_ProviderRef{id = ProviderID} <- Providers]};
{error, Error} ->
{error, Error}
end.
-spec system_accounts(payment_institution(), domain_revision()) ->
{ok, system_accounts()}
| {error, term()}.
@ -116,7 +103,6 @@ system_accounts(PaymentInstitution, DomainRevision) ->
decode(ID, #domain_PaymentInstitution{
wallet_system_account_set = SystemAccounts,
identity = Identity,
withdrawal_providers = WithdrawalProviders,
withdrawal_routing_rules = WithdrawalRoutingRules,
payment_system = PaymentSystem
}) ->
@ -124,7 +110,6 @@ decode(ID, #domain_PaymentInstitution{
id => ID,
system_accounts => SystemAccounts,
identity => Identity,
withdrawal_providers => WithdrawalProviders,
withdrawal_routing_rules => WithdrawalRoutingRules,
payment_system => PaymentSystem
}).

View File

@ -8,8 +8,7 @@
terms => dmsl_domain_thrift:'ProvisionTermSet'(),
accounts := accounts(),
adapter := ff_adapter:adapter(),
adapter_opts := map(),
terminal => dmsl_domain_thrift:'TerminalSelector'()
adapter_opts := map()
}.
-type id() :: dmsl_domain_thrift:'ObjectID'().
@ -98,8 +97,7 @@ decode(ID, #domain_Provider{
proxy = Proxy,
identity = Identity,
terms = Terms,
accounts = Accounts,
terminal = TerminalSelector
accounts = Accounts
}) ->
genlib_map:compact(
maps:merge(
@ -107,8 +105,7 @@ decode(ID, #domain_Provider{
id => ID,
identity => Identity,
terms => Terms,
accounts => decode_accounts(Identity, Accounts),
terminal => TerminalSelector
accounts => decode_accounts(Identity, Accounts)
},
decode_adapter(Proxy)
)

View File

@ -65,26 +65,16 @@ gather_routes(PaymentInstitution, RoutingRuleTag, VS, Revision) ->
| {error, misconfiguration}.
do_gather_routes(PaymentInstitution, RoutingRuleTag, VS, Revision) ->
do(fun() ->
case maps:get(RoutingRuleTag, PaymentInstitution, undefined) of
undefined ->
logger:log(
warning,
"RoutingRules ~p is undefined, PaymentInstitution: ~p",
[RoutingRuleTag, PaymentInstitution]
),
{[], []};
RoutingRules ->
RoutingRules = maps:get(RoutingRuleTag, PaymentInstitution),
Policies = RoutingRules#domain_RoutingRules.policies,
Prohibitions = RoutingRules#domain_RoutingRules.prohibitions,
PermitCandidates = unwrap(compute_routing_ruleset(Policies, VS, Revision)),
DenyCandidates = unwrap(compute_routing_ruleset(Prohibitions, VS, Revision)),
{AcceptedRoutes, RejectedRoutes} = prohibited_candidates_filter(
filter_prohibited_candidates(
PermitCandidates,
DenyCandidates,
Revision
),
{AcceptedRoutes, RejectedRoutes}
end
)
end).
-spec compute_routing_ruleset(routing_ruleset_ref(), varset(), revision()) ->
@ -115,8 +105,8 @@ check_ruleset_computing({candidates, Candidates}) ->
{error, misconfiguration}
end.
-spec prohibited_candidates_filter([candidate()], [candidate()], revision()) -> {[route()], [rejected_route()]}.
prohibited_candidates_filter(Candidates, ProhibitedCandidates, Revision) ->
-spec filter_prohibited_candidates([candidate()], [candidate()], revision()) -> {[route()], [rejected_route()]}.
filter_prohibited_candidates(Candidates, ProhibitedCandidates, Revision) ->
ProhibitionTable = lists:foldl(
fun(C, Acc) ->
Acc#{get_terminal_ref(C) => get_description(C)}

View File

@ -11,7 +11,6 @@
machinery,
machinery_extra,
woody,
woody_user_identity,
uuid,
damsel,
dmt_client,

View File

@ -8,7 +8,7 @@
-behaviour(machinery_backend).
-type namespace() :: machinery:namespace().
-type backend() :: machinery:backend(machinery:backend(_)).
-type backend() :: machinery:backend(_).
-type options() :: #{
handler := machinery:modopts(_),

View File

@ -7,7 +7,9 @@
-export([end_per_testcase/2]).
-export([get_missing_fails/1]).
-export([create_missing_fails/1]).
-export([create_missing_party_fails/1]).
-export([create_inaccessible_party_fails/1]).
-export([create_missing_provider_fails/1]).
-export([create_ok/1]).
%%
@ -23,12 +25,16 @@
all() ->
[
get_missing_fails,
create_missing_fails,
create_missing_party_fails,
create_inaccessible_party_fails,
create_missing_provider_fails,
create_ok
].
-spec get_missing_fails(config()) -> test_return().
-spec create_missing_fails(config()) -> test_return().
-spec create_missing_party_fails(config()) -> test_return().
-spec create_inaccessible_party_fails(config()) -> test_return().
-spec create_missing_provider_fails(config()) -> test_return().
-spec create_ok(config()) -> test_return().
-spec init_per_suite(config()) -> config().
@ -65,7 +71,36 @@ get_missing_fails(_C) ->
ID = genlib:unique(),
{error, notfound} = ff_identity_machine:get(ID).
create_missing_fails(C) ->
create_missing_party_fails(_C) ->
ID = genlib:unique(),
NonexistentParty = genlib:bsuuid(),
Name = <<"Identity Name">>,
{error, {party, notfound}} = ff_identity_machine:create(
#{
id => ID,
name => Name,
party => NonexistentParty,
provider => <<"good-one">>
},
#{<<"dev.vality.wapi">> => #{<<"name">> => Name}}
).
create_inaccessible_party_fails(C) ->
ID = genlib:unique(),
PartyID = create_party(C),
ok = block_party(PartyID, genlib:to_binary(?FUNCTION_NAME)),
Name = <<"Identity Name">>,
{error, {party, {inaccessible, blocked}}} = ff_identity_machine:create(
#{
id => ID,
name => Name,
party => PartyID,
provider => <<"good-one">>
},
#{<<"dev.vality.wapi">> => #{<<"name">> => Name}}
).
create_missing_provider_fails(C) ->
ID = genlib:unique(),
Party = create_party(C),
Name = <<"Identity Name">>,
@ -76,7 +111,7 @@ create_missing_fails(C) ->
party => Party,
provider => <<"who">>
},
#{<<"com.rbkmoney.wapi">> => #{<<"name">> => Name}}
#{<<"dev.vality.wapi">> => #{<<"name">> => Name}}
).
create_ok(C) ->
@ -90,7 +125,7 @@ create_ok(C) ->
party => Party,
provider => <<"good-one">>
},
#{<<"com.rbkmoney.wapi">> => #{<<"name">> => Name}}
#{<<"dev.vality.wapi">> => #{<<"name">> => Name}}
),
I1 = ff_identity_machine:identity(unwrap(ff_identity_machine:get(ID))),
{ok, accessible} = ff_identity:is_accessible(I1),
@ -100,3 +135,9 @@ create_party(_C) ->
ID = genlib:bsuuid(),
_ = ff_party:create(ID),
ID.
block_party(ID, Reason) ->
Context = ff_context:load(),
Client = ff_context:get_party_client(Context),
ClientContext = ff_context:get_party_client_context(Context),
party_client_thrift:block(ID, Reason, Client, ClientContext).

View File

@ -1,7 +1,6 @@
-module(ff_routing_rule_SUITE).
-include_lib("stdlib/include/assert.hrl").
-include_lib("damsel/include/dmsl_domain_thrift.hrl").
-include_lib("ff_cth/include/ct_domain.hrl").
%% Common test API
@ -21,7 +20,6 @@
-export([withdrawal_no_routes_found_test/1]).
-export([withdrawal_rejected_by_prohibitions_table_test/1]).
-export([withdrawal_ruleset_misconfig_test/1]).
-export([withdrawal_rules_not_found_test/1]).
%% Internal types
@ -47,8 +45,7 @@ groups() ->
withdrawal_routes_found_test,
withdrawal_no_routes_found_test,
withdrawal_rejected_by_prohibitions_table_test,
withdrawal_ruleset_misconfig_test,
withdrawal_rules_not_found_test
withdrawal_ruleset_misconfig_test
]}
].
@ -129,7 +126,7 @@ withdrawal_rejected_by_prohibitions_table_test(_C) ->
],
#{
rejected_routes := [
{_, ?trm(4), {'RoutingRule', <<"Candidate description">>}}
{_, ?trm(4), {'RoutingRule', undefined}}
]
}
},
@ -148,18 +145,6 @@ withdrawal_ruleset_misconfig_test(_C) ->
gather_routes(withdrawal_routing_rules, PaymentInstitutionID, VS)
).
-spec withdrawal_rules_not_found_test(config()) -> test_return().
withdrawal_rules_not_found_test(_C) ->
VS = make_varset(?cash(1000, <<"RUB">>), <<"12345">>),
PaymentInstitutionID = 2,
?assertMatch(
{
[],
#{rejected_routes := []}
},
gather_routes(withdrawal_routing_rules, PaymentInstitutionID, VS)
).
%%
make_varset(Cash, PartyID) ->

View File

@ -69,7 +69,7 @@ services:
retries: 20
party-management:
image: ghcr.io/valitydev/party-management:sha-e456e24
image: ghcr.io/valitydev/party-management:sha-f757b79
command: /opt/party-management/bin/party-management foreground
depends_on:
machinegun:

View File

@ -33,7 +33,6 @@
{scoper, {git, "https://github.com/valitydev/scoper.git", {branch, "master"}}},
{thrift, {git, "https://github.com/valitydev/thrift_erlang.git", {branch, "master"}}},
{woody, {git, "https://github.com/valitydev/woody_erlang.git", {branch, "master"}}},
{woody_user_identity, {git, "https://github.com/valitydev/woody_erlang_user_identity.git", {branch, "master"}}},
{erl_health, {git, "https://github.com/valitydev/erlang-health.git", {branch, "master"}}},
{machinery, {git, "https://github.com/valitydev/machinery.git", {branch, "master"}}},
{damsel, {git, "https://github.com/valitydev/damsel.git", {branch, "master"}}},

View File

@ -53,7 +53,7 @@
{<<"parse_trans">>,{pkg,<<"parse_trans">>,<<"3.3.1">>},2},
{<<"party_client">>,
{git,"https://github.com/valitydev/party-client-erlang.git",
{ref,"8fc5595c4c61c0fe3d2dc29a61f48ba94e9bdef7"}},
{ref,"31850a63f6c00da7e10897b23298ad38f9bf448d"}},
0},
{<<"prometheus">>,{pkg,<<"prometheus">>,<<"4.8.1">>},0},
{<<"prometheus_cowboy">>,{pkg,<<"prometheus_cowboy">>,<<"0.1.8">>},0},
@ -85,10 +85,6 @@
{<<"woody">>,
{git,"https://github.com/valitydev/woody_erlang.git",
{ref,"6f818c57e3b19f96260b1f968115c9bc5bcad4d2"}},
0},
{<<"woody_user_identity">>,
{git,"https://github.com/valitydev/woody_erlang_user_identity.git",
{ref,"a480762fea8d7c08f105fb39ca809482b6cb042e"}},
0}]}.
[
{pkg_hash,[