« Back to History
quality_rate_add.php
|
20260921_175631.php
Initial Domain Snapshot
Copy Code
<?php /* ============================================================================ File: /erp/quality_rate_manage.php Purpose: Company-scoped Add + Edit + List for quality_rates Notes: Defensive checks to avoid "offset of type string" errors ============================================================================ */ require_once __DIR__ . '/modules/auth/page_acl.php'; require_once __DIR__ . '/modules/activity/activity_logger.php'; $ctx = page_require_access('quality_rates_manage'); $user = $ctx['user'] ?? null; $company_id = (int)($ctx['company_id'] ?? 0); $pdo = $ctx['pdo'] ?? null; if (!$pdo) { require_once __DIR__ . '/core/db.php'; if (isset($GLOBALS['pdo'])) $pdo = $GLOBALS['pdo']; } if (!$pdo) { die("Database connection not available."); } if (!function_exists('h')) { function h($s) { return htmlspecialchars($s ?? '', ENT_QUOTES, 'UTF-8'); } } // session + CSRF if (session_status() === PHP_SESSION_NONE) session_start(); if (empty($_SESSION['csrf_token'])) $_SESSION['csrf_token'] = bin2hex(random_bytes(16)); $errors = []; $success = ''; // use GET ?id= for edit $edit_id = isset($_GET['id']) ? (int)$_GET['id'] : 0; // default form $form = ['quality_id' => 0, 'quality_name' => '', 'rate' => '']; // --- load qualities for dropdown (company-scoped) --- $qualities = []; try { $stmt = $pdo->prepare("SELECT id, quality_name FROM qualities WHERE company_id = :cid AND (is_active IS NULL OR is_active = 1) ORDER BY quality_name"); $stmt->execute([':cid' => $company_id]); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); if (is_array($rows)) $qualities = $rows; } catch (Exception $e) { $errors[] = "Failed to load qualities: " . $e->getMessage(); } // --- if editing, load the record safely --- if ($edit_id > 0) { try { $st = $pdo->prepare("SELECT id, quality_id, quality_name, rate FROM quality_rates WHERE id = :id AND company_id = :cid LIMIT 1"); $st->execute([':id' => $edit_id, ':cid' => $company_id]); $r = $st->fetch(PDO::FETCH_ASSOC); if ($r && is_array($r)) { $form['quality_id'] = isset($r['quality_id']) && $r['quality_id'] !== null ? (int)$r['quality_id'] : -1; $form['quality_name'] = isset($r['quality_name']) ? (string)$r['quality_name'] : ''; $form['rate'] = isset($r['rate']) ? (string)$r['rate'] : ''; } else { $errors[] = "Record not found or not authorized."; } } catch (Exception $e) { $errors[] = "Failed to load record: " . $e->getMessage(); } } // --- handle POST (insert/update) --- if ($_SERVER['REQUEST_METHOD'] === 'POST') { $token = $_POST['csrf_token'] ?? ''; if (!hash_equals($_SESSION['csrf_token'], (string)$token)) { $errors[] = "Invalid CSRF token."; } $edit_id = (int)($_POST['edit_id'] ?? 0); $quality_id = (int)($_POST['quality_id'] ?? 0); $quality_name = trim((string)($_POST['quality_name'] ?? '')); $rate = trim((string)($_POST['rate'] ?? '')); $uid = (int)($user['id'] ?? 0); // validation if ($company_id <= 0) $errors[] = "Invalid company context."; if ($quality_id <= 0 && $quality_name === '') $errors[] = "Please select a quality or enter a quality name."; if ($rate === '' || !is_numeric($rate)) $errors[] = "Rate is required and must be numeric."; // if a master quality is chosen but name is empty, pull display name (not required) if ($quality_id > 0 && $quality_name === '' && is_array($qualities)) { foreach ($qualities as $q) { if (is_array($q) && isset($q['id']) && (int)$q['id'] === $quality_id) { $quality_name = (string)($q['quality_name'] ?? ''); break; } } } if (empty($errors)) { try { $now = (new DateTime())->format('Y-m-d H:i:s'); if ($edit_id > 0) { // update $upd = $pdo->prepare("UPDATE quality_rates SET quality_id = :qid, quality_name = :qname, rate = :rate, updated_at = :updated WHERE id = :id AND company_id = :cid"); $upd->execute([ ':qid' => $quality_id > 0 ? $quality_id : null, ':qname' => $quality_name !== '' ? $quality_name : null, ':rate' => $rate, ':updated' => $now, ':id' => $edit_id, ':cid' => $company_id ]); activity_log([ 'company_id' => $company_id ?? 0, 'user_id' => $user['id'] ?? ($_SESSION['user_id'] ?? 0), 'module' => 'quality', 'action_name' => 'edit', 'entity_type' => 'quality_rate', 'entity_id' => $edit_id ?? 0, 'remarks' => 'Quality rate updated' ]); $success = "Quality rate updated successfully."; } else { // duplicate check if ($quality_id > 0) { $chk = $pdo->prepare("SELECT COUNT(*) FROM quality_rates WHERE company_id = :cid AND quality_id = :qid"); $chk->execute([':cid' => $company_id, ':qid' => $quality_id]); if ((int)$chk->fetchColumn() > 0) throw new Exception("A rate for the selected quality already exists."); } else { $chk = $pdo->prepare("SELECT COUNT(*) FROM quality_rates WHERE company_id = :cid AND quality_name = :qname"); $chk->execute([':cid' => $company_id, ':qname' => $quality_name]); if ((int)$chk->fetchColumn() > 0) throw new Exception("A rate for this quality name already exists."); } $ins = $pdo->prepare("INSERT INTO quality_rates (company_id, quality_id, quality_name, rate, created_by, created_at, updated_at) VALUES (:cid, :qid, :qname, :rate, :uid, :now, :now)"); $ins->execute([ ':cid' => $company_id, ':qid' => $quality_id > 0 ? $quality_id : null, ':qname' => $quality_name !== '' ? $quality_name : null, ':rate' => $rate, ':uid' => $uid, ':now' => $now ]); activity_log([ 'company_id' => $company_id ?? 0, 'user_id' => $user['id'] ?? ($_SESSION['user_id'] ?? 0), 'module' => 'quality', 'action_name' => 'create', 'entity_type' => 'quality_rate', 'entity_id' => (int)$pdo->lastInsertId(), 'remarks' => 'Quality rate created' ]); $success = "Quality rate added successfully."; // reset form after insert $form = ['quality_id' => 0, 'quality_name' => '', 'rate' => '']; } // regenerate token $_SESSION['csrf_token'] = bin2hex(random_bytes(16)); } catch (Exception $e) { $errors[] = $e->getMessage(); // keep posted values in form so user doesn't lose input $form['quality_id'] = $quality_id; $form['quality_name'] = $quality_name; $form['rate'] = $rate; } } else { // repopulate on validation errors $form['quality_id'] = $quality_id; $form['quality_name'] = $quality_name; $form['rate'] = $rate; } // refresh qualities list (safe) try { $stmt = $pdo->prepare("SELECT id, quality_name FROM qualities WHERE company_id = :cid AND (is_active IS NULL OR is_active = 1) ORDER BY quality_name"); $stmt->execute([':cid' => $company_id]); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); if (is_array($rows)) $qualities = $rows; } catch (Exception $e) { /* ignore refresh errors */ } } // --- fetch list for display (use COALESCE to prefer custom name) --- $list = []; try { $lst = $pdo->prepare("SELECT qr.id, COALESCE(qr.quality_name, q.quality_name) AS quality_name, qr.rate FROM quality_rates qr LEFT JOIN qualities q ON q.id = qr.quality_id WHERE qr.company_id = :cid ORDER BY qr.id DESC"); $lst->execute([':cid' => $company_id]); $rows = $lst->fetchAll(PDO::FETCH_ASSOC); if (is_array($rows)) $list = $rows; } catch (Exception $e) { $errors[] = "Failed to load quality rates: " . $e->getMessage(); } // render require_once __DIR__ . '/partials/header.php'; ?> <div class="container card"> <div class="card-body"> <h2 class="card-title"><?php echo $edit_id > 0 ? 'Edit Quality Rate' : 'Add Quality Rate'; ?></h2> <?php if (!empty($errors)): ?> <div class="notice notice-danger"> <ul><?php foreach ($errors as $e) echo '<li>'.h($e).'</li>'; ?></ul> </div> <?php endif; ?> <?php if ($success): ?> <div class="notice notice-success"><?php echo h($success); ?></div> <?php endif; ?> <form method="post" class="form-grid" autocomplete="off"> <input type="hidden" name="csrf_token" value="<?php echo h($_SESSION['csrf_token']); ?>"> <input type="hidden" name="edit_id" value="<?php echo (int)$edit_id; ?>"> <div class="form-row"> <label>Quality</label> <select name="quality_id" id="quality_id"> <option value="0">-- Select quality --</option> <?php if (is_array($qualities)): foreach ($qualities as $q): if (!is_array($q)) continue; $qid = (int)($q['id'] ?? 0); $qname = (string)($q['quality_name'] ?? ''); $sel = ($form['quality_id'] === $qid) ? 'selected' : ''; ?> <option value="<?php echo h($qid); ?>" <?php echo $sel; ?>><?php echo h($qname); ?></option> <?php endforeach; endif; ?> <option value="-1" <?php if ($form['quality_id'] === -1) echo 'selected'; ?>>-- Other / New --</option> </select> </div> <div class="form-row" id="quality_name_row" style="<?php echo ($form['quality_id'] === -1) ? '' : 'display:none;'; ?>"> <label>Quality Name (new)</label> <input type="text" name="quality_name" id="quality_name" value="<?php echo h($form['quality_name']); ?>"> </div> <div class="form-row"> <label>Rate</label> <input type="text" name="rate" required value="<?php echo h($form['rate']); ?>" placeholder="e.g., 8.00"> </div> <div class="form-row"> <button type="submit" class="btn"><?php echo $edit_id > 0 ? 'Update' : 'Add'; ?></button> <a href="/erp/quality_rate_manage.php" class="btn btn-secondary">Reset</a> </div> </form> <hr> <h3 class="mt-3">Existing Quality Rates</h3> <table class="table"> <thead><tr><th>ID</th><th>Quality</th><th>Rate</th><th>Action</th></tr></thead> <tbody> <?php if (!empty($list)): foreach ($list as $r): ?> <?php $display = ''; if (is_array($r)) { $display = (string)($r['quality_name'] ?? ''); } ?> <tr> <td><?php echo (int)($r['id'] ?? 0); ?></td> <td><?php echo h($display); ?></td> <td><?php echo h($r['rate'] ?? ''); ?></td> <td><a class="btn btn-small" href="?id=<?php echo (int)($r['id'] ?? 0); ?>">Edit</a></td> </tr> <?php endforeach; else: ?> <tr><td colspan="4" class="small text-muted">No quality rates found for this company.</td></tr> <?php endif; ?> </tbody> </table> </div> </div> <script> (function(){ var sel = document.getElementById('quality_id'); var row = document.getElementById('quality_name_row'); var name = document.getElementById('quality_name'); function toggle(){ if (!sel) return; if (sel.value === '-1') { row.style.display = ''; if (name) name.required = true; } else { row.style.display = 'none'; if (name) { name.required = false; name.value = ''; } } } if (sel) { sel.addEventListener('change', toggle); toggle(); } })(); </script> <?php require_once __DIR__ . '/partials/footer.php'; ?>