prawn_report 1.9.18
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.
- checksums.yaml +7 -0
- data/app/controllers/ac_filter_defs_controller.rb +17 -0
- data/app/controllers/custom_generate_report_controller.rb +18 -0
- data/app/controllers/generate_report_controller.rb +24 -0
- data/app/controllers/report_templates_controller.rb +40 -0
- data/app/models/ac_filter.rb +15 -0
- data/app/models/ac_filter_def.rb +38 -0
- data/app/models/ac_filter_option.rb +5 -0
- data/app/models/report_template.rb +22 -0
- data/lib/ac_filters_utils.rb +187 -0
- data/lib/active_record_helpers.rb +218 -0
- data/lib/bands/band.rb +23 -0
- data/lib/bands/footer_band.rb +7 -0
- data/lib/bands/header_band.rb +9 -0
- data/lib/bands/summary_band.rb +7 -0
- data/lib/custom_report_controller.rb +48 -0
- data/lib/generators/prawn_report/install/install_generator.rb +16 -0
- data/lib/generators/prawn_report/install/templates/20120108210141_create_prawn_report_catalogs.rb +14 -0
- data/lib/generators/prawn_report/install/templates/20120124012653_add_filter_defs.rb +35 -0
- data/lib/generators/prawn_report/install/templates/20120209231821_add_filters_to_reports.rb +13 -0
- data/lib/generators/prawn_report/install/templates/20120222021437_add_order_to_filter_def.rb +9 -0
- data/lib/generators/prawn_report/install/templates/20120222025632_add_select_sql.rb +9 -0
- data/lib/generators/prawn_report/install/templates/20120222030526_create_ac_filter_joins.rb +12 -0
- data/lib/generators/prawn_report/install/templates/20120222122507_add_serialization_params_to_report.rb +9 -0
- data/lib/generators/prawn_report/install/templates/20120222134101_create_ac_filter_includes.rb +12 -0
- data/lib/generators/prawn_report/install/templates/20120222150029_change_includes_and_joins_to_hash.rb +21 -0
- data/lib/generators/prawn_report/install/templates/20120229134810_add_group_to_filter_def.rb +9 -0
- data/lib/generators/prawn_report/install/templates/20120229194434_add_system_criteria_to_ac_filter.rb +9 -0
- data/lib/generators/prawn_report/install/templates/20120301063031_change_select_sql.rb +11 -0
- data/lib/generators/prawn_report/install/templates/20120303104431_change_filled_criteria_unfilled_criteria.rb +15 -0
- data/lib/generators/prawn_report/install/templates/20120316162712_add_filled_criteria_to_options.rb +9 -0
- data/lib/generators/prawn_report/install/templates/20120323124446_add_fields_to_filter.rb +17 -0
- data/lib/generators/prawn_report/install/templates/20130122101313_add_sql_query_to_ac_filter_def.rb +5 -0
- data/lib/generators/prawn_report/install/templates/20131107172133_add_excluir_to_report_template.rb +9 -0
- data/lib/prawn_report.rb +21 -0
- data/lib/prawn_report/engine.rb +9 -0
- data/lib/prawn_report/version.rb +3 -0
- data/lib/prawn_report_seeds.rb +46 -0
- data/lib/report.rb +190 -0
- data/lib/report_helpers.rb +82 -0
- data/lib/report_info.rb +27 -0
- data/repo/bands/footers/footer_001.rb +20 -0
- data/repo/bands/headers/header_001.rb +61 -0
- data/repo/bands/headers/header_002.rb +31 -0
- data/repo/reports/column_group.rb +58 -0
- data/repo/reports/listing.rb +144 -0
- data/repo/reports/simple_listing.rb +130 -0
- metadata +93 -0
data/lib/report.rb
ADDED
@@ -0,0 +1,190 @@
|
|
1
|
+
#coding: utf-8
|
2
|
+
|
3
|
+
require 'prawn'
|
4
|
+
|
5
|
+
require File.expand_path(File.dirname(__FILE__) + "/report_helpers")
|
6
|
+
require File.expand_path(File.dirname(__FILE__) + "/report_info")
|
7
|
+
|
8
|
+
# This is the module for all classes in the prawn_report gem
|
9
|
+
module PrawnReport
|
10
|
+
unless defined? DEFAULT_REPORT_PARAMS
|
11
|
+
DEFAULT_REPORT_PARAMS = {:page_size => 'A4', :margin => [20, 20, 20, 20],
|
12
|
+
:page_layout => :portrait}
|
13
|
+
|
14
|
+
LABEL_SIZE = 6
|
15
|
+
TEXT_SIZE = 10
|
16
|
+
|
17
|
+
SECTION_SPACING = LABEL_SIZE + 4
|
18
|
+
|
19
|
+
LINE_WIDTH = 0.3
|
20
|
+
|
21
|
+
DEFAULT_FONT = 'Times-Roman'
|
22
|
+
|
23
|
+
TEXT_BOX_RADIUS = 2
|
24
|
+
TEXT_BOX_HEIGTH = 20
|
25
|
+
end
|
26
|
+
|
27
|
+
# Report is the base class for all reports, it encapsulates all logic for rendering
|
28
|
+
# report parts.
|
29
|
+
class Report
|
30
|
+
attr_reader :pdf, :data, :max_width, :max_height, :totals, :group_totals
|
31
|
+
attr_accessor :header_class, :header_other_pages_class, :x, :report_params,
|
32
|
+
:running_totals
|
33
|
+
|
34
|
+
def initialize(report_params)
|
35
|
+
@report_params = DEFAULT_REPORT_PARAMS.merge(report_params || {})
|
36
|
+
@running_totals = @report_params.delete(:running_totals) || []
|
37
|
+
@num_pages = 1
|
38
|
+
|
39
|
+
@pdf = Prawn::Document.new(@report_params)
|
40
|
+
|
41
|
+
@pdf.font(DEFAULT_FONT)
|
42
|
+
@pdf.line_width = LINE_WIDTH
|
43
|
+
|
44
|
+
if @report_params[:page_size].is_a?(String)
|
45
|
+
if @report_params[:page_layout] == :portrait
|
46
|
+
w, h = *Prawn::Document::PageGeometry::SIZES[@report_params[:page_size]]
|
47
|
+
else
|
48
|
+
h, w = *Prawn::Document::PageGeometry::SIZES[@report_params[:page_size]]
|
49
|
+
end
|
50
|
+
else
|
51
|
+
w, h = @report_params[:page_size]
|
52
|
+
end
|
53
|
+
@x = 0
|
54
|
+
@y = @max_height = h - (@report_params[:margin][0] + @report_params[:margin][2])
|
55
|
+
@max_width = w - (@report_params[:margin][1] + @report_params[:margin][3])
|
56
|
+
|
57
|
+
@footer_size = 0
|
58
|
+
@pdf.move_cursor_to(max_height - @report_params[:margin][2])
|
59
|
+
|
60
|
+
@header_class = @header_other_pages_class = @summary_band_class = @footer_class = nil
|
61
|
+
@totals = {}
|
62
|
+
@group_totals = {}
|
63
|
+
|
64
|
+
initialize_running_totals
|
65
|
+
end
|
66
|
+
|
67
|
+
def params
|
68
|
+
@report_params
|
69
|
+
end
|
70
|
+
|
71
|
+
def draw(data)
|
72
|
+
@data = data
|
73
|
+
|
74
|
+
draw_header_first_page
|
75
|
+
draw_internal
|
76
|
+
draw_summary
|
77
|
+
draw_footer
|
78
|
+
|
79
|
+
second_pass
|
80
|
+
|
81
|
+
@pdf.close_and_stroke
|
82
|
+
@pdf.render
|
83
|
+
end
|
84
|
+
|
85
|
+
def new_page(print_titles = true)
|
86
|
+
draw_footer
|
87
|
+
|
88
|
+
@num_pages += 1
|
89
|
+
@pdf.start_new_page
|
90
|
+
@x = 0
|
91
|
+
@pdf.move_down(@report_params[:margin][0])
|
92
|
+
|
93
|
+
draw_header_other_pages
|
94
|
+
end
|
95
|
+
|
96
|
+
def fill_color(color)
|
97
|
+
@pdf.fill_color color
|
98
|
+
@pdf.fill_rectangle [x,y], max_width, 15
|
99
|
+
@pdf.fill_color '000000'
|
100
|
+
end
|
101
|
+
|
102
|
+
protected
|
103
|
+
|
104
|
+
def draw_header_first_page
|
105
|
+
draw_header(@header_class)
|
106
|
+
end
|
107
|
+
|
108
|
+
def draw_header_other_pages
|
109
|
+
draw_header(@header_other_pages_class || @header_class)
|
110
|
+
end
|
111
|
+
|
112
|
+
def draw_header(klass)
|
113
|
+
if klass
|
114
|
+
header = klass.new(self)
|
115
|
+
header.draw
|
116
|
+
@pdf.y = @max_height - header.height
|
117
|
+
@x = 0
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def draw_footer
|
122
|
+
if @footer_class
|
123
|
+
footer = @footer_class.new(self)
|
124
|
+
@pdf.move_cursor_to(@footer_class.height)
|
125
|
+
footer.draw
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def draw_summary
|
130
|
+
if @summary_class
|
131
|
+
summary = @summary_class.new(self)
|
132
|
+
summary.draw
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def draw_group_summary
|
137
|
+
if @report_params[:group] && @report_params[:group][:summary_class]
|
138
|
+
summary = @report_params[:group][:summary_class].new(self)
|
139
|
+
summary.draw
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def draw_group_header
|
144
|
+
if @report_params[:group][:header_class]
|
145
|
+
header = @report_params[:group][:header_class].new(self)
|
146
|
+
header.draw
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def second_pass
|
151
|
+
|
152
|
+
end
|
153
|
+
|
154
|
+
def run_totals(data_row)
|
155
|
+
@running_totals.each do |rt|
|
156
|
+
vl = get_raw_field_value(data_row, rt)
|
157
|
+
vl = (vl.is_a? (String) ? vl.to_f : vl)
|
158
|
+
@totals[rt] = (@totals[rt] || 0) + (vl == '' ? 0 : vl)
|
159
|
+
@group_totals[rt] = (@group_totals[rt] || 0) + (vl == '' ? 0 : vl)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def initialize_running_totals
|
164
|
+
@running_totals.each do |rt|
|
165
|
+
@totals[rt] = 0
|
166
|
+
@group_totals[rt] = 0
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def reset_group_totals
|
171
|
+
@running_totals.each do |rt|
|
172
|
+
@group_totals[rt] = 0
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def reset_totals
|
177
|
+
@running_totals.each do |rt|
|
178
|
+
@totals[rt] = 0
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def get_raw_field_value(row, column_name)
|
183
|
+
c = row
|
184
|
+
column_name.split('.').each {|n| c = c[n] if c}
|
185
|
+
c.nil? ? '' : c
|
186
|
+
end
|
187
|
+
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
module PrawnReport
|
4
|
+
class Report
|
5
|
+
|
6
|
+
def box(width, height, options = {})
|
7
|
+
@pdf.rounded_rectangle([0, y], width, height, TEXT_BOX_RADIUS)
|
8
|
+
end
|
9
|
+
|
10
|
+
def text_box_with_box(label, text, width, height = nil, options = {})
|
11
|
+
@pdf.rounded_rectangle([@x, y], width, height || TEXT_BOX_HEIGTH, TEXT_BOX_RADIUS)
|
12
|
+
@pdf.text_box(label, :size => LABEL_SIZE, :at => [@x + 2, y - 2], :width => width - 2,
|
13
|
+
:height => LABEL_SIZE, :valign => :top)
|
14
|
+
h_text = height.nil? ? TEXT_SIZE : height - LABEL_SIZE - 4
|
15
|
+
@pdf.text_box(text || '', { :size => TEXT_SIZE, :at => [@x + 2, y - LABEL_SIZE - 4],
|
16
|
+
:width => width - 2, :height => h_text, :valign => :top }.merge(options))
|
17
|
+
@x += width
|
18
|
+
end
|
19
|
+
|
20
|
+
def text(text, width, options = {})
|
21
|
+
font_size = options[:font_size] || TEXT_SIZE
|
22
|
+
@pdf.text_box(text, :size => font_size, :style => options[:style], :at => [@x, y - 4],
|
23
|
+
:width => width, :height => font_size,
|
24
|
+
:valign => (options[:valign] || :top),
|
25
|
+
:align => (options[:align] || :left)
|
26
|
+
)
|
27
|
+
@x = @x + width
|
28
|
+
end
|
29
|
+
|
30
|
+
def horizontal_line(x_ini = 0, x_end = @max_width)
|
31
|
+
@pdf.stroke do
|
32
|
+
@pdf.horizontal_line(x_ini, x_end, :at => y)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def y
|
37
|
+
@pdf.y
|
38
|
+
end
|
39
|
+
|
40
|
+
def y=(y)
|
41
|
+
@pdf.y = y
|
42
|
+
end
|
43
|
+
|
44
|
+
def space(width)
|
45
|
+
@x += width
|
46
|
+
end
|
47
|
+
|
48
|
+
def line_break(size = TEXT_SIZE)
|
49
|
+
@x = 0
|
50
|
+
@pdf.move_down(@pdf.height_of('A', :size => size) + 2)
|
51
|
+
end
|
52
|
+
|
53
|
+
def format(value, formatter, options = {})
|
54
|
+
if !value.nil? && value != ''
|
55
|
+
if (formatter == :currency)
|
56
|
+
if value < 0
|
57
|
+
'-'+((value.to_i*-1).to_s.reverse.gsub(/...(?=.)/,'\&.').reverse) + ',' + ('%02d' % ((value.abs * 100).round % 100))
|
58
|
+
else
|
59
|
+
(value.to_i.to_s.reverse.gsub(/...(?=.)/,'\&.').reverse) + ',' + ('%02d' % ((value * 100).round % 100))
|
60
|
+
end
|
61
|
+
elsif (formatter == :date)
|
62
|
+
value.to_time.strftime('%d/%m/%Y')
|
63
|
+
elsif (formatter == :timezone_date)
|
64
|
+
tz = Time.zone.parse(value)
|
65
|
+
tz.nil? ? '' : tz.strftime('%d/%m/%Y')
|
66
|
+
elsif (formatter == :function)
|
67
|
+
send(options[:formatter_function].to_s, value)
|
68
|
+
else
|
69
|
+
value.to_s
|
70
|
+
end
|
71
|
+
else
|
72
|
+
''
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def draw_graph(g, params)
|
77
|
+
data = StringIO.new(g.to_blob)
|
78
|
+
@pdf.image(data, params)
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
end
|
data/lib/report_info.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'date'
|
4
|
+
|
5
|
+
module PrawnReport
|
6
|
+
class Report
|
7
|
+
|
8
|
+
attr_accessor :force_today_as
|
9
|
+
|
10
|
+
def fits?(h)
|
11
|
+
(y - footer_size - h - @report_params[:margin][2]) >= 0
|
12
|
+
end
|
13
|
+
|
14
|
+
def header_size
|
15
|
+
@header ? @header_class.height : 0
|
16
|
+
end
|
17
|
+
|
18
|
+
def footer_size
|
19
|
+
@footer_class ? @footer_class.height : 0
|
20
|
+
end
|
21
|
+
|
22
|
+
def today
|
23
|
+
@force_today_as ? @force_today_as : Date.today
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
#coding: utf-8
|
2
|
+
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + "/../../../lib/bands/footer_band")
|
4
|
+
|
5
|
+
module PrawnReport
|
6
|
+
|
7
|
+
class Footer001 < FooterBand
|
8
|
+
|
9
|
+
def internal_draw
|
10
|
+
report.horizontal_line
|
11
|
+
report.x = 0
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.height
|
15
|
+
10
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
#coding: utf-8
|
2
|
+
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + "/../../../lib/bands/header_band")
|
4
|
+
|
5
|
+
module PrawnReport
|
6
|
+
|
7
|
+
#This header renders:
|
8
|
+
#
|
9
|
+
#* Company name based on a property at the root of data named +company_name+ left aligned
|
10
|
+
# font size 16.
|
11
|
+
#* Data de emissão dated today right aligned font size 12
|
12
|
+
#* Report name based on a parameter named +report_name+ setted in the report
|
13
|
+
#* A list of filters read from *report.params[:filters]*. Each filter is printed in one
|
14
|
+
# line. *params[:filters]* must be an array of arrays where the inner arrays must be
|
15
|
+
# tuples of two elements, the first one being the title and second one being the value of the
|
16
|
+
# filter. If value is present the title is concatenated with ':'
|
17
|
+
class Header001 < HeaderBand
|
18
|
+
|
19
|
+
def initialize(report, params = {})
|
20
|
+
super(report, params)
|
21
|
+
@filter_size = 0
|
22
|
+
end
|
23
|
+
|
24
|
+
def internal_draw
|
25
|
+
report.text(report.data['company_name'], 300, :style => :bold, :font_size => 16)
|
26
|
+
txt_emissao = 'Data de emissão: ' + report.today.strftime('%d/%m/%Y')
|
27
|
+
length = report.pdf.width_of(txt_emissao, :size => 12)
|
28
|
+
report.x = report.max_width - length
|
29
|
+
report.text(txt_emissao, length, :font_size => 12,
|
30
|
+
:valign => :bottom, :align => :right)
|
31
|
+
report.line_break(16)
|
32
|
+
report.text(report.params[:report_name], report.max_width, :font_size => 13,
|
33
|
+
:align => :center)
|
34
|
+
report.line_break(13)
|
35
|
+
draw_filters if report.params[:filters]
|
36
|
+
report.horizontal_line
|
37
|
+
end
|
38
|
+
|
39
|
+
def draw_filters
|
40
|
+
report.params[:filters].each do |param|
|
41
|
+
title = param[0]
|
42
|
+
if param[1].to_s != ''
|
43
|
+
title = title + ':'
|
44
|
+
end
|
45
|
+
report.text(title, 2 + report.pdf.width_of(title, :size => 10), :font_size => 10)
|
46
|
+
report.text(param[1], 2 + report.pdf.width_of(param[1], :size => 10), :font_size => 10)
|
47
|
+
report.x = 0
|
48
|
+
size = report.pdf.height_of(param[1], :size => 10)
|
49
|
+
size = 10 if size < 10
|
50
|
+
report.pdf.move_down(size + 2)
|
51
|
+
@filter_size += size + 2
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def height
|
56
|
+
45 + @filter_size
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
#coding: utf-8
|
2
|
+
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + "/../../../lib/bands/header_band")
|
4
|
+
|
5
|
+
module PrawnReport
|
6
|
+
#This is a minimalist header intended to render the company name and report name in additional
|
7
|
+
#pages of a report.
|
8
|
+
#
|
9
|
+
#This header renders:
|
10
|
+
#
|
11
|
+
#* Company name based on a property at the root of data named +company_name+ left aligned
|
12
|
+
# font size 12.
|
13
|
+
#* Report name based on a parameter named +report_name+ setted in the report
|
14
|
+
class Header002 < HeaderBand
|
15
|
+
|
16
|
+
def internal_draw
|
17
|
+
report.x = 0
|
18
|
+
report.text(report.data['company_name'], 300, :font_size => 12)
|
19
|
+
report.x = 0
|
20
|
+
report.text(report.params[:report_name], report.max_width, :font_size => 12, :align => :right)
|
21
|
+
report.line_break(12)
|
22
|
+
report.horizontal_line
|
23
|
+
end
|
24
|
+
|
25
|
+
def height
|
26
|
+
20
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module PrawnReport
|
2
|
+
class NoGroupingFieldProvided < Exception; end
|
3
|
+
class NoGroupingValueFieldProvided < Exception; end
|
4
|
+
class NoGroupingContextFieldProvided < Exception; end
|
5
|
+
|
6
|
+
class ColumnGroup < Listing
|
7
|
+
attr_accessor :grouping_field
|
8
|
+
attr_accessor :grouping_context_field
|
9
|
+
attr_accessor :grouping_value_field
|
10
|
+
|
11
|
+
def new_page(print_titles = true)
|
12
|
+
draw_column_titles if print_titles
|
13
|
+
end
|
14
|
+
|
15
|
+
def before_draw_lines
|
16
|
+
super
|
17
|
+
draw_column_titles
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize(report_params = {})
|
21
|
+
super(report_params)
|
22
|
+
raise NoGroupingFieldProvided unless report_params[:grouping_field]
|
23
|
+
raise NoGroupingValueFieldProvided unless report_params[:grouping_value_field]
|
24
|
+
raise NoGroupingContextFieldProvided unless report_params[:grouping_context_field]
|
25
|
+
@grouping_field = report_params[:grouping_field]
|
26
|
+
@grouping_value_field = report_params[:grouping_value_field]
|
27
|
+
@grouping_context_field = report_params[:grouping_context_field]
|
28
|
+
end
|
29
|
+
|
30
|
+
def draw(data)
|
31
|
+
data = traverse_data(data)
|
32
|
+
super(data)
|
33
|
+
end
|
34
|
+
|
35
|
+
protected
|
36
|
+
|
37
|
+
def traverse_data(data)
|
38
|
+
new_data = []
|
39
|
+
last_value = nil
|
40
|
+
new_row = nil
|
41
|
+
old_data = data[@detail_name]
|
42
|
+
old_data.each do |row|
|
43
|
+
if row[@grouping_field] != last_value then
|
44
|
+
new_data << new_row unless new_row.nil?
|
45
|
+
last_value = row[@grouping_field]
|
46
|
+
new_row = {}
|
47
|
+
row.each_pair {|k,v| new_row[k] = v}
|
48
|
+
end
|
49
|
+
new_row[@grouping_context_field.to_s + '_' + row[@grouping_context_field].to_s] = row[@grouping_value_field]
|
50
|
+
end
|
51
|
+
new_data << new_row unless new_row.nil?
|
52
|
+
data[@detail_name]=new_data
|
53
|
+
data
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|