offsite_payments 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +70 -0
  4. data/lib/offsite_payments.rb +46 -0
  5. data/lib/offsite_payments/action_view_helper.rb +72 -0
  6. data/lib/offsite_payments/helper.rb +119 -0
  7. data/lib/offsite_payments/integrations.rb +14 -0
  8. data/lib/offsite_payments/integrations/a1agregator.rb +245 -0
  9. data/lib/offsite_payments/integrations/authorize_net_sim.rb +580 -0
  10. data/lib/offsite_payments/integrations/bit_pay.rb +150 -0
  11. data/lib/offsite_payments/integrations/bogus.rb +32 -0
  12. data/lib/offsite_payments/integrations/chronopay.rb +283 -0
  13. data/lib/offsite_payments/integrations/citrus.rb +227 -0
  14. data/lib/offsite_payments/integrations/direc_pay.rb +339 -0
  15. data/lib/offsite_payments/integrations/directebanking.rb +237 -0
  16. data/lib/offsite_payments/integrations/doku.rb +171 -0
  17. data/lib/offsite_payments/integrations/dotpay.rb +166 -0
  18. data/lib/offsite_payments/integrations/dwolla.rb +160 -0
  19. data/lib/offsite_payments/integrations/e_payment_plans.rb +146 -0
  20. data/lib/offsite_payments/integrations/easy_pay.rb +137 -0
  21. data/lib/offsite_payments/integrations/epay.rb +161 -0
  22. data/lib/offsite_payments/integrations/first_data.rb +133 -0
  23. data/lib/offsite_payments/integrations/gestpay.rb +201 -0
  24. data/lib/offsite_payments/integrations/hi_trust.rb +179 -0
  25. data/lib/offsite_payments/integrations/ipay88.rb +240 -0
  26. data/lib/offsite_payments/integrations/klarna.rb +291 -0
  27. data/lib/offsite_payments/integrations/liqpay.rb +216 -0
  28. data/lib/offsite_payments/integrations/maksuturva.rb +231 -0
  29. data/lib/offsite_payments/integrations/mollie_ideal.rb +213 -0
  30. data/lib/offsite_payments/integrations/moneybookers.rb +199 -0
  31. data/lib/offsite_payments/integrations/nochex.rb +228 -0
  32. data/lib/offsite_payments/integrations/pag_seguro.rb +255 -0
  33. data/lib/offsite_payments/integrations/paxum.rb +114 -0
  34. data/lib/offsite_payments/integrations/pay_fast.rb +269 -0
  35. data/lib/offsite_payments/integrations/paydollar.rb +142 -0
  36. data/lib/offsite_payments/integrations/payflow_link.rb +194 -0
  37. data/lib/offsite_payments/integrations/paypal.rb +362 -0
  38. data/lib/offsite_payments/integrations/paypal_payments_advanced.rb +23 -0
  39. data/lib/offsite_payments/integrations/paysbuy.rb +71 -0
  40. data/lib/offsite_payments/integrations/payu_in.rb +266 -0
  41. data/lib/offsite_payments/integrations/payu_in_paisa.rb +46 -0
  42. data/lib/offsite_payments/integrations/platron.rb +153 -0
  43. data/lib/offsite_payments/integrations/pxpay.rb +271 -0
  44. data/lib/offsite_payments/integrations/quickpay.rb +232 -0
  45. data/lib/offsite_payments/integrations/rbkmoney.rb +110 -0
  46. data/lib/offsite_payments/integrations/robokassa.rb +154 -0
  47. data/lib/offsite_payments/integrations/sage_pay_form.rb +425 -0
  48. data/lib/offsite_payments/integrations/two_checkout.rb +332 -0
  49. data/lib/offsite_payments/integrations/universal.rb +180 -0
  50. data/lib/offsite_payments/integrations/valitor.rb +200 -0
  51. data/lib/offsite_payments/integrations/verkkomaksut.rb +143 -0
  52. data/lib/offsite_payments/integrations/web_pay.rb +186 -0
  53. data/lib/offsite_payments/integrations/webmoney.rb +119 -0
  54. data/lib/offsite_payments/integrations/wirecard_checkout_page.rb +359 -0
  55. data/lib/offsite_payments/integrations/world_pay.rb +273 -0
  56. data/lib/offsite_payments/notification.rb +71 -0
  57. data/lib/offsite_payments/return.rb +37 -0
  58. data/lib/offsite_payments/version.rb +3 -0
  59. metadata +270 -0
@@ -0,0 +1,580 @@
1
+ module OffsitePayments #:nodoc:
2
+ module Integrations #:nodoc:
3
+ module AuthorizeNetSim
4
+ # Overwrite this if you want to change the ANS test url
5
+ mattr_accessor :test_url
6
+ self.test_url = 'https://test.authorize.net/gateway/transact.dll'
7
+
8
+ # Overwrite this if you want to change the ANS production url
9
+ mattr_accessor :production_url
10
+ self.production_url = 'https://secure.authorize.net/gateway/transact.dll'
11
+
12
+ def self.service_url
13
+ mode = OffsitePayments.mode
14
+ case mode
15
+ when :production
16
+ self.production_url
17
+ when :test
18
+ self.test_url
19
+ else
20
+ raise StandardError, "Integration mode set to an invalid value: #{mode}"
21
+ end
22
+ end
23
+
24
+ def self.notification(post)
25
+ Notification.new(post)
26
+ end
27
+
28
+ def self.return(query_string)
29
+ Return.new(query_string)
30
+ end
31
+
32
+ # An example. Note the username as a parameter and transaction key you
33
+ # will want to use later. The amount that you pass in will be *rounded*,
34
+ # so preferably pass in X.2 decimal so that no rounding occurs. It is
35
+ # rounded because if it looks like 00.000 Authorize.Net fails the
36
+ # transaction as incorrectly formatted.
37
+ #
38
+ # payment_service_for('order_id', 'authorize_net_account', :service => :authorize_net_sim, :amount => 157.0) do |service|
39
+ #
40
+ # # You must call setup_hash and invoice
41
+ #
42
+ # service.setup_hash :transaction_key => '8CP6zJ7uD875J6tY',
43
+ # :order_timestamp => 1206836763
44
+ # service.customer_id 8
45
+ # service.customer :first_name => 'g',
46
+ # :last_name => 'g',
47
+ # :email => 'g@g.com',
48
+ # :phone => '3'
49
+ # service.billing_address :zip => 'g',
50
+ # :country => 'United States of America',
51
+ # :address => 'g'
52
+ #
53
+ # service.ship_to_address :first_name => 'g',
54
+ # :last_name => 'g',
55
+ # :city => '',
56
+ # :address => 'g',
57
+ # :address2 => '',
58
+ # :state => address.state,
59
+ # :country => 'United States of America',
60
+ # :zip => 'g'
61
+ #
62
+ # service.invoice "516428355" # your invoice number
63
+ # # The end-user is presented with the HTML produced by the notify_url.
64
+ # service.notify_url "http://t/authorize_net_sim/payment_received_notification_sub_step"
65
+ # service.payment_header 'My store name'
66
+ # service.add_line_item :name => 'item name', :quantity => 1, :unit_price => 0
67
+ # service.test_request 'true' # only if it's just a test
68
+ # service.shipping '25.0'
69
+ # # Tell it to display a "0" line item for shipping, with the price in
70
+ # # the name, otherwise it isn't shown at all, leaving the end user to
71
+ # # wonder why the total is different than the sum of the line items.
72
+ # service.add_shipping_as_line_item
73
+ # server.add_tax_as_line_item # same with tax
74
+ # # See the helper.rb file for various custom fields
75
+ # end
76
+
77
+ class Helper < OffsitePayments::Helper
78
+ mapping :order, 'x_fp_sequence'
79
+ mapping :account, 'x_login'
80
+
81
+ mapping :customer, :first_name => 'x_first_name',
82
+ :last_name => 'x_last_name',
83
+ :email => 'x_email',
84
+ :phone => 'x_phone'
85
+
86
+ mapping :notify_url, 'x_relay_url'
87
+ mapping :return_url, '' # unused
88
+ mapping :cancel_return_url, '' # unused
89
+
90
+ # Custom fields for Authorize.net SIM.
91
+ # See http://www.Authorize.Net/support/SIM_guide.pdf for more descriptions.
92
+ mapping :fax, 'x_fax'
93
+ mapping :customer_id, 'x_cust_id'
94
+ mapping :description, 'x_description'
95
+ mapping :tax, 'x_tax'
96
+ mapping :shipping, 'x_freight'
97
+
98
+ # True or false, or 0 or 1 same effect [not required to send one,
99
+ # defaults to false].
100
+ mapping :test_request, 'x_test_request'
101
+
102
+ # This one is necessary for the notify url to be able to parse its
103
+ # information later! They also pass back customer id, if that's
104
+ # useful.
105
+ def invoice(number)
106
+ add_field 'x_invoice_num', number
107
+ end
108
+
109
+ # Set the billing address. Call like service.billing_address {:city =>
110
+ # 'provo, :state => 'UT'}...
111
+ def billing_address(options)
112
+ for setting in [:city, :state, :zip, :country, :po_num] do
113
+ add_field 'x_' + setting.to_s, options[setting]
114
+ end
115
+ raise 'must use address1 and address2' if options[:address]
116
+ add_field 'x_address', (options[:address1].to_s + ' ' + options[:address2].to_s).strip
117
+ end
118
+
119
+ # Adds a custom field which you submit to Authorize.Net. These fields
120
+ # are all passed back to you verbatim when it does its relay
121
+ # (callback) to you note that if you call it twice with the same name,
122
+ # this function only uses keeps the second value you called it with.
123
+ def add_custom_field(name, value)
124
+ add_field name, value
125
+ end
126
+
127
+ # Displays tax as a line item, so they can see it. Otherwise it isn't
128
+ # displayed.
129
+ def add_tax_as_line_item
130
+ raise unless @fields['x_tax']
131
+ add_line_item :name => 'Total Tax', :quantity => 1, :unit_price => @fields['x_tax'], :tax => 0, :line_title => 'Tax'
132
+ end
133
+
134
+ # Displays shipping as a line item, so they can see it. Otherwise it
135
+ # isn't displayed.
136
+ def add_shipping_as_line_item(extra_options = {})
137
+ raise 'must set shipping/freight before calling this' unless @fields['x_freight']
138
+ add_line_item extra_options.merge({:name => 'Shipping and Handling Cost', :quantity => 1, :unit_price => @fields['x_freight'], :line_title => 'Shipping'})
139
+ end
140
+
141
+ # Add ship_to_address in the same format as the normal address is
142
+ # added.
143
+ def ship_to_address(options)
144
+ for setting in [:first_name, :last_name, :company, :city, :state, :zip, :country] do
145
+ if options[setting] then
146
+ add_field 'x_ship_to_' + setting.to_s, options[setting]
147
+ end
148
+ end
149
+ raise 'must use :address1 and/or :address2' if options[:address]
150
+ add_field 'x_ship_to_address', (options[:address1].to_s + ' ' + options[:address2].to_s).strip
151
+ end
152
+
153
+ # These control the look of the SIM payment page. Note that you can
154
+ # include a CSS header in descriptors, etc.
155
+ mapping :color_link, 'x_color_link'
156
+ mapping :color_text, 'x_color_text'
157
+ mapping :logo_url, 'x_logo_url'
158
+ mapping :background_url, 'x_background_url' # background image url for the page
159
+ mapping :payment_header, 'x_header_html_payment_form'
160
+ mapping :payment_footer, 'x_footer_html_payment_form'
161
+
162
+ # For this to work you must have also passed in an email for the
163
+ # purchaser.
164
+ def yes_email_customer_from_authorizes_side
165
+ add_field 'x_email_customer', 'TRUE'
166
+ end
167
+
168
+ # Add a line item to Authorize.Net.
169
+ # Call line add_line_item {:name => 'orange', :unit_price => 30, :tax_value => 'Y', :quantity => 3, }
170
+ # Note you can't pass in a negative unit price, and you can add an
171
+ # optional :line_title => 'special name' if you don't want it to say
172
+ # 'Item 1' or what not, the default coded here.
173
+ # Cannot have a negative price, nor a name with "'s or $
174
+ # You can use the :line_title for the product name and then :name for description, if desired
175
+ def add_line_item(options)
176
+ raise 'needs name' unless options[:name]
177
+
178
+ if @line_item_count == 30
179
+ # Add a note that we are not showing at least one -- AN doesn't
180
+ # display more than 30 or so.
181
+ description_of_last = @raw_html_fields[-1][1]
182
+ # Pull off the second to last section, which is the description.
183
+ description_of_last =~ />([^>]*)<\|>[YN]$/
184
+ # Create a new description, which can't be too big, so truncate here.
185
+ @raw_html_fields[-1][1] = description_of_last.gsub($1, $1[0..200] + ' + more unshown items after this one.')
186
+ end
187
+
188
+ name = options[:name]
189
+ quantity = options[:quantity] || 1
190
+ line_title = options[:line_title] || ('Item ' + (@line_item_count + 1).to_s) # left most field
191
+ unit_price = options[:unit_price] || 0
192
+ unit_price = unit_price.to_f.round(2)
193
+ tax_value = options[:tax_value] || 'N'
194
+
195
+ # Sanitization, in case they include a reserved word here, following
196
+ # their guidelines; unfortunately, they require 'raw' fields here,
197
+ # not CGI escaped, using their own delimiters.
198
+ #
199
+ # Authorize.net ignores the second field (sanitized_short_name)
200
+ raise 'illegal char for line item <|>' if name.include? '<|>'
201
+ raise 'illegal char for line item "' if name.include? '"'
202
+ raise 'cannot pass in dollar sign' if unit_price.to_s.include? '$'
203
+ raise 'must have positive or 0 unit price' if unit_price.to_f < 0
204
+ # Using CGI::escape causes the output to be formated incorrectly in
205
+ # the HTML presented to the end-user's browser (e.g., spaces turn
206
+ # into +'s).
207
+ sanitized_short_name = name[0..30]
208
+ name = name[0..255]
209
+
210
+ add_raw_html_field "x_line_item", "#{line_title}<|>#{sanitized_short_name}<|>#{name}<|>#{quantity}<|>#{unit_price}<|>#{tax_value}"
211
+
212
+ @line_item_count += 1
213
+ end
214
+
215
+ # If you call this it will e-mail to this address a copy of a receipt
216
+ # after successful, from Authorize.Net.
217
+ def email_merchant_from_authorizes_side(to_this_email)
218
+ add_field 'x_email_merchant', to_this_email
219
+ end
220
+
221
+ # You MUST call this at some point for it to actually work. Options
222
+ # must include :transaction_key and :order_timestamp
223
+ def setup_hash(options)
224
+ raise unless options[:transaction_key]
225
+ raise unless options[:order_timestamp]
226
+ amount = @fields['x_amount']
227
+ data = "#{@fields['x_login']}^#{@fields['x_fp_sequence']}^#{options[:order_timestamp].to_i}^#{amount}^#{@fields['x_currency_code']}"
228
+ hmac = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('md5'), options[:transaction_key], data)
229
+ add_field 'x_fp_hash', hmac
230
+ add_field 'x_fp_timestamp', options[:order_timestamp].to_i
231
+ end
232
+
233
+ # Note that you should call #invoice and #setup_hash as well, for the
234
+ # response_url to actually work.
235
+ def initialize(order, account, options = {})
236
+ super
237
+ raise 'missing parameter' unless order and account and options[:amount]
238
+ raise 'error -- amount with no digits!' unless options[:amount].to_s =~ /\d/
239
+ add_field('x_type', 'AUTH_CAPTURE') # the only one we deal with, for now. Not refunds or anything else, currently.
240
+ add_field 'x_show_form', 'PAYMENT_FORM'
241
+ add_field 'x_relay_response', 'TRUE'
242
+ add_field 'x_duplicate_window', '28800' # large default duplicate window.
243
+ add_field 'x_currency_code', currency_code
244
+ add_field 'x_version' , '3.1' # version from doc
245
+ add_field 'x_amount', options[:amount].to_f.round(2)
246
+ @line_item_count = 0
247
+ end
248
+ end
249
+
250
+ # # Example:
251
+ # parser = AuthorizeNetSim::Notification.new(request.raw_post)
252
+ # passed = parser.complete?
253
+ #
254
+ # order = Order.find_by_order_number(parser.invoice_num)
255
+ #
256
+ # unless order
257
+ # @message = 'Error--unable to find your transaction! Please contact us directly.'
258
+ # return render :partial => 'authorize_net_sim_payment_response'
259
+ # end
260
+ #
261
+ # if order.total != parser.gross.to_f
262
+ # logger.error "Authorize.Net sim said they paid for #{parser.gross} and it should have been #{order.total}!"
263
+ # passed = false
264
+ # end
265
+ #
266
+ # # Theoretically, Authorize.net will *never* pass us the same transaction
267
+ # # ID twice, but we can double check that... by using
268
+ # # parser.transaction_id, and checking against previous orders' transaction
269
+ # # id's (which you can save when the order is completed)....
270
+ # unless parser.acknowledge MD5_HASH_SET_IN_AUTHORIZE_NET, AUTHORIZE_LOGIN
271
+ # passed = false
272
+ # logger.error "ALERT POSSIBLE FRAUD ATTEMPT either that or you haven't setup your md5 hash setting right in #{__FILE__}
273
+ # because a transaction came back from Authorize.Net with the wrong hash value--rejecting!"
274
+ # end
275
+ #
276
+ # unless parser.cavv_matches? and parser.avs_code_matches?
277
+ # logger.error 'Warning--non matching CC!' + params.inspect
278
+ # # Could fail them here, as well (recommended)...
279
+ # end
280
+ #
281
+ # if passed
282
+ # # Set up your session, and render something that will redirect them to
283
+ # # your site, most likely.
284
+ # else
285
+ # # Render failure or redirect them to your site where you will render failure
286
+ # end
287
+ class Notification < OffsitePayments::Notification
288
+
289
+ def unescape(val) #:nodoc:
290
+ if val
291
+ CGI::unescape val
292
+ else
293
+ val
294
+ end
295
+ end
296
+
297
+ # Passes a hash of the address the user entered in at Authorize.Net
298
+ def billing_address
299
+ all = {}
300
+ [:fax, :city, :company, :last_name, :country, :zip, :first_name, :address, :email, :state].each do |key_out|
301
+ all[key_out] = unescape params['x_' + key_out.to_s]
302
+ end
303
+ all
304
+ end
305
+
306
+ def customer_id
307
+ unescape params['x_cust_id']
308
+ end
309
+
310
+ def auth_code
311
+ unescape params['x_auth_code']
312
+ end
313
+
314
+ def po_num
315
+ unescape params['x_po_num']
316
+ end
317
+
318
+ def ship_to_address
319
+ all = {}
320
+ [:city, :last_name, :first_name, :country, :zip, :address].each do |key_out|
321
+ all[key_out] = unescape params['x_ship_to_' + key_out.to_s]
322
+ end
323
+ all
324
+ end
325
+
326
+ # Tax amount we sent them.
327
+ def tax
328
+ unescape params['x_tax']
329
+ end
330
+
331
+ # Transaction type (probably going to be auth_capture, since that's
332
+ # all we set it as).
333
+ def transaction_type
334
+ unescape params['x_type']
335
+ end
336
+
337
+ # Payment method used--almost always CC (for credit card).
338
+ def method
339
+ unescape params['x_method']
340
+ end
341
+
342
+ # Ff our payment method is available. Almost always "true".
343
+ def method_available
344
+ params['x_method_available']
345
+ end
346
+
347
+ # Invoice num we passed in as invoice_num to them.
348
+ def invoice_num
349
+ item_id
350
+ end
351
+
352
+ # If you pass any values to authorize that aren't its expected, it
353
+ # will pass them back to you verbatim, returned by this method.
354
+ # custom values:
355
+ def all_custom_values_passed_in_and_now_passed_back_to_us
356
+ all = {}
357
+ params.each do |key, value|
358
+ if key[0..1] != 'x_'
359
+ all[key] = unescape value
360
+ end
361
+ end
362
+ all
363
+ end
364
+
365
+ def duty
366
+ unescape params['x_duty']
367
+ end
368
+
369
+ # Shipping we sent them.
370
+ def freight
371
+ unescape params['x_freight']
372
+ end
373
+ alias_method :shipping, :freight
374
+
375
+ def description
376
+ unescape params['x_description']
377
+ end
378
+
379
+ # Returns the response code as a symbol.
380
+ # {'1' => :approved, '2' => :declined, '3' => :error, '4' => :held_for_review}
381
+ def response_code_as_ruby_symbol
382
+ map = {'1' => :approved, '2' => :declined, '3' => :error, '4' => :held_for_review}
383
+ map[params['x_response_code']]
384
+ end
385
+
386
+ def response_reason_text
387
+ unescape params['x_response_reason_text']
388
+ end
389
+
390
+ # The response reason text's numeric id [equivalent--just a number]
391
+ def response_reason_code
392
+ unescape params['x_response_reason_code']
393
+ end
394
+
395
+ # 'used internally by their gateway'
396
+ def response_subcode
397
+ params['x_response_subcode']
398
+ end
399
+
400
+ # They pass back a tax_exempt value.
401
+ def tax_exempt
402
+ params['x_tax_exempt']
403
+ end
404
+
405
+ # avs [address verification] code
406
+ # A = Address (Street)
407
+ # matches, ZIP does not
408
+ # B = Address information
409
+ # not provided for AVS
410
+ # check
411
+ # E = AVS error
412
+ # G = Non-U.S. Card Issuing
413
+ # Bank
414
+ # N = No Match on Address
415
+ # (Street) or ZIP
416
+ # P = AVS not applicable for
417
+ # this transaction
418
+ # R = Retry – System
419
+ # unavailable or timed out
420
+ # S = Service not supported
421
+ # by issuer
422
+ # U = Address information is
423
+ # unavailable
424
+ # W = Nine digit ZIP
425
+ # matches, Address (Street)
426
+ # does not
427
+ # X = Address (Street) and
428
+ # nine digit ZIP match
429
+ # Y = Address (Street) and
430
+ # five digit ZIP match
431
+ # Z = Five digit ZIP matches
432
+ # Address (Street) does not
433
+ def avs_code
434
+ params['x_avs_code']
435
+ end
436
+
437
+ # Returns true if their address completely matched [Y or X, P from
438
+ # #avs_code, which mean 'add+zip match', 'address + 9-zip match', and
439
+ # not applicable, respectively].
440
+ def avs_code_matches?
441
+ return ['Y', 'X', 'P'].include? params['x_avs_code']
442
+ end
443
+
444
+ # cvv2 response
445
+ # M = Match
446
+ # N = No Match
447
+ # P = Not Processed
448
+ # S = Should have been
449
+ # present
450
+ # U = Issuer unable to
451
+ # process request
452
+ def cvv2_resp_code
453
+ params['x_cvv2_resp_code']
454
+ end
455
+
456
+ # check if #cvv2_resp_code == 'm' for Match. otherwise false
457
+ def cvv2_resp_code_matches?
458
+ return ['M'].include? cvv2_resp_code
459
+ end
460
+
461
+ # cavv_response--'cardholder authentication verification response code'--most likely not use for SIM
462
+ # Blank or not present =
463
+ # CAVV not validated
464
+ # 0 = CAVV not validated
465
+ # because erroneous data
466
+ # was submitted
467
+ # 1 = CAVV failed validation
468
+ # 2 = CAVV passed
469
+ # validation
470
+ # 3 = CAVV validation could
471
+ # not be performed; issuer
472
+ # attempt incomplete
473
+ # 4 = CAVV validation could
474
+ # not be performed; issuer
475
+ # system error
476
+ # 5 = Reserved for future
477
+ # use
478
+ # 6 = Reserved for future
479
+ # use
480
+ # 7 = CAVV attempt – failed
481
+ # validation – issuer
482
+ # available (U.S.-issued
483
+ # card/non-U.S acquirer)
484
+ # 8 = CAVV attempt –
485
+ # passed validation – issuer
486
+ # available (U.S.-issued
487
+ # card/non-U.S. acquirer)
488
+ # 9 = CAVV attempt – failed
489
+ # validation – issuer
490
+ def cavv_response
491
+ params['x_cavv_response']
492
+ end
493
+
494
+ # Check if #cavv_response == '', '2', '8' one of those [non failing]
495
+ # [blank means no validated, 2 is passed, 8 is passed issuer
496
+ # available]
497
+ def cavv_matches?
498
+ ['','2','8'].include? cavv_response
499
+ end
500
+
501
+ # Payment is complete -- returns true if x_response_code == '1'
502
+ def complete?
503
+ params["x_response_code"] == '1'
504
+ end
505
+
506
+ # Alias for invoice number--this is the only id they pass back to us
507
+ # that we passed to them, except customer id is also passed back.
508
+ def item_id
509
+ unescape params['x_invoice_num']
510
+ end
511
+
512
+ # They return this number to us [it's unique to Authorize.net].
513
+ def transaction_id
514
+ params['x_trans_id']
515
+ end
516
+
517
+ # When was this payment was received by the client. --unimplemented --
518
+ # always returns nil
519
+ def received_at
520
+ nil
521
+ end
522
+
523
+ # End-user's email
524
+ def payer_email
525
+ unescape params['x_email']
526
+ end
527
+
528
+ # They don't pass merchant email back to us -- unimplemented -- always
529
+ # returns nil
530
+ def receiver_email
531
+ nil
532
+ end
533
+
534
+ # md5 hash used internally
535
+ def security_key
536
+ params['x_MD5_Hash']
537
+ end
538
+
539
+ # The money amount we received in X.2 decimal. Returns a string
540
+ def gross
541
+ unescape params['x_amount']
542
+ end
543
+
544
+ # Was this a test transaction?
545
+ def test?
546
+ params['x_test_request'] == 'true'
547
+ end
548
+
549
+ # #method_available alias
550
+ def status
551
+ complete?
552
+ end
553
+
554
+ # Called to request back and check if it was a valid request.
555
+ # Authorize.net passes us back a hash that includes a hash of our
556
+ # 'unique' MD5 value that we set within their system.
557
+ #
558
+ # Example:
559
+ # acknowledge('my secret md5 hash that I set within Authorize.Net', 'authorize_login')
560
+ #
561
+ # Note this is somewhat unsafe unless you actually set that md5 hash
562
+ # to something (defaults to '' in their system).
563
+ def acknowledge(md5_hash_set_in_authorize_net, authorize_net_login_name)
564
+ Digest::MD5.hexdigest(md5_hash_set_in_authorize_net + authorize_net_login_name + params['x_trans_id'] + gross) == params['x_MD5_Hash'].downcase
565
+ end
566
+
567
+ private
568
+
569
+ # Take the posted data and move the relevant data into a hash.
570
+ def parse(post)
571
+ @raw = post
572
+ post.split('&').each do |line|
573
+ key, value = *line.scan( %r{^(\w+)\=(.*)$} ).flatten
574
+ params[key] = value
575
+ end
576
+ end
577
+ end
578
+ end
579
+ end
580
+ end