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,53 @@
|
|
1
|
+
module Spree
|
2
|
+
class ProductViewsToCartAdditionsReport < Spree::Report
|
3
|
+
DEFAULT_SORTABLE_ATTRIBUTE = :product_name
|
4
|
+
HEADERS = { product_name: :string, views: :integer, cart_additions: :integer, cart_to_view_ratio: :string }
|
5
|
+
SEARCH_ATTRIBUTES = { start_date: :product_view_from, end_date: :product_view_till }
|
6
|
+
SORTABLE_ATTRIBUTES = [:product_name, :views, :cart_additions]
|
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, :cart_additions, :cart_to_view_ratio]
|
13
|
+
|
14
|
+
def cart_to_view_ratio
|
15
|
+
(cart_additions.to_f / views.to_f).round(2)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def report_query
|
21
|
+
cart_additions =
|
22
|
+
Spree::CartEvent
|
23
|
+
.added
|
24
|
+
.joins(:variant)
|
25
|
+
.joins(:product)
|
26
|
+
.where(created_at: reporting_period)
|
27
|
+
.group('spree_products.name', 'spree_products.slug')
|
28
|
+
.select(
|
29
|
+
'spree_products.name as product_name',
|
30
|
+
'spree_products.slug as product_slug',
|
31
|
+
'SUM(spree_cart_events.quantity) as cart_additions'
|
32
|
+
)
|
33
|
+
total_views =
|
34
|
+
Spree::Product
|
35
|
+
.joins(:page_view_events)
|
36
|
+
.group(:name)
|
37
|
+
.select(
|
38
|
+
'spree_products.name as product_name',
|
39
|
+
'COUNT(*) as views'
|
40
|
+
)
|
41
|
+
|
42
|
+
Spree::Report::QueryFragments
|
43
|
+
.from_join(cart_additions, total_views, "q1.product_name = q2.product_name")
|
44
|
+
.project(
|
45
|
+
'q1.product_name',
|
46
|
+
'q1.product_slug',
|
47
|
+
'q2.views',
|
48
|
+
'q1.cart_additions'
|
49
|
+
)
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Spree
|
2
|
+
class ProductViewsToPurchasesReport < Spree::Report
|
3
|
+
DEFAULT_SORTABLE_ATTRIBUTE = :product_name
|
4
|
+
HEADERS = { product_name: :string, views: :integer, purchases: :integer, purchase_to_view_ratio: :integer }
|
5
|
+
SEARCH_ATTRIBUTES = { start_date: :product_view_from, end_date: :product_view_till }
|
6
|
+
SORTABLE_ATTRIBUTES = [:product_name, :views, :purchases]
|
7
|
+
|
8
|
+
class Result < Spree::Report::Result
|
9
|
+
class Observation < Spree::Report::Observation
|
10
|
+
observation_fields [:product_name, :product_slug, :views, :purchases, :purchase_to_view_ratio]
|
11
|
+
|
12
|
+
def purchase_to_view_ratio # This is inconsistent across postgres and mysql
|
13
|
+
(purchases.to_f / views.to_f).round(2)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
deeplink product_name: { template: %Q{<a href="/admin/products/{%# o.product_slug %}" target="_blank">{%# o.product_name %}</a>} }
|
19
|
+
|
20
|
+
def report_query
|
21
|
+
page_events_ar = Arel::Table.new(:spree_page_events)
|
22
|
+
purchase_line_items_ar = Arel::Table.new(:purchase_line_items)
|
23
|
+
|
24
|
+
Spree::Report::QueryFragments.from_subquery(purchase_line_items, as: :purchase_line_items)
|
25
|
+
.join(page_events_ar)
|
26
|
+
.on(page_events_ar[:target_id].eq(purchase_line_items_ar[:product_id]))
|
27
|
+
.where(page_events_ar[:target_type].eq(Arel::Nodes::Quoted.new('Spree::Product')))
|
28
|
+
.where(page_events_ar[:activity].eq(Arel::Nodes::Quoted.new('view')))
|
29
|
+
.group(purchase_line_items_ar[:product_id], purchase_line_items_ar[:product_name],
|
30
|
+
purchase_line_items_ar[:product_slug], purchase_line_items_ar[:purchases])
|
31
|
+
.project(
|
32
|
+
'product_name',
|
33
|
+
'product_slug',
|
34
|
+
'COUNT(*) as views',
|
35
|
+
'purchases'
|
36
|
+
)
|
37
|
+
end
|
38
|
+
|
39
|
+
private def purchase_line_items
|
40
|
+
Spree::LineItem
|
41
|
+
.joins(:order)
|
42
|
+
.joins(:variant)
|
43
|
+
.joins(:product)
|
44
|
+
.where(spree_orders: { state: 'complete', created_at: reporting_period })
|
45
|
+
.group('spree_products.id', 'spree_products.name')
|
46
|
+
.select(
|
47
|
+
'SUM(quantity) as purchases',
|
48
|
+
'spree_products.name as product_name',
|
49
|
+
'spree_products.slug as product_slug',
|
50
|
+
'spree_products.id as product_id'
|
51
|
+
)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Spree
|
2
|
+
class PromotionalCostReport < Spree::Report
|
3
|
+
DEFAULT_SORTABLE_ATTRIBUTE = :promotion_name
|
4
|
+
HEADERS = { promotion_name: :string, usage_count: :integer, promotion_discount: :integer, promotion_code: :string, promotion_start_date: :date, promotion_end_date: :date }
|
5
|
+
SEARCH_ATTRIBUTES = { start_date: :promotion_created_from, end_date: :promotion_created_till }
|
6
|
+
SORTABLE_ATTRIBUTES = [:promotion_name, :usage_count, :promotion_discount, :promotion_code, :promotion_start_date, :promotion_end_date]
|
7
|
+
|
8
|
+
class Result < Spree::Report::TimedResult
|
9
|
+
charts PromotionalCostChart, UsageCountChart
|
10
|
+
|
11
|
+
def build_empty_observations
|
12
|
+
super
|
13
|
+
@_promotions = @results.collect { |result| result['promotion_name'] }.uniq
|
14
|
+
@observations = @_promotions.collect do |promotion_name|
|
15
|
+
@observations.collect do |observation|
|
16
|
+
_d_observation = observation.dup
|
17
|
+
_d_observation.promotion_name = promotion_name
|
18
|
+
_d_observation.usage_count = 0
|
19
|
+
_d_observation
|
20
|
+
end
|
21
|
+
end.flatten
|
22
|
+
end
|
23
|
+
|
24
|
+
class Observation < Spree::Report::TimedObservation
|
25
|
+
observation_fields [
|
26
|
+
:promotion_name, :usage_count,
|
27
|
+
:promotion_discount, :promotion_code,
|
28
|
+
:promotion_start_date, :promotion_end_date
|
29
|
+
]
|
30
|
+
|
31
|
+
def promotion_start_date
|
32
|
+
@promotion_start_date.present? ? @promotion_start_date.to_date.strftime("%B %d %Y") : "-"
|
33
|
+
end
|
34
|
+
|
35
|
+
def promotion_end_date
|
36
|
+
@promotion_end_date.present? ? @promotion_end_date.to_date.strftime("%B %d %Y") : "-"
|
37
|
+
end
|
38
|
+
|
39
|
+
def promotion_discount
|
40
|
+
@promotion_discount.to_f.abs
|
41
|
+
end
|
42
|
+
|
43
|
+
def describes?(result, time_scale)
|
44
|
+
result['promotion_name'] == promotion_name && super
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def report_query
|
50
|
+
Spree::Report::QueryFragments
|
51
|
+
.from_subquery(eligible_promotions)
|
52
|
+
.group(*time_scale_columns, :promotion_id, :promotion_name,
|
53
|
+
:promotion_code, :promotion_start_date, :promotion_end_date)
|
54
|
+
.order(*time_scale_columns_to_s)
|
55
|
+
.project(
|
56
|
+
*time_scale_columns,
|
57
|
+
'promotion_name',
|
58
|
+
'promotion_code',
|
59
|
+
'promotion_start_date',
|
60
|
+
'promotion_end_date',
|
61
|
+
'SUM(promotion_discount) as promotion_discount',
|
62
|
+
'COUNT(promotion_id) as usage_count',
|
63
|
+
'promotion_id'
|
64
|
+
)
|
65
|
+
end
|
66
|
+
|
67
|
+
private def eligible_promotions
|
68
|
+
Spree::PromotionAction
|
69
|
+
.joins(:promotion)
|
70
|
+
.joins(:adjustment)
|
71
|
+
.where(spree_adjustments: { created_at: reporting_period })
|
72
|
+
.select(
|
73
|
+
'spree_promotions.starts_at as promotion_start_date',
|
74
|
+
'spree_promotions.expires_at as promotion_end_date',
|
75
|
+
'spree_adjustments.amount as promotion_discount',
|
76
|
+
'spree_promotions.id as promotion_id',
|
77
|
+
'spree_promotions.name as promotion_name',
|
78
|
+
'spree_promotions.code as promotion_code',
|
79
|
+
*time_scale_selects('spree_adjustments')
|
80
|
+
)
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
class Spree::PromotionalCostReport::PromotionalCostChart
|
2
|
+
attr_accessor :time, :series
|
3
|
+
|
4
|
+
def initialize(result)
|
5
|
+
@grouped_by_promotion = result.observations.group_by(&:promotion_name)
|
6
|
+
@time_dimension = result.time_dimension
|
7
|
+
self.time = []
|
8
|
+
self.time = @grouped_by_promotion.values.first.collect { |observation_value| observation_value.send(@time_dimension) } if @grouped_by_promotion.first.present?
|
9
|
+
self.series = @grouped_by_promotion.collect { |promotion, values| { type: 'column', name: promotion, data: values.collect(&:promotion_discount) } }
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_h
|
13
|
+
{
|
14
|
+
id: 'promotional-cost',
|
15
|
+
json: {
|
16
|
+
chart: { type: 'column' },
|
17
|
+
title: {
|
18
|
+
useHTML: true,
|
19
|
+
text: "<span class='chart-title'>Promotional Cost</span><span class='fa fa-question-circle' data-toggle='tooltip' title=' Compare the costing for various promotions'></span>"
|
20
|
+
},
|
21
|
+
xAxis: { categories: time },
|
22
|
+
yAxis: {
|
23
|
+
title: { text: 'Value($)' }
|
24
|
+
},
|
25
|
+
tooltip: { valuePrefix: '$' },
|
26
|
+
legend: {
|
27
|
+
layout: 'vertical',
|
28
|
+
align: 'right',
|
29
|
+
verticalAlign: 'middle',
|
30
|
+
borderWidth: 0
|
31
|
+
},
|
32
|
+
series: series
|
33
|
+
}
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
class Spree::PromotionalCostReport::UsageCountChart
|
2
|
+
|
3
|
+
attr_accessor :time, :series
|
4
|
+
|
5
|
+
def initialize(result)
|
6
|
+
@grouped_by_promotion = result.observations.group_by(&:promotion_name)
|
7
|
+
@time_dimension = result.time_dimension
|
8
|
+
self.time = []
|
9
|
+
if @grouped_by_promotion.values.first.present?
|
10
|
+
self.time = @grouped_by_promotion.values.first.collect { |observation_value| observation_value.send(@time_dimension) }
|
11
|
+
end
|
12
|
+
self.series = @grouped_by_promotion.collect { |promotion, values| { type: 'column', name: promotion, data: values.collect(&:usage_count) } }
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
def to_h
|
17
|
+
{
|
18
|
+
id: 'promotion-usage-count',
|
19
|
+
json: {
|
20
|
+
chart: { type: 'spline' },
|
21
|
+
title: {
|
22
|
+
useHTML: true,
|
23
|
+
text: "<span class='chart-title'>Promotion Usage Count</span><span class='fa fa-question-circle' data-toggle='tooltip' title='Compare the usage of individual promotions'></span>"
|
24
|
+
},
|
25
|
+
xAxis: { categories: time },
|
26
|
+
yAxis: {
|
27
|
+
title: { text: 'Count' }
|
28
|
+
},
|
29
|
+
tooltip: { valuePrefix: '#' },
|
30
|
+
legend: {
|
31
|
+
layout: 'vertical',
|
32
|
+
align: 'right',
|
33
|
+
verticalAlign: 'middle',
|
34
|
+
borderWidth: 0
|
35
|
+
},
|
36
|
+
series: series
|
37
|
+
}
|
38
|
+
}
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
module Spree
|
2
|
+
class Report
|
3
|
+
|
4
|
+
attr_accessor :sortable_attribute, :sortable_type, :total_records,
|
5
|
+
:records_per_page, :current_page, :paginate, :search, :reporting_period
|
6
|
+
alias_method :sort_direction, :sortable_type
|
7
|
+
alias_method :paginate?, :paginate
|
8
|
+
|
9
|
+
|
10
|
+
TIME_SCALES = [:hourly, :daily, :monthly, :yearly]
|
11
|
+
|
12
|
+
def paginated?
|
13
|
+
false
|
14
|
+
end
|
15
|
+
|
16
|
+
def pagination_required?
|
17
|
+
paginated? && paginate?
|
18
|
+
end
|
19
|
+
|
20
|
+
def deeplink_properties
|
21
|
+
{
|
22
|
+
deeplinked: false
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.deeplink(template_for_headers = {})
|
27
|
+
define_method :deeplink_properties do
|
28
|
+
{ deeplinked: true }.merge(template_for_headers)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def generate(options = {})
|
33
|
+
self.class::Result.new do |report|
|
34
|
+
report.start_date = @start_date
|
35
|
+
report.end_date = @end_date
|
36
|
+
report.time_scale = @time_scale
|
37
|
+
report.report = self
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
def initialize(options)
|
43
|
+
self.search = options.fetch(:search, {})
|
44
|
+
self.records_per_page = options[:records_per_page]
|
45
|
+
self.current_page = options[:offset]
|
46
|
+
self.paginate = options[:paginate]
|
47
|
+
extract_reporting_period
|
48
|
+
determine_report_time_scale
|
49
|
+
if self.class::SORTABLE_ATTRIBUTES.present?
|
50
|
+
set_sortable_attributes(options, self.class::DEFAULT_SORTABLE_ATTRIBUTE)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def header_sorted?(header)
|
55
|
+
sortable_attribute.present? && sortable_attribute.eql?(header)
|
56
|
+
end
|
57
|
+
|
58
|
+
def get_results
|
59
|
+
query =
|
60
|
+
if pagination_required?
|
61
|
+
paginated_report_query
|
62
|
+
else
|
63
|
+
report_query
|
64
|
+
end
|
65
|
+
|
66
|
+
query = query.order(active_record_sort) if sortable_attribute.present?
|
67
|
+
query_sql = query.to_sql
|
68
|
+
r = ActiveRecord::Base.connection.exec_query(query_sql)
|
69
|
+
end
|
70
|
+
|
71
|
+
def set_sortable_attributes(options, default_sortable_attribute)
|
72
|
+
self.sortable_type ||= (options[:sort] && options[:sort][:type].eql?('desc')) ? :desc : :asc
|
73
|
+
self.sortable_attribute = options[:sort] ? options[:sort][:attribute].to_sym : default_sortable_attribute
|
74
|
+
end
|
75
|
+
|
76
|
+
def active_record_sort
|
77
|
+
"#{ sortable_attribute } #{ sortable_type }"
|
78
|
+
end
|
79
|
+
|
80
|
+
def total_records
|
81
|
+
ActiveRecord::Base.connection.select_value(record_count_query.to_sql)
|
82
|
+
end
|
83
|
+
|
84
|
+
def total_pages
|
85
|
+
if pagination_required?
|
86
|
+
total_pages = total_records / records_per_page
|
87
|
+
total_pages -= 1 if total_records % records_per_page == 0
|
88
|
+
total_pages
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def time_scale_selects(time_scale_on = nil)
|
93
|
+
QueryTimeScale.select(@time_scale, time_scale_on)
|
94
|
+
end
|
95
|
+
|
96
|
+
def time_scale_columns
|
97
|
+
@_time_scale_columns ||= QueryTimeScale.time_scale_columns(@time_scale)
|
98
|
+
end
|
99
|
+
|
100
|
+
def time_scale_columns_to_s
|
101
|
+
@_time_scale_columns_to_s ||= time_scale_columns.collect(&:to_s)
|
102
|
+
end
|
103
|
+
|
104
|
+
def name
|
105
|
+
@_report_name ||= self.class.to_s.demodulize.underscore.gsub("_report", "")
|
106
|
+
end
|
107
|
+
|
108
|
+
private def extract_reporting_period
|
109
|
+
start_date = @search[:start_date]
|
110
|
+
@start_date = start_date.present? ? Date.parse(start_date) : Date.current.beginning_of_year
|
111
|
+
end_date = @search[:end_date]
|
112
|
+
@end_date = (end_date.present? ? Date.parse(end_date).next_day : Date.current.end_of_year)
|
113
|
+
self.reporting_period = (@start_date.beginning_of_day)..(@end_date.end_of_day)
|
114
|
+
end
|
115
|
+
|
116
|
+
private def determine_report_time_scale
|
117
|
+
@time_scale =
|
118
|
+
case (@end_date - @start_date).to_i
|
119
|
+
when 0..1
|
120
|
+
:hourly
|
121
|
+
when 1..60
|
122
|
+
:daily
|
123
|
+
when 61..600
|
124
|
+
:monthly
|
125
|
+
else
|
126
|
+
:yearly
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
class Spree::Report::Configuration
|
2
|
+
attr_accessor :default_report_category, :default_report
|
3
|
+
attr_reader :reports
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@reports = {}
|
7
|
+
end
|
8
|
+
|
9
|
+
def register_report_category(category)
|
10
|
+
@reports[category] = []
|
11
|
+
end
|
12
|
+
|
13
|
+
def register_report(category, report_name)
|
14
|
+
@reports[category] << report_name
|
15
|
+
end
|
16
|
+
|
17
|
+
def report_exists?(category, name)
|
18
|
+
@reports.key?(category) && @reports[category].include?(name)
|
19
|
+
end
|
20
|
+
|
21
|
+
def reports_for_category(category)
|
22
|
+
if category_exists? category
|
23
|
+
@reports[category]
|
24
|
+
else
|
25
|
+
[]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def default_report_category
|
30
|
+
@default_report_category || @reports.keys.first
|
31
|
+
end
|
32
|
+
|
33
|
+
def default_report
|
34
|
+
@default_report || @reports[default_report_category].first
|
35
|
+
end
|
36
|
+
|
37
|
+
def category_exists?(category)
|
38
|
+
@reports.key? category
|
39
|
+
end
|
40
|
+
end
|