authorize-net 1.5.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. data/License.pdf +0 -0
  2. data/README.rdoc +124 -0
  3. data/Rakefile +74 -0
  4. data/generators/authorize_net_direct_post/USAGE +20 -0
  5. data/generators/authorize_net_direct_post/authorize_net_direct_post_generator.rb +21 -0
  6. data/generators/authorize_net_direct_post/templates/README-AuthorizeNet +49 -0
  7. data/generators/authorize_net_direct_post/templates/config.yml.erb +8 -0
  8. data/generators/authorize_net_direct_post/templates/config.yml.rails3.erb +8 -0
  9. data/generators/authorize_net_direct_post/templates/controller.rb.erb +31 -0
  10. data/generators/authorize_net_direct_post/templates/initializer.rb +4 -0
  11. data/generators/authorize_net_direct_post/templates/layout.erb +18 -0
  12. data/generators/authorize_net_direct_post/templates/payment.erb +10 -0
  13. data/generators/authorize_net_direct_post/templates/payment.rails3.erb +10 -0
  14. data/generators/authorize_net_direct_post/templates/receipt.erb +1 -0
  15. data/generators/authorize_net_direct_post/templates/relay_response.erb +1 -0
  16. data/generators/authorize_net_sim/USAGE +20 -0
  17. data/generators/authorize_net_sim/authorize_net_sim_generator.rb +19 -0
  18. data/generators/authorize_net_sim/templates/README-AuthorizeNet +52 -0
  19. data/generators/authorize_net_sim/templates/config.yml.erb +8 -0
  20. data/generators/authorize_net_sim/templates/config.yml.rails3.erb +8 -0
  21. data/generators/authorize_net_sim/templates/controller.rb.erb +21 -0
  22. data/generators/authorize_net_sim/templates/initializer.rb +4 -0
  23. data/generators/authorize_net_sim/templates/layout.erb +18 -0
  24. data/generators/authorize_net_sim/templates/payment.erb +6 -0
  25. data/generators/authorize_net_sim/templates/payment.rails3.erb +6 -0
  26. data/generators/authorize_net_sim/templates/thank_you.erb +1 -0
  27. data/generators/generator_extensions.rb +75 -0
  28. data/init.rb +2 -0
  29. data/install.rb +1 -0
  30. data/lib/app/helpers/authorize_net_helper.rb +24 -0
  31. data/lib/authorize-net.rb +4 -0
  32. data/lib/authorize_net.rb +92 -0
  33. data/lib/authorize_net/addresses/address.rb +29 -0
  34. data/lib/authorize_net/addresses/shipping_address.rb +26 -0
  35. data/lib/authorize_net/aim/response.rb +131 -0
  36. data/lib/authorize_net/aim/transaction.rb +184 -0
  37. data/lib/authorize_net/arb/response.rb +34 -0
  38. data/lib/authorize_net/arb/subscription.rb +72 -0
  39. data/lib/authorize_net/arb/transaction.rb +146 -0
  40. data/lib/authorize_net/authorize_net.rb +154 -0
  41. data/lib/authorize_net/cim/customer_profile.rb +19 -0
  42. data/lib/authorize_net/cim/payment_profile.rb +37 -0
  43. data/lib/authorize_net/cim/response.rb +110 -0
  44. data/lib/authorize_net/cim/transaction.rb +678 -0
  45. data/lib/authorize_net/customer.rb +27 -0
  46. data/lib/authorize_net/email_receipt.rb +24 -0
  47. data/lib/authorize_net/fields.rb +736 -0
  48. data/lib/authorize_net/key_value_response.rb +117 -0
  49. data/lib/authorize_net/key_value_transaction.rb +291 -0
  50. data/lib/authorize_net/line_item.rb +25 -0
  51. data/lib/authorize_net/order.rb +42 -0
  52. data/lib/authorize_net/payment_methods/credit_card.rb +74 -0
  53. data/lib/authorize_net/payment_methods/echeck.rb +72 -0
  54. data/lib/authorize_net/reporting/batch.rb +19 -0
  55. data/lib/authorize_net/reporting/batch_statistics.rb +19 -0
  56. data/lib/authorize_net/reporting/fds_filter.rb +11 -0
  57. data/lib/authorize_net/reporting/response.rb +127 -0
  58. data/lib/authorize_net/reporting/transaction.rb +116 -0
  59. data/lib/authorize_net/reporting/transaction_details.rb +25 -0
  60. data/lib/authorize_net/response.rb +27 -0
  61. data/lib/authorize_net/sim/hosted_payment_form.rb +38 -0
  62. data/lib/authorize_net/sim/hosted_receipt_page.rb +37 -0
  63. data/lib/authorize_net/sim/response.rb +142 -0
  64. data/lib/authorize_net/sim/transaction.rb +138 -0
  65. data/lib/authorize_net/transaction.rb +66 -0
  66. data/lib/authorize_net/xml_response.rb +172 -0
  67. data/lib/authorize_net/xml_transaction.rb +275 -0
  68. data/lib/generators/authorize_net/direct_post_generator.rb +51 -0
  69. data/lib/generators/authorize_net/sim_generator.rb +47 -0
  70. data/spec/aim_spec.rb +310 -0
  71. data/spec/arb_spec.rb +191 -0
  72. data/spec/authorize_net_spec.rb +200 -0
  73. data/spec/cim_spec.rb +450 -0
  74. data/spec/reporting_spec.rb +431 -0
  75. data/spec/sim_spec.rb +97 -0
  76. data/spec/spec.opts +5 -0
  77. data/spec/spec_helper.rb +2 -0
  78. data/uninstall.rb +1 -0
  79. metadata +223 -0
@@ -0,0 +1,27 @@
1
+ module AuthorizeNet
2
+
3
+ # The core, API agnostic response class. You shouldn't instantiate this one.
4
+ # Instead you should use AuthorizeNet::AIM::Response, AuthorizeNet::ARB::Response or AuthorizeNet::SIM::Response.
5
+ class Response
6
+
7
+ include AuthorizeNet::TypeConversions
8
+
9
+ # Fields to convert to/from booleans.
10
+ @@boolean_fields = []
11
+
12
+ # Fields to convert to/from BigDecimal.
13
+ @@decimal_fields = []
14
+
15
+ # DO NOT USE. Instantiate AuthorizeNet::AIM::Response or AuthorizeNet::SIM::Response instead.
16
+ def initialize()
17
+ raise "#{self.class.to_s} should not be instantiated directly."
18
+ end
19
+
20
+ # Check to see if the response indicated success.
21
+ def success?
22
+ false
23
+ end
24
+
25
+ end
26
+
27
+ end
@@ -0,0 +1,38 @@
1
+ module AuthorizeNet::SIM
2
+
3
+ # Models a hosted payment form.
4
+ class HostedPaymentForm
5
+
6
+ include AuthorizeNet::Model
7
+
8
+ attr_accessor :header_html, :footer_html, :color_background, :color_link, :color_text, :logo_url, :background_url, :rename
9
+
10
+ # Convenience method for adding field rename requests to the transaction. This renames a field shown on
11
+ # the hosted payment form.
12
+ def add_rename(field, name)
13
+ rename = "#{field},#{name}"
14
+ unless @rename.nil?
15
+ @rename = @rename.to_a << rename
16
+ else
17
+ @rename = [rename]
18
+ end
19
+ end
20
+
21
+ def to_hash
22
+ hash = {
23
+ :header_html_payment_form => @header_html,
24
+ :footer_html_payment_form => @footer_html,
25
+ :color_background => @color_background,
26
+ :color_link => @color_link,
27
+ :color_text => @color_text,
28
+ :logo_url => @logo_url,
29
+ :background_url => @background_url,
30
+ :rename => @rename
31
+ }
32
+ hash.delete_if {|k, v| v.nil?}
33
+ hash
34
+ end
35
+
36
+ end
37
+
38
+ end
@@ -0,0 +1,37 @@
1
+ module AuthorizeNet::SIM
2
+
3
+ # Models a hosted receipt page.
4
+ class HostedReceiptPage
5
+
6
+ # Defines constants for each of the link methods used by the hosted receipt page.
7
+ module LinkMethod
8
+ LINK = 'LINK'
9
+ POST = 'POST'
10
+ GET = 'GET'
11
+ end
12
+
13
+ include AuthorizeNet::Model
14
+
15
+ attr_accessor :header_html, :footer_html, :color_background, :color_link, :color_text, :logo_url, :background_url, :link_method, :link_text, :link_url
16
+
17
+
18
+ def to_hash
19
+ hash = {
20
+ :header_html_receipt => @header_html,
21
+ :footer_html_receipt => @footer_html,
22
+ :color_background => @color_background,
23
+ :color_link => @color_link,
24
+ :color_text => @color_text,
25
+ :logo_url => @logo_url,
26
+ :background_url => @background_url,
27
+ :receipt_link_method => @link_method,
28
+ :receipt_link_text => @link_text,
29
+ :receipt_link_url => @link_url
30
+ }
31
+ hash.delete_if {|k, v| v.nil?}
32
+ hash
33
+ end
34
+
35
+ end
36
+
37
+ end
@@ -0,0 +1,142 @@
1
+ module AuthorizeNet::SIM
2
+
3
+ # The SIM response class. Handles parsing the response from the gateway. Also
4
+ # provides a few relay response helpers used to implement Direct Post Method.
5
+ class Response < AuthorizeNet::KeyValueResponse
6
+
7
+ # Our MD5 digest generator.
8
+ @@digest = OpenSSL::Digest::Digest.new('md5')
9
+
10
+ include AuthorizeNet::SIM::Fields
11
+
12
+ # Constructs a new response object from a +raw_response+. Provides utility methods
13
+ # for validating the response as authentic, and for handling the Direct Post Method
14
+ # relay response.
15
+ #
16
+ # +raw_response+:: The raw response, either a string in POST body or GET query string format, or a hash of key/value pairs.
17
+ #
18
+ # Typical usage:
19
+ # response = AuthorizeNet::SIM::Response("x_first_name=John&x_last_name=Doe")
20
+ def initialize(raw_response)
21
+ @raw_response = raw_response
22
+ @custom_fields = {}
23
+ @fields = {}
24
+ parse_response(@raw_response)
25
+ end
26
+
27
+
28
+ # Returns True if the MD5 hash found in the response payload validates using
29
+ # the supplied api_login and secret merchant_value (THIS IS NOT YOUR API KEY).
30
+ def valid_md5?(api_login, merchant_value)
31
+ if @fields[:MD5_Hash].nil?
32
+ return false
33
+ end
34
+ @@digest.hexdigest("#{merchant_value}#{api_login}#{@fields[:trans_id]}#{@fields[:amount]}").downcase == @fields[:MD5_Hash].downcase
35
+ end
36
+
37
+ # Returns an HTML string that can be returned to the gateway during the Relay Response,
38
+ # and will send the user on to URL you specify. Takes a hash of options, currently the
39
+ # only option is :include, which can be True to include all fields returned in the response
40
+ # as query string parameters, or it can be an array of fields to include.
41
+ def direct_post_reply(url, options = {})
42
+ url = direct_post_url(url, options[:include]) if options.has_key?(:include)
43
+ js_url = url.gsub("'", '\'')
44
+ html_url = url.gsub('&', '&amp;').gsub('"', "\"")
45
+ html = <<-HTML
46
+ <html><head><script type="text/javascript" charset="utf-8">window.location='#{js_url}';</script><noscript><meta http-equiv="refresh" content="1;url=#{html_url}"></noscript></head><body></body></html>
47
+ HTML
48
+ end
49
+
50
+ # Returns an URL with the fields found in the response and specified in include_fields attached as
51
+ # part of the URL's query string. If you pass true instead of an array of fields, all fields will be
52
+ # attached.
53
+ def direct_post_url(base_url, include_fields = true)
54
+ url = base_url
55
+ if include_fields
56
+ fields = []
57
+ case include_fields
58
+ when TrueClass
59
+ fields = FIELDS.collect do |k|
60
+ k_str = k.to_s
61
+ k_str[2..k_str.length].to_sym
62
+ end
63
+ when Array
64
+ fields = include_fields
65
+ else
66
+ fields = include_fields.to_a
67
+ end
68
+ parsed_url = URI.parse(url)
69
+ if parsed_url.query.nil?
70
+ parsed_url.query = ''
71
+ elsif parsed_url.query.length != 0
72
+ parsed_url.query = parsed_url.query.chomp('&') + '&'
73
+ end
74
+ parsed_url.query += ((fields.select { |k| @fields.has_key?(k) }).collect { |k| self.to_param(k, @fields[k]) }).join('&')
75
+ parsed_url.query.chomp('&')
76
+ url = parsed_url.to_s
77
+ end
78
+ url
79
+ end
80
+
81
+ # Check to see if the response indicated success. Success is defined as a valid MD5 hash
82
+ # and an response code of AuthorizeNet::Response::ResponseCode::APPROVED.
83
+ def success?(api_login, merchant_value)
84
+ valid_md5?(api_login, merchant_value) && approved?
85
+ end
86
+
87
+ # Returns the transaction's authorization code. This should be shown to the
88
+ # end user.
89
+ def authorization_code
90
+ @fields[:auth_code]
91
+ end
92
+
93
+ # Returns the transaction's authorization id. You will need this for future void, refund
94
+ # and prior authorization capture requests.
95
+ def transaction_id
96
+ @fields[:trans_id]
97
+ end
98
+
99
+ # Returns the customer id from the response.
100
+ def customer_id
101
+ @fields[:cust_id]
102
+ end
103
+
104
+ # Returns a response code (from AVSResponseCode) indicating the result of any Address Verification
105
+ # Service checks.
106
+ def avs_response
107
+ @fields[:avs_code]
108
+ end
109
+
110
+ #:enddoc:
111
+ protected
112
+
113
+ # Internal helper to parse the raw response object. It handles both raw POST bodies and
114
+ # hashes.
115
+ def parse_response(raw_response)
116
+ case raw_response
117
+ when Hash
118
+ raw_response.each do |k, v|
119
+ k = k.to_sym
120
+ if FIELDS.include?(k)
121
+ @fields[to_internal_field(k)] = v # remove x_ from sym and stick in @fields
122
+ else
123
+ @custom_fields[k] = v
124
+ end
125
+ end
126
+ when String
127
+ # convert to hash and re-parse
128
+ hash = CGI::parse(raw_response)
129
+ hash.each do |k, v|
130
+ if v.kind_of?(Array) && v.length == 1
131
+ hash[k] = v[0]
132
+ end
133
+ end
134
+ parse_response(hash)
135
+ else
136
+ parse_response(@raw_response.to_s)
137
+ end
138
+ end
139
+
140
+ end
141
+
142
+ end
@@ -0,0 +1,138 @@
1
+ module AuthorizeNet::SIM
2
+
3
+ # The SIM transaction class. Handles building the transaction payload and
4
+ # generating a set of hidden form fields to be POSTed to the gateway.
5
+ class Transaction < AuthorizeNet::KeyValueTransaction
6
+
7
+ RANDOM_SEQUENCE_MAX = (1 << 32) - 1
8
+
9
+ # Our MD5 digest generator.
10
+ @@digest = OpenSSL::Digest::Digest.new('md5')
11
+
12
+ # The default options for the constructor.
13
+ @@option_defaults = {
14
+ :sequence => nil,
15
+ :timestamp => nil,
16
+ :test => false,
17
+ :hosted_payment_form => false,
18
+ :relay_response => true,
19
+ :relay_url => nil,
20
+ :transaction_type => Type::AUTHORIZE_AND_CAPTURE
21
+ }
22
+
23
+ # Constructs a SIM transaction. You can use the new SIM transaction object
24
+ # to build the hidden field payload needed to process a SIM transaction with
25
+ # the gateway. In particular, this class handles generating the MD5 fingerprint
26
+ # used to authenticate transactions at the gateway. Since the fingerprint includes
27
+ # the amount to charge, you should not construct this object until you know EXACTLY
28
+ # how much you want to charge (or authorize).
29
+ #
30
+ # +api_login_id+:: Your API login ID, as a string.
31
+ # +api_transaction_key+:: Your API transaction key, as a string.
32
+ # +amount+:: The amount of the transaction, as a string, Float or BigDecimal.
33
+ # +options+:: A hash of options. See below for values.
34
+ #
35
+ # Options
36
+ # +sequence+:: The sequence number of the transaction as a string or Fixnum. This is usually something like an invoice number. If none is provided, the SDK generates one at random.
37
+ # +timestamp+:: The time the transaction was initiated as a string or Fixnum. This needs to be within 15 minutes of when the gateway receives the transaction. If no value is provided, the SDK defaults it to Time.now().
38
+ # +test+:: A boolean indicating if the transaction should be run in test mode or not (defaults to false).
39
+ # +hosted_payment_form+:: A boolean indicating if the transaction should use a hosted payment form (defaults to false).
40
+ # +relay_response+:: A boolean indicating if the transaction should use the relay response feature to return a receipt to the customer (defaults to true). Direct Post Method requires using a relay response.
41
+ # +relay_url+:: A string of the URL that the gateway should hit to get the relay response (defaults to nil).
42
+ # +transaction_type+:: The type of transaction to perform. Defaults to AuthorizeNet::Type::AUTHORIZE_AND_CAPTURE. This value is only used if run is called directly.
43
+ #
44
+ def initialize(api_login_id, api_transaction_key, amount, options = {})
45
+ super()
46
+ @api_transaction_key = api_transaction_key
47
+ @api_login_id = api_login_id
48
+ @amount = decimal_to_value(amount)
49
+ options = @@option_defaults.merge(options)
50
+ @sequence = options[:sequence]
51
+ @timestamp = options[:timestamp]
52
+ @test_mode = options[:test]
53
+ @hosted_payment_form = options[:hosted_payment_form]
54
+ @relay_url = options[:relay_url]
55
+ @type = options[:transaction_type]
56
+ unless @relay_url.nil?
57
+ @relay_response = true
58
+ else
59
+ @relay_response = !!options[:relay_response]
60
+ end
61
+ @delim_data = !@relay_response
62
+ end
63
+
64
+ # Calculates and returns the HMAC-MD5 fingerprint needed to authenticate the transaction
65
+ # with the SIM gateway.
66
+ def fingerprint
67
+ if @timestamp.nil?
68
+ @timestamp = Time.now.to_i
69
+ end
70
+
71
+ if @sequence.nil?
72
+ @sequence = rand(RANDOM_SEQUENCE_MAX)
73
+ end
74
+ OpenSSL::HMAC.hexdigest(@@digest, @api_transaction_key, "#{@api_login_id.to_s.rstrip}^#{@sequence.to_s.rstrip}^#{@timestamp.to_s.rstrip}^#{@amount.to_s.rstrip}^")
75
+ end
76
+
77
+ # Returns all the fields needed for the fingerprint. These must all be passed to the SIM
78
+ # exactly as returned. And these values are time sensitive.
79
+ def fingerprint_fields
80
+ {
81
+ :login => @api_login_id,
82
+ :fp_hash => fingerprint,
83
+ :fp_sequence => @sequence,
84
+ :fp_timestamp => @timestamp,
85
+ :amount => @amount
86
+ }
87
+ end
88
+
89
+ # Returns all the fields (including custom) exactly as they should be named
90
+ # in the SIM form. Fields with multiple values are returned with an array
91
+ # for the key's value.
92
+ def form_fields
93
+ form_fields = {}
94
+ form_fields[:x_test_request] = boolean_to_value(@test_mode)
95
+ if @hosted_payment_form
96
+ form_fields[:x_show_form] = 'PAYMENT_FORM'
97
+ end
98
+ if @relay_response && !@relay_url.nil?
99
+ form_fields[:x_relay_url] = @relay_url
100
+ end
101
+ fields.merge(:type => @type, :version => @version, :delim_data => boolean_to_value(@delim_data), :relay_response => boolean_to_value(@relay_response)).each do |k, v|
102
+ form_fields[to_external_field(k)] = v
103
+ end
104
+ fingerprint_fields.each do |k, v|
105
+ form_fields[to_external_field(k)] = v
106
+ end
107
+ form_fields.merge(custom_fields)
108
+ end
109
+
110
+
111
+ # Takes an instance of AuthorizeNet::SIM::HostedPaymentForm and adds it to the transaction. Note that
112
+ # many of the fields in AuthorizeNet::SIM::HostedPaymentForm are shared with those in
113
+ # AuthorizeNet::SIM::HostedReceiptPage. For the duplicate fields, which ever value
114
+ # is added to the transaction last will be the one used.
115
+ def set_hosted_payment_form(form)
116
+ @fields.merge!(form.to_hash)
117
+ @hosted_payment_form = true
118
+ end
119
+
120
+ # Takes an instance of AuthorizeNet::SIM::HostedReceiptPage and adds it to the transaction. Note that
121
+ # many of the fields in AuthorizeNet::SIM::HostedReceiptPage are shared with those in
122
+ # AuthorizeNet::SIM::HostedPaymentForm. For the duplicate fields, which ever value
123
+ # is added to the transaction last will be the one used. If you set a hosted payment receipt,
124
+ # the relay response will be disabled.
125
+ def set_hosted_payment_receipt(form)
126
+ @fields.merge!(form.to_hash)
127
+ @relay_response = false
128
+ @delim_data = true
129
+ end
130
+
131
+ # An alias for form_fields.
132
+ def run
133
+ form_fields
134
+ end
135
+
136
+ end
137
+
138
+ end
@@ -0,0 +1,66 @@
1
+ module AuthorizeNet
2
+
3
+ # The core, API agnostic transaction class. You shouldn't instantiate this one.
4
+ # Instead you should use AuthorizeNet::AIM::Transaction, AuthorizeNet::SIM::Transaction or AuthorizeNet::ARB::Transaction.
5
+ class Transaction
6
+
7
+ include AuthorizeNet::TypeConversions
8
+
9
+ # Fields to convert to/from booleans.
10
+ @@boolean_fields = []
11
+
12
+ # Fields to convert to/from BigDecimal.
13
+ @@decimal_fields = []
14
+
15
+ # DO NOT USE. Instantiate AuthorizeNet::AIM::Transaction, AuthorizeNet::SIM::Transaction or AuthorizeNet::ARB::Transaction instead.
16
+ def initialize()
17
+ @fields ||= {}
18
+ end
19
+
20
+ # Sets arbitrary API fields, overwriting existing values if they exist. Takes a hash of key/value pairs,
21
+ # where the keys are the field names without the "x_" prefix. You can set a field to Nil to unset it. If
22
+ # the value is an array, each value in the array will be added. For example, set_fields({:line_item =>
23
+ # ["item1<|>golf balls<|><|>2<|>18.95<|>Y", "item2<|>golf bag<|>Wilson golf carry bag, red<|>1<|>39.99<|>"]})
24
+ # would generate two x_line_item fields in the transaction. One for each value in the array.
25
+ def set_fields(fields = {})
26
+ @fields.merge!(fields)
27
+ @fields.reject! {|k, v| v.nil?}
28
+ @fields
29
+ end
30
+
31
+ # Returns the current hash of API fields.
32
+ def fields
33
+ @fields
34
+ end
35
+
36
+ # Takes an instance of AuthorizeNet::Address and adds it to the transaction.
37
+ def set_address(address)
38
+ @fields.merge!(address.to_hash)
39
+ end
40
+
41
+ # Takes an instance of AuthorizeNet::ShippingAddress and adds it to the transaction.
42
+ def set_shipping_address(address)
43
+ @fields.merge!(address.to_hash)
44
+ end
45
+
46
+ # Takes an instance of AuthorizeNet::Customer and adds it to the transaction.
47
+ def set_customer(customer)
48
+ @fields.merge!(customer.to_hash)
49
+ end
50
+
51
+ #:enddoc:
52
+ protected
53
+
54
+ # Internal method to handle multiple types of payment arguments.
55
+ def handle_payment_argument(payment)
56
+ case payment
57
+ when AuthorizeNet::CreditCard, AuthorizeNet::ECheck
58
+ set_fields(payment.to_hash)
59
+ else
60
+ set_fields(:card_num => payment)
61
+ end
62
+ end
63
+
64
+ end
65
+
66
+ end