spree_dash 0.70.7 → 1.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. data/LICENSE +2 -2
  2. data/README.md +1 -1
  3. data/app/assets/images/analytics_dashboard_preview.png +0 -0
  4. data/app/controllers/spree/admin/overview_controller.rb +15 -0
  5. data/app/controllers/spree/base_controller_decorator.rb +3 -0
  6. data/app/helpers/spree/analytics_helper.rb +69 -0
  7. data/app/models/spree/dash_configuration.rb +11 -0
  8. data/app/overrides/analytics_header.rb +4 -0
  9. data/app/views/spree/admin/overview/_form.html.erb +23 -0
  10. data/app/views/spree/admin/overview/index.html.erb +37 -0
  11. data/app/views/spree/analytics/_header.html.erb +12 -0
  12. data/config/locales/en.yml +1 -0
  13. data/config/routes.rb +2 -2
  14. data/lib/spree/dash.rb +9 -0
  15. data/lib/spree/dash/engine.rb +24 -0
  16. data/lib/spree_dash.rb +1 -7
  17. metadata +33 -32
  18. data/app/assets/javascripts/admin/dashboard.js +0 -144
  19. data/app/assets/javascripts/admin/spree_dash.js +0 -15
  20. data/app/assets/javascripts/store/spree_dash.js +0 -1
  21. data/app/assets/stylesheets/admin/dashboard.css.erb +0 -143
  22. data/app/assets/stylesheets/admin/spree_dash.css +0 -4
  23. data/app/assets/stylesheets/store/spree_dash.css +0 -3
  24. data/app/controllers/admin/overview_controller.rb +0 -152
  25. data/app/views/admin/overview/index.html.erb +0 -164
  26. data/vendor/assets/javascripts/jqPlot/excanvas.min.js +0 -1
  27. data/vendor/assets/javascripts/jqPlot/jquery.jqplot.min.js +0 -14
  28. data/vendor/assets/javascripts/jqPlot/plugins/jqplot.canvasAxisLabelRenderer.min.js +0 -14
  29. data/vendor/assets/javascripts/jqPlot/plugins/jqplot.canvasAxisTickRenderer.min.js +0 -14
  30. data/vendor/assets/javascripts/jqPlot/plugins/jqplot.canvasTextRenderer.min.js +0 -14
  31. data/vendor/assets/javascripts/jqPlot/plugins/jqplot.categoryAxisRenderer.min.js +0 -14
  32. data/vendor/assets/javascripts/jqPlot/plugins/jqplot.dateAxisRenderer.min.js +0 -14
  33. data/vendor/assets/javascripts/jqPlot/plugins/jqplot.highlighter.min.js +0 -14
  34. data/vendor/assets/javascripts/jqPlot/plugins/jqplot.pieRenderer.min.js +0 -14
@@ -1,15 +0,0 @@
1
- // This is a manifest file that'll be compiled into including all the files listed below.
2
- // Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
3
- // be included in the compiled file accessible from http://example.com/assets/application.js
4
- // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
5
- // the compiled file.
6
- //
7
- //= require_tree .
8
- //= require admin/spree_core
9
- //= require jqPlot/jquery.jqplot.min
10
- //= require jqPlot/plugins/jqplot.dateAxisRenderer.min
11
- //= require jqPlot/plugins/jqplot.highlighter.min
12
- //= require jqPlot/plugins/jqplot.canvasAxisTickRenderer.min
13
- //= require jqPlot/plugins/jqplot.canvasTextRenderer.min
14
- //= require jqPlot/plugins/jqplot.canvasAxisLabelRenderer.min
15
- //= require jqPlot/plugins/jqplot.pieRenderer.min
@@ -1 +0,0 @@
1
- //= require store/spree_core
@@ -1,143 +0,0 @@
1
- .dashboard h2{
2
- padding-bottom:5px;
3
- color: #476D9B;
4
- clear:both;
5
- }
6
-
7
- .dashboard_left{
8
- width:25%;
9
- float:left;
10
- }
11
-
12
- .dashboard_main{
13
- width:55%;
14
- float:left;
15
- }
16
-
17
- .dashboard_main #orders_by_day_options{
18
- background-color:#0095DA;
19
- -moz-border-radius-bottomleft:10px;
20
- -moz-border-radius-bottomright:10px;
21
- -moz-border-radius-topleft:10px;
22
- -moz-border-radius-topright:10px;
23
- -webkit-border-bottom-left-radius: 10px 10px;
24
- -webkit-border-bottom-right-radius: 10px 10px;
25
- -webkit-border-top-left-radius: 10px 10px;
26
- -webkit-border-top-right-radius: 10px 10px;
27
- color:#fff;
28
- margin-top:10px;
29
- padding:5px;
30
- text-align:center;
31
- }
32
-
33
- #order_by_day_title{
34
- padding-bottom:5px;
35
- color: #476D9B;
36
- clear:both;
37
- }
38
-
39
- #order_totals{
40
- background:#154E8C url(<%= asset_path("admin/bg/admin_tab_back.png") %>) repeat-x scroll left top;
41
- -moz-border-radius-bottomleft:10px;
42
- -moz-border-radius-bottomright:10px;
43
- -moz-border-radius-topleft:10px;
44
- -moz-border-radius-topright:10px;
45
- -webkit-border-bottom-left-radius: 10px 10px;
46
- -webkit-border-bottom-right-radius: 10px 10px;
47
- -webkit-border-top-left-radius: 10px 10px;
48
- -webkit-border-top-right-radius: 10px 10px;
49
- color:#fff;
50
- height:62px;
51
- padding:0 10px;
52
- margin-bottom:20px;
53
- }
54
-
55
- #order_totals hr{
56
- background-color:#fff;
57
- clear:none;
58
- float:left;
59
- height:80%;
60
- margin-top:6px;
61
- width:3px;
62
- }
63
-
64
- #order_totals .spacer{
65
- padding: 0px 10px;
66
- font-size: 50px;
67
- line-height: 60px;
68
- color: #476D9B;
69
- }
70
-
71
- #order_totals p{
72
- float:left;
73
- font-size:420%;
74
- font-weight:bold;
75
- line-height:60px;
76
- margin:0 5px 0 0;
77
- }
78
-
79
- #order_totals label{
80
- font-size:200%;
81
- line-height:50px;
82
- }
83
-
84
- #order_totals span{
85
- display:block;
86
- font-size:90%;
87
- font-weight:bold;
88
- margin-top: -10px;
89
- }
90
-
91
- .dashboard_main #orders_by_day_options label{
92
- padding: 0px 10px;
93
- }
94
-
95
- .dashboard_right{
96
- width:20%;
97
- float:left;
98
- }
99
-
100
- .dashboard table th{
101
- background-color: #0095DA;
102
- color: #fff;
103
- }
104
-
105
- .dashboard_small_wrapper{
106
- padding: 0px 20px 0px 0px;
107
- }
108
-
109
- .dashboard_main_wrapper{
110
- padding: 0px 30px 10px 30px;
111
- margin-left: auto;
112
- margin-right: auto;
113
- }
114
-
115
- #pie_legend{
116
- width:50%;
117
- float:left;
118
- font-size: 80%;
119
- }
120
-
121
- #pie_legend span{
122
- line-height:15px;
123
- width:15px;
124
- float:left;
125
- }
126
-
127
- #pie_legend label{
128
- margin-left:5px;
129
- float:left;
130
- }
131
-
132
- #pie_legend div{
133
- clear:both;
134
- text-align:right;
135
- }
136
-
137
- .text-right{
138
- text-align:right;
139
- }
140
-
141
- .jqplot-table-legend{
142
- width:60px;
143
- }
@@ -1,4 +0,0 @@
1
- /*
2
- *= require admin/spree_core
3
- *= require admin/dashboard
4
- */
@@ -1,3 +0,0 @@
1
- /*
2
- *= require store/spree_core
3
- */
@@ -1,152 +0,0 @@
1
- # this clas was inspired (heavily) from the mephisto admin architecture
2
-
3
- class Admin::OverviewController < Admin::BaseController
4
- before_filter :check_json_authenticity, :only => :get_report_data
5
- #todo, add rss feed of information that is happening
6
-
7
- def index
8
- @show_dashboard = show_dashboard
9
- return unless @show_dashboard
10
-
11
- p = {:from => (Time.new().to_date - 1.week).to_s(:db), :value => "Count"}
12
- @orders_by_day = orders_by_day(p)
13
- @orders_line_total = orders_line_total(p)
14
- @orders_total = orders_total(p)
15
- @orders_adjustment_total = orders_adjustment_total(p)
16
- @orders_credit_total = orders_credit_total(p)
17
-
18
- @best_selling_variants = best_selling_variants
19
- @top_grossing_variants = top_grossing_variants
20
- @last_five_orders = last_five_orders
21
- @biggest_spenders = biggest_spenders
22
- @out_of_stock_products = out_of_stock_products
23
- @best_selling_taxons = best_selling_taxons
24
-
25
- @pie_colors = [ "#0093DA", "#FF3500", "#92DB00", "#1AB3FF", "#FFB800"]
26
- end
27
-
28
- def get_report_data
29
- opts = case params[:name]
30
- when "7_days" then {:from => (Time.new().to_date - 1.week).to_s(:db)}
31
- when "14_days" then {:from => (Time.new().to_date - 2.week).to_s(:db)}
32
- when "this_month" then {:from => Date.new(Time.now.year, Time.now.month, 1).to_s(:db), :to => Date.new(Time.now.year, Time.now.month, -1).to_s(:db)}
33
- when "last_month" then {:from => (Date.new(Time.now.year, Time.now.month, 1) - 1.month).to_s(:db), :to => (Date.new(Time.now.year, Time.now.month, -1) - 1.month).to_s(:db)}
34
- when "this_year" then {:from => Date.new(Time.now.year, 1, 1).to_s(:db)}
35
- when "last_year" then {:from => Date.new(Time.now.year - 1, 1, 1).to_s(:db), :to => Date.new(Time.now.year - 1, 12, -1).to_s(:db)}
36
- end
37
-
38
- case params[:report]
39
- when "orders_by_day"
40
- opts[:value] = params[:value]
41
-
42
- render :js => "[[" + orders_by_day(opts).map { |day| "['#{day[0]}',#{day[1]}]" }.join(",") + "]]"
43
- when "orders_totals"
44
- render :js => [:orders_total => orders_total(opts).to_i, :orders_line_total => orders_line_total(opts).to_i,
45
- :orders_adjustment_total => orders_adjustment_total(opts).to_i, :orders_credit_total => orders_credit_total(opts).to_i ].to_json
46
- end
47
- end
48
-
49
- private
50
- def show_dashboard
51
- Order.count > 50
52
- end
53
-
54
- def conditions(params)
55
- if params.key? :to
56
- ["completed_at >= ? AND completed_at <= ? AND state <> 'canceled'", params[:from], params[:to]]
57
- else
58
- ["completed_at >= ? AND state <> 'canceled'", params[:from]]
59
- end
60
- end
61
-
62
- def fill_empty_entries(orders, params)
63
- from_date = params[:from].to_date
64
- to_date = (params[:to] || Time.now).to_date
65
- (from_date..to_date).each do |date|
66
- orders[date] ||= []
67
- end
68
- end
69
-
70
- def orders_by_day(params)
71
-
72
- if params[:value] == "Count"
73
- orders = Order.select(:created_at).where(conditions(params))
74
- orders = orders.group_by { |o| o.created_at.to_date }
75
- fill_empty_entries(orders, params)
76
- orders.keys.sort.map {|key| [key.strftime('%Y-%m-%d'), orders[key].size ]}
77
- else
78
- orders = Order.select([:created_at, :total]).where(conditions(params))
79
- orders = orders.group_by { |o| o.created_at.to_date }
80
- fill_empty_entries(orders, params)
81
- orders.keys.sort.map {|key| [key.strftime('%Y-%m-%d'), orders[key].inject(0){|s,o| s += o.total} ]}
82
- end
83
- end
84
-
85
- def orders_line_total(params)
86
- Order.sum(:item_total, :conditions => conditions(params))
87
- end
88
-
89
- def orders_total(params)
90
- Order.sum(:total, :conditions => conditions(params))
91
- end
92
-
93
- def orders_adjustment_total(params)
94
- Order.sum(:adjustment_total, :conditions => conditions(params))
95
- end
96
-
97
- def orders_credit_total(params)
98
- Order.sum(:credit_total, :conditions => conditions(params))
99
- end
100
-
101
- def best_selling_variants
102
- li = LineItem.includes(:order).where("orders.state = 'complete'").sum(:quantity, :group => :variant_id, :order => 'sum(quantity) desc', :limit => 5)
103
- variants = li.map do |v|
104
- variant = Variant.find(v[0])
105
- [variant.name, v[1] ]
106
- end
107
- variants.sort { |x,y| y[1] <=> x[1] }
108
- end
109
-
110
- def top_grossing_variants
111
- prices = LineItem.includes(:order).where("orders.state = 'complete'").sum(:price, :group => :variant_id, :order => 'sum(price) desc', :limit => 5)
112
- variants = prices.map do |v|
113
- variant = Variant.find(v[0])
114
- [variant.name, v[1] * prices[v[0]]]
115
- end
116
-
117
- variants.sort { |x,y| y[1] <=> x[1] }
118
- end
119
-
120
- def best_selling_taxons
121
- taxonomy = Taxonomy.last
122
- taxons = Taxon.connection.select_rows("select t.name, count(li.quantity) from line_items li inner join variants v on
123
- li.variant_id = v.id inner join products p on v.product_id = p.id inner join products_taxons pt on p.id = pt.product_id
124
- inner join taxons t on pt.taxon_id = t.id where t.taxonomy_id = #{taxonomy.id} group by t.name order by count(li.quantity) desc limit 5;")
125
- end
126
-
127
- def last_five_orders
128
- orders = Order.includes(:line_items).where("completed_at IS NOT NULL AND state <> 'canceled'").order("completed_at DESC").limit(5)
129
- orders.map do |o|
130
- qty = o.line_items.inject(0) {|sum,li| sum + li.quantity}
131
-
132
- [o.email, qty, o.total]
133
- end
134
- end
135
-
136
- def biggest_spenders
137
- spenders = Order.sum(:total, :group => :user_id, :limit => 5, :order => "sum(total) desc", :conditions => "completed_at is not null and state <> 'canceled' and user_id is not null")
138
- spenders = spenders.map do |o|
139
- orders = User.find(o[0]).orders
140
- qty = orders.size
141
-
142
- [orders.first.email, qty, o[1]]
143
-
144
- end
145
-
146
- spenders.sort { |x,y| y[2] <=> x[2] }
147
- end
148
-
149
- def out_of_stock_products
150
- Product.where(:count_on_hand => 0).limit(5)
151
- end
152
- end
@@ -1,164 +0,0 @@
1
- <h1><%= t(:overview) %></h1>
2
-
3
- <div data-hook="admin_dashboard">
4
- <% if @show_dashboard %>
5
- <div class="dashboard">
6
- <div class="dashboard_left">
7
- <div data-hook="admin_dashboard_left">
8
- <div class="dashboard_small_wrapper">
9
- <h2><%= t(:best_selling_products) %></h2>
10
- <div id="best_selling_products" style="width:50%; height:170px; float:left;"></div>
11
- <div id="pie_legend">
12
- <% @best_selling_variants.each_with_index do |v,i| %>
13
- <span style="background-color:<%= @pie_colors[i] %>">&nbsp;</span>
14
- <label><%= truncate v[0], :length => 27 %></label>
15
- <div><%= number_with_delimiter v[1] %> <%= t(:units) %></div>
16
- <% end %>
17
- </div>
18
-
19
- <h2><%= t(:top_grossing_products) %></h2>
20
- <div id="top_grossing_products" style="width:50%; height:170px; float:left;"></div>
21
- <div id="pie_legend">
22
- <% @top_grossing_variants.each_with_index do |v,i| %>
23
- <span style="background-color:<%= @pie_colors[i] %>">&nbsp;</span>
24
- <label><%= truncate v[0], :length => 27 %></label>
25
- <div><%= number_to_currency v[1], :precision => 0 %></div>
26
- <% end %>
27
- </div>
28
-
29
- <h2><%= t(:best_selling_taxons) %></h2>
30
- <div id="best_selling_taxons" style="width:50%; height:170px; float:left;"></div>
31
- <div id="pie_legend">
32
- <% @best_selling_taxons.each_with_index do |t,i| %>
33
- <span style="background-color:<%= @pie_colors[i] %>">&nbsp;</span>
34
- <label><%= truncate t[0], :length => 27 %></label>
35
- <div><%= number_with_delimiter t[1] %> <%= t(:units) %></div>
36
- <% end %>
37
- </div>
38
-
39
- </div>
40
- </div>
41
- </div>
42
- <div data-hook="admin_dashboard_center">
43
- <div class="dashboard_main">
44
- <div class="dashboard_main_wrapper">
45
- <h2 id="order_by_day_title"><%= t('orders') %> <%= t('count') %> <%= t('by_day') %> (<%= t('last_7_days') %>)</h2>
46
-
47
- <table id="order_totals">
48
- <tr>
49
- <td style="width:23%;">
50
- <p><%= t("number.currency.format.unit") %></p>
51
- <label id="orders_total"><%= number_with_delimiter @orders_total.to_i %></label>
52
- <span><%= t('order') %> <%= t('total') %></span>
53
- </td>
54
- <td class="spacer">|</td>
55
- <td style="width:23%;">
56
- <p><%= t("number.currency.format.unit") %></p>
57
- <label id="orders_line_total"><%= number_with_delimiter @orders_line_total.to_i %></label>
58
- <span><%= t('item') %> <%= t('total') %></span>
59
- </td>
60
- <td class="spacer">|</td>
61
- <td style="width:23%;">
62
- <p><%= t("number.currency.format.unit") %></p>
63
- <label id="orders_adjustment_total"><%= number_with_delimiter @orders_adjustment_total.to_i %></label>
64
- <span><%= t('adjustments') %></span>
65
- </td>
66
- <td class="spacer">|</td>
67
- <td style="width:22%">
68
- <p><%= t("number.currency.format.unit") %></p>
69
- <label id="orders_adjustment_total"><%= number_with_delimiter @orders_credit_total.to_i %></label>
70
- <span><%= t('credits') %></span>
71
- </td>
72
- </tr>
73
- </table>
74
-
75
- <div id="orders_by_day" style="width:100%;height:240px;"></div>
76
-
77
- <div id="orders_by_day_options">
78
- <label><%= t('range') %>:</label>
79
- <%= select_tag "orders_by_day_reports", options_for_select([[t('last_7_days'), "7_days"], [t('last_14_days'), "14_days"], [t('this_month'), "this_month"],
80
- [t('last_month'), "last_month"], [t('this_year'), "this_year"], [t('last_year'), "last_year"] ], "7_days") %>
81
- <label><%= t('value') %>:</label>
82
- <%= select_tag "orders_by_day_value", options_for_select({t('count') => 'Count', t('value') => 'Value'}, 'Count') %>
83
- </div>
84
- </div>
85
- </div>
86
- </div>
87
- <div data-hook="admin_dashboard_right">
88
- <div class="dashboard_right">
89
- <h2><%= t('last_5_orders') %></h2>
90
- <table>
91
- <thead>
92
- <tr>
93
- <th><%= t('name') %></th>
94
- <th class="text-right"><%= t('items') %></th>
95
- <th class="text-right"><%= t('total') %></th>
96
- </tr>
97
- </thead>
98
- <% @last_five_orders.each do |order| %>
99
- <tr>
100
- <td><%= truncate order[0], :length => 18 %></td>
101
- <td class="text-right"><%= order[1] %></td>
102
- <td class="text-right"><%= number_to_currency order[2] %></td>
103
- </tr>
104
- <% end %>
105
- </table>
106
-
107
- <h2><%= t('5_biggest_spenders') %></h2>
108
- <table>
109
- <thead>
110
- <tr>
111
- <th><%= t('name') %></th>
112
- <th class="text-right"><%= t('ord_qty') %></th>
113
- <th class="text-right"><%= t('ord_total') %></th>
114
- </tr>
115
- </thead>
116
- <% @biggest_spenders.each do |order| %>
117
- <tr>
118
- <td><%= truncate order[0], :length => 18 %></td>
119
- <td class="text-right"><%= order[1] %></td>
120
- <td class="text-right"><%= number_to_currency order[2] %></td>
121
- </tr>
122
- <% end %>
123
- </table>
124
-
125
- <h2><%= t('out_of_stock_products') %></h2>
126
- <table>
127
- <thead>
128
- <tr>
129
- <th><%= t('name') %></th>
130
- </tr>
131
- </thead>
132
- <% @out_of_stock_products.each do |product| %>
133
- <tr>
134
- <td><%= product.name %></td>
135
- </tr>
136
- <% end %>
137
- </table>
138
- </div>
139
- </div>
140
- </div>
141
- <p style="clear:both;">&nbsp;</p>
142
- <% else %>
143
- <div data-hook="admin_dashboard_welcome">
144
- <%== t('overview_welcome') %>
145
- </div>
146
- <% end %>
147
- </div>
148
-
149
- <% content_for :head do %>
150
- <% if @show_dashboard %>
151
- <%= javascript_tag do -%>
152
- var orders_by_day_points = [[<%== @orders_by_day.map { |day| "[\"#{day[0]}\",#{day[1]}]" }.join(",") %>]];
153
- var best_selling_variants_points = [<%== @best_selling_variants.map { |v| "[\"#{h(v[0])}\",#{v[1]}]" }.join(",") %>];
154
- var top_grossing_variants_points = [<%== @top_grossing_variants.map { |v| "[\"#{h(v[0])}\",#{v[1]}]" }.join(",") %>];
155
- var best_selling_taxons_points = [<%== @best_selling_taxons.map { |t| "[\"#{h(t[0])}\",#{t[1]}]" }.join(",") %>];
156
-
157
- var orders = "<%= t(:orders) %>";
158
- var by_day = "<%= t(:by_day) %>";
159
-
160
- var pie_colors = [<%== @pie_colors.map{|c| "'#{c}'"}.join(",") %>];
161
- <% end -%>
162
- <!--[if IE]><%= javascript_include_tag 'jqPlot/excanvas.min.js' %><![endif]-->
163
- <% end %>
164
- <% end %>