diff --git a/.env b/.env index b24b3fc..602b71f 100644 --- a/.env +++ b/.env @@ -17,3 +17,5 @@ GOOGLE_APPLICATION_CREDENTIALS= GOOGLE_SHEET_ID= GOOGLE_SHEET_EXPORT_ID= GOOGLE_SHEET_SCRIPT_URL= + +API_URL= \ No newline at end of file diff --git a/.github/workflows/slovensko_digital_ci.yml b/.github/workflows/slovensko_digital_ci.yml index 45444a7..3eadbbb 100644 --- a/.github/workflows/slovensko_digital_ci.yml +++ b/.github/workflows/slovensko_digital_ci.yml @@ -28,7 +28,8 @@ jobs: with: bundler-cache: true - - run: bundle exec rails db:create db:schema:load --trace + - run: bundle exec rails db:create db:structure:load --trace + - run: RAILS_ENV=test_datahub bundle exec rails db:create db:structure:load DB_STRUCTURE=db/datahub_structure.sql --trace - run: bundle exec rspec gitlab-push: diff --git a/.ruby-version b/.ruby-version index 37c2961..6a81b4c 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -2.7.2 +2.7.8 diff --git a/Dockerfile b/Dockerfile index eca10a4..7070182 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM ruby:2.7.2 +FROM ruby:2.7.8 # Install packages RUN apt-get update && apt-get install -y build-essential nodejs libpq-dev diff --git a/Gemfile b/Gemfile index d1e5e00..fb0abbc 100644 --- a/Gemfile +++ b/Gemfile @@ -1,6 +1,6 @@ source 'https://rubygems.org' -ruby '2.7.2' +ruby '2.7.8' git_source(:github) do |repo_name| repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/") diff --git a/app/assets/images/acf.png b/app/assets/images/acf.png new file mode 100644 index 0000000..a9e0602 Binary files /dev/null and b/app/assets/images/acf.png differ diff --git a/app/assets/images/icons/ai_logo.png b/app/assets/images/icons/ai_logo.png new file mode 100644 index 0000000..34fded2 Binary files /dev/null and b/app/assets/images/icons/ai_logo.png differ diff --git a/app/assets/images/icons/metais_logo.png b/app/assets/images/icons/metais_logo.png new file mode 100644 index 0000000..d68c929 Binary files /dev/null and b/app/assets/images/icons/metais_logo.png differ diff --git a/app/assets/images/icons/sd_logo.png b/app/assets/images/icons/sd_logo.png new file mode 100644 index 0000000..178fca5 Binary files /dev/null and b/app/assets/images/icons/sd_logo.png differ diff --git a/app/assets/images/pontis_white.svg b/app/assets/images/pontis_white.svg new file mode 100644 index 0000000..9a636de --- /dev/null +++ b/app/assets/images/pontis_white.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/skdigital_biela.svg b/app/assets/images/skdigital_biela.svg new file mode 100644 index 0000000..a93f86c --- /dev/null +++ b/app/assets/images/skdigital_biela.svg @@ -0,0 +1,31 @@ + + + + skdigital_farba copy + Created with Sketch. + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/assets/images/us_embassy.png b/app/assets/images/us_embassy.png new file mode 100644 index 0000000..d06b56f Binary files /dev/null and b/app/assets/images/us_embassy.png differ diff --git a/app/assets/javascripts/metais/projects.js b/app/assets/javascripts/metais/projects.js new file mode 100644 index 0000000..a928944 --- /dev/null +++ b/app/assets/javascripts/metais/projects.js @@ -0,0 +1,61 @@ +$(document).ready(function() { + function openFilterSection(sectionId) { + var $filterSection = $('#' + sectionId); + if ($filterSection.length) { + $filterSection.toggleClass('show'); + } + } + + var urlParams = new URLSearchParams(window.location.search); + var status = urlParams.get('status'); + var guarantor = urlParams.get('guarantor'); + var code = urlParams.get('code'); + var minPrice = urlParams.get('min_price'); + var maxPrice = urlParams.get('max_price'); + var hasEvaluation = urlParams.get('has_evaluation'); + + if (status || guarantor || code || minPrice || maxPrice || hasEvaluation) { + openFilterSection('filterForm'); + } + + $('#filterButton').click(function() { + openFilterSection('filterForm'); + }); +}); + +$(document).ready(function() { + function updateDropdownColors() { + var urlParams = new URLSearchParams(window.location.search); + + var filters = [ + { param: 'status', buttonId: 'dropdownMenuButton' }, + { param: 'guarantor', buttonId: 'dropdownMenuButton2' }, + { param: 'code', buttonId: 'dropdownMenuButton3' }, + { param: 'min_price', buttonId: 'dropdownMenuButton4' }, + { param: 'has_evaluation', buttonId: 'dropdownMenuButton5' } + ]; + + filters.forEach(function(filter) { + var filterValue = urlParams.get(filter.param); + var $dropdownButton = $('#' + filter.buttonId); + + if (filterValue) { + $dropdownButton.addClass('btn-active').removeClass('btn-outline-primary').addClass('btn-primary'); + } else { + $dropdownButton.removeClass('btn-active').addClass('btn-outline-primary').removeClass('btn-primary'); + } + }); + } + + updateDropdownColors(); +}); + +function removeFilter(filter) { + if (filter === 'price') { + document.getElementById('min_price').value = ''; + document.getElementById('max_price').value = ''; + } else { + document.getElementById(filter).value = ''; + } + document.getElementById('form').submit(); + } \ No newline at end of file diff --git a/app/assets/javascripts/projects.js b/app/assets/javascripts/projects.js index 9f9d08f..36e1c25 100644 --- a/app/assets/javascripts/projects.js +++ b/app/assets/javascripts/projects.js @@ -13,3 +13,37 @@ document.addEventListener("turbolinks:load", function() { document.addEventListener("turbolinks:before-render", function() { window.printCalled = false; }); + +document.addEventListener('turbolinks:load', function () { + var sortDirectionField = document.getElementById('sort_direction'); + var sortButton = document.getElementById('ascdesctoggle'); + var upIcon = document.getElementById('up-icon'); + var downIcon = document.getElementById('down-icon'); + + if (sortDirectionField && sortButton && upIcon && downIcon) { + var toggleState = sortDirectionField.value || 'desc'; + + function updateIcons() { + if (toggleState === 'desc') { + upIcon.style.fill = 'rgba(100, 100, 100, 0.4)'; + downIcon.style.fill = 'rgb(56, 94, 255)'; + } else { + upIcon.style.fill = 'rgb(56, 94, 255)'; + downIcon.style.fill = 'rgba(100, 100, 100, 0.4)'; + } + } + + updateIcons(); + + sortButton.addEventListener('click', function (event) { + event.preventDefault(); + + toggleState = (toggleState === 'desc') ? 'asc' : 'desc'; + sortDirectionField.value = toggleState; + + updateIcons(); + + document.getElementById('form').submit(); + }); + } +}); \ No newline at end of file diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 82b5d3c..1d98e9c 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -6,7 +6,15 @@ @import 'projects'; @import 'static'; - +@import 'schedule'; +@import 'statuses'; +@import 'navbar'; +@import 'footer'; + +h1, h2, h3, h4, h5, h6 { + font-family: $headings-font-family; + font-weight: $font-weight-bold; +} .btn-outline-primary:hover { border-color: $link-hover-color; @@ -14,48 +22,15 @@ background-color: transparent; } -.navbar { - @include media-breakpoint-up(md) { - .navbar-brand img { - width: 240px; - } - } -} - -.container { - max-width: 1024px; +.table-title-item, .table-price { + font-family: $headings-font-family; + font-size: large; + color: $black; } -footer { - background-color: $gray-dark; - color: $white; - - a { - color: $white; - &:hover { - color: $white; - } - } - - .fa-inverse { - color: $gray-dark; - } - - .icons { - a:hover { - text-decoration: none; - } - } +#filterForm.collapsing { + transition: height 0.5s ease-out; - .newsletter { - .legal { - font-size: $small-font-size; - - a { - text-decoration: underline; - } - } - } } h1 .badge-alpha { diff --git a/app/assets/stylesheets/footer.scss b/app/assets/stylesheets/footer.scss new file mode 100644 index 0000000..ce3155b --- /dev/null +++ b/app/assets/stylesheets/footer.scss @@ -0,0 +1,85 @@ +footer { + background-color: $light_black; + color: $white; + + a { + color: $white; + &:hover { + color: $white; + } + } + + .fa-inverse { + color: $gray-dark; + } + + .icons { + a:hover { + text-decoration: none; + } + } + + .newsletter { + .legal { + font-size: $small-font-size; + + a { + text-decoration: underline; + } + } + } +} + +.footer-border { + border-left: 1px solid; + padding-left: 3rem; +} + +.footer-sk { + padding-right: 3rem; +} + +.pontis-logo { + width: 125px; +} + +.us-logo, .acf-logo { + width: 200px; +} +@media (max-width: 1200px) { + .pontis-logo { + width: 100px; + } + .us-logo, .acf-logo { + width: 175px; + } +} +@media (max-width: 992px) { + .pontis-logo { + width: 75px; + } + .us-logo, .acf-logo { + width: 150px; + } +} +@media (max-width: 768px) { + .responsive-img { + width: 125px; + } + .footer-border { + border-top: 1px solid; + border-left: none; + padding-left: 2rem; + padding-right: 2rem; + padding-top: 3rem; + } + .footer-sk { + padding-right: 0; + padding-bottom: 3rem; + } +} +@media (max-width: 576px) { + .responsive-img { + width: 100px; + } +} \ No newline at end of file diff --git a/app/assets/stylesheets/google-fonts.scss b/app/assets/stylesheets/google-fonts.scss index 44c13bf..749a37f 100644 --- a/app/assets/stylesheets/google-fonts.scss +++ b/app/assets/stylesheets/google-fonts.scss @@ -1,3 +1,5 @@ +@import url('https://fonts.googleapis.com/css2?family=Roboto+Mono&family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap'); + /* cyrillic-ext */ @font-face { font-family: 'Merriweather'; diff --git a/app/assets/stylesheets/navbar.scss b/app/assets/stylesheets/navbar.scss new file mode 100644 index 0000000..d047c9e --- /dev/null +++ b/app/assets/stylesheets/navbar.scss @@ -0,0 +1,29 @@ +.navbar { + @include media-breakpoint-up(md) { + .navbar-brand img { + width: 100%; + } + } +} + +.navbar-light .navbar-nav .nav-link { + font-weight: $font-weight-semi-bold; + transition: 0.2s ease-in-out; + color: $black; +} + +.navbar-light .navbar-nav .nav-link:focus { + color: $black; +} + +.navbar-light .navbar-nav .nav-link:hover { + color: $blue; +} + +.navbar-light .navbar-nav .nav-link:active { + color: $blue; +} + +.navbar-light .navbar-nav .nav-item.active .nav-link { + color: $blue; +} \ No newline at end of file diff --git a/app/assets/stylesheets/projects.scss b/app/assets/stylesheets/projects.scss index 52293af..2c8acfe 100644 --- a/app/assets/stylesheets/projects.scss +++ b/app/assets/stylesheets/projects.scss @@ -1,6 +1,6 @@ #project-show { @include media-breakpoint-up(md) { - padding-top: 6rem; + padding-top: 3rem; } .full-description { @@ -109,13 +109,12 @@ img.emoji { } .accordion:after { - font-family: 'Merriweather'; - font-size: $h3-font-size; - content: "-"; + color: $black; + font-size: medium; + text-decoration: underline; + content: "Schovať hodnotené kritériá"; } .accordion.collapsed:after { - font-family: 'Merriweather'; - font-size: $h3-font-size; - content: "+"; + content: "Zobraziť hodnotené kritériá"; } diff --git a/app/assets/stylesheets/schedule.scss b/app/assets/stylesheets/schedule.scss new file mode 100644 index 0000000..dc40fe4 --- /dev/null +++ b/app/assets/stylesheets/schedule.scss @@ -0,0 +1,100 @@ +.card { + position: relative; + display: flex; + flex-direction: column; + min-width: 100%; + word-wrap: break-word; +} + +.card-body { + flex: 1 1 auto; + padding: 1.25rem; +} +.vertical-timeline { + width: 100%; + position: relative; + padding: 1.5rem 0 1rem; +} + +.vertical-timeline::before { + content: ''; + position: absolute; + top: 0; + left: 67px; + height: 100%; + width: 4px; + background: #e9ecef; +} + +.vertical-timeline-element { + position: relative; + margin: 0 0 1rem; +} + +.vertical-timeline--animate .vertical-timeline-element-icon.bounce-in { + visibility: visible; + animation: cd-bounce-1 .8s; +} +.vertical-timeline-element-icon { + position: absolute; + top: 0; + left: 60px; +} + +.vertical-timeline-element-icon .badge-dot-xl { + box-shadow: 0 0 0 5px #fff; +} + +.badge-dot-xl { + width: 18px; + height: 18px; + position: relative; +} +.badge:empty { + display: none; +} + + +.badge-dot-xl::before { + content: ''; + width: 10px; + height: 10px; + border-radius: .25rem; + position: absolute; + left: 50%; + top: 50%; + margin: -5px 0 0 -5px; + background: #fff; +} + +.vertical-timeline-element-content { + position: relative; + margin-left: 90px; + font-size: .8rem; +} + +.vertical-timeline-element-content .timeline-title { + font-size: .8rem; + text-transform: uppercase; + margin: 0 0 .5rem; + padding: 2px 0 0; + font-weight: bold; +} + +.vertical-timeline-element-content .vertical-timeline-element-date { + display: block; + position: absolute; + left: -100px; + top: 0; + padding-right: 10px; + text-align: right; + color: #000000; + font-size: .7619rem; + white-space: nowrap; +} + +.vertical-timeline-element-content:after { + content: ""; + display: table; + clear: both; +} \ No newline at end of file diff --git a/app/assets/stylesheets/statuses.scss b/app/assets/stylesheets/statuses.scss new file mode 100644 index 0000000..5bb3566 --- /dev/null +++ b/app/assets/stylesheets/statuses.scss @@ -0,0 +1,85 @@ +.state-badge { + border: 1px solid; + border-radius: 5px; + padding: 2px 10px; + font-size: 0.75rem; + font-weight: 500; +} + +.status-1 { + background-color: rgb(254, 242, 242); + color: rgb(185, 28, 28); + border-color: rgba(220, 38, 38, 0.25); +} + +.status-2 { + background-color: rgb(240, 253, 244); + color: rgb(21, 128, 61); + border-color: rgba(22, 163, 74, 0.25); +} + +.status-3 { + background-color: rgb(239, 246, 255); + color: rgb(29, 78, 216); + border-color: rgba(29, 78, 216, 0.25); +} + +.status-4 { + background-color: rgb(254, 252, 232); + color: rgb(133, 77, 14); + border-color: rgba(202, 138, 4, 0.25); +} + +.status-5 { + background-color: rgb(238, 242, 255); + color: rgb(67, 56, 202); + border-color: rgba(67, 56, 202, 0.25); +} + +.status-6 { + background-color: rgb(250, 245, 255); + color: rgb(126, 34, 206); + border-color: rgba(126, 34, 206, 0.25); +} + +.status-7 { + background-color: rgb(253, 242, 248); + color: rgb(190, 24, 93); + border-color: rgba(190, 24, 93, 0.25); +} + +.status-8 { + background-color: rgb(255, 247, 237); + color: rgb(194, 65, 12); + border-color: rgba(194, 65, 12, 0.25); +} + +.status-9 { + background-color: rgb(240, 253, 250); + color: rgb(20, 184, 166); + border-color: rgba(20, 184, 166, 0.25); +} + +.status-10 { + background-color: rgb(236, 254, 255); + color: rgb(6, 182, 212); + border-color: rgba(6, 182, 212, 0.25); +} + +.status-11 { + background-color: rgb(253, 244, 255); + color: rgb(162, 28, 175); + border-color: rgba(162, 28, 175, 0.25); +} + +.status-12 { + background-color: rgb(255, 241, 242); + color: rgb(225, 29, 72); + border-color: rgba(225, 29, 72, 0.25); +} + +.status-13 { + background-color: rgb(247, 254, 231); + color: rgb(132, 204, 22); + border-color: rgba(132, 204, 22, 0.25); +} \ No newline at end of file diff --git a/app/assets/stylesheets/variables.scss b/app/assets/stylesheets/variables.scss index 6a1f64a..6e55215 100644 --- a/app/assets/stylesheets/variables.scss +++ b/app/assets/stylesheets/variables.scss @@ -1,3 +1,5 @@ +$black: #000000; +$light_black: #141617; $gray-dark: #373a3c; $gray: #55595c; $gray-light: #818a91; @@ -5,7 +7,7 @@ $gray-lighter: #c4c3ca; $gray-lightest: #f4f4f4; $color-highlight: lightgoldenrodyellow; -$blue: #3a67e8; +$blue: #385EFF; $orange: #ffac33; $theme-colors: ( @@ -19,10 +21,12 @@ $theme-colors: ( dark: $gray-dark ); -$headings-font-family: 'Merriweather', 'Georgia', 'Times New Roman', serif; +$headings-font-family: 'Roboto Mono', 'Georgia', 'Times New Roman', serif; $font-family-sans-serif: 'Roboto', sans-serif; $font-weight-normal: 300; +$font-weight-semi-bold: 500; $font-weight-bold: 700; +$font-weight-black: 900; $modal-backdrop-bg: white; $modal-backdrop-opacity: .7; diff --git a/app/controllers/admin/metais/project_origins_controller.rb b/app/controllers/admin/metais/project_origins_controller.rb new file mode 100644 index 0000000..fc6351e --- /dev/null +++ b/app/controllers/admin/metais/project_origins_controller.rb @@ -0,0 +1,202 @@ +class Admin::Metais::ProjectOriginsController < ApplicationController + before_action :set_project, only: [:craete, :edit, :update, :add_event, :add_supplier, :add_link, :add_document, :remove_event, :remove_supplier, :remove_link, :remove_document, :update_group_order] + + def create + @project_origin = @project.project_origins.build(project_origin_params) + if @project_origin.save + redirect_to admin_metais_project_path(@project), notice: 'Projekt bol úspešne vytvorený.' + else + render :new + end + end + + def edit + @project_info = @project.get_project_origin_info + + @project_origins = @project.project_origins + @project_origin = @project_origins.find(params[:id]) + + @assumption_events = @project_origins.flat_map { |project_origin| project_origin.events.assumpted } + @real_events = @project_origins.flat_map { |project_origin| project_origin.events.real } + + @combined_suppliers = @project_origins.flat_map(&:suppliers).sort_by { |supplier| supplier.date || Time.zone.parse('2999-12-31') } + @combined_links = @project_origins.flat_map(&:links) + @combined_documents = @project_origins.flat_map(&:documents) + + @grouped_documents = @combined_documents.group_by(&:description).sort_by { |description, docs| docs.first.group_order || Float::INFINITY } + end + + def update + @project_origin = @project.project_origins.find(params[:id]) + current_project_info = @project.get_project_origin_info + + changed_params = detect_changes(current_project_info, project_origin_params.to_h) + + if changed_params.any? && @project_origin.update(changed_params) + redirect_to edit_admin_metais_project_project_origin_path(@project, @project_origin), notice: 'Projekt bol úspešne aktualizovaný.' + else + redirect_to edit_admin_metais_project_project_origin_path(@project, @project_origin), notice: 'Žiadne nové informácie v projekte.' + end + end + + def add_event + @project_origin = @project.project_origins.find(params[:project_origin_id]) + @event = @project_origin.events.build(event_params) + + if @event.save + redirect_to edit_admin_metais_project_project_origin_path(@project, @project_origin), notice: 'Aktivita bola úspešné pridaná.' + else + redirect_to edit_admin_metais_project_project_origin_path(@project, @project_origin), alert: "Nastala chyba pri vytváraní aktivity: #{@event.errors.full_messages.to_sentence}" + end + end + + def add_supplier + @project_origin = @project.project_origins.find(params[:project_origin_id]) + @supplier = @project_origin.suppliers.build(supplier_params) + + if @supplier.save + redirect_to edit_admin_metais_project_project_origin_path(@project, @project_origin), notice: 'Dodávateľ bol úspešné pridaný.' + else + redirect_to edit_admin_metais_project_project_origin_path(@project, @project_origin), alert: "Nastala chyba pri vytváraní dodávateľa: #{@event.errors.full_messages.to_sentence}" + end + end + + def add_link + @project_origin = @project.project_origins.find(params[:project_origin_id]) + @link = @project_origin.links.build(link_params) + + if @link.save + redirect_to edit_admin_metais_project_project_origin_path(@project, @project_origin), notice: 'Link bol úspešné pridaný.' + else + redirect_to edit_admin_metais_project_project_origin_path(@project, @project_origin), alert: "Nastala chyba pri vytváraní linku: #{@event.errors.full_messages.to_sentence}" + end + end + + def add_document + @project_origin = @project.project_origins.find(params[:project_origin_id]) + @document = @project_origin.documents.build(document_params) + + if @document.save + redirect_to edit_admin_metais_project_project_origin_path(@project, @project_origin), notice: 'Dokument bol úspešné pridaný.' + else + redirect_to edit_admin_metais_project_project_origin_path(@project, @project_origin), alert: "Nastala chyba pri vytváraní dokumentu: #{@event.errors.full_messages.to_sentence}" + end + end + + def remove_event + @project_origin = @project.project_origins.find(params[:project_origin_id]) + @project_event = @project_origin.events.find(params[:event_id]) + + if @project_event.destroy + redirect_to edit_admin_metais_project_project_origin_path(@project, @project_origin), notice: 'Aktivita bola úspešne odstránená z harmonogramu.' + else + redirect_to edit_admin_metais_project_project_origin_path(@project, @project_origin), alert: 'Nastala chyba pri odstraňovaní aktivity z harmonogramu.' + end + end + + def remove_supplier + @project_origin = @project.project_origins.find(params[:project_origin_id]) + @project_supplier = @project_origin.suppliers.find(params[:supplier_id]) + + if @project_supplier.destroy + redirect_to edit_admin_metais_project_project_origin_path(@project, @project_origin), notice: 'Dodávateľ bol úspešne odstránený.' + else + redirect_to edit_admin_metais_project_project_origin_path(@project, @project_origin), alert: 'Nastala chyba pri odstraňovaní dodávateľa.' + end + end + + def remove_link + @project_origin = @project.project_origins.find(params[:project_origin_id]) + @project_link = @project_origin.links.find(params[:link_id]) + + if @project_link.destroy + redirect_to edit_admin_metais_project_project_origin_path(@project, @project_origin), notice: 'Link bol úspešne odstránený.' + else + redirect_to edit_admin_metais_project_project_origin_path(@project, @project_origin), alert: 'Nastala chyba pri odstraňovaní linku.' + end + end + + def remove_document + @project_origin = @project.project_origins.find(params[:project_origin_id]) + @project_document = @project_origin.documents.find(params[:document_id]) + + if @project_document.destroy + redirect_to edit_admin_metais_project_project_origin_path(@project, @project_origin), notice: 'Dokument bol úspešne odstránený.' + else + redirect_to edit_admin_metais_project_project_origin_path(@project, @project_origin), alert: 'Nastala chyba pri odstraňovaní dokumentu.' + end + end + + def update_group_order + @project_origin = @project.project_origins.find(params[:project_origin_id]) + + description = params[:description] + group_order = params[:group_order].to_i + + Metais::ProjectDocument.where(description: description).update_all(group_order: group_order) + + flash[:notice] = "Zoskupenie dokumentov bolo úspešne updatované." + redirect_to edit_admin_metais_project_project_origin_path(@project, @project_origin) + end + + private + + def set_project + @project = Metais::Project.find(params[:project_id]) + end + + def project_origin_params + params.require(:metais_project_origin).permit(:title, :description, :guarantor, :project_manager, :start_date, :end_date, :status, :phase, :finance_source, :investment, :operation, :approved_investment, :approved_operation, :supplier, :supplier_cin, :targets_text, :documents_text, :links_text, project_events: [:name, :value, :date]) + end + + def event_params + origin_type = Metais::OriginType.find_by(name: params[:event][:origin_type]) + event_type = Metais::ProjectEventType.find_by(name: params[:event][:event_type]) + params.require(:event).permit(:name, :value, :date).merge(origin_type: origin_type, event_type: event_type) + end + + def supplier_params + origin_type = Metais::OriginType.find_by(name: params[:supplier][:origin_type]) + supplier_type = Metais::SupplierType.find(params[:supplier][:supplier_type]) + params.require(:supplier).permit(:name, :value).merge(name: params[:supplier][:value], origin_type: origin_type, supplier_type: supplier_type) + end + + def link_params + origin_type = Metais::OriginType.find_by(name: params[:link][:origin_type]) + params.require(:link).permit(:name, :value).merge(origin_type: origin_type) + end + + def document_params + origin_type = Metais::OriginType.find_by(name: params[:document][:origin_type]) + params.require(:document).permit(:name, :value, :description).merge(origin_type: origin_type) + end + + def detect_changes(current_project_info, new_params) + finance_source_mappings = Metais::Project::FINANCE_SOURCE_MAPPINGS + changed_params = {} + + new_params.each do |field, new_value| + current_value = current_project_info.send(field) + + if field == 'finance_source' + current_value_mapped = finance_source_mappings[current_value] || current_value + new_value_mapped = finance_source_mappings[new_value] || new_value + + if new_value.present? && new_value_mapped.to_s.strip != current_value_mapped.to_s.strip + changed_params[field] = new_value + end + else + if %w[end_date start_date].include?(field) + new_value = new_value.present? ? Date.parse(new_value.to_s) : nil + current_value = current_value.present? ? current_value.to_date : nil + end + + if new_value.present? && new_value.to_s.strip != current_value.to_s.strip + changed_params[field] = new_value + end + end + end + + changed_params + end +end diff --git a/app/controllers/admin/metais/projects_controller.rb b/app/controllers/admin/metais/projects_controller.rb new file mode 100644 index 0000000..d40a9b0 --- /dev/null +++ b/app/controllers/admin/metais/projects_controller.rb @@ -0,0 +1,31 @@ +class Admin::Metais::ProjectsController < AdminController + def index + @guarantor_counts = Metais::ProjectOrigin.guarantor_counts + @unique_guarantors = Metais::ProjectOrigin.unique_guarantors + @status_counts = Metais::ProjectOrigin.status_counts + @unique_statuses = Metais::ProjectOrigin.unique_statuses + @evaluation_counts = Metais::Project.evaluation_counts + + @projects = Metais::Project.filtered_and_sorted_projects(params) + end + + def create_human_origin + @project = Metais::Project.find(params[:id]) + origin_type = Metais::OriginType.find_by(name: 'Human') + fail 'OriginType not found' unless origin_type + + human_origin = Metais::ProjectOrigin.find_or_initialize_by(project: @project, origin_type: origin_type) + if human_origin.new_record? + human_origin.title = @project.project_origins.first.title + human_origin.save! + end + redirect_to edit_admin_metais_project_project_origin_path(@project, human_origin) + end + + def run_ai_extraction + @project = Metais::Project.find(params[:id]) + Metais::ProjectDataExtractionJob.perform_later(@project.uuid) + + redirect_to admin_metais_projects_path, notice: 'Projekt bol zaradený na spracovanie.' + end +end diff --git a/app/controllers/admin/pages_controller.rb b/app/controllers/admin/pages_controller.rb index d6ae40c..8de3e6a 100644 --- a/app/controllers/admin/pages_controller.rb +++ b/app/controllers/admin/pages_controller.rb @@ -20,6 +20,7 @@ def preview @phase_revision = @phase.revisions.find_by(revision: @page.revisions.find_by(version: params['version'])) end @ratings_by_type = @phase_revision.ratings.index_by(&:rating_type) + @project = @phase.project else if params['version'] == 'latest' diff --git a/app/controllers/metais/projects_controller.rb b/app/controllers/metais/projects_controller.rb new file mode 100644 index 0000000..9440d59 --- /dev/null +++ b/app/controllers/metais/projects_controller.rb @@ -0,0 +1,27 @@ +class Metais::ProjectsController < ApplicationController + + def index + @guarantor_counts = Metais::ProjectOrigin.guarantor_counts + @unique_guarantors = Metais::ProjectOrigin.unique_guarantors + @status_counts = Metais::ProjectOrigin.status_counts + @unique_statuses = Metais::ProjectOrigin.unique_statuses + @evaluation_counts = Metais::Project.evaluation_counts + + @projects = Metais::Project.filtered_and_sorted_projects(params) + end + + def show + @project = Metais::Project.find(params[:id]) + @project_info = @project.get_project_origin_info + @project_origins = @project.project_origins + + @assumption_events = @project_origins.flat_map { |project_origin| project_origin.events.assumpted } + @real_events = @project_origins.flat_map { |project_origin| project_origin.events.real } + + @combined_suppliers = @project_origins.flat_map(&:suppliers).sort_by { |supplier| supplier.date || Time.zone.parse('2999-12-31') } + @combined_links = @project_origins.flat_map(&:links) + @combined_documents = @project_origins.flat_map(&:documents) + + @grouped_documents = @combined_documents.group_by(&:description).sort_by { |description, docs| docs.first.group_order || Float::INFINITY } + end +end diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 83b39cd..31f91de 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -1,7 +1,7 @@ class ProjectsController < ApplicationController - + def index - @selected_tag = params[:tag] - @projects = Project.filtered_projects(@selected_tag, params[:sort]) + @projects = Project.filtered_and_sorted_projects(params) end + end diff --git a/app/controllers/static_controller.rb b/app/controllers/static_controller.rb index 4cd8d44..b540e4f 100644 --- a/app/controllers/static_controller.rb +++ b/app/controllers/static_controller.rb @@ -2,8 +2,8 @@ class StaticController < ApplicationController def index top_project_revisions = PhaseRevision.where(published: true).joins(:revision).limit(5) - @good_projects = top_project_revisions.where('phase_revisions.redflags_count = ?', 0).order('phase_revisions.total_score::float / phase_revisions.maximum_score DESC') - @bad_projects = top_project_revisions.order('phase_revisions.redflags_count DESC, phase_revisions.total_score::float / phase_revisions.maximum_score ASC') + @good_projects = top_project_revisions.where('phase_revisions.redflags_count = ? AND phase_revisions.maximum_score > 0', 0).order('phase_revisions.total_score::float / phase_revisions.maximum_score DESC') + @bad_projects = top_project_revisions.where('phase_revisions.maximum_score > 0').order('phase_revisions.redflags_count DESC, phase_revisions.total_score::float / phase_revisions.maximum_score ASC') end def about diff --git a/app/helpers/metais/projects_helper.rb b/app/helpers/metais/projects_helper.rb new file mode 100644 index 0000000..280499c --- /dev/null +++ b/app/helpers/metais/projects_helper.rb @@ -0,0 +1,33 @@ +module Metais::ProjectsHelper + def origin_type_logo(origin_type) + if origin_type.is_a?(Integer) + case origin_type + when 3 + ['icons/sd_logo.png', 'Ručne vyplnený údaj od Slovensko.Digital'] + when 2 + ['icons/ai_logo.png', 'Údaj spracovaný naším AI extraktorom'] + else + ['icons/metais_logo.png', 'Údaj pochádzajúci z MetaIS portálu'] + end + else + case origin_type.name + when 'Human' + ['icons/sd_logo.png', 'Ručne vyplnený údaj od Slovensko.Digital'] + when 'AI' + ['icons/ai_logo.png', 'Údaj spracovaný naším AI extraktorom'] + else + ['icons/metais_logo.png', 'Údaj pochádzajúci z MetaIS portálu'] + end + end +end + + def convert_to_list(text) + items = text.split('\n') + + list_items = items.map do |item| + ActionController::Base.helpers.sanitize("
  • #{item}
  • ") + end + + ActionController::Base.helpers.sanitize("") + end +end diff --git a/app/jobs/link_metais_projects_and_evaluations_job.rb b/app/jobs/link_metais_projects_and_evaluations_job.rb new file mode 100644 index 0000000..4d1e355 --- /dev/null +++ b/app/jobs/link_metais_projects_and_evaluations_job.rb @@ -0,0 +1,21 @@ +class LinkMetaisProjectsAndEvaluationsJob < ApplicationJob + queue_as :default + + def perform + Project.find_each do |project| + link_metais_project(project) + end + end + + private + + def link_metais_project(project) + code = project.metais_code + metais_project = Metais::Project.find_by(code: code) + return unless metais_project + + unless project.metais_projects.exists?(metais_project.id) + project.metais_projects << metais_project + end + end +end \ No newline at end of file diff --git a/app/jobs/metais/daily_sync_projects_job.rb b/app/jobs/metais/daily_sync_projects_job.rb new file mode 100644 index 0000000..895bd0a --- /dev/null +++ b/app/jobs/metais/daily_sync_projects_job.rb @@ -0,0 +1,13 @@ +class Metais::DailySyncProjectsJob < ApplicationJob + queue_as :metais + + def perform + Datahub::Metais::Project.where('updated_at > ?', Time.now - 1.day).find_each do |metais_project| + project = Metais::Project.find_or_initialize_by(code: metais_project.latest_version.kod_metais, + uuid: metais_project.uuid) + project.save! + + Metais::SyncProjectJob.perform_later(project, metais_project) + end + end +end diff --git a/app/jobs/metais/initial_sync_projects_job.rb b/app/jobs/metais/initial_sync_projects_job.rb new file mode 100644 index 0000000..884145d --- /dev/null +++ b/app/jobs/metais/initial_sync_projects_job.rb @@ -0,0 +1,13 @@ +class Metais::InitialSyncProjectsJob < ApplicationJob + queue_as :metais + + def perform + Datahub::Metais::Project.find_each do |metais_project| + project = Metais::Project.find_or_initialize_by(code: metais_project.latest_version.kod_metais, + uuid: metais_project.uuid) + project.save! + + Metais::SyncProjectJob.perform_later(project, metais_project) + end + end +end diff --git a/app/jobs/metais/project_data_extraction_delete_job.rb b/app/jobs/metais/project_data_extraction_delete_job.rb new file mode 100644 index 0000000..3461df8 --- /dev/null +++ b/app/jobs/metais/project_data_extraction_delete_job.rb @@ -0,0 +1,21 @@ +require 'net/http' +require 'uri' + +class Metais::ProjectDataExtractionDeleteJob < ApplicationJob + queue_as :metais_data_extraction + + def perform(project_uuid) + url = "#{ENV.fetch('API_URL')}/projects/#{project_uuid}" + uri = URI(url) + + req = Net::HTTP::Delete.new(uri) + res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') do |http| + http.request(req) + end + + unless res.is_a?(Net::HTTPSuccess) + error_message = "Failed to delete project: #{res.code}, body: #{res.body}" + raise RuntimeError, error_message + end + end +end diff --git a/app/jobs/metais/project_data_extraction_job.rb b/app/jobs/metais/project_data_extraction_job.rb new file mode 100644 index 0000000..227c3c9 --- /dev/null +++ b/app/jobs/metais/project_data_extraction_job.rb @@ -0,0 +1,24 @@ +require 'net/http' +require 'uri' + +class Metais::ProjectDataExtractionJob < ApplicationJob + queue_as :metais_data_extraction + + def perform(project_uuid) + url = "#{ENV.fetch('API_URL')}/projects/#{project_uuid}" + response = Net::HTTP.post(URI(url), '') + + unless response.is_a?(Net::HTTPAccepted) + error_message = "Response status is #{response.code}. Message: #{response.body}" + raise RuntimeError, error_message + end + + location = response['Location'] + if location.nil? + error_message = "Expected 'Location' header not found in the response." + raise RuntimeError, error_message + end + + Metais::ProjectDataExtractionStatusJob.perform_later(project_uuid, location) + end +end diff --git a/app/jobs/metais/project_data_extraction_result_job.rb b/app/jobs/metais/project_data_extraction_result_job.rb new file mode 100644 index 0000000..d3c3944 --- /dev/null +++ b/app/jobs/metais/project_data_extraction_result_job.rb @@ -0,0 +1,111 @@ +require 'net/http' +require 'uri' +require 'json' + +class Metais::ProjectDataExtractionResultJob < ApplicationJob + queue_as :metais_data_extraction + + def perform(project_uuid, location_header) + url = "#{ENV.fetch('API_URL')}/projects/#{project_uuid}" + response = Net::HTTP.get_response(URI(url)) + + handle_response_errors(response) + + body = parse_json(response.body) + raise RuntimeError.new('Result status is not "Done"') unless body['status'] == 'Done' + + result = body['result'] + + unless ['No documents', 'No documents for project plan'].include? result['detail'] + metais_project = find_metais_project(project_uuid) + project_origin = find_or_initialize_project_origin(metais_project) + + update_project_origin(project_origin, result) + process_harmonogram(result['harmonogram'], project_origin) + end + + Metais::ProjectDataExtractionDeleteJob.perform_later(project_uuid) + end + + private + + def handle_response_errors(response) + case response.code.to_i + when 200, 202 + else + error_message = "Unexpected response status: #{response.code}, body: #{response.body}" + raise RuntimeError, error_message + end + end + + def parse_json(body) + JSON.parse(body) + rescue JSON::ParserError => e + error_message = "Failed to parse JSON response: #{e.message}" + raise RuntimeError, error_message + end + + def find_metais_project(project_uuid) + Metais::Project.find_by(uuid: project_uuid).tap do |project| + unless project + error_message = "Couldn't find MetaIS project with 'uuid'=#{project_uuid}" + raise RuntimeError, error_message + end + end + end + + def find_or_initialize_project_origin(metais_project) + metais_project.project_origins.find_or_initialize_by(title: metais_project.project_origins.first.title, + project: metais_project, + origin_type: Metais::OriginType.find_by(name: 'AI')) + end + + def update_project_origin(project_origin, result) + project_origin.project_manager = "#{result['responsible']['first_name']} #{result['responsible']['surname']}" + project_origin.approved_investment = result['capex'] unless result['capex'].zero? + project_origin.approved_operation = result['opex'] unless result['opex'].zero? + project_origin.benefits = result['declared'] unless result['declared'].zero? + project_origin.targets_text = format_targets_text(result) unless format_targets_text(result).empty? + project_origin.save! + end + + def format_targets_text(result) + kpis = result['kpis'].join("\n") unless result['kpis'].empty? + goals = result['goals'].join("\n") unless result['goals'].empty? + [kpis, goals].compact.join("\n") + end + + def process_harmonogram(harmonogram, project_origin) + origin_type = Metais::OriginType.find_by(name: 'AI') + event_type = Metais::ProjectEventType.find_by(name: 'Predpoklad') + + harmonogram.each do |event_data| + event_start_date = event_data['start_date'] || 'N/A' + event_end_date = event_data['end_date'] || 'N/A' + event_date = parse_event_date(event_data['start_date']) + event_name = event_data['item_name'] unless event_data['item_name'].empty? + event_value = "Projektu bude v stave #{event_data['item_name'].downcase} od #{event_start_date} do #{event_end_date}" + + project_event = Metais::ProjectEvent.find_or_initialize_by( + project_origin: project_origin, + origin_type: origin_type, + event_type: event_type, + name: event_name, + value: event_value, + date: event_date + ) + + unless project_event.save + error_message = "Error encountered while creating an event: #{project_event.errors.full_messages.to_sentence}" + raise RuntimeError, error_message + end + end + end + + def parse_event_date(start_date) + return if start_date.blank? + Date.strptime(start_date, "%m/%Y") + rescue ArgumentError => e + raise RuntimeError, e + end +end diff --git a/app/jobs/metais/project_data_extraction_status_job.rb b/app/jobs/metais/project_data_extraction_status_job.rb new file mode 100644 index 0000000..0827951 --- /dev/null +++ b/app/jobs/metais/project_data_extraction_status_job.rb @@ -0,0 +1,17 @@ +class Metais::ProjectDataExtractionStatusJob < ApplicationJob + queue_as :metais_data_extraction + + def perform(project_uuid, location_header) + url = "#{ENV.fetch('API_URL')}/projects/#{project_uuid}/status" + response = Net::HTTP.get_response(URI(url)) + + if response.key?('Retry-After') + Metais::ProjectDataExtractionStatusJob.set(wait: response['Retry-After'].to_i.seconds).perform_later(project_uuid, location_header) + else + location = response['Location'] + raise "Location header missing in response" unless location + + Metais::ProjectDataExtractionResultJob.perform_later(project_uuid, location) + end + end +end diff --git a/app/jobs/metais/sync_project_documents_job.rb b/app/jobs/metais/sync_project_documents_job.rb new file mode 100644 index 0000000..8b68a17 --- /dev/null +++ b/app/jobs/metais/sync_project_documents_job.rb @@ -0,0 +1,17 @@ +class Metais::SyncProjectDocumentsJob < ApplicationJob + queue_as :metais + + def perform(project_origin, metais_project) + metais_project.documents.each do |document| + project_document = Metais::ProjectDocument.find_or_initialize_by(uuid: document.uuid, + project_origin: project_origin, + origin_type: Metais::OriginType.find_by(name: 'MetaIS')) + + project_document.name = document.latest_version.nazov + project_document.filename = document.latest_version.filename + project_document.value = 'https://metais.vicepremier.gov.sk/dms/file/' + document.uuid + project_document.description = "MetaIS" + project_document.save! + end + end +end diff --git a/app/jobs/metais/sync_project_events_job.rb b/app/jobs/metais/sync_project_events_job.rb new file mode 100644 index 0000000..0f49aa3 --- /dev/null +++ b/app/jobs/metais/sync_project_events_job.rb @@ -0,0 +1,43 @@ +class Metais::SyncProjectEventsJob < ApplicationJob + queue_as :metais + + def perform(project_origin, metais_project) + origin_type = Metais::OriginType.find_by(name: 'MetaIS') + event_type = Metais::ProjectEventType.find_by(name: 'Realita') + project_changes = Datahub::Metais::ProjectChange.where(project_version: metais_project.latest_version) + + project_changes.each do |change| + if change.field == 'status' + event_date = change.created_at + event_name = Datahub::Metais::CodelistProjectState.find_by(code: change.new_value)&.nazov || change.new_value + event_value = "Stav projektu bol zmenený z + #{Datahub::Metais::CodelistProjectState.find_by(code: change.old_value)&.nazov.downcase || change.new_value.downcase} na + #{Datahub::Metais::CodelistProjectState.find_by(code: change.new_value)&.nazov.downcase || change.new_value.downcase}" + + project_event = Metais::ProjectEvent.find_or_initialize_by(project_origin: project_origin, + origin_type: origin_type, + event_type: event_type, + name: event_name, + value: event_value, + date: event_date) + project_event.save! + + elsif change.field == 'faza_projektu' + event_date = change.created_at + event_name = Datahub::Metais::CodelistProjectPhase.find_by(code: change.new_value)&.nazov || change.new_value + event_value = "Fáza projektu bola zmenená z + #{Datahub::Metais::CodelistProjectPhase.find_by(code: change.old_value)&.nazov.downcase || change.old_value.downcase} na + #{Datahub::Metais::CodelistProjectPhase.find_by(code: change.new_value)&.nazov.downcase || change.new_value.downcase}" + + project_event = Metais::ProjectEvent.find_or_initialize_by(project_origin: project_origin, + origin_type: origin_type, + event_type: event_type, + name: event_name, + value: event_value, + date: event_date) + project_event.save! + + end + end + end +end diff --git a/app/jobs/metais/sync_project_job.rb b/app/jobs/metais/sync_project_job.rb new file mode 100644 index 0000000..eb28e60 --- /dev/null +++ b/app/jobs/metais/sync_project_job.rb @@ -0,0 +1,32 @@ +class Metais::SyncProjectJob < ApplicationJob + queue_as :metais + + def perform(project, metais_project) + project_origin = Metais::ProjectOrigin.find_or_initialize_by(project: project, + origin_type: Metais::OriginType.find_by(name: 'MetaIS')) + + project_origin.title = metais_project.latest_version.nazov + project_origin.description = metais_project.latest_version.popis + project_origin.status = Datahub::Metais::CodelistProjectState.find_by(code: metais_project.latest_version.status)&.nazov || metais_project.latest_version.status + project_origin.phase = Datahub::Metais::CodelistProjectPhase.find_by(code: metais_project.latest_version.faza_projektu)&.nazov || metais_project.latest_version.faza_projektu + project_origin.guarantor = metais_project.latest_version.prijimatel + + project_origin.metais_created_at = metais_project.latest_version.metais_created_at + project_origin.start_date = metais_project.latest_version.datum_zacatia + project_origin.end_date = metais_project.latest_version.termin_ukoncenia + project_origin.status_change_date = metais_project.latest_version.zmena_stavu + + project_origin.finance_source = Datahub::Metais::CodelistProgram.find_by(uuid: metais_project.latest_version.program)&.nazov || metais_project.latest_version.program + project_origin.investment = metais_project.latest_version.suma_vydavkov + project_origin.operation = metais_project.latest_version.rocne_naklady + project_origin.approved_investment = metais_project.latest_version.schvaleny_rozpocet + project_origin.approved_operation = metais_project.latest_version.schvalene_rocne_naklady + + project_origin.save! + + Metais::ProjectDataExtractionJob.set(wait: 5.minutes).perform_later(metais_project.uuid) + Metais::SyncProjectSuppliersJob.perform_later(project_origin, metais_project) + Metais::SyncProjectDocumentsJob.perform_later(project_origin, metais_project) + Metais::SyncProjectEventsJob.perform_later(project_origin, metais_project) + end +end diff --git a/app/jobs/metais/sync_project_suppliers_job.rb b/app/jobs/metais/sync_project_suppliers_job.rb new file mode 100644 index 0000000..d7d4fb5 --- /dev/null +++ b/app/jobs/metais/sync_project_suppliers_job.rb @@ -0,0 +1,117 @@ +require 'open-uri' +require 'nokogiri' + +class Metais::SyncProjectSuppliersJob < ApplicationJob + queue_as :metais + + def perform(project_origin, metais_project) + origin_type = Metais::OriginType.find_by(name: 'MetaIS') + + if metais_project.latest_version.link_nfp.present? + supplier_type = Metais::SupplierType.find_by(name: "NFP") + + link = metais_project.latest_version.link_nfp + + links = extract_links(link) + links.each do |url| + if valid_url?(url) + project_supplier = Metais::ProjectSupplier.find_or_initialize_by( + name: url, + value: url, + date: metais_project.latest_version.datum_nfp, + project_origin: project_origin, + origin_type: origin_type, + supplier_type: supplier_type) + + project_supplier.save! + end + end + end + + if metais_project.latest_version.vo.present? + supplier_type = Metais::SupplierType.find_by(name: "VO") + + link = metais_project.latest_version.vo + + links = extract_links(link) + links.each do |url| + if valid_url?(url) + project_supplier = Metais::ProjectSupplier.find_or_initialize_by( + name: url, + value: url, + date: metais_project.latest_version.vyhlasenie_vo, + project_origin: project_origin, + origin_type: origin_type, + supplier_type: supplier_type) + + project_supplier.save! + end + end + end + + if metais_project.latest_version.zmluva_o_dielo_crz.present? + supplier_type = Metais::SupplierType.find_by(name: "CRZ") + + link = metais_project.latest_version.zmluva_o_dielo_crz + + document = Nokogiri::HTML(open(link).read.force_encoding('UTF-8')) + crz_data = parse_crz_document(document) + + if crz_data[:supplier] && crz_data[:cin] + project_origin.supplier = crz_data[:supplier] + project_origin.supplier_cin = crz_data[:cin] + project_origin.save! + end + + links = extract_links(link) + links.each do |url| + if valid_url?(url) + project_supplier = Metais::ProjectSupplier.find_or_initialize_by( + name: url, + value: url, + date: metais_project.latest_version.zmluva_o_dielo, + project_origin: project_origin, + origin_type: origin_type, + supplier_type: supplier_type) + + project_supplier.save! + end + end + + end + end + + private + + def valid_url?(url) + uri = URI.parse(url) + uri.kind_of?(URI::HTTP) || uri.kind_of?(URI::HTTPS) + rescue URI::InvalidURIError + false + end + + def extract_links(str) + uri_regexp = /\b(?:https?|ftp):\/\/\S+\b/ + str.to_s.scan(uri_regexp) + end + + def parse_crz_document(document) + li_elements = document.css('li.py-2.border-top') + supplier_info = nil + cin = nil + + li_elements.each_with_index do |li_element, i| + supplier_label = li_element.at_css('strong.col-sm-3.text-sm-end')&.text&.strip + if supplier_label == 'Dodávateľ:' + supplier_info = li_element.at_css('span.col-sm-9')&.text&.strip + cin_label = li_elements[i + 1].at_css('strong.col-sm-3.text-sm-end')&.text&.strip + if cin_label == 'IČO:' + cin = li_elements[i + 1].at_css('span.col-sm-9')&.text&.strip + break if supplier_info && cin + end + end + end + + { supplier: supplier_info, cin: cin } + end +end diff --git a/app/jobs/set_metais_codes_for_projects_job.rb b/app/jobs/set_metais_codes_for_projects_job.rb new file mode 100644 index 0000000..44ef198 --- /dev/null +++ b/app/jobs/set_metais_codes_for_projects_job.rb @@ -0,0 +1,93 @@ +class SetMetaisCodesForProjectsJob < ApplicationJob + queue_as :default + + MAPPING = { + 9241 => 2477, + 8848 => 1734, + 8989 => nil, + 4284 => 326, + 7705 => 1097, + 8467 => 1840, + 4228 => 1552, + 6349 => 1616, + 6175 => 320, + 6054 => 515, + 8024 => 1247, + 8972 => 2263, + 6257 => 329, + 8119 => 1450, + 6258 => 491, + 4288 => 692, + 7713 => 1154, + 5599 => 476, + 4211 => 487, + 5645 => 471, + 5909 => nil, + 5033 => 346, + 6215 => 530, + 4493 => 347, + 4196 => 327, + 7712 => 1060, + 5048 => 376, + 4929 => 368, + 6309 => 578, + 4237 => 2545, + 6018 => 514, + 6350 => 565, + 4576 => 307, + 4599 => nil, + 6040 => 489, + 4283 => nil, + 8026 => 991, + 6216 => nil, + 5637 => 457, + 6308 => nil, + 6352 => nil, + 6017 => 483, + 5916 => 508, + 8255 => 1594, + 4898 => 473, + 5641 => 380, + 4431 => 361, + 4287 => nil, + 5640 => 1159, + 4035 => 611, + 4263 => 490, + 4262 => nil, + 8320 => 1760, + 5931 => 350, + 5928 => nil, + 5912 => 464, + 6346 => nil, + 8419 => 1479, + 8971 => 1774, + 5703 => 462, + 5911 => 488, + 4494 => nil, + 6256 => 536, + 6048 => 381, + 8462 => 2055, + 4229 => nil, + 4248 => 369, + 6347 => 778, + 8431 => 2054, + 8420 => 1934, + 4334 => 359, + 4329 => nil, + 4362 => 315, + 9041 => 2269, + 5402 => nil, + 4260 => 1704, + 6344 => 702, + } + + def perform + MAPPING.each do |project_id, metais_code| + project = Project.find_by_id(project_id) + if project + project.metais_code = "projekt_#{metais_code}" if metais_code + project.save + end + end + end +end diff --git a/app/jobs/sync_all_topics_job.rb b/app/jobs/sync_all_topics_job.rb index a111851..895806b 100644 --- a/app/jobs/sync_all_topics_job.rb +++ b/app/jobs/sync_all_topics_job.rb @@ -1,7 +1,7 @@ class SyncAllTopicsJob < ApplicationJob queue_as :default - COLUMN_NAMES = ['Projekt', 'Projekt ID', 'Platforma', 'ID draft prípravy', 'ID prípravy', 'ID draft produktu', 'ID produktu'].freeze + COLUMN_NAMES = ['Projekt', 'Projekt ID', 'MetaIS', 'Platforma', 'ID draft prípravy', 'ID prípravy', 'ID draft produktu', 'ID produktu'].freeze def perform(sync_all: true) sheets_service = GoogleApiService.get_sheets_service @@ -23,12 +23,20 @@ def find_indices(header_row) def process_row(row, indices, sync_all) project_name = row[indices["Projekt"]] project_id = row[indices["Projekt ID"]] + project_metais_code = row[indices["MetaIS"]] platform_link = row[indices["Platforma"]] preparation_document_id = row[indices["ID draft prípravy"]] preparation_page_id = row[indices["ID prípravy"]] product_document_id = row[indices["ID draft produktu"]] product_page_id = row[indices["ID produktu"]] + + if project_metais_code.present? + project = Project.find_by(id: project_id) + project.metais_code = project_metais_code + project.save! + end + if sync_all process_row_for_sync_all(project_name, project_id, platform_link, preparation_document_id, preparation_page_id, product_document_id, product_page_id) else diff --git a/app/models/datahub/metais/codelist_program.rb b/app/models/datahub/metais/codelist_program.rb new file mode 100644 index 0000000..c85f957 --- /dev/null +++ b/app/models/datahub/metais/codelist_program.rb @@ -0,0 +1,3 @@ +class Datahub::Metais::CodelistProgram < DatahubRecord + self.table_name = 'metais.codelist_program' +end \ No newline at end of file diff --git a/app/models/datahub/metais/codelist_project_phase.rb b/app/models/datahub/metais/codelist_project_phase.rb new file mode 100644 index 0000000..42ec601 --- /dev/null +++ b/app/models/datahub/metais/codelist_project_phase.rb @@ -0,0 +1,3 @@ +class Datahub::Metais::CodelistProjectPhase < DatahubRecord + self.table_name = 'metais.codelist_project_phase' +end \ No newline at end of file diff --git a/app/models/datahub/metais/codelist_project_state.rb b/app/models/datahub/metais/codelist_project_state.rb new file mode 100644 index 0000000..6063468 --- /dev/null +++ b/app/models/datahub/metais/codelist_project_state.rb @@ -0,0 +1,3 @@ +class Datahub::Metais::CodelistProjectState < DatahubRecord + self.table_name = 'metais.codelist_project_state' +end \ No newline at end of file diff --git a/app/models/datahub/metais/project.rb b/app/models/datahub/metais/project.rb new file mode 100644 index 0000000..3fa5394 --- /dev/null +++ b/app/models/datahub/metais/project.rb @@ -0,0 +1,7 @@ +class Datahub::Metais::Project < DatahubRecord + self.table_name = "metais.projects" + + has_many :documents, class_name: 'Datahub::Metais::ProjectDocument', foreign_key: 'project_id' + has_many :versions, class_name: 'Datahub::Metais::ProjectVersion', foreign_key: 'project_id' + belongs_to :latest_version, class_name: 'Datahub::Metais::ProjectVersion', foreign_key: 'latest_version_id', optional: true +end \ No newline at end of file diff --git a/app/models/datahub/metais/project_change.rb b/app/models/datahub/metais/project_change.rb new file mode 100644 index 0000000..6effb8a --- /dev/null +++ b/app/models/datahub/metais/project_change.rb @@ -0,0 +1,5 @@ +class Datahub::Metais::ProjectChange < DatahubRecord + self.table_name = "metais.project_changes" + + belongs_to :project_version, class_name: 'Datahub::Metais::ProjectVersion' +end \ No newline at end of file diff --git a/app/models/datahub/metais/project_document.rb b/app/models/datahub/metais/project_document.rb new file mode 100644 index 0000000..6a6f12d --- /dev/null +++ b/app/models/datahub/metais/project_document.rb @@ -0,0 +1,7 @@ +class Datahub::Metais::ProjectDocument < DatahubRecord + self.table_name = "metais.project_documents" + + belongs_to :project, class_name: 'Datahub::Metais::Project', foreign_key: 'project_id' + has_many :versions, class_name: 'Datahub::Metais::ProjectDocumentVersion' + belongs_to :latest_version, class_name: 'Datahub::Metais::ProjectDocumentVersion', foreign_key: 'latest_version_id', optional: true +end \ No newline at end of file diff --git a/app/models/datahub/metais/project_document_version.rb b/app/models/datahub/metais/project_document_version.rb new file mode 100644 index 0000000..57343ad --- /dev/null +++ b/app/models/datahub/metais/project_document_version.rb @@ -0,0 +1,5 @@ +class Datahub::Metais::ProjectDocumentVersion < DatahubRecord + self.table_name = "metais.project_document_versions" + + belongs_to :document, class_name: 'Datahub::Metais::ProjectDocument', foreign_key: 'document_id' +end \ No newline at end of file diff --git a/app/models/datahub/metais/project_version.rb b/app/models/datahub/metais/project_version.rb new file mode 100644 index 0000000..2593ec2 --- /dev/null +++ b/app/models/datahub/metais/project_version.rb @@ -0,0 +1,5 @@ +class Datahub::Metais::ProjectVersion < DatahubRecord + self.table_name = "metais.project_versions" + + belongs_to :project, class_name: 'Datahub::Metais::Project', foreign_key: 'project_id' +end \ No newline at end of file diff --git a/app/models/datahub_record.rb b/app/models/datahub_record.rb new file mode 100644 index 0000000..d96032a --- /dev/null +++ b/app/models/datahub_record.rb @@ -0,0 +1,4 @@ +class DatahubRecord < ActiveRecord::Base + self.abstract_class = true + establish_connection :"#{Rails.env}_datahub" +end diff --git a/app/models/metais.rb b/app/models/metais.rb new file mode 100644 index 0000000..ccdd2d7 --- /dev/null +++ b/app/models/metais.rb @@ -0,0 +1,5 @@ +module Metais + def self.table_name_prefix + "metais." + end +end \ No newline at end of file diff --git a/app/models/metais/origin_type.rb b/app/models/metais/origin_type.rb new file mode 100644 index 0000000..bb910ac --- /dev/null +++ b/app/models/metais/origin_type.rb @@ -0,0 +1,11 @@ +# == Schema Information +# +# Table name: metais.origin_types +# +# id :integer not null, primary key +# name :string not null +# created_at :datetime not null +# updated_at :datetime not null + +class Metais::OriginType < ApplicationRecord +end diff --git a/app/models/metais/project.rb b/app/models/metais/project.rb new file mode 100644 index 0000000..a7725ff --- /dev/null +++ b/app/models/metais/project.rb @@ -0,0 +1,113 @@ +# == Schema Information +# +# Table name: metais.projects +# +# id :integer not null, primary key +# code :string not null +# created_at :datetime not null +# updated_at :datetime not null + +class Metais::Project < ApplicationRecord + has_many :project_origins, :class_name => 'Metais::ProjectOrigin' + has_and_belongs_to_many :projects, class_name: 'Project', + join_table: 'public.projects_metais_projects', + foreign_key: 'metais_project_id', + association_foreign_key: 'project_id' + + FINANCE_SOURCE_MAPPINGS = { "Medzirezortný program 0EK Informačné technológie financované zo štátneho rozpočtu" => "Štátny rozpočet" } + + def evaluations + ::Project.joins(''' + INNER JOIN "public"."projects_metais_projects" ON "public"."projects_metais_projects"."project_id" = "projects"."id" + INNER JOIN "metais"."projects" AS "metais_projects" ON "metais_projects"."id" = "public"."projects_metais_projects"."metais_project_id" + ''').where('projects_metais_projects.metais_project_id = ?', self.id) + end + + def get_project_origin_info + @project_origin_info ||= load_project_origin_info + end + + def get_ai_project_origin + @ai_project_origin ||= project_origins.joins(:origin_type).find_by(origin_types: { name: 'AI' }) + end + + def self.evaluation_counts + total_count = Metais::Project.count + yes_count = Metais::Project + .joins('INNER JOIN public.projects_metais_projects ON public.projects_metais_projects.metais_project_id = metais.projects.id') + .distinct + .count('metais.projects.id') + no_count = total_count - yes_count + + { yes: yes_count, no: no_count } + end + + def self.filtered_and_sorted_projects(params) + per_page = 25 + page = params[:page] || 1 + + ordered_project_origins = Metais::ProjectOrigin + .select('project_id, + COALESCE(NULLIF(max(approved_investment) FILTER (WHERE approved_investment IS NOT NULL), 0), + NULLIF(max(investment) FILTER (WHERE investment IS NOT NULL), 0)) AS final_investment, + max(title) FILTER (WHERE title IS NOT NULL) AS final_title, + max(status) FILTER (WHERE status IS NOT NULL) AS final_status, + max(guarantor) FILTER (WHERE guarantor IS NOT NULL) AS final_guarantor') + .group('project_id') + + projects = Metais::Project.joins("INNER JOIN (#{ordered_project_origins.to_sql}) project_origins ON metais.projects.id = project_origins.project_id") + + projects = projects.where('project_origins.final_guarantor = ?', params[:guarantor]) if params[:guarantor].present? + projects = projects.where('project_origins.final_status = ?', params[:status]) if params[:status].present? + projects = projects.where('code ILIKE ?', "%#{params[:code]}%") if params[:code].present? + projects = projects.where('project_origins.final_title ILIKE ?', "%#{params[:title]}%") if params[:title].present? + projects = projects.where('project_origins.final_investment >= ?', params[:min_price].to_f) if params[:min_price].present? + projects = projects.where('project_origins.final_investment <= ?', params[:max_price].to_f) if params[:max_price].present? + + if params[:has_evaluation].present? + projects = projects.select { |project| + params[:has_evaluation] == 'yes' ? project.evaluations.exists? : project.evaluations.empty? + } + projects = projects.map(&:id) + projects = Metais::Project.where(id: projects) + end + + params[:sort] = 'date' unless params[:sort].present? + sort_direction = params[:sort_direction]&.upcase == 'ASC' ? 'ASC' : 'DESC' + projects = case params[:sort] + when 'alpha' + projects.order("LOWER(project_origins.final_title) #{sort_direction}") + when 'date' + projects.order("metais.projects.updated_at #{sort_direction}") + when 'price' + projects.order("project_origins.final_investment #{sort_direction} NULLS #{sort_direction == 'ASC' ? 'FIRST' : 'LAST'}") + end + + projects.page(page).per(per_page) + end + + private + + def load_project_origin_info + fields = %w[title status phase description guarantor project_manager start_date end_date + finance_source investment operation approved_investment approved_operation + supplier supplier_cin targets_text events_text documents_text links_text updated_at] + + origins = self.project_origins.sort_by { |origin| -origin.origin_type_id } + + project_info = OpenStruct.new + fields.each do |field| + origin = origins.detect { |origin| !origin.send(field).nil? } + value = origin&.send(field) + + if field == 'finance_source' && value + value = FINANCE_SOURCE_MAPPINGS[value] || value + end + if value + project_info.send("#{field}=", Metais::ValueWithOrigin.new(value, origin.origin_type_id)) + end + end + + project_info + end +end diff --git a/app/models/metais/project_document.rb b/app/models/metais/project_document.rb new file mode 100644 index 0000000..effbf3e --- /dev/null +++ b/app/models/metais/project_document.rb @@ -0,0 +1,14 @@ +# == Schema Information +# +# Table name: metais.project_documents +# +# id :integer not null, primary key +# name :string not null +# value :string not null +# created_at :datetime not null +# updated_at :datetime not null + +class Metais::ProjectDocument < ApplicationRecord + belongs_to :project_origin, class_name: 'Metais::ProjectOrigin' + belongs_to :origin_type, class_name: 'Metais::OriginType' +end diff --git a/app/models/metais/project_event.rb b/app/models/metais/project_event.rb new file mode 100644 index 0000000..39ffc71 --- /dev/null +++ b/app/models/metais/project_event.rb @@ -0,0 +1,24 @@ +# == Schema Information +# +# Table name: metais.project_events +# +# id :integer not null, primary key +# name :string not null +# value :string not null +# date :datetime not null +# created_at :datetime not null +# updated_at :datetime not null + +class Metais::ProjectEvent < ApplicationRecord + belongs_to :project_origin, class_name: 'Metais::ProjectOrigin' + belongs_to :origin_type, class_name: 'Metais::OriginType' + belongs_to :event_type, class_name: 'Metais::ProjectEventType' + + scope :assumpted, -> { + where(event_type: Metais::ProjectEventType.find_by(name: 'Predpoklad')).order(:date) + } + + scope :real, -> { + where(event_type: Metais::ProjectEventType.find_by(name: 'Realita')).order(:date) + } +end diff --git a/app/models/metais/project_event_type.rb b/app/models/metais/project_event_type.rb new file mode 100644 index 0000000..ea4a15b --- /dev/null +++ b/app/models/metais/project_event_type.rb @@ -0,0 +1,3 @@ +class Metais::ProjectEventType < ApplicationRecord + has_many :project_events, class_name: 'Metais::ProjectEvent' +end diff --git a/app/models/metais/project_link.rb b/app/models/metais/project_link.rb new file mode 100644 index 0000000..771a260 --- /dev/null +++ b/app/models/metais/project_link.rb @@ -0,0 +1,14 @@ +# == Schema Information +# +# Table name: metais.project_links +# +# id :integer not null, primary key +# name :string not null +# value :string not null +# created_at :datetime not null +# updated_at :datetime not null + +class Metais::ProjectLink < ApplicationRecord + belongs_to :project_origin, class_name: 'Metais::ProjectOrigin' + belongs_to :origin_type, class_name: 'Metais::OriginType' +end diff --git a/app/models/metais/project_origin.rb b/app/models/metais/project_origin.rb new file mode 100644 index 0000000..76c4a37 --- /dev/null +++ b/app/models/metais/project_origin.rb @@ -0,0 +1,65 @@ +# == Schema Information +# +# Table name: metais.project_origins +# +# id :integer not null, primary key +# project_id :integer not null +# origin_type_id :integer not null +# +# title :string not null +# status :string +# description :text +# guarantor :string +# project_manager :string +# start_date :datetime +# end_date :datetime +# +# source :string +# investment :decimal(15,2) +# operation :decimal(15,2) +# +# supplier :string +# +# targets_text :text +# events_text :text +# documents_text :text +# links_text :text +# +# created_at :datetime not null +# updated_at :datetime not null +# +# Indexes +# +# index_metais_project_origins_on_project_id (project_id) +# index_metais_project_origins_on_origin_type_id (origin_type_id) +# +# Foreign key constraints +# +# fk_metais_project_origins_project_id (project_id => metais.projects.id) +# fk_metais_project_origins_origin_type_id (origin_type_id => metais.origin_types.id) + +class Metais::ProjectOrigin < ApplicationRecord + belongs_to :project, :class_name => 'Metais::Project' + belongs_to :origin_type, :class_name => 'Metais::OriginType' + + has_many :documents, class_name: 'Metais::ProjectDocument', foreign_key: 'project_origin_id' + has_many :suppliers, class_name: 'Metais::ProjectSupplier', foreign_key: 'project_origin_id' + has_many :events, class_name: 'Metais::ProjectEvent', foreign_key: 'project_origin_id' + has_many :links, class_name: 'Metais::ProjectLink', foreign_key: 'project_origin_id' + + def self.guarantor_counts + group(:guarantor).count + end + + def self.unique_guarantors + pluck(:guarantor).reject(&:blank?).uniq + end + + def self.status_counts + group(:status).count + end + + def self.unique_statuses + pluck(:status).reject(&:blank?).uniq + end +end diff --git a/app/models/metais/project_supplier.rb b/app/models/metais/project_supplier.rb new file mode 100644 index 0000000..5742e89 --- /dev/null +++ b/app/models/metais/project_supplier.rb @@ -0,0 +1,15 @@ +# == Schema Information +# +# Table name: metais.project_suppliers +# +# id :integer not null, primary key +# name :string not null +# value :string not null +# created_at :datetime not null +# updated_at :datetime not null + +class Metais::ProjectSupplier < ApplicationRecord + belongs_to :project_origin, class_name: 'Metais::ProjectOrigin' + belongs_to :origin_type, class_name: 'Metais::OriginType' + belongs_to :supplier_type, class_name: 'Metais::SupplierType' +end diff --git a/app/models/metais/supplier_type.rb b/app/models/metais/supplier_type.rb new file mode 100644 index 0000000..cda5380 --- /dev/null +++ b/app/models/metais/supplier_type.rb @@ -0,0 +1,11 @@ +# == Schema Information +# +# Table name: metais.supplier_types +# +# id :integer not null, primary key +# name :string not null +# created_at :datetime not null +# updated_at :datetime not null + +class Metais::SupplierType < ApplicationRecord +end diff --git a/app/models/metais/value_with_origin.rb b/app/models/metais/value_with_origin.rb new file mode 100644 index 0000000..3f37339 --- /dev/null +++ b/app/models/metais/value_with_origin.rb @@ -0,0 +1,12 @@ +class Metais::ValueWithOrigin < BasicObject + attr_reader :origin + + def initialize(value, origin) + @value = value + @origin = origin + end + + def method_missing(name, *args) + @value.send(name, *args) + end +end \ No newline at end of file diff --git a/app/models/project.rb b/app/models/project.rb index 241b1c4..b35e2c4 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -9,77 +9,74 @@ class Project < ApplicationRecord has_many :phases + has_and_belongs_to_many :metais_projects, class_name: 'Metais::Project', + join_table: 'public.projects_metais_projects', + foreign_key: 'project_id', + association_foreign_key: 'metais_project_id' def has_published_phases? phases.any? { |phase| phase.published_revision.present? } end - def self.filtered_projects(selected_tag, sort_param) + def self.filtered_and_sorted_projects(params) + per_page = 25 + page = params[:page] || 1 - case sort_param - when 'newest' - projects = Project.joins(phases: :published_revision) - .select('projects.*, MAX(phase_revisions.published_at) AS newest_published_at') - .group('projects.id') - .order('newest_published_at DESC') - when 'oldest' - projects = Project.joins(phases: :published_revision) - .select('projects.*, MIN(phase_revisions.published_at) AS oldest_published_at') - .group('projects.id') - .order('oldest_published_at') - when 'alpha', 'alpha_reverse' - projects = Project.joins(phases: :published_revision) - .select('DISTINCT ON (projects.id) projects.*, LOWER(phase_revisions.title) AS alpha_title') - .order('projects.id, alpha_title') - projects = projects.sort_by(&:alpha_title) - projects = projects.reverse if sort_param == 'alpha_reverse' - when 'preparation_lowest' - projects = Project.joins(phases: :published_revision) - .where(phases: { phase_type: PhaseType.find_by(name: 'Prípravná fáza') }) - .distinct - projects = projects.sort_by do |project| - phase_prep = project.phases.find { |p| p.phase_type.name == 'Prípravná fáza' } - phase_prep ? (phase_prep.published_revision.aggregated_rating) : 0 - end.reverse - when 'preparation_highest' - projects = Project.joins(phases: :published_revision) - .where(phases: { phase_type: PhaseType.find_by(name: 'Prípravná fáza') }) - .distinct - projects = projects.sort_by do |project| - phase_prep = project.phases.find { |p| p.phase_type.name == 'Prípravná fáza' } - phase_prep ? (phase_prep.published_revision.aggregated_rating) : 0 - end - when 'product_lowest' - projects = Project.joins(phases: :published_revision) - .where(phases: { phase_type: PhaseType.find_by(name: 'Fáza produkt') }) - .distinct - projects = projects.sort_by do |project| - phase_prep = project.phases.find { |p| p.phase_type.name == 'Fáza produkt' } - phase_prep ? (phase_prep.published_revision.aggregated_rating) : 0 - end.reverse - when 'product_highest' - projects = Project.joins(phases: :published_revision) - .where(phases: { phase_type: PhaseType.find_by(name: 'Fáza produkt') }) - .distinct - projects = projects.sort_by do |project| - phase_prep = project.phases.find { |p| p.phase_type.name == 'Fáza produkt' } - phase_prep ? (phase_prep.published_revision.aggregated_rating) : 0 - end - else - projects = Project.joins(phases: :published_revision) - .distinct + projects = Project.joins(phases: :published_revision) - if ProjectsHelper::ALLOWED_TAGS.keys.include?(selected_tag) - projects = Project.joins(phases: :published_revision) - .where(phase_revisions: { tags: selected_tag }) - end - - projects = projects.sort_by do |project| - max_rating = project.phases.map { |p| p.published_revision&.aggregated_rating }.compact.max - max_rating - end + if params[:title].present? + projects = projects.where('phase_revisions.title ILIKE ?', "%#{params[:title]}%") end + params[:sort] = 'date' unless params[:sort].present? + sort_direction = params[:sort_direction]&.upcase == 'ASC' ? 'ASC' : 'DESC' + projects = case params[:sort] + when 'alpha' + projects = projects.select('DISTINCT ON (projects.id) projects.*, LOWER(phase_revisions.title) AS alpha_title') + .order("projects.id, alpha_title") + projects = projects.sort_by(&:alpha_title) + projects = projects.reverse if sort_direction == 'DESC' + projects + when 'date' + if sort_direction == 'ASC' + projects = projects.select("projects.*, MIN(phase_revisions.published_at) AS oldest_published_at").group("projects.id") + .order("oldest_published_at") + elsif sort_direction == 'DESC' + projects = projects.select('projects.*, MAX(phase_revisions.published_at) AS newest_published_at').group('projects.id') + .order('newest_published_at DESC') + end + when 'preparation' + if sort_direction == 'ASC' + projects = projects.where(phases: { phase_type: PhaseType.find_by(name: 'Prípravná fáza') }).distinct + projects = projects.sort_by do |project| + phase_prep = project.phases.find { |p| p.phase_type.name == 'Prípravná fáza' } + phase_prep ? (phase_prep.published_revision.aggregated_rating) : 0 + end.reverse + elsif sort_direction == 'DESC' + projects = projects.where(phases: { phase_type: PhaseType.find_by(name: 'Prípravná fáza') }).distinct + projects = projects.sort_by do |project| + phase_prep = project.phases.find { |p| p.phase_type.name == 'Prípravná fáza' } + phase_prep ? (phase_prep.published_revision.aggregated_rating) : 0 + end + end + when 'product' + if sort_direction == 'ASC' + projects = projects.where(phases: { phase_type: PhaseType.find_by(name: 'Fáza produkt') }).distinct + projects = projects.sort_by do |project| + phase_prep = project.phases.find { |p| p.phase_type.name == 'Fáza produkt' } + phase_prep ? (phase_prep.published_revision.aggregated_rating) : 0 + end.reverse + + elsif sort_direction == 'DESC' + projects = projects.where(phases: { phase_type: PhaseType.find_by(name: 'Fáza produkt') }).distinct + projects = projects.sort_by do |project| + phase_prep = project.phases.find { |p| p.phase_type.name == 'Fáza produkt' } + phase_prep ? (phase_prep.published_revision.aggregated_rating) : 0 + end + end + end + + projects = Kaminari.paginate_array(projects).page(page).per(per_page) projects end end diff --git a/app/views/admin/metais/project_origins/edit.html.erb b/app/views/admin/metais/project_origins/edit.html.erb new file mode 100644 index 0000000..a1c9c97 --- /dev/null +++ b/app/views/admin/metais/project_origins/edit.html.erb @@ -0,0 +1,443 @@ +<%= form_with(model: [@project, @project_origin], url: admin_metais_project_project_origin_path(@project, @project_origin), method: :patch, local: true) do |form| %> +
    + +
    +
    +
    <%= form.label :title, "Názov projektu" %> + <% if @project_info.title.present? %> + <% logo_path, tooltip_text = origin_type_logo(@project_info.title.origin) %> + <%= image_tag logo_path, alt: tooltip_text, title: tooltip_text, style: "width: 16px; height: 16px;", class:"tag-tooltip" %> + <% end %> +
    + <%= form.text_field :title, value: @project_info.title, class: "form-control" %> +
    +
    +
    <%= form.label :description, "Popis" %> + <% if @project_info.description.present? %> + <% logo_path, tooltip_text = origin_type_logo(@project_info.description.origin) %> + <%= image_tag logo_path, alt: tooltip_text, title: tooltip_text, style: "width: 16px; height: 16px;", class:"tag-tooltip" %> + <% end %> +
    + <%= form.text_area :description, value: @project_info.description, class: "form-control", rows: 12 %> +
    +
    + +
    +
    +
    <%= form.label :guarantor, "Garant" %> + <% if @project_info.guarantor.present? %> + <% logo_path, tooltip_text = origin_type_logo(@project_info.guarantor.origin) %> + <%= image_tag logo_path, alt: tooltip_text, title: tooltip_text, style: "width: 16px; height: 16px;", class:"tag-tooltip" %> + <% end %> +
    + <%= form.text_field :guarantor, value: @project_info.guarantor, class: "form-control" %> +
    +
    +
    <%= form.label :project_manager, "Projektový manažér" %> + <% if @project_info.project_manager.present? %> + <% logo_path, tooltip_text = origin_type_logo(@project_info.project_manager.origin) %> + <%= image_tag logo_path, alt: tooltip_text, title: tooltip_text, style: "width: 16px; height: 16px;", class:"tag-tooltip" %> + <% end %> +
    + <%= form.text_field :project_manager, value: @project_info.project_manager, class: "form-control" %> +
    + +
    +
    <%= form.label :finance_source, "Zdroj financovania" %> + <% if @project_info.finance_source.present? %> + <% logo_path, tooltip_text = origin_type_logo(@project_info.finance_source.origin) %> + <%= image_tag logo_path, alt: tooltip_text, title: tooltip_text, style: "width: 16px; height: 16px;", class:"tag-tooltip" %> + <% end %> +
    + <% finance_source_mappings = Metais::Project::FINANCE_SOURCE_MAPPINGS %> + <%= form.select :finance_source, + Metais::ProjectOrigin.pluck(:finance_source).uniq.reject(&:blank?).map { |fs| [finance_source_mappings[fs] || fs, fs] }, { selected: @project_info.finance_source }, class: "form-control" %> +
    +
    +
    <%= form.label :status, "Stav" %> + <% if @project_info.status.present? %> + <% logo_path, tooltip_text = origin_type_logo(@project_info.status.origin) %> + <%= image_tag logo_path, alt: tooltip_text, title: tooltip_text, style: "width: 16px; height: 16px;", class:"tag-tooltip" %> + <% end %> +
    + <%= form.select :status, Metais::ProjectOrigin.pluck(:status).uniq.reject(&:blank?), { selected: @project_info.status }, { class: "form-control" } %> +
    <%= form.label :phase, "Fáza" %> + <% if @project_info.phase.present? %> + <% logo_path, tooltip_text = origin_type_logo(@project_info.phase.origin) %> + <%= image_tag logo_path, alt: tooltip_text, title: tooltip_text, style: "width: 16px; height: 16px;", class:"tag-tooltip" %> + <% end %> +
    + <%= form.select :phase, Metais::ProjectOrigin.pluck(:phase).uniq.reject(&:blank?), { selected: @project_info.phase }, { class: "form-control" } %> +
    + +
    +
    <%= form.label :start_date, "Dátum začiatku" %> + <% if @project_info.start_date.present? %> + <% logo_path, tooltip_text = origin_type_logo(@project_info.start_date.origin) %> + <%= image_tag logo_path, alt: tooltip_text, title: tooltip_text, style: "width: 16px; height: 16px;", class:"tag-tooltip" %> + <% end %> +
    + <%= form.date_field :start_date, + value: (@project_info.start_date.present? ? @project_info.start_date.strftime("%F") : Date.today.strftime("%F")), + class: "form-control datepicker" %> +
    +
    +
    <%= form.label :end_date, "Termín ukončenia " %> + <% if @project_info.end_date.present? %> + <% logo_path, tooltip_text = origin_type_logo(@project_info.end_date.origin) %> + <%= image_tag logo_path, alt: tooltip_text, title: tooltip_text, style: "width: 16px; height: 16px;", class:"tag-tooltip" %> + <% end %> +
    + <%= form.date_field :end_date, + value: (@project_info.end_date.present? ? @project_info.end_date.strftime("%F") : Date.today.strftime("%F")), + class: "form-control datepicker" %> +
    + +
    +
    Rozpočet projektu
    +
    +
    +
    <%= form.label :investment, "Investícia" %> + <% if @project_info.investment.present? %> + <% logo_path, tooltip_text = origin_type_logo(@project_info.investment.origin) %> + <%= image_tag logo_path, alt: tooltip_text, title: tooltip_text, style: "width: 16px; height: 16px;", class:"tag-tooltip" %> + <% end %> +
    + <%= form.number_field :investment, value: @project_info.investment, step: 0.1, class: "form-control" %> +
    <%= form.label :operation, "Ročné náklady" %> + <% if @project_info.operation.present? %> + <% logo_path, tooltip_text = origin_type_logo(@project_info.operation.origin) %> + <%= image_tag logo_path, alt: tooltip_text, title: tooltip_text, style: "width: 16px; height: 16px;", class:"tag-tooltip" %> + <% end %> +
    + <%= form.number_field :operation, value: @project_info.operation, step: 0.1, class: "form-control" %> +
    +
    +
    <%= form.label :approved_investment, "Schválená investícia" %> + <% if @project_info.approved_investment.present? %> + <% logo_path, tooltip_text = origin_type_logo(@project_info.approved_investment.origin) %> + <%= image_tag logo_path, alt: tooltip_text, title: tooltip_text, style: "width: 16px; height: 16px;", class:"tag-tooltip" %> + <% end %> +
    + <%= form.number_field :approved_investment, value: @project_info.approved_investment, step: 0.1, class: "form-control" %> +
    <%= form.label :approved_operation, "Schválené ročné náklady" %> + <% if @project_info.approved_operation.present? %> + <% logo_path, tooltip_text = origin_type_logo(@project_info.approved_operation.origin) %> + <%= image_tag logo_path, alt: tooltip_text, title: tooltip_text, style: "width: 16px; height: 16px;", class:"tag-tooltip" %> + <% end %> +
    + <%= form.number_field :approved_operation, value: @project_info.approved_operation, step: 0.1, class: "form-control" %> +
    +
    +
    +
    + +
    + +
    +
    +
    <%= form.label :targets_text, "Ciele a merateľné ukazovatele" %> + <% if @project_info.targets_text.present? %> + <% logo_path, tooltip_text = origin_type_logo(@project_info.targets_text.origin) %> + <%= image_tag logo_path, alt: tooltip_text, title: tooltip_text, style: "width: 16px; height: 16px;", class:"tag-tooltip" %> + <% end %> +
    + <%= form.text_area :targets_text, value: @project_info.targets_text, class: "form-control", rows: 5 %> +
    +
    + +
    +
    +
    <%= form.label :documents_text, "Dokumenty" %> + <% if @project_info.documents_text.present? %> + <% logo_path, tooltip_text = origin_type_logo(@project_info.documents_text.origin) %> + <%= image_tag logo_path, alt: tooltip_text, title: tooltip_text, style: "width: 16px; height: 16px;", class:"tag-tooltip" %> + <% end %> +
    + <%= form.text_area :documents_text, value: @project_info.documents_text, class: "form-control", rows: 2 %> +
    +
    + +
    +
    +
    <%= form.label :links_text, "Linky" %> + <% if @project_info.links_text.present? %> + <% logo_path, tooltip_text = origin_type_logo(@project_info.links_text.origin) %> + <%= image_tag logo_path, alt: tooltip_text, title: tooltip_text, style: "width: 16px; height: 16px;", class:"tag-tooltip" %> + <% end %> +
    + <%= form.text_area :links_text, value: @project_info.links_text, class: "form-control", rows: 2 %> +
    +
    + +
    +
    +
    Dodávateľ projektu
    + +
    <%= form.label :supplier, "Dodávateľ" %>
    + <%= form.text_field :supplier, value: @project_info.supplier, class: "form-control", id: "supplier-input" %> + +
    <%= form.label :supplier_cin, "IČO" %>
    + <%= form.text_field :supplier_cin, value: @project_info.supplier_cin, class: "form-control", id: "supplier-cin-input" %> + + +
    +
    + +
    + <%= form.submit 'Uložiť', class: 'btn btn-primary' %> +
    +
    +<% end %> + +
    + +
    +
    +
    +
    Priebeh projektu
    +
    Predpokladaný priebeh projektu
    + + + + + + + + + + + <% @assumption_events.each do |event| %> + + + + + + + <% end %> + + <%= form_with(url: admin_metais_project_project_origin_add_event_path(project_id: @project.id, project_origin_id: @project_origin.id), method: :post, local: true) do |f| %> + + + + <%= hidden_field_tag 'event[origin_type]', 'Human' %> + <%= hidden_field_tag 'event[event_type]', 'Predpoklad' %> + + <% end %> + + +
    NázovPopisDátumAkcia
    + <% logo_path, tooltip_text = origin_type_logo(event.origin_type) %> + <%= image_tag logo_path, alt: tooltip_text, title: tooltip_text, style: "width: 16px; height: 16px;", class:"tag-tooltip" %> + <%= event.name %> + <%= event.value %><%= event.date.in_time_zone('Europe/Bratislava').strftime('%d.%m.%Y') %> + <%= link_to 'Odstrániť', admin_metais_project_project_origin_remove_event_path(project_id: @project.id, project_origin_id: @project_origin.id, event_id: event.id), method: :delete, data: { confirm: 'Naozaj chcete aktivitu odstrániť?' } %> +
    <%= f.text_field 'event[name]', class: "w-100 form-control" %><%= f.text_field 'event[value]', class: "w-100 form-control" %><%= f.date_field 'event[date]', class: "form-control" %><%= f.submit 'Pridať', class: 'btn btn-primary' %>
    +
    +
    +
    Reálný priebeh projektu
    + + + + + + + + + + + <% @real_events.each do |event| %> + + + + + + + <% end %> + + <%= form_with(url: admin_metais_project_project_origin_add_event_path(project_id: @project.id, project_origin_id: @project_origin.id), method: :post, local: true) do |f| %> + + + + <%= hidden_field_tag 'event[origin_type]', 'Human' %> + <%= hidden_field_tag 'event[event_type]', 'Realita' %> + + <% end %> + + +
    NázovPopisDátumAkcia
    + <% logo_path, tooltip_text = origin_type_logo(event.origin_type) %> + <%= image_tag logo_path, alt: tooltip_text, title: tooltip_text, style: "width: 16px; height: 16px;", class:"tag-tooltip" %> + <%= event.name %> + <%= event.value %><%= event.date.in_time_zone('Europe/Bratislava').strftime('%d.%m.%Y') %> + <%= link_to 'Odstrániť', admin_metais_project_project_origin_remove_event_path(project_id: @project.id, project_origin_id: @project_origin.id, event_id: event.id), method: :delete, data: { confirm: 'Naozaj chcete aktivitu odstrániť?' } %> +
    <%= f.text_field 'event[name]', class: "w-100 form-control" %><%= f.text_field 'event[value]', class: "w-100 form-control" %><%= f.date_field 'event[date]', class: "form-control" %><%= f.submit 'Pridať', class: 'btn btn-primary' %>
    +
    +
    +
    +
    +
    +
    +
    Verejné obstarávanie, Dodávateľská zmúva, Zmlúva o NFP
    + + + + + + + + + + <% @combined_suppliers.each do |supplier| %> + + + + + + <% end %> + + <%= form_with(url: admin_metais_project_project_origin_add_supplier_path(project_id: @project.id, project_origin_id: @project_origin.id), method: :post, local: true) do |f| %> + + + <%= hidden_field_tag 'supplier[origin_type]', 'Human' %> + + <% end %> + + +
    TypLinkAkcia
    + <% logo_path, tooltip_text = origin_type_logo(supplier.origin_type) %> + <%= image_tag logo_path, alt: tooltip_text, title: tooltip_text, style: "width: 16px; height: 16px;", class:"tag-tooltip" %> + <%= supplier.supplier_type.name if supplier.supplier_type.present? %> + <%= link_to supplier.name, supplier.value, class: "w-100" %> + <%= link_to 'Odstrániť', admin_metais_project_project_origin_remove_supplier_path(project_id: @project.id, project_origin_id: @project_origin.id, supplier_id: supplier.id), method: :delete, data: { confirm: 'Naozaj chcete item odstrániť?' } %> +
    <%= f.select 'supplier[supplier_type]', Metais::SupplierType.pluck(:name, :id), {}, {class: 'form-control'} %><%= f.text_field 'supplier[value]', class: "w-100 form-control" %><%= f.submit 'Pridať', class: 'btn btn-primary' %>
    +
    +
    +
    +
    +
    +
    Dokumenty
    + + + + + + + + + + <% @grouped_documents.each do |description, documents| %> + <%= form_with(url: admin_metais_project_project_origin_update_group_order_path(project_id: @project.id, project_origin_id: @project_origin.id, description: description), method: :patch, local: true) do |f| %> + + + + + + <% end %> + <% end %> + +
    Názov skupinyPrioritaAkcia
    <%= description %>
    <%= f.number_field 'group_order', value: documents.first.group_order, class: "form-control", min: 1 %><%= f.submit 'Aktualizovať poradie', class: 'btn btn-primary' %>
    + + + + + + + + + + + + <% @combined_documents.each do |document| %> + + + + + + + <% end %> + + <%= form_with(url: admin_metais_project_project_origin_add_document_path(project_id: @project.id, project_origin_id: @project_origin.id), method: :post, local: true) do |f| %> + + + + <%= hidden_field_tag 'document[origin_type]', 'Human' %> + + <% end %> + + +
    NázovLinkPopisAkcia
    + <% logo_path, tooltip_text = origin_type_logo(document.origin_type) %> + <%= image_tag logo_path, alt: tooltip_text, title: tooltip_text, style: "width: 16px; height: 16px;", class:"tag-tooltip" %> + <%= document.name %> + <%= link_to document.value, document.value %><%= document.description %> + <%= link_to 'Odstrániť', admin_metais_project_project_origin_remove_document_path(project_id: @project.id, project_origin_id: @project_origin.id, document_id: document.id), method: :delete, data: { confirm: 'Naozaj chcete item odstrániť?' } %> +
    <%= f.text_field 'document[name]', class: "form-control" %><%= f.text_field 'document[value]', class: "form-control" %><%= f.text_field 'document[description]', class: "form-control" %><%= f.submit 'Pridať', class: 'btn btn-primary' %>
    +
    +
    +
    +
    +
    +
    Linky
    + + + + + + + + + + <% @combined_links.each do |link| %> + + + + + + <% end %> + + <%= form_with(url: admin_metais_project_project_origin_add_link_path(project_id: @project.id, project_origin_id: @project_origin.id), method: :post, local: true) do |f| %> + + + <%= hidden_field_tag 'link[origin_type]', 'Human' %> + + <% end %> + + +
    NázovLinkAkcia
    + <% logo_path, tooltip_text = origin_type_logo(link.origin_type) %> + <%= image_tag logo_path, alt: tooltip_text, title: tooltip_text, style: "width: 16px; height: 16px;", class:"tag-tooltip" %> + <%= link.name %> + <%= link_to link.value, link.value %> + <%= link_to 'Odstrániť', admin_metais_project_project_origin_remove_link_path(project_id: @project.id, project_origin_id: @project_origin.id, link_id: link.id), method: :delete, data: { confirm: 'Naozaj chcete item odstrániť?' } %> +
    <%= f.text_field 'link[name]', class: "w-100 form-control" %><%= f.text_field 'link[value]', class: "w-100 form-control" %><%= f.submit 'Pridať', class: 'btn btn-primary' %>
    +
    +
    + \ No newline at end of file diff --git a/app/views/admin/metais/projects/index.html.erb b/app/views/admin/metais/projects/index.html.erb new file mode 100644 index 0000000..ebcdcb4 --- /dev/null +++ b/app/views/admin/metais/projects/index.html.erb @@ -0,0 +1,250 @@ +

    Admin

    + +
    +
    MetaIS projekty
    +
    + +
    + <%= form_with url: admin_metais_projects_path, method: :get, class: 'form my-2 my-lg-0', local: true, id: "form" do |form| %> + <%= hidden_field_tag :sort, params[:sort] %> + <%= hidden_field_tag :sort_direction, params[:sort_direction] %> + <%= hidden_field_tag :status, params[:status] %> + <%= hidden_field_tag :guarantor, params[:guarantor] %> + <%= hidden_field_tag :has_evaluation, params[:has_evaluation] %> + + +
    +
    +
    + <%= text_field_tag :title, params[:title], class: 'form-control mr-1', placeholder: "Meno projektu" %> + +
    +
    +
    +
    + +
    +
    + <% sort_options = { + '' => 'Odporúčané', + 'alpha' => 'Abecedne', + 'date' => 'Podľa dátumu', + 'price' => 'Podľa ceny'} %> + + <% current_sort = params[:sort] || '' %> + <% current_sort_label = sort_options[current_sort] %> + + + +
    +
    +
    +
    +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    + <% end %> +
    + + + + + + + + + + + + + + + + + <% @projects.each do |project| %> + + + + + + + + + + + + <% end %> + +
    IDNázovOriginsDokumentyDodávateliaAktivityLinkyAI dátumAkcie
    <%= project.id %> + <%= link_to project.project_origins.first.title, metais_project_path(project) %> + + <%= project.project_origins.count %> + + <%= project.project_origins.joins(:documents).count %> + + <%= project.project_origins.joins(:suppliers).count %> + + <%= project.project_origins.joins(:events).count %> + + <%= project.project_origins.joins(:links).count %> + + <%= project.get_ai_project_origin&.updated_at&.in_time_zone('Europe/Bratislava')&.strftime('%H:%M %d.%m.%Y') || '-' %> + + <%= link_to 'Upraviť', create_human_origin_admin_metais_project_path(project), method: :post, class: 'btn btn-secondary btn-sm' %> + <%= link_to 'Spracovať AI', run_ai_extraction_admin_metais_project_path(project), method: :post, class: 'btn btn-priamry btn-sm' %> +
    +
    + <%= paginate @projects %> +
    \ No newline at end of file diff --git a/app/views/admin/pages/index.html.erb b/app/views/admin/pages/index.html.erb index 4577ebc..6091ad3 100644 --- a/app/views/admin/pages/index.html.erb +++ b/app/views/admin/pages/index.html.erb @@ -7,6 +7,9 @@ <%= link_to 'Synchronize', sync_admin_pages_path, class: 'btn btn-primary btn-sm', method: :put %> <%= link_to 'Synchronize Google drafts', sync_google_admin_pages_path, class: 'btn btn-primary btn-sm', method: :put %> +
    + <%= link_to 'MetaIS Admin', admin_metais_projects_path, class: 'btn btn-secondary btn-sm' %> +
    Flags
    diff --git a/app/views/admin/pages/preview.html.erb b/app/views/admin/pages/preview.html.erb index 3e8294c..b07710f 100644 --- a/app/views/admin/pages/preview.html.erb +++ b/app/views/admin/pages/preview.html.erb @@ -12,7 +12,6 @@
    <% if @phase.present? %> - <% @project = @phase_revision %> <%= render file: 'phase_revision/show' %> <% else %> <% @page = @phase_revision %> diff --git a/app/views/components/_footer.html.erb b/app/views/components/_footer.html.erb new file mode 100644 index 0000000..5b6daa9 --- /dev/null +++ b/app/views/components/_footer.html.erb @@ -0,0 +1,92 @@ + \ No newline at end of file diff --git a/app/views/components/_navbar.html.erb b/app/views/components/_navbar.html.erb new file mode 100644 index 0000000..aa5cdcd --- /dev/null +++ b/app/views/components/_navbar.html.erb @@ -0,0 +1,45 @@ + +
    \ No newline at end of file diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index fb4a916..0a8a332 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -46,110 +46,13 @@ - -
    + <% end %> <%= yield %> - + <%= render 'components/footer' %> diff --git a/app/views/metais/projects/index.html.erb b/app/views/metais/projects/index.html.erb new file mode 100644 index 0000000..4ccf8b2 --- /dev/null +++ b/app/views/metais/projects/index.html.erb @@ -0,0 +1,346 @@ +
    +

    Zoznam štátných IT projektov

    +

    Moderný, prehľadný a jednoduchý prístup k štátným IT projektomnie je budúcnosť... Nemusíte tráviť hodiny čítaním dlhých dokumentácií, ktoré nedávajú zmysel. Naše riešenie Vám prináša všetky potrebné informácie.

    + +
    + <%= form_with url: metais_projects_path, method: :get, class: 'form my-2 my-lg-0', local: true, id: "form" do |form| %> + <%= hidden_field_tag :sort, params[:sort] %> + <%= hidden_field_tag :sort_direction, params[:sort_direction] %> + <%= hidden_field_tag :status, params[:status] %> + <%= hidden_field_tag :guarantor, params[:guarantor] %> + <%= hidden_field_tag :has_evaluation, params[:has_evaluation] %> + +
    +
    +
    + <%= text_field_tag :title, params[:title], class: 'form-control mr-1', placeholder: "Meno projektu" %> + +
    +
    +
    +
    + +
    +
    + <% sort_options = { + '' => 'Podľa dátumu', + 'alpha' => 'Abecedne', + 'date' => 'Podľa dátumu', + 'price' => 'Podľa ceny'} %> + + <% current_sort = params[:sort] || '' %> + <% current_sort_label = sort_options[current_sort] %> + + + +
    +
    +
    +
    +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    + <% end %> +
    + + + + + + + + + + <% @projects.each do |project| %> + + + + + <% end %> + +
    ProjektInvestičné náklady
    +
    + <%= link_to project.project_origins.first.title, metais_project_path(project), class: 'table-title-item hover:text-primary' %> +
    +

    Dátum poslednej zmeny: + <%= + if project.updated_at.present? + content_tag(:small, l(project.updated_at.in_time_zone('Europe/Bratislava'), format: "%d.%m.%Y"), class: "font-italic") + else + content_tag(:small, "Neuvedená", style: "color: grey;", class: "font-italic tag-tooltip", title: "Dátum poslednej zmeny projektu nie je známy") + end + %> +

    +
    +
    +
    + <%= + if project.get_project_origin_info.guarantor.present? + content_tag(:span, project.get_project_origin_info.guarantor, class: "tag-tooltip", title: "Gestor štátného IT projektu") + else + content_tag(:span, "Gestor neuvedený", style: "color: grey;", class: "font-italic tag-tooltip", title: "Gestor projektu nie je známy") + end + %> +
    + +
    + <% + status = project.get_project_origin_info.status&.strip + status_class = case status + when 'Rozpracovaný' + 'status-1' + when 'Ohlásený' + 'status-2' + when 'Plánovaný' + 'status-3' + when 'Hodnotený' + 'status-4' + when 'Vrátený na dopracovanie' + 'status-5' + when 'Schválený' + 'status-6' + when 'Zrušený' + 'status-7' + when 'Realizovaný' + 'status-8' + when 'Ukončený' + 'status-9' + when 'Nasadený' + 'status-10' + when 'Znovu hodnotený' + 'status-11' + when 'Neschválený' + 'status-12' + when 'Mimoriadne ukončený' + 'status-13' + else + '' + end + %> + <%= + if status.present? + content_tag(:span, status, class: "state-badge #{status_class} tag-tooltip", title: "Stav, v ktorom sa projekt nachádza") + else + content_tag(:span, "Stav neuvedený", style: "color: grey;", class: "font-italic tag-tooltip", title: "Stav a fáza projektu nie sú známe") + end + %> +
    +
    +

    Cena:

    + <%= + if project.get_project_origin_info.approved_investment.present? && project.get_project_origin_info.approved_investment > 0 + number_to_currency(project.get_project_origin_info.approved_investment, unit: "€", separator: ",", delimiter: " ", format: "%n %u") + elsif project.get_project_origin_info.investment.present? && project.get_project_origin_info.investment > 0 + number_to_currency(project.get_project_origin_info.investment, unit: "€", separator: ",", delimiter: " ", format: "%n %u") + else + content_tag(:span, "Neuvedená", style: "color: grey;", class: "font-italic tag-tooltip", title: "Investičné náklady projektu nie sú známe") + end + %> +
    +
    +
    +
    + <%= + if project.get_project_origin_info.approved_investment.present? && project.get_project_origin_info.approved_investment > 0 + number_to_currency(project.get_project_origin_info.approved_investment, unit: "€", separator: ",", delimiter: " ", format: "%n %u") + elsif project.get_project_origin_info.investment.present? && project.get_project_origin_info.investment > 0 + number_to_currency(project.get_project_origin_info.investment, unit: "€", separator: ",", delimiter: " ", format: "%n %u") + else + content_tag(:span, "Neuvedená", style: "color: grey;", class: "font-italic tag-tooltip", title: "Investičné náklady projektu nie sú známe") + end + %> +
    + +
    \ No newline at end of file diff --git a/app/views/metais/projects/show.html.erb b/app/views/metais/projects/show.html.erb new file mode 100644 index 0000000..06d744e --- /dev/null +++ b/app/views/metais/projects/show.html.erb @@ -0,0 +1,420 @@ +
    +
    +
    +

    <%= @project_info.title %>

    + +
    +
    +
      + <% [['icons/sd_logo.png', 'Údaj bol manuálne zadaný členmi tímu Slovensko.Digital. Tento proces zaručuje vysokú presnosť, keďže experti starostlivo vyplnili údaje na základe overených informácií.'], + ['icons/ai_logo.png', 'Údaj bol automaticky získaný pomocou nášho AI nástroja na spracovanie dát. Nástroj prehľadáva veľké množstvo dokumentov a extrahuje z nich relevantné informácie.'], + ['icons/metais_logo.png', 'Údaj pochádza z verejne dostupného informačného systému MetaIS, ktorý zhromažďuje informácie o štátnych IT projektoch verejnej správy. Poskytuje oficiálne informácie o projekte.']].each_with_index do |(logo_path, tooltip_text), index| %> +
    • +
      + <%= image_tag logo_path, style:"height: 28px; width:28px;" %> +
      + <%= raw tooltip_text %> +
    • + <% end %> +
    +
    +
    +
    <%= simple_format(@project_info.description) %>
    +
    +
    + +
    + +
    +
    +
    +
    +
    Garant + <% if @project_info.guarantor.present? %> + <% logo_path, tooltip_text = origin_type_logo(@project_info.guarantor.origin) %> + <%= image_tag logo_path, alt: tooltip_text, title: tooltip_text, style: "width: 16px; height: 16px; margin-left: 6px;", class:"tag-tooltip" %> + <% end %> +
    + <% if @project_info.guarantor.present? %> +

    <%= @project_info.guarantor %>

    + <% else %> +

    Neuvedený

    + <% end %> +
    +
    +
    Projektový manažér + <% if @project_info.project_manager.present? %> + <% logo_path, tooltip_text = origin_type_logo(@project_info.project_manager.origin) %> + <%= image_tag logo_path, alt: tooltip_text, title: tooltip_text, style: "width: 16px; height: 16px; margin-left: 6px;", class:"tag-tooltip" %> + <% end %> +
    + <% if @project_info.project_manager.present? %> +

    <%= @project_info.project_manager %>

    + <% else %> +

    Neuvedený

    + <% end %> +
    +
    +
    Investičné náklady + <% if @project_info.investment.present? %> + <% logo_path, tooltip_text = origin_type_logo(@project_info.investment.origin) %> + <%= image_tag logo_path, alt: tooltip_text, title: tooltip_text, style: "width: 16px; height: 16px; margin-left: 6px;", class:"tag-tooltip" %> + <% end %> +
    + <% if @project_info.investment.present? %> +

    <%= number_to_currency(@project_info.investment, :unit => "€", :separator => ",", :delimiter => " ", :format => "%n %u")%>

    + <% else %> +

    Neuvedené

    + <% end %> +
    +
    + +
    +
    +
    Zdroj financovania + <% if @project_info.finance_source.present? %> + <% logo_path, tooltip_text = origin_type_logo(@project_info.finance_source.origin) %> + <%= image_tag logo_path, alt: tooltip_text, title: tooltip_text, style: "width: 16px; height: 16px; margin-left: 6px;", class:"tag-tooltip" %> + <% end %> +
    + <% if @project_info.finance_source.present? %> +

    <%= @project_info.finance_source %>

    + <% else %> +

    Neuvedený

    + <% end %> +
    +
    +
    Aktuálny stav + <% if @project_info.status.present? %> + <% logo_path, tooltip_text = origin_type_logo(@project_info.status.origin) %> + <%= image_tag logo_path, alt: tooltip_text, title: tooltip_text, style: "width: 16px; height: 16px; margin-left: 6px;", class:"tag-tooltip" %> + <% elsif @project_info.phase.present? %> + <% logo_path, tooltip_text = origin_type_logo(@project_info.phase.origin) %> + <%= image_tag logo_path, alt: tooltip_text, title: tooltip_text, style: "width: 16px; height: 16px; margin-left: 6px;", class:"tag-tooltip" %> + <% end %> +
    + <% if @project_info.finance_source.present? %> +

    <%= @project_info.status %>, <%= @project_info.phase %>

    + <% else %> +

    Neuvedený

    + <% end %> +
    +
    +
    Ročné náklady + <% if @project_info.operation.present? %> + <% logo_path, tooltip_text = origin_type_logo(@project_info.operation.origin) %> + <%= image_tag logo_path, alt: tooltip_text, title: tooltip_text, style: "width: 16px; height: 16px; margin-left: 6px;", class:"tag-tooltip" %> + <% end %> +
    + <% if @project_info.operation.present? %> +

    <%= number_to_currency(@project_info.operation, :unit => "€", :separator => ",", :delimiter => " ", :format => "%n %u")%>

    + <% else %> +

    Neuvedené

    + <% end %> +
    +
    + +
    +
    +
    Dátum začiatku + <% if @project_info.start_date.present? %> + <% logo_path, tooltip_text = origin_type_logo(@project_info.start_date.origin) %> + <%= image_tag logo_path, alt: tooltip_text, title: tooltip_text, style: "width: 16px; height: 16px; margin-left: 6px;", class:"tag-tooltip" %> + <% end %> +
    + <% if @project_info.start_date.present? %> +

    <%= @project_info.start_date&.strftime('%d.%m.%Y') %>

    + <% else %> +

    Neuvedený

    + <% end %> +
    +
    +
    Termín ukončenia + <% if @project_info.end_date.present? %> + <% logo_path, tooltip_text = origin_type_logo(@project_info.end_date.origin) %> + <%= image_tag logo_path, alt: tooltip_text, title: tooltip_text, style: "width: 16px; height: 16px; margin-left: 6px;", class:"tag-tooltip" %> + <% end %> +
    + <% if @project_info.end_date.present? %> +

    <%= @project_info.end_date&.strftime('%d.%m.%Y') %>

    + <% else %> +

    Neuvedený

    + <% end %> +
    +
    +
    Schválené investičné náklady + <% if @project_info.approved_investment.present? %> + <% logo_path, tooltip_text = origin_type_logo(@project_info.approved_investment.origin) %> + <%= image_tag logo_path, alt: tooltip_text, title: tooltip_text, style: "width: 16px; height: 16px; margin-left: 6px;", class:"tag-tooltip" %> + <% end %> +
    + <% if @project_info.approved_investment.present? %> +

    <%= number_to_currency(@project_info.approved_investment, :unit => "€", :separator => ",", :delimiter => " ", :format => "%n %u")%>

    + <% else %> +

    Neuvedené

    + <% end %> +
    +
    + +
    +
    +
    MetaIS <%= help_icon_if_blank(@project.code) %>
    + <%= link_to @project.code, "https://metais.vicepremier.gov.sk/detail/Projekt/#{@project.uuid}/cimaster?tab=basicForm", target: "_blank" %> +
    +
    +
    Posledná zmena + <% if @project_info.updated_at.present? %> + <% logo_path, tooltip_text = origin_type_logo(@project_info.updated_at.origin) %> + <%= image_tag logo_path, alt: tooltip_text, title: tooltip_text, style: "width: 16px; height: 16px; margin-left: 6px;", class:"tag-tooltip" %> + <% end %> +
    + <% if @project.updated_at.present? %> +

    <%= @project.updated_at&.strftime('%d.%m.%Y') %>

    + <% else %> +

    Neuvedený

    + <% end %> +
    +
    +
    Schválené ročné náklady + <% if @project_info.approved_operation.present? %> + <% logo_path, tooltip_text = origin_type_logo(@project_info.approved_operation.origin) %> + <%= image_tag logo_path, alt: tooltip_text, title: tooltip_text, style: "width: 16px; height: 16px; margin-left: 6px;", class:"tag-tooltip" %> + <% end %> +
    + <% if @project_info.approved_operation.present? %> +

    <%= number_to_currency(@project_info.approved_operation, :unit => "€", :separator => ",", :delimiter => " ", :format => "%n %u")%>

    + <% else %> +

    Neuvedené

    + <% end %> +
    +
    +
    +
    + + <% if @project.evaluations.present? %> + <% @project.evaluations.each do |evaluation| %> + <% if evaluation.phases.present? %> + <% evaluation.phases.each do |phase| %> + <% if phase.published_revision.present? %> +
    + <% if phase.phase_type.name == 'Prípravná fáza' %> +
    <%= link_to 'Hodnotenie prípravnej fázy', project_show_revision_type_path(phase.project.id, 'hodnotenie-pripravy')%>
    + <% else %> +
    <%= link_to 'Hodnotenie fázy produkt', project_show_revision_type_path(phase.project.id, 'hodnotenie-produkt')%>
    + <% end %> +
    +
    + <% if phase.published_revision.summary.present? %> +
    +
    +
    Zhrnutie hodnotenia Red Flags
    +

    <%= phase.published_revision.summary %>

    +
    +
    + <% end %> + + <% if phase.published_revision.recommendation.present? %> +
    +
    +
    Stanovisko Slovensko.Digital
    +

    <%= phase.published_revision.recommendation %>

    +
    +
    + <% end %> +
    +
    + <% end %> + <% end %> + <% end %> + <% end %> + <% end %> + +
    + + <% if @project_info.targets_text.present? %> +
    +
    +
    Ciele a merateľné ukazovatele + <% logo_path, tooltip_text = origin_type_logo(@project_info.targets_text.origin) %> + <%= image_tag logo_path, alt: tooltip_text, title: tooltip_text, style: "width: 16px; height: 16px; margin-left: 6px;", class:"tag-tooltip" %> +
    + <%= convert_to_list(@project_info.targets_text) %> +
    +
    + <% end %> + + <% if @assumption_events.any? || @real_events.any? %> +
    +
    +
    Harmonogram
    +
    + <% if @assumption_events.any? %> +
    +
    +

    Plánovaný priebeh projektu

    +
    +
    + <% @assumption_events.each do |event| %> +
    +
    + + + +
    + <% logo_path, tooltip_text = origin_type_logo(event.origin_type) %> + +

    + <%= event.name %> <%= image_tag logo_path, alt: tooltip_text, title: tooltip_text, style: "width: 12px; height: 12px;", class:"mr-2 tag-tooltip" if event.origin_type.present? %> +

    + +

    <%= event.value %>

    + <%= event.date.in_time_zone('Europe/Bratislava').strftime('%m/%Y') %> +
    +
    +
    + <% end %> +
    +
    +
    +
    + <% end %> + + <% if @real_events.any? %> +
    +
    +

    Reálny priebeh projektu

    +
    +
    + <% @real_events.each do |event| %> +
    +
    + + + +
    + <% logo_path, tooltip_text = origin_type_logo(event.origin_type) %> + +

    + <%= event.name %> <%= image_tag logo_path, alt: tooltip_text, title: tooltip_text, style: "width: 12px; height: 12px;", class:"mr-2 tag-tooltip" if event.origin_type.present? %> +

    + +

    <%= event.value %>

    + <%= event.date.in_time_zone('Europe/Bratislava').strftime('%m/%Y') %> +
    +
    +
    + <% end %> +
    +
    +
    +
    + <% end %> +
    +
    +
    + <% end %> + + <% if @project_info.supplier.present? || @combined_suppliers.any? %> +
    +
    +
    Dodávateľ projektu
    +

    Dodávateľ: + <% if @project_info.supplier.present? && @project_info.supplier_cin.present? %> + + <%= @project_info.supplier %> + + <% logo_path, tooltip_text = origin_type_logo(@project_info.supplier&.origin) %> + <%= image_tag logo_path, alt: tooltip_text, title: tooltip_text, style: "width: 16px; height: 16px; margin-left: 6px;", class:"tag-tooltip" %> + + <% else %> + Neznámy + <% end %> +

    + + <% if @combined_suppliers.any? %> +
      + <% @combined_suppliers.each do |supplier| %> + <% logo_path, tooltip_text = origin_type_logo(supplier.origin_type) %> + <%= case supplier.supplier_type&.name + when "CRZ" + "Dodávateľská zmlúva" + when "NFP" + "Zmlúva o NFP" + when "VO" + "Verejné obstarávanie" + else + supplier.supplier_type&.name + end %> +
    • + <%= image_tag logo_path, alt: tooltip_text, title: tooltip_text, style: "width: 12px; height: 12px;", class:"tag-tooltip" if supplier.origin_type.present? %> + <% if supplier.value.present? && supplier.value =~ /\Ahttps?:\/\/[\S]+\z/ %> + <%= link_to supplier.name, supplier.value %> + <% else %> + <%= supplier.name %> + <% end %> +
    • + <% end %> +
    + <% end %> +
    +
    + <% end %> + + <% if @project_info.documents_text.present? || @grouped_documents.any? %> +
    +
    +
    Dokumenty
    + + <% if @project_info.documents_text.present? %> +

    <%= @project_info.documents_text %>

    + <% end %> + + <% if @grouped_documents.any? %> + <% @grouped_documents.each do |description, documents| %> +

    <%= description %>

    +
      + <% documents.each do |doc| %> + <% logo_path, tooltip_text = origin_type_logo(doc.origin_type) %> + +
    • + <%= image_tag logo_path, alt: tooltip_text, title: tooltip_text, style: "width: 12px; height: 12px;", class:"tag-tooltip" if doc.origin_type.present? %> + <%= link_to doc.name, doc.value %> +
    • + <% end %> +
    + <% end %> + <% end %> + +
    +
    + <% end %> + + <% if @project_info.links_text.present? || @combined_links.any? %> +
    +
    +
    Linky
    + + <% if @project_info.links_text.present? %> +

    <%= @project_info.links_text %>

    + <% end %> + + <% if @combined_links.any? %> +
      + <% @combined_links.each do |link| %> + <% logo_path, tooltip_text = origin_type_logo(link.origin_type) %> + +
    • + <%= image_tag logo_path, alt: tooltip_text, title: tooltip_text, style: "width: 12px; height: 12px;", class:"tag-tooltip" if link.origin_type.present? %> + <%= link_to link.name, link.value %> +
    • + <% end %> +
    + <% end %> + +
    +
    + <% end %> + +
    diff --git a/app/views/phase_revision/show.html.erb b/app/views/phase_revision/show.html.erb index 74af6cf..13150eb 100644 --- a/app/views/phase_revision/show.html.erb +++ b/app/views/phase_revision/show.html.erb @@ -74,6 +74,17 @@ + <% if @project.metais_projects.present? %> + <% @project.metais_projects.each do |metais_project| %> +
    +
    +
    Viac o projekte
    + <%= link_to metais_project.get_project_origin_info.title, metais_project_path(metais_project) %> +
    +
    + <% end %> + <% end %> +
    diff --git a/app/views/projects/index.html.erb b/app/views/projects/index.html.erb index 5272297..05a0d85 100644 --- a/app/views/projects/index.html.erb +++ b/app/views/projects/index.html.erb @@ -1,61 +1,138 @@ -
    +

    Zoznam hodnotených projektov

    Chýba Vám tu nejaký projekt? Nezdá sa Vám hodnotenie? Toto hodnotenie je možné <%= link_to 'dopĺňať a upravovať', contribute_path %>.

    -
    - <%= form_with url: projects_path, method: :get, local: true, id: "sort-form" do |form| %> - <% form.label :sort %> - <%= form.select :sort, options_for_select([ - ['Usporiadať', '', {disabled: true, selected: true}], - ['Abecedne (A-Z)', 'alpha'], - ['Abecedne (Z-A)', 'alpha_reverse'], - ['Podľa dátumu (od najnovších)', 'newest'], - ['Podľa dátumu (od najstarších)', 'oldest'], - ['Hodnotenie prípravy (vzostupne)', 'preparation_lowest'], - ['Hodnotenie prípravy (zostupne)', 'preparation_highest'], - ['Hodnotenie produktu (vzostupne)', 'product_lowest'], - ['Hodnotenie produktu (zostupne)', 'product_highest'], - ], params[:sort]), {}, { class: 'bg-primary pl-2 py-2 rounded border-0 text-white', onchange: "this.form.submit();" } %> +
    + <%= form_with url: projects_path, method: :get, class: 'form my-2 my-lg-0', id: "form", local: true do |form| %> + <%= hidden_field_tag :sort, params[:sort] %> + <%= hidden_field_tag :sort_direction, params[:sort_direction] %> + +
    +
    +
    + <%= text_field_tag :title, params[:title], class: 'form-control mr-1', placeholder: "Meno projektu" %> + +
    +
    +
    +
    + <% sort_options = { + '' => 'Podľa dátumu', + 'alpha' => 'Abecedne', + 'date' => 'Podľa dátumu', + 'preparation' => 'Hodnotenie prípravy', + 'product' => 'Hodnotenie produktu'} %> + + <% current_sort = params[:sort] || '' %> + <% current_sort_label = sort_options[current_sort] %> + + + +
    +
    +
    <% end %> - <%= link_to "Reset", projects_path, class: 'btn btn-link' %>
    - +
    - - + + - - - + <% @projects.each do |project| %> - <% prep_revision = project.phases.select { |phase| phase.phase_type.name == 'Prípravná fáza' && phase.published_revision.present? }.first %> <% prep_revision = prep_revision&.published_revision %> <% prep_page = prep_revision&.revision&.page %> - - - - - + <% project.phases.select { |phase| phase.published_revision.present? }.sort_by { |phase| phase.phase_type }.each do |phase| %> - + <% ratings = phase.published_revision&.ratings&.group_by(&:score) %> <% 4.downto(0).each do |index| rt = ratings[index] %>
    Projekt
    Projekt Hodnotenie prípravy Hodnotenie produktuPosledná aktualizáciaDetail
    - <% if project.has_published_phases? %> - <% latest_published_revision = project.phases.select { |phase| phase.published_revision.present? }&.max_by { |phase| phase.published_revision.published_at }&.published_revision %> - <%= latest_published_revision&.title %> - <% latest_stage = latest_published_revision&.stage %> - <% if latest_stage %> -
    - <%= latest_stage %> +
    +
    + <% if project.has_published_phases? %> + <% latest_published_revision = project.phases.select { |phase| phase.published_revision.present? }&.max_by { |phase| phase.published_revision.published_at }&.published_revision %> + <% if project.metais_projects.present? %> + <%= link_to latest_published_revision&.title, metais_project_path(id: project.metais_projects.first.id), class: 'table-title-item' %> + <% else %> + <%= content_tag(:p, latest_published_revision&.title, class: "table-title-item mb-0") %> + <% end %> +
    +

    Dátum poslednej aktualizácie:

    + <%= + content_tag(:p) do + latest_revision_date = project.phases.map { |phase| phase.published_revision&.published_at }.compact.max + if latest_revision_date.present? + content_tag(:small, l(latest_revision_date.in_time_zone('Europe/Bratislava'), format: "%d.%m.%Y"), class: "font-italic") + else + content_tag(:small, "Neuvedený", style: "color: grey;", class: "font-italic tag-tooltip", title: "Dátum poslednej aktualizácie projektu nie je známy") + end + end + %> +
    +
    +
    +

    + <% + latest_stage = latest_published_revision&.stage + status_class = case latest_stage&.name + when 'Príprava projektu' + 'status-1' + when 'Obstarávanie' + 'status-2' + when 'Zrušený projekt' + 'status-3' + when 'Zastavený projekt' + 'status-4' + when 'Vrátený na dopracovanie' + 'status-5' + when 'Schválený' + 'status-6' + when 'Zrušený' + 'status-7' + else + '' + end + %> + <%= + if latest_stage.present? + content_tag(:span, latest_stage, class: "state-badge #{status_class}") + else + content_tag(:span, "Neuvedený stav projektu", style: "color: grey;", class: "font-italic tag-tooltip", title: "Stav a fáza projektu nie sú známe") + end + %> +

    +
    + +
    + +
    <% end %> - <% end %> +
    + <% if prep_page.nil? %> - <% elsif prep_revision.redflags_count > 0 %>
    - - <%= prep_revision.redflags_count %> × <%= fa_icon('flag', class: 'text-danger') %> + + <%= prep_revision.redflags_count %>×<%= fa_icon('flag', class: 'text-danger') %> <% if prep_page.latest_revision %> <%= link_to 'Zobraziť', project_show_revision_type_path(project.id, 'hodnotenie-pripravy') %> @@ -63,7 +140,7 @@
    <% else %>
    - + <%= number_to_percentage(prep_revision.total_score_percentage, precision: 0) %> <% if prep_page.latest_revision %> @@ -76,13 +153,13 @@ <% prod_revision = project.phases.select { |phase| phase.phase_type.name == 'Fáza produkt' && phase.published_revision.present? }.first %> <% prod_revision = prod_revision&.published_revision %> <% prod_page = prod_revision&.revision&.page%> -
    + <% if prod_page.nil? %> - <% elsif prod_revision&.redflags_count > 0 %>
    - - <%= prod_revision.redflags_count %> × <%= fa_icon('flag', class: 'text-danger') %> + + <%= prod_revision.redflags_count %>×<%= fa_icon('flag', class: 'text-danger') %> <% if prod_page.latest_revision %> <%= link_to 'Zobraziť', project_show_revision_type_path(project.id, 'hodnotenie-produktu') %> @@ -90,7 +167,7 @@
    <% else %>
    - + <%= number_to_percentage(prod_revision.total_score_percentage, precision: 0) %> <% if prod_page.latest_revision %> @@ -99,17 +176,8 @@
    <% end %>
    - <% latest_revision_date = project.phases.map { |phase| phase.published_revision&.published_at }.compact.max %> - <%= latest_revision_date.strftime('%d.%m.%Y') if latest_revision_date.present? %> - - -
    <%= link_to phase.phase_type_label, project_show_revision_type_path(project.id, PhaseRevision.map_phase_type_to_route(phase.phase_type.name)) %><%= link_to phase.phase_type_label, project_show_revision_type_path(project.id, PhaseRevision.map_phase_type_to_route(phase.phase_type.name)) %> @@ -144,4 +212,45 @@ <% end %>
    +
    diff --git a/app/views/static/index.html.erb b/app/views/static/index.html.erb index f3bf1ca..36f4756 100644 --- a/app/views/static/index.html.erb +++ b/app/views/static/index.html.erb @@ -4,28 +4,32 @@
    - <%= fa_icon('flag', class: 'text-danger') %> + <%= fa_icon('flag', class: 'text-danger') %> <%= fa_icon('flag-o', class: 'text-danger') %> <%= fa_icon('flag-o', class: 'text-danger') %>
    -
    +

    - Štátne IT projekty
    - hodnotené odborníkmi + Štátne IT projekty
    nemusia byť len zlé

    +
    +

    + Moderný a jednoduchý prehľad k štátnym IT projektom je tu. Zabudnite na hodiny strávené nad zložitou a neprehľadnou dokumentáciou. +

    +

    - Otvorené a transparentné hodnotenie projektov informatizácie komunitou IT odborníkov. + Mnohé z týchto projektov informatizácie disponujú transparentným hodnotením vyhotoveným komunitou IT odborníkov.

    - <%= link_to 'O projekte', about_path, class: 'btn btn-primary btn-lg mr-3 my-1' %> - <%= link_to 'Zoznam projektov', projects_path, class: 'btn btn-outline-secondary btn-lg mr-3 my-1' %> - <%= link_to 'Štátne IT v číslach', stats_path, class: 'btn btn-outline-secondary btn-lg my-1' %> + <%= link_to 'O projekte', about_path, class: 'btn btn-primary btn-lg mr-3 my-1 font-weight-bold' %> + <%= link_to 'Štátne IT projekty', metais_projects_path, class: 'btn btn-outline-secondary btn-lg mr-3 my-1 font-weight-bold' %> + <%= link_to 'Hodnotenia Red Flags', projects_path, class: 'btn btn-outline-secondary btn-lg mr-3 my-1 font-weight-bold' %>
    -
    +
    <%= fa_icon('star') %> <%= fa_icon('star') %> <%= fa_icon('star') %> <%= fa_icon('star-o') %>
    @@ -64,23 +68,23 @@
    - <%= link_to 'Všetky projekty', projects_path, class: 'btn btn-lg btn-outline-light mt-3' %> + <%= link_to 'Všetky hodnotenia', projects_path, class: 'btn btn-lg btn-outline-light mt-3 font-weight-bold' %>
    -
    +

    Čo je to Red Flags?

    -

    +

    Red Flags je pokračovaním systematickej kontroly štátnych IT projektov občianskym združením Slovensko.Digital. Pozeráme sa na problematické oblasti projektov a verejným hodnotením vytvárame tlak na zlepšovanie ich kvality a výsledkov.

    - <%= link_to 'Viac o projekte', about_path, class: 'btn btn btn-outline-primary' %> + <%= link_to 'Viac o projekte', about_path, class: 'btn btn btn-outline-primary font-weight-bold' %>

    Ako hodnotíme

    -

    +

    Projekty sú hodnotené pomocou sady kritérií, rovnakých pre každý projekt, pričom v každom kritériu je uvedené slovné a bodové hodnotenie od @@ -89,7 +93,7 @@ <%= rating_stars(OpenStruct.new(score: 4)) %>. Zásadné problémy sú označené <%= rating_stars(OpenStruct.new(score: 0)) %>. Hodnotenie môže navrhovať ktokoľvek, avšak pred finálnou publikáciou je schvaľované tímom Slovensko.Digital pod dohľadom poradnej komisie.

    - <%= link_to 'Viac o hodnotení a poradnej komisii', about_rating_path, class: 'btn btn btn-outline-primary mt-3' %> + <%= link_to 'Viac o hodnotení a poradnej komisii', about_rating_path, class: 'btn btn btn-outline-primary mt-3 font-weight-bold' %>
    diff --git a/config/application.rb b/config/application.rb index 5677523..eaa5f9f 100644 --- a/config/application.rb +++ b/config/application.rb @@ -29,5 +29,6 @@ class Application < Rails::Application config.generators.system_tests = nil config.active_job.queue_adapter = :que + config.active_record.schema_format = :sql end end diff --git a/config/clock.rb b/config/clock.rb index 625f691..1b83ce9 100644 --- a/config/clock.rb +++ b/config/clock.rb @@ -13,5 +13,8 @@ module Clockwork end every(1.day, 'redflags:sync_google_drafts', at: '3:00') - every(1.day, 'redflags:sync_sheets', at: '5:00') + every(1.day, 'redflags:sync_sheets', at: '4:00') + + every(1.day, 'metais:daily_sync', at: '5:00') + every(1.day, 'metais:daily_sync_evaluations', at: '6:00') end diff --git a/config/database.yml b/config/database.yml index 34d315d..7373d9d 100644 --- a/config/database.yml +++ b/config/database.yml @@ -9,14 +9,32 @@ development: <<: *default database: redflags_development +development_datahub: + <<: *default + database: datahub_development + test: <<: *default database: redflags_test +test_datahub: + <<: *default + database: datahub_test + staging: <<: *default url: <%= ENV['DATABASE_URL'] %> +staging_datahub: + <<: *default + url: <%= ENV['DATAHUB_DATABASE_URL'] %> + replica: true + production: <<: *default url: <%= ENV['DATABASE_URL'] %> + +production_datahub: + <<: *default + url: <%= ENV['DATAHUB_DATABASE_URL'] %> + replica: true diff --git a/config/routes.rb b/config/routes.rb index a631a9b..402e3c4 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -5,8 +5,10 @@ end Rails.application.routes.draw do - get 'projekty/:id', to: redirect('/projekty/%{id}/hodnotenie-pripravy') - resources :projects, path: 'projekty' do + get 'projekty/:id', to: redirect('/hodnotenia/%{id}/hodnotenie-pripravy') + get 'projekty/:id/hodnotenie-pripravy', to: redirect('/hodnotenia/%{id}/hodnotenie-pripravy') + + resources :projects, path: 'hodnotenia' do get ':revision_type/verzia/:version', to: 'phase_revision#show_history', as: 'show_history' get ':revision_type', to: 'phase_revision#show', as: 'show_revision_type' get ':revision_type/pdf', to: 'phase_revision#pdf', as: 'show_pdf_project' @@ -26,11 +28,35 @@ put :sync_one, on: :member end + namespace :metais do + resources :projects do + post :create_human_origin, on: :member + post :run_ai_extraction, on: :member + + resources :project_origins, only: [:edit, :update, :create] do + delete 'remove_event/:event_id', to: 'project_origins#remove_event', as: 'remove_event' + delete 'remove_supplier/:supplier_id', to: 'project_origins#remove_supplier', as: 'remove_supplier' + delete 'remove_link/:link_id', to: 'project_origins#remove_link', as: 'remove_link' + delete 'remove_document/:document_id', to: 'project_origins#remove_document', as: 'remove_document' + + post 'add_event', to: 'project_origins#add_event', as: 'add_event' + post 'add_supplier', to: 'project_origins#add_supplier', as: 'add_supplier' + post 'add_link', to: 'project_origins#add_link', as: 'add_link' + post 'add_document', to: 'project_origins#add_document', as: 'add_document' + patch 'update_group_order', to: 'project_origins#update_group_order', as: 'update_group_order' + end + end + end + resources :projects mount Que::Web, at: 'que' end + namespace :metais, path: '' do + resources :projects, path: 'statne-it-projekty', only: [:index, :show] + end + get 'o-projekte', as: 'about', to: 'static#about' get 'ako-hodnotime', as: 'about_rating', to: 'static#about_rating' get 'ako-sa-zapojit', as: 'contribute', to: 'static#contribute' diff --git a/db/datahub_structure.sql b/db/datahub_structure.sql new file mode 100644 index 0000000..c6d155b --- /dev/null +++ b/db/datahub_structure.sql @@ -0,0 +1,1007 @@ +SET statement_timeout = 0; +SET lock_timeout = 0; +SET idle_in_transaction_session_timeout = 0; +SET client_encoding = 'UTF8'; +SET standard_conforming_strings = on; +SELECT pg_catalog.set_config('search_path', '', false); +SET check_function_bodies = false; +SET xmloption = content; +SET client_min_messages = warning; +SET row_security = off; + +-- +-- Name: metais; Type: SCHEMA; Schema: -; Owner: - +-- + +CREATE SCHEMA metais; + + +SET default_tablespace = ''; + +SET default_table_access_method = heap; + +-- +-- Name: codelist_investment_type; Type: TABLE; Schema: metais; Owner: - +-- + +CREATE TABLE metais.codelist_investment_type ( + id bigint NOT NULL, + code character varying NOT NULL, + nazov character varying NOT NULL, + order_list integer NOT NULL, + popis character varying, + created_at timestamp(6) without time zone NOT NULL, + updated_at timestamp(6) without time zone NOT NULL +); + + +-- +-- Name: codelist_investment_type_id_seq; Type: SEQUENCE; Schema: metais; Owner: - +-- + +CREATE SEQUENCE metais.codelist_investment_type_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: codelist_investment_type_id_seq; Type: SEQUENCE OWNED BY; Schema: metais; Owner: - +-- + +ALTER SEQUENCE metais.codelist_investment_type_id_seq OWNED BY metais.codelist_investment_type.id; + + +-- +-- Name: codelist_program; Type: TABLE; Schema: metais; Owner: - +-- + +CREATE TABLE metais.codelist_program ( + id bigint NOT NULL, + kod_metais character varying NOT NULL, + nazov character varying NOT NULL, + nazov_en character varying, + ref_id character varying, + zdroj character varying, + raw_data text, + created_at timestamp(6) without time zone NOT NULL, + updated_at timestamp(6) without time zone NOT NULL, + uuid character varying +); + + +-- +-- Name: codelist_program_id_seq; Type: SEQUENCE; Schema: metais; Owner: - +-- + +CREATE SEQUENCE metais.codelist_program_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: codelist_program_id_seq; Type: SEQUENCE OWNED BY; Schema: metais; Owner: - +-- + +ALTER SEQUENCE metais.codelist_program_id_seq OWNED BY metais.codelist_program.id; + + +-- +-- Name: codelist_project_phase; Type: TABLE; Schema: metais; Owner: - +-- + +CREATE TABLE metais.codelist_project_phase ( + id bigint NOT NULL, + code character varying NOT NULL, + nazov character varying NOT NULL, + order_list integer NOT NULL, + popis character varying, + created_at timestamp(6) without time zone NOT NULL, + updated_at timestamp(6) without time zone NOT NULL +); + + +-- +-- Name: codelist_project_phase_id_seq; Type: SEQUENCE; Schema: metais; Owner: - +-- + +CREATE SEQUENCE metais.codelist_project_phase_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: codelist_project_phase_id_seq; Type: SEQUENCE OWNED BY; Schema: metais; Owner: - +-- + +ALTER SEQUENCE metais.codelist_project_phase_id_seq OWNED BY metais.codelist_project_phase.id; + + +-- +-- Name: codelist_project_state; Type: TABLE; Schema: metais; Owner: - +-- + +CREATE TABLE metais.codelist_project_state ( + id bigint NOT NULL, + code character varying NOT NULL, + nazov character varying NOT NULL, + order_list integer NOT NULL, + popis character varying, + created_at timestamp(6) without time zone NOT NULL, + updated_at timestamp(6) without time zone NOT NULL +); + + +-- +-- Name: codelist_project_state_id_seq; Type: SEQUENCE; Schema: metais; Owner: - +-- + +CREATE SEQUENCE metais.codelist_project_state_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: codelist_project_state_id_seq; Type: SEQUENCE OWNED BY; Schema: metais; Owner: - +-- + +ALTER SEQUENCE metais.codelist_project_state_id_seq OWNED BY metais.codelist_project_state.id; + + +-- +-- Name: codelist_source; Type: TABLE; Schema: metais; Owner: - +-- + +CREATE TABLE metais.codelist_source ( + id bigint NOT NULL, + code character varying NOT NULL, + nazov character varying NOT NULL, + order_list integer NOT NULL, + popis character varying, + created_at timestamp(6) without time zone NOT NULL, + updated_at timestamp(6) without time zone NOT NULL +); + + +-- +-- Name: codelist_source_id_seq; Type: SEQUENCE; Schema: metais; Owner: - +-- + +CREATE SEQUENCE metais.codelist_source_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: codelist_source_id_seq; Type: SEQUENCE OWNED BY; Schema: metais; Owner: - +-- + +ALTER SEQUENCE metais.codelist_source_id_seq OWNED BY metais.codelist_source.id; + + +-- +-- Name: isvs; Type: TABLE; Schema: metais; Owner: - +-- + +CREATE TABLE metais.isvs ( + id bigint NOT NULL, + project_id bigint, + uuid character varying NOT NULL, + created_at timestamp(6) without time zone NOT NULL, + updated_at timestamp(6) without time zone NOT NULL, + latest_version_id bigint +); + + +-- +-- Name: isvs_document_versions; Type: TABLE; Schema: metais; Owner: - +-- + +CREATE TABLE metais.isvs_document_versions ( + id bigint NOT NULL, + document_id bigint NOT NULL, + nazov character varying NOT NULL, + kod_metais character varying NOT NULL, + ref_id character varying NOT NULL, + mime_type character varying, + content_length integer, + status character varying, + poznamka text, + typ_dokumentu character varying, + filename character varying, + metais_created_at timestamp without time zone, + metais_updated_at timestamp without time zone, + raw_data jsonb NOT NULL, + raw_meta jsonb NOT NULL, + created_at timestamp(6) without time zone NOT NULL, + updated_at timestamp(6) without time zone NOT NULL +); + + +-- +-- Name: isvs_document_versions_id_seq; Type: SEQUENCE; Schema: metais; Owner: - +-- + +CREATE SEQUENCE metais.isvs_document_versions_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: isvs_document_versions_id_seq; Type: SEQUENCE OWNED BY; Schema: metais; Owner: - +-- + +ALTER SEQUENCE metais.isvs_document_versions_id_seq OWNED BY metais.isvs_document_versions.id; + + +-- +-- Name: isvs_documents; Type: TABLE; Schema: metais; Owner: - +-- + +CREATE TABLE metais.isvs_documents ( + id bigint NOT NULL, + isvs_id bigint, + uuid character varying NOT NULL, + created_at timestamp(6) without time zone NOT NULL, + updated_at timestamp(6) without time zone NOT NULL, + latest_version_id bigint +); + + +-- +-- Name: isvs_documents_id_seq; Type: SEQUENCE; Schema: metais; Owner: - +-- + +CREATE SEQUENCE metais.isvs_documents_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: isvs_documents_id_seq; Type: SEQUENCE OWNED BY; Schema: metais; Owner: - +-- + +ALTER SEQUENCE metais.isvs_documents_id_seq OWNED BY metais.isvs_documents.id; + + +-- +-- Name: isvs_id_seq; Type: SEQUENCE; Schema: metais; Owner: - +-- + +CREATE SEQUENCE metais.isvs_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: isvs_id_seq; Type: SEQUENCE OWNED BY; Schema: metais; Owner: - +-- + +ALTER SEQUENCE metais.isvs_id_seq OWNED BY metais.isvs.id; + + +-- +-- Name: isvs_versions; Type: TABLE; Schema: metais; Owner: - +-- + +CREATE TABLE metais.isvs_versions ( + id bigint NOT NULL, + isvs_id bigint NOT NULL, + nazov character varying NOT NULL, + kod_metais character varying NOT NULL, + ref_id character varying, + popis text, + popis_as_is text, + poznamka text, + zdroj character varying, + stav_isvs character varying, + typ_isvs character varying, + raw_data jsonb NOT NULL, + created_at timestamp(6) without time zone NOT NULL, + updated_at timestamp(6) without time zone NOT NULL, + metais_created_at timestamp without time zone +); + + +-- +-- Name: isvs_versions_id_seq; Type: SEQUENCE; Schema: metais; Owner: - +-- + +CREATE SEQUENCE metais.isvs_versions_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: isvs_versions_id_seq; Type: SEQUENCE OWNED BY; Schema: metais; Owner: - +-- + +ALTER SEQUENCE metais.isvs_versions_id_seq OWNED BY metais.isvs_versions.id; + + +-- +-- Name: project_changes; Type: TABLE; Schema: metais; Owner: - +-- + +CREATE TABLE metais.project_changes ( + id bigint NOT NULL, + project_version_id bigint NOT NULL, + field character varying, + old_value character varying, + new_value character varying, + created_at timestamp(6) without time zone NOT NULL, + updated_at timestamp(6) without time zone NOT NULL +); + + +-- +-- Name: project_changes_id_seq; Type: SEQUENCE; Schema: metais; Owner: - +-- + +CREATE SEQUENCE metais.project_changes_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: project_changes_id_seq; Type: SEQUENCE OWNED BY; Schema: metais; Owner: - +-- + +ALTER SEQUENCE metais.project_changes_id_seq OWNED BY metais.project_changes.id; + + +-- +-- Name: project_document_versions; Type: TABLE; Schema: metais; Owner: - +-- + +CREATE TABLE metais.project_document_versions ( + id bigint NOT NULL, + document_id bigint NOT NULL, + nazov character varying NOT NULL, + kod_metais character varying NOT NULL, + ref_id character varying NOT NULL, + mime_type character varying, + content_length integer, + status character varying, + poznamka text, + typ_dokumentu character varying, + filename character varying, + metais_created_at timestamp without time zone, + metais_updated_at timestamp without time zone, + raw_data jsonb NOT NULL, + raw_meta jsonb NOT NULL, + created_at timestamp(6) without time zone NOT NULL, + updated_at timestamp(6) without time zone NOT NULL +); + + +-- +-- Name: project_document_versions_id_seq; Type: SEQUENCE; Schema: metais; Owner: - +-- + +CREATE SEQUENCE metais.project_document_versions_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: project_document_versions_id_seq; Type: SEQUENCE OWNED BY; Schema: metais; Owner: - +-- + +ALTER SEQUENCE metais.project_document_versions_id_seq OWNED BY metais.project_document_versions.id; + + +-- +-- Name: project_documents; Type: TABLE; Schema: metais; Owner: - +-- + +CREATE TABLE metais.project_documents ( + id bigint NOT NULL, + project_id bigint, + uuid character varying NOT NULL, + created_at timestamp(6) without time zone NOT NULL, + updated_at timestamp(6) without time zone NOT NULL, + latest_version_id bigint +); + + +-- +-- Name: project_documents_id_seq; Type: SEQUENCE; Schema: metais; Owner: - +-- + +CREATE SEQUENCE metais.project_documents_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: project_documents_id_seq; Type: SEQUENCE OWNED BY; Schema: metais; Owner: - +-- + +ALTER SEQUENCE metais.project_documents_id_seq OWNED BY metais.project_documents.id; + + +-- +-- Name: project_versions; Type: TABLE; Schema: metais; Owner: - +-- + +CREATE TABLE metais.project_versions ( + id bigint NOT NULL, + project_id bigint NOT NULL, + nazov character varying NOT NULL, + kod_metais character varying NOT NULL, + typ_investicie character varying, + prijimatel character varying, + faza_projektu character varying, + program character varying, + popis text, + datum_zacatia timestamp without time zone, + termin_ukoncenia timestamp without time zone, + schvalovaci_proces character varying, + zdroj character varying, + financna_skupina character varying, + suma_vydavkov numeric(15,2), + rocne_naklady numeric(15,2), + ref_id character varying, + status character varying, + zmena_stavu timestamp without time zone, + schvalene_rocne_naklady numeric(15,2), + schvaleny_rozpocet numeric(15,2), + datum_nfp timestamp without time zone, + link_nfp character varying, + vyhlasenie_vo timestamp without time zone, + vo character varying, + zmluva_o_dielo timestamp without time zone, + zmluva_o_dielo_crz character varying, + raw_data jsonb NOT NULL, + created_at timestamp(6) without time zone NOT NULL, + updated_at timestamp(6) without time zone NOT NULL, + metais_created_at timestamp without time zone +); + + +-- +-- Name: project_versions_id_seq; Type: SEQUENCE; Schema: metais; Owner: - +-- + +CREATE SEQUENCE metais.project_versions_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: project_versions_id_seq; Type: SEQUENCE OWNED BY; Schema: metais; Owner: - +-- + +ALTER SEQUENCE metais.project_versions_id_seq OWNED BY metais.project_versions.id; + + +-- +-- Name: projects; Type: TABLE; Schema: metais; Owner: - +-- + +CREATE TABLE metais.projects ( + id bigint NOT NULL, + uuid character varying NOT NULL, + created_at timestamp(6) without time zone NOT NULL, + updated_at timestamp(6) without time zone NOT NULL, + latest_version_id bigint +); + + +-- +-- Name: projects_id_seq; Type: SEQUENCE; Schema: metais; Owner: - +-- + +CREATE SEQUENCE metais.projects_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: projects_id_seq; Type: SEQUENCE OWNED BY; Schema: metais; Owner: - +-- + +ALTER SEQUENCE metais.projects_id_seq OWNED BY metais.projects.id; + + +-- +-- Name: codelist_investment_type id; Type: DEFAULT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.codelist_investment_type ALTER COLUMN id SET DEFAULT nextval('metais.codelist_investment_type_id_seq'::regclass); + + +-- +-- Name: codelist_program id; Type: DEFAULT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.codelist_program ALTER COLUMN id SET DEFAULT nextval('metais.codelist_program_id_seq'::regclass); + + +-- +-- Name: codelist_project_phase id; Type: DEFAULT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.codelist_project_phase ALTER COLUMN id SET DEFAULT nextval('metais.codelist_project_phase_id_seq'::regclass); + + +-- +-- Name: codelist_project_state id; Type: DEFAULT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.codelist_project_state ALTER COLUMN id SET DEFAULT nextval('metais.codelist_project_state_id_seq'::regclass); + + +-- +-- Name: codelist_source id; Type: DEFAULT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.codelist_source ALTER COLUMN id SET DEFAULT nextval('metais.codelist_source_id_seq'::regclass); + + +-- +-- Name: isvs id; Type: DEFAULT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.isvs ALTER COLUMN id SET DEFAULT nextval('metais.isvs_id_seq'::regclass); + + +-- +-- Name: isvs_document_versions id; Type: DEFAULT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.isvs_document_versions ALTER COLUMN id SET DEFAULT nextval('metais.isvs_document_versions_id_seq'::regclass); + + +-- +-- Name: isvs_documents id; Type: DEFAULT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.isvs_documents ALTER COLUMN id SET DEFAULT nextval('metais.isvs_documents_id_seq'::regclass); + + +-- +-- Name: isvs_versions id; Type: DEFAULT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.isvs_versions ALTER COLUMN id SET DEFAULT nextval('metais.isvs_versions_id_seq'::regclass); + + +-- +-- Name: project_changes id; Type: DEFAULT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.project_changes ALTER COLUMN id SET DEFAULT nextval('metais.project_changes_id_seq'::regclass); + + +-- +-- Name: project_document_versions id; Type: DEFAULT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.project_document_versions ALTER COLUMN id SET DEFAULT nextval('metais.project_document_versions_id_seq'::regclass); + + +-- +-- Name: project_documents id; Type: DEFAULT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.project_documents ALTER COLUMN id SET DEFAULT nextval('metais.project_documents_id_seq'::regclass); + + +-- +-- Name: project_versions id; Type: DEFAULT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.project_versions ALTER COLUMN id SET DEFAULT nextval('metais.project_versions_id_seq'::regclass); + + +-- +-- Name: projects id; Type: DEFAULT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.projects ALTER COLUMN id SET DEFAULT nextval('metais.projects_id_seq'::regclass); + + +-- +-- Name: codelist_investment_type codelist_investment_type_pkey; Type: CONSTRAINT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.codelist_investment_type + ADD CONSTRAINT codelist_investment_type_pkey PRIMARY KEY (id); + + +-- +-- Name: codelist_program codelist_program_pkey; Type: CONSTRAINT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.codelist_program + ADD CONSTRAINT codelist_program_pkey PRIMARY KEY (id); + + +-- +-- Name: codelist_project_phase codelist_project_phase_pkey; Type: CONSTRAINT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.codelist_project_phase + ADD CONSTRAINT codelist_project_phase_pkey PRIMARY KEY (id); + + +-- +-- Name: codelist_project_state codelist_project_state_pkey; Type: CONSTRAINT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.codelist_project_state + ADD CONSTRAINT codelist_project_state_pkey PRIMARY KEY (id); + + +-- +-- Name: codelist_source codelist_source_pkey; Type: CONSTRAINT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.codelist_source + ADD CONSTRAINT codelist_source_pkey PRIMARY KEY (id); + + +-- +-- Name: isvs_document_versions isvs_document_versions_pkey; Type: CONSTRAINT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.isvs_document_versions + ADD CONSTRAINT isvs_document_versions_pkey PRIMARY KEY (id); + + +-- +-- Name: isvs_documents isvs_documents_pkey; Type: CONSTRAINT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.isvs_documents + ADD CONSTRAINT isvs_documents_pkey PRIMARY KEY (id); + + +-- +-- Name: isvs isvs_pkey; Type: CONSTRAINT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.isvs + ADD CONSTRAINT isvs_pkey PRIMARY KEY (id); + + +-- +-- Name: isvs_versions isvs_versions_pkey; Type: CONSTRAINT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.isvs_versions + ADD CONSTRAINT isvs_versions_pkey PRIMARY KEY (id); + + +-- +-- Name: project_changes project_changes_pkey; Type: CONSTRAINT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.project_changes + ADD CONSTRAINT project_changes_pkey PRIMARY KEY (id); + + +-- +-- Name: project_document_versions project_document_versions_pkey; Type: CONSTRAINT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.project_document_versions + ADD CONSTRAINT project_document_versions_pkey PRIMARY KEY (id); + + +-- +-- Name: project_documents project_documents_pkey; Type: CONSTRAINT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.project_documents + ADD CONSTRAINT project_documents_pkey PRIMARY KEY (id); + + +-- +-- Name: project_versions project_versions_pkey; Type: CONSTRAINT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.project_versions + ADD CONSTRAINT project_versions_pkey PRIMARY KEY (id); + + +-- +-- Name: projects projects_pkey; Type: CONSTRAINT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.projects + ADD CONSTRAINT projects_pkey PRIMARY KEY (id); + + +-- +-- Name: index_metais.codelist_investment_type_on_code; Type: INDEX; Schema: metais; Owner: - +-- + +CREATE INDEX "index_metais.codelist_investment_type_on_code" ON metais.codelist_investment_type USING btree (code); + + +-- +-- Name: index_metais.codelist_program_on_kod_metais; Type: INDEX; Schema: metais; Owner: - +-- + +CREATE INDEX "index_metais.codelist_program_on_kod_metais" ON metais.codelist_program USING btree (kod_metais); + + +-- +-- Name: index_metais.codelist_project_phase_on_code; Type: INDEX; Schema: metais; Owner: - +-- + +CREATE INDEX "index_metais.codelist_project_phase_on_code" ON metais.codelist_project_phase USING btree (code); + + +-- +-- Name: index_metais.codelist_project_state_on_code; Type: INDEX; Schema: metais; Owner: - +-- + +CREATE INDEX "index_metais.codelist_project_state_on_code" ON metais.codelist_project_state USING btree (code); + + +-- +-- Name: index_metais.codelist_source_on_code; Type: INDEX; Schema: metais; Owner: - +-- + +CREATE INDEX "index_metais.codelist_source_on_code" ON metais.codelist_source USING btree (code); + + +-- +-- Name: index_metais.isvs_document_versions_on_document_id; Type: INDEX; Schema: metais; Owner: - +-- + +CREATE INDEX "index_metais.isvs_document_versions_on_document_id" ON metais.isvs_document_versions USING btree (document_id); + + +-- +-- Name: index_metais.isvs_documents_on_isvs_id; Type: INDEX; Schema: metais; Owner: - +-- + +CREATE INDEX "index_metais.isvs_documents_on_isvs_id" ON metais.isvs_documents USING btree (isvs_id); + + +-- +-- Name: index_metais.isvs_documents_on_latest_version_id; Type: INDEX; Schema: metais; Owner: - +-- + +CREATE INDEX "index_metais.isvs_documents_on_latest_version_id" ON metais.isvs_documents USING btree (latest_version_id); + + +-- +-- Name: index_metais.isvs_documents_on_uuid; Type: INDEX; Schema: metais; Owner: - +-- + +CREATE INDEX "index_metais.isvs_documents_on_uuid" ON metais.isvs_documents USING btree (uuid); + + +-- +-- Name: index_metais.isvs_on_latest_version_id; Type: INDEX; Schema: metais; Owner: - +-- + +CREATE INDEX "index_metais.isvs_on_latest_version_id" ON metais.isvs USING btree (latest_version_id); + + +-- +-- Name: index_metais.isvs_on_project_id; Type: INDEX; Schema: metais; Owner: - +-- + +CREATE INDEX "index_metais.isvs_on_project_id" ON metais.isvs USING btree (project_id); + + +-- +-- Name: index_metais.isvs_on_uuid; Type: INDEX; Schema: metais; Owner: - +-- + +CREATE INDEX "index_metais.isvs_on_uuid" ON metais.isvs USING btree (uuid); + + +-- +-- Name: index_metais.isvs_versions_on_isvs_id; Type: INDEX; Schema: metais; Owner: - +-- + +CREATE INDEX "index_metais.isvs_versions_on_isvs_id" ON metais.isvs_versions USING btree (isvs_id); + + +-- +-- Name: index_metais.project_changes_on_project_version_id; Type: INDEX; Schema: metais; Owner: - +-- + +CREATE INDEX "index_metais.project_changes_on_project_version_id" ON metais.project_changes USING btree (project_version_id); + + +-- +-- Name: index_metais.project_document_versions_on_document_id; Type: INDEX; Schema: metais; Owner: - +-- + +CREATE INDEX "index_metais.project_document_versions_on_document_id" ON metais.project_document_versions USING btree (document_id); + + +-- +-- Name: index_metais.project_documents_on_latest_version_id; Type: INDEX; Schema: metais; Owner: - +-- + +CREATE INDEX "index_metais.project_documents_on_latest_version_id" ON metais.project_documents USING btree (latest_version_id); + + +-- +-- Name: index_metais.project_documents_on_project_id; Type: INDEX; Schema: metais; Owner: - +-- + +CREATE INDEX "index_metais.project_documents_on_project_id" ON metais.project_documents USING btree (project_id); + + +-- +-- Name: index_metais.project_documents_on_uuid; Type: INDEX; Schema: metais; Owner: - +-- + +CREATE INDEX "index_metais.project_documents_on_uuid" ON metais.project_documents USING btree (uuid); + + +-- +-- Name: index_metais.project_versions_on_project_id; Type: INDEX; Schema: metais; Owner: - +-- + +CREATE INDEX "index_metais.project_versions_on_project_id" ON metais.project_versions USING btree (project_id); + + +-- +-- Name: index_metais.projects_on_latest_version_id; Type: INDEX; Schema: metais; Owner: - +-- + +CREATE INDEX "index_metais.projects_on_latest_version_id" ON metais.projects USING btree (latest_version_id); + + +-- +-- Name: index_metais.projects_on_uuid; Type: INDEX; Schema: metais; Owner: - +-- + +CREATE INDEX "index_metais.projects_on_uuid" ON metais.projects USING btree (uuid); + + +-- +-- Name: projects fk_rails_1925410d1c; Type: FK CONSTRAINT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.projects + ADD CONSTRAINT fk_rails_1925410d1c FOREIGN KEY (latest_version_id) REFERENCES metais.project_versions(id); + + +-- +-- Name: isvs_documents fk_rails_2926a855af; Type: FK CONSTRAINT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.isvs_documents + ADD CONSTRAINT fk_rails_2926a855af FOREIGN KEY (isvs_id) REFERENCES metais.isvs(id); + + +-- +-- Name: isvs_documents fk_rails_5d253a31fc; Type: FK CONSTRAINT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.isvs_documents + ADD CONSTRAINT fk_rails_5d253a31fc FOREIGN KEY (latest_version_id) REFERENCES metais.isvs_document_versions(id); + + +-- +-- Name: project_versions fk_rails_819be9e3a6; Type: FK CONSTRAINT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.project_versions + ADD CONSTRAINT fk_rails_819be9e3a6 FOREIGN KEY (project_id) REFERENCES metais.projects(id); + + +-- +-- Name: project_documents fk_rails_868923b92d; Type: FK CONSTRAINT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.project_documents + ADD CONSTRAINT fk_rails_868923b92d FOREIGN KEY (project_id) REFERENCES metais.projects(id); + + +-- +-- Name: isvs fk_rails_8befaa8056; Type: FK CONSTRAINT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.isvs + ADD CONSTRAINT fk_rails_8befaa8056 FOREIGN KEY (project_id) REFERENCES metais.projects(id); + + +-- +-- Name: project_documents fk_rails_9352955d7e; Type: FK CONSTRAINT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.project_documents + ADD CONSTRAINT fk_rails_9352955d7e FOREIGN KEY (latest_version_id) REFERENCES metais.project_document_versions(id); + + +-- +-- Name: project_changes fk_rails_a57192e308; Type: FK CONSTRAINT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.project_changes + ADD CONSTRAINT fk_rails_a57192e308 FOREIGN KEY (project_version_id) REFERENCES metais.project_versions(id); + + +-- +-- Name: project_document_versions fk_rails_ae50626673; Type: FK CONSTRAINT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.project_document_versions + ADD CONSTRAINT fk_rails_ae50626673 FOREIGN KEY (document_id) REFERENCES metais.project_documents(id); + + +-- +-- Name: isvs_document_versions fk_rails_affcff3ef1; Type: FK CONSTRAINT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.isvs_document_versions + ADD CONSTRAINT fk_rails_affcff3ef1 FOREIGN KEY (document_id) REFERENCES metais.isvs_documents(id); + + +-- +-- Name: isvs fk_rails_be183a92d5; Type: FK CONSTRAINT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.isvs + ADD CONSTRAINT fk_rails_be183a92d5 FOREIGN KEY (latest_version_id) REFERENCES metais.isvs_versions(id); + + +-- +-- Name: isvs_versions fk_rails_ce75fc7d23; Type: FK CONSTRAINT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.isvs_versions + ADD CONSTRAINT fk_rails_ce75fc7d23 FOREIGN KEY (isvs_id) REFERENCES metais.isvs(id); + + +-- +-- PostgreSQL database dump complete +-- + +SET search_path TO "$user", public; + diff --git a/db/migrate/20240715175807_create_metais.rb b/db/migrate/20240715175807_create_metais.rb new file mode 100644 index 0000000..0f27247 --- /dev/null +++ b/db/migrate/20240715175807_create_metais.rb @@ -0,0 +1,14 @@ +class CreateMetais < ActiveRecord::Migration[5.1] + def up + execute 'CREATE SCHEMA metais' + + create_table 'metais.projects' do |t| + t.string :code, null: false + t.timestamps + end + end + + def down + execute 'DROP SCHEMA metais CASCADE' + end +end diff --git a/db/migrate/20240715181117_create_metais_project_origins.rb b/db/migrate/20240715181117_create_metais_project_origins.rb new file mode 100644 index 0000000..13b2787 --- /dev/null +++ b/db/migrate/20240715181117_create_metais_project_origins.rb @@ -0,0 +1,34 @@ +class CreateMetaisProjectOrigins < ActiveRecord::Migration[5.1] + def change + create_table 'metais.origin_types' do |t| + t.string :name, null: false + t.timestamps + end + + create_table 'metais.project_origins' do |t| + t.references :project, null: false, index: true, foreign_key: { to_table: 'metais.projects' } + t.references :origin_type, null: false, index: true, foreign_key: { to_table: 'metais.origin_types' } + + t.string :title, null: false + t.string :status + t.text :description + t.string :guarantor + t.string :project_manager + t.datetime :start_date + t.datetime :end_date + + t.string :finance_source + t.decimal :investment, :precision => 15, :scale => 2 + t.decimal :operation, :precision => 15, :scale => 2 + + t.string :supplier + + t.text :targets_text + t.text :events_text + t.text :documents_text + t.text :links_text + + t.timestamps + end + end +end diff --git a/db/migrate/20240715182749_create_metais_project_items.rb b/db/migrate/20240715182749_create_metais_project_items.rb new file mode 100644 index 0000000..f407149 --- /dev/null +++ b/db/migrate/20240715182749_create_metais_project_items.rb @@ -0,0 +1,50 @@ +class CreateMetaisProjectItems < ActiveRecord::Migration[5.1] + def change + create_table 'metais.project_events' do |t| + t.references :project_origin, null: false, index: true, foreign_key: { to_table: 'metais.project_origins' } + t.references :origin_type, null: false, index: true, foreign_key: { to_table: 'metais.origin_types' } + + t.string :name, null: false + t.string :value, null: false + t.datetime :date, null: false + + t.timestamps + end + + create_table 'metais.supplier_types' do |t| + t.string :name, null: false + t.timestamps + end + + create_table 'metais.project_suppliers' do |t| + t.references :project_origin, null: false, index: true, foreign_key: { to_table: 'metais.project_origins' } + t.references :origin_type, null: false, index: true, foreign_key: { to_table: 'metais.origin_types' } + t.references :supplier_type, null: false, index: true, foreign_key: { to_table: 'metais.supplier_types' } + + t.string :name, null: false + t.string :value, null: false + + t.timestamps + end + + create_table 'metais.project_documents' do |t| + t.references :project_origin, null: false, index: true, foreign_key: { to_table: 'metais.project_origins' } + t.references :origin_type, null: false, index: true, foreign_key: { to_table: 'metais.origin_types' } + + t.string :name, null: false + t.string :value, null: false + + t.timestamps + end + + create_table 'metais.project_links' do |t| + t.references :project_origin, null: false, index: true, foreign_key: { to_table: 'metais.project_origins' } + t.references :origin_type, null: false, index: true, foreign_key: { to_table: 'metais.origin_types' } + + t.string :name, null: false + t.string :value, null: false + + t.timestamps + end + end +end diff --git a/db/migrate/20240716083355_add_filename_and_uuid_to_metais_project_documents.rb b/db/migrate/20240716083355_add_filename_and_uuid_to_metais_project_documents.rb new file mode 100644 index 0000000..84e89f9 --- /dev/null +++ b/db/migrate/20240716083355_add_filename_and_uuid_to_metais_project_documents.rb @@ -0,0 +1,6 @@ +class AddFilenameAndUuidToMetaisProjectDocuments < ActiveRecord::Migration[5.1] + def change + add_column :'metais.project_documents', :filename, :string + add_column :'metais.project_documents', :uuid, :string, null: false + end +end diff --git a/db/migrate/20240716120919_add_uuid_to_metais_projects.rb b/db/migrate/20240716120919_add_uuid_to_metais_projects.rb new file mode 100644 index 0000000..9b74c24 --- /dev/null +++ b/db/migrate/20240716120919_add_uuid_to_metais_projects.rb @@ -0,0 +1,5 @@ +class AddUuidToMetaisProjects < ActiveRecord::Migration[5.1] + def change + add_column :'metais.projects', :uuid, :string + end +end diff --git a/db/migrate/20240724071253_add_phase_approved_finances_to_metais_project_origins.rb b/db/migrate/20240724071253_add_phase_approved_finances_to_metais_project_origins.rb new file mode 100644 index 0000000..cf3650e --- /dev/null +++ b/db/migrate/20240724071253_add_phase_approved_finances_to_metais_project_origins.rb @@ -0,0 +1,7 @@ +class AddPhaseApprovedFinancesToMetaisProjectOrigins < ActiveRecord::Migration[5.1] + def change + add_column 'metais.project_origins', :phase, :string + add_column 'metais.project_origins', :approved_investment, :decimal, precision: 15, scale: 2 + add_column 'metais.project_origins', :approved_operation, :decimal, precision: 15, scale: 2 + end +end diff --git a/db/migrate/20240724072736_add_metais_created_at_to_metais_project_origins.rb b/db/migrate/20240724072736_add_metais_created_at_to_metais_project_origins.rb new file mode 100644 index 0000000..8df7c66 --- /dev/null +++ b/db/migrate/20240724072736_add_metais_created_at_to_metais_project_origins.rb @@ -0,0 +1,5 @@ +class AddMetaisCreatedAtToMetaisProjectOrigins < ActiveRecord::Migration[5.1] + def change + add_column 'metais.project_origins', :metais_created_at, :datetime + end +end diff --git a/db/migrate/20240730180654_add_date_to_metais_project_suppliers.rb b/db/migrate/20240730180654_add_date_to_metais_project_suppliers.rb new file mode 100644 index 0000000..29e3a76 --- /dev/null +++ b/db/migrate/20240730180654_add_date_to_metais_project_suppliers.rb @@ -0,0 +1,5 @@ +class AddDateToMetaisProjectSuppliers < ActiveRecord::Migration[5.1] + def change + add_column 'metais.project_suppliers', :date, :datetime + end +end diff --git a/db/migrate/20240731124741_add_metais_code_to_projects.rb b/db/migrate/20240731124741_add_metais_code_to_projects.rb new file mode 100644 index 0000000..4998f90 --- /dev/null +++ b/db/migrate/20240731124741_add_metais_code_to_projects.rb @@ -0,0 +1,5 @@ +class AddMetaisCodeToProjects < ActiveRecord::Migration[5.1] + def change + add_column 'projects', :metais_code, :string + end +end diff --git a/db/migrate/20240820080110_create_metais_project_event_types.rb b/db/migrate/20240820080110_create_metais_project_event_types.rb new file mode 100644 index 0000000..46a4e74 --- /dev/null +++ b/db/migrate/20240820080110_create_metais_project_event_types.rb @@ -0,0 +1,9 @@ +class CreateMetaisProjectEventTypes < ActiveRecord::Migration[5.1] + def change + create_table :'metais.project_event_types' do |t| + t.string :name + + t.timestamps + end + end +end diff --git a/db/migrate/20240820080303_add_event_type_ref_to_metais_project_events.rb b/db/migrate/20240820080303_add_event_type_ref_to_metais_project_events.rb new file mode 100644 index 0000000..8b806cf --- /dev/null +++ b/db/migrate/20240820080303_add_event_type_ref_to_metais_project_events.rb @@ -0,0 +1,5 @@ +class AddEventTypeRefToMetaisProjectEvents < ActiveRecord::Migration[5.1] + def change + add_reference :'metais.project_events', :event_type, index: true, foreign_key: { to_table: 'metais.project_event_types' } + end +end diff --git a/db/migrate/20240821210736_add_state_change_date_to_metais_project_origin.rb b/db/migrate/20240821210736_add_state_change_date_to_metais_project_origin.rb new file mode 100644 index 0000000..a8f4950 --- /dev/null +++ b/db/migrate/20240821210736_add_state_change_date_to_metais_project_origin.rb @@ -0,0 +1,5 @@ +class AddStateChangeDateToMetaisProjectOrigin < ActiveRecord::Migration[5.1] + def change + add_column :'metais.project_origins', :status_change_date, :datetime + end +end diff --git a/db/migrate/20240821212620_add_supplier_cin_to_metais_project_origins.rb b/db/migrate/20240821212620_add_supplier_cin_to_metais_project_origins.rb new file mode 100644 index 0000000..9103b2f --- /dev/null +++ b/db/migrate/20240821212620_add_supplier_cin_to_metais_project_origins.rb @@ -0,0 +1,5 @@ +class AddSupplierCinToMetaisProjectOrigins < ActiveRecord::Migration[5.1] + def change + add_column :'metais.project_origins', :supplier_cin, :bigint + end +end diff --git a/db/migrate/20240822112026_add_benefits_to_metais_project_origins.rb b/db/migrate/20240822112026_add_benefits_to_metais_project_origins.rb new file mode 100644 index 0000000..6814422 --- /dev/null +++ b/db/migrate/20240822112026_add_benefits_to_metais_project_origins.rb @@ -0,0 +1,5 @@ +class AddBenefitsToMetaisProjectOrigins < ActiveRecord::Migration[5.1] + def change + add_column :'metais.project_origins', :benefits, :decimal, precision: 15, scale: 2 + end +end diff --git a/db/migrate/20240822143116_add_description_to_metais_project_documents.rb b/db/migrate/20240822143116_add_description_to_metais_project_documents.rb new file mode 100644 index 0000000..98562b2 --- /dev/null +++ b/db/migrate/20240822143116_add_description_to_metais_project_documents.rb @@ -0,0 +1,5 @@ +class AddDescriptionToMetaisProjectDocuments < ActiveRecord::Migration[5.1] + def change + add_column :'metais.project_documents', :description, :string + end +end diff --git a/db/migrate/20240823082322_allow_null_on_uuid_in_metais_project_documents.rb b/db/migrate/20240823082322_allow_null_on_uuid_in_metais_project_documents.rb new file mode 100644 index 0000000..b4a5e0c --- /dev/null +++ b/db/migrate/20240823082322_allow_null_on_uuid_in_metais_project_documents.rb @@ -0,0 +1,5 @@ +class AllowNullOnUuidInMetaisProjectDocuments < ActiveRecord::Migration[5.1] + def change + change_column :'metais.project_documents', :uuid, :string, null: true + end +end diff --git a/db/migrate/20240825111806_create_join_table_projects_metais_projects.rb b/db/migrate/20240825111806_create_join_table_projects_metais_projects.rb new file mode 100644 index 0000000..db4f8fb --- /dev/null +++ b/db/migrate/20240825111806_create_join_table_projects_metais_projects.rb @@ -0,0 +1,8 @@ +class CreateJoinTableProjectsMetaisProjects < ActiveRecord::Migration[5.1] + def change + create_table :projects_metais_projects, id: false do |t| + t.references :project, index: true, foreign_key: {to_table: 'projects'} + t.references :metais_project, index: true, foreign_key: {to_table: 'metais.projects'} + end + end +end diff --git a/db/migrate/20240825115911_add_null_to_project_in_projects_metais_projects.rb b/db/migrate/20240825115911_add_null_to_project_in_projects_metais_projects.rb new file mode 100644 index 0000000..503839b --- /dev/null +++ b/db/migrate/20240825115911_add_null_to_project_in_projects_metais_projects.rb @@ -0,0 +1,5 @@ +class AddNullToProjectInProjectsMetaisProjects < ActiveRecord::Migration[5.1] + def change + change_column_null :projects_metais_projects, :project_id, true + end +end diff --git a/db/migrate/20240924210648_add_group_order_to_metais_documents.rb b/db/migrate/20240924210648_add_group_order_to_metais_documents.rb new file mode 100644 index 0000000..cc645fc --- /dev/null +++ b/db/migrate/20240924210648_add_group_order_to_metais_documents.rb @@ -0,0 +1,5 @@ +class AddGroupOrderToMetaisDocuments < ActiveRecord::Migration[5.1] + def change + add_column :'metais.project_documents', :group_order, :integer + end +end diff --git a/db/schema.rb b/db/schema.rb index 1920925..ac2fea5 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.define(version: 20240621112043) do +ActiveRecord::Schema.define(version: 20240820193320) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -85,6 +85,7 @@ create_table "projects", force: :cascade do |t| t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.string "metais_code" end create_table "que_jobs", primary_key: ["queue", "priority", "run_at", "job_id"], force: :cascade, comment: "3" do |t| diff --git a/db/seeds.rb b/db/seeds.rb index e8ca7b1..ba338f6 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -52,3 +52,13 @@ PhaseType.find_or_create_by!(name: 'Prípravná fáza') PhaseType.find_or_create_by!(name: 'Fáza produkt') +Metais::OriginType.find_or_create_by!(name: 'MetaIS') +Metais::OriginType.find_or_create_by!(name: 'AI') +Metais::OriginType.find_or_create_by!(name: 'Human') + +Metais::SupplierType.find_or_create_by!(name: 'CRZ') +Metais::SupplierType.find_or_create_by!(name: 'VO') +Metais::SupplierType.find_or_create_by!(name: 'NFP') + +Metais::ProjectEventType.find_or_create_by!(name: 'Predpoklad') +Metais::ProjectEventType.find_or_create_by!(name: 'Realita') \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql new file mode 100644 index 0000000..ffd6bdc --- /dev/null +++ b/db/structure.sql @@ -0,0 +1,1462 @@ +SET statement_timeout = 0; +SET lock_timeout = 0; +SET idle_in_transaction_session_timeout = 0; +SET client_encoding = 'UTF8'; +SET standard_conforming_strings = on; +SELECT pg_catalog.set_config('search_path', '', false); +SET check_function_bodies = false; +SET xmloption = content; +SET client_min_messages = warning; +SET row_security = off; + +-- +-- Name: metais; Type: SCHEMA; Schema: -; Owner: - +-- + +CREATE SCHEMA metais; + + +SET default_tablespace = ''; + +SET default_table_access_method = heap; + +-- +-- Name: origin_types; Type: TABLE; Schema: metais; Owner: - +-- + +CREATE TABLE metais.origin_types ( + id bigint NOT NULL, + name character varying NOT NULL, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: origin_types_id_seq; Type: SEQUENCE; Schema: metais; Owner: - +-- + +CREATE SEQUENCE metais.origin_types_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: origin_types_id_seq; Type: SEQUENCE OWNED BY; Schema: metais; Owner: - +-- + +ALTER SEQUENCE metais.origin_types_id_seq OWNED BY metais.origin_types.id; + + +-- +-- Name: project_documents; Type: TABLE; Schema: metais; Owner: - +-- + +CREATE TABLE metais.project_documents ( + id bigint NOT NULL, + project_origin_id bigint NOT NULL, + origin_type_id bigint NOT NULL, + name character varying NOT NULL, + value character varying NOT NULL, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL, + filename character varying, + uuid character varying, + description character varying, + group_order integer +); + + +-- +-- Name: project_documents_id_seq; Type: SEQUENCE; Schema: metais; Owner: - +-- + +CREATE SEQUENCE metais.project_documents_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: project_documents_id_seq; Type: SEQUENCE OWNED BY; Schema: metais; Owner: - +-- + +ALTER SEQUENCE metais.project_documents_id_seq OWNED BY metais.project_documents.id; + + +-- +-- Name: project_event_types; Type: TABLE; Schema: metais; Owner: - +-- + +CREATE TABLE metais.project_event_types ( + id bigint NOT NULL, + name character varying, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: project_event_types_id_seq; Type: SEQUENCE; Schema: metais; Owner: - +-- + +CREATE SEQUENCE metais.project_event_types_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: project_event_types_id_seq; Type: SEQUENCE OWNED BY; Schema: metais; Owner: - +-- + +ALTER SEQUENCE metais.project_event_types_id_seq OWNED BY metais.project_event_types.id; + + +-- +-- Name: project_events; Type: TABLE; Schema: metais; Owner: - +-- + +CREATE TABLE metais.project_events ( + id bigint NOT NULL, + project_origin_id bigint NOT NULL, + origin_type_id bigint NOT NULL, + name character varying NOT NULL, + value character varying NOT NULL, + date timestamp without time zone NOT NULL, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL, + event_type_id bigint +); + + +-- +-- Name: project_events_id_seq; Type: SEQUENCE; Schema: metais; Owner: - +-- + +CREATE SEQUENCE metais.project_events_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: project_events_id_seq; Type: SEQUENCE OWNED BY; Schema: metais; Owner: - +-- + +ALTER SEQUENCE metais.project_events_id_seq OWNED BY metais.project_events.id; + + +-- +-- Name: project_links; Type: TABLE; Schema: metais; Owner: - +-- + +CREATE TABLE metais.project_links ( + id bigint NOT NULL, + project_origin_id bigint NOT NULL, + origin_type_id bigint NOT NULL, + name character varying NOT NULL, + value character varying NOT NULL, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: project_links_id_seq; Type: SEQUENCE; Schema: metais; Owner: - +-- + +CREATE SEQUENCE metais.project_links_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: project_links_id_seq; Type: SEQUENCE OWNED BY; Schema: metais; Owner: - +-- + +ALTER SEQUENCE metais.project_links_id_seq OWNED BY metais.project_links.id; + + +-- +-- Name: project_origins; Type: TABLE; Schema: metais; Owner: - +-- + +CREATE TABLE metais.project_origins ( + id bigint NOT NULL, + project_id bigint NOT NULL, + origin_type_id bigint NOT NULL, + title character varying NOT NULL, + status character varying, + description text, + guarantor character varying, + project_manager character varying, + start_date timestamp without time zone, + end_date timestamp without time zone, + finance_source character varying, + investment numeric(15,2), + operation numeric(15,2), + supplier character varying, + targets_text text, + events_text text, + documents_text text, + links_text text, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL, + phase character varying, + approved_investment numeric(15,2), + approved_operation numeric(15,2), + metais_created_at timestamp without time zone, + status_change_date timestamp without time zone, + supplier_cin bigint, + benefits numeric(15,2) +); + + +-- +-- Name: project_origins_id_seq; Type: SEQUENCE; Schema: metais; Owner: - +-- + +CREATE SEQUENCE metais.project_origins_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: project_origins_id_seq; Type: SEQUENCE OWNED BY; Schema: metais; Owner: - +-- + +ALTER SEQUENCE metais.project_origins_id_seq OWNED BY metais.project_origins.id; + + +-- +-- Name: project_suppliers; Type: TABLE; Schema: metais; Owner: - +-- + +CREATE TABLE metais.project_suppliers ( + id bigint NOT NULL, + project_origin_id bigint NOT NULL, + origin_type_id bigint NOT NULL, + supplier_type_id bigint NOT NULL, + name character varying NOT NULL, + value character varying NOT NULL, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL, + date timestamp without time zone +); + + +-- +-- Name: project_suppliers_id_seq; Type: SEQUENCE; Schema: metais; Owner: - +-- + +CREATE SEQUENCE metais.project_suppliers_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: project_suppliers_id_seq; Type: SEQUENCE OWNED BY; Schema: metais; Owner: - +-- + +ALTER SEQUENCE metais.project_suppliers_id_seq OWNED BY metais.project_suppliers.id; + + +-- +-- Name: projects; Type: TABLE; Schema: metais; Owner: - +-- + +CREATE TABLE metais.projects ( + id bigint NOT NULL, + code character varying NOT NULL, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL, + uuid character varying +); + + +-- +-- Name: projects_id_seq; Type: SEQUENCE; Schema: metais; Owner: - +-- + +CREATE SEQUENCE metais.projects_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: projects_id_seq; Type: SEQUENCE OWNED BY; Schema: metais; Owner: - +-- + +ALTER SEQUENCE metais.projects_id_seq OWNED BY metais.projects.id; + + +-- +-- Name: supplier_types; Type: TABLE; Schema: metais; Owner: - +-- + +CREATE TABLE metais.supplier_types ( + id bigint NOT NULL, + name character varying NOT NULL, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: supplier_types_id_seq; Type: SEQUENCE; Schema: metais; Owner: - +-- + +CREATE SEQUENCE metais.supplier_types_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: supplier_types_id_seq; Type: SEQUENCE OWNED BY; Schema: metais; Owner: - +-- + +ALTER SEQUENCE metais.supplier_types_id_seq OWNED BY metais.supplier_types.id; + + +-- +-- Name: ar_internal_metadata; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.ar_internal_metadata ( + key character varying NOT NULL, + value character varying, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: pages; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.pages ( + id bigint NOT NULL, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL, + published_revision_id bigint, + latest_revision_id bigint, + phase_id bigint +); + + +-- +-- Name: pages_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.pages_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: pages_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.pages_id_seq OWNED BY public.pages.id; + + +-- +-- Name: phase_revision_ratings; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.phase_revision_ratings ( + id bigint NOT NULL, + phase_revision_id bigint NOT NULL, + rating_type_id bigint NOT NULL, + score integer, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: phase_revision_ratings_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.phase_revision_ratings_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: phase_revision_ratings_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.phase_revision_ratings_id_seq OWNED BY public.phase_revision_ratings.id; + + +-- +-- Name: phase_revisions; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.phase_revisions ( + id bigint NOT NULL, + revision_id bigint NOT NULL, + title character varying NOT NULL, + full_name character varying, + guarantor character varying, + description character varying, + budget character varying, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL, + body_html character varying, + total_score integer, + maximum_score integer, + redflags_count integer DEFAULT 0, + summary text, + recommendation text, + stage_id bigint, + current_status character varying, + phase_id bigint, + published boolean DEFAULT false, + was_published boolean DEFAULT false, + published_at timestamp without time zone +); + + +-- +-- Name: phase_revisions_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.phase_revisions_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: phase_revisions_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.phase_revisions_id_seq OWNED BY public.phase_revisions.id; + + +-- +-- Name: phase_types; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.phase_types ( + id bigint NOT NULL, + name character varying, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: phase_types_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.phase_types_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: phase_types_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.phase_types_id_seq OWNED BY public.phase_types.id; + + +-- +-- Name: phases; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.phases ( + id bigint NOT NULL, + project_id bigint, + phase_type_id bigint, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: phases_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.phases_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: phases_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.phases_id_seq OWNED BY public.phases.id; + + +-- +-- Name: project_stages; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.project_stages ( + id bigint NOT NULL, + name character varying NOT NULL, + "position" integer, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: project_stages_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.project_stages_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: project_stages_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.project_stages_id_seq OWNED BY public.project_stages.id; + + +-- +-- Name: projects; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.projects ( + id bigint NOT NULL, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL, + metais_code character varying +); + + +-- +-- Name: projects_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.projects_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: projects_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.projects_id_seq OWNED BY public.projects.id; + + +-- +-- Name: projects_metais_projects; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.projects_metais_projects ( + project_id bigint, + metais_project_id bigint +); + + +-- +-- Name: que_jobs; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.que_jobs ( + priority smallint DEFAULT 100 NOT NULL, + run_at timestamp with time zone DEFAULT now() NOT NULL, + job_id bigint NOT NULL, + job_class text NOT NULL, + args json DEFAULT '[]'::json NOT NULL, + error_count integer DEFAULT 0 NOT NULL, + last_error text, + queue text DEFAULT ''::text NOT NULL +); + + +-- +-- Name: TABLE que_jobs; Type: COMMENT; Schema: public; Owner: - +-- + +COMMENT ON TABLE public.que_jobs IS '3'; + + +-- +-- Name: que_jobs_job_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.que_jobs_job_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: que_jobs_job_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.que_jobs_job_id_seq OWNED BY public.que_jobs.job_id; + + +-- +-- Name: rating_types; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.rating_types ( + id bigint NOT NULL, + name character varying NOT NULL, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: rating_types_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.rating_types_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: rating_types_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.rating_types_id_seq OWNED BY public.rating_types.id; + + +-- +-- Name: revisions; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.revisions ( + id bigint NOT NULL, + page_id bigint NOT NULL, + version integer NOT NULL, + raw jsonb, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL, + title character varying NOT NULL, + tags character varying[] DEFAULT '{}'::character varying[] +); + + +-- +-- Name: revisions_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.revisions_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: revisions_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.revisions_id_seq OWNED BY public.revisions.id; + + +-- +-- Name: schema_migrations; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.schema_migrations ( + version character varying NOT NULL +); + + +-- +-- Name: origin_types id; Type: DEFAULT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.origin_types ALTER COLUMN id SET DEFAULT nextval('metais.origin_types_id_seq'::regclass); + + +-- +-- Name: project_documents id; Type: DEFAULT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.project_documents ALTER COLUMN id SET DEFAULT nextval('metais.project_documents_id_seq'::regclass); + + +-- +-- Name: project_event_types id; Type: DEFAULT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.project_event_types ALTER COLUMN id SET DEFAULT nextval('metais.project_event_types_id_seq'::regclass); + + +-- +-- Name: project_events id; Type: DEFAULT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.project_events ALTER COLUMN id SET DEFAULT nextval('metais.project_events_id_seq'::regclass); + + +-- +-- Name: project_links id; Type: DEFAULT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.project_links ALTER COLUMN id SET DEFAULT nextval('metais.project_links_id_seq'::regclass); + + +-- +-- Name: project_origins id; Type: DEFAULT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.project_origins ALTER COLUMN id SET DEFAULT nextval('metais.project_origins_id_seq'::regclass); + + +-- +-- Name: project_suppliers id; Type: DEFAULT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.project_suppliers ALTER COLUMN id SET DEFAULT nextval('metais.project_suppliers_id_seq'::regclass); + + +-- +-- Name: projects id; Type: DEFAULT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.projects ALTER COLUMN id SET DEFAULT nextval('metais.projects_id_seq'::regclass); + + +-- +-- Name: supplier_types id; Type: DEFAULT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.supplier_types ALTER COLUMN id SET DEFAULT nextval('metais.supplier_types_id_seq'::regclass); + + +-- +-- Name: pages id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.pages ALTER COLUMN id SET DEFAULT nextval('public.pages_id_seq'::regclass); + + +-- +-- Name: phase_revision_ratings id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.phase_revision_ratings ALTER COLUMN id SET DEFAULT nextval('public.phase_revision_ratings_id_seq'::regclass); + + +-- +-- Name: phase_revisions id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.phase_revisions ALTER COLUMN id SET DEFAULT nextval('public.phase_revisions_id_seq'::regclass); + + +-- +-- Name: phase_types id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.phase_types ALTER COLUMN id SET DEFAULT nextval('public.phase_types_id_seq'::regclass); + + +-- +-- Name: phases id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.phases ALTER COLUMN id SET DEFAULT nextval('public.phases_id_seq'::regclass); + + +-- +-- Name: project_stages id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.project_stages ALTER COLUMN id SET DEFAULT nextval('public.project_stages_id_seq'::regclass); + + +-- +-- Name: projects id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.projects ALTER COLUMN id SET DEFAULT nextval('public.projects_id_seq'::regclass); + + +-- +-- Name: que_jobs job_id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.que_jobs ALTER COLUMN job_id SET DEFAULT nextval('public.que_jobs_job_id_seq'::regclass); + + +-- +-- Name: rating_types id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.rating_types ALTER COLUMN id SET DEFAULT nextval('public.rating_types_id_seq'::regclass); + + +-- +-- Name: revisions id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.revisions ALTER COLUMN id SET DEFAULT nextval('public.revisions_id_seq'::regclass); + + +-- +-- Name: origin_types origin_types_pkey; Type: CONSTRAINT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.origin_types + ADD CONSTRAINT origin_types_pkey PRIMARY KEY (id); + + +-- +-- Name: project_documents project_documents_pkey; Type: CONSTRAINT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.project_documents + ADD CONSTRAINT project_documents_pkey PRIMARY KEY (id); + + +-- +-- Name: project_event_types project_event_types_pkey; Type: CONSTRAINT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.project_event_types + ADD CONSTRAINT project_event_types_pkey PRIMARY KEY (id); + + +-- +-- Name: project_events project_events_pkey; Type: CONSTRAINT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.project_events + ADD CONSTRAINT project_events_pkey PRIMARY KEY (id); + + +-- +-- Name: project_links project_links_pkey; Type: CONSTRAINT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.project_links + ADD CONSTRAINT project_links_pkey PRIMARY KEY (id); + + +-- +-- Name: project_origins project_origins_pkey; Type: CONSTRAINT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.project_origins + ADD CONSTRAINT project_origins_pkey PRIMARY KEY (id); + + +-- +-- Name: project_suppliers project_suppliers_pkey; Type: CONSTRAINT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.project_suppliers + ADD CONSTRAINT project_suppliers_pkey PRIMARY KEY (id); + + +-- +-- Name: projects projects_pkey; Type: CONSTRAINT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.projects + ADD CONSTRAINT projects_pkey PRIMARY KEY (id); + + +-- +-- Name: supplier_types supplier_types_pkey; Type: CONSTRAINT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.supplier_types + ADD CONSTRAINT supplier_types_pkey PRIMARY KEY (id); + + +-- +-- Name: ar_internal_metadata ar_internal_metadata_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.ar_internal_metadata + ADD CONSTRAINT ar_internal_metadata_pkey PRIMARY KEY (key); + + +-- +-- Name: pages pages_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.pages + ADD CONSTRAINT pages_pkey PRIMARY KEY (id); + + +-- +-- Name: phase_revision_ratings phase_revision_ratings_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.phase_revision_ratings + ADD CONSTRAINT phase_revision_ratings_pkey PRIMARY KEY (id); + + +-- +-- Name: phase_revisions phase_revisions_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.phase_revisions + ADD CONSTRAINT phase_revisions_pkey PRIMARY KEY (id); + + +-- +-- Name: phase_types phase_types_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.phase_types + ADD CONSTRAINT phase_types_pkey PRIMARY KEY (id); + + +-- +-- Name: phases phases_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.phases + ADD CONSTRAINT phases_pkey PRIMARY KEY (id); + + +-- +-- Name: project_stages project_stages_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.project_stages + ADD CONSTRAINT project_stages_pkey PRIMARY KEY (id); + + +-- +-- Name: projects projects_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.projects + ADD CONSTRAINT projects_pkey PRIMARY KEY (id); + + +-- +-- Name: que_jobs que_jobs_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.que_jobs + ADD CONSTRAINT que_jobs_pkey PRIMARY KEY (queue, priority, run_at, job_id); + + +-- +-- Name: rating_types rating_types_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.rating_types + ADD CONSTRAINT rating_types_pkey PRIMARY KEY (id); + + +-- +-- Name: revisions revisions_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.revisions + ADD CONSTRAINT revisions_pkey PRIMARY KEY (id); + + +-- +-- Name: schema_migrations schema_migrations_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.schema_migrations + ADD CONSTRAINT schema_migrations_pkey PRIMARY KEY (version); + + +-- +-- Name: index_metais.project_documents_on_origin_type_id; Type: INDEX; Schema: metais; Owner: - +-- + +CREATE INDEX "index_metais.project_documents_on_origin_type_id" ON metais.project_documents USING btree (origin_type_id); + + +-- +-- Name: index_metais.project_documents_on_project_origin_id; Type: INDEX; Schema: metais; Owner: - +-- + +CREATE INDEX "index_metais.project_documents_on_project_origin_id" ON metais.project_documents USING btree (project_origin_id); + + +-- +-- Name: index_metais.project_events_on_event_type_id; Type: INDEX; Schema: metais; Owner: - +-- + +CREATE INDEX "index_metais.project_events_on_event_type_id" ON metais.project_events USING btree (event_type_id); + + +-- +-- Name: index_metais.project_events_on_origin_type_id; Type: INDEX; Schema: metais; Owner: - +-- + +CREATE INDEX "index_metais.project_events_on_origin_type_id" ON metais.project_events USING btree (origin_type_id); + + +-- +-- Name: index_metais.project_events_on_project_origin_id; Type: INDEX; Schema: metais; Owner: - +-- + +CREATE INDEX "index_metais.project_events_on_project_origin_id" ON metais.project_events USING btree (project_origin_id); + + +-- +-- Name: index_metais.project_links_on_origin_type_id; Type: INDEX; Schema: metais; Owner: - +-- + +CREATE INDEX "index_metais.project_links_on_origin_type_id" ON metais.project_links USING btree (origin_type_id); + + +-- +-- Name: index_metais.project_links_on_project_origin_id; Type: INDEX; Schema: metais; Owner: - +-- + +CREATE INDEX "index_metais.project_links_on_project_origin_id" ON metais.project_links USING btree (project_origin_id); + + +-- +-- Name: index_metais.project_origins_on_origin_type_id; Type: INDEX; Schema: metais; Owner: - +-- + +CREATE INDEX "index_metais.project_origins_on_origin_type_id" ON metais.project_origins USING btree (origin_type_id); + + +-- +-- Name: index_metais.project_origins_on_project_id; Type: INDEX; Schema: metais; Owner: - +-- + +CREATE INDEX "index_metais.project_origins_on_project_id" ON metais.project_origins USING btree (project_id); + + +-- +-- Name: index_metais.project_suppliers_on_origin_type_id; Type: INDEX; Schema: metais; Owner: - +-- + +CREATE INDEX "index_metais.project_suppliers_on_origin_type_id" ON metais.project_suppliers USING btree (origin_type_id); + + +-- +-- Name: index_metais.project_suppliers_on_project_origin_id; Type: INDEX; Schema: metais; Owner: - +-- + +CREATE INDEX "index_metais.project_suppliers_on_project_origin_id" ON metais.project_suppliers USING btree (project_origin_id); + + +-- +-- Name: index_metais.project_suppliers_on_supplier_type_id; Type: INDEX; Schema: metais; Owner: - +-- + +CREATE INDEX "index_metais.project_suppliers_on_supplier_type_id" ON metais.project_suppliers USING btree (supplier_type_id); + + +-- +-- Name: index_pages_on_phase_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_pages_on_phase_id ON public.pages USING btree (phase_id); + + +-- +-- Name: index_phase_revision_ratings_on_phase_revision_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_phase_revision_ratings_on_phase_revision_id ON public.phase_revision_ratings USING btree (phase_revision_id); + + +-- +-- Name: index_phase_revision_ratings_on_rating_type_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_phase_revision_ratings_on_rating_type_id ON public.phase_revision_ratings USING btree (rating_type_id); + + +-- +-- Name: index_phase_revisions_on_phase_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_phase_revisions_on_phase_id ON public.phase_revisions USING btree (phase_id); + + +-- +-- Name: index_phase_revisions_on_revision_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_phase_revisions_on_revision_id ON public.phase_revisions USING btree (revision_id); + + +-- +-- Name: index_phase_revisions_on_stage_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_phase_revisions_on_stage_id ON public.phase_revisions USING btree (stage_id); + + +-- +-- Name: index_phases_on_phase_type_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_phases_on_phase_type_id ON public.phases USING btree (phase_type_id); + + +-- +-- Name: index_phases_on_project_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_phases_on_project_id ON public.phases USING btree (project_id); + + +-- +-- Name: index_projects_metais_projects_on_metais_project_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_projects_metais_projects_on_metais_project_id ON public.projects_metais_projects USING btree (metais_project_id); + + +-- +-- Name: index_projects_metais_projects_on_project_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_projects_metais_projects_on_project_id ON public.projects_metais_projects USING btree (project_id); + + +-- +-- Name: index_revisions_on_page_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_revisions_on_page_id ON public.revisions USING btree (page_id); + + +-- +-- Name: index_revisions_on_page_id_and_version; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX index_revisions_on_page_id_and_version ON public.revisions USING btree (page_id, version); + + +-- +-- Name: index_revisions_on_tags; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_revisions_on_tags ON public.revisions USING gin (tags); + + +-- +-- Name: project_origins fk_rails_20e053d2e1; Type: FK CONSTRAINT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.project_origins + ADD CONSTRAINT fk_rails_20e053d2e1 FOREIGN KEY (project_id) REFERENCES metais.projects(id); + + +-- +-- Name: project_links fk_rails_2aa878383f; Type: FK CONSTRAINT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.project_links + ADD CONSTRAINT fk_rails_2aa878383f FOREIGN KEY (project_origin_id) REFERENCES metais.project_origins(id); + + +-- +-- Name: project_events fk_rails_2f479867fb; Type: FK CONSTRAINT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.project_events + ADD CONSTRAINT fk_rails_2f479867fb FOREIGN KEY (event_type_id) REFERENCES metais.project_event_types(id); + + +-- +-- Name: project_events fk_rails_473e22a88e; Type: FK CONSTRAINT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.project_events + ADD CONSTRAINT fk_rails_473e22a88e FOREIGN KEY (origin_type_id) REFERENCES metais.origin_types(id); + + +-- +-- Name: project_origins fk_rails_4e9327b9e1; Type: FK CONSTRAINT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.project_origins + ADD CONSTRAINT fk_rails_4e9327b9e1 FOREIGN KEY (origin_type_id) REFERENCES metais.origin_types(id); + + +-- +-- Name: project_suppliers fk_rails_596e77825e; Type: FK CONSTRAINT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.project_suppliers + ADD CONSTRAINT fk_rails_596e77825e FOREIGN KEY (project_origin_id) REFERENCES metais.project_origins(id); + + +-- +-- Name: project_suppliers fk_rails_6d5c5bc861; Type: FK CONSTRAINT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.project_suppliers + ADD CONSTRAINT fk_rails_6d5c5bc861 FOREIGN KEY (origin_type_id) REFERENCES metais.origin_types(id); + + +-- +-- Name: project_links fk_rails_82aaaab23a; Type: FK CONSTRAINT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.project_links + ADD CONSTRAINT fk_rails_82aaaab23a FOREIGN KEY (origin_type_id) REFERENCES metais.origin_types(id); + + +-- +-- Name: project_documents fk_rails_94c7d5ceab; Type: FK CONSTRAINT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.project_documents + ADD CONSTRAINT fk_rails_94c7d5ceab FOREIGN KEY (origin_type_id) REFERENCES metais.origin_types(id); + + +-- +-- Name: project_documents fk_rails_db808f0ecf; Type: FK CONSTRAINT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.project_documents + ADD CONSTRAINT fk_rails_db808f0ecf FOREIGN KEY (project_origin_id) REFERENCES metais.project_origins(id); + + +-- +-- Name: project_suppliers fk_rails_e14d4d6e7a; Type: FK CONSTRAINT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.project_suppliers + ADD CONSTRAINT fk_rails_e14d4d6e7a FOREIGN KEY (supplier_type_id) REFERENCES metais.supplier_types(id); + + +-- +-- Name: project_events fk_rails_e243232959; Type: FK CONSTRAINT; Schema: metais; Owner: - +-- + +ALTER TABLE ONLY metais.project_events + ADD CONSTRAINT fk_rails_e243232959 FOREIGN KEY (project_origin_id) REFERENCES metais.project_origins(id); + + +-- +-- Name: projects_metais_projects fk_rails_747f5e41f3; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.projects_metais_projects + ADD CONSTRAINT fk_rails_747f5e41f3 FOREIGN KEY (project_id) REFERENCES public.projects(id); + + +-- +-- Name: phases fk_rails_7768cfc98c; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.phases + ADD CONSTRAINT fk_rails_7768cfc98c FOREIGN KEY (phase_type_id) REFERENCES public.phase_types(id); + + +-- +-- Name: projects_metais_projects fk_rails_7d4b01aec6; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.projects_metais_projects + ADD CONSTRAINT fk_rails_7d4b01aec6 FOREIGN KEY (metais_project_id) REFERENCES metais.projects(id); + + +-- +-- Name: phase_revision_ratings fk_rails_89f94d4743; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.phase_revision_ratings + ADD CONSTRAINT fk_rails_89f94d4743 FOREIGN KEY (phase_revision_id) REFERENCES public.phase_revisions(id); + + +-- +-- Name: phase_revision_ratings fk_rails_8f89f5f94e; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.phase_revision_ratings + ADD CONSTRAINT fk_rails_8f89f5f94e FOREIGN KEY (rating_type_id) REFERENCES public.rating_types(id); + + +-- +-- Name: pages fk_rails_9214ad0f21; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.pages + ADD CONSTRAINT fk_rails_9214ad0f21 FOREIGN KEY (phase_id) REFERENCES public.phases(id); + + +-- +-- Name: phase_revisions fk_rails_9b7644f642; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.phase_revisions + ADD CONSTRAINT fk_rails_9b7644f642 FOREIGN KEY (stage_id) REFERENCES public.project_stages(id); + + +-- +-- Name: phase_revisions fk_rails_9bbd5a8be5; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.phase_revisions + ADD CONSTRAINT fk_rails_9bbd5a8be5 FOREIGN KEY (revision_id) REFERENCES public.revisions(id); + + +-- +-- Name: phases fk_rails_b0efe660f5; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.phases + ADD CONSTRAINT fk_rails_b0efe660f5 FOREIGN KEY (project_id) REFERENCES public.projects(id); + + +-- +-- Name: phase_revisions fk_rails_c47dd3e5d5; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.phase_revisions + ADD CONSTRAINT fk_rails_c47dd3e5d5 FOREIGN KEY (phase_id) REFERENCES public.phases(id); + + +-- +-- Name: revisions fk_rails_d1037952e2; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.revisions + ADD CONSTRAINT fk_rails_d1037952e2 FOREIGN KEY (page_id) REFERENCES public.pages(id); + + +-- +-- Name: pages fk_rails_ee4b1c338f; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.pages + ADD CONSTRAINT fk_rails_ee4b1c338f FOREIGN KEY (latest_revision_id) REFERENCES public.revisions(id); + + +-- +-- Name: pages fk_rails_ffffd09d52; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.pages + ADD CONSTRAINT fk_rails_ffffd09d52 FOREIGN KEY (published_revision_id) REFERENCES public.revisions(id); + + +-- +-- PostgreSQL database dump complete +-- + +SET search_path TO "$user", public; + +INSERT INTO "schema_migrations" (version) VALUES +('20171024153945'), +('20171024154001'), +('20171024155327'), +('20171025151045'), +('20171027113100'), +('20171027113228'), +('20171027113301'), +('20171027121514'), +('20171027121801'), +('20171027121807'), +('20171027121959'), +('20171027122134'), +('20171030115814'), +('20171031125640'), +('20171031131417'), +('20171108160920'), +('20171110104007'), +('20171110114322'), +('20180531154604'), +('20180531162036'), +('20180531165022'), +('20180620144613'), +('20220306165121'), +('20240609101956'), +('20240609114857'), +('20240609120517'), +('20240610100714'), +('20240610100956'), +('20240610102411'), +('20240610110713'), +('20240611122213'), +('20240611153648'), +('20240611153759'), +('20240613113501'), +('20240621112043'), +('20240715175807'), +('20240715181117'), +('20240715182749'), +('20240716083355'), +('20240716120919'), +('20240724071253'), +('20240724072736'), +('20240730180654'), +('20240731124741'), +('20240801081124'), +('20240820080110'), +('20240820080303'), +('20240821210736'), +('20240821212620'), +('20240822112026'), +('20240822143116'), +('20240823082322'), +('20240825111806'), +('20240825115911'), +('20240924210648'); diff --git a/lib/tasks/metais.rake b/lib/tasks/metais.rake new file mode 100644 index 0000000..5ee7f2c --- /dev/null +++ b/lib/tasks/metais.rake @@ -0,0 +1,17 @@ +namespace :metais do + task daily_sync: :environment do + Metais::DailySyncProjectsJob.perform_later + end + + task daily_sync_evaluations: :environment do + LinkMetaisProjectsAndEvaluationsJob.perform_later + end + + task init_sync: :environment do + Metais::InitialSyncProjectsJob.perform_later + end + + task pair_older_projects: :environment do + SetMetaisCodesForProjectsJob.perform_later + end +end diff --git a/spec/factories/metais/origin_type.rb b/spec/factories/metais/origin_type.rb new file mode 100644 index 0000000..0882449 --- /dev/null +++ b/spec/factories/metais/origin_type.rb @@ -0,0 +1,5 @@ +FactoryBot.define do + factory :metais_origin_type, class: 'Metais::OriginType' do + name { "MetaIS" } + end +end \ No newline at end of file diff --git a/spec/factories/metais/project.rb b/spec/factories/metais/project.rb new file mode 100644 index 0000000..9ac9ce8 --- /dev/null +++ b/spec/factories/metais/project.rb @@ -0,0 +1,7 @@ +# spec/factories/metais_projects.rb +FactoryBot.define do + factory :metais_project, class: 'Metais::Project' do + code { "project_code" } + uuid { "project_uuid" } + end +end diff --git a/spec/jobs/metais/daily_sync_projects_job_spec.rb b/spec/jobs/metais/daily_sync_projects_job_spec.rb new file mode 100644 index 0000000..42b66cd --- /dev/null +++ b/spec/jobs/metais/daily_sync_projects_job_spec.rb @@ -0,0 +1,74 @@ +require 'rails_helper' + +RSpec.describe Metais::SyncProjectSuppliersJob, type: :job do + let!(:origin_type) { Metais::OriginType.create!(name: 'MetaIS') } + + let(:supplier_type_nfp) { Metais::SupplierType.create!(name: "NFP") } + let(:supplier_type_vo) { Metais::SupplierType.create!(name: "VO") } + let(:supplier_type_crz) { Metais::SupplierType.create!(name: "CRZ") } + + let!(:metais_project) { create(:metais_project) } + let(:project_origin) { Metais::ProjectOrigin.create!(project: metais_project, origin_type: origin_type, title: "Test") } + + let(:latest_version) { double('LatestVersion', kod_metais: 'code1', link_nfp: "http://example.com/nfp", datum_nfp: Date.today, vo: "http://example.com/vo", vyhlasenie_vo: Date.today, zmluva_o_dielo_crz: "http://example.com/crz", zmluva_o_dielo: Date.today) } + let(:datahub_project) { instance_double(Datahub::Metais::Project, uuid: 'uuid1', latest_version: latest_version) } + + before do + allow(datahub_project).to receive(:latest_version).and_return(latest_version) + + allow(Metais::SupplierType).to receive(:find_by).with(name: "NFP").and_return(supplier_type_nfp) + allow(Metais::SupplierType).to receive(:find_by).with(name: "VO").and_return(supplier_type_vo) + allow(Metais::SupplierType).to receive(:find_by).with(name: "CRZ").and_return(supplier_type_crz) + allow_any_instance_of(Metais::SyncProjectSuppliersJob).to receive(:extract_links).and_return([]) + + crz_html = <<-HTML + + +
      +
    • + Dodávateľ: + Supplier Name +
    • +
    • + IČO: + 12345678 +
    • +
    + + + HTML + + stub_request(:get, "http://example.com/crz").to_return(body: crz_html, headers: { 'Content-Type' => 'text/html' }) + allow_any_instance_of(Metais::SyncProjectSuppliersJob).to receive(:open).with("http://example.com/crz").and_return(StringIO.new(crz_html)) + end + + it 'creates ProjectSupplier records for NFP links' do + allow_any_instance_of(Metais::SyncProjectSuppliersJob).to receive(:extract_links).with('http://example.com/nfp').and_return(['http://supplier1.com', 'http://supplier2.com']) + expect { described_class.perform_now(project_origin, datahub_project) }.to change(Metais::ProjectSupplier, :count).by(2) + + suppliers = Metais::ProjectSupplier.where(supplier_type: supplier_type_nfp) + expect(suppliers.map(&:name)).to contain_exactly('http://supplier1.com', 'http://supplier2.com') + end + + it 'creates ProjectSupplier records for VO links' do + allow_any_instance_of(Metais::SyncProjectSuppliersJob).to receive(:extract_links).with('http://example.com/vo').and_return(['http://supplier3.com']) + expect { described_class.perform_now(project_origin, datahub_project) }.to change(Metais::ProjectSupplier, :count).by(1) + + supplier = Metais::ProjectSupplier.find_by(name: 'http://supplier3.com') + expect(supplier).to be_present + expect(supplier.supplier_type).to eq(supplier_type_vo) + end + + it 'updates project_origin with supplier info for CRZ links' do + allow_any_instance_of(Metais::SyncProjectSuppliersJob).to receive(:extract_links).with('http://example.com/crz').and_return(['http://supplier4.com']) + allow_any_instance_of(Metais::SyncProjectSuppliersJob).to receive(:valid_url?).and_return(true) + + # Mock the parsing to return specific values + allow_any_instance_of(Metais::SyncProjectSuppliersJob).to receive(:parse_crz_document).and_return({ supplier: 'Supplier Info', cin: 12345678 }) + + expect { described_class.perform_now(project_origin, datahub_project) }.to change(Metais::ProjectSupplier, :count).by(1) + + expect(project_origin.supplier).to eq('Supplier Info') + expect(project_origin.supplier_cin).to eq(12345678) + end +end diff --git a/spec/jobs/metais/initial_sync_projects_job_spec.rb b/spec/jobs/metais/initial_sync_projects_job_spec.rb new file mode 100644 index 0000000..dd675ee --- /dev/null +++ b/spec/jobs/metais/initial_sync_projects_job_spec.rb @@ -0,0 +1,22 @@ +require 'rails_helper' + +RSpec.describe Metais::InitialSyncProjectsJob, type: :job do + let(:latest_version) { double('LatestVersion', kod_metais: 'code1') } + let(:datahub_project) { instance_double(Datahub::Metais::Project, uuid: 'uuid1', latest_version: latest_version) } + let(:metais_project) { instance_double(Metais::Project, save!: true) } + + before do + allow(Datahub::Metais::Project).to receive(:find_each).and_yield(datahub_project) + allow(Metais::Project).to receive(:find_or_initialize_by).with(code: 'code1', uuid: 'uuid1').and_return(metais_project) + allow(Metais::SyncProjectJob).to receive(:perform_later) + end + + it 'processes each Datahub project and enqueues a SyncProjectJob' do + Metais::InitialSyncProjectsJob.perform_now + + expect(Datahub::Metais::Project).to have_received(:find_each) + expect(Metais::Project).to have_received(:find_or_initialize_by).with(code: 'code1', uuid: 'uuid1') + expect(metais_project).to have_received(:save!) + expect(Metais::SyncProjectJob).to have_received(:perform_later).with(metais_project, datahub_project) + end +end diff --git a/spec/jobs/metais/project_data_extraction_delete_job_spec.rb b/spec/jobs/metais/project_data_extraction_delete_job_spec.rb new file mode 100644 index 0000000..d3e8f81 --- /dev/null +++ b/spec/jobs/metais/project_data_extraction_delete_job_spec.rb @@ -0,0 +1,47 @@ +require 'rails_helper' +require 'net/http' + +RSpec.describe Metais::ProjectDataExtractionDeleteJob, type: :job do + include ActiveJob::TestHelper + + let(:project_uuid) { 'sample-uuid' } + let(:api_url) { 'http://example.com/api' } + let(:url) { "#{api_url}/projects/#{project_uuid}" } + let(:uri) { URI(url) } + let(:response) { instance_double('Net::HTTPResponse') } + + before do + allow(ENV).to receive(:fetch).with('API_URL').and_return(api_url) + allow(Net::HTTP).to receive(:start).and_return(response) + end + + describe '#perform' do + context 'when the delete request is successful' do + before do + allow(response).to receive(:is_a?).with(Net::HTTPSuccess).and_return(true) + end + + it 'sends a delete request' do + expect { + described_class.perform_now(project_uuid) + }.not_to raise_error + + expect(Net::HTTP).to have_received(:start).with(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') + end + end + + context 'when the delete request fails' do + before do + allow(response).to receive(:is_a?).with(Net::HTTPSuccess).and_return(false) + allow(response).to receive(:code).and_return('500') + allow(response).to receive(:body).and_return('Internal Server Error') + end + + it 'raises a RuntimeError with the correct message' do + expect { + described_class.perform_now(project_uuid) + }.to raise_error(RuntimeError, /Failed to delete project: 500, body: Internal Server Error/) + end + end + end +end diff --git a/spec/jobs/metais/project_data_extraction_job_spec.rb b/spec/jobs/metais/project_data_extraction_job_spec.rb new file mode 100644 index 0000000..2f00510 --- /dev/null +++ b/spec/jobs/metais/project_data_extraction_job_spec.rb @@ -0,0 +1,59 @@ +require 'rails_helper' +require 'net/http' + +RSpec.describe Metais::ProjectDataExtractionJob, type: :job do + let(:project_uuid) { 'sample-uuid' } + let(:api_url) { 'http://example.com/api' } + let(:url) { "#{api_url}/projects/#{project_uuid}" } + + before do + allow(ENV).to receive(:fetch).with('API_URL').and_return(api_url) + end + + describe '#perform' do + let(:response) { instance_double(Net::HTTPResponse) } + + before do + allow(Net::HTTP).to receive(:post).and_return(response) + end + + context 'when the response status is 202 Accepted' do + before do + allow(response).to receive(:is_a?).with(Net::HTTPAccepted).and_return(true) + allow(response).to receive(:[]).with('Location').and_return('http://example.com/location') + end + + it 'enqueues the Metais::ProjectDataExtractionStatusJob with the correct parameters' do + expect(Metais::ProjectDataExtractionStatusJob).to receive(:perform_later).with(project_uuid, 'http://example.com/location') + subject.perform(project_uuid) + end + end + + context 'when the response status is not 202 Accepted' do + before do + allow(response).to receive(:is_a?).with(Net::HTTPAccepted).and_return(false) + allow(response).to receive(:code).and_return('400') + allow(response).to receive(:body).and_return('Bad Request') + end + + it 'raises a RuntimeError with the appropriate message' do + expect { + subject.perform(project_uuid) + }.to raise_error(RuntimeError, /Response status is 400. Message: Bad Request/) + end + end + + context 'when the Location header is missing' do + before do + allow(response).to receive(:is_a?).with(Net::HTTPAccepted).and_return(true) + allow(response).to receive(:[]).with('Location').and_return(nil) + end + + it 'raises a RuntimeError indicating the missing Location header' do + expect { + subject.perform(project_uuid) + }.to raise_error(RuntimeError, /Expected 'Location' header not found in the response./) + end + end + end +end diff --git a/spec/jobs/metais/project_data_extraction_result_job_spec.rb b/spec/jobs/metais/project_data_extraction_result_job_spec.rb new file mode 100644 index 0000000..5b83902 --- /dev/null +++ b/spec/jobs/metais/project_data_extraction_result_job_spec.rb @@ -0,0 +1,137 @@ +require 'rails_helper' +require 'net/http' + +RSpec.describe Metais::ProjectDataExtractionResultJob, type: :job do + include ActiveJob::TestHelper + + let(:project_uuid) { 'sample-uuid' } + let(:location_header) { 'http://example.com/location' } + let(:api_url) { 'http://example.com/api' } + let(:url) { "#{api_url}/projects/#{project_uuid}" } + + let(:response) { instance_double('Net::HTTPResponse') } + let(:body) { { 'status' => 'Done', 'result' => result_data }.to_json } + let(:result_data) do + { + 'harmonogram' => [], + 'responsible' => { 'first_name' => 'John', 'surname' => 'Doe' }, + 'capex' => 1000, + 'opex' => 500, + 'declared' => 200, + 'kpis' => ['KPI 1', 'KPI 2'], + 'goals' => ['Goal 1', 'Goal 2'] + } + end + let(:metais_project) { instance_double('Metais::Project') } + let(:project_origin) { instance_double('Metais::ProjectOrigin') } + let(:origin_type) { instance_double('Metais::OriginType') } + let(:event_type) { instance_double('Metais::ProjectEventType') } + + let(:project_origins_double) { double('ProjectOrigins') } + + before do + allow(ENV).to receive(:fetch).with('API_URL').and_return(api_url) + end + + describe '#perform' do + before do + allow(Net::HTTP).to receive(:get_response).and_return(response) + end + + context 'when the response is successful and the project exists' do + before do + allow(response).to receive(:code).and_return('200') + allow(response).to receive(:body).and_return(body) + allow(JSON).to receive(:parse).and_return('status' => 'Done', 'result' => result_data) + + allow(Metais::Project).to receive(:find_by).with(uuid: project_uuid).and_return(metais_project) + + allow(metais_project).to receive(:project_origins).and_return(project_origins_double) + + allow(project_origins_double).to receive(:first).and_return(double('FirstProjectOrigin', title: 'Origin Title')) + allow(project_origins_double).to receive(:find_or_initialize_by).with( + title: 'Origin Title', + project: metais_project, + origin_type: origin_type + ).and_return(project_origin) + + allow(project_origin).to receive(:project_manager=) + allow(project_origin).to receive(:approved_investment=) + allow(project_origin).to receive(:approved_operation=) + allow(project_origin).to receive(:benefits=) + allow(project_origin).to receive(:targets_text=) + allow(project_origin).to receive(:save!) + + allow(Metais::OriginType).to receive(:find_by).with(name: 'AI').and_return(origin_type) + + allow(Metais::ProjectEventType).to receive(:find_by).with(name: 'Predpoklad').and_return(event_type) + + allow(Metais::ProjectEvent).to receive(:find_or_initialize_by).and_return(double('Metais::ProjectEvent', save!: true)) + end + + it 'successfully processes the result and sends a delete request' do + expect { + described_class.perform_now(project_uuid, location_header) + }.to have_enqueued_job(Metais::ProjectDataExtractionDeleteJob).with(project_uuid) + end + end + + context 'when the response status is not 200 or 202' do + before do + allow(response).to receive(:code).and_return('500') + allow(response).to receive(:body).and_return('Internal Server Error') + end + + it 'raises a RuntimeError with the correct message' do + expect { + described_class.perform_now(project_uuid, location_header) + }.to raise_error(RuntimeError, /Unexpected response status: 500, body: Internal Server Error/) + end + end + + context 'when JSON parsing fails' do + before do + allow(response).to receive(:code).and_return('200') + allow(response).to receive(:body).and_return('invalid json') + allow(JSON).to receive(:parse).and_raise(JSON::ParserError.new('error')) + end + + it 'raises a RuntimeError with the correct message' do + expect { + described_class.perform_now(project_uuid, location_header) + }.to raise_error(RuntimeError, /Failed to parse JSON response: error/) + end + end + + context 'when project cannot be found' do + before do + allow(response).to receive(:code).and_return('200') + allow(response).to receive(:body).and_return(body) + allow(JSON).to receive(:parse).and_return('status' => 'Done', 'result' => {}) + allow(Metais::Project).to receive(:find_by).with(uuid: project_uuid).and_return(nil) + end + + it 'raises a RuntimeError indicating the project was not found' do + expect { + described_class.perform_now(project_uuid, location_header) + }.to raise_error(RuntimeError, /Couldn't find MetaIS project with 'uuid'=sample-uuid/) + end + end + + context 'when project origin cannot be found or saved' do + before do + allow(response).to receive(:code).and_return('200') + allow(response).to receive(:body).and_return(body) + allow(JSON).to receive(:parse).and_return('status' => 'Done', 'result' => result_data) + + allow(project_origins_double).to receive(:find_or_initialize_by).and_return(nil) + end + + it 'raises an error when the project origin cannot be found or initialized' do + expect { + described_class.perform_now(project_uuid, location_header) + }.to raise_error(RuntimeError, /Couldn't find MetaIS project with 'uuid'=sample-uuid/) + end + end + end +end diff --git a/spec/jobs/metais/project_data_extraction_status_job_spec.rb b/spec/jobs/metais/project_data_extraction_status_job_spec.rb new file mode 100644 index 0000000..1483f1f --- /dev/null +++ b/spec/jobs/metais/project_data_extraction_status_job_spec.rb @@ -0,0 +1,68 @@ +require 'rails_helper' +require 'net/http' + +RSpec.describe Metais::ProjectDataExtractionStatusJob, type: :job do + include ActiveJob::TestHelper + + let(:project_uuid) { 'sample-uuid' } + let(:location_header) { 'http://example.com/location' } + let(:api_url) { 'http://example.com/api' } + let(:url) { "#{api_url}/projects/#{project_uuid}/status" } + + before do + allow(ENV).to receive(:fetch).with('API_URL').and_return(api_url) + end + + describe '#perform' do + let(:response) { instance_double(Net::HTTPResponse) } + + before do + allow(Net::HTTP).to receive(:get_response).and_return(response) + end + + context 'when Retry-After header is present' do + before do + allow(response).to receive(:key?).with('Retry-After').and_return(true) + allow(response).to receive(:[]).with('Retry-After').and_return('10') + end + + it 're-enqueues the job with a delay' do + Metais::ProjectDataExtractionStatusJob.perform_now(project_uuid, location_header) + + expect(enqueued_jobs).to include( + a_hash_including( + job: Metais::ProjectDataExtractionStatusJob, + args: [project_uuid, location_header], + queue: 'metais_data_extraction' + ) + ) + end + end + + context 'when Retry-After header is not present' do + before do + allow(response).to receive(:key?).with('Retry-After').and_return(false) + allow(response).to receive(:[]).with('Location').and_return('http://example.com/new_location') + end + + it 'enqueues the Metais::ProjectDataExtractionResultJob with the correct parameters' do + expect { + subject.perform(project_uuid, location_header) + }.to have_enqueued_job(Metais::ProjectDataExtractionResultJob).with(project_uuid, 'http://example.com/new_location') + end + + context 'when Location header is missing' do + before do + allow(response).to receive(:key?).with('Retry-After').and_return(false) + allow(response).to receive(:[]).with('Location').and_return(nil) + end + + it 'raises an error indicating the missing Location header' do + expect { + subject.perform(project_uuid, location_header) + }.to raise_error(RuntimeError, /Location header missing in response/) + end + end + end + end +end diff --git a/spec/jobs/metais/sync_project_documents_job_spec.rb b/spec/jobs/metais/sync_project_documents_job_spec.rb new file mode 100644 index 0000000..32e0d9c --- /dev/null +++ b/spec/jobs/metais/sync_project_documents_job_spec.rb @@ -0,0 +1,57 @@ +require 'rails_helper' + +RSpec.describe Metais::SyncProjectDocumentsJob, type: :job do + include ActiveJob::TestHelper + + let(:latest_version) do + double('LatestVersion', + nazov: 'Document Title', + filename: 'document.pdf') + end + + let(:document) do + double('Document', + uuid: 'doc-uuid', + latest_version: latest_version) + end + + let(:metais_project) do + double('MetaisProject', documents: [document]) + end + + let(:project_origin) { double('ProjectOrigin') } + let(:project_document) { instance_double(Metais::ProjectDocument, save!: true) } + + before do + allow(Metais::ProjectDocument).to receive(:find_or_initialize_by).and_return(project_document) + + allow(Metais::OriginType).to receive(:find_by).with(name: 'MetaIS').and_return(double('OriginType')) + + allow(project_document).to receive(:name=) + allow(project_document).to receive(:filename=) + allow(project_document).to receive(:value=) + allow(project_document).to receive(:description=) + end + + after do + clear_enqueued_jobs + clear_performed_jobs + end + + it 'processes each document and creates or updates ProjectDocument records' do + Metais::SyncProjectDocumentsJob.perform_now(project_origin, metais_project) + + expect(Metais::ProjectDocument).to have_received(:find_or_initialize_by).with( + uuid: document.uuid, + project_origin: project_origin, + origin_type: anything + ) + + expect(project_document).to have_received(:name=).with('Document Title') + expect(project_document).to have_received(:filename=).with('document.pdf') + expect(project_document).to have_received(:value=).with('https://metais.vicepremier.gov.sk/dms/file/doc-uuid') + expect(project_document).to have_received(:description=).with('MetaIS') + + expect(project_document).to have_received(:save!) + end +end diff --git a/spec/jobs/metais/sync_project_events_job_spec.rb b/spec/jobs/metais/sync_project_events_job_spec.rb new file mode 100644 index 0000000..c14d4d0 --- /dev/null +++ b/spec/jobs/metais/sync_project_events_job_spec.rb @@ -0,0 +1,63 @@ +require 'rails_helper' + +RSpec.describe Metais::SyncProjectEventsJob, type: :job do + include ActiveJob::TestHelper + + let(:project_origin) { instance_double('Metais::ProjectOrigin') } + + let(:origin_type) { instance_double('Metais::OriginType') } + let(:event_type) { instance_double('Metais::ProjectEventType') } + + let(:latest_version) { double('LatestVersion', kod_metais: 'code1') } + let(:datahub_project) { instance_double(Datahub::Metais::Project, uuid: 'uuid1', latest_version: latest_version) } + + let(:status_change) { double(Datahub::Metais::ProjectChange, field: 'status', created_at: Time.now, new_value: 'new_status', old_value: 'old_status') } + let(:phase_change) { double(Datahub::Metais::ProjectChange, field: 'faza_projektu', created_at: Time.now, new_value: 'new_phase', old_value: 'old_phase') } + + let(:codelist_project_state_old) { double(Datahub::Metais::CodelistProjectState, nazov: 'Old Status') } + let(:codelist_project_state_new) { double(Datahub::Metais::CodelistProjectState, nazov: 'New Status') } + let(:codelist_project_phase_old) { double(Datahub::Metais::CodelistProjectPhase, nazov: 'Old Phase') } + let(:codelist_project_phase_new) { double(Datahub::Metais::CodelistProjectPhase, nazov: 'New Phase') } + + before do + allow(Metais::OriginType).to receive(:find_by).with(name: 'MetaIS').and_return(origin_type) + allow(Metais::ProjectEventType).to receive(:find_by).with(name: 'Realita').and_return(event_type) + + allow(Datahub::Metais::ProjectChange).to receive(:where).with(project_version: datahub_project.latest_version).and_return([status_change, phase_change]) + + allow(Datahub::Metais::CodelistProjectState).to receive(:find_by).with(code: 'old_status').and_return(codelist_project_state_old) + allow(Datahub::Metais::CodelistProjectState).to receive(:find_by).with(code: 'new_status').and_return(codelist_project_state_new) + allow(Datahub::Metais::CodelistProjectPhase).to receive(:find_by).with(code: 'old_phase').and_return(codelist_project_phase_old) + allow(Datahub::Metais::CodelistProjectPhase).to receive(:find_by).with(code: 'new_phase').and_return(codelist_project_phase_new) + + @project_event_double = instance_double('Metais::ProjectEvent') + allow(Metais::ProjectEvent).to receive(:find_or_initialize_by).and_return(@project_event_double) + allow(@project_event_double).to receive(:save!) + end + + describe '#perform' do + it 'processes all changes and creates events correctly' do + described_class.perform_now(project_origin, datahub_project) + + expect(Metais::ProjectEvent).to have_received(:find_or_initialize_by).with( + project_origin: project_origin, + origin_type: origin_type, + event_type: event_type, + name: 'New Status', + value: "Stav projektu bol zmenený z\n old status na\n new status", + date: status_change.created_at + ).once + + expect(Metais::ProjectEvent).to have_received(:find_or_initialize_by).with( + project_origin: project_origin, + origin_type: origin_type, + event_type: event_type, + name: 'New Phase', + value: "Fáza projektu bola zmenená z\n old phase na\n new phase", + date: phase_change.created_at + ).once + + expect(@project_event_double).to have_received(:save!).twice + end + end +end diff --git a/spec/jobs/metais/sync_project_job_spec.rb b/spec/jobs/metais/sync_project_job_spec.rb new file mode 100644 index 0000000..dab9fc6 --- /dev/null +++ b/spec/jobs/metais/sync_project_job_spec.rb @@ -0,0 +1,72 @@ +require 'rails_helper' + +RSpec.describe Metais::SyncProjectJob, type: :job do + include ActiveJob::TestHelper + + let(:latest_version) do + double('LatestVersion', + nazov: 'Project Title', + popis: 'Project Description', + status: 'Active', + faza_projektu: 'Phase 1', + prijimatel: 'Guarantor Name', + metais_created_at: Time.now, + datum_zacatia: Date.today, + termin_ukoncenia: Date.today + 1.year, + zmena_stavu: Date.today, + program: 'Program UUID', + suma_vydavkov: 100_000, + rocne_naklady: 20_000, + schvaleny_rozpocet: 120_000, + schvalene_rocne_naklady: 25_000) + end + + let(:datahub_project) { double(Datahub::Metais::Project, latest_version: latest_version, uuid: 'uuid1') } + let(:project) { double(Metais::Project) } + let(:project_origin) { instance_double(Metais::ProjectOrigin, save!: true) } + + before do + allow(Metais::ProjectOrigin).to receive(:find_or_initialize_by).and_return(project_origin) + + allow(Metais::OriginType).to receive(:find_by).with(name: 'MetaIS').and_return(double('OriginType')) + allow(Datahub::Metais::CodelistProjectState).to receive(:find_by).with(code: 'Active').and_return(double('ProjectState', nazov: 'Active State')) + allow(Datahub::Metais::CodelistProjectPhase).to receive(:find_by).with(code: 'Phase 1').and_return(double('ProjectPhase', nazov: 'Phase 1')) + allow(Datahub::Metais::CodelistProgram).to receive(:find_by).with(uuid: 'Program UUID').and_return(double('Program', nazov: 'Program Name')) + + allow(project_origin).to receive(:title=) + allow(project_origin).to receive(:description=) + allow(project_origin).to receive(:status=) + allow(project_origin).to receive(:phase=) + allow(project_origin).to receive(:guarantor=) + allow(project_origin).to receive(:metais_created_at=) + allow(project_origin).to receive(:start_date=) + allow(project_origin).to receive(:end_date=) + allow(project_origin).to receive(:status_change_date=) + allow(project_origin).to receive(:finance_source=) + allow(project_origin).to receive(:investment=) + allow(project_origin).to receive(:operation=) + allow(project_origin).to receive(:approved_investment=) + allow(project_origin).to receive(:approved_operation=) + + allow(Metais::ProjectDataExtractionJob).to receive(:perform_later) + allow(Metais::SyncProjectSuppliersJob).to receive(:perform_later) + allow(Metais::SyncProjectDocumentsJob).to receive(:perform_later) + allow(Metais::SyncProjectEventsJob).to receive(:perform_later) + end + + after do + clear_enqueued_jobs + clear_performed_jobs + end + + it 'updates or creates a ProjectOrigin and enqueues subsequent jobs' do + Metais::SyncProjectJob.perform_now(project, datahub_project) + + expect(enqueued_jobs).to include(a_hash_including(job: Metais::ProjectDataExtractionJob, + args: [datahub_project.uuid], + queue: 'metais_data_extraction')) + expect(Metais::SyncProjectSuppliersJob).to have_received(:perform_later).with(project_origin, datahub_project) + expect(Metais::SyncProjectDocumentsJob).to have_received(:perform_later).with(project_origin, datahub_project) + expect(Metais::SyncProjectEventsJob).to have_received(:perform_later).with(project_origin, datahub_project) + end +end diff --git a/spec/jobs/metais/sync_project_suppliers_job_spec.rb b/spec/jobs/metais/sync_project_suppliers_job_spec.rb new file mode 100644 index 0000000..da15772 --- /dev/null +++ b/spec/jobs/metais/sync_project_suppliers_job_spec.rb @@ -0,0 +1,82 @@ +require 'rails_helper' +require 'webmock/rspec' + +RSpec.describe Metais::SyncProjectSuppliersJob, type: :job do + include ActiveJob::TestHelper + + let!(:origin_type) { Metais::OriginType.create!(name: 'MetaIS') } + + let!(:supplier_type_nfp) { Metais::SupplierType.create!(name: "NFP") } + let!(:supplier_type_vo) { Metais::SupplierType.create!(name: "VO") } + let!(:supplier_type_crz) { Metais::SupplierType.create!(name: "CRZ") } + + let!(:metais_project) { create(:metais_project) } + let(:project_origin) { Metais::ProjectOrigin.create!(project: metais_project, origin_type: origin_type, title: "Test") } + + let(:latest_version) { double('LatestVersion', kod_metais: 'code1', link_nfp: "http://example.com/nfp", datum_nfp: Date.today, vo: "http://example.com/vo", vyhlasenie_vo: Date.today, zmluva_o_dielo_crz: "http://example.com/crz", zmluva_o_dielo: Date.today) } + let(:datahub_project) { instance_double(Datahub::Metais::Project, uuid: 'uuid1', latest_version: latest_version) } + + before do + allow(datahub_project).to receive(:latest_version).and_return(latest_version) + + allow(Metais::OriginType).to receive(:find_by).with(name: 'MetaIS').and_return(origin_type) + allow(Metais::SupplierType).to receive(:find_by).with(name: "NFP").and_return(supplier_type_nfp) + allow(Metais::SupplierType).to receive(:find_by).with(name: "VO").and_return(supplier_type_vo) + allow(Metais::SupplierType).to receive(:find_by).with(name: "CRZ").and_return(supplier_type_crz) + + crz_html = <<-HTML + + +
      +
    • + Dodávateľ: + Supplier Name +
    • +
    • + IČO: + 12345678 +
    • +
    + + + HTML + stub_request(:get, "http://example.com/crz").to_return(body: crz_html, headers: { 'Content-Type' => 'text/html' }) + allow_any_instance_of(Metais::SyncProjectSuppliersJob).to receive(:open).with("http://example.com/crz").and_return(StringIO.new(crz_html)) + + allow(Metais::ProjectSupplier).to receive(:find_or_initialize_by).and_call_original + allow(project_origin).to receive(:supplier=).and_call_original + allow(project_origin).to receive(:supplier_cin=).and_call_original + allow(project_origin).to receive(:save!).and_call_original + + Metais::SyncProjectSuppliersJob.perform_now(project_origin, datahub_project) + end + + describe '#perform' do + context 'when processing NFP links' do + it 'creates project suppliers for valid NFP links' do + expect(Metais::ProjectSupplier).to have_received(:find_or_initialize_by) + .with(hash_including(name: 'http://example.com/nfp', value: 'http://example.com/nfp', date: Date.today, origin_type: origin_type, supplier_type: supplier_type_nfp)) + end + end + + context 'when processing VO links' do + it 'creates project suppliers for valid VO links' do + expect(Metais::ProjectSupplier).to have_received(:find_or_initialize_by) + .with(hash_including(name: 'http://example.com/vo', value: 'http://example.com/vo', date: Date.today, origin_type: origin_type, supplier_type: supplier_type_vo)) + end + end + + context 'when processing CRZ links' do + it 'scrapes supplier data from the CRZ page and updates the project_origin' do + expect(project_origin).to have_received(:supplier=).with('Supplier Name') + expect(project_origin).to have_received(:supplier_cin=).with('12345678') + expect(project_origin).to have_received(:save!) + end + + it 'creates project suppliers for valid CRZ links' do + expect(Metais::ProjectSupplier).to have_received(:find_or_initialize_by) + .with(hash_including(name: 'http://example.com/crz', value: 'http://example.com/crz', date: Date.today, origin_type: origin_type, supplier_type: supplier_type_crz)) + end + end + end +end \ No newline at end of file diff --git a/spec/jobs/sync_all_topics_job_spec.rb b/spec/jobs/sync_all_topics_job_spec.rb index 9f6d4a9..3521e56 100644 --- a/spec/jobs/sync_all_topics_job_spec.rb +++ b/spec/jobs/sync_all_topics_job_spec.rb @@ -10,15 +10,18 @@ [ [], [], - ['Projekt', 'Projekt ID', 'Platforma', 'ID draft prípravy', 'ID prípravy', 'ID draft produktu', 'ID produktu'], - ['Projekt1', 'ABC1', '', 'ABC1', 'ABC1', 'ABC1', 'ABC1'], - ['Projekt2', 'ABC2', '', 'ABC2', 'ABC2', 'ABC2', 'ABC2'] + ['Projekt', 'Projekt ID', 'MetaIS', 'Platforma', 'ID draft prípravy', 'ID prípravy', 'ID draft produktu', 'ID produktu'], + ['Projekt1', 1, '', '', 'ABC1', 'ABC1', 'ABC1', 'ABC1'], + ['Projekt2', 2, 'projekt_2741', '', 'ABC2', 'ABC2', 'ABC2', 'ABC2'] ] end - let(:indices) { { 'Projekt' => 0, 'Projekt ID' => 1, 'Platforma' => 2, 'ID draft prípravy' => 3, 'ID prípravy' => 4, 'ID draft produktu' => 5, 'ID produktu' => 6 } } + let(:indices) { { 'Projekt' => 0, 'Projekt ID' => 1, 'MetaIS' => 2,'Platforma' => 3, 'ID draft prípravy' => 4, 'ID prípravy' => 5, 'ID draft produktu' => 6, 'ID produktu' => 7 } } before do + Project.create(id: 1) + Project.create(id: 2) + mock_document = instance_double("Google::Apis::DocsV1::Document") allow(mock_document).to receive(:title).and_return("Dokument RF-priprava-template") allow(GoogleApiService).to receive(:get_document).and_return(mock_document) @@ -45,8 +48,8 @@ [], [], ['Projekt'], - ['Projekt1', 'ABC1', '', 'ABC1', 'ABC1', 'ABC1', 'ABC1'], - ['Projekt2', 'ABC2', 'http://google.com', 'ABC2', 'ABC2', 'ABC2', 'ABC2'] + ['Projekt1', 1, '', 'ABC1', 'ABC1', 'ABC1', 'ABC1'], + ['Projekt2', 2, 'projekt_2741', 'http://google.com', 'ABC2', 'ABC2', 'ABC2', 'ABC2'] ] end @@ -61,7 +64,7 @@ [ [], [], - ['Projekt', 'Projekt ID', 'Platforma', 'ID draft prípravy', 'ID prípravy', 'ID draft produktu', 'ID produktu'] + ['Projekt', 'Projekt ID', 'MetaIS', 'Platforma', 'ID draft prípravy', 'ID prípravy', 'ID draft produktu', 'ID produktu'] ] end @@ -76,9 +79,9 @@ [ [], [], - ['Projekt', 'Projekt ID', 'Platforma', 'ID draft prípravy', 'ID prípravy', 'ID draft produktu', 'ID produktu'], - ['Projekt1', 'ABC1', '', 'ABC1', '', 'ABC1', ''], - ['Projekt2', 'ABC2', 'http://google.com', 'ABC2', 'ABC2', 'ABC2', 'ABC2'] + ['Projekt', 'Projekt ID', 'MetaIS', 'Platforma', 'ID draft prípravy', 'ID prípravy', 'ID draft produktu', 'ID produktu'], + ['Projekt1', 1, '', '', 'ABC1', '', 'ABC1', ''], + ['Projekt2', 2, 'projekt_2741', 'http://google.com', 'ABC2', 'ABC2', 'ABC2', 'ABC2'] ] end