# frozen_string_literal: true require_relative 'support/case_insensitive_hash' require 'cgi' require 'date' module Buckaruby # Base class for any response. class Response attr_reader :response def initialize(body, config) @response = parse_response(body) logger = config.logger logger.debug("[response] params: #{params.inspect}") end def params @params ||= Support::CaseInsensitiveHash.new(response) end def status TransactionStatus.parse(params[:brq_statuscode]) end def timestamp parse_time(params[:brq_timestamp]) end def custom @custom ||= begin custom = Support::CaseInsensitiveHash.new params.each do |key, value| next unless key.upcase.start_with?('CUST_') new_key = key.to_s[5..-1] custom[new_key] = value end custom end end def additional @additional ||= begin additional = Support::CaseInsensitiveHash.new params.each do |key, value| next unless key.upcase.start_with?('ADD_') new_key = key.to_s[4..-1] additional[new_key] = value end additional end end private def parse_response(body) if body.is_a?(Hash) response = body else response = CGI.parse(body) response.each { |key, value| response[key] = value.first } end response end def parse_time(time) Time.strptime(time, '%Y-%m-%d %H:%M:%S') if time end end # Base for a transaction response. module TransactionResponse def consumer_bic case payment_method when PaymentMethod::IDEAL params[:brq_service_ideal_consumerbic] when PaymentMethod::IDEAL_PROCESSING params[:brq_service_idealprocessing_consumerbic] when PaymentMethod::SEPA_DIRECT_DEBIT params[:brq_service_sepadirectdebit_customerbic] end end def consumer_iban case payment_method when PaymentMethod::IDEAL params[:brq_service_ideal_consumeriban] when PaymentMethod::IDEAL_PROCESSING params[:brq_service_idealprocessing_consumeriban] when PaymentMethod::SEPA_DIRECT_DEBIT params[:brq_service_sepadirectdebit_customeriban] end end def consumer_name case payment_method when PaymentMethod::IDEAL params[:brq_service_ideal_consumername] || params[:brq_customer_name] when PaymentMethod::IDEAL_PROCESSING params[:brq_service_idealprocessing_consumername] || params[:brq_customer_name] when PaymentMethod::SEPA_DIRECT_DEBIT params[:brq_service_sepadirectdebit_customername] || params[:brq_customer_name] end end def collect_date if payment_method == PaymentMethod::SEPA_DIRECT_DEBIT parse_date(params[:brq_service_sepadirectdebit_collectdate]) end end def invoicenumber params[:brq_invoicenumber] end def mandate_reference if payment_method == PaymentMethod::SEPA_DIRECT_DEBIT params[:brq_service_sepadirectdebit_mandatereference] end end def payment_id params[:brq_payment] end def payment_method parse_payment_method(params[:brq_payment_method] || params[:brq_transaction_method]) end def transaction_id params[:brq_transactions] end def transaction_status status end def transaction_type TransactionType.parse(params[:brq_transaction_type], params[:brq_recurring]) end private def parse_date(date) Date.strptime(date, '%Y-%m-%d') if date end def parse_payment_method(method) method&.downcase end end # Base class for a response via the API. class ApiResponse < Response def initialize(body, config) super(body, config) if api_result.nil? || api_result.casecmp('fail').zero? raise ApiException, params end Signature.verify!(config, response) end private def api_result params[:brq_apiresult] end end # Response when creating a new transaction. class SetupTransactionResponse < ApiResponse include TransactionResponse def redirect_url params[:brq_redirecturl] end end # Response when creating a recurrent transaction. class RecurrentTransactionResponse < ApiResponse include TransactionResponse def transaction_type TransactionType::PAYMENT_RECURRENT end end # Response when creating a refund transaction. class RefundTransactionResponse < ApiResponse include TransactionResponse def refunded_transaction_id params[:brq_relatedtransaction_refund] end def transaction_type TransactionType::REFUND end end # Response when retrieving the refund information. class RefundInfoResponse < ApiResponse def payment_method params[:brq_refundinfo_1_servicecode] end def refundable? !params[:brq_refundinfo_1_isrefundable].nil? && params[:brq_refundinfo_1_isrefundable].casecmp('true').zero? end def maximum_amount params[:brq_refundinfo_1_maximumrefundamount] end def invoicenumber params[:brq_refundinfo_1_invoice] end def currency params[:brq_refundinfo_1_refundcurrency] end end # Response when getting the status of a transaction. class StatusResponse < ApiResponse include TransactionResponse def cancellable? !params[:brq_transaction_cancelable].nil? && params[:brq_transaction_cancelable].casecmp('true').zero? end def refunded_transaction_id params[:brq_relatedtransaction_refund] end def reversed_transaction_id params[:brq_relatedtransaction_reversal] end end # Response when cancelling a transaction. class CancelResponse < ApiResponse end # Response when verifying the push response. class PushResponse < Response include TransactionResponse def initialize(body, config) super(body, config) Signature.verify!(config, response) end def refunded_transaction_id params[:brq_relatedtransaction_refund] end def reversed_transaction_id params[:brq_relatedtransaction_reversal] end end # Response when retrieving the specification for a transaction. class TransactionSpecificationResponse < ApiResponse def services @services ||= FieldMapper.map_fields(params, :brq_services) end def basic_fields @basic_fields ||= FieldMapper.map_fields(params, :brq_basicfields) end def custom_parameters @custom_parameters ||= FieldMapper.map_fields(params, :brq_customparameters) end end end