activemerchant 1.29.3 → 1.30.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data.tar.gz.sig +0 -0
  2. data/CHANGELOG +39 -0
  3. data/CONTRIBUTORS +19 -0
  4. data/README.md +43 -41
  5. data/lib/active_merchant/billing/check.rb +15 -11
  6. data/lib/active_merchant/billing/credit_card.rb +5 -1
  7. data/lib/active_merchant/billing/credit_card_formatting.rb +8 -8
  8. data/lib/active_merchant/billing/gateway.rb +1 -1
  9. data/lib/active_merchant/billing/gateways/authorize_net.rb +9 -1
  10. data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +15 -4
  11. data/lib/active_merchant/billing/gateways/balanced.rb +9 -3
  12. data/lib/active_merchant/billing/gateways/banwire.rb +15 -1
  13. data/lib/active_merchant/billing/gateways/beanstream.rb +26 -24
  14. data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +6 -2
  15. data/lib/active_merchant/billing/gateways/braintree_blue.rb +5 -2
  16. data/lib/active_merchant/billing/gateways/cyber_source.rb +55 -22
  17. data/lib/active_merchant/billing/gateways/eway.rb +114 -171
  18. data/lib/active_merchant/billing/gateways/eway_managed.rb +52 -22
  19. data/lib/active_merchant/billing/gateways/firstdata_e4.rb +222 -0
  20. data/lib/active_merchant/billing/gateways/ideal_rabobank.rb +13 -2
  21. data/lib/active_merchant/billing/gateways/litle.rb +50 -19
  22. data/lib/active_merchant/billing/gateways/merchant_ware.rb +44 -9
  23. data/lib/active_merchant/billing/gateways/merchant_warrior.rb +190 -0
  24. data/lib/active_merchant/billing/gateways/moneris.rb +2 -4
  25. data/lib/active_merchant/billing/gateways/nab_transact.rb +20 -3
  26. data/lib/active_merchant/billing/gateways/netbilling.rb +1 -0
  27. data/lib/active_merchant/billing/gateways/netpay.rb +223 -0
  28. data/lib/active_merchant/billing/gateways/optimal_payment.rb +18 -3
  29. data/lib/active_merchant/billing/gateways/orbital.rb +9 -5
  30. data/lib/active_merchant/billing/gateways/payment_express.rb +62 -1
  31. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +1 -1
  32. data/lib/active_merchant/billing/gateways/paypal_express.rb +2 -0
  33. data/lib/active_merchant/billing/gateways/pin.rb +157 -0
  34. data/lib/active_merchant/billing/gateways/qbms.rb +3 -2
  35. data/lib/active_merchant/billing/gateways/quickpay.rb +66 -28
  36. data/lib/active_merchant/billing/gateways/sage_pay.rb +6 -0
  37. data/lib/active_merchant/billing/gateways/smart_ps.rb +1 -1
  38. data/lib/active_merchant/billing/gateways/spreedly_core.rb +235 -0
  39. data/lib/active_merchant/billing/gateways/stripe.rb +1 -0
  40. data/lib/active_merchant/billing/gateways/wirecard.rb +15 -9
  41. data/lib/active_merchant/billing/integrations/payflow_link/helper.rb +4 -1
  42. data/lib/active_merchant/billing/integrations/paypal/notification.rb +39 -31
  43. data/lib/active_merchant/billing/integrations/quickpay/helper.rb +13 -10
  44. data/lib/active_merchant/billing/integrations/quickpay/notification.rb +14 -14
  45. data/lib/active_merchant/version.rb +1 -1
  46. metadata +109 -49
  47. metadata.gz.sig +0 -0
@@ -1,7 +1,10 @@
1
1
  module ActiveMerchant #:nodoc:
2
2
  module Billing #:nodoc:
3
3
  class MerchantWareGateway < Gateway
4
+ class_attribute :v4_live_url
5
+
4
6
  self.live_url = self.test_url = 'https://ps1.merchantware.net/MerchantWARE/ws/RetailTransaction/TXRetail.asmx'
7
+ self.v4_live_url = 'https://ps1.merchantware.net/Merchantware/ws/RetailTransaction/v4/Credit.asmx'
5
8
 
6
9
  self.supported_countries = ['US']
7
10
  self.supported_cardtypes = [:visa, :master, :american_express, :discover]
@@ -12,13 +15,19 @@ module ActiveMerchant #:nodoc:
12
15
  "xmlns:xsd" => "http://www.w3.org/2001/XMLSchema",
13
16
  "xmlns:env" => "http://schemas.xmlsoap.org/soap/envelope/"
14
17
  }
18
+ ENV_NAMESPACES_V4 = { "xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance",
19
+ "xmlns:xsd" => "http://www.w3.org/2001/XMLSchema",
20
+ "xmlns:soap" => "http://schemas.xmlsoap.org/soap/envelope/"
21
+ }
22
+
15
23
  TX_NAMESPACE = "http://merchantwarehouse.com/MerchantWARE/Client/TransactionRetail"
24
+ TX_NAMESPACE_V4 = "http://schemas.merchantwarehouse.com/merchantware/40/Credit/"
16
25
 
17
26
  ACTIONS = {
18
27
  :purchase => "IssueKeyedSale",
19
28
  :authorize => "IssueKeyedPreAuth",
20
29
  :capture => "IssuePostAuth",
21
- :void => "IssueVoid",
30
+ :void => "VoidPreAuthorization",
22
31
  :credit => "IssueKeyedRefund",
23
32
  :reference_credit => "IssueRefundByReference"
24
33
  }
@@ -80,11 +89,10 @@ module ActiveMerchant #:nodoc:
80
89
  # * <tt>authorization</tt> - The authorization string returned from the initial authorization or purchase.
81
90
  def void(authorization, options = {})
82
91
  reference, options[:order_id] = split_reference(authorization)
83
-
84
- request = soap_request(:void) do |xml|
85
- add_reference(xml, reference)
92
+ request = v4_soap_request(:void) do |xml|
93
+ add_reference_token(xml, reference)
86
94
  end
87
- commit(:void, request)
95
+ commit(:void, request, true)
88
96
  end
89
97
 
90
98
  # Refund an amount back a cardholder
@@ -108,7 +116,6 @@ module ActiveMerchant #:nodoc:
108
116
  perform_reference_credit(money, reference, options)
109
117
  end
110
118
 
111
-
112
119
  private
113
120
 
114
121
  def soap_request(action)
@@ -125,6 +132,22 @@ module ActiveMerchant #:nodoc:
125
132
  xml.target!
126
133
  end
127
134
 
135
+ def v4_soap_request(action)
136
+ xml = Builder::XmlMarkup.new :indent => 2
137
+ xml.instruct!
138
+ xml.tag! "soap:Envelope", ENV_NAMESPACES_V4 do
139
+ xml.tag! "soap:Body" do
140
+ xml.tag! ACTIONS[:void], "xmlns" => TX_NAMESPACE_V4 do
141
+ xml.tag! "merchantName", @options[:name]
142
+ xml.tag! "merchantSiteId", @options[:login]
143
+ xml.tag! "merchantKey", @options[:password]
144
+ yield xml
145
+ end
146
+ end
147
+ end
148
+ xml.target!
149
+ end
150
+
128
151
  def build_purchase_request(action, money, credit_card, options)
129
152
  requires!(options, :order_id)
130
153
 
@@ -195,6 +218,10 @@ module ActiveMerchant #:nodoc:
195
218
  xml.tag! "strReferenceCode", reference
196
219
  end
197
220
 
221
+ def add_reference_token(xml, reference)
222
+ xml.tag! "token", reference
223
+ end
224
+
198
225
  def add_address(xml, options)
199
226
  if address = options[:billing_address] || options[:address]
200
227
  xml.tag! "strAVSStreetAddress", address[:address1]
@@ -258,11 +285,19 @@ module ActiveMerchant #:nodoc:
258
285
  response
259
286
  end
260
287
 
261
- def commit(action, request)
288
+ def soap_action(action, v4 = false)
289
+ v4 ? "#{TX_NAMESPACE_V4}#{ACTIONS[action]}" : "#{TX_NAMESPACE}/#{ACTIONS[action]}"
290
+ end
291
+
292
+ def url(v4 = false)
293
+ v4 ? v4_live_url : live_url
294
+ end
295
+
296
+ def commit(action, request, v4 = false)
262
297
  begin
263
- data = ssl_post(self.live_url, request,
298
+ data = ssl_post(url(v4), request,
264
299
  "Content-Type" => 'text/xml; charset=utf-8',
265
- "SOAPAction" => "http://merchantwarehouse.com/MerchantWARE/Client/TransactionRetail/#{ACTIONS[action]}"
300
+ "SOAPAction" => soap_action(action, v4)
266
301
  )
267
302
  response = parse(action, data)
268
303
  rescue ActiveMerchant::ResponseError => e
@@ -0,0 +1,190 @@
1
+ require 'digest/md5'
2
+ require 'rexml/document'
3
+
4
+ module ActiveMerchant #:nodoc:
5
+ module Billing #:nodoc:
6
+ class MerchantWarriorGateway < Gateway
7
+ TOKEN_TEST_URL = 'https://base.merchantwarrior.com/token/'
8
+ TOKEN_LIVE_URL = 'https://api.merchantwarrior.com/token/'
9
+
10
+ POST_TEST_URL = 'https://base.merchantwarrior.com/post/'
11
+ POST_LIVE_URL = 'https://api.merchantwarrior.com/post/'
12
+
13
+ self.supported_countries = ['AU']
14
+ self.supported_cardtypes = [:visa, :master, :american_express,
15
+ :diners_club, :discover]
16
+ self.homepage_url = 'http://www.merchantwarrior.com/'
17
+ self.display_name = 'MerchantWarrior'
18
+
19
+ self.money_format = :dollars
20
+ self.default_currency = 'AUD'
21
+
22
+ def initialize(options = {})
23
+ requires!(options, :merchant_uuid, :api_key, :api_passphrase)
24
+ super
25
+ end
26
+
27
+ def authorize(money, payment_method, options = {})
28
+ post = {}
29
+ add_amount(post, money, options)
30
+ add_product(post, options)
31
+ add_address(post, options)
32
+ add_payment_method(post, payment_method)
33
+ commit('processAuth', post)
34
+ end
35
+
36
+ def purchase(money, payment_method, options = {})
37
+ post = {}
38
+ add_amount(post, money, options)
39
+ add_product(post, options)
40
+ add_address(post, options)
41
+ add_payment_method(post, payment_method)
42
+ commit('processCard', post)
43
+ end
44
+
45
+ def capture(money, identification)
46
+ post = {}
47
+ add_amount(post, money, options)
48
+ add_transaction(post, identification)
49
+ post.merge!('captureAmount' => money.to_s)
50
+ commit('processCapture', post)
51
+ end
52
+
53
+ def refund(money, identification)
54
+ post = {}
55
+ add_amount(post, money, options)
56
+ add_transaction(post, identification)
57
+ post['refundAmount'] = money
58
+ commit('refundCard', post)
59
+ end
60
+
61
+ def store(creditcard, options = {})
62
+ post = {
63
+ 'cardName' => creditcard.name,
64
+ 'cardNumber' => creditcard.number,
65
+ 'cardExpiryMonth' => sprintf('%02d', creditcard.month),
66
+ 'cardExpiryYear' => sprintf('%02d', creditcard.year)
67
+ }
68
+ commit('addCard', post)
69
+ end
70
+
71
+ private
72
+
73
+ def add_transaction(post, identification)
74
+ post['transactionID'] = identification
75
+ end
76
+
77
+ def add_address(post, options)
78
+ return unless(address = options[:address])
79
+
80
+ post['customerName'] = address[:name]
81
+ post['customerCountry'] = address[:country]
82
+ post['customerState'] = address[:state]
83
+ post['customerCity'] = address[:city]
84
+ post['customerAddress'] = address[:address1]
85
+ post['customerPostCode'] = address[:zip]
86
+ end
87
+
88
+ def add_product(post, options)
89
+ post['transactionProduct'] = options[:transaction_product]
90
+ end
91
+
92
+ def add_payment_method(post, payment_method)
93
+ if payment_method.respond_to?(:number)
94
+ add_creditcard(post, payment_method)
95
+ else
96
+ add_token(post, payment_method)
97
+ end
98
+ end
99
+
100
+ def add_token(post, token)
101
+ post['cardID'] = token
102
+ end
103
+
104
+ def add_creditcard(post, creditcard)
105
+ post['paymentCardNumber'] = creditcard.number
106
+ post['paymentCardName'] = creditcard.name
107
+ post['paymentCardExpiry'] = creditcard.expiry_date.expiration.strftime("%m%y")
108
+ end
109
+
110
+ def add_amount(post, money, options)
111
+ currency = (options[:currency] || currency(money))
112
+
113
+ post['transactionAmount'] = money.to_s
114
+ post['transactionCurrency'] = currency
115
+ post['hash'] = verification_hash(money, currency)
116
+ end
117
+
118
+ def verification_hash(money, currency)
119
+ Digest::MD5.hexdigest(
120
+ (
121
+ @options[:api_passphrase].to_s +
122
+ @options[:merchant_uuid].to_s +
123
+ money.to_s +
124
+ currency
125
+ ).downcase
126
+ )
127
+ end
128
+
129
+ def parse(body)
130
+ xml = REXML::Document.new(body)
131
+
132
+ response = {}
133
+ xml.root.elements.to_a.each do |node|
134
+ parse_element(response, node)
135
+ end
136
+ response
137
+ end
138
+
139
+ def parse_element(response, node)
140
+ if node.has_elements?
141
+ node.elements.each{|element| parse_element(response, element)}
142
+ else
143
+ response[node.name.underscore.to_sym] = node.text
144
+ end
145
+ end
146
+
147
+ def commit(action, post)
148
+ add_auth(action, post)
149
+
150
+ response = parse(ssl_post(url_for(action, post), post_data(post)))
151
+
152
+ Response.new(
153
+ success?(response),
154
+ response[:response_message],
155
+ response,
156
+ :test => test?,
157
+ :authorization => (response[:card_id] || response[:transaction_id])
158
+ )
159
+ end
160
+
161
+ def add_auth(action, post)
162
+ post['merchantUUID'] = @options[:merchant_uuid]
163
+ post['apiKey'] = @options[:api_key]
164
+ unless token?(post)
165
+ post['method'] = action
166
+ end
167
+ end
168
+
169
+ def url_for(action, post)
170
+ if token?(post)
171
+ [(test? ? TOKEN_TEST_URL : TOKEN_LIVE_URL), action].join("/")
172
+ else
173
+ (test? ? POST_TEST_URL : POST_LIVE_URL)
174
+ end
175
+ end
176
+
177
+ def token?(post)
178
+ (post["cardID"] || post["cardName"])
179
+ end
180
+
181
+ def success?(response)
182
+ (response[:response_code] == '0')
183
+ end
184
+
185
+ def post_data(post)
186
+ post.collect{|k,v| "#{k}=#{CGI.escape(v.to_s)}" }.join("&")
187
+ end
188
+ end
189
+ end
190
+ end
@@ -70,15 +70,13 @@ module ActiveMerchant #:nodoc:
70
70
  commit 'completion', crediting_params(authorization, :comp_amount => amount(money))
71
71
  end
72
72
 
73
- # Voiding requires the original transaction ID and order ID of some open
74
- # transaction. Closed transactions must be refunded. Note that the only
75
- # methods which may be voided are +capture+ and +purchase+.
73
+ # Voiding cancels an open authorization.
76
74
  #
77
75
  # Concatenate your transaction number and order_id by using a semicolon
78
76
  # (';'). This is to keep the Moneris interface consistent with other
79
77
  # gateways. (See +capture+ for details.)
80
78
  def void(authorization, options = {})
81
- commit 'purchasecorrection', crediting_params(authorization)
79
+ capture(0, authorization, options)
82
80
  end
83
81
 
84
82
  # Performs a refund. This method requires that the original transaction
@@ -34,7 +34,7 @@ module ActiveMerchant #:nodoc:
34
34
  #Transactions currently accepted by NAB Transact XML API
35
35
  TRANSACTIONS = {
36
36
  :purchase => 0, #Standard Payment
37
- :credit => 4, #Refund
37
+ :refund => 4, #Refund
38
38
  :void => 6, #Client Reversal (Void)
39
39
  :authorization => 10, #Preauthorise
40
40
  :capture => 11 #Preauthorise Complete (Advice)
@@ -66,6 +66,10 @@ module ActiveMerchant #:nodoc:
66
66
  end
67
67
  end
68
68
 
69
+ def refund(money, authorization, options = {})
70
+ commit :refund, build_reference_request(money, authorization)
71
+ end
72
+
69
73
  def store(creditcard, options = {})
70
74
  requires!(options, :billing_id, :amount)
71
75
  commit_periodic(build_periodic_item(:addcrn, options[:amount], creditcard, options))
@@ -104,10 +108,23 @@ module ActiveMerchant #:nodoc:
104
108
  xml.target!
105
109
  end
106
110
 
111
+ def build_reference_request(money, reference)
112
+ xml = Builder::XmlMarkup.new
113
+
114
+ transaction_id, order_id, preauth_id, original_amount = reference.split('*')
115
+
116
+ xml.tag! 'amount', (money ? amount(money) : original_amount)
117
+ xml.tag! 'currency', options[:currency] || currency(money)
118
+ xml.tag! 'txnID', transaction_id
119
+ xml.tag! 'purchaseOrderNo', order_id
120
+ xml.tag! 'preauthID', preauth_id
121
+
122
+ xml.target!
123
+ end
124
+
107
125
  #Generate payment request XML
108
126
  # - API is set to allow multiple Txn's but currentlu only allows one
109
127
  # - txnSource = 23 - (XML)
110
-
111
128
  def build_request(action, body)
112
129
  xml = Builder::XmlMarkup.new
113
130
  xml.instruct!
@@ -210,7 +227,7 @@ module ActiveMerchant #:nodoc:
210
227
  end
211
228
 
212
229
  def authorization_from(response)
213
- response[:txn_id]
230
+ [response[:txn_id], response[:purchase_order_no], response[:preauth_id], response[:amount]].join('*')
214
231
  end
215
232
 
216
233
  def message_from(response)
@@ -177,6 +177,7 @@ module ActiveMerchant #:nodoc:
177
177
 
178
178
  def post_data(action, parameters = {})
179
179
  parameters[:account_id] = @options[:login]
180
+ parameters[:site_tag] = @options[:site_tag] if @options[:site_tag].present?
180
181
  parameters[:pay_type] = 'C'
181
182
  parameters[:tran_type] = TRANSACTIONS[action]
182
183
 
@@ -0,0 +1,223 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ #
4
+ # NETPAY Gateway
5
+ #
6
+ # Support for NETPAY's HTTP Connector payment gateway in Mexico.
7
+ #
8
+ # The gateway sends requests as HTTP POST and receives the response details
9
+ # in the HTTP header, making the process really rather simple.
10
+ #
11
+ # Support for calls to the authorize and capture methods have been included
12
+ # as per the Netpay manuals, however, your millage may vary with these
13
+ # methods. At the time of writing (January 2013) they were not fully
14
+ # supported by the production or test gateways. This situation is
15
+ # expected to change within a few weeks/months.
16
+ #
17
+ # Purchases can be cancelled (`#void`) only within 24 hours of the
18
+ # transaction. After this, a refund should be performed instead.
19
+ #
20
+ # In addition to the regular ActiveMerchant transaction options, NETPAY
21
+ # also supports a `:mode` parameter. This allows testing to be peformed
22
+ # in production and force specific results.
23
+ #
24
+ # * 'P' - Production
25
+ # * 'A' - Approved
26
+ # * 'D' - Declined
27
+ # * 'R' - Random (Approved or Declined)
28
+ # * 'T' - Test
29
+ #
30
+ # For example:
31
+ #
32
+ # response = @gateway.purchase(1000, card, :mode => 'D')
33
+ # response.success # false
34
+ #
35
+ class NetpayGateway < Gateway
36
+ self.test_url = 'http://200.57.87.243:8855'
37
+ self.live_url = 'https://suite.netpay.com.mx/acquirerprd'
38
+
39
+ # The countries the gateway supports merchants from as 2 digit ISO country codes
40
+ self.supported_countries = ['MX']
41
+
42
+ self.default_currency = 'MXN'
43
+
44
+ # The card types supported by the payment gateway
45
+ self.supported_cardtypes = [:visa, :master, :american_express, :diners_club]
46
+
47
+ # The homepage URL of the gateway
48
+ self.homepage_url = 'http://www.netpay.com.mx'
49
+
50
+ # The name of the gateway
51
+ self.display_name = 'NETPAY Gateway'
52
+
53
+ CURRENCY_CODES = {
54
+ "MXN" => '484'
55
+ }
56
+
57
+ # The header keys that we will provide in the response params hash
58
+ RESPONSE_KEYS = ['ResponseMsg', 'ResponseText', 'ResponseCode', 'TimeIn', 'TimeOut', 'AuthCode', 'OrderId', 'CardTypeName', 'MerchantId', 'IssuerAuthDate']
59
+
60
+ def initialize(options = {})
61
+ requires!(options, :store_id, :login, :password)
62
+ super
63
+ end
64
+
65
+ # Send an authorization request
66
+ def authorize(money, creditcard, options = {})
67
+ post = {}
68
+ add_invoice(post, options)
69
+ add_creditcard(post, creditcard)
70
+ add_customer_data(post, options)
71
+ add_amount(post, money, options)
72
+
73
+ commit('PreAuth', post, options)
74
+ end
75
+
76
+ # Capture an authorization
77
+ def capture(money, authorization, options = {})
78
+ post = {}
79
+ add_order_id(post, order_id_from(authorization))
80
+ add_amount(post, money, options)
81
+
82
+ commit('PostAuth', post, options)
83
+ end
84
+
85
+ # Cancel an auth/purchase within first 24 hours
86
+ def void(authorization, options = {})
87
+ post = {}
88
+ order_id, amount, currency = split_authorization(authorization)
89
+ add_order_id(post, order_id)
90
+ post['Total'] = (options[:amount] || amount)
91
+ post['CurrencyCode'] = currency
92
+
93
+ commit('Refund', post, options)
94
+ end
95
+
96
+ # Make a purchase.
97
+ def purchase(money, creditcard, options = {})
98
+ post = {}
99
+ add_invoice(post, options)
100
+ add_creditcard(post, creditcard)
101
+ add_customer_data(post, options)
102
+ add_amount(post, money, options)
103
+
104
+ commit('Auth', post, options)
105
+ end
106
+
107
+ # Perform a Credit transaction.
108
+ def refund(money, authorization, options = {})
109
+ post = {}
110
+ add_order_id(post, order_id_from(authorization))
111
+ add_amount(post, money, options)
112
+
113
+ #commit('Refund', post, options)
114
+ commit('Credit', post, options)
115
+ end
116
+
117
+ private
118
+
119
+ def add_login_data(post)
120
+ post['StoreId'] = @options[:store_id]
121
+ post['UserName'] = @options[:login]
122
+ post['Password'] = @options[:password]
123
+ end
124
+
125
+ def add_action(post, action, options)
126
+ post['ResourceName'] = action
127
+ post['ContentType'] = 'Transaction'
128
+ post['Mode'] = options[:mode] || 'P'
129
+ end
130
+
131
+ def add_order_id(post, order_id)
132
+ post['OrderId'] = order_id
133
+ end
134
+
135
+ def add_amount(post, money, options)
136
+ post['Total'] = amount(money)
137
+ post['CurrencyCode'] = currency_code(options[:currency] || currency(money))
138
+ end
139
+
140
+ def add_customer_data(post, options)
141
+ post['IPAddress'] = options[:ip] unless options[:ip].blank?
142
+ end
143
+
144
+ def add_invoice(post, options)
145
+ post['Comments'] = options[:description] if options[:description]
146
+ end
147
+
148
+ def add_creditcard(post, creditcard)
149
+ post['CardNumber'] = creditcard.number
150
+ post['ExpDate'] = expdate(creditcard)
151
+ post['CustomerName'] = creditcard.name
152
+ post['CVV2'] = creditcard.verification_value unless creditcard.verification_value.nil?
153
+ end
154
+
155
+ def build_authorization(request_params, response_params)
156
+ [response_params['OrderId'], request_params['Total'], request_params['CurrencyCode']].join('|')
157
+ end
158
+
159
+ def split_authorization(authorization)
160
+ order_id, amount, currency = authorization.split("|")
161
+ [order_id, amount, currency]
162
+ end
163
+
164
+ def order_id_from(authorization)
165
+ split_authorization(authorization).first
166
+ end
167
+
168
+ def expdate(credit_card)
169
+ year = sprintf("%.4i", credit_card.year)
170
+ month = sprintf("%.2i", credit_card.month)
171
+
172
+ "#{month}/#{year[-2..-1]}"
173
+ end
174
+
175
+ def url
176
+ test? ? test_url : live_url
177
+ end
178
+
179
+ def parse(response, request_params)
180
+ response_params = params_from_response(response)
181
+
182
+ success = (response_params['ResponseCode'] == '00')
183
+ message = response_params['ResponseText'] || response_params['ResponseMsg']
184
+ options = @options.merge(:test => test?,
185
+ :authorization => build_authorization(request_params, response_params))
186
+
187
+ Response.new(success, message, response_params, options)
188
+ end
189
+
190
+ def commit(action, parameters, options)
191
+ add_login_data(parameters)
192
+ add_action(parameters, action, options)
193
+
194
+ post = parameters.collect{|key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&")
195
+ parse(ssl_post(url, post), parameters)
196
+ end
197
+
198
+ # Override the regular handle response so we can access the headers
199
+ def handle_response(response)
200
+ case response.code.to_i
201
+ when 200...300
202
+ response
203
+ else
204
+ raise ResponseError.new(response)
205
+ end
206
+ end
207
+
208
+ # Return a hash containing all the useful, or informative values from netpay
209
+ def params_from_response(response)
210
+ params = {}
211
+ RESPONSE_KEYS.each do |k|
212
+ params[k] = response[k] unless response[k].to_s.empty?
213
+ end
214
+ params
215
+ end
216
+
217
+ def currency_code(currency)
218
+ return currency if currency =~ /^\d+$/
219
+ CURRENCY_CODES[currency]
220
+ end
221
+ end
222
+ end
223
+ end