mirror of
https://github.com/valitydev/limiter.git
synced 2024-11-06 00:55:22 +00:00
TD-329: Add withdrawal context support (#12)
* Bump to valitydev/machinery-erlang@62c3243 * Bump to valitydev/machinegun-proto@347c5c4 * Drop top-level `damsel` dependency * Drop `get_rate` testcase as meaningless * Drop testcases which became duplicate * Support new context type @ config * Delegate context accessors to specific modules * Support rollbacks @ valitydev/limiter-proto@6158184
This commit is contained in:
parent
2dff7b518d
commit
618a751712
4
.env
4
.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
|
||||
|
@ -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).
|
||||
|
@ -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}) ->
|
||||
|
@ -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{}}
|
||||
}
|
||||
}}
|
||||
)
|
||||
|
@ -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) ->
|
||||
<<Acc/binary, "/", Fragment/binary>>.
|
||||
|
||||
-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, <<Token/binary, "/", ExpData/binary>>};
|
||||
_ ->
|
||||
{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)
|
||||
)
|
||||
].
|
||||
|
||||
|
@ -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),
|
||||
|
@ -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">>) ->
|
||||
|
@ -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}.
|
||||
|
@ -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}
|
||||
}
|
||||
|
@ -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).
|
@ -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),
|
||||
<<BinaryMonth/binary, "/", BinaryYear/binary>>.
|
||||
-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.
|
||||
|
48
apps/limiter/src/lim_payproc_utils.erl
Normal file
48
apps/limiter/src/lim_payproc_utils.erl
Normal file
@ -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.
|
@ -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;
|
||||
|
@ -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),
|
||||
|
@ -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,
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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.
|
||||
|
73
apps/limiter/src/lim_wthdproc_context.erl
Normal file
73
apps/limiter/src/lim_wthdproc_context.erl
Normal file
@ -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}.
|
@ -5,7 +5,6 @@
|
||||
{applications, [
|
||||
kernel,
|
||||
stdlib,
|
||||
damsel,
|
||||
limiter_proto,
|
||||
xrates_proto,
|
||||
machinery,
|
||||
|
@ -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}
|
||||
}
|
||||
].
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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">>,
|
||||
|
@ -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.
|
||||
|
@ -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).
|
||||
|
@ -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"}}},
|
||||
|
10
rebar.lock
10
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},
|
||||
|
Loading…
Reference in New Issue
Block a user