From f6be5424400f901d6e407cc0213a882144a8c06d Mon Sep 17 00:00:00 2001 From: jonas Date: Fri, 28 Jul 2023 01:39:25 +0200 Subject: [PATCH] first commit --- IServ_Elternimport_Divis.php | 211 +++++++++++++++++++++++++++++++++++ README.md | 20 ++++ 2 files changed, 231 insertions(+) create mode 100644 IServ_Elternimport_Divis.php create mode 100644 README.md diff --git a/IServ_Elternimport_Divis.php b/IServ_Elternimport_Divis.php new file mode 100644 index 0000000..4ab67cc --- /dev/null +++ b/IServ_Elternimport_Divis.php @@ -0,0 +1,211 @@ + parents CSV + * and maps the parents to the IServ students, creating a third CSV file that can be imported + * into the IServ Elternverwaltung module. + * + * The IServ user export CSV is expected to have the following columns: + * Account;Vorname;Nachname;Status;"Erstellt am";"Erstellt von";"Interne ID";Benutzertyp;Import-ID;Klasse/Information;E-Mail-Adresse;Gruppen + * + * The student <> parents mapped CSV from DiViS should have the following columns: + * "Schüler Vorname","Schüler Nachname","Eltern 1 Vorname","Eltern 1 Nachname","Eltern 2 Vorname","Eltern 2 Nachname" + * + * The CSV exported by this script will have the following columns: + * Nachname;Vorname;Kind-ID;Klasse + * + * Status messages, information and errors are always written to STDERR, while the generated CSV + * will be exported to STDOUT, meaning you can redirect the STDOUT output of this script to a file + * to export the CSV and still be able to read any informational messages: + * $ php ./IServ_Elternimport_Divis.php iserv-user-export.csv divis-parents-export.csv > Parents_Import.csv + */ + +define ("WRITE_TO_CONSOLE", true); +define ("IS_CLI", (php_sapi_name() == "cli")); + +/** + * Writes text to the STDERR stream when running from the command line. + * + * @param string $text The text to write to console + * @return void + */ +function console_write ($text) { + global $argv; + + if (IS_CLI && WRITE_TO_CONSOLE) { + fwrite (STDERR, $text . PHP_EOL); + } +} + +/** + * Turns the first and last name of a student into a single string + * used to identify the student in the students array. + * + * @param string $firstname First name of the student + * @param string $lastname Last name of the student + * @return string Combined and lower-cased names of the student + */ +function hash_student ($firstname, $lastname) { + return strtolower($firstname) . "_" . strtolower($lastname); +} + +/** + * Tries the parent(s) of a student by their first and last name + * in the DiViS student <> parents mapped CSV. + * + * @param string $firstname First name of the student + * @param string $lastname Last name of the student + * @return string|null Array of parents first and last names, + * or null if no matching data was found. + */ +function find_parent_by_student ($firstname, $lastname) { + global $divis_parents; + + $student_hash = hash_student ($firstname, $lastname); + $best_match = [ "match_perc" => 0 ]; + $perc = 0; + + console_write ("INFO: Searching parent(s) for '{$firstname} {$lastname}' ({$student_hash})"); + + foreach ($divis_parents as $hash => $parent) { + similar_text ($student_hash, $hash, $perc); + + // If match is bigger or equal to 85% and this match is higher + // ranked than the last, make this the current best match + if ($perc >= 85 && $best_match["match_perc"] < $perc) { + console_write ("INFO: New best match '{$hash}' at {$perc}%"); + $best_match = [ + "match_perc" => $perc, + "student_hash" => $student_hash, + "parent_data" => $parent + ]; + } + } + + if ($best_match["match_perc"] == 0) { + console_write ("WARN: Could not find parent for '{$firstname} {$lastname}'!"); + return null; + } + + $parent1_firstname = $best_match['parent_data']['parent1_firstname']; + $parent1_lastname = $best_match['parent_data']['parent1_lastname']; + $parent2_firstname = $best_match['parent_data']['parent2_firstname']; + $parent2_lastname = $best_match['parent_data']['parent2_lastname']; + console_write ("INFO: Found parent(s):"); + console_write ("INFO: First Parent: {$parent1_firstname} {$parent1_lastname}"); + console_write ("INFO: Second Parent: {$parent2_firstname} {$parent2_lastname}"); + + return [ + "parent1" => [ + "firstname" => $parent1_firstname, + "lastname" => $parent1_lastname + ], + "parent2" => [ + "firstname" => $parent2_firstname, + "lastname" => $parent2_lastname + ] + ]; +} + +// Test if the two required input files have been specified +if (isset ($argc) && $argc == 3) { + $iserv_infile = $argv[1]; + $divis_infile = $argv[2]; + + if (! is_file ($iserv_infile)) { + console_write ("CRIT: The IServ CSV file specified is not a file or does not exist."); + exit (1); + } + + if (! is_file ($divis_infile)) { + console_write ("CRIT: The DiViS CSV file specified is not a file or does not exist."); + exit (1); + } +} else { + console_write ("Usage: "); + console_write (" {$argv[0]} "); + console_write (""); + exit (1); +} + +// Read DiViS student <> parents mapped CSV to an array +$parents_csv_fd = fopen ($divis_infile, "r"); +$divis_parents = []; +while ($parent = fgetcsv ($parents_csv_fd)) { + $student_firstname = $parent[0]; + $student_lastname = $parent[1]; + $student_hash = hash_student ($student_firstname, $student_lastname); + + $divis_parents[$student_hash] = [ + "student_firstname" => $student_firstname, + "student_lastname" => $student_lastname, + "parent1_firstname" => $parent[2], + "parent1_lastname" => $parent[3], + "parent2_firstname" => $parent[4], + "parent2_lastname" => $parent[5] + ]; +} +fclose ($parents_csv_fd); + + +// Iterate through all students in the IServ student export CSV +$students_csv_fd = fopen ($iserv_infile, "r"); +$parents_to_export = []; +$students_without_parents = []; +fgets ($students_csv_fd); // Skip header in the CSV file +while ($student = fgetcsv ($students_csv_fd, null, ";")) { + // Skip non-student users + if ($student[7] !== "Schüler") continue; + + $student_firstname = $student[1]; + $student_lastname = $student[2]; + $student_userid = $student[8]; + $student_class = strtolower ($student[9]); + $student_class = "klasse." . str_replace (" ", ".", $student_class); + + $parents = find_parent_by_student ($student_firstname, $student_lastname); + + if ($parents == null) { + $students_without_parents[] = $student; + } else { + if ($parents["parent1"]["firstname"] && $parents["parent1"]["lastname"]) { + $parents_to_export[] = [ + $parents["parent1"]["firstname"], + $parents["parent1"]["lastname"], + $student_userid, + $student_class + ]; + } else { + console_write ("WARN: Parent 1 dataset non-existant for student '{$student_firstname} {$student_lastname}'"); + } + + if ($parents["parent2"]["firstname"] && $parents["parent2"]["lastname"]) { + $parents_to_export[] = [ + $parents["parent2"]["firstname"], + $parents["parent2"]["lastname"], + $student_userid, + $student_class + ]; + } else { + console_write ("WARN: Parent 2 dataset non-existant for student '{$student_firstname} {$student_lastname}'"); + } + } + + console_write (""); +} +fclose ($students_csv_fd); + +// Iterate through each exportable parent and convert them to a CSV line +if (IS_CLI) { + $out_fd = STDOUT; +} else { + $out_fd = fopen ("php://output", "w"); + header('Content-Type: text/csv'); + header('Content-Disposition: attachment; filename="Elternimport.csv";'); +} + +foreach ($parents_to_export as $parent) { + fputcsv($out_fd, $parent, ";"); +} + +fclose ($out_fd); +?> \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..2598f5e --- /dev/null +++ b/README.md @@ -0,0 +1,20 @@ +## DiViS Parents Export to IServ Elternverwaltung module import ## + +This script takes two files, an IServ user export CSV and a DiViS student <> parents CSV +and maps the parents to the IServ students, creating a third CSV file that can be imported +into the IServ Elternverwaltung module. + +The IServ user export CSV is expected to have the following columns: +`Account;Vorname;Nachname;Status;"Erstellt am";"Erstellt von";"Interne ID";Benutzertyp;Import-ID;Klasse/Information;E-Mail-Adresse;Gruppen` + +The student <> parents mapped CSV from DiViS should have the following columns: +`"Schüler Vorname","Schüler Nachname","Eltern 1 Vorname","Eltern 1 Nachname","Eltern 2 Vorname","Eltern 2 Nachname"` + +The CSV exported by this script will have the following columns: +`Nachname;Vorname;Kind-ID;Klasse` + +Status messages, information and errors are always written to `STDERR`, while the generated CSV +will be exported to `STDOUT`, meaning you can redirect the `STDOUT` output of this script to a file +to export the CSV and still be able to read any informational messages: + +`$ php ./IServ_Elternimport_Divis.php iserv-user-export.csv divis-parents-export.csv > Parents_Import.csv` \ No newline at end of file