mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-02-03 22:06:07 +00:00
Each report can define formats for each column. But currency formatting was also applied to all columns that had "price" in the name. Removing this automation gives us more control and we can decide for each case. At the moment, the currency formatting in Excel spreadsheets is not ideal and it's easier to keep it as number. This PR introduces a visual regression as prices are not formatted as nicely but the columns can be used in calculations.
127 lines
3.4 KiB
Ruby
127 lines
3.4 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module Reporting
|
|
class ReportRowBuilder
|
|
include ActionView::Helpers::NumberHelper
|
|
include ActionView::Helpers::TagHelper
|
|
|
|
attr_reader :report
|
|
|
|
def initialize(report)
|
|
@report = report
|
|
end
|
|
|
|
# Compute the query result item into a result row
|
|
# We use OpenStruct to it's easier to access the properties
|
|
# i.e. row.my_field, rows.sum(&:quantity)
|
|
def build_row(item)
|
|
OpenStruct.new(
|
|
report.columns.transform_values do |column_constructor|
|
|
if column_constructor.is_a?(Symbol)
|
|
report.__send__(column_constructor, item)
|
|
else
|
|
column_constructor.call(item)
|
|
end
|
|
end
|
|
)
|
|
end
|
|
|
|
def slice_and_format_row(row)
|
|
result = row.to_h.reject { |k, _v| k.in?(report.fields_to_hide) }
|
|
unless report.raw_render?
|
|
result = result.map { |k, v| [k, format_cell(v, k)] }.to_h
|
|
end
|
|
OpenStruct.new(result)
|
|
end
|
|
|
|
def build_header(rule, group_value, group_datas)
|
|
return if rule[:header].blank?
|
|
|
|
rule[:header].call(group_value, group_datas.map(&:item), group_datas.map(&:full_row))
|
|
end
|
|
|
|
def build_summary_row(rule, group_value, datas)
|
|
return if rule[:summary_row].blank?
|
|
|
|
proc_args = [group_value, datas.map(&:item), datas.map(&:full_row)]
|
|
row = rule[:summary_row].call(*proc_args)
|
|
row = slice_and_format_row(OpenStruct.new(row.reverse_merge!(blank_row)))
|
|
add_summary_row_label(row, rule, proc_args)
|
|
end
|
|
|
|
private
|
|
|
|
def add_summary_row_label(row, rule, proc_args)
|
|
previous_key = nil
|
|
label = rule[:summary_row_label]
|
|
label = label.call(*proc_args) if label.respond_to?(:call)
|
|
# Adds Total before first non empty column
|
|
row.each_pair do |key, value|
|
|
if value.present? && previous_key.present? && row[previous_key].blank?
|
|
row[previous_key] = label and break
|
|
end
|
|
|
|
previous_key = key
|
|
end
|
|
row
|
|
end
|
|
|
|
def blank_row
|
|
report.columns.transform_values { |_v| "" }
|
|
end
|
|
|
|
# rubocop:disable Metrics/CyclomaticComplexity
|
|
def format_cell(value, column = nil)
|
|
return "" if value.nil?
|
|
|
|
# Currency
|
|
if report.columns_format[column] == :currency
|
|
format_currency(value)
|
|
# Quantity
|
|
elsif report.columns_format[column] == :quantity && report.html_render?
|
|
format_quantity(value)
|
|
# Numeric
|
|
elsif report.columns_format[column] == :numeric
|
|
format_numeric(value)
|
|
# Boolean
|
|
elsif value.in? [true, false]
|
|
format_boolean(value)
|
|
# Time
|
|
elsif value.is_a?(Time)
|
|
format_time(value)
|
|
# Date
|
|
elsif value.is_a?(Date)
|
|
format_date(value)
|
|
# Default
|
|
else
|
|
value
|
|
end
|
|
end
|
|
# rubocop:enable Metrics/CyclomaticComplexity
|
|
|
|
def format_currency(value)
|
|
value.present? ? number_to_currency(value, unit: Spree::Money.currency_symbol) : ""
|
|
end
|
|
|
|
def format_quantity(value)
|
|
content_tag(value > 1 ? :strong : :span, value)
|
|
end
|
|
|
|
def format_boolean(value)
|
|
value ? I18n.t(:yes) : I18n.t(:no)
|
|
end
|
|
|
|
def format_time(value)
|
|
value.to_datetime.in_time_zone.strftime "%Y-%m-%d %H:%M"
|
|
end
|
|
|
|
def format_date(value)
|
|
value.to_datetime.in_time_zone.strftime "%Y-%m-%d"
|
|
end
|
|
|
|
def format_numeric(value)
|
|
number_with_delimiter(value)
|
|
end
|
|
end
|
|
end
|