spree_core 4.4.0 → 4.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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/fulfilment_changer.rb +1 -1
- 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.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/{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
- 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 +63 -51
- data/app/models/friendly_id/slug_decorator.rb +0 -9
- data/app/models/spree/app_configuration.rb +0 -86
- data/lib/friendly_id/slug_rails5_patch.rb +0 -11
- data/lib/spree/core/app_dependencies.rb +0 -126
@@ -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
|