class ActiveMerchant::Billing::AirwallexGateway
Constants
- ENDPOINTS
- TEST_NETWORK_TRANSACTION_IDS
Provided by Airwallex for testing purposes
Public Class Methods
new(options = {})
click to toggle source
Calls superclass method
ActiveMerchant::Billing::Gateway::new
# File lib/active_merchant/billing/gateways/airwallex.rb, line 30 def initialize(options = {}) requires!(options, :client_id, :client_api_key) @client_id = options[:client_id] @client_api_key = options[:client_api_key] super @access_token = options[:access_token] || setup_access_token end
Public Instance Methods
capture(money, authorization, options = {})
click to toggle source
# File lib/active_merchant/billing/gateways/airwallex.rb, line 59 def capture(money, authorization, options = {}) raise ArgumentError, 'An authorization value must be provided.' if authorization.blank? post = { 'request_id' => request_id(options), 'merchant_order_id' => merchant_order_id(options), 'amount' => amount(money) } add_descriptor(post, options) commit(:capture, post, authorization) end
purchase(money, card, options = {})
click to toggle source
# File lib/active_merchant/billing/gateways/airwallex.rb, line 38 def purchase(money, card, options = {}) payment_intent_id = create_payment_intent(money, options) post = { 'request_id' => request_id(options), 'merchant_order_id' => merchant_order_id(options) } add_card(post, card, options) add_descriptor(post, options) add_stored_credential(post, options) add_return_url(post, options) post['payment_method_options'] = { 'card' => { 'auto_capture' => false } } if authorization_only?(options) add_three_ds(post, options) commit(:sale, post, payment_intent_id) end
refund(money, authorization, options = {})
click to toggle source
# File lib/active_merchant/billing/gateways/airwallex.rb, line 72 def refund(money, authorization, options = {}) raise ArgumentError, 'An authorization value must be provided.' if authorization.blank? post = {} post[:amount] = amount(money) post[:payment_intent_id] = authorization post[:request_id] = request_id(options) post[:merchant_order_id] = merchant_order_id(options) commit(:refund, post) end
scrub(transcript)
click to toggle source
# File lib/active_merchant/billing/gateways/airwallex.rb, line 106 def scrub(transcript) transcript. gsub(/(\\\"number\\\":\\\")\d+/, '\1[REDACTED]'). gsub(/(\\\"cvc\\\":\\\")\d+/, '\1[REDACTED]') end
supports_scrubbing?()
click to toggle source
# File lib/active_merchant/billing/gateways/airwallex.rb, line 102 def supports_scrubbing? true end
verify(credit_card, options = {})
click to toggle source
# File lib/active_merchant/billing/gateways/airwallex.rb, line 95 def verify(credit_card, options = {}) MultiResponse.run(:use_first_response) do |r| r.process { authorize(100, credit_card, options) } r.process(:ignore_result) { void(r.authorization, options) } end end
void(authorization, options = {})
click to toggle source
# File lib/active_merchant/billing/gateways/airwallex.rb, line 84 def void(authorization, options = {}) raise ArgumentError, 'An authorization value must be provided.' if authorization.blank? post = {} post[:request_id] = request_id(options) post[:merchant_order_id] = merchant_order_id(options) add_descriptor(post, options) commit(:void, post, authorization) end
Private Instance Methods
add_billing(post, card, options = {})
click to toggle source
# File lib/active_merchant/billing/gateways/airwallex.rb, line 179 def add_billing(post, card, options = {}) return unless has_name_info?(card) billing = post['payment_method']['card']['billing'] || {} billing['email'] = options[:email] if options[:email] billing['phone'] = options[:phone] if options[:phone] billing['first_name'] = card.first_name billing['last_name'] = card.last_name billing_address = options[:billing_address] billing['address'] = build_address(billing_address) if has_required_address_info?(billing_address) post['payment_method']['card']['billing'] = billing end
add_card(post, card, options = {})
click to toggle source
# File lib/active_merchant/billing/gateways/airwallex.rb, line 222 def add_card(post, card, options = {}) post['payment_method'] = { 'type' => 'card', 'card' => { 'expiry_month' => format(card.month, :two_digits), 'expiry_year' => card.year.to_s, 'number' => card.number.to_s, 'name' => card.name, 'cvc' => card.verification_value, 'brand' => card.brand } } add_billing(post, card, options) end
add_descriptor(post, options)
click to toggle source
# File lib/active_merchant/billing/gateways/airwallex.rb, line 328 def add_descriptor(post, options) post[:descriptor] = options[:description] if options[:description] end
add_invoice(post, money, options)
click to toggle source
# File lib/active_merchant/billing/gateways/airwallex.rb, line 217 def add_invoice(post, money, options) post[:amount] = amount(money) post[:currency] = (options[:currency] || currency(money)) end
add_order(post, options)
click to toggle source
# File lib/active_merchant/billing/gateways/airwallex.rb, line 237 def add_order(post, options) return unless shipping_address = options[:shipping_address] physical_address = build_shipping_address(shipping_address) first_name, last_name = split_names(shipping_address[:name]) shipping = {} shipping[:first_name] = first_name if first_name shipping[:last_name] = last_name if last_name shipping[:phone_number] = shipping_address[:phone_number] if shipping_address[:phone_number] shipping[:address] = physical_address post[:order] = { shipping: shipping } end
add_referrer_data(post)
click to toggle source
# File lib/active_merchant/billing/gateways/airwallex.rb, line 159 def add_referrer_data(post) post[:referrer_data] = { type: 'spreedly' } end
add_return_url(post, options)
click to toggle source
# File lib/active_merchant/billing/gateways/airwallex.rb, line 122 def add_return_url(post, options) post[:return_url] = options[:return_url] if options[:return_url] end
add_stored_credential(post, options)
click to toggle source
# File lib/active_merchant/billing/gateways/airwallex.rb, line 260 def add_stored_credential(post, options) return unless stored_credential = options[:stored_credential] external_recurring_data = post[:external_recurring_data] = {} case stored_credential.dig(:reason_type) when 'recurring', 'installment' external_recurring_data[:merchant_trigger_reason] = 'scheduled' when 'unscheduled' external_recurring_data[:merchant_trigger_reason] = 'unscheduled' end external_recurring_data[:original_transaction_id] = test_mit?(options) ? test_network_transaction_id(post) : stored_credential.dig(:network_transaction_id) external_recurring_data[:triggered_by] = stored_credential.dig(:initiator) == 'cardholder' ? 'customer' : 'merchant' end
add_three_ds(post, options)
click to toggle source
# File lib/active_merchant/billing/gateways/airwallex.rb, line 289 def add_three_ds(post, options) return unless three_d_secure = options[:three_d_secure] pm_options = post.dig('payment_method_options', 'card') external_three_ds = { version: format_three_ds_version(three_d_secure), eci: three_d_secure[:eci] }.merge(three_ds_version_specific_fields(three_d_secure)) pm_options ? pm_options.merge!(external_three_ds: external_three_ds) : post['payment_method_options'] = { card: { external_three_ds: external_three_ds } } end
build_address(address)
click to toggle source
# File lib/active_merchant/billing/gateways/airwallex.rb, line 205 def build_address(address) return unless address address_data = {} # names r hard address_data[:country_code] = address[:country] address_data[:street] = address[:address1] address_data[:city] = address[:city] if address[:city] # required per doc, not in practice address_data[:postcode] = address[:zip] if address[:zip] address_data[:state] = address[:state] if address[:state] address_data end
build_request_url(action, id = nil)
click to toggle source
# File lib/active_merchant/billing/gateways/airwallex.rb, line 152 def build_request_url(action, id = nil) base_url = (test? ? test_url : live_url) endpoint = ENDPOINTS[action].to_s endpoint = id.present? ? endpoint % { id: id } : endpoint base_url + endpoint end
build_shipping_address(shipping_address)
click to toggle source
# File lib/active_merchant/billing/gateways/airwallex.rb, line 250 def build_shipping_address(shipping_address) address = {} address[:city] = shipping_address[:city] address[:country_code] = shipping_address[:country] address[:postcode] = shipping_address[:zip] address[:state] = shipping_address[:state] address[:street] = shipping_address[:address1] address end
commit(action, post, id = nil)
click to toggle source
# File lib/active_merchant/billing/gateways/airwallex.rb, line 336 def commit(action, post, id = nil) url = build_request_url(action, id) post_headers = { 'Authorization' => "Bearer #{@access_token}", 'Content-Type' => 'application/json' } response = parse(ssl_post(url, post_data(post), post_headers)) Response.new( success_from(response), message_from(response), response, authorization: authorization_from(response), avs_result: AVSResult.new(code: response.dig('latest_payment_attempt', 'authentication_data', 'avs_result')), cvv_result: CVVResult.new(response.dig('latest_payment_attempt', 'authentication_data', 'cvc_code')), test: test?, error_code: error_code_from(response) ) end
create_payment_intent(money, options = {})
click to toggle source
# File lib/active_merchant/billing/gateways/airwallex.rb, line 163 def create_payment_intent(money, options = {}) post = {} add_invoice(post, money, options) add_order(post, options) post[:request_id] = "#{request_id(options)}_setup" post[:merchant_order_id] = merchant_order_id(options) add_referrer_data(post) add_descriptor(post, options) post['payment_method_options'] = { 'card' => { 'risk_control' => { 'three_ds_action' => 'SKIP_3DS' } } } if options[:skip_3ds] response = commit(:setup, post) raise ArgumentError.new(response.message) unless response.success? response.params['id'] end
error_code_from(response)
click to toggle source
# File lib/active_merchant/billing/gateways/airwallex.rb, line 379 def error_code_from(response) response['provider_original_response_code'] || response['code'] unless success_from(response) end
format_three_ds_version(three_d_secure)
click to toggle source
# File lib/active_merchant/billing/gateways/airwallex.rb, line 302 def format_three_ds_version(three_d_secure) version = three_d_secure[:version].split('.') version.push('0') until version.length == 3 version.join('.') end
generate_uuid()
click to toggle source
# File lib/active_merchant/billing/gateways/airwallex.rb, line 126 def generate_uuid SecureRandom.uuid end
handle_response(response)
click to toggle source
# File lib/active_merchant/billing/gateways/airwallex.rb, line 354 def handle_response(response) case response.code.to_i when 200...300, 400, 404 response.body else raise ResponseError.new(response) end end
has_name_info?(card)
click to toggle source
# File lib/active_merchant/billing/gateways/airwallex.rb, line 193 def has_name_info?(card) # These fields are required if billing data is sent. card.first_name && card.last_name end
has_required_address_info?(address)
click to toggle source
# File lib/active_merchant/billing/gateways/airwallex.rb, line 198 def has_required_address_info?(address) # These fields are required if address data is sent. return unless address address[:address1] && address[:country] end
merchant_order_id(options)
click to toggle source
# File lib/active_merchant/billing/gateways/airwallex.rb, line 118 def merchant_order_id(options) options[:merchant_order_id] || options[:order_id] || generate_uuid end
message_from(response)
click to toggle source
# File lib/active_merchant/billing/gateways/airwallex.rb, line 371 def message_from(response) response.dig('latest_payment_attempt', 'status') || response['status'] || response['message'] end
parse(body)
click to toggle source
# File lib/active_merchant/billing/gateways/airwallex.rb, line 332 def parse(body) JSON.parse(body) end
post_data(post)
click to toggle source
# File lib/active_merchant/billing/gateways/airwallex.rb, line 363 def post_data(post) post.to_json end
request_id(options)
click to toggle source
# File lib/active_merchant/billing/gateways/airwallex.rb, line 114 def request_id(options) options[:request_id] || generate_uuid end
setup_access_token()
click to toggle source
# File lib/active_merchant/billing/gateways/airwallex.rb, line 130 def setup_access_token token_headers = { 'Content-Type' => 'application/json', 'x-client-id' => @client_id, 'x-api-key' => @client_api_key } begin raw_response = ssl_post(build_request_url(:login), nil, token_headers) rescue ResponseError => e raise OAuthResponseError.new(e) else response = JSON.parse(raw_response) if (token = response['token']) token else oauth_response = Response.new(false, response['message']) raise OAuthResponseError.new(oauth_response) end end end
success_from(response)
click to toggle source
# File lib/active_merchant/billing/gateways/airwallex.rb, line 367 def success_from(response) %w(REQUIRES_PAYMENT_METHOD SUCCEEDED RECEIVED REQUIRES_CAPTURE CANCELLED).include?(response['status']) end
test_mit?(options)
click to toggle source
# File lib/active_merchant/billing/gateways/airwallex.rb, line 285 def test_mit?(options) test? && options.dig(:stored_credential, :initiator) == 'merchant' end
test_network_transaction_id(post)
click to toggle source
# File lib/active_merchant/billing/gateways/airwallex.rb, line 276 def test_network_transaction_id(post) case post['payment_method']['card']['brand'] when 'visa' TEST_NETWORK_TRANSACTION_IDS[:visa] when 'master' TEST_NETWORK_TRANSACTION_IDS[:master] end end
three_ds_version_specific_fields(three_d_secure)
click to toggle source
# File lib/active_merchant/billing/gateways/airwallex.rb, line 309 def three_ds_version_specific_fields(three_d_secure) if three_d_secure[:version].to_f >= 2 { authentication_value: three_d_secure[:cavv], ds_transaction_id: three_d_secure[:ds_transaction_id], three_ds_server_transaction_id: three_d_secure[:three_ds_server_trans_id] } else { cavv: three_d_secure[:cavv], xid: three_d_secure[:xid] } end end