caboose-store 0.0.2

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 (172) hide show
  1. checksums.yaml +15 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +113 -0
  4. data/Rakefile +38 -0
  5. data/app/assets/images/caboose_store/caboose_logo_small.png +0 -0
  6. data/app/assets/images/caboose_store/caboose_nav.png +0 -0
  7. data/app/assets/images/caboose_store/caboose_nav_black.png +0 -0
  8. data/app/assets/images/caboose_store/default_user_pic.png +0 -0
  9. data/app/assets/images/caboose_store/loading_green.gif +0 -0
  10. data/app/assets/images/caboose_store/loading_small_white_on_black.gif +0 -0
  11. data/app/assets/images/caboose_store/loading_white_on_black.gif +0 -0
  12. data/app/assets/javascripts/caboose_store/admin.js +20 -0
  13. data/app/assets/javascripts/caboose_store/application.js +17 -0
  14. data/app/assets/javascripts/caboose_store/modal.js +52 -0
  15. data/app/assets/javascripts/caboose_store/modal_integration.js +25 -0
  16. data/app/assets/javascripts/caboose_store/model.form.page.js +30 -0
  17. data/app/assets/javascripts/caboose_store/model.form.user.js +36 -0
  18. data/app/assets/javascripts/caboose_store/shortcut.js +11 -0
  19. data/app/assets/javascripts/caboose_store/station.js +60 -0
  20. data/app/assets/stylesheets/caboose_store/admin.css +100 -0
  21. data/app/assets/stylesheets/caboose_store/application.css +19 -0
  22. data/app/assets/stylesheets/caboose_store/bound_input.css +1 -0
  23. data/app/assets/stylesheets/caboose_store/caboose.css +4 -0
  24. data/app/assets/stylesheets/caboose_store/fonts/big_noodle_titling.ttf +0 -0
  25. data/app/assets/stylesheets/caboose_store/fonts/big_noodle_titling_oblique.ttf +0 -0
  26. data/app/assets/stylesheets/caboose_store/fonts.css +5 -0
  27. data/app/assets/stylesheets/caboose_store/login.css +23 -0
  28. data/app/assets/stylesheets/caboose_store/modal.css +240 -0
  29. data/app/assets/stylesheets/caboose_store/page_bar_generator.css +34 -0
  30. data/app/assets/stylesheets/caboose_store/register.css +25 -0
  31. data/app/assets/stylesheets/caboose_store/station_modal.css +104 -0
  32. data/app/assets/stylesheets/caboose_store/station_sidebar.css +232 -0
  33. data/app/assets/stylesheets/caboose_store/tinymce.css +25 -0
  34. data/app/controllers/caboose_store/application_controller.rb +18 -0
  35. data/app/controllers/caboose_store/cart_controller.rb +59 -0
  36. data/app/controllers/caboose_store/categories_controller.rb +128 -0
  37. data/app/controllers/caboose_store/checkout_controller.rb +164 -0
  38. data/app/controllers/caboose_store/orders_controller.rb +264 -0
  39. data/app/controllers/caboose_store/product_images_controller.rb +38 -0
  40. data/app/controllers/caboose_store/products_controller.rb +387 -0
  41. data/app/controllers/caboose_store/reviews_controller.rb +15 -0
  42. data/app/controllers/caboose_store/variants_controller.rb +152 -0
  43. data/app/helpers/caboose_store/application_helper.rb +46 -0
  44. data/app/helpers/caboose_store/cart_helper.rb +28 -0
  45. data/app/helpers/caboose_store/categories_helper.rb +38 -0
  46. data/app/helpers/caboose_store/products_helper.rb +87 -0
  47. data/app/mailers/caboose_store/orders_mailer.rb +36 -0
  48. data/app/models/caboose_store/address.rb +30 -0
  49. data/app/models/caboose_store/caboose_store_plugin.rb +22 -0
  50. data/app/models/caboose_store/category.rb +63 -0
  51. data/app/models/caboose_store/category_membership.rb +11 -0
  52. data/app/models/caboose_store/discount.rb +14 -0
  53. data/app/models/caboose_store/message.rb +22 -0
  54. data/app/models/caboose_store/order.rb +97 -0
  55. data/app/models/caboose_store/order_discount.rb +11 -0
  56. data/app/models/caboose_store/order_line_item.rb +13 -0
  57. data/app/models/caboose_store/order_pdf.rb +82 -0
  58. data/app/models/caboose_store/product.rb +78 -0
  59. data/app/models/caboose_store/product_image.rb +25 -0
  60. data/app/models/caboose_store/product_image_variant.rb +10 -0
  61. data/app/models/caboose_store/review.rb +13 -0
  62. data/app/models/caboose_store/schema.rb +146 -0
  63. data/app/models/caboose_store/shipping_calculator.rb +79 -0
  64. data/app/models/caboose_store/states.rb +60 -0
  65. data/app/models/caboose_store/tax_calculator.rb +26 -0
  66. data/app/models/caboose_store/tax_line.rb +12 -0
  67. data/app/models/caboose_store/variant.rb +42 -0
  68. data/app/models/caboose_store/vendor.rb +7 -0
  69. data/app/views/caboose_store/application/_category_thumb.html.erb +6 -0
  70. data/app/views/caboose_store/application/_product_thumb.html.erb +13 -0
  71. data/app/views/caboose_store/cart/index.html.erb +19 -0
  72. data/app/views/caboose_store/categories/admin_edit.html.erb +82 -0
  73. data/app/views/caboose_store/categories/admin_index.html.erb +13 -0
  74. data/app/views/caboose_store/categories/admin_new.html.erb +45 -0
  75. data/app/views/caboose_store/checkout/billing.html.erb +168 -0
  76. data/app/views/caboose_store/checkout/discount.html.erb +166 -0
  77. data/app/views/caboose_store/checkout/index.html.erb +113 -0
  78. data/app/views/caboose_store/checkout/quantity_box.html.erb +39 -0
  79. data/app/views/caboose_store/checkout/shipping.html.erb +90 -0
  80. data/app/views/caboose_store/checkout/thank_you.html.erb +36 -0
  81. data/app/views/caboose_store/layouts/_banner.html.erb +10 -0
  82. data/app/views/caboose_store/layouts/_banner2.html.erb +10 -0
  83. data/app/views/caboose_store/layouts/_footer.html.erb +55 -0
  84. data/app/views/caboose_store/layouts/_header.html.erb +69 -0
  85. data/app/views/caboose_store/layouts/_sidebar.html.erb +27 -0
  86. data/app/views/caboose_store/layouts/application.html.erb +33 -0
  87. data/app/views/caboose_store/layouts/authorize_net.erb +18 -0
  88. data/app/views/caboose_store/layouts/layout_about.html.erb +42 -0
  89. data/app/views/caboose_store/layouts/layout_blog.html.erb +159 -0
  90. data/app/views/caboose_store/layouts/layout_confirm.html.erb +85 -0
  91. data/app/views/caboose_store/layouts/layout_contact.html.erb +38 -0
  92. data/app/views/caboose_store/layouts/layout_default.html.erb +10 -0
  93. data/app/views/caboose_store/layouts/layout_detail.html.erb +114 -0
  94. data/app/views/caboose_store/layouts/layout_order.html.erb +77 -0
  95. data/app/views/caboose_store/layouts/layout_pricing.html.erb +182 -0
  96. data/app/views/caboose_store/layouts/layout_product.html.erb +110 -0
  97. data/app/views/caboose_store/layouts/layout_profile.html.erb +55 -0
  98. data/app/views/caboose_store/layouts/layout_single.html.erb +3 -0
  99. data/app/views/caboose_store/layouts/layout_testimonial.html.erb +110 -0
  100. data/app/views/caboose_store/layouts/layout_testing.html.erb +4 -0
  101. data/app/views/caboose_store/orders/_admin_footer.html.erb +2 -0
  102. data/app/views/caboose_store/orders/_admin_header.html.erb +31 -0
  103. data/app/views/caboose_store/orders/_quickbooks_order.html.erb +0 -0
  104. data/app/views/caboose_store/orders/admin_delete_form.html.erb +21 -0
  105. data/app/views/caboose_store/orders/admin_edit.html.erb +173 -0
  106. data/app/views/caboose_store/orders/admin_index.html.erb +79 -0
  107. data/app/views/caboose_store/orders/admin_new.html.erb +42 -0
  108. data/app/views/caboose_store/orders/admin_print.html.erb +72 -0
  109. data/app/views/caboose_store/orders_mailer/customer_new_order.html.erb +47 -0
  110. data/app/views/caboose_store/orders_mailer/customer_status_updated.html.erb +49 -0
  111. data/app/views/caboose_store/orders_mailer/fulfillment_new_order.html.erb +43 -0
  112. data/app/views/caboose_store/orders_mailer/shipping_order_ready.html.erb +46 -0
  113. data/app/views/caboose_store/products/_admin_footer.html.erb +2 -0
  114. data/app/views/caboose_store/products/_admin_header.html.erb +31 -0
  115. data/app/views/caboose_store/products/admin_delete_form.html.erb +21 -0
  116. data/app/views/caboose_store/products/admin_edit_categories.html.erb +73 -0
  117. data/app/views/caboose_store/products/admin_edit_category_images.html.erb +233 -0
  118. data/app/views/caboose_store/products/admin_edit_description.html.erb +41 -0
  119. data/app/views/caboose_store/products/admin_edit_general.html.erb +47 -0
  120. data/app/views/caboose_store/products/admin_edit_images.html.erb +234 -0
  121. data/app/views/caboose_store/products/admin_edit_options.html.erb +51 -0
  122. data/app/views/caboose_store/products/admin_edit_seo.html.erb +37 -0
  123. data/app/views/caboose_store/products/admin_edit_variant_columns.html.erb +75 -0
  124. data/app/views/caboose_store/products/admin_edit_variants.html.erb +101 -0
  125. data/app/views/caboose_store/products/admin_edit_variants_single.html.erb +68 -0
  126. data/app/views/caboose_store/products/admin_index.html.erb +47 -0
  127. data/app/views/caboose_store/products/admin_new.html.erb +41 -0
  128. data/app/views/caboose_store/products/details.html.erb +437 -0
  129. data/app/views/caboose_store/products/index.html.erb +46 -0
  130. data/app/views/caboose_store/products/not_available.html.erb +35 -0
  131. data/app/views/caboose_store/variants/admin_edit.html.erb +80 -0
  132. data/app/views/caboose_store/variants/admin_new.html.erb +59 -0
  133. data/config/routes.rb +95 -0
  134. data/lib/caboose-store/caboose_store_helper.rb +35 -0
  135. data/lib/caboose-store/engine.rb +8 -0
  136. data/lib/caboose-store/version.rb +3 -0
  137. data/lib/caboose-store.rb +9 -0
  138. data/lib/tasks/caboose-store.rake +17 -0
  139. data/test/caboose_test.rb +7 -0
  140. data/test/dummy/README.rdoc +261 -0
  141. data/test/dummy/Rakefile +7 -0
  142. data/test/dummy/app/assets/javascripts/application.js +15 -0
  143. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  144. data/test/dummy/app/controllers/application_controller.rb +3 -0
  145. data/test/dummy/app/helpers/application_helper.rb +2 -0
  146. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  147. data/test/dummy/config/application.rb +59 -0
  148. data/test/dummy/config/boot.rb +10 -0
  149. data/test/dummy/config/database.yml +25 -0
  150. data/test/dummy/config/environment.rb +5 -0
  151. data/test/dummy/config/environments/development.rb +37 -0
  152. data/test/dummy/config/environments/production.rb +67 -0
  153. data/test/dummy/config/environments/test.rb +37 -0
  154. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  155. data/test/dummy/config/initializers/inflections.rb +15 -0
  156. data/test/dummy/config/initializers/mime_types.rb +5 -0
  157. data/test/dummy/config/initializers/secret_token.rb +7 -0
  158. data/test/dummy/config/initializers/session_store.rb +8 -0
  159. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  160. data/test/dummy/config/locales/en.yml +5 -0
  161. data/test/dummy/config/routes.rb +4 -0
  162. data/test/dummy/config.ru +4 -0
  163. data/test/dummy/db/test.sqlite3 +0 -0
  164. data/test/dummy/log/test.log +25 -0
  165. data/test/dummy/public/404.html +26 -0
  166. data/test/dummy/public/422.html +26 -0
  167. data/test/dummy/public/500.html +25 -0
  168. data/test/dummy/public/favicon.ico +0 -0
  169. data/test/dummy/script/rails +6 -0
  170. data/test/integration/navigation_test.rb +10 -0
  171. data/test/test_helper.rb +15 -0
  172. metadata +260 -0
@@ -0,0 +1,87 @@
1
+ module CabooseStore
2
+ module ProductsHelper
3
+
4
+ def category_options(top_categories, selected_id = nil)
5
+ arr = []
6
+ top_categories.each do |cat|
7
+ category_options_helper(cat, selected_id, arr)
8
+ end
9
+ return arr.join("\n")
10
+ end
11
+
12
+ def category_options_helper(cat, selected_id, arr, prefix = "")
13
+ opt = "<option value='#{cat.id}'"
14
+ opt << " selected='true'" if !selected_id.nil? && selected_id == cat.id
15
+ opt << ">#{prefix}#{cat.name}</option>"
16
+ arr << opt
17
+ cat.children.each do |cat2|
18
+ category_options_helper(cat2, selected_id, arr, "#{prefix} - ")
19
+ end
20
+ end
21
+
22
+ def category_checkboxes(top_categories, selected_ids = nil)
23
+ str = "<ul>"
24
+ top_categories.each do |cat|
25
+ category_checkboxes_helper(cat, selected_ids, str)
26
+ end
27
+ str << "</ul>"
28
+ return str
29
+ end
30
+
31
+ def category_checkboxes_helper(cat, selected_ids, str, prefix = "")
32
+ str << "<li>"
33
+ if cat.children && cat.children.count > 0
34
+ str << "<input type='checkbox' id='cat_#{cat.id}' value='#{cat.id}'"
35
+ str << " checked='true'" if selected_ids && selected_ids.include?(cat.id)
36
+ str << "> <label for='#{cat.id}'><h2>#{cat.name}</h2></label>"
37
+ else
38
+ str << "<input type='checkbox' id='cat_#{cat.id}' value='#{cat.id}'"
39
+ str << " checked='true'" if selected_ids && selected_ids.include?(cat.id)
40
+ str << "> <label for='#{cat.id}'>#{cat.name}</label>"
41
+ end
42
+ cat.children.each do |cat2|
43
+ str << "<ul>"
44
+ category_checkboxes_helper(cat2, selected_ids, str, "#{prefix}&nbsp;&nbsp;")
45
+ str << "</ul>"
46
+ end
47
+ str << "</li>"
48
+ end
49
+
50
+ def product_price(p)
51
+ price = ""
52
+ if p.price_varies
53
+ arr = p.price_range
54
+ min = number_to_currency(arr[0], :precision => 2)
55
+ max = number_to_currency(arr[1], :precision => 2)
56
+ if min.eql? max
57
+ price = "#{min}"
58
+ else
59
+ price = "#{min}-#{max}"
60
+ end
61
+ else
62
+ price = p.variants[0].price
63
+ price = number_to_currency(price, :precision => 2)
64
+ end
65
+ return price
66
+ end
67
+
68
+ def breadcrumb(p)
69
+ return p.category.ancestry.collect{|cat| "<li><a href='/products/#{cat.id}'>#{cat.name}</a></li>"}.join("<span class='divider'>/</span>")
70
+ end
71
+
72
+ #def product_thumb(product, price)
73
+ # style = square_image(product.featured_image)
74
+ # price = product.most_popular_variant.price if price.nil?
75
+ #
76
+ # str = "<li class='thumb'>"
77
+ # str << "<a href='/products/#{product.id}'>"
78
+ # str << "<figure class='thumb-image' style='<%= style %>"></figure>"
79
+ # str << "<div class="thumb-title"><%= product.title %></div>"
80
+ # str << " <div class="thumb-price"><%= price %></div>"
81
+ # str << "</a>"
82
+ # str << "</li><!-- .thumb -->"
83
+ #
84
+ #end
85
+
86
+ end
87
+ end
@@ -0,0 +1,36 @@
1
+ module CabooseStore
2
+ class OrdersMailer < ActionMailer::Base
3
+ default :from => "orders@tuskwearcollection.com"
4
+
5
+ # Sends a confirmation email to the customer about a new order
6
+ def customer_new_order(order)
7
+ @order = order
8
+ mail(:to => order.customer.email, :subject => "Thank you from TuskWear!")
9
+ end
10
+
11
+ # Sends a notification email to the fulfillment dept about a new order
12
+ def fulfillment_new_order(order)
13
+ @order = order
14
+ #config = YAML::load(File.open("#{Rails.root}/config/tuskwear.yml"))
15
+ #fulfillment_email = config[Rails.env]['order_fulfillment_email']
16
+ #mail(:to => fulfillment_email, :subject => "New Order")
17
+ mail(:to => 'info@tuskwearcollection.com', :subject => "New Order")
18
+ #mail(:to => 'william@nine.is', :subject => "New Order")
19
+ end
20
+
21
+ # Sends a notification email to the shipping dept that an order is ready to be shipped
22
+ def shipping_order_ready(order)
23
+ @order = order
24
+ #config = YAML::load(File.open("#{Rails.root}/config/tuskwear.yml"))
25
+ #shipping_email = config[Rails.env]['order_shipping_email']
26
+ #mail(:to => shipping_email, :subject => "Order ready for shipping")
27
+ mail(:to => 'info@tuskwearcollection.com', :subject => "Order ready for shipping")
28
+ end
29
+
30
+ # Sends a notification email to the customer that the status of the order has been changed
31
+ def customer_status_updated(order)
32
+ @order = order
33
+ mail(:to => order.customer.email, :subject => "TuskWear Order Status Update")
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,30 @@
1
+ module CabooseStore
2
+ class Address < ActiveRecord::Base
3
+ self.table_name = "store_addresses"
4
+
5
+ attr_accessible :id,
6
+ :name,
7
+ :first_name,
8
+ :last_name,
9
+ :street,
10
+ :address1,
11
+ :address2,
12
+ :company,
13
+ :city,
14
+ :state,
15
+ :province,
16
+ :province_code,
17
+ :zip,
18
+ :country,
19
+ :country_code,
20
+ :phone
21
+
22
+ #validates :street, presence: true
23
+ #validates :address1, presence: true
24
+ #validates :city, presence: true
25
+ #validates :zip, numericality: true
26
+ #validates :phone, uniqueness: true
27
+ #validates :company, presence: true
28
+
29
+ end
30
+ end
@@ -0,0 +1,22 @@
1
+ module CabooseStore
2
+ class CabooseStorePlugin < Caboose::CaboosePlugin
3
+
4
+ def self.admin_nav(nav, user = nil, page = nil)
5
+ return nav if user.nil?
6
+
7
+ item = {
8
+ 'id' => 'general-store',
9
+ 'text' => 'General Store',
10
+ 'children' => []
11
+ }
12
+
13
+ item['children'] << { 'id' => 'categories', 'href' => '/admin/categories' , 'text' => 'Categories' , 'modal' => false } if user.is_allowed('categories' , 'view')
14
+ item['children'] << { 'id' => 'products' , 'href' => '/admin/products' , 'text' => 'Products' , 'modal' => false } if user.is_allowed('products' , 'view')
15
+ item['children'] << { 'id' => 'orders' , 'href' => '/admin/orders' , 'text' => 'Orders' , 'modal' => false } if user.is_allowed('orders' , 'view')
16
+
17
+ nav << item
18
+ return nav
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,63 @@
1
+ module CabooseStore
2
+ class Category < ActiveRecord::Base
3
+ self.table_name = "store_categories"
4
+
5
+ belongs_to :parent, :class_name => 'Category', :foreign_key => 'parent_id'
6
+ has_many :children, :class_name => 'Category', :foreign_key => 'parent_id', :order => 'name'
7
+ has_many :products, :through => :category_memberships, :order => 'title'
8
+ has_many :category_memberships
9
+ has_attached_file :image,
10
+ :path => "categories/:id_:style.jpg",
11
+ :default_url => '/categories/:id_:style.jpg',
12
+ :styles => {
13
+ :tiny => '100x100>',
14
+ :thumb => '250x250>',
15
+ :medium => '400x400>',
16
+ :large => '800x800>',
17
+ :huge => '1200x1200>'
18
+ }
19
+
20
+ attr_accessible :id, :parent_id, :name, :url, :slug
21
+
22
+ def ancestry
23
+ return [self] if self.parent.nil?
24
+ arr = self.parent.ancestry
25
+ arr << self
26
+ return arr
27
+ end
28
+
29
+ def self.options(selected_id = nil)
30
+ arr = []
31
+ self.where(:parent_id => nil).reorder('name').all.each do |cat|
32
+ self.options_helper(cat, selected_id, arr)
33
+ end
34
+ return arr
35
+ end
36
+
37
+ def self.options_helper(cat, selected_id, arr, prefix = "")
38
+ arr << {
39
+ :value => cat.id,
40
+ :text => "#{prefix}#{cat.name}"
41
+ }
42
+ cat.children.each do |cat2|
43
+ self.options_helper(cat2, selected_id, arr, "#{prefix} - ")
44
+ end
45
+ end
46
+
47
+ def featured_image(size)
48
+ if self.products == []
49
+ return 'http://s3.amazonaws.com/categories/no_image.jpg'
50
+ end
51
+
52
+ return self.products.reject{|p| p.featured_image.nil? || p.nil?}.first.featured_image.url(size) unless self.products.first.product_images == []
53
+ return self.products.reject{|p| p.featured_image.nil? || p.nil?}.second.featured_image.url(size) unless self.products.second.product_images == []
54
+ return self.products.reject{|p| p.featured_image.nil? || p.nil?}.last.featured_image.url(size) unless self.products.last.product_images == []
55
+
56
+ end
57
+
58
+ def self.get_slug(str)
59
+ return str.gsub(' ', '-').downcase
60
+ end
61
+
62
+ end
63
+ end
@@ -0,0 +1,11 @@
1
+ module CabooseStore
2
+ class CategoryMembership < ActiveRecord::Base
3
+ self.table_name = "store_category_memberships"
4
+
5
+ belongs_to :category
6
+ belongs_to :product
7
+
8
+ attr_accessible :category_id, :product_id
9
+
10
+ end
11
+ end
@@ -0,0 +1,14 @@
1
+ module CabooseStore
2
+ class Discount < ActiveRecord::Base
3
+ self.table_name = "store_discounts"
4
+
5
+ attr_accessible :id,
6
+ :name, # The name of this discount
7
+ :code, # The code the customer has to input to apply for this discount
8
+ :amount_flat, # Amount of the savings flat off the total
9
+ :amount_percentage, # Amount of savings as a percentage off the total
10
+ :no_shipping, # Whether or not it's a free shipping discount
11
+ :no_tax # Whether or not it's a free shipping discount
12
+
13
+ end
14
+ end
@@ -0,0 +1,22 @@
1
+ module CabooseStore
2
+ class Message
3
+ include ActiveModel::Validations
4
+ include ActiveModel::Conversion
5
+ extend ActiveModel::Naming
6
+
7
+ attr_accessor :name, :email, :body
8
+
9
+ validates :name, :email, :body, presence: true
10
+ validates :email, format: { with: %r{.+@.+\..+} }, allow_blank: false
11
+
12
+ def initialize(attributes = {})
13
+ attributes.each do |name, value|
14
+ send("#{name}=", value)
15
+ end
16
+ end
17
+
18
+ def persisted?
19
+ false
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,97 @@
1
+ module CabooseStore
2
+ class Order < ActiveRecord::Base
3
+ self.table_name = "store_orders"
4
+
5
+ belongs_to :customer, :class_name => 'Caboose::User'
6
+ belongs_to :shipping_address, :class_name => 'Address'
7
+ belongs_to :billing_address, :class_name => 'Address'
8
+ has_many :discounts, :through => :order_discounts
9
+ has_many :order_discounts
10
+ has_many :order_line_items
11
+
12
+ attr_accessible :id,
13
+ :order_number, # Customer-set unique number of the order
14
+ :subtotal,
15
+ :tax,
16
+ :shipping_method,
17
+ :shipping_method_code,
18
+ :shipping,
19
+ :discount,
20
+ :total,
21
+ :status, # The current order status. One of: cart, pending, backordered, fulfilled
22
+ :payment_status, # The current payment status. One of: nil, 'pending', 'authorized', 'paid', 'voided', 'refunded'
23
+ :notes, # The note which is attached to the order.
24
+ :referring_site, # Contains the url of the referrer that brought the customer to your store
25
+ :landing_site, # Contains the path of the landing site the customer used. The first page that the customer saw when he/she reached the store.
26
+ :landing_site_ref, # Looks at the landing site and extracts a reference parameter from it.
27
+ :cancel_reason, # The reason selected when cancelling the order. One of: 'inventory', 'customer', 'fraud', 'other'
28
+ :date_created,
29
+ :date_authorized,
30
+ :date_captured,
31
+ :date_cancelled
32
+
33
+ def line_items
34
+ return self.order_line_items
35
+ end
36
+
37
+ def subtotal
38
+ return self.order_line_items.inject(0.0){ |sum,li| sum + li.subtotal }
39
+ end
40
+
41
+ # Array of any Line Items which have been fulfilled (marked as shipped on the order screen).
42
+ def fulfilled_line_items
43
+ return self.order_line_items.where(:status => 'shipped').all
44
+ end
45
+
46
+ # Array of those Line Items which have not yet been fulfilled (marked as shipped on the order screen).
47
+ def unfulfilled_line_items
48
+ return self.order_line_items.where('status != ?', 'shipped').all
49
+ end
50
+
51
+ def cancelled
52
+ return self.status == 'cancelled'
53
+ end
54
+
55
+ # Returns true if there is at least one item in the order that requires shipping, and returns false otherwise
56
+ def requires_shipping
57
+ requires = false
58
+ self.order_line_items.each do |li|
59
+ if li.variant.requires_shipping
60
+ requires = true
61
+ break
62
+ end
63
+ end
64
+ return requires
65
+ end
66
+
67
+ def calculate_total
68
+ self.calculate_discount
69
+ self.total = self.subtotal + self.tax + self.shipping + self.handling - self.discount
70
+ return self.total
71
+ end
72
+
73
+ def calculate_discount
74
+
75
+ percentage_off = 0.0
76
+ amount_off = 0.0
77
+ no_shipping = false
78
+ no_tax = false
79
+
80
+ self.discounts.each do |d|
81
+ percentage_off = percentage_off + d.amount_percentage
82
+ amount_off = amount_off + d.amount_flat
83
+ no_shipping = true if d.no_shipping
84
+ no_tax = true if d.no_tax
85
+ end
86
+
87
+ x = 0.0
88
+ x = x + self.subtotal * percentage_off if percentage_off > 0
89
+ x = x + amount_off if amount_off > 0
90
+ x = x + self.shipping if no_shipping
91
+ x = x + self.tax if no_tax
92
+
93
+ self.discount = x
94
+ return self.discount
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,11 @@
1
+ module CabooseStore
2
+ class OrderDiscount < ActiveRecord::Base
3
+ self.table_name = "store_order_discounts"
4
+
5
+ belongs_to :order
6
+ belongs_to :discount
7
+
8
+ attr_accessible :order_id, :discount_id
9
+
10
+ end
11
+ end
@@ -0,0 +1,13 @@
1
+ module CabooseStore
2
+ class OrderLineItem < ActiveRecord::Base
3
+ self.table_name = "store_order_line_items"
4
+
5
+ belongs_to :variant
6
+ belongs_to :order
7
+ attr_accessible :id, :variant_id, :quantity, :quantity_shipped
8
+
9
+ def subtotal
10
+ return self.unit_price * self.quantity
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,82 @@
1
+ require 'prawn'
2
+
3
+ module CabooseStore
4
+ class OrderPdf < Prawn::Document
5
+
6
+ attr_accessor :order
7
+
8
+ def to_pdf
9
+ image open("https://dmwwflw4i3miv.cloudfront.net/logo.png"), :position => :center
10
+ text " "
11
+ customer_info
12
+ text " "
13
+ order_table
14
+ render
15
+ end
16
+
17
+ def customer_info
18
+
19
+ order_info = "Order ##{order.id}\n"
20
+ order_info << "Status: #{order.status.capitalize}\n"
21
+ order_info << "Received: #{order.date_created.strftime("%m/%d/%Y")}\n"
22
+ if order.status == 'shipped' && order.date_shipped
23
+ order_info << "Shipped: #{order.date_shipped.strftime("%m/%d/%Y")}"
24
+ end
25
+
26
+ c = order.customer
27
+ billed_to = "#{c.first_name} #{c.last_name}\n#{c.email}\n#{c.phone}"
28
+
29
+ sa = order.shipping_address
30
+ shipped_to = "#{sa.name}\n#{sa.address1}\n"
31
+ shipped_to << "#{sa.address2}\n" if sa.address2.strip.length > 0
32
+ shipped_to << "#{sa.city}, #{sa.state} #{sa.zip}"
33
+
34
+ tbl = []
35
+ tbl << [
36
+ { :content => "Order Info" , :align => :center, :valign => :bottom, :width => 180 },
37
+ { :content => "Billed To" , :align => :center, :valign => :bottom, :width => 180 },
38
+ { :content => "Shipped To" , :align => :center, :valign => :bottom, :width => 180 }
39
+ ]
40
+ tbl << [
41
+ { :content => order_info, :valign => :top, :height => 75 },
42
+ { :content => billed_to , :valign => :top, :height => 75 },
43
+ { :content => shipped_to, :valign => :top, :height => 75 }
44
+ ]
45
+ table tbl
46
+
47
+ end
48
+
49
+ def order_table
50
+
51
+ tbl = []
52
+ tbl << [
53
+ { :content => "Item" , :align => :center, :valign => :bottom },
54
+ { :content => "Tracking Number" , :align => :center, :valign => :bottom },
55
+ { :content => "Unit Price" , :align => :center, :valign => :bottom },
56
+ { :content => "Qty Ordered" , :align => :center, :valign => :bottom },
57
+ { :content => "Qty Shipped" , :align => :center, :valign => :bottom },
58
+ { :content => "Subtotal" , :align => :center, :valign => :bottom, :width => 60 }
59
+ ]
60
+
61
+ order.line_items.each do |li|
62
+ tbl << [
63
+ "#{li.variant.product.title}\n#{li.variant.sku}\n#{li.variant.title}",
64
+ { :content => li.tracking_number },
65
+ { :content => sprintf("%.2f", li.variant.price) , :align => :right },
66
+ { :content => "#{li.quantity}" , :align => :right },
67
+ { :content => "#{li.quantity_shipped}" , :align => :right },
68
+ { :content => sprintf("%.2f", li.subtotal) , :align => :right }
69
+ ]
70
+ end
71
+ tbl << [{ :content => "Subtotal" , :colspan => 5, :align => :right }, { :content => sprintf("%.2f", order.subtotal ) , :align => :right }]
72
+ tbl << [{ :content => "Tax" , :colspan => 5, :align => :right }, { :content => sprintf("%.2f", order.tax ) , :align => :right }]
73
+ tbl << [{ :content => "#{order.shipping_method} Shipping & Handling" , :colspan => 5, :align => :right }, { :content => sprintf("%.2f", order.shipping + order.handling) , :align => :right }]
74
+ tbl << [{ :content => "Discount" , :colspan => 5, :align => :right }, { :content => sprintf("%.2f", order.discount ) , :align => :right }]
75
+ tbl << [{ :content => "Total" , :colspan => 5, :align => :right }, { :content => sprintf("%.2f", order.total ) , :align => :right }]
76
+
77
+ table tbl
78
+
79
+ end
80
+
81
+ end
82
+ end
@@ -0,0 +1,78 @@
1
+ module CabooseStore
2
+ class Product < ActiveRecord::Base
3
+ self.table_name = "store_products"
4
+
5
+ belongs_to :vendor
6
+ has_many :categories, :through => :category_memberships
7
+ has_many :category_memberships
8
+ has_many :variants
9
+ has_many :product_images
10
+ has_many :reviews
11
+
12
+ attr_accessible :id,
13
+ :title,
14
+ :description,
15
+ :vendor_id,
16
+ :handle,
17
+ :seo_title,
18
+ :seo_description,
19
+ :option1,
20
+ :option2,
21
+ :option3,
22
+ :default1,
23
+ :default2,
24
+ :default3,
25
+ :status,
26
+ :alternate_id
27
+
28
+ def options
29
+ arr = []
30
+ arr << self.option1 if !self.option1.nil? && self.option1.strip.length > 0
31
+ arr << self.option2 if !self.option2.nil? && self.option2.strip.length > 0
32
+ arr << self.option3 if !self.option3.nil? && self.option3.strip.length > 0
33
+ return arr
34
+ end
35
+
36
+ def most_popular_variant
37
+ self.variants.order('price DESC').first
38
+ end
39
+
40
+ def featured_image
41
+ self.product_images.reject{|p| p.nil?}.first
42
+ end
43
+
44
+ def price_varies
45
+ arr = variants.collect{ |v| v.price }.uniq
46
+ return arr.count > 0
47
+ end
48
+
49
+ def price_range
50
+ min = 100000
51
+ max = 0
52
+ variants.each do |v|
53
+ next if v.nil? || v.price.nil?
54
+ min = v.price if v.price < min
55
+ max = v.price if v.price > max
56
+ end
57
+ return [min, max]
58
+ end
59
+
60
+ def url
61
+ return "/products/#{self.id}"
62
+ end
63
+
64
+ def related_items
65
+ return []
66
+ end
67
+
68
+ def in_stock
69
+ return Variant.where(:product_id => self.id).where("quantity_in_stock > 0").count > 0
70
+ end
71
+
72
+ # Returns non deleted variants
73
+ def live_variants
74
+ return self.variants.where(:status => ['Active', 'Inactive'])
75
+ end
76
+
77
+ end
78
+ end
@@ -0,0 +1,25 @@
1
+ module CabooseStore
2
+ class ProductImage < ActiveRecord::Base
3
+ self.table_name = "store_product_images"
4
+
5
+ belongs_to :product
6
+ has_and_belongs_to_many :variants
7
+ attr_accessible :id, :title
8
+ has_attached_file :image,
9
+ #:path => "#{Rails.root}/public/products/:product_id_:id_:style.:extension",
10
+ :path => "products/:product_id_:id_:style.:extension",
11
+ :default_url => '/products/:id_:style.:extension',
12
+ :styles => {
13
+ :tiny => '100x100>',
14
+ :thumb => '250x250>',
15
+ :medium => '400x400>',
16
+ :large => '800x800>',
17
+ :huge => '1200x1200>'
18
+ }
19
+
20
+ def url(size) # 'tiny', 'thumb', 'medium', 'large', 'huge'
21
+ self.image.url(size)
22
+ #"https://s3.amazonaws.com/tuskwear/products/#{self.product_id}_#{self.id}_#{size}.jpg"
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,10 @@
1
+
2
+ module CabooseStore
3
+ class ProductImageVariant < ActiveRecord::Base
4
+ self.table_name = "store_product_image_variants"
5
+
6
+ belongs_to :product_image
7
+ belongs_to :variant
8
+
9
+ end
10
+ end
@@ -0,0 +1,13 @@
1
+ module CabooseStore
2
+ class Review < ActiveRecord::Base
3
+ self.table_name = "store_reviews"
4
+
5
+ belongs_to :product
6
+
7
+ attr_accessible :id,
8
+ :product_id,
9
+ :name,
10
+ :rating,
11
+ :content
12
+ end
13
+ end