« Back to History
karigar_efficiency_report.php
|
20260920_164915.php
Initial Domain Snapshot
Copy Code
<?php /* ============================================================================= File: karigar_efficiency_report.php Purpose: Karigar Efficiency Report with Master Salary Snapshot Integration ============================================================================= */ header('X-Frame-Options: SAMEORIGIN'); error_reporting(E_ALL); ini_set('display_errors', 1); /* ---- Auth + DB (Project Standard matching monthly_salary_report.php) ---- */ require_once __DIR__ . '/modules/auth/auth.php'; require_login(); $u = auth_user(); $company_id = (int)$u['company_id']; $USER_ID = (int)$u['id']; $pdo = $GLOBALS['pdo'] ?? null; if (!$pdo) { require_once __DIR__ . '/core/db.php'; } /* ---- shared partial candidates ---- */ $header_candidates = [ __DIR__ . '/partials/header.php', __DIR__ . '/erp/partials/header.php', __DIR__ . '/../erp/partials/header.php', __DIR__ . '/../../erp/partials/header.php' ]; $footer_candidates = [ __DIR__ . '/partials/footer.php', __DIR__ . '/erp/partials/footer.php', __DIR__ . '/../erp/partials/footer.php', __DIR__ . '/../../erp/partials/footer.php' ]; /* ---- CSRF & Session ---- */ if (session_status() !== PHP_SESSION_ACTIVE) session_start(); if (empty($_SESSION['csrf'])) $_SESSION['csrf'] = bin2hex(random_bytes(16)); function csrf_field(){ echo '<input type="hidden" name="csrf" value="'.htmlspecialchars($_SESSION['csrf']).'">'; } function check_csrf(){ if (($_POST['csrf'] ?? '') !== ($_SESSION['csrf'] ?? '')) { http_response_code(403); exit('Bad CSRF'); }} function h($v){ return htmlspecialchars((string)$v, ENT_QUOTES, 'UTF-8'); } function include_first_existing(array $candidates): bool { foreach ($candidates as $candidate) { if (file_exists($candidate)) { require_once $candidate; return true; } } return false; } /* ---- Ensure master_salary_snapshots table exists ---- */ $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; $pdo->exec($snapshot_ddl); /* ---- fetch company name ---- */ try { $stComp = $pdo->prepare("SELECT name FROM companies WHERE id = ? LIMIT 1"); $stComp->execute([$company_id]); $company_name = $stComp->fetchColumn(); } catch (Throwable $e) { $company_name = ''; } if (!$company_name) $company_name = 'Company'; /* 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; } } } // --- Config / thresholds --- $SINGLE_DAY_THRESHOLD = 50; $SHIFT_MINUTES = 720; $EXPORT = $_GET['export'] ?? ''; $PRINT_ONLY = (isset($_GET['print']) && $_GET['print'] == '1'); // --- Sorting param --- $SORT = $_GET['sort'] ?? 'eff_desc'; $allowed_sorts = ['eff_desc','eff_asc','meter_desc','meter_asc']; if (!in_array($SORT, $allowed_sorts)) $SORT = 'eff_desc'; // --- Input filters --- $from = $_GET['from'] ?? date('Y-m-01'); $to = $_GET['to'] ?? date('Y-m-d'); $karigar_filter = !empty($_GET['karigar']) ? (int)$_GET['karigar'] : 0; $machine_filter = !empty($_GET['machine']) ? (int)$_GET['machine'] : 0; $quality_filter = !empty($_GET['quality']) ? (int)$_GET['quality'] : 0; $from_dt = date('Y-m-d', strtotime($from)); $to_dt = date('Y-m-d', strtotime($to)); $from_date_obj = new DateTime($from_dt); $s_year = (int)$from_date_obj->format('Y'); $s_month = (int)$from_date_obj->format('n'); $snapshot_period = 'H2'; $day_num_from = (int)$from_date_obj->format('d'); $day_num_to = (int)(new DateTime($to_dt))->format('d'); if ($day_num_from === 1 && $day_num_to <= 15) { $snapshot_period = 'H1'; } elseif ($day_num_from >= 16) { $snapshot_period = 'H2'; } // --- Handle Save Snapshot Action --- if (($_POST['action'] ?? '') === 'save_snapshot') { check_csrf(); $report_html = $_POST['report_html'] ?? ''; $snapshot_period = $_POST['period'] ?? $snapshot_period; $report_type = 'KarigarEfficiency'; if (!empty($report_html)) { 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, $s_year, $s_month, $snapshot_period, $report_type, $report_html, $USER_ID]); $qs = http_build_query(array_merge($_GET, ['snapshot_saved' => 1])); header("Location: ?" . $qs); exit; } catch (Throwable $e) { http_response_code(500); exit("Error saving snapshot: " . htmlspecialchars($e->getMessage())); } } } // --- Load karigar list --- $karigars = []; try { $st = $pdo->prepare("SELECT id, karigar_name FROM loom_karigar_master WHERE company_id = :cid AND is_active = 1 ORDER BY karigar_name"); $st->execute([':cid'=>$company_id]); while($r = $st->fetch(PDO::FETCH_ASSOC)) $karigars[] = $r; } catch (Throwable $e) {} // --- Load machines list --- $machines = []; try { $st = $pdo->prepare("SELECT DISTINCT machine_from AS machine_no FROM loom_karigar_master WHERE company_id = :cid ORDER BY machine_from"); $st->execute([':cid'=>$company_id]); while($r = $st->fetch(PDO::FETCH_ASSOC)) $machines[] = $r; } catch (Throwable $e) {} // --- Load qualities --- $qualities = []; try { $st = $pdo->prepare("SELECT id, quality_name, avg_per_day_pro FROM qualities WHERE company_id = :cid"); $st->execute([':cid'=>$company_id]); while($r = $st->fetch(PDO::FETCH_ASSOC)) { $qualities[(int)$r['id']] = [ 'name' => $r['quality_name'], 'avg' => (float)$r['avg_per_day_pro'] ]; } } catch (Throwable $e) {} // --- Load production entries --- $sql = "SELECT id, entry_date, machine_id, quality_id, meter_total, lines_json FROM production_entry WHERE company_id = :cid AND entry_date BETWEEN :from AND :to"; $params = [':cid'=>$company_id, ':from'=>$from_dt, ':to'=>$to_dt]; if ($machine_filter) { $sql .= " AND machine_id = :machine"; $params[':machine'] = $machine_filter; } if ($quality_filter) { $sql .= " AND quality_id = :quality"; $params[':quality'] = $quality_filter; } $production_rows = []; try { $st = $pdo->prepare($sql); $st->execute($params); $production_rows = $st->fetchAll(PDO::FETCH_ASSOC); } catch (Throwable $e) { echo "<pre>Error loading production entries: " . h($e->getMessage()) . "</pre>"; exit; } $dates_set = []; $karigar_map = []; $data_by_karigar = []; $machine_list_used = []; foreach($production_rows as $row) { $entry_date = date('Y-m-d', strtotime($row['entry_date'])); $dates_set[$entry_date] = true; $machine_no = (int)$row['machine_id']; $machine_list_used[$machine_no] = true; $lj = $row['lines_json']; $lines = []; if (!empty($lj)) { $decoded = json_decode($lj, true); if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) { $lines = $decoded; } } if (empty($lines)) continue; foreach($lines as $ln) { $kid = (int)($ln['karigar_id'] ?? 0); $meter = (float)($ln['meter'] ?? 0); if ($kid <= 0) continue; $data_by_karigar[$kid][$entry_date][$machine_no] = ($data_by_karigar[$kid][$entry_date][$machine_no] ?? 0) + $meter; } } if (!empty($data_by_karigar)) { $k_ids = array_keys($data_by_karigar); $placeholders = implode(',', array_fill(0, count($k_ids), '?')); try { $q = $pdo->prepare("SELECT id, karigar_name FROM loom_karigar_master WHERE company_id = ? AND id IN ($placeholders)"); $params = array_merge([$company_id], $k_ids); $q->execute($params); while($r = $q->fetch(PDO::FETCH_ASSOC)) { $karigar_map[(int)$r['id']] = $r['karigar_name']; } } catch (Throwable $e) {} } $downtime_map = []; if (!empty($machine_list_used)) { $machine_ids = array_keys($machine_list_used); $placeholders = implode(',', array_fill(0, count($machine_ids), '?')); $sql = "SELECT machine_no, downtime_date, SUM(duration_minutes) as total_minutes FROM loom_downtime WHERE company_id = ? AND status = 'closed' AND downtime_date BETWEEN ? AND ? AND machine_no IN ($placeholders) GROUP BY machine_no, downtime_date"; $params = array_merge([$company_id, $from_dt, $to_dt], $machine_ids); try { $q = $pdo->prepare($sql); $q->execute($params); while($r = $q->fetch(PDO::FETCH_ASSOC)) { $m = (int)$r['machine_no']; $d = date('Y-m-d', strtotime($r['downtime_date'])); $downtime_map[$m][$d] = (float)$r['total_minutes']; } } catch (Throwable $e) {} } $all_dates = array_keys($dates_set); sort($all_dates); $report_rows = []; foreach($data_by_karigar as $kid => $date_map) { if ($karigar_filter && $kid !== $karigar_filter) continue; $row = [ 'karigar_id' => $kid, 'karigar_name' => $karigar_map[$kid] ?? ('#'.$kid), 'per_date' => [], 'machines' => [], 'total_meter' => 0.0, 'expected_total' => 0.0, 'downtime_adj_expected_total' => 0.0, 'work_days' => 0 ]; foreach($all_dates as $date) { $day_total_for_karigar = 0.0; $machines_in_date = []; if (!empty($date_map[$date])) { foreach($date_map[$date] as $machine_no => $meter) { $day_total_for_karigar += $meter; $machines_in_date[] = $machine_no; $row['machines'][$machine_no] = true; } } $date_entries = []; foreach($data_by_karigar as $other_kid => $om) { if (empty($om[$date])) continue; foreach($om[$date] as $mno => $m_meter) { $date_entries[$mno][$other_kid] = ($date_entries[$mno][$other_kid] ?? 0) + $m_meter; } } $date_expected = 0.0; $date_meter = 0.0; $date_downtime_total_minutes = 0.0; if (!empty($machines_in_date)) { foreach($machines_in_date as $machine_no) { $karigar_meter_on_machine = (float)($date_map[$date][$machine_no] ?? 0); $machine_total_that_day = 0.0; if (!empty($date_entries[$machine_no])) { foreach($date_entries[$machine_no] as $mk => $mv) $machine_total_that_day += $mv; } $quality_id = 0; try { $q = $pdo->prepare("SELECT quality_id FROM production_entry WHERE company_id = :cid AND entry_date = :d AND machine_id = :m LIMIT 1"); $q->execute([':cid'=>$company_id, ':d'=>$date, ':m'=>$machine_no]); $qual_row = $q->fetch(PDO::FETCH_ASSOC); $quality_id = $qual_row ? (int)$qual_row['quality_id'] : ($quality_filter ?: 0); } catch (Throwable $e) { $quality_id = $quality_filter ?: 0; } $quality_avg = ($qualities[$quality_id]['avg'] ?? 0.0); $downtime_minutes = (float)($downtime_map[$machine_no][$date] ?? 0.0); if ($downtime_minutes >= $SHIFT_MINUTES || $machine_total_that_day <= 0) continue; $others_total = $machine_total_that_day - $karigar_meter_on_machine; $is_single_full_day = ($karigar_meter_on_machine >= $SINGLE_DAY_THRESHOLD && $others_total <= 0.0001); $base_expected = $is_single_full_day ? $quality_avg : ($quality_avg / 2.0); $working_minutes = max(0, $SHIFT_MINUTES - $downtime_minutes); if ($working_minutes <= 0) continue; $adjusted_expected = $base_expected * ($working_minutes / $SHIFT_MINUTES); $date_expected += $adjusted_expected; $date_meter += $karigar_meter_on_machine; $date_downtime_total_minutes += $downtime_minutes; } } if ($date_meter <= 0 || $date_expected <= 0) { $row['per_date'][$date] = ['meter'=>$date_meter, 'expected'=>0.0, 'downtime'=>$date_downtime_total_minutes, 'skip'=>true]; continue; } $row['work_days'] += 1; $row['total_meter'] += $date_meter; $row['expected_total'] += $date_expected; $row['downtime_adj_expected_total'] += $date_expected; $row['per_date'][$date] = ['meter'=>$date_meter, 'expected'=>$date_expected, 'downtime'=>$date_downtime_total_minutes, 'skip'=>false]; } if ($row['work_days'] > 0) { $row['efficiency'] = $row['expected_total'] > 0 ? ($row['total_meter'] / $row['expected_total']) * 100.0 : 0.0; $report_rows[] = $row; } } // --- Sorting --- if (!empty($report_rows)) { usort($report_rows, function($a, $b) use ($SORT) { if (strpos($SORT, 'meter_') === 0) { $ma = $a['total_meter'] ?? 0; $mb = $b['total_meter'] ?? 0; if ($ma == $mb) return 0; return ($SORT === 'meter_desc') ? (($ma < $mb) ? 1 : -1) : (($ma > $mb) ? 1 : -1); } else { $ea = $a['efficiency'] ?? 0; $eb = $b['efficiency'] ?? 0; if ($ea == $eb) return 0; return ($SORT === 'eff_desc') ? (($ea < $eb) ? 1 : -1) : (($ea > $eb) ? 1 : -1); } }); } // --- Handle CSV export --- if ($EXPORT === 'csv') { header('Content-Type: text/csv; charset=utf-8'); header('Content-Disposition: attachment; filename=karigar_efficiency_' . date('Ymd_His') . '.csv'); $out = fopen('php://output', 'w'); $date_headers = $all_dates; $cols = array_merge(['Karigar', 'Machines', 'Work Days', 'Total Meter', 'Expected Total', 'Performance %'], $date_headers); fputcsv($out, $cols); foreach($report_rows as $r) { $machines_list = implode(',', array_keys($r['machines'])); $base = [$r['karigar_name'], $machines_list, $r['work_days'], round($r['total_meter'], 2), round($r['expected_total'], 2), round($r['efficiency'], 2)]; foreach($date_headers as $d) { $cell = $r['per_date'][$d] ?? null; $base[] = (!$cell || $cell['skip']) ? '' : round($cell['meter'],2); } fputcsv($out, $base); } fclose($out); exit; } // --- PDF export --- if ($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>Karigar Performance Report PDF</title> <style> @page { margin: 10px 10px; } body { margin: 0; font-family: DejaVu Sans, sans-serif; font-size: 7px; color: #111; } h1 { margin: 0 0 4px; font-size: 11px; } .subhead { margin: 0 0 8px; color: #555; font-size: 8px; } table { width: 100%; border-collapse: collapse; table-layout: fixed; margin-bottom: 12px; } th, td { border: 1px solid #d9d9d9; padding: 3px 2px; vertical-align: middle; word-break: break-word; } th { background: #f3f4f6; font-size: 6px; } td { font-size: 7px; } </style> </head> <body> <h1>Karigar Performance Report</h1> <div class="subhead">Company: <?= h($company_name) ?> | Period: <?= h($from_dt) ?> - <?= h($to_dt) ?></div> <table> <thead> <tr> <th>Karigar</th><th>Machines</th><th>Work Days</th><th>Total Meter</th><th>Expected Total</th><th>Performance %</th> <?php foreach($all_dates as $date): ?><th><?= h($date) ?></th><?php endforeach; ?> </tr> </thead> <tbody> <?php foreach($report_rows as $r): ?> <tr> <td><?= h($r['karigar_name']) ?></td> <td><?= h(implode(',', array_keys($r['machines']))) ?></td> <td><?= h($r['work_days']) ?></td> <td><?= h(round($r['total_meter'], 2)) ?></td> <td><?= h(round($r['expected_total'], 2)) ?></td> <td><?= h(round($r['efficiency'], 2)) ?></td> <?php foreach($all_dates as $date): $cell = $r['per_date'][$date] ?? null; ?> <td><?= (!$cell || $cell['skip']) ? '' : h(round($cell['meter'], 2)) ?></td> <?php endforeach; ?> </tr> <?php endforeach; ?> </tbody> </table> </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(); $dompdf->stream('karigar_efficiency_' . $from_dt . '.pdf', ['Attachment' => true]); exit; } if (!$PRINT_ONLY) { include_first_existing($header_candidates); } ?> <div class="card"> <div class="card-header"> <h3>Karigar Performance Report</h3> <div class="card-sub">Company: <?= h($company_name) ?> | Period: <?= h($from_dt) ?> — <?= h($to_dt) ?></div> </div> <div class="card-body"> <?php if (isset($_GET['snapshot_saved'])): ?> <div class="alert alert-success alert-dismissible fade show mb-3" role="alert"> <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; ?> <div class="d-flex flex-wrap gap-2 align-items-center mb-3"> <form method="get" class="form-inline d-flex flex-wrap gap-2 m-0"> <input type="hidden" name="page" value="karigar_efficiency_report" /> From: <input type="date" name="from" value="<?= h($from_dt) ?>" class="form-control" /> To: <input type="date" name="to" value="<?= h($to_dt) ?>" class="form-control" /> Karigar: <select name="karigar" class="form-control"> <option value="">--All--</option> <?php foreach($karigars as $k): ?> <option value="<?= (int)$k['id'] ?>" <?= $karigar_filter== (int)$k['id'] ? 'selected':'' ?>><?= h($k['karigar_name']) ?></option> <?php endforeach; ?> </select> Machine: <select name="machine" class="form-control"> <option value="">--All--</option> <?php foreach($machines as $m): ?> <option value="<?= (int)$m['machine_no'] ?>" <?= $machine_filter == (int)$m['machine_no'] ? 'selected':'' ?>><?= h($m['machine_no']) ?></option> <?php endforeach; ?> </select> Quality: <select name="quality" class="form-control"> <option value="">--All--</option> <?php foreach($qualities as $qid=>$q): ?> <option value="<?= (int)$qid ?>" <?= $quality_filter==(int)$qid ? 'selected':'' ?>><?= h($q['name']) ?></option> <?php endforeach; ?> </select> Sort by: <select name="sort" class="form-control"> <option value="eff_desc" <?= $SORT==='eff_desc' ? 'selected':'' ?>>Performance: High → Low</option> <option value="eff_asc" <?= $SORT==='eff_asc' ? 'selected':'' ?>>Performance: Low → High</option> <option value="meter_desc" <?= $SORT==='meter_desc' ? 'selected':'' ?>>Total Meter: High → Low</option> <option value="meter_asc" <?= $SORT==='meter_asc' ? 'selected':'' ?>>Total Meter: Low → High</option> </select> <button class="btn btn-primary" type="submit">Filter</button> <a class="btn btn-success" href="?<?= http_build_query(array_merge($_GET, ['export'=>'csv'])) ?>">Export CSV</a> <a class="btn btn-danger" href="?<?= http_build_query(array_merge($_GET, ['export'=>'pdf'])) ?>">Export PDF</a> <a class="btn btn-secondary" target="_blank" href="?<?= http_build_query(array_merge($_GET, ['print'=>'1'])) ?>">Print</a> </form> <!-- Save to Master Salary Snapshot Form --> <form method="post" class="d-inline-flex gap-2 ms-2 m-0" id="snapshotForm"> <?php csrf_field(); ?> <input type="hidden" name="action" value="save_snapshot"> <input type="hidden" name="period" id="snapshotPeriodField" value="<?= h($snapshot_period); ?>"> <select name="snapshot_period_ui" id="snapshotPeriodUi" class="form-select d-inline-block w-auto align-middle me-1"> <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> <textarea name="report_html" id="reportHtmlField" style="display:none;"></textarea> <button type="button" onclick="saveReportSnapshot()" class="btn btn-dark px-3 align-middle"> <i class="bi bi-cloud-upload me-1"></i> Save to Master Salary </button> </form> </div> <div class="table-responsive" id="reportContent"> <table class="table table-sm table-striped table-bordered table-hover"> <thead class="table-light"> <tr> <th>Karigar</th> <th>Machines</th> <th>Work Days</th> <th>Total Meter</th> <th>Expected</th> <th>Performance %</th> <?php foreach($all_dates as $d): ?><th><?= h($d) ?></th><?php endforeach; ?> </tr> </thead> <tbody> <?php if (empty($report_rows)): ?> <tr><td colspan="<?= 6 + count($all_dates) ?>">No data found for selected filters.</td></tr> <?php else: ?> <?php foreach($report_rows as $r): ?> <tr> <td><?= h($r['karigar_name']) ?></td> <td><?= h(implode(', ', array_keys($r['machines']))) ?></td> <td><?= (int)$r['work_days'] ?></td> <td><?= round($r['total_meter'],2) ?></td> <td><?= round($r['expected_total'],2) ?></td> <td><?= round($r['efficiency'],2) ?>%</td> <?php foreach($all_dates as $d): $cell = $r['per_date'][$d] ?? null; if (!$cell || $cell['skip']): ?> <td class="text-muted">-</td> <?php else: ?> <td><?= round($cell['meter'],2) ?></td> <?php endif; endforeach; ?> </tr> <?php endforeach; ?> <?php endif; ?> </tbody> </table> </div> </div> </div> <script> 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 if ($PRINT_ONLY) { echo '<script>window.print(); setTimeout(()=>window.close(),1000);</script>'; exit; } include_first_existing($footer_candidates); ?>