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 CHANGED
@@ -1,4 +1,4 @@
1
- [Query report](http://ashrafuzzaman.github.io/query_report/) By [Ashrafuzzaman](http://www.ashrafuzzaman.com).
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.3"
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://www.ashrafuzzaman.com). See MIT-LICENSE for further details.
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>
@@ -1,2 +1,3 @@
1
1
  <%= link_to_download_report_pdf %>
2
- <%= link_to_download_report_csv %>
2
+ <%= link_to_download_report_csv %>
3
+ <%= link_to_email_query_report(@target_dom_id) %>
@@ -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>
@@ -0,0 +1,9 @@
1
+ <% if report.has_total? %>
2
+ <tfoot>
3
+ <tr>
4
+ <% report.column_total_with_colspan.each do |total_with_colspan| %>
5
+ <td colspan="<%= total_with_colspan[:colspan] %>"><%= total_with_colspan[:content] %></td>
6
+ <% end %>
7
+ </tr>
8
+ </tfoot>
9
+ <% end %>
@@ -1,8 +1,8 @@
1
1
  <% if report.records.size > 0 %>
2
- <table class="table table-bordered table-striped">
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
- <% if report.has_filter? %>
2
- <%= search_form_for report.search, :url => url_for, :html => {:method => :get, :class => 'form-inline'} do |f| %>
3
- <% report.filters.each do |filter| %>
4
- <% filter.comparators.each do |comparator| %>
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/search", locals: {report: @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 %>
@@ -4,4 +4,6 @@ en:
4
4
  query_report:
5
5
  filters:
6
6
  from: 'From'
7
- to: 'To'
7
+ to: 'To'
8
+ total:
9
+ Total
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: 12,
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: 12}
21
+ header: {bg_color: 'AAAAAA', font_size: 8}
22
22
  },
23
23
  chart: { height: 160, width: 200 }
24
24
  }
25
- config.date_format = :default
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
@@ -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
@@ -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
@@ -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 { render 'query_report/list' }
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 query_report_pdf_template_class(options).new(@report).to_pdf.render }
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
@@ -38,6 +38,10 @@ module QueryReport
38
38
  !@charts.empty?
39
39
  end
40
40
 
41
+ def has_total?
42
+ @columns.any?(&:has_total?)
43
+ end
44
+
41
45
  # to support the helper methods
42
46
  def method_missing(meth, *args, &block)
43
47
  if @template.respond_to?(meth)
@@ -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
- height = options[:chart][:height] * (report.charts.size.to_f/2).ceil
30
- pdf.column_box([0, pdf.cursor], :columns => 2, :width => pdf.bounds.width, :height => height) do
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
- pdf.image(data, :width => options[:chart][:width])
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)
@@ -1,3 +1,3 @@
1
1
  module QueryReport
2
- VERSION = "1.0.4"
2
+ VERSION = "1.0.5"
3
3
  end
@@ -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
- #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
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