activemerchant 1.29.1 → 1.34.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 (92) hide show
  1. data/CHANGELOG +143 -0
  2. data/CONTRIBUTORS +43 -0
  3. data/README.md +59 -51
  4. data/lib/active_merchant/billing/check.rb +15 -14
  5. data/lib/active_merchant/billing/credit_card.rb +14 -5
  6. data/lib/active_merchant/billing/credit_card_formatting.rb +8 -8
  7. data/lib/active_merchant/billing/gateway.rb +2 -2
  8. data/lib/active_merchant/billing/gateways/authorize_net.rb +36 -8
  9. data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +17 -5
  10. data/lib/active_merchant/billing/gateways/balanced.rb +9 -3
  11. data/lib/active_merchant/billing/gateways/banwire.rb +15 -1
  12. data/lib/active_merchant/billing/gateways/barclays_epdq.rb +8 -1
  13. data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +7 -2
  14. data/lib/active_merchant/billing/gateways/beanstream.rb +26 -24
  15. data/lib/active_merchant/billing/gateways/blue_pay.rb +201 -187
  16. data/lib/active_merchant/billing/gateways/bogus.rb +1 -1
  17. data/lib/active_merchant/billing/gateways/braintree_blue.rb +7 -3
  18. data/lib/active_merchant/billing/gateways/card_stream_modern.rb +155 -0
  19. data/lib/active_merchant/billing/gateways/cc5.rb +156 -0
  20. data/lib/active_merchant/billing/gateways/cyber_source.rb +55 -22
  21. data/lib/active_merchant/billing/gateways/data_cash.rb +3 -3
  22. data/lib/active_merchant/billing/gateways/evo_ca.rb +308 -0
  23. data/lib/active_merchant/billing/gateways/eway.rb +114 -171
  24. data/lib/active_merchant/billing/gateways/eway_managed.rb +52 -22
  25. data/lib/active_merchant/billing/gateways/finansbank.rb +22 -0
  26. data/lib/active_merchant/billing/gateways/firstdata_e4.rb +314 -0
  27. data/lib/active_merchant/billing/gateways/garanti.rb +0 -4
  28. data/lib/active_merchant/billing/gateways/ideal_rabobank.rb +13 -2
  29. data/lib/active_merchant/billing/gateways/iridium.rb +8 -2
  30. data/lib/active_merchant/billing/gateways/litle.rb +354 -105
  31. data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +28 -7
  32. data/lib/active_merchant/billing/gateways/merchant_ware.rb +44 -9
  33. data/lib/active_merchant/billing/gateways/merchant_warrior.rb +190 -0
  34. data/lib/active_merchant/billing/gateways/moneris.rb +4 -6
  35. data/lib/active_merchant/billing/gateways/moneris_us.rb +1 -1
  36. data/lib/active_merchant/billing/gateways/nab_transact.rb +20 -3
  37. data/lib/active_merchant/billing/gateways/net_registry.rb +8 -3
  38. data/lib/active_merchant/billing/gateways/netaxept.rb +65 -117
  39. data/lib/active_merchant/billing/gateways/netbilling.rb +1 -0
  40. data/lib/active_merchant/billing/gateways/netpay.rb +223 -0
  41. data/lib/active_merchant/billing/gateways/ogone.rb +7 -5
  42. data/lib/active_merchant/billing/gateways/optimal_payment.rb +43 -18
  43. data/lib/active_merchant/billing/gateways/orbital.rb +190 -53
  44. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +12 -10
  45. data/lib/active_merchant/billing/gateways/payment_express.rb +62 -1
  46. data/lib/active_merchant/billing/gateways/paymill.rb +179 -0
  47. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +12 -7
  48. data/lib/active_merchant/billing/gateways/paypal/paypal_express_response.rb +14 -9
  49. data/lib/active_merchant/billing/gateways/paypal_express.rb +59 -18
  50. data/lib/active_merchant/billing/gateways/pin.rb +165 -0
  51. data/lib/active_merchant/billing/gateways/qbms.rb +3 -2
  52. data/lib/active_merchant/billing/gateways/quickpay.rb +66 -28
  53. data/lib/active_merchant/billing/gateways/sage/sage_bankcard.rb +16 -11
  54. data/lib/active_merchant/billing/gateways/sage/sage_core.rb +1 -1
  55. data/lib/active_merchant/billing/gateways/sage/sage_virtual_check.rb +21 -16
  56. data/lib/active_merchant/billing/gateways/sage.rb +10 -5
  57. data/lib/active_merchant/billing/gateways/sage_pay.rb +7 -0
  58. data/lib/active_merchant/billing/gateways/smart_ps.rb +1 -1
  59. data/lib/active_merchant/billing/gateways/spreedly_core.rb +233 -0
  60. data/lib/active_merchant/billing/gateways/stripe.rb +49 -21
  61. data/lib/active_merchant/billing/gateways/transnational.rb +239 -0
  62. data/lib/active_merchant/billing/gateways/usa_epay_advanced.rb +9 -4
  63. data/lib/active_merchant/billing/gateways/webpay.rb +8 -0
  64. data/lib/active_merchant/billing/gateways/wirecard.rb +15 -9
  65. data/lib/active_merchant/billing/gateways/worldpay.rb +60 -24
  66. data/lib/active_merchant/billing/integrations/direc_pay/status.rb +1 -1
  67. data/lib/active_merchant/billing/integrations/direc_pay.rb +1 -1
  68. data/lib/active_merchant/billing/integrations/dwolla/common.rb +23 -0
  69. data/lib/active_merchant/billing/integrations/dwolla/helper.rb +18 -6
  70. data/lib/active_merchant/billing/integrations/dwolla/notification.rb +16 -7
  71. data/lib/active_merchant/billing/integrations/dwolla/return.rb +16 -5
  72. data/lib/active_merchant/billing/integrations/dwolla.rb +5 -12
  73. data/lib/active_merchant/billing/integrations/notification.rb +13 -8
  74. data/lib/active_merchant/billing/integrations/payflow_link/helper.rb +19 -3
  75. data/lib/active_merchant/billing/integrations/paypal/notification.rb +39 -31
  76. data/lib/active_merchant/billing/integrations/payu_in/helper.rb +74 -0
  77. data/lib/active_merchant/billing/integrations/payu_in/notification.rb +167 -0
  78. data/lib/active_merchant/billing/integrations/payu_in/return.rb +53 -0
  79. data/lib/active_merchant/billing/integrations/payu_in.rb +43 -0
  80. data/lib/active_merchant/billing/integrations/pxpay/helper.rb +1 -0
  81. data/lib/active_merchant/billing/integrations/quickpay/helper.rb +13 -10
  82. data/lib/active_merchant/billing/integrations/quickpay/notification.rb +78 -15
  83. data/lib/active_merchant/billing/integrations/rbkmoney/helper.rb +23 -0
  84. data/lib/active_merchant/billing/integrations/rbkmoney/notification.rb +91 -0
  85. data/lib/active_merchant/billing/integrations/rbkmoney.rb +17 -0
  86. data/lib/active_merchant/billing/integrations/robokassa/common.rb +1 -1
  87. data/lib/active_merchant/billing/integrations/sage_pay_form/helper.rb +7 -3
  88. data/lib/active_merchant/billing/integrations/world_pay.rb +15 -8
  89. data/lib/active_merchant/version.rb +1 -1
  90. data.tar.gz.sig +0 -0
  91. metadata +124 -50
  92. metadata.gz.sig +0 -0
@@ -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
@@ -154,23 +154,25 @@ module ActiveMerchant #:nodoc:
154
154
 
155
155
  # Verify and transfer the specified amount.
156
156
  def purchase(money, payment_source, options = {})
157
- post = {}
157
+ post = {}
158
+ action = options[:action] || 'SAL'
158
159
  add_invoice(post, options)
159
160
  add_payment_source(post, payment_source, options)
160
161
  add_address(post, payment_source, options)
161
162
  add_customer_data(post, options)
162
163
  add_money(post, money, options)
163
- commit('SAL', post)
164
+ commit(action, post)
164
165
  end
165
166
 
166
167
  # Complete a previously authorized transaction.
167
168
  def capture(money, authorization, options = {})
168
- post = {}
169
+ post = {}
170
+ action = options[:action] || 'SAL'
169
171
  add_authorization(post, reference_from(authorization))
170
172
  add_invoice(post, options)
171
173
  add_customer_data(post, options)
172
174
  add_money(post, money, options)
173
- commit('SAL', post)
175
+ commit(action, post)
174
176
  end
175
177
 
176
178
  # Cancels a previously authorized transaction.
@@ -198,7 +200,7 @@ module ActiveMerchant #:nodoc:
198
200
 
199
201
  # Store a credit card by creating an Ogone Alias
200
202
  def store(payment_source, options = {})
201
- options.merge!(:alias_operation => 'BYOGONE') unless options.has_key?(:billing_id) || options.has_key?(:store)
203
+ options.merge!(:alias_operation => 'BYPSP') unless(options.has_key?(:billing_id) || options.has_key?(:store))
202
204
  response = authorize(1, payment_source, options)
203
205
  void(response.authorization) if response.success?
204
206
  response
@@ -90,7 +90,9 @@ module ActiveMerchant #:nodoc:
90
90
 
91
91
  Response.new(successful?(response), message_from(response), hash_from_xml(response),
92
92
  :test => test?,
93
- :authorization => authorization_from(response)
93
+ :authorization => authorization_from(response),
94
+ :avs_result => { :code => avs_result_from(response) },
95
+ :cvv_result => cvv_result_from(response)
94
96
  )
95
97
  end
96
98
 
@@ -108,7 +110,15 @@ module ActiveMerchant #:nodoc:
108
110
  end
109
111
 
110
112
  def authorization_from(response)
111
- REXML::XPath.first(response, '//confirmationNumber').text rescue nil
113
+ get_text_from_document(response, '//confirmationNumber')
114
+ end
115
+
116
+ def avs_result_from(response)
117
+ get_text_from_document(response, '//avsResponse')
118
+ end
119
+
120
+ def cvv_result_from(response)
121
+ get_text_from_document(response, '//cvdResponse')
112
122
  end
113
123
 
114
124
  def hash_from_xml(response)
@@ -138,6 +148,11 @@ module ActiveMerchant #:nodoc:
138
148
  xml.target!
139
149
  end
140
150
 
151
+ def get_text_from_document(document, node)
152
+ node = REXML::XPath.first(document, node)
153
+ node && node.text
154
+ end
155
+
141
156
  def cc_auth_request(money, opts)
142
157
  xml_document('ccAuthRequestV1') do |xml|
143
158
  build_merchant_account(xml, @options)
@@ -145,6 +160,7 @@ module ActiveMerchant #:nodoc:
145
160
  xml.amount(money/100.0)
146
161
  build_card(xml, opts)
147
162
  build_billing_details(xml, opts)
163
+ build_shipping_details(xml, opts)
148
164
  end
149
165
  end
150
166
 
@@ -235,24 +251,33 @@ module ActiveMerchant #:nodoc:
235
251
 
236
252
  def build_billing_details(xml, opts)
237
253
  xml.tag! 'billingDetails' do
238
- addr = opts[:billing_address]
239
254
  xml.tag! 'cardPayMethod', 'WEB'
240
- if addr[:name]
241
- xml.tag! 'firstName', CGI.escape(addr[:name].split(' ').first) # TODO: parse properly
242
- xml.tag! 'lastName' , CGI.escape(addr[:name].split(' ').last )
243
- end
244
- xml.tag! 'street' , CGI.escape(addr[:address1]) if addr[:address1].present?
245
- xml.tag! 'street2', CGI.escape(addr[:address2]) if addr[:address2].present?
246
- xml.tag! 'city' , CGI.escape(addr[:city] ) if addr[:city].present?
247
- if addr[:state].present?
248
- state_tag = %w(US CA).include?(addr[:country]) ? 'state' : 'region'
249
- xml.tag! state_tag, CGI.escape(addr[:state])
250
- end
251
- xml.tag! 'country', CGI.escape(addr[:country] ) if addr[:country].present?
252
- xml.tag! 'zip' , CGI.escape(addr[:zip] ) # this one's actually required
253
- xml.tag! 'phone' , CGI.escape(addr[:phone] ) if addr[:phone].present?
254
- #xml.tag! 'email' , ''
255
+ build_address(xml, opts[:billing_address], opts[:email])
256
+ end
257
+ end
258
+
259
+ def build_shipping_details(xml, opts)
260
+ xml.tag! 'shippingDetails' do
261
+ build_address(xml, opts[:shipping_address], opts[:email])
262
+ end if opts[:shipping_address].present?
263
+ end
264
+
265
+ def build_address(xml, addr, email=nil)
266
+ if addr[:name]
267
+ xml.tag! 'firstName', CGI.escape(addr[:name].split(' ').first) # TODO: parse properly
268
+ xml.tag! 'lastName' , CGI.escape(addr[:name].split(' ').last )
269
+ end
270
+ xml.tag! 'street' , CGI.escape(addr[:address1]) if addr[:address1].present?
271
+ xml.tag! 'street2', CGI.escape(addr[:address2]) if addr[:address2].present?
272
+ xml.tag! 'city' , CGI.escape(addr[:city] ) if addr[:city].present?
273
+ if addr[:state].present?
274
+ state_tag = %w(US CA).include?(addr[:country]) ? 'state' : 'region'
275
+ xml.tag! state_tag, CGI.escape(addr[:state])
255
276
  end
277
+ xml.tag! 'country', CGI.escape(addr[:country] ) if addr[:country].present?
278
+ xml.tag! 'zip' , CGI.escape(addr[:zip] ) if addr[:zip].present?
279
+ xml.tag! 'phone' , CGI.escape(addr[:phone] ) if addr[:phone].present?
280
+ xml.tag! 'email', CGI.escape(email) if email
256
281
  end
257
282
 
258
283
  def card_type(key)