128 lines
4.4 KiB
PHP
128 lines
4.4 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use App\Repositories\WorkTimesheetRepository;
|
|
use App\Support\Auth;
|
|
use App\Support\Request;
|
|
use App\Support\Response;
|
|
|
|
final class WorkTimesheetController
|
|
{
|
|
public function index(Request $request): void
|
|
{
|
|
$user = Auth::requireUser();
|
|
|
|
$instructorId = (int) $request->query('instructor_id');
|
|
$from = (string) $request->query('from');
|
|
$to = (string) $request->query('to');
|
|
|
|
if ($instructorId <= 0 || $from === '' || $to === '') {
|
|
Response::json(['message' => 'instructor_id, from und to sind erforderlich'], 422);
|
|
}
|
|
|
|
$repo = new WorkTimesheetRepository();
|
|
$tenantId = (int) $user['tenant_id'];
|
|
|
|
$instructor = $repo->getInstructor($tenantId, $instructorId);
|
|
if ($instructor === null) {
|
|
Response::json(['message' => 'Fahrlehrer nicht gefunden'], 404);
|
|
}
|
|
|
|
$appointments = $repo->getAppointmentsForInstructor($tenantId, $instructorId, $from, $to);
|
|
|
|
// Gruppiere nach Datum
|
|
$daysMap = [];
|
|
foreach ($appointments as $apt) {
|
|
$date = date('Y-m-d', strtotime($apt['start_at']));
|
|
if (!isset($daysMap[$date])) {
|
|
$daysMap[$date] = [];
|
|
}
|
|
$daysMap[$date][] = $apt;
|
|
}
|
|
|
|
$days = [];
|
|
$typeSummaryMap = [];
|
|
|
|
foreach ($daysMap as $date => $aptList) {
|
|
$dayTotalMinutes = 0;
|
|
$dayTotalUe = 0.0;
|
|
|
|
$appointmentsOut = [];
|
|
foreach ($aptList as $apt) {
|
|
$startAt = new \DateTimeImmutable($apt['start_at']);
|
|
$endAt = new \DateTimeImmutable($apt['end_at']);
|
|
$durationMinutes = (int) round(($endAt->getTimestamp() - $startAt->getTimestamp()) / 60);
|
|
$ue = round((float) $apt['units'], 2);
|
|
|
|
$appointmentsOut[] = [
|
|
'type' => $apt['lesson_type_name'],
|
|
'start_at' => $startAt->format('H:i'),
|
|
'end_at' => $endAt->format('H:i'),
|
|
'duration_minutes' => $durationMinutes,
|
|
'ue' => $ue,
|
|
'ue_formatted' => self::formatUe($ue),
|
|
];
|
|
|
|
$dayTotalMinutes += $durationMinutes;
|
|
$dayTotalUe += $ue;
|
|
|
|
// Type summary
|
|
$typeKey = $apt['lesson_type_name'];
|
|
if (!isset($typeSummaryMap[$typeKey])) {
|
|
$typeSummaryMap[$typeKey] = ['type' => $apt['lesson_type_name'], 'total_minutes' => 0, 'total_ue' => 0.0, 'count' => 0];
|
|
}
|
|
$typeSummaryMap[$typeKey]['total_minutes'] += $durationMinutes;
|
|
$typeSummaryMap[$typeKey]['total_ue'] += $ue;
|
|
$typeSummaryMap[$typeKey]['count']++;
|
|
}
|
|
|
|
$days[] = [
|
|
'date' => $date,
|
|
'appointments' => $appointmentsOut,
|
|
'day_total_minutes' => $dayTotalMinutes,
|
|
'day_total_ue' => round($dayTotalUe, 2),
|
|
'day_total_ue_formatted' => self::formatUe($dayTotalUe),
|
|
];
|
|
}
|
|
|
|
// Gesamtsumme
|
|
$totalMinutes = 0;
|
|
$totalUe = 0.0;
|
|
foreach ($typeSummaryMap as $entry) {
|
|
$totalMinutes += $entry['total_minutes'];
|
|
$totalUe += $entry['total_ue'];
|
|
}
|
|
|
|
// Typ-Zusammenfassung sortieren
|
|
$typeSummary = array_values($typeSummaryMap);
|
|
usort($typeSummary, static fn($a, $b) => $a['type'] <=> $b['type']);
|
|
|
|
// UE formatiert
|
|
foreach ($typeSummary as &$entry) {
|
|
$entry['total_ue'] = round($entry['total_ue'], 2);
|
|
$entry['total_ue_formatted'] = self::formatUe($entry['total_ue']);
|
|
}
|
|
|
|
Response::json([
|
|
'data' => [
|
|
'instructor' => $instructor,
|
|
'period' => ['from' => $from, 'to' => $to],
|
|
'days' => $days,
|
|
'type_summary' => $typeSummary,
|
|
'summary' => [
|
|
'total_minutes' => $totalMinutes,
|
|
'total_ue' => round($totalUe, 2),
|
|
'total_ue_formatted' => self::formatUe($totalUe),
|
|
],
|
|
],
|
|
]);
|
|
}
|
|
|
|
private static function formatUe(float $ue): string
|
|
{
|
|
return str_replace('.', ',', number_format($ue, 2, ',', '')) . ' UE';
|
|
}
|
|
} |