My favorites | Sign in
Project Home Downloads Wiki Issues Source
READ-ONLY: This project has been archived. For more information see this post.
Search
for
  Advanced search   Search tips   Subscriptions

Issue 34 attachment: add_authorize_net_sim.diff (16.9 KB)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
Index: plugins/substruct/app/helpers/store_helper.rb
===================================================================
--- plugins/substruct/app/helpers/store_helper.rb (revision 0)
+++ plugins/substruct/app/helpers/store_helper.rb (revision 0)
@@ -0,0 +1,13 @@
+module StoreHelper
+ # helper function for authorize.net sim
+ def generate_authorize_net_sim_fp_hash cart
+ require 'hmac-md5' # requires gem ruby-hmac
+ txnkey = Preference.get_value('cc_pass')
+ api_login_id = Preference.get_value('cc_login')
+ hmac = HMAC::MD5.new txnkey
+ currency_code = '' # if you ever use currency_code, it may be necessary to account for it on the relay url, too
+ hmac.update "#{api_login_id}^#{cart.id}^#{cart.created_on.to_i}^#{cart.total}^#{currency_code}"
+ hmac.to_s
+ end
+
+end
Index: plugins/substruct/app/models/preference.rb
===================================================================
--- plugins/substruct/app/models/preference.rb (revision 43)
+++ plugins/substruct/app/models/preference.rb (working copy)
@@ -9,7 +9,7 @@
class Preference < ActiveRecord::Base
# Types can hold strings, booleans, or pointers to
# other records (like country)
- CC_PROCESSORS = ['Authorize.net', 'PayPal IPN']
+ CC_PROCESSORS = ['Authorize.net', 'PayPal IPN', 'Authorize.net SIM (off-site)']
MAIL_AUTH = ['none', 'plain', 'login', 'cram_md5']
validates_presence_of :name, :type
validates_uniqueness_of :name
@@ -51,4 +51,10 @@
end
return false
end
+
+ # gets a preference's value
+ def self.get_value name
+ return self.find_by_name(name).value
+ end
+
end
\ No newline at end of file
Index: plugins/substruct/app/models/order.rb
===================================================================
--- plugins/substruct/app/models/order.rb (revision 43)
+++ plugins/substruct/app/models/order.rb (working copy)
@@ -469,13 +469,13 @@
cc_processor = Order.get_cc_processor
if cc_processor == Preference::CC_PROCESSORS[0]
run_transaction_authorize
- elsif cc_processor == Preference::CC_PROCESSORS[1]
+ elsif cc_processor == Preference::CC_PROCESSORS[1] or cc_processor == Preference::CC_PROCESSORS[2]
run_transaction_paypal_ipn
else
throw "The currently set preference for cc_processor is not recognized. You might want to add it to the code..."
end
- end
-
+ end
+
# Check to see which cc processor is used
def self.get_cc_processor
Preference.find_by_name('cc_processor').value
@@ -494,7 +494,7 @@
ba = self.billing_address

# For debugging with a test account...
- # ActiveMerchant::Billing::Base.mode = :test
+ ActiveMerchant::Billing::Base.mode = :test if Preference.find_by_name('store_use_test_cc_submission_urls').is_true?

credit_card = ActiveMerchant::Billing::CreditCard.new(
:number => self.account.cc_number,
Index: plugins/substruct/app/controllers/store_controller.rb
===================================================================
--- plugins/substruct/app/controllers/store_controller.rb (revision 43)
+++ plugins/substruct/app/controllers/store_controller.rb (working copy)
@@ -288,6 +288,13 @@
@title = "Please confirm your order. - Step 3 of 3"
@cc_login = Order.get_cc_login
@paypal_url = Paypal.service_url
+
+ if Preference.find_by_name('store_use_test_cc_submission_urls').is_true?
+ @authorize_net_sim_url = 'https://test.authorize.net/gateway/transact.dll' # requires testing account login/pass
+ else
+ @authorize_net_sim_url = 'https://secure.authorize.net/gateway/transact.dll'
+ end
+
# Make sure a shipping method is set
if @order.order_shipping_type_id == nil
redirect_to_shipping and return
@@ -304,15 +311,15 @@
if order_success == true
@payment_message = "Card processed successfully"
clear_cart_and_order(false)
- elsif cc_processor == Preference::CC_PROCESSORS[1]
+ elsif cc_processor == Preference::CC_PROCESSORS[1] or cc_processor == Preference::CC_PROCESSORS[2]
+ processor_name = cc_processor.split(" ")[0]
case order_success
when 4
- @payment_message = %q\
- Your order has been processed at PayPal but we
+ @payment_message =
+ "Your order has been processed at #{processor_name} but we
have not heard back from them yet. Your order
will be ready to ship as soon as we receive
- confirmation of your payment.
- \
+ confirmation of your payment.".join("")
clear_cart_and_order(false)
when 5
@payment_message = "Transaction processed successfully"
Index: plugins/substruct/app/controllers/order_helper.rb
===================================================================
--- plugins/substruct/app/controllers/order_helper.rb (revision 43)
+++ plugins/substruct/app/controllers/order_helper.rb (working copy)
@@ -76,7 +76,7 @@
@shipping_address.valid?
end

- unless Order.get_cc_processor == Preference::CC_PROCESSORS[1]
+ if Order.get_cc_processor == Preference::CC_PROCESSORS[0]
@order_account = OrderAccount.new(params[:order_account])
else
# PayPal is collecting the credit card info, so stuff a bogus one
Index: plugins/substruct/app/controllers/authorize_net_sim_controller.rb
===================================================================
--- plugins/substruct/app/controllers/authorize_net_sim_controller.rb (revision 0)
+++ plugins/substruct/app/controllers/authorize_net_sim_controller.rb (revision 0)
@@ -0,0 +1,70 @@
+class AuthorizeNetSimController < ApplicationController
+ MD5_HASH_SET_IN_AUTHORIZE_NET = '' # requires restart. This is the value set within authorize.net as your "md5 hash" and defaults to blank if you haven't set one yet.
+
+ def payment_received_notification_sub_step
+
+ passed = params['x_response_code'].to_i == 1
+
+ order = Order.find_by_order_number params['x_invoice_num'],
+ :include => :shipping_address
+ unless order
+ @message = 'Error--unable to find your transaction! Please contact us directly.'
+ return render :partial => '/store/authorize_net_sim_payment_response'
+ end
+
+ # todo integrate AVS (?)
+ # todo double check if they changed any address information (just in case the user didn't set it up for that to be unchangeable, which would, of course, be much better)
+ if order.total != params['x_amount'].to_f
+ logger.error "ack authorize net sim said they paid for #{params['x_amount']} and it should have been #{order.total}!"
+ passed = false
+ end
+
+ existing_order = Order.find_by_auth_transaction_id(params['x_trans_id'])
+
+ if existing_order
+ logger.error "odd -- authorize.net SIM got a duplicate transaction!" # still allow it to pass--why not?
+ end
+
+ md5_hash_check = Digest::MD5.hexdigest(MD5_HASH_SET_IN_AUTHORIZE_NET + Preference.get_value('cc_login') + params['x_trans_id'] + params['x_amount'])
+
+ if md5_hash_check.upcase != params['x_MD5_Hash']
+ passed = false
+ logger.error "ALERT POSSIBLE FRAUD ATTEMPT either that or you haven't setup your md5 hash setting in #{__FILE__} because a transaction came back from authorize.net with the wrong hash value--rejecting!"
+ end
+
+ order.auth_transaction_id = params['x_trans_id']
+
+ # could refactor this with paypal (combine)
+ if passed
+ order.order_status_code_id = 5 # passed
+ order.new_notes = "Your order paid through Authorize.net SIM. Ready to ship."
+ # Set completed
+ order.cleanup_successful
+ # Send success message
+ begin
+ order.deliver_receipt # sends the emails right
+ rescue => e
+ logger.error("FAILED TO SEND THE CONFIRM EMAIL")
+ end
+ order.save
+ else
+ message = "FRAUD ALERT -- please investigate." + params.inspect
+ log.error params.inspect + " seemed to have failed authorize.net sim"
+ order.order_status_code_id = 3
+ order.new_notes = message
+ order.cleanup_failed(message)
+ # Send failed message
+ begin
+ order.deliver_failed
+ rescue => e
+ logger.error("FAILED TO SEND THE CONFIRM EMAIL")
+ end
+ order.save
+ end
+
+ @message = order.notes
+ @order = order
+ render :partial => 'store/authorize_net_sim_payment_response'
+ end
+
+end
\ No newline at end of file
Index: plugins/substruct/app/views/admin/preferences/index.rhtml
===================================================================
--- plugins/substruct/app/views/admin/preferences/index.rhtml (revision 43)
+++ plugins/substruct/app/views/admin/preferences/index.rhtml (working copy)
@@ -65,14 +65,22 @@
<h2>Credit Card Processing</h2>

<div class="padLeft">
- <p>
+ <p>
<label>
<%= check_box_tag('prefs[store_test_transactions]', 1, (@prefs['store_test_transactions'].is_true?)) %>
Store is in test mode
</label>
- <span class="info">When in test mode, no real orders will be processed.</span>
+ <span class="info">When in test mode, no real orders will be processed. Authorize.net will pass the "testing" flag and paypal will require sandbox (developer) accounts.</span>
<input name="prefs[store_test_transactions]" type="hidden" value="0" />
</p>
+ <p>
+ <label>
+ <%= check_box_tag('prefs[store_use_test_cc_submission_urls]', 1, (@prefs['store_use_test_cc_submission_urls'].is_true?)) %>
+ authorize.net use test (developer) credit card transaction urls.
+ </label>
+ <span class="info">Check this if you wish to use an authorize.net test account (will use authorize.net test url's).</span>
+ <input name="prefs[store_use_test_cc_submission_urls]" type="hidden" value="0" />
+ </p>
<p>
<%= make_label('Processor', true) %>
<%= select_tag('prefs[cc_processor]', options_for_select(Preference::CC_PROCESSORS, @prefs['cc_processor'].value)) %>
Index: plugins/substruct/app/views/store/_authorize_net_sim_cart.rhtml
===================================================================
--- plugins/substruct/app/views/store/_authorize_net_sim_cart.rhtml (revision 0)
+++ plugins/substruct/app/views/store/_authorize_net_sim_cart.rhtml (revision 0)
@@ -0,0 +1,66 @@
+<%
+ address = cart.billing_address
+ shipping = cart.shipping_address
+ for setting, value in {
+ 'x_fp_hash' => generate_authorize_net_sim_fp_hash(cart), # our 'secure' hash of the transaction
+ 'x_login' => Preference.get_value('cc_login'),
+ 'x_show_form' => 'PAYMENT_FORM',
+ 'x_amount' => cart.total,
+ 'x_fp_timestamp' => cart.created_on.to_i,
+ 'x_fp_sequence' => cart.id,
+ 'x_relay_response' => 'TRUE',
+ 'x_duplicate_window' => '28800', # that many seconds of duplicate window
+ 'x_relay_url' => url_for(:only_path => false, :controller => :authorize_net_sim, :action => :payment_received_notification_sub_step), # this value [http://hostname/authorize_net_sim/payment_received_notification_sub_step] must be setup within authorize.net, too, to be accepted.
+ 'x_address' => address.address,
+ 'x_first_name' => address.first_name,
+ 'x_last_name' => address.last_name,
+ 'x_city' => address.city,
+ 'x_state' => address.state,
+ 'x_country' => address.country.name,
+ 'x_zip' => address.zip,
+ 'x_phone' => address.telephone,
+ 'x_ship_to_first_name' => shipping.first_name,
+ 'x_ship_to_last_name' => shipping.last_name,
+ 'x_ship_to_address' => shipping.address,
+ 'x_ship_to_city' => shipping.city,
+ 'x_ship_to_state' => shipping.state,
+ 'x_ship_to_zip' => shipping.zip,
+ 'x_ship_to_country' => shipping.country.name,
+ 'x_cust_id' => cart.order_user.id,
+ #x_currency_code
+ 'x_email' => cart.order_user.email_address,
+# 'x_email_customer' => '', # email after transaction success
+# 'x_email_merchant' => '', # add in your email if you want authorize to email you. For now we email them if set in prefs.
+ 'x_invoice_num' => cart.order_number,
+ 'x_header_html_payment_form' => Preference.get_value('store_name'),
+
+ } do %>
+ <INPUT TYPE=HIDDEN name="<%= setting %>" VALUE="<%= value %>">
+<% end %>
+
+<%
+taxable = cart.tax > 0 ? 'Y' : 'N'
+
+cart.order_line_items[0..27].each_with_index do |oli, n|
+ name = h(oli.name) %>
+ <INPUT TYPE=HIDDEN name="x_line_item" value="<%="#{name}<|>#{name}<|>#{oli.item ? oli.item.description : "(Promo) #{oli.price}"}#{n == 27 ? 'MORE UNSHOWN ITEMS....' : ''}<|>#{oli.quantity}<|>#{oli.price.abs}<|>#{taxable}" %>">
+<% end %>
+
+<% if Preference.find_by_name('store_test_transactions').is_true? %>
+ <INPUT TYPE=HIDDEN NAME="x_test_request" VALUE="TRUE">
+<% end %>
+
+
+<% if cart.shipping_cost > 0 %>
+ <INPUT TYPE=HIDDEN name='x_freight' VALUE="<%= cart.shipping_cost %>"/> <!-- doesn't seem to work with single values, so we'll add a line item for it -->
+ <INPUT TYPE=HIDDEN name="x_line_item" value="<%="Shipping<|>Shipping Cost<|>Shipping Cost<|>1<|>#{cart.shipping_cost}<|>#{taxable}" %>">
+<% end %>
+
+
+<% tax_amount = cart.tax
+ if tax_amount > 0 %>
+ <INPUT TYPE=HIDDEN name='x_tax' VALUE="<%= tax_amount %>"/> <!-- add as line item, too- see above -->
+ <INPUT TYPE=HIDDEN name="x_line_item" value="<%="Tax<|>Tax<|>Total tax<|>1<|>#{tax_amount}<|>N" %>">
+ <% end %>
+
+<%# see http://www.authorize.net/support/SIM_guide.pdf for lots of optional texts/logos you can display besides these %>
Index: plugins/substruct/app/views/store/_authorize_net_sim_payment_response.rhtml
===================================================================
--- plugins/substruct/app/views/store/_authorize_net_sim_payment_response.rhtml (revision 0)
+++ plugins/substruct/app/views/store/_authorize_net_sim_payment_response.rhtml (revision 0)
@@ -0,0 +1,11 @@
+<head>
+ <!-- note that it redirects automatically for most, so they'll never really see this page -->
+ <% if @order.order_status_code_id == 5 # then it was successful, so forward them on to the status page %>
+ <SCRIPT LANGUAGE="JavaScript">
+ window.location="<%= url_for(:only_path => false, :controller => :store, :action => :finish_order) %>";
+ </script>
+ <% end %>
+</head>
+
+<!-- the user never really sees this message it just flashes on their screen (relayed from us), and redirects them back to the site -->
+Thank you for your purchase to <%= Preference.find_by_name('store_name').value %>! <%= @message %>. Click <a href="<%= url_for(:only_path => false, :controller => :store, :action => :finish_order) %>">here</a> to continue and view your order status.
\ No newline at end of file
Index: plugins/substruct/app/views/store/checkout.rhtml
===================================================================
--- plugins/substruct/app/views/store/checkout.rhtml (revision 43)
+++ plugins/substruct/app/views/store/checkout.rhtml (working copy)
@@ -71,7 +71,7 @@


<!-- PAYMENT INFORMATION -->
- <% if @cc_processor != 'PayPal IPN' -%>
+ <% if @cc_processor == Preference::CC_PROCESSORS[0] -%>
<div class="form_block">
<%= render(:partial => '/admin/orders/account') %>
</div>
Index: plugins/substruct/app/views/store/confirm_order.rhtml
===================================================================
--- plugins/substruct/app/views/store/confirm_order.rhtml (revision 43)
+++ plugins/substruct/app/views/store/confirm_order.rhtml (working copy)
@@ -2,22 +2,24 @@

<h1><%= @title %></h1>

-<% if Order.get_cc_processor == 'PayPal IPN' -%>
+<% if Order.get_cc_processor == Preference::CC_PROCESSORS[1] -%>
<form action="<%= @paypal_url %>" method="POST">
<%= render(:partial => 'paypal_cart', :locals => {:cart => @order}) %>
-<% else -%>
+<% elsif Order.get_cc_processor == Preference::CC_PROCESSORS[2] -%>
+ <form action="<%= @authorize_net_sim_url %>" method='POST'>
+ <%= render(:partial => 'authorize_net_sim_cart', :locals => {:cart => @order}) %>
+<% else %>
<%= form_tag :action => 'finish_order' %>
<% end -%>

<div class="padLeft">
<%= render(:partial => 'cart_contents', :locals => {:cart => @order}) %>
-
<br/>

<div class="line"></div>

<p>
- <%= submit_tag "Submit Your Order", :class => 'button', :id => 'submit_button', :disable_with => 'Submitting, please wait...' %>
+ <%= submit_tag Order.get_cc_processor == Preference::CC_PROCESSORS[0] ? "Submit Your Order" : "Pay securely with #{Order.get_cc_processor.split(' ')[0]}", :class => 'button', :id => 'submit_button', :disable_with => 'Submitting, please wait...' %>
</p>
</div>

@@ -29,9 +31,13 @@
<p>
Please make sure your order is correct before continuing.
</p>
- <p>
- After pressing the <i>Submit Your Order</i> button on this page you will be charged for the item(s) shown.
- </p>
+ <p>
+ <% if Order.get_cc_processor == Preference::CC_PROCESSORS[0] %>
+ After pressing the <i>Submit Your Order</i> button on this page you will be charged for the item(s) shown.
+ <% else %>
+ After pressing the order button on this page you will be redirected to pay for your purchase, then returned to the site.
+ <% end %>
+ </p>

<%= render :partial => 'clear_cart' %>
</div>
Powered by Google Project Hosting