« Back to History
beam_report.php
|
20260920_164915.php
Initial Domain Snapshot
Copy Code
<?php // beam_report.php (fixed: no undefined index warnings) // Place at /public_html/erp/beam_report.php // DEBUG (turn off on production) ini_set('display_errors',1); ini_set('display_startup_errors',1); error_reporting(E_ALL); ini_set('log_errors',1); if (!is_dir(__DIR__ . '/logs')) @mkdir(__DIR__ . '/logs', 0755, true); ini_set('error_log', __DIR__ . '/logs/beam_report_error.log'); session_start(); // config auto-detect (look in /erp/) $tryPaths = [ __DIR__ . '/config.php', __DIR__ . '/../config.php', $_SERVER['DOCUMENT_ROOT'] . '/erp/config.php', $_SERVER['DOCUMENT_ROOT'] . '/config.php' ]; $configFound = false; foreach ($tryPaths as $p) { if ($p && file_exists($p)) { require_once $p; $configFound = $p; break; } } if (!$configFound) { echo "<h3 style='color:#b33'>ERROR: config.php not found. Paths tried:</h3><ul>"; foreach ($tryPaths as $p) echo "<li>" . htmlspecialchars($p) . "</li>"; echo "</ul>"; exit; } // DB connect try { if (defined('DB_HOST') && defined('DB_NAME') && defined('DB_USER') && defined('DB_PASS')) { $dsn = "mysql:host=" . DB_HOST . ";dbname=" . DB_NAME . ";charset=utf8mb4"; $pdo = new PDO($dsn, DB_USER, DB_PASS, [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ]); } elseif (isset($DB_HOST,$DB_NAME,$DB_USER,$DB_PASS)) { $dsn = "mysql:host={$DB_HOST};dbname={$DB_NAME};charset=utf8mb4"; $pdo = new PDO($dsn, $DB_USER, $DB_PASS, [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ]); } else { throw new Exception("DB credentials not found in config.php"); } } catch (Exception $e) { echo "<h3>DB Connection error:</h3><pre>" . htmlspecialchars($e->getMessage()) . "</pre>"; exit; } function h($s){ return htmlspecialchars($s ?? '', ENT_QUOTES); } // MisterManager colors (kept for UI) $mm_primary = '#1fb14b'; $mm_accent = '#dff6e6'; $mm_dark = '#2b2b2b'; // safe input reading: avoid undefined index warnings $beam_no = trim((string) (filter_input(INPUT_GET,'beam_no') ?? filter_input(INPUT_POST,'beam_no') ?? '')); $from_raw = filter_input(INPUT_GET,'from') ?? filter_input(INPUT_POST,'from') ?? ''; $to_raw = filter_input(INPUT_GET,'to') ?? filter_input(INPUT_POST,'to') ?? ''; // validate dates (YYYY-MM-DD) else empty $from = preg_match('/^\d{4}-\d{2}-\d{2}$/', $from_raw) ? $from_raw : ''; $to = preg_match('/^\d{4}-\d{2}-\d{2}$/', $to_raw) ? $to_raw : ''; $from_q = $from ?: '1970-01-01'; $to_q = $to ?: date('Y-m-d'); // company_id from session (fallback try beam_card) $company_id = $_SESSION['user']['company_id'] ?? null; if (!$company_id) { try { $r = $pdo->query("SELECT company_id FROM beam_card LIMIT 1")->fetch(); $company_id = $r['company_id'] ?? null; if ($company_id) echo "<div style='background:#fff7e6;padding:8px;border:1px solid #ffd;'>Session company_id missing — using company_id={$company_id} (debug)</div>"; } catch(Exception $e){} } if (!$company_id) { echo "<h3 style='color:#b33'>Login / company context missing.</h3>"; exit; } // if no beam selected -> show selector UI if ($beam_no === '') { try { $stmt = $pdo->prepare("SELECT id, beam_no, beam_type, machine_no, install_date, finish_date FROM beam_card WHERE company_id = ? ORDER BY install_date DESC LIMIT 300"); $stmt->execute([$company_id]); $beams = $stmt->fetchAll(); } catch (Exception $e) { echo "<pre>" . h($e->getMessage()) . "</pre>"; exit; } ?> <!doctype html><html><head><meta charset="utf-8"><title>Select Beam</title> <style>body{font-family:Arial;margin:18px;color:<?=$mm_dark?>}.btn{background:<?=$mm_primary?>;color:#fff;padding:8px 12px;border-radius:6px;border:none}</style> </head><body> <h2 style="color:<?=$mm_primary?>">Select Beam</h2> <form method="get"> Beam: <select name="beam_no" required><option value="">-- choose --</option> <?php foreach($beams as $b): ?><option value="<?=h($b['beam_no'])?>"><?=h($b['beam_no'])?> - M:<?=h($b['machine_no'])?> - <?=h($b['install_date'])?></option><?php endforeach; ?> </select> From: <input type="date" name="from"> To: <input type="date" name="to"> <button class="btn" type="submit">Open</button> </form> </body></html> <?php exit; } // fetch beam installs try { $stmt = $pdo->prepare("SELECT * FROM beam_card WHERE company_id = ? AND beam_no = ? ORDER BY install_date ASC"); $stmt->execute([$company_id, $beam_no]); $beamInstalls = $stmt->fetchAll(); if (!$beamInstalls) { echo "<h3>No installs found for " . h($beam_no) . "</h3>"; exit; } $beamCardLatest = end($beamInstalls); } catch (Exception $e) { echo "<pre>" . h($e->getMessage()) . "</pre>"; exit; } // beam_entry meta (warper) try { $stmt = $pdo->prepare("SELECT be.*, emp.name AS warper_name FROM beam_entry be LEFT JOIN employees emp ON emp.id = be.employee_id WHERE be.company_id = ? AND be.beam_no = ? LIMIT 1"); $stmt->execute([$company_id, $beam_no]); $beamMeta = $stmt->fetch() ?: []; } catch (Exception $e) { $beamMeta = []; } // beam total meter: prefer beam_card.latest.total_meter then beam_entry.total_meter $beam_total_meter = 0.0; if (!empty($beamCardLatest['total_meter'])) $beam_total_meter = floatval($beamCardLatest['total_meter']); elseif (!empty($beamMeta['total_meter'])) $beam_total_meter = floatval($beamMeta['total_meter']); // CORE: lines_json-based counting per install (install-machine & install window only) try { $perInstallResults = []; $stmtFetchRows = $pdo->prepare("SELECT id, entry_date, machine_id, taka_no, meter_total, lines_json, extra_mtr FROM loom_production_entry WHERE company_id = ? AND machine_id = ? AND entry_date BETWEEN ? AND ? ORDER BY entry_date ASC, id ASC"); foreach ($beamInstalls as $inst) { $instMachine = $inst['machine_no']; $start = $inst['install_date'] ?? '1970-01-01'; $end = $inst['finish_date'] ?? $to_q; $s = max($start, $from_q); $e = min($end, $to_q); $dateBuckets = []; $extraTotal = 0.0; $fallbackUsed = []; if ($s <= $e) { $stmtFetchRows->execute([$company_id, $instMachine, $s, $e]); $prodRowsRaw = $stmtFetchRows->fetchAll(); foreach ($prodRowsRaw as $prow) { if (isset($prow['extra_mtr']) && $prow['extra_mtr'] !== null && $prow['extra_mtr'] !== '') $extraTotal += floatval($prow['extra_mtr']); $lines = []; if (!empty($prow['lines_json'])) { $decoded = @json_decode($prow['lines_json'], true); if ($decoded === null && json_last_error() !== JSON_ERROR_NONE) { $decoded2 = @json_decode(stripslashes($prow['lines_json']), true); if ($decoded2 !== null && json_last_error() === JSON_ERROR_NONE) $decoded = $decoded2; } if (is_array($decoded)) $lines = $decoded; } if (!empty($lines) && is_array($lines)) { foreach ($lines as $ln) { $lnDate = !empty($ln['date']) ? substr(trim($ln['date']),0,10) : substr($prow['entry_date'],0,10); $lnMeter = 0.0; if (isset($ln['meter'])) { $m = str_replace([',',' '],'',trim((string)$ln['meter'])); $lnMeter = is_numeric($m) ? floatval($m) : 0.0; } elseif (isset($ln['mtr'])) { $m = str_replace([',',' '],'',trim((string)$ln['mtr'])); $lnMeter = is_numeric($m) ? floatval($m) : 0.0; } if ($lnDate >= $s && $lnDate <= $e) { if (!isset($dateBuckets[$lnDate])) $dateBuckets[$lnDate] = 0.0; $dateBuckets[$lnDate] += $lnMeter; } } } else { // fallback to row-level meter_total attributed to row entry_date $fallbackDate = substr($prow['entry_date'],0,10); if ($fallbackDate >= $s && $fallbackDate <= $e) { $mt = isset($prow['meter_total']) ? floatval($prow['meter_total']) : 0.0; if (!isset($dateBuckets[$fallbackDate])) $dateBuckets[$fallbackDate] = 0.0; $dateBuckets[$fallbackDate] += $mt; $fallbackUsed[] = $prow['id']; } } } } ksort($dateBuckets); $rowsArray = []; $installTotal = 0.0; $periodStart = new DateTime($s); $periodEnd = new DateTime($e); for ($d = clone $periodStart; $d <= $periodEnd; $d->modify('+1 day')) { $ds = $d->format('Y-m-d'); $val = isset($dateBuckets[$ds]) ? floatval($dateBuckets[$ds]) : 0.0; $rowsArray[] = ['entry_date'=>$ds,'machine_no'=>$instMachine,'produced_m'=>$val]; $installTotal += $val; } $install_declared_total = isset($inst['total_meter']) ? floatval($inst['total_meter']) : null; $install_shortage = null; $install_shortage_pct = null; if ($install_declared_total !== null && $install_declared_total > 0) { $install_shortage = max(0, $install_declared_total - $installTotal); $install_shortage_pct = ($install_shortage / $install_declared_total) * 100.0; } $perInstallResults[] = [ 'install'=>$inst,'from'=>$s,'to'=>$e,'rows'=>$rowsArray,'total'=>$installTotal, 'extra_total'=>$extraTotal,'fallback_row_ids'=>$fallbackUsed,'declared_total'=>$install_declared_total, 'install_shortage'=>$install_shortage,'install_shortage_pct'=>$install_shortage_pct ]; } $grandProduced = 0.0; $grandExtra = 0.0; foreach ($perInstallResults as $p) { $grandProduced += floatval($p['total']); $grandExtra += floatval($p['extra_total']); } $overall_shortage = null; $overall_shortage_pct = null; if ($beam_total_meter > 0) { $overall_shortage = max(0, $beam_total_meter - $grandProduced); $overall_shortage_pct = ($overall_shortage / $beam_total_meter) * 100.0; } } catch (Exception $e) { echo "<h3 style='color:#b33'>Error:</h3><pre>" . h($e->getMessage()) . "</pre>"; exit; } // Render HTML (same simple UI) ?> <!doctype html><html><head><meta charset="utf-8"><title>Beam Report - <?=h($beam_no)?></title> <style>:root{--mm-primary:<?=$mm_primary?>;--mm-accent:<?=$mm_accent?>;--mm-dark:<?=$mm_dark?>}body{font-family:Arial;background:#f7fbf7;color:var(--mm-dark);margin:18px}.card{background:#fff;padding:12px;border-radius:8px;border:1px solid #e9f4ea;margin-bottom:12px}h1{color:var(--mm-primary)}.btn{background:var(--mm-primary);color:#fff;padding:8px 12px;border-radius:6px;border:none}.small{font-size:13px;color:#444}.note{font-size:13px;color:#666}.bad{color:#b33}</style> </head><body> <div class="card"><h1>Beam Report — <?=h($beam_no)?></h1><div class="small">Range: <?=h($from_q)?> → <?=h($to_q)?></div></div> <div class="card"> <form method="get" style="display:flex;gap:8px;align-items:center"> <input type="hidden" name="beam_no" value="<?=h($beam_no)?>"> From: <input type="date" name="from" value="<?=h($from)?>"> To: <input type="date" name="to" value="<?=h($to)?:date('Y-m-d')?>"> <button class="btn" type="submit">Apply</button> <a style="margin-left:12px" href="beam_report.php?beam_no=<?=urlencode($beam_no)?>">Reset</a> </form> </div> <div class="card"> <div style="display:flex;gap:16px;align-items:center"> <div><div class="small">Beam No</div><div style="font-weight:700"><?=h($beam_no)?></div></div> <div><div class="small">Total Meter (beam)</div><div style="font-weight:700"><?=number_format($beam_total_meter,2)?> m</div></div> <div><div class="small">Produced</div><div style="font-weight:700"><?=number_format($grandProduced,2)?> m</div></div> <div style="margin-left:auto"><div class="small">Warper</div><div style="font-weight:700"><?=h($beamMeta['warper_name'] ?? ($beamCardLatest['warper'] ?? '—'))?></div></div> </div> <div class="note" style="margin-top:8px">Only lines_json lines (line.date) inside install window are counted. meter_total used only as fallback.</div> </div> <?php foreach ($perInstallResults as $instBlock): $inst = $instBlock['install']; ?> <div class="card"> <div style="display:flex;align-items:center;gap:12px"><div><strong>Install on M<?=h($inst['machine_no'])?></strong></div><div class="small">installed <?=h($inst['install_date'])?> → <?=h($inst['finish_date']?:'now')?></div><div style="margin-left:auto" class="small">Reporting: <?=h($instBlock['from'])?> → <?=h($instBlock['to'])?></div></div> <table style="width:100%;margin-top:8px;border-collapse:collapse"><thead><tr><th style="text-align:left;padding:6px;background:#f0fff0">Date</th><th style="text-align:left;padding:6px;background:#f0fff0">Machine</th><th style="text-align:right;padding:6px;background:#f0fff0">Produced (m)</th></tr></thead><tbody> <?php foreach ($instBlock['rows'] as $r): ?> <tr><td style="padding:6px"><?=h($r['entry_date'])?></td><td style="padding:6px"><?=h($r['machine_no'])?></td><td style="padding:6px;text-align:right"><?=number_format($r['produced_m'],2)?></td></tr> <?php endforeach; ?> <tr style="font-weight:bold;background:#f7f7f7"><td colspan="2" style="padding:6px">Install total:</td><td style="padding:6px;text-align:right"><?=number_format($instBlock['total'],2)?></td></tr> <?php if(floatval($instBlock['extra_total'])>0): ?><tr><td colspan="2" class="small bad" style="padding:6px">Install extra meters:</td><td style="padding:6px;text-align:right;color:#b33"><?=number_format($instBlock['extra_total'],2)?></td></tr><?php endif; ?> <?php if ($instBlock['declared_total'] !== null): ?> <tr><td colspan="2" class="small" style="padding:6px">Install declared total (beam_card):</td><td style="padding:6px;text-align:right"><?=number_format($instBlock['declared_total'],2)?></td></tr> <tr><td colspan="2" class="small" style="padding:6px">Install shortage:</td><td style="padding:6px;text-align:right;color:<?=($instBlock['install_shortage']>0)?'#b33':'#2b8f3b'?>"><?=number_format($instBlock['install_shortage'],2)?> m (<?=number_format($instBlock['install_shortage_pct']??0,2)?>%)</td></tr> <?php endif; ?> <?php if (!empty($instBlock['fallback_row_ids'])): ?><tr><td colspan="3" class="small bad" style="padding:6px">Fallback used for rows: <?=h(implode(',', $instBlock['fallback_row_ids']))?></td></tr><?php endif; ?> </tbody></table> </div> <?php endforeach; ?> <div class="card"><div style="font-weight:700">Overall</div><div class="small">Produced: <?=number_format($grandProduced,2)?> m | Extra: <?=number_format($grandExtra,2)?> m</div> <div style="margin-top:8px"><strong>Shortage:</strong> <span style="color:<?=($overall_shortage>0)?'#b33':'#2b8f3b'?>"><?=number_format($overall_shortage,2)?> m</span> <?php if ($beam_total_meter>0): ?>(<?=number_format($overall_shortage_pct,2)?>% of <?=number_format($beam_total_meter,2)?> m)<?php endif; ?></div></div> </body></html>