activemerchant 1.13.0 → 1.14.0

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