shop_bunny 0.7.1 → 0.7.3
Sign up to get free protection for your applications and to get access to all the features.
- data/app/controllers/carts_controller.rb +1 -50
- data/app/models/cart.rb +1 -119
- data/config/initializers/shop_bunny.rb +0 -6
- data/config/routes.rb +2 -1
- data/lib/generators/shop_bunny/install_generator.rb +6 -1
- data/lib/generators/shop_bunny/templates/shopbunny_controller_template.rb +3 -0
- data/lib/generators/shop_bunny/templates/shopbunny_model_template.rb +3 -0
- data/lib/shop_bunny/cart_controller_module.rb +53 -0
- data/lib/shop_bunny/cart_module.rb +130 -0
- data/lib/shop_bunny.rb +2 -0
- metadata +16 -12
@@ -1,53 +1,4 @@
|
|
1
1
|
class CartsController < ApplicationController
|
2
|
-
|
3
|
-
before_filter :find_cart
|
4
|
-
before_filter :find_item, :only => [:add_item, :remove_item]
|
2
|
+
include ShopBunny::CartControllerModule
|
5
3
|
|
6
|
-
if ShopBunny.controller_enhancement
|
7
|
-
include ShopBunny.controller_enhancement
|
8
|
-
end
|
9
|
-
|
10
|
-
def show
|
11
|
-
respond_with @cart
|
12
|
-
end
|
13
|
-
|
14
|
-
def add_item
|
15
|
-
@cart.add_item(@item) if @item
|
16
|
-
respond_with @cart do |format|
|
17
|
-
format.html { redirect_to :action => :show }
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
def remove_item
|
22
|
-
@cart.remove_item(@item) if @item
|
23
|
-
respond_with @cart do |format|
|
24
|
-
format.html { redirect_to :action => :show }
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def checkout
|
29
|
-
end
|
30
|
-
|
31
|
-
def update
|
32
|
-
@cart.update_attributes(params[:cart])
|
33
|
-
respond_with @cart do |format|
|
34
|
-
format.html {
|
35
|
-
if @cart.errors.any?
|
36
|
-
render 'show'
|
37
|
-
else
|
38
|
-
# We have to redirect by hand here, because
|
39
|
-
# url_for(@cart) returns "/cart.x" when cart is a singular resource
|
40
|
-
# (see routes.rb). This is a known limitation of Rails.
|
41
|
-
# See https://rails.lighthouseapp.com/projects/8994/tickets/4168
|
42
|
-
redirect_to :action => :show
|
43
|
-
end
|
44
|
-
}
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
private
|
49
|
-
|
50
|
-
def find_item
|
51
|
-
@item = @cart.item_model.find(params[:item_id])
|
52
|
-
end
|
53
4
|
end
|
data/app/models/cart.rb
CHANGED
@@ -1,121 +1,3 @@
|
|
1
1
|
class Cart < ActiveRecord::Base
|
2
|
-
|
3
|
-
has_many :cart_items, :dependent => :destroy
|
4
|
-
has_many :coupon_uses, :dependent => :destroy
|
5
|
-
has_many :coupons, :through => :coupon_uses
|
6
|
-
accepts_nested_attributes_for :cart_items, :allow_destroy => true
|
7
|
-
before_save :update_coupons
|
8
|
-
attr_accessible :coupon_code, :cart_items_attributes
|
9
|
-
validate :coupon_code_must_be_valid
|
10
|
-
|
11
|
-
def items
|
12
|
-
self.cart_items
|
13
|
-
end
|
14
|
-
|
15
|
-
def item_count
|
16
|
-
self.cart_items.inject(0) {|sum,e| sum += e.quantity}
|
17
|
-
end
|
18
|
-
|
19
|
-
def shipping_costs
|
20
|
-
return 0 if coupons.any?(&:removes_shipping_cost)
|
21
|
-
shipping_cost_calculator.costs_for(self)
|
22
|
-
end
|
23
|
-
|
24
|
-
# Calculates the sum of all cart_items, excluding the coupons discount!
|
25
|
-
def item_sum
|
26
|
-
self.cart_items.inject(0) {|sum,e| sum += e.quantity*e.item.price}
|
27
|
-
end
|
28
|
-
|
29
|
-
# Calculates the total sum and applies the coupons discount!
|
30
|
-
def total
|
31
|
-
sum = item_sum
|
32
|
-
|
33
|
-
absolute_discount = coupons.sum(:discount_credit)
|
34
|
-
relative_discount = coupons.inject(1) {|s,coupon| s * coupon.discount_percentage }
|
35
|
-
|
36
|
-
sum -= absolute_discount
|
37
|
-
sum *= relative_discount
|
38
|
-
|
39
|
-
sum += shipping_costs
|
40
|
-
|
41
|
-
[0, sum].max
|
42
|
-
end
|
43
|
-
|
44
|
-
#increases the quantity of an article. creates a new one if it doesn't exist
|
45
|
-
def add_item(item,options = {})
|
46
|
-
options[:quantity] ||= 1
|
47
|
-
cart_item = self.cart_items.find_or_create_by_item_id(item.id)
|
48
|
-
cart_item.quantity += options[:quantity]
|
49
|
-
cart_item.save!
|
50
|
-
self.reload
|
51
|
-
cart_item
|
52
|
-
end
|
53
|
-
|
54
|
-
#removes a quantity of an article specified by :article_id, returns nil if no article has been found
|
55
|
-
def remove_item(item,options = {})
|
56
|
-
cart_item = self.cart_items.find_by_item_id(item)
|
57
|
-
|
58
|
-
options[:quantity] ||= cart_item.quantity
|
59
|
-
if cart_item
|
60
|
-
cart_item.quantity -= options[:quantity]
|
61
|
-
cart_item.save!
|
62
|
-
self.reload
|
63
|
-
end
|
64
|
-
cart_item
|
65
|
-
end
|
66
|
-
|
67
|
-
#sets the quantity of an article specified by :article_id, returns nil if no article has been found
|
68
|
-
def update_item(item,options)
|
69
|
-
cart_item = self.cart_items.find_by_item_id(item)
|
70
|
-
if cart_item
|
71
|
-
cart_item.quantity = options[:quantity]
|
72
|
-
cart_item.save!
|
73
|
-
self.reload
|
74
|
-
end
|
75
|
-
cart_item
|
76
|
-
end
|
77
|
-
|
78
|
-
def shipping_cost_calculator
|
79
|
-
ShopBunny.shipping_cost_calculator
|
80
|
-
end
|
81
|
-
|
82
|
-
# Returns the class/model of the items you can buy. (Products)
|
83
|
-
def item_model
|
84
|
-
ShopBunny.item_model_class_name.constantize
|
85
|
-
end
|
86
|
-
|
87
|
-
# Make
|
88
|
-
def as_json(options={})
|
89
|
-
{
|
90
|
-
:cart => attributes.
|
91
|
-
merge(
|
92
|
-
:cart_items => cart_items.as_json,
|
93
|
-
:item_count => item_count,
|
94
|
-
:coupons => coupons.as_json,
|
95
|
-
:item_sum => item_sum,
|
96
|
-
:shipping_costs => shipping_costs,
|
97
|
-
:total => total
|
98
|
-
)
|
99
|
-
}
|
100
|
-
end
|
101
|
-
|
102
|
-
private
|
103
|
-
|
104
|
-
def update_coupons
|
105
|
-
Array(@coupon_code).each { |code|
|
106
|
-
coupon = Coupon.find_by_code(code)
|
107
|
-
coupons << coupon if coupon
|
108
|
-
}
|
109
|
-
end
|
110
|
-
|
111
|
-
def coupon_code_must_be_valid
|
112
|
-
Array(@coupon_code).each { |code|
|
113
|
-
coupon = Coupon.find_by_code(code)
|
114
|
-
if coupon.nil?
|
115
|
-
errors.add(:coupon_code, "is unknown")
|
116
|
-
elsif coupon.expired?
|
117
|
-
errors.add(:coupon_code, "is expired")
|
118
|
-
end
|
119
|
-
}
|
120
|
-
end
|
2
|
+
include ShopBunny::CartModule
|
121
3
|
end
|
@@ -15,10 +15,4 @@ ShopBunny.setup do |config|
|
|
15
15
|
#
|
16
16
|
# config.shipping_cost_calculator = MyShippingCostCalculator
|
17
17
|
|
18
|
-
# ShopBunny.controller_enhancement is a module that is included into the
|
19
|
-
# CartsController. You can e.g. control which layout is used for rendering
|
20
|
-
# the cart or add filters. E.g. just drop a ShopBunnyEnhancements module in
|
21
|
-
# lib/shop_bunny_enhancements.rb and use it like this:
|
22
|
-
# require 'shop_bunny_enhancements'
|
23
|
-
# config.controller_enhancement = ShopBunnyEnhancements
|
24
18
|
end
|
data/config/routes.rb
CHANGED
@@ -1,11 +1,16 @@
|
|
1
1
|
module ShopBunny
|
2
2
|
class InstallGenerator < Rails::Generators::Base
|
3
3
|
source_root File.expand_path("../../../../", __FILE__)
|
4
|
-
|
4
|
+
class_option :controller, :type => :boolean, :default => true, :desc => "copy controller templatefile."
|
5
|
+
class_option :model, :type => :boolean, :default => true, :desc => "copy model templatefile."
|
6
|
+
|
7
|
+
|
5
8
|
def copy_files
|
6
9
|
puts Dir['.']
|
7
10
|
directory 'db/migrate'
|
8
11
|
copy_file 'config/initializers/shop_bunny.rb'
|
12
|
+
copy_file 'lib/generators/shop_bunny/templates/shopbunny_controller_template.rb', 'app/controllers/carts_controller.rb' if options.controller?
|
13
|
+
copy_file 'lib/generators/shop_bunny/templates/shopbunny_model_template.rb', 'app/models/cart.rb' if options.model?
|
9
14
|
end
|
10
15
|
end
|
11
16
|
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module ShopBunny
|
2
|
+
module CartControllerModule
|
3
|
+
def self.included(clazz)
|
4
|
+
clazz.send(:respond_to, :html, :json)
|
5
|
+
clazz.send(:before_filter, :find_cart)
|
6
|
+
clazz.send(:before_filter, :find_item, :only => [:add_item, :remove_item])
|
7
|
+
end
|
8
|
+
|
9
|
+
def show
|
10
|
+
respond_with @cart
|
11
|
+
end
|
12
|
+
|
13
|
+
def add_item
|
14
|
+
@cart.add_item(@item) if @item
|
15
|
+
respond_with @cart do |format|
|
16
|
+
format.html { redirect_to :action => :show }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def remove_item
|
21
|
+
@cart.remove_item(@item) if @item
|
22
|
+
respond_with @cart do |format|
|
23
|
+
format.html { redirect_to :action => :show }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def checkout
|
28
|
+
end
|
29
|
+
|
30
|
+
def update
|
31
|
+
@cart.update_attributes(params[:cart])
|
32
|
+
respond_with @cart do |format|
|
33
|
+
format.html {
|
34
|
+
if @cart.errors.any?
|
35
|
+
render 'show'
|
36
|
+
else
|
37
|
+
# We have to redirect by hand here, because
|
38
|
+
# url_for(@cart) returns "/cart.x" when cart is a singular resource
|
39
|
+
# (see routes.rb). This is a known limitation of Rails.
|
40
|
+
# See https://rails.lighthouseapp.com/projects/8994/tickets/4168
|
41
|
+
redirect_to :action => :show
|
42
|
+
end
|
43
|
+
}
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def find_item
|
50
|
+
@item = @cart.item_model.find(params[:item_id])
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
module ShopBunny
|
2
|
+
module CartModule
|
3
|
+
|
4
|
+
|
5
|
+
def self.included(clazz)
|
6
|
+
clazz.send(:attr_accessor, :coupon_code)
|
7
|
+
clazz.send(:has_many, :cart_items, :dependent => :destroy)
|
8
|
+
clazz.send(:has_many, :coupon_uses, :dependent => :destroy)
|
9
|
+
clazz.send(:has_many, :coupons, :through => :coupon_uses)
|
10
|
+
clazz.send(:accepts_nested_attributes_for, :cart_items, :allow_destroy => true )
|
11
|
+
clazz.send(:before_save, :update_coupons)
|
12
|
+
clazz.send(:attr_accessible, :coupon_code, :cart_items_attributes)
|
13
|
+
clazz.send(:validate, :coupon_code_must_be_valid)
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
|
18
|
+
|
19
|
+
def items
|
20
|
+
self.cart_items
|
21
|
+
end
|
22
|
+
|
23
|
+
def item_count
|
24
|
+
self.cart_items.inject(0) {|sum,e| sum += e.quantity}
|
25
|
+
end
|
26
|
+
|
27
|
+
def shipping_costs
|
28
|
+
return 0 if coupons.any?(&:removes_shipping_cost)
|
29
|
+
shipping_cost_calculator.costs_for(self)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Calculates the sum of all cart_items, excluding the coupons discount!
|
33
|
+
def item_sum
|
34
|
+
self.cart_items.inject(0) {|sum,e| sum += e.quantity*e.item.price}
|
35
|
+
end
|
36
|
+
|
37
|
+
# Calculates the total sum and applies the coupons discount!
|
38
|
+
def total
|
39
|
+
sum = item_sum
|
40
|
+
|
41
|
+
absolute_discount = coupons.sum(:discount_credit)
|
42
|
+
relative_discount = coupons.inject(1) {|s,coupon| s * coupon.discount_percentage }
|
43
|
+
|
44
|
+
sum -= absolute_discount
|
45
|
+
sum *= relative_discount
|
46
|
+
|
47
|
+
sum += shipping_costs
|
48
|
+
|
49
|
+
[0, sum].max
|
50
|
+
end
|
51
|
+
|
52
|
+
#increases the quantity of an article. creates a new one if it doesn't exist
|
53
|
+
def add_item(item,options = {})
|
54
|
+
options[:quantity] ||= 1
|
55
|
+
cart_item = self.cart_items.find_or_create_by_item_id(item.id)
|
56
|
+
cart_item.quantity += options[:quantity]
|
57
|
+
cart_item.save!
|
58
|
+
self.reload
|
59
|
+
cart_item
|
60
|
+
end
|
61
|
+
|
62
|
+
#removes a quantity of an article specified by :article_id, returns nil if no article has been found
|
63
|
+
def remove_item(item,options = {})
|
64
|
+
cart_item = self.cart_items.find_by_item_id(item)
|
65
|
+
|
66
|
+
options[:quantity] ||= cart_item.quantity
|
67
|
+
if cart_item
|
68
|
+
cart_item.quantity -= options[:quantity]
|
69
|
+
cart_item.save!
|
70
|
+
self.reload
|
71
|
+
end
|
72
|
+
cart_item
|
73
|
+
end
|
74
|
+
|
75
|
+
#sets the quantity of an article specified by :article_id, returns nil if no article has been found
|
76
|
+
def update_item(item,options)
|
77
|
+
cart_item = self.cart_items.find_by_item_id(item)
|
78
|
+
if cart_item
|
79
|
+
cart_item.quantity = options[:quantity]
|
80
|
+
cart_item.save!
|
81
|
+
self.reload
|
82
|
+
end
|
83
|
+
cart_item
|
84
|
+
end
|
85
|
+
|
86
|
+
def shipping_cost_calculator
|
87
|
+
ShopBunny.shipping_cost_calculator
|
88
|
+
end
|
89
|
+
|
90
|
+
# Returns the class/model of the items you can buy. (Products)
|
91
|
+
def item_model
|
92
|
+
ShopBunny.item_model_class_name.constantize
|
93
|
+
end
|
94
|
+
|
95
|
+
# Make
|
96
|
+
def as_json(options={})
|
97
|
+
{
|
98
|
+
:cart => attributes.
|
99
|
+
merge(
|
100
|
+
:cart_items => cart_items.as_json,
|
101
|
+
:item_count => item_count,
|
102
|
+
:coupons => coupons.as_json,
|
103
|
+
:item_sum => item_sum,
|
104
|
+
:shipping_costs => shipping_costs,
|
105
|
+
:total => total
|
106
|
+
)
|
107
|
+
}
|
108
|
+
end
|
109
|
+
|
110
|
+
protected
|
111
|
+
|
112
|
+
def update_coupons
|
113
|
+
Array(@coupon_code).each { |code|
|
114
|
+
coupon = Coupon.find_by_code(code)
|
115
|
+
coupons << coupon if coupon
|
116
|
+
}
|
117
|
+
end
|
118
|
+
|
119
|
+
def coupon_code_must_be_valid
|
120
|
+
Array(@coupon_code).each { |code|
|
121
|
+
coupon = Coupon.find_by_code(code)
|
122
|
+
if coupon.nil?
|
123
|
+
errors.add(:coupon_code, "is unknown")
|
124
|
+
elsif coupon.expired?
|
125
|
+
errors.add(:coupon_code, "is expired")
|
126
|
+
end
|
127
|
+
}
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
data/lib/shop_bunny.rb
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
module ShopBunny
|
3
3
|
require 'shop_bunny/engine' if defined?(Rails) && Rails::VERSION::MAJOR == 3
|
4
4
|
require 'shop_bunny/shipping_cost_calculator'
|
5
|
+
require 'shop_bunny/cart_module'
|
6
|
+
require 'shop_bunny/cart_controller_module'
|
5
7
|
|
6
8
|
mattr_accessor :item_model_class_name
|
7
9
|
@@item_model_class_name = 'Item'
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shop_bunny
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 5
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 7
|
9
|
-
-
|
10
|
-
version: 0.7.
|
9
|
+
- 3
|
10
|
+
version: 0.7.3
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- kopfmaschine.com
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-09-
|
18
|
+
date: 2010-09-24 00:00:00 +02:00
|
19
19
|
default_executable:
|
20
20
|
dependencies: []
|
21
21
|
|
@@ -29,28 +29,32 @@ extensions: []
|
|
29
29
|
extra_rdoc_files: []
|
30
30
|
|
31
31
|
files:
|
32
|
+
- lib/generators/shop_bunny/templates/shopbunny_model_template.rb
|
33
|
+
- lib/generators/shop_bunny/templates/shopbunny_controller_template.rb
|
34
|
+
- lib/generators/shop_bunny/install_generator.rb
|
32
35
|
- lib/shop_bunny.rb
|
33
|
-
- lib/shop_bunny/
|
36
|
+
- lib/shop_bunny/cart_controller_module.rb
|
37
|
+
- lib/shop_bunny/cart_module.rb
|
34
38
|
- lib/shop_bunny/shipping_cost_calculator.rb
|
35
|
-
- lib/
|
39
|
+
- lib/shop_bunny/engine.rb
|
36
40
|
- app/views/carts/show.html.erb
|
41
|
+
- app/models/cart.rb
|
37
42
|
- app/models/coupon_use.rb
|
43
|
+
- app/models/cart_item.rb
|
38
44
|
- app/models/coupon.rb
|
39
|
-
- app/models/cart.rb
|
40
45
|
- app/models/item.rb
|
41
|
-
- app/models/cart_item.rb
|
42
46
|
- app/controllers/application_controller.rb
|
43
47
|
- app/controllers/carts_controller.rb
|
44
|
-
- db/migrate/20100915093821_create_coupon_uses.rb
|
45
|
-
- db/migrate/20100915091059_create_coupons.rb
|
46
48
|
- db/migrate/20100915162029_remove_owner_id_from_carts.rb
|
49
|
+
- db/migrate/20100915091059_create_coupons.rb
|
50
|
+
- db/migrate/20100915073016_create_items.rb
|
47
51
|
- db/migrate/20100902115627_create_carts.rb
|
52
|
+
- db/migrate/20100915093821_create_coupon_uses.rb
|
48
53
|
- db/migrate/20100916194407_set_default_column_value_for_cart_items_quantity.rb
|
49
|
-
- db/migrate/20100915073016_create_items.rb
|
50
54
|
- db/migrate/20100902115757_create_cart_items.rb
|
55
|
+
- config/initializers/add_cart_finder_to_controllers.rb
|
51
56
|
- config/initializers/shop_bunny.rb
|
52
57
|
- config/initializers/machinist.rb
|
53
|
-
- config/initializers/add_cart_finder_to_controllers.rb
|
54
58
|
- config/routes.rb
|
55
59
|
has_rdoc: true
|
56
60
|
homepage: http://kopfmaschine.com
|