activemerchant 1.29.0 → 1.29.1

Sign up to get free protection for your applications and to get access to all the features.
data.tar.gz.sig CHANGED
Binary file
data/CHANGELOG CHANGED
@@ -1,5 +1,10 @@
1
1
  = ActiveMerchant CHANGELOG
2
2
 
3
+ == Version 1.29.1 (December 5, 2012)
4
+
5
+ * Add eWay Rapid 3.0 gateway [ntalbott]
6
+ * Fix AVS responses missing attributes [jduff]
7
+
3
8
  == Version 1.29.0 (November 30, 2012)
4
9
 
5
10
  * Authorize.Net gateway: Support description and order_id for capture [ntalbott]
data/CONTRIBUTORS CHANGED
@@ -353,3 +353,7 @@ A1Agregator (November 2012)
353
353
  Liqpay integration (November 2012)
354
354
 
355
355
  * beorc
356
+
357
+ eWay Rapid 3.0 gateway (December 2012)
358
+
359
+ * Nathaniel Talbott (ntalbott)
data/README.md CHANGED
@@ -100,6 +100,7 @@ The [ActiveMerchant Wiki](http://github.com/Shopify/active_merchant/wikis) conta
100
100
  * [Elavon MyVirtualMerchant](http://www.elavon.com) - US, CA
101
101
  * [ePay](http://www.epay.dk/) - DK, SE, NO
102
102
  * [eWAY](http://www.eway.com.au/) - AU
103
+ * [eWay Rapid 3.0](http://www.eway.com.au/) - AU
103
104
  * [E-xact](http://www.e-xact.com) - CA, US
104
105
  * [Fat Zebra](https://www.fatzebra.com.au) - AU
105
106
  * [Federated Canada](http://www.federatedcanada.com/) - CA
@@ -0,0 +1,300 @@
1
+ require "nokogiri"
2
+ require "cgi"
3
+
4
+ module ActiveMerchant #:nodoc:
5
+ module Billing #:nodoc:
6
+ class EwayRapidGateway < Gateway
7
+ self.test_url = "https://api.sandbox.ewaypayments.com/"
8
+ self.live_url = "https://api.ewaypayments.com/"
9
+
10
+ self.money_format = :cents
11
+ self.supported_countries = ["AU"]
12
+ self.supported_cardtypes = [:visa, :master, :american_express, :diners_club]
13
+ self.homepage_url = "http://www.eway.com.au/"
14
+ self.display_name = "eWAY Rapid 3.0"
15
+ self.default_currency = "AUD"
16
+
17
+ def initialize(options = {})
18
+ requires!(options, :login, :password)
19
+ super
20
+ end
21
+
22
+ # Public: Run a purchase transaction. Treats the Rapid 3.0 transparent
23
+ # redirect as an API endpoint in order to conform to the standard
24
+ # ActiveMerchant #purchase API.
25
+ #
26
+ # amount - The monetary amount of the transaction in cents.
27
+ # options - A standard ActiveMerchant options hash:
28
+ # :order_id - A merchant-supplied identifier for the
29
+ # transaction (optional).
30
+ # :description - A merchant-supplied description of the
31
+ # transaction (optional).
32
+ # :currency - Three letter currency code for the
33
+ # transaction (default: "AUD")
34
+ # :billing_address - Standard ActiveMerchant address hash
35
+ # (optional).
36
+ # :shipping_address - Standard ActiveMerchant address hash
37
+ # (optional).
38
+ # :ip - The ip of the consumer initiating the
39
+ # transaction (optional).
40
+ # :application_id - A string identifying the application
41
+ # submitting the transaction
42
+ # (default: "https://github.com/Shopify/active_merchant")
43
+ #
44
+ # Returns an ActiveMerchant::Billing::Response object
45
+ def purchase(amount, payment_method, options={})
46
+ MultiResponse.new.tap do |r|
47
+ # Rather than follow the redirect, we detect the 302 and capture the
48
+ # token out of the Location header in the run_purchase step. But we
49
+ # still need a placeholder url to pass to eWay, and that is what
50
+ # example.com is used for here.
51
+ r.process{setup_purchase(amount, options.merge(:redirect_url => "http://example.com/"))}
52
+ r.process{run_purchase(r.authorization, payment_method, r.params["formactionurl"])}
53
+ r.process{status(r.authorization)}
54
+ end
55
+ end
56
+
57
+ # Public: Acquire the token necessary to run a transparent redirect.
58
+ #
59
+ # amount - The monetary amount of the transaction in cents.
60
+ # options - A supplemented ActiveMerchant options hash:
61
+ # :redirect_url - The url to return the customer to after
62
+ # the transparent redirect is completed
63
+ # (required).
64
+ # :order_id - A merchant-supplied identifier for the
65
+ # transaction (optional).
66
+ # :description - A merchant-supplied description of the
67
+ # transaction (optional).
68
+ # :currency - Three letter currency code for the
69
+ # transaction (default: "AUD")
70
+ # :billing_address - Standard ActiveMerchant address hash
71
+ # (optional).
72
+ # :shipping_address - Standard ActiveMerchant address hash
73
+ # (optional).
74
+ # :ip - The ip of the consumer initiating the
75
+ # transaction (optional).
76
+ # :application_id - A string identifying the application
77
+ # submitting the transaction
78
+ # (default: "https://github.com/Shopify/active_merchant")
79
+ #
80
+ # Returns an EwayRapidResponse object, which conforms to the
81
+ # ActiveMerchant::Billing::Response API, but also exposes #form_url.
82
+ def setup_purchase(amount, options={})
83
+ requires!(options, :redirect_url)
84
+ request = build_xml_request("CreateAccessCodeRequest") do |doc|
85
+ add_metadata(doc, options)
86
+ add_invoice(doc, amount, options)
87
+ add_customer_data(doc, options)
88
+ end
89
+
90
+ commit(url_for("CreateAccessCode"), request)
91
+ end
92
+
93
+ # Public: Retrieve the status of a transaction.
94
+ #
95
+ # identification - The Eway Rapid 3.0 access code for the transaction
96
+ # (returned as the response.authorization by
97
+ # #setup_purchase).
98
+ #
99
+ # Returns an EwayRapidResponse object.
100
+ def status(identification)
101
+ request = build_xml_request("GetAccessCodeResultRequest") do |doc|
102
+ doc.AccessCode identification
103
+ end
104
+ commit(url_for("GetAccessCodeResult"), request)
105
+ end
106
+
107
+ private
108
+
109
+ def run_purchase(identification, payment_method, endpoint)
110
+ post = {
111
+ "accesscode" => identification
112
+ }
113
+ add_credit_card(post, payment_method)
114
+
115
+ commit_form(endpoint, build_form_request(post))
116
+ end
117
+
118
+ def add_metadata(doc, options)
119
+ doc.RedirectUrl(options[:redirect_url])
120
+ doc.CustomerIP options[:ip] if options[:ip]
121
+ doc.Method "ProcessPayment"
122
+ doc.DeviceID(options[:application_id] || application_id)
123
+ end
124
+
125
+ def add_invoice(doc, money, options)
126
+ doc.Payment do
127
+ doc.TotalAmount amount(money)
128
+ doc.InvoiceReference options[:order_id]
129
+ doc.InvoiceDescription options[:description]
130
+ currency_code = (options[:currency] || currency(money) || default_currency)
131
+ doc.CurrencyCode currency_code
132
+ end
133
+ end
134
+
135
+ def add_customer_data(doc, options)
136
+ doc.Customer do
137
+ add_address(doc, (options[:billing_address] || options[:address]), {:email => options[:email]})
138
+ end
139
+ doc.ShippingAddress do
140
+ add_address(doc, options[:shipping_address], {:skip_company => true})
141
+ end
142
+ end
143
+
144
+ def add_address(doc, address, options={})
145
+ return unless address
146
+ if name = address[:name]
147
+ parts = name.split(/\s+/)
148
+ doc.FirstName parts.shift if parts.size > 1
149
+ doc.LastName parts.join(" ")
150
+ end
151
+ doc.CompanyName address[:company] unless options[:skip_company]
152
+ doc.Street1 address[:address1]
153
+ doc.Street2 address[:address2]
154
+ doc.City address[:city]
155
+ doc.State address[:state]
156
+ doc.PostalCode address[:zip]
157
+ doc.Country address[:country]
158
+ doc.Phone address[:phone]
159
+ doc.Fax address[:fax]
160
+ doc.Email options[:email]
161
+ end
162
+
163
+ def add_credit_card(post, credit_card)
164
+ post["cardname"] = credit_card.name
165
+ post["cardnumber"] = credit_card.number
166
+ post["cardexpirymonth"] = credit_card.month
167
+ post["cardexpiryyear"] = credit_card.year
168
+ post["cardcvn"] = credit_card.verification_value
169
+ end
170
+
171
+ def build_xml_request(root)
172
+ builder = Nokogiri::XML::Builder.new
173
+ builder.__send__(root) do |doc|
174
+ yield(doc)
175
+ end
176
+ builder.to_xml
177
+ end
178
+
179
+ def build_form_request(post)
180
+ request = []
181
+ post.each do |key, value|
182
+ request << "EWAY_#{key.upcase}=#{CGI.escape(value.to_s)}"
183
+ end
184
+ request.join("&")
185
+ end
186
+
187
+ def url_for(action)
188
+ (test? ? test_url : live_url) + action + ".xml"
189
+ end
190
+
191
+ def commit(url, request, form_post=false)
192
+ headers = {
193
+ "Authorization" => ("Basic " + Base64.strict_encode64(@options[:login].to_s + ":" + @options[:password].to_s).chomp),
194
+ "Content-Type" => "text/xml"
195
+ }
196
+
197
+ raw = parse(ssl_post(url, request, headers))
198
+
199
+ succeeded = success?(raw)
200
+ EwayRapidResponse.new(
201
+ succeeded,
202
+ message_from(succeeded, raw),
203
+ raw,
204
+ :authorization => authorization_from(raw),
205
+ :test => test?,
206
+ :avs_result => avs_result_from(raw),
207
+ :cvv_result => cvv_result_from(raw)
208
+ )
209
+ rescue ActiveMerchant::ResponseError => e
210
+ return EwayRapidResponse.new(false, e.response.message, {:status_code => e.response.code}, :test => test?)
211
+ end
212
+
213
+ def commit_form(url, request)
214
+ http_response = raw_ssl_request(:post, url, request)
215
+
216
+ success = (http_response.code.to_s == "302")
217
+ message = (success ? "Succeeded" : http_response.body)
218
+ if success
219
+ authorization = CGI.unescape(http_response["Location"].split("=").last)
220
+ end
221
+ Response.new(success, message, {:location => http_response["Location"]}, :authorization => authorization, :test => test?)
222
+ end
223
+
224
+ def parse(xml)
225
+ response = {}
226
+
227
+ doc = Nokogiri::XML(xml)
228
+ doc.root.xpath("*").each do |node|
229
+ if (node.elements.size == 0)
230
+ response[node.name.downcase.to_sym] = node.text
231
+ else
232
+ node.elements.each do |childnode|
233
+ name = "#{node.name.downcase}_#{childnode.name.downcase}"
234
+ response[name.to_sym] = childnode.text
235
+ end
236
+ end
237
+ end unless doc.root.nil?
238
+
239
+ response
240
+ end
241
+
242
+ def success?(response)
243
+ if response[:errors]
244
+ false
245
+ elsif response[:transactionstatus]
246
+ (response[:transactionstatus] == "true")
247
+ else
248
+ true
249
+ end
250
+ end
251
+
252
+ def message_from(succeeded, response)
253
+ if response[:errors]
254
+ response[:errors]
255
+ elsif response[:responsecode]
256
+ ActiveMerchant::Billing::EwayGateway::MESSAGES[response[:responsecode]]
257
+ elsif response[:responsemessage]
258
+ response[:responsemessage]
259
+ elsif succeeded
260
+ "Succeeded"
261
+ else
262
+ "Failed"
263
+ end
264
+ end
265
+
266
+ def authorization_from(response)
267
+ response[:accesscode]
268
+ end
269
+
270
+ def avs_result_from(response)
271
+ code = case response[:verification_address]
272
+ when "Valid"
273
+ "M"
274
+ when "Invalid"
275
+ "N"
276
+ else
277
+ "I"
278
+ end
279
+ {:code => code}
280
+ end
281
+
282
+ def cvv_result_from(response)
283
+ case response[:verification_cvn]
284
+ when "Valid"
285
+ "M"
286
+ when "Invalid"
287
+ "N"
288
+ else
289
+ "P"
290
+ end
291
+ end
292
+
293
+ class EwayRapidResponse < ActiveMerchant::Billing::Response
294
+ def form_url
295
+ params["formactionurl"]
296
+ end
297
+ end
298
+ end
299
+ end
300
+ end
@@ -24,19 +24,17 @@ module ActiveMerchant #:nodoc:
24
24
  @authorization = options[:authorization]
25
25
  @fraud_review = options[:fraud_review]
26
26
 
27
- avs_result_builder = if options[:avs_result].kind_of?(Hash)
28
- AVSResult.new(options[:avs_result])
27
+ @avs_result = if options[:avs_result].kind_of?(AVSResult)
28
+ options[:avs_result].to_hash
29
29
  else
30
- options[:avs_result] || {}
30
+ AVSResult.new(options[:avs_result]).to_hash
31
31
  end
32
- @avs_result = avs_result_builder.to_hash
33
32
 
34
- cvv_result_builder = if options[:cvv_result].kind_of?(String)
35
- CVVResult.new(options[:cvv_result])
33
+ @cvv_result = if options[:cvv_result].kind_of?(CVVResult)
34
+ options[:cvv_result].to_hash
36
35
  else
37
- options[:cvv_result] || {}
36
+ CVVResult.new(options[:cvv_result]).to_hash
38
37
  end
39
- @cvv_result = cvv_result_builder.to_hash
40
38
  end
41
39
  end
42
40
 
@@ -1,3 +1,3 @@
1
1
  module ActiveMerchant
2
- VERSION = "1.29.0"
2
+ VERSION = "1.29.1"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activemerchant
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.29.0
4
+ version: 1.29.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -37,11 +37,11 @@ cert_chain:
37
37
  Z1BvU1BxN25rK3MyRlFVQko5VVpGSzFsZ016aG8vNGZaZ3pKd2J1K2NPOFNO
38
38
  dWFMUy9iagpoUGFTVHlWVTB5Q1Nudz09Ci0tLS0tRU5EIENFUlRJRklDQVRF
39
39
  LS0tLS0K
40
- date: 2012-11-30 00:00:00.000000000 Z
40
+ date: 2012-12-05 00:00:00.000000000 Z
41
41
  dependencies:
42
42
  - !ruby/object:Gem::Dependency
43
43
  name: activesupport
44
- requirement: &70188791610980 !ruby/object:Gem::Requirement
44
+ requirement: &70335632813660 !ruby/object:Gem::Requirement
45
45
  none: false
46
46
  requirements:
47
47
  - - ! '>='
@@ -49,10 +49,10 @@ dependencies:
49
49
  version: 2.3.14
50
50
  type: :runtime
51
51
  prerelease: false
52
- version_requirements: *70188791610980
52
+ version_requirements: *70335632813660
53
53
  - !ruby/object:Gem::Dependency
54
54
  name: i18n
55
- requirement: &70188791610560 !ruby/object:Gem::Requirement
55
+ requirement: &70335632813220 !ruby/object:Gem::Requirement
56
56
  none: false
57
57
  requirements:
58
58
  - - ! '>='
@@ -60,10 +60,10 @@ dependencies:
60
60
  version: '0'
61
61
  type: :runtime
62
62
  prerelease: false
63
- version_requirements: *70188791610560
63
+ version_requirements: *70335632813220
64
64
  - !ruby/object:Gem::Dependency
65
65
  name: money
66
- requirement: &70188791610100 !ruby/object:Gem::Requirement
66
+ requirement: &70335632812700 !ruby/object:Gem::Requirement
67
67
  none: false
68
68
  requirements:
69
69
  - - ! '>='
@@ -71,10 +71,10 @@ dependencies:
71
71
  version: '0'
72
72
  type: :runtime
73
73
  prerelease: false
74
- version_requirements: *70188791610100
74
+ version_requirements: *70335632812700
75
75
  - !ruby/object:Gem::Dependency
76
76
  name: builder
77
- requirement: &70188791609600 !ruby/object:Gem::Requirement
77
+ requirement: &70335632812180 !ruby/object:Gem::Requirement
78
78
  none: false
79
79
  requirements:
80
80
  - - ! '>='
@@ -82,10 +82,10 @@ dependencies:
82
82
  version: 2.0.0
83
83
  type: :runtime
84
84
  prerelease: false
85
- version_requirements: *70188791609600
85
+ version_requirements: *70335632812180
86
86
  - !ruby/object:Gem::Dependency
87
87
  name: json
88
- requirement: &70188791609100 !ruby/object:Gem::Requirement
88
+ requirement: &70335632811640 !ruby/object:Gem::Requirement
89
89
  none: false
90
90
  requirements:
91
91
  - - ! '>='
@@ -93,10 +93,10 @@ dependencies:
93
93
  version: 1.5.1
94
94
  type: :runtime
95
95
  prerelease: false
96
- version_requirements: *70188791609100
96
+ version_requirements: *70335632811640
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: active_utils
99
- requirement: &70188791608640 !ruby/object:Gem::Requirement
99
+ requirement: &70335632811140 !ruby/object:Gem::Requirement
100
100
  none: false
101
101
  requirements:
102
102
  - - ! '>='
@@ -104,10 +104,10 @@ dependencies:
104
104
  version: 1.0.2
105
105
  type: :runtime
106
106
  prerelease: false
107
- version_requirements: *70188791608640
107
+ version_requirements: *70335632811140
108
108
  - !ruby/object:Gem::Dependency
109
109
  name: nokogiri
110
- requirement: &70188791608260 !ruby/object:Gem::Requirement
110
+ requirement: &70335632810740 !ruby/object:Gem::Requirement
111
111
  none: false
112
112
  requirements:
113
113
  - - ! '>='
@@ -115,10 +115,10 @@ dependencies:
115
115
  version: '0'
116
116
  type: :runtime
117
117
  prerelease: false
118
- version_requirements: *70188791608260
118
+ version_requirements: *70335632810740
119
119
  - !ruby/object:Gem::Dependency
120
120
  name: rake
121
- requirement: &70188791607800 !ruby/object:Gem::Requirement
121
+ requirement: &70335632810240 !ruby/object:Gem::Requirement
122
122
  none: false
123
123
  requirements:
124
124
  - - ! '>='
@@ -126,10 +126,10 @@ dependencies:
126
126
  version: '0'
127
127
  type: :development
128
128
  prerelease: false
129
- version_requirements: *70188791607800
129
+ version_requirements: *70335632810240
130
130
  - !ruby/object:Gem::Dependency
131
131
  name: mocha
132
- requirement: &70188791607300 !ruby/object:Gem::Requirement
132
+ requirement: &70335632809700 !ruby/object:Gem::Requirement
133
133
  none: false
134
134
  requirements:
135
135
  - - ~>
@@ -137,10 +137,10 @@ dependencies:
137
137
  version: 0.11.3
138
138
  type: :development
139
139
  prerelease: false
140
- version_requirements: *70188791607300
140
+ version_requirements: *70335632809700
141
141
  - !ruby/object:Gem::Dependency
142
142
  name: rails
143
- requirement: &70188791606800 !ruby/object:Gem::Requirement
143
+ requirement: &70335632809180 !ruby/object:Gem::Requirement
144
144
  none: false
145
145
  requirements:
146
146
  - - ! '>='
@@ -148,10 +148,10 @@ dependencies:
148
148
  version: 2.3.14
149
149
  type: :development
150
150
  prerelease: false
151
- version_requirements: *70188791606800
151
+ version_requirements: *70335632809180
152
152
  - !ruby/object:Gem::Dependency
153
153
  name: thor
154
- requirement: &70188791606420 !ruby/object:Gem::Requirement
154
+ requirement: &70335632808760 !ruby/object:Gem::Requirement
155
155
  none: false
156
156
  requirements:
157
157
  - - ! '>='
@@ -159,7 +159,7 @@ dependencies:
159
159
  version: '0'
160
160
  type: :development
161
161
  prerelease: false
162
- version_requirements: *70188791606420
162
+ version_requirements: *70335632808760
163
163
  description: Active Merchant is a simple payment abstraction library used in and sponsored
164
164
  by Shopify. It is written by Tobias Luetke, Cody Fauser, and contributors. The aim
165
165
  of the project is to feel natural to Ruby users and to abstract as many parts as
@@ -208,6 +208,7 @@ files:
208
208
  - lib/active_merchant/billing/gateways/epay.rb
209
209
  - lib/active_merchant/billing/gateways/eway.rb
210
210
  - lib/active_merchant/billing/gateways/eway_managed.rb
211
+ - lib/active_merchant/billing/gateways/eway_rapid.rb
211
212
  - lib/active_merchant/billing/gateways/exact.rb
212
213
  - lib/active_merchant/billing/gateways/fat_zebra.rb
213
214
  - lib/active_merchant/billing/gateways/federated_canada.rb
metadata.gz.sig CHANGED
Binary file