SU2-33 | Фикс критических и серьёзных ошибок, удаление/перезагрузка организации, пагинация, favicon
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" fill="none">
|
||||
<rect width="32" height="32" rx="6" fill="#1a1a1a"/>
|
||||
<rect x="5" y="22" width="5" height="6" rx="1" fill="white"/>
|
||||
<rect x="13" y="16" width="5" height="12" rx="1" fill="white"/>
|
||||
<rect x="21" y="10" width="5" height="18" rx="1" fill="white"/>
|
||||
<polyline points="7.5,18 15.5,12 23.5,6" stroke="#4ade80" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle cx="7.5" cy="18" r="1.5" fill="#4ade80"/>
|
||||
<circle cx="15.5" cy="12" r="1.5" fill="#4ade80"/>
|
||||
<circle cx="23.5" cy="6" r="1.5" fill="#4ade80"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 614 B |
@@ -104,3 +104,55 @@ a.link:hover {
|
||||
a.link:has(.active__button) {
|
||||
background-color: gray;
|
||||
}
|
||||
|
||||
nav.pagy {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
margin-block: 20px;
|
||||
font-size: 1.2rem;
|
||||
|
||||
a {
|
||||
padding: 4px 10px;
|
||||
border: 1px solid black;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
|
||||
&.current { font-weight: 700; }
|
||||
&[aria-disabled="true"] { opacity: 0.4; }
|
||||
&:not([aria-disabled="true"]):hover { background-color: black; color: white; }
|
||||
}
|
||||
}
|
||||
|
||||
.organisation-actions {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
margin-block: 16px;
|
||||
}
|
||||
|
||||
a.link-action {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
border: 1px solid black;
|
||||
border-radius: 20px;
|
||||
padding: 8px 16px;
|
||||
font-size: 1.2rem;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
|
||||
&:hover {
|
||||
background-color: black;
|
||||
color: var(--white-color);
|
||||
}
|
||||
|
||||
&.link-action--danger {
|
||||
border-color: #c0392b;
|
||||
color: #c0392b;
|
||||
|
||||
&:hover {
|
||||
background-color: #c0392b;
|
||||
color: var(--white-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,18 +28,13 @@ module Authorization
|
||||
session['cas'] && session['cas']['user']
|
||||
end
|
||||
|
||||
def set_current_user(options = {})
|
||||
return nil if current_login.blank?
|
||||
load_current_user
|
||||
end
|
||||
|
||||
def load_current_user
|
||||
@current_user ||= User.where('lower(login) = lower(?)', current_login).first
|
||||
end
|
||||
|
||||
def check_authentication
|
||||
if session.blank? || session['cas'].blank? || session['cas']['user'].blank? ||
|
||||
(request.get? && !request.xhr? && request.xhr? != 0 && (session['cas']['last_validated_at'].blank? || session['cas']['last_validated_at'] < 15.minutes.ago))
|
||||
(request.get? && !request.xhr? && (session['cas']['last_validated_at'].blank? || session['cas']['last_validated_at'] < 15.minutes.ago))
|
||||
render plain: 'Требуется авторизация', status: 401
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
class OrganisationsController < ApplicationController
|
||||
before_action :set_organisation, only: [:show]
|
||||
before_action :set_organisation, only: [:show, :destroy, :reload]
|
||||
|
||||
DOC_TYPES = {
|
||||
0 => { title: 'Бухгалтерский баланс', form_code: '1.1' },
|
||||
@@ -9,7 +9,7 @@ class OrganisationsController < ApplicationController
|
||||
}.freeze
|
||||
|
||||
def index
|
||||
organizations = Organization.all
|
||||
@pagy, organizations = pagy(Organization.order(:created_at))
|
||||
|
||||
@info_about_organisations = organizations.each_with_object({}) do |org, hash|
|
||||
hash[org.id] = {
|
||||
@@ -42,6 +42,17 @@ class OrganisationsController < ApplicationController
|
||||
end
|
||||
|
||||
|
||||
def destroy
|
||||
@org.destroy!
|
||||
redirect_to '/organisations/index', notice: "Организация #{@org.inn} удалена"
|
||||
end
|
||||
|
||||
def reload
|
||||
report = Report.create!(inn: @org.inn, status: 'processing')
|
||||
FileProcessorJob.perform_async(@org.inn, report.id)
|
||||
redirect_to "/organisations/#{@org.id}", notice: 'Данные обновляются в фоне'
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_organisation
|
||||
|
||||
@@ -4,9 +4,13 @@ class ReportsController < ApplicationController
|
||||
end
|
||||
|
||||
def create
|
||||
inn = params[:inn]
|
||||
report = Report.create!(inn: inn, status: 'processing')
|
||||
inn = params[:inn].to_s.strip
|
||||
unless inn.match?(/\A\d{10}(\d{2})?\z/)
|
||||
redirect_to reports_path, alert: 'Некорректный ИНН (должен содержать 10 или 12 цифр)'
|
||||
return
|
||||
end
|
||||
|
||||
report = Report.create!(inn: inn, status: 'processing')
|
||||
FileProcessorJob.perform_async(inn, report.id)
|
||||
|
||||
redirect_to reports_path, notice: 'Отчёт загружается в фоне'
|
||||
|
||||
@@ -25,7 +25,7 @@ module OrganisationsHelper
|
||||
end
|
||||
|
||||
def parse_number(value)
|
||||
return 0 if value.empty? || ['-', '(-)', 'X'].include?(value)
|
||||
return 0 if value.nil? || value.empty? || ['-', '(-)', 'X'].include?(value)
|
||||
negative = value.start_with?('(') && value.end_with?(')')
|
||||
value = value.tr('()', '') if negative
|
||||
value = value.delete(' ')
|
||||
|
||||
@@ -33,17 +33,19 @@ class ReportParser
|
||||
parsed_forms = parse_forms
|
||||
save_aggregated_statements(parsed_forms)
|
||||
end
|
||||
ensure
|
||||
@tempfile&.close!
|
||||
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)
|
||||
@tempfile = Tempfile.new(['report', '.xlsx'])
|
||||
@tempfile.binmode
|
||||
@yearly_file.file.download { |chunk| @tempfile.write(chunk) }
|
||||
@tempfile.rewind
|
||||
Roo::Excelx.new(@tempfile.path)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -202,7 +204,7 @@ class ReportParser
|
||||
end
|
||||
|
||||
def report_codes
|
||||
@report_codes ||= ReportCode.select(:code, :name).to_a
|
||||
@report_codes ||= ReportCode.select(:code, :name).order(:id).to_a
|
||||
end
|
||||
|
||||
def report_codes_for_form(form_code, codes)
|
||||
@@ -229,7 +231,7 @@ class ReportParser
|
||||
.where(sheet_number: year)
|
||||
.where(yearly_files: { organization_id: @yearly_file.organization_id })
|
||||
.where.not(id: keeper_id)
|
||||
.delete_all
|
||||
.destroy_all
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -6,11 +6,12 @@ class FileProcessorJob
|
||||
include Sidekiq::Job
|
||||
|
||||
def perform(inn, report_id)
|
||||
raise ArgumentError, "Некорректный ИНН: #{inn}" unless inn.to_s.match?(/\A\d{10}(\d{2})?\z/)
|
||||
|
||||
report = Report.find(report_id)
|
||||
Rails.logger.info "=== Начало загрузки для ИНН: #{inn} ==="
|
||||
|
||||
# Временная папка
|
||||
temp_dir = Rails.root.join('tmp', 'reports', inn)
|
||||
temp_dir = Rails.root.join('tmp', 'reports', inn.to_s.gsub(/[^0-9]/, ''))
|
||||
FileUtils.mkdir_p(temp_dir)
|
||||
|
||||
download_inn(inn, temp_dir.to_s)
|
||||
@@ -26,7 +27,9 @@ class FileProcessorJob
|
||||
)
|
||||
|
||||
# Создаём YearlyFile и прикрепляем xlsx
|
||||
yearly_file = organization.yearly_files.build(year: 0)
|
||||
year_from_filename = File.basename(file_path, '.*').split('_')[2].to_i
|
||||
year_from_filename = 0 unless (2000..2099).cover?(year_from_filename)
|
||||
yearly_file = organization.yearly_files.build(year: year_from_filename)
|
||||
yearly_file.file.attach(
|
||||
io: File.open(file_path),
|
||||
filename: File.basename(file_path)
|
||||
@@ -57,18 +60,28 @@ class FileProcessorJob
|
||||
'Accept-Language' => 'en-US,en;q=0.9',
|
||||
'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8'
|
||||
}
|
||||
content = HTTParty.get(url, headers: headers).body
|
||||
json_need ? JSON.parse(content) : content
|
||||
response = HTTParty.get(url, headers: headers, timeout: 30)
|
||||
raise "HTTP #{response.code} при запросе #{url}" unless response.success?
|
||||
|
||||
json_need ? JSON.parse(response.body) : response.body
|
||||
end
|
||||
|
||||
def download_inn(inn, output)
|
||||
url = "https://bo.nalog.gov.ru/advanced-search/organizations/search?query=#{inn}&page=0&size=20"
|
||||
content = get_content(url, true)
|
||||
id = content['content'][0]['id']
|
||||
org_entry = content.dig('content', 0) or raise "Организация с ИНН #{inn} не найдена"
|
||||
id = org_entry['id']
|
||||
|
||||
url = "https://bo.nalog.gov.ru/nbo/organizations/#{id}/bfo/"
|
||||
content = get_content(url, true)
|
||||
periods_and_details_ids = content.map { |item| [item['period'], item['typeCorrections'][0]['correction']['id']] }
|
||||
raise "Нет отчётности для организации #{id}" if content.blank?
|
||||
|
||||
periods_and_details_ids = content.filter_map do |item|
|
||||
details_id = item.dig('typeCorrections', 0, 'correction', 'id')
|
||||
next if details_id.nil?
|
||||
|
||||
[item['period'], details_id]
|
||||
end
|
||||
|
||||
periods_and_details_ids.each do |period, details_id|
|
||||
url = "https://bo.nalog.gov.ru/download/bfo/#{id}?auditReport=false&balance=true"\
|
||||
|
||||
@@ -7,9 +7,7 @@ html
|
||||
meta name="turbo-refresh-method" content="morph"
|
||||
= csrf_meta_tags
|
||||
= csp_meta_tag
|
||||
/ = favicon_link_tag 'favicon.ico'
|
||||
/ = favicon_link_tag 'favicon-32x32.png', sizes: '32x32'
|
||||
/ = favicon_link_tag 'apple-icon.png', rel: 'apple-touch-icon'
|
||||
= favicon_link_tag 'favicon.svg', type: 'image/svg+xml'
|
||||
= stylesheet_link_tag "tailwind", "inter-font", "data-turbo-track": "reload"
|
||||
= stylesheet_link_tag "application", media: "all", "data-turbo-track": "reload"
|
||||
script[async src="https://ga.jspm.io/npm:es-module-shims@1.8.2/dist/es-module-shims.js" data-turbo-track="reload"]
|
||||
|
||||
@@ -17,3 +17,4 @@
|
||||
.information-button
|
||||
a.link[href="/organisations/#{organisation}"]
|
||||
= "Подробнее"
|
||||
== pagy_nav(@pagy)
|
||||
|
||||
@@ -14,6 +14,17 @@
|
||||
- @info_about_organisation["Сведения об организации"].each do |key, value|
|
||||
.information-elem
|
||||
= "#{key}: #{value}"
|
||||
.organisation-actions
|
||||
= link_to "/organisations/#{@org.id}/reload",
|
||||
class: 'link-action',
|
||||
data: { turbo_method: :post, turbo_confirm: 'Перекачать данные с nalog.gov.ru?' } do
|
||||
i.bi.bi-arrow-clockwise
|
||||
| Обновить данные
|
||||
= link_to "/organisations/#{@org.id}",
|
||||
class: 'link-action link-action--danger',
|
||||
data: { turbo_method: :delete, turbo_confirm: 'Удалить организацию и все её данные? Это действие необратимо.' } do
|
||||
i.bi.bi-trash
|
||||
| Удалить
|
||||
= render 'organisations/templates/type_doc', target: "type_doc_#{@type_doc}", org_id: "#{@org.id}"
|
||||
h2
|
||||
= "#{@doc_name}"
|
||||
|
||||
Reference in New Issue
Block a user