spree_core 3.7.14.1 → 4.0.0.beta
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +1 -1
- data/app/controllers/spree/base_controller.rb +0 -1
- data/app/finders/spree/taxons/find.rb +6 -5
- data/app/helpers/spree/base_helper.rb +0 -9
- data/app/helpers/spree/products_helper.rb +1 -1
- data/app/models/concerns/spree/product_scopes.rb +254 -0
- data/app/models/concerns/spree/user_address.rb +5 -2
- data/app/models/friendly_id/slug_decorator.rb +8 -2
- data/app/models/spree/ability.rb +21 -22
- data/app/models/spree/address.rb +37 -24
- data/app/models/spree/adjustment.rb +0 -10
- data/app/models/spree/app_dependencies.rb +2 -2
- data/app/models/spree/asset.rb +1 -12
- data/app/models/spree/country.rb +2 -2
- data/app/models/spree/credit_card.rb +4 -5
- data/app/models/spree/gateway/bogus.rb +1 -1
- data/app/models/spree/image.rb +8 -1
- data/app/models/spree/image/configuration/active_storage.rb +0 -2
- data/app/models/spree/order.rb +13 -78
- data/app/models/spree/order/address_book.rb +86 -0
- data/app/models/spree/order/checkout.rb +4 -22
- data/app/models/spree/order/currency_updater.rb +1 -1
- data/app/models/spree/order/store_credit.rb +0 -18
- data/app/models/spree/order_merger.rb +1 -0
- data/app/models/spree/payment.rb +4 -2
- data/app/models/spree/payment/gateway_options.rb +1 -1
- data/app/models/spree/payment/processing.rb +2 -0
- data/app/models/spree/preferences/configuration.rb +1 -1
- data/app/models/spree/preferences/preferable.rb +1 -1
- data/app/models/spree/product.rb +2 -3
- data/app/models/spree/promotion_handler/coupon.rb +2 -1
- data/app/models/spree/reimbursement_tax_calculator.rb +1 -1
- data/app/models/spree/return_item.rb +1 -1
- data/app/models/spree/return_item/eligibility_validator/default.rb +2 -0
- data/app/models/spree/return_item/eligibility_validator/{rma_required.rb → r_m_a_required.rb} +0 -0
- data/app/models/spree/shipment.rb +1 -1
- data/app/models/spree/store_credit.rb +4 -5
- data/app/models/spree/taxon_image.rb +1 -1
- data/app/models/spree/taxonomy.rb +1 -1
- data/app/services/spree/cart/add_item.rb +3 -1
- data/app/services/spree/cart/update.rb +1 -1
- data/config/locales/en.yml +15 -0
- data/db/default/spree/stores.rb +1 -0
- data/db/default/spree/zones.rb +16 -0
- data/db/migrate/20140806144901_add_type_to_reimbursement_type.rb +1 -1
- data/db/migrate/20141101231208_fix_adjustment_order_presence.rb +2 -2
- data/db/migrate/20170323151450_add_missing_unique_indexes_for_unique_attributes.rb +1 -1
- data/db/migrate/20190305121659_add_iso_and_iso3_validation_on_presence_and_uniqueness.rb +18 -0
- data/db/migrate/20190523092729_add_user_id_and_deleted_at_to_spree_addresses.rb +12 -0
- data/lib/generators/spree/dummy/dummy_generator.rb +3 -1
- data/lib/spree/core.rb +0 -2
- data/lib/spree/core/importer/order.rb +64 -103
- data/lib/spree/core/importer/product.rb +2 -2
- data/lib/spree/core/product_duplicator.rb +1 -5
- data/lib/spree/core/version.rb +1 -3
- data/lib/spree/permitted_attributes.rb +3 -1
- data/lib/spree/testing_support/ability_helpers.rb +3 -11
- data/lib/spree/testing_support/capybara_config.rb +4 -1
- data/lib/spree/testing_support/capybara_ext.rb +22 -98
- data/lib/spree/testing_support/controller_requests.rb +36 -26
- data/lib/spree/testing_support/factories/image_factory.rb +2 -6
- data/lib/spree/testing_support/factories/return_item_factory.rb +2 -2
- data/lib/spree/testing_support/factories/taxon_factory.rb +1 -1
- data/lib/spree/testing_support/i18n.rb +6 -8
- data/lib/spree/testing_support/image_helpers.rb +5 -11
- data/lib/tasks/exchanges.rake +35 -37
- data/spree_core.gemspec +11 -14
- metadata +63 -103
- data/app/models/concerns/spree/acts_as_taggable.rb +0 -11
- data/app/models/spree/image/configuration/paperclip.rb +0 -64
- data/app/models/spree/order_contents.rb +0 -54
- data/app/models/spree/product/scopes.rb +0 -250
- data/app/models/spree/tag.rb +0 -4
- data/app/models/spree/taxon_image/configuration/paperclip.rb +0 -27
- data/config/initializers/acts_as_taggable_on.rb +0 -9
- data/config/initializers/use_paperclip.rb +0 -3
- data/db/migrate/20160511071954_acts_as_taggable_on_spree_migration.rb +0 -40
- data/db/migrate/20160511072249_change_collation_for_spree_tag_names.rb +0 -9
- data/db/migrate/20160511072335_add_missing_indexes_to_spree_taggings.rb +0 -14
- data/lib/spree/core/controller_helpers/respond_with.rb +0 -67
- data/lib/spree/responder.rb +0 -44
- data/lib/spree/testing_support/factories/tag_factory.rb +0 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5064fe41cb92fc49b65d326a8104d304e34e53b14cd8ad841207bef116b35464
|
4
|
+
data.tar.gz: c5288fc5c3b503961af981fe4c374e4bafcb93cb117dcd6e9be983d2c06f96e8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b70df4383270e04fc466c704e7d97ca152793bb74eec3ca7f66cbe901700671255eb2d94016b66031f43f57fa40ab9817f3498a272624a383a392d998ff675ed
|
7
|
+
data.tar.gz: 2eaf71128b93b12a4502d4bdb0ef0719ab39c480968a8436b422a723d6c7c43e97c323df636259fe03891fbf924c3043fafab4dc1e505fafa13317717a4c6fbf
|
data/Gemfile
CHANGED
@@ -3,7 +3,6 @@ require_dependency 'spree/core/controller_helpers/strong_parameters'
|
|
3
3
|
|
4
4
|
class Spree::BaseController < ApplicationController
|
5
5
|
include Spree::Core::ControllerHelpers::Auth
|
6
|
-
include Spree::Core::ControllerHelpers::RespondWith
|
7
6
|
include Spree::Core::ControllerHelpers::Common
|
8
7
|
include Spree::Core::ControllerHelpers::Search
|
9
8
|
include Spree::Core::ControllerHelpers::Store
|
@@ -3,11 +3,12 @@ module Spree
|
|
3
3
|
class Find
|
4
4
|
def initialize(scope:, params:)
|
5
5
|
@scope = scope
|
6
|
-
|
7
|
-
@
|
8
|
-
@
|
9
|
-
@
|
10
|
-
@
|
6
|
+
|
7
|
+
@ids = String(params[:ids]).split(',')
|
8
|
+
@parent = params[:parent_id]
|
9
|
+
@taxonomy = params[:taxonomy_id]
|
10
|
+
@name = params[:name]
|
11
|
+
@roots = params[:roots]
|
11
12
|
end
|
12
13
|
|
13
14
|
def execute
|
@@ -79,15 +79,6 @@ module Spree
|
|
79
79
|
spree.nested_taxons_path(taxon.permalink)
|
80
80
|
end
|
81
81
|
|
82
|
-
# human readable list of variant options
|
83
|
-
def variant_options(variant, _options = {})
|
84
|
-
ActiveSupport::Deprecation.warn(<<-DEPRECATION, caller)
|
85
|
-
BaseHelper#variant_options is deprecated and will be removed in Spree 4.0.
|
86
|
-
Please use Variant#options_text or LineItem#options_text
|
87
|
-
DEPRECATION
|
88
|
-
variant.options_text
|
89
|
-
end
|
90
|
-
|
91
82
|
def frontend_available?
|
92
83
|
Spree::Core::Engine.frontend_available?
|
93
84
|
end
|
@@ -36,7 +36,7 @@ module Spree
|
|
36
36
|
else
|
37
37
|
product.description.to_s.gsub(/(.*?)\r?\n\r?\n/m, '<p>\1</p>')
|
38
38
|
end
|
39
|
-
description.blank? ? Spree.t(:product_has_no_description) :
|
39
|
+
description.blank? ? Spree.t(:product_has_no_description) : description
|
40
40
|
end
|
41
41
|
|
42
42
|
def line_item_description_text(description_text)
|
@@ -0,0 +1,254 @@
|
|
1
|
+
module Spree
|
2
|
+
module ProductScopes
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
cattr_accessor :search_scopes do
|
7
|
+
[]
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.add_search_scope(name, &block)
|
11
|
+
singleton_class.send(:define_method, name.to_sym, &block)
|
12
|
+
search_scopes << name.to_sym
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.simple_scopes
|
16
|
+
[
|
17
|
+
:ascend_by_updated_at,
|
18
|
+
:descend_by_updated_at,
|
19
|
+
:ascend_by_name,
|
20
|
+
:descend_by_name
|
21
|
+
]
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.add_simple_scopes(scopes)
|
25
|
+
scopes.each do |name|
|
26
|
+
# We should not define price scopes here, as they require something slightly different
|
27
|
+
next if name.to_s.include?('master_price')
|
28
|
+
|
29
|
+
parts = name.to_s.match(/(.*)_by_(.*)/)
|
30
|
+
scope(name.to_s, -> { order(Arel.sql("#{Product.quoted_table_name}.#{parts[2]} #{parts[1] == 'ascend' ? 'ASC' : 'DESC'}")) })
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.property_conditions(property)
|
35
|
+
properties = Property.table_name
|
36
|
+
case property
|
37
|
+
when String then { "#{properties}.name" => property }
|
38
|
+
when Property then { "#{properties}.id" => property.id }
|
39
|
+
else { "#{properties}.id" => property.to_i }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
add_simple_scopes simple_scopes
|
44
|
+
|
45
|
+
add_search_scope :ascend_by_master_price do
|
46
|
+
joins(master: :default_price).order("#{price_table_name}.amount ASC")
|
47
|
+
end
|
48
|
+
|
49
|
+
add_search_scope :descend_by_master_price do
|
50
|
+
joins(master: :default_price).order("#{price_table_name}.amount DESC")
|
51
|
+
end
|
52
|
+
|
53
|
+
add_search_scope :price_between do |low, high|
|
54
|
+
joins(master: :default_price).where(Price.table_name => { amount: low..high })
|
55
|
+
end
|
56
|
+
|
57
|
+
add_search_scope :master_price_lte do |price|
|
58
|
+
joins(master: :default_price).where("#{price_table_name}.amount <= ?", price)
|
59
|
+
end
|
60
|
+
|
61
|
+
add_search_scope :master_price_gte do |price|
|
62
|
+
joins(master: :default_price).where("#{price_table_name}.amount >= ?", price)
|
63
|
+
end
|
64
|
+
|
65
|
+
# This scope selects products in taxon AND all its descendants
|
66
|
+
# If you need products only within one taxon use
|
67
|
+
#
|
68
|
+
# Spree::Product.joins(:taxons).where(Taxon.table_name => { id: taxon.id })
|
69
|
+
#
|
70
|
+
# If you're using count on the result of this scope, you must use the
|
71
|
+
# `:distinct` option as well:
|
72
|
+
#
|
73
|
+
# Spree::Product.in_taxon(taxon).count(distinct: true)
|
74
|
+
#
|
75
|
+
# This is so that the count query is distinct'd:
|
76
|
+
#
|
77
|
+
# SELECT COUNT(DISTINCT "spree_products"."id") ...
|
78
|
+
#
|
79
|
+
# vs.
|
80
|
+
#
|
81
|
+
# SELECT COUNT(*) ...
|
82
|
+
add_search_scope :in_taxon do |taxon|
|
83
|
+
includes(:classifications).
|
84
|
+
where('spree_products_taxons.taxon_id' => taxon.self_and_descendants.pluck(:id)).
|
85
|
+
order('spree_products_taxons.position ASC')
|
86
|
+
end
|
87
|
+
|
88
|
+
# This scope selects products in all taxons AND all its descendants
|
89
|
+
# If you need products only within one taxon use
|
90
|
+
#
|
91
|
+
# Spree::Product.taxons_id_eq([x,y])
|
92
|
+
add_search_scope :in_taxons do |*taxons|
|
93
|
+
taxons = get_taxons(taxons)
|
94
|
+
taxons.first ? prepare_taxon_conditions(taxons) : where(nil)
|
95
|
+
end
|
96
|
+
|
97
|
+
# a scope that finds all products having property specified by name, object or id
|
98
|
+
add_search_scope :with_property do |property|
|
99
|
+
joins(:properties).where(property_conditions(property))
|
100
|
+
end
|
101
|
+
|
102
|
+
# a simple test for product with a certain property-value pairing
|
103
|
+
# note that it can test for properties with NULL values, but not for absent values
|
104
|
+
add_search_scope :with_property_value do |property, value|
|
105
|
+
joins(:properties).
|
106
|
+
where("#{ProductProperty.table_name}.value = ?", value).
|
107
|
+
where(property_conditions(property))
|
108
|
+
end
|
109
|
+
|
110
|
+
add_search_scope :with_option do |option|
|
111
|
+
option_types = OptionType.table_name
|
112
|
+
conditions = case option
|
113
|
+
when String then { "#{option_types}.name" => option }
|
114
|
+
when OptionType then { "#{option_types}.id" => option.id }
|
115
|
+
else { "#{option_types}.id" => option.to_i }
|
116
|
+
end
|
117
|
+
|
118
|
+
joins(:option_types).where(conditions)
|
119
|
+
end
|
120
|
+
|
121
|
+
add_search_scope :with_option_value do |option, value|
|
122
|
+
option_values = OptionValue.table_name
|
123
|
+
option_type_id = case option
|
124
|
+
when String then OptionType.find_by(name: option) || option.to_i
|
125
|
+
when OptionType then option.id
|
126
|
+
else option.to_i
|
127
|
+
end
|
128
|
+
|
129
|
+
conditions = "#{option_values}.name = ? AND #{option_values}.option_type_id = ?", value, option_type_id
|
130
|
+
group('spree_products.id').joins(variants_including_master: :option_values).where(conditions)
|
131
|
+
end
|
132
|
+
|
133
|
+
# Finds all products which have either:
|
134
|
+
# 1) have an option value with the name matching the one given
|
135
|
+
# 2) have a product property with a value matching the one given
|
136
|
+
add_search_scope :with do |value|
|
137
|
+
includes(variants_including_master: :option_values).
|
138
|
+
includes(:product_properties).
|
139
|
+
where("#{OptionValue.table_name}.name = ? OR #{ProductProperty.table_name}.value = ?", value, value)
|
140
|
+
end
|
141
|
+
|
142
|
+
# Finds all products that have a name containing the given words.
|
143
|
+
add_search_scope :in_name do |words|
|
144
|
+
like_any([:name], prepare_words(words))
|
145
|
+
end
|
146
|
+
|
147
|
+
# Finds all products that have a name or meta_keywords containing the given words.
|
148
|
+
add_search_scope :in_name_or_keywords do |words|
|
149
|
+
like_any([:name, :meta_keywords], prepare_words(words))
|
150
|
+
end
|
151
|
+
|
152
|
+
# Finds all products that have a name, description, meta_description or meta_keywords containing the given keywords.
|
153
|
+
add_search_scope :in_name_or_description do |words|
|
154
|
+
like_any([:name, :description, :meta_description, :meta_keywords], prepare_words(words))
|
155
|
+
end
|
156
|
+
|
157
|
+
# Finds all products that have the ids matching the given collection of ids.
|
158
|
+
# Alternatively, you could use find(collection_of_ids), but that would raise an exception if one product couldn't be found
|
159
|
+
add_search_scope :with_ids do |*ids|
|
160
|
+
where(id: ids)
|
161
|
+
end
|
162
|
+
|
163
|
+
# Sorts products from most popular (popularity is extracted from how many
|
164
|
+
# times use has put product in cart, not completed orders)
|
165
|
+
#
|
166
|
+
# there is alternative faster and more elegant solution, it has small drawback though,
|
167
|
+
# it doesn stack with other scopes :/
|
168
|
+
#
|
169
|
+
# 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",
|
170
|
+
# order: 'COALESCE(cnt, 0) DESC'
|
171
|
+
add_search_scope :descend_by_popularity do
|
172
|
+
joins(:master).
|
173
|
+
order(%Q{
|
174
|
+
COALESCE((
|
175
|
+
SELECT
|
176
|
+
COUNT(#{LineItem.quoted_table_name}.id)
|
177
|
+
FROM
|
178
|
+
#{LineItem.quoted_table_name}
|
179
|
+
JOIN
|
180
|
+
#{Variant.quoted_table_name} AS popular_variants
|
181
|
+
ON
|
182
|
+
popular_variants.id = #{LineItem.quoted_table_name}.variant_id
|
183
|
+
WHERE
|
184
|
+
popular_variants.product_id = #{Product.quoted_table_name}.id
|
185
|
+
), 0) DESC
|
186
|
+
})
|
187
|
+
end
|
188
|
+
|
189
|
+
add_search_scope :not_deleted do
|
190
|
+
where("#{Product.quoted_table_name}.deleted_at IS NULL or #{Product.quoted_table_name}.deleted_at >= ?", Time.zone.now)
|
191
|
+
end
|
192
|
+
|
193
|
+
def self.not_discontinued(only_not_discontinued = true)
|
194
|
+
if only_not_discontinued != '0' && only_not_discontinued
|
195
|
+
where("#{Product.quoted_table_name}.discontinue_on IS NULL or #{Product.quoted_table_name}.discontinue_on >= ?", Time.zone.now)
|
196
|
+
else
|
197
|
+
all
|
198
|
+
end
|
199
|
+
end
|
200
|
+
search_scopes << :not_discontinued
|
201
|
+
# Can't use add_search_scope for this as it needs a default argument
|
202
|
+
def self.available(available_on = nil, _currency = nil)
|
203
|
+
available_on ||= Time.current
|
204
|
+
not_discontinued.joins(master: :prices).where("#{Product.quoted_table_name}.available_on <= ?", available_on)
|
205
|
+
end
|
206
|
+
search_scopes << :available
|
207
|
+
|
208
|
+
def self.active(currency = nil)
|
209
|
+
available(nil, currency)
|
210
|
+
end
|
211
|
+
search_scopes << :active
|
212
|
+
|
213
|
+
add_search_scope :taxons_name_eq do |name|
|
214
|
+
group('spree_products.id').joins(:taxons).where(Taxon.arel_table[:name].eq(name))
|
215
|
+
end
|
216
|
+
|
217
|
+
def self.price_table_name
|
218
|
+
Price.quoted_table_name
|
219
|
+
end
|
220
|
+
private_class_method :price_table_name
|
221
|
+
|
222
|
+
# specifically avoid having an order for taxon search (conflicts with main order)
|
223
|
+
def self.prepare_taxon_conditions(taxons)
|
224
|
+
ids = taxons.map { |taxon| taxon.self_and_descendants.pluck(:id) }.flatten.uniq
|
225
|
+
joins(:classifications).where(Classification.table_name => { taxon_id: ids })
|
226
|
+
end
|
227
|
+
private_class_method :prepare_taxon_conditions
|
228
|
+
|
229
|
+
# Produce an array of keywords for use in scopes.
|
230
|
+
# Always return array with at least an empty string to avoid SQL errors
|
231
|
+
def self.prepare_words(words)
|
232
|
+
return [''] if words.blank?
|
233
|
+
|
234
|
+
a = words.split(/[,\s]/).map(&:strip)
|
235
|
+
a.any? ? a : ['']
|
236
|
+
end
|
237
|
+
private_class_method :prepare_words
|
238
|
+
|
239
|
+
def self.get_taxons(*ids_or_records_or_names)
|
240
|
+
taxons = Taxon.table_name
|
241
|
+
ids_or_records_or_names.flatten.map do |t|
|
242
|
+
case t
|
243
|
+
when Integer then Taxon.find_by(id: t)
|
244
|
+
when ApplicationRecord then t
|
245
|
+
when String
|
246
|
+
Taxon.find_by(name: t) ||
|
247
|
+
Taxon.where("#{taxons}.permalink LIKE ? OR #{taxons}.permalink = ?", "%/#{t}/", "#{t}/").first
|
248
|
+
end
|
249
|
+
end.compact.flatten.uniq
|
250
|
+
end
|
251
|
+
private_class_method :get_taxons
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
@@ -13,18 +13,21 @@ module Spree
|
|
13
13
|
|
14
14
|
accepts_nested_attributes_for :ship_address, :bill_address
|
15
15
|
|
16
|
+
has_many :addresses, -> { where(deleted_at: nil).order('updated_at DESC') },
|
17
|
+
class_name: 'Spree::Address', foreign_key: :user_id
|
18
|
+
|
16
19
|
def persist_order_address(order)
|
17
20
|
b_address = bill_address || build_bill_address
|
18
21
|
b_address.attributes = order.bill_address.value_attributes
|
19
22
|
b_address.save
|
20
|
-
|
23
|
+
update(bill_address_id: b_address.id)
|
21
24
|
|
22
25
|
# May not be present if delivery step has been removed
|
23
26
|
if order.ship_address
|
24
27
|
s_address = ship_address || build_ship_address
|
25
28
|
s_address.attributes = order.ship_address.value_attributes
|
26
29
|
s_address.save
|
27
|
-
|
30
|
+
update(ship_address_id: s_address.id)
|
28
31
|
end
|
29
32
|
end
|
30
33
|
end
|
data/app/models/spree/ability.rb
CHANGED
@@ -23,15 +23,8 @@ module Spree
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def initialize(user)
|
26
|
-
|
27
|
-
|
28
|
-
# override cancan default aliasing (we don't want to differentiate between read and index)
|
26
|
+
# add cancancan aliasing
|
29
27
|
alias_action :delete, to: :destroy
|
30
|
-
alias_action :edit, to: :update
|
31
|
-
alias_action :new, to: :create
|
32
|
-
alias_action :new_action, to: :create
|
33
|
-
alias_action :show, to: :read
|
34
|
-
alias_action :index, :read, to: :display
|
35
28
|
alias_action :create, :update, :destroy, to: :modify
|
36
29
|
|
37
30
|
user ||= Spree.user_class.new
|
@@ -39,27 +32,33 @@ module Spree
|
|
39
32
|
if user.respond_to?(:has_spree_role?) && user.has_spree_role?('admin')
|
40
33
|
can :manage, :all
|
41
34
|
else
|
42
|
-
can :
|
43
|
-
can :
|
44
|
-
can :
|
35
|
+
can :read, Country
|
36
|
+
can :read, OptionType
|
37
|
+
can :read, OptionValue
|
45
38
|
can :create, Order
|
46
|
-
can :
|
39
|
+
can :show, Order do |order, token|
|
47
40
|
order.user == user || order.token && token == order.token
|
48
41
|
end
|
49
42
|
can :update, Order do |order, token|
|
50
43
|
!order.completed? && (order.user == user || order.token && token == order.token)
|
51
44
|
end
|
52
|
-
can :
|
53
|
-
|
54
|
-
|
55
|
-
can :
|
45
|
+
can :manage, Spree::Address do |address|
|
46
|
+
address.user == user
|
47
|
+
end
|
48
|
+
can :create, Spree::Address do |_address|
|
49
|
+
user.id.present?
|
50
|
+
end
|
51
|
+
can :read, CreditCard, user_id: user.id
|
52
|
+
can :read, Product
|
53
|
+
can :read, ProductProperty
|
54
|
+
can :read, Property
|
56
55
|
can :create, Spree.user_class
|
57
|
-
can [:
|
58
|
-
can :
|
59
|
-
can :
|
60
|
-
can :
|
61
|
-
can :
|
62
|
-
can :
|
56
|
+
can [:show, :update, :destroy], Spree.user_class, id: user.id
|
57
|
+
can :read, State
|
58
|
+
can :read, Taxon
|
59
|
+
can :read, Taxonomy
|
60
|
+
can :read, Variant
|
61
|
+
can :read, Zone
|
63
62
|
end
|
64
63
|
|
65
64
|
# Include any abilities registered by extensions, etc.
|
data/app/models/spree/address.rb
CHANGED
@@ -12,10 +12,12 @@ module Spree
|
|
12
12
|
|
13
13
|
# we're not freezing this on purpose so developers can extend and manage
|
14
14
|
# those attributes depending of the logic of their applications
|
15
|
-
|
15
|
+
ADDRESS_FIELDS = %w(firstname lastname company address1 address2 city state zipcode country phone)
|
16
|
+
EXCLUDED_KEYS_FOR_COMPARISION = %w(id updated_at created_at deleted_at user_id)
|
16
17
|
|
17
18
|
belongs_to :country, class_name: 'Spree::Country'
|
18
19
|
belongs_to :state, class_name: 'Spree::State', optional: true
|
20
|
+
belongs_to :user, class_name: Spree.user_class.name, optional: true
|
19
21
|
|
20
22
|
has_many :shipments, inverse_of: :address
|
21
23
|
|
@@ -49,12 +51,10 @@ module Spree
|
|
49
51
|
end
|
50
52
|
end
|
51
53
|
|
52
|
-
def
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
DEPRECATION
|
57
|
-
country_iso_name
|
54
|
+
def self.required_fields
|
55
|
+
Spree::Address.validators.map do |v|
|
56
|
+
v.is_a?(ActiveModel::Validations::PresenceValidator) ? v.attributes : []
|
57
|
+
end.flatten
|
58
58
|
end
|
59
59
|
|
60
60
|
def full_name
|
@@ -69,24 +69,15 @@ module Spree
|
|
69
69
|
state_name.present? ? state_name : state&.name
|
70
70
|
end
|
71
71
|
|
72
|
-
def same_as?(other)
|
73
|
-
ActiveSupport::Deprecation.warn(<<-EOS, caller)
|
74
|
-
Address#same_as? is deprecated and will be removed in Spree 4.0. Please use Address#== instead"
|
75
|
-
EOS
|
76
|
-
|
77
|
-
self == other
|
78
|
-
end
|
79
|
-
|
80
|
-
def same_as(other)
|
81
|
-
ActiveSupport::Deprecation.warn(<<-EOS, caller)
|
82
|
-
Address#same_as is deprecated and will be removed in Spree 4.0. Please use Address#== instead"
|
83
|
-
EOS
|
84
|
-
|
85
|
-
self == other
|
86
|
-
end
|
87
|
-
|
88
72
|
def to_s
|
89
|
-
|
73
|
+
[
|
74
|
+
full_name,
|
75
|
+
company,
|
76
|
+
address1,
|
77
|
+
address2,
|
78
|
+
"#{city}, #{state_text} #{zipcode}",
|
79
|
+
country.to_s
|
80
|
+
].reject(&:blank?).map { |attribute| ERB::Util.html_escape(attribute) }.join('<br/>')
|
90
81
|
end
|
91
82
|
|
92
83
|
def clone
|
@@ -129,6 +120,28 @@ module Spree
|
|
129
120
|
country ? country.zipcode_required? : true
|
130
121
|
end
|
131
122
|
|
123
|
+
def editable?
|
124
|
+
new_record? || (shipments.empty? && !Order.complete.where('bill_address_id = ? OR ship_address_id = ?', id, id).exists?)
|
125
|
+
end
|
126
|
+
|
127
|
+
def can_be_deleted?
|
128
|
+
shipments.empty? && !Order.where('bill_address_id = ? OR ship_address_id = ?', id, id).exists?
|
129
|
+
end
|
130
|
+
|
131
|
+
def check
|
132
|
+
attrs = attributes.except('id', 'updated_at', 'created_at')
|
133
|
+
the_same_address = user&.addresses&.find_by(attrs)
|
134
|
+
the_same_address || self
|
135
|
+
end
|
136
|
+
|
137
|
+
def destroy
|
138
|
+
if can_be_deleted?
|
139
|
+
super
|
140
|
+
else
|
141
|
+
update_column :deleted_at, Time.current
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
132
145
|
private
|
133
146
|
|
134
147
|
def clear_state
|