activemerchant 1.119.0 → 1.120.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +75 -1
  3. data/README.md +3 -1
  4. data/lib/active_merchant/billing/check.rb +10 -0
  5. data/lib/active_merchant/billing/credit_card_methods.rb +9 -3
  6. data/lib/active_merchant/billing/gateways/adyen.rb +20 -6
  7. data/lib/active_merchant/billing/gateways/authorize_net.rb +9 -3
  8. data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +3 -0
  9. data/lib/active_merchant/billing/gateways/braintree_blue.rb +47 -7
  10. data/lib/active_merchant/billing/gateways/cashnet.rb +7 -2
  11. data/lib/active_merchant/billing/gateways/checkout_v2.rb +21 -0
  12. data/lib/active_merchant/billing/gateways/credorax.rb +13 -8
  13. data/lib/active_merchant/billing/gateways/cyber_source.rb +23 -3
  14. data/lib/active_merchant/billing/gateways/d_local.rb +1 -1
  15. data/lib/active_merchant/billing/gateways/elavon.rb +11 -1
  16. data/lib/active_merchant/billing/gateways/forte.rb +12 -0
  17. data/lib/active_merchant/billing/gateways/hps.rb +55 -1
  18. data/lib/active_merchant/billing/gateways/litle.rb +1 -1
  19. data/lib/active_merchant/billing/gateways/mercado_pago.rb +2 -2
  20. data/lib/active_merchant/billing/gateways/netbanx.rb +26 -2
  21. data/lib/active_merchant/billing/gateways/orbital.rb +62 -53
  22. data/lib/active_merchant/billing/gateways/payeezy.rb +30 -6
  23. data/lib/active_merchant/billing/gateways/payment_express.rb +5 -5
  24. data/lib/active_merchant/billing/gateways/payway_dot_com.rb +253 -0
  25. data/lib/active_merchant/billing/gateways/qvalent.rb +23 -9
  26. data/lib/active_merchant/billing/gateways/redsys.rb +19 -4
  27. data/lib/active_merchant/billing/gateways/safe_charge.rb +18 -11
  28. data/lib/active_merchant/billing/gateways/stripe.rb +8 -8
  29. data/lib/active_merchant/billing/gateways/stripe_payment_intents.rb +61 -25
  30. data/lib/active_merchant/billing/gateways/vpos.rb +172 -0
  31. data/lib/active_merchant/billing/gateways/worldpay.rb +24 -11
  32. data/lib/active_merchant/version.rb +1 -1
  33. data/lib/certs/cacert.pem +1582 -2431
  34. metadata +5 -3
@@ -334,6 +334,7 @@ module ActiveMerchant #:nodoc:
334
334
  post[:f23] = options[:f23] if options[:f23]
335
335
  post[:'3ds_purchasedate'] = Time.now.utc.strftime('%Y%m%d%I%M%S')
336
336
  options.dig(:stored_credential, :initiator) == 'merchant' ? post[:'3ds_channel'] = '03' : post[:'3ds_channel'] = '02'
337
+ post[:'3ds_reqchallengeind'] = options[:three_ds_reqchallengeind] if options[:three_ds_reqchallengeind]
337
338
  post[:'3ds_redirect_url'] = three_ds_2_options[:notification_url]
338
339
  post[:'3ds_challengewindowsize'] = options[:three_ds_challenge_window_size] || '03'
339
340
  post[:d5] = browser_info[:user_agent]
@@ -345,14 +346,7 @@ module ActiveMerchant #:nodoc:
345
346
  post[:d6] = browser_info[:language]
346
347
  post[:'3ds_browserjavaenabled'] = browser_info[:java]
347
348
  post[:'3ds_browseracceptheader'] = browser_info[:accept_header]
348
- if (shipping_address = options[:shipping_address])
349
- post[:'3ds_shipaddrstate'] = shipping_address[:state]
350
- post[:'3ds_shipaddrpostcode'] = shipping_address[:zip]
351
- post[:'3ds_shipaddrline2'] = shipping_address[:address2]
352
- post[:'3ds_shipaddrline1'] = shipping_address[:address1]
353
- post[:'3ds_shipaddrcountry'] = shipping_address[:country]
354
- post[:'3ds_shipaddrcity'] = shipping_address[:city]
355
- end
349
+ add_complete_shipping_address(post, options[:shipping_address]) if options[:shipping_address]
356
350
  elsif options[:three_d_secure]
357
351
  add_normalized_3d_secure_2_data(post, options)
358
352
  end
@@ -372,6 +366,17 @@ module ActiveMerchant #:nodoc:
372
366
  end
373
367
  end
374
368
 
369
+ def add_complete_shipping_address(post, shipping_address)
370
+ return if shipping_address.values.any?(&:blank?)
371
+
372
+ post[:'3ds_shipaddrstate'] = shipping_address[:state]
373
+ post[:'3ds_shipaddrpostcode'] = shipping_address[:zip]
374
+ post[:'3ds_shipaddrline2'] = shipping_address[:address2]
375
+ post[:'3ds_shipaddrline1'] = shipping_address[:address1]
376
+ post[:'3ds_shipaddrcountry'] = shipping_address[:country]
377
+ post[:'3ds_shipaddrcity'] = shipping_address[:city]
378
+ end
379
+
375
380
  def add_normalized_3d_secure_2_data(post, options)
376
381
  three_d_secure_options = options[:three_d_secure]
377
382
 
@@ -25,8 +25,8 @@ module ActiveMerchant #:nodoc:
25
25
  self.live_url = 'https://ics2wsa.ic3.com/commerce/1.x/transactionProcessor'
26
26
 
27
27
  # Schema files can be found here: https://ics2ws.ic3.com/commerce/1.x/transactionProcessor/
28
- TEST_XSD_VERSION = '1.164'
29
- PRODUCTION_XSD_VERSION = '1.164'
28
+ TEST_XSD_VERSION = '1.181'
29
+ PRODUCTION_XSD_VERSION = '1.181'
30
30
  ECI_BRAND_MAPPING = {
31
31
  visa: 'vbv',
32
32
  master: 'spa',
@@ -298,6 +298,8 @@ module ActiveMerchant #:nodoc:
298
298
  add_partner_solution_id(xml)
299
299
  add_stored_credential_options(xml, options)
300
300
  add_merchant_description(xml, options)
301
+ add_sales_slip_number(xml, options)
302
+ add_airline_data(xml, options)
301
303
 
302
304
  xml.target!
303
305
  end
@@ -336,6 +338,8 @@ module ActiveMerchant #:nodoc:
336
338
  add_threeds_2_ucaf_data(xml, payment_method_or_reference, options)
337
339
  add_decision_manager_fields(xml, options)
338
340
  add_mdd_fields(xml, options)
341
+ add_sales_slip_number(xml, options)
342
+ add_airline_data(xml, options)
339
343
  if !payment_method_or_reference.is_a?(String) && card_brand(payment_method_or_reference) == 'check'
340
344
  add_check_service(xml)
341
345
  add_issuer_additional_data(xml, options)
@@ -523,6 +527,18 @@ module ActiveMerchant #:nodoc:
523
527
  end
524
528
  end
525
529
 
530
+ def add_sales_slip_number(xml, options)
531
+ xml.tag! 'salesSlipNumber', options[:sales_slip_number] if options[:sales_slip_number]
532
+ end
533
+
534
+ def add_airline_data(xml, options)
535
+ return unless options[:airline_agent_code]
536
+
537
+ xml.tag! 'airlineData' do
538
+ xml.tag! 'agentCode', options[:airline_agent_code]
539
+ end
540
+ end
541
+
526
542
  def add_purchase_data(xml, money = 0, include_grand_total = false, options = {})
527
543
  xml.tag! 'purchaseTotals' do
528
544
  xml.tag! 'currency', options[:currency] || currency(money)
@@ -532,6 +548,7 @@ module ActiveMerchant #:nodoc:
532
548
 
533
549
  def add_address(xml, payment_method, address, options, shipTo = false)
534
550
  first_name, last_name = address_names(address[:name], payment_method)
551
+ bill_to_merchant_tax_id = options[:merchant_tax_id] unless shipTo
535
552
 
536
553
  xml.tag! shipTo ? 'shipTo' : 'billTo' do
537
554
  xml.tag! 'firstName', first_name if first_name
@@ -549,6 +566,7 @@ module ActiveMerchant #:nodoc:
549
566
  xml.tag! 'ipAddress', options[:ip] unless options[:ip].blank? || shipTo
550
567
  xml.tag! 'driversLicenseNumber', options[:drivers_license_number] unless options[:drivers_license_number].blank?
551
568
  xml.tag! 'driversLicenseState', options[:drivers_license_state] unless options[:drivers_license_state].blank?
569
+ xml.tag! 'merchantTaxID', bill_to_merchant_tax_id unless bill_to_merchant_tax_id.blank?
552
570
  end
553
571
  end
554
572
 
@@ -604,7 +622,7 @@ module ActiveMerchant #:nodoc:
604
622
  xml.tag! 'merchantDefinedData' do
605
623
  (1..100).each do |each|
606
624
  key = "mdd_field_#{each}".to_sym
607
- xml.tag!("field#{each}", options[key]) if options[key]
625
+ xml.tag!('mddField', options[key], 'id' => each) if options[key]
608
626
  end
609
627
  end
610
628
  end
@@ -853,6 +871,8 @@ module ActiveMerchant #:nodoc:
853
871
 
854
872
  xml.tag! 'installment' do
855
873
  xml.tag! 'totalCount', options[:installment_total_count]
874
+ xml.tag!('planType', options[:installment_plan_type]) if options[:installment_plan_type]
875
+ xml.tag!('firstInstallmentDate', options[:first_installment_date]) if options[:first_installment_date]
856
876
  end
857
877
  end
858
878
 
@@ -6,7 +6,7 @@ module ActiveMerchant #:nodoc:
6
6
 
7
7
  self.supported_countries = %w[AR BR CL CO MX PE UY TR]
8
8
  self.default_currency = 'USD'
9
- self.supported_cardtypes = %i[visa master american_express discover jcb diners_club maestro naranja cabal]
9
+ self.supported_cardtypes = %i[visa master american_express discover jcb diners_club maestro naranja cabal elo alia carnet]
10
10
 
11
11
  self.homepage_url = 'https://dlocal.com/'
12
12
  self.display_name = 'dLocal'
@@ -39,6 +39,7 @@ module ActiveMerchant #:nodoc:
39
39
 
40
40
  def purchase(money, payment_method, options = {})
41
41
  request = build_xml_request do |xml|
42
+ xml.ssl_vendor_id @options[:ssl_vendor_id] || options[:ssl_vendor_id]
42
43
  xml.ssl_transaction_type self.actions[:purchase]
43
44
  xml.ssl_amount amount(money)
44
45
 
@@ -63,6 +64,7 @@ module ActiveMerchant #:nodoc:
63
64
 
64
65
  def authorize(money, creditcard, options = {})
65
66
  request = build_xml_request do |xml|
67
+ xml.ssl_vendor_id @options[:ssl_vendor_id] || options[:ssl_vendor_id]
66
68
  xml.ssl_transaction_type self.actions[:authorize]
67
69
  xml.ssl_amount amount(money)
68
70
 
@@ -82,6 +84,8 @@ module ActiveMerchant #:nodoc:
82
84
 
83
85
  def capture(money, authorization, options = {})
84
86
  request = build_xml_request do |xml|
87
+ xml.ssl_vendor_id @options[:ssl_vendor_id] || options[:ssl_vendor_id]
88
+
85
89
  if options[:credit_card]
86
90
  xml.ssl_transaction_type self.actions[:capture]
87
91
  xml.ssl_amount amount(money)
@@ -107,6 +111,7 @@ module ActiveMerchant #:nodoc:
107
111
 
108
112
  def refund(money, identification, options = {})
109
113
  request = build_xml_request do |xml|
114
+ xml.ssl_vendor_id @options[:ssl_vendor_id] || options[:ssl_vendor_id]
110
115
  xml.ssl_transaction_type self.actions[:refund]
111
116
  xml.ssl_amount amount(money)
112
117
  add_txn_id(xml, identification)
@@ -117,6 +122,7 @@ module ActiveMerchant #:nodoc:
117
122
 
118
123
  def void(identification, options = {})
119
124
  request = build_xml_request do |xml|
125
+ xml.ssl_vendor_id @options[:ssl_vendor_id] || options[:ssl_vendor_id]
120
126
  xml.ssl_transaction_type self.actions[:void]
121
127
 
122
128
  add_txn_id(xml, identification)
@@ -129,6 +135,7 @@ module ActiveMerchant #:nodoc:
129
135
  raise ArgumentError, 'Reference credits are not supported. Please supply the original credit card or use the #refund method.' if creditcard.is_a?(String)
130
136
 
131
137
  request = build_xml_request do |xml|
138
+ xml.ssl_vendor_id @options[:ssl_vendor_id] || options[:ssl_vendor_id]
132
139
  xml.ssl_transaction_type self.actions[:credit]
133
140
  xml.ssl_amount amount(money)
134
141
  add_invoice(xml, options)
@@ -143,6 +150,7 @@ module ActiveMerchant #:nodoc:
143
150
 
144
151
  def verify(credit_card, options = {})
145
152
  request = build_xml_request do |xml|
153
+ xml.ssl_vendor_id @options[:ssl_vendor_id] || options[:ssl_vendor_id]
146
154
  xml.ssl_transaction_type self.actions[:verify]
147
155
  add_creditcard(xml, credit_card)
148
156
  add_address(xml, options)
@@ -154,6 +162,7 @@ module ActiveMerchant #:nodoc:
154
162
 
155
163
  def store(creditcard, options = {})
156
164
  request = build_xml_request do |xml|
165
+ xml.ssl_vendor_id @options[:ssl_vendor_id] || options[:ssl_vendor_id]
157
166
  xml.ssl_transaction_type self.actions[:store]
158
167
  xml.ssl_add_token 'Y'
159
168
  add_creditcard(xml, creditcard)
@@ -167,6 +176,7 @@ module ActiveMerchant #:nodoc:
167
176
 
168
177
  def update(token, creditcard, options = {})
169
178
  request = build_xml_request do |xml|
179
+ xml.ssl_vendor_id @options[:ssl_vendor_id] || options[:ssl_vendor_id]
170
180
  xml.ssl_transaction_type self.actions[:update]
171
181
  add_token(xml, token)
172
182
  add_creditcard(xml, creditcard)
@@ -423,7 +433,7 @@ module ActiveMerchant #:nodoc:
423
433
 
424
434
  difference = value.force_encoding('iso-8859-1').length - value.length
425
435
 
426
- return value.to_s[0, (size - difference)]
436
+ return value.delete('&"<>').to_s[0, (size - difference)]
427
437
  end
428
438
  end
429
439
  end
@@ -28,6 +28,7 @@ module ActiveMerchant #:nodoc:
28
28
  add_payment_method(post, payment_method, options)
29
29
  add_billing_address(post, payment_method, options)
30
30
  add_shipping_address(post, options)
31
+ add_xdata(post, options)
31
32
  post[:action] = 'sale'
32
33
 
33
34
  commit(:post, post)
@@ -41,6 +42,7 @@ module ActiveMerchant #:nodoc:
41
42
  add_payment_method(post, payment_method, options)
42
43
  add_billing_address(post, payment_method, options)
43
44
  add_shipping_address(post, options)
45
+ add_xdata(post, options)
44
46
  post[:action] = 'authorize'
45
47
 
46
48
  commit(:post, post)
@@ -122,6 +124,16 @@ module ActiveMerchant #:nodoc:
122
124
  post[:service_fee_amount] = options[:service_fee_amount] if options[:service_fee_amount]
123
125
  end
124
126
 
127
+ def add_xdata(post, options)
128
+ post[:xdata] = {}
129
+ if xdata = options[:xdata]
130
+ (1..9).each do |n|
131
+ field = "xdata_#{n}".to_sym
132
+ post[:xdata][field] = xdata[field] if xdata[field]
133
+ end
134
+ end
135
+ end
136
+
125
137
  def add_billing_address(post, payment, options)
126
138
  post[:billing_address] = {}
127
139
  if address = options[:billing_address] || options[:address]
@@ -39,6 +39,7 @@ module ActiveMerchant #:nodoc:
39
39
  add_descriptor_name(xml, options)
40
40
  add_card_or_token_payment(xml, card_or_token, options)
41
41
  add_three_d_secure(xml, card_or_token, options)
42
+ add_stored_credentials(xml, options)
42
43
  end
43
44
  end
44
45
 
@@ -52,6 +53,8 @@ module ActiveMerchant #:nodoc:
52
53
  def purchase(money, payment_method, options = {})
53
54
  if payment_method.is_a?(Check)
54
55
  commit_check_sale(money, payment_method, options)
56
+ elsif options.dig(:stored_credential, :reason_type) == 'recurring'
57
+ commit_recurring_billing_sale(money, payment_method, options)
55
58
  else
56
59
  commit_credit_sale(money, payment_method, options)
57
60
  end
@@ -131,6 +134,21 @@ module ActiveMerchant #:nodoc:
131
134
  add_descriptor_name(xml, options)
132
135
  add_card_or_token_payment(xml, card_or_token, options)
133
136
  add_three_d_secure(xml, card_or_token, options)
137
+ add_stored_credentials(xml, options)
138
+ end
139
+ end
140
+
141
+ def commit_recurring_billing_sale(money, card_or_token, options)
142
+ commit('RecurringBilling') do |xml|
143
+ add_amount(xml, money)
144
+ add_allow_dup(xml)
145
+ add_card_or_token_customer_data(xml, card_or_token, options)
146
+ add_details(xml, options)
147
+ add_descriptor_name(xml, options)
148
+ add_card_or_token_payment(xml, card_or_token, options)
149
+ add_three_d_secure(xml, card_or_token, options)
150
+ add_stored_credentials(xml, options)
151
+ add_stored_credentials_for_recurring_billing(xml, options)
134
152
  end
135
153
  end
136
154
 
@@ -157,7 +175,7 @@ module ActiveMerchant #:nodoc:
157
175
  xml.hps :CardHolderAddr, billing_address[:address1] if billing_address[:address1]
158
176
  xml.hps :CardHolderCity, billing_address[:city] if billing_address[:city]
159
177
  xml.hps :CardHolderState, billing_address[:state] if billing_address[:state]
160
- xml.hps :CardHolderZip, billing_address[:zip] if billing_address[:zip]
178
+ xml.hps :CardHolderZip, alphanumeric_zip(billing_address[:zip]) if billing_address[:zip]
161
179
  end
162
180
  end
163
181
  end
@@ -265,6 +283,38 @@ module ActiveMerchant #:nodoc:
265
283
  end
266
284
  end
267
285
 
286
+ # We do not currently support installments on this gateway.
287
+ # The HPS gateway treats recurring transactions as a seperate transaction type
288
+ def add_stored_credentials(xml, options)
289
+ return unless options[:stored_credential]
290
+
291
+ xml.hps :CardOnFileData do
292
+ if options[:stored_credential][:initiator] == 'customer'
293
+ xml.hps :CardOnFile, 'C'
294
+ elsif options[:stored_credential][:initiator] == 'merchant'
295
+ xml.hps :CardOnFile, 'M'
296
+ else
297
+ return
298
+ end
299
+
300
+ if options[:stored_credential][:network_transaction_id]
301
+ xml.hps :CardBrandTxnId, options[:stored_credential][:network_transaction_id]
302
+ else
303
+ return
304
+ end
305
+ end
306
+ end
307
+
308
+ def add_stored_credentials_for_recurring_billing(xml, options)
309
+ xml.hps :RecurringData do
310
+ if options[:stored_credential][:reason_type] = 'recurring'
311
+ xml.hps :OneTime, 'N'
312
+ else
313
+ xml.hps :OneTime, 'Y'
314
+ end
315
+ end
316
+ end
317
+
268
318
  def strip_leading_zero(value)
269
319
  return value unless value[0] == '0'
270
320
 
@@ -389,6 +439,10 @@ module ActiveMerchant #:nodoc:
389
439
  @options[:secret_api_key]&.include?('_cert_')
390
440
  end
391
441
 
442
+ def alphanumeric_zip(zip)
443
+ zip.gsub(/[^0-9a-z]/i, '')
444
+ end
445
+
392
446
  ISSUER_MESSAGES = {
393
447
  '13' => 'Must be greater than or equal 0.',
394
448
  '14' => 'The card number is incorrect.',
@@ -494,7 +494,7 @@ module ActiveMerchant #:nodoc:
494
494
  attributes = {}
495
495
  attributes[:id] = truncate(options[:id] || options[:order_id], 24)
496
496
  attributes[:reportGroup] = options[:merchant] || 'Default Report Group'
497
- attributes[:customerId] = options[:customer]
497
+ attributes[:customerId] = options[:customer_id]
498
498
  attributes.delete_if { |_key, value| value == nil }
499
499
  attributes
500
500
  end
@@ -4,7 +4,7 @@ module ActiveMerchant #:nodoc:
4
4
  self.live_url = self.test_url = 'https://api.mercadopago.com/v1'
5
5
 
6
6
  self.supported_countries = %w[AR BR CL CO MX PE UY]
7
- self.supported_cardtypes = %i[visa master american_express elo cabal naranja]
7
+ self.supported_cardtypes = %i[visa master american_express elo cabal naranja creditel]
8
8
 
9
9
  self.homepage_url = 'https://www.mercadopago.com/'
10
10
  self.display_name = 'Mercado Pago'
@@ -105,7 +105,7 @@ module ActiveMerchant #:nodoc:
105
105
 
106
106
  def authorize_request(money, payment, options = {})
107
107
  post = purchase_request(money, payment, options)
108
- post[:capture] = false
108
+ post[:capture] = options[:capture] || false
109
109
  post
110
110
  end
111
111
 
@@ -22,6 +22,22 @@ module ActiveMerchant #:nodoc:
22
22
  self.homepage_url = 'https://processing.paysafe.com/'
23
23
  self.display_name = 'Netbanx by PaySafe'
24
24
 
25
+ AVS_CODE_CONVERTER = {
26
+ 'MATCH' => 'X',
27
+ 'MATCH_ADDRESS_ONLY' => 'A',
28
+ 'MATCH_ZIP_ONLY' => 'Z',
29
+ 'NO_MATCH' => 'N',
30
+ 'NOT_PROCESSED' => 'U',
31
+ 'UNKNOWN' => 'Q'
32
+ }
33
+
34
+ CVV_CODE_CONVERTER = {
35
+ 'MATCH' => 'M',
36
+ 'NO_MATCH' => 'N',
37
+ 'NOT_PROCESSED' => 'P',
38
+ 'UNKNOWN' => 'U'
39
+ }
40
+
25
41
  def initialize(options = {})
26
42
  requires!(options, :account_number, :api_key)
27
43
  super
@@ -256,11 +272,19 @@ module ActiveMerchant #:nodoc:
256
272
  test: test?,
257
273
  error_code: error_code_from(response),
258
274
  authorization: authorization_from(success, get_url(uri), method, response),
259
- avs_result: AVSResult.new(code: response['avsResponse']),
260
- cvv_result: CVVResult.new(response['cvvVerification'])
275
+ avs_result: avs_result(response),
276
+ cvv_result: cvv_result(response)
261
277
  )
262
278
  end
263
279
 
280
+ def avs_result(response)
281
+ AVSResult.new(code: AVS_CODE_CONVERTER[response['avsResponse']])
282
+ end
283
+
284
+ def cvv_result(response)
285
+ CVVResult.new(CVV_CODE_CONVERTER[response['cvvVerification']])
286
+ end
287
+
264
288
  def get_url(uri)
265
289
  url = (test? ? test_url : live_url)
266
290
  if /^customervault/.match?(uri)
@@ -190,31 +190,6 @@ module ActiveMerchant #:nodoc:
190
190
  'checking' => 'C'
191
191
  }
192
192
 
193
- # Fixed possible values for orbital ECP attributes
194
- # Auth methods for electronic checks can be:
195
- # Written, Internet, Telephonic, Account Receivable, Point of Purchase.
196
- # Default auth method for ECP is Internet (I).
197
- # Bank payment delivery can be either ACH (Automated Clearing House) or Best Possible.
198
- # Default Bank Payment Delivery is Best Possible (B).
199
- # Action codes to be used for Early Warning System and additional validations.
200
- # Valid combinations of Message Type and Action Code to be used are:
201
- # A W1
202
- # AC W1
203
- # FC W4
204
- # R W6
205
- # FC W8
206
- # A W3
207
- # AC W3
208
- # FC W5
209
- # R W7
210
- # Default Action code for ECP is nil.
211
- # Electronic check to be processed on same day (Y) or next day (N).
212
- # Default ECP Same Day Index is Yes (Y).
213
- ECP_AUTH_METHODS = %w[W I T A P]
214
- ECP_BANK_PAYMENT = %w[A B]
215
- ECP_ACTION_CODES = %w[LO ND NC W1 W3 W4 W5 W6 W7 W8 W9]
216
- ECP_SAME_DAY = %w[Y N]
217
-
218
193
  def initialize(options = {})
219
194
  requires!(options, :merchant_id)
220
195
  requires!(options, :login, :password) unless options[:ip_authentication]
@@ -224,6 +199,14 @@ module ActiveMerchant #:nodoc:
224
199
 
225
200
  # A – Authorization request
226
201
  def authorize(money, payment_source, options = {})
202
+ # ECP for Orbital requires $0 prenotes so ensure
203
+ # if we are doing a force capture with a check, that
204
+ # we do a purchase here
205
+ if options[:force_capture] && payment_source.is_a?(Check) &&
206
+ (options[:action_code].include?('W8') || options[:action_code].include?('W9') || options[:action_code].include?('ND'))
207
+ return purchase(money, payment_source, options)
208
+ end
209
+
227
210
  order = build_new_order_xml(AUTH_ONLY, money, payment_source, options) do |xml|
228
211
  add_payment_source(xml, payment_source, options)
229
212
  add_address(xml, payment_source, options)
@@ -232,7 +215,7 @@ module ActiveMerchant #:nodoc:
232
215
  add_managed_billing(xml, options)
233
216
  end
234
217
  end
235
- commit(order, :authorize, options[:trace_number])
218
+ commit(order, :authorize, options[:retry_logic], options[:trace_number])
236
219
  end
237
220
 
238
221
  def verify(creditcard, options = {})
@@ -252,26 +235,34 @@ module ActiveMerchant #:nodoc:
252
235
  add_managed_billing(xml, options)
253
236
  end
254
237
  end
255
- commit(order, :purchase, options[:trace_number])
238
+
239
+ commit(order, :purchase, options[:retry_logic], options[:trace_number])
256
240
  end
257
241
 
258
242
  # MFC - Mark For Capture
259
243
  def capture(money, authorization, options = {})
260
- commit(build_mark_for_capture_xml(money, authorization, options), :capture)
244
+ commit(build_mark_for_capture_xml(money, authorization, options), :capture, options[:retry_logic], options[:trace_number])
261
245
  end
262
246
 
263
247
  # R – Refund request
264
248
  def refund(money, authorization, options = {})
265
- order = build_new_order_xml(REFUND, money, nil, options.merge(authorization: authorization)) do |xml|
266
- add_refund(xml, options[:currency])
249
+ payment_method = options[:payment_method]
250
+ order = build_new_order_xml(REFUND, money, payment_method, options.merge(authorization: authorization)) do |xml|
251
+ if payment_method.is_a?(Check)
252
+ add_echeck(xml, payment_method, options)
253
+ else
254
+ add_refund(xml, options[:currency])
255
+ end
267
256
  xml.tag! :CustomerRefNum, options[:customer_ref_num] if @options[:customer_profiles] && options[:profile_txn]
268
257
  end
269
- commit(order, :refund, options[:trace_number])
258
+ commit(order, :refund, options[:retry_logic], options[:trace_number])
270
259
  end
271
260
 
272
- def credit(money, authorization, options = {})
273
- ActiveMerchant.deprecated CREDIT_DEPRECATION_MESSAGE
274
- refund(money, authorization, options)
261
+ def credit(money, payment_method, options = {})
262
+ order = build_new_order_xml(REFUND, money, payment_method, options) do |xml|
263
+ add_payment_source(xml, payment_method, options)
264
+ end
265
+ commit(order, :refund, options[:retry_logic], options[:trace_number])
275
266
  end
276
267
 
277
268
  def void(authorization, options = {}, deprecated = {})
@@ -281,7 +272,7 @@ module ActiveMerchant #:nodoc:
281
272
  end
282
273
 
283
274
  order = build_void_request_xml(authorization, options)
284
- commit(order, :void, options[:trace_number])
275
+ commit(order, :void, options[:retry_logic], options[:trace_number])
285
276
  end
286
277
 
287
278
  # ==== Customer Profiles
@@ -398,9 +389,9 @@ module ActiveMerchant #:nodoc:
398
389
  def add_level3_tax(xml, options = {})
399
390
  if (level3 = options[:level_3_data])
400
391
  xml.tag! :PC3VATtaxAmt, byte_limit(level3[:vat_tax], 12) if level3[:vat_tax]
401
- xml.tag! :PC3AltTaxAmt, byte_limit(level3[:alt_tax], 9) if level3[:alt_tax]
402
392
  xml.tag! :PC3VATtaxRate, byte_limit(level3[:vat_rate], 4) if level3[:vat_rate]
403
393
  xml.tag! :PC3AltTaxInd, byte_limit(level3[:alt_ind], 15) if level3[:alt_ind]
394
+ xml.tag! :PC3AltTaxAmt, byte_limit(level3[:alt_tax], 9) if level3[:alt_tax]
404
395
  end
405
396
  end
406
397
 
@@ -458,20 +449,22 @@ module ActiveMerchant #:nodoc:
458
449
  xml.tag! :CardIndicators, options[:card_indicators] if options[:card_indicators]
459
450
  end
460
451
 
461
- def add_address(xml, creditcard, options)
462
- if (address = (options[:billing_address] || options[:address]))
452
+ def add_address(xml, payment_source, options)
453
+ address = get_address(options)
454
+
455
+ unless address.blank?
463
456
  avs_supported = AVS_SUPPORTED_COUNTRIES.include?(address[:country].to_s) || empty?(address[:country])
464
457
 
465
458
  if avs_supported
466
- xml.tag! :AVSzip, byte_limit(format_address_field(address[:zip]), 10)
459
+ xml.tag! :AVSzip, byte_limit(format_address_field(address[:zip]), 10)
467
460
  xml.tag! :AVSaddress1, byte_limit(format_address_field(address[:address1]), 30)
468
461
  xml.tag! :AVSaddress2, byte_limit(format_address_field(address[:address2]), 30)
469
- xml.tag! :AVScity, byte_limit(format_address_field(address[:city]), 20)
470
- xml.tag! :AVSstate, byte_limit(format_address_field(address[:state]), 2)
462
+ xml.tag! :AVScity, byte_limit(format_address_field(address[:city]), 20)
463
+ xml.tag! :AVSstate, byte_limit(format_address_field(address[:state]), 2)
471
464
  xml.tag! :AVSphoneNum, (address[:phone] ? address[:phone].scan(/\d/).join.to_s[0..13] : nil)
472
465
  end
473
466
 
474
- xml.tag! :AVSname, (creditcard&.name ? creditcard.name[0..29] : nil)
467
+ xml.tag! :AVSname, (payment_source&.name ? payment_source.name[0..29] : nil)
475
468
  xml.tag! :AVScountryCode, (avs_supported ? byte_limit(format_address_field(address[:country]), 2) : '')
476
469
 
477
470
  # Needs to come after AVScountryCode
@@ -497,7 +490,9 @@ module ActiveMerchant #:nodoc:
497
490
 
498
491
  # For Profile requests
499
492
  def add_customer_address(xml, options)
500
- if (address = (options[:billing_address] || options[:address]))
493
+ address = get_address(options)
494
+
495
+ unless address.blank?
501
496
  avs_supported = AVS_SUPPORTED_COUNTRIES.include?(address[:country].to_s)
502
497
 
503
498
  xml.tag! :CustomerAddress1, byte_limit(format_address_field(address[:address1]), 30)
@@ -530,8 +525,15 @@ module ActiveMerchant #:nodoc:
530
525
  xml.tag! :BCRtNum, check.routing_number
531
526
  xml.tag! :CheckDDA, check.account_number if check.account_number
532
527
  xml.tag! :BankAccountType, ACCOUNT_TYPE[check.account_type] if ACCOUNT_TYPE[check.account_type]
533
- xml.tag! :ECPAuthMethod, options[:auth_method] if options[:auth_method] && ECP_AUTH_METHODS.include?(options[:auth_method])
534
- xml.tag! :BankPmtDelv, options[:payment_delivery] if options[:payment_delivery] && ECP_BANK_PAYMENT.include?(options[:payment_delivery])
528
+ xml.tag! :ECPAuthMethod, options[:auth_method] if options[:auth_method]
529
+
530
+ if options[:payment_delivery]
531
+ xml.tag! :BankPmtDelv, options[:payment_delivery]
532
+ else
533
+ xml.tag! :BankPmtDelv, 'B'
534
+ end
535
+
536
+ xml.tag! :AVSname, (check&.name ? check.name[0..29] : nil) if get_address(options).blank?
535
537
  end
536
538
  end
537
539
 
@@ -664,7 +666,9 @@ module ActiveMerchant #:nodoc:
664
666
  end
665
667
 
666
668
  def add_ews_details(xml, payment_source, parameters = {})
667
- xml.tag! :EWSFirstName, payment_source.first_name
669
+ split_name = payment_source.first_name.split if payment_source.first_name
670
+ xml.tag! :EWSFirstName, split_name[0]
671
+ xml.tag! :EWSMiddleName, split_name[1..-1].join(' ')
668
672
  xml.tag! :EWSLastName, payment_source.last_name
669
673
  xml.tag! :EWSBusinessName, parameters[:company] if payment_source.first_name.empty? && payment_source.last_name.empty?
670
674
 
@@ -684,7 +688,7 @@ module ActiveMerchant #:nodoc:
684
688
  # Adds ECP conditional attributes depending on other attribute values
685
689
  def add_ecp_details(xml, payment_source, parameters = {})
686
690
  requires!(payment_source.account_number) if parameters[:auth_method]&.eql?('A') || parameters[:auth_method]&.eql?('P')
687
- xml.tag! :ECPActionCode, parameters[:action_code] if parameters[:action_code] && ECP_ACTION_CODES.include?(parameters[:action_code])
691
+ xml.tag! :ECPActionCode, parameters[:action_code] if parameters[:action_code]
688
692
  xml.tag! :ECPCheckSerialNumber, payment_source.account_number if parameters[:auth_method]&.eql?('A') || parameters[:auth_method]&.eql?('P')
689
693
  if parameters[:auth_method]&.eql?('P')
690
694
  xml.tag! :ECPTerminalCity, parameters[:terminal_city] if parameters[:terminal_city]
@@ -753,9 +757,9 @@ module ActiveMerchant #:nodoc:
753
757
  end
754
758
  end
755
759
 
756
- def commit(order, message_type, trace_number = nil)
760
+ def commit(order, message_type, retry_logic = nil, trace_number = nil)
757
761
  headers = POST_HEADERS.merge('Content-length' => order.size.to_s)
758
- if @options[:retry_logic] && trace_number
762
+ if (@options[:retry_logic] || retry_logic) && trace_number
759
763
  headers['Trace-number'] = trace_number.to_s
760
764
  headers['Merchant-Id'] = @options[:merchant_id]
761
765
  end
@@ -854,12 +858,12 @@ module ActiveMerchant #:nodoc:
854
858
  add_aevv(xml, payment_source, three_d_secure)
855
859
  add_digital_token_cryptogram(xml, payment_source)
856
860
 
857
- xml.tag! :ECPSameDayInd, parameters[:same_day] if parameters[:same_day] && ECP_SAME_DAY.include?(parameters[:same_day]) && payment_source.is_a?(Check)
861
+ xml.tag! :ECPSameDayInd, parameters[:same_day] if parameters[:same_day] && payment_source.is_a?(Check)
858
862
 
859
863
  set_recurring_ind(xml, parameters)
860
864
 
861
865
  # Append Transaction Reference Number at the end for Refund transactions
862
- if action == REFUND
866
+ if action == REFUND && parameters[:authorization]
863
867
  tx_ref_num, = split_authorization(parameters[:authorization])
864
868
  xml.tag! :TxRefNum, tx_ref_num
865
869
  end
@@ -906,6 +910,7 @@ module ActiveMerchant #:nodoc:
906
910
  add_level2_advice_addendum(xml, parameters)
907
911
  add_level3_purchase(xml, parameters)
908
912
  add_level3_tax(xml, parameters)
913
+ add_line_items(xml, parameters) if parameters[:line_items]
909
914
  end
910
915
  end
911
916
  xml.target!
@@ -968,6 +973,10 @@ module ActiveMerchant #:nodoc:
968
973
  @options[:merchant_id].length == 6
969
974
  end
970
975
 
976
+ def get_address(options)
977
+ options[:billing_address] || options[:address]
978
+ end
979
+
971
980
  # The valid characters include:
972
981
  #
973
982
  # 1. all letters and digits
@@ -1105,7 +1114,7 @@ module ActiveMerchant #:nodoc:
1105
1114
  'Y' => %w(9 A B C H JA JD M2 M3 M5 N5 N8 N9 X Z),
1106
1115
  'N' => %w(D E F G M8),
1107
1116
  'X' => %w(4 J R),
1108
- nil => %w(1 2 3 5 6 7 8 JB JC M1 M4 M6 M7 N3 N4 N6 N7 UK)
1117
+ nil => %w(1 2 3 5 6 7 8 JB JC M1 M4 M6 M7 N3 N4 N6 N7 UK)
1109
1118
  }.inject({}) do |map, (type, codes)|
1110
1119
  codes.each { |code| map[code] = type }
1111
1120
  map
@@ -1116,7 +1125,7 @@ module ActiveMerchant #:nodoc:
1116
1125
  'Y' => %w(9 B D F H JA JB M2 M4 M5 M6 M7 N3 N5 N7 N8 N9 X),
1117
1126
  'N' => %w(A C E G M8 Z),
1118
1127
  'X' => %w(4 J R),
1119
- nil => %w(1 2 3 5 6 7 8 JC JD M1 M3 N4 N6 UK)
1128
+ nil => %w(1 2 3 5 6 7 8 JC JD M1 M3 N4 N6 UK)
1120
1129
  }.inject({}) do |map, (type, codes)|
1121
1130
  codes.each { |code| map[code] = type }
1122
1131
  map