Контроллер настроен на парсер, готово к PR
This commit is contained in:
@@ -9,6 +9,7 @@ gem "rails", "~> 7.1.3", ">= 7.1.3.2"
|
||||
gem "sidekiq" # background jobs processing
|
||||
gem 'httparty' # for http requests
|
||||
gem 'rubyzip' # for zip file processing
|
||||
gem 'roo', '~> 2.10' # for xlsx file parsing
|
||||
|
||||
# The original asset pipeline for Rails [https://github.com/rails/sprockets-rails]
|
||||
gem "sprockets-rails"
|
||||
|
||||
@@ -335,6 +335,9 @@ GEM
|
||||
request_store (1.7.0)
|
||||
rack (>= 1.4)
|
||||
rexml (3.3.9)
|
||||
roo (2.10.1)
|
||||
nokogiri (~> 1)
|
||||
rubyzip (>= 1.3.0, < 3.0.0)
|
||||
rspec-core (3.13.2)
|
||||
rspec-support (~> 3.13.0)
|
||||
rspec-expectations (3.13.3)
|
||||
@@ -496,6 +499,7 @@ DEPENDENCIES
|
||||
rack-cas!
|
||||
rails (~> 7.1.3, >= 7.1.3.2)
|
||||
redis (>= 4.0.1)
|
||||
roo (~> 2.10)
|
||||
rspec-rails (~> 6.1.0)
|
||||
rubyzip
|
||||
selenium-webdriver
|
||||
|
||||
@@ -1,17 +1,13 @@
|
||||
class AuditorsController < ApplicationController
|
||||
def index
|
||||
@info_about_auditors = {"A" => {"Наименование аудиторской организации/ФИО индивидуального аудитора" => "ООО \"Инвест-Аудит\"",
|
||||
"ИНН" => 7606073440,
|
||||
"ОГРН/ОРГНИП" => 1097606001250
|
||||
},
|
||||
"B" => {"Наименование аудиторской организации/ФИО индивидуального аудитора" => "ООО \"Инвест-Аудит\"",
|
||||
"ИНН" => 7606073440,
|
||||
"ОГРН/ОРГНИП" => 1097606001250
|
||||
},
|
||||
"C" => {"Наименование аудиторской организации/ФИО индивидуального аудитора" => "ООО \"Инвест-Аудит\"",
|
||||
"ИНН" => 7606073440,
|
||||
"ОГРН/ОРГНИП" => 1097606001250
|
||||
}
|
||||
}
|
||||
auditors = Auditor.all
|
||||
|
||||
@info_about_auditors = auditors.each_with_object({}) do |auditor, hash|
|
||||
hash[auditor.id] = {
|
||||
"Наименование аудиторской организации/ФИО индивидуального аудитора" => auditor.name,
|
||||
"ИНН" => auditor.inn,
|
||||
"ОГРН/ОРГНИП" => auditor.ogrn
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,33 +1,19 @@
|
||||
class WelcomeController < ApplicationController
|
||||
|
||||
def index
|
||||
@info_about_organisations = {"A" => {"ИНН" => 7707602010,
|
||||
"Полное наименование юридического лица" =>"Публичное акционерное общество \"М.видео\"",
|
||||
"КПП" => 770101001,
|
||||
"Код по ОКПО" => 71630621,
|
||||
"Форма собственности (по ОКФС)" => "34 Совместная частная и иностранная собственность",
|
||||
"Организационно-правовая форма (по ОКОПФ)" => "12247 Публичные акционерные общества",
|
||||
"Вид экономической деятельности по ОКВЭД 2" => "70.10.1",
|
||||
"Местонахождение (адрес)" => "105066, г. Москва, ул. Красносельская Нижн., д. 40/12, к. 20, пом. II"
|
||||
},
|
||||
"B" => {"ИНН" => 7707602010,
|
||||
"Полное наименование юридического лица" =>"Публичное акционерное общество \"М.видео\"",
|
||||
"КПП" => 770101001,
|
||||
"Код по ОКПО" => 71630621,
|
||||
"Форма собственности (по ОКФС)" => "34 Совместная частная и иностранная собственность",
|
||||
"Организационно-правовая форма (по ОКОПФ)" => "12247 Публичные акционерные общества",
|
||||
"Вид экономической деятельности по ОКВЭД 2" => "70.10.1",
|
||||
"Местонахождение (адрес)" => "105066, г. Москва, ул. Красносельская Нижн., д. 40/12, к. 20, пом. II"
|
||||
},
|
||||
"C" => {"ИНН" => 7707602010,
|
||||
"Полное наименование юридического лица" =>"Публичное акционерное общество \"М.видео\"",
|
||||
"КПП" => 770101001,
|
||||
"Код по ОКПО" => 71630621,
|
||||
"Форма собственности (по ОКФС)" => "34 Совместная частная и иностранная собственность",
|
||||
"Организационно-правовая форма (по ОКОПФ)" => "12247 Публичные акционерные общества",
|
||||
"Вид экономической деятельности по ОКВЭД 2" => "70.10.1",
|
||||
"Местонахождение (адрес)" => "105066, г. Москва, ул. Красносельская Нижн., д. 40/12, к. 20, пом. II"
|
||||
}
|
||||
}
|
||||
organizations = Organization.all
|
||||
|
||||
@info_about_organisations = organizations.each_with_object({}) do |org, hash|
|
||||
hash[org.id] = {
|
||||
"ИНН" => org.inn,
|
||||
"Полное наименование юридического лица" => org.full_name,
|
||||
"КПП" => org.kpp,
|
||||
"Код по ОКПО" => org.okpo,
|
||||
"Форма собственности (по ОКФС)" => org.okfs,
|
||||
"Организационно-правовая форма (по ОКОПФ)" => org.okopf,
|
||||
"Вид экономической деятельности по ОКВЭД 2" => org.okved2,
|
||||
"Местонахождение (адрес)" => org.address
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
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
|
||||
@@ -15,11 +15,26 @@ class FileProcessorJob
|
||||
|
||||
download_inn(inn, temp_dir.to_s)
|
||||
|
||||
# Найти или создать организацию по ИНН
|
||||
organization = Organization.find_or_create_by!(inn: inn)
|
||||
|
||||
Dir.glob("#{temp_dir}/**/*").select { |f| File.file?(f) }.each do |file_path|
|
||||
# Прикрепляем файл к Report (обратная совместимость)
|
||||
report.files.attach(
|
||||
io: File.open(file_path),
|
||||
filename: File.basename(file_path)
|
||||
)
|
||||
|
||||
# Создаём YearlyFile и прикрепляем xlsx
|
||||
yearly_file = organization.yearly_files.build(year: 0)
|
||||
yearly_file.file.attach(
|
||||
io: File.open(file_path),
|
||||
filename: File.basename(file_path)
|
||||
)
|
||||
yearly_file.save!
|
||||
|
||||
# Парсим данные из xlsx
|
||||
ReportParser.new(yearly_file).call
|
||||
end
|
||||
|
||||
# Удали временные файлы
|
||||
@@ -69,4 +84,4 @@ class FileProcessorJob
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user