diff --git a/apps/hellgate/include/hg_invoice_payment.hrl b/apps/hellgate/include/hg_invoice_payment.hrl index 4853121c..dd9347f9 100644 --- a/apps/hellgate/include/hg_invoice_payment.hrl +++ b/apps/hellgate/include/hg_invoice_payment.hrl @@ -3,6 +3,7 @@ -record(st, { activity :: hg_invoice_payment:activity(), + status_log = [] :: [dmsl_domain_thrift:'InvoicePaymentStatus'()], payment :: undefined | hg_invoice_payment:payment(), risk_score :: undefined | hg_inspector:risk_score(), routes = [] :: [hg_route:payment_route()], diff --git a/apps/hellgate/src/hg_invoice_payment.erl b/apps/hellgate/src/hg_invoice_payment.erl index f535e617..1457d0dc 100644 --- a/apps/hellgate/src/hg_invoice_payment.erl +++ b/apps/hellgate/src/hg_invoice_payment.erl @@ -2218,8 +2218,18 @@ process_chargeback(Type = finalising_accounter, ID, Action0, St) -> process_chargeback(Type, ID, Action0, St) -> ChargebackState = get_chargeback_state(ID, St), ChargebackOpts = get_chargeback_opts(St), - {Changes, Action1} = hg_invoice_payment_chargeback:process_timeout(Type, ChargebackState, Action0, ChargebackOpts), - {done, {[?chargeback_ev(ID, C) || C <- Changes], Action1}}. + {Changes0, Action1} = hg_invoice_payment_chargeback:process_timeout(Type, ChargebackState, Action0, ChargebackOpts), + Changes1 = [?chargeback_ev(ID, C) || C <- Changes0], + case Type of + %% NOTE In case if payment is already charged back and we want + %% to reopen and change it, this will ensure machine to + %% continue processing activities following cashflow update + %% event. + updating_cash_flow -> + {next, {Changes1, Action1}}; + _ -> + {done, {Changes1, Action1}} + end. maybe_set_charged_back_status(?chargeback_status_accepted(), ChargebackBody, St) -> InterimPaymentAmount = get_remaining_payment_balance(St), @@ -2229,6 +2239,15 @@ maybe_set_charged_back_status(?chargeback_status_accepted(), ChargebackBody, St) ?cash(Amount, _) when Amount > 0 -> [] end; +maybe_set_charged_back_status( + ?chargeback_status_cancelled(), + _ChargebackBody, + #st{ + payment = #domain_InvoicePayment{status = ?charged_back()}, + status_log = [_ActualStatus, PrevStatus | _] + } +) -> + [?payment_status_changed(PrevStatus)]; maybe_set_charged_back_status(_ChargebackStatus, _ChargebackBody, _St) -> []. @@ -3262,7 +3281,7 @@ merge_change(Change = ?payment_status_changed({failed, _} = Status), #st{payment St, Opts ), - St#st{ + (record_status_change(Change, St))#st{ payment = Payment#domain_InvoicePayment{status = Status}, activity = idle, failure = undefined, @@ -3270,14 +3289,14 @@ merge_change(Change = ?payment_status_changed({failed, _} = Status), #st{payment }; merge_change(Change = ?payment_status_changed({cancelled, _} = Status), #st{payment = Payment} = St, Opts) -> _ = validate_transition({payment, finalizing_accounter}, Change, St, Opts), - St#st{ + (record_status_change(Change, St))#st{ payment = Payment#domain_InvoicePayment{status = Status}, activity = idle, timings = accrue_status_timing(cancelled, Opts, St) }; merge_change(Change = ?payment_status_changed({captured, Captured} = Status), #st{payment = Payment} = St, Opts) -> - _ = validate_transition({payment, finalizing_accounter}, Change, St, Opts), - St#st{ + _ = validate_transition([idle, {payment, finalizing_accounter}], Change, St, Opts), + (record_status_change(Change, St))#st{ payment = Payment#domain_InvoicePayment{ status = Status, cost = get_captured_cost(Captured, Payment) @@ -3288,19 +3307,19 @@ merge_change(Change = ?payment_status_changed({captured, Captured} = Status), #s }; merge_change(Change = ?payment_status_changed({processed, _} = Status), #st{payment = Payment} = St, Opts) -> _ = validate_transition({payment, processing_accounter}, Change, St, Opts), - St#st{ + (record_status_change(Change, St))#st{ payment = Payment#domain_InvoicePayment{status = Status}, activity = {payment, flow_waiting}, timings = accrue_status_timing(processed, Opts, St) }; merge_change(Change = ?payment_status_changed({refunded, _} = Status), #st{payment = Payment} = St, Opts) -> _ = validate_transition(idle, Change, St, Opts), - St#st{ + (record_status_change(Change, St))#st{ payment = Payment#domain_InvoicePayment{status = Status} }; merge_change(Change = ?payment_status_changed({charged_back, _} = Status), #st{payment = Payment} = St, Opts) -> _ = validate_transition(idle, Change, St, Opts), - St#st{ + (record_status_change(Change, St))#st{ payment = Payment#domain_InvoicePayment{status = Status} }; merge_change(Change = ?chargeback_ev(ID, Event), St, Opts) -> @@ -3467,6 +3486,9 @@ merge_change(Change = ?session_ev(Target, Event), St = #st{activity = Activity}, St2 end. +record_status_change(?payment_status_changed(Status), St) -> + St#st{status_log = [Status | St#st.status_log]}. + latest_adjustment_id(#st{adjustments = []}) -> undefined; latest_adjustment_id(#st{adjustments = Adjustments}) -> diff --git a/apps/hellgate/test/hg_invoice_tests_SUITE.erl b/apps/hellgate/test/hg_invoice_tests_SUITE.erl index 5680bf4b..db5ffbc0 100644 --- a/apps/hellgate/test/hg_invoice_tests_SUITE.erl +++ b/apps/hellgate/test/hg_invoice_tests_SUITE.erl @@ -128,6 +128,7 @@ -export([accept_payment_chargeback_twice/1]). -export([accept_payment_chargeback_new_body/1]). -export([accept_payment_chargeback_new_levy/1]). +-export([reopen_accepted_payment_chargeback_and_cancel_ok/1]). -export([reopen_payment_chargeback_inconsistent/1]). -export([reopen_payment_chargeback_exceeded/1]). -export([reopen_payment_chargeback_cancel/1]). @@ -388,6 +389,7 @@ groups() -> accept_payment_chargeback_twice, accept_payment_chargeback_new_body, accept_payment_chargeback_new_levy, + reopen_accepted_payment_chargeback_and_cancel_ok, reopen_payment_chargeback_inconsistent, reopen_payment_chargeback_exceeded, reopen_payment_chargeback_cancel, @@ -4062,6 +4064,44 @@ accept_payment_chargeback_new_levy(C) -> ?assertEqual(Paid - Cost - NewLevyAmount, maps:get(min_available_amount, Settlement1)), ?assertEqual(Paid - Cost - NewLevyAmount, maps:get(max_available_amount, Settlement1)). +-spec reopen_accepted_payment_chargeback_and_cancel_ok(config()) -> _ | no_return(). +reopen_accepted_payment_chargeback_and_cancel_ok(C) -> + Client = cfg(client, C), + Cost = 42000, + LevyAmount = 5000, + Levy = ?cash(LevyAmount, <<"RUB">>), + CBParams = make_chargeback_params(Levy), + {IID, PID, _SID, CB} = start_chargeback(C, Cost, CBParams, make_payment_params(?pmt_sys(<<"visa-ref">>))), + CBID = CB#domain_InvoicePaymentChargeback.id, + [ + ?payment_ev(PID, ?chargeback_ev(CBID, ?chargeback_created(CB))), + ?payment_ev(PID, ?chargeback_ev(CBID, ?chargeback_cash_flow_changed(CBCF))) + ] = next_changes(IID, 2, Client), + AcceptParams = make_chargeback_accept_params(), + ok = hg_client_invoicing:accept_chargeback(IID, PID, CBID, AcceptParams, Client), + [ + ?payment_ev(PID, ?chargeback_ev(CBID, ?chargeback_target_status_changed(?chargeback_status_accepted()))), + ?payment_ev(PID, ?chargeback_ev(CBID, ?chargeback_status_changed(?chargeback_status_accepted()))), + ?payment_ev(PID, ?payment_status_changed(?charged_back())) + ] = next_changes(IID, 3, Client), + ReopenParams = make_chargeback_reopen_params(Levy), + ok = hg_client_invoicing:reopen_chargeback(IID, PID, CBID, ReopenParams, Client), + [ + ?payment_ev(PID, ?chargeback_ev(CBID, ?chargeback_stage_changed(?chargeback_stage_pre_arbitration()))), + ?payment_ev(PID, ?chargeback_ev(CBID, ?chargeback_target_status_changed(?chargeback_status_pending()))), + ?payment_ev(PID, ?chargeback_ev(CBID, ?chargeback_cash_flow_changed(CBCF))), + ?payment_ev(PID, ?chargeback_ev(CBID, ?chargeback_status_changed(?chargeback_status_pending()))) + ] = next_changes(IID, 4, Client), + CancelParams = make_chargeback_cancel_params(), + ok = hg_client_invoicing:cancel_chargeback(IID, PID, CBID, CancelParams, Client), + [ + ?payment_ev(PID, ?chargeback_ev(CBID, ?chargeback_target_status_changed(?chargeback_status_cancelled()))), + ?payment_ev(PID, ?chargeback_ev(CBID, ?chargeback_cash_flow_changed([]))), + ?payment_ev(PID, ?chargeback_ev(CBID, ?chargeback_status_changed(?chargeback_status_cancelled()))), + ?payment_ev(PID, ?payment_status_changed(?captured())) + ] = next_changes(IID, 4, Client), + ok. + -spec reopen_payment_chargeback_inconsistent(config()) -> _ | no_return(). reopen_payment_chargeback_inconsistent(C) -> Client = cfg(client, C),