diff --git a/apps/ff_transfer/src/ff_withdrawal.erl b/apps/ff_transfer/src/ff_withdrawal.erl index 5e36f2f5..3a530de2 100644 --- a/apps/ff_transfer/src/ff_withdrawal.erl +++ b/apps/ff_transfer/src/ff_withdrawal.erl @@ -1929,10 +1929,11 @@ build_failure({route_not_found, []}, _Withdrawal) -> code => <<"no_route_found">> }; build_failure({route_not_found, RejectedRoutes}, _Withdrawal) -> - #{ + genlib_map:compact(#{ code => <<"no_route_found">>, - reason => genlib:format({rejected_routes, RejectedRoutes}) - }; + reason => genlib:format({rejected_routes, RejectedRoutes}), + sub => build_route_not_found_sub_failure(RejectedRoutes) + }); build_failure({inconsistent_quote_route, {Type, FoundID}}, Withdrawal) -> Details = {inconsistent_quote_route, #{ @@ -1948,6 +1949,25 @@ build_failure(session, Withdrawal) -> {failed, Failure} = Result, Failure. +-define(rejected_route(Reason), {_PrvRef, _TrmRef, Reason}). + +build_route_not_found_sub_failure([]) -> + undefined; +%% NOTE If limit overflow reason present in any rejected route See reason-tuple +%% construction in `ff_withdrawal_routing:validate_turnover_limits/4` and +%% `ff_limiter:check_limits/4`. +build_route_not_found_sub_failure([ + ?rejected_route({terms_violation, {overflow, OverflowedLimits}}) | _ +]) -> + #{ + code => <<"limit_overflow">>, + sub => #{ + code => genlib_string:join($,, [LimitID || {LimitID, _Amount, _Boundary} <- OverflowedLimits]) + } + }; +build_route_not_found_sub_failure([_H | Rest]) -> + build_route_not_found_sub_failure(Rest). + get_quote_field(provider_id, #{route := Route}) -> ff_withdrawal_routing:get_provider(Route); get_quote_field(terminal_id, #{route := Route}) -> diff --git a/apps/ff_transfer/test/ff_withdrawal_limits_SUITE.erl b/apps/ff_transfer/test/ff_withdrawal_limits_SUITE.erl index 4ec2c5e9..01dfaa11 100644 --- a/apps/ff_transfer/test/ff_withdrawal_limits_SUITE.erl +++ b/apps/ff_transfer/test/ff_withdrawal_limits_SUITE.erl @@ -257,7 +257,19 @@ limit_overflow(C) -> PreviousAmount = get_limit_amount(Cash, WalletID, DestinationID, ?LIMIT_TURNOVER_NUM_PAYTOOL_ID2, C), ok = ff_withdrawal_machine:create(WithdrawalParams, ff_entity_context:new()), Result = await_final_withdrawal_status(WithdrawalID), - ?assertMatch({failed, #{code := <<"no_route_found">>}}, Result), + ?assertMatch( + {failed, #{ + code := <<"no_route_found">>, + sub := #{ + code := <<"limit_overflow">>, + sub := #{ + code := LimitID + } + } + }} when + is_binary(LimitID), + Result + ), %% we get final withdrawal status before we rollback limits so wait for it some amount of time ok = timer:sleep(500), Withdrawal = get_withdrawal(WithdrawalID), diff --git a/apps/hellgate/include/domain.hrl b/apps/hellgate/include/domain.hrl index eeedc6d4..8919f5c5 100644 --- a/apps/hellgate/include/domain.hrl +++ b/apps/hellgate/include/domain.hrl @@ -13,13 +13,8 @@ terminal = TerminalRef }). --define(failure(Code), - ?failure(Code, undefined) -). - --define(failure(Code, Reason), - {failure, #domain_Failure{code = Code, reason = Reason}} -). +-define(failure(Code, Reason, Sub), #domain_Failure{code = Code, sub = Sub, reason = Reason}). +-define(subfailure(Code, Sub), #domain_SubFailure{code = Code, sub = Sub}). -define(operation_timeout(), {operation_timeout, #domain_OperationTimeout{}} diff --git a/apps/hellgate/src/hellgate.app.src b/apps/hellgate/src/hellgate.app.src index 0efc1939..000a0d1d 100644 --- a/apps/hellgate/src/hellgate.app.src +++ b/apps/hellgate/src/hellgate.app.src @@ -25,7 +25,6 @@ dmt_client, party_client, bender_client, - payproc_errors, erl_health, limiter_proto, opentelemetry_api, diff --git a/apps/hellgate/src/hg_cascade.erl b/apps/hellgate/src/hg_cascade.erl index 2864d56d..9ad99598 100644 --- a/apps/hellgate/src/hg_cascade.erl +++ b/apps/hellgate/src/hg_cascade.erl @@ -72,10 +72,10 @@ is_mapped_errors_triggered(#domain_CascadeOnMappedErrors{}, {operation_timeout, failure_matches_any_transient(Failure, TransientErrorsList) -> lists:any( fun(ExpectNotation) -> - payproc_errors:match_notation(Failure, fun - (Notation) when binary_part(Notation, {0, byte_size(ExpectNotation)}) =:= ExpectNotation -> true; - (_) -> false - end) + case iolist_to_binary(hg_invoice_utils:format_failure(Failure)) of + Notation when binary_part(Notation, {0, byte_size(ExpectNotation)}) =:= ExpectNotation -> true; + _ -> false + end end, TransientErrorsList ). diff --git a/apps/hellgate/src/hg_invoice_payment.erl b/apps/hellgate/src/hg_invoice_payment.erl index 2babf01a..daa3bf33 100644 --- a/apps/hellgate/src/hg_invoice_payment.erl +++ b/apps/hellgate/src/hg_invoice_payment.erl @@ -1048,11 +1048,9 @@ validate_processing_deadline(#domain_InvoicePayment{processing_deadline = Deadli ok -> ok; {error, deadline_reached} -> - {failure, - payproc_errors:construct( - 'PaymentFailure', - {authorization_failed, {processing_deadline_reached, #payproc_error_GeneralFailure{}}} - )} + {failure, #domain_Failure{ + code = <<"authorization_failed">>, sub = #domain_SubFailure{code = <<"processing_deadline_reached">>} + }} end; validate_processing_deadline(_, _TargetType) -> ok. @@ -1969,8 +1967,8 @@ process_shop_limit_initialization(_Action, St) -> case check_shop_limits(Opts, St) of ok -> {next, {[?shop_limit_initiated()], timeout}}; - {error, {limit_overflow = Error, IDs}} -> - Failure = construct_shop_limit_failure(Error, IDs), + {error, {limit_overflow = Error, LimitIDs}} -> + Failure = construct_shop_limit_failure(Error, LimitIDs), Events = [ ?shop_limit_initiated(), ?payment_rollback_started(Failure) @@ -1978,10 +1976,18 @@ process_shop_limit_initialization(_Action, St) -> {next, {Events, timeout}} 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)}. +construct_shop_limit_failure(limit_overflow, LimitIDs) -> + {failure, #domain_Failure{ + reason = genlib:format("Limits ~p overflowed", [LimitIDs]), + code = <<"authorization_failed">>, + sub = #domain_SubFailure{ + code = <<"shop_limit_exceeded">>, + sub = #domain_SubFailure{ + code = <<"unknown">>, + sub = #domain_SubFailure{code = genlib_string:join($,, LimitIDs)} + } + } + }}. process_shop_limit_failure(_Action, #st{failure = Failure} = St) -> Opts = get_opts(St), @@ -2190,19 +2196,44 @@ log_rejected_route_groups(Result, VS) -> construct_routing_failure({rejected_routes, {SubCode, RejectedRoutes}}) when SubCode =:= limit_misconfiguration orelse - SubCode =:= limit_overflow orelse SubCode =:= adapter_unavailable orelse SubCode =:= provider_conversion_is_too_low -> - construct_routing_failure([rejected, SubCode], genlib:format(normalize_rejected_routes(RejectedRoutes))); + construct_routing_failure( + #domain_SubFailure{code = <<"rejected">>, sub = #domain_SubFailure{code = atom_to_binary(SubCode)}}, + genlib:format(normalize_rejected_routes(RejectedRoutes)) + ); +construct_routing_failure({rejected_routes, {limit_overflow, RejectedRoutes}}) -> + %% NOTE See reason-tuple construction in `get_limit_overflow_routes/4`. + LimitIDs = ordsets:from_list( + lists:flatten([ + LimitIDs + || {_PrvRef, _TrmRef, {'LimitOverflow', LimitIDs}} <- normalize_rejected_routes(RejectedRoutes) + ]) + ), + construct_routing_failure( + #domain_SubFailure{ + code = <<"rejected">>, + sub = #domain_SubFailure{ + code = <<"limit_overflow">>, + sub = #domain_SubFailure{code = genlib_string:join($,, LimitIDs)} + } + }, + genlib:format(normalize_rejected_routes(RejectedRoutes)) + ); construct_routing_failure({rejected_routes, {_SubCode, RejectedRoutes}}) -> - construct_routing_failure([forbidden], genlib:format(normalize_rejected_routes(RejectedRoutes))); + construct_routing_failure( + #domain_SubFailure{code = <<"forbidden">>}, genlib:format(normalize_rejected_routes(RejectedRoutes)) + ); construct_routing_failure({misconfiguration = Code, Details}) -> - construct_routing_failure([unknown, {unknown_error, atom_to_binary(Code)}], genlib:format(Details)); + construct_routing_failure( + #domain_SubFailure{code = <<"unknown">>, sub = #domain_SubFailure{code = atom_to_binary(Code)}}, + genlib:format(Details) + ); construct_routing_failure(risk_score_is_too_high = Code) -> - construct_routing_failure([Code], undefined); + construct_routing_failure(#domain_SubFailure{code = atom_to_binary(Code)}, undefined); construct_routing_failure(Error) when is_atom(Error) -> - construct_routing_failure([{unknown_error, Error}], undefined). + construct_routing_failure(#domain_SubFailure{code = atom_to_binary(Error)}, undefined). normalize_rejected_routes(RejectedRoutes) -> [normalize_rejected_route(Route) || Route <- RejectedRoutes]. @@ -2214,12 +2245,8 @@ normalize_rejected_route(#{provider_ref := _, terminal_ref := _, rejection_reaso normalize_rejected_route(Route) -> Route. -construct_routing_failure(Codes, Reason) -> - {failure, payproc_errors:construct('PaymentFailure', mk_static_error([no_route_found | Codes]), Reason)}. - -mk_static_error([_ | _] = Codes) -> mk_static_error_(#payproc_error_GeneralFailure{}, lists:reverse(Codes)). -mk_static_error_(T, []) -> T; -mk_static_error_(Sub, [Code | Codes]) -> mk_static_error_({Code, Sub}, Codes). +construct_routing_failure(SubFailure, Reason) -> + {failure, #domain_Failure{reason = Reason, code = <<"no_route_found">>, sub = SubFailure}}. -spec process_cash_flow_building(action(), st()) -> machine_result(). process_cash_flow_building(_Action, St) -> @@ -2626,12 +2653,7 @@ get_bank_card_token(?recurrent_payer({bank_card, #domain_BankCard{token = Token} get_bank_card_token(_) -> undefined. -choose_fd_operation_status_for_failure({failure, Failure}) -> - payproc_errors:match('PaymentFailure', Failure, fun do_choose_fd_operation_status_for_failure/1); -choose_fd_operation_status_for_failure(_Failure) -> - finish. - -do_choose_fd_operation_status_for_failure({authorization_failed, {FailType, _}}) -> +choose_fd_operation_status_for_failure({failure, ?failure(<<"authorization_failed">>, _, ?subfailure(FailType0, _))}) -> DefaultBenignFailures = [ insufficient_funds, rejected_by_issuer, @@ -2640,11 +2662,17 @@ do_choose_fd_operation_status_for_failure({authorization_failed, {FailType, _}}) FDConfig = genlib_app:env(hellgate, fault_detector, #{}), Config = genlib_map:get(conversion, FDConfig, #{}), BenignFailures = genlib_map:get(benign_failures, Config, DefaultBenignFailures), - case lists:member(FailType, BenignFailures) of + FailType1 = + try + erlang:binary_to_existing_atom(FailType0, utf8) + catch + error:badarg -> undefined + end, + case lists:member(FailType1, BenignFailures) of false -> error; true -> finish end; -do_choose_fd_operation_status_for_failure(_Failure) -> +choose_fd_operation_status_for_failure(_) -> finish. maybe_notify_fault_detector({payment, processing_session}, processed, Status, St) -> @@ -2686,7 +2714,7 @@ get_initial_retry_strategy(TargetType) -> St :: st(), Timeout :: non_neg_integer(). check_retry_possibility(Target, Failure, St) -> - case check_failure_type(Target, Failure) of + case check_failure_type(Failure) of transient -> RetryStrategy = get_actual_retry_strategy(Target, St), case hg_retry:next_step(RetryStrategy) of @@ -2701,20 +2729,10 @@ check_retry_possibility(Target, Failure, St) -> fatal end. --spec check_failure_type(target(), failure()) -> transient | fatal. -check_failure_type(Target, {failure, Failure}) -> - payproc_errors:match(get_error_class(Target), Failure, fun do_check_failure_type/1); -check_failure_type(_Target, _Other) -> - fatal. - -get_error_class({Target, _}) when Target =:= processed; Target =:= captured; Target =:= cancelled -> - 'PaymentFailure'; -get_error_class(Target) -> - error({unsupported_target, Target}). - -do_check_failure_type({authorization_failed, {temporarily_unavailable, _}}) -> +-spec check_failure_type(failure()) -> transient | fatal. +check_failure_type({failure, ?failure(<<"authorization_failed">>, _, ?subfailure(<<"temporarily_unavailable">>, _))}) -> transient; -do_check_failure_type(_Failure) -> +check_failure_type(_) -> fatal. get_action(?processed(), _Action, St) -> @@ -2796,8 +2814,8 @@ get_limit_overflow_routes(Routes, VS, Iter, St) -> case hg_limiter:check_limits(TurnoverLimits, Invoice, Payment, Session, PaymentRoute, Iter) of {ok, Limits} -> {[Route | RoutesNoOverflowIn], RejectedIn, LimitsIn#{PaymentRoute => Limits}}; - {error, {limit_overflow, IDs, Limits}} -> - RejectedRoute = hg_route:set_rejection_reason({'LimitOverflow', IDs}, Route), + {error, {limit_overflow, LimitIDs}, Limits} -> + RejectedRoute = hg_route:set_rejection_reason({'LimitOverflow', LimitIDs}, Route), {RoutesNoOverflowIn, [RejectedRoute | RejectedIn], LimitsIn#{PaymentRoute => Limits}} end end, @@ -4181,10 +4199,7 @@ format_status_details(_) -> format_failure({operation_timeout, _}) -> [<<"timeout">>]; format_failure({failure, Failure}) -> - format_domain_failure(Failure). - -format_domain_failure(Failure) -> - payproc_errors:format_raw(Failure). + hg_invoice_utils:format_failure(Failure). get_account_key({AccountParty, AccountType}) -> hg_utils:join(AccountParty, $., AccountType). diff --git a/apps/hellgate/src/hg_invoice_payment_refund.erl b/apps/hellgate/src/hg_invoice_payment_refund.erl index f482a60d..4b53434d 100644 --- a/apps/hellgate/src/hg_invoice_payment_refund.erl +++ b/apps/hellgate/src/hg_invoice_payment_refund.erl @@ -304,11 +304,9 @@ process_refund_cashflow(Refund) -> {next, {Events, Action}}; _ -> Failure = - {failure, - payproc_errors:construct( - 'RefundFailure', - {terms_violated, {insufficient_merchant_funds, #payproc_error_GeneralFailure{}}} - )}, + {failure, #domain_Failure{ + code = <<"terms_violated">>, sub = #domain_SubFailure{code = <<"insufficient_merchant_funds">>} + }}, {next, {[?refund_rollback_started(Failure)], Action}} end. @@ -483,12 +481,9 @@ check_retry_possibility(Failure, Refund) -> fatal end. -check_failure_type({failure, Failure}) -> - payproc_errors:match('RefundFailure', Failure, fun do_check_failure_type/1). - -do_check_failure_type({authorization_failed, {temporarily_unavailable, _}}) -> +check_failure_type({failure, ?failure(<<"authorization_failed">>, _, ?subfailure(<<"temporarily_unavailable">>, _))}) -> transient; -do_check_failure_type(_Failure) -> +check_failure_type(_) -> fatal. get_actual_retry_strategy(Refund) -> diff --git a/apps/hellgate/src/hg_invoice_utils.erl b/apps/hellgate/src/hg_invoice_utils.erl index 815ed574..f413b2c2 100644 --- a/apps/hellgate/src/hg_invoice_utils.erl +++ b/apps/hellgate/src/hg_invoice_utils.erl @@ -21,6 +21,7 @@ -export([check_deadline/1]). -export([assert_party_unblocked/1]). -export([assert_shop_unblocked/1]). +-export([format_failure/1]). -type account_id() :: dmsl_domain_thrift:'AccountID'(). -type amount() :: dmsl_domain_thrift:'Amount'(). @@ -180,3 +181,10 @@ check_deadline(Deadline) -> _ -> {error, deadline_reached} end. + +-spec format_failure(dmsl_domain_thrift:'Failure'() | undefined) -> iolist(). +format_failure(Failure) -> lists:join($:, extract_failure_code(Failure)). + +extract_failure_code(undefined) -> []; +extract_failure_code(#domain_Failure{code = Code, sub = Sub}) -> [Code | extract_failure_code(Sub)]; +extract_failure_code(#domain_SubFailure{code = Code, sub = Sub}) -> [Code | extract_failure_code(Sub)]. diff --git a/apps/hellgate/src/hg_limiter.erl b/apps/hellgate/src/hg_limiter.erl index 17a18b2b..5fabdcb1 100644 --- a/apps/hellgate/src/hg_limiter.erl +++ b/apps/hellgate/src/hg_limiter.erl @@ -18,6 +18,7 @@ -type turnover_limit_value() :: dmsl_payproc_thrift:'TurnoverLimitValue'(). -type party_config_ref() :: dmsl_domain_thrift:'PartyConfigRef'(). -type shop_config_ref() :: dmsl_domain_thrift:'ShopConfigRef'(). +-type limit_id() :: dmsl_domain_thrift:'LimitConfigID'(). -export_type([turnover_limit_value/0]). @@ -109,34 +110,26 @@ get_batch_limit_values(Context, TurnoverLimits, OperationIdSegments) -> -spec check_limits([turnover_limit()], invoice(), payment(), session() | undefined, route(), pos_integer()) -> {ok, [turnover_limit_value()]} - | {error, {limit_overflow, [binary()], [turnover_limit_value()]}}. + | {error, {limit_overflow, nonempty_list(limit_id())}, [turnover_limit_value()]}. check_limits(TurnoverLimits, Invoice, Payment, Session, Route, Iter) -> Context = gen_limit_context(Invoice, Payment, Session, Route), Limits = get_limit_values(Context, TurnoverLimits, make_route_operation_segments(Invoice, Payment, Route, Iter)), - try - ok = check_limits_(Limits, Context), - {ok, Limits} - catch - throw:limit_overflow -> - IDs = [T#domain_TurnoverLimit.ref#domain_LimitConfigRef.id || T <- TurnoverLimits], - {error, {limit_overflow, IDs, Limits}} + case check_limits_(Limits) of + ok -> + {ok, Limits}; + {error, Reason} -> + {error, Reason, Limits} end. -spec check_shop_limits([turnover_limit()], party_config_ref(), shop_config_ref(), invoice(), payment()) -> ok - | {error, {limit_overflow, [binary()]}}. + | {error, {limit_overflow, nonempty_list(limit_id())}}. check_shop_limits(TurnoverLimits, PartyConfigRef, ShopConfigRef, Invoice, Payment) -> Context = gen_limit_shop_context(Invoice, Payment), Limits = get_limit_values( Context, TurnoverLimits, make_shop_operation_segments(PartyConfigRef, ShopConfigRef, Invoice, Payment) ), - try - check_limits_(Limits, Context) - catch - throw:limit_overflow -> - IDs = [T#domain_TurnoverLimit.ref#domain_LimitConfigRef.id || T <- TurnoverLimits], - {error, {limit_overflow, IDs}} - end. + check_limits_(Limits). make_shop_operation_segments(PartyConfigRef, ShopConfigRef, Invoice, Payment) -> [ @@ -146,26 +139,30 @@ make_shop_operation_segments(PartyConfigRef, ShopConfigRef, Invoice, Payment) -> get_payment_id(Payment) ]. -check_limits_([], _) -> - ok; -check_limits_([TurnoverLimitValue | TLVs], Context) -> +check_limits_(LimitValues) -> + case lists:foldl(fun check_limit_/2, [], LimitValues) of + [] -> + ok; + LimitIDs -> + {error, {limit_overflow, ordsets:from_list(LimitIDs)}} + end. + +check_limit_( #payproc_TurnoverLimitValue{ - limit = #domain_TurnoverLimit{ - ref = ?ref(LimitID), - upper_boundary = UpperBoundary - }, - value = LimiterAmount - } = TurnoverLimitValue, - case LimiterAmount =< UpperBoundary of + limit = #domain_TurnoverLimit{ref = ?ref(LimitID), upper_boundary = UpperBoundary}, + value = LimitAmount + }, + OverflowedLimits +) -> + case LimitAmount =< UpperBoundary of true -> - check_limits_(TLVs, Context); + OverflowedLimits; false -> - logger:notice("Limit with id ~p overflowed, amount ~p upper boundary ~p", [ - LimitID, - LimiterAmount, - UpperBoundary - ]), - throw(limit_overflow) + ok = logger:notice( + "Limit with id ~p overflowed, amount ~p upper boundary ~p", + [LimitID, LimitAmount, UpperBoundary] + ), + [LimitID | OverflowedLimits] end. -spec hold_payment_limits([turnover_limit()], invoice(), payment(), session() | undefined, route(), pos_integer()) -> diff --git a/apps/hellgate/test/hg_ct_domain.hrl b/apps/hellgate/test/hg_ct_domain.hrl index f62a8416..04952162 100644 --- a/apps/hellgate/test/hg_ct_domain.hrl +++ b/apps/hellgate/test/hg_ct_domain.hrl @@ -233,8 +233,6 @@ ]} }). --define(err_gen_failure(), #payproc_error_GeneralFailure{}). - -define(redirect(Uri, Form), {redirect, {post_request, #user_interaction_BrowserPostRequest{uri = Uri, form = Form}}} ). diff --git a/apps/hellgate/test/hg_dummy_provider.erl b/apps/hellgate/test/hg_dummy_provider.erl index a74a2e2a..90014da4 100644 --- a/apps/hellgate/test/hg_dummy_provider.erl +++ b/apps/hellgate/test/hg_dummy_provider.erl @@ -415,7 +415,7 @@ get_failure_scenario_step(Scenario, Step) -> lists:nth(Step, Scenario). process_refund(_State, PaymentInfo, #{<<"always_fail">> := FailureCode, <<"override">> := ProviderCode} = CtxOpts, _) -> - Failure = payproc_errors:from_notation(FailureCode, <<"sub failure by ", ProviderCode/binary>>), + Failure = from_notation(FailureCode, <<"sub failure by ", ProviderCode/binary>>), TrxID = hg_utils:construct_complex_id([get_payment_id(PaymentInfo), get_ctx_opts_override(CtxOpts)]), result(?finish({failure, Failure}), undefined, mk_trx(TrxID, PaymentInfo)); process_refund(undefined, PaymentInfo, CtxOpts, _) -> @@ -472,7 +472,7 @@ result(Intent, NextState, Trx) -> maybe_fail(PaymentInfo, #{<<"always_fail">> := FailureCode, <<"override">> := ProviderCode} = CtxOpts, _OrElse) -> _ = maybe_sleep(CtxOpts), Reason = <<"sub failure by ", ProviderCode/binary>>, - Failure = payproc_errors:from_notation(FailureCode, <<"sub failure by ", ProviderCode/binary>>), + Failure = from_notation(FailureCode, <<"sub failure by ", ProviderCode/binary>>), TrxID = hg_utils:construct_complex_id([get_payment_id(PaymentInfo), get_ctx_opts_override(CtxOpts)]), result(?finish({failure, Failure}), <<"state: ", Reason/binary>>, mk_trx(TrxID, PaymentInfo)); maybe_fail(_PaymentInfo, _CtxOpts, OrElse) -> @@ -524,11 +524,7 @@ failure(Code) when is_atom(Code) -> failure(Code, unknown). failure(Code, Sub) when is_atom(Code), is_atom(Sub) -> - {failure, - payproc_errors:construct( - 'PaymentFailure', - {Code, {Sub, #payproc_error_GeneralFailure{}}} - )}. + {failure, #domain_Failure{code = atom_to_binary(Code), sub = #domain_SubFailure{code = atom_to_binary(Sub)}}}. get_payment_id(#proxy_provider_PaymentInfo{payment = Payment}) -> Payment#proxy_provider_InvoicePayment.id. @@ -916,3 +912,14 @@ maybe_sleep(_Opts) -> get_ctx_opts_override(CtxOpts) -> maps:get(<<"override">>, CtxOpts, <<"">>). + +from_notation(Notation, Reason) when is_binary(Notation) -> + Codes = lists:reverse(binary:split(Notation, <<$:>>, [global])), + do_construct_from_notation(Codes, Reason, undefined). + +do_construct_from_notation([<<"">>], _Reason, _SubFailure) -> + undefined; +do_construct_from_notation([Code], Reason, SubFailure) -> + #domain_Failure{code = Code, reason = Reason, sub = SubFailure}; +do_construct_from_notation([SubCode | Codes], Reason, SubFailure) -> + do_construct_from_notation(Codes, Reason, #domain_SubFailure{code = SubCode, sub = SubFailure}). diff --git a/apps/hellgate/test/hg_invoice_tests_SUITE.erl b/apps/hellgate/test/hg_invoice_tests_SUITE.erl index fa500256..2247b149 100644 --- a/apps/hellgate/test/hg_invoice_tests_SUITE.erl +++ b/apps/hellgate/test/hg_invoice_tests_SUITE.erl @@ -653,15 +653,24 @@ end_per_suite(C) -> -define(system_to_external_fixed, ?fixed(20, <<"RUB">>)). -define(merchant_to_system_fixed, ?fixed(100, <<"RUB">>)). --define(assertRouteNotFound(Failure, Sub, ReasonSubstring), begin - ok = payproc_errors:match('PaymentFailure', Failure, fun({no_route_found, Sub}) -> ok end), +-define(assertFailure(Failure, TupleMask), ?assertMatch(TupleMask, failure_to_tuple(Failure))). + +-define(assertFailure(Failure, TupleMask, ReasonSubstring), begin + FailureTuple = failure_to_tuple(Failure), + ?assertMatch(TupleMask, FailureTuple), Reason = Failure#domain_Failure.reason, ?assert( nomatch =/= binary:match(Reason, ReasonSubstring), - <<"Failure reason '", Reason/binary, "' for 'no_route_found' doesn't match '", ReasonSubstring/binary, "'">> + iolist_to_binary( + io_lib:format("Failure reason '~s' for '~p' doesn't match '~s'", [Reason, FailureTuple, ReasonSubstring]) + ) ) end). +-define(assertRouteNotFound(Failure, Sub, ReasonSubstring), begin + ?assertFailure(Failure, {no_route_found, Sub}, ReasonSubstring) +end). + -spec init_per_group(group_name(), config()) -> config(). init_per_group(route_cascading, C) -> [{pre_group_domain_revision, hg_domain:head()} | init_route_cascading_group(C)]; @@ -1245,11 +1254,7 @@ payment_shop_limit_overflow(C) -> Failure = create_payment_shop_limit_overflow( PartyConfigRef, ShopConfigRef, PaymentAmount, Client, ?pmt_sys(<<"visa-ref">>) ), - ok = payproc_errors:match('PaymentFailure', Failure, fun( - {authorization_failed, {shop_limit_exceeded, {unknown, _}}} - ) -> - ok - end). + ?assertFailure(Failure, {authorization_failed, {shop_limit_exceeded, {unknown, _}}}). -spec payment_shop_limit_more_overflow(config()) -> test_return(). payment_shop_limit_more_overflow(C) -> @@ -1276,11 +1281,7 @@ payment_shop_limit_more_overflow(C) -> Failure = create_payment_shop_limit_overflow( PartyConfigRef, ShopConfigRef, PaymentAmount, Client, ?pmt_sys(<<"visa-ref">>) ), - ok = payproc_errors:match('PaymentFailure', Failure, fun( - {authorization_failed, {shop_limit_exceeded, {unknown, _}}} - ) -> - ok - end). + ?assertFailure(Failure, {authorization_failed, {shop_limit_exceeded, {unknown, _}}}). -spec payment_routes_limit_values(config()) -> test_return(). payment_routes_limit_values(C) -> @@ -1359,11 +1360,10 @@ payment_limit_overflow(C) -> ok = hg_limiter_helper:assert_payment_limit_amount( ?LIMIT_ID, configured_limit_version(C), PaymentAmount, Payment, Invoice ), - ok = payproc_errors:match( - 'PaymentFailure', - Failure, - fun({no_route_found, {rejected, {limit_overflow, _}}}) -> ok end - ). + %% NOTE We expect binary value of limit id to match exixting atom, so helper + %% fun inside an assert will translate it to it. + ExpectedLimitID = binary_to_existing_atom(?LIMIT_ID), + ?assertFailure(Failure, {no_route_found, {rejected, {limit_overflow, {ExpectedLimitID, undefined}}}}). -spec limit_hold_currency_error(config()) -> test_return(). limit_hold_currency_error(C) -> @@ -1384,7 +1384,13 @@ limit_hold_payment_tool_not_supported(C) -> -spec limit_hold_two_routes_failure(config()) -> test_return(). limit_hold_two_routes_failure(C) -> Failure = payment_route_not_found(C), - ?assertRouteNotFound(Failure, {rejected, {limit_overflow, _}}, <<"[{">>). + ?assertRouteNotFound( + Failure, + {rejected, {limit_overflow, _}}, + %% NOTE Start of long and nested list of tuples describing route with + %% corresponding limit's states + <<"[{">> + ). payment_route_not_found(C) -> PmtSys = ?pmt_sys(<<"visa-ref">>), @@ -1483,11 +1489,7 @@ refund_limit_success(C) -> ?payment(PaymentID) = Payment, Failure = create_payment_limit_overflow(PartyConfigRef, ShopConfigRef, 50000, Client, PmtSys), - ok = payproc_errors:match( - 'PaymentFailure', - Failure, - fun({no_route_found, {rejected, {limit_overflow, _}}}) -> ok end - ), + ?assertFailure(Failure, {no_route_found, {rejected, {limit_overflow, _}}}), % create a refund finally RefundParams = make_refund_params(), RefundID = execute_payment_refund(InvoiceID, PaymentID, RefundParams, Client), @@ -1611,11 +1613,7 @@ processing_deadline_reached_test(C) -> ?payment_ev(PaymentID, ?payment_rollback_started({failure, Failure})), ?payment_ev(PaymentID, ?payment_status_changed(?failed({failure, Failure}))) ] = next_changes(InvoiceID, 2, Client), - ok = payproc_errors:match( - 'PaymentFailure', - Failure, - fun({authorization_failed, {processing_deadline_reached, _}}) -> ok end - ). + ?assertFailure(Failure, {authorization_failed, {processing_deadline_reached, _}}). -spec payment_w_misconfigured_routing_failed(config()) -> test_return(). payment_w_misconfigured_routing_failed(C) -> @@ -1633,7 +1631,7 @@ payment_w_misconfigured_routing_failed(C) -> ?payment_ev(PaymentID, ?payment_status_changed(?failed({failure, Failure}))) ] = next_changes(InvoiceID, 5, Client), Reason = genlib:format({routing_decisions, {delegates, []}}), - ?assertRouteNotFound(Failure, {unknown, {{unknown_error, <<"misconfiguration">>}, _}}, Reason). + ?assertRouteNotFound(Failure, {unknown, {misconfiguration, _}}, Reason). payment_w_misconfigured_routing_failed_fixture(_Revision, _C) -> [ @@ -2340,12 +2338,13 @@ payment_session_changed_to_fail(C) -> %% Payment w/ preauth for suspend w/ user interaction occurrence. PaymentID = start_payment(InvoiceID, make_tds_payment_params(instant, ?pmt_sys(<<"visa-ref">>)), Client), UserInteraction = await_payment_process_interaction(InvoiceID, PaymentID, Client), - - Failure = payproc_errors:construct( - 'PaymentFailure', - {authorization_failed, {operation_blocked, ?err_gen_failure()}}, - genlib:unique() - ), + Failure = #domain_Failure{ + reason = genlib:unique(), + code = <<"authorization_failed">>, + sub = #domain_SubFailure{ + code = <<"operation_blocked">> + } + }, Change = #proxy_provider_PaymentSessionChange{status = {failure, Failure}}, %% Unknown session callback tag @@ -2534,11 +2533,7 @@ payment_risk_score_check(C) -> ?payment_ev(PaymentID3, ?risk_score_changed(fatal)), ?payment_ev(PaymentID3, ?payment_status_changed(?failed({failure, Failure}))) ] = next_changes(InvoiceID3, 5, Client), - ok = payproc_errors:match( - 'PaymentFailure', - Failure, - fun({no_route_found, _}) -> ok end - ). + ?assertFailure(Failure, {no_route_found, _}). -spec payment_risk_score_check_fail(config()) -> test_return(). payment_risk_score_check_fail(C) -> @@ -3397,11 +3392,7 @@ payment_temporary_unavailability_too_many_retries(C) -> PaymentID = await_payment_session_started(InvoiceID, PaymentID, Client, ?processed()), {failed, PaymentID, {failure, Failure}} = await_payment_process_failure(InvoiceID, PaymentID, Client, 3), - ok = payproc_errors:match( - 'PaymentFailure', - Failure, - fun({authorization_failed, {temporarily_unavailable, _}}) -> ok end - ). + ?assertFailure(Failure, {authorization_failed, {temporarily_unavailable, _}}). update_payment_terms_cashflow(ProviderRef, CashFlow) -> Provider = hg_domain:get({provider, ProviderRef}), @@ -4722,11 +4713,9 @@ payment_refund_success(C) -> PaymentID = await_payment_capture(InvoiceID, PaymentID, Client), % not enough funds on the merchant account Failure = - {failure, - payproc_errors:construct( - 'RefundFailure', - {terms_violated, {insufficient_merchant_funds, ?err_gen_failure()}} - )}, + {failure, #domain_Failure{ + code = <<"terms_violated">>, sub = #domain_SubFailure{code = <<"insufficient_merchant_funds">>} + }}, ?refund_id(RefundID0) = hg_client_invoicing:refund_payment(InvoiceID, PaymentID, RefundParams, Client), PaymentID = await_refund_created(InvoiceID, PaymentID, RefundID0, Client), @@ -4767,11 +4756,9 @@ payment_refund_failure(C) -> PaymentID = await_payment_capture(InvoiceID, PaymentID, Client), % not enough funds on the merchant account NoFunds = - {failure, - payproc_errors:construct( - 'RefundFailure', - {terms_violated, {insufficient_merchant_funds, ?err_gen_failure()}} - )}, + {failure, #domain_Failure{ + code = <<"terms_violated">>, sub = #domain_SubFailure{code = <<"insufficient_merchant_funds">>} + }}, ?refund_id(RefundID0) = hg_client_invoicing:refund_payment(InvoiceID, PaymentID, RefundParams, Client), PaymentID = await_refund_created(InvoiceID, PaymentID, RefundID0, Client), @@ -4879,11 +4866,9 @@ deadline_doesnt_affect_payment_refund(C) -> timer:sleep(ProcessingDeadline), % not enough funds on the merchant account NoFunds = - {failure, - payproc_errors:construct( - 'RefundFailure', - {terms_violated, {insufficient_merchant_funds, ?err_gen_failure()}} - )}, + {failure, #domain_Failure{ + code = <<"terms_violated">>, sub = #domain_SubFailure{code = <<"insufficient_merchant_funds">>} + }}, ?refund_id(RefundID0) = hg_client_invoicing:refund_payment(InvoiceID, PaymentID, RefundParams, Client), PaymentID = await_refund_created(InvoiceID, PaymentID, RefundID0, Client), @@ -4921,11 +4906,9 @@ payment_manual_refund(C) -> PaymentID = await_payment_capture(InvoiceID, PaymentID, Client), % not enough funds on the merchant account NoFunds = - {failure, - payproc_errors:construct( - 'RefundFailure', - {terms_violated, {insufficient_merchant_funds, ?err_gen_failure()}} - )}, + {failure, #domain_Failure{ + code = <<"terms_violated">>, sub = #domain_SubFailure{code = <<"insufficient_merchant_funds">>} + }}, Refund0 = ?refund_id(RefundID0) = hg_client_invoicing:refund_payment_manual(InvoiceID, PaymentID, RefundParams, Client), @@ -5607,10 +5590,7 @@ adhoc_repair_force_invalid_transition(C) -> PaymentParams = make_payment_params(?pmt_sys(<<"visa-ref">>)), PaymentID = execute_payment(InvoiceID, PaymentParams, Client), _ = ?assertEqual(ok, hg_invoice:fail(InvoiceID)), - Failure = payproc_errors:construct( - 'PaymentFailure', - {authorization_failed, {unknown, ?err_gen_failure()}} - ), + Failure = #domain_Failure{code = <<"authorization_failed">>, sub = #domain_SubFailure{code = <<"unknown">>}}, InvalidChanges = [ ?payment_ev(PaymentID, ?payment_status_changed(?failed({failure, Failure}))), ?invoice_status_changed(?invoice_unpaid()) @@ -5675,7 +5655,7 @@ payment_with_offsite_preauth_failed(C) -> next_change(InvoiceID, 8000, Client), ?payment_ev(PaymentID, ?payment_status_changed(?failed({failure, Failure}))) = next_change(InvoiceID, 8000, Client), - ok = payproc_errors:match('PaymentFailure', Failure, fun({authorization_failed, _}) -> ok end), + ?assertFailure(Failure, {authorization_failed, _}), ?invoice_status_changed(?invoice_cancelled(<<"overdue">>)) = next_change(InvoiceID, Client). -spec payment_with_tokenized_bank_card(config()) -> test_return(). @@ -5820,11 +5800,11 @@ repair_fail_session_on_processed_succeeded(C) -> timeout = next_change(InvoiceID, 2000, Client), - Failure = payproc_errors:construct( - 'PaymentFailure', - {authorization_failed, {security_policy_violated, ?err_gen_failure()}}, - genlib:unique() - ), + Failure = #domain_Failure{ + reason = genlib:unique(), + code = <<"authorization_failed">>, + sub = #domain_SubFailure{code = <<"security_policy_violated">>} + }, ok = repair_invoice_with_scenario(InvoiceID, {fail_session, Failure}, Client), [ @@ -6004,10 +5984,7 @@ repair_fulfill_session_with_trx_succeeded(C) -> PaymentID = await_payment_capture(InvoiceID, PaymentID, Client). construct_authorization_failure() -> - payproc_errors:construct( - 'PaymentFailure', - {authorization_failed, {unknown, ?err_gen_failure()}} - ). + #domain_Failure{code = <<"authorization_failed">>, sub = #domain_SubFailure{code = <<"unknown">>}}. %% @@ -6438,11 +6415,7 @@ payment_cascade_success(C) -> ] = next_changes(InvoiceID, 4, Client), {Route1, _Candidates1, _CashFlow1, TrxID1, Failure1} = await_cascade_triggering(InvoiceID, PaymentID, Client), - ok = payproc_errors:match( - 'PaymentFailure', - Failure1, - fun({preauthorization_failed, {card_blocked, _}}) -> ok end - ), + ?assertFailure(Failure1, {preauthorization_failed, {card_blocked, _}}), %% Assert payment status IS NOT failed ?invoice_state(?invoice_w_status(_), [?payment_state(PaymentInterim)]) = hg_client_invoicing:get(InvoiceID, Client), @@ -6828,7 +6801,7 @@ payment_cascade_limit_overflow(C) -> ] = next_changes(InvoiceID, 4, Client), {Route1, _Candidates1, _CashFlow1, _TrxID1, Failure1} = await_cascade_triggering(InvoiceID, PaymentID, Client), - ok = payproc_errors:match('PaymentFailure', Failure1, fun({authorization_failed, {unknown, _}}) -> ok end), + ?assertFailure(Failure1, {authorization_failed, {unknown, _}}), %% And again but no route found [ ?payment_ev(PaymentID, ?route_changed(Route2, Candidates2)), @@ -6839,7 +6812,7 @@ payment_cascade_limit_overflow(C) -> ?assertNotEqual(Route1, Route2), ?assertNot(lists:member(Route1, Candidates2)), %% No route found and so we pass original failure from previous attempt - ok = payproc_errors:match('PaymentFailure', Failure2, fun({authorization_failed, {unknown, _}}) -> ok end), + ?assertFailure(Failure2, {authorization_failed, {unknown, _}}), %% Assert payment status IS failed ?invoice_state(?invoice_w_status(_), [?payment_state(FinalPayment)]) = hg_client_invoicing:get(InvoiceID, Client), @@ -6889,11 +6862,7 @@ payment_big_cascade_success(C) -> (fun() -> {Route, Candidates, _CashFlow, _TrxID, Failure} = await_cascade_triggering(InvoiceID, PaymentID, Client), - ok = payproc_errors:match( - 'PaymentFailure', - Failure, - fun({preauthorization_failed, {card_blocked, _}}) -> ok end - ), + ?assertFailure(Failure, {preauthorization_failed, {card_blocked, _}}), _ = [ ?assertMatch( HoldValue when HoldValue =:= 0 orelse HoldValue =:= Amount, @@ -7179,7 +7148,7 @@ payment_cascade_fail_ui(C) -> ] = next_changes(InvoiceID, 4, Client), {_Route1, _Candidates1, _CashFlow1, _TrxID1, Failure1} = await_cascade_triggering(InvoiceID, PaymentID, Client), - ok = payproc_errors:match('PaymentFailure', Failure1, fun({authorization_failed, {unknown, _}}) -> ok end), + ?assertFailure(Failure1, {authorization_failed, {unknown, _}}), %% And again with UI [ ?payment_ev(PaymentID, ?route_changed(_Route2)), @@ -7200,7 +7169,7 @@ payment_cascade_fail_ui(C) -> next_changes(InvoiceID, 3, Client), ?payment_ev(PaymentID, ?payment_status_changed(?failed({failure, Failure2}))) = next_change(InvoiceID, Client), - ok = payproc_errors:match('PaymentFailure', Failure2, fun({preauthorization_failed, {unknown, _}}) -> ok end), + ?assertFailure(Failure2, {preauthorization_failed, {unknown, _}}), %% Assert payment status IS failed ?invoice_state(?invoice_w_status(_), [?payment_state(Payment)]) = hg_client_invoicing:get(InvoiceID, Client), @@ -7384,7 +7353,7 @@ payment_cascade_fail_wo_available_attempt_limit(C) -> await_cascade_triggering(InvoiceID, PaymentID, Client), ?payment_ev(PaymentID, ?payment_status_changed(?failed({failure, Failure}))) = next_change(InvoiceID, Client), - ok = payproc_errors:match('PaymentFailure', Failure, fun({preauthorization_failed, {card_blocked, _}}) -> ok end), + ?assertFailure(Failure, {preauthorization_failed, {card_blocked, _}}), %% Assert payment status IS failed ?invoice_state(?invoice_w_status(_), [?payment_state(Payment)]) = hg_client_invoicing:get(InvoiceID, Client), @@ -7472,13 +7441,13 @@ payment_cascade_failures(C) -> ] = next_changes(InvoiceID, 4, Client), {_Route1, _Candidates1, _CashFlow1, _TrxID1, Failure1} = await_cascade_triggering(InvoiceID, PaymentID, Client), - ok = payproc_errors:match('PaymentFailure', Failure1, fun({preauthorization_failed, {card_blocked, _}}) -> ok end), + ?assertFailure(Failure1, {preauthorization_failed, {card_blocked, _}}), %% And again {_Route2, _Candidates2, _CashFlow2, _TrxID2, Failure2} = await_cascade_triggering(InvoiceID, PaymentID, Client), ?payment_ev(PaymentID, ?payment_status_changed(?failed({failure, Failure2}))) = next_change(InvoiceID, Client), - ok = payproc_errors:match('PaymentFailure', Failure2, fun({preauthorization_failed, {card_blocked, _}}) -> ok end), + ?assertFailure(Failure2, {preauthorization_failed, {card_blocked, _}}), %% Assert payment status IS failed ?invoice_state(?invoice_w_status(_), [?payment_state(Payment)]) = hg_client_invoicing:get(InvoiceID, Client), @@ -7573,7 +7542,7 @@ payment_cascade_deadline_failures(C) -> ] = next_changes(InvoiceID, 4, Client), {_Route1, _Candidates1, _CashFlow1, _TrxID1, Failure1} = await_cascade_triggering(InvoiceID, PaymentID, Client), - ok = payproc_errors:match('PaymentFailure', Failure1, fun({preauthorization_failed, {card_blocked, _}}) -> ok end), + ?assertFailure(Failure1, {preauthorization_failed, {card_blocked, _}}), %% And again ?payment_ev(PaymentID, ?route_changed(_Route2)) = next_change(InvoiceID, Client), @@ -7583,11 +7552,7 @@ payment_cascade_deadline_failures(C) -> next_change(InvoiceID, Client), ?payment_ev(PaymentID, ?payment_status_changed(?failed({failure, Failure2}))) = next_change(InvoiceID, Client), - ok = payproc_errors:match( - 'PaymentFailure', - Failure2, - fun({authorization_failed, {processing_deadline_reached, _}}) -> ok end - ), + ?assertFailure(Failure2, {authorization_failed, {processing_deadline_reached, _}}), %% Assert payment status IS failed ?invoice_state(?invoice_w_status(_), [?payment_state(Payment)]) = hg_client_invoicing:get(InvoiceID, Client), @@ -7812,11 +7777,7 @@ payment_recurrent_cascade_success(C) -> #domain_PaymentRoute{provider = ?prv(?CASCADE_ID_RANGE(?PAYMENT_RECURRENT_CASCADE_SUCCESS_ID + 1))}, Route1 ), - ok = payproc_errors:match( - 'PaymentFailure', - Failure1, - fun({preauthorization_failed, {card_blocked, _}}) -> ok end - ), + ?assertFailure(Failure1, {preauthorization_failed, {card_blocked, _}}), [ ?payment_ev(PaymentID, ?route_changed(Route2)), ?payment_ev(PaymentID, ?cash_flow_changed(_CashFlow2)) @@ -7869,11 +7830,7 @@ payment_recurrent_cascade_fail(C) -> next_change(InvoiceID, Client), ?payment_ev(PaymentID, ?payment_status_changed(?failed({failure, Failure}))) = next_change(InvoiceID, Client), - ok = payproc_errors:match( - 'PaymentFailure', - Failure, - fun({preauthorization_failed, {card_blocked, _}}) -> ok end - ), + ?assertFailure(Failure, {preauthorization_failed, {card_blocked, _}}), ?invoice_state(?invoice_w_status(_), [?payment_state(Payment)]) = hg_client_invoicing:get(InvoiceID, Client), ?assertMatch(#domain_InvoicePayment{status = {failed, _}}, Payment). @@ -8159,7 +8116,7 @@ repair_invoice(InvoiceID, Changes, Action, Params, Client) -> hg_client_invoicing:repair(InvoiceID, Changes, Action, Params, Client). create_repair_scenario(fail_pre_processing) -> - Failure = payproc_errors:construct('PaymentFailure', {no_route_found, {unknown, ?err_gen_failure()}}), + Failure = #domain_Failure{code = <<"no_route_found">>, sub = #domain_SubFailure{code = <<"unknown">>}}, {'fail_pre_processing', #'payproc_InvoiceRepairFailPreProcessing'{failure = Failure}}; create_repair_scenario(skip_inspector) -> {'skip_inspector', #'payproc_InvoiceRepairSkipInspector'{risk_score = low}}; @@ -10728,3 +10685,17 @@ mock_fault_detector(SupPid) -> configured_limit_version(C) -> genlib:define(cfg(original_domain_revision, C), cfg(base_limits_domain_revision, C)). + +failure_to_tuple(undefined) -> undefined; +failure_to_tuple(?subfailure(Code, SubFailure)) -> failure_to_tuple_(Code, SubFailure); +failure_to_tuple(?failure(Code, _, SubFailure)) -> failure_to_tuple_(Code, SubFailure). + +failure_to_tuple_(Code, SubFailure) -> + {normalize_failure_code(Code), failure_to_tuple(SubFailure)}. +normalize_failure_code(Code) -> + try + erlang:binary_to_existing_atom(Code, utf8) + catch + error:badarg -> + {unknown_error, Code} + end. diff --git a/rebar.config b/rebar.config index 316e3ea4..1da95a43 100644 --- a/rebar.config +++ b/rebar.config @@ -38,7 +38,6 @@ {thrift, {git, "https://github.com/valitydev/thrift_erlang.git", {tag, "v1.0.0"}}}, {damsel, {git, "https://github.com/valitydev/damsel.git", {tag, "v2.2.44"}}}, {exrates_proto, {git, "https://github.com/valitydev/exrates-proto.git", {branch, "master"}}}, - {payproc_errors, {git, "https://github.com/valitydev/payproc-errors-erlang.git", {branch, "master"}}}, {mg_proto, {git, "https://github.com/valitydev/machinegun-proto.git", {branch, "master"}}}, {dmt_client, {git, "https://github.com/valitydev/dmt-client.git", {tag, "v2.0.3"}}}, {party_client, {git, "https://github.com/valitydev/party-client-erlang.git", {tag, "v2.0.1"}}}, diff --git a/rebar.lock b/rebar.lock index 8bbe4afc..3b439112 100644 --- a/rebar.lock +++ b/rebar.lock @@ -115,10 +115,6 @@ {git,"https://github.com/valitydev/party-client-erlang.git", {ref,"88cb5a9b5abd9bb437222de168bba096edd10882"}}, 0}, - {<<"payproc_errors">>, - {git,"https://github.com/valitydev/payproc-errors-erlang.git", - {ref,"8ae8586239ef68098398acf7eb8363d9ec3b3234"}}, - 0}, {<<"progressor">>, {git,"https://github.com/valitydev/progressor.git", {ref,"2435f86863a6ee3e6a1900cfcafaf15886e41112"}},