rfcommerce_dash 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +35 -0
- data/LICENSE +26 -0
- data/README.md +14 -0
- data/app/controllers/admin/overview_controller.rb +152 -0
- data/app/views/admin/overview/index.html.erb +174 -0
- data/config/routes.rb +4 -0
- data/lib/spree_dash.rb +6 -0
- data/lib/tasks/install.rake +24 -0
- data/public/javascripts/dashboard.js +143 -0
- data/public/javascripts/jqPlot/excanvas.min.js +1 -0
- data/public/javascripts/jqPlot/jquery.jqplot.min.js +14 -0
- data/public/javascripts/jqPlot/plugins/jqplot.canvasAxisLabelRenderer.min.js +14 -0
- data/public/javascripts/jqPlot/plugins/jqplot.canvasAxisTickRenderer.min.js +14 -0
- data/public/javascripts/jqPlot/plugins/jqplot.canvasTextRenderer.min.js +14 -0
- data/public/javascripts/jqPlot/plugins/jqplot.categoryAxisRenderer.min.js +14 -0
- data/public/javascripts/jqPlot/plugins/jqplot.dateAxisRenderer.min.js +14 -0
- data/public/javascripts/jqPlot/plugins/jqplot.highlighter.min.js +14 -0
- data/public/javascripts/jqPlot/plugins/jqplot.pieRenderer.min.js +14 -0
- data/public/stylesheets/admin/dashboard.css +143 -0
- metadata +141 -0
data/Gemfile
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
source 'http://rubygems.org'
|
2
|
+
|
3
|
+
group :test do
|
4
|
+
gem 'rspec-rails', '= 2.5.0'
|
5
|
+
gem 'factory_girl', '= 1.3.3'
|
6
|
+
gem 'factory_girl_rails', '= 1.0.1'
|
7
|
+
gem 'simplecov'
|
8
|
+
gem 'shoulda'
|
9
|
+
gem 'faker'
|
10
|
+
if RUBY_VERSION < "1.9"
|
11
|
+
gem "ruby-debug"
|
12
|
+
else
|
13
|
+
gem "ruby-debug19"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
group :cucumber do
|
18
|
+
gem 'cucumber-rails'
|
19
|
+
gem 'database_cleaner', '= 0.6.7'
|
20
|
+
gem 'nokogiri'
|
21
|
+
gem 'capybara', '= 0.4.1.2'
|
22
|
+
gem 'factory_girl', '= 1.3.3'
|
23
|
+
gem 'factory_girl_rails', '= 1.0.1'
|
24
|
+
gem 'faker'
|
25
|
+
gem 'launchy'
|
26
|
+
|
27
|
+
if RUBY_VERSION < "1.9"
|
28
|
+
gem "ruby-debug"
|
29
|
+
else
|
30
|
+
gem "ruby-debug19"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
gem 'spree_core', :path => '/home/santhosh/Downloads/Skype Downloads/rfcommerce/dash/../core'
|
34
|
+
gem 'spree_dash', :path => '/home/santhosh/Downloads/Skype Downloads/rfcommerce/dash'
|
35
|
+
gem 'sqlite3-ruby'
|
data/LICENSE
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
Copyright (c) 2007-2010, Rails Dog LLC and other contributors
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
Redistribution and use in source and binary forms, with or without modification,
|
5
|
+
are permitted provided that the following conditions are met:
|
6
|
+
|
7
|
+
* Redistributions of source code must retain the above copyright notice,
|
8
|
+
this list of conditions and the following disclaimer.
|
9
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
10
|
+
this list of conditions and the following disclaimer in the documentation
|
11
|
+
and/or other materials provided with the distribution.
|
12
|
+
* Neither the name Spree nor the names of its contributors may be used to
|
13
|
+
endorse or promote products derived from this software without specific
|
14
|
+
prior written permission.
|
15
|
+
|
16
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
17
|
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
18
|
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
19
|
+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
20
|
+
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
21
|
+
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
22
|
+
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
23
|
+
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
24
|
+
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
25
|
+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
26
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
= Overview Dashboard
|
2
|
+
|
3
|
+
Core extension to display basic graphs and charts on store activity. Can be deleted if you don't require the dashboard.
|
4
|
+
|
5
|
+
Running Tests
|
6
|
+
-------------
|
7
|
+
|
8
|
+
You need to do a quick one-time creation of a test application and then you can use it to run the tests.
|
9
|
+
|
10
|
+
rake test_app
|
11
|
+
|
12
|
+
Then run the tests
|
13
|
+
|
14
|
+
rake spec
|
@@ -0,0 +1,152 @@
|
|
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 * quantity", :group => :variant_id, :order => 'sum(price * quantity) desc', :limit => 5)
|
112
|
+
variants = prices.map do |v|
|
113
|
+
variant = Variant.find(v[0])
|
114
|
+
[variant.name, v[1]]
|
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
|
@@ -0,0 +1,174 @@
|
|
1
|
+
<h1><%= t("overview") %></h1>
|
2
|
+
|
3
|
+
<%= hook :admin_dashboard do %>
|
4
|
+
<% if @show_dashboard %>
|
5
|
+
<div class="dashboard">
|
6
|
+
<div class="dashboard_left">
|
7
|
+
<%= hook :admin_dashboard_left do %>
|
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] %>"> </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] %>"> </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] %>"> </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
|
+
<% end %>
|
42
|
+
<%= hook :admin_dashboard_center do %>
|
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
|
+
<% end %>
|
87
|
+
<%= hook :admin_dashboard_right do %>
|
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
|
+
<% end %>
|
141
|
+
<p style="clear:both;"> </p>
|
142
|
+
<% else %>
|
143
|
+
<%= hook :admin_dashboard_welcome do %>
|
144
|
+
<%== t('overview_welcome') %>
|
145
|
+
<% end %>
|
146
|
+
<% end %>
|
147
|
+
<% end %>
|
148
|
+
|
149
|
+
<% content_for :head do %>
|
150
|
+
<%= hook :admin_dashboard_javascript do %>
|
151
|
+
<% if @show_dashboard %>
|
152
|
+
<script type="text/javascript">
|
153
|
+
var orders_by_day_points = [[<%== @orders_by_day.map { |day| "[\"#{day[0]}\",#{day[1]}]" }.join(",") %>]];
|
154
|
+
var best_selling_variants_points = [<%== @best_selling_variants.map { |v| "[\"#{h(v[0])}\",#{v[1]}]" }.join(",") %>];
|
155
|
+
var top_grossing_variants_points = [<%== @top_grossing_variants.map { |v| "[\"#{h(v[0])}\",#{v[1]}]" }.join(",") %>];
|
156
|
+
var best_selling_taxons_points = [<%== @best_selling_taxons.map { |t| "[\"#{h(t[0])}\",#{t[1]}]" }.join(",") %>];
|
157
|
+
|
158
|
+
var orders = "<%= t(:orders) %>";
|
159
|
+
var by_day = "<%= t(:by_day) %>";
|
160
|
+
|
161
|
+
var pie_colors = [<%== @pie_colors.map{|c| "'#{c}'"}.join(",") %>];
|
162
|
+
</script>
|
163
|
+
|
164
|
+
<%= javascript_include_tag 'jqPlot/jquery.jqplot.min.js', 'jqPlot/plugins/jqplot.dateAxisRenderer.min.js', 'jqPlot/plugins/jqplot.highlighter.min.js',
|
165
|
+
'jqPlot/plugins/jqplot.canvasAxisTickRenderer.min.js', 'jqPlot/plugins/jqplot.canvasTextRenderer.min.js', 'jqPlot/plugins/jqplot.canvasAxisLabelRenderer.min.js',
|
166
|
+
'jqPlot/plugins/jqplot.pieRenderer.min.js', 'dashboard.js' %>
|
167
|
+
<!--[if IE]><%= javascript_include_tag 'jqPlot/excanvas.min.js' %><![endif]-->
|
168
|
+
<% end %>
|
169
|
+
<% end %>
|
170
|
+
|
171
|
+
<%= hook :admin_dashboard_stylesheet do %>
|
172
|
+
<%= stylesheet_link_tag 'admin/dashboard.css' %>
|
173
|
+
<% end %>
|
174
|
+
<% end %>
|
data/config/routes.rb
ADDED
data/lib/spree_dash.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
namespace :spree_dash do
|
2
|
+
desc "Copies all migrations and assets (NOTE: This will be obsolete with Rails 3.1)"
|
3
|
+
task :install do
|
4
|
+
Rake::Task['spree_dash:install:migrations'].invoke
|
5
|
+
Rake::Task['spree_dash:install:assets'].invoke
|
6
|
+
end
|
7
|
+
|
8
|
+
namespace :install do
|
9
|
+
|
10
|
+
desc "Copies all migrations (NOTE: This will be obsolete with Rails 3.1)"
|
11
|
+
task :migrations do
|
12
|
+
# no migrations to migrate
|
13
|
+
end
|
14
|
+
|
15
|
+
desc "Copies all assets (NOTE: This will be obsolete with Rails 3.1)"
|
16
|
+
task :assets do
|
17
|
+
source = File.join(File.dirname(__FILE__), '..', '..', 'public')
|
18
|
+
destination = File.join(Rails.root, 'public')
|
19
|
+
puts "INFO: Mirroring assets from #{source} to #{destination}"
|
20
|
+
Spree::FileUtilz.mirror_files(source, destination)
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
jQuery(document).ready(function(){
|
2
|
+
function number_with_delimiter(number, delimiter, separator) {
|
3
|
+
try {
|
4
|
+
var delimiter = delimiter || ",";
|
5
|
+
var separator = separator || ".";
|
6
|
+
|
7
|
+
var parts = number.toString().split('.');
|
8
|
+
parts[0] = parts[0].replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1" + delimiter);
|
9
|
+
formatted_number = parts.join(separator);
|
10
|
+
|
11
|
+
if(formatted_number.length>=6 && formatted_number.length<=9){
|
12
|
+
var arr = formatted_number.split(",");
|
13
|
+
return arr[0] + " k";
|
14
|
+
}else if(formatted_number.length==10){
|
15
|
+
var arr = formatted_number.split(",");
|
16
|
+
return arr[0] + " m";
|
17
|
+
}else{
|
18
|
+
return formatted_number
|
19
|
+
}
|
20
|
+
} catch(e) {
|
21
|
+
return number
|
22
|
+
}
|
23
|
+
}
|
24
|
+
|
25
|
+
function handle_orders_by_day(r){
|
26
|
+
var new_points = eval(r);
|
27
|
+
|
28
|
+
if(new_points[0].length>0){
|
29
|
+
orders_by_day_settings.axes.xaxis.min = new_points[0][0][0].replace(/-/g, "/");
|
30
|
+
orders_by_day_settings.axes.xaxis.max = new_points[0][new_points[0].length -1][0].replace(/-/g, "/");
|
31
|
+
}
|
32
|
+
|
33
|
+
orders_by_day_settings.axes.yaxis.label = jQuery("#orders_by_day_value :selected").val();
|
34
|
+
|
35
|
+
jQuery("#order_by_day_title").text(orders + " " + jQuery("#orders_by_day_value :selected").val() + " " + by_day + " (" + jQuery("#orders_by_day_reports :selected").text() + ")");
|
36
|
+
|
37
|
+
$('#orders_by_day').empty();
|
38
|
+
$.jqplot('orders_by_day', new_points, orders_by_day_settings);
|
39
|
+
|
40
|
+
}
|
41
|
+
|
42
|
+
function handle_orders_total(r){
|
43
|
+
var values = eval(r);
|
44
|
+
|
45
|
+
jQuery('#orders_total').text(number_with_delimiter(values[0].orders_total));
|
46
|
+
jQuery('#orders_line_total').text(number_with_delimiter(values[0].orders_line_total));
|
47
|
+
jQuery('#orders_adjustment_total').text(number_with_delimiter(values[0].orders_adjustment_total));
|
48
|
+
jQuery('#orders_adjustment_total').text(number_with_delimiter(values[0].orders_adjustment_total));
|
49
|
+
}
|
50
|
+
|
51
|
+
var orders_by_day_settings = {
|
52
|
+
title: {
|
53
|
+
textColor: '#476D9B',
|
54
|
+
fontSize: '12pt',
|
55
|
+
},
|
56
|
+
grid: {background:'#fff', gridLineColor:'#fff',borderColor: '#476D9B'},
|
57
|
+
axes:{
|
58
|
+
yaxis:{
|
59
|
+
label:'Order (Count)',
|
60
|
+
labelRenderer: $.jqplot.CanvasAxisLabelRenderer,
|
61
|
+
autoscale:true,
|
62
|
+
tickOptions:{
|
63
|
+
formatString:'%d',
|
64
|
+
fontSize: '10pt',
|
65
|
+
textColor: '#476D9B'
|
66
|
+
},
|
67
|
+
min: 0
|
68
|
+
},
|
69
|
+
xaxis:{
|
70
|
+
renderer:$.jqplot.DateAxisRenderer,
|
71
|
+
rendererOptions:{tickRenderer:$.jqplot.CanvasAxisTickRenderer},
|
72
|
+
tickOptions:{
|
73
|
+
formatString:'%b %#d, %y',
|
74
|
+
angle: -30,
|
75
|
+
fontSize: '10pt',
|
76
|
+
textColor: '#476D9B'
|
77
|
+
},
|
78
|
+
min: orders_by_day_points[0][0][0].replace(/-/g, "/"),
|
79
|
+
max: orders_by_day_points[0][orders_by_day_points[0].length -1][0].replace(/-/g, "/")//,
|
80
|
+
//tickInterval: '1 day'
|
81
|
+
}
|
82
|
+
},
|
83
|
+
series:[{lineWidth:3, color: '#0095DA', fillAndStroke: true, fill: true, fillColor: '#E6F7FF'}],
|
84
|
+
highlighter: {
|
85
|
+
formatString: "Date: %s <br/>Value: %s ",
|
86
|
+
sizeAdjust: 7.5
|
87
|
+
}
|
88
|
+
};
|
89
|
+
|
90
|
+
jQuery.jqplot('orders_by_day', orders_by_day_points, orders_by_day_settings);
|
91
|
+
|
92
|
+
jQuery("div#orders_by_day_options select").change(function(){
|
93
|
+
var report = jQuery("#orders_by_day_reports :selected").val();
|
94
|
+
var value = jQuery("#orders_by_day_value :selected").val();
|
95
|
+
|
96
|
+
jQuery.ajax({
|
97
|
+
type: 'GET',
|
98
|
+
url: 'admin/overview/get_report_data',
|
99
|
+
data: ({report: 'orders_by_day', name: report, value: value, authenticity_token: AUTH_TOKEN}),
|
100
|
+
success: handle_orders_by_day
|
101
|
+
});
|
102
|
+
|
103
|
+
jQuery.ajax({
|
104
|
+
type: 'GET',
|
105
|
+
url: 'admin/overview/get_report_data',
|
106
|
+
data: ({report: 'orders_totals', name: report, authenticity_token: AUTH_TOKEN}),
|
107
|
+
success: handle_orders_total
|
108
|
+
});
|
109
|
+
|
110
|
+
});
|
111
|
+
|
112
|
+
best_selling_variants = $.jqplot('best_selling_products', [best_selling_variants_points], {
|
113
|
+
grid: {background:'#fff',borderWidth: 0, borderColor: '#fff', shadow: false},
|
114
|
+
seriesDefaults:{
|
115
|
+
renderer:$.jqplot.PieRenderer,
|
116
|
+
rendererOptions:{padding:6,sliceMargin:0}
|
117
|
+
},
|
118
|
+
seriesColors: pie_colors
|
119
|
+
});
|
120
|
+
|
121
|
+
|
122
|
+
top_grossing_variants = $.jqplot('top_grossing_products', [top_grossing_variants_points], {
|
123
|
+
grid: {background:'#fff',borderWidth: 0, borderColor: '#fff', shadow: false},
|
124
|
+
seriesDefaults:{
|
125
|
+
renderer:$.jqplot.PieRenderer,
|
126
|
+
rendererOptions:{padding:6,sliceMargin:0}
|
127
|
+
},
|
128
|
+
|
129
|
+
seriesColors: pie_colors
|
130
|
+
});
|
131
|
+
|
132
|
+
tbest_selling_taxons = $.jqplot('best_selling_taxons', [best_selling_taxons_points], {
|
133
|
+
grid: {background:'#fff',borderWidth: 0, borderColor: '#fff', shadow: false},
|
134
|
+
seriesDefaults:{
|
135
|
+
renderer:$.jqplot.PieRenderer,
|
136
|
+
rendererOptions:{padding:6,sliceMargin:0}
|
137
|
+
},
|
138
|
+
|
139
|
+
seriesColors: pie_colors
|
140
|
+
});
|
141
|
+
|
142
|
+
|
143
|
+
});
|