mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-26 20:56:48 +00:00
This is supposed to lower the memory footprint of all Puma workers. The reports code will occupy needed memory in one Sidekiq worker instead of in several Puma processes. The current code doesn't limit the execution time yet. We either need a way to terminate the report rendering after a while or send an email with a link to access a rendered report.
99 lines
2.2 KiB
Ruby
99 lines
2.2 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require 'spreadsheet_architect'
|
|
|
|
module Reporting
|
|
class ReportRenderer
|
|
REPORT_FORMATS = [:csv, :json, :html, :xlsx, :pdf].freeze
|
|
|
|
def initialize(report)
|
|
@report = report
|
|
end
|
|
|
|
def raw_render?
|
|
@report.params[:report_format].in?(['json', 'csv'])
|
|
end
|
|
|
|
def html_render?
|
|
@report.params[:report_format].in?([nil, '', 'pdf'])
|
|
end
|
|
|
|
def display_header_row?
|
|
@report.params[:display_header_row].present? && !raw_render?
|
|
end
|
|
|
|
def display_summary_row?
|
|
@report.params[:display_summary_row].present? && !raw_render?
|
|
end
|
|
|
|
def table_headers
|
|
@report.table_headers || []
|
|
end
|
|
|
|
def table_rows
|
|
@report.table_rows || []
|
|
end
|
|
|
|
def as_json(_context_controller = nil)
|
|
@report.rows.map(&:to_h).as_json
|
|
end
|
|
|
|
def render_as(target_format)
|
|
unless target_format.to_sym.in?(REPORT_FORMATS)
|
|
raise ActionController::BadRequest, "report_format should be in #{REPORT_FORMATS}"
|
|
end
|
|
|
|
public_send("to_#{target_format}")
|
|
end
|
|
|
|
def to_html(layout: nil)
|
|
ApplicationController.render(
|
|
template: "admin/reports/_table",
|
|
layout: layout,
|
|
locals: { report: @report }
|
|
)
|
|
end
|
|
|
|
def to_csv
|
|
SpreadsheetArchitect.to_csv(headers: table_headers, data: table_rows)
|
|
end
|
|
|
|
def to_xlsx
|
|
SpreadsheetArchitect.to_xlsx(spreadsheets_options)
|
|
end
|
|
|
|
def to_pdf
|
|
html = to_html(layout: "pdf")
|
|
WickedPdf.new.pdf_from_string(html)
|
|
end
|
|
|
|
private
|
|
|
|
def spreadsheets_options
|
|
{
|
|
headers: table_headers,
|
|
data: table_rows,
|
|
freeze_headers: true,
|
|
row_style: spreadsheets_style,
|
|
header_style: spreadsheets_style.merge({ bg_color: "f7f6f6", bold: true }),
|
|
conditional_row_styles: [
|
|
{
|
|
# Detect header_row: the row is nil except for first cell
|
|
if: proc { |row_data, _row_index|
|
|
row_data.compact.count == 1 && row_data[0].present?
|
|
},
|
|
styles: { font_size: 12, bold: true }
|
|
},
|
|
],
|
|
}
|
|
end
|
|
|
|
def spreadsheets_style
|
|
{
|
|
font_name: 'system-ui',
|
|
alignment: { horizontal: :left, vertical: :bottom }
|
|
}
|
|
end
|
|
end
|
|
end
|