spree_core 4.4.0 → 4.6.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/option_values/find_available.rb +1 -1
- data/app/finders/spree/product_properties/find_available.rb +1 -1
- data/app/finders/spree/products/find.rb +21 -15
- data/app/finders/spree/taxons/find.rb +11 -8
- data/app/helpers/spree/base_helper.rb +14 -11
- 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 +34 -28
- data/app/models/concerns/spree/translatable_resource.rb +25 -0
- data/app/models/concerns/spree/translatable_resource_scopes.rb +24 -0
- data/app/models/concerns/spree/translatable_resource_slug.rb +17 -0
- 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/base.rb +1 -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/data_feed/google.rb +15 -0
- data/app/models/spree/data_feed.rb +40 -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 +9 -1
- data/app/models/spree/menu.rb +3 -0
- data/app/models/spree/menu_item.rb +7 -11
- data/app/models/spree/option_type.rb +8 -0
- data/app/models/spree/option_value.rb +9 -0
- data/app/models/spree/order/address_book.rb +1 -0
- data/app/models/spree/order.rb +12 -3
- 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 +97 -24
- data/app/models/spree/product_property.rb +13 -3
- 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 +10 -1
- 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 +8 -1
- 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 +39 -15
- 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 +26 -7
- 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 +8 -1
- data/app/models/spree/variant.rb +47 -21
- 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/data_feeds/google/optional_attributes.rb +23 -0
- data/app/services/spree/data_feeds/google/optional_sub_attributes.rb +21 -0
- data/app/services/spree/data_feeds/google/products_list.rb +14 -0
- data/app/services/spree/data_feeds/google/required_attributes.rb +67 -0
- data/app/services/spree/data_feeds/google/rss.rb +107 -0
- data/app/services/spree/variants/remove_line_items.rb +15 -0
- data/app/sorters/spree/products/sort.rb +23 -0
- data/brakeman.ignore +326 -18
- data/config/initializers/friendly_id.rb +2 -0
- data/config/initializers/mobility.rb +18 -0
- data/config/locales/en.yml +6 -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/db/migrate/20220706112554_create_product_name_and_description_translations_for_mobility_table_backend.rb +27 -0
- data/db/migrate/20220715083542_create_spree_product_translations_for_mobility.rb +7 -0
- data/db/migrate/20220715120222_change_product_name_null_to_true.rb +5 -0
- data/db/migrate/20220718100743_create_spree_taxon_name_and_description_translations_for_mobility_table_backend.rb +27 -0
- data/db/migrate/20220718100948_change_taxon_name_null_to_true.rb +5 -0
- data/db/migrate/20220802070609_add_locale_to_friendly_id_slugs.rb +11 -0
- data/db/migrate/20220802073225_create_spree_product_slug_translations_for_mobility_table_backend.rb +5 -0
- data/db/migrate/20220804073928_transfer_data_to_translatable_tables.rb +66 -0
- data/db/migrate/20221215151408_add_selected_locale_to_spree_users.rb +8 -0
- data/db/migrate/20221219123957_add_deleted_at_to_product_translations.rb +6 -0
- data/db/migrate/20221220133432_add_uniqueness_constraint_to_product_translations.rb +5 -0
- data/db/migrate/20221229132350_create_spree_data_feed_settings.rb +14 -0
- data/db/migrate/20230103144439_create_option_type_translations.rb +26 -0
- data/db/migrate/20230103151034_create_option_value_translations.rb +26 -0
- data/db/migrate/20230109084253_create_product_property_translations.rb +25 -0
- data/db/migrate/20230109094907_transfer_options_data_to_translatable_tables.rb +58 -0
- data/db/migrate/20230109105943_create_property_translations.rb +26 -0
- data/db/migrate/20230109110840_transfer_property_data_to_translatable_tables.rb +59 -0
- data/db/migrate/20230110142344_backfill_friendly_id_slug_locale.rb +15 -0
- data/db/migrate/20230111121534_add_additional_taxon_translation_fields.rb +8 -0
- data/db/migrate/20230111122511_transfer_product_and_taxon_data_to_translatable_tables.rb +82 -0
- data/db/migrate/20230117115531_create_taxonomy_translations.rb +24 -0
- data/db/migrate/20230117120430_allow_null_taxonomy_name.rb +5 -0
- data/db/migrate/20230117121303_transfer_taxonomy_data_to_translatable_tables.rb +11 -0
- data/db/migrate/20230210142732_create_store_translations.rb +50 -0
- data/db/migrate/20230210142849_transfer_store_data_to_translatable_tables.rb +11 -0
- data/db/migrate/20230210230434_add_deleted_at_to_store_translations.rb +6 -0
- data/db/migrate/20230415155958_rename_data_feed_settings_table.rb +5 -0
- data/db/migrate/20230415160828_rename_data_feed_table_columns.rb +7 -0
- data/db/migrate/20230415161226_add_indexes_to_data_feeds_table.rb +5 -0
- data/db/migrate/20230512094803_rename_data_feeds_column_provider_to_type.rb +5 -0
- data/db/migrate/20230514162157_add_index_on_locale_and_permalink_to_spree_taxons.rb +5 -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 +91 -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 +34 -8
- 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 +106 -0
- data/lib/spree/core/dependencies_helper.rb +19 -0
- data/lib/spree/core/engine.rb +53 -38
- 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/product_duplicator.rb +1 -1
- data/lib/spree/core/product_filters.rb +7 -4
- data/lib/spree/core/search/base.rb +10 -6
- data/lib/spree/core/version.rb +1 -1
- data/lib/spree/core.rb +27 -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/google_data_feed_factory.rb +8 -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 +12 -1
- data/lib/spree/testing_support/factories/product_property_factory.rb +1 -0
- data/lib/spree/testing_support/factories/product_translation_factory.rb +6 -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 +2 -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 +8 -0
- data/lib/spree/translation_migrations.rb +40 -0
- data/lib/spree_core.rb +2 -1
- data/lib/tasks/core.rake +12 -0
- data/spree_core.gemspec +5 -3
- metadata +152 -52
- 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
- /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/app/models/spree/store.rb
CHANGED
@@ -1,5 +1,24 @@
|
|
1
1
|
module Spree
|
2
2
|
class Store < Spree::Base
|
3
|
+
include TranslatableResource
|
4
|
+
if defined?(Spree::Webhooks)
|
5
|
+
include Spree::Webhooks::HasWebhooks
|
6
|
+
end
|
7
|
+
if defined?(Spree::Security::Stores)
|
8
|
+
include Spree::Security::Stores
|
9
|
+
end
|
10
|
+
|
11
|
+
TRANSLATABLE_FIELDS = %i[name meta_description meta_keywords seo_title facebook
|
12
|
+
twitter instagram customer_support_email description
|
13
|
+
address contact_phone new_order_notifications_email].freeze
|
14
|
+
translates(*TRANSLATABLE_FIELDS)
|
15
|
+
|
16
|
+
self::Translation.class_eval do
|
17
|
+
acts_as_paranoid
|
18
|
+
# deleted translation values still need to be accessible - remove deleted_at scope
|
19
|
+
default_scope { unscope(where: :deleted_at) }
|
20
|
+
end
|
21
|
+
|
3
22
|
typed_store :settings, coder: ActiveRecord::TypedStore::IdentityCoder do |s|
|
4
23
|
# Spree Digital Asset Configurations
|
5
24
|
s.boolean :limit_digital_download_count, default: true, null: false
|
@@ -9,8 +28,7 @@ module Spree
|
|
9
28
|
s.integer :digital_asset_link_expire_time, default: 300, null: false # 5 minutes in seconds
|
10
29
|
end
|
11
30
|
|
12
|
-
|
13
|
-
FAVICON_CONTENT_TYPES = ['image/png', 'image/x-icon', 'image/vnd.microsoft.icon'].freeze
|
31
|
+
attr_accessor :skip_validate_not_last
|
14
32
|
|
15
33
|
acts_as_paranoid
|
16
34
|
|
@@ -49,6 +67,8 @@ module Spree
|
|
49
67
|
|
50
68
|
has_many :wishlists, class_name: 'Spree::Wishlist'
|
51
69
|
|
70
|
+
has_many :data_feeds, class_name: 'Spree::DataFeed'
|
71
|
+
|
52
72
|
belongs_to :default_country, class_name: 'Spree::Country'
|
53
73
|
belongs_to :checkout_zone, class_name: 'Spree::Zone'
|
54
74
|
|
@@ -58,7 +78,7 @@ module Spree
|
|
58
78
|
|
59
79
|
validates :digital_asset_authorized_clicks, numericality: { only_integer: true, greater_than: 0 }
|
60
80
|
validates :digital_asset_authorized_days, numericality: { only_integer: true, greater_than: 0 }
|
61
|
-
validates :code, uniqueness: { conditions: -> { with_deleted } }
|
81
|
+
validates :code, uniqueness: { case_sensitive: false, conditions: -> { with_deleted } }
|
62
82
|
validates :mail_from_address, email: { allow_blank: false }
|
63
83
|
|
64
84
|
# FIXME: we should remove this condition in v5
|
@@ -71,19 +91,18 @@ module Spree
|
|
71
91
|
|
72
92
|
default_scope { order(created_at: :asc) }
|
73
93
|
|
74
|
-
|
75
|
-
|
76
|
-
|
94
|
+
has_one :logo, class_name: 'Spree::StoreLogo', dependent: :destroy, as: :viewable
|
95
|
+
accepts_nested_attributes_for :logo, reject_if: :all_blank
|
96
|
+
|
97
|
+
has_one :mailer_logo, class_name: 'Spree::StoreMailerLogo', dependent: :destroy, as: :viewable
|
98
|
+
accepts_nested_attributes_for :mailer_logo, reject_if: :all_blank
|
77
99
|
|
78
|
-
|
79
|
-
|
80
|
-
dimension: { max: 256..256 },
|
81
|
-
aspect_ratio: :square,
|
82
|
-
size: { less_than_or_equal_to: 1.megabyte }
|
100
|
+
has_one :favicon_image, class_name: 'Spree::StoreFaviconImage', dependent: :destroy, as: :viewable
|
101
|
+
accepts_nested_attributes_for :favicon_image, reject_if: :all_blank
|
83
102
|
|
84
103
|
before_save :ensure_default_exists_and_is_unique
|
85
104
|
before_save :ensure_supported_currencies, :ensure_supported_locales, :ensure_default_country
|
86
|
-
before_destroy :validate_not_last
|
105
|
+
before_destroy :validate_not_last, unless: :skip_validate_not_last
|
87
106
|
before_destroy :pass_default_flag_to_other_store
|
88
107
|
|
89
108
|
scope :by_url, ->(url) { where('url like ?', "%#{url}%") }
|
@@ -104,7 +123,12 @@ module Spree
|
|
104
123
|
# this behaviour is very buggy and unpredictable
|
105
124
|
def self.default
|
106
125
|
Rails.cache.fetch('default_store') do
|
107
|
-
|
126
|
+
# workaround for Mobility bug with first_or_initialize
|
127
|
+
if where(default: true).any?
|
128
|
+
where(default: true).first
|
129
|
+
else
|
130
|
+
new(default: true)
|
131
|
+
end
|
108
132
|
end
|
109
133
|
end
|
110
134
|
|
@@ -176,9 +200,9 @@ module Spree
|
|
176
200
|
end
|
177
201
|
|
178
202
|
def favicon
|
179
|
-
return unless favicon_image
|
203
|
+
return unless favicon_image&.attachment&.attached?
|
180
204
|
|
181
|
-
favicon_image.variant(
|
205
|
+
favicon_image.attachment.variant(resize_to_limit: [32, 32])
|
182
206
|
end
|
183
207
|
|
184
208
|
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
@@ -3,7 +3,12 @@ require 'stringex'
|
|
3
3
|
|
4
4
|
module Spree
|
5
5
|
class Taxon < Spree::Base
|
6
|
+
include TranslatableResource
|
7
|
+
include TranslatableResourceSlug
|
6
8
|
include Metadata
|
9
|
+
if defined?(Spree::Webhooks)
|
10
|
+
include Spree::Webhooks::HasWebhooks
|
11
|
+
end
|
7
12
|
|
8
13
|
extend FriendlyId
|
9
14
|
friendly_id :permalink, slug_column: :permalink, use: :history
|
@@ -24,7 +29,7 @@ module Spree
|
|
24
29
|
has_many :promotion_rule_taxons, class_name: 'Spree::PromotionRuleTaxon', dependent: :destroy
|
25
30
|
has_many :promotion_rules, through: :promotion_rule_taxons, class_name: 'Spree::PromotionRule'
|
26
31
|
|
27
|
-
validates :name, presence: true, uniqueness: { scope: [:parent_id, :taxonomy_id],
|
32
|
+
validates :name, presence: true, uniqueness: { scope: [:parent_id, :taxonomy_id], case_sensitive: false }
|
28
33
|
validates :taxonomy, presence: true
|
29
34
|
validates :permalink, uniqueness: { case_sensitive: false, scope: [:parent_id, :taxonomy_id] }
|
30
35
|
validates :hide_from_nav, inclusion: { in: [true, false] }
|
@@ -39,7 +44,7 @@ module Spree
|
|
39
44
|
|
40
45
|
before_validation :copy_taxonomy_from_parent
|
41
46
|
after_save :touch_ancestors_and_taxonomy
|
42
|
-
|
47
|
+
after_update :sync_taxonomy_name
|
43
48
|
after_touch :touch_ancestors_and_taxonomy
|
44
49
|
|
45
50
|
has_one :icon, as: :viewable, dependent: :destroy, class_name: 'Spree::TaxonImage'
|
@@ -51,6 +56,24 @@ module Spree
|
|
51
56
|
|
52
57
|
scope :for_stores, ->(stores) { joins(:taxonomy).where(spree_taxonomies: { store_id: stores.ids }) }
|
53
58
|
|
59
|
+
TRANSLATABLE_FIELDS = %i[name description permalink].freeze
|
60
|
+
translates(*TRANSLATABLE_FIELDS)
|
61
|
+
|
62
|
+
self::Translation.class_eval do
|
63
|
+
alias_attribute :slug, :permalink
|
64
|
+
|
65
|
+
before_create :set_permalink
|
66
|
+
|
67
|
+
def set_permalink
|
68
|
+
parent = translated_model.parent
|
69
|
+
if parent.present?
|
70
|
+
self.permalink = [parent.permalink, (permalink.blank? ? name.to_url : permalink.split('/').last)].join('/')
|
71
|
+
else
|
72
|
+
self.permalink = name.to_url if permalink.blank?
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
54
77
|
# indicate which filters should be used for a taxon
|
55
78
|
# this method should be customized to your own site
|
56
79
|
def applicable_filters
|
@@ -70,11 +93,7 @@ module Spree
|
|
70
93
|
|
71
94
|
# Creates permalink base for friendly_id
|
72
95
|
def set_permalink
|
73
|
-
|
74
|
-
self.permalink = [parent.permalink, (permalink.blank? ? name.to_url : permalink.split('/').last)].join('/')
|
75
|
-
else
|
76
|
-
self.permalink = name.to_url if permalink.blank?
|
77
|
-
end
|
96
|
+
translations.each(&:set_permalink)
|
78
97
|
end
|
79
98
|
|
80
99
|
def active_products
|
@@ -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,13 @@
|
|
1
1
|
module Spree
|
2
2
|
class Taxonomy < Spree::Base
|
3
|
+
include TranslatableResource
|
3
4
|
include Metadata
|
5
|
+
if defined?(Spree::Webhooks)
|
6
|
+
include Spree::Webhooks::HasWebhooks
|
7
|
+
end
|
8
|
+
|
9
|
+
TRANSLATABLE_FIELDS = %i[name].freeze
|
10
|
+
translates(*TRANSLATABLE_FIELDS)
|
4
11
|
|
5
12
|
acts_as_list
|
6
13
|
|
@@ -12,7 +19,7 @@ module Spree
|
|
12
19
|
belongs_to :store, class_name: 'Spree::Store'
|
13
20
|
|
14
21
|
after_create :set_root
|
15
|
-
|
22
|
+
after_update :set_root_taxon_name
|
16
23
|
|
17
24
|
default_scope { order("#{table_name}.position, #{table_name}.created_at") }
|
18
25
|
|
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
|
@@ -116,16 +122,13 @@ module Spree
|
|
116
122
|
self.whitelisted_ransackable_scopes = %i(product_name_or_sku_cont search_by_product_name_or_sku)
|
117
123
|
|
118
124
|
def self.product_name_or_sku_cont(query)
|
119
|
-
joins(:product).
|
125
|
+
joins(:product).join_translation_table(Product).
|
126
|
+
where("LOWER(#{Product.translation_table_alias}.name) LIKE LOWER(:query)
|
127
|
+
OR LOWER(sku) LIKE LOWER(:query)", query: "%#{query}%")
|
120
128
|
end
|
121
129
|
|
122
130
|
def self.search_by_product_name_or_sku(query)
|
123
|
-
|
124
|
-
joins(product: :translations).where("LOWER(#{Product::Translation.table_name}.name) LIKE LOWER(:query) OR LOWER(sku) LIKE LOWER(:query)",
|
125
|
-
query: "%#{query}%")
|
126
|
-
else
|
127
|
-
product_name_or_sku_cont(query)
|
128
|
-
end
|
131
|
+
product_name_or_sku_cont(query)
|
129
132
|
end
|
130
133
|
|
131
134
|
def available?
|
@@ -140,7 +143,7 @@ module Spree
|
|
140
143
|
@tax_category ||= if self[:tax_category_id].nil?
|
141
144
|
product.tax_category
|
142
145
|
else
|
143
|
-
Spree::TaxCategory.
|
146
|
+
Spree::TaxCategory.find_by(id: self[:tax_category_id]) || product.tax_category
|
144
147
|
end
|
145
148
|
end
|
146
149
|
|
@@ -166,6 +169,8 @@ module Spree
|
|
166
169
|
|
167
170
|
def options=(options = {})
|
168
171
|
options.each do |option|
|
172
|
+
next if option[:name].blank? || option[:value].blank?
|
173
|
+
|
169
174
|
set_option_value(option[:name], option[:value])
|
170
175
|
end
|
171
176
|
end
|
@@ -174,12 +179,12 @@ module Spree
|
|
174
179
|
# no option values on master
|
175
180
|
return if is_master
|
176
181
|
|
177
|
-
option_type = Spree::OptionType.where(name
|
178
|
-
o.presentation = opt_name
|
182
|
+
option_type = Spree::OptionType.where(['LOWER(name) = ?', opt_name.downcase.strip]).first_or_initialize do |o|
|
183
|
+
o.name = o.presentation = opt_name
|
179
184
|
o.save!
|
180
185
|
end
|
181
186
|
|
182
|
-
current_value =
|
187
|
+
current_value = find_option_value(opt_name)
|
183
188
|
|
184
189
|
if current_value.nil?
|
185
190
|
# then we have to check to make sure that the product has the option type
|
@@ -187,13 +192,13 @@ module Spree
|
|
187
192
|
product.option_types << option_type
|
188
193
|
end
|
189
194
|
else
|
190
|
-
return if current_value.name == opt_value
|
195
|
+
return if current_value.name.downcase.strip == opt_value.downcase.strip
|
191
196
|
|
192
197
|
option_values.delete(current_value)
|
193
198
|
end
|
194
199
|
|
195
|
-
option_value =
|
196
|
-
o.presentation = opt_value
|
200
|
+
option_value = option_type.option_values.where(['LOWER(name) = ?', opt_value.downcase.strip]).first_or_initialize do |o|
|
201
|
+
o.name = o.presentation = opt_value
|
197
202
|
o.save!
|
198
203
|
end
|
199
204
|
|
@@ -201,12 +206,29 @@ module Spree
|
|
201
206
|
save
|
202
207
|
end
|
203
208
|
|
209
|
+
def find_option_value(opt_name)
|
210
|
+
option_values.detect { |o| o.option_type.name.downcase.strip == opt_name.downcase.strip }
|
211
|
+
end
|
212
|
+
|
204
213
|
def option_value(opt_name)
|
205
|
-
|
214
|
+
find_option_value(opt_name).try(:presentation)
|
206
215
|
end
|
207
216
|
|
208
217
|
def price_in(currency)
|
209
|
-
|
218
|
+
currency = currency&.upcase
|
219
|
+
find_or_build_price = lambda do
|
220
|
+
if prices.loaded?
|
221
|
+
prices.detect { |price| price.currency == currency } || prices.build(currency: currency)
|
222
|
+
else
|
223
|
+
prices.find_or_initialize_by(currency: currency)
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
Rails.cache.fetch("spree/prices/#{cache_key_with_version}/price_in/#{currency}") do
|
228
|
+
find_or_build_price.call
|
229
|
+
end
|
230
|
+
rescue TypeError
|
231
|
+
find_or_build_price.call
|
210
232
|
end
|
211
233
|
|
212
234
|
def amount_in(currency)
|
@@ -312,13 +334,17 @@ module Spree
|
|
312
334
|
|
313
335
|
private
|
314
336
|
|
315
|
-
def
|
316
|
-
if
|
337
|
+
def ensure_not_in_complete_orders
|
338
|
+
if orders.complete.any?
|
317
339
|
errors.add(:base, :cannot_destroy_if_attached_to_line_items)
|
318
340
|
throw(:abort)
|
319
341
|
end
|
320
342
|
end
|
321
343
|
|
344
|
+
def remove_line_items_from_incomplete_orders
|
345
|
+
Spree::Variants::RemoveFromIncompleteOrdersJob.perform_later(self)
|
346
|
+
end
|
347
|
+
|
322
348
|
def quantifier
|
323
349
|
Spree::Stock::Quantifier.new(self)
|
324
350
|
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,23 @@
|
|
1
|
+
module Spree
|
2
|
+
module DataFeeds
|
3
|
+
module Google
|
4
|
+
class OptionalAttributes
|
5
|
+
prepend Spree::ServiceModule::Base
|
6
|
+
|
7
|
+
def call(input)
|
8
|
+
information = {}
|
9
|
+
|
10
|
+
input[:product].property_ids.each do |key|
|
11
|
+
name = Spree::Property.find(key)&.name
|
12
|
+
value = input[:product].property(name)
|
13
|
+
unless value.nil?
|
14
|
+
information[name] = value
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
success(information: information)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Spree
|
2
|
+
module DataFeeds
|
3
|
+
module Google
|
4
|
+
class OptionalSubAttributes
|
5
|
+
prepend Spree::ServiceModule::Base
|
6
|
+
|
7
|
+
def call(input)
|
8
|
+
information = {}
|
9
|
+
|
10
|
+
# This is a place where you can put attributes that have sub-attributes, example for shipping:
|
11
|
+
#
|
12
|
+
# information['shipping'] = {}
|
13
|
+
# information['shipping']['price'] = calculate_shipping(input[:product])
|
14
|
+
# information['shipping']['country'] = input[:store].default_country
|
15
|
+
|
16
|
+
success(information: information)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|