Commit aec79283 authored by Jiri Strojil's avatar Jiri Strojil
Browse files

Resolved conflict

parents 2a659e9d a3eb4e25
Pipeline #31143 passed with stage
in 56 minutes and 51 seconds
.form-group.float.optional.semester_process_volunteer_semester_feedbacks_hour_hours {
display: inline-flex;
}
class SemesterProcessVolunteersController < ApplicationController class SemesterProcessVolunteersController < ApplicationController
before_action :prepare_review, only: [:review_semester, :submit_review] before_action :prepare_review, :initialize_nested_objects, only: [:review_semester, :submit_review]
before_action :initialize_feedback, only: [:review_semester, :submit_review] before_action :set_semester_process_volunteer, only: [:show, :edit, :update, :take_responsibility]
before_action :set_semester_process_volunteer, only: [:show, :edit, :update]
before_action :set_semester, only: [:index] before_action :set_semester, only: [:index]
include SemesterProcessVolunteerHelper include SemesterProcessVolunteerHelper
def review_semester def review_semester
@hour = Hour.new
end end
def submit_review def submit_review
assign_reviewed_attributes # you shall not pass
return if @semester_process_volunteer.commited_at
set_reviewed set_reviewed
assign_volunteer_attributes
build_nested_objects
@semester_process_volunteer.volunteer.validate_waive_and_bank = true @semester_process_volunteer.volunteer.validate_waive_and_bank = true
begin
ActiveRecord::Base.transaction do
@semester_process_volunteer.semester_feedbacks << @feedback
@hour.save! unless @hour.hours == 0 || @hour.hours.blank?
@semester_process_volunteer.save!
@volunteer.save!
end
redirect_to( ActiveRecord::Base.transaction do
review_semester_semester_process_volunteer_path(@semester_process_volunteer), @semester_process_volunteer.save!
notice: 'Successfully reviewed.' @volunteer.save!
)
rescue ActiveRecord::RecordInvalid => exception @nested_objects.each do |_key, hash|
null_reviewed hash.each { |_id, obj| obj.save! }
@hours.reload end
render :review_semester, notice: exception
end end
redirect_to review_semester_semester_process_volunteer_path(@semester_process_volunteer), notice: t('.success')
rescue ActiveRecord::RecordInvalid => exception
logger.error exception.message
null_reviewed
flash[:alert] = exception.message
render :review_semester
end end
def index def index
authorize SemesterProcessVolunteer authorize SemesterProcessVolunteer
semester = Semester.parse(params[:semester]) semester = Semester.parse(params[:semester])
@spvs = SemesterProcessVolunteer.index(semester).page(params[:page])
@semester_process = SemesterProcess.find_by_semester(semester).last @semester_process = SemesterProcess.find_by_semester(semester).last
@spvs_sorted = @spvs.sort { |spv1, spv2| spv1.volunteer.contact.full_name <=> spv2.volunteer.contact.full_name} @q = SemesterProcessVolunteer.index(semester).ransack(params[:q])
@q.sorts = ['volunteer_contact_last_name asc'] if @q.sorts.empty?
@spvs = @q.result.paginate(page: params[:page])
set_responsibles
end end
def show; end def show; end
...@@ -53,23 +58,36 @@ class SemesterProcessVolunteersController < ApplicationController ...@@ -53,23 +58,36 @@ class SemesterProcessVolunteersController < ApplicationController
end end
end end
def take_responsibility
respond_to do |format|
if @spv.update(responsible: current_user)
format.html { redirect_to(@redirect_back_path, notice: 'Halbjahres-Rapport übernommen.') }
format.json do
render json: { link: url_for(@spv.responsible), at: I18n.l(@spv.responsibility_taken_at.to_date),
email: @spv.responsible.email }, status: :ok
end
else
format.html { redirect_to(@redirect_back_path, notice: 'Fehler: Übernehmen fehlgeschlagen.') }
format.json { render json: { errors: @spv.errors.messages }, status: :unprocessable_entity }
end
end
end
private private
def prepare_review def prepare_review
# careful cuz mission id can be present in both missions
@semester_process_volunteer = SemesterProcessVolunteer.find(params[:id]) @semester_process_volunteer = SemesterProcessVolunteer.find(params[:id])
@hours = @semester_process_volunteer.hours
@volunteer = @semester_process_volunteer.volunteer
@mission = @semester_process_volunteer.missions.first
authorize @semester_process_volunteer authorize @semester_process_volunteer
@volunteer = @semester_process_volunteer.volunteer
@missions = @semester_process_volunteer.missions
end end
def review_params def review_params
params.require(:semester_process_volunteer).permit( params.require(:semester_process_volunteer).permit(
volunteer_attributes: [:waive, :iban, :bank], volunteer_attributes: [:id ,:waive, :iban, :bank],
semester_feedback: [:goals, :achievements, :future, :comments, :conversation], semester_feedbacks_attributes: [[semester_feedback: [:mission, :goals, :achievements, :future, :comments, :conversation, :spv_mission_id]],
hour: [:hours] [hour: [:hours, :spv_mission_id ]]])
)
end end
def set_semester_process_volunteer def set_semester_process_volunteer
...@@ -89,6 +107,19 @@ class SemesterProcessVolunteersController < ApplicationController ...@@ -89,6 +107,19 @@ class SemesterProcessVolunteersController < ApplicationController
end end
end end
def set_responsibles
@responsibles = SemesterProcessVolunteer.joins(responsible: [profile: [:contact]])
.distinct
.select('users.id, contacts.full_name')
.map do |responsible|
{
q: :responsible_id_eq,
text: "Übernommen von #{responsible.full_name}",
value: responsible.id
}
end
end
def semester_process_volunteer_params def semester_process_volunteer_params
params.require(:semester_process_volunteer).permit(:semester) params.require(:semester_process_volunteer).permit(:semester)
end end
......
module SemesterProcessVolunteerHelper module SemesterProcessVolunteerHelper
def initialize_feedback
@feedback = SemesterFeedback.new(mission: @mission, semester_process_volunteer: @semester_process_volunteer,
author: current_user)
end
def set_reviewed def set_reviewed
@semester_process_volunteer.commited_by = current_user @semester_process_volunteer.commited_by = current_user
@semester_process_volunteer.commited_at = Time.zone.now @semester_process_volunteer.commited_at = Time.zone.now
end end
def assign_reviewed_attributes def initialize_nested_objects
@hour = Hour.new( @nested_objects = {}
volunteer: @volunteer, @semester_process_volunteer.semester_process_volunteer_missions.each do |spvm|
hourable: @mission, @nested_objects[spvm.id.to_s] = { feedback: @semester_process_volunteer.semester_feedback_with_mission(spvm.mission) || SemesterFeedback.new }
semester_process_volunteer: @semester_process_volunteer, end
meeting_date: Time.zone.now, @nested_objects
) end
@hour.assign_attributes(review_params[:hour])
def build_nested_objects
review_params[:semester_feedbacks_attributes].each do |_key, hash|
spv_mission = SemesterProcessVolunteerMission.find(hash[:semester_feedback][:spv_mission_id])
@nested_objects[spv_mission.id.to_s][:feedback] = SemesterFeedback.new(hash[:semester_feedback].merge({
author: current_user, semester_process_volunteer: @semester_process_volunteer
}))
if hash[:hour][:hours].to_i.positive?
@nested_objects[spv_mission.id.to_s][:hours] = Hour.new(hash[:hour].merge({
volunteer: spv_mission.volunteer,
meeting_date: Time.zone.now,
semester_process_volunteer: @semester_process_volunteer
}))
end
end
end
def assign_volunteer_attributes
@volunteer.assign_attributes(review_params[:volunteer_attributes] @volunteer.assign_attributes(review_params[:volunteer_attributes]
.slice(:waive, :bank, :iban)) .slice(:waive, :bank, :iban))
@feedback.assign_attributes(review_params[:semester_feedback])
end end
def null_reviewed def null_reviewed
......
...@@ -8,6 +8,8 @@ module MissionEitherOneRelation ...@@ -8,6 +8,8 @@ module MissionEitherOneRelation
validate :validate_group_assignment_or_assignment_present validate :validate_group_assignment_or_assignment_present
attr_accessor :mission_id
def mission=(mission) def mission=(mission)
if mission.class.name == 'Assignment' if mission.class.name == 'Assignment'
self.assignment = mission self.assignment = mission
......
...@@ -45,6 +45,13 @@ class Hour < ApplicationRecord ...@@ -45,6 +45,13 @@ class Hour < ApplicationRecord
group_offer.where(hourable_id: group_offer_ids) group_offer.where(hourable_id: group_offer_ids)
} }
attr_reader :spv_mission_id
def spv_mission_id= id
spv_mission = SemesterProcessVolunteerMission.find(id)
self.hourable = spv_mission.mission.group_assignment? ? spv_mission.mission.group_offer : spv_mission.mission
end
def assignment? def assignment?
hourable_type == 'Assignment' hourable_type == 'Assignment'
end end
......
...@@ -5,6 +5,11 @@ class SemesterFeedback < ApplicationRecord ...@@ -5,6 +5,11 @@ class SemesterFeedback < ApplicationRecord
belongs_to :semester_process_volunteer belongs_to :semester_process_volunteer
has_one :semester_process, through: :semester_process_volunteer has_one :semester_process, through: :semester_process_volunteer
has_one :volunteer, through: :semester_process_volunteer has_one :volunteer, through: :semester_process_volunteer
validates :goals, :achievements, :future, presence: true validates :goals, :achievements, :future, presence: true
attr_reader :spv_mission_id
def spv_mission_id= id
self.mission = SemesterProcessVolunteerMission.find(id).mission
end
end end
...@@ -28,7 +28,7 @@ class SemesterProcessVolunteer < ApplicationRecord ...@@ -28,7 +28,7 @@ class SemesterProcessVolunteer < ApplicationRecord
has_many :reminders, -> { where(kind: 'reminder') }, class_name: 'SemesterProcessMail', has_many :reminders, -> { where(kind: 'reminder') }, class_name: 'SemesterProcessMail',
foreign_key: 'semester_process_volunteer_id', inverse_of: 'semester_process_volunteer' foreign_key: 'semester_process_volunteer_id', inverse_of: 'semester_process_volunteer'
accepts_nested_attributes_for :hours, :volunteer, :semester_feedbacks accepts_nested_attributes_for :group_assignments, :assignments , :semester_process_volunteer_missions , :hours, :volunteer, :semester_feedbacks
validates_associated :hours, :semester_feedbacks, :volunteer validates_associated :hours, :semester_feedbacks, :volunteer
...@@ -44,6 +44,11 @@ class SemesterProcessVolunteer < ApplicationRecord ...@@ -44,6 +44,11 @@ class SemesterProcessVolunteer < ApplicationRecord
end end
} }
def semester_feedback_with_mission(mission)
self.semester_feedbacks.order(:created_at).select{|sf| sf.mission == mission}.last
end
# will only return an array, not a AD-result # will only return an array, not a AD-result
def missions def missions
semester_process_volunteer_missions.map(&:mission) semester_process_volunteer_missions.map(&:mission)
...@@ -70,4 +75,9 @@ class SemesterProcessVolunteer < ApplicationRecord ...@@ -70,4 +75,9 @@ class SemesterProcessVolunteer < ApplicationRecord
def render_feedback(field) def render_feedback(field)
semester_feedbacks.map(&field).join(', ') semester_feedbacks.map(&field).join(', ')
end end
def responsible=(responsible_user)
self.responsibility_taken_at = Time.zone.now
super(responsible_user)
end
end end
class SemesterProcessVolunteerMission < ApplicationRecord class SemesterProcessVolunteerMission < ApplicationRecord
include MissionEitherOneRelation include MissionEitherOneRelation
delegate :volunteer, to: :semester_process_volunteer
belongs_to :semester_process_volunteer belongs_to :semester_process_volunteer
end end
...@@ -7,13 +7,14 @@ class SemesterProcessVolunteerPolicy < ApplicationPolicy ...@@ -7,13 +7,14 @@ class SemesterProcessVolunteerPolicy < ApplicationPolicy
end end
# Actions # Actions
alias_method :index?, :superadmin? alias_method :index?, :superadmin?
alias_method :review_semester?, :superadmin_or_volunteer_related? alias_method :review_semester?, :superadmin_or_volunteer_related?
alias_method :submit_review?, :superadmin_or_volunteer_related? alias_method :submit_review?, :superadmin_or_volunteer_related?
alias_method :new?, :superadmin? alias_method :new?, :superadmin?
alias_method :show?, :superadmin? alias_method :show?, :superadmin?
alias_method :edit?, :superadmin? alias_method :edit?, :superadmin?
alias_method :create?, :superadmin? alias_method :create?, :superadmin?
alias_method :update?, :superadmin? alias_method :update?, :superadmin?
alias_method :destroy?, :superadmin? alias_method :destroy?, :superadmin?
alias_method :take_responsibility?, :superadmin?
end end
nav.navbar.section-navigation nav.navbar.section-navigation
hr hr
ul.list-inline ul.list-inline
li= clear_filter_button
li= button_link 'Neuen Semester Prozess erstellen', new_semester_process_path, dimension: 'sm' li= button_link 'Neuen Semester Prozess erstellen', new_semester_process_path, dimension: 'sm'
li= render 'semester_filter' li= render 'semester_filter'
- if @semester_process - if @semester_process
li= button_link 'Semester Prozess bearbeiten', edit_semester_process_path(@semester_process), dimension: 'sm' li= button_link 'Semester Prozess bearbeiten', edit_semester_process_path(@semester_process), dimension: 'sm'
= custom_filter_dropdown('Übernommen',
{ q: :responsible_id_null, text: 'Offen', value: 'true' },
{ q: :responsible_id_not_null, text: 'Übernommen', value: 'true' },
*@responsibles)
hr hr
...@@ -12,16 +12,16 @@ h1= t_title(:index) ...@@ -12,16 +12,16 @@ h1= t_title(:index)
th Status th Status
th Freiwilige/r th Freiwilige/r
th Einsätze th Einsätze
th Missions
th Ziele th Ziele
th Erfolge th Erfolge
th Zukunft th Zukunft
th Bemerkungen th Bemerkungen
th= t_attr(:commited_by) th= t_attr(:commited_by)
th Letzte Bestätigung th Letzte Bestätigung
th= sort_link @q, :responsible_profile_contact_full_name, 'Übernommen'
tbody tbody
- @spvs_sorted.each do |spv| - @spvs.each do |spv|
tr tr
td.index-action-cell.hidden-print td.index-action-cell.hidden-print
= button_link icon_span(:edit), review_semester_semester_process_volunteer_path(spv), title: 'Bearbeiten' = button_link icon_span(:edit), review_semester_semester_process_volunteer_path(spv), title: 'Bearbeiten'
...@@ -31,7 +31,6 @@ h1= t_title(:index) ...@@ -31,7 +31,6 @@ h1= t_title(:index)
- else - else
.label.label-warning Unbestätigt .label.label-warning Unbestätigt
td= link_to_if policy(Volunteer).edit?, spv.volunteer.contact.full_name, edit_volunteer_path(spv.volunteer) td= link_to_if policy(Volunteer).edit?, spv.volunteer.contact.full_name, edit_volunteer_path(spv.volunteer)
td= spv.semester_t
td= render_missions(spv) td= render_missions(spv)
= td_truncate_content_modal(spv.render_feedback(:goals), 'Ziele', shorten_size: 300) = td_truncate_content_modal(spv.render_feedback(:goals), 'Ziele', shorten_size: 300)
= td_truncate_content_modal(spv.render_feedback(:achievements), 'Erfolge', shorten_size: 300) = td_truncate_content_modal(spv.render_feedback(:achievements), 'Erfolge', shorten_size: 300)
...@@ -39,6 +38,15 @@ h1= t_title(:index) ...@@ -39,6 +38,15 @@ h1= t_title(:index)
= td_truncate_content_modal(spv.render_feedback(:comments), 'Bemerkungen', shorten_size: 300) = td_truncate_content_modal(spv.render_feedback(:comments), 'Bemerkungen', shorten_size: 300)
td= spv.commited_by td= spv.commited_by
td= spv.commited_at && l(spv.commited_at) td= spv.commited_at && l(spv.commited_at)
td.index-action-cell.hidden-print
- if spv.responsible.present?
= 'Übernommen durch '
= link_to spv.responsible.email, spv.responsible
= " am #{l(spv.responsibility_taken_at.to_date)}"
- else
= api_button('Übernehmen', subject: [spv],
action: :take_responsibility, extra_class: 'm-t-10',
template: 'Übernommen durch <a href="<%= data.link %>"><%= data.email %></a> am <%= data.at %>')
= bootstrap_paginate(@spvs) = bootstrap_paginate(@spvs)
......
...@@ -3,24 +3,31 @@ ...@@ -3,24 +3,31 @@
= simple_error_notice f = simple_error_notice f
h1 Halbjahres-Rapporte #{@semester_process_volunteer.semester_t} für #{@semester_process_volunteer.volunteer.contact.full_name} h1 Halbjahres-Rapporte #{@semester_process_volunteer.semester_t} für #{@semester_process_volunteer.volunteer.contact.full_name}
h2.m-b-20.m-t-30 = f.simple_fields_for :semester_feedbacks, @semester_process_volunteer.semester_process_volunteer_missions do |spvm|
'Einsatz - mission = spvm.object.mission
= link_to @mission.to_label, polymorphic_path([@mission.volunteer, @mission.polymorph_url_object]), target: '_blank' h2.m-b-20.m-t-30
'Einsatz
= link_to mission.to_label,
url: polymorphic_path([mission.volunteer, mission.polymorph_url_object]),
target: '_blank'
= f.simple_fields_for @feedback do |ff| = spvm.simple_fields_for :semester_feedback, @nested_objects[spvm.object.id.to_s][:feedback] do |ff|
- [:goals, :achievements, :future, :comments, :conversation].each do |field| = ff.input :spv_mission_id, as: :hidden, input_html: { value: spvm.object.id }
.row - [:goals, :achievements, :future, :comments, :conversation].each do |field|
.col-xs-12= ff.input field .row
.col-xs-12= ff.input field
- if @hours.any? - if mission.hours.any?
h3 Stunden h3 Stunden
= render 'hours/last_submitted_hours', hours: @hours = render 'hours/last_submitted_hours', hours: mission.hours
= spvm.simple_fields_for :hour, Hour.new do |hf|
= hf.input :spv_mission_id, as: :hidden, input_html: { value: spvm.object.id}
.row
.col-xs-12= hf.input :hours, label: "Restliche Stunden in diesem Semester #{@semester_process_volunteer.semester_period}",
input_html: { value: f.object.hours == 0 ? '' : f.object.hours, min: 0},
required: false
= f.simple_fields_for @hour do |hf|
.row
.col-xs-2= hf.input :hours,
label: "Restliche Stunden in diesem Semester #{@semester_process_volunteer.semester_period}",
required: false, input_html: { value: f.object.hours == 0 ? '' : f.object.hours}
h3 Spesen h3 Spesen
= f.simple_fields_for :volunteer, @volunteer do |vf| = f.simple_fields_for :volunteer, @volunteer do |vf|
......
...@@ -193,6 +193,8 @@ de: ...@@ -193,6 +193,8 @@ de:
semester_process_volunteers: semester_process_volunteers:
show: show:
title: 'Semester Prozess %{semester} von %{name}' title: 'Semester Prozess %{semester} von %{name}'
submit_review:
success: Erfolgreich überprüft
salutation: &id-salutations salutation: &id-salutations
all: Alle all: Alle
family: Familie family: Familie
......
...@@ -100,6 +100,7 @@ Rails.application.routes.draw do ...@@ -100,6 +100,7 @@ Rails.application.routes.draw do
resources :semester_process_volunteers do resources :semester_process_volunteers do
get :review_semester, on: :member get :review_semester, on: :member
patch :submit_review, on: :member patch :submit_review, on: :member
put :take_responsibility, on: :member
end end
resources :semester_processes, except: [:destroy] resources :semester_processes, except: [:destroy]
......
...@@ -30,6 +30,7 @@ FactoryBot.define do ...@@ -30,6 +30,7 @@ FactoryBot.define do
end end
sem_fb.volunteer = sem_fb.semester_process_volunteer.volunteer sem_fb.volunteer = sem_fb.semester_process_volunteer.volunteer
sem_fb.author = sem_fb.volunteer.user sem_fb.author = sem_fb.volunteer.user
sem_fb.goals = sem_fb.semester_process_volunteer.semester_t
end end
after(:create) do |sem_fb, evl| after(:create) do |sem_fb, evl|
......
...@@ -19,7 +19,7 @@ FactoryBot.define do ...@@ -19,7 +19,7 @@ FactoryBot.define do
after(:create) do |sem_proc, evaluator| after(:create) do |sem_proc, evaluator|
if evaluator.build_volunteers if evaluator.build_volunteers
evaluator.volunteers_count.times do evaluator.volunteers_count.times do
create :semester_process_volunteer, :with_mission, semester_process: sem_proc create :semester_process_volunteer, :with_mission, :with_feedbacks, semester_process: sem_proc
end end
end end
end end
......
require 'test_helper'
class SemesterProcessVolunteerTest < ActiveSupport::TestCase
def setup
@volunteer = create(:volunteer_with_user)
@assignment = create(:assignment, volunteer: @volunteer)
@group_assignment = create(:group_assignment, volunteer: @volunteer)
@subject = create(:semester_process_volunteer, volunteer: @volunteer)
end
test 'set responsible also sets responsibility taken at' do
@subject.update(responsible: create(:user))
assert @subject.responsibility_taken_at.present?
end
end
require 'application_system_test_case'
class SemesterProcessVolunteerActionsTest < ApplicationSystemTestCase
setup do
@superadmin = create :user
@volunteer = create :volunteer_with_user
@volunteer.contact.update(first_name: 'Walter', last_name: 'White')