require 'roo' class ReportParser SHEET_NAME = 'Сведения об организации' CELL_MAP = { full_name: { row: 6, col: 13 }, inn: { row: 10, col: 13 }, kpp: { row: 11, col: 13 }, okpo: { row: 12, col: 13 }, okfs: { row: 13, col: 13 }, okopf: { row: 14, col: 13 }, okved2: { row: 15, col: 13 }, address: { row: 16, col: 13 } }.freeze AUDITOR_MAP = { name: { row: 19, col: 13 }, inn: { row: 20, col: 13 }, ogrn: { row: 21, col: 13 } }.freeze def initialize(yearly_file) @yearly_file = yearly_file end def call ActiveRecord::Base.transaction do parse_organization parse_auditor extract_year 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 info_sheet @info_sheet ||= spreadsheet.sheet(SHEET_NAME) end def read_cell(sheet, row, col) value = sheet.cell(row, col) value.is_a?(String) ? value.strip.presence : value end def parse_organization org_data = CELL_MAP.each_with_object({}) do |(attr, pos), hash| hash[attr] = read_cell(info_sheet, pos[:row], pos[:col]) end organization = @yearly_file.organization organization.update!(org_data) organization end def parse_auditor auditor_data = AUDITOR_MAP.each_with_object({}) do |(attr, pos), hash| hash[attr] = read_cell(info_sheet, pos[:row], pos[:col]) end return if auditor_data[:name].blank? auditor_inn = auditor_data[:inn].to_s.strip auditor = if auditor_inn.present? Auditor.find_or_initialize_by(inn: auditor_inn) else Auditor.find_or_initialize_by(name: auditor_data[:name]) end auditor.assign_attributes( name: auditor_data[:name], inn: auditor_inn.presence, ogrn: auditor_data[:ogrn].to_s.strip.presence ) auditor.save! @yearly_file.update!(auditor: auditor) auditor end def extract_year balance_sheet = spreadsheet.sheet('Бухгалтерский баланс') period_text = balance_sheet.cell(4, 1).to_s year = period_text.match(/(\d{4})/)&.captures&.first&.to_i @yearly_file.update!(year: year) if year year end end