diff --git a/Gemfile.lock b/Gemfile.lock index 88a9a7fc..9f645c06 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -462,6 +462,7 @@ GEM sprockets (>= 3.0.0) sqlite3 (1.6.8) mini_portile2 (~> 2.8.0) + sqlite3 (1.6.8-x86_64-linux) ssrf_filter (1.1.2) stringio (3.1.1) strscan (3.1.0) @@ -497,6 +498,7 @@ GEM PLATFORMS ruby x86-mingw32 + x86_64-linux DEPENDENCIES active_scaffold! diff --git a/app/controllers/affiliation_controller.rb b/app/controllers/affiliation_controller.rb new file mode 100644 index 00000000..fcdeae67 --- /dev/null +++ b/app/controllers/affiliation_controller.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +class AffiliationController < ApplicationController + authorize_resource + + active_scaffold :affiliation do |config| + columns = [:professor, :institution, :start_date, :end_date] + + config.list.columns = columns + config.create.columns = columns + config.update.columns = columns + config.show.columns = columns + + config.columns[:professor].form_ui = :record_select + config.columns[:institution].form_ui = :record_select + config.columns[:start_date].form_ui = :date_picker + config.columns[:end_date].form_ui = :date_picker + end + record_select( + per_page: 10, + search_on: [:name], + order_by: "name", + full_text_search: true + ) +end diff --git a/app/controllers/concerns/shared_pdf_concern.rb b/app/controllers/concerns/shared_pdf_concern.rb index 12b51ee3..967c3548 100644 --- a/app/controllers/concerns/shared_pdf_concern.rb +++ b/app/controllers/concerns/shared_pdf_concern.rb @@ -41,7 +41,7 @@ def render_enrollments_academic_transcript_pdf(enrollment) .order("course_classes.year", "course_classes.semester") accomplished_phases = enrollment.accomplishments.order(:conclusion_date) - + program_level = ProgramLevel.on_date(enrollment.thesis_defense_date)&.last&.level || "" render_to_string( template: "enrollments/academic_transcript_pdf", type: "application/pdf", @@ -50,6 +50,7 @@ def render_enrollments_academic_transcript_pdf(enrollment) enrollment: enrollment, class_enrollments: class_enrollments, accomplished_phases: accomplished_phases, + program_level: program_level } ) end diff --git a/app/controllers/enrollments_controller.rb b/app/controllers/enrollments_controller.rb index b9e3fa90..cd206859 100644 --- a/app/controllers/enrollments_controller.rb +++ b/app/controllers/enrollments_controller.rb @@ -214,6 +214,7 @@ def to_pdf def academic_transcript_pdf enrollment = Enrollment.find(params[:id]) + respond_to do |format| format.pdf do title = I18n.t("pdf_content.enrollment.academic_transcript.title") diff --git a/app/controllers/professors_controller.rb b/app/controllers/professors_controller.rb index e9901761..9997fad9 100644 --- a/app/controllers/professors_controller.rb +++ b/app/controllers/professors_controller.rb @@ -29,7 +29,6 @@ class ProfessorsController < ApplicationController config.columns[:civil_status].options = { options: [["Solteiro(a)", "solteiro"], ["Casado(a)", "casado"]] } - config.columns[:institution].form_ui = :record_select config.columns[:sex].form_ui = :select config.columns[:sex].options = { options: [["Masculino", "M"], ["Feminino", "F"]] } @@ -53,9 +52,9 @@ class ProfessorsController < ApplicationController :address, :zip_code, :telephone1, :telephone2, :cpf, :identity_expedition_date, :identity_issuing_body, :identity_issuing_place, :identity_number, :enrollment_number, - :siape, :institution, :scholarships, :academic_title_level, + :siape, :scholarships, :academic_title_level, :academic_title_institution, :academic_title_country, - :academic_title_date, :obs, :professor_research_areas, + :academic_title_date, :obs, :professor_research_areas, :affiliations ] config.create.columns = form_columns @@ -64,7 +63,7 @@ class ProfessorsController < ApplicationController config.show.columns = [ :name, :email, :cpf, :birthdate, :address, :birthdate, :civil_status, :identity_expedition_date, :identity_issuing_body, :identity_number, - :neighborhood, :sex, :enrollment_number, :siape, + :neighborhood, :sex, :enrollment_number, :siape, :institutions, :telephone1, :telephone2, :zip_code, :scholarships, :advisement_authorizations, :advisements_with_points, :academic_title_level, :academic_title_institution, diff --git a/app/controllers/program_levels_controller.rb b/app/controllers/program_levels_controller.rb new file mode 100644 index 00000000..73722fd7 --- /dev/null +++ b/app/controllers/program_levels_controller.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +class ProgramLevelsController < ApplicationController + authorize_resource + active_scaffold :program_level do |config| + config.create.columns = [:level, :start_date, :end_date] + config.update.columns = [:level, :start_date, :end_date] + config.show.columns = [:level, :start_date, :end_date] + config.list.columns = [:level, :start_date, :end_date] + + config.actions.swap :search, :field_search + config.columns.add :active + config.field_search.columns = [:active] + + config.actions.exclude :deleted_records + end + + protected + def do_update + # BEFORE UPDATE + # cria o histórico + + pl = ProgramLevel.last + unless pl.nil? + ProgramLevel.create!( + level: pl.level, + start_date: pl.start_date, + end_date: Time.now + ) + end + + super + # AFTER UPDATE + # atualiza a data de início + + pl = ProgramLevel.last + pl.update!(start_date: pl.updated_at) + end +end diff --git a/app/helpers/enrollments_pdf_helper.rb b/app/helpers/enrollments_pdf_helper.rb index b737bd8c..b192b868 100644 --- a/app/helpers/enrollments_pdf_helper.rb +++ b/app/helpers/enrollments_pdf_helper.rb @@ -132,12 +132,12 @@ def grades_report_header(pdf, options = {}) def enrollment_header(pdf, options = {}) enrollment ||= options[:enrollment] + program_level ||= options[:program_level] pdf.bounding_box([0, pdf.cursor - 3], width: 560) do pdf.font("FreeMono", size: 8) do pdf.line_width 0.5 - common_header_part1(pdf, enrollment, [ - "#{i18n_eht(:program_level)} #{CustomVariable.program_level} " + "#{i18n_eht(:program_level)} #{program_level}" ]) common_header_part(pdf) do @@ -615,9 +615,10 @@ def thesis_table(curr_pdf, options = {}) "#{I18n.t("pdf_content.enrollment.thesis.defense_committee")} " ]] thesis_desense_committee.each do |professor| + affiliation = Affiliation.professor_date(professor, thesis_defense_date)&.last data_table_rows_defense_committee += [[ "#{professor.name} / #{rescue_blank_text( - professor.institution, method_call: :name + affiliation&.institution, method_call: :name )}" ]] end diff --git a/app/models/ability.rb b/app/models/ability.rb index 591dd693..f6c822af 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -46,7 +46,7 @@ class Ability CONFIGURATION_MODELS = [ User, Role, Version, Notification, EmailTemplate, Query, NotificationLog, CustomVariable, ReportConfiguration, - YearSemester + YearSemester, ProgramLevel ] def initialize(user) @@ -228,7 +228,7 @@ def initialize_configurations(user, roles) alias_action :execute_now, :execute_now, :notify, to: :update if roles[Role::ROLE_COORDENACAO] can :manage, (Ability::CONFIGURATION_MODELS - [ - CustomVariable, ReportConfiguration + CustomVariable, ReportConfiguration, ProgramLevel ]) end if roles[Role::ROLE_SECRETARIA] diff --git a/app/models/affiliation.rb b/app/models/affiliation.rb new file mode 100644 index 00000000..58885356 --- /dev/null +++ b/app/models/affiliation.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +class Affiliation < ApplicationRecord + has_paper_trail + + belongs_to :institution + belongs_to :professor + + validates :start_date, presence: true + validates :end_date, presence: false + validates_uniqueness_of :start_date, scope: [:professor_id], + allow_nil: true, allow_blank: true, + message: "A afiliação só pode ser iniciada em uma data por professor" + validate :uniqueness_end_date + + scope :on_date, ->(date) { where("DATE(start_date) <= ? AND (DATE(end_date) > ? OR end_date IS null)", date, date) } + scope :of_professor, ->(professor) { where(professor_id: professor.id) } + scope :professor_date, ->(professor, date) { of_professor(professor).on_date(date) } + scope :active, -> { where(end_date: nil) } + + private + def uniqueness_end_date + exists = Affiliation.where(professor_id: professor_id, end_date: end_date).where.not(id: id).exists? + if exists + errors.add(:end_date,"Apenas uma afiliação pode estar ativa por professor e só pode ter uma data de fim por professor") + end + exists + end + +end diff --git a/app/models/custom_variable.rb b/app/models/custom_variable.rb index 4ed0fee1..ad6371e1 100644 --- a/app/models/custom_variable.rb +++ b/app/models/custom_variable.rb @@ -12,7 +12,6 @@ class CustomVariable < ApplicationRecord VARIABLES = { "single_advisor_points" => :text, "multiple_advisor_points" => :text, - "program_level" => :text, "identity_issuing_country" => :text, "class_schedule_text" => :text, "redirect_email" => :text, @@ -42,11 +41,6 @@ def self.multiple_advisor_points config.blank? ? 0.5 : config.value.to_f end - def self.program_level - config = CustomVariable.find_by_variable(:program_level) - config.blank? ? nil : config.value.to_i - end - def self.identity_issuing_country config = CustomVariable.find_by_variable(:identity_issuing_country) config.blank? ? "" : config.value diff --git a/app/models/institution.rb b/app/models/institution.rb index e3bdc403..6e894638 100644 --- a/app/models/institution.rb +++ b/app/models/institution.rb @@ -8,7 +8,9 @@ class Institution < ApplicationRecord has_paper_trail has_many :majors, dependent: :restrict_with_exception - has_many :professors, dependent: :restrict_with_exception + has_many :affiliations, dependent: :destroy + has_many :professors, through: :affiliations, dependent: :destroy + validates :name, presence: true, uniqueness: true diff --git a/app/models/professor.rb b/app/models/professor.rb index de52ea61..49910236 100644 --- a/app/models/professor.rb +++ b/app/models/professor.rb @@ -18,9 +18,11 @@ class Professor < ApplicationRecord dependent: :restrict_with_exception has_many :thesis_defense_committee_enrollments, source: :enrollment, through: :thesis_defense_committee_participations + has_many :affiliations + has_many :institutions, through: :affiliations + accepts_nested_attributes_for :affiliations, allow_destroy: true, reject_if: :all_blank belongs_to :city, optional: true - belongs_to :institution, optional: true belongs_to :academic_title_country, optional: true, class_name: "Country", diff --git a/app/models/program_level.rb b/app/models/program_level.rb new file mode 100644 index 00000000..92722b8b --- /dev/null +++ b/app/models/program_level.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +class ProgramLevel < ApplicationRecord + has_paper_trail + + validates :level, presence: true, on: [:create, :update] + validates :start_date, presence: true, on: [:create, :update] + validates :end_date, presence: false + + scope :active, -> { where(end_date: nil) } + scope :on_date, -> (date) { where("program_levels.start_date <= ? AND program_levels.end_date > ? OR program_levels.end_date is null", date, date)} + +end diff --git a/app/views/enrollments/_show_defense_committee_table.html.erb b/app/views/enrollments/_show_defense_committee_table.html.erb index 37bd476b..eaeadda6 100644 --- a/app/views/enrollments/_show_defense_committee_table.html.erb +++ b/app/views/enrollments/_show_defense_committee_table.html.erb @@ -2,7 +2,7 @@ <%= I18n.t("activerecord.attributes.professor.name") %> - <%= I18n.t("activerecord.attributes.professor.institution") %> + <%= I18n.t("activerecord.attributes.professor.institution.one") %> @@ -12,7 +12,7 @@ <% tr_class = count.even? ? "even-record" : "" %> <%= professor.name %> - <%= rescue_blank_text(professor.institution, method_call: :name) %> + <%= rescue_blank_text(Affiliation.professor_date(professor, thesis_defense_date)&.last&.institution, method_call: :name) %> <% end %> diff --git a/app/views/enrollments/academic_transcript_pdf.pdf.prawn b/app/views/enrollments/academic_transcript_pdf.pdf.prawn index c0f7ac6e..b590fe8c 100644 --- a/app/views/enrollments/academic_transcript_pdf.pdf.prawn +++ b/app/views/enrollments/academic_transcript_pdf.pdf.prawn @@ -15,7 +15,7 @@ new_document( ) do |pdf| enrollment_student_header(pdf, enrollment: @enrollment) - enrollment_header(pdf, enrollment: @enrollment) + enrollment_header(pdf, enrollment: @enrollment, program_level: @program_level) transcript_table(pdf, class_enrollments: @class_enrollments) diff --git a/app/views/student_enrollment/_show_dismissal.html.erb b/app/views/student_enrollment/_show_dismissal.html.erb index 1827af75..11ad812b 100644 --- a/app/views/student_enrollment/_show_dismissal.html.erb +++ b/app/views/student_enrollment/_show_dismissal.html.erb @@ -34,7 +34,8 @@ <% unless thesis_defense_committee_professors.empty? %>

<%= t "activerecord.attributes.enrollment.thesis_defense_committee_professors" %>

<%= render partial: "enrollments/show_defense_committee_table", locals: { - thesis_defense_committee_professors: thesis_defense_committee_professors + thesis_defense_committee_professors: thesis_defense_committee_professors, + thesis_defense_date: enrollment.thesis_defense_date, } %> <% end %> diff --git a/config/application.rb b/config/application.rb index 38ce92cc..37750697 100644 --- a/config/application.rb +++ b/config/application.rb @@ -35,9 +35,11 @@ class Application < Rails::Application # config.autoload_paths += %W(#{config.root}/extras) config.autoload_paths << "#{config.root}/lib" + # Only load the plugins named here, in the order given (default is alphabetical). # :all can be used as a placeholder for all plugins not explicitly named. # config.plugins = [ :exception_notification, :ssl_requirement, :all ] + config.active_record.yaml_column_permitted_classes = [Symbol, Date, Time] # Activate observers that should always be running. # config.active_record.observers = :cacher, :garbage_collector, :forum_observer diff --git a/config/locales/affiliation.pt-BR.yml b/config/locales/affiliation.pt-BR.yml new file mode 100644 index 00000000..f4a2db88 --- /dev/null +++ b/config/locales/affiliation.pt-BR.yml @@ -0,0 +1,17 @@ +# Copyright (c) Universidade Federal Fluminense (UFF). +# This file is part of SAPOS. Please, consult the license terms in the LICENSE file. + +pt-BR: + activerecord: + attributes: + affiliation: + institution: "Instituição" + professor: "Professor" + start_date: "Data de início" + end_date: "Data de fim" + active: "Ativo" + + models: + affiliation: + one: "Afiliação" + other: "Afiliações" \ No newline at end of file diff --git a/config/locales/institution.pt-BR.yml b/config/locales/institution.pt-BR.yml index 1cab52e2..b6fb5eda 100644 --- a/config/locales/institution.pt-BR.yml +++ b/config/locales/institution.pt-BR.yml @@ -8,6 +8,7 @@ pt-BR: code: "Sigla" majors: "Cursos" name: "Nome" + affiliations: "Afiliações" models: institution: diff --git a/config/locales/navigation.pt-BR.yml b/config/locales/navigation.pt-BR.yml index 720d60b5..1d7e58f3 100644 --- a/config/locales/navigation.pt-BR.yml +++ b/config/locales/navigation.pt-BR.yml @@ -10,7 +10,6 @@ pt-BR: student: Alunos dismissal: Desligamentos enrollment: Matrículas - enrollment: Matrículas enrollment_hold: Trancamentos level: Níveis dismissal_reason: Razões de Desligamento @@ -82,6 +81,7 @@ pt-BR: notification_log: Notificações Enviadas custom_variable: Variáveis report_configuration: Configurações de Relatório + program_level: Conceito CAPES logout: label: 'Logout' diff --git a/config/locales/professor.pt-BR.yml b/config/locales/professor.pt-BR.yml index 7707c445..65f65bf4 100644 --- a/config/locales/professor.pt-BR.yml +++ b/config/locales/professor.pt-BR.yml @@ -21,7 +21,11 @@ pt-BR: identity_issuing_body: "Órgão Expeditor" identity_issuing_place: "Local de Expedição" identity_number: "Número da identidade" - institution: "Instituição" + affiliations: "Afiliações" + institution: + one: "Instituição" + other: "Instituições" + institutions: "Instituições" name: "Nome" neighborhood: "Bairro" professor_research_areas: "Áreas de Pesquisa" diff --git a/config/locales/program_level.pt-BR.yml b/config/locales/program_level.pt-BR.yml new file mode 100644 index 00000000..de822339 --- /dev/null +++ b/config/locales/program_level.pt-BR.yml @@ -0,0 +1,13 @@ +pt-BR: + activerecord: + attributes: + program_level: + active: Ativo? + level: Nível + start_date: Data de início + end_date: Data de fim + + models: + program_level: + one: Conceito CAPES + other: Conceito CAPES \ No newline at end of file diff --git a/config/navigation.rb b/config/navigation.rb index d2505ce8..190d49f3 100644 --- a/config/navigation.rb +++ b/config/navigation.rb @@ -243,6 +243,7 @@ def can_read?(*args) submenu.modelitem NotificationLog submenu.modelitem CustomVariable submenu.modelitem ReportConfiguration + submenu.modelitem ProgramLevel end mainhelper.item :logout, destroy_user_session_path diff --git a/config/routes.rb b/config/routes.rb index 8eaf23eb..6a1b347e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -160,6 +160,11 @@ end end + resources :affiliation do + concerns :active_scaffold + record_select_routes + end + resources :professors do concerns :active_scaffold record_select_routes @@ -231,6 +236,10 @@ concerns :active_scaffold end + resources :program_levels do + concerns :active_scaffold + end + resources :thesis_defense_committee_participations do concerns :active_scaffold record_select_routes diff --git a/db/migrate/20240524135850_create_affiliation.rb b/db/migrate/20240524135850_create_affiliation.rb new file mode 100644 index 00000000..5b93096a --- /dev/null +++ b/db/migrate/20240524135850_create_affiliation.rb @@ -0,0 +1,55 @@ +class CreateAffiliation < ActiveRecord::Migration[7.0] + def up + create_table :affiliations do |t| + t.belongs_to :professor, index: true + t.belongs_to :institution, index: true + t.datetime :start_date + t.datetime :end_date + + t.timestamps + end + Professor.where.not(institution_id: nil).each do |professor| + start_date = professor.updated_at + end_date = nil + institution_id = professor.institution_id + institutions = [] + affiliation = Affiliation.create( + professor: professor, + institution_id: institution_id, + start_date: start_date + ) + professor = professor.paper_trail.previous_version + while professor.present? + if professor.institution_id != institution_id + institutions << { institution_id:, start_date:, end_date: } + end_date = start_date + start_date = professor.updated_at + institution_id = professor.institution_id + affiliation = Affiliation.create( + professor: professor, + institution_id: institution_id, + start_date: start_date, + end_date: end_date + ) + else + # Atualiza data de início para data da primeira mudança em que instituição foi definida com esse valor + start_date = professor.updated_at + affiliation.update(start_date: start_date) + end + professor = professor.paper_trail.previous_version + end + institutions << { institution_id:, start_date:, end_date: } + end + + remove_column :professors, :institution_id + end + def down + add_column :professors, :institution_id, :integer + add_index :professors, :institution_id + Professor.all.each do |p| + affiliation = Affiliation.of_professor(p).where(end_date: nil).last + p.update(institution_id: affiliation.institution_id) + end + drop_table :affiliations + end +end diff --git a/db/migrate/20240527174758_create_program_level.rb b/db/migrate/20240527174758_create_program_level.rb new file mode 100644 index 00000000..daefeacd --- /dev/null +++ b/db/migrate/20240527174758_create_program_level.rb @@ -0,0 +1,45 @@ +class CreateProgramLevel < ActiveRecord::Migration[7.0] + def up + create_table :program_levels do |t| + t.integer :level, null: false + t.datetime :start_date, null: false + t.datetime :end_date + + t.timestamps + end + CustomVariable.where(variable: "program_level").each do |pl| + level = pl.value + program_level = ProgramLevel.create( + level: pl.value, + start_date: pl.updated_at, + ) + pl = pl.paper_trail.previous_version + while pl.present? + if pl.value != level + end_date = start_date + start_date = pl.updated_at + level = pl.value + program_level = ProgramLevel.create( + level: level, + end_date: end_date, + start_date: start_date, + ) + else + start_date = pl.updated_at + program_level.update(start_date: start_date) + end + pl.paper_trail.previous_version + end + end + CustomVariable.where(variable: "program_level").destroy_all + end + def down + ProgramLevel.all.each do |pl| + CustomVariable.create( + variable: "program_level", + value: pl.level, + ) + end + drop_table :program_levels + end +end diff --git a/db/schema.rb b/db/schema.rb index 3fe86129..c9c44de5 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -128,7 +128,7 @@ t.boolean "candidate_can_see_member", default: false, null: false t.boolean "candidate_can_see_shared", default: false, null: false t.boolean "candidate_can_see_consolidation", default: false, null: false - t.index ["approval_condition_id"], name: "index_admission_phases_on_approval_condition_id" + t.index "\"ranking_config_id\"", name: "index_admission_phases_on_ranking_config_id" t.index ["candidate_form_id"], name: "index_admission_phases_on_candidate_form_id" t.index ["consolidation_form_id"], name: "index_admission_phases_on_consolidation_form_id" t.index ["keep_in_phase_condition_id"], name: "index_admission_phases_on_keep_in_phase_condition_id" @@ -256,6 +256,17 @@ t.index ["professor_id"], name: "index_advisements_on_professor_id" end + create_table "affiliations", force: :cascade do |t| + t.integer "professor_id" + t.integer "institution_id" + t.datetime "start_date" + t.datetime "end_date" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["institution_id"], name: "index_affiliations_on_institution_id" + t.index ["professor_id"], name: "index_affiliations_on_professor_id" + end + create_table "allocations", force: :cascade do |t| t.string "day", limit: 255 t.string "room", limit: 255 @@ -702,7 +713,6 @@ t.string "siape", limit: 255 t.string "enrollment_number", limit: 255 t.string "identity_issuing_place", limit: 255 - t.integer "institution_id" t.string "email", limit: 255 t.date "academic_title_date" t.integer "academic_title_country_id" @@ -716,10 +726,17 @@ t.index ["city_id"], name: "index_professors_on_city_id" t.index ["cpf"], name: "index_professors_on_cpf" t.index ["email"], name: "index_professors_on_email" - t.index ["institution_id"], name: "index_professors_on_institution_id" t.index ["user_id"], name: "index_professors_on_user_id" end + create_table "program_levels", force: :cascade do |t| + t.integer "level", null: false + t.date "start_date", null: false + t.date "end_date" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + create_table "queries", force: :cascade do |t| t.string "name", limit: 255 t.text "sql" @@ -933,6 +950,8 @@ t.string "photo", limit: 255 t.integer "birth_country_id" t.integer "user_id", limit: 8 + t.string "skin_color" + t.boolean "pcd" t.index ["birth_city_id"], name: "index_students_on_birth_city_id" t.index ["birth_country_id"], name: "index_students_on_birth_country_id" t.index ["birth_state_id"], name: "index_students_on_state_id" diff --git a/db/seeds.rb b/db/seeds.rb index a96c2d47..0671ab59 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -16,7 +16,7 @@ CustomVariable.create([ { description: "Pontos para orientador único", variable: "single_advisor_points", value: "1.0" }, { description: "Pontos para orientador múltiplo", variable: "multiple_advisor_points", value: "0.5" }, - { description: "Nível do Programa na CAPES", variable: "program_level", value: "5" }, + { description: "País padrão de emissão da identidade", variable: "identity_issuing_country", value: "Brasil" }, { description: "Texto no final do quadro de horários", variable: "class_schedule_text", value: "Alunos interessados em cursar disciplinas de Tópicos Avançados devem consultar os respectivos professores antes da matrícula." }, { description: "E-mail de redirecionamento para as notificações", variable: "redirect_email", value: "" }, @@ -33,6 +33,7 @@ { description: "Nota de reprovação por falta", variable: "grade_of_disapproval_for_absence", value: "0.0" }, { description: "Professor logado no sistema pode lançar notas. O valor yes habilita turmas do semestre atual, yes_all_semesters habilita qualquer semestre.", variable: "professor_login_can_post_grades", value: "no" }, ]) +ProgramLevel.create([{ value: "5", start_date: Time.now, end_date: nil }]) ReportConfiguration.create([ { name: "Boletim", scale: 1, x: 0, y: 0, order: 1, diff --git a/spec/controllers/affiliation_controller_spec_spec.rb b/spec/controllers/affiliation_controller_spec_spec.rb new file mode 100644 index 00000000..d4f18700 --- /dev/null +++ b/spec/controllers/affiliation_controller_spec_spec.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +require "spec_helper" + + +RSpec.describe "AffiliationControllerSpec" do + + context "Populate" do + + end +end diff --git a/spec/factories/factory_affiliation.rb b/spec/factories/factory_affiliation.rb new file mode 100644 index 00000000..1425f5b6 --- /dev/null +++ b/spec/factories/factory_affiliation.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :affiliation do + institution + professor + start_date { Time.now } + end_date { Time.now } + end +end diff --git a/spec/factories/factory_program_level.rb b/spec/factories/factory_program_level.rb new file mode 100644 index 00000000..cbc232de --- /dev/null +++ b/spec/factories/factory_program_level.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :program_level do + sequence(:level) + start_date { Time.now } + end_date { nil } + end +end diff --git a/spec/features/custom_variables_spec.rb b/spec/features/custom_variables_spec.rb index 0f26a8c3..7d8ac606 100644 --- a/spec/features/custom_variables_spec.rb +++ b/spec/features/custom_variables_spec.rb @@ -15,7 +15,6 @@ @destroy_all << @role_adm = FactoryBot.create(:role_administrador) @destroy_all << @user = create_confirmed_user(@role_adm) - @destroy_all << FactoryBot.create(:custom_variable, variable: "program_level", value: "5") @destroy_all << @record = FactoryBot.create(:custom_variable, variable: "single_advisor_points", value: "1.0") @destroy_all << FactoryBot.create(:custom_variable, variable: "minimum_grade_for_approval", value: "6.0") end @@ -42,7 +41,7 @@ end it "should sort the list by variable, asc" do - expect(page.all("tr td.variable-column").map(&:text)).to eq ["minimum_grade_for_approval", "program_level", "single_advisor_points"] + expect(page.all("tr td.variable-column").map(&:text)).to eq ["minimum_grade_for_approval", "single_advisor_points"] end end @@ -64,12 +63,12 @@ expect(page).to have_css("tr:nth-child(1) td.variable-column", text: "identity_issuing_country") # Remove inserted record - expect(page.all("tr td.variable-column").map(&:text)).to eq ["identity_issuing_country", "minimum_grade_for_approval", "program_level", "single_advisor_points"] + expect(page.all("tr td.variable-column").map(&:text)).to eq ["identity_issuing_country", "minimum_grade_for_approval", "single_advisor_points"] record = model.last accept_confirm { find("#as_#{plural_name}-destroy-#{record.id}-link").click } sleep(0.2) visit current_path - expect(page.all("tr td.variable-column").map(&:text)).to eq ["minimum_grade_for_approval", "program_level", "single_advisor_points"] + expect(page.all("tr td.variable-column").map(&:text)).to eq ["minimum_grade_for_approval", "single_advisor_points"] end it "should have a selection for variable options" do diff --git a/spec/features/enrollments_spec.rb b/spec/features/enrollments_spec.rb index 53e991b6..a76f7e3d 100644 --- a/spec/features/enrollments_spec.rb +++ b/spec/features/enrollments_spec.rb @@ -37,6 +37,8 @@ @destroy_all << FactoryBot.create(:phase_duration, level: @level1, phase: @phase2, deadline_months: 3, deadline_days: 0) @destroy_all << FactoryBot.create(:phase_duration, level: @level1, phase: @phase3, deadline_months: 3, deadline_days: 0) + @destroy_all << FactoryBot.create(:program_level) + @destroy_all << @enrollment1 = FactoryBot.create(:enrollment, enrollment_number: "M02", student: @student1, level: @level2, enrollment_status: @enrollment_status1, admission_date: 3.years.ago.at_beginning_of_month.to_date) @destroy_all << @enrollment2 = FactoryBot.create(:enrollment, enrollment_number: "M01", student: @student2, level: @level2, enrollment_status: @enrollment_status2) @destroy_all << @enrollment3 = FactoryBot.create(:enrollment, enrollment_number: "M03", student: @student3, level: @level1, enrollment_status: @enrollment_status1, research_area: @reasearch_area1) diff --git a/spec/features/student_enrollment_spec.rb b/spec/features/student_enrollment_spec.rb index db72a664..71ea4a90 100644 --- a/spec/features/student_enrollment_spec.rb +++ b/spec/features/student_enrollment_spec.rb @@ -5,7 +5,7 @@ require "spec_helper" -RSpec.describe "StudentEnrollment features", type: :feature do +RSpec.describe "StudentEnrollment features", type: :feature, js: true do let(:url_path) { "/pendencies" } before(:all) do @destroy_later = [] @@ -51,6 +51,12 @@ @destroy_all << @professor3 = FactoryBot.create(:professor, name: "Gi", cpf: "1") @destroy_all << @professor4 = FactoryBot.create(:professor, name: "Helena", cpf: "4") + @destroy_all << @institution = FactoryBot.create(:institution, name: "UFF") + + @destroy_all << @affiliation1 = FactoryBot.create(:affiliation, institution: @institution, professor: @professor1, end_date: nil) + @destroy_all << @affiliation2 = FactoryBot.create(:affiliation, institution: @institution, professor: @professor2, end_date: nil) + @destroy_all << @affiliation3 = FactoryBot.create(:affiliation, institution: @institution, professor: @professor3, end_date: nil) + @destroy_all << FactoryBot.create(:advisement_authorization, professor: @professor1, level: @level1) @destroy_all << FactoryBot.create(:advisement_authorization, professor: @professor1, level: @level2) @destroy_all << FactoryBot.create(:advisement_authorization, professor: @professor2, level: @level1) @@ -59,7 +65,10 @@ @destroy_all << FactoryBot.create(:advisement_authorization, professor: @professor3, level: @level2) @destroy_all << @student1 = FactoryBot.create(:student, name: "Ana") - @destroy_all << @enrollment1 = FactoryBot.create(:enrollment, enrollment_number: "M01", student: @student1, level: @level2, enrollment_status: @enrollment_status1, admission_date: 3.years.ago.at_beginning_of_month.to_date, research_area: @research_area1) + @destroy_all << @enrollment1 = FactoryBot.create(:enrollment, enrollment_number: "M01", student: @student1, + level: @level2, enrollment_status: @enrollment_status1, + admission_date: 3.years.ago.at_beginning_of_month.to_date, + research_area: @research_area1, thesis_defense_date: Time.now) @destroy_all << @enrollment2 = FactoryBot.create(:enrollment, enrollment_number: "M02", student: @student1, level: @level2, enrollment_status: @enrollment_status1) @destroy_all << @enrollment3 = FactoryBot.create(:enrollment, enrollment_number: "D01", student: @student1, level: @level1, enrollment_status: @enrollment_status1) @destroy_all << @enrollment4 = FactoryBot.create(:enrollment, enrollment_number: "D02", student: @student1, level: @level1, enrollment_status: @enrollment_status1) @@ -184,6 +193,7 @@ "Nome", "Instituição" ] expect(page.all("tbody tr").size).to eq 3 + expect(page).to have_content "UFF" end end @@ -459,9 +469,8 @@ it "should show the proper allocations" do # Two allocations in the same day - expect(page.all(".enroll-table tbody tr:nth-of-type(1) td.cell-segunda").map(&:text)).to eq [ - "11-13 14-16" - ] + expect(page.all(".enroll-table tbody tr:nth-of-type(1) td.cell-segunda").map(&:text)).to have_text "11-13" + expect(page.all(".enroll-table tbody tr:nth-of-type(1) td.cell-segunda").map(&:text)).to have_text "14-16" # No allocations for class expect(page.all(".enroll-table tbody tr:nth-of-type(2) td.cell-segunda").map(&:text)).to eq [ "*" diff --git a/spec/models/affiliation_spec.rb b/spec/models/affiliation_spec.rb new file mode 100644 index 00000000..8d1d7598 --- /dev/null +++ b/spec/models/affiliation_spec.rb @@ -0,0 +1,78 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe Affiliation, type: :model do + it { should be_able_to_be_destroyed } + it { should belong_to(:institution) } + it { should belong_to(:professor) } + let(:affiliation) { FactoryBot.create :affiliation } + + + subject { affiliation } + context "Validation" do + it { should be_valid } + it { should validate_presence_of(:start_date) } + context "Active" do + let(:professor) { FactoryBot.create :professor } + let(:affiliation_active) { FactoryBot.create :affiliation, professor: professor, start_date: Time.now, end_date: nil } + let(:affiliation_inactive) { FactoryBot.create :affiliation, + professor: professor, + start_date: Time.now + 1.day, + end_date: Time.now + 2.day} + let(:affiliation_teste_active) { FactoryBot.build :affiliation, professor: professor, start_date: Time.now + 2.day } + let(:affiliation_teste_inactive) { FactoryBot.build :affiliation, + professor: professor, + start_date: Time.now + 3.day, + end_date: Time.now + 4.day } + + it "When active, do not add new affiliation active" do + affiliation_active + aff = FactoryBot.build(:affiliation, professor: professor, end_date: nil) + expect(aff).to be_invalid + end + context "When inactive, you can add new affiliation active/inactive" do + before do + affiliation_inactive + end + it { expect(affiliation_teste_active).to be_valid } + it { expect(affiliation_teste_inactive).to be_valid } + end + it "when inactive, you can add multiple affiliation" do + affiliation_inactive + expect(affiliation_inactive).to be_valid + affiliation_teste_inactive.save! + expect(Affiliation.all.count).to be_eql(2) + end + end + context "Active e End Date" do + let(:affiliation_active) { FactoryBot.create :affiliation, end_date: nil } + let(:affiliation_inactive_valid) { FactoryBot.create :affiliation, end_date: Time.now } + let(:affiliation_inactive_invalid) { FactoryBot.build :affiliation, professor: affiliation_active.professor, end_date: nil } + context "When active, don't need end date" do + it { expect(affiliation_active).to be_valid } + end + context "When inactive, need an end date" do + before(:each) do + affiliation_active + end + it { expect(affiliation_inactive_valid).to be_valid } + it { expect(affiliation_inactive_invalid).to be_invalid } + end + end + end + + context "Scope" do + context "date_professor" do + let!(:professor) { FactoryBot.create :professor } + let!(:affiliation_active) { FactoryBot.create :affiliation, professor: professor, start_date: Time.now, end_date: nil } + let!(:affiliation_inactive) do + FactoryBot.create :affiliation, professor: professor, start_date: Time.now - 1.day, end_date: Time.now + end + + + it { expect(Affiliation.professor_date(professor, Time.now).last).to eq(affiliation_active) } + it { expect(Affiliation.professor_date(professor, Time.now - 1.days).last).to eq(affiliation_inactive) } + end + end +end diff --git a/spec/models/custom_variable_spec.rb b/spec/models/custom_variable_spec.rb index a954cb5a..1c7945b0 100644 --- a/spec/models/custom_variable_spec.rb +++ b/spec/models/custom_variable_spec.rb @@ -61,23 +61,6 @@ end end - context "program_level" do - it "should return nil when there is no variable defined" do - config = CustomVariable.find_by_variable(:program_level) - config.delete unless config.nil? - - expect(CustomVariable.program_level).to eq(nil) - end - - it "should return 5 when it is defined to 5" do - config = CustomVariable.find_by_variable(:program_level) - config.delete unless config.nil? - @destroy_later << CustomVariable.create(variable: :program_level, value: "5") - - expect(CustomVariable.program_level).to eq(5) - end - end - context "identity_issuing_country" do it "should return '' when there is no variable defined" do config = CustomVariable.find_by_variable(:identity_issuing_country) diff --git a/spec/models/institution_spec.rb b/spec/models/institution_spec.rb index 1c2b82ce..c2a20f6c 100644 --- a/spec/models/institution_spec.rb +++ b/spec/models/institution_spec.rb @@ -8,7 +8,8 @@ RSpec.describe Institution, type: :model do it { should be_able_to_be_destroyed } it { should have_many(:majors).dependent(:restrict_with_exception) } - it { should have_many(:professors).dependent(:restrict_with_exception) } + it { should have_many(:affiliations).dependent(:destroy) } + it { should have_many(:professors).through(:affiliations) } let(:institution) { Institution.new(name: "instituicao") } subject { institution } diff --git a/spec/models/professor_spec.rb b/spec/models/professor_spec.rb index 44caffb3..cc87f79a 100644 --- a/spec/models/professor_spec.rb +++ b/spec/models/professor_spec.rb @@ -16,7 +16,8 @@ it { should have_many(:course_classes).dependent(:restrict_with_exception) } it { should have_many(:thesis_defense_committee_participations).dependent(:restrict_with_exception) } it { should have_many(:thesis_defense_committee_enrollments).source(:enrollment).through(:thesis_defense_committee_participations) } - + it { should have_many(:affiliations) } + it { should have_many(:institutions).through(:affiliations) } before(:all) do @professor_role = FactoryBot.create :role_professor @destroy_later = [] @@ -35,13 +36,12 @@ name: "professor", email: "professor@ic.uff.br", enrollment_number: "P1", - ) + ) end subject { professor } describe "Validations" do it { should be_valid } it { should belong_to(:city).required(false) } - it { should belong_to(:institution).required(false) } it { should belong_to(:academic_title_country).required(false) } it { should belong_to(:academic_title_institution).required(false) } it { should belong_to(:academic_title_level).required(false) }