Afegir o retirar stock de productes

De Wiki personal d'en Guillem Serrat
La revisió el 02:03, 12 gen 2026 per Guseba (discussió | contribucions)
(dif.) ← Versió més antiga | Versió actual (dif.) | Versió més nova → (dif.)

Afegir o retirar stock de productes

L'administrador o responsable del catàleg té la possibilitat mitjançant un formulari de modificar l'stock d'un producte manualment, ja sigui per afegir-ne o per retirar-ne.

Connexió a la BD

En aquest cas no requerim cap sessió, ja que és un formulari que les seves dades actúen en la pròpia pàgina i no cal desar-les en cap sessió.

El que si necessitem és una connexió d'escriptura a la BD.

require_once "../connexioBD/connexioRW.php"; // Connexió a la BBDD

Obtenció dels productes

Aquest codi, s'hagi o no afegit o retirat stock, sempre recuperarà a l'inici tots les productes del catàleg, concretament la ID, el nom i l'stock. Per tant, s'ha de tenir en compte que el fluxe és el següent

  1. Es recuperen les dades
  2. Es modifiquen les dades (si es respon el formulari)
  3. Es mostren les dades del punt 1, desactualitzades

És per això que més endavant es veurà com abordar aquesta situació per no mostrar dades desactualitzades quan es respongui el formulari

Mostra de missatges d'error o èxit

D'igual forma que amb altres codis, aquest compta amb missatges de confirmació o èxit que únicament es mostren si estan definits. En aquest cas, el missatge es defineix en el propi formulari abans de l'HTML, per tant no cal realitzar cap tasca amb sessions

<?php if (!empty($missatge)): ?> <!-- En cas que s'enviï un missatge un cop enviat el formulari -->
   <center><p style="color:green"><?= htmlspecialchars($missatge) ?></p></center> <!-- Missatge d'èxit -->
<?php endif; ?>
<?php if (!empty($missatge_error)): ?> <!-- En cas que s'enviï un missatge un cop enviat el formulari -->
   <center><p style="color:red"><?= htmlspecialchars($missatge_error) ?></p></center> <!-- Missatge d'error -->
<?php endif; ?>

Mostra del formulari

El formulari constarà d'un desplegable amb tots els productes i el seu stock. Per això, mitjançant un foreach, recorrerem l'array de la consulta SQL i imprimirem una opció per cada resultat, incloent el nom del producte i l'stock. El valor de cada opció serà la ID del producte, així quan recuperem les dades del formulari, el valor que ens retorni serà el producte que hem de modificar

<select name="producte_id" id="producte_id" required>
    <?php foreach ($productes as $prod): ?> <!-- Per cada producte del catàleg -->
        <option value="<?= $prod['id'] ?>"> <!-- Creem una opció que té com a valor la ID del producte-->
            <?= htmlspecialchars($prod['nom']) ?> (Stock actual: <?= $prod['estoc'] ?>) <!-- Mostrem el nom del producte i el seu stock actual de la BD -->
        </option>
    <?php endforeach; ?>
</select>

Per últim, disposem d'una entrada numérica (sense mínim ni màxim) i dos botons: un per retirar i l'altre per afegir. Tots dos tenen l'acció a la mateixa pàgina amb un nom identificatiu que servirà per indicar al codi quina acció realitzar

<label for="quantitat">Quantitat a afegir o retirar:</label> <input type="number" name="quantitat" id="quantitat" min="1" required> <!-- Definim la quantitat a afegir o retirar --> <button type="submit" name="afegir">Afegir stock</button> <button type="submit" name="retirar">Retirar stock</button>

El formulari es veuria de la següent forma

Modificació de l'stock del producte

Obtenció de paràmetres

En el moment que s'envia el formulari, recuperem la ID (segons l'opció seleccionada en el desplegable) i la quantitat

// Únicament si s'ha respòs al formulari
if (isset($_POST['producte_id']) && isset($_POST['quantitat'])) { // Comprovem si s'ha enviat el formulari
    $producte_id = $_POST['producte_id']; // Recuperem el ID de producte
    $quantitat = (int)$_POST['quantitat']; // I la quantitat

Definició de l'acció

Segons el botó premut (afegir o retirar) haurà arribat un POST o un altre. Per això comprovem quin dels dos ha arribat per definir l'acció a realitzar

// En cas d'haver premut el botó afegir, l'acció serà afegir
if (isset($_POST['afegir'])) {
    $accio = 'afegir';
} 

// En cas d'haver premut el botó retirar, l'acció serà retirar
if (isset($_POST['retirar'])) {
    $accio = 'retirar';
}

Obtenció del nom del producte i l'stock actual

Un cop sabem quin és el producte, recuperarem el nom (pel missatge) i la l'stock actual (per fer comprovacions a l'hora de retirar stock)

// Busquem el producte seleccionat
foreach ($productes as $prod) { // Dins de tots els productes del catàleg
    if ($prod['id'] == $producte_id) { // El producte que coincideixi la ID pasada en el formulari
        $nom_producte = $prod['nom']; // Recollim el nom del producte
        $stock_actual = $prod['estoc']; // I el seu stock
        break;
    }
}

Modificació de l'stock

Afegir

En cas que l'acció sigui afegir, únicament farem un Update a la BD indicant la ID del producte i sumant a l'stock la quantitat introduida. Per últim, mostrarem el missatge de confirmació

if ($accio === 'afegir') { // En cas que sigui afegir
    $stmt = $pdo->prepare("UPDATE productes SET estoc = estoc + :quantitat WHERE id = :id"); // Sumem la quantitat i l'stock
    $stmt->bindParam(':quantitat', $quantitat);
    $stmt->bindParam(':id', $producte_id);
    $stmt->execute();
    $missatge = "S'han afegit $quantitat unitats al producte $nom_producte.";

Retirar

En cas que sigui retirar, comprovarem si la quantitat retirada és menor a l’stock actual o si supera, és a dir:

  • Si tenim 50 unitats i retirem menys de les que hi ha (30, 10, 45, etc)
  • Si tenim 50 unitats i retirem igual o més de les que hi ha (50, 75, 90, etc). Recordem que l'entrada numèrica no té un màxim i per tant podem arribar a definir un nombre més gran del que realment hi ha a la BD

En cas de retirar menys unitats de les que hi ha, restarem la quantitat especificada a l’stock de la BD

} elseif ($accio === 'retirar') { // En cas que sigui retirar
    if ($quantitat < $stock_actual) { // I retirem menys productes dels que hi ha en stock
        $stmt = $pdo->prepare("UPDATE productes SET estoc = estoc - :quantitat WHERE id = :id"); // Restem la quantitat a l'stock
        $stmt->bindParam(':quantitat', $quantitat);
        $stmt->bindParam(':id', $producte_id);
        $stmt->execute();
        $missatge = "S'han retirat $quantitat unitats del producte $nom_producte.";

I per últim, en cas de retirar totes o més unitats de les que hi ha directament establirem el valor a 0, així evitem registrar números negatius.

} else { // Si retirem igual o més productes dels que hi ha en stock
    $stmt = $pdo->prepare("UPDATE productes SET estoc = 0 WHERE id = :id"); // Especifiquem l'stock a 0 per evitar stock negatiu
    $stmt->execute([':id' => $producte_id]);
    $missatge = "Retirades totes les unitats del producte $nom_producte.";
}

Actualització de les dades mostrades

Actualitzarem la variable $productes, ja que el codi abans de realitzar qualsevol operació, realitza una consulta SQL de tots els productes i posteriorment es fan les modificacions. És per això que realitzarem un altre cop la consulta SQL per obtenir l'stock actualitzat

Per tant, el fluxe seria el següent

  1. Es recuperen les dades
  2. Es modifiquen les dades (si es respon el formulari)
  3. Es torna a recuperar les dades (si es respon el formulari)
  4. Es mostren les dades del punt 3, actualitzades
// Actualitzem la llista de productes després del canvi per mostrar-ho en el propi formulari
$stmt = $pdo->query("SELECT id, nom, estoc FROM productes");
$productes = $stmt->fetchAll(PDO::FETCH_ASSOC);

Codi complet

<?php
require_once "../connexioBD/connexioRW.php"; // Connexió a la BBDD

try {
    // Obtenir productes. Aquesta part sempre es realitza per tal de poder mostrar els productes al formulari
    $stmt = $pdo->query("SELECT id, nom, estoc FROM productes");
    $productes = $stmt->fetchAll(PDO::FETCH_ASSOC);


    // Únicament si s'ha respòs al formulari
    if (isset($_POST['producte_id']) && isset($_POST['quantitat'])) { // Comprovem si s'ha enviat el formulari
        $producte_id = $_POST['producte_id']; // Recuperem el ID de producte
        $quantitat = (int)$_POST['quantitat']; // I la quantitat
        
        // En cas d'haver premut el botó afegir, l'acció serà afegir
        if (isset($_POST['afegir'])){
            $accio = 'afegir';
        } 

        // En cas d'haver premut el botó retirar, l'acció serà retirar
        if (isset($_POST['retirar'])){
            $accio = 'retirar';
        }

        // Busquem el producte seleccionat
        foreach ($productes as $prod) { // Dins de tots els productes del catàleg
            if ($prod['id'] == $producte_id) { // El producte que coincideixi la ID pasada en el formulari
                $nom_producte = $prod['nom']; // Recollim el nom del producte
                $stock_actual = $prod['estoc']; // I el seu stock
                break;
            }
        }

        // Sempre que la quantitat sigui superior a 0 (perque faci alguna cosa)
        if ($quantitat > 0) {
            if ($accio === 'afegir') { // En cas que sigui afegir
                $stmt = $pdo->prepare("UPDATE productes SET estoc = estoc + :quantitat WHERE id = :id"); // Sumem la quantitat i l'stock
                $stmt->bindParam(':quantitat', $quantitat);
                $stmt->bindParam(':id', $producte_id);
                $stmt->execute();
                $missatge = "S'han afegit $quantitat unitats al producte $nom_producte.";
            } elseif ($accio === 'retirar') { // En cas que sigui retirar
                if ($quantitat < $stock_actual) { // I retirem menys productes dels que hi ha en stock
                    $stmt = $pdo->prepare("UPDATE productes SET estoc = estoc - :quantitat WHERE id = :id"); // Restem la quantitat a l'stock
                    $stmt->bindParam(':quantitat', $quantitat);
                    $stmt->bindParam(':id', $producte_id);
                    $stmt->execute();
                    $missatge = "S'han retirat $quantitat unitats del producte $nom_producte.";
                } else { // Si retirem igual o més productes dels que hi ha en stock
                    $stmt = $pdo->prepare("UPDATE productes SET estoc = 0 WHERE id = :id"); // Especifiquem l'stock a 0 per evitar stock negatiu
                    $stmt->execute([':id' => $producte_id]);
                    $missatge = "Retirades totes les unitats del producte $nom_producte.";
                }
            }
        } else {
            $missatge_error = "La quantitat ha de ser superior a 0."; // En cas que s'envii un valor inferior a 1
        }

        // Actualitzem la llista de productes després del canvi per mostrar-ho en el propi formulari
        $stmt = $pdo->query("SELECT id, nom, estoc FROM productes");
        $productes = $stmt->fetchAll(PDO::FETCH_ASSOC);
    }

} catch (PDOException $e) {
    $missatge_error = "Error: " . $e->getMessage();
}

?>

<!DOCTYPE html>
<html lang="ca">
<head>
    <meta charset="UTF-8">
    <title>Gestionar Stock</title>
    <link rel="stylesheet" href="../css/stylesStock.css"> <!-- Definim el full d'estils -->
    <style>
        p {
            margin: 10px 0;
            font-size: 1rem;
        }

        p[style*="green"] {
            background-color: #eaf7ea;
            border: 1px solid #b6e2b6;
            padding: 10px 15px;
            border-radius: 6px;
            display: inline-block;
        }
    </style>
</head>
<body>
    <br><br><br><br><br><br><br> <!-- Salts de línia molt poc elegants pero molt eficients per centrar el contingut -->
    <h1>Gestionar Stock de Productes</h1>
    <?php if (!empty($missatge)): ?> <!-- En cas que s'enviï un missatge un cop enviat el formulari -->
        <center><p style="color:green"><?= htmlspecialchars($missatge) ?></p></center> <!-- Missatge d'èxit -->
    <?php endif; ?>
    <?php if (!empty($missatge_error)): ?> <!-- En cas que s'enviï un missatge un cop enviat el formulari -->
        <center><p style="color:red"><?= htmlspecialchars($missatge_error) ?></p></center> <!-- Missatge d'error -->
    <?php endif; ?>

<form method="post"> <!-- Formulari per afegir stock -->
    <label for="producte_id">Selecciona un producte:</label>
    <select name="producte_id" id="producte_id" required>
        <?php foreach ($productes as $prod): ?> <!-- Per cada producte del catàleg -->
            <option value="<?= $prod['id'] ?>"> <!-- Creem una opció que té com a valor la ID del producte-->
                <?= htmlspecialchars($prod['nom']) ?> (Stock actual: <?= $prod['estoc'] ?>) <!-- Mostrem el nom del producte i el seu stock actual de la BD -->
            </option>
        <?php endforeach; ?>
    </select>
    <label for="quantitat">Quantitat a afegir o retirar:</label>
    <input type="number" name="quantitat" id="quantitat" min="1" required> <!-- Definim la quantitat a afegir o retirar -->
    <button type="submit" name="afegir">Afegir stock</button>
    <button type="submit" name="retirar">Retirar stock</button>
</form>
</body>
</html>