workarea-core 3.5.0.beta.1 → 3.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.
- checksums.yaml +4 -4
- data/app/controllers/workarea/current_tracking.rb +4 -0
- data/app/models/workarea/checkout/collect_payment.rb +5 -5
- data/app/models/workarea/data_file/operation.rb +4 -0
- data/app/models/workarea/fulfillment/policies/base.rb +0 -4
- data/app/models/workarea/fulfillment/policies/{ignore.rb → shipping.rb} +2 -2
- data/app/models/workarea/fulfillment/sku.rb +0 -2
- data/app/models/workarea/insights/trending_searches.rb +8 -1
- data/app/models/workarea/metrics/search_by_day.rb +2 -0
- data/app/models/workarea/order.rb +12 -2
- data/app/models/workarea/order/item.rb +28 -2
- data/app/models/workarea/pricing/calculators/tax_calculator.rb +2 -2
- data/app/models/workarea/pricing/discount.rb +3 -2
- data/app/models/workarea/releasable.rb +3 -5
- data/app/models/workarea/reports/custom_event.rb +22 -0
- data/app/models/workarea/search/admin/releasable.rb +18 -6
- data/app/models/workarea/segment/life_cycle.rb +5 -5
- data/app/models/workarea/segment/rules/last_order.rb +9 -2
- data/app/models/workarea/segment/rules/traffic_referrer.rb +16 -5
- data/app/models/workarea/segmentable.rb +13 -0
- data/app/models/workarea/traffic_referrer.rb +3 -0
- data/app/queries/workarea/alerts.rb +21 -0
- data/app/queries/workarea/order_item_details.rb +16 -16
- data/app/queries/workarea/search/admin_index_search.rb +2 -1
- data/app/queries/workarea/search/product_display_rules.rb +0 -2
- data/app/services/workarea/direct_upload.rb +5 -0
- data/app/services/workarea/packaging.rb +1 -1
- data/app/workers/workarea/deactivate_stale_discounts.rb +1 -1
- data/app/workers/workarea/synchronize_user_metrics.rb +9 -0
- data/config/locales/en.yml +22 -0
- data/lib/tasks/migrate.rake +9 -12
- data/lib/workarea/configuration.rb +6 -6
- data/lib/workarea/configuration/redis.rb +21 -3
- data/lib/workarea/core.rb +3 -0
- data/lib/workarea/ext/freedom_patches/referer_parser.rb +7 -0
- data/lib/workarea/ext/mongoid/embedded_children.rb +20 -0
- data/lib/workarea/latest_version.rb +24 -0
- data/lib/workarea/ping_home_base.rb +0 -1
- data/lib/workarea/version.rb +1 -1
- data/lib/workarea/visit.rb +5 -2
- data/lib/workarea/warnings.rb +6 -6
- data/test/lib/workarea/ext/mongoid/embedded_children_test.rb +32 -0
- data/test/lib/workarea/latest_version_test.rb +11 -0
- data/test/models/workarea/checkout/collect_payment_test.rb +6 -6
- data/test/models/workarea/data_file/csv_test.rb +15 -0
- data/test/models/workarea/fulfillment/sku_test.rb +5 -5
- data/test/models/workarea/insights/cold_searches_test.rb +13 -11
- data/test/models/workarea/insights/hot_searches_test.rb +13 -11
- data/test/models/workarea/insights/searches_to_improve_test.rb +9 -6
- data/test/models/workarea/insights/star_searches_test.rb +5 -4
- data/test/models/workarea/insights/trending_searches_test.rb +12 -9
- data/test/models/workarea/pricing/calculators/tax_calculator_test.rb +1 -1
- data/test/models/workarea/search/admin/releasable_test.rb +5 -7
- data/test/models/workarea/segment/life_cycle_test.rb +5 -0
- data/test/models/workarea/segment/rules/last_order_test.rb +15 -3
- data/test/models/workarea/segment/rules/traffic_referrer_test.rb +10 -8
- data/test/models/workarea/segmentable_test.rb +18 -0
- data/test/queries/workarea/alerts_test.rb +11 -0
- data/test/queries/workarea/order_item_details_test.rb +4 -12
- data/test/services/workarea/direct_upload_test.rb +3 -0
- data/test/vcr_cassettes/get_latest_version.yml +90 -0
- data/test/workers/workarea/deactivate_stale_discounts_test.rb +2 -2
- data/workarea-core.gemspec +2 -3
- metadata +16 -25
- data/app/controllers/workarea/current_referrer.rb +0 -14
- data/app/models/workarea/fulfillment/policies/ship.rb +0 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 350a33b73048c0e24062f5bbd378518bfae1133b2e8d49b58907d4327191ffe9
|
4
|
+
data.tar.gz: 74ddf766b88286672ca1ac81924a09b753aa6e20efae0d9fa6eeb1ecbcf8bfa8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 349c362c45e578680ef743051bc3554c5995013be7a1e348bcac2780fa6a9425b137fbfec9f6d7be3af354996a5fcc895be5af91241e1bf7b7ad1a878cf428d1
|
7
|
+
data.tar.gz: 260730f0b9e935712e47230aa9b3a103b971ec190afbadb7b0a15a2b78efd562928f48f990ed0db0a4ecf515084bd65f385145683b33ac2a66fab971cdbeda47
|
@@ -36,12 +36,12 @@ module Workarea
|
|
36
36
|
# TODO deprecated, remove in v3.6
|
37
37
|
return 'purchase!' if Workarea.config.auto_capture
|
38
38
|
|
39
|
-
if @order.items.all?(&:
|
40
|
-
Workarea.config.checkout_payment_action[:
|
41
|
-
elsif @order.items.any?(&:
|
42
|
-
Workarea.config.checkout_payment_action[:
|
39
|
+
if @order.items.all?(&:shipping?)
|
40
|
+
Workarea.config.checkout_payment_action[:shipping]
|
41
|
+
elsif @order.items.any?(&:shipping?)
|
42
|
+
Workarea.config.checkout_payment_action[:partial_shipping]
|
43
43
|
else
|
44
|
-
Workarea.config.checkout_payment_action[:
|
44
|
+
Workarea.config.checkout_payment_action[:no_shipping]
|
45
45
|
end
|
46
46
|
end
|
47
47
|
end
|
@@ -15,8 +15,6 @@ module Workarea
|
|
15
15
|
dragonfly_accessor :file, app: :workarea
|
16
16
|
validates :file, presence: true, if: -> { download? }
|
17
17
|
|
18
|
-
delegate :requires_shipping?, to: :policy_object
|
19
|
-
|
20
18
|
def self.policies
|
21
19
|
Workarea.config.fulfillment_policies.map(&:demodulize).map(&:underscore)
|
22
20
|
end
|
@@ -7,7 +7,13 @@ module Workarea
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def generate_monthly!
|
10
|
-
results = generate_results.map
|
10
|
+
results = generate_results.map do |result|
|
11
|
+
result.merge(
|
12
|
+
query_id: result['_id'],
|
13
|
+
query_string: result['query_string'].presence || result['_id']
|
14
|
+
)
|
15
|
+
end
|
16
|
+
|
11
17
|
create!(results: results) if results.present?
|
12
18
|
end
|
13
19
|
|
@@ -33,6 +39,7 @@ module Workarea
|
|
33
39
|
{
|
34
40
|
'$group' => {
|
35
41
|
'_id' => '$query_id',
|
42
|
+
'query_string' => { '$first' => '$query_string' },
|
36
43
|
'improving_weeks' => { '$sum' => 1 },
|
37
44
|
'revenue_changes' => { '$push' => '$revenue_change' },
|
38
45
|
'orders' => { '$sum' => '$orders' }
|
@@ -17,6 +17,8 @@ module Workarea
|
|
17
17
|
field :revenue, type: Float, default: 0.0
|
18
18
|
|
19
19
|
index(reporting_on: 1, total_results: 1)
|
20
|
+
index(query_id: 1)
|
21
|
+
|
20
22
|
scope :by_query_id, ->(id) { where(query_id: id) }
|
21
23
|
|
22
24
|
def self.save_search(query_string, total_results, at: Time.current)
|
@@ -183,12 +183,22 @@ module Workarea
|
|
183
183
|
save!
|
184
184
|
end
|
185
185
|
|
186
|
-
#
|
186
|
+
# Check to see if this order delivers with any of the fulfillment policies
|
187
|
+
# passed in.
|
188
|
+
#
|
189
|
+
# @param [String,Symbol]
|
190
|
+
# @return [Boolean]
|
191
|
+
#
|
192
|
+
def fulfilled_by?(*types)
|
193
|
+
items.any? { |i| i.fulfilled_by?(*types) }
|
194
|
+
end
|
195
|
+
|
196
|
+
# Whether any of the order's items require physical shipping.
|
187
197
|
#
|
188
198
|
# @return [Boolean]
|
189
199
|
#
|
190
200
|
def requires_shipping?
|
191
|
-
|
201
|
+
fulfilled_by?(:shipping)
|
192
202
|
end
|
193
203
|
|
194
204
|
# Whether this order can be purchased, which is defined here as the order
|
@@ -13,7 +13,7 @@ module Workarea
|
|
13
13
|
field :total_value, type: Money, default: 0
|
14
14
|
field :total_price, type: Money, default: 0
|
15
15
|
field :via, type: String
|
16
|
-
field :
|
16
|
+
field :fulfillment, type: String, default: -> { Workarea.config.fulfillment_policies.first.demodulize.underscore }
|
17
17
|
|
18
18
|
scope :by_newest, -> { desc(:created_at) }
|
19
19
|
|
@@ -30,6 +30,32 @@ module Workarea
|
|
30
30
|
only_integer: true
|
31
31
|
}
|
32
32
|
|
33
|
+
# To allow for custom policies defining their own methods here
|
34
|
+
Workarea.config.fulfillment_policies.each do |class_name|
|
35
|
+
define_method "#{class_name.demodulize.underscore}?" do
|
36
|
+
fulfillment == class_name.demodulize.underscore
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# These methods exist for findability
|
41
|
+
def shipping?
|
42
|
+
fulfillment == 'shipping'
|
43
|
+
end
|
44
|
+
|
45
|
+
def download?
|
46
|
+
fulfillment == 'download'
|
47
|
+
end
|
48
|
+
|
49
|
+
# Whether this order has any items that need to be fulfilled by a particular
|
50
|
+
# fulfillment policy.
|
51
|
+
#
|
52
|
+
# @param [Array<String,Symbol>]
|
53
|
+
# @return [Boolean]
|
54
|
+
#
|
55
|
+
def fulfilled_by?(*types)
|
56
|
+
types.any? { |t| send("#{t}?") }
|
57
|
+
end
|
58
|
+
|
33
59
|
# Whether this item is a digital (not-shipped) type of item.
|
34
60
|
#
|
35
61
|
# @return [Boolean]
|
@@ -39,7 +65,7 @@ module Workarea
|
|
39
65
|
end
|
40
66
|
Workarea.deprecation.deprecate_methods(
|
41
67
|
Order::Item,
|
42
|
-
digital?:
|
68
|
+
digital?: :fulfilled_by?
|
43
69
|
)
|
44
70
|
|
45
71
|
# Adds a price adjustment to the item. Does not persist.
|
@@ -29,13 +29,13 @@ module Workarea
|
|
29
29
|
|
30
30
|
def shipped_items_price_adjustments
|
31
31
|
PriceAdjustmentSet.new(
|
32
|
-
order.items.select(&:
|
32
|
+
order.items.select(&:shipping?).flat_map(&:price_adjustments)
|
33
33
|
)
|
34
34
|
end
|
35
35
|
|
36
36
|
def not_shipped_items_price_adjustments
|
37
37
|
PriceAdjustmentSet.new(
|
38
|
-
order.items.reject(&:
|
38
|
+
order.items.reject(&:shipping?).flat_map(&:price_adjustments)
|
39
39
|
)
|
40
40
|
end
|
41
41
|
|
@@ -91,7 +91,8 @@ module Workarea
|
|
91
91
|
has_many :redemptions,
|
92
92
|
class_name: 'Workarea::Pricing::Discount::Redemption'
|
93
93
|
|
94
|
-
index(
|
94
|
+
index(active: 1)
|
95
|
+
index(updated_at: 1) # for DeactivateStaleDiscounts
|
95
96
|
|
96
97
|
validates :name, presence: true
|
97
98
|
|
@@ -242,7 +243,7 @@ module Workarea
|
|
242
243
|
# @return [Time]
|
243
244
|
#
|
244
245
|
def auto_deactivates_at
|
245
|
-
start = last_redemption.try(:created_at) ||
|
246
|
+
start = last_redemption.try(:created_at) || updated_at
|
246
247
|
start + Workarea.config.discount_staleness_ttl
|
247
248
|
end
|
248
249
|
|
@@ -32,11 +32,9 @@ module Workarea
|
|
32
32
|
{ releasable_type: self.class.name, releasable_id: id }
|
33
33
|
)
|
34
34
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
criteria.merge!(child.changesets_with_children)
|
39
|
-
end
|
35
|
+
embedded_children.each do |child|
|
36
|
+
if child.respond_to?(:changesets_with_children)
|
37
|
+
criteria.merge!(child.changesets_with_children)
|
40
38
|
end
|
41
39
|
end
|
42
40
|
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Workarea
|
2
|
+
module Reports
|
3
|
+
class CustomEvent
|
4
|
+
include ApplicationDocument
|
5
|
+
|
6
|
+
field :name, type: String
|
7
|
+
field :occurred_at, type: Time
|
8
|
+
|
9
|
+
index({ occurred_at: 1 });
|
10
|
+
|
11
|
+
validates :name, presence: true
|
12
|
+
validates :occurred_at, presence: true
|
13
|
+
|
14
|
+
scope :occurred_between, ->(starts_at: nil, ends_at: nil) do
|
15
|
+
where(
|
16
|
+
:occurred_at.gte => starts_at,
|
17
|
+
:occurred_at.lte => ends_at
|
18
|
+
)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -3,7 +3,10 @@ module Workarea
|
|
3
3
|
class Admin
|
4
4
|
module Releasable
|
5
5
|
def facets
|
6
|
-
super.merge(
|
6
|
+
super.merge(
|
7
|
+
upcoming_changes: upcoming_release_ids_with_changesets,
|
8
|
+
active_by_segment: active_segment_ids
|
9
|
+
)
|
7
10
|
end
|
8
11
|
|
9
12
|
def status
|
@@ -25,16 +28,25 @@ module Workarea
|
|
25
28
|
end
|
26
29
|
|
27
30
|
def content_changesets
|
28
|
-
return [] unless
|
29
|
-
|
30
|
-
Workarea::Content.for(model)
|
31
|
-
.changesets
|
32
|
-
.any_in(release_id: upcoming_release_ids)
|
31
|
+
return [] unless content.present?
|
32
|
+
content.changesets.any_in(release_id: upcoming_release_ids)
|
33
33
|
end
|
34
34
|
|
35
35
|
def upcoming_release_ids
|
36
36
|
@upcoming_release_ids ||= Workarea::Release.upcoming.map(&:id)
|
37
37
|
end
|
38
|
+
|
39
|
+
def content
|
40
|
+
return unless model.is_a?(Contentable)
|
41
|
+
@content ||= Workarea::Content.for(model)
|
42
|
+
end
|
43
|
+
|
44
|
+
def active_segment_ids
|
45
|
+
result = model.active_segment_ids_with_children +
|
46
|
+
(content&.active_segment_ids_with_children || [])
|
47
|
+
|
48
|
+
result.uniq
|
49
|
+
end
|
38
50
|
end
|
39
51
|
end
|
40
52
|
end
|
@@ -14,12 +14,16 @@ module Workarea
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def instance
|
17
|
-
first || create!(rules: default_rules)
|
17
|
+
first || create!(name: instance_name, rules: default_rules)
|
18
18
|
end
|
19
19
|
|
20
20
|
def instance_id
|
21
21
|
name.demodulize.underscore.to_sym
|
22
22
|
end
|
23
|
+
|
24
|
+
def instance_name
|
25
|
+
name.demodulize.underscore.titleize
|
26
|
+
end
|
23
27
|
end
|
24
28
|
|
25
29
|
def self.create!
|
@@ -32,10 +36,6 @@ module Workarea
|
|
32
36
|
].each(&:instance)
|
33
37
|
end
|
34
38
|
|
35
|
-
def name
|
36
|
-
self.class.name.demodulize.underscore.titleize
|
37
|
-
end
|
38
|
-
|
39
39
|
def destroy
|
40
40
|
false
|
41
41
|
end
|
@@ -2,11 +2,18 @@ module Workarea
|
|
2
2
|
class Segment
|
3
3
|
module Rules
|
4
4
|
class LastOrder < Base
|
5
|
+
field :within, type: Boolean, default: true
|
5
6
|
field :days, type: Integer
|
6
7
|
|
7
8
|
def qualifies?(visit)
|
8
|
-
return false if
|
9
|
-
visit.metrics.last_order_at
|
9
|
+
return false if days.blank?
|
10
|
+
return !within if visit.metrics.last_order_at.blank?
|
11
|
+
|
12
|
+
if within?
|
13
|
+
visit.metrics.last_order_at >= days.days.ago
|
14
|
+
else
|
15
|
+
visit.metrics.last_order_at < days.days.ago
|
16
|
+
end
|
10
17
|
end
|
11
18
|
end
|
12
19
|
end
|
@@ -3,14 +3,25 @@ module Workarea
|
|
3
3
|
module Rules
|
4
4
|
class TrafficReferrer < Base
|
5
5
|
field :medium, type: String
|
6
|
-
field :source, type:
|
6
|
+
field :source, type: Array, default: []
|
7
|
+
field :url, type: String
|
7
8
|
|
8
9
|
def qualifies?(visit)
|
9
|
-
|
10
|
-
|
10
|
+
medium_match?(visit.referrer) ||
|
11
|
+
source_match?(visit.referrer) ||
|
12
|
+
url_match?(visit.referrer)
|
13
|
+
end
|
14
|
+
|
15
|
+
def medium_match?(referrer)
|
16
|
+
medium.to_s.strip.casecmp?(referrer.medium)
|
17
|
+
end
|
18
|
+
|
19
|
+
def source_match?(referrer)
|
20
|
+
source.any? { |s| s.strip.casecmp?(referrer.source) }
|
21
|
+
end
|
11
22
|
|
12
|
-
|
13
|
-
|
23
|
+
def url_match?(referrer)
|
24
|
+
url.present? && referrer.uri.to_s =~ /#{url.strip}/i
|
14
25
|
end
|
15
26
|
end
|
16
27
|
end
|
@@ -50,10 +50,23 @@ module Workarea
|
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
53
|
+
def segmented?
|
54
|
+
active_segment_ids.present?
|
55
|
+
end
|
56
|
+
|
53
57
|
def segments
|
54
58
|
@segments ||= active_segment_ids.blank? ? [] : Segment.in(id: active_segment_ids)
|
55
59
|
end
|
56
60
|
|
61
|
+
def active_segment_ids_with_children
|
62
|
+
children = embedded_children.reduce([]) do |memo, child|
|
63
|
+
memo += child.active_segment_ids if child.respond_to?(:active_segment_ids)
|
64
|
+
memo
|
65
|
+
end
|
66
|
+
|
67
|
+
(active_segment_ids + children).uniq
|
68
|
+
end
|
69
|
+
|
57
70
|
private
|
58
71
|
|
59
72
|
def mark_segmented_content
|
@@ -2,8 +2,11 @@ module Workarea
|
|
2
2
|
class TrafficReferrer
|
3
3
|
include ApplicationDocument
|
4
4
|
|
5
|
+
field :known, type: Boolean, default: false
|
5
6
|
field :source, type: String
|
6
7
|
field :medium, type: String
|
7
8
|
field :uri, type: String
|
9
|
+
field :domain, type: String
|
10
|
+
field :term, type: String
|
8
11
|
end
|
9
12
|
end
|
@@ -78,5 +78,26 @@ module Workarea
|
|
78
78
|
.asc(:publish_at)
|
79
79
|
.reject(&:has_changes?)
|
80
80
|
end
|
81
|
+
|
82
|
+
def latest_workarea_version
|
83
|
+
return if Rails.env.test?
|
84
|
+
return if Rails.env.development? && ENV.fetch('SKIP_VERSION_CHECK', 'true') =~ /true/i
|
85
|
+
|
86
|
+
Workarea::LatestVersion.get
|
87
|
+
end
|
88
|
+
|
89
|
+
def missing_segments
|
90
|
+
@missing_segments ||= begin
|
91
|
+
search = Search::AdminSearch.new
|
92
|
+
active_by_segment_facet =
|
93
|
+
search.facets.detect { |f| f.name == 'active_by_segment' }
|
94
|
+
|
95
|
+
if active_by_segment_facet.present?
|
96
|
+
active_by_segment_facet.results.keys - Segment.pluck(:id).map(&:to_s)
|
97
|
+
else
|
98
|
+
[]
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
81
102
|
end
|
82
103
|
end
|