spree_core 4.4.0 → 4.6.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/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
|