ED-57: payment handler bouncer integration (#527)

This commit is contained in:
Boris 2021-04-30 12:26:47 +03:00 committed by GitHub
parent c533defaf1
commit 56137dfba0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 1398 additions and 1087 deletions

View File

@ -233,34 +233,6 @@ decode_bank_card(#domain_BankCard{
% <<"tokenization_method">> => TokenizationMethod
}).
% =======
% 'token' = Token,
% 'payment_system' = PaymentSystem,
% 'bin' = Bin,
% 'last_digits' = LastDigits,
% 'token_provider' = TokenProvider,
% 'issuer_country' = IssuerCountry,
% 'bank_name' = BankName,
% 'metadata' = Metadata,
% 'is_cvv_empty' = IsCVVEmpty
% % 'tokenization_method' = TokenizationMethod
% }) ->
% capi_utils:map_to_base64url(genlib_map:compact(#{
% <<"type" >> => <<"bank_card">>,
% <<"token" >> => Token,
% <<"payment_system">> => PaymentSystem,
% <<"bin" >> => Bin,
% <<"masked_pan" >> => LastDigits,
% <<"token_provider">> => TokenProvider,
% <<"issuer_country">> => IssuerCountry,
% <<"bank_name" >> => BankName,
% <<"metadata" >> => decode_bank_card_metadata(Metadata),
% <<"is_cvv_empty" >> => decode_bank_card_cvv_flag(IsCVVEmpty)
% % TODO: Uncomment or delete this when we negotiate deploying non-breaking changes
% % <<"tokenization_method">> => TokenizationMethod
% })).
% >>>>>>> master
decode_bank_card_cvv_flag(undefined) ->
undefined;
decode_bank_card_cvv_flag(CVVFlag) when is_atom(CVVFlag) ->

View File

@ -15,85 +15,97 @@
Req :: capi_handler:request_data(),
Context :: capi_handler:processing_context()
) -> {ok, capi_handler:request_state()} | {error, noimpl}.
prepare(OperationID, Req, Context) when
OperationID =:= 'GetPaymentInstitutions' orelse
OperationID =:= 'GetPaymentInstitutionByRef' orelse
OperationID =:= 'GetPaymentInstitutionPaymentTerms' orelse
OperationID =:= 'GetPaymentInstitutionPayoutMethods' orelse
OperationID =:= 'GetPaymentInstitutionPayoutSchedules'
->
Authorize = fun() -> {ok, capi_auth:authorize_operation(OperationID, [], Context, Req)} end,
Process = fun() -> process_request(OperationID, Context, Req) end,
prepare(OperationID = 'GetPaymentInstitutions', Req, #{woody_context := WoodyContext} = Context) ->
Authorize = mk_authorize_operation(OperationID, Context, Req),
Process = fun() ->
try
Residence = capi_handler_encoder:encode_residence(genlib_map:get(residence, Req)),
Realm = genlib_map:get(realm, Req),
{ok, PaymentInstObjects} = capi_domain:get_payment_institutions(WoodyContext),
Resp =
lists:filtermap(
fun(P) ->
case check_payment_institution(Realm, Residence, P) of
true ->
{true, decode_payment_institution_obj(P)};
false ->
false
end
end,
PaymentInstObjects
),
{ok, {200, #{}, Resp}}
catch
throw:{encode_residence, invalid_residence} ->
{ok, logic_error(invalidRequest, <<"Invalid residence">>)}
end
end,
{ok, #{authorize => Authorize, process => Process}};
prepare(OperationID = 'GetPaymentInstitutionByRef', Req, Context) ->
Authorize = mk_authorize_operation(OperationID, Context, Req),
Process = fun() ->
PaymentInstitutionID = genlib:to_int(maps:get(paymentInstitutionID, Req)),
case capi_domain:get({payment_institution, ?payment_institution_ref(PaymentInstitutionID)}, Context) of
{ok, PaymentInstitution} ->
{ok, {200, #{}, decode_payment_institution_obj(PaymentInstitution)}};
{error, not_found} ->
{ok, general_error(404, <<"Payment institution not found">>)}
end
end,
{ok, #{authorize => Authorize, process => Process}};
prepare(OperationID = 'GetPaymentInstitutionPaymentTerms', Req, Context) ->
Authorize = mk_authorize_operation(OperationID, Context, Req),
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)}};
{exception, #payproc_PaymentInstitutionNotFound{}} ->
{ok, general_error(404, <<"Payment institution not found">>)}
end
end,
{ok, #{authorize => Authorize, process => Process}};
prepare(OperationID = 'GetPaymentInstitutionPayoutMethods', Req, Context) ->
Authorize = mk_authorize_operation(OperationID, Context, Req),
Process = fun() ->
PaymentInstitutionID = genlib:to_int(maps:get(paymentInstitutionID, Req)),
case compute_payment_institution_terms(PaymentInstitutionID, prepare_request_varset(Req, Context), Context) of
{ok, #domain_TermSet{payouts = #domain_PayoutsServiceTerms{payout_methods = PayoutMethods}}} ->
{ok, {200, #{}, decode_payout_methods_selector(PayoutMethods)}};
{ok, #domain_TermSet{payouts = undefined}} ->
{ok, general_error(404, <<"Automatic payouts not allowed">>)};
{exception, #payproc_PaymentInstitutionNotFound{}} ->
{ok, general_error(404, <<"Payment institution not found">>)}
end
end,
{ok, #{authorize => Authorize, process => Process}};
prepare(OperationID = 'GetPaymentInstitutionPayoutSchedules', Req, Context) ->
Authorize = mk_authorize_operation(OperationID, Context, Req),
Process = fun() ->
PaymentInstitutionID = genlib:to_int(maps:get(paymentInstitutionID, Req)),
case compute_payment_institution_terms(PaymentInstitutionID, prepare_request_varset(Req, Context), Context) of
{ok, #domain_TermSet{payouts = #domain_PayoutsServiceTerms{payout_schedules = Schedules}}} ->
{ok, {200, #{}, decode_business_schedules_selector(Schedules)}};
{ok, #domain_TermSet{payouts = undefined}} ->
{ok, general_error(404, <<"Automatic payouts not allowed">>)};
{exception, #payproc_PaymentInstitutionNotFound{}} ->
{ok, general_error(404, <<"Payment institution not found">>)}
end
end,
{ok, #{authorize => Authorize, process => Process}};
prepare(_OperationID, _Req, _Context) ->
{error, noimpl}.
-spec process_request(
OperationID :: capi_handler:operation_id(),
Context :: capi_handler:processing_context(),
ReqState :: capi_handler:request_state()
) -> {ok, capi_handler:response()}.
process_request('GetPaymentInstitutions', #{woody_context := WoodyContext}, Req) ->
try
Residence = capi_handler_encoder:encode_residence(genlib_map:get(residence, Req)),
Realm = genlib_map:get(realm, Req),
{ok, PaymentInstObjects} = capi_domain:get_payment_institutions(WoodyContext),
Resp =
lists:filtermap(
fun(P) ->
case check_payment_institution(Realm, Residence, P) of
true ->
{true, decode_payment_institution_obj(P)};
false ->
false
end
end,
PaymentInstObjects
),
{ok, {200, #{}, Resp}}
catch
throw:{encode_residence, invalid_residence} ->
{ok, logic_error(invalidRequest, <<"Invalid residence">>)}
end;
process_request('GetPaymentInstitutionByRef', #{woody_context := WoodyContext}, Req) ->
PaymentInstitutionID = genlib:to_int(maps:get(paymentInstitutionID, Req)),
case capi_domain:get({payment_institution, ?payment_institution_ref(PaymentInstitutionID)}, WoodyContext) of
{ok, PaymentInstitution} ->
{ok, {200, #{}, decode_payment_institution_obj(PaymentInstitution)}};
{error, not_found} ->
{ok, general_error(404, <<"Payment institution not found">>)}
end;
process_request('GetPaymentInstitutionPaymentTerms', Context, Req) ->
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)}};
{exception, #payproc_PaymentInstitutionNotFound{}} ->
{ok, general_error(404, <<"Payment institution not found">>)}
end;
process_request('GetPaymentInstitutionPayoutMethods', Context, Req) ->
PaymentInstitutionID = genlib:to_int(maps:get(paymentInstitutionID, Req)),
case compute_payment_institution_terms(PaymentInstitutionID, prepare_request_varset(Req, Context), Context) of
{ok, #domain_TermSet{payouts = #domain_PayoutsServiceTerms{payout_methods = PayoutMethods}}} ->
{ok, {200, #{}, decode_payout_methods_selector(PayoutMethods)}};
{ok, #domain_TermSet{payouts = undefined}} ->
{ok, general_error(404, <<"Automatic payouts not allowed">>)};
{exception, #payproc_PaymentInstitutionNotFound{}} ->
{ok, general_error(404, <<"Payment institution not found">>)}
end;
process_request('GetPaymentInstitutionPayoutSchedules', Context, Req) ->
PaymentInstitutionID = genlib:to_int(maps:get(paymentInstitutionID, Req)),
case compute_payment_institution_terms(PaymentInstitutionID, prepare_request_varset(Req, Context), Context) of
{ok, #domain_TermSet{payouts = #domain_PayoutsServiceTerms{payout_schedules = Schedules}}} ->
{ok, {200, #{}, decode_business_schedules_selector(Schedules)}};
{ok, #domain_TermSet{payouts = undefined}} ->
{ok, general_error(404, <<"Automatic payouts not allowed">>)};
{exception, #payproc_PaymentInstitutionNotFound{}} ->
{ok, general_error(404, <<"Payment institution not found">>)}
end.
%%
mk_authorize_operation(OperationID, Context, Req) ->
fun() ->
Prototypes = [
{operation, #{id => OperationID}}
],
{ok, capi_auth:authorize_operation(OperationID, Prototypes, Context, Req)}
end.
check_payment_institution(Realm, Residence, PaymentInstitution) ->
check_payment_institution_realm(Realm, PaymentInstitution) andalso
check_payment_institution_residence(Residence, PaymentInstitution).

View File

@ -15,412 +15,480 @@
Req :: capi_handler:request_data(),
Context :: capi_handler:processing_context()
) -> {ok, capi_handler:request_state()} | {error, noimpl}.
prepare(OperationID, Req, Context) when
OperationID =:= 'CreatePayment' orelse
OperationID =:= 'GetPayments' orelse
OperationID =:= 'GetPaymentByID' orelse
OperationID =:= 'GetRefundByExternalID' orelse
OperationID =:= 'GetPaymentByExternalID' orelse
OperationID =:= 'CancelPayment' orelse
OperationID =:= 'CapturePayment' orelse
OperationID =:= 'CreateRefund' orelse
OperationID =:= 'GetRefunds' orelse
OperationID =:= 'GetRefundByID' orelse
OperationID =:= 'GetChargebacks' orelse
OperationID =:= 'GetChargebackByID'
->
Authorize = fun() -> {ok, capi_auth:authorize_operation(OperationID, [], Context, Req)} end,
Process = fun() -> process_request(OperationID, Context, Req) end,
{ok, #{authorize => Authorize, process => Process}};
prepare(_OperationID, _Req, _Context) ->
{error, noimpl}.
-spec process_request(
OperationID :: capi_handler:operation_id(),
Context :: capi_handler:processing_context(),
ReqState :: capi_handler:request_state()
) -> {ok, capi_handler:response()}.
process_request('CreatePayment' = OperationID, Context, Req) ->
InvoiceID = maps:get('invoiceID', Req),
prepare(OperationID = 'CreatePayment', Req, Context) ->
InvoiceID = maps:get(invoiceID, Req),
Invoice = map_result(get_invoice_by_id(InvoiceID, Context)),
PaymentParams = maps:get('PaymentParams', Req),
PartyID = capi_handler_utils:get_party_id(Context),
Result =
Authorize = fun() ->
Prototypes = [
{operation, #{id => OperationID, invoice => InvoiceID}},
{payproc, #{invoice => Invoice}}
],
{ok, capi_auth:authorize_operation(OperationID, Prototypes, Context, Req)}
end,
Process = fun() ->
try
create_payment(InvoiceID, PartyID, PaymentParams, Context, OperationID)
catch
throw:Error when
Error =:= invalid_token orelse
Error =:= invalid_payment_session orelse
Error =:= invalid_processing_deadline
->
{error, Error};
throw:Error = {external_id_conflict, _, _, _} ->
{error, Error}
end,
case Result of
{ok, Payment} ->
{ok, {201, #{}, decode_invoice_payment(InvoiceID, Payment, Context)}};
{exception, Exception} ->
case Exception of
#payproc_InvalidInvoiceStatus{} ->
capi_handler:respond_if_undefined(Invoice, general_error(404, <<"Invoice not found">>)),
case create_payment(Invoice, PaymentParams, Context, OperationID) of
{ok, Payment} ->
{ok, {201, #{}, decode_invoice_payment(InvoiceID, Payment, Context)}};
{exception, #payproc_InvalidInvoiceStatus{}} ->
{ok, logic_error(invalidInvoiceStatus, <<"Invalid invoice status">>)};
#payproc_InvoicePaymentPending{} ->
{exception, #payproc_InvoicePaymentPending{}} ->
ErrorResp = logic_error(
invoicePaymentPending,
<<"Invoice payment pending">>
),
{ok, ErrorResp};
#'InvalidRequest'{errors = Errors} ->
{exception, #'InvalidRequest'{errors = Errors}} ->
FormattedErrors = capi_handler_utils:format_request_errors(Errors),
{ok, logic_error(invalidRequest, FormattedErrors)};
#payproc_InvalidPartyStatus{} ->
{exception, #payproc_InvalidPartyStatus{}} ->
{ok, logic_error(invalidPartyStatus, <<"Invalid party status">>)};
#payproc_InvalidShopStatus{} ->
{exception, #payproc_InvalidShopStatus{}} ->
{ok, logic_error(invalidShopStatus, <<"Invalid shop status">>)};
#payproc_InvalidContractStatus{} ->
{exception, #payproc_InvalidContractStatus{}} ->
ErrorResp = logic_error(
invalidContractStatus,
<<"Invalid contract status">>
),
{ok, ErrorResp};
#payproc_InvalidRecurrentParentPayment{} ->
{exception, #payproc_InvalidRecurrentParentPayment{}} ->
ErrorResp = logic_error(
invalidRecurrentParent,
<<"Specified recurrent parent is invalid">>
),
{ok, ErrorResp};
#payproc_InvalidUser{} ->
{exception, #payproc_InvalidUser{}} ->
{ok, general_error(404, <<"Invoice not found">>)};
#payproc_InvoiceNotFound{} ->
{exception, #payproc_InvoiceNotFound{}} ->
{ok, general_error(404, <<"Invoice not found">>)}
end;
{error, invalid_token} ->
{ok,
logic_error(
invalidPaymentToolToken,
<<"Specified payment tool token is invalid">>
)};
{error, invalid_payment_session} ->
{ok,
logic_error(
invalidPaymentSession,
<<"Specified payment session is invalid">>
)};
{error, invalid_processing_deadline} ->
{ok,
logic_error(
invalidProcessingDeadline,
<<"Specified processing deadline is invalid">>
)};
{error, {external_id_conflict, PaymentID, ExternalID, _Schema}} ->
{ok, logic_error(externalIDConflict, {PaymentID, ExternalID})}
end;
process_request('GetPayments', Context, Req) ->
end
catch
throw:invalid_token ->
{ok,
logic_error(
invalidPaymentToolToken,
<<"Specified payment tool token is invalid">>
)};
throw:invalid_payment_session ->
{ok,
logic_error(
invalidPaymentSession,
<<"Specified payment session is invalid">>
)};
throw:invalid_processing_deadline ->
{ok,
logic_error(
invalidProcessingDeadline,
<<"Specified processing deadline is invalid">>
)};
throw:{external_id_conflict, PaymentID, ExternalID, _Schema} ->
{ok, logic_error(externalIDConflict, {PaymentID, ExternalID})}
end
end,
{ok, #{authorize => Authorize, process => Process}};
prepare(OperationID = 'GetPayments', Req, Context) ->
InvoiceID = maps:get(invoiceID, Req),
case capi_handler_utils:get_invoice_by_id(InvoiceID, Context) of
{ok, #'payproc_Invoice'{payments = Payments}} ->
{ok, {200, #{}, [decode_invoice_payment(InvoiceID, P, Context) || P <- Payments]}};
{exception, Exception} ->
case Exception of
#payproc_InvalidUser{} ->
{ok, general_error(404, <<"Invoice not found">>)};
#payproc_InvoiceNotFound{} ->
{ok, general_error(404, <<"Invoice not found">>)}
end
end;
process_request('GetPaymentByID', Context, Req) ->
InvoiceID = maps:get(invoiceID, Req),
case capi_handler_utils:get_payment_by_id(InvoiceID, maps:get(paymentID, Req), Context) of
{ok, Payment} ->
{ok, {200, #{}, decode_invoice_payment(InvoiceID, Payment, Context)}};
{exception, Exception} ->
case Exception of
#payproc_InvoicePaymentNotFound{} ->
{ok, general_error(404, <<"Payment not found">>)};
#payproc_InvalidUser{} ->
{ok, general_error(404, <<"Invoice not found">>)};
#payproc_InvoiceNotFound{} ->
{ok, general_error(404, <<"Invoice not found">>)}
end
end;
process_request('GetRefundByExternalID', Context, Req) ->
ExternalID = maps:get(externalID, Req),
case get_refund_by_external_id(ExternalID, Context) of
{ok, Refund} ->
{ok, {200, #{}, capi_handler_decoder_invoicing:decode_refund(Refund, Context)}};
{error, internal_id_not_found} ->
{ok, general_error(404, <<"Refund not found">>)};
{error, payment_not_found} ->
{ok, general_error(404, <<"Payment not found">>)};
{error, invoice_not_found} ->
{ok, general_error(404, <<"Invoice not found">>)};
{exception, Exception} ->
case Exception of
#payproc_InvoicePaymentRefundNotFound{} ->
{ok, general_error(404, <<"Refund not found">>)};
#payproc_InvoicePaymentNotFound{} ->
{ok, general_error(404, <<"Payment not found">>)};
#payproc_InvalidUser{} ->
{ok, general_error(404, <<"Invoice not found">>)};
#payproc_InvoiceNotFound{} ->
{ok, general_error(404, <<"Invoice not found">>)}
end
end;
process_request('GetPaymentByExternalID', Context, Req) ->
ExternalID = maps:get(externalID, Req),
case get_payment_by_external_id(ExternalID, Context) of
{ok, InvoiceID, Payment} ->
{ok, {200, #{}, decode_invoice_payment(InvoiceID, Payment, Context)}};
{error, internal_id_not_found} ->
{ok, general_error(404, <<"Payment not found">>)};
{error, invoice_not_found} ->
{ok, general_error(404, <<"Invoice not found">>)};
{exception, Exception} ->
case Exception of
#payproc_InvoicePaymentNotFound{} ->
{ok, general_error(404, <<"Payment not found">>)};
#payproc_InvalidUser{} ->
{ok, general_error(404, <<"Invoice not found">>)};
#payproc_InvoiceNotFound{} ->
{ok, general_error(404, <<"Invoice not found">>)}
end
end;
process_request('CancelPayment', Context, Req) ->
CallArgs = {maps:get(invoiceID, Req), maps:get(paymentID, Req), maps:get(<<"reason">>, maps:get('Reason', Req))},
Call = {invoicing, 'CancelPayment', CallArgs},
case capi_handler_utils:service_call_with([user_info], Call, Context) of
{ok, _} ->
{ok, {202, #{}, undefined}};
{exception, Exception} ->
case Exception of
#payproc_InvoicePaymentNotFound{} ->
{ok, general_error(404, <<"Payment not found">>)};
#payproc_InvalidPaymentStatus{} ->
{ok, logic_error(invalidPaymentStatus, <<"Invalid payment status">>)};
#payproc_InvalidUser{} ->
{ok, general_error(404, <<"Invoice not found">>)};
#payproc_InvoiceNotFound{} ->
{ok, general_error(404, <<"Invoice not found">>)};
#'InvalidRequest'{errors = Errors} ->
FormattedErrors = capi_handler_utils:format_request_errors(Errors),
{ok, logic_error(invalidRequest, FormattedErrors)};
#payproc_OperationNotPermitted{} ->
ErrorResp = logic_error(
operationNotPermitted,
<<"Operation not permitted">>
),
{ok, ErrorResp};
#payproc_InvalidPartyStatus{} ->
{ok, logic_error(invalidPartyStatus, <<"Invalid party status">>)};
#payproc_InvalidShopStatus{} ->
{ok, logic_error(invalidShopStatus, <<"Invalid shop status">>)}
end
end;
process_request('CapturePayment', Context, Req) ->
CaptureParams = maps:get('CaptureParams', Req),
Invoice = map_result(get_invoice_by_id(InvoiceID, Context)),
Authorize = fun() ->
Prototypes = [
{operation, #{id => OperationID, invoice => InvoiceID}},
{payproc, #{invoice => Invoice}}
],
{ok, capi_auth:authorize_operation(OperationID, Prototypes, Context, Req)}
end,
Process = fun() ->
capi_handler:respond_if_undefined(Invoice, general_error(404, <<"Invoice not found">>)),
#'payproc_Invoice'{payments = Payments} = Invoice,
{ok, {200, #{}, [decode_invoice_payment(InvoiceID, P, Context) || P <- Payments]}}
end,
{ok, #{authorize => Authorize, process => Process}};
prepare(OperationID = 'GetPaymentByID', Req, Context) ->
InvoiceID = maps:get(invoiceID, Req),
PaymentID = maps:get(paymentID, Req),
try
CallArgs = {
InvoiceID,
PaymentID,
#payproc_InvoicePaymentCaptureParams{
reason = maps:get(<<"reason">>, CaptureParams),
cash = encode_optional_cash(CaptureParams, InvoiceID, PaymentID, Context),
cart = capi_handler_encoder:encode_invoice_cart(CaptureParams)
}
},
Call = {invoicing, 'CapturePayment', CallArgs},
capi_handler_utils:service_call_with([user_info], Call, Context)
of
{ok, _} ->
{ok, {202, #{}, undefined}};
{exception, Exception} ->
case Exception of
#payproc_InvoicePaymentNotFound{} ->
{ok, general_error(404, <<"Payment not found">>)};
#payproc_InvalidPaymentStatus{} ->
{ok, logic_error(invalidPaymentStatus, <<"Invalid payment status">>)};
#payproc_InvalidUser{} ->
{ok, general_error(404, <<"Invoice not found">>)};
#payproc_InvoiceNotFound{} ->
{ok, general_error(404, <<"Invoice not found">>)};
#'InvalidRequest'{errors = Errors} ->
FormattedErrors = capi_handler_utils:format_request_errors(Errors),
{ok, logic_error(invalidRequest, FormattedErrors)};
#payproc_OperationNotPermitted{} ->
ErrorResp = logic_error(
operationNotPermitted,
<<"Operation not permitted">>
),
{ok, ErrorResp};
#payproc_InvalidPartyStatus{} ->
{ok, logic_error(invalidPartyStatus, <<"Invalid party status">>)};
#payproc_InvalidShopStatus{} ->
{ok, logic_error(invalidShopStatus, <<"Invalid shop status">>)};
#payproc_InconsistentCaptureCurrency{payment_currency = PaymentCurrency} ->
{ok,
logic_error(
inconsistentCaptureCurrency,
io_lib:format("Correct currency: ~p", [PaymentCurrency])
)};
#payproc_AmountExceededCaptureBalance{payment_amount = PaymentAmount} ->
{ok,
logic_error(
amountExceededCaptureBalance,
io_lib:format("Max amount: ~p", [PaymentAmount])
)}
end
catch
throw:invoice_cart_empty ->
{ok, logic_error(invalidInvoiceCart, <<"Wrong size. Path to item: cart">>)}
end;
process_request('CreateRefund' = OperationID, Context, Req) ->
Invoice = map_result(get_invoice_by_id(InvoiceID, Context)),
Authorize = fun() ->
Prototypes = [
{operation, #{id => OperationID, invoice => InvoiceID, payment => PaymentID}},
{payproc, #{invoice => Invoice}}
],
{ok, capi_auth:authorize_operation(OperationID, Prototypes, Context, Req)}
end,
Process = fun() ->
capi_handler:respond_if_undefined(Invoice, general_error(404, <<"Invoice not found">>)),
case find_payment_by_id(PaymentID, Invoice) of
{ok, Payment} ->
{ok, {200, #{}, decode_invoice_payment(InvoiceID, Payment, Context)}};
{error, payment_not_found} ->
{ok, general_error(404, <<"Payment not found">>)}
end
end,
{ok, #{authorize => Authorize, process => Process}};
prepare(OperationID = 'GetPaymentByExternalID', Req, Context) ->
ExternalID = maps:get(externalID, Req),
InternalID = map_result(get_payment_by_external_id(ExternalID, Context)),
Invoice = map_result(
maybe(InternalID, fun({InvoiceID, _}) ->
get_invoice_by_id(InvoiceID, Context)
end)
),
OperationPrototype = maybe(
InternalID,
fun({InvoiceID, PaymentID}) ->
#{id => OperationID, invoice => InvoiceID, payment => PaymentID}
end
),
Authorize = fun() ->
Prototypes = [
{operation, genlib:define(OperationPrototype, #{id => OperationID})},
{payproc, #{invoice => Invoice}}
],
{ok, capi_auth:authorize_operation(OperationID, Prototypes, Context, Req)}
end,
Process = fun() ->
capi_handler:respond_if_undefined(InternalID, general_error(404, <<"Payment not found">>)),
capi_handler:respond_if_undefined(Invoice, general_error(404, <<"Invoice not found">>)),
{InvoiceID, PaymentID} = InternalID,
case find_payment_by_id(PaymentID, Invoice) of
{ok, Payment} ->
{ok, {200, #{}, decode_invoice_payment(InvoiceID, Payment, Context)}};
{error, payment_not_found} ->
{ok, general_error(404, <<"Payment not found">>)}
end
end,
{ok, #{authorize => Authorize, process => Process}};
prepare(OperationID = 'CapturePayment', Req, Context) ->
InvoiceID = maps:get(invoiceID, Req),
PaymentID = maps:get(paymentID, Req),
Authorize = fun() ->
Prototypes = [
{operation, #{id => OperationID, invoice => InvoiceID, payment => PaymentID}},
{payproc, #{invoice => InvoiceID}}
],
{ok, capi_auth:authorize_operation(OperationID, Prototypes, Context, Req)}
end,
Process = fun() ->
Params = maps:get('CaptureParams', Req),
try
CaptureParams = #payproc_InvoicePaymentCaptureParams{
reason = maps:get(<<"reason">>, Params),
cash = encode_optional_cash(Params, InvoiceID, PaymentID, Context),
cart = capi_handler_encoder:encode_invoice_cart(Params)
},
CallArgs = {InvoiceID, PaymentID, CaptureParams},
Call = {invoicing, 'CapturePayment', CallArgs},
capi_handler_utils:service_call_with([user_info], Call, Context)
of
{ok, _} ->
{ok, {202, #{}, undefined}};
{exception, Exception} ->
case Exception of
#payproc_InvoicePaymentNotFound{} ->
{ok, general_error(404, <<"Payment not found">>)};
#payproc_InvalidPaymentStatus{} ->
{ok, logic_error(invalidPaymentStatus, <<"Invalid payment status">>)};
#payproc_InvalidUser{} ->
{ok, general_error(404, <<"Invoice not found">>)};
#payproc_InvoiceNotFound{} ->
{ok, general_error(404, <<"Invoice not found">>)};
#'InvalidRequest'{errors = Errors} ->
FormattedErrors = capi_handler_utils:format_request_errors(Errors),
{ok, logic_error(invalidRequest, FormattedErrors)};
#payproc_OperationNotPermitted{} ->
ErrorResp = logic_error(
operationNotPermitted,
<<"Operation not permitted">>
),
{ok, ErrorResp};
#payproc_InvalidPartyStatus{} ->
{ok, logic_error(invalidPartyStatus, <<"Invalid party status">>)};
#payproc_InvalidShopStatus{} ->
{ok, logic_error(invalidShopStatus, <<"Invalid shop status">>)};
#payproc_InconsistentCaptureCurrency{payment_currency = PaymentCurrency} ->
{ok,
logic_error(
inconsistentCaptureCurrency,
io_lib:format("Correct currency: ~p", [PaymentCurrency])
)};
#payproc_AmountExceededCaptureBalance{payment_amount = PaymentAmount} ->
{ok,
logic_error(
amountExceededCaptureBalance,
io_lib:format("Max amount: ~p", [PaymentAmount])
)}
end
catch
throw:invoice_cart_empty ->
{ok, logic_error(invalidInvoiceCart, <<"Wrong size. Path to item: cart">>)}
end
end,
{ok, #{authorize => Authorize, process => Process}};
prepare(OperationID = 'CancelPayment', Req, Context) ->
InvoiceID = maps:get(invoiceID, Req),
PaymentID = maps:get(paymentID, Req),
Authorize = fun() ->
Prototypes = [
{operation, #{id => OperationID, invoice => InvoiceID}},
{payproc, #{invoice => InvoiceID}}
],
{ok, capi_auth:authorize_operation(OperationID, Prototypes, Context, Req)}
end,
Process = fun() ->
Reason = maps:get(<<"reason">>, maps:get('Reason', Req)),
CallArgs = {InvoiceID, PaymentID, Reason},
Call = {invoicing, 'CancelPayment', CallArgs},
case capi_handler_utils:service_call_with([user_info], Call, Context) of
{ok, _} ->
{ok, {202, #{}, undefined}};
{exception, Exception} ->
case Exception of
#payproc_InvoicePaymentNotFound{} ->
{ok, general_error(404, <<"Payment not found">>)};
#payproc_InvalidPaymentStatus{} ->
{ok, logic_error(invalidPaymentStatus, <<"Invalid payment status">>)};
#payproc_InvalidUser{} ->
{ok, general_error(404, <<"Invoice not found">>)};
#payproc_InvoiceNotFound{} ->
{ok, general_error(404, <<"Invoice not found">>)};
#'InvalidRequest'{errors = Errors} ->
FormattedErrors = capi_handler_utils:format_request_errors(Errors),
{ok, logic_error(invalidRequest, FormattedErrors)};
#payproc_OperationNotPermitted{} ->
ErrorResp = logic_error(
operationNotPermitted,
<<"Operation not permitted">>
),
{ok, ErrorResp};
#payproc_InvalidPartyStatus{} ->
{ok, logic_error(invalidPartyStatus, <<"Invalid party status">>)};
#payproc_InvalidShopStatus{} ->
{ok, logic_error(invalidShopStatus, <<"Invalid shop status">>)}
end
end
end,
{ok, #{authorize => Authorize, process => Process}};
prepare(OperationID = 'CreateRefund', Req, Context) ->
InvoiceID = maps:get('invoiceID', Req),
PaymentID = maps:get(paymentID, Req),
RefundParams = maps:get('RefundParams', Req),
try create_refund(InvoiceID, PaymentID, RefundParams, Context, OperationID) of
{ok, Refund} ->
{ok, {201, #{}, capi_handler_decoder_invoicing:decode_refund(Refund, Context)}};
{exception, Exception} ->
case Exception of
#payproc_InvalidUser{} ->
{ok, general_error(404, <<"Invoice not found">>)};
#payproc_InvoicePaymentNotFound{} ->
{ok, general_error(404, <<"Payment not found">>)};
#payproc_InvoiceNotFound{} ->
{ok, general_error(404, <<"Invoice not found">>)};
#payproc_InvalidPartyStatus{} ->
{ok, logic_error(invalidPartyStatus, <<"Invalid party status">>)};
#payproc_InvalidShopStatus{} ->
{ok, logic_error(invalidShopStatus, <<"Invalid shop status">>)};
#payproc_InvalidContractStatus{} ->
ErrorResp = logic_error(
invalidContractStatus,
<<"Invalid contract status">>
),
{ok, ErrorResp};
#payproc_OperationNotPermitted{} ->
ErrorResp = logic_error(
operationNotPermitted,
<<"Operation not permitted">>
),
{ok, ErrorResp};
#payproc_InvalidPaymentStatus{} ->
ErrorResp = logic_error(
invalidPaymentStatus,
<<"Invalid invoice payment status">>
),
{ok, ErrorResp};
#payproc_InsufficientAccountBalance{} ->
{ok,
logic_error(
Authorize = fun() ->
Prototypes = [
{operation, #{id => OperationID, invoice => InvoiceID, payment => PaymentID}},
{payproc, #{invoice => InvoiceID}}
],
{ok, capi_auth:authorize_operation(OperationID, Prototypes, Context, Req)}
end,
Process = fun() ->
try create_refund(InvoiceID, PaymentID, RefundParams, Context, OperationID) of
{ok, Refund} ->
{ok, {201, #{}, capi_handler_decoder_invoicing:decode_refund(Refund, Context)}};
{exception, Exception} ->
case Exception of
#payproc_InvalidUser{} ->
{ok, general_error(404, <<"Invoice not found">>)};
#payproc_InvoicePaymentNotFound{} ->
{ok, general_error(404, <<"Payment not found">>)};
#payproc_InvoiceNotFound{} ->
{ok, general_error(404, <<"Invoice not found">>)};
#payproc_InvalidPartyStatus{} ->
{ok, logic_error(invalidPartyStatus, <<"Invalid party status">>)};
#payproc_InvalidShopStatus{} ->
{ok, logic_error(invalidShopStatus, <<"Invalid shop status">>)};
#payproc_InvalidContractStatus{} ->
ErrorResp = logic_error(
invalidContractStatus,
<<"Invalid contract status">>
),
{ok, ErrorResp};
#payproc_OperationNotPermitted{} ->
ErrorResp = logic_error(
operationNotPermitted,
<<"Operation not permitted">>
),
{ok, ErrorResp};
#payproc_InvalidPaymentStatus{} ->
ErrorResp = logic_error(
invalidPaymentStatus,
<<"Invalid invoice payment status">>
),
{ok, ErrorResp};
#payproc_InsufficientAccountBalance{} ->
ErrResp = logic_error(
insufficentAccountBalance,
<<"Operation can not be conducted because of insufficient funds on the merchant account">>
)};
#payproc_InvoicePaymentAmountExceeded{} ->
ErrorResp = logic_error(
invoicePaymentAmountExceeded,
<<"Payment amount exceeded">>
),
{ok, ErrorResp};
#payproc_InconsistentRefundCurrency{} ->
ErrorResp = logic_error(
inconsistentRefundCurrency,
<<"Inconsistent refund currency">>
),
{ok, ErrorResp};
#'InvalidRequest'{errors = Errors} ->
FormattedErrors = capi_handler_utils:format_request_errors(Errors),
{ok, logic_error(invalidRequest, FormattedErrors)}
end
catch
throw:invoice_cart_empty ->
{ok, logic_error(invalidInvoiceCart, <<"Wrong size. Path to item: cart">>)};
throw:{external_id_conflict, RefundID, ExternalID, _Schema} ->
{ok, logic_error(externalIDConflict, {RefundID, ExternalID})}
end;
process_request('GetRefunds', Context, Req) ->
case capi_handler_utils:get_payment_by_id(maps:get(invoiceID, Req), maps:get(paymentID, Req), Context) of
{ok, #payproc_InvoicePayment{refunds = Refunds}} ->
{ok,
{200, #{}, [
capi_handler_decoder_invoicing:decode_refund(R, Context)
|| #payproc_InvoicePaymentRefund{refund = R} <- Refunds
]}};
{exception, Exception} ->
case Exception of
#payproc_InvalidUser{} ->
{ok, general_error(404, <<"Invoice not found">>)};
#payproc_InvoicePaymentNotFound{} ->
{ok, general_error(404, <<"Payment not found">>)};
#payproc_InvoiceNotFound{} ->
{ok, general_error(404, <<"Invoice not found">>)}
end
end;
process_request('GetRefundByID', Context, Req) ->
case
capi_handler_utils:get_refund_by_id(
maps:get(invoiceID, Req),
maps:get(paymentID, Req),
maps:get(refundID, Req),
Context
)
of
{ok, Refund} ->
{ok, {200, #{}, capi_handler_decoder_invoicing:decode_refund(Refund, Context)}};
{exception, Exception} ->
case Exception of
#payproc_InvoicePaymentRefundNotFound{} ->
{ok, general_error(404, <<"Invoice payment refund not found">>)};
#payproc_InvoicePaymentNotFound{} ->
{ok, general_error(404, <<"Payment not found">>)};
#payproc_InvoiceNotFound{} ->
{ok, general_error(404, <<"Invoice not found">>)};
#payproc_InvalidUser{} ->
{ok, general_error(404, <<"Invoice not found">>)}
end
end;
process_request('GetChargebacks', Context, Req) ->
DecodeChargebackFun = fun(C) ->
capi_handler_decoder_invoicing:decode_chargeback(C#payproc_InvoicePaymentChargeback.chargeback, Context)
),
{ok, ErrResp};
#payproc_InvoicePaymentAmountExceeded{} ->
ErrorResp = logic_error(
invoicePaymentAmountExceeded,
<<"Payment amount exceeded">>
),
{ok, ErrorResp};
#payproc_InconsistentRefundCurrency{} ->
ErrorResp = logic_error(
inconsistentRefundCurrency,
<<"Inconsistent refund currency">>
),
{ok, ErrorResp};
#'InvalidRequest'{errors = Errors} ->
FormattedErrors = capi_handler_utils:format_request_errors(Errors),
{ok, logic_error(invalidRequest, FormattedErrors)}
end
catch
throw:invoice_cart_empty ->
{ok, logic_error(invalidInvoiceCart, <<"Wrong size. Path to item: cart">>)};
throw:{external_id_conflict, RefundID, ExternalID, _Schema} ->
{ok, logic_error(externalIDConflict, {RefundID, ExternalID})}
end
end,
case capi_handler_utils:get_payment_by_id(maps:get(invoiceID, Req), maps:get(paymentID, Req), Context) of
{ok, #payproc_InvoicePayment{chargebacks = Chargebacks}} ->
{ok, {200, #{}, [DecodeChargebackFun(C) || C <- Chargebacks]}};
{exception, Exception} ->
case Exception of
#payproc_InvalidUser{} ->
{ok, general_error(404, <<"Invoice not found">>)};
#payproc_InvoicePaymentNotFound{} ->
{ok, general_error(404, <<"Payment not found">>)};
#payproc_InvoiceNotFound{} ->
{ok, general_error(404, <<"Invoice not found">>)}
end
end;
process_request('GetChargebackByID', Context, Req) ->
CallArgs = {maps:get(invoiceID, Req), maps:get(paymentID, Req), maps:get(chargebackID, Req)},
Call = {invoicing, 'GetPaymentChargeback', CallArgs},
case capi_handler_utils:service_call_with([user_info], Call, Context) of
{ok, Chargeback} ->
{ok, {200, #{}, capi_handler_decoder_invoicing:decode_chargeback(Chargeback, Context)}};
{exception, Exception} ->
case Exception of
#payproc_InvoicePaymentChargebackNotFound{} ->
{ok, general_error(404, <<"Invoice payment chargeback not found">>)};
#payproc_InvoicePaymentNotFound{} ->
{ok, general_error(404, <<"Payment not found">>)};
#payproc_InvoiceNotFound{} ->
{ok, general_error(404, <<"Invoice not found">>)};
#payproc_InvalidUser{} ->
{ok, general_error(404, <<"Invoice not found">>)}
end
end.
{ok, #{authorize => Authorize, process => Process}};
prepare(OperationID = 'GetRefunds', Req, Context) ->
InvoiceID = maps:get(invoiceID, Req),
PaymentID = maps:get(paymentID, Req),
Invoice = map_result(get_invoice_by_id(InvoiceID, Context)),
Authorize = fun() ->
Prototypes = [
{operation, #{id => OperationID, invoice => InvoiceID, payment => PaymentID}},
{payproc, #{invoice => Invoice}}
],
{ok, capi_auth:authorize_operation(OperationID, Prototypes, Context, Req)}
end,
Process = fun() ->
capi_handler:respond_if_undefined(Invoice, general_error(404, <<"Invoice not found">>)),
case find_payment_by_id(PaymentID, Invoice) of
{ok, #payproc_InvoicePayment{refunds = Refunds}} ->
{ok,
{200, #{}, [
capi_handler_decoder_invoicing:decode_refund(R, Context)
|| #payproc_InvoicePaymentRefund{refund = R} <- Refunds
]}};
{error, payment_not_found} ->
{ok, general_error(404, <<"Payment not found">>)}
end
end,
{ok, #{authorize => Authorize, process => Process}};
prepare(OperationID = 'GetRefundByID', Req, Context) ->
InvoiceID = maps:get(invoiceID, Req),
PaymentID = maps:get(paymentID, Req),
RefundID = maps:get(refundID, Req),
Invoice = map_result(get_invoice_by_id(InvoiceID, Context)),
Payment = map_result(find_payment_by_id(PaymentID, Invoice)),
Authorize = fun() ->
Prototypes = [
{operation, #{id => OperationID, invoice => InvoiceID, payment => PaymentID, refund => RefundID}},
{payproc, #{invoice => Invoice}}
],
{ok, capi_auth:authorize_operation(OperationID, Prototypes, Context, Req)}
end,
Process = fun() ->
capi_handler:respond_if_undefined(Invoice, general_error(404, <<"Invoice not found">>)),
capi_handler:respond_if_undefined(Payment, general_error(404, <<"Payment not found">>)),
case find_refund_by_id(RefundID, Payment) of
{ok, #payproc_InvoicePaymentRefund{refund = Refund}} ->
{ok, {200, #{}, capi_handler_decoder_invoicing:decode_refund(Refund, Context)}};
{error, refund_not_found} ->
{ok, general_error(404, <<"Invoice payment refund not found">>)}
end
end,
{ok, #{authorize => Authorize, process => Process}};
prepare(OperationID = 'GetRefundByExternalID', Req, Context) ->
ExternalID = maps:get(externalID, Req),
InternalID = map_result(get_refund_by_external_id(ExternalID, Context)),
Invoice = map_result(
maybe(InternalID, fun({InvoiceID, _PaymentID, _RefundID}) ->
get_invoice_by_id(InvoiceID, Context)
end)
),
OperationPrototype = maybe(InternalID, fun({InvoiceID, PaymentID, RefundID}) ->
#{id => OperationID, invoice => InvoiceID, payment => PaymentID, refund => RefundID}
end),
Authorize = fun() ->
Prototypes = [
{operation, genlib:define(OperationPrototype, #{id => OperationID})},
{payproc, #{invoice => Invoice}}
],
{ok, capi_auth:authorize_operation(OperationID, Prototypes, Context, Req)}
end,
Process = fun() ->
capi_handler:respond_if_undefined(InternalID, general_error(404, <<"Refund not found">>)),
capi_handler:respond_if_undefined(Invoice, general_error(404, <<"Invoice not found">>)),
{_InvoiceID, PaymentID, RefundID} = InternalID,
Payment = map_result(find_payment_by_id(PaymentID, Invoice)),
capi_handler:respond_if_undefined(Payment, general_error(404, <<"Payment not found">>)),
case find_refund_by_id(RefundID, Payment) of
{ok, #payproc_InvoicePaymentRefund{refund = Refund}} ->
{ok, {200, #{}, capi_handler_decoder_invoicing:decode_refund(Refund, Context)}};
{error, refund_not_found} ->
{ok, general_error(404, <<"Invoice payment refund not found">>)}
end
end,
{ok, #{authorize => Authorize, process => Process}};
prepare(OperationID = 'GetChargebacks', Req, Context) ->
InvoiceID = maps:get(invoiceID, Req),
PaymentID = maps:get(paymentID, Req),
Invoice = map_result(get_invoice_by_id(InvoiceID, Context)),
Authorize = fun() ->
Prototypes = [
{operation, #{id => OperationID, invoice => InvoiceID, payment => PaymentID}},
{payproc, #{invoice => Invoice}}
],
{ok, capi_auth:authorize_operation(OperationID, Prototypes, Context, Req)}
end,
Process = fun() ->
capi_handler:respond_if_undefined(Invoice, general_error(404, <<"Invoice not found">>)),
DecodeChargebackFun = fun(C) ->
capi_handler_decoder_invoicing:decode_chargeback(C#payproc_InvoicePaymentChargeback.chargeback, Context)
end,
case find_payment_by_id(PaymentID, Invoice) of
{ok, #payproc_InvoicePayment{chargebacks = Chargebacks}} ->
{ok, {200, #{}, [DecodeChargebackFun(C) || C <- Chargebacks]}};
{error, payment_not_found} ->
{ok, general_error(404, <<"Payment not found">>)}
end
end,
{ok, #{authorize => Authorize, process => Process}};
prepare(OperationID = 'GetChargebackByID', Req, Context) ->
InvoiceID = maps:get(invoiceID, Req),
PaymentID = maps:get(paymentID, Req),
ChargebackID = maps:get(chargebackID, Req),
Invoice = map_result(get_invoice_by_id(InvoiceID, Context)),
Payment = map_result(find_payment_by_id(PaymentID, Invoice)),
Authorize = fun() ->
Prototypes = [
{operation, #{id => OperationID, invoice => InvoiceID, payment => PaymentID}},
{payproc, #{invoice => Invoice}}
],
{ok, capi_auth:authorize_operation(OperationID, Prototypes, Context, Req)}
end,
Process = fun() ->
capi_handler:respond_if_undefined(Invoice, general_error(404, <<"Invoice not found">>)),
capi_handler:respond_if_undefined(Payment, general_error(404, <<"Payment not found">>)),
case find_chargeback_by_id(ChargebackID, Payment) of
{ok, Chargeback} ->
{ok, {200, #{}, capi_handler_decoder_invoicing:decode_chargeback(Chargeback, Context)}};
{error, chargeback_not_found} ->
{ok, general_error(404, <<"Invoice payment chargeback not found">>)}
end
end,
{ok, #{authorize => Authorize, process => Process}};
prepare(_OperationID, _Req, _Context) ->
{error, noimpl}.
%%
create_payment(InvoiceID, PartyID, PaymentParams, Context, BenderPrefix) ->
create_payment(Invoice, PaymentParams, Context, BenderPrefix) ->
ExternalID = maps:get(<<"externalID">>, PaymentParams, undefined),
#payproc_Invoice{invoice = #domain_Invoice{id = InvoiceID, owner_id = PartyID}} = Invoice,
IdempotentKey = {BenderPrefix, PartyID, ExternalID},
{Payer, PaymentToolThrift} = decrypt_payer(maps:get(<<"payer">>, PaymentParams)),
@ -443,6 +511,62 @@ start_payment(ID, InvoiceID, ExternalID, PaymentParamsDecrypted, PaymentToolThri
Call = {invoicing, 'StartPayment', {InvoiceID, InvoicePaymentParams}},
capi_handler_utils:service_call_with([user_info], Call, Context).
find_payment_by_id(PaymentID, #payproc_Invoice{payments = Payments}) ->
Fun = fun(#payproc_InvoicePayment{payment = #domain_InvoicePayment{id = ID}}) ->
PaymentID == ID
end,
case find_by(Fun, genlib:define(Payments, [])) of
undefined ->
{error, payment_not_found};
Payment ->
{ok, Payment}
end.
find_refund_by_id(RefundID, #payproc_InvoicePayment{refunds = Refunds}) ->
Fun = fun(#payproc_InvoicePaymentRefund{refund = Refund}) ->
Refund#domain_InvoicePaymentRefund.id == RefundID
end,
case find_by(Fun, genlib:define(Refunds, [])) of
undefined ->
{error, refund_not_found};
Refund ->
{ok, Refund}
end.
find_chargeback_by_id(ChargebackID, #payproc_InvoicePayment{chargebacks = Chargebacks}) ->
Fun = fun(#payproc_InvoicePaymentChargeback{chargeback = Chargeback}) ->
Chargeback#domain_InvoicePaymentChargeback.id == ChargebackID
end,
case find_by(Fun, genlib:define(Chargebacks, [])) of
undefined ->
{error, chargeback_not_found};
Chargeback ->
{ok, Chargeback}
end.
find_by(Fun, [E | Rest]) ->
case Fun(E) of
true -> E;
false -> find_by(Fun, Rest)
end;
find_by(_, []) ->
undefined.
get_invoice_by_id(InvoiceID, Context) ->
case capi_handler_utils:get_invoice_by_id(InvoiceID, Context) of
{ok, Invoice} ->
{ok, Invoice};
{exception, #payproc_InvalidUser{}} ->
{error, invalid_user};
{exception, #payproc_InvoiceNotFound{}} ->
{error, invoice_not_found}
end.
map_result({ok, Value}) ->
Value;
map_result(_) ->
undefined.
decrypt_payer(#{<<"payerType">> := <<"PaymentResourcePayer">>} = Payer) ->
#{<<"paymentToolToken">> := Token} = Payer,
Payer2 = maps:without([<<"paymentToolToken">>], Payer),
@ -559,39 +683,24 @@ get_refund_by_external_id(ExternalID, #{woody_context := WoodyContext} = Context
IdempotentKey = {'CreateRefund', PartyID, ExternalID},
case capi_bender:get_internal_id(IdempotentKey, WoodyContext) of
{ok, RefundID, CtxData} ->
InvoiceID = maps:get(<<"invoice_id">>, CtxData, undefined),
PaymentID = maps:get(<<"payment_id">>, CtxData, undefined),
get_refund(InvoiceID, PaymentID, RefundID, Context);
Error ->
InvoiceID = maps:get(<<"invoice_id">>, CtxData),
PaymentID = maps:get(<<"payment_id">>, CtxData),
{ok, {InvoiceID, PaymentID, RefundID}};
{error, internal_id_not_found} = Error ->
Error
end.
get_refund(undefined, _, _, _) ->
{error, invoice_not_found};
get_refund(_, undefined, _, _) ->
{error, payment_not_found};
get_refund(InvoiceID, PaymentID, RefundID, Context) ->
capi_handler_utils:get_refund_by_id(InvoiceID, PaymentID, RefundID, Context).
-spec get_payment_by_external_id(binary(), capi_handler:processing_context()) -> woody:result().
-spec get_payment_by_external_id(binary(), capi_handler:processing_context()) ->
{ok, {binary(), binary()}}
| {error, internal_id_not_found}.
get_payment_by_external_id(ExternalID, #{woody_context := WoodyContext} = Context) ->
PartyID = capi_handler_utils:get_party_id(Context),
IdempotentKey = {'CreatePayment', PartyID, ExternalID},
case capi_bender:get_internal_id(IdempotentKey, WoodyContext) of
{ok, PaymentID, CtxData} ->
InvoiceID = maps:get(<<"invoice_id">>, CtxData, undefined),
get_payment(InvoiceID, PaymentID, Context);
Error ->
Error
end.
get_payment(undefined, _, _) ->
{error, invoice_not_found};
get_payment(InvoiceID, PaymentID, Context) ->
case capi_handler_utils:get_payment_by_id(InvoiceID, PaymentID, Context) of
{ok, Payment} ->
{ok, InvoiceID, Payment};
Error ->
InvoiceID = maps:get(<<"invoice_id">>, CtxData),
{ok, {InvoiceID, PaymentID}};
{error, internal_id_not_found} = Error ->
Error
end.
@ -644,3 +753,8 @@ create_sequence_id([Identifier | Rest], BenderPrefix) ->
<<Identifier/binary, ".", Next/binary>>;
create_sequence_id([], BenderPrefix) ->
genlib:to_binary(BenderPrefix).
maybe(undefined, _) ->
undefined;
maybe(V, Fun) ->
Fun(V).

View File

@ -2,7 +2,7 @@
-include_lib("common_test/include/ct.hrl").
-include_lib("damsel/include/dmsl_domain_config_thrift.hrl").
-include_lib("damsel/include/dmsl_domain_thrift.hrl").
-include_lib("capi_dummy_data.hrl").
-include_lib("jose/include/jose_jwk.hrl").
@ -29,7 +29,6 @@
authorization_bad_token_error_test/1
]).
-define(badresp(Code), {error, {invalid_response_code, Code}}).
-define(emptyresp(Code), {error, {Code, #{}}}).
-type test_case_name() :: atom().
@ -80,7 +79,7 @@ end_per_suite(C) ->
-spec init_per_group(group_name(), config()) -> config().
init_per_group(_, Config) ->
SupPid = capi_ct_helper:start_mocked_service_sup(?MODULE),
Apps = capi_ct_helper_bouncer:mock_bouncer_arbiter(capi_ct_helper_bouncer:judge_always_allowed(), SupPid),
Apps = capi_ct_helper_bouncer:mock_arbiter(capi_ct_helper_bouncer:judge_always_allowed(), SupPid),
[{group_apps, Apps}, {group_test_sup, SupPid} | Config].
-spec end_per_group(group_name(), config()) -> _.

File diff suppressed because it is too large Load Diff

View File

@ -42,11 +42,16 @@
payment = ?CTX_ENTITY(PaymentID)
}).
-define(CTX_PAYMENT_OP(ID, InvoiceID), #bctx_v1_CommonAPIOperation{
id = ID,
invoice = ?CTX_ENTITY(InvoiceID)
}).
-define(CTX_REFUND_OP(ID, InvoiceID, PaymentID, RefundID), #bctx_v1_CommonAPIOperation{
id = ID,
invoice = ?CTX_ENTITY(InvoiceID),
payment = ?CTX_ENTITY(PaymentID),
refund = ?CTX_ENTITY(PaymentID)
refund = ?CTX_ENTITY(RefundID)
}).
-define(CTX_INVOICE_TPL_OP(ID, InvoiceTemplateID), #bctx_v1_CommonAPIOperation{
@ -76,6 +81,39 @@
party = ?CTX_ENTITY(PartyID)
}).
-define(CTX_SEARCH_INVOICE_OP(ID, PartyID, ShopID, InvoiceID, PaymentID, CustomerID), #bctx_v1_CommonAPIOperation{
id = ID,
party = ?CTX_ENTITY(PartyID),
shop = ?CTX_ENTITY(ShopID),
invoice = ?CTX_ENTITY(InvoiceID),
payment = ?CTX_ENTITY(PaymentID),
customer = ?CTX_ENTITY(CustomerID)
}).
-define(CTX_SEARCH_PAYMENT_OP(ID, PartyID, ShopID, InvoiceID, PaymentID), #bctx_v1_CommonAPIOperation{
id = ID,
party = ?CTX_ENTITY(PartyID),
shop = ?CTX_ENTITY(ShopID),
invoice = ?CTX_ENTITY(InvoiceID),
payment = ?CTX_ENTITY(PaymentID)
}).
-define(CTX_SEARCH_PAYOUT_OP(ID, PartyID, ShopID, PayoutID), #bctx_v1_CommonAPIOperation{
id = ID,
party = ?CTX_ENTITY(PartyID),
shop = ?CTX_ENTITY(ShopID),
payout = ?CTX_ENTITY(PayoutID)
}).
-define(CTX_SEARCH_REFUND_OP(ID, PartyID, ShopID, InvoiceID, PaymentID, RefundID), #bctx_v1_CommonAPIOperation{
id = ID,
party = ?CTX_ENTITY(PartyID),
shop = ?CTX_ENTITY(ShopID),
invoice = ?CTX_ENTITY(InvoiceID),
payment = ?CTX_ENTITY(PaymentID),
refund = ?CTX_ENTITY(RefundID)
}).
-define(CTX_SEARCH_OP(
ID,
PartyID,
@ -151,8 +189,14 @@
}).
-define(assertContextMatches(Expect), fun(Context) ->
?assertMatch(Expect, Context),
{ok, ?JUDGEMENT(?ALLOWED)}
try
?assertMatch(Expect, Context),
{ok, ?JUDGEMENT(?ALLOWED)}
catch
error:AssertMatchError:Stacktrace ->
logger:error("failed ~p at ~p", [AssertMatchError, Stacktrace]),
{throwing, #bdcs_InvalidContext{}}
end
end).
-endif.

View File

@ -55,7 +55,7 @@ init_suite(Module, Config, CapiEnv) ->
Apps2 =
start_app(dmt_client, [{max_cache_size, #{}}, {service_urls, ServiceURLs}, {cache_update_interval, 50000}]) ++
start_capi(Config, CapiEnv) ++
capi_ct_helper_bouncer:mock_bouncer_client(SupPid),
capi_ct_helper_bouncer:mock_client(SupPid),
[{apps, lists:reverse(Apps1 ++ Apps2)}, {suite_test_sup, SupPid} | Config].
-spec start_app(app_name()) -> [app_name()].

View File

@ -5,29 +5,34 @@
-include_lib("capi_bouncer_data.hrl").
-include_lib("stdlib/include/assert.hrl").
-export([mock_bouncer_assert_op_ctx/2]).
-export([mock_bouncer_assert_party_op_ctx/3]).
-export([mock_bouncer_assert_shop_op_ctx/4]).
-export([mock_bouncer_assert_contract_op_ctx/4]).
-export([mock_bouncer_assert_invoice_op_ctx/5]).
-export([mock_bouncer_assert_payment_op_ctx/6]).
-export([mock_bouncer_assert_invoice_tpl_op_ctx/5]).
-export([mock_bouncer_assert_customer_op_ctx/5]).
-export([mock_bouncer_assert_claim_op_ctx/4]).
-export([mock_bouncer_assert_webhook_op_ctx/4]).
-export([mock_bouncer_assert_payout_op_ctx/6]).
-export([mock_bouncer_assert_search_op_ctx/9]).
-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_claim_op_ctx/4]).
-export([mock_assert_webhook_op_ctx/4]).
-export([mock_assert_payout_op_ctx/6]).
-export([mock_assert_search_invoice_op_ctx/7]).
-export([mock_assert_search_payment_op_ctx/6]).
-export([mock_assert_search_payout_op_ctx/5]).
-export([mock_assert_search_refund_op_ctx/7]).
-export([mock_bouncer_client/1]).
-export([mock_bouncer_arbiter/2]).
-export([mock_client/1]).
-export([mock_arbiter/2]).
-export([judge_always_allowed/0]).
-export([judge_always_forbidden/0]).
%%
-spec mock_bouncer_assert_op_ctx(_, _) -> _.
mock_bouncer_assert_op_ctx(Op, Config) ->
mock_bouncer_arbiter(
-spec mock_assert_op_ctx(_, _) -> _.
mock_assert_op_ctx(Op, Config) ->
mock_arbiter(
?assertContextMatches(
#bctx_v1_ContextFragment{
capi = ?CTX_CAPI(?CTX_CAPI_OP(Op))
@ -36,9 +41,9 @@ mock_bouncer_assert_op_ctx(Op, Config) ->
Config
).
-spec mock_bouncer_assert_party_op_ctx(_, _, _) -> _.
mock_bouncer_assert_party_op_ctx(Op, PartyID, Config) ->
mock_bouncer_arbiter(
-spec mock_assert_party_op_ctx(_, _, _) -> _.
mock_assert_party_op_ctx(Op, PartyID, Config) ->
mock_arbiter(
?assertContextMatches(
#bctx_v1_ContextFragment{
capi = ?CTX_CAPI(?CTX_PARTY_OP(Op, PartyID))
@ -47,9 +52,9 @@ mock_bouncer_assert_party_op_ctx(Op, PartyID, Config) ->
Config
).
-spec mock_bouncer_assert_shop_op_ctx(_, _, _, _) -> _.
mock_bouncer_assert_shop_op_ctx(Op, PartyID, ShopID, Config) ->
mock_bouncer_arbiter(
-spec mock_assert_shop_op_ctx(_, _, _, _) -> _.
mock_assert_shop_op_ctx(Op, PartyID, ShopID, Config) ->
mock_arbiter(
?assertContextMatches(
#bctx_v1_ContextFragment{
capi = ?CTX_CAPI(?CTX_SHOP_OP(Op, PartyID, ShopID))
@ -58,9 +63,9 @@ mock_bouncer_assert_shop_op_ctx(Op, PartyID, ShopID, Config) ->
Config
).
-spec mock_bouncer_assert_contract_op_ctx(_, _, _, _) -> _.
mock_bouncer_assert_contract_op_ctx(Op, PartyID, ContractID, Config) ->
mock_bouncer_arbiter(
-spec mock_assert_contract_op_ctx(_, _, _, _) -> _.
mock_assert_contract_op_ctx(Op, PartyID, ContractID, Config) ->
mock_arbiter(
?assertContextMatches(
#bctx_v1_ContextFragment{
capi = ?CTX_CAPI(?CTX_CONTRACT_OP(Op, PartyID, ContractID))
@ -69,9 +74,9 @@ mock_bouncer_assert_contract_op_ctx(Op, PartyID, ContractID, Config) ->
Config
).
-spec mock_bouncer_assert_invoice_op_ctx(_, _, _, _, _) -> _.
mock_bouncer_assert_invoice_op_ctx(Op, InvoiceID, PartyID, ShopID, Config) ->
mock_bouncer_arbiter(
-spec mock_assert_invoice_op_ctx(_, _, _, _, _) -> _.
mock_assert_invoice_op_ctx(Op, InvoiceID, PartyID, ShopID, Config) ->
mock_arbiter(
?assertContextMatches(
#bctx_v1_ContextFragment{
capi = ?CTX_CAPI(?CTX_INVOICE_OP(Op, InvoiceID)),
@ -83,9 +88,9 @@ mock_bouncer_assert_invoice_op_ctx(Op, InvoiceID, PartyID, ShopID, Config) ->
Config
).
-spec mock_bouncer_assert_payment_op_ctx(_, _, _, _, _, _) -> _.
mock_bouncer_assert_payment_op_ctx(Op, InvoiceID, PaymentID, PartyID, ShopID, Config) ->
mock_bouncer_arbiter(
-spec mock_assert_payment_op_ctx(_, _, _, _, _, _) -> _.
mock_assert_payment_op_ctx(Op, InvoiceID, PaymentID, PartyID, ShopID, Config) ->
mock_arbiter(
?assertContextMatches(
#bctx_v1_ContextFragment{
capi = ?CTX_CAPI(?CTX_PAYMENT_OP(Op, InvoiceID, PaymentID)),
@ -97,9 +102,37 @@ mock_bouncer_assert_payment_op_ctx(Op, InvoiceID, PaymentID, PartyID, ShopID, Co
Config
).
-spec mock_bouncer_assert_invoice_tpl_op_ctx(_, _, _, _, _) -> _.
mock_bouncer_assert_invoice_tpl_op_ctx(Op, InvoiceTemplateID, PartyID, ShopID, Config) ->
mock_bouncer_arbiter(
-spec mock_assert_payment_op_ctx(_, _, _, _, _) -> _.
mock_assert_payment_op_ctx(Op, InvoiceID, PartyID, ShopID, Config) ->
mock_arbiter(
?assertContextMatches(
#bctx_v1_ContextFragment{
capi = ?CTX_CAPI(?CTX_PAYMENT_OP(Op, InvoiceID)),
payment_processing = #bctx_v1_ContextPaymentProcessing{
invoice = ?CTX_INVOICE(InvoiceID, PartyID, ShopID, [])
}
}
),
Config
).
-spec mock_assert_refund_op_ctx(_, _, _, _, _, _, _) -> _.
mock_assert_refund_op_ctx(Op, InvoiceID, PaymentID, RefundID, PartyID, ShopID, Config) ->
mock_arbiter(
?assertContextMatches(
#bctx_v1_ContextFragment{
capi = ?CTX_CAPI(?CTX_REFUND_OP(Op, InvoiceID, PaymentID, RefundID)),
payment_processing = #bctx_v1_ContextPaymentProcessing{
invoice = ?CTX_INVOICE(InvoiceID, PartyID, ShopID, [?CTX_PAYMENT(PaymentID)])
}
}
),
Config
).
-spec mock_assert_invoice_tpl_op_ctx(_, _, _, _, _) -> _.
mock_assert_invoice_tpl_op_ctx(Op, InvoiceTemplateID, PartyID, ShopID, Config) ->
mock_arbiter(
?assertContextMatches(
#bctx_v1_ContextFragment{
capi = ?CTX_CAPI(?CTX_INVOICE_TPL_OP(Op, InvoiceTemplateID)),
@ -111,9 +144,9 @@ mock_bouncer_assert_invoice_tpl_op_ctx(Op, InvoiceTemplateID, PartyID, ShopID, C
Config
).
-spec mock_bouncer_assert_customer_op_ctx(_, _, _, _, _) -> _.
mock_bouncer_assert_customer_op_ctx(Op, CustomerID, PartyID, ShopID, Config) ->
mock_bouncer_arbiter(
-spec mock_assert_customer_op_ctx(_, _, _, _, _) -> _.
mock_assert_customer_op_ctx(Op, CustomerID, PartyID, ShopID, Config) ->
mock_arbiter(
?assertContextMatches(
#bctx_v1_ContextFragment{
capi = ?CTX_CAPI(?CTX_CUSTOMER_OP(Op, CustomerID)),
@ -125,9 +158,9 @@ mock_bouncer_assert_customer_op_ctx(Op, CustomerID, PartyID, ShopID, Config) ->
Config
).
-spec mock_bouncer_assert_claim_op_ctx(_, _, _, _) -> _.
mock_bouncer_assert_claim_op_ctx(Op, PartyID, ClaimID, Config) ->
mock_bouncer_arbiter(
-spec mock_assert_claim_op_ctx(_, _, _, _) -> _.
mock_assert_claim_op_ctx(Op, PartyID, ClaimID, Config) ->
mock_arbiter(
?assertContextMatches(
#bctx_v1_ContextFragment{
capi = ?CTX_CAPI(?CTX_CLAIM_OP(Op, PartyID, ClaimID))
@ -136,9 +169,9 @@ mock_bouncer_assert_claim_op_ctx(Op, PartyID, ClaimID, Config) ->
Config
).
-spec mock_bouncer_assert_webhook_op_ctx(_, _, _, _) -> _.
mock_bouncer_assert_webhook_op_ctx(Op, WebhookID, PartyID, Config) ->
mock_bouncer_arbiter(
-spec mock_assert_webhook_op_ctx(_, _, _, _) -> _.
mock_assert_webhook_op_ctx(Op, WebhookID, PartyID, Config) ->
mock_arbiter(
?assertContextMatches(
#bctx_v1_ContextFragment{
capi = ?CTX_CAPI(?CTX_WEBHOOK_OP(Op, WebhookID)),
@ -150,9 +183,9 @@ mock_bouncer_assert_webhook_op_ctx(Op, WebhookID, PartyID, Config) ->
Config
).
-spec mock_bouncer_assert_payout_op_ctx(_, _, _, _, _, _) -> _.
mock_bouncer_assert_payout_op_ctx(Op, PayoutID, PartyID, ContractID, ShopID, Config) ->
mock_bouncer_arbiter(
-spec mock_assert_payout_op_ctx(_, _, _, _, _, _) -> _.
mock_assert_payout_op_ctx(Op, PayoutID, PartyID, ContractID, ShopID, Config) ->
mock_arbiter(
?assertContextMatches(
#bctx_v1_ContextFragment{
capi = ?CTX_CAPI(?CTX_PAYOUT_OP(Op, PayoutID, PartyID)),
@ -164,19 +197,70 @@ mock_bouncer_assert_payout_op_ctx(Op, PayoutID, PartyID, ContractID, ShopID, Con
Config
).
-spec mock_bouncer_assert_search_op_ctx(_, _, _, _, _, _, _, _, _) -> _.
mock_bouncer_assert_search_op_ctx(Op, PartyID, ShopID, InvoiceID, PaymentID, CustomerID, PayoutID, RefundID, Config) ->
SearchCtx = ?CTX_SEARCH_OP(
-spec mock_assert_search_payment_op_ctx(_, _, _, _, _, _) -> _.
mock_assert_search_payment_op_ctx(Op, PartyID, ShopID, InvoiceID, PaymentID, Config) ->
SearchCtx = ?CTX_SEARCH_PAYMENT_OP(
Op,
PartyID,
ShopID,
InvoiceID,
PaymentID
),
mock_arbiter(
?assertContextMatches(
#bctx_v1_ContextFragment{
capi = ?CTX_CAPI(SearchCtx)
}
),
Config
).
-spec mock_assert_search_invoice_op_ctx(_, _, _, _, _, _, _) -> _.
mock_assert_search_invoice_op_ctx(Op, PartyID, ShopID, InvoiceID, PaymentID, CustomerID, Config) ->
SearchCtx = ?CTX_SEARCH_INVOICE_OP(
Op,
PartyID,
ShopID,
InvoiceID,
PaymentID,
CustomerID
),
mock_arbiter(
?assertContextMatches(
#bctx_v1_ContextFragment{
capi = ?CTX_CAPI(SearchCtx)
}
),
Config
).
-spec mock_assert_search_refund_op_ctx(_, _, _, _, _, _, _) -> _.
mock_assert_search_refund_op_ctx(Op, PartyID, ShopID, InvoiceID, PaymentID, RefundID, Config) ->
SearchCtx = ?CTX_SEARCH_REFUND_OP(
Op,
PartyID,
ShopID,
InvoiceID,
PaymentID,
CustomerID,
PayoutID,
RefundID
),
mock_bouncer_arbiter(
mock_arbiter(
?assertContextMatches(
#bctx_v1_ContextFragment{
capi = ?CTX_CAPI(SearchCtx)
}
),
Config
).
-spec mock_assert_search_payout_op_ctx(_, _, _, _, _) -> _.
mock_assert_search_payout_op_ctx(Op, PartyID, ShopID, PayoutID, Config) ->
SearchCtx = ?CTX_SEARCH_PAYOUT_OP(
Op,
PartyID,
ShopID,
PayoutID
),
mock_arbiter(
?assertContextMatches(
#bctx_v1_ContextFragment{
capi = ?CTX_CAPI(SearchCtx)
@ -186,15 +270,14 @@ mock_bouncer_assert_search_op_ctx(Op, PartyID, ShopID, InvoiceID, PaymentID, Cus
).
%%
start_bouncer_client(ServiceURLs) ->
start_client(ServiceURLs) ->
ServiceClients = maps:map(fun(_, URL) -> #{url => URL} end, ServiceURLs),
Acc = application:get_env(bouncer_client, service_clients, #{}),
capi_ct_helper:start_app(bouncer_client, [{service_clients, maps:merge(Acc, ServiceClients)}]).
-spec mock_bouncer_client(_) -> _.
mock_bouncer_client(SupOrConfig) ->
start_bouncer_client(
-spec mock_client(_) -> _.
mock_client(SupOrConfig) ->
start_client(
capi_ct_helper:mock_services_(
[
{
@ -216,16 +299,16 @@ mock_bouncer_client(SupOrConfig) ->
)
).
-spec mock_bouncer_arbiter(_, _) -> _.
mock_bouncer_arbiter(JudgeFun, SupOrConfig) ->
start_bouncer_client(
-spec mock_arbiter(_, _) -> _.
mock_arbiter(JudgeFun, SupOrConfig) ->
start_client(
capi_ct_helper:mock_services_(
[
{
bouncer,
{bouncer_decisions_thrift, 'Arbiter'},
fun('Judge', {?TEST_RULESET_ID, Context}) ->
Fragments = decode_bouncer_context(Context),
Fragments = decode_context(Context),
Combined = combine_fragments(Fragments),
JudgeFun(Combined)
end
@ -235,10 +318,10 @@ mock_bouncer_arbiter(JudgeFun, SupOrConfig) ->
)
).
decode_bouncer_context(#bdcs_Context{fragments = Fragments}) ->
maps:map(fun(_, Fragment) -> decode_bouncer_fragment(Fragment) end, Fragments).
decode_context(#bdcs_Context{fragments = Fragments}) ->
maps:map(fun(_, Fragment) -> decode_fragment(Fragment) end, Fragments).
decode_bouncer_fragment(#bctx_ContextFragment{type = v1_thrift_binary, content = Content}) ->
decode_fragment(#bctx_ContextFragment{type = v1_thrift_binary, content = Content}) ->
Type = {struct, struct, {bouncer_context_v1_thrift, 'ContextFragment'}},
Codec = thrift_strict_binary_codec:new(Content),
{ok, Fragment, _} = thrift_strict_binary_codec:read(Codec, Type),

View File

@ -2,10 +2,8 @@
-include_lib("common_test/include/ct.hrl").
-include_lib("damsel/include/dmsl_domain_config_thrift.hrl").
-include_lib("damsel/include/dmsl_payment_processing_thrift.hrl").
-include_lib("capi_dummy_data.hrl").
-include_lib("jose/include/jose_jwk.hrl").
-export([all/0]).
-export([groups/0]).
@ -27,12 +25,6 @@
get_customer_events_ok_test/1
]).
-define(CAPI_PORT, 8080).
-define(CAPI_HOST_NAME, "localhost").
-define(CAPI_URL, ?CAPI_HOST_NAME ++ ":" ++ integer_to_list(?CAPI_PORT)).
-define(badresp(Code), {error, {invalid_response_code, Code}}).
-type test_case_name() :: atom().
-type config() :: [{atom(), any()}].
-type group_name() :: atom().
@ -90,7 +82,7 @@ init_per_group(operations_by_customer_access_token_after_customer_creation, Conf
],
MockServiceSup
),
_ = capi_ct_helper_bouncer:mock_bouncer_arbiter(capi_ct_helper_bouncer:judge_always_allowed(), MockServiceSup),
_ = capi_ct_helper_bouncer:mock_arbiter(capi_ct_helper_bouncer:judge_always_allowed(), MockServiceSup),
{ok, Token} = capi_ct_helper:issue_token([{[customers], write}], unlimited),
Req = #{
<<"shopID">> => ?STRING,
@ -102,12 +94,12 @@ init_per_group(operations_by_customer_access_token_after_customer_creation, Conf
}} = 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),
Apps = capi_ct_helper_bouncer:mock_bouncer_arbiter(capi_ct_helper_bouncer:judge_always_allowed(), SupPid),
Apps = capi_ct_helper_bouncer:mock_arbiter(capi_ct_helper_bouncer:judge_always_allowed(), SupPid),
[{context, capi_ct_helper:get_context(CustAccToken)}, {group_apps, Apps}, {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_bouncer:mock_bouncer_arbiter(capi_ct_helper_bouncer:judge_always_allowed(), MockServiceSup),
_ = capi_ct_helper_bouncer:mock_arbiter(capi_ct_helper_bouncer:judge_always_allowed(), MockServiceSup),
{ok, Token} = capi_ct_helper:issue_token([{[customers], write}], unlimited),
{ok, #{<<"payload">> := CustAccToken}} = capi_client_customers:create_customer_access_token(
capi_ct_helper:get_context(Token),
@ -115,7 +107,7 @@ init_per_group(operations_by_customer_access_token_after_token_creation, Config)
),
_ = capi_ct_helper:stop_mocked_service_sup(MockServiceSup),
SupPid = capi_ct_helper:start_mocked_service_sup(?MODULE),
Apps = capi_ct_helper_bouncer:mock_bouncer_arbiter(capi_ct_helper_bouncer:judge_always_allowed(), SupPid),
Apps = capi_ct_helper_bouncer:mock_arbiter(capi_ct_helper_bouncer:judge_always_allowed(), SupPid),
[{context, capi_ct_helper:get_context(CustAccToken)}, {group_apps, Apps}, {group_test_sup, SupPid} | Config];
init_per_group(_, Config) ->
Config.

View File

@ -2,9 +2,8 @@
-include_lib("common_test/include/ct.hrl").
-include_lib("damsel/include/dmsl_domain_config_thrift.hrl").
-include_lib("damsel/include/dmsl_domain_thrift.hrl").
-include_lib("capi_dummy_data.hrl").
-include_lib("jose/include/jose_jwk.hrl").
-export([all/0]).
-export([groups/0]).
@ -86,7 +85,7 @@ init_per_group(deadline_header, Config) ->
Context = capi_ct_helper:get_context(Token),
Config2 = [{context_with_relative_deadline, get_context(Token2, <<"3s">>)} | Config],
SupPid = capi_ct_helper:start_mocked_service_sup(?MODULE),
Apps1 = capi_ct_helper_bouncer:mock_bouncer_arbiter(capi_ct_helper_bouncer:judge_always_allowed(), SupPid),
Apps1 = capi_ct_helper_bouncer:mock_arbiter(capi_ct_helper_bouncer:judge_always_allowed(), SupPid),
[{context_with_absolute_deadline, Context}, {group_apps, Apps1}, {group_test_sup, SupPid} | Config2];
init_per_group(_, Config) ->
Config.

View File

@ -312,6 +312,11 @@
external_id = EID
}).
-define(PAYPROC_REFUND(ID, EID), #payproc_InvoicePaymentRefund{
refund = ?REFUND(ID, EID),
sessions = []
}).
-define(CHARGEBACK, ?CHARGEBACK(?STRING)).
-define(PAYPROC_CHARGEBACK, ?PAYPROC_CHARGEBACK(?STRING)).
@ -1200,9 +1205,11 @@
bank_card = ?BANK_CARD
}).
-define(PAYOUT(Type, PayoutSummary), #'payout_processing_Payout'{
-define(PAYOUT(Type, PayoutSummary), ?PAYOUT(Type, ?STRING, PayoutSummary)).
-define(PAYOUT(Type, PartyID, PayoutSummary), #'payout_processing_Payout'{
id = ?STRING,
party_id = ?STRING,
party_id = PartyID,
shop_id = ?STRING,
contract_id = ?STRING,
created_at = ?TIMESTAMP,
@ -1336,3 +1343,18 @@
<<"how_about_null">> => null
}
}).
-define(PAYMENT_PARAMS(EID, Token), #{
<<"externalID">> => EID,
<<"flow">> => #{<<"type">> => <<"PaymentFlowInstant">>},
<<"payer">> => #{
<<"payerType">> => <<"PaymentResourcePayer">>,
<<"paymentSession">> => ?TEST_PAYMENT_SESSION,
<<"paymentToolToken">> => Token,
<<"contactInfo">> => #{
<<"email">> => <<"bla@bla.ru">>
}
},
<<"metadata">> => ?JSON,
<<"processingDeadline">> => <<"5m">>
}).

View File

@ -4,7 +4,6 @@
-include_lib("stdlib/include/assert.hrl").
-include_lib("capi_dummy_data.hrl").
-include_lib("damsel/include/dmsl_domain_config_thrift.hrl").
-include_lib("damsel/include/dmsl_payment_processing_thrift.hrl").
-export([all/0]).
@ -132,7 +131,6 @@ init_per_group(payment_creation, Config) ->
],
MockServiceSup
),
_ = capi_ct_helper_bouncer:mock_bouncer_assert_shop_op_ctx(<<"CreateInvoice">>, ?STRING, ?STRING, MockServiceSup),
Req = #{
<<"shopID">> => ?STRING,
<<"amount">> => ?INTEGER,
@ -142,6 +140,8 @@ init_per_group(payment_creation, Config) ->
<<"product">> => <<"test_product">>,
<<"description">> => <<"test_invoice_description">>
},
SupPid = capi_ct_helper:start_mocked_service_sup(?MODULE),
Apps1 = capi_ct_helper_bouncer:mock_arbiter(capi_ct_helper_bouncer:judge_always_allowed(), SupPid),
{{ok, #{
<<"invoiceAccessToken">> := #{<<"payload">> := InvAccToken}
}},
@ -151,67 +151,21 @@ init_per_group(payment_creation, Config) ->
end),
capi_ct_helper:stop_mocked_service_sup(MockServiceSup),
[{context, capi_ct_helper:get_context(InvAccToken)} | Config];
init_per_group(invoice_with_template_creation, Config) ->
SupPid = capi_ct_helper:start_mocked_service_sup(?MODULE),
BasePermissions = base_permissions(),
{ok, Token} = capi_ct_helper:issue_token(BasePermissions, unlimited),
_ = capi_ct_helper:mock_services(
[
{customer_management, fun('Get', _) ->
{ok, ?CUSTOMER}
end},
{invoice_templating, fun('Create', _) -> {ok, ?INVOICE_TPL} end},
{bender, fun('GenerateID', {_, _, CtxMsgPack}) ->
{ok, capi_ct_helper_bender:get_result(<<"bender_key">>, CtxMsgPack)}
end}
],
SupPid
),
Req = #{
<<"externalID">> => genlib:unique(),
<<"shopID">> => <<"1">>,
<<"lifetime">> => #{
<<"days">> => ?INTEGER,
<<"months">> => ?INTEGER,
<<"years">> => ?INTEGER
},
<<"details">> => ?INVOICE_TMPL_DETAILS_PARAMS,
<<"description">> => <<"Sample text">>
},
{{ok, #{
<<"invoiceTemplate">> := #{<<"id">> := InvoiceTemplateID}
}},
_} =
with_feature_storage(fun() ->
capi_client_invoice_templates:create(capi_ct_helper:get_context(Token, #{}), Req)
end),
Apps1 = capi_ct_helper_bouncer:mock_bouncer_arbiter(capi_ct_helper_bouncer:judge_always_allowed(), SupPid),
[
{invoice_template_id, InvoiceTemplateID},
{context, capi_ct_helper:get_context(Token)},
{group_apps, Apps1},
{group_test_sup, SupPid}
| Config
];
[{context, capi_ct_helper:get_context(InvAccToken)}, {group_apps, Apps1} | 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
GroupName =:= customer_creation orelse
GroupName =:= invoice_with_template_creation
->
BasePermissions = base_permissions(),
{ok, Token} = capi_ct_helper:issue_token(BasePermissions, unlimited),
{ok, Token2} = capi_ct_helper:issue_token(<<"TEST2">>, BasePermissions, unlimited, #{}),
Config2 = [{context_with_diff_party, capi_ct_helper:get_context(Token2)} | Config],
SupPid = capi_ct_helper:start_mocked_service_sup(?MODULE),
Apps1 = capi_ct_helper_bouncer:mock_bouncer_arbiter(capi_ct_helper_bouncer:judge_always_allowed(), SupPid),
Apps1 = capi_ct_helper_bouncer:mock_arbiter(capi_ct_helper_bouncer:judge_always_allowed(), SupPid),
[{context, capi_ct_helper:get_context(Token)}, {group_apps, Apps1}, {group_test_sup, SupPid} | Config2];
init_per_group(_, Config) ->
Config.
@ -571,7 +525,7 @@ create_invoice_template_fail_test(Config) ->
-spec create_invoice_with_template_ok_test(config()) -> _.
create_invoice_with_template_ok_test(Config) ->
BenderKey = <<"create_invoice_with_template_ok_test">>,
InvoiceTemplateID = ?config(invoice_template_id, Config),
InvoiceTemplateID = ?STRING,
Req1 = #{
<<"externalID">> => genlib:unique(),
<<"amount">> => ?INTEGER,
@ -601,7 +555,7 @@ create_invoice_with_template_ok_test(Config) ->
-spec create_invoice_with_template_fail_test(config()) -> _.
create_invoice_with_template_fail_test(Config) ->
BenderKey = <<"create_invoice_with_template_fail_test">>,
InvoiceTemplateID = ?config(invoice_template_id, Config),
InvoiceTemplateID = ?STRING,
ExternalID = genlib:unique(),
Req1 = #{
<<"externalID">> => ExternalID,
@ -751,9 +705,12 @@ create_payment(BenderKey, Requests, Config) ->
Tid = capi_ct_helper_bender:create_storage(),
_ = capi_ct_helper:mock_services(
[
{invoicing, fun('StartPayment', {_, _, IPP}) ->
#payproc_InvoicePaymentParams{id = ID, external_id = EID, context = ?CONTENT} = IPP,
{ok, ?PAYPROC_PAYMENT(ID, EID)}
{invoicing, fun
('Get', _) ->
{ok, ?PAYPROC_INVOICE};
('StartPayment', {_, _, IPP}) ->
#payproc_InvoicePaymentParams{id = ID, external_id = EID, context = ?CONTENT} = IPP,
{ok, ?PAYPROC_PAYMENT(ID, EID)}
end},
{bender, fun('GenerateID', {_, _, CtxMsgPack}) ->
capi_ct_helper_bender:get_internal_id(Tid, BenderKey, CtxMsgPack)
@ -798,11 +755,14 @@ create_refunds(BenderKey, Requests, Config) ->
Tid = capi_ct_helper_bender:create_storage(),
_ = capi_ct_helper:mock_services(
[
{invoicing, fun(
'RefundPayment',
{_, _, _, #payproc_InvoicePaymentRefundParams{id = ID, external_id = EID}}
) ->
{ok, ?REFUND(ID, EID)}
{invoicing, fun
('Get', _) ->
{ok, ?PAYPROC_INVOICE([?PAYPROC_PAYMENT])};
(
'RefundPayment',
{_, _, _, #payproc_InvoicePaymentRefundParams{id = ID, external_id = EID}}
) ->
{ok, ?REFUND(ID, EID)}
end},
{bender, fun('GenerateID', {_, _, CtxMsgPack}) ->
capi_ct_helper_bender:get_internal_id(Tid, BenderKey, CtxMsgPack)

View File

@ -2,12 +2,9 @@
-include_lib("common_test/include/ct.hrl").
-include_lib("damsel/include/dmsl_domain_config_thrift.hrl").
-include_lib("damsel/include/dmsl_payment_processing_thrift.hrl").
-include_lib("damsel/include/dmsl_payment_processing_errors_thrift.hrl").
-include_lib("damsel/include/dmsl_payment_tool_token_thrift.hrl").
-include_lib("capi_dummy_data.hrl").
-include_lib("jose/include/jose_jwk.hrl").
-export([all/0]).
-export([groups/0]).
@ -41,12 +38,6 @@
get_recurrent_payments_ok_test/1
]).
-define(CAPI_PORT, 8080).
-define(CAPI_HOST_NAME, "localhost").
-define(CAPI_URL, ?CAPI_HOST_NAME ++ ":" ++ integer_to_list(?CAPI_PORT)).
-define(badresp(Code), {error, {invalid_response_code, Code}}).
-type test_case_name() :: atom().
-type config() :: [{atom(), any()}].
-type group_name() :: atom().
@ -61,46 +52,38 @@ init([]) ->
all() ->
[
{group, operations_by_invoice_access_token_after_invoice_creation},
{group, operations_by_invoice_access_token_after_token_creation},
{group, operations_by_invoice_access_token_after_invoice_creation_with_new_auth},
{group, operations_by_invoice_access_token_after_token_creation_with_new_auth}
{group, operations_by_invoice_access_token_after_token_creation}
].
invoice_access_token_tests() ->
[
create_payment_ok_test,
create_payment_expired_test,
create_payment_qiwi_access_token_ok_test,
create_payment_with_empty_cvv_ok_test,
create_payment_with_googlepay_encrypt_ok_test,
get_payments_ok_test,
get_client_payment_status_test,
get_payment_by_id_ok_test,
get_payment_by_id_trx_ok_test,
cancel_payment_ok_test,
capture_payment_ok_test,
capture_partial_payment_ok_test,
create_first_recurrent_payment_ok_test,
create_second_recurrent_payment_ok_test,
get_recurrent_payments_ok_test
].
get_recurrent_payments_ok_test,
invoice_access_token_tests_with_new_auth() ->
[
get_invoice_ok_test,
get_invoice_events_ok_test,
get_invoice_payment_methods_ok_test
get_invoice_payment_methods_ok_test,
create_payment_ok_test,
create_payment_expired_test,
create_payment_with_empty_cvv_ok_test,
create_payment_with_googlepay_encrypt_ok_test,
get_payments_ok_test,
create_payment_qiwi_access_token_ok_test,
create_first_recurrent_payment_ok_test,
create_second_recurrent_payment_ok_test
].
-spec groups() -> [{group_name(), list(), [test_case_name()]}].
groups() ->
[
{operations_by_invoice_access_token_after_invoice_creation, [], invoice_access_token_tests()},
{operations_by_invoice_access_token_after_token_creation, [], invoice_access_token_tests()},
{operations_by_invoice_access_token_after_invoice_creation_with_new_auth, [],
invoice_access_token_tests_with_new_auth()},
{operations_by_invoice_access_token_after_token_creation_with_new_auth, [],
invoice_access_token_tests_with_new_auth()}
{operations_by_invoice_access_token_after_token_creation, [], invoice_access_token_tests()}
].
%%
@ -128,60 +111,7 @@ init_per_group(operations_by_invoice_access_token_after_invoice_creation, Config
],
MockServiceSup
),
_ = capi_ct_helper_bouncer:mock_bouncer_assert_shop_op_ctx(<<"CreateInvoice">>, ?STRING, ?STRING, MockServiceSup),
Req = #{
<<"shopID">> => ?STRING,
<<"amount">> => ?INTEGER,
<<"currency">> => ?RUB,
<<"metadata">> => #{<<"invoice_dummy_metadata">> => <<"test_value">>},
<<"dueDate">> => ?TIMESTAMP,
<<"product">> => <<"test_product">>,
<<"description">> => <<"test_invoice_description">>
},
{ok, #{
<<"invoiceAccessToken">> := #{<<"payload">> := InvAccToken}
}} = capi_client_invoices:create_invoice(capi_ct_helper:get_context(Token, ExtraProperties), Req),
capi_ct_helper:stop_mocked_service_sup(MockServiceSup),
SupPid = capi_ct_helper:start_mocked_service_sup(?MODULE),
Apps1 = capi_ct_helper_bouncer:mock_bouncer_arbiter(capi_ct_helper_bouncer:judge_always_allowed(), SupPid),
[{context, capi_ct_helper:get_context(InvAccToken)}, {group_apps, Apps1}, {group_test_sup, SupPid} | Config];
init_per_group(operations_by_invoice_access_token_after_token_creation, Config) ->
MockServiceSup = capi_ct_helper:start_mocked_service_sup(?MODULE),
{ok, Token} = capi_ct_helper:issue_token([{[invoices], write}], unlimited),
_ = capi_ct_helper:mock_services(
[
{invoicing, fun('Get', _) -> {ok, ?PAYPROC_INVOICE} end},
{bender, fun('GenerateID', _) -> {ok, capi_ct_helper_bender:get_result(<<"bender_key">>)} end}
],
MockServiceSup
),
_ = capi_ct_helper_bouncer:mock_bouncer_assert_invoice_op_ctx(
<<"CreateInvoiceAccessToken">>,
?STRING,
?STRING,
?STRING,
MockServiceSup
),
{ok, #{<<"payload">> := InvAccToken}} = capi_client_invoices:create_invoice_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_bouncer:mock_bouncer_arbiter(capi_ct_helper_bouncer:judge_always_allowed(), SupPid),
[{context, capi_ct_helper:get_context(InvAccToken)}, {group_apps, Apps1}, {group_test_sup, SupPid} | Config];
init_per_group(operations_by_invoice_access_token_after_invoice_creation_with_new_auth, Config) ->
MockServiceSup = capi_ct_helper:start_mocked_service_sup(?MODULE),
ExtraProperties = #{<<"ip_replacement_allowed">> => true},
{ok, Token} = capi_ct_helper:issue_token([{[invoices], write}], unlimited, ExtraProperties),
_ = capi_ct_helper:mock_services(
[
{invoicing, fun('Create', _) -> {ok, ?PAYPROC_INVOICE} end},
{generator, fun('GenerateID', _) -> capi_ct_helper_bender:generate_id(<<"bender_key">>) end}
],
MockServiceSup
),
_ = capi_ct_helper_bouncer:mock_bouncer_assert_shop_op_ctx(<<"CreateInvoice">>, ?STRING, ?STRING, MockServiceSup),
_ = capi_ct_helper_bouncer:mock_assert_shop_op_ctx(<<"CreateInvoice">>, ?STRING, ?STRING, MockServiceSup),
Req = #{
<<"shopID">> => ?STRING,
<<"amount">> => ?INTEGER,
@ -196,7 +126,7 @@ init_per_group(operations_by_invoice_access_token_after_invoice_creation_with_ne
}} = capi_client_invoices:create_invoice(capi_ct_helper:get_context(Token, ExtraProperties), Req),
capi_ct_helper:stop_mocked_service_sup(MockServiceSup),
[{context, capi_ct_helper:get_context(InvAccToken)} | Config];
init_per_group(operations_by_invoice_access_token_after_token_creation_with_new_auth, Config) ->
init_per_group(operations_by_invoice_access_token_after_token_creation, Config) ->
MockServiceSup = capi_ct_helper:start_mocked_service_sup(?MODULE),
{ok, Token} = capi_ct_helper:issue_token([{[invoices], write}], unlimited),
_ = capi_ct_helper:mock_services(
@ -206,7 +136,7 @@ init_per_group(operations_by_invoice_access_token_after_token_creation_with_new_
],
MockServiceSup
),
_ = capi_ct_helper_bouncer:mock_bouncer_assert_invoice_op_ctx(
_ = capi_ct_helper_bouncer:mock_assert_invoice_op_ctx(
<<"CreateInvoiceAccessToken">>,
?STRING,
?STRING,
@ -241,7 +171,7 @@ end_per_testcase(_Name, C) ->
-spec get_invoice_ok_test(config()) -> _.
get_invoice_ok_test(Config) ->
_ = capi_ct_helper:mock_services([{invoicing, fun('Get', _) -> {ok, ?PAYPROC_INVOICE} end}], Config),
_ = capi_ct_helper_bouncer:mock_bouncer_assert_invoice_op_ctx(
_ = capi_ct_helper_bouncer:mock_assert_invoice_op_ctx(
<<"GetInvoiceByID">>,
?STRING,
?STRING,
@ -280,7 +210,7 @@ get_invoice_events_ok_test(Config) ->
],
Config
),
_ = capi_ct_helper_bouncer:mock_bouncer_assert_invoice_op_ctx(
_ = capi_ct_helper_bouncer:mock_assert_invoice_op_ctx(
<<"GetInvoiceEvents">>,
?STRING,
?STRING,
@ -304,7 +234,7 @@ get_invoice_payment_methods_ok_test(Config) ->
],
Config
),
_ = capi_ct_helper_bouncer:mock_bouncer_assert_invoice_op_ctx(
_ = capi_ct_helper_bouncer:mock_assert_invoice_op_ctx(
<<"GetInvoicePaymentMethods">>,
?STRING,
?STRING,
@ -319,9 +249,12 @@ create_payment_ok_test(Config) ->
ExternalID = <<"merch_id">>,
_ = capi_ct_helper:mock_services(
[
{invoicing, fun('StartPayment', {_, _, IPP}) ->
#payproc_InvoicePaymentParams{id = ID, external_id = EID, context = ?CONTENT} = IPP,
{ok, ?PAYPROC_PAYMENT(ID, EID)}
{invoicing, fun
('Get', _) ->
{ok, ?PAYPROC_INVOICE};
('StartPayment', {_, _, IPP}) ->
#payproc_InvoicePaymentParams{id = ID, external_id = EID, context = ?CONTENT} = IPP,
{ok, ?PAYPROC_PAYMENT(ID, EID)}
end},
{bender, fun('GenerateID', _) ->
{ok, capi_ct_helper_bender:get_result(BenderKey)}
@ -329,29 +262,35 @@ create_payment_ok_test(Config) ->
],
Config
),
_ = capi_ct_helper_bouncer:mock_assert_payment_op_ctx(
<<"CreatePayment">>,
?STRING,
?STRING,
?STRING,
Config
),
PaymentToolToken = get_encrypted_token(visa, ?EXP_DATE(2, 2020)),
Req2 = #{
<<"externalID">> => ExternalID,
<<"flow">> => #{<<"type">> => <<"PaymentFlowInstant">>},
<<"payer">> => #{
<<"payerType">> => <<"PaymentResourcePayer">>,
<<"paymentSession">> => ?TEST_PAYMENT_SESSION,
<<"paymentToolToken">> => PaymentToolToken,
<<"contactInfo">> => #{
<<"email">> => <<"bla@bla.ru">>
}
},
<<"metadata">> => ?JSON,
<<"processingDeadline">> => <<"5m">>
},
Req = ?PAYMENT_PARAMS(ExternalID, PaymentToolToken),
{ok, #{
<<"id">> := BenderKey,
<<"externalID">> := ExternalID
}} = capi_client_payments:create_payment(?config(context, Config), Req2, ?STRING).
}} = capi_client_payments:create_payment(?config(context, Config), Req, ?STRING).
-spec create_payment_expired_test(config()) -> _.
create_payment_expired_test(Config) ->
PaymentTool = {bank_card, ?BANK_CARD},
_ = capi_ct_helper:mock_services(
[
{invoicing, fun
('Get', _) ->
{ok, ?PAYPROC_INVOICE};
('StartPayment', {_, _, IPP}) ->
#payproc_InvoicePaymentParams{id = ID, external_id = EID, context = ?CONTENT} = IPP,
{ok, ?PAYPROC_PAYMENT(ID, EID)}
end}
],
Config
),
ValidUntil = capi_utils:deadline_from_timeout(0),
PaymentToolToken = capi_crypto:create_encrypted_payment_tool_token(PaymentTool, ValidUntil),
Req = #{
@ -375,25 +314,28 @@ create_payment_expired_test(Config) ->
create_payment_with_empty_cvv_ok_test(Config) ->
_ = capi_ct_helper:mock_services(
[
{invoicing, fun(
'StartPayment',
{
_UserInfo,
_InvoiceID,
#payproc_InvoicePaymentParams{
payer =
{payment_resource, #payproc_PaymentResourcePayerParams{
resource = #domain_DisposablePaymentResource{
payment_tool = {
bank_card,
#domain_BankCard{is_cvv_empty = true}
{invoicing, fun
('Get', _) ->
{ok, ?PAYPROC_INVOICE};
(
'StartPayment',
{
_UserInfo,
_InvoiceID,
#payproc_InvoicePaymentParams{
payer =
{payment_resource, #payproc_PaymentResourcePayerParams{
resource = #domain_DisposablePaymentResource{
payment_tool = {
bank_card,
#domain_BankCard{is_cvv_empty = true}
}
}
}
}}
}}
}
}
}
) ->
{ok, ?PAYPROC_PAYMENT}
) ->
{ok, ?PAYPROC_PAYMENT}
end},
{generator, fun('GenerateID', _) -> capi_ct_helper_bender:generate_id(<<"bender_key">>) end}
],
@ -417,25 +359,28 @@ create_payment_with_empty_cvv_ok_test(Config) ->
create_payment_qiwi_access_token_ok_test(Config) ->
_ = capi_ct_helper:mock_services(
[
{invoicing, fun(
'StartPayment',
{
_UserInfo,
_InvoiceID,
#payproc_InvoicePaymentParams{
payer =
{payment_resource, #payproc_PaymentResourcePayerParams{
resource = #domain_DisposablePaymentResource{
payment_tool = {
digital_wallet,
#domain_DigitalWallet{token = <<"benderkey0">>}
{invoicing, fun
('Get', _) ->
{ok, ?PAYPROC_INVOICE};
(
'StartPayment',
{
_UserInfo,
_InvoiceID,
#payproc_InvoicePaymentParams{
payer =
{payment_resource, #payproc_PaymentResourcePayerParams{
resource = #domain_DisposablePaymentResource{
payment_tool = {
digital_wallet,
#domain_DigitalWallet{token = <<"benderkey0">>}
}
}
}
}}
}}
}
}
}
) ->
{ok, ?PAYPROC_PAYMENT}
) ->
{ok, ?PAYPROC_PAYMENT}
end},
{generator, fun('GenerateID', _) -> capi_ct_helper_bender:generate_id(<<"bender_key">>) end}
],
@ -457,29 +402,32 @@ create_payment_qiwi_access_token_ok_test(Config) ->
create_payment_with_googlepay_encrypt_ok_test(Config) ->
_ = capi_ct_helper:mock_services(
[
{invoicing, fun(
'StartPayment',
{
_UserInfo,
_InvoiceID,
#payproc_InvoicePaymentParams{
payer =
{payment_resource, #payproc_PaymentResourcePayerParams{
resource = #domain_DisposablePaymentResource{
payment_tool = {
bank_card,
#domain_BankCard{
is_cvv_empty = undefined,
token_provider_deprecated = undefined,
payment_system_deprecated = mastercard
{invoicing, fun
('Get', _) ->
{ok, ?PAYPROC_INVOICE};
(
'StartPayment',
{
_UserInfo,
_InvoiceID,
#payproc_InvoicePaymentParams{
payer =
{payment_resource, #payproc_PaymentResourcePayerParams{
resource = #domain_DisposablePaymentResource{
payment_tool = {
bank_card,
#domain_BankCard{
is_cvv_empty = undefined,
token_provider_deprecated = undefined,
payment_system_deprecated = mastercard
}
}
}
}
}}
}}
}
}
}
) ->
{ok, ?PAYPROC_PAYMENT}
) ->
{ok, ?PAYPROC_PAYMENT}
end},
{generator, fun('GenerateID', _) -> capi_ct_helper_bender:generate_id(<<"bender_key">>) end}
],
@ -511,12 +459,23 @@ get_payments_ok_test(Config) ->
-spec get_payment_by_id_ok_test(config()) -> _.
get_payment_by_id_ok_test(Config) ->
Result = ?PAYPROC_PAYMENT(?PAYMENT_WITH_RECURRENT_PAYER, [?REFUND], [?ADJUSTMENT], [?PAYPROC_CHARGEBACK]),
_ = capi_ct_helper:mock_services([{invoicing, fun('GetPayment', _) -> {ok, Result} end}], Config),
_ = capi_ct_helper:mock_services(
[
{invoicing, fun
('Get', _) -> {ok, ?PAYPROC_INVOICE([Result])};
('GetPayment', _) -> {ok, Result}
end}
],
Config
),
{ok, _} = capi_client_payments:get_payment_by_id(?config(context, Config), ?STRING, ?STRING).
-spec get_payment_by_id_trx_ok_test(config()) -> _.
get_payment_by_id_trx_ok_test(Config) ->
_ = capi_ct_helper:mock_services([{invoicing, fun('GetPayment', _) -> {ok, ?PAYPROC_PAYMENT} end}], Config),
_ = capi_ct_helper:mock_services(
[{invoicing, fun('Get', _) -> {ok, ?PAYPROC_INVOICE([?PAYPROC_PAYMENT])} end}],
Config
),
{ok, #{
<<"transactionInfo">> := #{
<<"rrn">> := <<"090909090909">>,
@ -533,12 +492,28 @@ get_client_payment_status_test(Config) ->
-spec cancel_payment_ok_test(config()) -> _.
cancel_payment_ok_test(Config) ->
_ = capi_ct_helper:mock_services([{invoicing, fun('CancelPayment', _) -> {ok, ok} end}], Config),
_ = capi_ct_helper:mock_services(
[
{invoicing, fun
('Get', _) -> {ok, ?PAYPROC_INVOICE};
('CancelPayment', _) -> {ok, ok}
end}
],
Config
),
ok = capi_client_payments:cancel_payment(?config(context, Config), ?STRING, ?STRING, ?STRING).
-spec capture_payment_ok_test(config()) -> _.
capture_payment_ok_test(Config) ->
_ = capi_ct_helper:mock_services([{invoicing, fun('CapturePayment', _) -> {ok, ok} end}], Config),
_ = capi_ct_helper:mock_services(
[
{invoicing, fun
('Get', _) -> {ok, ?PAYPROC_INVOICE};
('CapturePayment', _) -> {ok, ok}
end}
],
Config
),
Req = #{
<<"reason">> => ?STRING
},
@ -548,19 +523,22 @@ capture_payment_ok_test(Config) ->
capture_partial_payment_ok_test(Config) ->
_ = capi_ct_helper:mock_services(
[
{invoicing, fun(
'CapturePayment',
{
_,
_,
_,
#payproc_InvoicePaymentCaptureParams{
cash = ?CASH,
cart = ?THRIFT_INVOICE_CART
{invoicing, fun
('Get', _) ->
{ok, ?PAYPROC_INVOICE};
(
'CapturePayment',
{
_,
_,
_,
#payproc_InvoicePaymentCaptureParams{
cash = ?CASH,
cart = ?THRIFT_INVOICE_CART
}
}
}
) ->
{ok, ok}
) ->
{ok, ok}
end}
],
Config
@ -577,7 +555,12 @@ capture_partial_payment_ok_test(Config) ->
create_first_recurrent_payment_ok_test(Config) ->
_ = capi_ct_helper:mock_services(
[
{invoicing, fun('StartPayment', _) -> {ok, ?PAYPROC_PAYMENT} end},
{invoicing, fun
('Get', _) ->
{ok, ?PAYPROC_INVOICE};
('StartPayment', _) ->
{ok, ?PAYPROC_PAYMENT}
end},
{generator, fun('GenerateID', _) ->
capi_ct_helper_bender:generate_id(<<"bender_key">>)
end}
@ -603,7 +586,12 @@ create_first_recurrent_payment_ok_test(Config) ->
create_second_recurrent_payment_ok_test(Config) ->
_ = capi_ct_helper:mock_services(
[
{invoicing, fun('StartPayment', _) -> {ok, ?PAYPROC_PAYMENT} end},
{invoicing, fun
('Get', _) ->
{ok, ?PAYPROC_INVOICE};
('StartPayment', _) ->
{ok, ?PAYPROC_PAYMENT}
end},
{generator, fun('GenerateID', _) -> capi_ct_helper_bender:generate_id(<<"bender_key">>) end}
],
Config
@ -641,7 +629,12 @@ get_failed_payment_with_invalid_cvv(Config) ->
),
_ = capi_ct_helper:mock_services(
[
{invoicing, fun('GetPayment', _) -> {ok, ?PAYPROC_FAILED_PAYMENT({failure, Failure})} end}
{invoicing, fun
('Get', _) ->
{ok, ?PAYPROC_INVOICE([?PAYPROC_FAILED_PAYMENT({failure, Failure})])};
('GetPayment', _) ->
{ok, ?PAYPROC_FAILED_PAYMENT({failure, Failure})}
end}
],
Config
),

View File

@ -80,7 +80,7 @@ init_per_group(operations_by_invoice_template_access_token, Config) ->
],
MockServiceSup
),
_ = capi_ct_helper_bouncer:mock_bouncer_assert_shop_op_ctx(
_ = capi_ct_helper_bouncer:mock_assert_shop_op_ctx(
<<"CreateInvoiceTemplate">>,
?STRING,
?STRING,
@ -136,10 +136,11 @@ create_invoice_with_tpl_ok_test(Config) ->
],
Config
),
_ = capi_ct_helper_bouncer:mock_bouncer_assert_shop_op_ctx(
_ = capi_ct_helper_bouncer:mock_assert_invoice_tpl_op_ctx(
<<"CreateInvoiceWithTemplate">>,
?STRING,
?STRING,
?STRING,
Config
),
Req = #{
@ -152,7 +153,13 @@ create_invoice_with_tpl_ok_test(Config) ->
-spec get_invoice_template_ok_test(config()) -> _.
get_invoice_template_ok_test(Config) ->
_ = capi_ct_helper:mock_services([{invoice_templating, fun('Get', _) -> {ok, ?INVOICE_TPL} end}], Config),
_ = capi_ct_helper_bouncer:mock_bouncer_assert_shop_op_ctx(<<"GetInvoiceTemplateByID">>, ?STRING, ?STRING, Config),
_ = capi_ct_helper_bouncer:mock_assert_invoice_tpl_op_ctx(
<<"GetInvoiceTemplateByID">>,
?STRING,
?STRING,
?STRING,
Config
),
{ok, _} = capi_client_invoice_templates:get_template_by_id(?config(context, Config), ?STRING).
-spec get_invoice_payment_methods_by_tpl_id_ok_test(config()) -> _.
@ -167,10 +174,11 @@ get_invoice_payment_methods_by_tpl_id_ok_test(Config) ->
],
Config
),
_ = capi_ct_helper_bouncer:mock_bouncer_assert_shop_op_ctx(
_ = capi_ct_helper_bouncer:mock_assert_invoice_tpl_op_ctx(
<<"GetInvoicePaymentMethodsByTemplateID">>,
?STRING,
?STRING,
?STRING,
Config
),
{ok, _} = capi_client_invoice_templates:get_invoice_payment_methods(?config(context, Config), ?STRING).

View File

@ -1,13 +1,10 @@
-module(capi_self_tests_SUITE).
-include_lib("common_test/include/ct.hrl").
-include_lib("stdlib/include/assert.hrl").
-include_lib("damsel/include/dmsl_domain_config_thrift.hrl").
-include_lib("damsel/include/dmsl_payment_processing_thrift.hrl").
-include_lib("damsel/include/dmsl_merch_stat_thrift.hrl").
-include_lib("capi_dummy_data.hrl").
-include_lib("jose/include/jose_jwk.hrl").
-export([all/0]).
-export([groups/0]).
@ -90,7 +87,7 @@ init_per_group(GroupName, Config) when stream_handler_tests =:= GroupName; valid
{ok, Token} = capi_ct_helper:issue_token(BasePermissions, unlimited),
Context = capi_ct_helper:get_context(Token),
SupPid = capi_ct_helper:start_mocked_service_sup(?MODULE),
Apps1 = capi_ct_helper_bouncer:mock_bouncer_arbiter(capi_ct_helper_bouncer:judge_always_allowed(), SupPid),
Apps1 = capi_ct_helper_bouncer:mock_arbiter(capi_ct_helper_bouncer:judge_always_allowed(), SupPid),
[{context, Context}, {group_apps, Apps1}, {group_test_sup, SupPid} | Config];
init_per_group(_, Config) ->
Config.

View File

@ -2,10 +2,6 @@
-include_lib("common_test/include/ct.hrl").
-include_lib("damsel/include/dmsl_domain_config_thrift.hrl").
-include_lib("capi_dummy_data.hrl").
-include_lib("jose/include/jose_jwk.hrl").
-export([all/0]).
-export([groups/0]).
-export([init_per_suite/1]).
@ -82,7 +78,7 @@ init_per_group(woody_errors, Config) ->
{ok, Token} = capi_ct_helper:issue_token(BasePermissions, unlimited),
Context = capi_ct_helper:get_context(Token),
SupPid = capi_ct_helper:start_mocked_service_sup(?MODULE),
Apps1 = capi_ct_helper_bouncer:mock_bouncer_arbiter(capi_ct_helper_bouncer:judge_always_allowed(), SupPid),
Apps1 = capi_ct_helper_bouncer:mock_arbiter(capi_ct_helper_bouncer:judge_always_allowed(), SupPid),
[{context, Context}, {group_apps, Apps1}, {group_test_sup, SupPid} | Config];
init_per_group(_, Config) ->
Config.

@ -1 +1 @@
Subproject commit 24aa772730be966667adb285a09fcb494d4f218e
Subproject commit 56606f5cacec1c30ca11088c575e9c285f1f2f40