234 lines
8.2 KiB
PHP
234 lines
8.2 KiB
PHP
<?php
|
|
|
|
/**
|
|
* my_lessons.php
|
|
* --------------------------------------------------------------------------
|
|
* Endpoint API delle lezioni per l'app Flutter (scuola YogaSoul).
|
|
*
|
|
* Posizione prevista sul server: public/api/my_lessons.php
|
|
* (accanto a _bootstrap.php)
|
|
*
|
|
* Autenticazione: gestita da _bootstrap.php (Vanguard, token Bearer).
|
|
* Dopo il require sono già disponibili:
|
|
* - $user -> utente autenticato ($user->id == bookingclass.iduser)
|
|
* - $db -> connessione PDO (da DBHandlerSelect)
|
|
*
|
|
* Parametri GET:
|
|
* - month=YYYY-MM (opzionale, default = mese corrente)
|
|
*
|
|
* Logica ricalcata su userpanel.php:
|
|
* - summary: conteggi utente-globali (acquistate/praticate/prenotate/
|
|
* da confermare/da programmare/perse)
|
|
* - lessons: lezioni "booked" del mese selezionato, con regole
|
|
* can_reschedule / can_delete identiche alla webapp.
|
|
* --------------------------------------------------------------------------
|
|
*/
|
|
|
|
require_once __DIR__ . '/_bootstrap.php';
|
|
|
|
// A questo punto $user e $db esistono già (altrimenti _bootstrap ha fatto exit 401).
|
|
|
|
$userId = (int) $user->id;
|
|
|
|
// Location fissa, come nella webapp (userpanel.php la stampa hardcoded).
|
|
const LESSON_LOCATION = 'via Valassina 62/B Seregno - Sala Contesto Yoga';
|
|
|
|
// ==========================================================================
|
|
// PARAMETRI: mese
|
|
// ==========================================================================
|
|
$month = $_GET['month'] ?? date('Y-m');
|
|
|
|
// Validazione: deve essere YYYY-MM, altrimenti fallback al mese corrente.
|
|
$monthDate = DateTime::createFromFormat('Y-m-d', $month . '-01');
|
|
if ($monthDate === false) {
|
|
$month = date('Y-m');
|
|
$monthDate = new DateTime(date('Y-m') . '-01');
|
|
}
|
|
|
|
// Finestra del mese. Replichiamo la logica di userpanel.php:
|
|
// se il mese richiesto è quello corrente, si parte da OGGI (non dal giorno 1),
|
|
// così non si mostrano lezioni già passate del mese in corso.
|
|
$monthStart = $monthDate->format('Y-m-01');
|
|
$today = date('Y-m-d');
|
|
if ($today > $monthStart && date('Y-m') === $month) {
|
|
$monthStart = $today;
|
|
}
|
|
// Fine mese + 1 giorno (bound superiore esclusivo), come nella webapp.
|
|
$monthEndPlus1 = (clone $monthDate)->modify('first day of next month')->format('Y-m-d');
|
|
|
|
// ==========================================================================
|
|
// SUMMARY: conteggi utente-globali
|
|
// (tradotti 1:1 dalle query mysqli di userpanel.php in PDO)
|
|
// ==========================================================================
|
|
|
|
// -- Totale biglietti acquistati (SUM nticket sugli ordini dell'utente) -----
|
|
$stmt = $db->prepare("
|
|
SELECT COALESCE(SUM(nticket), 0) AS total_tickets
|
|
FROM orderbook
|
|
WHERE iduser = :uid
|
|
");
|
|
$stmt->execute([':uid' => $userId]);
|
|
$purchased = (int) $stmt->fetchColumn();
|
|
|
|
// -- Stato prenotazioni (passate/future/perse/pending) ----------------------
|
|
$now = date('Y-m-d H:i:s');
|
|
$stmt = $db->prepare("
|
|
SELECT
|
|
SUM(CASE WHEN ss.dateschedule <= :now1
|
|
AND bc.status = 'booked'
|
|
AND bc.lostlesson = 'N' THEN 1 ELSE 0 END) AS passed,
|
|
SUM(CASE WHEN ss.dateschedule > :now2
|
|
AND bc.status = 'booked'
|
|
AND bc.lostlesson = 'N' THEN 1 ELSE 0 END) AS future,
|
|
SUM(CASE WHEN bc.lostlesson = 'Y'
|
|
AND bc.status != 'cancelled' THEN 1 ELSE 0 END) AS lost,
|
|
SUM(CASE WHEN bc.status = 'pending' THEN 1 ELSE 0 END) AS pending
|
|
FROM bookingclass bc
|
|
LEFT JOIN serviceschedule ss
|
|
ON bc.idserviceschedule = ss.idserviceschedule
|
|
WHERE bc.iduser = :uid
|
|
AND bc.status != 'cancelled'
|
|
AND bc.is_gift = 'N'
|
|
");
|
|
$stmt->execute([
|
|
':now1' => $now,
|
|
':now2' => $now,
|
|
':uid' => $userId,
|
|
]);
|
|
$counts = $stmt->fetch() ?: [];
|
|
|
|
$practiced = (int) ($counts['passed'] ?? 0);
|
|
$booked = (int) ($counts['future'] ?? 0);
|
|
$lost = (int) ($counts['lost'] ?? 0);
|
|
$pending = (int) ($counts['pending'] ?? 0);
|
|
|
|
// "Da programmare" = acquistate - praticate - prenotate - da confermare - perse
|
|
// (identico al calcolo $toprogram di userpanel.php)
|
|
$toSchedule = $purchased - $practiced - $booked - $pending - $lost;
|
|
if ($toSchedule < 0) {
|
|
$toSchedule = 0;
|
|
}
|
|
|
|
$summary = [
|
|
'purchased' => $purchased,
|
|
'practiced' => $practiced,
|
|
'booked' => $booked,
|
|
'pending' => $pending,
|
|
'to_schedule' => $toSchedule,
|
|
'lost' => $lost,
|
|
];
|
|
|
|
// ==========================================================================
|
|
// LESSONS: lezioni "booked" del mese selezionato
|
|
// (query principale di userpanel.php, tradotta in PDO)
|
|
// ==========================================================================
|
|
$stmt = $db->prepare("
|
|
SELECT
|
|
bc.idbookingclass,
|
|
bc.status,
|
|
bc.idservice,
|
|
bc.idorder,
|
|
bc.lostlesson,
|
|
bc.is_gift,
|
|
ss.dateschedule,
|
|
s.servicename,
|
|
s.colorclass,
|
|
ob.expireon,
|
|
ob.maxreschedule,
|
|
ob.reprogrammed
|
|
FROM bookingclass bc
|
|
LEFT JOIN service s ON bc.idservice = s.idservice
|
|
LEFT JOIN serviceschedule ss ON bc.idserviceschedule = ss.idserviceschedule
|
|
LEFT JOIN orderbook ob ON bc.idorder = ob.idorderbook
|
|
WHERE bc.iduser = :uid
|
|
AND bc.status = 'booked'
|
|
AND ss.dateschedule >= :start
|
|
AND ss.dateschedule < :end
|
|
ORDER BY ss.dateschedule ASC
|
|
");
|
|
$stmt->execute([
|
|
':uid' => $userId,
|
|
':start' => $monthStart . ' 00:00:00',
|
|
':end' => $monthEndPlus1 . ' 00:00:00',
|
|
]);
|
|
$rows = $stmt->fetchAll();
|
|
|
|
$lessons = [];
|
|
$nowDt = new DateTime();
|
|
|
|
foreach ($rows as $r) {
|
|
$dateschedule = $r['dateschedule'] ?? null;
|
|
if ($dateschedule === null) {
|
|
continue; // riga orfana senza schedule, la saltiamo
|
|
}
|
|
|
|
$classDt = new DateTime($dateschedule);
|
|
|
|
// ------------------------------------------------------------------
|
|
// Regola oraria can_delete (identica a userpanel.php)
|
|
// ------------------------------------------------------------------
|
|
$isSameDay = $classDt->format('Y-m-d') === $nowDt->format('Y-m-d');
|
|
$classHour = (int) $classDt->format('H');
|
|
$classMinute = (int) $classDt->format('i');
|
|
// "prima delle 17:00" = ora < 17, oppure esattamente 17:00
|
|
$isBefore1700 = ($classHour < 17) || ($classHour === 17 && $classMinute === 0);
|
|
|
|
if ($isSameDay) {
|
|
if ($isBefore1700) {
|
|
// lezioni prima delle 17: valido fino alle 00:01 dello stesso giorno
|
|
$deadline = new DateTime($classDt->format('Y-m-d 00:01:00'));
|
|
} else {
|
|
// lezioni dalle 17 in poi: valido fino alle 12:00 dello stesso giorno
|
|
$deadline = new DateTime($classDt->format('Y-m-d 12:00:00'));
|
|
}
|
|
$canByTime = $nowDt <= $deadline;
|
|
} else {
|
|
// giorni futuri: sempre consentito
|
|
$canByTime = true;
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
// Limite riprogrammazioni dell'ordine (identico a userpanel.php)
|
|
// ------------------------------------------------------------------
|
|
$maxreschedule = (int) ($r['maxreschedule'] ?? 0);
|
|
$reprogrammed = (int) ($r['reprogrammed'] ?? 0);
|
|
$canReprogram = $reprogrammed < $maxreschedule;
|
|
|
|
$isGift = ($r['is_gift'] ?? 'N') === 'Y';
|
|
|
|
if ($isGift) {
|
|
// Omaggio: mai riprogrammabile, cancellabile in base al tempo.
|
|
$canReschedule = false;
|
|
$canDelete = $canByTime;
|
|
} else {
|
|
// Lezione normale: entrambi soggetti a tempo + limite riprogrammazioni.
|
|
$canReschedule = $canByTime && $canReprogram;
|
|
$canDelete = $canByTime && $canReprogram;
|
|
}
|
|
|
|
$lessons[] = [
|
|
'booking_id' => (int) $r['idbookingclass'],
|
|
'service_id' => (int) ($r['idservice'] ?? 0),
|
|
'datetime' => $classDt->format('Y-m-d H:i:s'),
|
|
'date' => $classDt->format('Y-m-d'),
|
|
'time' => $classDt->format('H:i'),
|
|
'class_name' => (string) ($r['servicename'] ?? ''),
|
|
'color' => (string) ($r['colorclass'] ?? '#1ebf73'),
|
|
'location' => LESSON_LOCATION,
|
|
'expire_on' => $r['expireon'] ?? null,
|
|
'lost_lesson' => ($r['lostlesson'] ?? 'N') === 'Y',
|
|
'can_reschedule' => $canReschedule,
|
|
'can_delete' => $canDelete,
|
|
];
|
|
}
|
|
|
|
// ==========================================================================
|
|
// OUTPUT
|
|
// ==========================================================================
|
|
echo json_encode([
|
|
'success' => true,
|
|
'month' => $month,
|
|
'summary' => $summary,
|
|
'lessons' => $lessons,
|
|
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|