activemerchant 1.95.0 → 1.96.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 (37) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +45 -0
  3. data/README.md +3 -0
  4. data/lib/active_merchant/billing/avs_result.rb +4 -5
  5. data/lib/active_merchant/billing/credit_card.rb +2 -0
  6. data/lib/active_merchant/billing/credit_card_methods.rb +14 -0
  7. data/lib/active_merchant/billing/gateway.rb +10 -0
  8. data/lib/active_merchant/billing/gateways/adyen.rb +19 -6
  9. data/lib/active_merchant/billing/gateways/barclaycard_smartpay.rb +39 -10
  10. data/lib/active_merchant/billing/gateways/blue_snap.rb +4 -1
  11. data/lib/active_merchant/billing/gateways/bpoint.rb +4 -4
  12. data/lib/active_merchant/billing/gateways/braintree_blue.rb +11 -1
  13. data/lib/active_merchant/billing/gateways/card_connect.rb +1 -0
  14. data/lib/active_merchant/billing/gateways/cecabank.rb +7 -7
  15. data/lib/active_merchant/billing/gateways/checkout_v2.rb +24 -24
  16. data/lib/active_merchant/billing/gateways/credorax.rb +29 -3
  17. data/lib/active_merchant/billing/gateways/cyber_source.rb +2 -2
  18. data/lib/active_merchant/billing/gateways/decidir.rb +232 -0
  19. data/lib/active_merchant/billing/gateways/global_collect.rb +2 -6
  20. data/lib/active_merchant/billing/gateways/hps.rb +46 -1
  21. data/lib/active_merchant/billing/gateways/kushki.rb +1 -1
  22. data/lib/active_merchant/billing/gateways/migs.rb +8 -0
  23. data/lib/active_merchant/billing/gateways/mundipagg.rb +1 -1
  24. data/lib/active_merchant/billing/gateways/nab_transact.rb +1 -1
  25. data/lib/active_merchant/billing/gateways/nmi.rb +39 -1
  26. data/lib/active_merchant/billing/gateways/opp.rb +20 -1
  27. data/lib/active_merchant/billing/gateways/payflow.rb +40 -2
  28. data/lib/active_merchant/billing/gateways/paypal.rb +14 -1
  29. data/lib/active_merchant/billing/gateways/realex.rb +11 -5
  30. data/lib/active_merchant/billing/gateways/spreedly_core.rb +43 -29
  31. data/lib/active_merchant/billing/gateways/trans_first_transaction_express.rb +2 -2
  32. data/lib/active_merchant/billing/gateways/trust_commerce.rb +24 -5
  33. data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +8 -5
  34. data/lib/active_merchant/billing/gateways/worldpay.rb +157 -37
  35. data/lib/active_merchant/country.rb +1 -0
  36. data/lib/active_merchant/version.rb +1 -1
  37. metadata +3 -2
@@ -5,7 +5,7 @@ module ActiveMerchant #:nodoc:
5
5
 
6
6
  self.supported_countries = ['US']
7
7
  self.default_currency = 'USD'
8
- self.supported_cardtypes = [:visa, :master, :american_express, :discover]
8
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover, :alelo]
9
9
 
10
10
  self.homepage_url = 'https://www.mundipagg.com/'
11
11
  self.display_name = 'Mundipagg'
@@ -12,7 +12,7 @@ module ActiveMerchant #:nodoc:
12
12
 
13
13
  self.test_url = 'https://demo.transact.nab.com.au/xmlapi/payment'
14
14
  self.live_url = 'https://transact.nab.com.au/live/xmlapi/payment'
15
- self.test_periodic_url = 'https://transact.nab.com.au/xmlapidemo/periodic'
15
+ self.test_periodic_url = 'https://demo.transact.nab.com.au/xmlapi/periodic'
16
16
  self.live_periodic_url = 'https://transact.nab.com.au/xmlapi/periodic'
17
17
 
18
18
  self.supported_countries = ['AU']
@@ -31,9 +31,11 @@ module ActiveMerchant #:nodoc:
31
31
  post = {}
32
32
  add_invoice(post, amount, options)
33
33
  add_payment_method(post, payment_method, options)
34
+ add_stored_credential(post, options)
34
35
  add_customer_data(post, options)
35
36
  add_vendor_data(post, options)
36
37
  add_merchant_defined_fields(post, options)
38
+ add_level3_fields(post, options)
37
39
 
38
40
  commit('sale', post)
39
41
  end
@@ -42,9 +44,11 @@ module ActiveMerchant #:nodoc:
42
44
  post = {}
43
45
  add_invoice(post, amount, options)
44
46
  add_payment_method(post, payment_method, options)
47
+ add_stored_credential(post, options)
45
48
  add_customer_data(post, options)
46
49
  add_vendor_data(post, options)
47
50
  add_merchant_defined_fields(post, options)
51
+ add_level3_fields(post, options)
48
52
 
49
53
  commit('auth', post)
50
54
  end
@@ -81,6 +85,7 @@ module ActiveMerchant #:nodoc:
81
85
  add_payment_method(post, payment_method, options)
82
86
  add_customer_data(post, options)
83
87
  add_vendor_data(post, options)
88
+ add_level3_fields(post, options)
84
89
 
85
90
  commit('credit', post)
86
91
  end
@@ -91,6 +96,7 @@ module ActiveMerchant #:nodoc:
91
96
  add_customer_data(post, options)
92
97
  add_vendor_data(post, options)
93
98
  add_merchant_defined_fields(post, options)
99
+ add_level3_fields(post, options)
94
100
 
95
101
  commit('validate', post)
96
102
  end
@@ -117,7 +123,7 @@ module ActiveMerchant #:nodoc:
117
123
 
118
124
  def scrub(transcript)
119
125
  transcript.
120
- gsub(%r((password=)\w+), '\1[FILTERED]').
126
+ gsub(%r((password=)[^&\n]*), '\1[FILTERED]').
121
127
  gsub(%r((ccnumber=)\d+), '\1[FILTERED]').
122
128
  gsub(%r((cvv=)\d+), '\1[FILTERED]').
123
129
  gsub(%r((checkaba=)\d+), '\1[FILTERED]').
@@ -131,6 +137,10 @@ module ActiveMerchant #:nodoc:
131
137
 
132
138
  private
133
139
 
140
+ def add_level3_fields(post, options)
141
+ add_fields_to_post_if_present(post, options, [:tax, :shipping, :ponumber])
142
+ end
143
+
134
144
  def add_invoice(post, money, options)
135
145
  post[:amount] = amount(money)
136
146
  post[:orderid] = options[:order_id]
@@ -170,6 +180,34 @@ module ActiveMerchant #:nodoc:
170
180
  end
171
181
  end
172
182
 
183
+ def add_stored_credential(post, options)
184
+ return unless (stored_credential = options[:stored_credential])
185
+
186
+ if stored_credential[:initiator] == 'cardholder'
187
+ post[:initiated_by] = 'customer'
188
+ else
189
+ post[:initiated_by] = 'merchant'
190
+ end
191
+
192
+ # :reason_type, when provided, overrides anything previously set in
193
+ # post[:billing_method] (see `add_invoice` and the :recurring) option
194
+ case stored_credential[:reason_type]
195
+ when 'recurring'
196
+ post[:billing_method] = 'recurring'
197
+ when 'installment'
198
+ post[:billing_method] = 'installment'
199
+ when 'unscheduled'
200
+ post.delete(:billing_method)
201
+ end
202
+
203
+ if stored_credential[:initial_transaction]
204
+ post[:stored_credential_indicator] = 'stored'
205
+ else
206
+ post[:stored_credential_indicator] = 'used'
207
+ post[:initial_transaction_id] = stored_credential[:network_transaction_id]
208
+ end
209
+ end
210
+
173
211
  def add_customer_data(post, options)
174
212
  post[:email] = options[:email]
175
213
  post[:ipaddress] = options[:ip]
@@ -125,6 +125,9 @@ module ActiveMerchant #:nodoc:
125
125
 
126
126
  def purchase(money, payment, options={})
127
127
  # debit
128
+ if payment.is_a?(String)
129
+ options[:registrationId] = payment
130
+ end
128
131
  execute_dbpa(options[:risk_workflow] ? 'PA.CP': 'DB',
129
132
  money, payment, options)
130
133
  end
@@ -156,6 +159,10 @@ module ActiveMerchant #:nodoc:
156
159
  end
157
160
  end
158
161
 
162
+ def store(credit_card, options = {})
163
+ execute_store(credit_card, options.merge(store: true))
164
+ end
165
+
159
166
  def supports_scrubbing?
160
167
  true
161
168
  end
@@ -169,6 +176,15 @@ module ActiveMerchant #:nodoc:
169
176
 
170
177
  private
171
178
 
179
+ def execute_store(payment, options)
180
+ post = {}
181
+ add_payment_method(post, payment, options)
182
+ add_address(post, options)
183
+ add_options(post, options)
184
+ add_3d_secure(post, options)
185
+ commit(post, nil, options)
186
+ end
187
+
172
188
  def execute_dbpa(txtype, money, payment, options)
173
189
  post = {}
174
190
  post[:paymentType] = txtype
@@ -243,6 +259,7 @@ module ActiveMerchant #:nodoc:
243
259
  end
244
260
 
245
261
  def add_payment_method(post, payment, options)
262
+ return if payment.is_a?(String)
246
263
  if options[:registrationId]
247
264
  post[:card] = {
248
265
  cvv: payment.verification_value,
@@ -278,7 +295,9 @@ module ActiveMerchant #:nodoc:
278
295
  end
279
296
 
280
297
  def build_url(url, authorization, options)
281
- if options[:registrationId]
298
+ if options[:store]
299
+ url.gsub(/payments/, 'registrations')
300
+ elsif options[:registrationId]
282
301
  "#{url.gsub(/payments/, 'registrations')}/#{options[:registrationId]}/payments"
283
302
  elsif authorization
284
303
  "#{url}/#{authorization}"
@@ -1,3 +1,4 @@
1
+ require 'nokogiri'
1
2
  require 'active_merchant/billing/gateways/payflow/payflow_common_api'
2
3
  require 'active_merchant/billing/gateways/payflow/payflow_response'
3
4
  require 'active_merchant/billing/gateways/payflow_express'
@@ -187,7 +188,44 @@ module ActiveMerchant #:nodoc:
187
188
  end
188
189
  end
189
190
  end
190
- xml.target!
191
+ add_level_two_three_fields(xml.target!, options)
192
+ end
193
+
194
+ def add_level_two_three_fields(xml_string, options)
195
+ if options[:level_two_fields] || options[:level_three_fields]
196
+ xml_doc = Nokogiri::XML.parse(xml_string)
197
+ %i[level_two_fields level_three_fields].each do |fields|
198
+ xml_string = add_fields(xml_doc, options[fields]) if options[fields]
199
+ end
200
+ end
201
+ xml_string
202
+ end
203
+
204
+ def check_fields(parent, fields, xml_doc)
205
+ fields.each do |k, v|
206
+ if v.is_a? String
207
+ new_node = Nokogiri::XML::Node.new(k, xml_doc)
208
+ new_node.add_child(v)
209
+ xml_doc.at_css(parent).add_child(new_node)
210
+ else
211
+ check_subparent_before_continuing(parent, k, xml_doc)
212
+ check_fields(k, v, xml_doc)
213
+ end
214
+ end
215
+ xml_doc
216
+ end
217
+
218
+ def check_subparent_before_continuing(parent, subparent, xml_doc)
219
+ unless xml_doc.at_css(subparent)
220
+ subparent_node = Nokogiri::XML::Node.new(subparent, xml_doc)
221
+ xml_doc.at_css(parent).add_child(subparent_node)
222
+ end
223
+ end
224
+
225
+ def add_fields(xml_doc, options_fields)
226
+ fields_to_add = JSON.parse(options_fields)
227
+ check_fields('Invoice', fields_to_add, xml_doc)
228
+ xml_doc.root.to_s
191
229
  end
192
230
 
193
231
  def build_check_request(action, money, check, options)
@@ -213,7 +251,7 @@ module ActiveMerchant #:nodoc:
213
251
  end
214
252
  end
215
253
  end
216
- xml.target!
254
+ add_level_two_three_fields(xml.target!, options)
217
255
  end
218
256
 
219
257
  def add_credit_card(xml, credit_card, options = {})
@@ -9,7 +9,7 @@ module ActiveMerchant #:nodoc:
9
9
  include PaypalRecurringApi
10
10
 
11
11
  self.supported_cardtypes = [:visa, :master, :american_express, :discover]
12
- self.supported_countries = ['US']
12
+ self.supported_countries = ['CA', 'NZ', 'GB', 'US']
13
13
  self.homepage_url = 'https://www.paypal.com/us/webapps/mpp/paypal-payments-pro'
14
14
  self.display_name = 'PayPal Payments Pro (US)'
15
15
 
@@ -90,6 +90,8 @@ module ActiveMerchant #:nodoc:
90
90
  xml.tag! 'n2:Payer', options[:email]
91
91
  add_address(xml, 'n2:Address', address)
92
92
  end
93
+
94
+ add_three_d_secure(xml, options) if options[:three_d_secure]
93
95
  end
94
96
  end
95
97
 
@@ -98,6 +100,17 @@ module ActiveMerchant #:nodoc:
98
100
  xml.tag! 'n2:SoftDescriptorCity', options[:soft_descriptor_city] unless options[:soft_descriptor_city].blank?
99
101
  end
100
102
 
103
+ def add_three_d_secure(xml, options)
104
+ three_d_secure = options[:three_d_secure]
105
+ xml.tag! 'ThreeDSecureRequest' do
106
+ xml.tag! 'MpiVendor3ds', 'Y'
107
+ xml.tag! 'AuthStatus3ds', three_d_secure[:trans_status] unless three_d_secure[:trans_status].blank?
108
+ xml.tag! 'Cavv', three_d_secure[:cavv] unless three_d_secure[:cavv].blank?
109
+ xml.tag! 'Eci3ds', three_d_secure[:eci] unless three_d_secure[:eci].blank?
110
+ xml.tag! 'Xid', three_d_secure[:xid] unless three_d_secure[:xid].blank?
111
+ end
112
+ end
113
+
101
114
  def credit_card_type(type)
102
115
  case type
103
116
  when 'visa' then 'Visa'
@@ -289,12 +289,18 @@ module ActiveMerchant
289
289
  end
290
290
 
291
291
  def add_three_d_secure(xml, options)
292
- if options[:three_d_secure]
293
- xml.tag! 'mpi' do
294
- xml.tag! 'cavv', options[:three_d_secure][:cavv]
295
- xml.tag! 'eci', options[:three_d_secure][:eci]
296
- xml.tag! 'xid', options[:three_d_secure][:xid]
292
+ return unless three_d_secure = options[:three_d_secure]
293
+ version = three_d_secure.fetch(:version, '')
294
+ xml.tag! 'mpi' do
295
+ if version =~ /^2/
296
+ xml.tag! 'authentication_value', three_d_secure[:cavv]
297
+ xml.tag! 'ds_trans_id', three_d_secure[:ds_transaction_id]
298
+ else
299
+ xml.tag! 'cavv', three_d_secure[:cavv]
300
+ xml.tag! 'xid', three_d_secure[:xid]
297
301
  end
302
+ xml.tag! 'eci', three_d_secure[:eci]
303
+ xml.tag! 'message_version', version
298
304
  end
299
305
  end
300
306
 
@@ -35,19 +35,13 @@ module ActiveMerchant #:nodoc:
35
35
  # Public: Run a purchase transaction.
36
36
  #
37
37
  # money - The monetary amount of the transaction in cents.
38
- # payment_method - The CreditCard or the Spreedly payment method token.
38
+ # payment_method - The CreditCard or Check or the Spreedly payment method token.
39
39
  # options - A hash of options:
40
40
  # :store - Retain the payment method if the purchase
41
41
  # succeeds. Defaults to false. (optional)
42
42
  def purchase(money, payment_method, options = {})
43
- if payment_method.is_a?(String)
44
- purchase_with_token(money, payment_method, options)
45
- else
46
- MultiResponse.run do |r|
47
- r.process { save_card(options[:store], payment_method, options) }
48
- r.process { purchase_with_token(money, r.authorization, options) }
49
- end
50
- end
43
+ request = build_transaction_request(money, payment_method, options)
44
+ commit("gateways/#{options[:gateway_token] || @options[:gateway_token]}/purchase.xml", request)
51
45
  end
52
46
 
53
47
  # Public: Run an authorize transaction.
@@ -58,14 +52,8 @@ module ActiveMerchant #:nodoc:
58
52
  # :store - Retain the payment method if the authorize
59
53
  # succeeds. Defaults to false. (optional)
60
54
  def authorize(money, payment_method, options = {})
61
- if payment_method.is_a?(String)
62
- authorize_with_token(money, payment_method, options)
63
- else
64
- MultiResponse.run do |r|
65
- r.process { save_card(options[:store], payment_method, options) }
66
- r.process { authorize_with_token(money, r.authorization, options) }
67
- end
68
- end
55
+ request = build_transaction_request(money, payment_method, options)
56
+ commit("gateways/#{@options[:gateway_token]}/authorize.xml", request)
69
57
  end
70
58
 
71
59
  def capture(money, authorization, options={})
@@ -79,6 +67,7 @@ module ActiveMerchant #:nodoc:
79
67
  def refund(money, authorization, options={})
80
68
  request = build_xml_request('transaction') do |doc|
81
69
  add_invoice(doc, money, options)
70
+ add_extra_options(:gateway_specific_fields, doc, options)
82
71
  end
83
72
 
84
73
  commit("transactions/#{authorization}/credit.xml", request)
@@ -155,32 +144,25 @@ module ActiveMerchant #:nodoc:
155
144
  end
156
145
 
157
146
  def purchase_with_token(money, payment_method_token, options)
158
- request = auth_purchase_request(money, payment_method_token, options)
147
+ request = build_transaction_request(money, payment_method_token, options)
159
148
  commit("gateways/#{options[:gateway_token] || @options[:gateway_token]}/purchase.xml", request)
160
149
  end
161
150
 
162
151
  def authorize_with_token(money, payment_method_token, options)
163
- request = auth_purchase_request(money, payment_method_token, options)
152
+ request = build_transaction_request(money, payment_method_token, options)
164
153
  commit("gateways/#{@options[:gateway_token]}/authorize.xml", request)
165
154
  end
166
155
 
167
156
  def verify_with_token(payment_method_token, options)
168
- request = build_xml_request('transaction') do |doc|
169
- add_invoice(doc, nil, options)
170
- doc.payment_method_token(payment_method_token)
171
- doc.retain_on_success(true) if options[:store]
172
- add_extra_options(:gateway_specific_fields, doc, options)
173
- end
174
-
157
+ request = build_transaction_request(nil, payment_method_token, options)
175
158
  commit("gateways/#{@options[:gateway_token]}/verify.xml", request)
176
159
  end
177
160
 
178
- def auth_purchase_request(money, payment_method_token, options)
161
+ def build_transaction_request(money, payment_method, options)
179
162
  build_xml_request('transaction') do |doc|
180
163
  add_invoice(doc, money, options)
164
+ add_payment_method(doc, payment_method, options)
181
165
  add_extra_options(:gateway_specific_fields, doc, options)
182
- doc.payment_method_token(payment_method_token)
183
- doc.retain_on_success(true) if options[:store]
184
166
  end
185
167
  end
186
168
 
@@ -190,6 +172,27 @@ module ActiveMerchant #:nodoc:
190
172
  doc.order_id(options[:order_id])
191
173
  doc.ip(options[:ip]) if options[:ip]
192
174
  doc.description(options[:description]) if options[:description]
175
+
176
+ if options[:merchant_name_descriptor]
177
+ doc.merchant_name_descriptor(options[:merchant_name_descriptor])
178
+ end
179
+ if options[:merchant_location_descriptor]
180
+ doc.merchant_location_descriptor(options[:merchant_location_descriptor])
181
+ end
182
+ end
183
+
184
+ def add_payment_method(doc, payment_method, options)
185
+ doc.retain_on_success(true) if options[:store]
186
+
187
+ if payment_method.is_a?(String)
188
+ doc.payment_method_token(payment_method)
189
+ elsif payment_method.is_a?(CreditCard)
190
+ add_credit_card(doc, payment_method, options)
191
+ elsif payment_method.is_a?(Check)
192
+ add_bank_account(doc, payment_method, options)
193
+ else
194
+ raise TypeError, 'Payment method not supported'
195
+ end
193
196
  end
194
197
 
195
198
  def add_credit_card(doc, credit_card, options)
@@ -210,6 +213,17 @@ module ActiveMerchant #:nodoc:
210
213
  end
211
214
  end
212
215
 
216
+ def add_bank_account(doc, bank_account, options)
217
+ doc.bank_account do
218
+ doc.first_name(bank_account.first_name)
219
+ doc.last_name(bank_account.last_name)
220
+ doc.bank_routing_number(bank_account.routing_number)
221
+ doc.bank_account_number(bank_account.account_number)
222
+ doc.bank_account_type(bank_account.account_type)
223
+ doc.bank_account_holder_type(bank_account.account_holder_type)
224
+ end
225
+ end
226
+
213
227
  def add_extra_options(type, doc, options)
214
228
  doc.send(type) do
215
229
  extra_options_to_doc(doc, options[type])
@@ -544,7 +544,7 @@ module ActiveMerchant #:nodoc:
544
544
  end
545
545
  end
546
546
  doc['v1'].addrLn1 billing_address[:address1] if billing_address[:address1]
547
- doc['v1'].addrLn2 billing_address[:address2] if billing_address[:address2]
547
+ doc['v1'].addrLn2 billing_address[:address2] unless billing_address[:address2].blank?
548
548
  doc['v1'].city billing_address[:city] if billing_address[:city]
549
549
  doc['v1'].state billing_address[:state] if billing_address[:state]
550
550
  doc['v1'].zipCode billing_address[:zip] if billing_address[:zip]
@@ -559,7 +559,7 @@ module ActiveMerchant #:nodoc:
559
559
  doc['v1'].ship do
560
560
  doc['v1'].fullName fullname unless fullname.blank?
561
561
  doc['v1'].addrLn1 shipping_address[:address1] if shipping_address[:address1]
562
- doc['v1'].addrLn2 shipping_address[:address2] if shipping_address[:address2]
562
+ doc['v1'].addrLn2 shipping_address[:address2] unless shipping_address[:address2].blank?
563
563
  doc['v1'].city shipping_address[:city] if shipping_address[:city]
564
564
  doc['v1'].state shipping_address[:state] if shipping_address[:state]
565
565
  doc['v1'].zipCode shipping_address[:zip] if shipping_address[:zip]
@@ -104,6 +104,8 @@ module ActiveMerchant #:nodoc:
104
104
  TEST_LOGIN = 'TestMerchant'
105
105
  TEST_PASSWORD = 'password'
106
106
 
107
+ VOIDABLE_ACTIONS = %w(preauth sale postauth credit)
108
+
107
109
  self.money_format = :cents
108
110
  self.supported_cardtypes = [:visa, :master, :discover, :american_express, :diners_club, :jcb]
109
111
  self.supported_countries = ['US']
@@ -179,9 +181,10 @@ module ActiveMerchant #:nodoc:
179
181
  # postauth, we preserve active_merchant's nomenclature of capture() for consistency with the rest of the library. To process
180
182
  # a postauthorization with TC, you need an amount in cents or a money object, and a TC transid.
181
183
  def capture(money, authorization, options = {})
184
+ transaction_id, _ = split_authorization(authorization)
182
185
  parameters = {
183
186
  :amount => amount(money),
184
- :transid => authorization,
187
+ :transid => transaction_id,
185
188
  }
186
189
  add_aggregator(parameters, options)
187
190
 
@@ -191,9 +194,10 @@ module ActiveMerchant #:nodoc:
191
194
  # refund() allows you to return money to a card that was previously billed. You need to supply the amount, in cents or a money object,
192
195
  # that you want to refund, and a TC transid for the transaction that you are refunding.
193
196
  def refund(money, identification, options = {})
197
+ transaction_id, _ = split_authorization(identification)
194
198
  parameters = {
195
199
  :amount => amount(money),
196
- :transid => identification
200
+ :transid => transaction_id
197
201
  }
198
202
  add_aggregator(parameters, options)
199
203
 
@@ -214,18 +218,24 @@ module ActiveMerchant #:nodoc:
214
218
  # TrustCommerce to allow for reversal transactions before you can use this
215
219
  # method.
216
220
  #
221
+ # void() is also used to to cancel a capture (postauth), purchase (sale),
222
+ # or refund (credit) or a before it is sent for settlement.
223
+ #
217
224
  # NOTE: AMEX preauth's cannot be reversed. If you want to clear it more
218
225
  # quickly than the automatic expiration (7-10 days), you will have to
219
226
  # capture it and then immediately issue a credit for the same amount
220
227
  # which should clear the customers credit card with 48 hours according to
221
228
  # TC.
222
229
  def void(authorization, options = {})
230
+ transaction_id, original_action = split_authorization(authorization)
231
+ action = (VOIDABLE_ACTIONS - ['preauth']).include?(original_action) ? 'void' : 'reversal'
232
+
223
233
  parameters = {
224
- :transid => authorization,
234
+ :transid => transaction_id,
225
235
  }
226
236
  add_aggregator(parameters, options)
227
237
 
228
- commit('reversal', parameters)
238
+ commit(action, parameters)
229
239
  end
230
240
 
231
241
  # recurring() a TrustCommerce account that is activated for Citadel, TrustCommerce's
@@ -416,7 +426,7 @@ module ActiveMerchant #:nodoc:
416
426
  message = message_from(data)
417
427
  Response.new(success, message, data,
418
428
  :test => test?,
419
- :authorization => data['transid'],
429
+ :authorization => authorization_from(action, data),
420
430
  :cvv_result => data['cvv'],
421
431
  :avs_result => { :code => data['avs'] }
422
432
  )
@@ -446,6 +456,15 @@ module ActiveMerchant #:nodoc:
446
456
  end
447
457
  end
448
458
 
459
+ def authorization_from(action, data)
460
+ authorization = data['transid']
461
+ authorization = "#{authorization}|#{action}" if authorization && VOIDABLE_ACTIONS.include?(action)
462
+ authorization
463
+ end
464
+
465
+ def split_authorization(authorization)
466
+ authorization.split('|')
467
+ end
449
468
  end
450
469
  end
451
470
  end