spree_core 5.0.3 → 5.1.0.beta
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 +4 -4
- data/app/assets/images/logo.png +0 -0
- data/app/finders/spree/products/find.rb +28 -1
- data/app/finders/spree/taxons/find.rb +1 -1
- data/app/helpers/spree/integrations_helper.rb +15 -0
- data/app/javascript/spree/core/controllers/disable_submit_button_controller.js +19 -0
- data/app/mailers/spree/invitation_mailer.rb +24 -0
- data/app/models/concerns/spree/integrations_concern.rb +11 -0
- data/app/models/concerns/spree/product_scopes.rb +6 -6
- data/app/models/concerns/spree/translatable_resource.rb +4 -0
- data/app/models/concerns/spree/translatable_resource_scopes.rb +17 -3
- data/app/models/concerns/spree/unique_name.rb +2 -0
- data/app/models/concerns/spree/user_management.rb +33 -0
- data/app/models/concerns/spree/user_methods.rb +19 -0
- data/app/models/concerns/spree/user_roles.rb +43 -17
- data/app/models/spree/ability.rb +8 -6
- data/app/models/spree/asset.rb +1 -6
- data/app/models/spree/base.rb +1 -0
- data/app/models/spree/base_analytics_event_handler.rb +7 -2
- data/app/models/spree/classification.rb +13 -0
- data/app/models/spree/custom_domain.rb +2 -1
- data/app/models/spree/export.rb +1 -1
- data/app/models/spree/integration.rb +63 -0
- data/app/models/spree/invitation.rb +153 -0
- data/app/models/spree/invitations/store.rb +6 -0
- data/app/models/spree/order.rb +17 -1
- data/app/models/spree/order_merger.rb +7 -5
- data/app/models/spree/page_blocks/products/buy_buttons.rb +8 -0
- data/app/models/spree/page_blocks/products/quantity_selector.rb +4 -0
- data/app/models/spree/page_blocks/products/variant_picker.rb +4 -0
- data/app/models/spree/page_sections/featured_product.rb +4 -0
- data/app/models/spree/page_sections/image_banner.rb +12 -0
- data/app/models/spree/page_sections/image_with_text.rb +12 -0
- data/app/models/spree/page_sections/newsletter.rb +1 -1
- data/app/models/spree/page_sections/rich_text.rb +11 -0
- data/app/models/spree/page_sections/video.rb +8 -0
- data/app/models/spree/product.rb +10 -2
- data/app/models/spree/product_property.rb +1 -1
- data/app/models/spree/property.rb +3 -1
- data/app/models/spree/reports/sales_total.rb +5 -1
- data/app/models/spree/role.rb +16 -0
- data/app/models/spree/role_user.rb +32 -1
- data/app/models/spree/shipment.rb +1 -1
- data/app/models/spree/shipment_handler.rb +1 -0
- data/app/models/spree/shipping_method.rb +1 -1
- data/app/models/spree/store.rb +11 -4
- data/app/models/spree/store_credit_category.rb +4 -0
- data/app/models/spree/taxon.rb +4 -3
- data/app/models/spree/variant.rb +9 -1
- data/app/services/spree/country_to_timezone.rb +273 -0
- data/app/services/spree/seeds/admin_user.rb +4 -2
- data/app/services/spree/seeds/all.rb +3 -1
- data/app/services/spree/seeds/digital_delivery.rb +20 -0
- data/app/services/spree/seeds/returns_environment.rb +27 -0
- data/app/services/spree/seeds/tax_categories.rb +12 -0
- data/app/services/spree/stores/settings_defaults_by_country.rb +38 -0
- data/app/services/spree/tags/bulk_add.rb +13 -7
- data/app/views/spree/invitation_mailer/invitation_accepted.html.erb +12 -0
- data/app/views/spree/invitation_mailer/invitation_email.html.erb +21 -0
- data/config/locales/en.yml +48 -9
- data/db/migrate/20250407085228_create_spree_integrations.rb +12 -0
- data/db/migrate/20250410061306_create_spree_invitations.rb +20 -0
- data/db/migrate/20250418174652_add_resource_to_spree_role_users.rb +8 -0
- data/db/migrate/20250508060800_add_selected_locale_to_spree_admin_users.rb +8 -0
- data/db/migrate/20250509143831_add_session_id_to_spree_assets.rb +5 -0
- data/lib/generators/spree/authentication/devise/devise_generator.rb +5 -2
- data/lib/generators/spree/authentication/devise/templates/authentication_helpers.rb.tt +3 -3
- data/lib/generators/spree/install/install_generator.rb +5 -0
- data/lib/spree/core/controller_helpers/auth.rb +16 -14
- data/lib/spree/core/controller_helpers/currency.rb +11 -0
- data/lib/spree/core/controller_helpers/order.rb +2 -1
- data/lib/spree/core/controller_helpers/strong_parameters.rb +3 -2
- data/lib/spree/core/engine.rb +13 -2
- data/lib/spree/core/version.rb +1 -1
- data/lib/spree/core.rb +1 -0
- data/lib/spree/permitted_attributes.rb +118 -13
- data/lib/spree/testing_support/capybara_config.rb +1 -1
- data/lib/spree/testing_support/factories/integration_factory.rb +7 -0
- data/lib/spree/testing_support/factories/invitation_factory.rb +6 -0
- data/lib/spree/testing_support/factories/promotion_action_factory.rb +4 -0
- data/lib/spree/testing_support/factories/stock_item_factory.rb +5 -1
- data/lib/spree/testing_support/factories/user_factory.rb +14 -1
- data/lib/spree/translation_migrations.rb +27 -15
- data/lib/tasks/core.rake +8 -0
- metadata +41 -4
@@ -0,0 +1,153 @@
|
|
1
|
+
module Spree
|
2
|
+
class Invitation < Spree.base_class
|
3
|
+
has_secure_token
|
4
|
+
acts_as_paranoid
|
5
|
+
|
6
|
+
#
|
7
|
+
# Virtual Attributes
|
8
|
+
#
|
9
|
+
attribute :skip_email, :boolean, default: false
|
10
|
+
|
11
|
+
#
|
12
|
+
# Associations
|
13
|
+
#
|
14
|
+
belongs_to :resource, polymorphic: true # eg. Store, Vendor, Account
|
15
|
+
belongs_to :inviter, polymorphic: true # User or AdminUser
|
16
|
+
belongs_to :invitee, polymorphic: true, optional: true # User or AdminUser
|
17
|
+
belongs_to :role, class_name: 'Spree::Role'
|
18
|
+
has_one :role_user, dependent: :destroy, class_name: 'Spree::RoleUser'
|
19
|
+
|
20
|
+
#
|
21
|
+
# Validations
|
22
|
+
#
|
23
|
+
validates :email, email: true, presence: true
|
24
|
+
validates :token, presence: true, uniqueness: true
|
25
|
+
validates :inviter, :resource, :role, presence: true
|
26
|
+
validate :invitee_is_not_inviter, on: :create
|
27
|
+
validate :invitee_already_exists, on: :create
|
28
|
+
|
29
|
+
#
|
30
|
+
# Scopes
|
31
|
+
#
|
32
|
+
scope :pending, -> { where(status: 'pending') }
|
33
|
+
scope :accepted, -> { where(status: 'accepted') }
|
34
|
+
scope :not_expired, -> { where('expires_at > ?', Time.current) }
|
35
|
+
|
36
|
+
#
|
37
|
+
# State Machine
|
38
|
+
#
|
39
|
+
state_machine initial: :pending, attribute: :status do
|
40
|
+
state :accepted do
|
41
|
+
validate :accept_invitation_within_time_limit
|
42
|
+
validates :invitee, presence: true
|
43
|
+
end
|
44
|
+
|
45
|
+
event :accept do
|
46
|
+
transition pending: :accepted
|
47
|
+
end
|
48
|
+
after_transition to: :accepted, do: :after_accept
|
49
|
+
end
|
50
|
+
|
51
|
+
#
|
52
|
+
# Callbacks
|
53
|
+
#
|
54
|
+
after_initialize :set_defaults, if: :new_record?
|
55
|
+
before_validation :set_invitee_from_email, on: :create
|
56
|
+
after_create :send_invitation_email, unless: :skip_email
|
57
|
+
|
58
|
+
# returns the store for the invitation
|
59
|
+
# if the resource is a store, return the resource
|
60
|
+
# if the resource responds to store, return the store
|
61
|
+
# otherwise, return the current store
|
62
|
+
# @return [Spree::Store]
|
63
|
+
def store
|
64
|
+
if resource.is_a?(Spree::Store)
|
65
|
+
resource
|
66
|
+
elsif resource.respond_to?(:store)
|
67
|
+
resource.store
|
68
|
+
else
|
69
|
+
Spree::Store.current
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# returns true if the invitation has expired
|
74
|
+
# @return [Boolean]
|
75
|
+
def expired?
|
76
|
+
expires_at < Time.current
|
77
|
+
end
|
78
|
+
|
79
|
+
# Resends the invitation email if the invitation is pending and not expired
|
80
|
+
def resend!
|
81
|
+
return if expired? || deleted? || accepted?
|
82
|
+
|
83
|
+
send_invitation_email
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
# this method can be extended by developers now
|
89
|
+
def after_accept
|
90
|
+
create_role_user
|
91
|
+
set_accepted_at
|
92
|
+
send_acceptance_notification
|
93
|
+
end
|
94
|
+
|
95
|
+
def send_invitation_email
|
96
|
+
Spree::InvitationMailer.invitation_email(self).deliver_later
|
97
|
+
end
|
98
|
+
|
99
|
+
def send_acceptance_notification
|
100
|
+
Spree::InvitationMailer.invitation_accepted(self).deliver_later
|
101
|
+
end
|
102
|
+
|
103
|
+
def set_defaults
|
104
|
+
self.expires_at ||= 2.weeks.from_now
|
105
|
+
self.resource ||= Spree::Store.current
|
106
|
+
self.role ||= Spree::Role.default_admin_role
|
107
|
+
end
|
108
|
+
|
109
|
+
def invitee_is_not_inviter
|
110
|
+
if invitee == inviter
|
111
|
+
errors.add(:invitee, 'cannot be the same as the inviter')
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def invitee_already_exists
|
116
|
+
return if resource.blank?
|
117
|
+
|
118
|
+
exists = if invitee.present?
|
119
|
+
resource.users.include?(invitee)
|
120
|
+
else
|
121
|
+
resource.users.exists?(email: email)
|
122
|
+
end
|
123
|
+
|
124
|
+
if exists
|
125
|
+
errors.add(:email, 'already exists')
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def set_accepted_at
|
130
|
+
update!(accepted_at: Time.current)
|
131
|
+
end
|
132
|
+
|
133
|
+
def create_role_user
|
134
|
+
return if invitee.blank?
|
135
|
+
|
136
|
+
role_user = resource.add_user(invitee, role)
|
137
|
+
self.role_user = role_user
|
138
|
+
save!
|
139
|
+
end
|
140
|
+
|
141
|
+
def set_invitee_from_email
|
142
|
+
return if invitee.present?
|
143
|
+
|
144
|
+
self.invitee = Spree.admin_user_class.find_by(email: email)
|
145
|
+
end
|
146
|
+
|
147
|
+
def accept_invitation_within_time_limit
|
148
|
+
if Time.current > expires_at
|
149
|
+
errors.add(:base, 'Invitation expired')
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
data/app/models/spree/order.rb
CHANGED
@@ -91,6 +91,8 @@ module Spree
|
|
91
91
|
acts_as_taggable_on :tags
|
92
92
|
acts_as_taggable_tenant :store_id
|
93
93
|
|
94
|
+
ASSOCIATED_USER_ATTRIBUTES = [:user_id, :email, :created_by_id, :bill_address_id, :ship_address_id]
|
95
|
+
|
94
96
|
belongs_to :user, class_name: "::#{Spree.user_class}", optional: true, autosave: true
|
95
97
|
belongs_to :created_by, class_name: "::#{Spree.admin_user_class}", optional: true
|
96
98
|
belongs_to :approver, class_name: "::#{Spree.admin_user_class}", optional: true
|
@@ -247,6 +249,13 @@ module Spree
|
|
247
249
|
pre_tax_item_amount + shipments.sum(:pre_tax_amount)
|
248
250
|
end
|
249
251
|
|
252
|
+
# Returns the subtotal used for analytics integrations
|
253
|
+
# It's a sum of the item total and the promo total
|
254
|
+
# @return [Float]
|
255
|
+
def analytics_subtotal
|
256
|
+
(item_total + line_items.sum(:promo_total)).to_f
|
257
|
+
end
|
258
|
+
|
250
259
|
def shipping_discount
|
251
260
|
shipment_adjustments.non_tax.eligible.sum(:amount) * - 1
|
252
261
|
end
|
@@ -355,7 +364,7 @@ module Spree
|
|
355
364
|
self.bill_address ||= user.bill_address
|
356
365
|
self.ship_address ||= user.ship_address
|
357
366
|
|
358
|
-
changes = slice(
|
367
|
+
changes = slice(*ASSOCIATED_USER_ATTRIBUTES)
|
359
368
|
|
360
369
|
# immediately persist the changes we just made, but don't use save
|
361
370
|
# since we might have an invalid address associated
|
@@ -364,6 +373,12 @@ module Spree
|
|
364
373
|
end
|
365
374
|
end
|
366
375
|
|
376
|
+
def disassociate_user!
|
377
|
+
nullified_attributes = ASSOCIATED_USER_ATTRIBUTES.index_with(nil)
|
378
|
+
|
379
|
+
update!(nullified_attributes)
|
380
|
+
end
|
381
|
+
|
367
382
|
def quantity_of(variant, options = {})
|
368
383
|
line_item = find_line_item_by_variant(variant, options)
|
369
384
|
line_item ? line_item.quantity : 0
|
@@ -443,6 +458,7 @@ module Spree
|
|
443
458
|
# @return [Array<Spree::Variant>] the backordered variants for the order
|
444
459
|
def backordered_variants
|
445
460
|
variants.
|
461
|
+
where(track_inventory: true).
|
446
462
|
joins(:stock_items, :product).
|
447
463
|
where(Spree::StockItem.table_name => { count_on_hand: ..0, backorderable: true })
|
448
464
|
end
|
@@ -7,7 +7,7 @@ module Spree
|
|
7
7
|
@order = order
|
8
8
|
end
|
9
9
|
|
10
|
-
def merge!(other_order, user = nil)
|
10
|
+
def merge!(other_order, user = nil, discard_merged: true)
|
11
11
|
other_order.line_items.each do |other_order_line_item|
|
12
12
|
next unless other_order_line_item.currency == order.currency
|
13
13
|
|
@@ -16,12 +16,14 @@ module Spree
|
|
16
16
|
end
|
17
17
|
|
18
18
|
set_user(user)
|
19
|
-
clear_addresses(other_order)
|
19
|
+
clear_addresses(other_order) if discard_merged
|
20
20
|
persist_merge
|
21
21
|
|
22
|
-
|
23
|
-
|
24
|
-
|
22
|
+
if discard_merged
|
23
|
+
# So that the destroy doesn't take out line items which may have been re-assigned
|
24
|
+
other_order.line_items.reload
|
25
|
+
other_order.destroy
|
26
|
+
end
|
25
27
|
end
|
26
28
|
|
27
29
|
# Compare the line item of the other order with mine.
|
@@ -26,10 +26,22 @@ module Spree
|
|
26
26
|
]
|
27
27
|
end
|
28
28
|
|
29
|
+
def available_blocks_to_add
|
30
|
+
[
|
31
|
+
Spree::PageBlocks::Buttons,
|
32
|
+
Spree::PageBlocks::Heading,
|
33
|
+
Spree::PageBlocks::Text
|
34
|
+
]
|
35
|
+
end
|
36
|
+
|
29
37
|
def blocks_available?
|
30
38
|
true
|
31
39
|
end
|
32
40
|
|
41
|
+
def can_sort_blocks?
|
42
|
+
true
|
43
|
+
end
|
44
|
+
|
33
45
|
def icon_name
|
34
46
|
'slideshow'
|
35
47
|
end
|
@@ -27,6 +27,14 @@ module Spree
|
|
27
27
|
]
|
28
28
|
end
|
29
29
|
|
30
|
+
def available_blocks_to_add
|
31
|
+
[
|
32
|
+
Spree::PageBlocks::Buttons,
|
33
|
+
Spree::PageBlocks::Heading,
|
34
|
+
Spree::PageBlocks::Text
|
35
|
+
]
|
36
|
+
end
|
37
|
+
|
30
38
|
def default_links
|
31
39
|
@default_links.presence || [
|
32
40
|
Spree::PageLink.new(
|
@@ -40,6 +48,10 @@ module Spree
|
|
40
48
|
true
|
41
49
|
end
|
42
50
|
|
51
|
+
def can_sort_blocks?
|
52
|
+
true
|
53
|
+
end
|
54
|
+
|
43
55
|
def icon_name
|
44
56
|
'photo'
|
45
57
|
end
|
@@ -8,10 +8,21 @@ module Spree
|
|
8
8
|
]
|
9
9
|
end
|
10
10
|
|
11
|
+
def available_blocks_to_add
|
12
|
+
[
|
13
|
+
Spree::PageBlocks::Heading,
|
14
|
+
Spree::PageBlocks::Text
|
15
|
+
]
|
16
|
+
end
|
17
|
+
|
11
18
|
def blocks_available?
|
12
19
|
true
|
13
20
|
end
|
14
21
|
|
22
|
+
def can_sort_blocks?
|
23
|
+
true
|
24
|
+
end
|
25
|
+
|
15
26
|
def icon_name
|
16
27
|
'text-caption'
|
17
28
|
end
|
@@ -44,6 +44,10 @@ module Spree
|
|
44
44
|
]
|
45
45
|
end
|
46
46
|
|
47
|
+
def available_blocks_to_add
|
48
|
+
[Spree::PageBlocks::Heading]
|
49
|
+
end
|
50
|
+
|
47
51
|
def icon_name
|
48
52
|
'movie'
|
49
53
|
end
|
@@ -52,6 +56,10 @@ module Spree
|
|
52
56
|
true
|
53
57
|
end
|
54
58
|
|
59
|
+
def can_sort_blocks?
|
60
|
+
true
|
61
|
+
end
|
62
|
+
|
55
63
|
def video_embed
|
56
64
|
@video_embed ||= ::ActionText::VideoEmbed.find_by(id: preferred_youtube_video_embed_id) if preferred_youtube_video_embed_id.present?
|
57
65
|
end
|
data/app/models/spree/product.rb
CHANGED
@@ -595,7 +595,11 @@ module Spree
|
|
595
595
|
join_translation_table(Taxonomy).
|
596
596
|
find_by(Taxonomy.translation_table_alias => { name: Spree.t(:taxonomy_brands_name) })
|
597
597
|
else
|
598
|
-
taxons.
|
598
|
+
if taxons.loaded?
|
599
|
+
taxons.find { |taxon| taxon.taxonomy.name == Spree.t(:taxonomy_brands_name) }
|
600
|
+
else
|
601
|
+
taxons.joins(:taxonomy).find_by(Taxonomy.table_name => { name: Spree.t(:taxonomy_brands_name) })
|
602
|
+
end
|
599
603
|
end
|
600
604
|
end
|
601
605
|
|
@@ -606,7 +610,11 @@ module Spree
|
|
606
610
|
order(depth: :desc).
|
607
611
|
find_by(Taxonomy.translation_table_alias => { name: Spree.t(:taxonomy_categories_name) })
|
608
612
|
else
|
609
|
-
taxons.
|
613
|
+
if taxons.loaded?
|
614
|
+
taxons.find { |taxon| taxon.taxonomy.name == Spree.t(:taxonomy_categories_name) }
|
615
|
+
else
|
616
|
+
taxons.joins(:taxonomy).order(depth: :desc).find_by(Taxonomy.table_name => { name: Spree.t(:taxonomy_categories_name) })
|
617
|
+
end
|
610
618
|
end
|
611
619
|
end
|
612
620
|
|
@@ -33,7 +33,7 @@ module Spree
|
|
33
33
|
scope :filterable, -> { joins(:property).where(Property.table_name => { filterable: true }) }
|
34
34
|
scope :for_products, ->(products) { joins(:product).merge(products) }
|
35
35
|
scope :sort_by_property_position, -> {
|
36
|
-
joins(:property).order("spree_properties.position ASC")
|
36
|
+
unscope(:order).joins(:property).order("spree_properties.position ASC")
|
37
37
|
}
|
38
38
|
|
39
39
|
self.whitelisted_ransackable_attributes = ['value', 'filter_param']
|
@@ -39,8 +39,10 @@ module Spree
|
|
39
39
|
KIND_OPTIONS = { short_text: 0, long_text: 1, number: 2, rich_text: 3 }.freeze
|
40
40
|
enum :kind, KIND_OPTIONS
|
41
41
|
|
42
|
+
DEPENDENCY_UPDATE_FIELDS = [:presentation, :name, :kind, :filterable, :display_on, :position].freeze
|
43
|
+
|
42
44
|
after_touch :touch_all_products
|
43
|
-
after_update :touch_all_products, if: -> { saved_changes.key?(
|
45
|
+
after_update :touch_all_products, if: -> { DEPENDENCY_UPDATE_FIELDS.any? { |field| saved_changes.key?(field) } }
|
44
46
|
after_save :ensure_product_properties_have_filter_params
|
45
47
|
|
46
48
|
self.whitelisted_ransackable_attributes = ['presentation', 'filterable']
|
@@ -2,12 +2,16 @@ module Spree
|
|
2
2
|
module Reports
|
3
3
|
class SalesTotal < Spree::Report
|
4
4
|
def line_items_scope
|
5
|
-
store.line_items.where(
|
5
|
+
scope = store.line_items.where(
|
6
6
|
order: Spree::Order.complete.where(
|
7
7
|
currency: currency,
|
8
8
|
completed_at: (date_from.to_time.beginning_of_day)..(date_to.to_time.end_of_day)
|
9
9
|
)
|
10
10
|
).includes(:order, variant: :product)
|
11
|
+
|
12
|
+
scope = scope.where(vendor_id: vendor.id) if defined?(vendor) && vendor.present?
|
13
|
+
|
14
|
+
scope
|
11
15
|
end
|
12
16
|
end
|
13
17
|
end
|
data/app/models/spree/role.rb
CHANGED
@@ -4,8 +4,24 @@ module Spree
|
|
4
4
|
|
5
5
|
ADMIN_ROLE = 'admin'
|
6
6
|
|
7
|
+
#
|
8
|
+
# Associations
|
9
|
+
#
|
7
10
|
has_many :role_users, class_name: 'Spree::RoleUser', dependent: :destroy
|
8
11
|
has_many :users, through: :role_users, source: :user, source_type: Spree.user_class.to_s
|
9
12
|
has_many :admin_users, through: :role_users, source: :user, source_type: Spree.admin_user_class.to_s
|
13
|
+
has_many :invitations, class_name: 'Spree::Invitation', dependent: :destroy
|
14
|
+
|
15
|
+
#
|
16
|
+
# Scopes
|
17
|
+
#
|
18
|
+
scope :admin, -> { where(name: ADMIN_ROLE) }
|
19
|
+
|
20
|
+
#
|
21
|
+
# Class Methods
|
22
|
+
#
|
23
|
+
def self.default_admin_role
|
24
|
+
find_or_create_by(name: ADMIN_ROLE)
|
25
|
+
end
|
10
26
|
end
|
11
27
|
end
|
@@ -1,6 +1,37 @@
|
|
1
1
|
module Spree
|
2
2
|
class RoleUser < Spree.base_class
|
3
|
-
|
3
|
+
#
|
4
|
+
# Associations
|
5
|
+
#
|
6
|
+
belongs_to :role, class_name: 'Spree::Role', foreign_key: :role_id
|
4
7
|
belongs_to :user, polymorphic: true
|
8
|
+
belongs_to :resource, polymorphic: true
|
9
|
+
belongs_to :invitation, class_name: 'Spree::Invitation', optional: true
|
10
|
+
|
11
|
+
#
|
12
|
+
# Validations
|
13
|
+
#
|
14
|
+
validates :role, presence: true
|
15
|
+
validates :user, presence: true
|
16
|
+
validates :resource, presence: true
|
17
|
+
validates :role_id, uniqueness: { scope: [:user_id, :resource_id, :user_type, :resource_type] }
|
18
|
+
|
19
|
+
#
|
20
|
+
# Delegations
|
21
|
+
#
|
22
|
+
delegate :name, to: :user
|
23
|
+
|
24
|
+
#
|
25
|
+
# Callbacks
|
26
|
+
#
|
27
|
+
before_validation :set_default_resource
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
# Set the default resource to the default store if the resource is not set
|
32
|
+
# this will allow a graceful migration from the old roles system to the new one
|
33
|
+
def set_default_resource
|
34
|
+
self.resource ||= Spree::Store.current
|
35
|
+
end
|
5
36
|
end
|
6
37
|
end
|
@@ -430,7 +430,7 @@ module Spree
|
|
430
430
|
end
|
431
431
|
|
432
432
|
def manifest_unstock(item)
|
433
|
-
stock_location.unstock
|
433
|
+
stock_location.unstock(item.variant, item.quantity, self) if item.variant.track_inventory?
|
434
434
|
end
|
435
435
|
|
436
436
|
def recalculate_adjustments
|
data/app/models/spree/store.rb
CHANGED
@@ -13,6 +13,7 @@ module Spree
|
|
13
13
|
include Spree::Stores::Socials
|
14
14
|
include Spree::Webhooks::HasWebhooks if defined?(Spree::Webhooks::HasWebhooks)
|
15
15
|
include Spree::Security::Stores if defined?(Spree::Security::Stores)
|
16
|
+
include Spree::UserManagement
|
16
17
|
|
17
18
|
#
|
18
19
|
# Magic methods
|
@@ -100,8 +101,10 @@ module Spree
|
|
100
101
|
has_many :custom_domains, class_name: 'Spree::CustomDomain', dependent: :destroy
|
101
102
|
has_one :default_custom_domain, -> { where(default: true) }, class_name: 'Spree::CustomDomain'
|
102
103
|
|
103
|
-
has_many :posts
|
104
|
-
has_many :post_categories
|
104
|
+
has_many :posts, class_name: 'Spree::Post'
|
105
|
+
has_many :post_categories, class_name: 'Spree::PostCategory'
|
106
|
+
|
107
|
+
has_many :integrations, class_name: 'Spree::Integration'
|
105
108
|
|
106
109
|
#
|
107
110
|
# Page Builder associations
|
@@ -338,9 +341,11 @@ module Spree
|
|
338
341
|
end
|
339
342
|
end
|
340
343
|
|
344
|
+
# Returns the default stock location for the store or creates a new one if it doesn't exist
|
345
|
+
# @return [Spree::StockLocation]
|
341
346
|
def default_stock_location
|
342
347
|
@default_stock_location ||= begin
|
343
|
-
stock_location_scope = Spree::StockLocation.
|
348
|
+
stock_location_scope = Spree::StockLocation.where(default: true)
|
344
349
|
stock_location_scope.first || ActiveRecord::Base.connected_to(role: :writing) do
|
345
350
|
stock_location_scope.create(default: true, name: Spree.t(:default_stock_location_name), country: default_country)
|
346
351
|
end
|
@@ -348,7 +353,9 @@ module Spree
|
|
348
353
|
end
|
349
354
|
|
350
355
|
def admin_users
|
351
|
-
|
356
|
+
Spree::Deprecation.warn('Store#admin_users is deprecated and will be removed in Spree 6.0. Please use Store#users instead.')
|
357
|
+
|
358
|
+
users
|
352
359
|
end
|
353
360
|
|
354
361
|
def favicon
|
data/app/models/spree/taxon.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
# TODO: let friendly id take care of sanitizing the url
|
2
1
|
require 'stringex'
|
3
2
|
|
4
3
|
module Spree
|
@@ -96,9 +95,11 @@ module Spree
|
|
96
95
|
if Spree.use_translations?
|
97
96
|
joins(:taxonomy).
|
98
97
|
join_translation_table(Taxonomy).
|
99
|
-
where(
|
98
|
+
where(
|
99
|
+
Taxonomy.arel_table_alias[:name].lower.matches(taxonomy_name.downcase.strip)
|
100
|
+
)
|
100
101
|
else
|
101
|
-
joins(:taxonomy).where(
|
102
|
+
joins(:taxonomy).where(Spree::Taxonomy.arel_table[:name].lower.matches(taxonomy_name.downcase.strip))
|
102
103
|
end
|
103
104
|
}
|
104
105
|
|
data/app/models/spree/variant.rb
CHANGED
@@ -73,6 +73,8 @@ module Spree
|
|
73
73
|
after_create :create_stock_items
|
74
74
|
after_create :set_master_out_of_stock, unless: :is_master?
|
75
75
|
after_commit :clear_line_items_cache, on: :update
|
76
|
+
|
77
|
+
after_create :create_default_stock_item, unless: :track_inventory?
|
76
78
|
after_update_commit :handle_track_inventory_change
|
77
79
|
|
78
80
|
after_commit :remove_prices_from_master_variant, on: [:create, :update], unless: :is_master?
|
@@ -553,11 +555,17 @@ module Spree
|
|
553
555
|
line_items.update_all(updated_at: Time.current)
|
554
556
|
end
|
555
557
|
|
558
|
+
def create_default_stock_item
|
559
|
+
return if stock_items.any?
|
560
|
+
|
561
|
+
Spree::Store.current.default_stock_location.set_up_stock_item(self)
|
562
|
+
end
|
563
|
+
|
556
564
|
def handle_track_inventory_change
|
557
565
|
return unless track_inventory_previously_changed?
|
558
566
|
return if track_inventory
|
559
567
|
|
560
|
-
stock_items.update_all(
|
568
|
+
stock_items.update_all(count_on_hand: 0, updated_at: Time.current)
|
561
569
|
end
|
562
570
|
|
563
571
|
def remove_prices_from_master_variant
|