OPS-356: Remove invoice adj (#88)

* removed invoice adj

* bumped to valitydev/damsel@c32f50f and valitydev/limiter-proto@e045813
This commit is contained in:
Артем 2023-09-05 13:30:45 +03:00 committed by GitHub
parent db39bf920d
commit 50a7f09c24
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 3 additions and 1260 deletions

View File

@ -14,33 +14,6 @@
{invoice_status_changed, #payproc_InvoiceStatusChanged{status = Status}}
).
-define(invoice_adjustment_ev(ID, Payload),
{invoice_adjustment_change, #payproc_InvoiceAdjustmentChange{
id = ID,
payload = Payload
}}
).
-define(invoice_adjustment_ev(ID, Payload, OccurredAt),
{invoice_adjustment_change, #payproc_InvoiceAdjustmentChange{
id = ID,
payload = Payload,
occurred_at = OccurredAt
}}
).
-define(invoice_adjustment_created(Adjustment),
{invoice_adjustment_created, #payproc_InvoiceAdjustmentCreated{
adjustment = Adjustment
}}
).
-define(invoice_adjustment_status_changed(Status),
{invoice_adjustment_status_changed, #payproc_InvoiceAdjustmentStatusChanged{
status = Status
}}
).
-define(payment_ev(PaymentID, Payload),
{invoice_payment_change, #payproc_InvoicePaymentChange{
id = PaymentID,

View File

@ -67,7 +67,6 @@
activity :: undefined | activity(),
invoice :: undefined | invoice(),
payments = [] :: [{payment_id(), payment_st()}],
adjustments = [] :: [adjustment()],
party :: undefined | party()
}).
@ -77,11 +76,7 @@
-type activity() ::
invoice
| {payment, payment_id()}
| {adjustment_new, adjustment_id()}
| {adjustment_pending, adjustment_id()}.
-type adjustment_id() :: dmsl_domain_thrift:'InvoiceAdjustmentID'().
| {payment, payment_id()}.
%% API
@ -189,10 +184,6 @@ handle_function_('Get', {InvoiceID, undefined}, _Opts) ->
handle_function_('GetEvents', {InvoiceID, Range}, _Opts) ->
_ = set_invoicing_meta(InvoiceID),
get_public_history(InvoiceID, Range);
handle_function_('GetInvoiceAdjustment', {InvoiceID, ID}, _Opts) ->
St = get_state(InvoiceID),
ok = set_invoicing_meta(InvoiceID),
get_adjustment(ID, St);
handle_function_('GetPayment', {InvoiceID, PaymentID}, _Opts) ->
_ = set_invoicing_meta(InvoiceID, PaymentID),
St = get_state(InvoiceID),
@ -231,7 +222,6 @@ handle_function_(Fun, Args, _Opts) when
Fun =:= 'CancelPayment' orelse
Fun =:= 'RefundPayment' orelse
Fun =:= 'CreateManualRefund' orelse
Fun =:= 'CreateInvoiceAdjustment' orelse
Fun =:= 'CreateChargeback' orelse
Fun =:= 'CancelChargeback' orelse
Fun =:= 'AcceptChargeback' orelse
@ -463,18 +453,10 @@ map_history_error({error, notfound}) ->
-type invoice() :: dmsl_domain_thrift:'Invoice'().
-type party() :: dmsl_domain_thrift:'Party'().
-type adjustment() :: dmsl_payproc_thrift:'InvoiceAdjustment'().
-type payment_id() :: dmsl_domain_thrift:'InvoicePaymentID'().
-type payment_st() :: hg_invoice_payment:st().
-define(payment_pending(PaymentID), #payproc_InvoicePaymentPending{id = PaymentID}).
-define(adjustment_target_status(Status), #domain_InvoiceAdjustment{
state =
{status_change, #domain_InvoiceAdjustmentStatusChangeState{
scenario = #domain_InvoiceAdjustmentStatusChange{target_status = Status}
}}
}).
%%
@ -534,24 +516,6 @@ handle_signal(timeout, St = #st{activity = {payment, PaymentID}}) ->
% there's a payment pending
PaymentSession = get_payment_session(PaymentID, St),
process_payment_signal(timeout, PaymentID, PaymentSession, St);
handle_signal(timeout, St = #st{activity = {adjustment_new, ID}}) ->
OccurredAt = hg_datetime:format_now(),
{ok, {Changes, Action}} = hg_invoice_adjustment:process(OccurredAt),
#{
changes => wrap_adjustment_changes(ID, Changes, OccurredAt),
action => Action,
state => St
};
handle_signal(timeout, St = #st{activity = {adjustment_pending, ID}}) ->
_ = assert_adjustment_processed(ID, St),
OccurredAt = hg_datetime:format_now(),
?adjustment_target_status(Status) = get_adjustment(ID, St),
{ok, {Changes, Action}} = hg_invoice_adjustment:capture(OccurredAt),
#{
changes => wrap_adjustment_changes(ID, Changes, OccurredAt),
action => set_invoice_timer(Status, Action, St),
state => St
};
handle_signal(timeout, St = #st{activity = invoice}) ->
% invoice is expired
handle_expiration(St).
@ -611,12 +575,10 @@ process_call(Call, #{history := History}) ->
handle_call({{'Invoicing', 'StartPayment'}, {_InvoiceID, PaymentParams}}, St0) ->
St = St0#st{party = hg_party:get_party(get_party_id(St0))},
_ = assert_invoice(operable, St),
_ = assert_all_adjustments_finalised(St),
start_payment(PaymentParams, St);
handle_call({{'Invoicing', 'RegisterPayment'}, {_InvoiceID, PaymentParams}}, St0) ->
St = St0#st{party = hg_party:get_party(get_party_id(St0))},
_ = assert_invoice(unblocked, St),
_ = assert_all_adjustments_finalised(St),
register_payment(PaymentParams, St);
handle_call({{'Invoicing', 'CapturePayment'}, {_InvoiceID, PaymentID, Params}}, St0) ->
St = St0#st{party = hg_party:get_party(get_party_id(St0))},
@ -665,15 +627,6 @@ handle_call({{'Invoicing', 'Rescind'}, {_InvoiceID, Reason}}, St0) ->
action => hg_machine_action:unset_timer(),
state => St
};
handle_call({{'Invoicing', 'CreateInvoiceAdjustment'}, {_InvoiceID, Params}}, St) ->
ID = create_adjustment_id(St),
TargetStatus = get_adjustment_params_target_status(Params),
InvoiceStatus = get_invoice_status(St),
ok = assert_no_pending_payment(St),
ok = assert_adjustment_target_status(TargetStatus, InvoiceStatus),
ok = assert_all_adjustments_finalised(St),
OccurredAt = hg_datetime:format_now(),
wrap_adjustment_impact(ID, hg_invoice_adjustment:create(ID, Params, OccurredAt), St, OccurredAt);
handle_call({{'Invoicing', 'RefundPayment'}, {_InvoiceID, PaymentID, Params}}, St0) ->
St = St0#st{party = hg_party:get_party(get_party_id(St0))},
_ = assert_invoice(operable, St),
@ -898,17 +851,6 @@ wrap_payment_impact(PaymentID, {Response, {Changes, Action}}, St, OccurredAt) ->
state => St
}.
wrap_adjustment_changes(AdjustmentID, Changes, OccurredAt) ->
[?invoice_adjustment_ev(AdjustmentID, C, OccurredAt) || C <- Changes].
wrap_adjustment_impact(AdjustmentID, {Response, {Changes, Action}}, St, OccurredAt) ->
#{
response => Response,
changes => wrap_adjustment_changes(AdjustmentID, Changes, OccurredAt),
action => Action,
state => St
}.
handle_result(#{} = Result) ->
St = validate_changes(Result),
_ = log_changes(maps:get(changes, Result, []), St),
@ -1117,24 +1059,6 @@ merge_change(?invoice_created(Invoice), St, _Opts) ->
St#st{activity = invoice, invoice = Invoice};
merge_change(?invoice_status_changed(Status), St = #st{invoice = I}, _Opts) ->
St#st{invoice = I#domain_Invoice{status = Status}};
merge_change(?invoice_adjustment_ev(ID, Event), St, _Opts) ->
St1 =
case Event of
?invoice_adjustment_created(_Adjustment) ->
St#st{activity = {adjustment_new, ID}};
?invoice_adjustment_status_changed({processed, _}) ->
St#st{activity = {adjustment_pending, ID}};
?invoice_adjustment_status_changed(_Status) ->
St#st{activity = invoice}
end,
Adjustment = merge_adjustment_change(Event, try_get_adjustment(ID, St1)),
St2 = set_adjustment(ID, Adjustment, St1),
case get_adjustment_status(Adjustment) of
{captured, _} ->
apply_adjustment_status(Adjustment, St2);
_ ->
St2
end;
merge_change(?payment_ev(PaymentID, Change), St = #st{invoice = #domain_Invoice{id = InvoiceID}}, Opts) ->
PaymentSession = try_get_payment_session(PaymentID, St),
PaymentSession1 = merge_payment_change(Change, PaymentSession, Opts#{invoice_id => InvoiceID}),
@ -1204,76 +1128,6 @@ set_payment_session(PaymentID, PaymentSession, St = #st{payments = Payments}) ->
%%
get_adjustment_params_target_status(#payproc_InvoiceAdjustmentParams{
scenario = {status_change, #domain_InvoiceAdjustmentStatusChange{target_status = Status}}
}) ->
Status.
get_invoice_status(#st{invoice = #domain_Invoice{status = Status}}) ->
Status.
assert_adjustment_target_status(TargetStatus, Status) when TargetStatus =:= Status ->
throw(#payproc_InvoiceAlreadyHasStatus{status = Status});
assert_adjustment_target_status({TargetStatus, _}, {Status, _}) when
TargetStatus =:= unpaid, Status =/= paid; TargetStatus =:= paid, Status =/= unpaid
->
throw(#payproc_InvoiceAdjustmentStatusUnacceptable{});
assert_adjustment_target_status(_TargetStatus, _Status) ->
ok.
assert_all_adjustments_finalised(#st{adjustments = Adjustments}) ->
lists:foreach(fun assert_adjustment_finalised/1, Adjustments).
assert_adjustment_finalised(#domain_InvoiceAdjustment{id = ID, status = {Status, _}}) when
Status =:= pending; Status =:= processed
->
throw(#payproc_InvoiceAdjustmentPending{id = ID});
assert_adjustment_finalised(_) ->
ok.
assert_adjustment_processed(ID, #st{adjustments = Adjustments}) ->
case lists:keyfind(ID, #domain_InvoiceAdjustment.id, Adjustments) of
#domain_InvoiceAdjustment{status = {processed, _}} ->
ok;
#domain_InvoiceAdjustment{status = Status} ->
throw(#payproc_InvalidInvoiceAdjustmentStatus{status = Status})
end.
merge_adjustment_change(?invoice_adjustment_created(Adjustment), undefined) ->
Adjustment;
merge_adjustment_change(?invoice_adjustment_status_changed(Status), Adjustment) ->
Adjustment#domain_InvoiceAdjustment{status = Status}.
get_adjustment(ID, St) ->
case try_get_adjustment(ID, St) of
Adjustment = #domain_InvoiceAdjustment{} ->
Adjustment;
undefined ->
throw(#payproc_InvoiceAdjustmentNotFound{})
end.
try_get_adjustment(ID, #st{adjustments = As}) ->
case lists:keyfind(ID, #domain_InvoiceAdjustment.id, As) of
V = #domain_InvoiceAdjustment{} ->
V;
false ->
undefined
end.
set_adjustment(ID, Adjustment, St = #st{adjustments = As}) ->
St#st{adjustments = lists:keystore(ID, #domain_InvoiceAdjustment.id, As, Adjustment)}.
get_adjustment_status(#domain_InvoiceAdjustment{status = Status}) ->
Status.
apply_adjustment_status(?adjustment_target_status(Status), St = #st{invoice = Invoice}) ->
St#st{invoice = Invoice#domain_Invoice{status = Status}}.
create_adjustment_id(#st{adjustments = Adjustments}) ->
integer_to_binary(length(Adjustments) + 1).
%%
make_invoice_params(Params) ->
#payproc_InvoiceWithTemplateParams{
id = InvoiceID,
@ -1407,20 +1261,6 @@ get_log_params(?invoice_created(Invoice), _St) ->
get_invoice_event_log(invoice_created, unpaid, Invoice);
get_log_params(?invoice_status_changed({StatusName, _}), #st{invoice = Invoice}) ->
get_invoice_event_log(invoice_status_changed, StatusName, Invoice);
get_log_params(?invoice_adjustment_ev(_ID, Change), #st{invoice = Invoice}) ->
case hg_invoice_adjustment:get_log_params(Change) of
{ok, Params} ->
{ok,
maps:update_with(
params,
fun(V) ->
[{invoice, get_invoice_params(Invoice)} | V]
end,
Params
)};
undefined ->
undefined
end;
get_log_params(?payment_ev(PaymentID, Change), St = #st{invoice = Invoice}) ->
PaymentSession = try_get_payment_session(PaymentID, St),
case hg_invoice_payment:get_log_params(Change, PaymentSession) of

View File

@ -1,173 +0,0 @@
-module(hg_invoice_adjustment).
-include("invoice_events.hrl").
-include_lib("damsel/include/dmsl_domain_thrift.hrl").
-export(
[
create/2,
create/3,
process/1,
capture/0,
capture/1
]
).
-export([get_log_params/1]).
-type adjustment() ::
dmsl_domain_thrift:'InvoiceAdjustment'().
-type id() ::
dmsl_domain_thrift:'InvoiceAdjustmentID'().
-type params() ::
dmsl_payproc_thrift:'InvoiceAdjustmentParams'().
-type adjustment_state() ::
dmsl_domain_thrift:'InvoiceAdjustmentState'().
-type captured() ::
{captured, dmsl_domain_thrift:'InvoiceAdjustmentCaptured'()}.
-type processed() ::
{processed, dmsl_domain_thrift:'InvoiceAdjustmentProcessed'()}.
-type result() ::
{[change()], action()}.
-type change() ::
dmsl_payproc_thrift:'InvoiceAdjustmentChangePayload'().
-type action() ::
hg_machine_action:t().
-type log_params() :: #{
type := invoice_adjustment_event,
params := list(),
message := string()
}.
% API
-spec create(id(), params()) -> {adjustment(), result()}.
create(ID, Params) ->
Timestamp = hg_datetime:format_now(),
create(ID, Params, Timestamp).
-spec create(id(), params(), hg_datetime:timestamp()) -> {adjustment(), result()}.
create(ID, Params, Timestamp) ->
Adjustment = build_adjustment(ID, Params, Timestamp),
Changes = [?invoice_adjustment_created(Adjustment)],
Action = hg_machine_action:instant(),
{Adjustment, {Changes, Action}}.
-spec process(hg_datetime:timestamp()) -> {ok, result()}.
process(Timestamp) ->
AdjustmentTarget = build_adjustment_target(processed, Timestamp),
Changes = [?invoice_adjustment_status_changed(AdjustmentTarget)],
Action = hg_machine_action:instant(),
{ok, {Changes, Action}}.
-spec capture() -> {ok, result()}.
capture() ->
capture(hg_datetime:format_now()).
-spec capture(hg_datetime:timestamp()) -> {ok, result()}.
capture(Timestamp) ->
AdjustmentTarget = build_adjustment_target(captured, Timestamp),
Changes = [?invoice_adjustment_status_changed(AdjustmentTarget)],
Action = hg_machine_action:new(),
{ok, {Changes, Action}}.
-spec get_log_params(change()) -> {ok, log_params()} | undefined.
get_log_params(Change) ->
do_get_log_params(Change).
% Internal
-spec build_adjustment(id(), params(), hg_datetime:timestamp()) -> adjustment().
build_adjustment(ID, Params, Timestamp) ->
#domain_InvoiceAdjustment{
id = ID,
reason = Params#payproc_InvoiceAdjustmentParams.reason,
status = {pending, #domain_InvoiceAdjustmentPending{}},
created_at = Timestamp,
domain_revision = hg_domain:head(),
state = build_adjustment_state(Params)
}.
-spec build_adjustment_state(params()) -> adjustment_state().
build_adjustment_state(Params) ->
case Params#payproc_InvoiceAdjustmentParams.scenario of
{status_change, StatusChange} ->
{status_change, #domain_InvoiceAdjustmentStatusChangeState{scenario = StatusChange}}
end.
-spec build_adjustment_target
(processed, hg_datetime:timestamp()) -> processed();
(captured, hg_datetime:timestamp()) -> captured().
build_adjustment_target(processed, _Timestamp) ->
{processed, #domain_InvoiceAdjustmentProcessed{}};
build_adjustment_target(captured, Timestamp) ->
{captured, #domain_InvoiceAdjustmentCaptured{at = Timestamp}}.
-spec do_get_log_params(change()) -> {ok, log_params()} | undefined.
do_get_log_params(?invoice_adjustment_created(Adjustment)) ->
Params = #{
adjustment => Adjustment,
event_type => invoice_adjustment_created
},
make_log_params(Params);
do_get_log_params(?invoice_adjustment_status_changed(Status)) ->
Params = #{
adjustment_status => Status,
event_type => invoice_adjustment_status_changed
},
make_log_params(Params);
do_get_log_params(_) ->
undefined.
-spec make_log_params(Params :: map()) -> {ok, log_params()}.
make_log_params(#{event_type := EventType} = Params) ->
LogParams = maps:fold(
fun(K, V, Acc) ->
build_log_param(K, V) ++ Acc
end,
[],
Params
),
Message = get_log_message(EventType),
{ok, #{
type => invoice_adjustment_event,
message => Message,
params => LogParams
}}.
-spec build_log_param(atom(), term()) -> [{atom(), term()}].
build_log_param(adjustment, #domain_InvoiceAdjustment{} = Adjustment) ->
[
{id, Adjustment#domain_InvoiceAdjustment.id},
{reason, Adjustment#domain_InvoiceAdjustment.reason}
| build_log_param(state, Adjustment#domain_InvoiceAdjustment.state)
];
build_log_param(state, {status_change, State}) ->
Scenario = State#domain_InvoiceAdjustmentStatusChangeState.scenario,
TargetStatus = Scenario#domain_InvoiceAdjustmentStatusChange.target_status,
build_log_param(target_status, TargetStatus);
build_log_param(adjustment_status, {Status, _Details}) ->
[{status, Status}];
build_log_param(target_status, {Status, _Details}) ->
[{status, Status}];
build_log_param(_Key, _Value) ->
[].
-spec get_log_message(EventType) -> string() when
EventType ::
invoice_adjustment_created
| invoice_adjustment_status_changed.
get_log_message(invoice_adjustment_created) ->
"Invoice adjustment created";
get_log_message(invoice_adjustment_status_changed) ->
"Invoice adjustment status changed".

View File

@ -1,879 +0,0 @@
-module(hg_invoice_adjustment_tests_SUITE).
-include("hg_ct_domain.hrl").
-include_lib("stdlib/include/assert.hrl").
-export([all/0]).
-export([groups/0]).
-export([init_per_suite/1]).
-export([end_per_suite/1]).
-export([init_per_testcase/2]).
-export([end_per_testcase/2]).
-export([invoice_adjustment_capture/1]).
-export([invoice_adjustment_existing_invoice_status/1]).
-export([invoice_adjustment_invalid_invoice_status/1]).
-export([invoice_adjustment_payment_pending/1]).
-export([invoice_adjustment_invoice_expiration_after_capture/1]).
-behaviour(supervisor).
-export([init/1]).
-spec init([]) -> {ok, {supervisor:sup_flags(), [supervisor:child_spec()]}}.
init([]) ->
{ok, {#{strategy => one_for_all, intensity => 1, period => 1}, []}}.
%% tests descriptions
-type config() :: hg_ct_helper:config().
-type test_case_name() :: hg_ct_helper:test_case_name().
-type group_name() :: hg_ct_helper:group_name().
-type test_return() :: _ | no_return().
cfg(Key, C) ->
hg_ct_helper:cfg(Key, C).
-spec all() -> [test_case_name() | {group, group_name()}].
all() ->
[
{group, all_tests}
].
-spec groups() -> [{group_name(), list(), [test_case_name()]}].
groups() ->
[
{all_tests, [parallel], [
invoice_adjustment_capture,
invoice_adjustment_existing_invoice_status,
invoice_adjustment_invalid_invoice_status,
invoice_adjustment_payment_pending,
invoice_adjustment_invoice_expiration_after_capture
]}
].
%% starting/stopping
-spec init_per_suite(config()) -> config().
init_per_suite(C) ->
% _ = dbg:tracer(),
% _ = dbg:p(all, c),
% _ = dbg:tpl({'hg_invoice_payment', 'p', '_'}, x),
CowboySpec = hg_dummy_provider:get_http_cowboy_spec(),
{Apps, Ret} = hg_ct_helper:start_apps([
woody,
scoper,
dmt_client,
bender_client,
party_client,
hg_proto,
hellgate,
{cowboy, CowboySpec}
]),
_ = hg_domain:insert(construct_domain_fixture()),
RootUrl = maps:get(hellgate_root_url, Ret),
PartyID = hg_utils:unique_id(),
PartyClient = {party_client:create_client(), party_client:create_context()},
ShopID = hg_ct_helper:create_party_and_shop(PartyID, ?cat(1), <<"RUB">>, ?tmpl(1), ?pinst(1), PartyClient),
{ok, SupPid} = supervisor:start_link(?MODULE, []),
_ = unlink(SupPid),
NewC = [
{party_id, PartyID},
{shop_id, ShopID},
{root_url, RootUrl},
{apps, Apps},
{test_sup, SupPid}
| C
],
ok = start_proxies([{hg_dummy_provider, 1, NewC}, {hg_dummy_inspector, 2, NewC}]),
NewC.
-spec end_per_suite(config()) -> _.
end_per_suite(C) ->
_ = hg_domain:cleanup(),
_ = [application:stop(App) || App <- cfg(apps, C)],
exit(cfg(test_sup, C), shutdown).
-spec init_per_testcase(test_case_name(), config()) -> config().
init_per_testcase(_Name, C) ->
init_per_testcase(C).
init_per_testcase(C) ->
ApiClient = hg_ct_helper:create_client(cfg(root_url, C)),
Client = hg_client_invoicing:start_link(ApiClient),
ClientTpl = hg_client_invoice_templating:start_link(ApiClient),
ok = hg_context:save(hg_context:create()),
[{client, Client}, {client_tpl, ClientTpl} | C].
-spec end_per_testcase(test_case_name(), config()) -> _.
end_per_testcase(_Name, _C) ->
ok = hg_context:cleanup().
-include("invoice_events.hrl").
-include("payment_events.hrl").
-include("customer_events.hrl").
-define(invoice(ID), #domain_Invoice{id = ID}).
-define(payment(ID), #domain_InvoicePayment{id = ID}).
-define(invoice_state(Invoice), #payproc_Invoice{invoice = Invoice}).
-define(payment_state(Payment), #payproc_InvoicePayment{payment = Payment}).
-define(payment_w_status(Status), #domain_InvoicePayment{status = Status}).
-define(trx_info(ID), #domain_TransactionInfo{id = ID}).
-define(merchant_to_system_share_1, ?share(45, 1000, operation_amount)).
-define(merchant_to_system_share_2, ?share(100, 1000, operation_amount)).
%% ADJ
-spec invoice_adjustment_capture(config()) -> test_return().
invoice_adjustment_capture(C) ->
Client = cfg(client, C),
ShopID = cfg(shop_id, C),
PartyID = cfg(party_id, C),
InvoiceParams = make_invoice_params(PartyID, ShopID, <<"rubberduck">>, make_due_date(10), make_cash(10000)),
InvoiceID = create_invoice(InvoiceParams, Client),
[?invoice_created(_Invoice)] = next_event(InvoiceID, Client),
PaymentID = process_payment(InvoiceID, make_payment_params(?pmt_sys(<<"visa-ref">>)), Client),
PaymentID = await_payment_capture(InvoiceID, PaymentID, Client),
Unpaid = {unpaid, #domain_InvoiceUnpaid{}},
AdjustmentParams = #payproc_InvoiceAdjustmentParams{
reason = <<"kek">>,
scenario =
{status_change, #domain_InvoiceAdjustmentStatusChange{
target_status = Unpaid
}}
},
Adjustment = hg_client_invoicing:create_invoice_adjustment(InvoiceID, AdjustmentParams, Client),
?assertMatch({pending, #domain_InvoiceAdjustmentPending{}}, Adjustment#domain_InvoiceAdjustment.status),
[?invoice_adjustment_ev(ID, ?invoice_adjustment_created(Adjustment))] = next_event(InvoiceID, Client),
[?invoice_adjustment_ev(ID, ?invoice_adjustment_status_changed(Processed))] = next_event(InvoiceID, Client),
?assertMatch({processed, #domain_InvoiceAdjustmentProcessed{}}, Processed),
[?invoice_adjustment_ev(ID, ?invoice_adjustment_status_changed(Captured))] = next_event(InvoiceID, Client),
?assertMatch({captured, #domain_InvoiceAdjustmentCaptured{}}, Captured),
#payproc_Invoice{invoice = #domain_Invoice{status = FinalStatus}} = hg_client_invoicing:get(InvoiceID, Client),
?assertMatch(Unpaid, FinalStatus).
-spec invoice_adjustment_invalid_invoice_status(config()) -> test_return().
invoice_adjustment_invalid_invoice_status(C) ->
Client = cfg(client, C),
ShopID = cfg(shop_id, C),
PartyID = cfg(party_id, C),
InvoiceParams = make_invoice_params(PartyID, ShopID, <<"rubberduck">>, make_cash(10000)),
InvoiceID = create_invoice(InvoiceParams, Client),
[?invoice_created(_)] = next_event(InvoiceID, Client),
PaymentID = process_payment(InvoiceID, make_payment_params(?pmt_sys(<<"visa-ref">>)), Client),
PaymentID = await_payment_capture(InvoiceID, PaymentID, Client),
AdjustmentParams = #payproc_InvoiceAdjustmentParams{
reason = <<"kek">>,
scenario =
{status_change, #domain_InvoiceAdjustmentStatusChange{
target_status = {unpaid, #domain_InvoiceUnpaid{}}
}}
},
ok = hg_client_invoicing:fulfill(InvoiceID, <<"ok">>, Client),
{exception, E} = hg_client_invoicing:create_invoice_adjustment(InvoiceID, AdjustmentParams, Client),
?assertMatch(#payproc_InvoiceAdjustmentStatusUnacceptable{}, E).
-spec invoice_adjustment_existing_invoice_status(config()) -> test_return().
invoice_adjustment_existing_invoice_status(C) ->
Client = cfg(client, C),
ShopID = cfg(shop_id, C),
PartyID = cfg(party_id, C),
InvoiceParams = make_invoice_params(PartyID, ShopID, <<"rubberduck">>, make_cash(10000)),
InvoiceID = create_invoice(InvoiceParams, Client),
[?invoice_created(_)] = next_event(InvoiceID, Client),
PaymentID = process_payment(InvoiceID, make_payment_params(?pmt_sys(<<"visa-ref">>)), Client),
PaymentID = await_payment_capture(InvoiceID, PaymentID, Client),
Paid = {paid, #domain_InvoicePaid{}},
AdjustmentParams = #payproc_InvoiceAdjustmentParams{
reason = <<"kek">>,
scenario =
{status_change, #domain_InvoiceAdjustmentStatusChange{
target_status = Paid
}}
},
{exception, E} = hg_client_invoicing:create_invoice_adjustment(InvoiceID, AdjustmentParams, Client),
?assertMatch(#payproc_InvoiceAlreadyHasStatus{status = Paid}, E).
-spec invoice_adjustment_payment_pending(config()) -> test_return().
invoice_adjustment_payment_pending(C) ->
Client = cfg(client, C),
ShopID = cfg(shop_id, C),
PartyID = cfg(party_id, C),
InvoiceParams = make_invoice_params(PartyID, ShopID, <<"rubberduck">>, make_due_date(10), make_cash(10000)),
InvoiceID = create_invoice(InvoiceParams, Client),
[?invoice_created(_)] = next_event(InvoiceID, Client),
PaymentID = start_payment(InvoiceID, make_tds_payment_params(instant, ?pmt_sys(<<"visa-ref">>)), Client),
Paid = {paid, #domain_InvoicePaid{}},
AdjustmentParams = #payproc_InvoiceAdjustmentParams{
reason = <<"kek">>,
scenario =
{status_change, #domain_InvoiceAdjustmentStatusChange{
target_status = Paid
}}
},
{exception, E} = hg_client_invoicing:create_invoice_adjustment(InvoiceID, AdjustmentParams, Client),
?assertMatch(#payproc_InvoicePaymentPending{id = PaymentID}, E),
UserInteraction = await_payment_process_interaction(InvoiceID, PaymentID, Client),
_ = assert_success_interaction(UserInteraction),
ok = await_payment_process_interaction_completion(InvoiceID, PaymentID, UserInteraction, Client),
PaymentID = await_payment_process_finish(InvoiceID, PaymentID, Client),
PaymentID = await_payment_capture(InvoiceID, PaymentID, Client).
-spec invoice_adjustment_invoice_expiration_after_capture(config()) -> test_return().
invoice_adjustment_invoice_expiration_after_capture(C) ->
Client = cfg(client, C),
ShopID = cfg(shop_id, C),
PartyID = cfg(party_id, C),
InvoiceParams = make_invoice_params(PartyID, ShopID, <<"rubberduck">>, make_due_date(10), make_cash(10000)),
InvoiceID = create_invoice(InvoiceParams, Client),
[?invoice_created(_)] = next_event(InvoiceID, Client),
Context = #base_Content{
type = <<"application/x-erlang-binary">>,
data = erlang:term_to_binary({you, 643, "not", [<<"welcome">>, here]})
},
PaymentParams = set_payment_context(Context, make_payment_params(?pmt_sys(<<"visa-ref">>))),
PaymentID = process_payment(InvoiceID, PaymentParams, Client),
PaymentID = await_payment_capture(InvoiceID, PaymentID, Client),
Unpaid = {unpaid, #domain_InvoiceUnpaid{}},
AdjustmentParams = #payproc_InvoiceAdjustmentParams{
reason = <<"kek">>,
scenario =
{status_change, #domain_InvoiceAdjustmentStatusChange{
target_status = Unpaid
}}
},
Adjustment = hg_client_invoicing:create_invoice_adjustment(InvoiceID, AdjustmentParams, Client),
?assertMatch({pending, #domain_InvoiceAdjustmentPending{}}, Adjustment#domain_InvoiceAdjustment.status),
[?invoice_adjustment_ev(ID, ?invoice_adjustment_created(Adjustment))] = next_event(InvoiceID, Client),
[?invoice_adjustment_ev(ID, ?invoice_adjustment_status_changed(Processed))] = next_event(InvoiceID, Client),
?assertMatch({processed, #domain_InvoiceAdjustmentProcessed{}}, Processed),
[?invoice_adjustment_ev(ID, ?invoice_adjustment_status_changed(Captured))] = next_event(InvoiceID, Client),
?assertMatch({captured, #domain_InvoiceAdjustmentCaptured{}}, Captured),
#payproc_Invoice{invoice = #domain_Invoice{status = Unpaid}} = hg_client_invoicing:get(InvoiceID, Client),
[?invoice_status_changed(?invoice_cancelled(_))] = next_event(InvoiceID, Client).
%% ADJ
-spec construct_domain_fixture() -> [hg_domain:object()].
construct_domain_fixture() ->
TestTermSet = #domain_TermSet{
payments = #domain_PaymentsServiceTerms{
currencies =
{value,
?ordset([
?cur(<<"RUB">>)
])},
categories =
{value,
?ordset([
?cat(1)
])},
payment_methods =
{decisions, [
#domain_PaymentMethodDecision{
if_ = {constant, true},
then_ =
{value,
?ordset([
?pmt(bank_card, ?bank_card(<<"visa-ref">>))
])}
}
]},
cash_limit =
{decisions, [
#domain_CashLimitDecision{
if_ = {condition, {currency_is, ?cur(<<"RUB">>)}},
then_ =
{value,
?cashrng(
{inclusive, ?cash(10, <<"RUB">>)},
{exclusive, ?cash(420000000, <<"RUB">>)}
)}
}
]},
fees =
{decisions, [
#domain_CashFlowDecision{
if_ =
{condition,
{payment_tool,
{bank_card, #domain_BankCardCondition{
definition = {category_is, ?bc_cat(1)}
}}}},
then_ =
{value, [
?cfpost(
{merchant, settlement},
{system, settlement},
?merchant_to_system_share_2
)
]}
},
#domain_CashFlowDecision{
if_ = {condition, {currency_is, ?cur(<<"RUB">>)}},
then_ =
{value, [
?cfpost(
{merchant, settlement},
{system, settlement},
?merchant_to_system_share_1
)
]}
}
]},
holds = #domain_PaymentHoldsServiceTerms{
payment_methods =
{value,
?ordset([
?pmt(bank_card, ?bank_card(<<"visa-ref">>))
])},
lifetime =
{decisions, [
#domain_HoldLifetimeDecision{
if_ = {condition, {currency_is, ?cur(<<"RUB">>)}},
then_ = {value, #domain_HoldLifetime{seconds = 10}}
}
]}
},
refunds = #domain_PaymentRefundsServiceTerms{
payment_methods =
{value,
?ordset([
?pmt(bank_card, ?bank_card(<<"visa-ref">>))
])},
fees =
{value, [
?cfpost(
{merchant, settlement},
{system, settlement},
?fixed(100, <<"RUB">>)
)
]},
eligibility_time = {value, #base_TimeSpan{minutes = 1}},
partial_refunds = #domain_PartialRefundsServiceTerms{
cash_limit =
{decisions, [
#domain_CashLimitDecision{
if_ = {condition, {currency_is, ?cur(<<"RUB">>)}},
then_ =
{value,
?cashrng(
{inclusive, ?cash(1000, <<"RUB">>)},
{exclusive, ?cash(1000000000, <<"RUB">>)}
)}
}
]}
}
}
},
recurrent_paytools = #domain_RecurrentPaytoolsServiceTerms{
payment_methods =
{value,
ordsets:from_list([
?pmt(bank_card, ?bank_card(<<"visa-ref">>))
])}
}
},
[
hg_ct_fixture:construct_bank_card_category(
?bc_cat(1),
<<"Bank card category">>,
<<"Corporative">>,
[<<"*CORPORAT*">>]
),
hg_ct_fixture:construct_currency(?cur(<<"RUB">>)),
hg_ct_fixture:construct_category(?cat(1), <<"Test category">>, test),
hg_ct_fixture:construct_payment_method(?pmt(bank_card, ?bank_card(<<"visa-ref">>))),
hg_ct_fixture:construct_proxy(?prx(1), <<"Dummy proxy">>),
hg_ct_fixture:construct_proxy(?prx(2), <<"Inspector proxy">>),
hg_ct_fixture:construct_inspector(?insp(1), <<"Rejector">>, ?prx(2), #{<<"risk_score">> => <<"low">>}),
hg_ct_fixture:construct_contract_template(?tmpl(1), ?trms(1)),
hg_ct_fixture:construct_system_account_set(?sas(1)),
hg_ct_fixture:construct_external_account_set(?eas(1)),
{payment_institution, #domain_PaymentInstitutionObject{
ref = ?pinst(1),
data = #domain_PaymentInstitution{
name = <<"Test Inc.">>,
system_account_set = {value, ?sas(1)},
default_contract_template = {value, ?tmpl(1)},
payment_routing_rules = #domain_RoutingRules{
policies = ?ruleset(2),
prohibitions = ?ruleset(1)
},
inspector =
{decisions, [
#domain_InspectorDecision{
if_ = {condition, {currency_is, ?cur(<<"RUB">>)}},
then_ =
{decisions, [
#domain_InspectorDecision{
if_ =
{condition,
{cost_in,
?cashrng(
{inclusive, ?cash(0, <<"RUB">>)},
{exclusive, ?cash(500000, <<"RUB">>)}
)}},
then_ = {value, ?insp(1)}
}
]}
}
]},
residences = [],
realm = test
}
}},
{routing_rules, #domain_RoutingRulesObject{
ref = ?ruleset(1),
data = #domain_RoutingRuleset{
name = <<"Prohibitions: all is allow">>,
decisions = {candidates, []}
}
}},
{routing_rules, #domain_RoutingRulesObject{
ref = ?ruleset(2),
data = #domain_RoutingRuleset{
name = <<"Prohibitions: all is allow">>,
decisions =
{candidates, [
?candidate({constant, true}, ?trm(1))
]}
}
}},
{globals, #domain_GlobalsObject{
ref = #domain_GlobalsRef{},
data = #domain_Globals{
external_account_set =
{decisions, [
#domain_ExternalAccountSetDecision{
if_ = {constant, true},
then_ = {value, ?eas(1)}
}
]},
payment_institutions = ?ordset([?pinst(1)])
}
}},
{term_set_hierarchy, #domain_TermSetHierarchyObject{
ref = ?trms(1),
data = #domain_TermSetHierarchy{
term_sets = [
#domain_TimedTermSet{
action_time = #base_TimestampInterval{},
terms = TestTermSet
}
]
}
}},
{provider, #domain_ProviderObject{
ref = ?prv(1),
data = #domain_Provider{
name = <<"Brovider">>,
description = <<"A provider but bro">>,
proxy = #domain_Proxy{
ref = ?prx(1),
additional = #{
<<"override">> => <<"brovider">>
}
},
abs_account = <<"1234567890">>,
accounts = hg_ct_fixture:construct_provider_account_set([?cur(<<"RUB">>)]),
terms = #domain_ProvisionTermSet{
payments = #domain_PaymentsProvisionTerms{
currencies =
{value,
?ordset([
?cur(<<"RUB">>)
])},
categories =
{value,
?ordset([
?cat(1)
])},
payment_methods =
{value,
?ordset([
?pmt(bank_card, ?bank_card(<<"visa-ref">>))
])},
cash_limit =
{value,
?cashrng(
{inclusive, ?cash(1000, <<"RUB">>)},
{exclusive, ?cash(1000000000, <<"RUB">>)}
)},
cash_flow =
{decisions, [
#domain_CashFlowDecision{
if_ =
{condition,
{payment_tool,
{bank_card, #domain_BankCardCondition{
definition =
{payment_system, #domain_PaymentSystemCondition{
payment_system_is = ?pmt_sys(<<"visa-ref">>)
}}
}}}},
then_ =
{value, [
?cfpost(
{provider, settlement},
{merchant, settlement},
?share(1, 1, operation_amount)
),
?cfpost(
{system, settlement},
{provider, settlement},
?share(18, 1000, operation_amount)
)
]}
}
]},
holds = #domain_PaymentHoldsProvisionTerms{
lifetime =
{decisions, [
#domain_HoldLifetimeDecision{
if_ =
{condition,
{payment_tool,
{bank_card, #domain_BankCardCondition{
definition =
{payment_system, #domain_PaymentSystemCondition{
payment_system_is = ?pmt_sys(<<"visa-ref">>)
}}
}}}},
then_ = {value, ?hold_lifetime(12)}
}
]}
},
refunds = #domain_PaymentRefundsProvisionTerms{
cash_flow =
{value, [
?cfpost(
{merchant, settlement},
{provider, settlement},
?share(1, 1, operation_amount)
)
]},
partial_refunds = #domain_PartialRefundsProvisionTerms{
cash_limit =
{value,
?cashrng(
{inclusive, ?cash(10, <<"RUB">>)},
{exclusive, ?cash(1000000000, <<"RUB">>)}
)}
}
},
chargebacks = #domain_PaymentChargebackProvisionTerms{
cash_flow =
{value, [
?cfpost(
{merchant, settlement},
{provider, settlement},
?share(1, 1, operation_amount)
)
]}
}
},
recurrent_paytools = #domain_RecurrentPaytoolsProvisionTerms{
categories = {value, ?ordset([?cat(1)])},
payment_methods =
{value,
?ordset([
?pmt(bank_card, ?bank_card(<<"visa-ref">>))
])},
cash_value = {value, ?cash(1000, <<"RUB">>)}
}
}
}
}},
{terminal, #domain_TerminalObject{
ref = ?trm(1),
data = #domain_Terminal{
name = <<"Brominal 1">>,
description = <<"Brominal 1">>,
risk_coverage = high,
provider_ref = ?prv(1)
}
}},
hg_ct_fixture:construct_payment_system(?pmt_sys(<<"visa-ref">>), <<"visa payment system">>)
].
start_service_handler(Module, C, HandlerOpts) ->
start_service_handler(Module, Module, C, HandlerOpts).
start_service_handler(Name, Module, C, HandlerOpts) ->
IP = "127.0.0.1",
Port = get_random_port(),
Opts = maps:merge(HandlerOpts, #{hellgate_root_url => cfg(root_url, C)}),
ChildSpec = hg_test_proxy:get_child_spec(Name, Module, IP, Port, Opts),
{ok, _} = supervisor:start_child(cfg(test_sup, C), ChildSpec),
hg_test_proxy:get_url(Module, IP, Port).
start_proxies(Proxies) ->
setup_proxies(
lists:map(
fun
Mapper({Module, ProxyID, Context}) ->
Mapper({Module, ProxyID, #{}, Context});
Mapper({Module, ProxyID, ProxyOpts, Context}) ->
construct_proxy(ProxyID, start_service_handler(Module, Context, #{}), ProxyOpts)
end,
Proxies
)
).
setup_proxies(Proxies) ->
_ = hg_domain:upsert(Proxies),
ok.
get_random_port() ->
rand:uniform(32768) + 32767.
construct_proxy(ID, Url, Options) ->
{proxy, #domain_ProxyObject{
ref = ?prx(ID),
data = #domain_ProxyDefinition{
name = Url,
description = Url,
url = Url,
options = Options
}
}}.
make_cash(Amount) ->
hg_ct_helper:make_cash(Amount, <<"RUB">>).
make_invoice_params(PartyID, ShopID, Product, Cost) ->
hg_ct_helper:make_invoice_params(PartyID, ShopID, Product, Cost).
make_invoice_params(PartyID, ShopID, Product, Due, Cost) ->
hg_ct_helper:make_invoice_params(PartyID, ShopID, Product, Due, Cost).
make_due_date(LifetimeSeconds) ->
genlib_time:unow() + LifetimeSeconds.
create_invoice(InvoiceParams, Client) ->
?invoice_state(?invoice(InvoiceID)) = hg_client_invoicing:create(InvoiceParams, Client),
InvoiceID.
next_event(InvoiceID, Client) ->
%% timeout should be at least as large as hold expiration in construct_domain_fixture/0
next_event(InvoiceID, 12000, Client).
next_event(InvoiceID, Timeout, Client) ->
case hg_client_invoicing:pull_event(InvoiceID, Timeout, Client) of
{ok, ?invoice_ev(Changes)} ->
case filter_changes(Changes) of
L when length(L) > 0 ->
L;
[] ->
next_event(InvoiceID, Timeout, Client)
end;
Result ->
Result
end.
filter_changes(Changes) ->
lists:filtermap(fun filter_change/1, Changes).
filter_change(?payment_ev(_, C)) ->
filter_change(C);
filter_change(?chargeback_ev(_, C)) ->
filter_change(C);
filter_change(?refund_ev(_, C)) ->
filter_change(C);
filter_change(?session_ev(_, ?proxy_st_changed(_))) ->
false;
filter_change(?session_ev(_, ?session_suspended(_, _))) ->
false;
filter_change(?session_ev(_, ?session_activated())) ->
false;
filter_change(_) ->
true.
set_payment_context(Context, Params = #payproc_InvoicePaymentParams{}) ->
Params#payproc_InvoicePaymentParams{context = Context}.
make_payment_params(PmtSys) ->
make_payment_params(instant, PmtSys).
make_payment_params(FlowType, PmtSys) ->
{PaymentTool, Session} = hg_dummy_provider:make_payment_tool(no_preauth, PmtSys),
make_payment_params(PaymentTool, Session, FlowType).
make_tds_payment_params(FlowType, PmtSys) ->
{PaymentTool, Session} = hg_dummy_provider:make_payment_tool(preauth_3ds, PmtSys),
make_payment_params(PaymentTool, Session, FlowType).
make_payment_params(PaymentTool, Session, FlowType) ->
Flow =
case FlowType of
instant ->
{instant, #payproc_InvoicePaymentParamsFlowInstant{}}
end,
#payproc_InvoicePaymentParams{
payer =
{payment_resource, #payproc_PaymentResourcePayerParams{
resource = #domain_DisposablePaymentResource{
payment_tool = PaymentTool,
payment_session_id = Session,
client_info = #domain_ClientInfo{}
},
contact_info = #domain_ContactInfo{}
}},
flow = Flow
}.
start_payment(InvoiceID, PaymentParams, Client) ->
?payment_state(?payment(PaymentID)) = hg_client_invoicing:start_payment(InvoiceID, PaymentParams, Client),
[
?payment_ev(PaymentID, ?payment_started(?payment_w_status(?pending())))
] = next_event(InvoiceID, Client),
[
?payment_ev(PaymentID, ?risk_score_changed(_))
] = next_event(InvoiceID, Client),
[
?payment_ev(PaymentID, ?route_changed(_))
] = next_event(InvoiceID, Client),
[
?payment_ev(PaymentID, ?cash_flow_changed(_))
] = next_event(InvoiceID, Client),
PaymentID.
process_payment(InvoiceID, PaymentParams, Client) ->
process_payment(InvoiceID, PaymentParams, Client, 0).
process_payment(InvoiceID, PaymentParams, Client, Restarts) ->
PaymentID = start_payment(InvoiceID, PaymentParams, Client),
PaymentID = await_payment_session_started(InvoiceID, PaymentID, Client, ?processed()),
PaymentID = await_payment_process_finish(InvoiceID, PaymentID, Client, Restarts).
await_payment_session_started(InvoiceID, PaymentID, Client, Target) ->
[
?payment_ev(PaymentID, ?session_ev(Target, ?session_started()))
] = next_event(InvoiceID, Client),
PaymentID.
await_payment_process_finish(InvoiceID, PaymentID, Client) ->
await_payment_process_finish(InvoiceID, PaymentID, Client, 0).
await_payment_process_finish(InvoiceID, PaymentID, Client, Restarts) ->
PaymentID = await_sessions_restarts(PaymentID, ?processed(), InvoiceID, Client, Restarts),
[
?payment_ev(PaymentID, ?session_ev(?processed(), ?trx_bound(?trx_info(_)))),
?payment_ev(PaymentID, ?session_ev(?processed(), ?session_finished(?session_succeeded())))
] = next_event(InvoiceID, Client),
[
?payment_ev(PaymentID, ?payment_status_changed(?processed()))
] = next_event(InvoiceID, Client),
PaymentID.
get_payment_cost(InvoiceID, PaymentID, Client) ->
#payproc_InvoicePayment{
payment = #domain_InvoicePayment{cost = Cost}
} = hg_client_invoicing:get_payment(InvoiceID, PaymentID, Client),
Cost.
await_payment_capture(InvoiceID, PaymentID, Client) ->
await_payment_capture(InvoiceID, PaymentID, ?timeout_reason(), Client).
await_payment_capture(InvoiceID, PaymentID, Reason, Client) ->
await_payment_capture(InvoiceID, PaymentID, Reason, Client, 0).
await_payment_capture(InvoiceID, PaymentID, Reason, Client, Restarts) ->
Cost = get_payment_cost(InvoiceID, PaymentID, Client),
[
?payment_ev(PaymentID, ?payment_capture_started(Reason, Cost, _, _Allocation)),
?payment_ev(PaymentID, ?session_ev(?captured(Reason, Cost), ?session_started()))
] = next_event(InvoiceID, Client),
await_payment_capture_finish(InvoiceID, PaymentID, Reason, Client, Restarts).
await_payment_capture_finish(InvoiceID, PaymentID, Reason, Client, Restarts) ->
Cost = get_payment_cost(InvoiceID, PaymentID, Client),
await_payment_capture_finish(InvoiceID, PaymentID, Reason, Client, Restarts, Cost).
await_payment_capture_finish(InvoiceID, PaymentID, Reason, Client, Restarts, Cost) ->
await_payment_capture_finish(InvoiceID, PaymentID, Reason, Client, Restarts, Cost, undefined).
await_payment_capture_finish(InvoiceID, PaymentID, Reason, Client, Restarts, Cost, Cart) ->
Target = ?captured(Reason, Cost, Cart),
PaymentID = await_sessions_restarts(PaymentID, Target, InvoiceID, Client, Restarts),
[
?payment_ev(PaymentID, ?session_ev(Target, ?session_finished(?session_succeeded())))
] = next_event(InvoiceID, Client),
[
?payment_ev(PaymentID, ?payment_status_changed(Target)),
?invoice_status_changed(?invoice_paid())
] = next_event(InvoiceID, Client),
PaymentID.
await_payment_process_interaction(InvoiceID, PaymentID, Client) ->
Events0 = next_event(InvoiceID, Client),
[
?payment_ev(PaymentID, ?session_ev(?processed(), ?session_started()))
] = Events0,
Events1 = next_event(InvoiceID, Client),
[
?payment_ev(
PaymentID,
?session_ev(?processed(), ?interaction_changed(UserInteraction, ?interaction_requested))
)
] = Events1,
UserInteraction.
await_payment_process_interaction_completion(InvoiceID, PaymentID, UserInteraction, Client) ->
[
?payment_ev(
PaymentID,
?session_ev(?processed(), ?interaction_changed(UserInteraction, ?interaction_completed))
)
] = next_event(InvoiceID, Client),
ok.
-dialyzer({no_match, await_sessions_restarts/5}).
await_sessions_restarts(PaymentID, _Target, _InvoiceID, _Client, 0) ->
PaymentID;
await_sessions_restarts(PaymentID, ?refunded() = Target, InvoiceID, Client, Restarts) when Restarts > 0 ->
[
?payment_ev(PaymentID, ?refund_ev(_, ?session_ev(Target, ?session_finished(?session_failed(_))))),
?payment_ev(PaymentID, ?refund_ev(_, ?session_ev(Target, ?session_started())))
] = next_event(InvoiceID, Client),
await_sessions_restarts(PaymentID, Target, InvoiceID, Client, Restarts - 1);
await_sessions_restarts(PaymentID, Target, InvoiceID, Client, Restarts) when Restarts > 0 ->
[
?payment_ev(PaymentID, ?session_ev(Target, ?session_finished(?session_failed(_)))),
?payment_ev(PaymentID, ?session_ev(Target, ?session_started()))
] = next_event(InvoiceID, Client),
await_sessions_restarts(PaymentID, Target, InvoiceID, Client, Restarts - 1).
assert_success_interaction(UserInteraction) ->
{URL, Form} = get_post_request(UserInteraction),
{ok, 200, _RespHeaders, _ClientRef} = post_request(URL, Form).
get_post_request(?redirect(URL, Form)) ->
{URL, Form};
get_post_request(?payterm_receipt(SPID)) ->
URL = hg_dummy_provider:get_callback_url(),
{URL, #{<<"tag">> => SPID}}.
post_request(URL, Form) ->
Method = post,
Headers = [],
Body = {form, maps:to_list(Form)},
hackney:request(Method, URL, Headers, Body).

View File

@ -17,9 +17,6 @@
-export([repair_scenario/3]).
-export([get_limit_values/3]).
-export([create_invoice_adjustment/3]).
-export([get_invoice_adjustment/3]).
-export([start_payment/3]).
-export([register_payment/3]).
-export([get_payment/3]).
@ -70,9 +67,6 @@
-type invoice_params() :: dmsl_payproc_thrift:'InvoiceParams'().
-type invoice_params_tpl() :: dmsl_payproc_thrift:'InvoiceWithTemplateParams'().
-type invoice_adjustment() :: dmsl_domain_thrift:'InvoiceAdjustment'().
-type invoice_adjustment_params() :: dmsl_payproc_thrift:'InvoiceAdjustmentParams'().
-type payment_params() :: dmsl_payproc_thrift:'InvoicePaymentParams'().
-type register_payment_params() :: dmsl_payproc_thrift:'RegisterInvoicePaymentParams'().
@ -157,18 +151,6 @@ repair_scenario(InvoiceID, Scenario, Client) ->
get_limit_values(InvoiceID, PaymentID, Client) ->
map_result_error(gen_server:call(Client, {call, 'GetPaymentRoutesLimitValues', [InvoiceID, PaymentID]})).
-spec create_invoice_adjustment(invoice_id(), invoice_adjustment_params(), pid()) ->
invoice_adjustment() | woody_error:business_error().
create_invoice_adjustment(InvoiceID, Params, Client) ->
Args = [InvoiceID, Params],
map_result_error(gen_server:call(Client, {call, 'CreateInvoiceAdjustment', Args})).
-spec get_invoice_adjustment(invoice_id(), invoice_adjustment_params(), pid()) ->
invoice_adjustment() | woody_error:business_error().
get_invoice_adjustment(InvoiceID, ID, Client) ->
Args = [InvoiceID, ID],
map_result_error(gen_server:call(Client, {call, 'GetInvoiceAdjustment', Args})).
-spec start_payment(invoice_id(), payment_params(), pid()) -> payment_st() | woody_error:business_error().
start_payment(InvoiceID, PaymentParams, Client) ->
map_result_error(gen_server:call(Client, {call, 'StartPayment', [InvoiceID, PaymentParams]})).

View File

@ -17,7 +17,7 @@
{<<"cowlib">>,{pkg,<<"cowlib">>,<<"2.11.0">>},2},
{<<"damsel">>,
{git,"https://github.com/valitydev/damsel.git",
{ref,"bfedcb9dbb0bfdbd7a06a86417b49be6e807b98d"}},
{ref,"c32f50f875bd1c58957e507420a23f7d2fac3ecb"}},
0},
{<<"dmt_client">>,
{git,"https://github.com/valitydev/dmt-client.git",
@ -45,7 +45,7 @@
{<<"jsx">>,{pkg,<<"jsx">>,<<"3.1.0">>},1},
{<<"limiter_proto">>,
{git,"https://github.com/valitydev/limiter-proto.git",
{ref,"bbd2c0dce044dd5b4e424fc8e38a0023a1685a22"}},
{ref,"e045813d32e67432e5592d582e59e45df05da647"}},
0},
{<<"metrics">>,{pkg,<<"metrics">>,<<"1.0.1">>},2},
{<<"mg_proto">>,