yetanothernguyen-activemerchant 1.16.0 → 1.21.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. data/CHANGELOG +95 -0
  2. data/CONTRIBUTORS +29 -0
  3. data/lib/active_merchant/billing/credit_card.rb +105 -19
  4. data/lib/active_merchant/billing/credit_card_methods.rb +5 -1
  5. data/lib/active_merchant/billing/gateway.rb +1 -1
  6. data/lib/active_merchant/billing/gateways/authorize_net.rb +24 -2
  7. data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +104 -18
  8. data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +110 -4
  9. data/lib/active_merchant/billing/gateways/beanstream.rb +29 -1
  10. data/lib/active_merchant/billing/gateways/braintree_blue.rb +9 -4
  11. data/lib/active_merchant/billing/gateways/braintree_orange.rb +4 -0
  12. data/lib/active_merchant/billing/gateways/card_save.rb +23 -0
  13. data/lib/active_merchant/billing/gateways/certo_direct.rb +279 -0
  14. data/lib/active_merchant/billing/gateways/efsnet.rb +9 -9
  15. data/lib/active_merchant/billing/gateways/elavon.rb +2 -1
  16. data/lib/active_merchant/billing/gateways/epay.rb +12 -6
  17. data/lib/active_merchant/billing/gateways/eway_managed.rb +46 -12
  18. data/lib/active_merchant/billing/gateways/exact.rb +5 -0
  19. data/lib/active_merchant/billing/gateways/ideal/ideal_base.rb +3 -3
  20. data/lib/active_merchant/billing/gateways/ipay88.rb +157 -0
  21. data/lib/active_merchant/billing/gateways/iridium.rb +3 -3
  22. data/lib/active_merchant/billing/gateways/itransact.rb +450 -0
  23. data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +1 -0
  24. data/lib/active_merchant/billing/gateways/moneris.rb +4 -0
  25. data/lib/active_merchant/billing/gateways/nab_transact.rb +244 -0
  26. data/lib/active_merchant/billing/gateways/ogone.rb +94 -56
  27. data/lib/active_merchant/billing/gateways/optimal_payment.rb +277 -0
  28. data/lib/active_merchant/billing/gateways/orbital.rb +57 -34
  29. data/lib/active_merchant/billing/gateways/pay_junction.rb +6 -1
  30. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +1 -0
  31. data/lib/active_merchant/billing/gateways/payflow/payflow_express_response.rb +2 -2
  32. data/lib/active_merchant/billing/gateways/payflow.rb +10 -2
  33. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +8 -5
  34. data/lib/active_merchant/billing/gateways/paypal_digital_goods.rb +43 -0
  35. data/lib/active_merchant/billing/gateways/paypal_express.rb +93 -40
  36. data/lib/active_merchant/billing/gateways/paypal_express_common.rb +8 -3
  37. data/lib/active_merchant/billing/gateways/qbms.rb +4 -0
  38. data/lib/active_merchant/billing/gateways/quickpay.rb +97 -22
  39. data/lib/active_merchant/billing/gateways/realex.rb +5 -1
  40. data/lib/active_merchant/billing/gateways/samurai.rb +121 -0
  41. data/lib/active_merchant/billing/gateways/secure_pay_au.rb +136 -49
  42. data/lib/active_merchant/billing/gateways/secure_pay_tech.rb +1 -1
  43. data/lib/active_merchant/billing/gateways/skip_jack.rb +7 -2
  44. data/lib/active_merchant/billing/gateways/stripe.rb +51 -19
  45. data/lib/active_merchant/billing/gateways/usa_epay.rb +13 -184
  46. data/lib/active_merchant/billing/gateways/usa_epay_advanced.rb +1496 -0
  47. data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +206 -0
  48. data/lib/active_merchant/billing/gateways/verifi.rb +2 -2
  49. data/lib/active_merchant/billing/gateways/viaklix.rb +1 -1
  50. data/lib/active_merchant/billing/gateways/worldpay.rb +1 -1
  51. data/lib/active_merchant/billing/integrations/action_view_helper.rb +6 -2
  52. data/lib/active_merchant/billing/integrations/authorize_net_sim/helper.rb +228 -0
  53. data/lib/active_merchant/billing/integrations/authorize_net_sim/notification.rb +340 -0
  54. data/lib/active_merchant/billing/integrations/authorize_net_sim.rb +38 -0
  55. data/lib/active_merchant/billing/integrations/direc_pay/helper.rb +4 -4
  56. data/lib/active_merchant/billing/integrations/dwolla/helper.rb +31 -0
  57. data/lib/active_merchant/billing/integrations/dwolla/notification.rb +55 -0
  58. data/lib/active_merchant/billing/integrations/dwolla/return.rb +38 -0
  59. data/lib/active_merchant/billing/integrations/dwolla.rb +30 -0
  60. data/lib/active_merchant/billing/integrations/helper.rb +19 -2
  61. data/lib/active_merchant/billing/integrations/ipay88/helper.rb +120 -0
  62. data/lib/active_merchant/billing/integrations/ipay88/return.rb +121 -0
  63. data/lib/active_merchant/billing/integrations/ipay88.rb +40 -0
  64. data/lib/active_merchant/billing/integrations/nochex.rb +1 -1
  65. data/lib/active_merchant/billing/integrations/payflow_link/helper.rb +100 -0
  66. data/lib/active_merchant/billing/integrations/payflow_link/notification.rb +78 -0
  67. data/lib/active_merchant/billing/integrations/payflow_link.rb +21 -0
  68. data/lib/active_merchant/billing/integrations/sage_pay_form/encryption.rb +4 -4
  69. data/lib/active_merchant/billing/integrations/sage_pay_form/helper.rb +18 -2
  70. data/lib/active_merchant/billing/integrations/two_checkout.rb +1 -2
  71. data/lib/active_merchant/railtie.rb +7 -7
  72. data/lib/active_merchant/railtie.rb.orig +19 -0
  73. data/lib/active_merchant/version.rb +1 -1
  74. data/lib/active_merchant.rb +23 -10
  75. data/lib/active_merchant.rb.orig +78 -0
  76. metadata +147 -63
  77. data/lib/active_merchant/common/connection.rb +0 -177
  78. data/lib/active_merchant/common/country.rb +0 -328
  79. data/lib/active_merchant/common/error.rb +0 -26
  80. data/lib/active_merchant/common/post_data.rb +0 -24
  81. data/lib/active_merchant/common/posts_data.rb +0 -63
  82. data/lib/active_merchant/common/requires_parameters.rb +0 -16
  83. data/lib/active_merchant/common/utils.rb +0 -22
  84. data/lib/active_merchant/common/validateable.rb +0 -81
  85. data/lib/active_merchant/common.rb +0 -14
  86. data/lib/certs/cacert.pem +0 -7815
@@ -0,0 +1,206 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+
4
+ class UsaEpayTransactionGateway < Gateway
5
+ URL = 'https://www.usaepay.com/gate.php'
6
+
7
+ self.supported_cardtypes = [:visa, :master, :american_express]
8
+ self.supported_countries = ['US']
9
+ self.homepage_url = 'http://www.usaepay.com/'
10
+ self.display_name = 'USA ePay'
11
+
12
+ TRANSACTIONS = {
13
+ :authorization => 'authonly',
14
+ :purchase => 'sale',
15
+ :capture => 'capture',
16
+ :refund => 'refund',
17
+ :void => 'void'
18
+ }
19
+
20
+ def initialize(options = {})
21
+ requires!(options, :login)
22
+ @options = options
23
+ super
24
+ end
25
+
26
+ def authorize(money, credit_card, options = {})
27
+ post = {}
28
+
29
+ add_amount(post, money)
30
+ add_invoice(post, options)
31
+ add_credit_card(post, credit_card)
32
+ add_address(post, credit_card, options)
33
+ add_customer_data(post, options)
34
+
35
+ commit(:authorization, post)
36
+ end
37
+
38
+ def purchase(money, credit_card, options = {})
39
+ post = {}
40
+
41
+ add_amount(post, money)
42
+ add_invoice(post, options)
43
+ add_credit_card(post, credit_card)
44
+ add_address(post, credit_card, options)
45
+ add_customer_data(post, options)
46
+
47
+ commit(:purchase, post)
48
+ end
49
+
50
+ def capture(money, authorization, options = {})
51
+ post = { :refNum => authorization }
52
+
53
+ add_amount(post, money)
54
+ commit(:capture, post)
55
+ end
56
+
57
+ def refund(money, authorization, options = {})
58
+ post = { :refNum => authorization }
59
+
60
+ add_amount(post, money)
61
+ commit(:refund, post)
62
+ end
63
+
64
+ def void(authorization, options = {})
65
+ post = { :refNum => authorization }
66
+ commit(:void, post)
67
+ end
68
+
69
+ private
70
+
71
+ def add_amount(post, money)
72
+ post[:amount] = amount(money)
73
+ end
74
+
75
+ def expdate(credit_card)
76
+ year = format(credit_card.year, :two_digits)
77
+ month = format(credit_card.month, :two_digits)
78
+
79
+ "#{month}#{year}"
80
+ end
81
+
82
+ def add_customer_data(post, options)
83
+ address = options[:billing_address] || options[:address] || {}
84
+ post[:street] = address[:address1]
85
+ post[:zip] = address[:zip]
86
+
87
+ if options.has_key? :email
88
+ post[:custemail] = options[:email]
89
+ post[:custreceipt] = 'No'
90
+ end
91
+
92
+ if options.has_key? :customer
93
+ post[:custid] = options[:customer]
94
+ end
95
+
96
+ if options.has_key? :ip
97
+ post[:ip] = options[:ip]
98
+ end
99
+ end
100
+
101
+ def add_address(post, credit_card, options)
102
+ billing_address = options[:billing_address] || options[:address]
103
+
104
+ add_address_for_type(:billing, post, credit_card, billing_address) if billing_address
105
+ add_address_for_type(:shipping, post, credit_card, options[:shipping_address]) if options[:shipping_address]
106
+ end
107
+
108
+ def add_address_for_type(type, post, credit_card, address)
109
+ prefix = address_key_prefix(type)
110
+
111
+ post[address_key(prefix, 'fname')] = credit_card.first_name
112
+ post[address_key(prefix, 'lname')] = credit_card.last_name
113
+ post[address_key(prefix, 'company')] = address[:company] unless address[:company].blank?
114
+ post[address_key(prefix, 'street')] = address[:address1] unless address[:address1].blank?
115
+ post[address_key(prefix, 'street2')] = address[:address2] unless address[:address2].blank?
116
+ post[address_key(prefix, 'city')] = address[:city] unless address[:city].blank?
117
+ post[address_key(prefix, 'state')] = address[:state] unless address[:state].blank?
118
+ post[address_key(prefix, 'zip')] = address[:zip] unless address[:zip].blank?
119
+ post[address_key(prefix, 'country')] = address[:country] unless address[:country].blank?
120
+ post[address_key(prefix, 'phone')] = address[:phone] unless address[:phone].blank?
121
+ end
122
+
123
+ def address_key_prefix(type)
124
+ case type
125
+ when :shipping then 'ship'
126
+ when :billing then 'bill'
127
+ end
128
+ end
129
+
130
+ def address_key(prefix, key)
131
+ "#{prefix}#{key}".to_sym
132
+ end
133
+
134
+ def add_invoice(post, options)
135
+ post[:invoice] = options[:order_id]
136
+ end
137
+
138
+ def add_credit_card(post, credit_card)
139
+ post[:card] = credit_card.number
140
+ post[:cvv2] = credit_card.verification_value if credit_card.verification_value?
141
+ post[:expir] = expdate(credit_card)
142
+ post[:name] = credit_card.name
143
+ end
144
+
145
+ def parse(body)
146
+ fields = {}
147
+ for line in body.split('&')
148
+ key, value = *line.scan( %r{^(\w+)\=(.*)$} ).flatten
149
+ fields[key] = CGI.unescape(value.to_s)
150
+ end
151
+
152
+ {
153
+ :status => fields['UMstatus'],
154
+ :auth_code => fields['UMauthCode'],
155
+ :ref_num => fields['UMrefNum'],
156
+ :batch => fields['UMbatch'],
157
+ :avs_result => fields['UMavsResult'],
158
+ :avs_result_code => fields['UMavsResultCode'],
159
+ :cvv2_result => fields['UMcvv2Result'],
160
+ :cvv2_result_code => fields['UMcvv2ResultCode'],
161
+ :vpas_result_code => fields['UMvpasResultCode'],
162
+ :result => fields['UMresult'],
163
+ :error => fields['UMerror'],
164
+ :error_code => fields['UMerrorcode'],
165
+ :acs_url => fields['UMacsurl'],
166
+ :payload => fields['UMpayload']
167
+ }.delete_if{|k, v| v.nil?}
168
+ end
169
+
170
+
171
+ def commit(action, parameters)
172
+ response = parse( ssl_post(URL, post_data(action, parameters)) )
173
+
174
+ Response.new(response[:status] == 'Approved', message_from(response), response,
175
+ :test => @options[:test] || test?,
176
+ :authorization => response[:ref_num],
177
+ :cvv_result => response[:cvv2_result_code],
178
+ :avs_result => {
179
+ :street_match => response[:avs_result_code].to_s[0,1],
180
+ :postal_match => response[:avs_result_code].to_s[1,1],
181
+ :code => response[:avs_result_code].to_s[2,1]
182
+ }
183
+ )
184
+ end
185
+
186
+ def message_from(response)
187
+ if response[:status] == "Approved"
188
+ return 'Success'
189
+ else
190
+ return 'Unspecified error' if response[:error].blank?
191
+ return response[:error]
192
+ end
193
+ end
194
+
195
+ def post_data(action, parameters = {})
196
+ parameters[:command] = TRANSACTIONS[action]
197
+ parameters[:key] = @options[:login]
198
+ parameters[:software] = 'Active Merchant'
199
+ parameters[:testmode] = @options[:test] ? 1 : 0
200
+
201
+ parameters.collect { |key, value| "UM#{key}=#{CGI.escape(value.to_s)}" }.join("&")
202
+ end
203
+ end
204
+ end
205
+ end
206
+
@@ -63,11 +63,11 @@ module ActiveMerchant #:nodoc:
63
63
  self.homepage_url = 'http://www.verifi.com/'
64
64
  self.display_name = 'Verifi'
65
65
 
66
- def initialize(options = {})
66
+ def initialize(options = {})
67
67
  requires!(options, :login, :password)
68
68
  @options = options
69
69
  super
70
- end
70
+ end
71
71
 
72
72
  def purchase(money, credit_card, options = {})
73
73
  sale_authorization_or_credit_template(:purchase, money, credit_card, options)
@@ -14,7 +14,7 @@ module ActiveMerchant #:nodoc:
14
14
 
15
15
  APPROVED = '0'
16
16
 
17
- self.supported_cardtypes = [:visa, :master, :american_express]
17
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover]
18
18
  self.supported_countries = ['US']
19
19
  self.display_name = 'ViaKLIX'
20
20
  self.homepage_url = 'http://viaklix.com'
@@ -27,7 +27,7 @@ module ActiveMerchant #:nodoc:
27
27
  def purchase(money, payment_method, options = {})
28
28
  response = MultiResponse.new
29
29
  response << authorize(money, payment_method, options)
30
- response << capture(money, response.authorization, :authorization_validated => true) if response.success?
30
+ response << capture(money, response.authorization, options.merge(:authorization_validated => true)) if response.success?
31
31
  response
32
32
  end
33
33
 
@@ -1,4 +1,4 @@
1
- require_library_or_gem 'action_pack'
1
+ require 'action_pack'
2
2
 
3
3
  module ActiveMerchant #:nodoc:
4
4
  module Billing #:nodoc:
@@ -57,7 +57,11 @@ module ActiveMerchant #:nodoc:
57
57
  service.form_fields.each do |field, value|
58
58
  result << hidden_field_tag(field, value)
59
59
  end
60
-
60
+
61
+ service.raw_html_fields.each do |field, value|
62
+ result << "<input id=\"#{field}\" name=\"#{field}\" type=\"hidden\" value=\"#{value}\" />\n"
63
+ end
64
+
61
65
  result << '</form>'
62
66
  result= result.join("\n")
63
67
 
@@ -0,0 +1,228 @@
1
+ require 'active_support/core_ext/float/rounding.rb' # Float#round(precision)
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
+ module Integrations #:nodoc:
6
+ module AuthorizeNetSim
7
+ # An example. Note the username as a parameter and transaction key you
8
+ # will want to use later. The amount that you pass in will be *rounded*,
9
+ # so preferably pass in X.2 decimal so that no rounding occurs. It is
10
+ # rounded because if it looks like 00.000 Authorize.Net fails the
11
+ # transaction as incorrectly formatted.
12
+ #
13
+ # payment_service_for('order_id', 'authorize_net_account', :service => :authorize_net_sim, :amount => 157.0) do |service|
14
+ #
15
+ # # You must call setup_hash and invoice
16
+ #
17
+ # service.setup_hash :transaction_key => '8CP6zJ7uD875J6tY',
18
+ # :order_timestamp => 1206836763
19
+ # service.customer_id 8
20
+ # service.customer :first_name => 'g',
21
+ # :last_name => 'g',
22
+ # :email => 'g@g.com',
23
+ # :phone => '3'
24
+ # service.billing_address :zip => 'g',
25
+ # :country => 'United States of America',
26
+ # :address => 'g'
27
+ #
28
+ # service.ship_to_address :first_name => 'g',
29
+ # :last_name => 'g',
30
+ # :city => '',
31
+ # :address => 'g',
32
+ # :address2 => '',
33
+ # :state => address.state,
34
+ # :country => 'United States of America',
35
+ # :zip => 'g'
36
+ #
37
+ # service.invoice "516428355" # your invoice number
38
+ # # The end-user is presented with the HTML produced by the notify_url.
39
+ # service.notify_url "http://t/authorize_net_sim/payment_received_notification_sub_step"
40
+ # service.payment_header 'My store name'
41
+ # service.add_line_item :name => 'item name', :quantity => 1, :unit_price => 0
42
+ # service.test_request 'true' # only if it's just a test
43
+ # service.shipping '25.0'
44
+ # # Tell it to display a "0" line item for shipping, with the price in
45
+ # # the name, otherwise it isn't shown at all, leaving the end user to
46
+ # # wonder why the total is different than the sum of the line items.
47
+ # service.add_shipping_as_line_item
48
+ # server.add_tax_as_line_item # same with tax
49
+ # # See the helper.rb file for various custom fields
50
+ # end
51
+
52
+ class Helper < ActiveMerchant::Billing::Integrations::Helper
53
+ mapping :order, 'x_fp_sequence'
54
+ mapping :account, 'x_login'
55
+
56
+ mapping :customer, :first_name => 'x_first_name',
57
+ :last_name => 'x_last_name',
58
+ :email => 'x_email',
59
+ :phone => 'x_phone'
60
+
61
+ mapping :notify_url, 'x_relay_url'
62
+ mapping :return_url, '' # unused
63
+ mapping :cancel_return_url, '' # unused
64
+
65
+ # Custom fields for Authorize.net SIM.
66
+ # See http://www.Authorize.Net/support/SIM_guide.pdf for more descriptions.
67
+ mapping :fax, 'x_fax'
68
+ mapping :customer_id, 'x_cust_id'
69
+ mapping :description, 'x_description'
70
+ mapping :tax, 'x_tax'
71
+ mapping :shipping, 'x_freight'
72
+
73
+ # True or false, or 0 or 1 same effect [not required to send one,
74
+ # defaults to false].
75
+ mapping :test_request, 'x_test_request'
76
+
77
+ # This one is necessary for the notify url to be able to parse its
78
+ # information later! They also pass back customer id, if that's
79
+ # useful.
80
+ def invoice(number)
81
+ add_field 'x_invoice_num', number
82
+ end
83
+
84
+ # Set the billing address. Call like service.billing_address {:city =>
85
+ # 'provo, :state => 'UT'}...
86
+ def billing_address(options)
87
+ for setting in [:city, :state, :zip, :country, :po_num] do
88
+ add_field 'x_' + setting.to_s, options[setting]
89
+ end
90
+ raise 'must use address1 and address2' if options[:address]
91
+ add_field 'x_address', (options[:address1].to_s + ' ' + options[:address2].to_s).strip
92
+ end
93
+
94
+ # Adds a custom field which you submit to Authorize.Net. These fields
95
+ # are all passed back to you verbatim when it does its relay
96
+ # (callback) to you note that if you call it twice with the same name,
97
+ # this function only uses keeps the second value you called it with.
98
+ def add_custom_field(name, value)
99
+ add_field name, value
100
+ end
101
+
102
+ # Displays tax as a line item, so they can see it. Otherwise it isn't
103
+ # displayed.
104
+ def add_tax_as_line_item
105
+ raise unless @fields['x_tax']
106
+ add_line_item :name => 'Total Tax', :quantity => 1, :unit_price => @fields['x_tax'], :tax => 0, :line_title => 'Tax'
107
+ end
108
+
109
+ # Displays shipping as a line item, so they can see it. Otherwise it
110
+ # isn't displayed.
111
+ def add_shipping_as_line_item(extra_options = {})
112
+ raise 'must set shipping/freight before calling this' unless @fields['x_freight']
113
+ add_line_item extra_options.merge({:name => 'Shipping and Handling Cost', :quantity => 1, :unit_price => @fields['x_freight'], :line_title => 'Shipping'})
114
+ end
115
+
116
+ # Add ship_to_address in the same format as the normal address is
117
+ # added.
118
+ def ship_to_address(options)
119
+ for setting in [:first_name, :last_name, :company, :city, :state, :zip, :country] do
120
+ if options[setting] then
121
+ add_field 'x_ship_to_' + setting.to_s, options[setting]
122
+ end
123
+ end
124
+ raise 'must use :address1 and/or :address2' if options[:address]
125
+ add_field 'x_ship_to_address', (options[:address1].to_s + ' ' + options[:address2].to_s).strip
126
+ end
127
+
128
+ # These control the look of the SIM payment page. Note that you can
129
+ # include a CSS header in descriptors, etc.
130
+ mapping :color_link, 'x_color_link'
131
+ mapping :color_text, 'x_color_text'
132
+ mapping :logo_url, 'x_logo_url'
133
+ mapping :background_url, 'x_background_url' # background image url for the page
134
+ mapping :payment_header, 'x_header_html_payment_form'
135
+ mapping :payment_footer, 'x_footer_html_payment_form'
136
+
137
+ # For this to work you must have also passed in an email for the
138
+ # purchaser.
139
+ def yes_email_customer_from_authorizes_side
140
+ add_field 'x_email_customer', 'TRUE'
141
+ end
142
+
143
+ # Add a line item to Authorize.Net.
144
+ # Call line add_line_item {:name => 'orange', :unit_price => 30, :tax_value => 'Y', :quantity => 3, }
145
+ # Note you can't pass in a negative unit price, and you can add an
146
+ # optional :line_title => 'special name' if you don't want it to say
147
+ # 'Item 1' or what not, the default coded here.
148
+ # Cannot have a negative price, nor a name with "'s or $
149
+ # You can use the :line_title for the product name and then :name for description, if desired
150
+ def add_line_item(options)
151
+ raise 'needs name' unless options[:name]
152
+
153
+ if @line_item_count == 30
154
+ # Add a note that we are not showing at least one -- AN doesn't
155
+ # display more than 30 or so.
156
+ description_of_last = @raw_html_fields[-1][1]
157
+ # Pull off the second to last section, which is the description.
158
+ description_of_last =~ />([^>]*)<\|>[YN]$/
159
+ # Create a new description, which can't be too big, so truncate here.
160
+ @raw_html_fields[-1][1] = description_of_last.gsub($1, $1[0..200] + ' + more unshown items after this one.')
161
+ end
162
+
163
+ name = options[:name]
164
+ quantity = options[:quantity] || 1
165
+ line_title = options[:line_title] || ('Item ' + (@line_item_count + 1).to_s) # left most field
166
+ unit_price = options[:unit_price] || 0
167
+ unit_price = unit_price.to_f.round(2)
168
+ tax_value = options[:tax_value] || 'N'
169
+
170
+ # Sanitization, in case they include a reserved word here, following
171
+ # their guidelines; unfortunately, they require 'raw' fields here,
172
+ # not CGI escaped, using their own delimiters.
173
+ #
174
+ # Authorize.net ignores the second field (sanitized_short_name)
175
+ raise 'illegal char for line item <|>' if name.include? '<|>'
176
+ raise 'illegal char for line item "' if name.include? '"'
177
+ raise 'cannot pass in dollar sign' if unit_price.to_s.include? '$'
178
+ raise 'must have positive or 0 unit price' if unit_price.to_f < 0
179
+ # Using CGI::escape causes the output to be formated incorrectly in
180
+ # the HTML presented to the end-user's browser (e.g., spaces turn
181
+ # into +'s).
182
+ sanitized_short_name = name[0..30]
183
+ name = name[0..255]
184
+
185
+ add_raw_html_field "x_line_item", "#{line_title}<|>#{sanitized_short_name}<|>#{name}<|>#{quantity}<|>#{unit_price}<|>#{tax_value}"
186
+
187
+ @line_item_count += 1
188
+ end
189
+
190
+ # If you call this it will e-mail to this address a copy of a receipt
191
+ # after successful, from Authorize.Net.
192
+ def email_merchant_from_authorizes_side(to_this_email)
193
+ add_field 'x_email_merchant', to_this_email
194
+ end
195
+
196
+ # You MUST call this at some point for it to actually work. Options
197
+ # must include :transaction_key and :order_timestamp
198
+ def setup_hash(options)
199
+ raise unless options[:transaction_key]
200
+ raise unless options[:order_timestamp]
201
+ amount = @fields['x_amount']
202
+ data = "#{@fields['x_login']}^#{@fields['x_fp_sequence']}^#{options[:order_timestamp].to_i}^#{amount}^#{@fields['x_currency_code']}"
203
+ hmac = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new('md5'), options[:transaction_key], data)
204
+ add_field 'x_fp_hash', hmac
205
+ add_field 'x_fp_timestamp', options[:order_timestamp].to_i
206
+ end
207
+
208
+ # Note that you should call #invoice and #setup_hash as well, for the
209
+ # response_url to actually work.
210
+ def initialize(order, account, options = {})
211
+ super
212
+ raise 'missing parameter' unless order and account and options[:amount]
213
+ raise 'error -- amount with no digits!' unless options[:amount].to_s =~ /\d/
214
+ add_field('x_type', 'AUTH_CAPTURE') # the only one we deal with, for now. Not refunds or anything else, currently.
215
+ add_field 'x_show_form', 'PAYMENT_FORM'
216
+ add_field 'x_relay_response', 'TRUE'
217
+ add_field 'x_duplicate_window', '28800' # large default duplicate window.
218
+ add_field 'x_currency_code', currency_code
219
+ add_field 'x_version' , '3.1' # version from doc
220
+ add_field 'x_amount', options[:amount].to_f.round(2)
221
+ @line_item_count = 0
222
+ end
223
+
224
+ end
225
+ end
226
+ end
227
+ end
228
+ end