Skip to content

Commit 7305ff0

Browse files
authored
TD-820: Refactors routing to support critical score rejections (#105)
* TD-820: Refactors routing to support critical score rejections * Moves routing context helpers to appropriate module * Splits large functions, fixes misconfiguration error bug * Fixes second fail rates query * Fixes routes equality check * Extracts route struct functions * Extracts routing context into separate module * Fixes rejected routes ordering consistency * Fixes funx naming and adds routes equality tests * Makes rejected routes reasons more explicit in code * Adds routing ctx pipeline test * Adds specified routing sub failures * Updates tests; replaces static errors translation * Fixes ubiquity of availability status naming * Updates route reject error codes * Bumps damsel
1 parent 42af922 commit 7305ff0

14 files changed

+954
-510
lines changed

apps/hellgate/include/hg_invoice_payment.hrl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
activity :: hg_invoice_payment:activity(),
66
payment :: undefined | hg_invoice_payment:payment(),
77
risk_score :: undefined | hg_inspector:risk_score(),
8-
routes = [] :: [hg_routing:payment_route()],
9-
candidate_routes :: undefined | [hg_routing:payment_route()],
8+
routes = [] :: [hg_route:payment_route()],
9+
candidate_routes :: undefined | [hg_route:payment_route()],
1010
interim_payment_status :: undefined | hg_invoice_payment:payment_status(),
1111
new_cash :: undefined | hg_cash:cash(),
1212
new_cash_provided :: undefined | boolean(),

apps/hellgate/src/hg_accounting.erl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
-type payment() :: dmsl_domain_thrift:'InvoicePayment'().
4040
-type party() :: dmsl_domain_thrift:'Party'().
4141
-type shop() :: dmsl_domain_thrift:'Shop'().
42-
-type route() :: hg_routing:payment_route().
42+
-type route() :: hg_route:payment_route().
4343
-type payment_institution() :: dmsl_domain_thrift:'PaymentInstitution'().
4444
-type provider() :: dmsl_domain_thrift:'Provider'().
4545
-type varset() :: hg_varset:varset().

apps/hellgate/src/hg_cascade.erl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
-spec is_triggered(
1313
cascade_behaviour() | undefined,
1414
operation_failure(),
15-
hg_routing:payment_route(),
15+
hg_route:payment_route(),
1616
[hg_session:t()]
1717
) ->
1818
boolean().

apps/hellgate/src/hg_cashflow.erl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929

3030
-type shop_id() :: dmsl_domain_thrift:'ShopID'().
3131
-type party_id() :: dmsl_domain_thrift:'PartyID'().
32-
-type route() :: hg_routing:payment_route().
32+
-type route() :: hg_route:payment_route().
3333

3434
%%
3535

apps/hellgate/src/hg_invoice_payment.erl

Lines changed: 221 additions & 235 deletions
Large diffs are not rendered by default.

apps/hellgate/src/hg_limiter.erl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
-type turnover_limit() :: dmsl_domain_thrift:'TurnoverLimit'().
1212
-type invoice() :: dmsl_domain_thrift:'Invoice'().
1313
-type payment() :: dmsl_domain_thrift:'InvoicePayment'().
14-
-type route() :: hg_routing:payment_route().
14+
-type route() :: hg_route:payment_route().
1515
-type refund() :: hg_invoice_payment:domain_refund().
1616
-type cash() :: dmsl_domain_thrift:'Cash'().
1717
-type handling_flag() :: ignore_business_error.

apps/hellgate/src/hg_proxy_provider.erl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
%%
2121

2222
-type trx_info() :: hg_invoice_payment:trx_info().
23-
-type route() :: hg_routing:payment_route().
23+
-type route() :: hg_route:payment_route().
2424

2525
-type change() :: dmsl_payproc_thrift:'SessionChangePayload'().
2626
-type proxy_state() :: dmsl_base_thrift:'Opaque'().

apps/hellgate/src/hg_recurrent_paytool.erl

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
-type rec_payment_tool_change() :: dmsl_payproc_thrift:'RecurrentPaymentToolChange'().
5252
-type rec_payment_tool_params() :: dmsl_payproc_thrift:'RecurrentPaymentToolParams'().
5353

54-
-type route() :: hg_routing:payment_route().
54+
-type route() :: hg_route:payment_route().
5555
-type risk_score() :: hg_inspector:risk_score().
5656
-type shop() :: dmsl_domain_thrift:'Shop'().
5757
-type party() :: dmsl_domain_thrift:'Party'().
@@ -251,7 +251,7 @@ init(EncodedParams, #{id := RecPaymentToolID}) ->
251251
client_ip => get_client_info_ip(Params#payproc_RecurrentPaymentToolParams.payment_resource)
252252
}),
253253
{ChosenRoute, ChoiceContext} = hg_routing:choose_route(NonFailRatedRoutes),
254-
ChosenPaymentRoute = hg_routing:to_payment_route(ChosenRoute),
254+
ChosenPaymentRoute = hg_route:to_payment_route(ChosenRoute),
255255
LoggerMetadata = hg_routing:get_logger_metadata(ChoiceContext, Revision),
256256
_ = logger:log(info, "Routing decision made", #{routing => LoggerMetadata}),
257257
RecPaymentTool2 = set_minimal_payment_cost(RecPaymentTool, ChosenPaymentRoute, VS, Revision),
@@ -274,20 +274,13 @@ init(EncodedParams, #{id := RecPaymentToolID}) ->
274274

275275
gather_routes(PaymentInstitution, VS, Revision, Ctx) ->
276276
Predestination = recurrent_paytool,
277-
case
278-
hg_routing:gather_routes(
279-
Predestination,
280-
PaymentInstitution,
281-
VS,
282-
Revision,
283-
Ctx
284-
)
285-
of
286-
{ok, {[], RejectedRoutes}} ->
287-
throw({no_route_found, {unknown, RejectedRoutes}});
288-
{ok, {Routes, _RejectContext}} ->
277+
RoutingCtx = hg_routing:gather_routes(Predestination, PaymentInstitution, VS, Revision, Ctx),
278+
case {hg_routing_ctx:candidates(RoutingCtx), hg_routing_ctx:error(RoutingCtx)} of
279+
{[], undefined} ->
280+
throw({no_route_found, {unknown, hg_routing_ctx:rejected_routes(RoutingCtx)}});
281+
{Routes, undefined} ->
289282
Routes;
290-
{error, {misconfiguration, _Reason}} ->
283+
{_Routes, {misconfiguration, _Reason}} ->
291284
throw({no_route_found, misconfiguration})
292285
end.
293286

apps/hellgate/src/hg_route.erl

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
-module(hg_route).
2+
3+
-export([new/2]).
4+
-export([new/4]).
5+
-export([new/5]).
6+
-export([new/6]).
7+
-export([provider_ref/1]).
8+
-export([terminal_ref/1]).
9+
-export([priority/1]).
10+
-export([weight/1]).
11+
-export([set_weight/2]).
12+
-export([pin/1]).
13+
-export([fd_overrides/1]).
14+
15+
-export([equal/2]).
16+
17+
-export([from_payment_route/1]).
18+
-export([to_payment_route/1]).
19+
-export([to_rejected_route/2]).
20+
21+
%%
22+
23+
-include("domain.hrl").
24+
25+
-record(route, {
26+
provider_ref :: dmsl_domain_thrift:'ProviderRef'(),
27+
terminal_ref :: dmsl_domain_thrift:'TerminalRef'(),
28+
weight :: integer(),
29+
priority :: integer(),
30+
pin :: pin(),
31+
fd_overrides :: fd_overrides()
32+
}).
33+
34+
-type t() :: #route{}.
35+
-type payment_route() :: dmsl_domain_thrift:'PaymentRoute'().
36+
-type route_rejection_reason() :: {atom(), _DescOrAttrs} | {atom(), _DescOrAttrs1, _DescOrAttrs2}.
37+
-type rejected_route() :: {provider_ref(), terminal_ref(), route_rejection_reason()}.
38+
-type provider_ref() :: dmsl_domain_thrift:'ProviderRef'().
39+
-type terminal_ref() :: dmsl_domain_thrift:'TerminalRef'().
40+
-type fd_overrides() :: dmsl_domain_thrift:'RouteFaultDetectorOverrides'().
41+
42+
-type currency() :: dmsl_domain_thrift:'CurrencyRef'().
43+
-type payment_tool() :: dmsl_domain_thrift:'PaymentTool'().
44+
-type party_id() :: dmsl_domain_thrift:'PartyID'().
45+
-type client_ip() :: dmsl_domain_thrift:'IPAddress'().
46+
47+
-type pin() :: #{
48+
currency => currency(),
49+
payment_tool => payment_tool(),
50+
party_id => party_id(),
51+
client_ip => client_ip() | undefined
52+
}.
53+
54+
-export_type([t/0]).
55+
-export_type([provider_ref/0]).
56+
-export_type([terminal_ref/0]).
57+
-export_type([payment_route/0]).
58+
-export_type([rejected_route/0]).
59+
60+
%%
61+
62+
-spec new(provider_ref(), terminal_ref()) -> t().
63+
new(ProviderRef, TerminalRef) ->
64+
new(
65+
ProviderRef,
66+
TerminalRef,
67+
?DOMAIN_CANDIDATE_WEIGHT,
68+
?DOMAIN_CANDIDATE_PRIORITY
69+
).
70+
71+
-spec new(provider_ref(), terminal_ref(), integer() | undefined, integer()) -> t().
72+
new(ProviderRef, TerminalRef, Weight, Priority) ->
73+
new(ProviderRef, TerminalRef, Weight, Priority, #{}).
74+
75+
-spec new(provider_ref(), terminal_ref(), integer() | undefined, integer(), pin()) -> t().
76+
new(ProviderRef, TerminalRef, undefined, Priority, Pin) ->
77+
new(ProviderRef, TerminalRef, ?DOMAIN_CANDIDATE_WEIGHT, Priority, Pin);
78+
new(ProviderRef, TerminalRef, Weight, Priority, Pin) ->
79+
new(ProviderRef, TerminalRef, Weight, Priority, Pin, #domain_RouteFaultDetectorOverrides{}).
80+
81+
-spec new(provider_ref(), terminal_ref(), integer(), integer(), pin(), fd_overrides() | undefined) -> t().
82+
new(ProviderRef, TerminalRef, Weight, Priority, Pin, undefined) ->
83+
new(ProviderRef, TerminalRef, Weight, Priority, Pin, #domain_RouteFaultDetectorOverrides{});
84+
new(ProviderRef, TerminalRef, Weight, Priority, Pin, FdOverrides) ->
85+
#route{
86+
provider_ref = ProviderRef,
87+
terminal_ref = TerminalRef,
88+
weight = Weight,
89+
priority = Priority,
90+
pin = Pin,
91+
fd_overrides = FdOverrides
92+
}.
93+
94+
-spec provider_ref(t()) -> provider_ref().
95+
provider_ref(#route{provider_ref = Ref}) ->
96+
Ref.
97+
98+
-spec terminal_ref(t()) -> terminal_ref().
99+
terminal_ref(#route{terminal_ref = Ref}) ->
100+
Ref.
101+
102+
-spec priority(t()) -> integer().
103+
priority(#route{priority = Priority}) ->
104+
Priority.
105+
106+
-spec weight(t()) -> integer().
107+
weight(#route{weight = Weight}) ->
108+
Weight.
109+
110+
-spec pin(t()) -> pin() | undefined.
111+
pin(#route{pin = Pin}) ->
112+
Pin.
113+
114+
-spec fd_overrides(t()) -> fd_overrides().
115+
fd_overrides(#route{fd_overrides = FdOverrides}) ->
116+
FdOverrides.
117+
118+
-spec set_weight(integer(), t()) -> t().
119+
set_weight(Weight, Route) ->
120+
Route#route{weight = Weight}.
121+
122+
-spec equal(R, R) -> boolean() when
123+
R :: t() | rejected_route() | payment_route() | {provider_ref(), terminal_ref()}.
124+
equal(A, B) ->
125+
routes_equal_(route_ref(A), route_ref(B)).
126+
127+
%%
128+
129+
-spec from_payment_route(payment_route()) -> t().
130+
from_payment_route(Route) ->
131+
?route(ProviderRef, TerminalRef) = Route,
132+
new(ProviderRef, TerminalRef).
133+
134+
-spec to_payment_route(t()) -> payment_route().
135+
to_payment_route(#route{} = Route) ->
136+
?route(provider_ref(Route), terminal_ref(Route)).
137+
138+
-spec to_rejected_route(t(), route_rejection_reason()) -> rejected_route().
139+
to_rejected_route(Route, Reason) ->
140+
{provider_ref(Route), terminal_ref(Route), Reason}.
141+
142+
%%
143+
144+
routes_equal_(A, A) when A =/= undefined ->
145+
true;
146+
routes_equal_(_A, _B) ->
147+
false.
148+
149+
route_ref(#route{provider_ref = Prv, terminal_ref = Trm}) ->
150+
{Prv, Trm};
151+
route_ref(#domain_PaymentRoute{provider = Prv, terminal = Trm}) ->
152+
{Prv, Trm};
153+
route_ref({Prv, Trm}) ->
154+
{Prv, Trm};
155+
route_ref({Prv, Trm, _RejectionReason}) ->
156+
{Prv, Trm};
157+
route_ref(_) ->
158+
undefined.
159+
160+
%%
161+
162+
-ifdef(TEST).
163+
164+
-include_lib("eunit/include/eunit.hrl").
165+
166+
-define(prv(ID), #domain_ProviderRef{id = ID}).
167+
-define(trm(ID), #domain_TerminalRef{id = ID}).
168+
169+
-spec test() -> _.
170+
171+
-spec routes_equality_test_() -> [_].
172+
routes_equality_test_() ->
173+
lists:flatten([
174+
[?_assert(equal(A, B)) || {A, B} <- route_pairs({?prv(1), ?trm(1)}, {?prv(1), ?trm(1)})],
175+
[?_assertNot(equal(A, B)) || {A, B} <- route_pairs({?prv(1), ?trm(1)}, {?prv(1), ?trm(2)})],
176+
[?_assertNot(equal(A, B)) || {A, B} <- route_pairs({?prv(1), ?trm(1)}, {?prv(2), ?trm(1)})],
177+
[?_assertNot(equal(A, B)) || {A, B} <- route_pairs({?prv(1), ?trm(1)}, {?prv(2), ?trm(2)})]
178+
]).
179+
180+
route_pairs({Prv1, Trm1}, {Prv2, Trm2}) ->
181+
Fs = [
182+
fun(X) -> X end,
183+
fun to_payment_route/1,
184+
fun(X) -> to_rejected_route(X, {test, <<"whatever">>}) end,
185+
fun(X) -> {provider_ref(X), terminal_ref(X)} end
186+
],
187+
A = new(Prv1, Trm1),
188+
B = new(Prv2, Trm2),
189+
lists:flatten([[{F1(A), F2(B)} || F1 <- Fs] || F2 <- Fs]).
190+
191+
-endif.

0 commit comments

Comments
 (0)