diff --git a/.gitignore b/.gitignore index 7b765bb..d5f3ef4 100644 --- a/.gitignore +++ b/.gitignore @@ -124,3 +124,5 @@ docker/test/db docker/development/media docker/production/media docker/test/media + +*.csv diff --git a/jdav_web/members/admin.py b/jdav_web/members/admin.py index c65e9d9..63f08e7 100644 --- a/jdav_web/members/admin.py +++ b/jdav_web/members/admin.py @@ -188,7 +188,8 @@ class MemberAdmin(CommonAdminMixin, admin.ModelAdmin): ), (_("Others"), { - 'fields': ['allergies', 'tetanus_vaccination', 'medication', 'photos_may_be_taken'] + 'fields': ['allergies', 'tetanus_vaccination', 'medication', 'photos_may_be_taken', + 'may_cancel_appointment_independently'] } ), (_("Organizational"), @@ -331,7 +332,7 @@ class MemberUnconfirmedAdmin(admin.ModelAdmin): { 'fields': [ ('good_conduct_certificate_presented_date', - 'good_conduct_certificate_presentation_needed'), + 'good_conduct_certificate_valid'), 'has_key', 'has_free_ticket_gym'] } ), @@ -339,7 +340,8 @@ class MemberUnconfirmedAdmin(admin.ModelAdmin): list_display = ('name', 'birth_date', 'age', 'get_group', 'confirmed_mail', 'confirmed_alternative_mail') search_fields = ('prename', 'lastname', 'email') list_filter = ('group', 'confirmed_mail', 'confirmed_alternative_mail') - readonly_fields = ['confirmed_mail', 'confirmed_alternative_mail'] + readonly_fields = ['confirmed_mail', 'confirmed_alternative_mail', + 'good_conduct_certificate_valid'] actions = ['request_mail_confirmation', 'confirm', 'demote_to_waiter'] inlines = [EmergencyContactInline] change_form_template = "members/change_member_unconfirmed.html" diff --git a/jdav_web/members/locale/de/LC_MESSAGES/django.po b/jdav_web/members/locale/de/LC_MESSAGES/django.po index 8fadeef..4190bf9 100644 --- a/jdav_web/members/locale/de/LC_MESSAGES/django.po +++ b/jdav_web/members/locale/de/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-11-17 22:30+0100\n" +"POT-Creation-Date: 2024-11-18 21:17+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -18,7 +18,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: members/admin.py:122 members/models.py:367 +#: members/admin.py:122 members/models.py:369 msgid "Registration complete" msgstr "Anmeldung vollständig" @@ -34,166 +34,166 @@ msgstr "Nein" msgid "All" msgstr "Alle" -#: members/admin.py:179 members/admin.py:315 +#: members/admin.py:179 members/admin.py:316 msgid "Contact information" msgstr "Kontaktinformationen" -#: members/admin.py:184 members/admin.py:320 +#: members/admin.py:184 members/admin.py:321 msgid "Skills" msgstr "Fähigkeiten" -#: members/admin.py:189 members/admin.py:325 +#: members/admin.py:189 members/admin.py:326 msgid "Others" msgstr "Sonstiges" -#: members/admin.py:194 members/admin.py:330 +#: members/admin.py:195 members/admin.py:331 msgid "Organizational" msgstr "Organisatorisches" -#: members/admin.py:257 +#: members/admin.py:258 msgid "Compose new mail to selected members" msgstr "Neue Nachricht an ausgewählte Teilnehmer verfassen" -#: members/admin.py:263 +#: members/admin.py:264 msgid "Echo required" msgstr "Rückmeldung erforderlich" -#: members/admin.py:265 +#: members/admin.py:266 msgid "Successfully requested echo from selected members." msgstr "" "Rückmeldungsaufforderung erfolgreich an ausgewählte Teilnehmer verschickt." -#: members/admin.py:266 +#: members/admin.py:267 msgid "Request echo from selected members" msgstr "Rückmeldungsaufforderung an ausgewählte Teilnehmer verschicken" -#: members/admin.py:283 +#: members/admin.py:284 msgid "activity" msgstr "Aktivität" -#: members/admin.py:293 members/models.py:53 members/models.py:1361 +#: members/admin.py:294 members/models.py:53 members/models.py:1363 msgid "Name" msgstr "Name" -#: members/admin.py:363 +#: members/admin.py:365 msgid "Successfully requested mail confirmation from selected registrations." msgstr "Aufforderung zur Bestätigung der Email Adresse versendet." -#: members/admin.py:364 +#: members/admin.py:366 msgid "Request mail confirmation from selected registrations" msgstr "Aufforderung zur Bestätigung der Email Adresse versenden" -#: members/admin.py:371 members/admin.py:405 +#: members/admin.py:373 members/admin.py:407 #, python-format msgid "Successfully confirmed %(name)s." msgstr "Registrierung von %(name)s erfolgreich bestätigt." -#: members/admin.py:375 members/admin.py:408 +#: members/admin.py:377 members/admin.py:410 #, python-format msgid "Can't confirm. %(name)s has unconfirmed email addresses." msgstr "Bestätigung nicht möglich. %(name)s hat unbestätigte Emailadressen." -#: members/admin.py:380 +#: members/admin.py:382 msgid "Successfully confirmed multiple registrations." msgstr "Erfolgreich mehrere Registrierungen bestätigt." -#: members/admin.py:382 +#: members/admin.py:384 msgid "" "Failed to confirm some registrations because of unconfirmed email addresses." msgstr "" "Einige Bestätigungen fehlgeschlagen, weil Emailadressen noch nicht bestätigt " "sind." -#: members/admin.py:383 +#: members/admin.py:385 msgid "Confirm selected registrations" msgstr "Ausgewählte Registrierungen bestätigen" -#: members/admin.py:399 +#: members/admin.py:401 #, python-format msgid "Successfully demoted %(name)s to waiter." msgstr "%(name)s zurück auf die Warteliste gesetzt." -#: members/admin.py:400 +#: members/admin.py:402 msgid "Demote selected registrations to waiters." msgstr "Ausgewählte Registrierungen zurück auf die Warteliste setzen." -#: members/admin.py:415 members/models.py:374 members/models.py:700 -#: members/models.py:1106 +#: members/admin.py:417 members/models.py:376 members/models.py:702 +#: members/models.py:1108 msgid "Group" msgstr "Gruppe" -#: members/admin.py:449 +#: members/admin.py:451 #, python-format msgid "Successfully asked %(name)s to confirm their waiting status." msgstr "Erfolgreich %(name)s aufgefordert den Wartelistenplatz zu bestätigen." -#: members/admin.py:450 +#: members/admin.py:452 msgid "Ask selected waiters to confirm their waiting status" msgstr "Wartende auffordern den Wartelistenplatz zu bestätigen" -#: members/admin.py:459 members/admin.py:515 +#: members/admin.py:461 members/admin.py:517 msgid "" "An error occurred while trying to invite said members. Please try again." msgstr "" "Beim Einladen dieser Personen ist ein Fehler aufgetreten. Bitte versuche es " "nochmal. " -#: members/admin.py:467 members/admin.py:522 +#: members/admin.py:469 members/admin.py:524 #, python-format msgid "Successfully invited %(name)s to %(group)s." msgstr "Erfolgreich %(name)s zu Gruppe %(group)s eingeladen." -#: members/admin.py:471 members/admin.py:527 +#: members/admin.py:473 members/admin.py:529 msgid "Select group for invitation" msgstr "Wähle Gruppe für Einladung aus" -#: members/admin.py:478 +#: members/admin.py:480 msgid "Offer waiter a place in a group." msgstr "Personen auf der Warteliste einen Gruppenplatz anbieten." -#: members/admin.py:568 +#: members/admin.py:570 msgid "Difficulty" msgstr "Schwierigkeit" -#: members/admin.py:571 +#: members/admin.py:573 msgid "Tour type" msgstr "Art der Tour" -#: members/admin.py:574 members/models.py:916 +#: members/admin.py:576 members/models.py:918 msgid "Means of transportation" msgstr "Verkehrsmittel" -#: members/admin.py:669 +#: members/admin.py:671 #, python-format msgid "You are not allowed to view all members on note list %(name)s." msgstr "" "Du hast nicht die nötigen Rechte um alle Teilnehmer:innen der Notizliste " "%(name)s anzusehen." -#: members/admin.py:679 +#: members/admin.py:681 msgid "Generate PDF summary" msgstr "Übersicht erstellen" -#: members/admin.py:717 +#: members/admin.py:719 #, python-format msgid "You are not allowed to view all members on excursion %(name)s." msgstr "" "Du hast nicht die nötigen Rechte um alle Teilnehmer:innen der Ausfahrt " "%(name)s anzusehen." -#: members/admin.py:727 +#: members/admin.py:729 msgid "Generate crisis intervention list" msgstr "Kriseninterventionsliste erstellen" -#: members/admin.py:737 +#: members/admin.py:739 msgid "Generate overview" msgstr "Hinweise für Jugendleiter erstellen" -#: members/admin.py:747 +#: members/admin.py:749 msgid "Generate seminar report" msgstr "Seminarbericht erstellen" -#: members/admin.py:761 +#: members/admin.py:763 msgid "Generate SJR application" msgstr "SJR Antrag erstellen" @@ -229,11 +229,11 @@ msgstr "Samstag" msgid "Sunday" msgstr "Sonntag" -#: members/models.py:54 members/models.py:902 +#: members/models.py:54 members/models.py:904 msgid "Description" msgstr "Beschreibung" -#: members/models.py:60 members/models.py:894 +#: members/models.py:60 members/models.py:896 #: members/templates/members/change_member.html:18 msgid "Activity" msgstr "Aktivität" @@ -266,7 +266,7 @@ msgstr "Bis Jahrgang" msgid "youth leaders" msgstr "Jugendleiter" -#: members/models.py:77 members/models.py:1188 +#: members/models.py:77 members/models.py:1190 msgid "Starting time" msgstr "Zeitpunkt" @@ -274,7 +274,7 @@ msgstr "Zeitpunkt" msgid "Ending time" msgstr "Endzeitpunkt" -#: members/models.py:85 members/models.py:245 +#: members/models.py:85 members/models.py:247 msgid "group" msgstr "Gruppe" @@ -339,425 +339,425 @@ msgid "Country" msgstr "Land" #: members/models.py:229 -msgid "Good conduct certificate presentation needed" -msgstr "Vorlage Führungszeugnis notwendig" - -#: members/models.py:230 msgid "Good conduct certificate presented on" msgstr "Führungszeugnis vorgelegt am" -#: members/models.py:231 +#: members/models.py:230 msgid "Joined on" msgstr "Eintritt" -#: members/models.py:232 +#: members/models.py:231 msgid "Left on" msgstr "Austritt" -#: members/models.py:233 +#: members/models.py:232 msgid "Has key" msgstr "Hat Jugendraumschlüssel" -#: members/models.py:234 +#: members/models.py:233 msgid "Has a free ticket for the climbing gym" msgstr "Hat Freikarte für Kletterhalle" -#: members/models.py:235 +#: members/models.py:234 msgid "DAV badge number" msgstr "DAV Mitgliedsnummer" -#: members/models.py:236 +#: members/models.py:235 msgid "Knows how to swim" msgstr "Kann schwimmen" -#: members/models.py:237 +#: members/models.py:236 msgid "Climbing badge" msgstr "Kletterschein" -#: members/models.py:238 +#: members/models.py:237 msgid "Alpine experience" msgstr "Alpine Erfahrung" -#: members/models.py:239 +#: members/models.py:238 msgid "Allergies" msgstr "Allergieen" -#: members/models.py:240 +#: members/models.py:239 msgid "Medication" msgstr "Medikamente" -#: members/models.py:241 +#: members/models.py:240 msgid "Tetanus vaccination" msgstr "Tetanusimpfung" -#: members/models.py:242 +#: members/models.py:241 msgid "Photos may be taken" msgstr "Fotoerlaubnis" -#: members/models.py:243 +#: members/models.py:242 msgid "Legal guardians" msgstr "Erziehungsberechtigte" -#: members/models.py:249 +#: members/models.py:244 +msgid "May cancel a group appointment independently" +msgstr "Darf sich allein von der Gruppenstunde abmelden" + +#: members/models.py:251 msgid "receives newsletter" msgstr "Erhält den Newsletter" -#: members/models.py:253 +#: members/models.py:255 msgid "created" msgstr "erstellt" -#: members/models.py:254 +#: members/models.py:256 msgid "Active" msgstr "Aktiv" -#: members/models.py:255 +#: members/models.py:257 msgid "registration form" msgstr "Anmeldeformular" -#: members/models.py:263 +#: members/models.py:265 msgid "image" msgstr "Bild" -#: members/models.py:272 +#: members/models.py:274 msgid "Echoed" msgstr "Rückgemeldet" -#: members/models.py:273 +#: members/models.py:275 msgid "Confirmed" msgstr "Bestätigt" -#: members/models.py:303 +#: members/models.py:305 msgid "Good conduct certificate valid" msgstr "Führungszeugnis gültig" -#: members/models.py:377 +#: members/models.py:379 msgid "member" msgstr "Teilnehmer" -#: members/models.py:378 +#: members/models.py:380 msgid "members" msgstr "Teilnehmer" -#: members/models.py:450 +#: members/models.py:452 #, python-format msgid "New unconfirmed registration for group %(group)s" msgstr "Neue unbestätigte Registrierung für Gruppe %(group)s" -#: members/models.py:657 members/models.py:850 members/models.py:861 -#: members/models.py:1137 members/models.py:1144 +#: members/models.py:659 members/models.py:852 members/models.py:863 +#: members/models.py:1139 members/models.py:1146 msgid "Member" msgstr "Teilnehmer" -#: members/models.py:663 +#: members/models.py:665 msgid "Emergency contact" msgstr "Notfallkontakt" -#: members/models.py:664 +#: members/models.py:666 msgid "Emergency contacts" msgstr "Notfallkontakte" -#: members/models.py:684 +#: members/models.py:686 msgid "Unconfirmed registration" msgstr "Unbestätigte Registrierung" -#: members/models.py:685 +#: members/models.py:687 msgid "Unconfirmed registrations" msgstr "Unbestätigte Registrierungen" -#: members/models.py:699 members/models.py:744 +#: members/models.py:701 members/models.py:746 msgid "Waiter" msgstr "Wartende Person" -#: members/models.py:701 +#: members/models.py:703 msgid "Invitation date" msgstr "Einladungsdatum" -#: members/models.py:702 members/templates/members/reject_success.html:6 +#: members/models.py:704 members/templates/members/reject_success.html:6 #: members/templates/members/reject_success.html:11 msgid "Invitation rejected" msgstr "Einladung abgelehnt" -#: members/models.py:706 +#: members/models.py:708 msgid "Invitation to group" msgstr "Gruppeneinladung" -#: members/models.py:707 +#: members/models.py:709 msgid "Invitations to groups" msgstr "Gruppeneinladungen" -#: members/models.py:714 +#: members/models.py:716 msgid "Rejected" msgstr "Abgelehnt" -#: members/models.py:716 +#: members/models.py:718 msgid "Expired" msgstr "Abgelaufen" -#: members/models.py:718 +#: members/models.py:720 msgid "Undecided" msgstr "Ausstehend" -#: members/models.py:719 +#: members/models.py:721 msgid "Status" msgstr "Status" -#: members/models.py:730 +#: members/models.py:732 msgid "Do you want to tell us something else?" msgstr "Möchtest du uns noch etwas mitteilen?" -#: members/models.py:731 +#: members/models.py:733 msgid "application date" msgstr "Bewerbungsdatum" -#: members/models.py:733 +#: members/models.py:735 msgid "Last wait confirmation" msgstr "Letzte Wartebestätigung" -#: members/models.py:737 +#: members/models.py:739 msgid "Last reminder" msgstr "Letzte Erinnerung" -#: members/models.py:738 +#: members/models.py:740 msgid "Missed reminders" msgstr "Verpasste Erinnerungen" -#: members/models.py:745 +#: members/models.py:747 msgid "Waiters" msgstr "Warteliste" -#: members/models.py:769 +#: members/models.py:771 msgid "Waiting status confirmed" msgstr "Wartelistenplatz bestätigt" -#: members/models.py:776 +#: members/models.py:778 msgid "Waiting confirmation needed" msgstr "Wartelistenplatzbestätigung erforderlich" -#: members/models.py:829 +#: members/models.py:831 msgid "Invitation to trial group meeting" msgstr "Einladung zu Schnupperstunde" -#: members/models.py:841 +#: members/models.py:843 msgid "Unregistered from waiting list" msgstr "Von der Warteliste abgemeldet" -#: members/models.py:855 +#: members/models.py:857 msgid "Comment" msgstr "Kommentar" -#: members/models.py:862 members/models.py:1145 +#: members/models.py:864 members/models.py:1147 msgid "Members" msgstr "Teilnehmer" -#: members/models.py:896 +#: members/models.py:898 msgid "Place" msgstr "Stützpunkt / Ort" -#: members/models.py:897 +#: members/models.py:899 msgid "Destination (optional)" msgstr "ggf. Ziel" -#: members/models.py:899 +#: members/models.py:901 msgid "e.g. a peak" msgstr "z.B. ein Gipfel" -#: members/models.py:900 +#: members/models.py:902 msgid "Begin" msgstr "Anfang" -#: members/models.py:901 +#: members/models.py:903 msgid "End (optional)" msgstr "Ende" -#: members/models.py:904 +#: members/models.py:906 msgid "Groups" msgstr "Gruppen" -#: members/models.py:917 +#: members/models.py:919 msgid "Kilometers traveled" msgstr "Fahrstrecke in Kilometer" -#: members/models.py:920 +#: members/models.py:922 msgid "Categories" msgstr "Kategorien" -#: members/models.py:921 +#: members/models.py:923 msgid "easy" msgstr "leicht" -#: members/models.py:921 +#: members/models.py:923 msgid "medium" msgstr "mittel" -#: members/models.py:921 +#: members/models.py:923 msgid "hard" msgstr "schwer" -#: members/models.py:931 members/models.py:1168 +#: members/models.py:933 members/models.py:1170 msgid "Excursion" msgstr "Ausfahrt" -#: members/models.py:932 +#: members/models.py:934 msgid "Excursions" msgstr "Ausfahrten" -#: members/models.py:1083 members/models.py:1159 members/models.py:1375 +#: members/models.py:1085 members/models.py:1161 members/models.py:1377 msgid "Title" msgstr "Titel" -#: members/models.py:1084 members/models.py:1102 members/models.py:1376 +#: members/models.py:1086 members/models.py:1104 members/models.py:1378 msgid "Date" msgstr "Datum" -#: members/models.py:1103 +#: members/models.py:1105 msgid "Location" msgstr "Ort" -#: members/models.py:1104 +#: members/models.py:1106 msgid "Topic" msgstr "Thema" -#: members/models.py:1128 +#: members/models.py:1130 msgid "Jugendleiter" msgstr "Jugendleiter" -#: members/models.py:1131 +#: members/models.py:1133 msgid "Klettertreff" msgstr "Klettertreff" -#: members/models.py:1132 +#: members/models.py:1134 msgid "Klettertreffs" msgstr "Klettertreffs" -#: members/models.py:1150 +#: members/models.py:1152 msgid "Password" msgstr "Passwort" -#: members/models.py:1153 +#: members/models.py:1155 msgid "registration password" msgstr "Registrierungspassort" -#: members/models.py:1154 +#: members/models.py:1156 msgid "registration passwords" msgstr "Registrierungspasswörter" -#: members/models.py:1161 +#: members/models.py:1163 msgid "Alpinistic goals" msgstr "Alpintechnische Ziele" -#: members/models.py:1162 +#: members/models.py:1164 msgid "Pedagogic goals" msgstr "Pädagogische Ziele" -#: members/models.py:1163 +#: members/models.py:1165 msgid "Content and methods" msgstr "Inhalte und Methoden" -#: members/models.py:1164 +#: members/models.py:1166 msgid "Evaluation" msgstr "Wertung" -#: members/models.py:1165 +#: members/models.py:1167 msgid "Experiences and possible improvements" msgstr "Erfahrungen und Verbesserungsvorschläge" -#: members/models.py:1174 members/models.py:1195 +#: members/models.py:1176 members/models.py:1197 msgid "LJP Proposal" msgstr "Seminarbericht" -#: members/models.py:1175 +#: members/models.py:1177 msgid "LJP Proposals" msgstr "Seminarberichte" -#: members/models.py:1189 +#: members/models.py:1191 msgid "Duration in hours" msgstr "Dauer in Stunden" -#: members/models.py:1192 +#: members/models.py:1194 msgid "Activity and method" msgstr "Art der Aktion inkl. Methode" -#: members/models.py:1200 +#: members/models.py:1202 msgid "Intervention" msgstr "Aktion" -#: members/models.py:1201 +#: members/models.py:1203 msgid "Interventions" msgstr "Aktionen" -#: members/models.py:1303 members/models.py:1333 +#: members/models.py:1305 members/models.py:1335 msgid "May list members" msgstr "Darf folgende Teilnehmer:innen listen" -#: members/models.py:1305 members/models.py:1335 +#: members/models.py:1307 members/models.py:1337 msgid "May view members" msgstr "Darf folgende Teilnehmer:innen anzeigen" -#: members/models.py:1307 members/models.py:1337 +#: members/models.py:1309 members/models.py:1339 msgid "May change members" msgstr "Darf folgende Teilnehmer:innen ändern" -#: members/models.py:1309 members/models.py:1339 +#: members/models.py:1311 members/models.py:1341 msgid "May delete members" msgstr "Darf folgende Teilnehmer:innen löschen" -#: members/models.py:1313 members/models.py:1343 +#: members/models.py:1315 members/models.py:1345 msgid "May list members of groups" msgstr "Darf Teilnehmer:innen folgender Gruppen listen" -#: members/models.py:1315 members/models.py:1345 +#: members/models.py:1317 members/models.py:1347 msgid "May view members of groups" msgstr "Darf Teilnehmer:innen folgender Gruppen anzeigen" -#: members/models.py:1317 members/models.py:1347 +#: members/models.py:1319 members/models.py:1349 msgid "May change members of groups" msgstr "Darf Teilnehmer:innen folgender Gruppen ändern" -#: members/models.py:1319 members/models.py:1349 +#: members/models.py:1321 members/models.py:1351 msgid "May delete members of groups" msgstr "Darf Teilnehmer:innen folgender Gruppen löschen" -#: members/models.py:1322 members/models.py:1323 members/models.py:1326 +#: members/models.py:1324 members/models.py:1325 members/models.py:1328 msgid "Permissions" msgstr "Berechtigungen" -#: members/models.py:1352 members/models.py:1353 members/models.py:1356 +#: members/models.py:1354 members/models.py:1355 members/models.py:1358 msgid "Group permissions" msgstr "Gruppenberechtigungen" -#: members/models.py:1362 +#: members/models.py:1364 msgid "Permission needed" msgstr "Freigabe erforderlich" -#: members/models.py:1365 +#: members/models.py:1367 msgid "Training category" msgstr "Fortbildungstyp" -#: members/models.py:1366 +#: members/models.py:1368 msgid "Training categories" msgstr "Fortbildungstypen" -#: members/models.py:1377 +#: members/models.py:1379 msgid "Category" msgstr "Kategorien" -#: members/models.py:1378 +#: members/models.py:1380 msgid "Comments" msgstr "Kommentar" -#: members/models.py:1379 +#: members/models.py:1381 msgid "Participated" msgstr "Teilgenommmen" -#: members/models.py:1380 +#: members/models.py:1382 msgid "Passed" msgstr "Bestanden" -#: members/models.py:1383 +#: members/models.py:1385 msgid "Training" msgstr "Fortbildung" -#: members/models.py:1384 +#: members/models.py:1386 msgid "Trainings" msgstr "Fortbildungen" @@ -1193,6 +1193,9 @@ msgstr "abgelaufen" msgid "Invalid emergency contacts" msgstr "Ungültige Notfallkontakte" +#~ msgid "Good conduct certificate presentation needed" +#~ msgstr "Vorlage Führungszeugnis notwendig" + #, python-format #~ msgid "" #~ "Do you want to reject the invitation to a trial group meeting of the\n" diff --git a/jdav_web/members/migrations/0022_adapt_fields.py b/jdav_web/members/migrations/0022_adapt_fields.py new file mode 100644 index 0000000..ad9ea38 --- /dev/null +++ b/jdav_web/members/migrations/0022_adapt_fields.py @@ -0,0 +1,43 @@ +# Generated by Django 4.0.1 on 2024-11-18 20:29 + +from django.db import migrations, models +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('members', '0021_group_invitations'), + ] + + operations = [ + migrations.RemoveField( + model_name='member', + name='good_conduct_certificate_presentation_needed', + ), + migrations.AlterField( + model_name='member', + name='allergies', + field=models.TextField(blank=True, default='', verbose_name='Allergies'), + ), + migrations.AlterField( + model_name='member', + name='medication', + field=models.TextField(blank=True, default='', verbose_name='Medication'), + ), + migrations.AddField( + model_name='member', + name='may_cancel_appointment_independently', + field=models.BooleanField(blank=True, default=None, null=True, verbose_name='May cancel a group appointment independently'), + ), + migrations.AlterField( + model_name='member', + name='phone_number', + field=models.CharField(blank=True, default='', max_length=100, verbose_name='phone number'), + ), + migrations.AlterField( + model_name='memberwaitinglist', + name='application_date', + field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='application date'), + ), + ] diff --git a/jdav_web/members/models.py b/jdav_web/members/models.py index 8504ea7..123d398 100644 --- a/jdav_web/members/models.py +++ b/jdav_web/members/models.py @@ -218,7 +218,7 @@ class Member(Person): verbose_name=_('Alternative email confirmed')) confirm_alternative_mail_key = models.CharField(max_length=32, default="") - phone_number = models.CharField(max_length=100, verbose_name=_('phone number')) + phone_number = models.CharField(max_length=100, verbose_name=_('phone number'), default='', blank=True) street = models.CharField(max_length=30, verbose_name=_('street and house number'), default='', blank=True) plz = models.CharField(max_length=10, verbose_name=_('Postcode'), default='', blank=True) @@ -226,7 +226,6 @@ class Member(Person): address_extra = models.CharField(max_length=100, verbose_name=_('Address extra'), default='', blank=True) country = models.CharField(max_length=30, verbose_name=_('Country'), default='', blank=True) - good_conduct_certificate_presentation_needed = models.BooleanField(_('Good conduct certificate presentation needed'), default=False) good_conduct_certificate_presented_date = models.DateField(_('Good conduct certificate presented on'), default=None, blank=True, null=True) join_date = models.DateField(_('Joined on'), default=None, blank=True, null=True) leave_date = models.DateField(_('Left on'), default=None, blank=True, null=True) @@ -236,11 +235,14 @@ class Member(Person): swimming_badge = models.BooleanField(verbose_name=_('Knows how to swim'), default=False) climbing_badge = models.CharField(max_length=100, verbose_name=_('Climbing badge'), default='', blank=True) alpine_experience = models.TextField(verbose_name=_('Alpine experience'), default='', blank=True) - allergies = models.CharField(max_length=100, verbose_name=_('Allergies'), default='', blank=True) - medication = models.CharField(max_length=100, verbose_name=_('Medication'), default='', blank=True) + allergies = models.TextField(verbose_name=_('Allergies'), default='', blank=True) + medication = models.TextField(verbose_name=_('Medication'), default='', blank=True) tetanus_vaccination = models.CharField(max_length=50, verbose_name=_('Tetanus vaccination'), default='', blank=True) photos_may_be_taken = models.BooleanField(verbose_name=_('Photos may be taken'), default=False) legal_guardians = models.CharField(max_length=100, verbose_name=_('Legal guardians'), default='', blank=True) + may_cancel_appointment_independently =\ + models.BooleanField(verbose_name=_('May cancel a group appointment independently'), null=True, + blank=True, default=None) group = models.ManyToManyField(Group, verbose_name=_('group')) @@ -728,7 +730,7 @@ class MemberWaitingList(Person): WAITING_CONFIRMED = 2 application_text = models.TextField(_('Do you want to tell us something else?'), default='', blank=True) - application_date = models.DateTimeField(verbose_name=_('application date'), auto_now=True) + application_date = models.DateTimeField(verbose_name=_('application date'), default=timezone.now) last_wait_confirmation = models.DateField(auto_now=True, verbose_name=_('Last wait confirmation')) wait_confirmation_key = models.CharField(max_length=32, default="") @@ -1391,7 +1393,6 @@ class MemberTraining(CommonModel): } - def import_from_csv(path): with open(path, encoding='ISO-8859-1') as csvfile: reader = csv.DictReader(csvfile, delimiter=';') @@ -1406,7 +1407,7 @@ def import_from_csv(path): def transform_row(row): kwargs = dict([ transform_field(k, v) for k, v in row.items() if k in CLUBDESK_TO_KOMPASS ]) - kwargs_filtered = { k : v for k, v in kwargs.items() if k not in ['group', 'last_training', 'has_fundamental_training', 'special_training'] } + kwargs_filtered = { k : v for k, v in kwargs.items() if k not in ['group', 'last_training', 'has_fundamental_training', 'special_training', 'phone_number_private', 'phone_number_parents'] } mem = Member(**kwargs_filtered) mem.save() mem.group.set(kwargs['group']) @@ -1441,6 +1442,16 @@ def import_from_csv(path): participated=True, passed=True) training.save() + if kwargs['phone_number_private'] != '': + prefix = '\n' if mem.comments else '' + mem.comments += prefix + 'Telefon (Privat): ' + kwargs['phone_number_private'] + mem.save() + + if kwargs['phone_number_parents'] != '': + prefix = '\n' if mem.comments else '' + mem.comments += prefix + 'Telefon (Eltern): ' + kwargs['phone_number_parents'] + mem.save() + for row in rows: transform_row(row) @@ -1492,6 +1503,26 @@ def parse_boolean(value): return value.lower() == "ja" +def parse_nullable_boolean(value): + if value == '': + return None + else: + return value.lower() == "ja" + + +def parse_gender(value): + if value == 'männlich': + return MALE + elif value == 'weiblich': + return FEMALE + else: + return DIVERSE + + +def parse_can_swim(value): + return True if len(value) > 0 else False + + CLUBDESK_TO_KOMPASS = { 'Nachname': 'lastname', 'Vorname': 'prename', @@ -1499,10 +1530,9 @@ CLUBDESK_TO_KOMPASS = { 'PLZ': 'plz', 'Ort': 'town', 'Telefon Privat': 'phone_number_private', - 'Telefon Mobil': 'phone_number_mobile', + 'Telefon Mobil': 'phone_number', 'Adress-Zusatz': 'address_extra', 'Land': 'country', - 'Nationalität': 'nationality', 'E-Mail': 'email', 'E-Mail Alternativ': 'alternative_email', 'Status': ('active', parse_status), @@ -1510,10 +1540,10 @@ CLUBDESK_TO_KOMPASS = { 'Austritt': ('leave_date', parse_date), 'Geburtsdatum': ('birth_date', parse_date), 'Geburtstag': ('birth_date', parse_date), + 'Geschlecht': ('gender', parse_gender), 'Bemerkungen': 'comments', 'IBAN': 'iban', 'Vorlage Führungszeugnis': ('good_conduct_certificate_presented_date', parse_date), - 'Vorlage Führungszeugnis notwendig': ('good_conduct_certificate_presentation_needed', parse_boolean), 'Letzte Fortbildung': ('last_training', parse_date), 'Grundausbildung': ('has_fundamental_training', parse_boolean), 'Besondere Ausbildung': 'special_training', @@ -1521,7 +1551,7 @@ CLUBDESK_TO_KOMPASS = { 'Schlüssel': ('has_key', parse_boolean), 'Freikarte': ('has_free_ticket_gym', parse_boolean), 'DAV Ausweis Nr.': 'dav_badge_no', - 'Schwimmabzeichen': 'swimming_badge', + 'Schwimmabzeichen': ('swimming_badge', parse_can_swim), 'Kletterschein': 'climbing_badge', 'Felserfahrung': 'alpine_experience', 'Allergien': 'allergies', @@ -1529,9 +1559,13 @@ CLUBDESK_TO_KOMPASS = { 'Tetanusimpfung': 'tetanus_vaccination', 'Fotoerlaubnis': ('photos_may_be_taken', parse_boolean), 'Erziehungsberechtigte': 'legal_guardians', + 'Darf sich allein von der Gruppenstunde abmelden': + ('may_cancel_appointment_independently', parse_nullable_boolean), 'Mobil Eltern': 'phone_number_parents', 'Sonstiges': 'application_text', 'Erhalten am': ('application_date', parse_datetime), + 'Angeschrieben von': 'contacted_by', + 'Angeschrieben von ': 'contacted_by', } @@ -1557,8 +1591,18 @@ def import_from_csv_waitinglist(path): def transform_row(row): kwargs = dict([ transform_field(k, v) for k, v in row.items() if k in CLUBDESK_TO_KOMPASS ]) kwargs_filtered = { k : v for k, v in kwargs.items() if k in ['prename', 'lastname', 'email', 'birth_date', 'application_text', 'application_date'] } + mem = MemberWaitingList(**kwargs_filtered) mem.save() + if kwargs['contacted_by']: + group_name = kwargs['contacted_by'] + try: + group = Group.objects.get(name=group_name) + invitation = InvitationToGroup(group=group, waiter=mem) + invitation.save() + except Group.DoesNotExist: + pass + for row in rows: transform_row(row)