getConnection();
$iduserlogin = (int) $iduserlogin;
/* -------------------------------------------------------------------------
* 1) Calcolo del mese da visualizzare
* ---------------------------------------------------------------------- */
if (isset($_GET['prev_month'])) {
$currentMonthStart = preg_replace('/[^0-9\-]/', '', $_GET['prev_month']) . '-01';
} elseif (isset($_GET['next_month'])) {
$currentMonthStart = preg_replace('/[^0-9\-]/', '', $_GET['next_month']) . '-01';
} else {
$currentMonthStart = date("Y-m-01");
}
if (strtotime($currentMonthStart) === false) {
$currentMonthStart = date("Y-m-01");
}
$currentDate = date("Y-m-d");
// Se oggi è dopo l'inizio del mese scelto, parti da oggi
if ($currentDate > $currentMonthStart) {
$currentMonthStart = $currentDate;
}
$currentMonthEnd = date("Y-m-t", strtotime($currentMonthStart));
$monthParams = [
':iduser' => $iduserlogin,
':idschool' => $idschool,
':monthStart' => $currentMonthStart,
':monthEnd' => $currentMonthEnd,
];
/* -------------------------------------------------------------------------
* 2) Lezioni del mese: prenotate, in attesa di conferma, in lista d'attesa
* ---------------------------------------------------------------------- */
$sqlBooked = "SELECT bookingclass.*, service.*, serviceschedule.*, orderbook.expireon
FROM bookingclass
LEFT JOIN service ON bookingclass.idservice = service.idservice
LEFT JOIN serviceschedule ON bookingclass.idserviceschedule = serviceschedule.idserviceschedule
LEFT JOIN orderbook ON bookingclass.idorder = orderbook.idorderbook
WHERE bookingclass.iduser = :iduser
AND bookingclass.idschool = :idschool
AND bookingclass.status = 'booked'
AND serviceschedule.dateschedule BETWEEN :monthStart AND DATE_ADD(:monthEnd, INTERVAL 1 DAY)
ORDER BY serviceschedule.dateschedule";
$stmt = $pdo->prepare($sqlBooked);
$stmt->execute($monthParams);
$bookedRows = $stmt->fetchAll();
$sqlPending = "SELECT bookingclass.*, service.servicename, service.colorclass, service.idteacher, serviceschedule.dateschedule
FROM bookingclass
LEFT JOIN service ON bookingclass.idservice = service.idservice
LEFT JOIN serviceschedule ON bookingclass.idserviceschedule = serviceschedule.idserviceschedule
WHERE bookingclass.iduser = :iduser
AND bookingclass.idschool = :idschool
AND bookingclass.status = 'pending'
AND serviceschedule.dateschedule BETWEEN :monthStart AND DATE_ADD(:monthEnd, INTERVAL 1 DAY)
ORDER BY serviceschedule.dateschedule";
$stmt = $pdo->prepare($sqlPending);
$stmt->execute($monthParams);
$pendingRows = $stmt->fetchAll();
$sqlWaiting = "SELECT bookingclass.*, service.servicename, service.colorclass, service.maxcapacity, service.idteacher, serviceschedule.dateschedule
FROM bookingclass
LEFT JOIN service ON bookingclass.idservice = service.idservice
LEFT JOIN serviceschedule ON bookingclass.idserviceschedule = serviceschedule.idserviceschedule
WHERE bookingclass.iduser = :iduser
AND bookingclass.idschool = :idschool
AND bookingclass.status = 'waiting'
AND serviceschedule.dateschedule BETWEEN :monthStart AND DATE_ADD(:monthEnd, INTERVAL 1 DAY)
ORDER BY serviceschedule.dateschedule";
$stmt = $pdo->prepare($sqlWaiting);
$stmt->execute($monthParams);
$waitingRows = $stmt->fetchAll();
// Posizione in coda per ciascuna lezione waiting (1-based, ordine per created_at)
$waitingPositions = [];
$stmtPos = $pdo->prepare(
"SELECT COUNT(*) FROM bookingclass
WHERE idserviceschedule = :sched AND idschool = :idschool
AND status = 'waiting' AND created_at <= :mycreated"
);
foreach ($waitingRows as $wrow) {
$stmtPos->execute([
':sched' => (int) $wrow['idserviceschedule'],
':idschool' => $idschool,
':mycreated' => $wrow['created_at'],
]);
$waitingPositions[(int) $wrow['idbookingclass']] = (int) $stmtPos->fetchColumn();
}
/* -------------------------------------------------------------------------
* 3) Ticket acquistati dall'utente in questa scuola
* ---------------------------------------------------------------------- */
$stmt = $pdo->prepare("SELECT SUM(nticket) FROM orderbook WHERE iduser = ? AND idschool = ?");
$stmt->execute([$iduserlogin, $idschool]);
$totalTickets = (int) $stmt->fetchColumn();
/* -------------------------------------------------------------------------
* 4) Conteggio stati lezioni (praticate / future / perse / da confermare)
* ---------------------------------------------------------------------- */
$currentDateTime = date("Y-m-d H:i:s");
$stmt = $pdo->prepare("SELECT
COUNT(*) AS total,
SUM(CASE WHEN serviceschedule.dateschedule <= :now1
AND bookingclass.status = 'booked'
AND bookingclass.lostlesson = 'N' THEN 1 ELSE 0 END) AS passed,
SUM(CASE WHEN serviceschedule.dateschedule > :now2
AND bookingclass.status = 'booked'
AND bookingclass.lostlesson = 'N' THEN 1 ELSE 0 END) AS future,
SUM(CASE WHEN bookingclass.lostlesson = 'Y'
AND bookingclass.status != 'cancelled' THEN 1 ELSE 0 END) AS lost,
SUM(CASE WHEN bookingclass.status = 'pending' THEN 1 ELSE 0 END) AS pending
FROM bookingclass
LEFT JOIN serviceschedule ON bookingclass.idserviceschedule = serviceschedule.idserviceschedule
WHERE bookingclass.iduser = :iduser
AND bookingclass.idschool = :idschool
AND bookingclass.status != 'cancelled'");
$stmt->execute([
':now1' => $currentDateTime,
':now2' => $currentDateTime,
':iduser' => $iduserlogin,
':idschool' => $idschool,
]);
$rowCounts = $stmt->fetch();
$totalRecords = (int) ($rowCounts['total'] ?? 0);
$passedRecords = (int) ($rowCounts['passed'] ?? 0);
$futureRecords = (int) ($rowCounts['future'] ?? 0);
$lost = (int) ($rowCounts['lost'] ?? 0);
$pending = (int) ($rowCounts['pending'] ?? 0);
$toprogram = $totalTickets - $passedRecords - $futureRecords - $pending - $lost;
/* -------------------------------------------------------------------------
* 4b) Impostazioni scuola: insegnanti, avviso, negozio, indirizzo
* ---------------------------------------------------------------------- */
$showTeacher = SchoolSettings::get('show_teacher', 'N') === 'Y';
$studentNotice = trim((string) SchoolSettings::get('student_notice', ''));
$shopUrl = trim((string) SchoolSettings::get('shop_url', ''));
$schoolAddress = implode(', ', array_filter([
trim((string) ($schoolData['address'] ?? '')),
trim((string) ($schoolData['city'] ?? '')),
]));
$teachersById = [];
if ($showTeacher) {
$stmt = $pdo->prepare("SELECT idemployee, nameemployee, surnameemployee, photo FROM employee WHERE idschool = ?");
$stmt->execute([$idschool]);
foreach ($stmt->fetchAll() as $t) {
$teachersById[(int) $t['idemployee']] = $t;
}
}
/* -------------------------------------------------------------------------
* 5) Limiti di riprogrammazione degli ordini coinvolti (una sola query)
* ---------------------------------------------------------------------- */
$reprogramInfo = [];
$orderIds = array_filter(array_unique(array_map(fn($r) => (int) ($r['idorder'] ?? 0), $bookedRows)));
if (!empty($orderIds)) {
$placeholders = implode(',', array_fill(0, count($orderIds), '?'));
$stmt = $pdo->prepare(
"SELECT idorderbook, maxreschedule, reprogrammed
FROM orderbook
WHERE idorderbook IN ($placeholders) AND idschool = ?"
);
$stmt->execute(array_merge(array_values($orderIds), [$idschool]));
foreach ($stmt->fetchAll() as $r) {
$reprogramInfo[(int) $r['idorderbook']] = [
'max' => (int) ($r['maxreschedule'] ?? 0),
'done' => (int) ($r['reprogrammed'] ?? 0),
];
}
}
/* -------------------------------------------------------------------------
* Helper
* ---------------------------------------------------------------------- */
function e($value): string
{
return htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8');
}
function teacherLine(array $row, bool $show, array $teachersById): string
{
if (!$show) return '';
$t = $teachersById[(int) ($row['idteacher'] ?? 0)] ?? null;
if (!$t) return '';
$name = trim($t['nameemployee'] . ' ' . $t['surnameemployee']);
if (!empty($t['photo'])) {
$avatar = ' ';
} else {
$ini = mb_strtoupper(mb_substr($t['nameemployee'], 0, 1) . mb_substr($t['surnameemployee'], 0, 1));
$avatar = '' . e($ini) . ' ';
}
return '
' . $avatar . 'Insegnante: ' . e($name) . '
';
}
/** Riga "Luogo" (vuota se la scuola non ha indirizzo) */
function placeLine(string $address): string
{
return $address !== '' ? 'Luogo: ' . e($address) . '
' : '';
}
$italianMonths = [
"January" => "Gennaio",
"February" => "Febbraio",
"March" => "Marzo",
"April" => "Aprile",
"May" => "Maggio",
"June" => "Giugno",
"July" => "Luglio",
"August" => "Agosto",
"September" => "Settembre",
"October" => "Ottobre",
"November" => "Novembre",
"December" => "Dicembre",
];
?>
YogiBook -
Benvenuta/o
Di seguito puoi vedere lo stato delle tue prenotazioni
Richiesta di riprogrammazione inviata con successo!
Richiesta di prenotazione inviata! La troverai tra le lezioni in attesa di conferma .
'Pacchetto non valido.',
'expired' => 'Il pacchetto è scaduto.',
'notickets' => 'Non hai più lezioni disponibili in questo pacchetto.',
'class' => 'Questa lezione non è disponibile per il tuo pacchetto.',
'afterexpiry' => 'La lezione è successiva alla scadenza del pacchetto.',
'already' => 'Sei già prenotata/o a questa lezione.',
'noreprog' => 'Questa lezione non può essere spostata (omaggio o riprogrammazioni esaurite).',
'toolate' => 'Il termine per spostare questa lezione è scaduto.',
'save' => 'Errore durante la prenotazione, riprova.',
];
?>
La classe era piena: sei stata/o inserita/o in lista d'attesa . Se si libera un posto verrai avvisata/o.
Sei uscita/o dalla lista d'attesa.
La classe è al completo e la lista d'attesa non è attiva. Prova con un altro orario.
Lezione cancellata con successo! Grazie per aver liberato il posto!
In attesa di conferma
format("d");
$pMonth = $italianMonths[$pDateObj->format("F")];
$pWhen = $pDateObj->format("d-m-Y H:i");
$pColor = $prow['colorclass'] ?? '#1ebf73';
$pName = $prow['servicename'] ?? '';
?>
In lista d'attesa
format("d");
$wMonth = $italianMonths[$wDateObj->format("F")];
$wWhen = $wDateObj->format("d-m-Y H:i");
$wColor = $wrow['colorclass'] ?? '#1ebf73';
$wName = $wrow['servicename'] ?? '';
$wPos = $waitingPositions[(int) $wrow['idbookingclass']] ?? 0;
?>
In coda
Quando:
Luogo: via Valassina 62/B Seregno - Sala Contesto Yoga
0) : ?>
La tua posizione in coda:
Se si libera un posto verrai avvisata/o. Non serve fare nulla.
Esci dalla lista d'attesa
Prenotate
Prenotazioni non presenti per questo mese
format("d");
$monthInItalian = $italianMonths[$dateObj->format("F")];
$newDateFormat = $dateObj->format("d-m-Y H:i");
// Calcolo finestra di cancellazione
$currentTime = new DateTime();
$classTime = new DateTime($dateschedule);
$isSameDay = $classTime->format('Y-m-d') === $currentTime->format('Y-m-d');
$classHour = (int) $classTime->format('H');
$classMinute = (int) $classTime->format('i');
$isBefore1700 = ($classHour < 17) || ($classHour === 17 && $classMinute === 0);
if ($isSameDay) {
if ($isBefore1700) {
$deadline = new DateTime($classTime->format('Y-m-d 00:01:00'));
} else {
$deadline = new DateTime($classTime->format('Y-m-d 12:00:00'));
}
$canBeDeleted = $currentTime <= $deadline;
} else {
$canBeDeleted = true;
}
// Limite riprogrammazioni (dai dati pre-caricati, niente query nel loop)
$idorder = (int) ($row['idorder'] ?? 0);
$canReprogram = true;
if (isset($reprogramInfo[$idorder])) {
$canReprogram = $reprogramInfo[$idorder]['done'] < $reprogramInfo[$idorder]['max'];
}
$idbookingclass = (int) $row['idbookingclass'];
$idservice = (int) $row['idservice'];
$expirydate = date("d/m/Y", strtotime($row['expireon']));
$colorclass = $row['colorclass'] ?? '#1ebf73';
$servicename = $row['servicename'] ?? '';
?>
Quando:
Luogo: via Valassina 62/B Seregno - Sala Contesto Yoga
Cal
Riprogramma
Cancella
Non puoi riprogrammare