mirror of
https://github.com/valitydev/fistful-server.git
synced 2024-11-06 02:35:18 +00:00
FF-210: W2W via Thrift (#286)
This commit is contained in:
parent
6e93682e1b
commit
1d94dd0ff6
@ -129,6 +129,7 @@ start_app(wapi_woody_client = AppName) ->
|
||||
fistful_wallet => "http://localhost:8022/v1/wallet",
|
||||
fistful_identity => "http://localhost:8022/v1/identity",
|
||||
fistful_destination => "http://localhost:8022/v1/destination",
|
||||
w2w_transfer => "http://localhost:8022/v1/w2w_transfer",
|
||||
fistful_withdrawal => "http://localhost:8022/v1/withdrawal"
|
||||
}},
|
||||
{service_retries, #{
|
||||
|
@ -3,13 +3,15 @@
|
||||
-include_lib("fistful_proto/include/ff_proto_identity_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/ff_proto_wallet_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/ff_proto_destination_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/ff_proto_w2w_transfer_thrift.hrl").
|
||||
-include_lib("fistful_proto/include/ff_proto_withdrawal_thrift.hrl").
|
||||
|
||||
-export([check_resource/3]).
|
||||
-export([check_resource_by_id/3]).
|
||||
|
||||
-type id() :: binary().
|
||||
-type resource_type() :: identity | wallet | destination | withdrawal.
|
||||
-type resource_type() :: identity | wallet | destination | w2w_transfer | withdrawal.
|
||||
|
||||
-type handler_context() :: wapi_handler:context().
|
||||
-type data() ::
|
||||
ff_proto_identity_thrift:'IdentityState'() |
|
||||
@ -66,6 +68,14 @@ get_context_by_id(destination, DestinationID, WoodyCtx) ->
|
||||
{exception, #fistful_DestinationNotFound{}} ->
|
||||
{error, notfound}
|
||||
end;
|
||||
get_context_by_id(w2w_transfer, W2WTransferID, WoodyCtx) ->
|
||||
Request = {w2w_transfer, 'GetContext', [W2WTransferID]},
|
||||
case wapi_handler_utils:service_call(Request, WoodyCtx) of
|
||||
{ok, Context} ->
|
||||
Context;
|
||||
{exception, #fistful_W2WNotFound{}} ->
|
||||
{error, notfound}
|
||||
end;
|
||||
get_context_by_id(withdrawal, WithdrawalID, WoodyCtx) ->
|
||||
Request = {fistful_withdrawal, 'GetContext', [WithdrawalID]},
|
||||
case wapi_handler_utils:service_call(Request, WoodyCtx) of
|
||||
@ -81,6 +91,8 @@ get_context_from_state(wallet, #wlt_WalletState{context = Context}) ->
|
||||
Context;
|
||||
get_context_from_state(destination, #dst_DestinationState{context = Context}) ->
|
||||
Context;
|
||||
get_context_from_state(w2w_transfer, #w2w_transfer_W2WTransferState{context = Context}) ->
|
||||
Context;
|
||||
get_context_from_state(withdrawal, #wthd_WithdrawalState{context = Context}) ->
|
||||
Context.
|
||||
|
||||
|
165
apps/wapi/src/wapi_w2w_backend.erl
Normal file
165
apps/wapi/src/wapi_w2w_backend.erl
Normal file
@ -0,0 +1,165 @@
|
||||
-module(wapi_w2w_backend).
|
||||
|
||||
-type req_data() :: wapi_handler:req_data().
|
||||
-type handler_context() :: wapi_handler:context().
|
||||
-type response_data() :: wapi_handler:response_data().
|
||||
|
||||
-type id() :: binary().
|
||||
-type external_id() :: id().
|
||||
|
||||
-export([create_transfer/2]).
|
||||
-export([get_transfer/2]).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_w2w_transfer_thrift.hrl").
|
||||
|
||||
-spec create_transfer(req_data(), handler_context()) ->
|
||||
{ok, response_data()} | {error, CreateError}
|
||||
when
|
||||
CreateError ::
|
||||
{external_id_conflict, external_id()} |
|
||||
{wallet_from, unauthorized} |
|
||||
{wallet_from | wallet_to, notfound} |
|
||||
bad_w2w_transfer_amount |
|
||||
not_allowed_currency |
|
||||
inconsistent_currency.
|
||||
|
||||
create_transfer(Params = #{<<"sender">> := SenderID}, HandlerContext) ->
|
||||
case wapi_access_backend:check_resource_by_id(wallet, SenderID, HandlerContext) of
|
||||
ok ->
|
||||
case wapi_backend_utils:gen_id(w2w_transfer, Params, HandlerContext) of
|
||||
{ok, ID} ->
|
||||
Context = wapi_backend_utils:make_ctx(Params, HandlerContext),
|
||||
create_transfer(ID, Params, Context, HandlerContext);
|
||||
{error, {external_id_conflict, _}} = Error ->
|
||||
Error
|
||||
end;
|
||||
{error, unauthorized} ->
|
||||
{error, {wallet_from, unauthorized}}
|
||||
end.
|
||||
|
||||
create_transfer(ID, Params, Context, HandlerContext) ->
|
||||
TransferParams = marshal(transfer_params, Params#{<<"id">> => ID}),
|
||||
Request = {w2w_transfer, 'Create', [TransferParams, marshal(context, Context)]},
|
||||
case service_call(Request, HandlerContext) of
|
||||
{ok, Transfer} ->
|
||||
{ok, unmarshal(transfer, Transfer)};
|
||||
{exception, #fistful_WalletNotFound{id = ID}} ->
|
||||
{error, wallet_not_found_error(unmarshal(id, ID), Params)};
|
||||
{exception, #fistful_ForbiddenOperationCurrency{}} ->
|
||||
{error, not_allowed_currency};
|
||||
{exception, #w2w_transfer_InconsistentW2WTransferCurrency{}} ->
|
||||
{error, inconsistent_currency};
|
||||
{exception, #fistful_InvalidOperationAmount{}} ->
|
||||
{error, bad_w2w_transfer_amount}
|
||||
end.
|
||||
|
||||
-spec get_transfer(req_data(), handler_context()) ->
|
||||
{ok, response_data()} | {error, GetError}
|
||||
when
|
||||
GetError ::
|
||||
{w2w_transfer, unauthorized} |
|
||||
{w2w_transfer, {unknown_w2w_transfer, id()}}.
|
||||
|
||||
get_transfer(ID, HandlerContext) ->
|
||||
EventRange = #'EventRange'{},
|
||||
Request = {w2w_transfer, 'Get', [ID, EventRange]},
|
||||
case service_call(Request, HandlerContext) of
|
||||
{ok, TransferThrift} ->
|
||||
case wapi_access_backend:check_resource(w2w_transfer, TransferThrift, HandlerContext) of
|
||||
ok ->
|
||||
{ok, unmarshal(transfer, TransferThrift)};
|
||||
{error, unauthorized} ->
|
||||
{error, {w2w_transfer, unauthorized}}
|
||||
end;
|
||||
{exception, #fistful_W2WNotFound{}} ->
|
||||
{error, {w2w_transfer, {unknown_w2w_transfer, ID}}}
|
||||
end.
|
||||
|
||||
%%
|
||||
%% Internal
|
||||
%%
|
||||
|
||||
service_call(Params, Ctx) ->
|
||||
wapi_handler_utils:service_call(Params, Ctx).
|
||||
|
||||
wallet_not_found_error(WalletID, #{<<"sender">> := WalletID}) ->
|
||||
{wallet_from, notfound};
|
||||
wallet_not_found_error(WalletID, #{<<"receiver">> := WalletID}) ->
|
||||
{wallet_to, notfound}.
|
||||
|
||||
%% Marshaling
|
||||
|
||||
marshal(transfer_params, #{
|
||||
<<"id">> := ID,
|
||||
<<"sender">> := SenderID,
|
||||
<<"receiver">> := ReceiverID,
|
||||
<<"body">> := Body
|
||||
} = Params) ->
|
||||
#w2w_transfer_W2WTransferParams{
|
||||
id = marshal(id, ID),
|
||||
wallet_from_id = marshal(id, SenderID),
|
||||
wallet_to_id = marshal(id, ReceiverID),
|
||||
body = marshal(body, Body),
|
||||
external_id = maps:get(<<"externalId">>, Params, undefined)
|
||||
};
|
||||
|
||||
marshal(body, #{
|
||||
<<"amount">> := Amount,
|
||||
<<"currency">> := Currency
|
||||
}) ->
|
||||
#'Cash'{
|
||||
amount = marshal(amount, Amount),
|
||||
currency = marshal(currency_ref, Currency)
|
||||
};
|
||||
|
||||
marshal(context, Ctx) ->
|
||||
ff_codec:marshal(context, Ctx);
|
||||
|
||||
marshal(T, V) ->
|
||||
ff_codec:marshal(T, V).
|
||||
|
||||
unmarshal(transfer, #w2w_transfer_W2WTransferState{
|
||||
id = ID,
|
||||
wallet_from_id = SenderID,
|
||||
wallet_to_id = ReceiverID,
|
||||
body = Body,
|
||||
created_at = CreatedAt,
|
||||
status = Status,
|
||||
external_id = ExternalID
|
||||
}) ->
|
||||
genlib_map:compact(#{
|
||||
<<"id">> => unmarshal(id, ID),
|
||||
<<"createdAt">> => CreatedAt,
|
||||
<<"body">> => unmarshal(body, Body),
|
||||
<<"sender">> => unmarshal(id, SenderID),
|
||||
<<"receiver">> => unmarshal(id, ReceiverID),
|
||||
<<"status">> => unmarshal(transfer_status, Status),
|
||||
<<"externalID">> => maybe_unmarshal(id, ExternalID)
|
||||
});
|
||||
|
||||
unmarshal(body, #'Cash'{
|
||||
amount = Amount,
|
||||
currency = Currency
|
||||
}) ->
|
||||
#{
|
||||
<<"amount">> => unmarshal(amount, Amount),
|
||||
<<"currency">> => unmarshal(currency_ref, Currency)
|
||||
};
|
||||
|
||||
unmarshal(transfer_status, {pending, _}) ->
|
||||
#{<<"status">> => <<"Pending">>};
|
||||
unmarshal(transfer_status, {succeeded, _}) ->
|
||||
#{<<"status">> => <<"Succeeded">>};
|
||||
unmarshal(transfer_status, {failed, #w2w_status_Failed{failure = Failure}}) ->
|
||||
#{
|
||||
<<"status">> => <<"Failed">>,
|
||||
<<"failure">> => unmarshal(failure, Failure)
|
||||
};
|
||||
|
||||
unmarshal(T, V) ->
|
||||
ff_codec:unmarshal(T, V).
|
||||
|
||||
maybe_unmarshal(_T, undefined) ->
|
||||
undefined;
|
||||
maybe_unmarshal(T, V) ->
|
||||
unmarshal(T, V).
|
@ -366,6 +366,42 @@ process_request('ListDeposits', Params, Context, _Opts) ->
|
||||
})
|
||||
end;
|
||||
|
||||
%% W2W
|
||||
|
||||
process_request('CreateW2WTransfer', #{'W2WTransferParameters' := Params}, Context, _Opts) ->
|
||||
case wapi_w2w_backend:create_transfer(Params, Context) of
|
||||
{ok, W2WTransfer} ->
|
||||
wapi_handler_utils:reply_ok(202, W2WTransfer);
|
||||
{error, {wallet_from, notfound}} ->
|
||||
wapi_handler_utils:reply_ok(422,
|
||||
wapi_handler_utils:get_error_msg(<<"No such wallet sender">>));
|
||||
{error, {wallet_from, unauthorized}} ->
|
||||
wapi_handler_utils:reply_ok(422,
|
||||
wapi_handler_utils:get_error_msg(<<"No such wallet sender">>));
|
||||
{error, {wallet_to, notfound}} ->
|
||||
wapi_handler_utils:reply_ok(422,
|
||||
wapi_handler_utils:get_error_msg(<<"No such wallet receiver">>));
|
||||
{error, not_allowed_currency} ->
|
||||
wapi_handler_utils:reply_ok(422,
|
||||
wapi_handler_utils:get_error_msg(<<"Currency not allowed">>));
|
||||
{error, bad_w2w_transfer_amount} ->
|
||||
wapi_handler_utils:reply_ok(422,
|
||||
wapi_handler_utils:get_error_msg(<<"Bad transfer amount">>));
|
||||
{error, inconsistent_currency} ->
|
||||
wapi_handler_utils:reply_ok(422,
|
||||
wapi_handler_utils:get_error_msg(<<"Inconsistent currency">>))
|
||||
end;
|
||||
|
||||
process_request('GetW2WTransfer', #{w2wTransferID := ID}, Context, _Opts) ->
|
||||
case wapi_w2w_backend:get_transfer(ID, Context) of
|
||||
{ok, W2WTransfer} ->
|
||||
wapi_handler_utils:reply_ok(200, W2WTransfer);
|
||||
{error, {w2w_transfer, unauthorized}} ->
|
||||
wapi_handler_utils:reply_ok(404);
|
||||
{error, {w2w_transfer, {unknown_w2w_transfer, _ID}}} ->
|
||||
wapi_handler_utils:reply_ok(404)
|
||||
end;
|
||||
|
||||
process_request(OperationID, Params, Context, Opts) ->
|
||||
wapi_wallet_handler:process_request(OperationID, Params, Context, Opts).
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
-export([identity_check_test/1]).
|
||||
-export([identity_challenge_check_test/1]).
|
||||
-export([destination_check_test/1]).
|
||||
-export([w2w_transfer_check_test/1]).
|
||||
-export([withdrawal_check_test/1]).
|
||||
|
||||
% common-api is used since it is the domain used in production RN
|
||||
@ -46,6 +47,7 @@ groups() ->
|
||||
identity_challenge_check_test,
|
||||
wallet_check_test,
|
||||
destination_check_test,
|
||||
w2w_transfer_check_test,
|
||||
withdrawal_check_test
|
||||
]}
|
||||
].
|
||||
@ -169,6 +171,24 @@ destination_check_test(C) ->
|
||||
DestinationID2 = create_destination(IdentityID2, C),
|
||||
?assertEqual(Keys, maps:keys(get_destination(DestinationID2, C))).
|
||||
|
||||
-spec w2w_transfer_check_test(config()) -> test_return().
|
||||
|
||||
w2w_transfer_check_test(C) ->
|
||||
Name = <<"Keyn Fawkes">>,
|
||||
Provider = ?ID_PROVIDER,
|
||||
Class = ?ID_CLASS,
|
||||
IdentityID1 = create_identity(Name, Provider, Class, C),
|
||||
WalletID11 = create_wallet(IdentityID1, C),
|
||||
WalletID12 = create_wallet(IdentityID1, C),
|
||||
W2WTransferID1 = create_w2w_transfer(WalletID11, WalletID12, C),
|
||||
Keys = maps:keys(get_w2w_transfer(W2WTransferID1, C)),
|
||||
ok = application:set_env(wapi, transport, thrift),
|
||||
IdentityID2 = create_identity(Name, Provider, Class, C),
|
||||
WalletID21 = create_wallet(IdentityID2, C),
|
||||
WalletID22 = create_wallet(IdentityID2, C),
|
||||
W2WTransferID2 = create_w2w_transfer(WalletID21, WalletID22, C),
|
||||
?assertEqual(Keys, maps:keys(get_w2w_transfer(W2WTransferID2, C))).
|
||||
|
||||
-spec withdrawal_check_test(config()) -> test_return().
|
||||
|
||||
withdrawal_check_test(C) ->
|
||||
@ -357,6 +377,30 @@ get_destination(DestinationID, C) ->
|
||||
),
|
||||
Destination.
|
||||
|
||||
create_w2w_transfer(WalletID1, WalletID2, C) ->
|
||||
DefaultParams = #{
|
||||
<<"sender">> => WalletID1,
|
||||
<<"receiver">> => WalletID2,
|
||||
<<"body">> => #{
|
||||
<<"amount">> => 1000,
|
||||
<<"currency">> => ?RUB
|
||||
}
|
||||
},
|
||||
{ok, W2WTransfer} = call_api(
|
||||
fun swag_client_wallet_w2_w_api:create_w2_w_transfer/3,
|
||||
#{body => DefaultParams},
|
||||
ct_helper:cfg(context, C)
|
||||
),
|
||||
maps:get(<<"id">>, W2WTransfer).
|
||||
|
||||
get_w2w_transfer(W2WTransferID2, C) ->
|
||||
{ok, W2WTransfer} = call_api(
|
||||
fun swag_client_wallet_w2_w_api:get_w2_w_transfer/3,
|
||||
#{binding => #{<<"w2wTransferID">> => W2WTransferID2}},
|
||||
ct_helper:cfg(context, C)
|
||||
),
|
||||
W2WTransfer.
|
||||
|
||||
await_destination(DestID) ->
|
||||
authorized = ct_helper:await(
|
||||
authorized,
|
||||
@ -466,6 +510,39 @@ get_default_termset() ->
|
||||
]}
|
||||
}
|
||||
]}
|
||||
},
|
||||
w2w = #domain_W2WServiceTerms{
|
||||
currencies = {value, ?ordset([?cur(<<"RUB">>), ?cur(<<"USD">>)])},
|
||||
allow = {constant, true},
|
||||
cash_limit = {decisions, [
|
||||
#domain_CashLimitDecision{
|
||||
if_ = {condition, {currency_is, ?cur(<<"RUB">>)}},
|
||||
then_ = {value, ?cashrng(
|
||||
{inclusive, ?cash( 0, <<"RUB">>)},
|
||||
{exclusive, ?cash(10001, <<"RUB">>)}
|
||||
)}
|
||||
}
|
||||
]},
|
||||
cash_flow = {decisions, [
|
||||
#domain_CashFlowDecision{
|
||||
if_ = {condition, {currency_is, ?cur(<<"RUB">>)}},
|
||||
then_ = {value, [
|
||||
?cfpost(
|
||||
{wallet, sender_settlement},
|
||||
{wallet, receiver_settlement},
|
||||
?share(1, 1, operation_amount)
|
||||
)
|
||||
]}
|
||||
}
|
||||
]},
|
||||
fees = {decisions, [
|
||||
#domain_FeeDecision{
|
||||
if_ = {condition, {currency_is, ?cur(<<"RUB">>)}},
|
||||
then_ = {value, #domain_Fees{
|
||||
fees = #{surplus => ?share(1, 1, operation_amount)}
|
||||
}}
|
||||
}
|
||||
]}
|
||||
}
|
||||
}
|
||||
}.
|
||||
|
210
apps/wapi/test/wapi_w2w_tests_SUITE.erl
Normal file
210
apps/wapi/test/wapi_w2w_tests_SUITE.erl
Normal file
@ -0,0 +1,210 @@
|
||||
-module(wapi_w2w_tests_SUITE).
|
||||
|
||||
-include_lib("common_test/include/ct.hrl").
|
||||
|
||||
-include_lib("damsel/include/dmsl_domain_config_thrift.hrl").
|
||||
|
||||
-include_lib("jose/include/jose_jwk.hrl").
|
||||
-include_lib("wapi_wallet_dummy_data.hrl").
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_w2w_transfer_thrift.hrl").
|
||||
|
||||
-export([all/0]).
|
||||
-export([groups/0]).
|
||||
-export([init_per_suite/1]).
|
||||
-export([end_per_suite/1]).
|
||||
-export([init_per_group/2]).
|
||||
-export([end_per_group/2]).
|
||||
-export([init_per_testcase/2]).
|
||||
-export([end_per_testcase/2]).
|
||||
|
||||
-export([init/1]).
|
||||
|
||||
-export([
|
||||
create/1,
|
||||
get/1,
|
||||
fail_unauthorized_wallet/1
|
||||
]).
|
||||
|
||||
% common-api is used since it is the domain used in production RN
|
||||
% TODO: change to wallet-api (or just omit since it is the default one) when new tokens will be a thing
|
||||
-define(DOMAIN, <<"common-api">>).
|
||||
-define(badresp(Code), {error, {invalid_response_code, Code}}).
|
||||
-define(emptyresp(Code), {error, {Code, #{}}}).
|
||||
|
||||
-type test_case_name() :: atom().
|
||||
-type config() :: [{atom(), any()}].
|
||||
-type group_name() :: atom().
|
||||
|
||||
-behaviour(supervisor).
|
||||
|
||||
-spec init([]) ->
|
||||
{ok, {supervisor:sup_flags(), [supervisor:child_spec()]}}.
|
||||
init([]) ->
|
||||
{ok, {#{strategy => one_for_all, intensity => 1, period => 1}, []}}.
|
||||
|
||||
-spec all() ->
|
||||
[test_case_name()].
|
||||
all() ->
|
||||
[
|
||||
{group, base}
|
||||
].
|
||||
|
||||
-spec groups() ->
|
||||
[{group_name(), list(), [test_case_name()]}].
|
||||
groups() ->
|
||||
[
|
||||
{base, [],
|
||||
[
|
||||
create,
|
||||
get,
|
||||
fail_unauthorized_wallet
|
||||
]
|
||||
}
|
||||
].
|
||||
|
||||
%%
|
||||
%% starting/stopping
|
||||
%%
|
||||
-spec init_per_suite(config()) ->
|
||||
config().
|
||||
init_per_suite(Config) ->
|
||||
%% TODO remove this after cut off wapi
|
||||
ok = application:set_env(wapi, transport, thrift),
|
||||
ct_helper:makeup_cfg([
|
||||
ct_helper:test_case_name(init),
|
||||
ct_payment_system:setup(#{
|
||||
optional_apps => [
|
||||
bender_client,
|
||||
wapi_woody_client,
|
||||
wapi
|
||||
]
|
||||
})
|
||||
], Config).
|
||||
|
||||
-spec end_per_suite(config()) ->
|
||||
_.
|
||||
end_per_suite(C) ->
|
||||
%% TODO remove this after cut off wapi
|
||||
ok = application:unset_env(wapi, transport),
|
||||
ok = ct_payment_system:shutdown(C).
|
||||
|
||||
-spec init_per_group(group_name(), config()) ->
|
||||
config().
|
||||
init_per_group(Group, Config) when Group =:= base ->
|
||||
ok = ff_context:save(ff_context:create(#{
|
||||
party_client => party_client:create_client(),
|
||||
woody_context => woody_context:new(<<"init_per_group/", (atom_to_binary(Group, utf8))/binary>>)
|
||||
})),
|
||||
Party = create_party(Config),
|
||||
BasePermissions = [
|
||||
{[w2w], read},
|
||||
{[w2w], write}
|
||||
],
|
||||
{ok, Token} = wapi_ct_helper:issue_token(Party, BasePermissions, {deadline, 10}, ?DOMAIN),
|
||||
Config1 = [{party, Party} | Config],
|
||||
[{context, wapi_ct_helper:get_context(Token)} | Config1];
|
||||
init_per_group(_, Config) ->
|
||||
Config.
|
||||
|
||||
-spec end_per_group(group_name(), config()) ->
|
||||
_.
|
||||
end_per_group(_Group, _C) ->
|
||||
ok.
|
||||
|
||||
-spec init_per_testcase(test_case_name(), config()) ->
|
||||
config().
|
||||
init_per_testcase(Name, C) ->
|
||||
C1 = ct_helper:makeup_cfg([ct_helper:test_case_name(Name), ct_helper:woody_ctx()], C),
|
||||
ok = ct_helper:set_context(C1),
|
||||
[{test_sup, wapi_ct_helper:start_mocked_service_sup(?MODULE)} | C1].
|
||||
|
||||
-spec end_per_testcase(test_case_name(), config()) ->
|
||||
config().
|
||||
end_per_testcase(_Name, C) ->
|
||||
ok = ct_helper:unset_context(),
|
||||
wapi_ct_helper:stop_mocked_service_sup(?config(test_sup, C)),
|
||||
ok.
|
||||
|
||||
%%% Tests
|
||||
|
||||
-spec create(config()) ->
|
||||
_.
|
||||
create(C) ->
|
||||
PartyID = ?config(party, C),
|
||||
wapi_ct_helper:mock_services([
|
||||
{bender_thrift, fun('GenerateID', _) -> {ok, ?GENERATE_ID_RESULT} end},
|
||||
{fistful_wallet, fun('GetContext', _) -> {ok, ?DEFAULT_CONTEXT(PartyID)} end},
|
||||
{w2w_transfer, fun('Create', _) -> {ok, ?W2W_TRANSFER(PartyID)} end}
|
||||
], C),
|
||||
{ok, _} = call_api(
|
||||
fun swag_client_wallet_w2_w_api:create_w2_w_transfer/3,
|
||||
#{
|
||||
body => #{
|
||||
<<"sender">> => ?STRING,
|
||||
<<"receiver">> => ?STRING,
|
||||
<<"body">> => #{
|
||||
<<"amount">> => ?INTEGER,
|
||||
<<"currency">> => ?RUB
|
||||
}
|
||||
}
|
||||
},
|
||||
ct_helper:cfg(context, C)
|
||||
).
|
||||
|
||||
-spec get(config()) ->
|
||||
_.
|
||||
get(C) ->
|
||||
PartyID = ?config(party, C),
|
||||
wapi_ct_helper:mock_services([
|
||||
{w2w_transfer, fun('Get', _) -> {ok, ?W2W_TRANSFER(PartyID)} end}
|
||||
], C),
|
||||
{ok, _} = call_api(
|
||||
fun swag_client_wallet_w2_w_api:get_w2_w_transfer/3,
|
||||
#{
|
||||
binding => #{
|
||||
<<"w2wTransferID">> => ?STRING
|
||||
}
|
||||
},
|
||||
ct_helper:cfg(context, C)
|
||||
).
|
||||
|
||||
-spec fail_unauthorized_wallet(config()) ->
|
||||
_.
|
||||
fail_unauthorized_wallet(C) ->
|
||||
PartyID = ?config(party, C),
|
||||
wapi_ct_helper:mock_services([
|
||||
{bender_thrift, fun('GenerateID', _) -> {ok, ?GENERATE_ID_RESULT} end},
|
||||
{fistful_wallet, fun('GetContext', _) -> {ok, ?DEFAULT_CONTEXT(<<"someotherparty">>)} end},
|
||||
{w2w_transfer, fun('Create', _) -> {ok, ?W2W_TRANSFER(PartyID)} end}
|
||||
], C),
|
||||
{error, {422, #{
|
||||
<<"message">> := <<"No such wallet sender">>
|
||||
}}} = call_api(
|
||||
fun swag_client_wallet_w2_w_api:create_w2_w_transfer/3,
|
||||
#{
|
||||
body => #{
|
||||
<<"sender">> => ?STRING,
|
||||
<<"receiver">> => ?STRING,
|
||||
<<"body">> => #{
|
||||
<<"amount">> => ?INTEGER,
|
||||
<<"currency">> => ?RUB
|
||||
}
|
||||
}
|
||||
},
|
||||
ct_helper:cfg(context, C)
|
||||
).
|
||||
|
||||
%%
|
||||
|
||||
-spec call_api(function(), map(), wapi_client_lib:context()) ->
|
||||
{ok, term()} | {error, term()}.
|
||||
call_api(F, Params, Context) ->
|
||||
{Url, PreparedParams, Opts} = wapi_client_lib:make_request(Context, Params),
|
||||
Response = F(Url, PreparedParams, Opts),
|
||||
wapi_client_lib:handle_response(Response).
|
||||
|
||||
create_party(_C) ->
|
||||
ID = genlib:bsuuid(),
|
||||
_ = ff_party:create(ID),
|
||||
ID.
|
@ -35,6 +35,13 @@
|
||||
undefined
|
||||
}).
|
||||
|
||||
-define(GENERATE_ID_RESULT, {
|
||||
'bender_GenerationResult',
|
||||
?STRING,
|
||||
undefined,
|
||||
undefined
|
||||
}).
|
||||
|
||||
-define(WITHDRAWAL_STATUS, {pending, #wthd_status_Pending{}}).
|
||||
|
||||
-define(WITHDRAWAL(PartyID), #wthd_WithdrawalState{
|
||||
@ -264,6 +271,24 @@
|
||||
enabled = false
|
||||
}).
|
||||
|
||||
-define(W2W_TRANSFER(PartyID), #w2w_transfer_W2WTransferState{
|
||||
id = ?STRING,
|
||||
wallet_from_id = ?STRING,
|
||||
wallet_to_id = ?STRING,
|
||||
body = ?CASH,
|
||||
created_at = ?TIMESTAMP,
|
||||
domain_revision = ?INTEGER,
|
||||
party_revision = ?INTEGER,
|
||||
status = {pending, #w2w_status_Pending{}},
|
||||
external_id = ?STRING,
|
||||
metadata = ?DEFAULT_METADATA(),
|
||||
context = ?DEFAULT_CONTEXT(PartyID),
|
||||
effective_final_cash_flow = #cashflow_FinalCashFlow{
|
||||
postings = []
|
||||
},
|
||||
adjustments = []
|
||||
}).
|
||||
|
||||
-define(SNAPSHOT, #'Snapshot'{
|
||||
version = ?INTEGER,
|
||||
domain = #{
|
||||
|
@ -91,7 +91,9 @@ get_service_modname(fistful_destination) ->
|
||||
get_service_modname(fistful_withdrawal) ->
|
||||
{ff_proto_withdrawal_thrift, 'Management'};
|
||||
get_service_modname(webhook_manager) ->
|
||||
{ff_proto_webhooker_thrift, 'WebhookManager'}.
|
||||
{ff_proto_webhooker_thrift, 'WebhookManager'};
|
||||
get_service_modname(w2w_transfer) ->
|
||||
{ff_proto_w2w_transfer_thrift, 'Management'}.
|
||||
|
||||
-spec get_service_deadline(service_name()) -> undefined | woody_deadline:deadline().
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user