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

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]);