extending results page to show metadata and group by clientid to improve tracking progress
Some checks failed
PHPUnit / test (push) Has been cancelled
Some checks failed
PHPUnit / test (push) Has been cancelled
This commit is contained in:
@ -289,16 +289,13 @@ function qdb_backfill_submissions_from_live(PDO $pdo): bool {
|
||||
}
|
||||
|
||||
/**
|
||||
* Build CSV rows for all submission versions of one questionnaire (RBAC-scoped).
|
||||
* RBAC-scoped submission rows for one questionnaire (client, then version).
|
||||
*
|
||||
* @return list<array<string, string>>
|
||||
* @return list<array<string, mixed>>
|
||||
*/
|
||||
function qdb_export_all_versions_rows(
|
||||
function qdb_fetch_questionnaire_submissions_scoped(
|
||||
PDO $pdo,
|
||||
string $questionnaireID,
|
||||
array $questions,
|
||||
array $resultColumns,
|
||||
array $optionTextMap,
|
||||
array $tokenRec
|
||||
): array {
|
||||
[$rbacClause, $rbacParams] = rbac_client_filter($tokenRec, 'cl');
|
||||
@ -308,6 +305,7 @@ function qdb_export_all_versions_rows(
|
||||
qs.completedAt AS submissionCompletedAt, qs.sumPoints AS submissionSumPoints,
|
||||
qs.startedAt AS submissionStartedAt, qs.status AS submissionStatus,
|
||||
qs.structureRevision, qs.structureSnapshotJson,
|
||||
qs.programCycleNumber, qs.programSessionID, qs.programSessionNumber,
|
||||
cl.clientCode, cl.coachID,
|
||||
co.username AS coachUsername,
|
||||
sv.username AS supervisorUsername
|
||||
@ -321,58 +319,99 @@ function qdb_export_all_versions_rows(
|
||||
$params = array_merge([':qnid' => $questionnaireID], $rbacParams);
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute($params);
|
||||
$submissions = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
$defaultQuestionIDs = array_column($questions, 'questionID');
|
||||
return $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
}
|
||||
|
||||
/** @return array<string, string> */
|
||||
function qdb_submission_submitter_username_map(PDO $pdo): array {
|
||||
$userMap = [];
|
||||
$userStmt = $pdo->query('SELECT userID, username FROM users');
|
||||
foreach ($userStmt->fetchAll(PDO::FETCH_ASSOC) as $u) {
|
||||
$userMap[$u['userID']] = $u['username'];
|
||||
}
|
||||
return $userMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve per-submission question columns from structure snapshot or questionnaire defaults.
|
||||
*
|
||||
* @return array{submissionColumns: array, submissionOptionMap: array, submissionQuestionIDs: list<string>}
|
||||
*/
|
||||
function qdb_submission_display_context(
|
||||
PDO $pdo,
|
||||
array $submissionRow,
|
||||
array $defaultQuestions,
|
||||
array $defaultResultColumns,
|
||||
array $defaultOptionTextMap
|
||||
): array {
|
||||
$snap = json_decode($submissionRow['structureSnapshotJson'] ?? '{}', true) ?: [];
|
||||
if (!empty($snap['questions'])) {
|
||||
$snapCtx = qdb_display_context_from_manifest($pdo, $snap);
|
||||
return [
|
||||
'submissionColumns' => $snapCtx['resultColumns'],
|
||||
'submissionOptionMap' => $snapCtx['optionTextMap'],
|
||||
'submissionQuestionIDs' => array_column($snapCtx['questions'], 'questionID'),
|
||||
];
|
||||
}
|
||||
return [
|
||||
'submissionColumns' => $defaultResultColumns,
|
||||
'submissionOptionMap' => $defaultOptionTextMap,
|
||||
'submissionQuestionIDs' => array_column($defaultQuestions, 'questionID'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Build CSV rows for all submission versions of one questionnaire (RBAC-scoped).
|
||||
*
|
||||
* @return list<array<string, string>>
|
||||
*/
|
||||
function qdb_export_all_versions_rows(
|
||||
PDO $pdo,
|
||||
string $questionnaireID,
|
||||
array $questions,
|
||||
array $resultColumns,
|
||||
array $optionTextMap,
|
||||
array $tokenRec
|
||||
): array {
|
||||
$submissions = qdb_fetch_questionnaire_submissions_scoped($pdo, $questionnaireID, $tokenRec);
|
||||
$userMap = qdb_submission_submitter_username_map($pdo);
|
||||
|
||||
$rows = [];
|
||||
foreach ($submissions as $s) {
|
||||
$snap = json_decode($s['structureSnapshotJson'] ?? '{}', true) ?: [];
|
||||
if (!empty($snap['questions'])) {
|
||||
$snapCtx = qdb_display_context_from_manifest($pdo, $snap);
|
||||
$submissionColumns = $snapCtx['resultColumns'];
|
||||
$submissionOptionMap = $snapCtx['optionTextMap'];
|
||||
$submissionQuestionIDs = array_column($snapCtx['questions'], 'questionID');
|
||||
} else {
|
||||
$submissionColumns = $resultColumns;
|
||||
$submissionOptionMap = $optionTextMap;
|
||||
$submissionQuestionIDs = $defaultQuestionIDs;
|
||||
}
|
||||
$ctx = qdb_submission_display_context($pdo, $s, $questions, $resultColumns, $optionTextMap);
|
||||
|
||||
$row = [
|
||||
'submissionID' => $s['submissionID'],
|
||||
'version' => (string)(int)$s['version'],
|
||||
'structureRevision' => (string)max(1, (int)($s['structureRevision'] ?? 1)),
|
||||
'submittedAt' => $s['submittedAt'] ? date('Y-m-d H:i', (int)$s['submittedAt']) : '',
|
||||
'submittedByRole' => $s['submittedByRole'] ?? '',
|
||||
'submittedBy' => $userMap[$s['submittedByUserID'] ?? ''] ?? ($s['submittedByUserID'] ?? ''),
|
||||
'clientCode' => $s['clientCode'],
|
||||
'coach' => $s['coachUsername'] ?? $s['coachID'],
|
||||
'supervisor' => $s['supervisorUsername'] ?? '',
|
||||
'status' => $s['submissionStatus'] ?? '',
|
||||
'sumPoints' => $s['submissionSumPoints'] ?? '',
|
||||
'startedAt' => $s['submissionStartedAt'] ? date('Y-m-d H:i', (int)$s['submissionStartedAt']) : '',
|
||||
'completedAt' => $s['submissionCompletedAt'] ? date('Y-m-d H:i', (int)$s['submissionCompletedAt']) : '',
|
||||
'clientCode' => $s['clientCode'],
|
||||
'version' => (string)(int)$s['version'],
|
||||
'programCycleNumber' => $s['programCycleNumber'] !== null ? (string)(int)$s['programCycleNumber'] : '',
|
||||
'programSessionNumber' => $s['programSessionNumber'] !== null ? (string)(int)$s['programSessionNumber'] : '',
|
||||
'programSessionID' => $s['programSessionID'] ?? '',
|
||||
'startedAt' => $s['submissionStartedAt'] ? date('Y-m-d H:i', (int)$s['submissionStartedAt']) : '',
|
||||
'completedAt' => $s['submissionCompletedAt'] ? date('Y-m-d H:i', (int)$s['submissionCompletedAt']) : '',
|
||||
'submittedAt' => $s['submittedAt'] ? date('Y-m-d H:i', (int)$s['submittedAt']) : '',
|
||||
'coach' => $s['coachUsername'] ?? $s['coachID'],
|
||||
'supervisor' => $s['supervisorUsername'] ?? '',
|
||||
'status' => $s['submissionStatus'] ?? '',
|
||||
'sumPoints' => $s['submissionSumPoints'] ?? '',
|
||||
'submissionID' => $s['submissionID'],
|
||||
'structureRevision' => (string)max(1, (int)($s['structureRevision'] ?? 1)),
|
||||
'submittedByRole' => $s['submittedByRole'] ?? '',
|
||||
'submittedBy' => $userMap[$s['submittedByUserID'] ?? ''] ?? ($s['submittedByUserID'] ?? ''),
|
||||
];
|
||||
|
||||
$answerMap = qdb_load_client_answer_map(
|
||||
$pdo,
|
||||
$s['clientCode'],
|
||||
$submissionQuestionIDs,
|
||||
$ctx['submissionQuestionIDs'],
|
||||
'client_answer_submission',
|
||||
$s['submissionID']
|
||||
);
|
||||
|
||||
foreach ($submissionColumns as $col) {
|
||||
foreach ($ctx['submissionColumns'] as $col) {
|
||||
$qid = $col['questionID'];
|
||||
$a = $answerMap[$qid] ?? null;
|
||||
$row[$col['header']] = qdb_results_column_cell_value($col, $a, $submissionOptionMap);
|
||||
$row[$col['header']] = qdb_results_column_cell_value($col, $a, $ctx['submissionOptionMap']);
|
||||
}
|
||||
$rows[] = $row;
|
||||
}
|
||||
@ -380,6 +419,68 @@ function qdb_export_all_versions_rows(
|
||||
return $rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submission rows for the results API (all versions, grouped by client in sort order).
|
||||
*
|
||||
* @return list<array<string, mixed>>
|
||||
*/
|
||||
function qdb_results_submission_entries(
|
||||
PDO $pdo,
|
||||
string $questionnaireID,
|
||||
array $questions,
|
||||
array $resultColumns,
|
||||
array $optionTextMap,
|
||||
array $tokenRec
|
||||
): array {
|
||||
$submissions = qdb_fetch_questionnaire_submissions_scoped($pdo, $questionnaireID, $tokenRec);
|
||||
$userMap = qdb_submission_submitter_username_map($pdo);
|
||||
$entries = [];
|
||||
|
||||
foreach ($submissions as $s) {
|
||||
$ctx = qdb_submission_display_context($pdo, $s, $questions, $resultColumns, $optionTextMap);
|
||||
$answerMap = qdb_load_client_answer_map(
|
||||
$pdo,
|
||||
$s['clientCode'],
|
||||
$ctx['submissionQuestionIDs'],
|
||||
'client_answer_submission',
|
||||
$s['submissionID']
|
||||
);
|
||||
|
||||
$answers = [];
|
||||
foreach ($answerMap as $qid => $a) {
|
||||
$answers[$qid] = [
|
||||
'answerOptionID' => $a['answerOptionID'],
|
||||
'freeTextValue' => $a['freeTextValue'],
|
||||
'numericValue' => $a['numericValue'] !== null ? (float)$a['numericValue'] : null,
|
||||
'answeredAt' => null,
|
||||
];
|
||||
}
|
||||
|
||||
$entries[] = [
|
||||
'submissionID' => $s['submissionID'],
|
||||
'version' => (int)$s['version'],
|
||||
'clientCode' => $s['clientCode'],
|
||||
'coachID' => $s['coachID'],
|
||||
'coachUsername' => $s['coachUsername'],
|
||||
'supervisorUsername' => $s['supervisorUsername'],
|
||||
'status' => $s['submissionStatus'] ?? '',
|
||||
'sumPoints' => $s['submissionSumPoints'] !== null ? (int)$s['submissionSumPoints'] : null,
|
||||
'startedAt' => $s['submissionStartedAt'] !== null ? (int)$s['submissionStartedAt'] : null,
|
||||
'completedAt' => $s['submissionCompletedAt'] !== null ? (int)$s['submissionCompletedAt'] : null,
|
||||
'submittedAt' => $s['submittedAt'] !== null ? (int)$s['submittedAt'] : null,
|
||||
'programCycleNumber' => $s['programCycleNumber'] !== null ? (int)$s['programCycleNumber'] : null,
|
||||
'programSessionID' => $s['programSessionID'],
|
||||
'programSessionNumber' => $s['programSessionNumber'] !== null ? (int)$s['programSessionNumber'] : null,
|
||||
'structureRevision' => max(1, (int)($s['structureRevision'] ?? 1)),
|
||||
'submittedByRole' => $s['submittedByRole'] ?? '',
|
||||
'submittedBy' => $userMap[$s['submittedByUserID'] ?? ''] ?? ($s['submittedByUserID'] ?? ''),
|
||||
'answers' => $answers,
|
||||
];
|
||||
}
|
||||
|
||||
return $entries;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{questions: array, resultColumns: array, optionTextMap: array}
|
||||
*/
|
||||
@ -428,7 +529,8 @@ function qdb_export_current_rows(
|
||||
SELECT cl.clientCode, cl.coachID,
|
||||
co.username AS coachUsername,
|
||||
sv.username AS supervisorUsername,
|
||||
cq.status, cq.sumPoints, cq.startedAt, cq.completedAt
|
||||
cq.status, cq.sumPoints, cq.startedAt, cq.completedAt,
|
||||
cq.programCycleNumber, cq.programSessionID, cq.programSessionNumber
|
||||
FROM client cl
|
||||
INNER JOIN completed_questionnaire cq ON cq.clientCode = cl.clientCode AND cq.questionnaireID = :qnid
|
||||
LEFT JOIN coach co ON co.coachID = cl.coachID
|
||||
@ -451,13 +553,16 @@ function qdb_export_current_rows(
|
||||
$rows = [];
|
||||
foreach ($clients as $c) {
|
||||
$row = [
|
||||
'clientCode' => $c['clientCode'],
|
||||
'coach' => $c['coachUsername'] ?? $c['coachID'],
|
||||
'supervisor' => $c['supervisorUsername'] ?? '',
|
||||
'status' => $c['status'],
|
||||
'sumPoints' => $c['sumPoints'],
|
||||
'startedAt' => $c['startedAt'] ? date('Y-m-d H:i', (int)$c['startedAt']) : '',
|
||||
'completedAt' => $c['completedAt'] ? date('Y-m-d H:i', (int)$c['completedAt']) : '',
|
||||
'clientCode' => $c['clientCode'],
|
||||
'programCycleNumber' => $c['programCycleNumber'] !== null ? (string)(int)$c['programCycleNumber'] : '',
|
||||
'programSessionNumber' => $c['programSessionNumber'] !== null ? (string)(int)$c['programSessionNumber'] : '',
|
||||
'programSessionID' => $c['programSessionID'] ?? '',
|
||||
'startedAt' => $c['startedAt'] ? date('Y-m-d H:i', (int)$c['startedAt']) : '',
|
||||
'completedAt' => $c['completedAt'] ? date('Y-m-d H:i', (int)$c['completedAt']) : '',
|
||||
'coach' => $c['coachUsername'] ?? $c['coachID'],
|
||||
'supervisor' => $c['supervisorUsername'] ?? '',
|
||||
'status' => $c['status'],
|
||||
'sumPoints' => $c['sumPoints'],
|
||||
];
|
||||
|
||||
$bindParams = array_merge([$c['clientCode']], $questionIDs);
|
||||
@ -523,7 +628,10 @@ function qdb_export_rows_to_csv_string(array $rows, array $fallbackHeader = []):
|
||||
}
|
||||
|
||||
function qdb_export_current_csv_fallback_header(array $resultColumns): array {
|
||||
$header = ['clientCode', 'coach', 'supervisor', 'status', 'sumPoints', 'startedAt', 'completedAt'];
|
||||
$header = [
|
||||
'clientCode', 'programCycleNumber', 'programSessionNumber', 'programSessionID',
|
||||
'startedAt', 'completedAt', 'coach', 'supervisor', 'status', 'sumPoints',
|
||||
];
|
||||
foreach ($resultColumns as $col) {
|
||||
$header[] = $col['header'];
|
||||
}
|
||||
@ -532,8 +640,10 @@ function qdb_export_current_csv_fallback_header(array $resultColumns): array {
|
||||
|
||||
function qdb_export_all_versions_csv_fallback_header(array $resultColumns): array {
|
||||
$header = [
|
||||
'submissionID', 'version', 'submittedAt', 'submittedByRole', 'submittedBy',
|
||||
'clientCode', 'coach', 'supervisor', 'status', 'sumPoints', 'startedAt', 'completedAt',
|
||||
'clientCode', 'version', 'programCycleNumber', 'programSessionNumber', 'programSessionID',
|
||||
'startedAt', 'completedAt', 'submittedAt',
|
||||
'coach', 'supervisor', 'status', 'sumPoints',
|
||||
'submissionID', 'structureRevision', 'submittedByRole', 'submittedBy',
|
||||
];
|
||||
foreach ($resultColumns as $col) {
|
||||
$header[] = $col['header'];
|
||||
|
||||
Reference in New Issue
Block a user