diff --git a/.env b/.env index aa65099..1934013 100644 --- a/.env +++ b/.env @@ -1,4 +1,4 @@ SERVICE_NAME=limiter -OTP_VERSION=24.2.0 +OTP_VERSION=24.3.4 REBAR_VERSION=3.18 -THRIFT_VERSION=0.14.2.2 +THRIFT_VERSION=0.14.2.3 diff --git a/apps/limiter/src/lim_accounting.erl b/apps/limiter/src/lim_accounting.erl index 0ef575a..39366c9 100644 --- a/apps/limiter/src/lim_accounting.erl +++ b/apps/limiter/src/lim_accounting.erl @@ -161,7 +161,7 @@ call_accounter(Function, Args, LimitContext) -> WoodyContext = lim_context:woody_context(LimitContext), lim_client_woody:call(accounter, Function, Args, WoodyContext). -convert_exception(#'InvalidRequest'{errors = Errors}) -> +convert_exception(#base_InvalidRequest{errors = Errors}) -> Errors; convert_exception(#accounter_InvalidPostingParams{wrong_postings = Errors}) -> maps:fold(fun(_, Error, Acc) -> [Error | Acc] end, [], Errors). diff --git a/apps/limiter/src/lim_body.erl b/apps/limiter/src/lim_body.erl index c2be6f4..9da6c45 100644 --- a/apps/limiter/src/lim_body.erl +++ b/apps/limiter/src/lim_body.erl @@ -8,7 +8,7 @@ currency := currency() }. --type currency() :: lim_domain_thrift:'CurrencySymbolicCode'(). +-type currency() :: dmsl_domain_thrift:'CurrencySymbolicCode'(). -type config() :: lim_config_machine:config(). -type body_type() :: full | partial. @@ -24,47 +24,18 @@ get(BodyType, Config, LimitContext) -> do(fun() -> ContextType = lim_config_machine:context_type(Config), {ok, Operation} = lim_context:get_operation(ContextType, LimitContext), - Body = unwrap(get_body_for_operation(BodyType, Operation, Config, LimitContext)), - apply_op_behaviour(Body, Config, LimitContext) + Body = unwrap(get_body_for_operation(BodyType, ContextType, LimitContext)), + apply_op_behaviour(Operation, Body, Config) end). --spec get_body_for_operation(body_type(), lim_context:context_operation(), config(), lim_context:t()) -> +-spec get_body_for_operation(body_type(), lim_context:context_type(), lim_context:t()) -> {ok, cash()} | {error, notfound}. -get_body_for_operation(full, invoice = Operation, Config, LimitContext) -> - ContextType = lim_config_machine:context_type(Config), - lim_context:get_from_context(ContextType, cost, Operation, LimitContext); -get_body_for_operation(full, invoice_adjustment, Config, LimitContext) -> - ContextType = lim_config_machine:context_type(Config), - lim_context:get_from_context(ContextType, cost, invoice, LimitContext); -get_body_for_operation(full, invoice_payment = Operation, Config, LimitContext) -> - ContextType = lim_config_machine:context_type(Config), - lim_context:get_from_context(ContextType, cost, Operation, LimitContext); -get_body_for_operation(full, invoice_payment_adjustment, Config, LimitContext) -> - ContextType = lim_config_machine:context_type(Config), - lim_context:get_from_context(ContextType, cost, invoice_payment, LimitContext); -get_body_for_operation(full, invoice_payment_refund, Config, LimitContext) -> - ContextType = lim_config_machine:context_type(Config), - lim_context:get_from_context(ContextType, cost, invoice_payment, LimitContext); -get_body_for_operation(full, invoice_payment_chargeback = Operation, Config, LimitContext) -> - ContextType = lim_config_machine:context_type(Config), - lim_context:get_from_context(ContextType, body, Operation, LimitContext); -get_body_for_operation(partial, invoice, _Config, _LimitContext) -> - {error, notfound}; -get_body_for_operation(partial, invoice_adjustment, _Config, _LimitContext) -> - {error, notfound}; -get_body_for_operation(partial, invoice_payment = Operation, Config, LimitContext) -> - ContextType = lim_config_machine:context_type(Config), - lim_context:get_from_context(ContextType, capture_cost, Operation, LimitContext); -get_body_for_operation(partial, invoice_payment_adjustment, _Config, _LimitContext) -> - {error, notfound}; -get_body_for_operation(partial, invoice_payment_refund = Operation, Config, LimitContext) -> - ContextType = lim_config_machine:context_type(Config), - lim_context:get_from_context(ContextType, cost, Operation, LimitContext); -get_body_for_operation(partial, invoice_payment_chargeback, _Config, _LimitContext) -> - {error, notfound}. +get_body_for_operation(full, ContextType, LimitContext) -> + lim_context:get_value(ContextType, cost, LimitContext); +get_body_for_operation(partial, ContextType, LimitContext) -> + lim_context:get_value(ContextType, capture_cost, LimitContext). -apply_op_behaviour(Body, #{op_behaviour := ComputationConfig}, LimitContext) -> - {ok, Operation} = lim_context:get_operation(payment_processing, LimitContext), +apply_op_behaviour(Operation, Body, #{op_behaviour := ComputationConfig}) -> case maps:get(Operation, ComputationConfig, undefined) of addition -> Body; @@ -73,7 +44,7 @@ apply_op_behaviour(Body, #{op_behaviour := ComputationConfig}, LimitContext) -> undefined -> Body end; -apply_op_behaviour(Body, _Config, _LimitContext) -> +apply_op_behaviour(_Operation, Body, _Config) -> Body. invert_body(Cash = #{amount := Amount}) -> diff --git a/apps/limiter/src/lim_config_codec.erl b/apps/limiter/src/lim_config_codec.erl index 13b25fa..52e3452 100644 --- a/apps/limiter/src/lim_config_codec.erl +++ b/apps/limiter/src/lim_config_codec.erl @@ -1,6 +1,7 @@ -module(lim_config_codec). --include_lib("limiter_proto/include/lim_limiter_config_thrift.hrl"). +-include_lib("limiter_proto/include/limproto_config_thrift.hrl"). +-include_lib("limiter_proto/include/limproto_timerange_thrift.hrl"). -export([marshal/2]). -export([unmarshal/2]). @@ -35,7 +36,7 @@ maybe_apply(Value, Fun, _Default) -> -spec marshal(type_name(), decoded_value()) -> encoded_value(). marshal(timestamped_change, {ev, Timestamp, Change}) -> - #limiter_config_TimestampedChange{ + #config_TimestampedChange{ change = marshal_change(Change), occured_at = marshal_timestamp(Timestamp) }. @@ -53,11 +54,11 @@ marshal_timestamp({DateTime, USec}) -> genlib_rfc3339:format_relaxed(TimeinUnit, Unit). marshal_change({created, Config}) -> - {created, #limiter_config_CreatedChange{limit_config = marshal_config(Config)}}. + {created, #config_CreatedChange{limit_config = marshal_config(Config)}}. -spec marshal_config(decoded_value()) -> encoded_value(). marshal_config(Config) -> - #limiter_config_LimitConfig{ + #config_LimitConfig{ id = lim_config_machine:id(Config), processor_type = lim_config_machine:processor_type(Config), description = lim_config_machine:description(Config), @@ -73,62 +74,64 @@ marshal_config(Config) -> marshal_op_behaviour(OpBehaviour) -> PaymentRefund = maps:get(invoice_payment_refund, OpBehaviour, undefined), - #limiter_config_OperationLimitBehaviour{ + #config_OperationLimitBehaviour{ invoice_payment_refund = maybe_apply(PaymentRefund, fun marshal_behaviour/1) }. marshal_behaviour(subtraction) -> - {subtraction, #limiter_config_Subtraction{}}; + {subtraction, #config_Subtraction{}}; marshal_behaviour(addition) -> - {addition, #limiter_config_Addition{}}. + {addition, #config_Addition{}}. marshal_time_range_type({calendar, CalendarType}) -> {calendar, marshal_calendar_time_range_type(CalendarType)}; marshal_time_range_type({interval, Amount}) -> - {interval, #limiter_time_range_TimeRangeTypeInterval{amount = Amount}}. + {interval, #timerange_TimeRangeTypeInterval{amount = Amount}}. marshal_calendar_time_range_type(day) -> - {day, #limiter_time_range_TimeRangeTypeCalendarDay{}}; + {day, #timerange_TimeRangeTypeCalendarDay{}}; marshal_calendar_time_range_type(week) -> - {week, #limiter_time_range_TimeRangeTypeCalendarWeek{}}; + {week, #timerange_TimeRangeTypeCalendarWeek{}}; marshal_calendar_time_range_type(month) -> - {month, #limiter_time_range_TimeRangeTypeCalendarMonth{}}; + {month, #timerange_TimeRangeTypeCalendarMonth{}}; marshal_calendar_time_range_type(year) -> - {year, #limiter_time_range_TimeRangeTypeCalendarYear{}}. + {year, #timerange_TimeRangeTypeCalendarYear{}}. marshal_context_type(payment_processing) -> - {payment_processing, #limiter_config_LimitContextTypePaymentProcessing{}}. + {payment_processing, #config_LimitContextTypePaymentProcessing{}}; +marshal_context_type(withdrawal_processing) -> + {withdrawal_processing, #config_LimitContextTypeWithdrawalProcessing{}}. marshal_type({turnover, Metric}) -> - {turnover, #limiter_config_LimitTypeTurnover{ + {turnover, #config_LimitTypeTurnover{ metric = marshal_turnover_metric(Metric) }}. marshal_turnover_metric(number) -> - {number, #limiter_config_LimitTurnoverNumber{}}; + {number, #config_LimitTurnoverNumber{}}; marshal_turnover_metric({amount, Currency}) -> - {amount, #limiter_config_LimitTurnoverAmount{currency = Currency}}. + {amount, #config_LimitTurnoverAmount{currency = Currency}}. marshal_scope(Types) -> {multi, ordsets:from_list(lists:map(fun marshal_scope_type/1, ordsets:to_list(Types)))}. marshal_scope_type(party) -> - {party, #limiter_config_LimitScopeEmptyDetails{}}; + {party, #config_LimitScopeEmptyDetails{}}; marshal_scope_type(shop) -> - {shop, #limiter_config_LimitScopeEmptyDetails{}}; + {shop, #config_LimitScopeEmptyDetails{}}; marshal_scope_type(wallet) -> - {wallet, #limiter_config_LimitScopeEmptyDetails{}}; + {wallet, #config_LimitScopeEmptyDetails{}}; marshal_scope_type(identity) -> - {identity, #limiter_config_LimitScopeEmptyDetails{}}; + {identity, #config_LimitScopeEmptyDetails{}}; marshal_scope_type(payment_tool) -> - {payment_tool, #limiter_config_LimitScopeEmptyDetails{}}. + {payment_tool, #config_LimitScopeEmptyDetails{}}. %% -spec unmarshal(type_name(), encoded_value()) -> decoded_value(). unmarshal(timestamped_change, TimestampedChange) -> - Timestamp = unmarshal_timestamp(TimestampedChange#limiter_config_TimestampedChange.occured_at), - Change = unmarshal_change(TimestampedChange#limiter_config_TimestampedChange.change), + Timestamp = unmarshal_timestamp(TimestampedChange#config_TimestampedChange.occured_at), + Change = unmarshal_change(TimestampedChange#config_TimestampedChange.change), {ev, Timestamp, Change}. unmarshal_timestamp(Timestamp) when is_binary(Timestamp) -> @@ -148,7 +151,7 @@ unmarshal_timestamp(Timestamp) when is_binary(Timestamp) -> end. -spec unmarshal_params(encoded_value()) -> decoded_value(). -unmarshal_params(#limiter_config_LimitConfigParams{ +unmarshal_params(#config_LimitConfigParams{ id = ID, description = Description, started_at = StartedAt, @@ -171,10 +174,10 @@ unmarshal_params(#limiter_config_LimitConfigParams{ op_behaviour => maybe_apply(OpBehaviour, fun unmarshal_op_behaviour/1) }). -unmarshal_change({created, #limiter_config_CreatedChange{limit_config = Config}}) -> +unmarshal_change({created, #config_CreatedChange{limit_config = Config}}) -> {created, unmarshal_config(Config)}. -unmarshal_config(#limiter_config_LimitConfig{ +unmarshal_config(#config_LimitConfig{ id = ID, processor_type = ProcessorType, description = Description, @@ -217,25 +220,25 @@ derive_type(undefined, {cash, Currency}) -> -spec unmarshal_op_behaviour(encoded_value()) -> decoded_value(). unmarshal_op_behaviour(OpBehaviour) -> - #limiter_config_OperationLimitBehaviour{ + #config_OperationLimitBehaviour{ invoice_payment_refund = Refund } = OpBehaviour, genlib_map:compact(#{ invoice_payment_refund => maybe_apply(Refund, fun unmarshal_behaviour/1) }). -unmarshal_behaviour({subtraction, #limiter_config_Subtraction{}}) -> +unmarshal_behaviour({subtraction, #config_Subtraction{}}) -> subtraction; -unmarshal_behaviour({addition, #limiter_config_Addition{}}) -> +unmarshal_behaviour({addition, #config_Addition{}}) -> addition. -spec unmarshal_body_type_deprecated(encoded_value()) -> decoded_value(). -unmarshal_body_type_deprecated({cash, #limiter_config_LimitBodyTypeCash{currency = Currency}}) -> +unmarshal_body_type_deprecated({cash, #config_LimitBodyTypeCash{currency = Currency}}) -> {cash, Currency}. unmarshal_time_range_type({calendar, CalendarType}) -> {calendar, unmarshal_calendar_time_range_type(CalendarType)}; -unmarshal_time_range_type({interval, #limiter_time_range_TimeRangeTypeInterval{amount = Amount}}) -> +unmarshal_time_range_type({interval, #timerange_TimeRangeTypeInterval{amount = Amount}}) -> {interval, Amount}. unmarshal_calendar_time_range_type({day, _}) -> @@ -247,15 +250,17 @@ unmarshal_calendar_time_range_type({month, _}) -> unmarshal_calendar_time_range_type({year, _}) -> year. -unmarshal_context_type({payment_processing, #limiter_config_LimitContextTypePaymentProcessing{}}) -> - payment_processing. +unmarshal_context_type({payment_processing, #config_LimitContextTypePaymentProcessing{}}) -> + payment_processing; +unmarshal_context_type({withdrawal_processing, #config_LimitContextTypeWithdrawalProcessing{}}) -> + withdrawal_processing. -unmarshal_type({turnover, #limiter_config_LimitTypeTurnover{metric = Metric}}) -> +unmarshal_type({turnover, #config_LimitTypeTurnover{metric = Metric}}) -> {turnover, maybe_apply(Metric, fun unmarshal_turnover_metric/1, number)}. unmarshal_turnover_metric({number, _}) -> number; -unmarshal_turnover_metric({amount, #limiter_config_LimitTurnoverAmount{currency = Currency}}) -> +unmarshal_turnover_metric({amount, #config_LimitTurnoverAmount{currency = Currency}}) -> {amount, Currency}. unmarshal_scope({single, Type}) -> @@ -302,15 +307,15 @@ marshal_unmarshal_created_test() -> -spec unmarshal_created_w_deprecated_body_type_test_() -> [_TestGen]. unmarshal_created_w_deprecated_body_type_test_() -> Now = lim_time:now(), - Config = #limiter_config_LimitConfig{ + Config = #config_LimitConfig{ id = <<"ID">>, processor_type = <<"TurnoverProcessor">>, created_at = lim_time:to_rfc3339(Now), started_at = <<"2000-01-01T00:00:00Z">>, shard_size = 42, - time_range_type = {calendar, {day, #limiter_time_range_TimeRangeTypeCalendarDay{}}}, - context_type = {payment_processing, #limiter_config_LimitContextTypePaymentProcessing{}}, - body_type_deprecated = {cash, #limiter_config_LimitBodyTypeCash{currency = <<"☭☭☭"/utf8>>}} + time_range_type = {calendar, {day, #timerange_TimeRangeTypeCalendarDay{}}}, + context_type = {payment_processing, #config_LimitContextTypePaymentProcessing{}}, + body_type_deprecated = {cash, #config_LimitBodyTypeCash{currency = <<"☭☭☭"/utf8>>}} }, [ ?_assertMatch( @@ -320,8 +325,8 @@ unmarshal_created_w_deprecated_body_type_test_() -> type := {turnover, {amount, <<"☭☭☭"/utf8>>}} }}, unmarshal_change( - {created, #limiter_config_CreatedChange{ - limit_config = Config#limiter_config_LimitConfig{ + {created, #config_CreatedChange{ + limit_config = Config#config_LimitConfig{ type = undefined } }} @@ -334,9 +339,9 @@ unmarshal_created_w_deprecated_body_type_test_() -> type := {turnover, {amount, <<"☭☭☭"/utf8>>}} }}, unmarshal_change( - {created, #limiter_config_CreatedChange{ - limit_config = Config#limiter_config_LimitConfig{ - type = {turnover, #limiter_config_LimitTypeTurnover{}} + {created, #config_CreatedChange{ + limit_config = Config#config_LimitConfig{ + type = {turnover, #config_LimitTypeTurnover{}} } }} ) diff --git a/apps/limiter/src/lim_config_machine.erl b/apps/limiter/src/lim_config_machine.erl index 81b3086..5a56748 100644 --- a/apps/limiter/src/lim_config_machine.erl +++ b/apps/limiter/src/lim_config_machine.erl @@ -1,6 +1,6 @@ -module(lim_config_machine). --include_lib("limiter_proto/include/lim_limiter_thrift.hrl"). +-include_lib("limiter_proto/include/limproto_limiter_thrift.hrl"). %% Accessors @@ -79,10 +79,10 @@ -type op_behaviour() :: #{operation_type() := addition | subtraction}. -type operation_type() :: invoice_payment_refund. --type lim_id() :: lim_limiter_thrift:'LimitID'(). --type lim_change() :: lim_limiter_thrift:'LimitChange'(). --type limit() :: lim_limiter_thrift:'Limit'(). --type timestamp() :: lim_base_thrift:'Timestamp'(). +-type lim_id() :: limproto_limiter_thrift:'LimitID'(). +-type lim_change() :: limproto_limiter_thrift:'LimitChange'(). +-type limit() :: limproto_limiter_thrift:'Limit'(). +-type timestamp() :: dmsl_base_thrift:'Timestamp'(). -export_type([config/0]). -export_type([limit_type/0]). @@ -522,14 +522,14 @@ mk_shard_id(Prefix, Units, ShardSize) -> -spec mk_scope_prefix(config(), lim_context()) -> prefix(). mk_scope_prefix(Config, LimitContext) -> - mk_scope_prefix_impl(scope(Config), LimitContext). + mk_scope_prefix_impl(scope(Config), context_type(Config), LimitContext). --spec mk_scope_prefix_impl(limit_scope(), lim_context()) -> prefix(). -mk_scope_prefix_impl(Scope, LimitContext) -> +-spec mk_scope_prefix_impl(limit_scope(), context_type(), lim_context()) -> prefix(). +mk_scope_prefix_impl(Scope, ContextType, LimitContext) -> Bits = enumerate_context_bits(Scope), ordsets:fold( fun(Bit, Acc) -> - {ok, Value} = extract_context_bit(Bit, LimitContext), + {ok, Value} = extract_context_bit(Bit, ContextType, LimitContext), append_prefix(Value, Acc) end, <<>>, @@ -541,7 +541,7 @@ append_prefix(Fragment, Acc) -> <>. -type context_bit() :: - {from, lim_context:context_type(), _Name :: atom(), lim_context:context_operation()} + {from, _ValueName :: atom()} | {order, integer(), context_bit()}. -spec enumerate_context_bits(limit_scope()) -> ordsets:ordset(context_bit()). @@ -550,7 +550,7 @@ enumerate_context_bits(Types) -> append_context_bits(party, Bits) -> ordsets:add_element( - {order, 1, {from, payment_processing, owner_id, invoice}}, + {order, 1, {from, owner_id}}, Bits ); append_context_bits(shop, Bits) -> @@ -558,31 +558,33 @@ append_context_bits(shop, Bits) -> % NOTE % Shop scope implies party scope. % Also we need to preserve order between party / shop to ensure backwards compatibility. - {order, 1, {from, payment_processing, owner_id, invoice}}, - {order, 2, {from, payment_processing, shop_id, invoice}} + {order, 1, {from, owner_id}}, + {order, 2, {from, shop_id}} ]); append_context_bits(payment_tool, Bits) -> ordsets:add_element( - {from, payment_processing, payer, invoice_payment}, + {from, payment_tool}, Bits ). --spec extract_context_bit(context_bit(), lim_context()) -> {ok, binary()}. -extract_context_bit({order, _, Bit}, LimitContext) -> - extract_context_bit(Bit, LimitContext); -extract_context_bit({from, payment_processing, payer, Op}, LimitContext) -> - {ok, {_, PayerData}} = lim_context:get_from_context(payment_processing, payer, Op, LimitContext), - #{payment_tool := {PaymentToolType, PaymentToolData}} = PayerData, - case PaymentToolType of - bank_card -> - Token = maps:get(token, PaymentToolData), - ExpData = maps:get(exp_date, PaymentToolData, <<>>), - {ok, <>}; - _ -> - {error, {unsupported_payment_tool_type, PaymentToolType}} +-spec extract_context_bit(context_bit(), context_type(), lim_context()) -> {ok, binary()}. +extract_context_bit({order, _, Bit}, ContextType, LimitContext) -> + extract_context_bit(Bit, ContextType, LimitContext); +extract_context_bit({from, payment_tool}, ContextType, LimitContext) -> + {ok, PaymentTool} = lim_context:get_value(ContextType, payment_tool, LimitContext), + case PaymentTool of + {bank_card, #{token := Token, exp_date := {Month, Year}}} -> + {ok, mk_scope_component([Token, Month, Year])}; + {bank_card, #{token := Token, exp_date := undefined}} -> + {ok, mk_scope_component([Token, <<"undefined">>])}; + {digital_wallet, #{id := ID, service := Service}} -> + {ok, mk_scope_component([<<"DW">>, Service, ID])} end; -extract_context_bit({from, ContextType, ValueName, Op}, LimitContext) -> - lim_context:get_from_context(ContextType, ValueName, Op, LimitContext). +extract_context_bit({from, ValueName}, ContextType, LimitContext) -> + lim_context:get_value(ContextType, ValueName, LimitContext). + +mk_scope_component(Fragments) -> + lim_string:join($/, Fragments). %%% Machinery callbacks @@ -640,6 +642,9 @@ apply_event_({created, Config}, undefined) -> -ifdef(TEST). -include_lib("eunit/include/eunit.hrl"). +-include_lib("limiter_proto/include/limproto_context_payproc_thrift.hrl"). +-include_lib("damsel/include/dmsl_domain_thrift.hrl"). + -spec test() -> _. -spec check_sign_prefix_test() -> _. @@ -782,32 +787,42 @@ check_calculate_year_shard_id_test() -> ?assertEqual(<<"past/year/1">>, calculate_calendar_shard_id(year, <<"2000-01-01T00:00:00Z">>, StartedAt2, 1)), ?assertEqual(<<"future/year/0">>, calculate_calendar_shard_id(year, <<"2001-01-01T00:00:00Z">>, StartedAt2, 1)). --define(LIMIT_CONTEXT, #{ - context => #{ - payment_processing => #{ - op => invoice, - invoice => #{ - owner_id => <<"OWNER">>, - shop_id => <<"SHLOP">> - } +-define(PAYPROC_CTX_INVOICE(Invoice), #limiter_LimitContext{ + payment_processing = #context_payproc_Context{ + op = {invoice, #context_payproc_OperationInvoice{}}, + invoice = #context_payproc_Invoice{ + invoice = Invoice } } }). +-define(INVOICE(OwnerID, ShopID), #domain_Invoice{ + id = <<"ID">>, + owner_id = OwnerID, + shop_id = ShopID, + created_at = <<"2000-02-02T12:12:12Z">>, + status = {unpaid, #domain_InvoiceUnpaid{}}, + details = #domain_InvoiceDetails{product = <<>>}, + due = <<"2222-02-02T12:12:12Z">>, + cost = #domain_Cash{amount = 42, currency = #domain_CurrencyRef{symbolic_code = <<"CNY">>}} +}). + -spec global_scope_empty_prefix_test() -> _. global_scope_empty_prefix_test() -> - ?assertEqual(<<>>, mk_scope_prefix_impl(ordsets:new(), ?LIMIT_CONTEXT)). + Context = #{context => ?PAYPROC_CTX_INVOICE(?INVOICE(<<"OWNER">>, <<"SHOP">>))}, + ?assertEqual(<<>>, mk_scope_prefix_impl(ordsets:new(), payment_processing, Context)). -spec preserve_scope_prefix_order_test_() -> [_TestGen]. preserve_scope_prefix_order_test_() -> + Context = #{context => ?PAYPROC_CTX_INVOICE(?INVOICE(<<"OWNER">>, <<"SHLOP">>))}, [ ?_assertEqual( <<"/OWNER/SHLOP">>, - mk_scope_prefix_impl(ordsets:from_list([shop, party]), ?LIMIT_CONTEXT) + mk_scope_prefix_impl(ordsets:from_list([shop, party]), payment_processing, Context) ), ?_assertEqual( <<"/OWNER/SHLOP">>, - mk_scope_prefix_impl(ordsets:from_list([shop]), ?LIMIT_CONTEXT) + mk_scope_prefix_impl(ordsets:from_list([shop]), payment_processing, Context) ) ]. diff --git a/apps/limiter/src/lim_config_machinery_schema.erl b/apps/limiter/src/lim_config_machinery_schema.erl index b18ec3a..0ef3c9f 100644 --- a/apps/limiter/src/lim_config_machinery_schema.erl +++ b/apps/limiter/src/lim_config_machinery_schema.erl @@ -70,13 +70,13 @@ unmarshal(T, V, C) when -spec marshal_event(machinery_mg_schema:version(), event(), context()) -> {machinery_msgpack:t(), context()}. marshal_event(1, TimestampedChange, Context) -> ThriftChange = lim_config_codec:marshal(timestamped_change, TimestampedChange), - Type = {struct, struct, {lim_limiter_config_thrift, 'TimestampedChange'}}, + Type = {struct, struct, {limproto_config_thrift, 'TimestampedChange'}}, {{bin, lim_proto_utils:serialize(Type, ThriftChange)}, Context}. -spec unmarshal_event(machinery_mg_schema:version(), machinery_msgpack:t(), context()) -> {event(), context()}. unmarshal_event(1, EncodedChange, Context) -> {bin, EncodedThriftChange} = EncodedChange, - Type = {struct, struct, {lim_limiter_config_thrift, 'TimestampedChange'}}, + Type = {struct, struct, {limproto_config_thrift, 'TimestampedChange'}}, ThriftChange = lim_proto_utils:deserialize(Type, EncodedThriftChange), {lim_config_codec:unmarshal(timestamped_change, ThriftChange), Context}. @@ -104,7 +104,7 @@ marshal_unmarshal_created_test() -> scope => ordsets:from_list([party]), description => <<"description">> }}, - Context = #{machine_ref => ID, machine_ns => config}, + Context = #{machine_id => ID, machine_ns => config}, Event = {ev, lim_time:machinery_now(), Created}, {Marshaled, _} = marshal_event(1, Event, Context), {Unmarshaled, _} = unmarshal_event(1, Marshaled, Context), diff --git a/apps/limiter/src/lim_configurator.erl b/apps/limiter/src/lim_configurator.erl index b5b09cd..f23c862 100644 --- a/apps/limiter/src/lim_configurator.erl +++ b/apps/limiter/src/lim_configurator.erl @@ -1,6 +1,7 @@ -module(lim_configurator). --include_lib("limiter_proto/include/lim_configurator_thrift.hrl"). +-include_lib("limiter_proto/include/limproto_configurator_thrift.hrl"). +-include_lib("damsel/include/dmsl_base_thrift.hrl"). %% Woody handler @@ -23,7 +24,7 @@ handle_function(Fn, Args, WoodyCtx, Opts) -> -spec handle_function_(woody:func(), woody:args(), lim_context:t(), woody:options()) -> {ok, woody:result()}. handle_function_( 'CreateLegacy', - {#limiter_configurator_LimitCreateParams{ + {#configurator_LimitCreateParams{ id = ID, name = Name, description = Description, @@ -51,7 +52,7 @@ handle_function_( {error, {name, notfound}} -> woody_error:raise( business, - #limiter_configurator_LimitConfigNameNotFound{} + #configurator_LimitConfigNameNotFound{} ) end; handle_function_('Create', {Params}, LimitContext, _Opts) -> @@ -70,7 +71,7 @@ handle_function_('Get', {LimitID}, LimitContext, _Opts) -> {ok, LimitConfig} -> {ok, lim_config_codec:marshal_config(LimitConfig)}; {error, notfound} -> - woody_error:raise(business, #limiter_configurator_LimitConfigNotFound{}) + woody_error:raise(business, #configurator_LimitConfigNotFound{}) end. map_type({turnover, _}) -> @@ -78,7 +79,7 @@ map_type({turnover, _}) -> map_type(_) -> woody_error:raise( business, - #'InvalidRequest'{errors = [<<"Config type not found.">>]} + #base_InvalidRequest{errors = [<<"Config type not found.">>]} ). mk_limit_config(<<"ShopDayTurnover">>) -> diff --git a/apps/limiter/src/lim_context.erl b/apps/limiter/src/lim_context.erl index f2bca88..de267af 100644 --- a/apps/limiter/src/lim_context.erl +++ b/apps/limiter/src/lim_context.erl @@ -1,12 +1,11 @@ -module(lim_context). --include_lib("limiter_proto/include/lim_limiter_context_thrift.hrl"). +-include_lib("limiter_proto/include/limproto_limiter_thrift.hrl"). -export([create/1]). -export([woody_context/1]). -export([get_operation/2]). --export([get_from_context/3]). --export([get_from_context/4]). +-export([get_value/3]). -export([set_context/2]). -export([set_clock/2]). @@ -14,107 +13,26 @@ -export([clock/1]). -type woody_context() :: woody_context:ctx(). --type timestamp() :: binary(). --type thrift_context() :: lim_limiter_thrift:'LimitContext'(). --type clock() :: lim_limiter_thrift:'Clock'(). --type id() :: binary(). --type token() :: binary(). --type exp_date() :: binary(). --type cash() :: lim_body:cash(). +-type limit_context() :: limproto_limiter_thrift:'LimitContext'(). +-type clock() :: limproto_limiter_thrift:'Clock'(). -type t() :: #{ woody_context => woody_context(), - context => context(), + context => limit_context(), clock => clock() }. --type context_type() :: payment_processing. --type context_operation() :: payment_processing_operation(). - --type context() :: #{ - payment_processing => payment_processing_context() -}. - --type payment_processing_context() :: #{ - op := payment_processing_operation(), - invoice => payment_processing_invoice() -}. - --type payment_processing_operation() :: - invoice - | invoice_adjustment - | invoice_payment - | invoice_payment_adjustment - | invoice_payment_refund - | invoice_payment_chargeback. - --type payment_processing_invoice() :: #{ - id => id(), - owner_id => id(), - shop_id => id(), - cost => cash(), - created_at => timestamp(), - adjustment => payment_processing_adjustment(), - payment => payment_processing_payment() -}. - --type payment_processing_adjustment() :: #{ - id => id() -}. - --type payment_processing_payment() :: #{ - id => id(), - owner_id => id(), - shop_id => id(), - cost => cash(), - capture_cost => cash(), - created_at => timestamp(), - flow => instant | hold, - payer => payment_processing_payer(), - adjustment => payment_processing_payment_adjustment(), - refund => payment_processing_payment_refund(), - chargeback => payment_processing_payment_chargeback() -}. - --type payment_processing_payer() :: - {payment_resource, payment_processing_payer_data()} - | {customer, payment_processing_payer_data()} - | {recurrent, payment_processing_payer_data()}. - --type payment_processing_payer_data() :: #{ - payment_tool => payment_processing_payment_tool() -}. - --type payment_processing_payment_tool() :: {bank_card, payment_processing_bank_card()}. - --type payment_processing_bank_card() :: #{ - token => token(), - exp_date => exp_date() -}. - --type payment_processing_payment_adjustment() :: #{ - id => id(), - created_at => timestamp() -}. - --type payment_processing_payment_refund() :: #{ - id => id(), - cost => cash(), - created_at => timestamp() -}. - --type payment_processing_payment_chargeback() :: #{ - id => id(), - levy => cash(), - body => cash(), - created_at => timestamp() -}. +-type context_type() :: payment_processing | withdrawal_processing. +-type context_inner() :: lim_payproc_context:context() | lim_wthdproc_context:context(). +-type context_operation() :: lim_payproc_context:operation() | lim_wthdproc_context:operation(). -export_type([t/0]). --export_type([context/0]). -export_type([context_type/0]). -export_type([context_operation/0]). +-callback get_operation(context_inner()) -> {ok, context_operation()} | {error, notfound}. +-callback get_value(_Name :: atom(), context_inner()) -> {ok, term()} | {error, notfound | {unsupported, _}}. + -spec create(woody_context()) -> t(). create(WoodyContext) -> #{woody_context => WoodyContext}. @@ -129,83 +47,33 @@ clock(#{clock := Clock}) -> clock(_) -> {error, notfound}. --spec set_context(thrift_context(), t()) -> t(). +-spec set_context(limit_context(), t()) -> t(). set_context(Context, LimContext) -> - LimContext#{context => unmarshal_context(Context)}. + LimContext#{context => Context}. -spec set_clock(clock(), t()) -> t(). set_clock(Clock, LimContext) -> LimContext#{clock => Clock}. --spec get_operation(context_type(), t()) -> {ok, atom()} | {error, notfound}. -get_operation(Type, #{context := Context}) -> - case maps:get(Type, Context, undefined) of - undefined -> - {error, notfound}; - #{op := Operation} -> - {ok, Operation} - end. +-spec get_operation(context_type(), t()) -> + {ok, context_operation()} | {error, notfound}. +get_operation(Type, Context) -> + {Mod, OperationContext} = get_operation_context(Type, Context), + Mod:get_operation(OperationContext). --spec get_from_context(context_type(), atom(), t()) -> {ok, term()} | {error, notfound}. -get_from_context(payment_processing, ValueName, LimContext = #{context := Context}) -> - case maps:get(payment_processing, Context, undefined) of - undefined -> - {error, notfound}; - #{op := Operation} -> - get_from_context(payment_processing, ValueName, Operation, LimContext) - end; -get_from_context(_, _ValueName, _LimContext) -> - {error, notfound}. +-spec get_value(context_type(), atom(), t()) -> + {ok, term()} | {error, notfound | {unsupported, _}}. +get_value(Type, ValueName, Context) -> + {Mod, OperationContext} = get_operation_context(Type, Context), + Mod:get_value(ValueName, OperationContext). --spec get_from_context(context_type(), atom(), context_operation(), t()) -> {ok, term()} | {error, notfound}. -get_from_context(payment_processing, ValueName, Op, #{context := #{payment_processing := Context}}) -> - case get_payment_processing_operation_context(Op, Context) of - {ok, OperationContext} -> - case maps:get(ValueName, OperationContext, undefined) of - undefined -> - {error, notfound}; - Value -> - {ok, Value} - end; - Error -> - Error - end; -get_from_context(_, _ValueName, _Op, _LimContext) -> - {error, notfound}. - -get_payment_processing_operation_context(invoice, #{invoice := Invoice}) -> - {ok, Invoice}; -get_payment_processing_operation_context(invoice_adjustment, #{invoice := #{adjustment := Adjustment}}) -> - {ok, Adjustment}; -get_payment_processing_operation_context(invoice_payment, #{invoice := #{payment := Payment}}) -> - {ok, Payment}; -get_payment_processing_operation_context( - invoice_payment_adjustment, - #{invoice := #{payment := #{adjustment := Adjustment}}} +get_operation_context( + payment_processing, + #{context := #limiter_LimitContext{payment_processing = PayprocContext}} ) -> - {ok, Adjustment}; -get_payment_processing_operation_context( - invoice_payment_refund, - #{invoice := #{payment := #{refund := Refund}}} + {lim_payproc_context, PayprocContext}; +get_operation_context( + withdrawal_processing, + #{context := #limiter_LimitContext{withdrawal_processing = WithdrawalContext}} ) -> - {ok, Refund}; -get_payment_processing_operation_context( - invoice_payment_chargeback, - #{invoice := #{payment := #{chargeback := Chargeback}}} -) -> - {ok, Chargeback}; -get_payment_processing_operation_context(_, _) -> - {error, notfound}. - -%% - -unmarshal_context(#limiter_context_LimitContext{limiter_payment_processing = PaymentProcessing}) when - PaymentProcessing =/= undefined --> - #{payment_processing => lim_limiter_context:unmarshal(PaymentProcessing)}; -unmarshal_context(#limiter_context_LimitContext{payment_processing = PaymentProcessing}) when - PaymentProcessing =/= undefined --> - #{payment_processing => lim_payproc_context:unmarshal(PaymentProcessing)}; -unmarshal_context(_) -> - #{}. + {lim_wthdproc_context, WithdrawalContext}. diff --git a/apps/limiter/src/lim_handler.erl b/apps/limiter/src/lim_handler.erl index 6e0d7b9..11e26d3 100644 --- a/apps/limiter/src/lim_handler.erl +++ b/apps/limiter/src/lim_handler.erl @@ -1,6 +1,8 @@ -module(lim_handler). --include_lib("limiter_proto/include/lim_limiter_thrift.hrl"). +-include_lib("limiter_proto/include/limproto_limiter_thrift.hrl"). +-include_lib("limiter_proto/include/limproto_base_thrift.hrl"). +-include_lib("damsel/include/dmsl_base_thrift.hrl"). %% Woody handler @@ -84,7 +86,7 @@ handle_get_error(Error) -> -spec handle_hold_error(_) -> no_return(). handle_hold_error({_, {invalid_request, Errors}}) -> - woody_error:raise(business, #'InvalidRequest'{errors = Errors}); + woody_error:raise(business, #base_InvalidRequest{errors = Errors}); handle_hold_error(Error) -> handle_default_error(Error). @@ -92,13 +94,13 @@ handle_hold_error(Error) -> handle_commit_error({_, {forbidden_operation_amount, Error}}) -> handle_forbidden_operation_amount_error(Error); handle_commit_error({_, {invalid_request, Errors}}) -> - woody_error:raise(business, #'InvalidRequest'{errors = Errors}); + woody_error:raise(business, #base_InvalidRequest{errors = Errors}); handle_commit_error(Error) -> handle_default_error(Error). -spec handle_rollback_error(_) -> no_return(). handle_rollback_error({_, {invalid_request, Errors}}) -> - woody_error:raise(business, #'InvalidRequest'{errors = Errors}); + woody_error:raise(business, #base_InvalidRequest{errors = Errors}); handle_rollback_error(Error) -> handle_default_error(Error). @@ -122,7 +124,7 @@ handle_forbidden_operation_amount_error(#{ positive -> woody_error:raise(business, #limiter_ForbiddenOperationAmount{ amount = Partial, - allowed_range = #limiter_base_AmountRange{ + allowed_range = #base_AmountRange{ upper = {inclusive, Full}, lower = {inclusive, 0} } @@ -130,7 +132,7 @@ handle_forbidden_operation_amount_error(#{ negative -> woody_error:raise(business, #limiter_ForbiddenOperationAmount{ amount = Partial, - allowed_range = #limiter_base_AmountRange{ + allowed_range = #base_AmountRange{ upper = {inclusive, 0}, lower = {inclusive, Full} } diff --git a/apps/limiter/src/lim_limiter_context.erl b/apps/limiter/src/lim_limiter_context.erl deleted file mode 100644 index 9ffbcb8..0000000 --- a/apps/limiter/src/lim_limiter_context.erl +++ /dev/null @@ -1,129 +0,0 @@ --module(lim_limiter_context). - --include_lib("limiter_proto/include/lim_limiter_context_thrift.hrl"). - --export([unmarshal/1]). - --type thrift_context() :: lim_limiter_context_thrift:'ContextPaymentProcessing'(). - -%% - --spec unmarshal(thrift_context()) -> lim_context:context(). -unmarshal(#limiter_context_ContextPaymentProcessing{ - op = {Operation, _}, - invoice = Invoice -}) -> - genlib_map:compact(#{ - op => Operation, - invoice => maybe_unmarshal(Invoice, fun unmarshal_payment_processing_invoice/1) - }). - -unmarshal_payment_processing_invoice(#limiter_context_Invoice{ - id = ID, - owner_id = OwnerID, - shop_id = ShopID, - cost = Cost, - created_at = CreatedAt, - effective_payment = Payment, - effective_adjustment = Adjustment -}) -> - genlib_map:compact(#{ - id => maybe_unmarshal(ID, fun unmarshal_string/1), - owner_id => maybe_unmarshal(OwnerID, fun unmarshal_string/1), - shop_id => maybe_unmarshal(ShopID, fun unmarshal_string/1), - cost => maybe_unmarshal(Cost, fun unmarshal_cash/1), - created_at => maybe_unmarshal(CreatedAt, fun unmarshal_string/1), - adjustment => maybe_unmarshal( - Adjustment, - fun unmarshal_payment_processing_invoice_adjustment/1 - ), - payment => maybe_unmarshal(Payment, fun unmarshal_payment_processing_invoice_payment/1) - }). - -unmarshal_payment_processing_invoice_adjustment(#limiter_context_InvoiceAdjustment{id = ID}) -> - genlib_map:compact(#{ - id => maybe_unmarshal(ID, fun unmarshal_string/1) - }). - -unmarshal_payment_processing_invoice_payment(#limiter_context_InvoicePayment{ - id = ID, - owner_id = OwnerID, - shop_id = ShopID, - cost = Cost, - capture_cost = CaptureCost, - created_at = CreatedAt, - flow = Flow, - payer = Payer, - effective_adjustment = Adjustment, - effective_refund = EffectiveRefund, - effective_chargeback = EffectiveChargeback -}) -> - genlib_map:compact(#{ - id => maybe_unmarshal(ID, fun unmarshal_string/1), - owner_id => maybe_unmarshal(OwnerID, fun unmarshal_string/1), - shop_id => maybe_unmarshal(ShopID, fun unmarshal_string/1), - cost => maybe_unmarshal(Cost, fun unmarshal_cash/1), - capture_cost => maybe_unmarshal(CaptureCost, fun unmarshal_cash/1), - created_at => maybe_unmarshal(CreatedAt, fun unmarshal_string/1), - flow => maybe_unmarshal(Flow, fun unmarshal_payment_processing_invoice_payment_flow/1), - payer => maybe_unmarshal(Payer, fun unmarshal_payment_processing_invoice_payment_payer/1), - adjustment => maybe_unmarshal( - Adjustment, - fun unmarshal_payment_processing_invoice_payment_adjustment/1 - ), - refund => maybe_unmarshal(EffectiveRefund, fun unmarshal_payment_processing_invoice_payment_refund/1), - chargeback => maybe_unmarshal( - EffectiveChargeback, - fun unmarshal_payment_processing_invoice_payment_chargeback/1 - ) - }). - -unmarshal_payment_processing_invoice_payment_flow({Flow, _}) -> - Flow. - -unmarshal_payment_processing_invoice_payment_payer({Payer, _}) -> - {Payer, #{}}. - -unmarshal_payment_processing_invoice_payment_adjustment(#limiter_context_InvoicePaymentAdjustment{ - id = ID, - created_at = CreatedAt -}) -> - genlib_map:compact(#{ - id => maybe_unmarshal(ID, fun unmarshal_string/1), - created_at => maybe_unmarshal(CreatedAt, fun unmarshal_string/1) - }). - -unmarshal_payment_processing_invoice_payment_refund(#limiter_context_InvoicePaymentRefund{ - id = ID, - cost = Cost, - created_at = CreatedAt -}) -> - genlib_map:compact(#{ - id => maybe_unmarshal(ID, fun unmarshal_string/1), - cost => maybe_unmarshal(Cost, fun unmarshal_cash/1), - created_at => maybe_unmarshal(CreatedAt, fun unmarshal_string/1) - }). - -unmarshal_payment_processing_invoice_payment_chargeback(#limiter_context_InvoicePaymentChargeback{ - id = ID, - levy = Levy, - body = Body, - created_at = CreatedAt -}) -> - genlib_map:compact(#{ - id => maybe_unmarshal(ID, fun unmarshal_string/1), - levy => maybe_unmarshal(Levy, fun unmarshal_cash/1), - body => maybe_unmarshal(Body, fun unmarshal_cash/1), - created_at => maybe_unmarshal(CreatedAt, fun unmarshal_string/1) - }). - -unmarshal_cash(#domain_Cash{amount = Amount, currency = #domain_CurrencyRef{symbolic_code = Currency}}) -> - #{amount => Amount, currency => Currency}. - -unmarshal_string(Value) -> - Value. - -maybe_unmarshal(undefined, _) -> - undefined; -maybe_unmarshal(Value, UnmarshalFun) -> - UnmarshalFun(Value). diff --git a/apps/limiter/src/lim_payproc_context.erl b/apps/limiter/src/lim_payproc_context.erl index 18cb257..0766465 100644 --- a/apps/limiter/src/lim_payproc_context.erl +++ b/apps/limiter/src/lim_payproc_context.erl @@ -1,213 +1,247 @@ -module(lim_payproc_context). --include_lib("limiter_proto/include/lim_limiter_payproc_context_thrift.hrl"). +-include_lib("limiter_proto/include/limproto_context_payproc_thrift.hrl"). +-include_lib("damsel/include/dmsl_domain_thrift.hrl"). --export([unmarshal/1]). +-behaviour(lim_context). +-export([get_operation/1]). +-export([get_value/2]). --type thrift_context() :: lim_limiter_payproc_context_thrift:'Context'(). +-type context() :: limproto_context_payproc_thrift:'Context'(). + +-type operation() :: + invoice + | invoice_adjustment + | invoice_payment + | invoice_payment_adjustment + | invoice_payment_refund + | invoice_payment_chargeback. + +-export_type([operation/0]). +-export_type([context/0]). %% --spec unmarshal(thrift_context()) -> lim_context:context(). -unmarshal(#limiter_context_payproc_Context{ - op = {Operation, _}, - invoice = Invoice -}) -> - genlib_map:compact(#{ - op => Operation, - invoice => maybe_unmarshal(Invoice, fun unmarshal_payment_processing_invoice/1) - }). +-spec get_operation(context()) -> {ok, operation()} | {error, notfound}. +get_operation(#context_payproc_Context{op = {Operation, _}}) -> + {ok, Operation}; +get_operation(#context_payproc_Context{op = undefined}) -> + {error, notfound}. -unmarshal_payment_processing_invoice(#limiter_context_payproc_Invoice{ - invoice = #domain_Invoice{ - id = ID, - owner_id = OwnerID, - shop_id = ShopID, - cost = Cost, - created_at = CreatedAt - }, - payment = Payment, - adjustment = Adjustment -}) -> - genlib_map:compact(#{ - id => maybe_unmarshal(ID, fun unmarshal_string/1), - owner_id => maybe_unmarshal(OwnerID, fun unmarshal_string/1), - shop_id => maybe_unmarshal(ShopID, fun unmarshal_string/1), - cost => maybe_unmarshal(Cost, fun unmarshal_cash/1), - created_at => maybe_unmarshal(CreatedAt, fun unmarshal_string/1), - adjustment => maybe_unmarshal( - Adjustment, - fun unmarshal_payment_processing_invoice_adjustment/1 - ), - payment => maybe_unmarshal(Payment, fun unmarshal_payment_processing_invoice_payment/1) - }). +-spec get_value(atom(), context()) -> {ok, term()} | {error, notfound | {unsupported, _}}. +get_value(ValueName, Context) -> + case get_operation(Context) of + {ok, Operation} -> + get_value(ValueName, Operation, Context); + {error, _} = Error -> + Error + end. -unmarshal_payment_processing_invoice_adjustment(#domain_InvoiceAdjustment{id = ID}) -> - #{id => unmarshal_string(ID)}. +get_value(owner_id, _Operation, Context) -> + get_owner_id(Context); +get_value(shop_id, _Operation, Context) -> + get_shop_id(Context); +get_value(created_at, Operation, Context) -> + get_created_at(Operation, Context); +get_value(cost, Operation, Context) -> + get_cost(Operation, Context); +get_value(capture_cost, Operation, Context) -> + get_capture_cost(Operation, Context); +get_value(payment_tool, Operation, Context) -> + get_payment_tool(Operation, Context); +get_value(ValueName, _Operation, _Context) -> + {error, {unsupported, ValueName}}. -unmarshal_payment_processing_invoice_payment(#limiter_context_payproc_InvoicePayment{ - payment = #domain_InvoicePayment{ - id = ID, - owner_id = OwnerID, - shop_id = ShopID, - cost = Cost, - created_at = CreatedAt, - flow = Flow, - status = Status, - payer = Payer - }, - adjustment = Adjustment, - refund = EffectiveRefund, - chargeback = EffectiveChargeback -}) -> - genlib_map:compact(#{ - id => maybe_unmarshal(ID, fun unmarshal_string/1), - owner_id => maybe_unmarshal(OwnerID, fun unmarshal_string/1), - shop_id => maybe_unmarshal(ShopID, fun unmarshal_string/1), - cost => maybe_unmarshal(Cost, fun unmarshal_cash/1), - capture_cost => get_capture_cost_from_status(Status), - created_at => maybe_unmarshal(CreatedAt, fun unmarshal_string/1), - flow => maybe_unmarshal(Flow, fun unmarshal_payment_processing_invoice_payment_flow/1), - payer => maybe_unmarshal(Payer, fun unmarshal_payment_processing_invoice_payment_payer/1), - adjustment => maybe_unmarshal( - Adjustment, - fun unmarshal_payment_processing_invoice_payment_adjustment/1 - ), - refund => maybe_unmarshal(EffectiveRefund, fun unmarshal_payment_processing_invoice_payment_refund/1), - chargeback => maybe_unmarshal( - EffectiveChargeback, - fun unmarshal_payment_processing_invoice_payment_chargeback/1 - ) - }). +%% -get_capture_cost_from_status({captured, #domain_InvoicePaymentCaptured{cost = Cost}}) -> - maybe_unmarshal(Cost, fun unmarshal_cash/1); -get_capture_cost_from_status(_) -> - undefined. +-define(INVOICE(V), #context_payproc_Context{ + invoice = #context_payproc_Invoice{ + invoice = V = #domain_Invoice{} + } +}). -unmarshal_payment_processing_invoice_payment_flow({Flow, _}) -> - Flow. +-define(INVOICE_ADJUSTMENT(V), #context_payproc_Context{ + invoice = #context_payproc_Invoice{ + adjustment = V = #domain_InvoiceAdjustment{} + } +}). -unmarshal_payment_processing_invoice_payment_payer({Payer, Data}) -> - {Payer, unmarshal_payment_processing_invoice_payment_payer_data(Data)}. +-define(INVOICE_PAYMENT(V), #context_payproc_Context{ + invoice = #context_payproc_Invoice{ + payment = #context_payproc_InvoicePayment{payment = V = #domain_InvoicePayment{}} + } +}). -unmarshal_payment_processing_invoice_payment_payer_data(#domain_PaymentResourcePayer{ - resource = #domain_DisposablePaymentResource{payment_tool = PaymentTool} -}) -> - genlib_map:compact(#{ - payment_tool => maybe_unmarshal(PaymentTool, fun unmarshal_payment_processing_payment_tool/1) - }); -unmarshal_payment_processing_invoice_payment_payer_data(#domain_CustomerPayer{payment_tool = PaymentTool}) -> - genlib_map:compact(#{ - payment_tool => maybe_unmarshal(PaymentTool, fun unmarshal_payment_processing_payment_tool/1) - }); -unmarshal_payment_processing_invoice_payment_payer_data(#domain_RecurrentPayer{payment_tool = PaymentTool}) -> - genlib_map:compact(#{ - payment_tool => maybe_unmarshal(PaymentTool, fun unmarshal_payment_processing_payment_tool/1) - }). +-define(INVOICE_PAYMENT_ADJUSTMENT(V), #context_payproc_Context{ + invoice = #context_payproc_Invoice{ + payment = #context_payproc_InvoicePayment{adjustment = V = #domain_InvoicePaymentAdjustment{}} + } +}). -unmarshal_payment_processing_payment_tool({bank_card, #domain_BankCard{token = Token, exp_date = ExpDate}}) -> - {bank_card, #{ - token => Token, - exp_date => maybe_unmarshal(ExpDate, fun unmarshal_payment_processing_bank_card_exp_data/1) - }}; -unmarshal_payment_processing_payment_tool(_) -> - undefined. +-define(INVOICE_PAYMENT_REFUND(V), #context_payproc_Context{ + invoice = #context_payproc_Invoice{ + payment = #context_payproc_InvoicePayment{refund = V = #domain_InvoicePaymentRefund{}} + } +}). -unmarshal_payment_processing_bank_card_exp_data(#domain_BankCardExpDate{month = Month, year = Year}) -> - BinaryMonth = integer_to_binary(Month), - BinaryYear = integer_to_binary(Year), - <>. +-define(INVOICE_PAYMENT_CHARGEBACK(V), #context_payproc_Context{ + invoice = #context_payproc_Invoice{ + payment = #context_payproc_InvoicePayment{chargeback = V = #domain_InvoicePaymentChargeback{}} + } +}). -unmarshal_payment_processing_invoice_payment_adjustment(#domain_InvoicePaymentAdjustment{ - id = ID, - created_at = CreatedAt -}) -> - genlib_map:compact(#{ - id => maybe_unmarshal(ID, fun unmarshal_string/1), - created_at => maybe_unmarshal(CreatedAt, fun unmarshal_string/1) - }). +get_owner_id(?INVOICE(Invoice)) -> + {ok, Invoice#domain_Invoice.owner_id}; +get_owner_id(_) -> + {error, notfound}. -unmarshal_payment_processing_invoice_payment_refund(#domain_InvoicePaymentRefund{ - id = ID, - cash = Cost, - created_at = CreatedAt -}) -> - genlib_map:compact(#{ - id => maybe_unmarshal(ID, fun unmarshal_string/1), - cost => maybe_unmarshal(Cost, fun unmarshal_cash/1), - created_at => maybe_unmarshal(CreatedAt, fun unmarshal_string/1) - }). +get_shop_id(?INVOICE(Invoice)) -> + {ok, Invoice#domain_Invoice.shop_id}; +get_shop_id(_) -> + {error, notfound}. -unmarshal_payment_processing_invoice_payment_chargeback(#domain_InvoicePaymentChargeback{ - id = ID, - levy = Levy, - body = Body, - created_at = CreatedAt -}) -> - genlib_map:compact(#{ - id => maybe_unmarshal(ID, fun unmarshal_string/1), - levy => maybe_unmarshal(Levy, fun unmarshal_cash/1), - body => maybe_unmarshal(Body, fun unmarshal_cash/1), - created_at => maybe_unmarshal(CreatedAt, fun unmarshal_string/1) - }). +get_created_at(invoice, ?INVOICE(Invoice)) -> + {ok, Invoice#domain_Invoice.created_at}; +get_created_at(invoice_adjustment, ?INVOICE_ADJUSTMENT(Adjustment)) -> + {ok, Adjustment#domain_InvoiceAdjustment.created_at}; +get_created_at(invoice_payment, ?INVOICE_PAYMENT(Payment)) -> + {ok, Payment#domain_InvoicePayment.created_at}; +get_created_at(invoice_payment_adjustment, ?INVOICE_PAYMENT_ADJUSTMENT(Adjustment)) -> + {ok, Adjustment#domain_InvoicePaymentAdjustment.created_at}; +get_created_at(invoice_payment_refund, ?INVOICE_PAYMENT_REFUND(Refund)) -> + {ok, Refund#domain_InvoicePaymentRefund.created_at}; +get_created_at(invoice_payment_chargeback, ?INVOICE_PAYMENT_CHARGEBACK(Chargeback)) -> + {ok, Chargeback#domain_InvoicePaymentChargeback.created_at}; +get_created_at(_, _CtxInvoice) -> + {error, notfound}. -unmarshal_cash(#domain_Cash{amount = Amount, currency = #domain_CurrencyRef{symbolic_code = Currency}}) -> - #{amount => Amount, currency => Currency}. +get_cost(invoice, ?INVOICE(Invoice)) -> + lim_payproc_utils:cash(Invoice#domain_Invoice.cost); +get_cost(invoice_payment, ?INVOICE_PAYMENT(Payment)) -> + lim_payproc_utils:cash(Payment#domain_InvoicePayment.cost); +get_cost(invoice_payment_refund, ?INVOICE_PAYMENT_REFUND(Refund)) -> + lim_payproc_utils:cash(Refund#domain_InvoicePaymentRefund.cash); +get_cost(invoice_payment_chargeback, ?INVOICE_PAYMENT_CHARGEBACK(Chargeback)) -> + lim_payproc_utils:cash(Chargeback#domain_InvoicePaymentChargeback.body); +get_cost(_, _CtxInvoice) -> + {error, notfound}. -unmarshal_string(Value) -> - Value. +get_capture_cost(invoice_payment, ?INVOICE_PAYMENT(Payment)) -> + get_capture_cost(Payment#domain_InvoicePayment.status); +get_capture_cost(_, _CtxInvoice) -> + {error, notfound}. -maybe_unmarshal(undefined, _) -> - undefined; -maybe_unmarshal(Value, UnmarshalFun) -> - UnmarshalFun(Value). +get_capture_cost({captured, #domain_InvoicePaymentCaptured{cost = Cost}}) when Cost /= undefined -> + lim_payproc_utils:cash(Cost); +get_capture_cost({_Status, _}) -> + {error, notfound}. + +get_payment_tool(Operation, ?INVOICE_PAYMENT(Payment)) when + Operation == invoice_payment; + Operation == invoice_payment_adjustment; + Operation == invoice_payment_refund; + Operation == invoice_payment_chargeback +-> + {_Type, Payer} = Payment#domain_InvoicePayment.payer, + get_payer_payment_tool(Payer); +get_payment_tool(_, _CtxInvoice) -> + {error, notfound}. + +get_payer_payment_tool(#domain_PaymentResourcePayer{resource = #domain_DisposablePaymentResource{payment_tool = PT}}) -> + lim_payproc_utils:payment_tool(PT); +get_payer_payment_tool(#domain_CustomerPayer{payment_tool = PT}) -> + lim_payproc_utils:payment_tool(PT); +get_payer_payment_tool(#domain_RecurrentPayer{payment_tool = PT}) -> + lim_payproc_utils:payment_tool(PT). -ifdef(TEST). -include_lib("eunit/include/eunit.hrl"). -spec test() -> _. --spec marshal_unmarshal_created_test() -> _. -marshal_unmarshal_created_test() -> - ExpDate = #domain_BankCardExpDate{month = 2, year = 2022}, +-define(PAYMENT_W_PAYER(Payer), #domain_InvoicePayment{ + id = <<"ID">>, + created_at = <<"2000-02-02T12:12:12Z">>, + status = {pending, #domain_InvoicePaymentPending{}}, + cost = #domain_Cash{ + amount = 42, + currency = #domain_CurrencyRef{symbolic_code = <<"CNY">>} + }, + domain_revision = 42, + flow = {instant, #domain_InvoicePaymentFlowInstant{}}, + payer = Payer +}). + +-define(CONTEXT_PAYMENT(Payment), #context_payproc_Context{ + op = {invoice_payment, #context_payproc_OperationInvoicePayment{}}, + invoice = #context_payproc_Invoice{ + payment = #context_payproc_InvoicePayment{ + payment = Payment + } + } +}). + +-spec get_payment_tool_test_() -> [_TestGen]. +get_payment_tool_test_() -> PaymentTool = {bank_card, #domain_BankCard{ token = <<"Token">>, - bin = <<"bin">>, - exp_date = ExpDate, + bin = <<"654321">>, + exp_date = #domain_BankCardExpDate{month = 2, year = 2022}, last_digits = <<"1234">> }}, - Data0 = #domain_PaymentResourcePayer{ - resource = #domain_DisposablePaymentResource{payment_tool = PaymentTool}, - contact_info = #domain_ContactInfo{} - }, - #{payment_tool := _} = unmarshal_payment_processing_invoice_payment_payer_data(Data0), - Data1 = #domain_CustomerPayer{ - customer_id = <<"customer_id">>, - customer_binding_id = <<"customer_binding_id">>, - rec_payment_tool_id = <<"rec_payment_tool_id">>, - payment_tool = PaymentTool, - contact_info = #domain_ContactInfo{} - }, - #{payment_tool := _} = unmarshal_payment_processing_invoice_payment_payer_data(Data1), - Data2 = #domain_RecurrentPayer{ - payment_tool = PaymentTool, - recurrent_parent = #domain_RecurrentParentPayment{ - invoice_id = <<"invoice_id">>, - payment_id = <<"payment_id">> - }, - contact_info = #domain_ContactInfo{} - }, - #{payment_tool := _} = unmarshal_payment_processing_invoice_payment_payer_data(Data2), - Data3 = #domain_RecurrentPayer{ - payment_tool = {payment_terminal, #domain_PaymentTerminal{}}, - recurrent_parent = #domain_RecurrentParentPayment{ - invoice_id = <<"invoice_id">>, - payment_id = <<"payment_id">> - }, - contact_info = #domain_ContactInfo{} - }, - #{} = unmarshal_payment_processing_invoice_payment_payer_data(Data3). + PaymentResourcePayer = + {payment_resource, #domain_PaymentResourcePayer{ + resource = #domain_DisposablePaymentResource{payment_tool = PaymentTool}, + contact_info = #domain_ContactInfo{} + }}, + CustomerPayer = + {customer, #domain_CustomerPayer{ + customer_id = <<"customer_id">>, + customer_binding_id = <<"customer_binding_id">>, + rec_payment_tool_id = <<"rec_payment_tool_id">>, + payment_tool = PaymentTool, + contact_info = #domain_ContactInfo{} + }}, + RecurrentPayer = + {recurrent, #domain_RecurrentPayer{ + payment_tool = PaymentTool, + recurrent_parent = #domain_RecurrentParentPayment{ + invoice_id = <<"invoice_id">>, + payment_id = <<"payment_id">> + }, + contact_info = #domain_ContactInfo{} + }}, + ExpectedValue = {bank_card, #{token => <<"Token">>, exp_date => {2, 2022}}}, + [ + ?_assertEqual( + {ok, ExpectedValue}, + get_value(payment_tool, ?CONTEXT_PAYMENT(?PAYMENT_W_PAYER(PaymentResourcePayer))) + ), + ?_assertEqual( + {ok, ExpectedValue}, + get_value(payment_tool, ?CONTEXT_PAYMENT(?PAYMENT_W_PAYER(CustomerPayer))) + ), + ?_assertEqual( + {ok, ExpectedValue}, + get_value(payment_tool, ?CONTEXT_PAYMENT(?PAYMENT_W_PAYER(RecurrentPayer))) + ) + ]. + +-spec get_payment_tool_unsupported_test_() -> _TestGen. +get_payment_tool_unsupported_test_() -> + Payer = + {recurrent, #domain_RecurrentPayer{ + payment_tool = {payment_terminal, #domain_PaymentTerminal{}}, + recurrent_parent = #domain_RecurrentParentPayment{ + invoice_id = <<"invoice_id">>, + payment_id = <<"payment_id">> + }, + contact_info = #domain_ContactInfo{} + }}, + ?_assertEqual( + {error, {unsupported, {payment_tool, payment_terminal}}}, + get_value(payment_tool, ?CONTEXT_PAYMENT(?PAYMENT_W_PAYER(Payer))) + ). -endif. diff --git a/apps/limiter/src/lim_payproc_utils.erl b/apps/limiter/src/lim_payproc_utils.erl new file mode 100644 index 0000000..7b62a57 --- /dev/null +++ b/apps/limiter/src/lim_payproc_utils.erl @@ -0,0 +1,48 @@ +-module(lim_payproc_utils). + +-include_lib("damsel/include/dmsl_domain_thrift.hrl"). + +-export([cash/1]). +-export([payment_tool/1]). + +-type cash() :: + lim_body:cash(). + +-type payment_tool() :: + {bank_card, #{ + token := binary(), + exp_date := {1..12, 2000..9999} | undefined + }} + | {digital_wallet, #{ + id := binary(), + service := binary() + }}. + +%% + +-spec cash(dmsl_domain_thrift:'Cash'()) -> + {ok, cash()}. +cash(#domain_Cash{amount = Amount, currency = #domain_CurrencyRef{symbolic_code = Currency}}) -> + {ok, #{amount => Amount, currency => Currency}}. + +-spec payment_tool(dmsl_domain_thrift:'PaymentTool'()) -> + {ok, payment_tool()} | {error, {unsupported, _}}. +payment_tool({bank_card, BC}) -> + {ok, + {bank_card, #{ + token => BC#domain_BankCard.token, + exp_date => get_bank_card_expdate(BC#domain_BankCard.exp_date) + }}}; +payment_tool({digital_wallet, DW}) -> + {ok, + {digital_wallet, #{ + id => DW#domain_DigitalWallet.id, + service => DW#domain_DigitalWallet.payment_service#domain_PaymentServiceRef.id + }}}; +payment_tool({Type, _}) -> + {error, {unsupported, {payment_tool, Type}}}. + +get_bank_card_expdate(#domain_BankCardExpDate{month = Month, year = Year}) -> + {Month, Year}; +get_bank_card_expdate(undefined) -> + undefined. diff --git a/apps/limiter/src/lim_range_codec.erl b/apps/limiter/src/lim_range_codec.erl index 8e854bd..d6b2424 100644 --- a/apps/limiter/src/lim_range_codec.erl +++ b/apps/limiter/src/lim_range_codec.erl @@ -1,6 +1,7 @@ -module(lim_range_codec). --include_lib("limiter_proto/include/lim_limiter_range_thrift.hrl"). +-include_lib("limiter_proto/include/limproto_range_thrift.hrl"). +-include_lib("limiter_proto/include/limproto_timerange_thrift.hrl"). -export([marshal/2]). -export([unmarshal/2]). @@ -20,14 +21,14 @@ -spec marshal(type_name(), decoded_value()) -> encoded_value(). marshal(timestamped_change, {ev, Timestamp, Change}) -> - #limiter_range_TimestampedChange{ + #range_TimestampedChange{ change = marshal(change, Change), occured_at = marshal(timestamp, Timestamp) }; marshal(change, {created, Range}) -> - {created, #limiter_range_CreatedChange{limit_range = marshal(range, Range)}}; + {created, #range_CreatedChange{limit_range = marshal(range, Range)}}; marshal(change, {time_range_created, TimeRange}) -> - {time_range_created, #limiter_range_TimeRangeCreatedChange{time_range = marshal(time_range, TimeRange)}}; + {time_range_created, #range_TimeRangeCreatedChange{time_range = marshal(time_range, TimeRange)}}; marshal( range, Range = #{ @@ -36,7 +37,7 @@ marshal( created_at := CreatedAt } ) -> - #limiter_range_LimitRange{ + #range_LimitRange{ id = ID, type = marshal(time_range_type, Type), created_at = CreatedAt, @@ -48,7 +49,7 @@ marshal(time_range, #{ account_id_from := AccountIDFrom, account_id_to := AccountIDTo }) -> - #limiter_time_range_TimeRange{ + #timerange_TimeRange{ upper = Upper, lower = Lower, account_id_from = AccountIDFrom, @@ -57,15 +58,15 @@ marshal(time_range, #{ marshal(time_range_type, {calendar, SubType}) -> {calendar, marshal(time_range_sub_type, SubType)}; marshal(time_range_type, {interval, Interval}) -> - {interval, #limiter_time_range_TimeRangeTypeInterval{amount = Interval}}; + {interval, #timerange_TimeRangeTypeInterval{amount = Interval}}; marshal(time_range_sub_type, year) -> - {year, #limiter_time_range_TimeRangeTypeCalendarYear{}}; + {year, #timerange_TimeRangeTypeCalendarYear{}}; marshal(time_range_sub_type, month) -> - {month, #limiter_time_range_TimeRangeTypeCalendarMonth{}}; + {month, #timerange_TimeRangeTypeCalendarMonth{}}; marshal(time_range_sub_type, week) -> - {week, #limiter_time_range_TimeRangeTypeCalendarWeek{}}; + {week, #timerange_TimeRangeTypeCalendarWeek{}}; marshal(time_range_sub_type, day) -> - {day, #limiter_time_range_TimeRangeTypeCalendarDay{}}; + {day, #timerange_TimeRangeTypeCalendarDay{}}; marshal(timestamp, {DateTime, USec}) -> DateTimeinSeconds = genlib_time:daytime_to_unixtime(DateTime), {TimeinUnit, Unit} = @@ -80,14 +81,14 @@ marshal(timestamp, {DateTime, USec}) -> -spec unmarshal(type_name(), encoded_value()) -> decoded_value(). unmarshal(timestamped_change, TimestampedChange) -> - Timestamp = unmarshal(timestamp, TimestampedChange#limiter_range_TimestampedChange.occured_at), - Change = unmarshal(change, TimestampedChange#limiter_range_TimestampedChange.change), + Timestamp = unmarshal(timestamp, TimestampedChange#range_TimestampedChange.occured_at), + Change = unmarshal(change, TimestampedChange#range_TimestampedChange.change), {ev, Timestamp, Change}; -unmarshal(change, {created, #limiter_range_CreatedChange{limit_range = Range}}) -> +unmarshal(change, {created, #range_CreatedChange{limit_range = Range}}) -> {created, unmarshal(range, Range)}; -unmarshal(change, {time_range_created, #limiter_range_TimeRangeCreatedChange{time_range = Range}}) -> +unmarshal(change, {time_range_created, #range_TimeRangeCreatedChange{time_range = Range}}) -> {time_range_created, unmarshal(time_range, Range)}; -unmarshal(range, #limiter_range_LimitRange{ +unmarshal(range, #range_LimitRange{ id = ID, type = Type, created_at = CreatedAt, @@ -99,7 +100,7 @@ unmarshal(range, #limiter_range_LimitRange{ created_at => CreatedAt, currency => Currency }); -unmarshal(time_range, #limiter_time_range_TimeRange{ +unmarshal(time_range, #timerange_TimeRange{ upper = Upper, lower = Lower, account_id_from = AccountIDFrom, @@ -113,7 +114,7 @@ unmarshal(time_range, #limiter_time_range_TimeRange{ }; unmarshal(time_range_type, {calendar, SubType}) -> {calendar, unmarshal(time_range_sub_type, SubType)}; -unmarshal(time_range_type, {interval, #limiter_time_range_TimeRangeTypeInterval{amount = Interval}}) -> +unmarshal(time_range_type, {interval, #timerange_TimeRangeTypeInterval{amount = Interval}}) -> {interval, Interval}; unmarshal(time_range_sub_type, {year, _}) -> year; diff --git a/apps/limiter/src/lim_range_machinery_schema.erl b/apps/limiter/src/lim_range_machinery_schema.erl index db8d84d..71b0413 100644 --- a/apps/limiter/src/lim_range_machinery_schema.erl +++ b/apps/limiter/src/lim_range_machinery_schema.erl @@ -70,13 +70,13 @@ unmarshal(T, V, C) when -spec marshal_event(machinery_mg_schema:version(), event(), context()) -> {machinery_msgpack:t(), context()}. marshal_event(1, TimestampedChange, Context) -> ThriftChange = lim_range_codec:marshal(timestamped_change, TimestampedChange), - Type = {struct, struct, {lim_limiter_range_thrift, 'TimestampedChange'}}, + Type = {struct, struct, {limproto_range_thrift, 'TimestampedChange'}}, {{bin, lim_proto_utils:serialize(Type, ThriftChange)}, Context}. -spec unmarshal_event(machinery_mg_schema:version(), machinery_msgpack:t(), context()) -> {event(), context()}. unmarshal_event(1, EncodedChange, Context) -> {bin, EncodedThriftChange} = EncodedChange, - Type = {struct, struct, {lim_limiter_range_thrift, 'TimestampedChange'}}, + Type = {struct, struct, {limproto_range_thrift, 'TimestampedChange'}}, ThriftChange = lim_proto_utils:deserialize(Type, EncodedThriftChange), {lim_range_codec:unmarshal(timestamped_change, ThriftChange), Context}. @@ -98,7 +98,7 @@ marshal_unmarshal_created_test() -> created_at => <<"2000-01-01T00:00:00Z">>, currency => <<"USD">> }}, - Context = #{machine_ref => ID, machine_ns => limrange}, + Context = #{machine_id => ID, machine_ns => limrange}, Event = {ev, lim_time:machinery_now(), Created}, {Marshaled, _} = marshal_event(1, Event, Context), {Unmarshaled, _} = unmarshal_event(1, Marshaled, Context), @@ -113,7 +113,7 @@ marshal_unmarshal_time_range_created_test() -> upper => <<"2000-01-01T00:00:00Z">>, lower => <<"2000-01-01T00:00:00Z">> }}, - Context = #{machine_ref => <<"id">>, machine_ns => limrange}, + Context = #{machine_id => <<"id">>, machine_ns => limrange}, Event = {ev, lim_time:machinery_now(), TimeRangeCreated}, {Marshaled, _} = marshal_event(1, Event, Context), {Unmarshaled, _} = unmarshal_event(1, Marshaled, Context), diff --git a/apps/limiter/src/lim_rates.erl b/apps/limiter/src/lim_rates.erl index f7eb00d..5526f8b 100644 --- a/apps/limiter/src/lim_rates.erl +++ b/apps/limiter/src/lim_rates.erl @@ -20,7 +20,7 @@ | {error, conversion_error()}. convert(#{amount := Amount, currency := Currency}, DestinationCurrency, Config, LimitContext) -> ContextType = lim_config_machine:context_type(Config), - {ok, Timestamp} = lim_context:get_from_context(ContextType, created_at, LimitContext), + {ok, Timestamp} = lim_context:get_value(ContextType, created_at, LimitContext), Request = #rate_ConversionRequest{ source = Currency, destination = DestinationCurrency, diff --git a/apps/limiter/src/lim_turnover_metric.erl b/apps/limiter/src/lim_turnover_metric.erl index cc99c6f..8ce2aa7 100644 --- a/apps/limiter/src/lim_turnover_metric.erl +++ b/apps/limiter/src/lim_turnover_metric.erl @@ -3,7 +3,7 @@ -export([compute/4]). -type amount() :: lim_body:amount(). --type currency() :: lim_domain_thrift:'CurrencySymbolicCode'(). +-type currency() :: dmsl_domain_thrift:'CurrencySymbolicCode'(). -type stage() :: hold | commit. -type t() :: number | {amount, currency()}. @@ -39,7 +39,7 @@ get_commit_body(Config, LimitContext) -> case lim_body:get(partial, Config, LimitContext) of {ok, Body} -> Body; - {error, notfound} -> + {error, _} -> get_body(Config, LimitContext) end. diff --git a/apps/limiter/src/lim_turnover_processor.erl b/apps/limiter/src/lim_turnover_processor.erl index 203d8f1..1cdfa54 100644 --- a/apps/limiter/src/lim_turnover_processor.erl +++ b/apps/limiter/src/lim_turnover_processor.erl @@ -1,6 +1,6 @@ -module(lim_turnover_processor). --include_lib("limiter_proto/include/lim_limiter_thrift.hrl"). +-include_lib("limiter_proto/include/limproto_limiter_thrift.hrl"). -behaviour(lim_config_machine). @@ -108,13 +108,13 @@ rollback(LimitChange = #limiter_LimitChange{id = LimitID}, Config, LimitContext) end). compute_limit_time_range_location(LimitID, Config, LimitContext) -> - {ok, Timestamp} = lim_context:get_from_context(payment_processing, created_at, LimitContext), + Timestamp = get_timestamp(Config, LimitContext), LimitRangeID = construct_range_id(LimitID, Timestamp, Config, LimitContext), TimeRange = lim_config_machine:calculate_time_range(Timestamp, Config), {LimitRangeID, TimeRange}. ensure_limit_time_range(LimitID, Config, LimitContext) -> - {ok, Timestamp} = lim_context:get_from_context(payment_processing, created_at, LimitContext), + Timestamp = get_timestamp(Config, LimitContext), {LimitRangeID, TimeRange} = compute_limit_time_range_location(LimitID, Config, LimitContext), CreateParams = genlib_map:compact(#{ id => LimitRangeID, @@ -124,6 +124,11 @@ ensure_limit_time_range(LimitID, Config, LimitContext) -> }), unwrap(lim_range_machine:ensure_exists(CreateParams, TimeRange, LimitContext)). +get_timestamp(Config, LimitContext) -> + ContextType = lim_config_machine:context_type(Config), + {ok, Timestamp} = lim_context:get_value(ContextType, created_at, LimitContext), + Timestamp. + construct_plan_id(#limiter_LimitChange{change_id = ChangeID}) -> % DISCUSS ChangeID. diff --git a/apps/limiter/src/lim_wthdproc_context.erl b/apps/limiter/src/lim_wthdproc_context.erl new file mode 100644 index 0000000..123716f --- /dev/null +++ b/apps/limiter/src/lim_wthdproc_context.erl @@ -0,0 +1,73 @@ +-module(lim_wthdproc_context). + +-include_lib("limiter_proto/include/limproto_context_withdrawal_thrift.hrl"). +-include_lib("damsel/include/dmsl_wthd_domain_thrift.hrl"). + +-behaviour(lim_context). +-export([get_operation/1]). +-export([get_value/2]). + +-type context() :: limproto_context_withdrawal_thrift:'Context'(). + +-type operation() :: + withdrawal. + +-export_type([operation/0]). +-export_type([context/0]). + +%% + +-spec get_operation(context()) -> {ok, operation()} | {error, notfound}. +get_operation(#context_withdrawal_Context{op = {Operation, _}}) -> + {ok, Operation}; +get_operation(#context_withdrawal_Context{op = undefined}) -> + {error, notfound}. + +-spec get_value(atom(), context()) -> {ok, term()} | {error, notfound | {unsupported, _}}. +get_value(ValueName, Context) -> + case get_operation(Context) of + {ok, Operation} -> + get_value(ValueName, Operation, Context); + {error, _} = Error -> + Error + end. + +get_value(owner_id, _Operation, Context) -> + get_owner_id(Context); +get_value(created_at, Operation, Context) -> + get_created_at(Operation, Context); +get_value(cost, Operation, Context) -> + get_cost(Operation, Context); +get_value(payment_tool, Operation, Context) -> + get_payment_tool(Operation, Context); +get_value(ValueName, _Operation, _Context) -> + {error, {unsupported, ValueName}}. + +-define(WITHDRAWAL(V), #context_withdrawal_Context{ + withdrawal = #context_withdrawal_Withdrawal{ + withdrawal = V = #wthd_domain_Withdrawal{} + } +}). + +get_owner_id(?WITHDRAWAL(Wthd)) -> + Identity = Wthd#wthd_domain_Withdrawal.sender, + {ok, Identity#wthd_domain_Identity.owner_id}; +get_owner_id(_CtxWithdrawal) -> + {error, notfound}. + +get_created_at(withdrawal, ?WITHDRAWAL(Wthd)) -> + {ok, Wthd#wthd_domain_Withdrawal.created_at}; +get_created_at(_, _CtxWithdrawal) -> + {error, notfound}. + +get_cost(withdrawal, ?WITHDRAWAL(Wthd)) -> + Body = Wthd#wthd_domain_Withdrawal.body, + lim_payproc_utils:cash(Body); +get_cost(_, _CtxWithdrawal) -> + {error, notfound}. + +get_payment_tool(withdrawal, ?WITHDRAWAL(Wthd)) -> + Destination = Wthd#wthd_domain_Withdrawal.destination, + lim_payproc_utils:payment_tool(Destination); +get_payment_tool(_, _CtxWithdrawal) -> + {error, notfound}. diff --git a/apps/limiter/src/limiter.app.src b/apps/limiter/src/limiter.app.src index 0e0bd83..a741026 100644 --- a/apps/limiter/src/limiter.app.src +++ b/apps/limiter/src/limiter.app.src @@ -5,7 +5,6 @@ {applications, [ kernel, stdlib, - damsel, limiter_proto, xrates_proto, machinery, diff --git a/apps/limiter/src/limiter.erl b/apps/limiter/src/limiter.erl index aaf6c4e..6bf855b 100644 --- a/apps/limiter/src/limiter.erl +++ b/apps/limiter/src/limiter.erl @@ -91,11 +91,11 @@ get_handler_specs(ServiceOpts) -> [ { maps:get(path, LimiterService, <<"/v1/limiter">>), - {{lim_limiter_thrift, 'Limiter'}, lim_handler} + {{limproto_limiter_thrift, 'Limiter'}, lim_handler} }, { maps:get(path, ConfiguratorService, <<"/v1/configurator">>), - {{lim_configurator_thrift, 'Configurator'}, lim_configurator} + {{limproto_configurator_thrift, 'Configurator'}, lim_configurator} } ]. diff --git a/apps/limiter/test/lim_client.erl b/apps/limiter/test/lim_client.erl index 5a14e13..1de2da4 100644 --- a/apps/limiter/test/lim_client.erl +++ b/apps/limiter/test/lim_client.erl @@ -1,11 +1,12 @@ -module(lim_client). --include_lib("limiter_proto/include/lim_limiter_thrift.hrl"). +-include_lib("limiter_proto/include/limproto_limiter_thrift.hrl"). -export([new/0]). -export([get/3]). -export([hold/3]). -export([commit/3]). +-export([rollback/3]). -export([legacy_create_config/2]). -export([create_config/2]). @@ -13,12 +14,12 @@ -type client() :: woody_context:ctx(). --type limit_id() :: lim_limiter_thrift:'LimitID'(). --type limit_change() :: lim_limiter_thrift:'LimitChange'(). --type limit_context() :: lim_limiter_thrift:'LimitContext'(). --type clock() :: lim_limiter_thrift:'Clock'(). --type legacy_create_params() :: lim_configurator_thrift:'LimitCreateParams'(). --type limit_config_params() :: lim_limiter_config_thrift:'LimitConfigParams'(). +-type limit_id() :: limproto_limiter_thrift:'LimitID'(). +-type limit_change() :: limproto_limiter_thrift:'LimitChange'(). +-type limit_context() :: limproto_limiter_thrift:'LimitContext'(). +-type clock() :: limproto_limiter_thrift:'Clock'(). +-type legacy_create_params() :: limproto_configurator_thrift:'LimitCreateParams'(). +-type limit_config_params() :: limproto_config_thrift:'LimitConfigParams'(). %%% API @@ -38,6 +39,10 @@ hold(LimitChange, Context, Client) -> commit(LimitChange, Context, Client) -> call('Commit', {LimitChange, clock(), Context}, Client). +-spec rollback(limit_change(), limit_context(), client()) -> woody:result() | no_return(). +rollback(LimitChange, Context, Client) -> + call('Rollback', {LimitChange, clock(), Context}, Client). + %% -spec legacy_create_config(legacy_create_params(), client()) -> woody:result() | no_return(). @@ -56,7 +61,7 @@ get_config(LimitConfigID, Client) -> -spec call(atom(), tuple(), client()) -> woody:result() | no_return(). call(Function, Args, Client) -> - Call = {{lim_limiter_thrift, 'Limiter'}, Function, Args}, + Call = {{limproto_limiter_thrift, 'Limiter'}, Function, Args}, Opts = #{ url => <<"http://limiter:8022/v1/limiter">>, event_handler => scoper_woody_event_handler, @@ -68,7 +73,7 @@ call(Function, Args, Client) -> -spec call_configurator(atom(), tuple(), client()) -> woody:result() | no_return(). call_configurator(Function, Args, Client) -> - Call = {{lim_configurator_thrift, 'Configurator'}, Function, Args}, + Call = {{limproto_configurator_thrift, 'Configurator'}, Function, Args}, Opts = #{ url => <<"http://limiter:8022/v1/configurator">>, event_handler => scoper_woody_event_handler, diff --git a/apps/limiter/test/lim_configurator_SUITE.erl b/apps/limiter/test/lim_configurator_SUITE.erl index 61e8f64..cb98e49 100644 --- a/apps/limiter/test/lim_configurator_SUITE.erl +++ b/apps/limiter/test/lim_configurator_SUITE.erl @@ -2,7 +2,7 @@ -include_lib("common_test/include/ct.hrl"). -include_lib("stdlib/include/assert.hrl"). --include_lib("limiter_proto/include/lim_configurator_thrift.hrl"). +-include_lib("limiter_proto/include/limproto_configurator_thrift.hrl"). -include("lim_ct_helper.hrl"). -export([all/0]). @@ -17,6 +17,7 @@ -export([create_config/1]). -export([create_config_single_scope/1]). -export([get_config/1]). +-export([get_inexistent_config/1]). -type group_name() :: atom(). -type test_case_name() :: atom(). @@ -36,7 +37,8 @@ groups() -> legacy_create_config, create_config, create_config_single_scope, - get_config + get_config, + get_inexistent_config ]} ]. @@ -81,14 +83,14 @@ legacy_create_config(C) -> Client = lim_client:new(), ID = ?config(limit_id, C), Description = genlib:unique(), - Params = #limiter_configurator_LimitCreateParams{ + Params = #configurator_LimitCreateParams{ id = ID, name = <<"GlobalMonthTurnover">>, description = Description, started_at = <<"2000-01-01T00:00:00Z">> }, ?assertMatch( - {ok, #limiter_config_LimitConfig{ + {ok, #config_LimitConfig{ id = ID, description = Description }}, @@ -100,7 +102,7 @@ create_config(C) -> Client = lim_client:new(), ID = ?config(limit_id, C), Description = genlib:unique(), - Params = #limiter_config_LimitConfigParams{ + Params = #config_LimitConfigParams{ id = ?config(limit_id, C), description = Description, started_at = <<"2000-01-01T00:00:00Z">>, @@ -115,7 +117,7 @@ create_config(C) -> context_type = ?ctx_type_payproc() }, ?assertMatch( - {ok, #limiter_config_LimitConfig{ + {ok, #config_LimitConfig{ id = ID, description = Description }}, @@ -125,7 +127,7 @@ create_config(C) -> -spec create_config_single_scope(config()) -> _. create_config_single_scope(C) -> Client = lim_client:new(), - Params = #limiter_config_LimitConfigParams{ + Params = #config_LimitConfigParams{ id = ?config(limit_id, C), started_at = <<"2000-01-01T00:00:00Z">>, time_range_type = ?time_range_week(), @@ -135,7 +137,7 @@ create_config_single_scope(C) -> context_type = ?ctx_type_payproc(), op_behaviour = ?op_behaviour() }, - {ok, #limiter_config_LimitConfig{ + {ok, #config_LimitConfig{ scope = Scope }} = lim_client:create_config(Params, Client), ?assertEqual(?scope([?scope_party()]), Scope). @@ -144,13 +146,20 @@ create_config_single_scope(C) -> get_config(C) -> ID = ?config(limit_id, C), #{client := Client} = prepare_environment(ID, <<"GlobalMonthTurnover">>, C), - {ok, #limiter_config_LimitConfig{id = ID}} = lim_client:get_config(ID, Client). + {ok, #config_LimitConfig{id = ID}} = lim_client:get_config(ID, Client). + +-spec get_inexistent_config(config()) -> _. +get_inexistent_config(_C) -> + ?assertEqual( + {exception, #configurator_LimitConfigNotFound{}}, + lim_client:get_config(<<"NOSUCHCONFIG">>, lim_client:new()) + ). %% prepare_environment(ID, LimitName, _C) -> Client = lim_client:new(), - Params = #limiter_configurator_LimitCreateParams{ + Params = #configurator_LimitCreateParams{ id = ID, name = LimitName, description = <<"description">>, diff --git a/apps/limiter/test/lim_ct_helper.hrl b/apps/limiter/test/lim_ct_helper.hrl index 57bbc3e..eaa5d8c 100644 --- a/apps/limiter/test/lim_ct_helper.hrl +++ b/apps/limiter/test/lim_ct_helper.hrl @@ -1,7 +1,13 @@ -ifndef(__limiter_ct_helper__). -define(__limiter_ct_helper__, 42). --include_lib("limiter_proto/include/lim_configurator_thrift.hrl"). +-include_lib("limiter_proto/include/limproto_config_thrift.hrl"). +-include_lib("limiter_proto/include/limproto_timerange_thrift.hrl"). +-include_lib("limiter_proto/include/limproto_limiter_thrift.hrl"). +-include_lib("limiter_proto/include/limproto_context_payproc_thrift.hrl"). +-include_lib("limiter_proto/include/limproto_context_withdrawal_thrift.hrl"). +-include_lib("damsel/include/dmsl_domain_thrift.hrl"). +-include_lib("damsel/include/dmsl_wthd_domain_thrift.hrl"). -define(currency, <<"RUB">>). -define(string, <<"STRING">>). @@ -16,126 +22,83 @@ -define(scope(Types), {multi, ordsets:from_list(Types)}). -define(global(), ?scope([])). --define(scope_party(), {party, #limiter_config_LimitScopeEmptyDetails{}}). --define(scope_shop(), {shop, #limiter_config_LimitScopeEmptyDetails{}}). --define(scope_payment_tool(), {payment_tool, #limiter_config_LimitScopeEmptyDetails{}}). +-define(scope_party(), {party, #config_LimitScopeEmptyDetails{}}). +-define(scope_shop(), {shop, #config_LimitScopeEmptyDetails{}}). +-define(scope_payment_tool(), {payment_tool, #config_LimitScopeEmptyDetails{}}). -define(lim_type_turnover(), ?lim_type_turnover(?turnover_metric_number())). -define(lim_type_turnover(Metric), - {turnover, #limiter_config_LimitTypeTurnover{metric = Metric}} + {turnover, #config_LimitTypeTurnover{metric = Metric}} ). --define(turnover_metric_number(), {number, #limiter_config_LimitTurnoverNumber{}}). +-define(turnover_metric_number(), {number, #config_LimitTurnoverNumber{}}). -define(turnover_metric_amount(), ?turnover_metric_amount(?currency)). -define(turnover_metric_amount(Currency), - {amount, #limiter_config_LimitTurnoverAmount{currency = Currency}} + {amount, #config_LimitTurnoverAmount{currency = Currency}} ). -define(time_range_day(), - {calendar, {day, #limiter_time_range_TimeRangeTypeCalendarDay{}}} + {calendar, {day, #timerange_TimeRangeTypeCalendarDay{}}} ). -define(time_range_week(), - {calendar, {week, #limiter_time_range_TimeRangeTypeCalendarWeek{}}} + {calendar, {week, #timerange_TimeRangeTypeCalendarWeek{}}} ). -define(time_range_month(), - {calendar, {month, #limiter_time_range_TimeRangeTypeCalendarMonth{}}} + {calendar, {month, #timerange_TimeRangeTypeCalendarMonth{}}} ). -define(time_range_year(), - {calendar, {year, #limiter_time_range_TimeRangeTypeCalendarYear{}}} + {calendar, {year, #timerange_TimeRangeTypeCalendarYear{}}} ). -define(op_behaviour(), ?op_behaviour(?op_addition())). --define(op_behaviour(Refund), #limiter_config_OperationLimitBehaviour{ +-define(op_behaviour(Refund), #config_OperationLimitBehaviour{ invoice_payment_refund = Refund }). --define(op_addition(), {addition, #limiter_config_Addition{}}). --define(op_subtraction(), {subtraction, #limiter_config_Subtraction{}}). +-define(op_addition(), {addition, #config_Addition{}}). +-define(op_subtraction(), {subtraction, #config_Subtraction{}}). -define(ctx_type_payproc(), - {payment_processing, #limiter_config_LimitContextTypePaymentProcessing{}} + {payment_processing, #config_LimitContextTypePaymentProcessing{}} ). --define(op_invoice(), {invoice, #limiter_context_PaymentProcessingOperationInvoice{}}). --define(op_invoice_payment(), {invoice_payment, #limiter_context_PaymentProcessingOperationInvoicePayment{}}). - --define(ctx_invoice(Cost), #limiter_context_LimitContext{ - limiter_payment_processing = #limiter_context_ContextPaymentProcessing{ - op = ?op_invoice(), - invoice = #limiter_context_Invoice{ - created_at = <<"2000-01-01T00:00:00Z">>, - cost = Cost - } - } -}). - --define(ctx_invoice_payment(Cost, CaptureCost), ?ctx_invoice_payment(undefined, undefined, Cost, CaptureCost)). - --define(ctx_invoice_payment(OwnerID, ShopID, Cost, CaptureCost), #limiter_context_LimitContext{ - limiter_payment_processing = #limiter_context_ContextPaymentProcessing{ - op = ?op_invoice_payment(), - invoice = #limiter_context_Invoice{ - owner_id = OwnerID, - shop_id = ShopID, - effective_payment = #limiter_context_InvoicePayment{ - created_at = <<"2000-01-01T00:00:00Z">>, - cost = Cost, - capture_cost = CaptureCost, - flow = {hold, #limiter_context_InvoicePaymentFlowHold{}}, - payer = {payment_resource, #limiter_context_PaymentResourcePayer{}}, - effective_adjustment = #limiter_context_InvoicePaymentAdjustment{}, - effective_chargeback = #limiter_context_InvoicePaymentChargeback{} - }, - effective_adjustment = #limiter_context_InvoiceAdjustment{} - } - } -}). - --define(ctx_invoice_payment(Payment), #limiter_context_LimitContext{ - limiter_payment_processing = #limiter_context_ContextPaymentProcessing{ - op = ?op_invoice_payment(), - invoice = #limiter_context_Invoice{ - effective_payment = Payment - } - } -}). - --define(ctx_invoice_payment_refund(OwnerID, ShopID, Cost, CaptureCost, RefundCost), #limiter_context_LimitContext{ - limiter_payment_processing = #limiter_context_ContextPaymentProcessing{ - op = {invoice_payment_refund, #limiter_context_PaymentProcessingOperationInvoicePaymentRefund{}}, - invoice = #limiter_context_Invoice{ - owner_id = OwnerID, - shop_id = ShopID, - effective_payment = #limiter_context_InvoicePayment{ - created_at = <<"2000-01-01T00:00:00Z">>, - cost = Cost, - capture_cost = CaptureCost, - effective_refund = #limiter_context_InvoicePaymentRefund{ - cost = RefundCost, - created_at = <<"2000-01-01T00:00:00Z">> - } - } - } - } -}). +-define(ctx_type_wthdproc(), + {withdrawal_processing, #config_LimitContextTypeWithdrawalProcessing{}} +). %% Payproc --define(payproc_op_invoice, {invoice, #limiter_context_payproc_OperationInvoice{}}). --define(payproc_op_invoice_payment, {invoice_payment, #limiter_context_payproc_OperationInvoicePayment{}}). +-define(op_invoice, {invoice, #context_payproc_OperationInvoice{}}). +-define(op_payment, {invoice_payment, #context_payproc_OperationInvoicePayment{}}). +-define(op_refund, {invoice_payment_refund, #context_payproc_OperationInvoicePaymentRefund{}}). --define(payproc_bank_card(), - ?payproc_bank_card(?string, 2, 2022) +-define(bank_card(), ?bank_card(?string, 2, 2022)). + +-define(bank_card(Token), + {bank_card, #domain_BankCard{ + token = Token, + bin = ?string, + last_digits = ?string + }} ). --define(payproc_bank_card(Token, Month, Year), #domain_BankCard{ - token = Token, - bin = ?string, - last_digits = ?string, - exp_date = #domain_BankCardExpDate{month = Month, year = Year} -}). +-define(bank_card(Token, Month, Year), + {bank_card, #domain_BankCard{ + token = Token, + bin = ?string, + last_digits = ?string, + exp_date = #domain_BankCardExpDate{month = Month, year = Year} + }} +). --define(payproc_invoice(OwnerID, ShopID, Cost), #domain_Invoice{ +-define(digital_wallet(ID, Service), + {digital_wallet, #domain_DigitalWallet{ + id = ID, + payment_service = #domain_PaymentServiceRef{id = Service} + }} +). + +-define(invoice(OwnerID, ShopID, Cost), #domain_Invoice{ id = ?string, owner_id = OwnerID, shop_id = ShopID, @@ -146,13 +109,17 @@ cost = Cost }). --define(payproc_invoice_payment(Cost, CaptureCost), - ?payproc_invoice_payment(Cost, CaptureCost, {bank_card, ?payproc_bank_card()}) +-define(invoice_payment(Cost, CaptureCost), + ?invoice_payment(Cost, CaptureCost, ?bank_card()) ). --define(payproc_invoice_payment(Cost, CaptureCost, PaymentTool), #domain_InvoicePayment{ +-define(invoice_payment(Cost, CaptureCost, PaymentTool), + ?invoice_payment(Cost, CaptureCost, PaymentTool, ?timestamp) +). + +-define(invoice_payment(Cost, CaptureCost, PaymentTool, CreatedAt), #domain_InvoicePayment{ id = ?string, - created_at = ?timestamp, + created_at = CreatedAt, status = {captured, #domain_InvoicePaymentCaptured{cost = CaptureCost}}, cost = Cost, domain_revision = 1, @@ -166,62 +133,87 @@ }} }). --define(payproc_ctx_invoice(Cost), #limiter_context_LimitContext{ - payment_processing = #limiter_context_payproc_Context{ - op = ?payproc_op_invoice, - invoice = #limiter_context_payproc_Invoice{ - invoice = ?payproc_invoice(?string, ?string, Cost) +-define(payproc_ctx_invoice(Cost), #limiter_LimitContext{ + payment_processing = #context_payproc_Context{ + op = ?op_invoice, + invoice = #context_payproc_Invoice{ + invoice = ?invoice(?string, ?string, Cost) } } }). --define(payproc_ctx_invoice_payment(Cost, CaptureCost), - ?payproc_ctx_invoice_payment(?string, ?string, Cost, CaptureCost) +-define(payproc_ctx_payment(Cost, CaptureCost), + ?payproc_ctx_payment(?string, ?string, Cost, CaptureCost) ). --define(payproc_ctx_invoice_payment(OwnerID, ShopID, Cost, CaptureCost), #limiter_context_LimitContext{ - payment_processing = #limiter_context_payproc_Context{ - op = ?payproc_op_invoice_payment, - invoice = #limiter_context_payproc_Invoice{ - invoice = ?payproc_invoice(OwnerID, ShopID, Cost), - payment = #limiter_context_payproc_InvoicePayment{ - payment = ?payproc_invoice_payment(Cost, CaptureCost) +-define(payproc_ctx_payment(OwnerID, ShopID, Cost, CaptureCost), #limiter_LimitContext{ + payment_processing = #context_payproc_Context{ + op = ?op_payment, + invoice = #context_payproc_Invoice{ + invoice = ?invoice(OwnerID, ShopID, Cost), + payment = #context_payproc_InvoicePayment{ + payment = ?invoice_payment(Cost, CaptureCost) } } } }). --define(payproc_ctx_invoice_payment(Payment), #limiter_context_LimitContext{ - payment_processing = #limiter_context_payproc_Context{ - op = ?payproc_op_invoice_payment, - invoice = #limiter_context_payproc_Invoice{ - invoice = ?payproc_invoice(?string, ?string, ?cash(10)), - payment = #limiter_context_payproc_InvoicePayment{ +-define(payproc_ctx_payment(Payment), #limiter_LimitContext{ + payment_processing = #context_payproc_Context{ + op = ?op_payment, + invoice = #context_payproc_Invoice{ + invoice = ?invoice(?string, ?string, ?cash(10)), + payment = #context_payproc_InvoicePayment{ payment = Payment } } } }). --define(payproc_ctx_invoice_payment_refund(OwnerID, ShopID, Cost, CaptureCost, RefundCost), - #limiter_context_LimitContext{ - payment_processing = #limiter_context_payproc_Context{ - op = {invoice_payment_refund, #limiter_context_payproc_OperationInvoicePaymentRefund{}}, - invoice = #limiter_context_payproc_Invoice{ - invoice = ?payproc_invoice(OwnerID, ShopID, Cost), - payment = #limiter_context_payproc_InvoicePayment{ - payment = ?payproc_invoice_payment(Cost, CaptureCost), - refund = #domain_InvoicePaymentRefund{ - id = ?string, - status = {succeeded, #domain_InvoicePaymentRefundSucceeded{}}, - created_at = ?timestamp, - domain_revision = 1, - cash = RefundCost - } +-define(payproc_ctx_refund(OwnerID, ShopID, Cost, CaptureCost, RefundCost), #limiter_LimitContext{ + payment_processing = #context_payproc_Context{ + op = ?op_refund, + invoice = #context_payproc_Invoice{ + invoice = ?invoice(OwnerID, ShopID, Cost), + payment = #context_payproc_InvoicePayment{ + payment = ?invoice_payment(Cost, CaptureCost), + refund = #domain_InvoicePaymentRefund{ + id = ?string, + status = {succeeded, #domain_InvoicePaymentRefundSucceeded{}}, + created_at = ?timestamp, + domain_revision = 1, + cash = RefundCost } } } } -). +}). + +%% Wthdproc + +-define(identity(OwnerID), #wthd_domain_Identity{ + id = OwnerID, + owner_id = OwnerID +}). + +-define(withdrawal(Body), ?withdrawal(Body, ?bank_card(), ?string)). + +-define(withdrawal(Body, Destination, OwnerID), #wthd_domain_Withdrawal{ + body = Body, + created_at = ?timestamp, + destination = Destination, + sender = ?identity(OwnerID) +}). + +-define(op_withdrawal, {withdrawal, #context_withdrawal_OperationWithdrawal{}}). + +-define(wthdproc_ctx_withdrawal(Cost), #limiter_LimitContext{ + withdrawal_processing = #context_withdrawal_Context{ + op = ?op_withdrawal, + withdrawal = #context_withdrawal_Withdrawal{ + withdrawal = ?withdrawal(Cost) + } + } +}). -endif. diff --git a/apps/limiter/test/lim_turnover_SUITE.erl b/apps/limiter/test/lim_turnover_SUITE.erl index 1d07ff1..b527a70 100644 --- a/apps/limiter/test/lim_turnover_SUITE.erl +++ b/apps/limiter/test/lim_turnover_SUITE.erl @@ -2,10 +2,8 @@ -include_lib("stdlib/include/assert.hrl"). -include_lib("common_test/include/ct.hrl"). --include_lib("lim_ct_helper.hrl"). - --include_lib("limiter_proto/include/lim_configurator_thrift.hrl"). --include_lib("xrates_proto/include/xrates_rate_thrift.hrl"). +-include_lib("damsel/include/dmsl_base_thrift.hrl"). +-include("lim_ct_helper.hrl"). -export([all/0]). @@ -18,17 +16,18 @@ -export([commit_with_default_exchange/1]). -export([partial_commit_with_exchange/1]). -export([commit_with_exchange/1]). --export([get_rate/1]). -export([get_limit_ok/1]). -export([get_limit_notfound/1]). -export([hold_ok/1]). -export([commit_ok/1]). -export([rollback_ok/1]). +-export([partial_zero_commit_rollbacks/1]). -export([refund_ok/1]). -export([get_config_ok/1]). -export([commit_inexistent_hold_fails/1]). -export([partial_commit_inexistent_hold_fails/1]). -export([commit_multirange_limit_ok/1]). +-export([commit_with_payment_tool_scope_ok/1]). -export([commit_processes_idempotently/1]). -export([full_commit_processes_idempotently/1]). @@ -40,23 +39,16 @@ -export([commit_refund_keep_number_unchanged/1]). -export([partial_commit_number_counts_as_single_op/1]). --export([payproc_hold_ok/1]). --export([payproc_commit_ok/1]). --export([payproc_rollback_ok/1]). --export([payproc_refund_ok/1]). --export([payproc_commit_with_payment_tool_scope_ok/1]). - -type group_name() :: atom(). -type test_case_name() :: atom(). --define(RATE_SOURCE_ID, <<"dummy_source_id">>). - %% tests descriptions -spec all() -> [{group, group_name()}]. all() -> [ {group, default}, + {group, withdrawals}, {group, cashless}, {group, idempotency} ]. @@ -68,22 +60,24 @@ groups() -> commit_with_default_exchange, partial_commit_with_exchange, commit_with_exchange, - get_rate, get_limit_ok, get_limit_notfound, hold_ok, commit_ok, rollback_ok, + partial_zero_commit_rollbacks, get_config_ok, refund_ok, commit_inexistent_hold_fails, partial_commit_inexistent_hold_fails, commit_multirange_limit_ok, - payproc_hold_ok, - payproc_commit_ok, - payproc_rollback_ok, - payproc_refund_ok, - payproc_commit_with_payment_tool_scope_ok + commit_with_payment_tool_scope_ok + ]}, + {withdrawals, [parallel], [ + get_limit_ok, + hold_ok, + commit_ok, + rollback_ok ]}, {cashless, [parallel], [ commit_number_ok, @@ -155,18 +149,8 @@ commit_with_default_exchange(C) -> Rational = #base_Rational{p = 1000000, q = 100}, _ = mock_exchange(Rational, C), ID = configure_limit(?time_range_month(), ?global(), C), - Context = #limiter_context_LimitContext{ - limiter_payment_processing = #limiter_context_ContextPaymentProcessing{ - op = {invoice, #limiter_context_PaymentProcessingOperationInvoice{}}, - invoice = #limiter_context_Invoice{ - created_at = <<"2000-01-01T00:00:00Z">>, - cost = #domain_Cash{ - amount = 10000, - currency = #domain_CurrencyRef{symbolic_code = <<"SOME_CURRENCY">>} - } - } - } - }, + Cost = ?cash(10000, <<"SOME_CURRENCY">>), + Context = ?payproc_ctx_invoice(Cost), {ok, {vector, _}} = hold_and_commit(?LIMIT_CHANGE(ID), Context, ?config(client, C)), {ok, #limiter_Limit{amount = 10000}} = lim_client:get(ID, Context, ?config(client, C)). @@ -175,24 +159,9 @@ partial_commit_with_exchange(C) -> Rational = #base_Rational{p = 800000, q = 100}, _ = mock_exchange(Rational, C), ID = configure_limit(?time_range_month(), ?global(), C), - Context = #limiter_context_LimitContext{ - limiter_payment_processing = #limiter_context_ContextPaymentProcessing{ - op = {invoice_payment, #limiter_context_PaymentProcessingOperationInvoicePayment{}}, - invoice = #limiter_context_Invoice{ - effective_payment = #limiter_context_InvoicePayment{ - created_at = <<"2000-01-01T00:00:00Z">>, - cost = #domain_Cash{ - amount = 10000, - currency = #domain_CurrencyRef{symbolic_code = <<"USD">>} - }, - capture_cost = #domain_Cash{ - amount = 8000, - currency = #domain_CurrencyRef{symbolic_code = <<"USD">>} - } - } - } - } - }, + Cost = ?cash(1000, <<"USD">>), + CaptureCost = ?cash(800, <<"USD">>), + Context = ?payproc_ctx_payment(Cost, CaptureCost), {ok, {vector, _}} = hold_and_commit(?LIMIT_CHANGE(ID), Context, ?config(client, C)), {ok, #limiter_Limit{amount = 8400}} = lim_client:get(ID, Context, ?config(client, C)). @@ -201,43 +170,19 @@ commit_with_exchange(C) -> Rational = #base_Rational{p = 1000000, q = 100}, _ = mock_exchange(Rational, C), ID = configure_limit(?time_range_month(), ?global(), C), - Context = #limiter_context_LimitContext{ - limiter_payment_processing = #limiter_context_ContextPaymentProcessing{ - op = {invoice, #limiter_context_PaymentProcessingOperationInvoice{}}, - invoice = #limiter_context_Invoice{ - created_at = <<"2000-01-01T00:00:00Z">>, - cost = #domain_Cash{ - amount = 10000, - currency = #domain_CurrencyRef{symbolic_code = <<"USD">>} - } - } - } - }, + Cost = ?cash(10000, <<"USD">>), + Context = ?payproc_ctx_invoice(Cost), {ok, {vector, _}} = hold_and_commit(?LIMIT_CHANGE(ID), Context, ?config(client, C)), {ok, #limiter_Limit{amount = 10500}} = lim_client:get(ID, Context, ?config(client, C)). --spec get_rate(config()) -> _. -get_rate(C) -> - Rational = #base_Rational{p = 10, q = 10}, - _ = mock_exchange(Rational, C), - Request = #rate_ConversionRequest{ - source = <<"RUB">>, - destination = <<"USD">>, - amount = 100, - datetime = <<"Timestamp">> - }, - WoodyContext = woody_context:new(), - {ok, Rational} = lim_client_woody:call( - xrates, - 'GetConvertedAmount', - {?RATE_SOURCE_ID, Request}, - WoodyContext - ). - -spec get_limit_ok(config()) -> _. get_limit_ok(C) -> ID = configure_limit(?time_range_month(), ?global(), C), - Context = ?ctx_invoice(_Cost = undefined), + Context = + case get_group_name(C) of + default -> ?payproc_ctx_invoice(?cash(0)); + withdrawals -> ?wthdproc_ctx_withdrawal(?cash(0)) + end, ?assertMatch( {ok, #limiter_Limit{amount = 0}}, lim_client:get(ID, Context, ?config(client, C)) @@ -245,7 +190,7 @@ get_limit_ok(C) -> -spec get_limit_notfound(config()) -> _. get_limit_notfound(C) -> - Context = ?ctx_invoice(_Cost = undefined), + Context = ?payproc_ctx_invoice(?cash(0)), ?assertEqual( {exception, #limiter_LimitNotFound{}}, lim_client:get(<<"NOSUCHLIMITID">>, Context, ?config(client, C)) @@ -254,36 +199,50 @@ get_limit_notfound(C) -> -spec hold_ok(config()) -> _. hold_ok(C) -> ID = configure_limit(?time_range_month(), ?global(), C), - Context = ?ctx_invoice(?cash(10)), + Context = + case get_group_name(C) of + default -> ?payproc_ctx_invoice(?cash(10)); + withdrawals -> ?wthdproc_ctx_withdrawal(?cash(10)) + end, {ok, {vector, #limiter_VectorClock{}}} = lim_client:hold(?LIMIT_CHANGE(ID), Context, ?config(client, C)), {ok, #limiter_Limit{}} = lim_client:get(ID, Context, ?config(client, C)). -spec commit_ok(config()) -> _. commit_ok(C) -> ID = configure_limit(?time_range_month(), ?global(), C), - Context = #limiter_context_LimitContext{ - limiter_payment_processing = #limiter_context_ContextPaymentProcessing{ - op = {invoice, #limiter_context_PaymentProcessingOperationInvoice{}}, - invoice = #limiter_context_Invoice{ - created_at = <<"2000-01-01T00:00:00Z">>, - cost = #domain_Cash{ - amount = 10, - currency = #domain_CurrencyRef{symbolic_code = <<"RUB">>} - } - } - } - }, + Context = + case get_group_name(C) of + default -> ?payproc_ctx_invoice(?cash(10, <<"RUB">>)); + withdrawals -> ?wthdproc_ctx_withdrawal(?cash(10, <<"RUB">>)) + end, {ok, {vector, _}} = hold_and_commit(?LIMIT_CHANGE(ID), Context, ?config(client, C)), {ok, #limiter_Limit{}} = lim_client:get(ID, Context, ?config(client, C)). -spec rollback_ok(config()) -> _. rollback_ok(C) -> ID = configure_limit(?time_range_week(), ?global(), C), - Context0 = ?ctx_invoice_payment(?cash(10), ?cash(10)), - Context1 = ?ctx_invoice_payment(?cash(10), ?cash(0)), + Context = + case get_group_name(C) of + default -> ?payproc_ctx_invoice(?cash(10, <<"RUB">>)); + withdrawals -> ?wthdproc_ctx_withdrawal(?cash(10, <<"RUB">>)) + end, + Change = ?LIMIT_CHANGE(ID), + {ok, {vector, _}} = lim_client:hold(Change, Context, ?config(client, C)), + {ok, {vector, _}} = lim_client:rollback(Change, Context, ?config(client, C)). + +-spec partial_zero_commit_rollbacks(config()) -> _. +partial_zero_commit_rollbacks(C) -> + ID = configure_limit(?time_range_week(), ?global(), C), + Context0 = ?payproc_ctx_payment(?cash(10), ?cash(10)), + Context1 = ?payproc_ctx_payment(?cash(10), ?cash(0)), Change = ?LIMIT_CHANGE(ID), {ok, {vector, _}} = lim_client:hold(Change, Context0, ?config(client, C)), - {ok, {vector, _}} = lim_client:commit(Change, Context1, ?config(client, C)). + {ok, {vector, _}} = lim_client:commit(Change, Context1, ?config(client, C)), + % NOTE + % Successful rollback here means that partial commit with zero is handled exactly + % like rollback, thus subsequent rollback succeeds idempotently. This is a backwards + % compatibility measure. + {ok, {vector, _}} = lim_client:rollback(Change, Context0, ?config(client, C)). -spec refund_ok(config()) -> _. refund_ok(C) -> @@ -291,8 +250,8 @@ refund_ok(C) -> OwnerID = <<"WWWcool Ltd">>, ShopID = <<"shop">>, ID = configure_limit(?time_range_day(), ?scope([?scope_party(), ?scope_shop()]), C), - Context0 = ?ctx_invoice_payment(OwnerID, ShopID, ?cash(15), ?cash(15)), - RefundContext1 = ?ctx_invoice_payment_refund(OwnerID, ShopID, ?cash(10), ?cash(10), ?cash(10)), + Context0 = ?payproc_ctx_payment(OwnerID, ShopID, ?cash(15), ?cash(15)), + RefundContext1 = ?payproc_ctx_refund(OwnerID, ShopID, ?cash(10), ?cash(10), ?cash(10)), {ok, {vector, _}} = hold_and_commit(?LIMIT_CHANGE(ID, <<"Payment">>), Context0, Client), {ok, {vector, _}} = hold_and_commit(?LIMIT_CHANGE(ID, <<"Refund">>), RefundContext1, Client), {ok, #limiter_Limit{} = Limit2} = lim_client:get(ID, RefundContext1, Client), @@ -301,33 +260,33 @@ refund_ok(C) -> -spec get_config_ok(config()) -> _. get_config_ok(C) -> ID = configure_limit(?time_range_week(), ?global(), C), - {ok, #limiter_config_LimitConfig{}} = lim_client:get_config(ID, ?config(client, C)). + {ok, #config_LimitConfig{}} = lim_client:get_config(ID, ?config(client, C)). -spec commit_inexistent_hold_fails(config()) -> _. commit_inexistent_hold_fails(C) -> ID = configure_limit(?time_range_week(), ?global(), C), - Context = ?ctx_invoice_payment(?cash(42), undefined), + Context = ?payproc_ctx_payment(?cash(42), undefined), % NOTE % We do not expect `LimitChangeNotFound` here because we no longer reconcile with accounter % before requesting him to hold / commit. - {exception, #'InvalidRequest'{}} = + {exception, #base_InvalidRequest{}} = lim_client:commit(?LIMIT_CHANGE(ID), Context, ?config(client, C)). -spec partial_commit_inexistent_hold_fails(config()) -> _. partial_commit_inexistent_hold_fails(C) -> ID = configure_limit(?time_range_week(), ?global(), C), - Context = ?ctx_invoice_payment(?cash(42), ?cash(21)), + Context = ?payproc_ctx_payment(?cash(42), ?cash(21)), % NOTE % We do not expect `LimitChangeNotFound` here because we no longer reconcile with accounter % before requesting him to hold / commit. - {exception, #'InvalidRequest'{}} = + {exception, #base_InvalidRequest{}} = lim_client:commit(?LIMIT_CHANGE(ID), Context, ?config(client, C)). -spec commit_multirange_limit_ok(config()) -> _. commit_multirange_limit_ok(C) -> ID = ?config(id, C), Client = ?config(client, C), - Params = #limiter_config_LimitConfigParams{ + Params = #config_LimitConfigParams{ id = ID, started_at = <<"2000-01-01T00:00:00Z">>, shard_size = 12, @@ -335,30 +294,52 @@ commit_multirange_limit_ok(C) -> context_type = ?ctx_type_payproc(), type = ?lim_type_turnover(?turnover_metric_amount(<<"RUB">>)), scope = ?scope([]), - op_behaviour = #limiter_config_OperationLimitBehaviour{} + op_behaviour = #config_OperationLimitBehaviour{} }, {ok, _LimitConfig} = lim_client:create_config(Params, Client), % NOTE % Expecting those 3 changes will be accounted in the same limit range machine. % We have no way to verify it here though. - PaymentJan = #limiter_context_InvoicePayment{ - created_at = <<"2020-01-01T00:00:00Z">>, - cost = ?cash(42) - }, - {ok, _} = hold_and_commit(?LIMIT_CHANGE(ID, 1), ?ctx_invoice_payment(PaymentJan), Client), - PaymentFeb = #limiter_context_InvoicePayment{ - created_at = <<"2020-02-01T00:00:00Z">>, - cost = ?cash(43) - }, - {ok, _} = hold_and_commit(?LIMIT_CHANGE(ID, 2), ?ctx_invoice_payment(PaymentFeb), Client), - PaymentApr = #limiter_context_InvoicePayment{ - created_at = <<"2020-04-01T00:00:00Z">>, - cost = ?cash(44) - }, - {ok, _} = hold_and_commit(?LIMIT_CHANGE(ID, 3), ?ctx_invoice_payment(PaymentApr), Client), - {ok, #limiter_Limit{amount = 42}} = lim_client:get(ID, ?ctx_invoice_payment(PaymentJan), Client), - {ok, #limiter_Limit{amount = 43}} = lim_client:get(ID, ?ctx_invoice_payment(PaymentFeb), Client), - {ok, #limiter_Limit{amount = 44}} = lim_client:get(ID, ?ctx_invoice_payment(PaymentApr), Client). + PaymentJan = ?invoice_payment(?cash(42), ?cash(42), ?bank_card(), <<"2020-01-01T00:00:00Z">>), + {ok, _} = hold_and_commit(?LIMIT_CHANGE(ID, 1), ?payproc_ctx_payment(PaymentJan), Client), + PaymentFeb = ?invoice_payment(?cash(43), ?cash(43), ?bank_card(), <<"2020-02-01T00:00:00Z">>), + {ok, _} = hold_and_commit(?LIMIT_CHANGE(ID, 2), ?payproc_ctx_payment(PaymentFeb), Client), + PaymentApr = ?invoice_payment(?cash(44), ?cash(44), ?bank_card(), <<"2020-04-01T00:00:00Z">>), + {ok, _} = hold_and_commit(?LIMIT_CHANGE(ID, 3), ?payproc_ctx_payment(PaymentApr), Client), + {ok, #limiter_Limit{amount = 42}} = lim_client:get(ID, ?payproc_ctx_payment(PaymentJan), Client), + {ok, #limiter_Limit{amount = 43}} = lim_client:get(ID, ?payproc_ctx_payment(PaymentFeb), Client), + {ok, #limiter_Limit{amount = 44}} = lim_client:get(ID, ?payproc_ctx_payment(PaymentApr), Client). + +-spec commit_with_payment_tool_scope_ok(config()) -> _. +commit_with_payment_tool_scope_ok(C) -> + Client = ?config(client, C), + ID = configure_limit(?time_range_week(), ?scope([?scope_payment_tool()]), ?turnover_metric_number(), C), + Context1 = ?payproc_ctx_payment( + ?invoice_payment(?cash(10), ?cash(10), ?bank_card(<<"Token">>, 2, 2022)) + ), + Context2 = ?payproc_ctx_payment( + ?invoice_payment(?cash(10), ?cash(10), ?bank_card(<<"OtherToken">>, 2, 2022)) + ), + Context3 = ?payproc_ctx_payment( + ?invoice_payment(?cash(10), ?cash(10), ?bank_card(?string, 3, 2022)) + ), + Context4 = ?payproc_ctx_payment( + ?invoice_payment(?cash(10), ?cash(10), ?bank_card(?string)) + ), + Context5 = ?payproc_ctx_payment( + ?invoice_payment(?cash(10), ?cash(10), ?digital_wallet(<<"ID42">>, <<"Pepal">>)) + ), + {ok, LimitState0} = lim_client:get(ID, Context1, Client), + _ = hold_and_commit(?LIMIT_CHANGE(ID, 1), Context1, Client), + _ = hold_and_commit(?LIMIT_CHANGE(ID, 2), Context2, Client), + _ = hold_and_commit(?LIMIT_CHANGE(ID, 3), Context3, Client), + _ = hold_and_commit(?LIMIT_CHANGE(ID, 4), Context4, Client), + _ = hold_and_commit(?LIMIT_CHANGE(ID, 5), Context5, Client), + {ok, LimitState1} = lim_client:get(ID, Context1, Client), + ?assertEqual( + LimitState1#limiter_Limit.amount, + LimitState0#limiter_Limit.amount + 1 + ). %% @@ -366,7 +347,7 @@ commit_multirange_limit_ok(C) -> commit_processes_idempotently(C) -> Client = ?config(client, C), ID = configure_limit(?time_range_week(), ?global(), C), - Context = ?ctx_invoice_payment(?cash(42), undefined), + Context = ?payproc_ctx_payment(?cash(42), undefined), Change = ?LIMIT_CHANGE(ID), {ok, _} = lim_client:hold(Change, Context, Client), {ok, _} = lim_client:hold(Change, Context, Client), @@ -380,7 +361,7 @@ full_commit_processes_idempotently(C) -> Client = ?config(client, C), ID = configure_limit(?time_range_week(), ?global(), C), Cost = ?cash(42), - Context = ?ctx_invoice_payment(Cost, Cost), + Context = ?payproc_ctx_payment(Cost, Cost), Change = ?LIMIT_CHANGE(ID), {ok, _} = lim_client:hold(Change, Context, Client), {ok, _} = lim_client:hold(Change, Context, Client), @@ -393,7 +374,7 @@ full_commit_processes_idempotently(C) -> partial_commit_processes_idempotently(C) -> Client = ?config(client, C), ID = configure_limit(?time_range_week(), ?global(), C), - Context = ?ctx_invoice_payment(?cash(42), ?cash(40)), + Context = ?payproc_ctx_payment(?cash(42), ?cash(40)), Change = ?LIMIT_CHANGE(ID), {ok, _} = lim_client:hold(Change, Context, Client), {ok, _} = lim_client:hold(Change, Context, Client), @@ -406,7 +387,7 @@ partial_commit_processes_idempotently(C) -> rollback_processes_idempotently(C) -> Client = ?config(client, C), ID = configure_limit(?time_range_week(), ?global(), C), - Context = ?ctx_invoice_payment(?cash(42), ?cash(0)), + Context = ?payproc_ctx_payment(?cash(42), ?cash(0)), Change = ?LIMIT_CHANGE(ID), {ok, _} = lim_client:hold(Change, Context, Client), {ok, _} = lim_client:hold(Change, Context, Client), @@ -421,7 +402,7 @@ rollback_processes_idempotently(C) -> commit_number_ok(C) -> Client = ?config(client, C), ID = configure_limit(?time_range_week(), ?global(), ?turnover_metric_number(), C), - Context = ?ctx_invoice_payment(?cash(10), ?cash(10)), + Context = ?payproc_ctx_payment(?cash(10), ?cash(10)), {ok, LimitState0} = lim_client:get(ID, Context, Client), _ = hold_and_commit(?LIMIT_CHANGE(ID), Context, Client), {ok, LimitState1} = lim_client:get(ID, Context, Client), @@ -434,8 +415,8 @@ commit_number_ok(C) -> rollback_number_ok(C) -> Client = ?config(client, C), ID = configure_limit(?time_range_week(), ?global(), ?turnover_metric_number(), C), - Context = ?ctx_invoice_payment(?cash(10), ?cash(10)), - ContextRollback = ?ctx_invoice_payment(?cash(10), ?cash(0)), + Context = ?payproc_ctx_payment(?cash(10), ?cash(10)), + ContextRollback = ?payproc_ctx_payment(?cash(10), ?cash(0)), {ok, LimitState0} = lim_client:get(ID, Context, Client), _ = hold_and_commit(?LIMIT_CHANGE(ID), Context, ContextRollback, Client), {ok, LimitState1} = lim_client:get(ID, Context, Client), @@ -451,8 +432,8 @@ commit_refund_keep_number_unchanged(C) -> Cost = ?cash(10), CaptureCost = ?cash(8), RefundCost = ?cash(5), - PaymentContext = ?ctx_invoice_payment(<<"OWNER">>, <<"SHOP">>, Cost, CaptureCost), - RefundContext = ?ctx_invoice_payment_refund(<<"OWNER">>, <<"SHOP">>, Cost, CaptureCost, RefundCost), + PaymentContext = ?payproc_ctx_payment(<<"OWNER">>, <<"SHOP">>, Cost, CaptureCost), + RefundContext = ?payproc_ctx_refund(<<"OWNER">>, <<"SHOP">>, Cost, CaptureCost, RefundCost), {ok, LimitState0} = lim_client:get(ID, PaymentContext, Client), _ = hold_and_commit(?LIMIT_CHANGE(ID, 1), PaymentContext, Client), _ = hold_and_commit(?LIMIT_CHANGE(ID, 2), RefundContext, Client), @@ -467,8 +448,8 @@ commit_refund_keep_number_unchanged(C) -> partial_commit_number_counts_as_single_op(C) -> Client = ?config(client, C), ID = configure_limit(?time_range_week(), ?global(), ?turnover_metric_number(), C), - Context = ?ctx_invoice_payment(?cash(10), ?cash(10)), - ContextPartial = ?ctx_invoice_payment(?cash(10), ?cash(5)), + Context = ?payproc_ctx_payment(?cash(10), ?cash(10)), + ContextPartial = ?payproc_ctx_payment(?cash(10), ?cash(5)), {ok, LimitState0} = lim_client:get(ID, Context, Client), _ = hold_and_commit(?LIMIT_CHANGE(ID), Context, ContextPartial, Client), {ok, LimitState1} = lim_client:get(ID, Context, Client), @@ -479,79 +460,6 @@ partial_commit_number_counts_as_single_op(C) -> %% --spec payproc_hold_ok(config()) -> _. -payproc_hold_ok(C) -> - ID = configure_limit(?time_range_month(), ?global(), C), - Context = ?payproc_ctx_invoice(?cash(10)), - {ok, {vector, #limiter_VectorClock{}}} = lim_client:hold(?LIMIT_CHANGE(ID), Context, ?config(client, C)), - {ok, #limiter_Limit{}} = lim_client:get(ID, Context, ?config(client, C)). - --spec payproc_commit_ok(config()) -> _. -payproc_commit_ok(C) -> - ID = configure_limit(?time_range_year(), ?global(), C), - Context = ?payproc_ctx_invoice(?cash(10)), - {ok, {vector, _}} = hold_and_commit(?LIMIT_CHANGE(ID), Context, ?config(client, C)), - {ok, #limiter_Limit{}} = lim_client:get(ID, Context, ?config(client, C)). - --spec payproc_rollback_ok(config()) -> _. -payproc_rollback_ok(C) -> - ID = configure_limit(?time_range_week(), ?global(), C), - Context0 = ?payproc_ctx_invoice_payment(?cash(10), ?cash(10)), - Context1 = ?payproc_ctx_invoice_payment(?cash(10), ?cash(0)), - Change = ?LIMIT_CHANGE(ID), - {ok, {vector, _}} = lim_client:hold(Change, Context0, ?config(client, C)), - {ok, {vector, _}} = lim_client:commit(Change, Context1, ?config(client, C)). - --spec payproc_refund_ok(config()) -> _. -payproc_refund_ok(C) -> - Client = ?config(client, C), - OwnerID = <<"WWWcool Ltd">>, - ShopID = <<"shop">>, - ID = configure_limit(?time_range_day(), ?scope([?scope_party(), ?scope_shop()]), C), - Context0 = ?payproc_ctx_invoice_payment(OwnerID, ShopID, ?cash(15), ?cash(15)), - RefundContext1 = ?payproc_ctx_invoice_payment_refund(OwnerID, ShopID, ?cash(10), ?cash(10), ?cash(10)), - {ok, {vector, _}} = hold_and_commit(?LIMIT_CHANGE(ID, <<"Payment">>), Context0, Client), - {ok, {vector, _}} = hold_and_commit(?LIMIT_CHANGE(ID, <<"Refund">>), RefundContext1, Client), - {ok, #limiter_Limit{} = Limit2} = lim_client:get(ID, RefundContext1, Client), - ?assertEqual(Limit2#limiter_Limit.amount, 5). - --spec payproc_commit_with_payment_tool_scope_ok(config()) -> _. -payproc_commit_with_payment_tool_scope_ok(C) -> - Client = ?config(client, C), - ID = configure_limit(?time_range_week(), ?scope([?scope_payment_tool()]), ?turnover_metric_number(), C), - Context0 = ?payproc_ctx_invoice_payment( - ?payproc_invoice_payment( - ?cash(10), - ?cash(10), - {bank_card, ?payproc_bank_card()} - ) - ), - Context1 = ?payproc_ctx_invoice_payment( - ?payproc_invoice_payment( - ?cash(10), - ?cash(10), - {bank_card, ?payproc_bank_card(<<"OtherToken">>, 2, 2022)} - ) - ), - Context2 = ?payproc_ctx_invoice_payment( - ?payproc_invoice_payment( - ?cash(10), - ?cash(10), - {bank_card, ?payproc_bank_card(?string, 3, 2022)} - ) - ), - {ok, LimitState0} = lim_client:get(ID, Context0, Client), - _ = hold_and_commit(?LIMIT_CHANGE(ID, 1), Context0, Client), - _ = hold_and_commit(?LIMIT_CHANGE(ID, 2), Context1, Client), - _ = hold_and_commit(?LIMIT_CHANGE(ID, 3), Context2, Client), - {ok, LimitState1} = lim_client:get(ID, Context0, Client), - ?assertEqual( - LimitState1#limiter_Limit.amount, - LimitState0#limiter_Limit.amount + 1 - ). - -%% - gen_change_id(LimitID, ChangeID) -> genlib:format("~s/~p", [LimitID, ChangeID]). @@ -570,14 +478,19 @@ configure_limit(TimeRange, Scope, C) -> configure_limit(TimeRange, Scope, Metric, C) -> ID = ?config(id, C), - Params = #limiter_config_LimitConfigParams{ + ContextType = + case get_group_name(C) of + withdrawals -> ?ctx_type_wthdproc(); + _Default -> ?ctx_type_payproc() + end, + Params = #config_LimitConfigParams{ id = ID, started_at = <<"2000-01-01T00:00:00Z">>, time_range_type = TimeRange, shard_size = 1, type = ?lim_type_turnover(Metric), scope = Scope, - context_type = ?ctx_type_payproc(), + context_type = ContextType, op_behaviour = ?op_behaviour(?op_subtraction()) }, {ok, _LimitConfig} = lim_client:create_config(Params, ?config(client, C)), @@ -585,3 +498,7 @@ configure_limit(TimeRange, Scope, Metric, C) -> gen_unique_id(Prefix) -> genlib:format("~s/~B", [Prefix, lim_time:now()]). + +get_group_name(C) -> + GroupProps = ?config(tc_group_properties, C), + proplists:get_value(name, GroupProps). diff --git a/rebar.config b/rebar.config index 80ddc11..5809961 100644 --- a/rebar.config +++ b/rebar.config @@ -26,7 +26,6 @@ %% Common project dependencies. {deps, [ - {damsel, {git, "https://github.com/valitydev/damsel.git", {branch, "master"}}}, {limiter_proto, {git, "https://github.com/valitydev/limiter-proto.git", {branch, "master"}}}, {xrates_proto, {git, "https://github.com/valitydev/xrates-proto.git", {branch, "master"}}}, {machinery, {git, "https://github.com/valitydev/machinery-erlang.git", {branch, "master"}}}, diff --git a/rebar.lock b/rebar.lock index a8ad132..3de7d89 100644 --- a/rebar.lock +++ b/rebar.lock @@ -9,8 +9,8 @@ {<<"cowlib">>,{pkg,<<"cowlib">>,<<"2.11.0">>},2}, {<<"damsel">>, {git,"https://github.com/valitydev/damsel.git", - {ref,"1d60b20f2136938c43902dd38a80ae70f03e4a14"}}, - 0}, + {ref,"33c5665571042440ccec109735481d8c13704ec2"}}, + 1}, {<<"erl_health">>, {git,"https://github.com/valitydev/erlang-health.git", {ref,"5958e2f35cd4d09f40685762b82b82f89b4d9333"}}, @@ -25,16 +25,16 @@ {<<"jsx">>,{pkg,<<"jsx">>,<<"3.1.0">>},1}, {<<"limiter_proto">>, {git,"https://github.com/valitydev/limiter-proto.git", - {ref,"ac9705389211682263c0a983ae76f663d4857ec9"}}, + {ref,"61581846b4d41de3a9e561c79f558e74450ab950"}}, 0}, {<<"machinery">>, {git,"https://github.com/valitydev/machinery-erlang.git", - {ref,"ff4cfefb616250f6905c25e79f74a7a30eb1aae5"}}, + {ref,"62c32434c80a462956ad9d50f9bce47836580d77"}}, 0}, {<<"metrics">>,{pkg,<<"metrics">>,<<"1.0.1">>},2}, {<<"mg_proto">>, {git,"https://github.com/valitydev/machinegun-proto.git", - {ref,"b43d6fd0939ee4029ec8873dbd16f3c5fbe4a95c"}}, + {ref,"347c5c44c8dcca24a50e0509c0df5401f863e790"}}, 1}, {<<"mimerl">>,{pkg,<<"mimerl">>,<<"1.2.0">>},2}, {<<"parse_trans">>,{pkg,<<"parse_trans">>,<<"3.3.1">>},2},