class ActiveMerchant::Billing::FirstdataE4V27Gateway
Constants
- BRANDS
- DEFAULT_ECI
- SENSITIVE_FIELDS
- STANDARD_ERROR_CODE_MAPPING
- SUCCESS
- TRANSACTIONS
Public Class Methods
new(options = {})
click to toggle source
Calls superclass method
ActiveMerchant::Billing::Gateway::new
# File lib/active_merchant/billing/gateways/firstdata_e4_v27.rb, line 58 def initialize(options = {}) requires!(options, :login, :password, :key_id, :hmac_key) @options = options super end
Public Instance Methods
capture(money, authorization, options = {})
click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4_v27.rb, line 73 def capture(money, authorization, options = {}) commit(:capture, build_capture_or_credit_request(money, authorization, options)) end
purchase(money, credit_card_or_store_authorization, options = {})
click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4_v27.rb, line 69 def purchase(money, credit_card_or_store_authorization, options = {}) commit(:sale, build_sale_or_authorization_request(money, credit_card_or_store_authorization, options)) end
refund(money, authorization, options = {})
click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4_v27.rb, line 81 def refund(money, authorization, options = {}) commit(:credit, build_capture_or_credit_request(money, authorization, options)) end
scrub(transcript)
click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4_v27.rb, line 114 def scrub(transcript) transcript. gsub(%r((<Card_Number>).+(</Card_Number>)), '\1[FILTERED]\2'). gsub(%r((<CVDCode>).+(</CVDCode>)), '\1[FILTERED]\2'). gsub(%r((<Password>).+(</Password>))i, '\1[FILTERED]\2'). gsub(%r((<CAVV>).+(</CAVV>)), '\1[FILTERED]\2'). gsub(%r((CARD NUMBER\s+: )#+\d+), '\1[FILTERED]') end
store(credit_card, options = {})
click to toggle source
Tokenize a credit card with TransArmor
The TransArmor token and other card data necessary for subsequent transactions is stored in the response's authorization
attribute. The authorization string may be passed to authorize
and purchase
instead of a ActiveMerchant::Billing::CreditCard
instance.
TransArmor support must be explicitly activated on your gateway account by FirstData. If your authorization string is empty, contact FirstData support for account setup assistance.
support.payeezy.com/hc/en-us/articles/203731189-TransArmor-Tokenization
# File lib/active_merchant/billing/gateways/firstdata_e4_v27.rb, line 101 def store(credit_card, options = {}) commit(:store, build_store_request(credit_card, options), credit_card) end
supports_network_tokenization?()
click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4_v27.rb, line 123 def supports_network_tokenization? true end
supports_scrubbing?()
click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4_v27.rb, line 110 def supports_scrubbing? true end
verify(credit_card, options = {})
click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4_v27.rb, line 85 def verify(credit_card, options = {}) commit(:verify, build_sale_or_authorization_request(0, credit_card, options)) end
verify_credentials()
click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4_v27.rb, line 105 def verify_credentials response = void('0') response.message != 'Unauthorized Request. Bad or missing credentials.' end
void(authorization, options = {})
click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4_v27.rb, line 77 def void(authorization, options = {}) commit(:void, build_capture_or_credit_request(money_from_authorization(authorization), authorization, options)) end
Private Instance Methods
add_address(xml, options)
click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4_v27.rb, line 288 def add_address(xml, options) if (address = options[:billing_address] || options[:address]) xml.tag! 'Address' do xml.tag! 'Address1', address[:address1] xml.tag! 'Address2', address[:address2] if address[:address2] xml.tag! 'City', address[:city] xml.tag! 'State', address[:state] xml.tag! 'Zip', address[:zip] xml.tag! 'CountryCode', address[:country] end xml.tag! 'ZipCode', address[:zip] end end
add_amount(xml, money, options)
click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4_v27.rb, line 200 def add_amount(xml, money, options) currency_code = options[:currency] || default_currency xml.tag! 'DollarAmount', localized_amount(money, currency_code) xml.tag! 'Currency', currency_code end
add_card_authentication_data(xml, options)
click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4_v27.rb, line 260 def add_card_authentication_data(xml, options) xml.tag! 'CAVV', options[:cavv] xml.tag! 'XID', options[:xid] end
add_credentials(xml)
click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4_v27.rb, line 184 def add_credentials(xml) xml.tag! 'ExactID', @options[:login] xml.tag! 'Password', @options[:password] end
add_credit_card(xml, credit_card, options)
click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4_v27.rb, line 206 def add_credit_card(xml, credit_card, options) if credit_card.respond_to?(:track_data) && credit_card.track_data.present? xml.tag! 'Track1', credit_card.track_data xml.tag! 'Ecommerce_Flag', 'R' else xml.tag! 'Card_Number', credit_card.number xml.tag! 'Expiry_Date', expdate(credit_card) xml.tag! 'CardHoldersName', credit_card.name xml.tag! 'CardType', card_type(credit_card.brand) xml.tag! 'WalletProviderID', options[:wallet_provider_id] if options[:wallet_provider_id] add_credit_card_eci(xml, credit_card, options) add_credit_card_verification_strings(xml, credit_card, options) end end
add_credit_card_eci(xml, credit_card, options)
click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4_v27.rb, line 222 def add_credit_card_eci(xml, credit_card, options) eci = if credit_card.is_a?(NetworkTokenizationCreditCard) && credit_card.source == :apple_pay && card_brand(credit_card) == 'discover' # Discover requires any Apple Pay transaction, regardless of in-app # or web, and regardless of the ECI contained in the PKPaymentToken, # to have an ECI value explicitly of 04. '04' else (credit_card.respond_to?(:eci) ? credit_card.eci : nil) || options[:eci] || DEFAULT_ECI end xml.tag! 'Ecommerce_Flag', eci.to_s =~ /^[0-9]+$/ ? eci.to_s.rjust(2, '0') : eci end
add_credit_card_token(xml, store_authorization, options)
click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4_v27.rb, line 265 def add_credit_card_token(xml, store_authorization, options) params = store_authorization.split(';') credit_card = CreditCard.new( :brand => params[1], :first_name => params[2], :last_name => params[3], :month => params[4], :year => params[5]) xml.tag! 'TransarmorToken', params[0] xml.tag! 'Expiry_Date', expdate(credit_card) xml.tag! 'CardHoldersName', credit_card.name xml.tag! 'CardType', card_type(credit_card.brand) xml.tag! 'WalletProviderID', options[:wallet_provider_id] if options[:wallet_provider_id] add_card_authentication_data(xml, options) end
add_credit_card_verification_strings(xml, credit_card, options)
click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4_v27.rb, line 235 def add_credit_card_verification_strings(xml, credit_card, options) if credit_card.is_a?(NetworkTokenizationCreditCard) add_network_tokenization_credit_card(xml, credit_card) else if credit_card.verification_value? xml.tag! 'CVD_Presence_Ind', '1' xml.tag! 'CVDCode', credit_card.verification_value end add_card_authentication_data(xml, options) end end
add_customer_data(xml, options)
click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4_v27.rb, line 282 def add_customer_data(xml, options) xml.tag! 'Customer_Ref', options[:customer] if options[:customer] xml.tag! 'Client_IP', options[:ip] if options[:ip] xml.tag! 'Client_Email', options[:email] if options[:email] end
add_identification(xml, identification)
click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4_v27.rb, line 193 def add_identification(xml, identification) authorization_num, transaction_tag, _ = identification.split(';') xml.tag! 'Authorization_Num', authorization_num xml.tag! 'Transaction_Tag', transaction_tag end
add_invoice(xml, options)
click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4_v27.rb, line 302 def add_invoice(xml, options) xml.tag! 'Reference_No', options[:order_id] xml.tag! 'Reference_3', options[:description] if options[:description] end
add_level_3(xml, options)
click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4_v27.rb, line 312 def add_level_3(xml, options) xml.tag!('Level3') { |x| x << options[:level_3] } if options[:level_3] end
add_network_tokenization_credit_card(xml, credit_card)
click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4_v27.rb, line 248 def add_network_tokenization_credit_card(xml, credit_card) case card_brand(credit_card).to_sym when :american_express cryptogram = Base64.decode64(credit_card.payment_cryptogram) xml.tag!('XID', Base64.encode64(cryptogram[20...40])) xml.tag!('CAVV', Base64.encode64(cryptogram[0...20])) else xml.tag!('XID', credit_card.transaction_id) if credit_card.transaction_id xml.tag!('CAVV', credit_card.payment_cryptogram) end end
add_stored_credentials(xml, card, options)
click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4_v27.rb, line 316 def add_stored_credentials(xml, card, options) return unless options[:stored_credential] xml.tag! 'StoredCredentials' do xml.tag! 'Indicator', stored_credential_indicator(xml, card, options) if initiator = options.dig(:stored_credential, :initiator) xml.tag! initiator == 'merchant' ? 'M' : 'C' end if reason_type = options.dig(:stored_credential, :reason_type) xml.tag! 'Schedule', reason_type == 'unscheduled' ? 'U' : 'S' end xml.tag! 'AuthorizationTypeOverride', options[:authorization_type_override] if options[:authorization_type_override] if network_transaction_id = options[:stored_credential][:network_transaction_id] xml.tag! 'TransactionId', network_transaction_id else xml.tag! 'TransactionId', 'new' end xml.tag! 'OriginalAmount', options[:original_amount] if options[:original_amount] xml.tag! 'ProtectbuyIndicator', options[:protectbuy_indicator] if options[:protectbuy_indicator] end end
add_tax_fields(xml, options)
click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4_v27.rb, line 307 def add_tax_fields(xml, options) xml.tag! 'Tax1Amount', options[:tax1_amount] if options[:tax1_amount] xml.tag! 'Tax1Number', options[:tax1_number] if options[:tax1_number] end
add_transaction_type(xml, action)
click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4_v27.rb, line 189 def add_transaction_type(xml, action) xml.tag! 'Transaction_Type', TRANSACTIONS[action] end
build_capture_or_credit_request(money, identification, options)
click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4_v27.rb, line 163 def build_capture_or_credit_request(money, identification, options) xml = Builder::XmlMarkup.new add_identification(xml, identification) add_amount(xml, money, options) add_customer_data(xml, options) add_card_authentication_data(xml, options) xml.target! end
build_request(action, body)
click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4_v27.rb, line 129 def build_request(action, body) xml = Builder::XmlMarkup.new xml.instruct! xml.tag! 'Transaction', xmlns: 'http://secure2.e-xact.com/vplug-in/transaction/rpc-enc/encodedTypes' do add_credentials(xml) add_transaction_type(xml, action) xml << body end xml.target! end
build_store_request(credit_card, options)
click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4_v27.rb, line 174 def build_store_request(credit_card, options) xml = Builder::XmlMarkup.new add_credit_card(xml, credit_card, options) add_address(xml, options) add_customer_data(xml, options) xml.target! end
card_type(credit_card_brand)
click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4_v27.rb, line 349 def card_type(credit_card_brand) BRANDS[credit_card_brand.to_sym] if credit_card_brand end
commit(action, data, credit_card = nil)
click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4_v27.rb, line 353 def commit(action, data, credit_card = nil) url = (test? ? self.test_url : self.live_url) request = build_request(action, data) begin response = parse(ssl_post(url, request, headers('POST', url, request))) rescue ResponseError => e response = parse_error(e.response) end Response.new(successful?(response), message_from(response), response, :test => test?, :authorization => successful?(response) ? response_authorization(action, response, credit_card) : '', :avs_result => {:code => response[:avs]}, :cvv_result => response[:cvv2], :error_code => standard_error_code(response) ) end
expdate(credit_card)
click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4_v27.rb, line 345 def expdate(credit_card) "#{format(credit_card.month, :two_digits)}#{format(credit_card.year, :two_digits)}" end
headers(method, url, request)
click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4_v27.rb, line 371 def headers(method, url, request) content_type = 'application/xml' content_digest = Digest::SHA1.hexdigest(request) sending_time = Time.now.utc.iso8601 payload = [method, content_type, content_digest, sending_time, url.split('.com')[1]].join("\n") hmac = OpenSSL::HMAC.digest('sha1', @options[:hmac_key], payload) encoded = Base64.strict_encode64(hmac) { 'x-gge4-date' => sending_time, 'x-gge4-content-sha1' => content_digest, 'Authorization' => 'GGE4_API ' + @options[:key_id].to_s + ':' + encoded, 'Accepts' => content_type, 'Content-Type' => content_type } end
message_from(response)
click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4_v27.rb, line 432 def message_from(response) if response[:faultcode] && response[:faultstring] response[:faultstring] elsif response[:error_number] && response[:error_number] != '0' response[:error_description] else result = (response[:exact_message] || '') result << " - #{response[:bank_message]}" if response[:bank_message].present? result end end
name_node(root, node)
click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4_v27.rb, line 479 def name_node(root, node) parent = root.name unless root.name == 'TransactionResult' "#{parent}#{node.name}".gsub(/EXact/, 'Exact').underscore.to_sym end
parse(xml)
click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4_v27.rb, line 457 def parse(xml) response = {} xml = REXML::Document.new(xml) if (root = REXML::XPath.first(xml, '//TransactionResult')) parse_elements(response, root) end SENSITIVE_FIELDS.each { |key| response.delete(key) } response end
parse_elements(response, root)
click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4_v27.rb, line 469 def parse_elements(response, root) root.elements.to_a.each do |node| if node.has_elements? parse_elements(response, node) else response[name_node(root, node)] = (node.text || '').strip end end end
parse_error(error)
click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4_v27.rb, line 444 def parse_error(error) { :transaction_approved => 'false', :error_number => error.code, :error_description => error.body, :ecommerce_error_code => error.body.gsub(/[^\d]/, '') } end
standard_error_code(response)
click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4_v27.rb, line 453 def standard_error_code(response) STANDARD_ERROR_CODE_MAPPING[response[:bank_resp_code] || response[:ecommerce_error_code]] end
stored_credential_indicator(xml, card, options)
click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4_v27.rb, line 337 def stored_credential_indicator(xml, card, options) if card.brand == 'master' || options.dig(:stored_credential, :initial_transaction) == false 'S' else '1' end end
successful?(response)
click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4_v27.rb, line 388 def successful?(response) response[:transaction_approved] == SUCCESS end