spree_core 5.0.4 → 5.0.6
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/helpers/spree/base_helper.rb +6 -1
- data/app/helpers/spree/images_helper.rb +13 -12
- data/app/helpers/spree/mail_helper.rb +4 -3
- data/app/models/concerns/spree/payment_source_concern.rb +39 -0
- data/app/models/spree/credit_card.rb +2 -24
- data/app/models/spree/custom_domain.rb +1 -1
- data/app/models/spree/gateway/custom_payment_source_method.rb +33 -0
- data/app/models/spree/option_value.rb +2 -2
- data/app/models/spree/page_sections/featured_posts.rb +4 -0
- data/app/models/spree/payment.rb +2 -1
- data/app/models/spree/payment_source.rb +21 -0
- data/app/models/spree/post.rb +1 -0
- data/app/models/spree/product/slugs.rb +112 -0
- data/app/models/spree/product.rb +5 -75
- data/app/models/spree/promotion/rules/item_total.rb +12 -12
- data/app/models/spree/shipping_method.rb +1 -1
- data/app/models/spree/taxon.rb +4 -0
- data/app/models/spree/theme.rb +1 -1
- data/app/models/spree/wishlist.rb +7 -0
- data/app/services/spree/products/prepare_nested_attributes.rb +9 -2
- data/app/views/spree/addresses/_form.html.erb +1 -1
- data/app/views/spree/shared/_payment.html.erb +9 -0
- data/config/locales/en.yml +11 -5
- data/lib/generators/spree/authentication/devise/devise_generator.rb +5 -2
- data/lib/generators/spree/install/install_generator.rb +5 -0
- data/lib/spree/core/engine.rb +1 -0
- data/lib/spree/core/version.rb +1 -1
- data/lib/spree/permitted_attributes.rb +8 -1
- data/lib/spree/testing_support/common_rake.rb +25 -7
- data/lib/spree/testing_support/extension_rake.rb +1 -1
- data/lib/spree/testing_support/factories/page_section_factory.rb +4 -0
- data/lib/spree/testing_support/factories/payment_factory.rb +5 -0
- data/lib/spree/testing_support/factories/payment_method_factory.rb +5 -0
- data/lib/spree/testing_support/factories/payment_source_factory.rb +5 -0
- data/lib/spree/testing_support/factories/taxon_factory.rb +6 -0
- metadata +8 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 964d9b4646aa2d9c5ac22647f126c304bc7756b3034757b8bda9b0f9faa6d496
|
4
|
+
data.tar.gz: '07803df2f7c528d8a35c10b04f02f591b4c2ffe859163c7b2c94e5ad0edfc388'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 36a5518a9bfd31ed6b6b3a74df7953534a8568cc36a7204acf0eca5499e93bd0b88068f35bd8b7dcbc52d09b9f47ea629cfa582a39d24d717d61c9803e865748
|
7
|
+
data.tar.gz: 46fb9aab1ceafb1d44f872e870908e3ff0df44458c4b6248a4bc6e54655f4de4e457b47c9a5c8c133b16cc631f93226a0280585cb8ebee3920b677cd48acee40
|
@@ -242,7 +242,7 @@ module Spree
|
|
242
242
|
end
|
243
243
|
|
244
244
|
def spree_base_cache_key
|
245
|
-
[
|
245
|
+
@spree_base_cache_key ||= [
|
246
246
|
I18n.locale,
|
247
247
|
(current_currency if defined?(current_currency)),
|
248
248
|
defined?(try_spree_current_user) && try_spree_current_user.present?,
|
@@ -258,6 +258,11 @@ module Spree
|
|
258
258
|
Spree::DatabaseTypeUtilities.maximum_value_for(:integer)
|
259
259
|
end
|
260
260
|
|
261
|
+
def payment_method_icon_tag(payment_method, opts = {})
|
262
|
+
image_tag "payment_icons/#{payment_method}.svg", opts
|
263
|
+
rescue Sprockets::Rails::Helper::AssetNotFound
|
264
|
+
end
|
265
|
+
|
261
266
|
private
|
262
267
|
|
263
268
|
def create_product_image_tag(image, product, options, style)
|
@@ -18,10 +18,10 @@ module Spree
|
|
18
18
|
width = options[:width]
|
19
19
|
height = options[:height]
|
20
20
|
|
21
|
-
width
|
22
|
-
height
|
21
|
+
width *= 2 if width.present?
|
22
|
+
height *= 2 if height.present?
|
23
23
|
|
24
|
-
return
|
24
|
+
return if image.respond_to?(:attached?) && !image.attached?
|
25
25
|
return unless image.variable?
|
26
26
|
|
27
27
|
if width.present? && height.present?
|
@@ -51,17 +51,18 @@ module Spree
|
|
51
51
|
return unless height
|
52
52
|
return if height.zero?
|
53
53
|
|
54
|
-
w
|
54
|
+
w = width.to_f
|
55
|
+
h = height.to_f
|
55
56
|
|
56
57
|
# Always return width / height, flipping if needed
|
57
|
-
if h > w
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
58
|
+
ratio = if h > w
|
59
|
+
h / w
|
60
|
+
elsif h < w
|
61
|
+
w / h
|
62
|
+
else
|
63
|
+
# h == w, square image
|
64
|
+
1.0
|
65
|
+
end
|
65
66
|
|
66
67
|
ratio.round(3)
|
67
68
|
end
|
@@ -1,10 +1,11 @@
|
|
1
1
|
module Spree
|
2
2
|
module MailHelper
|
3
|
-
include BaseHelper
|
3
|
+
include Spree::BaseHelper
|
4
|
+
include Spree::ImagesHelper
|
4
5
|
|
5
6
|
def variant_image_url(variant)
|
6
|
-
image =
|
7
|
-
image ?
|
7
|
+
image = variant.default_image
|
8
|
+
image.present? && image.attached? ? spree_image_url(image, width: 100, height: 100) : image_url('noimage/small.png')
|
8
9
|
end
|
9
10
|
|
10
11
|
def name_for(order)
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Spree
|
2
|
+
module PaymentSourceConcern
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
# Available actions for the payment source.
|
6
|
+
# @return [Array<String>]
|
7
|
+
def actions
|
8
|
+
%w{capture void credit}
|
9
|
+
end
|
10
|
+
|
11
|
+
# Indicates whether its possible to capture the payment
|
12
|
+
# @param payment [Spree::Payment]
|
13
|
+
# @return [Boolean]
|
14
|
+
def can_capture?(payment)
|
15
|
+
payment.pending? || payment.checkout?
|
16
|
+
end
|
17
|
+
|
18
|
+
# Indicates whether its possible to void the payment.
|
19
|
+
# @param payment [Spree::Payment]
|
20
|
+
# @return [Boolean]
|
21
|
+
def can_void?(payment)
|
22
|
+
!payment.failed? && !payment.void?
|
23
|
+
end
|
24
|
+
|
25
|
+
# Indicates whether its possible to credit the payment. Note that most gateways require that the
|
26
|
+
# payment be settled first which generally happens within 12-24 hours of the transaction.
|
27
|
+
# @param payment [Spree::Payment]
|
28
|
+
# @return [Boolean]
|
29
|
+
def can_credit?(payment)
|
30
|
+
payment.completed? && payment.credit_allowed > 0
|
31
|
+
end
|
32
|
+
|
33
|
+
# Returns true if the payment source has a payment profile.
|
34
|
+
# @return [Boolean]
|
35
|
+
def has_payment_profile?
|
36
|
+
gateway_customer_profile_id.present? || gateway_payment_profile_id.present?
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -2,6 +2,8 @@ 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
|
+
|
5
7
|
if defined?(Spree::Webhooks::HasWebhooks)
|
6
8
|
include Spree::Webhooks::HasWebhooks
|
7
9
|
end
|
@@ -135,30 +137,6 @@ module Spree
|
|
135
137
|
brand.present? ? brand.upcase : Spree.t(:no_cc_type)
|
136
138
|
end
|
137
139
|
|
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
|
-
|
162
140
|
# ActiveMerchant needs first_name/last_name because we pass it a Spree::CreditCard and it calls those methods on it.
|
163
141
|
# Looking at the ActiveMerchant source code we should probably be calling #to_active_merchant before passing
|
164
142
|
# the object to ActiveMerchant but this should do for now.
|
@@ -28,7 +28,7 @@ module Spree
|
|
28
28
|
def url_is_valid
|
29
29
|
parts = url.split('.')
|
30
30
|
|
31
|
-
errors.add(:url, 'use domain or subdomain') if
|
31
|
+
errors.add(:url, 'use domain or subdomain') if parts.size > 4 || parts.size < 2
|
32
32
|
end
|
33
33
|
|
34
34
|
def ensure_default
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Spree
|
2
|
+
class Gateway::CustomPaymentSourceMethod < Gateway
|
3
|
+
def provider_class
|
4
|
+
self.class
|
5
|
+
end
|
6
|
+
|
7
|
+
def payment_source_class
|
8
|
+
Spree::PaymentSource
|
9
|
+
end
|
10
|
+
|
11
|
+
def payment_profiles_supported?
|
12
|
+
true
|
13
|
+
end
|
14
|
+
|
15
|
+
def show_in_admin?
|
16
|
+
false
|
17
|
+
end
|
18
|
+
|
19
|
+
def create_profile(payment)
|
20
|
+
return if payment.source.gateway_customer.present?
|
21
|
+
|
22
|
+
user = payment.source.user || payment.order.user
|
23
|
+
return if user.blank?
|
24
|
+
|
25
|
+
find_or_create_customer(user)
|
26
|
+
end
|
27
|
+
|
28
|
+
# simulate a 3rd party payment gateway api to fetch/or create a customer
|
29
|
+
def find_or_create_customer(user)
|
30
|
+
gateway_customers.find_or_create_by!(user: user, profile_id: "CUSTOMER-#{user.id}")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
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(:name, :presentation).map do |name, presentation|
|
66
66
|
{
|
67
|
-
id:
|
67
|
+
id: name,
|
68
68
|
name: presentation
|
69
69
|
}
|
70
70
|
end
|
data/app/models/spree/payment.rb
CHANGED
@@ -302,7 +302,8 @@ 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
|
-
|
305
|
+
# Imported is only available on Spree::CreditCard, non-credit card payments should not have this attribute.
|
306
|
+
return if source.respond_to?(:imported) && source.imported
|
306
307
|
|
307
308
|
payment_method.create_profile(self)
|
308
309
|
rescue ActiveMerchant::ConnectionError => e
|
@@ -1,10 +1,31 @@
|
|
1
|
+
# This model is used to store payment sources for non-credit card payments, eg wallet, account, etc.
|
1
2
|
module Spree
|
2
3
|
class PaymentSource < Spree.base_class
|
3
4
|
include Spree::Metadata
|
5
|
+
include Spree::PaymentSourceConcern
|
4
6
|
|
7
|
+
#
|
8
|
+
# Associations
|
9
|
+
#
|
5
10
|
belongs_to :payment_method, class_name: 'Spree::PaymentMethod'
|
6
11
|
belongs_to :user, class_name: Spree.user_class.to_s, optional: true
|
7
12
|
|
13
|
+
#
|
14
|
+
# Validations
|
15
|
+
#
|
8
16
|
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
|
9
30
|
end
|
10
31
|
end
|
data/app/models/spree/post.rb
CHANGED
@@ -54,6 +54,7 @@ module Spree
|
|
54
54
|
# Scopes
|
55
55
|
#
|
56
56
|
scope :published, -> { where(published_at: [..Time.current]) }
|
57
|
+
scope :by_newest, -> { order(created_at: :desc) }
|
57
58
|
|
58
59
|
delegate :name, to: :author, prefix: true, allow_nil: true
|
59
60
|
delegate :title, to: :post_category, prefix: true, allow_nil: true
|
@@ -0,0 +1,112 @@
|
|
1
|
+
module Spree
|
2
|
+
class Product < Spree.base_class
|
3
|
+
module Slugs
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
extend FriendlyId
|
8
|
+
include Spree::TranslatableResourceSlug
|
9
|
+
|
10
|
+
translates :slug
|
11
|
+
friendly_id :slug_candidates, use: [:history, :slugged, :scoped, :mobility], scope: spree_base_uniqueness_scope, slug_limit: 255
|
12
|
+
|
13
|
+
Product::Translation.class_eval do
|
14
|
+
acts_as_paranoid
|
15
|
+
# deleted translation values also need to be accessible for index views listing deleted resources
|
16
|
+
default_scope { unscope(where: :deleted_at) }
|
17
|
+
|
18
|
+
before_validation :set_slug
|
19
|
+
before_validation :ensure_slug_is_unique
|
20
|
+
|
21
|
+
validates :slug, presence: true, uniqueness: { allow_blank: true, case_sensitive: true, scope: [*::Spree.base_class.spree_base_uniqueness_scope, :locale] }
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def set_slug
|
26
|
+
self.slug = generate_slug
|
27
|
+
end
|
28
|
+
|
29
|
+
def generate_slug
|
30
|
+
if name.blank? && slug.blank?
|
31
|
+
translated_model.name.to_url
|
32
|
+
elsif slug.blank?
|
33
|
+
name.to_url
|
34
|
+
else
|
35
|
+
slug.to_url
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def ensure_slug_is_unique
|
40
|
+
slug_exists = self.class.where(slug: slug, locale: locale).where.not(id: id).exists?
|
41
|
+
self.slug = [slug, SecureRandom.uuid].join('-') if slug_exists
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
before_validation :downcase_slug
|
46
|
+
before_validation :normalize_slug, on: :update
|
47
|
+
after_destroy :punch_slugs
|
48
|
+
after_restore :regenerate_slug
|
49
|
+
|
50
|
+
validates :slug, presence: true, uniqueness: { allow_blank: true, case_sensitive: true, scope: spree_base_uniqueness_scope }
|
51
|
+
|
52
|
+
def self.slug_available?(slug, id)
|
53
|
+
!where(slug: slug).where.not(id: id).exists?
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def ensure_slug_is_unique(candidate_slug)
|
58
|
+
return slug if candidate_slug.blank? || slug.blank?
|
59
|
+
return candidate_slug if self.class.slug_available?(candidate_slug, id)
|
60
|
+
|
61
|
+
normalize_friendly_id([candidate_slug, uuid_for_friendly_id])
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def slug_candidates
|
67
|
+
if defined?(:deleted_at) && deleted_at.present?
|
68
|
+
[
|
69
|
+
['deleted', :name],
|
70
|
+
['deleted', :name, :sku],
|
71
|
+
['deleted', :name, :uuid_for_friendly_id]
|
72
|
+
]
|
73
|
+
else
|
74
|
+
[
|
75
|
+
[:name],
|
76
|
+
[:name, :sku],
|
77
|
+
[:name, :uuid_for_friendly_id]
|
78
|
+
]
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def downcase_slug
|
83
|
+
slug&.downcase!
|
84
|
+
end
|
85
|
+
|
86
|
+
def normalize_slug
|
87
|
+
self.slug = normalize_friendly_id(slug)
|
88
|
+
end
|
89
|
+
|
90
|
+
def regenerate_slug
|
91
|
+
self.slug = nil
|
92
|
+
save!
|
93
|
+
end
|
94
|
+
|
95
|
+
def punch_slugs
|
96
|
+
return if new_record? || frozen?
|
97
|
+
|
98
|
+
self.slug = nil
|
99
|
+
|
100
|
+
set_slug
|
101
|
+
update_column(:slug, slug)
|
102
|
+
|
103
|
+
new_slug = ->(rec) { "deleted-#{rec.id}_#{rec.slug}"[..254] }
|
104
|
+
|
105
|
+
translations.with_deleted.each { |rec| rec.update_columns(slug: new_slug.call(rec)) }
|
106
|
+
slugs.with_deleted.each { |rec| rec.update_column(:slug, new_slug.call(rec)) }
|
107
|
+
|
108
|
+
translations.find_by!(locale: I18n.locale).update_column(:slug, slug) if Spree.use_translations?
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
data/app/models/spree/product.rb
CHANGED
@@ -20,14 +20,17 @@
|
|
20
20
|
|
21
21
|
module Spree
|
22
22
|
class Product < Spree.base_class
|
23
|
-
|
23
|
+
acts_as_paranoid
|
24
|
+
acts_as_taggable_on :tags, :labels
|
25
|
+
auto_strip_attributes :name
|
26
|
+
|
24
27
|
include Spree::ProductScopes
|
25
28
|
include Spree::MultiStoreResource
|
26
29
|
include Spree::TranslatableResource
|
27
|
-
include Spree::TranslatableResourceSlug
|
28
30
|
include Spree::MemoizedData
|
29
31
|
include Spree::Metadata
|
30
32
|
include Spree::Product::Webhooks
|
33
|
+
include Spree::Product::Slugs
|
31
34
|
if defined?(Spree::VendorConcern)
|
32
35
|
include Spree::VendorConcern
|
33
36
|
end
|
@@ -53,33 +56,8 @@ module Spree
|
|
53
56
|
pg_search_scope :search_by_name, against: { name: 'A', meta_title: 'B' },
|
54
57
|
using: { tsearch: { prefix: true, any_word: true } }
|
55
58
|
end
|
56
|
-
|
57
|
-
before_save :set_slug
|
58
|
-
acts_as_paranoid
|
59
|
-
# deleted translation values also need to be accessible for index views listing deleted resources
|
60
|
-
default_scope { unscope(where: :deleted_at) }
|
61
|
-
def set_slug
|
62
|
-
self.slug = generate_slug
|
63
|
-
end
|
64
|
-
|
65
|
-
private
|
66
|
-
|
67
|
-
def generate_slug
|
68
|
-
if name.blank? && slug.blank?
|
69
|
-
translated_model.name.to_url
|
70
|
-
elsif slug.blank?
|
71
|
-
name.to_url
|
72
|
-
else
|
73
|
-
slug.to_url
|
74
|
-
end
|
75
|
-
end
|
76
59
|
end
|
77
60
|
|
78
|
-
friendly_id :slug_candidates, use: [:history, :scoped, :mobility], scope: spree_base_uniqueness_scope
|
79
|
-
acts_as_paranoid
|
80
|
-
auto_strip_attributes :name
|
81
|
-
acts_as_taggable_on :tags, :labels
|
82
|
-
|
83
61
|
# we need to have this callback before any dependent: :destroy associations
|
84
62
|
# https://github.com/rails/rails/issues/3458
|
85
63
|
before_destroy :ensure_not_in_complete_orders
|
@@ -145,17 +123,12 @@ module Spree
|
|
145
123
|
after_initialize :ensure_master
|
146
124
|
after_initialize :assign_default_tax_category
|
147
125
|
|
148
|
-
before_validation :downcase_slug
|
149
|
-
before_validation :normalize_slug, on: :update
|
150
126
|
before_validation :validate_master
|
151
127
|
before_validation :ensure_default_shipping_category
|
152
128
|
|
153
129
|
after_create :add_associations_from_prototype
|
154
130
|
after_create :build_variants_from_option_values_hash, if: :option_values_hash
|
155
131
|
|
156
|
-
after_destroy :punch_slug
|
157
|
-
after_restore :update_slug_history
|
158
|
-
|
159
132
|
after_save :save_master
|
160
133
|
after_save :run_touch_callbacks, if: :anything_changed?
|
161
134
|
after_save :reset_nested_changes
|
@@ -173,7 +146,6 @@ module Spree
|
|
173
146
|
validates :price, if: :requires_price?
|
174
147
|
end
|
175
148
|
|
176
|
-
validates :slug, presence: true, uniqueness: { allow_blank: true, case_sensitive: true, scope: spree_base_uniqueness_scope }
|
177
149
|
validate :discontinue_on_must_be_later_than_make_active_at, if: -> { make_active_at && discontinue_on }
|
178
150
|
|
179
151
|
scope :for_store, ->(store) { joins(:store_products).where(StoreProduct.table_name => { store_id: store.id }) }
|
@@ -512,17 +484,6 @@ module Spree
|
|
512
484
|
where conditions.inject(:or)
|
513
485
|
end
|
514
486
|
|
515
|
-
def self.slug_available?(slug, id)
|
516
|
-
!where(slug: slug).where.not(id: id).exists?
|
517
|
-
end
|
518
|
-
|
519
|
-
def ensure_slug_is_unique(candidate_slug)
|
520
|
-
return slug if candidate_slug.blank? || slug.blank?
|
521
|
-
return candidate_slug if self.class.slug_available?(candidate_slug, id)
|
522
|
-
|
523
|
-
normalize_friendly_id([candidate_slug, uuid_for_friendly_id])
|
524
|
-
end
|
525
|
-
|
526
487
|
# Suitable for displaying only variants that has at least one option value.
|
527
488
|
# There may be scenarios where an option type is removed and along with it
|
528
489
|
# all option values. At that point all variants associated with only those
|
@@ -738,25 +699,6 @@ module Spree
|
|
738
699
|
self.tax_category = Spree::TaxCategory.default if new_record?
|
739
700
|
end
|
740
701
|
|
741
|
-
def normalize_slug
|
742
|
-
self.slug = normalize_friendly_id(slug)
|
743
|
-
end
|
744
|
-
|
745
|
-
def punch_slug
|
746
|
-
# punch slug with date prefix to allow reuse of original
|
747
|
-
return if frozen?
|
748
|
-
|
749
|
-
update_column(:slug, "#{Time.current.to_i}_#{slug}"[0..254])
|
750
|
-
|
751
|
-
translations.with_deleted.each do |t|
|
752
|
-
t.update_column :slug, "#{Time.current.to_i}_#{t.slug}"[0..254]
|
753
|
-
end
|
754
|
-
end
|
755
|
-
|
756
|
-
def update_slug_history
|
757
|
-
save!
|
758
|
-
end
|
759
|
-
|
760
702
|
def anything_changed?
|
761
703
|
saved_changes? || @nested_changes
|
762
704
|
end
|
@@ -812,14 +754,6 @@ module Spree
|
|
812
754
|
end
|
813
755
|
end
|
814
756
|
|
815
|
-
# Try building a slug based on the following fields in increasing order of specificity.
|
816
|
-
def slug_candidates
|
817
|
-
[
|
818
|
-
:name,
|
819
|
-
[:name, :sku]
|
820
|
-
]
|
821
|
-
end
|
822
|
-
|
823
757
|
def run_touch_callbacks
|
824
758
|
run_callbacks(:touch)
|
825
759
|
end
|
@@ -867,10 +801,6 @@ module Spree
|
|
867
801
|
previously_new_record? || tag_list_previously_changed? || available_on_previously_changed?
|
868
802
|
end
|
869
803
|
|
870
|
-
def downcase_slug
|
871
|
-
slug&.downcase!
|
872
|
-
end
|
873
|
-
|
874
804
|
def after_activate
|
875
805
|
# Implement your logic here
|
876
806
|
end
|
@@ -27,39 +27,39 @@ module Spree
|
|
27
27
|
upper_limit_condition = true
|
28
28
|
end
|
29
29
|
|
30
|
-
eligibility_errors.add(:base, ineligible_message_max) unless upper_limit_condition
|
31
|
-
eligibility_errors.add(:base, ineligible_message_min) unless lower_limit_condition
|
30
|
+
eligibility_errors.add(:base, ineligible_message_max(order)) unless upper_limit_condition
|
31
|
+
eligibility_errors.add(:base, ineligible_message_min(order)) unless lower_limit_condition
|
32
32
|
|
33
33
|
eligibility_errors.empty?
|
34
34
|
end
|
35
35
|
|
36
36
|
private
|
37
37
|
|
38
|
-
def formatted_amount_min
|
39
|
-
Spree::Money.new(preferred_amount_min).to_s
|
38
|
+
def formatted_amount_min(order)
|
39
|
+
Spree::Money.new(preferred_amount_min, currency: order.currency).to_s
|
40
40
|
end
|
41
41
|
|
42
|
-
def formatted_amount_max
|
42
|
+
def formatted_amount_max(order)
|
43
43
|
if preferred_amount_max.present?
|
44
|
-
Spree::Money.new(preferred_amount_max).to_s
|
44
|
+
Spree::Money.new(preferred_amount_max, currency: order.currency).to_s
|
45
45
|
else
|
46
46
|
Spree.t('no_maximum')
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
50
|
-
def ineligible_message_max
|
50
|
+
def ineligible_message_max(order)
|
51
51
|
if preferred_operator_max == 'lt'
|
52
|
-
eligibility_error_message(:item_total_more_than_or_equal, amount: formatted_amount_max)
|
52
|
+
eligibility_error_message(:item_total_more_than_or_equal, amount: formatted_amount_max(order))
|
53
53
|
else
|
54
|
-
eligibility_error_message(:item_total_more_than, amount: formatted_amount_max)
|
54
|
+
eligibility_error_message(:item_total_more_than, amount: formatted_amount_max(order))
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
58
|
-
def ineligible_message_min
|
58
|
+
def ineligible_message_min(order)
|
59
59
|
if preferred_operator_min == 'gte'
|
60
|
-
eligibility_error_message(:item_total_less_than, amount: formatted_amount_min)
|
60
|
+
eligibility_error_message(:item_total_less_than, amount: formatted_amount_min(order))
|
61
61
|
else
|
62
|
-
eligibility_error_message(:item_total_less_than_or_equal, amount: formatted_amount_min)
|
62
|
+
eligibility_error_message(:item_total_less_than_or_equal, amount: formatted_amount_min(order))
|
63
63
|
end
|
64
64
|
end
|
65
65
|
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].compact.join("-")
|
97
97
|
end
|
98
98
|
end
|
99
99
|
|
data/app/models/spree/taxon.rb
CHANGED
@@ -153,6 +153,10 @@ module Spree
|
|
153
153
|
sort_order == 'manual'
|
154
154
|
end
|
155
155
|
|
156
|
+
def page_builder_image
|
157
|
+
square_image.presence || image
|
158
|
+
end
|
159
|
+
|
156
160
|
def active_products_with_descendants
|
157
161
|
@active_products_with_descendants ||= store.products.
|
158
162
|
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, eg. header, footer, newsletter, etc.
|
159
159
|
#
|
160
160
|
# @return [Array<Class>]
|
161
161
|
def available_layout_sections
|
@@ -36,6 +36,13 @@ module Spree
|
|
36
36
|
@wished_items_count ||= variant_ids.count
|
37
37
|
end
|
38
38
|
|
39
|
+
# returns the variant ids in the wishlist
|
40
|
+
#
|
41
|
+
# @return [Array<Integer>]
|
42
|
+
def variant_ids
|
43
|
+
@variant_ids ||= wished_items.pluck(:variant_id)
|
44
|
+
end
|
45
|
+
|
39
46
|
def self.get_by_param(param)
|
40
47
|
find_by(token: param)
|
41
48
|
end
|
@@ -136,8 +136,15 @@ module Spree
|
|
136
136
|
o.position = opt[:position]
|
137
137
|
o.save!
|
138
138
|
end
|
139
|
-
|
140
|
-
|
139
|
+
|
140
|
+
option_value_identificator = if opt[:option_value_name].present?
|
141
|
+
opt[:option_value_name]
|
142
|
+
else
|
143
|
+
opt[:option_value_presentation].parameterize
|
144
|
+
end
|
145
|
+
|
146
|
+
option_value = option_type.option_values.where(name: option_value_identificator).first_or_initialize do |o|
|
147
|
+
o.name = o.presentation = opt[:option_value_presentation]
|
141
148
|
o.save!
|
142
149
|
end
|
143
150
|
|
@@ -5,7 +5,7 @@
|
|
5
5
|
data-controller="address-form address-autocomplete"
|
6
6
|
data-address-form-countries-value="<%= available_countries.to_json %>"
|
7
7
|
data-address-form-states-value="<%= available_states.to_json %>"
|
8
|
-
data-address-form-current-state-id-value="<%= address.state_id %>"
|
8
|
+
data-address-form-current-state-id-value="<%= address.state_id || address_form.object.state_id %>"
|
9
9
|
>
|
10
10
|
<div id="<%= "#{address_id}country" %>">
|
11
11
|
<div class="form-group mb-0">
|
@@ -30,6 +30,15 @@
|
|
30
30
|
<div class="flex-shrink-0">
|
31
31
|
<%= payment_method_icon_tag source.class.to_s.demodulize.downcase, height: 30 %>
|
32
32
|
</div>
|
33
|
+
<div>
|
34
|
+
<% if payment.payment_method.respond_to?(:source_partial_name) %>
|
35
|
+
<%= render partial: "spree/payment_sources/#{payment.payment_method.source_partial_name}", locals: { payment: payment, source: source } %>
|
36
|
+
<% elsif source.respond_to?(:name) %>
|
37
|
+
<%= source.name %>
|
38
|
+
<% else %>
|
39
|
+
<%= source.class.to_s.demodulize.downcase %>
|
40
|
+
<% end %>
|
41
|
+
</div>
|
33
42
|
<% else %>
|
34
43
|
<div class="flex-shrink-0">
|
35
44
|
<%= payment_method_icon_tag payment.payment_method.payment_icon_name %>
|
data/config/locales/en.yml
CHANGED
@@ -716,6 +716,7 @@ en:
|
|
716
716
|
capture: Capture
|
717
717
|
capture_events: Capture events
|
718
718
|
card_code: Card Verification Code (CVC)
|
719
|
+
card_expiration_placeholder: MM/YYYY
|
719
720
|
card_number: Card Number
|
720
721
|
card_type: Brand
|
721
722
|
card_type_is: Card type is
|
@@ -891,6 +892,8 @@ en:
|
|
891
892
|
destroy: Destroy
|
892
893
|
details: Details
|
893
894
|
developers: Developers
|
895
|
+
didn_t_receive_confirmation_instructions: Didn't receive confirmation instructions?
|
896
|
+
didn_t_receive_unlock_instructions: Didn't receive unlock instructions?
|
894
897
|
digital:
|
895
898
|
digital_delivery: Digital Delivery
|
896
899
|
digital_assets: Digital assets
|
@@ -1208,6 +1211,9 @@ en:
|
|
1208
1211
|
metadata: Metadata
|
1209
1212
|
min: Min
|
1210
1213
|
minimal_amount: Minimal Amount
|
1214
|
+
minimum_password_length:
|
1215
|
+
one: "(%{count} character minimum)"
|
1216
|
+
other: "(%{count} characters minimum)"
|
1211
1217
|
missing_return_authorization: Missing Return Authorization for %{item_name}.
|
1212
1218
|
month: Month
|
1213
1219
|
more: More
|
@@ -1481,7 +1487,7 @@ en:
|
|
1481
1487
|
password_protected: Password protected
|
1482
1488
|
paste: Paste
|
1483
1489
|
path: Path
|
1484
|
-
pay:
|
1490
|
+
pay: Pay
|
1485
1491
|
payment: Payment
|
1486
1492
|
payment_amount: Payment amount
|
1487
1493
|
payment_attempts: failed attempts
|
@@ -1498,11 +1504,11 @@ en:
|
|
1498
1504
|
payment_source: Payment source
|
1499
1505
|
payment_state: Payment State
|
1500
1506
|
payment_states:
|
1501
|
-
balance_due: Balance
|
1507
|
+
balance_due: Balance Due
|
1502
1508
|
checkout: Checkout
|
1503
1509
|
complete: Complete
|
1504
1510
|
completed: Completed
|
1505
|
-
credit_owed: Credit
|
1511
|
+
credit_owed: Credit Owed
|
1506
1512
|
failed: Failed
|
1507
1513
|
paid: Paid
|
1508
1514
|
partially_refunded: Partially Refunded
|
@@ -1526,8 +1532,6 @@ en:
|
|
1526
1532
|
please_check_back_soon: Please check back soon.
|
1527
1533
|
please_define_payment_methods: Please define some payment methods first.
|
1528
1534
|
please_enter_reasonable_quantity: Please enter a reasonable quantity.
|
1529
|
-
please_select: Please select
|
1530
|
-
please_select_all_options: Please select all options
|
1531
1535
|
policies: Policies
|
1532
1536
|
populate_get_error: Something went wrong. Please try adding the item again.
|
1533
1537
|
post_categories: Post categories
|
@@ -1878,6 +1882,7 @@ en:
|
|
1878
1882
|
show_store_selector:
|
1879
1883
|
long: Display the Store selector in the main nav bar of Storefront and allow users to change Store and Currency
|
1880
1884
|
short: Show Store selector
|
1885
|
+
sign_in_with_provider: Sign in with %{provider}
|
1881
1886
|
sign_out: Sign out
|
1882
1887
|
sign_up: Sign Up
|
1883
1888
|
site_name: Site name
|
@@ -2098,6 +2103,7 @@ en:
|
|
2098
2103
|
timezone: Timezone
|
2099
2104
|
title: Title
|
2100
2105
|
title_link: Title link
|
2106
|
+
to: To
|
2101
2107
|
to_add_variants_you_must_first_define: To add variants, you must first define
|
2102
2108
|
toggle_menu: Toggle menu
|
2103
2109
|
top_suggestions: Top suggestions
|
@@ -33,6 +33,8 @@ module Spree
|
|
33
33
|
include Spree::UserPaymentSource
|
34
34
|
RUBY
|
35
35
|
end
|
36
|
+
gsub_file user_class_file, "< ApplicationRecord", "< Spree.base_class"
|
37
|
+
|
36
38
|
say "Successfully added Spree user modules into #{user_class_file}"
|
37
39
|
else
|
38
40
|
say "Could not locate user model file at #{user_class_file}. Please add these lines manually:", :red
|
@@ -42,13 +44,14 @@ module Spree
|
|
42
44
|
include Spree::UserMethods
|
43
45
|
include Spree::UserPaymentSource
|
44
46
|
RUBY
|
47
|
+
|
48
|
+
say "Please replace < ApplicationRecord with < Spree.base_class in #{user_class_file}"
|
45
49
|
end
|
46
50
|
|
47
51
|
append_file 'config/initializers/spree.rb' do
|
48
52
|
%Q{
|
49
53
|
if defined?(Devise) && Devise.respond_to?(:parent_controller)
|
50
|
-
Devise.parent_controller = "Spree::
|
51
|
-
Devise.parent_mailer = "Spree::BaseMailer"
|
54
|
+
Devise.parent_controller = "Spree::BaseController"
|
52
55
|
end\n}
|
53
56
|
end
|
54
57
|
end
|
@@ -78,6 +78,11 @@ module Spree
|
|
78
78
|
def install_storefront
|
79
79
|
if @install_storefront && Spree::Core::Engine.frontend_available?
|
80
80
|
generate 'spree:storefront:install'
|
81
|
+
|
82
|
+
# generate devise controllers if authentication is devise
|
83
|
+
if @authentication == 'devise'
|
84
|
+
generate 'spree:storefront:devise'
|
85
|
+
end
|
81
86
|
end
|
82
87
|
end
|
83
88
|
|
data/lib/spree/core/engine.rb
CHANGED
data/lib/spree/core/version.rb
CHANGED
@@ -165,7 +165,14 @@ module Spree
|
|
165
165
|
:product_id, :product, :option_values_attributes, :price, :compare_at_price,
|
166
166
|
:weight, :height, :width, :depth, :sku, :barcode, :cost_currency,
|
167
167
|
:weight_unit, :dimensions_unit,
|
168
|
-
{
|
168
|
+
{
|
169
|
+
options: [:id, :name, :option_value_presentation, :option_value_name, :position, :_destroy],
|
170
|
+
stock_items_attributes: [:id, :count_on_hand, :stock_location_id, :backorderable, :_destroy],
|
171
|
+
prices_attributes: [:id, :amount, :compare_at_amount, :currency, :_destroy],
|
172
|
+
price: {},
|
173
|
+
option_value_variants_attributes: [:id, :option_value_id, :_destroy],
|
174
|
+
option_value_ids: []
|
175
|
+
}
|
169
176
|
]
|
170
177
|
|
171
178
|
@@wishlist_attributes = [:name, :is_default, :is_private]
|
@@ -46,21 +46,39 @@ namespace :common do
|
|
46
46
|
"--authentication=#{args[:authentication]}"
|
47
47
|
]
|
48
48
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
49
|
+
if !skip_javascript || ENV['LIB_NAME'] == 'spree/emails'
|
50
|
+
puts 'Precompiling assets...'
|
51
|
+
system('bundle exec rake assets:precompile > /dev/null 2>&1')
|
52
|
+
end
|
53
|
+
|
54
|
+
unless ENV['NO_MIGRATE']
|
55
|
+
puts 'Setting up dummy database...'
|
56
|
+
system('bin/rails db:environment:set RAILS_ENV=test > /dev/null 2>&1')
|
57
|
+
system('bundle exec rake db:drop db:create > /dev/null 2>&1')
|
58
|
+
Spree::DummyModelGenerator.start
|
59
|
+
system('bundle exec rake db:migrate > /dev/null 2>&1')
|
60
|
+
end
|
54
61
|
|
55
62
|
begin
|
56
63
|
require "generators/#{ENV['LIB_NAME']}/install/install_generator"
|
57
64
|
puts 'Running extension installation generator...'
|
58
|
-
|
65
|
+
|
66
|
+
if ENV['NO_MIGRATE']
|
67
|
+
"#{ENV['LIB_NAME'].camelize}::Generators::InstallGenerator".constantize.start([])
|
68
|
+
else
|
69
|
+
"#{ENV['LIB_NAME'].camelize}::Generators::InstallGenerator".constantize.start(['--auto-run-migrations'])
|
70
|
+
end
|
59
71
|
rescue LoadError
|
60
72
|
puts 'Skipping installation no generator to run...'
|
61
73
|
end
|
74
|
+
end
|
62
75
|
|
63
|
-
|
76
|
+
task :db_setup do |_t|
|
77
|
+
puts 'Setting up dummy database...'
|
78
|
+
system('bin/rails db:environment:set RAILS_ENV=test > /dev/null 2>&1')
|
79
|
+
system('bundle exec rake db:drop db:create > /dev/null 2>&1')
|
80
|
+
Spree::DummyModelGenerator.start
|
81
|
+
system('bundle exec rake db:migrate > /dev/null 2>&1')
|
64
82
|
end
|
65
83
|
|
66
84
|
task :seed do |_t|
|
@@ -2,7 +2,7 @@ require 'spree/testing_support/common_rake'
|
|
2
2
|
|
3
3
|
desc 'Generates a dummy app for testing an extension'
|
4
4
|
namespace :extension do
|
5
|
-
task :test_app, [:user_class] do |_t, args|
|
5
|
+
task :test_app, [:authentication, :user_class] do |_t, args|
|
6
6
|
Spree::DummyGeneratorHelper.inject_extension_requirements = true
|
7
7
|
Rake::Task['common:test_app'].execute(args.with_defaults(install_admin: true, install_storefront: true))
|
8
8
|
end
|
@@ -20,5 +20,9 @@ FactoryBot.define do
|
|
20
20
|
factory :newsletter_page_section, class: Spree::PageSections::Newsletter
|
21
21
|
|
22
22
|
factory :video_page_section, class: Spree::PageSections::Video
|
23
|
+
|
24
|
+
factory :image_with_text_page_section, class: Spree::PageSections::ImageWithText
|
25
|
+
|
26
|
+
factory :featured_posts_page_section, class: Spree::PageSections::FeaturedPosts
|
23
27
|
end
|
24
28
|
end
|
@@ -14,6 +14,11 @@ FactoryBot.define do
|
|
14
14
|
create(:refund, amount: 5, payment: payment)
|
15
15
|
end
|
16
16
|
end
|
17
|
+
|
18
|
+
factory :custom_payment, class: Spree::Payment do
|
19
|
+
payment_method { create(:custom_payment_method, stores: [order.store]) }
|
20
|
+
source { create(:payment_source, user: order.user, payment_method: payment_method) }
|
21
|
+
end
|
17
22
|
end
|
18
23
|
|
19
24
|
factory :check_payment, class: Spree::Payment do
|
@@ -37,4 +37,9 @@ FactoryBot.define do
|
|
37
37
|
active { true }
|
38
38
|
auto_capture { true }
|
39
39
|
end
|
40
|
+
|
41
|
+
factory :custom_payment_method, parent: :payment_method, class: Spree::Gateway::CustomPaymentSourceMethod do
|
42
|
+
type { 'Spree::Gateway::CustomPaymentSourceMethod' }
|
43
|
+
name { 'Custom' }
|
44
|
+
end
|
40
45
|
end
|
@@ -9,6 +9,12 @@ FactoryBot.define do
|
|
9
9
|
trait :with_description do
|
10
10
|
description { '<div>Test <strong>description</strong></div>' }
|
11
11
|
end
|
12
|
+
|
13
|
+
trait :with_header_image do
|
14
|
+
after(:create) do |taxon|
|
15
|
+
taxon.image.attach(io: File.new(Spree::Core::Engine.root.join('spec', 'fixtures', 'thinking-cat.jpg')), filename: 'thinking-cat.jpg')
|
16
|
+
end
|
17
|
+
end
|
12
18
|
end
|
13
19
|
|
14
20
|
factory :automatic_taxon, parent: :taxon do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spree_core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.0.
|
4
|
+
version: 5.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sean Schofield
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2025-
|
13
|
+
date: 2025-08-06 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: i18n-tasks
|
@@ -603,6 +603,7 @@ files:
|
|
603
603
|
- app/models/concerns/spree/number_as_param.rb
|
604
604
|
- app/models/concerns/spree/number_identifier.rb
|
605
605
|
- app/models/concerns/spree/parameterizable_name.rb
|
606
|
+
- app/models/concerns/spree/payment_source_concern.rb
|
606
607
|
- app/models/concerns/spree/previewable.rb
|
607
608
|
- app/models/concerns/spree/product_scopes.rb
|
608
609
|
- app/models/concerns/spree/ransackable_attributes.rb
|
@@ -666,6 +667,7 @@ files:
|
|
666
667
|
- app/models/spree/gateway.rb
|
667
668
|
- app/models/spree/gateway/bogus.rb
|
668
669
|
- app/models/spree/gateway/bogus_simple.rb
|
670
|
+
- app/models/spree/gateway/custom_payment_source_method.rb
|
669
671
|
- app/models/spree/gateway_customer.rb
|
670
672
|
- app/models/spree/image.rb
|
671
673
|
- app/models/spree/image/configuration/active_storage.rb
|
@@ -764,6 +766,7 @@ files:
|
|
764
766
|
- app/models/spree/preference.rb
|
765
767
|
- app/models/spree/price.rb
|
766
768
|
- app/models/spree/product.rb
|
769
|
+
- app/models/spree/product/slugs.rb
|
767
770
|
- app/models/spree/product/webhooks.rb
|
768
771
|
- app/models/spree/product_option_type.rb
|
769
772
|
- app/models/spree/product_promotion_rule.rb
|
@@ -1229,6 +1232,7 @@ files:
|
|
1229
1232
|
- lib/spree/testing_support/factories/payment_capture_event_factory.rb
|
1230
1233
|
- lib/spree/testing_support/factories/payment_factory.rb
|
1231
1234
|
- lib/spree/testing_support/factories/payment_method_factory.rb
|
1235
|
+
- lib/spree/testing_support/factories/payment_source_factory.rb
|
1232
1236
|
- lib/spree/testing_support/factories/post_category_factory.rb
|
1233
1237
|
- lib/spree/testing_support/factories/post_factory.rb
|
1234
1238
|
- lib/spree/testing_support/factories/price_factory.rb
|
@@ -1308,9 +1312,9 @@ licenses:
|
|
1308
1312
|
- BSD-3-Clause
|
1309
1313
|
metadata:
|
1310
1314
|
bug_tracker_uri: https://github.com/spree/spree/issues
|
1311
|
-
changelog_uri: https://github.com/spree/spree/releases/tag/v5.0.
|
1315
|
+
changelog_uri: https://github.com/spree/spree/releases/tag/v5.0.6
|
1312
1316
|
documentation_uri: https://docs.spreecommerce.org/
|
1313
|
-
source_code_uri: https://github.com/spree/spree/tree/v5.0.
|
1317
|
+
source_code_uri: https://github.com/spree/spree/tree/v5.0.6
|
1314
1318
|
post_install_message:
|
1315
1319
|
rdoc_options: []
|
1316
1320
|
require_paths:
|