lib/active_merchant/billing/gateways/rapyd.rb in activemerchant-1.126.0 vs lib/active_merchant/billing/gateways/rapyd.rb in activemerchant-1.129.0

- old
+ new

@@ -2,149 +2,166 @@ module Billing #:nodoc: class RapydGateway < Gateway self.test_url = 'https://sandboxapi.rapyd.net/v1/' self.live_url = 'https://api.rapyd.net/v1/' - self.supported_countries = %w(US BR CA CL CO DO SV MX PE PT VI AU HK IN ID JP MY NZ PH SG KR TW TH VN AD AT BE BA BG HR CY CZ DK EE FI FR GE DE GI GR GL HU IS IE IL IT LV LI LT LU MK MT MD MC ME NL GB NO PL RO RU SM SK SI ZA ES SE CH TR VA) + self.supported_countries = %w(CA CL CO DO SV PE PT VI AU HK IN ID JP MY NZ PH SG KR TW TH VN AD AT BE BA BG HR CY CZ DK EE FI FR GE DE GI GR GL HU IS IE IL IT LV LI LT LU MK MT MD MC ME NL GB NO PL RO RU SM SK SI ZA ES SE CH TR VA) self.default_currency = 'USD' self.supported_cardtypes = %i[visa master american_express discover] self.homepage_url = 'https://www.rapyd.net/' self.display_name = 'Rapyd Gateway' + USA_PAYMENT_METHODS = %w[us_debit_discover_card us_debit_mastercard_card us_debit_visa_card us_ach_bank] + STANDARD_ERROR_CODE_MAPPING = {} def initialize(options = {}) requires!(options, :secret_key, :access_key) super end def purchase(money, payment, options = {}) post = {} - add_invoice(post, money, options) - add_payment(post, payment, options) - add_address(post, payment, options) - add_metadata(post, options) - add_ewallet(post, options) - post[:capture] = true if payment_is_card?(options) + add_auth_purchase(post, money, payment, options) + post[:capture] = true unless payment.is_a?(Check) - if payment_is_ach?(options) - MultiResponse.run do |r| - r.process { commit(:post, 'payments', post) } - post = {} - post[:token] = r.authorization - post[:param2] = r.params.dig('data', 'original_amount').to_s - r.process { commit(:post, 'payments/completePayment', post) } - end - else - commit(:post, 'payments', post) - end + commit(:post, 'payments', post) end def authorize(money, payment, options = {}) post = {} - add_invoice(post, money, options) - add_payment(post, payment, options) - add_address(post, payment, options) - add_metadata(post, options) - add_ewallet(post, options) - post[:capture] = false + add_auth_purchase(post, money, payment, options) + post[:capture] = false unless payment.is_a?(Check) + commit(:post, 'payments', post) end def capture(money, authorization, options = {}) post = {} - commit(:post, "payments/#{authorization}/capture", post) + commit(:post, "payments/#{add_reference(authorization)}/capture", post) end def refund(money, authorization, options = {}) post = {} - post[:payment] = authorization + post[:payment] = add_reference(authorization) add_invoice(post, money, options) add_metadata(post, options) + add_ewallet(post, options) + commit(:post, 'refunds', post) end def void(authorization, options = {}) post = {} - commit(:delete, "payments/#{authorization}", post) + commit(:delete, "payments/#{add_reference(authorization)}", post) end - # Gateway returns an error if trying to run a $0 auth as invalid payment amount - # Gateway does not support void on a card transaction and refunds can only be done on completed transactions - # (such as a purchase). Authorize transactions are considered 'active' and not 'complete' until they are captured. def verify(credit_card, options = {}) - MultiResponse.run do |r| - r.process { purchase(100, credit_card, options) } - r.process { refund(100, r.authorization, options) } - end + authorize(0, credit_card, options) end + def store(payment, options = {}) + post = {} + add_payment(post, payment, options) + add_customer_object(post, payment, options) + add_metadata(post, options) + add_ewallet(post, options) + add_payment_fields(post, options) + add_payment_urls(post, options) + add_address(post, payment, options) + commit(:post, 'customers', post) + end + + def unstore(customer) + commit(:delete, "customers/#{add_reference(customer)}", {}) + end + def supports_scrubbing? true end def scrub(transcript) transcript. gsub(%r((Access_key: )\w+), '\1[FILTERED]'). gsub(%r(("number\\?":\\?")\d+), '\1[FILTERED]'). + gsub(%r(("account_number\\?":\\?")\d+), '\1[FILTERED]'). + gsub(%r(("routing_number\\?":\\?")\d+), '\1[FILTERED]'). gsub(%r(("cvv\\?":\\?")\d+), '\1[FILTERED]') end private - def payment_is_ach?(options) - return unless options[:pm_type] + def add_reference(authorization) + return unless authorization - return true if options[:pm_type].include?('_bank') + authorization.split('|')[0] end - def payment_is_card?(options) - return unless options[:pm_type] - - return true if options[:pm_type].include?('_card') + def add_auth_purchase(post, money, payment, options) + add_invoice(post, money, options) + add_payment(post, payment, options) + add_customer_object(post, payment, options) + add_3ds(post, payment, options) + add_address(post, payment, options) + add_metadata(post, options) + add_ewallet(post, options) + add_payment_fields(post, options) + add_payment_urls(post, options) + add_customer_id(post, options) end def add_address(post, creditcard, options) - return unless address = options[:address] + return unless address = options[:billing_address] post[:address] = {} # name and line_1 are required at the gateway post[:address][:name] = address[:name] if address[:name] post[:address][:line_1] = address[:address1] if address[:address1] post[:address][:line_2] = address[:address2] if address[:address2] post[:address][:city] = address[:city] if address[:city] post[:address][:state] = address[:state] if address[:state] post[:address][:country] = address[:country] if address[:country] post[:address][:zip] = address[:zip] if address[:zip] - post[:address][:phone_number] = address[:phone] if address[:phone] + post[:address][:phone_number] = address[:phone].gsub(/\D/, '') if address[:phone] end def add_invoice(post, money, options) - post[:amount] = amount(money).to_f.to_s + post[:amount] = money.zero? ? 0 : amount(money).to_f.to_s post[:currency] = (options[:currency] || currency(money)) end def add_payment(post, payment, options) - if payment_is_card?(options) + if payment.is_a?(CreditCard) add_creditcard(post, payment, options) - elsif payment_is_ach?(options) + elsif payment.is_a?(Check) add_ach(post, payment, options) + else + add_token(post, payment, options) end end + def add_stored_credential(post, options) + return unless stored_credential = options[:stored_credential] + + post[:payment_method][:fields][:network_reference_id] = stored_credential[:network_transaction_id] if stored_credential[:network_transaction_id] + post[:initiation_type] = stored_credential[:reason_type] if stored_credential[:reason_type] + end + def add_creditcard(post, payment, options) post[:payment_method] = {} post[:payment_method][:fields] = {} pm_fields = post[:payment_method][:fields] post[:payment_method][:type] = options[:pm_type] pm_fields[:number] = payment.number pm_fields[:expiration_month] = payment.month.to_s pm_fields[:expiration_year] = payment.year.to_s - pm_fields[:cvv] = payment.verification_value.to_s pm_fields[:name] = "#{payment.first_name} #{payment.last_name}" + pm_fields[:cvv] = payment.verification_value.to_s + + add_stored_credential(post, options) end def add_ach(post, payment, options) post[:payment_method] = {} post[:payment_method][:fields] = {} @@ -156,18 +173,60 @@ post[:payment_method][:fields][:routing_number] = payment.routing_number post[:payment_method][:fields][:account_number] = payment.account_number post[:payment_method][:fields][:payment_purpose] = options[:payment_purpose] if options[:payment_purpose] end + def add_token(post, payment, options) + return unless token = payment.split('|')[1] + + post[:payment_method] = token + end + + def add_3ds(post, payment, options) + return unless three_d_secure = options[:three_d_secure] + + post[:payment_method_options] = {} + post[:payment_method_options]['3d_required'] = three_d_secure[:required] + post[:payment_method_options]['3d_version'] = three_d_secure[:version] + post[:payment_method_options][:cavv] = three_d_secure[:cavv] + post[:payment_method_options][:eci] = three_d_secure[:eci] + post[:payment_method_options][:xid] = three_d_secure[:xid] + post[:payment_method_options][:ds_trans_id] = three_d_secure[:ds_transaction_id] + end + def add_metadata(post, options) post[:metadata] = options[:metadata] if options[:metadata] end def add_ewallet(post, options) post[:ewallet_id] = options[:ewallet_id] if options[:ewallet_id] end + def add_payment_fields(post, options) + post[:payment] = {} + + post[:payment][:description] = options[:description] if options[:description] + post[:payment][:statement_descriptor] = options[:statement_descriptor] if options[:statement_descriptor] + end + + def add_payment_urls(post, options) + post[:complete_payment_url] = options[:complete_payment_url] if options[:complete_payment_url] + post[:error_payment_url] = options[:error_payment_url] if options[:error_payment_url] + end + + def add_customer_object(post, payment, options) + post[:name] = "#{payment.first_name} #{payment.last_name}" unless payment.is_a?(String) + phone = options.dig(:billing_address, :phone) .gsub(/\D/, '') unless options[:billing_address].nil? + post[:phone_number] = phone || options.dig(:customer, :phone_number) + post[:email] = options[:email] || options.dig(:customer, :email) + post[:addresses] = options.dig(:customer, :addresses) if USA_PAYMENT_METHODS.include?(options[:pm_type]) + end + + def add_customer_id(post, options) + post[:customer] = options[:customer_id] if options[:customer_id] + end + def parse(body) return {} if body.empty? || body.nil? JSON.parse(body) end @@ -236,10 +295,12 @@ response.dig('status', 'status') end end def authorization_from(response) - response.dig('data') ? response.dig('data', 'id') : response.dig('status', 'operation_id') + id = response.dig('data') ? response.dig('data', 'id') : response.dig('status', 'operation_id') + + "#{id}|#{response.dig('data', 'default_payment_method')}" end def error_code_from(response) response.dig('status', 'error_code') unless success_from(response) end