From d069ee9c440b11190c2b22c33f6a0cb8544f4b49 Mon Sep 17 00:00:00 2001 From: Andrew Mayorov Date: Tue, 3 Apr 2018 20:09:12 +0300 Subject: [PATCH] Make adjustments respect possibly updated merchant terms (#199) --- apps/hellgate/src/hg_datetime.erl | 2 + apps/hellgate/src/hg_invoice.erl | 28 ++++++++----- apps/hellgate/src/hg_invoice_payment.erl | 8 ++-- apps/hellgate/test/hg_ct_helper.erl | 33 +++++++++++---- apps/hellgate/test/hg_invoice_tests_SUITE.erl | 42 ++++++++++++++++++- 5 files changed, 89 insertions(+), 24 deletions(-) diff --git a/apps/hellgate/src/hg_datetime.erl b/apps/hellgate/src/hg_datetime.erl index 153adf9..aa11f89 100644 --- a/apps/hellgate/src/hg_datetime.erl +++ b/apps/hellgate/src/hg_datetime.erl @@ -21,6 +21,8 @@ -type timestamp_interval_bound() :: dmsl_base_thrift:'TimestampIntervalBound'(). -type time_span() :: dmsl_base_thrift:'TimeSpan'(). +-export_type([timestamp/0]). + %% -spec format_dt(datetime()) -> timestamp(). diff --git a/apps/hellgate/src/hg_invoice.erl b/apps/hellgate/src/hg_invoice.erl index 531e721..b8c8117 100644 --- a/apps/hellgate/src/hg_invoice.erl +++ b/apps/hellgate/src/hg_invoice.erl @@ -86,9 +86,16 @@ get_payment_tags(PaymentSession) -> -spec get_payment_opts(st()) -> hg_invoice_payment:opts(). -get_payment_opts(St = #st{invoice = Invoice}) -> +get_payment_opts(St) -> + get_payment_opts(get_created_at(St), St). + +-spec get_payment_opts(hg_datetime:timestamp(), st()) -> + hg_invoice_payment:opts(). + +get_payment_opts(Timestamp, St = #st{invoice = Invoice}) -> #{ - party => checkout_party(St), + % TODO repalce with checkout by revision + party => hg_party_machine:checkout(get_party_id(St), {timestamp, Timestamp}), invoice => Invoice }. @@ -515,27 +522,33 @@ handle_call({refund_payment, PaymentID, Params}, St) -> handle_call({create_payment_adjustment, PaymentID, Params}, St) -> _ = assert_invoice_accessible(St), PaymentSession = get_payment_session(PaymentID, St), + Timestamp = hg_datetime:format_now(), + PaymentOpts = get_payment_opts(Timestamp, St), wrap_payment_impact( PaymentID, - hg_invoice_payment:create_adjustment(Params, PaymentSession, get_payment_opts(St)), + hg_invoice_payment:create_adjustment(Timestamp, Params, PaymentSession, PaymentOpts), St ); handle_call({capture_payment_adjustment, PaymentID, ID}, St) -> _ = assert_invoice_accessible(St), PaymentSession = get_payment_session(PaymentID, St), + Adjustment = hg_invoice_payment:get_adjustment(ID, PaymentSession), + PaymentOpts = get_payment_opts(Adjustment#domain_InvoicePaymentAdjustment.created_at, St), wrap_payment_impact( PaymentID, - hg_invoice_payment:capture_adjustment(ID, PaymentSession, get_payment_opts(St)), + hg_invoice_payment:capture_adjustment(ID, PaymentSession, PaymentOpts), St ); handle_call({cancel_payment_adjustment, PaymentID, ID}, St) -> _ = assert_invoice_accessible(St), PaymentSession = get_payment_session(PaymentID, St), + Adjustment = hg_invoice_payment:get_adjustment(ID, PaymentSession), + PaymentOpts = get_payment_opts(Adjustment#domain_InvoicePaymentAdjustment.created_at, St), wrap_payment_impact( PaymentID, - hg_invoice_payment:cancel_adjustment(ID, PaymentSession, get_payment_opts(St)), + hg_invoice_payment:cancel_adjustment(ID, PaymentSession, PaymentOpts), St ); @@ -648,11 +661,6 @@ wrap_payment_impact(PaymentID, {Response, {Changes, Action}}, St) -> state => St }. -checkout_party(St = #st{invoice = #domain_Invoice{created_at = CreationTimestamp}}) -> - PartyID = get_party_id(St), - % TODO repalce with checkout by revision - hg_party_machine:checkout(PartyID, {timestamp, CreationTimestamp}). - handle_result(#{state := St} = Params) -> _ = log_changes(maps:get(changes, Params, []), St), Result = handle_result_changes(Params, handle_result_action(Params, #{})), diff --git a/apps/hellgate/src/hg_invoice_payment.erl b/apps/hellgate/src/hg_invoice_payment.erl index 61945fb..7b3c053 100644 --- a/apps/hellgate/src/hg_invoice_payment.erl +++ b/apps/hellgate/src/hg_invoice_payment.erl @@ -48,7 +48,7 @@ -export([cancel/2]). -export([refund/3]). --export([create_adjustment/3]). +-export([create_adjustment/4]). -export([capture_adjustment/3]). -export([cancel_adjustment/3]). @@ -863,10 +863,10 @@ get_refund_cashflow_plan(RefundSt) -> %% --spec create_adjustment(adjustment_params(), st(), opts()) -> +-spec create_adjustment(hg_datetime:timestamp(), adjustment_params(), st(), opts()) -> {adjustment(), result()}. -create_adjustment(Params, St, Opts) -> +create_adjustment(Timestamp, Params, St, Opts) -> Payment = get_payment(St), Revision = get_adjustment_revision(Params), _ = assert_payment_status(captured, Payment), @@ -884,7 +884,7 @@ create_adjustment(Params, St, Opts) -> Adjustment = #domain_InvoicePaymentAdjustment{ id = ID, status = ?adjustment_pending(), - created_at = hg_datetime:format_now(), + created_at = Timestamp, domain_revision = Revision, reason = Params#payproc_InvoicePaymentAdjustmentParams.reason, old_cash_flow_inverse = hg_cashflow:revert(get_cashflow(St)), diff --git a/apps/hellgate/test/hg_ct_helper.erl b/apps/hellgate/test/hg_ct_helper.erl index c2c5d6d..d742261 100644 --- a/apps/hellgate/test/hg_ct_helper.erl +++ b/apps/hellgate/test/hg_ct_helper.erl @@ -15,6 +15,7 @@ -export([get_first_contract_id/1]). -export([get_first_battle_ready_contract_id/1]). -export([get_first_payout_tool_id/2]). +-export([adjust_contract/3]). -export([make_battle_ready_contract_params/2]). -export([make_battle_ready_payout_tool_params/0]). @@ -291,14 +292,7 @@ create_battle_ready_shop(Category, Currency, TemplateRef, PaymentInstitutionRef, ?shop_modification(ShopID, {creation, ShopParams}), ?shop_modification(ShopID, {shop_account_creation, ShopAccountParams}) ], - #payproc_Claim{id = ClaimID, revision = ClaimRevision, status = Status} = - hg_client_party:create_claim(Changeset, Client), - case Status of - {accepted, _} -> - ok; - _ -> - ok = hg_client_party:accept_claim(ClaimID, ClaimRevision, Client) - end, + ok = ensure_claim_accepted(hg_client_party:create_claim(Changeset, Client), Client), _Shop = hg_client_party:get_shop(ShopID, Client), ShopID. @@ -335,6 +329,29 @@ get_first_battle_ready_contract_id(Client) -> error(not_found) end. +-spec adjust_contract(contract_id(), contract_tpl(), Client :: pid()) -> ok. + +adjust_contract(ContractID, TemplateRef, Client) -> + ensure_claim_accepted(hg_client_party:create_claim([ + {contract_modification, #payproc_ContractModificationUnit{ + id = ContractID, + modification = {adjustment_modification, #payproc_ContractAdjustmentModificationUnit{ + adjustment_id = hg_utils:unique_id(), + modification = {creation, #payproc_ContractAdjustmentParams{ + template = TemplateRef + }} + }} + }} + ], Client), Client). + +ensure_claim_accepted(#payproc_Claim{id = ClaimID, revision = ClaimRevision, status = Status}, Client) -> + case Status of + {accepted, _} -> + ok; + _ -> + ok = hg_client_party:accept_claim(ClaimID, ClaimRevision, Client) + end. + -spec get_account(account_id()) -> account(). get_account(AccountID) -> diff --git a/apps/hellgate/test/hg_invoice_tests_SUITE.erl b/apps/hellgate/test/hg_invoice_tests_SUITE.erl index 338af4c..53d9b40 100644 --- a/apps/hellgate/test/hg_invoice_tests_SUITE.erl +++ b/apps/hellgate/test/hg_invoice_tests_SUITE.erl @@ -737,6 +737,7 @@ payment_adjustment_success(C) -> PaymentID = await_payment_capture(InvoiceID, PaymentID, Client), PrvAccount1 = get_cashflow_account({provider, settlement}, CF1), SysAccount1 = get_cashflow_account({system, settlement}, CF1), + MrcAccount1 = get_cashflow_account({merchant, settlement}, CF1), %% update terminal cashflow ProviderRef = ?prv(100), Provider = hg_domain:get(hg_domain:head(), {provider, ProviderRef}), @@ -753,6 +754,10 @@ payment_adjustment_success(C) -> } }} ), + %% update merchant fees + PartyClient = cfg(party_client, C), + Shop = hg_client_party:get_shop(cfg(shop_id, C), PartyClient), + ok = hg_ct_helper:adjust_contract(Shop#domain_Shop.contract_id, ?tmpl(3), PartyClient), %% make an adjustment Params = make_adjustment_params(Reason = <<"imdrunk">>), ?adjustment(AdjustmentID, ?adjustment_pending()) = Adjustment = @@ -778,8 +783,11 @@ payment_adjustment_success(C) -> #domain_InvoicePaymentAdjustment{new_cash_flow = CF2} = Adjustment, PrvAccount2 = get_cashflow_account({provider, settlement}, CF2), SysAccount2 = get_cashflow_account({system, settlement}, CF2), - 500 = maps:get(own_amount, PrvAccount1) - maps:get(own_amount, PrvAccount2), - -480 = maps:get(own_amount, SysAccount1) - maps:get(own_amount, SysAccount2). + MrcAccount2 = get_cashflow_account({merchant, settlement}, CF2), + 500 = MrcDiff = maps:get(own_amount, MrcAccount2) - maps:get(own_amount, MrcAccount1), + -500 = PrvDiff = maps:get(own_amount, PrvAccount2) - maps:get(own_amount, PrvAccount1), + SysDiff = MrcDiff + PrvDiff - 20, + SysDiff = maps:get(own_amount, SysAccount2) - maps:get(own_amount, SysAccount1). get_cashflow_account(Type, CF) -> [ID] = [V || #domain_FinalCashFlowPosting{ @@ -793,6 +801,27 @@ get_cashflow_account(Type, CF) -> get_adjustment_fixture(Revision) -> PaymentInstitution = hg_domain:get(Revision, {payment_institution, ?pinst(1)}), [ + + {term_set_hierarchy, #domain_TermSetHierarchyObject{ + ref = ?trms(3), + data = #domain_TermSetHierarchy{ + term_sets = [#domain_TimedTermSet{ + action_time = #'TimestampInterval'{}, + terms = #domain_TermSet{ + payments = #domain_PaymentsServiceTerms{ + fees = {value, [ + ?cfpost( + {merchant, settlement}, + {system, settlement}, + ?share(40, 1000, operation_amount) + ) + ]} + } + } + }] + } + }}, + {payment_institution, #domain_PaymentInstitutionObject{ ref = ?pinst(1), data = PaymentInstitution#domain_PaymentInstitution{ @@ -853,6 +882,7 @@ get_adjustment_fixture(Revision) -> risk_coverage = low } }} + ]. get_adjustment_provider_cashflow(initial) -> @@ -1960,6 +1990,7 @@ construct_domain_fixture() -> hg_ct_fixture:construct_contract_template(?tmpl(1), ?trms(1)), hg_ct_fixture:construct_contract_template(?tmpl(2), ?trms(2)), + hg_ct_fixture:construct_contract_template(?tmpl(3), ?trms(3)), hg_ct_fixture:construct_system_account_set(?sas(1)), hg_ct_fixture:construct_system_account_set(?sas(2)), @@ -2100,6 +2131,13 @@ construct_domain_fixture() -> }] } }}, + {term_set_hierarchy, #domain_TermSetHierarchyObject{ + ref = ?trms(3), + data = #domain_TermSetHierarchy{ + parent_terms = ?trms(1), + term_sets = [] + } + }}, {provider, #domain_ProviderObject{ ref = ?prv(1),