shoppe 0.0.14 → 0.0.15

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. data/app/assets/javascripts/shoppe/application.coffee +57 -1
  2. data/app/assets/javascripts/shoppe/mousetrap.js +9 -0
  3. data/app/assets/stylesheets/shoppe/application.scss +70 -59
  4. data/app/assets/stylesheets/shoppe/dialog.scss +10 -0
  5. data/app/assets/stylesheets/shoppe/sub.scss +15 -0
  6. data/app/controllers/shoppe/application_controller.rb +13 -1
  7. data/app/controllers/shoppe/attachments_controller.rb +10 -8
  8. data/app/controllers/shoppe/dashboard_controller.rb +6 -4
  9. data/app/controllers/shoppe/delivery_service_prices_controller.rb +33 -31
  10. data/app/controllers/shoppe/delivery_services_controller.rb +34 -32
  11. data/app/controllers/shoppe/orders_controller.rb +40 -38
  12. data/app/controllers/shoppe/product_categories_controller.rb +34 -32
  13. data/app/controllers/shoppe/products_controller.rb +32 -44
  14. data/app/controllers/shoppe/sessions_controller.rb +24 -22
  15. data/app/controllers/shoppe/stock_level_adjustments_controller.rb +40 -0
  16. data/app/controllers/shoppe/tax_rates_controller.rb +35 -33
  17. data/app/controllers/shoppe/users_controller.rb +40 -33
  18. data/app/controllers/shoppe/variants_controller.rb +50 -0
  19. data/app/helpers/shoppe/shoppe_helper.rb +2 -2
  20. data/app/mailers/shoppe/order_mailer.rb +20 -18
  21. data/app/models/shoppe/country.rb +1 -1
  22. data/app/models/shoppe/delivery_service.rb +17 -15
  23. data/app/models/shoppe/delivery_service_price.rb +18 -16
  24. data/app/models/shoppe/order.rb +293 -290
  25. data/app/models/shoppe/order_item.rb +115 -113
  26. data/app/models/shoppe/product.rb +76 -54
  27. data/app/models/shoppe/product/product_attributes.rb +12 -10
  28. data/app/models/shoppe/product/variants.rb +26 -0
  29. data/app/models/shoppe/product_attribute.rb +40 -38
  30. data/app/models/shoppe/product_category.rb +16 -14
  31. data/app/models/shoppe/stock_level_adjustment.rb +1 -2
  32. data/app/models/shoppe/tax_rate.rb +2 -2
  33. data/app/models/shoppe/user.rb +34 -32
  34. data/app/views/shoppe/orders/index.html.haml +3 -4
  35. data/app/views/shoppe/orders/show.html.haml +5 -5
  36. data/app/views/shoppe/products/_form.html.haml +28 -27
  37. data/app/views/shoppe/products/_table.html.haml +42 -0
  38. data/app/views/shoppe/products/edit.html.haml +2 -1
  39. data/app/views/shoppe/products/index.html.haml +1 -24
  40. data/app/views/shoppe/shared/error.html.haml +4 -0
  41. data/app/views/shoppe/{products/stock_levels.html.haml → stock_level_adjustments/index.html.haml} +12 -6
  42. data/app/views/shoppe/variants/form.html.haml +64 -0
  43. data/app/views/shoppe/variants/index.html.haml +33 -0
  44. data/config/routes.rb +2 -1
  45. data/config/shoppe.example.yml +16 -2
  46. data/db/migrate/20131022090919_refactor_order_items_to_allow_any_product.rb +6 -0
  47. data/db/migrate/20131022092904_rename_product_title_to_name.rb +5 -0
  48. data/db/migrate/20131022093538_stock_level_adjustments_should_be_polymorphic.rb +6 -0
  49. data/db/migrate/20131022135331_add_parent_id_to_products.rb +5 -0
  50. data/db/migrate/20131022145653_cost_price_should_be_default_to_zero.rb +9 -0
  51. data/db/seeds.rb +20 -20
  52. data/lib/shoppe.rb +2 -0
  53. data/lib/shoppe/errors/not_enough_stock.rb +1 -1
  54. data/lib/shoppe/errors/unorderable_item.rb +11 -0
  55. data/lib/shoppe/orderable_item.rb +39 -0
  56. data/lib/shoppe/version.rb +1 -1
  57. data/test/dummy/db/schema.rb +14 -11
  58. data/test/dummy/log/development.log +75 -0
  59. metadata +37 -5
@@ -0,0 +1,4 @@
1
+ = display_flash
2
+ .error
3
+ %p= @exception.message
4
+ %p.back= link_to "← Back to Shoppe".html_safe, root_path, :class => 'button'
@@ -1,16 +1,22 @@
1
- - @page_title = "Stock Levels - #{@product.title}"
1
+ - @page_title = "Stock Levels - #{@item.name}"
2
2
  = content_for :header do
3
3
  %p.buttons
4
- = link_to "Edit product", [:edit, @product], :class => 'button'
5
- = link_to "Back to product list", :products, :class => 'button'
6
- %h2.products= @product.title
4
+ - case @item
5
+ - when Shoppe::Product
6
+ - @active_nav = :products
7
+ = link_to "Edit product", [:edit, @item], :class => 'button'
8
+ = link_to "Back to product list", :products, :class => 'button'
9
+
10
+ %h2.products Stock Levels for #{@item.name}
7
11
 
8
12
  .table
9
13
  %p.info
10
- Current stock level is <b>#{@product.stock}</b>
14
+ Current stock level is <b>#{@item.stock}</b>
11
15
  %span.float-right= page_entries_info @stock_level_adjustments
12
16
 
13
- = form_for @new_sla, :url => [:stock_levels, @product] do |f|
17
+ = form_for @new_sla do |f|
18
+ = hidden_field_tag 'item_type', params[:item_type]
19
+ = hidden_field_tag 'item_id', params[:item_id]
14
20
  %table.data
15
21
  %thead
16
22
  %tr
@@ -0,0 +1,64 @@
1
+ - @page_title = "Variants - #{@product.name}"
2
+ = content_for :header do
3
+ %p.buttons= link_to "Back to variants", [@product, :variants], :class => 'button'
4
+ %h2.products Variants of #{@product.name}
5
+
6
+
7
+ = form_for [@product, @variant], :url => @variant.new_record? ? product_variants_path(@product) : product_variant_path(@product, @variant), :html => {:multipart => true} do |f|
8
+ = f.error_messages
9
+ = field_set_tag "Product Information" do
10
+ .splitContainer
11
+ %dl.third
12
+ %dt= f.label :name
13
+ %dd= f.text_field :name, :class => 'text focus'
14
+ %dl.third
15
+ %dt= f.label :permalink
16
+ %dd= f.text_field :permalink, :class => 'text'
17
+ %dl.third
18
+ %dt= f.label :sku, 'SKU'
19
+ %dd= f.text_field :sku, :class => 'text'
20
+
21
+ = field_set_tag "Image" do
22
+ %dl
23
+ %dd
24
+ = attachment_preview @variant.default_image, :hide_if_blank => true
25
+ %p= f.file_field :default_image_file
26
+
27
+ = field_set_tag "Pricing" do
28
+ .splitContainer
29
+ %dl.third
30
+ %dt= f.label :price
31
+ %dd= f.text_field :price, :class => 'text'
32
+ %dl.third
33
+ %dt= f.label :cost_price
34
+ %dd= f.text_field :cost_price, :class => 'text'
35
+ %dl.third
36
+ %dt= f.label :tax_rate_id
37
+ %dd= f.collection_select :tax_rate_id, Shoppe::TaxRate.ordered, :id, :description, {:include_blank => true}, {:class => 'chosen-with-deselect', :data => {:placeholder => "No tax"}}
38
+
39
+ = field_set_tag "Stock Control" do
40
+ .splitContainer
41
+ %dl.half
42
+ %dt= f.label :weight
43
+ %dd= f.text_field :weight, :class => 'text'
44
+
45
+ %dl.half
46
+ %dt= f.label :stock_control
47
+ %dd.checkbox
48
+ = f.check_box :stock_control
49
+ = f.label :stock_control, "Enable stock control for this product?"
50
+
51
+ = field_set_tag "Website Properties" do
52
+ .splitContainer
53
+ %dl.half
54
+ %dt= f.label :active, "On sale?"
55
+ %dd.checkbox
56
+ = f.check_box :active
57
+ = f.label :active, "If checked, this product will be displayed within the public store"
58
+ %dl.half
59
+
60
+ %p.submit
61
+ - unless @variant.new_record?
62
+ %span.right= link_to "Delete", product_variant_path(@product, @variant), :class => 'button purple', :method => :delete, :data => {:confirm => "Are you sure you wish to remove this variant?"}
63
+ = f.submit "Save Variant", :class => 'button green'
64
+ = link_to "Cancel", :products, :class => 'button'
@@ -0,0 +1,33 @@
1
+ - @page_title = "Variants - #{@product.name}"
2
+
3
+ = content_for :header do
4
+ %p.buttons
5
+ = link_to "Edit product", [:edit, @product], :class => 'button'
6
+ = link_to "New variant", [:new, @product, :variant], :class => 'button green'
7
+
8
+ %h2.products Variants of #{@product.name}
9
+
10
+ .table
11
+ %table.data
12
+ %thead
13
+ %tr
14
+ %th{:width => '20%'} SKU
15
+ %th{:width => '50%'} Name
16
+ %th{:width => '15%'} Price
17
+ %th{:width => '15%'} Stock
18
+ %tbody
19
+ - if @variants.empty?
20
+ %tr.empty
21
+ %td{:colspan => 4} No products to display.
22
+ - else
23
+ - for variant in @variants
24
+ %tr
25
+ %td= variant.sku
26
+ %td= link_to variant.name, edit_product_variant_path(@product, variant)
27
+ %td= number_to_currency variant.price
28
+ %td
29
+ - if variant.stock_control?
30
+ %span.float-right= link_to "Edit", stock_level_adjustments_path(:item_type => variant.class, :item_id => variant.id), :class => 'edit', :rel => 'dialog', :data => {:dialog_width => 700, :dialog_behavior => 'stockLevelAdjustments'}
31
+ = boolean_tag(variant.in_stock?, nil, :true_text => variant.stock, :false_text => 'No stock')
32
+ - else
33
+ &#8734;
data/config/routes.rb CHANGED
@@ -3,7 +3,7 @@ Shoppe::Engine.routes.draw do
3
3
  get 'attachment/:id/:filename.:extension' => 'attachments#show'
4
4
  resources :product_categories
5
5
  resources :products do
6
- match :stock_levels, :on => :member, :via => [:get, :post]
6
+ resources :variants
7
7
  end
8
8
  resources :orders do
9
9
  post :search, :on => :collection
@@ -12,6 +12,7 @@ Shoppe::Engine.routes.draw do
12
12
  post :ship, :on => :member
13
13
  post :pay, :on => :member
14
14
  end
15
+ resources :stock_level_adjustments, :only => [:index, :create]
15
16
  resources :delivery_services do
16
17
  resources :delivery_service_prices
17
18
  end
@@ -1,6 +1,20 @@
1
- # !! Remember to restart your server after making changes to this file.
1
+ # Shoppe Configuration File
2
+ # !! Be sure to restart your server after making any changes to this file.
2
3
 
3
- store_name: Shoppe
4
+ # The name of your Shoppe store.
5
+ store_name: Ye Old Widget Shoppe
6
+
7
+ # The e-mail address used to send all ourbound messages through Shoppe.
4
8
  email_address: sales@example.com
9
+
10
+ # The currency unit which should be shown before all currency values
11
+ # within the Shoppe interface.
5
12
  currency_unit: '&pound;'
13
+
14
+ # The name of "tax" which you would like displayed within the Shoppe
15
+ # interface.
6
16
  tax_name: VAT
17
+
18
+ # If enabled, Shoppe will behave in demo mode. This removes the requirement
19
+ # to login to the Shoppe interface and disabled editting of users.
20
+ demo_mode: false
@@ -0,0 +1,6 @@
1
+ class RefactorOrderItemsToAllowAnyProduct < ActiveRecord::Migration
2
+ def change
3
+ rename_column :shoppe_order_items, :product_id, :ordered_item_id
4
+ add_column :shoppe_order_items, :ordered_item_type, :string, :after => :ordered_item_id
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ class RenameProductTitleToName < ActiveRecord::Migration
2
+ def change
3
+ rename_column :shoppe_products, :title, :name
4
+ end
5
+ end
@@ -0,0 +1,6 @@
1
+ class StockLevelAdjustmentsShouldBePolymorphic < ActiveRecord::Migration
2
+ def change
3
+ rename_column :shoppe_stock_level_adjustments, :product_id, :item_id
4
+ add_column :shoppe_stock_level_adjustments, :item_type, :string, :after => :item_id
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ class AddParentIdToProducts < ActiveRecord::Migration
2
+ def change
3
+ add_column :shoppe_products, :parent_id, :integer, :after => :id
4
+ end
5
+ end
@@ -0,0 +1,9 @@
1
+ class CostPriceShouldBeDefaultToZero < ActiveRecord::Migration
2
+ def up
3
+ change_column_default :shoppe_products, :cost_price, 0.0
4
+ end
5
+
6
+ def down
7
+ change_column_default :shoppe_products, :cost_price, nil
8
+ end
9
+ end
data/db/seeds.rb CHANGED
@@ -46,7 +46,7 @@ end
46
46
 
47
47
  lorem = 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'
48
48
 
49
- pro = cat1.products.create!(:title => 'Yealink T20P', :sku => 'YL-SIP-T20P', :description => lorem, :short_description => 'If cheap & cheerful is what you’re after, the Yealink T20P is what you’re looking for.', :weight => 1.119, :price => 54.99, :cost_price => 44.99, :tax_rate => tax_rate, :featured => true)
49
+ pro = cat1.products.create!(:name => 'Yealink T20P', :sku => 'YL-SIP-T20P', :description => lorem, :short_description => 'If cheap & cheerful is what you’re after, the Yealink T20P is what you’re looking for.', :weight => 1.119, :price => 54.99, :cost_price => 44.99, :tax_rate => tax_rate, :featured => true)
50
50
  pro.default_image_file = get_file('t20p.jpg')
51
51
  pro.save!
52
52
  pro.stock_level_adjustments.create(:description => 'Initial Stock', :adjustment => 17)
@@ -57,7 +57,7 @@ pro.product_attributes.create!(:key => 'Lines', :value => '3', :position => 1)
57
57
  pro.product_attributes.create!(:key => 'Colour Screen?', :value => 'No', :position => 1)
58
58
  pro.product_attributes.create!(:key => 'Power over ethernet?', :value => 'Yes', :position => 1)
59
59
 
60
- pro = cat1.products.create!(:title => 'Yealink T22P', :sku => 'YL-SIP-T22P', :description => lorem, :short_description => lorem, :weight => 1.419, :price => 64.99, :cost_price => 56.99, :tax_rate => tax_rate)
60
+ pro = cat1.products.create!(:name => 'Yealink T22P', :sku => 'YL-SIP-T22P', :description => lorem, :short_description => lorem, :weight => 1.419, :price => 64.99, :cost_price => 56.99, :tax_rate => tax_rate)
61
61
  pro.default_image_file = get_file('t22p.jpg')
62
62
  pro.save!
63
63
  pro.stock_level_adjustments.create(:description => 'Initial Stock', :adjustment => 200)
@@ -69,7 +69,7 @@ pro.product_attributes.create!(:key => 'Colour Screen?', :value => 'No', :positi
69
69
  pro.product_attributes.create!(:key => 'Power over ethernet?', :value => 'Yes', :position => 1)
70
70
 
71
71
 
72
- pro = cat1.products.create!(:title => 'Yealink T26P', :sku => 'YL-SIP-T26P', :description => lorem, :short_description => lorem, :weight => 2.23, :price => 88.99, :cost_price => 78.99, :tax_rate => tax_rate)
72
+ pro = cat1.products.create!(:name => 'Yealink T26P', :sku => 'YL-SIP-T26P', :description => lorem, :short_description => lorem, :weight => 2.23, :price => 88.99, :cost_price => 78.99, :tax_rate => tax_rate)
73
73
  pro.default_image_file = get_file('t26p.jpg')
74
74
  pro.save!
75
75
  pro.stock_level_adjustments.create(:description => 'Initial Stock', :adjustment => 100)
@@ -80,7 +80,7 @@ pro.product_attributes.create!(:key => 'Lines', :value => '6', :position => 1)
80
80
  pro.product_attributes.create!(:key => 'Colour Screen?', :value => 'No', :position => 1)
81
81
  pro.product_attributes.create!(:key => 'Power over ethernet?', :value => 'Yes', :position => 1)
82
82
 
83
- pro = cat1.products.create!(:title => 'Yealink T46GN', :sku => 'YL-SIP-T46GN', :description => lorem, :short_description => 'Colourful, sharp, fast & down right sexy. The Yealink T46P will make your scream!', :weight => 2.23, :price => 149.99, :cost_price => 139.99, :tax_rate => tax_rate, :featured => true)
83
+ pro = cat1.products.create!(:name => 'Yealink T46GN', :sku => 'YL-SIP-T46GN', :description => lorem, :short_description => 'Colourful, sharp, fast & down right sexy. The Yealink T46P will make your scream!', :weight => 2.23, :price => 149.99, :cost_price => 139.99, :tax_rate => tax_rate, :featured => true)
84
84
  pro.default_image_file = get_file('t46gn.jpg')
85
85
  pro.save!
86
86
  pro.stock_level_adjustments.create(:description => 'Initial Stock', :adjustment => 10)
@@ -91,10 +91,9 @@ pro.product_attributes.create!(:key => 'Lines', :value => '4', :position => 1)
91
91
  pro.product_attributes.create!(:key => 'Colour Screen?', :value => 'Yes', :position => 1)
92
92
  pro.product_attributes.create!(:key => 'Power over ethernet?', :value => 'Yes', :position => 1)
93
93
 
94
- pro = cat1.products.create!(:title => 'Snom 870 (Grey)', :sku => 'SM-870-GREY', :description => lorem, :short_description => 'The perfect & beautiful VoIP phone for the discerning professional desk.', :weight => 2.4, :price => 235.00, :cost_price => 225.00, :tax_rate => tax_rate)
94
+ pro = cat1.products.create!(:name => 'Snom 870', :sku => 'SM-870', :description => lorem, :short_description => 'The perfect & beautiful VoIP phone for the discerning professional desk.', :featured => true)
95
95
  pro.default_image_file = get_file('snom-870-grey.jpg')
96
96
  pro.save!
97
- pro.stock_level_adjustments.create(:description => 'Initial Stock', :adjustment => 4)
98
97
  pro.product_attributes.create!(:key => 'Manufacturer', :value => 'Snom', :position => 1)
99
98
  pro.product_attributes.create!(:key => 'Model', :value => '870', :position => 1)
100
99
  pro.product_attributes.create!(:key => 'Colour', :value => 'Grey', :position => 1)
@@ -102,38 +101,39 @@ pro.product_attributes.create!(:key => 'Lines', :value => '10', :position => 1)
102
101
  pro.product_attributes.create!(:key => 'Colour Screen?', :value => 'Yes', :position => 1)
103
102
  pro.product_attributes.create!(:key => 'Power over ethernet?', :value => 'Yes', :position => 1)
104
103
 
105
- pro = cat1.products.create!(:title => 'Snom 870 (Black)', :sku => 'SM-870-BLK', :description => lorem, :short_description => 'The perfect & beautiful VoIP phone for the discerning professional desk.', :weight => 2.4, :price => 235.00, :cost_price => 225.00, :tax_rate => tax_rate, :featured => true)
106
- pro.default_image_file = get_file('snom-870-blk.jpg')
107
- pro.save!
108
- pro.stock_level_adjustments.create(:description => 'Initial Stock', :adjustment => 4)
109
- pro.product_attributes.create!(:key => 'Manufacturer', :value => 'Snom', :position => 1)
110
- pro.product_attributes.create!(:key => 'Model', :value => '870', :position => 1)
111
- pro.product_attributes.create!(:key => 'Colour', :value => 'Black', :position => 1)
112
- pro.product_attributes.create!(:key => 'Lines', :value => '10', :position => 1)
113
- pro.product_attributes.create!(:key => 'Colour Screen?', :value => 'Yes', :position => 1)
114
- pro.product_attributes.create!(:key => 'Power over ethernet?', :value => 'Yes', :position => 1)
104
+ v1 = pro.variants.create(:name => "White/Grey", :sku => "SM-870-GREY", :price => 230.00, :cost_price => 220, :tax_rate => tax_rate, :weight => 1.35)
105
+ v1.default_image_file = get_file('snom-870-grey.jpg')
106
+ v1.save!
107
+ v1.stock_level_adjustments.create(:description => 'Initial Stock', :adjustment => 4)
108
+
109
+
110
+ v2 = pro.variants.create(:name => "Black", :sku => "SM-870-BLK", :price => 230.00, :cost_price => 220, :tax_rate => tax_rate, :weight => 1.35)
111
+ v2.default_image_file = get_file('snom-870-blk.jpg')
112
+ v2.save!
113
+ v2.stock_level_adjustments.create(:description => 'Initial Stock', :adjustment => 2)
114
+
115
115
 
116
- pro = cat2.products.create!(:title => 'Yealink Mono Headset', :sku => 'YL-YHS32', :description => lorem, :short_description => 'If you\'re often on the phone, this headset will make your life 100x easier. Guaranteed*.', :weight => 0.890, :price => 34.99, :cost_price => 24.99, :tax_rate => tax_rate, :featured => true)
116
+ pro = cat2.products.create!(:name => 'Yealink Mono Headset', :sku => 'YL-YHS32', :description => lorem, :short_description => 'If you\'re often on the phone, this headset will make your life 100x easier. Guaranteed*.', :weight => 0.890, :price => 34.99, :cost_price => 24.99, :tax_rate => tax_rate, :featured => true)
117
117
  pro.default_image_file = get_file('yhs32.jpg')
118
118
  pro.save!
119
119
  pro.product_attributes.create!(:key => 'Manufacturer', :value => 'Yealink', :position => 1)
120
120
  pro.product_attributes.create!(:key => 'Model', :value => 'YHS32', :position => 1)
121
121
 
122
- pro = cat2.products.create!(:title => 'Snom Wired Headset (MM2)', :sku => 'SM-MM2', :description => lorem, :short_description => lorem, :weight => 0.780, :price => 38.00, :cost_price => 30, :tax_rate => tax_rate)
122
+ pro = cat2.products.create!(:name => 'Snom Wired Headset (MM2)', :sku => 'SM-MM2', :description => lorem, :short_description => lorem, :weight => 0.780, :price => 38.00, :cost_price => 30, :tax_rate => tax_rate)
123
123
  pro.default_image_file = get_file('snom-mm2.jpg')
124
124
  pro.save!
125
125
  pro.stock_level_adjustments.create(:description => 'Initial Stock', :adjustment => 7)
126
126
  pro.product_attributes.create!(:key => 'Manufacturer', :value => 'Snom', :position => 1)
127
127
  pro.product_attributes.create!(:key => 'Model', :value => 'MM2', :position => 1)
128
128
 
129
- pro = cat2.products.create!(:title => 'Snom Wired Headset (MM3)', :sku => 'SM-MM3', :description => lorem, :short_description => lorem, :weight => 0.780, :price => 38.00, :cost_price => 30, :tax_rate => tax_rate)
129
+ pro = cat2.products.create!(:name => 'Snom Wired Headset (MM3)', :sku => 'SM-MM3', :description => lorem, :short_description => lorem, :weight => 0.780, :price => 38.00, :cost_price => 30, :tax_rate => tax_rate)
130
130
  pro.default_image_file = get_file('snom-mm2.jpg')
131
131
  pro.save!
132
132
  pro.stock_level_adjustments.create(:description => 'Initial Stock', :adjustment => 5)
133
133
  pro.product_attributes.create!(:key => 'Manufacturer', :value => 'Snom', :position => 1)
134
134
  pro.product_attributes.create!(:key => 'Model', :value => 'MM3', :position => 1)
135
135
 
136
- pro = cat1.products.create!(:title => 'Yealink W52P', :sku => 'TL-SIP-W52P', :description => lorem, :short_description => 'Wireless SIP phones are hard to come by but this beauty from Yealink is fab.', :weight => 1.280, :price => 99.99, :cost_price => 89.99, :tax_rate => tax_rate, :featured => true)
136
+ pro = cat1.products.create!(:name => 'Yealink W52P', :sku => 'TL-SIP-W52P', :description => lorem, :short_description => 'Wireless SIP phones are hard to come by but this beauty from Yealink is fab.', :weight => 1.280, :price => 99.99, :cost_price => 89.99, :tax_rate => tax_rate, :featured => true)
137
137
  pro.default_image_file = get_file('w52p.jpg')
138
138
  pro.save!
139
139
  pro.stock_level_adjustments.create(:description => 'Initial Stock', :adjustment => 10)
data/lib/shoppe.rb CHANGED
@@ -3,9 +3,11 @@ require 'bcrypt'
3
3
  require 'dynamic_form'
4
4
  require 'kaminari'
5
5
  require 'ransack'
6
+
6
7
  require 'nifty/utils'
7
8
  require 'nifty/key_value_store'
8
9
  require 'nifty/attachments'
10
+ require 'nifty/dialog'
9
11
 
10
12
  module Shoppe
11
13
 
@@ -7,7 +7,7 @@ module Shoppe
7
7
  end
8
8
 
9
9
  def available_stock
10
- @options[:product].stock
10
+ @options[:ordered_item].stock
11
11
  end
12
12
 
13
13
  def requested_stock
@@ -0,0 +1,11 @@
1
+ module Shoppe
2
+ module Errors
3
+ class UnorderableItem < Error
4
+
5
+ def initialize(options)
6
+ @options = options
7
+ end
8
+
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,39 @@
1
+ module Shoppe
2
+ # All items which can be ordered should include this module and ensure that all methods
3
+ # have been overridden. It's a lazy-mans protocol.
4
+ module OrderableItem
5
+
6
+ # stock_level_adjustments must be an association
7
+
8
+ def full_name
9
+ end
10
+
11
+ def orderable?
12
+ end
13
+
14
+ def sku
15
+ end
16
+
17
+ def price
18
+ end
19
+
20
+ def cost_price
21
+ end
22
+
23
+ def tax_rate
24
+ end
25
+
26
+ def stock_control?
27
+ end
28
+
29
+ def in_stock?
30
+ end
31
+
32
+ def stock
33
+ end
34
+
35
+ def weight
36
+ end
37
+
38
+ end
39
+ end
@@ -1,3 +1,3 @@
1
1
  module Shoppe
2
- VERSION = "0.0.14"
2
+ VERSION = "0.0.15"
3
3
  end
@@ -11,7 +11,7 @@
11
11
  #
12
12
  # It's strongly recommended that you check this file into your version control system.
13
13
 
14
- ActiveRecord::Schema.define(version: 20131021135208) do
14
+ ActiveRecord::Schema.define(version: 20131022145653) do
15
15
 
16
16
  create_table "nifty_attachments", force: true do |t|
17
17
  t.integer "parent_id"
@@ -70,15 +70,16 @@ ActiveRecord::Schema.define(version: 20131021135208) do
70
70
 
71
71
  create_table "shoppe_order_items", force: true do |t|
72
72
  t.integer "order_id"
73
- t.integer "product_id"
74
- t.integer "quantity", default: 1
75
- t.decimal "unit_price", precision: 8, scale: 2
76
- t.decimal "tax_amount", precision: 8, scale: 2
77
- t.decimal "tax_rate", precision: 8, scale: 2
78
- t.decimal "weight", precision: 8, scale: 3, default: 0.0
73
+ t.integer "ordered_item_id"
74
+ t.integer "quantity", default: 1
75
+ t.decimal "unit_price", precision: 8, scale: 2
76
+ t.decimal "tax_amount", precision: 8, scale: 2
77
+ t.decimal "tax_rate", precision: 8, scale: 2
78
+ t.decimal "weight", precision: 8, scale: 3, default: 0.0
79
79
  t.datetime "created_at"
80
80
  t.datetime "updated_at"
81
- t.decimal "unit_cost_price", precision: 8, scale: 2
81
+ t.decimal "unit_cost_price", precision: 8, scale: 2
82
+ t.string "ordered_item_type"
82
83
  end
83
84
 
84
85
  create_table "shoppe_orders", force: true do |t|
@@ -137,8 +138,9 @@ ActiveRecord::Schema.define(version: 20131021135208) do
137
138
  end
138
139
 
139
140
  create_table "shoppe_products", force: true do |t|
141
+ t.integer "parent_id"
140
142
  t.integer "product_category_id"
141
- t.string "title"
143
+ t.string "name"
142
144
  t.string "sku"
143
145
  t.string "permalink"
144
146
  t.text "description"
@@ -151,18 +153,19 @@ ActiveRecord::Schema.define(version: 20131021135208) do
151
153
  t.datetime "updated_at"
152
154
  t.boolean "featured", default: false
153
155
  t.text "in_the_box"
154
- t.decimal "cost_price", precision: 8, scale: 2
156
+ t.decimal "cost_price", precision: 8, scale: 2, default: 0.0
155
157
  t.boolean "stock_control", default: true
156
158
  end
157
159
 
158
160
  create_table "shoppe_stock_level_adjustments", force: true do |t|
159
- t.integer "product_id"
161
+ t.integer "item_id"
160
162
  t.string "description"
161
163
  t.integer "adjustment", default: 0
162
164
  t.string "parent_type"
163
165
  t.integer "parent_id"
164
166
  t.datetime "created_at"
165
167
  t.datetime "updated_at"
168
+ t.string "item_type"
166
169
  end
167
170
 
168
171
  create_table "shoppe_tax_rates", force: true do |t|