diff --git a/api/app/resources/bookings/exam/exam_export_list.py b/api/app/resources/bookings/exam/exam_export_list.py
index 8ac8b209e..ee488eee2 100644
--- a/api/app/resources/bookings/exam/exam_export_list.py
+++ b/api/app/resources/bookings/exam/exam_export_list.py
@@ -37,8 +37,11 @@ class ExamList(Resource):
def get(self):
try:
+
csr = CSR.find_by_username(g.oidc_token_info['username'])
+ is_designate = csr.finance_designate
+
start_param = request.args.get("start_date")
end_param = request.args.get("end_date")
exam_type = request.args.get("exam_type")
@@ -59,8 +62,7 @@ def get(self):
end_date = self.timezone.localize(end_date)
- exams = Exam.query.filter_by(office_id=csr.office_id) \
- .join(Booking, Exam.booking_id == Booking.booking_id) \
+ exams = Exam.query.join(Booking, Exam.booking_id == Booking.booking_id) \
.filter(Booking.start_time >= start_date) \
.filter(Booking.start_time < end_date) \
.join(Invigilator, Booking.invigilator_id == Invigilator.invigilator_id, isouter=True) \
@@ -68,6 +70,9 @@ def get(self):
.join(Office, Booking.office_id == Office.office_id) \
.join(ExamType, Exam.exam_type_id == ExamType.exam_type_id)
+ if not is_designate:
+ exams = exams.filter(Booking.office_id == csr.office_id)
+
if exam_type == 'ita':
exams = exams.filter(ExamType.ita_ind == 1)
elif exam_type == 'all_non_ita':
@@ -160,10 +165,10 @@ def get(self):
def write_room(row, exam):
- if exam.exam_type.group_exam_ind == 1:
- row.append("")
- else:
+ if exam.booking and exam.booking.room:
row.append(exam.booking.room.room_name)
+ else:
+ row.append("")
def write_invigilator(row, exam):
diff --git a/api/app/resources/theq/csrs.py b/api/app/resources/theq/csrs.py
index 55c40b10c..dfbfe9293 100644
--- a/api/app/resources/theq/csrs.py
+++ b/api/app/resources/theq/csrs.py
@@ -89,7 +89,8 @@ def get(self):
.join(ExamType, Exam.exam_type_id == ExamType.exam_type_id) \
.filter(ExamType.group_exam_ind == 1) \
.join(Booking, Exam.booking_id == Booking.booking_id) \
- .filter(Booking.invigilator_id.is_(None)).count()
+ .filter(Booking.invigilator_id.is_(None))\
+ .filter(Booking.sbc_staff_invigilated == 0).count()
result = self.csr_schema.dump(csr)
active_citizens = self.citizen_schema.dump(active_citizens)
diff --git a/frontend/src/booking/scheduling-indicator.vue b/frontend/src/booking/scheduling-indicator.vue
index c21a11f50..ac27a31f6 100644
--- a/frontend/src/booking/scheduling-indicator.vue
+++ b/frontend/src/booking/scheduling-indicator.vue
@@ -74,7 +74,7 @@
return
}
let pushToExams = false
- if (this.selectedExam && this.selectedExam.referrer === 'scheduling') {
+ if (this.selectedExam && this.selectedExam.referrer === 'inventory') {
pushToExams = true
}
this.finishBooking()
diff --git a/frontend/src/exams/add-exam-form-confirm.vue b/frontend/src/exams/add-exam-form-confirm.vue
index 3581dec8d..0439b6106 100644
--- a/frontend/src/exams/add-exam-form-confirm.vue
+++ b/frontend/src/exams/add-exam-form-confirm.vue
@@ -75,10 +75,10 @@
- {{ exam.exam_received_date }}
+ {{ formatDate(exam.exam_received_date) }}
- {{ exam.exam_received_date }}
+ {{ formatDate(exam.exam_received_date) }}
Not Yet Received
diff --git a/frontend/src/exams/edit-exam-form-modal.vue b/frontend/src/exams/edit-exam-form-modal.vue
index f5aae7fce..71859965b 100644
--- a/frontend/src/exams/edit-exam-form-modal.vue
+++ b/frontend/src/exams/edit-exam-form-modal.vue
@@ -9,10 +9,13 @@
Edit Exam Details
+
+
+
@@ -23,6 +26,7 @@
v-model="fields.event_id" />
+
@@ -33,6 +37,7 @@
+
@@ -68,6 +73,7 @@
+
@@ -79,7 +85,8 @@
-
+
+
@@ -90,18 +97,22 @@
:options="examReceivedOptions" />
+
+ class="w-100 my-0 less-10-mb">
+
@@ -109,14 +120,17 @@
id="number_of_students" />
+
+ class="w-100 less-10-mb">
+
@@ -137,6 +152,7 @@
+
@@ -146,6 +162,7 @@
+
@@ -177,6 +194,7 @@
+
@@ -188,11 +206,14 @@
v-model="exam_received" />
+
+
@@ -209,20 +231,22 @@
+
{{ this.message }}
+
Delete Exam
Cancel
-
Submit
-
Submit
@@ -274,7 +298,62 @@
'examTypes',
'offices',
'showEditExamModal',
- 'showDeleteExamModal', ]),
+ 'showDeleteExamModal',
+ 'user', ]),
+ fieldsEdited() {
+ let fieldsEdited = []
+ let data = Object.assign({}, this.fields)
+ if (data.exam_received_date) {
+ data.exam_received_date = moment(data.exam_received_date).utc().format('YYYY-MM-DD[T]HH:mm:ssZ')
+ }
+ if (data.expiry_date) {
+ data.expiry_date = moment(data.expiry_date).utc().format('YYYY-MM-DD[T]HH:mm:ssZ')
+ }
+ for (let key in data) {
+ if (data[key] != this.actionedExam[key]) {
+ fieldsEdited.push(key)
+ }
+ }
+ if (fieldsEdited.length === 1 && fieldsEdited.includes('notes')) {
+ if (!data.notes && !this.actionedExam.notes) {
+ return false
+ }
+ }
+ return fieldsEdited
+ },
+ allowSubmit() {
+ if (this.actionedExam) {
+ let fieldsEdited = []
+ let data = Object.assign({}, this.fields)
+ if (data.exam_received_date) {
+ data.exam_received_date = moment(data.exam_received_date).utc().format('YYYY-MM-DD[T]HH:mm:ssZ')
+ }
+ if (data.expiry_date) {
+ data.expiry_date = moment(data.expiry_date).utc().format('YYYY-MM-DD[T]HH:mm:ssZ')
+ }
+ for (let key in data) {
+ if (data[key] != this.actionedExam[key]) {
+ fieldsEdited.push(key)
+ }
+ }
+ if (fieldsEdited.length === 1 && fieldsEdited.includes('notes')) {
+ if (!data.notes && !this.actionedExam.notes) {
+ return false
+ }
+ }
+ return (fieldsEdited.length > 0)
+ }
+ return false
+ },
+ otherOfficeExam() {
+ if (!this.is_liaison_designate) {
+ return false
+ }
+ if (this.actionedExam && this.actionedExam.office_id != this.user.office_id) {
+ return true
+ }
+ return false
+ },
exam() {
if (Object.keys(this.actionedExam).length > 0) {
return this.actionedExam
@@ -365,7 +444,7 @@
set(e) {
this.toggleEditExamModal(e)
}
- }
+ },
},
methods: {
...mapActions(['getBookings', 'getExams', 'getOffices', 'putExamInfo',]),
@@ -385,26 +464,8 @@
date
)
},
- allowSubmit() {
- if (this.actionedExam) {
- let fieldsEdited = false
- let fields = Object.keys(this.fields)
- for (let key of fields) {
- if (this.fields[key] != this.actionedExam[key]) {
- fieldsEdited = true
- this.showMessage = false
- break
- }
- }
- return fieldsEdited
- }
- return false
- },
isITAGropOrSingleExam(ex) {
- if (ex.exam_type.group_exam_ind || ex.exam_type.exam_type_name.includes('Single') ) {
- return true
- }
- return false
+ return ex.exam_type.ita_ind ? true : false
},
deleteExam() {
let deleteExamInfo = {}
@@ -416,7 +477,7 @@
examinee_name: this.fields.examinee_name,
event_id: this.fields.event_id,
}
- }else {
+ } else {
deleteExamInfo = {
booking_id: null,
exam_id: this.fields.exam_id,
@@ -440,7 +501,7 @@
},
populateForm() {
let exam = this.actionedExam
- Object.keys(this.actionedExam).forEach( key => {
+ Object.keys(exam).forEach( key => {
if (typeof exam[key] === 'string' || typeof exam[key] === 'number') {
Vue.set(
this.fields,
@@ -449,10 +510,14 @@
)
}
})
- this.office_number = exam.office.office_number
- if (exam.exam_received_date) {
+ if (exam.expiry_date) {
+ this.fields.expiry_date = new moment(exam.expiry_date).format('YYYY-MM-DD')
+ }
+ if (exam.exam_received_date && moment().isValid(exam.exam_received_date)) {
+ this.fields.exam_received_date = new moment(exam.exam_received_date).format('YYYY-MM-DD')
this.exam_received = true
}
+ this.office_number = exam.office.office_number
},
setOffice(officeNumber) {
this.office_number = officeNumber
@@ -477,7 +542,7 @@
this.resetExam()
},
setMessage() {
- if (!this.allowSubmit()) {
+ if (!this.allowSubmit) {
if (!this.fields.office_id) {
this.message = 'Please specify a valid office.'
} else {
@@ -487,15 +552,22 @@
}
},
submit() {
+ let data = Object.assign({}, this.fields)
let putRequest = {
exam_id: this.fields.exam_id
}
- Object.keys(this.fields).forEach( key => {
- if (this.fields[key] != this.actionedExam[key]) {
- putRequest[key] = this.fields[key]
+ if (data.exam_received_date) {
+ data.exam_received_date = moment(data.exam_received_date).utc().format('YYYY-MM-DD[T]HH:mm:ssZ')
+ }
+ if (data.expiry_date) {
+ data.expiry_date = moment(data.expiry_date).utc().format('YYYY-MM-DD[T]HH:mm:ssZ')
+ }
+ Object.keys(data).forEach( key => {
+ if (data[key] != this.actionedExam[key]) {
+ putRequest[key] = data[key]
}
})
- if (!this.exam_received && this.actionedExam.exam_received_date) {
+ if (!this.exam_received) {
putRequest['exam_received_date'] = null
}
this.putExamInfo(putRequest).then( () => {
@@ -507,11 +579,11 @@
updateExamReceived(e) {
let { exam_received_date } = this.fields
if (e && !exam_received_date) {
- this.fields['exam_received_date'] = new moment().format('YYYY-MM-DD[T]hh:mm:ssZ')
+ this.fields.exam_received_date = new moment().format('YYYY-MM-DD')
return
}
- if (!e && exam_received_date) {
- this.fields['exam_received_date'] = null
+ if (!e) {
+ this.fields.exam_received_date = null
}
}
},
diff --git a/frontend/src/exams/exam-inventory-table.vue b/frontend/src/exams/exam-inventory-table.vue
index f19668305..19ca92899 100644
--- a/frontend/src/exams/exam-inventory-table.vue
+++ b/frontend/src/exams/exam-inventory-table.vue
@@ -20,7 +20,7 @@
This Office
+ @click="setHomeOffice">This Office
Ok
@@ -643,6 +643,10 @@
setOfficeFilter(office_number) {
this.setFilter({type:'office_number', value: office_number})
},
+ setHomeOffice() {
+ this.setFilter({type: 'office_number', value: 'default'})
+ this.officeFilterModal = false
+ },
sortCompare(a, b, key) {
if (key === 'scheduled') {
let val1, val2
diff --git a/frontend/src/layout/nav.vue b/frontend/src/layout/nav.vue
index 9fa91cf63..3b83842cb 100644
--- a/frontend/src/layout/nav.vue
+++ b/frontend/src/layout/nav.vue
@@ -34,7 +34,7 @@
style="flex-grow: 8"
class="q-inline-title">{{ calendarSetup.title }}
-
+
-
-
+
+
diff --git a/frontend/src/store/index.js b/frontend/src/store/index.js
index de94683e3..79baa92c2 100644
--- a/frontend/src/store/index.js
+++ b/frontend/src/store/index.js
@@ -49,7 +49,6 @@ export const store = new Vuex.Store({
priority: 2
},
addModalSetup: null,
- nonITAExam: false,
addNextService: false,
adminNavigation: 'csr',
appointmentsStateInfo: {
@@ -82,24 +81,19 @@ export const store = new Vuex.Store({
dismissCount: 0,
editedBooking: null,
editedBookingOriginal: null,
- editExamFailureCount: 0,
editedGroupBooking: null,
+ editExamFailureCount: 0,
editExamSuccessCount: 0,
examAlertMessage: '',
- loginAlertMessage: '',
- examEditSuccessMessage: '',
- examEditFailureMessage: '',
examDismissCount: 0,
- loginDismissCount: 0,
+ examEditFailureMessage: '',
+ examEditSuccessMessage: '',
+ exams: [],
examsTrackingIP: false,
examSuccessDismiss : 0,
- exams: [],
examTypes: [],
feedbackMessage: '',
- showGenFinReportModal: false,
iframeLogedIn: false,
- invigilators: [],
- isLoggedIn: false,
inventoryFilters: {
expiryFilter: 'current',
scheduledFilter: 'both',
@@ -107,16 +101,21 @@ export const store = new Vuex.Store({
returnedFilter: 'unreturned',
office_number: 'default',
},
+ invigilators: [],
+ isLoggedIn: false,
+ loginAlertMessage: '',
+ loginDismissCount: 0,
+ nonITAExam: false,
nowServing: false,
- offices: [],
officeFilter: null,
+ offices: [],
officeType: null,
offsiteVisible: true,
performingAction: false,
rescheduling: false,
returnExam: null,
- rooms: [],
roomResources: [],
+ rooms: [],
scheduling: false,
selectedExam: {},
selectedOffice: {},
@@ -140,16 +139,17 @@ export const store = new Vuex.Store({
showBookingModal: false,
showDeleteExamModal: false,
showEditBookingModal: false,
- showEditGroupBookingModal: false,
showEditExamModal: false,
+ showEditGroupBookingModal: false,
showExamInventoryModal: false,
showFeedbackModal: false,
showGAScreenModal: false,
- showSelectInvigilatorModal: false,
- showServeCitizenSpinner: false,
+ showGenFinReportModal: false,
showOtherBookingModal: false,
showResponseModal: false,
showReturnExamModal: false,
+ showSelectInvigilatorModal: false,
+ showServeCitizenSpinner: false,
showServiceModal: false,
user: {
csr_id: null,
@@ -968,6 +968,7 @@ export const store = new Vuex.Store({
},
clickBeginService(context, payload) {
+ context.commit('toggleServeCitizenSpinner', true)
let { citizen_id } = context.getters.form_data.citizen
context.commit('setPerformingAction', true)
@@ -1132,6 +1133,7 @@ export const store = new Vuex.Store({
},
clickInvite(context) {
+ context.commit('toggleServeCitizenSpinner', true)
context.commit('setPerformingAction', true)
context.dispatch('postInvite', 'next').then(() => {
@@ -1235,6 +1237,7 @@ export const store = new Vuex.Store({
},
clickRowHoldQueue(context, citizen_id) {
+ context.commit('toggleServeCitizenSpinner', true)
context.commit('setPerformingAction', true)
context.dispatch('postBeginService', citizen_id).then( () => {
@@ -1245,7 +1248,7 @@ export const store = new Vuex.Store({
context.commit('setPerformingAction', false)
})
},
-
+
toggleBegunStatus({commit}) {
commit('toggleBegunStatus', payload)
},
@@ -1649,16 +1652,16 @@ export const store = new Vuex.Store({
}
delete responses.on_or_off
}
-
+ responses.office_id = responses.office_id ? responses.office_id : context.state.user.office_id
let defaultValues = {
exam_returned_ind: 0,
- number_of_students: 1,
- office_id: context.state.user.office_id
+ number_of_students: 1
}
- if (context.state.addExamModal.setup === 'pesticide') {
- defaultValues.office_id = responses['office_id']
+ let exp = new moment(responses.expiry_date).format('YYYY-MM-DD').toString()
+ responses.expiry_date = new moment(exp).utc().format('YYYY-MM-DD[T]HH:mm:ssZ')
+ if (responses.exam_received_date) {
+ responses.exam_received_date = new moment(responses.exam_received_date).utc().format('YYYY-MM-DD[T]HH:mm:ssZ')
}
- responses.expiry_date = moment(responses.expiry_date).format('YYYY-MM-DD')
if (responses.notes === null) {
responses.notes = ''
}
@@ -2409,6 +2412,8 @@ export const store = new Vuex.Store({
clearAddExamModalFromCalendarStatus: state => Vue.delete(state.addExamModal, 'fromCalendar'),
- toggleServeCitizenSpinner: (state, payload) => state.showServeCitizenSpinner = payload,
+ toggleServeCitizenSpinner(state, payload) {
+ state.showServeCitizenSpinner = payload
+ },
}
})