first commit

This commit is contained in:
Emanuele Slusarz
2026-08-22 11:15:29 +02:00
commit ec30fb40b9
38 changed files with 3723 additions and 0 deletions
Vendored Executable
BIN
View File
Binary file not shown.
Vendored Executable
BIN
View File
Binary file not shown.
+26
View File
@@ -0,0 +1,26 @@
<?php
require_once __DIR__ . "/../includes/auth.php";
requireRole("cliente");
$pageTitle = "Dashboard cliente";
$basePath = "..";
require __DIR__ . "/../includes/header.php";
?>
<div class="p-4 mb-4 bg-white rounded shadow-sm">
<h1 class="h3">Ciao, <?= e($_SESSION["nome"]) ?></h1>
<p class="mb-0">Consulta il menu, componi un ordine e controlla le tue consegne.</p>
</div>
<div class="row g-3">
<?php foreach ([
["Menu", "Prodotti disponibili e caratteristiche", "menu.php"],
["Nuovo ordine", "Componi e conferma un ordine", "ordine.php"],
["I miei ordini", "Stato e storico degli ordini", "miei_ordini.php"],
["Preferiti", "I prodotti ordinati più spesso", "preferiti.php"],
["Indirizzi", "Gestisci le destinazioni", "indirizzi.php"],
] as [$titolo, $testo, $url]): ?>
<div class="col-md-6 col-lg-4"><div class="card h-100 shadow-sm"><div class="card-body">
<h2 class="h5"><?= e($titolo) ?></h2><p><?= e($testo) ?></p>
<a class="btn btn-primary" href="<?= e($url) ?>">Apri</a>
</div></div></div>
<?php endforeach; ?>
</div>
<?php require __DIR__ . "/../includes/footer.php"; ?>
+224
View File
@@ -0,0 +1,224 @@
<?php
require_once __DIR__ . "/../includes/auth.php";
requireRole("cliente");
require_once __DIR__ . "/../config/database.php";
$idCliente = (int) $_SESSION["idUtente"];
$azione = $_POST["azione"] ?? null;
$idIndirizzo = filter_input(INPUT_POST, "idIndirizzo", FILTER_VALIDATE_INT);
$via = trim($_POST["via"] ?? "");
$numeroCivico = trim($_POST["numeroCivico"] ?? "");
$idComune = filter_input(INPUT_POST, "idComune", FILTER_VALIDATE_INT);
$indirizzi = [];
$messaggio = null;
$comuni = [];
$stmt = $pdo->prepare("
SELECT
comune.idComune,
comune.nome AS nomeComune,
provincia.nome AS nomeProvincia,
provincia.sigla
FROM comune JOIN provincia ON comune.idProvincia = provincia.idProvincia
");
$stmt->execute();
$comuni = $stmt->fetchAll(PDO::FETCH_ASSOC);
if (postMethod()) {
try {
switch($azione) {
case "predefinito": {
if (!$idIndirizzo) {
$messaggio = "Id indirizzo non valido";
die("Id indirizzo non valido");
}
$pdo->beginTransaction();
// Rimozione dei precedenti indirizzi predefiniti
$stmt = $pdo->prepare("
UPDATE indirizzo
SET predefinito = 0
WHERE idCliente = :idCliente
");
$stmt->execute([
"idCliente" => $idCliente
]);
// Settando indirizzo corrente come predefinito
$stmt = $pdo->prepare("
UPDATE indirizzo
SET predefinito = 1
WHERE
idCliente = :idCliente AND idIndirizzo = :idIndirizzo
");
$stmt->execute([
"idCliente" => $idCliente,
"idIndirizzo" => $idIndirizzo
]);
$pdo->commit();
break;
}
case "inserisci": {
if (
$via === "" ||
$numeroCivico === "" ||
$idComune === ""
) {
$messaggio = "Compila i campi correttamente";
die("Compila i campi correttamente");
}
$stmt = $pdo->prepare("
SELECT EXISTS (
SELECT 1
FROM indirizzo
WHERE idCliente = :idCliente
) AS esiste
");
$stmt->execute([
"idCliente" => $idCliente
]);
$predefinito = $stmt->fetchColumn();
if ($predefinito) {
// Sono presenti record di indirizzi
$predefinito = 0;
} else {
// Non sono presenti record di indirizzi
$predefinito = 1;
}
$pdo->beginTransaction();
$stmt = $pdo->prepare("
INSERT INTO indirizzo (via, numeroCivico, predefinito, idComune, idCliente)
VALUES (:via, :numeroCivico, :predefinito, :idComune, :idCliente)
");
$stmt->execute([
"via" => $via,
"numeroCivico" => $numeroCivico,
"predefinito" => $predefinito,
"idComune" => $idComune,
"idCliente" => $idCliente
]);
$pdo->commit();
break;
}
case "elimina": {
if (!$idIndirizzo) {
$messaggio = "Id indirizzo non valido";
die("Id indirizzo non valido");
}
$pdo->beginTransaction();
$stmt = $pdo->prepare("
DELETE FROM indirizzo
WHERE
idIndirizzo = :idIndirizzo AND idCliente = :idCliente
");
$stmt->execute([
"idIndirizzo" => $idIndirizzo,
"idCliente" => $idCliente
]);
$pdo->commit();
$messaggio = "Indirizzo eliminato con successo";
break;
}
default:
$messaggio = "Azione non valida";
break;
}
} catch (PDOException $e) {
if ($pdo->inTransaction()) {
$pdo->rollBack();
}
die(
"Errore durante l'aggiunta dell'indirizzo di consegna: "
. $e->getMessage()
);
}
}
$stmt = $pdo->prepare("
SELECT
indirizzo.idIndirizzo,
indirizzo.via,
indirizzo.numeroCivico,
indirizzo.predefinito,
comune.nome AS nomeComune,
provincia.sigla AS siglaProvincia
FROM (indirizzo JOIN comune ON indirizzo.idComune = comune.idComune)
JOIN provincia ON comune.idProvincia = provincia.idProvincia
WHERE idCliente = :idCliente
");
$stmt->execute([
"idCliente" => $idCliente
]);
$indirizzi = $stmt->fetchAll(PDO::FETCH_ASSOC);
$pageTitle = "Indirizzi"; $basePath = "..";
require __DIR__ . "/../includes/header.php";
?>
<h1 class="h3">Indirizzi di consegna</h1>
<?php if ($messaggio): ?><div class="alert alert-warning"><?= e($messaggio) ?></div><?php endif; ?>
<div class="row g-4"><div class="col-lg-7">
<?php foreach ($indirizzi as $i): ?>
<div class="card mb-2">
<div class="card-body d-flex justify-content-between">
<div>
<strong><?= e($i["via"] . " " . $i["numeroCivico"]) ?></strong>
<br>
<?= e(($i["nomeComune"] ?? "") . " " . ($i["siglaProvincia"] ?? "")) ?>
<?php if (!empty($i["predefinito"])): ?>
<span class="badge bg-success">Predefinito</span>
<?php endif; ?>
</div>
<form method="post">
<input type="hidden" name="idIndirizzo" value="<?= e($i["idIndirizzo"]) ?>">
<button class="btn btn-sm btn-outline-primary" name="azione" value="predefinito">Predefinito</button>
<button class="btn btn-sm btn-outline-danger" name="azione" value="elimina">Elimina</button>
</form>
</div>
</div>
<?php endforeach; ?>
</div>
<div class="col-lg-5">
<form method="post" class="card card-body shadow-sm">
<h2 class="h5">Nuovo indirizzo</h2>
<input type="hidden" name="azione" value="inserisci">
<div class="mb-3">
<label class="form-label" for="via">Via</label>
<input class="form-control" id="via" name="via" required></div>
<div class="mb-3"><label class="form-label" for="numeroCivico">Numero civico</label>
<input class="form-control" id="numeroCivico" name="numeroCivico" required></div>
<div class="mb-3"><label class="form-label" for="idComune">Comune</label>
<select class="form-select" id="idComune" name="idComune" required>
<option value="">
Seleziona un comune
</option>
<?php foreach ($comuni as $comune):?>
<option value="<?= $comune["idComune"] ?>">
<?=
htmlspecialchars($comune["nomeComune"] . " - " . $comune["nomeProvincia"] . " - " . $comune["sigla"])
?>
</option>
<?php endforeach; ?>
</select>
<br>
<button class="btn btn-primary">Salva</button>
</form>
</div>
</div>
<?php require __DIR__ . "/../includes/footer.php"; ?>
+46
View File
@@ -0,0 +1,46 @@
<?php
require_once __DIR__ . "/../includes/auth.php";
requireRole("cliente");
require_once __DIR__ . "/../config/database.php";
$idCliente = (int) $_SESSION["idUtente"];
$prodotti = [];
$stmt = $pdo->prepare("
SELECT
prodotto.idProdotto,
prodotto.nome,
prodotto.descrizione,
prodotto.prezzoBase,
caratteristica.nome AS nomeCaratteristica,
caratteristica.differenzaPrezzo
FROM prodotto JOIN caratteristica ON prodotto.idProdotto = caratteristica.idProdotto
");
$stmt->execute();
$prodotti = $stmt->fetchAll(PDO::FETCH_ASSOC);
$pageTitle = "Menu"; $basePath = "..";
require __DIR__ . "/../includes/header.php";
?>
<div class="d-flex justify-content-between align-items-center mb-3">
<div><h1 class="h3 mb-1">Menu</h1><p class="text-muted mb-0">Prodotti disponibili e personalizzazioni.</p></div>
<a class="btn btn-primary" href="ordine.php">Componi ordine</a>
</div>
<?php if (!$prodotti): ?>
<div class="alert alert-info">Il menu sarà visualizzato dopo l'implementazione della Query 1.</div>
<?php endif; ?>
<div class="row g-3">
<?php foreach ($prodotti as $prodotto): ?>
<div class="col-md-6"><div class="card h-100 shadow-sm"><div class="card-body">
<h2 class="h5"><?= e($prodotto["nome"] ?? "") ?></h2>
<p><?= e($prodotto["descrizione"] ?? "") ?></p>
<span class="badge bg-primary">€ <?= e(number_format((float) ($prodotto["prezzoBase"] ?? 0), 2, ",", ".")) ?></span>
<?php if (!empty($prodotto["nomeCaratteristica"])): ?>
<hr><strong>Caratteristica:</strong> <?= e($prodotto["nomeCaratteristica"]) ?>
(+ € <?= e($prodotto["differenzaPrezzo"] ?? 0) ?>)
<?php endif; ?>
</div></div></div>
<?php endforeach; ?>
</div>
<?php require __DIR__ . "/../includes/footer.php"; ?>
+88
View File
@@ -0,0 +1,88 @@
<?php
require_once __DIR__ . "/../includes/auth.php";
requireRole("cliente");
require_once __DIR__ . "/../config/database.php";
$idCliente = (int) $_SESSION["idUtente"];
$ordini = [];
$stmt = $pdo->prepare("
SELECT
o1.idOrdine,
o1.dataOraCreazione,
o1.statoConferma,
o1.orarioConsegna,
o1.totale,
o1.tempoStimatoConsegna,
so1.nomeStato
FROM
ordine AS o1
JOIN storicoStato AS ss1
ON o1.idOrdine = ss1.idOrdine
JOIN statoOrdine AS so1
ON ss1.idStatoOrdine = so1.idStatoOrdine
WHERE
o1.idCliente = :idCliente
AND so1.posizione = (
SELECT
MAX(so2.posizione)
FROM
storicoStato AS ss2
JOIN statoOrdine AS so2
ON ss2.idStatoOrdine = so2.idStatoOrdine
WHERE
ss2.idOrdine = o1.idOrdine
)
");
$stmt->execute([
"idCliente" => $idCliente
]);
$ordini = $stmt->fetchAll(PDO::FETCH_ASSOC);
/* TODO SQL DI SUPPORTO - Elenco e stato degli ordini del cliente.
* Input: $idCliente. Output: idOrdine, dataOraCreazione, statoConferma,
* orarioConsegna, totale, tempoStimatoConsegna, nomeStato. */
$pageTitle = "I miei ordini"; $basePath = "..";
require __DIR__ . "/../includes/header.php";
?>
<h1 class="h3">I miei ordini</h1>
<?php if (!$ordini): ?>
<div class="alert alert-info">Nessun ordine da mostrare.</div>
<?php endif; ?>
<div class="table-responsive">
<table class="table table-striped align-middle">
<thead>
<tr>
<th>ID</th>
<th>Creato</th>
<th>Conferma</th>
<th>Avanzamento</th>
<th>Consegna</th>
<th>Totale</th>
</tr>
</thead>
<tbody>
<?php foreach ($ordini as $o): ?>
<tr>
<td><?= e($o["idOrdine"]) ?>
</td><td><?= e($o["dataOraCreazione"]) ?>
</td><td>
<span class="badge bg-secondary"><?= e($o["statoConferma"]) ?>
</span>
</td><td><?= e($o["nomeStato"] ?? "—") ?>
</td><td><?= e($o["orarioConsegna"]) ?>
</td><td>€ <?= e($o["totale"]) ?>
</td></tr><?php endforeach; ?>
</tbody></table></div>
<?php require __DIR__ . "/../includes/footer.php"; ?>
+972
View File
@@ -0,0 +1,972 @@
<?php
require_once __DIR__ . "/../includes/auth.php";
requireRole("cliente");
require_once __DIR__ . "/../config/database.php";
$idCliente = (int) $_SESSION["idUtente"];
$idProdotto = filter_input(INPUT_POST, "idProdotto", FILTER_VALIDATE_INT);
$quantita = filter_input(INPUT_POST, "quantita", FILTER_VALIDATE_INT);
$caratteristiche = array_values(
array_unique(
array_filter(
array_map("intval", (array) ($_POST["caratteristiche"] ?? []))
)
)
);
$azione = $_POST["azione"] ?? null;
$orarioConsegna = $_POST["orarioConsegna"] ?? null;
$idIndirizzo = filter_input(INPUT_POST, "idIndirizzo", FILTER_VALIDATE_INT);
$idOrdine = null; // CARICATO
$prodotti = []; // CARICATO
$caratteristicheDisponibili = []; // CARICATO
$indirizzi = []; // CARICATO
$righeOrdine = []; // CARICATO
$riepilogo = null; // CARICATO
$messaggio = $_SESSION["messaggio"] ?? null; // CARICATO
unset($_SESSION["messaggio"]);
/* ============================================================
* INDIRIZZI DEL CLIENTE
* ============================================================
*/
$stmt = $pdo->prepare("
SELECT indirizzo.idIndirizzo, indirizzo.via, indirizzo.numeroCivico,
indirizzo.predefinito, indirizzo.idComune
FROM indirizzo
WHERE indirizzo.idCliente = :idCliente
");
$stmt->execute([
"idCliente" => $idCliente
]);
$indirizzi = $stmt->fetchAll(PDO::FETCH_ASSOC);
/* ============================================================
* EVENTUALE ORDINE IN BOZZA
* ============================================================
*/
$stmt = $pdo->prepare("
SELECT ordine.idOrdine
FROM ordine
WHERE ordine.idCliente = :idCliente
AND ordine.statoConferma = 'bozza'
ORDER BY ordine.dataOraCreazione DESC
LIMIT 1
");
$stmt->execute([
"idCliente" => $idCliente
]);
$idOrdine = $stmt->fetchColumn();
if ($idOrdine === false) {
$idOrdine = null;
}
/* ============================================================
* PRODOTTI DISPONIBILI
* ============================================================
*/
$stmt = $pdo->prepare("
SELECT prodotto.idProdotto, prodotto.nome, prodotto.descrizione,
prodotto.prezzoBase, prodotto.tempoPreparazione,
prodotto.proceduraPreparazione, prodotto.disponibile
FROM prodotto
WHERE prodotto.disponibile = 1
ORDER BY prodotto.nome
");
$stmt->execute();
$prodotti = $stmt->fetchAll(PDO::FETCH_ASSOC);
/* ============================================================
* CARATTERISTICHE DISPONIBILI
* ============================================================
*/
$stmt = $pdo->prepare("
SELECT caratteristica.idCaratteristica, caratteristica.nome,
caratteristica.descrizione, caratteristica.differenzaPrezzo,
caratteristica.predefinita, caratteristica.disponibile,
caratteristica.idProdotto, caratteristica.idGruppoEsclusione,
gruppoEsclusione.nome AS nomeGruppo
FROM caratteristica
LEFT JOIN gruppoEsclusione
ON caratteristica.idGruppoEsclusione = gruppoEsclusione.idGruppoEsclusione
WHERE caratteristica.disponibile = 1
ORDER BY caratteristica.idProdotto,
caratteristica.idGruppoEsclusione,
caratteristica.idCaratteristica
");
$stmt->execute();
$caratteristicheDisponibili = $stmt->fetchAll(PDO::FETCH_ASSOC);
/* ============================================================
* QUERY 3
*
* Inserimento di un prodotto in un ordine
* con le caratteristiche selezionate.
* ============================================================
*/
if (postMethod() && $azione === "aggiungi") {
if (
$idCliente <= 0 ||
!$idProdotto ||
!$quantita ||
$quantita < 1 ||
$quantita > 255
) {
$messaggio = "Dati in input non validi";
} else {
try {
/* Verifico che il prodotto esista e sia disponibile. */
$stmt = $pdo->prepare("
SELECT prodotto.prezzoBase
FROM prodotto
WHERE prodotto.idProdotto = :idProdotto
AND prodotto.disponibile = 1
LIMIT 1
");
$stmt->execute([
"idProdotto" => $idProdotto
]);
$prezzoBaseApplicato = $stmt->fetchColumn();
if ($prezzoBaseApplicato === false) {
$messaggio = "Prodotto inesistente o non disponibile";
} else {
/* Se non esiste una bozza recupero l'indirizzo predefinito. */
if (!$idOrdine) {
$stmt = $pdo->prepare("
SELECT indirizzo.idIndirizzo
FROM indirizzo
WHERE indirizzo.idCliente = :idCliente
AND indirizzo.predefinito = 1
LIMIT 1
");
$stmt->execute([
"idCliente" => $idCliente
]);
$idIndirizzo = $stmt->fetchColumn();
if ($idIndirizzo === false) {
$messaggio = "Prima di creare un ordine devi impostare un indirizzo predefinito.";
}
}
if ($idOrdine || $idIndirizzo) {
$pdo->beginTransaction();
/* ========================================================
* CREAZIONE EVENTUALE BOZZA
* ========================================================
*/
if (!$idOrdine) {
$stmt = $pdo->prepare("
INSERT INTO ordine (
dataOraCreazione,
dataOraConferma,
dataOraAnnullamento,
statoConferma,
orarioConsegna,
totale,
tempoStimatoConsegna,
idCliente,
idIndirizzo
)
VALUES (
NOW(),
NULL,
NULL,
'bozza',
NULL,
0.00,
NULL,
:idCliente,
:idIndirizzo
)
");
$stmt->execute([
"idCliente" => $idCliente,
"idIndirizzo" => $idIndirizzo
]);
$idOrdine = (int) $pdo->lastInsertId();
}
/* ========================================================
* INSERIMENTO RIGA ORDINE
* ========================================================
*/
$stmt = $pdo->prepare("
INSERT INTO rigaOrdine (
quantita,
prezzoBaseApplicato,
idOrdine,
idProdotto
)
VALUES (
:quantita,
:prezzoBaseApplicato,
:idOrdine,
:idProdotto
)
");
$stmt->execute([
"quantita" => $quantita,
"prezzoBaseApplicato" => $prezzoBaseApplicato,
"idOrdine" => $idOrdine,
"idProdotto" => $idProdotto
]);
$idRigaOrdine = (int) $pdo->lastInsertId();
/* ========================================================
* CARATTERISTICHE DELLA RIGA
* ========================================================
*/
$stmtCaratteristica = $pdo->prepare("
SELECT caratteristica.idCaratteristica,
caratteristica.differenzaPrezzo,
caratteristica.idGruppoEsclusione
FROM caratteristica
WHERE caratteristica.idCaratteristica = :idCaratteristica
AND caratteristica.idProdotto = :idProdotto
AND caratteristica.disponibile = 1
LIMIT 1
");
$stmtInserisciCaratteristica = $pdo->prepare("
INSERT INTO rigaOrdineSelezionaCaratteristica (
idCaratteristica,
idRigaOrdine,
differenzaPrezzoApplicata
)
VALUES (
:idCaratteristica,
:idRigaOrdine,
:differenzaPrezzoApplicata
)
");
$gruppiSelezionati = [];
foreach ($caratteristiche as $idCaratteristica) {
$stmtCaratteristica->execute([
"idCaratteristica" => $idCaratteristica,
"idProdotto" => $idProdotto
]);
$caratteristica = $stmtCaratteristica->fetch(PDO::FETCH_ASSOC);
if (!$caratteristica) {
throw new RuntimeException(
"Caratteristica non valida per il prodotto selezionato."
);
}
$idGruppoEsclusione = $caratteristica["idGruppoEsclusione"];
if ($idGruppoEsclusione !== null) {
$idGruppoEsclusione = (int) $idGruppoEsclusione;
if (isset($gruppiSelezionati[$idGruppoEsclusione])) {
throw new RuntimeException(
"Sono state selezionate due caratteristiche incompatibili."
);
}
$gruppiSelezionati[$idGruppoEsclusione] = true;
}
$stmtInserisciCaratteristica->execute([
"idCaratteristica" => $idCaratteristica,
"idRigaOrdine" => $idRigaOrdine,
"differenzaPrezzoApplicata" => $caratteristica["differenzaPrezzo"]
]);
}
/* ========================================================
* FINE QUERY 3
* ========================================================
*/
$pdo->commit();
// POST -> REDIRECT -> GET
header("Location: ordine.php");
exit;
}
}
} catch (Throwable $e) {
if ($pdo->inTransaction()) {
$pdo->rollBack();
}
die(
"Errore durante l'aggiunta del prodotto all'ordine: "
. $e->getMessage()
);
}
}
}
/* ============================================================
* RIGHE DELLA BOZZA
* ============================================================
*/
if ($idOrdine) {
$stmt = $pdo->prepare("
SELECT rigaOrdine.idRigaOrdine,
rigaOrdine.quantita,
rigaOrdine.prezzoBaseApplicato,
rigaOrdine.idOrdine,
rigaOrdine.idProdotto,
prodotto.nome AS nomeProdotto,
(
rigaOrdine.quantita *
(
rigaOrdine.prezzoBaseApplicato +
COALESCE(
(
SELECT SUM(
rigaOrdineSelezionaCaratteristica.differenzaPrezzoApplicata
)
FROM rigaOrdineSelezionaCaratteristica
WHERE rigaOrdineSelezionaCaratteristica.idRigaOrdine =
rigaOrdine.idRigaOrdine
),
0
)
)
) AS subtotale
FROM rigaOrdine
JOIN prodotto
ON rigaOrdine.idProdotto = prodotto.idProdotto
WHERE rigaOrdine.idOrdine = :idOrdine
ORDER BY rigaOrdine.idRigaOrdine
");
$stmt->execute([
"idOrdine" => $idOrdine
]);
$righeOrdine = $stmt->fetchAll(PDO::FETCH_ASSOC);
}
/* ============================================================
* QUERY 4
*
* Calcolo totale e tempo stimato di consegna
* ============================================================
*/
if ($idOrdine) {
$stmt = $pdo->prepare("
SELECT
SUM(
(
rigaOrdine.prezzoBaseApplicato +
COALESCE(
(
SELECT SUM(
rigaOrdineSelezionaCaratteristica.differenzaPrezzoApplicata
)
FROM rigaOrdineSelezionaCaratteristica
WHERE
rigaOrdineSelezionaCaratteristica.idRigaOrdine =
rigaOrdine.idRigaOrdine
),
0
)
) * rigaOrdine.quantita
) AS totale,
SUM(
prodotto.tempoPreparazione * rigaOrdine.quantita
) AS tempoStimatoConsegna
FROM rigaOrdine JOIN prodotto ON prodotto.idProdotto = rigaOrdine.idProdotto
WHERE rigaOrdine.idOrdine = :idOrdine
");
$stmt->execute([
"idOrdine" => $idOrdine
]);
$riepilogo = $stmt->fetch(PDO::FETCH_ASSOC);
}
/* ============================================================
* CONFERMA / ANNULLA
* ============================================================
*/
if (postMethod() && in_array($azione, ["conferma", "annulla"], true)) {
// Annullamento ordine
if ($azione === "annulla") {
// Registrazione dell'annullamento dell'ordine
$stmt = $pdo->prepare("
UPDATE
ordine
SET
ordine.dataOraAnnullamento = NOW(),
ordine.statoConferma = 'annullato',
ordine.orarioConsegna = NULL,
ordine.tempoStimatoConsegna = NULL
WHERE
ordine.idOrdine = :idOrdine
AND ordine.idCliente = :idCliente
AND ordine.statoConferma = 'bozza'
");
$stmt->execute([
"idOrdine" => $idOrdine,
"idCliente" => $idCliente
]);
// Pulizia del riepilogo
header("Location: ordine.php");
// Messaggio
$_SESSION["messaggio"] = "Ordine annullato con successo";
exit;
}
// Conferma ordine
if ($azione === "conferma") {
// Calcolo del tempo di preparazione
$stmt = $pdo->prepare("
SELECT
COALESCE(
SUM(rigaOrdine.quantita * prodotto.tempoPreparazione),
0
) AS tempoPreparazione
FROM
ordine
JOIN rigaOrdine
ON rigaOrdine.idOrdine = ordine.idOrdine
JOIN prodotto
ON rigaOrdine.idProdotto = prodotto.idProdotto
WHERE
ordine.idOrdine = :idOrdine
");
$stmt->execute([
"idOrdine" => $idOrdine
]);
$tempoPreparazione = $stmt->fetchColumn();
// Calcolo del totale
$stmt = $pdo->prepare("
SELECT
COALESCE(
SUM(totali.totaleRigaOrdine),
0
)
FROM
rigaOrdine AS ro1
LEFT JOIN (
SELECT
ro2.idRigaOrdine AS idRigaOrdine,
ro2.quantita * (
ro2.prezzoBaseApplicato
+
COALESCE(
SUM(rosc2.differenzaPrezzoApplicata),
0
)
) AS totaleRigaOrdine
FROM
rigaOrdine AS ro2
LEFT JOIN rigaOrdineSelezionaCaratteristica AS rosc2
ON ro2.idRigaOrdine = rosc2.idRigaOrdine
WHERE
ro2.idOrdine = :idOrdine
GROUP BY
ro2.idRigaOrdine
) AS totali
ON ro1.idRigaOrdine = totali.idRigaOrdine
WHERE
ro1.idOrdine = :idOrdine
");
$stmt->execute([
"idOrdine" => $idOrdine
]);
$totale = $stmt->fetchColumn();
// Registrazione della conferma dell'ordine
$stmt = $pdo->prepare("
UPDATE
ordine
SET
ordine.dataOraConferma = NOW(),
ordine.statoConferma = 'confermato',
ordine.totale = :totale,
ordine.tempoStimatoConsegna = :tempoPreparazione
WHERE
ordine.idOrdine = :idOrdine
AND ordine.idCliente = :idCliente
AND ordine.statoConferma = 'bozza'
");
$stmt->execute([
"idOrdine" => $idOrdine,
"idCliente" => $idCliente,
"totale" => $totale,
"tempoPreparazione" => $tempoPreparazione
]);
// Creazione dello storicoStato e statoOrdine
$stmt = $pdo->prepare("
INSERT
INTO statoOrdine
(
nomeStato,
posizione
)
VALUES (
'IN LAVORAZIONE',
1
)
");
$stmt->execute();
$idStatoOrdine = $pdo->lastInsertId();
$stmt = $pdo->prepare("
INSERT
INTO storicoStato
(
timestamp,
idOrdine,
idStatoOrdine
)
VALUES (
NOW(),
:idOrdine,
:idStatoOrdine
)
");
$stmt->execute([
"idOrdine" => $idOrdine,
"idStatoOrdine" => $idStatoOrdine
]);
// Pulizia del riepilogo
header("Location: ordine.php");
// Messaggio
$_SESSION["messaggio"] = "Ordine confermato con successo";
exit;
}
}
/* ============================================================
* PAGINA
* ============================================================
*/
$pageTitle = "Componi ordine";
$basePath = "..";
require __DIR__ . "/../includes/header.php";
?>
<h1 class="h3">Componi ordine</h1>
<?php if ($messaggio): ?>
<div class="alert alert-warning">
<?= e($messaggio) ?>
</div>
<?php endif; ?>
<div class="row g-4">
<!-- ======================================================
AGGIUNTA PRODOTTO
====================================================== -->
<div class="col-lg-7">
<div class="card shadow-sm">
<div class="card-body">
<h2 class="h5">Aggiungi un prodotto</h2>
<form method="post">
<input type="hidden" name="azione" value="aggiungi">
<!-- PRODOTTO -->
<div class="mb-3">
<label class="form-label" for="idProdotto">Prodotto</label>
<select class="form-select" id="idProdotto" name="idProdotto" required>
<option value="">Seleziona...</option>
<?php foreach ($prodotti as $p): ?>
<option value="<?= e($p["idProdotto"]) ?>">
<?= e($p["nome"]) ?> — € <?= e($p["prezzoBase"]) ?>
</option>
<?php endforeach; ?>
</select>
</div>
<!-- QUANTITA -->
<div class="mb-3">
<label class="form-label" for="quantita">Quantità</label>
<input
class="form-control"
type="number"
min="1"
max="255"
value="1"
id="quantita"
name="quantita"
required
>
</div>
<!-- CARATTERISTICHE -->
<fieldset class="mb-3">
<legend class="h6">Caratteristiche</legend>
<p id="messaggioCaratteristiche" class="text-muted">
Seleziona prima un prodotto.
</p>
<?php foreach ($caratteristicheDisponibili as $c): ?>
<div
class="caratteristica-item align-items-center gap-2"
style="display: none; width: 100%;"
data-id-prodotto="<?= e($c["idProdotto"]) ?>"
>
<input
class="form-check-input caratteristica-checkbox mt-0"
style="float: none; margin-left: 0;"
type="checkbox"
name="caratteristiche[]"
value="<?= e($c["idCaratteristica"]) ?>"
id="c<?= e($c["idCaratteristica"]) ?>"
data-gruppo-esclusione="<?= e($c["idGruppoEsclusione"] ?? "") ?>"
<?= !empty($c["predefinita"]) ? "checked" : "" ?>
disabled
>
<label
class="form-check-label"
for="c<?= e($c["idCaratteristica"]) ?>"
>
<?= e($c["nome"]) ?>
<?php if ($c["idGruppoEsclusione"] !== null): ?>
<small class="text-muted">
(<?= e($c["nomeGruppo"]) ?>)
</small>
<?php endif; ?>
<?= $c["differenzaPrezzo"] >= 0 ? "+" : "" ?>
€ <?= e($c["differenzaPrezzo"]) ?>
</label>
</div>
<?php endforeach; ?>
</fieldset>
<button class="btn btn-primary" type="submit">
Aggiungi all'ordine
</button>
</form>
</div>
</div>
</div>
<!-- ======================================================
RIEPILOGO
====================================================== -->
<div class="col-lg-5">
<div class="card shadow-sm mb-3">
<div class="card-body">
<h2 class="h5">Riepilogo</h2>
<?php if (!$righeOrdine): ?>
<p class="text-muted">La bozza è vuota.</p>
<?php endif; ?>
<?php foreach ($righeOrdine as $r): ?>
<div class="d-flex justify-content-between">
<span>
<?= e($r["quantita"]) ?> × <?= e($r["nomeProdotto"]) ?>
</span>
<span>
€ <?= e($r["subtotale"]) ?>
</span>
</div>
<?php endforeach; ?>
<hr>
<!-- QUERY 4 non ancora implementata. -->
<p>
<strong>Totale:</strong> €
<?= e($riepilogo["totale"] ?? "-")?>
<br>
<strong>Tempo stimato:</strong>
<?= e($riepilogo["tempoStimatoConsegna"] ?? "—") ?> min
</p>
</div>
</div>
<!-- ==================================================
CONFERMA / ANNULLA
================================================== -->
<div class="card shadow-sm">
<div class="card-body">
<h2 class="h5">Conferma o annulla</h2>
<form method="post">
<input type="hidden" name="idOrdine" value="<?= e($idOrdine) ?>">
<!-- INDIRIZZO -->
<div class="mb-3">
<label class="form-label" for="idIndirizzo">
Indirizzo
</label>
<select
class="form-select"
id="idIndirizzo"
name="idIndirizzo"
required
>
<option value="">Seleziona...</option>
<?php foreach ($indirizzi as $i): ?>
<option value="<?= e($i["idIndirizzo"]) ?>">
<?= e($i["via"] . " " . $i["numeroCivico"]) ?>
<?= !empty($i["predefinito"]) ? "(predefinito)" : "" ?>
</option>
<?php endforeach; ?>
</select>
</div>
<!-- ORARIO -->
<div class="mb-3">
<label class="form-label" for="orarioConsegna">
Orario di consegna
</label>
<input
class="form-control"
type="datetime-local"
id="orarioConsegna"
name="orarioConsegna"
required
>
</div>
<button
class="btn btn-success"
name="azione"
value="conferma"
>
Conferma
</button>
<button
class="btn btn-outline-danger"
name="azione"
value="annulla"
formnovalidate
>
Annulla
</button>
</form>
</div>
</div>
</div>
</div>
<!-- ==========================================================
JAVASCRIPT CARATTERISTICHE
========================================================== -->
<script>
document.addEventListener("DOMContentLoaded", function () {
const selectProdotto = document.getElementById("idProdotto");
const caratteristiche = document.querySelectorAll(".caratteristica-item");
const messaggio = document.getElementById("messaggioCaratteristiche");
function aggiornaCaratteristiche() {
const idProdotto = selectProdotto.value;
let trovata = false;
caratteristiche.forEach(function (elemento) {
const appartiene = elemento.dataset.idProdotto === idProdotto;
elemento.style.display = appartiene ? "flex" : "none";
const input = elemento.querySelector("input");
input.disabled = !appartiene;
if (appartiene) {
trovata = true;
}
});
if (!idProdotto) {
messaggio.textContent = "Seleziona prima un prodotto.";
messaggio.classList.remove("d-none");
} else if (!trovata) {
messaggio.textContent = "Questo prodotto non ha caratteristiche disponibili.";
messaggio.classList.remove("d-none");
} else {
messaggio.classList.add("d-none");
}
}
/*
* Se seleziono una caratteristica appartenente ad un gruppo
* deseleziono le altre dello stesso gruppo.
*/
document.querySelectorAll(".caratteristica-checkbox").forEach(function (checkbox) {
checkbox.addEventListener("change", function () {
const gruppo = this.dataset.gruppoEsclusione;
if (!this.checked || !gruppo) {
return;
}
document.querySelectorAll(".caratteristica-checkbox").forEach(function (altra) {
if (altra === checkbox) {
return;
}
if (altra.dataset.gruppoEsclusione === gruppo) {
altra.checked = false;
}
});
});
});
selectProdotto.addEventListener("change", aggiornaCaratteristiche);
aggiornaCaratteristiche();
});
</script>
<?php require __DIR__ . "/../includes/footer.php"; ?>
+22
View File
@@ -0,0 +1,22 @@
<?php
require_once __DIR__ . "/../includes/auth.php";
requireRole("cliente");
require_once __DIR__ . "/../config/database.php";
$idCliente = (int) $_SESSION["idUtente"];
$sogliaMinima = filter_input(INPUT_GET, "sogliaMinima", FILTER_VALIDATE_INT) ?: 3;
$prodotti = [];
/*
* QUERY 10 - Estrazione dei prodotti preferiti da un cliente
* Prodotti più ordinati dal cliente, con soglia minima configurabile.
* Input: $idCliente, $sogliaMinima
* Output atteso: idProdotto, nome, numeroOrdini, quantitaTotale
* TODO SQL: implementare manualmente la Query 10.
*/
$pageTitle = "Prodotti preferiti"; $basePath = "..";
require __DIR__ . "/../includes/header.php";
?>
<h1 class="h3">Prodotti preferiti</h1>
<form method="get" class="card card-body shadow-sm mb-3"><div class="row align-items-end g-3"><div class="col-md-4"><label class="form-label" for="sogliaMinima">Numero minimo di ordini</label><input class="form-control" type="number" min="1" id="sogliaMinima" name="sogliaMinima" value="<?= e($sogliaMinima) ?>" required></div><div class="col-md-3"><button class="btn btn-primary">Calcola</button></div></div></form>
<?php if (!$prodotti): ?><div class="alert alert-info">I preferiti saranno mostrati dopo l'implementazione della Query 10.</div><?php endif; ?>
<table class="table table-striped"><thead><tr><th>Posizione</th><th>Prodotto</th><th>Ordini</th><th>Quantità totale</th></tr></thead><tbody><?php foreach ($prodotti as $n => $p): ?><tr><td><?= e($n + 1) ?></td><td><?= e($p["nome"]) ?></td><td><?= e($p["numeroOrdini"]) ?></td><td><?= e($p["quantitaTotale"]) ?></td></tr><?php endforeach; ?></tbody></table>
<?php require __DIR__ . "/../includes/footer.php"; ?>
+17
View File
@@ -0,0 +1,17 @@
<?php
$host = "db";
$dbname = "delivery";
$username = "root";
$password = "root";
$pdo = new PDO(
"mysql:host=$host;port=3306;dbname=$dbname;charset=utf8mb4",
$username,
$password
);
$pdo -> setAttribute(
PDO::ATTR_ERRMODE,
PDO::ERRMODE_EXCEPTION
);
Vendored Executable
+6
View File
File diff suppressed because one or more lines are too long
+5
View File
@@ -0,0 +1,5 @@
<?php
require_once __DIR__ . "/includes/auth.php";
requireLogin();
header("Location: " . dashboardForRole($_SESSION["ruolo"] ?? null));
exit;
+46
View File
@@ -0,0 +1,46 @@
<?php
if (session_status() !== PHP_SESSION_ACTIVE) {
session_start();
}
function requireLogin(): void
{
if (empty($_SESSION["idUtente"])) {
$cartellaScript = basename(dirname($_SERVER["SCRIPT_NAME"] ?? ""));
$login = $cartellaScript === "PHP" ? "index.php" : "../index.php";
header("Location: " . $login . "?errore=accesso");
exit;
}
}
function requireRole(string $ruolo): void
{
requireLogin();
if (($_SESSION["ruolo"] ?? null) !== $ruolo) {
header("Location: ../dashboard.php?errore=autorizzazione");
exit;
}
}
function dashboardForRole(?string $ruolo): string
{
$destinazioni = [
"cliente" => "cliente/dashboard.php",
"personale" => "personale/dashboard.php",
"proprietario" => "proprietario/dashboard.php",
];
return $destinazioni[$ruolo] ?? "index.php";
}
function e(mixed $valore): string
{
return htmlspecialchars((string) $valore, ENT_QUOTES, "UTF-8");
}
function postMethod(): bool
{
return ($_SERVER["REQUEST_METHOD"] ?? "GET") === "POST";
}
+3
View File
@@ -0,0 +1,3 @@
</main>
</body>
</html>
+15
View File
@@ -0,0 +1,15 @@
<?php
$pageTitle = $pageTitle ?? "Delivery";
$basePath = $basePath ?? "..";
?>
<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?= e($pageTitle) ?> - Delivery</title>
<link rel="stylesheet" href="<?= e($basePath) ?>/css/bootstrap.min.css">
</head>
<body class="bg-light">
<?php require __DIR__ . "/navbar.php"; ?>
<main class="container py-4">
+33
View File
@@ -0,0 +1,33 @@
<?php
$ruolo = $_SESSION["ruolo"] ?? null;
$links = [
"cliente" => [
"Dashboard" => "cliente/dashboard.php", "Menu" => "cliente/menu.php",
"Nuovo ordine" => "cliente/ordine.php", "I miei ordini" => "cliente/miei_ordini.php",
"Preferiti" => "cliente/preferiti.php", "Indirizzi" => "cliente/indirizzi.php",
],
"personale" => [
"Dashboard" => "personale/dashboard.php", "Ordini" => "personale/ordini.php",
],
"proprietario" => [
"Dashboard" => "proprietario/dashboard.php", "Ordini" => "proprietario/ordini.php",
"Prodotti" => "proprietario/prodotti.php", "Caratteristiche" => "proprietario/caratteristiche.php",
"Menu" => "proprietario/menu.php", "Personale" => "proprietario/personale.php",
"Statistiche" => "proprietario/statistiche.php",
],
];
?>
<nav class="navbar navbar-dark bg-dark">
<div class="container d-flex flex-wrap gap-2">
<a class="navbar-brand" href="<?= e($basePath) ?>/dashboard.php">Delivery</a>
<?php if ($ruolo && isset($links[$ruolo])): ?>
<div class="d-flex flex-wrap gap-2 me-auto">
<?php foreach ($links[$ruolo] as $label => $url): ?>
<a class="btn btn-sm btn-outline-light" href="<?= e($basePath . "/" . $url) ?>"><?= e($label) ?></a>
<?php endforeach; ?>
</div>
<span class="navbar-text text-white me-2"><?= e($_SESSION["nome"] ?? "") ?> (<?= e($ruolo) ?>)</span>
<a class="btn btn-sm btn-danger" href="<?= e($basePath) ?>/logout.php">Esci</a>
<?php endif; ?>
</div>
</nav>
Executable
+131
View File
@@ -0,0 +1,131 @@
<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, initial-scale=1.0">
<title>Delivery - Login</title>
<link rel="stylesheet" href="css/bootstrap.min.css">
</head>
<body class="bg-light">
<div class="container mt-5">
<div class="row justify-content-center">
<div class="col-md-6">
<h2 class="mb-4">
Delivery
</h2>
<?php if (isset($_GET["registrazione"])): ?>
<div class="alert alert-success">
Registrazione completata. Ora puoi effettuare il login.
</div>
<?php endif; ?>
<?php if (isset($_GET["errore"])): ?>
<div class="alert alert-danger">
<?= $_GET["errore"] === "accesso" ? "Effettua il login per continuare." : "Email o password errati." ?>
</div>
<?php endif; ?>
<div class="card p-4 shadow-sm">
<form
action="login_action.php"
method="post"
>
<div class="mb-3">
<label
class="form-label"
for="email"
>
Email
</label>
<input
class="form-control"
type="email"
id="email"
name="email"
required
>
</div>
<div class="mb-3">
<label
class="form-label"
for="password"
>
Password
</label>
<input
class="form-control"
type="password"
id="password"
name="password"
required
>
</div>
<button
class="btn btn-primary w-100"
type="submit"
>
Login
</button>
</form>
<div class="text-center mt-3">
Non hai un account?
<a href="registrazione.php">
Registrati
</a>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
+111
View File
@@ -0,0 +1,111 @@
<?php
session_start();
require_once __DIR__ . "/config/database.php";
if ($_SERVER["REQUEST_METHOD"] !== "POST"){
header("Location: index.php");
exit;
}
$email = trim($_POST["email"] ?? "");
$password = $_POST["password"] ?? "";
// Cerco l'utente
$stmt = $pdo->prepare("
SELECT
utente.idUtente,
utente.nome,
utente.cognome,
utente.email,
utente.passwordHash,
utente.attivo,
CASE
WHEN proprietario.idUtente IS NOT NULL
THEN 'proprietario'
WHEN personale.idUtente IS NOT NULL
THEN 'personale'
WHEN cliente.idUtente IS NOT NULL
THEN 'cliente'
ELSE NULL
END as ruolo
FROM utente
LEFT JOIN proprietario ON proprietario.idUtente = utente.idUtente
LEFT JOIN personale ON personale.idUtente = utente.idUtente
LEFT JOIN cliente ON cliente.idUtente = utente.idUtente
WHERE utente.email = :email
");
$stmt->execute([
"email" => $email
]);
$utente = $stmt->fetch(PDO::FETCH_ASSOC);
// Utente inesistente
if (!$utente) {
header("Location: index.php?errore=login");
exit;
}
// Account disabilitato
if (!$utente["attivo"]) {
header("Location: index.php?errore=login");
exit;
}
// Password sbagliata
if (!password_verify($password, $utente["passwordHash"])) {
header("Location: index.php?errore=login");
exit;
}
// Utente senza ruolo
if ($utente["ruolo"] === null) {
die ("Errore: utente senza ruolo");
}
// Login riuscito
session_regenerate_id(true);
// Mettiamo i dati nella sessione
$_SESSION["idUtente"] = $utente["idUtente"];
$_SESSION["nome"] = $utente["nome"];
$_SESSION["cognome"] = $utente["cognome"];
$_SESSION["email"] = $utente["email"];
$_SESSION["ruolo"] = $utente["ruolo"];
// Reindirizzamento alla dashboard specifica del ruolo.
$dashboard = [
"cliente" => "cliente/dashboard.php",
"personale" => "personale/dashboard.php",
"proprietario" => "proprietario/dashboard.php",
];
header("Location: " . $dashboard[$utente["ruolo"]]);
exit;
Executable
+17
View File
@@ -0,0 +1,17 @@
<?php
session_start();
// Svuota i dati della sessione
$_SESSION = [];
// Distrugge la sessione
session_destroy();
// Torna al login
header("Location: index.php");
exit;
+20
View File
@@ -0,0 +1,20 @@
<?php
require_once __DIR__ . "/../includes/auth.php";
requireRole("personale");
require_once __DIR__ . "/../config/database.php";
$idPersonale = (int) $_SESSION["idUtente"];
$conteggi = [];
/*
* QUERY 11 - Conteggio degli ordini attivi divisi per stato di avanzamento
* Input: nessuno (l'id $idPersonale è disponibile per il contesto UI)
* Output atteso: idStatoOrdine, nomeStato, posizione, numeroOrdini
* TODO SQL: implementare manualmente la Query 11.
*/
$pageTitle = "Dashboard personale"; $basePath = "..";
require __DIR__ . "/../includes/header.php";
?>
<h1 class="h3">Dashboard personale</h1><p>Panoramica degli ordini attivi.</p>
<?php if (!$conteggi): ?><div class="alert alert-info">I conteggi saranno mostrati dopo l'implementazione della Query 11.</div><?php endif; ?>
<div class="row g-3 mb-4"><?php foreach ($conteggi as $c): ?><div class="col-sm-6 col-lg"><div class="card text-center h-100 shadow-sm"><div class="card-body"><div class="display-6"><?= e($c["numeroOrdini"]) ?></div><div><?= e($c["nomeStato"]) ?></div></div></div></div><?php endforeach; ?></div>
<a class="btn btn-primary" href="ordini.php">Apri gli ordini correnti</a>
<?php require __DIR__ . "/../includes/footer.php"; ?>
+33
View File
@@ -0,0 +1,33 @@
<?php
require_once __DIR__ . "/../includes/auth.php";
requireRole("personale");
require_once __DIR__ . "/../config/database.php";
$idPersonale = (int) $_SESSION["idUtente"];
$idOrdine = filter_input(INPUT_GET, "idOrdine", FILTER_VALIDATE_INT) ?: filter_input(INPUT_POST, "idOrdine", FILTER_VALIDATE_INT);
$idStatoOrdine = filter_input(INPUT_POST, "idStatoOrdine", FILTER_VALIDATE_INT);
$ordine = null; $righe = []; $storico = []; $statoSuccessivo = null; $messaggio = null;
/* TODO SQL DI SUPPORTO - Caricare testata, righe con caratteristiche,
* ingredienti/procedura, indirizzo, stato corrente e storico dell'ordine.
* Input: $idOrdine. Output: attributi omonimi dello schema e nomi descrittivi. */
if (postMethod()) {
/*
* QUERY 14 - Aggiornamento progressivo dello stato di un ordine
* Input: $idOrdine, $idStatoOrdine, $idPersonale
* Output: nuovo nomeStato, posizione e timestamp registrato
* Vincolo UI/DB: solo il successore dello stato corrente; mai regressioni.
* TODO SQL: implementare manualmente la Query 14.
*/
$messaggio = "Query 14 predisposta: stato non ancora aggiornato.";
}
$pageTitle = "Dettaglio ordine"; $basePath = "..";
require __DIR__ . "/../includes/header.php";
?>
<div class="d-flex justify-content-between"><h1 class="h3">Ordine #<?= e($idOrdine ?: "—") ?></h1><a class="btn btn-outline-secondary" href="ordini.php">Indietro</a></div>
<?php if (!$idOrdine): ?><div class="alert alert-danger">Specificare un ID ordine valido.</div><?php endif; ?>
<?php if ($messaggio): ?><div class="alert alert-warning"><?= e($messaggio) ?></div><?php endif; ?>
<?php if (!$ordine): ?><div class="alert alert-info">Il dettaglio sarà disponibile dopo il TODO SQL di supporto.</div><?php endif; ?>
<div class="row g-4"><div class="col-lg-8">
<div class="card shadow-sm mb-3"><div class="card-body"><h2 class="h5">Preparazione</h2><table class="table"><thead><tr><th>Prodotto</th><th>Qtà</th><th>Caratteristiche</th><th>Procedura</th></tr></thead><tbody><?php foreach ($righe as $r): ?><tr><td><?= e($r["nomeProdotto"]) ?></td><td><?= e($r["quantita"]) ?></td><td><?= e($r["caratteristiche"] ?? "—") ?></td><td><?= e($r["proceduraPreparazione"] ?? "—") ?></td></tr><?php endforeach; ?></tbody></table></div></div>
<div class="card shadow-sm"><div class="card-body"><h2 class="h5">Storico stati</h2><ol class="mb-0"><?php foreach ($storico as $s): ?><li><?= e($s["timestamp"]) ?> — <?= e($s["nomeStato"]) ?> (<?= e(($s["nomePersonale"] ?? "") . " " . ($s["cognomePersonale"] ?? "")) ?>)</li><?php endforeach; ?></ol></div></div>
</div><div class="col-lg-4"><div class="card shadow-sm"><div class="card-body"><h2 class="h5">Avanzamento</h2><p>Corrente: <span class="badge bg-primary"><?= e($ordine["nomeStato"] ?? "—") ?></span></p><p class="small text-muted">Progressione: inserito → in preparazione → pronto → in consegna → consegnato.</p><form method="post"><input type="hidden" name="idOrdine" value="<?= e($idOrdine) ?>"><input type="hidden" name="idStatoOrdine" value="<?= e($statoSuccessivo["idStatoOrdine"] ?? "") ?>"><button class="btn btn-success w-100" <?= $statoSuccessivo ? "" : "disabled" ?>>Passa a: <?= e($statoSuccessivo["nomeStato"] ?? "nessuno") ?></button></form></div></div></div></div>
<?php require __DIR__ . "/../includes/footer.php"; ?>
+24
View File
@@ -0,0 +1,24 @@
<?php
require_once __DIR__ . "/../includes/auth.php";
requireRole("personale");
require_once __DIR__ . "/../config/database.php";
$idPersonale = (int) $_SESSION["idUtente"];
$soloInRitardo = ($_GET["filtro"] ?? "") === "ritardo";
$ordini = [];
/*
* QUERY 5 - Ordini non ancora messi in preparazione dopo più di un'ora
* Input: nessuno; $soloInRitardo controlla la vista richiesta dalla UI
* Output atteso: idOrdine, dataOraCreazione, orarioConsegna, totale,
* nomeCliente, cognomeCliente, via, numeroCivico, nomeComune,
* nomeStato, timestampUltimoStato, minutiAttesa
* TODO SQL: implementare manualmente la Query 5.
*/
/* Per la vista completa degli ordini correnti predisporre inoltre una query
* di supporto con gli stessi campi, senza il vincolo "oltre un'ora". */
$pageTitle = "Ordini correnti"; $basePath = "..";
require __DIR__ . "/../includes/header.php";
?>
<div class="d-flex justify-content-between align-items-center mb-3"><h1 class="h3">Ordini correnti</h1><div><a class="btn btn-outline-secondary" href="ordini.php">Tutti</a> <a class="btn btn-warning" href="?filtro=ritardo">In attesa da oltre un'ora (Q5)</a></div></div>
<?php if (!$ordini): ?><div class="alert alert-info">Nessun risultato: completare la Query 5 o il caricamento di supporto.</div><?php endif; ?>
<div class="table-responsive"><table class="table table-striped align-middle"><thead><tr><th>Ordine</th><th>Cliente</th><th>Creato</th><th>Stato</th><th>Attesa</th><th>Consegna</th><th></th></tr></thead><tbody><?php foreach ($ordini as $o): ?><tr><td>#<?= e($o["idOrdine"]) ?></td><td><?= e(($o["nomeCliente"] ?? "") . " " . ($o["cognomeCliente"] ?? "")) ?></td><td><?= e($o["dataOraCreazione"]) ?></td><td><span class="badge bg-secondary"><?= e($o["nomeStato"]) ?></span></td><td><?= e($o["minutiAttesa"] ?? "—") ?> min</td><td><?= e($o["orarioConsegna"]) ?></td><td><a class="btn btn-sm btn-primary" href="dettaglio_ordine.php?idOrdine=<?= e($o["idOrdine"]) ?>">Dettaglio</a></td></tr><?php endforeach; ?></tbody></table></div>
<?php require __DIR__ . "/../includes/footer.php"; ?>
+22
View File
@@ -0,0 +1,22 @@
<?php
require_once __DIR__."/../includes/auth.php";requireRole("proprietario");require_once __DIR__."/../config/database.php";
$idProdotto=filter_input(INPUT_GET,"idProdotto",FILTER_VALIDATE_INT)?:filter_input(INPUT_POST,"idProdotto",FILTER_VALIDATE_INT);$idCaratteristica=filter_input(INPUT_POST,"idCaratteristica",FILTER_VALIDATE_INT);$azione=$_POST["azione"]??null;$caratteristiche=[];$prodotti=[];$gruppi=[];$messaggio=null;
/* TODO SQL DI SUPPORTO - Caricare prodotti, caratteristiche e gruppi esclusione.
* Input: $idProdotto. Output: identificativi e campi omonimi dello schema. */
if(postMethod()&&$azione==="elimina"){
/*
* QUERY 2 - Eliminazione di una caratteristica associata a un prodotto
* Input: $idProdotto, $idCaratteristica
* Output: numero di righe eliminate/esito
* TODO SQL: implementare manualmente la Query 2.
*/$messaggio="Query 2 predisposta: eliminazione non ancora eseguita.";
}elseif(postMethod()){
/* TODO SQL DI SUPPORTO - Inserire/modificare caratteristica o gruppo esclusione.
* Input: campi POST corrispondenti allo schema. Output: esito. */$messaggio="Salvataggio predisposto: completare il TODO SQL.";}
$pageTitle="Caratteristiche";$basePath="..";require __DIR__."/../includes/header.php";
?>
<h1 class="h3">Caratteristiche dei prodotti</h1><?php if($messaggio):?><div class="alert alert-warning"><?=e($messaggio)?></div><?php endif;?>
<form method="get" class="card card-body mb-3"><div class="row align-items-end"><div class="col-md-6"><label class="form-label" for="filtroProdotto">Prodotto</label><select class="form-select" id="filtroProdotto" name="idProdotto"><option value="">Tutti</option><?php foreach($prodotti as $p):?><option value="<?=e($p["idProdotto"])?>" <?=$idProdotto==($p["idProdotto"]??null)?"selected":""?>><?=e($p["nome"])?></option><?php endforeach;?></select></div><div class="col-md-3 mt-2"><button class="btn btn-primary">Filtra</button></div></div></form>
<?php if(!$caratteristiche):?><div class="alert alert-info">Completare il TODO SQL per caricare le caratteristiche.</div><?php endif;?><div class="table-responsive"><table class="table table-striped"><thead><tr><th>Prodotto</th><th>Nome</th><th>Differenza</th><th>Default</th><th>Gruppo</th><th></th></tr></thead><tbody><?php foreach($caratteristiche as $c):?><tr><td><?=e($c["nomeProdotto"])?></td><td><?=e($c["nome"])?></td><td>€ <?=e($c["differenzaPrezzo"])?></td><td><?=!empty($c["predefinita"])?"Sì":"No"?></td><td><?=e($c["nomeGruppo"]??"—")?></td><td><form method="post"><input type="hidden" name="azione" value="elimina"><input type="hidden" name="idProdotto" value="<?=e($c["idProdotto"])?>"><input type="hidden" name="idCaratteristica" value="<?=e($c["idCaratteristica"])?>"><button class="btn btn-sm btn-danger">Elimina (Q2)</button></form></td></tr><?php endforeach;?></tbody></table></div>
<form method="post" class="card card-body shadow-sm"><h2 class="h5">Nuova caratteristica</h2><input type="hidden" name="azione" value="salva"><div class="row g-3"><div class="col-md-4"><label class="form-label">ID caratteristica</label><input class="form-control" type="number" min="1" name="idCaratteristica" required></div><div class="col-md-4"><label class="form-label">ID prodotto</label><input class="form-control" type="number" min="1" name="idProdotto" required></div><div class="col-md-4"><label class="form-label">Nome</label><input class="form-control" name="nome" required></div><div class="col-md-8"><label class="form-label">Descrizione</label><textarea class="form-control" name="descrizione" required></textarea></div><div class="col-md-4"><label class="form-label">Differenza prezzo</label><input class="form-control" type="number" min="0" step=".01" name="differenzaPrezzo" required></div><div class="col-md-4"><label class="form-label">ID gruppo (opzionale)</label><input class="form-control" type="number" min="1" name="idGruppoEsclusione"></div><div class="col-md-4 form-check mt-5"><input class="form-check-input" type="checkbox" name="predefinita" value="1" id="predefinita"><label class="form-check-label" for="predefinita">Predefinita</label></div><div class="col-md-4 form-check mt-5"><input class="form-check-input" type="checkbox" name="disponibile" value="1" id="disponibile"><label class="form-check-label" for="disponibile">Disponibile</label></div></div><button class="btn btn-primary mt-3">Salva</button></form>
<?php require __DIR__."/../includes/footer.php";?>
+16
View File
@@ -0,0 +1,16 @@
<?php
require_once __DIR__ . "/../includes/auth.php";
requireRole("proprietario");
$pageTitle = "Dashboard proprietario"; $basePath = "..";
require __DIR__ . "/../includes/header.php";
?>
<h1 class="h3">Dashboard proprietario</h1><p>Gestione dell'attività e monitoraggio.</p>
<div class="row g-3"><?php foreach ([
["Ordini", "Monitora ordini passati, attivi ed evasi", "ordini.php"],
["Prodotti", "Anagrafica, ingredienti e preparazione", "prodotti.php"],
["Caratteristiche", "Personalizzazioni e gruppi di esclusione", "caratteristiche.php"],
["Menu", "Disponibilità dei prodotti", "menu.php"],
["Personale", "Registra membri del personale", "personale.php"],
["Statistiche", "Report delle operazioni aggregate", "statistiche.php"],
] as [$t,$d,$u]): ?><div class="col-md-6 col-lg-4"><div class="card h-100 shadow-sm"><div class="card-body"><h2 class="h5"><?= e($t) ?></h2><p><?= e($d) ?></p><a class="btn btn-primary" href="<?= e($u) ?>">Apri</a></div></div></div><?php endforeach; ?></div>
<?php require __DIR__ . "/../includes/footer.php"; ?>
+10
View File
@@ -0,0 +1,10 @@
<?php
require_once __DIR__."/../includes/auth.php";requireRole("proprietario");require_once __DIR__."/../config/database.php";
$prodotti=[];$messaggio=null;$idProdotto=filter_input(INPUT_POST,"idProdotto",FILTER_VALIDATE_INT);$disponibile=isset($_POST["disponibile"])?1:0;
/* TODO SQL DI SUPPORTO - Elencare prodotti con disponibilità. Output: idProdotto, nome, prezzoBase, disponibile. */
if(postMethod()){/* TODO SQL DI SUPPORTO - Aggiornare prodotto.disponibile. Input: $idProdotto, $disponibile. Output: esito. */$messaggio="Disponibilità predisposta: completare il TODO SQL.";}
$pageTitle="Gestione menu";$basePath="..";require __DIR__."/../includes/header.php";
?>
<h1 class="h3">Composizione menu</h1><p>La disponibilità determina quali prodotti vengono proposti al cliente.</p><?php if($messaggio):?><div class="alert alert-warning"><?=e($messaggio)?></div><?php endif;?><?php if(!$prodotti):?><div class="alert alert-info">Completare il TODO SQL per caricare il menu.</div><?php endif;?>
<?php foreach($prodotti as $p):?><form method="post" class="card card-body mb-2 d-flex flex-row justify-content-between align-items-center"><input type="hidden" name="idProdotto" value="<?=e($p["idProdotto"])?>"><div><strong><?=e($p["nome"])?></strong><br>€ <?=e($p["prezzoBase"])?></div><div class="form-check form-switch"><input class="form-check-input" type="checkbox" name="disponibile" id="p<?=e($p["idProdotto"])?>" <?=!empty($p["disponibile"])?"checked":""?>><label class="form-check-label" for="p<?=e($p["idProdotto"])?>">Disponibile</label></div><button class="btn btn-sm btn-primary">Aggiorna</button></form><?php endforeach;?>
<?php require __DIR__."/../includes/footer.php";?>
+20
View File
@@ -0,0 +1,20 @@
<?php
require_once __DIR__."/../includes/auth.php";requireRole("proprietario");require_once __DIR__."/../config/database.php";
$idOrdine=filter_input(INPUT_GET,"idOrdine",FILTER_VALIDATE_INT);$stato=trim($_GET["stato"]??"");$ordini=[];$personaleOrdine=[];
/* TODO SQL DI SUPPORTO - Monitorare ordini passati, attivi ed evasi.
* Input: $stato. Output: idOrdine, cliente, dataOraCreazione, statoConferma,
* nomeStato, orarioConsegna, totale, indirizzo. */
if($idOrdine){
/*
* QUERY 13 - Membri del personale che hanno lavorato a un ordine
* Input: $idOrdine
* Output atteso: idUtente, nome, cognome, email, numeroCambiStato,
* primoIntervento, ultimoIntervento
* TODO SQL: implementare manualmente la Query 13.
*/}
$pageTitle="Monitoraggio ordini";$basePath="..";require __DIR__."/../includes/header.php";
?>
<h1 class="h3">Monitoraggio ordini</h1><form method="get" class="card card-body mb-3"><div class="row g-3 align-items-end"><div class="col-md-4"><label class="form-label">Stato</label><select class="form-select" name="stato"><option value="">Tutti</option><?php foreach(["inserito","in preparazione","pronto","in consegna","consegnato"] as $s):?><option <?=$stato===$s?"selected":""?>><?=e($s)?></option><?php endforeach;?></select></div><div class="col-md-4"><label class="form-label">ID ordine per personale (Q13)</label><input class="form-control" type="number" min="1" name="idOrdine" value="<?=e($idOrdine)?>"></div><div class="col-md-2"><button class="btn btn-primary">Applica</button></div></div></form>
<?php if(!$ordini):?><div class="alert alert-info">Completare il TODO SQL per visualizzare gli ordini.</div><?php endif;?><div class="table-responsive"><table class="table table-striped"><thead><tr><th>ID</th><th>Cliente</th><th>Creazione</th><th>Conferma</th><th>Stato</th><th>Consegna</th><th>Totale</th></tr></thead><tbody><?php foreach($ordini as $o):?><tr><td><?=e($o["idOrdine"])?></td><td><?=e($o["cliente"])?></td><td><?=e($o["dataOraCreazione"])?></td><td><?=e($o["statoConferma"])?></td><td><?=e($o["nomeStato"]??"—")?></td><td><?=e($o["orarioConsegna"])?></td><td>€ <?=e($o["totale"])?></td></tr><?php endforeach;?></tbody></table></div>
<?php if($idOrdine):?><div class="card card-body mt-4"><h2 class="h5">Personale dell'ordine #<?=e($idOrdine)?> (Q13)</h2><?php if(!$personaleOrdine):?><p class="text-muted">Risultati disponibili dopo la Query 13.</p><?php endif;?><table class="table"><thead><tr><th>Nome</th><th>Email</th><th>Cambi stato</th><th>Primo</th><th>Ultimo</th></tr></thead><tbody><?php foreach($personaleOrdine as $p):?><tr><td><?=e($p["nome"]." ".$p["cognome"])?></td><td><?=e($p["email"])?></td><td><?=e($p["numeroCambiStato"])?></td><td><?=e($p["primoIntervento"])?></td><td><?=e($p["ultimoIntervento"])?></td></tr><?php endforeach;?></tbody></table></div><?php endif;?>
<?php require __DIR__."/../includes/footer.php";?>
+14
View File
@@ -0,0 +1,14 @@
<?php
require_once __DIR__."/../includes/auth.php";requireRole("proprietario");require_once __DIR__."/../config/database.php";
$personale=[];$messaggio=null;
/* TODO SQL DI SUPPORTO - Elencare membri del personale.
* Output: idUtente, nome, cognome, email, attivo, dataRegistrazione. */
if(postMethod()){
$nome=trim($_POST["nome"]??"");$cognome=trim($_POST["cognome"]??"");$email=trim($_POST["email"]??"");$password=$_POST["password"]??"";$passwordHash=$password!==""?password_hash($password,PASSWORD_DEFAULT):null;
/* TODO SQL DI SUPPORTO - Registrare utente e specializzazione personale in transazione.
* Input: $nome, $cognome, $email, $passwordHash. Output: idUtente creato.
* dataRegistrazione deve essere valorizzata secondo lo schema. */$messaggio="Registrazione predisposta: completare il TODO SQL.";}
$pageTitle="Gestione personale";$basePath="..";require __DIR__."/../includes/header.php";
?>
<h1 class="h3">Personale</h1><?php if($messaggio):?><div class="alert alert-warning"><?=e($messaggio)?></div><?php endif;?><div class="row g-4"><div class="col-lg-7"><table class="table table-striped"><thead><tr><th>Nome</th><th>Email</th><th>Registrazione</th><th>Attivo</th></tr></thead><tbody><?php foreach($personale as $p):?><tr><td><?=e($p["nome"]." ".$p["cognome"])?></td><td><?=e($p["email"])?></td><td><?=e($p["dataRegistrazione"])?></td><td><?=!empty($p["attivo"])?"Sì":"No"?></td></tr><?php endforeach;?></tbody></table><?php if(!$personale):?><div class="alert alert-info">Completare il TODO SQL per visualizzare il personale.</div><?php endif;?></div><div class="col-lg-5"><form method="post" class="card card-body shadow-sm"><h2 class="h5">Registra membro</h2><label class="form-label">Nome</label><input class="form-control mb-3" name="nome" required><label class="form-label">Cognome</label><input class="form-control mb-3" name="cognome" required><label class="form-label">Email</label><input class="form-control mb-3" type="email" name="email" required><label class="form-label">Password iniziale</label><input class="form-control mb-3" type="password" name="password" required><button class="btn btn-primary">Registra</button></form></div></div>
<?php require __DIR__."/../includes/footer.php";?>
+15
View File
@@ -0,0 +1,15 @@
<?php
require_once __DIR__ . "/../includes/auth.php"; requireRole("proprietario");
require_once __DIR__ . "/../config/database.php";
$azione = $_POST["azione"] ?? null; $prodotti = []; $messaggio = null;
/* TODO SQL DI SUPPORTO - Elencare i prodotti.
* Output: idProdotto, nome, descrizione, prezzoBase, tempoPreparazione, disponibile. */
if (postMethod()) { /* TODO SQL DI SUPPORTO - Inserire/modificare un prodotto.
* Input POST: idProdotto, nome, descrizione, prezzoBase, tempoPreparazione,
* proceduraPreparazione, disponibile. Output: esito. */ $messaggio = "Salvataggio predisposto: completare il TODO SQL."; }
$pageTitle="Gestione prodotti"; $basePath=".."; require __DIR__."/../includes/header.php";
?>
<h1 class="h3">Gestione prodotti</h1><?php if($messaggio):?><div class="alert alert-warning"><?=e($messaggio)?></div><?php endif;?>
<div class="row g-4"><div class="col-lg-7"><div class="table-responsive"><table class="table table-striped"><thead><tr><th>ID</th><th>Nome</th><th>Prezzo</th><th>Tempo</th><th>Disponibile</th><th></th></tr></thead><tbody><?php foreach($prodotti as $p):?><tr><td><?=e($p["idProdotto"])?></td><td><?=e($p["nome"])?></td><td>€ <?=e($p["prezzoBase"])?></td><td><?=e($p["tempoPreparazione"])?> min</td><td><?=!empty($p["disponibile"])?"Sì":"No"?></td><td><a class="btn btn-sm btn-outline-primary" href="prodotto.php?idProdotto=<?=e($p["idProdotto"])?>">Dettaglio</a></td></tr><?php endforeach;?></tbody></table></div><?php if(!$prodotti):?><div class="alert alert-info">Completare il TODO SQL per caricare i prodotti.</div><?php endif;?></div>
<div class="col-lg-5"><form method="post" class="card card-body shadow-sm"><h2 class="h5">Nuovo prodotto</h2><input type="hidden" name="azione" value="inserisci"><label class="form-label" for="idProdotto">ID prodotto</label><input class="form-control mb-3" type="number" min="1" id="idProdotto" name="idProdotto" required><label class="form-label" for="nome">Nome</label><input class="form-control mb-3" id="nome" name="nome" required><label class="form-label" for="descrizione">Descrizione</label><textarea class="form-control mb-3" id="descrizione" name="descrizione" required></textarea><div class="row"><div class="col"><label class="form-label" for="prezzoBase">Prezzo base</label><input class="form-control mb-3" type="number" min="0" step="0.01" id="prezzoBase" name="prezzoBase" required></div><div class="col"><label class="form-label" for="tempoPreparazione">Minuti</label><input class="form-control mb-3" type="number" min="0" id="tempoPreparazione" name="tempoPreparazione" required></div></div><label class="form-label" for="proceduraPreparazione">Procedura</label><textarea class="form-control mb-3" id="proceduraPreparazione" name="proceduraPreparazione" required></textarea><div class="form-check mb-3"><input class="form-check-input" type="checkbox" id="disponibile" name="disponibile" value="1"><label class="form-check-label" for="disponibile">Disponibile</label></div><button class="btn btn-primary">Salva</button></form></div></div>
<?php require __DIR__."/../includes/footer.php";?>
+12
View File
@@ -0,0 +1,12 @@
<?php
require_once __DIR__."/../includes/auth.php"; requireRole("proprietario"); require_once __DIR__."/../config/database.php";
$idProdotto=filter_input(INPUT_GET,"idProdotto",FILTER_VALIDATE_INT)?:filter_input(INPUT_POST,"idProdotto",FILTER_VALIDATE_INT); $prodotto=null; $ingredienti=[]; $messaggio=null;
/* TODO SQL DI SUPPORTO - Caricare prodotto e ingredienti con quantità.
* Input: $idProdotto. Output: campi prodotto; idIngrediente, nomeIngrediente, unitaMisura, quantita. */
if(postMethod()){ /* TODO SQL DI SUPPORTO - Modificare prodotto e associazioni ingrediente.
* Input: $idProdotto e campi POST aderenti allo schema. Output: esito. */ $messaggio="Modifica predisposta: completare il TODO SQL."; }
$pageTitle="Dettaglio prodotto";$basePath="..";require __DIR__."/../includes/header.php";
?>
<h1 class="h3">Dettaglio prodotto #<?=e($idProdotto?:"—")?></h1><?php if($messaggio):?><div class="alert alert-warning"><?=e($messaggio)?></div><?php endif;?><?php if(!$prodotto):?><div class="alert alert-info">Dati disponibili dopo il TODO SQL.</div><?php endif;?>
<div class="row g-4"><div class="col-lg-7"><form method="post" class="card card-body shadow-sm"><input type="hidden" name="idProdotto" value="<?=e($idProdotto)?>"><label class="form-label">Nome</label><input class="form-control mb-3" name="nome" value="<?=e($prodotto["nome"]??"")?>" required><label class="form-label">Descrizione</label><textarea class="form-control mb-3" name="descrizione" required><?=e($prodotto["descrizione"]??"")?></textarea><label class="form-label">Procedura preparazione</label><textarea class="form-control mb-3" name="proceduraPreparazione" required><?=e($prodotto["proceduraPreparazione"]??"")?></textarea><div class="row"><div class="col"><label class="form-label">Prezzo</label><input class="form-control mb-3" type="number" min="0" step=".01" name="prezzoBase" value="<?=e($prodotto["prezzoBase"]??"")?>" required></div><div class="col"><label class="form-label">Tempo</label><input class="form-control mb-3" type="number" min="0" name="tempoPreparazione" value="<?=e($prodotto["tempoPreparazione"]??"")?>" required></div></div><button class="btn btn-primary">Salva modifiche</button></form></div><div class="col-lg-5"><div class="card card-body shadow-sm"><h2 class="h5">Ingredienti</h2><table class="table"><thead><tr><th>Ingrediente</th><th>Quantità</th></tr></thead><tbody><?php foreach($ingredienti as $i):?><tr><td><?=e($i["nomeIngrediente"])?></td><td><?=e($i["quantita"]." ".$i["unitaMisura"])?></td></tr><?php endforeach;?></tbody></table><p class="small text-muted">La gestione delle associazioni è predisposta nel TODO SQL di supporto.</p></div></div></div>
<?php require __DIR__."/../includes/footer.php";?>
+42
View File
@@ -0,0 +1,42 @@
<?php
require_once __DIR__."/../includes/auth.php";requireRole("proprietario");require_once __DIR__."/../config/database.php";
$report=$_GET["report"]??null;$anno=filter_input(INPUT_GET,"anno",FILTER_VALIDATE_INT);$data=$_GET["data"]??null;
$tempiMedi=[];$classifica=[];$incasso=null;$consumi=[];$ordiniSmaltiti=null;
if($report==="q6"){
/* QUERY 6 - Tempo medio tra "in consegna" e "consegnato" per addetto.
* Input: nessuno. Output: idUtente, nome, cognome, numeroConsegne, tempoMedioMinuti.
* TODO SQL: implementare manualmente la Query 6. */
}
if($report==="q7"){
/* QUERY 7 - Classifica di gradimento dei prodotti.
* Input: nessuno. Output: idProdotto, nome, numeroOrdini, quantitaTotale, posizione.
* TODO SQL: implementare manualmente la Query 7. */
}
if($report==="q8"&&$data){
/* QUERY 8 - Calcolo dell'incasso giornaliero.
* Input: $data. Output atteso: incasso, numeroOrdini.
* TODO SQL: implementare manualmente la Query 8. */
}
if($report==="q9"&&$anno){
/* QUERY 9 - Prospetto del consumo di ingredienti in un anno.
* Input: $anno. Output: idIngrediente, nome, unitaMisura, quantitaConsumata.
* TODO SQL: implementare manualmente la Query 9. */
}
if($report==="q12"&&$data){
/* QUERY 12 - Conteggio degli ordini consegnati in uno specifico giorno.
* Input: $data. Output atteso: numeroOrdiniConsegnati.
* TODO SQL: implementare manualmente la Query 12. */
}
$pageTitle="Statistiche";$basePath="..";require __DIR__."/../includes/header.php";
?>
<h1 class="h3">Statistiche</h1><p class="text-muted">Ogni sezione corrisponde a un'operazione aggregata della specifica.</p>
<div class="row g-4">
<div class="col-lg-6"><section class="card h-100 shadow-sm"><div class="card-body"><h2 class="h5">Q6 — Tempo medio di consegna</h2><form method="get" class="mb-3"><input type="hidden" name="report" value="q6"><button class="btn btn-primary">Calcola per addetto</button></form><?php if($report==="q6"&&!$tempiMedi):?><div class="alert alert-info">Implementare la Query 6.</div><?php endif;?><table class="table"><thead><tr><th>Addetto</th><th>Consegne</th><th>Media (min)</th></tr></thead><tbody><?php foreach($tempiMedi as $r):?><tr><td><?=e($r["nome"]." ".$r["cognome"])?></td><td><?=e($r["numeroConsegne"])?></td><td><?=e($r["tempoMedioMinuti"])?></td></tr><?php endforeach;?></tbody></table></div></section></div>
<div class="col-lg-6"><section class="card h-100 shadow-sm"><div class="card-body"><h2 class="h5">Q7 — Classifica prodotti</h2><form method="get" class="mb-3"><input type="hidden" name="report" value="q7"><button class="btn btn-primary">Genera classifica</button></form><?php if($report==="q7"&&!$classifica):?><div class="alert alert-info">Implementare la Query 7.</div><?php endif;?><table class="table"><thead><tr><th>#</th><th>Prodotto</th><th>Ordini</th><th>Quantità</th></tr></thead><tbody><?php foreach($classifica as $n=>$r):?><tr><td><?=e($r["posizione"]??$n+1)?></td><td><?=e($r["nome"])?></td><td><?=e($r["numeroOrdini"])?></td><td><?=e($r["quantitaTotale"])?></td></tr><?php endforeach;?></tbody></table></div></section></div>
<div class="col-lg-6"><section class="card h-100 shadow-sm"><div class="card-body"><h2 class="h5">Q8 — Incasso giornaliero</h2><form method="get"><input type="hidden" name="report" value="q8"><label class="form-label" for="dataQ8">Giorno</label><input class="form-control mb-3" type="date" id="dataQ8" name="data" value="<?=e($report==="q8"?$data:"")?>" required><button class="btn btn-primary">Calcola</button></form><?php if($report==="q8"):?><hr><p class="display-6">€ <?=e($incasso["incasso"]??"—")?></p><p>Ordini conteggiati: <?=e($incasso["numeroOrdini"]??"—")?></p><div class="alert alert-info">Implementare la Query 8.</div><?php endif;?></div></section></div>
<div class="col-lg-6"><section class="card h-100 shadow-sm"><div class="card-body"><h2 class="h5">Q9 — Consumo ingredienti</h2><form method="get"><input type="hidden" name="report" value="q9"><label class="form-label" for="anno">Anno</label><input class="form-control mb-3" type="number" min="2000" max="2100" id="anno" name="anno" value="<?=e($anno?:date("Y"))?>" required><button class="btn btn-primary">Genera prospetto</button></form><?php if($report==="q9"&&!$consumi):?><div class="alert alert-info mt-3">Implementare la Query 9.</div><?php endif;?><table class="table mt-3"><thead><tr><th>Ingrediente</th><th>Consumo</th></tr></thead><tbody><?php foreach($consumi as $r):?><tr><td><?=e($r["nome"])?></td><td><?=e($r["quantitaConsumata"]." ".$r["unitaMisura"])?></td></tr><?php endforeach;?></tbody></table></div></section></div>
<div class="col-lg-6"><section class="card h-100 shadow-sm"><div class="card-body"><h2 class="h5">Q12 — Ordini consegnati nel giorno</h2><form method="get"><input type="hidden" name="report" value="q12"><label class="form-label" for="dataQ12">Giorno</label><input class="form-control mb-3" type="date" id="dataQ12" name="data" value="<?=e($report==="q12"?$data:"")?>" required><button class="btn btn-primary">Conta</button></form><?php if($report==="q12"):?><hr><p class="display-6"><?=e($ordiniSmaltiti["numeroOrdiniConsegnati"]??"—")?></p><div class="alert alert-info">Implementare la Query 12.</div><?php endif;?></div></section></div>
<div class="col-lg-6"><section class="card h-100 shadow-sm"><div class="card-body"><h2 class="h5">Ordini attivi</h2><p>Il conteggio diviso per stato corrisponde alla <strong>Query 11</strong> ed è predisposto nella dashboard del personale.</p><a class="btn btn-outline-primary" href="ordini.php">Monitora gli ordini</a><p class="small text-muted mt-3 mb-0">La pagina proprietario consente il monitoraggio, mentre il conteggio operativo Q11 resta protetto per il ruolo personale.</p></div></section></div>
</div>
<?php require __DIR__."/../includes/footer.php";?>
+112
View File
@@ -0,0 +1,112 @@
<!--
QUI VIENE IMPLEMENTATA LA REGISTRAZIONE:
UTENTE + CLIENTE
-->
<?php
require_once __DIR__ . "/config/database.php";
if ($_SERVER["REQUEST_METHOD"] !== "POST"){
header("Location: registrazione.php");
exit;
}
$nome = trim($_POST["nome"] ?? "");
$cognome = trim($_POST["cognome"] ?? "");
$email = trim($_POST["email"] ?? "");
$telefono = trim($_POST["telefono"] ?? "");
$password = trim($_POST["password"] ?? "");
$confermaPassword = trim($_POST["confermaPassword"] ?? "");
$via = trim($_POST["via"] ?? "");
$numeroCivico = trim($_POST["numeroCivico"] ?? "");
$idComune = filter_input(INPUT_POST, "idComune", FILTER_VALIDATE_INT);
// Controllo che i dati in input non siano vuoti
if (
$nome === "" ||
$cognome === "" ||
$email === "" ||
$telefono === "" ||
$password === "" ||
$via === "" ||
$numeroCivico === "" ||
!$idComune
) {
die("Compila tutti i campi.");
}
// Controllo che le due password siano identiche
if ($password !== $confermaPassword) {
die("Le passoword non corrispondono.");
}
// Hash delle password
$passwordHash = password_hash($password, PASSWORD_DEFAULT);
try {
$pdo->beginTransaction();
// Creazione dell'utente
$stmt = $pdo->prepare("
INSERT INTO utente (nome, cognome, email, passwordHash, attivo)
VALUES (:nome, :cognome, :email, :passwordHash, 1)
");
$stmt->execute([
"nome" => $nome,
"cognome" => $cognome,
"email" => $email,
"passwordHash" => $passwordHash
]);
/*
In seguito all'aggiunta dell'utente
recuperiamo l'ultimo elemento aggiunto
in modo da linkarlo alla tabella della
clientela
*/
$idUtente = $pdo->lastInsertId();
// Creazione del cliente
$stmt = $pdo->prepare("
INSERT INTO cliente (idUtente, telefono)
VALUES (:idUtente, :telefono)
");
$stmt->execute([
"idUtente" => $idUtente,
"telefono" => $telefono
]);
$stmt = $pdo->prepare("
INSERT INTO indirizzo (via, numeroCivico, predefinito, idComune, idCliente)
VALUES (:via, :numeroCivico, 1, :idComune, :idUtente)
");
$stmt->execute([
"via" => $via,
"numeroCivico" => $numeroCivico,
"idComune" => $idComune,
"idUtente" => $idUtente
]);
$pdo->commit();
header("Location: index.php?registrazione=ok");
exit;
} catch (PDOException $e) {
if ($pdo->inTransaction()) {
$pdo->rollBack();
}
die(
"Errore durante la registrazione: "
. $e->getMessage()
);
}
+241
View File
@@ -0,0 +1,241 @@
<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, initial-scale=1.0">
<title>Delivery - Registrazione</title>
<link rel="stylesheet" href="css/bootstrap.min.css">
</head>
<body class="bg-light">
<div class="container mt-5">
<div class="row justify-content-center">
<div class="col-md-6">
<h2 class="mb-4">
Registrazione
</h2>
<div class="card p-4 shadow-sm">
<form
action="register_action.php"
method="post"
>
<div class="mb-3">
<label
class="form-label"
for="nome"
>
Nome
</label>
<input
class="form-control"
type="text"
id="nome"
name="nome"
required
>
</div>
<div class="mb-3">
<label
class="form-label"
for="cognome"
>
Cognome
</label>
<input
class="form-control"
type="text"
id="cognome"
name="cognome"
required
>
</div>
<h5 class="mt-4">Indirizzo di consegna</h5>
<p class="text-muted small">La specifica richiede almeno un indirizzo per ogni cliente.</p>
<div class="row">
<div class="col-md-8 mb-3">
<label class="form-label" for="via">Via</label>
<input class="form-control" type="text" id="via" name="via" required>
</div>
<div class="col-md-4 mb-3">
<label class="form-label" for="numeroCivico">Numero civico</label>
<input class="form-control" type="text" id="numeroCivico" name="numeroCivico" required>
</div>
</div>
<div class="mb-3">
<label class="form-label" for="idComune">Comune</label>
<select class="form-select" id="idComune" name="idComune" required>
<option value="">
Seleziona un comune
</option>
<?php
require_once __DIR__ . "/config/database.php";
$stmt = $pdo->prepare("
SELECT
comune.idComune,
comune.nome AS nomeComune,
provincia.nome AS nomeProvincia,
provincia.sigla
FROM comune JOIN provincia ON comune.idProvincia = provincia.idProvincia
");
$stmt->execute();
$comuni = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>
<?php foreach ($comuni as $comune):?>
<option value="<?= $comune["idComune"] ?>">
<?=
htmlspecialchars($comune["nomeComune"] . " - " . $comune["nomeProvincia"] . " - " . $comune["sigla"])
?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="mb-3">
<label
class="form-label"
for="email"
>
Email
</label>
<input
class="form-control"
type="email"
id="email"
name="email"
required
>
</div>
<div class="mb-3">
<label
class="form-label"
for="telefono"
>
Telefono
</label>
<input
class="form-control"
type="tel"
id="telefono"
name="telefono"
required
>
</div>
<div class="mb-3">
<label
class="form-label"
for="password"
>
Password
</label>
<input
class="form-control"
type="password"
id="password"
name="password"
required
>
</div>
<div class="mb-3">
<label
class="form-label"
for="confermaPassword"
>
Conferma password
</label>
<input
class="form-control"
type="password"
id="confermaPassword"
name="confermaPassword"
required
>
</div>
<button
class="btn btn-primary w-100"
type="submit"
>
Registrati
</button>
</form>
<div class="text-center mt-3">
<a href="index.php">
Torna al login
</a>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
File diff suppressed because one or more lines are too long
+6
View File
@@ -0,0 +1,6 @@
-- 00_database.sql
DROP DATABASE IF EXISTS delivery; -- Canellazione del DATABASE se esiste
CREATE DATABASE delivery; -- Creazione del DATABASE
USE delivery; -- Selezione del DATABASE
+194
View File
@@ -0,0 +1,194 @@
-- 01_schema.sql
-- CREAZIONE RELAZIONE UTENTE
CREATE TABLE utente (
idUtente INT AUTO_INCREMENT PRIMARY KEY NOT NULL,
nome VARCHAR(30) NOT NULL,
cognome VARCHAR(30) NOT NULL,
email VARCHAR(255) NOT NULL UNIQUE,
passwordHash VARCHAR(255) NOT NULL,
attivo TINYINT(1) NOT NULL
);
-- CREAZIONE RELAZIONE PROPRIETARIO
CREATE TABLE proprietario (
idUtente INT PRIMARY KEY NOT NULL,
FOREIGN KEY (idUtente) REFERENCES utente (idUtente)
);
-- CREAZIONE RELAZIONE PERSONALE
CREATE TABLE personale (
idUtente INT PRIMARY KEY NOT NULL,
dataRegistrazione TIMESTAMP NOT NULL,
FOREIGN KEY (idUtente) REFERENCES utente (idUtente)
);
-- CREAZIONE RELAZIONE CLIENTE
CREATE TABLE cliente (
idUtente INT PRIMARY KEY NOT NULL,
telefono VARCHAR(20) NOT NULL,
FOREIGN KEY (idUtente) REFERENCES utente (idUtente)
);
-- CREAZIONE RELAZIONE PROVINCIA
CREATE TABLE provincia (
idProvincia INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
nome VARCHAR(45) NOT NULL,
sigla VARCHAR(45) NOT NULL
);
-- CREAZIONE RELAZIONE COMUNE
CREATE TABLE comune (
idComune INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
nome VARCHAR(45) NOT NULL,
idProvincia INT NOT NULL,
FOREIGN KEY (idProvincia) REFERENCES provincia(idProvincia)
);
-- CREAZIONE RELAZIONE INDIRIZZO
CREATE TABLE indirizzo (
idIndirizzo INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
via VARCHAR(45) NOT NULL,
numeroCivico VARCHAR (10) NOT NULL,
predefinito TINYINT(1) NOT NULL DEFAULT 0,
idComune INT NOT NULL,
idCliente INT NOT NULL,
FOREIGN KEY (idComune) REFERENCES comune (idComune),
FOREIGN KEY (idCliente) REFERENCES cliente (idUtente)
);
-- CREAZIONE RELAZIONE ORDINE
CREATE TABLE ordine (
idOrdine INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
dataOraCreazione TIMESTAMP NOT NULL,
dataOraConferma TIMESTAMP,
dataOraAnnullamento TIMESTAMP,
statoConferma ENUM('bozza','confermato','annullato') NOT NULL,
orarioConsegna TIMESTAMP,
totale DECIMAL(10,2) NOT NULL,
tempoStimatoConsegna INT,
idCliente INT NOT NULL,
idIndirizzo INT NOT NULL,
FOREIGN KEY (idCliente) REFERENCES cliente (idUtente),
FOREIGN KEY (idIndirizzo) REFERENCES indirizzo (idIndirizzo),
CHECK (dataOraCreazione <= dataOraConferma),
CHECK (dataOraConferma <= orarioConsegna),
CHECK (totale >= 0),
CHECK (tempoStimatoConsegna >= 0),
CHECK (statoConferma <> 'confermato' OR dataOraConferma IS NOT NULL) -- se è confermato → dataOraConferma non può essere NULL
);
-- CREAZIONE RELAZIONE STATO ORDINE
CREATE TABLE statoOrdine (
idStatoOrdine INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
nomeStato VARCHAR(30) NOT NULL,
posizione TINYINT NOT NULL
);
-- CREAZIONE RELAZIONE STORICO STATO
CREATE TABLE storicoStato (
idStoricoStato INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
timestamp TIMESTAMP NOT NULL,
idOrdine INT NOT NULL,
idStatoOrdine INT NOT NULL,
idPersonale INT,
FOREIGN KEY (idOrdine) REFERENCES ordine (idOrdine),
FOREIGN KEY (idStatoOrdine) REFERENCES statoOrdine (idStatoOrdine),
FOREIGN KEY (idPersonale) REFERENCES personale (idUtente)
);
-- CREAZIONE RELAZIONE INGREDIENTE
CREATE TABLE ingrediente (
idIngrediente INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
nome VARCHAR(100) NOT NULL,
unitaMisura VARCHAR(20) NOT NULL
);
-- CREAZIONE RELAZIONE PRODOTTO
CREATE TABLE prodotto (
idProdotto INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
nome VARCHAR(100) NOT NULL,
descrizione TEXT NOT NULL,
prezzoBase DECIMAL(10,2) NOT NULL,
tempoPreparazione INT NOT NULL,
proceduraPreparazione TEXT NOT NULL,
disponibile TINYINT(1) NOT NULL DEFAULT 0,
CHECK (prezzoBase >= 0),
CHECK (tempoPreparazione >= 0)
);
-- CREAZIONE RELAZIONE PRODOTTOUSAINGREDIENTE
CREATE TABLE prodottoUsaIngrediente (
quantita DECIMAL(10,3) NOT NULL,
idProdotto INT NOT NULL,
idIngrediente INT NOT NULL,
PRIMARY KEY (idProdotto, idIngrediente),
FOREIGN KEY (idProdotto) REFERENCES prodotto (idProdotto),
FOREIGN KEY (idIngrediente) REFERENCES ingrediente (idIngrediente),
CHECK (quantita > 0)
);
-- CREAZIONE RELAZIONE GRUPPO ECLUSIONE
CREATE TABLE gruppoEsclusione (
idGruppoEsclusione INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
nome VARCHAR(45) NOT NULL,
idProdotto INT NOT NULL,
FOREIGN KEY (idProdotto) REFERENCES prodotto (idProdotto)
);
-- CREAZIONE RELAZIONE CARATTERISTICA
CREATE TABLE caratteristica (
idCaratteristica INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
nome VARCHAR(100) NOT NULL,
descrizione TEXT NOT NULL,
differenzaPrezzo DECIMAL(10,2) NOT NULL,
predefinita TINYINT(1) DEFAULT 0 NOT NULL,
disponibile TINYINT(1) DEFAULT 0 NOT NULL,
idGruppoEsclusione INT, -- Una caratteristica può appartenere o no ad un gruppo di eclusione
idProdotto INT NOT NULL,
FOREIGN KEY (idGruppoEsclusione) REFERENCES gruppoEsclusione (idGruppoEsclusione),
FOREIGN KEY (idProdotto) REFERENCES prodotto (idProdotto),
CHECK (differenzaPrezzo >= 0)
);
-- CREAZIONE RELAZIONE RIGAORDINE
CREATE TABLE rigaOrdine (
idRigaOrdine INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
quantita TINYINT NOT NULL,
prezzoBaseApplicato DECIMAL(10,2) NOT NULL,
idOrdine INT NOT NULL,
idProdotto INT NOT NULL,
FOREIGN KEY (idOrdine) REFERENCES ordine (idOrdine),
FOREIGN KEY (idProdotto) REFERENCES prodotto (idProdotto),
CHECK (quantita > 0),
CHECK (prezzoBaseApplicato >= 0)
);
-- CREAZIONE RELAZIONE RIGAORDINESELEZIONACARATTERISTICA
CREATE TABLE rigaOrdineSelezionaCaratteristica (
idCaratteristica INT NOT NULL,
idRigaOrdine INT NOT NULL,
differenzaPrezzoApplicata DECIMAL(10,2) NOT NULL,
PRIMARY KEY (idCaratteristica, idRigaOrdine),
FOREIGN KEY (idCaratteristica) REFERENCES caratteristica (idCaratteristica),
FOREIGN KEY (idRigaOrdine) REFERENCES rigaOrdine (idRigaOrdine)
);
+1149
View File
File diff suppressed because it is too large Load Diff
+28
View File
@@ -0,0 +1,28 @@
-- LOGIN
-- Ricerca di un utente tramite email
SELECT idUtente, nome, cognome, email, passwordHash, attivo
FROM utente
WHERE email = ?;
-- Determinazione del ruolo dell'utente
SELECT
EXISTS (
SELECT 1
FROM cliente
WHERE idUtente = ?
) AS cliente,
EXISTS (
SELECT 1
FROM personale
WHERE idUtente = ?
) AS personale,
EXISTS (
SELECT 1
FROM proprietario
WHERE idUtente = ?
) AS proprietario;
View File
Executable
+2
View File
@@ -0,0 +1,2 @@
[+] Preferiti: Il cliente può avere dei prodotti preferiti
[+] Immagini