spree_analytics_trackers 1.0.1 → 2.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/.bundle/config +2 -0
  3. data/.rubocop.yml +2 -0
  4. data/.travis.yml +30 -15
  5. data/Appraisals +3 -9
  6. data/LICENSE +1 -1
  7. data/README.md +7 -3
  8. data/app/assets/javascripts/spree/frontend/add_to_cart_analytics.js +50 -0
  9. data/app/assets/javascripts/spree/frontend/remove_from_cart_analytics.js +34 -0
  10. data/app/controllers/spree/admin/trackers_controller.rb +8 -0
  11. data/app/controllers/spree_analytics_trackers/checkout_controller_decorator.rb +11 -0
  12. data/app/controllers/spree_analytics_trackers/store_controller_decorator.rb +13 -0
  13. data/app/controllers/spree_analytics_trackers/user_confirmations_controller_decorator.rb +11 -0
  14. data/app/controllers/spree_analytics_trackers/user_passwords_controller_decorator.rb +11 -0
  15. data/app/controllers/spree_analytics_trackers/user_registrations_controller_decorator.rb +11 -0
  16. data/app/controllers/spree_analytics_trackers/user_sessions_controller_decorator.rb +11 -0
  17. data/app/helpers/spree/trackers_helper.rb +79 -16
  18. data/app/models/spree/tracker.rb +11 -5
  19. data/app/models/spree_analytics_trackers/user_decorator.rb +9 -0
  20. data/app/overrides/add_analytics_to_admin_sidebar.rb +2 -3
  21. data/app/overrides/add_cart_viewed_to_orders_edit.rb +1 -1
  22. data/app/overrides/add_checkout_step_viewed_to_checkout_edit.rb +11 -3
  23. data/app/overrides/add_google_analytics_page_view_to_spree_application.rb +10 -0
  24. data/app/overrides/add_google_analytics_to_spree_application.rb +4 -4
  25. data/app/overrides/add_google_purchase_to_orders_show.rb +1 -1
  26. data/app/overrides/add_product_list_filtered_to_taxons_show.rb +1 -1
  27. data/app/overrides/add_product_list_viewed_to_products_list.rb +1 -1
  28. data/app/overrides/add_product_viewed_to_products_show.rb +2 -2
  29. data/app/overrides/add_products_searched_to_products_list.rb +2 -2
  30. data/app/overrides/add_segment_initializer_to_layout.rb +3 -3
  31. data/app/overrides/add_segment_page_viewed_to_layout.rb +10 -0
  32. data/app/presenters/spree_analytics_trackers/base_presenter.rb +14 -0
  33. data/app/presenters/spree_analytics_trackers/segment/order_presenter.rb +32 -0
  34. data/app/presenters/spree_analytics_trackers/segment/product_presenter.rb +40 -0
  35. data/app/views/spree/admin/shared/_analytics_sidebar_menu.html.erb +3 -5
  36. data/app/views/spree/admin/trackers/_form.html.erb +13 -7
  37. data/app/views/spree/admin/trackers/index.html.erb +6 -8
  38. data/app/views/spree/shared/trackers/google_analytics/_checkout_step_viewed.js.erb +19 -0
  39. data/app/views/spree/shared/trackers/google_analytics/_initializer.js.erb +25 -0
  40. data/app/views/spree/shared/trackers/google_analytics/_page_viewed.js.erb +13 -0
  41. data/app/views/spree/shared/trackers/google_analytics/_purchase.js.erb +22 -0
  42. data/app/views/spree/shared/trackers/segment/_cart_viewed.js.erb +24 -19
  43. data/app/views/spree/shared/trackers/segment/_checkout_step_viewed.js.erb +20 -11
  44. data/app/views/spree/shared/trackers/segment/_initializer.js.erb +2 -3
  45. data/app/views/spree/shared/trackers/segment/_order_complete.js.erb +8 -45
  46. data/app/views/spree/shared/trackers/segment/_page_viewed.js.erb +7 -0
  47. data/app/views/spree/shared/trackers/segment/_product_list_filtered.js.erb +19 -28
  48. data/app/views/spree/shared/trackers/segment/_product_list_viewed.js.erb +17 -20
  49. data/app/views/spree/shared/trackers/segment/_product_viewed.js.erb +12 -6
  50. data/app/views/spree/shared/trackers/segment/_products_searched.js.erb +7 -9
  51. data/config/locales/en.yml +0 -2
  52. data/config/locales/zh-TW.yml +19 -0
  53. data/db/migrate/20200721163729_add_store_id_to_spree_trackers.rb +14 -0
  54. data/gemfiles/{spree_3_5.gemfile → spree_4_1.gemfile} +2 -2
  55. data/gemfiles/spree_master.gemfile +0 -1
  56. data/lib/generators/spree_analytics_trackers/install/install_generator.rb +8 -0
  57. data/lib/spree_analytics_trackers.rb +1 -0
  58. data/lib/spree_analytics_trackers/factories.rb +1 -0
  59. data/lib/spree_analytics_trackers/version.rb +3 -9
  60. data/spec/features/admin/configuration/analytics_tracker_spec.rb +18 -7
  61. data/spec/features/checkout_spec.rb +15 -0
  62. data/spec/features/products_spec.rb +315 -0
  63. data/spec/features/user_login_spec.rb +7 -0
  64. data/spec/features/user_password_recovery_spec.rb +7 -0
  65. data/spec/features/user_registration_spec.rb +7 -0
  66. data/spec/fixtures/thinking-cat.jpg +0 -0
  67. data/spec/models/spree/tracker_spec.rb +15 -0
  68. data/spec/presenters/spree_analytics_trackers/segment/order_presenter_spec.rb +34 -0
  69. data/spec/spec_helper.rb +7 -82
  70. data/spec/support/custom_products.rb +26 -0
  71. data/spree_analytics_trackers.gemspec +4 -17
  72. metadata +56 -212
  73. data/app/controllers/spree/store_controller_decorator.rb +0 -5
  74. data/app/models/spree/line_item_decorator.rb +0 -6
  75. data/app/models/spree/order_decorator.rb +0 -7
  76. data/app/models/spree/product_decorator.rb +0 -11
  77. data/app/models/spree/user_decorator.rb +0 -5
  78. data/app/overrides/add_google_checkout_to_checkout_edit.rb +0 -9
  79. data/app/overrides/add_product_added_to_orders_edit.rb +0 -10
  80. data/app/views/spree/shared/_google_add_items.html.erb +0 -13
  81. data/app/views/spree/shared/_google_analytics.html.erb +0 -18
  82. data/app/views/spree/shared/_google_checkout.html.erb +0 -14
  83. data/app/views/spree/shared/_google_purchase.html.erb +0 -19
  84. data/app/views/spree/shared/trackers/segment/_product_added.js.erb +0 -9
  85. data/gemfiles/spree_3_7.gemfile +0 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 73068544992b2ab73b42d2d9973c61217f2e9006b1eeaf82bb487d0c06694253
4
- data.tar.gz: b5487f54f759141810e350a7aabe3c89870a2586d0f79c234c02a9a2f962c96d
3
+ metadata.gz: 39824346c7fd7f4f0369de8f15513e63cb3c3c490ea1ff746ab2022e644c0316
4
+ data.tar.gz: 6df1197ae57739e09de6f7abc91e3f3b44bec114efa608fa1b97c1f0e2b3a6d4
5
5
  SHA512:
6
- metadata.gz: 961549e600a21cb31dad51459269e95f304c2540ad6e4603780a74548e77331507f0ffa9b7e64663915f9ade40107422e105ec4ab3e735b22c269176b7cb0ba6
7
- data.tar.gz: bb01db4431806581753611af24c40f6bfe60b9454c063a3907676bbecce138a2c5260a4e52290cecb9c05cb65e448c32056d6d91da7714b7250d7fd3987a4d22
6
+ metadata.gz: 196444a2a5020015e889c7f8a4f09180338372a900b4f44e0af2c0637cca747ae00249a9afab3d8c7f67c6edb68821ee86bd59b181641b25121d630440ccd773
7
+ data.tar.gz: 73956ab392e0802b1256aac939ea280b846a7464d2fbfaeba5d4bf386622e750fc81cd936226cece3984b1badf8d00679301251609433cb13e37d02121362cad
data/.bundle/config ADDED
@@ -0,0 +1,2 @@
1
+ ---
2
+ BUNDLE_JOBS: "8"
data/.rubocop.yml ADDED
@@ -0,0 +1,2 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.5
data/.travis.yml CHANGED
@@ -1,29 +1,44 @@
1
- sudo: required
2
- dist: trusty
1
+ os: linux
2
+ dist: bionic
3
+
4
+ addons:
5
+ apt:
6
+ sources:
7
+ - google-chrome
8
+ packages:
9
+ - google-chrome-stable
10
+
11
+ services:
12
+ - mysql
13
+ - postgresql
3
14
 
4
15
  language: ruby
5
16
 
17
+ rvm:
18
+ - 2.5
19
+ - 2.6
20
+
6
21
  env:
7
- - DB=postgres
8
22
  - DB=mysql
23
+ - DB=postgres
9
24
 
10
25
  gemfile:
11
- - gemfiles/spree_3_5.gemfile
12
- - gemfiles/spree_3_7.gemfile
26
+ - gemfiles/spree_4_1.gemfile
13
27
  - gemfiles/spree_master.gemfile
14
28
 
15
- script:
16
- - bundle exec rake test_app
17
- - bundle exec rake spec
18
-
19
- rvm:
20
- - 2.3.3
21
- - 2.4.2
22
- - 2.5.2
23
-
24
- matrix:
29
+ jobs:
25
30
  allow_failures:
26
31
  - gemfile: gemfiles/spree_master.gemfile
27
32
 
28
33
  before_install:
29
34
  - mysql -u root -e "GRANT ALL ON *.* TO 'travis'@'%';"
35
+
36
+ before_script:
37
+ - CHROME_MAIN_VERSION=`google-chrome-stable --version | sed -E 's/(^Google Chrome |\.[0-9]+ )//g'`
38
+ - CHROMEDRIVER_VERSION=`curl -s "https://chromedriver.storage.googleapis.com/LATEST_RELEASE_$CHROME_MAIN_VERSION"`
39
+ - curl "https://chromedriver.storage.googleapis.com/${CHROMEDRIVER_VERSION}/chromedriver_linux64.zip" -O
40
+ - unzip chromedriver_linux64.zip -d ~/bin
41
+
42
+ script:
43
+ - bundle exec rake test_app
44
+ - bundle exec rake spec
data/Appraisals CHANGED
@@ -1,12 +1,6 @@
1
- appraise 'spree-3-5' do
2
- gem 'spree', '~> 3.5.0'
3
- gem 'spree_auth_devise', '~> 3.3.0'
4
- gem 'rails-controller-testing'
5
- end
6
-
7
- appraise 'spree-3-7' do
8
- gem 'spree', '~> 3.7.0'
9
- gem 'spree_auth_devise', '~> 3.5.0'
1
+ appraise 'spree-4-1' do
2
+ gem 'spree', '~> 4.1.0'
3
+ gem 'spree_auth_devise', '~> 4.1.0'
10
4
  gem 'rails-controller-testing'
11
5
  end
12
6
 
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2017-2018 Spark Solutions Sp. z o.o.
1
+ Copyright (c) 2017-2020 Spark Solutions Sp. z o.o.
2
2
  All rights reserved.
3
3
 
4
4
  Redistribution and use in source and binary forms, with or without modification,
data/README.md CHANGED
@@ -6,6 +6,7 @@ This extensions adds support for [Google Analytics Enhanced Ecommerce](https://d
6
6
  and [Segment Ecommerce](https://segment.com/docs/spec/ecommerce/v2/) tracking to [Spree Commerce](https://spreecommerce.org) stores.
7
7
 
8
8
  Via Segment.com you can plug-in also a lot of additional vendors and services like:
9
+
9
10
  * Mixpanel
10
11
  * Kissmetrics
11
12
  * Google Tag Manager
@@ -18,16 +19,19 @@ No additional development required.
18
19
  ## Installation
19
20
 
20
21
  1. Add this extension to your Gemfile with this line:
22
+
21
23
  ```ruby
22
- gem 'spree_analytics_trackers', '~> 1.0'
24
+ gem 'spree_analytics_trackers', '~> 2.0'
23
25
  ```
24
26
 
25
27
  2. Install the gem using Bundler:
28
+
26
29
  ```ruby
27
30
  bundle install
28
31
  ```
29
32
 
30
33
  3. Copy & run migrations
34
+
31
35
  ```ruby
32
36
  bundle exec rails g spree_analytics_trackers:install
33
37
  ```
@@ -52,10 +56,9 @@ Simply add this require statement to your spec_helper:
52
56
  require 'spree_analytics_trackers/factories'
53
57
  ```
54
58
 
55
-
56
59
  ## License
57
60
 
58
- Spree Analytics Trackers is copyright © 2017-2018
61
+ Spree Analytics Trackers is copyright © 2017-2020
59
62
  [Spark Solutions Sp. z o.o.][spark]. It is free software,
60
63
  and may be redistributed under the terms specified in the
61
64
  [LICENCE](LICENSE) file.
@@ -63,6 +66,7 @@ and may be redistributed under the terms specified in the
63
66
  [LICENSE]: https://github.com/spree-contrib/spree_analytics_trackers/blob/master/LICENSE
64
67
 
65
68
  ## About Spark Solutions
69
+
66
70
  [![Spark Solutions](http://sparksolutions.co/wp-content/uploads/2015/01/logo-ss-tr-221x100.png)][spark]
67
71
 
68
72
  Spree Analytics Trackers is maintained by [Spark Solutions Sp. z o.o.](http://sparksolutions.co?utm_source=github).
@@ -0,0 +1,50 @@
1
+ //= require spree/frontend
2
+
3
+ function gaAddToCart(variant, quantity) {
4
+ clearGAplugins();
5
+ var price = typeof variant.price === 'object' ? variant.price.amount : variant.price
6
+ gtag(
7
+ 'event',
8
+ 'add_to_cart',
9
+ {
10
+ items: [{
11
+ id: variant.sku,
12
+ name: variant.name,
13
+ category: variant.category,
14
+ variant: variant.options_text,
15
+ brand: variant.brand,
16
+ price: price,
17
+ quantity: quantity
18
+ }]
19
+ }
20
+ );
21
+ }
22
+
23
+ function segmentAddtoCart(variant, quantity, currency) {
24
+ analytics.track('Product Added', {
25
+ product_id: variant.id,
26
+ sku: variant.sku,
27
+ category: variant.category,
28
+ name: variant.name,
29
+ brand: variant.brand,
30
+ price: variant.price,
31
+ currency: currency,
32
+ quantity: quantity
33
+ });
34
+ }
35
+
36
+ Spree.ready(function(){
37
+ $('body').on('product_add_to_cart', function(event) {
38
+ var variant = event.variant
39
+ var quantity = event.quantity_increment
40
+ var currency = event.cart.currency
41
+
42
+ if (typeof gtag !== 'undefined') {
43
+ gaAddToCart(variant, quantity)
44
+ }
45
+
46
+ if (typeof analytics !== 'undefined') {
47
+ segmentAddtoCart(variant, quantity, currency)
48
+ }
49
+ })
50
+ });
@@ -0,0 +1,34 @@
1
+ //= require spree/frontend
2
+
3
+ function gaRemoveFromCart(variant) {
4
+ clearGAplugins();
5
+ gtag(
6
+ 'event',
7
+ 'remove_from_cart',
8
+ {
9
+ items: [{
10
+ id: variant.sku,
11
+ name: variant.name,
12
+ price: variant.price,
13
+ variant: variant.options,
14
+ quantity: variant.quantity
15
+ }]
16
+ }
17
+ );
18
+ }
19
+
20
+ Spree.ready(function(){
21
+ $('body').on('product_remove_from_cart', function(event) {
22
+ var variant = {
23
+ sku: event.variant_sku,
24
+ name: event.variant_name,
25
+ price: event.variant_price,
26
+ options: event.variant_options,
27
+ quantity: event.variant_quantity
28
+ }
29
+
30
+ if (typeof gtag !== 'undefined') {
31
+ gaRemoveFromCart(variant)
32
+ }
33
+ })
34
+ })
@@ -1,6 +1,14 @@
1
1
  module Spree
2
2
  module Admin
3
3
  class TrackersController < ResourceController
4
+ before_action :load_data
5
+
6
+ private
7
+
8
+ def load_data
9
+ @engines = Spree::Tracker.engines.keys.sort.map { |k| [k.humanize, k] }
10
+ @stores = Spree::Store.all
11
+ end
4
12
  end
5
13
  end
6
14
  end
@@ -0,0 +1,11 @@
1
+ module SpreeAnalyticsTrackers
2
+ module CheckoutControllerDecorator
3
+ def self.included(base)
4
+ base.helper 'spree/trackers'
5
+ end
6
+ end
7
+ end
8
+
9
+ if defined?(Spree::CheckoutController)
10
+ ::Spree::CheckoutController.include(::SpreeAnalyticsTrackers::CheckoutControllerDecorator)
11
+ end
@@ -0,0 +1,13 @@
1
+ module SpreeAnalyticsTrackers
2
+ module StoreControllerDecorator
3
+ def self.included(base)
4
+ base.include ::Spree::BaseHelper
5
+
6
+ base.helper 'spree/trackers'
7
+ end
8
+ end
9
+ end
10
+
11
+ if defined?(Spree::StoreController)
12
+ ::Spree::StoreController.include(::SpreeAnalyticsTrackers::StoreControllerDecorator)
13
+ end
@@ -0,0 +1,11 @@
1
+ module SpreeAnalyticsTrackers
2
+ module UserConfirmationsControllerDecorator
3
+ def self.included(base)
4
+ base.helper 'spree/trackers'
5
+ end
6
+ end
7
+ end
8
+
9
+ if defined?(Spree::UserConfirmationsController)
10
+ ::Spree::UserConfirmationsController.include(::SpreeAnalyticsTrackers::UserConfirmationsControllerDecorator)
11
+ end
@@ -0,0 +1,11 @@
1
+ module SpreeAnalyticsTrackers
2
+ module UserPasswordsControllerDecorator
3
+ def self.included(base)
4
+ base.helper 'spree/trackers'
5
+ end
6
+ end
7
+ end
8
+
9
+ if defined?(Spree::UserPasswordsController)
10
+ ::Spree::UserPasswordsController.include(::SpreeAnalyticsTrackers::UserPasswordsControllerDecorator)
11
+ end
@@ -0,0 +1,11 @@
1
+ module SpreeAnalyticsTrackers
2
+ module UserRegistrationsControllerDecorator
3
+ def self.included(base)
4
+ base.helper 'spree/trackers'
5
+ end
6
+ end
7
+ end
8
+
9
+ if defined?(Spree::UserRegistrationsController)
10
+ ::Spree::UserRegistrationsController.include(::SpreeAnalyticsTrackers::UserRegistrationsControllerDecorator)
11
+ end
@@ -0,0 +1,11 @@
1
+ module SpreeAnalyticsTrackers
2
+ module UserSessionsControllerDecorator
3
+ def self.included(base)
4
+ base.helper 'spree/trackers'
5
+ end
6
+ end
7
+ end
8
+
9
+ if defined?(Spree::UserSessionsController)
10
+ ::Spree::UserSessionsController.include(::SpreeAnalyticsTrackers::UserSessionsControllerDecorator)
11
+ end
@@ -1,23 +1,86 @@
1
1
  module Spree
2
2
  module TrackersHelper
3
3
  def product_for_segment(product, optional = {})
4
- {
5
- product_id: product.id,
6
- sku: product.sku,
7
- category: product.category.try(:name),
8
- name: product.name,
9
- brand: product.brand.try(:name),
10
- price: product.price.to_f,
11
- currency: product.currency,
12
- url: product_url(product),
13
- }.tap do |hash|
14
- # This method returns either asset_url (Paperclip) or rails_blob_path (ActiveStorage) to return the specified image(s)
15
- if defined?(ActiveStorage) && !Rails.application.config.use_paperclip
16
- hash[:image_url] = request.base_url + Rails.application.routes.url_helpers.rails_blob_path(optional.delete(:image).attachment, only_path: true) if optional[:image]
17
- else
18
- hash[:image_url] = request.base_url + asset_url(optional.delete(:image).attachment) if optional[:image]
19
- end
4
+ cache_key = [
5
+ 'spree-segment-product',
6
+ I18n.locale,
7
+ current_currency,
8
+ product.cache_key_with_version
9
+ ].compact.join('/')
10
+
11
+ product_hash = Rails.cache.fetch(cache_key) do
12
+ {
13
+ product_id: product.id,
14
+ sku: product.sku,
15
+ category: product.category&.name,
16
+ name: product.name,
17
+ brand: product.brand&.name,
18
+ price: product.price_in(current_currency).amount&.to_f,
19
+ currency: current_currency,
20
+ url: spree.product_url(product)
21
+ }
22
+ end
23
+
24
+ product_hash.tap do |hash|
25
+ hash[:image_url] = default_image_for_product_or_variant(product)
20
26
  end.merge(optional).to_json.html_safe
21
27
  end
28
+
29
+ def ga_line_item(line_item)
30
+ variant = line_item.variant
31
+
32
+ cache_key = [
33
+ 'spree-ga-line-item',
34
+ I18n.locale,
35
+ current_currency,
36
+ line_item.cache_key_with_version,
37
+ variant.cache_key_with_version
38
+ ].compact.join('/')
39
+
40
+ Rails.cache.fetch(cache_key) do
41
+ product = line_item.product
42
+ {
43
+ id: variant.sku,
44
+ name: variant.name,
45
+ category: product.category&.name,
46
+ variant: variant.options_text,
47
+ brand: product.brand&.name,
48
+ quantity: line_item.quantity,
49
+ price: variant.price_in(current_currency).amount&.to_f
50
+ }.to_json.html_safe
51
+ end
52
+ end
53
+
54
+ def filtering_param_present?(param)
55
+ params.key?(param) && params.fetch(param).present?
56
+ end
57
+
58
+ def any_filtering_params?
59
+ filtering_params.any? { |p| filtering_param_present?(p) }
60
+ end
61
+
62
+ def filtering_params_with_values
63
+ params_with_values = {}
64
+ filtering_params.each do |param|
65
+ params_with_values[param] = params.fetch(param) if filtering_param_present?(param)
66
+ end
67
+ params_with_values
68
+ end
69
+
70
+ def segment_tracker
71
+ @segment_tracker ||= Spree::Tracker.current(:segment, current_store)
72
+ end
73
+
74
+ def segment_enabled?
75
+ segment_tracker.present?
76
+ end
77
+
78
+ def ga_tracker
79
+ @ga_tracker ||= Spree::Tracker.current(:google_analytics, current_store)
80
+ end
81
+
82
+ def ga_enabled?
83
+ ga_tracker.present?
84
+ end
22
85
  end
23
86
  end
@@ -5,20 +5,26 @@ module Spree
5
5
 
6
6
  after_commit :clear_cache
7
7
 
8
- validates :analytics_id, presence: true, uniqueness: { scope: :engine, case_sensitive: false }
8
+ validates :analytics_id, presence: true, uniqueness: { scope: [:engine, :store_id], case_sensitive: false }
9
+ validates :store, presence: true
9
10
 
10
11
  scope :active, -> { where(active: true) }
11
12
 
12
- def self.current(engine = TRACKING_ENGINES.first)
13
- tracker = Rails.cache.fetch("current_tracker/#{engine}") do
14
- send(engine).active.first
13
+ belongs_to :store
14
+
15
+ def self.current(engine = nil, store = nil)
16
+ engine ||= TRACKING_ENGINES.first
17
+ store ||= Spree::Store.default
18
+
19
+ tracker = Rails.cache.fetch("current_tracker/#{engine}/#{store.id}") do
20
+ active.find_by(store: store, engine: engine)
15
21
  end
16
22
  tracker.analytics_id.present? ? tracker : nil if tracker
17
23
  end
18
24
 
19
25
  def clear_cache
20
26
  TRACKING_ENGINES.each do |engine|
21
- Rails.cache.delete("current_tracker/#{engine}")
27
+ Rails.cache.delete("current_tracker/#{engine}/#{store_id}")
22
28
  end
23
29
  end
24
30
  end