activemerchant 1.133.0 → 1.137.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (183) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +240 -0
  3. data/lib/active_merchant/billing/check.rb +2 -2
  4. data/lib/active_merchant/billing/compatibility.rb +4 -4
  5. data/lib/active_merchant/billing/credit_card.rb +11 -8
  6. data/lib/active_merchant/billing/credit_card_formatting.rb +4 -0
  7. data/lib/active_merchant/billing/credit_card_methods.rb +59 -6
  8. data/lib/active_merchant/billing/gateway.rb +9 -0
  9. data/lib/active_merchant/billing/gateways/adyen.rb +162 -43
  10. data/lib/active_merchant/billing/gateways/airwallex.rb +26 -12
  11. data/lib/active_merchant/billing/gateways/alelo.rb +23 -5
  12. data/lib/active_merchant/billing/gateways/authorize_net.rb +43 -35
  13. data/lib/active_merchant/billing/gateways/authorize_net_arb.rb +10 -6
  14. data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +1 -3
  15. data/lib/active_merchant/billing/gateways/axcessms.rb +6 -2
  16. data/lib/active_merchant/billing/gateways/banwire.rb +4 -2
  17. data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +7 -3
  18. data/lib/active_merchant/billing/gateways/blue_pay.rb +13 -5
  19. data/lib/active_merchant/billing/gateways/blue_snap.rb +5 -5
  20. data/lib/active_merchant/billing/gateways/braintree/token_nonce.rb +65 -20
  21. data/lib/active_merchant/billing/gateways/braintree_blue.rb +226 -73
  22. data/lib/active_merchant/billing/gateways/braintree_orange.rb +1 -1
  23. data/lib/active_merchant/billing/gateways/card_connect.rb +5 -2
  24. data/lib/active_merchant/billing/gateways/card_stream.rb +4 -6
  25. data/lib/active_merchant/billing/gateways/cashnet.rb +1 -1
  26. data/lib/active_merchant/billing/gateways/cecabank/cecabank_common.rb +36 -0
  27. data/lib/active_merchant/billing/gateways/cecabank/cecabank_json.rb +316 -0
  28. data/lib/active_merchant/billing/gateways/cecabank/cecabank_xml.rb +220 -0
  29. data/lib/active_merchant/billing/gateways/cecabank.rb +7 -240
  30. data/lib/active_merchant/billing/gateways/checkout_v2.rb +238 -34
  31. data/lib/active_merchant/billing/gateways/commerce_hub.rb +63 -6
  32. data/lib/active_merchant/billing/gateways/credorax.rb +3 -5
  33. data/lib/active_merchant/billing/gateways/cyber_source.rb +185 -47
  34. data/lib/active_merchant/billing/gateways/cyber_source_rest.rb +102 -58
  35. data/lib/active_merchant/billing/gateways/d_local.rb +26 -15
  36. data/lib/active_merchant/billing/gateways/data_cash.rb +21 -17
  37. data/lib/active_merchant/billing/gateways/datatrans.rb +279 -0
  38. data/lib/active_merchant/billing/gateways/decidir.rb +53 -18
  39. data/lib/active_merchant/billing/gateways/decidir_plus.rb +4 -1
  40. data/lib/active_merchant/billing/gateways/deepstack.rb +382 -0
  41. data/lib/active_merchant/billing/gateways/ebanx.rb +40 -36
  42. data/lib/active_merchant/billing/gateways/efsnet.rb +6 -2
  43. data/lib/active_merchant/billing/gateways/elavon.rb +99 -33
  44. data/lib/active_merchant/billing/gateways/element.rb +36 -7
  45. data/lib/active_merchant/billing/gateways/epay.rb +6 -2
  46. data/lib/active_merchant/billing/gateways/evo_ca.rb +6 -2
  47. data/lib/active_merchant/billing/gateways/eway.rb +4 -2
  48. data/lib/active_merchant/billing/gateways/eway_managed.rb +6 -2
  49. data/lib/active_merchant/billing/gateways/exact.rb +6 -2
  50. data/lib/active_merchant/billing/gateways/fat_zebra.rb +31 -3
  51. data/lib/active_merchant/billing/gateways/federated_canada.rb +6 -2
  52. data/lib/active_merchant/billing/gateways/first_pay/first_pay_common.rb +15 -0
  53. data/lib/active_merchant/billing/gateways/first_pay/first_pay_json.rb +190 -0
  54. data/lib/active_merchant/billing/gateways/first_pay/first_pay_xml.rb +183 -0
  55. data/lib/active_merchant/billing/gateways/first_pay.rb +6 -172
  56. data/lib/active_merchant/billing/gateways/firstdata_e4.rb +6 -2
  57. data/lib/active_merchant/billing/gateways/firstdata_e4_v27.rb +7 -3
  58. data/lib/active_merchant/billing/gateways/flex_charge.rb +347 -0
  59. data/lib/active_merchant/billing/gateways/garanti.rb +4 -2
  60. data/lib/active_merchant/billing/gateways/global_collect.rb +45 -37
  61. data/lib/active_merchant/billing/gateways/hi_pay.rb +286 -0
  62. data/lib/active_merchant/billing/gateways/hps.rb +1 -1
  63. data/lib/active_merchant/billing/gateways/iats_payments.rb +7 -2
  64. data/lib/active_merchant/billing/gateways/inspire.rb +6 -4
  65. data/lib/active_merchant/billing/gateways/instapay.rb +7 -4
  66. data/lib/active_merchant/billing/gateways/ipg.rb +9 -5
  67. data/lib/active_merchant/billing/gateways/iridium.rb +15 -5
  68. data/lib/active_merchant/billing/gateways/itransact.rb +6 -2
  69. data/lib/active_merchant/billing/gateways/iveri.rb +3 -3
  70. data/lib/active_merchant/billing/gateways/ixopay.rb +2 -2
  71. data/lib/active_merchant/billing/gateways/jetpay.rb +4 -2
  72. data/lib/active_merchant/billing/gateways/jetpay_v2.rb +4 -2
  73. data/lib/active_merchant/billing/gateways/kushki.rb +72 -12
  74. data/lib/active_merchant/billing/gateways/linkpoint.rb +6 -2
  75. data/lib/active_merchant/billing/gateways/litle.rb +33 -50
  76. data/lib/active_merchant/billing/gateways/mastercard.rb +4 -4
  77. data/lib/active_merchant/billing/gateways/maxipago.rb +2 -2
  78. data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +8 -5
  79. data/lib/active_merchant/billing/gateways/merchant_ware.rb +11 -4
  80. data/lib/active_merchant/billing/gateways/merchant_ware_version_four.rb +11 -4
  81. data/lib/active_merchant/billing/gateways/merchant_warrior.rb +19 -3
  82. data/lib/active_merchant/billing/gateways/mercury.rb +6 -2
  83. data/lib/active_merchant/billing/gateways/metrics_global.rb +8 -6
  84. data/lib/active_merchant/billing/gateways/migs/migs_codes.rb +1 -0
  85. data/lib/active_merchant/billing/gateways/migs.rb +6 -2
  86. data/lib/active_merchant/billing/gateways/mit.rb +8 -3
  87. data/lib/active_merchant/billing/gateways/modern_payments_cim.rb +18 -10
  88. data/lib/active_merchant/billing/gateways/monei.rb +1 -1
  89. data/lib/active_merchant/billing/gateways/moneris.rb +9 -3
  90. data/lib/active_merchant/billing/gateways/money_movers.rb +6 -2
  91. data/lib/active_merchant/billing/gateways/nab_transact.rb +12 -4
  92. data/lib/active_merchant/billing/gateways/net_registry.rb +6 -2
  93. data/lib/active_merchant/billing/gateways/netbanx.rb +1 -3
  94. data/lib/active_merchant/billing/gateways/netbilling.rb +6 -2
  95. data/lib/active_merchant/billing/gateways/network_merchants.rb +6 -2
  96. data/lib/active_merchant/billing/gateways/nmi.rb +18 -6
  97. data/lib/active_merchant/billing/gateways/ogone.rb +6 -2
  98. data/lib/active_merchant/billing/gateways/openpay.rb +4 -2
  99. data/lib/active_merchant/billing/gateways/opp.rb +1 -2
  100. data/lib/active_merchant/billing/gateways/optimal_payment.rb +6 -2
  101. data/lib/active_merchant/billing/gateways/orbital/orbital_soft_descriptors.rb +1 -3
  102. data/lib/active_merchant/billing/gateways/orbital.rb +83 -24
  103. data/lib/active_merchant/billing/gateways/pac_net_raven.rb +7 -4
  104. data/lib/active_merchant/billing/gateways/pay_gate_xml.rb +6 -2
  105. data/lib/active_merchant/billing/gateways/pay_hub.rb +4 -2
  106. data/lib/active_merchant/billing/gateways/pay_junction.rb +6 -2
  107. data/lib/active_merchant/billing/gateways/pay_secure.rb +6 -2
  108. data/lib/active_merchant/billing/gateways/pay_trace.rb +31 -18
  109. data/lib/active_merchant/billing/gateways/payeezy.rb +19 -8
  110. data/lib/active_merchant/billing/gateways/payex.rb +4 -2
  111. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +1 -1
  112. data/lib/active_merchant/billing/gateways/payflow.rb +1 -3
  113. data/lib/active_merchant/billing/gateways/payment_express.rb +8 -4
  114. data/lib/active_merchant/billing/gateways/paymentez.rb +23 -11
  115. data/lib/active_merchant/billing/gateways/paysafe.rb +12 -11
  116. data/lib/active_merchant/billing/gateways/payscout.rb +7 -4
  117. data/lib/active_merchant/billing/gateways/paystation.rb +7 -3
  118. data/lib/active_merchant/billing/gateways/payway.rb +6 -2
  119. data/lib/active_merchant/billing/gateways/payway_dot_com.rb +2 -2
  120. data/lib/active_merchant/billing/gateways/pin.rb +22 -4
  121. data/lib/active_merchant/billing/gateways/plexo.rb +49 -10
  122. data/lib/active_merchant/billing/gateways/plugnpay.rb +6 -2
  123. data/lib/active_merchant/billing/gateways/priority.rb +6 -5
  124. data/lib/active_merchant/billing/gateways/psigate.rb +6 -2
  125. data/lib/active_merchant/billing/gateways/psl_card.rb +6 -2
  126. data/lib/active_merchant/billing/gateways/qbms.rb +6 -2
  127. data/lib/active_merchant/billing/gateways/quantum.rb +6 -2
  128. data/lib/active_merchant/billing/gateways/quickbooks.rb +6 -5
  129. data/lib/active_merchant/billing/gateways/quickpay/quickpay_v10.rb +7 -4
  130. data/lib/active_merchant/billing/gateways/quickpay/quickpay_v4to7.rb +6 -2
  131. data/lib/active_merchant/billing/gateways/rapyd.rb +148 -46
  132. data/lib/active_merchant/billing/gateways/reach.rb +11 -4
  133. data/lib/active_merchant/billing/gateways/redsys.rb +2 -10
  134. data/lib/active_merchant/billing/gateways/redsys_rest.rb +507 -0
  135. data/lib/active_merchant/billing/gateways/s5.rb +3 -3
  136. data/lib/active_merchant/billing/gateways/safe_charge.rb +36 -16
  137. data/lib/active_merchant/billing/gateways/sage.rb +12 -4
  138. data/lib/active_merchant/billing/gateways/sage_pay.rb +79 -5
  139. data/lib/active_merchant/billing/gateways/sallie_mae.rb +6 -2
  140. data/lib/active_merchant/billing/gateways/secure_net.rb +6 -2
  141. data/lib/active_merchant/billing/gateways/secure_pay.rb +8 -6
  142. data/lib/active_merchant/billing/gateways/secure_pay_au.rb +12 -4
  143. data/lib/active_merchant/billing/gateways/secure_pay_tech.rb +6 -2
  144. data/lib/active_merchant/billing/gateways/securion_pay.rb +24 -10
  145. data/lib/active_merchant/billing/gateways/shift4.rb +17 -20
  146. data/lib/active_merchant/billing/gateways/shift4_v2.rb +117 -0
  147. data/lib/active_merchant/billing/gateways/simetrik.rb +17 -11
  148. data/lib/active_merchant/billing/gateways/skip_jack.rb +6 -2
  149. data/lib/active_merchant/billing/gateways/smart_ps.rb +7 -4
  150. data/lib/active_merchant/billing/gateways/so_easy_pay.rb +4 -2
  151. data/lib/active_merchant/billing/gateways/spreedly_core.rb +2 -4
  152. data/lib/active_merchant/billing/gateways/stripe.rb +53 -21
  153. data/lib/active_merchant/billing/gateways/stripe_payment_intents.rb +199 -50
  154. data/lib/active_merchant/billing/gateways/sum_up.rb +223 -0
  155. data/lib/active_merchant/billing/gateways/swipe_checkout.rb +4 -2
  156. data/lib/active_merchant/billing/gateways/telr.rb +3 -4
  157. data/lib/active_merchant/billing/gateways/trans_first.rb +1 -2
  158. data/lib/active_merchant/billing/gateways/trans_first_transaction_express.rb +8 -16
  159. data/lib/active_merchant/billing/gateways/transact_pro.rb +1 -1
  160. data/lib/active_merchant/billing/gateways/trust_commerce.rb +6 -2
  161. data/lib/active_merchant/billing/gateways/usa_epay_advanced.rb +9 -8
  162. data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +6 -2
  163. data/lib/active_merchant/billing/gateways/vanco.rb +2 -4
  164. data/lib/active_merchant/billing/gateways/vantiv_express.rb +587 -0
  165. data/lib/active_merchant/billing/gateways/verifi.rb +6 -2
  166. data/lib/active_merchant/billing/gateways/viaklix.rb +6 -2
  167. data/lib/active_merchant/billing/gateways/visanet_peru.rb +2 -2
  168. data/lib/active_merchant/billing/gateways/vpos.rb +3 -3
  169. data/lib/active_merchant/billing/gateways/wirecard.rb +7 -3
  170. data/lib/active_merchant/billing/gateways/wompi.rb +5 -0
  171. data/lib/active_merchant/billing/gateways/worldpay.rb +140 -73
  172. data/lib/active_merchant/billing/gateways/worldpay_online_payments.rb +13 -10
  173. data/lib/active_merchant/billing/gateways/xpay.rb +242 -0
  174. data/lib/active_merchant/billing/network_tokenization_credit_card.rb +1 -1
  175. data/lib/active_merchant/billing/response.rb +2 -2
  176. data/lib/active_merchant/connection.rb +3 -17
  177. data/lib/active_merchant/country.rb +1 -0
  178. data/lib/active_merchant/errors.rb +10 -0
  179. data/lib/active_merchant/version.rb +1 -1
  180. data/lib/support/gateway_support.rb +2 -2
  181. data/lib/support/ssl_verify.rb +4 -4
  182. data/lib/support/ssl_version.rb +6 -6
  183. metadata +30 -9
@@ -55,6 +55,7 @@ module ActiveMerchant #:nodoc:
55
55
  add_invoice(post, money, options)
56
56
  add_transaction_details(post, options, 'capture')
57
57
  add_reference_transaction_details(post, authorization, options, :capture)
58
+ add_dynamic_descriptors(post, options)
58
59
 
59
60
  commit('sale', post, options)
60
61
  end
@@ -68,6 +69,15 @@ module ActiveMerchant #:nodoc:
68
69
  commit('refund', post, options)
69
70
  end
70
71
 
72
+ def credit(money, payment_method, options = {})
73
+ post = {}
74
+ add_invoice(post, money, options)
75
+ add_transaction_interaction(post, options)
76
+ add_payment(post, payment_method, options)
77
+
78
+ commit('refund', post, options)
79
+ end
80
+
71
81
  def void(authorization, options = {})
72
82
  post = {}
73
83
  add_transaction_details(post, options)
@@ -102,6 +112,7 @@ module ActiveMerchant #:nodoc:
102
112
  transcript.
103
113
  gsub(%r((Authorization: )[a-zA-Z0-9+./=]+), '\1[FILTERED]').
104
114
  gsub(%r((Api-Key: )\w+), '\1[FILTERED]').
115
+ gsub(%r(("apiKey\\?":\\?")\w+), '\1[FILTERED]').
105
116
  gsub(%r(("cardData\\?":\\?")\d+), '\1[FILTERED]').
106
117
  gsub(%r(("securityCode\\?":\\?")\d+), '\1[FILTERED]').
107
118
  gsub(%r(("cavv\\?":\\?")\w+), '\1[FILTERED]')
@@ -109,6 +120,23 @@ module ActiveMerchant #:nodoc:
109
120
 
110
121
  private
111
122
 
123
+ def add_three_d_secure(post, payment, options)
124
+ return unless three_d_secure = options[:three_d_secure]
125
+
126
+ post[:additionalData3DS] = {
127
+ dsTransactionId: three_d_secure[:ds_transaction_id],
128
+ authenticationStatus: three_d_secure[:authentication_response_status],
129
+ serviceProviderTransactionId: three_d_secure[:three_ds_server_trans_id],
130
+ acsTransactionId: three_d_secure[:acs_transaction_id],
131
+ mpiData: {
132
+ cavv: three_d_secure[:cavv],
133
+ eci: three_d_secure[:eci],
134
+ xid: three_d_secure[:xid]
135
+ }.compact,
136
+ versionData: { recommendedVersion: three_d_secure[:version] }
137
+ }.compact
138
+ end
139
+
112
140
  def add_transaction_interaction(post, options)
113
141
  post[:transactionInteraction] = {}
114
142
  post[:transactionInteraction][:origin] = options[:origin] || 'ECOM'
@@ -144,10 +172,7 @@ module ActiveMerchant #:nodoc:
144
172
  return unless billing = options[:billing_address]
145
173
 
146
174
  billing_address = {}
147
- if payment.is_a?(CreditCard)
148
- billing_address[:firstName] = payment.first_name if payment.first_name
149
- billing_address[:lastName] = payment.last_name if payment.last_name
150
- end
175
+ name_from_address(billing_address, billing) || name_from_payment(billing_address, payment)
151
176
  address = {}
152
177
  address[:street] = billing[:address1] if billing[:address1]
153
178
  address[:houseNumberOrName] = billing[:address2] if billing[:address2]
@@ -165,6 +190,22 @@ module ActiveMerchant #:nodoc:
165
190
  post[:billingAddress] = billing_address
166
191
  end
167
192
 
193
+ def name_from_payment(billing_address, payment)
194
+ return unless payment.respond_to?(:first_name) && payment.respond_to?(:last_name)
195
+
196
+ billing_address[:firstName] = payment.first_name if payment.first_name
197
+ billing_address[:lastName] = payment.last_name if payment.last_name
198
+ end
199
+
200
+ def name_from_address(billing_address, billing)
201
+ return unless address = billing
202
+
203
+ first_name, last_name = split_names(address[:name]) if address[:name]
204
+
205
+ billing_address[:firstName] = first_name if first_name
206
+ billing_address[:lastName] = last_name if last_name
207
+ end
208
+
168
209
  def add_shipping_address(post, options)
169
210
  return unless shipping = options[:shipping_address]
170
211
 
@@ -187,12 +228,28 @@ module ActiveMerchant #:nodoc:
187
228
  end
188
229
 
189
230
  def build_purchase_and_auth_request(post, money, payment, options)
231
+ add_three_d_secure(post, payment, options)
190
232
  add_invoice(post, money, options)
191
233
  add_payment(post, payment, options)
192
234
  add_stored_credentials(post, options)
193
235
  add_transaction_interaction(post, options)
194
236
  add_billing_address(post, payment, options)
195
237
  add_shipping_address(post, options)
238
+ add_dynamic_descriptors(post, options)
239
+ end
240
+
241
+ def add_dynamic_descriptors(post, options)
242
+ dynamic_descriptors_fields = %i[mcc merchant_name customer_service_number service_entitlement dynamic_descriptors_address]
243
+ return unless dynamic_descriptors_fields.any? { |key| options.include?(key) }
244
+
245
+ dynamic_descriptors = {}
246
+ dynamic_descriptors[:mcc] = options[:mcc] if options[:mcc]
247
+ dynamic_descriptors[:merchantName] = options[:merchant_name] if options[:merchant_name]
248
+ dynamic_descriptors[:customerServiceNumber] = options[:customer_service_number] if options[:customer_service_number]
249
+ dynamic_descriptors[:serviceEntitlement] = options[:service_entitlement] if options[:service_entitlement]
250
+ dynamic_descriptors[:address] = options[:dynamic_descriptors_address] if options[:dynamic_descriptors_address]
251
+
252
+ post[:dynamicDescriptors] = dynamic_descriptors
196
253
  end
197
254
 
198
255
  def add_reference_transaction_details(post, authorization, options, action = nil)
@@ -282,7 +339,7 @@ module ActiveMerchant #:nodoc:
282
339
  raw_signature = @options[:api_key] + client_request_id.to_s + time + request
283
340
  hmac = OpenSSL::HMAC.digest('sha256', @options[:api_secret], raw_signature)
284
341
  signature = Base64.strict_encode64(hmac.to_s).to_s
285
-
342
+ custom_headers = options.fetch(:headers_identifiers, {})
286
343
  {
287
344
  'Client-Request-Id' => client_request_id,
288
345
  'Api-Key' => @options[:api_key],
@@ -292,7 +349,7 @@ module ActiveMerchant #:nodoc:
292
349
  'Content-Type' => 'application/json',
293
350
  'Accept' => 'application/json',
294
351
  'Authorization' => signature
295
- }
352
+ }.merge!(custom_headers)
296
353
  end
297
354
 
298
355
  def add_merchant_details(post)
@@ -254,9 +254,7 @@ module ActiveMerchant #:nodoc:
254
254
  normalized_value = normalize(value)
255
255
  next if normalized_value.nil?
256
256
 
257
- if key == :'3ds_homephonecountry'
258
- next unless options[:billing_address] && options[:billing_address][:phone]
259
- end
257
+ next if key == :'3ds_homephonecountry' && !(options[:billing_address] && options[:billing_address][:phone])
260
258
 
261
259
  post[key] = normalized_value unless post[key]
262
260
  end
@@ -417,7 +415,7 @@ module ActiveMerchant #:nodoc:
417
415
  three_d_secure_options[:eci],
418
416
  three_d_secure_options[:cavv]
419
417
  )
420
- post[:'3ds_version'] = three_d_secure_options[:version]&.start_with?('2') ? '2.0' : three_d_secure_options[:version]
418
+ post[:'3ds_version'] = three_d_secure_options[:version] == '2' ? '2.0' : three_d_secure_options[:version]
421
419
  post[:'3ds_dstrxid'] = three_d_secure_options[:ds_transaction_id]
422
420
  end
423
421
 
@@ -507,7 +505,7 @@ module ActiveMerchant #:nodoc:
507
505
  end
508
506
 
509
507
  def parse(body)
510
- Hash[CGI::parse(body).map { |k, v| [k.upcase, v.first] }]
508
+ CGI::parse(body).map { |k, v| [k.upcase, v.first] }.to_h
511
509
  end
512
510
 
513
511
  def success_from(response)
@@ -33,6 +33,15 @@ module ActiveMerchant #:nodoc:
33
33
  discover: 'pb',
34
34
  diners_club: 'pb'
35
35
  }.freeze
36
+ THREEDS_EXEMPTIONS = {
37
+ authentication_outage: 'authenticationOutageExemptionIndicator',
38
+ corporate_card: 'secureCorporatePaymentIndicator',
39
+ delegated_authentication: 'delegatedAuthenticationExemptionIndicator',
40
+ low_risk: 'riskAnalysisExemptionIndicator',
41
+ low_value: 'lowValueExemptionIndicator',
42
+ stored_credential: 'stored_credential',
43
+ trusted_merchant: 'trustedMerchantExemptionIndicator'
44
+ }
36
45
  DEFAULT_COLLECTION_INDICATOR = 2
37
46
 
38
47
  self.supported_cardtypes = %i[visa master american_express discover diners_club jcb dankort maestro elo]
@@ -53,7 +62,8 @@ module ActiveMerchant #:nodoc:
53
62
  jcb: '007',
54
63
  dankort: '034',
55
64
  maestro: '042',
56
- elo: '054'
65
+ elo: '054',
66
+ carnet: '058'
57
67
  }
58
68
 
59
69
  @@decision_codes = {
@@ -132,11 +142,16 @@ module ActiveMerchant #:nodoc:
132
142
  r703: 'Export hostname_country/ip_country match'
133
143
  }
134
144
 
135
- @@payment_solution = {
145
+ @@wallet_payment_solution = {
136
146
  apple_pay: '001',
137
147
  google_pay: '012'
138
148
  }
139
149
 
150
+ NT_PAYMENT_SOLUTION = {
151
+ 'master' => '014',
152
+ 'visa' => '015'
153
+ }
154
+
140
155
  # These are the options that can be used when creating a new CyberSource
141
156
  # Gateway object.
142
157
  #
@@ -161,9 +176,15 @@ module ActiveMerchant #:nodoc:
161
176
  super
162
177
  end
163
178
 
164
- def authorize(money, creditcard_or_reference, options = {})
165
- setup_address_hash(options)
166
- commit(build_auth_request(money, creditcard_or_reference, options), :authorize, money, options)
179
+ def authorize(money, payment_method, options = {})
180
+ if valid_payment_method?(payment_method)
181
+ setup_address_hash(options)
182
+ commit(build_auth_request(money, payment_method, options), :authorize, money, options)
183
+ else
184
+ # this is for NetworkToken, ApplePay or GooglePay brands that aren't supported at CyberSource
185
+ payment_type = payment_method.source.to_s.gsub('_', ' ').titleize.gsub(' ', '')
186
+ Response.new(false, "#{card_brand(payment_method).capitalize} is not supported by #{payment_type} at CyberSource, check https://developer.cybersource.com/docs/cybs/en-us/payments/developer/all/rest/payments/CreatingOnlineAuth/CreatingAuthReqPNT.html")
187
+ end
167
188
  end
168
189
 
169
190
  def capture(money, authorization, options = {})
@@ -171,9 +192,15 @@ module ActiveMerchant #:nodoc:
171
192
  commit(build_capture_request(money, authorization, options), :capture, money, options)
172
193
  end
173
194
 
174
- def purchase(money, payment_method_or_reference, options = {})
175
- setup_address_hash(options)
176
- commit(build_purchase_request(money, payment_method_or_reference, options), :purchase, money, options)
195
+ def purchase(money, payment_method, options = {})
196
+ if valid_payment_method?(payment_method)
197
+ setup_address_hash(options)
198
+ commit(build_purchase_request(money, payment_method, options), :purchase, money, options)
199
+ else
200
+ # this is for NetworkToken, ApplePay or GooglePay brands that aren't supported at CyberSource
201
+ payment_type = payment_method.source.to_s.gsub('_', ' ').titleize.gsub(' ', '')
202
+ Response.new(false, "#{card_brand(payment_method).capitalize} is not supported by #{payment_type} at CyberSource, check https://developer.cybersource.com/docs/cybs/en-us/payments/developer/all/rest/payments/CreatingOnlineAuth/CreatingAuthReqPNT.html")
203
+ end
177
204
  end
178
205
 
179
206
  def void(identification, options = {})
@@ -206,8 +233,14 @@ module ActiveMerchant #:nodoc:
206
233
  # To charge the card while creating a profile, pass
207
234
  # options[:setup_fee] => money
208
235
  def store(payment_method, options = {})
209
- setup_address_hash(options)
210
- commit(build_create_subscription_request(payment_method, options), :store, nil, options)
236
+ if valid_payment_method?(payment_method)
237
+ setup_address_hash(options)
238
+ commit(build_create_subscription_request(payment_method, options), :store, nil, options)
239
+ else
240
+ # this is for NetworkToken, ApplePay or GooglePay brands that aren't supported at CyberSource
241
+ payment_type = payment_method.source.to_s.gsub('_', ' ').titleize.gsub(' ', '')
242
+ Response.new(false, "#{card_brand(payment_method).capitalize} is not supported by #{payment_type} at CyberSource, check https://developer.cybersource.com/docs/cybs/en-us/payments/developer/all/rest/payments/CreatingOnlineAuth/CreatingAuthReqPNT.html")
243
+ end
211
244
  end
212
245
 
213
246
  # Updates a customer subscription/profile
@@ -272,6 +305,8 @@ module ActiveMerchant #:nodoc:
272
305
  gsub(%r((<cvNumber>)[^<]*(</cvNumber>))i, '\1[FILTERED]\2').
273
306
  gsub(%r((<cavv>)[^<]*(</cavv>))i, '\1[FILTERED]\2').
274
307
  gsub(%r((<xid>)[^<]*(</xid>))i, '\1[FILTERED]\2').
308
+ gsub(%r((<networkTokenCryptogram>)[^<]*(</networkTokenCryptogram>))i, '\1[FILTERED]\2').
309
+ gsub(%r((<requestorID>)[^<]*(</requestorID>))i, '\1[FILTERED]\2').
275
310
  gsub(%r((<authenticationData>)[^<]*(</authenticationData>))i, '\1[FILTERED]\2')
276
311
  end
277
312
 
@@ -286,6 +321,12 @@ module ActiveMerchant #:nodoc:
286
321
 
287
322
  private
288
323
 
324
+ def valid_payment_method?(payment_method)
325
+ return true unless payment_method.is_a?(NetworkTokenizationCreditCard)
326
+
327
+ %w(visa master american_express).include?(card_brand(payment_method))
328
+ end
329
+
289
330
  # Create all required address hash key value pairs
290
331
  # If a value of nil is received, that value will be passed on to the gateway and will not be replaced with a default value
291
332
  # Billing address fields received without an override value or with an empty string value will be replaced with the default_address values
@@ -317,17 +358,19 @@ module ActiveMerchant #:nodoc:
317
358
  xml = Builder::XmlMarkup.new indent: 2
318
359
  add_customer_id(xml, options)
319
360
  add_payment_method_or_subscription(xml, money, creditcard_or_reference, options)
320
- add_other_tax(xml, options)
321
361
  add_threeds_2_ucaf_data(xml, creditcard_or_reference, options)
362
+ add_mastercard_network_tokenization_ucaf_data(xml, creditcard_or_reference, options)
322
363
  add_decision_manager_fields(xml, options)
364
+ add_other_tax(xml, options)
323
365
  add_mdd_fields(xml, options)
324
366
  add_auth_service(xml, creditcard_or_reference, options)
367
+ add_capture_service_fields_with_run_false(xml, options)
325
368
  add_threeds_services(xml, options)
326
369
  add_business_rules_data(xml, creditcard_or_reference, options)
327
370
  add_airline_data(xml, options)
328
371
  add_sales_slip_number(xml, options)
329
- add_payment_network_token(xml) if network_tokenization?(creditcard_or_reference)
330
- add_payment_solution(xml, creditcard_or_reference.source) if network_tokenization?(creditcard_or_reference)
372
+ add_payment_network_token(xml, creditcard_or_reference, options)
373
+ add_payment_solution(xml, creditcard_or_reference)
331
374
  add_tax_management_indicator(xml, options)
332
375
  add_stored_credential_subsequent_auth(xml, options)
333
376
  add_issuer_additional_data(xml, options)
@@ -380,9 +423,10 @@ module ActiveMerchant #:nodoc:
380
423
  xml = Builder::XmlMarkup.new indent: 2
381
424
  add_customer_id(xml, options)
382
425
  add_payment_method_or_subscription(xml, money, payment_method_or_reference, options)
383
- add_other_tax(xml, options)
384
426
  add_threeds_2_ucaf_data(xml, payment_method_or_reference, options)
427
+ add_mastercard_network_tokenization_ucaf_data(xml, payment_method_or_reference, options)
385
428
  add_decision_manager_fields(xml, options)
429
+ add_other_tax(xml, options)
386
430
  add_mdd_fields(xml, options)
387
431
  if (!payment_method_or_reference.is_a?(String) && card_brand(payment_method_or_reference) == 'check') || reference_is_a_check?(payment_method_or_reference)
388
432
  add_check_service(xml)
@@ -398,8 +442,8 @@ module ActiveMerchant #:nodoc:
398
442
  add_business_rules_data(xml, payment_method_or_reference, options)
399
443
  add_airline_data(xml, options)
400
444
  add_sales_slip_number(xml, options)
401
- add_payment_network_token(xml) if network_tokenization?(payment_method_or_reference)
402
- add_payment_solution(xml, payment_method_or_reference.source) if network_tokenization?(payment_method_or_reference)
445
+ add_payment_network_token(xml, payment_method_or_reference, options)
446
+ add_payment_solution(xml, payment_method_or_reference)
403
447
  add_tax_management_indicator(xml, options)
404
448
  add_stored_credential_subsequent_auth(xml, options)
405
449
  add_issuer_additional_data(xml, options)
@@ -487,7 +531,7 @@ module ActiveMerchant #:nodoc:
487
531
  add_check_service(xml)
488
532
  else
489
533
  add_purchase_service(xml, payment_method, options)
490
- add_payment_network_token(xml) if network_tokenization?(payment_method)
534
+ add_payment_network_token(xml, payment_method, options)
491
535
  end
492
536
  end
493
537
  add_subscription_create_service(xml, options)
@@ -556,7 +600,7 @@ module ActiveMerchant #:nodoc:
556
600
  end
557
601
 
558
602
  def add_merchant_data(xml, options)
559
- xml.tag! 'merchantID', @options[:login]
603
+ xml.tag! 'merchantID', options[:merchant_id] || @options[:login]
560
604
  xml.tag! 'merchantReferenceCode', options[:order_id] || generate_unique_id
561
605
  xml.tag! 'clientLibrary', 'Ruby Active Merchant'
562
606
  xml.tag! 'clientLibraryVersion', VERSION
@@ -566,12 +610,24 @@ module ActiveMerchant #:nodoc:
566
610
  end
567
611
 
568
612
  def add_merchant_descriptor(xml, options)
569
- return unless options[:merchant_descriptor] || options[:user_po] || options[:taxable] || options[:reference_data_code] || options[:invoice_number]
613
+ return unless options[:merchant_descriptor] ||
614
+ options[:user_po] ||
615
+ options[:taxable] ||
616
+ options[:reference_data_code] ||
617
+ options[:invoice_number] ||
618
+ options[:merchant_descriptor_city] ||
619
+ options[:submerchant_id] ||
620
+ options[:merchant_descriptor_state] ||
621
+ options[:merchant_descriptor_country]
570
622
 
571
623
  xml.tag! 'invoiceHeader' do
572
624
  xml.tag! 'merchantDescriptor', options[:merchant_descriptor] if options[:merchant_descriptor]
625
+ xml.tag! 'merchantDescriptorCity', options[:merchant_descriptor_city] if options[:merchant_descriptor_city]
626
+ xml.tag! 'merchantDescriptorState', options[:merchant_descriptor_state] if options[:merchant_descriptor_state]
627
+ xml.tag! 'merchantDescriptorCountry', options[:merchant_descriptor_country] if options[:merchant_descriptor_country]
573
628
  xml.tag! 'userPO', options[:user_po] if options[:user_po]
574
629
  xml.tag! 'taxable', options[:taxable] if options[:taxable]
630
+ xml.tag! 'submerchantID', options[:submerchant_id] if options[:submerchant_id]
575
631
  xml.tag! 'referenceDataCode', options[:reference_data_code] if options[:reference_data_code]
576
632
  xml.tag! 'invoiceNumber', options[:invoice_number] if options[:invoice_number]
577
633
  end
@@ -677,10 +733,16 @@ module ActiveMerchant #:nodoc:
677
733
  end
678
734
  end
679
735
 
680
- def add_payment_solution(xml, source)
681
- return unless (payment_solution = @@payment_solution[source])
736
+ def add_payment_solution(xml, payment_method)
737
+ return unless network_tokenization?(payment_method)
682
738
 
683
- xml.tag! 'paymentSolution', payment_solution
739
+ case payment_method.source
740
+ when :network_token
741
+ payment_solution = NT_PAYMENT_SOLUTION[payment_method.brand]
742
+ xml.tag! 'paymentSolution', payment_solution if payment_solution
743
+ when :apple_pay, :google_pay
744
+ xml.tag! 'paymentSolution', @@wallet_payment_solution[payment_method.source]
745
+ end
684
746
  end
685
747
 
686
748
  def add_issuer_additional_data(xml, options)
@@ -692,7 +754,7 @@ module ActiveMerchant #:nodoc:
692
754
  end
693
755
 
694
756
  def add_other_tax(xml, options)
695
- return unless options[:local_tax_amount] || options[:national_tax_amount] || options[:national_tax_indicator]
757
+ return unless %i[vat_tax_rate local_tax_amount national_tax_amount national_tax_indicator].any? { |gsf| options.include?(gsf) }
696
758
 
697
759
  xml.tag! 'otherTax' do
698
760
  xml.tag! 'vatTaxRate', options[:vat_tax_rate] if options[:vat_tax_rate]
@@ -731,21 +793,39 @@ module ActiveMerchant #:nodoc:
731
793
 
732
794
  def add_auth_service(xml, payment_method, options)
733
795
  if network_tokenization?(payment_method)
734
- add_auth_network_tokenization(xml, payment_method, options)
796
+ if payment_method.source == :network_token
797
+ add_auth_network_tokenization(xml, payment_method, options)
798
+ else
799
+ add_auth_wallet(xml, payment_method, options)
800
+ end
735
801
  else
736
802
  xml.tag! 'ccAuthService', { 'run' => 'true' } do
737
803
  if options[:three_d_secure]
738
804
  add_normalized_threeds_2_data(xml, payment_method, options)
805
+ add_threeds_exemption_data(xml, options) if options[:three_ds_exemption_type]
739
806
  else
740
807
  indicator = options[:commerce_indicator] || stored_credential_commerce_indicator(options)
741
808
  xml.tag!('commerceIndicator', indicator) if indicator
742
809
  end
810
+ xml.tag!('aggregatorID', options[:aggregator_id]) if options[:aggregator_id]
743
811
  xml.tag!('reconciliationID', options[:reconciliation_id]) if options[:reconciliation_id]
812
+ xml.tag!('firstRecurringPayment', options[:first_recurring_payment]) if options[:first_recurring_payment]
744
813
  xml.tag!('mobileRemotePaymentType', options[:mobile_remote_payment_type]) if options[:mobile_remote_payment_type]
745
814
  end
746
815
  end
747
816
  end
748
817
 
818
+ def add_threeds_exemption_data(xml, options)
819
+ return unless options[:three_ds_exemption_type]
820
+
821
+ exemption = options[:three_ds_exemption_type].to_sym
822
+
823
+ case exemption
824
+ when :authentication_outage, :corporate_card, :delegated_authentication, :low_risk, :low_value, :trusted_merchant
825
+ xml.tag!(THREEDS_EXEMPTIONS[exemption], '1')
826
+ end
827
+ end
828
+
749
829
  def add_incremental_auth_service(xml, authorization, options)
750
830
  xml.tag! 'ccIncrementalAuthService', { 'run' => 'true' } do
751
831
  xml.tag! 'authRequestID', authorization
@@ -793,13 +873,15 @@ module ActiveMerchant #:nodoc:
793
873
  end
794
874
 
795
875
  def stored_credential_commerce_indicator(options)
796
- return unless options[:stored_credential]
876
+ return unless (reason_type = options.dig(:stored_credential, :reason_type))
797
877
 
798
- return if options[:stored_credential][:initial_transaction]
799
-
800
- case options[:stored_credential][:reason_type]
801
- when 'installment' then 'install'
802
- when 'recurring' then 'recurring'
878
+ case reason_type
879
+ when 'installment'
880
+ 'install'
881
+ when 'recurring'
882
+ 'recurring'
883
+ else
884
+ 'internet'
803
885
  end
804
886
  end
805
887
 
@@ -807,26 +889,38 @@ module ActiveMerchant #:nodoc:
807
889
  payment_method.is_a?(NetworkTokenizationCreditCard)
808
890
  end
809
891
 
892
+ def subsequent_nt_apple_pay_auth(source, options)
893
+ return unless options[:stored_credential] || options[:stored_credential_overrides]
894
+ return unless @@wallet_payment_solution[source]
895
+
896
+ options.dig(:stored_credential_overrides, :subsequent_auth) || options.dig(:stored_credential, :initiator) == 'merchant'
897
+ end
898
+
810
899
  def add_auth_network_tokenization(xml, payment_method, options)
811
- return unless network_tokenization?(payment_method)
900
+ commerce_indicator = stored_credential_commerce_indicator(options) || 'internet'
901
+ xml.tag! 'ccAuthService', { 'run' => 'true' } do
902
+ xml.tag!('networkTokenCryptogram', payment_method.payment_cryptogram)
903
+ xml.tag!('commerceIndicator', commerce_indicator)
904
+ xml.tag!('reconciliationID', options[:reconciliation_id]) if options[:reconciliation_id]
905
+ end
906
+ end
907
+
908
+ def add_auth_wallet(xml, payment_method, options)
909
+ commerce_indicator = 'internet' if subsequent_nt_apple_pay_auth(payment_method.source, options)
812
910
 
813
911
  brand = card_brand(payment_method).to_sym
814
912
 
815
913
  case brand
816
914
  when :visa
817
915
  xml.tag! 'ccAuthService', { 'run' => 'true' } do
818
- xml.tag!('cavv', payment_method.payment_cryptogram)
819
- xml.tag!('commerceIndicator', ECI_BRAND_MAPPING[brand])
820
- xml.tag!('xid', payment_method.payment_cryptogram)
916
+ xml.tag!('cavv', payment_method.payment_cryptogram) unless commerce_indicator
917
+ xml.commerceIndicator commerce_indicator.nil? ? ECI_BRAND_MAPPING[brand] : commerce_indicator
918
+ xml.tag!('xid', payment_method.payment_cryptogram) unless commerce_indicator
821
919
  xml.tag!('reconciliationID', options[:reconciliation_id]) if options[:reconciliation_id]
822
920
  end
823
921
  when :master
824
- xml.tag! 'ucaf' do
825
- xml.tag!('authenticationData', payment_method.payment_cryptogram)
826
- xml.tag!('collectionIndicator', DEFAULT_COLLECTION_INDICATOR)
827
- end
828
922
  xml.tag! 'ccAuthService', { 'run' => 'true' } do
829
- xml.tag!('commerceIndicator', ECI_BRAND_MAPPING[brand])
923
+ xml.commerceIndicator commerce_indicator.nil? ? ECI_BRAND_MAPPING[brand] : commerce_indicator
830
924
  xml.tag!('reconciliationID', options[:reconciliation_id]) if options[:reconciliation_id]
831
925
  end
832
926
  when :american_express
@@ -837,14 +931,28 @@ module ActiveMerchant #:nodoc:
837
931
  xml.tag!('xid', Base64.encode64(cryptogram[20...40])) if cryptogram.bytes.count > 20
838
932
  xml.tag!('reconciliationID', options[:reconciliation_id]) if options[:reconciliation_id]
839
933
  end
840
- else
841
- raise ArgumentError.new("Payment method #{brand} is not supported, check https://developer.cybersource.com/docs/cybs/en-us/payments/developer/all/rest/payments/CreatingOnlineAuth/CreatingAuthReqPNT.html")
842
934
  end
843
935
  end
844
936
 
845
- def add_payment_network_token(xml)
937
+ def add_mastercard_network_tokenization_ucaf_data(xml, payment_method, options)
938
+ return unless network_tokenization?(payment_method) && card_brand(payment_method).to_sym == :master
939
+ return if payment_method.source == :network_token
940
+
941
+ commerce_indicator = 'internet' if subsequent_nt_apple_pay_auth(payment_method.source, options)
942
+
943
+ xml.tag! 'ucaf' do
944
+ xml.tag!('authenticationData', payment_method.payment_cryptogram) unless commerce_indicator
945
+ xml.tag!('collectionIndicator', DEFAULT_COLLECTION_INDICATOR)
946
+ end
947
+ end
948
+
949
+ def add_payment_network_token(xml, payment_method, options)
950
+ return unless network_tokenization?(payment_method)
951
+
952
+ transaction_type = payment_method.source == :network_token ? '3' : '1'
846
953
  xml.tag! 'paymentNetworkToken' do
847
- xml.tag!('transactionType', '1')
954
+ xml.tag!('requestorID', options[:trid]) if transaction_type == '3' && options[:trid]
955
+ xml.tag!('transactionType', transaction_type)
848
956
  end
849
957
  end
850
958
 
@@ -857,10 +965,19 @@ module ActiveMerchant #:nodoc:
857
965
  end
858
966
  end
859
967
 
968
+ def add_capture_service_fields_with_run_false(xml, options)
969
+ return unless options[:gratuity_amount]
970
+
971
+ xml.tag! 'ccCaptureService', { 'run' => 'false' } do
972
+ xml.tag! 'gratuityAmount', options[:gratuity_amount]
973
+ end
974
+ end
975
+
860
976
  def add_purchase_service(xml, payment_method, options)
861
977
  add_auth_service(xml, payment_method, options)
862
978
  xml.tag! 'ccCaptureService', { 'run' => 'true' } do
863
979
  xml.tag!('reconciliationID', options[:reconciliation_id]) if options[:reconciliation_id]
980
+ xml.tag!('gratuityAmount', options[:gratuity_amount]) if options[:gratuity_amount]
864
981
  end
865
982
  end
866
983
 
@@ -1003,9 +1120,9 @@ module ActiveMerchant #:nodoc:
1003
1120
  def add_stored_credential_options(xml, options = {})
1004
1121
  return unless options[:stored_credential] || options[:stored_credential_overrides]
1005
1122
 
1006
- stored_credential_subsequent_auth_first = 'true' if options.dig(:stored_credential, :initial_transaction)
1123
+ stored_credential_subsequent_auth_first = 'true' if cardholder_or_initiated_transaction?(options)
1007
1124
  stored_credential_transaction_id = options.dig(:stored_credential, :network_transaction_id) if options.dig(:stored_credential, :initiator) == 'merchant'
1008
- stored_credential_subsequent_auth_stored_cred = 'true' if options.dig(:stored_credential, :initiator) == 'cardholder' && !options.dig(:stored_credential, :initial_transaction) || options.dig(:stored_credential, :initiator) == 'merchant' && options.dig(:stored_credential, :reason_type) == 'unscheduled'
1125
+ stored_credential_subsequent_auth_stored_cred = 'true' if subsequent_cardholder_initiated_transaction?(options) || unscheduled_merchant_initiated_transaction?(options) || threeds_stored_credential_exemption?(options)
1009
1126
 
1010
1127
  override_subsequent_auth_first = options.dig(:stored_credential_overrides, :subsequent_auth_first)
1011
1128
  override_subsequent_auth_transaction_id = options.dig(:stored_credential_overrides, :subsequent_auth_transaction_id)
@@ -1016,6 +1133,22 @@ module ActiveMerchant #:nodoc:
1016
1133
  xml.subsequentAuthStoredCredential override_subsequent_auth_stored_cred.nil? ? stored_credential_subsequent_auth_stored_cred : override_subsequent_auth_stored_cred
1017
1134
  end
1018
1135
 
1136
+ def cardholder_or_initiated_transaction?(options)
1137
+ options.dig(:stored_credential, :initiator) == 'cardholder' || options.dig(:stored_credential, :initial_transaction)
1138
+ end
1139
+
1140
+ def subsequent_cardholder_initiated_transaction?(options)
1141
+ options.dig(:stored_credential, :initiator) == 'cardholder' && !options.dig(:stored_credential, :initial_transaction)
1142
+ end
1143
+
1144
+ def unscheduled_merchant_initiated_transaction?(options)
1145
+ options.dig(:stored_credential, :initiator) == 'merchant' && options.dig(:stored_credential, :reason_type) == 'unscheduled'
1146
+ end
1147
+
1148
+ def threeds_stored_credential_exemption?(options)
1149
+ options[:three_ds_exemption_type] == THREEDS_EXEMPTIONS[:stored_credential]
1150
+ end
1151
+
1019
1152
  def add_partner_solution_id(xml)
1020
1153
  return unless application_id
1021
1154
 
@@ -1068,12 +1201,16 @@ module ActiveMerchant #:nodoc:
1068
1201
 
1069
1202
  message = auto_void?(authorization_from(response, action, amount, options), response, message, options)
1070
1203
 
1071
- Response.new(success, message, response,
1204
+ Response.new(
1205
+ success,
1206
+ message,
1207
+ response,
1072
1208
  test: test?,
1073
1209
  authorization: authorization,
1074
1210
  fraud_review: in_fraud_review?(response),
1075
1211
  avs_result: { code: response[:avsCode] },
1076
- cvv_result: response[:cvCode])
1212
+ cvv_result: response[:cvCode]
1213
+ )
1077
1214
  end
1078
1215
 
1079
1216
  def auto_void?(authorization, response, message, options = {})
@@ -1115,6 +1252,7 @@ module ActiveMerchant #:nodoc:
1115
1252
  parent += '_' + node.parent.attributes['id'] if node.parent.attributes['id']
1116
1253
  parent += '_'
1117
1254
  end
1255
+ reply[:reconciliationID2] = node.text if node.name == 'reconciliationID' && reply[:reconciliationID]
1118
1256
  reply["#{parent}#{node.name}".to_sym] ||= node.text
1119
1257
  end
1120
1258
  return reply