spree_core 4.4.1 → 4.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (158) hide show
  1. checksums.yaml +4 -4
  2. data/app/finders/spree/products/find.rb +1 -3
  3. data/app/finders/spree/taxons/find.rb +1 -1
  4. data/app/helpers/spree/base_helper.rb +12 -9
  5. data/app/helpers/spree/locale_helper.rb +6 -2
  6. data/app/helpers/spree/products_helper.rb +9 -4
  7. data/app/jobs/spree/variants/remove_from_incomplete_orders_job.rb +9 -0
  8. data/app/jobs/spree/variants/remove_line_item_job.rb +9 -0
  9. data/app/models/concerns/spree/calculated_adjustments.rb +1 -1
  10. data/app/models/concerns/spree/display_link.rb +17 -29
  11. data/app/models/concerns/spree/image_methods.rb +21 -9
  12. data/app/models/concerns/spree/metadata.rb +2 -2
  13. data/app/models/concerns/spree/product_scopes.rb +10 -8
  14. data/app/models/spree/address.rb +7 -1
  15. data/app/models/spree/asset/support/active_storage.rb +3 -2
  16. data/app/models/spree/asset.rb +3 -0
  17. data/app/models/spree/cms_page.rb +4 -0
  18. data/app/models/spree/cms_section.rb +12 -12
  19. data/app/models/spree/cms_section_image.rb +15 -0
  20. data/app/models/spree/cms_section_image_one.rb +4 -0
  21. data/app/models/spree/cms_section_image_three.rb +4 -0
  22. data/app/models/spree/cms_section_image_two.rb +4 -0
  23. data/app/models/spree/credit_card.rb +10 -4
  24. data/app/models/spree/customer_return.rb +3 -0
  25. data/app/models/spree/digital.rb +4 -0
  26. data/app/models/spree/digital_link.rb +7 -0
  27. data/app/models/spree/gateway/bogus.rb +1 -1
  28. data/app/models/spree/icon.rb +5 -1
  29. data/app/models/spree/image/configuration/active_storage.rb +5 -1
  30. data/app/models/spree/image.rb +3 -3
  31. data/app/models/spree/inventory_unit.rb +5 -2
  32. data/app/models/spree/legacy_user.rb +1 -2
  33. data/app/models/spree/line_item.rb +4 -1
  34. data/app/models/spree/linkable/homepage.rb +3 -0
  35. data/app/models/spree/linkable/uri.rb +3 -0
  36. data/app/models/spree/log_entry.rb +4 -0
  37. data/app/models/spree/menu.rb +3 -0
  38. data/app/models/spree/menu_item.rb +7 -11
  39. data/app/models/spree/option_type.rb +4 -0
  40. data/app/models/spree/option_value.rb +5 -0
  41. data/app/models/spree/order/address_book.rb +1 -0
  42. data/app/models/spree/order/store_credit.rb +0 -8
  43. data/app/models/spree/order.rb +11 -2
  44. data/app/models/spree/order_merger.rb +1 -1
  45. data/app/models/spree/payment/processing.rb +1 -1
  46. data/app/models/spree/payment.rb +7 -1
  47. data/app/models/spree/payment_capture_event.rb +4 -0
  48. data/app/models/spree/payment_method/store_credit.rb +1 -1
  49. data/app/models/spree/payment_method.rb +3 -0
  50. data/app/models/spree/payment_source.rb +10 -0
  51. data/app/models/spree/preference.rb +4 -0
  52. data/app/models/spree/price.rb +3 -0
  53. data/app/models/spree/product.rb +56 -14
  54. data/app/models/spree/product_property.rb +1 -0
  55. data/app/models/spree/promotion/rules/option_value.rb +2 -2
  56. data/app/models/spree/promotion.rb +6 -0
  57. data/app/models/spree/promotion_rule.rb +1 -1
  58. data/app/models/spree/promotion_rule_user.rb +1 -1
  59. data/app/models/spree/property.rb +3 -0
  60. data/app/models/spree/prototype.rb +3 -0
  61. data/app/models/spree/refund.rb +8 -0
  62. data/app/models/spree/reimbursement.rb +3 -0
  63. data/app/models/spree/return_authorization.rb +3 -0
  64. data/app/models/spree/return_item.rb +4 -0
  65. data/app/models/spree/role.rb +1 -1
  66. data/app/models/spree/role_user.rb +1 -1
  67. data/app/models/spree/shipment.rb +7 -0
  68. data/app/models/spree/shipping_category.rb +3 -0
  69. data/app/models/spree/shipping_method.rb +6 -0
  70. data/app/models/spree/state_change.rb +1 -1
  71. data/app/models/spree/stock/availability_validator.rb +9 -3
  72. data/app/models/spree/stock/content_item.rb +1 -1
  73. data/app/models/spree/stock/quantifier.rb +1 -1
  74. data/app/models/spree/stock_item.rb +5 -0
  75. data/app/models/spree/stock_location.rb +19 -5
  76. data/app/models/spree/stock_movement.rb +4 -0
  77. data/app/models/spree/stock_transfer.rb +3 -0
  78. data/app/models/spree/store.rb +19 -14
  79. data/app/models/spree/store_credit.rb +4 -1
  80. data/app/models/spree/store_favicon_image.rb +17 -0
  81. data/app/models/spree/store_logo.rb +9 -0
  82. data/app/models/spree/store_mailer_logo.rb +13 -0
  83. data/app/models/spree/tax_category.rb +6 -0
  84. data/app/models/spree/tax_rate.rb +6 -1
  85. data/app/models/spree/taxon.rb +4 -1
  86. data/app/models/spree/taxon_image/configuration/active_storage.rb +5 -1
  87. data/app/models/spree/taxon_image.rb +3 -2
  88. data/app/models/spree/taxonomy.rb +4 -1
  89. data/app/models/spree/variant.rb +43 -14
  90. data/app/models/spree/wished_item.rb +4 -0
  91. data/app/models/spree/wishlist.rb +4 -1
  92. data/app/models/spree/zone.rb +3 -0
  93. data/app/services/spree/addresses/create.rb +1 -1
  94. data/app/services/spree/addresses/update.rb +7 -2
  95. data/app/services/spree/cart/remove_line_item.rb +1 -0
  96. data/app/services/spree/variants/remove_line_items.rb +15 -0
  97. data/config/locales/en.yml +5 -2
  98. data/config/routes.rb +43 -0
  99. data/db/migrate/20211201202851_update_linkable_resource_types.rb +10 -0
  100. data/db/migrate/20211203082008_add_settings_to_payment_methods.rb +11 -0
  101. data/db/migrate/20211229162122_disable_propagate_all_variants_by_default.rb +5 -0
  102. data/db/migrate/20220103082046_add_status_and_make_active_at_to_spree_products.rb +7 -0
  103. data/db/migrate/20220106230929_add_internal_note_to_spree_orders.rb +5 -0
  104. data/db/migrate/20220113052823_create_payment_sources.rb +22 -0
  105. data/db/migrate/20220117100333_add_make_active_at_to_spree_products.rb +17 -0
  106. data/db/migrate/20220120092821_add_metadata_to_spree_tax_rates.rb +13 -0
  107. data/db/migrate/20220201103922_add_first_name_and_last_name_to_spree_users.rb +9 -0
  108. data/db/migrate/20220222083546_add_barcode_to_spree_variants.rb +6 -0
  109. data/db/migrate/20220329113557_fix_cms_pages_unique_indexes.rb +8 -0
  110. data/db/migrate/20220613133029_add_metadata_to_spree_stock_items.rb +13 -0
  111. data/lib/friendly_id/paranoia.rb +4 -0
  112. data/lib/generators/spree/dummy/dummy_generator.rb +13 -2
  113. data/lib/generators/spree/dummy/templates/package.json +12 -0
  114. data/lib/generators/spree/dummy/templates/rails/test.rb +2 -0
  115. data/lib/spree/core/configuration.rb +90 -0
  116. data/lib/spree/core/controller_helpers/auth.rb +3 -1
  117. data/lib/spree/core/controller_helpers/currency.rb +7 -5
  118. data/lib/spree/core/controller_helpers/locale.rb +8 -6
  119. data/lib/spree/core/controller_helpers/order.rb +4 -2
  120. data/lib/spree/core/controller_helpers/search.rb +1 -1
  121. data/lib/spree/core/controller_helpers/store.rb +5 -3
  122. data/lib/spree/core/dependencies.rb +130 -0
  123. data/lib/spree/core/engine.rb +47 -37
  124. data/{app/models/spree → lib/spree/core}/preferences/configuration.rb +3 -0
  125. data/{app/models/spree → lib/spree/core}/preferences/preferable.rb +3 -0
  126. data/lib/spree/core/search/base.rb +9 -5
  127. data/lib/spree/core/version.rb +1 -1
  128. data/lib/spree/core.rb +25 -5
  129. data/lib/spree/permitted_attributes.rb +9 -7
  130. data/lib/spree/testing_support/common_rake.rb +1 -0
  131. data/lib/spree/testing_support/factories/favicon_image_factory.rb +9 -0
  132. data/lib/spree/testing_support/factories/icon_factory.rb +3 -1
  133. data/lib/spree/testing_support/factories/image_factory.rb +3 -1
  134. data/lib/spree/testing_support/factories/menu_item_factory.rb +1 -1
  135. data/lib/spree/testing_support/factories/order_factory.rb +2 -1
  136. data/lib/spree/testing_support/factories/product_factory.rb +6 -1
  137. data/lib/spree/testing_support/factories/product_property_factory.rb +1 -0
  138. data/lib/spree/testing_support/factories/refund_factory.rb +1 -1
  139. data/lib/spree/testing_support/factories/return_authorization_factory.rb +1 -1
  140. data/lib/spree/testing_support/factories/role_factory.rb +1 -1
  141. data/lib/spree/testing_support/factories/shipping_category_factory.rb +1 -1
  142. data/lib/spree/testing_support/factories/stock_location_factory.rb +3 -2
  143. data/lib/spree/testing_support/factories/store_factory.rb +1 -1
  144. data/lib/spree/testing_support/factories/taxon_image_factory.rb +3 -1
  145. data/lib/spree/testing_support/factories/user_factory.rb +4 -0
  146. data/lib/spree/testing_support/factories/variant_factory.rb +4 -0
  147. data/lib/spree_core.rb +2 -1
  148. data/lib/tasks/core.rake +12 -0
  149. data/spree_core.gemspec +2 -3
  150. metadata +64 -53
  151. data/app/models/friendly_id/slug_decorator.rb +0 -9
  152. data/app/models/spree/app_configuration.rb +0 -86
  153. data/app/models/spree/order_contents.rb +0 -31
  154. data/lib/friendly_id/slug_rails5_patch.rb +0 -11
  155. data/lib/spree/core/app_dependencies.rb +0 -126
  156. /data/{app/models/spree → lib/spree/core}/preferences/preferable_class_methods.rb +0 -0
  157. /data/{app/models/spree → lib/spree/core}/preferences/scoped_store.rb +0 -0
  158. /data/{app/models/spree → lib/spree/core}/preferences/store.rb +0 -0
@@ -8,7 +8,6 @@ module Spree
8
8
 
9
9
  self.table_name = 'spree_users'
10
10
 
11
- attr_accessor :password
12
- attr_accessor :password_confirmation
11
+ attr_accessor :password, :password_confirmation
13
12
  end
14
13
  end
@@ -1,6 +1,9 @@
1
1
  module Spree
2
2
  class LineItem < Spree::Base
3
3
  include Metadata
4
+ if defined?(Spree::Webhooks)
5
+ include Spree::Webhooks::HasWebhooks
6
+ end
4
7
 
5
8
  before_validation :ensure_valid_quantity
6
9
 
@@ -8,7 +11,7 @@ module Spree
8
11
  belongs_to :order, class_name: 'Spree::Order', touch: true
9
12
  belongs_to :variant, -> { with_deleted }, class_name: 'Spree::Variant'
10
13
  end
11
- belongs_to :tax_category, class_name: 'Spree::TaxCategory'
14
+ belongs_to :tax_category, -> { with_deleted }, class_name: 'Spree::TaxCategory'
12
15
 
13
16
  has_one :product, through: :variant
14
17
 
@@ -0,0 +1,3 @@
1
+ module Spree::Linkable::Homepage
2
+ # Placeholder for polymorphic lookup.
3
+ end
@@ -0,0 +1,3 @@
1
+ module Spree::Linkable::Uri
2
+ # Placeholder for polymorphic lookup.
3
+ end
@@ -1,5 +1,9 @@
1
1
  module Spree
2
2
  class LogEntry < Spree::Base
3
+ if defined?(Spree::Security::LogEntries)
4
+ include Spree::Security::LogEntries
5
+ end
6
+
3
7
  belongs_to :source, polymorphic: true
4
8
 
5
9
  # Fix for #1767
@@ -1,6 +1,9 @@
1
1
  module Spree
2
2
  class Menu < Spree::Base
3
3
  include SingleStoreResource
4
+ if defined?(Spree::Webhooks)
5
+ include Spree::Webhooks::HasWebhooks
6
+ end
4
7
 
5
8
  MENU_LOCATIONS = ['Header', 'Footer']
6
9
  MENU_LOCATIONS_PARAMETERIZED = []
@@ -1,11 +1,16 @@
1
1
  module Spree
2
2
  class MenuItem < Spree::Base
3
3
  include Spree::DisplayLink
4
+ if defined?(Spree::Webhooks)
5
+ include Spree::Webhooks::HasWebhooks
6
+ end
4
7
 
5
8
  acts_as_nested_set dependent: :destroy
6
9
 
10
+ ITEM_TYPE = %w[Link Container]
11
+ LINKED_RESOURCE_TYPE = ['Spree::Linkable::Uri', 'Spree::Linkable::Homepage', 'Spree::Product', 'Spree::Taxon', 'Spree::CmsPage']
12
+
7
13
  belongs_to :menu, touch: true
8
- belongs_to :linked_resource, polymorphic: true
9
14
 
10
15
  before_create :ensure_item_belongs_to_root
11
16
  before_update :reset_link_attributes
@@ -14,15 +19,6 @@ module Spree
14
19
  after_save :touch_ancestors_and_menu
15
20
  after_touch :touch_ancestors_and_menu
16
21
 
17
- ITEM_TYPE = %w[Link Container]
18
-
19
- LINKED_RESOURCE_TYPE = ['URL']
20
- STATIC_RESOURCE_TYPE = ['Home Page']
21
- DYNAMIC_RESOURCE_TYPE = ['Spree::Product', 'Spree::Taxon', 'Spree::CmsPage']
22
-
23
- LINKED_RESOURCE_TYPE.unshift(*STATIC_RESOURCE_TYPE)
24
- LINKED_RESOURCE_TYPE.push(*DYNAMIC_RESOURCE_TYPE)
25
-
26
22
  validates :name, :menu, presence: true
27
23
  validates :item_type, inclusion: { in: ITEM_TYPE }
28
24
  validates :linked_resource_type, inclusion: { in: LINKED_RESOURCE_TYPE }
@@ -50,7 +46,7 @@ module Spree
50
46
  self.destination = nil
51
47
  self.new_window = false
52
48
 
53
- self.linked_resource_type = 'URL' if item_type == 'Container'
49
+ self.linked_resource_type = 'Spree::Linkable::Uri' if item_type == 'Container'
54
50
  end
55
51
  end
56
52
 
@@ -2,8 +2,12 @@ module Spree
2
2
  class OptionType < Spree::Base
3
3
  include UniqueName
4
4
  include Metadata
5
+ if defined?(Spree::Webhooks)
6
+ include Spree::Webhooks::HasWebhooks
7
+ end
5
8
 
6
9
  acts_as_list
10
+ auto_strip_attributes :name, :presentation
7
11
 
8
12
  with_options dependent: :destroy, inverse_of: :option_type do
9
13
  has_many :option_values, -> { order(:position) }
@@ -1,9 +1,14 @@
1
1
  module Spree
2
2
  class OptionValue < Spree::Base
3
3
  include Metadata
4
+ if defined?(Spree::Webhooks)
5
+ include Spree::Webhooks::HasWebhooks
6
+ end
4
7
 
5
8
  belongs_to :option_type, class_name: 'Spree::OptionType', touch: true, inverse_of: :option_values
9
+
6
10
  acts_as_list scope: :option_type
11
+ auto_strip_attributes :name, :presentation
7
12
 
8
13
  has_many :option_value_variants, class_name: 'Spree::OptionValueVariant'
9
14
  has_many :variants, through: :option_value_variants, class_name: 'Spree::Variant'
@@ -54,6 +54,7 @@ module Spree
54
54
  return if attributes.blank?
55
55
 
56
56
  attributes.transform_values! { |v| v == '' ? nil : v }
57
+ attributes = attributes.to_h.symbolize_keys
57
58
 
58
59
  default_address_scope = user ? user.addresses : ::Spree::Address
59
60
  default_address = default_address_scope.find_by(id: attributes[:id])
@@ -1,14 +1,6 @@
1
1
  module Spree
2
2
  class Order < Spree::Base
3
3
  module StoreCredit
4
- def add_store_credit_payments(amount = nil)
5
- Spree::Dependencies.checkout_add_store_credit_service.constantize.call(order: self, amount: amount)
6
- end
7
-
8
- def remove_store_credit_payments
9
- Spree::Dependencies.checkout_remove_store_credit_service.constantize.call(order: self)
10
- end
11
-
12
4
  def covered_by_store_credit?
13
5
  return false unless user
14
6
 
@@ -25,6 +25,15 @@ module Spree
25
25
  include SingleStoreResource
26
26
  include MemoizedData
27
27
  include Metadata
28
+ if defined?(Spree::Webhooks)
29
+ include Spree::Webhooks::HasWebhooks
30
+ end
31
+ if defined?(Spree::Security::Orders)
32
+ include Spree::Security::Orders
33
+ end
34
+ if defined?(Spree::VendorConcern)
35
+ include Spree::VendorConcern
36
+ end
28
37
 
29
38
  MEMOIZED_METHODS = %w(tax_zone)
30
39
 
@@ -77,7 +86,7 @@ module Spree
77
86
  attribute :state_machine_resumed, :boolean
78
87
 
79
88
  if Spree.user_class
80
- belongs_to :user, class_name: Spree.user_class.to_s, optional: true
89
+ belongs_to :user, class_name: "::#{Spree.user_class}", optional: true
81
90
  else
82
91
  belongs_to :user, optional: true
83
92
  end
@@ -146,7 +155,7 @@ module Spree
146
155
 
147
156
  before_create :create_token
148
157
  before_create :link_by_email
149
- before_update :homogenize_line_item_currencies, if: :currency_changed?
158
+ before_update :ensure_updated_shipments, :homogenize_line_item_currencies, if: :currency_changed?
150
159
 
151
160
  with_options presence: true do
152
161
  # we want to have this case_sentive: true as changing it to false causes all SQL to use LOWER(slug)
@@ -54,7 +54,7 @@ module Spree
54
54
 
55
55
  # Change the error messages as you choose.
56
56
  def handle_error(line_item)
57
- order.errors[:base] << line_item.errors.full_messages
57
+ order.errors.add(:base, line_item.errors.full_messages)
58
58
  end
59
59
 
60
60
  def persist_merge
@@ -72,7 +72,7 @@ module Spree
72
72
  end
73
73
 
74
74
  def cancel!
75
- response = payment_method.cancel(response_code)
75
+ response = payment_method.cancel(response_code, self)
76
76
  handle_response(response, :void, :failure)
77
77
  end
78
78
 
@@ -6,12 +6,18 @@ module Spree
6
6
  include NumberIdentifier
7
7
  include NumberAsParam
8
8
  include Metadata
9
+ if defined?(Spree::Webhooks)
10
+ include Spree::Webhooks::HasWebhooks
11
+ end
12
+ if defined?(Spree::Security::Payments)
13
+ include Spree::Security::Payments
14
+ end
9
15
 
10
16
  include Spree::Payment::Processing
11
17
 
12
18
  NON_RISKY_AVS_CODES = ['B', 'D', 'H', 'J', 'M', 'Q', 'T', 'V', 'X', 'Y'].freeze
13
19
  RISKY_AVS_CODES = ['A', 'C', 'E', 'F', 'G', 'I', 'K', 'L', 'N', 'O', 'P', 'R', 'S', 'U', 'W', 'Z'].freeze
14
- INVALID_STATES = %w(failed invalid).freeze
20
+ INVALID_STATES = %w(failed invalid void).freeze
15
21
 
16
22
  with_options inverse_of: :payments do
17
23
  belongs_to :order, class_name: 'Spree::Order', touch: true
@@ -1,5 +1,9 @@
1
1
  module Spree
2
2
  class PaymentCaptureEvent < Spree::Base
3
+ if defined?(Spree::Webhooks)
4
+ include Spree::Webhooks::HasWebhooks
5
+ end
6
+
3
7
  belongs_to :payment, class_name: 'Spree::Payment'
4
8
 
5
9
  def display_amount
@@ -74,7 +74,7 @@ module Spree
74
74
  handle_action(action, :credit, auth_code)
75
75
  end
76
76
 
77
- def cancel(auth_code)
77
+ def cancel(auth_code, _payment = nil)
78
78
  store_credit_event = StoreCreditEvent.find_by(authorization_code: auth_code,
79
79
  action: Spree::StoreCredit::CAPTURE_ACTION)
80
80
  store_credit = store_credit_event.try(:store_credit)
@@ -5,6 +5,9 @@ module Spree
5
5
 
6
6
  include MultiStoreResource
7
7
  include Spree::Metadata
8
+ if defined?(Spree::Security::PaymentMethods)
9
+ include Spree::Security::PaymentMethods
10
+ end
8
11
 
9
12
  DISPLAY = [:both, :front_end, :back_end].freeze
10
13
 
@@ -0,0 +1,10 @@
1
+ module Spree
2
+ class PaymentSource < Spree::Base
3
+ include Metadata
4
+
5
+ belongs_to :payment_method, class_name: 'Spree::PaymentMethod'
6
+ belongs_to :user, class_name: 'Spree::User', optional: true
7
+
8
+ validates_uniqueness_of :gateway_payment_profile_id, scope: :type
9
+ end
10
+ end
@@ -3,4 +3,8 @@ class Spree::Preference < Spree::Base
3
3
 
4
4
  validates :key, presence: true,
5
5
  uniqueness: { case_sensitive: false, allow_blank: true, scope: spree_base_uniqueness_scope }
6
+
7
+ if defined?(Spree::Security::Preferences)
8
+ include Spree::Security::Preferences
9
+ end
6
10
  end
@@ -1,6 +1,9 @@
1
1
  module Spree
2
2
  class Price < Spree::Base
3
3
  include VatPriceCalculation
4
+ if defined?(Spree::Webhooks)
5
+ include Spree::Webhooks::HasWebhooks
6
+ end
4
7
 
5
8
  acts_as_paranoid
6
9
 
@@ -25,6 +25,12 @@ module Spree
25
25
  include MultiStoreResource
26
26
  include MemoizedData
27
27
  include Metadata
28
+ if defined?(Spree::Webhooks)
29
+ include Spree::Webhooks::HasWebhooks
30
+ end
31
+ if defined?(Spree::VendorConcern)
32
+ include Spree::VendorConcern
33
+ end
28
34
 
29
35
  MEMOIZED_METHODS = %w(total_on_hand taxonomy_ids taxon_and_ancestors category
30
36
  default_variant_id tax_category default_variant
@@ -33,10 +39,11 @@ module Spree
33
39
  friendly_id :slug_candidates, use: :history
34
40
 
35
41
  acts_as_paranoid
42
+ auto_strip_attributes :name
36
43
 
37
44
  # we need to have this callback before any dependent: :destroy associations
38
45
  # https://github.com/rails/rails/issues/3458
39
- before_destroy :ensure_no_line_items
46
+ before_destroy :ensure_not_in_complete_orders
40
47
 
41
48
  has_many :product_option_types, dependent: :destroy, inverse_of: :product
42
49
  has_many :option_types, through: :product_option_types
@@ -118,7 +125,7 @@ module Spree
118
125
  end
119
126
 
120
127
  validates :slug, presence: true, uniqueness: { allow_blank: true, case_sensitive: true, scope: spree_base_uniqueness_scope }
121
- validate :discontinue_on_must_be_later_than_available_on, if: -> { available_on && discontinue_on }
128
+ validate :discontinue_on_must_be_later_than_make_active_at, if: -> { make_active_at && discontinue_on }
122
129
 
123
130
  scope :for_store, ->(store) { joins(:store_products).where(StoreProduct.table_name => { store_id: store.id }) }
124
131
 
@@ -129,11 +136,11 @@ module Spree
129
136
  alias options product_option_types
130
137
 
131
138
  self.whitelisted_ransackable_associations = %w[taxons stores variants_including_master master variants]
132
- self.whitelisted_ransackable_attributes = %w[description name slug discontinue_on]
139
+ self.whitelisted_ransackable_attributes = %w[description name slug discontinue_on status]
133
140
  self.whitelisted_ransackable_scopes = %w[not_discontinued search_by_name in_taxon price_between]
134
141
 
135
142
  [
136
- :sku, :price, :currency, :weight, :height, :width, :depth, :is_master,
143
+ :sku, :barcode, :price, :currency, :weight, :height, :width, :depth, :is_master,
137
144
  :cost_currency, :price_in, :amount_in, :cost_price, :compare_at_price, :compare_at_amount_in
138
145
  ].each do |method_name|
139
146
  delegate method_name, :"#{method_name}=", to: :find_or_build_master
@@ -144,6 +151,23 @@ module Spree
144
151
 
145
152
  alias master_images images
146
153
 
154
+ state_machine :status, initial: :draft do
155
+ event :activate do
156
+ transition to: :active
157
+ end
158
+ after_transition to: :active, do: :after_activate
159
+
160
+ event :archive do
161
+ transition to: :archived
162
+ end
163
+ after_transition to: :archived, do: :after_archive
164
+
165
+ event :draft do
166
+ transition to: :draft
167
+ end
168
+ after_transition to: :draft, do: :after_draft
169
+ end
170
+
147
171
  # Can't use short form block syntax due to https://github.com/Netflix/fast_jsonapi/issues/259
148
172
  def purchasable?
149
173
  default_variant.purchasable? || variants.any?(&:purchasable?)
@@ -225,14 +249,16 @@ module Spree
225
249
  end
226
250
 
227
251
  # determine if product is available.
228
- # deleted products and products with nil or future available_on date
252
+ # deleted products and products with status different than active
229
253
  # are not available
230
254
  def available?
231
- !(available_on.nil? || available_on.future?) && !deleted? && !discontinued?
255
+ active? && !deleted?
232
256
  end
233
257
 
234
258
  def discontinue!
235
- update_attribute(:discontinue_on, Time.current)
259
+ self.discontinue_on = Time.current
260
+ self.status = 'archived'
261
+ save(validate: false)
236
262
  end
237
263
 
238
264
  def discontinued?
@@ -296,7 +322,7 @@ module Spree
296
322
  def total_on_hand
297
323
  @total_on_hand ||= Rails.cache.fetch(['product-total-on-hand', cache_key_with_version]) do
298
324
  if any_variants_not_track_inventory?
299
- Float::INFINITY
325
+ BigDecimal::INFINITY
300
326
  else
301
327
  stock_items.sum(:count_on_hand)
302
328
  end
@@ -327,17 +353,21 @@ module Spree
327
353
  def any_variant_in_stock_or_backorderable?
328
354
  if variants.any?
329
355
  variants_including_master.in_stock_or_backorderable.exists?
330
- else
356
+ else
331
357
  master.in_stock_or_backorderable?
332
358
  end
333
359
  end
334
360
 
361
+ def digital?
362
+ shipping_category&.name == I18n.t('spree.seed.shipping.categories.digital')
363
+ end
364
+
335
365
  private
336
366
 
337
367
  def add_associations_from_prototype
338
368
  if prototype_id && prototype = Spree::Prototype.find_by(id: prototype_id)
339
369
  prototype.properties.each do |property|
340
- product_properties.create(property: property)
370
+ product_properties.create(property: property, value: 'Placeholder')
341
371
  end
342
372
  self.option_types = prototype.option_types
343
373
  self.taxons = prototype.taxons
@@ -473,8 +503,8 @@ module Spree
473
503
  Spree::Taxonomy.where(id: taxonomy_ids).update_all(updated_at: Time.current)
474
504
  end
475
505
 
476
- def ensure_no_line_items
477
- if line_items.any?
506
+ def ensure_not_in_complete_orders
507
+ if orders.complete.any?
478
508
  errors.add(:base, :cannot_destroy_if_attached_to_line_items)
479
509
  throw(:abort)
480
510
  end
@@ -485,8 +515,8 @@ module Spree
485
515
  removed_classifications.each &:remove_from_list
486
516
  end
487
517
 
488
- def discontinue_on_must_be_later_than_available_on
489
- if discontinue_on < available_on
518
+ def discontinue_on_must_be_later_than_make_active_at
519
+ if discontinue_on < make_active_at
490
520
  errors.add(:discontinue_on, :invalid_date_range)
491
521
  end
492
522
  end
@@ -502,5 +532,17 @@ module Spree
502
532
  def downcase_slug
503
533
  slug&.downcase!
504
534
  end
535
+
536
+ def after_activate
537
+ # this method is prepended in api/ to queue Webhooks requests
538
+ end
539
+
540
+ def after_archive
541
+ # this method is prepended in api/ to queue Webhooks requests
542
+ end
543
+
544
+ def after_draft
545
+ # this method is prepended in api/ to queue Webhooks requests
546
+ end
505
547
  end
506
548
  end
@@ -13,6 +13,7 @@ module Spree
13
13
 
14
14
  validates :property, presence: true
15
15
  validates :property_id, uniqueness: { scope: :product_id }
16
+ validates :value, presence: true
16
17
 
17
18
  default_scope { order(:position) }
18
19
 
@@ -4,9 +4,9 @@ module Spree
4
4
  module OptionValueWithNumerificationSupport
5
5
  def preferred_eligible_values
6
6
  values = super || {}
7
- Hash[values.keys.map(&:to_i).zip(
7
+ Hash[values.keys.zip(
8
8
  values.values.map do |v|
9
- (v.is_a?(Array) ? v : v.split(',')).map(&:to_i)
9
+ (v.is_a?(Array) ? v : v.split(','))
10
10
  end
11
11
  )]
12
12
  end
@@ -2,6 +2,12 @@ module Spree
2
2
  class Promotion < Spree::Base
3
3
  include MultiStoreResource
4
4
  include Metadata
5
+ if defined?(Spree::Webhooks)
6
+ include Spree::Webhooks::HasWebhooks
7
+ end
8
+ if defined?(Spree::Security::Promotions)
9
+ include Spree::Security::Promotions
10
+ end
5
11
 
6
12
  MATCH_POLICIES = %w(all any)
7
13
  UNACTIVATABLE_ORDER_STATES = ['complete', 'awaiting_return', 'returned']
@@ -35,7 +35,7 @@ module Spree
35
35
 
36
36
  def unique_per_promotion
37
37
  if Spree::PromotionRule.exists?(promotion_id: promotion_id, type: self.class.name)
38
- errors[:base] << 'Promotion already contains this rule type'
38
+ errors.add(:base, 'Promotion already contains this rule type')
39
39
  end
40
40
  end
41
41
 
@@ -1,7 +1,7 @@
1
1
  module Spree
2
2
  class PromotionRuleUser < Spree::Base
3
3
  belongs_to :promotion_rule, class_name: 'Spree::PromotionRule'
4
- belongs_to :user, class_name: Spree.user_class.to_s
4
+ belongs_to :user, class_name: "::#{Spree.user_class}"
5
5
 
6
6
  validates :user, :promotion_rule, presence: true
7
7
  validates :user_id, uniqueness: { scope: :promotion_rule_id }, allow_nil: true
@@ -2,6 +2,9 @@ module Spree
2
2
  class Property < Spree::Base
3
3
  include Spree::FilterParam
4
4
  include Metadata
5
+ if defined?(Spree::Webhooks)
6
+ include Spree::Webhooks::HasWebhooks
7
+ end
5
8
 
6
9
  auto_strip_attributes :name, :presentation
7
10
 
@@ -1,6 +1,9 @@
1
1
  module Spree
2
2
  class Prototype < Spree::Base
3
3
  include Metadata
4
+ if defined?(Spree::Webhooks)
5
+ include Spree::Webhooks::HasWebhooks
6
+ end
4
7
 
5
8
  has_many :property_prototypes, class_name: 'Spree::PropertyPrototype'
6
9
  has_many :properties, through: :property_prototypes, class_name: 'Spree::Property'
@@ -1,6 +1,12 @@
1
1
  module Spree
2
2
  class Refund < Spree::Base
3
3
  include Metadata
4
+ if defined?(Spree::Webhooks)
5
+ include Spree::Webhooks::HasWebhooks
6
+ end
7
+ if defined?(Spree::Security::Refunds)
8
+ include Spree::Security::Refunds
9
+ end
4
10
 
5
11
  with_options inverse_of: :refunds do
6
12
  belongs_to :payment
@@ -23,6 +29,8 @@ module Spree
23
29
 
24
30
  scope :non_reimbursement, -> { where(reimbursement_id: nil) }
25
31
 
32
+ attr_reader :response
33
+
26
34
  def money
27
35
  Spree::Money.new(amount, currency: payment.currency)
28
36
  end
@@ -2,6 +2,9 @@ module Spree
2
2
  class Reimbursement < Spree::Base
3
3
  include Spree::Core::NumberGenerator.new(prefix: 'RI', length: 9)
4
4
  include NumberIdentifier
5
+ if defined?(Spree::Webhooks)
6
+ include Spree::Webhooks::HasWebhooks
7
+ end
5
8
 
6
9
  class IncompleteReimbursementError < StandardError; end
7
10
 
@@ -2,6 +2,9 @@ module Spree
2
2
  class ReturnAuthorization < Spree::Base
3
3
  include Spree::Core::NumberGenerator.new(prefix: 'RA', length: 9)
4
4
  include NumberIdentifier
5
+ if defined?(Spree::Webhooks)
6
+ include Spree::Webhooks::HasWebhooks
7
+ end
5
8
 
6
9
  belongs_to :order, class_name: 'Spree::Order', inverse_of: :return_authorizations
7
10
 
@@ -2,6 +2,10 @@ module Spree
2
2
  class ReturnItem < Spree::Base
3
3
  COMPLETED_RECEPTION_STATUSES = %w(received given_to_customer)
4
4
 
5
+ if defined?(Spree::Webhooks)
6
+ include Spree::Webhooks::HasWebhooks
7
+ end
8
+
5
9
  class_attribute :return_eligibility_validator
6
10
  self.return_eligibility_validator = ReturnItem::EligibilityValidator::Default
7
11
 
@@ -3,6 +3,6 @@ module Spree
3
3
  include UniqueName
4
4
 
5
5
  has_many :role_users, class_name: 'Spree::RoleUser', dependent: :destroy
6
- has_many :users, through: :role_users, class_name: Spree.user_class.to_s
6
+ has_many :users, through: :role_users, class_name: "::#{Spree.user_class}"
7
7
  end
8
8
  end
@@ -1,6 +1,6 @@
1
1
  module Spree
2
2
  class RoleUser < Spree::Base
3
3
  belongs_to :role, class_name: 'Spree::Role'
4
- belongs_to :user, class_name: Spree.user_class.to_s
4
+ belongs_to :user, class_name: "::#{Spree.user_class}"
5
5
  end
6
6
  end
@@ -6,6 +6,12 @@ module Spree
6
6
  include NumberIdentifier
7
7
  include NumberAsParam
8
8
  include Metadata
9
+ if defined?(Spree::Webhooks)
10
+ include Spree::Webhooks::HasWebhooks
11
+ end
12
+ if defined?(Spree::Security::Shipments)
13
+ include Spree::Security::Shipments
14
+ end
9
15
 
10
16
  with_options inverse_of: :shipments do
11
17
  belongs_to :address, class_name: 'Spree::Address'
@@ -244,6 +250,7 @@ module Spree
244
250
 
245
251
  def selected_shipping_rate_id=(id)
246
252
  shipping_rates.update_all(selected: false)
253
+ shipping_rates.touch_all # Bust cache dependent on "updated_at" timestamp
247
254
  shipping_rates.update(id, selected: true)
248
255
  save!
249
256
  end
@@ -1,6 +1,9 @@
1
1
  module Spree
2
2
  class ShippingCategory < Spree::Base
3
3
  include UniqueName
4
+ if defined?(Spree::Webhooks)
5
+ include Spree::Webhooks::HasWebhooks
6
+ end
4
7
 
5
8
  with_options inverse_of: :shipping_category do
6
9
  has_many :products
@@ -3,6 +3,12 @@ module Spree
3
3
  acts_as_paranoid
4
4
  include Spree::CalculatedAdjustments
5
5
  include Metadata
6
+ if defined?(Spree::Webhooks)
7
+ include Spree::Webhooks::HasWebhooks
8
+ end
9
+ if defined?(Spree::VendorConcern)
10
+ include Spree::VendorConcern
11
+ end
6
12
 
7
13
  DISPLAY = [:both, :front_end, :back_end]
8
14