mirror of
https://github.com/valitydev/hellgate.git
synced 2024-11-06 02:45:20 +00:00
Merge branch 'master' into epic/kill_adjustments
This commit is contained in:
commit
a755338392
1
.gitignore
vendored
1
.gitignore
vendored
@ -13,3 +13,4 @@ tags
|
|||||||
# make stuff
|
# make stuff
|
||||||
/.image.*
|
/.image.*
|
||||||
Makefile.env
|
Makefile.env
|
||||||
|
*.iml
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
-export([get_balance/1]).
|
-export([get_balance/1]).
|
||||||
-export([create_account/1]).
|
-export([create_account/1]).
|
||||||
-export([create_account/2]).
|
-export([create_account/2]).
|
||||||
-export([collect_account_map/8]).
|
-export([collect_account_map/1]).
|
||||||
-export([collect_merchant_account_map/3]).
|
-export([collect_merchant_account_map/3]).
|
||||||
-export([collect_provider_account_map/4]).
|
-export([collect_provider_account_map/4]).
|
||||||
-export([collect_system_account_map/4]).
|
-export([collect_system_account_map/4]).
|
||||||
@ -45,8 +45,20 @@
|
|||||||
-type varset() :: hg_varset:varset().
|
-type varset() :: hg_varset:varset().
|
||||||
-type revision() :: hg_domain:revision().
|
-type revision() :: hg_domain:revision().
|
||||||
|
|
||||||
|
-type collect_account_context() :: #{
|
||||||
|
payment := payment(),
|
||||||
|
party := party(),
|
||||||
|
shop := shop(),
|
||||||
|
route := route(),
|
||||||
|
payment_institution := payment_institution(),
|
||||||
|
provider := provider(),
|
||||||
|
varset := varset(),
|
||||||
|
revision := revision()
|
||||||
|
}.
|
||||||
|
|
||||||
-export_type([plan_id/0]).
|
-export_type([plan_id/0]).
|
||||||
-export_type([batch/0]).
|
-export_type([batch/0]).
|
||||||
|
-export_type([collect_account_context/0]).
|
||||||
-export_type([posting_plan_log/0]).
|
-export_type([posting_plan_log/0]).
|
||||||
|
|
||||||
-type account() :: #{
|
-type account() :: #{
|
||||||
@ -85,17 +97,17 @@ create_account(CurrencyCode, Description) ->
|
|||||||
error({accounting, Exception})
|
error({accounting, Exception})
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec collect_account_map(
|
-spec collect_account_map(collect_account_context()) -> map().
|
||||||
payment(),
|
collect_account_map(#{
|
||||||
party(),
|
payment := Payment,
|
||||||
shop(),
|
party := Party,
|
||||||
route(),
|
shop := Shop,
|
||||||
payment_institution(),
|
route := Route,
|
||||||
provider(),
|
payment_institution := PaymentInstitution,
|
||||||
varset(),
|
provider := Provider,
|
||||||
revision()
|
varset := VS,
|
||||||
) -> map().
|
revision := Revision
|
||||||
collect_account_map(Payment, Party, Shop, Route, PaymentInstitution, Provider, VS, Revision) ->
|
}) ->
|
||||||
Map0 = collect_merchant_account_map(Party, Shop, #{}),
|
Map0 = collect_merchant_account_map(Party, Shop, #{}),
|
||||||
Map1 = collect_provider_account_map(Payment, Provider, Route, Map0),
|
Map1 = collect_provider_account_map(Payment, Provider, Route, Map0),
|
||||||
Map2 = collect_system_account_map(Payment, PaymentInstitution, Revision, Map1),
|
Map2 = collect_system_account_map(Payment, PaymentInstitution, Revision, Map1),
|
||||||
|
179
apps/hellgate/src/hg_cashflow_utils.erl
Normal file
179
apps/hellgate/src/hg_cashflow_utils.erl
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
-module(hg_cashflow_utils).
|
||||||
|
|
||||||
|
-include_lib("damsel/include/dmsl_base_thrift.hrl").
|
||||||
|
-include_lib("damsel/include/dmsl_payproc_thrift.hrl").
|
||||||
|
|
||||||
|
-include_lib("hellgate/include/allocation.hrl").
|
||||||
|
-include_lib("hellgate/include/domain.hrl").
|
||||||
|
-include("hg_invoice_payment.hrl").
|
||||||
|
|
||||||
|
-type cash_flow_context() :: #{
|
||||||
|
operation := refund | payment,
|
||||||
|
provision_terms := dmsl_domain_thrift:'PaymentsProvisionTerms'(),
|
||||||
|
party := party(),
|
||||||
|
shop := shop(),
|
||||||
|
route := route(),
|
||||||
|
payment := payment(),
|
||||||
|
provider := provider(),
|
||||||
|
timestamp := hg_datetime:timestamp(),
|
||||||
|
varset := hg_varset:varset(),
|
||||||
|
revision := revision(),
|
||||||
|
merchant_terms => dmsl_domain_thrift:'PaymentsServiceTerms'(),
|
||||||
|
refund => refund(),
|
||||||
|
allocation => hg_allocation:allocation()
|
||||||
|
}.
|
||||||
|
|
||||||
|
-export_type([cash_flow_context/0]).
|
||||||
|
|
||||||
|
-export([collect_cashflow/1]).
|
||||||
|
-export([collect_cashflow/2]).
|
||||||
|
|
||||||
|
-type party() :: dmsl_domain_thrift:'Party'().
|
||||||
|
-type shop() :: dmsl_domain_thrift:'Shop'().
|
||||||
|
-type route() :: dmsl_domain_thrift:'PaymentRoute'().
|
||||||
|
-type payment() :: dmsl_domain_thrift:'InvoicePayment'().
|
||||||
|
-type refund() :: dmsl_domain_thrift:'InvoicePaymentRefund'().
|
||||||
|
-type provider() :: dmsl_domain_thrift:'Provider'().
|
||||||
|
-type revision() :: hg_domain:revision().
|
||||||
|
-type payment_institution() :: hg_payment_institution:t().
|
||||||
|
-type final_cash_flow() :: hg_cashflow:final_cash_flow().
|
||||||
|
|
||||||
|
-spec collect_cashflow(cash_flow_context()) -> final_cash_flow().
|
||||||
|
collect_cashflow(#{party := Party, shop := Shop, varset := VS, revision := Revision} = Context) ->
|
||||||
|
PaymentInstitution = get_cashflow_payment_institution(Party, Shop, VS, Revision),
|
||||||
|
collect_cashflow(PaymentInstitution, Context).
|
||||||
|
|
||||||
|
-spec collect_cashflow(payment_institution(), cash_flow_context()) -> final_cash_flow().
|
||||||
|
collect_cashflow(PaymentInstitution, Context) ->
|
||||||
|
CF =
|
||||||
|
case maps:get(allocation, Context, undefined) of
|
||||||
|
undefined ->
|
||||||
|
Amount = get_amount(Context),
|
||||||
|
construct_transaction_cashflow(Amount, PaymentInstitution, Context);
|
||||||
|
?allocation(Transactions) ->
|
||||||
|
collect_allocation_cash_flow(Transactions, Context)
|
||||||
|
end,
|
||||||
|
ProviderCashflow = construct_provider_cashflow(PaymentInstitution, Context),
|
||||||
|
CF ++ ProviderCashflow.
|
||||||
|
|
||||||
|
%% Internal
|
||||||
|
|
||||||
|
collect_allocation_cash_flow(
|
||||||
|
Transactions,
|
||||||
|
Context = #{
|
||||||
|
revision := Revision,
|
||||||
|
party := Party,
|
||||||
|
shop := Shop,
|
||||||
|
varset := VS0
|
||||||
|
}
|
||||||
|
) ->
|
||||||
|
lists:foldl(
|
||||||
|
fun(?allocation_trx(_ID, Target, Amount), Acc) ->
|
||||||
|
?allocation_trx_target_shop(PartyID, ShopID) = Target,
|
||||||
|
TargetParty = hg_party:get_party(PartyID),
|
||||||
|
TargetShop = hg_party:get_shop(ShopID, TargetParty),
|
||||||
|
VS1 = VS0#{
|
||||||
|
party_id => Party#domain_Party.id,
|
||||||
|
shop_id => Shop#domain_Shop.id,
|
||||||
|
cost => Amount
|
||||||
|
},
|
||||||
|
AllocationPaymentInstitution =
|
||||||
|
get_cashflow_payment_institution(Party, Shop, VS1, Revision),
|
||||||
|
construct_transaction_cashflow(
|
||||||
|
Amount,
|
||||||
|
AllocationPaymentInstitution,
|
||||||
|
Context#{party => TargetParty, shop => TargetShop}
|
||||||
|
) ++ Acc
|
||||||
|
end,
|
||||||
|
[],
|
||||||
|
Transactions
|
||||||
|
).
|
||||||
|
|
||||||
|
construct_transaction_cashflow(
|
||||||
|
Amount,
|
||||||
|
PaymentInstitution,
|
||||||
|
Context = #{
|
||||||
|
operation := OpType,
|
||||||
|
party := Party,
|
||||||
|
shop := Shop,
|
||||||
|
varset := VS,
|
||||||
|
revision := Revision,
|
||||||
|
timestamp := Timestamp
|
||||||
|
}
|
||||||
|
) ->
|
||||||
|
MerchantPaymentsTerms1 =
|
||||||
|
case maps:get(merchant_terms, Context, undefined) of
|
||||||
|
undefined ->
|
||||||
|
TermSet = hg_invoice_utils:get_merchant_terms(Party, Shop, Revision, Timestamp, VS),
|
||||||
|
TermSet#domain_TermSet.payments;
|
||||||
|
MerchantPaymentsTerms0 ->
|
||||||
|
MerchantPaymentsTerms0
|
||||||
|
end,
|
||||||
|
MerchantCashflowSelector = get_terms_cashflow(OpType, MerchantPaymentsTerms1),
|
||||||
|
MerchantCashflow = get_selector_value(merchant_payment_fees, MerchantCashflowSelector),
|
||||||
|
AccountMap = hg_accounting:collect_account_map(make_collect_account_context(PaymentInstitution, Context)),
|
||||||
|
construct_final_cashflow(MerchantCashflow, #{operation_amount => Amount}, AccountMap).
|
||||||
|
|
||||||
|
construct_provider_cashflow(PaymentInstitution, Context = #{provision_terms := ProvisionTerms}) ->
|
||||||
|
ProviderCashflowSelector = get_provider_cashflow_selector(ProvisionTerms),
|
||||||
|
ProviderCashflow = get_selector_value(provider_payment_cash_flow, ProviderCashflowSelector),
|
||||||
|
AccountMap = hg_accounting:collect_account_map(make_collect_account_context(PaymentInstitution, Context)),
|
||||||
|
construct_final_cashflow(ProviderCashflow, #{operation_amount => get_amount(Context)}, AccountMap).
|
||||||
|
|
||||||
|
construct_final_cashflow(Cashflow, Context, AccountMap) ->
|
||||||
|
hg_cashflow:finalize(Cashflow, Context, AccountMap).
|
||||||
|
|
||||||
|
get_cashflow_payment_institution(Party, Shop, VS, Revision) ->
|
||||||
|
Contract = hg_party:get_contract(Shop#domain_Shop.contract_id, Party),
|
||||||
|
PaymentInstitutionRef = Contract#domain_Contract.payment_institution,
|
||||||
|
hg_payment_institution:compute_payment_institution(
|
||||||
|
PaymentInstitutionRef,
|
||||||
|
VS,
|
||||||
|
Revision
|
||||||
|
).
|
||||||
|
|
||||||
|
get_amount(#{refund := #domain_InvoicePaymentRefund{cash = Cash}}) ->
|
||||||
|
Cash;
|
||||||
|
get_amount(#{payment := #domain_InvoicePayment{cost = Cost}}) ->
|
||||||
|
Cost.
|
||||||
|
|
||||||
|
get_provider_cashflow_selector(#domain_PaymentsProvisionTerms{cash_flow = ProviderCashflowSelector}) ->
|
||||||
|
ProviderCashflowSelector;
|
||||||
|
get_provider_cashflow_selector(#domain_PaymentRefundsProvisionTerms{cash_flow = ProviderCashflowSelector}) ->
|
||||||
|
ProviderCashflowSelector.
|
||||||
|
|
||||||
|
get_terms_cashflow(payment, MerchantPaymentsTerms) ->
|
||||||
|
MerchantPaymentsTerms#domain_PaymentsServiceTerms.fees;
|
||||||
|
get_terms_cashflow(refund, MerchantPaymentsTerms) ->
|
||||||
|
MerchantRefundTerms = MerchantPaymentsTerms#domain_PaymentsServiceTerms.refunds,
|
||||||
|
MerchantRefundTerms#domain_PaymentRefundsServiceTerms.fees.
|
||||||
|
|
||||||
|
get_selector_value(Name, Selector) ->
|
||||||
|
case Selector of
|
||||||
|
{value, V} ->
|
||||||
|
V;
|
||||||
|
Ambiguous ->
|
||||||
|
error({misconfiguration, {'Could not reduce selector to a value', {Name, Ambiguous}}})
|
||||||
|
end.
|
||||||
|
|
||||||
|
-spec make_collect_account_context(payment_institution(), cash_flow_context()) ->
|
||||||
|
hg_accounting:collect_account_context().
|
||||||
|
make_collect_account_context(PaymentInstitution, #{
|
||||||
|
payment := Payment,
|
||||||
|
party := Party,
|
||||||
|
shop := Shop,
|
||||||
|
route := Route,
|
||||||
|
provider := Provider,
|
||||||
|
varset := VS,
|
||||||
|
revision := Revision
|
||||||
|
}) ->
|
||||||
|
#{
|
||||||
|
payment => Payment,
|
||||||
|
party => Party,
|
||||||
|
shop => Shop,
|
||||||
|
route => Route,
|
||||||
|
payment_institution => PaymentInstitution,
|
||||||
|
provider => Provider,
|
||||||
|
varset => VS,
|
||||||
|
revision => Revision
|
||||||
|
}.
|
@ -147,7 +147,11 @@ handle_function_('Create', {InvoiceParams}, _Opts) ->
|
|||||||
Party = hg_party:get_party(PartyID),
|
Party = hg_party:get_party(PartyID),
|
||||||
Shop = assert_shop_exists(hg_party:get_shop(ShopID, Party)),
|
Shop = assert_shop_exists(hg_party:get_shop(ShopID, Party)),
|
||||||
_ = assert_party_shop_operable(Shop, Party),
|
_ = assert_party_shop_operable(Shop, Party),
|
||||||
MerchantTerms = get_merchant_terms(Party, DomainRevision, Shop, hg_datetime:format_now(), InvoiceParams),
|
VS = #{
|
||||||
|
cost => InvoiceParams#payproc_InvoiceParams.cost,
|
||||||
|
shop_id => Shop#domain_Shop.id
|
||||||
|
},
|
||||||
|
MerchantTerms = hg_invoice_utils:get_merchant_terms(Party, Shop, DomainRevision, hg_datetime:format_now(), VS),
|
||||||
ok = validate_invoice_params(InvoiceParams, Shop, MerchantTerms),
|
ok = validate_invoice_params(InvoiceParams, Shop, MerchantTerms),
|
||||||
AllocationPrototype = InvoiceParams#payproc_InvoiceParams.allocation,
|
AllocationPrototype = InvoiceParams#payproc_InvoiceParams.allocation,
|
||||||
Cost = InvoiceParams#payproc_InvoiceParams.cost,
|
Cost = InvoiceParams#payproc_InvoiceParams.cost,
|
||||||
@ -160,7 +164,11 @@ handle_function_('CreateWithTemplate', {Params}, _Opts) ->
|
|||||||
_ = set_invoicing_meta(InvoiceID),
|
_ = set_invoicing_meta(InvoiceID),
|
||||||
TplID = Params#payproc_InvoiceWithTemplateParams.template_id,
|
TplID = Params#payproc_InvoiceWithTemplateParams.template_id,
|
||||||
{Party, Shop, InvoiceParams} = make_invoice_params(Params),
|
{Party, Shop, InvoiceParams} = make_invoice_params(Params),
|
||||||
MerchantTerms = get_merchant_terms(Party, DomainRevision, Shop, hg_datetime:format_now(), InvoiceParams),
|
VS = #{
|
||||||
|
cost => InvoiceParams#payproc_InvoiceParams.cost,
|
||||||
|
shop_id => Shop#domain_Shop.id
|
||||||
|
},
|
||||||
|
MerchantTerms = hg_invoice_utils:get_merchant_terms(Party, Shop, DomainRevision, hg_datetime:format_now(), VS),
|
||||||
ok = validate_invoice_params(InvoiceParams, Shop, MerchantTerms),
|
ok = validate_invoice_params(InvoiceParams, Shop, MerchantTerms),
|
||||||
AllocationPrototype = InvoiceParams#payproc_InvoiceParams.allocation,
|
AllocationPrototype = InvoiceParams#payproc_InvoiceParams.allocation,
|
||||||
Cost = InvoiceParams#payproc_InvoiceParams.cost,
|
Cost = InvoiceParams#payproc_InvoiceParams.cost,
|
||||||
@ -241,7 +249,11 @@ handle_function_('Repair', {InvoiceID, Changes, Action, Params}, _Opts) ->
|
|||||||
repair(InvoiceID, {changes, Changes, Action, Params});
|
repair(InvoiceID, {changes, Changes, Action, Params});
|
||||||
handle_function_('RepairWithScenario', {InvoiceID, Scenario}, _Opts) ->
|
handle_function_('RepairWithScenario', {InvoiceID, Scenario}, _Opts) ->
|
||||||
_ = set_invoicing_meta(InvoiceID),
|
_ = set_invoicing_meta(InvoiceID),
|
||||||
repair(InvoiceID, {scenario, Scenario}).
|
repair(InvoiceID, {scenario, Scenario});
|
||||||
|
handle_function_('GetPaymentRoutesLimitValues', {InvoiceID, PaymentID}, _Opts) ->
|
||||||
|
_ = set_invoicing_meta(InvoiceID, PaymentID),
|
||||||
|
St = get_state(InvoiceID),
|
||||||
|
hg_invoice_payment:get_limit_values(get_payment_session(PaymentID, St), get_payment_opts(St)).
|
||||||
|
|
||||||
maybe_allocation(undefined, _Cost, _MerchantTerms, _Party, _Shop) ->
|
maybe_allocation(undefined, _Cost, _MerchantTerms, _Party, _Shop) ->
|
||||||
undefined;
|
undefined;
|
||||||
@ -1312,24 +1324,6 @@ validate_invoice_cost(Cost, Shop, #domain_TermSet{payments = PaymentTerms}) ->
|
|||||||
_ = hg_invoice_utils:assert_cost_payable(Cost, PaymentTerms),
|
_ = hg_invoice_utils:assert_cost_payable(Cost, PaymentTerms),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
get_merchant_terms(#domain_Party{id = PartyId, revision = PartyRevision}, Revision, Shop, Timestamp, Params) ->
|
|
||||||
VS = #{
|
|
||||||
cost => Params#payproc_InvoiceParams.cost,
|
|
||||||
shop_id => Shop#domain_Shop.id
|
|
||||||
},
|
|
||||||
{Client, Context} = get_party_client(),
|
|
||||||
{ok, TermSet} = party_client_thrift:compute_contract_terms(
|
|
||||||
PartyId,
|
|
||||||
Shop#domain_Shop.contract_id,
|
|
||||||
Timestamp,
|
|
||||||
{revision, PartyRevision},
|
|
||||||
Revision,
|
|
||||||
hg_varset:prepare_contract_terms_varset(VS),
|
|
||||||
Client,
|
|
||||||
Context
|
|
||||||
),
|
|
||||||
TermSet.
|
|
||||||
|
|
||||||
make_invoice_cart(_, {cart, Cart}, _Shop) ->
|
make_invoice_cart(_, {cart, Cart}, _Shop) ->
|
||||||
Cart;
|
Cart;
|
||||||
make_invoice_cart(Cost, {product, TplProduct}, Shop) ->
|
make_invoice_cart(Cost, {product, TplProduct}, Shop) ->
|
||||||
@ -1397,10 +1391,6 @@ make_invoice_context(Context, _) ->
|
|||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
||||||
get_party_client() ->
|
|
||||||
Ctx = hg_context:load(),
|
|
||||||
{hg_context:get_party_client(Ctx), hg_context:get_party_client_context(Ctx)}.
|
|
||||||
|
|
||||||
log_changes(Changes, St) ->
|
log_changes(Changes, St) ->
|
||||||
lists:foreach(fun(C) -> log_change(C, St) end, Changes).
|
lists:foreach(fun(C) -> log_change(C, St) end, Changes).
|
||||||
|
|
||||||
|
@ -76,13 +76,13 @@
|
|||||||
-export([accept_chargeback/3]).
|
-export([accept_chargeback/3]).
|
||||||
-export([reopen_chargeback/3]).
|
-export([reopen_chargeback/3]).
|
||||||
|
|
||||||
-export([get_merchant_terms/5]).
|
|
||||||
-export([get_provider_terminal_terms/3]).
|
-export([get_provider_terminal_terms/3]).
|
||||||
-export([calculate_cashflow/10]).
|
-export([calculate_cashflow/3]).
|
||||||
|
|
||||||
-export([create_session_event_context/3]).
|
-export([create_session_event_context/3]).
|
||||||
-export([add_session/3]).
|
-export([add_session/3]).
|
||||||
-export([accrue_status_timing/3]).
|
-export([accrue_status_timing/3]).
|
||||||
|
-export([get_limit_values/2]).
|
||||||
|
|
||||||
%% Machine like
|
%% Machine like
|
||||||
|
|
||||||
@ -125,6 +125,7 @@
|
|||||||
-export_type([change/0]).
|
-export_type([change/0]).
|
||||||
-export_type([change_opts/0]).
|
-export_type([change_opts/0]).
|
||||||
-export_type([action/0]).
|
-export_type([action/0]).
|
||||||
|
-export_type([cashflow_context/0]).
|
||||||
|
|
||||||
-type activity() ::
|
-type activity() ::
|
||||||
payment_activity()
|
payment_activity()
|
||||||
@ -205,6 +206,7 @@
|
|||||||
-type recurrent_paytool_service_terms() :: dmsl_domain_thrift:'RecurrentPaytoolsServiceTerms'().
|
-type recurrent_paytool_service_terms() :: dmsl_domain_thrift:'RecurrentPaytoolsServiceTerms'().
|
||||||
-type session() :: hg_session:t().
|
-type session() :: hg_session:t().
|
||||||
-type payment_plan_id() :: hg_accounting:plan_id().
|
-type payment_plan_id() :: hg_accounting:plan_id().
|
||||||
|
-type route_limit_context() :: dmsl_payproc_thrift:'RouteLimitContext'().
|
||||||
|
|
||||||
-type opts() :: #{
|
-type opts() :: #{
|
||||||
party => party(),
|
party => party(),
|
||||||
@ -212,6 +214,17 @@
|
|||||||
timestamp => hg_datetime:timestamp()
|
timestamp => hg_datetime:timestamp()
|
||||||
}.
|
}.
|
||||||
|
|
||||||
|
-type cashflow_context() :: #{
|
||||||
|
provision_terms := dmsl_domain_thrift:'PaymentsProvisionTerms'(),
|
||||||
|
route := route(),
|
||||||
|
payment := payment(),
|
||||||
|
timestamp := hg_datetime:timestamp(),
|
||||||
|
varset := hg_varset:varset(),
|
||||||
|
revision := hg_domain:revision(),
|
||||||
|
merchant_terms => dmsl_domain_thrift:'PaymentsServiceTerms'(),
|
||||||
|
allocation => hg_allocation:allocation()
|
||||||
|
}.
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
||||||
-include("domain.hrl").
|
-include("domain.hrl").
|
||||||
@ -440,29 +453,9 @@ init_(PaymentID, Params, Opts = #{timestamp := CreatedAt}) ->
|
|||||||
get_merchant_payments_terms(Opts, Revision, Timestamp, VS) ->
|
get_merchant_payments_terms(Opts, Revision, Timestamp, VS) ->
|
||||||
Party = get_party(Opts),
|
Party = get_party(Opts),
|
||||||
Shop = get_shop(Opts),
|
Shop = get_shop(Opts),
|
||||||
TermSet = get_merchant_terms(Party, Shop, Revision, Timestamp, VS),
|
TermSet = hg_invoice_utils:get_merchant_terms(Party, Shop, Revision, Timestamp, VS),
|
||||||
TermSet#domain_TermSet.payments.
|
TermSet#domain_TermSet.payments.
|
||||||
|
|
||||||
-spec get_merchant_terms(party(), shop(), hg_domain:revision(), hg_datetime:timestamp(), hg_varset:varset()) ->
|
|
||||||
dmsl_domain_thrift:'TermSet'().
|
|
||||||
get_merchant_terms(Party, Shop, DomainRevision, Timestamp, VS) ->
|
|
||||||
ContractID = Shop#domain_Shop.contract_id,
|
|
||||||
Contract = hg_party:get_contract(ContractID, Party),
|
|
||||||
ok = assert_contract_active(Contract),
|
|
||||||
PreparedVS = hg_varset:prepare_contract_terms_varset(VS),
|
|
||||||
{Client, Context} = get_party_client(),
|
|
||||||
{ok, Terms} = party_client_thrift:compute_contract_terms(
|
|
||||||
Party#domain_Party.id,
|
|
||||||
ContractID,
|
|
||||||
Timestamp,
|
|
||||||
{revision, Party#domain_Party.revision},
|
|
||||||
DomainRevision,
|
|
||||||
PreparedVS,
|
|
||||||
Client,
|
|
||||||
Context
|
|
||||||
),
|
|
||||||
Terms.
|
|
||||||
|
|
||||||
-spec get_provider_terminal_terms(route(), hg_varset:varset(), hg_domain:revision()) ->
|
-spec get_provider_terminal_terms(route(), hg_varset:varset(), hg_domain:revision()) ->
|
||||||
dmsl_domain_thrift:'PaymentsProvisionTerms'() | undefined.
|
dmsl_domain_thrift:'PaymentsProvisionTerms'() | undefined.
|
||||||
get_provider_terminal_terms(?route(ProviderRef, TerminalRef), VS, Revision) ->
|
get_provider_terminal_terms(?route(ProviderRef, TerminalRef), VS, Revision) ->
|
||||||
@ -478,11 +471,6 @@ get_provider_terminal_terms(?route(ProviderRef, TerminalRef), VS, Revision) ->
|
|||||||
),
|
),
|
||||||
TermsSet#domain_ProvisionTermSet.payments.
|
TermsSet#domain_ProvisionTermSet.payments.
|
||||||
|
|
||||||
assert_contract_active(#domain_Contract{status = {active, _}}) ->
|
|
||||||
ok;
|
|
||||||
assert_contract_active(#domain_Contract{status = Status}) ->
|
|
||||||
throw(#payproc_InvalidContractStatus{status = Status}).
|
|
||||||
|
|
||||||
-spec construct_payer(payer_params(), shop()) -> {ok, payer(), map()}.
|
-spec construct_payer(payer_params(), shop()) -> {ok, payer(), map()}.
|
||||||
construct_payer(
|
construct_payer(
|
||||||
{payment_resource, #payproc_PaymentResourcePayerParams{
|
{payment_resource, #payproc_PaymentResourcePayerParams{
|
||||||
@ -564,7 +552,7 @@ construct_payment(
|
|||||||
payment_tool => PaymentTool,
|
payment_tool => PaymentTool,
|
||||||
cost => Cost
|
cost => Cost
|
||||||
},
|
},
|
||||||
Terms = get_merchant_terms(Party, Shop, Revision, CreatedAt, VS1),
|
Terms = hg_invoice_utils:get_merchant_terms(Party, Shop, Revision, CreatedAt, VS1),
|
||||||
#domain_TermSet{payments = PaymentTerms, recurrent_paytools = RecurrentTerms} = Terms,
|
#domain_TermSet{payments = PaymentTerms, recurrent_paytools = RecurrentTerms} = Terms,
|
||||||
ok = validate_payment_tool(
|
ok = validate_payment_tool(
|
||||||
PaymentTool,
|
PaymentTool,
|
||||||
@ -948,22 +936,6 @@ collect_validation_varset(Party, Shop, Payment, VS) ->
|
|||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
||||||
construct_final_cashflow(Cashflow, Context, AccountMap) ->
|
|
||||||
hg_cashflow:finalize(Cashflow, Context, AccountMap).
|
|
||||||
|
|
||||||
collect_cash_flow_context(
|
|
||||||
#domain_InvoicePayment{cost = Cost}
|
|
||||||
) ->
|
|
||||||
#{
|
|
||||||
operation_amount => Cost
|
|
||||||
};
|
|
||||||
collect_cash_flow_context(
|
|
||||||
#domain_InvoicePaymentRefund{cash = Cash}
|
|
||||||
) ->
|
|
||||||
#{
|
|
||||||
operation_amount => Cash
|
|
||||||
}.
|
|
||||||
|
|
||||||
-spec construct_payment_plan_id(st()) -> payment_plan_id().
|
-spec construct_payment_plan_id(st()) -> payment_plan_id().
|
||||||
construct_payment_plan_id(#st{opts = Opts, payment = Payment, routes = Routes}) ->
|
construct_payment_plan_id(#st{opts = Opts, payment = Payment, routes = Routes}) ->
|
||||||
construct_payment_plan_id(get_invoice(Opts), Payment, Routes, normal).
|
construct_payment_plan_id(get_invoice(Opts), Payment, Routes, normal).
|
||||||
@ -1093,8 +1065,17 @@ partial_capture(St0, Reason, Cost, Cart, Opts, MerchantTerms, Timestamp, Allocat
|
|||||||
Route = get_route(St),
|
Route = get_route(St),
|
||||||
ProviderTerms = hg_routing:get_payment_terms(Route, VS, Revision),
|
ProviderTerms = hg_routing:get_payment_terms(Route, VS, Revision),
|
||||||
ok = validate_provider_holds_terms(ProviderTerms),
|
ok = validate_provider_holds_terms(ProviderTerms),
|
||||||
FinalCashflow =
|
Context = #{
|
||||||
calculate_cashflow(Route, Payment2, ProviderTerms, MerchantTerms, VS, Revision, Opts, Timestamp, Allocation),
|
provision_terms => ProviderTerms,
|
||||||
|
merchant_terms => MerchantTerms,
|
||||||
|
route => Route,
|
||||||
|
payment => Payment2,
|
||||||
|
timestamp => Timestamp,
|
||||||
|
varset => VS,
|
||||||
|
revision => Revision,
|
||||||
|
allocation => Allocation
|
||||||
|
},
|
||||||
|
FinalCashflow = calculate_cashflow(Context, Opts),
|
||||||
Changes = start_partial_capture(Reason, Cost, Cart, FinalCashflow, Allocation),
|
Changes = start_partial_capture(Reason, Cost, Cart, FinalCashflow, Allocation),
|
||||||
{ok, {Changes, hg_machine_action:instant()}}.
|
{ok, {Changes, hg_machine_action:instant()}}.
|
||||||
|
|
||||||
@ -1318,27 +1299,24 @@ marshal_allocation_sub_details(no_transaction_to_sub) ->
|
|||||||
|
|
||||||
make_refund_cashflow(Refund, Payment, Revision, St, Opts, MerchantTerms, VS, Timestamp) ->
|
make_refund_cashflow(Refund, Payment, Revision, St, Opts, MerchantTerms, VS, Timestamp) ->
|
||||||
Route = get_route(St),
|
Route = get_route(St),
|
||||||
Party = get_party(Opts),
|
|
||||||
Shop = get_shop(Opts),
|
|
||||||
ProviderPaymentsTerms = get_provider_terminal_terms(Route, VS, Revision),
|
ProviderPaymentsTerms = get_provider_terminal_terms(Route, VS, Revision),
|
||||||
ProviderTerms = get_provider_refunds_terms(ProviderPaymentsTerms, Refund, Payment),
|
|
||||||
Allocation = Refund#domain_InvoicePaymentRefund.allocation,
|
Allocation = Refund#domain_InvoicePaymentRefund.allocation,
|
||||||
Provider = get_route_provider(Route, Revision),
|
CollectCashflowContext = genlib_map:compact(#{
|
||||||
collect_cashflow(
|
operation => refund,
|
||||||
refund,
|
provision_terms => get_provider_refunds_terms(ProviderPaymentsTerms, Refund, Payment),
|
||||||
ProviderTerms,
|
merchant_terms => MerchantTerms,
|
||||||
MerchantTerms,
|
party => get_party(Opts),
|
||||||
Party,
|
shop => get_shop(Opts),
|
||||||
Shop,
|
route => Route,
|
||||||
Route,
|
payment => Payment,
|
||||||
Allocation,
|
provider => get_route_provider(Route, Revision),
|
||||||
Payment,
|
timestamp => Timestamp,
|
||||||
Refund,
|
varset => VS,
|
||||||
Provider,
|
revision => Revision,
|
||||||
Timestamp,
|
refund => Refund,
|
||||||
VS,
|
allocation => Allocation
|
||||||
Revision
|
}),
|
||||||
).
|
hg_cashflow_utils:collect_cashflow(CollectCashflowContext).
|
||||||
|
|
||||||
assert_refund_cash(Cash, St) ->
|
assert_refund_cash(Cash, St) ->
|
||||||
PaymentAmount = get_remaining_payment_amount(Cash, St),
|
PaymentAmount = get_remaining_payment_amount(Cash, St),
|
||||||
@ -1491,235 +1469,6 @@ validate_common_refund_terms(Terms, Refund, Payment) ->
|
|||||||
),
|
),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
collect_cashflow(
|
|
||||||
OpType,
|
|
||||||
ProvisionTerms,
|
|
||||||
MerchantTerms,
|
|
||||||
Party,
|
|
||||||
Shop,
|
|
||||||
Route,
|
|
||||||
Allocation,
|
|
||||||
Payment,
|
|
||||||
ContextSource,
|
|
||||||
Provider,
|
|
||||||
Timestamp,
|
|
||||||
VS,
|
|
||||||
Revision
|
|
||||||
) ->
|
|
||||||
PaymentInstitution = get_cashflow_payment_institution(Party, Shop, VS, Revision),
|
|
||||||
collect_cashflow(
|
|
||||||
OpType,
|
|
||||||
ProvisionTerms,
|
|
||||||
MerchantTerms,
|
|
||||||
Party,
|
|
||||||
Shop,
|
|
||||||
PaymentInstitution,
|
|
||||||
Route,
|
|
||||||
Allocation,
|
|
||||||
Payment,
|
|
||||||
ContextSource,
|
|
||||||
Provider,
|
|
||||||
Timestamp,
|
|
||||||
VS,
|
|
||||||
Revision
|
|
||||||
).
|
|
||||||
|
|
||||||
collect_cashflow(
|
|
||||||
OpType,
|
|
||||||
ProvisionTerms,
|
|
||||||
MerchantTerms,
|
|
||||||
Party,
|
|
||||||
Shop,
|
|
||||||
PaymentInstitution,
|
|
||||||
Route,
|
|
||||||
undefined,
|
|
||||||
Payment,
|
|
||||||
ContextSource,
|
|
||||||
Provider,
|
|
||||||
Timestamp,
|
|
||||||
VS,
|
|
||||||
Revision
|
|
||||||
) ->
|
|
||||||
Amount = get_context_source_amount(ContextSource),
|
|
||||||
CF = construct_transaction_cashflow(
|
|
||||||
OpType,
|
|
||||||
Party,
|
|
||||||
Shop,
|
|
||||||
PaymentInstitution,
|
|
||||||
Route,
|
|
||||||
Amount,
|
|
||||||
MerchantTerms,
|
|
||||||
Timestamp,
|
|
||||||
Payment,
|
|
||||||
Provider,
|
|
||||||
VS,
|
|
||||||
Revision
|
|
||||||
),
|
|
||||||
ProviderCashflowSelector = get_provider_cashflow_selector(ProvisionTerms),
|
|
||||||
ProviderCashflow = construct_provider_cashflow(
|
|
||||||
ProviderCashflowSelector,
|
|
||||||
PaymentInstitution,
|
|
||||||
Party,
|
|
||||||
Shop,
|
|
||||||
Route,
|
|
||||||
ContextSource,
|
|
||||||
Payment,
|
|
||||||
Provider,
|
|
||||||
VS,
|
|
||||||
Revision
|
|
||||||
),
|
|
||||||
CF ++ ProviderCashflow;
|
|
||||||
collect_cashflow(
|
|
||||||
OpType,
|
|
||||||
ProvisionTerms,
|
|
||||||
_MerchantTerms,
|
|
||||||
Party,
|
|
||||||
Shop,
|
|
||||||
PaymentInstitution,
|
|
||||||
Route,
|
|
||||||
?allocation(Transactions),
|
|
||||||
Payment,
|
|
||||||
ContextSource,
|
|
||||||
Provider,
|
|
||||||
Timestamp,
|
|
||||||
VS0,
|
|
||||||
Revision
|
|
||||||
) ->
|
|
||||||
CF = lists:foldl(
|
|
||||||
fun(?allocation_trx(_ID, Target, Amount), Acc) ->
|
|
||||||
?allocation_trx_target_shop(PartyID, ShopID) = Target,
|
|
||||||
TargetParty = hg_party:get_party(PartyID),
|
|
||||||
TargetShop = hg_party:get_shop(ShopID, TargetParty),
|
|
||||||
VS1 = VS0#{
|
|
||||||
party_id => Party#domain_Party.id,
|
|
||||||
shop_id => Shop#domain_Shop.id,
|
|
||||||
cost => Amount
|
|
||||||
},
|
|
||||||
AllocationPaymentInstitution =
|
|
||||||
get_cashflow_payment_institution(Party, Shop, VS1, Revision),
|
|
||||||
construct_transaction_cashflow(
|
|
||||||
OpType,
|
|
||||||
TargetParty,
|
|
||||||
TargetShop,
|
|
||||||
AllocationPaymentInstitution,
|
|
||||||
Route,
|
|
||||||
Amount,
|
|
||||||
undefined,
|
|
||||||
Timestamp,
|
|
||||||
Payment,
|
|
||||||
Provider,
|
|
||||||
VS1,
|
|
||||||
Revision
|
|
||||||
) ++ Acc
|
|
||||||
end,
|
|
||||||
[],
|
|
||||||
Transactions
|
|
||||||
),
|
|
||||||
ProviderCashflowSelector = get_provider_cashflow_selector(ProvisionTerms),
|
|
||||||
ProviderCashflow = construct_provider_cashflow(
|
|
||||||
ProviderCashflowSelector,
|
|
||||||
PaymentInstitution,
|
|
||||||
Party,
|
|
||||||
Shop,
|
|
||||||
Route,
|
|
||||||
ContextSource,
|
|
||||||
Payment,
|
|
||||||
Provider,
|
|
||||||
VS0,
|
|
||||||
Revision
|
|
||||||
),
|
|
||||||
CF ++ ProviderCashflow.
|
|
||||||
|
|
||||||
get_cashflow_payment_institution(Party, Shop, VS, Revision) ->
|
|
||||||
Contract = hg_party:get_contract(Shop#domain_Shop.contract_id, Party),
|
|
||||||
PaymentInstitutionRef = Contract#domain_Contract.payment_institution,
|
|
||||||
hg_payment_institution:compute_payment_institution(
|
|
||||||
PaymentInstitutionRef,
|
|
||||||
VS,
|
|
||||||
Revision
|
|
||||||
).
|
|
||||||
|
|
||||||
get_context_source_amount(#domain_InvoicePayment{cost = Cost}) ->
|
|
||||||
Cost;
|
|
||||||
get_context_source_amount(#domain_InvoicePaymentRefund{cash = Cash}) ->
|
|
||||||
Cash.
|
|
||||||
|
|
||||||
get_provider_cashflow_selector(#domain_PaymentsProvisionTerms{cash_flow = ProviderCashflowSelector}) ->
|
|
||||||
ProviderCashflowSelector;
|
|
||||||
get_provider_cashflow_selector(#domain_PaymentRefundsProvisionTerms{cash_flow = ProviderCashflowSelector}) ->
|
|
||||||
ProviderCashflowSelector.
|
|
||||||
|
|
||||||
construct_transaction_cashflow(
|
|
||||||
OpType,
|
|
||||||
Party,
|
|
||||||
Shop,
|
|
||||||
PaymentInstitution,
|
|
||||||
Route,
|
|
||||||
Amount,
|
|
||||||
MerchantPaymentsTerms0,
|
|
||||||
Timestamp,
|
|
||||||
Payment,
|
|
||||||
Provider,
|
|
||||||
VS,
|
|
||||||
Revision
|
|
||||||
) ->
|
|
||||||
MerchantPaymentsTerms1 =
|
|
||||||
case MerchantPaymentsTerms0 of
|
|
||||||
undefined ->
|
|
||||||
TermSet = get_merchant_terms(Party, Shop, Revision, Timestamp, VS),
|
|
||||||
TermSet#domain_TermSet.payments;
|
|
||||||
_ ->
|
|
||||||
MerchantPaymentsTerms0
|
|
||||||
end,
|
|
||||||
MerchantCashflowSelector = get_terms_cashflow(OpType, MerchantPaymentsTerms1),
|
|
||||||
MerchantCashflow = get_selector_value(merchant_payment_fees, MerchantCashflowSelector),
|
|
||||||
AccountMap = hg_accounting:collect_account_map(
|
|
||||||
Payment,
|
|
||||||
Party,
|
|
||||||
Shop,
|
|
||||||
Route,
|
|
||||||
PaymentInstitution,
|
|
||||||
Provider,
|
|
||||||
VS,
|
|
||||||
Revision
|
|
||||||
),
|
|
||||||
Context = #{
|
|
||||||
operation_amount => Amount
|
|
||||||
},
|
|
||||||
construct_final_cashflow(MerchantCashflow, Context, AccountMap).
|
|
||||||
|
|
||||||
get_terms_cashflow(payment, MerchantPaymentsTerms) ->
|
|
||||||
MerchantPaymentsTerms#domain_PaymentsServiceTerms.fees;
|
|
||||||
get_terms_cashflow(refund, MerchantPaymentsTerms) ->
|
|
||||||
MerchantRefundTerms = MerchantPaymentsTerms#domain_PaymentsServiceTerms.refunds,
|
|
||||||
MerchantRefundTerms#domain_PaymentRefundsServiceTerms.fees.
|
|
||||||
|
|
||||||
construct_provider_cashflow(
|
|
||||||
ProviderCashflowSelector,
|
|
||||||
PaymentInstitution,
|
|
||||||
Party,
|
|
||||||
Shop,
|
|
||||||
Route,
|
|
||||||
ContextSource,
|
|
||||||
Payment,
|
|
||||||
Provider,
|
|
||||||
VS,
|
|
||||||
Revision
|
|
||||||
) ->
|
|
||||||
ProviderCashflow = get_selector_value(provider_payment_cash_flow, ProviderCashflowSelector),
|
|
||||||
Context = collect_cash_flow_context(ContextSource),
|
|
||||||
AccountMap = hg_accounting:collect_account_map(
|
|
||||||
Payment,
|
|
||||||
Party,
|
|
||||||
Shop,
|
|
||||||
Route,
|
|
||||||
PaymentInstitution,
|
|
||||||
Provider,
|
|
||||||
VS,
|
|
||||||
Revision
|
|
||||||
),
|
|
||||||
construct_final_cashflow(ProviderCashflow, Context, AccountMap).
|
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
||||||
-spec create_adjustment(hg_datetime:timestamp(), adjustment_params(), st(), opts()) -> {adjustment(), result()}.
|
-spec create_adjustment(hg_datetime:timestamp(), adjustment_params(), st(), opts()) -> {adjustment(), result()}.
|
||||||
@ -1748,7 +1497,16 @@ create_cash_flow_adjustment(Timestamp, Params, DomainRevision, St, Opts) ->
|
|||||||
OldCashFlow = get_final_cashflow(St),
|
OldCashFlow = get_final_cashflow(St),
|
||||||
VS = collect_validation_varset(St, Opts),
|
VS = collect_validation_varset(St, Opts),
|
||||||
Allocation = get_allocation(St),
|
Allocation = get_allocation(St),
|
||||||
NewCashFlow = calculate_cashflow(Route, Payment, Timestamp, VS, NewRevision, Opts, Allocation),
|
Context = #{
|
||||||
|
provision_terms => get_provider_terminal_terms(Route, VS, NewRevision),
|
||||||
|
route => Route,
|
||||||
|
payment => Payment,
|
||||||
|
timestamp => Timestamp,
|
||||||
|
varset => VS,
|
||||||
|
revision => NewRevision,
|
||||||
|
allocation => Allocation
|
||||||
|
},
|
||||||
|
NewCashFlow = calculate_cashflow(Context, Opts),
|
||||||
AdjState =
|
AdjState =
|
||||||
{cash_flow, #domain_InvoicePaymentAdjustmentCashFlowState{
|
{cash_flow, #domain_InvoicePaymentAdjustmentCashFlowState{
|
||||||
scenario = #domain_InvoicePaymentAdjustmentCashFlow{domain_revision = DomainRevision}
|
scenario = #domain_InvoicePaymentAdjustmentCashFlow{domain_revision = DomainRevision}
|
||||||
@ -1866,90 +1624,40 @@ get_cash_flow_for_target_status({captured, Captured}, St0, Opts) ->
|
|||||||
St = St0#st{payment = Payment},
|
St = St0#st{payment = Payment},
|
||||||
Revision = Payment#domain_InvoicePayment.domain_revision,
|
Revision = Payment#domain_InvoicePayment.domain_revision,
|
||||||
VS = collect_validation_varset(St, Opts),
|
VS = collect_validation_varset(St, Opts),
|
||||||
calculate_cashflow(Route, Payment, Timestamp, VS, Revision, Opts, Allocation);
|
Context = #{
|
||||||
|
provision_terms => get_provider_terminal_terms(Route, VS, Revision),
|
||||||
|
route => Route,
|
||||||
|
payment => Payment,
|
||||||
|
timestamp => Timestamp,
|
||||||
|
varset => VS,
|
||||||
|
revision => Revision,
|
||||||
|
allocation => Allocation
|
||||||
|
},
|
||||||
|
calculate_cashflow(Context, Opts);
|
||||||
get_cash_flow_for_target_status({cancelled, _}, _St, _Opts) ->
|
get_cash_flow_for_target_status({cancelled, _}, _St, _Opts) ->
|
||||||
[];
|
[];
|
||||||
get_cash_flow_for_target_status({failed, _}, _St, _Opts) ->
|
get_cash_flow_for_target_status({failed, _}, _St, _Opts) ->
|
||||||
[].
|
[].
|
||||||
|
|
||||||
-spec calculate_cashflow(
|
-spec calculate_cashflow(cashflow_context(), opts()) -> final_cash_flow().
|
||||||
route(),
|
calculate_cashflow(Context = #{route := Route, revision := Revision}, Opts) ->
|
||||||
payment(),
|
CollectCashflowContext = genlib_map:compact(Context#{
|
||||||
hg_datetime:timestamp(),
|
operation => payment,
|
||||||
hg_varset:varset(),
|
party => get_party(Opts),
|
||||||
hg_domain:revision(),
|
shop => get_shop(Opts),
|
||||||
opts(),
|
provider => get_route_provider(Route, Revision)
|
||||||
hg_allocation:allocation()
|
}),
|
||||||
) -> final_cash_flow().
|
hg_cashflow_utils:collect_cashflow(CollectCashflowContext).
|
||||||
calculate_cashflow(Route, Payment, Timestamp, VS, Revision, Opts, Allocation) ->
|
|
||||||
ProviderTerms = get_provider_terminal_terms(Route, VS, Revision),
|
|
||||||
calculate_cashflow(Route, Payment, ProviderTerms, undefined, VS, Revision, Opts, Timestamp, Allocation).
|
|
||||||
|
|
||||||
-spec calculate_cashflow(
|
-spec calculate_cashflow(hg_payment_institution:t(), cashflow_context(), opts()) -> final_cash_flow().
|
||||||
route(),
|
calculate_cashflow(PaymentInstitution, Context = #{route := Route, revision := Revision}, Opts) ->
|
||||||
payment(),
|
CollectCashflowContext = genlib_map:compact(Context#{
|
||||||
dmsl_domain_thrift:'PaymentsProvisionTerms'() | undefined,
|
operation => payment,
|
||||||
dmsl_domain_thrift:'PaymentsServiceTerms'() | undefined,
|
party => get_party(Opts),
|
||||||
hg_varset:varset(),
|
shop => get_shop(Opts),
|
||||||
hg_domain:revision(),
|
provider => get_route_provider(Route, Revision)
|
||||||
opts(),
|
}),
|
||||||
hg_datetime:timestamp(),
|
hg_cashflow_utils:collect_cashflow(PaymentInstitution, CollectCashflowContext).
|
||||||
hg_allocation:allocation()
|
|
||||||
) -> final_cash_flow().
|
|
||||||
calculate_cashflow(Route, Payment, ProviderTerms, MerchantTerms, VS, Revision, Opts, Timestamp, Allocation) ->
|
|
||||||
Provider = get_route_provider(Route, Revision),
|
|
||||||
Party = get_party(Opts),
|
|
||||||
Shop = get_shop(Opts),
|
|
||||||
collect_cashflow(
|
|
||||||
payment,
|
|
||||||
ProviderTerms,
|
|
||||||
MerchantTerms,
|
|
||||||
Party,
|
|
||||||
Shop,
|
|
||||||
Route,
|
|
||||||
Allocation,
|
|
||||||
Payment,
|
|
||||||
Payment,
|
|
||||||
Provider,
|
|
||||||
Timestamp,
|
|
||||||
VS,
|
|
||||||
Revision
|
|
||||||
).
|
|
||||||
|
|
||||||
-spec calculate_cashflow(
|
|
||||||
route(),
|
|
||||||
payment(),
|
|
||||||
hg_payment_institution:t(),
|
|
||||||
dmsl_domain_thrift:'PaymentsProvisionTerms'(),
|
|
||||||
dmsl_domain_thrift:'PaymentsServiceTerms'(),
|
|
||||||
hg_varset:varset(),
|
|
||||||
hg_domain:revision(),
|
|
||||||
opts(),
|
|
||||||
hg_datetime:timestamp(),
|
|
||||||
hg_allocation:allocation() | undefined
|
|
||||||
) -> final_cash_flow().
|
|
||||||
calculate_cashflow(
|
|
||||||
Route, Payment, PaymentInstitution, ProviderTerms, MerchantTerms, VS, Revision, Opts, Timestamp, Allocation
|
|
||||||
) ->
|
|
||||||
Provider = get_route_provider(Route, Revision),
|
|
||||||
Party = get_party(Opts),
|
|
||||||
Shop = get_shop(Opts),
|
|
||||||
collect_cashflow(
|
|
||||||
payment,
|
|
||||||
ProviderTerms,
|
|
||||||
MerchantTerms,
|
|
||||||
Party,
|
|
||||||
Shop,
|
|
||||||
PaymentInstitution,
|
|
||||||
Route,
|
|
||||||
Allocation,
|
|
||||||
Payment,
|
|
||||||
Payment,
|
|
||||||
Provider,
|
|
||||||
Timestamp,
|
|
||||||
VS,
|
|
||||||
Revision
|
|
||||||
).
|
|
||||||
|
|
||||||
-spec construct_adjustment(
|
-spec construct_adjustment(
|
||||||
Timestamp :: hg_datetime:timestamp(),
|
Timestamp :: hg_datetime:timestamp(),
|
||||||
@ -2245,6 +1953,26 @@ process_risk_score(Action, St) ->
|
|||||||
|
|
||||||
-spec process_routing(action(), st()) -> machine_result().
|
-spec process_routing(action(), st()) -> machine_result().
|
||||||
process_routing(Action, St) ->
|
process_routing(Action, St) ->
|
||||||
|
{PaymentInstitution, VS, Revision} = route_args(St),
|
||||||
|
try
|
||||||
|
AllRoutes = get_candidates(PaymentInstitution, VS, Revision, St),
|
||||||
|
AvailableRoutes = filter_out_attempted_routes(AllRoutes, St),
|
||||||
|
%% Since this is routing step then current attempt is not yet accounted for in `St`.
|
||||||
|
Iter = get_iter(St) + 1,
|
||||||
|
Events = handle_gathered_route_result(
|
||||||
|
filter_limit_overflow_routes(AvailableRoutes, VS, Iter, St),
|
||||||
|
[hg_routing:to_payment_route(R) || R <- AllRoutes],
|
||||||
|
[hg_routing:to_payment_route(R) || R <- AvailableRoutes],
|
||||||
|
Revision,
|
||||||
|
St
|
||||||
|
),
|
||||||
|
{next, {Events, hg_machine_action:set_timeout(0, Action)}}
|
||||||
|
catch
|
||||||
|
throw:{no_route_found, Reason} ->
|
||||||
|
handle_choose_route_error(Reason, [], St, Action)
|
||||||
|
end.
|
||||||
|
|
||||||
|
route_args(St) ->
|
||||||
Opts = get_opts(St),
|
Opts = get_opts(St),
|
||||||
Revision = get_payment_revision(St),
|
Revision = get_payment_revision(St),
|
||||||
Payment = get_payment(St),
|
Payment = get_payment(St),
|
||||||
@ -2255,29 +1983,15 @@ process_routing(Action, St) ->
|
|||||||
VS2 = collect_refund_varset(MerchantTerms#domain_PaymentsServiceTerms.refunds, PaymentTool, VS1),
|
VS2 = collect_refund_varset(MerchantTerms#domain_PaymentsServiceTerms.refunds, PaymentTool, VS1),
|
||||||
VS3 = collect_chargeback_varset(MerchantTerms#domain_PaymentsServiceTerms.chargebacks, VS2),
|
VS3 = collect_chargeback_varset(MerchantTerms#domain_PaymentsServiceTerms.chargebacks, VS2),
|
||||||
PaymentInstitution = hg_payment_institution:compute_payment_institution(PaymentInstitutionRef, VS1, Revision),
|
PaymentInstitution = hg_payment_institution:compute_payment_institution(PaymentInstitutionRef, VS1, Revision),
|
||||||
try
|
{PaymentInstitution, VS3, Revision}.
|
||||||
|
|
||||||
|
get_candidates(PaymentInstitution, VS, Revision, St) ->
|
||||||
Payer = get_payment_payer(St),
|
Payer = get_payment_payer(St),
|
||||||
AllRoutes =
|
|
||||||
case get_predefined_route(Payer) of
|
case get_predefined_route(Payer) of
|
||||||
{ok, PaymentRoute} ->
|
{ok, PaymentRoute} ->
|
||||||
[hg_routing:from_payment_route(PaymentRoute)];
|
[hg_routing:from_payment_route(PaymentRoute)];
|
||||||
undefined ->
|
undefined ->
|
||||||
gather_routes(PaymentInstitution, VS3, Revision, St)
|
gather_routes(PaymentInstitution, VS, Revision, St)
|
||||||
end,
|
|
||||||
AvailableRoutes = filter_out_attempted_routes(AllRoutes, St),
|
|
||||||
%% Since this is routing step then current attempt is not yet accounted for in `St`.
|
|
||||||
Iter = get_iter(St) + 1,
|
|
||||||
Events = handle_gathered_route_result(
|
|
||||||
filter_limit_overflow_routes(AvailableRoutes, VS3, Iter, St),
|
|
||||||
[hg_routing:to_payment_route(R) || R <- AllRoutes],
|
|
||||||
[hg_routing:to_payment_route(R) || R <- AvailableRoutes],
|
|
||||||
Revision,
|
|
||||||
St
|
|
||||||
),
|
|
||||||
{next, {Events, hg_machine_action:set_timeout(0, Action)}}
|
|
||||||
catch
|
|
||||||
throw:{no_route_found, Reason} ->
|
|
||||||
handle_choose_route_error(Reason, [], St, Action)
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
filter_out_attempted_routes(Routes, #st{routes = AttemptedRoutes}) ->
|
filter_out_attempted_routes(Routes, #st{routes = AttemptedRoutes}) ->
|
||||||
@ -2337,17 +2051,16 @@ process_cash_flow_building(Action, St) ->
|
|||||||
VS1 = collect_validation_varset(get_party(Opts), get_shop(Opts), Payment, VS0),
|
VS1 = collect_validation_varset(get_party(Opts), get_shop(Opts), Payment, VS0),
|
||||||
ProviderTerms = get_provider_terminal_terms(Route, VS1, Revision),
|
ProviderTerms = get_provider_terminal_terms(Route, VS1, Revision),
|
||||||
Allocation = get_allocation(St),
|
Allocation = get_allocation(St),
|
||||||
FinalCashflow = calculate_cashflow(
|
Context = #{
|
||||||
Route,
|
provision_terms => ProviderTerms,
|
||||||
Payment,
|
route => Route,
|
||||||
ProviderTerms,
|
payment => Payment,
|
||||||
undefined,
|
timestamp => Timestamp,
|
||||||
VS1,
|
varset => VS1,
|
||||||
Revision,
|
revision => Revision,
|
||||||
Opts,
|
allocation => Allocation
|
||||||
Timestamp,
|
},
|
||||||
Allocation
|
FinalCashflow = calculate_cashflow(Context, Opts),
|
||||||
),
|
|
||||||
_ = rollback_unused_payment_limits(St),
|
_ = rollback_unused_payment_limits(St),
|
||||||
_Clock = hg_accounting:hold(
|
_Clock = hg_accounting:hold(
|
||||||
construct_payment_plan_id(St),
|
construct_payment_plan_id(St),
|
||||||
@ -3418,7 +3131,7 @@ get_routing_attempt_limit(
|
|||||||
Party = hg_party:checkout(PartyID, {revision, PartyRevision}),
|
Party = hg_party:checkout(PartyID, {revision, PartyRevision}),
|
||||||
Shop = hg_party:get_shop(ShopID, Party),
|
Shop = hg_party:get_shop(ShopID, Party),
|
||||||
VS = collect_validation_varset(Party, Shop, get_payment(St), #{}),
|
VS = collect_validation_varset(Party, Shop, get_payment(St), #{}),
|
||||||
Terms = get_merchant_terms(Party, Shop, Revision, CreatedAt, VS),
|
Terms = hg_invoice_utils:get_merchant_terms(Party, Shop, Revision, CreatedAt, VS),
|
||||||
#domain_TermSet{payments = PaymentTerms} = Terms,
|
#domain_TermSet{payments = PaymentTerms} = Terms,
|
||||||
log_cascade_attempt_context(PaymentTerms, St),
|
log_cascade_attempt_context(PaymentTerms, St),
|
||||||
get_routing_attempt_limit_value(PaymentTerms#domain_PaymentsServiceTerms.attempt_limit).
|
get_routing_attempt_limit_value(PaymentTerms#domain_PaymentsServiceTerms.attempt_limit).
|
||||||
@ -3504,6 +3217,28 @@ accrue_status_timing(Name, Opts, #st{timings = Timings}) ->
|
|||||||
EventTime = define_event_timestamp(Opts),
|
EventTime = define_event_timestamp(Opts),
|
||||||
hg_timings:mark(Name, EventTime, hg_timings:accrue(Name, started, EventTime, Timings)).
|
hg_timings:mark(Name, EventTime, hg_timings:accrue(Name, started, EventTime, Timings)).
|
||||||
|
|
||||||
|
-spec get_limit_values(st()) -> route_limit_context().
|
||||||
|
get_limit_values(St) ->
|
||||||
|
{PaymentInstitution, VS, Revision} = route_args(St),
|
||||||
|
Routes = get_candidates(PaymentInstitution, VS, Revision, St),
|
||||||
|
Payment = get_payment(St),
|
||||||
|
Invoice = get_invoice(get_opts(St)),
|
||||||
|
lists:foldl(
|
||||||
|
fun(Route, Acc) ->
|
||||||
|
PaymentRoute = hg_routing:to_payment_route(Route),
|
||||||
|
ProviderTerms = hg_routing:get_payment_terms(PaymentRoute, VS, Revision),
|
||||||
|
TurnoverLimits = get_turnover_limits(ProviderTerms),
|
||||||
|
TurnoverLimitValues = hg_limiter:get_limit_values(TurnoverLimits, Invoice, Payment, PaymentRoute),
|
||||||
|
Acc#{PaymentRoute => TurnoverLimitValues}
|
||||||
|
end,
|
||||||
|
#{},
|
||||||
|
Routes
|
||||||
|
).
|
||||||
|
|
||||||
|
-spec get_limit_values(st(), opts()) -> route_limit_context().
|
||||||
|
get_limit_values(St, Opts) ->
|
||||||
|
get_limit_values(St#st{opts = Opts}).
|
||||||
|
|
||||||
try_accrue_waiting_timing(Opts, #st{payment = Payment, timings = Timings}) ->
|
try_accrue_waiting_timing(Opts, #st{payment = Payment, timings = Timings}) ->
|
||||||
case get_payment_flow(Payment) of
|
case get_payment_flow(Payment) of
|
||||||
?invoice_payment_flow_instant() ->
|
?invoice_payment_flow_instant() ->
|
||||||
|
@ -428,7 +428,17 @@ build_chargeback_final_cash_flow(State, Opts) ->
|
|||||||
PaymentInstitutionRef = get_payment_institution_ref(get_contract(Party, Shop)),
|
PaymentInstitutionRef = get_payment_institution_ref(get_contract(Party, Shop)),
|
||||||
PaymentInst = hg_payment_institution:compute_payment_institution(PaymentInstitutionRef, VS, Revision),
|
PaymentInst = hg_payment_institution:compute_payment_institution(PaymentInstitutionRef, VS, Revision),
|
||||||
Provider = get_route_provider(Route, Revision),
|
Provider = get_route_provider(Route, Revision),
|
||||||
AccountMap = hg_accounting:collect_account_map(Payment, Party, Shop, Route, PaymentInst, Provider, VS, Revision),
|
CollectAccountContext = #{
|
||||||
|
payment => Payment,
|
||||||
|
party => Party,
|
||||||
|
shop => Shop,
|
||||||
|
route => Route,
|
||||||
|
payment_institution => PaymentInst,
|
||||||
|
provider => Provider,
|
||||||
|
varset => VS,
|
||||||
|
revision => Revision
|
||||||
|
},
|
||||||
|
AccountMap = hg_accounting:collect_account_map(CollectAccountContext),
|
||||||
ServiceContext = build_service_cash_flow_context(State),
|
ServiceContext = build_service_cash_flow_context(State),
|
||||||
ProviderContext = build_provider_cash_flow_context(State, ProviderFees),
|
ProviderContext = build_provider_cash_flow_context(State, ProviderFees),
|
||||||
ServiceFinalCF = hg_cashflow:finalize(ServiceCashFlow, ServiceContext, AccountMap),
|
ServiceFinalCF = hg_cashflow:finalize(ServiceCashFlow, ServiceContext, AccountMap),
|
||||||
|
@ -72,18 +72,16 @@ init_(PaymentID, Params, Opts = #{timestamp := CreatedAt0}) ->
|
|||||||
|
|
||||||
MerchantTerms = get_merchant_payment_terms(Party, Shop, Revision, CreatedAt1, VS),
|
MerchantTerms = get_merchant_payment_terms(Party, Shop, Revision, CreatedAt1, VS),
|
||||||
ProviderTerms = hg_invoice_payment:get_provider_terminal_terms(Route, VS, Revision),
|
ProviderTerms = hg_invoice_payment:get_provider_terminal_terms(Route, VS, Revision),
|
||||||
FinalCashflow = hg_invoice_payment:calculate_cashflow(
|
CashflowContext = #{
|
||||||
Route,
|
provision_terms => ProviderTerms,
|
||||||
Payment,
|
merchant_terms => MerchantTerms,
|
||||||
PaymentInstitution,
|
route => Route,
|
||||||
ProviderTerms,
|
payment => Payment,
|
||||||
MerchantTerms,
|
timestamp => CreatedAt1,
|
||||||
VS,
|
varset => VS,
|
||||||
Revision,
|
revision => Revision
|
||||||
Opts,
|
},
|
||||||
CreatedAt1,
|
FinalCashflow = hg_invoice_payment:calculate_cashflow(PaymentInstitution, CashflowContext, Opts),
|
||||||
undefined
|
|
||||||
),
|
|
||||||
|
|
||||||
Events =
|
Events =
|
||||||
[
|
[
|
||||||
@ -182,7 +180,7 @@ maybe_risk_score_event_list(RiskScore) ->
|
|||||||
[?risk_score_changed(RiskScore)].
|
[?risk_score_changed(RiskScore)].
|
||||||
|
|
||||||
get_merchant_payment_terms(Party, Shop, DomainRevision, Timestamp, VS) ->
|
get_merchant_payment_terms(Party, Shop, DomainRevision, Timestamp, VS) ->
|
||||||
TermSet = hg_invoice_payment:get_merchant_terms(Party, Shop, DomainRevision, Timestamp, VS),
|
TermSet = hg_invoice_utils:get_merchant_terms(Party, Shop, DomainRevision, Timestamp, VS),
|
||||||
TermSet#domain_TermSet.payments.
|
TermSet#domain_TermSet.payments.
|
||||||
|
|
||||||
hold_payment_limits(Invoice, Payment, St) ->
|
hold_payment_limits(Invoice, Payment, St) ->
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
-export([assert_shop_operable/1]).
|
-export([assert_shop_operable/1]).
|
||||||
-export([assert_cost_payable/2]).
|
-export([assert_cost_payable/2]).
|
||||||
-export([compute_shop_terms/5]).
|
-export([compute_shop_terms/5]).
|
||||||
|
-export([get_merchant_terms/5]).
|
||||||
-export([get_shop_currency/1]).
|
-export([get_shop_currency/1]).
|
||||||
-export([get_cart_amount/1]).
|
-export([get_cart_amount/1]).
|
||||||
-export([check_deadline/1]).
|
-export([check_deadline/1]).
|
||||||
@ -111,6 +112,30 @@ compute_shop_terms(PartyID, ShopID, Timestamp, PartyRevision, Varset) ->
|
|||||||
party_client_thrift:compute_shop_terms(PartyID, ShopID, Timestamp, PartyRevision, Varset, Client, Context),
|
party_client_thrift:compute_shop_terms(PartyID, ShopID, Timestamp, PartyRevision, Varset, Client, Context),
|
||||||
TermSet.
|
TermSet.
|
||||||
|
|
||||||
|
-spec get_merchant_terms(party(), shop(), hg_domain:revision(), hg_datetime:timestamp(), hg_varset:varset()) ->
|
||||||
|
term_set().
|
||||||
|
get_merchant_terms(Party, Shop, DomainRevision, Timestamp, VS) ->
|
||||||
|
ContractID = Shop#domain_Shop.contract_id,
|
||||||
|
Contract = hg_party:get_contract(ContractID, Party),
|
||||||
|
ok = assert_contract_active(Contract),
|
||||||
|
{Client, Context} = get_party_client(),
|
||||||
|
{ok, Terms} = party_client_thrift:compute_contract_terms(
|
||||||
|
Party#domain_Party.id,
|
||||||
|
ContractID,
|
||||||
|
Timestamp,
|
||||||
|
{revision, Party#domain_Party.revision},
|
||||||
|
DomainRevision,
|
||||||
|
hg_varset:prepare_contract_terms_varset(VS),
|
||||||
|
Client,
|
||||||
|
Context
|
||||||
|
),
|
||||||
|
Terms.
|
||||||
|
|
||||||
|
assert_contract_active(#domain_Contract{status = {active, _}}) ->
|
||||||
|
ok;
|
||||||
|
assert_contract_active(#domain_Contract{status = Status}) ->
|
||||||
|
throw(#payproc_InvalidContractStatus{status = Status}).
|
||||||
|
|
||||||
validate_currency_(Currency, Currency) ->
|
validate_currency_(Currency, Currency) ->
|
||||||
ok;
|
ok;
|
||||||
validate_currency_(_, _) ->
|
validate_currency_(_, _) ->
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
-module(hg_limiter).
|
-module(hg_limiter).
|
||||||
|
|
||||||
|
-include_lib("damsel/include/dmsl_payproc_thrift.hrl").
|
||||||
-include_lib("damsel/include/dmsl_domain_thrift.hrl").
|
-include_lib("damsel/include/dmsl_domain_thrift.hrl").
|
||||||
-include_lib("damsel/include/dmsl_base_thrift.hrl").
|
-include_lib("damsel/include/dmsl_base_thrift.hrl").
|
||||||
-include_lib("limiter_proto/include/limproto_base_thrift.hrl").
|
-include_lib("limiter_proto/include/limproto_base_thrift.hrl").
|
||||||
@ -14,6 +15,7 @@
|
|||||||
-type refund() :: hg_invoice_payment:domain_refund().
|
-type refund() :: hg_invoice_payment:domain_refund().
|
||||||
-type cash() :: dmsl_domain_thrift:'Cash'().
|
-type cash() :: dmsl_domain_thrift:'Cash'().
|
||||||
-type handling_flag() :: ignore_business_error.
|
-type handling_flag() :: ignore_business_error.
|
||||||
|
-type turnover_limit_value() :: dmsl_payproc_thrift:'TurnoverLimitValue'().
|
||||||
|
|
||||||
-type change_queue() :: [hg_limiter_client:limit_change()].
|
-type change_queue() :: [hg_limiter_client:limit_change()].
|
||||||
|
|
||||||
@ -25,6 +27,7 @@
|
|||||||
-export([commit_refund_limits/5]).
|
-export([commit_refund_limits/5]).
|
||||||
-export([rollback_payment_limits/6]).
|
-export([rollback_payment_limits/6]).
|
||||||
-export([rollback_refund_limits/5]).
|
-export([rollback_refund_limits/5]).
|
||||||
|
-export([get_limit_values/4]).
|
||||||
|
|
||||||
-define(route(ProviderRef, TerminalRef), #domain_PaymentRoute{
|
-define(route(ProviderRef, TerminalRef), #domain_PaymentRoute{
|
||||||
provider = ProviderRef,
|
provider = ProviderRef,
|
||||||
@ -39,6 +42,23 @@ get_turnover_limits({value, Limits}) ->
|
|||||||
get_turnover_limits(Ambiguous) ->
|
get_turnover_limits(Ambiguous) ->
|
||||||
error({misconfiguration, {'Could not reduce selector to a value', Ambiguous}}).
|
error({misconfiguration, {'Could not reduce selector to a value', Ambiguous}}).
|
||||||
|
|
||||||
|
-spec get_limit_values([turnover_limit()], invoice(), payment(), route()) -> [turnover_limit_value()].
|
||||||
|
get_limit_values(TurnoverLimits, Invoice, Payment, Route) ->
|
||||||
|
Context = gen_limit_context(Invoice, Payment, Route),
|
||||||
|
lists:foldl(
|
||||||
|
fun(TurnoverLimit, Acc) ->
|
||||||
|
#domain_TurnoverLimit{id = LimitID, domain_revision = Version} = TurnoverLimit,
|
||||||
|
Clock = get_latest_clock(),
|
||||||
|
Limit = hg_limiter_client:get(LimitID, Version, Clock, Context),
|
||||||
|
#limiter_Limit{
|
||||||
|
amount = LimiterAmount
|
||||||
|
} = Limit,
|
||||||
|
[#payproc_TurnoverLimitValue{limit = TurnoverLimit, value = LimiterAmount} | Acc]
|
||||||
|
end,
|
||||||
|
[],
|
||||||
|
TurnoverLimits
|
||||||
|
).
|
||||||
|
|
||||||
-spec check_limits([turnover_limit()], invoice(), payment(), route()) ->
|
-spec check_limits([turnover_limit()], invoice(), payment(), route()) ->
|
||||||
{ok, [hg_limiter_client:limit()]}
|
{ok, [hg_limiter_client:limit()]}
|
||||||
| {error, {limit_overflow, [binary()]}}.
|
| {error, {limit_overflow, [binary()]}}.
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
-export([new/2]).
|
-export([new/2]).
|
||||||
-export([new/4]).
|
-export([new/4]).
|
||||||
-export([new/5]).
|
-export([new/5]).
|
||||||
|
-export([new/6]).
|
||||||
-export([to_payment_route/1]).
|
-export([to_payment_route/1]).
|
||||||
-export([to_rejected_route/2]).
|
-export([to_rejected_route/2]).
|
||||||
-export([provider_ref/1]).
|
-export([provider_ref/1]).
|
||||||
@ -32,7 +33,8 @@
|
|||||||
terminal_ref :: dmsl_domain_thrift:'TerminalRef'(),
|
terminal_ref :: dmsl_domain_thrift:'TerminalRef'(),
|
||||||
weight :: integer(),
|
weight :: integer(),
|
||||||
priority :: integer(),
|
priority :: integer(),
|
||||||
pin :: pin()
|
pin :: pin(),
|
||||||
|
fd_overrides :: fd_overrides()
|
||||||
}).
|
}).
|
||||||
|
|
||||||
-type pin() :: #{
|
-type pin() :: #{
|
||||||
@ -98,6 +100,7 @@
|
|||||||
|
|
||||||
-type varset() :: hg_varset:varset().
|
-type varset() :: hg_varset:varset().
|
||||||
-type revision() :: hg_domain:revision().
|
-type revision() :: hg_domain:revision().
|
||||||
|
-type fd_overrides() :: dmsl_domain_thrift:'RouteFaultDetectorOverrides'().
|
||||||
|
|
||||||
-record(route_scores, {
|
-record(route_scores, {
|
||||||
availability_condition :: condition_score(),
|
availability_condition :: condition_score(),
|
||||||
@ -136,12 +139,19 @@ new(ProviderRef, TerminalRef, Weight, Priority) ->
|
|||||||
new(ProviderRef, TerminalRef, undefined, Priority, Pin) ->
|
new(ProviderRef, TerminalRef, undefined, Priority, Pin) ->
|
||||||
new(ProviderRef, TerminalRef, ?DOMAIN_CANDIDATE_WEIGHT, Priority, Pin);
|
new(ProviderRef, TerminalRef, ?DOMAIN_CANDIDATE_WEIGHT, Priority, Pin);
|
||||||
new(ProviderRef, TerminalRef, Weight, Priority, Pin) ->
|
new(ProviderRef, TerminalRef, Weight, Priority, Pin) ->
|
||||||
|
new(ProviderRef, TerminalRef, Weight, Priority, Pin, #domain_RouteFaultDetectorOverrides{}).
|
||||||
|
|
||||||
|
-spec new(provider_ref(), terminal_ref(), integer(), integer(), pin(), fd_overrides() | undefined) -> route().
|
||||||
|
new(ProviderRef, TerminalRef, Weight, Priority, Pin, undefined) ->
|
||||||
|
new(ProviderRef, TerminalRef, Weight, Priority, Pin, #domain_RouteFaultDetectorOverrides{});
|
||||||
|
new(ProviderRef, TerminalRef, Weight, Priority, Pin, FdOverrides) ->
|
||||||
#route{
|
#route{
|
||||||
provider_ref = ProviderRef,
|
provider_ref = ProviderRef,
|
||||||
terminal_ref = TerminalRef,
|
terminal_ref = TerminalRef,
|
||||||
weight = Weight,
|
weight = Weight,
|
||||||
priority = Priority,
|
priority = Priority,
|
||||||
pin = Pin
|
pin = Pin,
|
||||||
|
fd_overrides = FdOverrides
|
||||||
}.
|
}.
|
||||||
|
|
||||||
-spec provider_ref(route()) -> provider_ref().
|
-spec provider_ref(route()) -> provider_ref().
|
||||||
@ -164,6 +174,9 @@ weight(#route{weight = Weight}) ->
|
|||||||
pin(#route{pin = Pin}) ->
|
pin(#route{pin = Pin}) ->
|
||||||
Pin.
|
Pin.
|
||||||
|
|
||||||
|
fd_overrides(#route{fd_overrides = FdOverrides}) ->
|
||||||
|
FdOverrides.
|
||||||
|
|
||||||
-spec from_payment_route(payment_route()) -> route().
|
-spec from_payment_route(payment_route()) -> route().
|
||||||
from_payment_route(Route) ->
|
from_payment_route(Route) ->
|
||||||
?route(ProviderRef, TerminalRef) = Route,
|
?route(ProviderRef, TerminalRef) = Route,
|
||||||
@ -260,12 +273,13 @@ collect_routes(Predestination, Candidates, VS, Revision, Ctx) ->
|
|||||||
% Looks like overhead, we got Terminal only for provider_ref. Maybe we can remove provider_ref from route().
|
% Looks like overhead, we got Terminal only for provider_ref. Maybe we can remove provider_ref from route().
|
||||||
% https://github.com/rbkmoney/hellgate/pull/583#discussion_r682745123
|
% https://github.com/rbkmoney/hellgate/pull/583#discussion_r682745123
|
||||||
#domain_Terminal{
|
#domain_Terminal{
|
||||||
provider_ref = ProviderRef
|
provider_ref = ProviderRef,
|
||||||
|
route_fd_overrides = FdOverrides
|
||||||
} = hg_domain:get(Revision, {terminal, TerminalRef}),
|
} = hg_domain:get(Revision, {terminal, TerminalRef}),
|
||||||
GatheredPinInfo = gather_pin_info(Pin, Ctx),
|
GatheredPinInfo = gather_pin_info(Pin, Ctx),
|
||||||
try
|
try
|
||||||
true = acceptable_terminal(Predestination, ProviderRef, TerminalRef, VS, Revision),
|
true = acceptable_terminal(Predestination, ProviderRef, TerminalRef, VS, Revision),
|
||||||
Route = new(ProviderRef, TerminalRef, Weight, Priority, GatheredPinInfo),
|
Route = new(ProviderRef, TerminalRef, Weight, Priority, GatheredPinInfo, FdOverrides),
|
||||||
{[Route | Accepted], Rejected}
|
{[Route | Accepted], Rejected}
|
||||||
catch
|
catch
|
||||||
{rejected, Reason} ->
|
{rejected, Reason} ->
|
||||||
@ -518,17 +532,22 @@ score_routes_with_fault_detector([]) ->
|
|||||||
score_routes_with_fault_detector(Routes) ->
|
score_routes_with_fault_detector(Routes) ->
|
||||||
IDs = build_ids(Routes),
|
IDs = build_ids(Routes),
|
||||||
FDStats = hg_fault_detector_client:get_statistics(IDs),
|
FDStats = hg_fault_detector_client:get_statistics(IDs),
|
||||||
[{R, get_provider_status(provider_ref(R), FDStats)} || R <- Routes].
|
[{R, get_provider_status(R, FDStats)} || R <- Routes].
|
||||||
|
|
||||||
-spec get_provider_status(provider_ref(), [fd_service_stats()]) -> provider_status().
|
-spec get_provider_status(route(), [fd_service_stats()]) -> provider_status().
|
||||||
get_provider_status(ProviderRef, FDStats) ->
|
get_provider_status(Route, FDStats) ->
|
||||||
|
ProviderRef = provider_ref(Route),
|
||||||
|
FdOverrides = fd_overrides(Route),
|
||||||
AvailabilityServiceID = build_fd_availability_service_id(ProviderRef),
|
AvailabilityServiceID = build_fd_availability_service_id(ProviderRef),
|
||||||
ConversionServiceID = build_fd_conversion_service_id(ProviderRef),
|
ConversionServiceID = build_fd_conversion_service_id(ProviderRef),
|
||||||
AvailabilityStatus = get_provider_availability_status(AvailabilityServiceID, FDStats),
|
AvailabilityStatus = get_provider_availability_status(FdOverrides, AvailabilityServiceID, FDStats),
|
||||||
ConversionStatus = get_provider_conversion_status(ConversionServiceID, FDStats),
|
ConversionStatus = get_provider_conversion_status(FdOverrides, ConversionServiceID, FDStats),
|
||||||
{AvailabilityStatus, ConversionStatus}.
|
{AvailabilityStatus, ConversionStatus}.
|
||||||
|
|
||||||
get_provider_availability_status(FDID, Stats) ->
|
get_provider_availability_status(#domain_RouteFaultDetectorOverrides{enabled = true}, _FDID, _Stats) ->
|
||||||
|
%% ignore fd statistic if set override
|
||||||
|
{alive, 0.0};
|
||||||
|
get_provider_availability_status(_, FDID, Stats) ->
|
||||||
AvailabilityConfig = maps:get(availability, genlib_app:env(hellgate, fault_detector, #{}), #{}),
|
AvailabilityConfig = maps:get(availability, genlib_app:env(hellgate, fault_detector, #{}), #{}),
|
||||||
CriticalFailRate = maps:get(critical_fail_rate, AvailabilityConfig, 0.7),
|
CriticalFailRate = maps:get(critical_fail_rate, AvailabilityConfig, 0.7),
|
||||||
case lists:keysearch(FDID, #fault_detector_ServiceStatistics.service_id, Stats) of
|
case lists:keysearch(FDID, #fault_detector_ServiceStatistics.service_id, Stats) of
|
||||||
@ -540,7 +559,10 @@ get_provider_availability_status(FDID, Stats) ->
|
|||||||
{alive, 0.0}
|
{alive, 0.0}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
get_provider_conversion_status(FDID, Stats) ->
|
get_provider_conversion_status(#domain_RouteFaultDetectorOverrides{enabled = true}, _FDID, _Stats) ->
|
||||||
|
%% ignore fd statistic if set override
|
||||||
|
{normal, 0.0};
|
||||||
|
get_provider_conversion_status(_, FDID, Stats) ->
|
||||||
ConversionConfig = maps:get(conversion, genlib_app:env(hellgate, fault_detector, #{}), #{}),
|
ConversionConfig = maps:get(conversion, genlib_app:env(hellgate, fault_detector, #{}), #{}),
|
||||||
CriticalFailRate = maps:get(critical_fail_rate, ConversionConfig, 0.7),
|
CriticalFailRate = maps:get(critical_fail_rate, ConversionConfig, 0.7),
|
||||||
case lists:keysearch(FDID, #fault_detector_ServiceStatistics.service_id, Stats) of
|
case lists:keysearch(FDID, #fault_detector_ServiceStatistics.service_id, Stats) of
|
||||||
|
@ -40,6 +40,7 @@
|
|||||||
-export([register_payment_customer_payer_success/1]).
|
-export([register_payment_customer_payer_success/1]).
|
||||||
|
|
||||||
-export([payment_limit_success/1]).
|
-export([payment_limit_success/1]).
|
||||||
|
-export([payment_routes_limit_values/1]).
|
||||||
-export([register_payment_limit_success/1]).
|
-export([register_payment_limit_success/1]).
|
||||||
-export([payment_limit_other_shop_success/1]).
|
-export([payment_limit_other_shop_success/1]).
|
||||||
-export([payment_limit_overflow/1]).
|
-export([payment_limit_overflow/1]).
|
||||||
@ -383,6 +384,7 @@ groups() ->
|
|||||||
|
|
||||||
{operation_limits, [], [
|
{operation_limits, [], [
|
||||||
payment_limit_success,
|
payment_limit_success,
|
||||||
|
payment_routes_limit_values,
|
||||||
register_payment_limit_success,
|
register_payment_limit_success,
|
||||||
payment_limit_other_shop_success,
|
payment_limit_other_shop_success,
|
||||||
payment_limit_overflow,
|
payment_limit_overflow,
|
||||||
@ -1254,6 +1256,30 @@ payment_limit_success(C) ->
|
|||||||
[?payment_state(_Payment)]
|
[?payment_state(_Payment)]
|
||||||
) = create_payment(PartyID, ShopID, 10000, Client, ?pmt_sys(<<"visa-ref">>)).
|
) = create_payment(PartyID, ShopID, 10000, Client, ?pmt_sys(<<"visa-ref">>)).
|
||||||
|
|
||||||
|
-spec payment_routes_limit_values(config()) -> test_return().
|
||||||
|
payment_routes_limit_values(C) ->
|
||||||
|
RootUrl = cfg(root_url, C),
|
||||||
|
PartyClient = cfg(party_client, C),
|
||||||
|
#{party_id := PartyID} = cfg(limits, C),
|
||||||
|
ShopID = hg_ct_helper:create_shop(PartyID, ?cat(8), <<"RUB">>, ?tmpl(1), ?pinst(1), PartyClient),
|
||||||
|
Client = hg_client_invoicing:start_link(hg_ct_helper:create_client(RootUrl)),
|
||||||
|
|
||||||
|
#payproc_Invoice{
|
||||||
|
invoice = #domain_Invoice{id = InvoiceId},
|
||||||
|
payments = [
|
||||||
|
#payproc_InvoicePayment{payment = #domain_InvoicePayment{id = PaymentId}}
|
||||||
|
]
|
||||||
|
} = create_payment(PartyID, ShopID, 10000, Client, ?pmt_sys(<<"visa-ref">>)),
|
||||||
|
Route = ?route(?prv(5), ?trm(12)),
|
||||||
|
#{
|
||||||
|
Route := [
|
||||||
|
#payproc_TurnoverLimitValue{
|
||||||
|
limit = #domain_TurnoverLimit{id = ?LIMIT_ID, upper_boundary = ?LIMIT_UPPER_BOUNDARY},
|
||||||
|
value = 10000
|
||||||
|
}
|
||||||
|
]
|
||||||
|
} = hg_client_invoicing:get_limit_values(InvoiceId, PaymentId, Client).
|
||||||
|
|
||||||
-spec register_payment_limit_success(config()) -> test_return().
|
-spec register_payment_limit_success(config()) -> test_return().
|
||||||
register_payment_limit_success(C0) ->
|
register_payment_limit_success(C0) ->
|
||||||
Client = cfg(client, C0),
|
Client = cfg(client, C0),
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
-export([terminal_priority_for_shop/1]).
|
-export([terminal_priority_for_shop/1]).
|
||||||
-export([gather_pinned_route/1]).
|
-export([gather_pinned_route/1]).
|
||||||
-export([choose_pinned_route/1]).
|
-export([choose_pinned_route/1]).
|
||||||
|
-export([choose_route_w_override/1]).
|
||||||
|
|
||||||
-define(PROVIDER_MIN_ALLOWED, ?cash(1000, <<"RUB">>)).
|
-define(PROVIDER_MIN_ALLOWED, ?cash(1000, <<"RUB">>)).
|
||||||
-define(PROVIDER_MIN_ALLOWED_W_EXTRA_CASH(ExtraCash), ?cash(1000 + ExtraCash, <<"RUB">>)).
|
-define(PROVIDER_MIN_ALLOWED_W_EXTRA_CASH(ExtraCash), ?cash(1000 + ExtraCash, <<"RUB">>)).
|
||||||
@ -72,7 +73,8 @@ groups() ->
|
|||||||
terminal_priority_for_shop,
|
terminal_priority_for_shop,
|
||||||
|
|
||||||
gather_pinned_route,
|
gather_pinned_route,
|
||||||
choose_pinned_route
|
choose_pinned_route,
|
||||||
|
choose_route_w_override
|
||||||
]}
|
]}
|
||||||
].
|
].
|
||||||
|
|
||||||
@ -821,6 +823,26 @@ choose_pinned_route(_C) ->
|
|||||||
[ChosenRoute | _] = lists:sort(Routes),
|
[ChosenRoute | _] = lists:sort(Routes),
|
||||||
{ChosenRoute, _} = hg_routing:choose_route(Routes).
|
{ChosenRoute, _} = hg_routing:choose_route(Routes).
|
||||||
|
|
||||||
|
-spec choose_route_w_override(config()) -> test_return().
|
||||||
|
choose_route_w_override(_C) ->
|
||||||
|
%% without overrides
|
||||||
|
Route1 = hg_routing:new(?prv(1), ?trm(1)),
|
||||||
|
Route2 = hg_routing:new(?prv(2), ?trm(2)),
|
||||||
|
Route3 = hg_routing:new(?prv(3), ?trm(3)),
|
||||||
|
Routes = [Route1, Route2, Route3],
|
||||||
|
{
|
||||||
|
Route2,
|
||||||
|
#{
|
||||||
|
preferable_route := Route3,
|
||||||
|
reject_reason := availability
|
||||||
|
}
|
||||||
|
} = hg_routing:choose_route(Routes),
|
||||||
|
|
||||||
|
%% with overrides
|
||||||
|
Route3WithOV = hg_routing:new(?prv(3), ?trm(3), 0, 1000, #{}, #domain_RouteFaultDetectorOverrides{enabled = true}),
|
||||||
|
RoutesWithOV = [Route1, Route2, Route3WithOV],
|
||||||
|
{Route3WithOV, _} = hg_routing:choose_route(RoutesWithOV).
|
||||||
|
|
||||||
%%% Domain config fixtures
|
%%% Domain config fixtures
|
||||||
|
|
||||||
routing_with_risk_score_fixture(Domain, AddRiskScore) ->
|
routing_with_risk_score_fixture(Domain, AddRiskScore) ->
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
-export([rescind/3]).
|
-export([rescind/3]).
|
||||||
-export([repair/5]).
|
-export([repair/5]).
|
||||||
-export([repair_scenario/3]).
|
-export([repair_scenario/3]).
|
||||||
|
-export([get_limit_values/3]).
|
||||||
|
|
||||||
-export([create_invoice_adjustment/3]).
|
-export([create_invoice_adjustment/3]).
|
||||||
-export([get_invoice_adjustment/3]).
|
-export([get_invoice_adjustment/3]).
|
||||||
@ -98,6 +99,8 @@
|
|||||||
-type event_range() :: dmsl_payproc_thrift:'EventRange'().
|
-type event_range() :: dmsl_payproc_thrift:'EventRange'().
|
||||||
-type party_revision_param() :: dmsl_payproc_thrift:'PartyRevisionParam'().
|
-type party_revision_param() :: dmsl_payproc_thrift:'PartyRevisionParam'().
|
||||||
|
|
||||||
|
-type route_limit_context() :: dmsl_payproc_thrift:'RouteLimitContext'().
|
||||||
|
|
||||||
-spec start(hg_client_api:t()) -> pid().
|
-spec start(hg_client_api:t()) -> pid().
|
||||||
start(ApiClient) ->
|
start(ApiClient) ->
|
||||||
start(start, ApiClient).
|
start(start, ApiClient).
|
||||||
@ -150,6 +153,10 @@ repair(InvoiceID, Changes, Action, Params, Client) ->
|
|||||||
repair_scenario(InvoiceID, Scenario, Client) ->
|
repair_scenario(InvoiceID, Scenario, Client) ->
|
||||||
map_result_error(gen_server:call(Client, {call, 'RepairWithScenario', [InvoiceID, Scenario]})).
|
map_result_error(gen_server:call(Client, {call, 'RepairWithScenario', [InvoiceID, Scenario]})).
|
||||||
|
|
||||||
|
-spec get_limit_values(invoice_id(), payment_id(), pid()) -> route_limit_context() | woody_error:business_error().
|
||||||
|
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()) ->
|
-spec create_invoice_adjustment(invoice_id(), invoice_adjustment_params(), pid()) ->
|
||||||
invoice_adjustment() | woody_error:business_error().
|
invoice_adjustment() | woody_error:business_error().
|
||||||
create_invoice_adjustment(InvoiceID, Params, Client) ->
|
create_invoice_adjustment(InvoiceID, Params, Client) ->
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
{<<"cowlib">>,{pkg,<<"cowlib">>,<<"2.11.0">>},2},
|
{<<"cowlib">>,{pkg,<<"cowlib">>,<<"2.11.0">>},2},
|
||||||
{<<"damsel">>,
|
{<<"damsel">>,
|
||||||
{git,"https://github.com/valitydev/damsel.git",
|
{git,"https://github.com/valitydev/damsel.git",
|
||||||
{ref,"03bf41075c39b6731c5ed200d5c4b0faaee9d937"}},
|
{ref,"bfedcb9dbb0bfdbd7a06a86417b49be6e807b98d"}},
|
||||||
0},
|
0},
|
||||||
{<<"dmt_client">>,
|
{<<"dmt_client">>,
|
||||||
{git,"https://github.com/valitydev/dmt-client.git",
|
{git,"https://github.com/valitydev/dmt-client.git",
|
||||||
|
Loading…
Reference in New Issue
Block a user