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.
- checksums.yaml +9 -9
- data/app/assets/javascripts/caboose/cart2.js +98 -0
- data/app/assets/javascripts/caboose/model/index_table.js +82 -30
- data/app/assets/javascripts/caboose/model/model_binder.js +4 -4
- data/app/assets/stylesheets/caboose/admin.css +1 -0
- data/app/assets/stylesheets/caboose/admin_main.css +0 -42
- data/app/assets/stylesheets/caboose/cart.scss +41 -0
- data/app/assets/stylesheets/caboose/checkout.css.scss +2 -3
- data/app/assets/stylesheets/caboose/message_boxes.scss +49 -0
- data/app/assets/templates/caboose/cart/add_to_cart.jst.ejs +1 -1
- data/app/controllers/caboose/block_types_controller.rb +3 -1
- data/app/controllers/caboose/cart_controller.rb +30 -23
- data/app/controllers/caboose/checkout_controller.rb +11 -1
- data/app/controllers/caboose/products_controller.rb +28 -14
- data/app/controllers/caboose/stackable_groups_controller.rb +107 -0
- data/app/models/caboose/line_item.rb +20 -6
- data/app/models/caboose/order.rb +2 -1
- data/app/models/caboose/order_package.rb +103 -0
- data/app/models/caboose/product.rb +2 -1
- data/app/models/caboose/schema.rb +45 -3
- data/app/models/caboose/shipping_calculator.rb +101 -60
- data/app/models/caboose/shipping_package.rb +80 -0
- data/app/models/caboose/site.rb +3 -1
- data/app/models/caboose/stackable_group.rb +17 -0
- data/app/models/caboose/tax_calculator.rb +1 -2
- data/app/models/caboose/variant.rb +2 -5
- data/app/views/caboose/cart/index.html.erb +19 -6
- data/app/views/caboose/checkout/_cart.html.erb +49 -52
- data/app/views/caboose/checkout/empty.html.erb +9 -2
- data/app/views/caboose/checkout/step_one.html.erb +2 -3
- data/app/views/caboose/checkout/step_three.html.erb +28 -10
- data/app/views/caboose/checkout/step_two.html.erb +2 -4
- data/app/views/caboose/pages/admin_edit_content.html.erb +1 -1
- data/app/views/caboose/products/admin_index.html.erb +12 -11
- data/app/views/caboose/sites/admin_edit.html.erb +33 -6
- data/app/views/caboose/stackable_groups/admin_index.html.erb +43 -0
- data/config/routes.rb +15 -6
- data/lib/caboose/version.rb +1 -1
- data/lib/tasks/caboose.rake +7 -1
- 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::
|
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 =>
|
37
|
-
:state =>
|
38
|
-
:city =>
|
39
|
-
: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 =>
|
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
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
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
|
data/app/models/caboose/site.rb
CHANGED
@@ -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
|
+
|
@@ -76,11 +76,8 @@ module Caboose
|
|
76
76
|
|
77
77
|
def as_json(options={})
|
78
78
|
self.attributes.merge({
|
79
|
-
:images =>
|
80
|
-
|
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="
|
2
|
-
<div id=
|
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/
|
7
|
-
<%= javascript_include_tag 'caboose/
|
8
|
-
|
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 %>
|