started work on scheduling
Some checks failed
PHPUnit / test (push) Has been cancelled

This commit is contained in:
2026-07-01 10:07:20 +02:00
parent 70dca17451
commit c5c61f22ad
13 changed files with 414 additions and 4 deletions

140
lib/session_schedule.php Normal file
View File

@ -0,0 +1,140 @@
<?php
/**
* Next program session appointments (date-only, DD-MM-YYYY).
*/
/** @return bool */
function qdb_scheduled_date_format_valid(string $date): bool
{
if (!preg_match('/^\d{2}-\d{2}-\d{4}$/', $date)) {
return false;
}
[$d, $m, $y] = array_map('intval', explode('-', $date));
return checkdate($m, $d, $y);
}
/** Start of calendar day in server default timezone. */
function qdb_scheduled_date_to_start_of_day_unix(string $date): ?int
{
if (!qdb_scheduled_date_format_valid($date)) {
return null;
}
[$d, $m, $y] = explode('-', $date);
$ts = mktime(0, 0, 0, (int)$m, (int)$d, (int)$y);
return $ts !== false ? $ts : null;
}
function qdb_scheduled_date_is_after_today(string $date, ?int $nowTs = null): bool
{
$dayStart = qdb_scheduled_date_to_start_of_day_unix($date);
if ($dayStart === null) {
return false;
}
$nowTs ??= time();
$todayStart = strtotime('today', $nowTs);
return $dayStart > $todayStart;
}
/**
* @return array{scheduledDate: string, programCycleNumber: int, programSessionNumber: int, programSessionID: ?string, updatedAt: int}|null
*/
function qdb_get_client_session_schedule(PDO $pdo, string $clientCode): ?array
{
$stmt = $pdo->prepare(
'SELECT scheduledDate, programCycleNumber, programSessionNumber, programSessionID, updatedAt
FROM client_session_schedule WHERE clientCode = :cc'
);
$stmt->execute([':cc' => $clientCode]);
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$row) {
return null;
}
return [
'scheduledDate' => (string)$row['scheduledDate'],
'programCycleNumber' => (int)$row['programCycleNumber'],
'programSessionNumber' => (int)$row['programSessionNumber'],
'programSessionID' => $row['programSessionID'] !== null && $row['programSessionID'] !== ''
? (string)$row['programSessionID']
: null,
'updatedAt' => (int)$row['updatedAt'],
];
}
function qdb_upsert_client_session_schedule(
PDO $pdo,
string $clientCode,
string $scheduledDate,
int $programCycleNumber,
int $programSessionNumber,
?string $programSessionID = null
): void {
if (!qdb_scheduled_date_format_valid($scheduledDate)) {
json_error('INVALID_FIELD', 'scheduledDate must be DD-MM-YYYY', 400);
}
if (!qdb_scheduled_date_is_after_today($scheduledDate)) {
json_error('INVALID_FIELD', 'scheduledDate must be in the future', 400);
}
if ($programCycleNumber < 1 || $programSessionNumber < 1) {
json_error('INVALID_FIELD', 'program cycle and session must be positive', 400);
}
$pdo->prepare(
'INSERT INTO client_session_schedule (
clientCode, scheduledDate, programCycleNumber, programSessionNumber, programSessionID, updatedAt
) VALUES (
:cc, :sd, :pcn, :psn, :psid, :uat
)
ON CONFLICT(clientCode) DO UPDATE SET
scheduledDate = excluded.scheduledDate,
programCycleNumber = excluded.programCycleNumber,
programSessionNumber = excluded.programSessionNumber,
programSessionID = excluded.programSessionID,
updatedAt = excluded.updatedAt'
)->execute([
':cc' => $clientCode,
':sd' => $scheduledDate,
':pcn' => $programCycleNumber,
':psn' => $programSessionNumber,
':psid' => $programSessionID,
':uat' => time(),
]);
}
/**
* RBAC-scoped schedule rows for the website Schedule view.
*
* @return list<array<string, mixed>>
*/
function qdb_list_session_schedules_scoped(PDO $pdo, array $tokenRec): array
{
[$rbacClause, $rbacParams] = rbac_client_filter($tokenRec, 'cl');
$sql = "
SELECT css.clientCode, css.scheduledDate, css.programCycleNumber, css.programSessionNumber,
css.programSessionID, css.updatedAt,
cl.coachID, co.username AS coachUsername,
sv.username AS supervisorUsername
FROM client_session_schedule css
INNER JOIN client cl ON cl.clientCode = css.clientCode
LEFT JOIN coach co ON co.coachID = cl.coachID
LEFT JOIN supervisor sv ON sv.supervisorID = co.supervisorID
WHERE ($rbacClause)
ORDER BY css.scheduledDate ASC, co.username ASC, css.clientCode ASC
";
$stmt = $pdo->prepare($sql);
$stmt->execute($rbacParams);
$rows = [];
foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
$rows[] = [
'clientCode' => $row['clientCode'],
'scheduledDate' => $row['scheduledDate'],
'programCycleNumber' => (int)$row['programCycleNumber'],
'programSessionNumber' => (int)$row['programSessionNumber'],
'programSessionID' => $row['programSessionID'],
'coachID' => $row['coachID'],
'coachUsername' => $row['coachUsername'] ?? $row['coachID'],
'supervisorUsername' => $row['supervisorUsername'] ?? '',
'updatedAt' => (int)$row['updatedAt'],
];
}
return $rows;
}