workarea-core 3.5.11 → 3.5.16

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 (40) hide show
  1. checksums.yaml +4 -4
  2. data/app/models/workarea/checkout.rb +1 -5
  3. data/app/models/workarea/inventory/sku.rb +2 -2
  4. data/app/models/workarea/metrics/user.rb +24 -8
  5. data/app/models/workarea/order.rb +13 -3
  6. data/app/models/workarea/payment.rb +1 -6
  7. data/app/models/workarea/releasable.rb +3 -1
  8. data/app/models/workarea/release/changeset.rb +1 -0
  9. data/app/models/workarea/search/admin/pricing_discount.rb +1 -1
  10. data/app/models/workarea/search/storefront.rb +9 -1
  11. data/app/models/workarea/search/storefront/category_query.rb +1 -1
  12. data/app/models/workarea/search/storefront/product.rb +11 -2
  13. data/app/queries/workarea/product_releases.rb +6 -0
  14. data/app/services/workarea/direct_upload.rb +17 -13
  15. data/app/services/workarea/index_release_schedule_previews.rb +37 -0
  16. data/app/workers/workarea/index_category_changes.rb +16 -3
  17. data/app/workers/workarea/index_release_schedule_change.rb +32 -0
  18. data/app/workers/workarea/process_import.rb +3 -3
  19. data/app/workers/workarea/publish_release.rb +1 -0
  20. data/lib/tasks/search.rake +10 -4
  21. data/lib/workarea/configuration.rb +11 -0
  22. data/lib/workarea/configuration/administrable_options.rb +1 -5
  23. data/lib/workarea/core.rb +2 -0
  24. data/lib/workarea/ext/jbuilder/jbuilder_cache.rb +29 -0
  25. data/lib/workarea/queues_pauser.rb +26 -0
  26. data/lib/workarea/version.rb +1 -1
  27. data/lib/workarea/visit.rb +8 -1
  28. data/test/models/workarea/releasable_test.rb +13 -0
  29. data/test/models/workarea/search/storefront/category_query_test.rb +11 -0
  30. data/test/models/workarea/search/storefront/product_releases_test.rb +60 -0
  31. data/test/models/workarea/search/storefront_test.rb +13 -0
  32. data/test/queries/workarea/search/category_browse_test.rb +23 -0
  33. data/test/services/workarea/direct_upload_test.rb +20 -3
  34. data/test/services/workarea/index_release_schedule_previews_test.rb +28 -0
  35. data/test/workers/workarea/index_release_schedule_change_test.rb +107 -0
  36. data/test/workers/workarea/process_import_test.rb +6 -0
  37. data/test/workers/workarea/publish_release_test.rb +24 -0
  38. data/workarea-core.gemspec +5 -4
  39. metadata +31 -11
  40. data/test/queries/workarea/product_releases_test.rb +0 -56
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 72fffa19332c0b8652c70135ef370a1704350ea0037845df1615c958bd9a8bc8
4
- data.tar.gz: 717aaef848a0ad75774fc0ed23b41c80362b8657c021d06630296dbdbe3e4dea
3
+ metadata.gz: 569f33ae16d992354fca8761ef67ed5473a12755dda710cfff057ebd2d7aa2b4
4
+ data.tar.gz: 24b32513e4215b2aa1c67a5f1d930ae5f8a81ee098be08234eab95f69a6bc574
5
5
  SHA512:
6
- metadata.gz: da8b605d36c1b60257fb73d8e65a3bee6e5b99f03d991861b4eef5ab9338fd00e8787eb1e32d6e1df3905bdc95ec349d3ab022a6b0a7e648e0006eb6341f444e
7
- data.tar.gz: '09fbd0f844ae5ff48b37f160981b9173982114a0f5584e6846a565be9459697812265e9c4224f82efabfe12265537b3e6bfb0f1c501ad0521bc632d9ca13f82e'
6
+ metadata.gz: 11b65e3f2de7268ec497fecb2019a10133e2a477cc5bf06cd64390976098baa97277a75a295633a4fd6e43b221d31453c6a4da99b1c05012534e19621a6c7d18
7
+ data.tar.gz: 614ed5b1d7970082ba8eb48b8448434737d194ed1fed7158537774b9e46dce862ab0cae2faafca35f40378a061e3a91c02b9ab4d36875201896ea33ff6b60991
@@ -47,11 +47,7 @@ module Workarea
47
47
  def inventory
48
48
  @inventory ||= Inventory::Transaction.from_order(
49
49
  order.id,
50
- order.items.inject({}) do |memo, item|
51
- memo[item.sku] ||= 0
52
- memo[item.sku] += item.quantity
53
- memo
54
- end
50
+ order.sku_quantities
55
51
  )
56
52
  end
57
53
 
@@ -142,11 +142,11 @@ module Workarea
142
142
  end
143
143
 
144
144
  def policy_class
145
- "Workarea::Inventory::Policies::#{policy.classify}".constantize
145
+ "Workarea::Inventory::Policies::#{policy.camelize}".constantize
146
146
  rescue NameError
147
147
  raise(
148
148
  InvalidPolicy,
149
- "Workarea::Inventory::Policies::#{policy.classify} must be a policy class"
149
+ "Workarea::Inventory::Policies::#{policy.camelize} must be a policy class"
150
150
  )
151
151
  end
152
152
 
@@ -110,14 +110,28 @@ module Workarea
110
110
  end
111
111
 
112
112
  def merge!(other)
113
- %w(orders revenue discounts cancellations refund).each do |field|
114
- self.send("#{field}=", send(field) + other.send(field))
115
- end
116
-
117
- self.first_order_at = [first_order_at, other.first_order_at].compact.min
118
- self.last_order_at = [last_order_at, other.last_order_at].compact.max
119
- self.average_order_value = average_order_value
120
- save!
113
+ # To recalculate average_order_value
114
+ self.orders += other.orders
115
+ self.revenue += other.revenue
116
+
117
+ update = {
118
+ '$set' => {
119
+ average_order_value: average_order_value,
120
+ updated_at: Time.current.utc
121
+ },
122
+ '$inc' => {
123
+ orders: other.orders,
124
+ revenue: other.revenue,
125
+ discounts: other.discounts,
126
+ cancellations: other.cancellations,
127
+ refund: other.refund
128
+ }
129
+ }
130
+
131
+ update['$min'] = { first_order_at: other.first_order_at.utc } if other.first_order_at.present?
132
+ update['$max'] = { last_order_at: other.last_order_at.utc } if other.last_order_at.present?
133
+
134
+ self.class.collection.update_one({ _id: id }, update, upsert: true)
121
135
 
122
136
  self.class.save_affinity(
123
137
  id: id,
@@ -133,6 +147,8 @@ module Workarea
133
147
  category_ids: other.purchased.category_ids,
134
148
  search_ids: other.purchased.search_ids
135
149
  )
150
+
151
+ reload
136
152
  end
137
153
  end
138
154
  end
@@ -47,13 +47,13 @@ module Workarea
47
47
  {
48
48
  placed_at: 1,
49
49
  reminded_at: 1,
50
+ fraud_suspected_at: 1,
50
51
  checkout_started_at: 1,
51
52
  email: 1,
52
- "items[0]._id": 1,
53
- fraud_suspected_at: 1
53
+ "items[0]._id": 1
54
54
  },
55
55
  {
56
- name: 'abandoned_order_email_with_fraud_index',
56
+ name: 'abandoned_order_email_with_fraud_index_v2',
57
57
  background: true
58
58
  }
59
59
  )
@@ -375,6 +375,16 @@ module Workarea
375
375
  )
376
376
  end
377
377
 
378
+ # A hash with the quantity of each SKU in the order
379
+ #
380
+ # @return [Hash]
381
+ #
382
+ def sku_quantities
383
+ items.each_with_object(Hash.new(0)) do |item, quantities|
384
+ quantities[item.sku] += item.quantity
385
+ end
386
+ end
387
+
378
388
  private
379
389
 
380
390
  def item_count_limit
@@ -80,12 +80,7 @@ module Workarea
80
80
  build_credit_card unless credit_card
81
81
  credit_card.saved_card_id = nil
82
82
  credit_card.attributes = attrs.slice(
83
- :month,
84
- :year,
85
- :saved_card_id,
86
- :number,
87
- :cvv,
88
- :amount
83
+ *Workarea.config.credit_card_attributes
89
84
  )
90
85
  save
91
86
  end
@@ -72,7 +72,9 @@ module Workarea
72
72
  release.preview.changesets_for(self).each { |cs| cs.apply_to(result) }
73
73
  result
74
74
  else
75
- Release.with_current(release) { self.class.find(id) }
75
+ Release.with_current(release) do
76
+ Mongoid::QueryCache.uncached { self.class.find(id) }
77
+ end
76
78
  end
77
79
  end
78
80
 
@@ -18,6 +18,7 @@ module Workarea
18
18
  index({ 'document_path.type' => 1, 'document_path.document_id' => 1 })
19
19
  index('changeset.product_ids' => 1)
20
20
  index('original.product_ids' => 1)
21
+ index('releasable_type' => 1, 'releasable_id' => 1)
21
22
 
22
23
  # Finds changeset by whether the passed document is in the document
23
24
  # path of the changeset. Useful for showing embedded changes in the
@@ -21,7 +21,7 @@ module Workarea
21
21
  end
22
22
 
23
23
  def keywords
24
- super + model.promo_codes
24
+ super + Array.wrap(model.try(:promo_codes))
25
25
  end
26
26
 
27
27
  def facets
@@ -82,6 +82,14 @@ module Workarea
82
82
  @changesets ||= Array.wrap(model.try(:changesets_with_children))
83
83
  end
84
84
 
85
+ def releases
86
+ changesets
87
+ .uniq(&:release)
88
+ .reject { |cs| cs.release.blank? }
89
+ .flat_map { |cs| [cs.release] + cs.release.scheduled_after }
90
+ .uniq
91
+ end
92
+
85
93
  def as_document
86
94
  Release.with_current(release_id) do
87
95
  {
@@ -91,7 +99,7 @@ module Workarea
91
99
  active: active,
92
100
  active_segment_ids: active_segment_ids,
93
101
  release_id: release_id,
94
- changeset_release_ids: changesets.map(&:release_id),
102
+ changeset_release_ids: releases.map(&:id),
95
103
  suggestion_content: suggestion_content,
96
104
  created_at: model.created_at,
97
105
  updated_at: model.updated_at,
@@ -144,7 +144,7 @@ module Workarea
144
144
  .where(releasable_type: ProductRule.name)
145
145
  .any_in(releasable_id: category.product_rules.map(&:id))
146
146
  .includes(:release)
147
- .to_a
147
+ .select(&:release)
148
148
  end
149
149
  end
150
150
  end
@@ -122,12 +122,21 @@ module Workarea
122
122
  ProductPrimaryImageUrl.new(model).path
123
123
  end
124
124
 
125
- # Override to include release changesets for pricing, featured products, etc.
125
+ # All {Releasable}s that could affect the product's Elasticsearch document
126
+ # should add their changesets to this method.
127
+ #
128
+ # @example Add to the changesets affecting a product in a decorator
129
+ # def changesets
130
+ # super.merge(SomeReleasable.for_product(product.id).changesets_with_children)
131
+ # end
126
132
  #
127
133
  # @return [Mongoid::Criteria]
128
134
  #
129
135
  def changesets
130
- @product_changesets ||= ProductReleases.new(model).changesets
136
+ criteria = model.changesets_with_children
137
+ pricing.each { |ps| criteria.merge!(ps.changesets_with_children) }
138
+ criteria.merge!(FeaturedProducts.changesets(model.id))
139
+ criteria.includes(:release)
131
140
  end
132
141
 
133
142
  private
@@ -1,4 +1,10 @@
1
1
  module Workarea
2
+ #
3
+ # TODO remove in v3.6
4
+ #
5
+ # This is no longer used, this logic was moved into the search models to allow
6
+ # it to be used for any model (not just products).
7
+ #
2
8
  class ProductReleases
3
9
  attr_reader :product
4
10
 
@@ -6,22 +6,26 @@ module Workarea
6
6
  uri = URI.parse(request_url)
7
7
  url = "#{uri.scheme}://#{uri.host}"
8
8
  url += ":#{uri.port}" unless uri.port.in? [80, 443]
9
+ id = "direct_upload_#{url}"
9
10
 
10
- redis_key = "cors_#{url.optionize}"
11
- return if Workarea.redis.get(redis_key) == 'true'
11
+ response = begin
12
+ Workarea.s3.get_bucket_cors(Configuration::S3.bucket)
13
+ rescue Excon::Error::NotFound
14
+ Excon::Response.new(body: { 'CORSConfiguration' => [] })
15
+ end
12
16
 
13
- response = Workarea.s3.get_bucket_cors(Configuration::S3.bucket)
14
17
  cors = response.data[:body]
15
- cors['CORSConfiguration'] << {
16
- 'ID' => "direct_upload_#{url}",
17
- 'AllowedMethod' => 'PUT',
18
- 'AllowedOrigin' => url,
19
- 'AllowedHeader' => '*'
20
- }
21
- cors['CORSConfiguration'].uniq!
22
-
23
- Workarea.s3.put_bucket_cors(Configuration::S3.bucket, cors)
24
- Workarea.redis.set(redis_key, 'true')
18
+
19
+ unless cors['CORSConfiguration'].pluck('ID').include?(id)
20
+ cors['CORSConfiguration'] << {
21
+ 'ID' => id,
22
+ 'AllowedMethod' => 'PUT',
23
+ 'AllowedOrigin' => url,
24
+ 'AllowedHeader' => '*'
25
+ }
26
+
27
+ Workarea.s3.put_bucket_cors(Configuration::S3.bucket, cors)
28
+ end
25
29
  end
26
30
 
27
31
  attr_reader :type, :filename
@@ -0,0 +1,37 @@
1
+ module Workarea
2
+ class IndexReleaseSchedulePreviews
3
+ attr_reader :release, :starts_at, :ends_at
4
+
5
+ def initialize(release: nil, starts_at: nil, ends_at: nil)
6
+ @release = release
7
+ @starts_at = starts_at
8
+ @ends_at = ends_at
9
+ end
10
+
11
+ def affected_releases
12
+ result = Release
13
+ .scheduled(after: starts_at, before: ends_at)
14
+ .includes(:changesets)
15
+ .to_a
16
+
17
+ result << release if release.present?
18
+ result.uniq
19
+ end
20
+
21
+ def affected_models
22
+ affected_releases.flat_map(&:changesets).flat_map(&:releasable).compact
23
+ end
24
+
25
+ def perform
26
+ affected_releases.each do |release|
27
+ affected_models.each do |releasable|
28
+ Search::Storefront.new(releasable.in_release(release)).destroy
29
+
30
+ # Different models have different indexing workers, running callbacks
31
+ # ensures the appropriate worker is triggered
32
+ releasable.run_callbacks(:save_release_changes)
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -4,16 +4,29 @@ module Workarea
4
4
  include Sidekiq::CallbacksWorker
5
5
 
6
6
  sidekiq_options(
7
- enqueue_on: { Catalog::Category => [:save, :save_release_changes], with: -> { [changes] } },
7
+ enqueue_on: {
8
+ Catalog::Category => [:save, :save_release_changes],
9
+ with: -> { [changes, Release.current.present?] }
10
+ },
8
11
  ignore_if: -> { changes['product_ids'].blank? },
9
12
  lock: :until_executing,
10
13
  query_cache: true
11
14
  )
12
15
 
13
- def perform(changes)
16
+ def perform(changes, for_release = false)
14
17
  return unless changes['product_ids'].present?
15
18
 
16
- ids = require_index_ids(*changes['product_ids'])
19
+ ids = if for_release
20
+ # This is a shortcut because if you're resorting products within a release,
21
+ # the `changes` hash doesn't reflect the repositioning within the release,
22
+ # only the difference between what's live and what's in the release.
23
+ #
24
+ # Reindexing all of them is a shortcut to having to manually build a diff
25
+ # between the changesets in the possible affected releases.
26
+ changes['product_ids'].flatten.uniq
27
+ else
28
+ require_index_ids(*changes['product_ids'])
29
+ end
17
30
 
18
31
  if ids.size > max_count
19
32
  ids.each { |id| IndexProduct.perform_async(id) }
@@ -0,0 +1,32 @@
1
+ module Workarea
2
+ class IndexReleaseScheduleChange
3
+ include Sidekiq::Worker
4
+ include Sidekiq::CallbacksWorker
5
+
6
+ sidekiq_options(
7
+ enqueue_on: {
8
+ Release => [:save, :destroy],
9
+ only_if: -> { publish_at_changed? || destroyed? },
10
+ with: -> { [id, publish_at_was, publish_at] }
11
+ },
12
+ queue: 'releases'
13
+ )
14
+
15
+ def perform(id, previous_publish_at, new_publish_at)
16
+ # When destroyed, changesets for the release ID will still exist and be used to update the index
17
+ rescheduled_release = Release.find_or_initialize_by(id: id)
18
+
19
+ earlier, later = if rescheduled_release.persisted? && previous_publish_at.present? && new_publish_at.present?
20
+ [previous_publish_at, new_publish_at].sort
21
+ elsif previous_publish_at.present?
22
+ [previous_publish_at, nil]
23
+ else
24
+ [new_publish_at, nil]
25
+ end
26
+
27
+ IndexReleaseSchedulePreviews
28
+ .new(release: rescheduled_release, starts_at: earlier, ends_at: later)
29
+ .perform
30
+ end
31
+ end
32
+ end
@@ -17,11 +17,11 @@ module Workarea
17
17
  import.process!
18
18
 
19
19
  ensure
20
- if import.error?
20
+ if import&.error?
21
21
  Admin::DataFileMailer.import_error(id).deliver_now
22
- elsif import.failure?
22
+ elsif import&.failure?
23
23
  Admin::DataFileMailer.import_failure(id).deliver_now
24
- else
24
+ elsif import.present?
25
25
  Admin::DataFileMailer.import(id).deliver_now
26
26
  end
27
27
  end
@@ -8,6 +8,7 @@ module Workarea
8
8
  system_user = User.find_system_user!(release.name, 'Release')
9
9
 
10
10
  Mongoid::AuditLog.record(system_user) { release.publish! }
11
+ IndexReleaseSchedulePreviews.new(release: release).perform
11
12
 
12
13
  rescue Mongoid::Errors::DocumentNotFound
13
14
  # Doesn't matter, release has been removed
@@ -16,7 +16,9 @@ namespace :workarea do
16
16
  task admin: :environment do
17
17
  setup
18
18
  puts 'Indexing admin...'
19
- Workarea::Search::Admin.reset_indexes!
19
+ Workarea::QueuesPauser.with_paused_queues do
20
+ Workarea::Search::Admin.reset_indexes!
21
+ end
20
22
 
21
23
  Mongoid.models.each do |klass|
22
24
  next unless Workarea::Search::Admin.for(klass.first).present?
@@ -36,8 +38,10 @@ namespace :workarea do
36
38
  setup
37
39
  puts 'Indexing storefront...'
38
40
 
39
- Workarea::Search::Storefront.reset_indexes!
40
- Workarea::Search::Storefront.ensure_dynamic_mappings
41
+ Workarea::QueuesPauser.with_paused_queues do
42
+ Workarea::Search::Storefront.reset_indexes!
43
+ Workarea::Search::Storefront.ensure_dynamic_mappings
44
+ end
41
45
 
42
46
  # This code finds all unique filters for products so we can index a sample
43
47
  # product for each to ensure the dynamic mappings get created.
@@ -83,7 +87,9 @@ namespace :workarea do
83
87
  setup
84
88
  puts 'Indexing help...'
85
89
 
86
- Workarea::Search::Help.reset_indexes!
90
+ Workarea::QueuesPauser.with_paused_queues do
91
+ Workarea::Search::Help.reset_indexes!
92
+ end
87
93
 
88
94
  Workarea::Help::Article.all.each_by(Workarea.config.bulk_index_batch_size) do |help_article|
89
95
  Workarea::Search::Help.new(help_article).save
@@ -1297,6 +1297,17 @@ module Workarea
1297
1297
 
1298
1298
  # The number of results that will show per-type in the admin jump to
1299
1299
  config.jump_to_results_per_type = 5
1300
+
1301
+ # Attributes that will be sliced out of params and persisted on
1302
+ # the credit card tender during checkout.
1303
+ config.credit_card_attributes = %i[
1304
+ month
1305
+ year
1306
+ saved_card_id
1307
+ number
1308
+ cvv
1309
+ amount
1310
+ ]
1300
1311
  end
1301
1312
  end
1302
1313
  end
@@ -1,7 +1,7 @@
1
1
  module Workarea
2
2
  module Configuration
3
3
  class AdministrableOptions < ActiveSupport::InheritableOptions
4
- def method_missing(name, *args)
4
+ def [](name)
5
5
  static_config = super
6
6
  return static_config if static_config.present? || static_config.to_s == 'false'
7
7
  return static_config unless check_fieldsets?(name)
@@ -9,10 +9,6 @@ module Workarea
9
9
  Configuration::Admin.instance.send(name)
10
10
  end
11
11
 
12
- def respond_to_missing?(name, include_private)
13
- true
14
- end
15
-
16
12
  private
17
13
 
18
14
  def check_fieldsets?(name)
@@ -146,6 +146,7 @@ require 'workarea/ext/mongoid/find_ordered'
146
146
  require 'workarea/ext/mongoid/embedded_children'
147
147
  require 'workarea/ext/sprockets/ruby_processor'
148
148
  require 'workarea/ext/jbuilder/jbuilder_append_partials'
149
+ require 'workarea/ext/jbuilder/jbuilder_cache'
149
150
 
150
151
  if Rails.env.development?
151
152
  require 'workarea/ext/freedom_patches/routes_reloader'
@@ -221,6 +222,7 @@ require 'workarea/mail_interceptor'
221
222
  require 'workarea/visit'
222
223
  require 'workarea/warnings'
223
224
  require 'workarea/latest_version'
225
+ require 'workarea/queues_pauser'
224
226
 
225
227
  #
226
228
  # Engines
@@ -0,0 +1,29 @@
1
+ decorate JbuilderTemplate, with: :workarea do
2
+ def _cache_fragment_for(*)
3
+ return yield if workarea_admin?
4
+
5
+ super
6
+ end
7
+
8
+ def _cache_key(*)
9
+ super.tap do |result|
10
+ result << workarea_cache_varies if workarea_cache_varies.present?
11
+ end
12
+ end
13
+
14
+ private
15
+
16
+ def workarea_admin?
17
+ @context&.controller&.current_user&.admin?
18
+ rescue ::RuntimeError
19
+ false
20
+ end
21
+
22
+ def workarea_cache_varies
23
+ workarea_request_env['workarea.cache_varies']
24
+ end
25
+
26
+ def workarea_request_env
27
+ @context.controller.request.env || {}
28
+ end
29
+ end
@@ -0,0 +1,26 @@
1
+ module Workarea
2
+ module QueuesPauser
3
+ extend self
4
+
5
+ def pause_queues!
6
+ pauser = Sidekiq::Throttled::QueuesPauser.instance
7
+ queues.each { |queue| pauser.pause!(queue) }
8
+ end
9
+
10
+ def resume_queues!
11
+ pauser = Sidekiq::Throttled::QueuesPauser.instance
12
+ queues.each { |queue| pauser.resume!(queue) }
13
+ end
14
+
15
+ def with_paused_queues(&block)
16
+ pause_queues!
17
+ yield
18
+ ensure
19
+ resume_queues!
20
+ end
21
+
22
+ def queues
23
+ Configuration::Sidekiq.queues
24
+ end
25
+ end
26
+ end
@@ -2,7 +2,7 @@ module Workarea
2
2
  module VERSION
3
3
  MAJOR = 3
4
4
  MINOR = 5
5
- PATCH = 11
5
+ PATCH = 16
6
6
  PRE = nil
7
7
  STRING = [MAJOR, MINOR, PATCH, PRE].compact.join('.')
8
8
 
@@ -38,7 +38,10 @@ module Workarea
38
38
  end
39
39
 
40
40
  def current_email
41
- cookies.signed[:email]
41
+ # For performance, prefer to use the cookie. The fallback to looking it up
42
+ # by user is a failsafe against a blank email cookie (e.g. from a raised
43
+ # error or poor application coding).
44
+ cookies.signed[:email].presence || (email_from_user_id if logged_in?)
42
45
  end
43
46
 
44
47
  def metrics
@@ -91,5 +94,9 @@ module Workarea
91
94
  def blank_metrics
92
95
  @blank_metrics ||= Metrics::User.new
93
96
  end
97
+
98
+ def email_from_user_id
99
+ User.find(session[:user_id]).email rescue nil
100
+ end
94
101
  end
95
102
  end
@@ -375,6 +375,19 @@ module Workarea
375
375
  in_release = model.in_release(nil)
376
376
  assert_equal('Foo', in_release.name)
377
377
  refute_equal(in_release.object_id, model.object_id)
378
+
379
+ Mongoid::QueryCache.cache do
380
+ cached = Foo.find(model.id) # a find to ensure it's in the cache table
381
+ cached.name = 'Bar' # so the cache table's instance has a change
382
+
383
+ in_release = model.in_release(nil)
384
+ assert_equal('Foo', in_release.name)
385
+ refute_equal(in_release.object_id, model.object_id)
386
+ refute_equal(cached.object_id, model.object_id)
387
+ end
388
+
389
+ ensure
390
+ Mongoid::QueryCache.clear_cache
378
391
  end
379
392
 
380
393
  def test_skip_changeset
@@ -75,6 +75,17 @@ module Workarea
75
75
  assert_equal([@category.id.to_s], CategoryQuery.find_by_product(@product))
76
76
  end
77
77
  end
78
+
79
+ def test_deleted_releases
80
+ release = create_release
81
+ release.as_current do
82
+ @category.product_rules.first.update!(value: 'bar')
83
+ end
84
+
85
+ release.destroy
86
+ CategoryQuery.new(@category).update
87
+ assert_equal([@category.id.to_s], CategoryQuery.find_by_product(@product))
88
+ end
78
89
  end
79
90
  end
80
91
  end
@@ -0,0 +1,60 @@
1
+ require 'test_helper'
2
+
3
+ module Workarea
4
+ module Search
5
+ class Storefront
6
+ class ProductReleasesTest < TestCase
7
+ def test_product_changes
8
+ product = create_product(name: 'Foo')
9
+ release_one = create_release
10
+ release_one.as_current { product.update!(name: 'Bar') }
11
+
12
+ assert_equal([release_one], Product.new(product).releases)
13
+
14
+ release_one.update!(publish_at: 1.day.from_now)
15
+ release_two = create_release(publish_at: 3.days.from_now)
16
+ assert_equal([release_one, release_two], Product.new(product).releases)
17
+ end
18
+
19
+ def test_featured_product_changes
20
+ product = create_product
21
+ category = create_category
22
+
23
+ release_one = create_release
24
+ release_one.as_current { category.update!(product_ids: [product.id]) }
25
+ assert_equal([release_one], Product.new(product).releases)
26
+
27
+ release_one.update!(publish_at: 1.day.from_now)
28
+ release_two = create_release(publish_at: 3.days.from_now)
29
+ assert_equal([release_one, release_two], Product.new(product).releases)
30
+ end
31
+
32
+ def test_variant_changes
33
+ product = create_product(variants: [{ sku: 'SKU' }])
34
+ release = create_release
35
+ release.as_current { product.variants.first.update!(details: { color: 'Red' }) }
36
+ assert_equal([release], Product.new(product).releases)
37
+ end
38
+
39
+ def test_pricing_changes
40
+ product = create_product(variants: [{ sku: 'SKU' }])
41
+ pricing = Pricing::Sku.find('SKU')
42
+
43
+ release = create_release
44
+ release.as_current { pricing.prices.first.update!(regular: 10_000) }
45
+ assert_equal([release], Product.new(product).releases)
46
+ end
47
+
48
+ def test_changesets_with_missing_releases
49
+ product = create_product(name: 'Foo')
50
+ release = create_release
51
+ release.as_current { product.update!(name: 'Bar') }
52
+ release.delete
53
+
54
+ assert_nil(product.reload.changesets.first.release)
55
+ assert_equal([], Product.new(product).releases)
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -25,6 +25,19 @@ module Workarea
25
25
  release.as_current { category.product_rules.first.update!(value: 'bar') }
26
26
  assert_equal(2, Storefront.new(category).changesets.size)
27
27
  end
28
+
29
+ def test_releases
30
+ category = create_category(name: 'Foo')
31
+ assert_empty(Storefront.new(category).as_document[:changeset_release_ids])
32
+
33
+ a = create_release(publish_at: 1.week.from_now)
34
+ a.as_current { category.update!(name: 'Bar') }
35
+ assert_equal([a.id], Storefront.new(category).as_document[:changeset_release_ids])
36
+
37
+ b = create_release(publish_at: 2.weeks.from_now)
38
+ assert_includes(Storefront.new(category).as_document[:changeset_release_ids], a.id)
39
+ assert_includes(Storefront.new(category).as_document[:changeset_release_ids], b.id)
40
+ end
28
41
  end
29
42
  end
30
43
  end
@@ -382,6 +382,29 @@ module Workarea
382
382
  refute_includes(result_ids, product_five.id)
383
383
  end
384
384
  end
385
+
386
+ def test_featured_product_changes_in_a_release
387
+ one = create_product
388
+ two = create_product
389
+ three = create_product(name: 'Foo', active: false)
390
+ category = create_category(product_ids: [one.id, two.id], product_rules: [])
391
+ release = create_release(publish_at: 1.week.from_now)
392
+
393
+ release.as_current do
394
+ three.update!(name: 'Bar', active: true, default_category_id: category.id)
395
+ category.update!(product_ids: [three.id, one.id, two.id])
396
+ search = CategoryBrowse.new(sort: %w(featured), category_ids: [category.id])
397
+ sorts = search.results.pluck(:raw).pluck('_source').pluck('sorts').pluck(category.id.to_s)
398
+ assert_equal([0, 1, 2], sorts)
399
+ end
400
+
401
+ release.as_current do
402
+ category.update!(product_ids: [one.id, two.id, three.id])
403
+ search = CategoryBrowse.new(sort: %w(featured), category_ids: [category.id])
404
+ sorts = search.results.pluck(:raw).pluck('_source').pluck('sorts').pluck(category.id.to_s)
405
+ assert_equal([0, 1, 2], sorts)
406
+ end
407
+ end
385
408
  end
386
409
  end
387
410
  end
@@ -108,11 +108,28 @@ module Workarea
108
108
  ).returns(true)
109
109
 
110
110
  assert(DirectUpload.ensure_cors!('http://test.host/admin/content_assets'))
111
- assert_equal('true', Workarea.redis.get('cors_http_test_host'))
112
111
  assert(DirectUpload.ensure_cors!('http://localhost:3000/admin/content_assets'))
113
- assert_equal('true', Workarea.redis.get('cors_http_localhost_3000'))
114
112
  assert(DirectUpload.ensure_cors!('https://example.com/admin/direct_uploads'))
115
- assert_equal('true', Workarea.redis.get('cors_https_example_com'))
113
+ end
114
+
115
+ def test_ensure_cors_with_no_existing_configuration
116
+ Workarea.s3.expects(:get_bucket_cors)
117
+ .raises(Excon::Errors::NotFound.new('CORS configuration does not exist'))
118
+
119
+
120
+ Workarea.s3.expects(:put_bucket_cors).with(
121
+ Configuration::S3.bucket,
122
+ 'CORSConfiguration' => [
123
+ {
124
+ 'ID' => "direct_upload_http://test.host",
125
+ 'AllowedMethod' => 'PUT',
126
+ 'AllowedOrigin' => 'http://test.host',
127
+ 'AllowedHeader' => '*'
128
+ }
129
+ ]
130
+ ).returns(true)
131
+
132
+ assert(DirectUpload.ensure_cors!('http://test.host/admin/content_assets'))
116
133
  end
117
134
 
118
135
  private
@@ -0,0 +1,28 @@
1
+ require 'test_helper'
2
+
3
+ module Workarea
4
+ class IndexReleaseSchedulePreviewsTest < TestCase
5
+ def test_affected_releases
6
+ release = create_release
7
+ results = IndexReleaseSchedulePreviews.new(release: release).affected_releases
8
+ assert_equal([release], results)
9
+
10
+ a = create_release(publish_at: 1.week.from_now)
11
+ b = create_release(publish_at: 2.weeks.from_now)
12
+ c = create_release(publish_at: 4.weeks.from_now)
13
+ assert_equal([a, b, c], IndexReleaseSchedulePreviews.new.affected_releases)
14
+
15
+ results = IndexReleaseSchedulePreviews
16
+ .new(starts_at: 3.days.from_now, ends_at: 17.days.from_now)
17
+ .affected_releases
18
+
19
+ assert_equal([a, b], results)
20
+
21
+ results = IndexReleaseSchedulePreviews
22
+ .new(release: release, starts_at: 3.days.from_now, ends_at: 10.days.from_now)
23
+ .affected_releases
24
+
25
+ assert_equal([a, release], results)
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,107 @@
1
+ require 'test_helper'
2
+
3
+ module Workarea
4
+ class IndexReleaseScheduleChangeTest < TestCase
5
+ include TestCase::SearchIndexing
6
+
7
+ setup :set_product
8
+
9
+ def set_product
10
+ @product = create_product(name: 'Foo')
11
+ end
12
+
13
+ def test_reschedule
14
+ a = create_release(name: 'A', publish_at: 1.week.from_now)
15
+ b = create_release(name: 'B', publish_at: 2.weeks.from_now)
16
+ c = create_release(name: 'C', publish_at: 4.weeks.from_now)
17
+
18
+ b.as_current { @product.update!(name: 'Bar') }
19
+ IndexProduct.perform(@product)
20
+
21
+ a.as_current { assert_empty(Search::ProductSearch.new(q: 'bar').results.pluck(:model)) }
22
+ b.as_current { assert_equal([@product], Search::ProductSearch.new(q: 'bar').results.pluck(:model)) }
23
+ c.as_current { assert_equal([@product], Search::ProductSearch.new(q: 'bar').results.pluck(:model)) }
24
+
25
+ # Changing publish_at via `update` causes the release to publish due to Sidekiq inline
26
+ previous_publish_at = b.publish_at
27
+ b.set(publish_at: 5.weeks.from_now)
28
+
29
+ Sidekiq::Callbacks.enable(IndexProduct) do
30
+ IndexReleaseScheduleChange.new.perform(b.id, previous_publish_at, b.publish_at)
31
+ end
32
+
33
+ a.as_current { assert_empty(Search::ProductSearch.new(q: 'bar').results.pluck(:model)) }
34
+ b.as_current { assert_equal([@product], Search::ProductSearch.new(q: 'bar').results.pluck(:model)) }
35
+ c.as_current { assert_empty(Search::ProductSearch.new(q: 'bar').results.pluck(:model)) }
36
+ end
37
+
38
+ def test_removing_from_schedule
39
+ a = create_release(name: 'A', publish_at: 1.week.from_now)
40
+ b = create_release(name: 'B', publish_at: 2.weeks.from_now)
41
+ c = create_release(name: 'C', publish_at: 4.weeks.from_now)
42
+
43
+ b.as_current { @product.update!(name: 'Bar') }
44
+ IndexProduct.perform(@product)
45
+
46
+ a.as_current { assert_empty(Search::ProductSearch.new(q: 'bar').results.pluck(:model)) }
47
+ b.as_current { assert_equal([@product], Search::ProductSearch.new(q: 'bar').results.pluck(:model)) }
48
+ c.as_current { assert_equal([@product], Search::ProductSearch.new(q: 'bar').results.pluck(:model)) }
49
+
50
+ # Changing publish_at via `update` causes the release to publish due to Sidekiq inline
51
+ previous_publish_at = b.publish_at
52
+ b.set(publish_at: nil)
53
+
54
+ Sidekiq::Callbacks.enable(IndexProduct) do
55
+ IndexReleaseScheduleChange.new.perform(b.id, previous_publish_at, nil)
56
+ end
57
+
58
+ a.as_current { assert_empty(Search::ProductSearch.new(q: 'bar').results.pluck(:model)) }
59
+ b.as_current { assert_equal([@product], Search::ProductSearch.new(q: 'bar').results.pluck(:model)) }
60
+ c.as_current { assert_empty(Search::ProductSearch.new(q: 'bar').results.pluck(:model)) }
61
+ end
62
+
63
+ def test_adding_to_schedule
64
+ a = create_release(name: 'A', publish_at: 1.week.from_now)
65
+ b = create_release(name: 'B')
66
+ c = create_release(name: 'C', publish_at: 4.weeks.from_now)
67
+
68
+ b.as_current { @product.update!(name: 'Bar') }
69
+ IndexProduct.perform(@product)
70
+
71
+ a.as_current { assert_empty(Search::ProductSearch.new(q: 'bar').results.pluck(:model)) }
72
+ b.as_current { assert_equal([@product], Search::ProductSearch.new(q: 'bar').results.pluck(:model)) }
73
+ c.as_current { assert_empty(Search::ProductSearch.new(q: 'bar').results.pluck(:model)) }
74
+
75
+ # Changing publish_at via `update` causes the release to publish due to Sidekiq inline
76
+ b.set(publish_at: 2.weeks.from_now)
77
+
78
+ Sidekiq::Callbacks.enable(IndexProduct) do
79
+ IndexReleaseScheduleChange.new.perform(b.id, nil, b.publish_at)
80
+ end
81
+
82
+ a.as_current { assert_empty(Search::ProductSearch.new(q: 'bar').results.pluck(:model)) }
83
+ b.as_current { assert_equal([@product], Search::ProductSearch.new(q: 'bar').results.pluck(:model)) }
84
+ c.as_current { assert_equal([@product], Search::ProductSearch.new(q: 'bar').results.pluck(:model)) }
85
+ end
86
+
87
+ def test_destroyed
88
+ a = create_release(name: 'A', publish_at: 1.week.from_now)
89
+ b = create_release(name: 'B', publish_at: 2.weeks.from_now)
90
+ c = create_release(name: 'C', publish_at: 4.weeks.from_now)
91
+
92
+ b.as_current { @product.update!(name: 'Bar') }
93
+ IndexProduct.perform(@product)
94
+
95
+ a.as_current { assert_empty(Search::ProductSearch.new(q: 'bar').results.pluck(:model)) }
96
+ b.as_current { assert_equal([@product], Search::ProductSearch.new(q: 'bar').results.pluck(:model)) }
97
+ c.as_current { assert_equal([@product], Search::ProductSearch.new(q: 'bar').results.pluck(:model)) }
98
+
99
+ Sidekiq::Callbacks.enable(IndexReleaseScheduleChange, IndexProduct) do
100
+ b.destroy
101
+ end
102
+
103
+ a.as_current { assert_empty(Search::ProductSearch.new(q: 'bar').results.pluck(:model)) }
104
+ c.as_current { assert_empty(Search::ProductSearch.new(q: 'bar').results.pluck(:model)) }
105
+ end
106
+ end
107
+ end
@@ -53,5 +53,11 @@ module Workarea
53
53
  t('workarea.admin.data_file_mailer.import_failure.errors')
54
54
  )
55
55
  end
56
+
57
+ def test_perform_with_missing_import
58
+ assert_raises Mongoid::Errors::DocumentNotFound do
59
+ ProcessImport.new.perform('foo')
60
+ end
61
+ end
56
62
  end
57
63
  end
@@ -2,6 +2,8 @@ require 'test_helper'
2
2
 
3
3
  module Workarea
4
4
  class PublishReleaseTest < TestCase
5
+ include TestCase::SearchIndexing
6
+
5
7
  def test_publishes_the_release
6
8
  release = create_release
7
9
  PublishRelease.new.perform(release.id)
@@ -16,5 +18,27 @@ module Workarea
16
18
  assert_equal(1, Mongoid::AuditLog::Entry.count)
17
19
  assert(Mongoid::AuditLog::Entry.first.modifier.system?)
18
20
  end
21
+
22
+ def test_reindexes_release_schedule
23
+ product = create_product(name: 'Foo')
24
+
25
+ a = create_release(publish_at: 1.week.from_now)
26
+ b = create_release(publish_at: 2.weeks.from_now)
27
+ c = create_release(publish_at: 4.weeks.from_now)
28
+
29
+ b.as_current { product.update!(name: 'Bar') }
30
+ IndexProduct.perform(product)
31
+
32
+ assert_empty(Search::ProductSearch.new(q: 'bar').results.pluck(:model))
33
+ a.as_current { assert_empty(Search::ProductSearch.new(q: 'bar').results.pluck(:model)) }
34
+ b.as_current { assert_equal([product], Search::ProductSearch.new(q: 'bar').results.pluck(:model)) }
35
+ c.as_current { assert_equal([product], Search::ProductSearch.new(q: 'bar').results.pluck(:model)) }
36
+
37
+ Sidekiq::Callbacks.enable(IndexProduct) { PublishRelease.new.perform(b.id) }
38
+
39
+ assert_equal([product], Search::ProductSearch.new(q: 'bar').results.pluck(:model))
40
+ a.as_current { assert_equal([product], Search::ProductSearch.new(q: 'bar').results.pluck(:model)) }
41
+ c.as_current { assert_equal([product], Search::ProductSearch.new(q: 'bar').results.pluck(:model)) }
42
+ end
19
43
  end
20
44
  end
@@ -25,7 +25,7 @@ Gem::Specification.new do |s|
25
25
  s.add_dependency 'mongoid-sample', '~> 0.1.0'
26
26
  s.add_dependency 'mongoid-encrypted', '~> 1.0.0'
27
27
  s.add_dependency 'elasticsearch', '~> 5.0.1'
28
- s.add_dependency 'kaminari', '~> 0.17.0'
28
+ s.add_dependency 'kaminari', '~> 1.2.1'
29
29
  s.add_dependency 'kaminari-mongoid', '~> 0.1.2'
30
30
  s.add_dependency 'activemerchant', '~> 1.52'
31
31
  s.add_dependency 'dragonfly', '~> 1.1.2'
@@ -33,7 +33,8 @@ Gem::Specification.new do |s|
33
33
  s.add_dependency 'sidekiq-cron', '~> 0.6.3'
34
34
  s.add_dependency 'sidekiq-unique-jobs', '~> 6.0.6'
35
35
  s.add_dependency 'sidekiq-throttled', '~> 0.8.2'
36
- s.add_dependency 'geocoder', '~> 1.4.4'
36
+ s.add_dependency 'geocoder', '~> 1.6.3'
37
+ s.add_dependency 'redis-rails', '~> 5.0.0'
37
38
  s.add_dependency 'redis-rack-cache', '~> 2.2.0'
38
39
  s.add_dependency 'easymon', '~> 1.4.0'
39
40
  s.add_dependency 'image_optim', '~> 0.26.0'
@@ -65,7 +66,7 @@ Gem::Specification.new do |s|
65
66
  s.add_dependency 'chart-horizontalbar-rails', '~> 1.0.4' # TODO remove v4
66
67
  s.add_dependency 'select2-rails', '~> 4.0.3'
67
68
  s.add_dependency 'wysihtml-rails', '~> 0.6.0.beta2'
68
- s.add_dependency 'rack-attack', '~> 5.0.1'
69
+ s.add_dependency 'rack-attack', '~> 6.3.1'
69
70
  s.add_dependency 'jquery-livetype-rails', '~> 0.1.0' # TODO remove v4
70
71
  s.add_dependency 'redcarpet', '~> 3.4.0'
71
72
  s.add_dependency 'jquery-unique-clone-rails', '~> 1.0.0'
@@ -93,7 +94,7 @@ Gem::Specification.new do |s|
93
94
  s.add_dependency 'chartkick', '~> 3.3.0'
94
95
  s.add_dependency 'browser', '~> 2.6.1'
95
96
  s.add_dependency 'puma', '>= 4.3.1'
96
- s.add_dependency 'rack', '>= 2.0.8'
97
+ s.add_dependency 'rack' , '>= 2.1.4'
97
98
 
98
99
  # HACK for vendoring active_shipping
99
100
  s.add_dependency 'active_utils', '~> 3.3.1'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: workarea-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.5.11
4
+ version: 3.5.16
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Crouse
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-05-13 00:00:00.000000000 Z
11
+ date: 2020-07-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -170,14 +170,14 @@ dependencies:
170
170
  requirements:
171
171
  - - "~>"
172
172
  - !ruby/object:Gem::Version
173
- version: 0.17.0
173
+ version: 1.2.1
174
174
  type: :runtime
175
175
  prerelease: false
176
176
  version_requirements: !ruby/object:Gem::Requirement
177
177
  requirements:
178
178
  - - "~>"
179
179
  - !ruby/object:Gem::Version
180
- version: 0.17.0
180
+ version: 1.2.1
181
181
  - !ruby/object:Gem::Dependency
182
182
  name: kaminari-mongoid
183
183
  requirement: !ruby/object:Gem::Requirement
@@ -282,14 +282,28 @@ dependencies:
282
282
  requirements:
283
283
  - - "~>"
284
284
  - !ruby/object:Gem::Version
285
- version: 1.4.4
285
+ version: 1.6.3
286
286
  type: :runtime
287
287
  prerelease: false
288
288
  version_requirements: !ruby/object:Gem::Requirement
289
289
  requirements:
290
290
  - - "~>"
291
291
  - !ruby/object:Gem::Version
292
- version: 1.4.4
292
+ version: 1.6.3
293
+ - !ruby/object:Gem::Dependency
294
+ name: redis-rails
295
+ requirement: !ruby/object:Gem::Requirement
296
+ requirements:
297
+ - - "~>"
298
+ - !ruby/object:Gem::Version
299
+ version: 5.0.0
300
+ type: :runtime
301
+ prerelease: false
302
+ version_requirements: !ruby/object:Gem::Requirement
303
+ requirements:
304
+ - - "~>"
305
+ - !ruby/object:Gem::Version
306
+ version: 5.0.0
293
307
  - !ruby/object:Gem::Dependency
294
308
  name: redis-rack-cache
295
309
  requirement: !ruby/object:Gem::Requirement
@@ -730,14 +744,14 @@ dependencies:
730
744
  requirements:
731
745
  - - "~>"
732
746
  - !ruby/object:Gem::Version
733
- version: 5.0.1
747
+ version: 6.3.1
734
748
  type: :runtime
735
749
  prerelease: false
736
750
  version_requirements: !ruby/object:Gem::Requirement
737
751
  requirements:
738
752
  - - "~>"
739
753
  - !ruby/object:Gem::Version
740
- version: 5.0.1
754
+ version: 6.3.1
741
755
  - !ruby/object:Gem::Dependency
742
756
  name: jquery-livetype-rails
743
757
  requirement: !ruby/object:Gem::Requirement
@@ -1128,14 +1142,14 @@ dependencies:
1128
1142
  requirements:
1129
1143
  - - ">="
1130
1144
  - !ruby/object:Gem::Version
1131
- version: 2.0.8
1145
+ version: 2.1.4
1132
1146
  type: :runtime
1133
1147
  prerelease: false
1134
1148
  version_requirements: !ruby/object:Gem::Requirement
1135
1149
  requirements:
1136
1150
  - - ">="
1137
1151
  - !ruby/object:Gem::Version
1138
- version: 2.0.8
1152
+ version: 2.1.4
1139
1153
  - !ruby/object:Gem::Dependency
1140
1154
  name: active_utils
1141
1155
  requirement: !ruby/object:Gem::Requirement
@@ -1720,6 +1734,7 @@ files:
1720
1734
  - app/services/workarea/direct_upload/product_image.rb
1721
1735
  - app/services/workarea/export_report.rb
1722
1736
  - app/services/workarea/hash_update.rb
1737
+ - app/services/workarea/index_release_schedule_previews.rb
1723
1738
  - app/services/workarea/inventory_adjustment.rb
1724
1739
  - app/services/workarea/login.rb
1725
1740
  - app/services/workarea/new_discount.rb
@@ -1757,6 +1772,7 @@ files:
1757
1772
  - app/workers/workarea/index_product.rb
1758
1773
  - app/workers/workarea/index_product_children.rb
1759
1774
  - app/workers/workarea/index_product_rule.rb
1775
+ - app/workers/workarea/index_release_schedule_change.rb
1760
1776
  - app/workers/workarea/index_search_customizations.rb
1761
1777
  - app/workers/workarea/index_skus.rb
1762
1778
  - app/workers/workarea/keep_product_index_fresh.rb
@@ -1930,6 +1946,7 @@ files:
1930
1946
  - lib/workarea/ext/freedom_patches/string.rb
1931
1947
  - lib/workarea/ext/freedom_patches/uri.rb
1932
1948
  - lib/workarea/ext/jbuilder/jbuilder_append_partials.rb
1949
+ - lib/workarea/ext/jbuilder/jbuilder_cache.rb
1933
1950
  - lib/workarea/ext/mongoid/audit_log_entry.decorator
1934
1951
  - lib/workarea/ext/mongoid/each_by.rb
1935
1952
  - lib/workarea/ext/mongoid/embedded_children.rb
@@ -1964,6 +1981,7 @@ files:
1964
1981
  - lib/workarea/ping_home_base.rb
1965
1982
  - lib/workarea/plugin.rb
1966
1983
  - lib/workarea/plugin/asset_appends_helper.rb
1984
+ - lib/workarea/queues_pauser.rb
1967
1985
  - lib/workarea/routes_constraints/redirect.rb
1968
1986
  - lib/workarea/routes_constraints/super_admin.rb
1969
1987
  - lib/workarea/scheduled_jobs.rb
@@ -2314,6 +2332,7 @@ files:
2314
2332
  - test/models/workarea/search/storefront/product/inventory_test.rb
2315
2333
  - test/models/workarea/search/storefront/product/pricing_test.rb
2316
2334
  - test/models/workarea/search/storefront/product/text_test.rb
2335
+ - test/models/workarea/search/storefront/product_releases_test.rb
2317
2336
  - test/models/workarea/search/storefront/product_test.rb
2318
2337
  - test/models/workarea/search/storefront_test.rb
2319
2338
  - test/models/workarea/segment/life_cycle_test.rb
@@ -2365,7 +2384,6 @@ files:
2365
2384
  - test/queries/workarea/pricing_override_params_test.rb
2366
2385
  - test/queries/workarea/product_primary_image_url_test.rb
2367
2386
  - test/queries/workarea/product_primary_navigation_test.rb
2368
- - test/queries/workarea/product_releases_test.rb
2369
2387
  - test/queries/workarea/recommendation/order_based_test.rb
2370
2388
  - test/queries/workarea/recommendation/product_based_test.rb
2371
2389
  - test/queries/workarea/recommendation/searches_test.rb
@@ -2426,6 +2444,7 @@ files:
2426
2444
  - test/services/workarea/direct_upload_test.rb
2427
2445
  - test/services/workarea/export_report_test.rb
2428
2446
  - test/services/workarea/hash_update_test.rb
2447
+ - test/services/workarea/index_release_schedule_previews_test.rb
2429
2448
  - test/services/workarea/inventory_adjustment_test.rb
2430
2449
  - test/services/workarea/login_test.rb
2431
2450
  - test/services/workarea/order_merge_test.rb
@@ -2458,6 +2477,7 @@ files:
2458
2477
  - test/workers/workarea/index_payment_transactions_test.rb
2459
2478
  - test/workers/workarea/index_product_rule_test.rb
2460
2479
  - test/workers/workarea/index_product_test.rb
2480
+ - test/workers/workarea/index_release_schedule_change_test.rb
2461
2481
  - test/workers/workarea/index_skus_test.rb
2462
2482
  - test/workers/workarea/keep_product_index_fresh_test.rb
2463
2483
  - test/workers/workarea/mark_discounts_as_redeemed_test.rb
@@ -1,56 +0,0 @@
1
- require 'test_helper'
2
-
3
- module Workarea
4
- class ProductReleasesTest < TestCase
5
- def test_product_changes
6
- product = create_product(name: 'Foo')
7
- release_one = create_release
8
- release_one.as_current { product.update!(name: 'Bar') }
9
-
10
- assert_equal([release_one], ProductReleases.new(product).releases)
11
-
12
- release_one.update!(publish_at: 1.day.from_now)
13
- release_two = create_release(publish_at: 3.days.from_now)
14
- assert_equal([release_one, release_two], ProductReleases.new(product).releases)
15
- end
16
-
17
- def test_featured_product_changes
18
- product = create_product
19
- category = create_category
20
-
21
- release_one = create_release
22
- release_one.as_current { category.update!(product_ids: [product.id]) }
23
- assert_equal([release_one], ProductReleases.new(product).releases)
24
-
25
- release_one.update!(publish_at: 1.day.from_now)
26
- release_two = create_release(publish_at: 3.days.from_now)
27
- assert_equal([release_one, release_two], ProductReleases.new(product).releases)
28
- end
29
-
30
- def test_variant_changes
31
- product = create_product(variants: [{ sku: 'SKU' }])
32
- release = create_release
33
- release.as_current { product.variants.first.update!(details: { color: 'Red' }) }
34
- assert_equal([release], ProductReleases.new(product).releases)
35
- end
36
-
37
- def test_pricing_changes
38
- product = create_product(variants: [{ sku: 'SKU' }])
39
- pricing = Pricing::Sku.find('SKU')
40
-
41
- release = create_release
42
- release.as_current { pricing.prices.first.update!(regular: 10_000) }
43
- assert_equal([release], ProductReleases.new(product).releases)
44
- end
45
-
46
- def test_changesets_with_missing_releases
47
- product = create_product(name: 'Foo')
48
- release = create_release
49
- release.as_current { product.update!(name: 'Bar') }
50
- release.delete
51
-
52
- assert_nil(product.reload.changesets.first.release)
53
- assert_equal([], ProductReleases.new(product).releases)
54
- end
55
- end
56
- end