class User < ApplicationRecord # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable, :confirmable has_many :entries, dependent: :destroy PRAKTIKUMSTYPEN = %w[ propädeutikum fachspezifikum mediation ].freeze # ------------------------------------------------------------ # Alle möglichen Entry-Arten # ------------------------------------------------------------ ENTRY_ARTEN = [ # Allgemein "Praktikum", "Selbsterfahrung", "Supervision", "Fortbildung", "Semesterkosten", # Mediation "Präsenzmodul", "Peergruppenarbeit", "Fallarbeit", "Praxisseminare", "Literatur- und Selbststudium", # Fachspezifikum "Gruppenselbsterfahrung", "Theorie/Methodikseminare", "Peergruppensupervision", "Einzel-/Kleingruppensupervision", "Eigenständige Tätigkeit" ].freeze # ------------------------------------------------------------ # Arten pro Ausbildung # # Kann im Frontend / Controller verwendet werden, damit nicht # jede Entry-Art bei jedem Ausbildungstyp angezeigt wird. # ------------------------------------------------------------ ENTRY_ARTEN_BY_TYP = { "propädeutikum" => [ "Praktikum", "Selbsterfahrung", "Supervision", "Fortbildung", "Semesterkosten" ], "fachspezifikum" => [ "Praktikum", "Selbsterfahrung", "Supervision", "Fortbildung", "Semesterkosten", "Gruppenselbsterfahrung", "Theorie/Methodikseminare", "Peergruppensupervision", "Einzel-/Kleingruppensupervision", "Eigenständige Tätigkeit" ], "mediation" => [ "Präsenzmodul", "Selbsterfahrung", "Supervision", "Peergruppenarbeit", "Fallarbeit", "Praxisseminare", "Literatur- und Selbststudium", "Fortbildung", "Semesterkosten" ] }.freeze # ------------------------------------------------------------ # Mediation – zusätzliche Anforderungen # ------------------------------------------------------------ # Vorgabe des konkreten Lehrgangs MEDIATION_PRAESENZMODULE_TAGE = 19 # ZivMediat-AV: # Von den insgesamt 26 Supervisionseinheiten müssen mindestens # 3 Einheiten Einzelsupervision sein. MEDIATION_EINZELSUPERVISION_MINDESTENS = 3 after_initialize :set_default, if: :new_record? # ------------------------------------------------------------ # Allgemein # ------------------------------------------------------------ def praepedeutikum_abgeschlossen? praepedeutikum_done end def is_admin? email == "christoph@marzell.net" end def self.entry_arten_for(typ) ENTRY_ARTEN_BY_TYP[typ.to_s] || ENTRY_ARTEN end # ------------------------------------------------------------ # Matrizen aktualisieren # ------------------------------------------------------------ def update_required_matrices! required = (required_hours_matrix || {}).deep_stringify_keys weekly = (weekly_target_matrix || {}).deep_stringify_keys migrate_legacy_peer_group_key!( required, use_default_when_zero: true ) migrate_legacy_peer_group_key!( weekly, use_default_when_zero: false ) PRAKTIKUMSTYPEN.each do |typ| required[typ] ||= {} weekly[typ] ||= {} ENTRY_ARTEN.each do |art| unless required[typ].key?(art) required[typ][art] = default_hours_for(typ, art) end unless weekly[typ].key?(art) weekly[typ][art] = default_weekly_target_for(typ, art) end end end self.required_hours_matrix = required self.weekly_target_matrix = weekly save! end # ------------------------------------------------------------ # Default-Wochenziele # ------------------------------------------------------------ def default_weekly_target_for(typ, art) typ = typ.to_s art = canonical_entry_art(art) case [typ, art] when ["propädeutikum", "Praktikum"] 12 when ["fachspezifikum", "Praktikum"] 10 when ["propädeutikum", "Selbsterfahrung"], ["fachspezifikum", "Selbsterfahrung"], ["fachspezifikum", "Gruppenselbsterfahrung"] 0.25 when ["propädeutikum", "Supervision"], ["fachspezifikum", "Supervision"], ["fachspezifikum", "Peergruppensupervision"], ["fachspezifikum", "Einzel-/Kleingruppensupervision"] 0.25 when ["fachspezifikum", "Eigenständige Tätigkeit"] 10 # Mediation findet typischerweise blockweise statt. # Deshalb kein künstliches Wochenziel. when ["mediation", "Präsenzmodul"], ["mediation", "Selbsterfahrung"], ["mediation", "Supervision"], ["mediation", "Peergruppenarbeit"], ["mediation", "Fallarbeit"], ["mediation", "Praxisseminare"], ["mediation", "Literatur- und Selbststudium"] 0 else 0 end end # ------------------------------------------------------------ # Default-Sollstunden / Einheiten # ------------------------------------------------------------ def default_hours_for(typ, art) typ = typ.to_s art = canonical_entry_art(art) case [typ, art] # ---------------------------------------------------------- # Propädeutikum # ---------------------------------------------------------- when ["propädeutikum", "Praktikum"] 480 when ["propädeutikum", "Selbsterfahrung"] 50 when ["propädeutikum", "Supervision"] 20 # ---------------------------------------------------------- # Fachspezifikum # ---------------------------------------------------------- when ["fachspezifikum", "Praktikum"] 600 when ["fachspezifikum", "Selbsterfahrung"] 80 when ["fachspezifikum", "Supervision"] 40 when ["fachspezifikum", "Gruppenselbsterfahrung"] 64 when ["fachspezifikum", "Theorie/Methodikseminare"] 216 when ["fachspezifikum", "Peergruppensupervision"] 168 when ["fachspezifikum", "Einzel-/Kleingruppensupervision"] 40 when ["fachspezifikum", "Eigenständige Tätigkeit"] 600 # ---------------------------------------------------------- # Mediation # ---------------------------------------------------------- # Wird in Tagen und nicht in Stunden bewertet. when ["mediation", "Präsenzmodul"] 0 # ZivMediat-AV Anlage 1 when ["mediation", "Selbsterfahrung"] 40 when ["mediation", "Supervision"] 26 when ["mediation", "Peergruppenarbeit"] 24 when ["mediation", "Fallarbeit"] 17 when ["mediation", "Praxisseminare"] 58 # Zusätzliche Lehrgangsvorgabe when ["mediation", "Literatur- und Selbststudium"] 150 else 0 end end # ------------------------------------------------------------ # Sollwert aus persönlicher Matrix # ------------------------------------------------------------ def required_hours_for(typ, art) typ = typ.to_s art = canonical_entry_art(art) value = required_hours_matrix&.dig(typ, art) value.nil? ? default_hours_for(typ, art) : value end def weekly_target_for(typ, art) typ = typ.to_s art = canonical_entry_art(art) value = weekly_target_matrix&.dig(typ, art) value.nil? ? default_weekly_target_for(typ, art) : value end # ------------------------------------------------------------ # Mediation – Präsenztage # ------------------------------------------------------------ def mediation_praesenzmodule_required MEDIATION_PRAESENZMODULE_TAGE end def mediation_praesenzmodule_completed entries .where( praktikums_typ: "mediation", entry_art: "Präsenzmodul" ) .distinct .count(:date) end def mediation_praesenzmodule_remaining [ mediation_praesenzmodule_required - mediation_praesenzmodule_completed, 0 ].max end def mediation_praesenzmodule_completed? mediation_praesenzmodule_completed >= mediation_praesenzmodule_required end # ------------------------------------------------------------ # Mediation – besondere Vorgaben # ------------------------------------------------------------ def mediation_einzelsupervision_required MEDIATION_EINZELSUPERVISION_MINDESTENS end private # ------------------------------------------------------------ # Defaults für neuen User # ------------------------------------------------------------ def set_default self.required_hours_matrix ||= PRAKTIKUMSTYPEN.to_h do |typ| [ typ, ENTRY_ARTEN.to_h do |art| [art, default_hours_for(typ, art)] end ] end self.weekly_target_matrix ||= PRAKTIKUMSTYPEN.to_h do |typ| [ typ, ENTRY_ARTEN.to_h do |art| [art, default_weekly_target_for(typ, art)] end ] end end # ------------------------------------------------------------ # Alte Bezeichnungen normalisieren # ------------------------------------------------------------ def canonical_entry_art(art) case art.to_s when "Peergroup", "Peer-Gruppe" "Peergruppenarbeit" else art.to_s end end def migrate_legacy_peer_group_key!(matrix, use_default_when_zero:) PRAKTIKUMSTYPEN.each do |typ| values = matrix[typ] next unless values.is_a?(Hash) legacy_value = nil if values.key?("Peergroup") legacy_value = values.delete("Peergroup") end if values.key?("Peer-Gruppe") legacy_value ||= values.delete("Peer-Gruppe") end next if legacy_value.nil? next if values.key?("Peergruppenarbeit") if use_default_when_zero && typ == "mediation" && legacy_value.to_f.zero? values["Peergruppenarbeit"] = default_hours_for( "mediation", "Peergruppenarbeit" ) else values["Peergruppenarbeit"] = legacy_value end end end end