diff --git a/apps/hellgate/src/hg_cashflow.erl b/apps/hellgate/src/hg_cashflow.erl index 3cbfd39b..1e5c0fd9 100644 --- a/apps/hellgate/src/hg_cashflow.erl +++ b/apps/hellgate/src/hg_cashflow.erl @@ -32,8 +32,9 @@ -type shop_config_ref() :: dmsl_domain_thrift:'ShopConfigRef'(). -type party_config_ref() :: dmsl_domain_thrift:'PartyConfigRef'(). -type route() :: hg_route:payment_route(). +-type exchange_context() :: hg_invoice_payment:exchange_context(). -type options() :: #{ - exchange_context => hg_invoice_payment:exchange_context() + exchange_context => exchange_context() }. %% @@ -43,6 +44,7 @@ -export([revert/1]). -export([compute_volume/2]). +-export([compute_volume/3]). -export([get_partial_remainders/1]). @@ -85,7 +87,7 @@ compute_postings(CF, Context, AccountMap, Opts) -> ?final_posting( construct_final_account(Source, AccountMap), construct_final_account(Destination, AccountMap), - hg_currency_converter:maybe_reverse_convert_cash(ExchangeContext, compute_volume(Volume, Context)), + compute_volume(Volume, Context, ExchangeContext), Details, ExchangeContext ) @@ -172,14 +174,20 @@ revert_details(Details) -> -define(rational(P, Q), #base_Rational{p = P, q = Q}). -spec compute_volume(cash_volume(), context()) -> cash() | no_return(). -compute_volume(?fixed(Cash), _Context) -> - Cash; -compute_volume(?share(P, Q, Of, RoundingMethod), Context) -> +compute_volume(Volume, Context) -> + compute_volume(Volume, Context, undefined). + +-spec compute_volume(cash_volume(), context(), exchange_context() | undefined) -> cash() | no_return(). +compute_volume(?fixed(Cash), _Context, ExchangeContext) -> + %% if posting currency differs from payment currency + %% needs re-convert it into payment currency + hg_currency_converter:maybe_reverse_convert_cash(ExchangeContext, Cash); +compute_volume(?share(P, Q, Of, RoundingMethod), Context, _ExchangeContext) -> compute_parts_of(P, Q, resolve_constant(Of, Context), RoundingMethod); -compute_volume(?product(Fun, CVs) = CV0, Context) -> +compute_volume(?product(Fun, CVs) = CV0, Context, ExchangeContext) -> case ordsets:size(CVs) of N when N > 0 -> - compute_product(Fun, ordsets:to_list(CVs), CV0, Context); + compute_product(Fun, ordsets:to_list(CVs), CV0, Context, ExchangeContext); 0 -> error({misconfiguration, {'Cash volume product over empty set', CV0}}) end. @@ -195,15 +203,22 @@ compute_parts_of(P, Q, #domain_Cash{amount = Amount} = Cash, RoundingMethod) -> ) }. -compute_product(Fun, [CV | CVRest], CV0, Context) -> +compute_product(Fun, [CV | CVRest], CV0, Context, ExchangeContext) -> lists:foldl( - fun(CVN, CVMin) -> compute_product(Fun, CVN, CVMin, CV0, Context) end, - compute_volume(CV, Context), + fun(CVN, CVMin) -> compute_product(Fun, CVN, CVMin, CV0, Context, ExchangeContext) end, + compute_volume(CV, Context, ExchangeContext), CVRest ). -compute_product(Fun, CV, #domain_Cash{amount = AmountMin, currency = Currency} = CVMin, CV0, Context) -> - case compute_volume(CV, Context) of +compute_product( + Fun, + CV, + #domain_Cash{amount = AmountMin, currency = Currency} = CVMin, + CV0, + Context, + ExchangeContext +) -> + case compute_volume(CV, Context, ExchangeContext) of #domain_Cash{amount = Amount, currency = Currency} -> CVMin#domain_Cash{amount = compute_product_fun(Fun, AmountMin, Amount)}; _ -> @@ -273,22 +288,22 @@ modify_remainder(#domain_FinalCashFlowAccount{account_type = AccountType}, ?cash compute_volume_test() -> Cash = ?cash(100, <<"RUB">>), - ?assertEqual(Cash, compute_volume(?fixed(Cash), #{})), + ?assertEqual(Cash, compute_volume(?fixed(Cash), #{}, undefined)), ?assertEqual( ?cash(1, <<"RUB">>), - compute_volume(?share(1, 100, operation_amount, undefined), #{operation_amount => Cash}) + compute_volume(?share(1, 100, operation_amount, undefined), #{operation_amount => Cash}, undefined) ), ?assertEqual( Cash, - compute_volume(?product(min_of, [?fixed(Cash), ?fixed(?cash(200, <<"RUB">>))]), #{}) + compute_volume(?product(min_of, [?fixed(Cash), ?fixed(?cash(200, <<"RUB">>))]), #{}, undefined) ), ?assertEqual( Cash, - compute_volume(?product(max_of, [?fixed(Cash), ?fixed(?cash(50, <<"RUB">>))]), #{}) + compute_volume(?product(max_of, [?fixed(Cash), ?fixed(?cash(50, <<"RUB">>))]), #{}, undefined) ), ?assertEqual( ?cash(200, <<"RUB">>), - compute_volume(?product(sum_of, [?fixed(Cash), ?fixed(Cash)]), #{}) + compute_volume(?product(sum_of, [?fixed(Cash), ?fixed(Cash)]), #{}, undefined) ). -endif. diff --git a/apps/hellgate/src/hg_invoice_payment_chargeback.erl b/apps/hellgate/src/hg_invoice_payment_chargeback.erl index 4fa7f5da..4de8b1cd 100644 --- a/apps/hellgate/src/hg_invoice_payment_chargeback.erl +++ b/apps/hellgate/src/hg_invoice_payment_chargeback.erl @@ -449,7 +449,7 @@ build_chargeback_final_cash_flow(State, Opts) -> }, AccountMap = hg_accounting:collect_account_map(CollectAccountContext), ServiceContext = build_service_cash_flow_context(State), - ProviderContext = build_provider_cash_flow_context(State, ProviderFees), + ProviderContext = build_provider_cash_flow_context(State, ProviderFees, ExchangeContext), ServiceFinalCF = hg_cashflow:finalize(ServiceCashFlow, ServiceContext, AccountMap), ProviderFinalCF = hg_cashflow:finalize(ProviderCashFlow, ProviderContext, AccountMap, ProviderOpts), ServiceFinalCF ++ ProviderFinalCF. @@ -457,9 +457,9 @@ build_chargeback_final_cash_flow(State, Opts) -> build_service_cash_flow_context(State) -> #{operation_amount => get_body(State), surplus => get_levy(State)}. -build_provider_cash_flow_context(State, Fees) -> +build_provider_cash_flow_context(State, Fees, ExchangeContext) -> FeesContext = #{operation_amount => get_body(State)}, - ComputedFees = maps:map(fun(_K, V) -> hg_cashflow:compute_volume(V, FeesContext) end, Fees), + ComputedFees = maps:map(fun(_K, V) -> hg_cashflow:compute_volume(V, FeesContext, ExchangeContext) end, Fees), case get_target_status(State) of ?chargeback_status_rejected() -> ?cash(_Amount, SymCode) = get_body(State), diff --git a/apps/hellgate/test/hg_invoice_dummy_data.erl b/apps/hellgate/test/hg_invoice_dummy_data.erl index 60bc1120..fd71f7f1 100644 --- a/apps/hellgate/test/hg_invoice_dummy_data.erl +++ b/apps/hellgate/test/hg_invoice_dummy_data.erl @@ -242,7 +242,12 @@ payment_provision_terms(Currency, Category) -> ?cfpost( {system, settlement}, {provider, settlement}, - ?fixed(10, Currency) + {product, + {min_of, + ?ordset([ + ?share(60, 1000, operation_amount), + ?fixed(10, Currency) + ])}} ) ] },