lib/active_merchant/billing/gateways/payflow.rb in activemerchant-1.125.0 vs lib/active_merchant/billing/gateways/payflow.rb in activemerchant-1.126.0
- old
+ new
@@ -81,10 +81,11 @@
ActiveMerchant.deprecated RECURRING_DEPRECATION_MESSAGE
options[:name] = credit_card.name if options[:name].blank? && credit_card
request = build_recurring_request(options[:profile_id] ? :modify : :add, money, options) do |xml|
add_credit_card(xml, credit_card, options) if credit_card
+ add_stored_credential(xml, options[:stored_credential])
end
commit(request, options.merge(request_type: :recurring))
end
def cancel_recurring(profile_id)
@@ -156,10 +157,11 @@
xml.tag! 'Tender' do
xml.tag! 'Card' do
xml.tag! 'ExtData', 'Name' => 'ORIGID', 'Value' => reference
end
end
+ add_stored_credential(xml, options[:stored_credential])
end
xml.tag! 'ExtData', 'Name' => 'BUTTONSOURCE', 'Value' => application_id unless application_id.blank?
end
xml.target!
end
@@ -188,19 +190,47 @@
add_address(xml, 'ShipTo', options[:shipping_address], options) if options[:shipping_address]
xml.tag! 'TotalAmt', amount(money), 'Currency' => options[:currency] || currency(money)
end
+ if %i(authorization purchase).include? action
+ add_mpi_3ds(xml, options[:three_d_secure]) if options[:three_d_secure]
+ end
+
xml.tag! 'Tender' do
add_credit_card(xml, credit_card, options)
end
+ add_stored_credential(xml, options[:stored_credential])
end
xml.tag! 'ExtData', 'Name' => 'BUTTONSOURCE', 'Value' => application_id unless application_id.blank?
end
add_level_two_three_fields(xml.target!, options)
end
+ def add_mpi_3ds(xml, three_d_secure_options)
+ # structure as per https://developer.paypal.com/api/nvp-soap/payflow/3d-secure-mpi/
+ authentication_id = three_d_secure_options[:authentication_id]
+ authentication_status = three_d_secure_options[:authentication_response_status]
+
+ eci = three_d_secure_options[:eci]
+ cavv = three_d_secure_options[:cavv]
+ xid = three_d_secure_options[:xid]
+ version = three_d_secure_options[:version]
+
+ # 3DS2 only
+ ds_transaction_id = three_d_secure_options[:ds_transaction_id] if version_2_or_newer?(three_d_secure_options)
+
+ xml.tag!('ExtData', 'Name' => 'AUTHENTICATION_ID', 'Value' => authentication_id) unless authentication_id.blank?
+ xml.tag!('ExtData', 'Name' => 'AUTHENTICATION_STATUS', 'Value' => authentication_status) unless authentication_status.blank?
+
+ xml.tag!('ExtData', 'Name' => 'CAVV', 'Value' => cavv) unless cavv.blank?
+ xml.tag!('ExtData', 'Name' => 'ECI', 'Value' => eci) unless eci.blank?
+ xml.tag!('ExtData', 'Name' => 'XID', 'Value' => xid) unless xid.blank?
+ xml.tag!('ExtData', 'Name' => 'THREEDSVERSION', 'Value' => version) unless version.blank?
+ xml.tag!('ExtData', 'Name' => 'DSTRANSACTIONID', 'Value' => ds_transaction_id) unless ds_transaction_id.blank?
+ end
+
def add_level_two_three_fields(xml_string, options)
if options[:level_two_fields] || options[:level_three_fields]
xml_doc = Nokogiri::XML.parse(xml_string)
%i[level_two_fields level_three_fields].each do |fields|
xml_string = add_fields(xml_doc, options[fields]) if options[fields]
@@ -256,10 +286,11 @@
xml.tag! 'AcctType', check.account_type == 'checking' ? 'C' : 'S'
xml.tag! 'AcctNum', check.account_number
xml.tag! 'ABA', check.routing_number
end
end
+ add_stored_credential(xml, options[:stored_credential])
end
xml.tag! 'ExtData', 'Name' => 'BUTTONSOURCE', 'Value' => application_id unless application_id.blank?
end
add_level_two_three_fields(xml.target!, options)
end
@@ -274,9 +305,40 @@
add_three_d_secure(options, xml)
xml.tag! 'ExtData', 'Name' => 'LASTNAME', 'Value' => credit_card.last_name
end
+ end
+
+ def add_stored_credential(xml, stored_credential)
+ return unless stored_credential
+
+ xml.tag! 'CardOnFile', add_card_on_file_type(stored_credential)
+ xml.tag! 'TxnId', stored_credential[:network_transaction_id] if stored_credential[:network_transaction_id]
+ end
+
+ def card_on_file_initiator(initator)
+ case initator
+ when 'merchant'
+ 'MIT'
+ when 'cardholder'
+ 'CIT'
+ end
+ end
+
+ def card_on_file_reason(stored_credential)
+ return 'I' if stored_credential[:initial_transaction] && stored_credential[:reason_type] == 'unscheduled'
+
+ case stored_credential[:reason_type]
+ when 'recurring', 'installment'
+ 'R'
+ when 'unscheduled'
+ 'U'
+ end
+ end
+
+ def add_card_on_file_type(stored_credential)
+ card_on_file_initiator(stored_credential[:initiator]).to_s + card_on_file_reason(stored_credential).to_s
end
def add_three_d_secure(options, xml)
if options[:three_d_secure]
three_d_secure = options[:three_d_secure]