From 006a763436e63b1d8639274f4b34259e7c7302ed Mon Sep 17 00:00:00 2001 From: cgfhtw Date: Tue, 16 Apr 2024 14:34:45 +0200 Subject: [PATCH 1/2] Konto delete --- .../controllers/api/frontend/v1/stv/Konto.php | 62 ++++++++++++++++--- public/js/api/stv/konto.js | 3 + .../Stv/Studentenverwaltung/Details/Konto.js | 16 ++++- system/phrasesupdate.php | 20 ++++++ 4 files changed, 93 insertions(+), 8 deletions(-) diff --git a/application/controllers/api/frontend/v1/stv/Konto.php b/application/controllers/api/frontend/v1/stv/Konto.php index 12892d2f7..1f6b963bb 100644 --- a/application/controllers/api/frontend/v1/stv/Konto.php +++ b/application/controllers/api/frontend/v1/stv/Konto.php @@ -39,7 +39,8 @@ class Konto extends FHCAPI_Controller 'getBuchungstypen' => 'student/stammdaten:r', // alle? 'checkDoubles' => ['admin:r', 'assistenz:r'], 'insert' => ['admin:w', 'assistenz:w'], - 'update' => ['admin:w', 'assistenz:w'] + 'update' => ['admin:w', 'assistenz:w'], + 'delete' => ['admin:w', 'assistenz:w'] ]); // Load models @@ -64,11 +65,12 @@ class Konto extends FHCAPI_Controller $this->load->library('form_validation'); $person_id = $this->input->post('person_id'); - if (!$person_id || !is_array($person_id)) + if (!$person_id || !is_array($person_id)) { $this->form_validation->set_rules('person_id', 'Person ID', 'required'); - if (!$this->form_validation->run()) - $this->terminateWithValidationErrors($this->form_validation->error_array()); + if (!$this->form_validation->run()) + $this->terminateWithValidationErrors($this->form_validation->error_array()); + } $studiengang_kz = $this->input->post('studiengang_kz'); @@ -251,14 +253,14 @@ class Konto extends FHCAPI_Controller $result = []; foreach ($person_ids as $person_id) { $id = $this->KontoModel->insert(array_merge($data, ['person_id' => $person_id])); - if (isError($id)) + if (isError($id)) { $this->addError(getError($id), self::ERROR_TYPE_GENERAL); - else { + } else { $data = $this->KontoModel->withAdditionalInfo()->load(getData($id)); if (isError($data)) $this->addError(getError($data), self::ERROR_TYPE_GENERAL); else - $result[] = getData($data); + $result[] = current(getData($data)); } } @@ -327,4 +329,50 @@ class Konto extends FHCAPI_Controller $this->terminateWithSuccess($result); } + + /** + * Delete Buchung + * + * @return void + */ + public function delete() + { + $this->load->library('form_validation'); + + $this->form_validation->set_rules('buchungsnr', 'Buchungsnr', 'required'); + + if (!$this->form_validation->run()) + $this->terminateWithValidationErrors($this->form_validation->error_array()); + + + $buchungsnr = $this->input->post('buchungsnr'); + + $result = $this->KontoModel->load($buchungsnr); + #$result = $this->getDataOrTerminateWithError($result); + if (isError($result)) + $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + $result = $result->retval; + + if (!$result) + $this->terminateWithError('buchung not found', self::ERROR_TYPE_GENERAL); + + $_POST['studiengang_kz'] = current($result)->studiengang_kz; + + $this->form_validation->set_rules('studiengang_kz', 'Studiengang', 'has_permissions_for_stg[admin:rw,assistenz:rw]'); + + Events::trigger('konto_delete_validation', $this->form_validation); + + if (!$this->form_validation->run()) + $this->terminateWithValidationErrors($this->form_validation->error_array()); + + + Events::trigger('konto_delete', $buchungsnr); + + $result = $this->KontoModel->delete($buchungsnr); + #$this->getDataOrTerminateWithError($result); + if (isError($result)) + $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + + $this->terminateWithSuccess(); + } } diff --git a/public/js/api/stv/konto.js b/public/js/api/stv/konto.js index 0e4069f2c..090bd30e2 100644 --- a/public/js/api/stv/konto.js +++ b/public/js/api/stv/konto.js @@ -25,6 +25,9 @@ export default { edit(data) { return this.$fhcApi.post('api/frontend/v1/stv/konto/update', data); }, + delete(buchungsnr) { + return this.$fhcApi.post('api/frontend/v1/stv/konto/delete', {buchungsnr}); + }, getBuchungstypen() { return this.$fhcApi.get('api/frontend/v1/stv/konto/getBuchungstypen'); } diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Konto.js b/public/js/components/Stv/Studentenverwaltung/Details/Konto.js index 849754050..155c51ee2 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Konto.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Konto.js @@ -154,6 +154,19 @@ export default { ); container.append(button); + button = document.createElement('button'); + button.className = 'btn btn-outline-secondary'; + button.innerHTML = ''; + button.addEventListener('click', () => + this.$fhcAlert + .confirmDelete() + .then(result => result ? cell.getData().buchungsnr : Promise.reject({handled:true})) + .then(this.$fhcApi.factory.stv.konto.delete) + .then(() => cell.getRow().delete()) + .catch(this.$fhcAlert.handleSystemError) + ); + container.append(button); + return container; }, frozen: true @@ -182,7 +195,7 @@ export default { updateData(data) { if (!data) return this.reload(); - this.$refs.table.tabulator.updateData(data); + this.$refs.table.tabulator.updateOrAddData(data); }, actionNew() { this.$refs.new.open(); @@ -221,6 +234,7 @@ export default { table-only :side-menu="false" :tabulator-options="tabulatorOptions" + reload new-btn-show new-btn-label="Buchung" :new-btn-disabled="stg_kz === ''" diff --git a/system/phrasesupdate.php b/system/phrasesupdate.php index abeb972a5..f4dd30a21 100644 --- a/system/phrasesupdate.php +++ b/system/phrasesupdate.php @@ -26573,6 +26573,26 @@ array( ) ) ), + array( + 'app' => 'core', + 'category' => 'sap', + 'phrase' => 'msg_buchung_deleted', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Buchungszuordnung SAP geloescht: SalesOrder: {sap_sales_order_id}', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Buchungszuordnung SAP deleted: SalesOrder: {sap_sales_order_id}', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), ); From 6025660e235e368e431c958be5324d8e36b675ef Mon Sep 17 00:00:00 2001 From: cgfhtw Date: Thu, 18 Apr 2024 15:14:41 +0200 Subject: [PATCH 2/2] Konto counter & Zahlungsreferenz --- .../controllers/api/frontend/v1/stv/Konto.php | 152 ++++++++++++++++-- application/models/crm/Konto_model.php | 103 ++++++++++++ public/js/api/stv/konto.js | 3 + .../Stv/Studentenverwaltung/Details/Konto.js | 55 ++++++- 4 files changed, 296 insertions(+), 17 deletions(-) diff --git a/application/controllers/api/frontend/v1/stv/Konto.php b/application/controllers/api/frontend/v1/stv/Konto.php index 1f6b963bb..002d84766 100644 --- a/application/controllers/api/frontend/v1/stv/Konto.php +++ b/application/controllers/api/frontend/v1/stv/Konto.php @@ -39,6 +39,7 @@ class Konto extends FHCAPI_Controller 'getBuchungstypen' => 'student/stammdaten:r', // alle? 'checkDoubles' => ['admin:r', 'assistenz:r'], 'insert' => ['admin:w', 'assistenz:w'], + 'counter' => ['admin:w', 'assistenz:w'], 'update' => ['admin:w', 'assistenz:w'], 'delete' => ['admin:w', 'assistenz:w'] ]); @@ -239,8 +240,8 @@ class Konto extends FHCAPI_Controller 'anmerkung' ]; $data = [ - 'updateamum' => date('c'), - 'updatevon' => getAuthUID() + 'insertamum' => date('c'), + 'insertvon' => getAuthUID() ]; foreach ($allowed as $field) if ($this->input->post($field) !== null) @@ -254,11 +255,11 @@ class Konto extends FHCAPI_Controller foreach ($person_ids as $person_id) { $id = $this->KontoModel->insert(array_merge($data, ['person_id' => $person_id])); if (isError($id)) { - $this->addError(getError($id), self::ERROR_TYPE_GENERAL); + $this->addError(getError($id), self::ERROR_TYPE_DB); } else { $data = $this->KontoModel->withAdditionalInfo()->load(getData($id)); if (isError($data)) - $this->addError(getError($data), self::ERROR_TYPE_GENERAL); + $this->addError(getError($data), self::ERROR_TYPE_DB); else $result[] = current(getData($data)); } @@ -266,7 +267,132 @@ class Konto extends FHCAPI_Controller if ($result) $this->terminateWithSuccess($result); - // NOTE(chris): else there should already be error in the return object + + $this->output->set_status_header(REST_Controller::HTTP_INTERNAL_SERVER_ERROR); + } + + /** + * Save Counter Buchung + * + * @return void + */ + public function counter() + { + $this->load->library('form_validation'); + + $buchungsnrs = $this->input->post('buchungsnr'); + + if (!$buchungsnrs || !is_array($buchungsnrs)) { + $buchungsnrs = $buchungsnrs ? [$buchungsnrs] : []; + $this->form_validation->set_rules('buchungsnr', 'Buchungsnr', 'required'); + } + $this->form_validation->set_rules('buchungsdatum', 'Buchungsdatum', 'is_valid_date'); + + if (!$this->form_validation->run()) + $this->terminateWithValidationErrors($this->form_validation->error_array()); + + $data = []; + $rules = []; + foreach ($buchungsnrs as $k => $buchungsnr) { + $result = $this->KontoModel->load($buchungsnr); + if (isError($result)) { + $rules[] = [ + 'field' => 'buchung[' . $k . ']', + 'label' => 'Buchung #' . $buchungsnr, + 'rules' => 'required', + 'errors' => [ + 'required' => getError($result) + ] + ]; + } elseif (!hasData($result)) { + $rules[] = [ + 'field' => 'buchung[' . $k . ']', + 'label' => 'Buchung #' . $buchungsnr, + 'rules' => 'required' + ]; + } else { + $data[$k] = get_object_vars(current(getData($result))); + $rules[] = [ + 'field' => 'buchung[' . $k . '][buchungsnr]', + 'label' => 'Buchung # ' . $buchungsnr, + 'rules' => 'required|numeric' + ]; + $rules[] = [ + 'field' => 'buchung[' . $k . '][studiengang_kz]', + 'label' => 'Buchung # ' . $buchungsnr, + 'rules' => 'required|has_permissions_for_stg[admin:rw,assistenz:rw]' + ]; + $rules[] = [ + 'field' => 'buchung[' . $k . '][buchungsnr_verweis]', + 'label' => 'Buchung # ' . $buchungsnr, + 'rules' => 'regex_match[/^$/]', + 'errors' => [ + 'regex_match' => 'Gegenbuchungen koennen nur auf die obersten Buchungen getaetigt werden' + ] // TODO(chris): phrase + ]; + } + } + + $this->form_validation->reset_validation(); + $this->form_validation->set_data(['buchung' => $data]); + $this->form_validation->set_rules($rules); + + Events::trigger('konto_counter_validation', $this->form_validation); + + if (!$this->form_validation->run()) + $this->terminateWithValidationErrors($this->form_validation->error_array()); + + $buchungsdatum = $this->input->post('buchungsdatum'); + + $newItems = []; + foreach ($data as $buchung) { + $result = $this->KontoModel->getDifferenz($buchung['buchungsnr']); + if (isError($result)) { + $this->addError(getError($result), self::ERROR_TYPE_GENERAL); + continue; + } + $betrag = $result->retval; + if ($betrag === null) { + $this->addError($this->p->t( + 'konto', + 'Buchung #{buchungsnr} does not exist', + $buchung + ), self::ERROR_TYPE_GENERAL); // TODO(chris): phrase + continue; + } + + + $result = $this->KontoModel->insert([ + 'person_id' => $buchung['person_id'], + 'studiengang_kz' => $buchung['studiengang_kz'], + 'studiensemester_kurzbz' => $buchung['studiensemester_kurzbz'], + 'buchungstext' => $buchung['buchungstext'], + 'buchungstyp_kurzbz' => $buchung['buchungstyp_kurzbz'], + 'credit_points' => $buchung['credit_points'], + 'zahlungsreferenz' => $buchung['zahlungsreferenz'], + 'betrag' => $betrag, + 'buchungsdatum' => $buchungsdatum, + 'mahnspanne' => '0', + 'buchungsnr_verweis' => $buchung['buchungsnr'], + 'insertamum' => date('c'), + 'insertvon' => getAuthUID(), + 'anmerkung' => '' + ]); + if (isError($result)) { + $this->addError(getError($result), self::ERROR_TYPE_GENERAL); + continue; + } + + $newItems = null; + // TODO(chris): get as tree? + /*$result = $this->KontoModel->withAdditionalInfo()->load($result->retval); + if (!hasData($result)) + $newItems = null; + elseif ($newItems !== null) + $newItems[] = current(getData($result));*/ + } + + $this->terminateWithSuccess($newItems); } /** @@ -320,12 +446,14 @@ class Konto extends FHCAPI_Controller if (isError($result)) $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); - $result = $this->KontoModel->withAdditionalInfo()->load($id); + $result = null; + // TODO(chris): get as tree? + /*$result = $this->KontoModel->withAdditionalInfo()->load($id); #$result = $this->getDataOrTerminateWithError($result); if (isError($result)) $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); - $result = $result->retval; + $result = $result->retval;*/ $this->terminateWithSuccess($result); } @@ -354,7 +482,7 @@ class Konto extends FHCAPI_Controller $result = $result->retval; if (!$result) - $this->terminateWithError('buchung not found', self::ERROR_TYPE_GENERAL); + $this->terminateWithError('buchung not found', self::ERROR_TYPE_GENERAL); // TODO(chris): phrase $_POST['studiengang_kz'] = current($result)->studiengang_kz; @@ -369,9 +497,11 @@ class Konto extends FHCAPI_Controller Events::trigger('konto_delete', $buchungsnr); $result = $this->KontoModel->delete($buchungsnr); - #$this->getDataOrTerminateWithError($result); - if (isError($result)) - $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + if (isError($result)) { + if (getCode($result) != 42) + $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); // TODO(chris): phrase + } $this->terminateWithSuccess(); } diff --git a/application/models/crm/Konto_model.php b/application/models/crm/Konto_model.php index 77ae04990..6122feef0 100644 --- a/application/models/crm/Konto_model.php +++ b/application/models/crm/Konto_model.php @@ -15,6 +15,78 @@ class Konto_model extends DB_Model $this->pk = 'buchungsnr'; } + /** + * Insert Data into DB-Table + * + * @param array $data DataArray for Insert + * @return stdClass + */ + public function insert($data, $encryptedColumns = null) + { + if (isset($data['buchungsnr_verweis']) && $data['buchungsnr_verweis']) + return parent::insert($data, $encryptedColumns); + + $this->db->trans_begin(); + + $result = parent::insert($data, $encryptedColumns); + if (isError($result)) { + $this->db->trans_rollback(); + return $result; + } + + $buchungsnr = $result->retval; + // If studiengang_kz is not present in $data it will fail above since it is a not null field + $studiengang_kz = $data['studiengang_kz']; + + + $zahlungsreferenz = false; + Events::trigger('generate_zahlungsreferenz', $buchungsnr, $data, function ($value) use ($zahlungsreferenz) { + $zahlungsreferenz = $value; + }); + + if ($zahlungsreferenz === false) { + $result = $this->execQuery('SELECT UPPER(oe_kurzbz) || ? as zahlungsreferenz + FROM public.tbl_studiengang + WHERE studiengang_kz=?', [$buchungsnr, $studiengang_kz]); + if (isError($result)) { + $this->db->trans_rollback(); + return $result; + } + $zahlungsreferenz = current(getData($result))->zahlungsreferenz; + } elseif (isError($zahlungsreferenz)) { + $this->db->trans_rollback(); + return $zahlungsreferenz; + } + + + $result = $this->update($buchungsnr, [ + 'zahlungsreferenz' => $zahlungsreferenz + ]); + + if (isError($result)) { + $this->db->trans_rollback(); + return $result; + } + + $this->db->trans_commit(); + + return success($buchungsnr); + } + + /** + * Delete data from DB-Table + * + * @param string $id Primary Key for DELETE + * + * @return stdClass + */ + public function delete($id) + { + $this->db->where('buchungsnr_verweis', $id); + if ($this->db->count_all_results($this->dbTable)) + return error('Bitte zuerst die zugeordneten Buchungen loeschen'); + return parent::delete($id, 42); + } /** * Adds additional fields to the Query @@ -124,6 +196,37 @@ class Konto_model extends DB_Model ]); } + /** + * Berechnet den offenen Betrag einer Buchung + * + * @param integer $buchungsnr + * + * @return stdClass + */ + public function getDifferenz($buchungsnr) + { + $this->addSelect('buchungsnr_verweis'); + $this->db->where('buchungsnr', $buchungsnr); + $sql = $this->db->get_compiled_select($this->dbTable); + + $this->addSelect('buchungsnr_verweis'); + $this->db->where('buchungsnr', $buchungsnr); + $this->db->or_where('buchungsnr_verweis', '(' . $sql . ')', false); + $sql = $this->db->get_compiled_select($this->dbTable); + + $this->addSelect('sum(betrag) differenz'); + $this->db->where('buchungsnr', $buchungsnr); + $this->db->or_where('buchungsnr_verweis', $buchungsnr); + $this->db->or_where('buchungsnr', '(' . $sql . ')', false); + + $result = $this->load(); + if (isError($result)) + return $result; + if (!hasData($result)) + return success(null); + return success(current(getData($result))->differenz * -1); + } + /** * Sets a Payment as paid */ diff --git a/public/js/api/stv/konto.js b/public/js/api/stv/konto.js index 090bd30e2..70d5c1ef5 100644 --- a/public/js/api/stv/konto.js +++ b/public/js/api/stv/konto.js @@ -22,6 +22,9 @@ export default { insert(data) { return this.$fhcApi.post('api/frontend/v1/stv/konto/insert', data); }, + counter(data) { + return this.$fhcApi.post('api/frontend/v1/stv/konto/counter', data); + }, edit(data) { return this.$fhcApi.post('api/frontend/v1/stv/konto/update', data); }, diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Konto.js b/public/js/components/Stv/Studentenverwaltung/Details/Konto.js index 155c51ee2..7e1d7d173 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Konto.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Konto.js @@ -5,7 +5,7 @@ import KontoEdit from "./Konto/Edit.js"; // TODO(chris): Phrasen // TODO(chris): multi pers -// TODO(chris): gegenb.(date) multi, löschen multi, best. multi(recht) +// TODO(chris): best. multi(recht) export default { components: { @@ -24,7 +24,8 @@ export default { data() { return { filter: false, - studiengang_kz: false + studiengang_kz: false, + counterdate: new Date() }; }, computed: { @@ -157,14 +158,19 @@ export default { button = document.createElement('button'); button.className = 'btn btn-outline-secondary'; button.innerHTML = ''; - button.addEventListener('click', () => + button.addEventListener('click', evt => { + evt.stopPropagation(); this.$fhcAlert .confirmDelete() .then(result => result ? cell.getData().buchungsnr : Promise.reject({handled:true})) .then(this.$fhcApi.factory.stv.konto.delete) - .then(() => cell.getRow().delete()) - .catch(this.$fhcAlert.handleSystemError) - ); + .then(() => { + // TODO(chris): deleting a child also removes the siblings! + //cell.getRow().delete(); + this.reload(); + }) + .catch(this.$fhcAlert.handleSystemError); + }); container.append(button); return container; @@ -195,10 +201,24 @@ export default { updateData(data) { if (!data) return this.reload(); + // TODO(chris): check children (!delete?, multiple children) + //this.$refs.table.tabulator.updateOrAddData(data.map(row => row.buchungsnr_verweis ? {buchungsnr:row.buchungsnr_verweis, _children:row} : row)); this.$refs.table.tabulator.updateOrAddData(data); }, actionNew() { this.$refs.new.open(); + }, + actionCounter(selected) { + this.$fhcApi + .factory.stv.konto.counter({ + buchungsnr: selected.map(e => e.buchungsnr), + buchungsdatum: this.counterdate + }) + .then(result => result.data) + .then(this.updateData) + .then(() => 'Daten wurden gespeichert') + .then(this.$fhcAlert.alertSuccess) + .catch(this.$fhcAlert.handleSystemError); } }, created() { @@ -240,6 +260,29 @@ export default { :new-btn-disabled="stg_kz === ''" @click:new="actionNew" > +