✏️ 编辑:stock_deduct.php
路径:
/home/boguraj1/public_html/isp/stock_deduct.php
大小:9.33 KB · 修改:2026-06-15 23:28:10 · 权限:0644 · 可写
← 返回目录
👁 查看
⬇ 下载
<?php session_start(); require_once 'includes/auth.php'; requireAdmin(); require_once 'config/db.php'; // Fetch all products $all_products = $pdo->query( "SELECT id, name, current_stock, unit FROM products ORDER BY name ASC" )->fetchAll(); // Pre-select product when coming from product list $preselect_id = (int) ($_GET['product_id'] ?? 0); $success = ''; $error = ''; $form = [ 'product_id' => $preselect_id, 'quantity' => '', 'notes' => '', ]; if ($_SERVER['REQUEST_METHOD'] === 'POST') { $form['product_id'] = (int) ($_POST['product_id'] ?? 0); $form['quantity'] = trim($_POST['quantity'] ?? ''); $form['notes'] = trim($_POST['notes'] ?? ''); $quantity = (int) $form['quantity']; if ($form['product_id'] <= 0) { $error = 'Please select a product.'; } elseif ($quantity <= 0) { $error = 'Quantity must be a positive number.'; } else { // Fetch fresh product data (prevents race-condition on stock) $prod_stmt = $pdo->prepare("SELECT id, name, current_stock, unit FROM products WHERE id = ?"); $prod_stmt->execute([$form['product_id']]); $product = $prod_stmt->fetch(); if (!$product) { $error = 'Selected product not found.'; } elseif ($quantity > $product['current_stock']) { $error = "Cannot deduct {$quantity} — only {$product['current_stock']} {$product['unit']}(s) in stock."; } else { // Decrease stock $pdo->prepare("UPDATE products SET current_stock = current_stock - ? WHERE id = ?") ->execute([$quantity, $product['id']]); // Log the transaction $pdo->prepare( "INSERT INTO stock_transactions (product_id, user_id, quantity, type, notes) VALUES (?, ?, ?, 'deducted', ?)" )->execute([$product['id'], $_SESSION['user_id'], $quantity, $form['notes']]); $remaining = $product['current_stock'] - $quantity; $success = "Deducted {$quantity} {$product['unit']}(s) from \"{$product['name']}\". " . "Remaining stock: {$remaining} {$product['unit']}(s)."; // Refresh products $all_products = $pdo->query( "SELECT id, name, current_stock, unit FROM products ORDER BY name ASC" )->fetchAll(); $form = ['product_id' => 0, 'quantity' => '', 'notes' => '']; } } } include 'includes/header.php'; ?> <div class="row mb-3"> <div class="col"> <h4 class="page-title"><i class="bi bi-dash-square me-2 text-danger"></i>Deduct Stock</h4> <nav aria-label="breadcrumb"> <ol class="breadcrumb"> <li class="breadcrumb-item"><a href="dashboard.php">Dashboard</a></li> <li class="breadcrumb-item active">Deduct Stock</li> </ol> </nav> </div> </div> <div class="row justify-content-center"> <div class="col-md-7 col-lg-6"> <div class="card"> <div class="card-header bg-danger text-white"> <i class="bi bi-arrow-down-circle me-1"></i> Deduct / Use Stock </div> <div class="card-body"> <?php if ($success !== ''): ?> <div class="alert alert-success d-flex align-items-start gap-2"> <i class="bi bi-check-circle-fill mt-1"></i> <div> <?= htmlspecialchars($success) ?> <div class="mt-2 d-flex gap-2"> <a href="stock_deduct.php" class="btn btn-sm btn-danger">Deduct More</a> <a href="stock_history.php" class="btn btn-sm btn-outline-secondary">View History</a> </div> </div> </div> <?php endif; ?> <?php if ($error !== ''): ?> <div class="alert alert-danger d-flex align-items-center gap-2"> <i class="bi bi-exclamation-triangle-fill"></i> <?= htmlspecialchars($error) ?> </div> <?php endif; ?> <?php if (empty($all_products)): ?> <div class="alert alert-info"> No products available. <a href="add_product.php">Add a product first</a>. </div> <?php else: ?> <form method="POST" action="" novalidate> <div class="mb-3"> <label for="product_id" class="form-label fw-semibold"> Select Product <span class="text-danger">*</span> </label> <select class="form-select" id="product_id" name="product_id" required> <option value="">-- Select a Product --</option> <?php foreach ($all_products as $p): ?> <option value="<?= $p['id'] ?>" data-stock="<?= $p['current_stock'] ?>" data-unit="<?= htmlspecialchars($p['unit']) ?>" <?= (int) $form['product_id'] === (int) $p['id'] ? 'selected' : '' ?>> <?= htmlspecialchars($p['name']) ?> (Stock: <?= number_format($p['current_stock']) ?> <?= $p['unit'] ?>) </option> <?php endforeach; ?> </select> </div> <!-- Dynamic current stock display --> <div class="mb-3"> <label class="form-label fw-semibold">Available Stock</label> <div id="stock-display" class="form-control bg-light fw-bold text-success"> Select a product above </div> </div> <div class="mb-3"> <label for="quantity" class="form-label fw-semibold"> Quantity to Deduct <span class="text-danger">*</span> </label> <input type="number" class="form-control" id="quantity" name="quantity" value="<?= htmlspecialchars($form['quantity']) ?>" min="1" placeholder="Enter quantity" required> <div id="qty-warning" class="form-text text-danger d-none"> Quantity exceeds available stock! </div> </div> <div class="mb-4"> <label for="notes" class="form-label fw-semibold">Reason / Notes (Optional)</label> <input type="text" class="form-control" id="notes" name="notes" value="<?= htmlspecialchars($form['notes']) ?>" placeholder="e.g., Used for customer installation, Faulty unit"> </div> <div class="d-grid gap-2"> <button type="submit" class="btn btn-danger fw-semibold" id="submitBtn"> <i class="bi bi-dash-circle me-1"></i> Deduct Stock </button> <a href="product_list.php" class="btn btn-outline-secondary">Cancel</a> </div> </form> <?php endif; ?> </div> </div> </div> </div> <script> (function () { const select = document.getElementById('product_id'); const display = document.getElementById('stock-display'); const qtyInput = document.getElementById('quantity'); const warning = document.getElementById('qty-warning'); const submitBtn = document.getElementById('submitBtn'); if (!select || !display) return; let currentStock = 0; function updateDisplay() { const opt = select.options[select.selectedIndex]; if (opt && opt.dataset.stock !== undefined) { currentStock = parseInt(opt.dataset.stock, 10); const unit = opt.dataset.unit; display.textContent = currentStock + ' ' + unit + '(s)'; display.className = 'form-control bg-light fw-bold ' + (currentStock === 0 ? 'text-danger' : (currentStock < 10 ? 'text-warning' : 'text-success')); } else { currentStock = 0; display.textContent = 'Select a product above'; display.className = 'form-control bg-light fw-bold text-success'; } validateQty(); } function validateQty() { if (!qtyInput || !warning || !submitBtn) return; const qty = parseInt(qtyInput.value, 10); if (qty > 0 && qty > currentStock) { warning.classList.remove('d-none'); submitBtn.disabled = true; } else { warning.classList.add('d-none'); submitBtn.disabled = false; } } select.addEventListener('change', updateDisplay); if (qtyInput) qtyInput.addEventListener('input', validateQty); updateDisplay(); }()); </script> <?php include 'includes/footer.php'; ?>
💾 保存
取消
保存为 UTF-8,换行统一为 LF