solidus_core 2.9.6 → 2.10.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of solidus_core might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/app/models/concerns/spree/user_address_book.rb +2 -2
- data/app/models/spree/address.rb +2 -2
- data/app/models/spree/adjustment.rb +9 -9
- data/app/models/spree/asset.rb +1 -1
- data/app/models/spree/base.rb +0 -2
- data/app/models/spree/calculator.rb +1 -1
- data/app/models/spree/carton.rb +3 -3
- data/app/models/spree/classification.rb +2 -2
- data/app/models/spree/credit_card.rb +2 -2
- data/app/models/spree/customer_return.rb +1 -1
- data/app/models/spree/image/paperclip_attachment.rb +1 -1
- data/app/models/spree/inventory_unit.rb +4 -4
- data/app/models/spree/line_item.rb +3 -3
- data/app/models/spree/line_item_action.rb +2 -2
- data/app/models/spree/log_entry.rb +1 -1
- data/app/models/spree/option_value.rb +1 -1
- data/app/models/spree/option_values_variant.rb +2 -2
- data/app/models/spree/order.rb +8 -25
- data/app/models/spree/order_cancellations.rb +1 -1
- data/app/models/spree/order_contents.rb +2 -2
- data/app/models/spree/order_mutex.rb +1 -1
- data/app/models/spree/order_promotion.rb +3 -3
- data/app/models/spree/order_shipping.rb +1 -1
- data/app/models/spree/order_taxation.rb +1 -1
- data/app/models/spree/payment/processing.rb +1 -1
- data/app/models/spree/payment.rb +4 -4
- data/app/models/spree/payment_capture_event.rb +1 -1
- data/app/models/spree/payment_method/bogus_credit_card.rb +1 -1
- data/app/models/spree/payment_method.rb +3 -0
- data/app/models/spree/payment_source.rb +1 -1
- data/app/models/spree/price.rb +2 -2
- data/app/models/spree/product/scopes.rb +217 -210
- data/app/models/spree/product.rb +2 -2
- data/app/models/spree/product_option_type.rb +2 -2
- data/app/models/spree/product_promotion_rule.rb +2 -2
- data/app/models/spree/product_property.rb +2 -2
- data/app/models/spree/promotion.rb +1 -1
- data/app/models/spree/promotion_action.rb +1 -1
- data/app/models/spree/promotion_code.rb +2 -2
- data/app/models/spree/promotion_code_batch.rb +1 -1
- data/app/models/spree/promotion_rule.rb +1 -1
- data/app/models/spree/promotion_rule_role.rb +2 -2
- data/app/models/spree/promotion_rule_store.rb +2 -2
- data/app/models/spree/promotion_rule_taxon.rb +2 -2
- data/app/models/spree/promotion_rule_user.rb +2 -2
- data/app/models/spree/refund.rb +3 -3
- data/app/models/spree/reimbursement/credit.rb +2 -2
- data/app/models/spree/reimbursement.rb +2 -2
- data/app/models/spree/reimbursement_tax_calculator.rb +1 -1
- data/app/models/spree/return_authorization.rb +3 -3
- data/app/models/spree/return_item.rb +10 -10
- data/app/models/spree/role_user.rb +2 -2
- data/app/models/spree/shipment.rb +3 -3
- data/app/models/spree/shipping_manifest.rb +3 -3
- data/app/models/spree/shipping_method.rb +1 -1
- data/app/models/spree/shipping_method_category.rb +2 -2
- data/app/models/spree/shipping_method_stock_location.rb +2 -2
- data/app/models/spree/shipping_method_zone.rb +2 -2
- data/app/models/spree/shipping_rate.rb +2 -2
- data/app/models/spree/shipping_rate_tax.rb +2 -2
- data/app/models/spree/state.rb +1 -1
- data/app/models/spree/state_change.rb +2 -2
- data/app/models/spree/stock_item.rb +2 -2
- data/app/models/spree/stock_location.rb +2 -2
- data/app/models/spree/stock_movement.rb +2 -2
- data/app/models/spree/store_credit.rb +8 -8
- data/app/models/spree/store_credit_event.rb +3 -3
- data/app/models/spree/store_payment_method.rb +2 -2
- data/app/models/spree/store_shipping_method.rb +2 -2
- data/app/models/spree/tax_rate.rb +1 -1
- data/app/models/spree/tax_rate_tax_category.rb +2 -2
- data/app/models/spree/unit_cancel.rb +5 -2
- data/app/models/spree/user_address.rb +2 -2
- data/app/models/spree/user_stock_location.rb +2 -2
- data/app/models/spree/variant/scopes.rb +37 -29
- data/app/models/spree/variant.rb +1 -1
- data/app/models/spree/variant_property_rule.rb +1 -1
- data/app/models/spree/variant_property_rule_condition.rb +2 -2
- data/app/models/spree/variant_property_rule_value.rb +2 -2
- data/app/models/spree/wallet_payment_source.rb +2 -2
- data/app/models/spree/zone_member.rb +2 -2
- data/config/initializers/inflections.rb +5 -0
- data/config/locales/en.yml +22 -3
- data/lib/generators/spree/dummy/dummy_generator.rb +2 -0
- data/lib/generators/spree/install/install_generator.rb +0 -3
- data/lib/spree/core/controller_helpers/strong_parameters.rb +7 -21
- data/lib/spree/core/environment_extension.rb +0 -9
- data/lib/spree/core/importer/order.rb +3 -4
- data/lib/spree/core/importer/product.rb +2 -2
- data/lib/spree/core/version.rb +1 -1
- data/lib/spree/permission_sets/default_customer.rb +1 -1
- data/lib/spree/permitted_attributes.rb +6 -75
- data/lib/spree/testing_support/dummy_app/rake_tasks.rb +6 -2
- data/solidus_core.gemspec +4 -4
- data/spec/lib/search/base_spec.rb +5 -1
- data/spec/lib/search/variant_spec.rb +1 -1
- data/spec/lib/spree/core/controller_helpers/strong_parameters_spec.rb +1 -8
- data/spec/lib/spree/core/environment_extension_spec.rb +1 -12
- data/spec/lib/spree/event_spec.rb +15 -3
- data/spec/migrate/20190106184413_remove_code_from_spree_promotions_spec.rb +18 -4
- data/spec/models/spree/calculator/refunds/default_refund_amount_spec.rb +1 -1
- data/spec/models/spree/carton_spec.rb +2 -2
- data/spec/models/spree/concerns/user_methods_spec.rb +3 -3
- data/spec/models/spree/credit_card_spec.rb +2 -2
- data/spec/models/spree/customer_return_spec.rb +1 -1
- data/spec/models/spree/order/checkout_spec.rb +1 -1
- data/spec/models/spree/order/outstanding_balance_integration_spec.rb +5 -5
- data/spec/models/spree/order/payment_spec.rb +1 -1
- data/spec/models/spree/order_contents_spec.rb +1 -1
- data/spec/models/spree/order_inventory_spec.rb +3 -3
- data/spec/models/spree/order_shipping_spec.rb +1 -1
- data/spec/models/spree/order_spec.rb +6 -6
- data/spec/models/spree/payment_create_spec.rb +2 -2
- data/spec/models/spree/payment_spec.rb +12 -12
- data/spec/models/spree/promotion/rules/first_repeat_purchase_since_spec.rb +2 -2
- data/spec/models/spree/promotion/rules/nth_order_spec.rb +2 -2
- data/spec/models/spree/promotion/rules/taxon_spec.rb +0 -1
- data/spec/models/spree/promotion_spec.rb +0 -4
- data/spec/models/spree/reimbursement_type/original_payment_spec.rb +2 -2
- data/spec/models/spree/return_item_spec.rb +11 -11
- data/spec/models/spree/shipment_spec.rb +6 -6
- data/spec/models/spree/stock/inventory_units_finalizer_spec.rb +4 -4
- data/spec/models/spree/stock/quantifier_spec.rb +2 -2
- data/spec/models/spree/store_credit_spec.rb +7 -7
- data/spec/models/spree/tax_category_spec.rb +1 -1
- data/spec/models/spree/taxon_spec.rb +2 -2
- data/spec/models/spree/unit_cancel_spec.rb +5 -0
- data/spec/models/spree/user_spec.rb +3 -3
- metadata +32 -32
- data/spec/lib/spree/permitted_attributes_spec.rb +0 -41
@@ -2,159 +2,162 @@
|
|
2
2
|
|
3
3
|
module Spree
|
4
4
|
class Product < Spree::Base
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
module Scopes
|
6
|
+
def self.prepended(base)
|
7
|
+
base.class_eval do
|
8
|
+
cattr_accessor :search_scopes do
|
9
|
+
[]
|
10
|
+
end
|
8
11
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
12
|
+
def self.add_search_scope(name, &block)
|
13
|
+
singleton_class.send(:define_method, name.to_sym, &block)
|
14
|
+
search_scopes << name.to_sym
|
15
|
+
end
|
13
16
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
17
|
+
def self.property_conditions(property)
|
18
|
+
properties = Property.table_name
|
19
|
+
case property
|
20
|
+
when String then { "#{properties}.name" => property }
|
21
|
+
when Property then { "#{properties}.id" => property.id }
|
22
|
+
else { "#{properties}.id" => property.to_i }
|
23
|
+
end
|
24
|
+
end
|
22
25
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
26
|
+
scope :ascend_by_updated_at, -> { order(updated_at: :asc) }
|
27
|
+
scope :descend_by_updated_at, -> { order(updated_at: :desc) }
|
28
|
+
scope :ascend_by_name, -> { order(name: :asc) }
|
29
|
+
scope :descend_by_name, -> { order(name: :desc) }
|
27
30
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
+
add_search_scope :ascend_by_master_price do
|
32
|
+
joins(master: :default_price).order(Spree::Price.arel_table[:amount].asc)
|
33
|
+
end
|
31
34
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
+
add_search_scope :descend_by_master_price do
|
36
|
+
joins(master: :default_price).order(Spree::Price.arel_table[:amount].desc)
|
37
|
+
end
|
35
38
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
+
add_search_scope :price_between do |low, high|
|
40
|
+
joins(master: :default_price).where(Price.table_name => { amount: low..high })
|
41
|
+
end
|
39
42
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
+
add_search_scope :master_price_lte do |price|
|
44
|
+
joins(master: :default_price).where("#{price_table_name}.amount <= ?", price)
|
45
|
+
end
|
43
46
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
+
add_search_scope :master_price_gte do |price|
|
48
|
+
joins(master: :default_price).where("#{price_table_name}.amount >= ?", price)
|
49
|
+
end
|
47
50
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
51
|
+
# This scope selects products in taxon AND all its descendants
|
52
|
+
# If you need products only within one taxon use
|
53
|
+
#
|
54
|
+
# Spree::Product.joins(:taxons).where(Taxon.table_name => { id: taxon.id })
|
55
|
+
#
|
56
|
+
# If you're using count on the result of this scope, you must use the
|
57
|
+
# `:distinct` option as well:
|
58
|
+
#
|
59
|
+
# Spree::Product.in_taxon(taxon).count(distinct: true)
|
60
|
+
#
|
61
|
+
# This is so that the count query is distinct'd:
|
62
|
+
#
|
63
|
+
# SELECT COUNT(DISTINCT "spree_products"."id") ...
|
64
|
+
#
|
65
|
+
# vs.
|
66
|
+
#
|
67
|
+
# SELECT COUNT(*) ...
|
68
|
+
add_search_scope :in_taxon do |taxon|
|
69
|
+
includes(:classifications)
|
70
|
+
.where('spree_products_taxons.taxon_id' => taxon.self_and_descendants.pluck(:id))
|
71
|
+
.select(Spree::Classification.arel_table[:position])
|
72
|
+
.order(Spree::Classification.arel_table[:position].asc)
|
73
|
+
end
|
71
74
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
75
|
+
# This scope selects products in all taxons AND all its descendants
|
76
|
+
# If you need products only within one taxon use
|
77
|
+
#
|
78
|
+
# Spree::Product.taxons_id_eq([x,y])
|
79
|
+
add_search_scope :in_taxons do |*taxons|
|
80
|
+
taxons = get_taxons(taxons)
|
81
|
+
taxons.first ? prepare_taxon_conditions(taxons) : where(nil)
|
82
|
+
end
|
80
83
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
84
|
+
# a scope that finds all products having property specified by name, object or id
|
85
|
+
add_search_scope :with_property do |property|
|
86
|
+
joins(:properties).where(property_conditions(property))
|
87
|
+
end
|
85
88
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
89
|
+
# a simple test for product with a certain property-value pairing
|
90
|
+
# note that it can test for properties with NULL values, but not for absent values
|
91
|
+
add_search_scope :with_property_value do |property, value|
|
92
|
+
joins(:properties)
|
93
|
+
.where("#{Spree::ProductProperty.table_name}.value = ?", value)
|
94
|
+
.where(property_conditions(property))
|
95
|
+
end
|
93
96
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
97
|
+
add_search_scope :with_option do |option|
|
98
|
+
option_types = Spree::OptionType.table_name
|
99
|
+
conditions = case option
|
100
|
+
when String then { "#{option_types}.name" => option }
|
101
|
+
when OptionType then { "#{option_types}.id" => option.id }
|
102
|
+
else { "#{option_types}.id" => option.to_i }
|
103
|
+
end
|
101
104
|
|
102
|
-
|
103
|
-
|
105
|
+
joins(:option_types).where(conditions)
|
106
|
+
end
|
104
107
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
108
|
+
add_search_scope :with_option_value do |option, value|
|
109
|
+
option_values = Spree::OptionValue.table_name
|
110
|
+
option_type_id = case option
|
111
|
+
when String then Spree::OptionType.find_by(name: option) || option.to_i
|
112
|
+
when Spree::OptionType then option.id
|
113
|
+
else option.to_i
|
114
|
+
end
|
112
115
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
+
conditions = "#{option_values}.name = ? AND #{option_values}.option_type_id = ?", value, option_type_id
|
117
|
+
group('spree_products.id').joins(variants_including_master: :option_values).where(conditions)
|
118
|
+
end
|
116
119
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
120
|
+
# Finds all products which have either:
|
121
|
+
# 1) have an option value with the name matching the one given
|
122
|
+
# 2) have a product property with a value matching the one given
|
123
|
+
add_search_scope :with do |value|
|
124
|
+
includes(variants_including_master: :option_values).
|
125
|
+
includes(:product_properties).
|
126
|
+
where("#{Spree::OptionValue.table_name}.name = ? OR #{Spree::ProductProperty.table_name}.value = ?", value, value)
|
127
|
+
end
|
125
128
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
129
|
+
# Finds all products that have a name containing the given words.
|
130
|
+
add_search_scope :in_name do |words|
|
131
|
+
like_any([:name], prepare_words(words))
|
132
|
+
end
|
130
133
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
134
|
+
# Finds all products that have a name or meta_keywords containing the given words.
|
135
|
+
add_search_scope :in_name_or_keywords do |words|
|
136
|
+
like_any([:name, :meta_keywords], prepare_words(words))
|
137
|
+
end
|
135
138
|
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
139
|
+
# Finds all products that have a name, description, meta_description or meta_keywords containing the given keywords.
|
140
|
+
add_search_scope :in_name_or_description do |words|
|
141
|
+
like_any([:name, :description, :meta_description, :meta_keywords], prepare_words(words))
|
142
|
+
end
|
140
143
|
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
144
|
+
# Finds all products that have the ids matching the given collection of ids.
|
145
|
+
# Alternatively, you could use find(collection_of_ids), but that would raise an exception if one product couldn't be found
|
146
|
+
add_search_scope :with_ids do |*ids|
|
147
|
+
where(id: ids)
|
148
|
+
end
|
146
149
|
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
150
|
+
# Sorts products from most popular (popularity is extracted from how many
|
151
|
+
# times use has put product in cart, not completed orders)
|
152
|
+
#
|
153
|
+
# there is alternative faster and more elegant solution, it has small drawback though,
|
154
|
+
# it doesn stack with other scopes :/
|
155
|
+
#
|
156
|
+
# joins: "LEFT OUTER JOIN (SELECT line_items.variant_id as vid, COUNT(*) as cnt FROM line_items GROUP BY line_items.variant_id) AS popularity_count ON variants.id = vid",
|
157
|
+
# order: 'COALESCE(cnt, 0) DESC'
|
158
|
+
add_search_scope :descend_by_popularity do
|
159
|
+
joins(:master).
|
160
|
+
order(%{
|
158
161
|
COALESCE((
|
159
162
|
SELECT
|
160
163
|
COUNT(#{Spree::LineItem.quoted_table_name}.id)
|
@@ -168,93 +171,97 @@ module Spree
|
|
168
171
|
popular_variants.product_id = #{Spree::Product.quoted_table_name}.id
|
169
172
|
), 0) DESC
|
170
173
|
})
|
171
|
-
|
172
|
-
|
173
|
-
add_search_scope :not_deleted do
|
174
|
-
where("#{Spree::Product.quoted_table_name}.deleted_at IS NULL or #{Spree::Product.quoted_table_name}.deleted_at >= ?", Time.current)
|
175
|
-
end
|
176
|
-
|
177
|
-
scope :with_master_price, -> do
|
178
|
-
joins(:master).where(Spree::Price.where(Spree::Variant.arel_table[:id].eq(Spree::Price.arel_table[:variant_id])).arel.exists)
|
179
|
-
end
|
180
|
-
|
181
|
-
# Can't use add_search_scope for this as it needs a default argument
|
182
|
-
def self.available(available_on = nil)
|
183
|
-
with_master_price.where("#{Spree::Product.quoted_table_name}.available_on <= ?", available_on || Time.current)
|
184
|
-
end
|
185
|
-
search_scopes << :available
|
186
|
-
|
187
|
-
add_search_scope :taxons_name_eq do |name|
|
188
|
-
group("spree_products.id").joins(:taxons).where(Spree::Taxon.arel_table[:name].eq(name))
|
189
|
-
end
|
190
|
-
|
191
|
-
def self.with_variant_sku_cont(sku)
|
192
|
-
sku_match = "%#{sku}%"
|
193
|
-
variant_table = Spree::Variant.arel_table
|
194
|
-
subquery = Spree::Variant.where(variant_table[:sku].matches(sku_match).and(variant_table[:product_id].eq(arel_table[:id])))
|
195
|
-
where(subquery.arel.exists)
|
196
|
-
end
|
174
|
+
end
|
197
175
|
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
sort_column = sort_order.split(" ").first
|
202
|
-
|
203
|
-
# Postgres will complain when using ordering by expressions not present in
|
204
|
-
# SELECT DISTINCT. e.g.
|
205
|
-
#
|
206
|
-
# PG::InvalidColumnReference: ERROR: for SELECT DISTINCT, ORDER BY
|
207
|
-
# expressions must appear in select list. e.g.
|
208
|
-
#
|
209
|
-
# SELECT DISTINCT "spree_products".* FROM "spree_products" LEFT OUTER JOIN
|
210
|
-
# "spree_variants" ON "spree_variants"."product_id" = "spree_products"."id" AND "spree_variants"."is_master" = 't'
|
211
|
-
# AND "spree_variants"."deleted_at" IS NULL LEFT OUTER JOIN "spree_prices" ON
|
212
|
-
# "spree_prices"."variant_id" = "spree_variants"."id" AND "spree_prices"."currency" = 'USD'
|
213
|
-
# AND "spree_prices"."deleted_at" IS NULL WHERE "spree_products"."deleted_at" IS NULL AND ('t'='t')
|
214
|
-
# ORDER BY "spree_prices"."amount" ASC LIMIT 10 OFFSET 0
|
215
|
-
#
|
216
|
-
# Don't allow sort_column, a variable coming from params,
|
217
|
-
# to be anything but a column in the database
|
218
|
-
if ActiveRecord::Base.connection.adapter_name == 'PostgreSQL' && !column_names.include?(sort_column)
|
219
|
-
all
|
220
|
-
else
|
221
|
-
distinct
|
222
|
-
end
|
223
|
-
end
|
176
|
+
add_search_scope :not_deleted do
|
177
|
+
where("#{Spree::Product.quoted_table_name}.deleted_at IS NULL or #{Spree::Product.quoted_table_name}.deleted_at >= ?", Time.current)
|
178
|
+
end
|
224
179
|
|
225
|
-
|
226
|
-
|
180
|
+
scope :with_master_price, -> do
|
181
|
+
joins(:master).where(Spree::Price.where(Spree::Variant.arel_table[:id].eq(Spree::Price.arel_table[:variant_id])).arel.exists)
|
182
|
+
end
|
183
|
+
# Can't use add_search_scope for this as it needs a default argument
|
184
|
+
def self.available(available_on = nil)
|
185
|
+
with_master_price.where("#{Spree::Product.quoted_table_name}.available_on <= ?", available_on || Time.current)
|
186
|
+
end
|
187
|
+
search_scopes << :available
|
227
188
|
|
228
|
-
|
229
|
-
|
230
|
-
|
189
|
+
add_search_scope :taxons_name_eq do |name|
|
190
|
+
group("spree_products.id").joins(:taxons).where(Spree::Taxon.arel_table[:name].eq(name))
|
191
|
+
end
|
231
192
|
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
193
|
+
def self.with_variant_sku_cont(sku)
|
194
|
+
sku_match = "%#{sku}%"
|
195
|
+
variant_table = Spree::Variant.arel_table
|
196
|
+
subquery = Spree::Variant.where(variant_table[:sku].matches(sku_match).and(variant_table[:product_id].eq(arel_table[:id])))
|
197
|
+
where(subquery.arel.exists)
|
198
|
+
end
|
237
199
|
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
200
|
+
def self.distinct_by_product_ids(sort_order = nil)
|
201
|
+
Spree::Deprecation.warn "Product.distinct_by_product_ids is deprecated and should not be used"
|
202
|
+
|
203
|
+
sort_column = sort_order.split(" ").first
|
204
|
+
|
205
|
+
# Postgres will complain when using ordering by expressions not present in
|
206
|
+
# SELECT DISTINCT. e.g.
|
207
|
+
#
|
208
|
+
# PG::InvalidColumnReference: ERROR: for SELECT DISTINCT, ORDER BY
|
209
|
+
# expressions must appear in select list. e.g.
|
210
|
+
#
|
211
|
+
# SELECT DISTINCT "spree_products".* FROM "spree_products" LEFT OUTER JOIN
|
212
|
+
# "spree_variants" ON "spree_variants"."product_id" = "spree_products"."id" AND "spree_variants"."is_master" = 't'
|
213
|
+
# AND "spree_variants"."deleted_at" IS NULL LEFT OUTER JOIN "spree_prices" ON
|
214
|
+
# "spree_prices"."variant_id" = "spree_variants"."id" AND "spree_prices"."currency" = 'USD'
|
215
|
+
# AND "spree_prices"."deleted_at" IS NULL WHERE "spree_products"."deleted_at" IS NULL AND ('t'='t')
|
216
|
+
# ORDER BY "spree_prices"."amount" ASC LIMIT 10 OFFSET 0
|
217
|
+
#
|
218
|
+
# Don't allow sort_column, a variable coming from params,
|
219
|
+
# to be anything but a column in the database
|
220
|
+
if ActiveRecord::Base.connection.adapter_name == 'PostgreSQL' && !column_names.include?(sort_column)
|
221
|
+
all
|
222
|
+
else
|
223
|
+
distinct
|
224
|
+
end
|
225
|
+
end
|
245
226
|
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
227
|
+
class << self
|
228
|
+
private
|
229
|
+
|
230
|
+
def price_table_name
|
231
|
+
Spree::Price.quoted_table_name
|
232
|
+
end
|
233
|
+
|
234
|
+
# specifically avoid having an order for taxon search (conflicts with main order)
|
235
|
+
def prepare_taxon_conditions(taxons)
|
236
|
+
ids = taxons.map { |taxon| taxon.self_and_descendants.pluck(:id) }.flatten.uniq
|
237
|
+
joins(:taxons).where("#{Spree::Taxon.table_name}.id" => ids)
|
238
|
+
end
|
239
|
+
|
240
|
+
# Produce an array of keywords for use in scopes.
|
241
|
+
# Always return array with at least an empty string to avoid SQL errors
|
242
|
+
def prepare_words(words)
|
243
|
+
return [''] if words.blank?
|
244
|
+
a = words.split(/[,\s]/).map(&:strip)
|
245
|
+
a.any? ? a : ['']
|
246
|
+
end
|
247
|
+
|
248
|
+
def get_taxons(*ids_or_records_or_names)
|
249
|
+
taxons = Spree::Taxon.table_name
|
250
|
+
ids_or_records_or_names.flatten.map { |t|
|
251
|
+
case t
|
252
|
+
when Integer then Spree::Taxon.find_by(id: t)
|
253
|
+
when ActiveRecord::Base then t
|
254
|
+
when String
|
255
|
+
Spree::Taxon.find_by(name: t) ||
|
256
|
+
Spree::Taxon.where("#{taxons}.permalink LIKE ? OR #{taxons}.permalink = ?", "%/#{t}/", "#{t}/").first
|
257
|
+
end
|
258
|
+
}.compact.flatten.uniq
|
259
|
+
end
|
255
260
|
end
|
256
|
-
|
261
|
+
end
|
257
262
|
end
|
263
|
+
|
264
|
+
::Spree::Product.prepend self
|
258
265
|
end
|
259
266
|
end
|
260
267
|
end
|
data/app/models/spree/product.rb
CHANGED
@@ -44,8 +44,8 @@ module Spree
|
|
44
44
|
has_many :product_promotion_rules, dependent: :destroy
|
45
45
|
has_many :promotion_rules, through: :product_promotion_rules
|
46
46
|
|
47
|
-
belongs_to :tax_category, class_name: 'Spree::TaxCategory'
|
48
|
-
belongs_to :shipping_category, class_name: 'Spree::ShippingCategory', inverse_of: :products
|
47
|
+
belongs_to :tax_category, class_name: 'Spree::TaxCategory', optional: true
|
48
|
+
belongs_to :shipping_category, class_name: 'Spree::ShippingCategory', inverse_of: :products, optional: true
|
49
49
|
|
50
50
|
has_one :master,
|
51
51
|
-> { where(is_master: true).with_deleted },
|
@@ -2,8 +2,8 @@
|
|
2
2
|
|
3
3
|
module Spree
|
4
4
|
class ProductOptionType < Spree::Base
|
5
|
-
belongs_to :product, class_name: 'Spree::Product', inverse_of: :product_option_types, touch: true
|
6
|
-
belongs_to :option_type, class_name: 'Spree::OptionType', inverse_of: :product_option_types
|
5
|
+
belongs_to :product, class_name: 'Spree::Product', inverse_of: :product_option_types, touch: true, optional: true
|
6
|
+
belongs_to :option_type, class_name: 'Spree::OptionType', inverse_of: :product_option_types, optional: true
|
7
7
|
acts_as_list scope: :product
|
8
8
|
end
|
9
9
|
end
|
@@ -6,8 +6,8 @@ module Spree
|
|
6
6
|
|
7
7
|
acts_as_list scope: :product
|
8
8
|
|
9
|
-
belongs_to :product, touch: true, class_name: 'Spree::Product', inverse_of: :product_properties
|
10
|
-
belongs_to :property, class_name: 'Spree::Property', inverse_of: :product_properties
|
9
|
+
belongs_to :product, touch: true, class_name: 'Spree::Product', inverse_of: :product_properties, optional: true
|
10
|
+
belongs_to :property, class_name: 'Spree::Property', inverse_of: :product_properties, optional: true
|
11
11
|
|
12
12
|
self.whitelisted_ransackable_attributes = ['value']
|
13
13
|
end
|
@@ -7,7 +7,7 @@ module Spree
|
|
7
7
|
|
8
8
|
attr_reader :eligibility_errors
|
9
9
|
|
10
|
-
belongs_to :promotion_category
|
10
|
+
belongs_to :promotion_category, optional: true
|
11
11
|
|
12
12
|
has_many :promotion_rules, autosave: true, dependent: :destroy, inverse_of: :promotion
|
13
13
|
alias_method :rules, :promotion_rules
|
@@ -14,7 +14,7 @@ module Spree
|
|
14
14
|
include Discard::Model
|
15
15
|
self.discard_column = :deleted_at
|
16
16
|
|
17
|
-
belongs_to :promotion, class_name: 'Spree::Promotion', inverse_of: :promotion_actions
|
17
|
+
belongs_to :promotion, class_name: 'Spree::Promotion', inverse_of: :promotion_actions, optional: true
|
18
18
|
|
19
19
|
scope :of_type, ->(t) { where(type: Array.wrap(t).map(&:to_s)) }
|
20
20
|
scope :shipping, -> { of_type(Spree::Config.environment.promotions.shipping_actions.to_a) }
|
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
class Spree::PromotionCode < Spree::Base
|
4
|
-
belongs_to :promotion, inverse_of: :codes
|
5
|
-
belongs_to :promotion_code_batch, class_name: "Spree::PromotionCodeBatch"
|
4
|
+
belongs_to :promotion, inverse_of: :codes, optional: true
|
5
|
+
belongs_to :promotion_code_batch, class_name: "Spree::PromotionCodeBatch", optional: true
|
6
6
|
has_many :adjustments
|
7
7
|
|
8
8
|
validates :value, presence: true, uniqueness: { allow_blank: true }
|
@@ -5,7 +5,7 @@ module Spree
|
|
5
5
|
class CantProcessStartedBatch < StandardError
|
6
6
|
end
|
7
7
|
|
8
|
-
belongs_to :promotion, class_name: "Spree::Promotion"
|
8
|
+
belongs_to :promotion, class_name: "Spree::Promotion", optional: true
|
9
9
|
has_many :promotion_codes, class_name: "Spree::PromotionCode", dependent: :destroy
|
10
10
|
|
11
11
|
validates :number_of_codes, numericality: { greater_than: 0 }
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module Spree
|
4
4
|
# Base class for all promotion rules
|
5
5
|
class PromotionRule < Spree::Base
|
6
|
-
belongs_to :promotion, class_name: 'Spree::Promotion', inverse_of: :promotion_rules
|
6
|
+
belongs_to :promotion, class_name: 'Spree::Promotion', inverse_of: :promotion_rules, optional: true
|
7
7
|
|
8
8
|
scope :of_type, ->(t) { where(type: t) }
|
9
9
|
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module Spree
|
4
4
|
class PromotionRuleRole < ActiveRecord::Base
|
5
|
-
belongs_to :promotion_rule, class_name: 'Spree::PromotionRule'
|
6
|
-
belongs_to :role, class_name: 'Spree::Role'
|
5
|
+
belongs_to :promotion_rule, class_name: 'Spree::PromotionRule', optional: true
|
6
|
+
belongs_to :role, class_name: 'Spree::Role', optional: true
|
7
7
|
end
|
8
8
|
end
|
@@ -4,7 +4,7 @@ module Spree
|
|
4
4
|
class PromotionRuleStore < Spree::Base
|
5
5
|
self.table_name = "spree_promotion_rules_stores"
|
6
6
|
|
7
|
-
belongs_to :promotion_rule, class_name: "Spree::PromotionRule"
|
8
|
-
belongs_to :store, class_name: "Spree::Store"
|
7
|
+
belongs_to :promotion_rule, class_name: "Spree::PromotionRule", optional: true
|
8
|
+
belongs_to :store, class_name: "Spree::Store", optional: true
|
9
9
|
end
|
10
10
|
end
|
@@ -4,7 +4,7 @@ module Spree
|
|
4
4
|
class PromotionRuleUser < Spree::Base
|
5
5
|
self.table_name = 'spree_promotion_rules_users'
|
6
6
|
|
7
|
-
belongs_to :promotion_rule, class_name: 'Spree::PromotionRule'
|
8
|
-
belongs_to :user, class_name: Spree::UserClassHandle.new
|
7
|
+
belongs_to :promotion_rule, class_name: 'Spree::PromotionRule', optional: true
|
8
|
+
belongs_to :user, class_name: Spree::UserClassHandle.new, optional: true
|
9
9
|
end
|
10
10
|
end
|
data/app/models/spree/refund.rb
CHANGED
@@ -2,9 +2,9 @@
|
|
2
2
|
|
3
3
|
module Spree
|
4
4
|
class Refund < Spree::Base
|
5
|
-
belongs_to :payment, inverse_of: :refunds
|
6
|
-
belongs_to :reason, class_name: 'Spree::RefundReason', foreign_key: :refund_reason_id
|
7
|
-
belongs_to :reimbursement, inverse_of: :refunds
|
5
|
+
belongs_to :payment, inverse_of: :refunds, optional: true
|
6
|
+
belongs_to :reason, class_name: 'Spree::RefundReason', foreign_key: :refund_reason_id, optional: true
|
7
|
+
belongs_to :reimbursement, inverse_of: :refunds, optional: true
|
8
8
|
|
9
9
|
has_many :log_entries, as: :source
|
10
10
|
|
@@ -6,8 +6,8 @@ module Spree
|
|
6
6
|
class_attribute :default_creditable_class
|
7
7
|
self.default_creditable_class = Spree::StoreCredit
|
8
8
|
|
9
|
-
belongs_to :reimbursement, inverse_of: :credits
|
10
|
-
belongs_to :creditable, polymorphic: true
|
9
|
+
belongs_to :reimbursement, inverse_of: :credits, optional: true
|
10
|
+
belongs_to :creditable, polymorphic: true, optional: true
|
11
11
|
|
12
12
|
validates :creditable, presence: true
|
13
13
|
|