glysellin 0.4.1 → 0.4.1.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.
- checksums.yaml +8 -8
- data/app/helpers/glysellin/cart_helper.rb +4 -4
- data/app/helpers/glysellin/products_helper.rb +19 -0
- data/app/models/glysellin/{order_item.rb → line_item.rb} +17 -7
- data/app/models/glysellin/order.rb +2 -2
- data/app/models/glysellin/product.rb +12 -114
- data/app/models/glysellin/product_property.rb +10 -3
- data/app/models/glysellin/product_property_type.rb +6 -4
- data/app/models/glysellin/variant.rb +25 -23
- data/app/views/glysellin/cart/_added_to_cart_warning.html.erb +11 -4
- data/app/views/glysellin/cart/_products.html.erb +1 -0
- data/app/views/glysellin/products/_add_to_cart.html.haml +13 -0
- data/config/locales/glysellin.en.yml +5 -4
- data/config/locales/glysellin.fr.yml +3 -0
- data/db/migrate/20130609013900_add_sellable_references_to_glysellin_products.rb +6 -0
- data/db/migrate/20130609023300_remove_unused_fields_from_glysellin_products.rb +18 -0
- data/db/migrate/20130609025800_remove_taxonomies_from_system.rb +21 -0
- data/db/migrate/20130609040600_rename_order_items_to_line_items.rb +6 -0
- data/db/migrate/20130609142100_add_variant_id_to_glysellin_line_items.rb +5 -0
- data/db/migrate/20130609155600_make_variants_belong_to_sellables_and_not_products.rb +16 -0
- data/db/migrate/20130609193600_drop_product_types.rb +22 -0
- data/db/migrate/20130609200000_remove_unused_product_properties_columns.rb +15 -0
- data/db/migrate/20130609200700_remove_position_from_glysellin_variants.rb +9 -0
- data/lib/glysellin.rb +0 -1
- data/lib/glysellin/engine.rb +7 -0
- data/lib/glysellin/engine/routes.rb +0 -11
- data/lib/glysellin/property_finder.rb +2 -2
- data/lib/glysellin/sellable.rb +69 -0
- data/lib/glysellin/sellable/multi.rb +24 -0
- data/lib/glysellin/sellable/simple.rb +30 -0
- data/lib/glysellin/version.rb +1 -1
- data/lib/tasks/glysellin_tasks.rake +1 -1
- metadata +16 -13
- data/app/controllers/glysellin/products_controller.rb +0 -12
- data/app/models/glysellin/product_type.rb +0 -11
- data/app/models/glysellin/taxonomy.rb +0 -35
- data/app/views/glysellin/products/_add_to_cart.html.erb +0 -16
- data/app/views/glysellin/products/_item.html.erb +0 -21
- data/app/views/glysellin/products/filter.html.erb +0 -0
- data/app/views/glysellin/products/index.html.erb +0 -3
- data/app/views/glysellin/products/show.html.erb +0 -3
- data/lib/glysellin/acts_as_sellable.rb +0 -14
- data/lib/glysellin/product_methods.rb +0 -66
checksums.yaml
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
---
|
|
2
2
|
!binary "U0hBMQ==":
|
|
3
3
|
metadata.gz: !binary |-
|
|
4
|
-
|
|
4
|
+
OGJiYTNiMzg1M2E3MTAxZjkyMzJkMjQzMWUxY2MwYzg3NDg2NTY1Zg==
|
|
5
5
|
data.tar.gz: !binary |-
|
|
6
|
-
|
|
6
|
+
Zjg4ZTQ2ZGQzMjk1ODNiMmFkZDAwZDg4ZTllZDhiYjE4ZjRhMjk1OA==
|
|
7
7
|
!binary "U0hBNTEy":
|
|
8
8
|
metadata.gz: !binary |-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
MTU5ZjJhNTcxZTNiNTJkZmEwODQwNDczMTZlZWM1M2MwZjI5MTk5OWJkMjMx
|
|
10
|
+
MTE0OTRiZjU0ZTBlNWIwNzY4NWQyYzU4YTNlNzllNmYwMDI1NzkwMjY3NjY0
|
|
11
|
+
YzBjZGUxZDgzY2NjOTc5MTBkN2VhZjVmYjExYTFkNDNjZDZjNmI=
|
|
12
12
|
data.tar.gz: !binary |-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
OGMwZDVjNDk1ZGU0NzAyNDM5YzBmYzlmMzZkOTBmMTlmYTY1NjBlZGZlODRl
|
|
14
|
+
YmZjNTc2Y2ZkODc0MTVhOWY0NDU5NzVkNmIzNmNmZThmZWE3NjJkZjU5YTEy
|
|
15
|
+
NWJlZGRiOWU2YmVkZDRmZGYyNGVjNmE5NzljNDA5YjZiMGJlOGM=
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
module Glysellin
|
|
2
2
|
module CartHelper
|
|
3
|
-
def add_to_cart_form
|
|
3
|
+
def add_to_cart_form sellable, options = {}
|
|
4
4
|
# Default to remote form
|
|
5
5
|
options[:remote] = true unless options[:remote] == false
|
|
6
6
|
# Render actual form
|
|
7
7
|
render partial: 'glysellin/products/add_to_cart', locals: {
|
|
8
|
-
|
|
8
|
+
sellable: sellable,
|
|
9
9
|
options: options
|
|
10
10
|
}
|
|
11
11
|
end
|
|
@@ -14,8 +14,8 @@ module Glysellin
|
|
|
14
14
|
render partial: 'glysellin/cart/added_to_cart_warning'
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
-
def render_cart
|
|
18
|
-
render partial: "glysellin/cart/cart", locals: { cart:
|
|
17
|
+
def render_cart
|
|
18
|
+
render partial: "glysellin/cart/cart", locals: { cart: current_cart }
|
|
19
19
|
end
|
|
20
20
|
end
|
|
21
21
|
end
|
|
@@ -1,4 +1,23 @@
|
|
|
1
1
|
module Glysellin
|
|
2
2
|
module ProductsHelper
|
|
3
|
+
def variants_options_for sellable
|
|
4
|
+
# Prepare ou arguments arrays
|
|
5
|
+
all_variants, disabled_variants = [], []
|
|
6
|
+
# Iterate on each variant to find which are enabled and disabled
|
|
7
|
+
sellable.published_variants.each do |variant|
|
|
8
|
+
next unless variant.published?
|
|
9
|
+
if variant.in_stock?
|
|
10
|
+
name = variant.name
|
|
11
|
+
else
|
|
12
|
+
disabled_variants << variant.id
|
|
13
|
+
name = variant.name +
|
|
14
|
+
" (#{ t('glysellin.labels.sellables.out_of_stock') })"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
all_variants << [name, variant.id]
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
options_for_select(all_variants, disabled: disabled_variants)
|
|
21
|
+
end
|
|
3
22
|
end
|
|
4
23
|
end
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
module Glysellin
|
|
2
|
-
class
|
|
3
|
-
self.table_name =
|
|
2
|
+
class LineItem < ActiveRecord::Base
|
|
3
|
+
self.table_name = "glysellin_line_items"
|
|
4
4
|
belongs_to :order, inverse_of: :products
|
|
5
5
|
|
|
6
|
+
belongs_to :variant, class_name: "Glysellin::Variant"
|
|
7
|
+
|
|
6
8
|
attr_accessible :sku, :name, :eot_price, :vat_rate, :bundle, :price,
|
|
7
|
-
:quantity, :weight
|
|
9
|
+
:quantity, :weight, :variant_id
|
|
8
10
|
|
|
9
11
|
# The attributes we getch from a product to build our order item
|
|
10
12
|
PRODUCT_ATTRIBUTES_FOR_ITEM = %w(sku name eot_price vat_rate price weight)
|
|
@@ -15,15 +17,19 @@ module Glysellin
|
|
|
15
17
|
# @param [String] id The id string of the item
|
|
16
18
|
# @param [Boolean] bundle If it's a bundle or just one product
|
|
17
19
|
#
|
|
18
|
-
# @return [
|
|
20
|
+
# @return [LineItem] The created order item
|
|
21
|
+
#
|
|
19
22
|
def build_from_product id, quantity
|
|
20
|
-
|
|
23
|
+
variant = Glysellin::Variant.find_by_id(id)
|
|
21
24
|
|
|
22
25
|
attrs = PRODUCT_ATTRIBUTES_FOR_ITEM.map do |key|
|
|
23
|
-
[key,
|
|
26
|
+
[key, variant.public_send(key)]
|
|
24
27
|
end
|
|
25
28
|
|
|
26
|
-
|
|
29
|
+
self.new Hash[attrs].merge(
|
|
30
|
+
"quantity" => quantity,
|
|
31
|
+
"variant_id" => variant.id
|
|
32
|
+
)
|
|
27
33
|
end
|
|
28
34
|
end
|
|
29
35
|
|
|
@@ -34,5 +40,9 @@ module Glysellin
|
|
|
34
40
|
def total_price
|
|
35
41
|
quantity * price
|
|
36
42
|
end
|
|
43
|
+
|
|
44
|
+
def sellable
|
|
45
|
+
variant && variant.product && variant.product.sellable
|
|
46
|
+
end
|
|
37
47
|
end
|
|
38
48
|
end
|
|
@@ -27,7 +27,7 @@ module Glysellin
|
|
|
27
27
|
#
|
|
28
28
|
# Order products are used to map order to cloned and simplified products
|
|
29
29
|
# so the Order propererties can't be affected by product updates
|
|
30
|
-
has_many :products, class_name: 'Glysellin::
|
|
30
|
+
has_many :products, class_name: 'Glysellin::LineItem',
|
|
31
31
|
foreign_key: 'order_id', dependent: :destroy
|
|
32
32
|
|
|
33
33
|
# The actual buyer
|
|
@@ -158,7 +158,7 @@ module Glysellin
|
|
|
158
158
|
|
|
159
159
|
def products=(attributes)
|
|
160
160
|
products = attributes.reduce([]) do |list, product|
|
|
161
|
-
item =
|
|
161
|
+
item = LineItem.build_from_product(product[:id], product[:quantity])
|
|
162
162
|
item ? (list << item) : list
|
|
163
163
|
end
|
|
164
164
|
|
|
@@ -3,134 +3,32 @@ require 'friendly_id'
|
|
|
3
3
|
|
|
4
4
|
module Glysellin
|
|
5
5
|
class Product < ActiveRecord::Base
|
|
6
|
-
include ProductMethods
|
|
7
|
-
extend FriendlyId
|
|
8
|
-
|
|
9
|
-
friendly_id :name, use: :slugged
|
|
10
6
|
|
|
11
7
|
self.table_name = 'glysellin_products'
|
|
12
8
|
|
|
13
|
-
|
|
14
|
-
#
|
|
15
|
-
# The ProductImage model is used for products and bundles with the same
|
|
16
|
-
has_many :images, as: :imageable, class_name: 'Glysellin::ProductImage',
|
|
17
|
-
inverse_of: :imageable, dependent: :destroy
|
|
18
|
-
|
|
19
|
-
# Can have multiple taxonomies
|
|
20
|
-
has_and_belongs_to_many :taxonomies, :class_name => 'Glysellin::Taxonomy',
|
|
21
|
-
join_table: 'glysellin_products_taxonomies', :foreign_key => 'product_id'
|
|
22
|
-
|
|
23
|
-
# N..N relation between bundles and products
|
|
24
|
-
# has_many :bundle_products, class_name: 'Glysellin::BundleProduct',
|
|
25
|
-
# foreign_key: 'product_id'
|
|
26
|
-
# has_many :bundles, class_name: 'Glysellin::Product',
|
|
27
|
-
# through: :bundle_products
|
|
28
|
-
|
|
29
|
-
# # Bundled products in current_product
|
|
30
|
-
# has_many :product_bundles, class_name: 'Glysellin::BundleProduct',
|
|
31
|
-
# foreign_key: 'bundle_id'
|
|
32
|
-
# has_many :bundled_products, class_name: 'Glysellin::Product',
|
|
33
|
-
# through: :product_bundles
|
|
9
|
+
belongs_to :sellable, polymorphic: true, inverse_of: :product
|
|
34
10
|
|
|
35
11
|
# Products can belong to a brand
|
|
36
|
-
belongs_to :brand, :
|
|
37
|
-
|
|
38
|
-
belongs_to :product_type
|
|
39
|
-
|
|
40
|
-
has_many :variants, class_name: 'Glysellin::Variant',
|
|
41
|
-
before_add: :set_product_on_variant, dependent: :destroy
|
|
42
|
-
|
|
43
|
-
accepts_nested_attributes_for :images, allow_destroy: true, reject_if: :all_blank
|
|
44
|
-
accepts_nested_attributes_for :variants, allow_destroy: true, reject_if: :all_blank
|
|
45
|
-
|
|
46
|
-
# accepts_nested_attributes_for :bundled_products, allow_destroy: true, reject_if: :all_blank
|
|
47
|
-
|
|
48
|
-
attr_accessible :description, :name, :sku, :slug, :vat_rate,
|
|
49
|
-
:brand, :taxonomies, :images, :published,
|
|
50
|
-
:display_priority, :images_attributes, :taxonomy_ids, :unlimited_stock,
|
|
51
|
-
:position, :brand_id, :variants_attributes, :variants, :product_type_id
|
|
52
|
-
|
|
53
|
-
# :bundled_products_attributes
|
|
54
|
-
|
|
55
|
-
# Validations
|
|
56
|
-
#
|
|
57
|
-
validates_presence_of :name, :slug
|
|
58
|
-
# Validates price related attributes only unless we have bundled products
|
|
59
|
-
# so we can defer validations to them
|
|
60
|
-
validates :vat_rate, presence: true,
|
|
61
|
-
numericality: true # , unless: proc { |p| p.bundled_products.length > 0 }
|
|
62
|
-
|
|
63
|
-
# We check presence of sku if set in global config
|
|
64
|
-
validates :sku, presence: true, if: proc { Glysellin.autoset_sku }
|
|
12
|
+
belongs_to :brand, class_name: "Glysellin::Brand", inverse_of: :products
|
|
65
13
|
|
|
66
|
-
|
|
67
|
-
#
|
|
68
|
-
before_validation :set_sku, :set_vat_rate, :ensure_variant
|
|
14
|
+
attr_accessible :vat_rate, :brand, :brand_id
|
|
69
15
|
|
|
70
|
-
|
|
71
|
-
scope :with_taxonomy, lambda { |*taxonomies|
|
|
72
|
-
# Ensure we only have slugs so we got a string vector
|
|
73
|
-
taxonomies.map! { |t| t.kind_of?(Glysellin::Taxonomy) ? t.slug : t }
|
|
74
|
-
# Get products with those taxonomies
|
|
75
|
-
includes(:taxonomies).where('glysellin_taxonomies.slug IN (?)', taxonomies)
|
|
76
|
-
}
|
|
16
|
+
validates :vat_rate, presence: true, numericality: true
|
|
77
17
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
# And as for the validation, if the SKU is configured to be autoset,
|
|
83
|
-
# we check generate it
|
|
84
|
-
def set_sku
|
|
85
|
-
unless (sku && sku.length > 0) || !Glysellin.autoset_sku
|
|
86
|
-
self.sku = generate_sku
|
|
87
|
-
end
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
def set_vat_rate
|
|
91
|
-
if !vat_rate
|
|
92
|
-
self.vat_rate = Glysellin.default_vat_rate
|
|
93
|
-
end
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
def ensure_variant
|
|
97
|
-
variants.build(product: self) unless variants.length > 0
|
|
18
|
+
def name
|
|
19
|
+
sellable && sellable.name
|
|
98
20
|
end
|
|
99
21
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
def available_variants
|
|
103
|
-
variants.available
|
|
22
|
+
def vat_rate
|
|
23
|
+
super.presence || Glysellin.default_vat_rate
|
|
104
24
|
end
|
|
105
25
|
|
|
106
|
-
def
|
|
107
|
-
|
|
26
|
+
def vat_ratio
|
|
27
|
+
1 + vat_rate / 100
|
|
108
28
|
end
|
|
109
29
|
|
|
110
|
-
def
|
|
111
|
-
|
|
30
|
+
def variants
|
|
31
|
+
sellable.published_variants
|
|
112
32
|
end
|
|
113
|
-
|
|
114
|
-
def set_product_on_variant variant
|
|
115
|
-
variant.product = self
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
# bundle_attribute :price do |product|
|
|
119
|
-
# product.bundled_products.reduce(0) do |total, product|
|
|
120
|
-
# total + product.price
|
|
121
|
-
# end
|
|
122
|
-
# end
|
|
123
|
-
|
|
124
|
-
# bundle_attribute :eot_price do |product, att|
|
|
125
|
-
# product.bundled_products.reduce(0) do |total, product|
|
|
126
|
-
# total + product.eot_price
|
|
127
|
-
# end
|
|
128
|
-
# end
|
|
129
|
-
|
|
130
|
-
# bundle_attribute :vat_rate do |product|
|
|
131
|
-
# product.bundled_products.reduce(0) do |total, product|
|
|
132
|
-
# total + (product.vat_rate * product.price)
|
|
133
|
-
# end / product.price
|
|
134
|
-
# end
|
|
135
33
|
end
|
|
136
34
|
end
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
module Glysellin
|
|
2
2
|
class ProductProperty < ActiveRecord::Base
|
|
3
3
|
self.table_name = 'glysellin_product_properties'
|
|
4
|
-
attr_accessible :
|
|
4
|
+
attr_accessible :value, :variant_id, :type_id
|
|
5
5
|
|
|
6
|
-
belongs_to :variant,
|
|
7
|
-
|
|
6
|
+
belongs_to :variant, class_name: "Glysellin::Variant",
|
|
7
|
+
inverse_of: :properties
|
|
8
|
+
|
|
9
|
+
belongs_to :type, class_name: 'Glysellin::ProductPropertyType',
|
|
10
|
+
inverse_of: :properties
|
|
8
11
|
|
|
9
12
|
# validate :check_uniqueness_of_type
|
|
10
13
|
|
|
@@ -13,6 +16,10 @@ module Glysellin
|
|
|
13
16
|
|
|
14
17
|
private
|
|
15
18
|
|
|
19
|
+
def name
|
|
20
|
+
type && type.name
|
|
21
|
+
end
|
|
22
|
+
|
|
16
23
|
def check_uniqueness_of_type
|
|
17
24
|
if self.variant.properties.map(&:type).include? self.type
|
|
18
25
|
errors.add(:type, I18n.t("glysellin.controllers.errors.double_property"))
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
module Glysellin
|
|
2
2
|
class ProductPropertyType < ActiveRecord::Base
|
|
3
3
|
self.table_name = 'glysellin_product_property_types'
|
|
4
|
-
attr_accessible :
|
|
4
|
+
attr_accessible :name
|
|
5
5
|
|
|
6
|
-
has_many :properties, class_name: "Glysellin::ProductProperty"
|
|
6
|
+
has_many :properties, class_name: "Glysellin::ProductProperty",
|
|
7
|
+
foreign_key: 'type_id', inverse_of: :type
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
def name
|
|
10
|
+
"hoo"
|
|
11
|
+
end
|
|
10
12
|
end
|
|
11
13
|
end
|
|
@@ -2,7 +2,6 @@ require 'friendly_id'
|
|
|
2
2
|
|
|
3
3
|
module Glysellin
|
|
4
4
|
class Variant < ActiveRecord::Base
|
|
5
|
-
include ProductMethods
|
|
6
5
|
extend FriendlyId
|
|
7
6
|
|
|
8
7
|
friendly_id :name, use: :slugged
|
|
@@ -10,24 +9,28 @@ module Glysellin
|
|
|
10
9
|
self.table_name = 'glysellin_variants'
|
|
11
10
|
|
|
12
11
|
attr_accessible :eot_price, :in_stock, :name, :position, :price,
|
|
13
|
-
:published, :sku, :slug, :unlimited_stock, :
|
|
14
|
-
:
|
|
12
|
+
:published, :sku, :slug, :unlimited_stock, :sellable_id,
|
|
13
|
+
:sellable_type, :properties_attributes, :weight,
|
|
14
|
+
:unmarked_price
|
|
15
15
|
|
|
16
|
-
belongs_to :
|
|
17
|
-
foreign_key: 'product_id'
|
|
16
|
+
belongs_to :sellable, polymorphic: true
|
|
18
17
|
|
|
19
18
|
has_many :properties, class_name: 'Glysellin::ProductProperty',
|
|
20
|
-
|
|
19
|
+
extend: Glysellin::PropertyFinder, dependent: :destroy,
|
|
20
|
+
inverse_of: :variant
|
|
21
21
|
|
|
22
22
|
accepts_nested_attributes_for :properties, allow_destroy: true
|
|
23
23
|
|
|
24
|
-
validates_presence_of :name, if: proc { |
|
|
24
|
+
validates_presence_of :name, if: proc { |variant|
|
|
25
|
+
variant.sellable.variants.length > 1
|
|
26
|
+
}
|
|
27
|
+
|
|
25
28
|
validates_numericality_of :price
|
|
26
29
|
validates_numericality_of :in_stock, if: proc { |v| v.in_stock.presence }
|
|
27
30
|
|
|
28
31
|
before_validation :check_prices
|
|
29
32
|
|
|
30
|
-
after_initialize :prepare_properties
|
|
33
|
+
# after_initialize :prepare_properties
|
|
31
34
|
|
|
32
35
|
AVAILABLE_QUERY = <<-SQL
|
|
33
36
|
glysellin_variants.published = ? AND (
|
|
@@ -37,25 +40,24 @@ module Glysellin
|
|
|
37
40
|
SQL
|
|
38
41
|
|
|
39
42
|
scope :available, where(AVAILABLE_QUERY, true, true, 0)
|
|
43
|
+
scope :published, where(published: true)
|
|
40
44
|
|
|
41
|
-
def prepare_properties
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
end
|
|
45
|
+
# def prepare_properties
|
|
46
|
+
# if product && product.product_type
|
|
47
|
+
# product.product_type.property_types.each do |type|
|
|
48
|
+
# properties.build(type: type) if properties.send(type.name) == false
|
|
49
|
+
# end
|
|
50
|
+
# end
|
|
51
|
+
# end
|
|
48
52
|
|
|
49
53
|
def description
|
|
50
|
-
|
|
54
|
+
sellable.description if sellable.respond_to?(:description)
|
|
51
55
|
end
|
|
52
56
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
end
|
|
57
|
+
delegate :vat_rate, :vat_ratio, to: :sellable
|
|
58
|
+
|
|
56
59
|
|
|
57
60
|
def check_prices
|
|
58
|
-
vat_ratio = self.product.vat_ratio rescue Glysellin.default_vat_rate
|
|
59
61
|
# If we have to fill one of the prices when changed
|
|
60
62
|
if eot_changed_alone?
|
|
61
63
|
self.price = (self.eot_price * vat_ratio).round(2)
|
|
@@ -84,12 +86,12 @@ module Glysellin
|
|
|
84
86
|
end
|
|
85
87
|
|
|
86
88
|
def name fullname = true
|
|
87
|
-
variant_name,
|
|
89
|
+
variant_name, sellable_name = super().presence, (sellable && sellable.name)
|
|
88
90
|
|
|
89
91
|
if fullname
|
|
90
|
-
variant_name ? "#{
|
|
92
|
+
variant_name ? "#{ sellable_name } - #{ variant_name }" : sellable_name
|
|
91
93
|
else
|
|
92
|
-
variant_name ? variant_name :
|
|
94
|
+
variant_name ? variant_name : sellable_name
|
|
93
95
|
end
|
|
94
96
|
end
|
|
95
97
|
|
|
@@ -2,12 +2,19 @@
|
|
|
2
2
|
To implement custom behavior, just replace this view, keeping the .added-to-cart-warning container
|
|
3
3
|
Default behavior is triggered when [data-warning] attribute is present on the container
|
|
4
4
|
%>
|
|
5
|
-
|
|
5
|
+
|
|
6
|
+
<% product = current_cart.product(params[:cart][:product_id]).variant %>
|
|
7
|
+
|
|
8
|
+
<div class="added-to-cart-warning" style="position:fixed;width:400px;height:200px;top:50%;left:50%;margin-left:-200px;margin-top:-140px;border:1px solid #CCC;border-radius:2px;padding:40px;box-shadow:0 0 15px #DDD;z-index:100;background:white;" data-warning>
|
|
6
9
|
<h3><%= t('glysellin.labels.cart.added_to_cart') %></h3>
|
|
7
10
|
<hr>
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
+
<strong>
|
|
12
|
+
<%= (quantity = params[:cart][:quantity].to_i) %> ×
|
|
13
|
+
</strong>
|
|
14
|
+
<%= product.name %> - <%= number_to_currency product.price %>
|
|
15
|
+
<strong style="float:right;">
|
|
16
|
+
<%= number_to_currency (product.price * quantity) %>
|
|
17
|
+
</strong>
|
|
11
18
|
<br>
|
|
12
19
|
|
|
13
20
|
<hr>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
- if sellable.published_variants.length > 0
|
|
2
|
+
= form_tag cart_products_path, class: 'add-to-cart-form', remote: options[:remote], data: { "add-to-cart-form" => true } do
|
|
3
|
+
.product-quantity
|
|
4
|
+
= number_field :cart, :quantity, value: 1
|
|
5
|
+
|
|
6
|
+
.submit-container
|
|
7
|
+
- if sellable.published_variants.length > 1
|
|
8
|
+
= select_tag 'cart[product_id]', variants_options_for(sellable), prompt: t("glysellin.labels.sellables.choose_your_variant"), required: "required"
|
|
9
|
+
- else
|
|
10
|
+
= hidden_field_tag 'cart[product_id]', sellable.published_variants.first.id
|
|
11
|
+
|
|
12
|
+
%button.submit{ type: "submit" }
|
|
13
|
+
= t('glysellin.labels.cart.add_to_cart')
|
|
@@ -78,6 +78,7 @@ en:
|
|
|
78
78
|
back_to_shop: "Back to shop"
|
|
79
79
|
remove_from_cart: "Delete"
|
|
80
80
|
update: "Update cart"
|
|
81
|
+
added_to_cart: "Product added to cart"
|
|
81
82
|
update_discount: "Update discount code"
|
|
82
83
|
create_order_form: "Submit order"
|
|
83
84
|
follow: "Go to order"
|
|
@@ -86,12 +87,12 @@ en:
|
|
|
86
87
|
informations: "Your informations"
|
|
87
88
|
shipping_method: "Shipping method"
|
|
88
89
|
payment_method: "Payment method"
|
|
90
|
+
sellables:
|
|
91
|
+
out_of_stock: "Out of stock"
|
|
92
|
+
choose_your_variant: "--- Choose your product ---"
|
|
89
93
|
orders:
|
|
90
94
|
states:
|
|
91
|
-
|
|
92
|
-
filling_address: "Addresses not filled"
|
|
93
|
-
address: "Addresses filled"
|
|
94
|
-
payment: "Payment method chosen"
|
|
95
|
+
ready: "Payment pending"
|
|
95
96
|
paid: "Paid"
|
|
96
97
|
shipped: "Shipped"
|
|
97
98
|
cart:
|
|
@@ -97,6 +97,9 @@ fr:
|
|
|
97
97
|
informations: "Vos informations"
|
|
98
98
|
shipping_method: "Mode de livraison"
|
|
99
99
|
payment_method: "Mode de paiement"
|
|
100
|
+
sellables:
|
|
101
|
+
out_of_stock: "Épuisé"
|
|
102
|
+
choose_your_variant: "--- Choisissez votre produit ---"
|
|
100
103
|
orders:
|
|
101
104
|
states:
|
|
102
105
|
ready: "Paiement en attente"
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
class RemoveUnusedFieldsFromGlysellinProducts < ActiveRecord::Migration
|
|
2
|
+
def up
|
|
3
|
+
remove_column :glysellin_products, :name, :description, :display_priority,
|
|
4
|
+
:position, :slug, :sku, :published
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def down
|
|
8
|
+
change_table :glysellin_products do |t|
|
|
9
|
+
t.string :name
|
|
10
|
+
t.text :description
|
|
11
|
+
t.integer :display_priority
|
|
12
|
+
t.integer :position
|
|
13
|
+
t.string :slug
|
|
14
|
+
t.string :sku
|
|
15
|
+
t.boolean :published, default: true
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
class RemoveTaxonomiesFromSystem < ActiveRecord::Migration
|
|
2
|
+
def up
|
|
3
|
+
drop_table :glysellin_taxonomies
|
|
4
|
+
drop_table :glysellin_products_taxonomies
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def down
|
|
8
|
+
create_table :glysellin_taxonomies do |t|
|
|
9
|
+
t.string :name
|
|
10
|
+
t.string :slug
|
|
11
|
+
t.integer :parent_taxonomy_id
|
|
12
|
+
|
|
13
|
+
t.timestamps
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
create_table :glysellin_products_taxonomies, :id => false do |t|
|
|
17
|
+
t.integer :product_id
|
|
18
|
+
t.integer :taxonomy_id
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
class MakeVariantsBelongToSellablesAndNotProducts < ActiveRecord::Migration
|
|
2
|
+
def up
|
|
3
|
+
change_table :glysellin_variants do |t|
|
|
4
|
+
t.integer :sellable_id
|
|
5
|
+
t.string :sellable_type
|
|
6
|
+
t.remove :product_id
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def down
|
|
11
|
+
change_table :glysellin_variants do |t|
|
|
12
|
+
t.integer :product_id
|
|
13
|
+
t.remove :sellable_id, :sellable_type
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
class DropProductTypes < ActiveRecord::Migration
|
|
2
|
+
def up
|
|
3
|
+
drop_table :glysellin_product_types
|
|
4
|
+
drop_table :glysellin_product_types_properties
|
|
5
|
+
|
|
6
|
+
remove_column :glysellin_products, :product_type_id
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def down
|
|
10
|
+
create_table :glysellin_product_types_properties, id: false do |t|
|
|
11
|
+
t.references :product_type, :product_property
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
create_table :glysellin_product_types do |t|
|
|
15
|
+
t.string :name
|
|
16
|
+
t.timestamps
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
add_column :glysellin_products, :product_type_id, :integer
|
|
20
|
+
add_column :glysellin_product_types_properties, :product_type_id, :integer
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
class RemoveUnusedProductPropertiesColumns < ActiveRecord::Migration
|
|
2
|
+
def up
|
|
3
|
+
change_table :glysellin_product_properties do |t|
|
|
4
|
+
t.remove :name, :adjustement, :variant_type
|
|
5
|
+
end
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def down
|
|
9
|
+
change_table :glysellin_product_properties do |t|
|
|
10
|
+
t.string :name
|
|
11
|
+
t.decimal :adjustement, :precision => 11, :scale => 2
|
|
12
|
+
t.string :variant_type
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
data/lib/glysellin.rb
CHANGED
|
@@ -5,7 +5,6 @@ require "glysellin/engine"
|
|
|
5
5
|
require "glysellin/helpers"
|
|
6
6
|
require "glysellin/gateway"
|
|
7
7
|
require "glysellin/discount_type_calculator"
|
|
8
|
-
require "glysellin/product_methods"
|
|
9
8
|
require "glysellin/property_finder"
|
|
10
9
|
require "glysellin/products_list"
|
|
11
10
|
require "glysellin/shipping_carrier"
|
data/lib/glysellin/engine.rb
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require 'glysellin/helpers'
|
|
2
|
+
require 'glysellin/sellable'
|
|
2
3
|
require 'glysellin/engine/routes'
|
|
3
4
|
|
|
4
5
|
module Glysellin
|
|
@@ -10,5 +11,11 @@ module Glysellin
|
|
|
10
11
|
end
|
|
11
12
|
end
|
|
12
13
|
|
|
14
|
+
initializer "Mix acts_as_sellable into ActiveRecord::Base" do
|
|
15
|
+
ActiveSupport.on_load :active_record do
|
|
16
|
+
ActiveRecord::Base.send(:include, Sellable)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
13
20
|
end
|
|
14
21
|
end
|
|
@@ -18,16 +18,6 @@ module ActionDispatch::Routing
|
|
|
18
18
|
end
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
-
resources :products, controller: controllers[:products] do
|
|
22
|
-
collection do
|
|
23
|
-
get 'taxonomy/:id', action: "filter", as: "filter"
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
resources :taxonomies, only: [] do
|
|
28
|
-
resources :products, only: [:index]
|
|
29
|
-
end
|
|
30
|
-
|
|
31
21
|
resource :cart, controller: controllers[:cart], only: [:show, :destroy] do
|
|
32
22
|
resources :products, controller: "glysellin/cart/products", only: [:create, :update, :destroy] do
|
|
33
23
|
collection do
|
|
@@ -51,7 +41,6 @@ module ActionDispatch::Routing
|
|
|
51
41
|
def parse_controllers options
|
|
52
42
|
defaults = {
|
|
53
43
|
orders: 'glysellin/orders',
|
|
54
|
-
products: 'glysellin/products',
|
|
55
44
|
cart: 'glysellin/cart'
|
|
56
45
|
}
|
|
57
46
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
module Glysellin
|
|
2
2
|
module PropertyFinder
|
|
3
|
-
def method_missing method, *args
|
|
3
|
+
def method_missing method, *args
|
|
4
4
|
if (prop = find { |prop| prop.type.name == method.to_s })
|
|
5
5
|
prop.value
|
|
6
6
|
elsif Glysellin::ProductPropertyType.select('1').find_by_name(method)
|
|
7
7
|
false
|
|
8
8
|
else
|
|
9
|
-
super
|
|
9
|
+
super
|
|
10
10
|
end
|
|
11
11
|
end
|
|
12
12
|
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
require "glysellin/sellable/simple"
|
|
2
|
+
require "glysellin/sellable/multi"
|
|
3
|
+
|
|
4
|
+
module Glysellin
|
|
5
|
+
module Sellable
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
|
|
8
|
+
module ClassMethods
|
|
9
|
+
|
|
10
|
+
# Macro to include sellable behaviour in side any model
|
|
11
|
+
#
|
|
12
|
+
# @param [Hash] options An option hash to configure the mixin
|
|
13
|
+
#
|
|
14
|
+
# @option options [Symbol] :simple If set to true, sellable will only have
|
|
15
|
+
# one variant, a has_one relation is defined between sellable and the
|
|
16
|
+
# Variant model
|
|
17
|
+
# @option options [Boolean] :stock If set to false, consider every itmes
|
|
18
|
+
# should have unlimited stock. Defaults to true
|
|
19
|
+
#
|
|
20
|
+
def acts_as_sellable options = {}
|
|
21
|
+
# Merge options with defaults and store them for further use
|
|
22
|
+
cattr_accessor :sellable_options
|
|
23
|
+
self.sellable_options = options.reverse_merge(
|
|
24
|
+
simple: false,
|
|
25
|
+
stock: true
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
if sellable_options[:simple]
|
|
29
|
+
include Sellable::Simple
|
|
30
|
+
else
|
|
31
|
+
include Sellable::Multi
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Defines the polymorphic has_one association with the
|
|
35
|
+
# Glysellin::Product model, holding product wide configurations
|
|
36
|
+
has_one :product, as: :sellable, class_name: "Glysellin::Product",
|
|
37
|
+
inverse_of: :sellable, dependent: :destroy
|
|
38
|
+
accepts_nested_attributes_for :product, allow_destroy: true
|
|
39
|
+
attr_accessible :product_attributes
|
|
40
|
+
|
|
41
|
+
unless sellable_options[:stock]
|
|
42
|
+
before_validation :ensure_unlimited_stock
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Attributes delegation. Allowing to consider Product as a simple
|
|
46
|
+
# configuration model for the sellable one.
|
|
47
|
+
#
|
|
48
|
+
delegate :vat_rate, :vat_ratio, to: :product
|
|
49
|
+
|
|
50
|
+
# delegate :price, :unmarked_price, :marked_down?, to: :master_variant
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# If acts_as_sellable is called with the option `stock: false`, we admit
|
|
55
|
+
# every variant must be unlimited stock, so admins never have to bother
|
|
56
|
+
# filling in stock or selecting `unlimited_stock: true`
|
|
57
|
+
#
|
|
58
|
+
def ensure_unlimited_stock
|
|
59
|
+
variants.each do |variant|
|
|
60
|
+
variant.unlimited_stock = true
|
|
61
|
+
variant.save unless variant.new_record?
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def published_variants
|
|
66
|
+
variants.published
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module Glysellin
|
|
2
|
+
module Sellable
|
|
3
|
+
module Multi
|
|
4
|
+
extend ActiveSupport::Concern
|
|
5
|
+
|
|
6
|
+
included do
|
|
7
|
+
has_many :variants, as: :sellable, class_name: "Glysellin::Variant",
|
|
8
|
+
inverse_of: :sellable, dependent: :destroy
|
|
9
|
+
accepts_nested_attributes_for :variants, allow_destroy: true,
|
|
10
|
+
reject_if: :all_blank
|
|
11
|
+
attr_accessible :variants_attributes
|
|
12
|
+
|
|
13
|
+
# Published sellables are the ones that have at least one variant
|
|
14
|
+
# published.
|
|
15
|
+
#
|
|
16
|
+
# This behaviour can be overriden inside the sellable's model if the
|
|
17
|
+
# scope is declared after the `acts_as_sellable` call
|
|
18
|
+
scope :published, -> {
|
|
19
|
+
includes(:variants).where(glysellin_variants: { published: true })
|
|
20
|
+
}
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module Glysellin
|
|
2
|
+
module Sellable
|
|
3
|
+
module Simple
|
|
4
|
+
extend ActiveSupport::Concern
|
|
5
|
+
|
|
6
|
+
included do
|
|
7
|
+
has_one :variant, as: :sellable, class_name: "Glysellin::Variant",
|
|
8
|
+
inverse_of: :sellable, dependent: :destroy
|
|
9
|
+
accepts_nested_attributes_for :variant, allow_destroy: true,
|
|
10
|
+
reject_if: :all_blank
|
|
11
|
+
attr_accessible :variant_attributes
|
|
12
|
+
|
|
13
|
+
# Published sellables are the ones that have at least one variant
|
|
14
|
+
# published.
|
|
15
|
+
#
|
|
16
|
+
# This behaviour can be overriden inside the sellable's model if the
|
|
17
|
+
# scope is declared after the `acts_as_sellable` call
|
|
18
|
+
scope :published, -> {
|
|
19
|
+
includes(:variant).where( glysellin_variants: { published: true })
|
|
20
|
+
}
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Fetches variant wrapping it in an ActiveRecord::Relation object to
|
|
24
|
+
# make behavior consistent with sellables in Multi mode
|
|
25
|
+
def variants
|
|
26
|
+
Variant.where(sellable_id: id, sellable_type: self.class.to_s)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
data/lib/glysellin/version.rb
CHANGED
|
@@ -5,7 +5,7 @@ namespace :glysellin do
|
|
|
5
5
|
task :seed => :environment do
|
|
6
6
|
[['Chèque', 'check'],
|
|
7
7
|
['Paypal', 'paypal-integral'],
|
|
8
|
-
['
|
|
8
|
+
['Carte bancaire', 'atos']].each do |payment_method|
|
|
9
9
|
attributes = Hash[[:name, :slug].zip(payment_method)]
|
|
10
10
|
Glysellin::PaymentMethod.create(attributes)
|
|
11
11
|
puts "Created payment method : #{ attributes[:name] }"
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: glysellin
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.4.1
|
|
4
|
+
version: 0.4.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Valentin Ballestrino
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2013-06-
|
|
11
|
+
date: 2013-06-12 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|
|
@@ -161,7 +161,6 @@ files:
|
|
|
161
161
|
- app/controllers/glysellin/cart/state_controller.rb
|
|
162
162
|
- app/controllers/glysellin/cart_controller.rb
|
|
163
163
|
- app/controllers/glysellin/orders_controller.rb
|
|
164
|
-
- app/controllers/glysellin/products_controller.rb
|
|
165
164
|
- app/helpers/glysellin/application_helper.rb
|
|
166
165
|
- app/helpers/glysellin/cart_helper.rb
|
|
167
166
|
- app/helpers/glysellin/orders_helper.rb
|
|
@@ -172,9 +171,9 @@ files:
|
|
|
172
171
|
- app/models/glysellin/brand.rb
|
|
173
172
|
- app/models/glysellin/discount_code.rb
|
|
174
173
|
- app/models/glysellin/discount_type.rb
|
|
174
|
+
- app/models/glysellin/line_item.rb
|
|
175
175
|
- app/models/glysellin/order.rb
|
|
176
176
|
- app/models/glysellin/order_adjustment.rb
|
|
177
|
-
- app/models/glysellin/order_item.rb
|
|
178
177
|
- app/models/glysellin/orderer.rb
|
|
179
178
|
- app/models/glysellin/payment.rb
|
|
180
179
|
- app/models/glysellin/payment_method.rb
|
|
@@ -182,9 +181,7 @@ files:
|
|
|
182
181
|
- app/models/glysellin/product_image.rb
|
|
183
182
|
- app/models/glysellin/product_property.rb
|
|
184
183
|
- app/models/glysellin/product_property_type.rb
|
|
185
|
-
- app/models/glysellin/product_type.rb
|
|
186
184
|
- app/models/glysellin/shipping_method.rb
|
|
187
|
-
- app/models/glysellin/taxonomy.rb
|
|
188
185
|
- app/models/glysellin/variant.rb
|
|
189
186
|
- app/views/glysellin/cart/_added_to_cart_warning.html.erb
|
|
190
187
|
- app/views/glysellin/cart/_cart.html.erb
|
|
@@ -214,11 +211,7 @@ files:
|
|
|
214
211
|
- app/views/glysellin/orders/_payment_successful.html.erb
|
|
215
212
|
- app/views/glysellin/orders/payment_response.html.erb
|
|
216
213
|
- app/views/glysellin/payment_methods/_paypal-integral.html.erb
|
|
217
|
-
- app/views/glysellin/products/_add_to_cart.html.
|
|
218
|
-
- app/views/glysellin/products/_item.html.erb
|
|
219
|
-
- app/views/glysellin/products/filter.html.erb
|
|
220
|
-
- app/views/glysellin/products/index.html.erb
|
|
221
|
-
- app/views/glysellin/products/show.html.erb
|
|
214
|
+
- app/views/glysellin/products/_add_to_cart.html.haml
|
|
222
215
|
- app/views/glysellin/shared/_address.html.erb
|
|
223
216
|
- app/views/glysellin/shared/_address.text.erb
|
|
224
217
|
- app/views/glysellin/shared/_order.text.erb
|
|
@@ -261,6 +254,15 @@ files:
|
|
|
261
254
|
- db/migrate/20130311135842_add_addressable_to_glysellin_addresses.rb
|
|
262
255
|
- db/migrate/20130314114048_change_addressable_associations_in_glysellin_addresses.rb
|
|
263
256
|
- db/migrate/20130325113903_remove_address_ids_from_glysellin_orders.rb
|
|
257
|
+
- db/migrate/20130609013900_add_sellable_references_to_glysellin_products.rb
|
|
258
|
+
- db/migrate/20130609023300_remove_unused_fields_from_glysellin_products.rb
|
|
259
|
+
- db/migrate/20130609025800_remove_taxonomies_from_system.rb
|
|
260
|
+
- db/migrate/20130609040600_rename_order_items_to_line_items.rb
|
|
261
|
+
- db/migrate/20130609142100_add_variant_id_to_glysellin_line_items.rb
|
|
262
|
+
- db/migrate/20130609155600_make_variants_belong_to_sellables_and_not_products.rb
|
|
263
|
+
- db/migrate/20130609193600_drop_product_types.rb
|
|
264
|
+
- db/migrate/20130609200000_remove_unused_product_properties_columns.rb
|
|
265
|
+
- db/migrate/20130609200700_remove_position_from_glysellin_variants.rb
|
|
264
266
|
- db/seeds/shipping_carrier/rates/colissimo.csv
|
|
265
267
|
- db/seeds/shipping_carrier/rates/lettre-max.csv
|
|
266
268
|
- lib/active_model/model.rb
|
|
@@ -269,7 +271,6 @@ files:
|
|
|
269
271
|
- lib/generators/glysellin/install/templates/initializer.rb
|
|
270
272
|
- lib/generators/glysellin/install/templates/order_observer.rb
|
|
271
273
|
- lib/generators/glysellin/install/utils.rb
|
|
272
|
-
- lib/glysellin/acts_as_sellable.rb
|
|
273
274
|
- lib/glysellin/cart/address.rb
|
|
274
275
|
- lib/glysellin/cart/adjustment/base.rb
|
|
275
276
|
- lib/glysellin/cart/adjustment/discount_code.rb
|
|
@@ -299,9 +300,11 @@ files:
|
|
|
299
300
|
- lib/glysellin/helpers/countries.rb
|
|
300
301
|
- lib/glysellin/helpers/views.rb
|
|
301
302
|
- lib/glysellin/helpers.rb
|
|
302
|
-
- lib/glysellin/product_methods.rb
|
|
303
303
|
- lib/glysellin/products_list.rb
|
|
304
304
|
- lib/glysellin/property_finder.rb
|
|
305
|
+
- lib/glysellin/sellable/multi.rb
|
|
306
|
+
- lib/glysellin/sellable/simple.rb
|
|
307
|
+
- lib/glysellin/sellable.rb
|
|
305
308
|
- lib/glysellin/shipping_carrier/base.rb
|
|
306
309
|
- lib/glysellin/shipping_carrier/colissimo.rb
|
|
307
310
|
- lib/glysellin/shipping_carrier/flat_rate.rb
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
module Glysellin
|
|
2
|
-
class ProductsController < ApplicationController
|
|
3
|
-
def index
|
|
4
|
-
@products = Glysellin::Product.order('created_at DESC').limit(10)
|
|
5
|
-
@products = @products.with_taxonomy(params[:taxonomy_id]) if params[:taxonomy_id]
|
|
6
|
-
end
|
|
7
|
-
|
|
8
|
-
def show
|
|
9
|
-
@product = Glysellin::Product.find(params[:id])
|
|
10
|
-
end
|
|
11
|
-
end
|
|
12
|
-
end
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
class Glysellin::ProductType < ActiveRecord::Base
|
|
2
|
-
self.table_name = 'glysellin_product_types'
|
|
3
|
-
|
|
4
|
-
has_and_belongs_to_many :property_types,
|
|
5
|
-
class_name: 'Glysellin::ProductPropertyType',
|
|
6
|
-
join_table: 'glysellin_product_types_property_types'
|
|
7
|
-
|
|
8
|
-
has_many :products
|
|
9
|
-
|
|
10
|
-
attr_accessible :name, :product_ids, :property_type_ids
|
|
11
|
-
end
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
module Glysellin
|
|
2
|
-
class Taxonomy < ActiveRecord::Base
|
|
3
|
-
extend FriendlyId
|
|
4
|
-
|
|
5
|
-
self.table_name = 'glysellin_taxonomies'
|
|
6
|
-
|
|
7
|
-
friendly_id :name, use: :slugged
|
|
8
|
-
|
|
9
|
-
has_and_belongs_to_many :products,
|
|
10
|
-
join_table: 'glysellin_products_taxonomies'
|
|
11
|
-
has_many :sub_taxonomies, class_name: 'Taxonomy',
|
|
12
|
-
foreign_key: 'parent_taxonomy_id'
|
|
13
|
-
belongs_to :parent_taxonomy, foreign_key: 'parent_taxonomy_id',
|
|
14
|
-
class_name: 'Taxonomy'
|
|
15
|
-
|
|
16
|
-
attr_accessible :name, :parent_taxonomy, :sub_taxonomies, :products,
|
|
17
|
-
:product_ids, :sub_taxonomy_ids, :parent_taxonomy_id
|
|
18
|
-
|
|
19
|
-
def all_products
|
|
20
|
-
Product.includes(:taxonomies).where(
|
|
21
|
-
'glysellin_products_taxonomies.taxonomy_id IN (?)',
|
|
22
|
-
taxonomy_tree_ids
|
|
23
|
-
)
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def taxonomy_tree_ids
|
|
27
|
-
if sub_taxonomies.length > 0
|
|
28
|
-
ts = sub_taxonomies.includes(:sub_taxonomies).map(&:taxonomy_tree_ids)
|
|
29
|
-
ts.flatten << self.id
|
|
30
|
-
else
|
|
31
|
-
self.id
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
end
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
<%= form_tag cart_products_path, class: 'add-to-cart-form', remote: options[:remote], data: { "add-to-cart-form" => true } do %>
|
|
2
|
-
<div class="product-quantity">
|
|
3
|
-
<%= number_field :cart, :quantity, value: 1 %>
|
|
4
|
-
</div>
|
|
5
|
-
<div class="submit-container">
|
|
6
|
-
<% if product.variants.length > 1 %>
|
|
7
|
-
<%= select_tag 'cart[product_id]', options_for_select(product.variants.collect {|v| [ v.name, v.id ] }) %>
|
|
8
|
-
<% else %>
|
|
9
|
-
<%= hidden_field_tag 'cart[product_id]', product.variants.first.id %>
|
|
10
|
-
<% end %>
|
|
11
|
-
|
|
12
|
-
<button class="submit" type="submit">
|
|
13
|
-
<%= t('glysellin.labels.cart.add_to_cart') %>
|
|
14
|
-
</button>
|
|
15
|
-
</div>
|
|
16
|
-
<% end %>
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
<div class="product-container">
|
|
2
|
-
<span class="name">
|
|
3
|
-
<%= link_to product.name, product_path(product) %>
|
|
4
|
-
</span>
|
|
5
|
-
<% if product.image %>
|
|
6
|
-
<div class="image">
|
|
7
|
-
<%= image_tag product.image.url(:thumb) %>
|
|
8
|
-
</div>
|
|
9
|
-
<% end %>
|
|
10
|
-
<div class="description">
|
|
11
|
-
<%= product.description %>
|
|
12
|
-
</div>
|
|
13
|
-
|
|
14
|
-
<div class="buying-infos">
|
|
15
|
-
<span class="price">
|
|
16
|
-
<%= number_to_currency(product.price) %>
|
|
17
|
-
</span>
|
|
18
|
-
|
|
19
|
-
<%= add_to_cart_form(product) %>
|
|
20
|
-
</div>
|
|
21
|
-
</div>
|
|
File without changes
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
module Glysellin
|
|
2
|
-
module ActsAsSellable
|
|
3
|
-
extend ActiveSupport::Concern
|
|
4
|
-
|
|
5
|
-
module ClassMethods
|
|
6
|
-
def acts_as_sellable
|
|
7
|
-
has_one :product, :class_name => "::Glysellin::Product", :inverse_of => :item
|
|
8
|
-
accepts_nested_attributes_for :product, :allow_destroy => true
|
|
9
|
-
end
|
|
10
|
-
end
|
|
11
|
-
end
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
::ActiveRecord::Base.send :include, Glysellin::ActsAsSellable
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
module Glysellin
|
|
2
|
-
module ProductMethods
|
|
3
|
-
extend ActiveSupport::Concern
|
|
4
|
-
|
|
5
|
-
module ClassMethods
|
|
6
|
-
attr_writer :bundle_attributes
|
|
7
|
-
|
|
8
|
-
def bundle_attributes
|
|
9
|
-
@bundle_attributes ||= {}
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def bundle_attribute attribute, &block
|
|
13
|
-
# Store block to be called to retrieve
|
|
14
|
-
self.bundle_attributes[attribute.to_sym] = block
|
|
15
|
-
|
|
16
|
-
class_eval <<-CLASS, __FILE__, __LINE__
|
|
17
|
-
def bundle_#{ attribute }
|
|
18
|
-
if bundled_products.length > 0
|
|
19
|
-
self.class.bundle_attributes[:#{ attribute }].call(self)
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def #{ attribute }
|
|
24
|
-
value = super
|
|
25
|
-
value = bundle_#{ attribute } if value == nil
|
|
26
|
-
value
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def #{ attribute }=(value)
|
|
30
|
-
super(value) if value != bundle_#{ attribute }
|
|
31
|
-
end
|
|
32
|
-
CLASS
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
# SKU generation helper
|
|
37
|
-
#
|
|
38
|
-
# @return [String] The generated SKU
|
|
39
|
-
def generate_sku
|
|
40
|
-
# Get last product only selecting id
|
|
41
|
-
last_item = self.class.select(:id).order('id DESC').first
|
|
42
|
-
# Generate SKU from the last product id we got,
|
|
43
|
-
# or appending "1" if there's no product
|
|
44
|
-
sku = (last_item ? (last_item.id + 1).to_s : '1')
|
|
45
|
-
sku += self.name.parameterize
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
# Checks if a product is a bundle of other sub products
|
|
49
|
-
#
|
|
50
|
-
# @return [true, false]
|
|
51
|
-
def bundle?
|
|
52
|
-
false
|
|
53
|
-
# bundled_products.length > 0
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
# Gives calculable vat rate
|
|
57
|
-
#
|
|
58
|
-
# Example :
|
|
59
|
-
# If vat_rate is set to 19.6%, returns back 1.196
|
|
60
|
-
#
|
|
61
|
-
# @return [Float] The processed VAT rate
|
|
62
|
-
def vat_ratio
|
|
63
|
-
1 + vat_rate / 100
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
end
|