caboose-store 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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