spree_core 5.0.5 → 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/base_helper.rb +1 -6
- data/app/helpers/spree/images_helper.rb +12 -13
- data/app/helpers/spree/integrations_helper.rb +15 -0
- data/app/helpers/spree/mail_helper.rb +3 -4
- 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/credit_card.rb +24 -2
- 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/option_value.rb +2 -2
- data/app/models/spree/order.rb +16 -5
- data/app/models/spree/order_merger.rb +7 -5
- data/app/models/spree/page_sections/featured_posts.rb +0 -4
- data/app/models/spree/payment.rb +1 -2
- data/app/models/spree/payment_source.rb +0 -21
- data/app/models/spree/post.rb +0 -1
- 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_handler.rb +1 -0
- data/app/models/spree/shipping_method.rb +2 -2
- data/app/models/spree/store.rb +9 -4
- data/app/models/spree/store_credit_category.rb +4 -0
- data/app/models/spree/taxon.rb +4 -7
- data/app/models/spree/theme.rb +1 -1
- data/app/models/spree/wishlist.rb +0 -7
- data/app/services/spree/country_to_timezone.rb +273 -0
- data/app/services/spree/products/prepare_nested_attributes.rb +2 -9
- 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/app/views/spree/shared/_payment.html.erb +0 -9
- data/config/locales/en.yml +48 -20
- 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 +15 -14
- data/lib/spree/core/controller_helpers/currency.rb +11 -0
- data/lib/spree/core/controller_helpers/strong_parameters.rb +3 -2
- data/lib/spree/core/engine.rb +13 -3
- data/lib/spree/core/version.rb +1 -1
- data/lib/spree/core.rb +1 -0
- data/lib/spree/permitted_attributes.rb +111 -13
- 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/page_section_factory.rb +0 -4
- data/lib/spree/testing_support/factories/payment_factory.rb +0 -5
- data/lib/spree/testing_support/factories/payment_method_factory.rb +0 -5
- data/lib/spree/testing_support/factories/promotion_action_factory.rb +4 -0
- 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 -7
- data/app/models/concerns/spree/payment_source_concern.rb +0 -39
- data/app/models/spree/gateway/custom_payment_source_method.rb +0 -33
- data/lib/spree/testing_support/factories/payment_source_factory.rb +0 -5
@@ -2,8 +2,6 @@ module Spree
|
|
2
2
|
class CreditCard < Spree.base_class
|
3
3
|
include ActiveMerchant::Billing::CreditCardMethods
|
4
4
|
include Spree::Metadata
|
5
|
-
include Spree::PaymentSourceConcern
|
6
|
-
|
7
5
|
if defined?(Spree::Webhooks::HasWebhooks)
|
8
6
|
include Spree::Webhooks::HasWebhooks
|
9
7
|
end
|
@@ -137,6 +135,30 @@ module Spree
|
|
137
135
|
brand.present? ? brand.upcase : Spree.t(:no_cc_type)
|
138
136
|
end
|
139
137
|
|
138
|
+
def actions
|
139
|
+
%w{capture void credit}
|
140
|
+
end
|
141
|
+
|
142
|
+
# Indicates whether its possible to capture the payment
|
143
|
+
def can_capture?(payment)
|
144
|
+
payment.pending? || payment.checkout?
|
145
|
+
end
|
146
|
+
|
147
|
+
# Indicates whether its possible to void the payment.
|
148
|
+
def can_void?(payment)
|
149
|
+
!payment.failed? && !payment.void?
|
150
|
+
end
|
151
|
+
|
152
|
+
# Indicates whether its possible to credit the payment. Note that most gateways require that the
|
153
|
+
# payment be settled first which generally happens within 12-24 hours of the transaction.
|
154
|
+
def can_credit?(payment)
|
155
|
+
payment.completed? && payment.credit_allowed > 0
|
156
|
+
end
|
157
|
+
|
158
|
+
def has_payment_profile?
|
159
|
+
gateway_customer_profile_id.present? || gateway_payment_profile_id.present?
|
160
|
+
end
|
161
|
+
|
140
162
|
# ActiveMerchant needs first_name/last_name because we pass it a Spree::CreditCard and it calls those methods on it.
|
141
163
|
# Looking at the ActiveMerchant source code we should probably be calling #to_active_merchant before passing
|
142
164
|
# the object to ActiveMerchant but this should do for now.
|
@@ -14,7 +14,7 @@ module Spree
|
|
14
14
|
# Validations
|
15
15
|
#
|
16
16
|
validates :url, presence: true, uniqueness: true, format: {
|
17
|
-
with: %r{[a-
|
17
|
+
with: %r{\A(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\z}i
|
18
18
|
}, length: { in: 1..63 }
|
19
19
|
validate :url_is_valid
|
20
20
|
|
@@ -26,6 +26,7 @@ module Spree
|
|
26
26
|
after_validation :ensure_default, on: :create
|
27
27
|
|
28
28
|
def url_is_valid
|
29
|
+
return if url.blank?
|
29
30
|
parts = url.split('.')
|
30
31
|
|
31
32
|
errors.add(:url, 'use domain or subdomain') if (parts[0] != 'www' && parts.size > 3) || (parts[0] == 'www' && parts.size > 4) || parts.size < 2
|
data/app/models/spree/export.rb
CHANGED
@@ -124,7 +124,7 @@ module Spree
|
|
124
124
|
end
|
125
125
|
|
126
126
|
def current_ability
|
127
|
-
@current_ability ||= Spree::Dependencies.ability_class.constantize.new(user)
|
127
|
+
@current_ability ||= Spree::Dependencies.ability_class.constantize.new(user, { store: store })
|
128
128
|
end
|
129
129
|
|
130
130
|
# eg. Spree::Exports::Products => products-store-my-store-code-20241030133348.csv
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Spree
|
2
|
+
class Integration < Spree.base_class
|
3
|
+
include Spree::SingleStoreResource
|
4
|
+
|
5
|
+
#
|
6
|
+
# Associations
|
7
|
+
#
|
8
|
+
belongs_to :store, class_name: 'Spree::Store', touch: true
|
9
|
+
|
10
|
+
#
|
11
|
+
# Validations
|
12
|
+
#
|
13
|
+
validates :type, presence: true
|
14
|
+
validates :store, presence: true, uniqueness: { scope: :type }
|
15
|
+
|
16
|
+
#
|
17
|
+
# Scopes
|
18
|
+
#
|
19
|
+
scope :active, -> { where(active: true) }
|
20
|
+
|
21
|
+
# This attribute is used to temporarily store connection-related error messages
|
22
|
+
# that can be displayed to users when testing or validating integration connections.
|
23
|
+
# It is not persisted to the database and is reset on each new connection attempt.
|
24
|
+
# @param message [String, nil] The error message to be stored
|
25
|
+
# @return [String, nil] The current error message
|
26
|
+
attr_accessor :connection_error_message
|
27
|
+
|
28
|
+
# Associates the integration to a group.
|
29
|
+
# The name here will be used as Spree.t key to display the group name.
|
30
|
+
# Leave blank to leave the integration ungrouped.
|
31
|
+
def self.integration_group
|
32
|
+
nil
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.icon_path
|
36
|
+
nil
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.integration_name
|
40
|
+
name.demodulize.titleize.strip
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.integration_key
|
44
|
+
name.demodulize.underscore
|
45
|
+
end
|
46
|
+
|
47
|
+
def name
|
48
|
+
self.class.integration_name
|
49
|
+
end
|
50
|
+
|
51
|
+
def key
|
52
|
+
self.class.integration_key
|
53
|
+
end
|
54
|
+
|
55
|
+
# Checks if the integration can establish a connection.
|
56
|
+
# This is a base implementation that always returns true.
|
57
|
+
# Subclasses should override this method to implement their own connection validation logic.
|
58
|
+
# @return [Boolean] true if the integration can connect, false otherwise
|
59
|
+
def can_connect?
|
60
|
+
true
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -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
|
@@ -62,9 +62,9 @@ module Spree
|
|
62
62
|
delegate :name, :presentation, to: :option_type, prefix: true, allow_nil: true
|
63
63
|
|
64
64
|
def self.to_tom_select_json
|
65
|
-
all.pluck(:
|
65
|
+
all.pluck(:id, :presentation).map do |id, presentation|
|
66
66
|
{
|
67
|
-
id:
|
67
|
+
id: id,
|
68
68
|
name: presentation
|
69
69
|
}
|
70
70
|
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
|
@@ -815,10 +830,6 @@ module Spree
|
|
815
830
|
csv_lines
|
816
831
|
end
|
817
832
|
|
818
|
-
def all_line_items
|
819
|
-
line_items
|
820
|
-
end
|
821
|
-
|
822
833
|
private
|
823
834
|
|
824
835
|
def link_by_email
|
@@ -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.
|
data/app/models/spree/payment.rb
CHANGED
@@ -302,8 +302,7 @@ module Spree
|
|
302
302
|
# Payment profile cannot be created without source
|
303
303
|
return unless source
|
304
304
|
# Imported payments shouldn't create a payment profile.
|
305
|
-
|
306
|
-
return if source.respond_to?(:imported) && source.imported
|
305
|
+
return if source.imported
|
307
306
|
|
308
307
|
payment_method.create_profile(self)
|
309
308
|
rescue ActiveMerchant::ConnectionError => e
|
@@ -1,31 +1,10 @@
|
|
1
|
-
# This model is used to store payment sources for non-credit card payments, eg wallet, account, etc.
|
2
1
|
module Spree
|
3
2
|
class PaymentSource < Spree.base_class
|
4
3
|
include Spree::Metadata
|
5
|
-
include Spree::PaymentSourceConcern
|
6
4
|
|
7
|
-
#
|
8
|
-
# Associations
|
9
|
-
#
|
10
5
|
belongs_to :payment_method, class_name: 'Spree::PaymentMethod'
|
11
6
|
belongs_to :user, class_name: Spree.user_class.to_s, optional: true
|
12
7
|
|
13
|
-
#
|
14
|
-
# Validations
|
15
|
-
#
|
16
8
|
validates_uniqueness_of :gateway_payment_profile_id, scope: :type
|
17
|
-
|
18
|
-
#
|
19
|
-
# Delegations
|
20
|
-
#
|
21
|
-
delegate :profile_id, to: :gateway_customer, prefix: true, allow_nil: true
|
22
|
-
|
23
|
-
# Returns the gateway customer for the user.
|
24
|
-
# @return [Spree::GatewayCustomer]
|
25
|
-
def gateway_customer
|
26
|
-
return if user.blank?
|
27
|
-
|
28
|
-
payment_method.gateway_customers.find_by(user: user)
|
29
|
-
end
|
30
9
|
end
|
31
10
|
end
|
data/app/models/spree/post.rb
CHANGED
@@ -54,7 +54,6 @@ module Spree
|
|
54
54
|
# Scopes
|
55
55
|
#
|
56
56
|
scope :published, -> { where(published_at: [..Time.current]) }
|
57
|
-
scope :by_newest, -> { order(created_at: :desc) }
|
58
57
|
|
59
58
|
delegate :name, to: :author, prefix: true, allow_nil: true
|
60
59
|
delegate :title, to: :post_category, prefix: true, allow_nil: true
|
@@ -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
|
@@ -50,7 +50,7 @@ module Spree
|
|
50
50
|
def include?(address)
|
51
51
|
return false unless address
|
52
52
|
|
53
|
-
zones.includes(:
|
53
|
+
zones.includes(zone_members: :zoneable).any? do |zone|
|
54
54
|
zone.include?(address)
|
55
55
|
end
|
56
56
|
end
|
@@ -93,7 +93,7 @@ module Spree
|
|
93
93
|
if estimated_transit_business_days_min == estimated_transit_business_days_max
|
94
94
|
estimated_transit_business_days_min.to_s
|
95
95
|
else
|
96
|
-
|
96
|
+
"#{estimated_transit_business_days_min}-#{estimated_transit_business_days_max}"
|
97
97
|
end
|
98
98
|
end
|
99
99
|
|
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
|
@@ -342,7 +345,7 @@ module Spree
|
|
342
345
|
# @return [Spree::StockLocation]
|
343
346
|
def default_stock_location
|
344
347
|
@default_stock_location ||= begin
|
345
|
-
stock_location_scope = Spree::StockLocation.
|
348
|
+
stock_location_scope = Spree::StockLocation.where(default: true)
|
346
349
|
stock_location_scope.first || ActiveRecord::Base.connected_to(role: :writing) do
|
347
350
|
stock_location_scope.create(default: true, name: Spree.t(:default_stock_location_name), country: default_country)
|
348
351
|
end
|
@@ -350,7 +353,9 @@ module Spree
|
|
350
353
|
end
|
351
354
|
|
352
355
|
def admin_users
|
353
|
-
|
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
|
354
359
|
end
|
355
360
|
|
356
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
|
|
@@ -153,10 +154,6 @@ module Spree
|
|
153
154
|
sort_order == 'manual'
|
154
155
|
end
|
155
156
|
|
156
|
-
def page_builder_image
|
157
|
-
square_image.presence || image
|
158
|
-
end
|
159
|
-
|
160
157
|
def active_products_with_descendants
|
161
158
|
@active_products_with_descendants ||= store.products.
|
162
159
|
joins(:classifications).
|
data/app/models/spree/theme.rb
CHANGED
@@ -155,7 +155,7 @@ module Spree
|
|
155
155
|
end
|
156
156
|
end
|
157
157
|
|
158
|
-
# Returns an array of available layout section classes for the theme
|
158
|
+
# Returns an array of available layout section classes for the theme
|
159
159
|
#
|
160
160
|
# @return [Array<Class>]
|
161
161
|
def available_layout_sections
|