diff --git a/Layout/default/Vatgroup/Index.php b/Layout/default/Vatgroup/Index.php
new file mode 100644
index 000000000..726720e66
--- /dev/null
+++ b/Layout/default/Vatgroup/Index.php
@@ -0,0 +1,132 @@
+getUrl($Mod,"Index");
+ $pagination_baseurl_params = ["filter" => $filter];
+ $pagination_entity_name = "Steuersätze";
+?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Steuersatzgruppe =$vatgroup->name?>
+
+
+
+
Neue Steuersatzgruppe
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Layout/default/menu.php b/Layout/default/menu.php
index 1fd173f5c..d7e393f7f 100644
--- a/Layout/default/menu.php
+++ b/Layout/default/menu.php
@@ -74,6 +74,7 @@
is(["Admin"])): ?>
"> Open Access IDs
"> Technologien
+ "> Steuersätze
diff --git a/application/Country/CountryModel.php b/application/Country/CountryModel.php
index 12dd2b0d9..594962ac8 100644
--- a/application/Country/CountryModel.php
+++ b/application/Country/CountryModel.php
@@ -86,36 +86,6 @@ class CountryModel {
return 0;
}
- public static function searchActive($filter, $limit = false) {
- //var_dump($filter);exit;
- $items = [];
- $db = FronkDB::singleton();
-
- $where = self::getSqlFilter($filter);
- $sql = "SELECT Country.* FROM Country
- WHERE $where
- ORDER BY Country.isocode";
-
- if(is_array($limit) && count($limit)) {
- if(is_numeric($limit['start']) && is_numeric($limit['count'])) {
- $sql .= " LIMIT ".$limit['start'].", ".$limit['count'];
- } elseif(is_numeric($count)) {
- $sql .= " LIMIT ".$limit['count'];
- }
- }
-
- mfLoghandler::singleton()->debug($sql);
-
- $res = $db->query($sql);
- if($db->num_rows($res)) {
- while($data = $db->fetch_object($res)) {
- $items[$data->id] = new Country($data);
- }
- }
-
- return $items;
- }
-
public static function search($filter, $limit = false) {
//var_dump($filter);exit;
$items = [];
diff --git a/application/Vatgroup/Vatgroup.php b/application/Vatgroup/Vatgroup.php
new file mode 100644
index 000000000..36f118c2a
--- /dev/null
+++ b/application/Vatgroup/Vatgroup.php
@@ -0,0 +1,37 @@
+ $this->id]) as $rate) {
+ $this->rates[$rate->area] = $rate;
+ }
+ return $this->rates;
+ }
+
+ public function getProperty($name) {
+ if($this->$name == null) {
+
+ if(!$this->id) {
+ return null;
+ }
+
+ if($name == "rates") {
+ return $this->loadRates();
+ }
+
+ $classname = ucfirst($name);
+ $idfield = $name."_id";
+ $this->$name = new $classname($this->$idfield);
+
+ if($this->$name->id) {
+ return $this->$name;
+ } else {
+ return null;
+ }
+ }
+
+ return $this->$name;
+ }
+}
\ No newline at end of file
diff --git a/application/Vatgroup/VatgroupController.php b/application/Vatgroup/VatgroupController.php
new file mode 100644
index 000000000..ca47a946e
--- /dev/null
+++ b/application/Vatgroup/VatgroupController.php
@@ -0,0 +1,103 @@
+needlogin=true;
+ $me = new User();
+ $me->loadMe();
+ $this->me = $me;
+ $this->layout()->set("me",$me);
+
+ if(!$me->is(["Admin"])) {
+ $this->redirect("Dashboard");
+ }
+ }
+
+
+ protected function indexAction() {
+ $vatgroups = VatgroupModel::getAll();
+ $this->layout()->set("vatgroups", $vatgroups);
+ }
+
+ protected function addGroupAction() {
+ $name = $this->request->group_name;
+ if(!$name) {
+ $this->layout()->setFlash("Bitte einen Namen angeben!", "error");
+ $this->redirect("Vatgroup");
+ }
+
+ if(VatgroupModel::getFirst(["name" => $name])) {
+ $this->layout()->setFlash("Eine Steuersatzgruppe mit diesem Namen ist bereits vorhanden!", "warning");
+ $this->redirect("Vatgroup");
+ }
+
+ $group = VatgroupModel::create([
+ "name" => $name
+ ]);
+
+ if(!$group->save()) {
+ $this->layout()->setFlash("Fehler beim Anlegen der Steuersatzgruppe!", "error");
+ $this->redirect("Vatgroup");
+ }
+
+ $this->layout()->setFlash("Steuersatzgruppe erfolgreic erstellt!", "success");
+ $this->redirect("Vatgroup");
+ }
+
+ protected function saveAction() {
+ $id = $this->request->id;
+ if(!is_numeric($id) || $id < 1) {
+ $this->layout()->setFlash("Ungültige Steuersatzgruppe", "error");
+ $this->redirect("Vatgroup");
+ }
+
+ $group = new Vatgroup($id);
+ if(!$group->id) {
+ $this->layout()->setFlash("Ungültige Steuersatzgruppe", "error");
+ $this->redirect("Vatgroup");
+ }
+
+ foreach($this->request->rates as $area => $rate) {
+ if(!$rate['account'] && !$rate['rate']) continue;
+
+ if(!$area || !array_key_exists($area, TT_VATRATE_AREAS)) {
+ $this->layout()->setFlash("Ungültiges Zielland", "error");
+ $this->redirect("Vatgroup");
+ }
+
+ $data = [];
+ $data["vatgroup_id"] = $group->id;
+ $data["area"] = $area;
+ $data["account"] = trim($rate["account"]);
+ $data["rate"] = str_replace(",",".", trim($rate["rate"]));
+ $data["invoice_text"] = (trim($rate["invoice_text"])) ? trim($rate["invoice_text"]) : null;
+
+ if(!$data["account"] || !is_numeric($data["account"])) {
+ $this->layout()->setFlash("Ungültige Erlöskontonummer", "error");
+ $this->redirect("Vatgroup");
+ }
+ if(!is_numeric($data["rate"])) {
+ $this->layout()->setFlash("Ungültiger Steuersatz", "error");
+ $this->redirect("Vatgroup");
+ }
+
+ $vatrate = VatrateModel::getFirst(["vatgroup_id" => $group->id, "area" => $area]);
+ if($vatrate) {
+ $vatrate->update($data);
+ } else {
+ $vatrate = VatrateModel::create($data);
+ }
+
+ if(!$vatrate->save()) {
+ $this->layout()->setFlash("Fehler beim Speichern eines Steuersatzes", "error");
+ $this->redirect("Vatgroup");
+ }
+ }
+
+ $this->layout()->setFlash("Steuersätze erfolgreich gespeichert", "success");
+ $this->redirect("Vatgroup");
+
+ }
+
+}
\ No newline at end of file
diff --git a/application/Vatgroup/VatgroupModel.php b/application/Vatgroup/VatgroupModel.php
new file mode 100644
index 000000000..adeade4fe
--- /dev/null
+++ b/application/Vatgroup/VatgroupModel.php
@@ -0,0 +1,133 @@
+ $value) {
+ if(property_exists(get_called_class(), $field)) {
+ $model ->$field = $value;
+ }
+ }
+
+ $me = new User();
+ $me->loadMe();
+
+ if($model->create_by === null) {
+ $model->create_by = $me->id;
+ }
+ if($model->edit_by === null) {
+ $model->edit_by = $me->id;
+ }
+
+ return $model;
+ }
+
+ public static function getAll() {
+ $items = [];
+
+ $db = FronkDB::singleton();
+
+ $res = $db->select("Vatgroup", "*", "1 = 1 ORDER BY name");
+ if($db->num_rows($res)) {
+ while($data = $db->fetch_object($res)) {
+ $items[] = new Vatgroup($data);
+ }
+ }
+ return $items;
+
+ }
+
+ public static function getFirst($filter) {
+ $db = FronkDB::singleton();
+
+ $where = self::getSqlFilter($filter);
+ $sql = "SELECT Vatgroup.* FROM Vatgroup
+ WHERE $where
+ LIMIT 1";
+ //var_dump($sql);exit;
+ $res = $db->query($sql);
+ if($db->num_rows($res)) {
+ $data = $db->fetch_object($res);
+ $item = new Vatgroup($data);
+ if($item->id) {
+ return $item;
+ } else {
+ return null;
+ }
+ }
+ return null;
+ }
+
+ public static function count($filter) {
+ $db = FronkDB::singleton();
+
+ $where = self::getSqlFilter($filter);
+ $sql = "SELECT COUT(*) as cnt FROM Vatgroup
+ WHERE $where
+ ";
+
+ mfLoghandler::singleton()->debug($sql);
+
+ $res = $db->query($sql);
+ if($db->num_rows($res)) {
+ $data = $db->fetch_object($res);
+ return $data->cnt;
+ }
+ return 0;
+ }
+
+ public static function search($filter, $limit = false) {
+ //var_dump($filter);exit;
+ $items = [];
+ $db = FronkDB::singleton();
+
+ $where = self::getSqlFilter($filter);
+ $sql = "SELECT Vatgroup.* FROM Vatgroup
+ WHERE $where
+ ORDER BY Vatgroup.name";
+
+ if(is_array($limit) && count($limit)) {
+ if(is_numeric($limit['start']) && is_numeric($limit['count'])) {
+ $sql .= " LIMIT ".$limit['start'].", ".$limit['count'];
+ } elseif(is_numeric($count)) {
+ $sql .= " LIMIT ".$limit['count'];
+ }
+ }
+
+ mfLoghandler::singleton()->debug($sql);
+
+ $res = $db->query($sql);
+ if($db->num_rows($res)) {
+ while($data = $db->fetch_object($res)) {
+ $items[$data->id] = new Vatgroup($data);
+ }
+ }
+
+ return $items;
+ }
+
+ private static function getSqlFilter($filter) {
+ $where = "1=1 ";
+
+ $db = FronkDB::singleton();
+
+ if(array_key_exists("name", $filter)) {
+ $name = $db->escape($filter['name']);
+ if($name) {
+ $where .= " AND Vatgroup.`name` = '$name'";
+ }
+ }
+
+ //var_dump($filter, $where);exit;
+ return $where;
+ }
+
+}
diff --git a/application/Vatrate/Vatrate.php b/application/Vatrate/Vatrate.php
new file mode 100644
index 000000000..fb5005e84
--- /dev/null
+++ b/application/Vatrate/Vatrate.php
@@ -0,0 +1,5 @@
+ $value) {
+ if(property_exists(get_called_class(), $field)) {
+ $model ->$field = $value;
+ }
+ }
+
+ $me = new User();
+ $me->loadMe();
+
+ if($model->create_by === null) {
+ $model->create_by = $me->id;
+ }
+ if($model->edit_by === null) {
+ $model->edit_by = $me->id;
+ }
+
+ return $model;
+ }
+
+ public static function getAll() {
+ $items = [];
+
+ $db = FronkDB::singleton();
+
+ $res = $db->select("Vatrate", "*", "1 = 1 ORDER BY area");
+ if($db->num_rows($res)) {
+ while($data = $db->fetch_object($res)) {
+ $items[] = new Vatrate($data);
+ }
+ }
+ return $items;
+
+ }
+
+ public static function getFirst($filter) {
+ $db = FronkDB::singleton();
+
+ $where = self::getSqlFilter($filter);
+ $sql = "SELECT Vatrate.* FROM Vatrate
+ WHERE $where
+ LIMIT 1";
+ //var_dump($sql);exit;
+ $res = $db->query($sql);
+ if($db->num_rows($res)) {
+ $data = $db->fetch_object($res);
+ $item = new Vatrate($data);
+ if($item->id) {
+ return $item;
+ } else {
+ return null;
+ }
+ }
+ return null;
+ }
+
+ public static function count($filter) {
+ $db = FronkDB::singleton();
+
+ $where = self::getSqlFilter($filter);
+ $sql = "SELECT COUT(*) as cnt FROM Vatrate
+ WHERE $where
+ ";
+
+ mfLoghandler::singleton()->debug($sql);
+
+ $res = $db->query($sql);
+ if($db->num_rows($res)) {
+ $data = $db->fetch_object($res);
+ return $data->cnt;
+ }
+ return 0;
+ }
+
+ public static function search($filter, $limit = false) {
+ //var_dump($filter);exit;
+ $items = [];
+ $db = FronkDB::singleton();
+
+ $where = self::getSqlFilter($filter);
+ $sql = "SELECT Vatrate.* FROM Vatrate
+ WHERE $where
+ ORDER BY Vatrate.area";
+
+ if(is_array($limit) && count($limit)) {
+ if(is_numeric($limit['start']) && is_numeric($limit['count'])) {
+ $sql .= " LIMIT ".$limit['start'].", ".$limit['count'];
+ } elseif(is_numeric($count)) {
+ $sql .= " LIMIT ".$limit['count'];
+ }
+ }
+
+ mfLoghandler::singleton()->debug($sql);
+
+ $res = $db->query($sql);
+ if($db->num_rows($res)) {
+ while($data = $db->fetch_object($res)) {
+ $items[$data->id] = new Vatrate($data);
+ }
+ }
+
+ return $items;
+ }
+
+ private static function getSqlFilter($filter) {
+ $where = "1=1 ";
+
+ $db = FronkDB::singleton();
+
+ if(array_key_exists("vatgroup_id", $filter)) {
+ $vatgroup_id = $filter['vatgroup_id'];
+ if(is_numeric($vatgroup_id)) {
+ $where .= " AND Vatrate.`vatgroup_id` = $vatgroup_id";
+ }
+ }
+
+ if(array_key_exists("area", $filter)) {
+ $area = $db->escape($filter['area']);
+ if($area) {
+ $where .= " AND Vatrate.`area` = '$area'";
+ }
+ }
+
+
+ //var_dump($filter, $where);exit;
+ return $where;
+ }
+
+}
diff --git a/db/migrations/20240220192901_create_vat_tables.php b/db/migrations/20240220192901_create_vat_tables.php
new file mode 100644
index 000000000..f7295527a
--- /dev/null
+++ b/db/migrations/20240220192901_create_vat_tables.php
@@ -0,0 +1,49 @@
+getEnvironment() == "thetool") {
+ $table = $this->table("Vatgroup");
+ $table->addColumn("name", "string", ["null" => false, "limit" => 255]);
+ $table->addColumn("create_by", "integer", ["null" => false]);
+ $table->addColumn("edit_by", "integer", ["null" => false]);
+ $table->addColumn("create", "integer", ["null" => false]);
+ $table->addColumn("edit", "integer", ["null" => false]);
+ $table->save();
+
+
+ $table = $this->table("Vatrate");
+ $table->addColumn("vatgroup_id", "integer", ["null" => false]);
+ $table->addColumn("area", "enum", ["null" => false, "values" => "domestic,eu,other"]);
+ $table->addColumn("account", "integer", ["null" => false]);
+ $table->addColumn("rate", "decimal", ["null" => false, "precision" => 6, "scale" => 2]);
+ $table->addColumn("invoice_text", "text", ["null" => true, "default" => null]);
+ $table->addColumn("create_by", "integer", ["null" => false]);
+ $table->addColumn("edit_by", "integer", ["null" => false]);
+ $table->addColumn("create", "integer", ["null" => false]);
+ $table->addColumn("edit", "integer", ["null" => false]);
+ $table->create();
+ }
+
+ if($this->getEnvironment() == "addressdb") {
+
+ }
+ }
+
+ public function down(): void
+ {
+ if($this->getEnvironment() == "thetool") {
+ $this->table("Vatrate")->drop()->save();
+ $this->table("Vatgroup")->drop()->save();
+ }
+
+ if($this->getEnvironment() == "addressdb") {
+
+ }
+ }
+}