38438-vm/reports.php
2026-02-15 01:10:00 +00:00

371 lines
18 KiB
PHP

<?php
declare(strict_types=1);
require_once __DIR__ . '/db/config.php';
// Simulate Tenant Context
$tenant_id = 1;
$report_type = $_GET['report_type'] ?? 'labour_export';
// Filter Data for Export Report
$f_employee = $_GET['employee_id'] ?? '';
$f_team = $_GET['team_id'] ?? '';
$f_start = $_GET['start_date'] ?? date('Y-m-01');
$f_end = $_GET['end_date'] ?? date('Y-m-t');
$f_projects = $_GET['projects'] ?? []; // Array
$f_activity = $_GET['activity_type_id'] ?? '';
// Handle Results for Labour Export
$exportResults = [];
$chartData = [];
if ($report_type === 'labour_export') {
$query = "
SELECT le.*, p.name as project_name, e.name as employee_name, lt.name as labour_type
FROM labour_entries le
JOIN projects p ON le.project_id = p.id
JOIN employees e ON le.employee_id = e.id
LEFT JOIN labour_types lt ON le.labour_type_id = lt.id
WHERE le.tenant_id = ? AND le.entry_date BETWEEN ? AND ?
";
$params = [$tenant_id, $f_start, $f_end];
if ($f_employee) {
$query .= " AND le.employee_id = ?";
$params[] = $f_employee;
}
if ($f_team) {
$query .= " AND le.employee_id IN (SELECT employee_id FROM employee_teams WHERE team_id = ?)";
$params[] = $f_team;
}
if (!empty($f_projects)) {
$placeholders = implode(',', array_fill(0, count($f_projects), '?'));
$query .= " AND le.project_id IN ($placeholders)";
foreach ($f_projects as $pid) $params[] = $pid;
}
if ($f_activity) {
$query .= " AND le.labour_type_id = ?";
$params[] = $f_activity;
}
$query .= " ORDER BY le.entry_date ASC";
$stmt = db()->prepare($query);
$stmt->execute($params);
$exportResults = $stmt->fetchAll();
// Group for Chart (Hours per Day)
$grouped = [];
foreach ($exportResults as $row) {
$grouped[$row['entry_date']] = ($grouped[$row['entry_date']] ?? 0) + (float)$row['hours'];
}
ksort($grouped);
$chartData = [
'labels' => array_keys($grouped),
'values' => array_values($grouped)
];
}
// Handle Calendar Report
$cal_month = $_GET['month'] ?? date('Y-m');
$calendarData = [];
if ($report_type === 'calendar') {
$stmt = db()->prepare("
SELECT entry_date, SUM(hours) as total_hours
FROM labour_entries
WHERE tenant_id = ? AND DATE_FORMAT(entry_date, '%Y-%m') = ?
GROUP BY entry_date
");
$stmt->execute([$tenant_id, $cal_month]);
$calendarData = $stmt->fetchAll(PDO::FETCH_KEY_PAIR);
}
// Fetch helper data
$employees = db()->prepare("SELECT id, name FROM employees WHERE tenant_id = ? ORDER BY name");
$employees->execute([$tenant_id]);
$employeeList = $employees->fetchAll();
$teams = db()->prepare("SELECT id, name FROM teams WHERE tenant_id = ? ORDER BY name");
$teams->execute([$tenant_id]);
$teamList = $teams->fetchAll();
$projects = db()->prepare("SELECT id, name FROM projects WHERE tenant_id = ? ORDER BY name");
$projects->execute([$tenant_id]);
$projectList = $projects->fetchAll();
$labourTypes = db()->prepare("SELECT id, name FROM labour_types WHERE tenant_id = ? ORDER BY name");
$labourTypes->execute([$tenant_id]);
$labourTypeList = $labourTypes->fetchAll();
?>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>SR&ED Manager - Reports</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<link href="assets/css/custom.css?v=<?= time() ?>" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
</head>
<body>
<nav class="navbar navbar-expand-lg sticky-top">
<div class="container-fluid">
<a class="navbar-brand" href="index.php">SR&ED MANAGER</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav me-auto">
<li class="nav-item"><a class="nav-link" href="index.php">Dashboard</a></li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown">Projects</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="index.php">List Projects</a></li>
</ul>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle active" href="#" role="button" data-bs-toggle="dropdown">Reports</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="reports.php?report_type=labour_export">Labour Export</a></li>
<li><a class="dropdown-item" href="reports.php?report_type=calendar">Monthly Calendar</a></li>
</ul>
</li>
</ul>
</div>
</div>
</nav>
<div class="container-fluid py-4">
<div class="row mb-4">
<div class="col-12">
<div class="card border-0 shadow-sm">
<div class="card-body">
<ul class="nav nav-pills mb-3">
<li class="nav-item">
<a class="nav-link <?= $report_type === 'labour_export' ? 'active' : '' ?>" href="reports.php?report_type=labour_export">Labour Export</a>
</li>
<li class="nav-item">
<a class="nav-link <?= $report_type === 'calendar' ? 'active' : '' ?>" href="reports.php?report_type=calendar">Monthly Calendar</a>
</li>
</ul>
<?php if ($report_type === 'labour_export'): ?>
<form method="GET" class="row g-3 align-items-end">
<input type="hidden" name="report_type" value="labour_export">
<div class="col-md-3">
<label class="form-label small fw-bold">Employee</label>
<select name="employee_id" class="form-select form-select-sm">
<option value="">All Employees</option>
<?php foreach ($employeeList as $e): ?>
<option value="<?= $e['id'] ?>" <?= $f_employee == $e['id'] ? 'selected' : '' ?>><?= htmlspecialchars($e['name']) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-3">
<label class="form-label small fw-bold">Team</label>
<select name="team_id" class="form-select form-select-sm">
<option value="">All Teams</option>
<?php foreach ($teamList as $t): ?>
<option value="<?= $t['id'] ?>" <?= $f_team == $t['id'] ? 'selected' : '' ?>><?= htmlspecialchars($t['name']) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-3">
<label class="form-label small fw-bold">Start Date</label>
<input type="date" name="start_date" class="form-control form-control-sm" value="<?= $f_start ?>">
</div>
<div class="col-md-3">
<label class="form-label small fw-bold">End Date</label>
<input type="date" name="end_date" class="form-control form-control-sm" value="<?= $f_end ?>">
</div>
<div class="col-md-3">
<label class="form-label small fw-bold">Projects (Multi-select)</label>
<select name="projects[]" class="form-select form-select-sm" multiple style="height: 100px;">
<?php foreach ($projectList as $p): ?>
<option value="<?= $p['id'] ?>" <?= in_array($p['id'], $f_projects) ? 'selected' : '' ?>><?= htmlspecialchars($p['name']) ?></option>
<?php endforeach; ?>
</select>
<div class="extra-small text-muted">Hold Ctrl/Cmd to select multiple</div>
</div>
<div class="col-md-3">
<label class="form-label small fw-bold">Activity Type</label>
<select name="activity_type_id" class="form-select form-select-sm">
<option value="">All Activities</option>
<?php foreach ($labourTypeList as $lt): ?>
<option value="<?= $lt['id'] ?>" <?= $f_activity == $lt['id'] ? 'selected' : '' ?>><?= htmlspecialchars($lt['name']) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-3">
<button type="submit" class="btn btn-sm btn-primary w-100">Generate Report</button>
</div>
</form>
<?php else: ?>
<form method="GET" class="row g-3 align-items-end">
<input type="hidden" name="report_type" value="calendar">
<div class="col-md-3">
<label class="form-label small fw-bold">Select Month</label>
<input type="month" name="month" class="form-control form-control-sm" value="<?= $cal_month ?>">
</div>
<div class="col-md-3">
<button type="submit" class="btn btn-sm btn-primary w-100">View Calendar</button>
</div>
</form>
<?php endif; ?>
</div>
</div>
</div>
</div>
<?php if ($report_type === 'labour_export'): ?>
<div class="row">
<div class="col-lg-8">
<div class="card border-0 shadow-sm mb-4">
<div class="card-header bg-white d-flex justify-content-between align-items-center">
<h6 class="mb-0 fw-bold">Detailed Labour Records</h6>
<div class="btn-group">
<button class="btn btn-sm btn-outline-secondary" onclick="window.print()"><i class="bi bi-printer"></i> Print</button>
<a href="export_pdf.php?<?= http_build_query($_GET) ?>" class="btn btn-sm btn-primary"><i class="bi bi-file-earmark-pdf"></i> Download PDF</a>
</div>
</div>
<div class="table-responsive">
<table class="table align-middle mb-0">
<thead class="bg-light">
<tr>
<th>Date</th>
<th>Employee</th>
<th>Project</th>
<th>Activity</th>
<th class="text-end">Hours</th>
</tr>
</thead>
<tbody>
<?php if (empty($exportResults)): ?>
<tr><td colspan="5" class="text-center py-5 text-muted">No records found for the selected criteria.</td></tr>
<?php endif; ?>
<?php $total = 0; foreach ($exportResults as $row): $total += (float)$row['hours']; ?>
<tr>
<td><?= $row['entry_date'] ?></td>
<td><strong><?= htmlspecialchars($row['employee_name']) ?></strong></td>
<td><?= htmlspecialchars($row['project_name']) ?></td>
<td><span class="badge bg-light text-dark border"><?= htmlspecialchars($row['labour_type'] ?? 'Uncategorized') ?></span></td>
<td class="text-end fw-bold"><?= number_format((float)$row['hours'], 2) ?></td>
</tr>
<?php endforeach; ?>
</tbody>
<?php if (!empty($exportResults)): ?>
<tfoot class="bg-light">
<tr>
<td colspan="4" class="text-end fw-bold">Total Hours:</td>
<td class="text-end fw-bold text-primary"><?= number_format($total, 2) ?></td>
</tr>
</tfoot>
<?php endif; ?>
</table>
</div>
</div>
</div>
<div class="col-lg-4">
<div class="card border-0 shadow-sm">
<div class="card-header bg-white">
<h6 class="mb-0 fw-bold">Hours Breakdown</h6>
</div>
<div class="card-body">
<canvas id="exportChart" style="height: 300px;"></canvas>
</div>
</div>
</div>
</div>
<script>
const ctx = document.getElementById('exportChart').getContext('2d');
new Chart(ctx, {
type: 'bar',
data: {
labels: <?= json_encode($chartData['labels']) ?>,
datasets: [{
label: 'Hours',
data: <?= json_encode($chartData['values']) ?>,
backgroundColor: 'rgba(13, 110, 253, 0.2)',
borderColor: '#0d6efd',
borderWidth: 2,
borderRadius: 5
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: { legend: { display: false } },
scales: {
y: { beginAtZero: true, grid: { display: false } },
x: { grid: { display: false } }
}
}
});
</script>
<?php elseif ($report_type === 'calendar'): ?>
<div class="card border-0 shadow-sm">
<div class="card-header bg-white d-flex justify-content-between align-items-center">
<h6 class="mb-0 fw-bold">Monthly Labour Calendar - <?= date('F Y', strtotime($cal_month)) ?></h6>
<div class="btn-group">
<button class="btn btn-sm btn-outline-secondary" onclick="window.print()"><i class="bi bi-printer"></i> Print</button>
<a href="export_pdf.php?<?= http_build_query($_GET) ?>" class="btn btn-sm btn-primary"><i class="bi bi-file-earmark-pdf"></i> Download PDF</a>
</div>
</div>
<div class="card-body p-0">
<div class="calendar-grid">
<div class="calendar-header-day">Sun</div>
<div class="calendar-header-day">Mon</div>
<div class="calendar-header-day">Tue</div>
<div class="calendar-header-day">Wed</div>
<div class="calendar-header-day">Thu</div>
<div class="calendar-header-day">Fri</div>
<div class="calendar-header-day">Sat</div>
<?php
$first_day = date('Y-m-01', strtotime($cal_month));
$days_in_month = date('t', strtotime($cal_month));
$start_day_of_week = (int)date('w', strtotime($first_day));
// Fill empty days before first of month
for ($i = 0; $i < $start_day_of_week; $i++) {
echo '<div class="calendar-day other-month"></div>';
}
// Days of month
for ($day = 1; $day <= $days_in_month; $day++) {
$current_date = date('Y-m-', strtotime($cal_month)) . str_pad((string)$day, 2, '0', STR_PAD_LEFT);
$hours = $calendarData[$current_date] ?? 0;
?>
<div class="calendar-day">
<span class="day-number"><?= $day ?></span>
<?php if ($hours > 0): ?>
<span class="day-hours"><?= number_format((float)$hours, 1) ?><small class="ms-1 h6 mb-0" style="font-size: 0.6rem;">h</small></span>
<?php endif; ?>
</div>
<?php
}
// Fill remaining days to complete grid
$total_cells = ceil(($start_day_of_week + $days_in_month) / 7) * 7;
for ($i = ($start_day_of_week + $days_in_month); $i < $total_cells; $i++) {
echo '<div class="calendar-day other-month"></div>';
}
?>
</div>
</div>
</div>
<?php endif; ?>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>