SU2-30 | добавлена фикс таблица для кодов, убрана таблица DocumentTypes, изменена структура jsonb
This commit is contained in:
+126
-25
@@ -1,6 +1,27 @@
|
||||
require 'roo'
|
||||
|
||||
class ReportParser
|
||||
FORM_DEFINITIONS = {
|
||||
'1.1' => {
|
||||
parser: ReportParsers::Form11Parser,
|
||||
sheet_name: 'Бухгалтерский баланс'
|
||||
},
|
||||
'1.2' => {
|
||||
parser: ReportParsers::Form12Parser,
|
||||
sheet_name: 'Отчет о финансовых результатах'
|
||||
},
|
||||
'1.3' => {
|
||||
parser: nil,
|
||||
sheet_name: 'Отчет об изменениях капитала'
|
||||
},
|
||||
'1.4' => {
|
||||
parser: ReportParsers::Form14Parser,
|
||||
sheet_name: 'Отчет о движении денежных средств'
|
||||
}
|
||||
}.freeze
|
||||
|
||||
DEFAULT_MISSING_VALUE = '-'
|
||||
|
||||
def initialize(yearly_file)
|
||||
@yearly_file = yearly_file
|
||||
end
|
||||
@@ -9,13 +30,8 @@ class ReportParser
|
||||
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
|
||||
form_14_data = ReportParsers::Form14Parser.new(@yearly_file, spreadsheet: spreadsheet).call
|
||||
|
||||
save_form_statements(form_11_data, 1) # 1 - Бух. баланс
|
||||
save_form_statements(form_12_data, 2) # 2 - Отчет о фин. результатах
|
||||
save_form_statements(form_14_data, 4) # 4 - Отчет о движении денежных средств
|
||||
parsed_forms = parse_forms
|
||||
save_aggregated_statements(parsed_forms)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -31,34 +47,119 @@ class ReportParser
|
||||
end
|
||||
end
|
||||
|
||||
def save_form_statements(form_data, form_id)
|
||||
document_type = DocumentType.find_by(id: form_id)
|
||||
raise "DocumentType with id=#{form_id} not found!" unless document_type
|
||||
|
||||
form_data.each do |year, data|
|
||||
rows = data[:rows] || data['rows'] || []
|
||||
next if rows.blank?
|
||||
|
||||
statement = find_or_build_statement(document_type, year)
|
||||
payload = {
|
||||
data_year: year,
|
||||
rows: rows
|
||||
}
|
||||
statement.assign_attributes(data: payload)
|
||||
statement.save!
|
||||
def parse_forms
|
||||
FORM_DEFINITIONS.each_with_object({}) do |(form_code, config), hash|
|
||||
parser_class = config.fetch(:parser)
|
||||
hash[form_code] = parser_class ? parser_class.new(@yearly_file, spreadsheet: spreadsheet).call : {}
|
||||
end
|
||||
end
|
||||
|
||||
def find_or_build_statement(document_type, year)
|
||||
def save_aggregated_statements(parsed_forms)
|
||||
codes = report_codes
|
||||
return if codes.blank?
|
||||
|
||||
target_years = extract_target_years(parsed_forms)
|
||||
return if target_years.blank?
|
||||
|
||||
target_years.each do |year|
|
||||
statement = find_or_build_statement(year)
|
||||
if should_update_statement?(statement)
|
||||
statement.assign_attributes(
|
||||
yearly_file: @yearly_file,
|
||||
sheet_number: year,
|
||||
data: build_payload_for_year(year, parsed_forms, codes)
|
||||
)
|
||||
statement.save!
|
||||
end
|
||||
|
||||
cleanup_duplicate_statements(year, statement.id)
|
||||
end
|
||||
end
|
||||
|
||||
def extract_target_years(parsed_forms)
|
||||
years = parsed_forms.values.flat_map(&:keys).map(&:to_i).select(&:positive?).uniq
|
||||
years = [@yearly_file.year.to_i] if years.blank? && @yearly_file.year.to_i.positive?
|
||||
years.sort.reverse
|
||||
end
|
||||
|
||||
def build_payload_for_year(year, parsed_forms, codes)
|
||||
forms_payload = FORM_DEFINITIONS.each_with_object({}) do |(form_code, config), hash|
|
||||
form_data = parsed_forms.fetch(form_code, {})[year] || {}
|
||||
source_rows = form_data[:rows] || form_data['rows'] || []
|
||||
rows_by_code = index_rows_by_code(source_rows)
|
||||
|
||||
hash[form_code] = {
|
||||
form_code: form_code,
|
||||
sheet_name: form_data[:sheet_name] || form_data['sheet_name'] || config.fetch(:sheet_name),
|
||||
rows: codes.map do |report_code|
|
||||
source_row = rows_by_code[report_code.code]
|
||||
source_value = source_row && (source_row[:value] || source_row['value'])
|
||||
|
||||
{
|
||||
line_name: report_code.name,
|
||||
line_code: report_code.code,
|
||||
value: source_value.presence || DEFAULT_MISSING_VALUE
|
||||
}
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
{
|
||||
data_year: year,
|
||||
forms: forms_payload
|
||||
}
|
||||
end
|
||||
|
||||
def index_rows_by_code(rows)
|
||||
rows.each_with_object({}) do |row, hash|
|
||||
normalized_code = normalize_code(row[:line_code] || row['line_code'])
|
||||
next if normalized_code.blank?
|
||||
|
||||
# Keep first non-blank value for duplicated codes inside one form/year.
|
||||
existing = hash[normalized_code]
|
||||
next if existing.present? && (existing[:value] || existing['value']).present?
|
||||
|
||||
hash[normalized_code] = row
|
||||
end
|
||||
end
|
||||
|
||||
def find_or_build_statement(year)
|
||||
existing = FinancialStatement
|
||||
.joins(:yearly_file)
|
||||
.where(document_type: document_type, sheet_number: year)
|
||||
.where(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)
|
||||
@yearly_file.financial_statements.new(sheet_number: year)
|
||||
end
|
||||
|
||||
def should_update_statement?(statement)
|
||||
return true if statement.new_record?
|
||||
|
||||
existing_source_year = statement.yearly_file&.year.to_i
|
||||
current_source_year = @yearly_file.year.to_i
|
||||
|
||||
existing_source_year <= current_source_year
|
||||
end
|
||||
|
||||
def normalize_code(value)
|
||||
value.to_s.scan(/\d+/).join.presence
|
||||
end
|
||||
|
||||
def report_codes
|
||||
@report_codes ||= ReportCode.order(:code).select(:code, :name).to_a
|
||||
end
|
||||
|
||||
def cleanup_duplicate_statements(year, keeper_id)
|
||||
FinancialStatement
|
||||
.joins(:yearly_file)
|
||||
.where(sheet_number: year)
|
||||
.where(yearly_files: { organization_id: @yearly_file.organization_id })
|
||||
.where.not(id: keeper_id)
|
||||
.delete_all
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user