fix: prevent report dropdown parameter mismatch

This commit is contained in:
Marco0300
2026-09-01 23:04:51 +02:00
parent 99aaaf3338
commit 2b3e04825c
2 changed files with 9 additions and 3 deletions
+7 -3
View File
@@ -740,9 +740,13 @@ if ($route === 'reports') {
$reportStmt->execute($params); $reportStmt->execute($params);
$reportRows = $reportStmt->fetchAll(); $reportRows = $reportStmt->fetchAll();
$rows = array_map(static fn (array $row): array => [$row['client_name'], (int)$row['jobcards'], round((float)$row['hours'], 2)], $reportRows); $rows = array_map(static fn (array $row): array => [$row['client_name'], (int)$row['jobcards'], round((float)$row['hours'], 2)], $reportRows);
$reportClients = $user['role_name'] === 'Technician' ? db()->prepare('SELECT DISTINCT c.id, c.name FROM clients c JOIN jobcards j ON j.client_id = c.id JOIN jobcard_assignments ja ON ja.jobcard_id = j.id AND ja.user_id = :user ORDER BY c.name') : db()->query('SELECT id, name FROM clients ORDER BY name'); if ($user['role_name'] === 'Technician') {
if ($reportClients instanceof PDOStatement) $reportClients->execute(['user' => $user['id']]); $reportClientsStmt = db()->prepare('SELECT DISTINCT c.id, c.name FROM clients c JOIN jobcards j ON j.client_id = c.id JOIN jobcard_assignments ja ON ja.jobcard_id = j.id AND ja.user_id = :user ORDER BY c.name');
$reportClients = $reportClients->fetchAll(); $reportClientsStmt->execute(['user' => $user['id']]);
$reportClients = $reportClientsStmt->fetchAll();
} else {
$reportClients = db()->query('SELECT id, name FROM clients ORDER BY name')->fetchAll();
}
$filterQuery = http_build_query(array_filter(['client_id' => $filters->clientId, 'date_from' => $filters->dateFrom, 'date_to' => $filters->dateTo, 'technician_id' => $filters->technicianId, 'status' => $filters->status, 'priority' => $filters->priority], static fn($value): bool => $value !== null && $value !== '')); $filterQuery = http_build_query(array_filter(['client_id' => $filters->clientId, 'date_from' => $filters->dateFrom, 'date_to' => $filters->dateTo, 'technician_id' => $filters->technicianId, 'status' => $filters->status, 'priority' => $filters->priority], static fn($value): bool => $value !== null && $value !== ''));
if ($format === 'print') { header('Content-Type: text/html; charset=UTF-8'); header('Cache-Control: no-store'); echo (new \PrintReportRenderer())->render('Hours per client', ['Client', 'Jobcards', 'Hours'], $rows); exit; } if ($format === 'print') { header('Content-Type: text/html; charset=UTF-8'); header('Cache-Control: no-store'); echo (new \PrintReportRenderer())->render('Hours per client', ['Client', 'Jobcards', 'Hours'], $rows); exit; }
if ($format === 'csv') { if ($format === 'csv') {
+2
View File
@@ -15,5 +15,7 @@ jobcard_feature_assert(str_contains($front, "j.status <> 'closed'"), 'Default Jo
jobcard_feature_assert(str_contains($front, "j.status = 'closed'"), 'Closed filter must explicitly select closed records.'); jobcard_feature_assert(str_contains($front, "j.status = 'closed'"), 'Closed filter must explicitly select closed records.');
jobcard_feature_assert(str_contains($front, 'All clients') && str_contains($front, '$reportClient'), 'Reports must use a client-name dropdown.'); jobcard_feature_assert(str_contains($front, 'All clients') && str_contains($front, '$reportClient'), 'Reports must use a client-name dropdown.');
jobcard_feature_assert(str_contains($front, 'format=xls&detail=1'), 'Reports must expose detailed XLS export.'); jobcard_feature_assert(str_contains($front, 'format=xls&detail=1'), 'Reports must expose detailed XLS export.');
jobcard_feature_assert(str_contains($front, "if (\$user['role_name'] === 'Technician') {") && str_contains($front, '$reportClientsStmt->execute'), 'Report client dropdown must bind parameters only on the technician prepared-query branch.');
jobcard_feature_assert(!str_contains($front, 'if ($reportClients instanceof PDOStatement) $reportClients->execute'), 'Report client dropdown must not execute parameters against the non-technician query branch.');
foreach (['Work requested', 'Technician notes / Work performed', 'Hours notes'] as $heading) jobcard_feature_assert(str_contains($front, $heading), "Detailed report must include {$heading}."); foreach (['Work requested', 'Technician notes / Work performed', 'Hours notes'] as $heading) jobcard_feature_assert(str_contains($front, $heading), "Detailed report must include {$heading}.");
printf("Jobcard search/close/report tests: 10 passed\n"); printf("Jobcard search/close/report tests: 10 passed\n");