Skip to content

Commit e4f2d42

Browse files
added new pupil identity fields (WIP), fixed automatic uml svg generation in the assets folder
1 parent 20bca42 commit e4f2d42

24 files changed

Lines changed: 359 additions & 125 deletions

File tree

docs/model_relations/school_data_hub_server.svg

Lines changed: 1 addition & 1 deletion
Loading

school_data_hub_client/lib/src/protocol/_features/pupil/models/pupil_identity/pupil_identity.dart

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,12 @@ abstract class PupilIdentity implements _i1.SerializableModel {
2020
required this.lastName,
2121
required this.group,
2222
required this.groupTutor,
23+
this.deputyGroupTutor,
2324
required this.schoolGrade,
2425
this.specialNeeds,
2526
required this.gender,
2627
required this.language,
28+
this.nationality,
2729
this.family,
2830
required this.birthday,
2931
this.migrationSupportEnds,
@@ -34,6 +36,7 @@ abstract class PupilIdentity implements _i1.SerializableModel {
3436
this.religionLessonsCancelledAt,
3537
this.familyLanguageLessonsSince,
3638
this.leavingDate,
39+
this.schoolTransitionRecommendation,
3740
});
3841

3942
factory PupilIdentity({
@@ -42,10 +45,12 @@ abstract class PupilIdentity implements _i1.SerializableModel {
4245
required String lastName,
4346
required String group,
4447
required String groupTutor,
48+
String? deputyGroupTutor,
4549
required _i2.SchoolGrade schoolGrade,
46-
String? specialNeeds,
50+
List<String>? specialNeeds,
4751
required String gender,
4852
required String language,
53+
String? nationality,
4954
String? family,
5055
required DateTime birthday,
5156
DateTime? migrationSupportEnds,
@@ -56,6 +61,7 @@ abstract class PupilIdentity implements _i1.SerializableModel {
5661
DateTime? religionLessonsCancelledAt,
5762
DateTime? familyLanguageLessonsSince,
5863
DateTime? leavingDate,
64+
String? schoolTransitionRecommendation,
5965
}) = _PupilIdentityImpl;
6066

6167
factory PupilIdentity.fromJson(Map<String, dynamic> jsonSerialization) {
@@ -65,11 +71,15 @@ abstract class PupilIdentity implements _i1.SerializableModel {
6571
lastName: jsonSerialization['lastName'] as String,
6672
group: jsonSerialization['group'] as String,
6773
groupTutor: jsonSerialization['groupTutor'] as String,
74+
deputyGroupTutor: jsonSerialization['deputyGroupTutor'] as String?,
6875
schoolGrade: _i2.SchoolGrade.fromJson(
6976
(jsonSerialization['schoolGrade'] as String)),
70-
specialNeeds: jsonSerialization['specialNeeds'] as String?,
77+
specialNeeds: (jsonSerialization['specialNeeds'] as List?)
78+
?.map((e) => e as String)
79+
.toList(),
7180
gender: jsonSerialization['gender'] as String,
7281
language: jsonSerialization['language'] as String,
82+
nationality: jsonSerialization['nationality'] as String?,
7383
family: jsonSerialization['family'] as String?,
7484
birthday:
7585
_i1.DateTimeJsonExtension.fromJson(jsonSerialization['birthday']),
@@ -99,6 +109,8 @@ abstract class PupilIdentity implements _i1.SerializableModel {
99109
? null
100110
: _i1.DateTimeJsonExtension.fromJson(
101111
jsonSerialization['leavingDate']),
112+
schoolTransitionRecommendation:
113+
jsonSerialization['schoolTransitionRecommendation'] as String?,
102114
);
103115
}
104116

@@ -112,14 +124,18 @@ abstract class PupilIdentity implements _i1.SerializableModel {
112124

113125
String groupTutor;
114126

127+
String? deputyGroupTutor;
128+
115129
_i2.SchoolGrade schoolGrade;
116130

117-
String? specialNeeds;
131+
List<String>? specialNeeds;
118132

119133
String gender;
120134

121135
String language;
122136

137+
String? nationality;
138+
123139
String? family;
124140

125141
DateTime birthday;
@@ -140,6 +156,8 @@ abstract class PupilIdentity implements _i1.SerializableModel {
140156

141157
DateTime? leavingDate;
142158

159+
String? schoolTransitionRecommendation;
160+
143161
/// Returns a shallow copy of this [PupilIdentity]
144162
/// with some or all fields replaced by the given arguments.
145163
@_i1.useResult
@@ -149,10 +167,12 @@ abstract class PupilIdentity implements _i1.SerializableModel {
149167
String? lastName,
150168
String? group,
151169
String? groupTutor,
170+
String? deputyGroupTutor,
152171
_i2.SchoolGrade? schoolGrade,
153-
String? specialNeeds,
172+
List<String>? specialNeeds,
154173
String? gender,
155174
String? language,
175+
String? nationality,
156176
String? family,
157177
DateTime? birthday,
158178
DateTime? migrationSupportEnds,
@@ -163,6 +183,7 @@ abstract class PupilIdentity implements _i1.SerializableModel {
163183
DateTime? religionLessonsCancelledAt,
164184
DateTime? familyLanguageLessonsSince,
165185
DateTime? leavingDate,
186+
String? schoolTransitionRecommendation,
166187
});
167188
@override
168189
Map<String, dynamic> toJson() {
@@ -172,10 +193,12 @@ abstract class PupilIdentity implements _i1.SerializableModel {
172193
'lastName': lastName,
173194
'group': group,
174195
'groupTutor': groupTutor,
196+
if (deputyGroupTutor != null) 'deputyGroupTutor': deputyGroupTutor,
175197
'schoolGrade': schoolGrade.toJson(),
176-
if (specialNeeds != null) 'specialNeeds': specialNeeds,
198+
if (specialNeeds != null) 'specialNeeds': specialNeeds?.toJson(),
177199
'gender': gender,
178200
'language': language,
201+
if (nationality != null) 'nationality': nationality,
179202
if (family != null) 'family': family,
180203
'birthday': birthday.toJson(),
181204
if (migrationSupportEnds != null)
@@ -190,6 +213,8 @@ abstract class PupilIdentity implements _i1.SerializableModel {
190213
if (familyLanguageLessonsSince != null)
191214
'familyLanguageLessonsSince': familyLanguageLessonsSince?.toJson(),
192215
if (leavingDate != null) 'leavingDate': leavingDate?.toJson(),
216+
if (schoolTransitionRecommendation != null)
217+
'schoolTransitionRecommendation': schoolTransitionRecommendation,
193218
};
194219
}
195220

@@ -208,10 +233,12 @@ class _PupilIdentityImpl extends PupilIdentity {
208233
required String lastName,
209234
required String group,
210235
required String groupTutor,
236+
String? deputyGroupTutor,
211237
required _i2.SchoolGrade schoolGrade,
212-
String? specialNeeds,
238+
List<String>? specialNeeds,
213239
required String gender,
214240
required String language,
241+
String? nationality,
215242
String? family,
216243
required DateTime birthday,
217244
DateTime? migrationSupportEnds,
@@ -222,16 +249,19 @@ class _PupilIdentityImpl extends PupilIdentity {
222249
DateTime? religionLessonsCancelledAt,
223250
DateTime? familyLanguageLessonsSince,
224251
DateTime? leavingDate,
252+
String? schoolTransitionRecommendation,
225253
}) : super._(
226254
id: id,
227255
firstName: firstName,
228256
lastName: lastName,
229257
group: group,
230258
groupTutor: groupTutor,
259+
deputyGroupTutor: deputyGroupTutor,
231260
schoolGrade: schoolGrade,
232261
specialNeeds: specialNeeds,
233262
gender: gender,
234263
language: language,
264+
nationality: nationality,
235265
family: family,
236266
birthday: birthday,
237267
migrationSupportEnds: migrationSupportEnds,
@@ -242,6 +272,7 @@ class _PupilIdentityImpl extends PupilIdentity {
242272
religionLessonsCancelledAt: religionLessonsCancelledAt,
243273
familyLanguageLessonsSince: familyLanguageLessonsSince,
244274
leavingDate: leavingDate,
275+
schoolTransitionRecommendation: schoolTransitionRecommendation,
245276
);
246277

247278
/// Returns a shallow copy of this [PupilIdentity]
@@ -254,10 +285,12 @@ class _PupilIdentityImpl extends PupilIdentity {
254285
String? lastName,
255286
String? group,
256287
String? groupTutor,
288+
Object? deputyGroupTutor = _Undefined,
257289
_i2.SchoolGrade? schoolGrade,
258290
Object? specialNeeds = _Undefined,
259291
String? gender,
260292
String? language,
293+
Object? nationality = _Undefined,
261294
Object? family = _Undefined,
262295
DateTime? birthday,
263296
Object? migrationSupportEnds = _Undefined,
@@ -268,17 +301,24 @@ class _PupilIdentityImpl extends PupilIdentity {
268301
Object? religionLessonsCancelledAt = _Undefined,
269302
Object? familyLanguageLessonsSince = _Undefined,
270303
Object? leavingDate = _Undefined,
304+
Object? schoolTransitionRecommendation = _Undefined,
271305
}) {
272306
return PupilIdentity(
273307
id: id ?? this.id,
274308
firstName: firstName ?? this.firstName,
275309
lastName: lastName ?? this.lastName,
276310
group: group ?? this.group,
277311
groupTutor: groupTutor ?? this.groupTutor,
312+
deputyGroupTutor: deputyGroupTutor is String?
313+
? deputyGroupTutor
314+
: this.deputyGroupTutor,
278315
schoolGrade: schoolGrade ?? this.schoolGrade,
279-
specialNeeds: specialNeeds is String? ? specialNeeds : this.specialNeeds,
316+
specialNeeds: specialNeeds is List<String>?
317+
? specialNeeds
318+
: this.specialNeeds?.map((e0) => e0).toList(),
280319
gender: gender ?? this.gender,
281320
language: language ?? this.language,
321+
nationality: nationality is String? ? nationality : this.nationality,
282322
family: family is String? ? family : this.family,
283323
birthday: birthday ?? this.birthday,
284324
migrationSupportEnds: migrationSupportEnds is DateTime?
@@ -297,6 +337,9 @@ class _PupilIdentityImpl extends PupilIdentity {
297337
? familyLanguageLessonsSince
298338
: this.familyLanguageLessonsSince,
299339
leavingDate: leavingDate is DateTime? ? leavingDate : this.leavingDate,
340+
schoolTransitionRecommendation: schoolTransitionRecommendation is String?
341+
? schoolTransitionRecommendation
342+
: this.schoolTransitionRecommendation,
300343
);
301344
}
302345
}

school_data_hub_client/lib/src/protocol/protocol.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1128,6 +1128,11 @@ class Protocol extends _i1.SerializationManager {
11281128
.toList()
11291129
: null) as T;
11301130
}
1131+
if (t == _i1.getType<List<String>?>()) {
1132+
return (data != null
1133+
? (data as List).map((e) => deserialize<String>(e)).toList()
1134+
: null) as T;
1135+
}
11311136
if (t == _i1.getType<List<_i61.PupilListEntry>?>()) {
11321137
return (data != null
11331138
? (data as List)

school_data_hub_flutter/assets/school_data_hub_server.svg

Lines changed: 1 addition & 1 deletion
Loading

school_data_hub_flutter/lib/app_utils/pupil_identity_file_import.dart

Lines changed: 40 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -30,28 +30,36 @@ Future<String?> pickPupilIdentityFileContent() async {
3030
}
3131

3232
/// SchILD export column indices (0-based). Mapping by position, not header names.
33-
/// Hijacked: Ausweisnummer (14) -> family; Externe ID-Nummer (15) -> familyLanguageLessonsSince.
34-
/// Förderschwerpunkt 1/2 (20, 21) -> specialNeeds columns 6 and 7.
33+
/// Headers: Interne ID-Nummer, Vorname, Nachname, Klasse, Klassenlehrer, Stv., Jahrgang,
34+
/// Förderschwerpunkt 1, Förderschwerpunkt 2, Geschlecht, Staatsangehörigkeit, Verkehrssprache,
35+
/// Externe ID-Nummer, Geburtsdatum, Ende Eingliederungsphase, Aufnahmedatum, bes.Merkmal,
36+
/// Konfession, Religionsanmeldung, Religionsabmeldung, Ausweisnummer, Übergangsempfehlung, Entlassdatum
37+
/// Hijacked: Ausweisnummer (20) -> family; Externe ID-Nummer (12) -> familyLanguageLessonsSince.
3538
class SchildExportColumns {
3639
SchildExportColumns._();
3740

38-
static const int id = 0; // Schulnummer / l.d.A.Schildnummer
39-
static const int group = 1; // Klasse
41+
static const int id = 0; // Interne ID-Nummer
42+
static const int firstName = 1; // Vorname
4043
static const int lastName = 2; // Nachname
41-
static const int firstName = 3; // Vorname
42-
static const int gender = 5; // Geschlecht
43-
static const int birthday = 6; // Geburtsdatum
44-
static const int religion = 8; // Rel.
45-
static const int family = 14; // Ausweisnummer (hijacked for family code)
46-
static const int familyLanguageLessonsSince =
47-
15; // Externe ID-Nummer (hijacked for family language lessons since)
48-
static const int specialNeeds1 = 20; // Förderschwerpunkt 1
49-
static const int specialNeeds2 = 21; // Förderschwerpunkt 2
50-
static const int groupTutor = 31; // Klassenleiter (if present)
51-
static const int schoolGrade = 29; // Jahrgang (if present)
52-
static const int pupilSince = 30; // Aufnahmedatum
53-
static const int leavingDate =
54-
32; // Datum Abgang (if present; column may vary)
44+
static const int group = 3; // Klasse
45+
static const int groupTutor = 4; // Klassenlehrer: Krz.
46+
static const int deputyGroupTutor = 5; // Stv. Klassenlehrer: Krz.
47+
static const int schoolGrade = 6; // Jahrgang
48+
static const int specialNeeds1 = 7; // Förderschwerpunkt 1
49+
static const int specialNeeds2 = 8; // Förderschwerpunkt 2
50+
static const int gender = 9; // Geschlecht
51+
static const int nationality = 10; // Staatsangehörigkeit (Schlüssel)
52+
static const int language = 11; // Verkehrssprache in der Familie
53+
static const int familyLanguageLessonsSince = 12; // Externe ID-Nummer (hijacked)
54+
static const int birthday = 13; // Geburtsdatum
55+
static const int migrationSupportEnds = 14; // Ende der Eingliederungsphase
56+
static const int pupilSince = 15; // Aufnahmedatum
57+
static const int religion = 17; // Konfession (Klartext)
58+
static const int religionLessonsSince = 18; // Religionsanmeldung
59+
static const int religionLessonsCancelledAt = 19; // Religionsabmeldung
60+
static const int family = 20; // Ausweisnummer (hijacked for family code)
61+
static const int schoolTransitionRecommendation = 21; // Übergangsempfehlung
62+
static const int leavingDate = 22; // Entlassdatum
5563
}
5664

5765
String _xlsxToPupilIdentityLines(List<int> bytes) {
@@ -110,17 +118,23 @@ String? _rowToCanonicalLine(
110118
cellStr(SchildExportColumns.specialNeeds1),
111119
cellStr(SchildExportColumns.specialNeeds2),
112120
cellStr(SchildExportColumns.gender),
113-
'', // language - not mapped from template
121+
cellStr(SchildExportColumns.language),
114122
cellStr(SchildExportColumns.family),
115123
_normalizeDateCell(cellStr(SchildExportColumns.birthday), dateFormat),
116-
'', // migrationSupportEnds
124+
_normalizeDateCell(
125+
cellStr(SchildExportColumns.migrationSupportEnds), dateFormat),
117126
_normalizeDateCell(cellStr(SchildExportColumns.pupilSince), dateFormat),
118-
'', // afterSchoolCare -> empty if not in export
127+
'', // afterSchoolCare -> not in export
119128
cellStr(SchildExportColumns.religion),
120-
'', // religionLessonsSince
121-
'', // religionLessonsCancelledAt
129+
_normalizeDateCell(
130+
cellStr(SchildExportColumns.religionLessonsSince), dateFormat),
131+
_normalizeDateCell(
132+
cellStr(SchildExportColumns.religionLessonsCancelledAt), dateFormat),
122133
cellStr(SchildExportColumns.familyLanguageLessonsSince),
123134
_normalizeDateCell(cellStr(SchildExportColumns.leavingDate), dateFormat),
135+
cellStr(SchildExportColumns.deputyGroupTutor),
136+
cellStr(SchildExportColumns.nationality),
137+
cellStr(SchildExportColumns.schoolTransitionRecommendation),
124138
];
125139

126140
return parts.map((p) => p.replaceAll(',', ' ')).join(',');
@@ -143,6 +157,8 @@ String _cellValueToCanonicalString(dynamic value, DateFormat dateFormat) {
143157
return value.toString();
144158
}
145159

160+
/// Returns a date string (yyyy-MM-dd) or '' if [raw] is not a valid date.
161+
/// Avoids passing non-date values (e.g. category codes like "LE") into date fields.
146162
String _normalizeDateCell(String raw, DateFormat dateFormat) {
147163
final s = raw.trim();
148164
if (s.isEmpty) return '';
@@ -152,6 +168,6 @@ String _normalizeDateCell(String raw, DateFormat dateFormat) {
152168
final ddMMyyyy = DateFormat('dd.MM.yyyy').parse(s);
153169
return dateFormat.format(ddMMyyyy);
154170
} catch (_) {
155-
return s;
171+
return '';
156172
}
157173
}

school_data_hub_flutter/lib/app_utils/shorebird_code_push_page.dart

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import 'package:flutter/foundation.dart';
12
import 'package:flutter/material.dart';
23
import 'package:flutter_it/flutter_it.dart';
34
import 'package:gap/gap.dart';
@@ -7,6 +8,7 @@ import 'package:school_data_hub_flutter/common/widgets/bottom_nav_bar/generic_bo
78
import 'package:school_data_hub_flutter/common/widgets/generic_components/generic_app_bar.dart';
89
import 'package:school_data_hub_flutter/core/updater/shorebird_update_manager.dart';
910
import 'package:shorebird_code_push/shorebird_code_push.dart';
11+
import 'package:terminate_restart/terminate_restart.dart';
1012

1113
final _log = Logger('CheckForUpdatesPage');
1214

@@ -196,6 +198,26 @@ class _ShorebirdCodePushPageState extends State<ShorebirdCodePushPage> {
196198
: const Icon(Icons.refresh),
197199
label: const Text('Nach Updates suchen'),
198200
),
201+
const Gap(12),
202+
ElevatedButton(
203+
onPressed: () async {
204+
if (defaultTargetPlatform == TargetPlatform.android ||
205+
defaultTargetPlatform == TargetPlatform.iOS) {
206+
await TerminateRestart.instance.restartAppWithConfirmation(
207+
context,
208+
title: 'Restart App',
209+
message: 'Do you want to restart the app?',
210+
terminate: true,
211+
);
212+
} else {
213+
if (!context.mounted) return;
214+
di<NotificationService>().showInformationDialog(
215+
'Bitte schließen Sie die App manuell und starten Sie sie erneut.',
216+
);
217+
}
218+
},
219+
child: const Text('App neu starten'),
220+
),
199221
const Spacer(),
200222
],
201223
),

0 commit comments

Comments
 (0)