query_report 1.0.4 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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