spree_core 4.4.0 → 4.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (157) 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/fulfilment_changer.rb +1 -1
  28. data/app/models/spree/gateway/bogus.rb +1 -1
  29. data/app/models/spree/icon.rb +5 -1
  30. data/app/models/spree/image/configuration/active_storage.rb +5 -1
  31. data/app/models/spree/image.rb +3 -3
  32. data/app/models/spree/inventory_unit.rb +5 -2
  33. data/app/models/spree/legacy_user.rb +1 -2
  34. data/app/models/spree/line_item.rb +4 -1
  35. data/app/models/spree/linkable/homepage.rb +3 -0
  36. data/app/models/spree/linkable/uri.rb +3 -0
  37. data/app/models/spree/log_entry.rb +4 -0
  38. data/app/models/spree/menu.rb +3 -0
  39. data/app/models/spree/menu_item.rb +7 -11
  40. data/app/models/spree/option_type.rb +4 -0
  41. data/app/models/spree/option_value.rb +5 -0
  42. data/app/models/spree/order/address_book.rb +1 -0
  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/{app/models/spree → lib/spree/core}/preferences/preferable_class_methods.rb +0 -0
  127. data/{app/models/spree → lib/spree/core}/preferences/scoped_store.rb +0 -0
  128. data/{app/models/spree → lib/spree/core}/preferences/store.rb +0 -0
  129. data/lib/spree/core/search/base.rb +9 -5
  130. data/lib/spree/core/version.rb +1 -1
  131. data/lib/spree/core.rb +25 -5
  132. data/lib/spree/permitted_attributes.rb +9 -7
  133. data/lib/spree/testing_support/common_rake.rb +1 -0
  134. data/lib/spree/testing_support/factories/favicon_image_factory.rb +9 -0
  135. data/lib/spree/testing_support/factories/icon_factory.rb +3 -1
  136. data/lib/spree/testing_support/factories/image_factory.rb +3 -1
  137. data/lib/spree/testing_support/factories/menu_item_factory.rb +1 -1
  138. data/lib/spree/testing_support/factories/order_factory.rb +2 -1
  139. data/lib/spree/testing_support/factories/product_factory.rb +6 -1
  140. data/lib/spree/testing_support/factories/product_property_factory.rb +1 -0
  141. data/lib/spree/testing_support/factories/refund_factory.rb +1 -1
  142. data/lib/spree/testing_support/factories/return_authorization_factory.rb +1 -1
  143. data/lib/spree/testing_support/factories/role_factory.rb +1 -1
  144. data/lib/spree/testing_support/factories/shipping_category_factory.rb +1 -1
  145. data/lib/spree/testing_support/factories/stock_location_factory.rb +3 -2
  146. data/lib/spree/testing_support/factories/store_factory.rb +1 -1
  147. data/lib/spree/testing_support/factories/taxon_image_factory.rb +3 -1
  148. data/lib/spree/testing_support/factories/user_factory.rb +4 -0
  149. data/lib/spree/testing_support/factories/variant_factory.rb +4 -0
  150. data/lib/spree_core.rb +2 -1
  151. data/lib/tasks/core.rake +12 -0
  152. data/spree_core.gemspec +2 -3
  153. metadata +63 -51
  154. data/app/models/friendly_id/slug_decorator.rb +0 -9
  155. data/app/models/spree/app_configuration.rb +0 -86
  156. data/lib/friendly_id/slug_rails5_patch.rb +0 -11
  157. data/lib/spree/core/app_dependencies.rb +0 -126
@@ -1,5 +1,9 @@
1
1
  module Spree
2
2
  class InventoryUnit < Spree::Base
3
+ if defined?(Spree::Webhooks)
4
+ include Spree::Webhooks::HasWebhooks
5
+ end
6
+
3
7
  with_options inverse_of: :inventory_units do
4
8
  belongs_to :variant, -> { with_deleted }, class_name: 'Spree::Variant'
5
9
  belongs_to :order, class_name: 'Spree::Order'
@@ -59,8 +63,7 @@ module Spree
59
63
  end
60
64
 
61
65
  def find_stock_item
62
- Spree::StockItem.where(stock_location_id: shipment.stock_location_id,
63
- variant_id: variant_id).first
66
+ shipment.stock_location.stock_item_or_create(variant)
64
67
  end
65
68
 
66
69
  def self.split(original_inventory_unit, extract_quantity)
@@ -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])
@@ -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