smulube-activemerchant 1.5.1 → 1.5.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,75 +1,376 @@
1
1
  module ActiveMerchant #:nodoc:
2
2
  module Billing #:nodoc:
3
3
  class PayflowNvpUkGateway < Gateway
4
- TEST_URL = 'https://example.com/test'
5
- LIVE_URL = 'https://example.com/live'
4
+ TEST_URL = 'https://pilot-payflowpro.paypal.com'
5
+ LIVE_URL = 'https://payflowpro.paypal.com'
6
+
7
+ self.class_inheritable_accessor :partner
8
+ self.class_inheritable_accessor :timeout
9
+
10
+ # Enable safe retry of failed connections
11
+ # Payflow is safe to retry because retried transactions use the same
12
+ # X-VPS-Request-ID header. If a transaction is detected as a duplicate
13
+ # only the original transaction data will be used by Payflow, and the
14
+ # subsequent Responses will have a :duplicate parameter set in the params
15
+ # hash.
16
+ self.retry_safe = true
6
17
 
7
18
  # The countries the gateway supports merchants from as 2 digit ISO country codes
8
- self.supported_countries = ['US']
19
+ self.supported_countries = ['GB']
9
20
 
10
21
  # The card types supported by the payment gateway
11
- self.supported_cardtypes = [:visa, :master, :american_express, :discover]
22
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover, :solo, :switch]
12
23
 
13
24
  # The homepage URL of the gateway
14
- self.homepage_url = 'http://www.example.net/'
25
+ self.homepage_url = 'https://www.paypal.com/uk/cgi-bin/webscr?cmd=_wp-pro-overview-outside'
15
26
 
16
27
  # The name of the gateway
17
- self.display_name = 'New Gateway'
28
+ self.display_name = 'PayPal Website Payments Pro (UK) [NVP API]'
18
29
 
30
+ self.default_currency = 'GBP'
31
+ self.partner = 'PayPalUk'
32
+ self.money_format = :dollars
33
+
34
+ TRANSACTIONS = {
35
+ :purchase => "S",
36
+ :authorization => "A",
37
+ :capture => "D",
38
+ :void => "V",
39
+ :credit => "C",
40
+ :recurring => "R"
41
+ }
42
+
43
+ PERIODS = {
44
+ :daily => "EDAY",
45
+ :weekly => "WEEK",
46
+ :biweekly => "BIWK",
47
+ :semimonthly => "SMMO",
48
+ :quadweekly => "FRWK",
49
+ :monthly => "MONT",
50
+ :quarterly => "QTER",
51
+ :semiyearly => "SMYR",
52
+ :yearly => "YEAR"
53
+ }
54
+
55
+ RECURRING_ACTIONS = {
56
+ :create => "A",
57
+ :modify => "M",
58
+ :deactivate => "C",
59
+ :reactivate => "R",
60
+ :inquiry => "I"
61
+ }
62
+
63
+ # Creates a new PayflowNvpUkGateway
64
+ #
65
+ # The gateway requires that a valid login and password be passed
66
+ # in the +options+ hash.
67
+ #
68
+ # ==== Parameters
69
+ #
70
+ # * <tt>options</tt>
71
+ # * <tt>:login</tt> - Your Payflow login
72
+ # * <tt>:password</tt> - Your Payflow password
19
73
  def initialize(options = {})
20
- #requires!(options, :login, :password)
74
+ requires!(options, :login, :password)
21
75
  @options = options
76
+ @options[:partner] = partner if @options[:partner].blank?
22
77
  super
23
- end
24
-
78
+ end
79
+
80
+
81
+ # Is the gateway in test mode?
82
+ def test?
83
+ @options[:test] || super
84
+ end
85
+
86
+ # Performs an authorization transaction. This is required due to Visa and
87
+ # Mastercard restrictions, in that a customer's card cannot be charged
88
+ # until the goods have been dispatched. An authorization allows an amout
89
+ # to be reserved on a customer's card, bringing down the available
90
+ # balance or credit, but they are not actually charged until a subsequent
91
+ # capture step actually captures the funds.
92
+ #
93
+ # ==== Parameters
94
+ #
95
+ # * <tt>money</tt> - The amount to be charged as an integer value in cents.
96
+ # * <tt>creditcard</tt> - The CreditCard object to be used as a funding source for the transaction.
97
+ # * <tt>options</tt> - A hash of optional parameters
98
+ # * <tt>:order_id</tt> - A unique reference for this order (maximum of 127 characters).
99
+ # * <tt>:email</tt> - The customer's email address
100
+ # * <tt>:customer</tt> - A unique reference for the customer (maximum of 12 characters).
101
+ # * <tt>:ip</tt> - The customer's IP address
102
+ # * <tt>:currency</tt> - The currency of the transaction. If present must be one of { AUD, CAD, EUR, JPY, GBP or USD }. If omitted the default currency is used.
103
+ # * <tt>:billing_address</tt> - The customer's billing address as a hash of address information.
104
+ # * <tt>:address1</tt> - The billing address street
105
+ # * <tt>:city</tt> - The billing address city
106
+ # * <tt>:state</tt> - The billing address state
107
+ # * <tt>:country</tt> - The 2 digit ISO billing address country code
108
+ # * <tt>:zip</tt> - The billing address zip code
109
+ # * <tt>:shipping_address</tt> - The customer's shipping address as a hash of address information.
110
+ # * <tt>:address1</tt> - The shipping address street
111
+ # * <tt>:city</tt> - The shipping address city
112
+ # * <tt>:state</tt> - The shipping address state code
113
+ # * <tt>:country</tt> - The 2 digit ISO shipping address country code
114
+ # * <tt>:zip</tt> - The shipping address zip code
25
115
  def authorize(money, creditcard, options = {})
26
116
  post = {}
27
117
  add_invoice(post, options)
28
118
  add_creditcard(post, creditcard)
29
- add_address(post, creditcard, options)
119
+ add_currency(post, money, options)
120
+ add_address(post, options[:billing_address] || options[:address])
121
+ add_address(post, options[:shipping_address], "shipto")
30
122
  add_customer_data(post, options)
31
123
 
32
- commit('authonly', money, post)
124
+ commit(TRANSACTIONS[:authorize], money, post)
33
125
  end
34
126
 
127
+ # A purchase transaction authorizes and captures in a single hit. We can only
128
+ # do this for transactions where you provide immediate fulfillment of products or services.
129
+ #
130
+ # ==== Parameters
131
+ #
132
+ # * <tt>money</tt> - The amount to be charged as an integer value in cents.
133
+ # * <tt>creditcard</tt> - The CreditCard object to be used as a funding source for the transaction.
134
+ # * <tt>options</tt> - A hash of optional parameters
135
+ # * <tt>:order_id</tt> - A unique reference for this order (maximum of 127 characters).
136
+ # * <tt>:email</tt> - The customer's email address
137
+ # * <tt>:customer</tt> - A unique reference for the customer (maximum of 12 characters).
138
+ # * <tt>:ip</tt> - The customer's IP address
139
+ # * <tt>:currency</tt> - The currency of the transaction. If present must be one of { AUD, CAD, EUR, JPY, GBP or USD }. If ommitted the default currency is used.
140
+ # * <tt>:billing_address</tt> - The customer's billing address as a hash of address information.
141
+ # * <tt>:address1</tt> - The billing address street
142
+ # * <tt>:city</tt> - The billing address city
143
+ # * <tt>:state</tt> - The billing address state
144
+ # * <tt>:country</tt> - The 2 digit ISO billing address country code
145
+ # * <tt>:zip</tt> - The billing address zip code
146
+ # * <tt>:shipping_address</tt> - The customer's shipping address as a hash of address information.
147
+ # * <tt>:address1</tt> - The shipping address street
148
+ # * <tt>:city</tt> - The shipping address city
149
+ # * <tt>:state</tt> - The shipping address state code
150
+ # * <tt>:country</tt> - The 2 digit ISO shipping address country code
151
+ # * <tt>:zip</tt> - The shipping address zip code
35
152
  def purchase(money, creditcard, options = {})
36
153
  post = {}
37
154
  add_invoice(post, options)
38
155
  add_creditcard(post, creditcard)
39
- add_address(post, creditcard, options)
156
+ add_currency(post, money, options)
157
+ add_address(post, options[:billing_address] || options[:address])
158
+ add_address(post, options[:shipping_address], "shipto")
40
159
  add_customer_data(post, options)
41
160
 
42
- commit('sale', money, post)
161
+ commit(TRANSACTIONS[:purchase], money, post)
43
162
  end
44
163
 
164
+ # Captures authorized funds.
165
+ #
166
+ # ==== Parameters
167
+ #
168
+ # * <tt>money</tt> - The amount to be authorized as an integer value in cents. Payflow does support changing the captured amount, so whatever is passed here will be captured.
169
+ # * <tt>authorization</tt> - The authorization reference string returned by the original transaction's Response#authorization.
170
+ # * <tt>options</tt> - not currently used.
45
171
  def capture(money, authorization, options = {})
46
- commit('capture', money, post)
172
+ post = {}
173
+ post[:origid] = authorization
174
+
175
+ commit(TRANSACTIONS[:capture], money, post)
176
+ end
177
+
178
+ # Voids an authorization or delayed capture
179
+ #
180
+ # ==== Parameters
181
+ #
182
+ # * <tt>authorization</tt> - The authorization reference string returned by the original transaction's Response#authorization.
183
+ # * <tt>options</tt> - Not currently used.
184
+ def void(authorization, options = {})
185
+ post = {}
186
+ post[:origid] = authorization
187
+
188
+ commit(TRANSACTIONS[:void], nil, post)
189
+ end
190
+
191
+ # Process a refund to a customer.
192
+ #
193
+ # ==== Parameters
194
+ # * <tt>money</tt> - The amount to be credited as an integer value in cents.
195
+ # * <tt>authorization_or_card</tt> - The CreditCard you want to refund to OR the PayPal PNRef of a previous transaction. It depends on the settings in your PayPal account as to whether non referenced credits are permitted. The default is that they are not.
196
+ # * <tt>options</tt> - not currently used
197
+ def credit(money, authorization_or_card, options = {})
198
+ post = {}
199
+
200
+ if authorization_or_card.is_a?(String)
201
+ # perform a referenced credit
202
+ post[:origid] = authorization
203
+ else
204
+ # perform an unreferenced credit
205
+ add_creditcard(post, creditcard)
206
+ end
207
+
208
+ commit(TRANSACTIONS[:credit], money, post)
209
+ end
210
+
211
+ # Create or modify a recurring profile.
212
+ #
213
+ # ==== Parameters
214
+ #
215
+ # * <tt>money</tt> - The amount that the recurring profile is to be set up for as an integer value in cents.
216
+ # * <tt>creditcard</tt> - The CreditCard object to be used as a funding source for the recurring profile.
217
+ # * <tt>options</tt> - A hash of parameters (some optional).
218
+ # * <tt>:profile_id</tt> - If present then we are modifying an existing profile, and this :profile_id identifies the profile we want to amend. If not present then we are creating a new recurring payments profile.
219
+ # * <tt>:starting_at</tt> - Takes a Date, Time or string in MMDDYYYY format. The date must be in the future.
220
+ # * <tt>:name</tt> - The name of the customer to be billed. If omitted the name from the creditcard is used.
221
+ # * <tt>:periodicity</tt> - The frequency that the recurring payments will occur at. Can be one of: [:daily, :weekly, :biweekly (every 2 weeks), :semimonthly (twice every month), :quadweekly (once every 4 weeks), :monthly (every month on the same date as the first payment), :quarterly (every 3 months on the same date as the first payment), :semiyearly (every 6 months on the same date as the first payment), :yearly.
222
+ # * <tt>:payments</tt> - Integer value describing the number of payments to be made.
223
+ # * <tt>:comment<tt> - Optional description of the goods or service being purchased
224
+ # * <tt>:max_failed_payments</tt> - The number of payments that are allowed to fail before PayPal suspends the profile. Defaults to 0 which means PayPal will never suspend the profile until the term is completed. PayPal will keep attempting to process failed payments.
225
+ # * <tt>:currency</tt> - The currency of the transaction. If present must be one of { AUD, CAD, EUR, JPY, GBP or USD }. If omitted the default currency is used.
226
+ def recurring(money, creditcard, options = {})
227
+ post = {}
228
+ add_creditcard(post, creditcard)
229
+ add_currency(post, money, options)
230
+ add_address(post, options[:billing_address] || options[:address])
231
+ add_address(post, options[:shipping_address], "shipto")
232
+ add_customer_data(post, options)
233
+ add_recurring_info(post, creditcard, options)
234
+
235
+ commit(TRANSACTIONS[:recurring], money, post)
236
+ end
237
+
238
+ # Inquire about the status of a previously created recurring profile.
239
+ #
240
+ # ==== Parameters
241
+ #
242
+ # * <tt>profile_id</tt>
243
+ # * <tt>options</tt>
244
+ def recurring_inquiry(profile_id, options = {})
245
+ post = {}
246
+
247
+ post[:action] = RECURRING_ACTIONS[:inquiry]
248
+ post[:origprofileid] = profile_id.to_s
249
+
250
+ commit(TRANSACTIONS[:recurring], nil, options)
251
+ end
252
+
253
+ # Cancel a recurring profile.
254
+ #
255
+ # ==== Parameters
256
+ #
257
+ # * <tt>profile_id</tt>
258
+ def cancel_recurring(profile_id)
259
+ post = {}
260
+
261
+ post[:action] = RECURRING_ACTIONS[:deactivate]
262
+ post[:origprofileid] = profile_id.to_s
263
+
264
+ commit(TRANSACTIONS[:recurring], nil, nil)
47
265
  end
48
266
 
49
267
  private
50
268
 
51
269
  def add_customer_data(post, options)
270
+ post[:email] = options[:email].to_s if options.has_key?(:email)
271
+ post[:custref] = options[:customer].to_s.slice(0,12) if options[:customer]
272
+ post[:custip] = options[:ip].to_s if options[:ip]
52
273
  end
53
274
 
54
- def add_address(post, creditcard, options)
275
+ # NOTE : If you pass in any of the ship-to address parameters such as SHIPTOCITY or
276
+ # SHIPTOSTATE, you must pass in the complete set (that is, SHIPTOSTREET,
277
+ # SHIPTOCITY, SHIPTOSTATE, SHIPTOCOUNTRY, and SHIPTOZIP).
278
+ def add_address(post, address, prefix = '')
279
+ unless address.blank? or address.values.blank?
280
+ post[prefix+"street"] = address[:address1].to_s
281
+ post[prefix+"city"] = address[:city].to_s
282
+ post[prefix+"state"] = address[:state].blank? ? 'n/a' : address[:state]
283
+ post[prefix+"country"] = address[:country].to_s
284
+ post[prefix+"zip"] = address[:zip].to_s
285
+ end
55
286
  end
56
287
 
57
288
  def add_invoice(post, options)
289
+ post[:invnum] = options[:order_id].to_s.slice(0,127)
58
290
  end
59
291
 
60
292
  def add_creditcard(post, creditcard)
293
+ post[:acct] = creditcard.number
294
+ post[:cvv2] = creditcard.verification_value
295
+ post[:expdate] = expdate(creditcard)
296
+ post[:firstname] = creditcard.first_name
297
+ post[:lastname] = creditcard.last_name
61
298
  end
62
299
 
300
+ def add_currency(post, money, options)
301
+ post[:currency] = options[:currency] || currency(money)
302
+ end
303
+
304
+ # need to add START, TERM, PAYPERIOD, ACTION
305
+ def add_recurring_info(post, creditcard, options)
306
+ post[:action] = options.has_key?(:profile_id) ? RECURRING_ACTIONS[:modify] : RECURRING_ACTIONS[:create]
307
+ post[:start] = format_date(options[:starting_at])
308
+ post[:term] = options[:payments] unless options[:payments].nil?
309
+ post[:payperiod] = PERIODS[options[:periodicity]]
310
+ post[:desc] = options[:comment] unless options[:comment].nil?
311
+ post[:maxfailedpayments] = options[:max_failed_payments] unless options[:max_failed_payments].nil?
312
+ post[:profilename] = (options[:name] || creditcard.name).to_s.slice(0,128)
313
+ end
314
+
315
+ def format_date(time)
316
+ case time
317
+ when Time, Date then time.strftime("%m%d%Y")
318
+ else
319
+ time.to_s
320
+ end
321
+ end
322
+
323
+ def expdate(creditcard)
324
+ year = sprintf("%.04i", creditcard.year.to_i)
325
+ month = sprintf("%.02i", creditcard.month.to_i)
326
+
327
+ "#{month}#{year[-2..-1]}"
328
+ end
329
+
63
330
  def parse(body)
331
+ results = {}
332
+ body.split(/&/).each do |pair|
333
+ key,val = pair.split(/=/)
334
+ results[key] = val
335
+ end
336
+
337
+ results
64
338
  end
65
-
66
- def commit(action, money, parameters)
339
+
340
+ def build_request(parameters, action = nil)
341
+ post = {}
342
+ post[:user] = @options[:login]
343
+ post[:pwd] = @options[:password]
344
+ post[:trxtype] = action if action
345
+
346
+ request = post.merge(parameters).map { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&")
347
+ request
67
348
  end
68
349
 
69
- def message_from(response)
350
+ def build_headers(content_length)
351
+ {
352
+ "Content-Type" => "text/namevalue",
353
+ "Content-Length" => content_length.to_s,
354
+ "X-VPS-Client-Timeout" => timeout.to_s,
355
+ "X-VPS-VIT-Integration-Product" => "ActiveMerchant",
356
+ "X-VPS-VIT-Runtime-Version" => RUBY_VERSION,
357
+ "X-VPS-Request-ID" => Utils.generate_unique_id
358
+ }
70
359
  end
71
360
 
72
- def post_data(action, parameters = {})
361
+ def commit(action, money, parameters)
362
+ request = build_request(parameters, action)
363
+ headers = build_headers(request.size)
364
+
365
+ parameters[:amount] = amount(money) if money
366
+ response = parse(ssl_post(test? ? TEST_URL : LIVE_URL, request, headers))
367
+ Response.new(response["RESULT"] == "0", response["RESPMSG"], response,
368
+ :authorization => response["PNREF"],
369
+ :test => test?,
370
+ :cvv_result => response["CVV2MATCH"],
371
+ :avs_result => { :code => response["IAVS"] }
372
+ )
373
+
73
374
  end
74
375
  end
75
376
  end
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -6,7 +6,8 @@ version: !ruby/object:Gem::Version
6
6
  - 1
7
7
  - 5
8
8
  - 1
9
- version: 1.5.1
9
+ - 1
10
+ version: 1.5.1.1
10
11
  platform: ruby
11
12
  authors:
12
13
  - Tobias Luetke
@@ -35,7 +36,7 @@ cert_chain:
35
36
  hPaSTyVU0yCSnw==
36
37
  -----END CERTIFICATE-----
37
38
 
38
- date: 2010-03-24 00:00:00 +00:00
39
+ date: 2010-04-06 00:00:00 +01:00
39
40
  default_executable:
40
41
  dependencies:
41
42
  - !ruby/object:Gem::Dependency
metadata.gz.sig CHANGED
Binary file