Skip to content

Commit 60ccfca

Browse files
authored
Merge pull request #2331 from bcgov/feature/doarSummary
Added the DOAR summary
2 parents 929d3da + 0f51162 commit 60ccfca

File tree

10 files changed

+200
-30
lines changed

10 files changed

+200
-30
lines changed

backend/src/components/assessments/assessments.js

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,18 @@
11
'use strict';
2-
const { logApiError, getAccessToken, getData, putData, postData, getCreateOrUpdateUserValue, getDataWithParams, handleExceptionResponse} = require('../utils');
2+
const {
3+
logApiError,
4+
getAccessToken,
5+
getData,
6+
putData,
7+
postData,
8+
getCreateOrUpdateUserValue,
9+
getDataWithParams,
10+
handleExceptionResponse
11+
} = require('../utils');
312
const HttpStatus = require('http-status-codes');
413
const config = require('../../config');
514
const cacheService = require('../cache-service');
6-
const { createMoreFiltersSearchCriteria } = require('./studentFilters');
15+
const {createMoreFiltersSearchCriteria} = require('./studentFilters');
716
const moment = require('moment');
817
const {DateTimeFormatter, LocalDate, LocalDateTime} = require('@js-joda/core');
918
const {FILTER_OPERATION, VALUE_TYPE, CONDITION} = require('../../util/constants');
@@ -95,7 +104,7 @@ async function getAssessmentStudentsPaginated(req, res) {
95104
};
96105

97106
const token = getAccessToken(req);
98-
let data = await getDataWithParams(token,`${config.get('assessments:assessmentStudentsURL')}/paginated`, params);
107+
let data = await getDataWithParams(token, `${config.get('assessments:assessmentStudentsURL')}/paginated`, params);
99108

100109
if (req?.query?.returnKey) {
101110
let result = data?.content.map((student) => student[req?.query?.returnKey]);
@@ -115,7 +124,7 @@ async function getAssessmentStudentsPaginated(req, res) {
115124
}
116125
}
117126

118-
async function postAssessmentStudent(req, res){
127+
async function postAssessmentStudent(req, res) {
119128
try {
120129
const payload = {
121130
...req.body,
@@ -133,9 +142,9 @@ async function postAssessmentStudent(req, res){
133142
}
134143

135144
async function getAssessmentStudentByID(req, res) {
136-
try {
145+
try {
137146
const token = getAccessToken(req);
138-
let assessmentStudent = getAssessmentStudent(req.params.assessmentStudentID, res, token, req.session?.correlationID);
147+
let assessmentStudent = await getAssessmentStudent(req.params.assessmentStudentID, res, token, req.session?.correlationID);
139148
return res.status(200).json(includeAssessmentStudentProps(assessmentStudent));
140149
} catch (e) {
141150
if (e?.status === 404) {
@@ -159,21 +168,21 @@ async function removeAssessmentStudents(req, res) {
159168
}
160169

161170
function includeAssessmentStudentProps(assessmentStudent) {
162-
if(assessmentStudent) {
171+
if (assessmentStudent) {
163172
let school = cacheService.getSchoolBySchoolID(assessmentStudent.schoolOfRecordSchoolID);
164173
let assessmentCenter = cacheService.getSchoolBySchoolID(assessmentStudent.assessmentCenterID);
165174

166-
if(school) {
175+
if (school) {
167176
assessmentStudent.schoolName_desc = getSchoolName(school);
168177
}
169-
170-
if(assessmentCenter) {
178+
179+
if (assessmentCenter) {
171180
assessmentStudent.assessmentCenterName_desc = getSchoolName(assessmentCenter);
172-
}
181+
}
173182

174183
assessmentStudent.assessmentTypeName_desc = assessmentStudent.assessmentTypeCode;
175184
assessmentStudent.provincialSpecialCaseName_desc = assessmentStudent.provincialSpecialCaseCode ? cacheService.getSpecialCaseTypeLabelByCode(assessmentStudent.provincialSpecialCaseCode) : null;
176-
assessmentStudent.sessionName_desc = moment(assessmentStudent.courseMonth, 'MM').format('MMMM') +' '+assessmentStudent.courseYear;
185+
assessmentStudent.sessionName_desc = moment(assessmentStudent.courseMonth, 'MM').format('MMMM') + ' ' + assessmentStudent.courseYear;
177186
}
178187
return assessmentStudent;
179188
}
@@ -187,7 +196,7 @@ async function updateAssessmentStudentByID(req, res) {
187196
try {
188197
const token = getAccessToken(req);
189198
const payload = req.body;
190-
payload.updateUser = getCreateOrUpdateUserValue(req);
199+
payload.updateUser = getCreateOrUpdateUserValue(req);
191200
payload.updateDate = null;
192201
payload.createDate = null;
193202
const result = await putData(token, payload, `${config.get('assessments:assessmentStudentsURL')}/${req.params.assessmentStudentID}`, getCreateOrUpdateUserValue(req));
@@ -250,7 +259,7 @@ function getSchoolName(school) {
250259
return school.mincode + ' - ' + school.schoolName;
251260
}
252261

253-
function getAssessmentSpecialCases(req, res) {
262+
function getAssessmentSpecialCases(req, res) {
254263
try {
255264
const codes = cacheService.getAllAssessmentSpecialCases();
256265
return res.status(HttpStatus.OK).json(Object.fromEntries(codes));

backend/src/validations/assessments.js

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
const { object, string, boolean, number, array } = require('yup');
22
const { baseRequestSchema } = require('./base');
33

4+
45
const putStudentAssessmentSchema = object({
56
body: object({
67
assessmentStudentID: string().nonNullable(),
78
sessionID:string().nonNullable(),
89
schoolOfRecordSchoolID: string().nonNullable(),
9-
assessmentCenterID: string().nonNullable(),
1010
assessmentID:string().nonNullable(),
1111
assessmentTypeCode: string().nonNullable(),
1212
studentID: string().nonNullable(),
1313
pen: string().max(9).nonNullable(),
14-
localID: string().max(12).nonNullable(),
14+
localID: string().max(12).nullable().optional(),
1515
givenName: string().max(25).nonNullable(),
1616
surname: string().max(25).nonNullable(),
1717
localCourseID: string().max(20).nullable().optional(),
@@ -20,6 +20,14 @@ const putStudentAssessmentSchema = object({
2020
provincialSpecialCaseCode: string().max(1).nullable().optional(),
2121
courseStatusCode: string().max(1).nullable().optional(),
2222
numberOfAttempts: number().nullable().optional(),
23+
schoolAtWriteSchoolID: string().nullable().optional(),
24+
assessmentCenterSchoolID: string().nullable().optional(),
25+
assessmentFormID: string().nullable().optional(),
26+
adaptedAssessmentCode: string().nullable().optional(),
27+
irtScore: number().nullable().optional(),
28+
localAssessmentID: string().nullable().optional(),
29+
markingSession: string().nullable().optional(),
30+
downloadDate: string().nullable().optional(),
2331
courseMonth: number().optional(),
2432
courseYear: number().optional(),
2533
assessmentStudentValidationIssues: array().of(object({
@@ -42,18 +50,25 @@ const postAssessmentStudentSchema = object({
4250
body: object({
4351
sessionID:string().nonNullable(),
4452
schoolOfRecordSchoolID: string().nonNullable(),
45-
assessmentCenterID: string().nonNullable(),
4653
assessmentID:string().nonNullable(),
4754
assessmentTypeCode: string().nonNullable(),
4855
studentID: string().nullable().optional(),
4956
assessmentStudentID: string().nullable().optional(),
5057
courseStatusCode: string().nullable().optional(),
5158
numberOfAttempts: string().nullable().optional(),
5259
pen: string().max(9).nonNullable(),
53-
localID: string().max(12).nonNullable(),
60+
localID: string().max(12).nullable().optional(),
5461
givenName: string().max(25).nonNullable(),
5562
surname: string().max(25).nonNullable(),
5663
isElectronicExam: boolean().nullable().optional(),
64+
schoolAtWriteSchoolID: string().nullable().optional(),
65+
assessmentCenterSchoolID: string().nullable().optional(),
66+
assessmentFormID: string().nullable().optional(),
67+
adaptedAssessmentCode: string().nullable().optional(),
68+
irtScore: number().nullable().optional(),
69+
localAssessmentID: string().nullable().optional(),
70+
markingSession: string().nullable().optional(),
71+
downloadDate: string().nullable().optional(),
5772
proficiencyScore: number().nullable().optional(),
5873
localCourseID: string().max(20).nullable().optional(),
5974
provincialSpecialCaseCode: string().max(1).nullable().optional(),

frontend/src/components/assessments/registrations/StudentRegistrations.vue

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,14 @@
2727
text="Add Registration"
2828
prepend-icon="mdi-plus"
2929
class="mr-1 mb-1"
30-
variant="outlined"
3130
@click="openCreateStudentRegDialog"
3231
/>
3332
<v-btn
3433
id="removeStudentReg"
3534
color="#003366"
3635
text="Remove Registration"
37-
prepend-icon="mdi-minus"
36+
variant="outlined"
37+
prepend-icon="mdi-trash-can-outline"
3838
class="mr-1 mb-1"
3939
:disabled="selectedAssessmentStudents.length <= 0"
4040
@click="removeStudents"
@@ -244,7 +244,7 @@ export default {
244244
}
245245
},
246246
getAssessmentStudents() {
247-
this.loading = true;
247+
this.isLoading = true;
248248
let sort = {assessmentStudentID: 'ASC',};
249249
let assessmentSearchParams = cloneDeep(this.filterSearchParams);
250250
if (! this.sessionID) {
@@ -279,7 +279,7 @@ export default {
279279
if (!confirmation) {
280280
return;
281281
}
282-
this.loading = true;
282+
this.isLoading = true;
283283
let payload = this.selectedAssessmentStudents.map(sas => sas.assessmentStudentID);
284284
ApiService.apiAxios.post(`${ApiRoutes.assessments.ASSESSMENT_REGISTRATIONS}/${this.userInfo.activeInstituteType.toLowerCase()}/students/remove`, payload)
285285
.then(() => {
@@ -290,7 +290,7 @@ export default {
290290
console.error(error);
291291
setFailureAlert(error?.response?.data?.message ? error?.response?.data?.message : 'An error occurred while trying to remove the registrations. Please try again later.');
292292
}).finally(() => {
293-
this.loading = false;
293+
this.isLoading = false;
294294
});
295295
},
296296
applyFilters($event) {

frontend/src/components/assessments/registrations/StudentRegistrationsCustomTable.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
{{ props.item['surname'] }}, {{ props.item['givenName'] }}
6969
</span>
7070
<span v-else-if="props.item[column.key]">{{ props.item[column.key] }}</span>
71+
<span v-else-if="column.key === 'select'"></span>
7172
<span v-else>-</span>
7273
</td>
7374
</tr>

frontend/src/components/assessments/registrations/forms/AddStudentRegistration.vue

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@
6161
variant="underlined"
6262
:maxlength="25"
6363
density="compact"
64-
:rules="[rules.required(), rules.number()]"
6564
/>
6665
</v-col>
6766
</v-row>
@@ -137,7 +136,7 @@
137136
<v-col>
138137
<v-autocomplete
139138
id="AssessmentCenter"
140-
v-model="newStudentDetail.assessmentCenterID"
139+
v-model="newStudentDetail.assessmentCenterSchoolID"
141140
variant="underlined"
142141
:items="assessmentCenterSearchNames"
143142
label="Assessment Center"
@@ -279,7 +278,7 @@ export default {
279278
newStudentDetail: {
280279
assessmentID: null,
281280
schoolOfRecordSchoolID: null,
282-
assessmentCenterID: null,
281+
assessmentCenterSchoolID: null,
283282
givenName: null,
284283
surname: null,
285284
pen: null,

frontend/src/components/assessments/registrations/forms/EditStudentRegistration.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@
105105
/>
106106
<v-autocomplete
107107
id="AssessmentCenter"
108-
v-model="assessmentStudentDetail.assessmentCenterID"
108+
v-model="assessmentStudentDetail.assessmentCenterSchoolID"
109109
variant="underlined"
110110
:items="assessmentCenterSearchNames"
111111
label="Assessment Center"

frontend/src/components/assessments/reports/AssessmentReports.vue

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,22 @@
215215
style="border: 1px solid black;border-radius: 10px;"
216216
>
217217
<v-card-title style="font-size: medium;">
218-
Distribution of Assessment Results (DOAR)
218+
<v-row>
219+
<v-col class="d-flex justify-start">
220+
Distribution of Assessment Results (DOAR)
221+
</v-col>
222+
<v-col class="d-flex justify-end mt-1">
223+
<v-icon
224+
aria-hidden="false"
225+
color="rgb(0, 51, 102)"
226+
style="cursor: pointer;"
227+
size="24"
228+
@click="openDOARSummaryHelp"
229+
>
230+
mdi-help-circle-outline
231+
</v-icon>
232+
</v-col>
233+
</v-row>
219234
</v-card-title>
220235
<v-row class="pl-3 pb-3">
221236
<v-col
@@ -348,6 +363,10 @@ export default {
348363
});
349364
this.schoolSearchNames = sortBy(this.schoolSearchNames, ['schoolCodeName']);
350365
},
366+
openDOARSummaryHelp() {
367+
const routeData = this.$router.resolve({name: 'doar-summary'});
368+
window.open(routeData.href, '_blank');
369+
},
351370
searchStudentForGivenPEN() {
352371
this.isSearchingStudent = true;
353372
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
2+
<template>
3+
<div class="assessment-report">
4+
<h2 class="justify-center text-center">Distribution of Assessment Results (DOAR) Summary - Report Description</h2>
5+
<h1>Description</h1>
6+
<p>
7+
This report lists the distribution of graduation assessment results for an assessment session for BC and Yukon.
8+
Specifically, the proportion of students achieving various assessment scores, and the number of participating students are listed.
9+
</p>
10+
11+
<h1>Included</h1>
12+
<ul>
13+
<li>The selected assessment session</li>
14+
<li>Provincial totals – all BC schools (both public and independent) and all Yukon public schools, except for Non-Independent First Nations schools.</li>
15+
<li>All Public totals – all public BC and Yukon schools, except for Non-Independent First Nations schools.</li>
16+
<li>District totals – public schools only. Within the District, except for Non-Independent First Nations schools.</li>
17+
</ul>
18+
19+
<h1>Excluded</h1>
20+
<ul>
21+
<li>Results for Aegrotats and Disqualifications</li>
22+
<li>Results where the student has exceeded the number of allowable writes for the assessment.</li>
23+
</ul>
24+
25+
<h1>Definitions</h1>
26+
<h1 style="font-size: 1.0em" class="mb-n1 mt-2">Proficiency Scores</h1>
27+
<ul>
28+
<li><strong>"1" = Emerging</strong></li>
29+
<li><strong>"2" = Developing</strong></li>
30+
<li><strong>"3" = Proficient</strong></li>
31+
<li><strong>"4" = Extending</strong></li>
32+
<li><strong>"NC" = Student did not complete enough of the assessment</strong></li>
33+
</ul>
34+
35+
<h1>School Types</h1>
36+
<p>
37+
<strong>Public School</strong> – A body of students, teachers, other staff, and facilities organized as a unit for educational purposes
38+
under the supervision of an administrative officer and administered by a district school board. This includes Online Learning Schools.
39+
</p>
40+
<p>
41+
<strong>Independent School</strong> – A school that is maintained and operated in British Columbia by an authority that provides an
42+
educational program to 10 or more school-aged students as outlined in the Independent School Act.
43+
</p>
44+
45+
<h1>Assessment Status</h1>
46+
<p>
47+
<strong>Aegrotat Standing</strong> - means the student has been excused from writing a Provincial Graduation Assessment due to
48+
unpredictable circumstances that render the student unable to write an assessment, even at a future session.
49+
</p>
50+
<p>
51+
<strong>Disqualification</strong> – an assessment is disqualified when the assessment rules are breached. No mark is given for the assessment.
52+
</p>
53+
54+
<h1>Notes</h1>
55+
<ul>
56+
<li>The numbers in this report may differ from previous reports for a particular session, due to updates of the data.</li>
57+
<li>If the report is for public use, a line of N/S means that less than 10 students were counted, or 100% of the students achieved the same assessment score.</li>
58+
</ul>
59+
60+
<h1>Explanations</h1>
61+
<ul>
62+
<li>All assessment results relate ONLY to the specific session shown at the top of the report</li>
63+
<li>These results do not include Aegrotats or Disqualifications.</li>
64+
<li>The Provincial results include all schools in BC and Yukon (both public and independent), except Non-Independent First Nations schools.</li>
65+
</ul>
66+
</div>
67+
</template>
68+
69+
<script>
70+
export default {
71+
name: 'DoarSummary',
72+
data() {
73+
return {
74+
// Component data can be added here if needed
75+
};
76+
}
77+
};
78+
</script>
79+
80+
<style scoped>
81+
.assessment-report {
82+
max-width: 80em;
83+
margin: 0 auto;
84+
padding: 1.25em;
85+
font-family: Arial, sans-serif;
86+
line-height: 1.6;
87+
}
88+
89+
h2{
90+
color: #34495e;
91+
}
92+
93+
h3 {
94+
color: #34495e;
95+
margin-top: 1.25em;
96+
margin-bottom: 0.625em;
97+
}
98+
99+
ul {
100+
margin: 0.625em 0;
101+
padding-left: 1.25em;
102+
}
103+
104+
li {
105+
margin: 0.3125em 0;
106+
}
107+
108+
p {
109+
margin: 0.625em 0;
110+
text-align: justify;
111+
}
112+
113+
strong {
114+
color: #2c3e50;
115+
}
116+
</style>

0 commit comments

Comments
 (0)