diff --git a/api.php b/api.php index 07a506d..164c8ad 100644 --- a/api.php +++ b/api.php @@ -280,12 +280,16 @@ class ZammadClient { } /** Hae tikettejä (search API palauttaa kaikki joihin on oikeus) */ - public function getTickets(array $groupIds = [], int $page = 1, int $perPage = 100): array { + public function getTickets(array $groupIds = [], int $page = 1, int $perPage = 100, ?string $updatedSince = null): array { if (!empty($groupIds)) { - $query = implode(' OR ', array_map(fn($id) => 'group_id:' . $id, $groupIds)); + $parts = array_map(fn($id) => 'group_id:' . $id, $groupIds); + $query = '(' . implode(' OR ', $parts) . ')'; } else { $query = '*'; } + if ($updatedSince) { + $query .= ' AND updated_at:>=' . $updatedSince; + } return $this->request('GET', 'tickets/search?query=' . urlencode($query) . '&per_page=' . $perPage . '&page=' . $page . '&expand=true'); } @@ -5094,21 +5098,37 @@ switch ($action) { $integ = dbGetIntegration($companyId, 'zammad'); if (!$integ || !$integ['enabled']) { http_response_code(400); echo json_encode(['error' => 'Zammad ei käytössä']); break; } + // full=1 pakottaa täyden synkkauksen (esim. "Hae postit" -napista) + $fullSync = ($_GET['full'] ?? $_POST['full'] ?? '') === '1'; + $input = json_decode(file_get_contents('php://input'), true) ?: []; + if (!empty($input['full'])) $fullSync = true; + try { $cfg = $integ['config']; $z = new ZammadClient($cfg['url'], $cfg['token']); $groupIds = $cfg['group_ids'] ?? []; $syncedGroupNames = $cfg['group_names'] ?? []; + // Hae viimeisin synkkausaika — inkrementaalinen haku + $lastSync = null; + if (!$fullSync) { + $row = _dbFetchOne("SELECT MAX(updated) as last_updated FROM tickets WHERE company_id = ? AND source = 'zammad'", [$companyId]); + if ($row && $row['last_updated']) { + // Hae 5 min marginaalilla ettei menetä mitään + $lastSync = date('Y-m-d\TH:i:s', strtotime($row['last_updated']) - 300); + } + } + // Hae tikettejä Zammadista $allTickets = []; $page = 1; + $maxPages = $fullSync ? 10 : 3; do { - $batch = $z->getTickets($groupIds, $page, 100); + $batch = $z->getTickets($groupIds, $page, 100, $lastSync); if (empty($batch)) break; $allTickets = array_merge($allTickets, $batch); $page++; - } while (count($batch) >= 100 && $page <= 10); + } while (count($batch) >= 100 && $page <= $maxPages); $created = 0; $updated = 0; @@ -5156,11 +5176,18 @@ switch ($action) { $created++; } else { $ticketId = $existing['id']; + $zammadUpdated = date('Y-m-d H:i:s', strtotime($zt['updated_at'] ?? 'now')); // Päivitä status/priority/group _dbExecute( "UPDATE tickets SET status = ?, type = ?, priority = ?, subject = ?, zammad_group = ?, updated = ? WHERE id = ?", - [$status, $type, $priority, $zt['title'] ?? '', $group, date('Y-m-d H:i:s', strtotime($zt['updated_at'] ?? 'now')), $ticketId] + [$status, $type, $priority, $zt['title'] ?? '', $group, $zammadUpdated, $ticketId] ); + // Ohita artikkelien haku jos tiketti ei muuttunut (inkrementaalisessa syncissä) + $existingUpdated = $existing['updated'] ?? ''; + if (!$fullSync && $existingUpdated === $zammadUpdated) { + $updated++; + continue; + } $updated++; } diff --git a/script.js b/script.js index 765a4e0..53e0a0b 100644 --- a/script.js +++ b/script.js @@ -2006,13 +2006,13 @@ document.getElementById('btn-fetch-emails').addEventListener('click', async () = const result = await apiCall('ticket_fetch', 'POST'); let statusMsg = `Valmis! ${result.new_tickets} uutta tikettiä, ${result.threaded} ketjutettu viestiä.`; - // Hae myös Zammadista + // Hae myös Zammadista (full sync) let zammadMsg = ''; try { status.textContent = 'Synkataan Zammad...'; - const zResult = await apiCall('zammad_sync', 'POST'); - if (zResult.created || zResult.updated || zResult.messages) { - zammadMsg = ` Zammad: ${zResult.created} uutta, ${zResult.updated} päivitettyä, ${zResult.messages} viestiä.`; + const zResult = await apiCall('zammad_sync', 'POST', { full: true }); + if (zResult.created || zResult.updated || zResult.messages_added) { + zammadMsg = ` Zammad: ${zResult.created} uutta, ${zResult.updated} päivitettyä, ${zResult.messages_added} viestiä.`; } } catch (ze) { /* Zammad ei käytössä tai virhe — ohitetaan */ }