caboose-cms 0.5.15 → 0.5.16

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +9 -9
  2. data/app/assets/javascripts/caboose/cart2.js +98 -0
  3. data/app/assets/javascripts/caboose/model/index_table.js +82 -30
  4. data/app/assets/javascripts/caboose/model/model_binder.js +4 -4
  5. data/app/assets/stylesheets/caboose/admin.css +1 -0
  6. data/app/assets/stylesheets/caboose/admin_main.css +0 -42
  7. data/app/assets/stylesheets/caboose/cart.scss +41 -0
  8. data/app/assets/stylesheets/caboose/checkout.css.scss +2 -3
  9. data/app/assets/stylesheets/caboose/message_boxes.scss +49 -0
  10. data/app/assets/templates/caboose/cart/add_to_cart.jst.ejs +1 -1
  11. data/app/controllers/caboose/block_types_controller.rb +3 -1
  12. data/app/controllers/caboose/cart_controller.rb +30 -23
  13. data/app/controllers/caboose/checkout_controller.rb +11 -1
  14. data/app/controllers/caboose/products_controller.rb +28 -14
  15. data/app/controllers/caboose/stackable_groups_controller.rb +107 -0
  16. data/app/models/caboose/line_item.rb +20 -6
  17. data/app/models/caboose/order.rb +2 -1
  18. data/app/models/caboose/order_package.rb +103 -0
  19. data/app/models/caboose/product.rb +2 -1
  20. data/app/models/caboose/schema.rb +45 -3
  21. data/app/models/caboose/shipping_calculator.rb +101 -60
  22. data/app/models/caboose/shipping_package.rb +80 -0
  23. data/app/models/caboose/site.rb +3 -1
  24. data/app/models/caboose/stackable_group.rb +17 -0
  25. data/app/models/caboose/tax_calculator.rb +1 -2
  26. data/app/models/caboose/variant.rb +2 -5
  27. data/app/views/caboose/cart/index.html.erb +19 -6
  28. data/app/views/caboose/checkout/_cart.html.erb +49 -52
  29. data/app/views/caboose/checkout/empty.html.erb +9 -2
  30. data/app/views/caboose/checkout/step_one.html.erb +2 -3
  31. data/app/views/caboose/checkout/step_three.html.erb +28 -10
  32. data/app/views/caboose/checkout/step_two.html.erb +2 -4
  33. data/app/views/caboose/pages/admin_edit_content.html.erb +1 -1
  34. data/app/views/caboose/products/admin_index.html.erb +12 -11
  35. data/app/views/caboose/sites/admin_edit.html.erb +33 -6
  36. data/app/views/caboose/stackable_groups/admin_index.html.erb +43 -0
  37. data/config/routes.rb +15 -6
  38. data/lib/caboose/version.rb +1 -1
  39. data/lib/tasks/caboose.rake +7 -1
  40. metadata +36 -14
@@ -3,6 +3,7 @@ module Caboose
3
3
  self.table_name = 'store_products'
4
4
  self.primary_key = 'id'
5
5
 
6
+ belongs_to :stackable_group, :class_name => 'Caboose::StackableGroup'
6
7
  belongs_to :vendor, :class_name => 'Caboose::Vendor'
7
8
  has_many :customizations, :class_name => 'Caboose::Product', :through => :customization_memberships
8
9
  has_many :customization_memberships, :class_name => 'Caboose::CustomizationMembership'
@@ -66,7 +67,7 @@ module Caboose
66
67
  :vendor => self.vendor,
67
68
  :categories => self.categories,
68
69
  :variants => self.variants,
69
- :images => self.product_images
70
+ :images => self.product_images
70
71
  })
71
72
  end
72
73
 
@@ -242,12 +242,12 @@ class Caboose::Schema < Caboose::Utilities::Schema
242
242
  ],
243
243
  Caboose::LineItem => [
244
244
  [ :order_id , :integer ],
245
+ [ :order_package_id , :integer ],
245
246
  [ :variant_id , :integer ],
246
247
  [ :parent_id , :integer ],
247
248
  [ :quantity , :integer , :default => 0 ],
248
249
  [ :status , :string ],
249
- [ :tracking_number , :string ],
250
- #[ :unit_price , :numeric ],
250
+ [ :tracking_number , :string ],
251
251
  [ :price , :numeric , :default => 0 ],
252
252
  [ :notes , :text ],
253
253
  [ :custom1 , :string ],
@@ -311,6 +311,12 @@ class Caboose::Schema < Caboose::Utilities::Schema
311
311
  [ :order_id , :integer ],
312
312
  [ :discount_id , :integer ]
313
313
  ],
314
+ Caboose::OrderPackage => [
315
+ [ :order_id , :integer ],
316
+ [ :shipping_package_id , :integer ],
317
+ [ :status , :string ],
318
+ [ :tracking_number , :string ]
319
+ ],
314
320
  Caboose::Page => [
315
321
  [ :site_id , :integer ],
316
322
  [ :parent_id , :integer ],
@@ -396,7 +402,8 @@ class Caboose::Schema < Caboose::Utilities::Schema
396
402
  [ :date_available , :datetime ],
397
403
  [ :custom_input , :text ],
398
404
  [ :sort_order , :integer ],
399
- [ :featured , :boolean , :default => false ]
405
+ [ :featured , :boolean , :default => false ],
406
+ [ :stackable_group_id , :integer ]
400
407
  ],
401
408
  Caboose::ProductImage => [
402
409
  [ :product_id , :integer ],
@@ -449,6 +456,16 @@ class Caboose::Schema < Caboose::Utilities::Schema
449
456
  [ :name , :string ],
450
457
  [ :value , :text ]
451
458
  ],
459
+ Caboose::ShippingPackage => [
460
+ [ :carrier , :string ],
461
+ [ :service_code , :string ],
462
+ [ :service_name , :string ],
463
+ [ :length , :decimal ],
464
+ [ :width , :decimal ],
465
+ [ :height , :decimal ],
466
+ [ :volume , :decimal ],
467
+ [ :price , :decimal ]
468
+ ],
452
469
  Caboose::Site => [
453
470
  [ :name , :string ],
454
471
  [ :description , :text ],
@@ -469,6 +486,15 @@ class Caboose::Schema < Caboose::Utilities::Schema
469
486
  [ :authentication , :string ], # :plain, :login, :cram_md5.
470
487
  [ :enable_starttls_auto , :boolean , { :default => true }]
471
488
  ],
489
+ Caboose::StackableGroup => [
490
+ [ :name , :string ],
491
+ [ :extra_length , :decimal ],
492
+ [ :extra_width , :decimal ],
493
+ [ :extra_height , :decimal ],
494
+ [ :max_length , :decimal ],
495
+ [ :max_width , :decimal ],
496
+ [ :max_height , :decimal ]
497
+ ],
472
498
  Caboose::User => [
473
499
  [ :first_name , :string ],
474
500
  [ :last_name , :string ],
@@ -502,6 +528,7 @@ class Caboose::Schema < Caboose::Utilities::Schema
502
528
  [ :length , :decimal ],
503
529
  [ :width , :decimal ],
504
530
  [ :height , :decimal ],
531
+ [ :volume , :decimal ],
505
532
  [ :cylinder , :boolean ],
506
533
  [ :option1 , :string ],
507
534
  [ :option2 , :string ],
@@ -687,6 +714,21 @@ class Caboose::Schema < Caboose::Utilities::Schema
687
714
  :slug => 'products'
688
715
  })
689
716
  end
717
+
718
+ if !Caboose::ShippingPackage.where(:carrier => 'USPS', :service_code => "29").exists?
719
+ Caboose::ShippingPackage.create(:carrier => 'USPS', :service_code => "29", :service_name => "USPS Priority Mail 1-Day Padded Flat Rate Envelope", :price=>610 , :volume => 180)
720
+ end
721
+ if !Caboose::ShippingPackage.where(:carrier => 'USPS', :service_code => "28").exists?
722
+ Caboose::ShippingPackage.create(:carrier => 'USPS', :service_code => "28", :service_name => "USPS Priority Mail 1-Day Small Flat Rate Box" , :price=>595 , :length => 8.625 , :width => 5.375 , :height => 1.625 , :volume => 75.334)
723
+ end
724
+ if !Caboose::ShippingPackage.where(:carrier => 'USPS', :service_code => "17").exists?
725
+ Caboose::ShippingPackage.create(:carrier => 'USPS', :service_code => "17", :service_name => "USPS Priority Mail 1-Day Medium Flat Rate Box" , :price=>1265 , :length => 11 , :width => 8.5 , :height => 5.5 , :volume => 514.25)
726
+ Caboose::ShippingPackage.create(:carrier => 'USPS', :service_code => "17", :service_name => "USPS Priority Mail 1-Day Medium Flat Rate Box" , :price=>1265 , :length => 13.625 , :width => 11.875 , :height => 3.375 , :volume => 546.06)
727
+ end
728
+ if !Caboose::ShippingPackage.where(:carrier => 'USPS', :service_code => "22").exists?
729
+ Caboose::ShippingPackage.create(:carrier => 'USPS', :service_code => "22", :service_name => "USPS Priority Mail 1-Day Large Flat Rate Box" , :price=>1790 , :length => 12 , :width => 12 , :height => 5.5 , :volume => 792 )
730
+ Caboose::ShippingPackage.create(:carrier => 'USPS', :service_code => "22", :service_name => "USPS Priority Mail 1-Day Large Flat Rate Box" , :price=>1790 , :length => 23.6875 , :width => 11.75 , :height => 3 , :volume => 834.98)
731
+ end
690
732
 
691
733
  end
692
734
  end
@@ -3,72 +3,48 @@ include ActiveMerchant::Shipping
3
3
 
4
4
  module Caboose
5
5
  class ShippingCalculator
6
+
6
7
  def self.rates(order)
7
- return [] if Caboose::shipping.nil?
8
-
9
- total = 0.0
10
- weight = 0.0
11
-
12
- order.line_items.each do |li|
13
- total = total + (li.variant.shipping_unit_value.nil? ? 0 : li.variant.shipping_unit_value)
14
- weight = weight + (li.variant.weight || 0)
15
- end
16
-
17
- length = 0
18
- width = 0
19
- height = 0
20
-
21
- if total <= 5
22
- length = 15.5
23
- width = 9.5
24
- height = 6
25
- elsif total <= 10
26
- length = 12
27
- width = 8
28
- height = 5
29
- else
30
- length = 20
31
- width = 16
32
- height = 14
33
- end
8
+ return [] if Caboose::store_shipping.nil?
34
9
 
10
+ ss = Caboose::store_shipping
35
11
  origin = Location.new(
36
- :country => Caboose::shipping[:origin][:country],
37
- :state => Caboose::shipping[:origin][:state],
38
- :city => Caboose::shipping[:origin][:city],
39
- :zip => Caboose::shipping[:origin][:zip]
40
- )
41
-
12
+ :country => ss[:origin][:country],
13
+ :state => ss[:origin][:state],
14
+ :city => ss[:origin][:city],
15
+ :zip => ss[:origin][:zip]
16
+ )
42
17
  destination = Location.new(
43
- :country => Caboose::shipping[:origin][:country],
18
+ :country => ss[:origin][:country],
44
19
  :state => order.shipping_address.state,
45
20
  :city => order.shipping_address.city,
46
21
  :postal_code => order.shipping_address.zip
47
- )
48
-
49
- packages = [Package.new(weight, [length, width, height], :units => :imperial)]
50
-
51
- ups = UPS.new(
52
- :key => Caboose::shipping[:ups][:key],
53
- :login => Caboose::shipping[:ups][:username],
54
- :password => Caboose::shipping[:ups][:password],
55
- :origin_account => Caboose::shipping[:ups][:origin_account]
56
- )
57
-
58
- ups_response = ups.find_rates(origin, destination, packages)
59
-
60
- rates = ups_response.rates.collect do |rate|
61
- next if Caboose::allowed_shipping_method_codes && !Caboose::allowed_shipping_method_codes.index(rate.service_code)
62
-
63
- {
64
- :service_code => rate.service_code,
65
- :service_name => rate.service_name,
66
- :total_price => rate.total_price.to_d / 100,
67
- :negotiated_rate => rate.negotiated_rate
68
- }
69
- end
70
-
71
- return rates.compact
22
+ )
23
+ ups = ss[:ups] ? UPS.new(:key => ss[:ups][:key], :login => ss[:ups][:username], :password => ss[:ups][:password], :origin_account => ss[:ups][:origin_account]) : nil
24
+ usps = ss[:usps] ? USPS.new(:login => ss[:usps][:username]) : nil
25
+
26
+ all_rates = []
27
+ order.packages.each do |op|
28
+ sp = op.shipping_package
29
+ package = op.activemerchant_package
30
+ rates = []
31
+ if ups
32
+ resp = ups.find_rates(origin, destination, package)
33
+ resp.rates.sort_by(&:price).each do |rate|
34
+ next if rate.service_code != sp.service_code
35
+ rates << { :carrier => 'UPS', :service_code => rate.service_code, :service_name => rate.service_name, :price => rate.total_price.to_d / 100 }
36
+ end
37
+ end
38
+ if usps
39
+ resp = usps.find_rates(origin, destination, package)
40
+ resp.rates.sort_by(&:price).each do |rate|
41
+ next if rate.service_code != sp.service_code
42
+ rates << { :carrier => 'USPS', :service_code => rate.service_code, :service_name => rate.service_name, :total_price => rate.total_price.to_d / 100 }
43
+ end
44
+ end
45
+ all_rates << [op, rates]
46
+ end
47
+ return all_rates
72
48
  end
73
49
 
74
50
  def self.rate(order)
@@ -76,6 +52,71 @@ module Caboose
76
52
  self.rates(order).each { |rate| return rate if rate[:service_code] == order.shipping_method_code }
77
53
  return nil
78
54
  end
55
+
56
+ # Calculates the packages required for all the items in the order
57
+ #def self.packages_for_order(order)
58
+ #
59
+ # # Make sure all the items in the order have attributes set
60
+ # order.line_items.each do |li|
61
+ # v = li.variant
62
+ # Caboose.log("Error: variant #{v.id} has a zero weight") and return false if v.weight.nil? || v.weight == 0
63
+ # next if v.volume && v.volume > 0
64
+ # Caboose.log("Error: variant #{v.id} has a zero length") and return false if v.length.nil? || v.length == 0
65
+ # Caboose.log("Error: variant #{v.id} has a zero width" ) and return false if v.width.nil? || v.width == 0
66
+ # Caboose.log("Error: variant #{v.id} has a zero height") and return false if v.height.nil? || v.height == 0
67
+ # v.volume = v.length * v.width * v.height
68
+ # v.save
69
+ # end
70
+ #
71
+ # # Reorder the items in the order by volume
72
+ # h = {}
73
+ # order.line_items.each do |li|
74
+ # (1..li.quantity).each do |i|
75
+ # v = li.variant
76
+ # h[v.volume] = v
77
+ # end
78
+ # end
79
+ # variants = h.sort_by{ |k,v| k }.collect{ |x| x[1] }
80
+ #
81
+ # all_packages = ShippingPackage.reorder(:price).all
82
+ # packages = []
83
+ #
84
+ # # Now go through each variant and fit it in a new or existing package
85
+ # variants.each do |v|
86
+ #
87
+ # # See if the item will fit in any of the existing packages
88
+ # it_fits = false
89
+ # packages.each do |h|
90
+ # it_fits = h.shipping_package.fits(h.variants, v)
91
+ # if it_fits
92
+ # h.variants << v
93
+ # break
94
+ # end
95
+ # end
96
+ # next if it_fits
97
+ #
98
+ # # Otherwise find the cheapest package the item will fit into
99
+ # all_packages.each do |p|
100
+ # if p.fits(v)
101
+ # packages << StdClass.new('shipping_package' => p, 'variants' => [v])
102
+ # break
103
+ # end
104
+ # end
105
+ #
106
+ # end
107
+ #
108
+ # return packages
109
+ #
110
+ # #arr = []
111
+ # #packages.each do |h|
112
+ # # p = h.package
113
+ # # weight = 0.0
114
+ # # h.variants.each{ |v| weight = weight + v.weight }
115
+ # # weight = weight * 0.035274
116
+ # # arr << Package.new(weight, [p.length, p.width, p.height], :units => :imperial)
117
+ # #end
118
+ # #return arr
119
+ #
120
+ #end
79
121
  end
80
122
  end
81
-
@@ -0,0 +1,80 @@
1
+ require 'box_packer'
2
+
3
+ module Caboose
4
+ class ShippingPackage < ActiveRecord::Base
5
+ self.table_name = 'store_shipping_packages'
6
+ attr_accessible :id, :carrier, :service_code, :service_name, :length, :width, :height, :volume, :price
7
+
8
+ def fits(variants)
9
+
10
+ arr = variants.is_a?(Array) ? variants : [variants]
11
+ rigid = []
12
+ floppy = []
13
+ arr.each do |v|
14
+ if v.length && v.length > 0 && v.width && v.width > 0 && v.height && v.height > 0
15
+ rigid << v
16
+ else
17
+ floppy << v
18
+ end
19
+ end
20
+ rigid_volume = 0.0
21
+ floppy_volume = 0.0
22
+ rigid.each { |v| rigid_volume = rigid_volume + v.volume }
23
+ floppy.each{ |v| floppy_volume = floppy_volume + v.volume }
24
+ return false if (rigid_volume + floppy_volume) > self.volume
25
+ rigid_boxes = self.boxes(rigid)
26
+
27
+ it_fits = false
28
+ BoxPacker.container [self.length, self.width, self.height] do
29
+ rigid_boxes.each{ |arr| add_item arr }
30
+ count = pack!
31
+ it_fits = true if count == rigid_boxes.count
32
+ end
33
+ return it_fits
34
+
35
+ end
36
+
37
+ # Gets the 3d dimensions of the variants after they're stacked
38
+ def boxes(rigid_variants)
39
+ stackable = {}
40
+ nonstackable = []
41
+ rigid_variants.each do |v|
42
+ sgid = v.product.stackable_group_id
43
+ if sgid
44
+ stackable[sgid] = [] if stackable[sgid].nil?
45
+ stackable[sgid] << v
46
+ else
47
+ nonstackable << [v.length, v.width, v.height]
48
+ end
49
+ end
50
+
51
+ stackable.each do |sgid, arr|
52
+ sg = arr[0].product.stackable_group
53
+ l = 0.0
54
+ w = 0.0
55
+ h = 0.0
56
+ arr.each do |v|
57
+ if l+sg.extra_length >= sg.max_length || w+sg.extra_width >= sg.max_width || h+sg.extra_height >= sg.max_height
58
+ nonstackable << [l, w, h]
59
+ l = 0.0
60
+ w = 0.0
61
+ h = 0.0
62
+ end
63
+ if l == 0.0
64
+ l = v.length
65
+ w = v.width
66
+ h = v.height
67
+ else
68
+ l = l + sg.extra_length
69
+ w = w + sg.extra_width
70
+ h = h + sg.extra_height
71
+ end
72
+ end
73
+ nonstackable << [l, w, h] if l > 0
74
+ end
75
+
76
+ return nonstackable
77
+ end
78
+
79
+ end
80
+ end
@@ -1,7 +1,9 @@
1
1
 
2
2
  class Caboose::Site < ActiveRecord::Base
3
3
  self.table_name = "sites"
4
-
4
+
5
+ has_many :block_type_site_memberships, :class_name => 'Caboose::BlockTypeSiteMembership', :dependent => :delete_all
6
+ has_many :block_types, :through => :block_type_site_memberships
5
7
  has_many :site_memberships, :class_name => 'Caboose::SiteMembership', :dependent => :delete_all
6
8
  has_many :domains, :class_name => 'Caboose::Domain', :dependent => :delete_all
7
9
  has_many :post_categories, :class_name => 'Caboose::PostCategory'
@@ -0,0 +1,17 @@
1
+ module Caboose
2
+ class StackableGroup < ActiveRecord::Base
3
+ self.table_name = 'store_stackable_groups'
4
+
5
+ has_many :products
6
+ attr_accessible :id,
7
+ :name,
8
+ :extra_length,
9
+ :extra_width,
10
+ :extra_height,
11
+ :max_length,
12
+ :max_width,
13
+ :max_height
14
+
15
+ end
16
+ end
17
+
@@ -1,7 +1,6 @@
1
1
  module Caboose
2
2
  class TaxCalculator
3
- def self.tax_rate(address)
4
- ap '--HOOK calculate tax'
3
+ def self.tax_rate(address)
5
4
  return 0 if address.state.downcase != 'al'
6
5
  city = address.city.downcase
7
6
  rate = 0.00
@@ -76,11 +76,8 @@ module Caboose
76
76
 
77
77
  def as_json(options={})
78
78
  self.attributes.merge({
79
- :images => if self.product_images.any?
80
- self.product_images
81
- else
82
- [self.product.product_images.first]
83
- end
79
+ :images => self.product_images.any? ? self.product_images : [self.product.product_images.first],
80
+ :title => "#{self.product.title} (#{self.options.join(', ')})"
84
81
  })
85
82
  end
86
83
 
@@ -1,8 +1,21 @@
1
- <div class="wrapper">
2
- <div id="cart"></div>
3
- </div>
1
+ <div class="constrain">
2
+ <div id='cart'></div>
3
+ </div>
4
+
5
+ <% content_for :caboose_css do %>
6
+ <%= stylesheet_link_tag 'caboose/message_boxes' %>
7
+ <%= stylesheet_link_tag 'caboose/model_binder' %>
8
+ <%= stylesheet_link_tag 'caboose/cart' %>
9
+ <% end %>
4
10
 
5
11
  <% content_for :caboose_js do %>
6
- <%= javascript_include_tag 'caboose/cart' %>
7
- <%= javascript_include_tag 'caboose/product' %>
8
- <% end %>
12
+ <%= javascript_include_tag 'caboose/model/all' %>
13
+ <%= javascript_include_tag 'caboose/cart2' %>
14
+ <script type='text/javascript'>
15
+
16
+ $(document).ready(function() {
17
+ var controller = new Cart();
18
+ });
19
+
20
+ </script>
21
+ <% end %>