rails_data 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (109) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +165 -0
  3. data/README.md +41 -0
  4. data/Rakefile +37 -0
  5. data/app/assets/config/rails_data_manifest.js +1 -0
  6. data/app/assets/javascripts/channels/done.js +10 -0
  7. data/app/assets/javascripts/controllers/the_data_admin/data_lists/edit.js +1 -0
  8. data/app/assets/javascripts/controllers/the_data_admin/data_lists/new.js +1 -0
  9. data/app/assets/javascripts/controllers/the_data_admin/table_lists/index.js +10 -0
  10. data/app/channels/done_channel.rb +7 -0
  11. data/app/channels/rails_data_connection.rb +29 -0
  12. data/app/controllers/rails_data_admin/base_controller.rb +3 -0
  13. data/app/controllers/rails_data_admin/data_lists_controller.rb +75 -0
  14. data/app/controllers/rails_data_admin/data_records_controller.rb +71 -0
  15. data/app/controllers/rails_data_admin/record_lists_controller.rb +105 -0
  16. data/app/controllers/rails_data_admin/table_lists_controller.rb +115 -0
  17. data/app/helpers/data_records_helper.rb +2 -0
  18. data/app/helpers/rails_data_helper.rb +21 -0
  19. data/app/jobs/table_job.rb +11 -0
  20. data/app/mailers/report_finish_mailer.rb +17 -0
  21. data/app/models/rails_data/concerns/data_cache_service.rb +26 -0
  22. data/app/models/rails_data/concerns/data_export_helper.rb +55 -0
  23. data/app/models/rails_data/concerns/data_import_helper.rb +40 -0
  24. data/app/models/rails_data/concerns/data_import_service.rb +35 -0
  25. data/app/models/rails_data/data_list.rb +47 -0
  26. data/app/models/rails_data/data_lists/data_export.rb +11 -0
  27. data/app/models/rails_data/data_lists/data_import.rb +11 -0
  28. data/app/models/rails_data/data_lists/data_record.rb +18 -0
  29. data/app/models/rails_data/export_services/csv_export_service.rb +24 -0
  30. data/app/models/rails_data/export_services/pdf_export_service.rb +74 -0
  31. data/app/models/rails_data/export_services/xlsx_export_service.rb +51 -0
  32. data/app/models/rails_data/record_list.rb +69 -0
  33. data/app/models/rails_data/table_item.rb +5 -0
  34. data/app/models/rails_data/table_list.rb +47 -0
  35. data/app/pdfs/concerns/pdf_page_helper.rb +37 -0
  36. data/app/pdfs/concerns/pdf_table_helper.rb +107 -0
  37. data/app/pdfs/concerns/pdf_text_helper.rb +18 -0
  38. data/app/pdfs/rails_data_pdf.rb +32 -0
  39. data/app/views/rails_data_admin/base/_nav.html.erb +9 -0
  40. data/app/views/rails_data_admin/data_lists/_item_form.html.erb +15 -0
  41. data/app/views/rails_data_admin/data_lists/add_item.js.erb +4 -0
  42. data/app/views/rails_data_admin/data_lists/edit.html.erb +33 -0
  43. data/app/views/rails_data_admin/data_lists/index.html.erb +43 -0
  44. data/app/views/rails_data_admin/data_lists/new.html.erb +17 -0
  45. data/app/views/rails_data_admin/data_lists/remove_item.js.erb +1 -0
  46. data/app/views/rails_data_admin/data_lists/reportable.html.erb +31 -0
  47. data/app/views/rails_data_admin/data_lists/show.html.erb +20 -0
  48. data/app/views/rails_data_admin/data_records/_item_form.html.erb +15 -0
  49. data/app/views/rails_data_admin/data_records/add_item.js.erb +4 -0
  50. data/app/views/rails_data_admin/data_records/edit.html.erb +33 -0
  51. data/app/views/rails_data_admin/data_records/index.html.erb +57 -0
  52. data/app/views/rails_data_admin/data_records/new.html.erb +16 -0
  53. data/app/views/rails_data_admin/data_records/remove_item.js.erb +1 -0
  54. data/app/views/rails_data_admin/data_records/reportable.html.erb +31 -0
  55. data/app/views/rails_data_admin/data_records/show.html.erb +20 -0
  56. data/app/views/rails_data_admin/record_lists/_edit_columns.html.erb +19 -0
  57. data/app/views/rails_data_admin/record_lists/_edit_table.erb +44 -0
  58. data/app/views/rails_data_admin/record_lists/_index.html.erb +22 -0
  59. data/app/views/rails_data_admin/record_lists/_search_form.html.erb +9 -0
  60. data/app/views/rails_data_admin/record_lists/_show.html.erb +16 -0
  61. data/app/views/rails_data_admin/record_lists/_table.html.erb +12 -0
  62. data/app/views/rails_data_admin/record_lists/edit.html.erb +19 -0
  63. data/app/views/rails_data_admin/record_lists/edit_columns.html.erb +30 -0
  64. data/app/views/rails_data_admin/record_lists/edit_columns.js.erb +9 -0
  65. data/app/views/rails_data_admin/record_lists/find.js.erb +8 -0
  66. data/app/views/rails_data_admin/record_lists/index.html.erb +52 -0
  67. data/app/views/rails_data_admin/record_lists/new.html.erb +19 -0
  68. data/app/views/rails_data_admin/record_lists/show.html.erb +19 -0
  69. data/app/views/rails_data_admin/record_lists/show.js.erb +8 -0
  70. data/app/views/rails_data_admin/record_lists/update_columns.js.erb +8 -0
  71. data/app/views/rails_data_admin/table_lists/_import.html.erb +17 -0
  72. data/app/views/rails_data_admin/table_lists/_index.html.erb +22 -0
  73. data/app/views/rails_data_admin/table_lists/_process.html.erb +5 -0
  74. data/app/views/rails_data_admin/table_lists/_show.html.erb +10 -0
  75. data/app/views/rails_data_admin/table_lists/_table.html.erb +38 -0
  76. data/app/views/rails_data_admin/table_lists/create_import.js.erb +8 -0
  77. data/app/views/rails_data_admin/table_lists/edit.html.erb +19 -0
  78. data/app/views/rails_data_admin/table_lists/find.js.erb +2 -0
  79. data/app/views/rails_data_admin/table_lists/index.html.erb +55 -0
  80. data/app/views/rails_data_admin/table_lists/new.html.erb +19 -0
  81. data/app/views/rails_data_admin/table_lists/new_import.js.erb +30 -0
  82. data/app/views/rails_data_admin/table_lists/run.js.erb +10 -0
  83. data/app/views/rails_data_admin/table_lists/show.html.erb +11 -0
  84. data/app/views/report_finish_mailer/finish_notify.text.erb +5 -0
  85. data/config/initializers/the_data.rb +4 -0
  86. data/config/locales/en.yml +10 -0
  87. data/config/locales/zh.yml +10 -0
  88. data/config/routes.rb +35 -0
  89. data/db/migrate/20150618053929_create_report_lists.rb +51 -0
  90. data/lib/rails_data/config.rb +23 -0
  91. data/lib/rails_data/engine.rb +18 -0
  92. data/lib/rails_data/export.rb +52 -0
  93. data/lib/rails_data/import.rb +42 -0
  94. data/lib/rails_data/record.rb +42 -0
  95. data/lib/rails_data/version.rb +3 -0
  96. data/lib/rails_data.rb +5 -0
  97. data/test/controllers/data_records_controller_test.rb +48 -0
  98. data/test/controllers/rails_data_admin/report_lists_controller_test.rb +49 -0
  99. data/test/controllers/rails_data_admin/table_lists_controller_test.rb +49 -0
  100. data/test/factories/combines.rb +7 -0
  101. data/test/factories/report_lists.rb +14 -0
  102. data/test/factories/table_items.rb +6 -0
  103. data/test/factories/table_lists.rb +6 -0
  104. data/test/integration/navigation_test.rb +10 -0
  105. data/test/models/data_list_test.rb +10 -0
  106. data/test/system/data_records_test.rb +41 -0
  107. data/test/test_helper.rb +21 -0
  108. data/test/the_data_test.rb +7 -0
  109. metadata +247 -0
@@ -0,0 +1,2 @@
1
+ module DataRecordsHelper
2
+ end
@@ -0,0 +1,21 @@
1
+ module RailsDataHelper
2
+
3
+ def text_field_tag(name, value = nil, options = {})
4
+ if options[:as]
5
+ type = RailsData.config.mapping[options[:as]][:input]
6
+
7
+ if type == 'textarea'
8
+ return text_area_tag(name, value, options)
9
+ end
10
+
11
+ if type == 'select'
12
+ opts = RailsData.config.mapping[options[:as]][:options]
13
+ selected = RailsData.config.mapping[options[:as]][:selected]
14
+ return select_tag name, options_for_select(opts, selected), options
15
+ end
16
+ end
17
+
18
+ super
19
+ end
20
+
21
+ end
@@ -0,0 +1,11 @@
1
+ class TableJob < ActiveJob::Base
2
+ queue_as :default
3
+
4
+ def perform(table_list_id, user_id)
5
+ @table_list = TableList.find(table_list_id)
6
+ @table_list.run
7
+
8
+ ActionCable.server.broadcast "user:#{user_id}", body: '<i class="green checkmark icon"></i>', done_id: table_list_id
9
+ end
10
+
11
+ end
@@ -0,0 +1,17 @@
1
+ class ReportFinishMailer < ActionMailer::Base
2
+ default from: ""
3
+
4
+ def finish_notify(id)
5
+ @report_list = ReportList.find(id)
6
+ @message = @report_list.notice_body
7
+
8
+ if Rails.env == 'production'
9
+ @email = @report_list.notice_email
10
+ else
11
+ @email = 'mingyuan0715@foxmail.com'
12
+ end
13
+
14
+ mail to: @email, subject: "Generation Complete"
15
+ end
16
+
17
+ end
@@ -0,0 +1,26 @@
1
+ class DataCacheService
2
+ include DataExportHelper
3
+
4
+ def initialize(table_list)
5
+ @table_list = table_list
6
+ @data_list = @table_list.data_list
7
+ @config_table = table_list.data_list.config_table
8
+ convert_parameters(@table_list.parameters)
9
+ end
10
+
11
+ def cache_table
12
+ @table_list.headers = header_result
13
+ cache_table_items
14
+ @table_list.footers = footer_result
15
+ @table_list.done = true
16
+ @table_list.save
17
+ end
18
+
19
+ def cache_table_items
20
+ @config_table.collection.call(@params).each_with_index do |object, index|
21
+ row = field_result(object, index)
22
+ @table_list.table_items.create(fields: row)
23
+ end
24
+ end
25
+
26
+ end
@@ -0,0 +1,55 @@
1
+ module DataExportHelper
2
+
3
+ def convert_parameters(parameters)
4
+ @params = {}
5
+ parameters.each do |k, v|
6
+ @params.merge! k.to_sym => v.send(RailsData.config.mapping[@data_list.parameters[k].to_sym][:output])
7
+ end
8
+ @params
9
+ end
10
+
11
+ def header_result
12
+ results = []
13
+
14
+ @config_table.columns.each do |_, column|
15
+ if column[:header].respond_to?(:call)
16
+ results << column[:header].call
17
+ else
18
+ results << column[:header]
19
+ end
20
+ end
21
+ results
22
+ end
23
+
24
+ def field_result(object, index)
25
+ results = []
26
+ @config_table.columns.each do |_, column|
27
+ params = column[:field].parameters.to_combined_h
28
+ if Array(params[:key]).include? :index
29
+ results << column[:field].call(object, index)
30
+ elsif params[:key]
31
+ results << column[:field].call(object, **@params.slice(params[:key]))
32
+ elsif params[:key].blank? && params[:req]
33
+ results << column[:field].call(object)
34
+ else
35
+ results << nil
36
+ end
37
+ end
38
+
39
+ results
40
+ end
41
+
42
+ def footer_result
43
+ results = []
44
+
45
+ @config_table.columns.each do |_, column|
46
+ if column[:footer].respond_to?(:call)
47
+ results << column[:footer].call
48
+ else
49
+ results << column[:footer]
50
+ end
51
+ end
52
+ results
53
+ end
54
+
55
+ end
@@ -0,0 +1,40 @@
1
+ module DataImportHelper
2
+
3
+ def import_to_table_list(file)
4
+ importer = data_list.importer(file)
5
+ self.headers = importer.results[0]
6
+ self.done = true
7
+ self.save
8
+ importer.results[1..-1].each do |row|
9
+ table_items.create(fields: row)
10
+ end
11
+ end
12
+
13
+ def import_columns
14
+ config = data_list.config_table
15
+ columns = {}
16
+ config.columns.each do |key, value|
17
+ columns[key] = config.columns[key].merge(index: self.headers.find_index(value[:header]))
18
+ end
19
+ columns.reject { |_, v| v[:index].nil? }
20
+ end
21
+
22
+ def migrate
23
+ config = data_list.config_table
24
+ columns = import_columns
25
+ self.table_items.each do |table_item|
26
+ attr = {}
27
+ columns.map do |key, value|
28
+ r = table_item.fields[value[:index]]
29
+ if value[:field] && value[:field].respond_to?(:call)
30
+ attr[key] = value[:field].call(r)
31
+ else
32
+ attr[key] = r
33
+ end
34
+ end
35
+ config.record.create attr
36
+ end
37
+ self.destroy
38
+ end
39
+
40
+ end
@@ -0,0 +1,35 @@
1
+ require 'roo'
2
+ class DataImportService
3
+ attr_reader :sheet, :column_index
4
+
5
+ def initialize(config, sheet_file)
6
+ if File.extname(sheet_file.path) == '.xls'
7
+ require 'roo-xls'
8
+ xlsx = Roo::Excel.new(sheet_file)
9
+ else
10
+ xlsx = Roo::Excelx.new(sheet_file)
11
+ end
12
+ @sheet = xlsx.sheet(xlsx.sheets[0])
13
+ @config = config
14
+
15
+ @column_index = init_header.compact
16
+ end
17
+
18
+ def init_header
19
+ headers = @config.columns.map { |_, v| v[:header] }
20
+ file_header = @sheet.row(1)
21
+
22
+ headers.map do |header|
23
+ file_header.find_index(header)
24
+ end
25
+ end
26
+
27
+ def results
28
+ results = []
29
+ @sheet.each do |row|
30
+ results << column_index.map { |index| row[index] }
31
+ end
32
+ results
33
+ end
34
+
35
+ end
@@ -0,0 +1,47 @@
1
+ require 'rails_com/utils/setting'
2
+ class DataList < ApplicationRecord
3
+ serialize :parameters, Hash
4
+ serialize :columns, Hash
5
+
6
+ has_many :table_lists, dependent: :destroy
7
+ has_many :table_items, through: :table_lists
8
+
9
+ scope :published, -> { where(published: true) }
10
+
11
+ before_create :update_parameters
12
+
13
+ def rebuild!
14
+ self.save
15
+ end
16
+
17
+ def form_parameters
18
+ r = parameters.map { |k, v| { key: k, value: v } }
19
+ if r.blank?
20
+ r = [{ key: nil, value: nil }]
21
+ end
22
+ Settings.new(r)
23
+ end
24
+
25
+ def update_parameters
26
+ self.parameters = config_params
27
+ end
28
+
29
+ def config_params
30
+ hash = {}
31
+ config_table.parameters.map { |p| hash[p] = nil }
32
+ hash
33
+ end
34
+
35
+ def config_table
36
+ @config_table ||= data_table.to_s.safe_constantize
37
+ end
38
+
39
+ def config_excel
40
+ @config_excel ||= export_excel.to_s.safe_constantize
41
+ end
42
+
43
+ def config_pdf
44
+ @config_pdf ||= export_pdf.to_s.safe_constantize
45
+ end
46
+
47
+ end
@@ -0,0 +1,11 @@
1
+ class DataExport < DataList
2
+
3
+ def headers
4
+ config_table.columns.map { |p| p[1][:header] }
5
+ end
6
+
7
+ def just_run
8
+
9
+ end
10
+
11
+ end
@@ -0,0 +1,11 @@
1
+ class DataImport < DataList
2
+
3
+ def importer(file)
4
+ @importer ||= DataImportService.new(config_table, file)
5
+ end
6
+
7
+
8
+ def config_params
9
+ {}
10
+ end
11
+ end
@@ -0,0 +1,18 @@
1
+ class DataRecord < DataList
2
+ has_many :record_lists, foreign_key: 'data_list_id', dependent: :destroy
3
+ has_many :record_items, through: :record_lists
4
+
5
+ def rebuild!
6
+ self.columns = self.config_params
7
+ super
8
+ end
9
+
10
+ def update_parameters
11
+ self.columns = config_columns
12
+ end
13
+
14
+ def config_columns
15
+ config_table.columns.transform_values { |x| x[:as] }
16
+ end
17
+
18
+ end
@@ -0,0 +1,24 @@
1
+ require 'csv'
2
+ class CsvExportService
3
+ include DataExportHelper
4
+
5
+ attr_reader :sheet, :headers
6
+
7
+ def initialize
8
+ headers =
9
+ config_table
10
+
11
+
12
+ end
13
+
14
+
15
+ def to_csv
16
+ csv = ''
17
+ csv << headers.to_csv
18
+ self.table_items.each do |table_item|
19
+ csv << table_item.fields.to_csv
20
+ end
21
+ csv
22
+ end
23
+
24
+ end
@@ -0,0 +1,74 @@
1
+ require 'prawn/table'
2
+ class PdfExportService
3
+ include DataExportHelper
4
+
5
+ def pdf
6
+ if reportable.respond_to?(:pdf_object)
7
+ @pdf ||= reportable.pdf_object(reportable_name)
8
+ else
9
+ @pdf ||= TablePdf.new
10
+ end
11
+ end
12
+
13
+ def remove_file_save
14
+ self.remove_file = true
15
+ self.save
16
+ self.remove_file = nil
17
+ end
18
+
19
+ def pdf_data
20
+ if file_id
21
+ file.read
22
+ else
23
+ pdf_string
24
+ end
25
+ end
26
+
27
+ def pdf_string
28
+ pdf_result.render
29
+ end
30
+
31
+ def pdf_result
32
+ pdf.table_data = table_lists.includes(:table_items).map { |i| i.csv_array }
33
+ pdf.header_data = header_data
34
+ pdf.ending_data = ending_data
35
+ pdf.run
36
+ pdf
37
+ end
38
+
39
+ def header_data
40
+ if reportable.respond_to? :header_info
41
+ reportable.header_info
42
+ else
43
+ [
44
+ ['', ''],
45
+ ['', '']
46
+ ]
47
+ end
48
+ end
49
+
50
+ def ending_data
51
+ if reportable.respond_to? :ending_data
52
+ reportable.try(:ending_data)
53
+ else
54
+ ''
55
+ end
56
+ end
57
+
58
+ def filename(extension = 'pdf')
59
+ if file_filename.present?
60
+ filename = file_filename
61
+ elsif reportable.respond_to?(:filename)
62
+ filename = reportable.filename
63
+ else
64
+ filename = "#{reportable_name.camelize}-#{reportable_id}"
65
+ end
66
+
67
+ unless filename.end_with?(extension)
68
+ filename << '.' << extension
69
+ end
70
+
71
+ filename
72
+ end
73
+
74
+ end
@@ -0,0 +1,51 @@
1
+ require 'write_xlsx'
2
+ class XlsxExportService
3
+ include DataExportHelper
4
+ attr_reader :sheet,
5
+ :table_list,
6
+ :params, :headers
7
+
8
+ def initialize(table_list: nil, data_list: nil, params: {}, headers: [])
9
+ if table_list
10
+ @table_list = table_list
11
+ @data_list = table_list.data_list
12
+ @headers = headers.presence || table_list.headers
13
+ convert_parameters(params)
14
+ elsif data_list
15
+ @data_list = data_list
16
+ @headers = headers
17
+ convert_parameters(params)
18
+ end
19
+ @config_table = @data_list.config_table
20
+
21
+ @io = StringIO.new
22
+ @workbook = WriteXLSX.new(@io)
23
+ @sheet = @workbook.add_worksheet
24
+ end
25
+
26
+ def direct_xlsx
27
+ sheet.write_row(0, 0, headers)
28
+
29
+ @config_table.collection.call(@params).each_with_index do |object, index|
30
+ row = field_result(object, index)
31
+ sheet.write_row(index + 1, 0, row)
32
+ end
33
+
34
+ @workbook.close
35
+ @io.string
36
+ end
37
+
38
+ def cached_xlsx
39
+ sheet.write_row(0, 0, table_list.headers)
40
+
41
+ table_list.table_items.each_with_index do |table_item, index|
42
+ sheet.write_row(index + 1, 0, table_item.fields)
43
+ end
44
+
45
+ sheet.write_row table_list.table_items_count + 1, 0, table_list.footers
46
+
47
+ @workbook.close
48
+ @io.string
49
+ end
50
+
51
+ end
@@ -0,0 +1,69 @@
1
+ class RecordList < ApplicationRecord
2
+ serialize :columns, Hash
3
+ serialize :parameters, Hash
4
+ belongs_to :data_list
5
+
6
+ default_scope -> { order(id: :desc) }
7
+
8
+ def run
9
+ to_table
10
+ end
11
+
12
+ def to_table
13
+ initialize_table
14
+ self.to_table_items
15
+ self.done = true
16
+ self.save
17
+ end
18
+
19
+ def initialize_table
20
+ @config_table = data_list.config_table
21
+ @record = @config_table.record.call(converted_parameters)
22
+ @config_table
23
+ end
24
+
25
+ def converted_parameters
26
+ param = {}
27
+ parameters.each do |k, v|
28
+ param.merge! k.to_sym => v.send(RailsData.config.mapping[data_list.parameters[k].to_sym][:output])
29
+ end
30
+ param
31
+ end
32
+
33
+ def to_table_items
34
+ self.columns = field_result(@record)
35
+ end
36
+
37
+ def field_result(object)
38
+ results = {}
39
+ @config_table.columns.each do |key, column|
40
+ if column[:field].arity == 1
41
+ results[key] = column[:field].call(object)
42
+ else
43
+ results[key] = nil
44
+ end
45
+ end
46
+
47
+ results
48
+ end
49
+
50
+ def to_xlsx
51
+ @config_excel = data_list.config_excel.new(self.columns)
52
+ @config_excel.render
53
+ end
54
+
55
+ def to_pdf
56
+ @config_pdf ||= data_list.config_pdf.new(self.columns)
57
+ @config_pdf.render
58
+ end
59
+
60
+ def xlsx_file_name
61
+ @config_excel.file_name || "#{self.id}.xlsx"
62
+ end
63
+
64
+ def file_name(format)
65
+ name = self.id || 'example'
66
+ "#{name}.#{format}"
67
+ end
68
+
69
+ end
@@ -0,0 +1,5 @@
1
+ class TableItem < ApplicationRecord
2
+ serialize :fields, Array
3
+ belongs_to :table_list, counter_cache: true
4
+
5
+ end
@@ -0,0 +1,47 @@
1
+ class TableList < ApplicationRecord
2
+ include DataImportHelper
3
+ serialize :parameters, Hash
4
+ serialize :headers, Array
5
+ serialize :footers, Array
6
+
7
+ belongs_to :data_list, optional: true
8
+ has_many :table_items, dependent: :delete_all
9
+
10
+ def run
11
+ clear_old
12
+ export = DataCacheService.new(self)
13
+ export.cache_table
14
+ end
15
+
16
+ def direct_xlsx
17
+ _headers = self.headers.presence || self.data_list.headers
18
+ export = XlsxExportService.new(data_list: self.data_list, params: self.parameters, headers: _headers)
19
+ export.direct_xlsx
20
+ end
21
+
22
+ def cached_xlsx
23
+ export = XlsxExportService.new(table_list: self)
24
+ export.cached_xlsx
25
+ end
26
+
27
+ def cached_run(_timestamp = nil)
28
+ unless self.timestamp.present? && self.timestamp == _timestamp.to_s
29
+ self.timestamp = _timestamp
30
+ run
31
+ end
32
+ end
33
+
34
+ def clear_old
35
+ self.done = false
36
+ self.class.transaction do
37
+ self.save!
38
+ table_items.delete_all
39
+ end
40
+ end
41
+
42
+ def file_name(format)
43
+ name = self.id || 'example'
44
+ "#{name}.#{format}"
45
+ end
46
+
47
+ end
@@ -0,0 +1,37 @@
1
+ module PdfPageHelper
2
+
3
+ def repeat_header(data = nil)
4
+ repeat :all do
5
+ canvas do
6
+ bounding_box [bounds.left+75, bounds.top-20], :width => bounds.width do
7
+ process_header(data)
8
+ end
9
+ end
10
+ end
11
+ end
12
+
13
+ def process_header(data)
14
+ default_options = {
15
+ cell_style: { borders: [] },
16
+ column_widths: [225, 220]
17
+ }
18
+
19
+ table(data, default_options) do
20
+ row(0).style font_style: :bold, size: 14
21
+ row(1..-1).style size: 10
22
+ column(0).style align: :left, padding: 0
23
+ column(1).style align: :right, padding: 0
24
+ cells[2, 0].style size: 12 if cells[2, 0].present?
25
+ end
26
+
27
+ move_down 50
28
+ end
29
+
30
+ def footer(data = nil, options = {})
31
+ text data
32
+ if options[:page]
33
+ number_pages "<page> / <total>", at: [bounds.right - 50, 0]
34
+ end
35
+ end
36
+
37
+ end