« Back to History
warper_performance_report.php
|
20260920_164915.php
Initial Domain Snapshot
Copy Code
<?php /* ============================================================================ File: /erp/warper_performance_report.php Purpose: Warper Performance Report (date range) using company_beam_stock + Master Salary Snapshot ============================================================================*/ $acl_candidates = [ __DIR__ . '/modules/auth/page_acl.php', __DIR__ . '/../modules/auth/page_acl.php', __DIR__ . '/../../modules/auth/page_acl.php', __DIR__ . '/erp/modules/auth/page_acl.php', ]; $acl_loaded = false; foreach ($acl_candidates as $acl) { if (file_exists($acl)) { require_once $acl; $acl_loaded = true; break; } } if (!$acl_loaded) { die("ACL not found"); } /* Bootstrap + ACL */ $ctx = page_require_access('warper_performance_report'); $u = $ctx['user'] ?? null; $company_id = (int)($ctx['company_id'] ?? 0); $user_id = (int)($u['id'] ?? 0); $pdo = $ctx['pdo'] ?? null; /* fallback include only if $pdo not provided by $ctx */ if (!$pdo && file_exists(__DIR__ . '/core/db.php')) { require_once __DIR__ . '/core/db.php'; } /* Helpers */ if (!function_exists('h')) { function h($s){ return htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8'); } } /* Dompdf bootstrap */ $PDF_AVAILABLE = false; $dompdf_autoloaders = [ __DIR__ . '/lib/dompdf/autoload.inc.php', __DIR__ . '/vendor/autoload.php', ]; foreach ($dompdf_autoloaders as $autoload) { if (is_file($autoload)) { require_once $autoload; if (class_exists(\Dompdf\Dompdf::class)) { $PDF_AVAILABLE = true; break; } } } /* Input defaults */ $from = $_GET['from'] ?? date('Y-m-01'); $to = $_GET['to'] ?? date('Y-m-d'); $month_key = date('Y-m-01', strtotime($from)); $y = (int)date('Y', strtotime($month_key)); $m = (int)date('m', strtotime($month_key)); $snapshot_period = 'Monthly'; $day_num_from = (int)date('d', strtotime($from)); $day_num_to = (int)date('d', strtotime($to)); if ($day_num_from === 1 && $day_num_to <= 15) { $snapshot_period = 'H1'; } elseif ($day_num_from >= 16) { $snapshot_period = 'H2'; } /* Ensure master_salary_snapshots table exists with report_type */ $snapshot_ddl = <<<SQL CREATE TABLE IF NOT EXISTS master_salary_snapshots ( id INT AUTO_INCREMENT PRIMARY KEY, company_id BIGINT UNSIGNED NOT NULL, salary_year INT NOT NULL, salary_month INT NOT NULL, period VARCHAR(20) NOT NULL, report_type VARCHAR(50) NOT NULL, report_html LONGTEXT NOT NULL, created_by BIGINT UNSIGNED NOT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY unique_report (company_id, salary_year, salary_month, period, report_type) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; SQL; if ($pdo) { $pdo->exec($snapshot_ddl); } /* Handle Save Snapshot Action with report_type = 'Warper' */ if (($_POST['action'] ?? '') === 'save_snapshot') { $report_html = $_POST['report_html'] ?? ''; $snapshot_period = $_POST['period'] ?? $snapshot_period; $report_type = 'Warper'; if (!empty($report_html) && $pdo) { try { $stmt = $pdo->prepare(" INSERT INTO master_salary_snapshots (company_id, salary_year, salary_month, period, report_type, report_html, created_by) VALUES (?, ?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE report_html = VALUES(report_html), created_by = VALUES(created_by), created_at = NOW() "); $stmt->execute([$company_id, $y, $m, $snapshot_period, $report_type, $report_html, $user_id]); header("Location: warper_performance_report.php?from={$from}&to={$to}&snapshot_saved=1"); exit; } catch (Throwable $e) { http_response_code(500); exit("Error saving snapshot: " . htmlspecialchars($e->getMessage())); } } } $report = []; $employee_summary = []; $quality_summary = []; $overall = ['total_beams'=>0,'total_taka'=>0.0,'total_meter'=>0.0,'days'=>1]; $db_error = null; if (isset($_GET['from']) || true) { try { $dt1 = new DateTime($from); $dt2 = new DateTime($to); $overall['days'] = max(1, $dt1->diff($dt2)->days + 1); } catch (Exception $e) { $overall['days'] = 1; } if (!$pdo) { $db_error = "Database connection not available (missing \$ctx['pdo'])."; } else { try { $sql = " SELECT cbs.id, cbs.warp_date AS entry_date, cbs.taka, cbs.meter, q.name AS quality_name, cem.name AS employee_name FROM company_beam_stock cbs JOIN company_employee_master cem ON cem.id = cbs.warper_id AND cem.company_id = cbs.company_id AND cem.is_active = 1 AND cem.department_id = 22 LEFT JOIN beam_qualities q ON q.id = cbs.quality_id AND q.company_id = cbs.company_id WHERE cbs.company_id = :cid AND cbs.warp_date BETWEEN :f AND :t AND cbs.warper_id IS NOT NULL ORDER BY cbs.warp_date ASC, cbs.id ASC "; $stmt = $pdo->prepare($sql); $stmt->execute([ ':cid' => $company_id, ':f' => $from, ':t' => $to, ]); $report = $stmt->fetchAll(PDO::FETCH_ASSOC); /* Build summaries */ foreach ($report as $r) { $overall['total_beams']++; $taka = (float)($r['taka'] ?? 0); $meter = (float)($r['meter'] ?? 0); $overall['total_taka'] += $taka; $overall['total_meter'] += $meter; $ename = trim($r['employee_name'] ?? '') ?: 'Unknown'; if (!isset($employee_summary[$ename])) $employee_summary[$ename] = ['beams'=>0,'taka'=>0.0,'meter'=>0.0]; $employee_summary[$ename]['beams']++; $employee_summary[$ename]['taka'] += $taka; $employee_summary[$ename]['meter'] += $meter; $qname = trim($r['quality_name'] ?? '') ?: 'Unknown'; if (!isset($quality_summary[$qname])) $quality_summary[$qname] = ['beams'=>0,'taka'=>0.0,'meter'=>0.0]; $quality_summary[$qname]['beams']++; $quality_summary[$qname]['taka'] += $taka; $quality_summary[$qname]['meter'] += $meter; } } catch (PDOException $e) { $db_error = $e->getMessage(); } catch (Exception $e) { $db_error = $e->getMessage(); } } } if (($_GET['export'] ?? '') === 'pdf') { if (!$PDF_AVAILABLE) { http_response_code(503); header('Content-Type: text/html; charset=UTF-8'); echo '<h3>PDF export unavailable</h3><p>Dompdf is not installed on this server.</p>'; exit; } ob_start(); ?> <!doctype html> <html> <head> <meta charset="utf-8"> <title>Warper Performance Report PDF</title> <style> @page { margin: 12px 12px; } body { margin: 0; font-family: DejaVu Sans, sans-serif; font-size: 8px; color: #111; } h1 { margin: 0 0 4px; font-size: 13px; } .subhead { margin: 0 0 10px; color: #555; font-size: 9px; } h2 { margin: 12px 0 6px; font-size: 11px; } table { width: 100%; border-collapse: collapse; table-layout: fixed; margin-bottom: 12px; } th, td { border: 1px solid #d9d9d9; padding: 4px 3px; vertical-align: middle; word-break: break-word; } th { background: #f3f4f6; font-size: 7px; } td { font-size: 8px; } </style> </head> <body> <h1>Warper Performance Report</h1> <div class="subhead">From <?= h($from) ?> to <?= h($to) ?></div> <?php if ($db_error): ?> <p><strong>Database error:</strong> <?= h($db_error) ?></p> <?php elseif (!empty($report)): ?> <h2>Overall Summary</h2> <table> <tr> <th>Total Beams</th> <td><?= h($overall['total_beams']) ?></td> <th>Avg Beams / Day</th> <td><?= h(round($overall['total_beams'] / $overall['days'], 2)) ?></td> </tr> <tr> <th>Total Taka</th> <td><?= h(round($overall['total_taka'], 2)) ?></td> <th>Avg Taka / Day</th> <td><?= h(round($overall['total_taka'] / $overall['days'], 2)) ?></td> </tr> <tr> <th>Total Meter</th> <td><?= h(round($overall['total_meter'], 2)) ?></td> <th>Avg Meter / Day</th> <td><?= h(round($overall['total_meter'] / $overall['days'], 2)) ?></td> </tr> <tr> <th>Days</th> <td><?= h($overall['days']) ?></td> <td></td> <td></td> </tr> </table> <h2>Quality-wise Summary</h2> <table> <thead> <tr> <th>Quality</th> <th>Beams</th> <th>Avg Beams / Day</th> <th>Taka</th> <th>Avg Taka / Day</th> <th>Meter</th> <th>Avg Meter / Day</th> </tr> </thead> <tbody> <?php foreach ($quality_summary as $qname => $vals): $avg_beams = round($vals['beams'] / max(1, $overall['days']), 2); $avg_taka = round($vals['taka'] / max(1, $overall['days']), 2); $avg_meter = round($vals['meter'] / max(1, $overall['days']), 2); ?> <tr> <td><?= h($qname) ?></td> <td><?= h($vals['beams']) ?></td> <td><?= h($avg_beams) ?></td> <td><?= h(round($vals['taka'], 2)) ?></td> <td><?= h($avg_taka) ?></td> <td><?= h(round($vals['meter'], 2)) ?></td> <td><?= h($avg_meter) ?></td> </tr> <?php endforeach; ?> </tbody> </table> <h2>Employee-wise Summary</h2> <table> <thead> <tr> <th>Employee</th> <th>Beams</th> <th>Avg Beams / Day</th> <th>Taka</th> <th>Avg Taka / Day</th> <th>Meter</th> <th>Avg Meter / Day</th> </tr> </thead> <tbody> <?php foreach ($employee_summary as $ename => $vals): $avg_beams = round($vals['beams'] / max(1, $overall['days']), 2); $avg_taka = round($vals['taka'] / max(1, $overall['days']), 2); $avg_meter = round($vals['meter'] / max(1, $overall['days']), 2); ?> <tr> <td><?= h($ename) ?></td> <td><?= h($vals['beams']) ?></td> <td><?= h($avg_beams) ?></td> <td><?= h(round($vals['taka'], 2)) ?></td> <td><?= h($avg_taka) ?></td> <td><?= h(round($vals['meter'], 2)) ?></td> <td><?= h($avg_meter) ?></td> </tr> <?php endforeach; ?> </tbody> </table> <?php else: ?> <p>No entries for selected dates. Choose a different range.</p> <?php endif; ?> </body> </html> <?php $pdfHtml = ob_get_clean(); $dompdf = new \Dompdf\Dompdf([ 'isRemoteEnabled' => false, 'defaultFont' => 'DejaVu Sans', ]); $dompdf->loadHtml($pdfHtml, 'UTF-8'); $dompdf->setPaper('A4', 'portrait'); $dompdf->render(); $filename = 'warper_performance_' . preg_replace('/[^0-9-]/', '', $from) . '_to_' . preg_replace('/[^0-9-]/', '', $to) . '.pdf'; $dompdf->stream($filename, ['Attachment' => true]); exit; } /* Include header (mandatory) */ require_once __DIR__ . '/partials/header.php'; ?> <div class="container mt-4 page-warper-report"> <div class="card p-4"> <?php if (isset($_GET['snapshot_saved'])): ?> <div class="alert alert-success alert-dismissible fade show border-0 shadow-sm mb-4" role="alert" style="background:#d4edda;color:#155724;padding:10px;border-radius:8px;"> <i class="bi bi-cloud-check-fill me-2"></i> Successfully saved to Master Salary Report! <button type="button" class="btn-close" data-bs-dismiss="alert"></button> </div> <?php endif; ?> <!-- TOP TOOLBAR (Title + Print / Export) --> <div class="report-toolbar" style="display:flex;justify-content:space-between;align-items:center;gap:12px;"> <div> <h2 class="m-0">Warper Performance Report</h2> <div class="text-muted">Choose date range to view summary</div> </div> <div class="report-actions d-flex gap-2"> <?php $pdf_qs = http_build_query(['from' => $from, 'to' => $to, 'export' => 'pdf']); ?> <button type="button" class="btn btn-outline-secondary" id="btn-print">Print</button> <a class="btn btn-outline-primary" href="?<?= h($pdf_qs) ?>">Export PDF</a> <a class="btn btn-light" href="#" onclick="window.location.reload(); return false;">Reset</a> </div> </div> <hr /> <!-- Filter form --> <form method="get" class="form-grid mb-4" autocomplete="off"> <div> <label>From Date</label> <input type="date" name="from" class="form-control" value="<?= h($from) ?>"> </div> <div> <label>To Date</label> <input type="date" name="to" class="form-control" value="<?= h($to) ?>"> </div> <div class="align-end"> <button class="btn btn-primary mt-4">Show</button> </div> </form> <!-- Save to Master Salary Snapshot Form with Period Selector --> <?php if (!empty($report)): ?> <form method="post" class="d-inline-flex gap-2 align-items-center mb-3" id="snapshotForm"> <input type="hidden" name="action" value="save_snapshot"> <input type="hidden" name="period" id="snapshotPeriodField" value="<?= h($snapshot_period); ?>"> <textarea name="report_html" id="reportHtmlField" style="display:none;"></textarea> <select name="snapshot_period_ui" id="snapshotPeriodUi" class="form-select form-select-sm w-auto"> <option value="H2" <?= ($snapshot_period === 'H2') ? 'selected' : ''; ?>>H2 (16–End)</option> <option value="H1" <?= ($snapshot_period === 'H1') ? 'selected' : ''; ?>>H1 (1–15)</option> <option value="Monthly" <?= ($snapshot_period === 'Monthly') ? 'selected' : ''; ?>>Monthly</option> </select> <button type="button" onclick="saveReportSnapshot()" class="btn btn-dark btn-sm"> <i class="bi bi-cloud-upload me-1"></i> Save to Master Salary </button> </form> <?php endif; ?> <?php if ($db_error): ?> <div class="alert alert-danger"> <strong>Database error:</strong> <?= h($db_error) ?> </div> <?php endif; ?> <div id="reportContent"> <?php if (!empty($report)): ?> <!-- Overall Summary --> <section id="overall-summary" class="mb-3"> <h4>Overall Summary</h4> <table class="table table-sm"> <tr> <th>Total Beams</th> <td><?= h($overall['total_beams']) ?></td> <th>Avg Beams / Day</th> <td><?= h(round($overall['total_beams'] / $overall['days'], 2)) ?></td> </tr> <tr> <th>Total Taka</th> <td><?= h(round($overall['total_taka'],2)) ?></td> <th>Avg Taka / Day</th> <td><?= h(round($overall['total_taka'] / $overall['days'], 2)) ?></td> </tr> <tr> <th>Total Meter</th> <td><?= h(round($overall['total_meter'],2)) ?></td> <th>Avg Meter / Day</th> <td><?= h(round($overall['total_meter'] / $overall['days'], 2)) ?></td> </tr> <tr> <th>Days</th> <td><?= h($overall['days']) ?></td> <td></td><td></td> </tr> </table> </section> <!-- Quality-wise Summary --> <section id="quality-summary" class="mb-3"> <h4>Quality-wise Summary</h4> <table class="table table-bordered table-sm table-color-quality"> <thead> <tr> <th>Quality</th> <th>Beams</th> <th>Avg Beams / Day</th> <th>Taka</th> <th>Avg Taka / Day</th> <th>Meter</th> <th>Avg Meter / Day</th> </tr> </thead> <tbody> <?php foreach ($quality_summary as $qname => $vals): $avg_beams = round($vals['beams'] / max(1, $overall['days']), 2); $avg_taka = round($vals['taka'] / max(1, $overall['days']), 2); $avg_meter = round($vals['meter'] / max(1, $overall['days']), 2); ?> <tr> <td><?= h($qname) ?></td> <td><?= h($vals['beams']) ?></td> <td><?= h($avg_beams) ?></td> <td><?= h(round($vals['taka'],2)) ?></td> <td><?= h($avg_taka) ?></td> <td><?= h(round($vals['meter'],2)) ?></td> <td><?= h($avg_meter) ?></td> </tr> <?php endforeach; ?> </tbody> </table> </section> <!-- Employee-wise Summary --> <section id="employee-summary" class="mb-3"> <h4>Employee-wise Summary</h4> <table class="table table-bordered table-sm table-color-employee"> <thead> <tr> <th>Employee</th> <th>Beams</th> <th>Avg Beams / Day</th> <th>Taka</th> <th>Avg Taka / Day</th> <th>Meter</th> <th>Avg Meter / Day</th> </tr> </thead> <tbody> <?php foreach ($employee_summary as $ename => $vals): $avg_beams = round($vals['beams'] / max(1, $overall['days']), 2); $avg_taka = round($vals['taka'] / max(1, $overall['days']), 2); $avg_meter = round($vals['meter'] / max(1, $overall['days']), 2); ?> <tr> <td><?= h($ename) ?></td> <td><?= h($vals['beams']) ?></td> <td><?= h($avg_beams) ?></td> <td><?= h(round($vals['taka'],2)) ?></td> <td><?= h($avg_taka) ?></td> <td><?= h(round($vals['meter'],2)) ?></td> <td><?= h($avg_meter) ?></td> </tr> <?php endforeach; ?> </tbody> </table> </section> <?php else: ?> <?php if (!$db_error): ?> <div class="alert alert-info mt-3">No entries for selected dates. Choose a different range.</div> <?php endif; ?> <?php endif; ?> </div> </div> <!-- card --> </div> <!-- container --> <!-- Small JS to trigger print/export/snapshot --> <script> document.getElementById('btn-print').addEventListener('click', function(){ window.print(); }); function saveReportSnapshot() { const reportContent = document.getElementById('reportContent').innerHTML; document.getElementById('reportHtmlField').value = reportContent; const uiVal = document.getElementById('snapshotPeriodUi').value; document.getElementById('snapshotPeriodField').value = uiVal; document.getElementById('snapshotForm').submit(); } </script> <?php /* Footer include (mandatory) */ require_once __DIR__ . '/partials/footer.php'; ?>