spree_core 4.0.7 → 4.1.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/spree.js +0 -1
  3. data/app/finders/spree/products/find.rb +19 -6
  4. data/app/finders/spree/variants/option_types_finder.rb +21 -0
  5. data/app/finders/spree/variants/visible_finder.rb +22 -0
  6. data/app/helpers/spree/base_helper.rb +48 -18
  7. data/app/helpers/spree/products_helper.rb +76 -8
  8. data/app/models/concerns/spree/user_methods.rb +2 -2
  9. data/app/models/spree/app_dependencies.rb +1 -7
  10. data/app/models/spree/credit_card.rb +4 -5
  11. data/app/models/spree/image.rb +52 -3
  12. data/app/models/spree/image/configuration/active_storage.rb +9 -1
  13. data/app/models/spree/line_item.rb +1 -2
  14. data/app/models/spree/option_type.rb +4 -0
  15. data/app/models/spree/order.rb +12 -12
  16. data/app/models/spree/order/address_book.rb +20 -7
  17. data/app/models/spree/payment_method.rb +8 -0
  18. data/app/models/spree/preferences/preferable.rb +1 -1
  19. data/app/models/spree/product.rb +7 -6
  20. data/app/models/spree/promotion/actions/create_item_adjustments.rb +1 -1
  21. data/app/models/spree/promotion_handler/coupon.rb +2 -1
  22. data/app/models/spree/return_item/eligibility_validator/base_validator.rb +1 -1
  23. data/app/models/spree/store.rb +2 -1
  24. data/app/models/spree/taxon.rb +2 -6
  25. data/app/models/spree/variant.rb +2 -14
  26. data/app/models/spree/zone.rb +6 -3
  27. data/app/presenters/spree/product_summary_presenter.rb +26 -0
  28. data/app/presenters/spree/variant_presenter.rb +69 -0
  29. data/app/presenters/spree/variants/option_types_presenter.rb +74 -0
  30. data/app/presenters/spree/variants/options_presenter.rb +49 -0
  31. data/app/services/spree/checkout/get_shipping_rates.rb +10 -7
  32. data/app/services/spree/checkout/update.rb +2 -13
  33. data/config/locales/en.yml +156 -14
  34. data/db/default/spree/stores.rb +8 -3
  35. data/db/migrate/20140309033438_create_store_from_preferences.rb +8 -4
  36. data/db/migrate/20191005121504_add_store_id_to_payment_methods.rb +7 -0
  37. data/db/migrate/20191016134113_add_deafult_value_for_store_default_currency.rb +5 -0
  38. data/db/migrate/20200102141311_add_social_to_spree_stores.rb +7 -0
  39. data/lib/generators/spree/dummy/dummy_generator.rb +2 -1
  40. data/lib/generators/spree/dummy/templates/initializers/bullet.rb +5 -0
  41. data/lib/generators/spree/install/install_generator.rb +13 -5
  42. data/lib/generators/spree/install/templates/config/initializers/spree.rb +0 -1
  43. data/lib/generators/spree/install/templates/config/initializers/spree_storefront.rb +1 -0
  44. data/lib/generators/spree/install/templates/config/spree_storefront.yml +67 -0
  45. data/lib/spree/core.rb +0 -1
  46. data/lib/spree/core/controller_helpers/order.rb +12 -6
  47. data/lib/spree/core/controller_helpers/store.rb +2 -2
  48. data/lib/spree/core/search/base.rb +59 -22
  49. data/lib/spree/core/version.rb +1 -3
  50. data/lib/spree/money.rb +8 -1
  51. data/lib/spree/permitted_attributes.rb +3 -2
  52. data/lib/spree/testing_support/capybara_ext.rb +0 -45
  53. data/lib/spree/testing_support/common_rake.rb +1 -1
  54. data/lib/spree/testing_support/factories/store_factory.rb +3 -0
  55. data/lib/spree/testing_support/order_walkthrough.rb +7 -3
  56. data/spree_core.gemspec +8 -14
  57. metadata +45 -24
  58. data/app/finders/spree/addresses/find.rb +0 -17
  59. data/app/services/spree/account/addresses/base.rb +0 -39
  60. data/app/services/spree/account/addresses/create.rb +0 -18
  61. data/app/services/spree/account/addresses/update.rb +0 -18
  62. data/lib/spree/database_type_utilities.rb +0 -12
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 24d8697b01ebe0da73f0747dc3ddc9a45522db809a92ebc93a97dc9e8c4fccef
4
- data.tar.gz: 691bcf5bba6d78868abb9b39893b63737398dae79d5e939381cc9c02ef6a6286
3
+ metadata.gz: db73357d472e46822ad95d6ee2071b01413e2f1ab743177f7cfc8845c6830092
4
+ data.tar.gz: 83c396103e3809183ac12c21f72e4831cb2c10d1089232bdecd58395459a961b
5
5
  SHA512:
6
- metadata.gz: 79a9d22bd03b122d64e7bf5a2505df120e4671442945eb2c2c0d8a63be3a592f344252730add4fde3bbf757282d9016fb8e2f6cf21b405415b6094d45d0407cf
7
- data.tar.gz: c12bb814fa2b091c153e5ebdc18c33c645ae6e5c40e4d0bf78e2fd36bc712f3017ee7b0149904402bca5376193e496df652a56cfed8486a908ee59b35e4d83ab
6
+ metadata.gz: f57f8d0b1bee1cb0b0d77b7aa82ac8f62d89a783e07dbd1e5f2a8a6d780eaf8de46ccf5e898420d423fe1d133ce2645615cd4611580ca92008d006c059667e1a
7
+ data.tar.gz: 7e3aee2e5bcc514a78dcc8da3cfb5b35635f691fc2fe9ac68002c9cd208bc96b5df4f784da4612cf1ad409dea467e0a5c29cc13e156e25aa7baeb5d72f367f47
@@ -2,7 +2,6 @@
2
2
  function Spree () {}
3
3
 
4
4
  Spree.ready = function (callback) {
5
- jQuery(callback)
6
5
  return jQuery(document).on('page:load turbolinks:load', function () {
7
6
  return callback(jQuery)
8
7
  })
@@ -112,17 +112,30 @@ module Spree
112
112
  def by_options(products)
113
113
  return products unless options?
114
114
 
115
- products.where(
116
- id: options.map do |key, value|
117
- products.with_option_value(key, value).ids
118
- end.flatten.compact.uniq
119
- )
115
+ options.map do |key, value|
116
+ products.with_option_value(key, value)
117
+ end.inject(:&)
120
118
  end
121
119
 
122
120
  def by_option_value_ids(products)
123
121
  return products unless option_value_ids?
124
122
 
125
- products.joins(variants: :option_values).distinct.where(spree_option_values: { id: option_value_ids })
123
+ product_ids = Spree::Product.
124
+ joins(variants: :option_values).
125
+ where(spree_option_values: { id: option_value_ids }).
126
+ group("#{Spree::Product.table_name}.id, #{Spree::Variant.table_name}.id").
127
+ having('COUNT(spree_option_values.option_type_id) = ?', option_types_count(option_value_ids)).
128
+ distinct.
129
+ ids
130
+
131
+ products.where(id: product_ids)
132
+ end
133
+
134
+ def option_types_count(option_value_ids)
135
+ Spree::OptionValue.
136
+ where(id: option_value_ids).
137
+ distinct.
138
+ count(:option_type_id)
126
139
  end
127
140
 
128
141
  def ordered(products)
@@ -0,0 +1,21 @@
1
+ module Spree
2
+ module Variants
3
+ class OptionTypesFinder
4
+ COLOR_TYPE = 'color'.freeze
5
+
6
+ def initialize(variant_ids:)
7
+ @variant_ids = variant_ids
8
+ end
9
+
10
+ def execute
11
+ Spree::OptionType.includes(option_values: :variants).where(spree_variants: { id: variant_ids }).
12
+ reorder('spree_option_types.position ASC, spree_option_values.position ASC').
13
+ partition { |option_type| option_type.name.downcase == COLOR_TYPE }.flatten
14
+ end
15
+
16
+ private
17
+
18
+ attr_reader :variant_ids
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,22 @@
1
+ module Spree
2
+ module Variants
3
+ class VisibleFinder
4
+ def initialize(scope:, current_currency:)
5
+ @scope = scope
6
+ @current_currency = current_currency
7
+ end
8
+
9
+ def execute
10
+ Spree::Variant.where(id: active_variants).joins(:option_values).order('spree_option_values.position ASC')
11
+ end
12
+
13
+ private
14
+
15
+ attr_reader :scope, :current_currency
16
+
17
+ def active_variants
18
+ scope.active(current_currency).unscope(:order)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -32,8 +32,12 @@ module Spree
32
32
  end
33
33
  end
34
34
 
35
- def logo(image_path = Spree::Config[:logo])
36
- link_to image_tag(image_path), spree.respond_to?(:root_path) ? spree.root_path : main_app.root_path
35
+ def logo(image_path = Spree::Config[:logo], options = {})
36
+ path = spree.respond_to?(:root_path) ? spree.root_path : main_app.root_path
37
+
38
+ link_to path, 'aria-label': current_store.name, method: options[:method] do
39
+ image_tag image_path, alt: current_store.name, title: current_store.name
40
+ end
37
41
  end
38
42
 
39
43
  def meta_data
@@ -50,15 +54,32 @@ module Spree
50
54
  end
51
55
 
52
56
  if meta[:keywords].blank? || meta[:description].blank?
53
- meta.reverse_merge!(keywords: current_store.meta_keywords,
54
- description: current_store.meta_description)
57
+ if object && object[:name].present?
58
+ meta.reverse_merge!(keywords: [object.name, current_store.meta_keywords].reject(&:blank?).join(', '),
59
+ description: [object.name, current_store.meta_description].reject(&:blank?).join(', '))
60
+ else
61
+ meta.reverse_merge!(keywords: (current_store.meta_keywords || current_store.seo_title),
62
+ description: (current_store.meta_description || current_store.seo_title))
63
+ end
55
64
  end
56
65
  meta
57
66
  end
58
67
 
68
+ def meta_image_url_path
69
+ object = instance_variable_get('@' + controller_name.singularize)
70
+ return unless object.is_a?(Spree::Product)
71
+
72
+ image = default_image_for_product_or_variant(object)
73
+ image&.attachment.present? ? main_app.url_for(image.attachment) : asset_path(Spree::Config[:logo])
74
+ end
75
+
76
+ def meta_image_data_tag
77
+ tag('meta', property: 'og:image', content: meta_image_url_path) if meta_image_url_path
78
+ end
79
+
59
80
  def meta_data_tags
60
81
  meta_data.map do |name, content|
61
- tag('meta', name: name, content: content)
82
+ tag('meta', name: name, content: content) unless name.nil? || content.nil?
62
83
  end.join("\n")
63
84
  end
64
85
 
@@ -75,14 +96,30 @@ module Spree
75
96
  [I18n.l(time.to_date, format: :long), time.strftime('%l:%M %p')].join(' ')
76
97
  end
77
98
 
78
- def seo_url(taxon)
79
- spree.nested_taxons_path(taxon.permalink)
99
+ def seo_url(taxon, options = nil)
100
+ spree.nested_taxons_path(taxon.permalink, options)
80
101
  end
81
102
 
82
103
  def frontend_available?
83
104
  Spree::Core::Engine.frontend_available?
84
105
  end
85
106
 
107
+ def default_image_for_product_or_variant(product_or_variant)
108
+ if product_or_variant.images.empty?
109
+ if product_or_variant.is_a?(Spree::Product) && product_or_variant.variant_images.any?
110
+ product_or_variant.variant_images.first
111
+ elsif product_or_variant.is_a?(Spree::Variant) && product_or_variant.product.variant_images.any?
112
+ product_or_variant.product.variant_images.first
113
+ end
114
+ else
115
+ product_or_variant.images.first
116
+ end
117
+ end
118
+
119
+ def base_cache_key
120
+ [I18n.locale, current_currency]
121
+ end
122
+
86
123
  private
87
124
 
88
125
  def create_product_image_tag(image, product, options, style)
@@ -94,18 +131,11 @@ module Spree
94
131
  self.class.send :define_method, "#{style}_image" do |product, *options|
95
132
  options = options.first || {}
96
133
  options[:alt] ||= product.name
97
- if product.images.empty?
98
- if !product.is_a?(Spree::Variant) && !product.variant_images.empty?
99
- create_product_image_tag(product.variant_images.first, product, options, style)
100
- else
101
- if product.is_a?(Variant) && !product.product.variant_images.empty?
102
- create_product_image_tag(product.product.variant_images.first, product, options, style)
103
- else
104
- image_tag "noimage/#{style}.png", options
105
- end
106
- end
134
+ image_path = default_image_for_product_or_variant(product)
135
+ if image_path.present?
136
+ create_product_image_tag image_path, product, options, style
107
137
  else
108
- create_product_image_tag(product.images.first, product, options, style)
138
+ image_tag "noimage/#{style}.png", options
109
139
  end
110
140
  end
111
141
  end
@@ -1,5 +1,7 @@
1
1
  module Spree
2
2
  module ProductsHelper
3
+ include BaseHelper
4
+
3
5
  # returns the formatted price for the specified variant as a full price or a difference depending on configuration
4
6
  def variant_price(variant)
5
7
  if Spree::Config[:show_variant_full_price]
@@ -29,6 +31,14 @@ module Spree
29
31
  end
30
32
  end
31
33
 
34
+ def default_variant(variants)
35
+ variants_option_types_presenter(variants).default_variant || variants.find(&:is_master)
36
+ end
37
+
38
+ def used_variants_options(variants)
39
+ variants_option_types_presenter(variants).options
40
+ end
41
+
32
42
  # converts line breaks in product description into <p> tags (for html display purposes)
33
43
  def product_description(product)
34
44
  description = if Spree::Config[:show_raw_product_description]
@@ -47,15 +57,27 @@ module Spree
47
57
  end
48
58
  end
49
59
 
50
- def cache_key_for_products
51
- count = @products.count
52
- max_updated_at = (@products.maximum(:updated_at) || Date.today).to_s(:number)
53
- products_cache_keys = "spree/products/all-#{params[:page]}-#{max_updated_at}-#{count}"
54
- (common_product_cache_keys + [products_cache_keys]).compact.join('/')
60
+ def cache_key_for_products(products = @products, additional_cache_key = nil)
61
+ count = products.count
62
+ max_updated_at = (products.maximum(:updated_at) || Date.today).to_s(:number)
63
+ products_cache_keys = "spree/products/all-#{params[:page]}-#{params[:sort_by]}-#{max_updated_at}-#{count}-#{@taxon&.id}"
64
+ (common_product_cache_keys + [products_cache_keys] + [additional_cache_key]).compact.join('/')
55
65
  end
56
66
 
57
67
  def cache_key_for_product(product = @product)
58
- (common_product_cache_keys + [product.cache_key_with_version, product.possible_promotions]).compact.join('/')
68
+ cache_key_elements = common_product_cache_keys
69
+ cache_key_elements += [
70
+ product.cache_key_with_version,
71
+ product.possible_promotions
72
+ ]
73
+
74
+ cache_key_elements.compact.join('/')
75
+ end
76
+
77
+ def limit_descritpion(string)
78
+ return string if string.length <= 450
79
+
80
+ string.slice(0..449) + '...'
59
81
  end
60
82
 
61
83
  def available_status(product) # will return a human readable string
@@ -71,16 +93,62 @@ module Spree
71
93
  end
72
94
  end
73
95
 
74
- private
96
+ def product_images(product, variants)
97
+ variants = if product.variants_and_option_values(current_currency).any?
98
+ variants.reject(&:is_master)
99
+ else
100
+ variants
101
+ end
102
+
103
+ variants.map(&:images).flatten
104
+ end
105
+
106
+ def product_variants_matrix(is_product_available_in_currency)
107
+ Spree::VariantPresenter.new(
108
+ variants: @variants,
109
+ is_product_available_in_currency: is_product_available_in_currency,
110
+ current_currency: current_currency,
111
+ current_price_options: current_price_options
112
+ ).call.to_json
113
+ end
114
+
115
+ def related_products
116
+ return [] unless @product.respond_to?(:has_related_products?) && @product.has_related_products?(:related_products)
117
+
118
+ @_related_products ||= @product.
119
+ related_products.
120
+ includes(
121
+ :tax_category,
122
+ master: [
123
+ :prices,
124
+ images: { attachment_attachment: :blob },
125
+ ]
126
+ ).
127
+ limit(Spree::Config[:products_per_page])
128
+ end
129
+
130
+ def product_available_in_currency?(product)
131
+ !(product.price_in(current_currency).amount.nil? || product.price_in(current_currency).amount.zero?)
132
+ end
75
133
 
76
134
  def common_product_cache_keys
77
- [I18n.locale, current_currency] + price_options_cache_key
135
+ base_cache_key + price_options_cache_key
78
136
  end
79
137
 
138
+ private
139
+
80
140
  def price_options_cache_key
81
141
  current_price_options.sort.map(&:last).map do |value|
82
142
  value.try(:cache_key) || value
83
143
  end
84
144
  end
145
+
146
+ def variants_option_types_presenter(variants)
147
+ @_variants_option_types_presenter ||= begin
148
+ option_types = Spree::Variants::OptionTypesFinder.new(variant_ids: variants.map(&:id)).execute
149
+
150
+ Spree::Variants::OptionTypesPresenter.new(option_types)
151
+ end
152
+ end
85
153
  end
86
154
  end
@@ -47,9 +47,9 @@ module Spree
47
47
  spree_roles.any? { |role| role.name == role_in_question.to_s }
48
48
  end
49
49
 
50
- def last_incomplete_spree_order(store)
50
+ def last_incomplete_spree_order(store, options = {})
51
51
  orders.where(store: store).incomplete.
52
- includes(line_items: [variant: [:images, :option_values, :product]]).
52
+ includes(options[:includes]).
53
53
  order('created_at DESC').
54
54
  first
55
55
  end
@@ -11,8 +11,7 @@ module Spree
11
11
  :checkout_remove_store_credit_service, :checkout_get_shipping_rates_service,
12
12
  :coupon_handler, :country_finder, :current_order_finder, :credit_card_finder,
13
13
  :completed_order_finder, :order_sorter, :cart_compare_line_items_service, :collection_paginator, :products_sorter,
14
- :products_finder, :taxon_finder, :line_item_by_variant_finder, :cart_estimate_shipping_rates_service,
15
- :account_create_address_service, :account_update_address_service, :address_finder
14
+ :products_finder, :taxon_finder, :line_item_by_variant_finder, :cart_estimate_shipping_rates_service
16
15
  ].freeze
17
16
 
18
17
  attr_accessor *INJECTION_POINTS
@@ -60,14 +59,9 @@ module Spree
60
59
  # coupons
61
60
  # TODO: we should split this service into 2 seperate - Add and Remove
62
61
  @coupon_handler = 'Spree::PromotionHandler::Coupon'
63
-
64
- # account
65
- @account_create_address_service = 'Spree::Account::Addresses::Create'
66
- @account_update_address_service = 'Spree::Account::Addresses::Update'
67
62
  end
68
63
 
69
64
  def set_default_finders
70
- @address_finder = 'Spree::Addresses::Find'
71
65
  @country_finder = 'Spree::Countries::Find'
72
66
  @current_order_finder = 'Spree::Orders::FindCurrent'
73
67
  @completed_order_finder = 'Spree::Orders::FindComplete'
@@ -24,9 +24,10 @@ module Spree
24
24
  attribute :month, ActiveRecord::Type::Integer.new
25
25
  attribute :year, ActiveRecord::Type::Integer.new
26
26
 
27
- attr_reader :number, :verification_value
27
+ attr_reader :number
28
28
  attr_accessor :encrypted_data,
29
29
  :imported,
30
+ :verification_value,
30
31
  :manual_entry
31
32
 
32
33
  with_options if: :require_card_numbers?, on: :create do
@@ -100,11 +101,9 @@ module Spree
100
101
  end
101
102
  end
102
103
 
103
- def verification_value=(value)
104
- @verification_value = value.to_s.gsub(/\s/, '')
105
- end
106
-
107
104
  def set_last_digits
105
+ number.to_s.gsub!(/\s/, '')
106
+ verification_value.to_s.gsub!(/\s/, '')
108
107
  self.last_digits ||= number.to_s.length <= 4 ? number : number.to_s.slice(-4..-1)
109
108
  end
110
109
 
@@ -2,7 +2,7 @@ module Spree
2
2
  class Image < Asset
3
3
  include Configuration::ActiveStorage
4
4
  include Rails.application.routes.url_helpers
5
-
5
+
6
6
  # In Rails 5.x class constants are being undefined/redefined during the code reloading process
7
7
  # in a rails development environment, after which the actual ruby objects stored in those class constants
8
8
  # are no longer equal (subclass == self) what causes error ActiveRecord::SubclassNotFound
@@ -12,14 +12,63 @@ module Spree
12
12
 
13
13
  def styles
14
14
  self.class.styles.map do |_, size|
15
- width, height = size[/(\d+)x(\d+)/].split('x')
15
+ width, height = size.chop.split('x')
16
16
 
17
17
  {
18
- url: polymorphic_path(attachment.variant(resize: size), only_path: true),
18
+ url: polymorphic_path(attachment.variant(combine_options: {
19
+ gravity: 'center',
20
+ resize: size,
21
+ extent: size,
22
+ background: 'snow2',
23
+ quality: 80
24
+ }), only_path: true),
19
25
  width: width,
20
26
  height: height
21
27
  }
22
28
  end
23
29
  end
30
+
31
+ def style(name)
32
+ size = self.class.styles[name]
33
+ return unless size
34
+
35
+ width, height = size.chop.split('x')
36
+
37
+ {
38
+ url: polymorphic_path(attachment.variant(combine_options: {
39
+ gravity: 'center',
40
+ resize: size,
41
+ extent: size,
42
+ background: 'snow2',
43
+ quality: 80
44
+ }), only_path: true),
45
+ size: size,
46
+ width: width,
47
+ height: height
48
+ }
49
+ end
50
+
51
+ def style_dimensions(name)
52
+ size = self.class.styles[name]
53
+ width, height = size.chop.split('x')
54
+
55
+ {
56
+ width: width,
57
+ height: height
58
+ }
59
+ end
60
+
61
+ def plp_url
62
+ size = self.class.styles[:plp_and_carousel]
63
+ variant = attachment.variant(
64
+ gravity: 'center',
65
+ resize: size,
66
+ extent: size,
67
+ background: 'snow2',
68
+ quality: 80
69
+ )
70
+
71
+ polymorphic_path(variant, only_path: true)
72
+ end
24
73
  end
25
74
  end