spree_core 4.4.1 → 4.5.0
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/finders/spree/products/find.rb +1 -3
- data/app/finders/spree/taxons/find.rb +1 -1
- data/app/helpers/spree/base_helper.rb +12 -9
- data/app/helpers/spree/locale_helper.rb +6 -2
- data/app/helpers/spree/products_helper.rb +9 -4
- data/app/jobs/spree/variants/remove_from_incomplete_orders_job.rb +9 -0
- data/app/jobs/spree/variants/remove_line_item_job.rb +9 -0
- data/app/models/concerns/spree/calculated_adjustments.rb +1 -1
- data/app/models/concerns/spree/display_link.rb +17 -29
- data/app/models/concerns/spree/image_methods.rb +21 -9
- data/app/models/concerns/spree/metadata.rb +2 -2
- data/app/models/concerns/spree/product_scopes.rb +10 -8
- data/app/models/spree/address.rb +7 -1
- data/app/models/spree/asset/support/active_storage.rb +3 -2
- data/app/models/spree/asset.rb +3 -0
- data/app/models/spree/cms_page.rb +4 -0
- data/app/models/spree/cms_section.rb +12 -12
- data/app/models/spree/cms_section_image.rb +15 -0
- data/app/models/spree/cms_section_image_one.rb +4 -0
- data/app/models/spree/cms_section_image_three.rb +4 -0
- data/app/models/spree/cms_section_image_two.rb +4 -0
- data/app/models/spree/credit_card.rb +10 -4
- data/app/models/spree/customer_return.rb +3 -0
- data/app/models/spree/digital.rb +4 -0
- data/app/models/spree/digital_link.rb +7 -0
- data/app/models/spree/gateway/bogus.rb +1 -1
- data/app/models/spree/icon.rb +5 -1
- data/app/models/spree/image/configuration/active_storage.rb +5 -1
- data/app/models/spree/image.rb +3 -3
- data/app/models/spree/inventory_unit.rb +5 -2
- data/app/models/spree/legacy_user.rb +1 -2
- data/app/models/spree/line_item.rb +4 -1
- data/app/models/spree/linkable/homepage.rb +3 -0
- data/app/models/spree/linkable/uri.rb +3 -0
- data/app/models/spree/log_entry.rb +4 -0
- data/app/models/spree/menu.rb +3 -0
- data/app/models/spree/menu_item.rb +7 -11
- data/app/models/spree/option_type.rb +4 -0
- data/app/models/spree/option_value.rb +5 -0
- data/app/models/spree/order/address_book.rb +1 -0
- data/app/models/spree/order/store_credit.rb +0 -8
- data/app/models/spree/order.rb +11 -2
- data/app/models/spree/order_merger.rb +1 -1
- data/app/models/spree/payment/processing.rb +1 -1
- data/app/models/spree/payment.rb +7 -1
- data/app/models/spree/payment_capture_event.rb +4 -0
- data/app/models/spree/payment_method/store_credit.rb +1 -1
- data/app/models/spree/payment_method.rb +3 -0
- data/app/models/spree/payment_source.rb +10 -0
- data/app/models/spree/preference.rb +4 -0
- data/app/models/spree/price.rb +3 -0
- data/app/models/spree/product.rb +56 -14
- data/app/models/spree/product_property.rb +1 -0
- data/app/models/spree/promotion/rules/option_value.rb +2 -2
- data/app/models/spree/promotion.rb +6 -0
- data/app/models/spree/promotion_rule.rb +1 -1
- data/app/models/spree/promotion_rule_user.rb +1 -1
- data/app/models/spree/property.rb +3 -0
- data/app/models/spree/prototype.rb +3 -0
- data/app/models/spree/refund.rb +8 -0
- data/app/models/spree/reimbursement.rb +3 -0
- data/app/models/spree/return_authorization.rb +3 -0
- data/app/models/spree/return_item.rb +4 -0
- data/app/models/spree/role.rb +1 -1
- data/app/models/spree/role_user.rb +1 -1
- data/app/models/spree/shipment.rb +7 -0
- data/app/models/spree/shipping_category.rb +3 -0
- data/app/models/spree/shipping_method.rb +6 -0
- data/app/models/spree/state_change.rb +1 -1
- data/app/models/spree/stock/availability_validator.rb +9 -3
- data/app/models/spree/stock/content_item.rb +1 -1
- data/app/models/spree/stock/quantifier.rb +1 -1
- data/app/models/spree/stock_item.rb +5 -0
- data/app/models/spree/stock_location.rb +19 -5
- data/app/models/spree/stock_movement.rb +4 -0
- data/app/models/spree/stock_transfer.rb +3 -0
- data/app/models/spree/store.rb +19 -14
- data/app/models/spree/store_credit.rb +4 -1
- data/app/models/spree/store_favicon_image.rb +17 -0
- data/app/models/spree/store_logo.rb +9 -0
- data/app/models/spree/store_mailer_logo.rb +13 -0
- data/app/models/spree/tax_category.rb +6 -0
- data/app/models/spree/tax_rate.rb +6 -1
- data/app/models/spree/taxon.rb +4 -1
- data/app/models/spree/taxon_image/configuration/active_storage.rb +5 -1
- data/app/models/spree/taxon_image.rb +3 -2
- data/app/models/spree/taxonomy.rb +4 -1
- data/app/models/spree/variant.rb +43 -14
- data/app/models/spree/wished_item.rb +4 -0
- data/app/models/spree/wishlist.rb +4 -1
- data/app/models/spree/zone.rb +3 -0
- data/app/services/spree/addresses/create.rb +1 -1
- data/app/services/spree/addresses/update.rb +7 -2
- data/app/services/spree/cart/remove_line_item.rb +1 -0
- data/app/services/spree/variants/remove_line_items.rb +15 -0
- data/config/locales/en.yml +5 -2
- data/config/routes.rb +43 -0
- data/db/migrate/20211201202851_update_linkable_resource_types.rb +10 -0
- data/db/migrate/20211203082008_add_settings_to_payment_methods.rb +11 -0
- data/db/migrate/20211229162122_disable_propagate_all_variants_by_default.rb +5 -0
- data/db/migrate/20220103082046_add_status_and_make_active_at_to_spree_products.rb +7 -0
- data/db/migrate/20220106230929_add_internal_note_to_spree_orders.rb +5 -0
- data/db/migrate/20220113052823_create_payment_sources.rb +22 -0
- data/db/migrate/20220117100333_add_make_active_at_to_spree_products.rb +17 -0
- data/db/migrate/20220120092821_add_metadata_to_spree_tax_rates.rb +13 -0
- data/db/migrate/20220201103922_add_first_name_and_last_name_to_spree_users.rb +9 -0
- data/db/migrate/20220222083546_add_barcode_to_spree_variants.rb +6 -0
- data/db/migrate/20220329113557_fix_cms_pages_unique_indexes.rb +8 -0
- data/db/migrate/20220613133029_add_metadata_to_spree_stock_items.rb +13 -0
- data/lib/friendly_id/paranoia.rb +4 -0
- data/lib/generators/spree/dummy/dummy_generator.rb +13 -2
- data/lib/generators/spree/dummy/templates/package.json +12 -0
- data/lib/generators/spree/dummy/templates/rails/test.rb +2 -0
- data/lib/spree/core/configuration.rb +90 -0
- data/lib/spree/core/controller_helpers/auth.rb +3 -1
- data/lib/spree/core/controller_helpers/currency.rb +7 -5
- data/lib/spree/core/controller_helpers/locale.rb +8 -6
- data/lib/spree/core/controller_helpers/order.rb +4 -2
- data/lib/spree/core/controller_helpers/search.rb +1 -1
- data/lib/spree/core/controller_helpers/store.rb +5 -3
- data/lib/spree/core/dependencies.rb +130 -0
- data/lib/spree/core/engine.rb +47 -37
- data/{app/models/spree → lib/spree/core}/preferences/configuration.rb +3 -0
- data/{app/models/spree → lib/spree/core}/preferences/preferable.rb +3 -0
- data/lib/spree/core/search/base.rb +9 -5
- data/lib/spree/core/version.rb +1 -1
- data/lib/spree/core.rb +25 -5
- data/lib/spree/permitted_attributes.rb +9 -7
- data/lib/spree/testing_support/common_rake.rb +1 -0
- data/lib/spree/testing_support/factories/favicon_image_factory.rb +9 -0
- data/lib/spree/testing_support/factories/icon_factory.rb +3 -1
- data/lib/spree/testing_support/factories/image_factory.rb +3 -1
- data/lib/spree/testing_support/factories/menu_item_factory.rb +1 -1
- data/lib/spree/testing_support/factories/order_factory.rb +2 -1
- data/lib/spree/testing_support/factories/product_factory.rb +6 -1
- data/lib/spree/testing_support/factories/product_property_factory.rb +1 -0
- data/lib/spree/testing_support/factories/refund_factory.rb +1 -1
- data/lib/spree/testing_support/factories/return_authorization_factory.rb +1 -1
- data/lib/spree/testing_support/factories/role_factory.rb +1 -1
- data/lib/spree/testing_support/factories/shipping_category_factory.rb +1 -1
- data/lib/spree/testing_support/factories/stock_location_factory.rb +3 -2
- data/lib/spree/testing_support/factories/store_factory.rb +1 -1
- data/lib/spree/testing_support/factories/taxon_image_factory.rb +3 -1
- data/lib/spree/testing_support/factories/user_factory.rb +4 -0
- data/lib/spree/testing_support/factories/variant_factory.rb +4 -0
- data/lib/spree_core.rb +2 -1
- data/lib/tasks/core.rake +12 -0
- data/spree_core.gemspec +2 -3
- metadata +64 -53
- data/app/models/friendly_id/slug_decorator.rb +0 -9
- data/app/models/spree/app_configuration.rb +0 -86
- data/app/models/spree/order_contents.rb +0 -31
- data/lib/friendly_id/slug_rails5_patch.rb +0 -11
- data/lib/spree/core/app_dependencies.rb +0 -126
- /data/{app/models/spree → lib/spree/core}/preferences/preferable_class_methods.rb +0 -0
- /data/{app/models/spree → lib/spree/core}/preferences/scoped_store.rb +0 -0
- /data/{app/models/spree → lib/spree/core}/preferences/store.rb +0 -0
|
@@ -14,9 +14,15 @@ module Spree
|
|
|
14
14
|
display_name = variant.name.to_s
|
|
15
15
|
display_name += " (#{variant.options_text})" unless variant.options_text.blank?
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
if variant.available?
|
|
18
|
+
line_item.errors.add(:quantity,
|
|
19
|
+
:selected_quantity_not_available,
|
|
20
|
+
message: Spree.t(:selected_quantity_not_available, item: display_name.inspect))
|
|
21
|
+
else
|
|
22
|
+
line_item.errors.add(:base,
|
|
23
|
+
:only_active_products_can_be_added_to_cart,
|
|
24
|
+
message: Spree.t(:only_active_products_can_be_added_to_cart))
|
|
25
|
+
end
|
|
20
26
|
end
|
|
21
27
|
|
|
22
28
|
private
|
|
@@ -2,6 +2,11 @@ module Spree
|
|
|
2
2
|
class StockItem < Spree::Base
|
|
3
3
|
acts_as_paranoid
|
|
4
4
|
|
|
5
|
+
include Metadata
|
|
6
|
+
if defined?(Spree::Webhooks)
|
|
7
|
+
include Spree::Webhooks::HasWebhooks
|
|
8
|
+
end
|
|
9
|
+
|
|
5
10
|
with_options inverse_of: :stock_items do
|
|
6
11
|
belongs_to :stock_location, class_name: 'Spree::StockLocation'
|
|
7
12
|
belongs_to :variant, -> { with_deleted }, class_name: 'Spree::Variant'
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
module Spree
|
|
2
2
|
class StockLocation < Spree::Base
|
|
3
3
|
include UniqueName
|
|
4
|
+
if defined?(Spree::Webhooks)
|
|
5
|
+
include Spree::Webhooks::HasWebhooks
|
|
6
|
+
end
|
|
7
|
+
if defined?(Spree::Security::StockLocations)
|
|
8
|
+
include Spree::Security::StockLocations
|
|
9
|
+
end
|
|
10
|
+
if defined?(Spree::VendorConcern)
|
|
11
|
+
include Spree::VendorConcern
|
|
12
|
+
end
|
|
4
13
|
|
|
5
14
|
has_many :shipments
|
|
6
15
|
has_many :stock_items, dependent: :delete_all, inverse_of: :stock_location
|
|
@@ -51,9 +60,15 @@ module Spree
|
|
|
51
60
|
# @param variant Variant instance or Variant ID
|
|
52
61
|
#
|
|
53
62
|
# @return [StockItem] Corresponding StockItem for the StockLocation's variant.
|
|
54
|
-
def stock_item_or_create(
|
|
55
|
-
|
|
56
|
-
|
|
63
|
+
def stock_item_or_create(variant_or_variant_id)
|
|
64
|
+
if variant_or_variant_id.is_a?(Spree::Variant)
|
|
65
|
+
variant_id = variant_or_variant_id.id
|
|
66
|
+
variant = variant_or_variant_id
|
|
67
|
+
else
|
|
68
|
+
variant_id = variant_or_variant_id
|
|
69
|
+
variant = Spree::Variant.find(variant_or_variant_id)
|
|
70
|
+
end
|
|
71
|
+
stock_item(variant_id) || propagate_variant(variant)
|
|
57
72
|
end
|
|
58
73
|
|
|
59
74
|
def count_on_hand(variant)
|
|
@@ -86,8 +101,7 @@ module Spree
|
|
|
86
101
|
end
|
|
87
102
|
|
|
88
103
|
def fill_status(variant, quantity)
|
|
89
|
-
if item =
|
|
90
|
-
|
|
104
|
+
if item = stock_item_or_create(variant)
|
|
91
105
|
if item.count_on_hand >= quantity
|
|
92
106
|
on_hand = quantity
|
|
93
107
|
backordered = 0
|
data/app/models/spree/store.rb
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
module Spree
|
|
2
2
|
class Store < Spree::Base
|
|
3
|
+
if defined?(Spree::Webhooks)
|
|
4
|
+
include Spree::Webhooks::HasWebhooks
|
|
5
|
+
end
|
|
6
|
+
if defined?(Spree::Security::Stores)
|
|
7
|
+
include Spree::Security::Stores
|
|
8
|
+
end
|
|
9
|
+
|
|
3
10
|
typed_store :settings, coder: ActiveRecord::TypedStore::IdentityCoder do |s|
|
|
4
11
|
# Spree Digital Asset Configurations
|
|
5
12
|
s.boolean :limit_digital_download_count, default: true, null: false
|
|
@@ -9,8 +16,7 @@ module Spree
|
|
|
9
16
|
s.integer :digital_asset_link_expire_time, default: 300, null: false # 5 minutes in seconds
|
|
10
17
|
end
|
|
11
18
|
|
|
12
|
-
|
|
13
|
-
FAVICON_CONTENT_TYPES = ['image/png', 'image/x-icon', 'image/vnd.microsoft.icon'].freeze
|
|
19
|
+
attr_accessor :skip_validate_not_last
|
|
14
20
|
|
|
15
21
|
acts_as_paranoid
|
|
16
22
|
|
|
@@ -58,7 +64,7 @@ module Spree
|
|
|
58
64
|
|
|
59
65
|
validates :digital_asset_authorized_clicks, numericality: { only_integer: true, greater_than: 0 }
|
|
60
66
|
validates :digital_asset_authorized_days, numericality: { only_integer: true, greater_than: 0 }
|
|
61
|
-
validates :code, uniqueness: { conditions: -> { with_deleted } }
|
|
67
|
+
validates :code, uniqueness: { case_sensitive: false, conditions: -> { with_deleted } }
|
|
62
68
|
validates :mail_from_address, email: { allow_blank: false }
|
|
63
69
|
|
|
64
70
|
# FIXME: we should remove this condition in v5
|
|
@@ -71,19 +77,18 @@ module Spree
|
|
|
71
77
|
|
|
72
78
|
default_scope { order(created_at: :asc) }
|
|
73
79
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
80
|
+
has_one :logo, class_name: 'Spree::StoreLogo', dependent: :destroy, as: :viewable
|
|
81
|
+
accepts_nested_attributes_for :logo, reject_if: :all_blank
|
|
82
|
+
|
|
83
|
+
has_one :mailer_logo, class_name: 'Spree::StoreMailerLogo', dependent: :destroy, as: :viewable
|
|
84
|
+
accepts_nested_attributes_for :mailer_logo, reject_if: :all_blank
|
|
77
85
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
dimension: { max: 256..256 },
|
|
81
|
-
aspect_ratio: :square,
|
|
82
|
-
size: { less_than_or_equal_to: 1.megabyte }
|
|
86
|
+
has_one :favicon_image, class_name: 'Spree::StoreFaviconImage', dependent: :destroy, as: :viewable
|
|
87
|
+
accepts_nested_attributes_for :favicon_image, reject_if: :all_blank
|
|
83
88
|
|
|
84
89
|
before_save :ensure_default_exists_and_is_unique
|
|
85
90
|
before_save :ensure_supported_currencies, :ensure_supported_locales, :ensure_default_country
|
|
86
|
-
before_destroy :validate_not_last
|
|
91
|
+
before_destroy :validate_not_last, unless: :skip_validate_not_last
|
|
87
92
|
before_destroy :pass_default_flag_to_other_store
|
|
88
93
|
|
|
89
94
|
scope :by_url, ->(url) { where('url like ?', "%#{url}%") }
|
|
@@ -176,9 +181,9 @@ module Spree
|
|
|
176
181
|
end
|
|
177
182
|
|
|
178
183
|
def favicon
|
|
179
|
-
return unless favicon_image
|
|
184
|
+
return unless favicon_image&.attachment&.attached?
|
|
180
185
|
|
|
181
|
-
favicon_image.variant(
|
|
186
|
+
favicon_image.attachment.variant(resize_to_limit: [32, 32])
|
|
182
187
|
end
|
|
183
188
|
|
|
184
189
|
def can_be_deleted?
|
|
@@ -2,6 +2,9 @@ module Spree
|
|
|
2
2
|
class StoreCredit < Spree::Base
|
|
3
3
|
include SingleStoreResource
|
|
4
4
|
include Metadata
|
|
5
|
+
if defined?(Spree::Webhooks)
|
|
6
|
+
include Spree::Webhooks::HasWebhooks
|
|
7
|
+
end
|
|
5
8
|
|
|
6
9
|
acts_as_paranoid
|
|
7
10
|
|
|
@@ -15,7 +18,7 @@ module Spree
|
|
|
15
18
|
|
|
16
19
|
DEFAULT_CREATED_BY_EMAIL = 'spree@example.com'.freeze
|
|
17
20
|
|
|
18
|
-
belongs_to :user, class_name: Spree.user_class
|
|
21
|
+
belongs_to :user, class_name: "::#{Spree.user_class}", foreign_key: 'user_id'
|
|
19
22
|
belongs_to :category, class_name: 'Spree::StoreCreditCategory'
|
|
20
23
|
belongs_to :created_by, class_name: Spree.admin_user_class.to_s, foreign_key: 'created_by_id'
|
|
21
24
|
belongs_to :credit_type, class_name: 'Spree::StoreCreditType', foreign_key: 'type_id'
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
class StoreFaviconImage < Asset
|
|
3
|
+
if Spree.public_storage_service_name
|
|
4
|
+
has_one_attached :attachment, service: Spree.public_storage_service_name
|
|
5
|
+
else
|
|
6
|
+
has_one_attached :attachment
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
VALID_CONTENT_TYPES = ['image/png', 'image/x-icon', 'image/vnd.microsoft.icon'].freeze
|
|
10
|
+
|
|
11
|
+
validates :attachment,
|
|
12
|
+
content_type: VALID_CONTENT_TYPES,
|
|
13
|
+
dimension: { max: 256..256 },
|
|
14
|
+
aspect_ratio: :square,
|
|
15
|
+
size: { less_than_or_equal_to: 1.megabyte }
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
class StoreMailerLogo < Asset
|
|
3
|
+
if Spree.public_storage_service_name
|
|
4
|
+
has_one_attached :attachment, service: Spree.public_storage_service_name
|
|
5
|
+
else
|
|
6
|
+
has_one_attached :attachment
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
VALID_CONTENT_TYPES = ['image/png', 'image/jpg', 'image/jpeg'].freeze
|
|
10
|
+
|
|
11
|
+
validates :attachment, content_type: VALID_CONTENT_TYPES
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
module Spree
|
|
2
2
|
class TaxCategory < Spree::Base
|
|
3
|
+
if defined?(Spree::Webhooks)
|
|
4
|
+
include Spree::Webhooks::HasWebhooks
|
|
5
|
+
end
|
|
6
|
+
|
|
3
7
|
acts_as_paranoid
|
|
4
8
|
validates :name, presence: true, uniqueness: { case_sensitive: false, scope: spree_base_uniqueness_scope.push(:deleted_at) }
|
|
5
9
|
|
|
6
10
|
has_many :tax_rates, dependent: :destroy, inverse_of: :tax_category
|
|
11
|
+
has_many :products, dependent: :nullify
|
|
12
|
+
has_many :variants, dependent: :nullify
|
|
7
13
|
|
|
8
14
|
before_save :set_default_category
|
|
9
15
|
|
|
@@ -4,6 +4,10 @@ module Spree
|
|
|
4
4
|
|
|
5
5
|
include Spree::CalculatedAdjustments
|
|
6
6
|
include Spree::AdjustmentSource
|
|
7
|
+
include Spree::Metadata
|
|
8
|
+
if defined?(Spree::Webhooks)
|
|
9
|
+
include Spree::Webhooks::HasWebhooks
|
|
10
|
+
end
|
|
7
11
|
|
|
8
12
|
with_options inverse_of: :tax_rates do
|
|
9
13
|
belongs_to :zone, class_name: 'Spree::Zone', optional: true
|
|
@@ -114,7 +118,8 @@ module Spree
|
|
|
114
118
|
|
|
115
119
|
' ' + ActiveSupport::NumberHelper::NumberToPercentageConverter.convert(
|
|
116
120
|
amount * 100,
|
|
117
|
-
locale: I18n.locale
|
|
121
|
+
locale: I18n.locale,
|
|
122
|
+
strip_insignificant_zeros: true
|
|
118
123
|
)
|
|
119
124
|
end
|
|
120
125
|
end
|
data/app/models/spree/taxon.rb
CHANGED
|
@@ -4,6 +4,9 @@ require 'stringex'
|
|
|
4
4
|
module Spree
|
|
5
5
|
class Taxon < Spree::Base
|
|
6
6
|
include Metadata
|
|
7
|
+
if defined?(Spree::Webhooks)
|
|
8
|
+
include Spree::Webhooks::HasWebhooks
|
|
9
|
+
end
|
|
7
10
|
|
|
8
11
|
extend FriendlyId
|
|
9
12
|
friendly_id :permalink, slug_column: :permalink, use: :history
|
|
@@ -39,7 +42,7 @@ module Spree
|
|
|
39
42
|
|
|
40
43
|
before_validation :copy_taxonomy_from_parent
|
|
41
44
|
after_save :touch_ancestors_and_taxonomy
|
|
42
|
-
|
|
45
|
+
after_update :sync_taxonomy_name
|
|
43
46
|
after_touch :touch_ancestors_and_taxonomy
|
|
44
47
|
|
|
45
48
|
has_one :icon, as: :viewable, dependent: :destroy, class_name: 'Spree::TaxonImage'
|
|
@@ -5,7 +5,11 @@ module Spree
|
|
|
5
5
|
extend ActiveSupport::Concern
|
|
6
6
|
|
|
7
7
|
included do
|
|
8
|
-
|
|
8
|
+
if Spree.public_storage_service_name
|
|
9
|
+
has_one_attached :attachment, service: Spree.public_storage_service_name
|
|
10
|
+
else
|
|
11
|
+
has_one_attached :attachment
|
|
12
|
+
end
|
|
9
13
|
|
|
10
14
|
validates :attachment, content_type: /\Aimage\/.*\z/
|
|
11
15
|
|
|
@@ -6,10 +6,11 @@ module Spree
|
|
|
6
6
|
|
|
7
7
|
def styles
|
|
8
8
|
self.class.styles.map do |_, size|
|
|
9
|
-
width, height = size[/(\d+)x(\d+)/].split('x')
|
|
9
|
+
width, height = size[/(\d+)x(\d+)/].split('x').map(&:to_i)
|
|
10
10
|
|
|
11
11
|
{
|
|
12
|
-
url:
|
|
12
|
+
url: generate_url(size: size),
|
|
13
|
+
size: size,
|
|
13
14
|
width: width,
|
|
14
15
|
height: height
|
|
15
16
|
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
module Spree
|
|
2
2
|
class Taxonomy < Spree::Base
|
|
3
3
|
include Metadata
|
|
4
|
+
if defined?(Spree::Webhooks)
|
|
5
|
+
include Spree::Webhooks::HasWebhooks
|
|
6
|
+
end
|
|
4
7
|
|
|
5
8
|
acts_as_list
|
|
6
9
|
|
|
@@ -12,7 +15,7 @@ module Spree
|
|
|
12
15
|
belongs_to :store, class_name: 'Spree::Store'
|
|
13
16
|
|
|
14
17
|
after_create :set_root
|
|
15
|
-
|
|
18
|
+
after_update :set_root_taxon_name
|
|
16
19
|
|
|
17
20
|
default_scope { order("#{table_name}.position, #{table_name}.created_at") }
|
|
18
21
|
|
data/app/models/spree/variant.rb
CHANGED
|
@@ -5,20 +5,26 @@ module Spree
|
|
|
5
5
|
|
|
6
6
|
include MemoizedData
|
|
7
7
|
include Metadata
|
|
8
|
+
if defined?(Spree::Webhooks)
|
|
9
|
+
include Spree::Webhooks::HasWebhooks
|
|
10
|
+
end
|
|
8
11
|
|
|
9
12
|
MEMOIZED_METHODS = %w(purchasable in_stock backorderable tax_category options_text compare_at_price)
|
|
10
13
|
|
|
11
14
|
belongs_to :product, -> { with_deleted }, touch: true, class_name: 'Spree::Product', inverse_of: :variants
|
|
12
15
|
belongs_to :tax_category, class_name: 'Spree::TaxCategory', optional: true
|
|
13
16
|
|
|
14
|
-
delegate :name, :name=, :description, :slug, :available_on, :shipping_category_id,
|
|
17
|
+
delegate :name, :name=, :description, :slug, :available_on, :make_active_at, :shipping_category_id,
|
|
15
18
|
:meta_description, :meta_keywords, :shipping_category, to: :product
|
|
16
19
|
|
|
20
|
+
auto_strip_attributes :sku, nullify: false
|
|
21
|
+
|
|
17
22
|
# we need to have this callback before any dependent: :destroy associations
|
|
18
23
|
# https://github.com/rails/rails/issues/3458
|
|
19
|
-
before_destroy :
|
|
24
|
+
before_destroy :ensure_not_in_complete_orders
|
|
25
|
+
after_destroy :remove_line_items_from_incomplete_orders
|
|
20
26
|
|
|
21
|
-
# must include this after
|
|
27
|
+
# must include this after ensure_not_in_complete_orders to make sure price won't be deleted before validation
|
|
22
28
|
include Spree::DefaultPrice
|
|
23
29
|
|
|
24
30
|
with_options inverse_of: :variant do
|
|
@@ -140,7 +146,7 @@ module Spree
|
|
|
140
146
|
@tax_category ||= if self[:tax_category_id].nil?
|
|
141
147
|
product.tax_category
|
|
142
148
|
else
|
|
143
|
-
Spree::TaxCategory.
|
|
149
|
+
Spree::TaxCategory.find_by(id: self[:tax_category_id]) || product.tax_category
|
|
144
150
|
end
|
|
145
151
|
end
|
|
146
152
|
|
|
@@ -166,6 +172,8 @@ module Spree
|
|
|
166
172
|
|
|
167
173
|
def options=(options = {})
|
|
168
174
|
options.each do |option|
|
|
175
|
+
next if option[:name].blank? || option[:value].blank?
|
|
176
|
+
|
|
169
177
|
set_option_value(option[:name], option[:value])
|
|
170
178
|
end
|
|
171
179
|
end
|
|
@@ -174,12 +182,12 @@ module Spree
|
|
|
174
182
|
# no option values on master
|
|
175
183
|
return if is_master
|
|
176
184
|
|
|
177
|
-
option_type = Spree::OptionType.where(name
|
|
178
|
-
o.presentation = opt_name
|
|
185
|
+
option_type = Spree::OptionType.where(['LOWER(name) = ?', opt_name.downcase.strip]).first_or_initialize do |o|
|
|
186
|
+
o.name = o.presentation = opt_name
|
|
179
187
|
o.save!
|
|
180
188
|
end
|
|
181
189
|
|
|
182
|
-
current_value =
|
|
190
|
+
current_value = find_option_value(opt_name)
|
|
183
191
|
|
|
184
192
|
if current_value.nil?
|
|
185
193
|
# then we have to check to make sure that the product has the option type
|
|
@@ -187,13 +195,13 @@ module Spree
|
|
|
187
195
|
product.option_types << option_type
|
|
188
196
|
end
|
|
189
197
|
else
|
|
190
|
-
return if current_value.name == opt_value
|
|
198
|
+
return if current_value.name.downcase.strip == opt_value.downcase.strip
|
|
191
199
|
|
|
192
200
|
option_values.delete(current_value)
|
|
193
201
|
end
|
|
194
202
|
|
|
195
|
-
option_value =
|
|
196
|
-
o.presentation = opt_value
|
|
203
|
+
option_value = option_type.option_values.where(['LOWER(name) = ?', opt_value.downcase.strip]).first_or_initialize do |o|
|
|
204
|
+
o.name = o.presentation = opt_value
|
|
197
205
|
o.save!
|
|
198
206
|
end
|
|
199
207
|
|
|
@@ -201,12 +209,29 @@ module Spree
|
|
|
201
209
|
save
|
|
202
210
|
end
|
|
203
211
|
|
|
212
|
+
def find_option_value(opt_name)
|
|
213
|
+
option_values.detect { |o| o.option_type.name.downcase.strip == opt_name.downcase.strip }
|
|
214
|
+
end
|
|
215
|
+
|
|
204
216
|
def option_value(opt_name)
|
|
205
|
-
|
|
217
|
+
find_option_value(opt_name).try(:presentation)
|
|
206
218
|
end
|
|
207
219
|
|
|
208
220
|
def price_in(currency)
|
|
209
|
-
|
|
221
|
+
currency = currency&.upcase
|
|
222
|
+
find_or_build_price = lambda do
|
|
223
|
+
if prices.loaded?
|
|
224
|
+
prices.detect { |price| price.currency == currency } || prices.build(currency: currency)
|
|
225
|
+
else
|
|
226
|
+
prices.find_or_initialize_by(currency: currency)
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
Rails.cache.fetch("spree/prices/#{cache_key_with_version}/price_in/#{currency}") do
|
|
231
|
+
find_or_build_price.call
|
|
232
|
+
end
|
|
233
|
+
rescue TypeError
|
|
234
|
+
find_or_build_price.call
|
|
210
235
|
end
|
|
211
236
|
|
|
212
237
|
def amount_in(currency)
|
|
@@ -312,13 +337,17 @@ module Spree
|
|
|
312
337
|
|
|
313
338
|
private
|
|
314
339
|
|
|
315
|
-
def
|
|
316
|
-
if
|
|
340
|
+
def ensure_not_in_complete_orders
|
|
341
|
+
if orders.complete.any?
|
|
317
342
|
errors.add(:base, :cannot_destroy_if_attached_to_line_items)
|
|
318
343
|
throw(:abort)
|
|
319
344
|
end
|
|
320
345
|
end
|
|
321
346
|
|
|
347
|
+
def remove_line_items_from_incomplete_orders
|
|
348
|
+
Spree::Variants::RemoveFromIncompleteOrdersJob.perform_later(self)
|
|
349
|
+
end
|
|
350
|
+
|
|
322
351
|
def quantifier
|
|
323
352
|
Spree::Stock::Quantifier.new(self)
|
|
324
353
|
end
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
module Spree
|
|
2
2
|
class Wishlist < Spree::Base
|
|
3
3
|
include SingleStoreResource
|
|
4
|
+
if defined?(Spree::Webhooks)
|
|
5
|
+
include Spree::Webhooks::HasWebhooks
|
|
6
|
+
end
|
|
4
7
|
|
|
5
8
|
has_secure_token
|
|
6
9
|
|
|
7
|
-
belongs_to :user, class_name: Spree.user_class
|
|
10
|
+
belongs_to :user, class_name: "::#{Spree.user_class}", touch: true
|
|
8
11
|
belongs_to :store, class_name: 'Spree::Store'
|
|
9
12
|
|
|
10
13
|
has_many :wished_items, class_name: 'Spree::WishedItem', dependent: :destroy
|
data/app/models/spree/zone.rb
CHANGED
|
@@ -7,7 +7,7 @@ module Spree
|
|
|
7
7
|
attr_accessor :country
|
|
8
8
|
|
|
9
9
|
def call(address_params: {}, user: nil)
|
|
10
|
-
fill_country_and_state_ids(address_params)
|
|
10
|
+
address_params = fill_country_and_state_ids(address_params)
|
|
11
11
|
|
|
12
12
|
address = Spree::Address.new(address_params)
|
|
13
13
|
address.user = user if user.present?
|
|
@@ -8,12 +8,17 @@ module Spree
|
|
|
8
8
|
|
|
9
9
|
def call(address:, address_params:)
|
|
10
10
|
address_params[:country_id] ||= address.country_id
|
|
11
|
-
fill_country_and_state_ids(address_params)
|
|
11
|
+
address_params = fill_country_and_state_ids(address_params)
|
|
12
12
|
|
|
13
13
|
if address&.editable?
|
|
14
14
|
address.update(address_params) ? success(address) : failure(address)
|
|
15
15
|
else
|
|
16
|
-
new_address(address_params).valid?
|
|
16
|
+
if new_address(address_params).valid?
|
|
17
|
+
address.destroy
|
|
18
|
+
success(new_address)
|
|
19
|
+
else
|
|
20
|
+
failure(new_address)
|
|
21
|
+
end
|
|
17
22
|
end
|
|
18
23
|
end
|
|
19
24
|
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Variants
|
|
3
|
+
class RemoveLineItems
|
|
4
|
+
prepend Spree::ServiceModule::Base
|
|
5
|
+
|
|
6
|
+
def call(variant:)
|
|
7
|
+
variant.line_items.joins(:order).where.not(spree_orders: { state: 'complete' }).find_each do |line_item|
|
|
8
|
+
Spree::Variants::RemoveLineItemJob.perform_later(line_item: line_item)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
success(true)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
data/config/locales/en.yml
CHANGED
|
@@ -91,6 +91,7 @@ en:
|
|
|
91
91
|
name: Name
|
|
92
92
|
spree/product:
|
|
93
93
|
available_on: Available On
|
|
94
|
+
make_active_at: Make Active At
|
|
94
95
|
discontinue_on: Discontinue On
|
|
95
96
|
cost_currency: Cost Currency
|
|
96
97
|
cost_price: Cost Price
|
|
@@ -360,7 +361,7 @@ en:
|
|
|
360
361
|
discontinue_on:
|
|
361
362
|
invalid_date_range: must be later than available date
|
|
362
363
|
base:
|
|
363
|
-
cannot_destroy_if_attached_to_line_items: Cannot delete
|
|
364
|
+
cannot_destroy_if_attached_to_line_items: Cannot delete Products that are added to placed Orders. In such cases, please discontinue them.
|
|
364
365
|
spree/refund:
|
|
365
366
|
attributes:
|
|
366
367
|
amount:
|
|
@@ -397,7 +398,7 @@ en:
|
|
|
397
398
|
spree/variant:
|
|
398
399
|
attributes:
|
|
399
400
|
base:
|
|
400
|
-
cannot_destroy_if_attached_to_line_items: Cannot delete
|
|
401
|
+
cannot_destroy_if_attached_to_line_items: Cannot delete Variants that are added to placed Orders. In such cases, please discontinue them.
|
|
401
402
|
no_master_variant_found_to_infer_price: No master variant found to infer price
|
|
402
403
|
must_supply_price_for_variant_or_master: Must supply price for variant or master price for product.
|
|
403
404
|
spree/image:
|
|
@@ -583,6 +584,7 @@ en:
|
|
|
583
584
|
auto_capture: Auto Capture
|
|
584
585
|
availability: availability
|
|
585
586
|
available_on: Available On
|
|
587
|
+
make_active_at: Make Active At
|
|
586
588
|
available: Available
|
|
587
589
|
average_order_value: Average Order Value
|
|
588
590
|
avs_response: AVS Response
|
|
@@ -1120,6 +1122,7 @@ en:
|
|
|
1120
1122
|
number: Number
|
|
1121
1123
|
ok: OK
|
|
1122
1124
|
on_hand: On Hand
|
|
1125
|
+
only_active_products_can_be_added_to_cart: Draft and archived products cannot be added to cart, please mark the product as active before.
|
|
1123
1126
|
open: Open
|
|
1124
1127
|
open_all_adjustments: Open All Adjustments
|
|
1125
1128
|
option_type: Option Type
|