spree_variant_options 0.4.0 → 0.4.1
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.
- data/.travis.yml +0 -1
- data/README.md +2 -1
- data/Versionfile +1 -1
- data/app/models/spree/option_value_decorator.rb +17 -0
- data/app/models/spree/product_decorator.rb +31 -0
- data/app/models/spree/variant_decorator.rb +15 -0
- data/app/views/spree/products/_variant_options.html.erb +6 -16
- data/features/step_definitions/variant_options.rb +1 -1
- data/lib/spree_variant_options/version.rb +1 -1
- data/test/unit/spree/option_value_test.rb +41 -16
- data/test/unit/spree/product_test.rb +11 -11
- metadata +23 -22
- data/app/models/option_value_decorator.rb +0 -13
- data/app/models/product_decorator.rb +0 -27
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -26,7 +26,7 @@ If you don't already have an existing Spree site, [click here](https://gist.gith
|
|
26
26
|
To install Spree Variant Options, just add the following to your Gemfile:
|
27
27
|
|
28
28
|
```ruby
|
29
|
-
gem 'spree_variant_options', '0.
|
29
|
+
gem 'spree_variant_options', '0.4.1'
|
30
30
|
```
|
31
31
|
|
32
32
|
Now, bundle up with:
|
@@ -97,6 +97,7 @@ Contributors
|
|
97
97
|
------------------------------------------------------------------------------
|
98
98
|
|
99
99
|
* Spencer Steffen ([@citrus](https://github.com/citrus))
|
100
|
+
* Stéphane Bounmy ([@sbounmy](https://github.com/sbounmy))
|
100
101
|
* Dan Morin ([@danmorin](https://github.com/danmorin))
|
101
102
|
* Richard Brown ([@rbrown](https://github.com/rbrown))
|
102
103
|
* [@baracek](https://github.com/baracek)
|
data/Versionfile
CHANGED
@@ -0,0 +1,17 @@
|
|
1
|
+
Spree::OptionValue.class_eval do
|
2
|
+
|
3
|
+
default_scope order("#{quoted_table_name}.position")
|
4
|
+
|
5
|
+
has_attached_file :image,
|
6
|
+
:styles => { :small => '40x30#', :large => '140x110#' },
|
7
|
+
:default_style => :small,
|
8
|
+
:url => "/spree/option_values/:id/:style/:basename.:extension",
|
9
|
+
:path => ":rails_root/public/spree/option_values/:id/:style/:basename.:extension"
|
10
|
+
|
11
|
+
def has_image?
|
12
|
+
image_file_name && !image_file_name.empty?
|
13
|
+
end
|
14
|
+
|
15
|
+
scope :for_product, lambda { |product| select("DISTINCT #{table_name}.*").where("spree_option_values_variants.variant_id IN (?)", product.variant_ids).joins(:variants)
|
16
|
+
}
|
17
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
Spree::Product.class_eval do
|
2
|
+
|
3
|
+
def option_values
|
4
|
+
@_option_values ||= Spree::OptionValue.for_product(self).sort_by {|ov| ov.option_type.position }
|
5
|
+
end
|
6
|
+
|
7
|
+
def grouped_option_values
|
8
|
+
@_grouped_option_values ||= option_values.group_by(&:option_type)
|
9
|
+
end
|
10
|
+
|
11
|
+
def variants_for_option_value(value)
|
12
|
+
@_variant_option_values ||= variants.includes(:option_values).all
|
13
|
+
@_variant_option_values.select { |i| i.option_value_ids.include?(value.id) }
|
14
|
+
end
|
15
|
+
|
16
|
+
def variant_options_hash
|
17
|
+
return @_variant_options_hash if @_variant_options_hash
|
18
|
+
hash = {}
|
19
|
+
variants.includes(:option_values).each do |variant|
|
20
|
+
variant.option_values.each do |ov|
|
21
|
+
otid = ov.option_type_id.to_s
|
22
|
+
ovid = ov.id.to_s
|
23
|
+
hash[otid] ||= {}
|
24
|
+
hash[otid][ovid] ||= {}
|
25
|
+
hash[otid][ovid][variant.id.to_s] = variant.to_hash
|
26
|
+
end
|
27
|
+
end
|
28
|
+
@_variant_options_hash = hash
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
Spree::Variant.class_eval do
|
2
|
+
|
3
|
+
include ActionView::Helpers::NumberHelper
|
4
|
+
|
5
|
+
def to_hash
|
6
|
+
actual_price = self.price
|
7
|
+
#actual_price += Calculator::Vat.calculate_tax_on(self) if Spree::Config[:show_price_inc_vat]
|
8
|
+
{
|
9
|
+
:id => self.id,
|
10
|
+
:count => self.count_on_hand,
|
11
|
+
:price => number_to_currency(actual_price)
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -1,25 +1,17 @@
|
|
1
1
|
<% if @product.has_variants? %>
|
2
2
|
<div id="product-variants">
|
3
3
|
<h2><%= t('variants') %></h2>
|
4
|
-
|
5
4
|
<% index = 0 %>
|
6
5
|
<% @product.grouped_option_values.each do |type, values| %>
|
7
6
|
<div id="<%= dom_id(type) %>" class="variant-options index-<%= index %>">
|
8
7
|
<h6 class="variant-option-type"><%= type.presentation %></h6>
|
9
8
|
<ul class="variant-option-values">
|
10
|
-
<% values.each do |value| %>
|
9
|
+
<% values.sort_by(&:position).each do |value| %>
|
11
10
|
<% classes = ["option-value"] %>
|
12
|
-
<%
|
13
|
-
<%
|
14
|
-
|
15
|
-
<% classes << "unavailable" %>
|
16
|
-
<% else %>
|
17
|
-
<% classes << ( Spree::Config[:allow_backorders] || variants.sum(&:count_on_hand) > 0 ? "in-stock" : "out-of-stock" ) %>
|
18
|
-
<% end %>
|
11
|
+
<% unless (variants = @product.variants_for_option_value(value)).empty? %>
|
12
|
+
<% classes << ( Spree::Config[:allow_backorders] || variants.sum(&:count_on_hand) > 0 ? "in-stock" : "out-of-stock" ) if index == 0 %>
|
13
|
+
<li><%= link_to value.has_image? ? image_tag(value.image.url, :alt => value.presentation) : content_tag(:span, value.presentation), "#", :title => value.presentation, :class => classes.join(" "), :rel => "#{type.id}-#{value.id}" %></li>
|
19
14
|
<% end %>
|
20
|
-
<li>
|
21
|
-
<%= link_to value.has_image? ? image_tag(value.image.url, :alt => value.presentation) : content_tag(:span, value.presentation), "#", :title => value.presentation, :class => classes.join(" "), :rel => "#{type.id}-#{value.id}" %>
|
22
|
-
</li>
|
23
15
|
<% end %>
|
24
16
|
<li class="clear-option"><%= link_to "X", "#clear", :class => "clear-button clear-index-#{index}" %></li>
|
25
17
|
<li class="clear"></li>
|
@@ -30,10 +22,8 @@
|
|
30
22
|
<%= hidden_field_tag "products[#{@product.id}]", "", :id => "variant_id", :class => "hidden" %>
|
31
23
|
<script type="text/javascript">
|
32
24
|
//<![CDATA[
|
33
|
-
|
25
|
+
var variant_options = new VariantOptions(<%== @product.variant_options_hash.to_json %>, <%== !!Spree::Config[:allow_backorders] %>);
|
34
26
|
//]]>
|
35
|
-
</script>
|
36
|
-
|
27
|
+
</script>
|
37
28
|
</div>
|
38
|
-
|
39
29
|
<% end%>
|
@@ -47,7 +47,7 @@ Then /^I should see image "([^"]*)" within the first option value$/ do |source|
|
|
47
47
|
ot = @product.option_types.first
|
48
48
|
ov = ot.option_values.first
|
49
49
|
within ".variant-options a[rel='#{ot.id}-#{ov.id}']" do
|
50
|
-
assert_match "/
|
50
|
+
assert_match "/spree/option_values/#{ov.id}/small/#{source}", find("img").native.attribute("src")
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
@@ -7,51 +7,76 @@ class Spree::OptionValueTest < ActiveSupport::TestCase
|
|
7
7
|
end
|
8
8
|
|
9
9
|
should_have_attached_file :image
|
10
|
-
|
10
|
+
|
11
11
|
context "a new option value" do
|
12
|
-
|
12
|
+
|
13
13
|
setup do
|
14
14
|
@option_value = Spree::OptionValue.new
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
should "not have an image" do
|
18
18
|
assert !@option_value.has_image?
|
19
19
|
end
|
20
|
-
|
20
|
+
|
21
21
|
end
|
22
|
-
|
22
|
+
|
23
23
|
context "an existing option value" do
|
24
|
-
|
24
|
+
|
25
25
|
setup do
|
26
26
|
@option_value = Factory.create(:option_value)
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
29
|
should "not have an image" do
|
30
30
|
assert !@option_value.has_image?
|
31
31
|
end
|
32
|
-
|
32
|
+
|
33
33
|
context "with an image" do
|
34
|
-
|
34
|
+
|
35
35
|
setup do
|
36
36
|
@path = @images.shuffle.first
|
37
37
|
file = File.open(@path)
|
38
38
|
@option_value.update_attributes(:image => file)
|
39
39
|
file.close
|
40
40
|
end
|
41
|
-
|
41
|
+
|
42
42
|
should "have an image" do
|
43
43
|
assert @option_value.has_image?
|
44
44
|
end
|
45
|
-
|
45
|
+
|
46
46
|
should "have small large and original images" do
|
47
|
-
dir = File.expand_path("../../../dummy/public/
|
47
|
+
dir = File.expand_path("../../../dummy/public/spree/option_values/#{@option_value.id}", __FILE__)
|
48
48
|
%w(small large original).each do |size|
|
49
49
|
assert File.exists?(File.join(dir, size, File.basename(@path)))
|
50
|
-
end
|
50
|
+
end
|
51
51
|
end
|
52
|
-
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
context "#for_product" do
|
58
|
+
setup do
|
59
|
+
@product = Factory.create(:product_with_variants)
|
60
|
+
end
|
61
|
+
|
62
|
+
should "return uniq option_values" do
|
63
|
+
unused = Factory(:option_value, :option_type => @product.option_types.first, :presentation => "Unused")
|
64
|
+
assert !Spree::OptionValue.for_product(@product).include?(unused)
|
65
|
+
end
|
66
|
+
|
67
|
+
should "retain option values sort order" do
|
68
|
+
@unordered, @prev_position = false, 0
|
69
|
+
Spree::OptionValue.for_product(@product).all.each do |ov|
|
70
|
+
@unordered = true if @prev_position > ov.position
|
71
|
+
@prev_position = ov.position
|
72
|
+
end
|
73
|
+
|
74
|
+
assert !@unordered
|
75
|
+
end
|
76
|
+
|
77
|
+
should "return empty array when no variants" do
|
78
|
+
product = Factory(:product)
|
79
|
+
assert_equal [], Spree::OptionValue.for_product(product)
|
53
80
|
end
|
54
|
-
|
55
81
|
end
|
56
|
-
|
57
82
|
end
|
@@ -5,34 +5,34 @@ class Spree::ProductTest < ActiveSupport::TestCase
|
|
5
5
|
setup do
|
6
6
|
@methods = %w(option_values grouped_option_values variant_options_hash)
|
7
7
|
end
|
8
|
-
|
8
|
+
|
9
9
|
context "any product" do
|
10
|
-
|
10
|
+
|
11
11
|
setup do
|
12
12
|
@product = Factory.create(:product)
|
13
13
|
end
|
14
|
-
|
14
|
+
|
15
15
|
should "have proper methods" do
|
16
16
|
@methods.each do |m|
|
17
17
|
assert @product.respond_to?(m)
|
18
18
|
end
|
19
19
|
end
|
20
|
-
|
20
|
+
|
21
21
|
end
|
22
|
-
|
23
|
-
|
22
|
+
|
23
|
+
|
24
24
|
context "a product with variants" do
|
25
|
-
|
25
|
+
|
26
26
|
setup do
|
27
27
|
@product = Factory.create(:product_with_variants)
|
28
28
|
end
|
29
|
-
|
29
|
+
|
30
30
|
should "have variants and option types and values" do
|
31
31
|
assert_equal 2, @product.option_types.count
|
32
32
|
assert_equal 12, @product.option_values.count
|
33
33
|
assert_equal 32, @product.variants.count
|
34
34
|
end
|
35
|
-
|
35
|
+
|
36
36
|
should "have values grouped by type" do
|
37
37
|
expected = { "size" => 4, "color" => 8 }
|
38
38
|
assert_equal 2, @product.grouped_option_values.count
|
@@ -40,7 +40,7 @@ class Spree::ProductTest < ActiveSupport::TestCase
|
|
40
40
|
assert_equal expected[type.name], values.length
|
41
41
|
end
|
42
42
|
end
|
43
|
-
|
43
|
+
|
44
44
|
end
|
45
|
-
|
45
|
+
|
46
46
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spree_variant_options
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-03-06 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: spree_core
|
16
|
-
requirement: &
|
16
|
+
requirement: &70249587535800 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: 1.0.0
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70249587535800
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: spree_sample
|
27
|
-
requirement: &
|
27
|
+
requirement: &70249587528380 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: 1.0.0
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70249587528380
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: dummier
|
38
|
-
requirement: &
|
38
|
+
requirement: &70249587527100 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: 0.3.0
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70249587527100
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: shoulda
|
49
|
-
requirement: &
|
49
|
+
requirement: &70249587525800 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: 3.0.0.beta2
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70249587525800
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: factory_girl
|
60
|
-
requirement: &
|
60
|
+
requirement: &70249587524740 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: 2.3.2
|
66
66
|
type: :development
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *70249587524740
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: cucumber-rails
|
71
|
-
requirement: &
|
71
|
+
requirement: &70249587523920 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ! '>='
|
@@ -76,10 +76,10 @@ dependencies:
|
|
76
76
|
version: 1.2.1
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *70249587523920
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
81
|
name: database_cleaner
|
82
|
-
requirement: &
|
82
|
+
requirement: &70249587522400 !ruby/object:Gem::Requirement
|
83
83
|
none: false
|
84
84
|
requirements:
|
85
85
|
- - ! '>='
|
@@ -87,10 +87,10 @@ dependencies:
|
|
87
87
|
version: 0.6.7
|
88
88
|
type: :development
|
89
89
|
prerelease: false
|
90
|
-
version_requirements: *
|
90
|
+
version_requirements: *70249587522400
|
91
91
|
- !ruby/object:Gem::Dependency
|
92
92
|
name: sqlite3
|
93
|
-
requirement: &
|
93
|
+
requirement: &70249587521480 !ruby/object:Gem::Requirement
|
94
94
|
none: false
|
95
95
|
requirements:
|
96
96
|
- - ! '>='
|
@@ -98,7 +98,7 @@ dependencies:
|
|
98
98
|
version: 1.3.4
|
99
99
|
type: :development
|
100
100
|
prerelease: false
|
101
|
-
version_requirements: *
|
101
|
+
version_requirements: *70249587521480
|
102
102
|
description: Spree Variant Options is a simple spree extension that replaces the radio-button
|
103
103
|
variant selection with groups of option types and values. Please see the documentation
|
104
104
|
for more details.
|
@@ -120,8 +120,9 @@ files:
|
|
120
120
|
- app/assets/javascripts/store/variant_options.js
|
121
121
|
- app/assets/stylesheets/store/variant_options.css.erb
|
122
122
|
- app/controllers/spree/admin/option_values_controller.rb
|
123
|
-
- app/models/option_value_decorator.rb
|
124
|
-
- app/models/product_decorator.rb
|
123
|
+
- app/models/spree/option_value_decorator.rb
|
124
|
+
- app/models/spree/product_decorator.rb
|
125
|
+
- app/models/spree/variant_decorator.rb
|
125
126
|
- app/overrides/spree_variant_options.rb
|
126
127
|
- app/views/spree/admin/option_types/_option_value_fields.html.erb
|
127
128
|
- app/views/spree/admin/option_values/_table_header.html.erb
|
@@ -180,7 +181,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
180
181
|
version: '0'
|
181
182
|
segments:
|
182
183
|
- 0
|
183
|
-
hash:
|
184
|
+
hash: 1078116666989698030
|
184
185
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
185
186
|
none: false
|
186
187
|
requirements:
|
@@ -189,7 +190,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
189
190
|
version: '0'
|
190
191
|
segments:
|
191
192
|
- 0
|
192
|
-
hash:
|
193
|
+
hash: 1078116666989698030
|
193
194
|
requirements: []
|
194
195
|
rubyforge_project: spree_variant_options
|
195
196
|
rubygems_version: 1.8.10
|
@@ -1,13 +0,0 @@
|
|
1
|
-
Spree::OptionValue.class_eval do
|
2
|
-
|
3
|
-
default_scope order(:position)
|
4
|
-
|
5
|
-
has_attached_file :image,
|
6
|
-
:styles => { :small => '40x30#', :large => '140x110#' },
|
7
|
-
:default_style => :small
|
8
|
-
|
9
|
-
def has_image?
|
10
|
-
image_file_name && !image_file_name.empty?
|
11
|
-
end
|
12
|
-
|
13
|
-
end
|
@@ -1,27 +0,0 @@
|
|
1
|
-
Spree::Product.class_eval do
|
2
|
-
|
3
|
-
include ActionView::Helpers::NumberHelper
|
4
|
-
|
5
|
-
def option_values
|
6
|
-
option_types.map{|i| i.option_values }.flatten.uniq
|
7
|
-
end
|
8
|
-
|
9
|
-
def grouped_option_values
|
10
|
-
option_values.group_by(&:option_type)
|
11
|
-
end
|
12
|
-
|
13
|
-
def variant_options_hash
|
14
|
-
return @variant_options_hash if @variant_options_hash
|
15
|
-
@variant_options_hash = Hash[grouped_option_values.map{ |type, values|
|
16
|
-
[type.id.inspect, Hash[values.map{ |value|
|
17
|
-
[value.id.inspect, Hash[variants.includes(:option_values).select{ |variant|
|
18
|
-
variant.option_values.select{ |val|
|
19
|
-
val.id == value.id && val.option_type_id == type.id
|
20
|
-
}.length == 1 }.map{ |v| [ v.id, { :id => v.id, :count => v.count_on_hand, :price => number_to_currency(v.price) } ] }]
|
21
|
-
]
|
22
|
-
}]]
|
23
|
-
}]
|
24
|
-
@variant_options_hash
|
25
|
-
end
|
26
|
-
|
27
|
-
end
|