refinerycms-stores 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (116) hide show
  1. data/Gemfile +26 -0
  2. data/Gemfile.lock +306 -0
  3. data/Guardfile +27 -0
  4. data/LICENSE.txt +20 -0
  5. data/Rakefile +65 -0
  6. data/VERSION +1 -0
  7. data/app/assets/stylesheets/refinery/refinerycms-stores.sass +76 -0
  8. data/app/controllers/refinery/addresses/admin/addresses_controller.rb +12 -0
  9. data/app/controllers/refinery/orders/admin/orders_controller.rb +12 -0
  10. data/app/controllers/refinery/orders/orders_controller.rb +96 -0
  11. data/app/controllers/refinery/products/admin/products_controller.rb +12 -0
  12. data/app/controllers/refinery/products/products_controller.rb +17 -0
  13. data/app/controllers/refinery/stores/admin/stores_controller.rb +12 -0
  14. data/app/controllers/refinery/stores/stores_controller.rb +80 -0
  15. data/app/helpers/refinery/orders/orders_helper.rb +11 -0
  16. data/app/models/refinery/addresses/address.rb +12 -0
  17. data/app/models/refinery/orders/line_item.rb +24 -0
  18. data/app/models/refinery/orders/order.rb +364 -0
  19. data/app/models/refinery/products/product.rb +17 -0
  20. data/app/models/refinery/stores/store.rb +33 -0
  21. data/app/views/refinery/addresses/admin/addresses/_actions.html.erb +25 -0
  22. data/app/views/refinery/addresses/admin/addresses/_address.html.erb +16 -0
  23. data/app/views/refinery/addresses/admin/addresses/_addresses.html.erb +2 -0
  24. data/app/views/refinery/addresses/admin/addresses/_form.html.erb +89 -0
  25. data/app/views/refinery/addresses/admin/addresses/_records.html.erb +18 -0
  26. data/app/views/refinery/addresses/admin/addresses/_sortable_list.html.erb +5 -0
  27. data/app/views/refinery/addresses/admin/addresses/edit.html.erb +1 -0
  28. data/app/views/refinery/addresses/admin/addresses/index.html.erb +7 -0
  29. data/app/views/refinery/addresses/admin/addresses/new.html.erb +1 -0
  30. data/app/views/refinery/orders/admin/orders/_actions.html.erb +25 -0
  31. data/app/views/refinery/orders/admin/orders/_form.html.erb +122 -0
  32. data/app/views/refinery/orders/admin/orders/_order.html.erb +20 -0
  33. data/app/views/refinery/orders/admin/orders/_orders.html.erb +2 -0
  34. data/app/views/refinery/orders/admin/orders/_records.html.erb +18 -0
  35. data/app/views/refinery/orders/admin/orders/_sortable_list.html.erb +5 -0
  36. data/app/views/refinery/orders/admin/orders/edit.html.erb +1 -0
  37. data/app/views/refinery/orders/admin/orders/index.html.erb +7 -0
  38. data/app/views/refinery/orders/admin/orders/new.html.erb +1 -0
  39. data/app/views/refinery/orders/orders/_address_form.html.haml +35 -0
  40. data/app/views/refinery/orders/orders/_card_form.html.haml +63 -0
  41. data/app/views/refinery/orders/orders/_order_snapshot.html.haml +44 -0
  42. data/app/views/refinery/orders/orders/confirmation.html.haml +26 -0
  43. data/app/views/refinery/orders/orders/edit.html.haml +36 -0
  44. data/app/views/refinery/orders/orders/index.html.haml +6 -0
  45. data/app/views/refinery/orders/orders/purchase.html.haml +25 -0
  46. data/app/views/refinery/orders/orders/show.html.haml +36 -0
  47. data/app/views/refinery/products/admin/products/_actions.html.erb +25 -0
  48. data/app/views/refinery/products/admin/products/_form.html.erb +127 -0
  49. data/app/views/refinery/products/admin/products/_product.html.erb +20 -0
  50. data/app/views/refinery/products/admin/products/_products.html.erb +2 -0
  51. data/app/views/refinery/products/admin/products/_records.html.erb +18 -0
  52. data/app/views/refinery/products/admin/products/_sortable_list.html.erb +5 -0
  53. data/app/views/refinery/products/admin/products/edit.html.erb +4 -0
  54. data/app/views/refinery/products/admin/products/index.html.erb +10 -0
  55. data/app/views/refinery/products/admin/products/new.html.erb +4 -0
  56. data/app/views/refinery/products/products/show.html.erb +105 -0
  57. data/app/views/refinery/stores/admin/stores/_actions.html.erb +57 -0
  58. data/app/views/refinery/stores/admin/stores/_form.html.erb +56 -0
  59. data/app/views/refinery/stores/admin/stores/_records.html.erb +18 -0
  60. data/app/views/refinery/stores/admin/stores/_sortable_list.html.erb +5 -0
  61. data/app/views/refinery/stores/admin/stores/_store.html.erb +20 -0
  62. data/app/views/refinery/stores/admin/stores/_stores.html.erb +2 -0
  63. data/app/views/refinery/stores/admin/stores/edit.html.erb +4 -0
  64. data/app/views/refinery/stores/admin/stores/index.html.erb +13 -0
  65. data/app/views/refinery/stores/admin/stores/new.html.erb +4 -0
  66. data/app/views/refinery/stores/stores/_cart.html.erb +22 -0
  67. data/app/views/refinery/stores/stores/_cart_item.html.erb +9 -0
  68. data/app/views/refinery/stores/stores/_list_product.html.erb +16 -0
  69. data/app/views/refinery/stores/stores/index.html.erb +11 -0
  70. data/app/views/refinery/stores/stores/show.html.erb +28 -0
  71. data/config/locales/en.yml +143 -0
  72. data/config/locales/es.yml +143 -0
  73. data/config/locales/fr.yml +139 -0
  74. data/config/locales/nb.yml +143 -0
  75. data/config/locales/nl.yml +143 -0
  76. data/config/routes.rb +81 -0
  77. data/db/migrate/1_create_stores_stores.rb +29 -0
  78. data/db/migrate/2_create_products_products.rb +44 -0
  79. data/db/migrate/3_create_orders_orders.rb +44 -0
  80. data/db/migrate/4_create_orders_line_items.rb +20 -0
  81. data/db/migrate/5_create_addresses_addresses.rb +39 -0
  82. data/db/seeds.rb +23 -0
  83. data/lib/generators/refinery/stores_generator.rb +17 -0
  84. data/lib/refinery/addresses/engine.rb +31 -0
  85. data/lib/refinery/addresses.rb +21 -0
  86. data/lib/refinery/cart.rb +36 -0
  87. data/lib/refinery/cart_item.rb +28 -0
  88. data/lib/refinery/orders/engine.rb +31 -0
  89. data/lib/refinery/orders.rb +21 -0
  90. data/lib/refinery/products/engine.rb +31 -0
  91. data/lib/refinery/products.rb +21 -0
  92. data/lib/refinery/store_gateway.rb +106 -0
  93. data/lib/refinery/stores/engine.rb +31 -0
  94. data/lib/refinery/stores.rb +21 -0
  95. data/lib/refinerycms-stores.rb +7 -0
  96. data/lib/tasks/refinery/stores.rake +13 -0
  97. data/readme.md +10 -0
  98. data/refinerycms-stores.gemspec +261 -0
  99. data/spec/models/refinery/addresses/address_spec.rb +18 -0
  100. data/spec/models/refinery/orders/order_spec.rb +18 -0
  101. data/spec/models/refinery/products/product_spec.rb +18 -0
  102. data/spec/models/refinery/stores/store_spec.rb +18 -0
  103. data/spec/requests/refinery/addresses/admin/addresses_spec.rb +101 -0
  104. data/spec/requests/refinery/orders/admin/orders_spec.rb +101 -0
  105. data/spec/requests/refinery/products/admin/products_spec.rb +101 -0
  106. data/spec/requests/refinery/stores/admin/stores_spec.rb +101 -0
  107. data/spec/spec_helper.rb +53 -0
  108. data/spec/support/factories/refinery/addresses.rb +7 -0
  109. data/spec/support/factories/refinery/orders.rb +7 -0
  110. data/spec/support/factories/refinery/products.rb +7 -0
  111. data/spec/support/factories/refinery/stores.rb +7 -0
  112. data/tasks/rspec.rake +6 -0
  113. data/tasks/testing.rake +8 -0
  114. data/test/helper.rb +17 -0
  115. data/test/test_refinerycms-cart.rb +7 -0
  116. metadata +571 -0
@@ -0,0 +1,80 @@
1
+ module Refinery
2
+ module Stores
3
+ class StoresController < ::ApplicationController
4
+
5
+ before_filter :find_all_stores, :only => :index
6
+ before_filter :find_page, :except => [:index, :add_to_cart, :empty_cart, :checkout]
7
+ before_filter :find_cart, :except => :empty_cart
8
+
9
+ def index
10
+ # you can use meta fields from your model instead (e.g. browser_title)
11
+ # by swapping @page for @store in the line below:
12
+ present(@page)
13
+ end
14
+
15
+ def show
16
+ @store = Store.find(params[:id])
17
+
18
+ # you can use meta fields from your model instead (e.g. browser_title)
19
+ # by swapping @page for @store in the line below:
20
+ present(@page)
21
+ end
22
+
23
+ def add_to_cart
24
+ begin
25
+ product = ::Refinery::Products::Product.find(params[:id])
26
+ rescue ActiveRecord::RecordNotFound
27
+ logger.error("Attempt to access invalid product #{params[:id]}")
28
+ redirect_to_index("Invalid product")
29
+ else
30
+ @current_item = @cart.add_product(product)
31
+ redirect_to_index unless request.xhr?
32
+ end
33
+ end
34
+
35
+ def empty_cart
36
+ session[:cart] = nil
37
+ redirect_to_index
38
+ end
39
+
40
+
41
+ def checkout
42
+ if @cart.items.empty?
43
+ redirect_to_index("Your cart is empty")
44
+ else
45
+ @order = ::Refinery::Orders::Order.checkout!( @cart )
46
+ session[:cart] = nil
47
+ redirect_to refinery.edit_orders_order_path( @order )
48
+ end
49
+ end
50
+
51
+ private
52
+
53
+ def redirect_to_index(msg = nil)
54
+ flash[:notice] = msg if msg
55
+ redirect_to refinery.stores_store_path( find_first_store )
56
+ end
57
+
58
+
59
+ def find_cart
60
+ @cart = (session[:cart] ||= Cart.new)
61
+ end
62
+
63
+ protected
64
+
65
+ def find_first_store
66
+ @store = Store.order('position ASC').first
67
+ end
68
+
69
+
70
+ def find_all_stores
71
+ @stores = Store.order('position ASC')
72
+ end
73
+
74
+ def find_page
75
+ @page = ::Refinery::Page.where(:link_url => "/stores").first
76
+ end
77
+
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,11 @@
1
+ module Refinery
2
+ module Orders
3
+ module OrdersHelper
4
+
5
+ def pretty_total_price( li )
6
+ number_to_currency( ( li.quantity.to_f * li.unit_price ) )
7
+ end
8
+
9
+ end # module OrdersHelper
10
+ end # module Orders
11
+ end # module Refinery
@@ -0,0 +1,12 @@
1
+ module Refinery
2
+ module Addresses
3
+ class Address < Refinery::Core::BaseModel
4
+ self.table_name = :refinery_addresses
5
+ # acts_as_indexed :fields => [:first_name, :last_name, :phone, :email, :address1, :address2, :city, :state, :zip, :country]
6
+
7
+ validates :first_name, :presence => true
8
+ validates :last_name, :presence => true
9
+
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,24 @@
1
+ module Refinery
2
+ module Orders
3
+ class LineItem < Refinery::Core::BaseModel
4
+ self.table_name = :refinery_line_items
5
+
6
+ belongs_to :order
7
+ belongs_to :product, :class_name => ::Refinery::Products::Product
8
+
9
+ # validates :order_status, :presence => true, :uniqueness => true
10
+
11
+ def self.from_cart_item( item )
12
+ return self.create(
13
+ :product => item.product,
14
+ :quantity => item.quantity,
15
+ :unit_price => item.price
16
+ )
17
+
18
+ end
19
+
20
+ end # class LineItem
21
+
22
+ end # module Orders
23
+
24
+ end # module Refinery
@@ -0,0 +1,364 @@
1
+ module Refinery
2
+ module Orders
3
+ # #########################################################################
4
+ class OrderProcessingException < SecurityError; end
5
+ # #########################################################################
6
+ # #########################################################################
7
+ # #########################################################################
8
+ class Order < Refinery::Core::BaseModel
9
+
10
+ require 'aasm'
11
+
12
+ self.table_name = :refinery_orders
13
+
14
+ has_many :addresses, :class_name => ::Refinery::Addresses::Address
15
+ has_many :line_items
16
+
17
+ # belongs_to :customer
18
+ # belongs_to :shipping_type
19
+ # belongs_to :discount
20
+ # belongs_to :shipping_vendor
21
+
22
+ before_create :generate_order_number
23
+
24
+ has_one :billing_address, :class_name => ::Refinery::Addresses::Address,
25
+ :conditions => { :is_billing => true }
26
+
27
+ has_one :shipping_address, :class_name => ::Refinery::Addresses::Address,
28
+ :conditions => { :is_billing => false }
29
+
30
+ # #########################################################################
31
+ # attr_protected :order_number
32
+ attr_accessible :order_notes, :shipping_type
33
+ # #########################################################################
34
+
35
+ # t.integer :order_number, :null => false, :unique => true
36
+ # t.references :order_customer
37
+ # t.string :order_status, :default => '', :null => false
38
+ # t.text :order_notes
39
+ # t.references :shipping_type
40
+ # t.datetime :shipped_on
41
+ # t.float :product_cost, :default => 0.0, :limit => 10
42
+ # t.float :shipping_cost, :default => 0.0, :limit => 10
43
+ # t.float :tax_cost, :default => 0.0, :limit => 5
44
+
45
+ # #########################################################################
46
+ # AASM STATE MACHINE AREA ... try to keep generic!
47
+ # #########################################################################
48
+
49
+ include AASM
50
+
51
+ # #########################################################################
52
+ # STATE MACHINE STATES
53
+ # #########################################################################
54
+ aasm_column :order_status # expects this field for persistance of state
55
+
56
+ # default starting state for order objects
57
+ aasm_initial_state :checkout_started
58
+
59
+ # initial state: cart becomes an "empty" order (nothing else filled in)
60
+ aasm_state :checkout_started
61
+
62
+ # 1 order processing states
63
+ aasm_state :edit_stage_completed, :enter => :edit_done
64
+
65
+ # 2 automatic states for purchased
66
+ aasm_state :purchase_confirmed, :enter => :order_confirmed
67
+ aasm_state :order_completed, :enter => :order_completed
68
+
69
+ # 2 defunct or cancelled states
70
+ aasm_state :refunded_defunct, :enter => :refund2defunct
71
+
72
+ # #########################################################################
73
+ # STATE MACHINE EVENT HANDLING
74
+ # #########################################################################
75
+ #
76
+ # Further note:
77
+ # if all digital download, skip delivery method
78
+ # if all digital download && gateway_handles_billing, skip address
79
+ # if gateway_does_everything, skip payment selection
80
+ #
81
+ # ---------------------------------------------------------------------------
82
+ # next_in_process -- advances order thru order wizard stages
83
+ # ---------------------------------------------------------------------------
84
+ aasm_event :next_in_process do
85
+ transitions :to => :edit_stage_completed, :from => :checkout_started
86
+ end
87
+
88
+ # ---------------------------------------------------------------------------
89
+ # confirm_purchase -- user definitely confirms purchase intent
90
+ # ---------------------------------------------------------------------------
91
+ aasm_event :confirm_purchase do
92
+ transitions :to => :purchase_confirmed, :from => :edit_stage_completed
93
+ end
94
+
95
+ # ---------------------------------------------------------------------------
96
+ # payment_verfified -- payment gateway verifies funds transfer
97
+ # ---------------------------------------------------------------------------
98
+ aasm_event :payment_verified do
99
+ transitions :to => :order_completed, :from => :purchase_confirmed
100
+ end
101
+
102
+ # ---------------------------------------------------------------------------
103
+ # purchase_failed -- payment gateway failed
104
+ # backs state to select a payment method
105
+ # ---------------------------------------------------------------------------
106
+ aasm_event( :purchase_failed, :success => :void_payment ) do
107
+ transitions :to => :delivery_stage_completed, :from => :purchase_confirmed
108
+ end
109
+
110
+ # ---------------------------------------------------------------------------
111
+ # refund_order -- order fully refunded making it defunct
112
+ # ---------------------------------------------------------------------------
113
+ aasm_event :refund_order do
114
+ transitions :to => :refunded_defunct, :from => :order_completed
115
+ end
116
+
117
+
118
+ # ---------------------------------------------------------------------------
119
+ # restart_checkout -- return to the edit stage
120
+ # ---------------------------------------------------------------------------
121
+ aasm_event :restart_checkout do
122
+ transitions :to => :checkout_started,
123
+ :from => [:checkout_started, :edit_stage_completed,
124
+ :purchase_confirmed ]
125
+ end
126
+
127
+ # ---------------------------------------------------------------------------
128
+ # cancel_process -- cancel the order wizard process, void any payt tokens
129
+ # ---------------------------------------------------------------------------
130
+ aasm_event( :cancel_process, :success => :void_payment ) do
131
+ transitions :to => :checkout_started,
132
+ :from => [:checkout_started, :edit_stage_completed ]
133
+ end
134
+
135
+ # #########################################################################
136
+ # #########################################################################
137
+ # END OF AASM AREA
138
+ # #########################################################################
139
+ # #########################################################################
140
+
141
+ # ---------------------------------------------------------------------------
142
+ # get_render_template -- returns template name for next edit render
143
+ # returns nil if an invalid state
144
+ # ---------------------------------------------------------------------------
145
+ def get_render_template
146
+ action = {
147
+ :checkout_started => :edit,
148
+ :edit_stage_completed => :confirmation
149
+ }[ self.order_status.to_sym ]
150
+
151
+ end
152
+
153
+ # ---------------------------------------------------------------------------
154
+ # handle_update -- handle user params for updating order
155
+ # returns bill_address, ship_address objects (or nil for both)
156
+ # which might have errors
157
+ # ---------------------------------------------------------------------------
158
+ def handle_update( params )
159
+ if checkout_started?
160
+ bill_address, ship_address = update_addresses( params )
161
+ next_in_process! if bill_address.errors.empty? && ship_address.errors.empty?
162
+ end
163
+
164
+ self.cc_token = params[:stripeToken]
165
+ self.cc_last4 = params[:last4]
166
+ self.cc_card_type = params[:card_type]
167
+ self.cc_expiry_month = params[:expiry_month]
168
+ self.cc_expiry_year = params[:expiry_year]
169
+ self.save!
170
+
171
+
172
+ return bill_address, ship_address
173
+ end
174
+
175
+ # ---------------------------------------------------------------------------
176
+ # checkout! -- checkout converts the cart into a fledgling order
177
+ # ---------------------------------------------------------------------------
178
+ def self.checkout!( cart )
179
+ order = Order.new
180
+
181
+ # convert cart.items to order.line_items
182
+ cart.items.each do | item |
183
+ order.line_items.build(
184
+ :product => item.product,
185
+ :quantity => item.quantity,
186
+ :unit_price => item.price
187
+ )
188
+ end # do
189
+
190
+ order.save!
191
+
192
+ return order
193
+ end
194
+
195
+ # TODO: convert customer's billing/shipping addresses to order addresses
196
+
197
+ # ---------------------------------------------------------------------------
198
+ # ---------------------------------------------------------------------------
199
+ def get_billship_addresses()
200
+ bill_address = self.billing_address || ::Refinery::Addresses::Address.new( :is_billing => true )
201
+
202
+ # ship needs to be populated from bill if no ship already present
203
+ ship_address = self.shipping_address ||
204
+ ::Refinery::Addresses::Address.new(
205
+ :first_name => bill_address.first_name ,
206
+ :last_name => bill_address.last_name ,
207
+ :phone => bill_address.phone ,
208
+ :email => bill_address.email ,
209
+ :address1 => bill_address.address1 ,
210
+ :address2 => bill_address.address2 ,
211
+ :city => bill_address.city ,
212
+ :state => bill_address.state ,
213
+ :zip => bill_address.zip ,
214
+ :country => bill_address.country ,
215
+ :is_billing => false
216
+ )
217
+
218
+ return bill_address, ship_address
219
+ end
220
+
221
+
222
+ # ---------------------------------------------------------------------------
223
+ # update_addresses -- complex logic for dealing with 2 order addresses
224
+ # return bill_address, ship_address objects
225
+ # ---------------------------------------------------------------------------
226
+ def update_addresses( params )
227
+ # if bill exists; update with parameters
228
+ # else create bill
229
+ if (bill_address = self.billing_address)
230
+ bill_address.update_attributes( params[:billing_address] )
231
+ else
232
+ bill_address = self.addresses.create(
233
+ params[:billing_address].merge( { :is_billing => true } )
234
+ )
235
+ end # if..then..else billing address setup
236
+
237
+ # continue if error free
238
+ if bill_address.errors.empty?
239
+
240
+ # does customer wants same address for both ?
241
+ ship_params = ( params[:use_billing] ?
242
+ params[:billing_address] :
243
+ params[:shipping_address]
244
+ ).merge( { :is_billing => false } )
245
+
246
+ if (ship_address = self.shipping_address)
247
+ ship_address.update_attributes( ship_params )
248
+ else
249
+ ship_address = self.addresses.create( ship_params )
250
+ end # if..then..else shiping address setup
251
+
252
+ else # need placeholder for re-editing the order
253
+ ship_address = self.addresses.build( params[:shipping_address] )
254
+ end # if no bill address errors
255
+
256
+ return bill_address, ship_address
257
+ end
258
+
259
+ # ---------------------------------------------------------------------------
260
+ # ---------------------------------------------------------------------------
261
+
262
+ def total_items
263
+ line_items.sum { |item| item.quantity }
264
+ end
265
+
266
+
267
+ def total_price
268
+ line_items.sum { |item| item.unit_price * item.quantity }
269
+ end
270
+
271
+
272
+ # ---------------------------------------------------------------------------
273
+ # process_purchase -- charges CC for the purchase
274
+ # returns nil if error (self.errors captures), or result JSON obj
275
+ # ---------------------------------------------------------------------------
276
+ def process_purchase( store_gateway )
277
+ raise OrderProcessingException unless self.purchase_confirmed?
278
+
279
+ result = store_gateway.charge_purchase(
280
+ self.cc_token,
281
+ self.product_total + self.shipping_charges + self.tax_charges,
282
+ self,
283
+ self.billing_address.email
284
+ )
285
+
286
+ unless result.nil? # unless there were errors ...
287
+ self.cc_purchased_on = Time.now # date of purchase
288
+ self.cc_confirmation_id = result.id # confirmation code
289
+ # next step saves above changes IFF paid is true
290
+ self.payment_verified! if result.paid # state becomes paid & final
291
+ end # unless there were errors
292
+
293
+ return result
294
+
295
+ end
296
+
297
+ # ---------------------------------------------------------------------------
298
+ # ---------------------------------------------------------------------------
299
+
300
+ private
301
+
302
+ # ---------------------------------------------------------------------------
303
+ # edit_done -- things to do after edit input & verified
304
+ # ---------------------------------------------------------------------------
305
+ def edit_done()
306
+
307
+ end
308
+
309
+ # ---------------------------------------------------------------------------
310
+ # order_confirmed -- things to do after user confirmed purchase decision
311
+ # ---------------------------------------------------------------------------
312
+ def order_confirmed()
313
+ self.product_total = total_price
314
+ # shipping_charges
315
+ # tax_charges
316
+ save!
317
+ end
318
+
319
+ # ---------------------------------------------------------------------------
320
+ # order_completed -- things to do after purchase verified by gateway
321
+ # ---------------------------------------------------------------------------
322
+ def order_completed()
323
+ # create a confirmation code
324
+ # kick off shipping process
325
+ end
326
+
327
+ # ---------------------------------------------------------------------------
328
+ # refund2defunct -- things to do after refunding an order making it defunct
329
+ # ---------------------------------------------------------------------------
330
+ def refund2defunct()
331
+ end
332
+
333
+ # ---------------------------------------------------------------------------
334
+ # ---------------------------------------------------------------------------
335
+ def void_payment
336
+
337
+ end
338
+
339
+ # ---------------------------------------------------------------------------
340
+ # ---------------------------------------------------------------------------
341
+ def generate_order_number
342
+ nbr = 0
343
+ max = 0xfffffffe
344
+ tries = max # deadman counter to prevent infinite loop
345
+
346
+ while ( tries > 0 && Order.find_by_order_number(nbr = rand( max ) + 1) ) do
347
+ tries = tries - 1 # decrement deadman counter
348
+ end # while
349
+ raise ArgumentError, "maxed out store order numbers?!" if tries.zero?
350
+
351
+ self.order_number = nbr
352
+ end
353
+
354
+ # ---------------------------------------------------------------------------
355
+ # ---------------------------------------------------------------------------
356
+
357
+ # ---------------------------------------------------------------------------
358
+ # ---------------------------------------------------------------------------
359
+
360
+ # #########################################################################
361
+ end # class Order
362
+ # #########################################################################
363
+ end # module Orders
364
+ end # module Refinery
@@ -0,0 +1,17 @@
1
+ module Refinery
2
+ module Products
3
+ class Product < Refinery::Core::BaseModel
4
+ self.table_name = :refinery_products
5
+ acts_as_indexed :fields => [:name, :code, :description]
6
+
7
+ validates :name, :presence => true, :uniqueness => true
8
+
9
+ belongs_to :main_pic, :class_name => '::Refinery::Image'
10
+ belongs_to :store, :class_name => '::Refinery::Stores::Store'
11
+ has_many :line_items, :class_name => '::Refinery::Orders::LineItem'
12
+
13
+ scope :active, lambda { |i| where(["date_available <= ? ", Time.now ]) }
14
+
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,33 @@
1
+ module Refinery
2
+ module Stores
3
+ class Store < Refinery::Core::BaseModel
4
+ self.table_name = :refinery_stores
5
+
6
+ acts_as_indexed :fields => [:name, :meta_keywords, :description]
7
+
8
+ validates :name, :presence => true, :uniqueness => true
9
+
10
+ has_many :products
11
+ # we may want to expand the concept of active in the future
12
+ has_many :active_products, :class_name => '::Refinery::Products::Product', :foreign_key => 'store_id'
13
+
14
+ # -----------------------------------------------------------------------
15
+ # select_list -- returns an html select list suitable for selecting a store
16
+ # -----------------------------------------------------------------------
17
+ def self.select_list()
18
+ all.map{ |x| [x.name, x.id] }
19
+ end
20
+
21
+ # -----------------------------------------------------------------------
22
+ # -----------------------------------------------------------------------
23
+
24
+ # -----------------------------------------------------------------------
25
+ # -----------------------------------------------------------------------
26
+
27
+ # -----------------------------------------------------------------------
28
+ # -----------------------------------------------------------------------
29
+
30
+ end # class Store
31
+
32
+ end # module Stores
33
+ end # module Refineryd
@@ -0,0 +1,25 @@
1
+ <ul>
2
+ <% if ::Refinery::Addresses::Admin::AddressesController.searchable? %>
3
+ <li>
4
+ <%= render '/refinery/admin/search', :url => refinery.addresses_admin_addresses_path %>
5
+ </li>
6
+ <% end %>
7
+ <li>
8
+ <%= link_to t('.create_new'), refinery.new_addresses_admin_address_path,
9
+ :class => "add_icon" %>
10
+ </li>
11
+ <% if !searching? && ::Refinery::Addresses::Admin::AddressesController.sortable? && ::Refinery::Addresses::Address.any? %>
12
+ <li>
13
+ <%= link_to t('.reorder', :what => "Addresses"),
14
+ refinery.addresses_admin_addresses_path,
15
+ :id => "reorder_action",
16
+ :class => "reorder_icon" %>
17
+
18
+ <%= link_to t('.reorder_done', :what => "Addresses"),
19
+ refinery.addresses_admin_addresses_path,
20
+ :id => "reorder_action_done",
21
+ :style => "display: none;",
22
+ :class => "reorder_icon" %>
23
+ </li>
24
+ <% end %>
25
+ </ul>
@@ -0,0 +1,16 @@
1
+ <li class='clearfix record <%= cycle("on", "on-hover") %>' id="<%= dom_id(address) -%>">
2
+ <span class='title'>
3
+ <%= address.first_name %>
4
+
5
+ </span>
6
+ <span class='actions'>
7
+
8
+ <%= link_to refinery_icon_tag("application_edit.png"), refinery.edit_addresses_admin_address_path(address),
9
+ :title => t('.edit') %>
10
+ <%= link_to refinery_icon_tag("delete.png"), refinery.addresses_admin_address_path(address),
11
+ :class => "cancel confirm-delete",
12
+ :title => t('.delete'),
13
+ :confirm => t('message', :scope => 'refinery.admin.delete', :title => address.first_name),
14
+ :method => :delete %>
15
+ </span>
16
+ </li>
@@ -0,0 +1,2 @@
1
+ <%= will_paginate @addresses if Refinery::Addresses::Admin::AddressesController.pageable? %>
2
+ <%= render 'sortable_list' %>
@@ -0,0 +1,89 @@
1
+ <%= form_for [refinery, :addresses_admin, @address] do |f| -%>
2
+ <%= render '/refinery/admin/error_messages',
3
+ :object => @address,
4
+ :include_object_name => true %>
5
+
6
+
7
+ <div class='field'>
8
+ <%= f.label :customer -%>
9
+ <%= f.text_field :customer, :class => 'larger widest' -%>
10
+
11
+ </div>
12
+
13
+ <div class='field'>
14
+ <%= f.label :order -%>
15
+ <%= f.text_field :order -%>
16
+
17
+ </div>
18
+
19
+ <div class='field'>
20
+ <%= f.label :is_billing -%>
21
+ <%= f.check_box :is_billing, :checked => @address[:is_billing] -%>
22
+
23
+ </div>
24
+
25
+ <div class='field'>
26
+ <%= f.label :first_name -%>
27
+ <%= f.text_field :first_name -%>
28
+
29
+ </div>
30
+
31
+ <div class='field'>
32
+ <%= f.label :last_name -%>
33
+ <%= f.text_field :last_name -%>
34
+
35
+ </div>
36
+
37
+ <div class='field'>
38
+ <%= f.label :phone -%>
39
+ <%= f.text_field :phone -%>
40
+
41
+ </div>
42
+
43
+ <div class='field'>
44
+ <%= f.label :email -%>
45
+ <%= f.text_field :email -%>
46
+
47
+ </div>
48
+
49
+ <div class='field'>
50
+ <%= f.label :address1 -%>
51
+ <%= f.text_field :address1 -%>
52
+
53
+ </div>
54
+
55
+ <div class='field'>
56
+ <%= f.label :address2 -%>
57
+ <%= f.text_field :address2 -%>
58
+
59
+ </div>
60
+
61
+ <div class='field'>
62
+ <%= f.label :city -%>
63
+ <%= f.text_field :city -%>
64
+
65
+ </div>
66
+
67
+ <div class='field'>
68
+ <%= f.label :state -%>
69
+ <%= f.text_field :state -%>
70
+
71
+ </div>
72
+
73
+ <div class='field'>
74
+ <%= f.label :zip -%>
75
+ <%= f.text_field :zip -%>
76
+
77
+ </div>
78
+
79
+ <div class='field'>
80
+ <%= f.label :country -%>
81
+ <%= f.text_field :country -%>
82
+
83
+ </div>
84
+
85
+ <%= render '/refinery/admin/form_actions', :f => f,
86
+ :continue_editing => false,
87
+ :delete_title => t('delete', :scope => 'refinery.addresses.admin.addresses.address'),
88
+ :delete_confirmation => t('message', :scope => 'refinery.admin.delete', :title => @address.first_name) %>
89
+ <% end -%>