« Back to History
gray_lifecycle_report.php
|
20260723_000646.php
Initial Domain Snapshot
Copy Code
<?php 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']; // Get Filters $from = $_GET['from'] ?? date('Y-m-d', strtotime('-30 days')); $to = $_GET['to'] ?? date('Y-m-d'); $order = $_GET['order'] ?? 'DESC'; $mill_id = isset($_GET['mill_id']) ? (int)$_GET['mill_id'] : 0; // Status filter: array expectations for handling multiple selections $selected_statuses = isset($_GET['statuses']) && is_array($_GET['statuses']) ? $_GET['statuses'] : []; $orderSql = ($order === 'ASC') ? 'ASC' : 'DESC'; /* ============================================================================= EAGER LOAD MILL MASTER FOR FILTER DROPDOWN ============================================================================= */ $millMstStmt = $pdo->prepare("SELECT id, short_name FROM mill_master WHERE company_id = :cid ORDER BY short_name ASC"); $millMstStmt->execute([':cid' => $company_id]); $millsDropdown = $millMstStmt->fetchAll(PDO::FETCH_ASSOC); /* ============================================================================= STEP 1: MAIN GRAY RECEIVE QUERY ============================================================================= */ $params = [':cid' => $company_id, ':f' => $from, ':t' => $to]; $millWhere = ""; if ($mill_id > 0) { $millWhere = " AND g.mill_id = :mid"; $params[':mid'] = $mill_id; } $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 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 WHERE g.company_id = :cid AND g.rec_date BETWEEN :f AND :t $millWhere GROUP BY g.gray_id, g.financial_year ORDER BY g.rec_date $orderSql, g.gray_id $orderSql "; $st = $pdo->prepare($sql); $st->execute($params); $rawRows = $st->fetchAll(PDO::FETCH_ASSOC); /* ============================================================================= STEP 2: EAGER LOAD CUTTING ENTRIES ============================================================================= */ $cutStmt = $pdo->prepare(" SELECT ce.gray_id, GROUP_CONCAT(DISTINCT sct.cut_name ORDER BY sct.cut_name SEPARATOR ', ') as cut_names, COALESCE(SUM(ce.fresh_saree), 0) as total_fresh, COALESCE(SUM(ce.second_saree), 0) as total_second, COALESCE(SUM(ce.total_meter), 0) as total_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 "); $cutStmt->execute([':cid' => $company_id]); $cutMap = []; foreach ($cutStmt->fetchAll(PDO::FETCH_ASSOC) as $c) { $cutMap[$c['gray_id']] = $c; } /* ============================================================================= STEP 3: EAGER LOAD 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'] ]; } /* ============================================================================= STEP 4: EAGER LOAD VA SEND MAP & LIFECYCLE COMBINER ============================================================================= */ $sendStmt = $pdo->prepare(" SELECT challan_no, financial_year, grey_id, mgray_detail, pcs FROM va_send_entry WHERE company_id = :cid "); $sendStmt->execute([':cid' => $company_id]); 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'), '.'); } $lifecycleMap = []; 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) { $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) { 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']) . ')'; } } /* ============================================================================= STEP 5: IN-MEMORY PROCESS & IN-MEMORY STATUS FILTERING ============================================================================= */ $rows = []; foreach ($rawRows as $row) { $gid = $row['gray_id']; // Inject Cutting Data if (isset($cutMap[$gid])) { $row['cut_name'] = $cutMap[$gid]['cut_names']; $row['fresh'] = $cutMap[$gid]['total_fresh']; $row['second_cut'] = $cutMap[$gid]['total_second']; $row['used_meter'] = $cutMap[$gid]['total_used_meter']; } else { $row['cut_name'] = '-'; $row['fresh'] = 0; $row['second_cut'] = 0; $row['used_meter'] = 0; } // Default VA states $row['sent_pcs'] = 0; $row['recv_pcs'] = 0; $row['recv_second'] = 0; $row['challan_details'] = ''; // Inject VA Lifecycle Data $mapKey = (string)$row['financial_year'] . '||' . (string)$gid; 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(', ', $lifecycleMap[$mapKey]['challan_details']); } // Determine Dynamic Calculated Status String $is_not_cut = ($row['fresh'] == 0 && $row['second_cut'] == 0); $is_not_sent = ($row['sent_pcs'] == 0); $pending = (float)($row['sent_pcs'] ?? 0) - (float)($row['recv_pcs'] ?? 0); if ($is_not_cut) { $calculatedStatus = 'CUT_PENDING'; } elseif ($is_not_sent) { $calculatedStatus = 'VA_SEND_PENDING'; } elseif ($pending <= 0) { $calculatedStatus = 'COMPLETED'; } else { $calculatedStatus = 'VA_RECV_PENDING'; } $row['calculated_status_key'] = $calculatedStatus; $row['calculated_pending_val'] = $pending; // Apply multiple selection filter logic if (!empty($selected_statuses)) { if (!in_array($calculatedStatus, $selected_statuses)) { continue; // Skip this row if not matched with selection } } $rows[] = $row; } function render_gray_lifecycle_report(array $rows, string $from, string $to, string $orderSql, int $mill_id, array $selected_statuses, array $millsDropdown, bool $isPdf = false): void { ?> <style> .challan-cell { min-width: 95px; max-width: 120px; white-space: nowrap; line-height: 1.2; } .challan-cell.wrap-challan { white-space: normal; } .challan-line { display: block; } <?php if ($isPdf): ?> body { font-family: DejaVu Sans, sans-serif; font-size: 11px; color: #111; } .container-fluid { padding: 0; } .card { border: 0; box-shadow: none; } .table-responsive { overflow: visible; } .table { width: 100%; border-collapse: collapse; font-size: 8.8px; } .table th, .table td { border: 1px solid #222; padding: 2px 3px; vertical-align: middle; } .table-dark th { background: #212529; color: #fff; } .badge { display: inline-block; padding: 2px 6px; 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; } .text-danger { color: #dc3545; } .text-success { color: #198754; } .text-warning { color: #b78103; } .text-info { color: #0dcaf0; } .fw-bold { font-weight: 700; } .table-hover tbody tr:nth-child(even) { background: #fafafa; } .challan-cell { min-width: 90px; max-width: 115px; white-space: nowrap; word-break: break-word; } .challan-cell.wrap-challan, .status-cell { white-space: normal; word-break: break-word; } .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: 8mm 6mm; } 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; } .table-responsive { overflow: visible !important; } table { page-break-inside: auto !important; break-inside: auto !important; } thead { display: table-header-group; } tfoot { display: table-footer-group; } tbody tr { page-break-inside: avoid !important; break-inside: avoid !important; } .table { width: 100% !important; font-size: 8.8px !important; table-layout: auto !important; } .table th, .table td { padding: 2px 3px !important; vertical-align: middle !important; } .table th { white-space: nowrap !important; } .challan-cell { min-width: 90px !important; max-width: 115px !important; white-space: nowrap !important; word-break: break-word; } .challan-cell.wrap-challan { white-space: normal !important; } .status-cell { white-space: normal !important; min-width: 105px !important; word-break: break-word; } .print-header { display: block !important; text-align: center; font-weight: 700; margin-bottom: 8px !important; } } <?php endif; ?> </style> <div class="container-fluid 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)) ?></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> <?php $statusQueryStr = ''; foreach($selected_statuses as $stVal) { $statusQueryStr .= '&statuses[]=' . urlencode($stVal); } ?> <a href="?from=<?= h($from) ?>&to=<?= h($to) ?>&mill_id=<?= $mill_id . $statusQueryStr ?>&order=ASC" class="btn btn-sm btn-outline-primary">ASC</a> <a href="?from=<?= h($from) ?>&to=<?= h($to) ?>&mill_id=<?= $mill_id . $statusQueryStr ?>&order=DESC" class="btn btn-sm btn-outline-primary">DESC</a> <a href="?from=<?= h($from) ?>&to=<?= h($to) ?>&mill_id=<?= $mill_id . $statusQueryStr ?>&order=<?= h($orderSql) ?>&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-3 col-lg-2"> <label class="form-label">From Date</label> <input type="date" name="from" class="form-control" value="<?= h($from) ?>"> </div> <div class="col-md-3 col-lg-2"> <label class="form-label">To Date</label> <input type="date" name="to" class="form-control" value="<?= h($to) ?>"> </div> <div class="col-md-3 col-lg-2"> <label class="form-label">Mill Master</label> <select name="mill_id" class="form-select"> <option value="0">-- All Mills --</option> <?php foreach ($millsDropdown as $mRow): ?> <option value="<?= (int)$mRow['id'] ?>" <?= $mill_id === (int)$mRow['id'] ? 'selected' : '' ?>> <?= h($mRow['short_name']) ?> </option> <?php endforeach; ?> </select> </div> <div class="col-md-3 col-lg-2"> <label class="form-label">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> <!-- Status Checkboxes (Multi-select framework) --> <div class="col-12 mt-2"> <label class="form-label d-block fw-bold">Select Status (Check multiple to include):</label> <div class="d-flex flex-wrap gap-3 bg-light p-2 rounded border"> <div class="form-check"> <input class="form-check-input" type="checkbox" name="statuses[]" value="CUT_PENDING" id="status_cut" <?= in_array('CUT_PENDING', $selected_statuses) ? 'checked' : '' ?>> <label class="form-check-label text-danger fw-bold" for="status_cut">Cutting Entry Pending</label> </div> <div class="form-check"> <input class="form-check-input" type="checkbox" name="statuses[]" value="VA_SEND_PENDING" id="status_send" <?= in_array('VA_SEND_PENDING', $selected_statuses) ? 'checked' : '' ?>> <label class="form-check-label text-secondary fw-bold" for="status_send">Pending for VA Send</label> </div> <div class="form-check"> <input class="form-check-input" type="checkbox" name="statuses[]" value="VA_RECV_PENDING" id="status_recv" <?= in_array('VA_RECV_PENDING', $selected_statuses) ? 'checked' : '' ?>> <label class="form-check-label text-warning fw-bold" for="status_recv">VA Receiving Pending</label> </div> <div class="form-check"> <input class="form-check-input" type="checkbox" name="statuses[]" value="COMPLETED" id="status_comp" <?= in_array('COMPLETED', $selected_statuses) ? 'checked' : '' ?>> <label class="form-check-label text-success fw-bold" for="status_comp">Completed</label> </div> </div> </div> <div class="col-12 d-flex gap-2 mt-3"> <button type="submit" class="btn btn-primary px-4">Apply Filters</button> <a href="?from=<?= h(date('Y-m-d', strtotime('-30 days'))) ?>&to=<?= h(date('Y-m-d')) ?>&order=DESC" class="btn btn-outline-secondary">Last 30 Days</a> <a href="?order=DESC" class="btn btn-outline-dark">Reset All</a> </div> </form> <?php if (empty($rows)): ?> <div class="alert alert-warning mb-0 mt-3"> Selected filter settings ya date range mein koi data nahi mila. Checkboxes badal kar dekhiye. </div> <?php endif; ?> </div> </div> </div> <div class="card"> <div class="table-responsive"> <table class="table table-bordered table-hover align-middle"> <thead class="table-dark"> <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">Status</th> </tr> </thead> <tbody> <?php foreach($rows as $r): $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['calculated_status_key'] === 'CUT_PENDING'); $is_not_sent = ($r['calculated_status_key'] === 'VA_SEND_PENDING'); ?> <tr> <td><?= h($r['gray_id']) ?></td> <td><?= 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="11" class="text-center text-muted fw-bold bg-light"> Pending for Cutting (Cutting Entry Pending) </td> <?php else: ?> <td class="fw-bold"><?= h($r['cut_name'] ?: '-') ?></td> <td class="text-success fw-bold text-end"><?= h(format_report_pcs($r['fresh'])) ?></td> <td class="text-danger text-end"><?= 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">Pending for VA Send</td> <?php else: ?> <td class="text-end"><?= h(format_report_pcs($r['sent_pcs'])) ?></td> <td class="text-danger fw-bold text-end"><?= h(format_report_pcs($not_sent)) ?></td> <td class="text-end"> <?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']); ?> <?= h($recv_total) ?> <br><span class="text-muted small">(<?= h($recv_fresh) ?>+<?= h($recv_second) ?>)</span> </td> <td class="text-end 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($r['calculated_status_key'] === 'CUT_PENDING'): ?> <span class="badge bg-danger">Cutting Entry Pending</span> <?php elseif($r['calculated_status_key'] === 'VA_SEND_PENDING'): ?> <span class="badge bg-secondary">Pending for VA Send</span> <?php elseif($r['calculated_status_key'] === 'COMPLETED'): ?> <span class="badge bg-success">Completed</span> <?php else: ?> <span class="badge bg-warning text-dark">Pending: <?= h(number_format((float)$r['calculated_pending_val'], 2, '.', '')) ?></span> <?php endif; ?> </td> </tr> <?php endforeach; ?> <?php if (empty($rows)): ?> <tr> <td colspan="17" class="text-center text-muted py-4">No lifecycle data found for the selected filter criteria.</td> </tr> <?php endif; ?> </tbody> </table> </div> </div> </div> <?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, $mill_id, $selected_statuses, $millsDropdown, 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, $mill_id, $selected_statuses, $millsDropdown, false); require_once __DIR__ . '/partials/footer.php'; ?>