activemerchant 1.13.0 → 1.14.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 (58) hide show
  1. data.tar.gz.sig +0 -0
  2. data/CHANGELOG +19 -0
  3. data/CONTRIBUTORS +14 -2
  4. data/README.rdoc +2 -0
  5. data/lib/active_merchant/billing/credit_card.rb +4 -4
  6. data/lib/active_merchant/billing/gateway.rb +1 -1
  7. data/lib/active_merchant/billing/gateways/authorize_net.rb +10 -5
  8. data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +133 -11
  9. data/lib/active_merchant/billing/gateways/barclays_epdq.rb +1 -1
  10. data/lib/active_merchant/billing/gateways/beanstream.rb +39 -2
  11. data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +64 -26
  12. data/lib/active_merchant/billing/gateways/bogus.rb +21 -3
  13. data/lib/active_merchant/billing/gateways/cyber_source.rb +5 -1
  14. data/lib/active_merchant/billing/gateways/data_cash.rb +1 -1
  15. data/lib/active_merchant/billing/gateways/efsnet.rb +1 -1
  16. data/lib/active_merchant/billing/gateways/epay.rb +5 -1
  17. data/lib/active_merchant/billing/gateways/eway.rb +4 -0
  18. data/lib/active_merchant/billing/gateways/eway_managed.rb +231 -0
  19. data/lib/active_merchant/billing/gateways/federated_canada.rb +6 -7
  20. data/lib/active_merchant/billing/gateways/first_pay.rb +7 -2
  21. data/lib/active_merchant/billing/gateways/iridium.rb +1 -1
  22. data/lib/active_merchant/billing/gateways/jetpay.rb +5 -2
  23. data/lib/active_merchant/billing/gateways/linkpoint.rb +6 -1
  24. data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +6 -4
  25. data/lib/active_merchant/billing/gateways/merchant_ware.rb +1 -1
  26. data/lib/active_merchant/billing/gateways/moneris.rb +1 -1
  27. data/lib/active_merchant/billing/gateways/netaxept.rb +6 -1
  28. data/lib/active_merchant/billing/gateways/ogone.rb +1 -1
  29. data/lib/active_merchant/billing/gateways/orbital.rb +317 -0
  30. data/lib/active_merchant/billing/gateways/orbital/orbital_soft_descriptors.rb +46 -0
  31. data/lib/active_merchant/billing/gateways/paybox_direct.rb +1 -1
  32. data/lib/active_merchant/billing/gateways/payflow.rb +1 -1
  33. data/lib/active_merchant/billing/gateways/payflow_express.rb +6 -1
  34. data/lib/active_merchant/billing/gateways/payment_express.rb +6 -1
  35. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +7 -2
  36. data/lib/active_merchant/billing/gateways/paypal/paypal_express_response.rb +11 -7
  37. data/lib/active_merchant/billing/gateways/plugnpay.rb +1 -1
  38. data/lib/active_merchant/billing/gateways/psigate.rb +1 -1
  39. data/lib/active_merchant/billing/gateways/qbms.rb +1 -1
  40. data/lib/active_merchant/billing/gateways/quantum.rb +6 -1
  41. data/lib/active_merchant/billing/gateways/quickpay.rb +6 -1
  42. data/lib/active_merchant/billing/gateways/realex.rb +196 -72
  43. data/lib/active_merchant/billing/gateways/sage_pay.rb +7 -2
  44. data/lib/active_merchant/billing/gateways/secure_pay_au.rb +38 -2
  45. data/lib/active_merchant/billing/gateways/smart_ps.rb +2 -2
  46. data/lib/active_merchant/billing/gateways/trust_commerce.rb +7 -2
  47. data/lib/active_merchant/billing/gateways/verifi.rb +1 -1
  48. data/lib/active_merchant/billing/gateways/worldpay.rb +280 -0
  49. data/lib/active_merchant/billing/integrations/moneybookers/helper.rb +0 -1
  50. data/lib/active_merchant/billing/integrations/return.rb +6 -1
  51. data/lib/active_merchant/billing/integrations/sage_pay_form/notification.rb +6 -0
  52. data/lib/active_merchant/billing/integrations/sage_pay_form/return.rb +5 -1
  53. data/lib/active_merchant/common/connection.rb +15 -0
  54. data/lib/active_merchant/common/posts_data.rb +2 -0
  55. data/lib/active_merchant/common/utils.rb +4 -0
  56. data/lib/active_merchant/version.rb +1 -1
  57. metadata +8 -4
  58. metadata.gz.sig +0 -0
@@ -7,10 +7,11 @@ module ActiveMerchant #:nodoc:
7
7
  SUCCESS_MESSAGE = "Bogus Gateway: Forced success"
8
8
  FAILURE_MESSAGE = "Bogus Gateway: Forced failure"
9
9
  ERROR_MESSAGE = "Bogus Gateway: Use CreditCard number 1 for success, 2 for exception and anything else for error"
10
- CREDIT_ERROR_MESSAGE = "Bogus Gateway: Use trans_id 1 for success, 2 for exception and anything else for error"
10
+ CREDIT_ERROR_MESSAGE = "Bogus Gateway: Use CreditCard number 1 for success, 2 for exception and anything else for error"
11
11
  UNSTORE_ERROR_MESSAGE = "Bogus Gateway: Use trans_id 1 for success, 2 for exception and anything else for error"
12
12
  CAPTURE_ERROR_MESSAGE = "Bogus Gateway: Use authorization number 1 for exception, 2 for error and anything else for success"
13
13
  VOID_ERROR_MESSAGE = "Bogus Gateway: Use authorization number 1 for exception, 2 for error and anything else for success"
14
+ REFUND_ERROR_MESSAGE = "Bogus Gateway: Use trans_id number 1 for exception, 2 for error and anything else for success"
14
15
 
15
16
  self.supported_countries = ['US']
16
17
  self.supported_cardtypes = [:bogus]
@@ -41,11 +42,28 @@ module ActiveMerchant #:nodoc:
41
42
  end
42
43
  end
43
44
 
44
- def credit(money, ident, options = {})
45
+ def credit(money, creditcard, options = {})
46
+ if creditcard.is_a?(String)
47
+ deprecated CREDIT_DEPRECATION_MESSAGE
48
+ return refund(money, creditcard, options)
49
+ end
50
+
45
51
  money = amount(money)
46
- case ident
52
+ case creditcard.number
47
53
  when '1'
54
+ Response.new(true, SUCCESS_MESSAGE, {:paid_amount => money}, :test => true )
55
+ when '2'
56
+ Response.new(false, FAILURE_MESSAGE, {:paid_amount => money, :error => FAILURE_MESSAGE }, :test => true)
57
+ else
48
58
  raise Error, CREDIT_ERROR_MESSAGE
59
+ end
60
+ end
61
+
62
+ def refund(money, ident, options = {})
63
+ money = amount(money)
64
+ case ident
65
+ when '1'
66
+ raise Error, REFUND_ERROR_MESSAGE
49
67
  when '2'
50
68
  Response.new(false, FAILURE_MESSAGE, {:paid_amount => money, :error => FAILURE_MESSAGE }, :test => true)
51
69
  else
@@ -128,10 +128,14 @@ module ActiveMerchant #:nodoc:
128
128
  commit(build_void_request(identification, options), options)
129
129
  end
130
130
 
131
- def credit(money, identification, options = {})
131
+ def refund(money, identification, options = {})
132
132
  commit(build_credit_request(money, identification, options), options)
133
133
  end
134
134
 
135
+ def credit(money, identification, options = {})
136
+ deprecated CREDIT_DEPRECATION_MESSAGE
137
+ refund(money, identification, options)
138
+ end
135
139
 
136
140
  # CyberSource requires that you provide line item information for tax calculations
137
141
  # If you do not have prices for each item or want to simplify the situation then pass in one fake line item that costs the subtotal of the order
@@ -139,7 +139,7 @@ module ActiveMerchant
139
139
  # * <tt>:address</tt>:: billing address for card
140
140
  def credit(money, reference_or_credit_card, options = {})
141
141
  if reference_or_credit_card.is_a?(String)
142
- warn CREDIT_DEPRECATION_MESSAGE
142
+ deprecated CREDIT_DEPRECATION_MESSAGE
143
143
  refund(money, reference_or_credit_card)
144
144
  else
145
145
  request = build_refund_request(money, reference_or_credit_card, options)
@@ -41,7 +41,7 @@ module ActiveMerchant #:nodoc:
41
41
 
42
42
  def credit(money, identification_or_credit_card, options = {})
43
43
  if identification_or_credit_card.is_a?(String)
44
- warn CREDIT_DEPRECATION_MESSAGE
44
+ deprecated CREDIT_DEPRECATION_MESSAGE
45
45
  # Perform authorization reversal
46
46
  refund(money, identification_or_credit_card, options)
47
47
  else
@@ -97,7 +97,7 @@ module ActiveMerchant #:nodoc:
97
97
  commit(:void, post)
98
98
  end
99
99
 
100
- def credit(money, identification, options = {})
100
+ def refund(money, identification, options = {})
101
101
  post = {}
102
102
 
103
103
  add_amount_without_currency(post, money)
@@ -106,6 +106,10 @@ module ActiveMerchant #:nodoc:
106
106
  commit(:credit, post)
107
107
  end
108
108
 
109
+ def credit(money, identification, options = {})
110
+ deprecated CREDIT_DEPRECATION_MESSAGE
111
+ refund(money, identification, options)
112
+ end
109
113
 
110
114
  private
111
115
 
@@ -272,6 +272,10 @@ module ActiveMerchant #:nodoc:
272
272
  end
273
273
  end
274
274
 
275
+ def test?
276
+ @options[:test] || super
277
+ end
278
+
275
279
  end
276
280
  end
277
281
  end
@@ -0,0 +1,231 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ class EwayManagedGateway < Gateway
4
+ TEST_URL = 'https://www.eway.com.au/gateway/ManagedPaymentService/test/managedCreditCardPayment.asmx'
5
+ LIVE_URL = 'https://www.eway.com.au/gateway/ManagedPaymentService/managedCreditCardPayment.asmx'
6
+
7
+ # The countries the gateway supports merchants from as 2 digit ISO country codes
8
+ self.supported_countries = ['AU']
9
+
10
+ # The card types supported by the payment gateway
11
+ self.supported_cardtypes = [:visa, :master]
12
+
13
+ self.default_currency = 'AUD'
14
+
15
+ #accepted money format
16
+ self.money_format = :cents
17
+
18
+ # The homepage URL of the gateway
19
+ self.homepage_url = 'http://www.eway.com.au/'
20
+
21
+ # The name of the gateway
22
+ self.display_name = 'eWay Managed Payments'
23
+
24
+ def initialize(options = {})
25
+ requires!(options, :login, :username, :password)
26
+ @options = options
27
+
28
+ # eWay returns 500 code for faults, which AM snaffles.
29
+ # So, we tell it to allow them.
30
+ @options[:ignore_http_status]=true
31
+ super
32
+ end
33
+
34
+ # add a new customer CC to your eway account and return unique ManagedCustomerID
35
+ # supports storing details required by eway see "add_creditcard" and "add_address"
36
+ def store(creditcard, options = {})
37
+ post = {}
38
+
39
+ # Handle our required fields
40
+ requires!(options, :billing_address)
41
+
42
+ # Handle eWay specific required fields.
43
+ billing_address = options[:billing_address]
44
+ eway_requires!(billing_address)
45
+
46
+ add_creditcard(post, creditcard)
47
+ add_address(post, billing_address)
48
+ add_misc_fields(post, billing_address)
49
+
50
+ commit("CreateCustomer", post)
51
+ end
52
+
53
+ def update(billing_id, creditcard, options={})
54
+ post = {}
55
+
56
+ # Handle our required fields
57
+ requires!(options, :billing_address)
58
+
59
+ # Handle eWay specific required fields.
60
+ billing_address = options[:billing_address]
61
+ eway_requires!(billing_address)
62
+
63
+ post[:managedCustomerID]=billing_id
64
+ add_creditcard(post, creditcard)
65
+ add_address(post, billing_address)
66
+ add_misc_fields(post, billing_address)
67
+
68
+ commit("UpdateCustomer", post)
69
+ end
70
+
71
+ #process payment for given amount from stored CC "ManagedCustomerID = billing_id"
72
+ def purchase(money, billing_id, options={})
73
+ post = {}
74
+ post[:managedCustomerID] = billing_id.to_s
75
+ post[:amount]=money
76
+
77
+ commit("ProcessPayment", post)
78
+ end
79
+
80
+ # TODO: eWay API also provides QueryCustomer
81
+ # TODO: eWay API also provides QueryPayment
82
+
83
+ def test?
84
+ @options[:test] || Base.gateway_mode == :test
85
+ end
86
+ private
87
+
88
+ def eway_requires!(hash)
89
+ raise ArgumentError.new("Missing eWay required parameter in `billing_address`: title") unless hash.has_key?(:title)
90
+ raise ArgumentError.new("Missing eWay required parameter in `billing_address`: country") unless hash.has_key?(:country)
91
+ end
92
+
93
+ def add_address(post, address)
94
+ post[:Address] = address[:address1].to_s
95
+ post[:Phone] = address[:phone].to_s
96
+ post[:PostCode] = address[:zip].to_s
97
+ post[:Suburb] = address[:city].to_s
98
+ post[:Country] = address[:country].to_s.downcase
99
+ post[:State] = address[:state].to_s
100
+ post[:Mobile] = address[:mobile].to_s
101
+ post[:Fax] = address[:fax].to_s
102
+ end
103
+
104
+ def add_misc_fields(post, options)
105
+ post[:CustomerRef]=options[:customer_ref].to_s
106
+ post[:Title]=options[:title]
107
+ post[:Company]=options[:company]
108
+ post[:JobDesc]=options[:job_desc]
109
+ post[:Email]=options[:email]
110
+ post[:URL]=options[:url]
111
+ end
112
+
113
+ # add credit card details to be stored by eway. NOTE eway requires "title" field
114
+ def add_creditcard(post, creditcard)
115
+ post[:CCNumber] = creditcard.number
116
+ post[:CCExpiryMonth] = sprintf("%.2i", creditcard.month)
117
+ post[:CCExpiryYear] = sprintf("%.4i", creditcard.year)[-2..-1]
118
+ post[:CCNameOnCard] = creditcard.name
119
+ post[:FirstName] = creditcard.first_name
120
+ post[:LastName] = creditcard.last_name
121
+ end
122
+
123
+ def parse(body)
124
+ reply = {}
125
+ xml = REXML::Document.new(body)
126
+ if root = REXML::XPath.first(xml, "//soap:Fault") then
127
+ reply=parse_fault(root)
128
+ else
129
+ if root = REXML::XPath.first(xml, '//ProcessPaymentResponse/ewayResponse') then
130
+ # Successful payment
131
+ reply=parse_purchase(root)
132
+ else
133
+ if root = REXML::XPath.first(xml, '//CreateCustomerResult') then
134
+ reply[:message]='OK'
135
+ reply[:CreateCustomerResult]=root.text
136
+ reply[:success]=true
137
+ else
138
+ if root = REXML::XPath.first(xml, '//UpdateCustomerResult') then
139
+ if root.text.downcase == 'true' then
140
+ reply[:message]='OK'
141
+ reply[:success]=true
142
+ else
143
+ # ERROR: This state should never occur. If there is a problem,
144
+ # a soap:Fault will be returned. The presence of this
145
+ # element always means a success.
146
+ raise StandardError, "Unexpected \"false\" in UpdateCustomerResult"
147
+ end
148
+ else
149
+ # ERROR: This state should never occur currently. We have handled
150
+ # responses for all the methods which we support.
151
+ raise StandardError, "Unexpected response"
152
+ end
153
+ end
154
+ end
155
+ end
156
+ return reply
157
+ end
158
+
159
+ def parse_fault(node)
160
+ reply={}
161
+ reply[:message]=REXML::XPath.first(node, '//soap:Reason/soap:Text').text
162
+ reply[:success]=false
163
+ reply
164
+ end
165
+
166
+ def parse_purchase(node)
167
+ reply={}
168
+ reply[:message]=REXML::XPath.first(node, '//ewayTrxnError').text
169
+ reply[:success]=(REXML::XPath.first(node, '//ewayTrxnStatus').text == 'True')
170
+ reply[:auth_code]=REXML::XPath.first(node, '//ewayAuthCode').text
171
+ reply
172
+ end
173
+
174
+ def commit(action, post)
175
+ raw = begin
176
+ ssl_post(test? ? TEST_URL : LIVE_URL, soap_request(post, action), 'Content-Type' => 'application/soap+xml; charset=utf-8')
177
+ rescue ResponseError => e
178
+ e.response.body
179
+ end
180
+ response = parse(raw)
181
+
182
+ EwayResponse.new(response[:success], response[:message], response,
183
+ :test => test?,
184
+ :authorization => response[:auth_code]
185
+ )
186
+ end
187
+
188
+ # Where we build the full SOAP 1.2 request using builder
189
+ def soap_request(arguments, action)
190
+ # eWay demands all fields be sent, but contain an empty string if blank
191
+ post=default_fields.merge(arguments)
192
+
193
+ xml = Builder::XmlMarkup.new :indent => 2
194
+ xml.instruct!
195
+ xml.tag! 'soap12:Envelope', {'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', 'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema', 'xmlns:soap12' => 'http://www.w3.org/2003/05/soap-envelope'} do
196
+ xml.tag! 'soap12:Header' do
197
+ xml.tag! 'eWAYHeader', {'xmlns' => 'https://www.eway.com.au/gateway/managedpayment'} do
198
+ xml.tag! 'eWAYCustomerID', @options[:login]
199
+ xml.tag! 'Username', @options[:username]
200
+ xml.tag! 'Password', @options[:password]
201
+ end
202
+ end
203
+ xml.tag! 'soap12:Body' do |x|
204
+ x.tag! "#{action}", {'xmlns' => 'https://www.eway.com.au/gateway/managedpayment'} do |y|
205
+ post.each do |key, value|
206
+ y.tag! "#{key}", "#{value}"
207
+ end
208
+ end
209
+ end
210
+ end
211
+ xml.target!
212
+ end
213
+
214
+ def default_fields
215
+ hash={}
216
+ %w( CustomerRef Title FirstName LastName Company JobDesc Email Address Suburb State PostCode Country Phone Mobile Fax URL Comments CCNumber CCNameOnCard CCExpiryMonth CCExpiryYear ).each do |field|
217
+ hash[field.to_sym]=''
218
+ end
219
+ return hash
220
+ end
221
+
222
+ class EwayResponse < Response
223
+ # add a method to response so we can easily get the eway token "ManagedCustomerID"
224
+ def token
225
+ @params['CreateCustomerResult']
226
+ end
227
+ end
228
+
229
+ end
230
+ end
231
+ end
@@ -49,19 +49,18 @@ module ActiveMerchant #:nodoc:
49
49
  commit('capture', money, options)
50
50
  end
51
51
 
52
- def credit(money, identification, options = {}) # also referred to as refund
53
- post = { :transactionid => identification}
54
- commit('refund', money, post)
55
- end
56
-
57
52
  def void(authorization, options = {})
58
53
  options[:transactionid] = authorization
59
54
  commit('void', nil, options)
60
55
  end
61
56
 
62
57
  def refund(money, authorization, options = {})
63
- options[:transactionid] = authorization
64
- commit('refund', money, options)
58
+ commit('refund', money, options.merge(:transactionid => authorization))
59
+ end
60
+
61
+ def credit(money, authorization, options = {})
62
+ deprecated CREDIT_DEPRECATION_MESSAGE
63
+ refund(money, authorization, options)
65
64
  end
66
65
 
67
66
  private
@@ -47,8 +47,8 @@ module ActiveMerchant #:nodoc:
47
47
  commit('sale', money, post)
48
48
  end
49
49
 
50
- def credit(money, reference, options = {})
51
- raise ArgumentError, "Both TransactionID and CreditCard are required" unless reference.is_a?(String) && options[:credit_card]
50
+ def refund(money, reference, options = {})
51
+ requires!(options, :credit_card)
52
52
 
53
53
  post = FirstPayPostData.new
54
54
  add_invoice(post, options)
@@ -59,6 +59,11 @@ module ActiveMerchant #:nodoc:
59
59
 
60
60
  commit('credit', money, post)
61
61
  end
62
+
63
+ def credit(money, reference, options = {})
64
+ deprecated CREDIT_DEPRECATION_MESSAGE
65
+ refund(money, reference, options)
66
+ end
62
67
 
63
68
  def void(money, creditcard, options = {})
64
69
  post = FirstPayPostData.new
@@ -59,7 +59,7 @@ module ActiveMerchant #:nodoc:
59
59
  end
60
60
 
61
61
  def credit(money, authorization, options={})
62
- warn CREDIT_DEPRECATION_MESSAGE
62
+ deprecated CREDIT_DEPRECATION_MESSAGE
63
63
  refund(money, authorization, options)
64
64
  end
65
65
 
@@ -58,7 +58,8 @@ module ActiveMerchant #:nodoc:
58
58
  "025" => "Transaction Not Found.",
59
59
  "981" => "AVS Error.",
60
60
  "913" => "Invalid Card Type.",
61
- "996" => "Terminal ID Not Found."
61
+ "996" => "Terminal ID Not Found.",
62
+ nil => "No response returned (missing credentials?)."
62
63
  }
63
64
 
64
65
  def initialize(options = {})
@@ -86,7 +87,7 @@ module ActiveMerchant #:nodoc:
86
87
 
87
88
  def credit(money, transaction_id_or_card, options = {})
88
89
  if transaction_id_or_card.is_a?(String)
89
- warn CREDIT_DEPRECATION_MESSAGE
90
+ deprecated CREDIT_DEPRECATION_MESSAGE
90
91
  refund(money, transaction_id_or_card, options)
91
92
  else
92
93
  commit(money, build_credit_request('CREDIT', money, nil, transaction_id_or_card))
@@ -180,6 +181,8 @@ module ActiveMerchant #:nodoc:
180
181
  end
181
182
 
182
183
  def parse(body)
184
+ return {} if body.blank?
185
+
183
186
  xml = REXML::Document.new(body)
184
187
 
185
188
  response = {}
@@ -233,13 +233,18 @@ module ActiveMerchant #:nodoc:
233
233
  #
234
234
  # identification must be a valid order id previously submitted by SALE
235
235
  #
236
- def credit(money, identification, options = {})
236
+ def refund(money, identification, options = {})
237
237
  options.update(
238
238
  :ordertype => "CREDIT",
239
239
  :order_id => identification
240
240
  )
241
241
  commit(money, nil, options)
242
242
  end
243
+
244
+ def credit(money, identification, options = {})
245
+ deprecated CREDIT_DEPRECATION_MESSAGE
246
+ refund(money, identification, options)
247
+ end
243
248
 
244
249
  def test?
245
250
  @options[:test] || super