Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PEOPLE: Geschwister in Abteilung als computed value #289

Merged
merged 17 commits into from
Dec 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Hitobito PBS Changelog

## unreleased

* Das Feld "Geschwister in der Abteilung" wird neu von eingetragenen Geschwistern abgeleitet und pro Ebene bzw. pro Anlass berechnet und angezeigt. (hitobito#2147)

## Version 1.30

* Das Anwesenheiten-Tab bei Kursen im Status "Qualifikationen erfasst" und "Abgeschlossen" wird neu mit einem Ausrufezeichen markiert, wenn die Anwesenheiten noch gespeichert werden müssen. Merci @ewangler! (hitobito/hitobito_pbs#262)
Expand Down
8 changes: 8 additions & 0 deletions app/decorators/pbs/person_decorator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,18 @@ def roles_grouped(scope:)
end
end

def siblings_in_context(context)
family_member_finder.family_members_in_context(context, kind: :sibling)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ich habe die Logik in einen abgekapselten Service verschoben, weil sie doch an einigen verschiedenen Orten gebraucht wird und so einfacher getestet werden kann.

end

end

private

def family_member_finder
@family_member_finder ||= Person::FamilyMemberFinder.new(self)
end

def layer_group_ids
@layer_group_ids ||= current_user&.layer_group_ids ||
[current_service_token&.layer_group_id].compact.presence ||
Expand Down
7 changes: 7 additions & 0 deletions app/domain/pbs/export/tabular/people/participation_row.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ def bsv_days
participation.bsv_days || participation.event.bsv_days
end

def has_siblings_in_event
event = participation.event

::Person::FamilyMemberFinder.new(participation.person)
.family_members_in_context(event, kind: :sibling).any?
end

end
end
end
Expand Down
7 changes: 7 additions & 0 deletions app/domain/pbs/export/tabular/people/participations_full.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,19 @@ module ParticipationsFull
extend ActiveSupport::Concern

included do
alias_method_chain :person_attributes, :pbs
alias_method_chain :build_attribute_labels, :pbs
end

def person_attributes_with_pbs
person_attributes_without_pbs + [:has_siblings_in_event]
end

def build_attribute_labels_with_pbs
build_attribute_labels_without_pbs.tap do |labels|
labels[:bsv_days] = ::Event::Participation.human_attribute_name(:bsv_days)
labels[:has_siblings_in_event] =
::Event::Participation.human_attribute_name(:has_siblings_in_event)
end
end
end
Expand Down
18 changes: 17 additions & 1 deletion app/domain/pbs/export/tabular/people/people_full.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,24 @@ module PeopleFull
end

def person_attributes_with_pbs
person_attributes_without_pbs + [:id, :layer_group_id, :pbs_number]
attrs = person_attributes_without_pbs + [:id, :layer_group_id, :pbs_number]
attrs += [:has_siblings_in_layer] if @group.present?
attrs
end

def initialize(list, group = nil)
super(list)
@group = group
end

private

def row_for(entry, format = nil)
return super unless row_class == ::Export::Tabular::People::PersonRow &&
@group.present?
row_class.new(entry, format, @group)
end

end
end
end
Expand Down
9 changes: 9 additions & 0 deletions app/domain/pbs/export/tabular/people/person_row.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ module People
module PersonRow
extend ActiveSupport::Concern

def initialize(entry, format = nil, group = nil)
super(entry, format)
@group = group
end

def salutation
entry.salutation_value
end
Expand All @@ -24,6 +29,10 @@ def layer_group_id
entry.try(:primary_group).try(:layer_group).try(:id)
end

def has_siblings_in_layer
::Person::FamilyMemberFinder.new(entry)
.family_members_in_context(@group, kind: :sibling)&.any?
end
end
end
end
Expand Down
33 changes: 33 additions & 0 deletions app/domain/person/family_member_finder.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Copyright (c) 2023, Pfadibewegung Schweiz. This file is part of
# hitobito_pbs 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_pbs.

class Person::FamilyMemberFinder
attr_reader :person

def initialize(person)
@person = person
end

def family_members_in_layer(group, kind: :sibling)
Role.joins(person: :family_members)
.where(group: group.groups_in_same_layer,
person: { family_members: { kind: kind, other: person } })
end

def family_members_in_event(event, kind: :sibling)
Event::Participation.joins(person: :family_members)
.where(person: { family_members: { kind: kind, other: person } },
event: event)
end

def family_members_in_context(context, kind: :sibling)
case context
when Event
family_members_in_event(context, kind: kind)
when Group
family_members_in_layer(context, kind: kind)
end
end
end
5 changes: 5 additions & 0 deletions app/jobs/pbs/export/event_participations_export_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,10 @@ def unfiltered_participants
references(:people).
distinct
end

def data
return super unless exporter == ::Export::Tabular::People::ParticipationsFull
::Export::Tabular::People::ParticipationsFull.export(@format, entries, @filter.event)
end

end
6 changes: 5 additions & 1 deletion app/jobs/pbs/export/people_export_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,12 @@ module Pbs::Export::PeopleExportJob
end

def exporter_with_detail
return Pbs::Export::Tabular::People::HouseholdsFull if @options[:household_details]
return Pbs::Export::Tabular::People::HouseholdsFull if @options[:household_details]
exporter_without_detail
end

def data
return super unless exporter == ::Export::Tabular::People::PeopleFull
::Export::Tabular::People::PeopleFull.export(@format, entries, group)
end
end
3 changes: 1 addition & 2 deletions app/models/pbs/person.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,7 @@ module Pbs::Person

alias_method_chain :full_name, :title

i18n_boolean_setter :brother_and_sisters, :prefers_digital_correspondence

i18n_boolean_setter :prefers_digital_correspondence

belongs_to :kantonalverband, class_name: 'Group' # might also be Group::Bund
has_many :crises, foreign_key: :creator_id
Expand Down
4 changes: 4 additions & 0 deletions app/serializers/pbs/event_participation_serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ module Pbs::EventParticipationSerializer
translated_label: number.translated_label
}
end)

property(:has_siblings_in_event,
::Person::FamilyMemberFinder.new(item.person)
.family_members_in_context(item.event, kind: :sibling).any?)
end
end
end
8 changes: 6 additions & 2 deletions app/serializers/pbs/person_serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,13 @@ module Pbs::PersonSerializer
included do
extension(:details) do |_|
map_properties :pbs_number, :salutation_value, :correspondence_language,
:prefers_digital_correspondence, :grade_of_school, :brother_and_sisters,
:entry_date, :leaving_date
:prefers_digital_correspondence, :grade_of_school, :entry_date, :leaving_date

if context[:group].present?
property :has_siblings_in_layer, item.siblings_in_context(context[:group]).any?
end
end

end

end
13 changes: 12 additions & 1 deletion app/views/people/_details_pbs.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,17 @@
-# https://github.com/hitobito/hitobito_pbs.

= render_attrs(entry, :pbs_number, :salutation, :correspondence_language,
:grade_of_school, :brother_and_sisters)
:grade_of_school)

%dl.dl-horizontal
- sibling_context = parent.try(:layer_group) || parent
- siblings_in_context = entry.siblings_in_context(sibling_context)
= labeled(t('people.fields_pbs.siblings_in_context', context: sibling_context)) do
- if siblings_in_context.any?
= t('global.yes')
= simple_list(siblings_in_context, class: 'unstyled mb-0') do |sibling_role|
- assoc_link(sibling_role.person)
- else
= t('global.no')

= render_attrs(entry, :entry_date, :leaving_date)
3 changes: 0 additions & 3 deletions app/views/people/_fields_pbs.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,3 @@

= field_set_tag do
= f.labeled_input_fields(:entry_date, :leaving_date)

= field_set_tag do
= f.labeled_boolean_field(:brother_and_sisters, caption: t('.in_abteilung'))
4 changes: 2 additions & 2 deletions config/locales/models.pbs.de.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1243,6 +1243,7 @@ de:
additional_information: Wie möchtest du dich im Anlass ernähren? Was sind deine Essgewohnheiten?
bsv_days: BSV-Tage
j_s_data_sharing_accepted: J+S Datenweitergabe
has_siblings_in_event: Geschwister im Anlass

event/question:
pass_on_to_supercamp: An übergeordnetes Lager weitergeben
Expand All @@ -1259,8 +1260,7 @@ de:
leaving_date: Austrittsdatum
j_s_number: J+S Personennummer
correspondence_language: Korrespondenzsprache
brother_and_sisters: Geschwister
relations_to_tails: Geschwister
has_siblings_in_layer: Geschwister in der Ebene
kv: Kantonalverband
prefers_digital_correspondence: Digitale Korrespondenz bevorzugt

Expand Down
2 changes: 1 addition & 1 deletion config/locales/views.pbs.de.yml
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ de:
no_sensitive_information: In diesem Feld keine besonders schützenswerte Personendaten erfassen.
fields_pbs:
non_automatic_field: Dies ist kein automatisches Feld und muss manuell angepasst werden.
in_abteilung: (in der Abteilung)
siblings_in_context: Geschwister in %{context}
qualification_buttons_pbs:
print_course_confirmation: Kursbestätigung drucken
household_attrs_pbs:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class RemoveBrotherAndSisterFromPersons < ActiveRecord::Migration[6.1]
def change
remove_column :people, :brother_and_sisters, :boolean, default: false, null: false
end
end
2 changes: 1 addition & 1 deletion lib/hitobito_pbs/wagon.rb
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ class Wagon < Rails::Engine
### controllers
PeopleController.permitted_attrs += [:salutation, :title, :grade_of_school, :entry_date,
:leaving_date, :j_s_number, :correspondence_language,
:prefers_digital_correspondence, :brother_and_sisters]
:prefers_digital_correspondence]
GroupsController.permitted_attrs += [:hostname]
Event::KindsController.permitted_attrs += [:documents_text, :campy, :can_have_confirmations,
:confirmation_name]
Expand Down
93 changes: 93 additions & 0 deletions spec/domain/person/family_member_finder_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# encoding: utf-8

# Copyright (c) 2017, Pfadibewegung Schweiz. This file is part of
# hitobito_pbs 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_pbs.
diegosteiner marked this conversation as resolved.
Show resolved Hide resolved

require 'spec_helper'

describe Person::FamilyMemberFinder do

let(:service) { described_class.new(person) }
let(:person) { Fabricate(:person) }
let(:sibling) { Fabricate(:person) }

let!(:sibling_relation) { Fabricate(:family_member, person: person, other: sibling, kind: :sibling) }

describe '#family_members_in_event' do

let(:person_event) { Fabricate(:event) }
let!(:person_participation) { Fabricate(:event_participation, person: person, event: person_event) }
let(:sibling_event) { Fabricate(:event) }
let!(:sibling_participation) { Fabricate(:event_participation, person: sibling, event: sibling_event) }

subject do
service.family_members_in_event(person_event, kind: :sibling)
end

context 'without siblings' do
let!(:sibling_relation) { nil }
it { is_expected.to be_empty }
end

context 'with siblings in different events' do
it { is_expected.to be_empty }
end

context 'with siblings in same event' do
let(:sibling_event) { person_event }
it { is_expected.to contain_exactly(sibling_participation) }
end

context 'with siblings with deleted role in same group' do
let!(:sibling_participation) { Fabricate(:event_participation, person: sibling, event: sibling_event, active: false) }
it { is_expected.to be_empty }
end

end

describe '#family_members_in_layer' do

let(:layer) { Fabricate(Group::Abteilung.name) }

let(:person_group) { Fabricate(Group::Pfadi.name, parent: layer)}
let!(:person_role) { Fabricate(person_group.default_role.name, person: person, group: person_group) }

let(:sibling_group) { Fabricate(Group::Woelfe.name, parent: layer)}
let!(:sibling_role) { Fabricate(sibling_group.default_role.name, person: sibling, group: sibling_group) }

subject do
service.family_members_in_layer(person_group, kind: :sibling)
end

context 'without siblings' do
let!(:sibling_relation) { nil }
it { is_expected.to be_empty }
end

context 'with siblings in different groups' do
let(:sibling_group) { Fabricate(Group::Woelfe.name, parent: Fabricate(Group::Abteilung.name))}
it { is_expected.to be_empty }
end

context 'with siblings in same group' do
let(:sibling_group) { person_group }
it { is_expected.to contain_exactly(sibling_role) }
end

context 'with siblings in same layer' do
it { is_expected.to contain_exactly(sibling_role) }
end

context 'with siblings with deleted role in same group' do
let!(:sibling_role) do
Fabricate(sibling_group.default_role.name, person: sibling, group: sibling_group,
created_at: 2.months.ago, deleted_at: 1.month.ago)
end
it { is_expected.to be_empty }
end

end

end