mirror of
https://github.com/valitydev/limiter.git
synced 2024-11-06 00:55:22 +00:00
Merge pull request #5 from rbkmoney/ED-181/ft/subtraction_behaviour
ED-181: add subtraction behaviour
This commit is contained in:
commit
886acc0503
@ -6,6 +6,8 @@
|
||||
-export([unmarshal/2]).
|
||||
-export([marshal_config/1]).
|
||||
-export([unmarshal_body_type/1]).
|
||||
-export([unmarshal_op_behaviour/1]).
|
||||
-export([maybe_apply/2]).
|
||||
|
||||
%% Types
|
||||
|
||||
@ -17,6 +19,7 @@
|
||||
-type decoded_value() :: decoded_value(any()).
|
||||
-type decoded_value(T) :: T.
|
||||
|
||||
-spec maybe_apply(any(), function()) -> any().
|
||||
maybe_apply(undefined, _) ->
|
||||
undefined;
|
||||
maybe_apply(Value, Fun) ->
|
||||
@ -59,9 +62,21 @@ marshal_config(Config) ->
|
||||
time_range_type = marshal_time_range_type(lim_config_machine:time_range_type(Config)),
|
||||
context_type = marshal_context_type(lim_config_machine:context_type(Config)),
|
||||
type = maybe_apply(lim_config_machine:type(Config), fun marshal_type/1),
|
||||
scope = maybe_apply(lim_config_machine:scope(Config), fun marshal_scope/1)
|
||||
scope = maybe_apply(lim_config_machine:scope(Config), fun marshal_scope/1),
|
||||
op_behaviour = maybe_apply(lim_config_machine:op_behaviour(Config), fun marshal_op_behaviour/1)
|
||||
}.
|
||||
|
||||
marshal_op_behaviour(OpBehaviour) ->
|
||||
PaymentRefund = maps:get(invoice_payment_refund, OpBehaviour, undefined),
|
||||
#limiter_config_OperationLimitBehaviour{
|
||||
invoice_payment_refund = maybe_apply(PaymentRefund, fun marshal_behaviour/1)
|
||||
}.
|
||||
|
||||
marshal_behaviour(subtraction) ->
|
||||
{subtraction, #limiter_config_Subtraction{}};
|
||||
marshal_behaviour(addition) ->
|
||||
{addition, #limiter_config_Addition{}}.
|
||||
|
||||
marshal_body_type(amount) ->
|
||||
{amount, #limiter_config_LimitBodyTypeAmount{}};
|
||||
marshal_body_type({cash, Currency}) ->
|
||||
@ -139,7 +154,8 @@ unmarshal_config(#limiter_config_LimitConfig{
|
||||
time_range_type = TimeRangeType,
|
||||
context_type = ContextType,
|
||||
type = Type,
|
||||
scope = Scope
|
||||
scope = Scope,
|
||||
op_behaviour = OpBehaviour
|
||||
}) ->
|
||||
genlib_map:compact(#{
|
||||
id => ID,
|
||||
@ -152,9 +168,24 @@ unmarshal_config(#limiter_config_LimitConfig{
|
||||
context_type => unmarshal_context_type(ContextType),
|
||||
type => maybe_apply(Type, fun unmarshal_type/1),
|
||||
scope => maybe_apply(Scope, fun unmarshal_scope/1),
|
||||
description => Description
|
||||
description => Description,
|
||||
op_behaviour => maybe_apply(OpBehaviour, fun unmarshal_op_behaviour/1)
|
||||
}).
|
||||
|
||||
-spec unmarshal_op_behaviour(encoded_value()) -> decoded_value().
|
||||
unmarshal_op_behaviour(OpBehaviour) ->
|
||||
#limiter_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{}}) ->
|
||||
subtraction;
|
||||
unmarshal_behaviour({addition, #limiter_config_Addition{}}) ->
|
||||
addition.
|
||||
|
||||
-spec unmarshal_body_type(encoded_value()) -> decoded_value().
|
||||
unmarshal_body_type({amount, #limiter_config_LimitBodyTypeAmount{}}) ->
|
||||
amount;
|
||||
|
@ -16,6 +16,7 @@
|
||||
-export([type/1]).
|
||||
-export([scope/1]).
|
||||
-export([context_type/1]).
|
||||
-export([op_behaviour/1]).
|
||||
|
||||
%% API
|
||||
|
||||
@ -62,7 +63,8 @@
|
||||
context_type := context_type(),
|
||||
type => limit_type(),
|
||||
scope => limit_scope(),
|
||||
description => description()
|
||||
description => description(),
|
||||
op_behaviour => op_behaviour()
|
||||
}.
|
||||
|
||||
-type create_params() :: #{
|
||||
@ -74,9 +76,13 @@
|
||||
context_type := context_type(),
|
||||
type => limit_type(),
|
||||
scope => limit_scope(),
|
||||
description => description()
|
||||
description => description(),
|
||||
op_behaviour => op_behaviour()
|
||||
}.
|
||||
|
||||
-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'().
|
||||
@ -209,6 +215,12 @@ scope(_) ->
|
||||
context_type(#{context_type := Value}) ->
|
||||
Value.
|
||||
|
||||
-spec op_behaviour(config()) -> lim_maybe:maybe(op_behaviour()).
|
||||
op_behaviour(#{op_behaviour := Value}) ->
|
||||
Value;
|
||||
op_behaviour(_) ->
|
||||
undefined.
|
||||
|
||||
%%
|
||||
|
||||
-spec start(lim_id(), create_params(), lim_context()) -> {ok, config()}.
|
||||
|
@ -30,7 +30,8 @@ handle_function_(
|
||||
name = Name,
|
||||
description = Description,
|
||||
started_at = StartedAt,
|
||||
body_type = BodyType
|
||||
body_type = BodyType,
|
||||
op_behaviour = OpBehaviour
|
||||
}},
|
||||
LimitContext,
|
||||
_Opts
|
||||
@ -39,11 +40,15 @@ handle_function_(
|
||||
{ok, Config} ->
|
||||
{ok, LimitConfig} = lim_config_machine:start(
|
||||
ID,
|
||||
Config#{
|
||||
genlib_map:compact(Config#{
|
||||
description => Description,
|
||||
started_at => StartedAt,
|
||||
body_type => lim_config_codec:unmarshal_body_type(BodyType)
|
||||
},
|
||||
body_type => lim_config_codec:unmarshal_body_type(BodyType),
|
||||
op_behaviour => lim_config_codec:maybe_apply(
|
||||
OpBehaviour,
|
||||
fun lim_config_codec:unmarshal_op_behaviour/1
|
||||
)
|
||||
}),
|
||||
LimitContext
|
||||
),
|
||||
{ok, lim_config_codec:marshal_config(LimitConfig)};
|
||||
@ -67,7 +72,7 @@ mk_limit_config(<<"ShopDayTurnover">>) ->
|
||||
processor_type => <<"TurnoverProcessor">>,
|
||||
type => turnover,
|
||||
scope => {scope, shop},
|
||||
shard_size => 12,
|
||||
shard_size => 7,
|
||||
context_type => payment_processing,
|
||||
time_range_type => {calendar, day}
|
||||
}};
|
||||
|
@ -84,7 +84,8 @@ hold(LimitChange = #limiter_LimitChange{id = LimitID}, Config = #{body_type := B
|
||||
{ok, #{account_id_from := AccountIDFrom, account_id_to := AccountIDTo}} =
|
||||
lim_range_machine:ensure_range_exist_in_state(TimeRange, LimitRangeState, LimitContext),
|
||||
Postings = lim_p_transfer:construct_postings(AccountIDFrom, AccountIDTo, Body),
|
||||
lim_accounting:hold(construct_plan_id(LimitChange), {1, Postings}, LimitContext)
|
||||
Postings1 = apply_op_behaviour(Postings, LimitContext, Config),
|
||||
lim_accounting:hold(construct_plan_id(LimitChange), {1, Postings1}, LimitContext)
|
||||
end).
|
||||
|
||||
-spec commit(lim_change(), config(), lim_context()) -> ok | {error, commit_error()}.
|
||||
@ -130,16 +131,27 @@ partial_commit(PartialBody, LimitChange = #limiter_LimitChange{id = LimitID}, Co
|
||||
TimeRange = lim_config_machine:calculate_time_range(Timestamp, Config),
|
||||
{ok, #{account_id_from := AccountIDFrom, account_id_to := AccountIDTo}} =
|
||||
lim_range_machine:get_range(TimeRange, LimitRangeState),
|
||||
|
||||
PartialPostings = lim_p_transfer:construct_postings(AccountIDFrom, AccountIDTo, PartialBody),
|
||||
FullPostings = lim_p_transfer:construct_postings(AccountIDFrom, AccountIDTo, FullBody),
|
||||
NewBatchList = [{2, lim_p_transfer:reverse_postings(FullPostings)} | [{3, PartialPostings}]],
|
||||
|
||||
PartialPostings0 = lim_p_transfer:construct_postings(AccountIDFrom, AccountIDTo, PartialBody),
|
||||
FullPostings0 = lim_p_transfer:construct_postings(AccountIDFrom, AccountIDTo, FullBody),
|
||||
PartialPostings1 = apply_op_behaviour(PartialPostings0, LimitContext, Config),
|
||||
FullPostings1 = apply_op_behaviour(FullPostings0, LimitContext, Config),
|
||||
NewBatchList = [{2, lim_p_transfer:reverse_postings(FullPostings1)} | [{3, PartialPostings1}]],
|
||||
PlanID = construct_plan_id(LimitChange),
|
||||
unwrap(lim_accounting:plan(PlanID, NewBatchList, LimitContext)),
|
||||
unwrap(lim_accounting:commit(PlanID, [{1, FullPostings} | NewBatchList], LimitContext))
|
||||
unwrap(lim_accounting:commit(PlanID, [{1, FullPostings1} | NewBatchList], LimitContext))
|
||||
end).
|
||||
|
||||
apply_op_behaviour(Posting, LimitContext, #{op_behaviour := ComputationConfig}) ->
|
||||
{ok, Operation} = lim_context:get_operation(payment_processing, LimitContext),
|
||||
case maps:get(Operation, ComputationConfig, undefined) of
|
||||
subtraction ->
|
||||
lim_p_transfer:reverse_postings(Posting);
|
||||
Type when Type =:= undefined orelse Type =:= additional ->
|
||||
Posting
|
||||
end;
|
||||
apply_op_behaviour(Body, _LimitContext, _Config) ->
|
||||
Body.
|
||||
|
||||
assert_partial_body(
|
||||
{cash, #{amount := Partial, currency := Currency}},
|
||||
{cash, #{amount := Full, currency := Currency}}
|
||||
|
47
apps/limiter/test/lim_ct_helper.hrl
Normal file
47
apps/limiter/test/lim_ct_helper.hrl
Normal file
@ -0,0 +1,47 @@
|
||||
-ifndef(__limiter_ct_helper__).
|
||||
-define(__limiter_ct_helper__, 42).
|
||||
|
||||
-include_lib("limiter_proto/include/lim_configurator_thrift.hrl").
|
||||
|
||||
-define(cash(Amount), #limiter_base_Cash{
|
||||
amount = Amount,
|
||||
currency = #limiter_base_CurrencyRef{symbolic_code = <<"RUB">>}
|
||||
}).
|
||||
|
||||
-define(ctx_invoice_payment(Cost, CaptureCost), ?ctx_invoice_payment(undefined, undefined, Cost, CaptureCost)).
|
||||
|
||||
-define(ctx_invoice_payment(OwnerID, ShopID, Cost, CaptureCost), #limiter_context_LimitContext{
|
||||
payment_processing = #limiter_context_ContextPaymentProcessing{
|
||||
op = {invoice_payment, #limiter_context_PaymentProcessingOperationInvoicePayment{}},
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}).
|
||||
|
||||
-define(ctx_invoice_payment_refund(OwnerID, ShopID, Cost, CaptureCost, RefundCost), #limiter_context_LimitContext{
|
||||
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">>
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}).
|
||||
|
||||
-endif.
|
@ -2,6 +2,7 @@
|
||||
|
||||
-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").
|
||||
@ -22,6 +23,7 @@
|
||||
-export([hold_ok/1]).
|
||||
-export([commit_ok/1]).
|
||||
-export([rollback_ok/1]).
|
||||
-export([refund_ok/1]).
|
||||
-export([get_config_ok/1]).
|
||||
|
||||
-type test_case_name() :: atom().
|
||||
@ -48,7 +50,8 @@ groups() ->
|
||||
hold_ok,
|
||||
commit_ok,
|
||||
rollback_ok,
|
||||
get_config_ok
|
||||
get_config_ok,
|
||||
refund_ok
|
||||
]}
|
||||
].
|
||||
|
||||
@ -266,32 +269,45 @@ commit_ok(C) ->
|
||||
rollback_ok(C) ->
|
||||
ID = <<"ID">>,
|
||||
#{client := Client} = prepare_environment(ID, <<"GlobalMonthTurnover">>, C),
|
||||
Context = #limiter_context_LimitContext{
|
||||
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 = #limiter_base_Cash{
|
||||
amount = 10,
|
||||
currency = #limiter_base_CurrencyRef{symbolic_code = <<"RUB">>}
|
||||
},
|
||||
capture_cost = #limiter_base_Cash{
|
||||
amount = 0,
|
||||
currency = #limiter_base_CurrencyRef{symbolic_code = <<"RUB">>}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
Context0 = ?ctx_invoice_payment(?cash(10), ?cash(10)),
|
||||
Context1 = ?ctx_invoice_payment(?cash(10), ?cash(0)),
|
||||
|
||||
Timestamp = lim_time:to_rfc3339(lim_time:now()),
|
||||
LimitChangeID = <<Timestamp/binary, "Rollback">>,
|
||||
Change = #limiter_LimitChange{
|
||||
id = ID,
|
||||
change_id = LimitChangeID
|
||||
},
|
||||
{ok, {vector, _}} = hold_and_commit(Change, Context, Client),
|
||||
{ok, #limiter_Limit{}} = lim_client:get(ID, Context, Client).
|
||||
{ok, {vector, _}} = lim_client:hold(Change, Context0, Client),
|
||||
{ok, {vector, _}} = lim_client:commit(Change, Context1, Client).
|
||||
|
||||
-spec refund_ok(config()) -> _.
|
||||
refund_ok(C) ->
|
||||
ID = lim_time:to_rfc3339(lim_time:now()),
|
||||
OwnerID = <<"WWWcool Ltd">>,
|
||||
ShopID = <<"shop">>,
|
||||
#{client := Client} = _LimitConfig = prepare_environment(ID, <<"ShopDayTurnover">>, C),
|
||||
Context0 = ?ctx_invoice_payment(OwnerID, ShopID, ?cash(15), ?cash(15)),
|
||||
RefundContext1 = ?ctx_invoice_payment_refund(OwnerID, ShopID, ?cash(10), ?cash(10), ?cash(10)),
|
||||
Timestamp = lim_time:to_rfc3339(lim_time:now()),
|
||||
LimitChangeID = <<Timestamp/binary, "Payment">>,
|
||||
|
||||
Change = #limiter_LimitChange{
|
||||
id = ID,
|
||||
change_id = LimitChangeID
|
||||
},
|
||||
{ok, {vector, _}} = hold_and_commit(Change, Context0, Client),
|
||||
|
||||
Timestamp2 = lim_time:to_rfc3339(lim_time:now()),
|
||||
LimitChangeID2 = <<Timestamp2/binary, "Refund">>,
|
||||
Change2 = #limiter_LimitChange{
|
||||
id = ID,
|
||||
change_id = LimitChangeID2
|
||||
},
|
||||
|
||||
{ok, {vector, _}} = hold_and_commit(Change2, RefundContext1, Client),
|
||||
{ok, #limiter_Limit{} = Limit2} = lim_client:get(ID, RefundContext1, Client),
|
||||
?assertEqual(Limit2#limiter_Limit.amount, 5).
|
||||
|
||||
-spec get_config_ok(config()) -> _.
|
||||
get_config_ok(C) ->
|
||||
@ -315,7 +331,10 @@ prepare_environment(ID, LimitName, _C) ->
|
||||
name = LimitName,
|
||||
description = <<"description">>,
|
||||
started_at = <<"2000-01-01T00:00:00Z">>,
|
||||
body_type = {cash, #limiter_config_LimitBodyTypeCash{currency = <<"RUB">>}}
|
||||
body_type = {cash, #limiter_config_LimitBodyTypeCash{currency = <<"RUB">>}},
|
||||
op_behaviour = #limiter_config_OperationLimitBehaviour{
|
||||
invoice_payment_refund = {subtraction, #limiter_config_Subtraction{}}
|
||||
}
|
||||
},
|
||||
{ok, LimitConfig} = lim_client:create_config(Params, Client),
|
||||
#{config => LimitConfig, client => Client}.
|
||||
|
@ -35,7 +35,7 @@
|
||||
{<<"jsx">>,{pkg,<<"jsx">>,<<"3.0.0">>},1},
|
||||
{<<"limiter_proto">>,
|
||||
{git,"git@github.com:rbkmoney/limiter-proto.git",
|
||||
{ref,"d4b40ead589dd4dbd9d442397239c635d2a8382e"}},
|
||||
{ref,"9c0653ff7281ff443f515d2fddf9673fe837a5be"}},
|
||||
0},
|
||||
{<<"machinery">>,
|
||||
{git,"https://github.com/rbkmoney/machinery.git",
|
||||
|
Loading…
Reference in New Issue
Block a user