require 'roo' class ReportParser def initialize(yearly_file) @yearly_file = yearly_file end def call ActiveRecord::Base.transaction do ReportParsers::OrganizationInfoParser.new(@yearly_file, spreadsheet: spreadsheet).call form_11_data = ReportParsers::Form11Parser.new(@yearly_file, spreadsheet: spreadsheet).call form_12_data = ReportParsers::Form12Parser.new(@yearly_file, spreadsheet: spreadsheet).call merge_financial_statements(form_11_data, form_12_data) end end private def spreadsheet @spreadsheet ||= begin tempfile = Tempfile.new(['report', '.xlsx']) tempfile.binmode @yearly_file.file.download { |chunk| tempfile.write(chunk) } tempfile.rewind Roo::Excelx.new(tempfile.path) end end def merge_financial_statements(form_11_data, form_12_data) document_type = DocumentType.find_or_create_by!(name: 'Финансовые данные') all_years = (form_11_data.keys + form_12_data.keys).uniq all_years.each do |year| statement = find_or_build_statement(document_type, year) all_rows = [] if form_11_data[year].present? form_11_rows = form_11_data[year][:rows] || form_11_data[year]['rows'] || [] all_rows.concat(form_11_rows) end if form_12_data[year].present? form_12_rows = form_12_data[year][:rows] || form_12_data[year]['rows'] || [] all_rows.concat(form_12_rows) end if all_rows.present? payload = { data_year: year, rows: all_rows } statement.assign_attributes(data: payload) statement.save! end end end def find_or_build_statement(document_type, year) existing = FinancialStatement .joins(:yearly_file) .where(document_type: document_type, sheet_number: year) .where(yearly_files: { organization_id: @yearly_file.organization_id }) .order('yearly_files.year DESC NULLS LAST, financial_statements.updated_at DESC') .first return existing if existing @yearly_file.financial_statements.new(document_type: document_type, sheet_number: year) end end