265 lines
9.3 KiB
PHP
265 lines
9.3 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
require_once __DIR__ . '/db/config.php';
|
|
require_once '/usr/share/php/dompdf/autoload.php';
|
|
|
|
use Dompdf\Dompdf;
|
|
use Dompdf\Options;
|
|
|
|
// Simulate Tenant Context
|
|
$tenant_id = 1;
|
|
|
|
$report_type = $_GET['report_type'] ?? 'labour_export';
|
|
|
|
// Filter Data (Same as reports.php)
|
|
$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'] ?? [];
|
|
$f_activity = $_GET['activity_type_id'] ?? '';
|
|
|
|
// Handle Results for Labour Export
|
|
$results = [];
|
|
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);
|
|
$results = $stmt->fetchAll();
|
|
}
|
|
|
|
// Handle Calendar Report
|
|
$calendarData = [];
|
|
$cal_month = $_GET['month'] ?? date('Y-m');
|
|
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 filter names for header (Labour Export only)
|
|
$employee_name = 'All Employees';
|
|
if ($report_type === 'labour_export') {
|
|
if ($f_employee) {
|
|
$stmt = db()->prepare("SELECT name FROM employees WHERE id = ?");
|
|
$stmt->execute([$f_employee]);
|
|
$employee_name = $stmt->fetchColumn() ?: 'All Employees';
|
|
}
|
|
|
|
$project_names = 'All Projects';
|
|
if (!empty($f_projects)) {
|
|
$placeholders = implode(',', array_fill(0, count($f_projects), '?'));
|
|
$stmt = db()->prepare("SELECT name FROM projects WHERE id IN ($placeholders)");
|
|
$stmt->execute($f_projects);
|
|
$p_list = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
|
$project_names = implode(', ', $p_list);
|
|
}
|
|
}
|
|
|
|
// Generate HTML
|
|
$html = '
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<style>
|
|
body { font-family: Helvetica, Arial, sans-serif; font-size: 12px; color: #333; }
|
|
.header { text-align: center; margin-bottom: 20px; border-bottom: 2px solid #3b82f6; padding-bottom: 10px; }
|
|
.header h1 { margin: 0; color: #0f172a; font-size: 20px; }
|
|
.filters { margin-bottom: 20px; background: #f8fafc; padding: 10px; border-radius: 5px; border: 1px solid #e2e8f0; }
|
|
.filters table { width: 100%; }
|
|
.label { font-weight: bold; color: #64748b; font-size: 10px; }
|
|
table.data { width: 100%; border-collapse: collapse; margin-top: 10px; }
|
|
table.data th { background: #f1f5f9; color: #475569; text-align: left; padding: 8px; border: 1px solid #e2e8f0; text-transform: uppercase; font-size: 9px; }
|
|
table.data td { padding: 8px; border: 1px solid #e2e8f0; }
|
|
.text-end { text-align: right; }
|
|
.footer { margin-top: 30px; text-align: center; font-size: 9px; color: #94a3b8; }
|
|
.total-row { background: #f8fafc; font-weight: bold; }
|
|
.badge { background: #f1f5f9; padding: 2px 5px; border-radius: 3px; border: 1px solid #e2e8f0; font-size: 9px; }
|
|
|
|
/* Calendar Styles for PDF */
|
|
.calendar { width: 100%; border-collapse: collapse; table-layout: fixed; }
|
|
.calendar th { background: #f1f5f9; padding: 10px; border: 1px solid #e2e8f0; text-transform: uppercase; font-size: 10px; color: #64748b; }
|
|
.calendar td { height: 70px; vertical-align: top; padding: 5px; border: 1px solid #e2e8f0; background: #fff; }
|
|
.day-num { font-weight: bold; color: #94a3b8; margin-bottom: 5px; display: block; }
|
|
.day-hours { color: #3b82f6; font-weight: bold; font-size: 14px; text-align: right; display: block; margin-top: 10px; }
|
|
.other-month { background: #f8fafc; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="header">
|
|
<h1>' . ($report_type === 'calendar' ? 'Monthly Labour Calendar' : 'SR&ED Labour Report') . '</h1>
|
|
<p style="margin-top: 5px; color: #64748b;">Generated on ' . date('F j, Y, g:i a') . '</p>
|
|
</div>';
|
|
|
|
if ($report_type === 'labour_export') {
|
|
$html .= '
|
|
<div class="filters">
|
|
<table cellspacing="0" cellpadding="0">
|
|
<tr>
|
|
<td class="label" width="15%">Period:</td>
|
|
<td width="35%">' . date('M j, Y', strtotime($f_start)) . ' to ' . date('M j, Y', strtotime($f_end)) . '</td>
|
|
<td class="label" width="15%">Employee:</td>
|
|
<td width="35%">' . htmlspecialchars($employee_name) . '</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="label">Projects:</td>
|
|
<td colspan="3">' . htmlspecialchars($project_names) . '</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
|
|
<table class="data">
|
|
<thead>
|
|
<tr>
|
|
<th>Date</th>
|
|
<th>Employee</th>
|
|
<th>Project</th>
|
|
<th>Activity</th>
|
|
<th class="text-end">Hours</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>';
|
|
|
|
$total_hours = 0;
|
|
foreach ($results as $row) {
|
|
$total_hours += (float)$row['hours'];
|
|
$html .= '
|
|
<tr>
|
|
<td>' . $row['entry_date'] . '</td>
|
|
<td><strong>' . htmlspecialchars($row['employee_name']) . '</strong></td>
|
|
<td>' . htmlspecialchars($row['project_name']) . '</td>
|
|
<td><span class="badge">' . htmlspecialchars($row['labour_type'] ?? 'Uncategorized') . '</span></td>
|
|
<td class="text-end">' . number_format((float)$row['hours'], 2) . '</td>
|
|
</tr>';
|
|
}
|
|
|
|
if (empty($results)) {
|
|
$html .= '<tr><td colspan="5" style="text-align:center; padding: 20px;">No records found.</td></tr>';
|
|
}
|
|
|
|
$html .= '
|
|
</tbody>
|
|
<tfoot>
|
|
<tr class="total-row">
|
|
<td colspan="4" class="text-end">Total Hours:</td>
|
|
<td class="text-end" style="color: #3b82f6;">' . number_format($total_hours, 2) . '</td>
|
|
</tr>
|
|
</tfoot>
|
|
</table>';
|
|
} else {
|
|
// Calendar View
|
|
$html .= '
|
|
<div class="filters" style="text-align: center; font-size: 14px; font-weight: bold; color: #0f172a;">
|
|
' . date('F Y', strtotime($cal_month)) . '
|
|
</div>
|
|
|
|
<table class="calendar">
|
|
<thead>
|
|
<tr>
|
|
<th>Sun</th><th>Mon</th><th>Tue</th><th>Wed</th><th>Thu</th><th>Fri</th><th>Sat</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>';
|
|
|
|
$first_day = date('Y-m-01', strtotime($cal_month));
|
|
$days_in_month = (int)date('t', strtotime($cal_month));
|
|
$start_day_of_week = (int)date('w', strtotime($first_day));
|
|
|
|
$cal_day_count = 0;
|
|
$html .= '<tr>';
|
|
// Fill empty days before first of month
|
|
for ($i = 0; $i < $start_day_of_week; $i++) {
|
|
$html .= '<td class="other-month"></td>';
|
|
$cal_day_count++;
|
|
}
|
|
|
|
// Days of month
|
|
for ($day = 1; $day <= $days_in_month; $day++) {
|
|
if ($cal_day_count > 0 && ($cal_day_count % 7) == 0) {
|
|
$html .= '</tr><tr>';
|
|
}
|
|
|
|
$current_date = date('Y-m-', strtotime($cal_month)) . str_pad((string)$day, 2, '0', STR_PAD_LEFT);
|
|
$hours = $calendarData[$current_date] ?? 0;
|
|
|
|
$html .= '<td>';
|
|
$html .= '<span class="day-num">' . $day . '</span>';
|
|
if ($hours > 0) {
|
|
$html .= '<span class="day-hours">' . number_format((float)$hours, 1) . 'h</span>';
|
|
}
|
|
$html .= '</td>';
|
|
$cal_day_count++;
|
|
}
|
|
|
|
// Fill remaining days to complete grid
|
|
while ($cal_day_count % 7 != 0) {
|
|
$html .= '<td class="other-month"></td>';
|
|
$cal_day_count++;
|
|
}
|
|
$html .= '</tr>';
|
|
|
|
$html .= '
|
|
</tbody>
|
|
</table>';
|
|
}
|
|
|
|
$html .= '
|
|
<div class="footer">
|
|
<p>This report is for internal ERP and SR&ED documentation purposes.</p>
|
|
</div>
|
|
</body>
|
|
</html>';
|
|
|
|
// Setup Dompdf
|
|
$options = new Options();
|
|
$options->set('isHtml5ParserEnabled', true);
|
|
$options->set('isRemoteEnabled', true);
|
|
|
|
$dompdf = new Dompdf($options);
|
|
$dompdf->loadHtml($html);
|
|
$dompdf->setPaper('A4', 'portrait');
|
|
$dompdf->render();
|
|
|
|
// Output the PDF
|
|
$prefix = $report_type === 'calendar' ? 'Monthly_Calendar_' : 'Labour_Report_';
|
|
$filename = $prefix . date('Ymd_His') . '.pdf';
|
|
$dompdf->stream($filename, ['Attachment' => true]);
|