report update
This commit is contained in:
parent
444cd73cc6
commit
bb0b464262
264
export_pdf.php
Normal file
264
export_pdf.php
Normal file
@ -0,0 +1,264 @@
|
||||
<?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]);
|
||||
11
reports.php
11
reports.php
@ -229,7 +229,10 @@ $labourTypeList = $labourTypes->fetchAll();
|
||||
<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>
|
||||
<button class="btn btn-sm btn-outline-secondary" onclick="window.print()"><i class="bi bi-printer"></i> Print / PDF</button>
|
||||
<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">
|
||||
@ -309,8 +312,12 @@ $labourTypeList = $labourTypes->fetchAll();
|
||||
|
||||
<?php elseif ($report_type === 'calendar'): ?>
|
||||
<div class="card border-0 shadow-sm">
|
||||
<div class="card-header bg-white">
|
||||
<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">
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user