331 lines
16 KiB
PHP
331 lines
16 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();
|
|
|
|
$pageTitle = "SR&ED Manager - Reports";
|
|
include __DIR__ . '/includes/header.php';
|
|
?>
|
|
|
|
<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>
|
|
|
|
<?php include __DIR__ . '/includes/footer.php'; ?>
|