« Back to History
new_gray_lifecycle_report.php
|
20260723_000646.php
Initial Domain Snapshot
Copy Code
<?php /* ============================================================================= File: /erp/new_gray_lifecycle_report.php Purpose: Highly Optimized Grey Lifecycle Report with Automatic Schema Patching ============================================================================= */ require_once __DIR__ . '/modules/auth/page_acl.php'; $ctx = page_require_access('gray_lifecycle_report'); if (!function_exists('h')) { function h($value) { return htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8'); } } $pdo = $ctx['pdo']; $company_id = (int)$ctx['company_id']; /* ===================== SCHEMA AUTO-PATCHING SYSTEM ===================== */ try { $pdo->exec("ALTER TABLE gray_receive ADD COLUMN IF NOT EXISTS check_status VARCHAR(20) DEFAULT 'need_check'"); } catch (Exception $e) { try { $pdo->exec("ALTER TABLE gray_receive ADD check_status VARCHAR(20) DEFAULT 'need_check'"); } catch (Exception $ex) { // Column already exists master bypass } } /* ===================== AJAX ENDPOINT: UPDATE CHECK STATUS ===================== */ if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_GET['action'] ?? '') === 'update_check_status') { header('Content-Type: application/json'); $gray_id = trim($_POST['gray_id'] ?? ''); $status = trim($_POST['check_status'] ?? 'need_check'); if ($gray_id === '' || !in_array($status, ['ok', 'need_check'])) { echo json_encode(['success' => false, 'message' => 'Invalid parameters']); exit; } try { $up = $pdo->prepare("UPDATE gray_receive SET check_status = ? WHERE gray_id = ? AND company_id = ?"); $up->execute([$status, $gray_id, $company_id]); echo json_encode(['success' => true]); } catch (Exception $e) { echo json_encode(['success' => false, 'message' => $e->getMessage()]); } exit; } // Request Filter States $from = $_GET['from'] ?? date('Y-m-d', strtotime('-30 days')); $to = $_GET['to'] ?? date('Y-m-d'); $order = $_GET['order'] ?? 'DESC'; $check_filter = $_GET['check_filter'] ?? 'all'; $orderSql = ($order === 'ASC') ? 'ASC' : 'DESC'; // Dynamic Filtering Clause $check_clause = ""; if ($check_filter === 'ok') { $check_clause = " AND COALESCE(g.check_status, 'need_check') = 'ok' "; } elseif ($check_filter === 'need_check') { $check_clause = " AND COALESCE(g.check_status, 'need_check') = 'need_check' "; } /* ===================== OPTIMIZED MAIN QUERY ===================== */ $sql = " SELECT g.gray_id, g.rec_date, mm.short_name AS mill_short_name, fq.quality_name, g.finish_mts, g.shortage, g.grey_mts, g.financial_year, COALESCE(g.check_status, 'need_check') AS check_status, ce.cut_name, COALESCE(ce.fresh, 0) AS fresh, COALESCE(ce.second_cut, 0) AS second_cut, COALESCE(ce.used_meter, 0) AS used_meter FROM gray_receive g LEFT JOIN fabric_quality_master fq ON fq.id = g.quality_id LEFT JOIN mill_master mm ON mm.id = g.mill_id AND mm.company_id = g.company_id LEFT JOIN ( SELECT ce.gray_id, ce.company_id, GROUP_CONCAT(DISTINCT sct.cut_name ORDER BY sct.cut_name SEPARATOR ', ') AS cut_name, SUM(ce.fresh_saree) AS fresh, SUM(ce.second_saree) AS second_cut, SUM(ce.total_meter) AS used_meter FROM cutting_entry ce LEFT JOIN saree_cut_types sct ON sct.id = ce.cut_type_id AND sct.company_id = ce.company_id WHERE ce.company_id = :cid GROUP BY ce.gray_id ) ce ON ce.gray_id = g.gray_id AND ce.company_id = g.company_id WHERE g.company_id = :cid2 AND g.rec_date BETWEEN :f AND :t $check_clause ORDER BY g.rec_date $orderSql, g.gray_id $orderSql "; $st = $pdo->prepare($sql); $st->execute([ ':cid' => $company_id, ':cid2' => $company_id, ':f' => $from, ':t' => $to ]); $rows = $st->fetchAll(PDO::FETCH_ASSOC); function format_report_pcs($value) { $value = (float)$value; return fmod($value, 1.0) == 0.0 ? (string)(int)$value : rtrim(rtrim(number_format($value, 2, '.', ''), '0'), '.'); } /* ===================== OPTIMIZED VA SEND / RECEIVE MAPS ===================== */ $grayIdsArray = array_column($rows, 'gray_id'); $lifecycleMap = []; if (!empty($grayIdsArray)) { // 1. Fetch VA Receive Map $recvStmt = $pdo->prepare(" SELECT challan_no, financial_year, COALESCE(SUM(total_pcs), 0) AS recv_pcs, COALESCE(SUM(second), 0) AS recv_second FROM va_receive_entry WHERE company_id = :cid GROUP BY challan_no, financial_year "); $recvStmt->execute([':cid' => $company_id]); $recvMap = []; foreach ($recvStmt->fetchAll(PDO::FETCH_ASSOC) as $rv) { $recvMap[$rv['financial_year'] . '||' . $rv['challan_no']] = [ 'pcs' => (float)$rv['recv_pcs'], 'second' => (float)$rv['recv_second'] ]; } // 2. Optimized VA Send Data Extraction $whereClauses = []; $params = [':cid' => $company_id]; foreach ($grayIdsArray as $idx => $gid) { $whereClauses[] = "FIND_IN_SET(:gid_$idx, grey_id) OR mgray_detail LIKE :gjson_$idx"; $params[":gid_$idx"] = $gid; $params[":gjson_$idx"] = '%"gray_id":"' . $gid . '"%'; } $sendSql = "SELECT challan_no, financial_year, grey_id, mgray_detail, pcs FROM va_send_entry WHERE company_id = :cid AND (" . implode(' OR ', $whereClauses) . ")"; $sendStmt = $pdo->prepare($sendSql); $sendStmt->execute($params); foreach ($sendStmt->fetchAll(PDO::FETCH_ASSOC) as $vs) { $fy = (string)($vs['financial_year'] ?? ''); $challanNo = (string)($vs['challan_no'] ?? ''); $recvKey = $fy . '||' . $challanNo; $challanRecv = (float)($recvMap[$recvKey]['pcs'] ?? 0); $challanSecond = (float)($recvMap[$recvKey]['second'] ?? 0); $greyId = trim((string)($vs['grey_id'] ?? '')); if ($greyId !== '') { $grayIds = array_filter(array_map('trim', explode(',', $greyId)), function ($value) { return $value !== ''; }); foreach ($grayIds as $singleGrayId) { if (!in_array($singleGrayId, $grayIdsArray)) continue; $mapKey = $fy . '||' . $singleGrayId; if (!isset($lifecycleMap[$mapKey])) { $lifecycleMap[$mapKey] = ['sent_pcs' => 0, 'recv_pcs' => 0, 'recv_second' => 0, 'challan_details' => []]; } $lifecycleMap[$mapKey]['sent_pcs'] += (float)$vs['pcs']; $lifecycleMap[$mapKey]['recv_pcs'] += $challanRecv; $lifecycleMap[$mapKey]['recv_second'] += $challanSecond; $lifecycleMap[$mapKey]['challan_details'][] = $challanNo . ' (' . format_report_pcs($vs['pcs']) . ')'; } continue; } $detailRows = json_decode((string)($vs['mgray_detail'] ?? ''), true); if (!is_array($detailRows) || empty($detailRows)) { continue; } $cleanRows = []; $detailTotal = 0; foreach ($detailRows as $detail) { $singleGrayId = trim((string)($detail['gray_id'] ?? '')); $pcs = (float)($detail['pcs'] ?? 0); if ($singleGrayId === '' || $pcs <= 0 || !in_array($singleGrayId, $grayIdsArray)) { continue; } $cleanRows[] = ['gray_id' => $singleGrayId, 'pcs' => $pcs]; $detailTotal += $pcs; } foreach ($cleanRows as $detail) { $mapKey = $fy . '||' . $detail['gray_id']; if (!isset($lifecycleMap[$mapKey])) { $lifecycleMap[$mapKey] = ['sent_pcs' => 0, 'recv_pcs' => 0, 'recv_second' => 0, 'challan_details' => []]; } $allocRecv = $detailTotal > 0 ? ($challanRecv * $detail['pcs'] / $detailTotal) : 0; $allocSecond = $detailTotal > 0 ? ($challanSecond * $detail['pcs'] / $detailTotal) : 0; $lifecycleMap[$mapKey]['sent_pcs'] += $detail['pcs']; $lifecycleMap[$mapKey]['recv_pcs'] += $allocRecv; $lifecycleMap[$mapKey]['recv_second'] += $allocSecond; $lifecycleMap[$mapKey]['challan_details'][] = $challanNo . ' (' . format_report_pcs($detail['pcs']) . ')'; } } } // Map calculated variables back to rows foreach ($rows as &$row) { $row['sent_pcs'] = 0; $row['recv_pcs'] = 0; $row['recv_second'] = 0; $row['challan_details'] = ''; $mapKey = (string)$row['financial_year'] . '||' . (string)$row['gray_id']; if (isset($lifecycleMap[$mapKey])) { $row['sent_pcs'] = $lifecycleMap[$mapKey]['sent_pcs']; $row['recv_pcs'] = $lifecycleMap[$mapKey]['recv_pcs']; $row['recv_second'] = $lifecycleMap[$mapKey]['recv_second']; $row['challan_details'] = implode(', ', array_unique($lifecycleMap[$mapKey]['challan_details'])); } } unset($row); function render_gray_lifecycle_report(array $rows, string $from, string $to, string $orderSql, string $check_filter, bool $isPdf = false): void { ?> <style> .challan-cell { min-width: 75px; max-width: 95px; white-space: nowrap; line-height: 1.2; text-align: center; } .challan-cell.wrap-challan { white-space: normal; } .challan-line { display: block; } .btn-toggle-check { padding: 1px 4px; font-weight: bold; border-radius: 4px; } /* Fixed Split Scroll Sync Layout */ .lifecycle-header-wrapper { overflow: hidden; width: 100%; background-color: #212529; border: 1px solid #dee2e6; border-bottom: none; } .lifecycle-body-wrapper { max-height: calc(100vh - 320px); overflow-y: auto; overflow-x: auto; width: 100%; border: 1px solid #dee2e6; } .lifecycle-header-wrapper table, .lifecycle-body-wrapper table { min-width: 1220px; border-collapse: collapse !important; table-layout: fixed; } /* Strict Squeezed Real-Estate Width Mapping */ .col-gray-id { width: 45px; } .col-date { width: 75px; } .col-mill { width: 65px; } .col-quality { width: 135px; } .col-finish { width: 70px; } .col-gr-srtg { width: 55px; } .col-cut { width: 40px; } .col-fresh { width: 45px; } .col-second { width: 45px; } .col-cutti-pct { width: 55px; } .col-second-pct { width: 55px; } .col-sent { width: 45px; } .col-ns { width: 40px; } .col-received { width: 65px; } .col-va-sec-pct { width: 60px; } .col-challan { width: 85px; } .col-status { width: 105px; } .col-action { width: 90px; } /* Default dynamic scaling baseline style hook */ .lifecycle-header-wrapper table th, .lifecycle-body-wrapper table td { padding: 2px 3px !important; font-size: 11.5px; /* Scaled via JS dynamically */ line-height: 1.2 !important; } .lifecycle-body-wrapper table td.text-center, .lifecycle-header-wrapper table th { text-align: center !important; } <?php if ($isPdf): ?> body { font-family: DejaVu Sans, sans-serif; font-size: 10px; color: #111; } .container-fluid { padding: 0; } .card { border: 0; box-shadow: none; } .lifecycle-header-wrapper { display: none !important; } .lifecycle-body-wrapper { max-height: none; overflow: visible; border: 0; } .lifecycle-body-wrapper table { min-width: 100%; table-layout: auto; border-collapse: collapse !important; } .table th, .table td { border: 1px solid #222; padding: 2px 3px; vertical-align: middle; } .table-dark th { background: #212529; color: #fff; position: static !important; } .badge { display: inline-block; padding: 1px 4px; border-radius: 999px; font-size: 8px; font-weight: 700; } .bg-danger { background: #dc3545; color: #fff; } .bg-secondary { background: #6c757d; color: #fff; } .bg-success { background: #198754; color: #fff; } .bg-warning { background: #ffc107; color: #111; } .text-center { text-align: center; } .text-end { text-align: right; } .fw-bold { font-weight: 700; } .table-hover tbody tr:nth-child(even) { background: #fafafa; } .print-header { display: block !important; text-align: center; font-weight: 700; margin-bottom: 8px; } .no-print { display: none !important; } <?php else: ?> @media print { @page { size: A4 landscape; margin: 6mm 4mm; } html, body { background: #fff !important; -webkit-print-color-adjust: exact; print-color-adjust: exact; } .no-print { display: none !important; } .card { border: 0 !important; box-shadow: none !important; } .lifecycle-header-wrapper { display: none !important; } .lifecycle-body-wrapper { overflow: visible !important; max-height: none !important; border: 0 !important; } .lifecycle-body-wrapper table { min-width: 100% !important; table-layout: auto !important; border-collapse: collapse !important; } thead { display: table-header-group !important; } .table th, .table td { padding: 2px 3px !important; vertical-align: middle !important; font-size: 11px !important; } .print-header { display: block !important; text-align: center; font-weight: 700; margin-bottom: 6px !important; } } <?php endif; ?> </style> <div class="container-fluid <?= ($isPdf) ? '' : 'py-4' ?>"> <div class="print-header" style="<?= $isPdf ? '' : 'display:none;' ?>"> Grey Lifecycle Report<br> <small>From <?= date('d-m-Y', strtotime($from)) ?> To <?= date('d-m-Y', strtotime($to)) ?> | Filter: <?= h(strtoupper($check_filter)) ?></small> </div> <div class="card shadow-sm mb-4 no-print border-0"> <div class="card-body"> <div class="d-flex justify-content-between align-items-center flex-wrap gap-3"> <h4 class="mb-0">Grey Lifecycle Report</h4> <div class="d-flex align-items-center gap-2"> <div class="btn-group btn-group-sm me-2" role="group" aria-label="Font Resizer"> <button type="button" class="btn btn-outline-dark fw-bold" onclick="adjustReportFontSize(-1)" title="Font Decrease">- A</button> <button type="button" class="btn btn-outline-dark bg-light text-dark font-monospace small" id="lbl_font_sz" style="min-width:55px; pointer-events:none;">11.5px</button> <button type="button" class="btn btn-outline-dark fw-bold" onclick="adjustReportFontSize(1)" title="Font Increase">+ A</button> </div> <a href="?from=<?= h($from) ?>&to=<?= h($to) ?>&order=ASC&check_filter=<?= h($check_filter) ?>" class="btn btn-sm btn-outline-primary">ASC</a> <a href="?from=<?= h($from) ?>&to=<?= h($to) ?>&order=DESC&check_filter=<?= h($check_filter) ?>" class="btn btn-sm btn-outline-primary">DESC</a> <a href="?from=<?= h($from) ?>&to=<?= h($to) ?>&order=<?= h($orderSql) ?>&check_filter=<?= h($check_filter) ?>&export=pdf" class="btn btn-danger btn-sm">Export PDF</a> <button onclick="window.print()" class="btn btn-dark btn-sm">Print</button> </div> </div> <form method="get" class="row g-3 align-items-end mt-1"> <div class="col-md-2"> <label class="form-label small fw-bold text-muted">From Date</label> <input type="date" name="from" class="form-control" value="<?= h($from) ?>"> </div> <div class="col-md-2"> <label class="form-label small fw-bold text-muted">To Date</label> <input type="date" name="to" class="form-control" value="<?= h($to) ?>"> </div> <div class="col-md-2"> <label class="form-label small fw-bold text-muted">Order</label> <select name="order" class="form-select"> <option value="DESC" <?= $orderSql === 'DESC' ? 'selected' : '' ?>>DESC</option> <option value="ASC" <?= $orderSql === 'ASC' ? 'selected' : '' ?>>ASC</option> </select> </div> <div class="col-md-2"> <label class="form-label small fw-bold text-muted">Verification Check</label> <select name="check_filter" class="form-select bg-light fw-bold border-primary"> <option value="all" <?= $check_filter === 'all' ? 'selected' : '' ?>>All Rows</option> <option value="ok" <?= $check_filter === 'ok' ? 'selected' : '' ?>>Checked OK Only</option> <option value="need_check" <?= $check_filter === 'need_check' ? 'selected' : '' ?>>Need Check Only</option> </select> </div> <div class="col-md-4 d-flex gap-2"> <button type="submit" class="btn btn-primary px-3">Show Data</button> <a href="?from=<?= h(date('Y-m-d', strtotime('-30 days'))) ?>&to=<?= h(date('Y-m-d')) ?>&order=DESC&check_filter=all" class="btn btn-outline-secondary">Last 30 Days</a> <a href="?order=DESC&check_filter=all" class="btn btn-outline-dark">Reset</a> </div> </form> <?php if (empty($rows)): ?> <div class="alert alert-warning mb-0 mt-3"> Selected properties/date range mein data nahi mila. Options badal kar dekhein. </div> <?php endif; ?> </div> </div> <div class="card border-0 shadow-sm"> <div class="lifecycle-header-wrapper"> <table class="table table-bordered align-middle mb-0 text-white"> <colgroup> <col class="col-gray-id"> <col class="col-date"> <col class="col-mill"> <col class="col-quality"> <col class="col-finish"> <col class="col-gr-srtg"> <col class="col-cut"> <col class="col-fresh"> <col class="col-second"> <col class="col-cutti-pct"> <col class="col-second-pct"> <col class="col-sent"> <col class="col-ns"> <col class="col-received"> <col class="col-va-sec-pct"> <col class="col-challan"> <col class="col-status"> <col class="col-action"> </colgroup> <thead class="table-dark text-nowrap"> <tr> <th>Grey ID</th> <th>Date</th> <th>Mill</th> <th>Quality</th> <th>Finish</th> <th>GR SRTG</th> <th>Cut</th> <th>Fresh</th> <th>Second</th> <th>Cutti. %</th> <th>Second %</th> <th>Sent</th> <th>NS</th> <th>Received</th> <th>VA Second %</th> <th class="challan-cell">Challan</th> <th class="status-cell text-center">Status</th> <th class="no-print text-center">Verification Action</th> </tr> </thead> </table> </div> <div class="lifecycle-body-wrapper"> <table class="table table-bordered table-hover align-middle mb-0"> <colgroup> <col class="col-gray-id"> <col class="col-date"> <col class="col-mill"> <col class="col-quality"> <col class="col-finish"> <col class="col-gr-srtg"> <col class="col-cut"> <col class="col-fresh"> <col class="col-second"> <col class="col-cutti-pct"> <col class="col-second-pct"> <col class="col-sent"> <col class="col-ns"> <col class="col-received"> <col class="col-va-sec-pct"> <col class="col-challan"> <col class="col-status"> <col class="col-action"> </colgroup> <thead class="table-dark text-nowrap <?= $isPdf ? '' : 'd-none d-print-table-header-group' ?>"> <tr> <th>Grey ID</th> <th>Date</th> <th>Mill</th> <th>Quality</th> <th>Finish</th> <th>GR SRTG</th> <th>Cut</th> <th>Fresh</th> <th>Second</th> <th>Cutti. %</th> <th>Second %</th> <th>Sent</th> <th>NS</th> <th>Received</th> <th>VA Second %</th> <th class="challan-cell">Challan</th> <th class="status-cell text-center">Status</th> <th class="no-print text-center">Verification Action</th> </tr> </thead> <tbody> <?php foreach($rows as $r): $pending = (float)($r['sent_pcs'] ?? 0) - (float)($r['recv_pcs'] ?? 0); $total_cut = (float)($r['fresh'] ?? 0) + (float)($r['second_cut'] ?? 0); $not_sent = (float)($r['fresh'] ?? 0) - (float)($r['sent_pcs'] ?? 0); $second_pct = $total_cut > 0 ? round(($r['second_cut'] / $total_cut) * 100, 2) : 0; $shortage_pct = ((float)$r['grey_mts'] > 0) ? round((((float)$r['grey_mts'] - (float)$r['finish_mts']) / (float)$r['grey_mts']) * 100, 2) : 0; $cutting_pct = (float)$r['finish_mts'] > 0 ? round((((float)$r['finish_mts'] - (float)$r['used_meter']) / (float)$r['finish_mts']) * 100, 2) : 0; $va_second_pct = (float)$r['recv_pcs'] > 0 ? round(((float)$r['recv_second'] / (float)$r['recv_pcs']) * 100, 2) : 0; $challanList = []; if (!empty($r['challan_details'])) { $challanList = array_map('trim', explode(',', (string)$r['challan_details'])); $challanList = array_values(array_filter($challanList, function ($value) { return $value !== ''; })); } $challanGroups = count($challanList) > 2 ? array_chunk($challanList, 2) : []; $challanClass = count($challanList) > 2 ? 'challan-cell wrap-challan' : 'challan-cell'; $is_not_cut = ($r['fresh'] == 0 && $r['second_cut'] == 0); $is_not_sent = ($r['sent_pcs'] == 0); $row_status_class = ($r['check_status'] === 'ok') ? 'table-success-subtle' : ''; ?> <tr id="tr_<?= h($r['gray_id']) ?>" class="<?= $row_status_class ?>"> <td class="text-center fw-bold"><?= h($r['gray_id']) ?></td> <td class="text-center text-nowrap"><?= date('d-m-Y', strtotime($r['rec_date'])) ?></td> <td><?= h($r['mill_short_name'] ?: '-') ?></td> <td><?= h($r['quality_name']) ?></td> <td class="fw-bold text-end"><?= number_format((float)$r['finish_mts'], 2) ?></td> <td class="text-danger fw-bold text-end"><?= h($shortage_pct) ?>%</td> <?php if($is_not_cut): ?> <td colspan="10" class="text-center text-muted py-2 bg-light font-monospace small"> Pending for Cutting (Cutting Entry Pending) </td> <?php else: ?> <td class="text-center fw-bold text-primary"><?= h($r['cut_name'] ?: '-') ?></td> <td class="text-success fw-bold text-center"><?= h(format_report_pcs($r['fresh'])) ?></td> <td class="text-danger text-center"><?= h(format_report_pcs($r['second_cut'])) ?></td> <td class="text-warning fw-bold text-end"><?= h($cutting_pct) ?>%</td> <td class="text-info fw-bold text-end"><?= h($second_pct) ?>%</td> <?php if($is_not_sent): ?> <td colspan="5" class="text-center text-muted bg-light small">Pending for VA Send</td> <?php else: ?> <td class="text-center"><?= h(format_report_pcs($r['sent_pcs'])) ?></td> <td class="text-danger fw-bold text-center"><?= h(format_report_pcs($not_sent)) ?></td> <td class="text-center"> <?php $recv_total = format_report_pcs($r['recv_pcs']); $recv_fresh = format_report_pcs((float)$r['recv_pcs'] - (float)$r['recv_second']); $recv_second = format_report_pcs($r['recv_second']); ?> <span class="fw-bold"><?= h($recv_total) ?></span> <br><span class="text-muted small" style="font-size: 10px !important;">(<?= h($recv_fresh) ?>+<?= h($recv_second) ?>)</span> </td> <td class="text-center fw-bold text-info"><?= number_format($va_second_pct, 2) ?>%</td> <td class="<?= h($challanClass) ?>"> <?php if($challanGroups): ?> <?php foreach($challanGroups as $group): ?> <span class="challan-line"><?= h(implode(', ', $group)) ?></span> <?php endforeach; ?> <?php elseif(!empty($r['challan_details'])): ?> <?= h($r['challan_details']) ?> <?php else: ?> - <?php endif; ?> </td> <?php endif; ?> <?php endif; ?> <td class="text-center fw-bold status-cell"> <?php if($is_not_cut): ?> <span class="badge bg-danger">Cutting Pending</span> <?php elseif($is_not_sent): ?> <span class="badge bg-secondary">VA Send Pending</span> <?php elseif($pending <= 0): ?> <span class="badge bg-success">Completed</span> <?php else: ?> <span class="badge bg-warning text-dark text-nowrap">Pending: <?= h(number_format((float)$pending, 2, '.', '')) ?></span> <?php endif; ?> </td> <td class="no-print text-center"> <div class="btn-group btn-group-sm" role="group"> <button type="button" onclick="changeCheckStatus('<?= h($r['gray_id']) ?>', 'ok')" id="btn_ok_<?= h($r['gray_id']) ?>" class="btn <?= $r['check_status'] === 'ok' ? 'btn-success' : 'btn-outline-success' ?> btn-toggle-check"> OK </button> <button type="button" onclick="changeCheckStatus('<?= h($r['gray_id']) ?>', 'need_check')" id="btn_need_<?= h($r['gray_id']) ?>" class="btn <?= $r['check_status'] === 'need_check' ? 'btn-danger' : 'btn-outline-danger' ?> btn-toggle-check"> NOT OK </button> </div> </td> </tr> <?php endforeach; ?> <?php if (empty($rows)): ?> <tr> <td colspan="18" class="text-center text-muted py-4">No lifecycle data found for specified filter states.</td> </tr> <?php endif; ?> </tbody> </table> </div> </div> </div> <script> /* Global configuration tracker state for sizing engine */ let currentFontSize = 11.5; function adjustReportFontSize(direction) { currentFontSize += (direction * 0.5); if(currentFontSize < 9) currentFontSize = 9; if(currentFontSize > 16) currentFontSize = 16; // Write dynamic runtime feedback node document.getElementById('lbl_font_sz').innerText = currentFontSize + 'px'; // Inject dynamic scaling to table nodes const targetCells = document.querySelectorAll('.lifecycle-header-wrapper table th, .lifecycle-body-wrapper table td, .lifecycle-body-wrapper table th'); targetCells.forEach(cell => { cell.style.setProperty('font-size', currentFontSize + 'px', 'important'); }); // Handle micro actions sizing bounds inside button groups wrapper const checkButtons = document.querySelectorAll('.btn-toggle-check'); checkButtons.forEach(btn => { btn.style.setProperty('font-size', (currentFontSize - 2) + 'px', 'important'); }); } /* Precise Bi-Directional Horizontal Scroll Lock Sync Engine */ document.addEventListener('DOMContentLoaded', function() { const header = document.querySelector('.lifecycle-header-wrapper'); const body = document.querySelector('.lifecycle-body-wrapper'); if (header && body) { body.addEventListener('scroll', function() { header.scrollLeft = body.scrollLeft; }); } }); function changeCheckStatus(grayId, targetStatus) { const formData = new FormData(); formData.append('gray_id', grayId); formData.append('check_status', targetStatus); fetch('?action=update_check_status', { method: 'POST', body: formData }) .then(response => response.json()) .then(data => { if(data.success) { const btnOk = document.getElementById(`btn_ok_${grayId}`); const btnNeed = document.getElementById(`btn_need_${grayId}`); const tableRow = document.getElementById(`tr_${grayId}`); if(targetStatus === 'ok') { btnOk.className = "btn btn-success btn-toggle-check"; btnNeed.className = "btn btn-outline-danger btn-toggle-check"; if(tableRow) tableRow.classList.add('table-success-subtle'); } else { btnOk.className = "btn btn-outline-success btn-toggle-check"; btnNeed.className = "btn btn-danger btn-toggle-check"; if(tableRow) tableRow.classList.remove('table-success-subtle'); } } else { alert('Status update failed: ' + (data.message || 'Unknown Context')); } }) .catch(error => { console.error('Error:', error); alert('Communication breakdown during async status dispatch.'); }); } </script> <?php } if (($_GET['export'] ?? '') === 'pdf') { $autoloadCandidates = [ __DIR__ . '/lib/dompdf/vendor/autoload.php', __DIR__ . '/vendor/autoload.php', dirname(__DIR__) . '/vendor/autoload.php', ]; $autoloadPath = null; foreach ($autoloadCandidates as $candidate) { if (is_file($candidate)) { $autoloadPath = $candidate; break; } } if ($autoloadPath === null) { throw new RuntimeException('PDF library not found.'); } require_once $autoloadPath; $dompdf = new \Dompdf\Dompdf([ 'isHtml5ParserEnabled' => true, 'isRemoteEnabled' => true, ]); ob_start(); ?> <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>Grey Lifecycle Report</title> </head> <body> <?php render_gray_lifecycle_report($rows, $from, $to, $orderSql, $check_filter, true); ?> </body> </html> <?php $html = ob_get_clean(); $dompdf->loadHtml($html, 'UTF-8'); $dompdf->setPaper('A4', 'landscape'); $dompdf->render(); $dompdf->stream('grey-lifecycle-report-' . $from . '-to-' . $to . '.pdf', ['Attachment' => true]); exit; } require_once __DIR__ . '/partials/header.php'; render_gray_lifecycle_report($rows, $from, $to, $orderSql, $check_filter, false); require_once __DIR__ . '/partials/footer.php'; ?>