diff --git a/application/controllers/Cis/Benotungstool.php b/application/controllers/Cis/Benotungstool.php
index 81379b587..18038bb39 100644
--- a/application/controllers/Cis/Benotungstool.php
+++ b/application/controllers/Cis/Benotungstool.php
@@ -31,9 +31,17 @@ class Benotungstool extends Auth_Controller
// TODO: check if related CIS config is also loaded when being routed in Cis4 by vuerouter
// TODO: check if new benotungstool should be configurable the exact same way?
+
+
$viewData = array(
'uid'=>getAuthUID(),
- 'CIS_GESAMTNOTE_UEBERSCHREIBEN' => CIS_GESAMTNOTE_UEBERSCHREIBEN
+ 'CIS_GESAMTNOTE_UEBERSCHREIBEN' => CIS_GESAMTNOTE_UEBERSCHREIBEN,
+ 'CIS_GESAMTNOTE_PRUEFUNG_KOMMPRUEF' => CIS_GESAMTNOTE_PRUEFUNG_KOMMPRUEF,
+ 'CIS_GESAMTNOTE_PRUEFUNG_TERMIN3' => CIS_GESAMTNOTE_PRUEFUNG_TERMIN3,
+ 'CIS_GESAMTNOTE_PRUEFUNG_TERMIN2' => CIS_GESAMTNOTE_PRUEFUNG_TERMIN2,
+ 'CIS_GESAMTNOTE_PRUEFUNG_MOODLE_LE_NOTE' => CIS_GESAMTNOTE_PRUEFUNG_MOODLE_LE_NOTE,
+ 'CIS_GESAMTNOTE_PUNKTE' => CIS_GESAMTNOTE_PUNKTE,
+ 'CIS_GESAMTNOTE_GEWICHTUNG' => CIS_GESAMTNOTE_GEWICHTUNG
);
$this->load->view('CisRouterView/CisRouterView.php', ['viewData' => $viewData, 'route' => 'Benotungstool']);
diff --git a/application/controllers/api/frontend/v1/Noten.php b/application/controllers/api/frontend/v1/Noten.php
index 290105cdf..c106b204f 100644
--- a/application/controllers/api/frontend/v1/Noten.php
+++ b/application/controllers/api/frontend/v1/Noten.php
@@ -35,7 +35,8 @@ class Noten extends FHCAPI_Controller
'getNotenvorschlagStudent' => self::PERM_LOGGED,
'saveNotenvorschlag' => self::PERM_LOGGED,
'saveStudentPruefung' => self::PERM_LOGGED,
- 'createPruefungen' => self::PERM_LOGGED
+ 'createPruefungen' => self::PERM_LOGGED,
+ 'saveNotenvorschlagBulk' => self::PERM_LOGGED
]);
$this->load->library('AuthLib', null, 'AuthLib');
@@ -108,6 +109,8 @@ class Noten extends FHCAPI_Controller
}
// send $grades reference to moodle addon
+
+ // TODO: event getExterneNoten
Events::trigger(
'moodleGrades',
function & () use (&$grades)
@@ -556,6 +559,72 @@ class Noten extends FHCAPI_Controller
$this->terminateWithSuccess(array($ret, $lvgesamtnote));
}
+
+ public function saveNotenvorschlagBulk() {
+ $result = $this->getPostJSON();
+
+ if(!property_exists($result, 'lv_id') || !property_exists($result, 'sem_kurzbz') ||
+ !property_exists($result, 'noten')) {
+ $this->terminateWithError($this->p->t('global', 'missingParameters'), 'general');
+ }
+
+ $lv_id = $result->lv_id;
+ $sem_kurzbz = $result->sem_kurzbz;
+ $noten = $result->noten;
+
+ $retLvNoten = [];
+ $responseMsgs = [];
+
+ foreach($noten as $note)
+ {
+ $lvgesamtnote = new lvgesamtnote();
+ if (!$lvgesamtnote->load($lv_id, $note->uid, $sem_kurzbz))
+ {
+ $lvgesamtnote->student_uid = $note->uid;
+ $lvgesamtnote->lehrveranstaltung_id = $lv_id;
+ $lvgesamtnote->studiensemester_kurzbz = $sem_kurzbz;
+ $lvgesamtnote->note = trim($note->note);
+ $lvgesamtnote->mitarbeiter_uid = getAuthUID();
+ $lvgesamtnote->benotungsdatum = date("Y-m-d H:i:s");
+ $lvgesamtnote->freigabedatum = null;
+ $lvgesamtnote->freigabevon_uid = null;
+ $lvgesamtnote->bemerkung = null;
+ $lvgesamtnote->updateamum = null;
+ $lvgesamtnote->updatevon = null;
+ $lvgesamtnote->insertamum = date("Y-m-d H:i:s");
+ $lvgesamtnote->insertvon = getAuthUID();
+ $lvgesamtnote->punkte =// TODO: deprecated?
+ $new = true;
+ $response = "neu";
+ }
+ else
+ {
+ $lvgesamtnote->note = trim($note->note);
+ $lvgesamtnote->punkte = null; // TODO: deprecated?
+ $lvgesamtnote->benotungsdatum = date("Y-m-d H:i:s");
+ $lvgesamtnote->updateamum = date("Y-m-d H:i:s");
+ $lvgesamtnote->updatevon = getAuthUID();
+ $new = false;
+ if ($lvgesamtnote->freigabedatum)
+ $response = "update_f";
+ else
+ $response = "update";
+ }
+
+ if (!$lvgesamtnote->save($new))
+ $responseMsgs[] = $lvgesamtnote->errormsg;
+ else
+ $responseMsgs[] = $response;
+
+
+ $lvgesamtnote->load($lv_id, $note->uid, $sem_kurzbz);
+
+ $retLvNoten[] = $lvgesamtnote;
+ }
+
+ $this->terminateWithSuccess(array($retLvNoten, $responseMsgs));
+
+ }
public function createPruefungen() {
$result = $this->getPostJSON();
diff --git a/application/views/CisRouterView/CisRouterView.php b/application/views/CisRouterView/CisRouterView.php
index b58490094..d45ec0951 100644
--- a/application/views/CisRouterView/CisRouterView.php
+++ b/application/views/CisRouterView/CisRouterView.php
@@ -26,7 +26,8 @@ $includesArray = array(
'vendor/npm-asset/primevue/accordion/accordion.js',
'vendor/npm-asset/primevue/accordiontab/accordiontab.js',
'vendor/npm-asset/primevue/password/password.js',
- 'vendor/npm-asset/primevue/multiselect/multiselect.js'
+ 'vendor/npm-asset/primevue/multiselect/multiselect.js',
+ 'vendor/npm-asset/primevue/textarea/textarea.js'
),
'customJSModules' => array(
'public/js/apps/Dashboard/Fhc.js'
diff --git a/public/js/api/factory/noten.js b/public/js/api/factory/noten.js
index b62ba1fe1..e472f9a98 100644
--- a/public/js/api/factory/noten.js
+++ b/public/js/api/factory/noten.js
@@ -57,4 +57,14 @@ export default {
params: { uids, datum, lva_id, sem_kurzbz }
};
},
+ saveNotenvorschlagBulk(lv_id, sem_kurzbz, noten) {
+ return {
+ method: 'post',
+ url: '/api/frontend/v1/Noten/saveNotenvorschlagBulk',
+ params: { lv_id, sem_kurzbz, noten }
+ };
+ },
+ saveStudentPruefungBulk(lv_id, sem_kurzbz, pruefungen) {
+
+ }
};
\ No newline at end of file
diff --git a/public/js/components/Cis/Benotungstool/Benotungstool.js b/public/js/components/Cis/Benotungstool/Benotungstool.js
index cbc73415c..50b7ec676 100644
--- a/public/js/components/Cis/Benotungstool/Benotungstool.js
+++ b/public/js/components/Cis/Benotungstool/Benotungstool.js
@@ -12,6 +12,7 @@ export const Benotungstool = {
CoreFilterCmpt,
Dropdown: primevue.dropdown,
Password: primevue.password,
+ Textarea: primevue.textarea,
Datepicker: VueDatePicker,
Multiselect: primevue.multiselect
},
@@ -49,6 +50,7 @@ export const Benotungstool = {
changedNotenCounter: 0,
tabulatorUuid: Vue.ref(0),
domain: '',
+ importString: '',
teilnoten: null,
lv: null,
studenten: null,
@@ -107,6 +109,102 @@ export const Benotungstool = {
]};
},
methods: {
+ parseNote(rowParts, notenbulk) {
+ const uid = rowParts[0]
+
+ const student = this.studenten.find(s => s.uid === uid)
+ if(!student) return
+
+ const note = rowParts[1]
+
+ // find notenoption and check if its allowed to use in lehre
+ const notenOption = this.notenOptions.find(n => n.note == note)
+ if(!notenOption.lehre) return
+
+ notenbulk.push({uid, note})
+ },
+ parsePruefung(rowParts, notenbulk) {
+ const uid = rowParts[0]
+
+ const student = this.studenten.find(s => s.uid === uid)
+ if(!student) return
+
+ const datum = rowParts[1] // should be in 'YYYY.MM.DD'
+ const datumObj = datum
+
+ const year = datumObj.getFullYear();
+ const month = String(datumObj.getMonth() + 1).padStart(2, '0'); // Months are 0-based
+ const day = String(datumObj.getDate()).padStart(2, '0');
+ const dateStr = `${year}-${month}-${day}`
+
+ const note = rowParts[2]
+
+ // find notenoption and check if its allowed to use in lehre
+ const notenOption = this.notenOptions.find(n => n.note == note)
+ if(!notenOption.lehre) return
+ },
+ saveNotenBulk(notenbulk) {
+ this.$api.call(ApiNoten.saveNotenvorschlagBulk(this.lv_id, this.sem_kurzbz, notenbulk)).then(res => {
+ console.log(res)
+ if(res.meta.status === 'success') {
+ const lvNoten = res.data[0]
+
+ lvNoten.forEach(lvn => {
+ // 1.) get relevant student row by uid
+ const s = this.studenten.find(s => s.uid === lvn.uid)
+ s.note_vorschlag = lvn.note // TODO: check if note_vorschlag should be changed by import
+
+ this.teilnoten[s.uid].note_lv = lvn.note
+ s.freigabedatum = this.parseDate(lvn['freigabedatum'])
+ s.benotungsdatum = this.parseDate(lvn['benotungsdatum'])
+
+ s.freigegeben = this.checkFreigabe(s.freigabedatum, s.benotungsdatum, s.uid);
+ })
+
+ }
+
+ // 2.) set note_vorschlag field
+
+ // 4.) update rows with note_lv = note_vorschlag & recalculate freigabestatus
+ })
+ },
+ savePruefungBulk(pruefungenbulk) {
+ this.$api.call(ApiNoten.saveStudentPruefungBulk(this.lv_id, this.sem_kurzbz, pruefungenbulk))
+ .then((res)=> {
+ if(res.meta.status === 'success') {
+
+
+
+
+ this.$fhcAlert.alertInfo('Prüfungen gespeichert') // TODO: phrase
+ }
+ })
+ },
+ importNoten() {
+ console.log('importNoten', this.importString)
+
+ // TODO: check for signs of notenimport or pruefung import
+
+ const rows = this.importString.split('\n')
+ const bulk = []
+ let mode = ''
+ // read the lines
+ rows.forEach(r => {
+ const rowParts = r.split('\t')
+ if(rowParts.length === 3) {
+ this.parsePruefung(rowParts, bulk)
+ mode = 'pruefung' // if line parts are not uniform we are in trouble
+ } else if(rowParts.length === 2) {
+ this.parseNote(rowParts, bulk)
+ mode = 'note'
+ }
+ })
+
+ if(mode === 'note') this.saveNotenBulk(bulk)
+ else if (mode === 'pruefung') this.savePruefungBulk(bulk)
+
+ this.$refs.modalContainerNotenImport.hide()
+ },
selectionArraysAreEqual(arr1, arr2) {
if(arr1.length !== arr2.length) return false
@@ -408,7 +506,7 @@ export const Benotungstool = {
const date = `${dateParts[2]}.${dateParts[1]}.${dateParts[0]}`
// First column (date)
- rowDiv.appendChild(createCol(date, 'col-4 d-flex align-items-center'));
+ rowDiv.appendChild(createCol(date, 'col-4 d-flex justify-content-center align-items-center'));
const noteDefEntry = data.note ? this.notenOptions.find(n => n.note == data[field].note) : null
@@ -418,7 +516,7 @@ export const Benotungstool = {
// no actions on kommPruef allowed
// no actions on termin1 aka pruefung 0 aka ursprüngliche note erlaubt
if(field === 'kommPruef' || colDef.originalNote) {
- rowDiv.appendChild(createCol('', 'col-4 d-flex justify-content-center align-items-center')); // append empty col4 to have formatting similar
+ // rowDiv.appendChild(createCol('', 'col-4 d-flex justify-content-center align-items-center')); // append empty col4 to have formatting similar
return rowDiv
}
@@ -450,17 +548,22 @@ export const Benotungstool = {
openPruefungModal(student, pruefung = null, field) {
this.pruefungStudent = student
this.pruefung = pruefung
-
const dateStr = this.pruefung?.datum ?? field
const pruefungDateParts = dateStr.split('-')
+
+ // does not work correctly
// new date obj so datepicker picks ob the change by ref
- const newDate = new Date()
- newDate.setFullYear(pruefungDateParts[0])
- newDate.setMonth(pruefungDateParts[1])
- newDate.setMonth(newDate.getMonth() - 1) // acount for js date month offset
- newDate.setDate(pruefungDateParts[2])
+ // const newDate = new Date()
+ // newDate.setFullYear(+pruefungDateParts[0])
+ // newDate.setMonth(+pruefungDateParts[1])
+ // // newDate.setMonth(newDate.getMonth() - 1) // acount for js date month offset
+ // newDate.setDate(+pruefungDateParts[2])
+
+ // works correctly
+ const newDate = new Date(+pruefungDateParts[0], +pruefungDateParts[1], +pruefungDateParts[2])
+ newDate.setMonth(newDate.getMonth() - 1)
this.selectedPruefungDate = newDate
@@ -1037,6 +1140,9 @@ export const Benotungstool = {
openNewPruefungsdatumModal() {
this.$refs.modalContainerNeuesPruefungsdatum.show()
},
+ openNotenImportModal() {
+ this.$refs.modalContainerNotenImport.show()
+ },
getOptionLabelNotePruefung(option) {
return option.bezeichnung
},
@@ -1233,12 +1339,13 @@ export const Benotungstool = {
return counter
},
getSaveBtnClass() {
- // return "btn btn-primary ml-2"
return this.changedNoten?.length ? "btn btn-primary ml-2" : "btn btn-secondary ml-2"
},
getNewBtnClass() {
return "btn btn-primary ml-2"
- // return !this.changedData.length ? "btn btn-secondary ml-2" : "btn btn-primary ml-2"
+ },
+ getNotenImportBtnClass() {
+ return "btn btn-primary ml-2"
},
changedNoten() {
const v = this.changedNotenCounter // hack to trigger computed
@@ -1259,6 +1366,19 @@ export const Benotungstool = {
this.setupMounted()
},
template: `
+
+ {{$p.t('benotungstool/c4notenImportieren')}}
+
+
+
+
+
+
+
+
+
+
+
{{$p.t('benotungstool/c4addNewPruefung')}}
@@ -1408,6 +1528,9 @@ export const Benotungstool = {
+
diff --git a/system/phrasesupdate.php b/system/phrasesupdate.php
index 5cfa302cd..f85bded48 100644
--- a/system/phrasesupdate.php
+++ b/system/phrasesupdate.php
@@ -42036,6 +42036,46 @@ and represent the current state of research on the topic. The prescribed citatio
)
)
),
+ array(
+ 'app' => 'core',
+ 'category' => 'benotungstool',
+ 'phrase' => 'c4notenImportieren',
+ 'insertvon' => 'system',
+ 'phrases' => array(
+ array(
+ 'sprache' => 'German',
+ 'text' => 'Noten Import',
+ 'description' => '',
+ 'insertvon' => 'system'
+ ),
+ array(
+ 'sprache' => 'English',
+ 'text' => 'Import Grades',
+ 'description' => '',
+ 'insertvon' => 'system'
+ )
+ )
+ ),
+ array(
+ 'app' => 'core',
+ 'category' => 'benotungstool',
+ 'phrase' => 'c4import',
+ 'insertvon' => 'system',
+ 'phrases' => array(
+ array(
+ 'sprache' => 'German',
+ 'text' => 'Importieren',
+ 'description' => '',
+ 'insertvon' => 'system'
+ ),
+ array(
+ 'sprache' => 'English',
+ 'text' => 'Import',
+ 'description' => '',
+ 'insertvon' => 'system'
+ )
+ )
+ ),
array(
'app' => 'core',
'category' => 'benotungstool',