workarea-core 3.5.0.beta.1 → 3.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|