activemerchant 1.95.0 → 1.96.0

Sign up to get free protection for your applications and to get access to all the features.
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