offsite_payments 2.0.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 (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