Skip to main content

Timetables from Zermelo, Untis, Xedule and TimeEdit into planninq

Integriq reads a school timetable from a rostering system and delivers it into planninq. Planninq keeps the timetable; learniq shows it to teachers, pupils and parents.

The four rostering sources ship switched off. Until a school has its own connection, a delivery sends a small example timetable, and the result says so (flavour: mock).

What happens during a delivery​

  1. Integriq fetches the lessons from the rostering system.
  2. The source's preset turns each lesson into planninq's timetable session: source id, subject, start and end, group, teacher and room.
  3. The target configuration adds the learniq cohort and the teacher's Nextcloud account where the school's code is known.
  4. Planninq adds new lessons, updates moved ones and leaves unchanged ones alone.

A lesson with a group code integriq cannot link to a cohort still lands. Planninq keeps the school's group code, and learniq can find the lesson by it.

The four presets​

SourceLesson idSubjectTimesGroupTeacherRoomCancelled when
Zermelo (roster-zermelo)appointmentInstancesubjectsstart, end (Unix seconds)groupsteacherslocationscancelled is true
Untis (roster-untis-oneroster)idfaechIdstartDateTime, endDateTimeklasseIdlehrerIdraumIdcode is cancelled
Xedule (roster-xedule)eventIdactivityNamestartMoment, endMomentgroupCodeteacherCodelocationNamestatus is cancelled
TimeEdit (roster-timeedit)activityIdactivityTitlebeginTime, endTimeresourceGroupstaffIdroomNamecancelled is true

The presets live in lib/roster-mapping-presets.seed.json. The field names come from each vendor's published API and were not captured from a live school. If a real delivery uses other names, correct the preset; no code changes.

Linking school codes to cohorts and teachers​

Store two maps per source in integriq's app config. Each is a JSON object.

occ config:app:set integriq roster.roster-zermelo.group_map --value='{"3a": "<cohort id>", "3b": "<cohort id>"}'
occ config:app:set integriq roster.roster-zermelo.teacher_map --value='{"JAN": "jan.devries"}'

Learniq can also send maps with a delivery. Its entries win over the stored ones. An unreadable stored value counts as an empty map and is written to the log.

For integrators​

Ask integriq for a delivery with a typed event (ADR-041). Look the class up by name and treat a missing class as "integriq is not installed".

$class = 'OCA\\Integriq\\Event\\RosterImportRequestedEvent';
$event = new $class(sourceApp: 'learniq', systemId: 'roster-zermelo', options: ['groupMap' => [...]], correlationId: $jobId);
$dispatcher->dispatchTyped($event);
$result = $event->getResult(); // status: delivered | failed

A failed result names why in errorCode:

errorCodeMeaning
unknown-sourceThe source id is not one of the four rostering sources.
fetch-failedThe rostering system could not be read.
planninq-absentPlanninq is not installed, or did not answer.
planninq-refusedPlanninq refused the whole delivery.

The full contract is in openspec/changes/rostering-adapter-targets-planninq/contract.md.