Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,5 @@ tags
/.image.*
Makefile.env
*.iml
CLAUDE.md
.claude/
2 changes: 2 additions & 0 deletions .tool-versions
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
rebar 3.24.0
erlang 27.1.2
1 change: 1 addition & 0 deletions apps/hellgate/include/hg_invoice_payment.hrl
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
chargebacks = #{} :: #{hg_invoice_payment_chargeback:id() => hg_invoice_payment_chargeback:state()},
adjustments = [] :: [hg_invoice_payment:adjustment()],
recurrent_token :: undefined | dmsl_domain_thrift:'Token'(),
cascade_recurrent_tokens :: undefined | hg_customer_client:cascade_tokens(),
opts :: undefined | hg_invoice_payment:opts(),
repair_scenario :: undefined | hg_invoice_repair:scenario(),
capture_data :: undefined | hg_invoice_payment:capture_data(),
Expand Down
4 changes: 4 additions & 0 deletions apps/hellgate/include/payment_events.hrl
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@
{invoice_payment_rec_token_acquired, #payproc_InvoicePaymentRecTokenAcquired{token = Token}}
).

-define(cascade_tokens_loaded(Tokens),
{invoice_payment_cascade_tokens_loaded, #payproc_InvoicePaymentCascadeTokensLoaded{tokens = Tokens}}
).

-define(cash_changed(OldCash, NewCash),
{invoice_payment_cash_changed, #payproc_InvoicePaymentCashChanged{old_cash = OldCash, new_cash = NewCash}}
).
Expand Down
119 changes: 119 additions & 0 deletions apps/hellgate/src/hg_customer_client.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
-module(hg_customer_client).

-include_lib("damsel/include/dmsl_customer_thrift.hrl").
-include_lib("damsel/include/dmsl_domain_thrift.hrl").

-export([create_customer/1]).
-export([get_recurrent_tokens/2]).
-export([tokens_to_map/1]).
-export([save_recurrent_token/6]).

-export_type([cascade_tokens/0]).

-type invoice_id() :: dmsl_domain_thrift:'InvoiceID'().
-type payment_id() :: dmsl_domain_thrift:'InvoicePaymentID'().
-type provider_terminal_key() :: dmsl_customer_thrift:'ProviderTerminalKey'().
-type token() :: dmsl_domain_thrift:'Token'().
-type recurrent_token() :: dmsl_customer_thrift:'RecurrentToken'().
-type cascade_tokens() :: #{provider_terminal_key() => token()}.

%%

-spec create_customer(dmsl_domain_thrift:'PartyConfigRef'()) -> dmsl_customer_thrift:'Customer'().
create_customer(PartyConfigRef) ->
{ok, Customer} = call(customer_management, 'Create', {#customer_CustomerParams{party_ref = PartyConfigRef}}),
Customer.
Comment on lines +24 to +25
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ключа идемпотентности нет, в параметрах создания нет привязки, значит если что то пойдет не так - у тебя будет миллиард пустых кастумеров

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Например создание и сразу привязка к платежу? А если платеж не успешен? Я думал чтобы список платежей в кастомере был списком успешных платежей


-spec get_recurrent_tokens(invoice_id(), payment_id()) -> [recurrent_token()].
get_recurrent_tokens(InvoiceID, PaymentID) ->
case call(customer_management, 'GetByParentPayment', {InvoiceID, PaymentID}) of
{ok, #customer_CustomerState{bank_card_refs = BankCardRefs}} ->
lists:flatmap(fun collect_bank_card_tokens/1, BankCardRefs);
{exception, #customer_CustomerNotFound{}} ->
[];
{exception, #customer_InvalidRecurrentParent{}} ->
[]
end.

-spec tokens_to_map([recurrent_token()]) -> cascade_tokens().
tokens_to_map(Tokens) ->
lists:foldl(fun token_to_map_entry/2, #{}, Tokens).

-spec save_recurrent_token(
dmsl_customer_thrift:'CustomerID'(),
token(),
dmsl_domain_thrift:'PaymentRoute'(),
token(),
invoice_id(),
payment_id()
) -> ok.
save_recurrent_token(
CustomerID,
BankCardToken,
#domain_PaymentRoute{provider = ProviderRef, terminal = TerminalRef},
RecToken,
InvoiceID,
PaymentID
) ->
{ok, #customer_BankCard{id = BankCardID}} = call(
customer_management,
'AddBankCard',
{CustomerID, #customer_BankCardParams{bank_card_token = BankCardToken}}
),
{ok, _} = call(
bank_card_storage,
'AddRecurrentToken',
{#customer_RecurrentTokenParams{
bank_card_id = BankCardID,
provider_ref = ProviderRef,
terminal_ref = TerminalRef,
token = RecToken
}}
),
{ok, ok} = call(
customer_management,
'AddPayment',
{CustomerID, InvoiceID, PaymentID}
),
ok.

%%

call(ServiceName, Function, Args) ->
Service = hg_proto:get_service(ServiceName),
Opts = hg_woody_wrapper:get_service_options(ServiceName),
WoodyContext =
try
hg_context:get_woody_context(hg_context:load())
catch
error:badarg -> woody_context:new()
end,
Request = {Service, Function, Args},
woody_client:call(
Request,
Opts#{
event_handler => {
scoper_woody_event_handler,
genlib_app:env(hellgate, scoper_event_handler_options, #{})
}
},
WoodyContext
).

collect_bank_card_tokens(#customer_BankCardRef{id = BankCardID}) ->
{ok, Tokens} = call(bank_card_storage, 'GetRecurrentTokens', {BankCardID}),
Tokens.

token_to_map_entry(
#customer_RecurrentToken{
provider_ref = ProviderRef,
terminal_ref = TerminalRef,
token = Token
},
Acc
) ->
Key = #customer_ProviderTerminalKey{
provider_ref = ProviderRef,
terminal_ref = TerminalRef
},
Acc#{Key => Token}.
Loading
Loading