Add cross-company ticket viewing and move Yritykset button to header
- tickets endpoint supports ?all=1 to fetch from all user's companies - ticket_detail/reply/status/etc support ?company_id= for cross-company ops - Support tab shows all companies' tickets with company badge on subject - Yritykset button moved from tab bar to header (next to Käyttäjät) - requireCompanyOrParam() helper for ticket endpoints Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
154
api.php
154
api.php
@@ -105,6 +105,22 @@ function requireCompany(): string {
|
||||
return $companyId;
|
||||
}
|
||||
|
||||
// Kuten requireCompany(), mutta sallii company_id:n overriden GET-parametrista
|
||||
// Käytetään tiketti-endpointeissa jotta toisen yrityksen tikettejä voi avata
|
||||
function requireCompanyOrParam(): string {
|
||||
$paramCompany = $_GET['company_id'] ?? '';
|
||||
if (!empty($paramCompany)) {
|
||||
$userCompanies = $_SESSION['companies'] ?? [];
|
||||
if (!in_array($paramCompany, $userCompanies)) {
|
||||
http_response_code(403);
|
||||
echo json_encode(['error' => 'Ei oikeutta tähän yritykseen']);
|
||||
exit;
|
||||
}
|
||||
$_SESSION['company_id'] = $paramCompany;
|
||||
}
|
||||
return requireCompany();
|
||||
}
|
||||
|
||||
function companyFile(string $filename): string {
|
||||
return getCompanyDir() . '/' . $filename;
|
||||
}
|
||||
@@ -1663,62 +1679,86 @@ switch ($action) {
|
||||
// ---------- TICKETS ----------
|
||||
case 'tickets':
|
||||
requireAuth();
|
||||
requireCompany();
|
||||
$tickets = loadTickets();
|
||||
// Palauta ilman viestisisältöjä (lista-näkymä)
|
||||
// Auto-close tarkistus: sulje tiketit joiden auto_close_at on ohitettu
|
||||
$now = date('Y-m-d H:i:s');
|
||||
$autoCloseCount = 0;
|
||||
foreach ($tickets as &$tc) {
|
||||
if (!empty($tc['auto_close_at']) && $tc['auto_close_at'] <= $now && !in_array($tc['status'], ['suljettu'])) {
|
||||
$tc['status'] = 'suljettu';
|
||||
$tc['updated'] = $now;
|
||||
$autoCloseCount++;
|
||||
$allCompanies = !empty($_GET['all']);
|
||||
$userCompanyIds = $_SESSION['companies'] ?? [];
|
||||
|
||||
// Kerää yritykset joista haetaan
|
||||
$companiesToQuery = [];
|
||||
if ($allCompanies && count($userCompanyIds) > 1) {
|
||||
$allComps = loadCompanies();
|
||||
foreach ($allComps as $c) {
|
||||
if (in_array($c['id'], $userCompanyIds)) {
|
||||
$companiesToQuery[] = $c;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
requireCompany();
|
||||
$companiesToQuery[] = ['id' => $_SESSION['company_id'], 'nimi' => ''];
|
||||
}
|
||||
|
||||
$list = [];
|
||||
foreach ($companiesToQuery as $comp) {
|
||||
$cDir = DATA_DIR . '/companies/' . $comp['id'];
|
||||
$ticketsFile = $cDir . '/tickets.json';
|
||||
if (!file_exists($ticketsFile)) continue;
|
||||
$tickets = json_decode(file_get_contents($ticketsFile), true) ?: [];
|
||||
|
||||
// Auto-close tarkistus
|
||||
$now = date('Y-m-d H:i:s');
|
||||
$autoCloseCount = 0;
|
||||
foreach ($tickets as &$tc) {
|
||||
if (!empty($tc['auto_close_at']) && $tc['auto_close_at'] <= $now && !in_array($tc['status'], ['suljettu'])) {
|
||||
$tc['status'] = 'suljettu';
|
||||
$tc['updated'] = $now;
|
||||
$autoCloseCount++;
|
||||
}
|
||||
}
|
||||
unset($tc);
|
||||
if ($autoCloseCount > 0) {
|
||||
file_put_contents($ticketsFile, json_encode($tickets, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
|
||||
}
|
||||
|
||||
// Resolve mailbox names for this company
|
||||
$confFile = $cDir . '/config.json';
|
||||
$companyConf = file_exists($confFile) ? (json_decode(file_get_contents($confFile), true) ?: []) : [];
|
||||
$mailboxNames = [];
|
||||
foreach ($companyConf['mailboxes'] ?? [] as $mb) {
|
||||
$mailboxNames[$mb['id']] = $mb['nimi'];
|
||||
}
|
||||
|
||||
foreach ($tickets as $t) {
|
||||
$msgCount = count($t['messages'] ?? []);
|
||||
$lastMsg = $msgCount > 0 ? $t['messages'][$msgCount - 1] : null;
|
||||
$list[] = [
|
||||
'id' => $t['id'],
|
||||
'subject' => $t['subject'],
|
||||
'from_email' => $t['from_email'],
|
||||
'from_name' => $t['from_name'],
|
||||
'status' => $t['status'],
|
||||
'type' => $t['type'] ?? 'muu',
|
||||
'assigned_to' => $t['assigned_to'] ?? '',
|
||||
'customer_id' => $t['customer_id'] ?? '',
|
||||
'customer_name' => $t['customer_name'] ?? '',
|
||||
'tags' => $t['tags'] ?? [],
|
||||
'auto_close_at' => $t['auto_close_at'] ?? '',
|
||||
'mailbox_id' => $t['mailbox_id'] ?? '',
|
||||
'mailbox_name' => $mailboxNames[$t['mailbox_id'] ?? ''] ?? '',
|
||||
'company_id' => $comp['id'],
|
||||
'company_name' => $comp['nimi'] ?? '',
|
||||
'created' => $t['created'],
|
||||
'updated' => $t['updated'],
|
||||
'message_count' => $msgCount,
|
||||
'last_message_type' => $lastMsg ? ($lastMsg['type'] ?? '') : '',
|
||||
'last_message_time' => $lastMsg ? ($lastMsg['timestamp'] ?? '') : '',
|
||||
];
|
||||
}
|
||||
}
|
||||
unset($tc);
|
||||
if ($autoCloseCount > 0) {
|
||||
saveTickets($tickets);
|
||||
addLog('ticket_auto_close', '', '', "Automaattisulku: $autoCloseCount tikettiä");
|
||||
}
|
||||
|
||||
// Resolve mailbox names
|
||||
$companyConf = loadCompanyConfig();
|
||||
$mailboxNames = [];
|
||||
foreach ($companyConf['mailboxes'] ?? [] as $mb) {
|
||||
$mailboxNames[$mb['id']] = $mb['nimi'];
|
||||
}
|
||||
|
||||
$list = array_map(function($t) use ($mailboxNames) {
|
||||
$msgCount = count($t['messages'] ?? []);
|
||||
$lastMsg = $msgCount > 0 ? $t['messages'][$msgCount - 1] : null;
|
||||
return [
|
||||
'id' => $t['id'],
|
||||
'subject' => $t['subject'],
|
||||
'from_email' => $t['from_email'],
|
||||
'from_name' => $t['from_name'],
|
||||
'status' => $t['status'],
|
||||
'type' => $t['type'] ?? 'muu',
|
||||
'assigned_to' => $t['assigned_to'] ?? '',
|
||||
'customer_id' => $t['customer_id'] ?? '',
|
||||
'customer_name' => $t['customer_name'] ?? '',
|
||||
'tags' => $t['tags'] ?? [],
|
||||
'auto_close_at' => $t['auto_close_at'] ?? '',
|
||||
'mailbox_id' => $t['mailbox_id'] ?? '',
|
||||
'mailbox_name' => $mailboxNames[$t['mailbox_id'] ?? ''] ?? '',
|
||||
'created' => $t['created'],
|
||||
'updated' => $t['updated'],
|
||||
'message_count' => $msgCount,
|
||||
'last_message_type' => $lastMsg ? ($lastMsg['type'] ?? '') : '',
|
||||
'last_message_time' => $lastMsg ? ($lastMsg['timestamp'] ?? '') : '',
|
||||
];
|
||||
}, $tickets);
|
||||
echo json_encode($list);
|
||||
break;
|
||||
|
||||
case 'ticket_detail':
|
||||
requireAuth();
|
||||
requireCompany();
|
||||
requireCompanyOrParam();
|
||||
$id = $_GET['id'] ?? '';
|
||||
$tickets = loadTickets();
|
||||
$ticket = null;
|
||||
@@ -1880,7 +1920,7 @@ switch ($action) {
|
||||
|
||||
case 'ticket_reply':
|
||||
requireAuth();
|
||||
requireCompany();
|
||||
requireCompanyOrParam();
|
||||
if ($method !== 'POST') break;
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
$id = $input['id'] ?? '';
|
||||
@@ -1955,7 +1995,7 @@ switch ($action) {
|
||||
|
||||
case 'ticket_status':
|
||||
requireAuth();
|
||||
requireCompany();
|
||||
requireCompanyOrParam();
|
||||
if ($method !== 'POST') break;
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
$id = $input['id'] ?? '';
|
||||
@@ -1990,7 +2030,7 @@ switch ($action) {
|
||||
|
||||
case 'ticket_type':
|
||||
requireAuth();
|
||||
requireCompany();
|
||||
requireCompanyOrParam();
|
||||
if ($method !== 'POST') break;
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
$id = $input['id'] ?? '';
|
||||
@@ -2025,7 +2065,7 @@ switch ($action) {
|
||||
|
||||
case 'ticket_customer':
|
||||
requireAuth();
|
||||
requireCompany();
|
||||
requireCompanyOrParam();
|
||||
if ($method !== 'POST') break;
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
$id = $input['id'] ?? '';
|
||||
@@ -2055,7 +2095,7 @@ switch ($action) {
|
||||
|
||||
case 'ticket_assign':
|
||||
requireAuth();
|
||||
requireCompany();
|
||||
requireCompanyOrParam();
|
||||
if ($method !== 'POST') break;
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
$id = $input['id'] ?? '';
|
||||
@@ -2083,7 +2123,7 @@ switch ($action) {
|
||||
|
||||
case 'ticket_note':
|
||||
requireAuth();
|
||||
requireCompany();
|
||||
requireCompanyOrParam();
|
||||
if ($method !== 'POST') break;
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
$id = $input['id'] ?? '';
|
||||
@@ -2125,7 +2165,7 @@ switch ($action) {
|
||||
|
||||
case 'ticket_delete':
|
||||
requireAuth();
|
||||
requireCompany();
|
||||
requireCompanyOrParam();
|
||||
if ($method !== 'POST') break;
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
$id = $input['id'] ?? '';
|
||||
@@ -2142,7 +2182,7 @@ switch ($action) {
|
||||
|
||||
case 'ticket_tags':
|
||||
requireAuth();
|
||||
requireCompany();
|
||||
requireCompanyOrParam();
|
||||
if ($method !== 'POST') break;
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
$id = $input['id'] ?? '';
|
||||
|
||||
Reference in New Issue
Block a user