From 0dc0f10da7cf3f0e6e44e8a38bf3e88664a749f4 Mon Sep 17 00:00:00 2001 From: ARLakhin Date: Tue, 10 Mar 2026 23:44:59 +0300 Subject: [PATCH 1/5] Test layout --- app/assets/stylesheets/application.scss | 4 +- .../stylesheets/application_settings.scss | 39 +++++++++++++++++++ app/assets/stylesheets/main.scss | 29 ++++++++++++++ app/controllers/auditors_controller.rb | 18 +++++++++ app/controllers/welcome_controller.rb | 20 +++++++++- app/helpers/auditors_helper.rb | 2 + app/views/auditors/index.html.slim | 10 +++++ app/views/layouts/_navbar.html.slim | 1 + app/views/layouts/application.html.slim | 2 +- app/views/welcome/index.html.slim | 10 +++++ config/routes.rb | 3 +- spec/helpers/auditors_helper_spec.rb | 15 +++++++ spec/requests/auditors_spec.rb | 11 ++++++ .../auditors/index.html.tailwindcss_spec.rb | 5 +++ 14 files changed, 165 insertions(+), 4 deletions(-) create mode 100644 app/assets/stylesheets/application_settings.scss create mode 100644 app/assets/stylesheets/main.scss create mode 100644 app/controllers/auditors_controller.rb create mode 100644 app/helpers/auditors_helper.rb create mode 100644 app/views/auditors/index.html.slim create mode 100644 app/views/layouts/_navbar.html.slim create mode 100644 app/views/welcome/index.html.slim create mode 100644 spec/helpers/auditors_helper_spec.rb create mode 100644 spec/requests/auditors_spec.rb create mode 100644 spec/views/auditors/index.html.tailwindcss_spec.rb diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 263c9ba..31ab3a2 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -18,4 +18,6 @@ @use "jquery-ui/core"; @use "toastr"; - @use "base"; \ No newline at end of file + @use "base"; + @use "application_settings"; + @use "main"; \ No newline at end of file diff --git a/app/assets/stylesheets/application_settings.scss b/app/assets/stylesheets/application_settings.scss new file mode 100644 index 0000000..fd65cd1 --- /dev/null +++ b/app/assets/stylesheets/application_settings.scss @@ -0,0 +1,39 @@ +:root{ + --bg-color: #F3F3F5; + --navbar-border: #d3d3d3; + --blue-color: #0078F6; + --blue-light-color: #e5f1fe; + --text-callout-color: #B6B6B6; + --yellow-color: #F9D256; + --white-color: #fff; + --red-color: #EF3E3B; + --footer-text-color: #757575; + --purple-color: #4C13A2; + --green-color: #4CBFC0; + --orange-color: #FE9F40; + --grey-color: #C9CBCE; + --grey-light-color:#F6F6F6; + --grey-dark-color:#a9a9a9; + --border-dropdown-color: #e8e8e8; + --text-dropdown-color: #0F0F11; + --main-header-text: #7C7C7C; + +//TEXT weight + --bold: 700; + --semi-bold: 600; + --medium: 500; + --regular: 400; +} + +body { + font-family: 'Inter', sans-serif; + background-color: var(--bg-color); +} + +@media screen and (min-width: 1024px) { +.main-container.top-main{ + margin-left: 144px; + width: calc(100% - 144px); + // margin: 0 auto;] + // max-width: 1260px; +}} diff --git a/app/assets/stylesheets/main.scss b/app/assets/stylesheets/main.scss new file mode 100644 index 0000000..262e5e4 --- /dev/null +++ b/app/assets/stylesheets/main.scss @@ -0,0 +1,29 @@ +.header{ + width: 100vw; + text-align: center; +} + +.header-title { + font-size: 2.5rem; + font-weight: var(--bold); +} +.organisations-data { + display: flex; + flex-direction: column; + justify-content: space-between; + border: 8px solid black; + height: 100vh; + +} + + +.organisation-data { + border: 2px solid grey; + white-space: pre-line; + display: flex; + flex-direction: column; +} +.organisation-elem { + font-weight: var(--semi-bold); + font-size: 1.5rem; +} \ No newline at end of file diff --git a/app/controllers/auditors_controller.rb b/app/controllers/auditors_controller.rb new file mode 100644 index 0000000..bebf711 --- /dev/null +++ b/app/controllers/auditors_controller.rb @@ -0,0 +1,18 @@ +class AuditorsController < ApplicationController + def index + @auditors = ["A", "B", "C"] + @info_about_auditors = {"A" => {"ИНН" => 1000, + "Наименование" =>"ООО-БАШИР", + "ОГРН" => "123145" + }, + "B" => {"ИНН" => 1000, + "Наименование" =>"ООО-БАШИР", + "ОГРН" => "123145" + }, + "C" => {"ИНН" => 1000, + "Наименование" =>"ООО-БАШИР", + "ОГРН" => "123145" + } + } + end +end diff --git a/app/controllers/welcome_controller.rb b/app/controllers/welcome_controller.rb index 9b58bae..676ea47 100644 --- a/app/controllers/welcome_controller.rb +++ b/app/controllers/welcome_controller.rb @@ -1,4 +1,22 @@ class WelcomeController < ApplicationController - def home; end + def index + @organisations = ["A", "B", "C"] + @info_about_organisation = {"A" => {"ИНН" => 1000, + "Наименование" =>"ООО-БАШИР", + "КПП" => "123145", + "Код по ОКПО" => "123123", + }, + "B" => {"ИНН" => 1000, + "Наименование" =>"ООО-БАШИР", + "КПП" => "123145", + "Код по ОКПО" => "123123", + }, + "C" => {"ИНН" => 1000, + "Наименование" =>"ООО-БАШИР", + "КПП" => "123145", + "Код по ОКПО" => "123123", + } + } + end end diff --git a/app/helpers/auditors_helper.rb b/app/helpers/auditors_helper.rb new file mode 100644 index 0000000..6cab4b3 --- /dev/null +++ b/app/helpers/auditors_helper.rb @@ -0,0 +1,2 @@ +module AuditorsHelper +end diff --git a/app/views/auditors/index.html.slim b/app/views/auditors/index.html.slim new file mode 100644 index 0000000..44f92b8 --- /dev/null +++ b/app/views/auditors/index.html.slim @@ -0,0 +1,10 @@ +.header + .header-title + = "Аудиторы" +.main-container + .organisations-data + - @auditors.each do |auditor| + .organisation-data + - @info_about_auditors[auditor].keys.each do |key| + .organisation-elem + = "#{key}: #{@info_about_auditors[auditor][key]}" \ No newline at end of file diff --git a/app/views/layouts/_navbar.html.slim b/app/views/layouts/_navbar.html.slim new file mode 100644 index 0000000..eb924fd --- /dev/null +++ b/app/views/layouts/_navbar.html.slim @@ -0,0 +1 @@ +=render 'error', error: @error diff --git a/app/views/layouts/application.html.slim b/app/views/layouts/application.html.slim index df3e7b2..788579e 100644 --- a/app/views/layouts/application.html.slim +++ b/app/views/layouts/application.html.slim @@ -2,7 +2,7 @@ doctype html html head title - =t('app_name') + = "Отчетность 2026" meta[name="viewport" content="width=device-width,initial-scale=1"] meta name="turbo-refresh-method" content="morph" = csrf_meta_tags diff --git a/app/views/welcome/index.html.slim b/app/views/welcome/index.html.slim new file mode 100644 index 0000000..363b508 --- /dev/null +++ b/app/views/welcome/index.html.slim @@ -0,0 +1,10 @@ +.header + .header-title + = "Организации" +.main-container + .organisations-data + - @organisations.each do |organisation| + .organisation-data + - @info_about_organisation[organisation].keys.each do |key| + .organisation-elem + = "#{key}: #{@info_about_organisation[organisation][key]}" \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 5d9a41b..ff926e5 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,6 +1,7 @@ # require 'sidekiq/web' Rails.application.routes.draw do + get 'auditors/index' get 'reports/create' get '/reports', to: 'reports#index' post '/reports', to: 'reports#create' @@ -9,5 +10,5 @@ Rails.application.routes.draw do # Defines the root path route ("/") - root "welcome#home" + root "welcome#index" end diff --git a/spec/helpers/auditors_helper_spec.rb b/spec/helpers/auditors_helper_spec.rb new file mode 100644 index 0000000..56e693d --- /dev/null +++ b/spec/helpers/auditors_helper_spec.rb @@ -0,0 +1,15 @@ +require 'rails_helper' + +# Specs in this file have access to a helper object that includes +# the AuditorsHelper. For example: +# +# describe AuditorsHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# expect(helper.concat_strings("this","that")).to eq("this that") +# end +# end +# end +RSpec.describe AuditorsHelper, type: :helper do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/requests/auditors_spec.rb b/spec/requests/auditors_spec.rb new file mode 100644 index 0000000..6ed3516 --- /dev/null +++ b/spec/requests/auditors_spec.rb @@ -0,0 +1,11 @@ +require 'rails_helper' + +RSpec.describe "Auditors", type: :request do + describe "GET /index" do + it "returns http success" do + get "/auditors/index" + expect(response).to have_http_status(:success) + end + end + +end diff --git a/spec/views/auditors/index.html.tailwindcss_spec.rb b/spec/views/auditors/index.html.tailwindcss_spec.rb new file mode 100644 index 0000000..6183b41 --- /dev/null +++ b/spec/views/auditors/index.html.tailwindcss_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe "auditors/index.html.tailwindcss", type: :view do + pending "add some examples to (or delete) #{__FILE__}" +end From e55ecb7d293acdfe05202ae215c545009fb04e61 Mon Sep 17 00:00:00 2001 From: ARLakhin Date: Thu, 12 Mar 2026 10:14:15 +0300 Subject: [PATCH 2/5] Auditor/Organisation layouts --- .../stylesheets/application_settings.scss | 8 --- app/assets/stylesheets/main.scss | 66 +++++++++++++++++-- app/controllers/auditors_controller.rb | 19 +++--- app/controllers/welcome_controller.rb | 37 +++++++---- app/views/application/_header.html.slim | 2 + app/views/application/_navbar.html.slim | 5 ++ app/views/auditors/index.html.slim | 15 +++-- app/views/layouts/_navbar.html.slim | 1 - app/views/layouts/application.html.slim | 2 + app/views/welcome/index.html.slim | 18 +++-- 10 files changed, 122 insertions(+), 51 deletions(-) create mode 100644 app/views/application/_header.html.slim create mode 100644 app/views/application/_navbar.html.slim delete mode 100644 app/views/layouts/_navbar.html.slim diff --git a/app/assets/stylesheets/application_settings.scss b/app/assets/stylesheets/application_settings.scss index fd65cd1..a8e43dc 100644 --- a/app/assets/stylesheets/application_settings.scss +++ b/app/assets/stylesheets/application_settings.scss @@ -29,11 +29,3 @@ body { font-family: 'Inter', sans-serif; background-color: var(--bg-color); } - -@media screen and (min-width: 1024px) { -.main-container.top-main{ - margin-left: 144px; - width: calc(100% - 144px); - // margin: 0 auto;] - // max-width: 1260px; -}} diff --git a/app/assets/stylesheets/main.scss b/app/assets/stylesheets/main.scss index 262e5e4..89c714b 100644 --- a/app/assets/stylesheets/main.scss +++ b/app/assets/stylesheets/main.scss @@ -1,3 +1,38 @@ +.main-header { + width: 100vw; + text-align: center; + font-size: 2.5rem; + font-weight: var(--bold); +} + +.nav-container { + width: 20%; + margin: 0 auto; + display: flex; + justify-content: space-around; + +} + +.add-new { + text-align: center; + width: 100vw; + margin-block: 15px; +} + +a.link { + border: 1px solid black; + border-radius: 20px 20px; + padding: 10px; + font-size: 1.5rem; + +} + +a.link:hover { + background-color: black; + color: var(--white-color) + +} + .header{ width: 100vw; text-align: center; @@ -7,23 +42,40 @@ font-size: 2.5rem; font-weight: var(--bold); } -.organisations-data { + +.informations-data { display: flex; flex-direction: column; justify-content: space-between; - border: 8px solid black; height: 100vh; - + min-width: 300px; + max-width: 1200px; + margin: 0 auto; } +.vh-50-height { + height: 50vh; +} -.organisation-data { - border: 2px solid grey; - white-space: pre-line; +.information-data { + border: 2px solid black; display: flex; flex-direction: column; + padding: 5px; } -.organisation-elem { + +.information-elem { font-weight: var(--semi-bold); font-size: 1.5rem; + padding: 2.5px; +} + +.green { + color: green; +} + +.add-new-organisation { + border: 1px solid #ccc; + padding: 10px; + margin: 10px 0; } \ No newline at end of file diff --git a/app/controllers/auditors_controller.rb b/app/controllers/auditors_controller.rb index bebf711..1c963ee 100644 --- a/app/controllers/auditors_controller.rb +++ b/app/controllers/auditors_controller.rb @@ -1,17 +1,16 @@ class AuditorsController < ApplicationController def index - @auditors = ["A", "B", "C"] - @info_about_auditors = {"A" => {"ИНН" => 1000, - "Наименование" =>"ООО-БАШИР", - "ОГРН" => "123145" + @info_about_auditors = {"A" => {"Наименование аудиторской организации/ФИО индивидуального аудитора" => "ООО \"Инвест-Аудит\"", + "ИНН" => 7606073440, + "ОГРН/ОРГНИП" => 1097606001250 }, - "B" => {"ИНН" => 1000, - "Наименование" =>"ООО-БАШИР", - "ОГРН" => "123145" + "B" => {"Наименование аудиторской организации/ФИО индивидуального аудитора" => "ООО \"Инвест-Аудит\"", + "ИНН" => 7606073440, + "ОГРН/ОРГНИП" => 1097606001250 }, - "C" => {"ИНН" => 1000, - "Наименование" =>"ООО-БАШИР", - "ОГРН" => "123145" + "C" => {"Наименование аудиторской организации/ФИО индивидуального аудитора" => "ООО \"Инвест-Аудит\"", + "ИНН" => 7606073440, + "ОГРН/ОРГНИП" => 1097606001250 } } end diff --git a/app/controllers/welcome_controller.rb b/app/controllers/welcome_controller.rb index 676ea47..2eb0396 100644 --- a/app/controllers/welcome_controller.rb +++ b/app/controllers/welcome_controller.rb @@ -1,21 +1,32 @@ class WelcomeController < ApplicationController def index - @organisations = ["A", "B", "C"] - @info_about_organisation = {"A" => {"ИНН" => 1000, - "Наименование" =>"ООО-БАШИР", - "КПП" => "123145", - "Код по ОКПО" => "123123", + @info_about_organisations = {"A" => {"ИНН" => 7707602010, + "Полное наименование юридического лица" =>"Публичное акционерное общество \"М.видео\"", + "КПП" => 770101001, + "Код по ОКПО" => 71630621, + "Форма собственности (по ОКФС)" => "34 Совместная частная и иностранная собственность", + "Организационно-правовая форма (по ОКОПФ)" => "12247 Публичные акционерные общества", + "Вид экономической деятельности по ОКВЭД 2" => "70.10.1", + "Местонахождение (адрес)" => "105066, г. Москва, ул. Красносельская Нижн., д. 40/12, к. 20, пом. II" }, - "B" => {"ИНН" => 1000, - "Наименование" =>"ООО-БАШИР", - "КПП" => "123145", - "Код по ОКПО" => "123123", + "B" => {"ИНН" => 7707602010, + "Полное наименование юридического лица" =>"Публичное акционерное общество \"М.видео\"", + "КПП" => 770101001, + "Код по ОКПО" => 71630621, + "Форма собственности (по ОКФС)" => "34 Совместная частная и иностранная собственность", + "Организационно-правовая форма (по ОКОПФ)" => "12247 Публичные акционерные общества", + "Вид экономической деятельности по ОКВЭД 2" => "70.10.1", + "Местонахождение (адрес)" => "105066, г. Москва, ул. Красносельская Нижн., д. 40/12, к. 20, пом. II" }, - "C" => {"ИНН" => 1000, - "Наименование" =>"ООО-БАШИР", - "КПП" => "123145", - "Код по ОКПО" => "123123", + "C" => {"ИНН" => 7707602010, + "Полное наименование юридического лица" =>"Публичное акционерное общество \"М.видео\"", + "КПП" => 770101001, + "Код по ОКПО" => 71630621, + "Форма собственности (по ОКФС)" => "34 Совместная частная и иностранная собственность", + "Организационно-правовая форма (по ОКОПФ)" => "12247 Публичные акционерные общества", + "Вид экономической деятельности по ОКВЭД 2" => "70.10.1", + "Местонахождение (адрес)" => "105066, г. Москва, ул. Красносельская Нижн., д. 40/12, к. 20, пом. II" } } end diff --git a/app/views/application/_header.html.slim b/app/views/application/_header.html.slim new file mode 100644 index 0000000..acd29d3 --- /dev/null +++ b/app/views/application/_header.html.slim @@ -0,0 +1,2 @@ +.main-header + = 'Отчетность за 2026 год' \ No newline at end of file diff --git a/app/views/application/_navbar.html.slim b/app/views/application/_navbar.html.slim new file mode 100644 index 0000000..5f085fb --- /dev/null +++ b/app/views/application/_navbar.html.slim @@ -0,0 +1,5 @@ +.nav-container + a.link[href="/"] + = 'Организации' + a.link[href="/auditors/index"] + = 'Аудиторы' \ No newline at end of file diff --git a/app/views/auditors/index.html.slim b/app/views/auditors/index.html.slim index 44f92b8..9bd30af 100644 --- a/app/views/auditors/index.html.slim +++ b/app/views/auditors/index.html.slim @@ -2,9 +2,12 @@ .header-title = "Аудиторы" .main-container - .organisations-data - - @auditors.each do |auditor| - .organisation-data - - @info_about_auditors[auditor].keys.each do |key| - .organisation-elem - = "#{key}: #{@info_about_auditors[auditor][key]}" \ No newline at end of file + - unless @info_about_auditors.any? + = "Аудиторы не найдены" + - else + .informations-data.vh-50-height + - @info_about_auditors.each do |auditor, params| + .information-data + - params.keys.each do |key| + .information-elem + = "#{key}: #{params[key]}" \ No newline at end of file diff --git a/app/views/layouts/_navbar.html.slim b/app/views/layouts/_navbar.html.slim deleted file mode 100644 index eb924fd..0000000 --- a/app/views/layouts/_navbar.html.slim +++ /dev/null @@ -1 +0,0 @@ -=render 'error', error: @error diff --git a/app/views/layouts/application.html.slim b/app/views/layouts/application.html.slim index 788579e..03be6ca 100644 --- a/app/views/layouts/application.html.slim +++ b/app/views/layouts/application.html.slim @@ -16,4 +16,6 @@ html = javascript_importmap_tags = hotwire_livereload_tags if Rails.env.development? body + = render 'header' + = render 'navbar' = yield \ No newline at end of file diff --git a/app/views/welcome/index.html.slim b/app/views/welcome/index.html.slim index 363b508..f6c4b94 100644 --- a/app/views/welcome/index.html.slim +++ b/app/views/welcome/index.html.slim @@ -2,9 +2,15 @@ .header-title = "Организации" .main-container - .organisations-data - - @organisations.each do |organisation| - .organisation-data - - @info_about_organisation[organisation].keys.each do |key| - .organisation-elem - = "#{key}: #{@info_about_organisation[organisation][key]}" \ No newline at end of file + .add-new + a.link[href="/reports"] + = "Добавить новую организацию" + - unless @info_about_organisations.any? + = 'Организации не найдены' + - else + .informations-data + - @info_about_organisations.each do |organisation, params| + .information-data + - params.keys.each do |key| + .information-elem + = "#{key}: #{params[key]}" \ No newline at end of file From c016d6a31988e57a8ace3d9ad430bb8b8df0f441 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Thu, 12 Mar 2026 11:30:22 +0300 Subject: [PATCH 3/5] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D0=BC=D0=B8=D0=B3=D1=80=D0=B0=D1=86=D0=B8?= =?UTF-8?q?=D0=B9=20=D0=91=D0=94=20=D0=B8=20=D0=BC=D0=BE=D0=B4=D0=B5=D0=BB?= =?UTF-8?q?=D0=B5=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/auditor.rb | 3 + app/models/document_type.rb | 5 ++ app/models/financial_statement.rb | 6 ++ app/models/organization.rb | 6 ++ app/models/yearly_file.rb | 10 ++++ .../20260312000001_create_organizations.rb | 18 ++++++ db/migrate/20260312000002_create_auditors.rb | 13 +++++ .../20260312000003_create_document_types.rb | 9 +++ .../20260312000004_create_yearly_files.rb | 11 ++++ ...60312000005_create_financial_statements.rb | 12 ++++ db/schema.rb | 56 ++++++++++++++++++- 11 files changed, 148 insertions(+), 1 deletion(-) create mode 100644 app/models/auditor.rb create mode 100644 app/models/document_type.rb create mode 100644 app/models/financial_statement.rb create mode 100644 app/models/organization.rb create mode 100644 app/models/yearly_file.rb create mode 100644 db/migrate/20260312000001_create_organizations.rb create mode 100644 db/migrate/20260312000002_create_auditors.rb create mode 100644 db/migrate/20260312000003_create_document_types.rb create mode 100644 db/migrate/20260312000004_create_yearly_files.rb create mode 100644 db/migrate/20260312000005_create_financial_statements.rb diff --git a/app/models/auditor.rb b/app/models/auditor.rb new file mode 100644 index 0000000..e3056b6 --- /dev/null +++ b/app/models/auditor.rb @@ -0,0 +1,3 @@ +class Auditor < ApplicationRecord + has_many :yearly_files, dependent: :nullify +end diff --git a/app/models/document_type.rb b/app/models/document_type.rb new file mode 100644 index 0000000..17db798 --- /dev/null +++ b/app/models/document_type.rb @@ -0,0 +1,5 @@ +class DocumentType < ApplicationRecord + has_many :financial_statements, dependent: :restrict_with_error + + validates :name, presence: true +end diff --git a/app/models/financial_statement.rb b/app/models/financial_statement.rb new file mode 100644 index 0000000..427ad08 --- /dev/null +++ b/app/models/financial_statement.rb @@ -0,0 +1,6 @@ +class FinancialStatement < ApplicationRecord + belongs_to :yearly_file + belongs_to :document_type + + validates :data, presence: true +end diff --git a/app/models/organization.rb b/app/models/organization.rb new file mode 100644 index 0000000..4cedcd4 --- /dev/null +++ b/app/models/organization.rb @@ -0,0 +1,6 @@ +class Organization < ApplicationRecord + has_many :yearly_files, dependent: :destroy + has_many :financial_statements, through: :yearly_files + + validates :inn, presence: true +end diff --git a/app/models/yearly_file.rb b/app/models/yearly_file.rb new file mode 100644 index 0000000..d094f8a --- /dev/null +++ b/app/models/yearly_file.rb @@ -0,0 +1,10 @@ +class YearlyFile < ApplicationRecord + belongs_to :organization + belongs_to :auditor, optional: true + + has_many :financial_statements, dependent: :destroy + + has_one_attached :file + + validates :year, presence: true +end diff --git a/db/migrate/20260312000001_create_organizations.rb b/db/migrate/20260312000001_create_organizations.rb new file mode 100644 index 0000000..a2a2b19 --- /dev/null +++ b/db/migrate/20260312000001_create_organizations.rb @@ -0,0 +1,18 @@ +class CreateOrganizations < ActiveRecord::Migration[7.1] + def change + create_table :organizations do |t| + t.string :inn, null: false + t.string :full_name + t.string :kpp + t.string :okpo + t.string :okfs + t.string :okopf + t.string :okved2 + t.string :address + + t.timestamps + end + + add_index :organizations, :inn + end +end diff --git a/db/migrate/20260312000002_create_auditors.rb b/db/migrate/20260312000002_create_auditors.rb new file mode 100644 index 0000000..5edfe27 --- /dev/null +++ b/db/migrate/20260312000002_create_auditors.rb @@ -0,0 +1,13 @@ +class CreateAuditors < ActiveRecord::Migration[7.1] + def change + create_table :auditors do |t| + t.string :name + t.string :inn + t.string :ogrn + + t.timestamps + end + + add_index :auditors, :inn + end +end diff --git a/db/migrate/20260312000003_create_document_types.rb b/db/migrate/20260312000003_create_document_types.rb new file mode 100644 index 0000000..9b64f1c --- /dev/null +++ b/db/migrate/20260312000003_create_document_types.rb @@ -0,0 +1,9 @@ +class CreateDocumentTypes < ActiveRecord::Migration[7.1] + def change + create_table :document_types do |t| + t.string :name, null: false + + t.timestamps + end + end +end diff --git a/db/migrate/20260312000004_create_yearly_files.rb b/db/migrate/20260312000004_create_yearly_files.rb new file mode 100644 index 0000000..2604aba --- /dev/null +++ b/db/migrate/20260312000004_create_yearly_files.rb @@ -0,0 +1,11 @@ +class CreateYearlyFiles < ActiveRecord::Migration[7.1] + def change + create_table :yearly_files do |t| + t.references :organization, null: false, foreign_key: true + t.integer :year, null: false + t.references :auditor, foreign_key: true + + t.timestamps + end + end +end diff --git a/db/migrate/20260312000005_create_financial_statements.rb b/db/migrate/20260312000005_create_financial_statements.rb new file mode 100644 index 0000000..6aeaf71 --- /dev/null +++ b/db/migrate/20260312000005_create_financial_statements.rb @@ -0,0 +1,12 @@ +class CreateFinancialStatements < ActiveRecord::Migration[7.1] + def change + create_table :financial_statements do |t| + t.references :yearly_file, null: false, foreign_key: true + t.references :document_type, null: false, foreign_key: true + t.integer :sheet_number + t.jsonb :data, default: {} + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 6967052..7cab919 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2025_12_09_142642) do +ActiveRecord::Schema[7.1].define(version: 2026_03_12_000005) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -42,6 +42,46 @@ ActiveRecord::Schema[7.1].define(version: 2025_12_09_142642) do t.index ["blob_id", "variation_digest"], name: "index_active_storage_variant_records_uniqueness", unique: true end + create_table "auditors", force: :cascade do |t| + t.string "name" + t.string "inn" + t.string "ogrn" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["inn"], name: "index_auditors_on_inn" + end + + create_table "document_types", force: :cascade do |t| + t.string "name", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + create_table "financial_statements", force: :cascade do |t| + t.bigint "yearly_file_id", null: false + t.bigint "document_type_id", null: false + t.integer "sheet_number" + t.jsonb "data", default: {} + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["document_type_id"], name: "index_financial_statements_on_document_type_id" + t.index ["yearly_file_id"], name: "index_financial_statements_on_yearly_file_id" + end + + create_table "organizations", force: :cascade do |t| + t.string "inn", null: false + t.string "full_name" + t.string "kpp" + t.string "okpo" + t.string "okfs" + t.string "okopf" + t.string "okved2" + t.string "address" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["inn"], name: "index_organizations_on_inn" + end + create_table "reports", force: :cascade do |t| t.string "inn" t.string "status" @@ -76,6 +116,20 @@ ActiveRecord::Schema[7.1].define(version: 2025_12_09_142642) do t.index ["item_type", "item_id"], name: "index_versions_on_item_type_and_item_id" end + create_table "yearly_files", force: :cascade do |t| + t.bigint "organization_id", null: false + t.integer "year", null: false + t.bigint "auditor_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["auditor_id"], name: "index_yearly_files_on_auditor_id" + t.index ["organization_id"], name: "index_yearly_files_on_organization_id" + end + add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id" add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id" + add_foreign_key "financial_statements", "document_types" + add_foreign_key "financial_statements", "yearly_files" + add_foreign_key "yearly_files", "auditors" + add_foreign_key "yearly_files", "organizations" end From f973ec78df06608e30360ff1158874517ea4d677 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Thu, 12 Mar 2026 13:26:48 +0300 Subject: [PATCH 4/5] =?UTF-8?q?=D0=9A=D0=BE=D0=BD=D1=82=D1=80=D0=BE=D0=BB?= =?UTF-8?q?=D0=BB=D0=B5=D1=80=20=D0=BD=D0=B0=D1=81=D1=82=D1=80=D0=BE=D0=B5?= =?UTF-8?q?=D0=BD=20=D0=BD=D0=B0=20=D0=BF=D0=B0=D1=80=D1=81=D0=B5=D1=80,?= =?UTF-8?q?=20=D0=B3=D0=BE=D1=82=D0=BE=D0=B2=D0=BE=20=D0=BA=20PR?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Gemfile | 1 + Gemfile.lock | 4 ++ app/controllers/auditors_controller.rb | 22 +++--- app/controllers/welcome_controller.rb | 42 ++++------- app/services/report_parser.rb | 98 ++++++++++++++++++++++++++ app/sidekiq/file_processor_job.rb | 17 ++++- 6 files changed, 142 insertions(+), 42 deletions(-) create mode 100644 app/services/report_parser.rb diff --git a/Gemfile b/Gemfile index 7eb2513..6975eed 100644 --- a/Gemfile +++ b/Gemfile @@ -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" diff --git a/Gemfile.lock b/Gemfile.lock index 866345b..299c6c3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -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 diff --git a/app/controllers/auditors_controller.rb b/app/controllers/auditors_controller.rb index 1c963ee..bb0a4eb 100644 --- a/app/controllers/auditors_controller.rb +++ b/app/controllers/auditors_controller.rb @@ -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 diff --git a/app/controllers/welcome_controller.rb b/app/controllers/welcome_controller.rb index 2eb0396..83a8c4c 100644 --- a/app/controllers/welcome_controller.rb +++ b/app/controllers/welcome_controller.rb @@ -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 diff --git a/app/services/report_parser.rb b/app/services/report_parser.rb new file mode 100644 index 0000000..f277c92 --- /dev/null +++ b/app/services/report_parser.rb @@ -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 diff --git a/app/sidekiq/file_processor_job.rb b/app/sidekiq/file_processor_job.rb index a331ac5..7080ff5 100644 --- a/app/sidekiq/file_processor_job.rb +++ b/app/sidekiq/file_processor_job.rb @@ -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 \ No newline at end of file +end From 70f051da925fd6abab9682e61abb9ad297797041 Mon Sep 17 00:00:00 2001 From: ARLakhin Date: Sat, 21 Mar 2026 12:35:57 +0300 Subject: [PATCH 5/5] =?UTF-8?q?=D0=92=D0=B8=D0=B7=D1=83=D0=B0=D0=BB=D1=8C?= =?UTF-8?q?=D0=BD=D1=8B=D0=B5=20=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F=20=D0=BE=D1=81=D0=BD=D0=BE=D0=B2=D0=BD=D0=BE=D0=B9?= =?UTF-8?q?=20=D1=81=D1=82=D1=80=D0=B0=D0=BD=D0=B8=D1=87=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../stylesheets/application_settings.scss | 2 ++ app/assets/stylesheets/main.scss | 26 ++++++++----------- app/views/auditors/index.html.slim | 2 +- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/app/assets/stylesheets/application_settings.scss b/app/assets/stylesheets/application_settings.scss index a8e43dc..3cc73d4 100644 --- a/app/assets/stylesheets/application_settings.scss +++ b/app/assets/stylesheets/application_settings.scss @@ -28,4 +28,6 @@ body { font-family: 'Inter', sans-serif; background-color: var(--bg-color); + width: 90vw; + margin: 0 auto; } diff --git a/app/assets/stylesheets/main.scss b/app/assets/stylesheets/main.scss index 89c714b..44b28e8 100644 --- a/app/assets/stylesheets/main.scss +++ b/app/assets/stylesheets/main.scss @@ -1,5 +1,5 @@ .main-header { - width: 100vw; + width: 100%; text-align: center; font-size: 2.5rem; font-weight: var(--bold); @@ -15,7 +15,7 @@ .add-new { text-align: center; - width: 100vw; + width: 100%; margin-block: 15px; } @@ -34,7 +34,7 @@ a.link:hover { } .header{ - width: 100vw; + width: 100%; text-align: center; } @@ -43,18 +43,17 @@ a.link:hover { font-weight: var(--bold); } +.main-container { + height: 100vh; +} + .informations-data { display: flex; flex-direction: column; - justify-content: space-between; - height: 100vh; + width: 80%; min-width: 300px; max-width: 1200px; - margin: 0 auto; -} - -.vh-50-height { - height: 50vh; + margin: 0 auto 10px; } .information-data { @@ -62,6 +61,7 @@ a.link:hover { display: flex; flex-direction: column; padding: 5px; + margin: 20px; } .information-elem { @@ -70,12 +70,8 @@ a.link:hover { padding: 2.5px; } -.green { - color: green; -} - .add-new-organisation { border: 1px solid #ccc; padding: 10px; margin: 10px 0; -} \ No newline at end of file +} diff --git a/app/views/auditors/index.html.slim b/app/views/auditors/index.html.slim index 9bd30af..64f4870 100644 --- a/app/views/auditors/index.html.slim +++ b/app/views/auditors/index.html.slim @@ -5,7 +5,7 @@ - unless @info_about_auditors.any? = "Аудиторы не найдены" - else - .informations-data.vh-50-height + .informations-data - @info_about_auditors.each do |auditor, params| .information-data - params.keys.each do |key|