Skip to content

Commit

Permalink
Support adding external_trainings for multiple people (#524)
Browse files Browse the repository at this point in the history
  • Loading branch information
amaierhofer committed May 22, 2024
1 parent 0e98e4a commit aaf4dfd
Show file tree
Hide file tree
Showing 10 changed files with 179 additions and 19 deletions.
49 changes: 39 additions & 10 deletions app/controllers/external_trainings_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,37 +15,66 @@ class ExternalTrainingsController < CrudController
:finish_at,
:training_days,
:link,
:remarks]
:remarks,
{ other_people_ids: [] }]

decorates :group, :person

# load parents before authorization
prepend_before_action :parent
before_render_form :load_event_kinds
before_render_form :load_other_people

def create
super(location: history_group_person_path(@group, @person)) do
qualifier.issue if entry.valid?
assign_attributes
if ExternalTraining.transaction { save_entry }
redirect_to(history_path, notice: create_success_message)
else
respond_with(entry)
end
end

def destroy
super(location: history_group_person_path(@group, @person)) do
qualifier.revoke
end
super(location: history_path)
end

private

def history_path
history_group_person_path(@group, @person)
end

def build_entry
@person.external_trainings.build
end

def qualifier
@qualifier ||= ExternalTrainings::Qualifier.new(@person, entry, 'participant')
def load_event_kinds
@event_kinds = Event::Kind.list
end

def load_event_kinds
@event_kinds ||= Event::Kind.list
def load_other_people
@other_people = writables.where(id: entry.other_people_ids)
end

# need to clear out any potential non writable person ids
def permitted_params
super.tap do |p|
next if p[:other_people_ids].blank?

p[:other_people_ids] = writables.where(id: p[:other_people_ids]).pluck(:id) - [@person.id]
end
end

def writables
Person.accessible_by(PersonWritables.new(current_user))
end

def create_success_message
return flash_message(:success) if entry.other_people_ids.blank?

names = [entry.person.to_s] + Person.where(id: entry.other_people_ids).map(&:to_s)
I18n.t("external_trainings.create.flash.success_multiple",
model: "#{models_label(true)} <i>#{ERB::Util.h(entry.to_s)}</i>".html_safe, # rubocop:disable Rails/OutputSafety
names: names.to_sentence)
end
end
19 changes: 19 additions & 0 deletions app/controllers/person/query_external_training_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# frozen_string_literal: true

# Copyright (c) 2012-2024, Schweizer Alpen-Club. This file is part of
# hitobito_sac_cas and licensed under the Affero General Public License version 3
# or later. See the COPYING file at the top-level directory or at
# https://github.com/hitobito/hitobito_sac_cas.


class Person::QueryExternalTrainingController < Person::QueryController

private

def scope
Person
.accessible_by(PersonWritables.new(current_user))
.distinct.joins(roles: :group)
end

end
29 changes: 28 additions & 1 deletion app/models/external_training.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,16 @@ class ExternalTraining < ActiveRecord::Base
belongs_to :person
belongs_to :event_kind, class_name: 'Event::Kind'

attr_accessor :other_people_ids

validates_date :finish_at, on_or_after: :start_at, allow_blank: true

scope :list, -> { order(created_at: :desc) }

after_destroy :revoke_qualifications
after_save :issue_qualifications
after_save :create_trainings_for_other_people

def self.between(start_date, end_date)
where('start_at <= :end_date AND finish_at >= :start_date ',
start_date: start_date, end_date: end_date).distinct
Expand All @@ -32,5 +38,26 @@ def qualification_date
finish_at
end

alias_method :kind, :event_kind
alias kind event_kind

private

def qualifier
ExternalTrainings::Qualifier.new(person, self, 'participant')
end

def issue_qualifications
qualifier.issue
end

def revoke_qualifications
qualifier.revoke
end

def create_trainings_for_other_people
Array(other_people_ids).each do |person_id|
ExternalTraining.create!(attributes.except('id', 'person_id').merge(person_id: person_id))
end
end

end
14 changes: 14 additions & 0 deletions app/views/external_trainings/_form.html.haml
Original file line number Diff line number Diff line change
@@ -1,6 +1,20 @@
- # Copyright (c) 2024, Schweizer Alpen-Club. This file is part of
- # hitobito_sac_cas and licensed under the Affero General Public License version 3
- # or later. See the COPYING file at the top-level directory or at
- # https://github.com/hitobito/hitobito_sac_cas

= entry_form(cancel_url: history_group_person_path(@group, @person), data: { controller: :forwarder }) do |f|
= f.labeled_input_fields :name, :provider
= f.labeled_input_field :start_at
= f.labeled_input_field :finish_at
= render 'event_kind_field_with_info', f: f
= f.labeled_input_fields :training_days, :link, :remarks
= field_set_tag do
= f.labeled(:other_people_ids, '') do
= f.collection_select(:other_people_ids, @other_people.to_a, :id, :to_s, {},
{ multiple: true, placeholder: I18n.t('global.search.placeholder_person'),
data: { controller: 'tom-select',
tom_select_url_value: query_external_training_path,
tom_select_no_results_value: I18n.t('global.no_list_entries'),
tom_select_label_value: 'label' } })
= f.help_inline(t('.help_other_people'))
1 change: 1 addition & 0 deletions app/views/external_trainings/_person.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
= f.input_field :person_id
22 changes: 16 additions & 6 deletions config/locales/wagon.de.yml
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ de:
finish_at: Enddatum
training_days: Ausbildungstage
link: Link
other_people_ids: Weitere Personen
remarks: Bemerkung
created_at: Erstellt
updated_at: Geändert
Expand Down Expand Up @@ -234,12 +235,12 @@ de:
entry_fee_adult: Eintrittsgebühr, Mitgliedschaft Einzel
entry_fee_family: Eintrittsgebühr, Mitgliedschaft Familie
entry_fee_youth: Eintrittsgebühr, Mitgliedschaft Jugend
hut_solidarity_fee_with_hut_adult: Hüttensolidaritätsbeitrag Sektion mit Hütten, Mitgliedschaft Einzel
hut_solidarity_fee_with_hut_family: Hüttensolidaritätsbeitrag Sektion mit Hütten, Mitgliedschaft Familie
hut_solidarity_fee_with_hut_youth: Hüttensolidaritätsbeitrag Sektion mit Hütten, Mitgliedschaft Jugend
hut_solidarity_fee_without_hut_adult: Hüttensolidaritätsbeitrag Sektion ohne Hütten, Mitgliedschaft Einzel
hut_solidarity_fee_without_hut_family: Hüttensolidaritätsbeitrag Sektion ohne Hütten, Mitgliedschaft Familie
hut_solidarity_fee_without_hut_youth: Hüttensolidaritätsbeitrag Sektion ohne Hütten, Mitgliedschaft Jugend
hut_solidarity_fee_with_hut_adult: Hüttensolidaritätsbeitrag Sektion mit Hütten, Mitgliedschaft Einzel
hut_solidarity_fee_with_hut_family: Hüttensolidaritätsbeitrag Sektion mit Hütten, Mitgliedschaft Familie
hut_solidarity_fee_with_hut_youth: Hüttensolidaritätsbeitrag Sektion mit Hütten, Mitgliedschaft Jugend
hut_solidarity_fee_without_hut_adult: Hüttensolidaritätsbeitrag Sektion ohne Hütten, Mitgliedschaft Einzel
hut_solidarity_fee_without_hut_family: Hüttensolidaritätsbeitrag Sektion ohne Hütten, Mitgliedschaft Familie
hut_solidarity_fee_without_hut_youth: Hüttensolidaritätsbeitrag Sektion ohne Hütten, Mitgliedschaft Jugend
magazine_fee_adult: Abogebühr SAC Magazin, Mitgliedschaft Einzel
magazine_fee_family: Abogebühr SAC Magazin, Mitgliedschaft Familie
magazine_fee_youth: Abogebühr SAC Magazin, Mitgliedschaft Jugend
Expand Down Expand Up @@ -529,6 +530,15 @@ de:
Kostenträger) auf alle Kursarten übertragen? Dabei werden die aktuellen Werte
überschrieben.

external_trainings:
form:
help_other_people: Zusätzliche Personen für welche die Externe Ausbildung erfasst werden soll.
create:
flash:
success_multiple:
"%{model} wurde erfolgreich für %{names} erstellt."


participations:
edit:
title: Zusatzdaten
Expand Down
2 changes: 2 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
# Define wagon routes here

get '/people/:id/membership' => 'people/membership#show', as: 'membership'
get '/people/query_external_training' => 'person/query_external_training#index',
as: :query_external_training

resources :event_levels, module: 'event', controller: 'levels', except: [:show]

Expand Down
50 changes: 49 additions & 1 deletion spec/controllers/external_trainings_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
before { sign_in(people(:admin)) }

describe 'POST#create' do
let(:ski_leader_qualis) { person.qualifications.where(qualification_kind: ski_leader) }
let(:ski_leader_qualis) { Qualification.where(qualification_kind: ski_leader) }
let(:params) {
{
group_id: group.id,
Expand All @@ -39,6 +39,7 @@
expect(response).to redirect_to(history_group_person_path(group, person))
end.to change { ExternalTraining.count }.by(1)
.and not_change { Qualification.count }
expect(flash[:notice]).to eq 'Externe Ausbildung <i>Skikurs</i> wurde erfolgreich erstellt.'
end

it 'creates qualification if event qualifies' do
Expand All @@ -48,6 +49,53 @@
end.to change { ski_leader_qualis.count }.by(1)
end

context 'with other people' do
let(:admin) { people(:admin) }
let(:tourenchef) { people(:tourenchef) }

before { params[:external_training][:other_people_ids] = [admin.id, tourenchef.id] }

it 'creates trainings for people listed as other_ids' do
expect do
post :create, params: params
end.to change { ExternalTraining.count }.by(3)
expect(flash[:notice]).to eq 'Externe Ausbildungen <i>Skikurs</i> wurde erfolgreich für ' \
'Edmund Hillary, Anna Admin und Ida Paschke erstellt.'
end

it 'ignores person if it also listed in other_people_ids' do
params[:external_training][:other_people_ids] += [person.id]
expect do
post :create, params: params
end.to change { ExternalTraining.count }.by(3)
end

it 'creates qualification if event qualifies' do
create_event_kind_quali_kind(ski_course, ski_leader, category: :qualification)
expect do
post :create, params: params
end.to change { ski_leader_qualis.count }.by(3)
end

context 'as mitglied' do
let(:funktionaere) { groups(:bluemlisalp_funktionaere) }
let(:verwalter) do
Fabricate(Group::SektionsFunktionaere::Mitgliederverwaltung.sti_name,
group: funktionaere).person
end

it 'ignores person for which current user has no write permission' do
sign_in(verwalter)
params[:external_training][:other_people_ids] = [admin.id, verwalter.id]
expect do
post :create, params: params
end.to change { ExternalTraining.count }.by(2)
.and change { verwalter.external_trainings.count }.by(1)
.and not_change { admin.external_trainings.count }
end
end
end

context 'existing qualification' do
let!(:quali) do
Fabricate(:qualification, qualification_kind: ski_leader, person: person, start_at: 3.years.ago, qualified_at: 3.years.ago)
Expand Down
10 changes: 10 additions & 0 deletions spec/features/external_training_model_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,16 @@
text: "Externe Ausbildung Schwimmkurs wurde erfolgreich gelöscht.")
end

it "can multiselect people" do
sign_in(admin)
visit history_group_person_path(group_id: mitglieder, id: mitglied)
click_on 'Erstellen'
fill_in 'Weitere Personen', with: 'Tenzing'
find('.option.active', text: 'Norgay').click
fill_in 'Weitere Personen', with: 'Paschke'
find('.option.active', text: 'Ida').click
end

it "reloads qualification infos", js: true do
sign_in(admin)
visit history_group_person_path(group_id: mitglieder, id: mitglied)
Expand Down
2 changes: 1 addition & 1 deletion spec/fixtures/roles.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,6 @@ abonnent_alpen:
tourenchef_bluemlisalp_ortsgruppe_ausserberg:
person_id: 600_006
group: bluemlisalp_ortsgruppe_ausserberg_tourenkommission
type: Group::SektionsTourenkommission::Tourenchef
type: Group::SektionsTourenkommission::TourenchefSommer
created_at: 2015-01-01 00:00:00
delete_on: 2015-12-31

0 comments on commit aaf4dfd

Please sign in to comment.