From 03c876b409d2c7774e9c9ac74cd7da6f8496fcb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D0=B5=D0=BC?= Date: Wed, 4 Jun 2025 18:21:33 +0300 Subject: [PATCH 1/7] Party here! (#60) * fixed compile * fixed wip 1 * fixed dialyzer * fixed tests --- apps/capi/src/capi_auth.erl | 10 +- apps/capi/src/capi_bouncer_context.erl | 43 +- apps/capi/src/capi_domain.erl | 28 +- apps/capi/src/capi_feature_schemas.erl | 171 +------ apps/capi/src/capi_handler.erl | 7 +- apps/capi/src/capi_handler_contracts.erl | 221 -------- apps/capi/src/capi_handler_customers.erl | 478 ------------------ .../src/capi_handler_decoder_invoicing.erl | 11 - apps/capi/src/capi_handler_decoder_party.erl | 113 +---- .../src/capi_handler_invoice_templates.erl | 9 +- apps/capi/src/capi_handler_invoices.erl | 8 +- apps/capi/src/capi_handler_parties.erl | 127 +---- apps/capi/src/capi_handler_payments.erl | 12 +- apps/capi/src/capi_handler_search.erl | 476 ----------------- apps/capi/src/capi_handler_shops.erl | 179 ++----- apps/capi/src/capi_handler_utils.erl | 19 +- apps/capi/src/capi_handler_webhooks.erl | 41 +- apps/capi/src/capi_party.erl | 79 ++- .../test/capi_authorization_tests_SUITE.erl | 18 +- .../test/capi_base_api_token_tests_SUITE.erl | 472 +---------------- apps/capi/test/capi_bouncer_data.hrl | 55 -- apps/capi/test/capi_ct_helper_bouncer.erl | 52 -- .../capi/test/capi_ct_helper_token_keeper.erl | 14 - ...capi_customer_access_token_tests_SUITE.erl | 316 ------------ .../keys/local/jwk.priv.json | 10 - .../keys/local/jwk.publ.json | 9 - .../keys/local/private.pem | 9 - apps/capi/test/capi_dummy_data.hrl | 324 ++---------- .../test/capi_idempotency_tests_SUITE.erl | 164 +----- .../capi_invoice_access_token_tests_SUITE.erl | 10 +- ...oice_template_access_token_tests_SUITE.erl | 3 +- .../test/capi_magista_stat_tests_SUITE.erl | 417 --------------- .../keys/local/dummy.pem | 13 - .../keys/local/jwk.json | 7 - .../keys/local/jwk.priv.json | 10 - .../keys/local/jwk.publ.json | 9 - .../keys/local/private.pem | 9 - .../keys/local/public.pem | 4 - apps/capi/test/capi_self_tests_SUITE.erl | 2 +- .../capi_client/src/capi_client_contracts.erl | 101 ---- .../capi_client/src/capi_client_customers.erl | 124 ----- apps/capi_client/src/capi_client_parties.erl | 57 --- apps/capi_client/src/capi_client_searches.erl | 35 -- apps/capi_client/src/capi_client_shops.erl | 49 -- .../src/capi_woody_client.erl | 6 +- rebar.config | 4 +- rebar.lock | 38 +- 47 files changed, 206 insertions(+), 4167 deletions(-) delete mode 100644 apps/capi/src/capi_handler_contracts.erl delete mode 100644 apps/capi/src/capi_handler_customers.erl delete mode 100644 apps/capi/src/capi_handler_search.erl delete mode 100644 apps/capi/test/capi_customer_access_token_tests_SUITE.erl delete mode 100644 apps/capi/test/capi_customer_access_token_tests_SUITE_data/keys/local/jwk.priv.json delete mode 100644 apps/capi/test/capi_customer_access_token_tests_SUITE_data/keys/local/jwk.publ.json delete mode 100644 apps/capi/test/capi_customer_access_token_tests_SUITE_data/keys/local/private.pem delete mode 100644 apps/capi/test/capi_magista_stat_tests_SUITE.erl delete mode 100644 apps/capi/test/capi_magista_stat_tests_SUITE_data/keys/local/dummy.pem delete mode 100644 apps/capi/test/capi_magista_stat_tests_SUITE_data/keys/local/jwk.json delete mode 100644 apps/capi/test/capi_magista_stat_tests_SUITE_data/keys/local/jwk.priv.json delete mode 100644 apps/capi/test/capi_magista_stat_tests_SUITE_data/keys/local/jwk.publ.json delete mode 100644 apps/capi/test/capi_magista_stat_tests_SUITE_data/keys/local/private.pem delete mode 100644 apps/capi/test/capi_magista_stat_tests_SUITE_data/keys/local/public.pem delete mode 100644 apps/capi_client/src/capi_client_contracts.erl delete mode 100644 apps/capi_client/src/capi_client_customers.erl delete mode 100644 apps/capi_client/src/capi_client_searches.erl diff --git a/apps/capi/src/capi_auth.erl b/apps/capi/src/capi_auth.erl index 2092f36..f26e0ba 100644 --- a/apps/capi/src/capi_auth.erl +++ b/apps/capi/src/capi_auth.erl @@ -27,7 +27,7 @@ -type consumer() :: client | merchant | provider. -type token_spec() :: #{ party := binary(), - scope := {invoice | invoice_template | customer, binary()}, + scope := {invoice | invoice_template, binary()}, shop => binary(), lifetime => pos_integer() | unlimited, metadata => token_keeper_client:metadata() @@ -132,7 +132,6 @@ issue_access_token(TokenSpec, WoodyContext) -> %% -define(DEFAULT_INVOICE_ACCESS_TOKEN_LIFETIME, 259200). --define(DEFAULT_CUSTOMER_ACCESS_TOKEN_LIFETIME, 259200). -include_lib("bouncer_proto/include/bouncer_ctx_v1_thrift.hrl"). @@ -169,7 +168,6 @@ resolve_auth_scope(TokenSpec) -> ). resolve_auth_method(#{scope := {invoice, _}}) -> ?CTX_V1_AUTHMETHOD_INVOICEACCESSTOKEN; -resolve_auth_method(#{scope := {customer, _}}) -> ?CTX_V1_AUTHMETHOD_CUSTOMERACCESSTOKEN; resolve_auth_method(#{scope := {invoice_template, _}}) -> ?CTX_V1_AUTHMETHOD_INVOICETEMPLATEACCESSTOKEN. resolve_auth_expiration(TokenSpec) -> @@ -187,13 +185,9 @@ get_token_lifetime(#{lifetime := LifeTime} = TokenSpec) when LifeTime =/= undefi get_token_lifetime(#{scope := {invoice, _}}) -> ?DEFAULT_INVOICE_ACCESS_TOKEN_LIFETIME; get_token_lifetime(#{scope := {invoice_template, _}}) -> - unlimited; -get_token_lifetime(#{scope := {customer, _}}) -> - ?DEFAULT_CUSTOMER_ACCESS_TOKEN_LIFETIME. + unlimited. -%% Forbid creation of unlimited lifetime invoice and customer tokens verify_token_lifetime(#{scope := {invoice, _}}, LifeTime) when LifeTime =/= unlimited -> ok; -verify_token_lifetime(#{scope := {customer, _}}, LifeTime) when LifeTime =/= unlimited -> ok; verify_token_lifetime(#{scope := {invoice_template, _}}, _LifeTime) -> ok. %% diff --git a/apps/capi/src/capi_bouncer_context.erl b/apps/capi/src/capi_bouncer_context.erl index ee48b1a..5800b19 100644 --- a/apps/capi/src/capi_bouncer_context.erl +++ b/apps/capi/src/capi_bouncer_context.erl @@ -26,21 +26,16 @@ id => swag_server:operation_id(), party => entity_id(), shop => entity_id(), - contract => entity_id(), invoice => entity_id(), payment => entity_id(), refund => entity_id(), invoice_template => entity_id(), - customer => entity_id(), - binding => entity_id(), - file => entity_id(), webhook => entity_id() }. -type prototype_payproc() :: #{ invoice => invoice_id() | invoice() | undefined, - invoice_template => invoice_template_id() | invoice_template() | undefined, - customer => customer_id() | customer() | undefined + invoice_template => invoice_template_id() | invoice_template() | undefined }. -type prototype_webhooks() :: #{ @@ -53,9 +48,6 @@ -type invoice_template_id() :: dmsl_domain_thrift:'InvoiceTemplateID'(). -type invoice_template() :: dmsl_domain_thrift:'InvoiceTemplate'(). --type customer_id() :: dmsl_payproc_thrift:'CustomerID'(). --type customer() :: dmsl_payproc_thrift:'Customer'(). - -type webhook_id() :: dmsl_webhooker_thrift:'WebhookID'(). -type webhook() :: dmsl_webhooker_thrift:'Webhook'(). @@ -93,14 +85,10 @@ build(operation, #{id := OperationID} = Params, Acc, _WoodyCtx) -> id = operation_id_to_binary(OperationID), party = maybe_entity(party, Params), shop = maybe_entity(shop, Params), - contract = maybe_entity(contract, Params), invoice = maybe_entity(invoice, Params), payment = maybe_entity(payment, Params), refund = maybe_entity(refund, Params), invoice_template = maybe_entity(invoice_template, Params), - customer = maybe_entity(customer, Params), - binding = maybe_entity(binding, Params), - file = maybe_entity(file, Params), webhook = maybe_entity(webhook, Params) } } @@ -117,11 +105,6 @@ build(payproc, #{} = Params, Acc, WoodyCtx) -> invoice_template, Params, fun(V) -> build_invoice_template_ctx(V, WoodyCtx) end - ), - customer = maybe_with( - customer, - Params, - fun(V) -> build_customer_ctx(V, WoodyCtx) end ) } }; @@ -184,28 +167,6 @@ build_invoice_template_ctx(#domain_InvoiceTemplate{id = ID, owner_id = OwnerID, shop = build_entity(ShopID) }. -build_customer_ctx(ID, WoodyCtx) when is_binary(ID) -> - maybe_with_woody_result( - customer_management, - 'Get', - {ID, #payproc_EventRange{}}, - WoodyCtx, - fun build_customer_ctx/1 - ); -build_customer_ctx(Customer, _WoodyCtx) -> - build_customer_ctx(Customer). - -build_customer_ctx(#payproc_Customer{id = ID, owner_id = OwnerID, shop_id = ShopID, bindings = Bindings}) -> - #ctx_v1_Customer{ - id = ID, - party = build_entity(OwnerID), - shop = build_entity(ShopID), - bindings = build_set(lists:map(fun build_binding_ctx/1, Bindings)) - }. - -build_binding_ctx(#payproc_CustomerBinding{id = ID}) -> - build_entity(ID). - %% build_webhook_ctx(ID, WoodyCtx) when is_integer(ID) -> @@ -230,8 +191,6 @@ build_webhook_filter_details(#webhooker_PartyEventFilter{}, Ctx) -> Ctx; build_webhook_filter_details(#webhooker_InvoiceEventFilter{shop_id = ShopID}, Ctx) -> Ctx#ctx_v1_WebhookFilter{shop = 'maybe'(ShopID, fun build_entity/1)}; -build_webhook_filter_details(#webhooker_CustomerEventFilter{shop_id = ShopID}, Ctx) -> - Ctx#ctx_v1_WebhookFilter{shop = 'maybe'(ShopID, fun build_entity/1)}; build_webhook_filter_details(#webhooker_WalletEventFilter{}, Ctx) -> Ctx. diff --git a/apps/capi/src/capi_domain.erl b/apps/capi/src/capi_domain.erl index 287dc3b..331314c 100644 --- a/apps/capi/src/capi_domain.erl +++ b/apps/capi/src/capi_domain.erl @@ -3,9 +3,12 @@ -include_lib("damsel/include/dmsl_domain_thrift.hrl"). -include_lib("damsel/include/dmsl_domain_conf_thrift.hrl"). +-export([head/0]). -export([get_payment_institution/2]). -export([get_payment_institutions/1]). -export([get/2]). +-export([get/3]). +-export([get_ext/3]). -export([get_objects_by_type/2]). -export([encode_enum/2]). -export([encode_enum/3]). @@ -14,6 +17,7 @@ -type processing_context() :: capi_handler:processing_context(). -type ref() :: dmsl_domain_thrift:'Reference'(). -type data() :: _. +-type revision() :: dmt_client:version(). -type payment_institution() :: dmsl_domain_thrift:'PaymentInstitution'(). -type payment_institution_ref() :: dmsl_domain_thrift:'PaymentInstitutionRef'(). @@ -21,6 +25,11 @@ -type realm() :: dmsl_domain_thrift:'PaymentInstitutionRealm'(). -export_type([realm/0]). +-export_type([revision/0]). + +-spec head() -> revision(). +head() -> + dmt_client:get_last_version(). -spec get_payment_institution(payment_institution_ref(), processing_context()) -> {ok, payment_institution()} | {error, not_found}. @@ -67,15 +76,32 @@ get_payment_institutions(Context) -> -spec get(ref(), processing_context() | undefined) -> {ok, data()} | {error, not_found}. get(Ref, Context) -> + get(Ref, latest, Context). + +-spec get(ref(), revision(), processing_context() | undefined) -> {ok, data()} | {error, not_found}. +get(Ref, Revision, Context) -> try Opts = make_opts(Context), - {_Type, Object} = dmt_client:checkout_object(latest, Ref, Opts), + {_Type, Object} = dmt_client:checkout_object(Revision, Ref, Opts), {ok, Object} catch throw:#'domain_conf_ObjectNotFound'{} -> {error, not_found} end. +-spec get_ext(ref(), revision(), processing_context() | undefined) -> {ok, data()} | {error, not_found}. +get_ext(Ref, Revision, Context) -> + try + Opts = make_opts(Context), + {ok, extract_data(dmt_client:checkout_object(Revision, Ref, Opts))} + catch + throw:#'domain_conf_ObjectNotFound'{} -> + {error, not_found} + end. + +extract_data({_Tag, {_Name, _Ref, Data}}) -> + Data. + -spec encode_enum(Type :: atom(), binary()) -> {ok, atom()} | {error, unknown_atom | unknown_variant}. encode_enum(Type, Binary) -> encode_enum(dmsl_domain_thrift, Type, Binary). diff --git a/apps/capi/src/capi_feature_schemas.erl b/apps/capi/src/capi_feature_schemas.erl index 709fb64..fe3e63d 100644 --- a/apps/capi/src/capi_feature_schemas.erl +++ b/apps/capi/src/capi_feature_schemas.erl @@ -23,7 +23,6 @@ -define(mobile_commerce, 17). -define(operator, 18). -define(phone, 19). --define(customer, 20). -define(recurrent, 21). -define(invoice, 22). -define(payment, 23). @@ -82,8 +81,6 @@ -export([invoice/0]). -export([invoice_template/0]). -export([refund/0]). --export([customer_binding/0]). --export([customer/0]). -spec payment() -> schema(). payment() -> @@ -103,10 +100,6 @@ payment() -> ?payer => { <<"payer">>, {union, <<"payerType">>, #{ - <<"CustomerPayer">> => - {?customer, #{ - ?customer => <<"customerID">> - }}, <<"RecurrentPayer">> => { ?recurrent, #{ ?recurrent => { @@ -173,25 +166,6 @@ refund() -> ?allocation => {<<"allocation">>, {set, allocation_transaction()}} }. --spec customer() -> schema(). -customer() -> - #{ - ?shop_id => <<"shopID">>, - ?contact_info => {<<"contactInfo">>, contact_info_schema()} - }. - --spec customer_binding() -> schema(). -customer_binding() -> - #{ - ?payment_resource => { - <<"paymentResource">>, - #{ - ?payment_session => <<"paymentSession">>, - ?payment_tool => {<<"paymentTool">>, payment_tool_schema()} - } - } - }. - -spec payment_tool_schema() -> schema(). payment_tool_schema() -> {union, <<"type">>, #{ @@ -331,22 +305,6 @@ lifetime_schema() -> ?years => <<"years">> }. --spec contact_info_schema() -> schema(). -contact_info_schema() -> - #{ - ?email => <<"email">>, - ?phone_number => <<"phoneNumber">>, - ?first_name => <<"firstName">>, - ?last_name => <<"lastName">>, - ?country => <<"country">>, - ?state => <<"state">>, - ?city => <<"city">>, - ?address => <<"address">>, - ?postal_code => <<"postalCode">>, - ?date_of_birth => <<"dateOfBirth">>, - ?document_id => <<"documentId">> - }. - -ifdef(TEST). -include_lib("eunit/include/eunit.hrl"). -include_lib("capi_dummy_data.hrl"). @@ -458,27 +416,6 @@ compare_different_payment_tool_test() -> common_compare_tests(payment(), Request1, Request2, [<<"payer">>]). --spec read_payment_customer_features_value_test() -> _. -read_payment_customer_features_value_test() -> - PayerType = <<"CustomerPayer">>, - CustomerID = <<"some customer id">>, - Request = #{ - <<"payer">> => #{ - <<"payerType">> => PayerType, - <<"customerID">> => CustomerID - } - }, - Features = read(payment(), Request), - ?assertEqual( - #{ - ?invoice_id => undefined, - ?make_recurrent => undefined, - ?flow => undefined, - ?payer => [?customer, #{?customer => hash(CustomerID)}] - }, - Features - ). - -spec read_invoice_features_test() -> _. read_invoice_features_test() -> ShopID = <<"shopus">>, @@ -613,100 +550,6 @@ compare_invoices_features_test() -> ), ?assert(compare(Invoice1, Invoice1#{?cart => undefined})). --spec read_customer_features_test() -> _. -read_customer_features_test() -> - Request = ?CUSTOMER_PARAMS, - Features = #{ - ?shop_id => hash(?STRING), - ?contact_info => #{ - ?email => hash(<<"bla@bla.ru">>), - ?phone_number => undefined, - ?first_name => undefined, - ?last_name => undefined, - ?country => undefined, - ?state => undefined, - ?city => undefined, - ?address => undefined, - ?postal_code => undefined, - ?date_of_birth => undefined, - ?document_id => undefined - } - }, - ?assertEqual( - Features, - read(customer(), Request) - ). - --spec compare_customer_features_test() -> _. -compare_customer_features_test() -> - Request = ?CUSTOMER_PARAMS, - RequestSame = Request#{ - <<"partyID">> => <<"ANOTHER PARTY">>, - - <<"metadata">> => #{<<"text">> => <<"sample text">>} - }, - RequestDifferent = Request#{ - <<"shopID">> => hash(<<"Another shop">>), - <<"contactInfo">> => #{ - <<"email">> => hash(<<"bla@example.com">>), - <<"phoneNumber">> => <<"8-800-555-35-35">>, - <<"firstName">> => <<"firstName">>, - <<"lastName">> => <<"lastName">>, - <<"country">> => <<"country">>, - <<"state">> => <<"state">>, - <<"city">> => <<"city">>, - <<"address">> => <<"address">>, - <<"postalCode">> => <<"postalCode">>, - <<"dateOfBirth">> => <<"dateOfBirth">>, - <<"documentId">> => <<"documentId">> - } - }, - common_compare_tests( - customer(), - Request, - RequestSame, - RequestDifferent, - all - ). - --spec read_customer_binding_features_test() -> _. -read_customer_binding_features_test() -> - Session = ?TEST_PAYMENT_SESSION(<<"Session">>), - Tool = ?TEST_PAYMENT_TOOL(<<"visa">>, <<"TOKEN">>), - Request = payment_resource(Session, Tool), - Features = #{ - ?payment_resource => #{ - ?payment_session => hash(Session), - ?payment_tool => [ - ?bank_card, - #{ - ?token => hash(<<"TOKEN">>), - ?exp_date => hash(<<"12/2012">>) - } - ] - } - }, - - ?assertEqual( - Features, - read(customer_binding(), Request) - ). - --spec compare_customer_binding_features_test() -> _. -compare_customer_binding_features_test() -> - Session1 = ?TEST_PAYMENT_SESSION(<<"Session1">>), - Tool1 = ?TEST_PAYMENT_TOOL(<<"visa">>), - Request1 = payment_resource(Session1, Tool1), - - Session2 = ?TEST_PAYMENT_SESSION(<<"Session2">>), - Tool2 = maps:merge(?TEST_PAYMENT_TOOL(<<"mastercard">>), #{<<"exp_date">> => <<"01/2020">>}), - Request2 = payment_resource(Session2, Tool2), - - common_compare_tests(customer_binding(), Request1, Request2, [ - <<"paymentResource.paymentTool.exp_date">>, - <<"paymentResource.paymentSession">> - ]). - %% Add invoice_template tests -spec read_invoice_template_features_test() -> _. @@ -914,13 +757,13 @@ demo_compare_allocation_transaction_test() -> %% -payment_resource(Session, Tool) -> - #{ - <<"paymentResource">> => #{ - <<"paymentSession">> => Session, - <<"paymentTool">> => Tool - } - }. +% payment_resource(Session, Tool) -> +% #{ +% <<"paymentResource">> => #{ +% <<"paymentSession">> => Session, +% <<"paymentTool">> => Tool +% } +% }. payment_params(PaymentTool) -> deep_merge( diff --git a/apps/capi/src/capi_handler.erl b/apps/capi/src/capi_handler.erl index 6791548..f4e56ee 100644 --- a/apps/capi/src/capi_handler.erl +++ b/apps/capi/src/capi_handler.erl @@ -103,15 +103,12 @@ map_error(validation_error, Error) -> get_handlers() -> [ capi_handler_categories, - capi_handler_contracts, capi_handler_countries, - capi_handler_customers, capi_handler_invoice_templates, capi_handler_invoices, capi_handler_parties, capi_handler_payment_institutions, capi_handler_payments, - capi_handler_search, capi_handler_shops, capi_handler_trade_blocs, capi_handler_webhooks @@ -322,10 +319,8 @@ set_request_meta(OperationID, Req) -> InterestParams = [ 'invoiceID', 'invoiceTemplateID', - 'contractID', 'webhookID', - 'shopID', - 'customerID' + 'shopID' ], Meta = #{ operation_id => OperationID, diff --git a/apps/capi/src/capi_handler_contracts.erl b/apps/capi/src/capi_handler_contracts.erl deleted file mode 100644 index cb1c4dc..0000000 --- a/apps/capi/src/capi_handler_contracts.erl +++ /dev/null @@ -1,221 +0,0 @@ --module(capi_handler_contracts). - --include_lib("damsel/include/dmsl_payproc_thrift.hrl"). --include_lib("damsel/include/dmsl_domain_thrift.hrl"). - --behaviour(capi_handler). - --export([prepare/3]). - --import(capi_handler_utils, [general_error/2]). - --spec prepare( - OperationID :: capi_handler:operation_id(), - Req :: capi_handler:request_data(), - Context :: capi_handler:processing_context() -) -> {ok, capi_handler:request_state()} | {error, noimpl}. -prepare('GetContracts' = OperationID, _Req, Context) -> - PartyID = capi_handler_utils:get_party_id(Context), - Authorize = fun() -> - Prototypes = [ - {operation, #{party => PartyID, id => OperationID}} - ], - {ok, capi_auth:authorize_operation(Prototypes, Context)} - end, - Process = fun() -> - {ok, Party} = capi_party:get_party(PartyID, Context), - {ok, {200, #{}, decode_contracts_map(Party#domain_Party.contracts, Party#domain_Party.contractors)}} - end, - {ok, #{authorize => Authorize, process => Process}}; -prepare('GetContractByID' = OperationID, Req, Context) -> - ContractID = maps:get('contractID', Req), - PartyID = capi_handler_utils:get_party_id(Context), - Authorize = fun() -> - Prototypes = [ - {operation, #{party => PartyID, contract => ContractID, id => OperationID}} - ], - {ok, capi_auth:authorize_operation(Prototypes, Context)} - end, - Process = fun() -> - % Получение Party требуется для извлечения domain_Party.contractors - {ok, Party} = capi_party:get_party(PartyID, Context), - case genlib_map:get(ContractID, Party#domain_Party.contracts) of - undefined -> - {ok, general_error(404, <<"Contract not found">>)}; - Contract -> - {ok, {200, #{}, decode_contract(Contract, Party#domain_Party.contractors)}} - end - end, - {ok, #{authorize => Authorize, process => Process}}; -prepare('GetContractAdjustments' = OperationID, Req, Context) -> - ContractID = maps:get('contractID', Req), - PartyID = capi_handler_utils:get_party_id(Context), - Authorize = fun() -> - Prototypes = [ - {operation, #{party => PartyID, contract => ContractID, id => OperationID}} - ], - {ok, capi_auth:authorize_operation(Prototypes, Context)} - end, - Process = fun() -> - Contract = get_contract_or_fail(PartyID, ContractID, Context), - Resp = [decode_contract_adjustment(A) || A <- Contract#domain_Contract.adjustments], - {ok, {200, #{}, Resp}} - end, - {ok, #{authorize => Authorize, process => Process}}; -prepare('GetContractAdjustmentByID' = OperationID, Req, Context) -> - ContractID = maps:get('contractID', Req), - PartyID = capi_handler_utils:get_party_id(Context), - Authorize = fun() -> - Prototypes = [ - {operation, #{party => PartyID, contract => ContractID, id => OperationID}} - ], - {ok, capi_auth:authorize_operation(Prototypes, Context)} - end, - Process = fun() -> - Contract = get_contract_or_fail(PartyID, ContractID, Context), - AdjustmentID = maps:get('adjustmentID', Req), - Adjustments = Contract#domain_Contract.adjustments, - case lists:keyfind(AdjustmentID, #domain_ContractAdjustment.id, Adjustments) of - #domain_ContractAdjustment{} = A -> - {ok, {200, #{}, decode_contract_adjustment(A)}}; - false -> - {ok, general_error(404, <<"Adjustment not found">>)} - end - end, - {ok, #{authorize => Authorize, process => Process}}; -prepare('GetContractsForParty' = OperationID, Req, Context) -> - PartyID = maps:get('partyID', Req), - Authorize = fun() -> - Prototypes = [ - {operation, #{party => PartyID, id => OperationID}} - ], - {ok, capi_auth:authorize_operation(Prototypes, Context)} - end, - Process = fun() -> - case capi_party:get_party(PartyID, Context) of - {ok, Party} -> - {ok, {200, #{}, decode_contracts_map(Party#domain_Party.contracts, Party#domain_Party.contractors)}}; - {error, #payproc_PartyNotFound{}} -> - {ok, general_error(404, <<"Party not found">>)} - end - end, - {ok, #{authorize => Authorize, process => Process}}; -prepare('GetContractByIDForParty' = OperationID, Req, Context) -> - ContractID = maps:get('contractID', Req), - PartyID = maps:get('partyID', Req), - Authorize = fun() -> - Prototypes = [ - {operation, #{party => PartyID, contract => ContractID, id => OperationID}} - ], - {ok, capi_auth:authorize_operation(Prototypes, Context)} - end, - Process = fun() -> - Contract = get_contract_or_fail(PartyID, ContractID, Context), - % Получение Party требуется для извлечения domain_Party.contractors - {ok, Party} = capi_party:get_party(PartyID, Context), - {ok, {200, #{}, decode_contract(Contract, Party#domain_Party.contractors)}} - end, - {ok, #{authorize => Authorize, process => Process}}; -prepare('GetContractAdjustmentsForParty' = OperationID, Req, Context) -> - ContractID = maps:get('contractID', Req), - PartyID = maps:get('partyID', Req), - Authorize = fun() -> - Prototypes = [ - {operation, #{party => PartyID, contract => ContractID, id => OperationID}} - ], - {ok, capi_auth:authorize_operation(Prototypes, Context)} - end, - Process = fun() -> - Contract = get_contract_or_fail(PartyID, ContractID, Context), - Resp = [decode_contract_adjustment(A) || A <- Contract#domain_Contract.adjustments], - {ok, {200, #{}, Resp}} - end, - {ok, #{authorize => Authorize, process => Process}}; -prepare('GetContractAdjustmentByIDForParty' = OperationID, Req, Context) -> - ContractID = maps:get('contractID', Req), - PartyID = maps:get('partyID', Req), - Authorize = fun() -> - Prototypes = [ - {operation, #{party => PartyID, contract => ContractID, id => OperationID}} - ], - {ok, capi_auth:authorize_operation(Prototypes, Context)} - end, - Process = fun() -> - Contract = get_contract_or_fail(PartyID, ContractID, Context), - AdjustmentID = maps:get('adjustmentID', Req), - Adjustments = Contract#domain_Contract.adjustments, - case lists:keyfind(AdjustmentID, #domain_ContractAdjustment.id, Adjustments) of - #domain_ContractAdjustment{} = A -> - {ok, {200, #{}, decode_contract_adjustment(A)}}; - false -> - {ok, general_error(404, <<"Adjustment not found">>)} - end - end, - {ok, #{authorize => Authorize, process => Process}}; -prepare(_OperationID, _Req, _Context) -> - {error, noimpl}. - -get_contract_or_fail(PartyID, ContractID, Context) -> - case capi_party:get_contract(PartyID, ContractID, Context) of - {ok, Contract} -> - Contract; - {error, #payproc_PartyNotFound{}} -> - capi_handler:respond(general_error(404, <<"Party not found">>)); - {error, #payproc_ContractNotFound{}} -> - capi_handler:respond(general_error(404, <<"Contract not found">>)) - end. - -%% - -decode_contracts_map(Contracts, Contractors) -> - capi_handler_decoder_utils:decode_map(Contracts, fun(C) -> decode_contract(C, Contractors) end). - -decode_contract(Contract, Contractors) -> - capi_handler_utils:merge_and_compact( - #{ - <<"id">> => Contract#domain_Contract.id, - <<"createdAt">> => Contract#domain_Contract.created_at, - <<"contractor">> => capi_handler_decoder_party:decode_contractor( - get_contractor(Contract, Contractors) - ), - <<"paymentInstitutionID">> => - capi_handler_decoder_party:decode_payment_institution_ref(Contract#domain_Contract.payment_institution), - <<"validSince">> => Contract#domain_Contract.valid_since, - <<"validUntil">> => Contract#domain_Contract.valid_until, - <<"legalAgreement">> => capi_handler_decoder_utils:decode_optional( - Contract#domain_Contract.legal_agreement, - fun capi_handler_decoder_party:decode_legal_agreement/1 - ), - <<"reportingPreferences">> => capi_handler_decoder_utils:decode_optional( - Contract#domain_Contract.report_preferences, - fun capi_handler_decoder_party:decode_reporting_preferences/1 - ) - }, - decode_contract_status(Contract#domain_Contract.status) - ). - -decode_contract_status({active, _}) -> - #{ - <<"status">> => <<"active">> - }; -decode_contract_status({terminated, #domain_ContractTerminated{terminated_at = TerminatedAt}}) -> - #{ - <<"status">> => <<"terminated">>, - <<"terminatedAt">> => TerminatedAt - }. - -get_contractor(#domain_Contract{contractor = Contractor}, _) when Contractor =/= undefined -> - Contractor; -get_contractor(#domain_Contract{contractor_id = ContractorID}, Contractors) -> - #domain_PartyContractor{ - contractor = Contractor - } = maps:get(ContractorID, Contractors), - Contractor. - -decode_contract_adjustment(ContractAdjustment) -> - genlib_map:compact(#{ - <<"id">> => ContractAdjustment#domain_ContractAdjustment.id, - <<"createdAt">> => ContractAdjustment#domain_ContractAdjustment.created_at, - <<"validSince">> => ContractAdjustment#domain_ContractAdjustment.valid_since, - <<"validUntil">> => ContractAdjustment#domain_ContractAdjustment.valid_until - }). diff --git a/apps/capi/src/capi_handler_customers.erl b/apps/capi/src/capi_handler_customers.erl deleted file mode 100644 index 13aaa86..0000000 --- a/apps/capi/src/capi_handler_customers.erl +++ /dev/null @@ -1,478 +0,0 @@ --module(capi_handler_customers). - --include_lib("damsel/include/dmsl_payproc_thrift.hrl"). --include_lib("damsel/include/dmsl_domain_thrift.hrl"). - --behaviour(capi_handler). - --export([prepare/3]). - --import(capi_handler_utils, [ - general_error/2, - logic_error/1, - logic_error/2, - conflict_error/1, - map_service_result/1 -]). - --spec prepare( - OperationID :: capi_handler:operation_id(), - Req :: capi_handler:request_data(), - Context :: capi_handler:processing_context() -) -> {ok, capi_handler:request_state()} | {error, noimpl}. -prepare('CreateCustomer' = OperationID, Req, Context) -> - CustomerParams = maps:get('CustomerParams', Req), - PartyID = maps:get(<<"partyID">>, CustomerParams, capi_handler_utils:get_party_id(Context)), - ShopID = maps:get(<<"shopID">>, CustomerParams), - Authorize = fun() -> - Prototypes = [{operation, #{id => OperationID, party => PartyID, shop => ShopID}}], - {ok, capi_auth:authorize_operation(Prototypes, Context)} - end, - Process = fun() -> - try - CustomerID = generate_customer_id(OperationID, PartyID, CustomerParams, Context), - EncodedCustomerParams = encode_customer_params(CustomerID, PartyID, CustomerParams), - Call = {customer_management, 'Create', {EncodedCustomerParams}}, - case capi_handler_utils:service_call(Call, Context) of - {ok, Customer} -> - {ok, {201, #{}, make_customer_and_token(Customer, Context)}}; - {exception, #payproc_InvalidPartyStatus{}} -> - {ok, logic_error('invalidPartyStatus', <<"Invalid party status">>)}; - {exception, #payproc_InvalidShopStatus{}} -> - {ok, logic_error('invalidShopStatus', <<"Invalid shop status">>)}; - {exception, #payproc_ShopNotFound{}} -> - {ok, logic_error('invalidShopID', <<"Shop not found">>)}; - {exception, #payproc_PartyNotFound{}} -> - {ok, logic_error('invalidPartyID', <<"Party not found">>)}; - {exception, #payproc_OperationNotPermitted{}} -> - {ok, logic_error('operationNotPermitted', <<"Operation not permitted">>)} - end - catch - throw:{external_id_conflict, ID, UsedExternalID, _Schema} -> - {ok, conflict_error({ID, UsedExternalID})} - end - end, - {ok, #{authorize => Authorize, process => Process}}; -prepare('GetCustomerById' = OperationID, Req, Context) -> - CustomerID = maps:get('customerID', Req), - Customer = map_service_result(get_customer_by_id(CustomerID, Context)), - Authorize = fun() -> - Prototypes = [ - {operation, #{id => OperationID, customer => CustomerID}}, - {payproc, #{customer => Customer}} - ], - {ok, mask_customer_notfound(capi_auth:authorize_operation(Prototypes, Context))} - end, - Process = fun() -> - case Customer of - #payproc_Customer{} -> - {ok, {200, #{}, decode_customer(Customer)}}; - undefined -> - {ok, general_error(404, <<"Customer not found">>)} - end - end, - {ok, #{authorize => Authorize, process => Process}}; -prepare('DeleteCustomer' = OperationID, Req, Context) -> - CustomerID = maps:get('customerID', Req), - Authorize = fun() -> - Prototypes = [ - {operation, #{id => OperationID, customer => CustomerID}}, - {payproc, #{customer => CustomerID}} - ], - {ok, capi_auth:authorize_operation(Prototypes, Context)} - end, - Process = fun() -> - Call = {customer_management, 'Delete', {CustomerID}}, - case capi_handler_utils:service_call(Call, Context) of - {ok, _} -> - {ok, {204, #{}, undefined}}; - {exception, #payproc_CustomerNotFound{}} -> - {ok, general_error(404, <<"Customer not found">>)}; - {exception, #payproc_InvalidPartyStatus{}} -> - {ok, logic_error('invalidPartyStatus', <<"Invalid party status">>)}; - {exception, #payproc_InvalidShopStatus{}} -> - {ok, logic_error('invalidShopStatus', <<"Invalid shop status">>)} - end - end, - {ok, #{authorize => Authorize, process => Process}}; -prepare('CreateCustomerAccessToken' = OperationID, Req, Context) -> - CustomerID = maps:get('customerID', Req), - Customer = map_service_result(get_customer_by_id(CustomerID, Context)), - Authorize = fun() -> - Prototypes = [ - {operation, #{id => OperationID, customer => CustomerID}}, - {payproc, #{customer => Customer}} - ], - {ok, capi_auth:authorize_operation(Prototypes, Context)} - end, - Process = fun() -> - case Customer of - #payproc_Customer{} -> - Response = capi_handler_utils:issue_access_token(Customer, Context), - {ok, {201, #{}, Response}}; - undefined -> - {ok, general_error(404, <<"Customer not found">>)} - end - end, - {ok, #{authorize => Authorize, process => Process}}; -prepare('CreateBinding' = OperationID, Req, Context) -> - CustomerID = maps:get('customerID', Req), - Authorize = fun() -> - Prototypes = [ - {operation, #{id => OperationID, customer => CustomerID}}, - {payproc, #{customer => CustomerID}} - ], - {ok, capi_auth:authorize_operation(Prototypes, Context)} - end, - Process = fun() -> - Result = - try - CustomerBindingParams = maps:get('CustomerBindingParams', Req), - - {CustomerBindingID, RecPaymentToolID} = generate_binding_ids( - OperationID, - CustomerBindingParams, - Context - ), - - EncodedCustomerBindingParams = encode_customer_binding_params( - CustomerBindingID, - RecPaymentToolID, - CustomerBindingParams - ), - - Call = {customer_management, 'StartBinding', {CustomerID, EncodedCustomerBindingParams}}, - capi_handler_utils:service_call(Call, Context) - catch - throw:invalid_payment_session -> - {error, invalid_payment_session}; - throw:Error = {external_id_conflict, _, _, _} -> - {error, Error} - end, - case Result of - {ok, CustomerBinding} -> - {ok, {201, #{}, decode_customer_binding(CustomerBinding)}}; - {exception, #payproc_CustomerNotFound{}} -> - {ok, general_error(404, <<"Customer not found">>)}; - {exception, #payproc_InvalidPartyStatus{}} -> - {ok, logic_error('invalidPartyStatus', <<"Invalid party status">>)}; - {exception, #payproc_InvalidShopStatus{}} -> - {ok, logic_error('invalidShopStatus', <<"Invalid shop status">>)}; - {exception, #payproc_InvalidContractStatus{}} -> - {ok, logic_error('invalidRequest', <<"Invalid contract status">>)}; - {exception, #payproc_OperationNotPermitted{}} -> - {ok, logic_error('operationNotPermitted', <<"Operation not permitted">>)}; - {error, invalid_payment_session} -> - {ok, logic_error('invalidPaymentSession', <<"Specified payment session is invalid">>)}; - {error, {external_id_conflict, ID, UsedExternalID, _Schema}} -> - {ok, conflict_error({ID, UsedExternalID})} - end - end, - {ok, #{authorize => Authorize, process => Process}}; -prepare('GetBindings' = OperationID, Req, Context) -> - CustomerID = maps:get('customerID', Req), - Customer = map_service_result(get_customer_by_id(CustomerID, Context)), - Authorize = fun() -> - Prototypes = [ - {operation, #{id => OperationID, customer => CustomerID}}, - {payproc, #{customer => Customer}} - ], - {ok, mask_customer_notfound(capi_auth:authorize_operation(Prototypes, Context))} - end, - Process = fun() -> - _ = capi_handler:respond_if_undefined(Customer, general_error(404, <<"Customer not found">>)), - {ok, {200, #{}, [decode_customer_binding(B) || B <- Customer#payproc_Customer.bindings]}} - end, - {ok, #{authorize => Authorize, process => Process}}; -prepare('GetBinding' = OperationID, Req, Context) -> - CustomerID = maps:get('customerID', Req), - CustomerBindingID = maps:get('customerBindingID', Req), - Customer = map_service_result(get_customer_by_id(CustomerID, Context)), - Authorize = fun() -> - Prototypes = [ - {operation, #{id => OperationID, customer => CustomerID, binding => CustomerBindingID}}, - {payproc, #{customer => Customer}} - ], - {ok, mask_customer_notfound(capi_auth:authorize_operation(Prototypes, Context))} - end, - Process = fun() -> - _ = capi_handler:respond_if_undefined(Customer, general_error(404, <<"Customer not found">>)), - Bindings = Customer#payproc_Customer.bindings, - case lists:keyfind(CustomerBindingID, #payproc_CustomerBinding.id, Bindings) of - #payproc_CustomerBinding{} = B -> - {ok, {200, #{}, decode_customer_binding(B)}}; - false -> - {ok, general_error(404, <<"Customer binding not found">>)} - end - end, - {ok, #{authorize => Authorize, process => Process}}; -prepare('GetCustomerEvents' = OperationID, Req, Context) -> - CustomerID = maps:get('customerID', Req), - Authorize = fun() -> - Prototypes = [ - {operation, #{id => OperationID, customer => CustomerID}}, - {payproc, #{customer => CustomerID}} - ], - {ok, mask_customer_notfound(capi_auth:authorize_operation(Prototypes, Context))} - end, - Process = fun() -> - GetterFun = fun(Range) -> - capi_handler_utils:service_call( - {customer_management, 'GetEvents', {CustomerID, Range}}, - Context - ) - end, - Result = capi_handler_utils:collect_events( - maps:get('limit', Req), - genlib_map:get('eventID', Req), - GetterFun, - fun decode_customer_event/1 - ), - case Result of - {ok, Events} when is_list(Events) -> - {ok, {200, #{}, Events}}; - {exception, #payproc_CustomerNotFound{}} -> - {ok, general_error(404, <<"Customer not found">>)}; - {exception, #payproc_EventNotFound{}} -> - {ok, general_error(404, <<"Event not found">>)} - end - end, - {ok, #{authorize => Authorize, process => Process}}; -prepare('GetCustomerPaymentMethods' = OperationID, Req, Context) -> - CustomerID = maps:get('customerID', Req), - Customer = map_service_result(get_customer_by_id(CustomerID, Context)), - Authorize = fun() -> - Prototypes = [ - {operation, #{id => OperationID, customer => CustomerID}}, - {payproc, #{customer => Customer}} - ], - {ok, mask_customer_notfound(capi_auth:authorize_operation(Prototypes, Context))} - end, - Process = fun() -> - capi_handler:respond_if_undefined(Customer, general_error(404, <<"Customer not found">>)), - PartyID = Customer#payproc_Customer.owner_id, - % В данном контексте - Party не может не существовать - {ok, Party} = capi_party:get_party(PartyID, Context), - Args = {CustomerID, {revision, Party#domain_Party.revision}}, - case capi_handler_utils:get_payment_methods(customer_management, Args, Context) of - {ok, PaymentMethodRefs} -> - PaymentMethods0 = capi_handler_decoder_invoicing:decode_payment_methods(PaymentMethodRefs), - PaymentMethods1 = capi_utils:deduplicate_payment_methods(PaymentMethods0), - PaymentMethods = capi_handler_utils:emplace_token_provider_data(Customer, PaymentMethods1, Context), - {ok, {200, #{}, PaymentMethods}}; - {exception, #payproc_CustomerNotFound{}} -> - {ok, general_error(404, <<"Customer not found">>)} - end - end, - {ok, #{authorize => Authorize, process => Process}}; -prepare(_OperationID, _Req, _Context) -> - {error, noimpl}. - -%% - -get_customer_by_id(CustomerID, Context) -> - EventRange = #payproc_EventRange{}, - capi_handler_utils:service_call({customer_management, 'Get', {CustomerID, EventRange}}, Context). - -mask_customer_notfound(Resolution) -> - % ED-206 - % When bouncer says "forbidden" we can't really tell the difference between "forbidden because - % of no such customer", "forbidden because client has no access to it" and "forbidden because - % client has no permission to act on it". From the point of view of existing integrations this - % is not great, so we have to mask specific instances of missing authorization as if specified - % customer is nonexistent. - capi_handler:respond_if_forbidden(Resolution, general_error(404, <<"Customer not found">>)). - -generate_customer_id(OperationID, PartyID, CustomerParams, #{woody_context := WoodyContext}) -> - ExternalID = maps:get(<<"externalID">>, CustomerParams, undefined), - IdempKey = {OperationID, PartyID, ExternalID}, - Identity = capi_bender:make_identity(capi_feature_schemas:customer(), CustomerParams), - capi_bender:gen_snowflake(IdempKey, Identity, WoodyContext). - -encode_customer_params(CustomerID, PartyID, Params) -> - #payproc_CustomerParams{ - customer_id = CustomerID, - party_id = PartyID, - shop_id = genlib_map:get(<<"shopID">>, Params), - contact_info = capi_handler_encoder:encode_contact_info(genlib_map:get(<<"contactInfo">>, Params)), - metadata = encode_customer_metadata(genlib_map:get(<<"metadata">>, Params)) - }. - -encode_customer_metadata(Meta) -> - capi_json_marshalling:marshal(Meta). - -generate_binding_ids(OperationID, CustomerBindingParams, #{woody_context := WoodyContext} = Context) -> - ExternalID = maps:get(<<"externalID">>, CustomerBindingParams, undefined), - PartyID = capi_handler_utils:get_party_id(Context), - - PaymentResource = maps:get(<<"paymentResource">>, CustomerBindingParams), - PaymentToolToken = maps:get(<<"paymentToolToken">>, PaymentResource), - PaymentTool = capi_handler_decoder_invoicing:decode_payment_tool(encode_payment_tool_token(PaymentToolToken)), - CustomerBindingParamsEncrypted = - maps:put( - <<"paymentResource">>, - maps:put( - <<"paymentTool">>, - PaymentTool, - maps:remove(<<"paymentToolToken">>, PaymentResource) - ), - CustomerBindingParams - ), - - Identity = capi_bender:make_identity( - capi_feature_schemas:customer_binding(), - CustomerBindingParamsEncrypted - ), - - OperationIDBin = erlang:atom_to_binary(OperationID), - CustomerBindingID = capi_bender:gen_snowflake( - {<>, PartyID, ExternalID}, - Identity, - WoodyContext - ), - RecPaymentToolID = capi_bender:gen_snowflake( - {<>, PartyID, ExternalID}, - Identity, - WoodyContext - ), - {CustomerBindingID, RecPaymentToolID}. - -encode_customer_binding_params( - CustomerBindingID, - RecPaymentToolID, - #{<<"paymentResource">> := PaymentResource} -) -> - PaymentToolToken = maps:get(<<"paymentToolToken">>, PaymentResource), - PaymentTool = encode_payment_tool_token(PaymentToolToken), - - {ClientInfo, PaymentSession} = - capi_handler_utils:unwrap_payment_session(maps:get(<<"paymentSession">>, PaymentResource)), - - #payproc_CustomerBindingParams{ - customer_binding_id = CustomerBindingID, - rec_payment_tool_id = RecPaymentToolID, - payment_resource = #domain_DisposablePaymentResource{ - payment_tool = PaymentTool, - payment_session_id = PaymentSession, - client_info = capi_handler_encoder:encode_client_info(ClientInfo) - } - }. - -encode_payment_tool_token(Token) -> - case capi_crypto:decode_token(Token) of - {ok, TokenData} -> - #{payment_tool := PaymentTool, valid_until := ValidUntil} = TokenData, - case capi_utils:deadline_is_reached(ValidUntil) of - true -> - logger:info("Payment tool token expired: ~p", [capi_utils:deadline_to_binary(ValidUntil)]), - capi_handler:respond(logic_error('invalidPaymentToolToken')); - _ -> - PaymentTool - end; - unrecognized -> - capi_handler:respond(logic_error('invalidPaymentToolToken')); - {error, {decryption_failed, Error}} -> - logger:info("Payment tool token decryption failed: ~p", [Error]), - capi_handler:respond(logic_error('invalidPaymentToolToken')) - end. - -make_customer_and_token(Customer, ProcessingContext) -> - #{ - <<"customer">> => decode_customer(Customer), - <<"customerAccessToken">> => capi_handler_utils:issue_access_token(Customer, ProcessingContext) - }. - -decode_customer(Customer) -> - #{ - <<"id">> => Customer#payproc_Customer.id, - <<"shopID">> => Customer#payproc_Customer.shop_id, - <<"status">> => decode_customer_status(Customer#payproc_Customer.status), - <<"contactInfo">> => - capi_handler_decoder_party:decode_contact_info(Customer#payproc_Customer.contact_info), - <<"metadata">> => decode_customer_metadata(Customer#payproc_Customer.metadata) - }. - -decode_customer_status({Status, _}) -> - erlang:atom_to_binary(Status, utf8). - -decode_customer_metadata(Meta) -> - capi_json_marshalling:unmarshal(Meta). - -decode_customer_binding(CustomerBinding) -> - capi_handler_utils:merge_and_compact( - #{ - <<"id">> => CustomerBinding#payproc_CustomerBinding.id, - <<"paymentResource">> => - capi_handler_decoder_invoicing:decode_disposable_payment_resource( - CustomerBinding#payproc_CustomerBinding.payment_resource - ) - }, - decode_customer_binding_status(CustomerBinding#payproc_CustomerBinding.status) - ). - -decode_customer_binding_status({Status, StatusInfo}) -> - Error = - case StatusInfo of - #payproc_CustomerBindingFailed{failure = OperationFailure} -> - capi_handler_decoder_utils:decode_operation_failure(OperationFailure); - _ -> - undefined - end, - #{ - <<"status">> => genlib:to_binary(Status), - <<"error">> => Error - }. - -decode_customer_event(#payproc_Event{source = {customer_id, _}, payload = Payload} = Event) -> - case decode_customer_changes(Payload) of - [_Something | _] = Changes -> - {true, #{ - <<"id">> => Event#payproc_Event.id, - <<"createdAt">> => Event#payproc_Event.created_at, - <<"changes">> => Changes - }}; - [] -> - false - end. - -decode_customer_changes({customer_changes, CustomerChanges}) -> - lists:filtermap(fun decode_customer_change/1, CustomerChanges). - -decode_customer_change({customer_binding_changed, CustomerBindingChanged}) -> - #payproc_CustomerBindingChanged{id = BindingID, payload = Payload} = CustomerBindingChanged, - decode_customer_binding_change(BindingID, Payload); -decode_customer_change(_) -> - false. - -decode_customer_binding_change(_, {started, Start}) -> - #payproc_CustomerBindingStarted{binding = CustomerBinding} = Start, - {true, #{ - <<"changeType">> => <<"CustomerBindingStarted">>, - <<"customerBinding">> => decode_customer_binding(CustomerBinding) - }}; -decode_customer_binding_change(BindingID, {status_changed, StatusChange}) -> - #payproc_CustomerBindingStatusChanged{status = Status} = StatusChange, - {true, - capi_handler_utils:merge_and_compact( - #{ - <<"changeType">> => <<"CustomerBindingStatusChanged">>, - <<"customerBindingID">> => BindingID - }, - decode_customer_binding_status(Status) - )}; -decode_customer_binding_change(BindingID, {interaction_changed, InteractionChange}) -> - #payproc_CustomerBindingInteractionChanged{ - interaction = UserInteraction, - status = Status - } = InteractionChange, - ChangeType = - case Status of - {requested, _} -> <<"CustomerBindingInteractionRequested">>; - {completed, _} -> <<"CustomerBindingInteractionCompleted">>; - undefined -> <<"CustomerBindingInteractionRequested">> - end, - {true, #{ - <<"changeType">> => ChangeType, - <<"customerBindingID">> => BindingID, - <<"userInteraction">> => capi_handler_decoder_invoicing:decode_user_interaction(UserInteraction) - }}. diff --git a/apps/capi/src/capi_handler_decoder_invoicing.erl b/apps/capi/src/capi_handler_decoder_invoicing.erl index 393a2af..43dc85d 100644 --- a/apps/capi/src/capi_handler_decoder_invoicing.erl +++ b/apps/capi/src/capi_handler_decoder_invoicing.erl @@ -200,17 +200,6 @@ decode_additional_tx_info(AdditionalTransactionInfo) -> <<"extra_payment_info">> => AdditionalTransactionInfo#domain_AdditionalTransactionInfo.extra_payment_info }). -decode_payer( - {customer, #domain_CustomerPayer{ - payment_tool = PaymentTool, - customer_id = ID - }} -) -> - #{ - <<"payerType">> => <<"CustomerPayer">>, - <<"customerID">> => ID, - <<"paymentToolDetails">> => decode_payment_tool_details(PaymentTool) - }; decode_payer( {recurrent, #domain_RecurrentPayer{ payment_tool = PaymentTool, diff --git a/apps/capi/src/capi_handler_decoder_party.erl b/apps/capi/src/capi_handler_decoder_party.erl index 62e5c88..f5d21e2 100644 --- a/apps/capi/src/capi_handler_decoder_party.erl +++ b/apps/capi/src/capi_handler_decoder_party.erl @@ -8,9 +8,6 @@ -export([decode_party/1]). -export([is_blocked/1]). -export([is_suspended/1]). --export([decode_contractor/1]). --export([decode_legal_agreement/1]). --export([decode_reporting_preferences/1]). -export([decode_residence/1]). -export([decode_payment_institution_ref/1]). @@ -25,6 +22,11 @@ decode_shop_location({url, Location}) -> -spec decode_shop_details(capi_handler_encoder:encode_data()) -> capi_handler_decoder_utils:decode_data(). decode_shop_details(#domain_ShopDetails{name = Name, description = Description}) -> + genlib_map:compact(#{ + <<"name">> => Name, + <<"description">> => Description + }); +decode_shop_details(#domain_Details{name = Name, description = Description}) -> genlib_map:compact(#{ <<"name">> => Name, <<"description">> => Description @@ -59,7 +61,7 @@ decode_contact_info(#domain_ContactInfo{ }). -spec decode_party(capi_handler_encoder:encode_data()) -> capi_handler_decoder_utils:decode_data(). -decode_party(#domain_Party{id = PartyID, blocking = Blocking, suspension = Suspension}) -> +decode_party(#domain_PartyConfig{id = PartyID, blocking = Blocking, suspension = Suspension}) -> #{ <<"id">> => PartyID, <<"isBlocked">> => is_blocked(Blocking), @@ -74,101 +76,6 @@ is_blocked({unblocked, _}) -> false. is_suspended({suspended, _}) -> true; is_suspended({active, _}) -> false. --spec decode_contractor(capi_handler_encoder:encode_data()) -> capi_handler_decoder_utils:decode_data(). -decode_contractor({legal_entity, LegalEntity}) -> - maps:merge(#{<<"contractorType">> => <<"LegalEntity">>}, decode_legal_entity(LegalEntity)); -decode_contractor({private_entity, PrivateEntity}) -> - maps:merge(#{<<"contractorType">> => <<"PrivateEntity">>}, decode_private_entity(PrivateEntity)); -decode_contractor({registered_user, RegisteredUser}) -> - maps:merge(#{<<"contractorType">> => <<"RegisteredUser">>}, decode_registered_user(RegisteredUser)). - -decode_legal_entity({russian_legal_entity, LegalEntity}) -> - #{ - <<"entityType">> => <<"RussianLegalEntity">>, - <<"registeredName">> => LegalEntity#domain_RussianLegalEntity.registered_name, - <<"registeredNumber">> => LegalEntity#domain_RussianLegalEntity.registered_number, - <<"inn">> => LegalEntity#domain_RussianLegalEntity.inn, - <<"actualAddress">> => LegalEntity#domain_RussianLegalEntity.actual_address, - <<"postAddress">> => LegalEntity#domain_RussianLegalEntity.post_address, - <<"representativePosition">> => LegalEntity#domain_RussianLegalEntity.representative_position, - <<"representativeFullName">> => LegalEntity#domain_RussianLegalEntity.representative_full_name, - <<"representativeDocument">> => LegalEntity#domain_RussianLegalEntity.representative_document, - <<"bankAccount">> => - decode_russian_bank_account(LegalEntity#domain_RussianLegalEntity.russian_bank_account, #{}) - }; -decode_legal_entity({international_legal_entity, LegalEntity}) -> - genlib_map:compact(#{ - <<"entityType">> => <<"InternationalLegalEntity">>, - <<"legalName">> => LegalEntity#domain_InternationalLegalEntity.legal_name, - <<"tradingName">> => LegalEntity#domain_InternationalLegalEntity.trading_name, - <<"registeredOffice">> => LegalEntity#domain_InternationalLegalEntity.registered_address, - <<"principalPlaceOfBusiness">> => LegalEntity#domain_InternationalLegalEntity.actual_address, - <<"registeredNumber">> => LegalEntity#domain_InternationalLegalEntity.registered_number - }). - -decode_private_entity({russian_private_entity, PrivateEntity}) -> - #{ - <<"entityType">> => <<"RussianPrivateEntity">>, - <<"firstName">> => PrivateEntity#domain_RussianPrivateEntity.first_name, - <<"secondName">> => PrivateEntity#domain_RussianPrivateEntity.second_name, - <<"middleName">> => PrivateEntity#domain_RussianPrivateEntity.middle_name, - <<"contactInfo">> => decode_contact_info(PrivateEntity#domain_RussianPrivateEntity.contact_info) - }. - -decode_registered_user(#domain_RegisteredUser{email = Email}) -> - #{<<"email">> => Email}. - --spec decode_legal_agreement(capi_handler_encoder:encode_data()) -> capi_handler_decoder_utils:decode_data(). -decode_legal_agreement( - #domain_LegalAgreement{ - signed_at = SignedAt, - legal_agreement_id = ID, - valid_until = ValidUntil - } -) -> - genlib_map:compact(#{ - <<"id">> => ID, - <<"signedAt">> => SignedAt, - <<"validUntil">> => ValidUntil - }). - --spec decode_reporting_preferences(capi_handler_encoder:encode_data()) -> capi_handler_decoder_utils:decode_data(). -decode_reporting_preferences(#domain_ReportPreferences{ - service_acceptance_act_preferences = #domain_ServiceAcceptanceActPreferences{ - schedule = ScheduleRef, - signer = Signer - } -}) -> - #{ - <<"serviceAcceptanceActPreferences">> => #{ - <<"scheduleID">> => capi_handler_decoder_utils:decode_business_schedule_ref(ScheduleRef), - <<"signer">> => decode_representative(Signer) - } - }; -decode_reporting_preferences(#domain_ReportPreferences{service_acceptance_act_preferences = undefined}) -> - #{}. - -decode_representative(#domain_Representative{ - position = Position, - full_name = Name, - document = Document -}) -> - #{ - <<"position">> => Position, - <<"fullName">> => Name, - <<"document">> => decode_representative_document(Document) - }. - -decode_representative_document({articles_of_association, #domain_ArticlesOfAssociation{}}) -> - #{ - <<"representativeDocumentType">> => <<"ArticlesOfAssociation">> - }; -decode_representative_document({power_of_attorney, LegalAgreement}) -> - maps:merge( - #{<<"representativeDocumentType">> => <<"PowerOfAttorney">>}, - decode_legal_agreement(LegalAgreement) - ). - -spec decode_residence(atom() | undefined) -> binary(). decode_residence(undefined) -> undefined; @@ -178,11 +85,3 @@ decode_residence(Residence) when is_atom(Residence) -> -spec decode_payment_institution_ref(capi_handler_encoder:encode_data()) -> integer(). decode_payment_institution_ref(#domain_PaymentInstitutionRef{id = Ref}) -> Ref. - -decode_russian_bank_account(BankAccount, V) -> - V#{ - <<"account">> => BankAccount#domain_RussianBankAccount.account, - <<"bankName">> => BankAccount#domain_RussianBankAccount.bank_name, - <<"bankPostAccount">> => BankAccount#domain_RussianBankAccount.bank_post_account, - <<"bankBik">> => BankAccount#domain_RussianBankAccount.bank_bik - }. diff --git a/apps/capi/src/capi_handler_invoice_templates.erl b/apps/capi/src/capi_handler_invoice_templates.erl index 7978b87..910579d 100644 --- a/apps/capi/src/capi_handler_invoice_templates.erl +++ b/apps/capi/src/capi_handler_invoice_templates.erl @@ -169,7 +169,7 @@ prepare('CreateInvoiceWithTemplate' = OperationID, Req, Context) -> {exception, #payproc_InvoiceTemplateRemoved{}} -> {ok, general_error(404, <<"Invoice Template not found">>)}; {exception, #payproc_InvoiceTermsViolated{}} -> - {ok, logic_error('invoiceTermsViolated', <<"Invoice parameters violate contract terms">>)} + {ok, logic_error('invoiceTermsViolated', <<"Invoice parameters violate terms">>)} catch throw:{bad_invoice_params, currency_no_amount} -> {ok, logic_error('invalidRequest', <<"Amount is required for the currency">>)}; @@ -193,12 +193,7 @@ prepare('GetInvoicePaymentMethodsByTemplateID' = OperationID, Req, Context) -> end, Process = fun() -> capi_handler:respond_if_undefined(InvoiceTemplate, general_error(404, <<"Invoice template not found">>)), - Timestamp = genlib_rfc3339:format_relaxed(erlang:system_time(microsecond), microsecond), - PartyID = InvoiceTemplate#domain_InvoiceTemplate.owner_id, - % В данном контексте - Party не может не существовать - {ok, Party} = capi_party:get_party(PartyID, Context), - Args = {InvoiceTemplateID, Timestamp, {revision, Party#domain_Party.revision}}, - case capi_handler_utils:get_payment_methods(invoice_templating, Args, Context) of + case capi_handler_utils:get_payment_methods(invoice_templating, {InvoiceTemplateID}, Context) of {ok, PaymentMethodRefs} -> PaymentMethods0 = capi_handler_decoder_invoicing:decode_payment_methods(PaymentMethodRefs), PaymentMethods1 = capi_utils:deduplicate_payment_methods(PaymentMethods0), diff --git a/apps/capi/src/capi_handler_invoices.erl b/apps/capi/src/capi_handler_invoices.erl index 5455f03..e139821 100644 --- a/apps/capi/src/capi_handler_invoices.erl +++ b/apps/capi/src/capi_handler_invoices.erl @@ -45,7 +45,7 @@ prepare('CreateInvoice' = OperationID, Req, Context) -> {exception, #payproc_InvalidShopStatus{}} -> {ok, logic_error('invalidShopStatus', <<"Invalid shop status">>)}; {exception, #payproc_InvoiceTermsViolated{}} -> - {ok, logic_error('invoiceTermsViolated', <<"Invoice parameters violate contract terms">>)}; + {ok, logic_error('invoiceTermsViolated', <<"Invoice parameters violate terms">>)}; {exception, #payproc_AllocationNotAllowed{}} -> {ok, logic_error('allocationNotPermitted', <<"Not allowed">>)}; {exception, #payproc_AllocationExceededPaymentAmount{}} -> @@ -239,11 +239,7 @@ prepare('GetInvoicePaymentMethods' = OperationID, Req, Context) -> end, Process = fun() -> capi_handler:respond_if_undefined(ResultInvoice, general_error(404, <<"Invoice not found">>)), - PartyID = ResultInvoice#payproc_Invoice.invoice#domain_Invoice.owner_id, - % В данном контексте - Party не может не существовать - {ok, Party} = capi_party:get_party(PartyID, Context), - Args = {InvoiceID, {revision, Party#domain_Party.revision}}, - case capi_handler_utils:get_payment_methods(invoicing, Args, Context) of + case capi_handler_utils:get_payment_methods(invoicing, {InvoiceID}, Context) of {ok, PaymentMethodRefs} -> #payproc_Invoice{invoice = Invoice} = ResultInvoice, PaymentMethods0 = capi_handler_decoder_invoicing:decode_payment_methods(PaymentMethodRefs), diff --git a/apps/capi/src/capi_handler_parties.erl b/apps/capi/src/capi_handler_parties.erl index 50d47b3..ee57f41 100644 --- a/apps/capi/src/capi_handler_parties.erl +++ b/apps/capi/src/capi_handler_parties.erl @@ -7,65 +7,15 @@ -export([prepare/3]). --import(capi_handler_utils, [general_error/2, logic_error/2]). +-import(capi_handler_utils, [general_error/2]). -type processing_context() :: capi_handler:processing_context(). -spec prepare( OperationID :: capi_handler:operation_id(), Req :: capi_handler:request_data(), - Context :: capi_handler:processing_context() + Context :: processing_context() ) -> {ok, capi_handler:request_state()} | {error, noimpl}. -prepare('GetMyParty' = OperationID, _Req, Context) -> - PartyID = capi_handler_utils:get_party_id(Context), - Authorize = fun() -> - Prototypes = [{operation, #{id => OperationID, party => PartyID}}], - {ok, capi_auth:authorize_operation(Prototypes, Context)} - end, - Process = fun() -> - case get_or_create_party(PartyID, Context) of - {ok, Party} -> - DecodedParty = capi_handler_decoder_party:decode_party(Party), - {ok, {200, #{}, DecodedParty}}; - {error, #payproc_PartyNotFound{}} -> - {ok, logic_error(<<"invalidRequest">>, <<"Party not found">>)} - end - end, - {ok, #{authorize => Authorize, process => Process}}; -prepare('ActivateMyParty' = OperationID, _Req, Context) -> - PartyID = capi_handler_utils:get_party_id(Context), - Authorize = fun() -> - Prototypes = [{operation, #{id => OperationID, party => PartyID}}], - {ok, capi_auth:authorize_operation(Prototypes, Context)} - end, - Process = fun() -> - case capi_party:activate_party(PartyID, Context) of - ok -> - {ok, {204, #{}, undefined}}; - {error, #payproc_PartyNotFound{}} -> - {ok, logic_error(<<"invalidRequest">>, <<"Party not found">>)}; - {error, #payproc_InvalidPartyStatus{status = {suspension, {active, _}}}} -> - {ok, logic_error(<<"invalidRequest">>, <<"Invalid party status">>)} - end - end, - {ok, #{authorize => Authorize, process => Process}}; -prepare('SuspendMyParty' = OperationID, _Req, Context) -> - PartyID = capi_handler_utils:get_party_id(Context), - Authorize = fun() -> - Prototypes = [{operation, #{id => OperationID, party => PartyID}}], - {ok, capi_auth:authorize_operation(Prototypes, Context)} - end, - Process = fun() -> - case capi_party:suspend_party(PartyID, Context) of - ok -> - {ok, {204, #{}, undefined}}; - {error, #payproc_PartyNotFound{}} -> - {ok, logic_error(<<"invalidRequest">>, <<"Party not found">>)}; - {error, #payproc_InvalidPartyStatus{status = {suspension, {suspended, _}}}} -> - {ok, logic_error(<<"invalidRequest">>, <<"Invalid party status">>)} - end - end, - {ok, #{authorize => Authorize, process => Process}}; prepare('GetPartyByID' = OperationID, Req, Context) -> PartyID = maps:get('partyID', Req), Authorize = fun() -> @@ -77,83 +27,20 @@ prepare('GetPartyByID' = OperationID, Req, Context) -> {ok, Party} -> DecodedParty = capi_handler_decoder_party:decode_party(Party), {ok, {200, #{}, DecodedParty}}; - {error, #payproc_PartyNotFound{}} -> + {error, not_found} -> {ok, general_error(404, <<"Party not found">>)} end end, {ok, #{authorize => Authorize, process => Process}}; -prepare('ActivatePartyByID' = OperationID, Req, Context) -> - PartyID = maps:get('partyID', Req), - Authorize = fun() -> - Prototypes = [{operation, #{id => OperationID, party => PartyID}}], - {ok, capi_auth:authorize_operation(Prototypes, Context)} - end, - Process = fun() -> - case capi_party:activate_party(PartyID, Context) of - ok -> - {ok, {204, #{}, undefined}}; - {error, #payproc_PartyNotFound{}} -> - {ok, general_error(404, <<"Party not found">>)}; - {error, #payproc_InvalidPartyStatus{status = {suspension, {active, _}}}} -> - {ok, logic_error(<<"invalidRequest">>, <<"Invalid party status">>)} - end - end, - {ok, #{authorize => Authorize, process => Process}}; -prepare('SuspendPartyByID' = OperationID, Req, Context) -> - PartyID = maps:get('partyID', Req), - Authorize = fun() -> - Prototypes = [{operation, #{id => OperationID, party => PartyID}}], - {ok, capi_auth:authorize_operation(Prototypes, Context)} - end, - Process = fun() -> - case capi_party:suspend_party(PartyID, Context) of - ok -> - {ok, {204, #{}, undefined}}; - {error, #payproc_PartyNotFound{}} -> - {ok, general_error(404, <<"Party not found">>)}; - {error, #payproc_InvalidPartyStatus{status = {suspension, {suspended, _}}}} -> - {ok, logic_error(<<"invalidRequest">>, <<"Invalid party status">>)} - end - end, - {ok, #{authorize => Authorize, process => Process}}; +prepare('ActivatePartyByID', _Req, _Context) -> + {error, noimpl}; +prepare('SuspendPartyByID', _Req, _Context) -> + {error, noimpl}; prepare(_OperationID, _Req, _Context) -> {error, noimpl}. %% --spec get_or_create_party(binary(), processing_context()) -> woody:result(). -get_or_create_party(PartyID, Context) -> - case capi_party:get_party(PartyID, Context) of - {error, #payproc_PartyNotFound{}} = NotFound -> - _ = logger:info("Attempting to create a missing party"), - case capi_auth:get_user_email(capi_handler_utils:get_auth_context(Context)) of - Email when Email =/= undefined -> - create_party(PartyID, Email, Context); - undefined -> - %% API keys dont have an email attached to them, which makes it impossible to create parties - _ = logger:info("Can't create missing party: no email found"), - NotFound - end; - Reply -> - Reply - end. - --spec create_party(binary(), binary(), processing_context()) -> woody:result(). -create_party(PartyID, Email, Context) -> - PartyParams = #payproc_PartyParams{ - contact_info = #domain_PartyContactInfo{ - registration_email = Email - } - }, - case capi_party:create_party(PartyID, PartyParams, Context) of - ok -> - capi_party:get_party(PartyID, Context); - {error, #payproc_PartyExists{}} -> - capi_party:get_party(PartyID, Context); - Error -> - Error - end. - mask_party_notfound(Resolution) -> % ED-206 % When bouncer says "forbidden" we can't really tell the difference between "forbidden because diff --git a/apps/capi/src/capi_handler_payments.erl b/apps/capi/src/capi_handler_payments.erl index a91cea5..6c51d8e 100644 --- a/apps/capi/src/capi_handler_payments.erl +++ b/apps/capi/src/capi_handler_payments.erl @@ -48,7 +48,7 @@ prepare('CreatePayment' = OperationID, Req, Context) -> {exception, #payproc_InvalidShopStatus{}} -> {ok, logic_error('invalidShopStatus', <<"Invalid shop status">>)}; {exception, #payproc_InvalidContractStatus{}} -> - {ok, logic_error('invalidContractStatus', <<"Invalid contract status">>)}; + {ok, logic_error('invalidContractStatus', <<"Invalid status">>)}; {exception, #payproc_InvalidRecurrentParentPayment{}} -> {ok, logic_error('invalidRecurrentParent', <<"Specified recurrent parent is invalid">>)}; {exception, #payproc_InvoiceNotFound{}} -> @@ -278,7 +278,7 @@ prepare('CreateRefund' = OperationID, Req, Context) -> {exception, #payproc_InvalidShopStatus{}} -> {ok, logic_error('invalidShopStatus', <<"Invalid shop status">>)}; {exception, #payproc_InvalidContractStatus{}} -> - {ok, logic_error('invalidContractStatus', <<"Invalid contract status">>)}; + {ok, logic_error('invalidContractStatus', <<"Invalid status">>)}; {exception, #payproc_OperationNotPermitted{}} -> {ok, logic_error('operationNotPermitted', <<"Operation not permitted">>)}; {exception, #payproc_InvalidPaymentStatus{}} -> @@ -569,14 +569,6 @@ encode_invoice_payment_params(ID, ExternalID, PaymentParams, PaymentTool) -> ) }. -encode_payer_params( - #{ - <<"payerType">> := <<"CustomerPayer">>, - <<"customerID">> := ID - }, - _ -) -> - {customer, #payproc_CustomerPayerParams{customer_id = ID}}; encode_payer_params( #{ <<"payerType">> := <<"PaymentResourcePayer">>, diff --git a/apps/capi/src/capi_handler_search.erl b/apps/capi/src/capi_handler_search.erl deleted file mode 100644 index 79fad77..0000000 --- a/apps/capi/src/capi_handler_search.erl +++ /dev/null @@ -1,476 +0,0 @@ --module(capi_handler_search). - --include_lib("magista_proto/include/magista_magista_thrift.hrl"). --include_lib("damsel/include/dmsl_base_thrift.hrl"). --include_lib("damsel/include/dmsl_domain_thrift.hrl"). - --behaviour(capi_handler). - --export([prepare/3]). - --import(capi_handler_utils, [logic_error/2]). - --spec prepare( - OperationID :: capi_handler:operation_id(), - Req :: capi_handler:request_data(), - Context :: capi_handler:processing_context() -) -> {ok, capi_handler:request_state()} | {error, noimpl}. -prepare(OperationID, Req, Context) when OperationID =:= 'SearchInvoices' -> - Prototypes = build_prototypes(OperationID, Context, Req), - Authorize = fun() -> {ok, capi_auth:authorize_operation(Prototypes, Context)} end, - Process = fun() -> - Query = make_invoices_search_query(Context, Req), - process_search_request('SearchInvoices', Query, Req, Context) - end, - {ok, #{authorize => Authorize, process => Process}}; -prepare(OperationID, Req, Context) when OperationID =:= 'SearchPayments' -> - Prototypes = build_prototypes(OperationID, Context, Req), - Authorize = fun() -> {ok, capi_auth:authorize_operation(Prototypes, Context)} end, - Process = fun() -> - Query = make_payments_search_query(Context, Req), - process_search_request('SearchPayments', Query, Req, Context) - end, - {ok, #{authorize => Authorize, process => Process}}; -prepare(OperationID, Req, Context) when OperationID =:= 'SearchRefunds' -> - Prototypes = build_prototypes(OperationID, Context, Req), - Authorize = fun() -> {ok, capi_auth:authorize_operation(Prototypes, Context)} end, - Process = fun() -> - Query = make_refunds_search_query(Context, Req), - process_search_request('SearchRefunds', Query, Req, Context) - end, - {ok, #{authorize => Authorize, process => Process}}; -prepare(_OperationID, _Req, _Context) -> - {error, noimpl}. - -%% - -make_invoices_search_query(Context, Req) -> - #magista_InvoiceSearchQuery{ - common_search_query_params = make_common_query_params(Context, Req), - payment_params = make_payment_query_params(Req), - invoice_ids = encode_invoice_ids(genlib_map:get('invoiceID', Req)), - invoice_status = encode_invoice_status(genlib_map:get('invoiceStatus', Req)), - invoice_amount = genlib_map:get('invoiceAmount', Req) - }. - -make_payments_search_query(Context, Req) -> - #magista_PaymentSearchQuery{ - common_search_query_params = make_common_query_params(Context, Req), - payment_params = make_payment_query_params(Req), - invoice_ids = encode_invoice_ids(genlib_map:get('invoiceID', Req)) - }. - -make_refunds_search_query(Context, Req) -> - #magista_RefundSearchQuery{ - common_search_query_params = make_common_query_params(Context, Req), - invoice_ids = encode_invoice_ids(genlib_map:get('invoiceID', Req)), - payment_id = genlib_map:get('paymentID', Req), - refund_id = genlib_map:get('refundID', Req), - refund_status = encode_refund_status(genlib_map:get('refundStatus', Req)) - }. - -make_common_query_params(Context, Req) -> - #magista_CommonSearchQueryParams{ - to_time = capi_handler_utils:get_time('toTime', Req), - from_time = capi_handler_utils:get_time('fromTime', Req), - shop_ids = [genlib_map:get('shopID', Req)], - party_id = capi_handler_utils:get_party_id(Context), - continuation_token = genlib_map:get('continuationToken', Req), - limit = genlib_map:get('limit', Req) - }. - -make_payment_query_params(Req) -> - #magista_PaymentParams{ - payment_id = genlib_map:get('paymentID', Req), - payment_status = encode_payment_status(genlib_map:get('paymentStatus', Req)), - payment_flow = encode_payment_flow(genlib_map:get('paymentFlow', Req)), - payment_tool = encode_payment_method(genlib_map:get('paymentMethod', Req)), - payment_terminal_provider = encode_terminal_provider(genlib_map:get('paymentTerminalProvider', Req)), - payment_email = genlib_map:get('payerEmail', Req), - payment_ip = genlib_map:get('payerIP', Req), - payment_fingerprint = genlib_map:get('payerFingerprint', Req), - payment_first6 = genlib_map:get('first6', Req), - payment_system = encode_payment_system_ref(genlib_map:get('bankCardPaymentSystem', Req)), - payment_last4 = genlib_map:get('last4', Req), - payment_customer_id = genlib_map:get('customerID', Req), - payment_amount = genlib_map:get('paymentAmount', Req), - payment_rrn = genlib_map:get('rrn', Req), - payment_approval_code = genlib_map:get('approvalCode', Req), - payment_token_provider = encode_payment_token_provider(genlib_map:get('bankCardTokenProvider', Req)) - }. - -process_search_request(Function, Query, _Req, Context) -> - Call = {magista, Function, {Query}}, - process_search_request_result(Function, capi_handler_utils:service_call(Call, Context), Context). - -process_search_request_result(Function, Result, Context) -> - case Result of - {ok, Response} -> - {Results, ContinuationToken} = decode_search_response(Function, Response, Context), - Resp = genlib_map:compact(#{ - <<"result">> => Results, - <<"totalCount">> => length(Results), - <<"continuationToken">> => ContinuationToken - }), - {ok, {200, #{}, Resp}}; - {exception, #base_InvalidRequest{errors = Errors}} -> - FormattedErrors = capi_handler_utils:format_request_errors(Errors), - {ok, logic_error('invalidRequest', FormattedErrors)}; - {exception, #magista_LimitExceeded{}} -> - {ok, logic_error('invalidRequest', <<"Invalid limit">>)}; - {exception, #magista_BadContinuationToken{}} -> - {ok, logic_error('invalidRequest', <<"Invalid token">>)} - end. - -decode_search_response( - 'SearchInvoices', - #magista_StatInvoiceResponse{ - invoices = Invoices, - continuation_token = ContinuationToken - }, - _Context -) -> - { - [decode_stat_invoice(Invoice) || Invoice <- Invoices], - ContinuationToken - }; -decode_search_response( - 'SearchPayments', - #magista_StatPaymentResponse{ - payments = Payments, - continuation_token = ContinuationToken - }, - Context -) -> - { - [decode_stat_payment(Payment, Context) || Payment <- Payments], - ContinuationToken - }; -decode_search_response( - 'SearchRefunds', - #magista_StatRefundResponse{ - refunds = Refunds, - continuation_token = ContinuationToken - }, - _Context -) -> - {[decode_stat_refund(Refund) || Refund <- Refunds], ContinuationToken}. - -%% - -encode_invoice_status(unpaid) -> unpaid; -encode_invoice_status(cancelled) -> cancelled; -encode_invoice_status(paid) -> paid; -encode_invoice_status(fulfilled) -> fulfilled; -encode_invoice_status(undefined) -> undefined. - -encode_payment_status(pending) -> pending; -encode_payment_status(processed) -> processed; -encode_payment_status(captured) -> captured; -encode_payment_status(cancelled) -> cancelled; -encode_payment_status(refunded) -> refunded; -encode_payment_status(failed) -> failed; -encode_payment_status(undefined) -> undefined. - -encode_refund_status(pending) -> pending; -encode_refund_status(succeeded) -> succeeded; -encode_refund_status(failed) -> failed; -encode_refund_status(undefined) -> undefined. - -encode_payment_flow(instant) -> instant; -encode_payment_flow(hold) -> hold; -encode_payment_flow(undefined) -> undefined. - -encode_payment_method('bankCard') -> bank_card; -encode_payment_method('paymentTerminal') -> payment_terminal; -encode_payment_method(undefined) -> undefined. - -encode_terminal_provider(ID) -> encode_payment_service_ref(ID). - -encode_payment_service_ref(ID) when is_binary(ID) -> #domain_PaymentServiceRef{id = ID}; -encode_payment_service_ref(undefined) -> undefined. - -encode_payment_system_ref(ID) when is_binary(ID) -> #domain_PaymentSystemRef{id = ID}; -encode_payment_system_ref(undefined) -> undefined. - -encode_payment_token_provider(ID) when is_binary(ID) -> #domain_BankCardTokenServiceRef{id = ID}; -encode_payment_token_provider(undefined) -> undefined. - -encode_invoice_ids(ID) when is_binary(ID) -> [ID]; -encode_invoice_ids(undefined) -> undefined. - -%% - -decode_stat_invoice(Stat) -> - capi_handler_utils:merge_and_compact( - #{ - <<"id">> => Stat#magista_StatInvoice.id, - <<"externalID">> => Stat#magista_StatInvoice.external_id, - <<"shopID">> => Stat#magista_StatInvoice.shop_id, - <<"createdAt">> => Stat#magista_StatInvoice.created_at, - <<"dueDate">> => Stat#magista_StatInvoice.due, - <<"amount">> => Stat#magista_StatInvoice.amount, - <<"currency">> => Stat#magista_StatInvoice.currency_symbolic_code, - <<"metadata">> => capi_handler_decoder_utils:decode_context(Stat#magista_StatInvoice.context), - <<"product">> => Stat#magista_StatInvoice.product, - <<"description">> => Stat#magista_StatInvoice.description, - <<"cart">> => capi_handler_decoder_invoicing:decode_invoice_cart(Stat#magista_StatInvoice.cart) - }, - capi_handler_decoder_invoicing:decode_invoice_status(Stat#magista_StatInvoice.status) - ). - -decode_stat_payment(Stat, Context) -> - capi_handler_utils:merge_and_compact( - #{ - <<"id">> => Stat#magista_StatPayment.id, - <<"shortID">> => Stat#magista_StatPayment.short_id, - <<"invoiceID">> => Stat#magista_StatPayment.invoice_id, - <<"shopID">> => Stat#magista_StatPayment.shop_id, - <<"createdAt">> => Stat#magista_StatPayment.created_at, - <<"amount">> => Stat#magista_StatPayment.amount, - <<"fee">> => Stat#magista_StatPayment.fee, - <<"currency">> => Stat#magista_StatPayment.currency_symbolic_code, - <<"payer">> => decode_stat_payer(Stat#magista_StatPayment.payer), - <<"flow">> => decode_stat_payment_flow(Stat#magista_StatPayment.flow), - <<"metadata">> => capi_handler_decoder_utils:decode_context(Stat#magista_StatPayment.context), - <<"transactionInfo">> => decode_stat_tx_info(Stat#magista_StatPayment.additional_transaction_info), - <<"statusChangedAt">> => Stat#magista_StatPayment.status_changed_at, - <<"makeRecurrent">> => capi_handler_decoder_invoicing:decode_make_recurrent( - Stat#magista_StatPayment.make_recurrent - ), - <<"cart">> => capi_handler_decoder_invoicing:decode_invoice_cart(Stat#magista_StatPayment.cart) - }, - decode_stat_payment_status(Stat#magista_StatPayment.status, Context) - ). - -decode_stat_refund(Stat) -> - Status = capi_handler_decoder_invoicing:decode_refund_status(Stat#magista_StatRefund.status), - capi_handler_utils:merge_and_compact( - #{ - <<"id">> => Stat#magista_StatRefund.id, - <<"externalID">> => Stat#magista_StatRefund.external_id, - <<"invoiceID">> => Stat#magista_StatRefund.invoice_id, - <<"paymentID">> => Stat#magista_StatRefund.payment_id, - <<"createdAt">> => Stat#magista_StatRefund.created_at, - <<"reason">> => Stat#magista_StatRefund.reason, - <<"amount">> => Stat#magista_StatRefund.amount, - <<"currency">> => Stat#magista_StatRefund.currency_symbolic_code, - <<"cart">> => capi_handler_decoder_invoicing:decode_invoice_cart(Stat#magista_StatRefund.cart) - }, - Status - ). - -decode_stat_tx_info(undefined) -> - undefined; -decode_stat_tx_info(TransactionInfo) -> - RRN = TransactionInfo#domain_AdditionalTransactionInfo.rrn, - AAC = TransactionInfo#domain_AdditionalTransactionInfo.approval_code, - ParsedTransactionInfo = #{ - <<"rrn">> => RRN, - <<"approvalCode">> => AAC - }, - genlib_map:compact(ParsedTransactionInfo). - -decode_stat_payer( - {customer, #magista_CustomerPayer{ - customer_id = ID, - payment_tool = PaymentTool - }} -) -> - #{ - <<"payerType">> => <<"CustomerPayer">>, - <<"paymentToolDetails">> => decode_stat_payment_tool_details(PaymentTool), - <<"customerID">> => ID - }; -decode_stat_payer( - {recurrent, #domain_RecurrentPayer{ - payment_tool = PaymentTool, - recurrent_parent = RecurrentParent, - contact_info = #domain_ContactInfo{ - phone_number = PhoneNumber, - email = Email, - first_name = FirstName, - last_name = LastName, - country = Country, - state = State, - city = City, - address = Address, - postal_code = PostalCode, - date_of_birth = DateOfBirth, - document_id = DocumentId - } - }} -) -> - #{ - <<"payerType">> => <<"RecurrentPayer">>, - <<"paymentToolDetails">> => decode_stat_payment_tool_details(PaymentTool), - <<"contactInfo">> => genlib_map:compact(#{ - <<"phoneNumber">> => PhoneNumber, - <<"email">> => Email, - <<"firstName">> => FirstName, - <<"lastName">> => LastName, - <<"country">> => Country, - <<"state">> => State, - <<"city">> => City, - <<"address">> => Address, - <<"postalCode">> => PostalCode, - <<"dateOfBirth">> => DateOfBirth, - <<"documentId">> => DocumentId - }), - <<"recurrentParentPayment">> => capi_handler_decoder_invoicing:decode_recurrent_parent(RecurrentParent) - }; -decode_stat_payer( - {payment_resource, #domain_PaymentResourcePayer{ - resource = #domain_DisposablePaymentResource{ - payment_tool = PaymentTool, - payment_session_id = PaymentSession, - client_info = #domain_ClientInfo{ - ip_address = IP, - fingerprint = Fingerprint - } - }, - contact_info = #domain_ContactInfo{ - phone_number = PhoneNumber, - email = Email, - first_name = FirstName, - last_name = LastName, - country = Country, - state = State, - city = City, - address = Address, - postal_code = PostalCode, - date_of_birth = DateOfBirth, - document_id = DocumentId - } - }} -) -> - genlib_map:compact(#{ - <<"payerType">> => <<"PaymentResourcePayer">>, - <<"paymentToolDetails">> => decode_stat_payment_tool_details(PaymentTool), - <<"paymentSession">> => PaymentSession, - <<"clientInfo">> => genlib_map:compact(#{ - <<"ip">> => IP, - <<"fingerprint">> => Fingerprint - }), - <<"contactInfo">> => genlib_map:compact(#{ - <<"phoneNumber">> => PhoneNumber, - <<"email">> => Email, - <<"firstName">> => FirstName, - <<"lastName">> => LastName, - <<"country">> => Country, - <<"state">> => State, - <<"city">> => City, - <<"address">> => Address, - <<"postalCode">> => PostalCode, - <<"dateOfBirth">> => DateOfBirth, - <<"documentId">> => DocumentId - }) - }). - -decode_stat_payment_flow({instant, _}) -> - #{<<"type">> => <<"PaymentFlowInstant">>}; -decode_stat_payment_flow( - {hold, #magista_InvoicePaymentFlowHold{ - on_hold_expiration = OnHoldExpiration, - held_until = HeldUntil - }} -) -> - #{ - <<"type">> => <<"PaymentFlowHold">>, - <<"onHoldExpiration">> => atom_to_binary(OnHoldExpiration, utf8), - <<"heldUntil">> => HeldUntil - }. - -decode_stat_payment_status({Status, StatusInfo}, Context) -> - Error = - case StatusInfo of - #domain_InvoicePaymentFailed{failure = OperationFailure} -> - capi_handler_decoder_invoicing:decode_payment_operation_failure(OperationFailure, Context); - _ -> - undefined - end, - #{ - <<"status">> => genlib:to_binary(Status), - <<"error">> => Error - }. - -decode_stat_payment_tool_details({bank_card, V}) -> - decode_bank_card_details(V, #{<<"detailsType">> => <<"PaymentToolDetailsBankCard">>}); -decode_stat_payment_tool_details({payment_terminal, V}) -> - decode_payment_terminal_details(V, #{<<"detailsType">> => <<"PaymentToolDetailsPaymentTerminal">>}); -decode_stat_payment_tool_details({digital_wallet, V}) -> - decode_digital_wallet_details(V, #{<<"detailsType">> => <<"PaymentToolDetailsDigitalWallet">>}); -decode_stat_payment_tool_details({crypto_currency, CryptoCurrency}) -> - #{ - <<"detailsType">> => <<"PaymentToolDetailsCryptoWallet">>, - <<"cryptoCurrency">> => decode_crypto_wallet_details(CryptoCurrency) - }; -decode_stat_payment_tool_details({mobile_commerce, MobileCommerce}) -> - #domain_MobileCommerce{ - phone = Phone - } = MobileCommerce, - PhoneNumber = gen_phone_number(decode_mobile_phone(Phone)), - #{ - <<"detailsType">> => <<"PaymentToolDetailsMobileCommerce">>, - <<"phoneNumber">> => mask_phone_number(PhoneNumber) - }. - -decode_bank_card_details(BankCard, V) -> - LastDigits = BankCard#domain_BankCard.last_digits, - Bin = capi_handler_decoder_utils:decode_bank_card_bin(BankCard#domain_BankCard.bin), - PaymentSystem = capi_handler_decoder_utils:decode_payment_system_ref(BankCard#domain_BankCard.payment_system), - BankCardTokenServiceRef = capi_utils:'maybe'( - BankCard#domain_BankCard.payment_token, - fun capi_handler_decoder_utils:decode_bank_card_token_service_ref/1 - ), - capi_handler_utils:merge_and_compact(V, #{ - <<"last4">> => LastDigits, - <<"first6">> => Bin, - <<"cardNumberMask">> => capi_handler_decoder_utils:decode_masked_pan(Bin, LastDigits), - <<"paymentSystem">> => PaymentSystem, - <<"tokenProvider">> => BankCardTokenServiceRef - }). - -decode_payment_terminal_details( - #domain_PaymentTerminal{payment_service = #domain_PaymentServiceRef{id = Provider}}, - V -) -> - V#{ - <<"provider">> => Provider - }. - -decode_digital_wallet_details(#domain_DigitalWallet{payment_service = #domain_PaymentServiceRef{id = Provider}}, V) -> - V#{ - <<"provider">> => Provider - }. - -decode_crypto_wallet_details(#domain_CryptoCurrencyRef{id = Provider}) -> - Provider. - -mask_phone_number(PhoneNumber) -> - capi_utils:redact(PhoneNumber, <<"^\\+\\d(\\d{1,10}?)\\d{2,4}$">>). - -decode_mobile_phone(#domain_MobilePhone{cc = Cc, ctn = Ctn}) -> - #{<<"cc">> => Cc, <<"ctn">> => Ctn}. - -gen_phone_number(#{<<"cc">> := Cc, <<"ctn">> := Ctn}) -> - <<"+", Cc/binary, Ctn/binary>>. - -build_prototypes(OperationID, Context, Req) -> - InvoiceID = genlib_map:get('invoiceID', Req), - CustomerID = genlib_map:get('customerID', Req), - [ - {operation, #{ - id => OperationID, - party => capi_handler_utils:get_party_id(Context), - shop => genlib_map:get('shopID', Req), - invoice => InvoiceID, - payment => genlib_map:get('paymentID', Req), - customer => CustomerID, - refund => genlib_map:get('refundID', Req) - }}, - {payproc, #{ - invoice => InvoiceID, - customer => CustomerID - }} - ]. diff --git a/apps/capi/src/capi_handler_shops.erl b/apps/capi/src/capi_handler_shops.erl index 538dd2c..c808680 100644 --- a/apps/capi/src/capi_handler_shops.erl +++ b/apps/capi/src/capi_handler_shops.erl @@ -14,71 +14,6 @@ Req :: capi_handler:request_data(), Context :: capi_handler:processing_context() ) -> {ok, capi_handler:request_state()} | {error, noimpl}. -prepare('ActivateShop' = OperationID, Req, Context) -> - PartyID = capi_handler_utils:get_party_id(Context), - ShopID = maps:get('shopID', Req), - Authorize = fun() -> - Prototypes = [{operation, #{id => OperationID, party => PartyID, shop => ShopID}}], - {ok, capi_auth:authorize_operation(Prototypes, Context)} - end, - Process = fun() -> - case capi_party:activate_shop(PartyID, ShopID, Context) of - ok -> - {ok, {204, #{}, undefined}}; - {error, #payproc_ShopNotFound{}} -> - {ok, general_error(404, <<"Shop not found">>)}; - {error, #payproc_InvalidShopStatus{status = {suspension, {active, _}}}} -> - {ok, {204, #{}, undefined}} - end - end, - {ok, #{authorize => Authorize, process => Process}}; -prepare('SuspendShop' = OperationID, Req, Context) -> - PartyID = capi_handler_utils:get_party_id(Context), - ShopID = maps:get('shopID', Req), - Authorize = fun() -> - Prototypes = [{operation, #{id => OperationID, party => PartyID, shop => ShopID}}], - {ok, capi_auth:authorize_operation(Prototypes, Context)} - end, - Process = fun() -> - case capi_party:suspend_shop(PartyID, ShopID, Context) of - ok -> - {ok, {204, #{}, undefined}}; - {error, #payproc_ShopNotFound{}} -> - {ok, general_error(404, <<"Shop not found">>)}; - {error, #payproc_InvalidShopStatus{status = {suspension, {suspended, _}}}} -> - {ok, {204, #{}, undefined}} - end - end, - {ok, #{authorize => Authorize, process => Process}}; -prepare('GetShops' = OperationID, _Req, Context) -> - PartyID = capi_handler_utils:get_party_id(Context), - Authorize = fun() -> - Prototypes = [{operation, #{id => OperationID, party => PartyID}}], - {ok, capi_auth:authorize_operation(Prototypes, Context)} - end, - Process = fun() -> - Party = capi_utils:unwrap(capi_party:get_party(PartyID, Context)), - {ok, {200, #{}, decode_shops_map(Party#domain_Party.shops)}} - end, - {ok, #{authorize => Authorize, process => Process}}; -prepare('GetShopByID' = OperationID, Req, Context) -> - PartyID = capi_handler_utils:get_party_id(Context), - ShopID = maps:get('shopID', Req), - Authorize = fun() -> - Prototypes = [{operation, #{id => OperationID, party => PartyID, shop => ShopID}}], - {ok, capi_auth:authorize_operation(Prototypes, Context)} - end, - Process = fun() -> - case capi_party:get_shop(PartyID, ShopID, Context) of - {ok, Shop} -> - {ok, {200, #{}, decode_shop(Shop)}}; - {error, #payproc_PartyNotFound{}} -> - {ok, general_error(404, <<"Shop not found">>)}; - {error, #payproc_ShopNotFound{}} -> - {ok, general_error(404, <<"Shop not found">>)} - end - end, - {ok, #{authorize => Authorize, process => Process}}; prepare('GetShopsForParty' = OperationID, Req, Context) -> PartyID = maps:get('partyID', Req), Authorize = fun() -> @@ -88,17 +23,19 @@ prepare('GetShopsForParty' = OperationID, Req, Context) -> Process = fun() -> case capi_party:get_party(PartyID, Context) of {ok, Party} -> - {ok, {200, #{}, decode_shops_map(Party#domain_Party.shops)}}; - {error, #payproc_PartyNotFound{}} -> + Shops = get_shops_for_party(Party, Context), + {ok, {200, #{}, Shops}}; + {error, not_found} -> {ok, general_error(404, <<"Party not found">>)} end end, ProcessRestricted = fun(Restrictions) -> case capi_party:get_party(PartyID, Context) of {ok, Party} -> - Shops = restrict_shops(Party#domain_Party.shops, Restrictions), - {ok, {200, #{}, decode_shops_map(Shops)}}; - {error, #payproc_PartyNotFound{}} -> + Shops = get_shops_for_party(Party, Context), + RestrictedShops = restrict_shops(Shops, Restrictions), + {ok, {200, #{}, RestrictedShops}}; + {error, not_found} -> {ok, general_error(404, <<"Party not found">>)} end end, @@ -114,80 +51,60 @@ prepare('GetShopByIDForParty' = OperationID, Req, Context) -> case capi_party:get_shop(PartyID, ShopID, Context) of {ok, Shop} -> {ok, {200, #{}, decode_shop(Shop)}}; - {error, #payproc_PartyNotFound{}} -> - {ok, general_error(404, <<"Party not found">>)}; - {error, #payproc_ShopNotFound{}} -> + {error, not_found} -> {ok, general_error(404, <<"Shop not found">>)} end end, {ok, #{authorize => Authorize, process => Process}}; -prepare('ActivateShopForParty' = OperationID, Req, Context) -> - PartyID = maps:get('partyID', Req), - ShopID = maps:get('shopID', Req), - Authorize = fun() -> - Prototypes = [{operation, #{id => OperationID, party => PartyID, shop => ShopID}}], - {ok, capi_auth:authorize_operation(Prototypes, Context)} - end, - Process = fun() -> - case capi_party:activate_shop(PartyID, ShopID, Context) of - ok -> - {ok, {204, #{}, undefined}}; - {error, #payproc_PartyNotFound{}} -> - {ok, general_error(404, <<"Party not found">>)}; - {error, #payproc_ShopNotFound{}} -> - {ok, general_error(404, <<"Shop not found">>)}; - {error, #payproc_InvalidShopStatus{status = {suspension, {active, _}}}} -> - {ok, {204, #{}, undefined}} - end - end, - {ok, #{authorize => Authorize, process => Process}}; -prepare('SuspendShopForParty' = OperationID, Req, Context) -> - PartyID = maps:get('partyID', Req), - ShopID = maps:get('shopID', Req), - Authorize = fun() -> - Prototypes = [{operation, #{id => OperationID, party => PartyID, shop => ShopID}}], - {ok, capi_auth:authorize_operation(Prototypes, Context)} - end, - Process = fun() -> - case capi_party:suspend_shop(PartyID, ShopID, Context) of - ok -> - {ok, {204, #{}, undefined}}; - {error, #payproc_PartyNotFound{}} -> - {ok, general_error(404, <<"Party not found">>)}; - {error, #payproc_ShopNotFound{}} -> - {ok, general_error(404, <<"Shop not found">>)}; - {error, #payproc_InvalidShopStatus{status = {suspension, {suspended, _}}}} -> - {ok, {204, #{}, undefined}} - end - end, - {ok, #{authorize => Authorize, process => Process}}; +prepare('ActivateShopForParty', _Req, _Context) -> + {error, noimpl}; +prepare('SuspendShopForParty', _Req, _Context) -> + {error, noimpl}; prepare(_OperationID, _Req, _Context) -> {error, noimpl}. %% +get_shops_for_party(#domain_PartyConfig{shops = ShopRefs}, Context) -> + Shops = lists:foldl( + fun(ShopRef, Acc) -> + case capi_domain:get_ext({shop_config, ShopRef}, capi_domain:head(), Context) of + {ok, Shop} -> + [decode_shop(Shop) | Acc]; + {error, not_found} -> + Acc + end + end, + [], + ShopRefs + ), + lists:reverse(Shops). + restrict_shops(Shops, Restrictions) -> RestrictedShopIDs = capi_bouncer_restrictions:get_restricted_shop_ids(Restrictions), - maps:filter(fun(Key, _Value) -> lists:member(Key, RestrictedShopIDs) end, Shops). - -decode_shops_map(Shops) -> - capi_handler_decoder_utils:decode_map(Shops, fun decode_shop/1). + lists:filter( + fun(Shop) -> + ShopID = maps:get(<<"id">>, Shop), + lists:member(ShopID, RestrictedShopIDs) + end, + Shops + ). decode_shop(Shop) -> - Currency = capi_utils:'maybe'( - Shop#domain_Shop.account, - fun(#domain_ShopAccount{currency = Currency}) -> - capi_handler_decoder_utils:decode_currency(Currency) - end - ), + Currency = get_shop_currency(Shop), genlib_map:compact(#{ - <<"id">> => Shop#domain_Shop.id, - <<"createdAt">> => Shop#domain_Shop.created_at, - <<"isBlocked">> => capi_handler_decoder_party:is_blocked(Shop#domain_Shop.blocking), - <<"isSuspended">> => capi_handler_decoder_party:is_suspended(Shop#domain_Shop.suspension), + <<"id">> => Shop#domain_ShopConfig.id, + <<"createdAt">> => Shop#domain_ShopConfig.created_at, + <<"isBlocked">> => capi_handler_decoder_party:is_blocked(Shop#domain_ShopConfig.blocking), + <<"isSuspended">> => capi_handler_decoder_party:is_suspended(Shop#domain_ShopConfig.suspension), <<"currency">> => Currency, - <<"categoryID">> => capi_handler_decoder_utils:decode_category_ref(Shop#domain_Shop.category), - <<"details">> => capi_handler_decoder_party:decode_shop_details(Shop#domain_Shop.details), - <<"location">> => capi_handler_decoder_party:decode_shop_location(Shop#domain_Shop.location), - <<"contractID">> => Shop#domain_Shop.contract_id + <<"categoryID">> => capi_handler_decoder_utils:decode_category_ref(Shop#domain_ShopConfig.category), + <<"details">> => capi_handler_decoder_party:decode_shop_details(Shop#domain_ShopConfig.details), + <<"location">> => capi_handler_decoder_party:decode_shop_location(Shop#domain_ShopConfig.location), + <<"contractID">> => genlib:to_binary(Shop#domain_ShopConfig.terms#domain_TermSetHierarchyRef.id) }). + +get_shop_currency(#domain_ShopConfig{currency_configs = Configs}) when is_map(Configs) -> + %% TODO: fix it when add multi currency support + [Currency | _] = maps:keys(Configs), + capi_handler_decoder_utils:decode_currency(Currency). diff --git a/apps/capi/src/capi_handler_utils.erl b/apps/capi/src/capi_handler_utils.erl index 2d2e2d8..6f1f4bf 100644 --- a/apps/capi/src/capi_handler_utils.erl +++ b/apps/capi/src/capi_handler_utils.erl @@ -39,7 +39,6 @@ -type response() :: capi_handler:response(). -type entity() :: dmsl_domain_thrift:'Invoice'() - | dmsl_payproc_thrift:'Customer'() | dmsl_domain_thrift:'InvoiceTemplate'(). -type token_source() :: capi_auth:token_spec() | entity(). @@ -127,13 +126,6 @@ issue_access_token(#domain_Invoice{} = Invoice, ProcessingContext) -> shop => Invoice#domain_Invoice.shop_id }, issue_access_token(TokenSpec, ProcessingContext); -issue_access_token(#payproc_Customer{} = Customer, ProcessingContext) -> - TokenSpec = #{ - party => Customer#payproc_Customer.owner_id, - scope => {customer, Customer#payproc_Customer.id}, - shop => Customer#payproc_Customer.shop_id - }, - issue_access_token(TokenSpec, ProcessingContext); issue_access_token(#domain_InvoiceTemplate{} = InvoiceTpl, ProcessingContext) -> TokenSpec = #{ party => InvoiceTpl#domain_InvoiceTemplate.owner_id, @@ -288,11 +280,6 @@ emplace_token_provider_data(#domain_InvoiceTemplate{} = InvoiceTemplate, Payment PartyID = InvoiceTemplate#domain_InvoiceTemplate.owner_id, ShopID = InvoiceTemplate#domain_InvoiceTemplate.shop_id, TokenProviderData = construct_token_provider_data(PartyID, ShopID, Context), - emplace_token_provider_data(PaymentMethods, TokenProviderData); -emplace_token_provider_data(#payproc_Customer{} = Customer, PaymentMethods, Context) -> - PartyID = Customer#payproc_Customer.owner_id, - ShopID = Customer#payproc_Customer.shop_id, - TokenProviderData = construct_token_provider_data(PartyID, ShopID, Context), emplace_token_provider_data(PaymentMethods, TokenProviderData). emplace_token_provider_data(PaymentMethods, TokenProviderData) -> @@ -307,9 +294,9 @@ emplace_token_provider_data(PaymentMethods, TokenProviderData) -> ). construct_token_provider_data(PartyID, ShopID, Context) -> - {ok, ShopContract} = capi_party:get_shop_contract(PartyID, ShopID, Context), - ShopName = ShopContract#payproc_ShopContract.shop#domain_Shop.details#domain_ShopDetails.name, - PiRef = ShopContract#payproc_ShopContract.contract#domain_Contract.payment_institution, + {ok, ShopConfig} = capi_party:get_shop(PartyID, ShopID, Context), + ShopName = ShopConfig#domain_ShopConfig.details#domain_Details.name, + PiRef = ShopConfig#domain_ShopConfig.payment_institution, {ok, Pi} = capi_domain:get_payment_institution(PiRef, Context), Realm = Pi#domain_PaymentInstitution.realm, MerchantID = capi_merchant_id:encode(Realm, PartyID, ShopID), diff --git a/apps/capi/src/capi_handler_webhooks.erl b/apps/capi/src/capi_handler_webhooks.erl index f613995..624016c 100644 --- a/apps/capi/src/capi_handler_webhooks.erl +++ b/apps/capi/src/capi_handler_webhooks.erl @@ -28,7 +28,7 @@ prepare('CreateWebhook' = OperationID, Req, Context) -> case capi_party:get_shop(PartyID, ShopID, Context) of {ok, _} -> ok; - {error, #payproc_ShopNotFound{}} -> + {error, not_found} -> capi_handler:respond(logic_error('invalidShopID', <<"Shop not found">>)) end, case capi_handler_utils:service_call({webhook_manager, 'Create', {WebhookParams}}, Context) of @@ -127,8 +127,6 @@ validate_webhook_params(#webhooker_WebhookParams{event_filter = EventFilter}) -> validate_event_filter(EventFilter). validate_event_filter({invoice, #webhooker_InvoiceEventFilter{shop_id = ShopID}}) -> - validate_event_filter_shop(ShopID); -validate_event_filter({customer, #webhooker_CustomerEventFilter{shop_id = ShopID}}) -> validate_event_filter_shop(ShopID). validate_event_filter_shop(ShopID) when ShopID /= undefined -> @@ -171,11 +169,6 @@ encode_webhook_scope(#{<<"topic">> := <<"InvoicesTopic">>, <<"shopID">> := ShopI {invoice, #webhooker_InvoiceEventFilter{ shop_id = ShopID, types = ordsets:from_list([encode_invoice_event_type(V) || V <- EventTypes]) - }}; -encode_webhook_scope(#{<<"topic">> := <<"CustomersTopic">>, <<"shopID">> := ShopID, <<"eventTypes">> := EventTypes}) -> - {customer, #webhooker_CustomerEventFilter{ - shop_id = ShopID, - types = ordsets:from_list([encode_customer_event_type(V) || V <- EventTypes]) }}. -define(INVPAID(), {paid, #webhooker_InvoicePaid{}}). @@ -235,19 +228,6 @@ encode_invoice_event_type(<<"PaymentUserInteractionRequested">>) -> encode_invoice_event_type(<<"PaymentUserInteractionCompleted">>) -> {payment, {user_interaction, ?PMTUI(?PMTUISTATUSCOMPLETED())}}. -encode_customer_event_type(<<"CustomerCreated">>) -> - {created, #webhooker_CustomerCreated{}}; -encode_customer_event_type(<<"CustomerDeleted">>) -> - {deleted, #webhooker_CustomerDeleted{}}; -encode_customer_event_type(<<"CustomerReady">>) -> - {ready, #webhooker_CustomerStatusReady{}}; -encode_customer_event_type(<<"CustomerBindingStarted">>) -> - {binding, {started, #webhooker_CustomerBindingStarted{}}}; -encode_customer_event_type(<<"CustomerBindingSucceeded">>) -> - {binding, {succeeded, #webhooker_CustomerBindingSucceeded{}}}; -encode_customer_event_type(<<"CustomerBindingFailed">>) -> - {binding, {failed, #webhooker_CustomerBindingFailed{}}}. - %% decode_webhook(Hook) -> @@ -264,12 +244,6 @@ decode_event_filter({invoice, #webhooker_InvoiceEventFilter{shop_id = ShopID, ty <<"topic">> => <<"InvoicesTopic">>, <<"shopID">> => ShopID, <<"eventTypes">> => lists:flatmap(fun decode_invoice_event_type/1, ordsets:to_list(EventTypes)) - }); -decode_event_filter({customer, #webhooker_CustomerEventFilter{shop_id = ShopID, types = EventTypes}}) -> - genlib_map:compact(#{ - <<"topic">> => <<"CustomersTopic">>, - <<"shopID">> => ShopID, - <<"eventTypes">> => lists:map(fun decode_customer_event_type/1, ordsets:to_list(EventTypes)) }). decode_invoice_event_type({created, #webhooker_InvoiceCreated{}}) -> @@ -302,16 +276,3 @@ decode_payment_refund_status_event_type(?PMTRFNDSUCCEEDED()) -> <<"PaymentRefund decode_payment_user_interaction_status_event_type(?PMTUISTATUSREQUESTED()) -> <<"PaymentUserInteractionRequested">>; decode_payment_user_interaction_status_event_type(?PMTUISTATUSCOMPLETED()) -> <<"PaymentUserInteractionCompleted">>. - -decode_customer_event_type({created, #webhooker_CustomerCreated{}}) -> - <<"CustomerCreated">>; -decode_customer_event_type({deleted, #webhooker_CustomerDeleted{}}) -> - <<"CustomerDeleted">>; -decode_customer_event_type({ready, #webhooker_CustomerStatusReady{}}) -> - <<"CustomerReady">>; -decode_customer_event_type({binding, {started, #webhooker_CustomerBindingStarted{}}}) -> - <<"CustomerBindingStarted">>; -decode_customer_event_type({binding, {succeeded, #webhooker_CustomerBindingSucceeded{}}}) -> - <<"CustomerBindingSucceeded">>; -decode_customer_event_type({binding, {failed, #webhooker_CustomerBindingFailed{}}}) -> - <<"CustomerBindingFailed">>. diff --git a/apps/capi/src/capi_party.erl b/apps/capi/src/capi_party.erl index be53156..c22dfc0 100644 --- a/apps/capi/src/capi_party.erl +++ b/apps/capi/src/capi_party.erl @@ -1,70 +1,53 @@ -module(capi_party). --export([create_party/3]). +-include_lib("damsel/include/dmsl_domain_thrift.hrl"). +-include_lib("damsel/include/dmsl_payproc_thrift.hrl"). + -export([get_party/2]). --export([activate_party/2]). --export([suspend_party/2]). --export([get_contract/3]). -export([get_shop/3]). --export([get_shop_contract/3]). --export([activate_shop/3]). --export([suspend_shop/3]). -export([compute_payment_institution_terms/3]). -type result() :: ok | {ok, woody:result()} | {error, woody_error:business_error()}. -type processing_context() :: capi_handler:processing_context(). -type party_id() :: party_client_thrift:party_id(). --type party_params() :: party_client_thrift:party_params(). -type payment_institution_ref() :: party_client_thrift:payment_institution_ref(). -type varset() :: party_client_thrift:varset(). --type contract_id() :: party_client_thrift:contract_id(). -type shop_id() :: party_client_thrift:shop_id(). +-type party() :: dmsl_domain_thrift:'PartyConfig'(). +-type shop() :: dmsl_domain_thrift:'ShopConfig'(). --spec create_party(party_id(), party_params(), processing_context()) -> result(). -create_party(PartyID, PartyParams, Context) -> - {Client, ClientContext} = client_context(Context), - party_client_thrift:create(PartyID, PartyParams, Client, ClientContext). - --spec get_party(party_id(), processing_context()) -> result(). +-spec get_party(party_id(), processing_context()) -> {ok, party()} | {error, not_found}. get_party(PartyID, Context) -> - {Client, ClientContext} = client_context(Context), - party_client_thrift:get(PartyID, Client, ClientContext). + checkout(PartyID, get_party_revision(), Context). --spec activate_party(party_id(), processing_context()) -> result(). -activate_party(PartyID, Context) -> - {Client, ClientContext} = client_context(Context), - party_client_thrift:activate(PartyID, Client, ClientContext). - --spec suspend_party(party_id(), processing_context()) -> result(). -suspend_party(PartyID, Context) -> - {Client, ClientContext} = client_context(Context), - party_client_thrift:suspend(PartyID, Client, ClientContext). +-spec get_party_revision() -> capi_domain:revision(). +get_party_revision() -> + capi_domain:head(). --spec get_contract(party_id(), contract_id(), processing_context()) -> result(). -get_contract(PartyID, ContractID, Context) -> - {Client, ClientContext} = client_context(Context), - party_client_thrift:get_contract(PartyID, ContractID, Client, ClientContext). +-spec checkout(party_id(), capi_domain:revision(), processing_context()) -> {ok, party()} | {error, not_found}. +checkout(PartyID, Revision, Context) -> + case capi_domain:get_ext({party_config, #domain_PartyConfigRef{id = PartyID}}, Revision, Context) of + {error, not_found} = Error -> + Error; + Party -> + Party + end. --spec get_shop(party_id(), shop_id(), processing_context()) -> result(). +-spec get_shop(party_id(), shop_id(), processing_context()) -> {ok, shop()} | {error, not_found}. get_shop(PartyID, ShopID, Context) -> - {Client, ClientContext} = client_context(Context), - party_client_thrift:get_shop(PartyID, ShopID, Client, ClientContext). - --spec get_shop_contract(party_id(), shop_id(), processing_context()) -> result(). -get_shop_contract(PartyID, ShopID, Context) -> - {Client, ClientContext} = client_context(Context), - party_client_thrift:get_shop_contract(PartyID, ShopID, Client, ClientContext). - --spec activate_shop(party_id(), shop_id(), processing_context()) -> result(). -activate_shop(PartyID, ShopID, Context) -> - {Client, ClientContext} = client_context(Context), - party_client_thrift:activate_shop(PartyID, ShopID, Client, ClientContext). - --spec suspend_shop(party_id(), shop_id(), processing_context()) -> result(). -suspend_shop(PartyID, ShopID, Context) -> - {Client, ClientContext} = client_context(Context), - party_client_thrift:suspend_shop(PartyID, ShopID, Client, ClientContext). + case get_party(PartyID, Context) of + {ok, #domain_PartyConfig{shops = ShopRefs}} -> + Ref = #domain_ShopConfigRef{id = ShopID}, + case lists:member(Ref, ShopRefs) of + true -> + capi_domain:get_ext({shop_config, Ref}, capi_domain:head(), Context); + false -> + {error, not_found} + end; + {error, not_found} -> + {error, not_found} + end. -spec compute_payment_institution_terms( payment_institution_ref(), diff --git a/apps/capi/test/capi_authorization_tests_SUITE.erl b/apps/capi/test/capi_authorization_tests_SUITE.erl index 9277fb1..a65d851 100644 --- a/apps/capi/test/capi_authorization_tests_SUITE.erl +++ b/apps/capi/test/capi_authorization_tests_SUITE.erl @@ -27,8 +27,7 @@ get_invoice_forbidden_notfound/1, get_invoice_by_external_id_forbidden_notfound/1, get_payment_by_external_id_forbidden_notfound/1, - get_refund_by_external_id_forbidden_notfound/1, - get_customer_forbidden_notfound/1 + get_refund_by_external_id_forbidden_notfound/1 ]). -define(EMPTYRESP(Code), {error, {Code, #{}}}). @@ -62,8 +61,7 @@ groups() -> get_invoice_forbidden_notfound, get_invoice_by_external_id_forbidden_notfound, get_payment_by_external_id_forbidden_notfound, - get_refund_by_external_id_forbidden_notfound, - get_customer_forbidden_notfound + get_refund_by_external_id_forbidden_notfound ]} ]. @@ -117,9 +115,8 @@ authorization_error_no_header_test(Config) -> -spec authorization_error_no_permission_test(config()) -> _. authorization_error_no_permission_test(Config) -> - Token = ?API_TOKEN, _ = capi_ct_helper_bouncer:mock_arbiter(capi_ct_helper_bouncer:judge_always_forbidden(), Config), - ?EMPTYRESP(401) = capi_client_parties:get_my_party(capi_ct_helper:get_context(Token)). + ?EMPTYRESP(404) = capi_client_parties:get_party_by_id(mk_context(), <<"ANY_ID">>). %%% @@ -128,7 +125,6 @@ authorization_error_no_permission_test(Config) -> -spec get_invoice_by_external_id_forbidden_notfound(config()) -> _. -spec get_payment_by_external_id_forbidden_notfound(config()) -> _. -spec get_refund_by_external_id_forbidden_notfound(config()) -> _. --spec get_customer_forbidden_notfound(config()) -> _. get_party_forbidden_notfound(Config) -> PartyID = <<"NONEXISTENT">>, @@ -175,13 +171,5 @@ get_refund_by_external_id_forbidden_notfound(Config) -> ), {error, {404, _}} = capi_client_payments:get_refund_by_external_id(mk_context(), ExternalID). -get_customer_forbidden_notfound(Config) -> - CustomerID = <<"NONEXISTENT">>, - _ = capi_ct_helper:mock_services( - [{customer_management, fun('Get', _) -> {throwing, #payproc_CustomerNotFound{}} end}], - Config - ), - {error, {404, _}} = capi_client_customers:get_customer_by_id(mk_context(), CustomerID). - mk_context() -> capi_ct_helper:get_context(?API_TOKEN). diff --git a/apps/capi/test/capi_base_api_token_tests_SUITE.erl b/apps/capi/test/capi_base_api_token_tests_SUITE.erl index feb74a6..60f198e 100644 --- a/apps/capi/test/capi_base_api_token_tests_SUITE.erl +++ b/apps/capi/test/capi_base_api_token_tests_SUITE.erl @@ -34,10 +34,6 @@ create_invoice_template_w_randomization_ok_test/1, create_invoice_with_template_test/1, create_invoice_template_autorization_error_test/1, - create_customer_ok_test/1, - create_customer_autorization_error_test/1, - delete_customer_ok_test/1, - create_customer_access_token_ok_test/1, rescind_invoice_ok_test/1, fulfill_invoice_ok_test/1, @@ -63,35 +59,12 @@ get_refund_by_external_id/1, update_invoice_template_ok_test/1, delete_invoice_template_ok_test/1, - get_my_party_ok_test/1, - get_my_party_lazy_creation_ok_test/1, - get_my_party_lazy_creation_fail_test/1, - suspend_my_party_ok_test/1, - activate_my_party_ok_test/1, get_party_by_id_ok_test/1, - suspend_party_by_id_ok_test/1, - activate_party_by_id_ok_test/1, - get_shop_by_id_ok_test/1, - get_shops_ok_test/1, - activate_shop_ok_test/1, - suspend_shop_ok_test/1, get_shop_by_id_for_party_ok_test/1, get_shops_for_party_ok_test/1, get_shops_for_party_restricted_ok_test/1, - suspend_shop_for_party_ok_test/1, - activate_shop_for_party_ok_test/1, get_shop_by_id_for_party_error_test/1, get_shops_for_party_error_test/1, - suspend_shop_for_party_error_test/1, - activate_shop_for_party_error_test/1, - get_contract_by_id_ok_test/1, - get_contract_by_id_for_party_ok_test/1, - get_contracts_ok_test/1, - get_contracts_for_party_ok_test/1, - get_contract_adjustments_ok_test/1, - get_contract_adjustments_for_party_ok_test/1, - get_contract_adjustment_by_id_ok_test/1, - get_contract_adjustment_by_id_for_party_ok_test/1, create_webhook_ok_test/1, create_webhook_limit_exceeded_test/1, get_webhooks/1, @@ -141,19 +114,12 @@ all() -> groups() -> [ {operations_by_api_key_token, [], [ - get_my_party_lazy_creation_fail_test, {group, operations_by_any_token} ]}, {operations_by_user_session_token, [], [ - get_my_party_lazy_creation_ok_test, {group, operations_by_any_token} ]}, {operations_by_any_token, [], [ - create_customer_ok_test, - create_customer_autorization_error_test, - delete_customer_ok_test, - create_customer_access_token_ok_test, - create_invoice_ok_test, create_invoice_rand_amount_ok_test, create_invoice_autorization_error_test, @@ -171,37 +137,14 @@ groups() -> update_invoice_template_ok_test, delete_invoice_template_ok_test, - get_my_party_ok_test, - suspend_my_party_ok_test, - activate_my_party_ok_test, get_party_by_id_ok_test, - suspend_party_by_id_ok_test, - activate_party_by_id_ok_test, - get_shop_by_id_ok_test, - get_shops_ok_test, - activate_shop_ok_test, - suspend_shop_ok_test, - get_categories_ok_test, - get_contract_by_id_ok_test, - get_contract_by_id_for_party_ok_test, - get_contracts_ok_test, - get_contracts_for_party_ok_test, - get_contract_adjustments_ok_test, - get_contract_adjustments_for_party_ok_test, - get_contract_adjustment_by_id_ok_test, - get_contract_adjustment_by_id_for_party_ok_test, - get_shop_by_id_for_party_ok_test, get_shop_by_id_for_party_error_test, get_shops_for_party_ok_test, get_shops_for_party_restricted_ok_test, get_shops_for_party_error_test, - suspend_shop_for_party_ok_test, - suspend_shop_for_party_error_test, - activate_shop_for_party_ok_test, - activate_shop_for_party_error_test, create_payment_ok_test, create_payment_with_changed_cost_ok_test, @@ -646,77 +589,6 @@ check_no_internal_id_for_external_id_test(Config) -> %% {error, {401, #{}}}. {error, {_, 500}} = capi_client_payments:get_payment_by_external_id(?config(context, Config), ExternalID). --spec create_customer_ok_test(config()) -> _. -create_customer_ok_test(Config) -> - _ = capi_ct_helper:mock_services( - [ - {customer_management, fun('Create', {#payproc_CustomerParams{party_id = ?STRING}}) -> {ok, ?CUSTOMER} end}, - {generator, fun('GenerateID', _) -> capi_ct_helper_bender:generate_id(<<"bender_key">>) end} - ], - Config - ), - _ = capi_ct_helper_bouncer:mock_assert_shop_op_ctx(<<"CreateCustomer">>, ?STRING, ?STRING, Config), - {ok, _} = capi_client_customers:create_customer(?config(context, Config), ?CUSTOMER_PARAMS). - --spec create_customer_autorization_error_test(config()) -> _. -create_customer_autorization_error_test(Config) -> - _ = capi_ct_helper:mock_services( - [ - {customer_management, fun('Create', {#payproc_CustomerParams{party_id = <<"WrongPartyID">>}}) -> - {throwing, #payproc_PartyNotFound{}} - end}, - {generator, fun('GenerateID', _) -> capi_ct_helper_bender:generate_id(<<"bender_key">>) end} - ], - Config - ), - _ = capi_ct_helper_bouncer:mock_assert_shop_op_ctx( - <<"CreateCustomer">>, - <<"WrongPartyID">>, - ?STRING, - Config - ), - ?assertMatch( - {error, {400, #{<<"code">> := <<"invalidPartyID">>}}}, - capi_client_customers:create_customer( - ?config(context, Config), - maps:merge(?CUSTOMER_PARAMS, #{ - <<"partyID">> => <<"WrongPartyID">> - }) - ) - ). - --spec delete_customer_ok_test(config()) -> _. -delete_customer_ok_test(Config) -> - _ = capi_ct_helper:mock_services( - [ - {customer_management, fun - ('Get', _) -> {ok, ?CUSTOMER}; - ('Delete', _) -> {ok, ok} - end} - ], - Config - ), - _ = capi_ct_helper_bouncer:mock_assert_customer_op_ctx( - <<"DeleteCustomer">>, - ?STRING, - ?STRING, - ?STRING, - Config - ), - {ok, _} = capi_client_customers:delete_customer(?config(context, Config), ?STRING). - --spec create_customer_access_token_ok_test(config()) -> _. -create_customer_access_token_ok_test(Config) -> - _ = capi_ct_helper:mock_services([{customer_management, fun('Get', _) -> {ok, ?CUSTOMER} end}], Config), - _ = capi_ct_helper_bouncer:mock_assert_customer_op_ctx( - <<"CreateCustomerAccessToken">>, - ?STRING, - ?STRING, - ?STRING, - Config - ), - {ok, _} = capi_client_customers:create_customer_access_token(?config(context, Config), ?STRING). - -spec rescind_invoice_ok_test(config()) -> _. rescind_invoice_ok_test(Config) -> _ = capi_ct_helper:mock_services( @@ -1294,93 +1166,6 @@ delete_invoice_template_ok_test(Config) -> ), ok = capi_client_invoice_templates:delete(?config(context, Config), ?STRING). --spec get_my_party_ok_test(config()) -> _. -get_my_party_ok_test(Config) -> - _ = capi_ct_helper:mock_services( - [ - {party_management, fun - ('GetRevision', _) -> {ok, ?INTEGER}; - ('Checkout', _) -> {ok, ?PARTY} - end} - ], - Config - ), - _ = capi_ct_helper_bouncer:mock_assert_party_op_ctx(<<"GetMyParty">>, ?STRING, Config), - {ok, _} = capi_client_parties:get_my_party(?config(context, Config)). - --spec get_my_party_lazy_creation_ok_test(config()) -> _. -get_my_party_lazy_creation_ok_test(Config) -> - TestETS = ets:new(get_my_party_lazy_creation_ok_test, [public]), - _ = capi_ct_helper:mock_services( - [ - {party_management, fun - ('GetRevision', _) -> - case ets:lookup(TestETS, party_created) of - [{party_created, true}] -> {ok, ?INTEGER}; - _ -> {throwing, #payproc_PartyNotFound{}} - end; - ('Checkout', _) -> - case ets:lookup(TestETS, party_created) of - [{party_created, true}] -> {ok, ?PARTY}; - _ -> {throwing, #payproc_PartyNotFound{}} - end; - ('Create', _) -> - case ets:insert_new(TestETS, {party_created, true}) of - true -> {ok, ok}; - _ -> {throwing, #payproc_PartyExists{}} - end - end} - ], - Config - ), - _ = capi_ct_helper_bouncer:mock_assert_party_op_ctx(<<"GetMyParty">>, ?STRING, Config), - {ok, _} = capi_client_parties:get_my_party(?config(context, Config)), - true = ets:delete(TestETS). - --spec get_my_party_lazy_creation_fail_test(config()) -> _. -get_my_party_lazy_creation_fail_test(Config) -> - TestETS = ets:new(get_my_party_lazy_creation_fail_test, [public]), - _ = capi_ct_helper:mock_services( - [ - {party_management, fun - ('GetRevision', _) -> - case ets:lookup(TestETS, party_created) of - [{party_created, true}] -> {ok, ?INTEGER}; - _ -> {throwing, #payproc_PartyNotFound{}} - end; - ('Checkout', _) -> - case ets:lookup(TestETS, party_created) of - [{party_created, true}] -> {ok, ?PARTY}; - _ -> {throwing, #payproc_PartyNotFound{}} - end; - ('Create', _) -> - case ets:insert_new(TestETS, {party_created, true}) of - true -> {ok, ok}; - _ -> {throwing, #payproc_PartyExists{}} - end - end} - ], - Config - ), - _ = capi_ct_helper_bouncer:mock_assert_party_op_ctx(<<"GetMyParty">>, ?STRING, Config), - ?assertMatch( - {error, {400, _}}, - capi_client_parties:get_my_party(?config(context, Config)) - ), - true = ets:delete(TestETS). - --spec suspend_my_party_ok_test(config()) -> _. -suspend_my_party_ok_test(Config) -> - _ = capi_ct_helper:mock_services([{party_management, fun('Suspend', _) -> {ok, ok} end}], Config), - _ = capi_ct_helper_bouncer:mock_assert_party_op_ctx(<<"SuspendMyParty">>, ?STRING, Config), - ok = capi_client_parties:suspend_my_party(?config(context, Config)). - --spec activate_my_party_ok_test(config()) -> _. -activate_my_party_ok_test(Config) -> - _ = capi_ct_helper:mock_services([{party_management, fun('Activate', _) -> {ok, ok} end}], Config), - _ = capi_ct_helper_bouncer:mock_assert_party_op_ctx(<<"ActivateMyParty">>, ?STRING, Config), - ok = capi_client_parties:activate_my_party(?config(context, Config)). - -spec get_party_by_id_ok_test(config()) -> _. get_party_by_id_ok_test(Config) -> _ = capi_ct_helper:mock_services( @@ -1395,24 +1180,6 @@ get_party_by_id_ok_test(Config) -> _ = capi_ct_helper_bouncer:mock_assert_party_op_ctx(<<"GetPartyByID">>, ?STRING, Config), {ok, _} = capi_client_parties:get_party_by_id(?config(context, Config), ?STRING). --spec suspend_party_by_id_ok_test(config()) -> _. -suspend_party_by_id_ok_test(Config) -> - _ = capi_ct_helper:mock_services([{party_management, fun('Suspend', _) -> {ok, ok} end}], Config), - _ = capi_ct_helper_bouncer:mock_assert_party_op_ctx(<<"SuspendPartyByID">>, ?STRING, Config), - ok = capi_client_parties:suspend_party_by_id(?config(context, Config), ?STRING). - --spec activate_party_by_id_ok_test(config()) -> _. -activate_party_by_id_ok_test(Config) -> - _ = capi_ct_helper:mock_services([{party_management, fun('Activate', _) -> {ok, ok} end}], Config), - _ = capi_ct_helper_bouncer:mock_assert_party_op_ctx(<<"ActivatePartyByID">>, ?STRING, Config), - ok = capi_client_parties:activate_party_by_id(?config(context, Config), ?STRING). - --spec get_shop_by_id_ok_test(config()) -> _. -get_shop_by_id_ok_test(Config) -> - _ = capi_ct_helper:mock_services([{party_management, fun('GetShop', _) -> {ok, ?SHOP} end}], Config), - _ = capi_ct_helper_bouncer:mock_assert_shop_op_ctx(<<"GetShopByID">>, ?STRING, ?STRING, Config), - {ok, _} = capi_client_shops:get_shop_by_id(?config(context, Config), ?STRING). - -spec get_shop_by_id_for_party_ok_test(config()) -> _. get_shop_by_id_for_party_ok_test(Config) -> _ = capi_ct_helper:mock_services( @@ -1445,27 +1212,13 @@ get_shop_by_id_for_party_error_test(Config) -> capi_client_shops:get_shop_by_id_for_party(?config(context, Config), <<"WrongPartyID">>, ?STRING) ). --spec get_shops_ok_test(config()) -> _. -get_shops_ok_test(Config) -> - _ = capi_ct_helper:mock_services( - [ - {party_management, fun - ('GetRevision', _) -> {ok, ?INTEGER}; - ('Checkout', _) -> {ok, ?PARTY} - end} - ], - Config - ), - _ = capi_ct_helper_bouncer:mock_assert_party_op_ctx(<<"GetShops">>, ?STRING, Config), - {ok, _} = capi_client_shops:get_shops(?config(context, Config)). - -spec get_shops_for_party_ok_test(config()) -> _. get_shops_for_party_ok_test(Config) -> _ = capi_ct_helper:mock_services( [ {party_management, fun ('GetRevision', _) -> {ok, ?INTEGER}; - ('Checkout', _) -> {ok, ?PARTY} + ('Checkout', _) -> {ok, ?PARTY_WITH_SHOPS} end} ], Config @@ -1479,12 +1232,12 @@ get_shops_for_party_restricted_ok_test(Config) -> [ {party_management, fun ('GetRevision', _) -> {ok, ?INTEGER}; - ('Checkout', _) -> {ok, ?PARTY} + ('Checkout', _) -> {ok, ?PARTY_WITH_SHOPS} end} ], Config ), - _ = capi_ct_helper_bouncer:mock_restricted_shops([?CTX_ENTITY(?USD)], Config), + _ = capi_ct_helper_bouncer:mock_restricted_shops([?CTX_ENTITY(?STRING)], Config), {ok, [#{<<"currency">> := ?USD}]} = capi_client_shops:get_shops_for_party(?config(context, Config), ?STRING). @@ -1501,223 +1254,6 @@ get_shops_for_party_error_test(Config) -> capi_client_shops:get_shops_for_party(?config(context, Config), <<"WrongPartyID">>) ). --spec activate_shop_ok_test(config()) -> _. -activate_shop_ok_test(Config) -> - _ = capi_ct_helper:mock_services([{party_management, fun('ActivateShop', _) -> {ok, ok} end}], Config), - _ = capi_ct_helper_bouncer:mock_assert_shop_op_ctx(<<"ActivateShop">>, ?STRING, ?STRING, Config), - ok = capi_client_shops:activate_shop(?config(context, Config), ?STRING). - --spec activate_shop_for_party_ok_test(config()) -> _. -activate_shop_for_party_ok_test(Config) -> - _ = capi_ct_helper:mock_services( - [ - {party_management, fun('ActivateShop', {?STRING, _}) -> {ok, ok} end} - ], - Config - ), - _ = capi_ct_helper_bouncer:mock_assert_shop_op_ctx(<<"ActivateShopForParty">>, ?STRING, ?STRING, Config), - ok = capi_client_shops:activate_shop_for_party(?config(context, Config), ?STRING, ?STRING). - --spec activate_shop_for_party_error_test(config()) -> _. -activate_shop_for_party_error_test(Config) -> - _ = capi_ct_helper:mock_services( - [ - {party_management, fun('ActivateShop', {<<"WrongPartyID">>, _}) -> - {throwing, #payproc_PartyNotFound{}} - end} - ], - Config - ), - _ = capi_ct_helper_bouncer:mock_assert_shop_op_ctx( - <<"ActivateShopForParty">>, - <<"WrongPartyID">>, - ?STRING, - Config - ), - ?assertMatch( - {error, {404, _}}, - capi_client_shops:activate_shop_for_party(?config(context, Config), <<"WrongPartyID">>, ?STRING) - ). - --spec suspend_shop_ok_test(config()) -> _. -suspend_shop_ok_test(Config) -> - _ = capi_ct_helper:mock_services([{party_management, fun('SuspendShop', _) -> {ok, ok} end}], Config), - _ = capi_ct_helper_bouncer:mock_assert_shop_op_ctx(<<"SuspendShop">>, ?STRING, ?STRING, Config), - ok = capi_client_shops:suspend_shop(?config(context, Config), ?STRING). - --spec suspend_shop_for_party_ok_test(config()) -> _. -suspend_shop_for_party_ok_test(Config) -> - _ = capi_ct_helper:mock_services( - [ - {party_management, fun('SuspendShop', _) -> {ok, ok} end} - ], - Config - ), - _ = capi_ct_helper_bouncer:mock_assert_shop_op_ctx(<<"SuspendShopForParty">>, ?STRING, ?STRING, Config), - ok = capi_client_shops:suspend_shop_for_party(?config(context, Config), ?STRING, ?STRING). - --spec suspend_shop_for_party_error_test(config()) -> _. -suspend_shop_for_party_error_test(Config) -> - _ = capi_ct_helper:mock_services( - [ - {party_management, fun('SuspendShop', {<<"WrongPartyID">>, _}) -> - {throwing, #payproc_PartyNotFound{}} - end} - ], - Config - ), - _ = capi_ct_helper_bouncer:mock_assert_shop_op_ctx( - <<"SuspendShopForParty">>, - <<"WrongPartyID">>, - ?STRING, - Config - ), - ?assertMatch( - {error, {404, _}}, - capi_client_shops:suspend_shop_for_party(?config(context, Config), <<"WrongPartyID">>, ?STRING) - ). - --spec get_contract_by_id_ok_test(config()) -> _. -get_contract_by_id_ok_test(Config) -> - _ = capi_ct_helper:mock_services( - [ - {party_management, fun - ('GetRevision', _) -> {ok, ?INTEGER}; - ('Checkout', _) -> {ok, ?PARTY}; - ('GetContract', _) -> {ok, ?CONTRACT} - end} - ], - Config - ), - - _ = capi_ct_helper_bouncer:mock_arbiter( - ?assertContextMatches( - #ctx_v1_ContextFragment{ - capi = ?CTX_CAPI(?CTX_CONTRACT_OP(<<"GetContractByID">>, ?STRING, _)) - } - ), - Config - ), - {ok, _} = capi_client_contracts:get_contract_by_id(?config(context, Config), ?STRING), - {ok, _} = capi_client_contracts:get_contract_by_id(?config(context, Config), ?WALLET_CONTRACT_ID). - --spec get_contract_by_id_for_party_ok_test(config()) -> _. -get_contract_by_id_for_party_ok_test(Config) -> - _ = capi_ct_helper:mock_services( - [ - {party_management, fun - ('GetRevision', _) -> {ok, ?INTEGER}; - ('Checkout', _) -> {ok, ?PARTY}; - ('GetContract', _) -> {ok, ?CONTRACT} - end} - ], - Config - ), - - _ = capi_ct_helper_bouncer:mock_assert_contract_op_ctx( - <<"GetContractByIDForParty">>, - ?STRING, - ?STRING, - Config - ), - {ok, _} = capi_client_contracts:get_contract_by_id_for_party(?config(context, Config), ?STRING, ?STRING). - --spec get_contracts_ok_test(config()) -> _. -get_contracts_ok_test(Config) -> - _ = capi_ct_helper:mock_services( - [ - {party_management, fun - ('GetRevision', _) -> {ok, ?INTEGER}; - ('Checkout', _) -> {ok, ?PARTY} - end} - ], - Config - ), - - _ = capi_ct_helper_bouncer:mock_assert_party_op_ctx(<<"GetContracts">>, ?STRING, Config), - {ok, [_First, _Second]} = capi_client_contracts:get_contracts(?config(context, Config)). - --spec get_contracts_for_party_ok_test(config()) -> _. -get_contracts_for_party_ok_test(Config) -> - _ = capi_ct_helper:mock_services( - [ - {party_management, fun - ('GetRevision', _) -> {ok, ?INTEGER}; - ('Checkout', _) -> {ok, ?PARTY} - end} - ], - Config - ), - _ = capi_ct_helper_bouncer:mock_assert_party_op_ctx(<<"GetContractsForParty">>, ?STRING, Config), - {ok, [_First, _Second]} = capi_client_contracts:get_contracts_for_party(?config(context, Config), ?STRING). - --spec get_contract_adjustments_ok_test(config()) -> _. -get_contract_adjustments_ok_test(Config) -> - _ = capi_ct_helper:mock_services( - [ - {party_management, fun - ('GetRevision', _) -> {ok, ?INTEGER}; - ('Checkout', _) -> {ok, ?PARTY}; - ('GetContract', _) -> {ok, ?CONTRACT} - end} - ], - Config - ), - _ = capi_ct_helper_bouncer:mock_assert_contract_op_ctx( - <<"GetContractAdjustments">>, - ?STRING, - ?STRING, - Config - ), - {ok, _} = capi_client_contracts:get_contract_adjustments(?config(context, Config), ?STRING). - --spec get_contract_adjustments_for_party_ok_test(config()) -> _. -get_contract_adjustments_for_party_ok_test(Config) -> - _ = capi_ct_helper:mock_services([{party_management, fun('GetContract', _) -> {ok, ?CONTRACT} end}], Config), - _ = capi_ct_helper_bouncer:mock_assert_contract_op_ctx( - <<"GetContractAdjustmentsForParty">>, - ?STRING, - ?STRING, - Config - ), - {ok, _} = capi_client_contracts:get_contract_adjustments_for_party(?config(context, Config), ?STRING, ?STRING). - --spec get_contract_adjustment_by_id_ok_test(config()) -> _. -get_contract_adjustment_by_id_ok_test(Config) -> - _ = capi_ct_helper:mock_services( - [ - {party_management, fun - ('GetRevision', _) -> {ok, ?INTEGER}; - ('Checkout', _) -> {ok, ?PARTY}; - ('GetContract', _) -> {ok, ?CONTRACT} - end} - ], - Config - ), - _ = capi_ct_helper_bouncer:mock_assert_contract_op_ctx( - <<"GetContractAdjustmentByID">>, - ?STRING, - ?STRING, - Config - ), - {ok, _} = capi_client_contracts:get_contract_adjustment_by_id(?config(context, Config), ?STRING, ?STRING). - --spec get_contract_adjustment_by_id_for_party_ok_test(config()) -> _. -get_contract_adjustment_by_id_for_party_ok_test(Config) -> - _ = capi_ct_helper:mock_services([{party_management, fun('GetContract', _) -> {ok, ?CONTRACT} end}], Config), - _ = capi_ct_helper_bouncer:mock_assert_contract_op_ctx( - <<"GetContractAdjustmentByIDForParty">>, - ?STRING, - ?STRING, - Config - ), - {ok, _} = capi_client_contracts:get_contract_adjustment_by_id_for_party( - ?config(context, Config), - ?STRING, - ?STRING, - ?STRING - ). - -spec create_webhook_ok_test(config()) -> _. create_webhook_ok_test(Config) -> _ = capi_ct_helper:mock_services( @@ -2150,4 +1686,4 @@ different_ip_header(Config) -> ), Context0 = ?config(context, Config), Context1 = Context0#{ip_address => IPAddress}, - {ok, _} = capi_client_shops:get_shop_by_id(Context1, ?STRING). + {ok, _} = capi_client_shops:get_shop_by_id_for_party(Context1, ?STRING, ?STRING). diff --git a/apps/capi/test/capi_bouncer_data.hrl b/apps/capi/test/capi_bouncer_data.hrl index 145432b..55d7370 100644 --- a/apps/capi/test/capi_bouncer_data.hrl +++ b/apps/capi/test/capi_bouncer_data.hrl @@ -43,12 +43,6 @@ shop = ?CTX_ENTITY(ShopID) }). --define(CTX_CONTRACT_OP(ID, PartyID, ContractID), #ctx_v1_CommonAPIOperation{ - id = ID, - party = ?CTX_ENTITY(PartyID), - contract = ?CTX_ENTITY(ContractID) -}). - -define(CTX_INVOICE_OP(ID, InvoiceID), #ctx_v1_CommonAPIOperation{ id = ID, invoice = ?CTX_ENTITY(InvoiceID) @@ -77,54 +71,11 @@ invoice_template = ?CTX_ENTITY(InvoiceTemplateID) }). --define(CTX_CUSTOMER_OP(ID, CustomerID), #ctx_v1_CommonAPIOperation{ - id = ID, - customer = ?CTX_ENTITY(CustomerID) -}). - --define(CTX_BINDING_OP(ID, CustomerID, BindingID), #ctx_v1_CommonAPIOperation{ - id = ID, - customer = ?CTX_ENTITY(CustomerID), - binding = ?CTX_ENTITY(BindingID) -}). - -define(CTX_WEBHOOK_OP(ID, WebhookID), #ctx_v1_CommonAPIOperation{ id = ID, webhook = ?CTX_ENTITY(WebhookID) }). --define(CTX_SEARCH_OP(ID, PartyID, ShopID, InvoiceID, PaymentID), - ?CTX_SEARCH_OP( - ID, - PartyID, - ShopID, - InvoiceID, - PaymentID, - undefined, - undefined - ) -). - --define(CTX_SEARCH_OP( - ID, - PartyID, - ShopID, - InvoiceID, - PaymentID, - CustomerID, - RefundID -), - #ctx_v1_CommonAPIOperation{ - id = ID, - party = ?CTX_ENTITY(PartyID), - shop = ?CTX_ENTITY(ShopID), - invoice = capi_utils:'maybe'(InvoiceID, fun(V) -> ?CTX_ENTITY(V) end), - payment = capi_utils:'maybe'(PaymentID, fun(V) -> ?CTX_ENTITY(V) end), - customer = capi_utils:'maybe'(CustomerID, fun(V) -> ?CTX_ENTITY(V) end), - refund = capi_utils:'maybe'(RefundID, fun(V) -> ?CTX_ENTITY(V) end) - } -). - -define(CTX_INVOICE(ID, PartyID, ShopID), #ctx_v1_Invoice{ id = ID, party = ?CTX_ENTITY(PartyID), @@ -146,12 +97,6 @@ shop = ?CTX_ENTITY(ShopID) }). --define(CTX_CUSTOMER(ID, PartyID, ShopID), #ctx_v1_Customer{ - id = ID, - party = ?CTX_ENTITY(PartyID), - shop = ?CTX_ENTITY(ShopID) -}). - -define(CTX_WEBHOOK(ID, PartyID), #ctx_v1_Webhook{ id = ID, party = ?CTX_ENTITY(PartyID) diff --git a/apps/capi/test/capi_ct_helper_bouncer.erl b/apps/capi/test/capi_ct_helper_bouncer.erl index 56bf612..5dbe903 100644 --- a/apps/capi/test/capi_ct_helper_bouncer.erl +++ b/apps/capi/test/capi_ct_helper_bouncer.erl @@ -6,16 +6,12 @@ -export([mock_assert_op_ctx/2]). -export([mock_assert_party_op_ctx/3]). -export([mock_assert_shop_op_ctx/4]). --export([mock_assert_contract_op_ctx/4]). -export([mock_assert_invoice_op_ctx/5]). -export([mock_assert_payment_op_ctx/5]). -export([mock_assert_payment_op_ctx/6]). -export([mock_assert_refund_op_ctx/7]). -export([mock_assert_invoice_tpl_op_ctx/5]). --export([mock_assert_customer_op_ctx/5]). -export([mock_assert_webhook_op_ctx/4]). --export([mock_assert_search_op_ctx/2]). --export([mock_assert_search_op_ctx/3]). -export([mock_assert_requester_ctx/2]). -export([mock_restricted_shops/2]). @@ -59,17 +55,6 @@ mock_assert_shop_op_ctx(Op, PartyID, ShopID, Config) -> Config ). --spec mock_assert_contract_op_ctx(_, _, _, _) -> _. -mock_assert_contract_op_ctx(Op, PartyID, ContractID, Config) -> - mock_arbiter( - ?assertContextMatches( - #ctx_v1_ContextFragment{ - capi = ?CTX_CAPI(?CTX_CONTRACT_OP(Op, PartyID, ContractID)) - } - ), - Config - ). - -spec mock_assert_invoice_op_ctx(_, _, _, _, _) -> _. mock_assert_invoice_op_ctx(Op, InvoiceID, PartyID, ShopID, Config) -> mock_arbiter( @@ -140,20 +125,6 @@ mock_assert_invoice_tpl_op_ctx(Op, InvoiceTemplateID, PartyID, ShopID, Config) - Config ). --spec mock_assert_customer_op_ctx(_, _, _, _, _) -> _. -mock_assert_customer_op_ctx(Op, CustomerID, PartyID, ShopID, Config) -> - mock_arbiter( - ?assertContextMatches( - #ctx_v1_ContextFragment{ - capi = ?CTX_CAPI(?CTX_CUSTOMER_OP(Op, CustomerID)), - payment_processing = #ctx_v1_ContextPaymentProcessing{ - customer = ?CTX_CUSTOMER(CustomerID, PartyID, ShopID) - } - } - ), - Config - ). - -spec mock_assert_webhook_op_ctx(_, _, _, _) -> _. mock_assert_webhook_op_ctx(Op, WebhookID, PartyID, Config) -> mock_arbiter( @@ -168,29 +139,6 @@ mock_assert_webhook_op_ctx(Op, WebhookID, PartyID, Config) -> Config ). --spec mock_assert_search_op_ctx(_, _) -> _. -mock_assert_search_op_ctx(SearchCtx, Config) -> - mock_arbiter( - ?assertContextMatches( - #ctx_v1_ContextFragment{ - capi = ?CTX_CAPI(SearchCtx) - } - ), - Config - ). - --spec mock_assert_search_op_ctx(_, _, _) -> _. -mock_assert_search_op_ctx(SearchCtx, PayprocCtx, Config) -> - mock_arbiter( - ?assertContextMatches( - #ctx_v1_ContextFragment{ - capi = ?CTX_CAPI(SearchCtx), - payment_processing = PayprocCtx - } - ), - Config - ). - -spec mock_assert_requester_ctx(_, _) -> _. mock_assert_requester_ctx(IPAddress, Config) -> mock_arbiter( diff --git a/apps/capi/test/capi_ct_helper_token_keeper.erl b/apps/capi/test/capi_ct_helper_token_keeper.erl index c390337..0bfb896 100644 --- a/apps/capi/test/capi_ct_helper_token_keeper.erl +++ b/apps/capi/test/capi_ct_helper_token_keeper.erl @@ -20,7 +20,6 @@ -export([mock_api_key_token/2]). -export([mock_invoice_access_token/3]). -export([mock_invoice_template_access_token/3]). --export([mock_customer_access_token/3]). -spec mock_token(token_handler(), sup_or_config()) -> list(app_name()). mock_token(HandlerFun, SupOrConfig) -> @@ -122,19 +121,6 @@ mock_invoice_template_access_token(PartyID, InvoiceTemplateID, SupOrConfig) -> end), mock_token(Handler, SupOrConfig). --spec mock_customer_access_token(binary(), binary(), sup_or_config()) -> list(app_name()). -mock_customer_access_token(PartyID, CustomerID, SupOrConfig) -> - Handler = make_authenticator_handler(fun() -> - AuthParams = #{ - method => <<"CustomerAccessToken">>, - expiration => posix_to_rfc3339(lifetime_to_expiration(?TOKEN_LIFETIME)), - token => #{id => ?STRING}, - scope => [#{party => #{id => PartyID}, customer => #{id => CustomerID}}] - }, - {<<"dev.vality.capi">>, create_bouncer_context(AuthParams), api_key_metadata()} - end), - mock_token(Handler, SupOrConfig). - %% -spec make_authenticator_handler(function()) -> token_handler(). diff --git a/apps/capi/test/capi_customer_access_token_tests_SUITE.erl b/apps/capi/test/capi_customer_access_token_tests_SUITE.erl deleted file mode 100644 index d75b445..0000000 --- a/apps/capi/test/capi_customer_access_token_tests_SUITE.erl +++ /dev/null @@ -1,316 +0,0 @@ --module(capi_customer_access_token_tests_SUITE). - --include_lib("common_test/include/ct.hrl"). --include_lib("stdlib/include/assert.hrl"). - --include_lib("damsel/include/dmsl_payproc_thrift.hrl"). --include_lib("damsel/include/dmsl_base_thrift.hrl"). --include_lib("damsel/include/dmsl_domain_thrift.hrl"). --include_lib("damsel/include/dmsl_user_interaction_thrift.hrl"). --include_lib("capi_dummy_data.hrl"). - --export([all/0]). --export([groups/0]). --export([init_per_suite/1]). --export([end_per_suite/1]). --export([init_per_group/2]). --export([end_per_group/2]). --export([init_per_testcase/2]). --export([end_per_testcase/2]). - --export([init/1]). - --export([ - get_customer_ok_test/1, - create_binding_ok_test/1, - create_binding_fail_test/1, - create_binding_expired_test/1, - get_bindings_ok_test/1, - get_binding_ok_test/1, - get_customer_events_ok_test/1, - get_customer_payment_methods_ok_test/1 -]). - --type test_case_name() :: atom(). --type config() :: [{atom(), any()}]. --type group_name() :: atom(). - --behaviour(supervisor). - --spec init([]) -> {ok, {supervisor:sup_flags(), [supervisor:child_spec()]}}. -init([]) -> - {ok, {#{strategy => one_for_all, intensity => 1, period => 1}, []}}. - --spec all() -> [{group, test_case_name()}]. -all() -> - [ - {group, operations_by_customer_access_token_after_customer_creation}, - {group, operations_by_customer_access_token_after_token_creation} - ]. - -customer_access_token_tests() -> - [ - get_customer_ok_test, - create_binding_ok_test, - create_binding_fail_test, - create_binding_expired_test, - get_bindings_ok_test, - get_binding_ok_test, - get_customer_events_ok_test, - get_customer_payment_methods_ok_test - ]. - --spec groups() -> [{group_name(), list(), [test_case_name()]}]. -groups() -> - [ - {operations_by_customer_access_token_after_customer_creation, [], customer_access_token_tests()}, - {operations_by_customer_access_token_after_token_creation, [], customer_access_token_tests()} - ]. - -%% -%% starting/stopping -%% --spec init_per_suite(config()) -> config(). -init_per_suite(Config) -> - capi_ct_helper:init_suite(?MODULE, Config). - --spec end_per_suite(config()) -> _. -end_per_suite(C) -> - _ = capi_ct_helper:stop_mocked_service_sup(?config(suite_test_sup, C)), - _ = [application:stop(App) || App <- proplists:get_value(apps, C)], - ok. - --spec init_per_group(group_name(), config()) -> config(). -init_per_group(operations_by_customer_access_token_after_customer_creation, Config) -> - MockServiceSup = capi_ct_helper:start_mocked_service_sup(?MODULE), - _ = capi_ct_helper:mock_services( - [ - {customer_management, fun('Create', _) -> {ok, ?CUSTOMER} end}, - {generator, fun('GenerateID', _) -> capi_ct_helper_bender:generate_id(<<"bender_key">>) end} - ], - MockServiceSup - ), - _ = capi_ct_helper_token_keeper:mock_api_key_token(?STRING, MockServiceSup), - _ = capi_ct_helper_bouncer:mock_arbiter(capi_ct_helper_bouncer:judge_always_allowed(), MockServiceSup), - Token = ?API_TOKEN, - Req = #{ - <<"shopID">> => ?STRING, - <<"contactInfo">> => #{<<"email">> => <<"bla@bla.ru">>}, - <<"metadata">> => #{<<"text">> => [<<"SOMESHIT">>, 42]} - }, - {ok, #{ - <<"customerAccessToken">> := #{<<"payload">> := CustAccToken} - }} = capi_client_customers:create_customer(capi_ct_helper:get_context(Token), Req), - _ = capi_ct_helper:stop_mocked_service_sup(MockServiceSup), - SupPid = capi_ct_helper:start_mocked_service_sup(?MODULE), - Apps1 = capi_ct_helper_token_keeper:mock_customer_access_token(?STRING, ?STRING, SupPid), - Apps2 = capi_ct_helper_bouncer:mock_arbiter(capi_ct_helper_bouncer:judge_always_allowed(), SupPid), - [ - {context, capi_ct_helper:get_context(CustAccToken)}, - {group_apps, Apps1 ++ Apps2}, - {group_test_sup, SupPid} - | Config - ]; -init_per_group(operations_by_customer_access_token_after_token_creation, Config) -> - MockServiceSup = capi_ct_helper:start_mocked_service_sup(?MODULE), - _ = capi_ct_helper:mock_services([{customer_management, fun('Get', _) -> {ok, ?CUSTOMER} end}], MockServiceSup), - _ = capi_ct_helper_token_keeper:mock_api_key_token(?STRING, MockServiceSup), - _ = capi_ct_helper_bouncer:mock_arbiter(capi_ct_helper_bouncer:judge_always_allowed(), MockServiceSup), - Token = ?API_TOKEN, - {ok, #{<<"payload">> := CustAccToken}} = capi_client_customers:create_customer_access_token( - capi_ct_helper:get_context(Token), - ?STRING - ), - _ = capi_ct_helper:stop_mocked_service_sup(MockServiceSup), - SupPid = capi_ct_helper:start_mocked_service_sup(?MODULE), - Apps1 = capi_ct_helper_token_keeper:mock_customer_access_token(?STRING, ?STRING, SupPid), - Apps2 = capi_ct_helper_bouncer:mock_arbiter(capi_ct_helper_bouncer:judge_always_allowed(), SupPid), - [ - {context, capi_ct_helper:get_context(CustAccToken)}, - {group_apps, Apps1 ++ Apps2}, - {group_test_sup, SupPid} - | Config - ]; -init_per_group(_, Config) -> - Config. - --spec end_per_group(group_name(), config()) -> _. -end_per_group(_Group, C) -> - _ = capi_utils:'maybe'(?config(group_test_sup, C), fun capi_ct_helper:stop_mocked_service_sup/1), - ok. - --spec init_per_testcase(test_case_name(), config()) -> config(). -init_per_testcase(_Name, C) -> - [{test_sup, capi_ct_helper:start_mocked_service_sup(?MODULE)} | C]. - --spec end_per_testcase(test_case_name(), config()) -> _. -end_per_testcase(_Name, C) -> - capi_ct_helper:stop_mocked_service_sup(?config(test_sup, C)), - ok. - -%%% Tests - --spec get_customer_ok_test(config()) -> _. -get_customer_ok_test(Config) -> - _ = capi_ct_helper:mock_services([{customer_management, fun('Get', _) -> {ok, ?CUSTOMER} end}], Config), - {ok, _} = capi_client_customers:get_customer_by_id(?config(context, Config), ?STRING). - --spec create_binding_ok_test(config()) -> _. -create_binding_ok_test(Config) -> - _ = capi_ct_helper:mock_services( - [ - {customer_management, fun - ('Get', _) -> {ok, ?CUSTOMER}; - ('StartBinding', _) -> {ok, ?CUSTOMER_BINDING} - end}, - {generator, fun('GenerateID', _) -> capi_ct_helper_bender:generate_id(<<"bender_key">>) end} - ], - Config - ), - PaymentTool = {bank_card, ?BANK_CARD}, - ValidUntil = capi_utils:deadline_from_timeout(10000), - PaymentToolToken = capi_crypto:encode_token(#{payment_tool => PaymentTool, valid_until => ValidUntil}), - Req2 = #{ - <<"paymentResource">> => #{ - <<"paymentSession">> => ?TEST_PAYMENT_SESSION, - <<"paymentToolToken">> => PaymentToolToken - } - }, - {ok, _} = capi_client_customers:create_binding(?config(context, Config), ?STRING, Req2). - --spec create_binding_expired_test(config()) -> _. -create_binding_expired_test(Config) -> - _ = capi_ct_helper:mock_services( - [ - {customer_management, fun('Get', _) -> {ok, ?CUSTOMER} end}, - {generator, fun('GenerateID', _) -> capi_ct_helper_bender:generate_id(<<"bender_key">>) end} - ], - Config - ), - PaymentTool = {bank_card, ?BANK_CARD}, - ValidUntil = capi_utils:deadline_from_timeout(0), - PaymentToolToken = capi_crypto:encode_token(#{payment_tool => PaymentTool, valid_until => ValidUntil}), - Req = #{ - <<"paymentResource">> => #{ - <<"paymentSession">> => ?TEST_PAYMENT_SESSION, - <<"paymentToolToken">> => PaymentToolToken - } - }, - Resp = capi_client_customers:create_binding(?config(context, Config), ?STRING, Req), - {error, {400, #{<<"code">> := <<"invalidPaymentToolToken">>}}} = Resp. - --spec create_binding_fail_test(config()) -> _. -create_binding_fail_test(Config) -> - _ = capi_ct_helper:mock_services( - [ - {customer_management, fun('Get', _) -> {ok, ?CUSTOMER} end}, - {generator, fun('GenerateID', _) -> capi_ct_helper_bender:generate_id(<<"bender_key">>) end} - ], - Config - ), - Req = #{ - <<"paymentResource">> => #{ - <<"paymentSession">> => ?TEST_PAYMENT_SESSION, - <<"paymentToolToken">> => <<"wrongPaymentToolToken">> - } - }, - Resp = capi_client_customers:create_binding(?config(context, Config), ?STRING, Req), - {error, {400, #{<<"code">> := <<"invalidPaymentToolToken">>}}} = Resp. - --spec get_bindings_ok_test(config()) -> _. -get_bindings_ok_test(Config) -> - _ = capi_ct_helper:mock_services( - [ - {customer_management, fun('Get', _) -> {ok, ?CUSTOMER} end} - ], - Config - ), - {ok, _} = capi_client_customers:get_bindings(?config(context, Config), ?STRING). - --spec get_binding_ok_test(config()) -> _. -get_binding_ok_test(Config) -> - _ = capi_ct_helper:mock_services([{customer_management, fun('Get', _) -> {ok, ?CUSTOMER} end}], Config), - {ok, _} = capi_client_customers:get_binding(?config(context, Config), ?STRING, ?STRING). - --spec get_customer_events_ok_test(config()) -> _. -get_customer_events_ok_test(Config) -> - _ = capi_ct_helper:mock_services( - [ - {customer_management, fun - ('Get', _) -> - {ok, ?CUSTOMER}; - ('GetEvents', _) -> - {ok, [ - ?CUSTOMER_EVENT(1), - ?CUSTOMER_EVENT(2), - ?CUSTOMER_EVENT(3) - ]} - end} - ], - Config - ), - {ok, [Event1, _, _]} = capi_client_customers:get_customer_events(?config(context, Config), ?STRING, 10), - _ = ?assertMatch( - #{ - <<"id">> := 1, - <<"createdAt">> := ?TIMESTAMP, - <<"changes">> := [ - #{ - <<"changeType">> := <<"CustomerBindingStarted">>, - <<"customerBinding">> := #{} - }, - #{ - <<"changeType">> := <<"CustomerBindingStatusChanged">>, - <<"customerBindingID">> := ?STRING, - <<"status">> := <<"failed">> - }, - #{ - <<"changeType">> := <<"CustomerBindingInteractionRequested">>, - <<"userInteraction">> := #{ - <<"interactionType">> := <<"Redirect">>, - <<"request">> := #{} - } - }, - #{ - <<"changeType">> := <<"CustomerBindingInteractionCompleted">>, - <<"userInteraction">> := #{ - <<"interactionType">> := <<"Redirect">>, - <<"request">> := #{} - } - } - ] - }, - Event1 - ). - --spec get_customer_payment_methods_ok_test(config()) -> _. -get_customer_payment_methods_ok_test(Config) -> - _ = capi_ct_helper:mock_services( - [ - {customer_management, fun - ('Get', _) -> {ok, ?CUSTOMER}; - ('ComputeTerms', _) -> {ok, ?TERM_SET} - end}, - {party_management, fun - ('GetRevision', _) -> {ok, ?INTEGER}; - ('Checkout', _) -> {ok, ?PARTY}; - ('GetShopContract', _) -> {ok, ?SHOP_CONTRACT} - end} - ], - Config - ), - {ok, Methods} = capi_client_customers:get_customer_payment_methods(?config(context, Config), ?STRING), - [ProviderMethod] = lists:filter( - fun(Method) -> - maps:get(<<"tokenProviderData">>, Method, undefined) /= undefined - end, - Methods - ), - ?assertMatch( - #{ - <<"merchantID">> := <<_/binary>>, - <<"merchantName">> := ?STRING, - <<"realm">> := <<"test">> - }, - maps:get(<<"tokenProviderData">>, ProviderMethod) - ). diff --git a/apps/capi/test/capi_customer_access_token_tests_SUITE_data/keys/local/jwk.priv.json b/apps/capi/test/capi_customer_access_token_tests_SUITE_data/keys/local/jwk.priv.json deleted file mode 100644 index e7d6557..0000000 --- a/apps/capi/test/capi_customer_access_token_tests_SUITE_data/keys/local/jwk.priv.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "use": "enc", - "kty": "EC", - "kid": "kxdD0orVPGoAxWrqAMTeQ0U5MRoK47uZxWiSJdgo0t0", - "crv": "P-256", - "alg": "ECDH-ES", - "x": "nHi7TCgBwfrPuNTf49bGvJMczk6WZOI-mCKAghbrOlM", - "y": "_8kiXGOIWkfz57m8K5dmTfbYzCJVYHZZZisCfbYicr0", - "d": "i45qDiARZ5qbS_uzeT-CiKnPUe64qHitKaVdAvcN6TI" -} \ No newline at end of file diff --git a/apps/capi/test/capi_customer_access_token_tests_SUITE_data/keys/local/jwk.publ.json b/apps/capi/test/capi_customer_access_token_tests_SUITE_data/keys/local/jwk.publ.json deleted file mode 100644 index 00b7002..0000000 --- a/apps/capi/test/capi_customer_access_token_tests_SUITE_data/keys/local/jwk.publ.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "use": "enc", - "kty": "EC", - "kid": "kxdD0orVPGoAxWrqAMTeQ0U5MRoK47uZxWiSJdgo0t0", - "crv": "P-256", - "alg": "ECDH-ES", - "x": "nHi7TCgBwfrPuNTf49bGvJMczk6WZOI-mCKAghbrOlM", - "y": "_8kiXGOIWkfz57m8K5dmTfbYzCJVYHZZZisCfbYicr0" -} \ No newline at end of file diff --git a/apps/capi/test/capi_customer_access_token_tests_SUITE_data/keys/local/private.pem b/apps/capi/test/capi_customer_access_token_tests_SUITE_data/keys/local/private.pem deleted file mode 100644 index 4e6d12c..0000000 --- a/apps/capi/test/capi_customer_access_token_tests_SUITE_data/keys/local/private.pem +++ /dev/null @@ -1,9 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIBOwIBAAJBAK9fx7qOJT7Aoseu7KKgaLagBh3wvDzg7F/ZMtGbPFikJnnvRWvF -B5oEGbMPblvtF0/fjqfu+eqjP3Z1tUSn7TkCAwEAAQJABUY5KIgr4JZEjwLYxQ9T -9uIbLP1Xe/E7yqoqmBk2GGhSrPY0OeRkYnUVLcP96UPQhF63iuG8VF6uZ7oAPsq+ -gQIhANZy3jSCzPjXYHRU1kRqQzpt2S+OqoEiqQ6YG1HrC/VxAiEA0Vq6JlQK2tOX -37SS00dK0Qog4Qi8dN73GliFQNP18EkCIQC4epSA48zkfJMzQBAbRraSuxDNApPX -BzQbo+pMrEDbYQIgY4AncQgIkLB4Qk5kah48JNYXglzQlQtTjiX8Ty9ueGECIQCM -GD3UbQKiA0gf5plBA24I4wFVKxxa4wXbW/7SfP6XmQ== ------END RSA PRIVATE KEY----- diff --git a/apps/capi/test/capi_dummy_data.hrl b/apps/capi/test/capi_dummy_data.hrl index 6175f35..e03d8c0 100644 --- a/apps/capi/test/capi_dummy_data.hrl +++ b/apps/capi/test/capi_dummy_data.hrl @@ -287,16 +287,6 @@ }} ). --define(CUSTOMER_PAYER, - {customer, #domain_CustomerPayer{ - customer_id = ?STRING, - customer_binding_id = ?STRING, - rec_payment_tool_id = ?STRING, - payment_tool = {bank_card, ?BANK_CARD}, - contact_info = ?CONTACT_INFO - }} -). - -define(PAYER(PT), {payment_resource, #domain_PaymentResourcePayer{ resource = ?DISP_PAYMENT_RESOURCE(PT), @@ -332,7 +322,6 @@ -define(PAYMENT, ?PAYMENT(?STRING, ?PAYMENT_STATUS_PENDING, ?PAYER)). -define(PAYMENT_WITH_RECURRENT_PAYER, ?PAYMENT(?STRING, ?PAYMENT_STATUS_PENDING, ?RECURRENT_PAYER)). --define(PAYMENT_WITH_CUSTOMER_PAYER, ?PAYMENT(?STRING, ?PAYMENT_STATUS_PENDING, ?CUSTOMER_PAYER)). -define(PAYMENT_W_EXTERNAL_ID(ID, ExternalID), ?PAYMENT(ID, ?PAYMENT_STATUS_PENDING, ?PAYER, ExternalID, undefined)). @@ -424,40 +413,6 @@ category = {dispute, #'domain_InvoicePaymentChargebackCategoryDispute'{}} }). --define(CONTRACT, #domain_Contract{ - id = ?STRING, - contractor = ?CONTRACTOR_REGISTERED_USER, - payment_institution = #domain_PaymentInstitutionRef{id = ?INTEGER}, - created_at = ?TIMESTAMP, - valid_since = ?TIMESTAMP, - valid_until = ?TIMESTAMP, - status = {active, #domain_ContractActive{}}, - terms = #domain_TermSetHierarchyRef{id = ?INTEGER}, - adjustments = [?CONTRACT_ADJUSTMENT], - payout_tools = [], - legal_agreement = ?CONTRACT_LEGAL_AGREEMENT, - report_preferences = ?CONTRACT_REPORT_PREFS -}). - --define(CONTRACT_LEGAL_AGREEMENT, #domain_LegalAgreement{ - signed_at = ?TIMESTAMP, - legal_agreement_id = ?STRING, - valid_until = ?TIMESTAMP -}). - --define(CONTRACT_REPORT_PREFS, #domain_ReportPreferences{ - service_acceptance_act_preferences = #domain_ServiceAcceptanceActPreferences{ - schedule = #domain_BusinessScheduleRef{id = ?INTEGER}, - signer = #domain_Representative{ - position = ?STRING, - full_name = ?STRING, - document = {articles_of_association, #domain_ArticlesOfAssociation{}} - } - } -}). - --define(CONTRACTOR_REGISTERED_USER, {registered_user, #domain_RegisteredUser{email = ?STRING}}). - -define(BLOCKING, {unblocked, #domain_Unblocked{ reason = ?STRING, @@ -467,7 +422,7 @@ -define(SUSPENTION, {active, #domain_Active{since = ?TIMESTAMP}}). --define(SHOP(Account), #domain_Shop{ +-define(SHOP(Currency), #domain_ShopConfig{ id = ?STRING, created_at = ?TIMESTAMP, blocking = ?BLOCKING, @@ -475,82 +430,42 @@ details = ?SHOP_DETAILS, location = ?SHOP_LOCATION, category = #domain_CategoryRef{id = ?INTEGER}, - contract_id = ?STRING, - account = Account -}). - --define(SHOP, ?SHOP(undefined)). - --define(SHOP_ACCOUNT(Currency), #domain_ShopAccount{ - currency = #domain_CurrencyRef{symbolic_code = Currency}, - settlement = ?INTEGER, - guarantee = ?INTEGER, - payout = ?INTEGER + currency_configs = #{ + #domain_CurrencyRef{symbolic_code = Currency} => #domain_ShopCurrencyConfig{ + currency = #domain_CurrencyRef{symbolic_code = Currency}, + settlement = ?INTEGER, + guarantee = ?INTEGER + } + }, + payment_institution = #domain_PaymentInstitutionRef{id = ?INTEGER}, + terms = #domain_TermSetHierarchyRef{id = ?INTEGER}, + party_id = ?STRING }). --define(SHOP_CONTRACT, #payproc_ShopContract{ - shop = ?SHOP, - contract = ?CONTRACT -}). +-define(SHOP, ?SHOP(?RUB)). -define(SHOP_LOCATION, {url, ?URL}). --define(SHOP_DETAILS, #domain_ShopDetails{name = ?STRING}). - --define(PARTY_CONTRACTOR, #domain_PartyContractor{ - id = ?STRING, - contractor = - {private_entity, - {russian_private_entity, #domain_RussianPrivateEntity{ - first_name = ?STRING, - second_name = ?STRING, - middle_name = ?STRING, - contact_info = ?CONTACT_INFO - }}}, - status = none, - identity_documents = [] -}). - --define(WALLET_CONTRACT_ID, <<"WALLET_CONTRACT_ID">>). - --define(WALLET_CONTRACT, #domain_Contract{ - id = ?WALLET_CONTRACT_ID, - contractor_id = ?STRING, - payment_institution = #domain_PaymentInstitutionRef{id = ?INTEGER}, - created_at = ?TIMESTAMP, - valid_since = ?TIMESTAMP, - valid_until = ?TIMESTAMP, - status = {active, #domain_ContractActive{}}, - terms = #domain_TermSetHierarchyRef{id = ?INTEGER}, - adjustments = [], - payout_tools = [] -}). +-define(SHOP_DETAILS, #domain_Details{name = ?STRING}). --define(WALLET, #domain_Wallet{ +-define(PARTY, #domain_PartyConfig{ id = ?STRING, + contact_info = #domain_PartyContactInfo{registration_email = ?STRING}, created_at = ?TIMESTAMP, blocking = ?BLOCKING, suspension = ?SUSPENTION, - contract = ?WALLET_CONTRACT_ID + shops = [], + wallets = [] }). --define(PARTY, #domain_Party{ +-define(PARTY_WITH_SHOPS, #domain_PartyConfig{ id = ?STRING, contact_info = #domain_PartyContactInfo{registration_email = ?STRING}, created_at = ?TIMESTAMP, blocking = ?BLOCKING, suspension = ?SUSPENTION, - contracts = #{ - ?STRING => ?CONTRACT, - ?WALLET_CONTRACT_ID => ?WALLET_CONTRACT - }, - shops = #{ - ?STRING => ?SHOP, - ?USD => ?SHOP(?SHOP_ACCOUNT(?USD)) - }, - contractors = #{?STRING => ?PARTY_CONTRACTOR}, - wallets = #{?STRING => ?WALLET}, - revision = 0 + shops = [#domain_ShopConfigRef{id = ?STRING}], + wallets = [] }). -define(ADJUSTMENT, #domain_InvoicePaymentAdjustment{ @@ -563,14 +478,6 @@ old_cash_flow_inverse = [] }). --define(CONTRACT_ADJUSTMENT, #domain_ContractAdjustment{ - id = ?STRING, - created_at = ?TIMESTAMP, - valid_since = ?TIMESTAMP, - valid_until = ?TIMESTAMP, - terms = #domain_TermSetHierarchyRef{id = ?INTEGER} -}). - -define(PAYOUT_TOOL(ID, ToolInfo), #domain_PayoutTool{ id = ID, created_at = ?TIMESTAMP, @@ -582,34 +489,6 @@ {payment_institution_account, #domain_PaymentInstitutionAccount{}} ). --define(RUSSIAN_BANK_ACCOUNT, - {russian_bank_account, #domain_RussianBankAccount{ - account = <<"12345678901234567890">>, - bank_name = ?STRING, - bank_post_account = <<"12345678901234567890">>, - bank_bik = <<"123456789">> - }} -). - --define(INTERNATIONAL_BANK_ACCOUNT, - {international_bank_account, #domain_InternationalBankAccount{ - number = <<"12345678901234567890">>, - bank = ?INTERNATIONAL_BANK_DETAILS, - correspondent_account = #domain_InternationalBankAccount{number = <<"00000000000000000000">>}, - iban = <<"GR1601101250000000012300695">>, - account_holder = ?STRING - }} -). - --define(INTERNATIONAL_BANK_DETAILS, #domain_InternationalBankDetails{ - %% In reality either bic or aba_rtn should be used, not both. - bic = <<"DEUTDEFF500">>, - country = usa, - name = ?STRING, - address = ?STRING, - aba_rtn = <<"129131673">> -}). - -define(WALLET_INFO, {wallet_info, #domain_WalletInfo{ wallet_id = ?STRING @@ -754,70 +633,6 @@ enabled = true }). --define(STAT_RESPONSE_INVOICES, #magista_StatInvoiceResponse{ - invoices = [ - ?STAT_INVOICE({unpaid, #domain_InvoiceUnpaid{}}), - ?STAT_INVOICE({paid, #domain_InvoicePaid{}}), - ?STAT_INVOICE({cancelled, #domain_InvoiceCancelled{details = ?STRING}}), - ?STAT_INVOICE({fulfilled, #domain_InvoiceFulfilled{details = ?STRING}}) - ], - continuation_token = ?STRING -}). - --define(STAT_INVOICE(Status), #magista_StatInvoice{ - id = ?STRING, - owner_id = ?STRING, - shop_id = ?STRING, - created_at = ?TIMESTAMP, - status = Status, - product = ?STRING, - description = ?STRING, - due = ?TIMESTAMP, - amount = ?INTEGER, - currency_symbolic_code = ?RUB, - context = ?CONTENT, - cart = ?INVOICE_CART, - external_id = ?STRING, - status_changed_at = ?TIMESTAMP -}). - --define(STAT_RESPONSE_PAYMENTS, #magista_StatPaymentResponse{ - payments = [ - ?STAT_PAYMENT( - ?STAT_CUSTOMER_PAYER({digital_wallet, ?DIGITAL_WALLET(?STRING, ?STRING, ?STRING)}), - ?STAT_PAYMENT_STATUS_PENDING - ), - ?STAT_PAYMENT(?STAT_CUSTOMER_PAYER({bank_card, ?BANK_CARD}), ?STAT_PAYMENT_STATUS_FAILED), - ?STAT_PAYMENT(?RECURRENT_PAYER, ?STAT_PAYMENT_STATUS_PENDING), - ?STAT_PAYMENT(?PAYER, ?STAT_PAYMENT_STATUS_CAPTURED), - ?STAT_PAYMENT( - ?PAYER, - ?STAT_PAYMENT_STATUS_PENDING, - {hold, #magista_InvoicePaymentFlowHold{on_hold_expiration = cancel, held_until = ?TIMESTAMP}} - ) - ], - continuation_token = ?STRING -}). - --define(STAT_PAYMENT(Payer, Status, Flow), #magista_StatPayment{ - id = ?STRING, - invoice_id = ?STRING, - owner_id = ?STRING, - shop_id = ?STRING, - created_at = ?TIMESTAMP, - status = Status, - amount = ?INTEGER, - fee = ?INTEGER, - currency_symbolic_code = ?RUB, - payer = Payer, - context = ?CONTENT, - flow = Flow, - domain_revision = ?INTEGER, - additional_transaction_info = ?ADDITIONAL_TX_INFO -}). - --define(STAT_PAYMENT(Payer, Status), ?STAT_PAYMENT(Payer, Status, {instant, #magista_InvoicePaymentFlowInstant{}})). - -define(TX_INFO, #domain_TransactionInfo{ id = ?STRING, timestamp = ?TIMESTAMP, @@ -831,14 +646,6 @@ extra_payment_info = #{<<"test_key">> => <<"test_value">>} }). --define(STAT_CUSTOMER_PAYER(PaymentTool), - {customer, #magista_CustomerPayer{ - customer_id = ?STRING, - payment_tool = PaymentTool, - contact_info = ?CONTACT_INFO - }} -). - -define(STAT_PAYMENT_STATUS_PENDING, {pending, #domain_InvoicePaymentPending{}}). -define(STAT_PAYMENT_STATUS_CAPTURED, {captured, #domain_InvoicePaymentCaptured{}}). @@ -935,6 +742,16 @@ name = <<"Russia">> } }}, + {party_config, #domain_PartyConfigRef{id = ?STRING}} => + {party_config, #domain_PartyConfigObject{ + ref = #domain_PartyConfigRef{id = ?STRING}, + data = ?PARTY_WITH_SHOPS + }}, + {shop_config, #domain_ShopConfigRef{id = ?STRING}} => + {shop_config, #domain_ShopConfigObject{ + ref = #domain_ShopConfigRef{id = ?STRING}, + data = ?SHOP(?USD) + }}, {country, #domain_CountryRef{id = deu}} => {country, #domain_CountryObject{ ref = #domain_CountryRef{id = deu}, @@ -1138,81 +955,6 @@ ])} }). --define(CUSTOMER, ?CUSTOMER(?STRING)). --define(CUSTOMER(ID), #payproc_Customer{ - id = ID, - owner_id = ?STRING, - shop_id = ?STRING, - status = ?CUSTOMER_READY, - created_at = ?TIMESTAMP, - bindings = [?CUSTOMER_BINDING], - contact_info = ?CONTACT_INFO, - metadata = {obj, #{}} -}). - --define(CUSTOMER_READY, {ready, #payproc_CustomerReady{}}). - --define(CUSTOMER_BINDING, ?CUSTOMER_BINDING(?STRING, ?STRING)). - --define(CUSTOMER_BINDING(ID, RECID), #payproc_CustomerBinding{ - id = ID, - rec_payment_tool_id = RECID, - payment_resource = ?DISP_PAYMENT_RESOURCE, - status = {succeeded, #payproc_CustomerBindingSucceeded{}} -}). - --define(CUSTOMER_EVENT(ID), #payproc_Event{ - id = ID, - created_at = ?TIMESTAMP, - source = {customer_id, ?STRING}, - payload = - {customer_changes, [ - {customer_created, #payproc_CustomerCreated{ - customer_id = ?STRING, - owner_id = ?STRING, - shop_id = ?STRING, - created_at = ?TIMESTAMP, - contact_info = ?CONTACT_INFO, - metadata = {obj, #{}} - }}, - {customer_status_changed, #payproc_CustomerStatusChanged{ - status = ?CUSTOMER_READY - }}, - {customer_binding_changed, #payproc_CustomerBindingChanged{ - id = ?STRING, - payload = - {started, #payproc_CustomerBindingStarted{ - binding = ?CUSTOMER_BINDING - }} - }}, - {customer_binding_changed, #payproc_CustomerBindingChanged{ - id = ?STRING, - payload = - {status_changed, #payproc_CustomerBindingStatusChanged{ - status = - {failed, #payproc_CustomerBindingFailed{ - failure = {failure, #domain_Failure{code = <<"error_code">>}} - }} - }} - }}, - {customer_binding_changed, #payproc_CustomerBindingChanged{ - id = ?STRING, - payload = - {interaction_changed, #payproc_CustomerBindingInteractionChanged{ - interaction = ?USER_INTERACTION - }} - }}, - {customer_binding_changed, #payproc_CustomerBindingChanged{ - id = ?STRING, - payload = - {interaction_changed, #payproc_CustomerBindingInteractionChanged{ - interaction = ?USER_INTERACTION, - status = ?USER_INTERACTION_COMPLETED - }} - }} - ]} -}). - -define(PAYOUT, ?PAYOUT(?PI_ACCOUNT_TOOL, ?STRING)). -define(PAYOUT(ToolID), ?PAYOUT(ToolID, ?STRING)). @@ -1296,12 +1038,6 @@ } }). --define(CUSTOMER_PARAMS, #{ - <<"shopID">> => ?STRING, - <<"contactInfo">> => #{<<"email">> => <<"bla@bla.ru">>}, - <<"metadata">> => #{<<"text">> => [<<"SOMESHIT">>, 42]} -}). - -define(PAYMENT_PARAMS(EID, Token), #{ <<"externalID">> => EID, <<"flow">> => #{<<"type">> => <<"PaymentFlowInstant">>}, diff --git a/apps/capi/test/capi_idempotency_tests_SUITE.erl b/apps/capi/test/capi_idempotency_tests_SUITE.erl index 903bf4e..1fe38a4 100644 --- a/apps/capi/test/capi_idempotency_tests_SUITE.erl +++ b/apps/capi/test/capi_idempotency_tests_SUITE.erl @@ -36,10 +36,6 @@ -export([create_invoice_random_amount_ok_test/1]). -export([create_refund_idemp_ok_test/1]). -export([create_refund_idemp_fail_test/1]). --export([create_customer_ok_test/1]). --export([create_customer_fail_test/1]). --export([create_customer_binding_ok_test/1]). --export([create_customer_binding_fail_test/1]). -type test_case_name() :: atom(). -type config() :: [{atom(), any()}]. @@ -59,9 +55,7 @@ all() -> {group, invoice_template_creation}, {group, invoice_with_template_creation}, {group, refund_creation}, - {group, invoice_template_creation}, - {group, customer_creation}, - {group, customer_binding_creation} + {group, invoice_template_creation} ]. -spec groups() -> [{group_name(), list(), [test_case_name()]}]. @@ -93,14 +87,6 @@ groups() -> {refund_creation, [], [ create_refund_idemp_ok_test, create_refund_idemp_fail_test - ]}, - {customer_creation, [], [ - create_customer_ok_test, - create_customer_fail_test - ]}, - {customer_binding_creation, [], [ - create_customer_binding_ok_test, - create_customer_binding_fail_test ]} ]. @@ -161,9 +147,7 @@ init_per_group(payment_creation, Config) -> init_per_group(GroupName, Config) when GroupName =:= invoice_creation orelse GroupName =:= refund_creation orelse - GroupName =:= customer_binding_creation orelse GroupName =:= invoice_template_creation orelse - GroupName =:= customer_creation orelse GroupName =:= invoice_with_template_creation -> Context = capi_ct_helper:get_context(?API_TOKEN), @@ -632,95 +616,6 @@ create_refund_idemp_fail_test(Config) -> ?assertEqual(Unused, Unused2), ?assertEqual(response_error(409, ExternalID, BenderKey), Response2). --spec create_customer_ok_test(config()) -> _. -create_customer_ok_test(Config) -> - BenderKey = <<"create_customer_ok_test">>, - Req1 = maps:merge(?CUSTOMER_PARAMS, #{<<"externalID">> => genlib:unique()}), - Req2 = Req1#{<<"externalID">> => genlib:unique()}, - - UnusedFeatures = [[<<"externalID">>], [<<"metadata">>, <<"text">>, 0], [<<"metadata">>, <<"text">>, 1]], - Result = create_customers(BenderKey, [Req1, Req2], Config), - - [{{ok, #{<<"customer">> := Customer1}}, UnusedFeatures1}, {{ok, #{<<"customer">> := Customer2}}, UnusedFeatures2}] = - Result, - - ?assertEqual(Customer1, Customer2), - ?assertEqual(UnusedFeatures1, UnusedFeatures2), - ?assertEqual(UnusedFeatures1, UnusedFeatures). - --spec create_customer_fail_test(config()) -> _. -create_customer_fail_test(Config) -> - BenderKey = <<"create_customer_fail_test">>, - ExternalID = genlib:unique(), - Req1 = maps:merge(?CUSTOMER_PARAMS, #{<<"externalID">> => ExternalID, <<"shopID">> => <<"1">>}), - Req2 = Req1#{<<"shopID">> => <<"2">>}, - - [CustomerResult1, CustomerResult2] = create_customers(BenderKey, [Req1, Req2], Config), - ?assertMatch({{ok, _}, _}, CustomerResult1), - ?assertEqual( - {response_error(409, ExternalID, BenderKey), [ - [<<"externalID">>], [<<"metadata">>, <<"text">>, 0], [<<"metadata">>, <<"text">>, 1] - ]}, - CustomerResult2 - ). - --spec create_customer_binding_ok_test(config()) -> _. -create_customer_binding_ok_test(Config) -> - BenderKey = <<"customer_binding_bender_key">>, - PaymentTool = {bank_card, ?BANK_CARD}, - ValidUntil = capi_utils:deadline_from_timeout(10000), - PaymentToolToken = capi_crypto:encode_token(#{payment_tool => PaymentTool, valid_until => ValidUntil}), - Req1 = #{ - <<"externalID">> => genlib:unique(), - <<"paymentResource">> => #{ - <<"paymentSession">> => ?TEST_PAYMENT_SESSION, - <<"paymentToolToken">> => PaymentToolToken - } - }, - Req2 = Req1#{<<"externalID">> => genlib:unique()}, - - [BindingResult1, BindingResult2] = create_customer_bindings(BenderKey, [Req1, Req2], Config), - ?assertMatch( - {{ok, _}, [ - [<<"externalID">>], - [<<"paymentResource">>, <<"paymentTool">>, <<"payment_system">>] - ]}, - BindingResult1 - ), - ?assertEqual(BindingResult1, BindingResult2). - --spec create_customer_binding_fail_test(config()) -> _. -create_customer_binding_fail_test(Config) -> - BenderKey = <<"customer_binding_bender_key">>, - ExternalID = genlib:unique(), - PaymentTool1 = {bank_card, ?BANK_CARD}, - ValidUntil1 = capi_utils:deadline_from_timeout(10000), - PaymentToolToken1 = capi_crypto:encode_token(#{payment_tool => PaymentTool1, valid_until => ValidUntil1}), - Req1 = #{ - <<"externalID">> => ExternalID, - <<"paymentResource">> => #{ - <<"paymentSession">> => ?TEST_PAYMENT_SESSION, - <<"paymentToolToken">> => PaymentToolToken1 - } - }, - PaymentTool2 = {bank_card, ?BANK_CARD(<<"mastercard">>)}, - ValidUntil2 = capi_utils:deadline_from_timeout(10000), - PaymentToolToken2 = capi_crypto:encode_token(#{payment_tool => PaymentTool2, valid_until => ValidUntil2}), - Req2 = Req1#{ - <<"paymentResource">> => #{ - <<"paymentSession">> => ?TEST_PAYMENT_SESSION, - <<"paymentToolToken">> => PaymentToolToken2 - } - }, - - [BindingResult1, BindingResult2] = create_customer_bindings(BenderKey, [Req1, Req2], Config), - ?assertMatch({{ok, _}, _}, BindingResult1), - {ActualBindingResult2, _UnusedParams} = BindingResult2, - ?assertEqual( - response_error(409, ExternalID, BenderKey), - ActualBindingResult2 - ). - %% Internal functions create_payment(BenderKey, Requests, Config) -> @@ -858,63 +753,6 @@ get_encrypted_token(PS, ExpDate, IsCvvEmpty) -> encrypt_payment_tool(PaymentTool) -> capi_crypto:encode_token(#{payment_tool => PaymentTool, valid_until => undefined}). -create_customers(BenderKey, Requests, Config) -> - Context = ?config(context, Config), - capi_ct_helper_bender:with_storage( - fun(StorageID) -> - _ = capi_ct_helper:mock_services( - [ - {customer_management, fun( - 'Create', - {#payproc_CustomerParams{customer_id = CustomerID}} - ) -> - {ok, ?CUSTOMER(CustomerID)} - end}, - {bender, fun('GenerateID', {_, _, CtxMsgPack}) -> - capi_ct_helper_bender:get_internal_id(StorageID, BenderKey, CtxMsgPack) - end} - ], - Config - ), - [ - with_feature_storage(fun() -> capi_client_customers:create_customer(Context, R) end) - || R <- Requests - ] - end - ). - -create_customer_bindings(BenderKey, Requests, Config) -> - Context = ?config(context, Config), - capi_ct_helper_bender:with_storage( - fun(StorageID) -> - _ = capi_ct_helper:mock_services( - [ - {customer_management, fun - ('Get', _) -> - {ok, ?CUSTOMER}; - ( - 'StartBinding', - {_, #payproc_CustomerBindingParams{ - customer_binding_id = BindingID, - rec_payment_tool_id = RecPaymentToolID - }} - ) -> - {ok, ?CUSTOMER_BINDING(BindingID, RecPaymentToolID)} - end}, - - {bender, fun('GenerateID', {_, _, CtxMsgPack}) -> - capi_ct_helper_bender:get_internal_id(StorageID, BenderKey, CtxMsgPack) - end} - ], - Config - ), - [ - with_feature_storage(fun() -> capi_client_customers:create_binding(Context, ?STRING, R) end) - || R <- Requests - ] - end - ). - create_invoice_templates(BenderKey, Requests, Config) -> Context = ?config(context, Config), capi_ct_helper_bender:with_storage( diff --git a/apps/capi/test/capi_invoice_access_token_tests_SUITE.erl b/apps/capi/test/capi_invoice_access_token_tests_SUITE.erl index a3547cb..f6bfd5a 100644 --- a/apps/capi/test/capi_invoice_access_token_tests_SUITE.erl +++ b/apps/capi/test/capi_invoice_access_token_tests_SUITE.erl @@ -306,8 +306,7 @@ get_invoice_payment_methods_ok_test(Config) -> end}, {party_management, fun ('GetRevision', _) -> {ok, ?INTEGER}; - ('Checkout', _) -> {ok, ?PARTY}; - ('GetShopContract', _) -> {ok, ?SHOP_CONTRACT} + ('Checkout', _) -> {ok, ?PARTY} end} ], Config @@ -520,10 +519,9 @@ check_ip_on_payment_creation_ok_test(Config) -> -spec get_payments_ok_test(config()) -> _. get_payments_ok_test(Config) -> - Payment0 = ?PAYPROC_PAYMENT(?PAYMENT_WITH_CUSTOMER_PAYER, [?REFUND], [?ADJUSTMENT], [?PAYPROC_CHARGEBACK]), - Payment1 = ?PAYPROC_PAYMENT(?PAYMENT_WITH_RECURRENT_PAYER, [?REFUND], [?ADJUSTMENT], [?PAYPROC_CHARGEBACK]), - Payment2 = ?PAYPROC_PAYMENT(?PAYMENT, [?REFUND], [?ADJUSTMENT], [?PAYPROC_CHARGEBACK]), - Result = ?PAYPROC_INVOICE([Payment0, Payment1, Payment2]), + Payment0 = ?PAYPROC_PAYMENT(?PAYMENT_WITH_RECURRENT_PAYER, [?REFUND], [?ADJUSTMENT], [?PAYPROC_CHARGEBACK]), + Payment1 = ?PAYPROC_PAYMENT(?PAYMENT, [?REFUND], [?ADJUSTMENT], [?PAYPROC_CHARGEBACK]), + Result = ?PAYPROC_INVOICE([Payment0, Payment1]), _ = capi_ct_helper:mock_services([{invoicing, fun('Get', _) -> {ok, Result} end}], Config), _ = capi_ct_helper_bouncer:mock_assert_invoice_op_ctx( <<"GetPayments">>, diff --git a/apps/capi/test/capi_invoice_template_access_token_tests_SUITE.erl b/apps/capi/test/capi_invoice_template_access_token_tests_SUITE.erl index a2f85e8..4d88fd7 100644 --- a/apps/capi/test/capi_invoice_template_access_token_tests_SUITE.erl +++ b/apps/capi/test/capi_invoice_template_access_token_tests_SUITE.erl @@ -171,8 +171,7 @@ get_invoice_payment_methods_by_tpl_id_ok_test(Config) -> end}, {party_management, fun ('GetRevision', _) -> {ok, ?INTEGER}; - ('Checkout', _) -> {ok, ?PARTY}; - ('GetShopContract', _) -> {ok, ?SHOP_CONTRACT} + ('Checkout', _) -> {ok, ?PARTY} end} ], Config diff --git a/apps/capi/test/capi_magista_stat_tests_SUITE.erl b/apps/capi/test/capi_magista_stat_tests_SUITE.erl deleted file mode 100644 index 5e799ff..0000000 --- a/apps/capi/test/capi_magista_stat_tests_SUITE.erl +++ /dev/null @@ -1,417 +0,0 @@ --module(capi_magista_stat_tests_SUITE). - --include_lib("common_test/include/ct.hrl"). - --include_lib("damsel/include/dmsl_base_thrift.hrl"). --include_lib("damsel/include/dmsl_domain_thrift.hrl"). --include_lib("damsel/include/dmsl_payproc_thrift.hrl"). --include_lib("magista_proto/include/magista_magista_thrift.hrl"). --include_lib("capi_dummy_data.hrl"). --include_lib("capi_bouncer_data.hrl"). - --export([all/0]). --export([groups/0]). --export([init_per_suite/1]). --export([end_per_suite/1]). --export([init_per_group/2]). --export([end_per_group/2]). --export([init_per_testcase/2]). --export([end_per_testcase/2]). - --export([init/1]). - --export([ - search_invoices_ok_test/1, - search_invoices_by_invoice_id_ok_test/1, - search_invoices_by_customer_id_ok_test/1, - search_payments_without_all_optional_fields_ok_test/1, - search_payments_ok_test/1, - search_refunds_ok_test/1, - search_refunds_by_refund_id_ok_test/1, - search_refunds_by_invoice_id_ok_test/1, - search_payments_invalid_request_test/1, - search_payments_invalid_token_test/1, - search_payments_limit_exceeded_test/1 -]). - --type test_case_name() :: atom(). --type config() :: [{atom(), any()}]. --type group_name() :: atom(). - --behaviour(supervisor). - --spec init([]) -> {ok, {supervisor:sup_flags(), [supervisor:child_spec()]}}. -init([]) -> - {ok, {#{strategy => one_for_all, intensity => 1, period => 1}, []}}. - --spec all() -> [{group, test_case_name()}]. -all() -> - [ - {group, operations_by_api_key_token}, - {group, operations_by_user_session_token} - ]. - --spec groups() -> [{group_name(), list(), [test_case_name()]}]. -groups() -> - [ - {operations_by_api_key_token, [], [ - {group, operations_by_any_token} - ]}, - {operations_by_user_session_token, [], [ - {group, operations_by_any_token} - ]}, - {operations_by_any_token, [], [ - search_invoices_ok_test, - search_invoices_by_invoice_id_ok_test, - search_invoices_by_customer_id_ok_test, - search_payments_without_all_optional_fields_ok_test, - search_payments_ok_test, - search_refunds_ok_test, - search_refunds_by_refund_id_ok_test, - search_refunds_by_invoice_id_ok_test, - search_payments_invalid_request_test, - search_payments_invalid_token_test, - search_payments_limit_exceeded_test - ]} - ]. - -%% -%% starting/stopping -%% --spec init_per_suite(config()) -> config(). -init_per_suite(Config) -> - capi_ct_helper:init_suite(?MODULE, Config). - --spec end_per_suite(config()) -> _. -end_per_suite(C) -> - _ = capi_ct_helper:stop_mocked_service_sup(?config(suite_test_sup, C)), - _ = [application:stop(App) || App <- proplists:get_value(apps, C)], - ok. - --spec init_per_group(group_name(), config()) -> config(). -init_per_group(operations_by_api_key_token, Config) -> - SupPid = capi_ct_helper:start_mocked_service_sup(?MODULE), - Apps = capi_ct_helper_token_keeper:mock_api_key_token(?STRING, SupPid), - [{context, capi_ct_helper:get_context(?API_TOKEN)}, {group_apps, Apps}, {group_test_sup, SupPid} | Config]; -init_per_group(operations_by_user_session_token, Config) -> - SupPid = capi_ct_helper:start_mocked_service_sup(?MODULE), - Apps = capi_ct_helper_token_keeper:mock_user_session_token(SupPid), - [{context, capi_ct_helper:get_context(?API_TOKEN)}, {group_apps, Apps}, {group_test_sup, SupPid} | Config]; -init_per_group(_, Config) -> - Config. - --spec end_per_group(group_name(), config()) -> _. - -end_per_group(Group, C) when - Group =:= operations_by_api_key_token; - Group =:= operations_by_user_session_token --> - capi_utils:'maybe'(?config(group_test_sup, C), fun capi_ct_helper:stop_mocked_service_sup/1); -end_per_group(_Group, _C) -> - ok. - --spec init_per_testcase(test_case_name(), config()) -> config(). -init_per_testcase(_Name, C) -> - [{test_sup, capi_ct_helper:start_mocked_service_sup(?MODULE)} | C]. - --spec end_per_testcase(test_case_name(), config()) -> _. -end_per_testcase(_Name, C) -> - capi_ct_helper:stop_mocked_service_sup(?config(test_sup, C)), - ok. - -%%% Tests - --spec search_invoices_ok_test(config()) -> _. -search_invoices_ok_test(Config) -> - _ = capi_ct_helper:mock_services( - [ - {magista, fun('SearchInvoices', _) -> {ok, ?STAT_RESPONSE_INVOICES} end} - ], - Config - ), - _ = capi_ct_helper_bouncer:mock_assert_search_op_ctx( - ?CTX_SEARCH_OP(<<"SearchInvoices">>, ?STRING, ?STRING, undefined, undefined), - #ctx_v1_ContextPaymentProcessing{}, - Config - ), - {ok, _, _} = search_invoices([], Config), - {ok, _, _} = search_invoices([{'offset', 42}], Config), - {ok, _, _} = search_invoices([{'invoiceStatus', <<"unpaid">>}], Config), - {ok, _, _} = search_invoices([{'invoiceStatus', <<"cancelled">>}], Config), - {ok, _, _} = search_invoices([{'invoiceStatus', <<"fulfilled">>}, {'invoiceAmount', 42}], Config), - {ok, _, _} = search_invoices( - [ - {'paymentStatus', <<"failed">>}, - {'paymentAmount', 42}, - {'payerEmail', ?EMAIL}, - {'rrn', <<"090909090909">>}, - {'approvalCode', <<"808080">>} - ], - Config - ). - --spec search_invoices_by_invoice_id_ok_test(config()) -> _. -search_invoices_by_invoice_id_ok_test(Config) -> - InvoiceID = <<"blarg">>, - PaymentID = <<"blorg">>, - _ = capi_ct_helper:mock_services( - [ - {invoicing, fun('Get', _) -> {ok, ?PAYPROC_INVOICE_WITH_ID(InvoiceID)} end}, - {magista, fun('SearchInvoices', _) -> {ok, ?STAT_RESPONSE_INVOICES} end} - ], - Config - ), - SearchCtx = ?CTX_SEARCH_OP(<<"SearchInvoices">>, ?STRING, ?STRING, InvoiceID, PaymentID), - _ = capi_ct_helper_bouncer:mock_arbiter( - ?assertContextMatches( - #ctx_v1_ContextFragment{ - capi = ?CTX_CAPI(SearchCtx), - payment_processing = #ctx_v1_ContextPaymentProcessing{ - invoice = ?CTX_INVOICE(InvoiceID, ?STRING, ?STRING) - } - } - ), - Config - ), - {ok, _, _} = search_invoices([{'invoiceID', InvoiceID}, {'paymentID', PaymentID}], Config). - --spec search_invoices_by_customer_id_ok_test(config()) -> _. -search_invoices_by_customer_id_ok_test(Config) -> - CustomerID = <<"blerg">>, - _ = capi_ct_helper:mock_services( - [ - {customer_management, fun('Get', _) -> {ok, ?CUSTOMER(CustomerID)} end}, - {magista, fun('SearchInvoices', _) -> {ok, ?STAT_RESPONSE_INVOICES} end} - ], - Config - ), - SearchCtx = ?CTX_SEARCH_OP(<<"SearchInvoices">>, ?STRING, ?STRING, undefined, undefined, CustomerID, undefined), - _ = capi_ct_helper_bouncer:mock_arbiter( - ?assertContextMatches( - #ctx_v1_ContextFragment{ - capi = ?CTX_CAPI(SearchCtx), - payment_processing = #ctx_v1_ContextPaymentProcessing{ - customer = ?CTX_CUSTOMER(CustomerID, ?STRING, ?STRING) - } - } - ), - Config - ), - {ok, _, _} = search_invoices([{'customerID', CustomerID}], Config). - -search_invoices(Query, Config) -> - BaseQuery = [ - {limit, 42}, - {from_time, {{2015, 08, 11}, {19, 42, 35}}}, - {to_time, {{2020, 08, 11}, {19, 42, 35}}}, - {'continuationToken', <<"come_back_next_time">>} - ], - capi_client_searches:search_invoices(?config(context, Config), ?STRING, BaseQuery ++ Query). - --spec search_payments_without_all_optional_fields_ok_test(config()) -> _. -search_payments_without_all_optional_fields_ok_test(Config) -> - _ = capi_ct_helper:mock_services( - [ - {magista, fun('SearchPayments', _) -> {ok, ?STAT_RESPONSE_PAYMENTS} end} - ], - Config - ), - _ = capi_ct_helper_bouncer:mock_assert_search_op_ctx( - ?CTX_SEARCH_OP(<<"SearchPayments">>, ?STRING, ?STRING, undefined, undefined), - Config - ), - Query = [ - {limit, 2}, - {from_time, {{2015, 08, 11}, {19, 42, 35}}}, - {to_time, {{2020, 08, 11}, {19, 42, 35}}} - ], - {ok, _, _} = capi_client_searches:search_payments(?config(context, Config), ?STRING, Query). - --spec search_payments_ok_test(config()) -> _. -search_payments_ok_test(Config) -> - _ = capi_ct_helper:mock_services( - [ - {invoicing, fun('Get', _) -> {ok, ?PAYPROC_INVOICE_WITH_ID(<<"testInvoiceID">>)} end}, - {magista, fun('SearchPayments', _) -> {ok, ?STAT_RESPONSE_PAYMENTS} end} - ], - Config - ), - SearchCtx = ?CTX_SEARCH_OP(<<"SearchPayments">>, ?STRING, ?STRING, <<"testInvoiceID">>, <<"testPaymentID">>), - _ = capi_ct_helper_bouncer:mock_arbiter( - ?assertContextMatches( - #ctx_v1_ContextFragment{ - capi = ?CTX_CAPI(SearchCtx), - payment_processing = #ctx_v1_ContextPaymentProcessing{ - invoice = ?CTX_INVOICE(<<"testInvoiceID">>, ?STRING, ?STRING) - } - } - ), - Config - ), - {ok, _, _} = search_payments([{'paymentStatus', <<"pending">>}], Config), - {ok, _, _} = search_payments([{'paymentStatus', <<"processed">>}], Config), - {ok, _, _} = search_payments([{'paymentStatus', <<"captured">>}], Config), - {ok, _, _} = search_payments([{'paymentStatus', <<"cancelled">>}], Config), - {ok, _, _} = search_payments([{'paymentStatus', <<"refunded">>}], Config), - {ok, _, _} = search_payments([{'paymentStatus', <<"failed">>}], Config), - {ok, _, _} = search_payments([{'paymentFlow', <<"instant">>}], Config), - {ok, _, _} = search_payments([{'paymentFlow', <<"hold">>}], Config), - {ok, _, _} = search_payments([{'paymentMethod', <<"bankCard">>}], Config), - {ok, _, _} = search_payments([{'paymentMethod', <<"paymentTerminal">>}], Config), - {ok, _, _} = search_payments( - [ - {'payerFingerprint', <<"blablablalbalbal">>}, - {'first6', <<"424242">>}, - {'last4', <<"2222">>}, - {'rrn', <<"090909090909">>}, - {'approvalCode', <<"808080">>}, - {'paymentAmount', 10000}, - {'paymentTerminalProvider', <<"NEUROSET">>}, - {'barnkCardPaymentSystem', <<"MONSTERCARD">>}, - {'barnkCardTokenProvider', <<"BLABLAPAY">>} - ], - Config - ). - -search_payments(QueryAdds, Config) -> - Query = [ - {limit, 2}, - {offset, 42}, - {from_time, {{2015, 08, 11}, {19, 42, 35}}}, - {to_time, {{2020, 08, 11}, {19, 42, 35}}}, - {'payerEmail', <<"test@test.ru">>}, - {'payerIP', <<"192.168.0.1">>}, - {'invoiceID', <<"testInvoiceID">>}, - {'paymentID', <<"testPaymentID">>}, - {'continuationToken', <<"come_back_next_time">>} - ], - capi_client_searches:search_payments(?config(context, Config), ?STRING, Query ++ QueryAdds). - --spec search_refunds_ok_test(config()) -> _. -search_refunds_ok_test(Config) -> - _ = capi_ct_helper:mock_services( - [ - {magista, fun('SearchRefunds', _) -> {ok, ?STAT_RESPONSE_REFUNDS} end} - ], - Config - ), - _ = capi_ct_helper_bouncer:mock_assert_search_op_ctx( - ?CTX_SEARCH_OP(<<"SearchRefunds">>, ?STRING, ?STRING, undefined, undefined), - #ctx_v1_ContextPaymentProcessing{}, - Config - ), - {ok, _, _} = search_refunds([], Config), - {ok, _, _} = search_refunds([{'refundStatus', <<"pending">>}], Config), - {ok, _, _} = search_refunds([{'refundStatus', <<"succeeded">>}], Config), - {ok, _, _} = search_refunds([{'refundStatus', <<"failed">>}], Config), - {ok, _, _} = search_refunds([{'rrn', <<"090909090909">>}, {'approvalCode', <<"808080">>}], Config). - --spec search_refunds_by_refund_id_ok_test(config()) -> _. -search_refunds_by_refund_id_ok_test(Config) -> - RefundID = <<"refünd">>, - _ = capi_ct_helper:mock_services( - [ - {magista, fun('SearchRefunds', _) -> {ok, ?STAT_RESPONSE_REFUNDS} end} - ], - Config - ), - _ = capi_ct_helper_bouncer:mock_assert_search_op_ctx( - ?CTX_SEARCH_OP(<<"SearchRefunds">>, ?STRING, ?STRING, undefined, undefined, undefined, RefundID), - #ctx_v1_ContextPaymentProcessing{}, - Config - ), - {ok, _, _} = search_refunds([{'refundID', RefundID}], Config). - --spec search_refunds_by_invoice_id_ok_test(config()) -> _. -search_refunds_by_invoice_id_ok_test(Config) -> - InvoiceID = <<"blarg">>, - PaymentID = <<"blorg">>, - _ = capi_ct_helper:mock_services( - [ - {invoicing, fun('Get', _) -> {ok, ?PAYPROC_INVOICE_WITH_ID(InvoiceID)} end}, - {magista, fun('SearchRefunds', _) -> {ok, ?STAT_RESPONSE_REFUNDS} end} - ], - Config - ), - SearchCtx = ?CTX_SEARCH_OP(<<"SearchRefunds">>, ?STRING, ?STRING, InvoiceID, PaymentID), - _ = capi_ct_helper_bouncer:mock_arbiter( - ?assertContextMatches( - #ctx_v1_ContextFragment{ - capi = ?CTX_CAPI(SearchCtx), - payment_processing = #ctx_v1_ContextPaymentProcessing{ - invoice = ?CTX_INVOICE(InvoiceID, ?STRING, ?STRING) - } - } - ), - Config - ), - {ok, _, _} = search_refunds([{'invoiceID', InvoiceID}, {'paymentID', PaymentID}], Config). - -search_refunds(Query, Config) -> - BaseQuery = [ - {limit, 42}, - {from_time, {{2015, 08, 11}, {19, 42, 35}}}, - {to_time, {{2020, 08, 11}, {19, 42, 35}}}, - {'continuationToken', <<"come_back_next_time">>} - ], - capi_client_searches:search_refunds(?config(context, Config), ?STRING, BaseQuery ++ Query). - --spec search_payments_invalid_request_test(config()) -> _. -search_payments_invalid_request_test(Config) -> - _ = capi_ct_helper:mock_services( - [ - {magista, fun('SearchPayments', _) -> {throwing, #base_InvalidRequest{errors = [<<"error">>]}} end} - ], - Config - ), - _ = capi_ct_helper_bouncer:mock_assert_search_op_ctx( - ?CTX_SEARCH_OP(<<"SearchPayments">>, ?STRING, ?STRING, undefined, undefined), - Config - ), - Query = [ - {limit, 2}, - {from_time, {{2015, 08, 11}, {19, 42, 35}}}, - {to_time, {{2020, 08, 11}, {19, 42, 35}}}, - {'continuationToken', <<"come_back_next_time">>} - ], - {error, {400, _}} = capi_client_searches:search_payments(?config(context, Config), ?STRING, Query). - --spec search_payments_invalid_token_test(config()) -> _. -search_payments_invalid_token_test(Config) -> - _ = capi_ct_helper:mock_services( - [ - {magista, fun('SearchPayments', _) -> {throwing, #magista_BadContinuationToken{reason = <<"">>}} end} - ], - Config - ), - _ = capi_ct_helper_bouncer:mock_assert_search_op_ctx( - ?CTX_SEARCH_OP(<<"SearchPayments">>, ?STRING, ?STRING, undefined, undefined), - Config - ), - Query = [ - {limit, 2}, - {from_time, {{2015, 08, 11}, {19, 42, 35}}}, - {to_time, {{2020, 08, 11}, {19, 42, 35}}}, - {'continuationToken', <<"come_back_next_time">>} - ], - {error, {400, _}} = capi_client_searches:search_payments(?config(context, Config), ?STRING, Query). - --spec search_payments_limit_exceeded_test(config()) -> _. -search_payments_limit_exceeded_test(Config) -> - _ = capi_ct_helper:mock_services( - [ - {magista, fun('SearchPayments', _) -> {throwing, #magista_LimitExceeded{}} end} - ], - Config - ), - _ = capi_ct_helper_bouncer:mock_assert_search_op_ctx( - ?CTX_SEARCH_OP(<<"SearchPayments">>, ?STRING, ?STRING, undefined, undefined), - Config - ), - Query = [ - {limit, 2}, - {from_time, {{2015, 08, 11}, {19, 42, 35}}}, - {to_time, {{2020, 08, 11}, {19, 42, 35}}}, - {'continuationToken', <<"come_back_next_time">>} - ], - {error, {400, _}} = capi_client_searches:search_payments(?config(context, Config), ?STRING, Query). diff --git a/apps/capi/test/capi_magista_stat_tests_SUITE_data/keys/local/dummy.pem b/apps/capi/test/capi_magista_stat_tests_SUITE_data/keys/local/dummy.pem deleted file mode 100644 index 059582b..0000000 --- a/apps/capi/test/capi_magista_stat_tests_SUITE_data/keys/local/dummy.pem +++ /dev/null @@ -1,13 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIICXAIBAAKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUp -wmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ5 -1s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZwIDAQABAoGAFijko56+qGyN8M0RVyaRAXz++xTqHBLh -3tx4VgMtrQ+WEgCjhoTwo23KMBAuJGSYnRmoBZM3lMfTKevIkAidPExvYCdm5dYq3XToLkkLv5L2 -pIIVOFMDG+KESnAFV7l2c+cnzRMW0+b6f8mR1CJzZuxVLL6Q02fvLi55/mbSYxECQQDeAw6fiIQX -GukBI4eMZZt4nscy2o12KyYner3VpoeE+Np2q+Z3pvAMd/aNzQ/W9WaI+NRfcxUJrmfPwIGm63il -AkEAxCL5HQb2bQr4ByorcMWm/hEP2MZzROV73yF41hPsRC9m66KrheO9HPTJuo3/9s5p+sqGxOlF -L0NDt4SkosjgGwJAFklyR1uZ/wPJjj611cdBcztlPdqoxssQGnh85BzCj/u3WqBpE2vjvyyvyI5k -X6zk7S0ljKtt2jny2+00VsBerQJBAJGC1Mg5Oydo5NwD6BiROrPxGo2bpTbu/fhrT8ebHkTz2epl -U9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ -37sJ5QsW+sJyoNde3xH8vdXhzU7eT82D6X/scw9RZz+/6rCJ4p0= ------END RSA PRIVATE KEY----- \ No newline at end of file diff --git a/apps/capi/test/capi_magista_stat_tests_SUITE_data/keys/local/jwk.json b/apps/capi/test/capi_magista_stat_tests_SUITE_data/keys/local/jwk.json deleted file mode 100644 index 1b908b2..0000000 --- a/apps/capi/test/capi_magista_stat_tests_SUITE_data/keys/local/jwk.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "use": "enc", - "kty": "oct", - "kid": "1111", - "alg": "dir", - "k": "d3JPWmpORzVqbGRrZ2s0aUdjQnJ6ZTh1OW1pdk1kR2Y" -} \ No newline at end of file diff --git a/apps/capi/test/capi_magista_stat_tests_SUITE_data/keys/local/jwk.priv.json b/apps/capi/test/capi_magista_stat_tests_SUITE_data/keys/local/jwk.priv.json deleted file mode 100644 index e7d6557..0000000 --- a/apps/capi/test/capi_magista_stat_tests_SUITE_data/keys/local/jwk.priv.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "use": "enc", - "kty": "EC", - "kid": "kxdD0orVPGoAxWrqAMTeQ0U5MRoK47uZxWiSJdgo0t0", - "crv": "P-256", - "alg": "ECDH-ES", - "x": "nHi7TCgBwfrPuNTf49bGvJMczk6WZOI-mCKAghbrOlM", - "y": "_8kiXGOIWkfz57m8K5dmTfbYzCJVYHZZZisCfbYicr0", - "d": "i45qDiARZ5qbS_uzeT-CiKnPUe64qHitKaVdAvcN6TI" -} \ No newline at end of file diff --git a/apps/capi/test/capi_magista_stat_tests_SUITE_data/keys/local/jwk.publ.json b/apps/capi/test/capi_magista_stat_tests_SUITE_data/keys/local/jwk.publ.json deleted file mode 100644 index 00b7002..0000000 --- a/apps/capi/test/capi_magista_stat_tests_SUITE_data/keys/local/jwk.publ.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "use": "enc", - "kty": "EC", - "kid": "kxdD0orVPGoAxWrqAMTeQ0U5MRoK47uZxWiSJdgo0t0", - "crv": "P-256", - "alg": "ECDH-ES", - "x": "nHi7TCgBwfrPuNTf49bGvJMczk6WZOI-mCKAghbrOlM", - "y": "_8kiXGOIWkfz57m8K5dmTfbYzCJVYHZZZisCfbYicr0" -} \ No newline at end of file diff --git a/apps/capi/test/capi_magista_stat_tests_SUITE_data/keys/local/private.pem b/apps/capi/test/capi_magista_stat_tests_SUITE_data/keys/local/private.pem deleted file mode 100644 index 4e6d12c..0000000 --- a/apps/capi/test/capi_magista_stat_tests_SUITE_data/keys/local/private.pem +++ /dev/null @@ -1,9 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIBOwIBAAJBAK9fx7qOJT7Aoseu7KKgaLagBh3wvDzg7F/ZMtGbPFikJnnvRWvF -B5oEGbMPblvtF0/fjqfu+eqjP3Z1tUSn7TkCAwEAAQJABUY5KIgr4JZEjwLYxQ9T -9uIbLP1Xe/E7yqoqmBk2GGhSrPY0OeRkYnUVLcP96UPQhF63iuG8VF6uZ7oAPsq+ -gQIhANZy3jSCzPjXYHRU1kRqQzpt2S+OqoEiqQ6YG1HrC/VxAiEA0Vq6JlQK2tOX -37SS00dK0Qog4Qi8dN73GliFQNP18EkCIQC4epSA48zkfJMzQBAbRraSuxDNApPX -BzQbo+pMrEDbYQIgY4AncQgIkLB4Qk5kah48JNYXglzQlQtTjiX8Ty9ueGECIQCM -GD3UbQKiA0gf5plBA24I4wFVKxxa4wXbW/7SfP6XmQ== ------END RSA PRIVATE KEY----- diff --git a/apps/capi/test/capi_magista_stat_tests_SUITE_data/keys/local/public.pem b/apps/capi/test/capi_magista_stat_tests_SUITE_data/keys/local/public.pem deleted file mode 100644 index c2f50d4..0000000 --- a/apps/capi/test/capi_magista_stat_tests_SUITE_data/keys/local/public.pem +++ /dev/null @@ -1,4 +0,0 @@ ------BEGIN PUBLIC KEY----- -MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAK9fx7qOJT7Aoseu7KKgaLagBh3wvDzg -7F/ZMtGbPFikJnnvRWvFB5oEGbMPblvtF0/fjqfu+eqjP3Z1tUSn7TkCAwEAAQ== ------END PUBLIC KEY----- diff --git a/apps/capi/test/capi_self_tests_SUITE.erl b/apps/capi/test/capi_self_tests_SUITE.erl index 2039c3a..dcbe58d 100644 --- a/apps/capi/test/capi_self_tests_SUITE.erl +++ b/apps/capi/test/capi_self_tests_SUITE.erl @@ -105,7 +105,7 @@ oops_body_test(Config) -> Context = ?config(context, Config), Params = #{binding => #{<<"invoiceID">> => ?STRING}}, {Endpoint, PreparedParams, Opts0} = capi_client_lib:make_request(Context, Params), - Url = swag_client_utils:get_url(Endpoint, "/v2/processing/me"), + Url = swag_client_utils:get_url(Endpoint, "/v2/processing/invoices/" ++ binary_to_list(?STRING)), Headers = maps:to_list(maps:get(header, PreparedParams)), Body = <<"{}">>, Opts = Opts0 ++ [with_body], diff --git a/apps/capi_client/src/capi_client_contracts.erl b/apps/capi_client/src/capi_client_contracts.erl deleted file mode 100644 index 5a413fa..0000000 --- a/apps/capi_client/src/capi_client_contracts.erl +++ /dev/null @@ -1,101 +0,0 @@ --module(capi_client_contracts). - --export([get_contract_by_id/2]). --export([get_contract_by_id_for_party/3]). --export([get_contracts/1]). --export([get_contracts_for_party/2]). --export([get_contract_adjustment_by_id/3]). --export([get_contract_adjustment_by_id_for_party/4]). --export([get_contract_adjustments/2]). --export([get_contract_adjustments_for_party/3]). - --type context() :: capi_client_lib:context(). - --spec get_contract_by_id(context(), binary()) -> {ok, term()} | {error, term()}. -get_contract_by_id(Context, ContractID) -> - Params = #{ - binding => genlib_map:compact(#{ - <<"contractID">> => ContractID - }) - }, - {Url, PreparedParams, Opts} = capi_client_lib:make_request(Context, Params), - Response = swag_client_contracts_api:get_contract_by_id(Url, PreparedParams, Opts), - capi_client_lib:handle_response(Response). - --spec get_contract_by_id_for_party(context(), binary(), binary()) -> {ok, term()} | {error, term()}. -get_contract_by_id_for_party(Context, PartyID, ContractID) -> - Params = #{ - binding => genlib_map:compact(#{ - <<"partyID">> => PartyID, - <<"contractID">> => ContractID - }) - }, - {Url, PreparedParams, Opts} = capi_client_lib:make_request(Context, Params), - Response = swag_client_contracts_api:get_contract_by_id_for_party(Url, PreparedParams, Opts), - capi_client_lib:handle_response(Response). - --spec get_contracts(context()) -> {ok, term()} | {error, term()}. -get_contracts(Context) -> - {Url, PreparedParams, Opts} = capi_client_lib:make_request(Context, #{}), - Response = swag_client_contracts_api:get_contracts(Url, PreparedParams, Opts), - capi_client_lib:handle_response(Response). - --spec get_contracts_for_party(context(), binary()) -> {ok, term()} | {error, term()}. -get_contracts_for_party(Context, PartyID) -> - Params = #{ - binding => #{ - <<"partyID">> => PartyID - } - }, - {Url, PreparedParams, Opts} = capi_client_lib:make_request(Context, Params), - Response = swag_client_contracts_api:get_contracts_for_party(Url, PreparedParams, Opts), - capi_client_lib:handle_response(Response). - --spec get_contract_adjustment_by_id(context(), binary(), binary()) -> {ok, term()} | {error, term()}. -get_contract_adjustment_by_id(Context, ContractID, AdjID) -> - Params = #{ - binding => genlib_map:compact(#{ - <<"contractID">> => ContractID, - <<"adjustmentID">> => AdjID - }) - }, - {Url, PreparedParams, Opts} = capi_client_lib:make_request(Context, Params), - Response = swag_client_contracts_api:get_contract_adjustment_by_id(Url, PreparedParams, Opts), - capi_client_lib:handle_response(Response). - --spec get_contract_adjustment_by_id_for_party(context(), binary(), binary(), binary()) -> - {ok, term()} | {error, term()}. -get_contract_adjustment_by_id_for_party(Context, PartyID, ContractID, AdjID) -> - Params = #{ - binding => genlib_map:compact(#{ - <<"partyID">> => PartyID, - <<"contractID">> => ContractID, - <<"adjustmentID">> => AdjID - }) - }, - {Url, PreparedParams, Opts} = capi_client_lib:make_request(Context, Params), - Response = swag_client_contracts_api:get_contract_adjustment_by_id_for_party(Url, PreparedParams, Opts), - capi_client_lib:handle_response(Response). - --spec get_contract_adjustments(context(), binary()) -> {ok, term()} | {error, term()}. -get_contract_adjustments(Context, ContractID) -> - Params = #{ - binding => genlib_map:compact(#{ - <<"contractID">> => ContractID - }) - }, - {Url, PreparedParams, Opts} = capi_client_lib:make_request(Context, Params), - Response = swag_client_contracts_api:get_contract_adjustments(Url, PreparedParams, Opts), - capi_client_lib:handle_response(Response). - --spec get_contract_adjustments_for_party(context(), binary(), binary()) -> {ok, term()} | {error, term()}. -get_contract_adjustments_for_party(Context, PartyID, ContractID) -> - Params = #{ - binding => genlib_map:compact(#{ - <<"partyID">> => PartyID, - <<"contractID">> => ContractID - }) - }, - {Url, PreparedParams, Opts} = capi_client_lib:make_request(Context, Params), - Response = swag_client_contracts_api:get_contract_adjustments_for_party(Url, PreparedParams, Opts), - capi_client_lib:handle_response(Response). diff --git a/apps/capi_client/src/capi_client_customers.erl b/apps/capi_client/src/capi_client_customers.erl deleted file mode 100644 index f004b1b..0000000 --- a/apps/capi_client/src/capi_client_customers.erl +++ /dev/null @@ -1,124 +0,0 @@ --module(capi_client_customers). - --export([create_customer/2]). --export([get_customer_by_id/2]). --export([delete_customer/2]). --export([create_customer_access_token/2]). --export([create_binding/3]). --export([get_bindings/2]). --export([get_binding/3]). --export([get_customer_events/3]). --export([get_customer_events/4]). --export([get_customer_payment_methods/2]). - --type context() :: capi_client_lib:context(). - --spec create_customer(context(), map()) -> {ok, term()} | {error, term()}. -create_customer(Context, Request) -> - Params = #{ - body => Request - }, - {Url, PreparedParams, Opts} = capi_client_lib:make_request(Context, Params), - Response = swag_client_customers_api:create_customer(Url, PreparedParams, Opts), - capi_client_lib:handle_response(Response). - --spec get_customer_by_id(context(), binary()) -> {ok, term()} | {error, term()}. -get_customer_by_id(Context, CustomerID) -> - Params = #{ - binding => #{ - <<"customerID">> => CustomerID - } - }, - {Url, PreparedParams, Opts} = capi_client_lib:make_request(Context, Params), - Response = swag_client_customers_api:get_customer_by_id(Url, PreparedParams, Opts), - capi_client_lib:handle_response(Response). - --spec delete_customer(context(), binary()) -> {ok, term()} | {error, term()}. -delete_customer(Context, CustomerID) -> - Params = #{ - binding => #{ - <<"customerID">> => CustomerID - } - }, - {Url, PreparedParams, Opts} = capi_client_lib:make_request(Context, Params), - Response = swag_client_customers_api:delete_customer(Url, PreparedParams, Opts), - capi_client_lib:handle_response(Response). - --spec create_customer_access_token(context(), binary()) -> {ok, term()} | {error, term()}. -create_customer_access_token(Context, CustomerID) -> - Params = #{ - binding => #{ - <<"customerID">> => CustomerID - } - }, - {Url, PreparedParams, Opts} = capi_client_lib:make_request(Context, Params), - Response = swag_client_customers_api:create_customer_access_token(Url, PreparedParams, Opts), - capi_client_lib:handle_response(Response). - --spec create_binding(context(), binary(), map()) -> {ok, term()} | {error, term()}. -create_binding(Context, CustomerID, Request) -> - Params = #{ - binding => #{ - <<"customerID">> => CustomerID - }, - body => Request - }, - {Url, PreparedParams, Opts} = capi_client_lib:make_request(Context, Params), - Response = swag_client_customers_api:create_binding(Url, PreparedParams, Opts), - capi_client_lib:handle_response(Response). - --spec get_bindings(context(), binary()) -> {ok, term()} | {error, term()}. -get_bindings(Context, CustomerID) -> - Params = #{ - binding => #{ - <<"customerID">> => CustomerID - } - }, - {Url, PreparedParams, Opts} = capi_client_lib:make_request(Context, Params), - Response = swag_client_customers_api:get_bindings(Url, PreparedParams, Opts), - capi_client_lib:handle_response(Response). - --spec get_binding(context(), binary(), binary()) -> {ok, term()} | {error, term()}. -get_binding(Context, CustomerID, BindingID) -> - Params = #{ - binding => #{ - <<"customerID">> => CustomerID, - <<"customerBindingID">> => BindingID - } - }, - {Url, PreparedParams, Opts} = capi_client_lib:make_request(Context, Params), - Response = swag_client_customers_api:get_binding(Url, PreparedParams, Opts), - capi_client_lib:handle_response(Response). - --spec get_customer_events(context(), binary(), integer()) -> {ok, term()} | {error, term()}. -get_customer_events(Context, CustomerID, Limit) -> - Qs = #{ - <<"limit">> => genlib:to_binary(Limit) - }, - get_customer_events_with(Context, CustomerID, Qs). - --spec get_customer_events(context(), binary(), integer(), integer()) -> {ok, term()} | {error, term()}. -get_customer_events(Context, CustomerID, EventID, Limit) -> - Qs = #{ - <<"eventID">> => genlib:to_binary(EventID), - <<"limit">> => genlib:to_binary(Limit) - }, - get_customer_events_with(Context, CustomerID, Qs). - -get_customer_events_with(Context, CustomerID, Qs) -> - Params = #{ - binding => #{ - <<"customerID">> => CustomerID - }, - qs_val => Qs - }, - {Url, PreparedParams, Opts} = capi_client_lib:make_request(Context, Params), - Response = swag_client_customers_api:get_customer_events(Url, PreparedParams, Opts), - capi_client_lib:handle_response(Response). - --spec get_customer_payment_methods(context(), binary()) -> {ok, term()} | {error, term()}. -get_customer_payment_methods(Context, CustomerID) -> - Params = #{binding => #{<<"customerID">> => CustomerID}}, - {Url, PreparedParams, Opts} = capi_client_lib:make_request(Context, Params), - Response = swag_client_customers_api:get_customer_payment_methods(Url, PreparedParams, Opts), - capi_client_lib:handle_response(Response). diff --git a/apps/capi_client/src/capi_client_parties.erl b/apps/capi_client/src/capi_client_parties.erl index 877f44b..7675c43 100644 --- a/apps/capi_client/src/capi_client_parties.erl +++ b/apps/capi_client/src/capi_client_parties.erl @@ -1,38 +1,9 @@ -module(capi_client_parties). --export([get_my_party/1]). --export([suspend_my_party/1]). --export([activate_my_party/1]). -export([get_party_by_id/2]). --export([suspend_party_by_id/2]). --export([activate_party_by_id/2]). -type context() :: capi_client_lib:context(). --spec get_my_party(context()) -> {ok, term()} | {error, term()}. -get_my_party(Context) -> - {Url, PreparedParams, Opts} = capi_client_lib:make_request(Context, #{}), - Response = swag_client_parties_api:get_my_party(Url, PreparedParams, Opts), - capi_client_lib:handle_response(Response). - --spec suspend_my_party(context()) -> ok | {error, term()}. -suspend_my_party(Context) -> - {Url, PreparedParams, Opts} = capi_client_lib:make_request(Context, #{}), - Response = swag_client_parties_api:suspend_my_party(Url, PreparedParams, Opts), - case capi_client_lib:handle_response(Response) of - {ok, undefined} -> ok; - {error, Error} -> {error, Error} - end. - --spec activate_my_party(context()) -> ok | {error, term()}. -activate_my_party(Context) -> - {Url, PreparedParams, Opts} = capi_client_lib:make_request(Context, #{}), - Response = swag_client_parties_api:activate_my_party(Url, PreparedParams, Opts), - case capi_client_lib:handle_response(Response) of - {ok, undefined} -> ok; - {error, Error} -> {error, Error} - end. - -spec get_party_by_id(context(), binary()) -> {ok, term()} | {error, term()}. get_party_by_id(Context, PartyID) -> Params = #{ @@ -43,31 +14,3 @@ get_party_by_id(Context, PartyID) -> {Url, PreparedParams, Opts} = capi_client_lib:make_request(Context, Params), Response = swag_client_parties_api:get_party_by_id(Url, PreparedParams, Opts), capi_client_lib:handle_response(Response). - --spec suspend_party_by_id(context(), binary()) -> ok | {error, term()}. -suspend_party_by_id(Context, PartyID) -> - Params = #{ - binding => #{ - <<"partyID">> => PartyID - } - }, - {Url, PreparedParams, Opts} = capi_client_lib:make_request(Context, Params), - Response = swag_client_parties_api:suspend_party_by_id(Url, PreparedParams, Opts), - case capi_client_lib:handle_response(Response) of - {ok, undefined} -> ok; - {error, Error} -> {error, Error} - end. - --spec activate_party_by_id(context(), binary()) -> ok | {error, term()}. -activate_party_by_id(Context, PartyID) -> - Params = #{ - binding => #{ - <<"partyID">> => PartyID - } - }, - {Url, PreparedParams, Opts} = capi_client_lib:make_request(Context, Params), - Response = swag_client_parties_api:activate_party_by_id(Url, PreparedParams, Opts), - case capi_client_lib:handle_response(Response) of - {ok, undefined} -> ok; - {error, Error} -> {error, Error} - end. diff --git a/apps/capi_client/src/capi_client_searches.erl b/apps/capi_client/src/capi_client_searches.erl deleted file mode 100644 index 36be642..0000000 --- a/apps/capi_client/src/capi_client_searches.erl +++ /dev/null @@ -1,35 +0,0 @@ --module(capi_client_searches). - --export([search_invoices/3]). --export([search_payments/3]). --export([search_refunds/3]). - --type context() :: capi_client_lib:context(). --type search_query() :: capi_client_lib:search_query(). - --spec search_invoices(context(), binary(), search_query()) -> {ok, term(), term()} | {error, term()}. -search_invoices(Context, ShopID, Query) -> - search(Context, fun swag_client_search_api:search_invoices/3, ShopID, Query). - --spec search_payments(context(), binary(), search_query()) -> {ok, term(), term()} | {error, term()}. -search_payments(Context, ShopID, Query) -> - search(Context, fun swag_client_search_api:search_payments/3, ShopID, Query). - --spec search_refunds(context(), binary(), search_query()) -> {ok, term(), term()} | {error, term()}. -search_refunds(Context, ShopID, Query) -> - search(Context, fun swag_client_search_api:search_refunds/3, ShopID, Query). - -search(Context, WithFun, ShopID, Query) -> - Qs = capi_client_lib:make_search_query_string(Query), - Params = #{ - binding => #{<<"shopID">> => ShopID}, - qs_val => Qs - }, - {Url, PreparedParams, Opts} = capi_client_lib:make_request(Context, Params), - Response = WithFun(Url, PreparedParams, Opts), - case capi_client_lib:handle_response(Response) of - {ok, #{<<"totalCount">> := TotalCount, <<"result">> := Payments}} -> - {ok, TotalCount, Payments}; - {error, Error} -> - {error, Error} - end. diff --git a/apps/capi_client/src/capi_client_shops.erl b/apps/capi_client/src/capi_client_shops.erl index ccbf86d..449e967 100644 --- a/apps/capi_client/src/capi_client_shops.erl +++ b/apps/capi_client/src/capi_client_shops.erl @@ -1,22 +1,12 @@ -module(capi_client_shops). --export([get_shops/1]). -export([get_shops_for_party/2]). --export([get_shop_by_id/2]). -export([get_shop_by_id_for_party/3]). --export([suspend_shop/2]). -export([suspend_shop_for_party/3]). --export([activate_shop/2]). -export([activate_shop_for_party/3]). -type context() :: capi_client_lib:context(). --spec get_shops(context()) -> {ok, term()} | {error, term()}. -get_shops(Context) -> - {Url, PreparedParams, Opts} = capi_client_lib:make_request(Context, #{}), - Response = swag_client_shops_api:get_shops(Url, PreparedParams, Opts), - capi_client_lib:handle_response(Response). - -spec get_shops_for_party(context(), binary()) -> {ok, term()} | {error, term()}. get_shops_for_party(Context, PartyID) -> Params = #{ @@ -28,17 +18,6 @@ get_shops_for_party(Context, PartyID) -> Response = swag_client_shops_api:get_shops_for_party(Url, PreparedParams, Opts), capi_client_lib:handle_response(Response). --spec get_shop_by_id(context(), binary()) -> {ok, term()} | {error, term()}. -get_shop_by_id(Context, ShopID) -> - Params = #{ - binding => genlib_map:compact(#{ - <<"shopID">> => ShopID - }) - }, - {Url, PreparedParams, Opts} = capi_client_lib:make_request(Context, Params), - Response = swag_client_shops_api:get_shop_by_id(Url, PreparedParams, Opts), - capi_client_lib:handle_response(Response). - -spec get_shop_by_id_for_party(context(), binary(), binary()) -> {ok, term()} | {error, term()}. get_shop_by_id_for_party(Context, PartyID, ShopID) -> Params = #{ @@ -51,20 +30,6 @@ get_shop_by_id_for_party(Context, PartyID, ShopID) -> Response = swag_client_shops_api:get_shop_by_id_for_party(Url, PreparedParams, Opts), capi_client_lib:handle_response(Response). --spec suspend_shop(context(), binary()) -> ok | {error, term()}. -suspend_shop(Context, ShopID) -> - Params = #{ - binding => #{ - <<"shopID">> => ShopID - } - }, - {Url, PreparedParams, Opts} = capi_client_lib:make_request(Context, Params), - Response = swag_client_shops_api:suspend_shop(Url, PreparedParams, Opts), - case capi_client_lib:handle_response(Response) of - {ok, undefined} -> ok; - {error, Error} -> {error, Error} - end. - -spec suspend_shop_for_party(context(), binary(), binary()) -> ok | {error, term()}. suspend_shop_for_party(Context, PartyID, ShopID) -> Params = #{ @@ -80,20 +45,6 @@ suspend_shop_for_party(Context, PartyID, ShopID) -> {error, Error} -> {error, Error} end. --spec activate_shop(context(), binary()) -> ok | {error, term()}. -activate_shop(Context, ShopID) -> - Params = #{ - binding => genlib_map:compact(#{ - <<"shopID">> => ShopID - }) - }, - {Url, PreparedParams, Opts} = capi_client_lib:make_request(Context, Params), - Response = swag_client_shops_api:activate_shop(Url, PreparedParams, Opts), - case capi_client_lib:handle_response(Response) of - {ok, undefined} -> ok; - {error, Error} -> {error, Error} - end. - -spec activate_shop_for_party(context(), binary(), binary()) -> ok | {error, term()}. activate_shop_for_party(Context, PartyID, ShopID) -> Params = #{ diff --git a/apps/capi_woody_client/src/capi_woody_client.erl b/apps/capi_woody_client/src/capi_woody_client.erl index fec65ab..2a14143 100644 --- a/apps/capi_woody_client/src/capi_woody_client.erl +++ b/apps/capi_woody_client/src/capi_woody_client.erl @@ -77,12 +77,8 @@ get_service_modname(invoicing) -> {dmsl_payproc_thrift, 'Invoicing'}; get_service_modname(invoice_templating) -> {dmsl_payproc_thrift, 'InvoiceTemplating'}; -get_service_modname(magista) -> - {magista_magista_thrift, 'MerchantStatisticsService'}; get_service_modname(webhook_manager) -> - {dmsl_webhooker_thrift, 'WebhookManager'}; -get_service_modname(customer_management) -> - {dmsl_payproc_thrift, 'CustomerManagement'}. + {dmsl_webhooker_thrift, 'WebhookManager'}. get_service_deadline(ServiceName) -> ServiceDeadlines = genlib_app:env(?MODULE, service_deadlines, #{}), diff --git a/rebar.config b/rebar.config index 97d6aa4..5dd42cc 100644 --- a/rebar.config +++ b/rebar.config @@ -54,8 +54,8 @@ {feat, {git, "https://github.com/valitydev/feat.git", {branch, master}}}, {magista_proto, {git, "https://github.com/valitydev/magista-proto.git", {branch, master}}}, %% Libraries generated with swagger-codegen-erlang from valitydev/swag-payments - {swag_server, {git, "https://github.com/valitydev/swag-payments", {branch, "release/erlang/server/v2"}}}, - {swag_client, {git, "https://github.com/valitydev/swag-payments", {branch, "release/erlang/client/v2"}}}, + {swag_server, {git, "https://github.com/valitydev/swag-payments", {branch, "release/erlang/server/epic-v3"}}}, + {swag_client, {git, "https://github.com/valitydev/swag-payments", {branch, "release/erlang/client/epic-v3"}}}, %% OpenTelemetry deps {opentelemetry_api, "1.4.0"}, {opentelemetry, "1.5.0"}, diff --git a/rebar.lock b/rebar.lock index 2895942..ab1bf95 100644 --- a/rebar.lock +++ b/rebar.lock @@ -1,5 +1,5 @@ {"1.2.0", -[{<<"accept">>,{pkg,<<"accept">>,<<"0.3.6">>},2}, +[{<<"accept">>,{pkg,<<"accept">>,<<"0.3.7">>},2}, {<<"acceptor_pool">>,{pkg,<<"acceptor_pool">>,<<"1.0.0">>},2}, {<<"bender_client">>, {git,"https://github.com/valitydev/bender-client-erlang.git", @@ -15,7 +15,7 @@ 0}, {<<"bouncer_proto">>, {git,"https://github.com/valitydev/bouncer-proto.git", - {ref,"07dcc7b9b4599923b20bcf5f84642c3a1d6570e2"}}, + {ref,"31866c36c049dc568d4bc795a641690db3cb20ab"}}, 0}, {<<"cache">>,{pkg,<<"cache">>,<<"2.3.3">>},1}, {<<"certifi">>,{pkg,<<"certifi">>,<<"2.6.1">>},2}, @@ -41,7 +41,7 @@ {<<"ctx">>,{pkg,<<"ctx">>,<<"0.6.0">>},2}, {<<"damsel">>, {git,"https://github.com/valitydev/damsel.git", - {ref,"24932cdc557a75bfb3a4aeb1738638366003aba4"}}, + {ref,"5ca4f4a2af6bd68ba4d255889c0e2c0c1c5479a4"}}, 0}, {<<"dmt_client">>, {git,"https://github.com/valitydev/dmt_client.git", @@ -91,7 +91,7 @@ {ref,"e49ad10f49d50c746f7017412ba5409411731e89"}}, 0}, {<<"metrics">>,{pkg,<<"metrics">>,<<"1.0.1">>},2}, - {<<"mimerl">>,{pkg,<<"mimerl">>,<<"1.3.0">>},2}, + {<<"mimerl">>,{pkg,<<"mimerl">>,<<"1.4.0">>},2}, {<<"msgpack_proto">>, {git,"https://github.com/valitydev/msgpack-proto.git", {ref,"7e447496aa5df4a5f1ace7ef2e3c31248b2a3ed0"}}, @@ -120,7 +120,7 @@ 0}, {<<"prometheus">>,{pkg,<<"prometheus">>,<<"4.11.0">>},0}, {<<"prometheus_cowboy">>,{pkg,<<"prometheus_cowboy">>,<<"0.1.9">>},0}, - {<<"prometheus_httpd">>,{pkg,<<"prometheus_httpd">>,<<"2.1.14">>},1}, + {<<"prometheus_httpd">>,{pkg,<<"prometheus_httpd">>,<<"2.1.15">>},1}, {<<"quantile_estimator">>,{pkg,<<"quantile_estimator">>,<<"0.2.1">>},1}, {<<"ranch">>,{pkg,<<"ranch">>,<<"1.8.0">>},1}, {<<"scoper">>, @@ -134,18 +134,18 @@ {<<"ssl_verify_fun">>,{pkg,<<"ssl_verify_fun">>,<<"1.1.7">>},2}, {<<"swag_client">>, {git,"https://github.com/valitydev/swag-payments", - {ref,"c69fe919595791304c861925cfddc4448785a4a2"}}, + {ref,"8459eb26140bbd3a831cff7a79fe94f83c5911ce"}}, 0}, {<<"swag_server">>, {git,"https://github.com/valitydev/swag-payments", - {ref,"5d9b348a8f9cfeaea85a2f259e13f19a248e2aef"}}, + {ref,"a9ab04934b9b4ec14fd3e5ffc1927220225d680a"}}, 0}, {<<"thrift">>, {git,"https://github.com/valitydev/thrift_erlang.git", {ref,"3a60e5dc5bbd709495024f26e100b041c3547fd9"}}, 1}, {<<"tls_certificate_check">>, - {pkg,<<"tls_certificate_check">>,<<"1.27.0">>}, + {pkg,<<"tls_certificate_check">>,<<"1.28.0">>}, 1}, {<<"token_keeper_client">>, {git,"https://github.com/valitydev/token-keeper-client.git", @@ -155,7 +155,7 @@ {git,"https://github.com/valitydev/token-keeper-proto.git", {ref,"8b8bb4333828350301ae2fe801c0c8de61c6529c"}}, 1}, - {<<"unicode_util_compat">>,{pkg,<<"unicode_util_compat">>,<<"0.7.0">>},2}, + {<<"unicode_util_compat">>,{pkg,<<"unicode_util_compat">>,<<"0.7.1">>},2}, {<<"woody">>, {git,"https://github.com/valitydev/woody_erlang.git", {ref,"cc983a9423325ba1d6a509775eb6ff7ace721539"}}, @@ -166,7 +166,7 @@ 0}]}. [ {pkg_hash,[ - {<<"accept">>, <<"AD44AC7D704BF70EF8FB2E313EF5B978F9D1330BDDAC64509E93AFDA13281215">>}, + {<<"accept">>, <<"CD6E34A2D7E28CA38B2D3CB233734CA0C221EFBC1F171F91FEC5F162CC2D18DA">>}, {<<"acceptor_pool">>, <<"43C20D2ACAE35F0C2BCD64F9D2BDE267E459F0F3FD23DAB26485BF518C281B21">>}, {<<"cache">>, <<"B23A5FE7095445A88412A6E614C933377E0137B44FFED77C9B3FEF1A731A20B2">>}, {<<"certifi">>, <<"DBAB8E5E155A0763EEA978C913CA280A6B544BFA115633FA20249C3D396D9493">>}, @@ -182,21 +182,21 @@ {<<"idna">>, <<"8A63070E9F7D0C62EB9D9FCB360A7DE382448200FBBD1B106CC96D3D8099DF8D">>}, {<<"jsx">>, <<"D12516BAA0BB23A59BB35DCCAF02A1BD08243FCBB9EFE24F2D9D056CCFF71268">>}, {<<"metrics">>, <<"25F094DEA2CDA98213CECC3AEFF09E940299D950904393B2A29D191C346A8486">>}, - {<<"mimerl">>, <<"D0CD9FC04B9061F82490F6581E0128379830E78535E017F7780F37FEA7545726">>}, + {<<"mimerl">>, <<"3882A5CA67FBBE7117BA8947F27643557ADEC38FA2307490C4C4207624CB213B">>}, {<<"opentelemetry">>, <<"7DDA6551EDFC3050EA4B0B40C0D2570423D6372B97E9C60793263EF62C53C3C2">>}, {<<"opentelemetry_api">>, <<"63CA1742F92F00059298F478048DFB826F4B20D49534493D6919A0DB39B6DB04">>}, {<<"opentelemetry_exporter">>, <<"5D546123230771EF4174E37BEDFD77E3374913304CD6EA3CA82A2ADD49CD5D56">>}, {<<"parse_trans">>, <<"6E6AA8167CB44CC8F39441D05193BE6E6F4E7C2946CB2759F015F8C56B76E5FF">>}, {<<"prometheus">>, <<"B95F8DE8530F541BD95951E18E355A840003672E5EDA4788C5FA6183406BA29A">>}, {<<"prometheus_cowboy">>, <<"D9D5B300516A61ED5AE31391F8EEEEB202230081D32A1813F2D78772B6F274E1">>}, - {<<"prometheus_httpd">>, <<"529A63CA2A451FC5D28C77020787A75AF661DADF721E7EC14B5842412FB67A32">>}, + {<<"prometheus_httpd">>, <<"8F767D819A5D36275EAB9264AFF40D87279151646776069BF69FBDBBD562BD75">>}, {<<"quantile_estimator">>, <<"EF50A361F11B5F26B5F16D0696E46A9E4661756492C981F7B2229EF42FF1CD15">>}, {<<"ranch">>, <<"8C7A100A139FD57F17327B6413E4167AC559FBC04CA7448E9BE9057311597A1D">>}, {<<"ssl_verify_fun">>, <<"354C321CF377240C7B8716899E182CE4890C5938111A1296ADD3EC74CF1715DF">>}, - {<<"tls_certificate_check">>, <<"2C1C7FC922A329B9EB45DDF39113C998BBDEB28A534219CD884431E2AEE1811E">>}, - {<<"unicode_util_compat">>, <<"BC84380C9AB48177092F43AC89E4DFA2C6D62B40B8BD132B1059ECC7232F9A78">>}]}, + {<<"tls_certificate_check">>, <<"C39BF21F67C2D124AE905454FAD00F27E625917E8AB1009146E916E1DF6AB275">>}, + {<<"unicode_util_compat">>, <<"A48703A25C170EEDADCA83B11E88985AF08D35F37C6F664D6DCFB106A97782FC">>}]}, {pkg_hash_ext,[ - {<<"accept">>, <<"A5167FA1AE90315C3F1DD189446312F8A55D00EFA357E9C569BDA47736B874C3">>}, + {<<"accept">>, <<"CA69388943F5DAD2E7232A5478F16086E3C872F48E32B88B378E1885A59F5649">>}, {<<"acceptor_pool">>, <<"0CBCD83FDC8B9AD2EEE2067EF8B91A14858A5883CB7CD800E6FCD5803E158788">>}, {<<"cache">>, <<"44516CE6FA03594D3A2AF025DD3A87BFE711000EB730219E1DDEFC816E0AA2F4">>}, {<<"certifi">>, <<"524C97B4991B3849DD5C17A631223896272C6B0AF446778BA4675A1DFF53BB7E">>}, @@ -212,17 +212,17 @@ {<<"idna">>, <<"92376EB7894412ED19AC475E4A86F7B413C1B9FBB5BD16DCCD57934157944CEA">>}, {<<"jsx">>, <<"0C5CC8FDC11B53CC25CF65AC6705AD39E54ECC56D1C22E4ADB8F5A53FB9427F3">>}, {<<"metrics">>, <<"69B09ADDDC4F74A40716AE54D140F93BEB0FB8978D8636EADED0C31B6F099F16">>}, - {<<"mimerl">>, <<"A1E15A50D1887217DE95F0B9B0793E32853F7C258A5CD227650889B38839FE9D">>}, + {<<"mimerl">>, <<"13AF15F9F68C65884ECCA3A3891D50A7B57D82152792F3E19D88650AA126B144">>}, {<<"opentelemetry">>, <<"CDF4F51D17B592FC592B9A75F86A6F808C23044BA7CF7B9534DEBBCC5C23B0EE">>}, {<<"opentelemetry_api">>, <<"3DFBBFAA2C2ED3121C5C483162836C4F9027DEF469C41578AF5EF32589FCFC58">>}, {<<"opentelemetry_exporter">>, <<"A1F9F271F8D3B02B81462A6BFEF7075FD8457FDB06ADFF5D2537DF5E2264D9AF">>}, {<<"parse_trans">>, <<"620A406CE75DADA827B82E453C19CF06776BE266F5A67CFF34E1EF2CBB60E49A">>}, {<<"prometheus">>, <<"719862351AABF4DF7079B05DC085D2BBCBE3AC0AC3009E956671B1D5AB88247D">>}, {<<"prometheus_cowboy">>, <<"5F71C039DEB9E9FF9DD6366BC74C907A463872B85286E619EFF0BDA15111695A">>}, - {<<"prometheus_httpd">>, <<"8B39F8CB6467B80D648FB982FDEB796BAB006BB43B1C95279289F311DB562D4E">>}, + {<<"prometheus_httpd">>, <<"67736D000745184D5013C58A63E947821AB90CB9320BC2E6AE5D3061C6FFE039">>}, {<<"quantile_estimator">>, <<"282A8A323CA2A845C9E6F787D166348F776C1D4A41EDE63046D72D422E3DA946">>}, {<<"ranch">>, <<"49FBCFD3682FAB1F5D109351B61257676DA1A2FDBE295904176D5E521A2DDFE5">>}, {<<"ssl_verify_fun">>, <<"FE4C190E8F37401D30167C8C405EDA19469F34577987C76DDE613E838BBC67F8">>}, - {<<"tls_certificate_check">>, <<"51A5AD3DBD72D4694848965F3B5076E8B55D70EB8D5057FCDDD536029AB8A23C">>}, - {<<"unicode_util_compat">>, <<"25EEE6D67DF61960CF6A794239566599B09E17E668D3700247BC498638152521">>}]} + {<<"tls_certificate_check">>, <<"3AB058C3F9457FFFCA916729587415F0DDC822048A0E5B5E2694918556D92DF1">>}, + {<<"unicode_util_compat">>, <<"B3A917854CE3AE233619744AD1E0102E05673136776FB2FA76234F3E03B23642">>}]} ]. From 404b8703bf243a953811a43845985956b4509341 Mon Sep 17 00:00:00 2001 From: Aleksey Kashapov Date: Mon, 9 Jun 2025 13:33:55 +0300 Subject: [PATCH 2/7] Upgrades to dmt v2 (#59) * Upgrades to dmt v2 * Wraps country retrieval function * Bumps dmt client v2 * Fixes dmt client usage --- apps/capi/src/capi_domain.erl | 55 ++++-- apps/capi/src/capi_handler_countries.erl | 3 +- apps/capi/test/capi_ct_helper.erl | 56 +++++- apps/capi/test/capi_dummy_data.hrl | 234 +++++++++++------------ rebar.config | 10 +- rebar.lock | 8 +- 6 files changed, 213 insertions(+), 153 deletions(-) diff --git a/apps/capi/src/capi_domain.erl b/apps/capi/src/capi_domain.erl index 331314c..22ab95d 100644 --- a/apps/capi/src/capi_domain.erl +++ b/apps/capi/src/capi_domain.erl @@ -1,11 +1,12 @@ -module(capi_domain). -include_lib("damsel/include/dmsl_domain_thrift.hrl"). --include_lib("damsel/include/dmsl_domain_conf_thrift.hrl"). +-include_lib("damsel/include/dmsl_domain_conf_v2_thrift.hrl"). -export([head/0]). -export([get_payment_institution/2]). -export([get_payment_institutions/1]). +-export([get_country/2]). -export([get/2]). -export([get/3]). -export([get_ext/3]). @@ -15,6 +16,8 @@ -export([extract_type/1]). -type processing_context() :: capi_handler:processing_context(). +-type country_code() :: dmsl_domain_thrift:'CountryCode'(). +-type country_object() :: dmsl_domain_thrift:'CountryObject'(). -type ref() :: dmsl_domain_thrift:'Reference'(). -type data() :: _. -type revision() :: dmt_client:version(). @@ -29,7 +32,7 @@ -spec head() -> revision(). head() -> - dmt_client:get_last_version(). + dmt_client:get_latest_version(). -spec get_payment_institution(payment_institution_ref(), processing_context()) -> {ok, payment_institution()} | {error, not_found}. @@ -46,10 +49,8 @@ get_payment_institutions(Context) -> try Opts = make_opts(Context), - #'domain_conf_VersionedObject'{ - version = Version, - object = {globals, #domain_GlobalsObject{data = Globals}} - } = dmt_client:checkout_versioned_object(latest, globals(), Opts), + {Version, #domain_GlobalsObject{data = Globals}} = + unwrap_versioned(dmt_client:checkout_object(latest, globals(), Opts)), PaymentInstitutionRefs = case Globals#domain_Globals.payment_institutions of @@ -60,9 +61,8 @@ get_payment_institutions(Context) -> PaymentInstitutions = lists:map( fun(Ref) -> - {payment_institution, Object} = dmt_client:checkout_object( - Version, {payment_institution, Ref}, Opts - ), + {_, Object} = + unwrap_versioned(dmt_client:checkout_object(Version, {payment_institution, Ref}, Opts)), Object end, PaymentInstitutionRefs @@ -70,7 +70,18 @@ get_payment_institutions(Context) -> {ok, PaymentInstitutions} catch - throw:#'domain_conf_ObjectNotFound'{} -> + throw:#domain_conf_v2_ObjectNotFound{} -> + {error, not_found} + end. + +-spec get_country(country_code(), processing_context() | undefined) -> {ok, country_object()} | {error, not_found}. +get_country(CountryCode, Context) -> + Ref = {country, #domain_CountryRef{id = CountryCode}}, + try + get(Ref, Context) + catch + error:{woody_error, {internal, result_unexpected, _}} -> + %% NOTE Object not exists if woody fails to encode country code {error, not_found} end. @@ -82,20 +93,22 @@ get(Ref, Context) -> get(Ref, Revision, Context) -> try Opts = make_opts(Context), - {_Type, Object} = dmt_client:checkout_object(Revision, Ref, Opts), + {_, Object} = unwrap_versioned(dmt_client:checkout_object(Revision, Ref, Opts)), {ok, Object} catch - throw:#'domain_conf_ObjectNotFound'{} -> + throw:#domain_conf_v2_ObjectNotFound{} -> {error, not_found} end. +%% FIXME Naming. It supposed to return unwrapped `Data` from object +%% structured as `{Type, {Tag, Ref, Data}}`. -spec get_ext(ref(), revision(), processing_context() | undefined) -> {ok, data()} | {error, not_found}. get_ext(Ref, Revision, Context) -> try Opts = make_opts(Context), - {ok, extract_data(dmt_client:checkout_object(Revision, Ref, Opts))} + {ok, extract_data(unwrap_versioned(dmt_client:checkout_object(Revision, Ref, Opts)))} catch - throw:#'domain_conf_ObjectNotFound'{} -> + throw:#domain_conf_v2_ObjectNotFound{} -> {error, not_found} end. @@ -143,7 +156,13 @@ globals() -> -spec get_objects_by_type(Type :: atom(), processing_context()) -> {ok, [dmsl_domain_thrift:'DomainObject'()]}. get_objects_by_type(Type, Context) -> Opts = make_opts(Context), - Objects = dmt_client:checkout_objects_by_type(latest, Type, Opts), + Objects = lists:map( + fun(VersionedObject) -> + {_, Object} = unwrap_versioned(VersionedObject), + Object + end, + dmt_client:checkout_objects_by_type(latest, Type, Opts) + ), {ok, Objects}. -spec make_opts(processing_context()) -> dmt_client:opts(). @@ -151,3 +170,9 @@ make_opts(#{woody_context := WoodyContext}) -> #{woody_context => WoodyContext}; make_opts(_) -> #{}. + +unwrap_versioned(#domain_conf_v2_VersionedObject{ + info = #domain_conf_v2_VersionedObjectInfo{version = Version}, + object = {_Type, Object} +}) -> + {Version, Object}. diff --git a/apps/capi/src/capi_handler_countries.erl b/apps/capi/src/capi_handler_countries.erl index 1ded40b..ffafa69 100644 --- a/apps/capi/src/capi_handler_countries.erl +++ b/apps/capi/src/capi_handler_countries.erl @@ -29,8 +29,7 @@ process_request('GetCountries', _Req, Context) -> {ok, {200, #{}, lists:map(fun decode_country_object/1, Countries)}}; process_request('GetCountryByID', Req, Context) -> CountryCode = capi_coder_utils:encode_country_code(maps:get('countryID', Req)), - Ref = {country, #domain_CountryRef{id = CountryCode}}, - case capi_domain:get(Ref, Context) of + case capi_domain:get_country(CountryCode, Context) of {ok, CountryObject} -> {ok, {200, #{}, decode_country_object(CountryObject)}}; {error, not_found} -> diff --git a/apps/capi/test/capi_ct_helper.erl b/apps/capi/test/capi_ct_helper.erl index 08dc05c..d178ec1 100644 --- a/apps/capi/test/capi_ct_helper.erl +++ b/apps/capi/test/capi_ct_helper.erl @@ -3,9 +3,7 @@ -include_lib("common_test/include/ct.hrl"). -include_lib("capi_dummy_data.hrl"). -include_lib("capi_token_keeper_data.hrl"). --include_lib("damsel/include/dmsl_domain_conf_thrift.hrl"). --include_lib("damsel/include/dmsl_domain_thrift.hrl"). --include_lib("damsel/include/dmsl_base_thrift.hrl"). +-include_lib("damsel/include/dmsl_domain_conf_v2_thrift.hrl"). -export([init_suite/2]). -export([init_suite/3]). @@ -50,12 +48,44 @@ init_suite(Module, Config, CapiEnv) -> WoodyApp = start_app(woody), ServiceURLs = mock_services_( [ + { + 'RepositoryClient', + {dmsl_domain_conf_v2_thrift, 'RepositoryClient'}, + fun('CheckoutObject', {{version, ?INTEGER}, ObjectRef}) -> + case maps:get(ObjectRef, ?ALL_OBJECTS, undefined) of + undefined -> + woody_error:raise(business, #domain_conf_v2_ObjectNotFound{}); + Object -> + {ok, dmt_wrap_object(Object)} + end + end + }, { 'Repository', - {dmsl_domain_conf_thrift, 'Repository'}, + {dmsl_domain_conf_v2_thrift, 'Repository'}, fun - ('Checkout', _) -> {ok, ?SNAPSHOT}; - ('PullRange', _) -> {ok, #{}} + ('GetLatestVersion', _) -> + {ok, ?INTEGER}; + ( + 'SearchFullObjects', + {#domain_conf_v2_SearchRequestParams{ + query = ~b"*", version = ?INTEGER, limit = _, type = Type, continuation_token = _ + }} + ) -> + Result0 = lists:foldl( + fun + ({{T, _}, Object}, Acc) when T =:= Type -> + [dmt_wrap_object(Object) | Acc]; + (_, Acc) -> + Acc + end, + [], + maps:to_list(?ALL_OBJECTS) + ), + Result1 = lists:reverse(Result0), + {ok, #domain_conf_v2_SearchFullResponse{ + result = Result1, total_count = length(Result1), continuation_token = undefined + }} end } ], @@ -321,3 +351,17 @@ add_prefix(Key, Value, {Prefix, Acc}) -> get_blacklisted_keys_dir(Config) -> filename:join(?config(data_dir, Config), "blacklisted_keys"). + +dmt_wrap_object(Object) -> + #domain_conf_v2_VersionedObject{ + info = #domain_conf_v2_VersionedObjectInfo{ + version = ?INTEGER, + changed_at = genlib_rfc3339:format(genlib_time:unow(), second), + changed_by = #domain_conf_v2_Author{ + id = ?STRING, + name = ?STRING, + email = ?STRING + } + }, + object = Object + }. diff --git a/apps/capi/test/capi_dummy_data.hrl b/apps/capi/test/capi_dummy_data.hrl index e03d8c0..246eaec 100644 --- a/apps/capi/test/capi_dummy_data.hrl +++ b/apps/capi/test/capi_dummy_data.hrl @@ -5,7 +5,6 @@ -include_lib("damsel/include/dmsl_domain_thrift.hrl"). -include_lib("damsel/include/dmsl_payproc_thrift.hrl"). -include_lib("damsel/include/dmsl_webhooker_thrift.hrl"). --include_lib("damsel/include/dmsl_domain_conf_thrift.hrl"). -include_lib("damsel/include/dmsl_user_interaction_thrift.hrl"). -include_lib("magista_proto/include/magista_magista_thrift.hrl"). @@ -684,125 +683,122 @@ status_changed_at = ?TIMESTAMP }). --define(SNAPSHOT, #'domain_conf_Snapshot'{ - version = ?INTEGER, - domain = #{ - {category, #domain_CategoryRef{id = ?INTEGER}} => - {category, #domain_CategoryObject{ - ref = #domain_CategoryRef{id = ?INTEGER}, - data = #domain_Category{ - name = ?STRING, - description = ?STRING - } - }}, - {business_schedule, #domain_BusinessScheduleRef{id = ?INTEGER}} => - {business_schedule, #domain_BusinessScheduleObject{ - ref = #domain_BusinessScheduleRef{id = ?INTEGER}, - data = #domain_BusinessSchedule{ - name = ?STRING, - description = ?STRING, - schedule = #'base_Schedule'{ - year = {every, #'base_ScheduleEvery'{}}, - month = {every, #'base_ScheduleEvery'{}}, - day_of_month = {every, #'base_ScheduleEvery'{}}, - day_of_week = {every, #'base_ScheduleEvery'{}}, - hour = {every, #'base_ScheduleEvery'{}}, - minute = {every, #'base_ScheduleEvery'{}}, - second = {every, #'base_ScheduleEvery'{}} - }, - delay = #'base_TimeSpan'{} - } - }}, - {globals, #domain_GlobalsRef{}} => - {globals, #domain_GlobalsObject{ - ref = #domain_GlobalsRef{}, - data = #domain_Globals{ - external_account_set = {value, #domain_ExternalAccountSetRef{id = ?INTEGER}}, - payment_institutions = [#domain_PaymentInstitutionRef{id = ?INTEGER}] - } - }}, - {payment_institution, #domain_PaymentInstitutionRef{id = ?INTEGER}} => - {payment_institution, #domain_PaymentInstitutionObject{ - ref = #domain_PaymentInstitutionRef{id = ?INTEGER}, - data = #domain_PaymentInstitution{ - name = ?STRING, - description = ?STRING, - system_account_set = {value, #domain_SystemAccountSetRef{id = ?INTEGER}}, - default_contract_template = {value, #domain_ContractTemplateRef{id = ?INTEGER}}, - providers = {value, []}, - inspector = {value, #domain_InspectorRef{id = ?INTEGER}}, - realm = test, - residences = [rus] - } - }}, - {country, #domain_CountryRef{id = rus}} => - {country, #domain_CountryObject{ - ref = #domain_CountryRef{id = rus}, - data = #domain_Country{ - name = <<"Russia">> - } - }}, - {party_config, #domain_PartyConfigRef{id = ?STRING}} => - {party_config, #domain_PartyConfigObject{ - ref = #domain_PartyConfigRef{id = ?STRING}, - data = ?PARTY_WITH_SHOPS - }}, - {shop_config, #domain_ShopConfigRef{id = ?STRING}} => - {shop_config, #domain_ShopConfigObject{ - ref = #domain_ShopConfigRef{id = ?STRING}, - data = ?SHOP(?USD) - }}, - {country, #domain_CountryRef{id = deu}} => - {country, #domain_CountryObject{ - ref = #domain_CountryRef{id = deu}, - data = #domain_Country{ - name = <<"Germany">>, - trade_blocs = ordsets:from_list( - [#domain_TradeBlocRef{id = <<"EEA">>}] - ) - } - }}, - {trade_bloc, #domain_TradeBlocRef{id = <<"EEA">>}} => - {trade_bloc, #domain_TradeBlocObject{ - ref = #domain_TradeBlocRef{id = <<"EEA">>}, - data = #domain_TradeBloc{ - name = <<"European Economic Area">>, - description = <<"Extension of EU">> - } - }}, - - {payment_system, #domain_PaymentSystemRef{id = <<"visa">>}} => - {payment_system, #domain_PaymentSystemObject{ - ref = #domain_PaymentSystemRef{id = <<"visa">>}, - data = #domain_PaymentSystem{name = <<"Visa">>} - }}, - - {payment_system, #domain_PaymentSystemRef{id = <<"mastercard">>}} => - {payment_system, #domain_PaymentSystemObject{ - ref = #domain_PaymentSystemRef{id = <<"mastercard">>}, - data = #domain_PaymentSystem{name = <<"Mastercard">>} - }}, - - {payment_service, #domain_PaymentServiceRef{id = <<"qiwi">>}} => - {payment_service, #domain_PaymentServiceObject{ - ref = #domain_PaymentServiceRef{id = <<"qiwi">>}, - data = #domain_PaymentService{ - name = <<"Qiwi">>, - brand_name = <<"QIWI">>, - category = <<"wallets">>, - metadata = #{ - <<"test.ns">> => - {obj, #{ - <<"answer">> => {i, 42}, - <<"localization">> => - {obj, #{ - <<"ru_RU">> => {arr, [{str, <<"КИВИ Кошелёк">>}]} - }} - }} - } +-define(ALL_OBJECTS, #{ + {category, #domain_CategoryRef{id = ?INTEGER}} => + {category, #domain_CategoryObject{ + ref = #domain_CategoryRef{id = ?INTEGER}, + data = #domain_Category{ + name = ?STRING, + description = ?STRING + } + }}, + {business_schedule, #domain_BusinessScheduleRef{id = ?INTEGER}} => + {business_schedule, #domain_BusinessScheduleObject{ + ref = #domain_BusinessScheduleRef{id = ?INTEGER}, + data = #domain_BusinessSchedule{ + name = ?STRING, + description = ?STRING, + schedule = #'base_Schedule'{ + year = {every, #'base_ScheduleEvery'{}}, + month = {every, #'base_ScheduleEvery'{}}, + day_of_month = {every, #'base_ScheduleEvery'{}}, + day_of_week = {every, #'base_ScheduleEvery'{}}, + hour = {every, #'base_ScheduleEvery'{}}, + minute = {every, #'base_ScheduleEvery'{}}, + second = {every, #'base_ScheduleEvery'{}} + }, + delay = #'base_TimeSpan'{} + } + }}, + {globals, #domain_GlobalsRef{}} => + {globals, #domain_GlobalsObject{ + ref = #domain_GlobalsRef{}, + data = #domain_Globals{ + external_account_set = {value, #domain_ExternalAccountSetRef{id = ?INTEGER}}, + payment_institutions = [#domain_PaymentInstitutionRef{id = ?INTEGER}] + } + }}, + {payment_institution, #domain_PaymentInstitutionRef{id = ?INTEGER}} => + {payment_institution, #domain_PaymentInstitutionObject{ + ref = #domain_PaymentInstitutionRef{id = ?INTEGER}, + data = #domain_PaymentInstitution{ + name = ?STRING, + description = ?STRING, + system_account_set = {value, #domain_SystemAccountSetRef{id = ?INTEGER}}, + default_contract_template = {value, #domain_ContractTemplateRef{id = ?INTEGER}}, + providers = {value, []}, + inspector = {value, #domain_InspectorRef{id = ?INTEGER}}, + realm = test, + residences = [rus] + } + }}, + {country, #domain_CountryRef{id = rus}} => + {country, #domain_CountryObject{ + ref = #domain_CountryRef{id = rus}, + data = #domain_Country{ + name = <<"Russia">> + } + }}, + {party_config, #domain_PartyConfigRef{id = ?STRING}} => + {party_config, #domain_PartyConfigObject{ + ref = #domain_PartyConfigRef{id = ?STRING}, + data = ?PARTY_WITH_SHOPS + }}, + {shop_config, #domain_ShopConfigRef{id = ?STRING}} => + {shop_config, #domain_ShopConfigObject{ + ref = #domain_ShopConfigRef{id = ?STRING}, + data = ?SHOP(?USD) + }}, + {country, #domain_CountryRef{id = deu}} => + {country, #domain_CountryObject{ + ref = #domain_CountryRef{id = deu}, + data = #domain_Country{ + name = <<"Germany">>, + trade_blocs = ordsets:from_list( + [#domain_TradeBlocRef{id = <<"EEA">>}] + ) + } + }}, + {trade_bloc, #domain_TradeBlocRef{id = <<"EEA">>}} => + {trade_bloc, #domain_TradeBlocObject{ + ref = #domain_TradeBlocRef{id = <<"EEA">>}, + data = #domain_TradeBloc{ + name = <<"European Economic Area">>, + description = <<"Extension of EU">> + } + }}, + + {payment_system, #domain_PaymentSystemRef{id = <<"visa">>}} => + {payment_system, #domain_PaymentSystemObject{ + ref = #domain_PaymentSystemRef{id = <<"visa">>}, + data = #domain_PaymentSystem{name = <<"Visa">>} + }}, + + {payment_system, #domain_PaymentSystemRef{id = <<"mastercard">>}} => + {payment_system, #domain_PaymentSystemObject{ + ref = #domain_PaymentSystemRef{id = <<"mastercard">>}, + data = #domain_PaymentSystem{name = <<"Mastercard">>} + }}, + + {payment_service, #domain_PaymentServiceRef{id = <<"qiwi">>}} => + {payment_service, #domain_PaymentServiceObject{ + ref = #domain_PaymentServiceRef{id = <<"qiwi">>}, + data = #domain_PaymentService{ + name = <<"Qiwi">>, + brand_name = <<"QIWI">>, + category = <<"wallets">>, + metadata = #{ + <<"test.ns">> => + {obj, #{ + <<"answer">> => {i, 42}, + <<"localization">> => + {obj, #{ + <<"ru_RU">> => {arr, [{str, <<"КИВИ Кошелёк">>}]} + }} + }} } - }} - } + } + }} }). -define(USER_INTERACTION, diff --git a/rebar.config b/rebar.config index 5dd42cc..7c266ba 100644 --- a/rebar.config +++ b/rebar.config @@ -35,11 +35,11 @@ {genlib, {git, "https://github.com/valitydev/genlib.git", {tag, "v1.1.0"}}}, {cowboy_draining_server, {git, "https://github.com/valitydev/cowboy_draining_server.git", {branch, "master"}}}, {woody, {git, "https://github.com/valitydev/woody_erlang.git", {tag, "v1.1.0"}}}, - {woody_user_identity, {git, "https://github.com/valitydev/woody_erlang_user_identity.git", {branch, "master"}}}, - {damsel, {git, "https://github.com/valitydev/damsel.git", {branch, "master"}}}, + {woody_user_identity, {git, "https://github.com/valitydev/woody_erlang_user_identity.git", {tag, "v1.1.0"}}}, + {damsel, {git, "https://github.com/valitydev/damsel.git", {tag, "v2.2.0"}}}, {bender_proto, {git, "https://github.com/valitydev/bender-proto.git", {branch, "master"}}}, {bender_client, {git, "https://github.com/valitydev/bender-client-erlang.git", {tag, "v1.1.0"}}}, - {dmt_client, {git, "https://github.com/valitydev/dmt_client.git", {branch, "master"}}}, + {dmt_client, {git, "https://github.com/valitydev/dmt_client.git", {tag, "v2.0.0"}}}, {cowboy_cors, {git, "https://github.com/valitydev/cowboy_cors.git", {branch, "master"}}}, {cowboy_access_log, {git, "https://github.com/valitydev/cowboy_access_log.git", {branch, "master"}}}, {payproc_errors, {git, "https://github.com/valitydev/payproc-errors-erlang.git", {branch, "master"}}}, @@ -90,10 +90,6 @@ {profiles, [ {prod, [ {deps, [ - %% NOTE - %% Because of a dependency conflict, prometheus libs are only included in production build for now - %% https://github.com/project-fifo/rebar3_lint/issues/42 - %% https://github.com/valitydev/hellgate/pull/2/commits/884724c1799703cee4d1033850fe32c17f986d9e {recon, "2.3.6"}, {logger_logstash_formatter, {git, "https://github.com/valitydev/logger_logstash_formatter.git", {ref, "08a66a6"}}} diff --git a/rebar.lock b/rebar.lock index ab1bf95..7b9efdb 100644 --- a/rebar.lock +++ b/rebar.lock @@ -41,11 +41,11 @@ {<<"ctx">>,{pkg,<<"ctx">>,<<"0.6.0">>},2}, {<<"damsel">>, {git,"https://github.com/valitydev/damsel.git", - {ref,"5ca4f4a2af6bd68ba4d255889c0e2c0c1c5479a4"}}, + {ref,"ba7414811590859d058817b8f22d2e9c22f627f8"}}, 0}, {<<"dmt_client">>, {git,"https://github.com/valitydev/dmt_client.git", - {ref,"d8a4f490d49c038d96f1cbc2a279164c6f4039f9"}}, + {ref,"fcfb028a041149caeebec8d9cef469c8cdbbc63e"}}, 0}, {<<"dmt_core">>, {git,"https://github.com/valitydev/dmt-core.git", @@ -108,7 +108,7 @@ {<<"parse_trans">>,{pkg,<<"parse_trans">>,<<"3.4.1">>},1}, {<<"party_client">>, {git,"https://github.com/valitydev/party-client-erlang.git", - {ref,"a82682b6f55f41ff4962b2666bbd12cb5f1ece25"}}, + {ref,"b10b102673d899f6661e0c1a9e70f04ebddc9263"}}, 0}, {<<"payout_manager_proto">>, {git,"https://github.com/valitydev/payout-manager-proto.git", @@ -162,7 +162,7 @@ 0}, {<<"woody_user_identity">>, {git,"https://github.com/valitydev/woody_erlang_user_identity.git", - {ref,"a480762fea8d7c08f105fb39ca809482b6cb042e"}}, + {ref,"1bc1e260b8d464fe7720ca3e26f52fed363aff67"}}, 0}]}. [ {pkg_hash,[ From d2f314b158c38d114003d506c05ea891ecc009f0 Mon Sep 17 00:00:00 2001 From: Aleksey Kashapov Date: Mon, 9 Jun 2025 13:35:20 +0300 Subject: [PATCH 3/7] Adds tag action --- .github/workflows/tag-action.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 .github/workflows/tag-action.yml diff --git a/.github/workflows/tag-action.yml b/.github/workflows/tag-action.yml new file mode 100644 index 0000000..ec3faf4 --- /dev/null +++ b/.github/workflows/tag-action.yml @@ -0,0 +1,18 @@ +name: Create Tag + +on: + push: + branches: + - master + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout Repo + uses: actions/checkout@v3 + + - uses: valitydev/action-tagger@v2 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + with-v: true From b19de63b8147e0a820650934114bbafc534f474a Mon Sep 17 00:00:00 2001 From: Aleksey Kashapov Date: Mon, 4 Aug 2025 18:40:57 +0300 Subject: [PATCH 4/7] Removes obsolete testcases and fixtures; bumps deps (#62) --- apps/capi/src/capi.app.src | 1 - apps/capi/src/capi_bouncer_context.erl | 6 +- apps/capi/src/capi_handler_decoder_party.erl | 14 +-- apps/capi/src/capi_handler_parties.erl | 2 +- .../src/capi_handler_payment_institutions.erl | 30 ------ apps/capi/src/capi_handler_payments.erl | 4 - apps/capi/src/capi_handler_shops.erl | 22 ++-- apps/capi/src/capi_handler_utils.erl | 2 +- apps/capi/src/capi_party.erl | 24 +---- .../test/capi_base_api_token_tests_SUITE.erl | 43 -------- apps/capi/test/capi_dummy_data.hrl | 101 ++++-------------- .../test/capi_idempotency_tests_SUITE.erl | 3 +- ...oice_template_access_token_tests_SUITE.erl | 4 - .../src/capi_client_payment_institutions.erl | 12 --- config/sys.config | 8 +- rebar.config | 10 +- rebar.lock | 22 +--- 17 files changed, 51 insertions(+), 257 deletions(-) diff --git a/apps/capi/src/capi.app.src b/apps/capi/src/capi.app.src index 69ff142..4ce6d78 100644 --- a/apps/capi/src/capi.app.src +++ b/apps/capi/src/capi.app.src @@ -30,7 +30,6 @@ bouncer_client, token_keeper_client, party_client, - magista_proto, opentelemetry_api, opentelemetry_exporter, opentelemetry diff --git a/apps/capi/src/capi_bouncer_context.erl b/apps/capi/src/capi_bouncer_context.erl index 5800b19..96a37d2 100644 --- a/apps/capi/src/capi_bouncer_context.erl +++ b/apps/capi/src/capi_bouncer_context.erl @@ -187,12 +187,8 @@ build_webhook_filter({Type, Filter}) -> #ctx_v1_WebhookFilter{topic = erlang:atom_to_binary(Type, utf8)} ). -build_webhook_filter_details(#webhooker_PartyEventFilter{}, Ctx) -> - Ctx; build_webhook_filter_details(#webhooker_InvoiceEventFilter{shop_id = ShopID}, Ctx) -> - Ctx#ctx_v1_WebhookFilter{shop = 'maybe'(ShopID, fun build_entity/1)}; -build_webhook_filter_details(#webhooker_WalletEventFilter{}, Ctx) -> - Ctx. + Ctx#ctx_v1_WebhookFilter{shop = 'maybe'(ShopID, fun build_entity/1)}. %% diff --git a/apps/capi/src/capi_handler_decoder_party.erl b/apps/capi/src/capi_handler_decoder_party.erl index f5d21e2..7a2cead 100644 --- a/apps/capi/src/capi_handler_decoder_party.erl +++ b/apps/capi/src/capi_handler_decoder_party.erl @@ -5,7 +5,7 @@ -export([decode_shop_location/1]). -export([decode_shop_details/1]). -export([decode_contact_info/1]). --export([decode_party/1]). +-export([decode_party/2]). -export([is_blocked/1]). -export([is_suspended/1]). -export([decode_residence/1]). @@ -21,12 +21,7 @@ decode_shop_location({url, Location}) -> }. -spec decode_shop_details(capi_handler_encoder:encode_data()) -> capi_handler_decoder_utils:decode_data(). -decode_shop_details(#domain_ShopDetails{name = Name, description = Description}) -> - genlib_map:compact(#{ - <<"name">> => Name, - <<"description">> => Description - }); -decode_shop_details(#domain_Details{name = Name, description = Description}) -> +decode_shop_details(#domain_ShopConfig{name = Name, description = Description}) -> genlib_map:compact(#{ <<"name">> => Name, <<"description">> => Description @@ -60,8 +55,9 @@ decode_contact_info(#domain_ContactInfo{ <<"documentId">> => DocumentId }). --spec decode_party(capi_handler_encoder:encode_data()) -> capi_handler_decoder_utils:decode_data(). -decode_party(#domain_PartyConfig{id = PartyID, blocking = Blocking, suspension = Suspension}) -> +-spec decode_party(capi_party:party_id(), capi_handler_encoder:encode_data()) -> + capi_handler_decoder_utils:decode_data(). +decode_party(PartyID, #domain_PartyConfig{block = Blocking, suspension = Suspension}) -> #{ <<"id">> => PartyID, <<"isBlocked">> => is_blocked(Blocking), diff --git a/apps/capi/src/capi_handler_parties.erl b/apps/capi/src/capi_handler_parties.erl index ee57f41..331efeb 100644 --- a/apps/capi/src/capi_handler_parties.erl +++ b/apps/capi/src/capi_handler_parties.erl @@ -25,7 +25,7 @@ prepare('GetPartyByID' = OperationID, Req, Context) -> Process = fun() -> case capi_party:get_party(PartyID, Context) of {ok, Party} -> - DecodedParty = capi_handler_decoder_party:decode_party(Party), + DecodedParty = capi_handler_decoder_party:decode_party(PartyID, Party), {ok, {200, #{}, DecodedParty}}; {error, not_found} -> {ok, general_error(404, <<"Party not found">>)} diff --git a/apps/capi/src/capi_handler_payment_institutions.erl b/apps/capi/src/capi_handler_payment_institutions.erl index 1e3c03d..f866b6f 100644 --- a/apps/capi/src/capi_handler_payment_institutions.erl +++ b/apps/capi/src/capi_handler_payment_institutions.erl @@ -1,6 +1,5 @@ -module(capi_handler_payment_institutions). --include_lib("damsel/include/dmsl_payproc_thrift.hrl"). -include_lib("damsel/include/dmsl_domain_thrift.hrl"). -behaviour(capi_handler). @@ -44,18 +43,6 @@ prepare('GetPaymentInstitutionByRef' = OperationID, Req, Context) -> end end, {ok, #{authorize => Authorize, process => Process}}; -prepare('GetPaymentInstitutionPaymentTerms' = OperationID, Req, Context) -> - Authorize = mk_authorize_operation(OperationID, Context), - Process = fun() -> - PaymentInstitutionID = genlib:to_int(maps:get('paymentInstitutionID', Req)), - case compute_payment_institution_terms(PaymentInstitutionID, #payproc_Varset{}, Context) of - {ok, #domain_TermSet{payments = PaymentTerms}} -> - {ok, {200, #{}, decode_payment_terms(PaymentTerms)}}; - {error, #payproc_PaymentInstitutionNotFound{}} -> - {ok, general_error(404, <<"Payment institution not found">>)} - end - end, - {ok, #{authorize => Authorize, process => Process}}; prepare('GetServiceProviderByID' = OperationID, Req, Context) -> Authorize = mk_authorize_operation(OperationID, Context), Process = fun() -> @@ -113,10 +100,6 @@ check_payment_institution_residence(Residence, #domain_PaymentInstitutionObject{ }) -> ordsets:is_element(Residence, Residences). -compute_payment_institution_terms(PaymentInstitutionID, VS, Context) -> - Ref = ?PAYMENT_INSTITUTION_REF(PaymentInstitutionID), - capi_party:compute_payment_institution_terms(Ref, VS, Context). - % decode_payment_institution(#domain_PaymentInstitutionObject{ref = Ref, data = Data}) -> @@ -131,19 +114,6 @@ decode_payment_institution(#domain_PaymentInstitutionObject{ref = Ref, data = Da ] }). -decode_payment_terms(#domain_PaymentsServiceTerms{currencies = Currencies, categories = Categories}) -> - genlib_map:compact(#{ - <<"currencies">> => decode_payment_terms(fun capi_handler_decoder_utils:decode_currency/1, Currencies), - <<"categories">> => decode_payment_terms(fun capi_handler_decoder_utils:decode_category_ref/1, Categories) - }); -decode_payment_terms(undefined) -> - #{}. - -decode_payment_terms(Fun, {value, Val}) when is_list(Val) -> - [Fun(V) || V <- Val]; -decode_payment_terms(_, _) -> - undefined. - %% decode_payment_service(ID, #domain_PaymentService{} = PaymentService) -> diff --git a/apps/capi/src/capi_handler_payments.erl b/apps/capi/src/capi_handler_payments.erl index 6c51d8e..49a6ce2 100644 --- a/apps/capi/src/capi_handler_payments.erl +++ b/apps/capi/src/capi_handler_payments.erl @@ -47,8 +47,6 @@ prepare('CreatePayment' = OperationID, Req, Context) -> {ok, logic_error('invalidPartyStatus', <<"Invalid party status">>)}; {exception, #payproc_InvalidShopStatus{}} -> {ok, logic_error('invalidShopStatus', <<"Invalid shop status">>)}; - {exception, #payproc_InvalidContractStatus{}} -> - {ok, logic_error('invalidContractStatus', <<"Invalid status">>)}; {exception, #payproc_InvalidRecurrentParentPayment{}} -> {ok, logic_error('invalidRecurrentParent', <<"Specified recurrent parent is invalid">>)}; {exception, #payproc_InvoiceNotFound{}} -> @@ -277,8 +275,6 @@ prepare('CreateRefund' = OperationID, Req, Context) -> {ok, logic_error('invalidPartyStatus', <<"Invalid party status">>)}; {exception, #payproc_InvalidShopStatus{}} -> {ok, logic_error('invalidShopStatus', <<"Invalid shop status">>)}; - {exception, #payproc_InvalidContractStatus{}} -> - {ok, logic_error('invalidContractStatus', <<"Invalid status">>)}; {exception, #payproc_OperationNotPermitted{}} -> {ok, logic_error('operationNotPermitted', <<"Operation not permitted">>)}; {exception, #payproc_InvalidPaymentStatus{}} -> diff --git a/apps/capi/src/capi_handler_shops.erl b/apps/capi/src/capi_handler_shops.erl index c808680..7966f42 100644 --- a/apps/capi/src/capi_handler_shops.erl +++ b/apps/capi/src/capi_handler_shops.erl @@ -50,12 +50,14 @@ prepare('GetShopByIDForParty' = OperationID, Req, Context) -> Process = fun() -> case capi_party:get_shop(PartyID, ShopID, Context) of {ok, Shop} -> - {ok, {200, #{}, decode_shop(Shop)}}; + {ok, {200, #{}, decode_shop(ShopID, Shop)}}; {error, not_found} -> {ok, general_error(404, <<"Shop not found">>)} end end, {ok, #{authorize => Authorize, process => Process}}; +prepare('GetShopAccount' = _OperationID, _Req, _Context) -> + {error, noimpl}; prepare('ActivateShopForParty', _Req, _Context) -> {error, noimpl}; prepare('SuspendShopForParty', _Req, _Context) -> @@ -70,7 +72,7 @@ get_shops_for_party(#domain_PartyConfig{shops = ShopRefs}, Context) -> fun(ShopRef, Acc) -> case capi_domain:get_ext({shop_config, ShopRef}, capi_domain:head(), Context) of {ok, Shop} -> - [decode_shop(Shop) | Acc]; + [decode_shop(ShopRef#domain_ShopConfigRef.id, Shop) | Acc]; {error, not_found} -> Acc end @@ -90,21 +92,17 @@ restrict_shops(Shops, Restrictions) -> Shops ). -decode_shop(Shop) -> - Currency = get_shop_currency(Shop), +decode_shop(ShopID, Shop) -> genlib_map:compact(#{ - <<"id">> => Shop#domain_ShopConfig.id, - <<"createdAt">> => Shop#domain_ShopConfig.created_at, - <<"isBlocked">> => capi_handler_decoder_party:is_blocked(Shop#domain_ShopConfig.blocking), + <<"id">> => ShopID, + <<"isBlocked">> => capi_handler_decoder_party:is_blocked(Shop#domain_ShopConfig.block), <<"isSuspended">> => capi_handler_decoder_party:is_suspended(Shop#domain_ShopConfig.suspension), - <<"currency">> => Currency, + <<"currency">> => get_shop_currency(Shop#domain_ShopConfig.account), <<"categoryID">> => capi_handler_decoder_utils:decode_category_ref(Shop#domain_ShopConfig.category), - <<"details">> => capi_handler_decoder_party:decode_shop_details(Shop#domain_ShopConfig.details), + <<"details">> => capi_handler_decoder_party:decode_shop_details(Shop), <<"location">> => capi_handler_decoder_party:decode_shop_location(Shop#domain_ShopConfig.location), <<"contractID">> => genlib:to_binary(Shop#domain_ShopConfig.terms#domain_TermSetHierarchyRef.id) }). -get_shop_currency(#domain_ShopConfig{currency_configs = Configs}) when is_map(Configs) -> - %% TODO: fix it when add multi currency support - [Currency | _] = maps:keys(Configs), +get_shop_currency(#domain_ShopAccount{currency = Currency}) -> capi_handler_decoder_utils:decode_currency(Currency). diff --git a/apps/capi/src/capi_handler_utils.erl b/apps/capi/src/capi_handler_utils.erl index 6f1f4bf..0fd0308 100644 --- a/apps/capi/src/capi_handler_utils.erl +++ b/apps/capi/src/capi_handler_utils.erl @@ -295,7 +295,7 @@ emplace_token_provider_data(PaymentMethods, TokenProviderData) -> construct_token_provider_data(PartyID, ShopID, Context) -> {ok, ShopConfig} = capi_party:get_shop(PartyID, ShopID, Context), - ShopName = ShopConfig#domain_ShopConfig.details#domain_Details.name, + ShopName = ShopConfig#domain_ShopConfig.name, PiRef = ShopConfig#domain_ShopConfig.payment_institution, {ok, Pi} = capi_domain:get_payment_institution(PiRef, Context), Realm = Pi#domain_PaymentInstitution.realm, diff --git a/apps/capi/src/capi_party.erl b/apps/capi/src/capi_party.erl index c22dfc0..e273396 100644 --- a/apps/capi/src/capi_party.erl +++ b/apps/capi/src/capi_party.erl @@ -1,18 +1,15 @@ -module(capi_party). -include_lib("damsel/include/dmsl_domain_thrift.hrl"). --include_lib("damsel/include/dmsl_payproc_thrift.hrl"). -export([get_party/2]). -export([get_shop/3]). --export([compute_payment_institution_terms/3]). --type result() :: ok | {ok, woody:result()} | {error, woody_error:business_error()}. +-export_type([party_id/0]). + -type processing_context() :: capi_handler:processing_context(). -type party_id() :: party_client_thrift:party_id(). --type payment_institution_ref() :: party_client_thrift:payment_institution_ref(). --type varset() :: party_client_thrift:varset(). -type shop_id() :: party_client_thrift:shop_id(). -type party() :: dmsl_domain_thrift:'PartyConfig'(). -type shop() :: dmsl_domain_thrift:'ShopConfig'(). @@ -48,20 +45,3 @@ get_shop(PartyID, ShopID, Context) -> {error, not_found} -> {error, not_found} end. - --spec compute_payment_institution_terms( - payment_institution_ref(), - varset(), - processing_context() -) -> result(). -compute_payment_institution_terms(Ref, Varset, Context) -> - {Client, ClientContext} = client_context(Context), - party_client_thrift:compute_payment_institution_terms( - Ref, - Varset, - Client, - ClientContext - ). - -client_context(#{party_client := Client, party_client_context := ClientContext}) -> - {Client, ClientContext}. diff --git a/apps/capi/test/capi_base_api_token_tests_SUITE.erl b/apps/capi/test/capi_base_api_token_tests_SUITE.erl index 60f198e..d98c202 100644 --- a/apps/capi/test/capi_base_api_token_tests_SUITE.erl +++ b/apps/capi/test/capi_base_api_token_tests_SUITE.erl @@ -49,7 +49,6 @@ create_payment_with_changed_cost_ok_test/1, create_refund/1, create_refund_blocked_error/1, - create_refund_expired_error/1, create_partial_refund/1, create_partial_refund_without_currency/1, get_refund_by_id/1, @@ -75,7 +74,6 @@ get_category_by_ref_ok_test/1, get_payment_institutions/1, get_payment_institution_by_ref/1, - get_payment_institution_payment_terms/1, get_service_provider_by_id/1, check_no_payment_by_external_id_test/1, check_no_internal_id_for_external_id_test/1, @@ -155,7 +153,6 @@ groups() -> retrieve_refund_by_external_id_for_party_test, create_refund, create_refund_blocked_error, - create_refund_expired_error, create_partial_refund, create_partial_refund_without_currency, get_chargebacks, @@ -174,7 +171,6 @@ groups() -> get_payment_institutions, get_payment_institution_by_ref, - get_payment_institution_payment_terms, get_service_provider_by_id, get_category_by_ref_ok_test, @@ -879,33 +875,6 @@ create_refund_blocked_error(Config) -> ), {error, {400, _}} = capi_client_payments:create_refund(?config(context, Config), Req, ?STRING, ?STRING). --spec create_refund_expired_error(config()) -> _. -create_refund_expired_error(Config) -> - BenderKey = <<"bender_key">>, - Req = #{<<"reason">> => ?STRING}, - _ = capi_ct_helper:mock_services( - [ - {invoicing, fun - ('Get', _) -> - Invoice = ?PAYPROC_INVOICE, - {ok, Invoice#payproc_Invoice{payments = [?PAYPROC_PAYMENT]}}; - ('RefundPayment', {?STRING, _, _}) -> - {throwing, #payproc_InvalidContractStatus{status = {expired, #domain_ContractExpired{}}}} - end}, - {generator, fun('GenerateID', _) -> capi_ct_helper_bender:generate_id(BenderKey) end} - ], - Config - ), - _ = capi_ct_helper_bouncer:mock_assert_payment_op_ctx( - <<"CreateRefund">>, - ?STRING, - ?STRING, - ?STRING, - ?STRING, - Config - ), - {error, {400, _}} = capi_client_payments:create_refund(?config(context, Config), Req, ?STRING, ?STRING). - -spec create_partial_refund(config()) -> _. create_partial_refund(Config) -> BenderKey = <<"bender_key">>, @@ -1570,18 +1539,6 @@ get_payment_institution_by_ref(Config) -> _ = capi_ct_helper_bouncer:mock_assert_op_ctx(<<"GetPaymentInstitutionByRef">>, Config), {ok, _} = capi_client_payment_institutions:get_payment_institution_by_ref(?config(context, Config), ?INTEGER). --spec get_payment_institution_payment_terms(config()) -> _. -get_payment_institution_payment_terms(Config) -> - _ = capi_ct_helper:mock_services( - [ - {party_management, fun('ComputePaymentInstitutionTerms', _) -> {ok, ?TERM_SET} end} - ], - Config - ), - _ = capi_ct_helper_bouncer:mock_assert_op_ctx(<<"GetPaymentInstitutionPaymentTerms">>, Config), - {ok, _} = - capi_client_payment_institutions:get_payment_institution_payment_terms(?config(context, Config), ?INTEGER). - -spec get_service_provider_by_id(config()) -> _. get_service_provider_by_id(Config) -> _ = capi_ct_helper_bouncer:mock_assert_op_ctx(<<"GetServiceProviderByID">>, Config), diff --git a/apps/capi/test/capi_dummy_data.hrl b/apps/capi/test/capi_dummy_data.hrl index 246eaec..0a54b74 100644 --- a/apps/capi/test/capi_dummy_data.hrl +++ b/apps/capi/test/capi_dummy_data.hrl @@ -6,7 +6,6 @@ -include_lib("damsel/include/dmsl_payproc_thrift.hrl"). -include_lib("damsel/include/dmsl_webhooker_thrift.hrl"). -include_lib("damsel/include/dmsl_user_interaction_thrift.hrl"). --include_lib("magista_proto/include/magista_magista_thrift.hrl"). -define(RECORD_UPDATE(FieldIndex, Value, Record), erlang:setelement(FieldIndex, Record, Value)). @@ -84,6 +83,7 @@ -define(INVOICE(ID, EID, OwnerID), #domain_Invoice{ id = ID, + domain_revision = ?INTEGER, created_at = ?TIMESTAMP, status = ?INVOICE_STATUS(unpaid), due = ?TIMESTAMP, @@ -422,23 +422,19 @@ -define(SUSPENTION, {active, #domain_Active{since = ?TIMESTAMP}}). -define(SHOP(Currency), #domain_ShopConfig{ - id = ?STRING, - created_at = ?TIMESTAMP, - blocking = ?BLOCKING, + name = ?STRING, + block = ?BLOCKING, suspension = ?SUSPENTION, - details = ?SHOP_DETAILS, - location = ?SHOP_LOCATION, - category = #domain_CategoryRef{id = ?INTEGER}, - currency_configs = #{ - #domain_CurrencyRef{symbolic_code = Currency} => #domain_ShopCurrencyConfig{ - currency = #domain_CurrencyRef{symbolic_code = Currency}, - settlement = ?INTEGER, - guarantee = ?INTEGER - } - }, payment_institution = #domain_PaymentInstitutionRef{id = ?INTEGER}, terms = #domain_TermSetHierarchyRef{id = ?INTEGER}, - party_id = ?STRING + account = #domain_ShopAccount{ + currency = #domain_CurrencyRef{symbolic_code = Currency}, + settlement = ?INTEGER, + guarantee = ?INTEGER + }, + party_id = ?STRING, + location = ?SHOP_LOCATION, + category = #domain_CategoryRef{id = ?INTEGER} }). -define(SHOP, ?SHOP(?RUB)). @@ -448,23 +444,21 @@ -define(SHOP_DETAILS, #domain_Details{name = ?STRING}). -define(PARTY, #domain_PartyConfig{ - id = ?STRING, - contact_info = #domain_PartyContactInfo{registration_email = ?STRING}, - created_at = ?TIMESTAMP, - blocking = ?BLOCKING, + name = <<"PARTY">>, + block = ?BLOCKING, suspension = ?SUSPENTION, shops = [], - wallets = [] + wallets = [], + contact_info = #domain_PartyContactInfo{registration_email = ?STRING} }). -define(PARTY_WITH_SHOPS, #domain_PartyConfig{ - id = ?STRING, - contact_info = #domain_PartyContactInfo{registration_email = ?STRING}, - created_at = ?TIMESTAMP, - blocking = ?BLOCKING, + name = <<"PARTY_WITH_SHOPS">>, + block = ?BLOCKING, suspension = ?SUSPENTION, shops = [#domain_ShopConfigRef{id = ?STRING}], - wallets = [] + wallets = [], + contact_info = #domain_PartyContactInfo{registration_email = ?STRING} }). -define(ADJUSTMENT, #domain_InvoicePaymentAdjustment{ @@ -477,13 +471,6 @@ old_cash_flow_inverse = [] }). --define(PAYOUT_TOOL(ID, ToolInfo), #domain_PayoutTool{ - id = ID, - created_at = ?TIMESTAMP, - currency = #domain_CurrencyRef{symbolic_code = ?RUB}, - payout_tool_info = ToolInfo -}). - -define(PAYMENT_INSTITUTION_ACCOUNT, {payment_institution_account, #domain_PaymentInstitutionAccount{}} ). @@ -653,36 +640,6 @@ {failed, #domain_InvoicePaymentFailed{failure = {failure, #domain_Failure{code = <<"error_code">>}}}} ). --define(STAT_RESPONSE_REFUNDS, #magista_StatRefundResponse{ - refunds = [ - ?STAT_REFUND({pending, #domain_InvoicePaymentRefundPending{}}), - ?STAT_REFUND({succeeded, #domain_InvoicePaymentRefundSucceeded{}}), - ?STAT_REFUND( - {failed, #domain_InvoicePaymentRefundFailed{ - failure = {operation_timeout, #domain_OperationTimeout{}} - }} - ) - ], - continuation_token = ?STRING -}). - --define(STAT_REFUND(Status), #magista_StatRefund{ - id = ?STRING, - payment_id = ?STRING, - invoice_id = ?STRING, - owner_id = ?STRING, - shop_id = ?STRING, - status = Status, - created_at = ?TIMESTAMP, - amount = ?INTEGER, - fee = ?INTEGER, - currency_symbolic_code = ?RUB, - reason = ?STRING, - cart = ?INVOICE_CART, - external_id = ?STRING, - status_changed_at = ?TIMESTAMP -}). - -define(ALL_OBJECTS, #{ {category, #domain_CategoryRef{id = ?INTEGER}} => {category, #domain_CategoryObject{ @@ -725,8 +682,6 @@ name = ?STRING, description = ?STRING, system_account_set = {value, #domain_SystemAccountSetRef{id = ?INTEGER}}, - default_contract_template = {value, #domain_ContractTemplateRef{id = ?INTEGER}}, - providers = {value, []}, inspector = {value, #domain_InspectorRef{id = ?INTEGER}}, realm = test, residences = [rus] @@ -951,24 +906,6 @@ ])} }). --define(PAYOUT, ?PAYOUT(?PI_ACCOUNT_TOOL, ?STRING)). --define(PAYOUT(ToolID), ?PAYOUT(ToolID, ?STRING)). - --define(PAYOUT(ToolID, PartyID), #payouts_Payout{ - payout_id = ?STRING, - created_at = ?TIMESTAMP, - party_id = PartyID, - shop_id = ?STRING, - status = {paid, #payouts_PayoutPaid{}}, - cash_flow = [], - payout_tool_id = ToolID, - amount = ?INTEGER, - fee = ?INTEGER, - currency = #payouts_CurrencyRef{ - symbolic_code = ?RUB - } -}). - -define(TEST_PAYMENT_TOKEN, ?STRING). -define(TEST_PAYMENT_TOOL, ?TEST_PAYMENT_TOOL(<<"visa">>)). diff --git a/apps/capi/test/capi_idempotency_tests_SUITE.erl b/apps/capi/test/capi_idempotency_tests_SUITE.erl index 1fe38a4..d09890d 100644 --- a/apps/capi/test/capi_idempotency_tests_SUITE.erl +++ b/apps/capi/test/capi_idempotency_tests_SUITE.erl @@ -631,8 +631,7 @@ create_payment(BenderKey, Requests, Config) -> end}, {bender, fun('GenerateID', {_, _, CtxMsgPack}) -> capi_ct_helper_bender:get_internal_id(Tid, BenderKey, CtxMsgPack) - end}, - {party_management, fun('GetShop', _) -> {ok, ?SHOP} end} + end} ], Config ), diff --git a/apps/capi/test/capi_invoice_template_access_token_tests_SUITE.erl b/apps/capi/test/capi_invoice_template_access_token_tests_SUITE.erl index 4d88fd7..dd3434c 100644 --- a/apps/capi/test/capi_invoice_template_access_token_tests_SUITE.erl +++ b/apps/capi/test/capi_invoice_template_access_token_tests_SUITE.erl @@ -168,10 +168,6 @@ get_invoice_payment_methods_by_tpl_id_ok_test(Config) -> {invoice_templating, fun ('ComputeTerms', _) -> {ok, ?TERM_SET}; ('Get', _) -> {ok, ?INVOICE_TPL} - end}, - {party_management, fun - ('GetRevision', _) -> {ok, ?INTEGER}; - ('Checkout', _) -> {ok, ?PARTY} end} ], Config diff --git a/apps/capi_client/src/capi_client_payment_institutions.erl b/apps/capi_client/src/capi_client_payment_institutions.erl index a9c46a1..7961d66 100644 --- a/apps/capi_client/src/capi_client_payment_institutions.erl +++ b/apps/capi_client/src/capi_client_payment_institutions.erl @@ -3,7 +3,6 @@ -export([get_payment_institutions/1]). -export([get_payment_institutions/3]). -export([get_payment_institution_by_ref/2]). --export([get_payment_institution_payment_terms/2]). -export([get_service_provider_by_id/2]). -type context() :: capi_client_lib:context(). @@ -37,17 +36,6 @@ get_payment_institution_by_ref(Context, PaymentInstitutionRef) -> Response = swag_client_payment_institutions_api:get_payment_institution_by_ref(Url, PreparedParams, Opts), capi_client_lib:handle_response(Response). --spec get_payment_institution_payment_terms(context(), term()) -> {ok, term()} | {error, term()}. -get_payment_institution_payment_terms(Context, PaymentInstitutionID) -> - Params = #{ - binding => #{ - <<"paymentInstitutionID">> => genlib:to_list(PaymentInstitutionID) - } - }, - {Url, PreparedParams, Opts} = capi_client_lib:make_request(Context, Params), - Response = swag_client_payment_institutions_api:get_payment_institution_payment_terms(Url, PreparedParams, Opts), - capi_client_lib:handle_response(Response). - -spec get_service_provider_by_id(context(), binary()) -> {ok, term()} | {error, term()}. get_service_provider_by_id(Context, ServiceProviderID) -> Params = #{ diff --git a/config/sys.config b/config/sys.config index 7d9caf5..32052d3 100644 --- a/config/sys.config +++ b/config/sys.config @@ -86,16 +86,12 @@ {capi_woody_client, [ {services, #{ party_management => <<"http://hellgate:8022/v1/processing/partymgmt">>, - customer_management => <<"http://hellgate:8022/v1/processing/customer_management">>, invoicing => <<"http://hellgate:8022/v1/processing/invoicing">>, invoice_templating => <<"http://hellgate:8022/v1/processing/invoice_templating">>, - webhook_manager => <<"http://hooker:8022/hook">>, - merchant_stat => <<"http://magista:8022/stat">>, - payouts => <<"http://payouter:8022/reports">> + webhook_manager => <<"http://hooker:8022/hook">> }}, {service_deadlines, #{ - party_management => 5000, % milliseconds - customer_management => 10000 + party_management => 5000 % milliseconds }}, {service_retries, #{ party_management => #{ diff --git a/rebar.config b/rebar.config index 7c266ba..aa6e2a8 100644 --- a/rebar.config +++ b/rebar.config @@ -36,10 +36,10 @@ {cowboy_draining_server, {git, "https://github.com/valitydev/cowboy_draining_server.git", {branch, "master"}}}, {woody, {git, "https://github.com/valitydev/woody_erlang.git", {tag, "v1.1.0"}}}, {woody_user_identity, {git, "https://github.com/valitydev/woody_erlang_user_identity.git", {tag, "v1.1.0"}}}, - {damsel, {git, "https://github.com/valitydev/damsel.git", {tag, "v2.2.0"}}}, + {damsel, {git, "https://github.com/valitydev/damsel.git", {tag, "v2.2.11"}}}, {bender_proto, {git, "https://github.com/valitydev/bender-proto.git", {branch, "master"}}}, {bender_client, {git, "https://github.com/valitydev/bender-client-erlang.git", {tag, "v1.1.0"}}}, - {dmt_client, {git, "https://github.com/valitydev/dmt_client.git", {tag, "v2.0.0"}}}, + {dmt_client, {git, "https://github.com/valitydev/dmt_client.git", {tag, "v2.0.2"}}}, {cowboy_cors, {git, "https://github.com/valitydev/cowboy_cors.git", {branch, "master"}}}, {cowboy_access_log, {git, "https://github.com/valitydev/cowboy_access_log.git", {branch, "master"}}}, {payproc_errors, {git, "https://github.com/valitydev/payproc-errors-erlang.git", {branch, "master"}}}, @@ -49,10 +49,8 @@ {bouncer_proto, {git, "https://github.com/valitydev/bouncer-proto.git", {branch, master}}}, {bouncer_client, {git, "https://github.com/valitydev/bouncer-client-erlang.git", {tag, "v1.1.0"}}}, {token_keeper_client, {git, "https://github.com/valitydev/token-keeper-client.git", {tag, "v1.1.0"}}}, - {party_client, {git, "https://github.com/valitydev/party-client-erlang.git", {branch, master}}}, - {payout_manager_proto, {git, "https://github.com/valitydev/payout-manager-proto.git", {branch, master}}}, + {party_client, {git, "https://github.com/valitydev/party-client-erlang.git", {tag, "v2.0.1"}}}, {feat, {git, "https://github.com/valitydev/feat.git", {branch, master}}}, - {magista_proto, {git, "https://github.com/valitydev/magista-proto.git", {branch, master}}}, %% Libraries generated with swagger-codegen-erlang from valitydev/swag-payments {swag_server, {git, "https://github.com/valitydev/swag-payments", {branch, "release/erlang/server/epic-v3"}}}, {swag_client, {git, "https://github.com/valitydev/swag-payments", {branch, "release/erlang/client/epic-v3"}}}, @@ -116,7 +114,7 @@ ]} ]}, {test, [ - {dialyzer, [{plt_extra_apps, [eunit, common_test, runtime_tools, bender_proto, payout_manager_proto]}]} + {dialyzer, [{plt_extra_apps, [eunit, common_test, runtime_tools, bender_proto]}]} ]} ]}. diff --git a/rebar.lock b/rebar.lock index 7b9efdb..7a4598b 100644 --- a/rebar.lock +++ b/rebar.lock @@ -41,16 +41,12 @@ {<<"ctx">>,{pkg,<<"ctx">>,<<"0.6.0">>},2}, {<<"damsel">>, {git,"https://github.com/valitydev/damsel.git", - {ref,"ba7414811590859d058817b8f22d2e9c22f627f8"}}, + {ref,"ff9b01f552f922ce4a16710827aa872325dbe5a9"}}, 0}, {<<"dmt_client">>, {git,"https://github.com/valitydev/dmt_client.git", - {ref,"fcfb028a041149caeebec8d9cef469c8cdbbc63e"}}, + {ref,"fff521d3d50b48e3c6b628fe4796b3628aedc6b7"}}, 0}, - {<<"dmt_core">>, - {git,"https://github.com/valitydev/dmt-core.git", - {ref,"19d8f57198f2cbe5b64aa4a923ba32774e505503"}}, - 1}, {<<"email_validator">>,{pkg,<<"email_validator">>,<<"1.1.0">>},1}, {<<"erl_health">>, {git,"https://github.com/valitydev/erlang-health.git", @@ -86,10 +82,6 @@ {git,"https://github.com/valitydev/lechiffre.git", {ref,"3f9c136ae2f70b9830f46c990e00d75dacfd73d9"}}, 0}, - {<<"magista_proto">>, - {git,"https://github.com/valitydev/magista-proto.git", - {ref,"e49ad10f49d50c746f7017412ba5409411731e89"}}, - 0}, {<<"metrics">>,{pkg,<<"metrics">>,<<"1.0.1">>},2}, {<<"mimerl">>,{pkg,<<"mimerl">>,<<"1.4.0">>},2}, {<<"msgpack_proto">>, @@ -108,11 +100,7 @@ {<<"parse_trans">>,{pkg,<<"parse_trans">>,<<"3.4.1">>},1}, {<<"party_client">>, {git,"https://github.com/valitydev/party-client-erlang.git", - {ref,"b10b102673d899f6661e0c1a9e70f04ebddc9263"}}, - 0}, - {<<"payout_manager_proto">>, - {git,"https://github.com/valitydev/payout-manager-proto.git", - {ref,"eb4091aff7c11c6c825cbe4b43ab44250d00a09a"}}, + {ref,"88cb5a9b5abd9bb437222de168bba096edd10882"}}, 0}, {<<"payproc_errors">>, {git,"https://github.com/valitydev/payproc-errors-erlang.git", @@ -134,11 +122,11 @@ {<<"ssl_verify_fun">>,{pkg,<<"ssl_verify_fun">>,<<"1.1.7">>},2}, {<<"swag_client">>, {git,"https://github.com/valitydev/swag-payments", - {ref,"8459eb26140bbd3a831cff7a79fe94f83c5911ce"}}, + {ref,"7fe8ac4c0dfe40cb1341a56238157119a1603187"}}, 0}, {<<"swag_server">>, {git,"https://github.com/valitydev/swag-payments", - {ref,"a9ab04934b9b4ec14fd3e5ffc1927220225d680a"}}, + {ref,"8f261e1e6371c4b6e15646e01ce10052b719bcad"}}, 0}, {<<"thrift">>, {git,"https://github.com/valitydev/thrift_erlang.git", From 92e192ab1924d578f18fb06d2fde2c8ccd0bc8b8 Mon Sep 17 00:00:00 2001 From: Aleksey Kashapov Date: Tue, 26 Aug 2025 16:21:26 +0300 Subject: [PATCH 5/7] Bumps dmt protocol 2.2.12 --- apps/capi/src/capi_allocation.erl | 22 +++++----- apps/capi/src/capi_bender.erl | 2 +- apps/capi/src/capi_bouncer_context.erl | 18 +++++--- apps/capi/src/capi_domain.erl | 27 ++++++++++++ .../src/capi_handler_decoder_invoicing.erl | 2 +- .../src/capi_handler_invoice_templates.erl | 8 ++-- apps/capi/src/capi_handler_invoices.erl | 4 +- apps/capi/src/capi_handler_payments.erl | 6 +-- apps/capi/src/capi_handler_shops.erl | 35 +++++++-------- apps/capi/src/capi_handler_utils.erl | 16 +++---- apps/capi/src/capi_handler_webhooks.erl | 16 ++++--- apps/capi/src/capi_merchant_id.erl | 15 ++++--- apps/capi/src/capi_party.erl | 29 +++++++++---- .../test/capi_base_api_token_tests_SUITE.erl | 15 ++++--- apps/capi/test/capi_ct_helper.erl | 43 ++++++++++++++++--- apps/capi/test/capi_dummy_data.hrl | 26 +++++------ apps/capi_client/src/capi_client_webhooks.erl | 2 +- rebar.config | 6 +-- rebar.lock | 6 +-- 19 files changed, 186 insertions(+), 112 deletions(-) diff --git a/apps/capi/src/capi_allocation.erl b/apps/capi/src/capi_allocation.erl index e1dea68..cf9b4c9 100644 --- a/apps/capi/src/capi_allocation.erl +++ b/apps/capi/src/capi_allocation.erl @@ -32,9 +32,9 @@ transaction_error(#payproc_AllocationInvalidTransaction{reason = Reason, transac ShopID = case Transaction of {transaction, #domain_AllocationTransaction{target = {shop, Target}}} -> - Target#domain_AllocationTransactionTargetShop.shop_id; + Target#domain_AllocationTransactionTargetShop.shop_ref#domain_ShopConfigRef.id; {transaction_prototype, #domain_AllocationTransactionPrototype{target = {shop, Target}}} -> - Target#domain_AllocationTransactionTargetShop.shop_id + Target#domain_AllocationTransactionTargetShop.shop_ref#domain_ShopConfigRef.id end, Message = io_lib:format("Invalid allocation transaction with shop_id \"~ts\" and error \"~ts\"", [ShopID, Reason]), genlib:to_binary(Message). @@ -56,8 +56,8 @@ encode_transaction(PartyID, Transaction) -> encode_target(PartyID, #{<<"allocationTargetType">> := <<"AllocationTargetShop">>} = Target) -> {shop, #domain_AllocationTransactionTargetShop{ - owner_id = PartyID, - shop_id = maps:get(<<"shopID">>, Target) + party_ref = #domain_PartyConfigRef{id = PartyID}, + shop_ref = #domain_ShopConfigRef{id = maps:get(<<"shopID">>, Target)} }}. encode_details(#{<<"cart">> := _Cart} = Transaction) -> @@ -123,7 +123,7 @@ decode_transaction(Transaction) -> decode_target({shop, AllocationShop}) -> #{ <<"allocationTargetType">> => <<"AllocationTargetShop">>, - <<"shopID">> => AllocationShop#domain_AllocationTransactionTargetShop.shop_id + <<"shopID">> => AllocationShop#domain_AllocationTransactionTargetShop.shop_ref#domain_ShopConfigRef.id }. decode_details(undefined) -> @@ -239,8 +239,8 @@ encode_test() -> #domain_AllocationTransactionPrototype{ target = {shop, #domain_AllocationTransactionTargetShop{ - owner_id = <<"partyID">>, - shop_id = <<"shopID1">> + party_ref = #domain_PartyConfigRef{id = <<"partyID">>}, + shop_ref = #domain_ShopConfigRef{id = <<"shopID1">>} }}, body = {total, #domain_AllocationTransactionPrototypeBodyTotal{ @@ -285,15 +285,15 @@ decode_test() -> id = <<"0">>, target = {shop, #domain_AllocationTransactionTargetShop{ - owner_id = <<"partyID1">>, - shop_id = <<"shopID1">> + party_ref = #domain_PartyConfigRef{id = <<"partyID1">>}, + shop_ref = #domain_ShopConfigRef{id = <<"shopID1">>} }}, amount = make_cash(32), body = #domain_AllocationTransactionBodyTotal{ fee_target = {shop, #domain_AllocationTransactionTargetShop{ - owner_id = <<"partyID2">>, - shop_id = <<"shopID2">> + party_ref = #domain_PartyConfigRef{id = <<"partyID2">>}, + shop_ref = #domain_ShopConfigRef{id = <<"shopID2">>} }}, total = make_cash(16), fee_amount = make_cash(8), diff --git a/apps/capi/src/capi_bender.erl b/apps/capi/src/capi_bender.erl index f1cfad4..88dbd11 100644 --- a/apps/capi/src/capi_bender.erl +++ b/apps/capi/src/capi_bender.erl @@ -5,7 +5,7 @@ -type id() :: binary(). -type idempotent_key_prefix() :: binary() | atom(). -type external_id() :: binary(). --type issuer_id() :: dmsl_domain_thrift:'PartyID'(). +-type issuer_id() :: dmsl_base_thrift:'ID'(). -type idempotent_key() :: binary(). -type idempotent_key_params() :: {idempotent_key_prefix(), issuer_id(), external_id() | undefined}. diff --git a/apps/capi/src/capi_bouncer_context.erl b/apps/capi/src/capi_bouncer_context.erl index 96a37d2..81de8f9 100644 --- a/apps/capi/src/capi_bouncer_context.erl +++ b/apps/capi/src/capi_bouncer_context.erl @@ -135,8 +135,8 @@ build_invoice_ctx(Invoice, _WoodyCtx) -> build_invoice_ctx(#payproc_Invoice{invoice = Invoice, payments = Payments}) -> #ctx_v1_Invoice{ id = Invoice#domain_Invoice.id, - party = build_entity(Invoice#domain_Invoice.owner_id), - shop = build_entity(Invoice#domain_Invoice.shop_id), + party = build_entity(Invoice#domain_Invoice.party_ref#domain_PartyConfigRef.id), + shop = build_entity(Invoice#domain_Invoice.shop_ref#domain_ShopConfigRef.id), payments = build_set(lists:map(fun build_payment_ctx/1, Payments)) }. @@ -160,10 +160,12 @@ build_invoice_template_ctx(ID, WoodyCtx) when is_binary(ID) -> build_invoice_template_ctx(InvoiceTemplate, _WoodyCtx) -> build_invoice_template_ctx(InvoiceTemplate). -build_invoice_template_ctx(#domain_InvoiceTemplate{id = ID, owner_id = OwnerID, shop_id = ShopID}) -> +build_invoice_template_ctx(#domain_InvoiceTemplate{ + id = ID, party_ref = #domain_PartyConfigRef{id = PartyID}, shop_ref = #domain_ShopConfigRef{id = ShopID} +}) -> #ctx_v1_InvoiceTemplate{ id = ID, - party = build_entity(OwnerID), + party = build_entity(PartyID), shop = build_entity(ShopID) }. @@ -174,7 +176,11 @@ build_webhook_ctx(ID, WoodyCtx) when is_integer(ID) -> build_webhook_ctx(Webhook, _WoodyCtx) -> build_webhook_ctx(Webhook). -build_webhook_ctx(#webhooker_Webhook{id = ID, party_id = PartyID, event_filter = Filter}) -> +build_webhook_ctx(#webhooker_Webhook{ + id = ID, + party_ref = #domain_PartyConfigRef{id = PartyID}, + event_filter = Filter +}) -> #ctx_v1_Webhook{ id = integer_to_binary(ID), party = build_entity(PartyID), @@ -187,7 +193,7 @@ build_webhook_filter({Type, Filter}) -> #ctx_v1_WebhookFilter{topic = erlang:atom_to_binary(Type, utf8)} ). -build_webhook_filter_details(#webhooker_InvoiceEventFilter{shop_id = ShopID}, Ctx) -> +build_webhook_filter_details(#webhooker_InvoiceEventFilter{shop_ref = #domain_ShopConfigRef{id = ShopID}}, Ctx) -> Ctx#ctx_v1_WebhookFilter{shop = 'maybe'(ShopID, fun build_entity/1)}. %% diff --git a/apps/capi/src/capi_domain.erl b/apps/capi/src/capi_domain.erl index 22ab95d..22fb3e6 100644 --- a/apps/capi/src/capi_domain.erl +++ b/apps/capi/src/capi_domain.erl @@ -10,6 +10,7 @@ -export([get/2]). -export([get/3]). -export([get_ext/3]). +-export([get_with_related/3]). -export([get_objects_by_type/2]). -export([encode_enum/2]). -export([encode_enum/3]). @@ -115,6 +116,32 @@ get_ext(Ref, Revision, Context) -> extract_data({_Tag, {_Name, _Ref, Data}}) -> Data. +-spec get_with_related(ref(), revision(), processing_context() | undefined) -> + { + ok, + dmt_client:domain_object(), + ReferencedBy :: [dmt_client:domain_object()], + ReferencesTo :: [dmt_client:domain_object()] + } + | {error, not_found}. +get_with_related(Ref, Revision, Context) -> + try + Opts = make_opts(Context), + #domain_conf_v2_VersionedObjectWithReferences{ + object = #domain_conf_v2_VersionedObject{object = Object}, + referenced_by = ReferencedBy, + references_to = ReferencesTo + } = + dmt_client:checkout_object_with_references(Revision, Ref, Opts), + Unwrapper = fun(#domain_conf_v2_VersionedObject{object = O}) -> O end, + {ok, Object, lists:map(Unwrapper, ReferencedBy), lists:map(Unwrapper, ReferencesTo)} + catch + error:version_not_found -> + {error, not_found}; + throw:#domain_conf_v2_ObjectNotFound{} -> + {error, not_found} + end. + -spec encode_enum(Type :: atom(), binary()) -> {ok, atom()} | {error, unknown_atom | unknown_variant}. encode_enum(Type, Binary) -> encode_enum(dmsl_domain_thrift, Type, Binary). diff --git a/apps/capi/src/capi_handler_decoder_invoicing.erl b/apps/capi/src/capi_handler_decoder_invoicing.erl index 43dc85d..a3b3412 100644 --- a/apps/capi/src/capi_handler_decoder_invoicing.erl +++ b/apps/capi/src/capi_handler_decoder_invoicing.erl @@ -480,7 +480,7 @@ decode_invoice(Invoice) -> #{ <<"id">> => Invoice#domain_Invoice.id, <<"externalID">> => Invoice#domain_Invoice.external_id, - <<"shopID">> => Invoice#domain_Invoice.shop_id, + <<"shopID">> => Invoice#domain_Invoice.shop_ref#domain_ShopConfigRef.id, <<"createdAt">> => Invoice#domain_Invoice.created_at, <<"dueDate">> => Invoice#domain_Invoice.due, <<"amount">> => Amount, diff --git a/apps/capi/src/capi_handler_invoice_templates.erl b/apps/capi/src/capi_handler_invoice_templates.erl index 910579d..68f221c 100644 --- a/apps/capi/src/capi_handler_invoice_templates.erl +++ b/apps/capi/src/capi_handler_invoice_templates.erl @@ -153,7 +153,7 @@ prepare('CreateInvoiceWithTemplate' = OperationID, Req, Context) -> Process = fun() -> capi_handler:respond_if_undefined(InvoiceTpl, general_error(404, <<"Invoice template not found">>)), InvoiceParams = maps:get('InvoiceParamsWithTemplate', Req), - PartyID = InvoiceTpl#domain_InvoiceTemplate.owner_id, + PartyID = InvoiceTpl#domain_InvoiceTemplate.party_ref#domain_PartyConfigRef.id, try create_invoice(PartyID, InvoiceTplID, InvoiceParams, Context, OperationID) of {ok, #'payproc_Invoice'{invoice = Invoice}} -> {ok, {201, #{}, capi_handler_decoder_invoicing:make_invoice_and_token(Invoice, Context)}}; @@ -251,8 +251,8 @@ encode_invoice_tpl_create_params(InvoiceTemplateID, PartyID, Params) -> Product = get_product_from_tpl_details(Details), #payproc_InvoiceTemplateCreateParams{ template_id = InvoiceTemplateID, - party_id = PartyID, - shop_id = genlib_map:get(<<"shopID">>, Params), + party_id = #domain_PartyConfigRef{id = PartyID}, + shop_id = #domain_ShopConfigRef{id = genlib_map:get(<<"shopID">>, Params)}, invoice_lifetime = encode_lifetime(Params), product = Product, name = genlib_map:get(<<"name">>, Params), @@ -372,7 +372,7 @@ decode_invoice_tpl(InvoiceTpl) -> #domain_LifetimeInterval{days = DD, months = MM, years = YY} = InvoiceTpl#domain_InvoiceTemplate.invoice_lifetime, genlib_map:compact(#{ <<"id">> => InvoiceTpl#domain_InvoiceTemplate.id, - <<"shopID">> => InvoiceTpl#domain_InvoiceTemplate.shop_id, + <<"shopID">> => InvoiceTpl#domain_InvoiceTemplate.shop_ref#domain_ShopConfigRef.id, <<"name">> => InvoiceTpl#domain_InvoiceTemplate.name, <<"description">> => InvoiceTpl#domain_InvoiceTemplate.description, <<"createdAt">> => InvoiceTpl#domain_InvoiceTemplate.created_at, diff --git a/apps/capi/src/capi_handler_invoices.erl b/apps/capi/src/capi_handler_invoices.erl index e139821..aa7bbe2 100644 --- a/apps/capi/src/capi_handler_invoices.erl +++ b/apps/capi/src/capi_handler_invoices.erl @@ -279,12 +279,12 @@ encode_invoice_params(ID, PartyID, InvoiceParams) -> Allocation = genlib_map:get(<<"allocation">>, InvoiceParams), #payproc_InvoiceParams{ id = ID, - party_id = PartyID, + party_id = #domain_PartyConfigRef{id = PartyID}, details = encode_invoice_details(InvoiceParams), cost = encode_invoice_cost(Amount, Currency, Cart), due = capi_handler_utils:get_time(<<"dueDate">>, InvoiceParams), context = capi_handler_encoder:encode_invoice_context(InvoiceParams), - shop_id = genlib_map:get(<<"shopID">>, InvoiceParams), + shop_id = #domain_ShopConfigRef{id = genlib_map:get(<<"shopID">>, InvoiceParams)}, external_id = genlib_map:get(<<"externalID">>, InvoiceParams, undefined), client_info = encode_client_info(ClientInfo), allocation = capi_allocation:encode(Allocation, PartyID), diff --git a/apps/capi/src/capi_handler_payments.erl b/apps/capi/src/capi_handler_payments.erl index 49a6ce2..6da3c91 100644 --- a/apps/capi/src/capi_handler_payments.erl +++ b/apps/capi/src/capi_handler_payments.erl @@ -143,7 +143,7 @@ prepare('CapturePayment' = OperationID, Req, Context) -> InvoiceID = maps:get('invoiceID', Req), PaymentID = maps:get('paymentID', Req), Invoice = get_invoice_by_id(InvoiceID, Context), - PartyID = Invoice#payproc_Invoice.invoice#domain_Invoice.owner_id, + PartyID = Invoice#payproc_Invoice.invoice#domain_Invoice.party_ref#domain_PartyConfigRef.id, Authorize = fun() -> Prototypes = [ {operation, #{id => OperationID, invoice => InvoiceID, payment => PaymentID}}, @@ -252,7 +252,7 @@ prepare('CreateRefund' = OperationID, Req, Context) -> PaymentID = maps:get('paymentID', Req), RefundParams = maps:get('RefundParams', Req), Invoice = get_invoice_by_id(InvoiceID, Context), - PartyID = Invoice#payproc_Invoice.invoice#domain_Invoice.owner_id, + PartyID = Invoice#payproc_Invoice.invoice#domain_Invoice.party_ref#domain_PartyConfigRef.id, Authorize = fun() -> Prototypes = [ {operation, #{id => OperationID, invoice => InvoiceID, payment => PaymentID}}, @@ -489,7 +489,7 @@ create_payment(Invoice, PaymentParams, Context, OperationID) -> create_payment_id(Invoice, PaymentParams0, Context, OperationID, PaymentToolThrift) -> InvoiceID = Invoice#domain_Invoice.id, - PartyID = Invoice#domain_Invoice.owner_id, + PartyID = Invoice#domain_Invoice.party_ref#domain_PartyConfigRef.id, Payer = maps:get(<<"payer">>, PaymentParams0), PaymentTool = capi_utils:'maybe'(PaymentToolThrift, fun capi_handler_decoder_invoicing:decode_payment_tool/1), PaymentParams = PaymentParams0#{ diff --git a/apps/capi/src/capi_handler_shops.erl b/apps/capi/src/capi_handler_shops.erl index 7966f42..b2fbea7 100644 --- a/apps/capi/src/capi_handler_shops.erl +++ b/apps/capi/src/capi_handler_shops.erl @@ -21,18 +21,16 @@ prepare('GetShopsForParty' = OperationID, Req, Context) -> {ok, capi_auth:authorize_operation(Prototypes, Context)} end, Process = fun() -> - case capi_party:get_party(PartyID, Context) of - {ok, Party} -> - Shops = get_shops_for_party(Party, Context), + case get_shops_for_party(PartyID, Context) of + {ok, Shops} -> {ok, {200, #{}, Shops}}; {error, not_found} -> {ok, general_error(404, <<"Party not found">>)} end end, ProcessRestricted = fun(Restrictions) -> - case capi_party:get_party(PartyID, Context) of - {ok, Party} -> - Shops = get_shops_for_party(Party, Context), + case get_shops_for_party(PartyID, Context) of + {ok, Shops} -> RestrictedShops = restrict_shops(Shops, Restrictions), {ok, {200, #{}, RestrictedShops}}; {error, not_found} -> @@ -67,20 +65,17 @@ prepare(_OperationID, _Req, _Context) -> %% -get_shops_for_party(#domain_PartyConfig{shops = ShopRefs}, Context) -> - Shops = lists:foldl( - fun(ShopRef, Acc) -> - case capi_domain:get_ext({shop_config, ShopRef}, capi_domain:head(), Context) of - {ok, Shop} -> - [decode_shop(ShopRef#domain_ShopConfigRef.id, Shop) | Acc]; - {error, not_found} -> - Acc - end - end, - [], - ShopRefs - ), - lists:reverse(Shops). +get_shops_for_party(PartyID, Context) -> + case capi_party:get_shops(PartyID, Context) of + {ok, ShopsWithIDs} -> + {ok, + lists:map( + fun({ShopID, Shop}) -> decode_shop(ShopID, Shop) end, + ShopsWithIDs + )}; + {error, not_found} -> + {error, not_found} + end. restrict_shops(Shops, Restrictions) -> RestrictedShopIDs = capi_bouncer_restrictions:get_restricted_shop_ids(Restrictions), diff --git a/apps/capi/src/capi_handler_utils.erl b/apps/capi/src/capi_handler_utils.erl index 0fd0308..5f15b5c 100644 --- a/apps/capi/src/capi_handler_utils.erl +++ b/apps/capi/src/capi_handler_utils.erl @@ -121,16 +121,16 @@ get_party_id(Context) -> -spec issue_access_token(token_source(), processing_context()) -> map(). issue_access_token(#domain_Invoice{} = Invoice, ProcessingContext) -> TokenSpec = #{ - party => Invoice#domain_Invoice.owner_id, + party => Invoice#domain_Invoice.party_ref#domain_PartyConfigRef.id, scope => {invoice, Invoice#domain_Invoice.id}, - shop => Invoice#domain_Invoice.shop_id + shop => Invoice#domain_Invoice.shop_ref#domain_ShopConfigRef.id }, issue_access_token(TokenSpec, ProcessingContext); issue_access_token(#domain_InvoiceTemplate{} = InvoiceTpl, ProcessingContext) -> TokenSpec = #{ - party => InvoiceTpl#domain_InvoiceTemplate.owner_id, + party => InvoiceTpl#domain_InvoiceTemplate.party_ref#domain_PartyConfigRef.id, scope => {invoice_template, InvoiceTpl#domain_InvoiceTemplate.id}, - shop => InvoiceTpl#domain_InvoiceTemplate.shop_id + shop => InvoiceTpl#domain_InvoiceTemplate.shop_ref#domain_ShopConfigRef.id }, issue_access_token(TokenSpec, ProcessingContext); issue_access_token(TokenSpec, ProcessingContext) -> @@ -269,16 +269,16 @@ run_if_party_accessible(UserID, PartyID, Fun) -> -spec emplace_token_provider_data(entity(), list(), processing_context()) -> list(). emplace_token_provider_data(#domain_Invoice{} = Invoice, PaymentMethods, Context) -> InvoiceID = Invoice#domain_Invoice.id, - PartyID = Invoice#domain_Invoice.owner_id, - ShopID = Invoice#domain_Invoice.shop_id, + PartyID = Invoice#domain_Invoice.party_ref#domain_PartyConfigRef.id, + ShopID = Invoice#domain_Invoice.shop_ref#domain_ShopConfigRef.id, TokenProviderData = maps:merge( #{<<"orderID">> => InvoiceID}, construct_token_provider_data(PartyID, ShopID, Context) ), emplace_token_provider_data(PaymentMethods, TokenProviderData); emplace_token_provider_data(#domain_InvoiceTemplate{} = InvoiceTemplate, PaymentMethods, Context) -> - PartyID = InvoiceTemplate#domain_InvoiceTemplate.owner_id, - ShopID = InvoiceTemplate#domain_InvoiceTemplate.shop_id, + PartyID = InvoiceTemplate#domain_InvoiceTemplate.party_ref#domain_PartyConfigRef.id, + ShopID = InvoiceTemplate#domain_InvoiceTemplate.shop_ref#domain_ShopConfigRef.id, TokenProviderData = construct_token_provider_data(PartyID, ShopID, Context), emplace_token_provider_data(PaymentMethods, TokenProviderData). diff --git a/apps/capi/src/capi_handler_webhooks.erl b/apps/capi/src/capi_handler_webhooks.erl index 624016c..3963822 100644 --- a/apps/capi/src/capi_handler_webhooks.erl +++ b/apps/capi/src/capi_handler_webhooks.erl @@ -1,7 +1,7 @@ -module(capi_handler_webhooks). -include_lib("damsel/include/dmsl_webhooker_thrift.hrl"). --include_lib("damsel/include/dmsl_payproc_thrift.hrl"). +-include_lib("damsel/include/dmsl_domain_thrift.hrl"). -behaviour(capi_handler). @@ -50,7 +50,9 @@ prepare(OperationID, #{'partyID' := PartyID}, Context) when end, Process = fun() -> Webhooks = capi_utils:unwrap( - capi_handler_utils:service_call({webhook_manager, 'GetList', {PartyID}}, Context) + capi_handler_utils:service_call( + {webhook_manager, 'GetList', {#domain_PartyConfigRef{id = PartyID}}}, Context + ) ), {ok, {200, #{}, [decode_webhook(V) || V <- Webhooks]}} end, @@ -126,7 +128,7 @@ prepare(_OperationID, _Req, _Context) -> validate_webhook_params(#webhooker_WebhookParams{event_filter = EventFilter}) -> validate_event_filter(EventFilter). -validate_event_filter({invoice, #webhooker_InvoiceEventFilter{shop_id = ShopID}}) -> +validate_event_filter({invoice, #webhooker_InvoiceEventFilter{shop_ref = #domain_ShopConfigRef{id = ShopID}}}) -> validate_event_filter_shop(ShopID). validate_event_filter_shop(ShopID) when ShopID /= undefined -> @@ -160,14 +162,14 @@ delete_webhook(WebhookID, Context) -> encode_webhook_params(PartyID, #{<<"scope">> := Scope, <<"url">> := URL}) -> #webhooker_WebhookParams{ - party_id = PartyID, + party_ref = #domain_PartyConfigRef{id = PartyID}, url = URL, event_filter = encode_webhook_scope(Scope) }. encode_webhook_scope(#{<<"topic">> := <<"InvoicesTopic">>, <<"shopID">> := ShopID, <<"eventTypes">> := EventTypes}) -> {invoice, #webhooker_InvoiceEventFilter{ - shop_id = ShopID, + shop_ref = #domain_ShopConfigRef{id = ShopID}, types = ordsets:from_list([encode_invoice_event_type(V) || V <- EventTypes]) }}. @@ -239,7 +241,9 @@ decode_webhook(Hook) -> <<"publicKey">> => Hook#webhooker_Webhook.pub_key }. -decode_event_filter({invoice, #webhooker_InvoiceEventFilter{shop_id = ShopID, types = EventTypes}}) -> +decode_event_filter( + {invoice, #webhooker_InvoiceEventFilter{shop_ref = #domain_ShopConfigRef{id = ShopID}, types = EventTypes}} +) -> genlib_map:compact(#{ <<"topic">> => <<"InvoicesTopic">>, <<"shopID">> => ShopID, diff --git a/apps/capi/src/capi_merchant_id.erl b/apps/capi/src/capi_merchant_id.erl index b207048..bcf5d41 100644 --- a/apps/capi/src/capi_merchant_id.erl +++ b/apps/capi/src/capi_merchant_id.erl @@ -1,8 +1,9 @@ -module(capi_merchant_id). -include_lib("damsel/include/dmsl_paytool_provider_thrift.hrl"). +-include_lib("damsel/include/dmsl_domain_thrift.hrl"). --type party_id() :: dmsl_domain_thrift:'PartyID'(). +-type party_id() :: dmsl_base_thrift:'ID'(). -type shop_id() :: dmsl_domain_thrift:'ShopID'(). -type realm() :: dmsl_domain_thrift:'PaymentInstitutionRealm'(). -type merchant_data() :: dmsl_paytool_provider_thrift:'MerchantID'(). @@ -18,11 +19,11 @@ -define(THRIFT_TYPE, {struct, struct, {dmsl_paytool_provider_thrift, 'MerchantID'}}). -spec party_id(merchant_data()) -> party_id(). -party_id(#paytool_provider_MerchantID{party_id = PartyID}) -> +party_id(#paytool_provider_MerchantID{party_ref = #domain_PartyConfigRef{id = PartyID}}) -> PartyID. -spec shop_id(merchant_data()) -> shop_id(). -shop_id(#paytool_provider_MerchantID{shop_id = ShopID}) -> +shop_id(#paytool_provider_MerchantID{shop_ref = #domain_ShopConfigRef{id = ShopID}}) -> ShopID. -spec realm(merchant_data()) -> realm() | undefined. @@ -32,8 +33,8 @@ realm(#paytool_provider_MerchantID{realm = Realm}) -> -spec encode(realm(), party_id(), shop_id()) -> merchant_id(). encode(Realm, PartyID, ShopID) -> encode(#paytool_provider_MerchantID{ - party_id = PartyID, - shop_id = ShopID, + party_ref = #domain_PartyConfigRef{id = PartyID}, + shop_ref = #domain_ShopConfigRef{id = ShopID}, realm = Realm }). @@ -74,8 +75,8 @@ merchant_id_test_() -> MerchantID = encode(Realm, PartyID, ShopID), MerchantData = decode(MerchantID), [ - ?_assertEqual(undefined, decode(<<"*CwABAAAAIXBhcnR5LWE0ZW">>)), - ?_assertEqual(undefined, decode(<<"CwABAAAAIXBhcnR5LWE0ZW">>)), + ?_assertEqual(undefined, decode(<<"*DAABCwABAAAAIXBhcnR5LW">>)), + ?_assertEqual(undefined, decode(<<"DAABCwABAAAAIXBhcnR5LW">>)), ?_assertNotEqual(undefined, MerchantData), ?_assertEqual(PartyID, party_id(MerchantData)), ?_assertEqual(ShopID, shop_id(MerchantData)), diff --git a/apps/capi/src/capi_party.erl b/apps/capi/src/capi_party.erl index e273396..976eb22 100644 --- a/apps/capi/src/capi_party.erl +++ b/apps/capi/src/capi_party.erl @@ -4,6 +4,7 @@ -export([get_party/2]). -export([get_shop/3]). +-export([get_shops/2]). -export_type([party_id/0]). @@ -33,15 +34,25 @@ checkout(PartyID, Revision, Context) -> -spec get_shop(party_id(), shop_id(), processing_context()) -> {ok, shop()} | {error, not_found}. get_shop(PartyID, ShopID, Context) -> - case get_party(PartyID, Context) of - {ok, #domain_PartyConfig{shops = ShopRefs}} -> - Ref = #domain_ShopConfigRef{id = ShopID}, - case lists:member(Ref, ShopRefs) of - true -> - capi_domain:get_ext({shop_config, Ref}, capi_domain:head(), Context); - false -> - {error, not_found} - end; + PartyRef = #domain_PartyConfigRef{id = PartyID}, + ShopRef = #domain_ShopConfigRef{id = ShopID}, + case capi_domain:get_ext({shop_config, ShopRef}, get_party_revision(), Context) of + {ok, #domain_ShopConfig{party_ref = PartyRef} = Shop} -> {ok, Shop}; + _ -> {error, not_found} + end. + +-spec get_shops(party_id(), processing_context()) -> {ok, [{shop_id(), shop()}]} | {error, not_found}. +get_shops(PartyID, Context) -> + PartyRef = #domain_PartyConfigRef{id = PartyID}, + case capi_domain:get_with_related({party_config, PartyRef}, get_party_revision(), Context) of + {ok, _, ReferencedBy, _} -> + F = fun + ({shop_config, #domain_ShopConfigObject{ref = #domain_ShopConfigRef{id = ShopID}, data = Shop}}) -> + {true, {ShopID, Shop}}; + (_) -> + false + end, + {ok, lists:filtermap(F, ReferencedBy)}; {error, not_found} -> {error, not_found} end. diff --git a/apps/capi/test/capi_base_api_token_tests_SUITE.erl b/apps/capi/test/capi_base_api_token_tests_SUITE.erl index d98c202..4dc791f 100644 --- a/apps/capi/test/capi_base_api_token_tests_SUITE.erl +++ b/apps/capi/test/capi_base_api_token_tests_SUITE.erl @@ -291,7 +291,9 @@ create_invoice_rand_amount_ok_test(Config) -> create_invoice_autorization_error_test(Config) -> _ = capi_ct_helper:mock_services( [ - {invoicing, fun('Create', {#payproc_InvoiceParams{party_id = <<"WrongPartyID">>}}) -> + {invoicing, fun( + 'Create', {#payproc_InvoiceParams{party_id = #domain_PartyConfigRef{id = <<"WrongPartyID">>}}} + ) -> {throwing, #payproc_PartyNotFound{}} end}, {generator, fun('GenerateID', _) -> capi_ct_helper_bender:generate_id(<<"bender_key">>) end} @@ -396,7 +398,9 @@ create_invoice_access_token_ok_test(Config) -> create_invoice_template_ok_test(Config) -> _ = capi_ct_helper:mock_services( [ - {invoice_templating, fun('Create', {#payproc_InvoiceTemplateCreateParams{party_id = ?STRING}}) -> + {invoice_templating, fun( + 'Create', {#payproc_InvoiceTemplateCreateParams{party_id = #domain_PartyConfigRef{id = ?STRING}}} + ) -> {ok, ?INVOICE_TPL} end}, {generator, fun('GenerateID', _) -> capi_ct_helper_bender:generate_id(<<"bender_key">>) end} @@ -428,7 +432,9 @@ create_invoice_template_ok_test(Config) -> create_invoice_template_w_randomization_ok_test(Config) -> _ = capi_ct_helper:mock_services( [ - {invoice_templating, fun('Create', {#payproc_InvoiceTemplateCreateParams{party_id = ?STRING}}) -> + {invoice_templating, fun( + 'Create', {#payproc_InvoiceTemplateCreateParams{party_id = #domain_PartyConfigRef{id = ?STRING}}} + ) -> {ok, ?RECORD_UPDATE( #domain_InvoiceTemplate.mutations, @@ -492,7 +498,7 @@ create_invoice_template_autorization_error_test(Config) -> [ {invoice_templating, fun( 'Create', - {#payproc_InvoiceTemplateCreateParams{party_id = <<"WrongPartyID">>}} + {#payproc_InvoiceTemplateCreateParams{party_id = #domain_PartyConfigRef{id = <<"WrongPartyID">>}}} ) -> {throwing, #payproc_PartyNotFound{}} end}, @@ -1635,7 +1641,6 @@ get_trade_blocs_test(Config) -> -spec different_ip_header(config()) -> _. different_ip_header(Config) -> - _ = capi_ct_helper:mock_services([{party_management, fun('GetShop', _) -> {ok, ?SHOP} end}], Config), IPAddress = <<"192.168.4.2">>, _ = capi_ct_helper_bouncer:mock_assert_requester_ctx( IPAddress, diff --git a/apps/capi/test/capi_ct_helper.erl b/apps/capi/test/capi_ct_helper.erl index d178ec1..ff6e8fa 100644 --- a/apps/capi/test/capi_ct_helper.erl +++ b/apps/capi/test/capi_ct_helper.erl @@ -51,13 +51,28 @@ init_suite(Module, Config, CapiEnv) -> { 'RepositoryClient', {dmsl_domain_conf_v2_thrift, 'RepositoryClient'}, - fun('CheckoutObject', {{version, ?INTEGER}, ObjectRef}) -> - case maps:get(ObjectRef, ?ALL_OBJECTS, undefined) of - undefined -> - woody_error:raise(business, #domain_conf_v2_ObjectNotFound{}); - Object -> - {ok, dmt_wrap_object(Object)} - end + fun + ('CheckoutObject', {{version, ?INTEGER}, ObjectRef}) -> + case maps:get(ObjectRef, ?ALL_OBJECTS, undefined) of + undefined -> + woody_error:raise(business, #domain_conf_v2_ObjectNotFound{}); + Object -> + {ok, dmt_wrap_object(Object)} + end; + %% NOTE Mocks function only for party with shops referencing it + ('CheckoutObjectWithReferences', {{version, ?INTEGER}, {party_config, PartyRef} = ObjectRef}) -> + case maps:get(ObjectRef, ?ALL_OBJECTS, undefined) of + undefined -> + woody_error:raise(business, #domain_conf_v2_ObjectNotFound{}); + Object -> + {ok, #domain_conf_v2_VersionedObjectWithReferences{ + object = dmt_wrap_object(Object), + referenced_by = ordsets:from_list( + filter_only_party_shops(PartyRef, ?ALL_OBJECTS) + ), + references_to = [] + }} + end end }, { @@ -365,3 +380,17 @@ dmt_wrap_object(Object) -> }, object = Object }. + +filter_only_party_shops(PartyRef, AllObjects) -> + Filter = fun + ( + {_, + {shop_config, #domain_ShopConfigObject{ + data = #domain_ShopConfig{party_ref = P} + }} = O} + ) when P =:= PartyRef -> + {true, dmt_wrap_object(O)}; + (_) -> + false + end, + lists:filtermap(Filter, maps:to_list(AllObjects)). diff --git a/apps/capi/test/capi_dummy_data.hrl b/apps/capi/test/capi_dummy_data.hrl index 0a54b74..a4e4cf1 100644 --- a/apps/capi/test/capi_dummy_data.hrl +++ b/apps/capi/test/capi_dummy_data.hrl @@ -90,8 +90,8 @@ details = ?DETAILS, cost = ?CASH, context = ?CONTENT, - shop_id = ?STRING, - owner_id = OwnerID, + shop_ref = #domain_ShopConfigRef{id = ?STRING}, + party_ref = #domain_PartyConfigRef{id = OwnerID}, template_id = ?STRING, external_id = EID }). @@ -157,15 +157,15 @@ id = ?STRING, target = {shop, #domain_AllocationTransactionTargetShop{ - owner_id = ?STRING, - shop_id = ?STRING + party_ref = #domain_PartyConfigRef{id = ?STRING}, + shop_ref = #domain_ShopConfigRef{id = ?STRING} }}, amount = ?CASH, body = #domain_AllocationTransactionBodyTotal{ fee_target = {shop, #domain_AllocationTransactionTargetShop{ - owner_id = ?STRING, - shop_id = ?STRING + party_ref = #domain_PartyConfigRef{id = ?STRING}, + shop_ref = #domain_ShopConfigRef{id = ?STRING} }}, total = ?CASH, fee_amount = ?CASH, @@ -203,8 +203,8 @@ }}, product = ?STRING, context = ?CONTENT, - shop_id = ?STRING, - owner_id = ?STRING, + shop_ref = #domain_ShopConfigRef{id = ?STRING}, + party_ref = #domain_PartyConfigRef{id = ?STRING}, invoice_lifetime = ?LIFETIME_INTERVAL }). @@ -432,7 +432,7 @@ settlement = ?INTEGER, guarantee = ?INTEGER }, - party_id = ?STRING, + party_ref = #domain_PartyConfigRef{id = ?STRING}, location = ?SHOP_LOCATION, category = #domain_CategoryRef{id = ?INTEGER} }). @@ -447,8 +447,6 @@ name = <<"PARTY">>, block = ?BLOCKING, suspension = ?SUSPENTION, - shops = [], - wallets = [], contact_info = #domain_PartyContactInfo{registration_email = ?STRING} }). @@ -456,8 +454,6 @@ name = <<"PARTY_WITH_SHOPS">>, block = ?BLOCKING, suspension = ?SUSPENTION, - shops = [#domain_ShopConfigRef{id = ?STRING}], - wallets = [], contact_info = #domain_PartyContactInfo{registration_email = ?STRING} }). @@ -483,10 +479,10 @@ -define(WEBHOOK, #webhooker_Webhook{ id = ?INTEGER, - party_id = ?STRING, + party_ref = #domain_PartyConfigRef{id = ?STRING}, event_filter = {invoice, #webhooker_InvoiceEventFilter{ - shop_id = ?STRING, + shop_ref = #domain_ShopConfigRef{id = ?STRING}, types = ordsets:from_list([ {created, #webhooker_InvoiceCreated{}}, diff --git a/apps/capi_client/src/capi_client_webhooks.erl b/apps/capi_client/src/capi_client_webhooks.erl index 2f54f3e..195fb1d 100644 --- a/apps/capi_client/src/capi_client_webhooks.erl +++ b/apps/capi_client/src/capi_client_webhooks.erl @@ -6,7 +6,7 @@ -export([get_webhook_by_id/2]). -export([delete_webhook_by_id/2]). --type party_id() :: dmsl_domain_thrift:'PartyID'(). +-type party_id() :: dmsl_base_thrift:'ID'(). -type webhook_id() :: binary(). -type webhook_params() :: map(). -type webhook() :: map(). diff --git a/rebar.config b/rebar.config index aa6e2a8..d34d4fa 100644 --- a/rebar.config +++ b/rebar.config @@ -36,10 +36,10 @@ {cowboy_draining_server, {git, "https://github.com/valitydev/cowboy_draining_server.git", {branch, "master"}}}, {woody, {git, "https://github.com/valitydev/woody_erlang.git", {tag, "v1.1.0"}}}, {woody_user_identity, {git, "https://github.com/valitydev/woody_erlang_user_identity.git", {tag, "v1.1.0"}}}, - {damsel, {git, "https://github.com/valitydev/damsel.git", {tag, "v2.2.11"}}}, + {damsel, {git, "https://github.com/valitydev/damsel.git", {tag, "v2.2.12"}}}, {bender_proto, {git, "https://github.com/valitydev/bender-proto.git", {branch, "master"}}}, {bender_client, {git, "https://github.com/valitydev/bender-client-erlang.git", {tag, "v1.1.0"}}}, - {dmt_client, {git, "https://github.com/valitydev/dmt_client.git", {tag, "v2.0.2"}}}, + {dmt_client, {git, "https://github.com/valitydev/dmt_client.git", {tag, "v2.0.3"}}}, {cowboy_cors, {git, "https://github.com/valitydev/cowboy_cors.git", {branch, "master"}}}, {cowboy_access_log, {git, "https://github.com/valitydev/cowboy_access_log.git", {branch, "master"}}}, {payproc_errors, {git, "https://github.com/valitydev/payproc-errors-erlang.git", {branch, "master"}}}, @@ -49,7 +49,7 @@ {bouncer_proto, {git, "https://github.com/valitydev/bouncer-proto.git", {branch, master}}}, {bouncer_client, {git, "https://github.com/valitydev/bouncer-client-erlang.git", {tag, "v1.1.0"}}}, {token_keeper_client, {git, "https://github.com/valitydev/token-keeper-client.git", {tag, "v1.1.0"}}}, - {party_client, {git, "https://github.com/valitydev/party-client-erlang.git", {tag, "v2.0.1"}}}, + {party_client, {git, "https://github.com/valitydev/party-client-erlang.git", {branch, "ft/bumps-protocol-2.2.12"}}}, {feat, {git, "https://github.com/valitydev/feat.git", {branch, master}}}, %% Libraries generated with swagger-codegen-erlang from valitydev/swag-payments {swag_server, {git, "https://github.com/valitydev/swag-payments", {branch, "release/erlang/server/epic-v3"}}}, diff --git a/rebar.lock b/rebar.lock index 7a4598b..d931867 100644 --- a/rebar.lock +++ b/rebar.lock @@ -41,11 +41,11 @@ {<<"ctx">>,{pkg,<<"ctx">>,<<"0.6.0">>},2}, {<<"damsel">>, {git,"https://github.com/valitydev/damsel.git", - {ref,"ff9b01f552f922ce4a16710827aa872325dbe5a9"}}, + {ref,"8cab698cd78125ac47489d0ba81169df376757a4"}}, 0}, {<<"dmt_client">>, {git,"https://github.com/valitydev/dmt_client.git", - {ref,"fff521d3d50b48e3c6b628fe4796b3628aedc6b7"}}, + {ref,"20c18cc9b51d0f273db60c929e8a8a871d6a1866"}}, 0}, {<<"email_validator">>,{pkg,<<"email_validator">>,<<"1.1.0">>},1}, {<<"erl_health">>, @@ -100,7 +100,7 @@ {<<"parse_trans">>,{pkg,<<"parse_trans">>,<<"3.4.1">>},1}, {<<"party_client">>, {git,"https://github.com/valitydev/party-client-erlang.git", - {ref,"88cb5a9b5abd9bb437222de168bba096edd10882"}}, + {ref,"8b3626374ff1b4cba973867796042bec65017461"}}, 0}, {<<"payproc_errors">>, {git,"https://github.com/valitydev/payproc-errors-erlang.git", From 3a2c756b3b0a57b8d2dc144f8d78c8b03c9b67c6 Mon Sep 17 00:00:00 2001 From: Aleksey Kashapov Date: Wed, 29 Oct 2025 15:39:52 +0300 Subject: [PATCH 6/7] Bumps damsel v2.2.17 --- rebar.config | 4 ++-- rebar.lock | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/rebar.config b/rebar.config index d34d4fa..82325bf 100644 --- a/rebar.config +++ b/rebar.config @@ -36,7 +36,7 @@ {cowboy_draining_server, {git, "https://github.com/valitydev/cowboy_draining_server.git", {branch, "master"}}}, {woody, {git, "https://github.com/valitydev/woody_erlang.git", {tag, "v1.1.0"}}}, {woody_user_identity, {git, "https://github.com/valitydev/woody_erlang_user_identity.git", {tag, "v1.1.0"}}}, - {damsel, {git, "https://github.com/valitydev/damsel.git", {tag, "v2.2.12"}}}, + {damsel, {git, "https://github.com/valitydev/damsel.git", {tag, "v2.2.17"}}}, {bender_proto, {git, "https://github.com/valitydev/bender-proto.git", {branch, "master"}}}, {bender_client, {git, "https://github.com/valitydev/bender-client-erlang.git", {tag, "v1.1.0"}}}, {dmt_client, {git, "https://github.com/valitydev/dmt_client.git", {tag, "v2.0.3"}}}, @@ -49,7 +49,7 @@ {bouncer_proto, {git, "https://github.com/valitydev/bouncer-proto.git", {branch, master}}}, {bouncer_client, {git, "https://github.com/valitydev/bouncer-client-erlang.git", {tag, "v1.1.0"}}}, {token_keeper_client, {git, "https://github.com/valitydev/token-keeper-client.git", {tag, "v1.1.0"}}}, - {party_client, {git, "https://github.com/valitydev/party-client-erlang.git", {branch, "ft/bumps-protocol-2.2.12"}}}, + {party_client, {git, "https://github.com/valitydev/party-client-erlang.git", {tag, "v2.0.2"}}}, {feat, {git, "https://github.com/valitydev/feat.git", {branch, master}}}, %% Libraries generated with swagger-codegen-erlang from valitydev/swag-payments {swag_server, {git, "https://github.com/valitydev/swag-payments", {branch, "release/erlang/server/epic-v3"}}}, diff --git a/rebar.lock b/rebar.lock index d931867..61fc5a6 100644 --- a/rebar.lock +++ b/rebar.lock @@ -41,7 +41,7 @@ {<<"ctx">>,{pkg,<<"ctx">>,<<"0.6.0">>},2}, {<<"damsel">>, {git,"https://github.com/valitydev/damsel.git", - {ref,"8cab698cd78125ac47489d0ba81169df376757a4"}}, + {ref,"f831d3aa5fdfd0338b41af44d1eeffe810ca9708"}}, 0}, {<<"dmt_client">>, {git,"https://github.com/valitydev/dmt_client.git", @@ -100,7 +100,7 @@ {<<"parse_trans">>,{pkg,<<"parse_trans">>,<<"3.4.1">>},1}, {<<"party_client">>, {git,"https://github.com/valitydev/party-client-erlang.git", - {ref,"8b3626374ff1b4cba973867796042bec65017461"}}, + {ref,"8448535eb60e6130bb12902594d2c59eea03e8b0"}}, 0}, {<<"payproc_errors">>, {git,"https://github.com/valitydev/payproc-errors-erlang.git", @@ -133,7 +133,7 @@ {ref,"3a60e5dc5bbd709495024f26e100b041c3547fd9"}}, 1}, {<<"tls_certificate_check">>, - {pkg,<<"tls_certificate_check">>,<<"1.28.0">>}, + {pkg,<<"tls_certificate_check">>,<<"1.29.0">>}, 1}, {<<"token_keeper_client">>, {git,"https://github.com/valitydev/token-keeper-client.git", @@ -181,7 +181,7 @@ {<<"quantile_estimator">>, <<"EF50A361F11B5F26B5F16D0696E46A9E4661756492C981F7B2229EF42FF1CD15">>}, {<<"ranch">>, <<"8C7A100A139FD57F17327B6413E4167AC559FBC04CA7448E9BE9057311597A1D">>}, {<<"ssl_verify_fun">>, <<"354C321CF377240C7B8716899E182CE4890C5938111A1296ADD3EC74CF1715DF">>}, - {<<"tls_certificate_check">>, <<"C39BF21F67C2D124AE905454FAD00F27E625917E8AB1009146E916E1DF6AB275">>}, + {<<"tls_certificate_check">>, <<"4473005EB0BBDAD215D7083A230E2E076F538D9EA472C8009FD22006A4CFC5F6">>}, {<<"unicode_util_compat">>, <<"A48703A25C170EEDADCA83B11E88985AF08D35F37C6F664D6DCFB106A97782FC">>}]}, {pkg_hash_ext,[ {<<"accept">>, <<"CA69388943F5DAD2E7232A5478F16086E3C872F48E32B88B378E1885A59F5649">>}, @@ -211,6 +211,6 @@ {<<"quantile_estimator">>, <<"282A8A323CA2A845C9E6F787D166348F776C1D4A41EDE63046D72D422E3DA946">>}, {<<"ranch">>, <<"49FBCFD3682FAB1F5D109351B61257676DA1A2FDBE295904176D5E521A2DDFE5">>}, {<<"ssl_verify_fun">>, <<"FE4C190E8F37401D30167C8C405EDA19469F34577987C76DDE613E838BBC67F8">>}, - {<<"tls_certificate_check">>, <<"3AB058C3F9457FFFCA916729587415F0DDC822048A0E5B5E2694918556D92DF1">>}, + {<<"tls_certificate_check">>, <<"5B0D0E5CB0F928BC4F210DF667304ED91C5BFF2A391CE6BDEDFBFE70A8F096C5">>}, {<<"unicode_util_compat">>, <<"B3A917854CE3AE233619744AD1E0102E05673136776FB2FA76234F3E03B23642">>}]} ]. From baa1f324af5377c338a8f5fedb46db88d675d21d Mon Sep 17 00:00:00 2001 From: Aleksey Kashapov Date: Mon, 8 Dec 2025 10:55:45 +0300 Subject: [PATCH 7/7] Adds thrift handler for invoice-template creation w/ access token (#63) * Adds thrift handler for invoice-template creation w/ access token * Adds test case w/ idempotency check for thrift version of invoice template creation * Fixes formatting * Fixes thrift proto' indentation * Extends idempotency testcase w/ assertion against result of equivalent swag operation * Adds get update and delete functions to invoice-templating handler * Adds invoice-templating woody testsuite * Moves API extensions to damsel * Bumps damsel --- .../src/capi_handler_invoice_templates.erl | 238 +++++++++++++++++- apps/capi/src/capi_sup.erl | 25 +- .../test/capi_idempotency_tests_SUITE.erl | 107 ++++++++ .../capi_invoice_template_woody_SUITE.erl | 233 +++++++++++++++++ .../keys/local/jwk.priv.json | 10 + .../keys/local/jwk.publ.json | 9 + .../keys/local/private.pem | 9 + config/sys.config | 73 +++--- elvis.config | 1 + rebar.config | 10 +- rebar.lock | 2 +- 11 files changed, 681 insertions(+), 36 deletions(-) create mode 100644 apps/capi/test/capi_invoice_template_woody_SUITE.erl create mode 100644 apps/capi/test/capi_invoice_template_woody_SUITE_data/keys/local/jwk.priv.json create mode 100644 apps/capi/test/capi_invoice_template_woody_SUITE_data/keys/local/jwk.publ.json create mode 100644 apps/capi/test/capi_invoice_template_woody_SUITE_data/keys/local/private.pem diff --git a/apps/capi/src/capi_handler_invoice_templates.erl b/apps/capi/src/capi_handler_invoice_templates.erl index 68f221c..b1ccc8d 100644 --- a/apps/capi/src/capi_handler_invoice_templates.erl +++ b/apps/capi/src/capi_handler_invoice_templates.erl @@ -3,11 +3,14 @@ -include_lib("damsel/include/dmsl_base_thrift.hrl"). -include_lib("damsel/include/dmsl_domain_thrift.hrl"). -include_lib("damsel/include/dmsl_payproc_thrift.hrl"). +-include_lib("damsel/include/dmsl_api_ext_thrift.hrl"). -behaviour(capi_handler). - -export([prepare/3]). +-behaviour(woody_server_thrift_handler). +-export([handle_function/4]). + -import(capi_handler_utils, [general_error/2, logic_error/2, conflict_error/1, map_service_result/1]). -spec prepare( @@ -212,6 +215,66 @@ prepare('GetInvoicePaymentMethodsByTemplateID' = OperationID, Req, Context) -> prepare(_OperationID, _Req, _Context) -> {error, noimpl}. +-spec handle_function(woody:func(), woody:args(), woody_context:ctx(), _) -> + {ok, term()} | no_return(). +handle_function(Function, Args, WoodyContext, Opts) -> + scoper:scope( + invoice_templating, + fun() -> + try handle_function_(Function, Args, WoodyContext, Opts) of + {ok, _} = Result -> + Result; + {exception, #payproc_InvoiceTemplateNotFound{} = Exception} -> + woody_error:raise(business, Exception); + {exception, #payproc_InvoiceTemplateRemoved{} = Exception} -> + woody_error:raise(business, Exception); + {exception, #payproc_PartyNotFound{} = Exception} -> + woody_error:raise(business, Exception); + {exception, #payproc_ShopNotFound{} = Exception} -> + woody_error:raise(business, Exception); + {exception, #payproc_InvalidPartyStatus{} = Exception} -> + woody_error:raise(business, Exception); + {exception, #payproc_InvalidShopStatus{} = Exception} -> + woody_error:raise(business, Exception); + {exception, #base_InvalidRequest{errors = Errors}} -> + woody_error:raise(business, #base_InvalidRequest{errors = Errors}) + catch + throw:(#payproc_InvoiceTemplateNotFound{} = Exception) -> + woody_error:raise(business, Exception); + throw:(#payproc_InvoiceTemplateRemoved{} = Exception) -> + woody_error:raise(business, Exception); + throw:invoice_cart_empty -> + woody_error:raise(business, #base_InvalidRequest{errors = [<<"Wrong size. Path to item: cart">>]}); + throw:zero_invoice_lifetime -> + woody_error:raise(business, #base_InvalidRequest{errors = [<<"Lifetime cannot be zero">>]}); + throw:{external_id_conflict, _ID, _UsedExternalID, _Schema} -> + woody_error:raise(business, #base_InvalidRequest{ + errors = [<<"This 'externalID' has been used by another request">>] + }) + end + end + ). + +handle_function_('Create', {InvoiceTemplateParams}, WoodyContext, _Opts) -> + %% NOTE Use same operation ID as the original in swagger/JSON API + InvoiceTemplateID = generate_thrift_invoice_template_id( + 'CreateInvoiceTemplate', InvoiceTemplateParams, WoodyContext + ), + CallArgs = {encode_thrift_invoice_tpl_create_params(InvoiceTemplateID, InvoiceTemplateParams)}, + case capi_woody_client:call_service(invoice_templating, 'Create', CallArgs, WoodyContext) of + {ok, InvoiceTpl} -> + {ok, make_thrift_invoice_tpl_and_token(InvoiceTpl, WoodyContext)}; + Passthrough -> + Passthrough + end; +handle_function_('Get', {InvoiceTemplateID}, WoodyContext, _Opts) -> + capi_woody_client:call_service(invoice_templating, 'Get', {InvoiceTemplateID}, WoodyContext); +handle_function_('Update', {InvoiceTemplateID, InvoiceTemplateParams}, WoodyContext, _Opts) -> + Params = encode_thrift_invoice_tpl_update_params(InvoiceTemplateParams), + capi_woody_client:call_service(invoice_templating, 'Update', {InvoiceTemplateID, Params}, WoodyContext); +handle_function_('Delete', {InvoiceTemplateID}, WoodyContext, _Opts) -> + capi_woody_client:call_service(invoice_templating, 'Delete', {InvoiceTemplateID}, WoodyContext). + mask_invoice_template_notfound(Resolution) -> % ED-206 % When bouncer says "forbidden" we can't really tell the difference between "forbidden because @@ -246,7 +309,121 @@ generate_invoice_template_id(OperationID, TemplateParams, PartyID, #{woody_conte Identity = capi_bender:make_identity(capi_feature_schemas:invoice_template(), TemplateParams), capi_bender:gen_snowflake(IdempKey, Identity, WoodyContext). -encode_invoice_tpl_create_params(InvoiceTemplateID, PartyID, Params) -> +generate_thrift_invoice_template_id( + OperationID, + #api_ext_InvoiceTemplateCreateParams{external_id = ExternalID, party_id = #domain_PartyConfigRef{id = PartyID}} = + TemplateParams, + WoodyContext +) -> + IdempKey = {OperationID, PartyID, ExternalID}, + Identity = capi_bender:make_identity( + capi_feature_schemas:invoice_template(), + decode_to_feature_container(TemplateParams) + ), + capi_bender:gen_snowflake(IdempKey, Identity, WoodyContext). + +decode_to_feature_container(#api_ext_InvoiceTemplateCreateParams{ + shop_id = #domain_ShopConfigRef{id = ShopID}, + invoice_lifetime = #domain_LifetimeInterval{days = DD, months = MM, years = YY}, + details = Details +}) -> + #{ + <<"shopID">> => ShopID, + <<"lifetime">> => #{<<"days">> => DD, <<"months">> => MM, <<"years">> => YY}, + <<"details">> => encode_details_to_feature_container(Details) + }. + +encode_details_to_feature_container( + {product, #domain_InvoiceTemplateProduct{ + product = Product, + price = Price, + metadata = Metadata + }} +) -> + genlib_map:compact(#{ + <<"templateType">> => <<"InvoiceTemplateSingleLine">>, + <<"product">> => Product, + <<"price">> => encode_price_to_feature_container(Price), + <<"taxMode">> => encode_tax_metadata_to_feature_container(Metadata) + }); +encode_details_to_feature_container({cart, #domain_InvoiceCart{lines = Lines}}) -> + {Cart, Currency} = encode_cart_lines_to_feature_container(Lines), + #{ + <<"templateType">> => <<"InvoiceTemplateMultiLine">>, + <<"currency">> => Currency, + <<"cart">> => Cart + }. + +encode_cart_lines_to_feature_container([]) -> + throw(invoice_cart_empty); +encode_cart_lines_to_feature_container(Lines) -> + {Cart, Currency} = lists:foldl( + fun( + #domain_InvoiceLine{ + product = Product, + quantity = Quantity, + price = #domain_Cash{amount = Amount, currency = #domain_CurrencyRef{symbolic_code = Curr}}, + metadata = Metadata + }, + {Items, _} + ) -> + { + [ + genlib_map:compact(#{ + <<"product">> => Product, + <<"quantity">> => Quantity, + <<"price">> => Amount, + <<"taxMode">> => encode_tax_metadata_to_feature_container(Metadata) + }) + | Items + ], + Curr + } + end, + {[], undefined}, + Lines + ), + {lists:reverse(Cart), Currency}. + +encode_price_to_feature_container({unlim, #domain_InvoiceTemplateCostUnlimited{}}) -> + #{<<"costType">> => <<"InvoiceTemplateLineCostUnlim">>}; +encode_price_to_feature_container( + {fixed, #domain_Cash{amount = Amount, currency = #domain_CurrencyRef{symbolic_code = Currency}}} +) -> + #{ + <<"costType">> => <<"InvoiceTemplateLineCostFixed">>, + <<"amount">> => Amount, + <<"currency">> => Currency + }; +encode_price_to_feature_container( + {range, #domain_CashRange{ + lower = {_, #domain_Cash{currency = #domain_CurrencyRef{symbolic_code = Currency}}} = LowerBound, + upper = UpperBound + }} +) -> + #{ + <<"costType">> => <<"InvoiceTemplateLineCostRange">>, + <<"currency">> => Currency, + <<"range">> => #{ + <<"lowerBound">> => encode_bound_to_feature_container(LowerBound, 1), + <<"upperBound">> => encode_bound_to_feature_container(UpperBound, -1) + } + }. + +encode_bound_to_feature_container({inclusive, #domain_Cash{amount = Bound}}, _Delta) -> + Bound; +encode_bound_to_feature_container({exclusive, #domain_Cash{amount = Bound}}, Delta) -> + Bound + Delta. + +encode_tax_metadata_to_feature_container(#{<<"TaxMode">> := {str, TM}}) -> + #{ + <<"type">> => <<"InvoiceLineTaxVAT">>, + <<"rate">> => TM + }; +encode_tax_metadata_to_feature_container(#{}) -> + undefined. + +encode_invoice_tpl_create_params(InvoiceTemplateID, PartyID, Params) when is_map(Params) -> Details = encode_invoice_tpl_details(genlib_map:get(<<"details">>, Params)), Product = get_product_from_tpl_details(Details), #payproc_InvoiceTemplateCreateParams{ @@ -275,12 +452,69 @@ encode_invoice_tpl_update_params(Params) -> mutations = capi_mutation:encode_amount_randomization_params(genlib_map:get(<<"randomizeAmount">>, Params)) }. +encode_thrift_invoice_tpl_update_params(#api_ext_InvoiceTemplateUpdateParams{ + invoice_lifetime = InvoiceLifetime, + name = Name, + description = Description, + details = Details, + context = Context +}) -> + ok = assert_cart_is_not_empty(Details), + Product = get_product_from_tpl_details(Details), + #payproc_InvoiceTemplateUpdateParams{ + invoice_lifetime = InvoiceLifetime, + product = Product, + name = Name, + description = Description, + details = Details, + context = Context + }. + +assert_cart_is_not_empty({cart, #domain_InvoiceCart{lines = []}}) -> + throw(invoice_cart_empty); +assert_cart_is_not_empty(_) -> + ok. + make_invoice_tpl_and_token(InvoiceTpl, ProcessingContext) -> #{ <<"invoiceTemplate">> => decode_invoice_tpl(InvoiceTpl), <<"invoiceTemplateAccessToken">> => capi_handler_utils:issue_access_token(InvoiceTpl, ProcessingContext) }. +encode_thrift_invoice_tpl_create_params(InvoiceTemplateID, #api_ext_InvoiceTemplateCreateParams{ + party_id = PartyID, + shop_id = ShopID, + invoice_lifetime = InvoiceLifetime, + name = Name, + description = Description, + details = Details, + context = Context +}) -> + Product = get_product_from_tpl_details(Details), + #payproc_InvoiceTemplateCreateParams{ + template_id = InvoiceTemplateID, + party_id = PartyID, + shop_id = ShopID, + invoice_lifetime = InvoiceLifetime, + product = Product, + name = Name, + description = Description, + details = Details, + context = Context + }. + +make_thrift_invoice_tpl_and_token(InvoiceTpl, WoodyContext) -> + TokenSpec = #{ + party => InvoiceTpl#domain_InvoiceTemplate.party_ref#domain_PartyConfigRef.id, + scope => {invoice_template, InvoiceTpl#domain_InvoiceTemplate.id}, + shop => InvoiceTpl#domain_InvoiceTemplate.shop_ref#domain_ShopConfigRef.id + }, + TokenPayload = capi_auth:issue_access_token(TokenSpec, WoodyContext), + #api_ext_InvoiceTemplateAndToken{ + invoice_template = InvoiceTpl, + invoice_template_access_token = #api_ext_AccessToken{payload = TokenPayload} + }. + encode_invoice_tpl_details(#{<<"templateType">> := <<"InvoiceTemplateSingleLine">>} = Details) -> {product, encode_invoice_tpl_product(Details)}; encode_invoice_tpl_details(#{<<"templateType">> := <<"InvoiceTemplateMultiLine">>} = Details) -> diff --git a/apps/capi/src/capi_sup.erl b/apps/capi/src/capi_sup.erl index 72d0575..9714c10 100644 --- a/apps/capi/src/capi_sup.erl +++ b/apps/capi/src/capi_sup.erl @@ -32,12 +32,35 @@ init([]) -> AdditionalRoutes = [{'_', [erl_health_handle:get_route(HealthCheck), get_prometheus_route()]}], SwaggerHandlerOpts = genlib_app:env(?APP, swagger_handler_opts, #{}), SwaggerSpec = capi_swagger_server:child_spec(AdditionalRoutes, LogicHandler, SwaggerHandlerOpts), + WoodyChildSPec = get_woody_child_spec(), {ok, { {one_for_all, 0, 1}, - [LechiffreSpec, SwaggerSpec, PartyClientSpec] + [LechiffreSpec, SwaggerSpec, PartyClientSpec, WoodyChildSPec] }}. +get_woody_child_spec() -> + {ok, IP} = inet:parse_address(genlib_app:env(capi_woody_server, ip, "::")), + EventHandlerOpts = genlib_app:env(capi_woody_server, scoper_event_handler_options, #{}), + woody_server:child_spec( + ?MODULE, + #{ + ip => IP, + port => genlib_app:env(capi_woody_server, port, 8022), + transport_opts => genlib_app:env(capi_woody_server, transport_opts, #{}), + protocol_opts => genlib_app:env(capi_woody_server, protocol_opts, #{}), + event_handler => {scoper_woody_event_handler, EventHandlerOpts}, + handlers => [ + %% TODO Proper path + {"/v2/extensions/invoice_templating", { + {dmsl_api_ext_thrift, 'InvoiceTemplating'}, {capi_handler_invoice_templates, #{}} + }} + ], + additional_routes => [], + shutdown_timeout => genlib_app:env(?MODULE, shutdown_timeout, 0) + } + ). + -spec get_logic_handler_info(capi_handler:handler_opts()) -> {Handler :: swag_server:logic_handler(_), [Spec :: supervisor:child_spec()] | []}. get_logic_handler_info(HandlerOpts) -> diff --git a/apps/capi/test/capi_idempotency_tests_SUITE.erl b/apps/capi/test/capi_idempotency_tests_SUITE.erl index d09890d..f37442f 100644 --- a/apps/capi/test/capi_idempotency_tests_SUITE.erl +++ b/apps/capi/test/capi_idempotency_tests_SUITE.erl @@ -7,6 +7,7 @@ -include_lib("damsel/include/dmsl_payproc_thrift.hrl"). -include_lib("damsel/include/dmsl_base_thrift.hrl"). -include_lib("damsel/include/dmsl_domain_thrift.hrl"). +-include_lib("damsel/include/dmsl_api_ext_thrift.hrl"). -export([all/0]). -export([groups/0]). @@ -30,6 +31,7 @@ -export([create_invoice_idemp_cart_fail_test/1]). -export([create_invoice_idemp_bank_account_fail_test/1]). -export([create_invoice_template_ok_test/1]). +-export([create_invoice_template_with_woody_ok_test/1]). -export([create_invoice_template_fail_test/1]). -export([create_invoice_with_template_ok_test/1]). -export([create_invoice_with_template_fail_test/1]). @@ -78,6 +80,7 @@ groups() -> ]}, {invoice_template_creation, [], [ create_invoice_template_ok_test, + create_invoice_template_with_woody_ok_test, create_invoice_template_fail_test ]}, {invoice_with_template_creation, [], [ @@ -463,6 +466,110 @@ create_invoice_template_ok_test(Config) -> UnusedParams1 ). +-spec create_invoice_template_with_woody_ok_test(config()) -> _. +create_invoice_template_with_woody_ok_test(Config) -> + BenderKey = <<"create_invoice_template_with_woody_ok_test_bender_key">>, + ExternalID = genlib:unique(), + CreateParams = #api_ext_InvoiceTemplateCreateParams{ + external_id = ExternalID, + party_id = #domain_PartyConfigRef{id = <<"2">>}, + shop_id = #domain_ShopConfigRef{id = <<"1">>}, + invoice_lifetime = #domain_LifetimeInterval{days = ?INTEGER, months = ?INTEGER, years = ?INTEGER}, + description = <<"Sample text">>, + details = + {cart, #domain_InvoiceCart{ + lines = [ + #domain_InvoiceLine{ + product = ?STRING, + quantity = ?INTEGER, + price = ?CASH, + metadata = #{?STRING => {obj, #{}}} + }, + #domain_InvoiceLine{ + product = ?STRING, + quantity = ?INTEGER, + price = ?CASH, + metadata = #{<<"TaxMode">> => {str, <<"18%">>}} + } + ] + }}, + context = ?CONTENT + }, + SwagReq = #{ + <<"externalID">> => ExternalID, + <<"shopID">> => <<"1">>, + <<"lifetime">> => #{ + <<"days">> => ?INTEGER, + <<"months">> => ?INTEGER, + <<"years">> => ?INTEGER + }, + <<"partyID">> => <<"2">>, + <<"details">> => ?INVOICE_TMPL_DETAILS_PARAMS, + <<"description">> => <<"Sample text">> + }, + Result = capi_ct_helper_bender:with_storage( + fun(StorageID) -> + _ = capi_ct_helper:mock_services( + [ + {invoice_templating, fun( + 'Create', + {#payproc_InvoiceTemplateCreateParams{template_id = TemplateID}} + ) -> + {ok, ?INVOICE_TPL(TemplateID)} + end}, + {bender, fun('GenerateID', {_Key, _, CtxMsgPack}) -> + capi_ct_helper_bender:get_internal_id(StorageID, BenderKey, CtxMsgPack) + end} + ], + Config + ), + %% Two thrift calls + [ + with_feature_storage(fun() -> + woody_client:call({{dmsl_api_ext_thrift, 'InvoiceTemplating'}, 'Create', {Params}}, #{ + url => "http://localhost:8022/v2/extensions/invoice_templating", + event_handler => scoper_woody_event_handler + }) + end) + || Params <- [ + CreateParams, + CreateParams#api_ext_InvoiceTemplateCreateParams{description = <<"whatever">>} + ] + ] ++ + %% And one swag request + [ + with_feature_storage(fun() -> + capi_client_invoice_templates:create(?config(context, Config), SwagReq) + end) + ] + end + ), + %% NOTE Since thrift parameters are decoded into the feature set only with + %% fields present in the schema, no other fields should be tracked as unused + %% by `capi_ct_features_reader_event_handler` and its storage. + %% NOTE See `capi_handler_invoice_templates:decode_to_feature_container/1`. + ?assertMatch( + [ + { + {ok, #api_ext_InvoiceTemplateAndToken{invoice_template = #domain_InvoiceTemplate{id = ID} = Template}}, + [] = UnusedParams + }, + { + {ok, #api_ext_InvoiceTemplateAndToken{invoice_template = Template}}, + UnusedParams + }, + { + {ok, #{<<"invoiceTemplate">> := #{<<"id">> := ID}}}, + [ + [<<"description">>], + [<<"externalID">>], + [<<"partyID">>] + ] = _OtherUnusedParams + } + ], + Result + ). + -spec create_invoice_template_fail_test(config()) -> _. create_invoice_template_fail_test(Config) -> BenderKey = <<"create_invoice_template_fail_test_bender_key">>, diff --git a/apps/capi/test/capi_invoice_template_woody_SUITE.erl b/apps/capi/test/capi_invoice_template_woody_SUITE.erl new file mode 100644 index 0000000..7b08cc6 --- /dev/null +++ b/apps/capi/test/capi_invoice_template_woody_SUITE.erl @@ -0,0 +1,233 @@ +-module(capi_invoice_template_woody_SUITE). + +-include_lib("common_test/include/ct.hrl"). +-include_lib("stdlib/include/assert.hrl"). + +-include_lib("capi_dummy_data.hrl"). +-include_lib("damsel/include/dmsl_payproc_thrift.hrl"). +%% -include_lib("damsel/include/dmsl_base_thrift.hrl"). +-include_lib("damsel/include/dmsl_domain_thrift.hrl"). +-include_lib("damsel/include/dmsl_api_ext_thrift.hrl"). + +-export([all/0]). +-export([groups/0]). +-export([init_per_suite/1]). +-export([end_per_suite/1]). +-export([init_per_group/2]). +-export([end_per_group/2]). +-export([init_per_testcase/2]). +-export([end_per_testcase/2]). + +-export([init/1]). + +-export([create_invoice_template_ok_test/1]). +-export([update_invoice_template_ok_test/1]). +-export([get_invoice_template_ok_test/1]). +-export([delete_invoice_template_ok_test/1]). + +-type test_case_name() :: atom(). +-type config() :: [{atom(), any()}]. +-type group_name() :: atom(). + +-behaviour(supervisor). + +-spec init([]) -> {ok, {supervisor:sup_flags(), [supervisor:child_spec()]}}. +init([]) -> + {ok, {#{strategy => one_for_all, intensity => 1, period => 1}, []}}. + +-spec all() -> [{group, test_case_name()}]. +all() -> + [ + {group, default} + ]. + +-spec groups() -> [{group_name(), list(), [test_case_name()]}]. +groups() -> + [ + %% NOTE Sequential execution due to mocks. + {default, [sequence], [ + create_invoice_template_ok_test, + update_invoice_template_ok_test, + get_invoice_template_ok_test, + delete_invoice_template_ok_test + ]} + ]. + +%% +%% starting/stopping +%% +-spec init_per_suite(config()) -> config(). +init_per_suite(Config0) -> + capi_ct_helper:init_suite(?MODULE, Config0). + +-spec end_per_suite(config()) -> _. +end_per_suite(C) -> + _ = capi_ct_helper:stop_mocked_service_sup(?config(suite_test_sup, C)), + _ = [application:stop(App) || App <- proplists:get_value(apps, C)], + ok. + +-spec init_per_group(group_name(), config()) -> config(). +init_per_group(_GroupName, Config) -> + SupPid = capi_ct_helper:start_mocked_service_sup(?MODULE), + Apps1 = capi_ct_helper_token_keeper:mock_user_session_token(SupPid), + [ + {group_apps, Apps1}, + {group_test_sup, SupPid} + | Config + ]. + +-spec end_per_group(group_name(), config()) -> _. +end_per_group(_Group, C) -> + _ = capi_utils:'maybe'(?config(group_test_sup, C), fun capi_ct_helper:stop_mocked_service_sup/1), + ok. + +-spec init_per_testcase(test_case_name(), config()) -> config(). +init_per_testcase(_Name, C) -> + [{test_sup, capi_ct_helper:start_mocked_service_sup(?MODULE)} | C]. + +-spec end_per_testcase(test_case_name(), config()) -> _. +end_per_testcase(_Name, C) -> + capi_ct_helper:stop_mocked_service_sup(?config(test_sup, C)), + ok. + +%% TESTS + +-spec create_invoice_template_ok_test(config()) -> _. +create_invoice_template_ok_test(Config) -> + Params = #api_ext_InvoiceTemplateCreateParams{ + external_id = ?STRING, + party_id = #domain_PartyConfigRef{id = <<"2">>}, + shop_id = #domain_ShopConfigRef{id = <<"1">>}, + invoice_lifetime = #domain_LifetimeInterval{days = ?INTEGER, months = ?INTEGER, years = ?INTEGER}, + description = <<"Sample text">>, + details = + {cart, #domain_InvoiceCart{ + lines = [ + #domain_InvoiceLine{ + product = ?STRING, + quantity = ?INTEGER, + price = ?CASH, + metadata = #{?STRING => {obj, #{}}} + }, + #domain_InvoiceLine{ + product = ?STRING, + quantity = ?INTEGER, + price = ?CASH, + metadata = #{<<"TaxMode">> => {str, <<"18%">>}} + } + ] + }}, + context = ?CONTENT + }, + InvoiceTemplateID = genlib:unique(), + _ = capi_ct_helper:mock_services( + [ + {invoice_templating, fun( + 'Create', + {#payproc_InvoiceTemplateCreateParams{template_id = TemplateID}} + ) -> + {ok, ?INVOICE_TPL(TemplateID)} + end}, + {bender, fun('GenerateID', {_Key, _, _Ctx}) -> + {ok, capi_ct_helper_bender:get_result(InvoiceTemplateID)} + end} + ], + Config + ), + ?assertMatch( + {ok, #api_ext_InvoiceTemplateAndToken{ + invoice_template = #domain_InvoiceTemplate{id = InvoiceTemplateID}, + invoice_template_access_token = #api_ext_AccessToken{payload = ?API_TOKEN} + }}, + woody_client:call({{dmsl_api_ext_thrift, 'InvoiceTemplating'}, 'Create', {Params}}, #{ + url => "http://localhost:8022/v2/extensions/invoice_templating", + event_handler => scoper_woody_event_handler + }) + ). + +-spec update_invoice_template_ok_test(config()) -> _. +update_invoice_template_ok_test(Config) -> + Params = #api_ext_InvoiceTemplateUpdateParams{ + invoice_lifetime = #domain_LifetimeInterval{days = ?INTEGER, months = ?INTEGER, years = ?INTEGER}, + description = <<"Sample text">>, + details = + {cart, #domain_InvoiceCart{ + lines = [ + #domain_InvoiceLine{ + product = ?STRING, + quantity = ?INTEGER, + price = ?CASH, + metadata = #{?STRING => {obj, #{}}} + }, + #domain_InvoiceLine{ + product = ?STRING, + quantity = ?INTEGER, + price = ?CASH, + metadata = #{<<"TaxMode">> => {str, <<"18%">>}} + } + ] + }}, + context = ?CONTENT + }, + InvoiceTemplateID = genlib:unique(), + _ = capi_ct_helper:mock_services( + [ + {invoice_templating, fun( + 'Update', + {TemplateID, #payproc_InvoiceTemplateUpdateParams{ + invoice_lifetime = _, + description = _, + details = _, + context = ?CONTENT + }} + ) -> + {ok, ?INVOICE_TPL(TemplateID)} + end} + ], + Config + ), + ?assertMatch( + {ok, #domain_InvoiceTemplate{id = InvoiceTemplateID}}, + woody_client:call({{dmsl_api_ext_thrift, 'InvoiceTemplating'}, 'Update', {InvoiceTemplateID, Params}}, #{ + url => "http://localhost:8022/v2/extensions/invoice_templating", + event_handler => scoper_woody_event_handler + }) + ). + +-spec get_invoice_template_ok_test(config()) -> _. +get_invoice_template_ok_test(Config) -> + InvoiceTemplateID = genlib:unique(), + _ = capi_ct_helper:mock_services( + [ + {invoice_templating, fun('Get', {TemplateID}) -> + {ok, ?INVOICE_TPL(TemplateID)} + end} + ], + Config + ), + ?assertMatch( + {ok, #domain_InvoiceTemplate{id = InvoiceTemplateID}}, + woody_client:call({{dmsl_api_ext_thrift, 'InvoiceTemplating'}, 'Get', {InvoiceTemplateID}}, #{ + url => "http://localhost:8022/v2/extensions/invoice_templating", + event_handler => scoper_woody_event_handler + }) + ). + +-spec delete_invoice_template_ok_test(config()) -> _. +delete_invoice_template_ok_test(Config) -> + InvoiceTemplateID = genlib:unique(), + _ = capi_ct_helper:mock_services( + [ + {invoice_templating, fun('Delete', {TemplateID}) when TemplateID =:= InvoiceTemplateID -> + {ok, ok} + end} + ], + Config + ), + ?assertMatch( + {ok, ok}, + woody_client:call({{dmsl_api_ext_thrift, 'InvoiceTemplating'}, 'Delete', {InvoiceTemplateID}}, #{ + url => "http://localhost:8022/v2/extensions/invoice_templating", + event_handler => scoper_woody_event_handler + }) + ). diff --git a/apps/capi/test/capi_invoice_template_woody_SUITE_data/keys/local/jwk.priv.json b/apps/capi/test/capi_invoice_template_woody_SUITE_data/keys/local/jwk.priv.json new file mode 100644 index 0000000..e7d6557 --- /dev/null +++ b/apps/capi/test/capi_invoice_template_woody_SUITE_data/keys/local/jwk.priv.json @@ -0,0 +1,10 @@ +{ + "use": "enc", + "kty": "EC", + "kid": "kxdD0orVPGoAxWrqAMTeQ0U5MRoK47uZxWiSJdgo0t0", + "crv": "P-256", + "alg": "ECDH-ES", + "x": "nHi7TCgBwfrPuNTf49bGvJMczk6WZOI-mCKAghbrOlM", + "y": "_8kiXGOIWkfz57m8K5dmTfbYzCJVYHZZZisCfbYicr0", + "d": "i45qDiARZ5qbS_uzeT-CiKnPUe64qHitKaVdAvcN6TI" +} \ No newline at end of file diff --git a/apps/capi/test/capi_invoice_template_woody_SUITE_data/keys/local/jwk.publ.json b/apps/capi/test/capi_invoice_template_woody_SUITE_data/keys/local/jwk.publ.json new file mode 100644 index 0000000..00b7002 --- /dev/null +++ b/apps/capi/test/capi_invoice_template_woody_SUITE_data/keys/local/jwk.publ.json @@ -0,0 +1,9 @@ +{ + "use": "enc", + "kty": "EC", + "kid": "kxdD0orVPGoAxWrqAMTeQ0U5MRoK47uZxWiSJdgo0t0", + "crv": "P-256", + "alg": "ECDH-ES", + "x": "nHi7TCgBwfrPuNTf49bGvJMczk6WZOI-mCKAghbrOlM", + "y": "_8kiXGOIWkfz57m8K5dmTfbYzCJVYHZZZisCfbYicr0" +} \ No newline at end of file diff --git a/apps/capi/test/capi_invoice_template_woody_SUITE_data/keys/local/private.pem b/apps/capi/test/capi_invoice_template_woody_SUITE_data/keys/local/private.pem new file mode 100644 index 0000000..4e6d12c --- /dev/null +++ b/apps/capi/test/capi_invoice_template_woody_SUITE_data/keys/local/private.pem @@ -0,0 +1,9 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIBOwIBAAJBAK9fx7qOJT7Aoseu7KKgaLagBh3wvDzg7F/ZMtGbPFikJnnvRWvF +B5oEGbMPblvtF0/fjqfu+eqjP3Z1tUSn7TkCAwEAAQJABUY5KIgr4JZEjwLYxQ9T +9uIbLP1Xe/E7yqoqmBk2GGhSrPY0OeRkYnUVLcP96UPQhF63iuG8VF6uZ7oAPsq+ +gQIhANZy3jSCzPjXYHRU1kRqQzpt2S+OqoEiqQ6YG1HrC/VxAiEA0Vq6JlQK2tOX +37SS00dK0Qog4Qi8dN73GliFQNP18EkCIQC4epSA48zkfJMzQBAbRraSuxDNApPX +BzQbo+pMrEDbYQIgY4AncQgIkLB4Qk5kah48JNYXglzQlQtTjiX8Ty9ueGECIQCM +GD3UbQKiA0gf5plBA24I4wFVKxxa4wXbW/7SfP6XmQ== +-----END RSA PRIVATE KEY----- diff --git a/config/sys.config b/config/sys.config index 32052d3..c39d1a1 100644 --- a/config/sys.config +++ b/config/sys.config @@ -40,7 +40,9 @@ %% {oops_bodies, #{ %% 500 => "oops_bodies/500_body" %% }}, - {graceful_shutdown_timeout, 5000}, % non_neg_integer() | infinity + + % non_neg_integer() | infinity + {graceful_shutdown_timeout, 5000}, {bouncer_ruleset_id, <<"service/authz/api">>}, {access_conf, #{ jwt => #{ @@ -63,13 +65,14 @@ } }}, {health_check, #{ - disk => {erl_health, disk , ["/", 99]}, - memory => {erl_health, cg_memory, [99]}, - service => {erl_health, service , [<<"capi">>]} + disk => {erl_health, disk, ["/", 99]}, + memory => {erl_health, cg_memory, [99]}, + service => {erl_health, service, [<<"capi">>]} }}, - {max_request_deadline, 60000}, % milliseconds + % milliseconds + {max_request_deadline, 60000}, {default_processing_deadline, <<"30m">>}, - {lechiffre_opts, #{ + {lechiffre_opts, #{ encryption_key_path => <<"path/to/key1.secret">>, decryption_key_paths => [<<"path/to/key1.secret">>] }}, @@ -83,37 +86,45 @@ }} ]}, + {capi_woody_server, [ + {ip, "::"}, + {port, 8022} + ]}, + {capi_woody_client, [ {services, #{ - party_management => <<"http://hellgate:8022/v1/processing/partymgmt">>, - invoicing => <<"http://hellgate:8022/v1/processing/invoicing">>, - invoice_templating => <<"http://hellgate:8022/v1/processing/invoice_templating">>, - webhook_manager => <<"http://hooker:8022/hook">> + party_management => <<"http://hellgate:8022/v1/processing/partymgmt">>, + invoicing => <<"http://hellgate:8022/v1/processing/invoicing">>, + invoice_templating => <<"http://hellgate:8022/v1/processing/invoice_templating">>, + webhook_manager => <<"http://hooker:8022/hook">> }}, {service_deadlines, #{ - party_management => 5000 % milliseconds + % milliseconds + party_management => 5000 }}, {service_retries, #{ - party_management => #{ - % function => retry strategy - % '_' work as "any" - % default value is 'finish' - % for more info look genlib_retry :: strategy() - % https://github.com/valitydev/genlib/blob/master/src/genlib_retry.erl#L19 - 'Get' => {linear, 3, 1000}, - '_' => finish + party_management => #{ + % function => retry strategy + % '_' work as "any" + % default value is 'finish' + % for more info look genlib_retry :: strategy() + % https://github.com/valitydev/genlib/blob/master/src/genlib_retry.erl#L19 + 'Get' => {linear, 3, 1000}, + '_' => finish } }} ]}, {dmt_client, [ - {cache_update_interval, 30000}, % milliseconds + % milliseconds + {cache_update_interval, 30000}, {max_cache_size, #{ elements => 20, - memory => 52428800 % 50Mb + % 50Mb + memory => 52428800 }}, {service_urls, #{ - 'Repository' => <<"http://dominant:8022/v1/domain/repository">>, + 'Repository' => <<"http://dominant:8022/v1/domain/repository">>, 'RepositoryClient' => <<"http://dominant:8022/v1/domain/repository_client">> }} ]}, @@ -123,16 +134,18 @@ 'party_management' => "http://hellgate:8022/v1/processing/partymgmt" }}, {woody, #{ - cache_mode => safe, % disabled | safe | aggressive + % disabled | safe | aggressive + cache_mode => safe, options => #{ woody_client => #{ - event_handler => {scoper_woody_event_handler, #{ - event_handler_opts => #{ - formatter_opts => #{ - max_length => 1000 + event_handler => + {scoper_woody_event_handler, #{ + event_handler_opts => #{ + formatter_opts => #{ + max_length => 1000 + } } - } - }} + }} } }, %retries => #{ @@ -203,7 +216,7 @@ ]}, {snowflake, [ - % {machine_id, 42} + % {machine_id, 42} ]}, {prometheus, [ diff --git a/elvis.config b/elvis.config index 7e974ae..5ac8919 100644 --- a/elvis.config +++ b/elvis.config @@ -40,6 +40,7 @@ capi_feature_schemas ] }}, + {elvis_style, private_data_types, disable}, {elvis_style, no_import, disable}, {elvis_style, no_throw, disable}, {elvis_style, export_used_types, disable} diff --git a/rebar.config b/rebar.config index 82325bf..0267d7d 100644 --- a/rebar.config +++ b/rebar.config @@ -36,7 +36,7 @@ {cowboy_draining_server, {git, "https://github.com/valitydev/cowboy_draining_server.git", {branch, "master"}}}, {woody, {git, "https://github.com/valitydev/woody_erlang.git", {tag, "v1.1.0"}}}, {woody_user_identity, {git, "https://github.com/valitydev/woody_erlang_user_identity.git", {tag, "v1.1.0"}}}, - {damsel, {git, "https://github.com/valitydev/damsel.git", {tag, "v2.2.17"}}}, + {damsel, {git, "https://github.com/valitydev/damsel.git", {tag, "v2.2.21"}}}, {bender_proto, {git, "https://github.com/valitydev/bender-proto.git", {branch, "master"}}}, {bender_client, {git, "https://github.com/valitydev/bender-client-erlang.git", {tag, "v1.1.0"}}}, {dmt_client, {git, "https://github.com/valitydev/dmt_client.git", {tag, "v2.0.3"}}}, @@ -126,7 +126,13 @@ {erlfmt, [ {print_width, 120}, - {files, ["apps/capi*/{src,include,test}/*.{hrl,erl}", "rebar.config", "elvis.config"]} + {files, [ + "apps/capi*/{src,include,test}/*.{hrl,erl}", + "apps/capi*/rebar.config", + "rebar.config", + "elvis.config", + "config/sys.config" + ]} ]}. {covertool, [ diff --git a/rebar.lock b/rebar.lock index 61fc5a6..e42f5f8 100644 --- a/rebar.lock +++ b/rebar.lock @@ -41,7 +41,7 @@ {<<"ctx">>,{pkg,<<"ctx">>,<<"0.6.0">>},2}, {<<"damsel">>, {git,"https://github.com/valitydev/damsel.git", - {ref,"f831d3aa5fdfd0338b41af44d1eeffe810ca9708"}}, + {ref,"0ac1d9c85e61a3f7428e1a6bc56330116e5a8129"}}, 0}, {<<"dmt_client">>, {git,"https://github.com/valitydev/dmt_client.git",