solidus_admin_insights 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +54 -0
- data/Gemfile +2 -0
- data/LICENSE +26 -0
- data/README.md +71 -0
- data/Rakefile +21 -0
- data/app/assets/javascripts/spree/backend/jquery.tablesorter.min.js +4 -0
- data/app/assets/javascripts/spree/backend/solidus_admin_insights.js +2 -0
- data/app/assets/javascripts/spree/backend/solidus_admin_insights/paginator.js +128 -0
- data/app/assets/javascripts/spree/backend/solidus_admin_insights/report_loader.js +265 -0
- data/app/assets/javascripts/spree/backend/solidus_admin_insights/searcher.js +72 -0
- data/app/assets/javascripts/spree/backend/solidus_admin_insights/table_sorter.js +47 -0
- data/app/assets/javascripts/spree/backend/tmpl.js +87 -0
- data/app/assets/javascripts/spree/frontend/solidus_admin_insights.js +2 -0
- data/app/assets/stylesheets/spree/backend/override_pdf.css +71 -0
- data/app/assets/stylesheets/spree/backend/solidus_admin_insights.css +132 -0
- data/app/assets/stylesheets/spree/frontend/solidus_admin_insights.css +4 -0
- data/app/controllers/spree/admin/insights_controller.rb +103 -0
- data/app/helpers/spree/admin/base_helper_decorator.rb +17 -0
- data/app/models/spree/app_configuration_decorator.rb +3 -0
- data/app/models/spree/product_decorator.rb +3 -0
- data/app/models/spree/promotion_action_decorator.rb +3 -0
- data/app/models/spree/return_authorization_decorator.rb +4 -0
- data/app/permissions/spree/permission_sets/insight_display.rb +9 -0
- data/app/reports/spree/best_selling_products_report.rb +42 -0
- data/app/reports/spree/cart_additions_report.rb +36 -0
- data/app/reports/spree/cart_removals_report.rb +36 -0
- data/app/reports/spree/cart_updations_report.rb +40 -0
- data/app/reports/spree/payment_method_transactions_conversion_rate_report.rb +74 -0
- data/app/reports/spree/payment_method_transactions_conversion_rate_report/payment_method_state_distribution_chart.rb +39 -0
- data/app/reports/spree/payment_method_transactions_report.rb +60 -0
- data/app/reports/spree/payment_method_transactions_report/payment_method_revenue_distribution_chart.rb +36 -0
- data/app/reports/spree/product_views_report.rb +46 -0
- data/app/reports/spree/product_views_to_cart_additions_report.rb +53 -0
- data/app/reports/spree/product_views_to_purchases_report.rb +54 -0
- data/app/reports/spree/promotional_cost_report.rb +84 -0
- data/app/reports/spree/promotional_cost_report/promotional_cost_chart.rb +37 -0
- data/app/reports/spree/promotional_cost_report/usage_count_chart.rb +41 -0
- data/app/reports/spree/report.rb +131 -0
- data/app/reports/spree/report/chart.rb +11 -0
- data/app/reports/spree/report/configuration.rb +40 -0
- data/app/reports/spree/report/date_slicer.rb +61 -0
- data/app/reports/spree/report/observation.rb +49 -0
- data/app/reports/spree/report/query_fragments.rb +45 -0
- data/app/reports/spree/report/query_time_scale.rb +19 -0
- data/app/reports/spree/report/result.rb +100 -0
- data/app/reports/spree/report/timed_observation.rb +47 -0
- data/app/reports/spree/report/timed_result.rb +48 -0
- data/app/reports/spree/returned_products_report.rb +37 -0
- data/app/reports/spree/sales_performance_report.rb +107 -0
- data/app/reports/spree/sales_performance_report/profit_loss_chart.rb +37 -0
- data/app/reports/spree/sales_performance_report/profit_loss_percent_chart.rb +36 -0
- data/app/reports/spree/sales_performance_report/sale_cost_price_chart.rb +48 -0
- data/app/reports/spree/sales_tax_report.rb +64 -0
- data/app/reports/spree/sales_tax_report/monthly_sales_tax_comparison_chart.rb +39 -0
- data/app/reports/spree/shipping_cost_report.rb +89 -0
- data/app/reports/spree/shipping_cost_report/shipping_cost_distribution_chart.rb +38 -0
- data/app/reports/spree/trending_search_report.rb +50 -0
- data/app/reports/spree/trending_search_report/frequency_distribution_pie_chart.rb +41 -0
- data/app/reports/spree/unique_purchases_report.rb +39 -0
- data/app/reports/spree/user_pool_report.rb +66 -0
- data/app/reports/spree/user_pool_report/distribution_column_chart.rb +65 -0
- data/app/reports/spree/users_not_converted_report.rb +48 -0
- data/app/reports/spree/users_who_recently_purchased_report.rb +69 -0
- data/app/services/spree/report_generation_service.rb +27 -0
- data/app/views/spree/admin/insights/_chart.html.erb +4 -0
- data/app/views/spree/admin/insights/download.pdf.erb +27 -0
- data/app/views/spree/admin/insights/index.html.erb +82 -0
- data/app/views/spree/admin/insights/search/_product_views_search.html.erb +13 -0
- data/app/views/spree/admin/insights/search/_search_form.html.erb +39 -0
- data/app/views/spree/admin/insights/search/_trending_searches_search.html.erb +13 -0
- data/app/views/spree/admin/insights/search/_users_not_converted_search.html.erb +13 -0
- data/app/views/spree/admin/insights/search/_users_who_have_not_purchased_recently_search.html.erb +13 -0
- data/app/views/spree/admin/insights/search/_users_who_recently_purchased_search.html.erb +13 -0
- data/app/views/spree/admin/shared/_insights_side_menu.html.erb +5 -0
- data/app/views/spree/admin/shared/sub_menu/_insight.html.erb +7 -0
- data/app/views/spree/admin/templates/insights/_paginator.template +11 -0
- data/app/views/spree/admin/templates/insights/_search.template +76 -0
- data/app/views/spree/admin/templates/insights/_show.template +49 -0
- data/app/views/spree/layouts/pdf.html.erb +9 -0
- data/bin/rails +7 -0
- data/config/initializers/add_to_sidebar.rb +14 -0
- data/config/initializers/assets.rb +1 -0
- data/config/initializers/mime_types.rb +2 -0
- data/config/initializers/wicked_pdf.rb +21 -0
- data/config/locales/en.yml +167 -0
- data/config/routes.rb +6 -0
- data/lib/generators/solidus_admin_insights/install/install_generator.rb +36 -0
- data/lib/generators/solidus_admin_insights/install/solidus_admin_insights.rb +22 -0
- data/lib/solidus_admin_insights.rb +14 -0
- data/lib/solidus_admin_insights/engine.rb +27 -0
- data/lib/solidus_admin_insights/factories.rb +6 -0
- data/solidus_admin_insights.gemspec +42 -0
- data/spec/spec_helper.rb +93 -0
- metadata +419 -0
@@ -0,0 +1,17 @@
|
|
1
|
+
Spree::BaseHelper.class_eval do
|
2
|
+
def selected?(path)
|
3
|
+
path == 'spree/admin/insights'
|
4
|
+
end
|
5
|
+
|
6
|
+
def form_action(insight, insight_type)
|
7
|
+
insight ? admin_insight_path(id: @report_name, type: insight_type) : 'javascript:void(0)'
|
8
|
+
end
|
9
|
+
|
10
|
+
def page_selector_options
|
11
|
+
[5, 10, 15, 30, 45, 60]
|
12
|
+
end
|
13
|
+
|
14
|
+
def pdf_logo(image_path = Spree::Config[:logo])
|
15
|
+
wicked_pdf_image_tag image_path, class: 'logo'
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Spree
|
2
|
+
class BestSellingProductsReport < Spree::Report
|
3
|
+
DEFAULT_SORTABLE_ATTRIBUTE = :sold_count
|
4
|
+
HEADERS = { sku: :string, product_name: :string, sold_count: :integer }
|
5
|
+
SEARCH_ATTRIBUTES = { start_date: :orders_completed_from, end_date: :orders_completed_to }
|
6
|
+
SORTABLE_ATTRIBUTES = [:product_name, :sku, :sold_count]
|
7
|
+
|
8
|
+
deeplink product_name: { template: %Q{<a href="/admin/products/{%# o.product_slug %}" target="_blank">{%# o.product_name %}</a>} }
|
9
|
+
|
10
|
+
class Result < Spree::Report::Result
|
11
|
+
class Observation < Spree::Report::Observation
|
12
|
+
observation_fields [:product_name, :product_slug, :sku, :sold_count]
|
13
|
+
|
14
|
+
def sku
|
15
|
+
@sku.presence || @product_name
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def report_query
|
21
|
+
Spree::LineItem
|
22
|
+
.joins(:order)
|
23
|
+
.joins(:variant)
|
24
|
+
.joins(:product)
|
25
|
+
.where(Spree::Product.arel_table[:name].matches(search_name))
|
26
|
+
.where(spree_orders: { state: 'complete' })
|
27
|
+
.where(spree_orders: { completed_at: reporting_period })
|
28
|
+
.group(:variant_id, :product_name, :product_slug, 'spree_variants.sku')
|
29
|
+
.select(
|
30
|
+
'spree_products.name as product_name',
|
31
|
+
'spree_products.slug as product_slug',
|
32
|
+
'spree_variants.sku as sku',
|
33
|
+
'sum(quantity) as sold_count'
|
34
|
+
)
|
35
|
+
end
|
36
|
+
|
37
|
+
private def search_name
|
38
|
+
search[:name].present? ? "%#{ search[:name] }%" : '%'
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Spree
|
2
|
+
class CartAdditionsReport < Spree::Report
|
3
|
+
DEFAULT_SORTABLE_ATTRIBUTE = :product_name
|
4
|
+
HEADERS = { sku: :string, product_name: :string, additions: :integer, quantity_change: :integer }
|
5
|
+
SEARCH_ATTRIBUTES = { start_date: :product_added_from, end_date: :product_added_to }
|
6
|
+
SORTABLE_ATTRIBUTES = [:product_name, :sku, :additions, :quantity_change]
|
7
|
+
|
8
|
+
deeplink product_name: { template: %Q{<a href="/admin/products/{%# o.product_slug %}" target="_blank">{%# o.product_name %}</a>} }
|
9
|
+
|
10
|
+
class Result < Spree::Report::Result
|
11
|
+
class Observation < Spree::Report::Observation
|
12
|
+
observation_fields [:product_name, :product_slug, :additions, :quantity_change, :sku]
|
13
|
+
|
14
|
+
def sku
|
15
|
+
@sku.presence || @product_name
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def report_query
|
21
|
+
Spree::CartEvent
|
22
|
+
.added
|
23
|
+
.joins(:variant)
|
24
|
+
.joins(:product)
|
25
|
+
.where(created_at: reporting_period)
|
26
|
+
.group('product_name', 'product_slug', 'spree_variants.sku')
|
27
|
+
.select(
|
28
|
+
'spree_products.name as product_name',
|
29
|
+
'spree_products.slug as product_slug',
|
30
|
+
'spree_variants.sku as sku',
|
31
|
+
'count(spree_products.name) as additions',
|
32
|
+
'sum(spree_cart_events.quantity) as quantity_change'
|
33
|
+
)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Spree
|
2
|
+
class CartRemovalsReport < Spree::Report
|
3
|
+
DEFAULT_SORTABLE_ATTRIBUTE = :product_name
|
4
|
+
HEADERS = { sku: :string, product_name: :string, removals: :integer, quantity_change: :integer }
|
5
|
+
SEARCH_ATTRIBUTES = { start_date: :product_removed_from, end_date: :product_removed_to }
|
6
|
+
SORTABLE_ATTRIBUTES = [:product_name, :sku, :removals, :quantity_change]
|
7
|
+
|
8
|
+
deeplink product_name: { template: %Q{<a href="/admin/products/{%# o.product_slug %}" target="_blank">{%# o.product_name %}</a>} }
|
9
|
+
|
10
|
+
class Result < Spree::Report::Result
|
11
|
+
class Observation < Spree::Report::Observation
|
12
|
+
observation_fields [:product_name, :product_slug, :removals, :quantity_change, :sku]
|
13
|
+
|
14
|
+
def sku
|
15
|
+
@sku.presence || @product_name
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def report_query
|
21
|
+
Spree::CartEvent
|
22
|
+
.removed
|
23
|
+
.joins(:variant)
|
24
|
+
.joins(:product)
|
25
|
+
.where(created_at: reporting_period)
|
26
|
+
.group('product_name', 'product_slug', 'spree_variants.sku')
|
27
|
+
.select(
|
28
|
+
'spree_products.name as product_name',
|
29
|
+
'spree_products.slug as product_slug',
|
30
|
+
'spree_variants.sku as sku',
|
31
|
+
'count(spree_products.name) as removals',
|
32
|
+
'sum(spree_cart_events.quantity) as quantity_change'
|
33
|
+
)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Spree
|
2
|
+
class CartUpdationsReport < Spree::Report
|
3
|
+
DEFAULT_SORTABLE_ATTRIBUTE = :product_name
|
4
|
+
HEADERS = { sku: :string, product_name: :string, updations: :integer, quantity_increase: :integer, quantity_decrease: :integer }
|
5
|
+
SEARCH_ATTRIBUTES = { start_date: :product_updated_from, end_date: :product_updated_to }
|
6
|
+
SORTABLE_ATTRIBUTES = [:product_name, :sku, :updations, :quantity_increase, :quantity_decrease]
|
7
|
+
|
8
|
+
deeplink product_name: { template: %Q{<a href="/admin/products/{%# o.product_slug %}" target="_blank">{%# o.product_name %}</a>} }
|
9
|
+
|
10
|
+
class Result < Spree::Report::Result
|
11
|
+
class Observation < Spree::Report::Observation
|
12
|
+
observation_fields [:product_name, :product_slug, :updations, :quantity_increase, :sku, :quantity_decrease]
|
13
|
+
|
14
|
+
def sku
|
15
|
+
@sku.presence || @product_name
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def report_query
|
21
|
+
quantity_increase_sql = "CASE WHEN quantity > 0 then spree_cart_events.quantity ELSE 0 END"
|
22
|
+
quantity_decrease_sql = "CASE WHEN quantity < 0 then spree_cart_events.quantity ELSE 0 END"
|
23
|
+
|
24
|
+
Spree::CartEvent
|
25
|
+
.updated
|
26
|
+
.joins(:variant)
|
27
|
+
.joins(:product)
|
28
|
+
.where(created_at: reporting_period)
|
29
|
+
.group('product_name', 'product_slug', 'spree_variants.sku')
|
30
|
+
.select(
|
31
|
+
'spree_products.name as product_name',
|
32
|
+
'spree_products.slug as product_slug',
|
33
|
+
'spree_variants.sku as sku',
|
34
|
+
'count(spree_products.name) as updations',
|
35
|
+
"SUM(#{ quantity_increase_sql }) as quantity_increase",
|
36
|
+
"SUM(#{ quantity_decrease_sql }) as quantity_decrease"
|
37
|
+
)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module Spree
|
2
|
+
class PaymentMethodTransactionsConversionRateReport < Spree::Report
|
3
|
+
DEFAULT_SORTABLE_ATTRIBUTE = :payment_method_name
|
4
|
+
HEADERS = { payment_method_name: :string, payment_state: :string, months_name: :string, count: :integer }
|
5
|
+
SEARCH_ATTRIBUTES = { start_date: :payments_created_from, end_date: :payments_created_to }
|
6
|
+
SORTABLE_ATTRIBUTES = [:payment_method_name, :successful_payments_count, :failed_payments_count, :pending_payments_count, :invalid_payments_count]
|
7
|
+
|
8
|
+
class Result < Spree::Report::TimedResult
|
9
|
+
charts PaymentMethodStateDistributionChart
|
10
|
+
|
11
|
+
def build_empty_observations
|
12
|
+
super
|
13
|
+
@_payment_methods = @results.collect { |result| result['payment_method_name'] }.uniq
|
14
|
+
@observations = @_payment_methods.collect do |payment_method_name|
|
15
|
+
payment_states = @results
|
16
|
+
.select { |result| result['payment_method_name'] == payment_method_name }
|
17
|
+
.collect { |result| result['payment_state'] }
|
18
|
+
.uniq
|
19
|
+
|
20
|
+
payment_states.collect do |state|
|
21
|
+
@observations.collect do |observation|
|
22
|
+
_d_observation = observation.dup
|
23
|
+
_d_observation.payment_method_name = payment_method_name
|
24
|
+
_d_observation.payment_state = state
|
25
|
+
_d_observation.count = 0
|
26
|
+
_d_observation
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end.flatten
|
30
|
+
end
|
31
|
+
|
32
|
+
class Observation < Spree::Report::TimedObservation
|
33
|
+
observation_fields [:payment_method_name, :payment_state, :count]
|
34
|
+
|
35
|
+
def payment_state
|
36
|
+
if @payment_state == 'pending'
|
37
|
+
@payment_state
|
38
|
+
else
|
39
|
+
"capturing #{ @payment_state }"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def describes?(result, time_scale)
|
44
|
+
(result['payment_method_name'] == payment_method_name && result['payment_state'] == @payment_state) && super
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def report_query
|
50
|
+
Spree::Report::QueryFragments
|
51
|
+
.from_subquery(payment_methods)
|
52
|
+
.group(*time_scale_columns_to_s, 'payment_method_name', 'payment_state')
|
53
|
+
.order(*time_scale_columns)
|
54
|
+
.project(
|
55
|
+
*time_scale_columns,
|
56
|
+
'payment_method_name',
|
57
|
+
'payment_state',
|
58
|
+
'COUNT(payment_method_id) as count'
|
59
|
+
)
|
60
|
+
end
|
61
|
+
|
62
|
+
private def payment_methods
|
63
|
+
Spree::PaymentMethod
|
64
|
+
.joins(:payments)
|
65
|
+
.where(spree_payments: { created_at: reporting_period })
|
66
|
+
.select(
|
67
|
+
'spree_payment_methods.id as payment_method_id',
|
68
|
+
'name as payment_method_name',
|
69
|
+
'state as payment_state',
|
70
|
+
*time_scale_selects('spree_payments')
|
71
|
+
)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
class Spree::PaymentMethodTransactionsConversionRateReport::PaymentMethodStateDistributionChart
|
2
|
+
attr_accessor :chart_data
|
3
|
+
|
4
|
+
def initialize(result)
|
5
|
+
@time_dimension = result.time_dimension
|
6
|
+
@grouped_by_payment_method = result.observations.group_by(&:payment_method_name)
|
7
|
+
@time_series = []
|
8
|
+
@time_series = @grouped_by_payment_method.values.first.collect { |observation| observation.send(@time_dimension) } if @grouped_by_payment_method.first.present?
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_h
|
12
|
+
@grouped_by_payment_method.collect do |method_name, observations|
|
13
|
+
{
|
14
|
+
id: 'payment-state-' + method_name,
|
15
|
+
json: {
|
16
|
+
chart: { type: 'column' },
|
17
|
+
title: {
|
18
|
+
useHTML: true,
|
19
|
+
text: %Q(<span class='chart-title'>#{ method_name } Conversion Status</span>
|
20
|
+
<span class='fa fa-question-circle' data-toggle='tooltip' title=' Tracks the status of Payments made from different payment methods such as CC, Check etc.'></span>)
|
21
|
+
},
|
22
|
+
|
23
|
+
xAxis: { categories: @time_series },
|
24
|
+
yAxis: {
|
25
|
+
title: { text: 'Count' }
|
26
|
+
},
|
27
|
+
tooltip: { valuePrefix: '#' },
|
28
|
+
legend: {
|
29
|
+
layout: 'vertical',
|
30
|
+
align: 'right',
|
31
|
+
verticalAlign: 'middle',
|
32
|
+
borderWidth: 0
|
33
|
+
},
|
34
|
+
series: observations.group_by(&:payment_state).map { |key, value| { name: key, data: value.map(&:count) } }
|
35
|
+
}
|
36
|
+
}
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Spree
|
2
|
+
class PaymentMethodTransactionsReport < Spree::Report
|
3
|
+
DEFAULT_SORTABLE_ATTRIBUTE = :payment_method_name
|
4
|
+
HEADERS = { payment_method_name: :string, payment_amount: :integer }
|
5
|
+
SEARCH_ATTRIBUTES = { start_date: :payments_created_from, end_date: :payments_created_till }
|
6
|
+
SORTABLE_ATTRIBUTES = []
|
7
|
+
|
8
|
+
class Result < Spree::Report::TimedResult
|
9
|
+
charts PaymentMethodRevenueDistributionChart
|
10
|
+
|
11
|
+
def build_empty_observations
|
12
|
+
super
|
13
|
+
@_payment_methods = @results.collect { |result| result['payment_method_name'] }.uniq
|
14
|
+
@observations = @_payment_methods.collect do |payment_method_name|
|
15
|
+
@observations.collect do |observation|
|
16
|
+
_d_observation = observation.dup
|
17
|
+
_d_observation.payment_amount = 0
|
18
|
+
_d_observation.payment_method_name = payment_method_name
|
19
|
+
_d_observation
|
20
|
+
end
|
21
|
+
end.flatten
|
22
|
+
end
|
23
|
+
|
24
|
+
class Observation < Spree::Report::TimedObservation
|
25
|
+
observation_fields [:payment_method_name, :payment_amount]
|
26
|
+
|
27
|
+
def describes?(result, time_scale)
|
28
|
+
(result['payment_method_name'] == payment_method_name) && super
|
29
|
+
end
|
30
|
+
|
31
|
+
def payment_amount
|
32
|
+
@payment_amount.to_f
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def report_query
|
38
|
+
Spree::Report::QueryFragments
|
39
|
+
.from_subquery(payments)
|
40
|
+
.group(*time_scale_columns_to_s, 'payment_method_name')
|
41
|
+
.order(*time_scale_columns)
|
42
|
+
.project(
|
43
|
+
*time_scale_columns,
|
44
|
+
'payment_method_name',
|
45
|
+
'SUM(payment_amount) as payment_amount'
|
46
|
+
)
|
47
|
+
end
|
48
|
+
|
49
|
+
private def payments
|
50
|
+
Spree::PaymentMethod
|
51
|
+
.joins(:payments)
|
52
|
+
.where(spree_payments: { created_at: reporting_period })
|
53
|
+
.select(
|
54
|
+
*time_scale_selects('spree_payments'),
|
55
|
+
'spree_payment_methods.name as payment_method_name',
|
56
|
+
'spree_payments.amount as payment_amount',
|
57
|
+
)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class Spree::PaymentMethodTransactionsReport::PaymentMethodRevenueDistributionChart
|
2
|
+
def initialize(result)
|
3
|
+
@time_dimension = result.time_dimension
|
4
|
+
@grouped_by_payment_method = result.observations.group_by(&:payment_method_name)
|
5
|
+
@time_series = []
|
6
|
+
if @grouped_by_payment_method.values.first.present?
|
7
|
+
@time_series = @grouped_by_payment_method.values.first.collect { |observation| observation.send(@time_dimension) }
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_h
|
12
|
+
{
|
13
|
+
id: 'payment-methods',
|
14
|
+
json: {
|
15
|
+
chart: { type: 'column' },
|
16
|
+
title: {
|
17
|
+
useHTML: true,
|
18
|
+
text: "<span class='chart-title'>Payment Methods</span><span class='fa fa-question-circle' data-toggle='tooltip' title=' Compare the revenue generated by different Payment methods such as CC, Check etc.'></span>"
|
19
|
+
},
|
20
|
+
xAxis: { categories: @time_series },
|
21
|
+
yAxis: {
|
22
|
+
title: { text: 'value($)' }
|
23
|
+
},
|
24
|
+
tooltip: { valuePrefix: '$' },
|
25
|
+
legend: {
|
26
|
+
layout: 'vertical',
|
27
|
+
align: 'right',
|
28
|
+
verticalAlign: 'middle',
|
29
|
+
borderWidth: 0
|
30
|
+
},
|
31
|
+
series: @grouped_by_payment_method.collect { |key, value| { name: key, data: value.map(&:payment_amount) }
|
32
|
+
}
|
33
|
+
}
|
34
|
+
}
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Spree
|
2
|
+
class ProductViewsReport < Spree::Report
|
3
|
+
DEFAULT_SORTABLE_ATTRIBUTE = :product_name
|
4
|
+
HEADERS = { product_name: :string, views: :integer, users: :integer, guest_sessions: :integer }
|
5
|
+
SEARCH_ATTRIBUTES = { start_date: :product_view_from, end_date: :product_view_till, name: :name}
|
6
|
+
SORTABLE_ATTRIBUTES = [:product_name, :views, :users, :guest_sessions]
|
7
|
+
|
8
|
+
deeplink product_name: { template: %Q{<a href="/admin/products/{%# o.product_slug %}" target="_blank">{%# o.product_name %}</a>} }
|
9
|
+
|
10
|
+
class Result < Spree::Report::Result
|
11
|
+
class Observation < Spree::Report::Observation
|
12
|
+
observation_fields [:product_name, :product_slug, :views, :users, :guest_sessions]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def report_query
|
17
|
+
viewed_events =
|
18
|
+
Spree::Product
|
19
|
+
.where(Spree::Product.arel_table[:name].matches(search_name))
|
20
|
+
.joins(:page_view_events)
|
21
|
+
.where(spree_page_events: { created_at: reporting_period })
|
22
|
+
.group('product_name', 'product_slug', 'spree_page_events.actor_id', 'spree_page_events.session_id')
|
23
|
+
.select(
|
24
|
+
'spree_products.name as product_name',
|
25
|
+
'spree_products.slug as product_slug',
|
26
|
+
'COUNT(*) as total_views_per_session',
|
27
|
+
'spree_page_events.session_id as session_id',
|
28
|
+
'spree_page_events.actor_id as actor_id'
|
29
|
+
)
|
30
|
+
Spree::Report::QueryFragments
|
31
|
+
.from_subquery(viewed_events)
|
32
|
+
.group('product_name', 'product_slug')
|
33
|
+
.project(
|
34
|
+
'product_name',
|
35
|
+
'product_slug',
|
36
|
+
'SUM(total_views_per_session) as views',
|
37
|
+
'COUNT(DISTINCT actor_id) as users',
|
38
|
+
'(COUNT(DISTINCT session_id) - COUNT(actor_id)) as guest_sessions'
|
39
|
+
)
|
40
|
+
end
|
41
|
+
|
42
|
+
private def search_name
|
43
|
+
search[:name].present? ? "%#{ search[:name] }%" : '%'
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|