« Back to History
beam_load_approval.php
|
20260721_154032.php
Initial Bulk Import
Copy Code
<?php declare(strict_types=1); // Enforce strict types for better code quality require_once __DIR__ . '/modules/auth/page_acl.php'; $ctx = page_require_access('beam_load_approval'); $pdo = $ctx['pdo']; $company_id = (int)$ctx['company_id']; $u = $ctx['user']; $user_id = (int)$u['id']; require_once __DIR__ . '/helpers/machine_beam_status_helper.php'; require_once __DIR__ . '/helpers/beam_auto_finish_helper.php'; require_once __DIR__ . '/helpers/activity_helper.php'; function h($v){ return htmlspecialchars((string)$v, ENT_QUOTES, 'UTF-8'); } function debug_step(array &$steps, string $title, string $detail): void { $steps[] = ['title' => $title, 'detail' => $detail]; } function ensure_company_lifecycle_row(PDO $pdo, int $company_id, string $beam_no): string { $pdo->prepare(" INSERT INTO beam_life_cycle (company_id, beam_no, life_events) VALUES (?, ?, JSON_ARRAY()) ON DUPLICATE KEY UPDATE beam_no = beam_no ")->execute([$company_id, $beam_no]); $st = $pdo->prepare(" SELECT beam_no FROM beam_life_cycle WHERE company_id = ? AND beam_no = ? LIMIT 1 "); $st->execute([$company_id, $beam_no]); if ($st->fetchColumn()) { return 'Company-scoped lifecycle row already available.'; } $pdo->prepare(" UPDATE beam_life_cycle SET company_id = ? WHERE beam_no = ? AND COALESCE(company_id, 0) = 0 ")->execute([$company_id, $beam_no]); $st->execute([$company_id, $beam_no]); if ($st->fetchColumn()) { return 'Legacy lifecycle row without company_id was claimed for this company.'; } $legacy = $pdo->prepare(" SELECT company_id FROM beam_life_cycle WHERE beam_no = ? LIMIT 1 "); $legacy->execute([$beam_no]); $legacy_company_id = $legacy->fetchColumn(); if ($legacy_company_id !== false) { $pdo->prepare(" UPDATE beam_life_cycle SET company_id = ? WHERE beam_no = ? ")->execute([$company_id, $beam_no]); $st->execute([$company_id, $beam_no]); if ($st->fetchColumn()) { return 'Legacy lifecycle row moved from company ' . (string)$legacy_company_id . ' to company ' . $company_id . '.'; } } throw new Exception('Beam lifecycle row create/resolve failed for beam ' . $beam_no . '.'); } function fetch_last_lifecycle_event(PDO $pdo, int $company_id, string $beam_no): array { $st = $pdo->prepare(" SELECT life_events FROM beam_life_cycle WHERE company_id = ? AND beam_no = ? LIMIT 1 "); $st->execute([$company_id, $beam_no]); $life_json = $st->fetchColumn(); if (!$life_json) { throw new Exception('Beam lifecycle JSON missing for beam ' . $beam_no . '.'); } $events = json_decode((string)$life_json, true); if (!is_array($events) || empty($events)) { throw new Exception('Beam lifecycle events missing for beam ' . $beam_no . '.'); } $last = end($events); return is_array($last) ? $last : []; } $msg = $err = ''; $debug_enabled = ($company_id === 6); $debug_steps = []; /* ================= ACTION ================= */ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $id = (int)($_POST['id'] ?? 0); $action = $_POST['action'] ?? ''; try { $pdo->beginTransaction(); $st = $pdo->prepare(" SELECT * FROM beam_load_requests WHERE id = ? AND company_id = ? AND status = 'pending' FOR UPDATE "); $st->execute([$id, $company_id]); $r = $st->fetch(PDO::FETCH_ASSOC); if (!$r) throw new Exception('Invalid or already processed request'); if ($action === 'reject') { $remark = trim($_POST['remark'] ?? ''); if ($remark === '') throw new Exception('Reject remark required'); $pdo->prepare(" UPDATE beam_load_requests SET status = 'rejected', reject_remark = ?, approved_by = ?, approved_at = NOW() WHERE id = ? AND company_id = ? ")->execute([$remark, $user_id, $id, $company_id]); $pdo->commit(); log_activity([ 'activity_type' => 'action', 'module_name' => 'beam', 'action_name' => 'REJECT', 'reference_id' => $id, 'activity_note' => "Beam load request #$id rejected. Reason: $remark" ]); $msg = "Rejected successfully"; } if ($action === 'approve') { $beam = null; $running_col = (($r['beam_slot'] ?? '') === 'primary') ? 'primary_running_beam' : 'secondary_running_beam'; $st_running = $pdo->prepare(" SELECT {$running_col} FROM machine_beam_status WHERE company_id = ? AND machine_no = ? LIMIT 1 "); $st_running->execute([$company_id, $r['machine_no']]); $previous_running_beam = $st_running->fetchColumn(); if ($debug_enabled) { debug_step($debug_steps, 'Request locked', 'Pending request #' . $id . ' loaded for machine ' . $r['machine_no'] . ' slot ' . $r['beam_slot'] . '.'); debug_step($debug_steps, 'Previous running beam', $previous_running_beam ? ('Before approval machine par beam ' . $previous_running_beam . ' running tha.') : 'Before approval is slot par koi running beam nahi tha.'); } if (!empty($r['beam_id'])) { $st_beam = $pdo->prepare(" SELECT id, beam_no, beam_slot, quality_id FROM company_beam_stock WHERE id = ? AND company_id = ? AND load_type = 'stock' "); $st_beam->execute([(int)$r['beam_id'], $company_id]); $beam = $st_beam->fetch(PDO::FETCH_ASSOC) ?: null; } if (!$beam && !empty($r['beam_no'])) { $st_beam = $pdo->prepare(" SELECT id, beam_no, beam_slot, quality_id FROM company_beam_stock WHERE beam_no = ? AND company_id = ? AND load_type = 'stock' ORDER BY id DESC LIMIT 1 "); $st_beam->execute([$r['beam_no'], $company_id]); $beam = $st_beam->fetch(PDO::FETCH_ASSOC) ?: null; } if (!$beam) { throw new Exception('Beam stock me nahi hai.'); } if ($debug_enabled) { debug_step($debug_steps, 'Beam stock check', 'Beam ' . $beam['beam_no'] . ' stock me mila. Slot ' . $beam['beam_slot'] . ', quality ' . (string)$beam['quality_id'] . '.'); } if ((string)$beam['beam_slot'] !== (string)$r['beam_slot']) { throw new Exception('Beam slot mismatch.'); } if ($debug_enabled) { debug_step($debug_steps, 'Beam slot verified', 'Request slot aur stock slot dono ' . $r['beam_slot'] . ' hai.'); } $actual_quality_id = (int)($beam['quality_id'] ?? 0); if ($actual_quality_id <= 0) { $actual_quality_id = (int)($r['quality_id'] ?? 0); } if ($actual_quality_id <= 0) { throw new Exception('Could not determine beam quality for approval.'); } if ($debug_enabled) { debug_step($debug_steps, 'Quality resolved', 'Approval quality_id = ' . (string)$actual_quality_id . '.'); } auto_finish_running_beam($pdo, $company_id, $r['machine_no'], $r['beam_slot'], $r['load_date'], $user_id); if ($previous_running_beam) { $st_prev = $pdo->prepare(" SELECT load_type FROM company_beam_stock WHERE company_id = ? AND beam_no = ? LIMIT 1 "); $st_prev->execute([$company_id, $previous_running_beam]); $previous_load_type = (string)$st_prev->fetchColumn(); $previous_last = fetch_last_lifecycle_event($pdo, $company_id, (string)$previous_running_beam); if ($previous_load_type !== 'finished') { throw new Exception('Previous running beam ' . $previous_running_beam . ' stock status not marked finished.'); } if (($previous_last['action'] ?? '') !== 'finish') { throw new Exception('Previous running beam ' . $previous_running_beam . ' lifecycle not marked finish.'); } if ($debug_enabled) { debug_step($debug_steps, 'Previous beam finished', 'Pehale running beam ' . $previous_running_beam . ' ka stock status finished hua aur lifecycle action finish verify hua.'); } } elseif ($debug_enabled) { debug_step($debug_steps, 'Auto finish step', 'No previous running beam tha, isliye finish step skip hua.'); } $pdo->prepare(" INSERT INTO beam_load_data (company_id, financial_year, beam_no, event_type, event_date, machine_no, machine_type, beam_slot, quality_id, load_type, employee_id, load_date, created_by) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?) ")->execute([ $company_id, $r['financial_year'], $beam['beam_no'], 'loaded', $r['load_date'], $r['machine_no'], $r['machine_type'], $r['beam_slot'], $actual_quality_id, // Use the fetched quality_id $r['load_type'], $r['employee_id'], $r['load_date'], $user_id ]); $beam_load_data_id = (string)$pdo->lastInsertId(); if ($debug_enabled) { debug_step($debug_steps, 'Beam load log inserted', 'beam_load_data me loaded event insert hua. Insert id ' . ($beam_load_data_id !== '' ? $beam_load_data_id : 'n/a') . '.'); } $pdo->prepare(" UPDATE company_beam_stock SET load_type = ?, beam_load_date = ? WHERE company_id = ? AND beam_no = ? ")->execute([$r['load_type'], $r['load_date'], $company_id, $beam['beam_no']]); $st_stock = $pdo->prepare(" SELECT load_type, beam_load_date FROM company_beam_stock WHERE company_id = ? AND beam_no = ? LIMIT 1 "); $st_stock->execute([$company_id, $beam['beam_no']]); $stock_row = $st_stock->fetch(PDO::FETCH_ASSOC) ?: []; if (($stock_row['load_type'] ?? '') !== $r['load_type']) { throw new Exception('Beam stock update verification failed for beam ' . $beam['beam_no'] . '.'); } if ($debug_enabled) { debug_step($debug_steps, 'Beam stock updated', 'Beam ' . $beam['beam_no'] . ' ab stock se hat kar load_type ' . $stock_row['load_type'] . ' me chala gaya. Load date ' . ($stock_row['beam_load_date'] ?? '') . '.'); } $lifecycle_resolution = ensure_company_lifecycle_row($pdo, $company_id, (string)$beam['beam_no']); if ($debug_enabled) { debug_step($debug_steps, 'Lifecycle row ensured', 'Beam ' . $beam['beam_no'] . ' ke liye beam_life_cycle row company ' . $company_id . ' par available hai. ' . $lifecycle_resolution); } $pdo->prepare(" UPDATE beam_life_cycle SET life_events = JSON_ARRAY_APPEND( IFNULL(life_events, JSON_ARRAY()), '$', JSON_OBJECT( 'machine_no', ?, 'slot', ?, 'load_date', ?, 'action', 'running', 'machine_id', ? ) ) WHERE company_id = ? AND beam_no = ? ")->execute([ (string)$r['machine_no'], $r['beam_slot'], $r['load_date'], (string)$r['machine_no'], $company_id, $beam['beam_no'] ]); $current_last = fetch_last_lifecycle_event($pdo, $company_id, (string)$beam['beam_no']); if ( ($current_last['action'] ?? '') !== 'running' || (string)($current_last['machine_no'] ?? '') !== (string)$r['machine_no'] || (string)($current_last['slot'] ?? '') !== (string)$r['beam_slot'] || (string)($current_last['load_date'] ?? '') !== (string)$r['load_date'] ) { throw new Exception('Beam lifecycle verification failed for beam ' . $beam['beam_no'] . '.'); } if ($debug_enabled) { debug_step($debug_steps, 'Lifecycle appended', 'Is beam ki lifecycle add hui: machine ' . ($current_last['machine_no'] ?? '') . ', slot ' . ($current_last['slot'] ?? '') . ', action ' . ($current_last['action'] ?? '') . ', load date ' . ($current_last['load_date'] ?? '') . '.'); } machine_on_beam_load($pdo, $company_id, $r['machine_no'], $r['machine_type'], $r['beam_slot'], (int)$beam['beam_no']); $st_running->execute([$company_id, $r['machine_no']]); $current_running_beam = (string)$st_running->fetchColumn(); if ($current_running_beam !== (string)$beam['beam_no']) { throw new Exception('Machine running beam verification failed for machine ' . $r['machine_no'] . '.'); } if ($debug_enabled) { debug_step($debug_steps, 'Machine status updated', 'Machine ' . $r['machine_no'] . ' ke ' . $r['beam_slot'] . ' slot par ab beam ' . $current_running_beam . ' running verified hai.'); } $pdo->prepare(" UPDATE beam_load_requests SET status = 'approved', approved_by = ?, approved_at = NOW() WHERE id = ? AND company_id = ? ")->execute([$user_id, $id, $company_id]); if ($debug_enabled) { debug_step($debug_steps, 'Request approved', 'Request #' . $id . ' approved mark ho gayi.'); } $pdo->commit(); log_activity([ 'activity_type' => 'action', 'module_name' => 'beam', 'action_name' => 'APPROVE', 'reference_id' => $id, 'activity_note' => "Beam load request #$id approved for beam " . ($beam['beam_no'] ?? '') ]); $msg = "Approved successfully"; } } catch (Exception $e) { $pdo->rollBack(); $err = $e->getMessage(); } } /* ================= LIST ================= */ $st = $pdo->prepare(" SELECT r.*, e.name AS employee_name FROM beam_load_requests r LEFT JOIN company_employee_master e ON e.id = r.employee_id AND e.company_id = r.company_id WHERE r.company_id = ? AND r.status = 'pending' AND r.beam_no IS NOT NULL AND r.machine_no IS NOT NULL ORDER BY r.id DESC "); $st->execute([$company_id]); $beam_list = $st->fetchAll(PDO::FETCH_ASSOC); require_once __DIR__ . '/partials/header.php'; ?> <div class="container-fluid py-4"> <div class="card shadow-sm"> <div class="card-header fw-bold bg-white">Beam Load Approval</div> <div class="card-body"> <?php if ($msg): ?><div class="alert alert-success"><?=h($msg)?></div><?php endif; ?> <?php if ($err): ?><div class="alert alert-danger"><?=h($err)?></div><?php endif; ?> <?php if ($debug_enabled && $debug_steps): ?> <div class="alert alert-info"> <div class="fw-bold mb-2">Debug Verification Report</div> <ol class="mb-0 ps-3"> <?php foreach ($debug_steps as $step): ?> <li class="mb-2"> <strong><?= h($step['title']) ?>:</strong> <?= h($step['detail']) ?> </li> <?php endforeach; ?> </ol> </div> <?php endif; ?> <div class="table-responsive"> <table class="table table-bordered table-sm align-middle"> <thead class="table-light"> <tr> <th>ID</th> <th>Beam</th> <th>Machine</th> <th>Slot</th> <th>Type</th> <th>Employee</th> <th>Date</th> <th>Status</th> <th>Action</th> </tr> </thead> <tbody> <?php foreach ($beam_list as $row): ?> <tr> <td><?=h($row['id'])?></td> <td><?=h($row['beam_no'] ?? '')?></td> <td><?=h($row['machine_no'] ?? '')?></td> <td><?=h($row['beam_slot'] ?? '')?></td> <td><?=h($row['load_type'] ?? '')?></td> <td><?=h($row['employee_name'] ?? '—')?></td> <td><?=h($row['load_date'] ?? '')?></td> <td> <?php $s = $row['status'] ?? ''; ?> <?php if ($s === 'pending'): ?> <span class="badge bg-warning text-dark">Pending</span> <?php elseif ($s === 'approved'): ?> <span class="badge bg-success">Approved</span> <?php elseif ($s === 'rejected'): ?> <span class="badge bg-danger">Rejected</span> <?php else: ?> <span class="badge bg-secondary"><?=h($s)?></span> <?php endif; ?> </td> <td> <?php if (($row['status'] ?? '') === 'pending'): ?> <button class="btn btn-success btn-sm" onclick="approve(<?=$row['id']?>)">Approve</button> <button class="btn btn-danger btn-sm" onclick="openReject(<?=$row['id']?>)">Reject</button> <?php else: ?> <span class="text-muted">—</span> <?php endif; ?> </td> </tr> <?php endforeach; ?> </tbody> </table> </div> </div> </div> </div> <div class="modal fade" id="rejectModal" tabindex="-1"> <div class="modal-dialog"> <div class="modal-content"> <form method="post"> <div class="modal-header"> <h5 class="modal-title">Reject Reason</h5> <button type="button" class="btn-close" data-bs-dismiss="modal"></button> </div> <div class="modal-body"> <input type="hidden" name="id" id="reject_id"> <input type="hidden" name="action" value="reject"> <textarea name="remark" class="form-control" required placeholder="Enter reason"></textarea> </div> <div class="modal-footer"> <button type="submit" class="btn btn-danger">Confirm Reject</button> </div> </form> </div> </div> </div> <form method="post" id="approveForm" style="display:none;"> <input type="hidden" name="id" id="approve_id"> <input type="hidden" name="action" value="approve"> </form> <script> function approve(id){ if(confirm('Approve this beam load?')){ document.getElementById('approve_id').value = id; document.getElementById('approveForm').submit(); } } function openReject(id){ document.getElementById('reject_id').value = id; new bootstrap.Modal(document.getElementById('rejectModal')).show(); } </script> <?php require_once __DIR__ . '/partials/footer.php'; ?>