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