mirror of
https://github.com/valitydev/fistful-server.git
synced 2024-11-06 02:35:18 +00:00
erlfrm code formatter (#347)
This commit is contained in:
parent
dcc4b32a35
commit
d8713b86c9
8
Makefile
8
Makefile
@ -24,7 +24,7 @@ BUILD_IMAGE_TAG := 442c2c274c1d8e484e5213089906a4271641d95e
|
||||
|
||||
REGISTRY := dr2.rbkmoney.com
|
||||
|
||||
CALL_ANYWHERE := all submodules compile xref lint dialyze release clean distclean
|
||||
CALL_ANYWHERE := all submodules compile xref lint format check_format dialyze release clean distclean
|
||||
CALL_ANYWHERE += generate regenerate
|
||||
|
||||
CALL_W_CONTAINER := $(CALL_ANYWHERE) test
|
||||
@ -51,6 +51,12 @@ xref: submodules
|
||||
lint:
|
||||
elvis rock
|
||||
|
||||
check_format:
|
||||
$(REBAR) fmt -c
|
||||
|
||||
format:
|
||||
$(REBAR) fmt -w
|
||||
|
||||
dialyze: submodules generate
|
||||
$(REBAR) dialyzer
|
||||
|
||||
|
@ -7,14 +7,14 @@
|
||||
-type reason() :: binary().
|
||||
|
||||
-type failure() :: #{
|
||||
code := code(),
|
||||
code := code(),
|
||||
reason => reason(),
|
||||
sub => sub_failure()
|
||||
sub => sub_failure()
|
||||
}.
|
||||
|
||||
-type sub_failure() :: #{
|
||||
code := code(),
|
||||
sub => sub_failure()
|
||||
sub => sub_failure()
|
||||
}.
|
||||
|
||||
-export_type([code/0]).
|
||||
|
@ -14,11 +14,12 @@
|
||||
|
||||
-export([to_range/1]).
|
||||
|
||||
-type ord(T) :: T. % totally ordered
|
||||
% totally ordered
|
||||
-type ord(T) :: T.
|
||||
|
||||
-type indef(T) :: #{
|
||||
expected_min := ord(T),
|
||||
current := ord(T),
|
||||
current := ord(T),
|
||||
expected_max := ord(T)
|
||||
}.
|
||||
|
||||
@ -26,40 +27,32 @@
|
||||
|
||||
%%
|
||||
|
||||
-spec new(T) ->
|
||||
indef(T).
|
||||
-spec new(T) -> indef(T).
|
||||
|
||||
-spec new(T, T, T) ->
|
||||
indef(T).
|
||||
-spec new(T, T, T) -> indef(T).
|
||||
|
||||
-spec current(indef(T)) ->
|
||||
T.
|
||||
-spec current(indef(T)) -> T.
|
||||
|
||||
-spec expmin(indef(T)) ->
|
||||
T.
|
||||
-spec expmin(indef(T)) -> T.
|
||||
|
||||
-spec expmax(indef(T)) ->
|
||||
T.
|
||||
-spec account(T, indef(T)) ->
|
||||
indef(T).
|
||||
-spec expmax(indef(T)) -> T.
|
||||
-spec account(T, indef(T)) -> indef(T).
|
||||
|
||||
-spec confirm(T, indef(T)) ->
|
||||
indef(T).
|
||||
-spec confirm(T, indef(T)) -> indef(T).
|
||||
|
||||
-spec reject(T, indef(T)) ->
|
||||
indef(T).
|
||||
-spec reject(T, indef(T)) -> indef(T).
|
||||
|
||||
new(Seed) ->
|
||||
#{
|
||||
expected_min => Seed,
|
||||
current => Seed,
|
||||
current => Seed,
|
||||
expected_max => Seed
|
||||
}.
|
||||
|
||||
new(ExpMin, Current, ExpMax) ->
|
||||
#{
|
||||
expected_min => ExpMin,
|
||||
current => Current,
|
||||
current => Current,
|
||||
expected_max => ExpMax
|
||||
}.
|
||||
|
||||
@ -80,7 +73,7 @@ account(Delta, Indef = #{expected_min := ExpMin, expected_max := ExpMax}) ->
|
||||
|
||||
confirm(Delta, Indef = #{current := Current, expected_min := ExpMin, expected_max := ExpMax}) ->
|
||||
Indef#{
|
||||
current := Current + Delta,
|
||||
current := Current + Delta,
|
||||
expected_min := erlang:max(ExpMin + Delta, ExpMin),
|
||||
expected_max := erlang:min(ExpMax + Delta, ExpMax)
|
||||
}.
|
||||
@ -91,9 +84,7 @@ reject(Delta, Indef = #{expected_min := ExpMin, expected_max := ExpMax}) ->
|
||||
expected_max := erlang:min(ExpMax - Delta, ExpMax)
|
||||
}.
|
||||
|
||||
-spec to_range(indef(T)) ->
|
||||
ff_range:range(T).
|
||||
|
||||
-spec to_range(indef(T)) -> ff_range:range(T).
|
||||
to_range(#{expected_min := ExpMin, expected_max := ExpMax}) ->
|
||||
{{inclusive, ExpMin}, {inclusive, ExpMax}}.
|
||||
|
||||
@ -108,13 +99,13 @@ to_range(#{expected_min := ExpMin, expected_max := ExpMax}) ->
|
||||
-spec convergency_test() -> _.
|
||||
|
||||
convergency_test() ->
|
||||
Opset = gen_opset(3/5, 2/3, 20),
|
||||
Opset = gen_opset(3 / 5, 2 / 3, 20),
|
||||
#{
|
||||
current := C,
|
||||
current := C,
|
||||
expected_min := ExpMin,
|
||||
expected_max := ExpMax
|
||||
} = lists:foldl(
|
||||
fun ({Op, Delta}, Indef) -> Op(Delta, Indef) end,
|
||||
fun({Op, Delta}, Indef) -> Op(Delta, Indef) end,
|
||||
new(0),
|
||||
Opset
|
||||
),
|
||||
@ -135,16 +126,18 @@ gen_opset(St, Acc) ->
|
||||
gen_op({_, _, 0, []}) ->
|
||||
done;
|
||||
gen_op({Pe, Pc, N, Ds}) ->
|
||||
case ff_random:from_choices([
|
||||
{ Pe * sign(N) , account},
|
||||
{(1 - Pe) * sign(length(Ds)) , commit}
|
||||
]) of
|
||||
case
|
||||
ff_random:from_choices([
|
||||
{Pe * sign(N), account},
|
||||
{(1 - Pe) * sign(length(Ds)), commit}
|
||||
])
|
||||
of
|
||||
account ->
|
||||
Delta = ff_random:from_range(-1000, 1000),
|
||||
{{fun account/2, Delta}, {Pe, Pc, N - 1, [Delta | Ds]}};
|
||||
commit ->
|
||||
Delta = ff_random:from_list(Ds),
|
||||
Op = ff_random:from_choices([{Pc, fun confirm/2}, {1 - Pc, fun reject/2}]),
|
||||
Op = ff_random:from_choices([{Pc, fun confirm/2}, {1 - Pc, fun reject/2}]),
|
||||
{{Op, Delta}, {Pe, Pc, N, Ds -- [Delta]}}
|
||||
end.
|
||||
|
||||
|
@ -5,8 +5,8 @@
|
||||
-module(ff_map).
|
||||
|
||||
-type result(T) ::
|
||||
{ok, T} |
|
||||
{error, notfound} .
|
||||
{ok, T}
|
||||
| {error, notfound}.
|
||||
|
||||
-export_type([result/1]).
|
||||
|
||||
@ -14,9 +14,7 @@
|
||||
|
||||
%%
|
||||
|
||||
-spec find(Key, #{Key => Value}) ->
|
||||
result(Value).
|
||||
|
||||
-spec find(Key, #{Key => Value}) -> result(Value).
|
||||
find(Key, Map) ->
|
||||
case Map of
|
||||
#{Key := Value} ->
|
||||
|
@ -18,37 +18,29 @@
|
||||
|
||||
%%
|
||||
|
||||
-spec from_result({ok, T} | {error, _}) ->
|
||||
maybe(T).
|
||||
|
||||
-spec from_result({ok, T} | {error, _}) -> maybe(T).
|
||||
from_result({ok, T}) ->
|
||||
T;
|
||||
from_result({error, _}) ->
|
||||
undefined.
|
||||
|
||||
-spec to_list(maybe(T)) ->
|
||||
[T].
|
||||
|
||||
-spec to_list(maybe(T)) -> [T].
|
||||
to_list(undefined) ->
|
||||
[];
|
||||
to_list(T) ->
|
||||
[T].
|
||||
|
||||
-spec apply(fun(), Arg :: undefined | term()) ->
|
||||
term().
|
||||
-spec apply(fun(), Arg :: undefined | term()) -> term().
|
||||
apply(Fun, Arg) ->
|
||||
ff_maybe:apply(Fun, Arg, undefined).
|
||||
|
||||
-spec apply(fun(), Arg :: undefined | term(), Default :: term()) ->
|
||||
term().
|
||||
-spec apply(fun(), Arg :: undefined | term(), Default :: term()) -> term().
|
||||
apply(Fun, Arg, _Default) when Arg =/= undefined ->
|
||||
Fun(Arg);
|
||||
apply(_Fun, undefined, Default) ->
|
||||
Default.
|
||||
|
||||
-spec get_defined([maybe(T)]) ->
|
||||
T.
|
||||
|
||||
-spec get_defined([maybe(T)]) -> T.
|
||||
get_defined([]) ->
|
||||
erlang:error(badarg);
|
||||
get_defined([Value | _Tail]) when Value =/= undefined ->
|
||||
@ -56,9 +48,6 @@ get_defined([Value | _Tail]) when Value =/= undefined ->
|
||||
get_defined([undefined | Tail]) ->
|
||||
get_defined(Tail).
|
||||
|
||||
|
||||
-spec get_defined(maybe(T), maybe(T)) ->
|
||||
T.
|
||||
|
||||
-spec get_defined(maybe(T), maybe(T)) -> T.
|
||||
get_defined(V1, V2) ->
|
||||
get_defined([V1, V2]).
|
||||
|
@ -25,9 +25,7 @@
|
||||
-type result(T, E) ::
|
||||
{ok, T} | {error, E}.
|
||||
|
||||
-spec do(fun(() -> ok | T | thrown(E))) ->
|
||||
ok | result(T, E).
|
||||
|
||||
-spec do(fun(() -> ok | T | thrown(E))) -> ok | result(T, E).
|
||||
do(Fun) ->
|
||||
try Fun() of
|
||||
ok ->
|
||||
@ -38,17 +36,14 @@ do(Fun) ->
|
||||
Thrown -> {error, Thrown}
|
||||
end.
|
||||
|
||||
-spec do(Tag, fun(() -> ok | T | thrown(E))) ->
|
||||
ok | result(T, {Tag, E}).
|
||||
|
||||
-spec do(Tag, fun(() -> ok | T | thrown(E))) -> ok | result(T, {Tag, E}).
|
||||
do(Tag, Fun) ->
|
||||
do(fun () -> unwrap(Tag, do(Fun)) end).
|
||||
do(fun() -> unwrap(Tag, do(Fun)) end).
|
||||
|
||||
-spec unwrap
|
||||
(ok) -> ok;
|
||||
({ok, V}) -> V;
|
||||
(ok) -> ok;
|
||||
({ok, V}) -> V;
|
||||
({error, E}) -> thrown(E).
|
||||
|
||||
unwrap(ok) ->
|
||||
ok;
|
||||
unwrap({ok, V}) ->
|
||||
@ -57,10 +52,9 @@ unwrap({error, E}) ->
|
||||
throw(E).
|
||||
|
||||
-spec expect
|
||||
(_E, ok) -> ok;
|
||||
(_E, {ok, V}) -> V;
|
||||
( E, {error, _}) -> thrown(E).
|
||||
|
||||
(_E, ok) -> ok;
|
||||
(_E, {ok, V}) -> V;
|
||||
(E, {error, _}) -> thrown(E).
|
||||
expect(_, ok) ->
|
||||
ok;
|
||||
expect(_, {ok, V}) ->
|
||||
@ -68,19 +62,16 @@ expect(_, {ok, V}) ->
|
||||
expect(E, {error, _}) ->
|
||||
throw(E).
|
||||
|
||||
-spec flip(result(T, E)) ->
|
||||
result(E, T).
|
||||
|
||||
-spec flip(result(T, E)) -> result(E, T).
|
||||
flip({ok, T}) ->
|
||||
{error, T};
|
||||
flip({error, E}) ->
|
||||
{ok, E}.
|
||||
|
||||
-spec unwrap
|
||||
(_Tag, ok) -> ok;
|
||||
(_Tag, {ok, V}) -> V;
|
||||
( Tag, {error, E}) -> thrown({Tag, E}).
|
||||
|
||||
(_Tag, ok) -> ok;
|
||||
(_Tag, {ok, V}) -> V;
|
||||
(Tag, {error, E}) -> thrown({Tag, E}).
|
||||
unwrap(_, ok) ->
|
||||
ok;
|
||||
unwrap(_, {ok, V}) ->
|
||||
@ -88,9 +79,7 @@ unwrap(_, {ok, V}) ->
|
||||
unwrap(Tag, {error, E}) ->
|
||||
throw({Tag, E}).
|
||||
|
||||
-spec valid(T, T) ->
|
||||
ok | {error, T}.
|
||||
|
||||
-spec valid(T, T) -> ok | {error, T}.
|
||||
valid(V, V) ->
|
||||
ok;
|
||||
valid(_, V) ->
|
||||
@ -103,12 +92,10 @@ valid(_, V) ->
|
||||
-type outcome(E, R) ::
|
||||
{ok, [E]} | {error, R}.
|
||||
|
||||
-spec with(Sub, St, fun((SubSt | undefined) -> outcome(SubEv, Reason))) ->
|
||||
outcome({Sub, SubEv}, {Sub, Reason}) when
|
||||
Sub :: atom(),
|
||||
St :: #{Sub => SubSt},
|
||||
SubSt :: _.
|
||||
|
||||
-spec with(Sub, St, fun((SubSt | undefined) -> outcome(SubEv, Reason))) -> outcome({Sub, SubEv}, {Sub, Reason}) when
|
||||
Sub :: atom(),
|
||||
St :: #{Sub => SubSt},
|
||||
SubSt :: _.
|
||||
with(Model, St, F) ->
|
||||
case F(maps:get(Model, St, undefined)) of
|
||||
{ok, Events0} when is_list(Events0) ->
|
||||
|
@ -12,11 +12,9 @@
|
||||
|
||||
%%
|
||||
|
||||
-spec date() ->
|
||||
calendar:date().
|
||||
-spec date() -> calendar:date().
|
||||
|
||||
-spec time() ->
|
||||
calendar:time().
|
||||
-spec time() -> calendar:time().
|
||||
|
||||
date() ->
|
||||
Y = from_range(1970, 9999),
|
||||
@ -32,12 +30,11 @@ time() ->
|
||||
|
||||
%%
|
||||
|
||||
-type choice(T) :: {probability(), T}.
|
||||
-type probability() :: number(). % >= 0
|
||||
|
||||
-spec from_choices([choice(T)]) ->
|
||||
T.
|
||||
-type choice(T) :: {probability(), T}.
|
||||
% >= 0
|
||||
-type probability() :: number().
|
||||
|
||||
-spec from_choices([choice(T)]) -> T.
|
||||
from_choices(Choices) ->
|
||||
Psum = lists:sum([assert_probability(P) || {P, _} <- Choices]),
|
||||
Roll = rand:uniform() * Psum,
|
||||
@ -60,14 +57,12 @@ assert_probability(P) when is_number(P), P >= 0 ->
|
||||
assert_probability(_) ->
|
||||
error(badarg).
|
||||
|
||||
-spec from_list([T, ...]) ->
|
||||
T.
|
||||
|
||||
-spec from_list([T, ...]) -> T.
|
||||
from_list(List) ->
|
||||
from_choices([{1, E} || E <- List]).
|
||||
|
||||
-spec from_range(M :: integer(), N :: integer()) ->
|
||||
integer(). % from [M; N]
|
||||
|
||||
% from [M; N]
|
||||
integer().
|
||||
from_range(M, N) when M < N ->
|
||||
rand:uniform(N - M + 1) - 1 + M.
|
||||
|
@ -3,11 +3,12 @@
|
||||
|
||||
-module(ff_range).
|
||||
|
||||
-type range(T) :: {maybe(bound(T)), maybe(bound(T))}.
|
||||
-type bound(T) :: {exclusive | inclusive, ord(T)}.
|
||||
-type range(T) :: {maybe(bound(T)), maybe(bound(T))}.
|
||||
-type bound(T) :: {exclusive | inclusive, ord(T)}.
|
||||
|
||||
-type maybe(T) :: infinity | T.
|
||||
-type ord(T) :: T. % totally ordered
|
||||
-type maybe(T) :: infinity | T.
|
||||
% totally ordered
|
||||
-type ord(T) :: T.
|
||||
|
||||
-export_type([range/1]).
|
||||
-export_type([bound/1]).
|
||||
@ -17,9 +18,7 @@
|
||||
|
||||
%%
|
||||
|
||||
-spec intersect(range(T), range(T)) ->
|
||||
range(T) | undefined.
|
||||
|
||||
-spec intersect(range(T), range(T)) -> range(T) | undefined.
|
||||
intersect(R1, R2) ->
|
||||
B1 = max_bound(lower(R1), lower(R2)),
|
||||
B2 = min_bound(upper(R1), upper(R2)),
|
||||
@ -30,9 +29,7 @@ intersect(R1, R2) ->
|
||||
from_bounds(B1, B2)
|
||||
end.
|
||||
|
||||
-spec contains(range(T), range(T)) ->
|
||||
boolean().
|
||||
|
||||
-spec contains(range(T), range(T)) -> boolean().
|
||||
contains(R1, R2) ->
|
||||
intersect(R1, R2) =:= R2.
|
||||
|
||||
@ -59,13 +56,13 @@ compare_bounds(B1, B2) ->
|
||||
max_bound(B1, B2) ->
|
||||
case compare_bounds(B1, B2) of
|
||||
gt -> B1;
|
||||
_ -> B2
|
||||
_ -> B2
|
||||
end.
|
||||
|
||||
min_bound(B1, B2) ->
|
||||
case compare_bounds(B1, B2) of
|
||||
lt -> B1;
|
||||
_ -> B2
|
||||
_ -> B2
|
||||
end.
|
||||
|
||||
%%
|
||||
|
@ -9,20 +9,18 @@
|
||||
%%
|
||||
|
||||
-type fragment() ::
|
||||
iodata() |
|
||||
char() |
|
||||
atom() |
|
||||
number() .
|
||||
iodata()
|
||||
| char()
|
||||
| atom()
|
||||
| number().
|
||||
|
||||
-spec join([fragment()]) -> binary().
|
||||
|
||||
join(Fragments) ->
|
||||
join(<<>>, Fragments).
|
||||
|
||||
-spec join(Delim, [fragment()]) -> binary() when
|
||||
Delim ::
|
||||
char() |
|
||||
iodata() .
|
||||
|
||||
char()
|
||||
| iodata().
|
||||
join(Delim, Fragments) ->
|
||||
genlib_string:join(Delim, lists:map(fun genlib:to_binary/1, Fragments)).
|
||||
|
@ -10,15 +10,15 @@
|
||||
|
||||
-export_type([timestamp_ms/0]).
|
||||
|
||||
-type timestamp_ms() :: integer().
|
||||
-type year() :: integer().
|
||||
-type month() :: integer().
|
||||
-type day() :: integer().
|
||||
-type hour() :: integer().
|
||||
-type minute() :: integer().
|
||||
-type second() :: integer().
|
||||
-type date() :: {year(), month(), day()}.
|
||||
-type time() :: {hour(), minute(), second()}.
|
||||
-type timestamp_ms() :: integer().
|
||||
-type year() :: integer().
|
||||
-type month() :: integer().
|
||||
-type day() :: integer().
|
||||
-type hour() :: integer().
|
||||
-type minute() :: integer().
|
||||
-type second() :: integer().
|
||||
-type date() :: {year(), month(), day()}.
|
||||
-type time() :: {hour(), minute(), second()}.
|
||||
-type datetime_interval() :: {date(), time()}.
|
||||
|
||||
%% API
|
||||
@ -35,24 +35,24 @@ to_rfc3339(Timestamp) ->
|
||||
from_rfc3339(BTimestamp) ->
|
||||
genlib_rfc3339:parse(BTimestamp, millisecond).
|
||||
|
||||
-spec add_interval(timestamp_ms(), datetime_interval()) ->
|
||||
timestamp_ms().
|
||||
-spec add_interval(timestamp_ms(), datetime_interval()) -> timestamp_ms().
|
||||
add_interval(Timestamp, {Date, Time}) ->
|
||||
Ms = Timestamp rem 1000,
|
||||
TSSeconds = erlang:convert_time_unit(Timestamp, millisecond, second),
|
||||
{D, T} = genlib_time:unixtime_to_daytime(TSSeconds),
|
||||
NewDate = genlib_time:daytime_to_unixtime({genlib_time:shift_date(D, Date), T}),
|
||||
DateTime = genlib_time:add_duration(NewDate, Time),
|
||||
DateTime*1000 + Ms.
|
||||
|
||||
DateTime * 1000 + Ms.
|
||||
|
||||
%% TESTS
|
||||
|
||||
-ifdef(TEST).
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
-spec test() -> _.
|
||||
|
||||
-spec rfc3339_symmetry_test() -> _.
|
||||
|
||||
rfc3339_symmetry_test() ->
|
||||
TimestampStr = <<"2000-01-01T00:00:00Z">>,
|
||||
?assertEqual(TimestampStr, to_rfc3339(from_rfc3339(TimestampStr))).
|
||||
@ -67,18 +67,18 @@ add_second_interval_test() ->
|
||||
add_minute_interval_test() ->
|
||||
Timestamp = ff_time:now(),
|
||||
NewTimestamp = add_interval(Timestamp, {{0, 0, 0}, {0, 1, 0}}),
|
||||
?assertEqual(Timestamp + 60*1000, NewTimestamp).
|
||||
?assertEqual(Timestamp + 60 * 1000, NewTimestamp).
|
||||
|
||||
-spec add_hour_interval_test() -> _.
|
||||
add_hour_interval_test() ->
|
||||
Timestamp = ff_time:now(),
|
||||
NewTimestamp = add_interval(Timestamp, {{0, 0, 0}, {1, 0, 0}}),
|
||||
?assertEqual(Timestamp + 60*60*1000, NewTimestamp).
|
||||
?assertEqual(Timestamp + 60 * 60 * 1000, NewTimestamp).
|
||||
|
||||
-spec add_day_interval_test() -> _.
|
||||
add_day_interval_test() ->
|
||||
Timestamp = ff_time:now(),
|
||||
NewTimestamp = add_interval(Timestamp, {{0, 0, 1}, {0, 0, 0}}),
|
||||
?assertEqual(Timestamp + 24*60*60*1000, NewTimestamp).
|
||||
?assertEqual(Timestamp + 24 * 60 * 60 * 1000, NewTimestamp).
|
||||
|
||||
-endif.
|
||||
|
@ -3,67 +3,64 @@
|
||||
|
||||
-include_lib("damsel/include/dmsl_domain_config_thrift.hrl").
|
||||
|
||||
-define(ordset(Es), ordsets:from_list(Es)).
|
||||
-define(ordset(Es), ordsets:from_list(Es)).
|
||||
|
||||
-define(glob(), #domain_GlobalsRef{}).
|
||||
-define(cur(ID), #domain_CurrencyRef{symbolic_code = ID}).
|
||||
-define(pmt(C, T), #domain_PaymentMethodRef{id = {C, T}}).
|
||||
-define(cat(ID), #domain_CategoryRef{id = ID}).
|
||||
-define(prx(ID), #domain_ProxyRef{id = ID}).
|
||||
-define(prv(ID), #domain_ProviderRef{id = ID}).
|
||||
-define(trm(ID), #domain_TerminalRef{id = ID}).
|
||||
-define(prv_trm(ID), #domain_ProviderTerminalRef{id = ID}).
|
||||
-define(glob(), #domain_GlobalsRef{}).
|
||||
-define(cur(ID), #domain_CurrencyRef{symbolic_code = ID}).
|
||||
-define(pmt(C, T), #domain_PaymentMethodRef{id = {C, T}}).
|
||||
-define(cat(ID), #domain_CategoryRef{id = ID}).
|
||||
-define(prx(ID), #domain_ProxyRef{id = ID}).
|
||||
-define(prv(ID), #domain_ProviderRef{id = ID}).
|
||||
-define(trm(ID), #domain_TerminalRef{id = ID}).
|
||||
-define(prv_trm(ID), #domain_ProviderTerminalRef{id = ID}).
|
||||
-define(prv_trm(ID, P), #domain_ProviderTerminalRef{id = ID, priority = P}).
|
||||
-define(tmpl(ID), #domain_ContractTemplateRef{id = ID}).
|
||||
-define(trms(ID), #domain_TermSetHierarchyRef{id = ID}).
|
||||
-define(sas(ID), #domain_SystemAccountSetRef{id = ID}).
|
||||
-define(eas(ID), #domain_ExternalAccountSetRef{id = ID}).
|
||||
-define(insp(ID), #domain_InspectorRef{id = ID}).
|
||||
-define(p2p_insp(ID), #domain_P2PInspectorRef{id = ID}).
|
||||
-define(payinst(ID), #domain_PaymentInstitutionRef{id = ID}).
|
||||
-define(tmpl(ID), #domain_ContractTemplateRef{id = ID}).
|
||||
-define(trms(ID), #domain_TermSetHierarchyRef{id = ID}).
|
||||
-define(sas(ID), #domain_SystemAccountSetRef{id = ID}).
|
||||
-define(eas(ID), #domain_ExternalAccountSetRef{id = ID}).
|
||||
-define(insp(ID), #domain_InspectorRef{id = ID}).
|
||||
-define(p2p_insp(ID), #domain_P2PInspectorRef{id = ID}).
|
||||
-define(payinst(ID), #domain_PaymentInstitutionRef{id = ID}).
|
||||
|
||||
-define(cash(Amount, SymCode),
|
||||
#domain_Cash{amount = Amount, currency = ?cur(SymCode)}
|
||||
).
|
||||
-define(cash(Amount, SymCode), #domain_Cash{amount = Amount, currency = ?cur(SymCode)}).
|
||||
|
||||
-define(cashrng(Lower, Upper),
|
||||
#domain_CashRange{lower = Lower, upper = Upper}
|
||||
).
|
||||
-define(cashrng(Lower, Upper), #domain_CashRange{lower = Lower, upper = Upper}).
|
||||
|
||||
-define(fixed(Amount, SymCode),
|
||||
{fixed, #domain_CashVolumeFixed{cash = #domain_Cash{
|
||||
amount = Amount,
|
||||
currency = ?cur(SymCode)
|
||||
}}}
|
||||
{fixed, #domain_CashVolumeFixed{
|
||||
cash = #domain_Cash{
|
||||
amount = Amount,
|
||||
currency = ?cur(SymCode)
|
||||
}
|
||||
}}
|
||||
).
|
||||
|
||||
-define(share(P, Q, C),
|
||||
{share, #domain_CashVolumeShare{
|
||||
parts = #'Rational'{p = P, q = Q}, 'of' = C}
|
||||
}
|
||||
parts = #'Rational'{p = P, q = Q},
|
||||
'of' = C
|
||||
}}
|
||||
).
|
||||
|
||||
-define(share(P, Q, C, RM),
|
||||
{share, #domain_CashVolumeShare{
|
||||
parts = #'Rational'{p = P, q = Q}, 'of' = C, 'rounding_method' = RM}
|
||||
}
|
||||
parts = #'Rational'{p = P, q = Q},
|
||||
'of' = C,
|
||||
'rounding_method' = RM
|
||||
}}
|
||||
).
|
||||
|
||||
-define(cfpost(A1, A2, V),
|
||||
#domain_CashFlowPosting{
|
||||
source = A1,
|
||||
destination = A2,
|
||||
volume = V
|
||||
}
|
||||
).
|
||||
-define(cfpost(A1, A2, V), #domain_CashFlowPosting{
|
||||
source = A1,
|
||||
destination = A2,
|
||||
volume = V
|
||||
}).
|
||||
|
||||
-define(cfpost(A1, A2, V, D),
|
||||
#domain_CashFlowPosting{
|
||||
source = A1,
|
||||
destination = A2,
|
||||
volume = V,
|
||||
details = D
|
||||
}
|
||||
).
|
||||
-define(cfpost(A1, A2, V, D), #domain_CashFlowPosting{
|
||||
source = A1,
|
||||
destination = A2,
|
||||
volume = V,
|
||||
details = D
|
||||
}).
|
||||
|
||||
-endif.
|
||||
|
@ -8,32 +8,33 @@
|
||||
|
||||
-spec bank_card(binary(), {1..12, 2000..9999}, ct_helper:config()) ->
|
||||
#{
|
||||
token := binary(),
|
||||
bin => binary(),
|
||||
masked_pan => binary(),
|
||||
exp_date => {integer(), integer()},
|
||||
token := binary(),
|
||||
bin => binary(),
|
||||
masked_pan => binary(),
|
||||
exp_date => {integer(), integer()},
|
||||
cardholder_name => binary()
|
||||
}.
|
||||
|
||||
bank_card(PAN, {MM, YYYY} = ExpDate, C) ->
|
||||
CardData = #cds_PutCardData{
|
||||
pan = PAN,
|
||||
pan = PAN,
|
||||
exp_date = #cds_ExpDate{month = MM, year = YYYY}
|
||||
},
|
||||
Client = ff_woody_client:new(maps:get('cds', ct_helper:cfg(services, C))),
|
||||
WoodyCtx = ct_helper:get_woody_ctx(C),
|
||||
Request = {{cds_proto_storage_thrift, 'Storage'}, 'PutCard', [CardData]},
|
||||
case woody_client:call(Request, Client, WoodyCtx) of
|
||||
{ok, #cds_PutCardResult{bank_card = #cds_BankCard{
|
||||
token = Token,
|
||||
bin = BIN,
|
||||
last_digits = Masked
|
||||
}}} ->
|
||||
{ok, #cds_PutCardResult{
|
||||
bank_card = #cds_BankCard{
|
||||
token = Token,
|
||||
bin = BIN,
|
||||
last_digits = Masked
|
||||
}
|
||||
}} ->
|
||||
#{
|
||||
token => Token,
|
||||
bin => BIN,
|
||||
masked_pan => Masked,
|
||||
exp_date => ExpDate,
|
||||
token => Token,
|
||||
bin => BIN,
|
||||
masked_pan => Masked,
|
||||
exp_date => ExpDate,
|
||||
cardholder_name => <<"ct_cardholder_name">>
|
||||
}
|
||||
end.
|
||||
|
@ -35,9 +35,7 @@
|
||||
-type object() ::
|
||||
dmsl_domain_thrift:'DomainObject'().
|
||||
|
||||
-spec p2p_provider(?dtp('ProviderRef'), ?dtp('ProxyRef'), binary(), ct_helper:config()) ->
|
||||
object().
|
||||
|
||||
-spec p2p_provider(?dtp('ProviderRef'), ?dtp('ProxyRef'), binary(), ct_helper:config()) -> object().
|
||||
p2p_provider(Ref, ProxyRef, IdentityID, C) ->
|
||||
AccountID = account(<<"RUB">>, C),
|
||||
{provider, #domain_ProviderObject{
|
||||
@ -51,44 +49,54 @@ p2p_provider(Ref, ProxyRef, IdentityID, C) ->
|
||||
wallet = #domain_WalletProvisionTerms{
|
||||
p2p = #domain_P2PProvisionTerms{
|
||||
currencies = {value, ?ordset([?cur(<<"RUB">>)])},
|
||||
cash_limit = {value, ?cashrng(
|
||||
{inclusive, ?cash( 0, <<"RUB">>)},
|
||||
{exclusive, ?cash(10000000, <<"RUB">>)}
|
||||
)},
|
||||
cash_flow = {decisions, [
|
||||
#domain_CashFlowDecision{
|
||||
if_ = {condition, {currency_is, ?cur(<<"RUB">>)}},
|
||||
then_ = {value, [
|
||||
?cfpost(
|
||||
{system, settlement},
|
||||
{provider, settlement},
|
||||
{product, {min_of, ?ordset([
|
||||
?fixed(10, <<"RUB">>),
|
||||
?share(5, 100, operation_amount, round_half_towards_zero)
|
||||
])}}
|
||||
)
|
||||
]}
|
||||
}
|
||||
]},
|
||||
fees = {decisions, [
|
||||
#domain_FeeDecision{
|
||||
if_ = {condition, {currency_is, ?cur(<<"RUB">>)}},
|
||||
then_ = {value, #domain_Fees{
|
||||
fees = #{surplus => ?share(1, 1, operation_amount)}
|
||||
}}
|
||||
},
|
||||
#domain_FeeDecision{
|
||||
if_ = {condition, {currency_is, ?cur(<<"USD">>)}},
|
||||
then_ = {value, #domain_Fees{
|
||||
fees = #{surplus => ?share(1, 1, operation_amount)}
|
||||
}}
|
||||
}#domain_FeeDecision{
|
||||
if_ = {condition, {currency_is, ?cur(<<"EUR">>)}},
|
||||
then_ = {value, #domain_Fees{
|
||||
fees = #{surplus => ?share(1, 1, operation_amount)}
|
||||
}}
|
||||
}
|
||||
]}
|
||||
cash_limit =
|
||||
{value,
|
||||
?cashrng(
|
||||
{inclusive, ?cash(0, <<"RUB">>)},
|
||||
{exclusive, ?cash(10000000, <<"RUB">>)}
|
||||
)},
|
||||
cash_flow =
|
||||
{decisions, [
|
||||
#domain_CashFlowDecision{
|
||||
if_ = {condition, {currency_is, ?cur(<<"RUB">>)}},
|
||||
then_ =
|
||||
{value, [
|
||||
?cfpost(
|
||||
{system, settlement},
|
||||
{provider, settlement},
|
||||
{product,
|
||||
{min_of,
|
||||
?ordset([
|
||||
?fixed(10, <<"RUB">>),
|
||||
?share(5, 100, operation_amount, round_half_towards_zero)
|
||||
])}}
|
||||
)
|
||||
]}
|
||||
}
|
||||
]},
|
||||
fees =
|
||||
{decisions, [
|
||||
#domain_FeeDecision{
|
||||
if_ = {condition, {currency_is, ?cur(<<"RUB">>)}},
|
||||
then_ =
|
||||
{value, #domain_Fees{
|
||||
fees = #{surplus => ?share(1, 1, operation_amount)}
|
||||
}}
|
||||
},
|
||||
#domain_FeeDecision{
|
||||
if_ = {condition, {currency_is, ?cur(<<"USD">>)}},
|
||||
then_ =
|
||||
{value, #domain_Fees{
|
||||
fees = #{surplus => ?share(1, 1, operation_amount)}
|
||||
}}
|
||||
}#domain_FeeDecision{
|
||||
if_ = {condition, {currency_is, ?cur(<<"EUR">>)}},
|
||||
then_ =
|
||||
{value, #domain_Fees{
|
||||
fees = #{surplus => ?share(1, 1, operation_amount)}
|
||||
}}
|
||||
}
|
||||
]}
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -98,9 +106,7 @@ p2p_provider(Ref, ProxyRef, IdentityID, C) ->
|
||||
}
|
||||
}}.
|
||||
|
||||
-spec withdrawal_provider(?dtp('ProviderRef'), ?dtp('ProxyRef'), binary(), ct_helper:config()) ->
|
||||
object().
|
||||
|
||||
-spec withdrawal_provider(?dtp('ProviderRef'), ?dtp('ProxyRef'), binary(), ct_helper:config()) -> object().
|
||||
withdrawal_provider(?prv(16) = Ref, ProxyRef, IdentityID, C) ->
|
||||
AccountID = account(<<"RUB">>, C),
|
||||
{provider, #domain_ProviderObject{
|
||||
@ -114,15 +120,15 @@ withdrawal_provider(?prv(16) = Ref, ProxyRef, IdentityID, C) ->
|
||||
accounts = #{
|
||||
?cur(<<"RUB">>) => #domain_ProviderAccount{settlement = AccountID}
|
||||
},
|
||||
terminal = {decisions, [
|
||||
#domain_TerminalDecision{
|
||||
if_ = {constant, true},
|
||||
then_ = {value, [?prv_trm(6)]}
|
||||
}
|
||||
]}
|
||||
terminal =
|
||||
{decisions, [
|
||||
#domain_TerminalDecision{
|
||||
if_ = {constant, true},
|
||||
then_ = {value, [?prv_trm(6)]}
|
||||
}
|
||||
]}
|
||||
}
|
||||
}};
|
||||
|
||||
withdrawal_provider(Ref, ProxyRef, IdentityID, C) ->
|
||||
AccountID = account(<<"RUB">>, C),
|
||||
{provider, #domain_ProviderObject{
|
||||
@ -137,25 +143,31 @@ withdrawal_provider(Ref, ProxyRef, IdentityID, C) ->
|
||||
withdrawals = #domain_WithdrawalProvisionTerms{
|
||||
currencies = {value, ?ordset([?cur(<<"RUB">>)])},
|
||||
payout_methods = {value, ?ordset([])},
|
||||
cash_limit = {value, ?cashrng(
|
||||
{inclusive, ?cash( 0, <<"RUB">>)},
|
||||
{exclusive, ?cash(10000000, <<"RUB">>)}
|
||||
)},
|
||||
cash_flow = {decisions, [
|
||||
#domain_CashFlowDecision{
|
||||
if_ = {condition, {currency_is, ?cur(<<"RUB">>)}},
|
||||
then_ = {value, [
|
||||
?cfpost(
|
||||
{system, settlement},
|
||||
{provider, settlement},
|
||||
{product, {min_of, ?ordset([
|
||||
?fixed(10, <<"RUB">>),
|
||||
?share(5, 100, operation_amount, round_half_towards_zero)
|
||||
])}}
|
||||
)
|
||||
]}
|
||||
}
|
||||
]}
|
||||
cash_limit =
|
||||
{value,
|
||||
?cashrng(
|
||||
{inclusive, ?cash(0, <<"RUB">>)},
|
||||
{exclusive, ?cash(10000000, <<"RUB">>)}
|
||||
)},
|
||||
cash_flow =
|
||||
{decisions, [
|
||||
#domain_CashFlowDecision{
|
||||
if_ = {condition, {currency_is, ?cur(<<"RUB">>)}},
|
||||
then_ =
|
||||
{value, [
|
||||
?cfpost(
|
||||
{system, settlement},
|
||||
{provider, settlement},
|
||||
{product,
|
||||
{min_of,
|
||||
?ordset([
|
||||
?fixed(10, <<"RUB">>),
|
||||
?share(5, 100, operation_amount, round_half_towards_zero)
|
||||
])}}
|
||||
)
|
||||
]}
|
||||
}
|
||||
]}
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -167,38 +179,44 @@ withdrawal_provider(Ref, ProxyRef, IdentityID, C) ->
|
||||
?prv(9) ->
|
||||
{decisions, [
|
||||
#domain_TerminalDecision{
|
||||
if_ = {constant, true},
|
||||
if_ = {constant, true},
|
||||
then_ = {value, [?prv_trm(1, 500)]}
|
||||
}
|
||||
]};
|
||||
?prv(10) ->
|
||||
{decisions, [
|
||||
#domain_TerminalDecision{
|
||||
if_ = {constant, true},
|
||||
if_ = {constant, true},
|
||||
then_ = {value, [?prv_trm(1)]}
|
||||
}
|
||||
]};
|
||||
?prv(11) ->
|
||||
{decisions, [
|
||||
#domain_TerminalDecision{
|
||||
if_ = {constant, true},
|
||||
if_ = {constant, true},
|
||||
then_ = {value, [?prv_trm(1)]}
|
||||
}
|
||||
]};
|
||||
_ ->
|
||||
{decisions, [
|
||||
#domain_TerminalDecision{
|
||||
if_ = {condition, {cost_in, ?cashrng(
|
||||
{inclusive, ?cash( 0, <<"RUB">>)},
|
||||
{exclusive, ?cash(1000000, <<"RUB">>)}
|
||||
)}},
|
||||
if_ =
|
||||
{condition,
|
||||
{cost_in,
|
||||
?cashrng(
|
||||
{inclusive, ?cash(0, <<"RUB">>)},
|
||||
{exclusive, ?cash(1000000, <<"RUB">>)}
|
||||
)}},
|
||||
then_ = {value, [?prv_trm(1)]}
|
||||
},
|
||||
#domain_TerminalDecision{
|
||||
if_ = {condition, {cost_in, ?cashrng(
|
||||
{inclusive, ?cash( 3000000, <<"RUB">>)},
|
||||
{exclusive, ?cash(10000000, <<"RUB">>)}
|
||||
)}},
|
||||
if_ =
|
||||
{condition,
|
||||
{cost_in,
|
||||
?cashrng(
|
||||
{inclusive, ?cash(3000000, <<"RUB">>)},
|
||||
{exclusive, ?cash(10000000, <<"RUB">>)}
|
||||
)}},
|
||||
then_ = {value, [?prv_trm(7)]}
|
||||
}
|
||||
]}
|
||||
@ -206,8 +224,7 @@ withdrawal_provider(Ref, ProxyRef, IdentityID, C) ->
|
||||
}
|
||||
}}.
|
||||
|
||||
-spec withdrawal_terminal(?dtp('TerminalRef')) ->
|
||||
object().
|
||||
-spec withdrawal_terminal(?dtp('TerminalRef')) -> object().
|
||||
withdrawal_terminal(?trm(1) = Ref) ->
|
||||
{terminal, #domain_TerminalObject{
|
||||
ref = Ref,
|
||||
@ -241,10 +258,12 @@ withdrawal_terminal(?trm(7) = Ref) ->
|
||||
withdrawals = #domain_WithdrawalProvisionTerms{
|
||||
currencies = {value, ?ordset([?cur(<<"BTC">>)])},
|
||||
payout_methods = {value, ?ordset([])},
|
||||
cash_limit = {value, ?cashrng(
|
||||
{inclusive, ?cash( 1000000, <<"BTC">>)},
|
||||
{exclusive, ?cash(10000000, <<"BTC">>)}
|
||||
)},
|
||||
cash_limit =
|
||||
{value,
|
||||
?cashrng(
|
||||
{inclusive, ?cash(1000000, <<"BTC">>)},
|
||||
{exclusive, ?cash(10000000, <<"BTC">>)}
|
||||
)},
|
||||
cash_flow = {value, ?ordset([])}
|
||||
}
|
||||
}
|
||||
@ -252,66 +271,60 @@ withdrawal_terminal(?trm(7) = Ref) ->
|
||||
}
|
||||
}}.
|
||||
|
||||
-spec currency(?dtp('CurrencyRef')) ->
|
||||
object().
|
||||
|
||||
-spec currency(?dtp('CurrencyRef')) -> object().
|
||||
currency(?cur(<<"EUR">> = SymCode) = Ref) ->
|
||||
{currency, #domain_CurrencyObject{
|
||||
ref = Ref,
|
||||
data = #domain_Currency{
|
||||
name = <<"Europe"/utf8>>,
|
||||
numeric_code = 978,
|
||||
name = <<"Europe"/utf8>>,
|
||||
numeric_code = 978,
|
||||
symbolic_code = SymCode,
|
||||
exponent = 2
|
||||
exponent = 2
|
||||
}
|
||||
}};
|
||||
currency(?cur(<<"RUB">> = SymCode) = Ref) ->
|
||||
{currency, #domain_CurrencyObject{
|
||||
ref = Ref,
|
||||
data = #domain_Currency{
|
||||
name = <<"Яussian Яuble"/utf8>>,
|
||||
numeric_code = 643,
|
||||
name = <<"Яussian Яuble"/utf8>>,
|
||||
numeric_code = 643,
|
||||
symbolic_code = SymCode,
|
||||
exponent = 2
|
||||
exponent = 2
|
||||
}
|
||||
}};
|
||||
currency(?cur(<<"USD">> = SymCode) = Ref) ->
|
||||
{currency, #domain_CurrencyObject{
|
||||
ref = Ref,
|
||||
data = #domain_Currency{
|
||||
name = <<"U$ Dollar">>,
|
||||
numeric_code = 840,
|
||||
name = <<"U$ Dollar">>,
|
||||
numeric_code = 840,
|
||||
symbolic_code = SymCode,
|
||||
exponent = 2
|
||||
exponent = 2
|
||||
}
|
||||
}};
|
||||
currency(?cur(<<"BTC">> = SymCode) = Ref) ->
|
||||
{currency, #domain_CurrencyObject{
|
||||
ref = Ref,
|
||||
data = #domain_Currency{
|
||||
name = <<"Bitcoin">>,
|
||||
numeric_code = 999,
|
||||
name = <<"Bitcoin">>,
|
||||
numeric_code = 999,
|
||||
symbolic_code = SymCode,
|
||||
exponent = 10
|
||||
exponent = 10
|
||||
}
|
||||
}}.
|
||||
|
||||
-spec category(?dtp('CategoryRef'), binary(), ?dtp('CategoryType')) ->
|
||||
object().
|
||||
|
||||
-spec category(?dtp('CategoryRef'), binary(), ?dtp('CategoryType')) -> object().
|
||||
category(Ref, Name, Type) ->
|
||||
{category, #domain_CategoryObject{
|
||||
ref = Ref,
|
||||
data = #domain_Category{
|
||||
name = Name,
|
||||
name = Name,
|
||||
description = <<>>,
|
||||
type = Type
|
||||
type = Type
|
||||
}
|
||||
}}.
|
||||
|
||||
-spec payment_method(?dtp('PaymentMethodRef')) ->
|
||||
object().
|
||||
|
||||
-spec payment_method(?dtp('PaymentMethodRef')) -> object().
|
||||
payment_method(?pmt(_Type, Name) = Ref) when is_atom(Name) ->
|
||||
payment_method(Name, Ref);
|
||||
payment_method(?pmt(_Type, #domain_BankCardPaymentMethod{} = PM) = Ref) ->
|
||||
@ -321,14 +334,12 @@ payment_method(Name, Ref) ->
|
||||
{payment_method, #domain_PaymentMethodObject{
|
||||
ref = Ref,
|
||||
data = #domain_PaymentMethodDefinition{
|
||||
name = erlang:atom_to_binary(Name, unicode),
|
||||
name = erlang:atom_to_binary(Name, unicode),
|
||||
description = <<>>
|
||||
}
|
||||
}}.
|
||||
|
||||
-spec contract_template(?dtp('ContractTemplateRef'), ?dtp('TermSetHierarchyRef')) ->
|
||||
object().
|
||||
|
||||
-spec contract_template(?dtp('ContractTemplateRef'), ?dtp('TermSetHierarchyRef')) -> object().
|
||||
contract_template(Ref, TermsRef) ->
|
||||
contract_template(Ref, TermsRef, undefined, undefined).
|
||||
|
||||
@ -342,75 +353,60 @@ contract_template(Ref, TermsRef, ValidSince, ValidUntil) ->
|
||||
}
|
||||
}}.
|
||||
|
||||
-spec inspector(?dtp('InspectorRef'), binary(), ?dtp('ProxyRef')) ->
|
||||
object().
|
||||
|
||||
-spec inspector(?dtp('InspectorRef'), binary(), ?dtp('ProxyRef')) -> object().
|
||||
inspector(Ref, Name, ProxyRef) ->
|
||||
inspector(Ref, Name, ProxyRef, #{}).
|
||||
|
||||
-spec inspector(?dtp('InspectorRef'), binary(), ?dtp('ProxyRef'), ?dtp('ProxyOptions')) ->
|
||||
object().
|
||||
|
||||
-spec inspector(?dtp('InspectorRef'), binary(), ?dtp('ProxyRef'), ?dtp('ProxyOptions')) -> object().
|
||||
inspector(Ref, Name, ProxyRef, Additional) ->
|
||||
{inspector, #domain_InspectorObject{
|
||||
ref = Ref,
|
||||
ref = Ref,
|
||||
data = #domain_Inspector{
|
||||
name = Name,
|
||||
name = Name,
|
||||
description = <<>>,
|
||||
proxy = #domain_Proxy{
|
||||
ref = ProxyRef,
|
||||
ref = ProxyRef,
|
||||
additional = Additional
|
||||
}
|
||||
}
|
||||
}}.
|
||||
|
||||
-spec p2p_inspector(?dtp('P2PInspectorRef'), binary(), ?dtp('ProxyRef'), ?dtp('ProxyOptions')) ->
|
||||
object().
|
||||
|
||||
-spec p2p_inspector(?dtp('P2PInspectorRef'), binary(), ?dtp('ProxyRef'), ?dtp('ProxyOptions')) -> object().
|
||||
p2p_inspector(Ref, Name, ProxyRef, Additional) ->
|
||||
{p2p_inspector, #domain_P2PInspectorObject{
|
||||
ref = Ref,
|
||||
ref = Ref,
|
||||
data = #domain_P2PInspector{
|
||||
name = Name,
|
||||
name = Name,
|
||||
description = <<>>,
|
||||
fallback_risk_score = #{<<"fraud">> => high},
|
||||
proxy = #domain_Proxy{
|
||||
ref = ProxyRef,
|
||||
ref = ProxyRef,
|
||||
additional = Additional
|
||||
}
|
||||
}
|
||||
}}.
|
||||
|
||||
-spec proxy(?dtp('ProxyRef'), Name :: binary()) ->
|
||||
object().
|
||||
|
||||
-spec proxy(?dtp('ProxyRef'), Name :: binary()) -> object().
|
||||
proxy(Ref, Name) ->
|
||||
proxy(Ref, Name, <<>>).
|
||||
|
||||
-spec proxy(?dtp('ProxyRef'), Name :: binary(), URL :: binary()) ->
|
||||
object().
|
||||
|
||||
-spec proxy(?dtp('ProxyRef'), Name :: binary(), URL :: binary()) -> object().
|
||||
proxy(Ref, Name, URL) ->
|
||||
proxy(Ref, Name, URL, #{}).
|
||||
|
||||
|
||||
-spec proxy(?dtp('ProxyRef'), Name :: binary(), URL :: binary(), ?dtp('ProxyOptions')) ->
|
||||
object().
|
||||
|
||||
-spec proxy(?dtp('ProxyRef'), Name :: binary(), URL :: binary(), ?dtp('ProxyOptions')) -> object().
|
||||
proxy(Ref, Name, URL, Opts) ->
|
||||
{proxy, #domain_ProxyObject{
|
||||
ref = Ref,
|
||||
ref = Ref,
|
||||
data = #domain_ProxyDefinition{
|
||||
name = Name,
|
||||
name = Name,
|
||||
description = <<>>,
|
||||
url = URL,
|
||||
options = Opts
|
||||
url = URL,
|
||||
options = Opts
|
||||
}
|
||||
}}.
|
||||
|
||||
-spec system_account_set(?dtp('SystemAccountSetRef'), binary(), ?dtp('CurrencyRef'), ct_helper:config()) ->
|
||||
object().
|
||||
|
||||
-spec system_account_set(?dtp('SystemAccountSetRef'), binary(), ?dtp('CurrencyRef'), ct_helper:config()) -> object().
|
||||
system_account_set(Ref, Name, ?cur(SymCode), C) ->
|
||||
AccountID1 = account(SymCode, C),
|
||||
AccountID2 = account(SymCode, C),
|
||||
@ -430,7 +426,6 @@ system_account_set(Ref, Name, ?cur(SymCode), C) ->
|
||||
|
||||
-spec external_account_set(?dtp('ExternalAccountSetRef'), binary(), ?dtp('CurrencyRef'), ct_helper:config()) ->
|
||||
object().
|
||||
|
||||
external_account_set(Ref, Name, ?cur(SymCode), C) ->
|
||||
AccountID1 = account(SymCode, C),
|
||||
AccountID2 = account(SymCode, C),
|
||||
@ -441,29 +436,23 @@ external_account_set(Ref, Name, ?cur(SymCode), C) ->
|
||||
description = <<>>,
|
||||
accounts = #{
|
||||
?cur(SymCode) => #domain_ExternalAccount{
|
||||
income = AccountID1,
|
||||
income = AccountID1,
|
||||
outcome = AccountID2
|
||||
}
|
||||
}
|
||||
}
|
||||
}}.
|
||||
|
||||
-spec term_set_hierarchy(?dtp('TermSetHierarchyRef')) ->
|
||||
object().
|
||||
|
||||
-spec term_set_hierarchy(?dtp('TermSetHierarchyRef')) -> object().
|
||||
term_set_hierarchy(Ref) ->
|
||||
term_set_hierarchy(Ref, []).
|
||||
|
||||
-spec term_set_hierarchy(?dtp('TermSetHierarchyRef'), [?dtp('TimedTermSet')]) ->
|
||||
object().
|
||||
|
||||
-spec term_set_hierarchy(?dtp('TermSetHierarchyRef'), [?dtp('TimedTermSet')]) -> object().
|
||||
term_set_hierarchy(Ref, TermSets) ->
|
||||
term_set_hierarchy(Ref, undefined, TermSets).
|
||||
|
||||
-spec term_set_hierarchy(Ref, ff_maybe:maybe(Ref), [?dtp('TimedTermSet')]) ->
|
||||
object() when
|
||||
Ref :: ?dtp('TermSetHierarchyRef').
|
||||
|
||||
-spec term_set_hierarchy(Ref, ff_maybe:maybe(Ref), [?dtp('TimedTermSet')]) -> object() when
|
||||
Ref :: ?dtp('TermSetHierarchyRef').
|
||||
term_set_hierarchy(Ref, ParentRef, TermSets) ->
|
||||
{term_set_hierarchy, #domain_TermSetHierarchyObject{
|
||||
ref = Ref,
|
||||
@ -473,18 +462,14 @@ term_set_hierarchy(Ref, ParentRef, TermSets) ->
|
||||
}
|
||||
}}.
|
||||
|
||||
-spec timed_term_set(?dtp('TermSet')) ->
|
||||
?dtp('TimedTermSet').
|
||||
|
||||
-spec timed_term_set(?dtp('TermSet')) -> ?dtp('TimedTermSet').
|
||||
timed_term_set(TermSet) ->
|
||||
#domain_TimedTermSet{
|
||||
action_time = #'TimestampInterval'{},
|
||||
terms = TermSet
|
||||
}.
|
||||
|
||||
-spec globals(?dtp('ExternalAccountSetRef'), [?dtp('PaymentInstitutionRef')]) ->
|
||||
object().
|
||||
|
||||
-spec globals(?dtp('ExternalAccountSetRef'), [?dtp('PaymentInstitutionRef')]) -> object().
|
||||
globals(EASRef, PIRefs) ->
|
||||
{globals, #domain_GlobalsObject{
|
||||
ref = ?glob(),
|
||||
@ -494,16 +479,14 @@ globals(EASRef, PIRefs) ->
|
||||
}
|
||||
}}.
|
||||
|
||||
-spec account(binary(), ct_helper:config()) ->
|
||||
shumpune_shumpune_thrift:'AccountID'().
|
||||
|
||||
-spec account(binary(), ct_helper:config()) -> shumpune_shumpune_thrift:'AccountID'().
|
||||
account(SymCode, C) ->
|
||||
Client = ff_woody_client:new(maps:get('accounter', ct_helper:cfg(services, C))),
|
||||
WoodyCtx = ct_helper:get_woody_ctx(C),
|
||||
Prototype = #shumpune_AccountPrototype{
|
||||
currency_sym_code = SymCode,
|
||||
description = <<>>,
|
||||
creation_time = timestamp()
|
||||
description = <<>>,
|
||||
creation_time = timestamp()
|
||||
},
|
||||
Request = {{shumpune_shumpune_thrift, 'Accounter'}, 'CreateAccount', [Prototype]},
|
||||
case woody_client:call(Request, Client, WoodyCtx) of
|
||||
|
@ -20,24 +20,21 @@
|
||||
-include_lib("damsel/include/dmsl_domain_config_thrift.hrl").
|
||||
|
||||
-type revision() :: pos_integer().
|
||||
-type ref() :: dmsl_domain_thrift:'Reference'().
|
||||
-type object() :: dmsl_domain_thrift:'DomainObject'().
|
||||
-type data() :: _.
|
||||
-type ref() :: dmsl_domain_thrift:'Reference'().
|
||||
-type object() :: dmsl_domain_thrift:'DomainObject'().
|
||||
-type data() :: _.
|
||||
|
||||
-spec head() -> revision().
|
||||
|
||||
head() ->
|
||||
#'Snapshot'{version = Version} = dmt_client:checkout({head, #'Head'{}}),
|
||||
Version.
|
||||
|
||||
-spec all(revision()) -> dmsl_domain_thrift:'Domain'().
|
||||
|
||||
all(Revision) ->
|
||||
#'Snapshot'{domain = Domain} = dmt_client:checkout({version, Revision}),
|
||||
Domain.
|
||||
|
||||
-spec get(revision(), ref()) -> data() | no_return().
|
||||
|
||||
get(Revision, Ref) ->
|
||||
try
|
||||
extract_data(dmt_client:checkout_object({version, Revision}, Ref))
|
||||
@ -47,7 +44,6 @@ get(Revision, Ref) ->
|
||||
end.
|
||||
|
||||
-spec find(revision(), ref()) -> data() | notfound.
|
||||
|
||||
find(Revision, Ref) ->
|
||||
try
|
||||
extract_data(dmt_client:checkout_object({version, Revision}, Ref))
|
||||
@ -60,14 +56,12 @@ extract_data(#'VersionedObject'{object = {_Tag, {_Name, _Ref, Data}}}) ->
|
||||
Data.
|
||||
|
||||
-spec commit(revision(), dmt_client:commit()) -> ok | no_return().
|
||||
|
||||
commit(Revision, Commit) ->
|
||||
Revision = dmt_client:commit(Revision, Commit) - 1,
|
||||
_ = all(Revision + 1),
|
||||
ok.
|
||||
|
||||
-spec insert(object() | [object()]) -> ok | no_return().
|
||||
|
||||
insert(Object) when not is_list(Object) ->
|
||||
insert([Object]);
|
||||
insert(Objects) ->
|
||||
@ -75,14 +69,13 @@ insert(Objects) ->
|
||||
ops = [
|
||||
{insert, #'InsertOp'{
|
||||
object = Object
|
||||
}} ||
|
||||
Object <- Objects
|
||||
}}
|
||||
|| Object <- Objects
|
||||
]
|
||||
},
|
||||
commit(head(), Commit).
|
||||
|
||||
-spec update(object() | [object()]) -> ok | no_return().
|
||||
|
||||
update(NewObject) when not is_list(NewObject) ->
|
||||
update([NewObject]);
|
||||
update(NewObjects) ->
|
||||
@ -93,33 +86,38 @@ update(NewObjects) ->
|
||||
old_object = {Tag, {ObjectName, Ref, OldData}},
|
||||
new_object = NewObject
|
||||
}}
|
||||
|| NewObject = {Tag, {ObjectName, Ref, _Data}} <- NewObjects,
|
||||
OldData <- [get(Revision, {Tag, Ref})]
|
||||
|| NewObject = {Tag, {ObjectName, Ref, _Data}} <- NewObjects,
|
||||
OldData <- [get(Revision, {Tag, Ref})]
|
||||
]
|
||||
},
|
||||
commit(Revision, Commit).
|
||||
|
||||
-spec upsert(object() | [object()]) -> ok | no_return().
|
||||
|
||||
upsert(NewObject) when not is_list(NewObject) ->
|
||||
upsert([NewObject]);
|
||||
upsert(NewObjects) ->
|
||||
Revision = head(),
|
||||
Commit = #'Commit'{
|
||||
ops = lists:foldl(
|
||||
fun (NewObject = {Tag, {ObjectName, Ref, NewData}}, Ops) ->
|
||||
fun(NewObject = {Tag, {ObjectName, Ref, NewData}}, Ops) ->
|
||||
case find(Revision, {Tag, Ref}) of
|
||||
NewData ->
|
||||
Ops;
|
||||
notfound ->
|
||||
[{insert, #'InsertOp'{
|
||||
object = NewObject
|
||||
}} | Ops];
|
||||
[
|
||||
{insert, #'InsertOp'{
|
||||
object = NewObject
|
||||
}}
|
||||
| Ops
|
||||
];
|
||||
OldData ->
|
||||
[{update, #'UpdateOp'{
|
||||
old_object = {Tag, {ObjectName, Ref, OldData}},
|
||||
new_object = NewObject
|
||||
}} | Ops]
|
||||
[
|
||||
{update, #'UpdateOp'{
|
||||
old_object = {Tag, {ObjectName, Ref, OldData}},
|
||||
new_object = NewObject
|
||||
}}
|
||||
| Ops
|
||||
]
|
||||
end
|
||||
end,
|
||||
[],
|
||||
@ -129,7 +127,6 @@ upsert(NewObjects) ->
|
||||
commit(Revision, Commit).
|
||||
|
||||
-spec remove(object() | [object()]) -> ok | no_return().
|
||||
|
||||
remove(Object) when not is_list(Object) ->
|
||||
remove([Object]);
|
||||
remove(Objects) ->
|
||||
@ -137,25 +134,22 @@ remove(Objects) ->
|
||||
ops = [
|
||||
{remove, #'RemoveOp'{
|
||||
object = Object
|
||||
}} ||
|
||||
Object <- Objects
|
||||
}}
|
||||
|| Object <- Objects
|
||||
]
|
||||
},
|
||||
commit(head(), Commit).
|
||||
|
||||
-spec reset(revision()) -> ok | no_return().
|
||||
|
||||
reset(Revision) ->
|
||||
upsert(maps:values(all(Revision))).
|
||||
|
||||
-spec cleanup() -> ok | no_return().
|
||||
|
||||
cleanup() ->
|
||||
Domain = all(head()),
|
||||
remove(maps:values(Domain)).
|
||||
|
||||
-spec bump_revision() -> ok | no_return().
|
||||
|
||||
bump_revision() ->
|
||||
Commit = #'Commit'{ops = []},
|
||||
Revision = dmt_client:get_last_version(),
|
||||
|
@ -16,7 +16,7 @@
|
||||
ff_services:service_name().
|
||||
|
||||
-type event() ::
|
||||
ff_proto_wallet_thrift:'SinkEvent'()
|
||||
ff_proto_wallet_thrift:'SinkEvent'()
|
||||
| ff_proto_withdrawal_thrift:'SinkEvent'()
|
||||
| ff_proto_identity_thrift:'SinkEvent'()
|
||||
| ff_proto_destination_thrift:'SinkEvent'()
|
||||
@ -26,11 +26,10 @@
|
||||
| ff_proto_p2p_transfer_thrift:'SinkEvent'()
|
||||
| ff_proto_p2p_session_thrift:'SinkEvent'()
|
||||
| ff_proto_w2w_transfer_thrift:'SinkEvent'()
|
||||
| ff_proto_p2p_template_thrift:'SinkEvent'()
|
||||
.
|
||||
| ff_proto_p2p_template_thrift:'SinkEvent'().
|
||||
|
||||
-type event_id() :: ff_proto_eventsink_thrift:'EventID'().
|
||||
-type limit() :: non_neg_integer().
|
||||
-type limit() :: non_neg_integer().
|
||||
|
||||
-export([last_id/1]).
|
||||
|
||||
@ -43,7 +42,6 @@
|
||||
%%
|
||||
|
||||
-spec last_id(sink()) -> event_id() | 0.
|
||||
|
||||
last_id(Sink) ->
|
||||
case call_handler('GetLastEventID', Sink, []) of
|
||||
{ok, EventID} ->
|
||||
@ -53,19 +51,16 @@ last_id(Sink) ->
|
||||
end.
|
||||
|
||||
-spec events(_After :: event_id() | undefined, limit(), sink()) -> {[event()], _Last :: event_id()}.
|
||||
|
||||
events(After, Limit, Sink) ->
|
||||
Range = #'evsink_EventRange'{'after' = After, limit = Limit},
|
||||
{ok, Events} = call_handler('GetEvents', Sink, [Range]),
|
||||
{Events, get_max_event_id(Events)}.
|
||||
|
||||
-spec consume(_ChunkSize :: limit(), sink()) -> [event()].
|
||||
|
||||
consume(ChunkSize, Sink) ->
|
||||
fold(fun (Chunk, Acc) -> Chunk ++ Acc end, [], ChunkSize, Sink).
|
||||
fold(fun(Chunk, Acc) -> Chunk ++ Acc end, [], ChunkSize, Sink).
|
||||
|
||||
-spec fold(fun(([event()], State) -> State), State, _ChunkSize :: limit(), sink()) -> State.
|
||||
|
||||
fold(FoldFun, InitialState, ChunkSize, Sink) ->
|
||||
fold(FoldFun, InitialState, ChunkSize, Sink, undefined).
|
||||
|
||||
@ -80,12 +75,10 @@ fold(FoldFun, State0, ChunkSize, Sink, Cursor) ->
|
||||
end.
|
||||
|
||||
-spec get_max_event_id([event()]) -> event_id().
|
||||
|
||||
get_max_event_id(Events) when is_list(Events) ->
|
||||
lists:foldl(fun (Ev, Max) -> erlang:max(get_event_id(Ev), Max) end, 0, Events).
|
||||
lists:foldl(fun(Ev, Max) -> erlang:max(get_event_id(Ev), Max) end, 0, Events).
|
||||
|
||||
-spec get_event_id(event()) -> event_id().
|
||||
|
||||
get_event_id(#'wlt_SinkEvent'{id = ID}) -> ID;
|
||||
get_event_id(#'wthd_SinkEvent'{id = ID}) -> ID;
|
||||
get_event_id(#'idnt_SinkEvent'{id = ID}) -> ID;
|
||||
@ -102,8 +95,8 @@ call_handler(Function, ServiceName, Args) ->
|
||||
Service = ff_services:get_service(ServiceName),
|
||||
Path = erlang:list_to_binary(ff_services:get_service_path(ServiceName)),
|
||||
Request = {Service, Function, Args},
|
||||
Client = ff_woody_client:new(#{
|
||||
url => <<"http://localhost:8022", Path/binary>>,
|
||||
Client = ff_woody_client:new(#{
|
||||
url => <<"http://localhost:8022", Path/binary>>,
|
||||
event_handler => scoper_woody_event_handler
|
||||
}),
|
||||
ff_woody_client:call(Client, Request).
|
||||
|
@ -34,30 +34,27 @@
|
||||
%%
|
||||
|
||||
-spec cfg(atom(), config()) -> term().
|
||||
|
||||
cfg(Key, Config) ->
|
||||
case lists:keyfind(Key, 1, Config) of
|
||||
{Key, V} -> V;
|
||||
_ -> error({'ct config entry missing', Key})
|
||||
_ -> error({'ct config entry missing', Key})
|
||||
end.
|
||||
|
||||
-spec cfg(atom(), _, config()) -> config().
|
||||
|
||||
cfg(Key, Value, Config) ->
|
||||
lists:keystore(Key, 1, Config, {Key, Value}).
|
||||
|
||||
%%
|
||||
|
||||
-type app_name() :: atom().
|
||||
-type app_env() :: [{atom(), term()}].
|
||||
-type app_name() :: atom().
|
||||
-type app_env() :: [{atom(), term()}].
|
||||
-type app_with_env() :: {app_name(), app_env()}.
|
||||
-type startup_ctx() :: #{atom() => _}.
|
||||
-type startup_ctx() :: #{atom() => _}.
|
||||
|
||||
-spec start_apps([app_name() | app_with_env()]) -> {[Started :: app_name()], startup_ctx()}.
|
||||
|
||||
start_apps(AppNames) ->
|
||||
lists:foldl(
|
||||
fun (AppName, {SAcc, CtxAcc}) ->
|
||||
fun(AppName, {SAcc, CtxAcc}) ->
|
||||
{Started, Ctx} = start_app(AppName),
|
||||
{SAcc ++ Started, maps:merge(CtxAcc, Ctx)}
|
||||
end,
|
||||
@ -66,153 +63,144 @@ start_apps(AppNames) ->
|
||||
).
|
||||
|
||||
-spec start_app(app_name() | app_with_env()) -> {[Started :: app_name()], startup_ctx()}.
|
||||
|
||||
start_app(scoper = AppName) ->
|
||||
{start_app_with(AppName, [
|
||||
{storage, scoper_storage_logger}
|
||||
]), #{}};
|
||||
|
||||
{storage, scoper_storage_logger}
|
||||
]), #{}};
|
||||
start_app(woody = AppName) ->
|
||||
{start_app_with(AppName, [
|
||||
{acceptors_pool_size, 4}
|
||||
]), #{}};
|
||||
|
||||
{acceptors_pool_size, 4}
|
||||
]), #{}};
|
||||
start_app(dmt_client = AppName) ->
|
||||
{start_app_with(AppName, [
|
||||
{cache_update_interval, 500}, % milliseconds
|
||||
{max_cache_size, #{
|
||||
elements => 1,
|
||||
memory => 52428800 % 50Mb
|
||||
}},
|
||||
{woody_event_handlers, [
|
||||
{scoper_woody_event_handler, #{}}
|
||||
]},
|
||||
{service_urls, #{
|
||||
'Repository' => <<"http://dominant:8022/v1/domain/repository">>,
|
||||
'RepositoryClient' => <<"http://dominant:8022/v1/domain/repository_client">>
|
||||
}}
|
||||
]), #{}};
|
||||
|
||||
% milliseconds
|
||||
{cache_update_interval, 500},
|
||||
{max_cache_size, #{
|
||||
elements => 1,
|
||||
% 50Mb
|
||||
memory => 52428800
|
||||
}},
|
||||
{woody_event_handlers, [
|
||||
{scoper_woody_event_handler, #{}}
|
||||
]},
|
||||
{service_urls, #{
|
||||
'Repository' => <<"http://dominant:8022/v1/domain/repository">>,
|
||||
'RepositoryClient' => <<"http://dominant:8022/v1/domain/repository_client">>
|
||||
}}
|
||||
]), #{}};
|
||||
start_app(wapi = AppName) ->
|
||||
{start_app_with(AppName, [
|
||||
{ip, "::"},
|
||||
{port, 8080},
|
||||
{realm, <<"external">>},
|
||||
{public_endpoint, <<"localhost:8080">>},
|
||||
{access_conf, #{
|
||||
jwt => #{
|
||||
keyset => #{
|
||||
wapi => {pem_file, "/opt/wapi/config/private.pem"}
|
||||
{ip, "::"},
|
||||
{port, 8080},
|
||||
{realm, <<"external">>},
|
||||
{public_endpoint, <<"localhost:8080">>},
|
||||
{access_conf, #{
|
||||
jwt => #{
|
||||
keyset => #{
|
||||
wapi => {pem_file, "/opt/wapi/config/private.pem"}
|
||||
}
|
||||
}
|
||||
}
|
||||
}},
|
||||
{signee, wapi},
|
||||
{lechiffre_opts, #{
|
||||
encryption_key_path => "/opt/wapi/config/jwk.json",
|
||||
decryption_key_paths => [
|
||||
"/opt/wapi/config/jwk.json"
|
||||
]
|
||||
}},
|
||||
{swagger_handler_opts, #{
|
||||
validation_opts => #{
|
||||
custom_validator => wapi_swagger_validator
|
||||
}
|
||||
}},
|
||||
{events_fetch_limit, 32}
|
||||
]), #{}};
|
||||
|
||||
}},
|
||||
{signee, wapi},
|
||||
{lechiffre_opts, #{
|
||||
encryption_key_path => "/opt/wapi/config/jwk.json",
|
||||
decryption_key_paths => [
|
||||
"/opt/wapi/config/jwk.json"
|
||||
]
|
||||
}},
|
||||
{swagger_handler_opts, #{
|
||||
validation_opts => #{
|
||||
custom_validator => wapi_swagger_validator
|
||||
}
|
||||
}},
|
||||
{events_fetch_limit, 32}
|
||||
]), #{}};
|
||||
start_app(wapi_woody_client = AppName) ->
|
||||
{start_app_with(AppName, [
|
||||
{service_urls, #{
|
||||
cds_storage => "http://cds:8022/v1/storage",
|
||||
identdoc_storage => "http://cds:8022/v1/identity_document_storage",
|
||||
fistful_stat => "http://fistful-magista:8022/stat",
|
||||
fistful_wallet => "http://localhost:8022/v1/wallet",
|
||||
fistful_identity => "http://localhost:8022/v1/identity",
|
||||
fistful_destination => "http://localhost:8022/v1/destination",
|
||||
fistful_withdrawal => "http://localhost:8022/v1/withdrawal",
|
||||
fistful_w2w_transfer => "http://localhost:8022/v1/w2w_transfer",
|
||||
fistful_p2p_template => "http://localhost:8022/v1/p2p_template",
|
||||
fistful_p2p_transfer => "http://localhost:8022/v1/p2p_transfer",
|
||||
fistful_p2p_session => "http://localhost:8022/v1/p2p_transfer/session"
|
||||
}},
|
||||
{service_retries, #{
|
||||
fistful_stat => #{
|
||||
'GetWallets' => {linear, 3, 1000},
|
||||
'_' => finish
|
||||
}
|
||||
}},
|
||||
{api_deadlines, #{
|
||||
fistful_stat => 5000
|
||||
}}
|
||||
]), #{}};
|
||||
|
||||
{service_urls, #{
|
||||
cds_storage => "http://cds:8022/v1/storage",
|
||||
identdoc_storage => "http://cds:8022/v1/identity_document_storage",
|
||||
fistful_stat => "http://fistful-magista:8022/stat",
|
||||
fistful_wallet => "http://localhost:8022/v1/wallet",
|
||||
fistful_identity => "http://localhost:8022/v1/identity",
|
||||
fistful_destination => "http://localhost:8022/v1/destination",
|
||||
fistful_withdrawal => "http://localhost:8022/v1/withdrawal",
|
||||
fistful_w2w_transfer => "http://localhost:8022/v1/w2w_transfer",
|
||||
fistful_p2p_template => "http://localhost:8022/v1/p2p_template",
|
||||
fistful_p2p_transfer => "http://localhost:8022/v1/p2p_transfer",
|
||||
fistful_p2p_session => "http://localhost:8022/v1/p2p_transfer/session"
|
||||
}},
|
||||
{service_retries, #{
|
||||
fistful_stat => #{
|
||||
'GetWallets' => {linear, 3, 1000},
|
||||
'_' => finish
|
||||
}
|
||||
}},
|
||||
{api_deadlines, #{
|
||||
fistful_stat => 5000
|
||||
}}
|
||||
]), #{}};
|
||||
start_app(ff_server = AppName) ->
|
||||
{start_app_with(AppName, [
|
||||
{ip, "::"},
|
||||
{port, 8022},
|
||||
{admin, #{
|
||||
path => <<"/v1/admin">>
|
||||
}},
|
||||
{eventsink, #{
|
||||
identity => #{
|
||||
namespace => 'ff/identity'
|
||||
},
|
||||
wallet => #{
|
||||
namespace => 'ff/wallet_v2'
|
||||
},
|
||||
withdrawal => #{
|
||||
namespace => 'ff/withdrawal_v2'
|
||||
},
|
||||
deposit => #{
|
||||
namespace => 'ff/deposit_v1'
|
||||
},
|
||||
destination => #{
|
||||
namespace => 'ff/destination_v2'
|
||||
},
|
||||
source => #{
|
||||
namespace => 'ff/source_v1'
|
||||
},
|
||||
withdrawal_session => #{
|
||||
namespace => 'ff/withdrawal/session_v2'
|
||||
},
|
||||
p2p_transfer => #{
|
||||
namespace => 'ff/p2p_transfer_v1'
|
||||
},
|
||||
p2p_session => #{
|
||||
namespace => 'ff/p2p_transfer/session_v1'
|
||||
},
|
||||
w2w_transfer => #{
|
||||
namespace => 'ff/w2w_transfer_v1'
|
||||
},
|
||||
p2p_template => #{
|
||||
namespace => 'ff/p2p_template_v1'
|
||||
}
|
||||
}}
|
||||
]), #{}};
|
||||
|
||||
{ip, "::"},
|
||||
{port, 8022},
|
||||
{admin, #{
|
||||
path => <<"/v1/admin">>
|
||||
}},
|
||||
{eventsink, #{
|
||||
identity => #{
|
||||
namespace => 'ff/identity'
|
||||
},
|
||||
wallet => #{
|
||||
namespace => 'ff/wallet_v2'
|
||||
},
|
||||
withdrawal => #{
|
||||
namespace => 'ff/withdrawal_v2'
|
||||
},
|
||||
deposit => #{
|
||||
namespace => 'ff/deposit_v1'
|
||||
},
|
||||
destination => #{
|
||||
namespace => 'ff/destination_v2'
|
||||
},
|
||||
source => #{
|
||||
namespace => 'ff/source_v1'
|
||||
},
|
||||
withdrawal_session => #{
|
||||
namespace => 'ff/withdrawal/session_v2'
|
||||
},
|
||||
p2p_transfer => #{
|
||||
namespace => 'ff/p2p_transfer_v1'
|
||||
},
|
||||
p2p_session => #{
|
||||
namespace => 'ff/p2p_transfer/session_v1'
|
||||
},
|
||||
w2w_transfer => #{
|
||||
namespace => 'ff/w2w_transfer_v1'
|
||||
},
|
||||
p2p_template => #{
|
||||
namespace => 'ff/p2p_template_v1'
|
||||
}
|
||||
}}
|
||||
]), #{}};
|
||||
start_app(bender_client = AppName) ->
|
||||
{start_app_with(AppName, [
|
||||
{services, #{
|
||||
'Bender' => <<"http://bender:8022/v1/bender">>,
|
||||
'Generator' => <<"http://bender:8022/v1/generator">>
|
||||
}},
|
||||
{deadline, 60000}
|
||||
]), #{}};
|
||||
|
||||
{services, #{
|
||||
'Bender' => <<"http://bender:8022/v1/bender">>,
|
||||
'Generator' => <<"http://bender:8022/v1/generator">>
|
||||
}},
|
||||
{deadline, 60000}
|
||||
]), #{}};
|
||||
start_app(p2p = AppName) ->
|
||||
{start_app_with(AppName, [
|
||||
{score_id, <<"fraud">>}
|
||||
]), #{}};
|
||||
|
||||
{score_id, <<"fraud">>}
|
||||
]), #{}};
|
||||
start_app({AppName, AppEnv}) ->
|
||||
{start_app_with(AppName, AppEnv), #{}};
|
||||
|
||||
start_app(AppName) ->
|
||||
{start_app_with(AppName, []), #{}}.
|
||||
|
||||
-spec start_app_with(app_name(), app_env()) -> [app_name()].
|
||||
|
||||
start_app_with(AppName, Env) ->
|
||||
_ = application:load(AppName),
|
||||
_ = set_app_env(AppName, Env),
|
||||
@ -225,19 +213,17 @@ start_app_with(AppName, Env) ->
|
||||
|
||||
set_app_env(AppName, Env) ->
|
||||
lists:foreach(
|
||||
fun ({K, V}) ->
|
||||
fun({K, V}) ->
|
||||
ok = application:set_env(AppName, K, V)
|
||||
end,
|
||||
Env
|
||||
).
|
||||
|
||||
-spec stop_apps([app_name()]) -> ok.
|
||||
|
||||
stop_apps(AppNames) ->
|
||||
lists:foreach(fun stop_app/1, lists:reverse(AppNames)).
|
||||
|
||||
-spec stop_app(app_name()) -> ok.
|
||||
|
||||
stop_app(AppName) ->
|
||||
case application:stop(AppName) of
|
||||
ok ->
|
||||
@ -252,15 +238,15 @@ stop_app(AppName) ->
|
||||
end.
|
||||
|
||||
-spec set_context(config()) -> ok.
|
||||
|
||||
set_context(C) ->
|
||||
ok = ff_context:save(ff_context:create(#{
|
||||
party_client => party_client:create_client(),
|
||||
woody_context => cfg('$woody_ctx', C)
|
||||
})).
|
||||
ok = ff_context:save(
|
||||
ff_context:create(#{
|
||||
party_client => party_client:create_client(),
|
||||
woody_context => cfg('$woody_ctx', C)
|
||||
})
|
||||
).
|
||||
|
||||
-spec unset_context() -> ok.
|
||||
|
||||
unset_context() ->
|
||||
ok = ff_context:cleanup().
|
||||
|
||||
@ -269,14 +255,12 @@ unset_context() ->
|
||||
-type config_mut_fun() :: fun((config()) -> config()).
|
||||
|
||||
-spec makeup_cfg([config_mut_fun()], config()) -> config().
|
||||
|
||||
makeup_cfg(CMFs, C0) ->
|
||||
lists:foldl(fun (CMF, C) -> CMF(C) end, C0, CMFs).
|
||||
lists:foldl(fun(CMF, C) -> CMF(C) end, C0, CMFs).
|
||||
|
||||
-spec woody_ctx() -> config_mut_fun().
|
||||
|
||||
woody_ctx() ->
|
||||
fun (C) -> cfg('$woody_ctx', construct_woody_ctx(C), C) end.
|
||||
fun(C) -> cfg('$woody_ctx', construct_woody_ctx(C), C) end.
|
||||
|
||||
construct_woody_ctx(C) ->
|
||||
woody_context:new(construct_rpc_id(get_test_case_name(C))).
|
||||
@ -289,33 +273,26 @@ construct_rpc_id(TestCaseName) ->
|
||||
).
|
||||
|
||||
-spec get_woody_ctx(config()) -> woody_context:ctx().
|
||||
|
||||
get_woody_ctx(C) ->
|
||||
cfg('$woody_ctx', C).
|
||||
|
||||
%%
|
||||
|
||||
-spec test_case_name(test_case_name()) -> config_mut_fun().
|
||||
|
||||
test_case_name(TestCaseName) ->
|
||||
fun (C) -> cfg('$test_case_name', TestCaseName, C) end.
|
||||
fun(C) -> cfg('$test_case_name', TestCaseName, C) end.
|
||||
|
||||
-spec get_test_case_name(config()) -> test_case_name().
|
||||
|
||||
get_test_case_name(C) ->
|
||||
cfg('$test_case_name', C).
|
||||
|
||||
%%
|
||||
|
||||
-spec await(Expect, fun(() -> Expect | _)) ->
|
||||
Expect.
|
||||
|
||||
-spec await(Expect, fun(() -> Expect | _)) -> Expect.
|
||||
await(Expect, Compute) ->
|
||||
await(Expect, Compute, genlib_retry:linear(3, 1000)).
|
||||
|
||||
-spec await(Expect, fun(() -> Expect | _), genlib_retry:strategy()) ->
|
||||
Expect.
|
||||
|
||||
-spec await(Expect, fun(() -> Expect | _), genlib_retry:strategy()) -> Expect.
|
||||
await(Expect, Compute, Retry0) ->
|
||||
case Compute() of
|
||||
Expect ->
|
||||
|
@ -7,22 +7,20 @@
|
||||
|
||||
-include_lib("identdocstore_proto/include/identdocstore_identity_document_storage_thrift.hrl").
|
||||
|
||||
-spec rus_domestic_passport(ct_helper:config()) ->
|
||||
{rus_domestic_passport, binary()}.
|
||||
|
||||
-spec rus_domestic_passport(ct_helper:config()) -> {rus_domestic_passport, binary()}.
|
||||
rus_domestic_passport(C) ->
|
||||
Document = {
|
||||
russian_domestic_passport,
|
||||
#identdocstore_RussianDomesticPassport{
|
||||
series = <<"1234">>,
|
||||
number = <<"567890">>,
|
||||
issuer = <<"Чаржбекистон УВД"/utf8>>,
|
||||
series = <<"1234">>,
|
||||
number = <<"567890">>,
|
||||
issuer = <<"Чаржбекистон УВД"/utf8>>,
|
||||
issuer_code = <<"012345">>,
|
||||
issued_at = <<"2012-12-22T12:42:11Z">>,
|
||||
issued_at = <<"2012-12-22T12:42:11Z">>,
|
||||
family_name = <<"Котлетка"/utf8>>,
|
||||
first_name = <<"С"/utf8>>,
|
||||
patronymic = <<"Пюрешкой"/utf8>>,
|
||||
birth_date = <<"1972-03-12T00:00:00Z">>,
|
||||
first_name = <<"С"/utf8>>,
|
||||
patronymic = <<"Пюрешкой"/utf8>>,
|
||||
birth_date = <<"1972-03-12T00:00:00Z">>,
|
||||
birth_place = <<"Чаржбечхала"/utf8>>
|
||||
}
|
||||
},
|
||||
@ -34,9 +32,7 @@ rus_domestic_passport(C) ->
|
||||
{rus_domestic_passport, Token}
|
||||
end.
|
||||
|
||||
-spec rus_retiree_insurance_cert(_Number :: binary(), ct_helper:config()) ->
|
||||
{rus_retiree_insurance_cert, binary()}.
|
||||
|
||||
-spec rus_retiree_insurance_cert(_Number :: binary(), ct_helper:config()) -> {rus_retiree_insurance_cert, binary()}.
|
||||
rus_retiree_insurance_cert(Number, C) ->
|
||||
Document = {
|
||||
russian_retiree_insurance_certificate,
|
||||
|
@ -1,4 +1,5 @@
|
||||
-module(ct_keyring).
|
||||
|
||||
-include_lib("cds_proto/include/cds_proto_keyring_thrift.hrl").
|
||||
|
||||
-include_lib("jose/include/jose_jwk.hrl").
|
||||
@ -15,7 +16,6 @@
|
||||
}.
|
||||
|
||||
-spec init(_) -> ok.
|
||||
|
||||
init(Config) ->
|
||||
case get_state(Config) of
|
||||
not_initialized ->
|
||||
@ -77,15 +77,11 @@ call(Fun, Args, C) ->
|
||||
|
||||
%% DECODE
|
||||
|
||||
-spec decode_encrypted_shares([cds_proto_keyring_thrift:'EncryptedMasterKeyShare'()]) ->
|
||||
[encrypted_master_key_share()].
|
||||
|
||||
-spec decode_encrypted_shares([cds_proto_keyring_thrift:'EncryptedMasterKeyShare'()]) -> [encrypted_master_key_share()].
|
||||
decode_encrypted_shares(EncryptedMasterKeyShares) ->
|
||||
lists:map(fun decode_encrypted_share/1, EncryptedMasterKeyShares).
|
||||
|
||||
-spec decode_encrypted_share(cds_proto_keyring_thrift:'EncryptedMasterKeyShare'()) ->
|
||||
encrypted_master_key_share().
|
||||
|
||||
-spec decode_encrypted_share(cds_proto_keyring_thrift:'EncryptedMasterKeyShare'()) -> encrypted_master_key_share().
|
||||
decode_encrypted_share(#cds_EncryptedMasterKeyShare{
|
||||
id = Id,
|
||||
owner = Owner,
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -6,26 +6,23 @@
|
||||
%%
|
||||
|
||||
-behaviour(supervisor).
|
||||
|
||||
-export([init/1]).
|
||||
|
||||
%%
|
||||
|
||||
-spec start() -> pid().
|
||||
|
||||
start() ->
|
||||
{ok, PID} = supervisor:start_link(?MODULE, []),
|
||||
true = unlink(PID),
|
||||
PID.
|
||||
|
||||
-spec stop(pid()) -> ok.
|
||||
|
||||
stop(Pid) ->
|
||||
ok = proc_lib:stop(Pid).
|
||||
|
||||
%%
|
||||
|
||||
-spec init([]) ->
|
||||
{ok, {supervisor:sup_flags(), [supervisor:child_spec()]}}.
|
||||
|
||||
-spec init([]) -> {ok, {supervisor:sup_flags(), [supervisor:child_spec()]}}.
|
||||
init([]) ->
|
||||
{ok, {#{strategy => one_for_all, intensity => 1, period => 1}, []}}.
|
||||
|
@ -9,12 +9,9 @@
|
||||
|
||||
%% API
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) ->
|
||||
ff_codec:encoded_value().
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) -> ff_codec:encoded_value().
|
||||
marshal({list, T}, V) ->
|
||||
[marshal(T, E) || E <- V];
|
||||
|
||||
marshal(final_cash_flow, #{postings := Postings}) ->
|
||||
#cashflow_FinalCashFlow{
|
||||
postings = marshal({list, postings}, Postings)
|
||||
@ -27,10 +24,10 @@ marshal(postings, Posting) ->
|
||||
} = Posting,
|
||||
Details = maps:get(details, Posting, undefined),
|
||||
#cashflow_FinalCashFlowPosting{
|
||||
source = marshal(final_cash_flow_account, Sender),
|
||||
source = marshal(final_cash_flow_account, Sender),
|
||||
destination = marshal(final_cash_flow_account, Receiver),
|
||||
volume = marshal(cash, Cash),
|
||||
details = marshal(string, Details)
|
||||
volume = marshal(cash, Cash),
|
||||
details = marshal(string, Details)
|
||||
};
|
||||
marshal(final_cash_flow_account, #{
|
||||
account := Account,
|
||||
@ -38,25 +35,20 @@ marshal(final_cash_flow_account, #{
|
||||
}) ->
|
||||
#{id := AccountID} = Account,
|
||||
#cashflow_FinalCashFlowAccount{
|
||||
account_type = marshal(account_type, AccountType),
|
||||
account_id = marshal(id, AccountID), % for compatability, deprecate
|
||||
account = ff_codec:marshal(account, Account)
|
||||
account_type = marshal(account_type, AccountType),
|
||||
% for compatability, deprecate
|
||||
account_id = marshal(id, AccountID),
|
||||
account = ff_codec:marshal(account, Account)
|
||||
};
|
||||
|
||||
marshal(account_type, CashflowAccount) ->
|
||||
% Mapped to thrift type WalletCashFlowAccount as is
|
||||
CashflowAccount;
|
||||
|
||||
marshal(T, V) ->
|
||||
ff_codec:marshal(T, V).
|
||||
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) ->
|
||||
ff_codec:decoded_value().
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) -> ff_codec:decoded_value().
|
||||
unmarshal({list, T}, V) ->
|
||||
[unmarshal(T, E) || E <- V];
|
||||
|
||||
unmarshal(final_cash_flow, #cashflow_FinalCashFlow{
|
||||
postings = Postings
|
||||
}) ->
|
||||
@ -70,24 +62,22 @@ unmarshal(postings, #cashflow_FinalCashFlowPosting{
|
||||
details = Details
|
||||
}) ->
|
||||
genlib_map:compact(#{
|
||||
sender => unmarshal(final_cash_flow_account, Source),
|
||||
receiver => unmarshal(final_cash_flow_account, Destination),
|
||||
volume => unmarshal(cash, Cash),
|
||||
details => maybe_unmarshal(string, Details)
|
||||
sender => unmarshal(final_cash_flow_account, Source),
|
||||
receiver => unmarshal(final_cash_flow_account, Destination),
|
||||
volume => unmarshal(cash, Cash),
|
||||
details => maybe_unmarshal(string, Details)
|
||||
});
|
||||
unmarshal(final_cash_flow_account, #cashflow_FinalCashFlowAccount{
|
||||
account_type = AccountType,
|
||||
account = Account
|
||||
account = Account
|
||||
}) ->
|
||||
#{
|
||||
account => ff_codec:unmarshal(account, Account),
|
||||
type => unmarshal(account_type, AccountType)
|
||||
type => unmarshal(account_type, AccountType)
|
||||
};
|
||||
|
||||
unmarshal(account_type, CashflowAccount) ->
|
||||
% Mapped to thrift type WalletCashFlowAccount as is
|
||||
CashflowAccount;
|
||||
|
||||
unmarshal(T, V) ->
|
||||
ff_codec:unmarshal(T, V).
|
||||
|
||||
@ -102,9 +92,11 @@ maybe_unmarshal(Type, Value) ->
|
||||
|
||||
-ifdef(TEST).
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
-spec test() -> _.
|
||||
|
||||
-spec final_cash_flow_symmetry_test() -> _.
|
||||
|
||||
final_cash_flow_symmetry_test() ->
|
||||
PostingFn = fun() ->
|
||||
#{
|
||||
|
@ -31,56 +31,47 @@
|
||||
|
||||
%% Callbacks
|
||||
|
||||
-callback unmarshal(type_name(), encoded_value()) ->
|
||||
decoded_value().
|
||||
-callback marshal(type_name(), decoded_value()) ->
|
||||
encoded_value().
|
||||
-callback unmarshal(type_name(), encoded_value()) -> decoded_value().
|
||||
-callback marshal(type_name(), decoded_value()) -> encoded_value().
|
||||
|
||||
%% API
|
||||
|
||||
-spec unmarshal(codec(), type_name(), encoded_value()) ->
|
||||
decoded_value().
|
||||
-spec unmarshal(codec(), type_name(), encoded_value()) -> decoded_value().
|
||||
unmarshal(Codec, Type, Value) ->
|
||||
Codec:unmarshal(Type, Value).
|
||||
|
||||
-spec marshal(codec(), type_name(), decoded_value()) ->
|
||||
encoded_value().
|
||||
-spec marshal(codec(), type_name(), decoded_value()) -> encoded_value().
|
||||
marshal(Codec, Type, Value) ->
|
||||
Codec:marshal(Type, Value).
|
||||
|
||||
%% Generic codec
|
||||
|
||||
-spec marshal(type_name(), decoded_value()) ->
|
||||
encoded_value().
|
||||
|
||||
-spec marshal(type_name(), decoded_value()) -> encoded_value().
|
||||
marshal({list, T}, V) ->
|
||||
[marshal(T, E) || E <- V];
|
||||
marshal({set, T}, V) ->
|
||||
ordsets:from_list([marshal(T, E) || E <- ordsets:to_list(V)]);
|
||||
|
||||
marshal(id, V) ->
|
||||
marshal(string, V);
|
||||
marshal(event_id, V) ->
|
||||
marshal(integer, V);
|
||||
|
||||
marshal(provider_id, V) ->
|
||||
marshal(integer, V);
|
||||
|
||||
marshal(terminal_id, V) ->
|
||||
marshal(integer, V);
|
||||
|
||||
marshal(blocking, blocked) ->
|
||||
blocked;
|
||||
marshal(blocking, unblocked) ->
|
||||
unblocked;
|
||||
|
||||
marshal(identity_provider, Provider) when is_binary(Provider) ->
|
||||
Provider;
|
||||
|
||||
marshal(transaction_info, TransactionInfo = #{
|
||||
id := TransactionID,
|
||||
extra := Extra
|
||||
}) ->
|
||||
marshal(
|
||||
transaction_info,
|
||||
TransactionInfo = #{
|
||||
id := TransactionID,
|
||||
extra := Extra
|
||||
}
|
||||
) ->
|
||||
Timestamp = maps:get(timestamp, TransactionInfo, undefined),
|
||||
AddInfo = maps:get(additional_info, TransactionInfo, undefined),
|
||||
#'TransactionInfo'{
|
||||
@ -89,7 +80,6 @@ marshal(transaction_info, TransactionInfo = #{
|
||||
extra = Extra,
|
||||
additional_info = marshal(additional_transaction_info, AddInfo)
|
||||
};
|
||||
|
||||
marshal(additional_transaction_info, AddInfo = #{}) ->
|
||||
#'AdditionalTransactionInfo'{
|
||||
rrn = marshal(string, maps:get(rrn, AddInfo, undefined)),
|
||||
@ -108,21 +98,19 @@ marshal(additional_transaction_info, AddInfo = #{}) ->
|
||||
maps:get(three_ds_verification, AddInfo, undefined)
|
||||
)
|
||||
};
|
||||
|
||||
marshal(three_ds_verification, Value) when
|
||||
Value =:= authentication_successful orelse
|
||||
Value =:= attempts_processing_performed orelse
|
||||
Value =:= authentication_failed orelse
|
||||
Value =:= authentication_could_not_be_performed
|
||||
Value =:= attempts_processing_performed orelse
|
||||
Value =:= authentication_failed orelse
|
||||
Value =:= authentication_could_not_be_performed
|
||||
->
|
||||
Value;
|
||||
|
||||
marshal(account_change, {created, Account}) ->
|
||||
{created, marshal(account, Account)};
|
||||
marshal(account, #{
|
||||
id := ID,
|
||||
identity := IdentityID,
|
||||
currency := CurrencyID,
|
||||
id := ID,
|
||||
identity := IdentityID,
|
||||
currency := CurrencyID,
|
||||
accounter_account_id := AAID
|
||||
}) ->
|
||||
#'account_Account'{
|
||||
@ -131,7 +119,6 @@ marshal(account, #{
|
||||
currency = marshal(currency_ref, CurrencyID),
|
||||
accounter_account_id = marshal(event_id, AAID)
|
||||
};
|
||||
|
||||
marshal(resource, {bank_card, #{bank_card := BankCard} = ResourceBankCard}) ->
|
||||
{bank_card, #'ResourceBankCard'{
|
||||
bank_card = marshal(bank_card, BankCard),
|
||||
@ -141,12 +128,10 @@ marshal(resource, {crypto_wallet, #{crypto_wallet := CryptoWallet}}) ->
|
||||
{crypto_wallet, #'ResourceCryptoWallet'{
|
||||
crypto_wallet = marshal(crypto_wallet, CryptoWallet)
|
||||
}};
|
||||
|
||||
marshal(resource_descriptor, {bank_card, BinDataID}) ->
|
||||
{bank_card, #'ResourceDescriptorBankCard'{
|
||||
bin_data_id = marshal(msgpack, BinDataID)
|
||||
}};
|
||||
|
||||
marshal(bank_card, BankCard = #{token := Token}) ->
|
||||
Bin = maps:get(bin, BankCard, undefined),
|
||||
PaymentSystem = maps:get(payment_system, BankCard, undefined),
|
||||
@ -169,28 +154,23 @@ marshal(bank_card, BankCard = #{token := Token}) ->
|
||||
cardholder_name = maybe_marshal(string, CardholderName),
|
||||
bin_data_id = maybe_marshal(msgpack, BinDataID)
|
||||
};
|
||||
|
||||
marshal(bank_card_auth_data, {session, #{session_id := ID}}) ->
|
||||
{session_data, #'SessionAuthData'{
|
||||
id = marshal(string, ID)
|
||||
}};
|
||||
|
||||
marshal(crypto_wallet, #{id := ID, currency := Currency}) ->
|
||||
#'CryptoWallet'{
|
||||
id = marshal(string, ID),
|
||||
id = marshal(string, ID),
|
||||
currency = marshal(crypto_currency, Currency),
|
||||
data = marshal(crypto_data, Currency)
|
||||
data = marshal(crypto_data, Currency)
|
||||
};
|
||||
|
||||
marshal(exp_date, {Month, Year}) ->
|
||||
#'BankCardExpDate'{
|
||||
month = marshal(integer, Month),
|
||||
year = marshal(integer, Year)
|
||||
};
|
||||
|
||||
marshal(crypto_currency, {Currency, _}) ->
|
||||
Currency;
|
||||
|
||||
marshal(crypto_data, {bitcoin, #{}}) ->
|
||||
{bitcoin, #'CryptoDataBitcoin'{}};
|
||||
marshal(crypto_data, {litecoin, #{}}) ->
|
||||
@ -207,19 +187,15 @@ marshal(crypto_data, {ripple, Data}) ->
|
||||
{ripple, #'CryptoDataRipple'{
|
||||
tag = maybe_marshal(string, maps:get(tag, Data, undefined))
|
||||
}};
|
||||
|
||||
marshal(payment_system, V) when is_atom(V) ->
|
||||
V;
|
||||
|
||||
marshal(iso_country_code, V) when is_atom(V) ->
|
||||
V;
|
||||
|
||||
marshal(card_type, V) when is_atom(V) ->
|
||||
V;
|
||||
|
||||
marshal(cash, {Amount, CurrencyRef}) ->
|
||||
#'Cash'{
|
||||
amount = marshal(amount, Amount),
|
||||
amount = marshal(amount, Amount),
|
||||
currency = marshal(currency_ref, CurrencyRef)
|
||||
};
|
||||
marshal(cash_range, {{BoundLower, CashLower}, {BoundUpper, CashUpper}}) ->
|
||||
@ -233,13 +209,11 @@ marshal(currency_ref, CurrencyID) when is_binary(CurrencyID) ->
|
||||
};
|
||||
marshal(amount, V) ->
|
||||
marshal(integer, V);
|
||||
|
||||
marshal(event_range, {After, Limit}) ->
|
||||
#'EventRange'{
|
||||
'after' = maybe_marshal(integer, After),
|
||||
limit = maybe_marshal(integer, Limit)
|
||||
limit = maybe_marshal(integer, Limit)
|
||||
};
|
||||
|
||||
marshal(failure, Failure) ->
|
||||
#'Failure'{
|
||||
code = marshal(string, ff_failure:code(Failure)),
|
||||
@ -255,7 +229,6 @@ marshal(fees, Fees) ->
|
||||
#'Fees'{
|
||||
fees = maps:map(fun(_Constant, Value) -> marshal(cash, Value) end, maps:get(fees, Fees))
|
||||
};
|
||||
|
||||
marshal(timestamp, {DateTime, USec}) ->
|
||||
DateTimeinSeconds = genlib_time:daytime_to_unixtime(DateTime),
|
||||
{TimeinUnit, Unit} =
|
||||
@ -283,35 +256,27 @@ marshal(context, V) when is_map(V) ->
|
||||
ff_entity_context_codec:marshal(V);
|
||||
marshal(msgpack, V) ->
|
||||
ff_msgpack_codec:marshal(msgpack, V);
|
||||
|
||||
% Catch this up in thrift validation
|
||||
marshal(_, Other) ->
|
||||
Other.
|
||||
|
||||
-spec unmarshal(type_name(), encoded_value()) ->
|
||||
decoded_value().
|
||||
|
||||
-spec unmarshal(type_name(), encoded_value()) -> decoded_value().
|
||||
unmarshal({list, T}, V) ->
|
||||
[marshal(T, E) || E <- V];
|
||||
unmarshal({set, T}, V) ->
|
||||
ordsets:from_list([unmarshal(T, E) || E <- ordsets:to_list(V)]);
|
||||
|
||||
unmarshal(id, V) ->
|
||||
unmarshal(string, V);
|
||||
unmarshal(event_id, V) ->
|
||||
unmarshal(integer, V);
|
||||
|
||||
unmarshal(provider_id, V) ->
|
||||
unmarshal(integer, V);
|
||||
|
||||
unmarshal(terminal_id, V) ->
|
||||
unmarshal(integer, V);
|
||||
|
||||
unmarshal(blocking, blocked) ->
|
||||
blocked;
|
||||
unmarshal(blocking, unblocked) ->
|
||||
unblocked;
|
||||
|
||||
unmarshal(transaction_info, #'TransactionInfo'{
|
||||
id = TransactionID,
|
||||
timestamp = Timestamp,
|
||||
@ -324,7 +289,6 @@ unmarshal(transaction_info, #'TransactionInfo'{
|
||||
extra => Extra,
|
||||
additional_info => maybe_unmarshal(additional_transaction_info, AddInfo)
|
||||
});
|
||||
|
||||
unmarshal(additional_transaction_info, #'AdditionalTransactionInfo'{
|
||||
rrn = RRN,
|
||||
approval_code = ApprovalCode,
|
||||
@ -353,15 +317,13 @@ unmarshal(additional_transaction_info, #'AdditionalTransactionInfo'{
|
||||
cavv_algorithm => maybe_unmarshal(string, CAVVAlgorithm),
|
||||
three_ds_verification => maybe_unmarshal(three_ds_verification, ThreeDSVerification)
|
||||
});
|
||||
|
||||
unmarshal(three_ds_verification, Value) when
|
||||
Value =:= authentication_successful orelse
|
||||
Value =:= attempts_processing_performed orelse
|
||||
Value =:= authentication_failed orelse
|
||||
Value =:= authentication_could_not_be_performed
|
||||
Value =:= attempts_processing_performed orelse
|
||||
Value =:= authentication_failed orelse
|
||||
Value =:= authentication_could_not_be_performed
|
||||
->
|
||||
Value;
|
||||
|
||||
unmarshal(complex_action, #ff_repairer_ComplexAction{
|
||||
timer = TimerAction,
|
||||
remove = RemoveAction
|
||||
@ -377,12 +339,10 @@ unmarshal(remove_action, undefined) ->
|
||||
[];
|
||||
unmarshal(remove_action, #ff_repairer_RemoveAction{}) ->
|
||||
[remove];
|
||||
|
||||
unmarshal(set_timer_action, {timeout, Timeout}) ->
|
||||
{timeout, unmarshal(integer, Timeout)};
|
||||
unmarshal(set_timer_action, {deadline, Deadline}) ->
|
||||
{deadline, unmarshal(timestamp, Deadline)};
|
||||
|
||||
unmarshal(account_change, {created, Account}) ->
|
||||
{created, unmarshal(account, Account)};
|
||||
unmarshal(account, #'account_Account'{
|
||||
@ -399,28 +359,28 @@ unmarshal(account, #'account_Account'{
|
||||
};
|
||||
unmarshal(accounter_account_id, V) ->
|
||||
unmarshal(integer, V);
|
||||
|
||||
unmarshal(resource, {bank_card, #'ResourceBankCard'{
|
||||
bank_card = BankCard,
|
||||
auth_data = AuthData
|
||||
}}) ->
|
||||
{bank_card, genlib_map:compact(#{
|
||||
bank_card => unmarshal(bank_card, BankCard),
|
||||
auth_data => maybe_unmarshal(bank_card_auth_data, AuthData)
|
||||
})};
|
||||
unmarshal(
|
||||
resource,
|
||||
{bank_card, #'ResourceBankCard'{
|
||||
bank_card = BankCard,
|
||||
auth_data = AuthData
|
||||
}}
|
||||
) ->
|
||||
{bank_card,
|
||||
genlib_map:compact(#{
|
||||
bank_card => unmarshal(bank_card, BankCard),
|
||||
auth_data => maybe_unmarshal(bank_card_auth_data, AuthData)
|
||||
})};
|
||||
unmarshal(resource, {crypto_wallet, #'ResourceCryptoWallet'{crypto_wallet = CryptoWallet}}) ->
|
||||
{crypto_wallet, #{
|
||||
crypto_wallet => unmarshal(crypto_wallet, CryptoWallet)
|
||||
}};
|
||||
|
||||
unmarshal(resource_descriptor, {bank_card, BankCard}) ->
|
||||
{bank_card, unmarshal(msgpack, BankCard#'ResourceDescriptorBankCard'.bin_data_id)};
|
||||
|
||||
unmarshal(bank_card_auth_data, {session_data, #'SessionAuthData'{id = ID}}) ->
|
||||
{session, #{
|
||||
session_id => unmarshal(string, ID)
|
||||
}};
|
||||
|
||||
unmarshal(bank_card, #'BankCard'{
|
||||
token = Token,
|
||||
bin = Bin,
|
||||
@ -445,22 +405,17 @@ unmarshal(bank_card, #'BankCard'{
|
||||
cardholder_name => maybe_unmarshal(string, CardholderName),
|
||||
bin_data_id => maybe_unmarshal(msgpack, BinDataID)
|
||||
});
|
||||
|
||||
unmarshal(exp_date, #'BankCardExpDate'{
|
||||
month = Month,
|
||||
year = Year
|
||||
}) ->
|
||||
{unmarshal(integer, Month), unmarshal(integer, Year)};
|
||||
|
||||
unmarshal(payment_system, V) when is_atom(V) ->
|
||||
V;
|
||||
|
||||
unmarshal(iso_country_code, V) when is_atom(V) ->
|
||||
V;
|
||||
|
||||
unmarshal(card_type, V) when is_atom(V) ->
|
||||
V;
|
||||
|
||||
unmarshal(crypto_wallet, #'CryptoWallet'{
|
||||
id = CryptoWalletID,
|
||||
currency = CryptoWalletCurrency,
|
||||
@ -470,20 +425,17 @@ unmarshal(crypto_wallet, #'CryptoWallet'{
|
||||
id => unmarshal(string, CryptoWalletID),
|
||||
currency => {CryptoWalletCurrency, unmarshal(crypto_data, Data)}
|
||||
});
|
||||
|
||||
unmarshal(crypto_data, {ripple, #'CryptoDataRipple'{tag = Tag}}) ->
|
||||
genlib_map:compact(#{
|
||||
tag => maybe_unmarshal(string, Tag)
|
||||
});
|
||||
unmarshal(crypto_data, _) ->
|
||||
#{};
|
||||
|
||||
unmarshal(cash, #'Cash'{
|
||||
amount = Amount,
|
||||
amount = Amount,
|
||||
currency = CurrencyRef
|
||||
}) ->
|
||||
{unmarshal(amount, Amount), unmarshal(currency_ref, CurrencyRef)};
|
||||
|
||||
unmarshal(cash_range, #'CashRange'{
|
||||
lower = {BoundLower, CashLower},
|
||||
upper = {BoundUpper, CashUpper}
|
||||
@ -492,17 +444,14 @@ unmarshal(cash_range, #'CashRange'{
|
||||
{BoundLower, unmarshal(cash, CashLower)},
|
||||
{BoundUpper, unmarshal(cash, CashUpper)}
|
||||
};
|
||||
|
||||
unmarshal(currency_ref, #'CurrencyRef'{
|
||||
symbolic_code = SymbolicCode
|
||||
}) ->
|
||||
unmarshal(string, SymbolicCode);
|
||||
unmarshal(amount, V) ->
|
||||
unmarshal(integer, V);
|
||||
|
||||
unmarshal(event_range, #'EventRange'{'after' = After, limit = Limit}) ->
|
||||
{maybe_unmarshal(integer, After), maybe_unmarshal(integer, Limit)};
|
||||
|
||||
unmarshal(failure, Failure) ->
|
||||
genlib_map:compact(#{
|
||||
code => unmarshal(string, Failure#'Failure'.code),
|
||||
@ -514,20 +463,17 @@ unmarshal(sub_failure, Failure) ->
|
||||
code => unmarshal(string, Failure#'SubFailure'.code),
|
||||
sub => maybe_unmarshal(sub_failure, Failure#'SubFailure'.sub)
|
||||
});
|
||||
|
||||
unmarshal(context, V) -> ff_entity_context_codec:unmarshal(V);
|
||||
|
||||
unmarshal(context, V) ->
|
||||
ff_entity_context_codec:unmarshal(V);
|
||||
unmarshal(range, #evsink_EventRange{
|
||||
'after' = Cursor,
|
||||
limit = Limit
|
||||
limit = Limit
|
||||
}) ->
|
||||
{Cursor, Limit, forward};
|
||||
|
||||
unmarshal(fees, Fees) ->
|
||||
#{
|
||||
fees => maps:map(fun(_Constant, Value) -> unmarshal(cash, Value) end, Fees#'Fees'.fees)
|
||||
};
|
||||
|
||||
unmarshal(timestamp, Timestamp) when is_binary(Timestamp) ->
|
||||
parse_timestamp(Timestamp);
|
||||
unmarshal(timestamp_ms, V) ->
|
||||
@ -540,16 +486,13 @@ unmarshal(string, V) when is_binary(V) ->
|
||||
V;
|
||||
unmarshal(integer, V) when is_integer(V) ->
|
||||
V;
|
||||
|
||||
unmarshal(msgpack, V) ->
|
||||
ff_msgpack_codec:unmarshal(msgpack, V);
|
||||
|
||||
unmarshal(range, #'EventRange'{
|
||||
'after' = Cursor,
|
||||
limit = Limit
|
||||
limit = Limit
|
||||
}) ->
|
||||
{Cursor, Limit, forward};
|
||||
|
||||
unmarshal(bool, V) when is_boolean(V) ->
|
||||
V.
|
||||
|
||||
@ -563,8 +506,7 @@ maybe_marshal(_Type, undefined) ->
|
||||
maybe_marshal(Type, Value) ->
|
||||
marshal(Type, Value).
|
||||
|
||||
-spec parse_timestamp(binary()) ->
|
||||
machinery:timestamp().
|
||||
-spec parse_timestamp(binary()) -> machinery:timestamp().
|
||||
parse_timestamp(Bin) ->
|
||||
try
|
||||
MicroSeconds = genlib_rfc3339:parse(Bin, microsecond),
|
||||
@ -577,7 +519,7 @@ parse_timestamp(Bin) ->
|
||||
{DateTime, USec}
|
||||
end
|
||||
catch
|
||||
error:Error:St ->
|
||||
error:Error:St ->
|
||||
erlang:raise(error, {bad_timestamp, Bin, Error}, St)
|
||||
end.
|
||||
|
||||
@ -585,9 +527,11 @@ parse_timestamp(Bin) ->
|
||||
|
||||
-ifdef(TEST).
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
-spec test() -> _.
|
||||
|
||||
-spec bank_card_codec_test() -> _.
|
||||
|
||||
bank_card_codec_test() ->
|
||||
BankCard = #{
|
||||
token => <<"token">>,
|
||||
|
@ -9,16 +9,13 @@
|
||||
|
||||
%% API
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) ->
|
||||
ff_codec:encoded_value().
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) -> ff_codec:encoded_value().
|
||||
marshal(change, {created, Adjustment}) ->
|
||||
{created, #dep_adj_CreatedChange{adjustment = marshal(adjustment, Adjustment)}};
|
||||
marshal(change, {status_changed, Status}) ->
|
||||
{status_changed, #dep_adj_StatusChange{status = marshal(status, Status)}};
|
||||
marshal(change, {p_transfer, TransferChange}) ->
|
||||
{transfer, #dep_adj_TransferChange{payload = ff_p_transfer_codec:marshal(change, TransferChange)}};
|
||||
|
||||
marshal(adjustment, Adjustment) ->
|
||||
#dep_adj_Adjustment{
|
||||
id = marshal(id, ff_adjustment:id(Adjustment)),
|
||||
@ -47,12 +44,10 @@ marshal(adjustment_state, Adjustment) ->
|
||||
operation_timestamp = marshal(timestamp_ms, ff_adjustment:operation_timestamp(Adjustment)),
|
||||
external_id = maybe_marshal(id, ff_adjustment:external_id(Adjustment))
|
||||
};
|
||||
|
||||
marshal(status, pending) ->
|
||||
{pending, #dep_adj_Pending{}};
|
||||
marshal(status, succeeded) ->
|
||||
{succeeded, #dep_adj_Succeeded{}};
|
||||
|
||||
marshal(changes_plan, Plan) ->
|
||||
#dep_adj_ChangesPlan{
|
||||
new_cash_flow = maybe_marshal(cash_flow_change_plan, maps:get(new_cash_flow, Plan, undefined)),
|
||||
@ -69,26 +64,20 @@ marshal(status_change_plan, Plan) ->
|
||||
#dep_adj_StatusChangePlan{
|
||||
new_status = ff_deposit_status_codec:marshal(status, maps:get(new_status, Plan))
|
||||
};
|
||||
|
||||
marshal(change_request, {change_status, Status}) ->
|
||||
{change_status, #dep_adj_ChangeStatusRequest{
|
||||
new_status = ff_deposit_status_codec:marshal(status, Status)
|
||||
}};
|
||||
|
||||
marshal(T, V) ->
|
||||
ff_codec:marshal(T, V).
|
||||
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) ->
|
||||
ff_codec:decoded_value().
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) -> ff_codec:decoded_value().
|
||||
unmarshal(change, {created, #dep_adj_CreatedChange{adjustment = Adjustment}}) ->
|
||||
{created, unmarshal(adjustment, Adjustment)};
|
||||
unmarshal(change, {status_changed, #dep_adj_StatusChange{status = Status}}) ->
|
||||
{status_changed, unmarshal(status, Status)};
|
||||
unmarshal(change, {transfer, #dep_adj_TransferChange{payload = TransferChange}}) ->
|
||||
{p_transfer, ff_p_transfer_codec:unmarshal(change, TransferChange)};
|
||||
|
||||
unmarshal(adjustment, Adjustment) ->
|
||||
#{
|
||||
id => unmarshal(id, Adjustment#dep_adj_Adjustment.id),
|
||||
@ -100,19 +89,16 @@ unmarshal(adjustment, Adjustment) ->
|
||||
operation_timestamp => unmarshal(timestamp_ms, Adjustment#dep_adj_Adjustment.operation_timestamp),
|
||||
external_id => maybe_unmarshal(id, Adjustment#dep_adj_Adjustment.external_id)
|
||||
};
|
||||
|
||||
unmarshal(adjustment_params, Params) ->
|
||||
genlib_map:compact(#{
|
||||
id => unmarshal(id, Params#dep_adj_AdjustmentParams.id),
|
||||
change => unmarshal(change_request, Params#dep_adj_AdjustmentParams.change),
|
||||
external_id => maybe_unmarshal(id, Params#dep_adj_AdjustmentParams.external_id)
|
||||
});
|
||||
|
||||
unmarshal(status, {pending, #dep_adj_Pending{}}) ->
|
||||
pending;
|
||||
unmarshal(status, {succeeded, #dep_adj_Succeeded{}}) ->
|
||||
succeeded;
|
||||
|
||||
unmarshal(changes_plan, Plan) ->
|
||||
genlib_map:compact(#{
|
||||
new_cash_flow => maybe_unmarshal(cash_flow_change_plan, Plan#dep_adj_ChangesPlan.new_cash_flow),
|
||||
@ -130,11 +116,9 @@ unmarshal(status_change_plan, Plan) ->
|
||||
#{
|
||||
new_status => ff_deposit_status_codec:unmarshal(status, Status)
|
||||
};
|
||||
|
||||
unmarshal(change_request, {change_status, Request}) ->
|
||||
Status = Request#dep_adj_ChangeStatusRequest.new_status,
|
||||
{change_status, ff_deposit_status_codec:unmarshal(status, Status)};
|
||||
|
||||
unmarshal(T, V) ->
|
||||
ff_codec:unmarshal(T, V).
|
||||
|
||||
@ -154,9 +138,11 @@ maybe_marshal(Type, Value) ->
|
||||
|
||||
-ifdef(TEST).
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
-spec test() -> _.
|
||||
|
||||
-spec adjustment_codec_test() -> _.
|
||||
|
||||
adjustment_codec_test() ->
|
||||
FinalCashFlow = #{
|
||||
postings => [
|
||||
|
@ -11,11 +11,11 @@
|
||||
%% Data transform
|
||||
|
||||
-define(to_session_event(SessionID, Payload),
|
||||
{session, #{id => SessionID, payload => Payload}}).
|
||||
{session, #{id => SessionID, payload => Payload}}
|
||||
).
|
||||
|
||||
-spec marshal_deposit_state(ff_deposit:deposit_state(), ff_entity_context:context()) ->
|
||||
ff_proto_deposit_thrift:'DepositState'().
|
||||
|
||||
marshal_deposit_state(DepositState, Context) ->
|
||||
CashFlow = ff_deposit:effective_final_cash_flow(DepositState),
|
||||
Reverts = ff_deposit:reverts(DepositState),
|
||||
@ -39,25 +39,20 @@ marshal_deposit_state(DepositState, Context) ->
|
||||
|
||||
%% API
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) ->
|
||||
ff_codec:encoded_value().
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) -> ff_codec:encoded_value().
|
||||
marshal({list, T}, V) ->
|
||||
[marshal(T, E) || E <- V];
|
||||
|
||||
marshal(event, {EventID, {ev, Timestamp, Change}}) ->
|
||||
#deposit_Event{
|
||||
event_id = ff_codec:marshal(event_id, EventID),
|
||||
occured_at = ff_codec:marshal(timestamp, Timestamp),
|
||||
change = marshal(change, Change)
|
||||
};
|
||||
|
||||
marshal(timestamped_change, {ev, Timestamp, Change}) ->
|
||||
#deposit_TimestampedChange{
|
||||
change = marshal(change, Change),
|
||||
occured_at = ff_codec:marshal(timestamp, Timestamp)
|
||||
};
|
||||
|
||||
marshal(change, {created, Deposit}) ->
|
||||
{created, #deposit_CreatedChange{deposit = marshal(deposit, Deposit)}};
|
||||
marshal(change, {status_changed, Status}) ->
|
||||
@ -76,7 +71,6 @@ marshal(change, {adjustment, #{id := ID, payload := Payload}}) ->
|
||||
id = marshal(id, ID),
|
||||
payload = ff_deposit_adjustment_codec:marshal(change, Payload)
|
||||
}};
|
||||
|
||||
marshal(deposit, Deposit) ->
|
||||
#deposit_Deposit{
|
||||
id = marshal(id, ff_deposit:id(Deposit)),
|
||||
@ -99,34 +93,26 @@ marshal(deposit_params, DepositParams) ->
|
||||
external_id = maybe_marshal(id, maps:get(external_id, DepositParams, undefined)),
|
||||
metadata = maybe_marshal(ctx, maps:get(metadata, DepositParams, undefined))
|
||||
};
|
||||
|
||||
marshal(ctx, Ctx) ->
|
||||
maybe_marshal(context, Ctx);
|
||||
|
||||
marshal(status, Status) ->
|
||||
ff_deposit_status_codec:marshal(status, Status);
|
||||
|
||||
marshal(T, V) ->
|
||||
ff_codec:marshal(T, V).
|
||||
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) ->
|
||||
ff_codec:decoded_value().
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) -> ff_codec:decoded_value().
|
||||
unmarshal({list, T}, V) ->
|
||||
[unmarshal(T, E) || E <- V];
|
||||
|
||||
unmarshal(repair_scenario, {add_events, #deposit_AddEventsRepair{events = Events, action = Action}}) ->
|
||||
{add_events, genlib_map:compact(#{
|
||||
events => unmarshal({list, change}, Events),
|
||||
action => maybe_unmarshal(complex_action, Action)
|
||||
})};
|
||||
|
||||
{add_events,
|
||||
genlib_map:compact(#{
|
||||
events => unmarshal({list, change}, Events),
|
||||
action => maybe_unmarshal(complex_action, Action)
|
||||
})};
|
||||
unmarshal(timestamped_change, TimestampedChange) ->
|
||||
Timestamp = ff_codec:unmarshal(timestamp, TimestampedChange#deposit_TimestampedChange.occured_at),
|
||||
Change = unmarshal(change, TimestampedChange#deposit_TimestampedChange.change),
|
||||
{ev, Timestamp, Change};
|
||||
|
||||
unmarshal(change, {created, #deposit_CreatedChange{deposit = Deposit}}) ->
|
||||
{created, unmarshal(deposit, Deposit)};
|
||||
unmarshal(change, {status_changed, #deposit_StatusChange{status = DepositStatus}}) ->
|
||||
@ -145,10 +131,8 @@ unmarshal(change, {adjustment, Change}) ->
|
||||
id => unmarshal(id, Change#deposit_AdjustmentChange.id),
|
||||
payload => ff_deposit_adjustment_codec:unmarshal(change, Change#deposit_AdjustmentChange.payload)
|
||||
}};
|
||||
|
||||
unmarshal(status, Status) ->
|
||||
ff_deposit_status_codec:unmarshal(status, Status);
|
||||
|
||||
unmarshal(deposit, Deposit) ->
|
||||
genlib_map:compact(#{
|
||||
version => 3,
|
||||
@ -166,7 +150,6 @@ unmarshal(deposit, Deposit) ->
|
||||
created_at => maybe_unmarshal(timestamp_ms, Deposit#deposit_Deposit.created_at),
|
||||
metadata => maybe_unmarshal(ctx, Deposit#deposit_Deposit.metadata)
|
||||
});
|
||||
|
||||
unmarshal(deposit_params, DepositParams) ->
|
||||
genlib_map:compact(#{
|
||||
id => unmarshal(id, DepositParams#deposit_DepositParams.id),
|
||||
@ -176,10 +159,8 @@ unmarshal(deposit_params, DepositParams) ->
|
||||
metadata => maybe_unmarshal(ctx, DepositParams#deposit_DepositParams.metadata),
|
||||
external_id => maybe_unmarshal(id, DepositParams#deposit_DepositParams.external_id)
|
||||
});
|
||||
|
||||
unmarshal(ctx, Ctx) ->
|
||||
maybe_unmarshal(context, Ctx);
|
||||
|
||||
unmarshal(T, V) ->
|
||||
ff_codec:unmarshal(T, V).
|
||||
|
||||
@ -199,14 +180,16 @@ maybe_marshal(Type, Value) ->
|
||||
|
||||
-ifdef(TEST).
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
-spec test() -> _.
|
||||
|
||||
-spec deposit_symmetry_test() -> _.
|
||||
|
||||
deposit_symmetry_test() ->
|
||||
Encoded = #deposit_Deposit{
|
||||
body = #'Cash'{
|
||||
amount = 10101,
|
||||
currency = #'CurrencyRef'{ symbolic_code = <<"Banana Republic">> }
|
||||
currency = #'CurrencyRef'{symbolic_code = <<"Banana Republic">>}
|
||||
},
|
||||
source_id = genlib:unique(),
|
||||
wallet_id = genlib:unique(),
|
||||
@ -225,7 +208,7 @@ deposit_params_symmetry_test() ->
|
||||
Encoded = #deposit_DepositParams{
|
||||
body = #'Cash'{
|
||||
amount = 10101,
|
||||
currency = #'CurrencyRef'{ symbolic_code = <<"Banana Republic">> }
|
||||
currency = #'CurrencyRef'{symbolic_code = <<"Banana Republic">>}
|
||||
},
|
||||
source_id = genlib:unique(),
|
||||
wallet_id = genlib:unique(),
|
||||
@ -263,17 +246,18 @@ deposit_timestamped_change_codec_test() ->
|
||||
deposit_change_revert_codec_test() ->
|
||||
Revert = #{
|
||||
id => genlib:unique(),
|
||||
payload => {created, #{
|
||||
id => genlib:unique(),
|
||||
status => pending,
|
||||
body => {123, <<"RUB">>},
|
||||
created_at => ff_time:now(),
|
||||
domain_revision => 123,
|
||||
party_revision => 321,
|
||||
external_id => genlib:unique(),
|
||||
wallet_id => genlib:unique(),
|
||||
source_id => genlib:unique()
|
||||
}}
|
||||
payload =>
|
||||
{created, #{
|
||||
id => genlib:unique(),
|
||||
status => pending,
|
||||
body => {123, <<"RUB">>},
|
||||
created_at => ff_time:now(),
|
||||
domain_revision => 123,
|
||||
party_revision => 321,
|
||||
external_id => genlib:unique(),
|
||||
wallet_id => genlib:unique(),
|
||||
source_id => genlib:unique()
|
||||
}}
|
||||
},
|
||||
Change = {revert, Revert},
|
||||
TimestampedChange = {ev, machinery_time:now(), Change},
|
||||
@ -286,24 +270,25 @@ deposit_change_revert_codec_test() ->
|
||||
deposit_change_adjustment_codec_test() ->
|
||||
Adjustment = #{
|
||||
id => genlib:unique(),
|
||||
payload => {created, #{
|
||||
id => genlib:unique(),
|
||||
status => pending,
|
||||
changes_plan => #{
|
||||
new_cash_flow => #{
|
||||
old_cash_flow_inverted => #{postings => []},
|
||||
new_cash_flow => #{postings => []}
|
||||
payload =>
|
||||
{created, #{
|
||||
id => genlib:unique(),
|
||||
status => pending,
|
||||
changes_plan => #{
|
||||
new_cash_flow => #{
|
||||
old_cash_flow_inverted => #{postings => []},
|
||||
new_cash_flow => #{postings => []}
|
||||
},
|
||||
new_status => #{
|
||||
new_status => succeeded
|
||||
}
|
||||
},
|
||||
new_status => #{
|
||||
new_status => succeeded
|
||||
}
|
||||
},
|
||||
created_at => ff_time:now(),
|
||||
domain_revision => 123,
|
||||
party_revision => 321,
|
||||
operation_timestamp => ff_time:now(),
|
||||
external_id => genlib:unique()
|
||||
}}
|
||||
created_at => ff_time:now(),
|
||||
domain_revision => 123,
|
||||
party_revision => 321,
|
||||
operation_timestamp => ff_time:now(),
|
||||
external_id => genlib:unique()
|
||||
}}
|
||||
},
|
||||
Change = {adjustment, Adjustment},
|
||||
TimestampedChange = {ev, machinery_time:now(), Change},
|
||||
|
@ -16,32 +16,28 @@
|
||||
%% Internals
|
||||
%%
|
||||
|
||||
-spec publish_events(list(event())) ->
|
||||
list(sinkevent()).
|
||||
|
||||
-spec publish_events(list(event())) -> list(sinkevent()).
|
||||
publish_events(Events) ->
|
||||
[publish_event(Event) || Event <- Events].
|
||||
|
||||
-spec publish_event(event()) ->
|
||||
sinkevent().
|
||||
|
||||
-spec publish_event(event()) -> sinkevent().
|
||||
publish_event(#{
|
||||
id := ID,
|
||||
source_id := SourceID,
|
||||
event := {
|
||||
id := ID,
|
||||
source_id := SourceID,
|
||||
event := {
|
||||
EventID,
|
||||
Dt,
|
||||
{ev, EventDt, Payload}
|
||||
}
|
||||
}) ->
|
||||
#deposit_SinkEvent{
|
||||
id = marshal(event_id, ID),
|
||||
created_at = marshal(timestamp, Dt),
|
||||
source = marshal(id, SourceID),
|
||||
payload = #deposit_EventSinkPayload{
|
||||
sequence = marshal(event_id, EventID),
|
||||
id = marshal(event_id, ID),
|
||||
created_at = marshal(timestamp, Dt),
|
||||
source = marshal(id, SourceID),
|
||||
payload = #deposit_EventSinkPayload{
|
||||
sequence = marshal(event_id, EventID),
|
||||
occured_at = marshal(timestamp, EventDt),
|
||||
changes = [marshal(change, Payload)]
|
||||
changes = [marshal(change, Payload)]
|
||||
}
|
||||
}.
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
-module(ff_deposit_handler).
|
||||
|
||||
-behaviour(ff_woody_wrapper).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_deposit_thrift.hrl").
|
||||
@ -10,10 +11,11 @@
|
||||
%% ff_woody_wrapper callbacks
|
||||
%%
|
||||
|
||||
-spec handle_function(woody:func(), woody:args(), woody:options()) ->
|
||||
{ok, woody:result()} | no_return().
|
||||
-spec handle_function(woody:func(), woody:args(), woody:options()) -> {ok, woody:result()} | no_return().
|
||||
handle_function(Func, Args, Opts) ->
|
||||
scoper:scope(deposit, #{},
|
||||
scoper:scope(
|
||||
deposit,
|
||||
#{},
|
||||
fun() ->
|
||||
handle_function_(Func, Args, Opts)
|
||||
end
|
||||
@ -87,11 +89,13 @@ handle_function_('GetEvents', [ID, EventRange], _Opts) ->
|
||||
handle_function_('CreateAdjustment', [ID, MarshaledParams], _Opts) ->
|
||||
Params = ff_deposit_adjustment_codec:unmarshal(adjustment_params, MarshaledParams),
|
||||
AdjustmentID = maps:get(id, Params),
|
||||
ok = scoper:add_meta(genlib_map:compact(#{
|
||||
id => ID,
|
||||
adjustment_id => AdjustmentID,
|
||||
external_id => maps:get(external_id, Params, undefined)
|
||||
})),
|
||||
ok = scoper:add_meta(
|
||||
genlib_map:compact(#{
|
||||
id => ID,
|
||||
adjustment_id => AdjustmentID,
|
||||
external_id => maps:get(external_id, Params, undefined)
|
||||
})
|
||||
),
|
||||
case ff_deposit_machine:start_adjustment(ID, Params) of
|
||||
ok ->
|
||||
{ok, Machine} = ff_deposit_machine:get(ID),
|
||||
@ -120,11 +124,13 @@ handle_function_('CreateAdjustment', [ID, MarshaledParams], _Opts) ->
|
||||
handle_function_('CreateRevert', [ID, MarshaledParams], _Opts) ->
|
||||
Params = ff_deposit_revert_codec:unmarshal(revert_params, MarshaledParams),
|
||||
RevertID = maps:get(id, Params),
|
||||
ok = scoper:add_meta(genlib_map:compact(#{
|
||||
id => ID,
|
||||
revert_id => RevertID,
|
||||
external_id => maps:get(external_id, Params, undefined)
|
||||
})),
|
||||
ok = scoper:add_meta(
|
||||
genlib_map:compact(#{
|
||||
id => ID,
|
||||
revert_id => RevertID,
|
||||
external_id => maps:get(external_id, Params, undefined)
|
||||
})
|
||||
),
|
||||
case ff_deposit_machine:start_revert(ID, Params) of
|
||||
ok ->
|
||||
{ok, Machine} = ff_deposit_machine:get(ID),
|
||||
@ -155,12 +161,14 @@ handle_function_('CreateRevert', [ID, MarshaledParams], _Opts) ->
|
||||
handle_function_('CreateRevertAdjustment', [ID, RevertID, MarshaledParams], _Opts) ->
|
||||
Params = ff_deposit_revert_adjustment_codec:unmarshal(adjustment_params, MarshaledParams),
|
||||
AdjustmentID = maps:get(id, Params),
|
||||
ok = scoper:add_meta(genlib_map:compact(#{
|
||||
id => ID,
|
||||
revert_id => RevertID,
|
||||
adjustment_id => AdjustmentID,
|
||||
external_id => maps:get(external_id, Params, undefined)
|
||||
})),
|
||||
ok = scoper:add_meta(
|
||||
genlib_map:compact(#{
|
||||
id => ID,
|
||||
revert_id => RevertID,
|
||||
adjustment_id => AdjustmentID,
|
||||
external_id => maps:get(external_id, Params, undefined)
|
||||
})
|
||||
),
|
||||
case ff_deposit_machine:start_revert_adjustment(ID, RevertID, Params) of
|
||||
ok ->
|
||||
{ok, Machine} = ff_deposit_machine:get(ID),
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -12,8 +12,7 @@
|
||||
%% ff_woody_wrapper callbacks
|
||||
%%
|
||||
|
||||
-spec handle_function(woody:func(), woody:args(), options()) ->
|
||||
{ok, woody:result()} | no_return().
|
||||
-spec handle_function(woody:func(), woody:args(), options()) -> {ok, woody:result()} | no_return().
|
||||
handle_function('Repair', [ID, Scenario], _Opts) ->
|
||||
DecodedScenario = ff_deposit_codec:unmarshal(repair_scenario, Scenario),
|
||||
case ff_deposit_machine:repair(ID, DecodedScenario) of
|
||||
|
@ -9,16 +9,13 @@
|
||||
|
||||
%% API
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) ->
|
||||
ff_codec:encoded_value().
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) -> ff_codec:encoded_value().
|
||||
marshal(change, {created, Adjustment}) ->
|
||||
{created, #dep_rev_adj_CreatedChange{adjustment = marshal(adjustment, Adjustment)}};
|
||||
marshal(change, {status_changed, Status}) ->
|
||||
{status_changed, #dep_rev_adj_StatusChange{status = marshal(status, Status)}};
|
||||
marshal(change, {p_transfer, TransferChange}) ->
|
||||
{transfer, #dep_rev_adj_TransferChange{payload = ff_p_transfer_codec:marshal(change, TransferChange)}};
|
||||
|
||||
marshal(adjustment, Adjustment) ->
|
||||
#dep_rev_adj_Adjustment{
|
||||
id = marshal(id, ff_adjustment:id(Adjustment)),
|
||||
@ -47,12 +44,10 @@ marshal(adjustment_state, Adjustment) ->
|
||||
operation_timestamp = marshal(timestamp_ms, ff_adjustment:operation_timestamp(Adjustment)),
|
||||
external_id = maybe_marshal(id, ff_adjustment:external_id(Adjustment))
|
||||
};
|
||||
|
||||
marshal(status, pending) ->
|
||||
{pending, #dep_rev_adj_Pending{}};
|
||||
marshal(status, succeeded) ->
|
||||
{succeeded, #dep_rev_adj_Succeeded{}};
|
||||
|
||||
marshal(changes_plan, Plan) ->
|
||||
#dep_rev_adj_ChangesPlan{
|
||||
new_cash_flow = maybe_marshal(cash_flow_change_plan, maps:get(new_cash_flow, Plan, undefined)),
|
||||
@ -69,26 +64,20 @@ marshal(status_change_plan, Plan) ->
|
||||
#dep_rev_adj_StatusChangePlan{
|
||||
new_status = ff_deposit_revert_status_codec:marshal(status, maps:get(new_status, Plan))
|
||||
};
|
||||
|
||||
marshal(change_request, {change_status, Status}) ->
|
||||
{change_status, #dep_rev_adj_ChangeStatusRequest{
|
||||
new_status = ff_deposit_revert_status_codec:marshal(status, Status)
|
||||
}};
|
||||
|
||||
marshal(T, V) ->
|
||||
ff_codec:marshal(T, V).
|
||||
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) ->
|
||||
ff_codec:decoded_value().
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) -> ff_codec:decoded_value().
|
||||
unmarshal(change, {created, #dep_rev_adj_CreatedChange{adjustment = Adjustment}}) ->
|
||||
{created, unmarshal(adjustment, Adjustment)};
|
||||
unmarshal(change, {status_changed, #dep_rev_adj_StatusChange{status = Status}}) ->
|
||||
{status_changed, unmarshal(status, Status)};
|
||||
unmarshal(change, {transfer, #dep_rev_adj_TransferChange{payload = TransferChange}}) ->
|
||||
{p_transfer, ff_p_transfer_codec:unmarshal(change, TransferChange)};
|
||||
|
||||
unmarshal(adjustment, Adjustment) ->
|
||||
#{
|
||||
id => unmarshal(id, Adjustment#dep_rev_adj_Adjustment.id),
|
||||
@ -100,19 +89,16 @@ unmarshal(adjustment, Adjustment) ->
|
||||
operation_timestamp => unmarshal(timestamp_ms, Adjustment#dep_rev_adj_Adjustment.operation_timestamp),
|
||||
external_id => maybe_unmarshal(id, Adjustment#dep_rev_adj_Adjustment.external_id)
|
||||
};
|
||||
|
||||
unmarshal(adjustment_params, Params) ->
|
||||
genlib_map:compact(#{
|
||||
id => unmarshal(id, Params#dep_rev_adj_AdjustmentParams.id),
|
||||
change => unmarshal(change_request, Params#dep_rev_adj_AdjustmentParams.change),
|
||||
external_id => maybe_unmarshal(id, Params#dep_rev_adj_AdjustmentParams.external_id)
|
||||
});
|
||||
|
||||
unmarshal(status, {pending, #dep_rev_adj_Pending{}}) ->
|
||||
pending;
|
||||
unmarshal(status, {succeeded, #dep_rev_adj_Succeeded{}}) ->
|
||||
succeeded;
|
||||
|
||||
unmarshal(changes_plan, Plan) ->
|
||||
genlib_map:compact(#{
|
||||
new_cash_flow => maybe_unmarshal(cash_flow_change_plan, Plan#dep_rev_adj_ChangesPlan.new_cash_flow),
|
||||
@ -130,11 +116,9 @@ unmarshal(status_change_plan, Plan) ->
|
||||
#{
|
||||
new_status => ff_deposit_revert_status_codec:unmarshal(status, Status)
|
||||
};
|
||||
|
||||
unmarshal(change_request, {change_status, Request}) ->
|
||||
Status = Request#dep_rev_adj_ChangeStatusRequest.new_status,
|
||||
{change_status, ff_deposit_revert_status_codec:unmarshal(status, Status)};
|
||||
|
||||
unmarshal(T, V) ->
|
||||
ff_codec:unmarshal(T, V).
|
||||
|
||||
@ -154,9 +138,11 @@ maybe_marshal(Type, Value) ->
|
||||
|
||||
-ifdef(TEST).
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
-spec test() -> _.
|
||||
|
||||
-spec adjustment_codec_test() -> _.
|
||||
|
||||
adjustment_codec_test() ->
|
||||
FinalCashFlow = #{
|
||||
postings => [
|
||||
|
@ -10,13 +10,12 @@
|
||||
%% Data transform
|
||||
|
||||
-define(to_session_event(SessionID, Payload),
|
||||
{session, #{id => SessionID, payload => Payload}}).
|
||||
{session, #{id => SessionID, payload => Payload}}
|
||||
).
|
||||
|
||||
%% API
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) ->
|
||||
ff_codec:encoded_value().
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) -> ff_codec:encoded_value().
|
||||
marshal(change, {created, Revert}) ->
|
||||
{created, #deposit_revert_CreatedChange{revert = marshal(revert, Revert)}};
|
||||
marshal(change, {status_changed, Status}) ->
|
||||
@ -31,7 +30,6 @@ marshal(change, {adjustment, #{id := ID, payload := Payload}}) ->
|
||||
id = marshal(id, ID),
|
||||
payload = ff_deposit_revert_adjustment_codec:marshal(change, Payload)
|
||||
}};
|
||||
|
||||
marshal(revert, Revert) ->
|
||||
#deposit_revert_Revert{
|
||||
id = marshal(id, ff_deposit_revert:id(Revert)),
|
||||
@ -69,17 +67,12 @@ marshal(revert_state, Revert) ->
|
||||
effective_final_cash_flow = ff_cash_flow_codec:marshal(final_cash_flow, CashFlow),
|
||||
adjustments = [ff_deposit_revert_adjustment_codec:marshal(adjustment_state, A) || A <- Adjustments]
|
||||
};
|
||||
|
||||
marshal(status, Status) ->
|
||||
ff_deposit_revert_status_codec:marshal(status, Status);
|
||||
|
||||
marshal(T, V) ->
|
||||
ff_codec:marshal(T, V).
|
||||
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) ->
|
||||
ff_codec:decoded_value().
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) -> ff_codec:decoded_value().
|
||||
unmarshal(change, {created, #deposit_revert_CreatedChange{revert = Revert}}) ->
|
||||
{created, unmarshal(revert, Revert)};
|
||||
unmarshal(change, {status_changed, #deposit_revert_StatusChange{status = Status}}) ->
|
||||
@ -97,10 +90,8 @@ unmarshal(change, {adjustment, Change}) ->
|
||||
id => unmarshal(id, ID),
|
||||
payload => ff_deposit_revert_adjustment_codec:unmarshal(change, Payload)
|
||||
}};
|
||||
|
||||
unmarshal(status, Status) ->
|
||||
ff_deposit_revert_status_codec:unmarshal(status, Status);
|
||||
|
||||
unmarshal(revert, Revert) ->
|
||||
genlib_map:compact(#{
|
||||
id => unmarshal(id, Revert#deposit_revert_Revert.id),
|
||||
@ -114,7 +105,6 @@ unmarshal(revert, Revert) ->
|
||||
reason => maybe_unmarshal(string, Revert#deposit_revert_Revert.reason),
|
||||
external_id => maybe_unmarshal(id, Revert#deposit_revert_Revert.external_id)
|
||||
});
|
||||
|
||||
unmarshal(revert_params, Params) ->
|
||||
genlib_map:compact(#{
|
||||
id => unmarshal(id, Params#deposit_revert_RevertParams.id),
|
||||
@ -122,7 +112,6 @@ unmarshal(revert_params, Params) ->
|
||||
external_id => maybe_unmarshal(id, Params#deposit_revert_RevertParams.external_id),
|
||||
reason => maybe_unmarshal(string, Params#deposit_revert_RevertParams.reason)
|
||||
});
|
||||
|
||||
unmarshal(T, V) ->
|
||||
ff_codec:unmarshal(T, V).
|
||||
|
||||
@ -142,14 +131,16 @@ maybe_marshal(Type, Value) ->
|
||||
|
||||
-ifdef(TEST).
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
-spec test() -> _.
|
||||
|
||||
-spec revert_symmetry_test() -> _.
|
||||
|
||||
revert_symmetry_test() ->
|
||||
Encoded = #deposit_revert_Revert{
|
||||
body = #'Cash'{
|
||||
amount = 10101,
|
||||
currency = #'CurrencyRef'{ symbolic_code = <<"Banana Republic">> }
|
||||
currency = #'CurrencyRef'{symbolic_code = <<"Banana Republic">>}
|
||||
},
|
||||
source_id = genlib:unique(),
|
||||
wallet_id = genlib:unique(),
|
||||
@ -168,7 +159,7 @@ revert_params_symmetry_test() ->
|
||||
Encoded = #deposit_revert_RevertParams{
|
||||
body = #'Cash'{
|
||||
amount = 10101,
|
||||
currency = #'CurrencyRef'{ symbolic_code = <<"Banana Republic">> }
|
||||
currency = #'CurrencyRef'{symbolic_code = <<"Banana Republic">>}
|
||||
},
|
||||
external_id = undefined,
|
||||
reason = <<"why not">>,
|
||||
@ -178,26 +169,28 @@ revert_params_symmetry_test() ->
|
||||
|
||||
-spec change_adjustment_symmetry_test() -> _.
|
||||
change_adjustment_symmetry_test() ->
|
||||
Encoded = {adjustment, #deposit_revert_AdjustmentChange{
|
||||
id = genlib:unique(),
|
||||
payload = {created, #dep_rev_adj_CreatedChange{
|
||||
adjustment = #dep_rev_adj_Adjustment{
|
||||
id = genlib:unique(),
|
||||
status = {pending, #dep_rev_adj_Pending{}},
|
||||
changes_plan = #dep_rev_adj_ChangesPlan{
|
||||
new_cash_flow = #dep_rev_adj_CashFlowChangePlan{
|
||||
old_cash_flow_inverted = #cashflow_FinalCashFlow{postings = []},
|
||||
new_cash_flow = #cashflow_FinalCashFlow{postings = []}
|
||||
Encoded =
|
||||
{adjustment, #deposit_revert_AdjustmentChange{
|
||||
id = genlib:unique(),
|
||||
payload =
|
||||
{created, #dep_rev_adj_CreatedChange{
|
||||
adjustment = #dep_rev_adj_Adjustment{
|
||||
id = genlib:unique(),
|
||||
status = {pending, #dep_rev_adj_Pending{}},
|
||||
changes_plan = #dep_rev_adj_ChangesPlan{
|
||||
new_cash_flow = #dep_rev_adj_CashFlowChangePlan{
|
||||
old_cash_flow_inverted = #cashflow_FinalCashFlow{postings = []},
|
||||
new_cash_flow = #cashflow_FinalCashFlow{postings = []}
|
||||
}
|
||||
},
|
||||
created_at = <<"2000-01-01T00:00:00Z">>,
|
||||
domain_revision = 123,
|
||||
party_revision = 321,
|
||||
operation_timestamp = <<"2000-01-01T00:00:00Z">>,
|
||||
external_id = genlib:unique()
|
||||
}
|
||||
},
|
||||
created_at = <<"2000-01-01T00:00:00Z">>,
|
||||
domain_revision = 123,
|
||||
party_revision = 321,
|
||||
operation_timestamp = <<"2000-01-01T00:00:00Z">>,
|
||||
external_id = genlib:unique()
|
||||
}
|
||||
}}
|
||||
}},
|
||||
}}
|
||||
}},
|
||||
?assertEqual(Encoded, marshal(change, unmarshal(change, Encoded))).
|
||||
|
||||
-endif.
|
||||
|
@ -9,30 +9,23 @@
|
||||
|
||||
%% API
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) ->
|
||||
ff_codec:encoded_value().
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) -> ff_codec:encoded_value().
|
||||
marshal(status, pending) ->
|
||||
{pending, #dep_rev_status_Pending{}};
|
||||
marshal(status, succeeded) ->
|
||||
{succeeded, #dep_rev_status_Succeeded{}};
|
||||
marshal(status, {failed, Failure}) ->
|
||||
{failed, #dep_rev_status_Failed{failure = marshal(failure, Failure)}};
|
||||
|
||||
marshal(T, V) ->
|
||||
ff_codec:marshal(T, V).
|
||||
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) ->
|
||||
ff_codec:decoded_value().
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) -> ff_codec:decoded_value().
|
||||
unmarshal(status, {pending, #dep_rev_status_Pending{}}) ->
|
||||
pending;
|
||||
unmarshal(status, {succeeded, #dep_rev_status_Succeeded{}}) ->
|
||||
succeeded;
|
||||
unmarshal(status, {failed, #dep_rev_status_Failed{failure = Failure}}) ->
|
||||
{failed, unmarshal(failure, Failure)};
|
||||
|
||||
unmarshal(T, V) ->
|
||||
ff_codec:unmarshal(T, V).
|
||||
|
||||
@ -40,9 +33,11 @@ unmarshal(T, V) ->
|
||||
|
||||
-ifdef(TEST).
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
-spec test() -> _.
|
||||
|
||||
-spec pending_symmetry_test() -> _.
|
||||
|
||||
pending_symmetry_test() ->
|
||||
Status = pending,
|
||||
?assertEqual(Status, unmarshal(status, marshal(status, Status))).
|
||||
@ -54,13 +49,14 @@ succeeded_symmetry_test() ->
|
||||
|
||||
-spec failed_symmetry_test() -> _.
|
||||
failed_symmetry_test() ->
|
||||
Status = {failed, #{
|
||||
code => <<"test">>,
|
||||
reason => <<"why not">>,
|
||||
sub => #{
|
||||
code => <<"sub">>
|
||||
}
|
||||
}},
|
||||
Status =
|
||||
{failed, #{
|
||||
code => <<"test">>,
|
||||
reason => <<"why not">>,
|
||||
sub => #{
|
||||
code => <<"sub">>
|
||||
}
|
||||
}},
|
||||
?assertEqual(Status, unmarshal(status, marshal(status, Status))).
|
||||
|
||||
-endif.
|
||||
|
@ -9,30 +9,23 @@
|
||||
|
||||
%% API
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) ->
|
||||
ff_codec:encoded_value().
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) -> ff_codec:encoded_value().
|
||||
marshal(status, pending) ->
|
||||
{pending, #dep_status_Pending{}};
|
||||
marshal(status, succeeded) ->
|
||||
{succeeded, #dep_status_Succeeded{}};
|
||||
marshal(status, {failed, Failure}) ->
|
||||
{failed, #dep_status_Failed{failure = marshal(failure, Failure)}};
|
||||
|
||||
marshal(T, V) ->
|
||||
ff_codec:marshal(T, V).
|
||||
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) ->
|
||||
ff_codec:decoded_value().
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) -> ff_codec:decoded_value().
|
||||
unmarshal(status, {pending, #dep_status_Pending{}}) ->
|
||||
pending;
|
||||
unmarshal(status, {succeeded, #dep_status_Succeeded{}}) ->
|
||||
succeeded;
|
||||
unmarshal(status, {failed, #dep_status_Failed{failure = Failure}}) ->
|
||||
{failed, unmarshal(failure, Failure)};
|
||||
|
||||
unmarshal(T, V) ->
|
||||
ff_codec:unmarshal(T, V).
|
||||
|
||||
@ -40,9 +33,11 @@ unmarshal(T, V) ->
|
||||
|
||||
-ifdef(TEST).
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
-spec test() -> _.
|
||||
|
||||
-spec pending_symmetry_test() -> _.
|
||||
|
||||
pending_symmetry_test() ->
|
||||
Status = pending,
|
||||
?assertEqual(Status, unmarshal(status, marshal(status, Status))).
|
||||
@ -54,13 +49,14 @@ succeeded_symmetry_test() ->
|
||||
|
||||
-spec failed_symmetry_test() -> _.
|
||||
failed_symmetry_test() ->
|
||||
Status = {failed, #{
|
||||
code => <<"test">>,
|
||||
reason => <<"why not">>,
|
||||
sub => #{
|
||||
code => <<"sub">>
|
||||
}
|
||||
}},
|
||||
Status =
|
||||
{failed, #{
|
||||
code => <<"test">>,
|
||||
reason => <<"why not">>,
|
||||
sub => #{
|
||||
code => <<"sub">>
|
||||
}
|
||||
}},
|
||||
?assertEqual(Status, unmarshal(status, marshal(status, Status))).
|
||||
|
||||
-endif.
|
||||
|
@ -14,30 +14,28 @@
|
||||
|
||||
%% API
|
||||
|
||||
-spec unmarshal_destination_params(ff_proto_destination_thrift:'DestinationParams'()) ->
|
||||
ff_destination:params().
|
||||
|
||||
-spec unmarshal_destination_params(ff_proto_destination_thrift:'DestinationParams'()) -> ff_destination:params().
|
||||
unmarshal_destination_params(Params) ->
|
||||
genlib_map:compact(#{
|
||||
id => unmarshal(id, Params#dst_DestinationParams.id),
|
||||
identity => unmarshal(id, Params#dst_DestinationParams.identity),
|
||||
name => unmarshal(string, Params#dst_DestinationParams.name),
|
||||
currency => unmarshal(string, Params#dst_DestinationParams.currency),
|
||||
resource => unmarshal(resource, Params#dst_DestinationParams.resource),
|
||||
id => unmarshal(id, Params#dst_DestinationParams.id),
|
||||
identity => unmarshal(id, Params#dst_DestinationParams.identity),
|
||||
name => unmarshal(string, Params#dst_DestinationParams.name),
|
||||
currency => unmarshal(string, Params#dst_DestinationParams.currency),
|
||||
resource => unmarshal(resource, Params#dst_DestinationParams.resource),
|
||||
external_id => maybe_unmarshal(id, Params#dst_DestinationParams.external_id),
|
||||
metadata => maybe_unmarshal(ctx, Params#dst_DestinationParams.metadata)
|
||||
metadata => maybe_unmarshal(ctx, Params#dst_DestinationParams.metadata)
|
||||
}).
|
||||
|
||||
-spec marshal_destination_state(ff_destination:destination_state(), ff_entity_context:context()) ->
|
||||
ff_proto_destination_thrift:'DestinationState'().
|
||||
|
||||
marshal_destination_state(DestinationState, Context) ->
|
||||
Blocking = case ff_destination:is_accessible(DestinationState) of
|
||||
{ok, accessible} ->
|
||||
unblocked;
|
||||
_ ->
|
||||
blocked
|
||||
end,
|
||||
Blocking =
|
||||
case ff_destination:is_accessible(DestinationState) of
|
||||
{ok, accessible} ->
|
||||
unblocked;
|
||||
_ ->
|
||||
blocked
|
||||
end,
|
||||
#dst_DestinationState{
|
||||
id = marshal(id, ff_destination:id(DestinationState)),
|
||||
name = marshal(string, ff_destination:name(DestinationState)),
|
||||
@ -51,9 +49,7 @@ marshal_destination_state(DestinationState, Context) ->
|
||||
context = maybe_marshal(ctx, Context)
|
||||
}.
|
||||
|
||||
-spec marshal_event(ff_destination_machine:event()) ->
|
||||
ff_proto_destination_thrift:'Event'().
|
||||
|
||||
-spec marshal_event(ff_destination_machine:event()) -> ff_proto_destination_thrift:'Event'().
|
||||
marshal_event({EventID, {ev, Timestamp, Change}}) ->
|
||||
#dst_Event{
|
||||
event_id = ff_codec:marshal(event_id, EventID),
|
||||
@ -61,74 +57,64 @@ marshal_event({EventID, {ev, Timestamp, Change}}) ->
|
||||
change = marshal(change, Change)
|
||||
}.
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) ->
|
||||
ff_codec:encoded_value().
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) -> ff_codec:encoded_value().
|
||||
marshal(timestamped_change, {ev, Timestamp, Change}) ->
|
||||
#dst_TimestampedChange{
|
||||
change = marshal(change, Change),
|
||||
occured_at = ff_codec:marshal(timestamp, Timestamp)
|
||||
};
|
||||
|
||||
marshal(change, {created, Destination}) ->
|
||||
{created, marshal(create_change, Destination)};
|
||||
marshal(change, {account, AccountChange}) ->
|
||||
{account, marshal(account_change, AccountChange)};
|
||||
marshal(change, {status_changed, StatusChange}) ->
|
||||
{status, marshal(status_change, StatusChange)};
|
||||
|
||||
marshal(create_change, Destination = #{
|
||||
name := Name,
|
||||
resource := Resource
|
||||
}) ->
|
||||
marshal(
|
||||
create_change,
|
||||
Destination = #{
|
||||
name := Name,
|
||||
resource := Resource
|
||||
}
|
||||
) ->
|
||||
#dst_Destination{
|
||||
name = Name,
|
||||
resource = marshal(resource, Resource),
|
||||
created_at = maybe_marshal(timestamp_ms, maps:get(created_at, Destination, undefined)),
|
||||
external_id = maybe_marshal(id, maps:get(external_id, Destination, undefined)),
|
||||
metadata = maybe_marshal(ctx, maps:get(metadata, Destination, undefined))
|
||||
created_at = maybe_marshal(timestamp_ms, maps:get(created_at, Destination, undefined)),
|
||||
external_id = maybe_marshal(id, maps:get(external_id, Destination, undefined)),
|
||||
metadata = maybe_marshal(ctx, maps:get(metadata, Destination, undefined))
|
||||
};
|
||||
|
||||
marshal(status, authorized) ->
|
||||
{authorized, #dst_Authorized{}};
|
||||
marshal(status, unauthorized) ->
|
||||
{unauthorized, #dst_Unauthorized{}};
|
||||
|
||||
marshal(status_change, unauthorized) ->
|
||||
{changed, {unauthorized, #dst_Unauthorized{}}};
|
||||
marshal(status_change, authorized) ->
|
||||
{changed, {authorized, #dst_Authorized{}}};
|
||||
|
||||
marshal(ctx, Ctx) ->
|
||||
marshal(context, Ctx);
|
||||
|
||||
marshal(T, V) ->
|
||||
ff_codec:marshal(T, V).
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) ->
|
||||
ff_codec:decoded_value().
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) -> ff_codec:decoded_value().
|
||||
unmarshal({list, T}, V) ->
|
||||
[unmarshal(T, E) || E <- V];
|
||||
|
||||
unmarshal(repair_scenario, {add_events, #dst_AddEventsRepair{events = Events, action = Action}}) ->
|
||||
{add_events, genlib_map:compact(#{
|
||||
events => unmarshal({list, change}, Events),
|
||||
action => maybe_unmarshal(complex_action, Action)
|
||||
})};
|
||||
|
||||
{add_events,
|
||||
genlib_map:compact(#{
|
||||
events => unmarshal({list, change}, Events),
|
||||
action => maybe_unmarshal(complex_action, Action)
|
||||
})};
|
||||
unmarshal(timestamped_change, TimestampedChange) ->
|
||||
Timestamp = ff_codec:unmarshal(timestamp, TimestampedChange#dst_TimestampedChange.occured_at),
|
||||
Change = unmarshal(change, TimestampedChange#dst_TimestampedChange.change),
|
||||
{ev, Timestamp, Change};
|
||||
|
||||
unmarshal(change, {created, Destination}) ->
|
||||
{created, unmarshal(destination, Destination)};
|
||||
unmarshal(change, {account, AccountChange}) ->
|
||||
{account, unmarshal(account_change, AccountChange)};
|
||||
unmarshal(change, {status, StatusChange}) ->
|
||||
{status_changed, unmarshal(status_change, StatusChange)};
|
||||
|
||||
unmarshal(destination, Dest) ->
|
||||
genlib_map:compact(#{
|
||||
version => 3,
|
||||
@ -138,20 +124,16 @@ unmarshal(destination, Dest) ->
|
||||
external_id => maybe_unmarshal(id, Dest#dst_Destination.external_id),
|
||||
metadata => maybe_unmarshal(ctx, Dest#dst_Destination.metadata)
|
||||
});
|
||||
|
||||
unmarshal(status, {authorized, #dst_Authorized{}}) ->
|
||||
authorized;
|
||||
unmarshal(status, {unauthorized, #dst_Unauthorized{}}) ->
|
||||
unauthorized;
|
||||
|
||||
unmarshal(status_change, {changed, {unauthorized, #dst_Unauthorized{}}}) ->
|
||||
unauthorized;
|
||||
unmarshal(status_change, {changed, {authorized, #dst_Authorized{}}}) ->
|
||||
authorized;
|
||||
|
||||
unmarshal(ctx, Ctx) ->
|
||||
maybe_unmarshal(context, Ctx);
|
||||
|
||||
unmarshal(T, V) ->
|
||||
ff_codec:unmarshal(T, V).
|
||||
|
||||
@ -171,27 +153,35 @@ maybe_unmarshal(Type, Value) ->
|
||||
|
||||
-ifdef(TEST).
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
-spec test() -> _.
|
||||
|
||||
-spec destination_test() -> _.
|
||||
|
||||
destination_test() ->
|
||||
Resource = {bank_card, #{bank_card => #{
|
||||
token => <<"token auth">>
|
||||
}}},
|
||||
Resource =
|
||||
{bank_card, #{
|
||||
bank_card => #{
|
||||
token => <<"token auth">>
|
||||
}
|
||||
}},
|
||||
In = #{
|
||||
version => 3,
|
||||
name => <<"Wallet">>,
|
||||
resource => Resource
|
||||
version => 3,
|
||||
name => <<"Wallet">>,
|
||||
resource => Resource
|
||||
},
|
||||
|
||||
?assertEqual(In, unmarshal(destination, marshal(create_change, In))).
|
||||
|
||||
-spec crypto_wallet_resource_test() -> _.
|
||||
crypto_wallet_resource_test() ->
|
||||
Resource = {crypto_wallet, #{crypto_wallet => #{
|
||||
id => <<"9e6245a7a6e15f75769a4d87183b090a">>,
|
||||
currency => {bitcoin, #{}}
|
||||
}}},
|
||||
Resource =
|
||||
{crypto_wallet, #{
|
||||
crypto_wallet => #{
|
||||
id => <<"9e6245a7a6e15f75769a4d87183b090a">>,
|
||||
currency => {bitcoin, #{}}
|
||||
}
|
||||
}},
|
||||
?assertEqual(Resource, unmarshal(resource, marshal(resource, Resource))).
|
||||
|
||||
-endif.
|
||||
|
@ -9,32 +9,28 @@
|
||||
-type event() :: ff_eventsink_publisher:event(ff_destination:event()).
|
||||
-type sinkevent() :: ff_eventsink_publisher:sinkevent(ff_proto_destination_thrift:'SinkEvent'()).
|
||||
|
||||
-spec publish_events(list(event())) ->
|
||||
list(sinkevent()).
|
||||
|
||||
-spec publish_events(list(event())) -> list(sinkevent()).
|
||||
publish_events(Events) ->
|
||||
[publish_event(Event) || Event <- Events].
|
||||
|
||||
-spec publish_event(event()) ->
|
||||
sinkevent().
|
||||
|
||||
-spec publish_event(event()) -> sinkevent().
|
||||
publish_event(#{
|
||||
id := ID,
|
||||
source_id := SourceID,
|
||||
event := {
|
||||
id := ID,
|
||||
source_id := SourceID,
|
||||
event := {
|
||||
EventID,
|
||||
Dt,
|
||||
{ev, EventDt, Payload}
|
||||
}
|
||||
}) ->
|
||||
#dst_SinkEvent{
|
||||
id = marshal(event_id, ID),
|
||||
created_at = marshal(timestamp, Dt),
|
||||
source = marshal(id, SourceID),
|
||||
payload = #dst_EventSinkPayload{
|
||||
sequence = marshal(event_id, EventID),
|
||||
id = marshal(event_id, ID),
|
||||
created_at = marshal(timestamp, Dt),
|
||||
source = marshal(id, SourceID),
|
||||
payload = #dst_EventSinkPayload{
|
||||
sequence = marshal(event_id, EventID),
|
||||
occured_at = marshal(timestamp, EventDt),
|
||||
changes = [marshal(change, Payload)]
|
||||
changes = [marshal(change, Payload)]
|
||||
}
|
||||
}.
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
-module(ff_destination_handler).
|
||||
|
||||
-behaviour(ff_woody_wrapper).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_destination_thrift.hrl").
|
||||
@ -9,10 +10,11 @@
|
||||
%%
|
||||
%% ff_woody_wrapper callbacks
|
||||
%%
|
||||
-spec handle_function(woody:func(), woody:args(), woody:options()) ->
|
||||
{ok, woody:result()} | no_return().
|
||||
-spec handle_function(woody:func(), woody:args(), woody:options()) -> {ok, woody:result()} | no_return().
|
||||
handle_function(Func, Args, Opts) ->
|
||||
scoper:scope(destination, #{},
|
||||
scoper:scope(
|
||||
destination,
|
||||
#{},
|
||||
fun() ->
|
||||
handle_function_(Func, Args, Opts)
|
||||
end
|
||||
@ -23,9 +25,11 @@ handle_function(Func, Args, Opts) ->
|
||||
%%
|
||||
handle_function_('Create', [Params, Ctx], Opts) ->
|
||||
ID = Params#dst_DestinationParams.id,
|
||||
case ff_destination_machine:create(
|
||||
ff_destination_codec:unmarshal_destination_params(Params),
|
||||
ff_destination_codec:unmarshal(ctx, Ctx))
|
||||
case
|
||||
ff_destination_machine:create(
|
||||
ff_destination_codec:unmarshal_destination_params(Params),
|
||||
ff_destination_codec:unmarshal(ctx, Ctx)
|
||||
)
|
||||
of
|
||||
ok ->
|
||||
handle_function_('Get', [ID, #'EventRange'{}], Opts);
|
||||
|
@ -21,72 +21,67 @@
|
||||
-type value_type() :: machinery_mg_schema:vt().
|
||||
-type context() :: machinery_mg_schema:context().
|
||||
|
||||
-type event() :: ff_machine:timestamped_event(ff_destination:event()).
|
||||
-type event() :: ff_machine:timestamped_event(ff_destination:event()).
|
||||
-type aux_state() :: ff_machine:auxst().
|
||||
-type call_args() :: term().
|
||||
-type call_response() :: term().
|
||||
|
||||
-type data() ::
|
||||
aux_state() |
|
||||
event() |
|
||||
call_args() |
|
||||
call_response().
|
||||
aux_state()
|
||||
| event()
|
||||
| call_args()
|
||||
| call_response().
|
||||
|
||||
%% machinery_mg_schema callbacks
|
||||
|
||||
-spec get_version(value_type()) ->
|
||||
machinery_mg_schema:version().
|
||||
-spec get_version(value_type()) -> machinery_mg_schema:version().
|
||||
get_version(event) ->
|
||||
?CURRENT_EVENT_FORMAT_VERSION;
|
||||
get_version(aux_state) ->
|
||||
undefined.
|
||||
|
||||
-spec marshal(type(), value(data()), context()) ->
|
||||
{machinery_msgpack:t(), context()}.
|
||||
-spec marshal(type(), value(data()), context()) -> {machinery_msgpack:t(), context()}.
|
||||
marshal({event, Format}, TimestampedChange, Context) ->
|
||||
marshal_event(Format, TimestampedChange, Context);
|
||||
marshal(T, V, C) when
|
||||
T =:= {args, init} orelse
|
||||
T =:= {args, call} orelse
|
||||
T =:= {args, repair} orelse
|
||||
T =:= {aux_state, undefined} orelse
|
||||
T =:= {response, call} orelse
|
||||
T =:= {response, {repair, success}} orelse
|
||||
T =:= {response, {repair, failure}}
|
||||
T =:= {args, call} orelse
|
||||
T =:= {args, repair} orelse
|
||||
T =:= {aux_state, undefined} orelse
|
||||
T =:= {response, call} orelse
|
||||
T =:= {response, {repair, success}} orelse
|
||||
T =:= {response, {repair, failure}}
|
||||
->
|
||||
machinery_mg_schema_generic:marshal(T, V, C).
|
||||
|
||||
-spec unmarshal(type(), machinery_msgpack:t(), context()) ->
|
||||
{data(), context()}.
|
||||
-spec unmarshal(type(), machinery_msgpack:t(), context()) -> {data(), context()}.
|
||||
unmarshal({event, FormatVersion}, EncodedChange, Context) ->
|
||||
unmarshal_event(FormatVersion, EncodedChange, Context);
|
||||
unmarshal(T, V, C) when
|
||||
T =:= {args, init} orelse
|
||||
T =:= {args, call} orelse
|
||||
T =:= {args, repair} orelse
|
||||
T =:= {aux_state, undefined} orelse
|
||||
T =:= {response, call} orelse
|
||||
T =:= {response, {repair, success}} orelse
|
||||
T =:= {response, {repair, failure}}
|
||||
T =:= {args, call} orelse
|
||||
T =:= {args, repair} orelse
|
||||
T =:= {aux_state, undefined} orelse
|
||||
T =:= {response, call} orelse
|
||||
T =:= {response, {repair, success}} orelse
|
||||
T =:= {response, {repair, failure}}
|
||||
->
|
||||
machinery_mg_schema_generic:unmarshal(T, V, C).
|
||||
|
||||
%% Internals
|
||||
|
||||
-spec marshal_event(machinery_mg_schema:version(), event(), context()) ->
|
||||
{machinery_msgpack:t(), context()}.
|
||||
-spec marshal_event(machinery_mg_schema:version(), event(), context()) -> {machinery_msgpack:t(), context()}.
|
||||
%%@TODO remove post migration
|
||||
%%======
|
||||
marshal_event(undefined = Version, TimestampedChange, Context) ->
|
||||
machinery_mg_schema_generic:marshal({event, Version}, TimestampedChange, Context);
|
||||
machinery_mg_schema_generic:marshal({event, Version}, TimestampedChange, Context);
|
||||
%%======
|
||||
marshal_event(1, TimestampedChange, Context) ->
|
||||
ThriftChange = ff_destination_codec:marshal(timestamped_change, TimestampedChange),
|
||||
Type = {struct, struct, {ff_proto_destination_thrift, 'TimestampedChange'}},
|
||||
{{bin, ff_proto_utils:serialize(Type, ThriftChange)}, Context}.
|
||||
|
||||
-spec unmarshal_event(machinery_mg_schema:version(), machinery_msgpack:t(), context()) ->
|
||||
{event(), context()}.
|
||||
-spec unmarshal_event(machinery_mg_schema:version(), machinery_msgpack:t(), context()) -> {event(), context()}.
|
||||
unmarshal_event(1, EncodedChange, Context) ->
|
||||
{bin, EncodedThriftChange} = EncodedChange,
|
||||
Type = {struct, struct, {ff_proto_destination_thrift, 'TimestampedChange'}},
|
||||
@ -96,84 +91,90 @@ unmarshal_event(undefined = Version, EncodedChange, Context0) ->
|
||||
{Event, Context1} = machinery_mg_schema_generic:unmarshal({event, Version}, EncodedChange, Context0),
|
||||
{maybe_migrate(Event), Context1}.
|
||||
|
||||
-spec maybe_migrate(any()) ->
|
||||
event().
|
||||
-spec maybe_migrate(any()) -> event().
|
||||
maybe_migrate({ev, Timestamp, Change}) ->
|
||||
{ev, Timestamp, ff_destination:maybe_migrate(Change, #{timestamp => Timestamp})}.
|
||||
|
||||
-ifdef(TEST).
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
-spec test() -> _.
|
||||
|
||||
-spec marshal(type(), value(data())) ->
|
||||
machinery_msgpack:t().
|
||||
-spec marshal(type(), value(data())) -> machinery_msgpack:t().
|
||||
|
||||
marshal(Type, Value) ->
|
||||
{Result, _Context} = marshal(Type, Value, #{}),
|
||||
Result.
|
||||
|
||||
-spec unmarshal(type(), machinery_msgpack:t()) ->
|
||||
data().
|
||||
-spec unmarshal(type(), machinery_msgpack:t()) -> data().
|
||||
unmarshal(Type, Value) ->
|
||||
{Result, _Context} = unmarshal(Type, Value, #{}),
|
||||
Result.
|
||||
|
||||
-spec created_v0_0_decoding_test() -> _.
|
||||
created_v0_0_decoding_test() ->
|
||||
Resource = {crypto_wallet, #{crypto_wallet => #{
|
||||
id => <<"kek">>,
|
||||
currency => {bitcoin, #{}}
|
||||
}}},
|
||||
Resource =
|
||||
{crypto_wallet, #{
|
||||
crypto_wallet => #{
|
||||
id => <<"kek">>,
|
||||
currency => {bitcoin, #{}}
|
||||
}
|
||||
}},
|
||||
Destination = #{
|
||||
version => 3,
|
||||
resource => Resource,
|
||||
name => <<"name">>,
|
||||
created_at => 1590434350293,
|
||||
version => 3,
|
||||
resource => Resource,
|
||||
name => <<"name">>,
|
||||
created_at => 1590434350293,
|
||||
external_id => <<"external_id">>
|
||||
},
|
||||
Change = {created, Destination},
|
||||
Event = {ev, {{{2020, 5, 25}, {19, 19, 10}}, 293305}, Change},
|
||||
|
||||
LegacyResource = {arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"crypto_wallet">>},
|
||||
{arr, [
|
||||
{str, <<"map">>},
|
||||
{obj, #{
|
||||
{str, <<"currency">>} => {arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"bitcoin">>},
|
||||
{arr, [{str, <<"map">>}, {obj, #{}}]}
|
||||
]},
|
||||
{str, <<"id">>} => {bin, <<"kek">>}
|
||||
}}
|
||||
]}
|
||||
]},
|
||||
LegacyChange = {arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"created">>},
|
||||
{arr, [
|
||||
{str, <<"map">>},
|
||||
{obj, #{
|
||||
{str, <<"resource">>} => LegacyResource,
|
||||
{str, <<"name">>} => {bin, <<"name">>},
|
||||
{str, <<"external_id">>} => {bin, <<"external_id">>}
|
||||
}}
|
||||
]}
|
||||
]},
|
||||
LegacyEvent = {arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"ev">>},
|
||||
LegacyResource =
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"crypto_wallet">>},
|
||||
{arr, [
|
||||
{str, <<"map">>},
|
||||
{obj, #{
|
||||
{str, <<"currency">>} =>
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"bitcoin">>},
|
||||
{arr, [{str, <<"map">>}, {obj, #{}}]}
|
||||
]},
|
||||
{str, <<"id">>} => {bin, <<"kek">>}
|
||||
}}
|
||||
]}
|
||||
]},
|
||||
LegacyChange =
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"created">>},
|
||||
{arr, [
|
||||
{str, <<"map">>},
|
||||
{obj, #{
|
||||
{str, <<"resource">>} => LegacyResource,
|
||||
{str, <<"name">>} => {bin, <<"name">>},
|
||||
{str, <<"external_id">>} => {bin, <<"external_id">>}
|
||||
}}
|
||||
]}
|
||||
]},
|
||||
LegacyEvent =
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"ev">>},
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{arr, [{str, <<"tup">>}, {i, 2020}, {i, 5}, {i, 25}]},
|
||||
{arr, [{str, <<"tup">>}, {i, 19}, {i, 19}, {i, 10}]}
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{arr, [{str, <<"tup">>}, {i, 2020}, {i, 5}, {i, 25}]},
|
||||
{arr, [{str, <<"tup">>}, {i, 19}, {i, 19}, {i, 10}]}
|
||||
]},
|
||||
{i, 293305}
|
||||
]},
|
||||
{i, 293305}
|
||||
LegacyChange
|
||||
]},
|
||||
LegacyChange
|
||||
]},
|
||||
|
||||
DecodedLegacy = unmarshal({event, undefined}, LegacyEvent),
|
||||
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
|
||||
@ -182,69 +183,76 @@ created_v0_0_decoding_test() ->
|
||||
|
||||
-spec created_v0_1_decoding_test() -> _.
|
||||
created_v0_1_decoding_test() ->
|
||||
Resource = {bank_card, #{bank_card => #{
|
||||
token => <<"token">>,
|
||||
bin_data_id => {binary, <<"ebin">>}
|
||||
}}},
|
||||
Resource =
|
||||
{bank_card, #{
|
||||
bank_card => #{
|
||||
token => <<"token">>,
|
||||
bin_data_id => {binary, <<"ebin">>}
|
||||
}
|
||||
}},
|
||||
Destination = #{
|
||||
version => 3,
|
||||
resource => Resource,
|
||||
name => <<"name">>,
|
||||
created_at => 1590434350293,
|
||||
version => 3,
|
||||
resource => Resource,
|
||||
name => <<"name">>,
|
||||
created_at => 1590434350293,
|
||||
external_id => <<"external_id">>
|
||||
},
|
||||
Change = {created, Destination},
|
||||
Event = {ev, {{{2020, 5, 25}, {19, 19, 10}}, 293305}, Change},
|
||||
|
||||
LegacyResource = {arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"bank_card">>},
|
||||
{arr, [
|
||||
{str, <<"map">>},
|
||||
{obj, #{
|
||||
{str, <<"bank_card">>} =>
|
||||
{arr, [
|
||||
{str, <<"map">>},
|
||||
{obj, #{
|
||||
{str, <<"bin_data_id">>} => {arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"binary">>},
|
||||
{bin, <<"ebin">>}
|
||||
]},
|
||||
{str, <<"token">>} => {bin, <<"token">>}
|
||||
}}
|
||||
]}
|
||||
}}
|
||||
]}
|
||||
]},
|
||||
LegacyChange = {arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"created">>},
|
||||
{arr, [
|
||||
{str, <<"map">>},
|
||||
{obj, #{
|
||||
{str, <<"version">>} => {i, 1},
|
||||
{str, <<"resource">>} => LegacyResource,
|
||||
{str, <<"name">>} => {bin, <<"name">>},
|
||||
{str, <<"created_at">>} => {i, 1590434350293},
|
||||
{str, <<"external_id">>} => {bin, <<"external_id">>}
|
||||
}}
|
||||
]}
|
||||
]},
|
||||
LegacyEvent = {arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"ev">>},
|
||||
LegacyResource =
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"bank_card">>},
|
||||
{arr, [
|
||||
{str, <<"map">>},
|
||||
{obj, #{
|
||||
{str, <<"bank_card">>} =>
|
||||
{arr, [
|
||||
{str, <<"map">>},
|
||||
{obj, #{
|
||||
{str, <<"bin_data_id">>} =>
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"binary">>},
|
||||
{bin, <<"ebin">>}
|
||||
]},
|
||||
{str, <<"token">>} => {bin, <<"token">>}
|
||||
}}
|
||||
]}
|
||||
}}
|
||||
]}
|
||||
]},
|
||||
LegacyChange =
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"created">>},
|
||||
{arr, [
|
||||
{str, <<"map">>},
|
||||
{obj, #{
|
||||
{str, <<"version">>} => {i, 1},
|
||||
{str, <<"resource">>} => LegacyResource,
|
||||
{str, <<"name">>} => {bin, <<"name">>},
|
||||
{str, <<"created_at">>} => {i, 1590434350293},
|
||||
{str, <<"external_id">>} => {bin, <<"external_id">>}
|
||||
}}
|
||||
]}
|
||||
]},
|
||||
LegacyEvent =
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"ev">>},
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{arr, [{str, <<"tup">>}, {i, 2020}, {i, 5}, {i, 25}]},
|
||||
{arr, [{str, <<"tup">>}, {i, 19}, {i, 19}, {i, 10}]}
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{arr, [{str, <<"tup">>}, {i, 2020}, {i, 5}, {i, 25}]},
|
||||
{arr, [{str, <<"tup">>}, {i, 19}, {i, 19}, {i, 10}]}
|
||||
]},
|
||||
{i, 293305}
|
||||
]},
|
||||
{i, 293305}
|
||||
LegacyChange
|
||||
]},
|
||||
LegacyChange
|
||||
]},
|
||||
|
||||
DecodedLegacy = unmarshal({event, undefined}, LegacyEvent),
|
||||
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
|
||||
@ -253,47 +261,51 @@ created_v0_1_decoding_test() ->
|
||||
|
||||
-spec account_v0_decoding_test() -> _.
|
||||
account_v0_decoding_test() ->
|
||||
Change = {account, {created, #{
|
||||
id => <<"1">>,
|
||||
identity => <<"Solo">>,
|
||||
currency => <<"USD">>,
|
||||
accounter_account_id => 322
|
||||
}}},
|
||||
Change =
|
||||
{account,
|
||||
{created, #{
|
||||
id => <<"1">>,
|
||||
identity => <<"Solo">>,
|
||||
currency => <<"USD">>,
|
||||
accounter_account_id => 322
|
||||
}}},
|
||||
|
||||
Event = {ev, {{{2020, 5, 25}, {19, 19, 10}}, 293305}, Change},
|
||||
|
||||
LegacyChange = {arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"account">>},
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"created">>},
|
||||
{arr, [
|
||||
{str, <<"map">>},
|
||||
{obj, #{
|
||||
{str, <<"id">>} => {bin, <<"1">>},
|
||||
{str, <<"identity">>} => {bin, <<"Solo">>},
|
||||
{str, <<"currency">>} => {bin, <<"USD">>},
|
||||
{str, <<"accounter_account_id">>} => {i, 322}
|
||||
}}
|
||||
]}
|
||||
]}
|
||||
]},
|
||||
|
||||
LegacyEvent = {arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"ev">>},
|
||||
LegacyChange =
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"account">>},
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{arr, [{str, <<"tup">>}, {i, 2020}, {i, 5}, {i, 25}]},
|
||||
{arr, [{str, <<"tup">>}, {i, 19}, {i, 19}, {i, 10}]}
|
||||
]},
|
||||
{i, 293305}
|
||||
{str, <<"created">>},
|
||||
{arr, [
|
||||
{str, <<"map">>},
|
||||
{obj, #{
|
||||
{str, <<"id">>} => {bin, <<"1">>},
|
||||
{str, <<"identity">>} => {bin, <<"Solo">>},
|
||||
{str, <<"currency">>} => {bin, <<"USD">>},
|
||||
{str, <<"accounter_account_id">>} => {i, 322}
|
||||
}}
|
||||
]}
|
||||
]}
|
||||
]},
|
||||
|
||||
LegacyEvent =
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"ev">>},
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{arr, [{str, <<"tup">>}, {i, 2020}, {i, 5}, {i, 25}]},
|
||||
{arr, [{str, <<"tup">>}, {i, 19}, {i, 19}, {i, 10}]}
|
||||
]},
|
||||
{i, 293305}
|
||||
]},
|
||||
LegacyChange
|
||||
]},
|
||||
LegacyChange
|
||||
]},
|
||||
|
||||
DecodedLegacy = unmarshal({event, undefined}, LegacyEvent),
|
||||
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
|
||||
@ -308,24 +320,25 @@ status_v0_decoding_test() ->
|
||||
{status_changed, unauthorized}
|
||||
},
|
||||
|
||||
LegacyEvent = {arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"ev">>},
|
||||
LegacyEvent =
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"ev">>},
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{arr, [{str, <<"tup">>}, {i, 2020}, {i, 5}, {i, 25}]},
|
||||
{arr, [{str, <<"tup">>}, {i, 19}, {i, 19}, {i, 10}]}
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{arr, [{str, <<"tup">>}, {i, 2020}, {i, 5}, {i, 25}]},
|
||||
{arr, [{str, <<"tup">>}, {i, 19}, {i, 19}, {i, 10}]}
|
||||
]},
|
||||
{i, 293305}
|
||||
]},
|
||||
{i, 293305}
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"status_changed">>},
|
||||
{str, <<"unauthorized">>}
|
||||
]}
|
||||
]},
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"status_changed">>},
|
||||
{str, <<"unauthorized">>}
|
||||
]}
|
||||
]},
|
||||
|
||||
DecodedLegacy = unmarshal({event, undefined}, LegacyEvent),
|
||||
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
|
||||
@ -334,25 +347,30 @@ status_v0_decoding_test() ->
|
||||
|
||||
-spec created_v1_3_decoding_test() -> _.
|
||||
created_v1_3_decoding_test() ->
|
||||
Resource = {crypto_wallet, #{crypto_wallet => #{
|
||||
id => <<"kek">>,
|
||||
currency => {bitcoin, #{}}
|
||||
}}},
|
||||
Resource =
|
||||
{crypto_wallet, #{
|
||||
crypto_wallet => #{
|
||||
id => <<"kek">>,
|
||||
currency => {bitcoin, #{}}
|
||||
}
|
||||
}},
|
||||
Destination = #{
|
||||
version => 3,
|
||||
resource => Resource,
|
||||
name => <<"name">>,
|
||||
created_at => 1590434350293,
|
||||
version => 3,
|
||||
resource => Resource,
|
||||
name => <<"name">>,
|
||||
created_at => 1590434350293,
|
||||
external_id => <<"external_id">>
|
||||
},
|
||||
Change = {created, Destination},
|
||||
Event = {ev, {{{2020, 5, 25}, {19, 19, 10}}, 293305}, Change},
|
||||
|
||||
LegacyEvent = {bin, base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgwAAQsAAQAAAARuYW1lDAA"
|
||||
"CDAACDAABCwABAAAAA2tlawwAAwwAAQAACAACAAAAAAAAAAsAAwAAAAtleHRlcm5hbF9pZA"
|
||||
"sABwAAABgyMDIwLTA1LTI1VDE5OjE5OjEwLjI5M1oAAAA="
|
||||
>>)},
|
||||
LegacyEvent =
|
||||
{bin,
|
||||
base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgwAAQsAAQAAAARuYW1lDAA"
|
||||
"CDAACDAABCwABAAAAA2tlawwAAwwAAQAACAACAAAAAAAAAAsAAwAAAAtleHRlcm5hbF9pZA"
|
||||
"sABwAAABgyMDIwLTA1LTI1VDE5OjE5OjEwLjI5M1oAAAA="
|
||||
>>)},
|
||||
|
||||
DecodedLegacy = unmarshal({event, 1}, LegacyEvent),
|
||||
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
|
||||
@ -361,19 +379,23 @@ created_v1_3_decoding_test() ->
|
||||
|
||||
-spec account_v1_decoding_test() -> _.
|
||||
account_v1_decoding_test() ->
|
||||
Change = {account, {created, #{
|
||||
id => <<"1">>,
|
||||
identity => <<"Solo">>,
|
||||
currency => <<"USD">>,
|
||||
accounter_account_id => 322
|
||||
}}},
|
||||
Change =
|
||||
{account,
|
||||
{created, #{
|
||||
id => <<"1">>,
|
||||
identity => <<"Solo">>,
|
||||
currency => <<"USD">>,
|
||||
accounter_account_id => 322
|
||||
}}},
|
||||
|
||||
Event = {ev, {{{2020, 5, 25}, {19, 19, 10}}, 293305}, Change},
|
||||
|
||||
LegacyEvent = {bin, base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgwAAgwAAQsAAwAAAAExCw"
|
||||
"ABAAAABFNvbG8MAAILAAEAAAADVVNEAAoABAAAAAAAAAFCAAAAAA=="
|
||||
>>)},
|
||||
LegacyEvent =
|
||||
{bin,
|
||||
base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgwAAgwAAQsAAwAAAAExCw"
|
||||
"ABAAAABFNvbG8MAAILAAEAAAADVVNEAAoABAAAAAAAAAFCAAAAAA=="
|
||||
>>)},
|
||||
|
||||
DecodedLegacy = unmarshal({event, 1}, LegacyEvent),
|
||||
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
|
||||
@ -388,9 +410,11 @@ status_v1_decoding_test() ->
|
||||
{status_changed, unauthorized}
|
||||
},
|
||||
|
||||
LegacyEvent = {bin, base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgwAAwwAAQwAAgAAAAAA"
|
||||
>>)},
|
||||
LegacyEvent =
|
||||
{bin,
|
||||
base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgwAAwwAAQwAAgAAAAAA"
|
||||
>>)},
|
||||
|
||||
DecodedLegacy = unmarshal({event, 1}, LegacyEvent),
|
||||
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
|
||||
|
@ -2,37 +2,49 @@
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_msgpack_thrift.hrl").
|
||||
|
||||
-type ctx()::ff_entity_context:context().
|
||||
|
||||
-type ctx() :: ff_entity_context:context().
|
||||
|
||||
-export([marshal/1]).
|
||||
-export([unmarshal/1]).
|
||||
|
||||
%% snatch from https://github.com/rbkmoney/erlang_capi/blob/v2/apps/capi/src/capi_msgpack.erl
|
||||
-spec unmarshal(map()) ->
|
||||
ctx().
|
||||
-spec unmarshal(map()) -> ctx().
|
||||
unmarshal(Ctx) when is_map(Ctx) ->
|
||||
maps:map(fun(_NS, V) -> unwrap_(V) end, Ctx).
|
||||
|
||||
unwrap_({nl, #msgp_Nil{}}) -> nil;
|
||||
unwrap_({b, V}) when is_boolean(V) -> V;
|
||||
unwrap_({i, V}) when is_integer(V) -> V;
|
||||
unwrap_({flt, V}) when is_float(V) -> V;
|
||||
unwrap_({str, V}) when is_binary(V) -> V; % Assuming well-formed UTF-8 bytestring.
|
||||
unwrap_({bin, V}) when is_binary(V) -> {binary, V};
|
||||
unwrap_({arr, V}) when is_list(V) -> [unwrap_(ListItem) || ListItem <- V];
|
||||
unwrap_({obj, V}) when is_map(V) ->
|
||||
unwrap_({nl, #msgp_Nil{}}) ->
|
||||
nil;
|
||||
unwrap_({b, V}) when is_boolean(V) ->
|
||||
V;
|
||||
unwrap_({i, V}) when is_integer(V) ->
|
||||
V;
|
||||
unwrap_({flt, V}) when is_float(V) ->
|
||||
V;
|
||||
% Assuming well-formed UTF-8 bytestring.
|
||||
unwrap_({str, V}) when is_binary(V) ->
|
||||
V;
|
||||
unwrap_({bin, V}) when is_binary(V) ->
|
||||
{binary, V};
|
||||
unwrap_({arr, V}) when is_list(V) ->
|
||||
[unwrap_(ListItem) || ListItem <- V];
|
||||
unwrap_({obj, V}) when is_map(V) ->
|
||||
maps:fold(fun(Key, Value, Map) -> Map#{unwrap_(Key) => unwrap_(Value)} end, #{}, V).
|
||||
|
||||
-spec marshal(map()) -> ctx().
|
||||
marshal(Value) when is_map(Value) ->
|
||||
maps:map(fun(_K, V) -> wrap_(V) end, Value).
|
||||
|
||||
wrap_(nil) -> {nl, #msgp_Nil{}};
|
||||
wrap_(V) when is_boolean(V) -> {b, V};
|
||||
wrap_(V) when is_integer(V) -> {i, V};
|
||||
wrap_(V) when is_float(V) -> V;
|
||||
wrap_(V) when is_binary(V) -> {str, V}; % Assuming well-formed UTF-8 bytestring.
|
||||
wrap_(nil) ->
|
||||
{nl, #msgp_Nil{}};
|
||||
wrap_(V) when is_boolean(V) ->
|
||||
{b, V};
|
||||
wrap_(V) when is_integer(V) ->
|
||||
{i, V};
|
||||
wrap_(V) when is_float(V) ->
|
||||
V;
|
||||
% Assuming well-formed UTF-8 bytestring.
|
||||
wrap_(V) when is_binary(V) ->
|
||||
{str, V};
|
||||
wrap_({binary, V}) when is_binary(V) ->
|
||||
{bin, V};
|
||||
wrap_(V) when is_list(V) ->
|
||||
@ -48,9 +60,11 @@ wrap_(V) when is_map(V) ->
|
||||
-spec test() -> _.
|
||||
|
||||
-spec unwrap_test() -> _.
|
||||
|
||||
unwrap_test() ->
|
||||
K = {str, <<"Key">>},
|
||||
K2 = {i, 1}, V = {str, <<"Value">>},
|
||||
K2 = {i, 1},
|
||||
V = {str, <<"Value">>},
|
||||
Obj = {obj, #{K => V}},
|
||||
Obj2 = {obj, #{K2 => Obj}},
|
||||
MsgPack = {arr, [Obj2]},
|
||||
@ -65,10 +79,10 @@ wrap_test() ->
|
||||
Obj = #{123 => Str},
|
||||
Arr = [Obj],
|
||||
MsgPack = marshal(#{<<"NS">> => Arr}),
|
||||
?assertEqual(#{<<"NS">> => {arr, [{obj, #{ {i, 123} => {str, Str} }}]}}, MsgPack).
|
||||
?assertEqual(#{<<"NS">> => {arr, [{obj, #{{i, 123} => {str, Str}}}]}}, MsgPack).
|
||||
|
||||
-spec wrap_empty_obj_test() -> _.
|
||||
wrap_empty_obj_test() ->
|
||||
?assertEqual({obj, #{}}, wrap_(#{})).
|
||||
|
||||
-endif.
|
||||
-endif.
|
||||
|
@ -7,20 +7,21 @@
|
||||
-include_lib("fistful_proto/include/ff_proto_eventsink_thrift.hrl").
|
||||
|
||||
-type options() :: #{
|
||||
schema := module(),
|
||||
client := woody_client:options(),
|
||||
ns := binary(),
|
||||
publisher := module()
|
||||
schema := module(),
|
||||
client := woody_client:options(),
|
||||
ns := binary(),
|
||||
publisher := module()
|
||||
}.
|
||||
|
||||
%%
|
||||
%% ff_woody_wrapper callbacks
|
||||
%%
|
||||
|
||||
-spec handle_function(woody:func(), woody:args(), options()) ->
|
||||
{ok, woody:result()} | no_return().
|
||||
-spec handle_function(woody:func(), woody:args(), options()) -> {ok, woody:result()} | no_return().
|
||||
handle_function(Func, Args, Opts) ->
|
||||
scoper:scope(eventsink_handler, #{},
|
||||
scoper:scope(
|
||||
eventsink_handler,
|
||||
#{},
|
||||
fun() ->
|
||||
handle_function_(Func, Args, Opts)
|
||||
end
|
||||
@ -36,8 +37,12 @@ handle_function_('GetEvents', [#'evsink_EventRange'{'after' = After0, limit = Li
|
||||
} = Options,
|
||||
After = erlang:max(After0, StartEvent),
|
||||
WoodyContext = ff_context:get_woody_context(ff_context:load()),
|
||||
{ok, Events} = machinery_mg_eventsink:get_events(NS, After, Limit,
|
||||
#{client => {Client, WoodyContext}, schema => Schema}),
|
||||
{ok, Events} = machinery_mg_eventsink:get_events(
|
||||
NS,
|
||||
After,
|
||||
Limit,
|
||||
#{client => {Client, WoodyContext}, schema => Schema}
|
||||
),
|
||||
ff_eventsink_publisher:publish_events(Events, #{publisher => Publisher});
|
||||
handle_function_('GetLastEventID', _Params, #{schema := Schema, client := Client, ns := NS}) ->
|
||||
WoodyContext = ff_context:get_woody_context(ff_context:load()),
|
||||
|
@ -19,16 +19,13 @@
|
||||
-export_type([sinkevent/1]).
|
||||
-export_type([options/0]).
|
||||
|
||||
-callback publish_events(list(event(_))) ->
|
||||
list(sinkevent(_)).
|
||||
-callback publish_events(list(event(_))) -> list(sinkevent(_)).
|
||||
|
||||
%% API
|
||||
|
||||
-export([publish_events/2]).
|
||||
|
||||
-spec publish_events(list(event(_)), options()) ->
|
||||
{ok, list(sinkevent(_))}.
|
||||
|
||||
-spec publish_events(list(event(_)), options()) -> {ok, list(sinkevent(_))}.
|
||||
publish_events(Events, Opts) ->
|
||||
{ok, handler_publish_events(Events, Opts)}.
|
||||
|
||||
|
@ -15,72 +15,67 @@
|
||||
-export([unmarshal/2]).
|
||||
|
||||
%% This special functions hasn't got opposite functions.
|
||||
-spec unmarshal_identity_params(ff_proto_identity_thrift:'IdentityParams'()) ->
|
||||
ff_identity_machine:params().
|
||||
|
||||
-spec unmarshal_identity_params(ff_proto_identity_thrift:'IdentityParams'()) -> ff_identity_machine:params().
|
||||
unmarshal_identity_params(#idnt_IdentityParams{
|
||||
id = ID,
|
||||
name = Name,
|
||||
party = PartyID,
|
||||
provider = ProviderID,
|
||||
cls = ClassID,
|
||||
id = ID,
|
||||
name = Name,
|
||||
party = PartyID,
|
||||
provider = ProviderID,
|
||||
cls = ClassID,
|
||||
external_id = ExternalID,
|
||||
metadata = Metadata
|
||||
metadata = Metadata
|
||||
}) ->
|
||||
genlib_map:compact(#{
|
||||
id => unmarshal(id, ID),
|
||||
name => unmarshal(string, Name),
|
||||
party => unmarshal(id, PartyID),
|
||||
provider => unmarshal(id, ProviderID),
|
||||
class => unmarshal(id, ClassID),
|
||||
id => unmarshal(id, ID),
|
||||
name => unmarshal(string, Name),
|
||||
party => unmarshal(id, PartyID),
|
||||
provider => unmarshal(id, ProviderID),
|
||||
class => unmarshal(id, ClassID),
|
||||
external_id => maybe_unmarshal(id, ExternalID),
|
||||
metadata => maybe_unmarshal(ctx, Metadata)
|
||||
metadata => maybe_unmarshal(ctx, Metadata)
|
||||
}).
|
||||
|
||||
-spec unmarshal_challenge_params(ff_proto_identity_thrift:'ChallengeParams'()) ->
|
||||
ff_identity_machine:challenge_params().
|
||||
|
||||
unmarshal_challenge_params(#idnt_ChallengeParams{
|
||||
id = ID,
|
||||
cls = ClassID,
|
||||
id = ID,
|
||||
cls = ClassID,
|
||||
proofs = Proofs
|
||||
}) ->
|
||||
genlib_map:compact(#{
|
||||
id => unmarshal(id, ID),
|
||||
class => unmarshal(id, ClassID),
|
||||
id => unmarshal(id, ID),
|
||||
class => unmarshal(id, ClassID),
|
||||
proofs => unmarshal({list, challenge_proofs}, Proofs)
|
||||
}).
|
||||
|
||||
-spec marshal_identity_event({integer(), ff_machine:timestamped_event(ff_identity:event())}) ->
|
||||
ff_proto_identity_thrift:'Event'().
|
||||
|
||||
marshal_identity_event({ID, {ev, Timestamp, Ev}}) ->
|
||||
#idnt_Event{
|
||||
sequence = marshal(event_id, ID),
|
||||
sequence = marshal(event_id, ID),
|
||||
occured_at = marshal(timestamp, Timestamp),
|
||||
change = marshal(change, Ev)
|
||||
change = marshal(change, Ev)
|
||||
}.
|
||||
|
||||
-spec marshal_challenge_state(ff_identity_challenge:challenge_state()) -> ff_proto_identity_thrift:'ChallengeState'().
|
||||
|
||||
marshal_challenge_state(ChallengeState) ->
|
||||
Proofs = ff_identity_challenge:proofs(ChallengeState),
|
||||
Status = ff_identity_challenge:status(ChallengeState),
|
||||
#idnt_ChallengeState{
|
||||
id = ff_identity_challenge:id(ChallengeState),
|
||||
cls = ff_identity_challenge:class(ChallengeState),
|
||||
id = ff_identity_challenge:id(ChallengeState),
|
||||
cls = ff_identity_challenge:class(ChallengeState),
|
||||
proofs = marshal({list, challenge_proofs}, Proofs),
|
||||
status = marshal(challenge_payload_status_changed, Status)
|
||||
}.
|
||||
|
||||
-spec marshal_identity_state(ff_identity:identity_state(), ff_entity_context:context()) ->
|
||||
ff_proto_identity_thrift:'IdentityState'().
|
||||
|
||||
marshal_identity_state(IdentityState, Context) ->
|
||||
EffectiveChallengeID = case ff_identity:effective_challenge(IdentityState) of
|
||||
{ok, ID} -> maybe_marshal(id, ID);
|
||||
{error, notfound} -> undefined
|
||||
end,
|
||||
EffectiveChallengeID =
|
||||
case ff_identity:effective_challenge(IdentityState) of
|
||||
{ok, ID} -> maybe_marshal(id, ID);
|
||||
{error, notfound} -> undefined
|
||||
end,
|
||||
#idnt_IdentityState{
|
||||
id = maybe_marshal(id, ff_identity:id(IdentityState)),
|
||||
name = marshal(string, ff_identity:name(IdentityState)),
|
||||
@ -98,28 +93,25 @@ marshal_identity_state(IdentityState, Context) ->
|
||||
}.
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) -> ff_codec:encoded_value().
|
||||
|
||||
marshal({list, T}, V) ->
|
||||
[marshal(T, E) || E <- V];
|
||||
|
||||
marshal(timestamped_change, {ev, Timestamp, Change}) ->
|
||||
#idnt_TimestampedChange{
|
||||
#idnt_TimestampedChange{
|
||||
change = marshal(change, Change),
|
||||
occured_at = ff_codec:marshal(timestamp, Timestamp)
|
||||
};
|
||||
|
||||
marshal(change, {created, Identity}) ->
|
||||
{created, marshal(identity, Identity)};
|
||||
marshal(change, {level_changed, LevelID}) ->
|
||||
{level_changed, marshal(id, LevelID)};
|
||||
marshal(change, {{challenge, ChallengeID}, ChallengeChange}) ->
|
||||
{identity_challenge, marshal(challenge_change, #{
|
||||
id => ChallengeID,
|
||||
payload => ChallengeChange
|
||||
})};
|
||||
{identity_challenge,
|
||||
marshal(challenge_change, #{
|
||||
id => ChallengeID,
|
||||
payload => ChallengeChange
|
||||
})};
|
||||
marshal(change, {effective_challenge_changed, ChallengeID}) ->
|
||||
{effective_challenge_changed, marshal(id, ChallengeID)};
|
||||
|
||||
marshal(identity, Identity) ->
|
||||
#idnt_Identity{
|
||||
id = maybe_marshal(id, ff_identity:id(Identity)),
|
||||
@ -132,22 +124,24 @@ marshal(identity, Identity) ->
|
||||
external_id = maybe_marshal(id, ff_identity:external_id(Identity)),
|
||||
metadata = maybe_marshal(ctx, ff_identity:metadata(Identity))
|
||||
};
|
||||
|
||||
marshal(challenge_change, #{
|
||||
id := ID,
|
||||
payload := Payload
|
||||
id := ID,
|
||||
payload := Payload
|
||||
}) ->
|
||||
#idnt_ChallengeChange{
|
||||
id = marshal(id, ID),
|
||||
id = marshal(id, ID),
|
||||
payload = marshal(challenge_payload, Payload)
|
||||
};
|
||||
marshal(challenge_payload, {created, Challenge}) ->
|
||||
{created, marshal(challenge_payload_created, Challenge)};
|
||||
marshal(challenge_payload, {status_changed, ChallengeStatus}) ->
|
||||
{status_changed, marshal(challenge_payload_status_changed, ChallengeStatus)};
|
||||
marshal(challenge_payload_created, Challenge = #{
|
||||
id := ID
|
||||
}) ->
|
||||
marshal(
|
||||
challenge_payload_created,
|
||||
Challenge = #{
|
||||
id := ID
|
||||
}
|
||||
) ->
|
||||
Proofs = maps:get(proofs, Challenge, []),
|
||||
#idnt_Challenge{
|
||||
id = marshal(id, ID),
|
||||
@ -155,24 +149,26 @@ marshal(challenge_payload_created, Challenge = #{
|
||||
provider_id = marshal(id, maps:get(provider, Challenge)),
|
||||
class_id = marshal(id, maps:get(identity_class, Challenge)),
|
||||
proofs = marshal({list, challenge_proofs}, Proofs),
|
||||
claim_id = marshal(id, maps:get(claim_id, Challenge)),
|
||||
claimant = marshal(id, maps:get(claimant, Challenge)),
|
||||
master_id = marshal(id, maps:get(master_id, Challenge))
|
||||
claim_id = marshal(id, maps:get(claim_id, Challenge)),
|
||||
claimant = marshal(id, maps:get(claimant, Challenge)),
|
||||
master_id = marshal(id, maps:get(master_id, Challenge))
|
||||
};
|
||||
|
||||
marshal(challenge_proofs, {Type, Token}) ->
|
||||
#idnt_ChallengeProof{
|
||||
type = Type,
|
||||
token = Token
|
||||
};
|
||||
|
||||
marshal(challenge_payload_status_changed, pending) ->
|
||||
{pending, #idnt_ChallengePending{}};
|
||||
marshal(challenge_payload_status_changed, cancelled) ->
|
||||
{cancelled, #idnt_ChallengeCancelled{}};
|
||||
marshal(challenge_payload_status_changed, {completed, Status = #{
|
||||
resolution := Resolution
|
||||
}}) ->
|
||||
marshal(
|
||||
challenge_payload_status_changed,
|
||||
{completed,
|
||||
Status = #{
|
||||
resolution := Resolution
|
||||
}}
|
||||
) ->
|
||||
ValidUntil = maps:get(valid_until, Status, undefined),
|
||||
NewStatus = #idnt_ChallengeCompleted{
|
||||
resolution = marshal(resolution, Resolution),
|
||||
@ -181,39 +177,30 @@ marshal(challenge_payload_status_changed, {completed, Status = #{
|
||||
{completed, NewStatus};
|
||||
marshal(challenge_payload_status_changed, {failed, _Status}) ->
|
||||
{failed, #idnt_ChallengeFailed{}};
|
||||
|
||||
marshal(resolution, approved) ->
|
||||
approved;
|
||||
marshal(resolution, denied) ->
|
||||
denied;
|
||||
|
||||
marshal(ctx, Ctx) ->
|
||||
maybe_marshal(context, Ctx);
|
||||
|
||||
marshal(created_at, TimeMS) ->
|
||||
marshal(string, ff_time:to_rfc3339(TimeMS));
|
||||
|
||||
marshal(T, V) ->
|
||||
ff_codec:marshal(T, V).
|
||||
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) ->
|
||||
ff_codec:decoded_value().
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) -> ff_codec:decoded_value().
|
||||
unmarshal({list, T}, V) ->
|
||||
[unmarshal(T, E) || E <- V];
|
||||
|
||||
unmarshal(timestamped_change, TimestampedChange) ->
|
||||
Timestamp = ff_codec:unmarshal(timestamp, TimestampedChange#idnt_TimestampedChange.occured_at),
|
||||
Change = unmarshal(change, TimestampedChange#idnt_TimestampedChange.change),
|
||||
{ev, Timestamp, Change};
|
||||
|
||||
unmarshal(repair_scenario, {add_events, #idnt_AddEventsRepair{events = Events, action = Action}}) ->
|
||||
{add_events, genlib_map:compact(#{
|
||||
events => unmarshal({list, change}, Events),
|
||||
action => maybe_unmarshal(complex_action, Action)
|
||||
})};
|
||||
|
||||
{add_events,
|
||||
genlib_map:compact(#{
|
||||
events => unmarshal({list, change}, Events),
|
||||
action => maybe_unmarshal(complex_action, Action)
|
||||
})};
|
||||
unmarshal(change, {created, Identity}) ->
|
||||
{created, unmarshal(identity, Identity)};
|
||||
unmarshal(change, {level_changed, LevelID}) ->
|
||||
@ -222,31 +209,29 @@ unmarshal(change, {identity_challenge, #idnt_ChallengeChange{id = ID, payload =
|
||||
{{challenge, unmarshal(id, ID)}, unmarshal(challenge_payload, Payload)};
|
||||
unmarshal(change, {effective_challenge_changed, ChallengeID}) ->
|
||||
{effective_challenge_changed, unmarshal(id, ChallengeID)};
|
||||
|
||||
unmarshal(identity, #idnt_Identity{
|
||||
id = ID,
|
||||
name = Name,
|
||||
party = PartyID,
|
||||
provider = ProviderID,
|
||||
cls = ClassID,
|
||||
contract = ContractID,
|
||||
id = ID,
|
||||
name = Name,
|
||||
party = PartyID,
|
||||
provider = ProviderID,
|
||||
cls = ClassID,
|
||||
contract = ContractID,
|
||||
external_id = ExternalID,
|
||||
created_at = CreatedAt,
|
||||
metadata = Metadata
|
||||
created_at = CreatedAt,
|
||||
metadata = Metadata
|
||||
}) ->
|
||||
genlib_map:compact(#{
|
||||
id => unmarshal(id, ID),
|
||||
name => unmarshal(string, Name),
|
||||
party => unmarshal(id, PartyID),
|
||||
provider => unmarshal(id, ProviderID),
|
||||
class => unmarshal(id, ClassID),
|
||||
contract => unmarshal(id, ContractID),
|
||||
id => unmarshal(id, ID),
|
||||
name => unmarshal(string, Name),
|
||||
party => unmarshal(id, PartyID),
|
||||
provider => unmarshal(id, ProviderID),
|
||||
class => unmarshal(id, ClassID),
|
||||
contract => unmarshal(id, ContractID),
|
||||
external_id => maybe_unmarshal(id, ExternalID),
|
||||
created_at => maybe_unmarshal(created_at, CreatedAt),
|
||||
metadata => maybe_unmarshal(ctx, Metadata),
|
||||
version => 2
|
||||
created_at => maybe_unmarshal(created_at, CreatedAt),
|
||||
metadata => maybe_unmarshal(ctx, Metadata),
|
||||
version => 2
|
||||
});
|
||||
|
||||
unmarshal(challenge_payload, {created, Challenge}) ->
|
||||
{created, unmarshal(challenge_payload_created, Challenge)};
|
||||
unmarshal(challenge_payload, {status_changed, ChallengeStatus}) ->
|
||||
@ -271,29 +256,31 @@ unmarshal(challenge_payload_created, #idnt_Challenge{
|
||||
master_id => unmarshal(id, MasterID),
|
||||
claimant => unmarshal(id, Claimant)
|
||||
};
|
||||
|
||||
unmarshal(challenge_proofs, Proof) -> {
|
||||
unmarshal(challenge_proofs, Proof) ->
|
||||
{
|
||||
unmarshal(proof_type, Proof#idnt_ChallengeProof.type),
|
||||
unmarshal(id, Proof#idnt_ChallengeProof.token)
|
||||
};
|
||||
|
||||
unmarshal(proof_type, rus_domestic_passport) ->
|
||||
rus_domestic_passport;
|
||||
unmarshal(proof_type, rus_retiree_insurance_cert) ->
|
||||
rus_retiree_insurance_cert;
|
||||
|
||||
unmarshal(challenge_payload_status_changed, {pending, #idnt_ChallengePending{}}) ->
|
||||
pending;
|
||||
unmarshal(challenge_payload_status_changed, {cancelled, #idnt_ChallengeCancelled{}}) ->
|
||||
cancelled;
|
||||
unmarshal(challenge_payload_status_changed, {completed, #idnt_ChallengeCompleted{
|
||||
resolution = Resolution,
|
||||
valid_until = ValidUntil
|
||||
}}) ->
|
||||
{completed, genlib_map:compact(#{
|
||||
resolution => unmarshal(resolution, Resolution),
|
||||
valid_until => maybe_unmarshal(timestamp, ValidUntil)
|
||||
})};
|
||||
unmarshal(
|
||||
challenge_payload_status_changed,
|
||||
{completed, #idnt_ChallengeCompleted{
|
||||
resolution = Resolution,
|
||||
valid_until = ValidUntil
|
||||
}}
|
||||
) ->
|
||||
{completed,
|
||||
genlib_map:compact(#{
|
||||
resolution => unmarshal(resolution, Resolution),
|
||||
valid_until => maybe_unmarshal(timestamp, ValidUntil)
|
||||
})};
|
||||
unmarshal(challenge_payload_status_changed, {failed, #idnt_ChallengeFailed{}}) ->
|
||||
% FIXME: Describe failures in protocol
|
||||
{failed, unknown};
|
||||
@ -301,18 +288,14 @@ unmarshal(resolution, approved) ->
|
||||
approved;
|
||||
unmarshal(resolution, denied) ->
|
||||
denied;
|
||||
|
||||
unmarshal(effective_challenge, undefined) ->
|
||||
{error, notfound};
|
||||
unmarshal(effective_challenge, EffectiveChallengeID) ->
|
||||
{ok, unmarshal(id, EffectiveChallengeID)};
|
||||
|
||||
unmarshal(created_at, Timestamp) ->
|
||||
unmarshal(integer, ff_time:from_rfc3339(Timestamp));
|
||||
|
||||
unmarshal(ctx, Ctx) ->
|
||||
maybe_unmarshal(context, Ctx);
|
||||
|
||||
unmarshal(T, V) ->
|
||||
ff_codec:unmarshal(T, V).
|
||||
|
||||
@ -336,16 +319,17 @@ maybe_unmarshal(Type, Value) ->
|
||||
-spec test() -> _.
|
||||
|
||||
-spec identity_test() -> _.
|
||||
|
||||
identity_test() ->
|
||||
IdentityIn = #{
|
||||
id => genlib:unique(),
|
||||
name => genlib:unique(),
|
||||
party => genlib:unique(),
|
||||
provider => genlib:unique(),
|
||||
class => genlib:unique(),
|
||||
contract => genlib:unique(),
|
||||
id => genlib:unique(),
|
||||
name => genlib:unique(),
|
||||
party => genlib:unique(),
|
||||
provider => genlib:unique(),
|
||||
class => genlib:unique(),
|
||||
contract => genlib:unique(),
|
||||
external_id => genlib:unique(),
|
||||
version => 2
|
||||
version => 2
|
||||
},
|
||||
IdentityOut = unmarshal(identity, marshal(identity, IdentityIn)),
|
||||
?assertEqual(IdentityOut, IdentityIn).
|
||||
@ -353,7 +337,7 @@ identity_test() ->
|
||||
-spec challenge_test() -> _.
|
||||
challenge_test() ->
|
||||
ChallengeIn = #{
|
||||
id => genlib:unique(),
|
||||
id => genlib:unique(),
|
||||
proofs => [{rus_retiree_insurance_cert, <<"Bananazzzz">>}],
|
||||
challenge_class => <<"challenge_class">>,
|
||||
claim_id => <<"claim_id">>,
|
||||
|
@ -9,32 +9,28 @@
|
||||
-type event() :: ff_eventsink_publisher:event(ff_identity:event()).
|
||||
-type sinkevent() :: ff_eventsink_publisher:sinkevent(ff_proto_identity_thrift:'SinkEvent'()).
|
||||
|
||||
-spec publish_events(list(event())) ->
|
||||
list(sinkevent()).
|
||||
|
||||
-spec publish_events(list(event())) -> list(sinkevent()).
|
||||
publish_events(Events) ->
|
||||
[publish_event(Event) || Event <- Events].
|
||||
|
||||
-spec publish_event(event()) ->
|
||||
sinkevent().
|
||||
|
||||
-spec publish_event(event()) -> sinkevent().
|
||||
publish_event(#{
|
||||
id := ID,
|
||||
source_id := SourceID,
|
||||
event := {
|
||||
id := ID,
|
||||
source_id := SourceID,
|
||||
event := {
|
||||
EventID,
|
||||
Dt,
|
||||
{ev, EventDt, Payload}
|
||||
}
|
||||
}) ->
|
||||
#idnt_SinkEvent{
|
||||
id = marshal(event_id, ID),
|
||||
created_at = marshal(timestamp, Dt),
|
||||
source = marshal(id, SourceID),
|
||||
payload = #idnt_EventSinkPayload{
|
||||
sequence = marshal(event_id, EventID),
|
||||
id = marshal(event_id, ID),
|
||||
created_at = marshal(timestamp, Dt),
|
||||
source = marshal(id, SourceID),
|
||||
payload = #idnt_EventSinkPayload{
|
||||
sequence = marshal(event_id, EventID),
|
||||
occured_at = marshal(timestamp, EventDt),
|
||||
changes = [marshal(change, Payload)]
|
||||
changes = [marshal(change, Payload)]
|
||||
}
|
||||
}.
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
-module(ff_identity_handler).
|
||||
|
||||
-behaviour(ff_woody_wrapper).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_identity_thrift.hrl").
|
||||
@ -9,11 +10,12 @@
|
||||
%%
|
||||
%% ff_woody_wrapper callbacks
|
||||
%%
|
||||
-spec handle_function(woody:func(), woody:args(), woody:options()) ->
|
||||
{ok, woody:result()} | no_return().
|
||||
-spec handle_function(woody:func(), woody:args(), woody:options()) -> {ok, woody:result()} | no_return().
|
||||
handle_function(Func, Args, Opts) ->
|
||||
[IdentityID| _ ] = Args,
|
||||
scoper:scope(identity, #{identity_id => IdentityID},
|
||||
[IdentityID | _] = Args,
|
||||
scoper:scope(
|
||||
identity,
|
||||
#{identity_id => IdentityID},
|
||||
fun() ->
|
||||
handle_function_(Func, Args, Opts)
|
||||
end
|
||||
@ -45,7 +47,7 @@ handle_function_('Get', [ID, EventRange], _Opts) ->
|
||||
case ff_identity_machine:get(ID, ff_codec:unmarshal(event_range, EventRange)) of
|
||||
{ok, Machine} ->
|
||||
Identity = ff_identity:set_blocking(ff_identity_machine:identity(Machine)),
|
||||
Context = ff_identity_machine:ctx(Machine),
|
||||
Context = ff_identity_machine:ctx(Machine),
|
||||
Response = ff_identity_codec:marshal_identity_state(Identity, Context),
|
||||
{ok, Response};
|
||||
{error, notfound} ->
|
||||
@ -66,8 +68,8 @@ handle_function_('StartChallenge', [IdentityID, Params], _Opts) ->
|
||||
case ff_identity_machine:start_challenge(IdentityID, ChallengeParams) of
|
||||
ok ->
|
||||
ChallengeID = maps:get(id, ChallengeParams),
|
||||
{ok, Machine} = ff_identity_machine:get(IdentityID),
|
||||
Identity = ff_identity_machine:identity(Machine),
|
||||
{ok, Machine} = ff_identity_machine:get(IdentityID),
|
||||
Identity = ff_identity_machine:identity(Machine),
|
||||
{ok, Challenge} = ff_identity:challenge(ChallengeID, Identity),
|
||||
{ok, ff_identity_codec:marshal_challenge_state(Challenge)};
|
||||
{error, notfound} ->
|
||||
@ -96,7 +98,6 @@ handle_function_('GetChallenges', [ID], _Opts) ->
|
||||
{error, notfound} ->
|
||||
woody_error:raise(business, #fistful_IdentityNotFound{})
|
||||
end;
|
||||
|
||||
handle_function_('GetEvents', [IdentityID, EventRange], _Opts) ->
|
||||
case ff_identity_machine:events(IdentityID, ff_codec:unmarshal(event_range, EventRange)) of
|
||||
{ok, EventList} ->
|
||||
|
@ -20,7 +20,7 @@
|
||||
-type value(T) :: machinery_mg_schema:v(T).
|
||||
-type value_type() :: machinery_mg_schema:vt().
|
||||
|
||||
-type event() :: ff_machine:timestamped_event(ff_identity:event()).
|
||||
-type event() :: ff_machine:timestamped_event(ff_identity:event()).
|
||||
-type aux_state() :: ff_machine:auxst().
|
||||
-type call_args() :: term().
|
||||
-type call_response() :: term().
|
||||
@ -32,71 +32,61 @@
|
||||
-type thrift_change() :: ff_proto_identity_thrift:'Change'().
|
||||
|
||||
-type data() ::
|
||||
aux_state() |
|
||||
event() |
|
||||
call_args() |
|
||||
call_response().
|
||||
aux_state()
|
||||
| event()
|
||||
| call_args()
|
||||
| call_response().
|
||||
|
||||
%% machinery_mg_schema callbacks
|
||||
|
||||
-spec get_version(value_type()) ->
|
||||
machinery_mg_schema:version().
|
||||
-spec get_version(value_type()) -> machinery_mg_schema:version().
|
||||
get_version(event) ->
|
||||
?CURRENT_EVENT_FORMAT_VERSION;
|
||||
get_version(aux_state) ->
|
||||
undefined.
|
||||
|
||||
-spec marshal(type(), value(data()), context()) ->
|
||||
{machinery_msgpack:t(), context()}.
|
||||
-spec marshal(type(), value(data()), context()) -> {machinery_msgpack:t(), context()}.
|
||||
marshal({event, Format}, TimestampedChange, Context) ->
|
||||
marshal_event(Format, TimestampedChange, Context);
|
||||
marshal(T, V, C) when
|
||||
T =:= {args, init} orelse
|
||||
T =:= {args, call} orelse
|
||||
T =:= {args, repair} orelse
|
||||
T =:= {aux_state, undefined} orelse
|
||||
T =:= {response, call} orelse
|
||||
T =:= {response, {repair, success}} orelse
|
||||
T =:= {response, {repair, failure}}
|
||||
T =:= {args, call} orelse
|
||||
T =:= {args, repair} orelse
|
||||
T =:= {aux_state, undefined} orelse
|
||||
T =:= {response, call} orelse
|
||||
T =:= {response, {repair, success}} orelse
|
||||
T =:= {response, {repair, failure}}
|
||||
->
|
||||
machinery_mg_schema_generic:marshal(T, V, C).
|
||||
|
||||
-spec unmarshal(type(), machinery_msgpack:t(), context()) ->
|
||||
{data(), context()}.
|
||||
-spec unmarshal(type(), machinery_msgpack:t(), context()) -> {data(), context()}.
|
||||
unmarshal({event, FormatVersion}, EncodedChange, Context) ->
|
||||
unmarshal_event(FormatVersion, EncodedChange, Context);
|
||||
|
||||
unmarshal({aux_state, undefined} = T, V, C0) ->
|
||||
{AuxState, C1} = machinery_mg_schema_generic:unmarshal(T, V, C0),
|
||||
{AuxState, C1#{ctx => get_aux_state_ctx(AuxState)}};
|
||||
|
||||
unmarshal(T, V, C) when
|
||||
T =:= {args, init} orelse
|
||||
T =:= {args, call} orelse
|
||||
T =:= {args, repair} orelse
|
||||
T =:= {response, call} orelse
|
||||
T =:= {response, {repair, success}} orelse
|
||||
T =:= {response, {repair, failure}}
|
||||
T =:= {args, call} orelse
|
||||
T =:= {args, repair} orelse
|
||||
T =:= {response, call} orelse
|
||||
T =:= {response, {repair, success}} orelse
|
||||
T =:= {response, {repair, failure}}
|
||||
->
|
||||
machinery_mg_schema_generic:unmarshal(T, V, C).
|
||||
|
||||
%% Internals
|
||||
|
||||
-spec marshal_event(machinery_mg_schema:version(), event(), context()) ->
|
||||
{machinery_msgpack:t(), context()}.
|
||||
-spec marshal_event(machinery_mg_schema:version(), event(), context()) -> {machinery_msgpack:t(), context()}.
|
||||
marshal_event(undefined = Version, TimestampedChange, Context) ->
|
||||
% TODO: Remove this clause after MSPF-561 finish
|
||||
machinery_mg_schema_generic:marshal({event, Version}, TimestampedChange, Context);
|
||||
marshal_event(Version, TimestampedChange, Context) when
|
||||
Version =:= 1;
|
||||
Version =:= 2
|
||||
->
|
||||
marshal_event(Version, TimestampedChange, Context) when Version =:= 1; Version =:= 2 ->
|
||||
ThriftChange = ff_identity_codec:marshal(timestamped_change, TimestampedChange),
|
||||
Type = {struct, struct, {ff_proto_identity_thrift, 'TimestampedChange'}},
|
||||
{{bin, ff_proto_utils:serialize(Type, ThriftChange)}, Context}.
|
||||
|
||||
-spec unmarshal_event(machinery_mg_schema:version(), machinery_msgpack:t(), context()) ->
|
||||
{event(), context()}.
|
||||
-spec unmarshal_event(machinery_mg_schema:version(), machinery_msgpack:t(), context()) -> {event(), context()}.
|
||||
unmarshal_event(2, EncodedChange, Context) ->
|
||||
ThriftChange = unmashal_thrift_change(EncodedChange),
|
||||
{ff_identity_codec:unmarshal(timestamped_change, ThriftChange), Context};
|
||||
@ -114,49 +104,57 @@ unmarshal_event(undefined = Version, EncodedChange, Context) ->
|
||||
),
|
||||
{{ev, Timestamp, maybe_migrate_change(Change, Context1)}, Context1}.
|
||||
|
||||
-spec unmashal_thrift_change(machinery_msgpack:t()) ->
|
||||
timestamped_change().
|
||||
|
||||
-spec unmashal_thrift_change(machinery_msgpack:t()) -> timestamped_change().
|
||||
unmashal_thrift_change(EncodedChange) ->
|
||||
{bin, EncodedThriftChange} = EncodedChange,
|
||||
Type = {struct, struct, {ff_proto_identity_thrift, 'TimestampedChange'}},
|
||||
ff_proto_utils:deserialize(Type, EncodedThriftChange).
|
||||
|
||||
-spec maybe_migrate_thrift_change(thrift_change(), context()) ->
|
||||
thrift_change().
|
||||
|
||||
-spec maybe_migrate_thrift_change(thrift_change(), context()) -> thrift_change().
|
||||
maybe_migrate_thrift_change({created, #idnt_Identity{name = undefined} = Identity}, MigrateContext) ->
|
||||
Context = fetch_entity_context(Identity#idnt_Identity.id, MigrateContext),
|
||||
{created, Identity#idnt_Identity{name = get_legacy_name(Context)}};
|
||||
maybe_migrate_thrift_change(Change, _MigrateContext) ->
|
||||
Change.
|
||||
|
||||
-spec maybe_migrate_change(legacy_change(), context()) ->
|
||||
ff_identity:event().
|
||||
|
||||
-spec maybe_migrate_change(legacy_change(), context()) -> ff_identity:event().
|
||||
maybe_migrate_change(Event = {created, #{version := 2, name := _}}, _MigrateContext) ->
|
||||
Event;
|
||||
maybe_migrate_change({created, Identity = #{version := 2, id := ID}}, MigrateContext) ->
|
||||
Context = fetch_entity_context(ID, MigrateContext),
|
||||
maybe_migrate_change({created, genlib_map:compact(Identity#{
|
||||
name => get_legacy_name(Context)
|
||||
})}, MigrateContext);
|
||||
maybe_migrate_change(
|
||||
{created,
|
||||
genlib_map:compact(Identity#{
|
||||
name => get_legacy_name(Context)
|
||||
})},
|
||||
MigrateContext
|
||||
);
|
||||
maybe_migrate_change({created, Identity = #{version := 1, id := ID}}, MigrateContext) ->
|
||||
Context = fetch_entity_context(ID, MigrateContext),
|
||||
maybe_migrate_change({created, genlib_map:compact(Identity#{
|
||||
version => 2,
|
||||
metadata => ff_entity_context:try_get_legacy_metadata(Context)
|
||||
})}, MigrateContext);
|
||||
maybe_migrate_change(
|
||||
{created,
|
||||
genlib_map:compact(Identity#{
|
||||
version => 2,
|
||||
metadata => ff_entity_context:try_get_legacy_metadata(Context)
|
||||
})},
|
||||
MigrateContext
|
||||
);
|
||||
maybe_migrate_change({created, Identity = #{created_at := _CreatedAt}}, MigrateContext) ->
|
||||
maybe_migrate_change({created, Identity#{
|
||||
version => 1
|
||||
}}, MigrateContext);
|
||||
maybe_migrate_change(
|
||||
{created, Identity#{
|
||||
version => 1
|
||||
}},
|
||||
MigrateContext
|
||||
);
|
||||
maybe_migrate_change({created, Identity}, MigrateContext) ->
|
||||
Timestamp = maps:get(created_at, MigrateContext),
|
||||
CreatedAt = ff_codec:unmarshal(timestamp_ms, ff_codec:marshal(timestamp, Timestamp)),
|
||||
maybe_migrate_change({created, Identity#{
|
||||
created_at => CreatedAt
|
||||
}}, MigrateContext);
|
||||
maybe_migrate_change(
|
||||
{created, Identity#{
|
||||
created_at => CreatedAt
|
||||
}},
|
||||
MigrateContext
|
||||
);
|
||||
maybe_migrate_change(Ev, _MigrateContext) ->
|
||||
Ev.
|
||||
|
||||
@ -179,18 +177,18 @@ get_legacy_name(#{<<"com.rbkmoney.wapi">> := #{<<"name">> := Name}}) ->
|
||||
|
||||
-ifdef(TEST).
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
-spec test() -> _.
|
||||
|
||||
% tests helpers
|
||||
|
||||
-spec marshal(type(), value(data())) ->
|
||||
machinery_msgpack:t().
|
||||
-spec marshal(type(), value(data())) -> machinery_msgpack:t().
|
||||
|
||||
marshal(Type, Value) ->
|
||||
{Result, _Context} = marshal(Type, Value, #{}),
|
||||
Result.
|
||||
|
||||
-spec unmarshal(type(), machinery_msgpack:t()) ->
|
||||
data().
|
||||
-spec unmarshal(type(), machinery_msgpack:t()) -> data().
|
||||
unmarshal(Type, Value) ->
|
||||
{Result, _Context} = unmarshal(Type, Value, #{}),
|
||||
Result.
|
||||
@ -211,42 +209,45 @@ created_v0_decoding_test() ->
|
||||
Change = {created, Identity},
|
||||
Event = {ev, {{{2020, 5, 25}, {19, 19, 10}}, 293305}, Change},
|
||||
|
||||
LegacyChange = {arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"created">>},
|
||||
{arr, [
|
||||
{str, <<"map">>},
|
||||
{obj, #{
|
||||
{str, <<"class">>} => {bin, <<"class">>},
|
||||
{str, <<"contract">>} => {bin, <<"ContractID">>},
|
||||
{str, <<"created_at">>} => {i, 1592576943762},
|
||||
{str, <<"id">>} => {bin, <<"ID">>},
|
||||
{str, <<"party">>} => {bin, <<"PartyID">>},
|
||||
{str, <<"provider">>} => {bin, <<"good-one">>},
|
||||
{str, <<"version">>} => {i, 2},
|
||||
{str, <<"metadata">>} => {arr, [
|
||||
{str, <<"map">>},
|
||||
{obj, #{
|
||||
{bin, <<"some key">>} => {bin, <<"some val">>}
|
||||
}}
|
||||
]}
|
||||
}}
|
||||
]}
|
||||
]},
|
||||
LegacyEvent = {arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"ev">>},
|
||||
LegacyChange =
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"created">>},
|
||||
{arr, [
|
||||
{str, <<"map">>},
|
||||
{obj, #{
|
||||
{str, <<"class">>} => {bin, <<"class">>},
|
||||
{str, <<"contract">>} => {bin, <<"ContractID">>},
|
||||
{str, <<"created_at">>} => {i, 1592576943762},
|
||||
{str, <<"id">>} => {bin, <<"ID">>},
|
||||
{str, <<"party">>} => {bin, <<"PartyID">>},
|
||||
{str, <<"provider">>} => {bin, <<"good-one">>},
|
||||
{str, <<"version">>} => {i, 2},
|
||||
{str, <<"metadata">>} =>
|
||||
{arr, [
|
||||
{str, <<"map">>},
|
||||
{obj, #{
|
||||
{bin, <<"some key">>} => {bin, <<"some val">>}
|
||||
}}
|
||||
]}
|
||||
}}
|
||||
]}
|
||||
]},
|
||||
LegacyEvent =
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"ev">>},
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{arr, [{str, <<"tup">>}, {i, 2020}, {i, 5}, {i, 25}]},
|
||||
{arr, [{str, <<"tup">>}, {i, 19}, {i, 19}, {i, 10}]}
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{arr, [{str, <<"tup">>}, {i, 2020}, {i, 5}, {i, 25}]},
|
||||
{arr, [{str, <<"tup">>}, {i, 19}, {i, 19}, {i, 10}]}
|
||||
]},
|
||||
{i, 293305}
|
||||
]},
|
||||
{i, 293305}
|
||||
LegacyChange
|
||||
]},
|
||||
LegacyChange
|
||||
]},
|
||||
|
||||
{DecodedLegacy, _} = unmarshal({event, undefined}, LegacyEvent, #{
|
||||
ctx => #{<<"com.rbkmoney.wapi">> => #{<<"name">> => <<"Name">>}}
|
||||
@ -262,25 +263,27 @@ level_changed_v0_decoding_test() ->
|
||||
Change = {level_changed, <<"level_changed">>},
|
||||
Event = {ev, {{{2020, 5, 25}, {19, 19, 10}}, 293305}, Change},
|
||||
|
||||
LegacyChange = {arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"level_changed">>},
|
||||
{bin, <<"level_changed">>}
|
||||
]},
|
||||
LegacyEvent = {arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"ev">>},
|
||||
LegacyChange =
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"level_changed">>},
|
||||
{bin, <<"level_changed">>}
|
||||
]},
|
||||
LegacyEvent =
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"ev">>},
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{arr, [{str, <<"tup">>}, {i, 2020}, {i, 5}, {i, 25}]},
|
||||
{arr, [{str, <<"tup">>}, {i, 19}, {i, 19}, {i, 10}]}
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{arr, [{str, <<"tup">>}, {i, 2020}, {i, 5}, {i, 25}]},
|
||||
{arr, [{str, <<"tup">>}, {i, 19}, {i, 19}, {i, 10}]}
|
||||
]},
|
||||
{i, 293305}
|
||||
]},
|
||||
{i, 293305}
|
||||
LegacyChange
|
||||
]},
|
||||
LegacyChange
|
||||
]},
|
||||
|
||||
{DecodedLegacy, _} = unmarshal({event, undefined}, LegacyEvent, #{}),
|
||||
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
|
||||
@ -292,25 +295,27 @@ effective_challenge_changed_v0_decoding_test() ->
|
||||
Change = {effective_challenge_changed, <<"effective_challenge_changed">>},
|
||||
Event = {ev, {{{2020, 5, 25}, {19, 19, 10}}, 293305}, Change},
|
||||
|
||||
LegacyChange = {arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"effective_challenge_changed">>},
|
||||
{bin, <<"effective_challenge_changed">>}
|
||||
]},
|
||||
LegacyEvent = {arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"ev">>},
|
||||
LegacyChange =
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"effective_challenge_changed">>},
|
||||
{bin, <<"effective_challenge_changed">>}
|
||||
]},
|
||||
LegacyEvent =
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"ev">>},
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{arr, [{str, <<"tup">>}, {i, 2020}, {i, 5}, {i, 25}]},
|
||||
{arr, [{str, <<"tup">>}, {i, 19}, {i, 19}, {i, 10}]}
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{arr, [{str, <<"tup">>}, {i, 2020}, {i, 5}, {i, 25}]},
|
||||
{arr, [{str, <<"tup">>}, {i, 19}, {i, 19}, {i, 10}]}
|
||||
]},
|
||||
{i, 293305}
|
||||
]},
|
||||
{i, 293305}
|
||||
LegacyChange
|
||||
]},
|
||||
LegacyChange
|
||||
]},
|
||||
|
||||
{DecodedLegacy, _} = unmarshal({event, undefined}, LegacyEvent, #{}),
|
||||
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
|
||||
@ -319,64 +324,69 @@ effective_challenge_changed_v0_decoding_test() ->
|
||||
|
||||
-spec challenge_created_v0_decoding_test() -> _.
|
||||
challenge_created_v0_decoding_test() ->
|
||||
Change = {{challenge, <<"challengeID">>}, {created, #{
|
||||
id => <<"id">>,
|
||||
claimant => <<"claimant">>,
|
||||
provider => <<"provider">>,
|
||||
identity_class => <<"identity_class">>,
|
||||
challenge_class => <<"challenge_class">>,
|
||||
proofs => [{rus_domestic_passport, <<"identdoc_token">>}],
|
||||
master_id => <<"master_id">>,
|
||||
claim_id => <<"claim_id">>
|
||||
}}},
|
||||
Change =
|
||||
{{challenge, <<"challengeID">>},
|
||||
{created, #{
|
||||
id => <<"id">>,
|
||||
claimant => <<"claimant">>,
|
||||
provider => <<"provider">>,
|
||||
identity_class => <<"identity_class">>,
|
||||
challenge_class => <<"challenge_class">>,
|
||||
proofs => [{rus_domestic_passport, <<"identdoc_token">>}],
|
||||
master_id => <<"master_id">>,
|
||||
claim_id => <<"claim_id">>
|
||||
}}},
|
||||
Event = {ev, {{{2020, 5, 25}, {19, 19, 10}}, 293305}, Change},
|
||||
|
||||
LegacyChange = {arr, [
|
||||
{str, <<"tup">>},
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"challenge">>},
|
||||
{bin, <<"challengeID">>}
|
||||
]},
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"created">>},
|
||||
{arr, [
|
||||
{str, <<"map">>},
|
||||
{obj, #{
|
||||
{str, <<"id">>} => {bin, <<"id">>},
|
||||
{str, <<"claimant">>} => {bin, <<"claimant">>},
|
||||
{str, <<"provider">>} => {bin, <<"provider">>},
|
||||
{str, <<"identity_class">>} => {bin, <<"identity_class">>},
|
||||
{str, <<"challenge_class">>} => {bin, <<"challenge_class">>},
|
||||
{str, <<"master_id">>} => {bin, <<"master_id">>},
|
||||
{str, <<"claim_id">>} => {bin, <<"claim_id">>},
|
||||
{str, <<"proofs">>} => {arr, [
|
||||
{str, <<"lst">>},
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"rus_domestic_passport">>},
|
||||
{bin, <<"identdoc_token">>}
|
||||
]}
|
||||
]}
|
||||
}}
|
||||
]}
|
||||
]}
|
||||
]},
|
||||
LegacyEvent = {arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"ev">>},
|
||||
LegacyChange =
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{arr, [{str, <<"tup">>}, {i, 2020}, {i, 5}, {i, 25}]},
|
||||
{arr, [{str, <<"tup">>}, {i, 19}, {i, 19}, {i, 10}]}
|
||||
{str, <<"challenge">>},
|
||||
{bin, <<"challengeID">>}
|
||||
]},
|
||||
{i, 293305}
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"created">>},
|
||||
{arr, [
|
||||
{str, <<"map">>},
|
||||
{obj, #{
|
||||
{str, <<"id">>} => {bin, <<"id">>},
|
||||
{str, <<"claimant">>} => {bin, <<"claimant">>},
|
||||
{str, <<"provider">>} => {bin, <<"provider">>},
|
||||
{str, <<"identity_class">>} => {bin, <<"identity_class">>},
|
||||
{str, <<"challenge_class">>} => {bin, <<"challenge_class">>},
|
||||
{str, <<"master_id">>} => {bin, <<"master_id">>},
|
||||
{str, <<"claim_id">>} => {bin, <<"claim_id">>},
|
||||
{str, <<"proofs">>} =>
|
||||
{arr, [
|
||||
{str, <<"lst">>},
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"rus_domestic_passport">>},
|
||||
{bin, <<"identdoc_token">>}
|
||||
]}
|
||||
]}
|
||||
}}
|
||||
]}
|
||||
]}
|
||||
]},
|
||||
LegacyEvent =
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"ev">>},
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{arr, [{str, <<"tup">>}, {i, 2020}, {i, 5}, {i, 25}]},
|
||||
{arr, [{str, <<"tup">>}, {i, 19}, {i, 19}, {i, 10}]}
|
||||
]},
|
||||
{i, 293305}
|
||||
]},
|
||||
LegacyChange
|
||||
]},
|
||||
LegacyChange
|
||||
]},
|
||||
|
||||
{DecodedLegacy, _} = unmarshal({event, undefined}, LegacyEvent, #{}),
|
||||
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
|
||||
@ -388,33 +398,35 @@ challenge_status_changed_v0_decoding_test() ->
|
||||
Change = {{challenge, <<"challengeID">>}, {status_changed, pending}},
|
||||
Event = {ev, {{{2020, 5, 25}, {19, 19, 10}}, 293305}, Change},
|
||||
|
||||
LegacyChange = {arr, [
|
||||
{str, <<"tup">>},
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"challenge">>},
|
||||
{bin, <<"challengeID">>}
|
||||
]},
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"status_changed">>},
|
||||
{str, <<"pending">>}
|
||||
]}
|
||||
]},
|
||||
LegacyEvent = {arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"ev">>},
|
||||
LegacyChange =
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{arr, [{str, <<"tup">>}, {i, 2020}, {i, 5}, {i, 25}]},
|
||||
{arr, [{str, <<"tup">>}, {i, 19}, {i, 19}, {i, 10}]}
|
||||
{str, <<"challenge">>},
|
||||
{bin, <<"challengeID">>}
|
||||
]},
|
||||
{i, 293305}
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"status_changed">>},
|
||||
{str, <<"pending">>}
|
||||
]}
|
||||
]},
|
||||
LegacyEvent =
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"ev">>},
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{arr, [{str, <<"tup">>}, {i, 2020}, {i, 5}, {i, 25}]},
|
||||
{arr, [{str, <<"tup">>}, {i, 19}, {i, 19}, {i, 10}]}
|
||||
]},
|
||||
{i, 293305}
|
||||
]},
|
||||
LegacyChange
|
||||
]},
|
||||
LegacyChange
|
||||
]},
|
||||
|
||||
{DecodedLegacy, _} = unmarshal({event, undefined}, LegacyEvent, #{}),
|
||||
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
|
||||
@ -436,11 +448,13 @@ created_v1_decoding_test() ->
|
||||
},
|
||||
Change = {created, Identity},
|
||||
Event = {ev, {{{2020, 5, 25}, {19, 19, 10}}, 293305}, Change},
|
||||
LegacyEvent = {bin, base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgwAAQsABgAAAAJJRAsAAQAAAAd"
|
||||
"QYXJ0eUlECwACAAAACGdvb2Qtb25lCwADAAAABWNsYXNzCwAEAAAACkNvbnRyYWN0SUQLAAoAAA"
|
||||
"AYMjAyMC0wNi0xOVQxNDoyOTowMy43NjJaDQALCwwAAAABAAAACHNvbWUga2V5CwAFAAAACHNvbWUgdmFsAAAAAA=="
|
||||
>>)},
|
||||
LegacyEvent =
|
||||
{bin,
|
||||
base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgwAAQsABgAAAAJJRAsAAQAAAAd"
|
||||
"QYXJ0eUlECwACAAAACGdvb2Qtb25lCwADAAAABWNsYXNzCwAEAAAACkNvbnRyYWN0SUQLAAoAAA"
|
||||
"AYMjAyMC0wNi0xOVQxNDoyOTowMy43NjJaDQALCwwAAAABAAAACHNvbWUga2V5CwAFAAAACHNvbWUgdmFsAAAAAA=="
|
||||
>>)},
|
||||
{DecodedLegacy, _} = unmarshal({event, 1}, LegacyEvent, #{
|
||||
ctx => #{<<"com.rbkmoney.wapi">> => #{<<"name">> => <<"Name">>}}
|
||||
}),
|
||||
@ -454,9 +468,11 @@ created_v1_decoding_test() ->
|
||||
level_changed_v1_decoding_test() ->
|
||||
Change = {level_changed, <<"level_changed">>},
|
||||
Event = {ev, {{{2020, 5, 25}, {19, 19, 10}}, 293305}, Change},
|
||||
LegacyEvent = {bin, base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgsAAgAAAA1sZXZlbF9jaGFuZ2VkAAA="
|
||||
>>)},
|
||||
LegacyEvent =
|
||||
{bin,
|
||||
base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgsAAgAAAA1sZXZlbF9jaGFuZ2VkAAA="
|
||||
>>)},
|
||||
DecodedLegacy = unmarshal({event, 1}, LegacyEvent),
|
||||
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
|
||||
Decoded = unmarshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, ModernizedBinary),
|
||||
@ -466,9 +482,11 @@ level_changed_v1_decoding_test() ->
|
||||
effective_challenge_changed_v1_decoding_test() ->
|
||||
Change = {effective_challenge_changed, <<"effective_challenge_changed">>},
|
||||
Event = {ev, {{{2020, 5, 25}, {19, 19, 10}}, 293305}, Change},
|
||||
LegacyEvent = {bin, base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgsABAAAABtlZmZlY3RpdmVfY2hhbGxlbmdlX2NoYW5nZWQAAA=="
|
||||
>>)},
|
||||
LegacyEvent =
|
||||
{bin,
|
||||
base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgsABAAAABtlZmZlY3RpdmVfY2hhbGxlbmdlX2NoYW5nZWQAAA=="
|
||||
>>)},
|
||||
DecodedLegacy = unmarshal({event, 1}, LegacyEvent),
|
||||
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
|
||||
Decoded = unmarshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, ModernizedBinary),
|
||||
@ -476,23 +494,27 @@ effective_challenge_changed_v1_decoding_test() ->
|
||||
|
||||
-spec challenge_created_v1_decoding_test() -> _.
|
||||
challenge_created_v1_decoding_test() ->
|
||||
Change = {{challenge, <<"challengeID">>}, {created, #{
|
||||
id => <<"id">>,
|
||||
claimant => <<"claimant">>,
|
||||
provider => <<"provider">>,
|
||||
identity_class => <<"identity_class">>,
|
||||
challenge_class => <<"challenge_class">>,
|
||||
proofs => [{rus_domestic_passport, <<"identdoc_token">>}],
|
||||
master_id => <<"master_id">>,
|
||||
claim_id => <<"claim_id">>
|
||||
}}},
|
||||
Change =
|
||||
{{challenge, <<"challengeID">>},
|
||||
{created, #{
|
||||
id => <<"id">>,
|
||||
claimant => <<"claimant">>,
|
||||
provider => <<"provider">>,
|
||||
identity_class => <<"identity_class">>,
|
||||
challenge_class => <<"challenge_class">>,
|
||||
proofs => [{rus_domestic_passport, <<"identdoc_token">>}],
|
||||
master_id => <<"master_id">>,
|
||||
claim_id => <<"claim_id">>
|
||||
}}},
|
||||
Event = {ev, {{{2020, 5, 25}, {19, 19, 10}}, 293305}, Change},
|
||||
LegacyEvent = {bin, base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgwAAwsAAQAAAAtjaGFsbGVuZ2VJRA"
|
||||
"wAAgwAAQsAAwAAAAJpZAsAAQAAAA9jaGFsbGVuZ2VfY2xhc3MPAAIMAAAAAQgAAQAAAAALAAIAAAAO"
|
||||
"aWRlbnRkb2NfdG9rZW4ACwAFAAAACHByb3ZpZGVyCwAGAAAADmlkZW50aXR5X2NsYXNzCwAHAAAACG"
|
||||
"NsYWltX2lkCwAIAAAACW1hc3Rlcl9pZAsACQAAAAhjbGFpbWFudAAAAAAA"
|
||||
>>)},
|
||||
LegacyEvent =
|
||||
{bin,
|
||||
base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgwAAwsAAQAAAAtjaGFsbGVuZ2VJRA"
|
||||
"wAAgwAAQsAAwAAAAJpZAsAAQAAAA9jaGFsbGVuZ2VfY2xhc3MPAAIMAAAAAQgAAQAAAAALAAIAAAAO"
|
||||
"aWRlbnRkb2NfdG9rZW4ACwAFAAAACHByb3ZpZGVyCwAGAAAADmlkZW50aXR5X2NsYXNzCwAHAAAACG"
|
||||
"NsYWltX2lkCwAIAAAACW1hc3Rlcl9pZAsACQAAAAhjbGFpbWFudAAAAAAA"
|
||||
>>)},
|
||||
DecodedLegacy = unmarshal({event, 1}, LegacyEvent),
|
||||
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
|
||||
Decoded = unmarshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, ModernizedBinary),
|
||||
@ -502,9 +524,11 @@ challenge_created_v1_decoding_test() ->
|
||||
challenge_status_changed_v1_decoding_test() ->
|
||||
Change = {{challenge, <<"challengeID">>}, {status_changed, pending}},
|
||||
Event = {ev, {{{2020, 5, 25}, {19, 19, 10}}, 293305}, Change},
|
||||
LegacyEvent = {bin, base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgwAAwsAAQAAAAtjaGFsbGVuZ2VJRAwAAgwAAgwAAQAAAAAAAA=="
|
||||
>>)},
|
||||
LegacyEvent =
|
||||
{bin,
|
||||
base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgwAAwsAAQAAAAtjaGFsbGVuZ2VJRAwAAgwAAgwAAQAAAAAAAA=="
|
||||
>>)},
|
||||
DecodedLegacy = unmarshal({event, 1}, LegacyEvent),
|
||||
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
|
||||
Decoded = unmarshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, ModernizedBinary),
|
||||
@ -525,12 +549,14 @@ created_v2_decoding_test() ->
|
||||
},
|
||||
Change = {created, Identity},
|
||||
Event = {ev, {{{2020, 5, 25}, {19, 19, 10}}, 293305}, Change},
|
||||
LegacyEvent = {bin, base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgwAAQsABgAAAAJJRAsADAAAAAROYW1lC"
|
||||
"wABAAAAB1BhcnR5SUQLAAIAAAAIZ29vZC1vbmULAAMAAAAFY2xhc3MLAAQAAAAKQ29udHJhY3RJRAsACg"
|
||||
"AAABgyMDIwLTA2LTE5VDE0OjI5OjAzLjc2MloNAAsLDAAAAAEAAAAIc29tZSBrZXkLAAUAAAAIc29tZSB2"
|
||||
"YWwAAAAA"
|
||||
>>)},
|
||||
LegacyEvent =
|
||||
{bin,
|
||||
base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgwAAQsABgAAAAJJRAsADAAAAAROYW1lC"
|
||||
"wABAAAAB1BhcnR5SUQLAAIAAAAIZ29vZC1vbmULAAMAAAAFY2xhc3MLAAQAAAAKQ29udHJhY3RJRAsACg"
|
||||
"AAABgyMDIwLTA2LTE5VDE0OjI5OjAzLjc2MloNAAsLDAAAAAEAAAAIc29tZSBrZXkLAAUAAAAIc29tZSB2"
|
||||
"YWwAAAAA"
|
||||
>>)},
|
||||
DecodedLegacy = unmarshal({event, 2}, LegacyEvent),
|
||||
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
|
||||
Decoded = unmarshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, ModernizedBinary),
|
||||
@ -540,9 +566,11 @@ created_v2_decoding_test() ->
|
||||
level_changed_v2_decoding_test() ->
|
||||
Change = {level_changed, <<"level_changed">>},
|
||||
Event = {ev, {{{2020, 5, 25}, {19, 19, 10}}, 293305}, Change},
|
||||
LegacyEvent = {bin, base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgsAAgAAAA1sZXZlbF9jaGFuZ2VkAAA="
|
||||
>>)},
|
||||
LegacyEvent =
|
||||
{bin,
|
||||
base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgsAAgAAAA1sZXZlbF9jaGFuZ2VkAAA="
|
||||
>>)},
|
||||
DecodedLegacy = unmarshal({event, 2}, LegacyEvent),
|
||||
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
|
||||
Decoded = unmarshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, ModernizedBinary),
|
||||
@ -552,9 +580,11 @@ level_changed_v2_decoding_test() ->
|
||||
effective_challenge_changed_v2_decoding_test() ->
|
||||
Change = {effective_challenge_changed, <<"effective_challenge_changed">>},
|
||||
Event = {ev, {{{2020, 5, 25}, {19, 19, 10}}, 293305}, Change},
|
||||
LegacyEvent = {bin, base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgsABAAAABtlZmZlY3RpdmVfY2hhbGxlbmdlX2NoYW5nZWQAAA=="
|
||||
>>)},
|
||||
LegacyEvent =
|
||||
{bin,
|
||||
base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgsABAAAABtlZmZlY3RpdmVfY2hhbGxlbmdlX2NoYW5nZWQAAA=="
|
||||
>>)},
|
||||
DecodedLegacy = unmarshal({event, 2}, LegacyEvent),
|
||||
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
|
||||
Decoded = unmarshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, ModernizedBinary),
|
||||
@ -562,23 +592,27 @@ effective_challenge_changed_v2_decoding_test() ->
|
||||
|
||||
-spec challenge_created_v2_decoding_test() -> _.
|
||||
challenge_created_v2_decoding_test() ->
|
||||
Change = {{challenge, <<"challengeID">>}, {created, #{
|
||||
id => <<"id">>,
|
||||
claimant => <<"claimant">>,
|
||||
provider => <<"provider">>,
|
||||
identity_class => <<"identity_class">>,
|
||||
challenge_class => <<"challenge_class">>,
|
||||
proofs => [{rus_domestic_passport, <<"identdoc_token">>}],
|
||||
master_id => <<"master_id">>,
|
||||
claim_id => <<"claim_id">>
|
||||
}}},
|
||||
Change =
|
||||
{{challenge, <<"challengeID">>},
|
||||
{created, #{
|
||||
id => <<"id">>,
|
||||
claimant => <<"claimant">>,
|
||||
provider => <<"provider">>,
|
||||
identity_class => <<"identity_class">>,
|
||||
challenge_class => <<"challenge_class">>,
|
||||
proofs => [{rus_domestic_passport, <<"identdoc_token">>}],
|
||||
master_id => <<"master_id">>,
|
||||
claim_id => <<"claim_id">>
|
||||
}}},
|
||||
Event = {ev, {{{2020, 5, 25}, {19, 19, 10}}, 293305}, Change},
|
||||
LegacyEvent = {bin, base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgwAAwsAAQAAAAtjaGFsbGVuZ2VJRA"
|
||||
"wAAgwAAQsAAwAAAAJpZAsAAQAAAA9jaGFsbGVuZ2VfY2xhc3MPAAIMAAAAAQgAAQAAAAALAAIAAAAO"
|
||||
"aWRlbnRkb2NfdG9rZW4ACwAFAAAACHByb3ZpZGVyCwAGAAAADmlkZW50aXR5X2NsYXNzCwAHAAAACG"
|
||||
"NsYWltX2lkCwAIAAAACW1hc3Rlcl9pZAsACQAAAAhjbGFpbWFudAAAAAAA"
|
||||
>>)},
|
||||
LegacyEvent =
|
||||
{bin,
|
||||
base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgwAAwsAAQAAAAtjaGFsbGVuZ2VJRA"
|
||||
"wAAgwAAQsAAwAAAAJpZAsAAQAAAA9jaGFsbGVuZ2VfY2xhc3MPAAIMAAAAAQgAAQAAAAALAAIAAAAO"
|
||||
"aWRlbnRkb2NfdG9rZW4ACwAFAAAACHByb3ZpZGVyCwAGAAAADmlkZW50aXR5X2NsYXNzCwAHAAAACG"
|
||||
"NsYWltX2lkCwAIAAAACW1hc3Rlcl9pZAsACQAAAAhjbGFpbWFudAAAAAAA"
|
||||
>>)},
|
||||
DecodedLegacy = unmarshal({event, 2}, LegacyEvent),
|
||||
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
|
||||
Decoded = unmarshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, ModernizedBinary),
|
||||
@ -588,9 +622,11 @@ challenge_created_v2_decoding_test() ->
|
||||
challenge_status_changed_v2_decoding_test() ->
|
||||
Change = {{challenge, <<"challengeID">>}, {status_changed, pending}},
|
||||
Event = {ev, {{{2020, 5, 25}, {19, 19, 10}}, 293305}, Change},
|
||||
LegacyEvent = {bin, base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgwAAwsAAQAAAAtjaGFsbGVuZ2VJRAwAAgwAAgwAAQAAAAAAAA=="
|
||||
>>)},
|
||||
LegacyEvent =
|
||||
{bin,
|
||||
base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgwAAwsAAQAAAAtjaGFsbGVuZ2VJRAwAAgwAAgwAAQAAAAAAAA=="
|
||||
>>)},
|
||||
DecodedLegacy = unmarshal({event, 2}, LegacyEvent),
|
||||
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
|
||||
Decoded = unmarshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, ModernizedBinary),
|
||||
|
@ -10,18 +10,16 @@
|
||||
%% Data transform
|
||||
|
||||
-define(to_session_event(SessionID, Payload),
|
||||
{session, #{id => SessionID, payload => Payload}}).
|
||||
{session, #{id => SessionID, payload => Payload}}
|
||||
).
|
||||
|
||||
%% API
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) ->
|
||||
ff_codec:encoded_value().
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) -> ff_codec:encoded_value().
|
||||
marshal(details, {wallet_sender, WalletDetails}) ->
|
||||
{wallet_sender, marshal(wallet_details, WalletDetails)};
|
||||
marshal(details, {wallet_receiver, WalletDetails}) ->
|
||||
{wallet_receiver, marshal(wallet_details, WalletDetails)};
|
||||
|
||||
marshal(wallet_details, ok) ->
|
||||
{ok, #lim_check_WalletOk{}};
|
||||
marshal(wallet_details, {failed, Details}) ->
|
||||
@ -31,14 +29,11 @@ marshal(wallet_details, {failed, Details}) ->
|
||||
balance = ff_codec:marshal(cash, Balance)
|
||||
}}.
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) ->
|
||||
ff_codec:decoded_value().
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) -> ff_codec:decoded_value().
|
||||
unmarshal(details, {wallet_sender, WalletDetails}) ->
|
||||
{wallet_sender, unmarshal(wallet_details, WalletDetails)};
|
||||
unmarshal(details, {wallet_receiver, WalletDetails}) ->
|
||||
{wallet_receiver, unmarshal(wallet_details, WalletDetails)};
|
||||
|
||||
unmarshal(wallet_details, {ok, #lim_check_WalletOk{}}) ->
|
||||
ok;
|
||||
unmarshal(wallet_details, {failed, Details}) ->
|
||||
@ -50,9 +45,11 @@ unmarshal(wallet_details, {failed, Details}) ->
|
||||
|
||||
-ifdef(TEST).
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
-spec test() -> _.
|
||||
|
||||
-spec wallet_ok_test() -> _.
|
||||
|
||||
wallet_ok_test() ->
|
||||
Details0 = {wallet_sender, ok},
|
||||
?assertEqual(Details0, unmarshal(details, (marshal(details, Details0)))),
|
||||
@ -61,15 +58,19 @@ wallet_ok_test() ->
|
||||
|
||||
-spec wallet_fail_test() -> _.
|
||||
wallet_fail_test() ->
|
||||
Details0 = {wallet_sender, {failed, #{
|
||||
expected_range => {{exclusive, {1, <<"RUB">>}}, {inclusive, {10, <<"RUB">>}}},
|
||||
balance => {0, <<"RUB">>}
|
||||
}}},
|
||||
Details0 =
|
||||
{wallet_sender,
|
||||
{failed, #{
|
||||
expected_range => {{exclusive, {1, <<"RUB">>}}, {inclusive, {10, <<"RUB">>}}},
|
||||
balance => {0, <<"RUB">>}
|
||||
}}},
|
||||
?assertEqual(Details0, unmarshal(details, (marshal(details, Details0)))),
|
||||
Details1 = {wallet_receiver, {failed, #{
|
||||
expected_range => {{exclusive, {1, <<"RUB">>}}, {inclusive, {10, <<"RUB">>}}},
|
||||
balance => {0, <<"RUB">>}
|
||||
}}},
|
||||
Details1 =
|
||||
{wallet_receiver,
|
||||
{failed, #{
|
||||
expected_range => {{exclusive, {1, <<"RUB">>}}, {inclusive, {10, <<"RUB">>}}},
|
||||
balance => {0, <<"RUB">>}
|
||||
}}},
|
||||
?assertEqual(Details1, unmarshal(details, (marshal(details, Details1)))).
|
||||
|
||||
-endif.
|
||||
|
@ -9,26 +9,32 @@
|
||||
|
||||
-type type_name() :: msgpack.
|
||||
-type decoded_value() ::
|
||||
#{decoded_value() => decoded_value()} |
|
||||
[decoded_value()] |
|
||||
integer() |
|
||||
float() |
|
||||
binary() |
|
||||
{binary, binary()} |
|
||||
nil.
|
||||
#{decoded_value() => decoded_value()}
|
||||
| [decoded_value()]
|
||||
| integer()
|
||||
| float()
|
||||
| binary()
|
||||
| {binary, binary()}
|
||||
| nil.
|
||||
|
||||
-type encoded_value() :: ff_proto_msgpack_thrift:'Value'().
|
||||
|
||||
-export_type([type_name/0]).
|
||||
-export_type([encoded_value/0]).
|
||||
-export_type([decoded_value/0]).
|
||||
|
||||
-spec marshal(type_name(), decoded_value()) ->
|
||||
encoded_value().
|
||||
marshal(msgpack, nil) -> {nl, #msgp_Nil{}};
|
||||
marshal(msgpack, V) when is_boolean(V) -> {b, V};
|
||||
marshal(msgpack, V) when is_integer(V) -> {i, V};
|
||||
marshal(msgpack, V) when is_float(V) -> V;
|
||||
marshal(msgpack, V) when is_binary(V) -> {str, V}; % Assuming well-formed UTF-8 bytestring.
|
||||
-spec marshal(type_name(), decoded_value()) -> encoded_value().
|
||||
marshal(msgpack, nil) ->
|
||||
{nl, #msgp_Nil{}};
|
||||
marshal(msgpack, V) when is_boolean(V) ->
|
||||
{b, V};
|
||||
marshal(msgpack, V) when is_integer(V) ->
|
||||
{i, V};
|
||||
marshal(msgpack, V) when is_float(V) ->
|
||||
V;
|
||||
% Assuming well-formed UTF-8 bytestring.
|
||||
marshal(msgpack, V) when is_binary(V) ->
|
||||
{str, V};
|
||||
marshal(msgpack, {binary, V}) when is_binary(V) ->
|
||||
{bin, V};
|
||||
marshal(msgpack, V) when is_list(V) ->
|
||||
@ -36,14 +42,21 @@ marshal(msgpack, V) when is_list(V) ->
|
||||
marshal(msgpack, V) when is_map(V) ->
|
||||
{obj, maps:fold(fun(Key, Value, Map) -> Map#{marshal(msgpack, Key) => marshal(msgpack, Value)} end, #{}, V)}.
|
||||
|
||||
-spec unmarshal(type_name(), encoded_value()) ->
|
||||
decoded_value().
|
||||
unmarshal(msgpack, {nl, #msgp_Nil{}}) -> nil;
|
||||
unmarshal(msgpack, {b, V}) when is_boolean(V) -> V;
|
||||
unmarshal(msgpack, {i, V}) when is_integer(V) -> V;
|
||||
unmarshal(msgpack, {flt, V}) when is_float(V) -> V;
|
||||
unmarshal(msgpack, {str, V}) when is_binary(V) -> V; % Assuming well-formed UTF-8 bytestring.
|
||||
unmarshal(msgpack, {bin, V}) when is_binary(V) -> {binary, V};
|
||||
unmarshal(msgpack, {arr, V}) when is_list(V) -> [unmarshal(msgpack, ListItem) || ListItem <- V];
|
||||
unmarshal(msgpack, {obj, V}) when is_map(V) ->
|
||||
-spec unmarshal(type_name(), encoded_value()) -> decoded_value().
|
||||
unmarshal(msgpack, {nl, #msgp_Nil{}}) ->
|
||||
nil;
|
||||
unmarshal(msgpack, {b, V}) when is_boolean(V) ->
|
||||
V;
|
||||
unmarshal(msgpack, {i, V}) when is_integer(V) ->
|
||||
V;
|
||||
unmarshal(msgpack, {flt, V}) when is_float(V) ->
|
||||
V;
|
||||
% Assuming well-formed UTF-8 bytestring.
|
||||
unmarshal(msgpack, {str, V}) when is_binary(V) ->
|
||||
V;
|
||||
unmarshal(msgpack, {bin, V}) when is_binary(V) ->
|
||||
{binary, V};
|
||||
unmarshal(msgpack, {arr, V}) when is_list(V) ->
|
||||
[unmarshal(msgpack, ListItem) || ListItem <- V];
|
||||
unmarshal(msgpack, {obj, V}) when is_map(V) ->
|
||||
maps:fold(fun(Key, Value, Map) -> Map#{unmarshal(msgpack, Key) => unmarshal(msgpack, Value)} end, #{}, V).
|
||||
|
@ -1,6 +1,7 @@
|
||||
%% P2P adapter host
|
||||
|
||||
-module(ff_p2p_adapter_host).
|
||||
|
||||
-behaviour(ff_woody_wrapper).
|
||||
|
||||
-include_lib("damsel/include/dmsl_base_thrift.hrl").
|
||||
@ -18,8 +19,7 @@
|
||||
|
||||
%% Handler
|
||||
|
||||
-spec handle_function(woody:func(), woody:args(), woody:options()) ->
|
||||
{ok, woody:result()} | no_return().
|
||||
-spec handle_function(woody:func(), woody:args(), woody:options()) -> {ok, woody:result()} | no_return().
|
||||
handle_function(Func, Args, Opts) ->
|
||||
scoper:scope(ff_p2p_adapter_host, #{}, fun() -> handle_function_(Func, Args, Opts) end).
|
||||
|
||||
|
@ -15,7 +15,6 @@
|
||||
%% API
|
||||
-spec marshal_state(p2p_session:session_state(), ff_entity_context:context()) ->
|
||||
ff_proto_p2p_session_thrift:'SessionState'().
|
||||
|
||||
marshal_state(State, Context) ->
|
||||
#p2p_session_SessionState{
|
||||
id = marshal(id, p2p_session:id(State)),
|
||||
@ -27,9 +26,7 @@ marshal_state(State, Context) ->
|
||||
context = marshal(ctx, Context)
|
||||
}.
|
||||
|
||||
-spec marshal_event(p2p_transfer_machine:event()) ->
|
||||
ff_proto_p2p_session_thrift:'Event'().
|
||||
|
||||
-spec marshal_event(p2p_transfer_machine:event()) -> ff_proto_p2p_session_thrift:'Event'().
|
||||
marshal_event({EventID, {ev, Timestamp, Change}}) ->
|
||||
#p2p_session_Event{
|
||||
event = ff_codec:marshal(event_id, EventID),
|
||||
@ -37,18 +34,14 @@ marshal_event({EventID, {ev, Timestamp, Change}}) ->
|
||||
change = marshal(change, Change)
|
||||
}.
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) ->
|
||||
ff_codec:encoded_value().
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) -> ff_codec:encoded_value().
|
||||
marshal({list, T}, V) ->
|
||||
[marshal(T, E) || E <- V];
|
||||
|
||||
marshal(timestamped_change, {ev, Timestamp, Change}) ->
|
||||
#p2p_session_TimestampedChange{
|
||||
change = marshal(change, Change),
|
||||
occured_at = ff_codec:marshal(timestamp, Timestamp)
|
||||
};
|
||||
|
||||
marshal(change, {created, Session}) ->
|
||||
{created, #p2p_session_CreatedChange{session = marshal(session, Session)}};
|
||||
marshal(change, {next_state, AdapterState}) ->
|
||||
@ -61,15 +54,17 @@ marshal(change, {callback, CallbackChange}) ->
|
||||
{callback, marshal(callback_change, CallbackChange)};
|
||||
marshal(change, {user_interaction, UserInteractionChange}) ->
|
||||
{ui, marshal(user_interaction_change, UserInteractionChange)};
|
||||
|
||||
marshal(session, #{
|
||||
id := ID,
|
||||
status := Status,
|
||||
transfer_params := TransferParams,
|
||||
domain_revision := DomainRevision,
|
||||
party_revision := PartyRevision,
|
||||
route := Route
|
||||
} = Session) ->
|
||||
marshal(
|
||||
session,
|
||||
#{
|
||||
id := ID,
|
||||
status := Status,
|
||||
transfer_params := TransferParams,
|
||||
domain_revision := DomainRevision,
|
||||
party_revision := PartyRevision,
|
||||
route := Route
|
||||
} = Session
|
||||
) ->
|
||||
#p2p_session_Session{
|
||||
id = marshal(id, ID),
|
||||
status = marshal(status, Status),
|
||||
@ -79,23 +74,23 @@ marshal(session, #{
|
||||
domain_revision = marshal(domain_revision, DomainRevision),
|
||||
provider_legacy = maybe_marshal(integer, genlib_map:get(provider_id_legacy, Session))
|
||||
};
|
||||
|
||||
marshal(status, active) ->
|
||||
{active, #p2p_session_SessionActive{}};
|
||||
marshal(status, {finished, SessionResult}) ->
|
||||
{finished, #p2p_session_SessionFinished{result = marshal(session_result, SessionResult)}};
|
||||
|
||||
marshal(session_result, success) ->
|
||||
{success, #p2p_session_ResultSuccess{}};
|
||||
marshal(session_result, {failure, Failure}) ->
|
||||
{failed, #p2p_session_ResultFailed{failure = marshal(failure, Failure)}};
|
||||
|
||||
marshal(p2p_transfer, Transfer = #{
|
||||
id := ID,
|
||||
body := Body,
|
||||
sender := Sender,
|
||||
receiver := Receiver
|
||||
}) ->
|
||||
marshal(
|
||||
p2p_transfer,
|
||||
Transfer = #{
|
||||
id := ID,
|
||||
body := Body,
|
||||
sender := Sender,
|
||||
receiver := Receiver
|
||||
}
|
||||
) ->
|
||||
Deadline = maps:get(deadline, Transfer, undefined),
|
||||
MerchantFees = maps:get(merchant_fees, Transfer, undefined),
|
||||
ProviderFees = maps:get(provider_fees, Transfer, undefined),
|
||||
@ -108,15 +103,12 @@ marshal(p2p_transfer, Transfer = #{
|
||||
merchant_fees = maybe_marshal(fees, MerchantFees),
|
||||
provider_fees = maybe_marshal(fees, ProviderFees)
|
||||
};
|
||||
|
||||
marshal(route, Route) ->
|
||||
#p2p_session_Route{
|
||||
provider_id = marshal(provider_id, maps:get(provider_id, Route))
|
||||
};
|
||||
|
||||
marshal(deadline, Deadline) ->
|
||||
ff_time:to_rfc3339(Deadline);
|
||||
|
||||
marshal(fees, #{fees := Fees}) ->
|
||||
#'Fees'{
|
||||
fees = maps:fold(
|
||||
@ -127,92 +119,77 @@ marshal(fees, #{fees := Fees}) ->
|
||||
Fees
|
||||
)
|
||||
};
|
||||
|
||||
marshal(cash_flow_constant, Constant) ->
|
||||
Constant;
|
||||
|
||||
marshal(callback_change, #{tag := Tag, payload := Payload}) ->
|
||||
#p2p_session_CallbackChange{
|
||||
tag = marshal(string, Tag),
|
||||
payload = marshal(callback_event, Payload)
|
||||
};
|
||||
|
||||
marshal(callback_event, {created, Callback}) ->
|
||||
{created, #p2p_session_CallbackCreatedChange{callback = marshal(callback, Callback)}};
|
||||
marshal(callback_event, {finished, #{payload := Response}}) ->
|
||||
{finished, #p2p_session_CallbackResultChange{payload = Response}};
|
||||
marshal(callback_event, {status_changed, Status}) ->
|
||||
{status_changed, #p2p_session_CallbackStatusChange{status = marshal(callback_status, Status)}};
|
||||
|
||||
marshal(callback, #{tag := Tag}) ->
|
||||
#p2p_session_Callback{tag = marshal(string, Tag)};
|
||||
|
||||
marshal(callback_status, pending) ->
|
||||
{pending, #p2p_session_CallbackStatusPending{}};
|
||||
marshal(callback_status, succeeded) ->
|
||||
{succeeded, #p2p_session_CallbackStatusSucceeded{}};
|
||||
|
||||
marshal(user_interaction_change, #{id := ID, payload := Payload}) ->
|
||||
#p2p_session_UserInteractionChange{
|
||||
id = marshal(id, ID),
|
||||
payload = marshal(user_interaction_event, Payload)
|
||||
};
|
||||
|
||||
marshal(user_interaction_event, {created, UserInteraction}) ->
|
||||
{created, #p2p_session_UserInteractionCreatedChange{ui = marshal(user_interaction, UserInteraction)}};
|
||||
marshal(user_interaction_event, {status_changed, Status}) ->
|
||||
{status_changed, #p2p_session_UserInteractionStatusChange{
|
||||
status = marshal(user_interaction_status, Status)
|
||||
}};
|
||||
|
||||
marshal(user_interaction, #{id := ID, content := Content}) ->
|
||||
#p2p_session_UserInteraction{
|
||||
id = marshal(id, ID),
|
||||
user_interaction = marshal(user_interaction_content, Content)
|
||||
};
|
||||
|
||||
marshal(user_interaction_content, {redirect, #{content := Redirect}}) ->
|
||||
{redirect, marshal(redirect, Redirect)};
|
||||
|
||||
marshal(redirect, {get, URI}) ->
|
||||
{get_request, #ui_BrowserGetRequest{uri = URI}};
|
||||
marshal(redirect, {post, URI, Form}) ->
|
||||
{post_request, #ui_BrowserPostRequest{uri = URI, form = marshal(form, Form)}};
|
||||
|
||||
marshal(form, Form) when is_map(Form) ->
|
||||
maps:fold(fun(Key, Value, Map) ->
|
||||
Map#{marshal(string, Key) => marshal(string, Value)} end,
|
||||
maps:fold(
|
||||
fun(Key, Value, Map) ->
|
||||
Map#{marshal(string, Key) => marshal(string, Value)}
|
||||
end,
|
||||
#{},
|
||||
Form
|
||||
);
|
||||
|
||||
marshal(user_interaction_status, pending) ->
|
||||
{pending, #p2p_session_UserInteractionStatusPending{}};
|
||||
marshal(user_interaction_status, finished) ->
|
||||
{finished, #p2p_session_UserInteractionStatusFinished{}};
|
||||
|
||||
marshal(T, V) ->
|
||||
ff_codec:marshal(T, V).
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) ->
|
||||
ff_codec:decoded_value().
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) -> ff_codec:decoded_value().
|
||||
unmarshal({list, T}, V) ->
|
||||
[unmarshal(T, E) || E <- V];
|
||||
|
||||
unmarshal(repair_scenario, {add_events, #p2p_session_AddEventsRepair{events = Events, action = Action}}) ->
|
||||
{add_events, genlib_map:compact(#{
|
||||
events => unmarshal({list, change}, Events),
|
||||
action => maybe_unmarshal(complex_action, Action)
|
||||
})};
|
||||
{add_events,
|
||||
genlib_map:compact(#{
|
||||
events => unmarshal({list, change}, Events),
|
||||
action => maybe_unmarshal(complex_action, Action)
|
||||
})};
|
||||
unmarshal(repair_scenario, {set_session_result, #p2p_session_SetResultRepair{result = Result}}) ->
|
||||
{set_session_result, unmarshal(session_result, Result)};
|
||||
|
||||
unmarshal(timestamped_change, TimestampedChange) ->
|
||||
Timestamp = ff_codec:unmarshal(timestamp, TimestampedChange#p2p_session_TimestampedChange.occured_at),
|
||||
Change = unmarshal(change, TimestampedChange#p2p_session_TimestampedChange.change),
|
||||
{ev, Timestamp, Change};
|
||||
|
||||
unmarshal(change, {created, #p2p_session_CreatedChange{session = Session}}) ->
|
||||
{created, unmarshal(session, Session)};
|
||||
unmarshal(change, {adapter_state, #p2p_session_AdapterStateChange{state = AdapterState}}) ->
|
||||
@ -231,7 +208,6 @@ unmarshal(change, {ui, #p2p_session_UserInteractionChange{id = ID, payload = Pay
|
||||
id => unmarshal(id, ID),
|
||||
payload => unmarshal(user_interaction_event, Payload)
|
||||
}};
|
||||
|
||||
unmarshal(session, #p2p_session_Session{
|
||||
id = ID,
|
||||
status = Status,
|
||||
@ -251,17 +227,14 @@ unmarshal(session, #p2p_session_Session{
|
||||
domain_revision => unmarshal(domain_revision, DomainRevision),
|
||||
provider_id_legacy => maybe_unmarshal(integer, ProviderID)
|
||||
});
|
||||
|
||||
unmarshal(status, {active, #p2p_session_SessionActive{}}) ->
|
||||
active;
|
||||
unmarshal(status, {finished, #p2p_session_SessionFinished{result = SessionResult}}) ->
|
||||
{finished, unmarshal(session_result, SessionResult)};
|
||||
|
||||
unmarshal(session_result, {success, #p2p_session_ResultSuccess{}}) ->
|
||||
success;
|
||||
unmarshal(session_result, {failed, #p2p_session_ResultFailed{failure = Failure}}) ->
|
||||
{failure, unmarshal(failure, Failure)};
|
||||
|
||||
unmarshal(p2p_transfer, #p2p_session_P2PTransfer{
|
||||
id = ID,
|
||||
sender = Sender,
|
||||
@ -280,54 +253,53 @@ unmarshal(p2p_transfer, #p2p_session_P2PTransfer{
|
||||
merchant_fees => maybe_unmarshal(fees, MerchantFees),
|
||||
provider_fees => maybe_unmarshal(fees, ProviderFees)
|
||||
});
|
||||
|
||||
unmarshal(route, Route) ->
|
||||
#{
|
||||
provider_id => unmarshal(provider_id, Route#p2p_session_Route.provider_id)
|
||||
};
|
||||
|
||||
unmarshal(deadline, Deadline) ->
|
||||
ff_time:from_rfc3339(Deadline);
|
||||
|
||||
unmarshal(fees, #'Fees'{fees = Fees}) ->
|
||||
#{fees => maps:fold(
|
||||
fun(Key, Value, Map) ->
|
||||
Map#{unmarshal(cash_flow_constant, Key) => unmarshal(cash, Value)}
|
||||
end,
|
||||
#{},
|
||||
Fees
|
||||
)};
|
||||
|
||||
#{
|
||||
fees => maps:fold(
|
||||
fun(Key, Value, Map) ->
|
||||
Map#{unmarshal(cash_flow_constant, Key) => unmarshal(cash, Value)}
|
||||
end,
|
||||
#{},
|
||||
Fees
|
||||
)
|
||||
};
|
||||
unmarshal(cash_flow_constant, Constant) ->
|
||||
Constant;
|
||||
|
||||
unmarshal(callback_event, {created, #p2p_session_CallbackCreatedChange{callback = Callback}}) ->
|
||||
{created, unmarshal(callback, Callback)};
|
||||
unmarshal(callback_event, {finished, #p2p_session_CallbackResultChange{payload = Response}}) ->
|
||||
{finished, #{payload => Response}};
|
||||
unmarshal(callback_event, {status_changed, #p2p_session_CallbackStatusChange{status = Status}}) ->
|
||||
{status_changed, unmarshal(callback_status, Status)};
|
||||
|
||||
unmarshal(callback, #p2p_session_Callback{tag = Tag}) ->
|
||||
#{
|
||||
version => 1,
|
||||
tag => unmarshal(string, Tag)
|
||||
};
|
||||
|
||||
unmarshal(callback_status, {pending, #p2p_session_CallbackStatusPending{}}) ->
|
||||
pending;
|
||||
unmarshal(callback_status, {succeeded, #p2p_session_CallbackStatusSucceeded{}}) ->
|
||||
succeeded;
|
||||
|
||||
unmarshal(user_interaction_event, {created, #p2p_session_UserInteractionCreatedChange{
|
||||
ui = UserInteraction
|
||||
}}) ->
|
||||
unmarshal(
|
||||
user_interaction_event,
|
||||
{created, #p2p_session_UserInteractionCreatedChange{
|
||||
ui = UserInteraction
|
||||
}}
|
||||
) ->
|
||||
{created, unmarshal(user_interaction, UserInteraction)};
|
||||
unmarshal(user_interaction_event, {status_changed, #p2p_session_UserInteractionStatusChange{
|
||||
status = Status
|
||||
}}) ->
|
||||
unmarshal(
|
||||
user_interaction_event,
|
||||
{status_changed, #p2p_session_UserInteractionStatusChange{
|
||||
status = Status
|
||||
}}
|
||||
) ->
|
||||
{status_changed, unmarshal(user_interaction_status, Status)};
|
||||
|
||||
unmarshal(user_interaction, #p2p_session_UserInteraction{
|
||||
id = ID,
|
||||
user_interaction = Content
|
||||
@ -337,29 +309,26 @@ unmarshal(user_interaction, #p2p_session_UserInteraction{
|
||||
id => unmarshal(id, ID),
|
||||
content => unmarshal(user_interaction_content, Content)
|
||||
};
|
||||
|
||||
unmarshal(user_interaction_content, {redirect, Redirect}) ->
|
||||
{redirect, #{
|
||||
content => unmarshal(redirect, Redirect)
|
||||
}};
|
||||
|
||||
unmarshal(redirect, {get_request, #ui_BrowserGetRequest{uri = URI}}) ->
|
||||
{get, URI};
|
||||
unmarshal(redirect, {post_request, #ui_BrowserPostRequest{uri = URI, form = Form}}) ->
|
||||
{post, URI, unmarshal(form, Form)};
|
||||
|
||||
unmarshal(form, Form) when is_map(Form) ->
|
||||
maps:fold(fun(Key, Value, Map) ->
|
||||
Map#{unmarshal(string, Key) => unmarshal(string, Value)} end,
|
||||
maps:fold(
|
||||
fun(Key, Value, Map) ->
|
||||
Map#{unmarshal(string, Key) => unmarshal(string, Value)}
|
||||
end,
|
||||
#{},
|
||||
Form
|
||||
);
|
||||
|
||||
unmarshal(user_interaction_status, {pending, #p2p_session_UserInteractionStatusPending{}}) ->
|
||||
pending;
|
||||
unmarshal(user_interaction_status, {finished, #p2p_session_UserInteractionStatusFinished{}}) ->
|
||||
finished;
|
||||
|
||||
unmarshal(T, V) ->
|
||||
ff_codec:unmarshal(T, V).
|
||||
|
||||
@ -375,21 +344,23 @@ maybe_unmarshal(_Type, undefined) ->
|
||||
maybe_unmarshal(Type, Value) ->
|
||||
unmarshal(Type, Value).
|
||||
|
||||
|
||||
%% TESTS
|
||||
|
||||
-ifdef(TEST).
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
-spec test() -> _.
|
||||
|
||||
-spec p2p_session_codec_test() -> _.
|
||||
|
||||
p2p_session_codec_test() ->
|
||||
UserInteraction = #{
|
||||
version => 1,
|
||||
id => genlib:unique(),
|
||||
content => {redirect, #{
|
||||
content => {get, <<"URI">>}
|
||||
}}
|
||||
content =>
|
||||
{redirect, #{
|
||||
content => {get, <<"URI">>}
|
||||
}}
|
||||
},
|
||||
|
||||
Callback = #{
|
||||
@ -402,10 +373,13 @@ p2p_session_codec_test() ->
|
||||
extra => #{<<"key">> => <<"Extra">>}
|
||||
},
|
||||
|
||||
Resource = {bank_card, #{bank_card => #{
|
||||
token => <<"token">>,
|
||||
payment_system => visa
|
||||
}}},
|
||||
Resource =
|
||||
{bank_card, #{
|
||||
bank_card => #{
|
||||
token => <<"token">>,
|
||||
payment_system => visa
|
||||
}
|
||||
}},
|
||||
|
||||
TransferParams = #{
|
||||
id => genlib:unique(),
|
||||
|
@ -16,32 +16,28 @@
|
||||
%% Internals
|
||||
%%
|
||||
|
||||
-spec publish_events(list(event())) ->
|
||||
list(sinkevent()).
|
||||
|
||||
-spec publish_events(list(event())) -> list(sinkevent()).
|
||||
publish_events(Events) ->
|
||||
[publish_event(Event) || Event <- Events].
|
||||
|
||||
-spec publish_event(event()) ->
|
||||
sinkevent().
|
||||
|
||||
-spec publish_event(event()) -> sinkevent().
|
||||
publish_event(#{
|
||||
id := ID,
|
||||
source_id := SourceID,
|
||||
event := {
|
||||
id := ID,
|
||||
source_id := SourceID,
|
||||
event := {
|
||||
EventID,
|
||||
Dt,
|
||||
{ev, EventDt, Payload}
|
||||
}
|
||||
}) ->
|
||||
#p2p_session_SinkEvent{
|
||||
id = marshal(event_id, ID),
|
||||
created_at = marshal(timestamp, Dt),
|
||||
source = marshal(id, SourceID),
|
||||
payload = #p2p_session_EventSinkPayload{
|
||||
sequence = marshal(event_id, EventID),
|
||||
id = marshal(event_id, ID),
|
||||
created_at = marshal(timestamp, Dt),
|
||||
source = marshal(id, SourceID),
|
||||
payload = #p2p_session_EventSinkPayload{
|
||||
sequence = marshal(event_id, EventID),
|
||||
occured_at = marshal(timestamp, EventDt),
|
||||
changes = [marshal(change, Payload)]
|
||||
changes = [marshal(change, Payload)]
|
||||
}
|
||||
}.
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
-module(ff_p2p_session_handler).
|
||||
|
||||
-behaviour(ff_woody_wrapper).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_p2p_session_thrift.hrl").
|
||||
@ -9,11 +10,11 @@
|
||||
%%
|
||||
%% ff_woody_wrapper callbacks
|
||||
%%
|
||||
-spec handle_function(woody:func(), woody:args(), woody:options()) ->
|
||||
{ok, woody:result()} | no_return().
|
||||
|
||||
-spec handle_function(woody:func(), woody:args(), woody:options()) -> {ok, woody:result()} | no_return().
|
||||
handle_function(Func, Args, Opts) ->
|
||||
scoper:scope(p2p_session, #{},
|
||||
scoper:scope(
|
||||
p2p_session,
|
||||
#{},
|
||||
fun() ->
|
||||
handle_function_(Func, Args, Opts)
|
||||
end
|
||||
@ -33,7 +34,6 @@ handle_function_('Get', [ID, EventRange], _Opts) ->
|
||||
{error, {unknown_p2p_session, _Ref}} ->
|
||||
woody_error:raise(business, #fistful_P2PSessionNotFound{})
|
||||
end;
|
||||
|
||||
handle_function_('GetContext', [ID], _Opts) ->
|
||||
case p2p_session_machine:get(ID, {undefined, 0}) of
|
||||
{ok, Machine} ->
|
||||
@ -42,7 +42,6 @@ handle_function_('GetContext', [ID], _Opts) ->
|
||||
{error, {unknown_p2p_session, _Ref}} ->
|
||||
woody_error:raise(business, #fistful_P2PSessionNotFound{})
|
||||
end;
|
||||
|
||||
handle_function_('GetEvents', [ID, EventRange], _Opts) ->
|
||||
ok = scoper:add_meta(#{id => ID}),
|
||||
case p2p_session_machine:events(ID, ff_codec:unmarshal(event_range, EventRange)) of
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -12,8 +12,7 @@
|
||||
%% ff_woody_wrapper callbacks
|
||||
%%
|
||||
|
||||
-spec handle_function(woody:func(), woody:args(), options()) ->
|
||||
{ok, woody:result()} | no_return().
|
||||
-spec handle_function(woody:func(), woody:args(), options()) -> {ok, woody:result()} | no_return().
|
||||
handle_function('Repair', [ID, Scenario], _Opts) ->
|
||||
DecodedScenario = ff_codec:unmarshal(ff_p2p_session_codec, repair_scenario, Scenario),
|
||||
case p2p_session_machine:repair(ID, DecodedScenario) of
|
||||
|
@ -16,7 +16,6 @@
|
||||
|
||||
-spec marshal_p2p_template_state(p2p_template:template_state(), ff_entity_context:context()) ->
|
||||
ff_proto_p2p_template_thrift:'P2PTemplateState'().
|
||||
|
||||
marshal_p2p_template_state(P2PTemplate, Ctx) ->
|
||||
#p2p_template_P2PTemplateState{
|
||||
id = marshal(id, p2p_template:id(P2PTemplate)),
|
||||
@ -32,13 +31,11 @@ marshal_p2p_template_state(P2PTemplate, Ctx) ->
|
||||
|
||||
-spec marshal_p2p_transfer_state(p2p_transfer:p2p_transfer_state(), ff_entity_context:context()) ->
|
||||
ff_proto_p2p_transfer_thrift:'P2PTransferState'().
|
||||
|
||||
marshal_p2p_transfer_state(P2PTransfer, Ctx) ->
|
||||
ff_p2p_transfer_codec:marshal_p2p_transfer_state(P2PTransfer, Ctx).
|
||||
|
||||
-spec unmarshal_p2p_template_params(ff_proto_p2p_template_thrift:'P2PTemplateParams'()) ->
|
||||
p2p_template_machine:params().
|
||||
|
||||
unmarshal_p2p_template_params(#p2p_template_P2PTemplateParams{
|
||||
id = ID,
|
||||
identity_id = IdentityID,
|
||||
@ -54,7 +51,6 @@ unmarshal_p2p_template_params(#p2p_template_P2PTemplateParams{
|
||||
|
||||
-spec unmarshal_p2p_quote_params(ff_proto_p2p_template_thrift:'P2PTemplateQuoteParams'()) ->
|
||||
p2p_template:quote_params().
|
||||
|
||||
unmarshal_p2p_quote_params(#p2p_template_P2PTemplateQuoteParams{
|
||||
sender = Sender,
|
||||
receiver = Receiver,
|
||||
@ -68,7 +64,6 @@ unmarshal_p2p_quote_params(#p2p_template_P2PTemplateQuoteParams{
|
||||
|
||||
-spec unmarshal_p2p_transfer_params(ff_proto_p2p_template_thrift:'P2PTemplateTransferParams'()) ->
|
||||
p2p_template:transfer_params().
|
||||
|
||||
unmarshal_p2p_transfer_params(#p2p_template_P2PTemplateTransferParams{
|
||||
id = ID,
|
||||
sender = Sender,
|
||||
@ -78,7 +73,6 @@ unmarshal_p2p_transfer_params(#p2p_template_P2PTemplateTransferParams{
|
||||
quote = Quote,
|
||||
metadata = Metadata,
|
||||
deadline = Deadline
|
||||
|
||||
}) ->
|
||||
genlib_map:compact(#{
|
||||
id => unmarshal(id, ID),
|
||||
@ -91,31 +85,29 @@ unmarshal_p2p_transfer_params(#p2p_template_P2PTemplateTransferParams{
|
||||
deadline => maybe_unmarshal(timestamp_ms, Deadline)
|
||||
}).
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) ->
|
||||
ff_codec:encoded_value().
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) -> ff_codec:encoded_value().
|
||||
marshal({list, T}, V) ->
|
||||
[marshal(T, E) || E <- V];
|
||||
|
||||
marshal(timestamped_change, {ev, Timestamp, Change}) ->
|
||||
#p2p_template_TimestampedChange{
|
||||
change = marshal(change, Change),
|
||||
occured_at = ff_codec:marshal(timestamp, Timestamp)
|
||||
};
|
||||
|
||||
marshal(change, {created, Template}) ->
|
||||
{created, #p2p_template_CreatedChange{p2p_template = marshal(template, Template)}};
|
||||
marshal(change, {blocking_changed, Blocking}) ->
|
||||
{blocking_changed, #p2p_template_BlockingChange{blocking = marshal(blocking, Blocking)}};
|
||||
|
||||
marshal(template, Template = #{
|
||||
id := ID,
|
||||
identity_id := IdentityID,
|
||||
domain_revision := DomainRevision,
|
||||
party_revision := PartyRevision,
|
||||
created_at := CreatedAt,
|
||||
details := Details
|
||||
}) ->
|
||||
marshal(
|
||||
template,
|
||||
Template = #{
|
||||
id := ID,
|
||||
identity_id := IdentityID,
|
||||
domain_revision := DomainRevision,
|
||||
party_revision := PartyRevision,
|
||||
created_at := CreatedAt,
|
||||
details := Details
|
||||
}
|
||||
) ->
|
||||
ExternalID = maps:get(external_id, Template, undefined),
|
||||
|
||||
#p2p_template_P2PTemplate{
|
||||
@ -127,7 +119,6 @@ marshal(template, Template = #{
|
||||
party_revision = marshal(party_revision, PartyRevision),
|
||||
external_id = maybe_marshal(id, ExternalID)
|
||||
};
|
||||
|
||||
marshal(details, Details) ->
|
||||
Body = maps:get(body, Details),
|
||||
Metadata = maps:get(metadata, Details, undefined),
|
||||
@ -135,7 +126,6 @@ marshal(details, Details) ->
|
||||
body = marshal(template_body, Body),
|
||||
metadata = maybe_marshal(template_metadata, Metadata)
|
||||
};
|
||||
|
||||
marshal(template_body, #{value := Body = #{currency := Currency}}) ->
|
||||
Amount = maps:get(amount, Body, undefined),
|
||||
#p2p_template_P2PTemplateBody{
|
||||
@ -144,51 +134,40 @@ marshal(template_body, #{value := Body = #{currency := Currency}}) ->
|
||||
currency = marshal(currency_ref, Currency)
|
||||
}
|
||||
};
|
||||
|
||||
marshal(template_metadata, #{value := Metadata}) ->
|
||||
#p2p_template_P2PTemplateMetadata{
|
||||
value = marshal(ctx, Metadata)
|
||||
};
|
||||
|
||||
marshal(quote, Quote) ->
|
||||
ff_p2p_transfer_codec:marshal(quote, Quote);
|
||||
|
||||
marshal(blocking, unblocked) ->
|
||||
unblocked;
|
||||
marshal(blocking, blocked) ->
|
||||
blocked;
|
||||
|
||||
marshal(timestamp, Timestamp) when is_integer(Timestamp) ->
|
||||
ff_time:to_rfc3339(Timestamp);
|
||||
|
||||
marshal(ctx, Context) ->
|
||||
maybe_marshal(context, Context);
|
||||
|
||||
marshal(T, V) ->
|
||||
ff_codec:marshal(T, V).
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) ->
|
||||
ff_codec:decoded_value().
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) -> ff_codec:decoded_value().
|
||||
unmarshal({list, T}, V) ->
|
||||
[unmarshal(T, E) || E <- V];
|
||||
|
||||
unmarshal(timestamped_change, TimestampedChange) ->
|
||||
Timestamp = ff_codec:unmarshal(timestamp, TimestampedChange#p2p_template_TimestampedChange.occured_at),
|
||||
Change = unmarshal(change, TimestampedChange#p2p_template_TimestampedChange.change),
|
||||
{ev, Timestamp, Change};
|
||||
|
||||
unmarshal(repair_scenario, {add_events, #p2p_template_AddEventsRepair{events = Events, action = Action}}) ->
|
||||
{add_events, genlib_map:compact(#{
|
||||
events => unmarshal({list, change}, Events),
|
||||
action => maybe_unmarshal(complex_action, Action)
|
||||
})};
|
||||
|
||||
{add_events,
|
||||
genlib_map:compact(#{
|
||||
events => unmarshal({list, change}, Events),
|
||||
action => maybe_unmarshal(complex_action, Action)
|
||||
})};
|
||||
unmarshal(change, {created, #p2p_template_CreatedChange{p2p_template = Template}}) ->
|
||||
{created, unmarshal(template, Template)};
|
||||
unmarshal(change, {blocking_changed, #p2p_template_BlockingChange{blocking = Blocking}}) ->
|
||||
{blocking_changed, unmarshal(blocking, Blocking)};
|
||||
|
||||
unmarshal(template, #p2p_template_P2PTemplate{
|
||||
id = ID,
|
||||
identity_id = IdentityID,
|
||||
@ -208,7 +187,6 @@ unmarshal(template, #p2p_template_P2PTemplate{
|
||||
created_at => ff_time:from_rfc3339(unmarshal(timestamp, CreatedAt)),
|
||||
external_id => maybe_unmarshal(id, ExternalID)
|
||||
});
|
||||
|
||||
unmarshal(details, #p2p_template_P2PTemplateDetails{
|
||||
body = Body,
|
||||
metadata = Metadata
|
||||
@ -217,7 +195,6 @@ unmarshal(details, #p2p_template_P2PTemplateDetails{
|
||||
body => unmarshal(template_body, Body),
|
||||
metadata => maybe_unmarshal(template_metadata, Metadata)
|
||||
});
|
||||
|
||||
unmarshal(template_body, #p2p_template_P2PTemplateBody{
|
||||
value = #p2p_template_Cash{
|
||||
amount = Amount,
|
||||
@ -230,32 +207,24 @@ unmarshal(template_body, #p2p_template_P2PTemplateBody{
|
||||
currency => unmarshal(currency_ref, Currency)
|
||||
})
|
||||
};
|
||||
|
||||
unmarshal(template_metadata, #p2p_template_P2PTemplateMetadata{
|
||||
value = Metadata
|
||||
}) ->
|
||||
#{value => unmarshal(ctx, Metadata)};
|
||||
|
||||
unmarshal(quote, Quote) ->
|
||||
ff_p2p_transfer_codec:unmarshal(quote, Quote);
|
||||
|
||||
unmarshal(participant, Participant) ->
|
||||
ff_p2p_transfer_codec:unmarshal(participant, Participant);
|
||||
|
||||
unmarshal(client_info, ClientInfo) ->
|
||||
ff_p2p_transfer_codec:unmarshal(client_info, ClientInfo);
|
||||
|
||||
unmarshal(ctx, Context) ->
|
||||
maybe_unmarshal(context, Context);
|
||||
|
||||
unmarshal(blocking, unblocked) ->
|
||||
unblocked;
|
||||
unmarshal(blocking, blocked) ->
|
||||
blocked;
|
||||
|
||||
unmarshal(timestamp, Timestamp) ->
|
||||
unmarshal(string, Timestamp);
|
||||
|
||||
unmarshal(T, V) ->
|
||||
ff_codec:unmarshal(T, V).
|
||||
|
||||
@ -275,9 +244,11 @@ maybe_marshal(Type, Value) ->
|
||||
|
||||
-ifdef(TEST).
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
-spec test() -> _.
|
||||
|
||||
-spec p2p_template_codec_test() -> _.
|
||||
|
||||
p2p_template_codec_test() ->
|
||||
Details = #{
|
||||
body => #{
|
||||
|
@ -9,32 +9,28 @@
|
||||
-type event() :: ff_eventsink_publisher:event(p2p_template:event()).
|
||||
-type sinkevent() :: ff_eventsink_publisher:sinkevent(ff_proto_p2p_template_thrift:'SinkEvent'()).
|
||||
|
||||
-spec publish_events(list(event())) ->
|
||||
list(sinkevent()).
|
||||
|
||||
-spec publish_events(list(event())) -> list(sinkevent()).
|
||||
publish_events(Events) ->
|
||||
[publish_event(Event) || Event <- Events].
|
||||
|
||||
-spec publish_event(event()) ->
|
||||
sinkevent().
|
||||
|
||||
-spec publish_event(event()) -> sinkevent().
|
||||
publish_event(#{
|
||||
id := ID,
|
||||
source_id := SourceID,
|
||||
event := {
|
||||
id := ID,
|
||||
source_id := SourceID,
|
||||
event := {
|
||||
EventID,
|
||||
Dt,
|
||||
{ev, EventDt, Payload}
|
||||
}
|
||||
}) ->
|
||||
#p2p_template_SinkEvent{
|
||||
id = marshal(event_id, ID),
|
||||
created_at = marshal(timestamp, Dt),
|
||||
source = marshal(id, SourceID),
|
||||
payload = #p2p_template_EventSinkPayload{
|
||||
sequence = marshal(event_id, EventID),
|
||||
id = marshal(event_id, ID),
|
||||
created_at = marshal(timestamp, Dt),
|
||||
source = marshal(id, SourceID),
|
||||
payload = #p2p_template_EventSinkPayload{
|
||||
sequence = marshal(event_id, EventID),
|
||||
occured_at = marshal(timestamp, EventDt),
|
||||
changes = [marshal(change, Payload)]
|
||||
changes = [marshal(change, Payload)]
|
||||
}
|
||||
}.
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
-module(ff_p2p_template_handler).
|
||||
|
||||
-behaviour(ff_woody_wrapper).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_p2p_template_thrift.hrl").
|
||||
@ -10,11 +11,11 @@
|
||||
%%
|
||||
%% ff_woody_wrapper callbacks
|
||||
%%
|
||||
-spec handle_function(woody:func(), woody:args(), woody:options()) ->
|
||||
{ok, woody:result()} | no_return().
|
||||
|
||||
-spec handle_function(woody:func(), woody:args(), woody:options()) -> {ok, woody:result()} | no_return().
|
||||
handle_function(Func, Args, Opts) ->
|
||||
scoper:scope(p2p_template, #{},
|
||||
scoper:scope(
|
||||
p2p_template,
|
||||
#{},
|
||||
fun() ->
|
||||
handle_function_(Func, Args, Opts)
|
||||
end
|
||||
@ -40,7 +41,6 @@ handle_function_('Create', [MarshaledParams, MarshaledContext], Opts) ->
|
||||
{error, Error} ->
|
||||
woody_error:raise(system, {internal, result_unexpected, woody_error:format_details(Error)})
|
||||
end;
|
||||
|
||||
handle_function_('Get', [ID, MarshaledEventRange], _Opts) ->
|
||||
ok = scoper:add_meta(#{id => ID}),
|
||||
EventRange = ff_codec:unmarshal(event_range, MarshaledEventRange),
|
||||
@ -53,7 +53,6 @@ handle_function_('Get', [ID, MarshaledEventRange], _Opts) ->
|
||||
{error, {unknown_p2p_template, _Ref}} ->
|
||||
woody_error:raise(business, #fistful_P2PTemplateNotFound{})
|
||||
end;
|
||||
|
||||
handle_function_('GetContext', [ID], _Opts) ->
|
||||
case p2p_template_machine:get(ID, {undefined, 0}) of
|
||||
{ok, Machine} ->
|
||||
@ -63,7 +62,6 @@ handle_function_('GetContext', [ID], _Opts) ->
|
||||
{error, {unknown_p2p_template, _Ref}} ->
|
||||
woody_error:raise(business, #fistful_P2PTemplateNotFound{})
|
||||
end;
|
||||
|
||||
handle_function_('SetBlocking', [ID, MarshaledBlocking], _Opts) ->
|
||||
ok = scoper:add_meta(#{id => ID}),
|
||||
Blocking = ff_p2p_template_codec:unmarshal(blocking, MarshaledBlocking),
|
||||
@ -73,7 +71,6 @@ handle_function_('SetBlocking', [ID, MarshaledBlocking], _Opts) ->
|
||||
{error, {unknown_p2p_template, _Ref}} ->
|
||||
woody_error:raise(business, #fistful_P2PTemplateNotFound{})
|
||||
end;
|
||||
|
||||
handle_function_('GetQuote', [ID, MarshaledParams], _Opts) ->
|
||||
ok = scoper:add_meta(#{id => ID}),
|
||||
Params = ff_p2p_template_codec:unmarshal_p2p_quote_params(MarshaledParams),
|
||||
@ -108,9 +105,7 @@ handle_function_('GetQuote', [ID, MarshaledParams], _Opts) ->
|
||||
woody_error:raise(business, #p2p_transfer_NoResourceInfo{type = Type});
|
||||
{error, Error} ->
|
||||
woody_error:raise(system, {internal, result_unexpected, woody_error:format_details(Error)})
|
||||
|
||||
end;
|
||||
|
||||
handle_function_('CreateTransfer', [ID, MarshaledParams, MarshaledContext], Opts) ->
|
||||
ok = scoper:add_meta(#{id => ID}),
|
||||
TransferID = MarshaledParams#p2p_template_P2PTemplateTransferParams.id,
|
||||
|
@ -21,67 +21,62 @@
|
||||
-type value_type() :: machinery_mg_schema:vt().
|
||||
-type context() :: machinery_mg_schema:context().
|
||||
|
||||
-type event() :: ff_machine:timestamped_event(p2p_template:event()).
|
||||
-type event() :: ff_machine:timestamped_event(p2p_template:event()).
|
||||
-type aux_state() :: ff_machine:auxst().
|
||||
-type call_args() :: term().
|
||||
-type call_response() :: term().
|
||||
|
||||
-type data() ::
|
||||
aux_state() |
|
||||
event() |
|
||||
call_args() |
|
||||
call_response().
|
||||
aux_state()
|
||||
| event()
|
||||
| call_args()
|
||||
| call_response().
|
||||
|
||||
%% machinery_mg_schema callbacks
|
||||
|
||||
-spec get_version(value_type()) ->
|
||||
machinery_mg_schema:version().
|
||||
-spec get_version(value_type()) -> machinery_mg_schema:version().
|
||||
get_version(event) ->
|
||||
?CURRENT_EVENT_FORMAT_VERSION;
|
||||
get_version(aux_state) ->
|
||||
undefined.
|
||||
|
||||
-spec marshal(type(), value(data()), context()) ->
|
||||
{machinery_msgpack:t(), context()}.
|
||||
-spec marshal(type(), value(data()), context()) -> {machinery_msgpack:t(), context()}.
|
||||
marshal({event, Format}, TimestampedChange, Context) ->
|
||||
marshal_event(Format, TimestampedChange, Context);
|
||||
marshal(T, V, C) when
|
||||
T =:= {args, init} orelse
|
||||
T =:= {args, call} orelse
|
||||
T =:= {args, repair} orelse
|
||||
T =:= {aux_state, undefined} orelse
|
||||
T =:= {response, call} orelse
|
||||
T =:= {response, {repair, success}} orelse
|
||||
T =:= {response, {repair, failure}}
|
||||
T =:= {args, call} orelse
|
||||
T =:= {args, repair} orelse
|
||||
T =:= {aux_state, undefined} orelse
|
||||
T =:= {response, call} orelse
|
||||
T =:= {response, {repair, success}} orelse
|
||||
T =:= {response, {repair, failure}}
|
||||
->
|
||||
machinery_mg_schema_generic:marshal(T, V, C).
|
||||
|
||||
-spec unmarshal(type(), machinery_msgpack:t(), context()) ->
|
||||
{data(), context()}.
|
||||
-spec unmarshal(type(), machinery_msgpack:t(), context()) -> {data(), context()}.
|
||||
unmarshal({event, FormatVersion}, EncodedChange, Context) ->
|
||||
unmarshal_event(FormatVersion, EncodedChange, Context);
|
||||
unmarshal(T, V, C) when
|
||||
T =:= {args, init} orelse
|
||||
T =:= {args, call} orelse
|
||||
T =:= {args, repair} orelse
|
||||
T =:= {aux_state, undefined} orelse
|
||||
T =:= {response, call} orelse
|
||||
T =:= {response, {repair, success}} orelse
|
||||
T =:= {response, {repair, failure}}
|
||||
T =:= {args, call} orelse
|
||||
T =:= {args, repair} orelse
|
||||
T =:= {aux_state, undefined} orelse
|
||||
T =:= {response, call} orelse
|
||||
T =:= {response, {repair, success}} orelse
|
||||
T =:= {response, {repair, failure}}
|
||||
->
|
||||
machinery_mg_schema_generic:unmarshal(T, V, C).
|
||||
|
||||
%% Internals
|
||||
|
||||
-spec marshal_event(machinery_mg_schema:version(), event(), context()) ->
|
||||
{machinery_msgpack:t(), context()}.
|
||||
-spec marshal_event(machinery_mg_schema:version(), event(), context()) -> {machinery_msgpack:t(), context()}.
|
||||
marshal_event(1, TimestampedChange, Context) ->
|
||||
ThriftChange = ff_p2p_template_codec:marshal(timestamped_change, TimestampedChange),
|
||||
Type = {struct, struct, {ff_proto_p2p_template_thrift, 'TimestampedChange'}},
|
||||
{{bin, ff_proto_utils:serialize(Type, ThriftChange)}, Context}.
|
||||
|
||||
-spec unmarshal_event(machinery_mg_schema:version(), machinery_msgpack:t(), context()) ->
|
||||
{event(), context()}.
|
||||
-spec unmarshal_event(machinery_mg_schema:version(), machinery_msgpack:t(), context()) -> {event(), context()}.
|
||||
unmarshal_event(1, EncodedChange, Context) ->
|
||||
{bin, EncodedThriftChange} = EncodedChange,
|
||||
Type = {struct, struct, {ff_proto_p2p_template_thrift, 'TimestampedChange'}},
|
||||
@ -92,18 +87,18 @@ unmarshal_event(1, EncodedChange, Context) ->
|
||||
|
||||
-ifdef(TEST).
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
-spec test() -> _.
|
||||
|
||||
% tests helpers
|
||||
|
||||
-spec marshal(type(), value(data())) ->
|
||||
machinery_msgpack:t().
|
||||
-spec marshal(type(), value(data())) -> machinery_msgpack:t().
|
||||
|
||||
marshal(Type, Value) ->
|
||||
{Result, _Context} = marshal(Type, Value, #{}),
|
||||
Result.
|
||||
|
||||
-spec unmarshal(type(), machinery_msgpack:t()) ->
|
||||
data().
|
||||
-spec unmarshal(type(), machinery_msgpack:t()) -> data().
|
||||
unmarshal(Type, Value) ->
|
||||
{Result, _Context} = unmarshal(Type, Value, #{}),
|
||||
Result.
|
||||
@ -129,11 +124,13 @@ created_v1_decoding_test() ->
|
||||
},
|
||||
Change = {created, P2PTemplate},
|
||||
Event = {ev, {{{2020, 5, 25}, {19, 19, 10}}, 293305}, Change},
|
||||
LegacyEvent = {bin, base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgwAAQwAAQsAAQAAAAh0cmFuc2Zlc"
|
||||
"gsAAgAAAAtpZGVudGl0eV9pZAsAAwAAABgyMDIwLTA1LTI1VDE3OjEyOjU3Ljk4NVoKAAQAAAAAAA"
|
||||
"AAewoABQAAAAAAAAFBDAAGDAABDAABCgABAAAAAAAAAHsMAAILAAEAAAADUlVCAAAAAAsABwAAAAtleHRlcm5hbF9pZAAAAAA="
|
||||
>>)},
|
||||
LegacyEvent =
|
||||
{bin,
|
||||
base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgwAAQwAAQsAAQAAAAh0cmFuc2Zlc"
|
||||
"gsAAgAAAAtpZGVudGl0eV9pZAsAAwAAABgyMDIwLTA1LTI1VDE3OjEyOjU3Ljk4NVoKAAQAAAAAAA"
|
||||
"AAewoABQAAAAAAAAFBDAAGDAABDAABCgABAAAAAAAAAHsMAAILAAEAAAADUlVCAAAAAAsABwAAAAtleHRlcm5hbF9pZAAAAAA="
|
||||
>>)},
|
||||
DecodedLegacy = unmarshal({event, 1}, LegacyEvent),
|
||||
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
|
||||
Decoded = unmarshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, ModernizedBinary),
|
||||
@ -143,12 +140,14 @@ created_v1_decoding_test() ->
|
||||
blocking_v1_decoding_test() ->
|
||||
Change = {blocking_changed, unblocked},
|
||||
Event = {ev, {{{2020, 5, 25}, {19, 19, 10}}, 293305}, Change},
|
||||
LegacyEvent = {bin, base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgwAAggAAQAAAAAAAAA="
|
||||
>>)},
|
||||
LegacyEvent =
|
||||
{bin,
|
||||
base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgwAAggAAQAAAAAAAAA="
|
||||
>>)},
|
||||
DecodedLegacy = unmarshal({event, 1}, LegacyEvent),
|
||||
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
|
||||
Decoded = unmarshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, ModernizedBinary),
|
||||
?assertEqual(Event, Decoded).
|
||||
|
||||
-endif.
|
||||
-endif.
|
||||
|
@ -12,8 +12,7 @@
|
||||
%% ff_woody_wrapper callbacks
|
||||
%%
|
||||
|
||||
-spec handle_function(woody:func(), woody:args(), options()) ->
|
||||
{ok, woody:result()} | no_return().
|
||||
-spec handle_function(woody:func(), woody:args(), options()) -> {ok, woody:result()} | no_return().
|
||||
handle_function('Repair', [ID, Scenario], _Opts) ->
|
||||
DecodedScenario = ff_codec:unmarshal(ff_p2p_template_codec, repair_scenario, Scenario),
|
||||
case p2p_template_machine:repair(ID, DecodedScenario) of
|
||||
|
@ -9,16 +9,13 @@
|
||||
|
||||
%% API
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) ->
|
||||
ff_codec:encoded_value().
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) -> ff_codec:encoded_value().
|
||||
marshal(change, {created, Adjustment}) ->
|
||||
{created, #p2p_adj_CreatedChange{adjustment = marshal(adjustment, Adjustment)}};
|
||||
marshal(change, {status_changed, Status}) ->
|
||||
{status_changed, #p2p_adj_StatusChange{status = marshal(status, Status)}};
|
||||
marshal(change, {p_transfer, TransferChange}) ->
|
||||
{transfer, #p2p_adj_TransferChange{payload = ff_p_transfer_codec:marshal(change, TransferChange)}};
|
||||
|
||||
marshal(adjustment, Adjustment) ->
|
||||
#p2p_adj_Adjustment{
|
||||
id = marshal(id, ff_adjustment:id(Adjustment)),
|
||||
@ -47,12 +44,10 @@ marshal(adjustment_state, Adjustment) ->
|
||||
operation_timestamp = marshal(timestamp_ms, ff_adjustment:operation_timestamp(Adjustment)),
|
||||
external_id = maybe_marshal(id, ff_adjustment:external_id(Adjustment))
|
||||
};
|
||||
|
||||
marshal(status, pending) ->
|
||||
{pending, #p2p_adj_Pending{}};
|
||||
marshal(status, succeeded) ->
|
||||
{succeeded, #p2p_adj_Succeeded{}};
|
||||
|
||||
marshal(changes_plan, Plan) ->
|
||||
#p2p_adj_ChangesPlan{
|
||||
new_cash_flow = maybe_marshal(cash_flow_change_plan, maps:get(new_cash_flow, Plan, undefined)),
|
||||
@ -69,26 +64,20 @@ marshal(status_change_plan, Plan) ->
|
||||
#p2p_adj_StatusChangePlan{
|
||||
new_status = ff_p2p_transfer_status_codec:marshal(status, maps:get(new_status, Plan))
|
||||
};
|
||||
|
||||
marshal(change_request, {change_status, Status}) ->
|
||||
{change_status, #p2p_adj_ChangeStatusRequest{
|
||||
new_status = ff_p2p_transfer_status_codec:marshal(status, Status)
|
||||
}};
|
||||
|
||||
marshal(T, V) ->
|
||||
ff_codec:marshal(T, V).
|
||||
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) ->
|
||||
ff_codec:decoded_value().
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) -> ff_codec:decoded_value().
|
||||
unmarshal(change, {created, #p2p_adj_CreatedChange{adjustment = Adjustment}}) ->
|
||||
{created, unmarshal(adjustment, Adjustment)};
|
||||
unmarshal(change, {status_changed, #p2p_adj_StatusChange{status = Status}}) ->
|
||||
{status_changed, unmarshal(status, Status)};
|
||||
unmarshal(change, {transfer, #p2p_adj_TransferChange{payload = TransferChange}}) ->
|
||||
{p_transfer, ff_p_transfer_codec:unmarshal(change, TransferChange)};
|
||||
|
||||
unmarshal(adjustment, Adjustment) ->
|
||||
#{
|
||||
id => unmarshal(id, Adjustment#p2p_adj_Adjustment.id),
|
||||
@ -100,19 +89,16 @@ unmarshal(adjustment, Adjustment) ->
|
||||
operation_timestamp => unmarshal(timestamp_ms, Adjustment#p2p_adj_Adjustment.operation_timestamp),
|
||||
external_id => maybe_unmarshal(id, Adjustment#p2p_adj_Adjustment.external_id)
|
||||
};
|
||||
|
||||
unmarshal(adjustment_params, Params) ->
|
||||
genlib_map:compact(#{
|
||||
id => unmarshal(id, Params#p2p_adj_AdjustmentParams.id),
|
||||
change => unmarshal(change_request, Params#p2p_adj_AdjustmentParams.change),
|
||||
external_id => maybe_unmarshal(id, Params#p2p_adj_AdjustmentParams.external_id)
|
||||
});
|
||||
|
||||
unmarshal(status, {pending, #p2p_adj_Pending{}}) ->
|
||||
pending;
|
||||
unmarshal(status, {succeeded, #p2p_adj_Succeeded{}}) ->
|
||||
succeeded;
|
||||
|
||||
unmarshal(changes_plan, Plan) ->
|
||||
genlib_map:compact(#{
|
||||
new_cash_flow => maybe_unmarshal(cash_flow_change_plan, Plan#p2p_adj_ChangesPlan.new_cash_flow),
|
||||
@ -130,11 +116,9 @@ unmarshal(status_change_plan, Plan) ->
|
||||
#{
|
||||
new_status => ff_p2p_transfer_status_codec:unmarshal(status, Status)
|
||||
};
|
||||
|
||||
unmarshal(change_request, {change_status, Request}) ->
|
||||
Status = Request#p2p_adj_ChangeStatusRequest.new_status,
|
||||
{change_status, ff_p2p_transfer_status_codec:unmarshal(status, Status)};
|
||||
|
||||
unmarshal(T, V) ->
|
||||
ff_codec:unmarshal(T, V).
|
||||
|
||||
@ -154,9 +138,11 @@ maybe_marshal(Type, Value) ->
|
||||
|
||||
-ifdef(TEST).
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
-spec test() -> _.
|
||||
|
||||
-spec adjustment_codec_test() -> _.
|
||||
|
||||
adjustment_codec_test() ->
|
||||
FinalCashFlow = #{
|
||||
postings => [
|
||||
|
@ -14,9 +14,7 @@
|
||||
|
||||
%% API
|
||||
|
||||
-spec unmarshal_p2p_quote_params(ff_proto_p2p_transfer_thrift:'QuoteParams'()) ->
|
||||
p2p_quote:params().
|
||||
|
||||
-spec unmarshal_p2p_quote_params(ff_proto_p2p_transfer_thrift:'QuoteParams'()) -> p2p_quote:params().
|
||||
unmarshal_p2p_quote_params(#p2p_transfer_QuoteParams{
|
||||
identity_id = IdentityID,
|
||||
sender = Sender,
|
||||
@ -32,7 +30,6 @@ unmarshal_p2p_quote_params(#p2p_transfer_QuoteParams{
|
||||
|
||||
-spec marshal_p2p_transfer_state(p2p_transfer:p2p_transfer_state(), ff_entity_context:context()) ->
|
||||
ff_proto_p2p_transfer_thrift:'P2PTransferState'().
|
||||
|
||||
marshal_p2p_transfer_state(P2PTransferState, Ctx) ->
|
||||
CashFlow = p2p_transfer:effective_final_cash_flow(P2PTransferState),
|
||||
Adjustments = p2p_transfer:adjustments(P2PTransferState),
|
||||
@ -62,7 +59,6 @@ marshal_p2p_transfer_state(P2PTransferState, Ctx) ->
|
||||
|
||||
-spec unmarshal_p2p_transfer_params(ff_proto_p2p_transfer_thrift:'P2PTransferParams'()) ->
|
||||
p2p_transfer_machine:params().
|
||||
|
||||
unmarshal_p2p_transfer_params(#p2p_transfer_P2PTransferParams{
|
||||
id = ID,
|
||||
identity_id = IdentityID,
|
||||
@ -88,9 +84,7 @@ unmarshal_p2p_transfer_params(#p2p_transfer_P2PTransferParams{
|
||||
metadata => maybe_unmarshal(ctx, Metadata)
|
||||
}).
|
||||
|
||||
-spec marshal_event(p2p_transfer_machine:event()) ->
|
||||
ff_proto_p2p_transfer_thrift:'Event'().
|
||||
|
||||
-spec marshal_event(p2p_transfer_machine:event()) -> ff_proto_p2p_transfer_thrift:'Event'().
|
||||
marshal_event({EventID, {ev, Timestamp, Change}}) ->
|
||||
#p2p_transfer_Event{
|
||||
event = ff_codec:marshal(event_id, EventID),
|
||||
@ -98,18 +92,14 @@ marshal_event({EventID, {ev, Timestamp, Change}}) ->
|
||||
change = marshal(change, Change)
|
||||
}.
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) ->
|
||||
ff_codec:encoded_value().
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) -> ff_codec:encoded_value().
|
||||
marshal({list, T}, V) ->
|
||||
[marshal(T, E) || E <- V];
|
||||
|
||||
marshal(timestamped_change, {ev, Timestamp, Change}) ->
|
||||
#p2p_transfer_TimestampedChange{
|
||||
change = marshal(change, Change),
|
||||
occured_at = ff_codec:marshal(timestamp, Timestamp)
|
||||
};
|
||||
|
||||
marshal(change, {created, Transfer}) ->
|
||||
{created, #p2p_transfer_CreatedChange{p2p_transfer = marshal(transfer, Transfer)}};
|
||||
marshal(change, {status_changed, Status}) ->
|
||||
@ -129,19 +119,21 @@ marshal(change, {adjustment, #{id := ID, payload := Payload}}) ->
|
||||
id = marshal(id, ID),
|
||||
payload = ff_p2p_transfer_adjustment_codec:marshal(change, Payload)
|
||||
}};
|
||||
|
||||
marshal(transfer, Transfer = #{
|
||||
id := ID,
|
||||
status := Status,
|
||||
owner := Owner,
|
||||
sender := Sender,
|
||||
receiver := Receiver,
|
||||
body := Body,
|
||||
domain_revision := DomainRevision,
|
||||
party_revision := PartyRevision,
|
||||
operation_timestamp := OperationTimestamp,
|
||||
created_at := CreatedAt
|
||||
}) ->
|
||||
marshal(
|
||||
transfer,
|
||||
Transfer = #{
|
||||
id := ID,
|
||||
status := Status,
|
||||
owner := Owner,
|
||||
sender := Sender,
|
||||
receiver := Receiver,
|
||||
body := Body,
|
||||
domain_revision := DomainRevision,
|
||||
party_revision := PartyRevision,
|
||||
operation_timestamp := OperationTimestamp,
|
||||
created_at := CreatedAt
|
||||
}
|
||||
) ->
|
||||
ExternalID = maps:get(external_id, Transfer, undefined),
|
||||
Quote = maps:get(quote, Transfer, undefined),
|
||||
Deadline = maps:get(deadline, Transfer, undefined),
|
||||
@ -165,7 +157,6 @@ marshal(transfer, Transfer = #{
|
||||
deadline = maybe_marshal(timestamp_ms, Deadline),
|
||||
metadata = maybe_marshal(ctx, Metadata)
|
||||
};
|
||||
|
||||
marshal(quote_state, Quote) ->
|
||||
#p2p_transfer_QuoteState{
|
||||
fees = maybe_marshal(fees, genlib_map:get(fees, Quote)),
|
||||
@ -186,24 +177,20 @@ marshal(quote, Quote) ->
|
||||
sender = marshal(compact_resource, maps:get(sender, Quote)),
|
||||
receiver = marshal(compact_resource, maps:get(receiver, Quote))
|
||||
};
|
||||
|
||||
marshal(compact_resource, {bank_card, BankCardResource}) ->
|
||||
#{
|
||||
token := Token,
|
||||
bin_data_id := BinDataId
|
||||
} = BankCardResource,
|
||||
marshal(resource, {bank_card, #{bank_card => #{token => Token, bin_data_id => BinDataId}}});
|
||||
|
||||
marshal(status, Status) ->
|
||||
ff_p2p_transfer_status_codec:marshal(status, Status);
|
||||
|
||||
marshal(participant, {raw, #{resource_params := ResourceParams} = Raw}) ->
|
||||
ContactInfo = maps:get(contact_info, Raw),
|
||||
{resource, #p2p_transfer_RawResource{
|
||||
resource = marshal(resource, ResourceParams),
|
||||
contact_info = marshal(contact_info, ContactInfo)
|
||||
}};
|
||||
|
||||
marshal(contact_info, ContactInfo) ->
|
||||
PhoneNumber = maps:get(phone_number, ContactInfo, undefined),
|
||||
Email = maps:get(email, ContactInfo, undefined),
|
||||
@ -211,7 +198,6 @@ marshal(contact_info, ContactInfo) ->
|
||||
phone_number = marshal(string, PhoneNumber),
|
||||
email = marshal(string, Email)
|
||||
};
|
||||
|
||||
marshal(client_info, ClientInfo) ->
|
||||
IPAddress = maps:get(ip_address, ClientInfo, undefined),
|
||||
Fingerprint = maps:get(fingerprint, ClientInfo, undefined),
|
||||
@ -219,25 +205,24 @@ marshal(client_info, ClientInfo) ->
|
||||
ip_address = marshal(string, IPAddress),
|
||||
fingerprint = marshal(string, Fingerprint)
|
||||
};
|
||||
|
||||
marshal(resource_got, {Sender, Receiver}) ->
|
||||
#p2p_transfer_ResourceChange{payload = {got, #p2p_transfer_ResourceGot{
|
||||
sender = marshal(resource, Sender),
|
||||
receiver = marshal(resource, Receiver)
|
||||
}}};
|
||||
|
||||
#p2p_transfer_ResourceChange{
|
||||
payload =
|
||||
{got, #p2p_transfer_ResourceGot{
|
||||
sender = marshal(resource, Sender),
|
||||
receiver = marshal(resource, Receiver)
|
||||
}}
|
||||
};
|
||||
marshal(risk_score, low) ->
|
||||
low;
|
||||
marshal(risk_score, high) ->
|
||||
high;
|
||||
marshal(risk_score, fatal) ->
|
||||
fatal;
|
||||
|
||||
marshal(route, #{provider_id := ProviderID}) ->
|
||||
#p2p_transfer_Route{
|
||||
provider_id = marshal(integer, ProviderID)
|
||||
provider_id = marshal(integer, ProviderID)
|
||||
};
|
||||
|
||||
marshal(session, {SessionID, started}) ->
|
||||
#p2p_transfer_SessionChange{
|
||||
id = marshal(id, SessionID),
|
||||
@ -246,53 +231,48 @@ marshal(session, {SessionID, started}) ->
|
||||
marshal(session, {SessionID, {finished, SessionResult}}) ->
|
||||
#p2p_transfer_SessionChange{
|
||||
id = marshal(id, SessionID),
|
||||
payload = {finished, #p2p_transfer_SessionFinished{
|
||||
result = marshal(session_result, SessionResult)
|
||||
}}
|
||||
payload =
|
||||
{finished, #p2p_transfer_SessionFinished{
|
||||
result = marshal(session_result, SessionResult)
|
||||
}}
|
||||
};
|
||||
|
||||
marshal(session_state, Session) ->
|
||||
#p2p_transfer_SessionState{
|
||||
id = marshal(id, maps:get(id, Session)),
|
||||
result = maybe_marshal(session_result, maps:get(result, Session, undefined))
|
||||
};
|
||||
|
||||
marshal(session_result, success) ->
|
||||
{succeeded, #p2p_transfer_SessionSucceeded{}};
|
||||
marshal(session_result, {failure, Failure}) ->
|
||||
{failed, #p2p_transfer_SessionFailed{failure = marshal(failure, Failure)}};
|
||||
|
||||
marshal(ctx, Ctx) ->
|
||||
maybe_marshal(context, Ctx);
|
||||
|
||||
marshal(T, V) ->
|
||||
ff_codec:marshal(T, V).
|
||||
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) ->
|
||||
ff_codec:decoded_value().
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) -> ff_codec:decoded_value().
|
||||
unmarshal({list, T}, V) ->
|
||||
[unmarshal(T, E) || E <- V];
|
||||
|
||||
unmarshal(repair_scenario, {add_events, #p2p_transfer_AddEventsRepair{events = Events, action = Action}}) ->
|
||||
{add_events, genlib_map:compact(#{
|
||||
events => unmarshal({list, change}, Events),
|
||||
action => maybe_unmarshal(complex_action, Action)
|
||||
})};
|
||||
|
||||
{add_events,
|
||||
genlib_map:compact(#{
|
||||
events => unmarshal({list, change}, Events),
|
||||
action => maybe_unmarshal(complex_action, Action)
|
||||
})};
|
||||
unmarshal(timestamped_change, TimestampedChange) ->
|
||||
Timestamp = ff_codec:unmarshal(timestamp, TimestampedChange#p2p_transfer_TimestampedChange.occured_at),
|
||||
Change = unmarshal(change, TimestampedChange#p2p_transfer_TimestampedChange.change),
|
||||
{ev, Timestamp, Change};
|
||||
|
||||
unmarshal(change, {created, #p2p_transfer_CreatedChange{p2p_transfer = Transfer}}) ->
|
||||
{created, unmarshal(transfer, Transfer)};
|
||||
unmarshal(change, {status_changed, #p2p_transfer_StatusChange{status = Status}}) ->
|
||||
{status_changed, unmarshal(status, Status)};
|
||||
unmarshal(change, {resource, #p2p_transfer_ResourceChange{
|
||||
payload = {got, #p2p_transfer_ResourceGot{sender = Sender, receiver = Receiver}
|
||||
}}}) ->
|
||||
unmarshal(
|
||||
change,
|
||||
{resource, #p2p_transfer_ResourceChange{
|
||||
payload = {got, #p2p_transfer_ResourceGot{sender = Sender, receiver = Receiver}}
|
||||
}}
|
||||
) ->
|
||||
unmarshal(resource_got, {Sender, Receiver});
|
||||
unmarshal(change, {risk_score, #p2p_transfer_RiskScoreChange{score = RiskScore}}) ->
|
||||
{risk_score_changed, unmarshal(risk_score, RiskScore)};
|
||||
@ -308,7 +288,6 @@ unmarshal(change, {adjustment, Change}) ->
|
||||
id => unmarshal(id, Change#p2p_transfer_AdjustmentChange.id),
|
||||
payload => Payload
|
||||
}};
|
||||
|
||||
unmarshal(transfer, #p2p_transfer_P2PTransfer{
|
||||
id = ID,
|
||||
owner = Owner,
|
||||
@ -344,7 +323,6 @@ unmarshal(transfer, #p2p_transfer_P2PTransfer{
|
||||
deadline => maybe_unmarshal(timestamp_ms, Deadline),
|
||||
metadata => maybe_unmarshal(ctx, Metadata)
|
||||
});
|
||||
|
||||
unmarshal(quote_state, Quote) ->
|
||||
genlib_map:compact(#{
|
||||
fees => maybe_unmarshal(fees, Quote#p2p_transfer_QuoteState.fees),
|
||||
@ -365,29 +343,28 @@ unmarshal(quote, Quote) ->
|
||||
sender => unmarshal(compact_resource, Quote#p2p_transfer_Quote.sender),
|
||||
receiver => unmarshal(compact_resource, Quote#p2p_transfer_Quote.receiver)
|
||||
});
|
||||
|
||||
unmarshal(compact_resource, Resource) ->
|
||||
{bank_card, #{bank_card := BankCard}} = unmarshal(resource, Resource),
|
||||
{bank_card, #{
|
||||
token => maps:get(token, BankCard),
|
||||
bin_data_id => maps:get(bin_data_id, BankCard)
|
||||
}};
|
||||
|
||||
unmarshal(status, Status) ->
|
||||
ff_p2p_transfer_status_codec:unmarshal(status, Status);
|
||||
|
||||
unmarshal(resource_got, {Sender, Receiver}) ->
|
||||
{resource_got, unmarshal(resource, Sender), unmarshal(resource, Receiver)};
|
||||
|
||||
unmarshal(participant, {resource, #p2p_transfer_RawResource{
|
||||
resource = Resource,
|
||||
contact_info = ContactInfo
|
||||
}}) ->
|
||||
{raw, genlib_map:compact(#{
|
||||
resource_params => unmarshal(resource, Resource),
|
||||
contact_info => unmarshal(contact_info, ContactInfo)
|
||||
})};
|
||||
|
||||
unmarshal(
|
||||
participant,
|
||||
{resource, #p2p_transfer_RawResource{
|
||||
resource = Resource,
|
||||
contact_info = ContactInfo
|
||||
}}
|
||||
) ->
|
||||
{raw,
|
||||
genlib_map:compact(#{
|
||||
resource_params => unmarshal(resource, Resource),
|
||||
contact_info => unmarshal(contact_info, ContactInfo)
|
||||
})};
|
||||
unmarshal(contact_info, #'ContactInfo'{
|
||||
phone_number = PhoneNumber,
|
||||
email = Email
|
||||
@ -396,7 +373,6 @@ unmarshal(contact_info, #'ContactInfo'{
|
||||
phone_number => maybe_unmarshal(string, PhoneNumber),
|
||||
email => maybe_unmarshal(string, Email)
|
||||
});
|
||||
|
||||
unmarshal(client_info, #'ClientInfo'{
|
||||
ip_address = IPAddress,
|
||||
fingerprint = Fingerprint
|
||||
@ -405,39 +381,32 @@ unmarshal(client_info, #'ClientInfo'{
|
||||
ip_address => maybe_unmarshal(string, IPAddress),
|
||||
fingerprint => maybe_unmarshal(string, Fingerprint)
|
||||
});
|
||||
|
||||
unmarshal(risk_score, low) ->
|
||||
low;
|
||||
unmarshal(risk_score, high) ->
|
||||
high;
|
||||
unmarshal(risk_score, fatal) ->
|
||||
fatal;
|
||||
|
||||
unmarshal(route, #p2p_transfer_Route{provider_id = ProviderID}) ->
|
||||
#{
|
||||
version => 1,
|
||||
provider_id => unmarshal(integer, ProviderID)
|
||||
};
|
||||
|
||||
unmarshal(session, {SessionID, {started, #p2p_transfer_SessionStarted{}}}) ->
|
||||
{SessionID, started};
|
||||
unmarshal(session, {SessionID, {finished, #p2p_transfer_SessionFinished{result = SessionResult}}}) ->
|
||||
{SessionID, {finished, unmarshal(session_result, SessionResult)}};
|
||||
|
||||
unmarshal(session_state, Session) ->
|
||||
genlib_map:compact(#{
|
||||
id => unmarshal(id, Session#p2p_transfer_SessionState.id),
|
||||
result => maybe_unmarshal(session_result, Session#p2p_transfer_SessionState.result)
|
||||
});
|
||||
|
||||
unmarshal(session_result, {succeeded, #p2p_transfer_SessionSucceeded{}}) ->
|
||||
success;
|
||||
unmarshal(session_result, {failed, #p2p_transfer_SessionFailed{failure = Failure}}) ->
|
||||
{failure, unmarshal(failure, Failure)};
|
||||
|
||||
unmarshal(ctx, Ctx) ->
|
||||
maybe_unmarshal(context, Ctx);
|
||||
|
||||
unmarshal(T, V) ->
|
||||
ff_codec:unmarshal(T, V).
|
||||
|
||||
@ -457,9 +426,11 @@ maybe_marshal(Type, Value) ->
|
||||
|
||||
-ifdef(TEST).
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
-spec test() -> _.
|
||||
|
||||
-spec p2p_transfer_codec_test() -> _.
|
||||
|
||||
p2p_transfer_codec_test() ->
|
||||
FinalCashFlow = #{
|
||||
postings => []
|
||||
@ -488,15 +459,19 @@ p2p_transfer_codec_test() ->
|
||||
external_id => genlib:unique()
|
||||
},
|
||||
|
||||
Resource = {bank_card, #{bank_card => #{
|
||||
token => genlib:unique(),
|
||||
bin_data_id => {binary, genlib:unique()}
|
||||
}}},
|
||||
Resource =
|
||||
{bank_card, #{
|
||||
bank_card => #{
|
||||
token => genlib:unique(),
|
||||
bin_data_id => {binary, genlib:unique()}
|
||||
}
|
||||
}},
|
||||
|
||||
Participant = {raw, #{
|
||||
resource_params => Resource,
|
||||
contact_info => #{}
|
||||
}},
|
||||
Participant =
|
||||
{raw, #{
|
||||
resource_params => Resource,
|
||||
contact_info => #{}
|
||||
}},
|
||||
|
||||
Quote = #{
|
||||
fees => #{
|
||||
@ -551,15 +526,19 @@ p2p_transfer_codec_test() ->
|
||||
|
||||
-spec p2p_timestamped_change_codec_test() -> _.
|
||||
p2p_timestamped_change_codec_test() ->
|
||||
Resource = {bank_card, #{bank_card => #{
|
||||
token => genlib:unique(),
|
||||
bin_data_id => {binary, genlib:unique()}
|
||||
}}},
|
||||
Resource =
|
||||
{bank_card, #{
|
||||
bank_card => #{
|
||||
token => genlib:unique(),
|
||||
bin_data_id => {binary, genlib:unique()}
|
||||
}
|
||||
}},
|
||||
|
||||
Participant = {raw, #{
|
||||
resource_params => Resource,
|
||||
contact_info => #{}
|
||||
}},
|
||||
Participant =
|
||||
{raw, #{
|
||||
resource_params => Resource,
|
||||
contact_info => #{}
|
||||
}},
|
||||
|
||||
P2PTransfer = #{
|
||||
version => 3,
|
||||
|
@ -9,32 +9,28 @@
|
||||
-type event() :: ff_eventsink_publisher:event(p2p_transfer:event()).
|
||||
-type sinkevent() :: ff_eventsink_publisher:sinkevent(ff_proto_p2p_transfer_thrift:'SinkEvent'()).
|
||||
|
||||
-spec publish_events(list(event())) ->
|
||||
list(sinkevent()).
|
||||
|
||||
-spec publish_events(list(event())) -> list(sinkevent()).
|
||||
publish_events(Events) ->
|
||||
[publish_event(Event) || Event <- Events].
|
||||
|
||||
-spec publish_event(event()) ->
|
||||
sinkevent().
|
||||
|
||||
-spec publish_event(event()) -> sinkevent().
|
||||
publish_event(#{
|
||||
id := ID,
|
||||
source_id := SourceID,
|
||||
event := {
|
||||
id := ID,
|
||||
source_id := SourceID,
|
||||
event := {
|
||||
EventID,
|
||||
Dt,
|
||||
{ev, EventDt, Payload}
|
||||
}
|
||||
}) ->
|
||||
#p2p_transfer_SinkEvent{
|
||||
id = marshal(event_id, ID),
|
||||
created_at = marshal(timestamp, Dt),
|
||||
source = marshal(id, SourceID),
|
||||
payload = #p2p_transfer_EventSinkPayload{
|
||||
sequence = marshal(event_id, EventID),
|
||||
id = marshal(event_id, ID),
|
||||
created_at = marshal(timestamp, Dt),
|
||||
source = marshal(id, SourceID),
|
||||
payload = #p2p_transfer_EventSinkPayload{
|
||||
sequence = marshal(event_id, EventID),
|
||||
occured_at = marshal(timestamp, EventDt),
|
||||
changes = [marshal(change, Payload)]
|
||||
changes = [marshal(change, Payload)]
|
||||
}
|
||||
}.
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
-module(ff_p2p_transfer_handler).
|
||||
|
||||
-behaviour(ff_woody_wrapper).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_p2p_transfer_thrift.hrl").
|
||||
@ -10,11 +11,11 @@
|
||||
%%
|
||||
%% ff_woody_wrapper callbacks
|
||||
%%
|
||||
-spec handle_function(woody:func(), woody:args(), woody:options()) ->
|
||||
{ok, woody:result()} | no_return().
|
||||
|
||||
-spec handle_function(woody:func(), woody:args(), woody:options()) -> {ok, woody:result()} | no_return().
|
||||
handle_function(Func, Args, Opts) ->
|
||||
scoper:scope(p2p_transfer, #{},
|
||||
scoper:scope(
|
||||
p2p_transfer,
|
||||
#{},
|
||||
fun() ->
|
||||
handle_function_(Func, Args, Opts)
|
||||
end
|
||||
@ -85,7 +86,6 @@ handle_function_('Create', [MarshaledParams, MarshaledContext], Opts) ->
|
||||
{error, Error} ->
|
||||
woody_error:raise(system, {internal, result_unexpected, woody_error:format_details(Error)})
|
||||
end;
|
||||
|
||||
handle_function_('Get', [ID, EventRange], _Opts) ->
|
||||
{After, Limit} = ff_codec:unmarshal(event_range, EventRange),
|
||||
ok = scoper:add_meta(#{id => ID}),
|
||||
@ -98,7 +98,6 @@ handle_function_('Get', [ID, EventRange], _Opts) ->
|
||||
{error, {unknown_p2p_transfer, _Ref}} ->
|
||||
woody_error:raise(business, #fistful_P2PNotFound{})
|
||||
end;
|
||||
|
||||
handle_function_('GetContext', [ID], _Opts) ->
|
||||
case p2p_transfer_machine:get(ID, {undefined, 0}) of
|
||||
{ok, Machine} ->
|
||||
@ -108,7 +107,6 @@ handle_function_('GetContext', [ID], _Opts) ->
|
||||
{error, {unknown_p2p_transfer, _Ref}} ->
|
||||
woody_error:raise(business, #fistful_P2PNotFound{})
|
||||
end;
|
||||
|
||||
handle_function_('GetEvents', [ID, EventRange], _Opts) ->
|
||||
ok = scoper:add_meta(#{id => ID}),
|
||||
case p2p_transfer_machine:events(ID, ff_codec:unmarshal(event_range, EventRange)) of
|
||||
@ -117,15 +115,16 @@ handle_function_('GetEvents', [ID, EventRange], _Opts) ->
|
||||
{error, {unknown_p2p_transfer, ID}} ->
|
||||
woody_error:raise(business, #fistful_P2PNotFound{})
|
||||
end;
|
||||
|
||||
handle_function_('CreateAdjustment', [ID, MarshaledParams], _Opts) ->
|
||||
Params = ff_p2p_transfer_adjustment_codec:unmarshal(adjustment_params, MarshaledParams),
|
||||
AdjustmentID = maps:get(id, Params),
|
||||
ok = scoper:add_meta(genlib_map:compact(#{
|
||||
id => ID,
|
||||
adjustment_id => AdjustmentID,
|
||||
external_id => maps:get(external_id, Params, undefined)
|
||||
})),
|
||||
ok = scoper:add_meta(
|
||||
genlib_map:compact(#{
|
||||
id => ID,
|
||||
adjustment_id => AdjustmentID,
|
||||
external_id => maps:get(external_id, Params, undefined)
|
||||
})
|
||||
),
|
||||
case p2p_transfer_machine:start_adjustment(ID, Params) of
|
||||
ok ->
|
||||
{ok, Machine} = p2p_transfer_machine:get(ID),
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -12,8 +12,7 @@
|
||||
%% ff_woody_wrapper callbacks
|
||||
%%
|
||||
|
||||
-spec handle_function(woody:func(), woody:args(), options()) ->
|
||||
{ok, woody:result()} | no_return().
|
||||
-spec handle_function(woody:func(), woody:args(), options()) -> {ok, woody:result()} | no_return().
|
||||
handle_function('Repair', [ID, Scenario], _Opts) ->
|
||||
DecodedScenario = ff_codec:unmarshal(ff_p2p_transfer_codec, repair_scenario, Scenario),
|
||||
case p2p_transfer_machine:repair(ID, DecodedScenario) of
|
||||
|
@ -9,30 +9,23 @@
|
||||
|
||||
%% API
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) ->
|
||||
ff_codec:encoded_value().
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) -> ff_codec:encoded_value().
|
||||
marshal(status, pending) ->
|
||||
{pending, #p2p_status_Pending{}};
|
||||
marshal(status, succeeded) ->
|
||||
{succeeded, #p2p_status_Succeeded{}};
|
||||
marshal(status, {failed, Failure}) ->
|
||||
{failed, #p2p_status_Failed{failure = marshal(failure, Failure)}};
|
||||
|
||||
marshal(T, V) ->
|
||||
ff_codec:marshal(T, V).
|
||||
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) ->
|
||||
ff_codec:decoded_value().
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) -> ff_codec:decoded_value().
|
||||
unmarshal(status, {pending, #p2p_status_Pending{}}) ->
|
||||
pending;
|
||||
unmarshal(status, {succeeded, #p2p_status_Succeeded{}}) ->
|
||||
succeeded;
|
||||
unmarshal(status, {failed, #p2p_status_Failed{failure = Failure}}) ->
|
||||
{failed, unmarshal(failure, Failure)};
|
||||
|
||||
unmarshal(T, V) ->
|
||||
ff_codec:unmarshal(T, V).
|
||||
|
||||
@ -40,9 +33,11 @@ unmarshal(T, V) ->
|
||||
|
||||
-ifdef(TEST).
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
-spec test() -> _.
|
||||
|
||||
-spec pending_symmetry_test() -> _.
|
||||
|
||||
pending_symmetry_test() ->
|
||||
Status = pending,
|
||||
?assertEqual(Status, unmarshal(status, marshal(status, Status))).
|
||||
@ -54,13 +49,14 @@ succeeded_symmetry_test() ->
|
||||
|
||||
-spec failed_symmetry_test() -> _.
|
||||
failed_symmetry_test() ->
|
||||
Status = {failed, #{
|
||||
code => <<"test">>,
|
||||
reason => <<"why not">>,
|
||||
sub => #{
|
||||
code => <<"sub">>
|
||||
}
|
||||
}},
|
||||
Status =
|
||||
{failed, #{
|
||||
code => <<"test">>,
|
||||
reason => <<"why not">>,
|
||||
sub => #{
|
||||
code => <<"sub">>
|
||||
}
|
||||
}},
|
||||
?assertEqual(Status, unmarshal(status, marshal(status, Status))).
|
||||
|
||||
-endif.
|
||||
|
@ -11,25 +11,20 @@
|
||||
|
||||
%% API
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) ->
|
||||
ff_codec:encoded_value().
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) -> ff_codec:encoded_value().
|
||||
marshal({list, T}, V) ->
|
||||
[marshal(T, E) || E <- V];
|
||||
|
||||
marshal(change, {created, Transfer}) ->
|
||||
{created, #transfer_CreatedChange{transfer = marshal(transfer, Transfer)}};
|
||||
marshal(change, {status_changed, Status}) ->
|
||||
{status_changed, #transfer_StatusChange{status = marshal(status, Status)}};
|
||||
marshal(change, {clock_updated, Clock}) ->
|
||||
{clock_updated, #transfer_ClockChange{clock = marshal(clock, Clock)}};
|
||||
|
||||
marshal(transfer, Transfer) ->
|
||||
#transfer_Transfer{
|
||||
id = marshal(id, ff_postings_transfer:id(Transfer)),
|
||||
cashflow = ff_cash_flow_codec:marshal(final_cash_flow, ff_postings_transfer:final_cash_flow(Transfer))
|
||||
};
|
||||
|
||||
marshal(status, created) ->
|
||||
{created, #transfer_Created{}};
|
||||
marshal(status, prepared) ->
|
||||
@ -38,37 +33,28 @@ marshal(status, committed) ->
|
||||
{committed, #transfer_Committed{}};
|
||||
marshal(status, cancelled) ->
|
||||
{cancelled, #transfer_Cancelled{}};
|
||||
|
||||
marshal(clock, Clock) ->
|
||||
ff_clock:marshal(transfer, Clock);
|
||||
|
||||
marshal(T, V) ->
|
||||
ff_codec:marshal(T, V).
|
||||
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) ->
|
||||
ff_codec:decoded_value().
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) -> ff_codec:decoded_value().
|
||||
unmarshal({list, T}, V) ->
|
||||
[unmarshal(T, E) || E <- V];
|
||||
|
||||
unmarshal(change, {created, #transfer_CreatedChange{transfer = Transfer}}) ->
|
||||
{created, unmarshal(transfer, Transfer)};
|
||||
unmarshal(change, {status_changed, #transfer_StatusChange{status = Status}}) ->
|
||||
{status_changed, unmarshal(status, Status)};
|
||||
unmarshal(change, {clock_updated, #transfer_ClockChange{clock = Clock}}) ->
|
||||
{clock_updated, unmarshal(clock, Clock)};
|
||||
|
||||
unmarshal(transfer, Transfer) ->
|
||||
#{
|
||||
id => ff_codec:unmarshal(id, Transfer#transfer_Transfer.id),
|
||||
id => ff_codec:unmarshal(id, Transfer#transfer_Transfer.id),
|
||||
final_cash_flow => ff_cash_flow_codec:unmarshal(final_cash_flow, Transfer#transfer_Transfer.cashflow)
|
||||
};
|
||||
|
||||
unmarshal(account_type, CashflowAccount) ->
|
||||
% Mapped to thrift type WalletCashFlowAccount as is
|
||||
CashflowAccount;
|
||||
|
||||
unmarshal(status, {created, #transfer_Created{}}) ->
|
||||
created;
|
||||
unmarshal(status, {prepared, #transfer_Prepared{}}) ->
|
||||
@ -77,9 +63,7 @@ unmarshal(status, {committed, #transfer_Committed{}}) ->
|
||||
committed;
|
||||
unmarshal(status, {cancelled, #transfer_Cancelled{}}) ->
|
||||
cancelled;
|
||||
|
||||
unmarshal(clock, Clock) ->
|
||||
ff_clock:unmarshal(transfer, Clock);
|
||||
|
||||
unmarshal(T, V) ->
|
||||
ff_codec:unmarshal(T, V).
|
||||
|
@ -6,24 +6,24 @@
|
||||
-spec serialize(thrift_type(), term()) -> binary().
|
||||
|
||||
-type thrift_type() ::
|
||||
thrift_base_type() |
|
||||
thrift_collection_type() |
|
||||
thrift_enum_type() |
|
||||
thrift_struct_type().
|
||||
thrift_base_type()
|
||||
| thrift_collection_type()
|
||||
| thrift_enum_type()
|
||||
| thrift_struct_type().
|
||||
|
||||
-type thrift_base_type() ::
|
||||
bool |
|
||||
double |
|
||||
i8 |
|
||||
i16 |
|
||||
i32 |
|
||||
i64 |
|
||||
string.
|
||||
bool
|
||||
| double
|
||||
| i8
|
||||
| i16
|
||||
| i32
|
||||
| i64
|
||||
| string.
|
||||
|
||||
-type thrift_collection_type() ::
|
||||
{list, thrift_type()} |
|
||||
{set, thrift_type()} |
|
||||
{map, thrift_type(), thrift_type()}.
|
||||
{list, thrift_type()}
|
||||
| {set, thrift_type()}
|
||||
| {map, thrift_type(), thrift_type()}.
|
||||
|
||||
-type thrift_enum_type() ::
|
||||
{enum, thrift_type_ref()}.
|
||||
@ -54,9 +54,7 @@ serialize(Type, Data) ->
|
||||
erlang:error({thrift, {protocol, Reason}})
|
||||
end.
|
||||
|
||||
-spec deserialize(thrift_type(), binary()) ->
|
||||
term().
|
||||
|
||||
-spec deserialize(thrift_type(), binary()) -> term().
|
||||
deserialize(Type, Data) ->
|
||||
{ok, Trans} = thrift_membuffer_transport:new(Data),
|
||||
{ok, Proto} = new_protocol(Trans),
|
||||
|
@ -1,4 +1,5 @@
|
||||
-module(ff_provider_handler).
|
||||
|
||||
-behaviour(ff_woody_wrapper).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_provider_thrift.hrl").
|
||||
@ -9,11 +10,11 @@
|
||||
%%
|
||||
%% ff_woody_wrapper callbacks
|
||||
%%
|
||||
-spec handle_function(woody:func(), woody:args(), woody:options()) ->
|
||||
{ok, woody:result()} | no_return().
|
||||
|
||||
-spec handle_function(woody:func(), woody:args(), woody:options()) -> {ok, woody:result()} | no_return().
|
||||
handle_function(Func, Args, Opts) ->
|
||||
scoper:scope(provider, #{},
|
||||
scoper:scope(
|
||||
provider,
|
||||
#{},
|
||||
fun() ->
|
||||
handle_function_(Func, Args, Opts)
|
||||
end
|
||||
@ -31,21 +32,16 @@ handle_function_('GetProvider', [ID], _Opts) ->
|
||||
{error, notfound} ->
|
||||
woody_error:raise(business, #fistful_ProviderNotFound{})
|
||||
end;
|
||||
|
||||
handle_function_('ListProviders', _, _Opts) ->
|
||||
{ok, marshal_providers(ff_provider:list())}.
|
||||
|
||||
%%
|
||||
|
||||
-spec marshal_providers([ff_provider:provider()]) ->
|
||||
[ff_proto_provider_thrift:'Provider'()].
|
||||
|
||||
-spec marshal_providers([ff_provider:provider()]) -> [ff_proto_provider_thrift:'Provider'()].
|
||||
marshal_providers(Providers) when is_list(Providers) ->
|
||||
lists:map(fun(Provider) -> marshal_provider(Provider) end, Providers).
|
||||
|
||||
-spec marshal_provider(ff_provider:provider()) ->
|
||||
ff_proto_provider_thrift:'Provider'().
|
||||
|
||||
-spec marshal_provider(ff_provider:provider()) -> ff_proto_provider_thrift:'Provider'().
|
||||
marshal_provider(Provider) ->
|
||||
ID = ff_provider:id(Provider),
|
||||
Name = ff_provider:name(Provider),
|
||||
@ -66,13 +62,10 @@ marshal_residence(Residence) ->
|
||||
|
||||
-spec marshal_identity_classes(ff_provider:identity_classes()) ->
|
||||
#{ff_proto_provider_thrift:'IdentityClassID'() => ff_proto_provider_thrift:'IdentityClass'()}.
|
||||
|
||||
marshal_identity_classes(Map) ->
|
||||
maps:map(fun(_ClassID, Class) -> marshal_identity_class(Class) end, Map).
|
||||
|
||||
-spec marshal_identity_class(ff_identity_class:class()) ->
|
||||
ff_proto_provider_thrift:'IdentityClass'().
|
||||
|
||||
-spec marshal_identity_class(ff_identity_class:class()) -> ff_proto_provider_thrift:'IdentityClass'().
|
||||
marshal_identity_class(Class) ->
|
||||
#provider_IdentityClass{
|
||||
id = ff_identity_class:id(Class),
|
||||
|
@ -25,41 +25,34 @@
|
||||
|
||||
-export([init/1]).
|
||||
|
||||
-define(DEFAULT_HANDLING_TIMEOUT, 30000). % 30 seconds
|
||||
% 30 seconds
|
||||
-define(DEFAULT_HANDLING_TIMEOUT, 30000).
|
||||
|
||||
%%
|
||||
|
||||
-spec start() ->
|
||||
{ok, _}.
|
||||
|
||||
-spec start() -> {ok, _}.
|
||||
start() ->
|
||||
application:ensure_all_started(?MODULE).
|
||||
|
||||
%% Application
|
||||
|
||||
-spec start(normal, any()) ->
|
||||
{ok, pid()} | {error, any()}.
|
||||
|
||||
-spec start(normal, any()) -> {ok, pid()} | {error, any()}.
|
||||
start(_StartType, _StartArgs) ->
|
||||
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
|
||||
|
||||
-spec stop(any()) ->
|
||||
ok.
|
||||
|
||||
-spec stop(any()) -> ok.
|
||||
stop(_State) ->
|
||||
ok.
|
||||
|
||||
%% Supervisor
|
||||
|
||||
-spec init([]) ->
|
||||
{ok, {supervisor:sup_flags(), [supervisor:child_spec()]}}.
|
||||
|
||||
-spec init([]) -> {ok, {supervisor:sup_flags(), [supervisor:child_spec()]}}.
|
||||
init([]) ->
|
||||
IpEnv = genlib_app:env(?MODULE, ip, "::1"),
|
||||
Port = genlib_app:env(?MODULE, port, 8022),
|
||||
HealthCheck = genlib_app:env(?MODULE, health_check, #{}),
|
||||
WoodyOptsEnv = genlib_app:env(?MODULE, woody_opts, #{}),
|
||||
RouteOptsEnv = genlib_app:env(?MODULE, route_opts, #{}),
|
||||
IpEnv = genlib_app:env(?MODULE, ip, "::1"),
|
||||
Port = genlib_app:env(?MODULE, port, 8022),
|
||||
HealthCheck = genlib_app:env(?MODULE, health_check, #{}),
|
||||
WoodyOptsEnv = genlib_app:env(?MODULE, woody_opts, #{}),
|
||||
RouteOptsEnv = genlib_app:env(?MODULE, route_opts, #{}),
|
||||
|
||||
PartyClient = party_client:create_client(),
|
||||
DefaultTimeout = genlib_app:env(?MODULE, default_woody_handling_timeout, ?DEFAULT_HANDLING_TIMEOUT),
|
||||
@ -68,51 +61,52 @@ init([]) ->
|
||||
default_handling_timeout => DefaultTimeout
|
||||
},
|
||||
|
||||
{ok, Ip} = inet:parse_address(IpEnv),
|
||||
WoodyOpts = maps:with([net_opts, handler_limits], WoodyOptsEnv),
|
||||
{ok, Ip} = inet:parse_address(IpEnv),
|
||||
WoodyOpts = maps:with([net_opts, handler_limits], WoodyOptsEnv),
|
||||
EventHandlerOpts = genlib_app:env(?MODULE, scoper_event_handler_options, #{}),
|
||||
RouteOpts = RouteOptsEnv#{event_handler => {scoper_woody_event_handler, EventHandlerOpts}},
|
||||
RouteOpts = RouteOptsEnv#{event_handler => {scoper_woody_event_handler, EventHandlerOpts}},
|
||||
|
||||
% TODO
|
||||
% - Make it palatable
|
||||
{Backends, MachineHandlers, ModernizerHandlers} = lists:unzip3([
|
||||
contruct_backend_childspec('ff/identity' , ff_identity_machine , PartyClient),
|
||||
contruct_backend_childspec('ff/wallet_v2' , ff_wallet_machine , PartyClient),
|
||||
contruct_backend_childspec('ff/source_v1' , ff_source_machine , PartyClient),
|
||||
contruct_backend_childspec('ff/destination_v2' , ff_destination_machine , PartyClient),
|
||||
contruct_backend_childspec('ff/deposit_v1' , ff_deposit_machine , PartyClient),
|
||||
contruct_backend_childspec('ff/withdrawal_v2' , ff_withdrawal_machine , PartyClient),
|
||||
contruct_backend_childspec('ff/withdrawal/session_v2' , ff_withdrawal_session_machine , PartyClient),
|
||||
contruct_backend_childspec('ff/p2p_transfer_v1' , p2p_transfer_machine , PartyClient),
|
||||
contruct_backend_childspec('ff/p2p_transfer/session_v1' , p2p_session_machine , PartyClient),
|
||||
contruct_backend_childspec('ff/w2w_transfer_v1' , w2w_transfer_machine , PartyClient),
|
||||
contruct_backend_childspec('ff/p2p_template_v1' , p2p_template_machine , PartyClient)
|
||||
contruct_backend_childspec('ff/identity', ff_identity_machine, PartyClient),
|
||||
contruct_backend_childspec('ff/wallet_v2', ff_wallet_machine, PartyClient),
|
||||
contruct_backend_childspec('ff/source_v1', ff_source_machine, PartyClient),
|
||||
contruct_backend_childspec('ff/destination_v2', ff_destination_machine, PartyClient),
|
||||
contruct_backend_childspec('ff/deposit_v1', ff_deposit_machine, PartyClient),
|
||||
contruct_backend_childspec('ff/withdrawal_v2', ff_withdrawal_machine, PartyClient),
|
||||
contruct_backend_childspec('ff/withdrawal/session_v2', ff_withdrawal_session_machine, PartyClient),
|
||||
contruct_backend_childspec('ff/p2p_transfer_v1', p2p_transfer_machine, PartyClient),
|
||||
contruct_backend_childspec('ff/p2p_transfer/session_v1', p2p_session_machine, PartyClient),
|
||||
contruct_backend_childspec('ff/w2w_transfer_v1', w2w_transfer_machine, PartyClient),
|
||||
contruct_backend_childspec('ff/p2p_template_v1', p2p_template_machine, PartyClient)
|
||||
]),
|
||||
ok = application:set_env(fistful, backends, maps:from_list(Backends)),
|
||||
|
||||
Services = [
|
||||
{fistful_admin, ff_server_admin_handler},
|
||||
{fistful_provider, ff_provider_handler},
|
||||
{ff_p2p_adapter_host, ff_p2p_adapter_host},
|
||||
{ff_withdrawal_adapter_host, ff_withdrawal_adapter_host},
|
||||
{wallet_management, ff_wallet_handler},
|
||||
{identity_management, ff_identity_handler},
|
||||
{destination_management, ff_destination_handler},
|
||||
{source_management, ff_source_handler},
|
||||
{withdrawal_management, ff_withdrawal_handler},
|
||||
{withdrawal_session_management, ff_withdrawal_session_handler},
|
||||
{deposit_management, ff_deposit_handler},
|
||||
{withdrawal_session_repairer, ff_withdrawal_session_repair},
|
||||
{withdrawal_repairer, ff_withdrawal_repair},
|
||||
{deposit_repairer, ff_deposit_repair},
|
||||
{p2p_transfer_management, ff_p2p_transfer_handler},
|
||||
{p2p_transfer_repairer, ff_p2p_transfer_repair},
|
||||
{p2p_session_management, ff_p2p_session_handler},
|
||||
{p2p_session_repairer, ff_p2p_session_repair},
|
||||
{p2p_template_management, ff_p2p_template_handler},
|
||||
{w2w_transfer_management, ff_w2w_transfer_handler},
|
||||
{w2w_transfer_repairer, ff_w2w_transfer_repair}
|
||||
] ++ get_eventsink_handlers(),
|
||||
Services =
|
||||
[
|
||||
{fistful_admin, ff_server_admin_handler},
|
||||
{fistful_provider, ff_provider_handler},
|
||||
{ff_p2p_adapter_host, ff_p2p_adapter_host},
|
||||
{ff_withdrawal_adapter_host, ff_withdrawal_adapter_host},
|
||||
{wallet_management, ff_wallet_handler},
|
||||
{identity_management, ff_identity_handler},
|
||||
{destination_management, ff_destination_handler},
|
||||
{source_management, ff_source_handler},
|
||||
{withdrawal_management, ff_withdrawal_handler},
|
||||
{withdrawal_session_management, ff_withdrawal_session_handler},
|
||||
{deposit_management, ff_deposit_handler},
|
||||
{withdrawal_session_repairer, ff_withdrawal_session_repair},
|
||||
{withdrawal_repairer, ff_withdrawal_repair},
|
||||
{deposit_repairer, ff_deposit_repair},
|
||||
{p2p_transfer_management, ff_p2p_transfer_handler},
|
||||
{p2p_transfer_repairer, ff_p2p_transfer_repair},
|
||||
{p2p_session_management, ff_p2p_session_handler},
|
||||
{p2p_session_repairer, ff_p2p_session_repair},
|
||||
{p2p_template_management, ff_p2p_template_handler},
|
||||
{w2w_transfer_management, ff_w2w_transfer_handler},
|
||||
{w2w_transfer_repairer, ff_w2w_transfer_repair}
|
||||
] ++ get_eventsink_handlers(),
|
||||
WoodyHandlers = [get_handler(Service, Handler, WrapperOpts) || {Service, Handler} <- Services],
|
||||
|
||||
ServicesChildSpec = woody_server:child_spec(
|
||||
@ -120,10 +114,10 @@ init([]) ->
|
||||
maps:merge(
|
||||
WoodyOpts,
|
||||
#{
|
||||
ip => Ip,
|
||||
port => Port,
|
||||
handlers => WoodyHandlers,
|
||||
event_handler => scoper_woody_event_handler,
|
||||
ip => Ip,
|
||||
port => Port,
|
||||
handlers => WoodyHandlers,
|
||||
event_handler => scoper_woody_event_handler,
|
||||
additional_routes =>
|
||||
machinery_mg_backend:get_routes(MachineHandlers, RouteOpts) ++
|
||||
machinery_modernizer_mg_backend:get_routes(ModernizerHandlers, RouteOpts) ++
|
||||
@ -136,16 +130,12 @@ init([]) ->
|
||||
% - Zero thoughts given while defining this strategy.
|
||||
{ok, {#{strategy => one_for_one}, [PartyClientSpec, ServicesChildSpec]}}.
|
||||
|
||||
-spec enable_health_logging(erl_health:check()) ->
|
||||
erl_health:check().
|
||||
|
||||
-spec enable_health_logging(erl_health:check()) -> erl_health:check().
|
||||
enable_health_logging(Check) ->
|
||||
EvHandler = {erl_health_event_handler, []},
|
||||
maps:map(fun (_, V = {_, _, _}) -> #{runner => V, event_handler => EvHandler} end, Check).
|
||||
|
||||
-spec get_handler(ff_services:service_name(), woody:handler(_), map()) ->
|
||||
woody:http_handler(woody:th_handler()).
|
||||
maps:map(fun(_, V = {_, _, _}) -> #{runner => V, event_handler => EvHandler} end, Check).
|
||||
|
||||
-spec get_handler(ff_services:service_name(), woody:handler(_), map()) -> woody:http_handler(woody:th_handler()).
|
||||
get_handler(Service, Handler, WrapperOpts) ->
|
||||
{Path, ServiceSpec} = ff_services:get_service_spec(Service),
|
||||
{Path, {ServiceSpec, wrap_handler(Handler, WrapperOpts)}}.
|
||||
@ -159,22 +149,21 @@ contruct_backend_childspec(NS, Handler, PartyClient) ->
|
||||
}.
|
||||
|
||||
construct_machinery_backend_spec(NS, Schema) ->
|
||||
{NS, {machinery_mg_backend, #{
|
||||
schema => Schema,
|
||||
client => get_service_client(automaton)
|
||||
}}}.
|
||||
{NS,
|
||||
{machinery_mg_backend, #{
|
||||
schema => Schema,
|
||||
client => get_service_client(automaton)
|
||||
}}}.
|
||||
|
||||
construct_machinery_handler_spec(NS, Handler, Schema, PartyClient) ->
|
||||
{{fistful, #{handler => Handler, party_client => PartyClient}},
|
||||
#{
|
||||
path => ff_string:join(["/v1/stateproc/", NS]),
|
||||
backend_config => #{schema => Schema}
|
||||
}
|
||||
}.
|
||||
{{fistful, #{handler => Handler, party_client => PartyClient}}, #{
|
||||
path => ff_string:join(["/v1/stateproc/", NS]),
|
||||
backend_config => #{schema => Schema}
|
||||
}}.
|
||||
|
||||
construct_machinery_modernizer_spec(NS, Schema) ->
|
||||
#{
|
||||
path => ff_string:join(["/v1/modernizer/", NS]),
|
||||
path => ff_string:join(["/v1/modernizer/", NS]),
|
||||
backend_config => #{schema => Schema}
|
||||
}.
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
-module(ff_server_admin_handler).
|
||||
|
||||
-behaviour(ff_woody_wrapper).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_fistful_admin_thrift.hrl").
|
||||
@ -10,10 +11,11 @@
|
||||
%% ff_woody_wrapper callbacks
|
||||
%%
|
||||
|
||||
-spec handle_function(woody:func(), woody:args(), woody:options()) ->
|
||||
{ok, woody:result()} | no_return().
|
||||
-spec handle_function(woody:func(), woody:args(), woody:options()) -> {ok, woody:result()} | no_return().
|
||||
handle_function(Func, Args, Opts) ->
|
||||
scoper:scope(fistful_admin, #{},
|
||||
scoper:scope(
|
||||
fistful_admin,
|
||||
#{},
|
||||
fun() ->
|
||||
handle_function_(Func, Args, Opts)
|
||||
end
|
||||
@ -25,13 +27,17 @@ handle_function(Func, Args, Opts) ->
|
||||
|
||||
handle_function_('CreateSource', [Params], Opts) ->
|
||||
SourceID = Params#ff_admin_SourceParams.id,
|
||||
case ff_source_machine:create(#{
|
||||
id => SourceID,
|
||||
identity => Params#ff_admin_SourceParams.identity_id,
|
||||
name => Params#ff_admin_SourceParams.name,
|
||||
currency => ff_codec:unmarshal(currency_ref, Params#ff_admin_SourceParams.currency),
|
||||
resource => ff_source_codec:unmarshal(resource, Params#ff_admin_SourceParams.resource)
|
||||
}, ff_entity_context:new())
|
||||
case
|
||||
ff_source_machine:create(
|
||||
#{
|
||||
id => SourceID,
|
||||
identity => Params#ff_admin_SourceParams.identity_id,
|
||||
name => Params#ff_admin_SourceParams.name,
|
||||
currency => ff_codec:unmarshal(currency_ref, Params#ff_admin_SourceParams.currency),
|
||||
resource => ff_source_codec:unmarshal(resource, Params#ff_admin_SourceParams.resource)
|
||||
},
|
||||
ff_entity_context:new()
|
||||
)
|
||||
of
|
||||
ok ->
|
||||
handle_function_('GetSource', [SourceID], Opts);
|
||||
@ -53,10 +59,10 @@ handle_function_('GetSource', [ID], _Opts) ->
|
||||
handle_function_('CreateDeposit', [Params], Opts) ->
|
||||
DepositID = Params#ff_admin_DepositParams.id,
|
||||
DepositParams = #{
|
||||
id => DepositID,
|
||||
source_id => Params#ff_admin_DepositParams.source,
|
||||
wallet_id => Params#ff_admin_DepositParams.destination,
|
||||
body => ff_codec:unmarshal(cash, Params#ff_admin_DepositParams.body)
|
||||
id => DepositID,
|
||||
source_id => Params#ff_admin_DepositParams.source,
|
||||
wallet_id => Params#ff_admin_DepositParams.destination,
|
||||
body => ff_codec:unmarshal(cash, Params#ff_admin_DepositParams.body)
|
||||
},
|
||||
case handle_create_result(ff_deposit_machine:create(DepositParams, ff_entity_context:new())) of
|
||||
ok ->
|
||||
@ -91,4 +97,3 @@ handle_create_result({error, exists}) ->
|
||||
ok;
|
||||
handle_create_result({error, _Reason} = Error) ->
|
||||
Error.
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
%%
|
||||
|
||||
-type service() :: woody:service().
|
||||
-type service() :: woody:service().
|
||||
-type service_name() :: atom().
|
||||
-type service_spec() :: {Path :: string(), service()}.
|
||||
|
||||
|
@ -13,30 +13,28 @@
|
||||
|
||||
%% API
|
||||
|
||||
-spec unmarshal_source_params(ff_proto_source_thrift:'SourceParams'()) ->
|
||||
ff_source:params().
|
||||
|
||||
-spec unmarshal_source_params(ff_proto_source_thrift:'SourceParams'()) -> ff_source:params().
|
||||
unmarshal_source_params(Params) ->
|
||||
genlib_map:compact(#{
|
||||
id => unmarshal(id, Params#src_SourceParams.id),
|
||||
identity => unmarshal(id, Params#src_SourceParams.identity_id),
|
||||
name => unmarshal(string, Params#src_SourceParams.name),
|
||||
currency => unmarshal(currency_ref, Params#src_SourceParams.currency),
|
||||
resource => unmarshal(resource, Params#src_SourceParams.resource),
|
||||
id => unmarshal(id, Params#src_SourceParams.id),
|
||||
identity => unmarshal(id, Params#src_SourceParams.identity_id),
|
||||
name => unmarshal(string, Params#src_SourceParams.name),
|
||||
currency => unmarshal(currency_ref, Params#src_SourceParams.currency),
|
||||
resource => unmarshal(resource, Params#src_SourceParams.resource),
|
||||
external_id => maybe_unmarshal(id, Params#src_SourceParams.external_id),
|
||||
metadata => maybe_unmarshal(ctx, Params#src_SourceParams.metadata)
|
||||
metadata => maybe_unmarshal(ctx, Params#src_SourceParams.metadata)
|
||||
}).
|
||||
|
||||
-spec marshal_source_state(ff_source:source_state(), ff_entity_context:context()) ->
|
||||
ff_proto_source_thrift:'SourceState'().
|
||||
|
||||
marshal_source_state(SourceState, Context) ->
|
||||
Blocking = case ff_source:is_accessible(SourceState) of
|
||||
{ok, accessible} ->
|
||||
unblocked;
|
||||
_ ->
|
||||
blocked
|
||||
end,
|
||||
Blocking =
|
||||
case ff_source:is_accessible(SourceState) of
|
||||
{ok, accessible} ->
|
||||
unblocked;
|
||||
_ ->
|
||||
blocked
|
||||
end,
|
||||
#src_SourceState{
|
||||
id = maybe_marshal(id, ff_source:id(SourceState)),
|
||||
name = marshal(string, ff_source:name(SourceState)),
|
||||
@ -50,9 +48,7 @@ marshal_source_state(SourceState, Context) ->
|
||||
context = maybe_marshal(ctx, Context)
|
||||
}.
|
||||
|
||||
-spec marshal_event(ff_source_machine:event()) ->
|
||||
ff_proto_source_thrift:'Event'().
|
||||
|
||||
-spec marshal_event(ff_source_machine:event()) -> ff_proto_source_thrift:'Event'().
|
||||
marshal_event({EventID, {ev, Timestamp, Change}}) ->
|
||||
#src_Event{
|
||||
event_id = ff_codec:marshal(event_id, EventID),
|
||||
@ -60,33 +56,32 @@ marshal_event({EventID, {ev, Timestamp, Change}}) ->
|
||||
change = marshal(change, Change)
|
||||
}.
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) ->
|
||||
ff_codec:encoded_value().
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) -> ff_codec:encoded_value().
|
||||
marshal(timestamped_change, {ev, Timestamp, Change}) ->
|
||||
#src_TimestampedChange{
|
||||
change = marshal(change, Change),
|
||||
occured_at = ff_codec:marshal(timestamp, Timestamp)
|
||||
};
|
||||
|
||||
marshal(change, {created, Source}) ->
|
||||
{created, marshal(source, Source)};
|
||||
marshal(change, {account, AccountChange}) ->
|
||||
{account, marshal(account_change, AccountChange)};
|
||||
marshal(change, {status_changed, Status}) ->
|
||||
{status, #src_StatusChange{status = marshal(status, Status)}};
|
||||
|
||||
marshal(source, Source = #{
|
||||
name := Name,
|
||||
resource := Resource
|
||||
}) ->
|
||||
marshal(
|
||||
source,
|
||||
Source = #{
|
||||
name := Name,
|
||||
resource := Resource
|
||||
}
|
||||
) ->
|
||||
#src_Source{
|
||||
id = marshal(id, ff_source:id(Source)),
|
||||
status = maybe_marshal(status, ff_source:status(Source)),
|
||||
name = marshal(string, Name),
|
||||
resource = marshal(resource, Resource),
|
||||
external_id = maybe_marshal(id, maps:get(external_id, Source, undefined)),
|
||||
created_at = maybe_marshal(timestamp_ms, maps:get(created_at, Source, undefined)),
|
||||
created_at = maybe_marshal(timestamp_ms, maps:get(created_at, Source, undefined)),
|
||||
metadata = maybe_marshal(context, maps:get(metadata, Source, undefined))
|
||||
};
|
||||
marshal(resource, #{type := internal} = Internal) ->
|
||||
@ -96,43 +91,34 @@ marshal(internal, Internal) ->
|
||||
#src_Internal{
|
||||
details = marshal(string, Details)
|
||||
};
|
||||
|
||||
marshal(status, unauthorized) ->
|
||||
{unauthorized, #src_Unauthorized{}};
|
||||
marshal(status, authorized) ->
|
||||
{authorized, #src_Authorized{}};
|
||||
|
||||
marshal(ctx, Ctx) ->
|
||||
marshal(context, Ctx);
|
||||
|
||||
marshal(T, V) ->
|
||||
ff_codec:marshal(T, V).
|
||||
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) ->
|
||||
ff_codec:decoded_value().
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) -> ff_codec:decoded_value().
|
||||
unmarshal({list, T}, V) ->
|
||||
[unmarshal(T, E) || E <- V];
|
||||
|
||||
unmarshal(repair_scenario, {add_events, #src_AddEventsRepair{events = Events, action = Action}}) ->
|
||||
{add_events, genlib_map:compact(#{
|
||||
events => unmarshal({list, change}, Events),
|
||||
action => maybe_unmarshal(complex_action, Action)
|
||||
})};
|
||||
|
||||
{add_events,
|
||||
genlib_map:compact(#{
|
||||
events => unmarshal({list, change}, Events),
|
||||
action => maybe_unmarshal(complex_action, Action)
|
||||
})};
|
||||
unmarshal(timestamped_change, TimestampedChange) ->
|
||||
Timestamp = ff_codec:unmarshal(timestamp, TimestampedChange#src_TimestampedChange.occured_at),
|
||||
Change = unmarshal(change, TimestampedChange#src_TimestampedChange.change),
|
||||
{ev, Timestamp, Change};
|
||||
|
||||
unmarshal(change, {created, Source}) ->
|
||||
{created, unmarshal(source, Source)};
|
||||
unmarshal(change, {account, AccountChange}) ->
|
||||
{account, unmarshal(account_change, AccountChange)};
|
||||
unmarshal(change, {status, #src_StatusChange{status = Status}}) ->
|
||||
{status_changed, unmarshal(status, Status)};
|
||||
|
||||
unmarshal(source, #src_Source{
|
||||
name = Name,
|
||||
resource = Resource,
|
||||
@ -153,15 +139,12 @@ unmarshal(resource, {internal, #src_Internal{details = Details}}) ->
|
||||
type => internal,
|
||||
details => unmarshal(string, Details)
|
||||
});
|
||||
|
||||
unmarshal(status, {unauthorized, #src_Unauthorized{}}) ->
|
||||
unauthorized;
|
||||
unmarshal(status, {authorized, #src_Authorized{}}) ->
|
||||
authorized;
|
||||
|
||||
unmarshal(ctx, Ctx) ->
|
||||
maybe_unmarshal(context, Ctx);
|
||||
|
||||
unmarshal(T, V) ->
|
||||
ff_codec:unmarshal(T, V).
|
||||
|
||||
|
@ -9,32 +9,28 @@
|
||||
-type event() :: ff_eventsink_publisher:event(ff_source:event()).
|
||||
-type sinkevent() :: ff_eventsink_publisher:sinkevent(ff_proto_source_thrift:'SinkEvent'()).
|
||||
|
||||
-spec publish_events(list(event())) ->
|
||||
list(sinkevent()).
|
||||
|
||||
-spec publish_events(list(event())) -> list(sinkevent()).
|
||||
publish_events(Events) ->
|
||||
[publish_event(Event) || Event <- Events].
|
||||
|
||||
-spec publish_event(event()) ->
|
||||
sinkevent().
|
||||
|
||||
-spec publish_event(event()) -> sinkevent().
|
||||
publish_event(#{
|
||||
id := ID,
|
||||
source_id := SourceID,
|
||||
event := {
|
||||
id := ID,
|
||||
source_id := SourceID,
|
||||
event := {
|
||||
EventID,
|
||||
Dt,
|
||||
{ev, EventDt, Payload}
|
||||
}
|
||||
}) ->
|
||||
#src_SinkEvent{
|
||||
id = marshal(event_id, ID),
|
||||
created_at = marshal(timestamp, Dt),
|
||||
source = marshal(id, SourceID),
|
||||
payload = #src_EventSinkPayload{
|
||||
sequence = marshal(event_id, EventID),
|
||||
id = marshal(event_id, ID),
|
||||
created_at = marshal(timestamp, Dt),
|
||||
source = marshal(id, SourceID),
|
||||
payload = #src_EventSinkPayload{
|
||||
sequence = marshal(event_id, EventID),
|
||||
occured_at = marshal(timestamp, EventDt),
|
||||
changes = [marshal(change, Payload)]
|
||||
changes = [marshal(change, Payload)]
|
||||
}
|
||||
}.
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
-module(ff_source_handler).
|
||||
|
||||
-behaviour(ff_woody_wrapper).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_source_thrift.hrl").
|
||||
@ -9,10 +10,11 @@
|
||||
%%
|
||||
%% ff_woody_wrapper callbacks
|
||||
%%
|
||||
-spec handle_function(woody:func(), woody:args(), woody:options()) ->
|
||||
{ok, woody:result()} | no_return().
|
||||
-spec handle_function(woody:func(), woody:args(), woody:options()) -> {ok, woody:result()} | no_return().
|
||||
handle_function(Func, Args, Opts) ->
|
||||
scoper:scope(source, #{},
|
||||
scoper:scope(
|
||||
source,
|
||||
#{},
|
||||
fun() ->
|
||||
handle_function_(Func, Args, Opts)
|
||||
end
|
||||
@ -24,9 +26,11 @@ handle_function(Func, Args, Opts) ->
|
||||
handle_function_('Create', [Params, Ctx], Opts) ->
|
||||
ID = Params#src_SourceParams.id,
|
||||
ok = scoper:add_meta(#{id => ID}),
|
||||
case ff_source_machine:create(
|
||||
ff_source_codec:unmarshal_source_params(Params),
|
||||
ff_source_codec:unmarshal(ctx, Ctx))
|
||||
case
|
||||
ff_source_machine:create(
|
||||
ff_source_codec:unmarshal_source_params(Params),
|
||||
ff_source_codec:unmarshal(ctx, Ctx)
|
||||
)
|
||||
of
|
||||
ok ->
|
||||
handle_function_('Get', [ID, #'EventRange'{}], Opts);
|
||||
|
@ -21,60 +21,56 @@
|
||||
-type value_type() :: machinery_mg_schema:vt().
|
||||
-type context() :: machinery_mg_schema:context().
|
||||
|
||||
-type event() :: ff_machine:timestamped_event(ff_source:event()).
|
||||
-type event() :: ff_machine:timestamped_event(ff_source:event()).
|
||||
-type aux_state() :: ff_machine:auxst().
|
||||
-type call_args() :: term().
|
||||
-type call_response() :: term().
|
||||
|
||||
-type data() ::
|
||||
aux_state() |
|
||||
event() |
|
||||
call_args() |
|
||||
call_response().
|
||||
aux_state()
|
||||
| event()
|
||||
| call_args()
|
||||
| call_response().
|
||||
|
||||
%% machinery_mg_schema callbacks
|
||||
|
||||
-spec get_version(value_type()) ->
|
||||
machinery_mg_schema:version().
|
||||
-spec get_version(value_type()) -> machinery_mg_schema:version().
|
||||
get_version(event) ->
|
||||
?CURRENT_EVENT_FORMAT_VERSION;
|
||||
get_version(aux_state) ->
|
||||
undefined.
|
||||
|
||||
-spec marshal(type(), value(data()), context()) ->
|
||||
{machinery_msgpack:t(), context()}.
|
||||
-spec marshal(type(), value(data()), context()) -> {machinery_msgpack:t(), context()}.
|
||||
marshal({event, Format}, TimestampedChange, Context) ->
|
||||
marshal_event(Format, TimestampedChange, Context);
|
||||
marshal(T, V, C) when
|
||||
T =:= {args, init} orelse
|
||||
T =:= {args, call} orelse
|
||||
T =:= {args, repair} orelse
|
||||
T =:= {aux_state, undefined} orelse
|
||||
T =:= {response, call} orelse
|
||||
T =:= {response, {repair, success}} orelse
|
||||
T =:= {response, {repair, failure}}
|
||||
T =:= {args, call} orelse
|
||||
T =:= {args, repair} orelse
|
||||
T =:= {aux_state, undefined} orelse
|
||||
T =:= {response, call} orelse
|
||||
T =:= {response, {repair, success}} orelse
|
||||
T =:= {response, {repair, failure}}
|
||||
->
|
||||
machinery_mg_schema_generic:marshal(T, V, C).
|
||||
|
||||
-spec unmarshal(type(), machinery_msgpack:t(), context()) ->
|
||||
{data(), context()}.
|
||||
-spec unmarshal(type(), machinery_msgpack:t(), context()) -> {data(), context()}.
|
||||
unmarshal({event, FormatVersion}, EncodedChange, Context) ->
|
||||
unmarshal_event(FormatVersion, EncodedChange, Context);
|
||||
unmarshal(T, V, C) when
|
||||
T =:= {args, init} orelse
|
||||
T =:= {args, call} orelse
|
||||
T =:= {args, repair} orelse
|
||||
T =:= {aux_state, undefined} orelse
|
||||
T =:= {response, call} orelse
|
||||
T =:= {response, {repair, success}} orelse
|
||||
T =:= {response, {repair, failure}}
|
||||
T =:= {args, call} orelse
|
||||
T =:= {args, repair} orelse
|
||||
T =:= {aux_state, undefined} orelse
|
||||
T =:= {response, call} orelse
|
||||
T =:= {response, {repair, success}} orelse
|
||||
T =:= {response, {repair, failure}}
|
||||
->
|
||||
machinery_mg_schema_generic:unmarshal(T, V, C).
|
||||
|
||||
%% Internals
|
||||
|
||||
-spec marshal_event(machinery_mg_schema:version(), event(), context()) ->
|
||||
{machinery_msgpack:t(), context()}.
|
||||
-spec marshal_event(machinery_mg_schema:version(), event(), context()) -> {machinery_msgpack:t(), context()}.
|
||||
marshal_event(undefined = Version, TimestampedChange, Context) ->
|
||||
% @TODO: Remove after migration
|
||||
machinery_mg_schema_generic:marshal({event, Version}, TimestampedChange, Context);
|
||||
@ -83,8 +79,7 @@ marshal_event(1, TimestampedChange, Context) ->
|
||||
Type = {struct, struct, {ff_proto_source_thrift, 'TimestampedChange'}},
|
||||
{{bin, ff_proto_utils:serialize(Type, ThriftChange)}, Context}.
|
||||
|
||||
-spec unmarshal_event(machinery_mg_schema:version(), machinery_msgpack:t(), context()) ->
|
||||
{event(), context()}.
|
||||
-spec unmarshal_event(machinery_mg_schema:version(), machinery_msgpack:t(), context()) -> {event(), context()}.
|
||||
unmarshal_event(1, EncodedChange, Context) ->
|
||||
{bin, EncodedThriftChange} = EncodedChange,
|
||||
Type = {struct, struct, {ff_proto_source_thrift, 'TimestampedChange'}},
|
||||
@ -94,72 +89,77 @@ unmarshal_event(undefined = Version, EncodedChange, Context0) ->
|
||||
{Event, Context1} = machinery_mg_schema_generic:unmarshal({event, Version}, EncodedChange, Context0),
|
||||
{maybe_migrate(Event), Context1}.
|
||||
|
||||
-spec maybe_migrate(any()) ->
|
||||
event().
|
||||
-spec maybe_migrate(any()) -> event().
|
||||
maybe_migrate({ev, Timestamp, Change0}) ->
|
||||
Change = ff_source:maybe_migrate(Change0, #{timestamp => Timestamp}),
|
||||
{ev, Timestamp, Change}.
|
||||
|
||||
-ifdef(TEST).
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
-spec test() -> _.
|
||||
|
||||
-spec created_3_undef_3_1_decoding_test() -> _.
|
||||
|
||||
created_3_undef_3_1_decoding_test() ->
|
||||
Resource = #{
|
||||
type => internal,
|
||||
type => internal,
|
||||
details => <<"details">>
|
||||
},
|
||||
Source = #{
|
||||
version => 3,
|
||||
resource => Resource,
|
||||
name => <<"name">>,
|
||||
created_at => 1590434350293,
|
||||
version => 3,
|
||||
resource => Resource,
|
||||
name => <<"name">>,
|
||||
created_at => 1590434350293,
|
||||
external_id => <<"external_id">>,
|
||||
metadata => #{}
|
||||
metadata => #{}
|
||||
},
|
||||
Change = {created, Source},
|
||||
Event = {ev, {{{2020, 5, 25}, {19, 19, 10}}, 293305}, Change},
|
||||
|
||||
ResourceMsgpack = {arr, [
|
||||
{str, <<"map">>},
|
||||
{obj, #{
|
||||
{str, <<"type">>} => {str, <<"internal">>},
|
||||
{str, <<"details">>} => {bin, <<"details">>}
|
||||
}}
|
||||
]},
|
||||
LegacyChange = {arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"created">>},
|
||||
ResourceMsgpack =
|
||||
{arr, [
|
||||
{str, <<"map">>},
|
||||
{obj, #{
|
||||
{str, <<"version">>} => {i, 3},
|
||||
{str, <<"resource">>} => ResourceMsgpack,
|
||||
{str, <<"name">>} => {bin, <<"name">>},
|
||||
{str, <<"created_at">>} => {i, 1590434350293},
|
||||
{str, <<"external_id">>} => {bin, <<"external_id">>},
|
||||
{str, <<"metadata">>} => {arr, [
|
||||
{str, <<"map">>},
|
||||
{obj, #{}}
|
||||
]}
|
||||
{str, <<"type">>} => {str, <<"internal">>},
|
||||
{str, <<"details">>} => {bin, <<"details">>}
|
||||
}}
|
||||
]}
|
||||
]},
|
||||
LegacyEvent = {arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"ev">>},
|
||||
]},
|
||||
LegacyChange =
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"created">>},
|
||||
{arr, [
|
||||
{str, <<"map">>},
|
||||
{obj, #{
|
||||
{str, <<"version">>} => {i, 3},
|
||||
{str, <<"resource">>} => ResourceMsgpack,
|
||||
{str, <<"name">>} => {bin, <<"name">>},
|
||||
{str, <<"created_at">>} => {i, 1590434350293},
|
||||
{str, <<"external_id">>} => {bin, <<"external_id">>},
|
||||
{str, <<"metadata">>} =>
|
||||
{arr, [
|
||||
{str, <<"map">>},
|
||||
{obj, #{}}
|
||||
]}
|
||||
}}
|
||||
]}
|
||||
]},
|
||||
LegacyEvent =
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"ev">>},
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{arr, [{str, <<"tup">>}, {i, 2020}, {i, 5}, {i, 25}]},
|
||||
{arr, [{str, <<"tup">>}, {i, 19}, {i, 19}, {i, 10}]}
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{arr, [{str, <<"tup">>}, {i, 2020}, {i, 5}, {i, 25}]},
|
||||
{arr, [{str, <<"tup">>}, {i, 19}, {i, 19}, {i, 10}]}
|
||||
]},
|
||||
{i, 293305}
|
||||
]},
|
||||
{i, 293305}
|
||||
LegacyChange
|
||||
]},
|
||||
LegacyChange
|
||||
]},
|
||||
|
||||
DecodedLegacy = unmarshal({event, undefined}, LegacyEvent),
|
||||
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
|
||||
@ -169,53 +169,56 @@ created_3_undef_3_1_decoding_test() ->
|
||||
-spec created_1_undef_3_1_decoding_test() -> _.
|
||||
created_1_undef_3_1_decoding_test() ->
|
||||
Resource = #{
|
||||
type => internal,
|
||||
type => internal,
|
||||
details => <<"details">>
|
||||
},
|
||||
Source = #{
|
||||
version => 3,
|
||||
resource => Resource,
|
||||
name => <<"name">>,
|
||||
created_at => 1590434350293,
|
||||
version => 3,
|
||||
resource => Resource,
|
||||
name => <<"name">>,
|
||||
created_at => 1590434350293,
|
||||
external_id => <<"external_id">>
|
||||
},
|
||||
Change = {created, Source},
|
||||
Event = {ev, {{{2020, 5, 25}, {19, 19, 10}}, 293305}, Change},
|
||||
|
||||
ResourceMsgpack = {arr, [
|
||||
{str, <<"map">>},
|
||||
{obj, #{
|
||||
{str, <<"type">>} => {str, <<"internal">>},
|
||||
{str, <<"details">>} => {bin, <<"details">>}
|
||||
}}
|
||||
]},
|
||||
LegacyChange = {arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"created">>},
|
||||
ResourceMsgpack =
|
||||
{arr, [
|
||||
{str, <<"map">>},
|
||||
{obj, #{
|
||||
{str, <<"version">>} => {i, 1},
|
||||
{str, <<"resource">>} => ResourceMsgpack,
|
||||
{str, <<"name">>} => {bin, <<"name">>},
|
||||
{str, <<"external_id">>} => {bin, <<"external_id">>}
|
||||
{str, <<"type">>} => {str, <<"internal">>},
|
||||
{str, <<"details">>} => {bin, <<"details">>}
|
||||
}}
|
||||
]}
|
||||
]},
|
||||
LegacyEvent = {arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"ev">>},
|
||||
]},
|
||||
LegacyChange =
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"created">>},
|
||||
{arr, [
|
||||
{str, <<"map">>},
|
||||
{obj, #{
|
||||
{str, <<"version">>} => {i, 1},
|
||||
{str, <<"resource">>} => ResourceMsgpack,
|
||||
{str, <<"name">>} => {bin, <<"name">>},
|
||||
{str, <<"external_id">>} => {bin, <<"external_id">>}
|
||||
}}
|
||||
]}
|
||||
]},
|
||||
LegacyEvent =
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"ev">>},
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{arr, [{str, <<"tup">>}, {i, 2020}, {i, 5}, {i, 25}]},
|
||||
{arr, [{str, <<"tup">>}, {i, 19}, {i, 19}, {i, 10}]}
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{arr, [{str, <<"tup">>}, {i, 2020}, {i, 5}, {i, 25}]},
|
||||
{arr, [{str, <<"tup">>}, {i, 19}, {i, 19}, {i, 10}]}
|
||||
]},
|
||||
{i, 293305}
|
||||
]},
|
||||
{i, 293305}
|
||||
LegacyChange
|
||||
]},
|
||||
LegacyChange
|
||||
]},
|
||||
|
||||
DecodedLegacy = unmarshal({event, undefined}, LegacyEvent),
|
||||
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
|
||||
@ -224,45 +227,49 @@ created_1_undef_3_1_decoding_test() ->
|
||||
|
||||
-spec account_undef_1_decoding_test() -> _.
|
||||
account_undef_1_decoding_test() ->
|
||||
Change = {account, {created, #{
|
||||
id => <<"id">>,
|
||||
identity => <<"identity">>,
|
||||
currency => <<"USD">>,
|
||||
accounter_account_id => 1
|
||||
}}},
|
||||
Change =
|
||||
{account,
|
||||
{created, #{
|
||||
id => <<"id">>,
|
||||
identity => <<"identity">>,
|
||||
currency => <<"USD">>,
|
||||
accounter_account_id => 1
|
||||
}}},
|
||||
Event = {ev, {{{2020, 5, 25}, {19, 19, 10}}, 293305}, Change},
|
||||
|
||||
LegacyChange = {arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"account">>},
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"created">>},
|
||||
{arr, [
|
||||
{str, <<"map">>},
|
||||
{obj, #{
|
||||
{str, <<"id">>} => {bin, <<"id">>},
|
||||
{str, <<"identity">>} => {bin, <<"identity">>},
|
||||
{str, <<"currency">>} => {bin, <<"USD">>},
|
||||
{str, <<"accounter_account_id">>} => {i, 1}
|
||||
}}
|
||||
]}
|
||||
]}
|
||||
]},
|
||||
LegacyEvent = {arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"ev">>},
|
||||
LegacyChange =
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"account">>},
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{arr, [{str, <<"tup">>}, {i, 2020}, {i, 5}, {i, 25}]},
|
||||
{arr, [{str, <<"tup">>}, {i, 19}, {i, 19}, {i, 10}]}
|
||||
]},
|
||||
{i, 293305}
|
||||
{str, <<"created">>},
|
||||
{arr, [
|
||||
{str, <<"map">>},
|
||||
{obj, #{
|
||||
{str, <<"id">>} => {bin, <<"id">>},
|
||||
{str, <<"identity">>} => {bin, <<"identity">>},
|
||||
{str, <<"currency">>} => {bin, <<"USD">>},
|
||||
{str, <<"accounter_account_id">>} => {i, 1}
|
||||
}}
|
||||
]}
|
||||
]}
|
||||
]},
|
||||
LegacyEvent =
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"ev">>},
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{arr, [{str, <<"tup">>}, {i, 2020}, {i, 5}, {i, 25}]},
|
||||
{arr, [{str, <<"tup">>}, {i, 19}, {i, 19}, {i, 10}]}
|
||||
]},
|
||||
{i, 293305}
|
||||
]},
|
||||
LegacyChange
|
||||
]},
|
||||
LegacyChange
|
||||
]},
|
||||
|
||||
DecodedLegacy = unmarshal({event, undefined}, LegacyEvent),
|
||||
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
|
||||
@ -274,25 +281,27 @@ status_undef_1_decoding_test() ->
|
||||
Change = {status_changed, unauthorized},
|
||||
Event = {ev, {{{2020, 5, 25}, {19, 19, 10}}, 293305}, Change},
|
||||
|
||||
LegacyChange = {arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"status_changed">>},
|
||||
{str, <<"unauthorized">>}
|
||||
]},
|
||||
LegacyEvent = {arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"ev">>},
|
||||
LegacyChange =
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"status_changed">>},
|
||||
{str, <<"unauthorized">>}
|
||||
]},
|
||||
LegacyEvent =
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"ev">>},
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{arr, [{str, <<"tup">>}, {i, 2020}, {i, 5}, {i, 25}]},
|
||||
{arr, [{str, <<"tup">>}, {i, 19}, {i, 19}, {i, 10}]}
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{arr, [{str, <<"tup">>}, {i, 2020}, {i, 5}, {i, 25}]},
|
||||
{arr, [{str, <<"tup">>}, {i, 19}, {i, 19}, {i, 10}]}
|
||||
]},
|
||||
{i, 293305}
|
||||
]},
|
||||
{i, 293305}
|
||||
LegacyChange
|
||||
]},
|
||||
LegacyChange
|
||||
]},
|
||||
|
||||
DecodedLegacy = unmarshal({event, undefined}, LegacyEvent),
|
||||
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
|
||||
@ -302,24 +311,26 @@ status_undef_1_decoding_test() ->
|
||||
-spec created_1_decoding_test() -> _.
|
||||
created_1_decoding_test() ->
|
||||
Resource = #{
|
||||
type => internal,
|
||||
type => internal,
|
||||
details => <<"details">>
|
||||
},
|
||||
Source = #{
|
||||
version => 3,
|
||||
resource => Resource,
|
||||
name => <<"name">>,
|
||||
created_at => 1590434350293,
|
||||
version => 3,
|
||||
resource => Resource,
|
||||
name => <<"name">>,
|
||||
created_at => 1590434350293,
|
||||
external_id => <<"external_id">>
|
||||
},
|
||||
Change = {created, Source},
|
||||
Event = {ev, {{{2020, 5, 25}, {19, 19, 10}}, 293305}, Change},
|
||||
|
||||
LegacyEvent = {bin, base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgwAAQsAAQAAAARuYW1lDA"
|
||||
"ACDAABCwABAAAAB2RldGFpbHMAAAsAAwAAAAtleHRlcm5hbF9pZAsABgAAABgyMDIwLTA1"
|
||||
"LTI1VDE5OjE5OjEwLjI5M1oAAAA="
|
||||
>>)},
|
||||
LegacyEvent =
|
||||
{bin,
|
||||
base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgwAAQsAAQAAAARuYW1lDA"
|
||||
"ACDAABCwABAAAAB2RldGFpbHMAAAsAAwAAAAtleHRlcm5hbF9pZAsABgAAABgyMDIwLTA1"
|
||||
"LTI1VDE5OjE5OjEwLjI5M1oAAAA="
|
||||
>>)},
|
||||
|
||||
DecodedLegacy = unmarshal({event, 1}, LegacyEvent),
|
||||
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
|
||||
@ -328,18 +339,22 @@ created_1_decoding_test() ->
|
||||
|
||||
-spec account_1_decoding_test() -> _.
|
||||
account_1_decoding_test() ->
|
||||
Change = {account, {created, #{
|
||||
id => <<"id">>,
|
||||
identity => <<"identity">>,
|
||||
currency => <<"USD">>,
|
||||
accounter_account_id => 1
|
||||
}}},
|
||||
Change =
|
||||
{account,
|
||||
{created, #{
|
||||
id => <<"id">>,
|
||||
identity => <<"identity">>,
|
||||
currency => <<"USD">>,
|
||||
accounter_account_id => 1
|
||||
}}},
|
||||
Event = {ev, {{{2020, 5, 25}, {19, 19, 10}}, 293305}, Change},
|
||||
|
||||
LegacyEvent = {bin, base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgwAAgwAAQsAAwAAAAJpZA"
|
||||
"sAAQAAAAhpZGVudGl0eQwAAgsAAQAAAANVU0QACgAEAAAAAAAAAAEAAAAA"
|
||||
>>)},
|
||||
LegacyEvent =
|
||||
{bin,
|
||||
base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgwAAgwAAQsAAwAAAAJpZA"
|
||||
"sAAQAAAAhpZGVudGl0eQwAAgsAAQAAAANVU0QACgAEAAAAAAAAAAEAAAAA"
|
||||
>>)},
|
||||
|
||||
DecodedLegacy = unmarshal({event, 1}, LegacyEvent),
|
||||
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
|
||||
@ -351,22 +366,22 @@ status_1_decoding_test() ->
|
||||
Change = {status_changed, unauthorized},
|
||||
Event = {ev, {{{2020, 5, 25}, {19, 19, 10}}, 293305}, Change},
|
||||
|
||||
LegacyEvent = {bin, base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgwAAwwAAQwAAgAAAAAA"
|
||||
>>)},
|
||||
LegacyEvent =
|
||||
{bin,
|
||||
base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgwAAwwAAQwAAgAAAAAA"
|
||||
>>)},
|
||||
|
||||
DecodedLegacy = unmarshal({event, 1}, LegacyEvent),
|
||||
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
|
||||
Decoded = unmarshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, ModernizedBinary),
|
||||
?assertEqual(Event, Decoded).
|
||||
|
||||
-spec marshal(type(), value(data())) ->
|
||||
machinery_msgpack:t().
|
||||
-spec marshal(type(), value(data())) -> machinery_msgpack:t().
|
||||
marshal(Type, Value) ->
|
||||
element(1, marshal(Type, Value, #{})).
|
||||
|
||||
-spec unmarshal(type(), machinery_msgpack:t()) ->
|
||||
data().
|
||||
-spec unmarshal(type(), machinery_msgpack:t()) -> data().
|
||||
unmarshal(Type, Value) ->
|
||||
element(1, unmarshal(Type, Value, #{})).
|
||||
|
||||
|
@ -9,16 +9,13 @@
|
||||
|
||||
%% API
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) ->
|
||||
ff_codec:encoded_value().
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) -> ff_codec:encoded_value().
|
||||
marshal(change, {created, Adjustment}) ->
|
||||
{created, #w2w_adj_CreatedChange{adjustment = marshal(adjustment, Adjustment)}};
|
||||
marshal(change, {status_changed, Status}) ->
|
||||
{status_changed, #w2w_adj_StatusChange{status = marshal(status, Status)}};
|
||||
marshal(change, {p_transfer, TransferChange}) ->
|
||||
{transfer, #w2w_adj_TransferChange{payload = ff_p_transfer_codec:marshal(change, TransferChange)}};
|
||||
|
||||
marshal(adjustment, Adjustment) ->
|
||||
#w2w_adj_Adjustment{
|
||||
id = marshal(id, ff_adjustment:id(Adjustment)),
|
||||
@ -47,12 +44,10 @@ marshal(adjustment_state, Adjustment) ->
|
||||
operation_timestamp = marshal(timestamp_ms, ff_adjustment:operation_timestamp(Adjustment)),
|
||||
external_id = maybe_marshal(id, ff_adjustment:external_id(Adjustment))
|
||||
};
|
||||
|
||||
marshal(status, pending) ->
|
||||
{pending, #w2w_adj_Pending{}};
|
||||
marshal(status, succeeded) ->
|
||||
{succeeded, #w2w_adj_Succeeded{}};
|
||||
|
||||
marshal(changes_plan, Plan) ->
|
||||
#w2w_adj_ChangesPlan{
|
||||
new_cash_flow = maybe_marshal(cash_flow_change_plan, maps:get(new_cash_flow, Plan, undefined)),
|
||||
@ -69,26 +64,20 @@ marshal(status_change_plan, Plan) ->
|
||||
#w2w_adj_StatusChangePlan{
|
||||
new_status = ff_w2w_transfer_status_codec:marshal(status, maps:get(new_status, Plan))
|
||||
};
|
||||
|
||||
marshal(change_request, {change_status, Status}) ->
|
||||
{change_status, #w2w_adj_ChangeStatusRequest{
|
||||
new_status = ff_w2w_transfer_status_codec:marshal(status, Status)
|
||||
}};
|
||||
|
||||
marshal(T, V) ->
|
||||
ff_codec:marshal(T, V).
|
||||
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) ->
|
||||
ff_codec:decoded_value().
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) -> ff_codec:decoded_value().
|
||||
unmarshal(change, {created, #w2w_adj_CreatedChange{adjustment = Adjustment}}) ->
|
||||
{created, unmarshal(adjustment, Adjustment)};
|
||||
unmarshal(change, {status_changed, #w2w_adj_StatusChange{status = Status}}) ->
|
||||
{status_changed, unmarshal(status, Status)};
|
||||
unmarshal(change, {transfer, #w2w_adj_TransferChange{payload = TransferChange}}) ->
|
||||
{p_transfer, ff_p_transfer_codec:unmarshal(change, TransferChange)};
|
||||
|
||||
unmarshal(adjustment, Adjustment) ->
|
||||
#{
|
||||
version => 1,
|
||||
@ -101,19 +90,16 @@ unmarshal(adjustment, Adjustment) ->
|
||||
operation_timestamp => unmarshal(timestamp_ms, Adjustment#w2w_adj_Adjustment.operation_timestamp),
|
||||
external_id => maybe_unmarshal(id, Adjustment#w2w_adj_Adjustment.external_id)
|
||||
};
|
||||
|
||||
unmarshal(adjustment_params, Params) ->
|
||||
genlib_map:compact(#{
|
||||
id => unmarshal(id, Params#w2w_adj_AdjustmentParams.id),
|
||||
change => unmarshal(change_request, Params#w2w_adj_AdjustmentParams.change),
|
||||
external_id => maybe_unmarshal(id, Params#w2w_adj_AdjustmentParams.external_id)
|
||||
});
|
||||
|
||||
unmarshal(status, {pending, #w2w_adj_Pending{}}) ->
|
||||
pending;
|
||||
unmarshal(status, {succeeded, #w2w_adj_Succeeded{}}) ->
|
||||
succeeded;
|
||||
|
||||
unmarshal(changes_plan, Plan) ->
|
||||
genlib_map:compact(#{
|
||||
new_cash_flow => maybe_unmarshal(cash_flow_change_plan, Plan#w2w_adj_ChangesPlan.new_cash_flow),
|
||||
@ -131,11 +117,9 @@ unmarshal(status_change_plan, Plan) ->
|
||||
#{
|
||||
new_status => ff_w2w_transfer_status_codec:unmarshal(status, Status)
|
||||
};
|
||||
|
||||
unmarshal(change_request, {change_status, Request}) ->
|
||||
Status = Request#w2w_adj_ChangeStatusRequest.new_status,
|
||||
{change_status, ff_w2w_transfer_status_codec:unmarshal(status, Status)};
|
||||
|
||||
unmarshal(T, V) ->
|
||||
ff_codec:unmarshal(T, V).
|
||||
|
||||
@ -155,9 +139,11 @@ maybe_marshal(Type, Value) ->
|
||||
|
||||
-ifdef(TEST).
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
-spec test() -> _.
|
||||
|
||||
-spec adjustment_codec_test() -> _.
|
||||
|
||||
adjustment_codec_test() ->
|
||||
FinalCashFlow = #{
|
||||
postings => [
|
||||
|
@ -13,13 +13,13 @@
|
||||
%% Data transform
|
||||
|
||||
-define(to_session_event(SessionID, Payload),
|
||||
{session, #{id => SessionID, payload => Payload}}).
|
||||
{session, #{id => SessionID, payload => Payload}}
|
||||
).
|
||||
|
||||
%% API
|
||||
|
||||
-spec marshal_w2w_transfer_state(w2w_transfer:w2w_transfer_state(), ff_entity_context:context()) ->
|
||||
ff_proto_w2w_transfer_thrift:'W2WTransferState'().
|
||||
|
||||
marshal_w2w_transfer_state(W2WTransferState, Ctx) ->
|
||||
CashFlow = w2w_transfer:effective_final_cash_flow(W2WTransferState),
|
||||
Adjustments = w2w_transfer:adjustments(W2WTransferState),
|
||||
@ -41,7 +41,6 @@ marshal_w2w_transfer_state(W2WTransferState, Ctx) ->
|
||||
|
||||
-spec unmarshal_w2w_transfer_params(ff_proto_w2w_transfer_thrift:'W2WTransferParams'()) ->
|
||||
w2w_transfer_machine:params().
|
||||
|
||||
unmarshal_w2w_transfer_params(#w2w_transfer_W2WTransferParams{
|
||||
id = ID,
|
||||
body = Body,
|
||||
@ -59,25 +58,20 @@ unmarshal_w2w_transfer_params(#w2w_transfer_W2WTransferParams{
|
||||
metadata => maybe_unmarshal(ctx, Metadata)
|
||||
}).
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) ->
|
||||
ff_codec:encoded_value().
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) -> ff_codec:encoded_value().
|
||||
marshal({list, T}, V) ->
|
||||
[marshal(T, E) || E <- V];
|
||||
|
||||
marshal(timestamped_change, {ev, Timestamp, Change}) ->
|
||||
#w2w_transfer_TimestampedChange{
|
||||
change = marshal(change, Change),
|
||||
occured_at = ff_codec:marshal(timestamp, Timestamp)
|
||||
};
|
||||
|
||||
marshal(event, {EventID, {ev, Timestamp, Change}}) ->
|
||||
#w2w_transfer_Event{
|
||||
event_id = ff_codec:marshal(event_id, EventID),
|
||||
occured_at = ff_codec:marshal(timestamp, Timestamp),
|
||||
change = marshal(change, Change)
|
||||
};
|
||||
|
||||
marshal(change, {created, W2WTransfer}) ->
|
||||
{created, #w2w_transfer_CreatedChange{w2w_transfer = marshal(w2w_transfer, W2WTransfer)}};
|
||||
marshal(change, {status_changed, Status}) ->
|
||||
@ -91,7 +85,6 @@ marshal(change, {adjustment, #{id := ID, payload := Payload}}) ->
|
||||
id = marshal(id, ID),
|
||||
payload = ff_w2w_transfer_adjustment_codec:marshal(change, Payload)
|
||||
}};
|
||||
|
||||
marshal(w2w_transfer, W2WTransfer) ->
|
||||
#w2w_transfer_W2WTransfer{
|
||||
id = marshal(id, w2w_transfer:id(W2WTransfer)),
|
||||
@ -105,34 +98,26 @@ marshal(w2w_transfer, W2WTransfer) ->
|
||||
created_at = maybe_marshal(timestamp_ms, w2w_transfer:created_at(W2WTransfer)),
|
||||
metadata = maybe_marshal(ctx, w2w_transfer:metadata(W2WTransfer))
|
||||
};
|
||||
|
||||
marshal(status, Status) ->
|
||||
ff_w2w_transfer_status_codec:marshal(status, Status);
|
||||
|
||||
marshal(ctx, Ctx) ->
|
||||
maybe_marshal(context, Ctx);
|
||||
|
||||
marshal(T, V) ->
|
||||
ff_codec:marshal(T, V).
|
||||
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) ->
|
||||
ff_codec:decoded_value().
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) -> ff_codec:decoded_value().
|
||||
unmarshal({list, T}, V) ->
|
||||
[unmarshal(T, E) || E <- V];
|
||||
|
||||
unmarshal(timestamped_change, TimestampedChange) ->
|
||||
Timestamp = ff_codec:unmarshal(timestamp, TimestampedChange#w2w_transfer_TimestampedChange.occured_at),
|
||||
Change = unmarshal(change, TimestampedChange#w2w_transfer_TimestampedChange.change),
|
||||
{ev, Timestamp, Change};
|
||||
|
||||
unmarshal(repair_scenario, {add_events, #w2w_transfer_AddEventsRepair{events = Events, action = Action}}) ->
|
||||
{add_events, genlib_map:compact(#{
|
||||
events => unmarshal({list, change}, Events),
|
||||
action => maybe_unmarshal(complex_action, Action)
|
||||
})};
|
||||
|
||||
{add_events,
|
||||
genlib_map:compact(#{
|
||||
events => unmarshal({list, change}, Events),
|
||||
action => maybe_unmarshal(complex_action, Action)
|
||||
})};
|
||||
unmarshal(change, {created, #w2w_transfer_CreatedChange{w2w_transfer = W2WTransfer}}) ->
|
||||
{created, unmarshal(w2w_transfer, W2WTransfer)};
|
||||
unmarshal(change, {status_changed, #w2w_transfer_StatusChange{status = W2WTransferStatus}}) ->
|
||||
@ -146,10 +131,8 @@ unmarshal(change, {adjustment, Change}) ->
|
||||
id => unmarshal(id, Change#w2w_transfer_AdjustmentChange.id),
|
||||
payload => ff_w2w_transfer_adjustment_codec:unmarshal(change, Change#w2w_transfer_AdjustmentChange.payload)
|
||||
}};
|
||||
|
||||
unmarshal(status, Status) ->
|
||||
ff_w2w_transfer_status_codec:unmarshal(status, Status);
|
||||
|
||||
unmarshal(w2w_transfer, W2WTransfer) ->
|
||||
genlib_map:compact(#{
|
||||
version => 1,
|
||||
@ -164,10 +147,8 @@ unmarshal(w2w_transfer, W2WTransfer) ->
|
||||
created_at => maybe_unmarshal(timestamp_ms, W2WTransfer#w2w_transfer_W2WTransfer.created_at),
|
||||
metadata => maybe_unmarshal(ctx, W2WTransfer#w2w_transfer_W2WTransfer.metadata)
|
||||
});
|
||||
|
||||
unmarshal(ctx, Ctx) ->
|
||||
maybe_unmarshal(context, Ctx);
|
||||
|
||||
unmarshal(T, V) ->
|
||||
ff_codec:unmarshal(T, V).
|
||||
|
||||
@ -187,14 +168,16 @@ maybe_marshal(Type, Value) ->
|
||||
|
||||
-ifdef(TEST).
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
-spec test() -> _.
|
||||
|
||||
-spec w2w_transfer_symmetry_test() -> _.
|
||||
|
||||
w2w_transfer_symmetry_test() ->
|
||||
Encoded = #w2w_transfer_W2WTransfer{
|
||||
body = #'Cash'{
|
||||
amount = 10101,
|
||||
currency = #'CurrencyRef'{ symbolic_code = <<"Banana Republic">> }
|
||||
currency = #'CurrencyRef'{symbolic_code = <<"Banana Republic">>}
|
||||
},
|
||||
wallet_from_id = genlib:unique(),
|
||||
wallet_to_id = genlib:unique(),
|
||||
|
@ -16,32 +16,28 @@
|
||||
%% Internals
|
||||
%%
|
||||
|
||||
-spec publish_events(list(event())) ->
|
||||
list(sinkevent()).
|
||||
|
||||
-spec publish_events(list(event())) -> list(sinkevent()).
|
||||
publish_events(Events) ->
|
||||
[publish_event(Event) || Event <- Events].
|
||||
|
||||
-spec publish_event(event()) ->
|
||||
sinkevent().
|
||||
|
||||
-spec publish_event(event()) -> sinkevent().
|
||||
publish_event(#{
|
||||
id := ID,
|
||||
source_id := SourceID,
|
||||
event := {
|
||||
id := ID,
|
||||
source_id := SourceID,
|
||||
event := {
|
||||
EventID,
|
||||
Dt,
|
||||
{ev, EventDt, Payload}
|
||||
}
|
||||
}) ->
|
||||
#w2w_transfer_SinkEvent{
|
||||
id = marshal(event_id, ID),
|
||||
created_at = marshal(timestamp, Dt),
|
||||
source = marshal(id, SourceID),
|
||||
payload = #w2w_transfer_EventSinkPayload{
|
||||
sequence = marshal(event_id, EventID),
|
||||
id = marshal(event_id, ID),
|
||||
created_at = marshal(timestamp, Dt),
|
||||
source = marshal(id, SourceID),
|
||||
payload = #w2w_transfer_EventSinkPayload{
|
||||
sequence = marshal(event_id, EventID),
|
||||
occured_at = marshal(timestamp, EventDt),
|
||||
changes = [marshal(change, Payload)]
|
||||
changes = [marshal(change, Payload)]
|
||||
}
|
||||
}.
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
-module(ff_w2w_transfer_handler).
|
||||
|
||||
-behaviour(ff_woody_wrapper).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_w2w_transfer_thrift.hrl").
|
||||
@ -10,11 +11,11 @@
|
||||
%%
|
||||
%% ff_woody_wrapper callbacks
|
||||
%%
|
||||
-spec handle_function(woody:func(), woody:args(), woody:options()) ->
|
||||
{ok, woody:result()} | no_return().
|
||||
|
||||
-spec handle_function(woody:func(), woody:args(), woody:options()) -> {ok, woody:result()} | no_return().
|
||||
handle_function(Func, Args, Opts) ->
|
||||
scoper:scope(w2w_transfer, #{},
|
||||
scoper:scope(
|
||||
w2w_transfer,
|
||||
#{},
|
||||
fun() ->
|
||||
handle_function_(Func, Args, Opts)
|
||||
end
|
||||
@ -69,7 +70,6 @@ handle_function_('Create', [MarshaledParams, MarshaledContext], Opts) ->
|
||||
{error, Error} ->
|
||||
woody_error:raise(system, {internal, result_unexpected, woody_error:format_details(Error)})
|
||||
end;
|
||||
|
||||
handle_function_('Get', [ID, EventRange], _Opts) ->
|
||||
{After, Limit} = ff_codec:unmarshal(event_range, EventRange),
|
||||
ok = scoper:add_meta(#{id => ID}),
|
||||
@ -82,7 +82,6 @@ handle_function_('Get', [ID, EventRange], _Opts) ->
|
||||
{error, {unknown_w2w_transfer, _Ref}} ->
|
||||
woody_error:raise(business, #fistful_W2WNotFound{})
|
||||
end;
|
||||
|
||||
handle_function_('GetContext', [ID], _Opts) ->
|
||||
case w2w_transfer_machine:get(ID, {undefined, 0}) of
|
||||
{ok, Machine} ->
|
||||
@ -92,15 +91,16 @@ handle_function_('GetContext', [ID], _Opts) ->
|
||||
{error, {unknown_w2w_transfer, _Ref}} ->
|
||||
woody_error:raise(business, #fistful_W2WNotFound{})
|
||||
end;
|
||||
|
||||
handle_function_('CreateAdjustment', [ID, MarshaledParams], _Opts) ->
|
||||
Params = ff_w2w_transfer_adjustment_codec:unmarshal(adjustment_params, MarshaledParams),
|
||||
AdjustmentID = maps:get(id, Params),
|
||||
ok = scoper:add_meta(genlib_map:compact(#{
|
||||
id => ID,
|
||||
adjustment_id => AdjustmentID,
|
||||
external_id => maps:get(external_id, Params, undefined)
|
||||
})),
|
||||
ok = scoper:add_meta(
|
||||
genlib_map:compact(#{
|
||||
id => ID,
|
||||
adjustment_id => AdjustmentID,
|
||||
external_id => maps:get(external_id, Params, undefined)
|
||||
})
|
||||
),
|
||||
case w2w_transfer_machine:start_adjustment(ID, Params) of
|
||||
ok ->
|
||||
{ok, Machine} = w2w_transfer_machine:get(ID),
|
||||
|
@ -21,67 +21,62 @@
|
||||
-type value_type() :: machinery_mg_schema:vt().
|
||||
-type context() :: machinery_mg_schema:context().
|
||||
|
||||
-type event() :: ff_machine:timestamped_event(w2w_transfer:event()).
|
||||
-type event() :: ff_machine:timestamped_event(w2w_transfer:event()).
|
||||
-type aux_state() :: ff_machine:auxst().
|
||||
-type call_args() :: term().
|
||||
-type call_response() :: term().
|
||||
|
||||
-type data() ::
|
||||
aux_state() |
|
||||
event() |
|
||||
call_args() |
|
||||
call_response().
|
||||
aux_state()
|
||||
| event()
|
||||
| call_args()
|
||||
| call_response().
|
||||
|
||||
%% machinery_mg_schema callbacks
|
||||
|
||||
-spec get_version(value_type()) ->
|
||||
machinery_mg_schema:version().
|
||||
-spec get_version(value_type()) -> machinery_mg_schema:version().
|
||||
get_version(event) ->
|
||||
?CURRENT_EVENT_FORMAT_VERSION;
|
||||
get_version(aux_state) ->
|
||||
undefined.
|
||||
|
||||
-spec marshal(type(), value(data()), context()) ->
|
||||
{machinery_msgpack:t(), context()}.
|
||||
-spec marshal(type(), value(data()), context()) -> {machinery_msgpack:t(), context()}.
|
||||
marshal({event, Format}, TimestampedChange, Context) ->
|
||||
marshal_event(Format, TimestampedChange, Context);
|
||||
marshal(T, V, C) when
|
||||
T =:= {args, init} orelse
|
||||
T =:= {args, call} orelse
|
||||
T =:= {args, repair} orelse
|
||||
T =:= {aux_state, undefined} orelse
|
||||
T =:= {response, call} orelse
|
||||
T =:= {response, {repair, success}} orelse
|
||||
T =:= {response, {repair, failure}}
|
||||
T =:= {args, call} orelse
|
||||
T =:= {args, repair} orelse
|
||||
T =:= {aux_state, undefined} orelse
|
||||
T =:= {response, call} orelse
|
||||
T =:= {response, {repair, success}} orelse
|
||||
T =:= {response, {repair, failure}}
|
||||
->
|
||||
machinery_mg_schema_generic:marshal(T, V, C).
|
||||
|
||||
-spec unmarshal(type(), machinery_msgpack:t(), context()) ->
|
||||
{data(), context()}.
|
||||
-spec unmarshal(type(), machinery_msgpack:t(), context()) -> {data(), context()}.
|
||||
unmarshal({event, FormatVersion}, EncodedChange, Context) ->
|
||||
unmarshal_event(FormatVersion, EncodedChange, Context);
|
||||
unmarshal(T, V, C) when
|
||||
T =:= {args, init} orelse
|
||||
T =:= {args, call} orelse
|
||||
T =:= {args, repair} orelse
|
||||
T =:= {aux_state, undefined} orelse
|
||||
T =:= {response, call} orelse
|
||||
T =:= {response, {repair, success}} orelse
|
||||
T =:= {response, {repair, failure}}
|
||||
T =:= {args, call} orelse
|
||||
T =:= {args, repair} orelse
|
||||
T =:= {aux_state, undefined} orelse
|
||||
T =:= {response, call} orelse
|
||||
T =:= {response, {repair, success}} orelse
|
||||
T =:= {response, {repair, failure}}
|
||||
->
|
||||
machinery_mg_schema_generic:unmarshal(T, V, C).
|
||||
|
||||
%% Internals
|
||||
|
||||
-spec marshal_event(machinery_mg_schema:version(), event(), context()) ->
|
||||
{machinery_msgpack:t(), context()}.
|
||||
-spec marshal_event(machinery_mg_schema:version(), event(), context()) -> {machinery_msgpack:t(), context()}.
|
||||
marshal_event(1, TimestampedChange, Context) ->
|
||||
ThriftChange = ff_w2w_transfer_codec:marshal(timestamped_change, TimestampedChange),
|
||||
Type = {struct, struct, {ff_proto_w2w_transfer_thrift, 'TimestampedChange'}},
|
||||
{{bin, ff_proto_utils:serialize(Type, ThriftChange)}, Context}.
|
||||
|
||||
-spec unmarshal_event(machinery_mg_schema:version(), machinery_msgpack:t(), context()) ->
|
||||
{event(), context()}.
|
||||
-spec unmarshal_event(machinery_mg_schema:version(), machinery_msgpack:t(), context()) -> {event(), context()}.
|
||||
unmarshal_event(1, EncodedChange, Context) ->
|
||||
{bin, EncodedThriftChange} = EncodedChange,
|
||||
Type = {struct, struct, {ff_proto_w2w_transfer_thrift, 'TimestampedChange'}},
|
||||
@ -92,18 +87,18 @@ unmarshal_event(1, EncodedChange, Context) ->
|
||||
|
||||
-ifdef(TEST).
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
-spec test() -> _.
|
||||
|
||||
% tests helpers
|
||||
|
||||
-spec marshal(type(), value(data())) ->
|
||||
machinery_msgpack:t().
|
||||
-spec marshal(type(), value(data())) -> machinery_msgpack:t().
|
||||
|
||||
marshal(Type, Value) ->
|
||||
{Result, _Context} = marshal(Type, Value, #{}),
|
||||
Result.
|
||||
|
||||
-spec unmarshal(type(), machinery_msgpack:t()) ->
|
||||
data().
|
||||
-spec unmarshal(type(), machinery_msgpack:t()) -> data().
|
||||
unmarshal(Type, Value) ->
|
||||
{Result, _Context} = unmarshal(Type, Value, #{}),
|
||||
Result.
|
||||
@ -123,13 +118,15 @@ created_v1_decoding_test() ->
|
||||
},
|
||||
Change = {created, W2WTransfer},
|
||||
Event = {ev, {{{2020, 5, 25}, {19, 19, 10}}, 293305}, Change},
|
||||
LegacyEvent = {bin, base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgwAAQwAAQsAAQ"
|
||||
"AAAAh0cmFuc2ZlcgsAAgAAAAxXYWxsZXRGcm9tSUQLAAMAAAAKV2FsbGV0VG9J"
|
||||
"RAwABAoAAQAAAAAAAAB7DAACCwABAAAAA1JVQgAACwAFAAAAGDIwMjAtMDUtMj"
|
||||
"VUMTc6MTI6NTcuOTg1WgoABgAAAAAAAAB7CgAHAAAAAAAAAUELAAkAAAALZXh0"
|
||||
"ZXJuYWxfaWQAAAAA"
|
||||
>>)},
|
||||
LegacyEvent =
|
||||
{bin,
|
||||
base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgwAAQwAAQsAAQ"
|
||||
"AAAAh0cmFuc2ZlcgsAAgAAAAxXYWxsZXRGcm9tSUQLAAMAAAAKV2FsbGV0VG9J"
|
||||
"RAwABAoAAQAAAAAAAAB7DAACCwABAAAAA1JVQgAACwAFAAAAGDIwMjAtMDUtMj"
|
||||
"VUMTc6MTI6NTcuOTg1WgoABgAAAAAAAAB7CgAHAAAAAAAAAUELAAkAAAALZXh0"
|
||||
"ZXJuYWxfaWQAAAAA"
|
||||
>>)},
|
||||
DecodedLegacy = unmarshal({event, 1}, LegacyEvent),
|
||||
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
|
||||
Decoded = unmarshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, ModernizedBinary),
|
||||
@ -139,9 +136,11 @@ created_v1_decoding_test() ->
|
||||
status_changes_v1_decoding_test() ->
|
||||
Change = {status_changed, succeeded},
|
||||
Event = {ev, {{{2020, 5, 25}, {19, 19, 10}}, 293305}, Change},
|
||||
LegacyEvent = {bin, base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgwAAgwAAQwAAgAAAAAA"
|
||||
>>)},
|
||||
LegacyEvent =
|
||||
{bin,
|
||||
base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgwAAgwAAQwAAgAAAAAA"
|
||||
>>)},
|
||||
DecodedLegacy = unmarshal({event, 1}, LegacyEvent),
|
||||
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
|
||||
Decoded = unmarshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, ModernizedBinary),
|
||||
@ -151,9 +150,11 @@ status_changes_v1_decoding_test() ->
|
||||
limit_check_v1_decoding_test() ->
|
||||
Change = {limit_check, {wallet_sender, ok}},
|
||||
Event = {ev, {{{2020, 5, 25}, {19, 19, 10}}, 293305}, Change},
|
||||
LegacyEvent = {bin, base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgwABQwAAQwAAQwAAQAAAAAAAA=="
|
||||
>>)},
|
||||
LegacyEvent =
|
||||
{bin,
|
||||
base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgwABQwAAQwAAQwAAQAAAAAAAA=="
|
||||
>>)},
|
||||
DecodedLegacy = unmarshal({event, 1}, LegacyEvent),
|
||||
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
|
||||
Decoded = unmarshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, ModernizedBinary),
|
||||
@ -161,15 +162,19 @@ limit_check_v1_decoding_test() ->
|
||||
|
||||
-spec p_transfer_created_v1_decoding_test() -> _.
|
||||
p_transfer_created_v1_decoding_test() ->
|
||||
Change = {p_transfer, {created, #{
|
||||
id => <<"id">>,
|
||||
final_cash_flow => #{postings => []}
|
||||
}}},
|
||||
Change =
|
||||
{p_transfer,
|
||||
{created, #{
|
||||
id => <<"id">>,
|
||||
final_cash_flow => #{postings => []}
|
||||
}}},
|
||||
Event = {ev, {{{2020, 5, 25}, {19, 19, 10}}, 293305}, Change},
|
||||
LegacyEvent = {bin, base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgwAAwwAAQwAAQwAAQ"
|
||||
"sAAgAAAAJpZAwAAQ8AAQwAAAAAAAAAAAAAAA=="
|
||||
>>)},
|
||||
LegacyEvent =
|
||||
{bin,
|
||||
base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgwAAwwAAQwAAQwAAQ"
|
||||
"sAAgAAAAJpZAwAAQ8AAQwAAAAAAAAAAAAAAA=="
|
||||
>>)},
|
||||
DecodedLegacy = unmarshal({event, 1}, LegacyEvent),
|
||||
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
|
||||
Decoded = unmarshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, ModernizedBinary),
|
||||
@ -177,14 +182,18 @@ p_transfer_created_v1_decoding_test() ->
|
||||
|
||||
-spec p_transfer_clock_updated_v1_decoding_test() -> _.
|
||||
p_transfer_clock_updated_v1_decoding_test() ->
|
||||
Change = {p_transfer, {clock_updated, #{
|
||||
version => 1,
|
||||
type => latest
|
||||
}}},
|
||||
Change =
|
||||
{p_transfer,
|
||||
{clock_updated, #{
|
||||
version => 1,
|
||||
type => latest
|
||||
}}},
|
||||
Event = {ev, {{{2020, 5, 25}, {19, 19, 10}}, 293305}, Change},
|
||||
LegacyEvent = {bin, base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgwAAwwAAQwAAwwAAQwAAQAAAAAAAAA="
|
||||
>>)},
|
||||
LegacyEvent =
|
||||
{bin,
|
||||
base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgwAAwwAAQwAAwwAAQwAAQAAAAAAAAA="
|
||||
>>)},
|
||||
DecodedLegacy = unmarshal({event, 1}, LegacyEvent),
|
||||
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
|
||||
Decoded = unmarshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, ModernizedBinary),
|
||||
@ -194,9 +203,11 @@ p_transfer_clock_updated_v1_decoding_test() ->
|
||||
p_transfer_status_changed_v1_decoding_test() ->
|
||||
Change = {p_transfer, {status_changed, committed}},
|
||||
Event = {ev, {{{2020, 5, 25}, {19, 19, 10}}, 293305}, Change},
|
||||
LegacyEvent = {bin, base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgwAAwwAAQwAAgwAAQwAAwAAAAAAAAA="
|
||||
>>)},
|
||||
LegacyEvent =
|
||||
{bin,
|
||||
base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgwAAwwAAQwAAgwAAQwAAwAAAAAAAAA="
|
||||
>>)},
|
||||
DecodedLegacy = unmarshal({event, 1}, LegacyEvent),
|
||||
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
|
||||
Decoded = unmarshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, ModernizedBinary),
|
||||
@ -204,27 +215,31 @@ p_transfer_status_changed_v1_decoding_test() ->
|
||||
|
||||
-spec adjustment_created_v1_decoding_test() -> _.
|
||||
adjustment_created_v1_decoding_test() ->
|
||||
Change = {adjustment, #{
|
||||
id => <<"id">>,
|
||||
payload => {created, #{
|
||||
version => 1,
|
||||
Change =
|
||||
{adjustment, #{
|
||||
id => <<"id">>,
|
||||
status => succeeded,
|
||||
created_at => 1590426777985,
|
||||
changes_plan => #{},
|
||||
domain_revision => 123,
|
||||
party_revision => 321,
|
||||
operation_timestamp => 1590426777985,
|
||||
external_id => <<"external_id">>
|
||||
}}
|
||||
}},
|
||||
payload =>
|
||||
{created, #{
|
||||
version => 1,
|
||||
id => <<"id">>,
|
||||
status => succeeded,
|
||||
created_at => 1590426777985,
|
||||
changes_plan => #{},
|
||||
domain_revision => 123,
|
||||
party_revision => 321,
|
||||
operation_timestamp => 1590426777985,
|
||||
external_id => <<"external_id">>
|
||||
}}
|
||||
}},
|
||||
Event = {ev, {{{2020, 5, 25}, {19, 19, 10}}, 293305}, Change},
|
||||
LegacyEvent = {bin, base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgwABAsAAQAAAAJpZAwAAgwAAQwAAQs"
|
||||
"AAQAAAAJpZAwAAgwAAgAADAADAAsABAAAABgyMDIwLTA1LTI1VDE3OjEyOjU3Ljk4NVoKAAUAAAAAAA"
|
||||
"AAewoABgAAAAAAAAFBCwAHAAAAC2V4dGVybmFsX2lkCwAIAAAAGDIwMjAtMDUtMjVUMTc6MTI6NTcuO"
|
||||
"Tg1WgAAAAAAAA=="
|
||||
>>)},
|
||||
LegacyEvent =
|
||||
{bin,
|
||||
base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgwABAsAAQAAAAJpZAwAAgwAAQwAAQs"
|
||||
"AAQAAAAJpZAwAAgwAAgAADAADAAsABAAAABgyMDIwLTA1LTI1VDE3OjEyOjU3Ljk4NVoKAAUAAAAAAA"
|
||||
"AAewoABgAAAAAAAAFBCwAHAAAAC2V4dGVybmFsX2lkCwAIAAAAGDIwMjAtMDUtMjVUMTc6MTI6NTcuO"
|
||||
"Tg1WgAAAAAAAA=="
|
||||
>>)},
|
||||
DecodedLegacy = unmarshal({event, 1}, LegacyEvent),
|
||||
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
|
||||
Decoded = unmarshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, ModernizedBinary),
|
||||
|
@ -12,8 +12,7 @@
|
||||
%% ff_woody_wrapper callbacks
|
||||
%%
|
||||
|
||||
-spec handle_function(woody:func(), woody:args(), options()) ->
|
||||
{ok, woody:result()} | no_return().
|
||||
-spec handle_function(woody:func(), woody:args(), options()) -> {ok, woody:result()} | no_return().
|
||||
handle_function('Repair', [ID, Scenario], _Opts) ->
|
||||
DecodedScenario = ff_w2w_transfer_codec:unmarshal(repair_scenario, Scenario),
|
||||
case w2w_transfer_machine:repair(ID, DecodedScenario) of
|
||||
|
@ -9,30 +9,23 @@
|
||||
|
||||
%% API
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) ->
|
||||
ff_codec:encoded_value().
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) -> ff_codec:encoded_value().
|
||||
marshal(status, pending) ->
|
||||
{pending, #w2w_status_Pending{}};
|
||||
marshal(status, succeeded) ->
|
||||
{succeeded, #w2w_status_Succeeded{}};
|
||||
marshal(status, {failed, Failure}) ->
|
||||
{failed, #w2w_status_Failed{failure = marshal(failure, Failure)}};
|
||||
|
||||
marshal(T, V) ->
|
||||
ff_codec:marshal(T, V).
|
||||
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) ->
|
||||
ff_codec:decoded_value().
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) -> ff_codec:decoded_value().
|
||||
unmarshal(status, {pending, #w2w_status_Pending{}}) ->
|
||||
pending;
|
||||
unmarshal(status, {succeeded, #w2w_status_Succeeded{}}) ->
|
||||
succeeded;
|
||||
unmarshal(status, {failed, #w2w_status_Failed{failure = Failure}}) ->
|
||||
{failed, unmarshal(failure, Failure)};
|
||||
|
||||
unmarshal(T, V) ->
|
||||
ff_codec:unmarshal(T, V).
|
||||
|
||||
@ -40,9 +33,11 @@ unmarshal(T, V) ->
|
||||
|
||||
-ifdef(TEST).
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
-spec test() -> _.
|
||||
|
||||
-spec pending_symmetry_test() -> _.
|
||||
|
||||
pending_symmetry_test() ->
|
||||
Status = pending,
|
||||
?assertEqual(Status, unmarshal(status, marshal(status, Status))).
|
||||
@ -54,13 +49,14 @@ succeeded_symmetry_test() ->
|
||||
|
||||
-spec failed_symmetry_test() -> _.
|
||||
failed_symmetry_test() ->
|
||||
Status = {failed, #{
|
||||
code => <<"test">>,
|
||||
reason => <<"why not">>,
|
||||
sub => #{
|
||||
code => <<"sub">>
|
||||
}
|
||||
}},
|
||||
Status =
|
||||
{failed, #{
|
||||
code => <<"test">>,
|
||||
reason => <<"why not">>,
|
||||
sub => #{
|
||||
code => <<"sub">>
|
||||
}
|
||||
}},
|
||||
?assertEqual(Status, unmarshal(status, marshal(status, Status))).
|
||||
|
||||
-endif.
|
||||
|
@ -13,7 +13,6 @@
|
||||
%% API
|
||||
-spec marshal_wallet_state(ff_wallet:wallet_state(), ff_wallet:id(), ff_entity_context:context()) ->
|
||||
ff_proto_wallet_thrift:'WalletState'().
|
||||
|
||||
marshal_wallet_state(WalletState, ID, Context) ->
|
||||
#wlt_WalletState{
|
||||
id = marshal(id, ID),
|
||||
@ -26,9 +25,7 @@ marshal_wallet_state(WalletState, ID, Context) ->
|
||||
context = marshal(ctx, Context)
|
||||
}.
|
||||
|
||||
-spec unmarshal_wallet_params(ff_proto_wallet_thrift:'WalletParams'()) ->
|
||||
ff_wallet_machine:params().
|
||||
|
||||
-spec unmarshal_wallet_params(ff_proto_wallet_thrift:'WalletParams'()) -> ff_wallet_machine:params().
|
||||
unmarshal_wallet_params(#wlt_WalletParams{
|
||||
id = ID,
|
||||
account_params = AccountParams,
|
||||
@ -38,28 +35,24 @@ unmarshal_wallet_params(#wlt_WalletParams{
|
||||
}) ->
|
||||
{IdentityID, Currency} = unmarshal(account_params, AccountParams),
|
||||
genlib_map:compact(#{
|
||||
id => unmarshal(id, ID),
|
||||
name => unmarshal(string, Name),
|
||||
identity => IdentityID,
|
||||
currency => Currency,
|
||||
id => unmarshal(id, ID),
|
||||
name => unmarshal(string, Name),
|
||||
identity => IdentityID,
|
||||
currency => Currency,
|
||||
external_id => maybe_unmarshal(id, ExternalID),
|
||||
metadata => maybe_unmarshal(ctx, Metadata)
|
||||
metadata => maybe_unmarshal(ctx, Metadata)
|
||||
}).
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) ->
|
||||
ff_codec:encoded_value().
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) -> ff_codec:encoded_value().
|
||||
marshal(timestamped_change, {ev, Timestamp, Change}) ->
|
||||
#wlt_TimestampedChange{
|
||||
change = marshal(change, Change),
|
||||
occured_at = ff_codec:marshal(timestamp, Timestamp)
|
||||
};
|
||||
|
||||
marshal(change, {created, Wallet}) ->
|
||||
{created, marshal(wallet, Wallet)};
|
||||
marshal(change, {account, AccountChange}) ->
|
||||
{account, marshal(account_change, AccountChange)};
|
||||
|
||||
marshal(wallet, Wallet) ->
|
||||
#wlt_Wallet{
|
||||
name = marshal(string, maps:get(name, Wallet, <<>>)),
|
||||
@ -68,7 +61,6 @@ marshal(wallet, Wallet) ->
|
||||
created_at = maybe_marshal(timestamp_ms, maps:get(created_at, Wallet, undefined)),
|
||||
metadata = maybe_marshal(ctx, maps:get(metadata, Wallet, undefined))
|
||||
};
|
||||
|
||||
marshal(wallet_account_balance, AccountBalance) ->
|
||||
#account_AccountBalance{
|
||||
id = marshal(id, maps:get(id, AccountBalance)),
|
||||
@ -77,36 +69,28 @@ marshal(wallet_account_balance, AccountBalance) ->
|
||||
current = marshal(amount, maps:get(current, AccountBalance)),
|
||||
expected_max = marshal(amount, maps:get(expected_max, AccountBalance))
|
||||
};
|
||||
|
||||
marshal(ctx, Ctx) ->
|
||||
marshal(context, Ctx);
|
||||
|
||||
marshal(T, V) ->
|
||||
ff_codec:marshal(T, V).
|
||||
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) ->
|
||||
ff_codec:decoded_value().
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) -> ff_codec:decoded_value().
|
||||
unmarshal({list, T}, V) ->
|
||||
[unmarshal(T, E) || E <- V];
|
||||
|
||||
unmarshal(timestamped_change, TimestampedChange) ->
|
||||
Timestamp = ff_codec:unmarshal(timestamp, TimestampedChange#wlt_TimestampedChange.occured_at),
|
||||
Change = unmarshal(change, TimestampedChange#wlt_TimestampedChange.change),
|
||||
{ev, Timestamp, Change};
|
||||
|
||||
unmarshal(repair_scenario, {add_events, #wlt_AddEventsRepair{events = Events, action = Action}}) ->
|
||||
{add_events, genlib_map:compact(#{
|
||||
events => unmarshal({list, change}, Events),
|
||||
action => maybe_unmarshal(complex_action, Action)
|
||||
})};
|
||||
|
||||
{add_events,
|
||||
genlib_map:compact(#{
|
||||
events => unmarshal({list, change}, Events),
|
||||
action => maybe_unmarshal(complex_action, Action)
|
||||
})};
|
||||
unmarshal(change, {created, Wallet}) ->
|
||||
{created, unmarshal(wallet, Wallet)};
|
||||
unmarshal(change, {account, AccountChange}) ->
|
||||
{account, unmarshal(account_change, AccountChange)};
|
||||
|
||||
unmarshal(wallet, #wlt_Wallet{
|
||||
name = Name,
|
||||
blocking = Blocking,
|
||||
@ -122,16 +106,13 @@ unmarshal(wallet, #wlt_Wallet{
|
||||
external_id => maybe_unmarshal(id, ExternalID),
|
||||
metadata => maybe_unmarshal(ctx, Metadata)
|
||||
});
|
||||
|
||||
unmarshal(account_params, #account_AccountParams{
|
||||
identity_id = IdentityID,
|
||||
identity_id = IdentityID,
|
||||
symbolic_code = SymbolicCode
|
||||
}) ->
|
||||
{unmarshal(id, IdentityID), unmarshal(string, SymbolicCode) };
|
||||
|
||||
{unmarshal(id, IdentityID), unmarshal(string, SymbolicCode)};
|
||||
unmarshal(ctx, Ctx) ->
|
||||
maybe_unmarshal(context, Ctx);
|
||||
|
||||
unmarshal(T, V) ->
|
||||
ff_codec:unmarshal(T, V).
|
||||
|
||||
@ -146,4 +127,3 @@ maybe_unmarshal(_Type, undefined) ->
|
||||
undefined;
|
||||
maybe_unmarshal(Type, Value) ->
|
||||
unmarshal(Type, Value).
|
||||
|
||||
|
@ -9,32 +9,28 @@
|
||||
-type event() :: ff_eventsink_publisher:event(ff_wallet:event()).
|
||||
-type sinkevent() :: ff_eventsink_publisher:sinkevent(ff_proto_wallet_thrift:'SinkEvent'()).
|
||||
|
||||
-spec publish_events(list(event())) ->
|
||||
list(sinkevent()).
|
||||
|
||||
-spec publish_events(list(event())) -> list(sinkevent()).
|
||||
publish_events(Events) ->
|
||||
[publish_event(Event) || Event <- Events].
|
||||
|
||||
-spec publish_event(event()) ->
|
||||
sinkevent().
|
||||
|
||||
-spec publish_event(event()) -> sinkevent().
|
||||
publish_event(#{
|
||||
id := ID,
|
||||
source_id := SourceID,
|
||||
event := {
|
||||
id := ID,
|
||||
source_id := SourceID,
|
||||
event := {
|
||||
EventID,
|
||||
Dt,
|
||||
{ev, EventDt, Payload}
|
||||
}
|
||||
}) ->
|
||||
#wlt_SinkEvent{
|
||||
id = marshal(event_id, ID),
|
||||
created_at = marshal(timestamp, Dt),
|
||||
source = marshal(id, SourceID),
|
||||
payload = #wlt_Event{
|
||||
sequence = marshal(event_id, EventID),
|
||||
id = marshal(event_id, ID),
|
||||
created_at = marshal(timestamp, Dt),
|
||||
source = marshal(id, SourceID),
|
||||
payload = #wlt_Event{
|
||||
sequence = marshal(event_id, EventID),
|
||||
occured_at = marshal(timestamp, EventDt),
|
||||
changes = [marshal(change, Payload)]
|
||||
changes = [marshal(change, Payload)]
|
||||
}
|
||||
}.
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
-module(ff_wallet_handler).
|
||||
|
||||
-behaviour(ff_woody_wrapper).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_wallet_thrift.hrl").
|
||||
@ -9,11 +10,11 @@
|
||||
%%
|
||||
%% ff_woody_wrapper callbacks
|
||||
%%
|
||||
-spec handle_function(woody:func(), woody:args(), woody:options()) ->
|
||||
{ok, woody:result()} | no_return().
|
||||
|
||||
-spec handle_function(woody:func(), woody:args(), woody:options()) -> {ok, woody:result()} | no_return().
|
||||
handle_function(Func, Args, Opts) ->
|
||||
scoper:scope(wallet, #{},
|
||||
scoper:scope(
|
||||
wallet,
|
||||
#{},
|
||||
fun() ->
|
||||
handle_function_(Func, Args, Opts)
|
||||
end
|
||||
@ -24,9 +25,11 @@ handle_function(Func, Args, Opts) ->
|
||||
%%
|
||||
handle_function_('Create', [Params, Context], Opts) ->
|
||||
WalletID = Params#wlt_WalletParams.id,
|
||||
case ff_wallet_machine:create(
|
||||
ff_wallet_codec:unmarshal_wallet_params(Params),
|
||||
ff_wallet_codec:unmarshal(ctx, Context))
|
||||
case
|
||||
ff_wallet_machine:create(
|
||||
ff_wallet_codec:unmarshal_wallet_params(Params),
|
||||
ff_wallet_codec:unmarshal(ctx, Context)
|
||||
)
|
||||
of
|
||||
ok ->
|
||||
handle_function_('Get', [WalletID, #'EventRange'{}], Opts);
|
||||
@ -41,28 +44,25 @@ handle_function_('Create', [Params, Context], Opts) ->
|
||||
{error, Error} ->
|
||||
woody_error:raise(system, {internal, result_unexpected, woody_error:format_details(Error)})
|
||||
end;
|
||||
|
||||
handle_function_('Get', [ID, EventRange], _Opts) ->
|
||||
case ff_wallet_machine:get(ID, ff_codec:unmarshal(event_range, EventRange)) of
|
||||
{ok, Machine} ->
|
||||
Wallet = ff_wallet_machine:wallet(Machine),
|
||||
Ctx = ff_wallet_machine:ctx(Machine),
|
||||
Response = ff_wallet_codec:marshal_wallet_state(Wallet, ID, Ctx),
|
||||
Wallet = ff_wallet_machine:wallet(Machine),
|
||||
Ctx = ff_wallet_machine:ctx(Machine),
|
||||
Response = ff_wallet_codec:marshal_wallet_state(Wallet, ID, Ctx),
|
||||
{ok, Response};
|
||||
{error, notfound} ->
|
||||
woody_error:raise(business, #fistful_WalletNotFound{})
|
||||
end;
|
||||
|
||||
handle_function_('GetContext', [ID], _Opts) ->
|
||||
case ff_wallet_machine:get(ID, {undefined, 0}) of
|
||||
{ok, Machine} ->
|
||||
Ctx = ff_wallet_machine:ctx(Machine),
|
||||
Response = ff_wallet_codec:marshal(ctx, Ctx),
|
||||
Ctx = ff_wallet_machine:ctx(Machine),
|
||||
Response = ff_wallet_codec:marshal(ctx, Ctx),
|
||||
{ok, Response};
|
||||
{error, notfound} ->
|
||||
woody_error:raise(business, #fistful_WalletNotFound{})
|
||||
end;
|
||||
|
||||
handle_function_('GetAccountBalance', [ID], _Opts) ->
|
||||
case ff_wallet_machine:get(ID) of
|
||||
{ok, Machine} ->
|
||||
|
@ -21,60 +21,56 @@
|
||||
-type value_type() :: machinery_mg_schema:vt().
|
||||
-type context() :: machinery_mg_schema:context().
|
||||
|
||||
-type event() :: ff_machine:timestamped_event(p2p_transfer:event()).
|
||||
-type event() :: ff_machine:timestamped_event(p2p_transfer:event()).
|
||||
-type aux_state() :: ff_machine:auxst().
|
||||
-type call_args() :: term().
|
||||
-type call_response() :: term().
|
||||
|
||||
-type data() ::
|
||||
aux_state() |
|
||||
event() |
|
||||
call_args() |
|
||||
call_response().
|
||||
aux_state()
|
||||
| event()
|
||||
| call_args()
|
||||
| call_response().
|
||||
|
||||
%% machinery_mg_schema callbacks
|
||||
|
||||
-spec get_version(value_type()) ->
|
||||
machinery_mg_schema:version().
|
||||
-spec get_version(value_type()) -> machinery_mg_schema:version().
|
||||
get_version(event) ->
|
||||
?CURRENT_EVENT_FORMAT_VERSION;
|
||||
get_version(aux_state) ->
|
||||
undefined.
|
||||
|
||||
-spec marshal(type(), value(data()), context()) ->
|
||||
{machinery_msgpack:t(), context()}.
|
||||
-spec marshal(type(), value(data()), context()) -> {machinery_msgpack:t(), context()}.
|
||||
marshal({event, Format}, TimestampedChange, Context) ->
|
||||
marshal_event(Format, TimestampedChange, Context);
|
||||
marshal(T, V, C) when
|
||||
T =:= {args, init} orelse
|
||||
T =:= {args, call} orelse
|
||||
T =:= {args, repair} orelse
|
||||
T =:= {aux_state, undefined} orelse
|
||||
T =:= {response, call} orelse
|
||||
T =:= {response, {repair, success}} orelse
|
||||
T =:= {response, {repair, failure}}
|
||||
T =:= {args, call} orelse
|
||||
T =:= {args, repair} orelse
|
||||
T =:= {aux_state, undefined} orelse
|
||||
T =:= {response, call} orelse
|
||||
T =:= {response, {repair, success}} orelse
|
||||
T =:= {response, {repair, failure}}
|
||||
->
|
||||
machinery_mg_schema_generic:marshal(T, V, C).
|
||||
|
||||
-spec unmarshal(type(), machinery_msgpack:t(), context()) ->
|
||||
{data(), context()}.
|
||||
-spec unmarshal(type(), machinery_msgpack:t(), context()) -> {data(), context()}.
|
||||
unmarshal({event, FormatVersion}, EncodedChange, Context) ->
|
||||
unmarshal_event(FormatVersion, EncodedChange, Context);
|
||||
unmarshal(T, V, C) when
|
||||
T =:= {args, init} orelse
|
||||
T =:= {args, call} orelse
|
||||
T =:= {args, repair} orelse
|
||||
T =:= {aux_state, undefined} orelse
|
||||
T =:= {response, call} orelse
|
||||
T =:= {response, {repair, success}} orelse
|
||||
T =:= {response, {repair, failure}}
|
||||
T =:= {args, call} orelse
|
||||
T =:= {args, repair} orelse
|
||||
T =:= {aux_state, undefined} orelse
|
||||
T =:= {response, call} orelse
|
||||
T =:= {response, {repair, success}} orelse
|
||||
T =:= {response, {repair, failure}}
|
||||
->
|
||||
machinery_mg_schema_generic:unmarshal(T, V, C).
|
||||
|
||||
%% Internals
|
||||
|
||||
-spec marshal_event(machinery_mg_schema:version(), event(), context()) ->
|
||||
{machinery_msgpack:t(), context()}.
|
||||
-spec marshal_event(machinery_mg_schema:version(), event(), context()) -> {machinery_msgpack:t(), context()}.
|
||||
marshal_event(undefined = Version, TimestampedChange, Context) ->
|
||||
% TODO: Удалить после выкатки
|
||||
machinery_mg_schema_generic:marshal({event, Version}, TimestampedChange, Context);
|
||||
@ -83,8 +79,7 @@ marshal_event(1, TimestampedChange, Context) ->
|
||||
Type = {struct, struct, {ff_proto_wallet_thrift, 'TimestampedChange'}},
|
||||
{{bin, ff_proto_utils:serialize(Type, ThriftChange)}, Context}.
|
||||
|
||||
-spec unmarshal_event(machinery_mg_schema:version(), machinery_msgpack:t(), context()) ->
|
||||
{event(), context()}.
|
||||
-spec unmarshal_event(machinery_mg_schema:version(), machinery_msgpack:t(), context()) -> {event(), context()}.
|
||||
unmarshal_event(1, EncodedChange, Context) ->
|
||||
{bin, EncodedThriftChange} = EncodedChange,
|
||||
Type = {struct, struct, {ff_proto_wallet_thrift, 'TimestampedChange'}},
|
||||
@ -95,135 +90,147 @@ unmarshal_event(undefined = Version, EncodedChange, Context0) ->
|
||||
{ev, Timestamp, Change} = Event,
|
||||
{{ev, Timestamp, maybe_migrate(Change, Context1)}, Context1}.
|
||||
|
||||
-spec maybe_migrate(any(), context()) ->
|
||||
ff_wallet:event().
|
||||
-spec maybe_migrate(any(), context()) -> ff_wallet:event().
|
||||
maybe_migrate(Event = {created, #{version := 2}}, _MigrateContext) ->
|
||||
Event;
|
||||
maybe_migrate({created, Wallet = #{version := 1}}, MigrateContext) ->
|
||||
Context = case maps:get(machine_ref, MigrateContext, undefined) of
|
||||
undefined ->
|
||||
undefined;
|
||||
ID ->
|
||||
{ok, State} = ff_machine:get(ff_wallet, 'ff/wallet_v2', ID, {undefined, 0, forward}),
|
||||
maps:get(ctx, State, undefined)
|
||||
end,
|
||||
maybe_migrate({created, genlib_map:compact(Wallet#{
|
||||
version => 2,
|
||||
metadata => ff_entity_context:try_get_legacy_metadata(Context)
|
||||
})}, MigrateContext);
|
||||
Context =
|
||||
case maps:get(machine_ref, MigrateContext, undefined) of
|
||||
undefined ->
|
||||
undefined;
|
||||
ID ->
|
||||
{ok, State} = ff_machine:get(ff_wallet, 'ff/wallet_v2', ID, {undefined, 0, forward}),
|
||||
maps:get(ctx, State, undefined)
|
||||
end,
|
||||
maybe_migrate(
|
||||
{created,
|
||||
genlib_map:compact(Wallet#{
|
||||
version => 2,
|
||||
metadata => ff_entity_context:try_get_legacy_metadata(Context)
|
||||
})},
|
||||
MigrateContext
|
||||
);
|
||||
maybe_migrate({created, Wallet}, MigrateContext) ->
|
||||
Timestamp = maps:get(created_at, MigrateContext),
|
||||
CreatedAt = ff_codec:unmarshal(timestamp_ms, ff_codec:marshal(timestamp, Timestamp)),
|
||||
maybe_migrate({created, Wallet#{
|
||||
version => 1,
|
||||
created_at => CreatedAt
|
||||
}}, MigrateContext);
|
||||
maybe_migrate(
|
||||
{created, Wallet#{
|
||||
version => 1,
|
||||
created_at => CreatedAt
|
||||
}},
|
||||
MigrateContext
|
||||
);
|
||||
maybe_migrate(Ev, _MigrateContext) ->
|
||||
Ev.
|
||||
|
||||
|
||||
%% Tests
|
||||
|
||||
-ifdef(TEST).
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
-spec test() -> _.
|
||||
|
||||
% tests helpers
|
||||
|
||||
-spec marshal(type(), value(data())) ->
|
||||
machinery_msgpack:t().
|
||||
-spec marshal(type(), value(data())) -> machinery_msgpack:t().
|
||||
|
||||
marshal(Type, Value) ->
|
||||
{Result, _Context} = marshal(Type, Value, #{}),
|
||||
Result.
|
||||
|
||||
-spec unmarshal(type(), machinery_msgpack:t()) ->
|
||||
data().
|
||||
-spec unmarshal(type(), machinery_msgpack:t()) -> data().
|
||||
unmarshal(Type, Value) ->
|
||||
{Result, _Context} = unmarshal(Type, Value, #{}),
|
||||
Result.
|
||||
|
||||
-spec created_v0_2_decoding_test() -> _.
|
||||
created_v0_2_decoding_test() ->
|
||||
Change = {created, #{
|
||||
version => 2,
|
||||
name => <<"name">>,
|
||||
blocking => unblocked,
|
||||
created_at => 123
|
||||
}},
|
||||
Change =
|
||||
{created, #{
|
||||
version => 2,
|
||||
name => <<"name">>,
|
||||
blocking => unblocked,
|
||||
created_at => 123
|
||||
}},
|
||||
Event = {ev, {{{2020, 5, 25}, {19, 19, 10}}, 293305}, Change},
|
||||
LegacyChange = {arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"created">>},
|
||||
{arr, [
|
||||
{str, <<"map">>},
|
||||
{obj, #{
|
||||
{str, <<"version">>} => {i, 1},
|
||||
{str, <<"name">>} => {bin, <<"name">>},
|
||||
{str, <<"blocking">>} => {str, <<"unblocked">>},
|
||||
{str, <<"created_at">>} => {i, 123}
|
||||
}}
|
||||
]}
|
||||
]},
|
||||
LegacyEvent = {arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"ev">>},
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{arr, [{str, <<"tup">>}, {i, 2020}, {i, 5}, {i, 25}]},
|
||||
{arr, [{str, <<"tup">>}, {i, 19}, {i, 19}, {i, 10}]}
|
||||
]},
|
||||
{i, 293305}
|
||||
]},
|
||||
LegacyChange
|
||||
]},
|
||||
DecodedLegacy = unmarshal({event, undefined}, LegacyEvent),
|
||||
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
|
||||
Decoded = unmarshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, ModernizedBinary),
|
||||
?assertEqual(Event, Decoded).
|
||||
|
||||
|
||||
-spec created_account_v0_2_decoding_test() -> _.
|
||||
created_account_v0_2_decoding_test() ->
|
||||
Change = {account, {created, #{
|
||||
id => <<"id">>,
|
||||
identity => <<"identity_id">>,
|
||||
currency => <<"RUB">>,
|
||||
accounter_account_id => 123
|
||||
}}},
|
||||
Event = {ev, {{{2020, 5, 25}, {19, 19, 10}}, 293305}, Change},
|
||||
LegacyChange = {arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"account">>},
|
||||
LegacyChange =
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"created">>},
|
||||
{arr, [
|
||||
{str, <<"map">>},
|
||||
{obj, #{
|
||||
{str, <<"id">>} => {bin, <<"id">>},
|
||||
{str, <<"identity">>} => {bin, <<"identity_id">>},
|
||||
{str, <<"currency">>} => {bin, <<"RUB">>},
|
||||
{str, <<"accounter_account_id">>} => {i, 123}
|
||||
{str, <<"version">>} => {i, 1},
|
||||
{str, <<"name">>} => {bin, <<"name">>},
|
||||
{str, <<"blocking">>} => {str, <<"unblocked">>},
|
||||
{str, <<"created_at">>} => {i, 123}
|
||||
}}
|
||||
]}
|
||||
]}
|
||||
]},
|
||||
LegacyEvent = {arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"ev">>},
|
||||
]},
|
||||
LegacyEvent =
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"ev">>},
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{arr, [{str, <<"tup">>}, {i, 2020}, {i, 5}, {i, 25}]},
|
||||
{arr, [{str, <<"tup">>}, {i, 19}, {i, 19}, {i, 10}]}
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{arr, [{str, <<"tup">>}, {i, 2020}, {i, 5}, {i, 25}]},
|
||||
{arr, [{str, <<"tup">>}, {i, 19}, {i, 19}, {i, 10}]}
|
||||
]},
|
||||
{i, 293305}
|
||||
]},
|
||||
{i, 293305}
|
||||
LegacyChange
|
||||
]},
|
||||
DecodedLegacy = unmarshal({event, undefined}, LegacyEvent),
|
||||
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
|
||||
Decoded = unmarshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, ModernizedBinary),
|
||||
?assertEqual(Event, Decoded).
|
||||
|
||||
-spec created_account_v0_2_decoding_test() -> _.
|
||||
created_account_v0_2_decoding_test() ->
|
||||
Change =
|
||||
{account,
|
||||
{created, #{
|
||||
id => <<"id">>,
|
||||
identity => <<"identity_id">>,
|
||||
currency => <<"RUB">>,
|
||||
accounter_account_id => 123
|
||||
}}},
|
||||
Event = {ev, {{{2020, 5, 25}, {19, 19, 10}}, 293305}, Change},
|
||||
LegacyChange =
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"account">>},
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"created">>},
|
||||
{arr, [
|
||||
{str, <<"map">>},
|
||||
{obj, #{
|
||||
{str, <<"id">>} => {bin, <<"id">>},
|
||||
{str, <<"identity">>} => {bin, <<"identity_id">>},
|
||||
{str, <<"currency">>} => {bin, <<"RUB">>},
|
||||
{str, <<"accounter_account_id">>} => {i, 123}
|
||||
}}
|
||||
]}
|
||||
]}
|
||||
]},
|
||||
LegacyEvent =
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{str, <<"ev">>},
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{arr, [
|
||||
{str, <<"tup">>},
|
||||
{arr, [{str, <<"tup">>}, {i, 2020}, {i, 5}, {i, 25}]},
|
||||
{arr, [{str, <<"tup">>}, {i, 19}, {i, 19}, {i, 10}]}
|
||||
]},
|
||||
{i, 293305}
|
||||
]},
|
||||
LegacyChange
|
||||
]},
|
||||
LegacyChange
|
||||
]},
|
||||
DecodedLegacy = unmarshal({event, undefined}, LegacyEvent),
|
||||
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
|
||||
Decoded = unmarshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, ModernizedBinary),
|
||||
@ -231,17 +238,20 @@ created_account_v0_2_decoding_test() ->
|
||||
|
||||
-spec created_v2_decoding_test() -> _.
|
||||
created_v2_decoding_test() ->
|
||||
Change = {created, #{
|
||||
version => 2,
|
||||
name => <<"name">>,
|
||||
blocking => unblocked,
|
||||
created_at => 123
|
||||
}},
|
||||
Change =
|
||||
{created, #{
|
||||
version => 2,
|
||||
name => <<"name">>,
|
||||
blocking => unblocked,
|
||||
created_at => 123
|
||||
}},
|
||||
Event = {ev, {{{2020, 5, 25}, {19, 19, 10}}, 293305}, Change},
|
||||
LegacyEvent = {bin, base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgwAAQsAAQAAAARuYW1lC"
|
||||
"AAEAAAAAAsABgAAABgxOTcwLTAxLTAxVDAwOjAwOjAwLjEyM1oAAAA="
|
||||
>>)},
|
||||
LegacyEvent =
|
||||
{bin,
|
||||
base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgwAAQsAAQAAAARuYW1lC"
|
||||
"AAEAAAAAAsABgAAABgxOTcwLTAxLTAxVDAwOjAwOjAwLjEyM1oAAAA="
|
||||
>>)},
|
||||
DecodedLegacy = unmarshal({event, 1}, LegacyEvent),
|
||||
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
|
||||
Decoded = unmarshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, ModernizedBinary),
|
||||
@ -249,17 +259,21 @@ created_v2_decoding_test() ->
|
||||
|
||||
-spec created_account_v2_decoding_test() -> _.
|
||||
created_account_v2_decoding_test() ->
|
||||
Change = {account, {created, #{
|
||||
id => <<"id">>,
|
||||
identity => <<"identity_id">>,
|
||||
currency => <<"RUB">>,
|
||||
accounter_account_id => 123
|
||||
}}},
|
||||
Change =
|
||||
{account,
|
||||
{created, #{
|
||||
id => <<"id">>,
|
||||
identity => <<"identity_id">>,
|
||||
currency => <<"RUB">>,
|
||||
accounter_account_id => 123
|
||||
}}},
|
||||
Event = {ev, {{{2020, 5, 25}, {19, 19, 10}}, 293305}, Change},
|
||||
LegacyEvent = {bin, base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgwAAgwAAQsAAwAAAAJpZAs"
|
||||
"AAQAAAAtpZGVudGl0eV9pZAwAAgsAAQAAAANSVUIACgAEAAAAAAAAAHsAAAAA"
|
||||
>>)},
|
||||
LegacyEvent =
|
||||
{bin,
|
||||
base64:decode(<<
|
||||
"CwABAAAAGzIwMjAtMDUtMjVUMTk6MTk6MTAuMjkzMzA1WgwAAgwAAgwAAQsAAwAAAAJpZAs"
|
||||
"AAQAAAAtpZGVudGl0eV9pZAwAAgsAAQAAAANSVUIACgAEAAAAAAAAAHsAAAAA"
|
||||
>>)},
|
||||
DecodedLegacy = unmarshal({event, 1}, LegacyEvent),
|
||||
ModernizedBinary = marshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, DecodedLegacy),
|
||||
Decoded = unmarshal({event, ?CURRENT_EVENT_FORMAT_VERSION}, ModernizedBinary),
|
||||
|
@ -1,4 +1,5 @@
|
||||
-module(ff_withdrawal_adapter_host).
|
||||
|
||||
-behaviour(ff_woody_wrapper).
|
||||
|
||||
-include_lib("damsel/include/dmsl_withdrawals_provider_adapter_thrift.hrl").
|
||||
@ -13,8 +14,7 @@
|
||||
|
||||
%% Handler
|
||||
|
||||
-spec handle_function(woody:func(), woody:args(), woody:options()) ->
|
||||
{ok, woody:result()} | no_return().
|
||||
-spec handle_function(woody:func(), woody:args(), woody:options()) -> {ok, woody:result()} | no_return().
|
||||
handle_function(Func, Args, Opts) ->
|
||||
scoper:scope(ff_withdrawal_adapter_host, #{}, fun() -> handle_function_(Func, Args, Opts) end).
|
||||
|
||||
|
@ -9,16 +9,13 @@
|
||||
|
||||
%% API
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) ->
|
||||
ff_codec:encoded_value().
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) -> ff_codec:encoded_value().
|
||||
marshal(change, {created, Adjustment}) ->
|
||||
{created, #wthd_adj_CreatedChange{adjustment = marshal(adjustment, Adjustment)}};
|
||||
marshal(change, {status_changed, Status}) ->
|
||||
{status_changed, #wthd_adj_StatusChange{status = marshal(status, Status)}};
|
||||
marshal(change, {p_transfer, TransferChange}) ->
|
||||
{transfer, #wthd_adj_TransferChange{payload = ff_p_transfer_codec:marshal(change, TransferChange)}};
|
||||
|
||||
marshal(adjustment, Adjustment) ->
|
||||
#wthd_adj_Adjustment{
|
||||
id = marshal(id, ff_adjustment:id(Adjustment)),
|
||||
@ -47,12 +44,10 @@ marshal(adjustment_state, Adjustment) ->
|
||||
operation_timestamp = marshal(timestamp_ms, ff_adjustment:operation_timestamp(Adjustment)),
|
||||
external_id = maybe_marshal(id, ff_adjustment:external_id(Adjustment))
|
||||
};
|
||||
|
||||
marshal(status, pending) ->
|
||||
{pending, #wthd_adj_Pending{}};
|
||||
marshal(status, succeeded) ->
|
||||
{succeeded, #wthd_adj_Succeeded{}};
|
||||
|
||||
marshal(changes_plan, Plan) ->
|
||||
#wthd_adj_ChangesPlan{
|
||||
new_cash_flow = maybe_marshal(cash_flow_change_plan, maps:get(new_cash_flow, Plan, undefined)),
|
||||
@ -69,26 +64,20 @@ marshal(status_change_plan, Plan) ->
|
||||
#wthd_adj_StatusChangePlan{
|
||||
new_status = ff_withdrawal_status_codec:marshal(status, maps:get(new_status, Plan))
|
||||
};
|
||||
|
||||
marshal(change_request, {change_status, Status}) ->
|
||||
{change_status, #wthd_adj_ChangeStatusRequest{
|
||||
new_status = ff_withdrawal_status_codec:marshal(status, Status)
|
||||
}};
|
||||
|
||||
marshal(T, V) ->
|
||||
ff_codec:marshal(T, V).
|
||||
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) ->
|
||||
ff_codec:decoded_value().
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) -> ff_codec:decoded_value().
|
||||
unmarshal(change, {created, #wthd_adj_CreatedChange{adjustment = Adjustment}}) ->
|
||||
{created, unmarshal(adjustment, Adjustment)};
|
||||
unmarshal(change, {status_changed, #wthd_adj_StatusChange{status = Status}}) ->
|
||||
{status_changed, unmarshal(status, Status)};
|
||||
unmarshal(change, {transfer, #wthd_adj_TransferChange{payload = TransferChange}}) ->
|
||||
{p_transfer, ff_p_transfer_codec:unmarshal(change, TransferChange)};
|
||||
|
||||
unmarshal(adjustment, Adjustment) ->
|
||||
#{
|
||||
id => unmarshal(id, Adjustment#wthd_adj_Adjustment.id),
|
||||
@ -100,19 +89,16 @@ unmarshal(adjustment, Adjustment) ->
|
||||
operation_timestamp => unmarshal(timestamp_ms, Adjustment#wthd_adj_Adjustment.operation_timestamp),
|
||||
external_id => maybe_unmarshal(id, Adjustment#wthd_adj_Adjustment.external_id)
|
||||
};
|
||||
|
||||
unmarshal(adjustment_params, Params) ->
|
||||
genlib_map:compact(#{
|
||||
id => unmarshal(id, Params#wthd_adj_AdjustmentParams.id),
|
||||
change => unmarshal(change_request, Params#wthd_adj_AdjustmentParams.change),
|
||||
external_id => maybe_unmarshal(id, Params#wthd_adj_AdjustmentParams.external_id)
|
||||
});
|
||||
|
||||
unmarshal(status, {pending, #wthd_adj_Pending{}}) ->
|
||||
pending;
|
||||
unmarshal(status, {succeeded, #wthd_adj_Succeeded{}}) ->
|
||||
succeeded;
|
||||
|
||||
unmarshal(changes_plan, Plan) ->
|
||||
genlib_map:compact(#{
|
||||
new_cash_flow => maybe_unmarshal(cash_flow_change_plan, Plan#wthd_adj_ChangesPlan.new_cash_flow),
|
||||
@ -130,11 +116,9 @@ unmarshal(status_change_plan, Plan) ->
|
||||
#{
|
||||
new_status => ff_withdrawal_status_codec:unmarshal(status, Status)
|
||||
};
|
||||
|
||||
unmarshal(change_request, {change_status, Request}) ->
|
||||
Status = Request#wthd_adj_ChangeStatusRequest.new_status,
|
||||
{change_status, ff_withdrawal_status_codec:unmarshal(status, Status)};
|
||||
|
||||
unmarshal(T, V) ->
|
||||
ff_codec:unmarshal(T, V).
|
||||
|
||||
@ -154,9 +138,11 @@ maybe_marshal(Type, Value) ->
|
||||
|
||||
-ifdef(TEST).
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
-spec test() -> _.
|
||||
|
||||
-spec adjustment_codec_test() -> _.
|
||||
|
||||
adjustment_codec_test() ->
|
||||
FinalCashFlow = #{
|
||||
postings => [
|
||||
|
@ -17,49 +17,42 @@
|
||||
|
||||
%% API
|
||||
|
||||
-spec unmarshal_quote_params(ff_proto_withdrawal_thrift:'QuoteParams'()) ->
|
||||
ff_withdrawal:quote_params().
|
||||
|
||||
-spec unmarshal_quote_params(ff_proto_withdrawal_thrift:'QuoteParams'()) -> ff_withdrawal:quote_params().
|
||||
unmarshal_quote_params(Params) ->
|
||||
genlib_map:compact(#{
|
||||
wallet_id => unmarshal(id, Params#wthd_QuoteParams.wallet_id),
|
||||
currency_from => unmarshal(currency_ref, Params#wthd_QuoteParams.currency_from),
|
||||
currency_to => unmarshal(currency_ref, Params#wthd_QuoteParams.currency_to),
|
||||
body => unmarshal(cash, Params#wthd_QuoteParams.body),
|
||||
wallet_id => unmarshal(id, Params#wthd_QuoteParams.wallet_id),
|
||||
currency_from => unmarshal(currency_ref, Params#wthd_QuoteParams.currency_from),
|
||||
currency_to => unmarshal(currency_ref, Params#wthd_QuoteParams.currency_to),
|
||||
body => unmarshal(cash, Params#wthd_QuoteParams.body),
|
||||
destination_id => maybe_unmarshal(id, Params#wthd_QuoteParams.destination_id),
|
||||
external_id => maybe_unmarshal(id, Params#wthd_QuoteParams.external_id)
|
||||
external_id => maybe_unmarshal(id, Params#wthd_QuoteParams.external_id)
|
||||
}).
|
||||
|
||||
-spec marshal_withdrawal_params(ff_withdrawal:params()) ->
|
||||
ff_proto_withdrawal_thrift:'WithdrawalParams'().
|
||||
|
||||
-spec marshal_withdrawal_params(ff_withdrawal:params()) -> ff_proto_withdrawal_thrift:'WithdrawalParams'().
|
||||
marshal_withdrawal_params(Params) ->
|
||||
#wthd_WithdrawalParams{
|
||||
id = marshal(id, maps:get(id, Params)),
|
||||
wallet_id = marshal(id, maps:get(wallet_id, Params)),
|
||||
id = marshal(id, maps:get(id, Params)),
|
||||
wallet_id = marshal(id, maps:get(wallet_id, Params)),
|
||||
destination_id = marshal(id, maps:get(destination_id, Params)),
|
||||
body = marshal(cash, maps:get(body, Params)),
|
||||
external_id = maybe_marshal(id, maps:get(external_id, Params, undefined)),
|
||||
metadata = maybe_marshal(ctx, maps:get(metadata, Params, undefined))
|
||||
body = marshal(cash, maps:get(body, Params)),
|
||||
external_id = maybe_marshal(id, maps:get(external_id, Params, undefined)),
|
||||
metadata = maybe_marshal(ctx, maps:get(metadata, Params, undefined))
|
||||
}.
|
||||
|
||||
-spec unmarshal_withdrawal_params(ff_proto_withdrawal_thrift:'WithdrawalParams'()) ->
|
||||
ff_withdrawal:params().
|
||||
|
||||
-spec unmarshal_withdrawal_params(ff_proto_withdrawal_thrift:'WithdrawalParams'()) -> ff_withdrawal:params().
|
||||
unmarshal_withdrawal_params(Params) ->
|
||||
genlib_map:compact(#{
|
||||
id => unmarshal(id, Params#wthd_WithdrawalParams.id),
|
||||
wallet_id => unmarshal(id, Params#wthd_WithdrawalParams.wallet_id),
|
||||
id => unmarshal(id, Params#wthd_WithdrawalParams.id),
|
||||
wallet_id => unmarshal(id, Params#wthd_WithdrawalParams.wallet_id),
|
||||
destination_id => unmarshal(id, Params#wthd_WithdrawalParams.destination_id),
|
||||
body => unmarshal(cash, Params#wthd_WithdrawalParams.body),
|
||||
quote => maybe_unmarshal(quote, Params#wthd_WithdrawalParams.quote),
|
||||
external_id => maybe_unmarshal(id, Params#wthd_WithdrawalParams.external_id),
|
||||
metadata => maybe_unmarshal(ctx, Params#wthd_WithdrawalParams.metadata)
|
||||
body => unmarshal(cash, Params#wthd_WithdrawalParams.body),
|
||||
quote => maybe_unmarshal(quote, Params#wthd_WithdrawalParams.quote),
|
||||
external_id => maybe_unmarshal(id, Params#wthd_WithdrawalParams.external_id),
|
||||
metadata => maybe_unmarshal(ctx, Params#wthd_WithdrawalParams.metadata)
|
||||
}).
|
||||
|
||||
-spec marshal_withdrawal_state(ff_withdrawal:withdrawal_state(), ff_entity_context:context()) ->
|
||||
ff_proto_withdrawal_thrift:'WithdrawalState'().
|
||||
|
||||
marshal_withdrawal_state(WithdrawalState, Context) ->
|
||||
CashFlow = ff_withdrawal:effective_final_cash_flow(WithdrawalState),
|
||||
Adjustments = ff_withdrawal:adjustments(WithdrawalState),
|
||||
@ -84,9 +77,7 @@ marshal_withdrawal_state(WithdrawalState, Context) ->
|
||||
quote = maybe_marshal(quote_state, ff_withdrawal:quote(WithdrawalState))
|
||||
}.
|
||||
|
||||
-spec marshal_event(ff_withdrawal_machine:event()) ->
|
||||
ff_proto_withdrawal_thrift:'Event'().
|
||||
|
||||
-spec marshal_event(ff_withdrawal_machine:event()) -> ff_proto_withdrawal_thrift:'Event'().
|
||||
marshal_event({EventID, {ev, Timestamp, Change}}) ->
|
||||
#wthd_Event{
|
||||
event_id = ff_codec:marshal(event_id, EventID),
|
||||
@ -94,18 +85,14 @@ marshal_event({EventID, {ev, Timestamp, Change}}) ->
|
||||
change = marshal(change, Change)
|
||||
}.
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) ->
|
||||
ff_codec:encoded_value().
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) -> ff_codec:encoded_value().
|
||||
marshal({list, T}, V) ->
|
||||
[marshal(T, E) || E <- V];
|
||||
|
||||
marshal(timestamped_change, {ev, Timestamp, Change}) ->
|
||||
#wthd_TimestampedChange{
|
||||
change = marshal(change, Change),
|
||||
occured_at = ff_codec:marshal(timestamp, Timestamp)
|
||||
};
|
||||
|
||||
marshal(change, {created, Withdrawal}) ->
|
||||
{created, #wthd_CreatedChange{withdrawal = marshal(withdrawal, Withdrawal)}};
|
||||
marshal(change, {status_changed, Status}) ->
|
||||
@ -127,7 +114,6 @@ marshal(change, {adjustment, #{id := ID, payload := Payload}}) ->
|
||||
id = marshal(id, ID),
|
||||
payload = ff_withdrawal_adjustment_codec:marshal(change, Payload)
|
||||
}};
|
||||
|
||||
marshal(withdrawal, Withdrawal) ->
|
||||
#wthd_Withdrawal{
|
||||
id = marshal(id, ff_withdrawal:id(Withdrawal)),
|
||||
@ -142,7 +128,6 @@ marshal(withdrawal, Withdrawal) ->
|
||||
metadata = maybe_marshal(ctx, ff_withdrawal:metadata(Withdrawal)),
|
||||
quote = maybe_marshal(quote_state, ff_withdrawal:quote(Withdrawal))
|
||||
};
|
||||
|
||||
marshal(route, Route) ->
|
||||
#{
|
||||
version := 1,
|
||||
@ -153,15 +138,12 @@ marshal(route, Route) ->
|
||||
terminal_id = maybe_marshal(terminal_id, genlib_map:get(terminal_id, Route)),
|
||||
provider_id_legacy = marshal(string, get_legacy_provider_id(Route))
|
||||
};
|
||||
|
||||
marshal(status, Status) ->
|
||||
ff_withdrawal_status_codec:marshal(status, Status);
|
||||
|
||||
marshal(session_event, started) ->
|
||||
{started, #wthd_SessionStarted{}};
|
||||
marshal(session_event, {finished, Result}) ->
|
||||
{finished, #wthd_SessionFinished{result = marshal(session_result, Result)}};
|
||||
|
||||
marshal(session_result, success) ->
|
||||
{succeeded, #wthd_SessionSucceeded{}};
|
||||
marshal(session_result, {success, TransactionInfo}) ->
|
||||
@ -170,21 +152,19 @@ marshal(session_result, {success, TransactionInfo}) ->
|
||||
{succeeded, #wthd_SessionSucceeded{trx_info = marshal(transaction_info, TransactionInfo)}};
|
||||
marshal(session_result, {failed, Failure}) ->
|
||||
{failed, #wthd_SessionFailed{failure = ff_codec:marshal(failure, Failure)}};
|
||||
|
||||
marshal(transaction_info, TrxInfo) ->
|
||||
ff_withdrawal_session_codec:marshal(transaction_info, TrxInfo);
|
||||
|
||||
marshal(session_state, Session) ->
|
||||
#wthd_SessionState{
|
||||
id = marshal(id, maps:get(id, Session)),
|
||||
result = maybe_marshal(session_result, maps:get(result, Session, undefined))
|
||||
};
|
||||
|
||||
marshal(quote_state, Quote) ->
|
||||
#wthd_QuoteState{
|
||||
cash_from = marshal(cash, maps:get(cash_from, Quote)),
|
||||
cash_to = marshal(cash, maps:get(cash_to, Quote)),
|
||||
created_at = maps:get(created_at, Quote), % already formatted
|
||||
cash_from = marshal(cash, maps:get(cash_from, Quote)),
|
||||
cash_to = marshal(cash, maps:get(cash_to, Quote)),
|
||||
% already formatted
|
||||
created_at = maps:get(created_at, Quote),
|
||||
expires_on = maps:get(expires_on, Quote),
|
||||
quote_data = maybe_marshal(msgpack, maps:get(quote_data, Quote, undefined)),
|
||||
route = maybe_marshal(route, maps:get(route, Quote, undefined)),
|
||||
@ -193,9 +173,10 @@ marshal(quote_state, Quote) ->
|
||||
};
|
||||
marshal(quote, Quote) ->
|
||||
#wthd_Quote{
|
||||
cash_from = marshal(cash, maps:get(cash_from, Quote)),
|
||||
cash_to = marshal(cash, maps:get(cash_to, Quote)),
|
||||
created_at = maps:get(created_at, Quote), % already formatted
|
||||
cash_from = marshal(cash, maps:get(cash_from, Quote)),
|
||||
cash_to = marshal(cash, maps:get(cash_to, Quote)),
|
||||
% already formatted
|
||||
created_at = maps:get(created_at, Quote),
|
||||
expires_on = maps:get(expires_on, Quote),
|
||||
quote_data = maybe_marshal(msgpack, genlib_map:get(quote_data, Quote)),
|
||||
route = maybe_marshal(route, genlib_map:get(route, Quote)),
|
||||
@ -204,31 +185,24 @@ marshal(quote, Quote) ->
|
||||
domain_revision = maybe_marshal(domain_revision, genlib_map:get(domain_revision, Quote)),
|
||||
operation_timestamp = maybe_marshal(timestamp_ms, genlib_map:get(operation_timestamp, Quote))
|
||||
};
|
||||
|
||||
marshal(ctx, Ctx) ->
|
||||
maybe_marshal(context, Ctx);
|
||||
|
||||
marshal(T, V) ->
|
||||
ff_codec:marshal(T, V).
|
||||
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) ->
|
||||
ff_codec:decoded_value().
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) -> ff_codec:decoded_value().
|
||||
unmarshal({list, T}, V) ->
|
||||
[unmarshal(T, E) || E <- V];
|
||||
|
||||
unmarshal(timestamped_change, TimestampedChange) ->
|
||||
Timestamp = ff_codec:unmarshal(timestamp, TimestampedChange#wthd_TimestampedChange.occured_at),
|
||||
Change = unmarshal(change, TimestampedChange#wthd_TimestampedChange.change),
|
||||
{ev, Timestamp, Change};
|
||||
|
||||
unmarshal(repair_scenario, {add_events, #wthd_AddEventsRepair{events = Events, action = Action}}) ->
|
||||
{add_events, genlib_map:compact(#{
|
||||
events => unmarshal({list, change}, Events),
|
||||
action => maybe_unmarshal(complex_action, Action)
|
||||
})};
|
||||
|
||||
{add_events,
|
||||
genlib_map:compact(#{
|
||||
events => unmarshal({list, change}, Events),
|
||||
action => maybe_unmarshal(complex_action, Action)
|
||||
})};
|
||||
unmarshal(change, {created, #wthd_CreatedChange{withdrawal = Withdrawal}}) ->
|
||||
{created, unmarshal(withdrawal, Withdrawal)};
|
||||
unmarshal(change, {status_changed, #wthd_StatusChange{status = Status}}) ->
|
||||
@ -248,7 +222,6 @@ unmarshal(change, {adjustment, Change}) ->
|
||||
id => unmarshal(id, Change#wthd_AdjustmentChange.id),
|
||||
payload => ff_withdrawal_adjustment_codec:unmarshal(change, Change#wthd_AdjustmentChange.payload)
|
||||
}};
|
||||
|
||||
unmarshal(withdrawal, Withdrawal = #wthd_Withdrawal{}) ->
|
||||
ff_withdrawal:gen(#{
|
||||
id => unmarshal(id, Withdrawal#wthd_Withdrawal.id),
|
||||
@ -266,7 +239,6 @@ unmarshal(withdrawal, Withdrawal = #wthd_Withdrawal{}) ->
|
||||
transfer_type => withdrawal,
|
||||
metadata => maybe_unmarshal(ctx, Withdrawal#wthd_Withdrawal.metadata)
|
||||
});
|
||||
|
||||
unmarshal(route, Route) ->
|
||||
genlib_map:compact(#{
|
||||
version => 1,
|
||||
@ -274,17 +246,13 @@ unmarshal(route, Route) ->
|
||||
terminal_id => maybe_unmarshal(terminal_id, Route#wthd_Route.terminal_id),
|
||||
provider_id_legacy => maybe_unmarshal(string, Route#wthd_Route.provider_id_legacy)
|
||||
});
|
||||
|
||||
unmarshal(status, Status) ->
|
||||
ff_withdrawal_status_codec:unmarshal(status, Status);
|
||||
|
||||
unmarshal(session_event, #wthd_SessionChange{id = ID, payload = {started, #wthd_SessionStarted{}}}) ->
|
||||
{session_started, unmarshal(id, ID)};
|
||||
unmarshal(session_event, #wthd_SessionChange{id = ID, payload = {finished, Finished}}) ->
|
||||
#wthd_SessionFinished{result = Result} = Finished,
|
||||
{session_finished, {unmarshal(id, ID), unmarshal(session_result, Result)}};
|
||||
|
||||
|
||||
unmarshal(session_result, {succeeded, #wthd_SessionSucceeded{trx_info = undefined}}) ->
|
||||
success;
|
||||
unmarshal(session_result, {succeeded, #wthd_SessionSucceeded{trx_info = TransactionInfo}}) ->
|
||||
@ -293,31 +261,27 @@ unmarshal(session_result, {succeeded, #wthd_SessionSucceeded{trx_info = Transact
|
||||
{success, unmarshal(transaction_info, TransactionInfo)};
|
||||
unmarshal(session_result, {failed, #wthd_SessionFailed{failure = Failure}}) ->
|
||||
{failed, ff_codec:unmarshal(failure, Failure)};
|
||||
|
||||
unmarshal(transaction_info, TrxInfo) ->
|
||||
ff_withdrawal_session_codec:unmarshal(transaction_info, TrxInfo);
|
||||
|
||||
unmarshal(session_state, Session) ->
|
||||
genlib_map:compact(#{
|
||||
id => unmarshal(id, Session#wthd_SessionState.id),
|
||||
result => maybe_unmarshal(session_result, Session#wthd_SessionState.result)
|
||||
});
|
||||
|
||||
unmarshal(quote_state, Quote) ->
|
||||
genlib_map:compact(#{
|
||||
cash_from => unmarshal(cash, Quote#wthd_QuoteState.cash_from),
|
||||
cash_to => unmarshal(cash, Quote#wthd_QuoteState.cash_to),
|
||||
cash_to => unmarshal(cash, Quote#wthd_QuoteState.cash_to),
|
||||
created_at => Quote#wthd_QuoteState.created_at,
|
||||
expires_on => Quote#wthd_QuoteState.expires_on,
|
||||
route => maybe_unmarshal(route, Quote#wthd_QuoteState.route),
|
||||
resource_descriptor => maybe_unmarshal(resource_descriptor, Quote#wthd_QuoteState.resource),
|
||||
quote_data => maybe_unmarshal(msgpack, Quote#wthd_QuoteState.quote_data)
|
||||
});
|
||||
|
||||
unmarshal(quote, Quote) ->
|
||||
genlib_map:compact(#{
|
||||
cash_from => unmarshal(cash, Quote#wthd_Quote.cash_from),
|
||||
cash_to => unmarshal(cash, Quote#wthd_Quote.cash_to),
|
||||
cash_to => unmarshal(cash, Quote#wthd_Quote.cash_to),
|
||||
created_at => Quote#wthd_Quote.created_at,
|
||||
expires_on => Quote#wthd_Quote.expires_on,
|
||||
route => maybe_unmarshal(route, Quote#wthd_Quote.route),
|
||||
@ -327,10 +291,8 @@ unmarshal(quote, Quote) ->
|
||||
party_revision => maybe_unmarshal(party_revision, Quote#wthd_Quote.party_revision),
|
||||
operation_timestamp => maybe_unmarshal(timestamp_ms, Quote#wthd_Quote.operation_timestamp)
|
||||
});
|
||||
|
||||
unmarshal(ctx, Ctx) ->
|
||||
maybe_unmarshal(context, Ctx);
|
||||
|
||||
unmarshal(T, V) ->
|
||||
ff_codec:unmarshal(T, V).
|
||||
|
||||
@ -355,15 +317,17 @@ get_legacy_provider_id(#{provider_id := Provider}) when is_integer(Provider) ->
|
||||
|
||||
-ifdef(TEST).
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
-spec test() -> _.
|
||||
|
||||
-spec withdrawal_symmetry_test() -> _.
|
||||
|
||||
withdrawal_symmetry_test() ->
|
||||
In = #wthd_Withdrawal{
|
||||
id = genlib:unique(),
|
||||
body = #'Cash'{
|
||||
amount = 10101,
|
||||
currency = #'CurrencyRef'{ symbolic_code = <<"Banana Republic">> }
|
||||
currency = #'CurrencyRef'{symbolic_code = <<"Banana Republic">>}
|
||||
},
|
||||
wallet_id = genlib:unique(),
|
||||
destination_id = genlib:unique(),
|
||||
@ -385,7 +349,7 @@ withdrawal_params_symmetry_test() ->
|
||||
id = genlib:unique(),
|
||||
body = #'Cash'{
|
||||
amount = 10101,
|
||||
currency = #'CurrencyRef'{ symbolic_code = <<"Banana Republic">> }
|
||||
currency = #'CurrencyRef'{symbolic_code = <<"Banana Republic">>}
|
||||
},
|
||||
wallet_id = genlib:unique(),
|
||||
destination_id = genlib:unique(),
|
||||
@ -396,13 +360,13 @@ withdrawal_params_symmetry_test() ->
|
||||
-spec quote_state_symmetry_test() -> _.
|
||||
quote_state_symmetry_test() ->
|
||||
In = #wthd_QuoteState{
|
||||
cash_from = #'Cash'{
|
||||
cash_from = #'Cash'{
|
||||
amount = 10101,
|
||||
currency = #'CurrencyRef'{ symbolic_code = <<"Banana Republic">> }
|
||||
currency = #'CurrencyRef'{symbolic_code = <<"Banana Republic">>}
|
||||
},
|
||||
cash_to = #'Cash'{
|
||||
cash_to = #'Cash'{
|
||||
amount = 20202,
|
||||
currency = #'CurrencyRef'{ symbolic_code = <<"Pineapple Empire">> }
|
||||
currency = #'CurrencyRef'{symbolic_code = <<"Pineapple Empire">>}
|
||||
},
|
||||
created_at = genlib:unique(),
|
||||
expires_on = genlib:unique(),
|
||||
@ -420,13 +384,13 @@ quote_state_symmetry_test() ->
|
||||
-spec quote_symmetry_test() -> _.
|
||||
quote_symmetry_test() ->
|
||||
In = #wthd_Quote{
|
||||
cash_from = #'Cash'{
|
||||
cash_from = #'Cash'{
|
||||
amount = 10101,
|
||||
currency = #'CurrencyRef'{ symbolic_code = <<"Banana Republic">> }
|
||||
currency = #'CurrencyRef'{symbolic_code = <<"Banana Republic">>}
|
||||
},
|
||||
cash_to = #'Cash'{
|
||||
cash_to = #'Cash'{
|
||||
amount = 20202,
|
||||
currency = #'CurrencyRef'{ symbolic_code = <<"Pineapple Empire">> }
|
||||
currency = #'CurrencyRef'{symbolic_code = <<"Pineapple Empire">>}
|
||||
},
|
||||
created_at = genlib:unique(),
|
||||
expires_on = genlib:unique(),
|
||||
@ -443,10 +407,9 @@ quote_symmetry_test() ->
|
||||
},
|
||||
?assertEqual(In, marshal(quote, unmarshal(quote, In))).
|
||||
|
||||
|
||||
-spec marshal_session_result_test_() -> _.
|
||||
-spec marshal_session_result_test_() -> _.
|
||||
marshal_session_result_test_() ->
|
||||
TransactionInfo = #{ id => <<"ID">>, extra => #{<<"Hello">> => <<"World">>} },
|
||||
TransactionInfo = #{id => <<"ID">>, extra => #{<<"Hello">> => <<"World">>}},
|
||||
TransactionInfoThrift = marshal(transaction_info, TransactionInfo),
|
||||
Results = [
|
||||
{success, TransactionInfo},
|
||||
|
@ -16,32 +16,28 @@
|
||||
%% Internals
|
||||
%%
|
||||
|
||||
-spec publish_events(list(event())) ->
|
||||
list(sinkevent()).
|
||||
|
||||
-spec publish_events(list(event())) -> list(sinkevent()).
|
||||
publish_events(Events) ->
|
||||
[publish_event(Event) || Event <- Events].
|
||||
|
||||
-spec publish_event(event()) ->
|
||||
sinkevent().
|
||||
|
||||
-spec publish_event(event()) -> sinkevent().
|
||||
publish_event(#{
|
||||
id := ID,
|
||||
source_id := SourceID,
|
||||
event := {
|
||||
id := ID,
|
||||
source_id := SourceID,
|
||||
event := {
|
||||
EventID,
|
||||
Dt,
|
||||
{ev, EventDt, Payload}
|
||||
}
|
||||
}) ->
|
||||
#wthd_SinkEvent{
|
||||
id = marshal(event_id, ID),
|
||||
created_at = marshal(timestamp, Dt),
|
||||
source = marshal(id, SourceID),
|
||||
payload = #wthd_EventSinkPayload{
|
||||
sequence = marshal(event_id, EventID),
|
||||
id = marshal(event_id, ID),
|
||||
created_at = marshal(timestamp, Dt),
|
||||
source = marshal(id, SourceID),
|
||||
payload = #wthd_EventSinkPayload{
|
||||
sequence = marshal(event_id, EventID),
|
||||
occured_at = marshal(timestamp, EventDt),
|
||||
changes = [marshal(change, Payload)]
|
||||
changes = [marshal(change, Payload)]
|
||||
}
|
||||
}.
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
-module(ff_withdrawal_handler).
|
||||
|
||||
-behaviour(ff_woody_wrapper).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_withdrawal_thrift.hrl").
|
||||
@ -9,10 +10,11 @@
|
||||
%%
|
||||
%% ff_woody_wrapper callbacks
|
||||
%%
|
||||
-spec handle_function(woody:func(), woody:args(), woody:options()) ->
|
||||
{ok, woody:result()} | no_return().
|
||||
-spec handle_function(woody:func(), woody:args(), woody:options()) -> {ok, woody:result()} | no_return().
|
||||
handle_function(Func, Args, Opts) ->
|
||||
scoper:scope(withdrawal, #{},
|
||||
scoper:scope(
|
||||
withdrawal,
|
||||
#{},
|
||||
fun() ->
|
||||
handle_function_(Func, Args, Opts)
|
||||
end
|
||||
@ -136,11 +138,13 @@ handle_function_('GetEvents', [ID, EventRange], _Opts) ->
|
||||
handle_function_('CreateAdjustment', [ID, MarshaledParams], _Opts) ->
|
||||
Params = ff_withdrawal_adjustment_codec:unmarshal(adjustment_params, MarshaledParams),
|
||||
AdjustmentID = maps:get(id, Params),
|
||||
ok = scoper:add_meta(genlib_map:compact(#{
|
||||
id => ID,
|
||||
adjustment_id => AdjustmentID,
|
||||
external_id => maps:get(external_id, Params, undefined)
|
||||
})),
|
||||
ok = scoper:add_meta(
|
||||
genlib_map:compact(#{
|
||||
id => ID,
|
||||
adjustment_id => AdjustmentID,
|
||||
external_id => maps:get(external_id, Params, undefined)
|
||||
})
|
||||
),
|
||||
case ff_withdrawal_machine:start_adjustment(ID, Params) of
|
||||
ok ->
|
||||
{ok, Machine} = ff_withdrawal_machine:get(ID),
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -12,8 +12,7 @@
|
||||
%% ff_woody_wrapper callbacks
|
||||
%%
|
||||
|
||||
-spec handle_function(woody:func(), woody:args(), options()) ->
|
||||
{ok, woody:result()} | no_return().
|
||||
-spec handle_function(woody:func(), woody:args(), options()) -> {ok, woody:result()} | no_return().
|
||||
handle_function('Repair', [ID, Scenario], _Opts) ->
|
||||
DecodedScenario = ff_withdrawal_codec:unmarshal(repair_scenario, Scenario),
|
||||
case ff_withdrawal_machine:repair(ID, DecodedScenario) of
|
||||
|
@ -13,7 +13,6 @@
|
||||
%% API
|
||||
-spec marshal_state(ff_withdrawal_session:session_state(), ff_withdrawal_session:id(), ff_entity_context:context()) ->
|
||||
ff_proto_withdrawal_session_thrift:'SessionState'().
|
||||
|
||||
marshal_state(State, ID, Context) ->
|
||||
#wthd_session_SessionState{
|
||||
id = marshal(id, ID),
|
||||
@ -23,18 +22,14 @@ marshal_state(State, ID, Context) ->
|
||||
context = marshal(ctx, Context)
|
||||
}.
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) ->
|
||||
ff_codec:encoded_value().
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) -> ff_codec:encoded_value().
|
||||
marshal({list, T}, V) ->
|
||||
[marshal(T, E) || E <- V];
|
||||
|
||||
marshal(timestamped_change, {ev, Timestamp, Change}) ->
|
||||
#wthd_session_TimestampedChange{
|
||||
change = marshal(change, Change),
|
||||
occured_at = ff_codec:marshal(timestamp, Timestamp)
|
||||
};
|
||||
|
||||
marshal(change, {created, Session}) ->
|
||||
{created, marshal(session, Session)};
|
||||
marshal(change, {next_state, AdapterState}) ->
|
||||
@ -45,7 +40,6 @@ marshal(change, {finished, SessionResult}) ->
|
||||
{finished, marshal(session_result, SessionResult)};
|
||||
marshal(change, {callback, CallbackChange}) ->
|
||||
{callback, marshal(callback_change, CallbackChange)};
|
||||
|
||||
marshal(session, Session) ->
|
||||
#{
|
||||
id := SessionID,
|
||||
@ -60,7 +54,6 @@ marshal(session, Session) ->
|
||||
route = marshal(route, Route),
|
||||
provider_legacy = marshal(string, get_legacy_provider_id(Session))
|
||||
};
|
||||
|
||||
marshal(session_status, active) ->
|
||||
{active, #wthd_session_SessionActive{}};
|
||||
marshal(session_status, {finished, Result}) ->
|
||||
@ -72,12 +65,14 @@ marshal(session_finished_status, success) ->
|
||||
{success, #wthd_session_SessionFinishedSuccess{}};
|
||||
marshal(session_finished_status, {failed, Failure}) ->
|
||||
{failed, #wthd_session_SessionFinishedFailed{failure = marshal(failure, Failure)}};
|
||||
|
||||
marshal(withdrawal, Params = #{
|
||||
id := WithdrawalID,
|
||||
resource := Resource,
|
||||
cash := Cash
|
||||
}) ->
|
||||
marshal(
|
||||
withdrawal,
|
||||
Params = #{
|
||||
id := WithdrawalID,
|
||||
resource := Resource,
|
||||
cash := Cash
|
||||
}
|
||||
) ->
|
||||
SenderIdentity = maps:get(sender, Params, undefined),
|
||||
ReceiverIdentity = maps:get(receiver, Params, undefined),
|
||||
SessionID = maps:get(session_id, Params, undefined),
|
||||
@ -86,36 +81,31 @@ marshal(withdrawal, Params = #{
|
||||
id = marshal(id, WithdrawalID),
|
||||
destination_resource = marshal(resource, Resource),
|
||||
cash = marshal(cash, Cash),
|
||||
sender = marshal(identity, SenderIdentity),
|
||||
sender = marshal(identity, SenderIdentity),
|
||||
receiver = marshal(identity, ReceiverIdentity),
|
||||
session_id = maybe_marshal(id, SessionID),
|
||||
quote = maybe_marshal(quote, Quote)
|
||||
};
|
||||
|
||||
marshal(identity, Identity = #{id := ID}) ->
|
||||
#wthd_session_Identity{
|
||||
identity_id = marshal(id, ID),
|
||||
effective_challenge = maybe_marshal(challenge, maps:get(effective_challenge, Identity, undefined))
|
||||
};
|
||||
|
||||
marshal(challenge, #{id := ID, proofs := Proofs}) ->
|
||||
#wthd_session_Challenge{
|
||||
id = maybe_marshal(id, ID),
|
||||
proofs = maybe_marshal({list, proof}, Proofs)
|
||||
};
|
||||
|
||||
marshal(proof, {Type, Token}) ->
|
||||
#wthd_session_ChallengeProof{
|
||||
type = Type,
|
||||
token = Token
|
||||
};
|
||||
|
||||
marshal(route, Route) ->
|
||||
#wthd_session_Route{
|
||||
provider_id = marshal(provider_id, maps:get(provider_id, Route)),
|
||||
terminal_id = maybe_marshal(terminal_id, genlib_map:get(terminal_id, Route))
|
||||
};
|
||||
|
||||
marshal(quote, #{
|
||||
cash_from := CashFrom,
|
||||
cash_to := CashTo,
|
||||
@ -131,10 +121,8 @@ marshal(quote, #{
|
||||
quote_data = maybe_marshal(msgpack, Data),
|
||||
quote_data_legacy = marshal(ctx, #{})
|
||||
};
|
||||
|
||||
marshal(ctx, Ctx) ->
|
||||
maybe_marshal(context, Ctx);
|
||||
|
||||
marshal(session_result, success) ->
|
||||
{success, #wthd_session_SessionResultSuccess{}};
|
||||
marshal(session_result, {success, TransactionInfo}) ->
|
||||
@ -143,50 +131,41 @@ marshal(session_result, {success, TransactionInfo}) ->
|
||||
{success, #wthd_session_SessionResultSuccess{trx_info = marshal(transaction_info, TransactionInfo)}};
|
||||
marshal(session_result, {failed, Failure}) ->
|
||||
{failed, #wthd_session_SessionResultFailed{failure = ff_codec:marshal(failure, Failure)}};
|
||||
|
||||
marshal(callback_change, #{tag := Tag, payload := Payload}) ->
|
||||
#wthd_session_CallbackChange{
|
||||
tag = marshal(string, Tag),
|
||||
payload = marshal(callback_event, Payload)
|
||||
};
|
||||
|
||||
marshal(callback_event, {created, Callback}) ->
|
||||
{created, #wthd_session_CallbackCreatedChange{callback = marshal(callback, Callback)}};
|
||||
marshal(callback_event, {status_changed, Status}) ->
|
||||
{status_changed, #wthd_session_CallbackStatusChange{status = marshal(callback_status, Status)}};
|
||||
marshal(callback_event, {finished, #{payload := Response}}) ->
|
||||
{finished, #wthd_session_CallbackResultChange{payload = Response}};
|
||||
|
||||
marshal(callback, #{tag := Tag}) ->
|
||||
#wthd_session_Callback{tag = marshal(string, Tag)};
|
||||
|
||||
marshal(callback_status, pending) ->
|
||||
{pending, #wthd_session_CallbackStatusPending{}};
|
||||
marshal(callback_status, succeeded) ->
|
||||
{succeeded, #wthd_session_CallbackStatusSucceeded{}};
|
||||
|
||||
marshal(T, V) ->
|
||||
ff_codec:marshal(T, V).
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) ->
|
||||
ff_codec:decoded_value().
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) -> ff_codec:decoded_value().
|
||||
unmarshal({list, T}, V) ->
|
||||
[unmarshal(T, E) || E <- V];
|
||||
|
||||
unmarshal(timestamped_change, TimestampedChange) ->
|
||||
Timestamp = ff_codec:unmarshal(timestamp, TimestampedChange#wthd_session_TimestampedChange.occured_at),
|
||||
Change = unmarshal(change, TimestampedChange#wthd_session_TimestampedChange.change),
|
||||
{ev, Timestamp, Change};
|
||||
|
||||
unmarshal(repair_scenario, {add_events, #wthd_session_AddEventsRepair{events = Events, action = Action}}) ->
|
||||
{add_events, genlib_map:compact(#{
|
||||
events => unmarshal({list, change}, Events),
|
||||
action => maybe_unmarshal(complex_action, Action)
|
||||
})};
|
||||
{add_events,
|
||||
genlib_map:compact(#{
|
||||
events => unmarshal({list, change}, Events),
|
||||
action => maybe_unmarshal(complex_action, Action)
|
||||
})};
|
||||
unmarshal(repair_scenario, {set_session_result, #wthd_session_SetResultRepair{result = Result}}) ->
|
||||
{set_session_result, unmarshal(session_result, Result)};
|
||||
|
||||
unmarshal(change, {created, Session}) ->
|
||||
{created, unmarshal(session, Session)};
|
||||
unmarshal(change, {next_state, AdapterState}) ->
|
||||
@ -200,7 +179,6 @@ unmarshal(change, {callback, #wthd_session_CallbackChange{tag = Tag, payload = P
|
||||
tag => unmarshal(string, Tag),
|
||||
payload => unmarshal(callback_event, Payload)
|
||||
}};
|
||||
|
||||
unmarshal(session, #wthd_session_Session{
|
||||
id = SessionID,
|
||||
status = SessionStatus,
|
||||
@ -217,17 +195,14 @@ unmarshal(session, #wthd_session_Session{
|
||||
route => Route1,
|
||||
provider_legacy => ProviderLegacy
|
||||
});
|
||||
|
||||
unmarshal(session_status, {active, #wthd_session_SessionActive{}}) ->
|
||||
active;
|
||||
unmarshal(session_status, {finished, #wthd_session_SessionFinished{status = Result}}) ->
|
||||
{finished, unmarshal(session_finished_status, Result)};
|
||||
|
||||
unmarshal(session_finished_status, {success, #wthd_session_SessionFinishedSuccess{}}) ->
|
||||
success;
|
||||
unmarshal(session_finished_status, {failed, #wthd_session_SessionFinishedFailed{failure = Failure}}) ->
|
||||
{failed, unmarshal(failure, Failure)};
|
||||
|
||||
unmarshal(withdrawal, #wthd_session_Withdrawal{
|
||||
id = WithdrawalID,
|
||||
destination_resource = Resource,
|
||||
@ -246,7 +221,6 @@ unmarshal(withdrawal, #wthd_session_Withdrawal{
|
||||
session_id => maybe_unmarshal(id, SessionID),
|
||||
quote => maybe_unmarshal(quote, Quote)
|
||||
});
|
||||
|
||||
unmarshal(identity, #wthd_session_Identity{
|
||||
identity_id = ID,
|
||||
effective_challenge = EffectiveChallenge
|
||||
@ -255,7 +229,6 @@ unmarshal(identity, #wthd_session_Identity{
|
||||
id => unmarshal(id, ID),
|
||||
effective_challenge => maybe_unmarshal(challenge, EffectiveChallenge)
|
||||
});
|
||||
|
||||
unmarshal(challenge, #wthd_session_Challenge{
|
||||
id = ID,
|
||||
proofs = Proofs
|
||||
@ -264,19 +237,16 @@ unmarshal(challenge, #wthd_session_Challenge{
|
||||
id => maybe_unmarshal(id, ID),
|
||||
proofs => maybe_unmarshal({list, proof}, Proofs)
|
||||
};
|
||||
|
||||
unmarshal(proof, #wthd_session_ChallengeProof{
|
||||
type = Type,
|
||||
token = Token
|
||||
}) ->
|
||||
{Type, Token};
|
||||
|
||||
unmarshal(route, Route) ->
|
||||
genlib_map:compact(#{
|
||||
provider_id => unmarshal(provider_id, Route#wthd_session_Route.provider_id),
|
||||
terminal_id => maybe_unmarshal(terminal_id, Route#wthd_session_Route.terminal_id)
|
||||
});
|
||||
|
||||
unmarshal(quote, #wthd_session_Quote{
|
||||
cash_from = CashFrom,
|
||||
cash_to = CashTo,
|
||||
@ -291,7 +261,6 @@ unmarshal(quote, #wthd_session_Quote{
|
||||
expires_on => ExpiresOn,
|
||||
quote_data => maybe_unmarshal(msgpack, Data)
|
||||
});
|
||||
|
||||
unmarshal(session_result, {success, #wthd_session_SessionResultSuccess{trx_info = undefined}}) ->
|
||||
success;
|
||||
unmarshal(session_result, {success, #wthd_session_SessionResultSuccess{trx_info = TransactionInfo}}) ->
|
||||
@ -300,25 +269,20 @@ unmarshal(session_result, {success, #wthd_session_SessionResultSuccess{trx_info
|
||||
{success, unmarshal(transaction_info, TransactionInfo)};
|
||||
unmarshal(session_result, {failed, #wthd_session_SessionResultFailed{failure = Failure}}) ->
|
||||
{failed, ff_codec:unmarshal(failure, Failure)};
|
||||
|
||||
unmarshal(callback_event, {created, #wthd_session_CallbackCreatedChange{callback = Callback}}) ->
|
||||
{created, unmarshal(callback, Callback)};
|
||||
unmarshal(callback_event, {finished, #wthd_session_CallbackResultChange{payload = Response}}) ->
|
||||
{finished, #{payload => Response}};
|
||||
unmarshal(callback_event, {status_changed, #wthd_session_CallbackStatusChange{status = Status}}) ->
|
||||
{status_changed, unmarshal(callback_status, Status)};
|
||||
|
||||
unmarshal(callback, #wthd_session_Callback{tag = Tag}) ->
|
||||
#{tag => unmarshal(string, Tag)};
|
||||
|
||||
unmarshal(callback_status, {pending, #wthd_session_CallbackStatusPending{}}) ->
|
||||
pending;
|
||||
unmarshal(callback_status, {succeeded, #wthd_session_CallbackStatusSucceeded{}}) ->
|
||||
succeeded;
|
||||
|
||||
unmarshal(ctx, Ctx) ->
|
||||
maybe_unmarshal(context, Ctx);
|
||||
|
||||
unmarshal(T, V) ->
|
||||
ff_codec:unmarshal(T, V).
|
||||
|
||||
@ -344,14 +308,12 @@ get_legacy_provider_id(#{route := #{provider_id := Provider}}) when is_integer(P
|
||||
-ifdef(TEST).
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
-spec test() ->
|
||||
_.
|
||||
-spec test() -> _.
|
||||
|
||||
-spec marshal_change_test_() ->
|
||||
_.
|
||||
-spec marshal_change_test_() -> _.
|
||||
|
||||
marshal_change_test_() ->
|
||||
TransactionInfo = #{ id => <<"ID">>, extra => #{<<"Hello">> => <<"World">>} },
|
||||
TransactionInfo = #{id => <<"ID">>, extra => #{<<"Hello">> => <<"World">>}},
|
||||
TransactionInfoThrift = marshal(transaction_info, TransactionInfo),
|
||||
Changes = [
|
||||
{finished, {success, TransactionInfo}},
|
||||
|
@ -16,32 +16,28 @@
|
||||
%% Internals
|
||||
%%
|
||||
|
||||
-spec publish_events(list(event())) ->
|
||||
list(sinkevent()).
|
||||
|
||||
-spec publish_events(list(event())) -> list(sinkevent()).
|
||||
publish_events(Events) ->
|
||||
[publish_event(Event) || Event <- Events].
|
||||
|
||||
-spec publish_event(event()) ->
|
||||
sinkevent().
|
||||
|
||||
-spec publish_event(event()) -> sinkevent().
|
||||
publish_event(#{
|
||||
id := ID,
|
||||
source_id := SourceID,
|
||||
event := {
|
||||
id := ID,
|
||||
source_id := SourceID,
|
||||
event := {
|
||||
EventID,
|
||||
Dt,
|
||||
{ev, EventDt, Payload}
|
||||
}
|
||||
}) ->
|
||||
#wthd_session_SinkEvent{
|
||||
id = marshal(event_id, ID),
|
||||
created_at = marshal(timestamp, Dt),
|
||||
source = marshal(id, SourceID),
|
||||
payload = #wthd_session_Event{
|
||||
sequence = marshal(event_id, EventID),
|
||||
id = marshal(event_id, ID),
|
||||
created_at = marshal(timestamp, Dt),
|
||||
source = marshal(id, SourceID),
|
||||
payload = #wthd_session_Event{
|
||||
sequence = marshal(event_id, EventID),
|
||||
occured_at = marshal(timestamp, EventDt),
|
||||
changes = [marshal(change, Payload)]
|
||||
changes = [marshal(change, Payload)]
|
||||
}
|
||||
}.
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
-module(ff_withdrawal_session_handler).
|
||||
|
||||
-behaviour(ff_woody_wrapper).
|
||||
|
||||
-include_lib("fistful_proto/include/ff_proto_withdrawal_session_thrift.hrl").
|
||||
@ -9,11 +10,11 @@
|
||||
%%
|
||||
%% ff_woody_wrapper callbacks
|
||||
%%
|
||||
-spec handle_function(woody:func(), woody:args(), woody:options()) ->
|
||||
{ok, woody:result()} | no_return().
|
||||
|
||||
-spec handle_function(woody:func(), woody:args(), woody:options()) -> {ok, woody:result()} | no_return().
|
||||
handle_function(Func, Args, Opts) ->
|
||||
scoper:scope(withdrawal_session, #{},
|
||||
scoper:scope(
|
||||
withdrawal_session,
|
||||
#{},
|
||||
fun() ->
|
||||
handle_function_(Func, Args, Opts)
|
||||
end
|
||||
@ -33,7 +34,6 @@ handle_function_('Get', [ID, EventRange], _Opts) ->
|
||||
{error, notfound} ->
|
||||
woody_error:raise(business, #fistful_WithdrawalSessionNotFound{})
|
||||
end;
|
||||
|
||||
handle_function_('GetContext', [ID], _Opts) ->
|
||||
case ff_withdrawal_session_machine:get(ID, {undefined, 0}) of
|
||||
{ok, Machine} ->
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -12,8 +12,7 @@
|
||||
%% ff_woody_wrapper callbacks
|
||||
%%
|
||||
|
||||
-spec handle_function(woody:func(), woody:args(), options()) ->
|
||||
{ok, woody:result()} | no_return().
|
||||
-spec handle_function(woody:func(), woody:args(), options()) -> {ok, woody:result()} | no_return().
|
||||
handle_function('Repair', [ID, Scenario], _Opts) ->
|
||||
DecodedScenario = ff_codec:unmarshal(ff_withdrawal_session_codec, repair_scenario, Scenario),
|
||||
case ff_withdrawal_session_machine:repair(ID, DecodedScenario) of
|
||||
|
@ -9,30 +9,23 @@
|
||||
|
||||
%% API
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) ->
|
||||
ff_codec:encoded_value().
|
||||
|
||||
-spec marshal(ff_codec:type_name(), ff_codec:decoded_value()) -> ff_codec:encoded_value().
|
||||
marshal(status, pending) ->
|
||||
{pending, #wthd_status_Pending{}};
|
||||
marshal(status, succeeded) ->
|
||||
{succeeded, #wthd_status_Succeeded{}};
|
||||
marshal(status, {failed, Failure}) ->
|
||||
{failed, #wthd_status_Failed{failure = marshal(failure, Failure)}};
|
||||
|
||||
marshal(T, V) ->
|
||||
ff_codec:marshal(T, V).
|
||||
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) ->
|
||||
ff_codec:decoded_value().
|
||||
|
||||
-spec unmarshal(ff_codec:type_name(), ff_codec:encoded_value()) -> ff_codec:decoded_value().
|
||||
unmarshal(status, {pending, #wthd_status_Pending{}}) ->
|
||||
pending;
|
||||
unmarshal(status, {succeeded, #wthd_status_Succeeded{}}) ->
|
||||
succeeded;
|
||||
unmarshal(status, {failed, #wthd_status_Failed{failure = Failure}}) ->
|
||||
{failed, unmarshal(failure, Failure)};
|
||||
|
||||
unmarshal(T, V) ->
|
||||
ff_codec:unmarshal(T, V).
|
||||
|
||||
@ -40,9 +33,11 @@ unmarshal(T, V) ->
|
||||
|
||||
-ifdef(TEST).
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
-spec test() -> _.
|
||||
|
||||
-spec pending_symmetry_test() -> _.
|
||||
|
||||
pending_symmetry_test() ->
|
||||
Status = pending,
|
||||
?assertEqual(Status, unmarshal(status, marshal(status, Status))).
|
||||
@ -54,13 +49,14 @@ succeeded_symmetry_test() ->
|
||||
|
||||
-spec failed_symmetry_test() -> _.
|
||||
failed_symmetry_test() ->
|
||||
Status = {failed, #{
|
||||
code => <<"test">>,
|
||||
reason => <<"why not">>,
|
||||
sub => #{
|
||||
code => <<"sub">>
|
||||
}
|
||||
}},
|
||||
Status =
|
||||
{failed, #{
|
||||
code => <<"test">>,
|
||||
reason => <<"why not">>,
|
||||
sub => #{
|
||||
code => <<"sub">>
|
||||
}
|
||||
}},
|
||||
?assertEqual(Status, unmarshal(status, marshal(status, Status))).
|
||||
|
||||
-endif.
|
||||
|
@ -5,6 +5,7 @@
|
||||
-behaviour(woody_server_thrift_handler).
|
||||
|
||||
-export([handle_function/4]).
|
||||
|
||||
-export_type([options/0]).
|
||||
-export_type([handler/0]).
|
||||
-export_type([client_opts/0]).
|
||||
@ -18,22 +19,20 @@
|
||||
}.
|
||||
|
||||
-type client_opts() :: #{
|
||||
url := woody:url(),
|
||||
url := woody:url(),
|
||||
transport_opts => [{_, _}]
|
||||
}.
|
||||
|
||||
-define(DEFAULT_HANDLING_TIMEOUT, 30000). % 30 seconds
|
||||
% 30 seconds
|
||||
-define(DEFAULT_HANDLING_TIMEOUT, 30000).
|
||||
|
||||
%% Callbacks
|
||||
|
||||
-callback(handle_function(woody:func(), woody:args(), handler_options()) ->
|
||||
{ok, woody:result()} | no_return()).
|
||||
-callback handle_function(woody:func(), woody:args(), handler_options()) -> {ok, woody:result()} | no_return().
|
||||
|
||||
%% API
|
||||
|
||||
-spec handle_function(woody:func(), woody:args(), woody_context:ctx(), options()) ->
|
||||
{ok, woody:result()} | no_return().
|
||||
|
||||
-spec handle_function(woody:func(), woody:args(), woody_context:ctx(), options()) -> {ok, woody:result()} | no_return().
|
||||
handle_function(Func, Args, WoodyContext0, #{handler := Handler} = Opts) ->
|
||||
WoodyContext = ensure_woody_deadline_set(WoodyContext0, Opts),
|
||||
{HandlerMod, HandlerOptions} = get_handler_opts(Handler),
|
||||
@ -57,9 +56,7 @@ create_context(WoodyContext, Opts) ->
|
||||
},
|
||||
ff_context:create(ContextOptions).
|
||||
|
||||
-spec ensure_woody_deadline_set(woody_context:ctx(), options()) ->
|
||||
woody_context:ctx().
|
||||
|
||||
-spec ensure_woody_deadline_set(woody_context:ctx(), options()) -> woody_context:ctx().
|
||||
ensure_woody_deadline_set(WoodyContext, Opts) ->
|
||||
case woody_context:get_deadline(WoodyContext) of
|
||||
undefined ->
|
||||
@ -70,11 +67,8 @@ ensure_woody_deadline_set(WoodyContext, Opts) ->
|
||||
WoodyContext
|
||||
end.
|
||||
|
||||
-spec get_handler_opts(handler()) ->
|
||||
{module(), handler_options()}.
|
||||
|
||||
-spec get_handler_opts(handler()) -> {module(), handler_options()}.
|
||||
get_handler_opts(Handler) when is_atom(Handler) ->
|
||||
{Handler, undefined};
|
||||
get_handler_opts({Handler, Options}) when is_atom(Handler) ->
|
||||
{Handler, Options}.
|
||||
|
||||
|
@ -41,10 +41,10 @@
|
||||
|
||||
%% Internal types
|
||||
|
||||
-type config() :: ct_helper:config().
|
||||
-type config() :: ct_helper:config().
|
||||
-type test_case_name() :: ct_helper:test_case_name().
|
||||
-type group_name() :: ct_helper:group_name().
|
||||
-type test_return() :: _ | no_return().
|
||||
-type group_name() :: ct_helper:group_name().
|
||||
-type test_return() :: _ | no_return().
|
||||
|
||||
%% Macro helpers
|
||||
|
||||
@ -85,10 +85,13 @@ groups() ->
|
||||
|
||||
-spec init_per_suite(config()) -> config().
|
||||
init_per_suite(C) ->
|
||||
ct_helper:makeup_cfg([
|
||||
ct_helper:test_case_name(init),
|
||||
ct_payment_system:setup()
|
||||
], C).
|
||||
ct_helper:makeup_cfg(
|
||||
[
|
||||
ct_helper:test_case_name(init),
|
||||
ct_payment_system:setup()
|
||||
],
|
||||
C
|
||||
).
|
||||
|
||||
-spec end_per_suite(config()) -> _.
|
||||
end_per_suite(C) ->
|
||||
@ -103,6 +106,7 @@ init_per_group(_, C) ->
|
||||
-spec end_per_group(group_name(), config()) -> _.
|
||||
end_per_group(_, _) ->
|
||||
ok.
|
||||
|
||||
%%
|
||||
|
||||
-spec init_per_testcase(test_case_name(), config()) -> config().
|
||||
@ -125,10 +129,10 @@ create_bad_amount_test(C) ->
|
||||
source_id := SourceID
|
||||
} = prepare_standard_environment(Body, C),
|
||||
Params = #deposit_DepositParams{
|
||||
id = generate_id(),
|
||||
body = Body,
|
||||
source_id = SourceID,
|
||||
wallet_id = WalletID
|
||||
id = generate_id(),
|
||||
body = Body,
|
||||
source_id = SourceID,
|
||||
wallet_id = WalletID
|
||||
},
|
||||
Result = call_deposit('Create', [Params, #{}]),
|
||||
ExpectedError = #fistful_InvalidOperationAmount{
|
||||
@ -144,10 +148,10 @@ create_currency_validation_error_test(C) ->
|
||||
source_id := SourceID
|
||||
} = prepare_standard_environment(Body, C),
|
||||
Params = #deposit_DepositParams{
|
||||
id = generate_id(),
|
||||
body = make_cash({5000, <<"EUR">>}),
|
||||
source_id = SourceID,
|
||||
wallet_id = WalletID
|
||||
id = generate_id(),
|
||||
body = make_cash({5000, <<"EUR">>}),
|
||||
source_id = SourceID,
|
||||
wallet_id = WalletID
|
||||
},
|
||||
Result = call_deposit('Create', [Params, #{}]),
|
||||
ExpectedError = #fistful_ForbiddenOperationCurrency{
|
||||
@ -166,10 +170,10 @@ create_source_notfound_test(C) ->
|
||||
wallet_id := WalletID
|
||||
} = prepare_standard_environment(Body, C),
|
||||
Params = #deposit_DepositParams{
|
||||
id = generate_id(),
|
||||
body = Body,
|
||||
source_id = <<"unknown_source">>,
|
||||
wallet_id = WalletID
|
||||
id = generate_id(),
|
||||
body = Body,
|
||||
source_id = <<"unknown_source">>,
|
||||
wallet_id = WalletID
|
||||
},
|
||||
Result = call_deposit('Create', [Params, #{}]),
|
||||
ExpectedError = #fistful_SourceNotFound{},
|
||||
@ -182,16 +186,15 @@ create_wallet_notfound_test(C) ->
|
||||
source_id := SourceID
|
||||
} = prepare_standard_environment(Body, C),
|
||||
Params = #deposit_DepositParams{
|
||||
id = generate_id(),
|
||||
body = Body,
|
||||
source_id = SourceID,
|
||||
wallet_id = <<"unknown_wallet">>
|
||||
id = generate_id(),
|
||||
body = Body,
|
||||
source_id = SourceID,
|
||||
wallet_id = <<"unknown_wallet">>
|
||||
},
|
||||
Result = call_deposit('Create', [Params, #{}]),
|
||||
ExpectedError = #fistful_WalletNotFound{},
|
||||
?assertEqual({exception, ExpectedError}, Result).
|
||||
|
||||
|
||||
-spec create_ok_test(config()) -> test_return().
|
||||
create_ok_test(C) ->
|
||||
Body = make_cash({100, <<"RUB">>}),
|
||||
@ -204,12 +207,12 @@ create_ok_test(C) ->
|
||||
Context = #{<<"NS">> => #{generate_id() => generate_id()}},
|
||||
Metadata = ff_entity_context_codec:marshal(#{<<"metadata">> => #{<<"some key">> => <<"some data">>}}),
|
||||
Params = #deposit_DepositParams{
|
||||
id = DepositID,
|
||||
body = Body,
|
||||
source_id = SourceID,
|
||||
wallet_id = WalletID,
|
||||
metadata = Metadata,
|
||||
external_id = ExternalID
|
||||
id = DepositID,
|
||||
body = Body,
|
||||
source_id = SourceID,
|
||||
wallet_id = WalletID,
|
||||
metadata = Metadata,
|
||||
external_id = ExternalID
|
||||
},
|
||||
{ok, DepositState} = call_deposit('Create', [Params, ff_entity_context_codec:marshal(Context)]),
|
||||
Expected = get_deposit(DepositID),
|
||||
@ -269,9 +272,10 @@ create_adjustment_ok_test(C) ->
|
||||
ExternalID = generate_id(),
|
||||
Params = #dep_adj_AdjustmentParams{
|
||||
id = AdjustmentID,
|
||||
change = {change_status, #dep_adj_ChangeStatusRequest{
|
||||
new_status = {failed, #dep_status_Failed{failure = #'Failure'{code = <<"Ooops">>}}}
|
||||
}},
|
||||
change =
|
||||
{change_status, #dep_adj_ChangeStatusRequest{
|
||||
new_status = {failed, #dep_status_Failed{failure = #'Failure'{code = <<"Ooops">>}}}
|
||||
}},
|
||||
external_id = ExternalID
|
||||
},
|
||||
{ok, AdjustmentState} = call_deposit('CreateAdjustment', [DepositID, Params]),
|
||||
@ -303,9 +307,10 @@ create_adjustment_unavailable_status_error_test(C) ->
|
||||
} = prepare_standard_environment_with_deposit(C),
|
||||
Params = #dep_adj_AdjustmentParams{
|
||||
id = generate_id(),
|
||||
change = {change_status, #dep_adj_ChangeStatusRequest{
|
||||
new_status = {pending, #dep_status_Pending{}}
|
||||
}}
|
||||
change =
|
||||
{change_status, #dep_adj_ChangeStatusRequest{
|
||||
new_status = {pending, #dep_status_Pending{}}
|
||||
}}
|
||||
},
|
||||
Result = call_deposit('CreateAdjustment', [DepositID, Params]),
|
||||
ExpectedError = #deposit_ForbiddenStatusChange{
|
||||
@ -320,9 +325,10 @@ create_adjustment_already_has_status_error_test(C) ->
|
||||
} = prepare_standard_environment_with_deposit(C),
|
||||
Params = #dep_adj_AdjustmentParams{
|
||||
id = generate_id(),
|
||||
change = {change_status, #dep_adj_ChangeStatusRequest{
|
||||
new_status = {succeeded, #dep_status_Succeeded{}}
|
||||
}}
|
||||
change =
|
||||
{change_status, #dep_adj_ChangeStatusRequest{
|
||||
new_status = {succeeded, #dep_status_Succeeded{}}
|
||||
}}
|
||||
},
|
||||
Result = call_deposit('CreateAdjustment', [DepositID, Params]),
|
||||
ExpectedError = #deposit_AlreadyHasStatus{
|
||||
@ -439,9 +445,10 @@ create_revert_adjustment_ok_test(C) ->
|
||||
ExternalID = generate_id(),
|
||||
Params = #dep_rev_adj_AdjustmentParams{
|
||||
id = AdjustmentID,
|
||||
change = {change_status, #dep_rev_adj_ChangeStatusRequest{
|
||||
new_status = {failed, #dep_rev_status_Failed{failure = #'Failure'{code = <<"Ooops">>}}}
|
||||
}},
|
||||
change =
|
||||
{change_status, #dep_rev_adj_ChangeStatusRequest{
|
||||
new_status = {failed, #dep_rev_status_Failed{failure = #'Failure'{code = <<"Ooops">>}}}
|
||||
}},
|
||||
external_id = ExternalID
|
||||
},
|
||||
{ok, AdjustmentState} = call_deposit('CreateRevertAdjustment', [DepositID, RevertID, Params]),
|
||||
@ -474,9 +481,10 @@ create_revert_adjustment_unavailable_status_error_test(C) ->
|
||||
} = prepare_standard_environment_with_revert(C),
|
||||
Params = #dep_rev_adj_AdjustmentParams{
|
||||
id = generate_id(),
|
||||
change = {change_status, #dep_rev_adj_ChangeStatusRequest{
|
||||
new_status = {pending, #dep_rev_status_Pending{}}
|
||||
}}
|
||||
change =
|
||||
{change_status, #dep_rev_adj_ChangeStatusRequest{
|
||||
new_status = {pending, #dep_rev_status_Pending{}}
|
||||
}}
|
||||
},
|
||||
Result = call_deposit('CreateRevertAdjustment', [DepositID, RevertID, Params]),
|
||||
ExpectedError = #deposit_ForbiddenRevertStatusChange{
|
||||
@ -492,9 +500,10 @@ create_revert_adjustment_already_has_status_error_test(C) ->
|
||||
} = prepare_standard_environment_with_revert(C),
|
||||
Params = #dep_rev_adj_AdjustmentParams{
|
||||
id = generate_id(),
|
||||
change = {change_status, #dep_rev_adj_ChangeStatusRequest{
|
||||
new_status = {succeeded, #dep_rev_status_Succeeded{}}
|
||||
}}
|
||||
change =
|
||||
{change_status, #dep_rev_adj_ChangeStatusRequest{
|
||||
new_status = {succeeded, #dep_rev_status_Succeeded{}}
|
||||
}}
|
||||
},
|
||||
Result = call_deposit('CreateRevertAdjustment', [DepositID, RevertID, Params]),
|
||||
ExpectedError = #deposit_RevertAlreadyHasStatus{
|
||||
@ -510,16 +519,18 @@ deposit_state_content_test(C) ->
|
||||
} = prepare_standard_environment_with_revert(C),
|
||||
AdjustmentParams = #dep_adj_AdjustmentParams{
|
||||
id = generate_id(),
|
||||
change = {change_status, #dep_adj_ChangeStatusRequest{
|
||||
new_status = {failed, #dep_status_Failed{failure = #'Failure'{code = <<"Ooops">>}}}
|
||||
}}
|
||||
change =
|
||||
{change_status, #dep_adj_ChangeStatusRequest{
|
||||
new_status = {failed, #dep_status_Failed{failure = #'Failure'{code = <<"Ooops">>}}}
|
||||
}}
|
||||
},
|
||||
{ok, _} = call_deposit('CreateAdjustment', [DepositID, AdjustmentParams]),
|
||||
RevertAdjustmentParams = #dep_rev_adj_AdjustmentParams{
|
||||
id = generate_id(),
|
||||
change = {change_status, #dep_rev_adj_ChangeStatusRequest{
|
||||
new_status = {failed, #dep_rev_status_Failed{failure = #'Failure'{code = <<"Ooops">>}}}
|
||||
}}
|
||||
change =
|
||||
{change_status, #dep_rev_adj_ChangeStatusRequest{
|
||||
new_status = {failed, #dep_rev_status_Failed{failure = #'Failure'{code = <<"Ooops">>}}}
|
||||
}}
|
||||
},
|
||||
{ok, _} = call_deposit('CreateRevertAdjustment', [DepositID, RevertID, RevertAdjustmentParams]),
|
||||
|
||||
@ -541,7 +552,7 @@ call_deposit(Fun, Args) ->
|
||||
ServiceName = deposit_management,
|
||||
Service = ff_services:get_service(ServiceName),
|
||||
Request = {Service, Fun, Args},
|
||||
Client = ff_woody_client:new(#{
|
||||
Client = ff_woody_client:new(#{
|
||||
url => "http://localhost:8022" ++ ff_services:get_service_path(ServiceName)
|
||||
}),
|
||||
ff_woody_client:call(Client, Request).
|
||||
@ -638,7 +649,7 @@ get_revert_adjustment(DepositID, RevertID, AdjustmentID) ->
|
||||
await_final_deposit_status(DepositID) ->
|
||||
finished = ct_helper:await(
|
||||
finished,
|
||||
fun () ->
|
||||
fun() ->
|
||||
{ok, Machine} = ff_deposit_machine:get(DepositID),
|
||||
Deposit = ff_deposit_machine:deposit(Machine),
|
||||
case ff_deposit:is_finished(Deposit) of
|
||||
@ -655,7 +666,7 @@ await_final_deposit_status(DepositID) ->
|
||||
await_final_revert_status(DepositID, RevertID) ->
|
||||
finished = ct_helper:await(
|
||||
finished,
|
||||
fun () ->
|
||||
fun() ->
|
||||
{ok, Machine} = ff_deposit_machine:get(DepositID),
|
||||
Deposit = ff_deposit_machine:deposit(Machine),
|
||||
{ok, Revert} = ff_deposit:find_revert(RevertID, Deposit),
|
||||
@ -705,7 +716,7 @@ await_wallet_balance({Amount, Currency}, ID) ->
|
||||
Balance = {Amount, {{inclusive, Amount}, {inclusive, Amount}}, Currency},
|
||||
Balance = ct_helper:await(
|
||||
Balance,
|
||||
fun () -> get_wallet_balance(ID) end,
|
||||
fun() -> get_wallet_balance(ID) end,
|
||||
genlib_retry:linear(3, 500)
|
||||
),
|
||||
ok.
|
||||
@ -743,7 +754,7 @@ create_source(IID, _C) ->
|
||||
ok = ff_source_machine:create(Params, ff_entity_context:new()),
|
||||
authorized = ct_helper:await(
|
||||
authorized,
|
||||
fun () ->
|
||||
fun() ->
|
||||
{ok, SrcM} = ff_source_machine:get(ID),
|
||||
Source = ff_source_machine:source(SrcM),
|
||||
ff_source:status(Source)
|
||||
|
@ -15,18 +15,16 @@
|
||||
-export([create_crypto_wallet_destination_ok/1]).
|
||||
-export([create_ripple_wallet_destination_ok/1]).
|
||||
|
||||
-type config() :: ct_helper:config().
|
||||
-type config() :: ct_helper:config().
|
||||
-type test_case_name() :: ct_helper:test_case_name().
|
||||
-type group_name() :: ct_helper:group_name().
|
||||
-type test_return() :: _ | no_return().
|
||||
-type group_name() :: ct_helper:group_name().
|
||||
-type test_return() :: _ | no_return().
|
||||
|
||||
-spec all() -> [test_case_name() | {group, group_name()}].
|
||||
|
||||
all() ->
|
||||
[{group, default}].
|
||||
|
||||
-spec groups() -> [{group_name(), list(), [test_case_name()]}].
|
||||
|
||||
groups() ->
|
||||
[
|
||||
{default, [parallel], [
|
||||
@ -37,69 +35,73 @@ groups() ->
|
||||
].
|
||||
|
||||
-spec init_per_suite(config()) -> config().
|
||||
|
||||
init_per_suite(C) ->
|
||||
ct_helper:makeup_cfg([
|
||||
ct_helper:test_case_name(init),
|
||||
ct_payment_system:setup()
|
||||
], C).
|
||||
ct_helper:makeup_cfg(
|
||||
[
|
||||
ct_helper:test_case_name(init),
|
||||
ct_payment_system:setup()
|
||||
],
|
||||
C
|
||||
).
|
||||
|
||||
-spec end_per_suite(config()) -> _.
|
||||
|
||||
end_per_suite(C) ->
|
||||
ok = ct_payment_system:shutdown(C).
|
||||
|
||||
%%
|
||||
|
||||
-spec init_per_group(group_name(), config()) -> config().
|
||||
|
||||
init_per_group(_, C) ->
|
||||
C.
|
||||
|
||||
-spec end_per_group(group_name(), config()) -> _.
|
||||
|
||||
end_per_group(_, _) ->
|
||||
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),
|
||||
C1.
|
||||
|
||||
-spec end_per_testcase(test_case_name(), config()) -> _.
|
||||
|
||||
end_per_testcase(_Name, _C) ->
|
||||
ok = ct_helper:unset_context().
|
||||
|
||||
-spec create_bank_card_destination_ok(config()) -> test_return().
|
||||
|
||||
create_bank_card_destination_ok(C) ->
|
||||
Resource = {bank_card, #'ResourceBankCard'{bank_card = #'BankCard'{
|
||||
token = <<"TOKEN shmOKEN">>
|
||||
}}},
|
||||
Resource =
|
||||
{bank_card, #'ResourceBankCard'{
|
||||
bank_card = #'BankCard'{
|
||||
token = <<"TOKEN shmOKEN">>
|
||||
}
|
||||
}},
|
||||
create_destination_ok(Resource, C).
|
||||
|
||||
-spec create_crypto_wallet_destination_ok(config()) -> test_return().
|
||||
|
||||
create_crypto_wallet_destination_ok(C) ->
|
||||
Resource = {crypto_wallet, #'ResourceCryptoWallet'{crypto_wallet = #'CryptoWallet'{
|
||||
id = <<"f195298af836f41d072cb390ee62bee8">>,
|
||||
currency = bitcoin_cash,
|
||||
data = {bitcoin_cash, #'CryptoDataBitcoinCash'{}}
|
||||
}}},
|
||||
Resource =
|
||||
{crypto_wallet, #'ResourceCryptoWallet'{
|
||||
crypto_wallet = #'CryptoWallet'{
|
||||
id = <<"f195298af836f41d072cb390ee62bee8">>,
|
||||
currency = bitcoin_cash,
|
||||
data = {bitcoin_cash, #'CryptoDataBitcoinCash'{}}
|
||||
}
|
||||
}},
|
||||
create_destination_ok(Resource, C).
|
||||
|
||||
-spec create_ripple_wallet_destination_ok(config()) -> test_return().
|
||||
|
||||
create_ripple_wallet_destination_ok(C) ->
|
||||
Resource = {crypto_wallet, #'ResourceCryptoWallet'{crypto_wallet = #'CryptoWallet'{
|
||||
id = <<"ab843336bf7738dc697522fbb90508de">>,
|
||||
currency = ripple,
|
||||
data = {ripple, #'CryptoDataRipple'{tag = undefined}}
|
||||
}}},
|
||||
Resource =
|
||||
{crypto_wallet, #'ResourceCryptoWallet'{
|
||||
crypto_wallet = #'CryptoWallet'{
|
||||
id = <<"ab843336bf7738dc697522fbb90508de">>,
|
||||
currency = ripple,
|
||||
data = {ripple, #'CryptoDataRipple'{tag = undefined}}
|
||||
}
|
||||
}},
|
||||
create_destination_ok(Resource, C).
|
||||
|
||||
%%----------------------------------------------------------------------
|
||||
@ -116,21 +118,21 @@ create_destination_ok(Resource, C) ->
|
||||
Ctx = ff_entity_context_codec:marshal(#{<<"NS">> => #{}}),
|
||||
Metadata = ff_entity_context_codec:marshal(#{<<"metadata">> => #{<<"some key">> => <<"some data">>}}),
|
||||
Params = #dst_DestinationParams{
|
||||
id = ID,
|
||||
identity = IdentityID,
|
||||
name = DstName,
|
||||
currency = Currency,
|
||||
resource = Resource,
|
||||
id = ID,
|
||||
identity = IdentityID,
|
||||
name = DstName,
|
||||
currency = Currency,
|
||||
resource = Resource,
|
||||
external_id = ExternalId,
|
||||
metadata = Metadata
|
||||
metadata = Metadata
|
||||
},
|
||||
{ok, Dst} = call_service('Create', [Params, Ctx]),
|
||||
DstName = Dst#dst_DestinationState.name,
|
||||
ID = Dst#dst_DestinationState.id,
|
||||
Resource = Dst#dst_DestinationState.resource,
|
||||
ExternalId = Dst#dst_DestinationState.external_id,
|
||||
Metadata = Dst#dst_DestinationState.metadata,
|
||||
Ctx = Dst#dst_DestinationState.context,
|
||||
{ok, Dst} = call_service('Create', [Params, Ctx]),
|
||||
DstName = Dst#dst_DestinationState.name,
|
||||
ID = Dst#dst_DestinationState.id,
|
||||
Resource = Dst#dst_DestinationState.resource,
|
||||
ExternalId = Dst#dst_DestinationState.external_id,
|
||||
Metadata = Dst#dst_DestinationState.metadata,
|
||||
Ctx = Dst#dst_DestinationState.context,
|
||||
|
||||
Account = Dst#dst_DestinationState.account,
|
||||
IdentityID = Account#account_Account.identity,
|
||||
@ -140,9 +142,9 @@ create_destination_ok(Resource, C) ->
|
||||
|
||||
{authorized, #dst_Authorized{}} = ct_helper:await(
|
||||
{authorized, #dst_Authorized{}},
|
||||
fun () ->
|
||||
{ok, #dst_DestinationState{status = Status}}
|
||||
= call_service('Get', [ID, #'EventRange'{}]),
|
||||
fun() ->
|
||||
{ok, #dst_DestinationState{status = Status}} =
|
||||
call_service('Get', [ID, #'EventRange'{}]),
|
||||
Status
|
||||
end,
|
||||
genlib_retry:linear(15, 1000)
|
||||
@ -153,13 +155,12 @@ create_destination_ok(Resource, C) ->
|
||||
call_service(Fun, Args) ->
|
||||
Service = {ff_proto_destination_thrift, 'Management'},
|
||||
Request = {Service, Fun, Args},
|
||||
Client = ff_woody_client:new(#{
|
||||
url => <<"http://localhost:8022/v1/destination">>,
|
||||
Client = ff_woody_client:new(#{
|
||||
url => <<"http://localhost:8022/v1/destination">>,
|
||||
event_handler => scoper_woody_event_handler
|
||||
}),
|
||||
ff_woody_client:call(Client, Request).
|
||||
|
||||
|
||||
create_party(_C) ->
|
||||
ID = genlib:bsuuid(),
|
||||
_ = ff_party:create(ID),
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user