caboose-cms 0.5.56 → 0.5.57

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +8 -8
  2. data/app/assets/javascripts/caboose/cart.js +43 -47
  3. data/app/assets/javascripts/caboose/checkout_step3.js +5 -3
  4. data/app/assets/javascripts/caboose/checkout_step4.js +2 -1
  5. data/app/assets/javascripts/caboose/model/index_table.js +6 -6
  6. data/app/assets/javascripts/caboose/product.js +61 -61
  7. data/app/assets/stylesheets/caboose/product_images.css.scss +31 -0
  8. data/app/assets/stylesheets/caboose/product_options.css.scss +34 -0
  9. data/app/assets/templates/caboose/cart/add_to_cart.jst.ejs +1 -2
  10. data/app/assets/templates/caboose/product/images.jst.ejs +1 -2
  11. data/app/assets/templates/caboose/product/images_old.jst.ejs +7 -0
  12. data/app/assets/templates/caboose/product/options.jst.ejs +0 -10
  13. data/app/controllers/caboose/application_controller.rb +12 -12
  14. data/app/controllers/caboose/checkout_controller.rb +53 -11
  15. data/app/controllers/caboose/products_controller.rb +27 -281
  16. data/app/controllers/caboose/sites_controller.rb +8 -7
  17. data/app/controllers/caboose/variants_controller.rb +123 -41
  18. data/app/models/caboose/order.rb +20 -13
  19. data/app/models/caboose/order_package.rb +3 -0
  20. data/app/models/caboose/schema.rb +30 -22
  21. data/app/models/caboose/shipping_calculator.rb +14 -4
  22. data/app/models/caboose/store_config.rb +1 -0
  23. data/app/views/caboose/checkout/_confirm.html.erb +1 -1
  24. data/app/views/caboose/checkout/step_four.html.erb +8 -41
  25. data/app/views/caboose/checkout/step_one.html.erb +2 -0
  26. data/app/views/caboose/checkout/step_three.html.erb +45 -34
  27. data/app/views/caboose/checkout/step_two.html.erb +2 -1
  28. data/app/views/caboose/products/_admin_header.html.erb +1 -1
  29. data/app/views/caboose/products/admin_edit_images.html.erb +2 -2
  30. data/app/views/caboose/sites/admin_edit_store_config.html.erb +2 -0
  31. data/app/views/caboose/{products/admin_edit_variant_sort_order.html.erb → variants/admin_edit_sort_order.html.erb} +0 -0
  32. data/app/views/caboose/variants/admin_index.html.erb +101 -0
  33. data/config/routes.rb +184 -113
  34. data/lib/caboose/version.rb +1 -1
  35. metadata +7 -7
  36. data/app/views/caboose/products/admin_edit_variant_columns.html.erb +0 -75
  37. data/app/views/caboose/products/admin_edit_variants.html.erb +0 -92
  38. data/app/views/caboose/products/admin_edit_variants_old.html.erb +0 -171
  39. data/app/views/caboose/products/admin_edit_variants_single.html.erb +0 -68
@@ -30,33 +30,33 @@ module Caboose
30
30
  @site = Site.new
31
31
  end
32
32
 
33
- # GET /admin/sites/1/edit
33
+ # GET /admin/sites/:id
34
34
  def admin_edit
35
35
  return if !user_is_allowed('sites', 'edit')
36
36
  @site = Site.find(params[:id])
37
37
  end
38
38
 
39
- # GET /admin/sites/1/edit/store
39
+ # GET /admin/sites/:id/store
40
40
  def admin_edit_store_config
41
41
  return if !user_is_allowed('sites', 'edit')
42
42
  @site = Site.find(params[:id])
43
43
  StoreConfig.create(:site_id => @site.id) if @site.store_config.nil?
44
44
  end
45
45
 
46
- # GET /admin/sites/1/edit/smtp
46
+ # GET /admin/sites/:id/smtp
47
47
  def admin_edit_smtp_config
48
48
  return if !user_is_allowed('sites', 'edit')
49
49
  @site = Site.find(params[:id])
50
50
  SmtpConfig.create(:site_id => @site.id) if @site.smtp_config.nil?
51
51
  end
52
52
 
53
- # GET /admin/sites/1/edit/block-types
53
+ # GET /admin/sites/:id/block-types
54
54
  def admin_edit_block_types
55
55
  return if !user_is_allowed('sites', 'edit')
56
56
  @site = Site.find(params[:id])
57
57
  end
58
58
 
59
- # GET /admin/sites/1/edit/delete
59
+ # GET /admin/sites/:id/delete
60
60
  def admin_delete_form
61
61
  return if !user_is_allowed('sites', 'edit')
62
62
  @site = Site.find(params[:id])
@@ -184,8 +184,9 @@ module Caboose
184
184
  # GET /admin/sites/payment-processor-options
185
185
  def payment_processor_options
186
186
  return if !user_is_allowed('sites', 'view')
187
- options = [
188
- { 'value' => 'stripe', 'text' => 'Stripe' }
187
+ options = [
188
+ { 'value' => 'authorize.net' , 'text' => 'Authorize.net' },
189
+ { 'value' => 'stripe' , 'text' => 'Stripe' }
189
190
  ]
190
191
  render :json => options
191
192
  end
@@ -28,7 +28,27 @@ module Caboose
28
28
  #=============================================================================
29
29
  # Admin actions
30
30
  #=============================================================================
31
-
31
+
32
+ # GET /admin/products/:id/variants
33
+ # GET /admin/products/:id/variants/:variant_id
34
+ def admin_index
35
+ return if !user_is_allowed('products', 'edit')
36
+ @product = Product.find(params[:product_id])
37
+
38
+ if @product.variants.nil? || @product.variants.count == 0
39
+ v = Variant.new
40
+ v.option1 = @product.default1 if @product.option1
41
+ v.option2 = @product.default2 if @product.option2
42
+ v.option3 = @product.default3 if @product.option3
43
+ v.status = 'Active'
44
+ @product.variants = [v]
45
+ @product.save
46
+ end
47
+ @variant = params[:variant_id] ? Variant.find(params[:variant_id]) : @product.variants[0]
48
+ @highlight_variant_id = params[:highlight] ? params[:highlight].to_i : nil
49
+ render :layout => 'caboose/admin'
50
+ end
51
+
32
52
  # GET /admin/products/:product_id/variants/json
33
53
  def admin_json
34
54
  return if !user_is_allowed('products', 'view')
@@ -48,44 +68,15 @@ module Caboose
48
68
  :models => pager.items
49
69
  }
50
70
  end
51
-
52
- # GET /admin/variants/:variant_id/edit
53
- # GET /admin/products/:product_id/variants/:variant_id/edit
71
+
72
+ # GET /admin/products/:product_id/variants/:variant_id
54
73
  def admin_edit
55
74
  return if !user_is_allowed('variants', 'edit')
56
- @variant = Variant.find(params[:variant_id])
75
+ @variant = Variant.find(params[:id])
57
76
  @product = @variant.product
58
77
  render :layout => 'caboose/admin'
59
78
  end
60
79
 
61
- # GET /admin/products/:id/variants
62
- # GET /admin/products/:id/variants/:variant_id
63
- def admin_edit_variants
64
- return if !user_is_allowed('products', 'edit')
65
- @product = Product.find(params[:id])
66
-
67
- if @product.variants.nil? || @product.variants.count == 0
68
- v = Variant.new
69
- v.option1 = @product.default1 if @product.option1
70
- v.option2 = @product.default2 if @product.option2
71
- v.option3 = @product.default3 if @product.option3
72
- v.status = 'Active'
73
- @product.variants = [v]
74
- @product.save
75
- end
76
- @variant = params[:variant_id] ? Variant.find(params[:variant_id]) : @product.variants[0]
77
- session['variant_cols'] = self.default_variant_cols if session['variant_cols'].nil?
78
- @cols = session['variant_cols']
79
-
80
- @highlight_variant_id = params[:highlight] ? params[:highlight].to_i : nil
81
-
82
- if @product.options.nil? || @product.options.count == 0
83
- render 'caboose/products/admin_edit_variants_single', :layout => 'caboose/admin'
84
- else
85
- render 'caboose/products/admin_edit_variants', :layout => 'caboose/admin'
86
- end
87
- end
88
-
89
80
  # PUT /admin/variants/:id
90
81
  def admin_update
91
82
  return if !user_is_allowed('variants', 'edit')
@@ -182,7 +173,7 @@ module Caboose
182
173
  render :json => true
183
174
  end
184
175
 
185
- # DELETE /admin/variants/:id
176
+ # DELETE /admin/products/:product_id/variants/:id
186
177
  def admin_delete
187
178
  return if !user_is_allowed('variants', 'delete')
188
179
  v = Variant.find(params[:id])
@@ -193,6 +184,20 @@ module Caboose
193
184
  })
194
185
  end
195
186
 
187
+ # DELETE /admin/products/:product_id/variants/bulk
188
+ def admin_bulk_delete
189
+ return if !user_is_allowed('variants', 'delete')
190
+
191
+ resp = Caboose::StdClass.new
192
+ params[:model_ids].each do |variant_id|
193
+ v = Variant.find(variant_id)
194
+ v.status = 'Deleted'
195
+ v.save
196
+ end
197
+ resp.success = true
198
+ render :json => resp
199
+ end
200
+
196
201
  # GET /admin/products/:product_id/variants/sort-order
197
202
  def admin_edit_sort_order
198
203
  return if !user_is_allowed('products', 'edit')
@@ -238,7 +243,7 @@ module Caboose
238
243
  return if !user_is_allowed('variants', 'edit')
239
244
 
240
245
  joins = []
241
- where = ''
246
+ where = []
242
247
  values = []
243
248
 
244
249
  if params[:category_ids]
@@ -258,21 +263,98 @@ module Caboose
258
263
  values << "%#{params[:title].downcase}%"
259
264
  end
260
265
 
261
- # Query for all relevant products
262
- products = values.any? ? Caboose::Product.joins(joins).where([where].concat(values)) : []
266
+ # Query for all relevant products
267
+ products = values.any? ? Caboose::Product.joins(joins).where([where.join(' AND ')].concat(values)) : []
263
268
 
264
269
  # Grab variants for each product
265
270
  @variants = products.collect { |product| product.variants }.flatten
266
271
 
267
- # Grab all categories; except for all and uncategorized
268
- @categories = Caboose::Category.where('parent_id IS NOT NULL')
272
+ # Grab all categories; except for all and uncategorized
273
+ @categories = Category.where('site_id = ? and parent_id IS NOT NULL AND name IS NOT NULL', @site.id).order(:url)
269
274
 
270
- # Grab all vendors
271
- @vendors = Caboose::Vendor.all
275
+ # Grab all vendors
276
+ @vendors = Vendor.where('site_id = ? and name IS NOT NULL', @site.id).order(:name)
272
277
 
273
278
  render :layout => 'caboose/admin'
274
279
  end
275
280
 
281
+ # POST /admin/products/:product_id/variants/add
282
+ def admin_add
283
+
284
+ resp = Caboose::StdClass.new
285
+ p = Caboose::Product.find(params[:product_id])
286
+
287
+ v = Caboose::Variant.where(:alternate_id => params[:alternate_id]).first
288
+ v = Caboose::Variant.new(:product_id => p.id) if v.nil?
289
+
290
+ v.product_id = p.id
291
+ v.alternate_id = params[:alternate_id].strip
292
+ v.quantity_in_stock = params[:quantity_in_stock].strip.to_i
293
+ v.price = '%.2f' % params[:price].strip.to_f
294
+ v.option1 = params[:option1] if p.option1
295
+ v.option2 = params[:option2] if p.option2
296
+ v.option3 = params[:option3] if p.option3
297
+ v.save
298
+
299
+ resp.success = true
300
+ render :json => resp
301
+ end
302
+
303
+ # POST /admin/products/:product_id/variants/bulk
304
+ def admin_bulk_add
305
+ product = Product.find(params[:product_id])
306
+
307
+ resp = Caboose::StdClass.new
308
+ p = Caboose::Product.find(params[:product_id])
309
+
310
+ # Check for data integrity first
311
+ CSV.parse(params[:csv_data]).each do |row|
312
+ if row[1].nil? then resp.error = "Quantity is not defined for variant: #{row[0].strip}" and break
313
+ elsif row[2].nil? then resp.error = "Price is not defined for variant: #{row[0].strip}" and break
314
+ elsif p.option1 && row[3].nil? then resp.error = "#{p.option1} is not defined for variant: #{row[0].strip}" and break
315
+ elsif p.option2 && row[4].nil? then resp.error = "#{p.option2} is not defined for variant: #{row[0].strip}" and break
316
+ elsif p.option3 && row[5].nil? then resp.error = "#{p.option3} is not defined for variant: #{row[0].strip}" and break
317
+ end
318
+ end
319
+
320
+ if resp.error.nil?
321
+ CSV.parse(params[:csv_data]).each do |row|
322
+ v = Caboose::Variant.where(:alternate_id => row[0]).first
323
+ v = Caboose::Variant.new(:product_id => p.id) if v.nil?
324
+
325
+ v.product_id = p.id
326
+ v.alternate_id = row[0].strip
327
+ v.quantity_in_stock = row[1].strip.to_i
328
+ v.price = '%.2f' % row[2].strip.to_f
329
+ v.option1 = row[3] if p.option1
330
+ v.option2 = row[4] if p.option2
331
+ v.option3 = row[5] if p.option3
332
+ v.save
333
+ end
334
+ resp.success = true
335
+ end
336
+
337
+ render :json => resp
338
+ end
339
+
340
+ # POST /admin/products/:product_id/variants/remove
341
+ def admin_remove_variants
342
+ params[:variant_ids].each do |variant_id|
343
+ variant = Variant.find(variant_id)
344
+ # variant.update_attribute(:status, 'deleted')
345
+ # variant.product.update_attribute(:status, 'deleted') if variant.product.variants.where('status != ?', 'deleted').count == 0
346
+ end
347
+
348
+ # Remove passed variants
349
+ # redirect_to "/admin/products/#{params[:id]}/variants/group"
350
+
351
+ render :json => true
352
+ end
353
+
354
+ #===========================================================================
355
+ # Option methods
356
+ #===========================================================================
357
+
276
358
  # GET /admin/variants/status-options
277
359
  def admin_status_options
278
360
  arr = ['Active', 'Inactive', 'Deleted']
@@ -21,8 +21,8 @@ module Caboose
21
21
  :order_number,
22
22
  :subtotal,
23
23
  :tax,
24
- :shipping_method,
25
- :shipping_method_code,
24
+ :shipping_carrier,
25
+ :shipping_service_code,
26
26
  :shipping,
27
27
  :handling,
28
28
  :discount,
@@ -56,19 +56,25 @@ module Caboose
56
56
  :transaction_service,
57
57
  :transaction_id
58
58
 
59
+ STATUS_CART = 'cart'
60
+ STATUS_PENDING = 'pending'
61
+ STATUS_CANCELED = 'canceled'
62
+ STATUS_SHIPPED = 'shipped'
63
+ STATUS_TESTING = 'testing'
64
+
59
65
  #
60
66
  # Scopes
61
67
  #
62
68
 
63
- scope :test, where('status = ?', 'testing')
64
- scope :cancelled, where('status = ?', 'cancelled')
65
- scope :pending, where('status = ?', 'pending')
69
+ scope :test , where('status = ?', 'testing')
70
+ scope :cancelled , where('status = ?', 'cancelled')
71
+ scope :pending , where('status = ?', 'pending')
66
72
  #TODO scope :fulfilled
67
73
  #TODO scope :unfulfilled
68
- scope :authorized, where('financial_status = ?', 'authorized')
69
- scope :captured, where('financial_status = ?', 'captured')
70
- scope :refunded, where('financial_status = ?', 'refunded')
71
- scope :voided, where('financial_status = ?', 'voided')
74
+ scope :authorized , where('financial_status = ?', 'authorized')
75
+ scope :captured , where('financial_status = ?', 'captured')
76
+ scope :refunded , where('financial_status = ?', 'refunded')
77
+ scope :voided , where('financial_status = ?', 'voided')
72
78
 
73
79
  #
74
80
  # Validations
@@ -157,7 +163,7 @@ module Caboose
157
163
  def calculate
158
164
  self.update_column(:subtotal, (self.calculate_subtotal * 100).ceil / 100.00)
159
165
  self.update_column(:tax, (self.calculate_tax * 100).ceil / 100.00)
160
- self.update_column(:shipping, (self.calculate_shipping * 100).ceil / 100.00)
166
+ #self.update_column(:shipping, (self.calculate_shipping * 100).ceil / 100.00)
161
167
  self.update_column(:handling, (self.calculate_handling * 100).ceil / 100.00)
162
168
  self.update_column(:total, (self.calculate_total * 100).ceil / 100.00)
163
169
  end
@@ -173,13 +179,14 @@ module Caboose
173
179
  end
174
180
 
175
181
  def calculate_shipping
176
- return 0 if !self.shipping_address || !self.shipping_method_code
177
- ShippingCalculator.rate(self)[:total_price]
182
+ return 0 if !self.shipping_address || !self.shipping_service_code
183
+ return 0.0
184
+ #ShippingCalculator.rates(self)
178
185
  end
179
186
 
180
187
  def calculate_handling
181
188
  return 0 if !Caboose::store_handling_percentage
182
- self.shipping * Caboose::store_handling_percentage
189
+ self.shipping * Caboose::store_handling_percentage.to_f
183
190
  end
184
191
 
185
192
  def calculate_total
@@ -17,6 +17,9 @@ module Caboose
17
17
  # Calculates the shipping packages required for all the items in the order
18
18
  def self.create_for_order(order)
19
19
 
20
+ store_config = order.site.store_config
21
+ return if !store_config.calculate_packages
22
+
20
23
  # Make sure all the line items in the order have a quantity of 1
21
24
  extra_line_items = []
22
25
  order.line_items.each do |li|
@@ -54,7 +54,9 @@ class Caboose::Schema < Caboose::Utilities::Schema
54
54
  :repeat_start ,
55
55
  :repeat_end
56
56
  ],
57
+ Caboose::Order => [:shipping_method, :shipping_method_code],
57
58
  #Caboose::PageCache => [:block],
59
+ Caboose::Site => [:shipping_cost_function],
58
60
  Caboose::Variant => [:quantity],
59
61
  Caboose::Vendor => [:vendor, :vendor_id]
60
62
  }
@@ -63,6 +65,8 @@ class Caboose::Schema < Caboose::Utilities::Schema
63
65
  # Any column indexes that need to exist in the database
64
66
  def self.indexes
65
67
  {
68
+ Caboose::Block => [:parent_id],
69
+ Caboose::BlockType => [:parent_id],
66
70
  Caboose::RoleMembership => [ :role_id , :user_id ],
67
71
  Caboose::RolePermission => [ :role_id , :permission_id ],
68
72
  Caboose::PostCategoryMembership => [ :post_id , :post_category_id ]
@@ -300,9 +304,10 @@ class Caboose::Schema < Caboose::Utilities::Schema
300
304
  [ :date_cancelled , :datetime ],
301
305
  [ :referring_site , :text ],
302
306
  [ :landing_page , :string ],
303
- [ :landing_page_ref , :string ],
304
- [ :shipping_method , :string ],
305
- [ :shipping_method_code , :string ],
307
+ [ :landing_page_ref , :string ],
308
+ [ :shipping_carrier , :string ],
309
+ [ :shipping_service_code , :string ],
310
+ [ :shipping_service_name , :string ],
306
311
  [ :transaction_id , :string ],
307
312
  [ :auth_code , :string ],
308
313
  [ :alternate_id , :integer ],
@@ -472,6 +477,7 @@ class Caboose::Schema < Caboose::Utilities::Schema
472
477
  [ :value , :text ]
473
478
  ],
474
479
  Caboose::ShippingPackage => [
480
+ [ :site_id , :integer ],
475
481
  [ :carrier , :string ],
476
482
  [ :service_code , :string ],
477
483
  [ :service_name , :string ],
@@ -482,9 +488,9 @@ class Caboose::Schema < Caboose::Utilities::Schema
482
488
  [ :price , :decimal ]
483
489
  ],
484
490
  Caboose::Site => [
485
- [ :name , :string ],
486
- [ :description , :text ],
487
- [ :under_construction_html , :text ]
491
+ [ :name , :string ],
492
+ [ :description , :text ],
493
+ [ :under_construction_html , :text ]
488
494
  ],
489
495
  Caboose::SiteMembership => [
490
496
  [ :site_id , :integer ],
@@ -511,22 +517,24 @@ class Caboose::Schema < Caboose::Utilities::Schema
511
517
  [ :max_height , :decimal ]
512
518
  ],
513
519
  Caboose::StoreConfig => [
514
- [ :site_id , :integer ],
515
- [ :pp_name , :string ],
516
- [ :pp_username , :string ],
517
- [ :pp_password , :string ],
518
- [ :use_usps , :boolean , { :default => false } ],
519
- [ :usps_secret_key , :string ],
520
- [ :usps_publishable_key , :string ],
521
- [ :allowed_shipping_codes , :string ],
522
- [ :default_shipping_code , :string ],
523
- [ :origin_country , :string ],
524
- [ :origin_state , :string ],
525
- [ :origin_city , :string ],
526
- [ :origin_zip , :string ],
527
- [ :fulfillment_email , :string ],
528
- [ :shipping_email , :string ],
529
- [ :handling_percentage , :string ]
520
+ [ :site_id , :integer ],
521
+ [ :pp_name , :string ],
522
+ [ :pp_username , :string ],
523
+ [ :pp_password , :string ],
524
+ [ :use_usps , :boolean , { :default => false } ],
525
+ [ :usps_secret_key , :string ],
526
+ [ :usps_publishable_key , :string ],
527
+ [ :allowed_shipping_codes , :string ],
528
+ [ :default_shipping_code , :string ],
529
+ [ :origin_country , :string ],
530
+ [ :origin_state , :string ],
531
+ [ :origin_city , :string ],
532
+ [ :origin_zip , :string ],
533
+ [ :fulfillment_email , :string ],
534
+ [ :shipping_email , :string ],
535
+ [ :handling_percentage , :string ],
536
+ [ :calculate_packages , :boolean , { :default => true }],
537
+ [ :shipping_rates_function , :text ]
530
538
  ],
531
539
  Caboose::User => [
532
540
  [ :site_id , :integer ],
@@ -4,9 +4,19 @@ include ActiveMerchant::Shipping
4
4
  module Caboose
5
5
  class ShippingCalculator
6
6
 
7
+ def self.custom_rates(store_config, order)
8
+ return eval(store_config.shipping_rates_function)
9
+ end
10
+
7
11
  def self.rates(order)
8
12
  return [] if Caboose::store_shipping.nil?
9
-
13
+
14
+ store_config = order.site.store_config
15
+ if store_config
16
+ rates = self.custom_rates(store_config, order)
17
+ return rates
18
+ end
19
+
10
20
  ss = Caboose::store_shipping
11
21
  origin = Location.new(
12
22
  :country => ss[:origin][:country],
@@ -42,14 +52,14 @@ module Caboose
42
52
  rates << { :carrier => 'USPS', :service_code => rate.service_code, :service_name => rate.service_name, :total_price => rate.total_price.to_d / 100 }
43
53
  end
44
54
  end
45
- all_rates << [op, rates]
55
+ all_rates << { :order_package => op, :rates => rates }
46
56
  end
47
57
  return all_rates
48
58
  end
49
59
 
50
60
  def self.rate(order)
51
- return nil if !order.shipping_method_code
52
- self.rates(order).each { |rate| return rate if rate[:service_code] == order.shipping_method_code }
61
+ return nil if !order.shipping_service_code
62
+ self.rates(order).each { |rate| return rate if rate[:service_code] == order.shipping_service_code }
53
63
  return nil
54
64
  end
55
65