query_report 1.0.4 → 1.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +4 -3
- data/app/helpers/query_report_link_helper.rb +4 -0
- data/app/mailers/report_mailer.rb +10 -0
- data/app/views/query_report/_content.html.erb +9 -0
- data/app/views/query_report/_links.html.erb +2 -1
- data/app/views/query_report/_list.html.erb +15 -0
- data/app/views/query_report/_record_footer.html.erb +9 -0
- data/app/views/query_report/_records.html.erb +3 -2
- data/app/views/query_report/_search.html.erb +10 -7
- data/app/views/query_report/list.html.erb +1 -14
- data/app/views/query_report/list.js.erb +9 -0
- data/app/views/report_mailer/send_report.html.erb +1 -0
- data/config/locales/query_report.yml +3 -1
- data/lib/query_report.rb +7 -3
- data/lib/query_report/column.rb +36 -0
- data/lib/query_report/comparator.rb +2 -2
- data/lib/query_report/config.rb +4 -0
- data/lib/query_report/helper.rb +20 -2
- data/lib/query_report/report.rb +4 -0
- data/lib/query_report/report_pdf.rb +14 -6
- data/lib/query_report/version.rb +1 -1
- data/test/dummy/app/controllers/invoices_controller.rb +19 -19
- data/test/dummy/db/development.sqlite3 +0 -0
- data/test/dummy/db/schema.rb +2 -2
- data/test/dummy/db/seed.rb +0 -1
- data/test/dummy/log/development.log +4357 -0
- data/test/dummy/log/test.log +148 -0
- data/test/functional/report_mailer_test.rb +7 -0
- metadata +14 -6
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
[Query report](http://ashrafuzzaman.github.io/query_report/) By [Ashrafuzzaman](http://
|
1
|
+
[Query report](http://ashrafuzzaman.github.io/query_report/) By [Ashrafuzzaman](http://ashrafuzzaman.github.io/site).
|
2
2
|
|
3
3
|
[![Build Status](https://api.travis-ci.org/ashrafuzzaman/query_report.png?branch=master)](http://travis-ci.org/ashrafuzzaman/query_report)
|
4
4
|
|
@@ -9,6 +9,7 @@ Query report is a reporting tool, which does the following:
|
|
9
9
|
* Provide feature to define re usable custom filter
|
10
10
|
|
11
11
|
As built in filter I have used [ransack](https://github.com/ernie/ransack) and pagination with [kaminari](https://github.com/amatsuda/kaminari)
|
12
|
+
|
12
13
|
For a demo see [here](http://query-report-demo.herokuapp.com)
|
13
14
|
|
14
15
|
## The purpose
|
@@ -19,7 +20,7 @@ concentrate in a report is the query and filter.
|
|
19
20
|
Query report is tested with Rails 3. You can add it to your Gemfile with:
|
20
21
|
|
21
22
|
```ruby
|
22
|
-
gem "query_report", "~> 1.0.
|
23
|
+
gem "query_report", "~> 1.0.4"
|
23
24
|
```
|
24
25
|
|
25
26
|
Run the bundle command to install it.
|
@@ -53,4 +54,4 @@ end
|
|
53
54
|
```
|
54
55
|
|
55
56
|
## License
|
56
|
-
MIT License. Copyright © 2013 [Ashrafuzzaman](http://
|
57
|
+
MIT License. Copyright © 2013 [Ashrafuzzaman](http://ashrafuzzaman.github.io/site). See MIT-LICENSE for further details.
|
@@ -6,4 +6,8 @@ module QueryReportLinkHelper
|
|
6
6
|
def link_to_download_report_csv
|
7
7
|
link_to t('views.links.csv'), export_report_url_with_format('csv'), :target => "_blank"
|
8
8
|
end
|
9
|
+
|
10
|
+
def link_to_email_query_report(target_dom_id)
|
11
|
+
link_to t('views.labels.email'), 'javascript:void(0)', :onclick => "QueryReportEmail.openEmailModal('#{target_dom_id}');" if QueryReport.config.allow_email_report
|
12
|
+
end
|
9
13
|
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
class ReportMailer < ActionMailer::Base
|
2
|
+
default from: QueryReport.config.email_from
|
3
|
+
|
4
|
+
def send_report(user, to, subject, message, file_name, attachment)
|
5
|
+
@user = user
|
6
|
+
@message = message
|
7
|
+
attachments["#{file_name}.pdf"] = attachment
|
8
|
+
mail(:to => to, :subject => subject)
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
<div class="query_report_charts">
|
2
|
+
<%= render :partial => "query_report/charts", locals: {report: report} %>
|
3
|
+
</div>
|
4
|
+
<div class="query_report_records">
|
5
|
+
<%= render :partial => "query_report/records", locals: {report: report} %>
|
6
|
+
</div>
|
7
|
+
<div class="query_report_pagination">
|
8
|
+
<%= paginate report.paginated_query, remote: @remote if report.paginate? %>
|
9
|
+
</div>
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<% uuid = Time.now.to_i
|
2
|
+
@target_dom_id = params[:target_dom_id] || "report_#{uuid}" %>
|
3
|
+
<div class="query_report" id="<%= @target_dom_id %>">
|
4
|
+
<div class="query_report_header">
|
5
|
+
<div class="query_report_search_form" style="<%= report.has_filter? ? '' : 'display: none;' %>">
|
6
|
+
<%= render :partial => "query_report/search", locals: {report: report} %>
|
7
|
+
</div>
|
8
|
+
<div class="query_report_links">
|
9
|
+
<%= render :partial => "query_report/links", locals: {report: report} %>
|
10
|
+
</div>
|
11
|
+
</div>
|
12
|
+
<div class="query_report_content">
|
13
|
+
<%= render :partial => "query_report/content", locals: {report: report} %>
|
14
|
+
</div>
|
15
|
+
</div>
|
@@ -1,8 +1,8 @@
|
|
1
1
|
<% if report.records.size > 0 %>
|
2
|
-
<table class="
|
2
|
+
<table class="<%= QueryReport.config.record_table_class %>" cellpadding="0" cellspacing="0">
|
3
3
|
<thead>
|
4
4
|
<% report.columns.each do |column| %>
|
5
|
-
<th><%= sort_link(report.search, column.name) %></th>
|
5
|
+
<th><%= column.sortable? ? sort_link(report.search, column.name, {}, remote: @remote) : column.name %></th>
|
6
6
|
<% end %>
|
7
7
|
</thead>
|
8
8
|
|
@@ -14,6 +14,7 @@
|
|
14
14
|
<% end %>
|
15
15
|
</tr>
|
16
16
|
<% end %>
|
17
|
+
<%= render :partial => "query_report/record_footer", locals: {report: report} %>
|
17
18
|
</tbody>
|
18
19
|
</table>
|
19
20
|
<% else %>
|
@@ -1,10 +1,13 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
<%
|
4
|
-
|
5
|
-
<%= query_report_render_filter(filter, comparator) %>
|
6
|
-
<% end %>
|
1
|
+
<%= search_form_for report.search, url: url_for, remote: @remote, html: {:method => :get, :class => 'form-inline'} do |f| %>
|
2
|
+
<% report.filters.each do |filter| %>
|
3
|
+
<% filter.comparators.each do |comparator| %>
|
4
|
+
<%= query_report_render_filter(filter, comparator) %>
|
7
5
|
<% end %>
|
8
|
-
<%= f.submit 'Search', :class => 'btn btn-blue' %>
|
9
6
|
<% end %>
|
7
|
+
<%= hidden_field_tag :send_as_email, false %>
|
8
|
+
<%= hidden_field_tag :email_to %>
|
9
|
+
<%= hidden_field_tag :subject %>
|
10
|
+
<%= hidden_field_tag :message %>
|
11
|
+
<%= hidden_field_tag :target_dom_id, @target_dom_id %>
|
12
|
+
<%= f.submit 'Search', :class => QueryReport.config.search_button_class, :onclick => "$('#{@target_dom_id} #send_as_email').val(0);" %>
|
10
13
|
<% end %>
|
@@ -1,14 +1 @@
|
|
1
|
-
<%= render :partial => "query_report/
|
2
|
-
<br/>
|
3
|
-
<%= render :partial => "query_report/links", locals: {report: @report} %>
|
4
|
-
<%= render :partial => "query_report/charts", locals: {report: @report} %>
|
5
|
-
<br/>
|
6
|
-
<%# if @report.scopes.size > 0 %>
|
7
|
-
<%#= link_to_with_scope('all', @report.current_scope) %>
|
8
|
-
<%# @report.scopes.each do |scope| %>
|
9
|
-
<%#= link_to_with_scope(scope, @report.current_scope) %>
|
10
|
-
<%# end %>
|
11
|
-
<%# end %>
|
12
|
-
|
13
|
-
<%= render :partial => "query_report/records", locals: {report: @report} %>
|
14
|
-
<%= paginate @report.paginated_query if @report.paginate? %>
|
1
|
+
<%= render :partial => "query_report/_list", locals: {report: @report} %>
|
@@ -0,0 +1,9 @@
|
|
1
|
+
<%if params['target_dom_id'].present?%>
|
2
|
+
if ($('#<%=params['target_dom_id']%> .query_report_content').length == 0) {
|
3
|
+
$('#<%=params['target_dom_id']%>').html('<%= escape_javascript(render :partial => 'query_report/list', locals: {report: @report})%>');
|
4
|
+
} else {
|
5
|
+
$('#<%=params['target_dom_id']%> .query_report_content').html('<%= escape_javascript(render :partial => 'query_report/content', locals: {report: @report})%>');
|
6
|
+
}
|
7
|
+
<% else %>
|
8
|
+
console.log("target_dom_id was not defined");
|
9
|
+
<% end %>
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= @message.gsub(/\n/, '<br />').html_safe %>
|
data/lib/query_report.rb
CHANGED
@@ -15,14 +15,18 @@ module QueryReport
|
|
15
15
|
config.pdf_options = {
|
16
16
|
template_class: nil,
|
17
17
|
color: '000000',
|
18
|
-
font_size:
|
18
|
+
font_size: 8,
|
19
19
|
table: {
|
20
20
|
row: {odd_bg_color: "DDDDDD", even_bg_color: "FFFFFF"},
|
21
|
-
header: {bg_color: 'AAAAAA', font_size:
|
21
|
+
header: {bg_color: 'AAAAAA', font_size: 8}
|
22
22
|
},
|
23
23
|
chart: { height: 160, width: 200 }
|
24
24
|
}
|
25
|
-
config.date_format
|
25
|
+
config.date_format = :default
|
26
26
|
config.datetime_format = :default
|
27
|
+
config.email_from = "from@example.com"
|
28
|
+
config.allow_email_report = true
|
29
|
+
config.record_table_class = 'table table-bordered table-striped'
|
30
|
+
config.search_button_class = 'btn btn-blue'
|
27
31
|
end
|
28
32
|
end
|
data/lib/query_report/column.rb
CHANGED
@@ -13,11 +13,35 @@ module QueryReport
|
|
13
13
|
# +options+:: Options can have the following,
|
14
14
|
# options[:type] => date | text | whatever
|
15
15
|
# options[:comp] => the comparators used for ransack search, [:gteq, :lteq]
|
16
|
+
# options[:show_total] => set true to calculate total for that column
|
16
17
|
# options[:only_on_web] => the column will appear on the web and not appear in PDF or csv if set to true
|
17
18
|
def column(name, options={}, &block)
|
18
19
|
@columns << Column.new(self, name, options, block)
|
19
20
|
end
|
20
21
|
|
22
|
+
def column_total_with_colspan
|
23
|
+
total_with_colspan = []
|
24
|
+
colspan = 0
|
25
|
+
total_text_printed = false
|
26
|
+
columns.each do |column|
|
27
|
+
if column.has_total?
|
28
|
+
if colspan > 0
|
29
|
+
title = total_text_printed ? '' : I18n.t('query_report.total')
|
30
|
+
total_with_colspan << (colspan == 1 ? {content: title} : {content: title, colspan: colspan})
|
31
|
+
end
|
32
|
+
total_with_colspan << {content: column.total}
|
33
|
+
total_text_printed = true
|
34
|
+
colspan = 0
|
35
|
+
else
|
36
|
+
colspan += 1
|
37
|
+
end
|
38
|
+
end
|
39
|
+
if colspan > 0
|
40
|
+
total_with_colspan << {content: '', colspan: colspan}
|
41
|
+
end
|
42
|
+
total_with_colspan
|
43
|
+
end
|
44
|
+
|
21
45
|
class Column
|
22
46
|
attr_reader :report, :name, :options, :type, :data
|
23
47
|
|
@@ -31,6 +55,10 @@ module QueryReport
|
|
31
55
|
@options[:only_on_web] == true
|
32
56
|
end
|
33
57
|
|
58
|
+
def sortable?
|
59
|
+
@options[:sortable] == true
|
60
|
+
end
|
61
|
+
|
34
62
|
def humanize
|
35
63
|
@humanize ||= options[:as] || @report.model_class.human_attribute_name(name)
|
36
64
|
end
|
@@ -38,6 +66,14 @@ module QueryReport
|
|
38
66
|
def value(record)
|
39
67
|
self.data.kind_of?(Symbol) ? record.send(self.name) : self.data.call(record)
|
40
68
|
end
|
69
|
+
|
70
|
+
def has_total?
|
71
|
+
@options[:show_total] == true
|
72
|
+
end
|
73
|
+
|
74
|
+
def total
|
75
|
+
@total ||= has_total? ? report.records.inject(0) {|sum, r| sum + r[humanize] } : nil
|
76
|
+
end
|
41
77
|
end
|
42
78
|
end
|
43
79
|
end
|
@@ -41,9 +41,9 @@ module QueryReport
|
|
41
41
|
def objectified_param_value
|
42
42
|
@stringified_default ||= case @filter.type
|
43
43
|
when :date
|
44
|
-
Date.current.parse(@default)
|
44
|
+
@default.kind_of?(String) ? Date.current.parse(@default) : @default
|
45
45
|
when :datetime
|
46
|
-
Time.zone.parse(@default)
|
46
|
+
@default.kind_of?(String) ? Time.zone.parse(@default) : @default
|
47
47
|
when :boolean
|
48
48
|
@default.to_boolean
|
49
49
|
else
|
data/lib/query_report/config.rb
CHANGED
@@ -4,5 +4,9 @@ module QueryReport
|
|
4
4
|
config_accessor :pdf_options
|
5
5
|
config_accessor :date_format
|
6
6
|
config_accessor :datetime_format
|
7
|
+
config_accessor :email_from
|
8
|
+
config_accessor :allow_email_report
|
9
|
+
config_accessor :record_table_class
|
10
|
+
config_accessor :search_button_class
|
7
11
|
end
|
8
12
|
end
|
data/lib/query_report/helper.rb
CHANGED
@@ -17,15 +17,27 @@ module QueryReport
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def render_report(options)
|
20
|
+
if (params[:send_as_email].to_i > 0)
|
21
|
+
send_pdf_email(params[:email_to], params[:subject], params[:message], action_name, pdf_for_report(options))
|
22
|
+
end
|
23
|
+
|
24
|
+
@remote = false
|
20
25
|
respond_to do |format|
|
21
|
-
format.js
|
26
|
+
format.js do
|
27
|
+
@remote = true
|
28
|
+
render 'query_report/list'
|
29
|
+
end
|
22
30
|
format.html { render 'query_report/list' }
|
23
31
|
format.json { render json: @report.all_records }
|
24
32
|
format.csv { send_data generate_csv_for_report(@report.all_records), :disposition => "attachment;" }
|
25
|
-
format.pdf { send_data
|
33
|
+
format.pdf { send_data pdf_for_report(options) }
|
26
34
|
end
|
27
35
|
end
|
28
36
|
|
37
|
+
def pdf_for_report(options)
|
38
|
+
query_report_pdf_template_class(options).new(@report).to_pdf.render
|
39
|
+
end
|
40
|
+
|
29
41
|
def query_report_pdf_template_class(options)
|
30
42
|
options = QueryReport.config.pdf_options.merge(options)
|
31
43
|
if options[:template_class]
|
@@ -48,5 +60,11 @@ module QueryReport
|
|
48
60
|
nil
|
49
61
|
end
|
50
62
|
end
|
63
|
+
|
64
|
+
def send_pdf_email(email, subject, message, file_name, attachment)
|
65
|
+
@user = current_user
|
66
|
+
to = email.split(',')
|
67
|
+
ReportMailer.send_report(@user, to, subject, message, file_name, attachment).deliver
|
68
|
+
end
|
51
69
|
end
|
52
70
|
end
|
data/lib/query_report/report.rb
CHANGED
@@ -26,8 +26,9 @@ module QueryReport
|
|
26
26
|
private
|
27
27
|
def render_charts_with(report)
|
28
28
|
return if report.charts.empty? #or !report.chart_on_pdf?
|
29
|
-
|
30
|
-
|
29
|
+
num_of_column = 2
|
30
|
+
height = (pdf.bounds.width/num_of_column - 50) * (report.charts.size.to_f/num_of_column).ceil
|
31
|
+
pdf.column_box([0, pdf.cursor], :columns => num_of_column, :width => pdf.bounds.width, :height => height) do
|
31
32
|
report.charts.each do |chart|
|
32
33
|
render_chart(chart)
|
33
34
|
end
|
@@ -38,9 +39,9 @@ module QueryReport
|
|
38
39
|
if chart.respond_to?(:to_blob)
|
39
40
|
blob = chart.to_blob
|
40
41
|
data = StringIO.new(blob)
|
41
|
-
pdf.pad_top(10) do
|
42
|
-
|
43
|
-
end
|
42
|
+
#pdf.pad_top(10) do
|
43
|
+
pdf.image(data, :width => pdf.bounds.width)
|
44
|
+
#end
|
44
45
|
end
|
45
46
|
end
|
46
47
|
|
@@ -54,7 +55,7 @@ module QueryReport
|
|
54
55
|
|
55
56
|
def table_content_for(report)
|
56
57
|
table_items = report.all_records
|
57
|
-
table_items.map do |item|
|
58
|
+
items = table_items.map do |item|
|
58
59
|
item_values = []
|
59
60
|
|
60
61
|
report_columns.collect(&:humanize).each do |column|
|
@@ -62,6 +63,13 @@ module QueryReport
|
|
62
63
|
end
|
63
64
|
item_values
|
64
65
|
end
|
66
|
+
|
67
|
+
if report.has_total?
|
68
|
+
items = items << report.column_total_with_colspan.collect do |total|
|
69
|
+
total[:colspan] ? total : total[:content]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
items
|
65
73
|
end
|
66
74
|
|
67
75
|
def render_table_with(report)
|
data/lib/query_report/version.rb
CHANGED
@@ -15,28 +15,28 @@ class InvoicesController < ApplicationController
|
|
15
15
|
column :title do |invoice|
|
16
16
|
link_to invoice.title, invoice
|
17
17
|
end
|
18
|
-
column :total_paid
|
19
|
-
column :total_charged
|
18
|
+
column :total_paid, show_total: true
|
19
|
+
column :total_charged, show_total: true
|
20
20
|
column :paid
|
21
21
|
column :received_by
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
23
|
+
column_chart('Unpaid VS Paid') do
|
24
|
+
add 'Unpaid' do |query|
|
25
|
+
(query.sum('total_charged').to_f - query.sum('total_paid').to_f).to_f
|
26
|
+
end
|
27
|
+
add 'Paid' do |query|
|
28
|
+
query.sum('total_paid').to_f
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
pie_chart('Unpaid VS Paid') do
|
33
|
+
add 'Unpaid' do |query|
|
34
|
+
(query.sum('total_charged').to_f - query.sum('total_paid').to_f).to_f
|
35
|
+
end
|
36
|
+
add 'Paid' do |query|
|
37
|
+
query.sum('total_paid').to_f
|
38
|
+
end
|
39
|
+
end
|
40
40
|
end
|
41
41
|
#ap @report.filters.last.comparators.first.default
|
42
42
|
#ap @report.filters.last.comparators.first.param_value
|
Binary file
|