OPS-442: Add shop limits (#121)

* OPS-442: Add shop limits

* Fix tests and specs

* Add tests

* Format

* Add regression test

* Fix

* Update PM image
This commit is contained in:
ndiezel0 2024-04-03 23:37:36 +03:00 committed by GitHub
parent 55899c876c
commit 50480643a5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 519 additions and 74 deletions

View File

@ -29,7 +29,8 @@
timings :: undefined | hg_timings:t(),
allocation :: undefined | hg_allocation:allocation(),
route_limits = #{} :: hg_routing:limits(),
route_scores = #{} :: hg_routing:scores()
route_scores = #{} :: hg_routing:scores(),
shop_limit_status = undefined :: undefined | initialized | finalized
}).
-record(refund_st, {

View File

@ -51,6 +51,20 @@
}}
).
-define(shop_limit_initiated(),
{
invoice_payment_shop_limit_initiated,
#payproc_InvoicePaymentShopLimitInitiated{}
}
).
-define(shop_limit_applied(),
{
invoice_payment_shop_limit_applied,
#payproc_InvoicePaymentShopLimitApplied{}
}
).
-define(cash_flow_changed(CashFlow),
{invoice_payment_cash_flow_changed, #payproc_InvoicePaymentCashFlowChanged{
cash_flow = CashFlow

View File

@ -148,6 +148,9 @@
-type payment_step() ::
new
| shop_limit_initializing
| shop_limit_failure
| shop_limit_finalizing
| risk_scoring
| routing
| routing_failure
@ -1813,6 +1816,12 @@ process_timeout(St) ->
repair_process_timeout(get_activity(St), Action, St).
-spec process_timeout(activity(), action(), st()) -> machine_result().
process_timeout({payment, shop_limit_initializing}, Action, St) ->
process_shop_limit_initialization(Action, St);
process_timeout({payment, shop_limit_failure}, Action, St) ->
process_shop_limit_failure(Action, St);
process_timeout({payment, shop_limit_finalizing}, Action, St) ->
process_shop_limit_finalization(Action, St);
process_timeout({payment, risk_scoring}, Action, St) ->
process_risk_score(Action, St);
process_timeout({payment, routing}, Action, St) ->
@ -1924,6 +1933,39 @@ process_callback(_Tag, _Payload, undefined, _St) ->
throw(invalid_callback).
%%
-spec process_shop_limit_initialization(action(), st()) -> machine_result().
process_shop_limit_initialization(Action, St) ->
Opts = get_opts(St),
_ = hold_shop_limits(Opts, St),
case check_shop_limits(Opts, St) of
ok ->
{next, {[?shop_limit_initiated()], hg_machine_action:set_timeout(0, Action)}};
{error, {limit_overflow = Error, IDs}} ->
Failure = construct_shop_limit_failure(Error, IDs),
Events = [
?shop_limit_initiated(),
?payment_rollback_started(Failure)
],
{next, {Events, hg_machine_action:set_timeout(0, Action)}}
end.
construct_shop_limit_failure(limit_overflow, IDs) ->
Error = mk_static_error([authorization_failed, shop_limit_exceeded, unknown]),
Reason = genlib:format("Limits with following IDs overflowed: ~p", [IDs]),
{failure, payproc_errors:construct('PaymentFailure', Error, Reason)}.
process_shop_limit_failure(Action, St = #st{failure = Failure}) ->
Opts = get_opts(St),
_ = rollback_shop_limits(Opts, St, [ignore_business_error, ignore_not_found]),
{done, {[?payment_status_changed(?failed(Failure))], hg_machine_action:set_timeout(0, Action)}}.
-spec process_shop_limit_finalization(action(), st()) -> machine_result().
process_shop_limit_finalization(Action, St) ->
Opts = get_opts(St),
_ = commit_shop_limits(Opts, St),
{next, {[?shop_limit_applied()], hg_machine_action:set_timeout(0, Action)}}.
-spec process_risk_score(action(), st()) -> machine_result().
process_risk_score(Action, St) ->
Opts = get_opts(St),
@ -2551,6 +2593,52 @@ get_limit_overflow_routes(Routes, VS, St) ->
Routes
).
%% Shop limits
hold_shop_limits(Opts, St) ->
Payment = get_payment(St),
Invoice = get_invoice(Opts),
Party = get_party(Opts),
Shop = get_shop(Opts),
TurnoverLimits = get_shop_turnover_limits(Shop),
ok = hg_limiter:hold_shop_limits(TurnoverLimits, Party, Shop, Invoice, Payment).
commit_shop_limits(Opts, St) ->
Payment = get_payment(St),
Invoice = get_invoice(Opts),
Party = get_party(Opts),
Shop = get_shop(Opts),
TurnoverLimits = get_shop_turnover_limits(Shop),
ok = hg_limiter:commit_shop_limits(TurnoverLimits, Party, Shop, Invoice, Payment).
check_shop_limits(Opts, St) ->
Payment = get_payment(St),
Invoice = get_invoice(Opts),
TurnoverLimits = get_shop_turnover_limits(get_shop(Opts)),
hg_limiter:check_shop_limits(TurnoverLimits, Invoice, Payment).
rollback_shop_limits(Opts, St, Flags) ->
Payment = get_payment(St),
Invoice = get_invoice(Opts),
Party = get_party(Opts),
Shop = get_shop(Opts),
TurnoverLimits = get_shop_turnover_limits(Shop),
ok = hg_limiter:rollback_shop_limits(
TurnoverLimits,
Party,
Shop,
Invoice,
Payment,
Flags
).
get_shop_turnover_limits(#domain_Shop{turnover_limits = undefined}) ->
[];
get_shop_turnover_limits(#domain_Shop{turnover_limits = T}) ->
ordsets:to_list(T).
%%
-spec hold_limit_routes([hg_route:t()], hg_varset:varset(), pos_integer(), st()) ->
{[hg_route:t()], [hg_route:rejected_route()]}.
hold_limit_routes(Routes0, VS, Iter, St) ->
@ -2979,11 +3067,35 @@ merge_change(Change = ?payment_started(Payment), #st{} = St, Opts) ->
St#st{
target = ?processed(),
payment = Payment,
activity = {payment, risk_scoring},
activity = {payment, shop_limit_initializing},
timings = hg_timings:mark(started, define_event_timestamp(Opts))
};
merge_change(Change = ?shop_limit_initiated(), #st{} = St, Opts) ->
_ = validate_transition({payment, shop_limit_initializing}, Change, St, Opts),
St#st{
shop_limit_status = initialized,
activity = {payment, shop_limit_finalizing}
};
merge_change(Change = ?shop_limit_applied(), #st{} = St, Opts) ->
_ = validate_transition({payment, shop_limit_finalizing}, Change, St, Opts),
St#st{
shop_limit_status = finalized,
activity = {payment, risk_scoring}
};
merge_change(Change = ?risk_score_changed(RiskScore), #st{} = St, Opts) ->
_ = validate_transition({payment, risk_scoring}, Change, St, Opts),
_ = validate_transition(
[
{payment, S}
|| S <- [
risk_scoring,
%% Added for backward compatibility
shop_limit_initializing
]
],
Change,
St,
Opts
),
St#st{
risk_score = RiskScore,
activity = {payment, routing}
@ -3061,14 +3173,20 @@ merge_change(Change = ?cash_changed(_OldCash, NewCash), #st{} = St, Opts) ->
St#st{new_cash = NewCash, new_cash_provided = true, payment = Payment1};
merge_change(Change = ?payment_rollback_started(Failure), St, Opts) ->
_ = validate_transition(
[{payment, cash_flow_building}, {payment, processing_session}],
[
{payment, shop_limit_finalizing},
{payment, cash_flow_building},
{payment, processing_session}
],
Change,
St,
Opts
),
Activity =
case St#st.cash_flow of
undefined ->
case St of
#st{shop_limit_status = initialized} ->
{payment, shop_limit_failure};
#st{cash_flow = undefined} ->
{payment, routing_failure};
_ ->
{payment, processing_failure}
@ -3086,6 +3204,7 @@ merge_change(Change = ?payment_status_changed({failed, _} = Status), #st{payment
risk_scoring,
routing,
cash_flow_building,
shop_limit_failure,
routing_failure,
processing_failure
]
@ -3834,6 +3953,7 @@ get_route_cascade_behaviour(Route, Revision) ->
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
-include_lib("hellgate/test/hg_ct_domain.hrl").
-spec test() -> _.
@ -3925,4 +4045,50 @@ filter_attempted_routes_test_() ->
)
].
-spec shop_limits_regression_test() -> _.
shop_limits_regression_test() ->
DisposableResource = #domain_DisposablePaymentResource{
payment_tool =
{generic, #domain_GenericPaymentTool{
payment_service = ?pmt_srv(<<"id">>)
}}
},
ContactInfo = #domain_ContactInfo{},
Payment = #domain_InvoicePayment{
id = <<"PaymentID">>,
created_at = <<"Timestamp">>,
status = ?pending(),
cost = ?cash(1000, <<"USD">>),
domain_revision = 1,
flow = ?invoice_payment_flow_instant(),
payer = ?payment_resource_payer(DisposableResource, ContactInfo)
},
RiskScore = low,
Route = #domain_PaymentRoute{
provider = ?prv(1),
terminal = ?trm(1)
},
FinalCashflow = [],
TransactionInfo = #domain_TransactionInfo{
id = <<"TransactionID">>,
extra = #{}
},
Events = [
?payment_started(Payment),
?risk_score_changed(RiskScore),
?route_changed(Route),
?cash_flow_changed(FinalCashflow),
hg_session:wrap_event(?processed(), hg_session:create()),
hg_session:wrap_event(?processed(), ?trx_bound(TransactionInfo)),
hg_session:wrap_event(?processed(), ?session_finished(?session_succeeded())),
?payment_status_changed(?processed())
],
ChangeOpts = #{
invoice_id => <<"InvoiceID">>
},
?assertMatch(
#st{},
collapse_changes(Events, undefined, ChangeOpts)
).
-endif.

View File

@ -85,7 +85,9 @@ init_(PaymentID, Params, Opts = #{timestamp := CreatedAt0}) ->
Events =
[
?payment_started(Payment)
?payment_started(Payment),
?shop_limit_initiated(),
?shop_limit_applied()
] ++
RiskScoreEventList ++
[

View File

@ -16,6 +16,8 @@
-type cash() :: dmsl_domain_thrift:'Cash'().
-type handling_flag() :: ignore_business_error | ignore_not_found.
-type turnover_limit_value() :: dmsl_payproc_thrift:'TurnoverLimitValue'().
-type party() :: hg_party:party().
-type shop() :: dmsl_domain_thrift:'Shop'().
-type change_queue() :: [hg_limiter_client:limit_change()].
@ -23,11 +25,15 @@
-export([get_turnover_limits/1]).
-export([check_limits/4]).
-export([check_shop_limits/3]).
-export([hold_payment_limits/5]).
-export([hold_shop_limits/5]).
-export([hold_refund_limits/5]).
-export([commit_payment_limits/6]).
-export([commit_shop_limits/5]).
-export([commit_refund_limits/5]).
-export([rollback_payment_limits/6]).
-export([rollback_shop_limits/6]).
-export([rollback_refund_limits/5]).
-export([get_limit_values/4]).
@ -36,6 +42,14 @@
terminal = TerminalRef
}).
-define(party(PartyID), #domain_Party{
id = PartyID
}).
-define(shop(ShopID), #domain_Shop{
id = ShopID
}).
-spec get_turnover_limits(turnover_selector() | undefined) -> [turnover_limit()].
get_turnover_limits(undefined) ->
[];
@ -76,6 +90,21 @@ check_limits(TurnoverLimits, Invoice, Payment, Route) ->
{error, {limit_overflow, IDs, Limits}}
end.
-spec check_shop_limits([turnover_limit()], invoice(), payment()) ->
ok
| {error, {limit_overflow, [binary()]}}.
check_shop_limits(TurnoverLimits, Invoice, Payment) ->
Context = gen_limit_shop_context(Invoice, Payment),
{ok, Limits} = gather_limits(TurnoverLimits, Context, []),
try
ok = check_limits_(Limits, Context),
ok
catch
throw:limit_overflow ->
IDs = [T#domain_TurnoverLimit.id || T <- TurnoverLimits],
{error, {limit_overflow, IDs}}
end.
check_limits_([], _) ->
ok;
check_limits_([TurnoverLimitValue | TLVs], Context) ->
@ -114,6 +143,13 @@ hold_payment_limits(TurnoverLimits, Route, Iter, Invoice, Payment) ->
Context = gen_limit_context(Invoice, Payment, Route),
hold(LimitChanges, get_latest_clock(), Context).
-spec hold_shop_limits([turnover_limit()], party(), shop(), invoice(), payment()) -> ok.
hold_shop_limits(TurnoverLimits, Party, Shop, Invoice, Payment) ->
ChangeIDs = [construct_shop_change_id(Party, Shop, Invoice, Payment)],
LimitChanges = gen_limit_changes(TurnoverLimits, ChangeIDs),
Context = gen_limit_shop_context(Invoice, Payment),
hold(LimitChanges, get_latest_clock(), Context).
-spec hold_refund_limits([turnover_limit()], invoice(), payment(), refund(), route()) -> ok.
hold_refund_limits(TurnoverLimits, Invoice, Payment, Refund, Route) ->
ChangeIDs = [construct_refund_change_id(Invoice, Payment, Refund)],
@ -133,6 +169,16 @@ commit_payment_limits(TurnoverLimits, Route, Iter, Invoice, Payment, CapturedCas
ok = commit(LimitChanges, Clock, Context),
ok = log_limit_changes(TurnoverLimits, Clock, Context).
-spec commit_shop_limits([turnover_limit()], party(), shop(), invoice(), payment()) -> ok.
commit_shop_limits(TurnoverLimits, Party, Shop, Invoice, Payment) ->
ChangeIDs = [construct_shop_change_id(Party, Shop, Invoice, Payment)],
LimitChanges = gen_limit_changes(TurnoverLimits, ChangeIDs),
Context = gen_limit_shop_context(Invoice, Payment),
Clock = get_latest_clock(),
ok = commit(LimitChanges, Clock, Context),
ok = log_limit_changes(TurnoverLimits, Clock, Context),
ok.
-spec commit_refund_limits([turnover_limit()], invoice(), payment(), refund(), route()) -> ok.
commit_refund_limits(TurnoverLimits, Invoice, Payment, Refund, Route) ->
ChangeIDs = [construct_refund_change_id(Invoice, Payment, Refund)],
@ -161,6 +207,14 @@ rollback_payment_limits(TurnoverLimits, Route, Iter, Invoice, Payment, Flags) ->
Context = gen_limit_context(Invoice, Payment, Route),
rollback(LimitChanges, get_latest_clock(), Context, Flags).
-spec rollback_shop_limits([turnover_limit()], party(), shop(), invoice(), payment(), [handling_flag()]) ->
ok.
rollback_shop_limits(TurnoverLimits, Party, Shop, Invoice, Payment, Flags) ->
ChangeIDs = [construct_shop_change_id(Party, Shop, Invoice, Payment)],
LimitChanges = gen_limit_changes(TurnoverLimits, ChangeIDs),
Context = gen_limit_shop_context(Invoice, Payment),
rollback(LimitChanges, get_latest_clock(), Context, Flags).
-spec rollback_refund_limits([turnover_limit()], invoice(), payment(), refund(), route()) -> ok.
rollback_refund_limits(TurnoverLimits, Invoice, Payment, Refund, Route) ->
ChangeIDs = [construct_refund_change_id(Invoice, Payment, Refund)],
@ -238,6 +292,19 @@ gen_limit_context(Invoice, Payment, Route, CapturedCash) ->
}
}.
gen_limit_shop_context(Invoice, Payment) ->
#limiter_LimitContext{
payment_processing = #context_payproc_Context{
op = {invoice_payment, #context_payproc_OperationInvoicePayment{}},
invoice = #context_payproc_Invoice{
invoice = Invoice,
payment = #context_payproc_InvoicePayment{
payment = Payment
}
}
}
}.
gen_limit_refund_context(Invoice, Payment, Refund, Route) ->
PaymentCtx = #context_payproc_InvoicePayment{
payment = Payment,
@ -290,6 +357,14 @@ construct_payment_change_id(?route(ProviderRef, TerminalRef), Iter, Invoice, Pay
integer_to_binary(Iter)
]).
construct_shop_change_id(?party(PartyID), ?shop(ShopID), Invoice, Payment) ->
hg_utils:construct_complex_id([
PartyID,
ShopID,
get_invoice_id(Invoice),
get_payment_id(Payment)
]).
construct_refund_change_id(Invoice, Payment, Refund) ->
hg_utils:construct_complex_id([
get_invoice_id(Invoice),
@ -341,7 +416,7 @@ mk_limit_log_attributes(#limiter_LimitContext{
payment = #context_payproc_InvoicePayment{
payment = Payment,
refund = Refund,
route = #base_Route{provider = Provider, terminal = Terminal}
route = Route
}
} = CtxInvoice,
#domain_Cash{amount = Amount, currency = Currency} =
@ -357,10 +432,7 @@ mk_limit_log_attributes(#limiter_LimitContext{
boundary => undefined,
%% Current amount with accounted change
amount => undefined,
route => #{
provider_id => Provider#domain_ProviderRef.id,
terminal_id => Terminal#domain_TerminalRef.id
},
route => maybe_route_context(Route),
party_id => PartyID,
shop_id => ShopID,
change => #{
@ -368,3 +440,11 @@ mk_limit_log_attributes(#limiter_LimitContext{
currency => Currency#domain_CurrencyRef.symbolic_code
}
}.
maybe_route_context(undefined) ->
undefined;
maybe_route_context(#base_Route{provider = Provider, terminal = Terminal}) ->
#{
provider_id => Provider#domain_ProviderRef.id,
terminal_id => Terminal#domain_TerminalRef.id
}.

View File

@ -12,6 +12,7 @@
-export([create_party_and_shop/6]).
-export([create_party/2]).
-export([create_shop/6]).
-export([create_shop/7]).
-export([create_battle_ready_shop/6]).
-export([adjust_contract/4]).
@ -350,6 +351,8 @@ create_client_w_context(RootUrl, WoodyCtx) ->
-type party() :: dmsl_domain_thrift:'Party'().
-type contract_id() :: dmsl_domain_thrift:'ContractID'().
-type contract_tpl() :: dmsl_domain_thrift:'ContractTemplateRef'().
-type turnover_limit() :: dmsl_domain_thrift:'TurnoverLimit'().
-type turnover_limits() :: ordsets:ordset(turnover_limit()).
-type shop_id() :: dmsl_domain_thrift:'ShopID'().
-type category() :: dmsl_domain_thrift:'CategoryRef'().
-type cash() :: dmsl_domain_thrift:'Cash'().
@ -390,9 +393,34 @@ create_shop(PartyID, Category, Currency, TemplateRef, PaymentInstRef, PartyClien
{ok, _Claim} = party_client_thrift:create_claim(PartyID, Changeset, Client, Context),
ok
end,
create_shop_(PartyID, Category, Currency, TemplateRef, PaymentInstRef, PartyClient, Fun).
create_shop_(PartyID, Category, Currency, TemplateRef, PaymentInstRef, undefined, PartyClient, Fun).
create_shop_(PartyID, Category, Currency, TemplateRef, PaymentInstRef, {Client, Context}, CreateShopFun) ->
-spec create_shop(
party_id(),
category(),
currency(),
contract_tpl(),
payment_inst_ref(),
turnover_limits(),
party_client()
) -> shop_id().
create_shop(PartyID, Category, Currency, TemplateRef, PaymentInstRef, TurnoverLimits, PartyClient) ->
Fun = fun(_, Changeset, Client, Context) ->
{ok, _Claim} = party_client_thrift:create_claim(PartyID, Changeset, Client, Context),
ok
end,
create_shop_(PartyID, Category, Currency, TemplateRef, PaymentInstRef, TurnoverLimits, PartyClient, Fun).
create_shop_(
PartyID,
Category,
Currency,
TemplateRef,
PaymentInstRef,
TurnoverLimits0,
{Client, Context},
CreateShopFun
) ->
ShopID = hg_utils:unique_id(),
ContractID = hg_utils:unique_id(),
PayoutToolID = hg_utils:unique_id(),
@ -403,6 +431,8 @@ create_shop_(PartyID, Category, Currency, TemplateRef, PaymentInstRef, {Client,
ContractParams = make_contract_params(TemplateRef, PaymentInstRef),
PayoutToolParams = make_payout_tool_params(),
TurnoverLimits1 = genlib:define(TurnoverLimits0, ordsets:new()),
Changeset = [
{contract_modification, #payproc_ContractModificationUnit{
id = ContractID,
@ -417,7 +447,8 @@ create_shop_(PartyID, Category, Currency, TemplateRef, PaymentInstRef, {Client,
}}
}},
?shop_modification(ShopID, {creation, ShopParams}),
?shop_modification(ShopID, {shop_account_creation, ShopAccountParams})
?shop_modification(ShopID, {shop_account_creation, ShopAccountParams}),
?shop_modification(ShopID, {turnover_limits_modification, TurnoverLimits1})
],
ok = CreateShopFun(PartyID, Changeset, Client, Context),
@ -465,7 +496,7 @@ create_battle_ready_shop(PartyID, Category, Currency, TemplateRef, PaymentInstRe
Fun = fun(_, Changeset, _, _) ->
create_claim(PartyID, Changeset, PartyPair)
end,
create_shop_(PartyID, Category, Currency, TemplateRef, PaymentInstRef, PartyPair, Fun).
create_shop_(PartyID, Category, Currency, TemplateRef, PaymentInstRef, undefined, PartyPair, Fun).
-spec adjust_contract(party_id(), contract_id(), contract_tpl(), party_client()) -> ok.
adjust_contract(PartyID, ContractID, TemplateRef, Client) ->

View File

@ -26,7 +26,7 @@
register_payment/4,
start_payment/3,
start_payment_ev/2,
start_payment_ev_no_risk_scoring/2,
register_payment_ev_no_risk_scoring/2,
await_payment_session_started/4,
await_payment_capture/3,
await_payment_capture/4,
@ -237,7 +237,7 @@ register_payment(InvoiceID, RegisterPaymentParams, WithRiskScoring, Client) ->
true ->
start_payment_ev(InvoiceID, Client);
false ->
start_payment_ev_no_risk_scoring(InvoiceID, Client)
register_payment_ev_no_risk_scoring(InvoiceID, Client)
end,
?payment_ev(PaymentID, ?cash_flow_changed(_)) =
next_change(InvoiceID, Client),
@ -255,17 +255,21 @@ start_payment(InvoiceID, PaymentParams, Client) ->
start_payment_ev(InvoiceID, Client) ->
[
?payment_ev(PaymentID, ?payment_started(?payment_w_status(?pending()))),
?payment_ev(PaymentID, ?shop_limit_initiated()),
?payment_ev(PaymentID, ?shop_limit_applied()),
?payment_ev(PaymentID, ?risk_score_changed(_RiskScore)),
?payment_ev(PaymentID, ?route_changed(Route))
] = next_changes(InvoiceID, 3, Client),
] = next_changes(InvoiceID, 5, Client),
Route.
-spec start_payment_ev_no_risk_scoring(_, _) -> _.
start_payment_ev_no_risk_scoring(InvoiceID, Client) ->
-spec register_payment_ev_no_risk_scoring(_, _) -> _.
register_payment_ev_no_risk_scoring(InvoiceID, Client) ->
[
?payment_ev(PaymentID, ?payment_started(?payment_w_status(?pending()))),
?payment_ev(PaymentID, ?shop_limit_initiated()),
?payment_ev(PaymentID, ?shop_limit_applied()),
?payment_ev(PaymentID, ?route_changed(Route))
] = next_changes(InvoiceID, 2, Client),
] = next_changes(InvoiceID, 4, Client),
Route.
-spec await_payment_session_started(_, _, _, _) -> _.
@ -322,10 +326,12 @@ await_payment_capture_finish(InvoiceID, PaymentID, Reason, Cost, Cart, Client) -
-spec await_payment_cash_flow(_, _, _) -> _.
await_payment_cash_flow(InvoiceID, PaymentID, Client) ->
[
?payment_ev(PaymentID, ?shop_limit_initiated()),
?payment_ev(PaymentID, ?shop_limit_applied()),
?payment_ev(PaymentID, ?risk_score_changed(_)),
?payment_ev(PaymentID, ?route_changed(Route)),
?payment_ev(PaymentID, ?cash_flow_changed(CashFlow))
] = next_changes(InvoiceID, 3, Client),
] = next_changes(InvoiceID, 5, Client),
{CashFlow, Route}.
-spec construct_ta_context(_, _, _) -> _.

View File

@ -232,10 +232,12 @@ payment_w_all_blacklisted(C) ->
?payment_state(?payment(PaymentID)) = hg_client_invoicing:start_payment(InvoiceID, PaymentParams, Client),
[
?payment_ev(PaymentID, ?payment_started(?payment_w_status(?pending()))),
?payment_ev(PaymentID, ?shop_limit_initiated()),
?payment_ev(PaymentID, ?shop_limit_applied()),
?payment_ev(PaymentID, ?risk_score_changed(_RiskScore)),
?payment_ev(PaymentID, ?route_changed(_Route)),
?payment_ev(PaymentID, ?payment_rollback_started({failure, _Failure}))
] = next_changes(InvoiceID, 4, Client),
] = next_changes(InvoiceID, 6, Client),
?invoice_state(
?invoice_w_status(?invoice_unpaid()),
[_PaymentSt]

View File

@ -37,6 +37,9 @@
-export([invalid_payment_amount/1]).
-export([payment_limit_success/1]).
-export([payment_shop_limit_success/1]).
-export([payment_shop_limit_overflow/1]).
-export([payment_shop_limit_more_overflow/1]).
-export([payment_routes_limit_values/1]).
-export([register_payment_limit_success/1]).
-export([payment_limit_other_shop_success/1]).
@ -220,11 +223,13 @@ init([]) ->
-define(PARTY_ID_WITH_LIMIT, <<"bIg merch limit">>).
-define(PARTY_ID_WITH_SEVERAL_LIMITS, <<"bIg merch limit cascading">>).
-define(PARTY_ID_WITH_SHOP_LIMITS, <<"small merch limit shop">>).
-define(PARTYID_EXTERNAL, <<"DUBTV">>).
-define(LIMIT_ID, <<"ID">>).
-define(LIMIT_ID2, <<"ID2">>).
-define(LIMIT_ID3, <<"ID3">>).
-define(LIMIT_ID4, <<"ID4">>).
-define(SHOPLIMIT_ID, <<"SHOPLIMITID">>).
-define(LIMIT_UPPER_BOUNDARY, 100000).
-define(BIG_LIMIT_UPPER_BOUNDARY, 1000000).
-define(DEFAULT_NEXT_CHANGE_TIMEOUT, 12000).
@ -378,6 +383,9 @@ groups() ->
{operation_limits, [], [
payment_limit_success,
payment_shop_limit_success,
payment_shop_limit_overflow,
payment_shop_limit_more_overflow,
payment_routes_limit_values,
register_payment_limit_success,
payment_limit_other_shop_success,
@ -1100,9 +1108,18 @@ register_invoice_payment(Route, ShopID, Client, C) ->
init_operation_limits_group(C) ->
PartyID1 = ?PARTY_ID_WITH_LIMIT,
PartyID2 = ?PARTY_ID_WITH_SEVERAL_LIMITS,
PartyID3 = ?PARTY_ID_WITH_SHOP_LIMITS,
_ = hg_ct_helper:create_party(PartyID1, cfg(party_client, C)),
_ = hg_ct_helper:create_party(PartyID2, cfg(party_client, C)),
[{limits, #{party_id => PartyID1, party_id_w_several_limits => PartyID2}} | C].
_ = hg_ct_helper:create_party(PartyID3, cfg(party_client, C)),
[
{limits, #{
party_id => PartyID1,
party_id_w_several_limits => PartyID2,
party_id_w_shop_limits => PartyID3
}}
| C
].
-spec payment_limit_success(config()) -> test_return().
payment_limit_success(C) ->
@ -1117,6 +1134,78 @@ payment_limit_success(C) ->
[?payment_state(_Payment)]
) = create_payment(PartyID, ShopID, 10000, Client, ?pmt_sys(<<"visa-ref">>)).
-spec payment_shop_limit_success(config()) -> test_return().
payment_shop_limit_success(C) ->
RootUrl = cfg(root_url, C),
PartyClient = cfg(party_client, C),
PartyID = cfg(party_id_big_merch, C),
TurnoverLimits = [
#domain_TurnoverLimit{
id = ?SHOPLIMIT_ID,
upper_boundary = ?LIMIT_UPPER_BOUNDARY,
domain_revision = dmt_client:get_last_version()
}
],
ShopID = hg_ct_helper:create_shop(PartyID, ?cat(1), <<"RUB">>, ?tmpl(1), ?pinst(1), TurnoverLimits, PartyClient),
Client = hg_client_invoicing:start_link(hg_ct_helper:create_client(RootUrl)),
PaymentAmount = ?LIMIT_UPPER_BOUNDARY - 1,
?invoice_state(
?invoice_w_status(?invoice_paid()),
[?payment_state(_Payment)]
) = create_payment(PartyID, ShopID, PaymentAmount, Client, ?pmt_sys(<<"visa-ref">>)).
-spec payment_shop_limit_overflow(config()) -> test_return().
payment_shop_limit_overflow(C) ->
RootUrl = cfg(root_url, C),
PartyClient = cfg(party_client, C),
PartyID = cfg(party_id_big_merch, C),
TurnoverLimits = ordsets:from_list([
#domain_TurnoverLimit{
id = ?SHOPLIMIT_ID,
upper_boundary = ?LIMIT_UPPER_BOUNDARY,
domain_revision = dmt_client:get_last_version()
}
]),
ShopID = hg_ct_helper:create_shop(PartyID, ?cat(1), <<"RUB">>, ?tmpl(1), ?pinst(1), TurnoverLimits, PartyClient),
Client = hg_client_invoicing:start_link(hg_ct_helper:create_client(RootUrl)),
PaymentAmount = ?LIMIT_UPPER_BOUNDARY + 1,
Failure = create_payment_shop_limit_overflow(PartyID, ShopID, PaymentAmount, Client, ?pmt_sys(<<"visa-ref">>)),
ok = payproc_errors:match('PaymentFailure', Failure, fun(
{authorization_failed, {shop_limit_exceeded, {unknown, _}}}
) ->
ok
end).
-spec payment_shop_limit_more_overflow(config()) -> test_return().
payment_shop_limit_more_overflow(C) ->
RootUrl = cfg(root_url, C),
PartyClient = cfg(party_client, C),
PartyID = cfg(party_id_big_merch, C),
TurnoverLimits = ordsets:from_list([
#domain_TurnoverLimit{
id = ?SHOPLIMIT_ID,
upper_boundary = ?LIMIT_UPPER_BOUNDARY,
domain_revision = dmt_client:get_last_version()
}
]),
ShopID = hg_ct_helper:create_shop(PartyID, ?cat(1), <<"RUB">>, ?tmpl(1), ?pinst(1), TurnoverLimits, PartyClient),
Client = hg_client_invoicing:start_link(hg_ct_helper:create_client(RootUrl)),
PaymentAmount = ?LIMIT_UPPER_BOUNDARY - 1,
?invoice_state(
?invoice_w_status(?invoice_paid()),
[?payment_state(_Payment)]
) = create_payment(PartyID, ShopID, PaymentAmount, Client, ?pmt_sys(<<"visa-ref">>)),
Failure = create_payment_shop_limit_overflow(PartyID, ShopID, PaymentAmount, Client, ?pmt_sys(<<"visa-ref">>)),
ok = payproc_errors:match('PaymentFailure', Failure, fun(
{authorization_failed, {shop_limit_exceeded, {unknown, _}}}
) ->
ok
end).
-spec payment_routes_limit_values(config()) -> test_return().
payment_routes_limit_values(C) ->
RootUrl = cfg(root_url, C),
@ -1386,6 +1475,15 @@ create_payment_limit_overflow(PartyID, ShopID, Amount, Client, PmtSys) ->
PaymentID = await_payment_started(InvoiceID, PaymentID, Client),
await_payment_rollback(InvoiceID, PaymentID, Client).
create_payment_shop_limit_overflow(PartyID, ShopID, Amount, Client, PmtSys) ->
InvoiceParams = make_invoice_params(PartyID, ShopID, <<"rubberduck">>, make_due_date(10), make_cash(Amount)),
InvoiceID = create_invoice(InvoiceParams, Client),
?invoice_created(?invoice_w_status(?invoice_unpaid())) = next_change(InvoiceID, Client),
PaymentParams = make_payment_params(PmtSys),
?payment_state(?payment(PaymentID)) = hg_client_invoicing:start_payment(InvoiceID, PaymentParams, Client),
PaymentID = await_payment_started(InvoiceID, PaymentID, Client),
await_payment_shop_limit_rollback(InvoiceID, PaymentID, Client).
%%----------------- operation_limits group end
-spec payment_success_ruleset(config()) -> test_return().
@ -1435,9 +1533,11 @@ payment_w_misconfigured_routing_failed(C) ->
?payment_state(?payment(PaymentID)) = hg_client_invoicing:start_payment(InvoiceID, PaymentParams, Client),
[
?payment_ev(PaymentID, ?payment_started(?payment_w_status(?pending()))),
?payment_ev(PaymentID, ?shop_limit_initiated()),
?payment_ev(PaymentID, ?shop_limit_applied()),
?payment_ev(PaymentID, ?risk_score_changed(_)),
?payment_ev(PaymentID, ?payment_status_changed(?failed({failure, Failure})))
] = next_changes(InvoiceID, 3, Client),
] = next_changes(InvoiceID, 5, Client),
Reason = genlib:format({routing_decisions, {delegates, []}}),
?assertRouteNotFound(Failure, {unknown, {{unknown_error, <<"misconfiguration">>}, _}}, Reason).
@ -2193,10 +2293,12 @@ payment_risk_score_check(C) ->
?payment_state(?payment(PaymentID3)) = hg_client_invoicing:start_payment(InvoiceID3, PaymentParams, Client),
[
?payment_ev(PaymentID3, ?payment_started(?payment_w_status(?pending()))),
?payment_ev(PaymentID, ?shop_limit_initiated()),
?payment_ev(PaymentID, ?shop_limit_applied()),
% fatal risk score is not going to be covered
?payment_ev(PaymentID3, ?risk_score_changed(fatal)),
?payment_ev(PaymentID3, ?payment_status_changed(?failed({failure, Failure})))
] = next_changes(InvoiceID3, 3, Client),
] = next_changes(InvoiceID3, 5, Client),
ok = payproc_errors:match(
'PaymentFailure',
Failure,
@ -2721,7 +2823,7 @@ registered_payment_adjustment_success(C) ->
},
?payment_state(?payment(PaymentID)) =
hg_client_invoicing:register_payment(InvoiceID, PaymentParams, Client),
_ = start_payment_ev_no_risk_scoring(InvoiceID, Client),
_ = register_payment_ev_no_risk_scoring(InvoiceID, Client),
?payment_ev(PaymentID, ?cash_flow_changed(CF1)) =
next_change(InvoiceID, Client),
PaymentID = await_payment_session_started(InvoiceID, PaymentID, Client, ?processed()),
@ -5100,8 +5202,12 @@ repair_fail_routing_succeeded(C) ->
%% Payment
PaymentParams = make_payment_params(?pmt_sys(<<"visa-ref">>)),
?payment_state(?payment(PaymentID)) = hg_client_invoicing:start_payment(InvoiceID, PaymentParams, Client),
?payment_ev(PaymentID, ?payment_started(?payment_w_status(?pending()))) = next_change(InvoiceID, Client),
?payment_ev(PaymentID, ?risk_score_changed(_RS)) = next_change(InvoiceID, Client),
[
?payment_ev(PaymentID, ?payment_started(?payment_w_status(?pending()))),
?payment_ev(PaymentID, ?shop_limit_initiated()),
?payment_ev(PaymentID, ?shop_limit_applied()),
?payment_ev(PaymentID, ?risk_score_changed(_))
] = next_changes(InvoiceID, 4, Client),
%% routing broken
timeout = next_change(InvoiceID, 2000, Client),
@ -5154,9 +5260,13 @@ repair_fail_cash_flow_building_succeeded(C) ->
%% Payment
PaymentParams = make_payment_params(?pmt_sys(<<"visa-ref">>)),
?payment_state(?payment(PaymentID)) = hg_client_invoicing:start_payment(InvoiceID, PaymentParams, Client),
?payment_ev(PaymentID, ?payment_started(?payment_w_status(?pending()))) = next_change(InvoiceID, Client),
?payment_ev(PaymentID, ?risk_score_changed(_RS)) = next_change(InvoiceID, Client),
?payment_ev(PaymentID, ?route_changed(Route)) = next_change(InvoiceID, Client),
[
?payment_ev(PaymentID, ?payment_started(?payment_w_status(?pending()))),
?payment_ev(PaymentID, ?shop_limit_initiated()),
?payment_ev(PaymentID, ?shop_limit_applied()),
?payment_ev(PaymentID, ?risk_score_changed(_)),
?payment_ev(PaymentID, ?route_changed(Route))
] = next_changes(InvoiceID, 5, Client),
%% cash_flow_building broken
timeout = next_change(InvoiceID, 2000, Client),
@ -6075,10 +6185,12 @@ payment_cascade_success(C) ->
?invoice_created(?invoice_w_status(?invoice_unpaid())) = next_change(InvoiceID, Client),
{ok, Limit} = hg_limiter_helper:get_payment_limit_amount(?LIMIT_ID4, hg_domain:head(), Payment, Invoice),
InitialAccountedAmount = hg_limiter_helper:get_amount(Limit),
?payment_ev(PaymentID, ?payment_started(?payment_w_status(?pending()))) =
next_change(InvoiceID, Client),
?payment_ev(PaymentID, ?risk_score_changed(_)) =
next_change(InvoiceID, Client),
[
?payment_ev(PaymentID, ?payment_started(?payment_w_status(?pending()))),
?payment_ev(PaymentID, ?shop_limit_initiated()),
?payment_ev(PaymentID, ?shop_limit_applied()),
?payment_ev(PaymentID, ?risk_score_changed(_))
] = next_changes(InvoiceID, 4, Client),
{Route1, _CashFlow1, TrxID1, Failure1} =
await_cascade_triggering(InvoiceID, PaymentID, Client),
ok = payproc_errors:match('PaymentFailure', Failure1, fun({preauthorization_failed, {card_blocked, _}}) -> ok end),
@ -6461,10 +6573,12 @@ payment_cascade_limit_overflow(C) ->
?invoice_created(?invoice_w_status(?invoice_unpaid())) = next_change(InvoiceID, Client),
{ok, Limit} = hg_limiter_helper:get_payment_limit_amount(?LIMIT_ID4, hg_domain:head(), Payment, Invoice),
InitialAccountedAmount = hg_limiter_helper:get_amount(Limit),
?payment_ev(PaymentID, ?payment_started(?payment_w_status(?pending()))) =
next_change(InvoiceID, Client),
?payment_ev(PaymentID, ?risk_score_changed(_)) =
next_change(InvoiceID, Client),
[
?payment_ev(PaymentID, ?payment_started(?payment_w_status(?pending()))),
?payment_ev(PaymentID, ?shop_limit_initiated()),
?payment_ev(PaymentID, ?shop_limit_applied()),
?payment_ev(PaymentID, ?risk_score_changed(_))
] = next_changes(InvoiceID, 4, Client),
{Route1, _CashFlow1, _TrxID1, Failure1} =
await_cascade_triggering(InvoiceID, PaymentID, Client),
ok = payproc_errors:match('PaymentFailure', Failure1, fun({authorization_failed, {unknown, _}}) -> ok end),
@ -6515,10 +6629,12 @@ payment_big_cascade_success(C) ->
?invoice_created(?invoice_w_status(?invoice_unpaid())) = next_change(InvoiceID, Client),
{ok, Limit} = hg_limiter_helper:get_payment_limit_amount(?LIMIT_ID4, hg_domain:head(), Payment, Invoice),
InitialAccountedAmount = hg_limiter_helper:get_amount(Limit),
?payment_ev(PaymentID, ?payment_started(?payment_w_status(?pending()))) =
next_change(InvoiceID, Client),
?payment_ev(PaymentID, ?risk_score_changed(_)) =
next_change(InvoiceID, Client),
[
?payment_ev(PaymentID, ?payment_started(?payment_w_status(?pending()))),
?payment_ev(PaymentID, ?shop_limit_initiated()),
?payment_ev(PaymentID, ?shop_limit_applied()),
?payment_ev(PaymentID, ?risk_score_changed(_))
] = next_changes(InvoiceID, 4, Client),
[
(fun() ->
{_Route, _CashFlow, _TrxID, Failure} =
@ -6672,10 +6788,12 @@ payment_cascade_fail_provider_error(C) ->
{PaymentTool, Session} = hg_dummy_provider:make_payment_tool(no_preauth, ?pmt_sys(<<"visa-ref">>)),
PaymentParams = make_payment_params(PaymentTool, Session, instant),
hg_client_invoicing:start_payment(InvoiceID, PaymentParams, Client),
?payment_ev(PaymentID, ?payment_started(?payment_w_status(?pending()))) =
next_change(InvoiceID, Client),
?payment_ev(PaymentID, ?risk_score_changed(_)) =
next_change(InvoiceID, Client),
[
?payment_ev(PaymentID, ?payment_started(?payment_w_status(?pending()))),
?payment_ev(PaymentID, ?shop_limit_initiated()),
?payment_ev(PaymentID, ?shop_limit_applied()),
?payment_ev(PaymentID, ?risk_score_changed(_))
] = next_changes(InvoiceID, 4, Client),
{_Route1, _CashFlow1, _TrxID1, Failure1} =
await_cascade_triggering(InvoiceID, PaymentID, Client),
%% And again
@ -6774,10 +6892,12 @@ payment_cascade_fail_ui(C) ->
{PaymentTool, Session} = hg_dummy_provider:make_payment_tool(preauth_3ds, ?pmt_sys(<<"visa-ref">>)),
PaymentParams = make_payment_params(PaymentTool, Session, instant),
hg_client_invoicing:start_payment(InvoiceID, PaymentParams, Client),
?payment_ev(PaymentID, ?payment_started(?payment_w_status(?pending()))) =
next_change(InvoiceID, Client),
?payment_ev(PaymentID, ?risk_score_changed(_)) =
next_change(InvoiceID, Client),
[
?payment_ev(PaymentID, ?payment_started(?payment_w_status(?pending()))),
?payment_ev(PaymentID, ?shop_limit_initiated()),
?payment_ev(PaymentID, ?shop_limit_applied()),
?payment_ev(PaymentID, ?risk_score_changed(_))
] = next_changes(InvoiceID, 4, Client),
{_Route1, _CashFlow1, _TrxID1, Failure1} =
await_cascade_triggering(InvoiceID, PaymentID, Client),
ok = payproc_errors:match('PaymentFailure', Failure1, fun({authorization_failed, {unknown, _}}) -> ok end),
@ -6983,10 +7103,12 @@ payment_cascade_fail_wo_available_attempt_limit(C) ->
{PaymentTool, Session} = hg_dummy_provider:make_payment_tool(no_preauth, ?pmt_sys(<<"visa-ref">>)),
PaymentParams = make_payment_params(PaymentTool, Session, instant),
hg_client_invoicing:start_payment(InvoiceID, PaymentParams, Client),
?payment_ev(PaymentID, ?payment_started(?payment_w_status(?pending()))) =
next_change(InvoiceID, Client),
?payment_ev(PaymentID, ?risk_score_changed(_)) =
next_change(InvoiceID, Client),
[
?payment_ev(PaymentID, ?payment_started(?payment_w_status(?pending()))),
?payment_ev(PaymentID, ?shop_limit_initiated()),
?payment_ev(PaymentID, ?shop_limit_applied()),
?payment_ev(PaymentID, ?risk_score_changed(_))
] = next_changes(InvoiceID, 4, Client),
{_Route, _CashFlow, _TrxID, Failure} =
await_cascade_triggering(InvoiceID, PaymentID, Client),
?payment_ev(PaymentID, ?payment_status_changed(?failed({failure, Failure}))) =
@ -7071,10 +7193,12 @@ payment_cascade_failures(C) ->
{PaymentTool, Session} = hg_dummy_provider:make_payment_tool(no_preauth, ?pmt_sys(<<"visa-ref">>)),
PaymentParams = make_payment_params(PaymentTool, Session, instant),
hg_client_invoicing:start_payment(InvoiceID, PaymentParams, Client),
?payment_ev(PaymentID, ?payment_started(?payment_w_status(?pending()))) =
next_change(InvoiceID, Client),
?payment_ev(PaymentID, ?risk_score_changed(_)) =
next_change(InvoiceID, Client),
[
?payment_ev(PaymentID, ?payment_started(?payment_w_status(?pending()))),
?payment_ev(PaymentID, ?shop_limit_initiated()),
?payment_ev(PaymentID, ?shop_limit_applied()),
?payment_ev(PaymentID, ?risk_score_changed(_))
] = next_changes(InvoiceID, 4, Client),
{_Route1, _CashFlow1, _TrxID1, Failure1} =
await_cascade_triggering(InvoiceID, PaymentID, Client),
ok = payproc_errors:match('PaymentFailure', Failure1, fun({preauthorization_failed, {card_blocked, _}}) -> ok end),
@ -7170,10 +7294,12 @@ payment_cascade_deadline_failures(C) ->
processing_deadline = hg_datetime:add_time_span(#base_TimeSpan{seconds = 2}, hg_datetime:format_now())
},
hg_client_invoicing:start_payment(InvoiceID, PaymentParams, Client),
?payment_ev(PaymentID, ?payment_started(?payment_w_status(?pending()))) =
next_change(InvoiceID, Client),
?payment_ev(PaymentID, ?risk_score_changed(_)) =
next_change(InvoiceID, Client),
[
?payment_ev(PaymentID, ?payment_started(?payment_w_status(?pending()))),
?payment_ev(PaymentID, ?shop_limit_initiated()),
?payment_ev(PaymentID, ?shop_limit_applied()),
?payment_ev(PaymentID, ?risk_score_changed(_))
] = next_changes(InvoiceID, 4, Client),
{_Route1, _CashFlow1, _TrxID1, Failure1} =
await_cascade_triggering(InvoiceID, PaymentID, Client),
ok = payproc_errors:match('PaymentFailure', Failure1, fun({preauthorization_failed, {card_blocked, _}}) -> ok end),
@ -7481,8 +7607,8 @@ register_payment(InvoiceID, RegisterPaymentParams, WithRiskScoring, Client) ->
start_payment_ev(InvoiceID, Client) ->
hg_invoice_helper:start_payment_ev(InvoiceID, Client).
start_payment_ev_no_risk_scoring(InvoiceID, Client) ->
hg_invoice_helper:start_payment_ev_no_risk_scoring(InvoiceID, Client).
register_payment_ev_no_risk_scoring(InvoiceID, Client) ->
hg_invoice_helper:register_payment_ev_no_risk_scoring(InvoiceID, Client).
process_payment(InvoiceID, PaymentParams, Client) ->
hg_invoice_helper:process_payment(InvoiceID, PaymentParams, Client).
@ -7497,18 +7623,29 @@ await_payment_cash_flow(InvoiceID, PaymentID, Client) ->
await_payment_cash_flow(RS, Route, InvoiceID, PaymentID, Client) ->
[
?payment_ev(PaymentID, ?shop_limit_initiated()),
?payment_ev(PaymentID, ?shop_limit_applied()),
?payment_ev(PaymentID, ?risk_score_changed(RS)),
?payment_ev(PaymentID, ?route_changed(Route)),
?payment_ev(PaymentID, ?cash_flow_changed(CashFlow))
] = next_changes(InvoiceID, 3, Client),
] = next_changes(InvoiceID, 5, Client),
CashFlow.
await_payment_rollback(InvoiceID, PaymentID, Client) ->
[
?payment_ev(PaymentID, ?shop_limit_initiated()),
?payment_ev(PaymentID, ?shop_limit_applied()),
?payment_ev(PaymentID, ?risk_score_changed(_)),
?payment_ev(PaymentID, ?route_changed(_, _)),
?payment_ev(PaymentID, ?payment_rollback_started({failure, Failure}))
] = next_changes(InvoiceID, 3, Client),
] = next_changes(InvoiceID, 5, Client),
Failure.
await_payment_shop_limit_rollback(InvoiceID, PaymentID, Client) ->
[
?payment_ev(PaymentID, ?shop_limit_initiated()),
?payment_ev(PaymentID, ?payment_rollback_started({failure, Failure}))
] = next_changes(InvoiceID, 2, Client),
Failure.
await_payment_session_started(InvoiceID, PaymentID, Client, Target) ->
@ -7710,9 +7847,11 @@ execute_payment_w_cascade(InvoiceID, Params, Client, CascadeCount) when CascadeC
#payproc_InvoicePayment{payment = _Payment} = hg_client_invoicing:start_payment(InvoiceID, Params, Client),
[
?payment_ev(PaymentID, ?payment_started(?payment_w_status(?pending()))),
?payment_ev(PaymentID, ?shop_limit_initiated()),
?payment_ev(PaymentID, ?shop_limit_applied()),
?payment_ev(PaymentID, ?risk_score_changed(_))
] =
next_changes(InvoiceID, 2, Client),
next_changes(InvoiceID, 4, Client),
FailedRoutes = [
begin
{Route, _CashFlow, _TrxID, _Failure} =
@ -7856,9 +7995,11 @@ payment_customer_risk_score_check(C) ->
?payment_state(?payment(PaymentID1)) = hg_client_invoicing:start_payment(InvoiceID1, PaymentParams, Client),
[
?payment_ev(PaymentID1, ?payment_started(?payment_w_status(?pending()))),
?payment_ev(PaymentID, ?shop_limit_initiated()),
?payment_ev(PaymentID, ?shop_limit_applied()),
?payment_ev(PaymentID1, ?risk_score_changed(fatal)),
?payment_ev(PaymentID1, ?payment_status_changed(?failed(Failure)))
] = next_changes(InvoiceID1, 3, Client),
] = next_changes(InvoiceID1, 5, Client),
{failure, #domain_Failure{
code = <<"no_route_found">>,
sub = #domain_SubFailure{code = <<"risk_score_is_too_high">>}

View File

@ -23,13 +23,15 @@
-define(LIMIT_ID2, <<"ID2">>).
-define(LIMIT_ID3, <<"ID3">>).
-define(LIMIT_ID4, <<"ID4">>).
-define(SHOPLIMIT_ID, <<"SHOPLIMITID">>).
-spec init_per_suite(config()) -> _.
init_per_suite(_Config) ->
_ = dmt_client:upsert({limit_config, mk_config_object(?LIMIT_ID)}),
_ = dmt_client:upsert({limit_config, mk_config_object(?LIMIT_ID2)}),
_ = dmt_client:upsert({limit_config, mk_config_object(?LIMIT_ID3)}),
_ = dmt_client:upsert({limit_config, mk_config_object(?LIMIT_ID4)}).
_ = dmt_client:upsert({limit_config, mk_config_object(?LIMIT_ID4)}),
_ = dmt_client:upsert({limit_config, mk_config_object(?SHOPLIMIT_ID)}).
-spec get_amount(_) -> pos_integer().
get_amount(#limiter_Limit{amount = Amount}) ->

View File

@ -97,7 +97,7 @@ services:
disable: true
party-management:
image: ghcr.io/valitydev/party-management:sha-28c1b38
image: ghcr.io/valitydev/party-management:sha-7c202dc
command: /opt/party-management/bin/party-management foreground
depends_on:
machinegun:

View File

@ -21,7 +21,7 @@
{<<"ctx">>,{pkg,<<"ctx">>,<<"0.6.0">>},2},
{<<"damsel">>,
{git,"https://github.com/valitydev/damsel.git",
{ref,"781e19277224071639719f9fdfcfd46f9f03a832"}},
{ref,"b04aba83100a4d0adc19b5797372970fd632f911"}},
0},
{<<"dmt_client">>,
{git,"https://github.com/valitydev/dmt-client.git",