shoppe 0.0.14 → 0.0.15
Sign up to get free protection for your applications and to get access to all the features.
- data/app/assets/javascripts/shoppe/application.coffee +57 -1
- data/app/assets/javascripts/shoppe/mousetrap.js +9 -0
- data/app/assets/stylesheets/shoppe/application.scss +70 -59
- data/app/assets/stylesheets/shoppe/dialog.scss +10 -0
- data/app/assets/stylesheets/shoppe/sub.scss +15 -0
- data/app/controllers/shoppe/application_controller.rb +13 -1
- data/app/controllers/shoppe/attachments_controller.rb +10 -8
- data/app/controllers/shoppe/dashboard_controller.rb +6 -4
- data/app/controllers/shoppe/delivery_service_prices_controller.rb +33 -31
- data/app/controllers/shoppe/delivery_services_controller.rb +34 -32
- data/app/controllers/shoppe/orders_controller.rb +40 -38
- data/app/controllers/shoppe/product_categories_controller.rb +34 -32
- data/app/controllers/shoppe/products_controller.rb +32 -44
- data/app/controllers/shoppe/sessions_controller.rb +24 -22
- data/app/controllers/shoppe/stock_level_adjustments_controller.rb +40 -0
- data/app/controllers/shoppe/tax_rates_controller.rb +35 -33
- data/app/controllers/shoppe/users_controller.rb +40 -33
- data/app/controllers/shoppe/variants_controller.rb +50 -0
- data/app/helpers/shoppe/shoppe_helper.rb +2 -2
- data/app/mailers/shoppe/order_mailer.rb +20 -18
- data/app/models/shoppe/country.rb +1 -1
- data/app/models/shoppe/delivery_service.rb +17 -15
- data/app/models/shoppe/delivery_service_price.rb +18 -16
- data/app/models/shoppe/order.rb +293 -290
- data/app/models/shoppe/order_item.rb +115 -113
- data/app/models/shoppe/product.rb +76 -54
- data/app/models/shoppe/product/product_attributes.rb +12 -10
- data/app/models/shoppe/product/variants.rb +26 -0
- data/app/models/shoppe/product_attribute.rb +40 -38
- data/app/models/shoppe/product_category.rb +16 -14
- data/app/models/shoppe/stock_level_adjustment.rb +1 -2
- data/app/models/shoppe/tax_rate.rb +2 -2
- data/app/models/shoppe/user.rb +34 -32
- data/app/views/shoppe/orders/index.html.haml +3 -4
- data/app/views/shoppe/orders/show.html.haml +5 -5
- data/app/views/shoppe/products/_form.html.haml +28 -27
- data/app/views/shoppe/products/_table.html.haml +42 -0
- data/app/views/shoppe/products/edit.html.haml +2 -1
- data/app/views/shoppe/products/index.html.haml +1 -24
- data/app/views/shoppe/shared/error.html.haml +4 -0
- data/app/views/shoppe/{products/stock_levels.html.haml → stock_level_adjustments/index.html.haml} +12 -6
- data/app/views/shoppe/variants/form.html.haml +64 -0
- data/app/views/shoppe/variants/index.html.haml +33 -0
- data/config/routes.rb +2 -1
- data/config/shoppe.example.yml +16 -2
- data/db/migrate/20131022090919_refactor_order_items_to_allow_any_product.rb +6 -0
- data/db/migrate/20131022092904_rename_product_title_to_name.rb +5 -0
- data/db/migrate/20131022093538_stock_level_adjustments_should_be_polymorphic.rb +6 -0
- data/db/migrate/20131022135331_add_parent_id_to_products.rb +5 -0
- data/db/migrate/20131022145653_cost_price_should_be_default_to_zero.rb +9 -0
- data/db/seeds.rb +20 -20
- data/lib/shoppe.rb +2 -0
- data/lib/shoppe/errors/not_enough_stock.rb +1 -1
- data/lib/shoppe/errors/unorderable_item.rb +11 -0
- data/lib/shoppe/orderable_item.rb +39 -0
- data/lib/shoppe/version.rb +1 -1
- data/test/dummy/db/schema.rb +14 -11
- data/test/dummy/log/development.log +75 -0
- metadata +37 -5
@@ -1,41 +1,43 @@
|
|
1
|
-
|
1
|
+
module Shoppe
|
2
|
+
class OrdersController < Shoppe::ApplicationController
|
3
|
+
|
4
|
+
before_filter { @active_nav = :orders }
|
5
|
+
before_filter { params[:id] && @order = Shoppe::Order.find(params[:id])}
|
6
|
+
|
7
|
+
def index
|
8
|
+
@query = Shoppe::Order.ordered.received.includes(:order_items => :ordered_item).page(params[:page]).search(params[:q])
|
9
|
+
@orders = @query.result
|
10
|
+
end
|
11
|
+
|
12
|
+
def update
|
13
|
+
@order.update_attributes!(params[:order].permit(:notes))
|
14
|
+
redirect_to @order, :notice => "Order has been saved successfully"
|
15
|
+
end
|
16
|
+
|
17
|
+
def search
|
18
|
+
index
|
19
|
+
render :action => "index"
|
20
|
+
end
|
21
|
+
|
22
|
+
def accept
|
23
|
+
@order.accept!(current_user)
|
24
|
+
redirect_to @order, :notice => "Order has been accepted successfully"
|
25
|
+
end
|
26
|
+
|
27
|
+
def reject
|
28
|
+
@order.reject!(current_user)
|
29
|
+
redirect_to @order, :notice => "Order has been rejected successfully"
|
30
|
+
end
|
31
|
+
|
32
|
+
def ship
|
33
|
+
@order.ship!(current_user, params[:consignment_number])
|
34
|
+
redirect_to @order, :notice => "Order has been shipped successfully"
|
35
|
+
end
|
36
|
+
|
37
|
+
def pay
|
38
|
+
@order.pay!(params[:payment_reference], params[:payment_method].blank? ? 'Unknown' : params[:payment_method])
|
39
|
+
redirect_to @order, :notice => "Order has been marked as paid successfully"
|
40
|
+
end
|
2
41
|
|
3
|
-
before_filter { @active_nav = :orders }
|
4
|
-
before_filter { params[:id] && @order = Shoppe::Order.find(params[:id])}
|
5
|
-
|
6
|
-
def index
|
7
|
-
@query = Shoppe::Order.ordered.received.includes(:order_items => :product).page(params[:page]).search(params[:q])
|
8
|
-
@orders = @query.result
|
9
|
-
end
|
10
|
-
|
11
|
-
def update
|
12
|
-
@order.update_attributes!(params[:order].permit(:notes))
|
13
|
-
redirect_to @order, :notice => "Order has been saved successfully"
|
14
|
-
end
|
15
|
-
|
16
|
-
def search
|
17
|
-
index
|
18
|
-
render :action => "index"
|
19
|
-
end
|
20
|
-
|
21
|
-
def accept
|
22
|
-
@order.accept!(current_user)
|
23
|
-
redirect_to @order, :notice => "Order has been accepted successfully"
|
24
42
|
end
|
25
|
-
|
26
|
-
def reject
|
27
|
-
@order.reject!(current_user)
|
28
|
-
redirect_to @order, :notice => "Order has been rejected successfully"
|
29
|
-
end
|
30
|
-
|
31
|
-
def ship
|
32
|
-
@order.ship!(current_user, params[:consignment_number])
|
33
|
-
redirect_to @order, :notice => "Order has been shipped successfully"
|
34
|
-
end
|
35
|
-
|
36
|
-
def pay
|
37
|
-
@order.pay!(params[:payment_reference], params[:payment_method].blank? ? 'Unknown' : params[:payment_method])
|
38
|
-
redirect_to @order, :notice => "Order has been marked as paid successfully"
|
39
|
-
end
|
40
|
-
|
41
43
|
end
|
@@ -1,45 +1,47 @@
|
|
1
|
-
|
1
|
+
module Shoppe
|
2
|
+
class ProductCategoriesController < Shoppe::ApplicationController
|
2
3
|
|
3
|
-
|
4
|
-
|
4
|
+
before_filter { @active_nav = :product_categories }
|
5
|
+
before_filter { params[:id] && @product_category = Shoppe::ProductCategory.find(params[:id]) }
|
5
6
|
|
6
|
-
|
7
|
-
|
8
|
-
|
7
|
+
def index
|
8
|
+
@product_categories = Shoppe::ProductCategory.ordered.all
|
9
|
+
end
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
11
|
+
def new
|
12
|
+
@product_category = Shoppe::ProductCategory.new
|
13
|
+
end
|
13
14
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
15
|
+
def create
|
16
|
+
@product_category = Shoppe::ProductCategory.new(safe_params)
|
17
|
+
if @product_category.save
|
18
|
+
redirect_to :product_categories, :flash => {:notice => "Category has been created successfully"}
|
19
|
+
else
|
20
|
+
render :action => "new"
|
21
|
+
end
|
20
22
|
end
|
21
|
-
end
|
22
23
|
|
23
|
-
|
24
|
-
|
24
|
+
def edit
|
25
|
+
end
|
25
26
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
27
|
+
def update
|
28
|
+
if @product_category.update(safe_params)
|
29
|
+
redirect_to [:edit, @product_category], :flash => {:notice => "Category has been updated successfully"}
|
30
|
+
else
|
31
|
+
render :action => "edit"
|
32
|
+
end
|
31
33
|
end
|
32
|
-
end
|
33
34
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
35
|
+
def destroy
|
36
|
+
@product_category.destroy
|
37
|
+
redirect_to :product_categories, :flash => {:notice => "Category has been removed successfully"}
|
38
|
+
end
|
38
39
|
|
39
|
-
|
40
|
+
private
|
40
41
|
|
41
|
-
|
42
|
-
|
43
|
-
|
42
|
+
def safe_params
|
43
|
+
params[:product_category].permit(:name, :permalink, :description, :image_file)
|
44
|
+
end
|
44
45
|
|
46
|
+
end
|
45
47
|
end
|
@@ -1,59 +1,47 @@
|
|
1
|
-
|
1
|
+
module Shoppe
|
2
|
+
class ProductsController < Shoppe::ApplicationController
|
2
3
|
|
3
|
-
|
4
|
-
|
4
|
+
before_filter { @active_nav = :products }
|
5
|
+
before_filter { params[:id] && @product = Shoppe::Product.root.find(params[:id]) }
|
5
6
|
|
6
|
-
|
7
|
-
|
8
|
-
end
|
9
|
-
|
10
|
-
def new
|
11
|
-
@product = Shoppe::Product.new
|
12
|
-
end
|
13
|
-
|
14
|
-
def create
|
15
|
-
@product = Shoppe::Product.new(safe_params)
|
16
|
-
if @product.save
|
17
|
-
redirect_to :products, :flash => {:notice => "Product has been created successfully"}
|
18
|
-
else
|
19
|
-
render :action => "new"
|
7
|
+
def index
|
8
|
+
@products = Shoppe::Product.root.includes(:stock_level_adjustments, :default_image, :product_category, :variants).order(:name).group_by(&:product_category).sort_by { |cat,pro| cat.name }
|
20
9
|
end
|
21
|
-
end
|
22
10
|
|
23
|
-
|
24
|
-
|
11
|
+
def new
|
12
|
+
@product = Shoppe::Product.new
|
13
|
+
end
|
25
14
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
15
|
+
def create
|
16
|
+
@product = Shoppe::Product.new(safe_params)
|
17
|
+
if @product.save
|
18
|
+
redirect_to :products, :flash => {:notice => "Product has been created successfully"}
|
19
|
+
else
|
20
|
+
render :action => "new"
|
21
|
+
end
|
31
22
|
end
|
32
|
-
end
|
33
23
|
|
34
|
-
|
35
|
-
|
36
|
-
redirect_to :products, :flash => {:notice => "Product has been removed successfully"}
|
37
|
-
end
|
24
|
+
def edit
|
25
|
+
end
|
38
26
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
@new_sla = @product.stock_level_adjustments.build(params[:stock_level_adjustment].permit(:description, :adjustment))
|
43
|
-
if @new_sla.save
|
44
|
-
redirect_to [:stock_levels, @product], :notice => "Stock level adjustment has been recorded"
|
27
|
+
def update
|
28
|
+
if @product.update(safe_params)
|
29
|
+
redirect_to [:edit, @product], :flash => {:notice => "Product has been updated successfully"}
|
45
30
|
else
|
46
|
-
|
31
|
+
render :action => "edit"
|
47
32
|
end
|
48
|
-
else
|
49
|
-
@new_sla = @product.stock_level_adjustments.build
|
50
33
|
end
|
51
|
-
end
|
52
34
|
|
53
|
-
|
35
|
+
def destroy
|
36
|
+
@product.destroy
|
37
|
+
redirect_to :products, :flash => {:notice => "Product has been removed successfully"}
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
54
41
|
|
55
|
-
|
56
|
-
|
57
|
-
|
42
|
+
def safe_params
|
43
|
+
params[:product].permit(:product_category_id, :name, :sku, :permalink, :description, :short_description, :weight, :price, :cost_price, :tax_rate_id, :stock_control, :default_image_file, :data_sheet_file, :active, :featured, :in_the_box, :product_attributes_array => [:key, :value, :searchable, :public])
|
44
|
+
end
|
58
45
|
|
46
|
+
end
|
59
47
|
end
|
@@ -1,30 +1,32 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
module Shoppe
|
2
|
+
class SessionsController < Shoppe::ApplicationController
|
3
|
+
layout 'shoppe/sub'
|
4
|
+
skip_before_filter :login_required, :only => [:new, :create, :reset]
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
6
|
+
def create
|
7
|
+
if user = Shoppe::User.authenticate(params[:email_address], params[:password])
|
8
|
+
session[:shoppe_user_id] = user.id
|
9
|
+
redirect_to :orders
|
10
|
+
else
|
11
|
+
flash.now[:alert] = "The email address and/or password you have entered is invalid. Please check and try again."
|
12
|
+
render :action => "new"
|
13
|
+
end
|
12
14
|
end
|
13
|
-
end
|
14
15
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
def destroy
|
17
|
+
session[:shoppe_user_id] = nil
|
18
|
+
redirect_to :login
|
19
|
+
end
|
19
20
|
|
20
|
-
|
21
|
+
def reset
|
21
22
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
23
|
+
if request.post?
|
24
|
+
if user = Shoppe::User.find_by_email_address(params[:email_address])
|
25
|
+
user.reset_password!
|
26
|
+
redirect_to login_path(:email_address => params[:email_address]), :notice => "An e-mail has been sent to #{user.email_address} with a new password"
|
27
|
+
else
|
28
|
+
flash.now[:alert] = "No user was found matching the e-mail address"
|
29
|
+
end
|
28
30
|
end
|
29
31
|
end
|
30
32
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Shoppe
|
2
|
+
class StockLevelAdjustmentsController < ApplicationController
|
3
|
+
|
4
|
+
SUITABLE_OBJECTS = ['Shoppe::Product']
|
5
|
+
before_filter do
|
6
|
+
raise Shoppe::Error, "Invalid item_type (must be one of #{SUITABLE_OBJECTS.to_sentence})" unless SUITABLE_OBJECTS.include?(params[:item_type])
|
7
|
+
@item = params[:item_type].constantize.find(params[:item_id].to_i)
|
8
|
+
end
|
9
|
+
before_filter { params[:id] && @sla = @item.stock_level_adjustments.find(params[:id].to_i) }
|
10
|
+
|
11
|
+
def index
|
12
|
+
@stock_level_adjustments = @item.stock_level_adjustments.ordered.page(params[:page]).per(10)
|
13
|
+
@new_sla = @item.stock_level_adjustments.build if @new_sla.nil?
|
14
|
+
if request.xhr?
|
15
|
+
render :action => 'index', :layout => false
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def create
|
20
|
+
@new_sla = @item.stock_level_adjustments.build(params[:stock_level_adjustment].permit(:description, :adjustment))
|
21
|
+
if @new_sla.save
|
22
|
+
if request.xhr?
|
23
|
+
@new_sla = @item.stock_level_adjustments.build
|
24
|
+
index
|
25
|
+
else
|
26
|
+
redirect_to stock_level_adjustments_path(:item_id => params[:item_id], :item_type => params[:item_type]), :notice => "Adjustment has been added successfully"
|
27
|
+
end
|
28
|
+
else
|
29
|
+
if request.xhr?
|
30
|
+
render :text => @new_sla.errors.full_messages.to_sentence, :status => 422
|
31
|
+
else
|
32
|
+
index
|
33
|
+
flash.now[:alert] = @new_sla.errors.full_messages.to_sentence
|
34
|
+
render :action => "index"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
@@ -1,47 +1,49 @@
|
|
1
|
-
|
1
|
+
module Shoppe
|
2
|
+
class TaxRatesController < Shoppe::ApplicationController
|
2
3
|
|
3
|
-
|
4
|
-
|
4
|
+
before_filter { @active_nav = :tax_rates }
|
5
|
+
before_filter { params[:id] && @tax_rate = Shoppe::TaxRate.find(params[:id]) }
|
5
6
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
def new
|
11
|
-
@tax_rate = Shoppe::TaxRate.new
|
12
|
-
render :action => "form"
|
13
|
-
end
|
7
|
+
def index
|
8
|
+
@tax_rates = Shoppe::TaxRate.ordered.all
|
9
|
+
end
|
14
10
|
|
15
|
-
|
16
|
-
|
17
|
-
if @tax_rate.save
|
18
|
-
redirect_to :tax_rates, :flash => {:notice => "Tax rate has been created successfully"}
|
19
|
-
else
|
11
|
+
def new
|
12
|
+
@tax_rate = Shoppe::TaxRate.new
|
20
13
|
render :action => "form"
|
21
14
|
end
|
22
|
-
end
|
23
15
|
|
24
|
-
|
25
|
-
|
26
|
-
|
16
|
+
def create
|
17
|
+
@tax_rate = Shoppe::TaxRate.new(safe_params)
|
18
|
+
if @tax_rate.save
|
19
|
+
redirect_to :tax_rates, :flash => {:notice => "Tax rate has been created successfully"}
|
20
|
+
else
|
21
|
+
render :action => "form"
|
22
|
+
end
|
23
|
+
end
|
27
24
|
|
28
|
-
|
29
|
-
if @tax_rate.update(safe_params)
|
30
|
-
redirect_to [:edit, @tax_rate], :flash => {:notice => "Tax rate has been updated successfully"}
|
31
|
-
else
|
25
|
+
def edit
|
32
26
|
render :action => "form"
|
33
27
|
end
|
34
|
-
end
|
35
28
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
29
|
+
def update
|
30
|
+
if @tax_rate.update(safe_params)
|
31
|
+
redirect_to [:edit, @tax_rate], :flash => {:notice => "Tax rate has been updated successfully"}
|
32
|
+
else
|
33
|
+
render :action => "form"
|
34
|
+
end
|
35
|
+
end
|
40
36
|
|
41
|
-
|
37
|
+
def destroy
|
38
|
+
@tax_rate.destroy
|
39
|
+
redirect_to :tax_rates, :flash => {:notice => "Tax rate has been removed successfully"}
|
40
|
+
end
|
42
41
|
|
43
|
-
|
44
|
-
params[:tax_rate].permit(:name, :rate, :country_ids => [])
|
45
|
-
end
|
42
|
+
private
|
46
43
|
|
44
|
+
def safe_params
|
45
|
+
params[:tax_rate].permit(:name, :rate, :country_ids => [])
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
47
49
|
end
|
@@ -1,46 +1,53 @@
|
|
1
|
-
|
1
|
+
module Shoppe
|
2
|
+
class UsersController < Shoppe::ApplicationController
|
3
|
+
|
4
|
+
before_filter { @active_nav = :users }
|
5
|
+
before_filter { params[:id] && @user = Shoppe::User.find(params[:id]) }
|
6
|
+
if Shoppe.config[:demo_mode]
|
7
|
+
before_filter(:only => [:create, :update, :destroy]) do
|
8
|
+
raise Shoppe::Error, "You cannot make changes to user in demo mode. Sorry about that."
|
9
|
+
end
|
10
|
+
end
|
2
11
|
|
3
|
-
|
4
|
-
|
12
|
+
def index
|
13
|
+
@users = Shoppe::User.all
|
14
|
+
end
|
5
15
|
|
6
|
-
|
7
|
-
|
8
|
-
|
16
|
+
def new
|
17
|
+
@user = Shoppe::User.new
|
18
|
+
end
|
9
19
|
|
10
|
-
|
11
|
-
|
12
|
-
|
20
|
+
def create
|
21
|
+
@user = Shoppe::User.new(safe_params)
|
22
|
+
if @user.save
|
23
|
+
redirect_to :users, :flash => {:notice => "User has been created successfully"}
|
24
|
+
else
|
25
|
+
render :action => "new"
|
26
|
+
end
|
27
|
+
end
|
13
28
|
|
14
|
-
|
15
|
-
@user = Shoppe::User.new(safe_params)
|
16
|
-
if @user.save
|
17
|
-
redirect_to :users, :flash => {:notice => "User has been created successfully"}
|
18
|
-
else
|
19
|
-
render :action => "new"
|
29
|
+
def edit
|
20
30
|
end
|
21
|
-
end
|
22
31
|
|
23
|
-
|
24
|
-
|
32
|
+
def update
|
33
|
+
if @user.update(safe_params)
|
34
|
+
redirect_to [:edit, @user], :flash => {:notice => "User has been updated successfully"}
|
35
|
+
else
|
36
|
+
render :action => "edit"
|
37
|
+
end
|
38
|
+
end
|
25
39
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
render :action => "edit"
|
40
|
+
def destroy
|
41
|
+
raise Shoppe::Error, "You cannot remove yourself" if @user == current_user
|
42
|
+
@user.destroy
|
43
|
+
redirect_to :users, :flash => {:notice => "User has been removed successfully"}
|
31
44
|
end
|
32
|
-
end
|
33
45
|
|
34
|
-
|
35
|
-
raise Shoppe::Error, "You cannot remove yourself" if @user == current_user
|
36
|
-
@user.destroy
|
37
|
-
redirect_to :users, :flash => {:notice => "User has been removed successfully"}
|
38
|
-
end
|
46
|
+
private
|
39
47
|
|
40
|
-
|
48
|
+
def safe_params
|
49
|
+
params[:user].permit(:first_name, :last_name, :email_address, :password, :password_confirmation)
|
50
|
+
end
|
41
51
|
|
42
|
-
def safe_params
|
43
|
-
params[:user].permit(:first_name, :last_name, :email_address, :password, :password_confirmation)
|
44
52
|
end
|
45
|
-
|
46
53
|
end
|