feat(outlook): fix calendar sync format and enable bidirectional task-to-outlook scheduling

This commit is contained in:
2026-09-09 12:10:54 +02:00
parent 60f458b28a
commit 247fb4cd26
5 changed files with 473 additions and 55 deletions
+145 -10
View File
@@ -4,6 +4,7 @@
*/
require_once __DIR__ . '/../includes/auth.php';
require_once __DIR__ . '/../includes/integrations/microsoft.php';
$user = require_auth();
$db = get_db_connection();
@@ -36,8 +37,11 @@ try {
$data = json_decode(file_get_contents('php://input'), true);
$title = trim($data['title'] ?? '');
$priority = in_array($data['priority'] ?? '', ['P1', 'P2', 'P3']) ? $data['priority'] : 'P2';
$timeBlockStart = $data['time_block_start'] ?? null;
$date = $data['date'] ?? $today;
$timeBlockStart = !empty($data['time_block_start']) ? trim($data['time_block_start']) : null;
$durationMinutes = (int)($data['duration_minutes'] ?? 30);
if ($durationMinutes <= 0) $durationMinutes = 30;
$date = !empty($data['date']) ? trim($data['date']) : $today;
$syncOutlook = !empty($data['sync_to_outlook']);
if (empty($title)) {
echo json_encode(['error' => 'Titel is verplicht']);
@@ -54,14 +58,44 @@ try {
$planId = $db->lastInsertId();
$source = !empty($data['source']) ? substr(trim($data['source']), 0, 50) : 'FOCIZ';
$externalId = !empty($data['external_id']) ? substr(trim($data['external_id']), 0, 100) : null;
$externalId = !empty($data['external_id']) ? substr(trim($data['external_id']), 0, 255) : null;
$externalUrl = !empty($data['external_url']) ? trim($data['external_url']) : null;
$timeBlockEnd = null;
// Als er een tijdblok is en de gebruiker heeft synchronisatie naar Outlook gekozen (of source is OUTLOOK)
if (($syncOutlook || $source === 'OUTLOOK') && !empty($timeBlockStart) && empty($externalId)) {
$msResult = microsoft_create_event($user['id'], [
'subject' => $title,
'description' => "Gepland via Fociz Dagplanning ({$priority})",
'date' => $date,
'start_time' => $timeBlockStart,
'duration_minutes' => $durationMinutes,
]);
if (!empty($msResult['success']) && !empty($msResult['event_id'])) {
$source = 'OUTLOOK';
$externalId = $msResult['event_id'];
$externalUrl = $msResult['web_link'] ?? 'https://outlook.office.com';
$timeBlockEnd = $msResult['end_time'] ?? null;
}
}
// Bereken timeBlockEnd indien nog niet gezet maar wel starttijd bekend
if (!empty($timeBlockStart) && empty($timeBlockEnd)) {
try {
$dtEnd = new DateTime("{$date} {$timeBlockStart}:00", new DateTimeZone('Europe/Amsterdam'));
$dtEnd->modify("+{$durationMinutes} minutes");
$timeBlockEnd = $dtEnd->format('H:i');
} catch (Throwable $e) {
// negeer
}
}
$stmt = $db->prepare("
INSERT INTO tasks (user_id, daily_plan_id, title, priority, time_block_start, status, source, external_id, external_url)
VALUES (?, ?, ?, ?, ?, 'TODO', ?, ?, ?)
INSERT INTO tasks (user_id, daily_plan_id, title, priority, time_block_start, time_block_end, duration_minutes, status, source, external_id, external_url)
VALUES (?, ?, ?, ?, ?, ?, ?, 'TODO', ?, ?, ?)
");
$stmt->execute([$user['id'], $planId, $title, $priority, $timeBlockStart, $source, $externalId, $externalUrl]);
$stmt->execute([$user['id'], $planId, $title, $priority, $timeBlockStart, $timeBlockEnd, $durationMinutes, $source, $externalId, $externalUrl]);
$taskId = (int)$db->lastInsertId();
echo json_encode([
@@ -71,14 +105,102 @@ try {
'title' => $title,
'priority' => $priority,
'time_block_start' => $timeBlockStart,
'time_block_end' => $timeBlockEnd,
'duration_minutes' => $durationMinutes,
'is_completed' => 0,
'status' => 'TODO'
]
'status' => 'TODO',
'source' => $source,
'external_id' => $externalId,
'external_url' => $externalUrl,
],
'outlook_synced' => ($source === 'OUTLOOK' && !empty($externalId)),
]);
exit;
}
// 3. Taak status toggelen (voltooid / open)
// 3. Bestaande taak handmatig naar Microsoft Outlook synchroniseren
if ($action === 'sync_task_to_outlook') {
$data = json_decode(file_get_contents('php://input'), true);
$taskId = (int)($data['task_id'] ?? 0);
if (!$taskId) {
echo json_encode(['error' => 'Geen taak-ID opgegeven']);
exit;
}
// Haal taak inclusief plan datum op
$stmtTask = $db->prepare("
SELECT t.*, dp.plan_date
FROM tasks t
LEFT JOIN daily_plans dp ON t.daily_plan_id = dp.id
WHERE t.id = ? AND t.user_id = ?
");
$stmtTask->execute([$taskId, $user['id']]);
$task = $stmtTask->fetch();
if (!$task) {
echo json_encode(['error' => 'Taak niet gevonden']);
exit;
}
// Als al gesynchroniseerd
if (!empty($task['external_id']) && $task['source'] === 'OUTLOOK') {
echo json_encode([
'success' => true,
'already_synced' => true,
'external_id' => $task['external_id'],
'external_url' => $task['external_url']
]);
exit;
}
$planDate = $task['plan_date'] ?: $today;
$startTime = !empty($task['time_block_start']) ? $task['time_block_start'] : ($data['time_block_start'] ?? '09:00');
$duration = (int)($task['duration_minutes'] ?: 30);
$msResult = microsoft_create_event($user['id'], [
'subject' => $task['title'],
'description' => "Gepland via Fociz Dagplanning (" . $task['priority'] . ")",
'date' => $planDate,
'start_time' => $startTime,
'duration_minutes' => $duration,
]);
if (empty($msResult['success']) || empty($msResult['event_id'])) {
echo json_encode(['error' => $msResult['error'] ?? 'Kon afspraak niet aanmaken in Microsoft Outlook']);
exit;
}
// Sla Outlook ID en bron op in de taak
$stmtUp = $db->prepare("
UPDATE tasks
SET source = 'OUTLOOK',
external_id = ?,
external_url = ?,
time_block_start = COALESCE(time_block_start, ?),
time_block_end = ?
WHERE id = ? AND user_id = ?
");
$stmtUp->execute([
$msResult['event_id'],
$msResult['web_link'] ?? 'https://outlook.office.com',
$msResult['start_time'],
$msResult['end_time'],
$taskId,
$user['id']
]);
echo json_encode([
'success' => true,
'external_id' => $msResult['event_id'],
'external_url' => $msResult['web_link'] ?? 'https://outlook.office.com',
'start_time' => $msResult['start_time'],
'end_time' => $msResult['end_time'],
]);
exit;
}
// 4. Taak status toggelen (voltooid / open)
if ($action === 'toggle_task') {
$data = json_decode(file_get_contents('php://input'), true);
$taskId = (int)($data['task_id'] ?? 0);
@@ -95,11 +217,24 @@ try {
exit;
}
// 4. Taak verwijderen
// 5. Taak verwijderen (verwijder ook eventueel gekoppelde Outlook afspraak)
if ($action === 'delete_task') {
$data = json_decode(file_get_contents('php://input'), true);
$taskId = (int)($data['task_id'] ?? 0);
// Haal eerst op of deze taak aan Outlook was gekoppeld
$stmtCheck = $db->prepare("SELECT external_id, source FROM tasks WHERE id = ? AND user_id = ?");
$stmtCheck->execute([$taskId, $user['id']]);
$taskToDelete = $stmtCheck->fetch();
if ($taskToDelete && !empty($taskToDelete['external_id']) && $taskToDelete['source'] === 'OUTLOOK') {
try {
microsoft_delete_event($user['id'], $taskToDelete['external_id']);
} catch (Throwable $t) {
error_log("Fout bij verwijderen Outlook afspraak voor taak {$taskId}: " . $t->getMessage());
}
}
$stmt = $db->prepare("DELETE FROM tasks WHERE id = ? AND user_id = ?");
$stmt->execute([$taskId, $user['id']]);