caboose-cms 0.5.56 → 0.5.57

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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