HG-314: Introduce digital wallets (#164)

* HG-314: Let it learn new payment tool and storage schema

* HG-314: Add forgotten payment tool condition assertions

* HG-314: Increase healthcheck timeouts just for the fun of it

* HG-326: Introduce new rounding rule for cashflow volume (#169)

* BA-52: Bump to master rbkmoney/damsel@620cca5

* BA-52: Bump to master rbkmoney/dominant@68d75c0
This commit is contained in:
Andrew Mayorov 2018-01-24 16:40:54 +03:00 committed by GitHub
parent 46c7638166
commit 0791b44eee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 399 additions and 175 deletions

View File

@ -3,23 +3,21 @@ cat <<EOF
FROM $BASE_IMAGE
MAINTAINER Andrey Mayorov <a.mayorov@rbkmoney.com>
COPY ./_build/prod/rel/hellgate /opt/hellgate
WORKDIR /opt/hellgate
CMD /opt/hellgate/bin/hellgate foreground
EXPOSE 8022
LABEL base_image_tag=$BASE_IMAGE_TAG
LABEL build_image_tag=$BUILD_IMAGE_TAG
# A bit of magic to get a proper branch name
# even when the HEAD is detached (Hey Jenkins!
# BRANCH_NAME is available in Jenkins env).
LABEL branch=$( \
if [ "HEAD" != $(git rev-parse --abbrev-ref HEAD) ]; then \
echo $(git rev-parse --abbrev-ref HEAD); \
elif [ -n "$BRANCH_NAME" ]; then \
echo $BRANCH_NAME; \
else \
echo $(git name-rev --name-only HEAD); \
fi)
LABEL commit=$(git rev-parse HEAD)
LABEL commit_number=$(git rev-list --count HEAD)
WORKDIR /opt/hellgate
LABEL com.rbkmoney.$SERVICE_NAME.parent=$BASE_IMAGE_NAME \
com.rbkmoney.$SERVICE_NAME.parent_tag=$BASE_IMAGE_TAG \
com.rbkmoney.$SERVICE_NAME.build_img=build \
com.rbkmoney.$SERVICE_NAME.build_img_tag=$BUILD_IMAGE_TAG \
com.rbkmoney.$SERVICE_NAME.commit_id=$(git rev-parse HEAD) \
com.rbkmoney.$SERVICE_NAME.commit_number=$(git rev-list --count HEAD) \
com.rbkmoney.$SERVICE_NAME.branch=$( \
if [ "HEAD" != $(git rev-parse --abbrev-ref HEAD) ]; then \
echo $(git rev-parse --abbrev-ref HEAD); \
elif [ -n "$BRANCH_NAME" ]; then \
echo $BRANCH_NAME; \
else \
echo $(git name-rev --name-only HEAD); \
fi)
EOF

View File

@ -49,7 +49,7 @@ xref: submodules
lint:
elvis rock
dialyze:
dialyze: submodules
$(REBAR) dialyzer
start: submodules
@ -58,7 +58,7 @@ start: submodules
devrel: submodules
$(REBAR) release
release: distclean
release: submodules
$(REBAR) as prod release
clean:

View File

@ -94,8 +94,8 @@ revert_details(Details) ->
-define(fixed(Cash),
{fixed, #domain_CashVolumeFixed{cash = Cash}}).
-define(share(P, Q, Of),
{share, #domain_CashVolumeShare{'parts' = ?rational(P, Q), 'of' = Of}}).
-define(share(P, Q, Of, RoundingMethod),
{share, #domain_CashVolumeShare{'parts' = ?rational(P, Q), 'of' = Of, 'rounding_method' = RoundingMethod}}).
-define(product(Fun, CVs),
{product, {Fun, CVs}}).
-define(rational(P, Q),
@ -103,8 +103,8 @@ revert_details(Details) ->
compute_volume(?fixed(Cash), _Context) ->
Cash;
compute_volume(?share(P, Q, Of), Context) ->
compute_parts_of(P, Q, resolve_constant(Of, Context));
compute_volume(?share(P, Q, Of, RoundingMethod), Context) ->
compute_parts_of(P, Q, resolve_constant(Of, Context), RoundingMethod);
compute_volume(?product(Fun, CVs) = CV0, Context) ->
case ordsets:size(CVs) of
N when N > 0 ->
@ -113,12 +113,13 @@ compute_volume(?product(Fun, CVs) = CV0, Context) ->
error({misconfiguration, {'Cash volume product over empty set', CV0}})
end.
compute_parts_of(P, Q, Cash = #domain_Cash{amount = Amount}) ->
compute_parts_of(P, Q, Cash = #domain_Cash{amount = Amount}, RoundingMethod) ->
Cash#domain_Cash{amount = genlib_rational:round(
genlib_rational:mul(
genlib_rational:new(Amount),
genlib_rational:new(P, Q)
)
),
get_rounding_method(RoundingMethod)
)}.
compute_product(Fun, [CV | CVRest], CV0, Context) ->
@ -149,6 +150,13 @@ resolve_constant(Constant, Context) ->
error({misconfiguration, {'Cash flow constant not found', {Constant, Context}}})
end.
get_rounding_method(undefined) ->
round_half_away_from_zero;
get_rounding_method(round_half_towards_zero) ->
round_half_towards_zero;
get_rounding_method(round_half_away_from_zero) ->
round_half_away_from_zero.
%%
-include("domain.hrl").

View File

@ -22,7 +22,9 @@
get_method({bank_card, #domain_BankCard{payment_system = PaymentSystem}}) ->
#domain_PaymentMethodRef{id = {bank_card, PaymentSystem}};
get_method({payment_terminal, #domain_PaymentTerminal{terminal_type = TerminalType}}) ->
#domain_PaymentMethodRef{id = {payment_terminal, TerminalType}}.
#domain_PaymentMethodRef{id = {payment_terminal, TerminalType}};
get_method({digital_wallet, #domain_DigitalWallet{provider = Provider}}) ->
#domain_PaymentMethodRef{id = {digital_wallet, Provider}}.
%%
@ -30,62 +32,109 @@ get_method({payment_terminal, #domain_PaymentTerminal{terminal_type = TerminalTy
test_condition({bank_card, C}, {bank_card, V = #domain_BankCard{}}, Rev) ->
test_bank_card_condition(C, V, Rev);
test_condition({payment_terminal, C}, {payment_terminal, V = #domain_PaymentTerminal{}}, Rev) ->
test_payment_terminal_condition(C, V, Rev);
test_condition({digital_wallet, C}, {digital_wallet, V = #domain_DigitalWallet{}}, Rev) ->
test_digital_wallet_condition(C, V, Rev);
test_condition(_PaymentTool, _Condition, _Rev) ->
false.
test_bank_card_condition({payment_system_is, Ps}, #domain_BankCard{payment_system = Ps0}, _Rev) ->
test_bank_card_condition(#domain_BankCardCondition{definition = Def}, V, Rev) when Def /= undefined ->
test_bank_card_condition_def(Def, V, Rev);
% legacy
test_bank_card_condition(#domain_BankCardCondition{payment_system_is = Ps}, V, Rev) when Ps /= undefined ->
test_bank_card_condition_def({payment_system_is, Ps}, V, Rev);
test_bank_card_condition(#domain_BankCardCondition{bin_in = RangeRef}, V, Rev) when RangeRef /= undefined ->
test_bank_card_condition_def({bin_in, RangeRef}, V, Rev);
test_bank_card_condition(#domain_BankCardCondition{}, _, _Rev) ->
true.
test_bank_card_condition_def({payment_system_is, Ps}, #domain_BankCard{payment_system = Ps0}, _Rev) ->
Ps =:= Ps0;
test_bank_card_condition({bin_in, RangeRef}, #domain_BankCard{bin = BIN}, Rev) ->
test_bank_card_condition_def({bin_in, RangeRef}, #domain_BankCard{bin = BIN}, Rev) ->
#domain_BankCardBINRange{bins = BINs} = hg_domain:get(Rev, {bank_card_bin_range, RangeRef}),
ordsets:is_element(BIN, BINs).
-include("legacy_structures.hrl").
test_payment_terminal_condition(#domain_PaymentTerminalCondition{definition = Def}, V, Rev) ->
Def =:= undefined orelse test_payment_terminal_condition_def(Def, V, Rev).
test_payment_terminal_condition_def({provider_is, V1}, #domain_PaymentTerminal{terminal_type = V2}, _Rev) ->
V1 =:= V2.
test_digital_wallet_condition(#domain_DigitalWalletCondition{definition = Def}, V, Rev) ->
Def =:= undefined orelse test_digital_wallet_condition_def(Def, V, Rev).
test_digital_wallet_condition_def({provider_is, V1}, #domain_DigitalWallet{provider = V2}, _Rev) ->
V1 =:= V2.
%% Marshalling
-include("legacy_structures.hrl").
-spec marshal(t()) ->
hg_msgpack_marshalling:value().
marshal(PaymentTool) ->
marshal(payment_tool, PaymentTool).
marshal(payment_tool, {bank_card, #domain_BankCard{} = BankCard}) ->
[2, #{
marshal(payment_tool, {PaymentMethod, V}) ->
[3, marshal(payment_method, PaymentMethod), marshal(PaymentMethod, V)];
marshal(bank_card = T, #domain_BankCard{} = BankCard) ->
#{
<<"token">> => marshal(str, BankCard#domain_BankCard.token),
<<"payment_system">> => marshal(payment_system, BankCard#domain_BankCard.payment_system),
<<"payment_system">> => marshal({T, payment_system}, BankCard#domain_BankCard.payment_system),
<<"bin">> => marshal(str, BankCard#domain_BankCard.bin),
<<"masked_pan">> => marshal(str, BankCard#domain_BankCard.masked_pan)
}];
marshal(payment_tool, {payment_terminal, #domain_PaymentTerminal{terminal_type = TerminalType}}) ->
[2, marshal(terminal_type, TerminalType)];
};
marshal(payment_terminal = T, #domain_PaymentTerminal{terminal_type = TerminalType}) ->
marshal({T, type}, TerminalType);
marshal(digital_wallet = T, #domain_DigitalWallet{} = DigitalWallet) ->
#{
<<"provider">> => marshal({T, provider}, DigitalWallet#domain_DigitalWallet.provider),
<<"id">> => marshal(str, DigitalWallet#domain_DigitalWallet.id)
};
marshal(payment_system, visa) ->
marshal(payment_method, bank_card) ->
<<"card">>;
marshal(payment_method, payment_terminal) ->
<<"payterm">>;
marshal(payment_method, digital_wallet) ->
<<"wallet">>;
marshal({bank_card, payment_system}, visa) ->
<<"visa">>;
marshal(payment_system, mastercard) ->
marshal({bank_card, payment_system}, mastercard) ->
<<"mastercard">>;
marshal(payment_system, visaelectron) ->
marshal({bank_card, payment_system}, visaelectron) ->
<<"visaelectron">>;
marshal(payment_system, maestro) ->
marshal({bank_card, payment_system}, maestro) ->
<<"maestro">>;
marshal(payment_system, forbrugsforeningen) ->
marshal({bank_card, payment_system}, forbrugsforeningen) ->
<<"forbrugsforeningen">>;
marshal(payment_system, dankort) ->
marshal({bank_card, payment_system}, dankort) ->
<<"dankort">>;
marshal(payment_system, amex) ->
marshal({bank_card, payment_system}, amex) ->
<<"amex">>;
marshal(payment_system, dinersclub) ->
marshal({bank_card, payment_system}, dinersclub) ->
<<"dinersclub">>;
marshal(payment_system, discover) ->
marshal({bank_card, payment_system}, discover) ->
<<"discover">>;
marshal(payment_system, unionpay) ->
marshal({bank_card, payment_system}, unionpay) ->
<<"unionpay">>;
marshal(payment_system, jcb) ->
marshal({bank_card, payment_system}, jcb) ->
<<"jcb">>;
marshal(payment_system, nspkmir) ->
marshal({bank_card, payment_system}, nspkmir) ->
<<"nspkmir">>;
marshal(terminal_type, euroset) ->
marshal({payment_terminal, type}, euroset) ->
<<"euroset">>;
marshal({digital_wallet, provider}, qiwi) ->
<<"qiwi">>;
marshal(_, Other) ->
Other.
@ -97,61 +146,123 @@ marshal(_, Other) ->
unmarshal(PaymentTool) ->
unmarshal(payment_tool, PaymentTool).
unmarshal(payment_tool, [2, #{
<<"token">> := Token,
<<"payment_system">> := PaymentSystem,
<<"bin">> := Bin,
<<"masked_pan">> := MaskedPan
}]) ->
{bank_card, #domain_BankCard{
token = unmarshal(str, Token),
payment_system = unmarshal(payment_system, PaymentSystem),
bin = unmarshal(str, Bin),
masked_pan = unmarshal(str, MaskedPan)
}};
unmarshal(payment_tool, [3, PMV, V]) ->
PaymentMethod = unmarshal(payment_method, PMV),
{PaymentMethod, unmarshal(PaymentMethod, V)};
unmarshal(bank_card = T, #{
<<"token">> := Token,
<<"payment_system">> := PaymentSystem,
<<"bin">> := Bin,
<<"masked_pan">> := MaskedPan
}) ->
#domain_BankCard{
token = unmarshal(str, Token),
payment_system = unmarshal({T, payment_system}, PaymentSystem),
bin = unmarshal(str, Bin),
masked_pan = unmarshal(str, MaskedPan)
};
unmarshal(payment_terminal = T, TerminalType) ->
#domain_PaymentTerminal{
terminal_type = unmarshal({T, type}, TerminalType)
};
unmarshal(digital_wallet = T, #{
<<"provider">> := Provider,
<<"id">> := ID
}) ->
#domain_DigitalWallet{
provider = unmarshal({T, provider}, Provider),
id = unmarshal(str, ID)
};
unmarshal(payment_tool, [2, #{<<"token">>:= _} = BankCard]) ->
{bank_card, unmarshal(bank_card, BankCard)};
unmarshal(payment_tool, [2, TerminalType]) ->
{payment_terminal, #domain_PaymentTerminal{
terminal_type = unmarshal(terminal_type, TerminalType)
terminal_type = unmarshal({payment_terminal, type}, TerminalType)
}};
unmarshal(payment_tool, [1, ?legacy_bank_card(Token, PaymentSystem, Bin, MaskedPan)]) ->
{bank_card, #domain_BankCard{
token = unmarshal(str, Token),
payment_system = unmarshal(payment_system, PaymentSystem),
payment_system = unmarshal({bank_card, payment_system}, PaymentSystem),
bin = unmarshal(str, Bin),
masked_pan = unmarshal(str, MaskedPan)
}};
unmarshal(payment_system, <<"visa">>) ->
unmarshal(payment_method, <<"card">>) ->
bank_card;
unmarshal(payment_method, <<"payterm">>) ->
payment_terminal;
unmarshal(payment_method, <<"wallet">>) ->
digital_wallet;
unmarshal({bank_card, payment_system}, <<"visa">>) ->
visa;
unmarshal(payment_system, <<"mastercard">>) ->
unmarshal({bank_card, payment_system}, <<"mastercard">>) ->
mastercard;
unmarshal(payment_system, <<"visaelectron">>) ->
unmarshal({bank_card, payment_system}, <<"visaelectron">>) ->
visaelectron;
unmarshal(payment_system, <<"maestro">>) ->
unmarshal({bank_card, payment_system}, <<"maestro">>) ->
maestro;
unmarshal(payment_system, <<"forbrugsforeningen">>) ->
unmarshal({bank_card, payment_system}, <<"forbrugsforeningen">>) ->
forbrugsforeningen;
unmarshal(payment_system, <<"dankort">>) ->
unmarshal({bank_card, payment_system}, <<"dankort">>) ->
dankort;
unmarshal(payment_system, <<"amex">>) ->
unmarshal({bank_card, payment_system}, <<"amex">>) ->
amex;
unmarshal(payment_system, <<"dinersclub">>) ->
unmarshal({bank_card, payment_system}, <<"dinersclub">>) ->
dinersclub;
unmarshal(payment_system, <<"discover">>) ->
unmarshal({bank_card, payment_system}, <<"discover">>) ->
discover;
unmarshal(payment_system, <<"unionpay">>) ->
unmarshal({bank_card, payment_system}, <<"unionpay">>) ->
unionpay;
unmarshal(payment_system, <<"jcb">>) ->
unmarshal({bank_card, payment_system}, <<"jcb">>) ->
jcb;
unmarshal(payment_system, <<"nspkmir">>) ->
unmarshal({bank_card, payment_system}, <<"nspkmir">>) ->
nspkmir;
unmarshal(terminal_type, <<"euroset">>) ->
unmarshal({payment_terminal, type}, <<"euroset">>) ->
euroset;
unmarshal(payment_system, PaymentSystem) when is_atom(PaymentSystem) ->
PaymentSystem;
unmarshal({digital_wallet, provider}, <<"qiwi">>) ->
qiwi;
unmarshal(_, Other) ->
Other.
Other.
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
-spec test() -> _.
-type testcase() :: {_, fun()}.
-spec legacy_unmarshalling_test_() -> [testcase()].
legacy_unmarshalling_test_() ->
PT1 = {bank_card, #domain_BankCard{
token = <<"abcdefabcdefabcdefabcdef">>,
payment_system = nspkmir,
bin = <<"22002201">>,
masked_pan = <<"11">>
}},
PT2 = {payment_terminal, #domain_PaymentTerminal{
terminal_type = euroset
}},
[
?_assertEqual(PT1, unmarshal(legacy_marshal(2, PT1))),
?_assertEqual(PT2, unmarshal(legacy_marshal(2, PT2)))
].
legacy_marshal(_Vsn = 2, {bank_card, #domain_BankCard{} = BankCard}) ->
[2, #{
<<"token">> => marshal(str, BankCard#domain_BankCard.token),
<<"payment_system">> => marshal({bank_card, payment_system}, BankCard#domain_BankCard.payment_system),
<<"bin">> => marshal(str, BankCard#domain_BankCard.bin),
<<"masked_pan">> => marshal(str, BankCard#domain_BankCard.masked_pan)
}];
legacy_marshal(_Vsn = 2, {payment_terminal, #domain_PaymentTerminal{terminal_type = TerminalType}}) ->
[2, marshal({payment_terminal, type}, TerminalType)].
-endif.

View File

@ -32,6 +32,8 @@
}}}).
-define(share(P, Q, C), {share, #domain_CashVolumeShare{parts = #'Rational'{p = P, q = Q}, 'of' = C}}).
-define(share_with_rounding_method(P, Q, C, RM), {share, #domain_CashVolumeShare{parts = #'Rational'{p = P, q = Q}, 'of' = C, 'rounding_method' = RM}}).
-define(cfpost(A1, A2, V),
#domain_CashFlowPosting{
source = A1,

View File

@ -47,13 +47,10 @@
-export([make_invoice_details/1]).
-export([make_invoice_details/2]).
-export([make_disposable_payment_resource/1]).
-export([make_customer_params/3]).
-export([make_customer_binding_params/0]).
-export([make_customer_binding_params/1]).
-export([bank_card_simple_token/0]).
-export([make_bad_payment_tool/0]).
-export([is_bad_payment_tool/1]).
-export([make_disposable_payment_resource/0]).
-export([make_meta_ns/0]).
-export([make_meta_data/0]).
-export([make_meta_data/1]).
@ -583,46 +580,13 @@ make_shop_details(Name, Description) ->
description = Description
}.
-spec bank_card_simple_token() -> string().
-spec make_disposable_payment_resource({dmsl_domain_thrift:'PaymentTool'(), dmsl_domain_thrift:'SessionID'()}) ->
hg_domain_thrift:'DisposablePaymentResource'().
bank_card_simple_token() ->
<<"TOKEN42">>.
-spec make_bad_payment_tool() -> {hg_domain_thrift:'PaymentTool'(), hg_domain_thrift:'PaymentSessionID'()}.
make_bad_payment_tool() ->
{
{bank_card, #domain_BankCard{
token = bank_card_simple_token(),
payment_system = visa,
bin = <<"000000">>,
masked_pan = <<"0000">>
}},
<<"SESSION00">>
}.
-spec is_bad_payment_tool(hg_domain_thrift:'PaymentTool'()) -> boolean().
is_bad_payment_tool(PaymentTool) ->
{BadPaymentTool, _} = make_bad_payment_tool(),
BadPaymentTool =:= PaymentTool.
-spec make_disposable_payment_resource() ->
{
hg_domain_thrift:'PaymentTool'(),
hg_domain_thrift:'PaymentSessionID'(),
hg_domain_thrift:'ClientInfo'()
}.
make_disposable_payment_resource() ->
make_disposable_payment_resource({PaymentTool, SessionID}) ->
#domain_DisposablePaymentResource{
payment_tool = {bank_card, #domain_BankCard{
token = bank_card_simple_token(),
payment_system = visa,
bin = <<"424242">>,
masked_pan = <<"4242">>
}},
payment_session_id = <<"SESSION42">>,
payment_tool = PaymentTool,
payment_session_id = SessionID,
client_info = #domain_ClientInfo{}
}.
@ -660,11 +624,12 @@ make_customer_params(PartyID, ShopID, EMail) ->
metadata = ?null()
}.
-spec make_customer_binding_params() -> dmsl_payment_processing_thrift:'CustomerBindingParams'().
-spec make_customer_binding_params({dmsl_domain_thrift:'PaymentTool'(), dmsl_domain_thrift:'SessionID'()}) ->
dmsl_payment_processing_thrift:'CustomerBindingParams'().
make_customer_binding_params() ->
make_customer_binding_params(PaymentToolSession) ->
#payproc_CustomerBindingParams{
payment_resource = make_disposable_payment_resource()
payment_resource = make_disposable_payment_resource(PaymentToolSession)
}.
%%

View File

@ -230,10 +230,8 @@ start_binding_w_failure(C) ->
CustomerParams = hg_ct_helper:make_customer_params(PartyID, ShopID, cfg(test_case_name, C)),
Customer = hg_client_customer:create(CustomerParams, Client),
#payproc_Customer{id = CustomerID} = Customer,
{PaymentTool, Session} = hg_ct_helper:make_bad_payment_tool(),
CustomerBindingParams = #payproc_CustomerBindingParams{
payment_resource = make_disposable_payment_resource(PaymentTool, Session)
},
CustomerBindingParams =
hg_ct_helper:make_customer_binding_params(hg_dummy_provider:make_payment_tool(forbidden)),
CustomerBinding = hg_client_customer:start_binding(CustomerID, CustomerBindingParams, Client),
Customer1 = hg_client_customer:get(CustomerID, Client),
#payproc_Customer{id = CustomerID, bindings = Bindings} = Customer1,
@ -255,7 +253,8 @@ start_binding(C) ->
CustomerParams = hg_ct_helper:make_customer_params(PartyID, ShopID, cfg(test_case_name, C)),
Customer = hg_client_customer:create(CustomerParams, Client),
#payproc_Customer{id = CustomerID} = Customer,
CustomerBindingParams = hg_ct_helper:make_customer_binding_params(),
CustomerBindingParams =
hg_ct_helper:make_customer_binding_params(hg_dummy_provider:make_payment_tool(no_preauth)),
CustomerBinding = hg_client_customer:start_binding(CustomerID, CustomerBindingParams, Client),
Customer1 = hg_client_customer:get(CustomerID, Client),
#payproc_Customer{id = CustomerID, bindings = Bindings} = Customer1,
@ -278,10 +277,8 @@ start_binding_w_tds(C) ->
CustomerParams = hg_ct_helper:make_customer_params(PartyID, ShopID, cfg(test_case_name, C)),
Customer = hg_client_customer:create(CustomerParams, Client),
#payproc_Customer{id = CustomerID} = Customer,
{PaymentTool, Session} = hg_dummy_provider:make_payment_tool(preauth_3ds),
CustomerBindingParams = #payproc_CustomerBindingParams{
payment_resource = make_disposable_payment_resource(PaymentTool, Session)
},
CustomerBindingParams =
hg_ct_helper:make_customer_binding_params(hg_dummy_provider:make_payment_tool(preauth_3ds)),
CustomerBinding = hg_client_customer:start_binding(CustomerID, CustomerBindingParams, Client),
Customer1 = hg_client_customer:get(CustomerID, Client),
#payproc_Customer{id = CustomerID, bindings = Bindings} = Customer1,
@ -308,7 +305,8 @@ start_two_bindings(C) ->
ShopID = cfg(shop_id, C),
CustomerParams = hg_ct_helper:make_customer_params(PartyID, ShopID, cfg(test_case_name, C)),
#payproc_Customer{id = CustomerID} = hg_client_customer:create(CustomerParams, Client),
CustomerBindingParams = hg_ct_helper:make_customer_binding_params(),
CustomerBindingParams =
hg_ct_helper:make_customer_binding_params(hg_dummy_provider:make_payment_tool(no_preauth)),
CustomerBinding1 = #payproc_CustomerBinding{id = CustomerBindingID1} =
hg_client_customer:start_binding(CustomerID, CustomerBindingParams, Client),
CustomerBinding2 = #payproc_CustomerBinding{id = CustomerBindingID2} =
@ -392,7 +390,8 @@ start_binding_not_permitted(C) ->
CustomerParams = hg_ct_helper:make_customer_params(PartyID, ShopID, cfg(test_case_name, C)),
#payproc_Customer{id = CustomerID} = hg_client_customer:create(CustomerParams, Client),
ok = hg_domain:upsert(construct_domain_fixture(construct_simple_term_set())),
CustomerBindingParams = hg_ct_helper:make_customer_binding_params(),
CustomerBindingParams =
hg_ct_helper:make_customer_binding_params(hg_dummy_provider:make_payment_tool(no_preauth)),
{exception, #payproc_OperationNotPermitted{}} =
hg_client_customer:start_binding(CustomerID, CustomerBindingParams, Client).

View File

@ -133,27 +133,17 @@ handle_function(
% Recurrent tokens
%
generate_token(
undefined,
#prxprv_RecurrentTokenInfo{
payment_tool = #prxprv_RecurrentPaymentTool{
payment_resource = #domain_DisposablePaymentResource{
payment_tool = PaymentTool
}
}
},
_Opts
) ->
case hg_ct_helper:is_bad_payment_tool(PaymentTool) of
true ->
generate_token(undefined, #prxprv_RecurrentTokenInfo{payment_tool = RecurrentPaytool}, _Opts) ->
case get_recurrent_paytool_scenario(RecurrentPaytool) of
forbidden ->
#prxprv_RecurrentTokenProxyResult{
intent = ?recurrent_token_finish_w_failure(#'Failure'{code = <<"badparams">>})
intent = ?recurrent_token_finish_w_failure(#'Failure'{code = <<"forbidden">>})
};
false ->
_ ->
token_sleep(1, <<"sleeping">>)
end;
generate_token(<<"sleeping">>, #prxprv_RecurrentTokenInfo{payment_tool = PaymentTool}, _Opts) ->
case get_recurrent_paytool_scenario(PaymentTool) of
generate_token(<<"sleeping">>, #prxprv_RecurrentTokenInfo{payment_tool = RecurrentPaytool}, _Opts) ->
case get_recurrent_paytool_scenario(RecurrentPaytool) of
preauth_3ds ->
Tag = generate_recurent_tag(),
Uri = get_callback_url(),
@ -245,6 +235,9 @@ process_payment(?processed(), undefined, PaymentInfo, _) ->
due = get_invoice_due_date(PaymentInfo)
}},
suspend(SPID, 2, <<"suspended">>, UserInteraction);
digital_wallet ->
%% simple workflow
sleep(1, <<"sleeping">>);
recurrent ->
%% simple workflow without 3DS
sleep(1, <<"sleeping">>)
@ -343,30 +336,43 @@ get_recurrent_paytool_scenario(#prxprv_RecurrentPaymentTool{payment_resource = P
PaymentTool = get_payment_tool(PaymentResource),
get_payment_tool_scenario(PaymentTool).
get_payment_tool_scenario({'bank_card', #domain_BankCard{token = <<"no_preauth">>}}) ->
no_preauth;
get_payment_tool_scenario({'bank_card', #domain_BankCard{token = <<"preauth_3ds">>}}) ->
preauth_3ds;
get_payment_tool_scenario({'bank_card', #domain_BankCard{token = <<"preauth_3ds_offsite">>}}) ->
preauth_3ds_offsite;
get_payment_tool_scenario({'bank_card', _}) ->
no_preauth;
get_payment_tool_scenario({'bank_card', #domain_BankCard{token = <<"forbidden">>}}) ->
forbidden;
get_payment_tool_scenario({'payment_terminal', #domain_PaymentTerminal{terminal_type = euroset}}) ->
terminal.
terminal;
get_payment_tool_scenario({'digital_wallet', #domain_DigitalWallet{provider = qiwi}}) ->
digital_wallet.
-spec make_payment_tool(atom()) -> {hg_domain_thrift:'PaymentTool'(), hg_domain_thrift:'PaymentSessionID'()}.
make_payment_tool(no_preauth) ->
make_simple_payment_tool(<<"no_preauth">>, visa);
make_payment_tool(preauth_3ds) ->
construct_payment_tool_and_session(<<"preauth_3ds">>, visa, <<"666666">>, <<"666">>, <<"SESSION666">>);
make_simple_payment_tool(<<"preauth_3ds">>, visa);
make_payment_tool(preauth_3ds_offsite) ->
make_simple_payment_tool(<<"preauth_3ds_offsite">>, jcb);
make_payment_tool(no_preauth) ->
Token = <<"no_preauth">>,
make_simple_payment_tool(Token, visa);
make_payment_tool(forbidden) ->
make_simple_payment_tool(<<"forbidden">>, visa);
make_payment_tool(terminal) ->
{
{payment_terminal, #domain_PaymentTerminal{
terminal_type = euroset
}},
<<"">>
<<>>
};
make_payment_tool(digital_wallet) ->
{
{digital_wallet, #domain_DigitalWallet{
provider = qiwi,
id = <<"+79876543210">>
}},
<<>>
}.
make_simple_payment_tool(Token, PaymentSystem) ->

View File

@ -537,6 +537,7 @@ construct_domain_fixture() ->
hg_ct_fixture:construct_payment_method(?pmt(bank_card, visa)),
hg_ct_fixture:construct_payment_method(?pmt(bank_card, mastercard)),
hg_ct_fixture:construct_payment_method(?pmt(payment_terminal, euroset)),
hg_ct_fixture:construct_payment_method(?pmt(digital_wallet, qiwi)),
{payment_institution, #domain_PaymentInstitutionObject{
ref = ?pinst(1),

View File

@ -32,6 +32,7 @@
-export([payment_success/1]).
-export([payment_w_terminal_success/1]).
-export([payment_w_wallet_success/1]).
-export([payment_w_customer_success/1]).
-export([payment_w_incorrect_customer/1]).
-export([payment_w_deleted_customer/1]).
@ -48,6 +49,7 @@
-export([payment_hold_capturing/1]).
-export([payment_hold_auto_capturing/1]).
-export([payment_refund_success/1]).
-export([rounding_cashflow_volume/1]).
-export([payment_with_offsite_preauth_success/1]).
-export([payment_with_offsite_preauth_failed/1]).
-export([terms_retrieval/1]).
@ -93,6 +95,7 @@ all() ->
invalid_payment_amount,
payment_success,
payment_w_terminal_success,
payment_w_wallet_success,
payment_w_customer_success,
payment_w_incorrect_customer,
payment_w_deleted_customer,
@ -112,6 +115,7 @@ all() ->
payment_refund_success,
rounding_cashflow_volume,
{group, offsite_preauth_payment},
terms_retrieval,
@ -225,9 +229,15 @@ end_per_group(_Group, _C) ->
-spec init_per_testcase(test_case_name(), config()) -> config().
init_per_testcase(payment_adjustment_success, C) ->
init_per_testcase(Name, C) when Name == payment_adjustment_success; Name == rounding_cashflow_volume ->
Revision = hg_domain:head(),
ok = hg_domain:upsert(get_adjustment_fixture(Revision)),
Fixture = case Name of
payment_adjustment_success ->
get_adjustment_fixture(Revision);
rounding_cashflow_volume ->
get_cashflow_rounding_fixture(Revision)
end,
ok = hg_domain:upsert(Fixture),
[{original_domain_revision, Revision} | init_per_testcase(C)];
init_per_testcase(_Name, C) ->
init_per_testcase(C).
@ -520,6 +530,19 @@ payment_w_terminal_success(C) ->
[?payment_state(?payment_w_status(PaymentID, ?captured()))]
) = hg_client_invoicing:get(InvoiceID, Client).
-spec payment_w_wallet_success(config()) -> _ | no_return().
payment_w_wallet_success(C) ->
Client = cfg(client, C),
InvoiceID = start_invoice(<<"bubbleblob">>, make_due_date(10), 42000, C),
PaymentParams = make_wallet_payment_params(),
PaymentID = process_payment(InvoiceID, PaymentParams, Client),
PaymentID = await_payment_capture(InvoiceID, PaymentID, Client),
?invoice_state(
?invoice_w_status(?invoice_paid()),
[?payment_state(?payment_w_status(PaymentID, ?captured()))]
) = hg_client_invoicing:get(InvoiceID, Client).
-spec payment_w_customer_success(config()) -> test_return().
payment_w_customer_success(C) ->
@ -979,6 +1002,93 @@ payment_hold_auto_capturing(C) ->
_ = assert_invalid_post_request(get_post_request(UserInteraction)),
PaymentID = await_payment_capture(InvoiceID, PaymentID, undefined, Client).
-spec rounding_cashflow_volume(config()) -> _ | no_return().
rounding_cashflow_volume(C) ->
Client = cfg(client, C),
InvoiceID = start_invoice(<<"rubberduck">>, make_due_date(10), 100000, C),
PaymentParams = make_payment_params(),
?payment_state(?payment(PaymentID)) = hg_client_invoicing:start_payment(InvoiceID, PaymentParams, Client),
[
?payment_ev(PaymentID, ?payment_started(?payment_w_status(?pending()), _, _, CF)),
?payment_ev(PaymentID, ?session_ev(?processed(), ?session_started()))
] = next_event(InvoiceID, Client),
?cash(0, <<"RUB">>) = get_cashflow_volume({provider, settlement}, {merchant, settlement}, CF),
?cash(1, <<"RUB">>) = get_cashflow_volume({system, settlement}, {provider, settlement}, CF),
?cash(1, <<"RUB">>) = get_cashflow_volume({system, settlement}, {external, outcome}, CF).
get_cashflow_rounding_fixture(Revision) ->
PaymentInstituition = hg_domain:get(Revision, {payment_institution, ?pinst(1)}),
[
{payment_institution, #domain_PaymentInstitutionObject{
ref = ?pinst(1),
data = PaymentInstituition#domain_PaymentInstitution{
providers = {value, ?ordset([
?prv(100)
])}
}}
},
{provider, #domain_ProviderObject{
ref = ?prv(100),
data = #domain_Provider{
name = <<"Rounding">>,
description = <<>>,
abs_account = <<>>,
terminal = {value, [?trm(100)]},
proxy = #domain_Proxy{ref = ?prx(1), additional = #{}},
accounts = hg_ct_fixture:construct_provider_account_set([?cur(<<"RUB">>)]),
payment_terms = #domain_PaymentsProvisionTerms{
currencies = {value, ?ordset([
?cur(<<"RUB">>)
])},
categories = {value, ?ordset([
?cat(1)
])},
cash_limit = {value, ?cashrng(
{inclusive, ?cash( 1000, <<"RUB">>)},
{exclusive, ?cash(100000000, <<"RUB">>)}
)},
payment_methods = {value, ?ordset([
?pmt(bank_card, visa)
])},
cash_flow = {value, [
?cfpost(
{provider, settlement},
{merchant, settlement},
?share_with_rounding_method(1, 200000, payment_amount, round_half_towards_zero)
),
?cfpost(
{system, settlement},
{provider, settlement},
?share_with_rounding_method(1, 200000, payment_amount, round_half_away_from_zero)
),
?cfpost(
{system, settlement},
{external, outcome},
?share(1, 200000, payment_amount)
)
]}
}
}
}},
{terminal, #domain_TerminalObject{
ref = ?trm(100),
data = #domain_Terminal{
name = <<"Rounding Terminal">>,
description = <<>>,
risk_coverage = low
}
}}
].
get_cashflow_volume(Source, Destination, CF) ->
[Volume] = [V || #domain_FinalCashFlowPosting{
source = #domain_FinalCashFlowAccount{account_type = S},
destination = #domain_FinalCashFlowAccount{account_type = D},
volume = V
} <- CF, S == Source, D == Destination],
Volume.
%%
-spec terms_retrieval(config()) -> _ | no_return().
@ -992,6 +1102,7 @@ terms_retrieval(C) ->
?pmt(bank_card, jcb),
?pmt(bank_card, mastercard),
?pmt(bank_card, visa),
?pmt(digital_wallet, qiwi),
?pmt(payment_terminal, euroset)
]}
}} = TermSet1,
@ -1188,6 +1299,10 @@ make_terminal_payment_params() ->
{PaymentTool, Session} = hg_dummy_provider:make_payment_tool(terminal),
make_payment_params(PaymentTool, Session, instant).
make_wallet_payment_params() ->
{PaymentTool, Session} = hg_dummy_provider:make_payment_tool(digital_wallet),
make_payment_params(PaymentTool, Session, instant).
make_tds_payment_params() ->
make_tds_payment_params(instant).
@ -1350,7 +1465,11 @@ make_customer_w_rec_tool(PartyID, ShopID, Client) ->
#payproc_Customer{id = CustomerID} =
hg_client_customer:create(CustomerParams, Client),
#payproc_CustomerBinding{id = BindingID} =
hg_client_customer:start_binding(CustomerID, hg_ct_helper:make_customer_binding_params(), Client),
hg_client_customer:start_binding(
CustomerID,
hg_ct_helper:make_customer_binding_params(hg_dummy_provider:make_payment_tool(no_preauth)),
Client
),
ok = wait_for_binding_success(CustomerID, BindingID, Client),
CustomerID.
@ -1401,7 +1520,8 @@ construct_domain_fixture() ->
?pmt(bank_card, visa),
?pmt(bank_card, mastercard),
?pmt(bank_card, jcb),
?pmt(payment_terminal, euroset)
?pmt(payment_terminal, euroset),
?pmt(digital_wallet, qiwi)
])}
}
]},
@ -1545,6 +1665,7 @@ construct_domain_fixture() ->
hg_ct_fixture:construct_payment_method(?pmt(bank_card, mastercard)),
hg_ct_fixture:construct_payment_method(?pmt(bank_card, jcb)),
hg_ct_fixture:construct_payment_method(?pmt(payment_terminal, euroset)),
hg_ct_fixture:construct_payment_method(?pmt(digital_wallet, qiwi)),
hg_ct_fixture:construct_proxy(?prx(1), <<"Dummy proxy">>),
hg_ct_fixture:construct_proxy(?prx(2), <<"Inspector proxy">>),
@ -1695,6 +1816,7 @@ construct_domain_fixture() ->
}]
}
}},
{provider, #domain_ProviderObject{
ref = ?prv(1),
data = #domain_Provider{
@ -1729,7 +1851,9 @@ construct_domain_fixture() ->
)},
cash_flow = {decisions, [
#domain_CashFlowDecision{
if_ = {condition, {payment_tool, {bank_card, {payment_system_is, visa}}}},
if_ = {condition, {payment_tool, {bank_card, #domain_BankCardCondition{
definition = {payment_system_is, visa}
}}}},
then_ = {value, [
?cfpost(
{provider, settlement},
@ -1744,7 +1868,9 @@ construct_domain_fixture() ->
]}
},
#domain_CashFlowDecision{
if_ = {condition, {payment_tool, {bank_card, {payment_system_is, mastercard}}}},
if_ = {condition, {payment_tool, {bank_card, #domain_BankCardCondition{
definition = {payment_system_is, mastercard}
}}}},
then_ = {value, [
?cfpost(
{provider, settlement},
@ -1759,7 +1885,9 @@ construct_domain_fixture() ->
]}
},
#domain_CashFlowDecision{
if_ = {condition, {payment_tool, {bank_card, {payment_system_is, jcb}}}},
if_ = {condition, {payment_tool, {bank_card, #domain_BankCardCondition{
definition = {payment_system_is, jcb}
}}}},
then_ = {value, [
?cfpost(
{provider, settlement},
@ -1777,7 +1905,9 @@ construct_domain_fixture() ->
holds = #domain_PaymentHoldsProvisionTerms{
lifetime = {decisions, [
#domain_HoldLifetimeDecision{
if_ = {condition, {payment_tool, {bank_card, {payment_system_is, visa}}}},
if_ = {condition, {payment_tool, {bank_card, #domain_BankCardCondition{
payment_system_is = visa
}}}},
then_ = {value, ?hold_lifetime(5)}
}
]}
@ -1810,6 +1940,7 @@ construct_domain_fixture() ->
risk_coverage = high
}
}},
{provider, #domain_ProviderObject{
ref = ?prv(2),
data = #domain_Provider{
@ -1912,6 +2043,7 @@ construct_domain_fixture() ->
risk_coverage = high
}
}},
{provider, #domain_ProviderObject{
ref = ?prv(3),
data = #domain_Provider{
@ -1934,7 +2066,8 @@ construct_domain_fixture() ->
?cat(1)
])},
payment_methods = {value, ?ordset([
?pmt(payment_terminal, euroset)
?pmt(payment_terminal, euroset),
?pmt(digital_wallet, qiwi)
])},
cash_limit = {value, ?cashrng(
{inclusive, ?cash( 1000, <<"RUB">>)},
@ -1963,6 +2096,7 @@ construct_domain_fixture() ->
risk_coverage = low
}
}}
].
construct_term_set_for_cost(LowerBound, UpperBound) ->

View File

@ -312,7 +312,7 @@ recurrent_paytool_creation_not_permitted(C) ->
%%
make_bad_recurrent_paytool_params(PartyID, ShopID) ->
{PaymentTool, Session} = hg_ct_helper:make_bad_payment_tool(),
{PaymentTool, Session} = hg_dummy_provider:make_payment_tool(forbidden),
PaymentResource = make_disposable_payment_resource(PaymentTool, Session),
#payproc_RecurrentPaymentToolParams{
party_id = PartyID,

View File

@ -17,7 +17,7 @@ services:
condition: service_healthy
dominant:
image: dr.rbkmoney.com/rbkmoney/dominant:3a58d9d20c6229002d8744bbd1745869fe5695f8
image: dr.rbkmoney.com/rbkmoney/dominant:68d75c0d8523a150a68852de4572ad1c1ee140ef
command: /opt/dominant/bin/dominant foreground
depends_on:
machinegun:
@ -32,7 +32,7 @@ services:
test: "curl http://localhost:8022/"
interval: 5s
timeout: 1s
retries: 12
retries: 20
shumway:
image: dr.rbkmoney.com/rbkmoney/shumway:7a5f95ee1e8baa42fdee9c08cc0ae96cd7187d55
@ -51,7 +51,7 @@ services:
test: "curl http://localhost:8022/"
interval: 5s
timeout: 1s
retries: 12
retries: 20
shumway-db:
image: dr.rbkmoney.com/rbkmoney/postgres:9.6

View File

@ -4,7 +4,7 @@
{<<"cowlib">>,{pkg,<<"cowlib">>,<<"1.0.2">>},2},
{<<"dmsl">>,
{git,"git@github.com:rbkmoney/damsel.git",
{ref,"07fbb3057e78e37611e642160a7201fe31d6ff69"}},
{ref,"4ca2329c564b3730dbd742ae370be9919905b9de"}},
0},
{<<"dmt_client">>,
{git,"git@github.com:rbkmoney/dmt_client.git",
@ -16,7 +16,7 @@
1},
{<<"genlib">>,
{git,"https://github.com/rbkmoney/genlib.git",
{ref,"7fc1ca1a57dbe2b8b837951095e314c32afd6c9a"}},
{ref,"3e5690def4297e9c5d00ace6ae9995ea9fac525e"}},
0},
{<<"goldrush">>,{pkg,<<"goldrush">>,<<"0.1.8">>},1},
{<<"gproc">>,{pkg,<<"gproc">>,<<"0.6.1">>},0},