Skip to content

Commit 8f49077

Browse files
authored
Implements GetWalletAccount operation bypassing fistful service #minor (#39)
* Implements `GetWalletAccount` operation bypassing fistful service * Adds `GetWallet` operation * Reverts auth context for wallets to use backend module * Retires `createdAt` field for wallet object; bumps deps * Upgrades deps with PM compat
1 parent 1500ffd commit 8f49077

13 files changed

Lines changed: 394 additions & 87 deletions

rebar.config

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@
3131
{scoper, {git, "https://github.com/valitydev/scoper.git", {tag, "v1.1.0"}}},
3232
{thrift, {git, "https://github.com/valitydev/thrift-erlang.git", {tag, "v1.0.0"}}},
3333
{woody, {git, "https://github.com/valitydev/woody_erlang.git", {tag, "v1.1.0"}}},
34-
{dmt_client, {git, "https://github.com/valitydev/dmt-client.git", {tag, "v2.0.0"}}},
35-
{damsel, {git, "https://github.com/valitydev/damsel.git", {tag, "v2.2.0"}}},
34+
{dmt_client, {git, "https://github.com/valitydev/dmt-client.git", {tag, "v2.0.2"}}},
35+
{damsel, {git, "https://github.com/valitydev/damsel.git", {tag, "v2.2.11"}}},
3636
{identdocstore_proto, {git, "https://github.com/valitydev/identdocstore-proto.git", {branch, "master"}}},
3737
{fistful_proto, {git, "https://github.com/valitydev/fistful-proto.git", {tag, "v2.0.0"}}},
3838
{fistful_reporter_proto, {git, "https://github.com/valitydev/fistful-reporter-proto.git", {branch, "master"}}},

rebar.lock

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,12 @@
2121
{<<"cowlib">>,{pkg,<<"cowlib">>,<<"2.11.0">>},2},
2222
{<<"damsel">>,
2323
{git,"https://github.com/valitydev/damsel.git",
24-
{ref,"ba7414811590859d058817b8f22d2e9c22f627f8"}},
24+
{ref,"ff9b01f552f922ce4a16710827aa872325dbe5a9"}},
2525
0},
2626
{<<"dmt_client">>,
2727
{git,"https://github.com/valitydev/dmt-client.git",
28-
{ref,"fcfb028a041149caeebec8d9cef469c8cdbbc63e"}},
28+
{ref,"fff521d3d50b48e3c6b628fe4796b3628aedc6b7"}},
2929
0},
30-
{<<"dmt_core">>,
31-
{git,"https://github.com/valitydev/dmt-core.git",
32-
{ref,"19d8f57198f2cbe5b64aa4a923ba32774e505503"}},
33-
1},
3430
{<<"file_storage_proto">>,
3531
{git,"https://github.com/valitydev/file-storage-proto.git",
3632
{ref,"f01d2d914c674860b866918c18b0cd8cb4ae8d15"}},
@@ -41,7 +37,7 @@
4137
0},
4238
{<<"fistful_reporter_proto">>,
4339
{git,"https://github.com/valitydev/fistful-reporter-proto.git",
44-
{ref,"6d5695d2e8aa13247f93451937adefa70c6edeca"}},
40+
{ref,"533e95934683665bc840a45ca8735b87a3e3e2ba"}},
4541
0},
4642
{<<"genlib">>,
4743
{git,"https://github.com/valitydev/genlib.git",

src/wapi_domain_backend.erl

Lines changed: 16 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@
55

66
-type response_data() :: wapi_handler_utils:response_data().
77

8+
-export([head/0]).
89
-export([get_currency/1]).
910
-export([get_party_config/1]).
10-
-export([get_wallet_config/1]).
11+
-export([get_object/1]).
12+
-export([get_object/2]).
1113

1214
%%
1315

@@ -20,30 +22,21 @@
2022

2123
%%
2224

25+
-spec head() -> dmt_client:vsn().
26+
head() ->
27+
dmt_client:get_latest_version().
28+
2329
-spec get_party_config(id()) -> {ok, {map(), id()}} | {error, notfound}.
2430
get_party_config(PartyID) ->
2531
do(fun() ->
26-
Party = unwrap(object({party_config, #domain_PartyConfigRef{id = PartyID}})),
27-
{#{<<"id">> => Party#domain_PartyConfig.id}, PartyID}
28-
end).
29-
30-
-spec get_wallet_config(id()) -> {ok, {map(), id()}} | {error, notfound}.
31-
get_wallet_config(WalletID) ->
32-
do(fun() ->
33-
Wallet = unwrap(object({wallet_config, #domain_WalletConfigRef{id = WalletID}})),
34-
{
35-
#{
36-
<<"id">> => Wallet#domain_WalletConfig.id,
37-
<<"partyID">> => Wallet#domain_WalletConfig.party_id
38-
},
39-
Wallet#domain_WalletConfig.party_id
40-
}
32+
_Party = unwrap(get_object({party_config, #domain_PartyConfigRef{id = PartyID}})),
33+
{#{<<"id">> => PartyID}, PartyID}
4134
end).
4235

4336
-spec get_currency(id()) -> {ok, response_data()} | {error, notfound}.
4437
get_currency(ID) ->
4538
do(fun() ->
46-
Currency = unwrap(object({currency, #domain_CurrencyRef{symbolic_code = ID}})),
39+
Currency = unwrap(get_object({currency, #domain_CurrencyRef{symbolic_code = ID}})),
4740
#{
4841
<<"id">> => genlib_string:to_upper(genlib:to_binary(ID)),
4942
<<"name">> => Currency#domain_Currency.name,
@@ -52,18 +45,14 @@ get_currency(ID) ->
5245
}
5346
end).
5447

55-
%%
56-
%% Internal
57-
%%
58-
59-
-spec object(dmt_client:object_ref()) -> {ok, object_data()} | {error, notfound}.
60-
object(ObjectRef) ->
61-
object(latest, ObjectRef).
48+
-spec get_object(dmt_client:object_ref()) -> {ok, object_data()} | {error, notfound}.
49+
get_object(ObjectRef) ->
50+
get_object(latest, ObjectRef).
6251

63-
-spec object(dmt_client:version(), dmt_client:object_ref()) -> {ok, object_data()} | {error, notfound}.
64-
object(Ref, {Type, ObjectRef}) ->
52+
-spec get_object(dmt_client:version(), dmt_client:object_ref()) -> {ok, object_data()} | {error, notfound}.
53+
get_object(Ref, {Type, ObjectRef}) ->
6554
try dmt_client:checkout_object(Ref, {Type, ObjectRef}) of
66-
#domain_conf_v2_VersionedObject{object = {Type, {_RecordName, ObjectRef, ObjectData}}} ->
55+
#domain_conf_v2_VersionedObject{object = {Type, {_, ObjectRef, ObjectData}}} ->
6756
{ok, ObjectData}
6857
catch
6958
#domain_conf_v2_ObjectNotFound{} ->

src/wapi_wallet_backend.erl

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
-module(wapi_wallet_backend).
2+
3+
-type handler_context() :: wapi_handler_utils:handler_context().
4+
-type response_data() :: wapi_handler_utils:response_data().
5+
-type id() :: binary().
6+
7+
-export([get/2]).
8+
-export([get_account/2]).
9+
10+
-include_lib("damsel/include/dmsl_domain_thrift.hrl").
11+
-include_lib("damsel/include/dmsl_payproc_thrift.hrl").
12+
13+
-spec get(id(), handler_context()) -> {ok, response_data(), id()} | {error, {wallet, notfound}}.
14+
get(WalletID, _HandlerContext) ->
15+
case get_wallet_config(WalletID) of
16+
{ok, WalletConfig} ->
17+
{ok, unmarshal(wallet, {WalletID, WalletConfig}), WalletConfig#domain_WalletConfig.party_id};
18+
{error, notfound} ->
19+
{error, {wallet, notfound}}
20+
end.
21+
22+
-spec get_account(id(), handler_context()) -> {ok, response_data()} | {error, {wallet, notfound}}.
23+
get_account(WalletID, HandlerContext) ->
24+
DomainRevision = wapi_domain_backend:head(),
25+
case get_wallet_config(WalletID) of
26+
{ok, #domain_WalletConfig{party_id = PartyID, account = #domain_WalletAccount{settlement = AccountID}}} ->
27+
Request = {party_management, 'GetAccountState', {PartyID, AccountID, DomainRevision}},
28+
case wapi_handler_utils:service_call(Request, HandlerContext) of
29+
{ok, AccountBalanceThrift} ->
30+
{ok, unmarshal(account_state, AccountBalanceThrift)};
31+
{exception, #payproc_PartyNotFound{}} ->
32+
{error, {wallet, notfound}};
33+
{exception, #payproc_AccountNotFound{}} ->
34+
{error, {wallet, notfound}}
35+
end;
36+
{error, notfound} ->
37+
{error, {wallet, notfound}}
38+
end.
39+
40+
%% Internal
41+
42+
get_wallet_config(WalletID) ->
43+
ObjectRef = {wallet_config, #domain_WalletConfigRef{id = WalletID}},
44+
wapi_domain_backend:get_object(ObjectRef).
45+
46+
%% Marshaling
47+
48+
unmarshal(
49+
wallet,
50+
{WalletID, #domain_WalletConfig{
51+
name = Name,
52+
block = Blocking,
53+
account = #domain_WalletAccount{currency = #domain_CurrencyRef{symbolic_code = Currency}},
54+
party_id = PartyID
55+
}}
56+
) ->
57+
genlib_map:compact(#{
58+
<<"id">> => unmarshal(id, WalletID),
59+
<<"name">> => unmarshal(string, Name),
60+
<<"isBlocked">> => unmarshal(blocking, Blocking),
61+
<<"party">> => PartyID,
62+
<<"currency">> => Currency
63+
});
64+
unmarshal(blocking, {unblocked, _}) ->
65+
false;
66+
unmarshal(blocking, {blocked, _}) ->
67+
true;
68+
unmarshal(account_state, #payproc_AccountState{
69+
own_amount = OwnAmount,
70+
available_amount = AvailableAmount,
71+
currency = #domain_Currency{symbolic_code = CurrencyCode}
72+
}) ->
73+
#{
74+
<<"own">> => #{
75+
<<"amount">> => OwnAmount,
76+
<<"currency">> => CurrencyCode
77+
},
78+
<<"available">> => #{
79+
<<"amount">> => AvailableAmount,
80+
<<"currency">> => CurrencyCode
81+
}
82+
};
83+
unmarshal(T, V) ->
84+
wapi_codec:unmarshal(T, V).

src/wapi_wallet_handler.erl

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,25 @@ mask_notfound(Resolution) ->
7272
%% Providers
7373
-spec prepare(operation_id(), request_data(), handler_context(), handler_opts()) -> {ok, request_state()}.
7474

75+
%% Wallets
76+
prepare('GetWallet' = OperationID, #{'walletID' := WalletID}, Context, _Opts) ->
77+
{ResultWallet, ResultWalletOwner} =
78+
case wapi_wallet_backend:get(WalletID, Context) of
79+
{ok, Wallet, Owner} -> {Wallet, Owner};
80+
{error, {wallet, notfound}} -> {undefined, undefined}
81+
end,
82+
Authorize = fun() ->
83+
Prototypes = [
84+
{operation, #{wallet => WalletID, id => OperationID}},
85+
{wallet, [wapi_bouncer_context:build_wallet_entity(wallet, ResultWallet, {party, ResultWalletOwner})]}
86+
],
87+
Resolution = mask_notfound(wapi_auth:authorize_operation(Prototypes, Context)),
88+
{ok, Resolution}
89+
end,
90+
Process = fun() ->
91+
wapi_handler_utils:reply_ok(200, ResultWallet)
92+
end,
93+
{ok, #{authorize => Authorize, process => Process}};
7594
prepare('GetWalletAccount' = OperationID, #{'walletID' := WalletID}, Context, _Opts) ->
7695
AuthContext = build_auth_context([{wallet, WalletID}], [], Context),
7796
Authorize = fun() ->
@@ -83,8 +102,10 @@ prepare('GetWalletAccount' = OperationID, #{'walletID' := WalletID}, Context, _O
83102
{ok, Resolution}
84103
end,
85104
Process = fun() ->
86-
%% TODO: implement from new party service
87-
wapi_handler_utils:reply_ok(404)
105+
case wapi_wallet_backend:get_account(WalletID, Context) of
106+
{ok, WalletAccount} -> wapi_handler_utils:reply_ok(200, WalletAccount);
107+
{error, {wallet, notfound}} -> wapi_handler_utils:reply_ok(404)
108+
end
88109
end,
89110
{ok, #{authorize => Authorize, process => Process}};
90111
%% Destinations
@@ -799,11 +820,11 @@ build_auth_context({party, PartyID}, _Context) ->
799820
{error, notfound} -> {undefined, undefined}
800821
end,
801822
{party, {PartyID, ResultParty, ResultPartyOwner}};
802-
build_auth_context({wallet, WalletID}, _Context) ->
823+
build_auth_context({wallet, WalletID}, Context) ->
803824
{ResultWallet, ResultWalletOwner} =
804-
case wapi_domain_backend:get_wallet_config(WalletID) of
805-
{ok, {WalletConfig, Owner}} -> {WalletConfig, Owner};
806-
{error, notfound} -> {undefined, undefined}
825+
case wapi_wallet_backend:get(WalletID, Context) of
826+
{ok, Wallet, Owner} -> {Wallet, Owner};
827+
{error, {wallet, notfound}} -> {undefined, undefined}
807828
end,
808829
{wallet, {WalletID, ResultWallet, ResultWalletOwner}};
809830
build_auth_context({destination, DestinationID}, Context) ->

src/wapi_woody_client.erl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,9 @@ get_service_modname(fistful_destination) ->
8181
get_service_modname(fistful_withdrawal) ->
8282
{fistful_wthd_thrift, 'Management'};
8383
get_service_modname(webhook_manager) ->
84-
{fistful_webhooker_thrift, 'WebhookManager'}.
84+
{fistful_webhooker_thrift, 'WebhookManager'};
85+
get_service_modname(party_management) ->
86+
{dmsl_payproc_thrift, 'PartyManagement'}.
8587

8688
-spec get_service_deadline(service_name()) -> undefined | woody_deadline:deadline().
8789
get_service_deadline(ServiceName) ->

test/wapi_ct_helper.erl

Lines changed: 40 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -133,52 +133,48 @@ start_app(woody = AppName) ->
133133
{acceptors_pool_size, 4}
134134
]);
135135
start_app({dmt_client = AppName, SupPid}) ->
136-
WalletConfig = #domain_WalletConfig{
137-
id = ?STRING,
138-
created_at = wapi_time:rfc3339(),
139-
blocking =
140-
{unblocked, #domain_Unblocked{
141-
reason = <<"">>,
142-
since = wapi_time:rfc3339()
143-
}},
144-
suspension =
145-
{active, #domain_Active{
146-
since = wapi_time:rfc3339()
147-
}},
148-
details = #domain_Details{
149-
name = <<"Test Wallet">>,
150-
description = <<"Test description">>
151-
},
152-
currency_configs = #{
153-
#domain_CurrencyRef{symbolic_code = <<"RUB">>} => #domain_WalletCurrencyConfig{
136+
WalletConfigObject = #domain_WalletConfigObject{
137+
ref = #domain_WalletConfigRef{id = ?STRING},
138+
data = #domain_WalletConfig{
139+
name = ?STRING,
140+
block =
141+
{unblocked, #domain_Unblocked{
142+
reason = <<"">>,
143+
since = wapi_time:rfc3339()
144+
}},
145+
suspension =
146+
{active, #domain_Active{
147+
since = wapi_time:rfc3339()
148+
}},
149+
payment_institution = #domain_PaymentInstitutionRef{id = 1},
150+
terms = #domain_TermSetHierarchyRef{id = 1},
151+
account = #domain_WalletAccount{
154152
currency = #domain_CurrencyRef{symbolic_code = <<"RUB">>},
155153
settlement = ?INTEGER
156-
}
157-
},
158-
payment_institution = #domain_PaymentInstitutionRef{id = 1},
159-
terms = #domain_TermSetHierarchyRef{id = 1},
160-
party_id = ?STRING
154+
},
155+
party_id = ?STRING
156+
}
161157
},
162-
WalletConfigObject = #domain_WalletConfigObject{ref = #domain_WalletConfigRef{id = ?STRING}, data = WalletConfig},
163-
PartyConfig = #domain_PartyConfig{
164-
id = ?STRING,
165-
contact_info = #domain_PartyContactInfo{
166-
registration_email = <<"test@test.ru">>
167-
},
168-
created_at = wapi_time:rfc3339(),
169-
blocking =
170-
{unblocked, #domain_Unblocked{
171-
reason = <<"">>,
172-
since = wapi_time:rfc3339()
173-
}},
174-
suspension =
175-
{active, #domain_Active{
176-
since = wapi_time:rfc3339()
177-
}},
178-
shops = [],
179-
wallets = [#domain_WalletConfigRef{id = ?STRING}]
158+
PartyConfigObject = #domain_PartyConfigObject{
159+
ref = #domain_PartyConfigRef{id = ?STRING},
160+
data = #domain_PartyConfig{
161+
name = ?STRING,
162+
block =
163+
{unblocked, #domain_Unblocked{
164+
reason = <<"">>,
165+
since = wapi_time:rfc3339()
166+
}},
167+
suspension =
168+
{active, #domain_Active{
169+
since = wapi_time:rfc3339()
170+
}},
171+
shops = [],
172+
wallets = [#domain_WalletConfigRef{id = ?STRING}],
173+
contact_info = #domain_PartyContactInfo{
174+
registration_email = <<"test@test.ru">>
175+
}
176+
}
180177
},
181-
PartyConfigObject = #domain_PartyConfigObject{ref = #domain_PartyConfigRef{id = ?STRING}, data = PartyConfig},
182178
Urls = mock_services_(
183179
[
184180
{domain_config_client, fun
@@ -373,6 +369,8 @@ mock_service_handler({ServiceName = domain_config, Fun}) ->
373369
mock_service_handler(ServiceName, {dmsl_domain_conf_v2_thrift, 'Repository'}, Fun);
374370
mock_service_handler({ServiceName = domain_config_client, Fun}) ->
375371
mock_service_handler(ServiceName, {dmsl_domain_conf_v2_thrift, 'RepositoryClient'}, Fun);
372+
mock_service_handler({ServiceName = party_management, Fun}) ->
373+
mock_service_handler(ServiceName, {dmsl_payproc_thrift, 'PartyManagement'}, Fun);
376374
mock_service_handler({ServiceName, Fun}) ->
377375
mock_service_handler(ServiceName, wapi_woody_client:get_service_modname(ServiceName), Fun);
378376
mock_service_handler({ServiceName, WoodyService, Fun}) ->

test/wapi_wallet_dummy_data.hrl

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,8 +192,6 @@
192192

193193
-define(LAST_DIGITS(CardNumber), string:slice(CardNumber, 12)).
194194

195-
-define(DESTINATION_STATUS, {authorized, #destination_Authorized{}}).
196-
197195
-define(DESTINATION(PartyID), ?DESTINATION(PartyID, ?RESOURCE_BANK_CARD)).
198196

199197
-define(DESTINATION(PartyID, Resource), #destination_DestinationState{

0 commit comments

Comments
 (0)