TD-305: Add new payproc context and payment tool scope implementetion (#9)

* updated limiter proto

* added payproc context

* fixed linter

* bumped proto

* added base tests

* added payment tool tests

* added minor test

* fixed dialyzer

* fixed
This commit is contained in:
Артем 2022-06-20 15:53:54 +03:00 committed by GitHub
parent d36b97f44a
commit 2dff7b518d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 654 additions and 190 deletions

View File

@ -8,7 +8,7 @@
currency := currency() currency := currency()
}. }.
-type currency() :: lim_base_thrift:'CurrencySymbolicCode'(). -type currency() :: lim_domain_thrift:'CurrencySymbolicCode'().
-type config() :: lim_config_machine:config(). -type config() :: lim_config_machine:config().
-type body_type() :: full | partial. -type body_type() :: full | partial.

View File

@ -85,16 +85,16 @@ marshal_behaviour(addition) ->
marshal_time_range_type({calendar, CalendarType}) -> marshal_time_range_type({calendar, CalendarType}) ->
{calendar, marshal_calendar_time_range_type(CalendarType)}; {calendar, marshal_calendar_time_range_type(CalendarType)};
marshal_time_range_type({interval, Amount}) -> marshal_time_range_type({interval, Amount}) ->
{interval, #time_range_TimeRangeTypeInterval{amount = Amount}}. {interval, #limiter_time_range_TimeRangeTypeInterval{amount = Amount}}.
marshal_calendar_time_range_type(day) -> marshal_calendar_time_range_type(day) ->
{day, #time_range_TimeRangeTypeCalendarDay{}}; {day, #limiter_time_range_TimeRangeTypeCalendarDay{}};
marshal_calendar_time_range_type(week) -> marshal_calendar_time_range_type(week) ->
{week, #time_range_TimeRangeTypeCalendarWeek{}}; {week, #limiter_time_range_TimeRangeTypeCalendarWeek{}};
marshal_calendar_time_range_type(month) -> marshal_calendar_time_range_type(month) ->
{month, #time_range_TimeRangeTypeCalendarMonth{}}; {month, #limiter_time_range_TimeRangeTypeCalendarMonth{}};
marshal_calendar_time_range_type(year) -> marshal_calendar_time_range_type(year) ->
{year, #time_range_TimeRangeTypeCalendarYear{}}. {year, #limiter_time_range_TimeRangeTypeCalendarYear{}}.
marshal_context_type(payment_processing) -> marshal_context_type(payment_processing) ->
{payment_processing, #limiter_config_LimitContextTypePaymentProcessing{}}. {payment_processing, #limiter_config_LimitContextTypePaymentProcessing{}}.
@ -235,7 +235,7 @@ unmarshal_body_type_deprecated({cash, #limiter_config_LimitBodyTypeCash{currency
unmarshal_time_range_type({calendar, CalendarType}) -> unmarshal_time_range_type({calendar, CalendarType}) ->
{calendar, unmarshal_calendar_time_range_type(CalendarType)}; {calendar, unmarshal_calendar_time_range_type(CalendarType)};
unmarshal_time_range_type({interval, #time_range_TimeRangeTypeInterval{amount = Amount}}) -> unmarshal_time_range_type({interval, #limiter_time_range_TimeRangeTypeInterval{amount = Amount}}) ->
{interval, Amount}. {interval, Amount}.
unmarshal_calendar_time_range_type({day, _}) -> unmarshal_calendar_time_range_type({day, _}) ->
@ -308,7 +308,7 @@ unmarshal_created_w_deprecated_body_type_test_() ->
created_at = lim_time:to_rfc3339(Now), created_at = lim_time:to_rfc3339(Now),
started_at = <<"2000-01-01T00:00:00Z">>, started_at = <<"2000-01-01T00:00:00Z">>,
shard_size = 42, shard_size = 42,
time_range_type = {calendar, {day, #time_range_TimeRangeTypeCalendarDay{}}}, time_range_type = {calendar, {day, #limiter_time_range_TimeRangeTypeCalendarDay{}}},
context_type = {payment_processing, #limiter_config_LimitContextTypePaymentProcessing{}}, context_type = {payment_processing, #limiter_config_LimitContextTypePaymentProcessing{}},
body_type_deprecated = {cash, #limiter_config_LimitBodyTypeCash{currency = <<"☭☭☭"/utf8>>}} body_type_deprecated = {cash, #limiter_config_LimitBodyTypeCash{currency = <<"☭☭☭"/utf8>>}}
}, },

View File

@ -38,7 +38,7 @@
-type limit_type() :: {turnover, lim_turnover_metric:t()}. -type limit_type() :: {turnover, lim_turnover_metric:t()}.
-type limit_scope() :: ordsets:ordset(limit_scope_type()). -type limit_scope() :: ordsets:ordset(limit_scope_type()).
-type limit_scope_type() :: party | shop | wallet | identity. -type limit_scope_type() :: party | shop | wallet | identity | payment_tool.
-type shard_size() :: pos_integer(). -type shard_size() :: pos_integer().
-type shard_id() :: binary(). -type shard_id() :: binary().
-type prefix() :: binary(). -type prefix() :: binary().
@ -560,11 +560,27 @@ append_context_bits(shop, Bits) ->
% Also we need to preserve order between party / shop to ensure backwards compatibility. % Also we need to preserve order between party / shop to ensure backwards compatibility.
{order, 1, {from, payment_processing, owner_id, invoice}}, {order, 1, {from, payment_processing, owner_id, invoice}},
{order, 2, {from, payment_processing, shop_id, invoice}} {order, 2, {from, payment_processing, shop_id, invoice}}
]). ]);
append_context_bits(payment_tool, Bits) ->
ordsets:add_element(
{from, payment_processing, payer, invoice_payment},
Bits
).
-spec extract_context_bit(context_bit(), lim_context()) -> {ok, binary()}. -spec extract_context_bit(context_bit(), lim_context()) -> {ok, binary()}.
extract_context_bit({order, _, Bit}, LimitContext) -> extract_context_bit({order, _, Bit}, LimitContext) ->
extract_context_bit(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}}
end;
extract_context_bit({from, ContextType, ValueName, Op}, LimitContext) -> extract_context_bit({from, ContextType, ValueName, Op}, LimitContext) ->
lim_context:get_from_context(ContextType, ValueName, Op, LimitContext). lim_context:get_from_context(ContextType, ValueName, Op, LimitContext).

View File

@ -23,7 +23,7 @@ handle_function(Fn, Args, WoodyCtx, Opts) ->
-spec handle_function_(woody:func(), woody:args(), lim_context:t(), woody:options()) -> {ok, woody:result()}. -spec handle_function_(woody:func(), woody:args(), lim_context:t(), woody:options()) -> {ok, woody:result()}.
handle_function_( handle_function_(
'CreateLegacy', 'CreateLegacy',
{#limiter_cfg_LimitCreateParams{ {#limiter_configurator_LimitCreateParams{
id = ID, id = ID,
name = Name, name = Name,
description = Description, description = Description,
@ -51,7 +51,7 @@ handle_function_(
{error, {name, notfound}} -> {error, {name, notfound}} ->
woody_error:raise( woody_error:raise(
business, business,
#limiter_cfg_LimitConfigNameNotFound{} #limiter_configurator_LimitConfigNameNotFound{}
) )
end; end;
handle_function_('Create', {Params}, LimitContext, _Opts) -> handle_function_('Create', {Params}, LimitContext, _Opts) ->
@ -70,7 +70,7 @@ handle_function_('Get', {LimitID}, LimitContext, _Opts) ->
{ok, LimitConfig} -> {ok, LimitConfig} ->
{ok, lim_config_codec:marshal_config(LimitConfig)}; {ok, lim_config_codec:marshal_config(LimitConfig)};
{error, notfound} -> {error, notfound} ->
woody_error:raise(business, #limiter_cfg_LimitConfigNotFound{}) woody_error:raise(business, #limiter_configurator_LimitConfigNotFound{})
end. end.
map_type({turnover, _}) -> map_type({turnover, _}) ->
@ -78,7 +78,7 @@ map_type({turnover, _}) ->
map_type(_) -> map_type(_) ->
woody_error:raise( woody_error:raise(
business, business,
#limiter_base_InvalidRequest{errors = [<<"Config type not found.">>]} #'InvalidRequest'{errors = [<<"Config type not found.">>]}
). ).
mk_limit_config(<<"ShopDayTurnover">>) -> mk_limit_config(<<"ShopDayTurnover">>) ->

View File

@ -18,6 +18,8 @@
-type thrift_context() :: lim_limiter_thrift:'LimitContext'(). -type thrift_context() :: lim_limiter_thrift:'LimitContext'().
-type clock() :: lim_limiter_thrift:'Clock'(). -type clock() :: lim_limiter_thrift:'Clock'().
-type id() :: binary(). -type id() :: binary().
-type token() :: binary().
-type exp_date() :: binary().
-type cash() :: lim_body:cash(). -type cash() :: lim_body:cash().
-type t() :: #{ -type t() :: #{
@ -52,8 +54,8 @@
shop_id => id(), shop_id => id(),
cost => cash(), cost => cash(),
created_at => timestamp(), created_at => timestamp(),
effective_adjustment => payment_processing_adjustment(), adjustment => payment_processing_adjustment(),
effective_payment => payment_processing_payment() payment => payment_processing_payment()
}. }.
-type payment_processing_adjustment() :: #{ -type payment_processing_adjustment() :: #{
@ -68,10 +70,26 @@
capture_cost => cash(), capture_cost => cash(),
created_at => timestamp(), created_at => timestamp(),
flow => instant | hold, flow => instant | hold,
payer => payment_resource | customer | recurrent, payer => payment_processing_payer(),
effective_adjustment => payment_processing_payment_adjustment(), adjustment => payment_processing_payment_adjustment(),
effective_refund => payment_processing_payment_refund(), refund => payment_processing_payment_refund(),
effective_chargeback => payment_processing_payment_chargeback() 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() :: #{ -type payment_processing_payment_adjustment() :: #{
@ -93,6 +111,7 @@
}. }.
-export_type([t/0]). -export_type([t/0]).
-export_type([context/0]).
-export_type([context_type/0]). -export_type([context_type/0]).
-export_type([context_operation/0]). -export_type([context_operation/0]).
@ -156,23 +175,23 @@ get_from_context(_, _ValueName, _Op, _LimContext) ->
get_payment_processing_operation_context(invoice, #{invoice := Invoice}) -> get_payment_processing_operation_context(invoice, #{invoice := Invoice}) ->
{ok, Invoice}; {ok, Invoice};
get_payment_processing_operation_context(invoice_adjustment, #{invoice := #{effective_adjustment := Adjustment}}) -> get_payment_processing_operation_context(invoice_adjustment, #{invoice := #{adjustment := Adjustment}}) ->
{ok, Adjustment}; {ok, Adjustment};
get_payment_processing_operation_context(invoice_payment, #{invoice := #{effective_payment := Payment}}) -> get_payment_processing_operation_context(invoice_payment, #{invoice := #{payment := Payment}}) ->
{ok, Payment}; {ok, Payment};
get_payment_processing_operation_context( get_payment_processing_operation_context(
invoice_payment_adjustment, invoice_payment_adjustment,
#{invoice := #{effective_payment := #{effective_adjustment := Adjustment}}} #{invoice := #{payment := #{adjustment := Adjustment}}}
) -> ) ->
{ok, Adjustment}; {ok, Adjustment};
get_payment_processing_operation_context( get_payment_processing_operation_context(
invoice_payment_refund, invoice_payment_refund,
#{invoice := #{effective_payment := #{effective_refund := Refund}}} #{invoice := #{payment := #{refund := Refund}}}
) -> ) ->
{ok, Refund}; {ok, Refund};
get_payment_processing_operation_context( get_payment_processing_operation_context(
invoice_payment_chargeback, invoice_payment_chargeback,
#{invoice := #{effective_payment := #{effective_chargeback := Chargeback}}} #{invoice := #{payment := #{chargeback := Chargeback}}}
) -> ) ->
{ok, Chargeback}; {ok, Chargeback};
get_payment_processing_operation_context(_, _) -> get_payment_processing_operation_context(_, _) ->
@ -180,126 +199,13 @@ get_payment_processing_operation_context(_, _) ->
%% %%
unmarshal_context(#limiter_context_LimitContext{payment_processing = PaymentProcessing}) -> unmarshal_context(#limiter_context_LimitContext{limiter_payment_processing = PaymentProcessing}) when
#{payment_processing => unmarshal_payment_processing_context(PaymentProcessing)}; 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(_) -> unmarshal_context(_) ->
#{}. #{}.
unmarshal_payment_processing_context(#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 = EffectivePayment,
effective_adjustment = EffectiveAdjustment
}) ->
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),
effective_adjustment => maybe_unmarshal(
EffectiveAdjustment,
fun unmarshal_payment_processing_invoice_adjustment/1
),
effective_payment => maybe_unmarshal(EffectivePayment, 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 = EffectiveAdjustment,
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),
effective_adjustment => maybe_unmarshal(
EffectiveAdjustment,
fun unmarshal_payment_processing_invoice_payment_adjustment/1
),
effective_refund => maybe_unmarshal(EffectiveRefund, fun unmarshal_payment_processing_invoice_payment_refund/1),
effective_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(#limiter_base_Cash{amount = Amount, currency = #limiter_base_CurrencyRef{symbolic_code = Currency}}) ->
#{amount => Amount, currency => Currency}.
unmarshal_string(Value) ->
Value.
maybe_unmarshal(undefined, _) ->
undefined;
maybe_unmarshal(Value, UnmarshalFun) ->
UnmarshalFun(Value).

View File

@ -84,7 +84,7 @@ handle_get_error(Error) ->
-spec handle_hold_error(_) -> no_return(). -spec handle_hold_error(_) -> no_return().
handle_hold_error({_, {invalid_request, Errors}}) -> handle_hold_error({_, {invalid_request, Errors}}) ->
woody_error:raise(business, #limiter_base_InvalidRequest{errors = Errors}); woody_error:raise(business, #'InvalidRequest'{errors = Errors});
handle_hold_error(Error) -> handle_hold_error(Error) ->
handle_default_error(Error). handle_default_error(Error).
@ -92,13 +92,13 @@ handle_hold_error(Error) ->
handle_commit_error({_, {forbidden_operation_amount, Error}}) -> handle_commit_error({_, {forbidden_operation_amount, Error}}) ->
handle_forbidden_operation_amount_error(Error); handle_forbidden_operation_amount_error(Error);
handle_commit_error({_, {invalid_request, Errors}}) -> handle_commit_error({_, {invalid_request, Errors}}) ->
woody_error:raise(business, #limiter_base_InvalidRequest{errors = Errors}); woody_error:raise(business, #'InvalidRequest'{errors = Errors});
handle_commit_error(Error) -> handle_commit_error(Error) ->
handle_default_error(Error). handle_default_error(Error).
-spec handle_rollback_error(_) -> no_return(). -spec handle_rollback_error(_) -> no_return().
handle_rollback_error({_, {invalid_request, Errors}}) -> handle_rollback_error({_, {invalid_request, Errors}}) ->
woody_error:raise(business, #limiter_base_InvalidRequest{errors = Errors}); woody_error:raise(business, #'InvalidRequest'{errors = Errors});
handle_rollback_error(Error) -> handle_rollback_error(Error) ->
handle_default_error(Error). handle_default_error(Error).

View File

@ -0,0 +1,129 @@
-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).

View File

@ -0,0 +1,213 @@
-module(lim_payproc_context).
-include_lib("limiter_proto/include/lim_limiter_payproc_context_thrift.hrl").
-export([unmarshal/1]).
-type thrift_context() :: lim_limiter_payproc_context_thrift:'Context'().
%%
-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)
}).
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)
}).
unmarshal_payment_processing_invoice_adjustment(#domain_InvoiceAdjustment{id = ID}) ->
#{id => unmarshal_string(ID)}.
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.
unmarshal_payment_processing_invoice_payment_flow({Flow, _}) ->
Flow.
unmarshal_payment_processing_invoice_payment_payer({Payer, Data}) ->
{Payer, unmarshal_payment_processing_invoice_payment_payer_data(Data)}.
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)
}).
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.
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>>.
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)
}).
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)
}).
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)
}).
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).
-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},
PaymentTool =
{bank_card, #domain_BankCard{
token = <<"Token">>,
bin = <<"bin">>,
exp_date = ExpDate,
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).
-endif.

View File

@ -48,7 +48,7 @@ marshal(time_range, #{
account_id_from := AccountIDFrom, account_id_from := AccountIDFrom,
account_id_to := AccountIDTo account_id_to := AccountIDTo
}) -> }) ->
#time_range_TimeRange{ #limiter_time_range_TimeRange{
upper = Upper, upper = Upper,
lower = Lower, lower = Lower,
account_id_from = AccountIDFrom, account_id_from = AccountIDFrom,
@ -57,15 +57,15 @@ marshal(time_range, #{
marshal(time_range_type, {calendar, SubType}) -> marshal(time_range_type, {calendar, SubType}) ->
{calendar, marshal(time_range_sub_type, SubType)}; {calendar, marshal(time_range_sub_type, SubType)};
marshal(time_range_type, {interval, Interval}) -> marshal(time_range_type, {interval, Interval}) ->
{interval, #time_range_TimeRangeTypeInterval{amount = Interval}}; {interval, #limiter_time_range_TimeRangeTypeInterval{amount = Interval}};
marshal(time_range_sub_type, year) -> marshal(time_range_sub_type, year) ->
{year, #time_range_TimeRangeTypeCalendarYear{}}; {year, #limiter_time_range_TimeRangeTypeCalendarYear{}};
marshal(time_range_sub_type, month) -> marshal(time_range_sub_type, month) ->
{month, #time_range_TimeRangeTypeCalendarMonth{}}; {month, #limiter_time_range_TimeRangeTypeCalendarMonth{}};
marshal(time_range_sub_type, week) -> marshal(time_range_sub_type, week) ->
{week, #time_range_TimeRangeTypeCalendarWeek{}}; {week, #limiter_time_range_TimeRangeTypeCalendarWeek{}};
marshal(time_range_sub_type, day) -> marshal(time_range_sub_type, day) ->
{day, #time_range_TimeRangeTypeCalendarDay{}}; {day, #limiter_time_range_TimeRangeTypeCalendarDay{}};
marshal(timestamp, {DateTime, USec}) -> marshal(timestamp, {DateTime, USec}) ->
DateTimeinSeconds = genlib_time:daytime_to_unixtime(DateTime), DateTimeinSeconds = genlib_time:daytime_to_unixtime(DateTime),
{TimeinUnit, Unit} = {TimeinUnit, Unit} =
@ -99,7 +99,7 @@ unmarshal(range, #limiter_range_LimitRange{
created_at => CreatedAt, created_at => CreatedAt,
currency => Currency currency => Currency
}); });
unmarshal(time_range, #time_range_TimeRange{ unmarshal(time_range, #limiter_time_range_TimeRange{
upper = Upper, upper = Upper,
lower = Lower, lower = Lower,
account_id_from = AccountIDFrom, account_id_from = AccountIDFrom,
@ -113,7 +113,7 @@ unmarshal(time_range, #time_range_TimeRange{
}; };
unmarshal(time_range_type, {calendar, SubType}) -> unmarshal(time_range_type, {calendar, SubType}) ->
{calendar, unmarshal(time_range_sub_type, SubType)}; {calendar, unmarshal(time_range_sub_type, SubType)};
unmarshal(time_range_type, {interval, #time_range_TimeRangeTypeInterval{amount = Interval}}) -> unmarshal(time_range_type, {interval, #limiter_time_range_TimeRangeTypeInterval{amount = Interval}}) ->
{interval, Interval}; {interval, Interval};
unmarshal(time_range_sub_type, {year, _}) -> unmarshal(time_range_sub_type, {year, _}) ->
year; year;

View File

@ -3,7 +3,7 @@
-export([compute/4]). -export([compute/4]).
-type amount() :: lim_body:amount(). -type amount() :: lim_body:amount().
-type currency() :: lim_base_thrift:'CurrencySymbolicCode'(). -type currency() :: lim_domain_thrift:'CurrencySymbolicCode'().
-type stage() :: hold | commit. -type stage() :: hold | commit.
-type t() :: number | {amount, currency()}. -type t() :: number | {amount, currency()}.

View File

@ -81,7 +81,7 @@ legacy_create_config(C) ->
Client = lim_client:new(), Client = lim_client:new(),
ID = ?config(limit_id, C), ID = ?config(limit_id, C),
Description = genlib:unique(), Description = genlib:unique(),
Params = #limiter_cfg_LimitCreateParams{ Params = #limiter_configurator_LimitCreateParams{
id = ID, id = ID,
name = <<"GlobalMonthTurnover">>, name = <<"GlobalMonthTurnover">>,
description = Description, description = Description,
@ -150,7 +150,7 @@ get_config(C) ->
prepare_environment(ID, LimitName, _C) -> prepare_environment(ID, LimitName, _C) ->
Client = lim_client:new(), Client = lim_client:new(),
Params = #limiter_cfg_LimitCreateParams{ Params = #limiter_configurator_LimitCreateParams{
id = ID, id = ID,
name = LimitName, name = LimitName,
description = <<"description">>, description = <<"description">>,

View File

@ -4,11 +4,13 @@
-include_lib("limiter_proto/include/lim_configurator_thrift.hrl"). -include_lib("limiter_proto/include/lim_configurator_thrift.hrl").
-define(currency, <<"RUB">>). -define(currency, <<"RUB">>).
-define(string, <<"STRING">>).
-define(timestamp, <<"2000-01-01T00:00:00Z">>).
-define(cash(Amount), ?cash(Amount, ?currency)). -define(cash(Amount), ?cash(Amount, ?currency)).
-define(cash(Amount, Currency), #limiter_base_Cash{ -define(cash(Amount, Currency), #domain_Cash{
amount = Amount, amount = Amount,
currency = #limiter_base_CurrencyRef{symbolic_code = Currency} currency = #domain_CurrencyRef{symbolic_code = Currency}
}). }).
-define(scope(Types), {multi, ordsets:from_list(Types)}). -define(scope(Types), {multi, ordsets:from_list(Types)}).
@ -16,6 +18,7 @@
-define(scope_party(), {party, #limiter_config_LimitScopeEmptyDetails{}}). -define(scope_party(), {party, #limiter_config_LimitScopeEmptyDetails{}}).
-define(scope_shop(), {shop, #limiter_config_LimitScopeEmptyDetails{}}). -define(scope_shop(), {shop, #limiter_config_LimitScopeEmptyDetails{}}).
-define(scope_payment_tool(), {payment_tool, #limiter_config_LimitScopeEmptyDetails{}}).
-define(lim_type_turnover(), ?lim_type_turnover(?turnover_metric_number())). -define(lim_type_turnover(), ?lim_type_turnover(?turnover_metric_number())).
-define(lim_type_turnover(Metric), -define(lim_type_turnover(Metric),
@ -29,13 +32,16 @@
). ).
-define(time_range_day(), -define(time_range_day(),
{calendar, {day, #time_range_TimeRangeTypeCalendarDay{}}} {calendar, {day, #limiter_time_range_TimeRangeTypeCalendarDay{}}}
). ).
-define(time_range_week(), -define(time_range_week(),
{calendar, {week, #time_range_TimeRangeTypeCalendarWeek{}}} {calendar, {week, #limiter_time_range_TimeRangeTypeCalendarWeek{}}}
). ).
-define(time_range_month(), -define(time_range_month(),
{calendar, {month, #time_range_TimeRangeTypeCalendarMonth{}}} {calendar, {month, #limiter_time_range_TimeRangeTypeCalendarMonth{}}}
).
-define(time_range_year(),
{calendar, {year, #limiter_time_range_TimeRangeTypeCalendarYear{}}}
). ).
-define(op_behaviour(), ?op_behaviour(?op_addition())). -define(op_behaviour(), ?op_behaviour(?op_addition())).
@ -54,7 +60,7 @@
-define(op_invoice_payment(), {invoice_payment, #limiter_context_PaymentProcessingOperationInvoicePayment{}}). -define(op_invoice_payment(), {invoice_payment, #limiter_context_PaymentProcessingOperationInvoicePayment{}}).
-define(ctx_invoice(Cost), #limiter_context_LimitContext{ -define(ctx_invoice(Cost), #limiter_context_LimitContext{
payment_processing = #limiter_context_ContextPaymentProcessing{ limiter_payment_processing = #limiter_context_ContextPaymentProcessing{
op = ?op_invoice(), op = ?op_invoice(),
invoice = #limiter_context_Invoice{ invoice = #limiter_context_Invoice{
created_at = <<"2000-01-01T00:00:00Z">>, created_at = <<"2000-01-01T00:00:00Z">>,
@ -66,7 +72,7 @@
-define(ctx_invoice_payment(Cost, CaptureCost), ?ctx_invoice_payment(undefined, undefined, Cost, CaptureCost)). -define(ctx_invoice_payment(Cost, CaptureCost), ?ctx_invoice_payment(undefined, undefined, Cost, CaptureCost)).
-define(ctx_invoice_payment(OwnerID, ShopID, Cost, CaptureCost), #limiter_context_LimitContext{ -define(ctx_invoice_payment(OwnerID, ShopID, Cost, CaptureCost), #limiter_context_LimitContext{
payment_processing = #limiter_context_ContextPaymentProcessing{ limiter_payment_processing = #limiter_context_ContextPaymentProcessing{
op = ?op_invoice_payment(), op = ?op_invoice_payment(),
invoice = #limiter_context_Invoice{ invoice = #limiter_context_Invoice{
owner_id = OwnerID, owner_id = OwnerID,
@ -74,14 +80,19 @@
effective_payment = #limiter_context_InvoicePayment{ effective_payment = #limiter_context_InvoicePayment{
created_at = <<"2000-01-01T00:00:00Z">>, created_at = <<"2000-01-01T00:00:00Z">>,
cost = Cost, cost = Cost,
capture_cost = CaptureCost 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{ -define(ctx_invoice_payment(Payment), #limiter_context_LimitContext{
payment_processing = #limiter_context_ContextPaymentProcessing{ limiter_payment_processing = #limiter_context_ContextPaymentProcessing{
op = ?op_invoice_payment(), op = ?op_invoice_payment(),
invoice = #limiter_context_Invoice{ invoice = #limiter_context_Invoice{
effective_payment = Payment effective_payment = Payment
@ -90,7 +101,7 @@
}). }).
-define(ctx_invoice_payment_refund(OwnerID, ShopID, Cost, CaptureCost, RefundCost), #limiter_context_LimitContext{ -define(ctx_invoice_payment_refund(OwnerID, ShopID, Cost, CaptureCost, RefundCost), #limiter_context_LimitContext{
payment_processing = #limiter_context_ContextPaymentProcessing{ limiter_payment_processing = #limiter_context_ContextPaymentProcessing{
op = {invoice_payment_refund, #limiter_context_PaymentProcessingOperationInvoicePaymentRefund{}}, op = {invoice_payment_refund, #limiter_context_PaymentProcessingOperationInvoicePaymentRefund{}},
invoice = #limiter_context_Invoice{ invoice = #limiter_context_Invoice{
owner_id = OwnerID, owner_id = OwnerID,
@ -108,4 +119,109 @@
} }
}). }).
%% Payproc
-define(payproc_op_invoice, {invoice, #limiter_context_payproc_OperationInvoice{}}).
-define(payproc_op_invoice_payment, {invoice_payment, #limiter_context_payproc_OperationInvoicePayment{}}).
-define(payproc_bank_card(),
?payproc_bank_card(?string, 2, 2022)
).
-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(payproc_invoice(OwnerID, ShopID, Cost), #domain_Invoice{
id = ?string,
owner_id = OwnerID,
shop_id = ShopID,
created_at = ?timestamp,
status = {unpaid, #domain_InvoiceUnpaid{}},
details = #domain_InvoiceDetails{product = ?string},
due = ?timestamp,
cost = Cost
}).
-define(payproc_invoice_payment(Cost, CaptureCost),
?payproc_invoice_payment(Cost, CaptureCost, {bank_card, ?payproc_bank_card()})
).
-define(payproc_invoice_payment(Cost, CaptureCost, PaymentTool), #domain_InvoicePayment{
id = ?string,
created_at = ?timestamp,
status = {captured, #domain_InvoicePaymentCaptured{cost = CaptureCost}},
cost = Cost,
domain_revision = 1,
flow = {instant, #domain_InvoicePaymentFlowInstant{}},
payer =
{payment_resource, #domain_PaymentResourcePayer{
resource = #domain_DisposablePaymentResource{
payment_tool = PaymentTool
},
contact_info = #domain_ContactInfo{}
}}
}).
-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_payment(Cost, CaptureCost),
?payproc_ctx_invoice_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_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{
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
}
}
}
}
}
).
-endif. -endif.

View File

@ -40,6 +40,12 @@
-export([commit_refund_keep_number_unchanged/1]). -export([commit_refund_keep_number_unchanged/1]).
-export([partial_commit_number_counts_as_single_op/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 group_name() :: atom().
-type test_case_name() :: atom(). -type test_case_name() :: atom().
@ -72,7 +78,12 @@ groups() ->
refund_ok, refund_ok,
commit_inexistent_hold_fails, commit_inexistent_hold_fails,
partial_commit_inexistent_hold_fails, partial_commit_inexistent_hold_fails,
commit_multirange_limit_ok commit_multirange_limit_ok,
payproc_hold_ok,
payproc_commit_ok,
payproc_rollback_ok,
payproc_refund_ok,
payproc_commit_with_payment_tool_scope_ok
]}, ]},
{cashless, [parallel], [ {cashless, [parallel], [
commit_number_ok, commit_number_ok,
@ -145,13 +156,13 @@ commit_with_default_exchange(C) ->
_ = mock_exchange(Rational, C), _ = mock_exchange(Rational, C),
ID = configure_limit(?time_range_month(), ?global(), C), ID = configure_limit(?time_range_month(), ?global(), C),
Context = #limiter_context_LimitContext{ Context = #limiter_context_LimitContext{
payment_processing = #limiter_context_ContextPaymentProcessing{ limiter_payment_processing = #limiter_context_ContextPaymentProcessing{
op = {invoice, #limiter_context_PaymentProcessingOperationInvoice{}}, op = {invoice, #limiter_context_PaymentProcessingOperationInvoice{}},
invoice = #limiter_context_Invoice{ invoice = #limiter_context_Invoice{
created_at = <<"2000-01-01T00:00:00Z">>, created_at = <<"2000-01-01T00:00:00Z">>,
cost = #limiter_base_Cash{ cost = #domain_Cash{
amount = 10000, amount = 10000,
currency = #limiter_base_CurrencyRef{symbolic_code = <<"SOME_CURRENCY">>} currency = #domain_CurrencyRef{symbolic_code = <<"SOME_CURRENCY">>}
} }
} }
} }
@ -165,18 +176,18 @@ partial_commit_with_exchange(C) ->
_ = mock_exchange(Rational, C), _ = mock_exchange(Rational, C),
ID = configure_limit(?time_range_month(), ?global(), C), ID = configure_limit(?time_range_month(), ?global(), C),
Context = #limiter_context_LimitContext{ Context = #limiter_context_LimitContext{
payment_processing = #limiter_context_ContextPaymentProcessing{ limiter_payment_processing = #limiter_context_ContextPaymentProcessing{
op = {invoice_payment, #limiter_context_PaymentProcessingOperationInvoicePayment{}}, op = {invoice_payment, #limiter_context_PaymentProcessingOperationInvoicePayment{}},
invoice = #limiter_context_Invoice{ invoice = #limiter_context_Invoice{
effective_payment = #limiter_context_InvoicePayment{ effective_payment = #limiter_context_InvoicePayment{
created_at = <<"2000-01-01T00:00:00Z">>, created_at = <<"2000-01-01T00:00:00Z">>,
cost = #limiter_base_Cash{ cost = #domain_Cash{
amount = 10000, amount = 10000,
currency = #limiter_base_CurrencyRef{symbolic_code = <<"USD">>} currency = #domain_CurrencyRef{symbolic_code = <<"USD">>}
}, },
capture_cost = #limiter_base_Cash{ capture_cost = #domain_Cash{
amount = 8000, amount = 8000,
currency = #limiter_base_CurrencyRef{symbolic_code = <<"USD">>} currency = #domain_CurrencyRef{symbolic_code = <<"USD">>}
} }
} }
} }
@ -191,13 +202,13 @@ commit_with_exchange(C) ->
_ = mock_exchange(Rational, C), _ = mock_exchange(Rational, C),
ID = configure_limit(?time_range_month(), ?global(), C), ID = configure_limit(?time_range_month(), ?global(), C),
Context = #limiter_context_LimitContext{ Context = #limiter_context_LimitContext{
payment_processing = #limiter_context_ContextPaymentProcessing{ limiter_payment_processing = #limiter_context_ContextPaymentProcessing{
op = {invoice, #limiter_context_PaymentProcessingOperationInvoice{}}, op = {invoice, #limiter_context_PaymentProcessingOperationInvoice{}},
invoice = #limiter_context_Invoice{ invoice = #limiter_context_Invoice{
created_at = <<"2000-01-01T00:00:00Z">>, created_at = <<"2000-01-01T00:00:00Z">>,
cost = #limiter_base_Cash{ cost = #domain_Cash{
amount = 10000, amount = 10000,
currency = #limiter_base_CurrencyRef{symbolic_code = <<"USD">>} currency = #domain_CurrencyRef{symbolic_code = <<"USD">>}
} }
} }
} }
@ -251,13 +262,13 @@ hold_ok(C) ->
commit_ok(C) -> commit_ok(C) ->
ID = configure_limit(?time_range_month(), ?global(), C), ID = configure_limit(?time_range_month(), ?global(), C),
Context = #limiter_context_LimitContext{ Context = #limiter_context_LimitContext{
payment_processing = #limiter_context_ContextPaymentProcessing{ limiter_payment_processing = #limiter_context_ContextPaymentProcessing{
op = {invoice, #limiter_context_PaymentProcessingOperationInvoice{}}, op = {invoice, #limiter_context_PaymentProcessingOperationInvoice{}},
invoice = #limiter_context_Invoice{ invoice = #limiter_context_Invoice{
created_at = <<"2000-01-01T00:00:00Z">>, created_at = <<"2000-01-01T00:00:00Z">>,
cost = #limiter_base_Cash{ cost = #domain_Cash{
amount = 10, amount = 10,
currency = #limiter_base_CurrencyRef{symbolic_code = <<"RUB">>} currency = #domain_CurrencyRef{symbolic_code = <<"RUB">>}
} }
} }
} }
@ -299,7 +310,7 @@ commit_inexistent_hold_fails(C) ->
% NOTE % NOTE
% We do not expect `LimitChangeNotFound` here because we no longer reconcile with accounter % We do not expect `LimitChangeNotFound` here because we no longer reconcile with accounter
% before requesting him to hold / commit. % before requesting him to hold / commit.
{exception, #limiter_base_InvalidRequest{}} = {exception, #'InvalidRequest'{}} =
lim_client:commit(?LIMIT_CHANGE(ID), Context, ?config(client, C)). lim_client:commit(?LIMIT_CHANGE(ID), Context, ?config(client, C)).
-spec partial_commit_inexistent_hold_fails(config()) -> _. -spec partial_commit_inexistent_hold_fails(config()) -> _.
@ -309,7 +320,7 @@ partial_commit_inexistent_hold_fails(C) ->
% NOTE % NOTE
% We do not expect `LimitChangeNotFound` here because we no longer reconcile with accounter % We do not expect `LimitChangeNotFound` here because we no longer reconcile with accounter
% before requesting him to hold / commit. % before requesting him to hold / commit.
{exception, #limiter_base_InvalidRequest{}} = {exception, #'InvalidRequest'{}} =
lim_client:commit(?LIMIT_CHANGE(ID), Context, ?config(client, C)). lim_client:commit(?LIMIT_CHANGE(ID), Context, ?config(client, C)).
-spec commit_multirange_limit_ok(config()) -> _. -spec commit_multirange_limit_ok(config()) -> _.
@ -468,6 +479,79 @@ 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) -> gen_change_id(LimitID, ChangeID) ->
genlib:format("~s/~p", [LimitID, ChangeID]). genlib:format("~s/~p", [LimitID, ChangeID]).

View File

@ -50,7 +50,7 @@
% mandatory % mandatory
unmatched_returns, unmatched_returns,
error_handling, error_handling,
race_conditions, % race_conditions,
unknown unknown
]}, ]},
{plt_apps, all_deps} {plt_apps, all_deps}

View File

@ -25,7 +25,7 @@
{<<"jsx">>,{pkg,<<"jsx">>,<<"3.1.0">>},1}, {<<"jsx">>,{pkg,<<"jsx">>,<<"3.1.0">>},1},
{<<"limiter_proto">>, {<<"limiter_proto">>,
{git,"https://github.com/valitydev/limiter-proto.git", {git,"https://github.com/valitydev/limiter-proto.git",
{ref,"6723e862157a7f78194a64271899c2ef1581e177"}}, {ref,"ac9705389211682263c0a983ae76f663d4857ec9"}},
0}, 0},
{<<"machinery">>, {<<"machinery">>,
{git,"https://github.com/valitydev/machinery-erlang.git", {git,"https://github.com/valitydev/machinery-erlang.git",