diff --git a/Layout/default/TimerecordingBilling/Detail.php b/Layout/default/TimerecordingBilling/Detail.php
new file mode 100644
index 000000000..71d10d391
--- /dev/null
+++ b/Layout/default/TimerecordingBilling/Detail.php
@@ -0,0 +1,122 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ | Mitarbeiter |
+ Personal Nr. |
+ Sollstunden |
+ Iststunden |
+ Sollabweichung |
+ Akuelle Überstunden |
+ Nichtleistungszeiten |
+ Diäten |
+ Homeoffice Tage |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+ $value) {
+ if ($counter > 1) {
+ $offdays .= "
";
+ }
+ $offdays .= $category . ": " . $value . " Tag(e) ";
+ $counter++;
+ }
+ } else {
+ $offdays = "keine";
+ }
+ ?>
+
+ | = $timerecording['user_name'] ?> |
+ = $timerecording['employee_number'] ?> |
+ = $timerecording['data']['time']['must'] ?> |
+ = $timerecording['data']['time']['is'] ?> |
+ = $timerecording['data']['time']['summseconds'] ?> |
+ = $timerecording['data']['time']['overtime_now'] ?> |
+ = $offdays ?> |
+ = number_format($timerecording['data']['time']['diet'], 2, ',', '.') ?>
+ €
+ |
+ = $timerecording['data']['time']['homeoffice'] ?> Tag(e) |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Layout/default/TimerecordingBilling/Index.php b/Layout/default/TimerecordingBilling/Index.php
new file mode 100644
index 000000000..81fb23d56
--- /dev/null
+++ b/Layout/default/TimerecordingBilling/Index.php
@@ -0,0 +1,77 @@
+
+
+
+
+
+
+
+
+ - ">= MFAPPNAME_SLUG ?>
+
+ - Zeiterfassung Verrechnung
+
+
+
Zeiterfassung Verrechnung/Abrechnung
+
+
+
+
+
+
+
+
+
+
+
+
+ | Monat |
+ Abgeschlossen |
+ Abgeschlossen am |
+ Abgeschlossen von |
+
+
+ |
+ |
+ |
+ |
+
+
+
+
+
+ | $month]) ?>"> = $month ?> |
+ |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Layout/default/TimerecordingCategories/Form.php b/Layout/default/TimerecordingCategories/Form.php
index 6e21f051f..96072b0fe 100644
--- a/Layout/default/TimerecordingCategories/Form.php
+++ b/Layout/default/TimerecordingCategories/Form.php
@@ -93,6 +93,17 @@
+
diff --git a/application/Timerecording/TimerecordingModel.php b/application/Timerecording/TimerecordingModel.php
index e95ad81a0..59cd19121 100644
--- a/application/Timerecording/TimerecordingModel.php
+++ b/application/Timerecording/TimerecordingModel.php
@@ -155,7 +155,7 @@ class TimerecordingModel
$start = $filter['start'];
$end = $filter['end'];
if (is_numeric($start) && is_numeric($end)) {
- $where .= " AND ((`start` >= $start AND `start` <= $end) OR (`end` >= $start AND `end` <= $end) OR `end` is NULL) ORDER by user_id ASC";
+ $where .= " AND ((`start` >= $start AND `start` <= $end) OR (`end` >= $start AND `end` <= $end) OR `end` is NULL) ORDER by user_id,start ASC";
}
}
if (array_key_exists("start", $filter) && array_key_exists("timerecordingCategory_id", $filter)) {
@@ -199,9 +199,9 @@ class TimerecordingModel
$id = $filter['id'];
if (is_numeric($starttime) && is_numeric($endtime)) {
if ($id && is_numeric($id)) {
- $where .= " AND `id` != $id";
+ $where .= " AND `id` != $id AND `days`='0'";
}
- $where .= " AND (((`start` <= $starttime AND `end` > $starttime ) OR (`start` > $endtime AND `end` < $endtime) OR (`start` > $starttime AND `end` > $starttime AND `start` <= $endtime AND `end` <= $endtime) OR (`start` > $starttime AND `end` > $starttime AND `start` < $endtime AND `end` > $endtime) OR (`start` = $starttime AND `end` = $endtime )) OR ( `start` <= $starttime AND `end` IS NULL)) ORDER by user_id ASC";
+ $where .= " AND (((`start` <= $starttime AND `end` > $starttime ) OR (`start` > $endtime AND `end` < $endtime) OR (`start` > $starttime AND `end` > $starttime AND `start` <= $endtime AND `end` <= $endtime) OR (`start` > $starttime AND `end` > $starttime AND `start` < $endtime AND `end` > $endtime) OR (`start` = $starttime AND `end` = $endtime )) OR ( `start` <= $starttime AND `end` IS NULL)) ORDER by user_id,start ASC";
//var_dump($where);exit;
}
diff --git a/application/TimerecordingBilling/TimerecordingBillingController.php b/application/TimerecordingBilling/TimerecordingBillingController.php
new file mode 100644
index 000000000..48b4fe84c
--- /dev/null
+++ b/application/TimerecordingBilling/TimerecordingBillingController.php
@@ -0,0 +1,176 @@
+needlogin = true;
+ $me = new User();
+ $me->loadMe();
+ $this->me = $me;
+ $this->layout()->set("me", $me);
+
+ if (!$me->can(["Fibu"])) {
+ $this->redirect("Dashboard");
+ }
+ }
+
+ protected function indexAction()
+ {
+ $startdate = 1709254800;
+ $today = time();
+ $months = [];
+ $month = $startdate;
+ while ($month < $today) {
+ $months[] = date("m.Y", $month);
+ $month = strtotime("+1 month", $month);
+ }
+ $this->layout()->set("months", $months);
+ $this->layout()->setTemplate("TimerecordingBilling/Index");
+ }
+
+ protected function detailAction()
+ {
+ $r = $this->request;
+ $month = $r->get("month");
+ if (!$month) {
+ $this->redirect("TimerecordingBilling");
+ }
+ $month = strtotime("01." . $month);
+ $timerecordingsEmolyees = TimerecordingEmployeeModel::getAll();
+ foreach ($timerecordingsEmolyees as $timerecordingsEmolyee) {
+ $user = new User($timerecordingsEmolyee->user_id);
+ $employee_number = (string)$user->getFlag('employee_number');
+ $timerecordingReport = new TimerecordingReportController();
+ $timerecordings[$timerecordingsEmolyee->user_id]['user_id'] = $timerecordingsEmolyee->user_id;
+ $timerecordings[$timerecordingsEmolyee->user_id]['user_name'] = $timerecordingsEmolyee->user->name;
+ $timerecordings[$timerecordingsEmolyee->user_id]['employee_number'] = $employee_number;
+ $timerecordings[$timerecordingsEmolyee->user_id]['data'] = $timerecordingReport->getTimerecordingsTimes('2', $month, $month, $month, $timerecordingsEmolyee->user_id, 0);
+ }
+ $this->layout()->set("timerecordings", $timerecordings);
+ $this->layout()->setTemplate("TimerecordingBilling/Detail");
+ $this->layout()->set("month", date("m.Y", $month));
+ }
+
+ protected function apiAction()
+ {
+ $do = $this->request->do;
+ $month = $this->request->month;
+
+ $data = [];
+
+ switch ($do) {
+ case "generatebmdexport":
+ $return = $this->generateBmdExport($month);
+ break;
+ case "generatebmdexportnlz":
+ $return = $this->generateBmdExport($month, 1);
+ break;
+ default:
+ $return = false;
+ }
+ if (!is_array($return) || !count($return)) {
+ $data = ["status" => "error"];
+ $this->returnJson($data);
+ }
+ $data['status'] = "OK";
+ $data['result'] = $return;
+ $this->returnJson($data);
+ }
+
+ protected function addAction()
+ {
+
+
+ }
+
+ protected function editAction()
+ {
+
+ }
+
+ protected function saveAction()
+ {
+
+ }
+
+
+ protected function deleteAction()
+ {
+
+ }
+
+ protected function generateBmdLine()
+ {
+
+ }
+
+ protected function generateBmdExport($month, $nlz = 0)
+ {
+ //create and download csv file
+ $filename = "BMDExport_" . $month . ".csv";
+ $file = fopen("php://output", 'w');
+ header('Content-Type: text/csv; charset=utf-8');
+ header('Content-Disposition: attachment; filename=' . $filename);
+ if ($nlz == 0) {
+ $headerarray = ["Monat", "Firma", "Mitarbeiter", "Lohnart", "Menge", "Satz", "Betrag", "Kostenstelle", "NLZ-Kennzeichen", "NLZ Von-Datum", "NLZ Bis-Datum"];
+ fputcsv($file, $headerarray, ";");
+ } else {
+ $headerarray = ["Firma", "Mitarbeiter", "DV-Nr", "Art", "Sonderzeit", "Verarbeitungs-KZ", "Von", "Bis", "Verwaltung", "Bezahlt"];
+ fputcsv($file, $headerarray, ";");
+ }
+ $month = strtotime("01." . $month);
+ $monthbmd = date("n", $month);
+ $companybmd = "1";
+ $timerecordingsEmolyees = TimerecordingEmployeeModel::getAll();
+ foreach ($timerecordingsEmolyees as $timerecordingsEmolyee) {
+ $user = new User($timerecordingsEmolyee->user_id);
+ $employee_number = (string)$user->getFlag('employee_number');
+ $employeetypesbmd = TimerecordingEmployeeModel::$employeetypesbmd;
+ $employee_type = $employeetypesbmd[$timerecordingsEmolyee->type];
+ $timerecordingReport = new TimerecordingReportController();
+ $timerecording = $timerecordingReport->getTimerecordingsTimes('2', $month, $month, $month, $timerecordingsEmolyee->user_id, 0);
+
+ foreach ($timerecording['time']['isclean'] as $key => $value) {
+ $hours = $value;
+ //calc ishours in hours
+ $hours = $hours / 3600;
+ $hours = round($hours, 2);
+ $hours = str_replace(".", ",", $hours);
+ if (strpos($key, ',') !== false && $nlz == 0) {
+ $bodyarray = [$monthbmd, $companybmd, $employee_number, $employee_type, $hours, "", "", "", "", "", ""];
+ fputcsv($file, $bodyarray, ";");
+ } else if (strpos($key, ',') === false && $nlz == 1) {
+
+ }
+
+ }
+
+ if ($timerecording['time']['diet'] > 0 && $nlz == 0) {
+ $dietsum = round($timerecording['time']['diet'], 2);
+ $dietsum = str_replace(".", ",", $dietsum);
+ $bodyarray = [$monthbmd, $companybmd, $employee_number, "2500", "", "", $dietsum, "", "", "", ""];
+ fputcsv($file, $bodyarray, ";");
+ }
+ if (!empty($timerecording['time']['nlztimes']) && $nlz == 1) {
+ foreach ($timerecording['time']['nlztimes'] as $nlztime) {
+ if ($nlztime['minutes']) {
+ $time = $nlztime['minutes'] / 60;
+ $time = round($time, 2);
+ $time = str_replace(".", ",", $time);
+ } else {
+ $time = "";
+ }
+ $bodyarray = [$companybmd, $employee_number, 1, $nlztime['categoryshort'], "", "3", $nlztime['start'], $nlztime['end'], $time, $hours];
+ fputcsv($file, $bodyarray, ";");
+ }
+ }
+
+ }
+
+
+ die();
+
+ }
+}
diff --git a/application/TimerecordingBilling/TimerecordingBillingModel.php b/application/TimerecordingBilling/TimerecordingBillingModel.php
new file mode 100644
index 000000000..75e6eec9f
--- /dev/null
+++ b/application/TimerecordingBilling/TimerecordingBillingModel.php
@@ -0,0 +1,8 @@
+require_comment);
$data['only_admin'] = trim($r->only_admin);
$data['businesstrip'] = trim($r->businesstrip);
+ $data['unpaid'] = trim($r->unpaid);
if (!$data['name']) {
@@ -107,6 +108,9 @@ class TimerecordingCategoryController extends mfBaseController
if (!$data['businesstrip']) {
$data['businesstrip'] = 0;
}
+ if (!$data['unpaid']) {
+ $data['unpaid'] = 0;
+ }
// var_dump($_FILES);
// var_dump($upload);
// exit;
diff --git a/application/TimerecordingCategory/TimerecordingCategoryModel.php b/application/TimerecordingCategory/TimerecordingCategoryModel.php
index 437cf93dc..eaa7a89be 100644
--- a/application/TimerecordingCategory/TimerecordingCategoryModel.php
+++ b/application/TimerecordingCategory/TimerecordingCategoryModel.php
@@ -9,6 +9,7 @@ class TimerecordingCategoryModel
private $require_comment;
private $only_admin;
private $businesstrip;
+ private $unpaid;
public static $hourday_definition = array(1 => "Uhrzeit (von/bis)", 2 => "Tage (von/bis)", 3 => "Startdatum", 4 => "Enddatum", 5 => "Anzahl Tage", 6 => "ZA Uhrzeit (von/bis)", 7 => "Fahrtenbuch (von/bis)");
public static $approval_definition = array(0 => "Nein", 1 => "Ja");
public static $require_comment_definition = array(0 => "Nein", 1 => "Ja");
diff --git a/application/TimerecordingEmployee/TimerecordingEmployeeModel.php b/application/TimerecordingEmployee/TimerecordingEmployeeModel.php
index a76f9a4a7..089e76cfb 100644
--- a/application/TimerecordingEmployee/TimerecordingEmployeeModel.php
+++ b/application/TimerecordingEmployee/TimerecordingEmployeeModel.php
@@ -17,6 +17,7 @@ class TimerecordingEmployeeModel
private $bpahours;
private $startdate;
private $birthday;
+ public static $employeetypesbmd = array('1' => '1000', '2' => '1200', '3' => '1400');
public static function find($data)
diff --git a/application/TimerecordingReport/TimerecordingReportController.php b/application/TimerecordingReport/TimerecordingReportController.php
index 7c2e3bc14..7df46f181 100644
--- a/application/TimerecordingReport/TimerecordingReportController.php
+++ b/application/TimerecordingReport/TimerecordingReportController.php
@@ -392,8 +392,10 @@ class TimerecordingReportController extends mfBaseController
$r = $this->request;
$mustSeconds = 0;
$isSeconds = 0;
+ $isSecondscleanarray = array();
$holiDays = 0;
$plusHours = 0;
+ $nlzTimes = array();
$daysum = array();
if (!$user_id) {
$user_id = $r->user_id;
@@ -405,6 +407,7 @@ class TimerecordingReportController extends mfBaseController
if ($employee) {
$holiDays = $employee[0]->holidays;
$plusHours = $employee[0]->plushours;
+ $overtime_now = $employee[0]->overtime_now;
$auto_workinghours = $employee[0]->auto_workinghours;
$startdate = $employee[0]->startdate;
}
@@ -451,6 +454,10 @@ class TimerecordingReportController extends mfBaseController
$lastdate = strtotime(date("Y-m-t", $datamonth));
$daycount = date("t", $datamonth);
$lastdate = strtotime(date("Y-m-d", $lastdate) . ' 23:59:59');
+ //Lastdate staticmust deleted
+// $lastdate = strtotime("2024-03-22 23:59:59");
+// $daycount=22;
+
$searchArray = ['user_id' => $user_id, 'start' => $firstdate, 'end' => $lastdate];
$timestamp = $firstdate;
@@ -493,13 +500,50 @@ class TimerecordingReportController extends mfBaseController
$timerecordings = TimerecordingModel::search($searchArray);
$responsecount = count($timerecordings);
+ $oldday = "";
+ $homeoffice = false;
+ $homeofficesum = 0;
+ $dietsum = 0;
+ $diet = 0;
+ $dietbase = TimerecordingBillingModel::$dieatBase;
+
foreach ($timerecordings as $timerecording):
$state = "";
$enddate = "";
$sum = "-";
$day = "";
$orderdate = $timerecording->start;
+ if ($oldday != date('Y-m-d', $timerecording->start)) {
+
+ if ($homeoffice == 1) {
+ $homeofficesum++;
+ $homeoffice = false;
+ }
+ if ($diet > 10800) {
+ if ($diet >= 43200) {
+ $diet = 43200;
+ }
+ $calcdiet = $dietbase / 12;
+ $calcdiet = ($diet / 3600) * $calcdiet;
+ $dietsum = $dietsum + $calcdiet;
+ }
+ $diet = 0;
+
+ }
+ if ($timerecording->homeoffice == 1 && (!$homeoffice || $homeoffice == 1)) {
+
+ $homeoffice = 1;
+ } else {
+ $homeoffice = 0;
+ }
+
+
+ if ($timerecording->businesstrip == 1 && $timerecording->timerecordingCategory->hourday == 1) {
+ $diet = $diet + $timerecording->end - $timerecording->start;
+ }
+
if ($timerecording->timerecordingCategory->hourday == 1) {
+
$date = date("d.m.Y", $timerecording->start);
$datadate = date("Y-m-d", $timerecording->start);
$start = date("H:i", $timerecording->start);
@@ -510,6 +554,18 @@ class TimerecordingReportController extends mfBaseController
$sum = sprintf("%02d", $hours) . ":" . sprintf("%02d", $minutes);
$day = $daysgerm[date("w", $timerecording->start)];
$isSeconds = $isSeconds + $seconds;
+ if ($isSecondscleanarray[$timerecording->timerecordingCategory->short]) {
+ $isSecondscleanarray[$timerecording->timerecordingCategory->short] = $isSecondscleanarray[$timerecording->timerecordingCategory->short] + $seconds;
+ } else {
+ $isSecondscleanarray[$timerecording->timerecordingCategory->short] = $seconds;
+ }
+ if ($timerecording->timerecordingCategory->short != "1000,1200,1400") {
+ $nlzTimes[$timerecording->id]['start'] = date("d.m.Y", $timerecording->start);
+ $nlzTimes[$timerecording->id]['end'] = date("d.m.Y", $timerecording->end);
+ $nlzTimes[$timerecording->id]['minutes'] = $seconds / 60;
+ $nlzTimes[$timerecording->id]['category'] = $timerecording->timerecordingCategory->name;
+ $nlzTimes[$timerecording->id]['categoryshort'] = $timerecording->timerecordingCategory->short;
+ }
} else if ($timerecording->timerecordingCategory->hourday == 2 || ($timerecording->timerecordingCategory->hourday == 3 && $timerecording->end)) {
$date = date("d.m.", $timerecording->start) . " - " . $daysgerm[date("w", $timerecording->end)] . " " . date("d.m.Y", $timerecording->end);
$datadate = date("Y-m-d", $timerecording->start);
@@ -558,11 +614,17 @@ class TimerecordingReportController extends mfBaseController
$sum = $sumdays . " Tage";
}
- if (!$daysum[$timerecording->timerecordingCategory->short]) {
- $daysum[$timerecording->timerecordingCategory->short] = $sumdays;
+ if (!$daysum[$timerecording->timerecordingCategory->name]) {
+ $daysum[$timerecording->timerecordingCategory->name] = $sumdays;
} else {
- $daysum[$timerecording->timerecordingCategory->short] = $daysum[$timerecording->timerecordingCategory->short] + $sumdays;
+ $daysum[$timerecording->timerecordingCategory->name] = $daysum[$timerecording->timerecordingCategory->name] + $sumdays;
}
+ $nlzTimes[$timerecording->id]['start'] = date("d.m.Y", $timerecording->start);
+ $nlzTimes[$timerecording->id]['end'] = date("d.m.Y", $timerecording->end);
+ $nlzTimes[$timerecording->id]['days'] = $sumdays;
+ $nlzTimes[$timerecording->id]['category'] = $timerecording->timerecordingCategory->name;
+ $nlzTimes[$timerecording->id]['categoryshort'] = $timerecording->timerecordingCategory->short;
+
} else if ($timerecording->timerecordingCategory->hourday == 3 && !$timerecording->end) {
$date = date("d.m.Y", $timerecording->start) . " - " . $daysgerm[date("w", time())] . " " . date("d.m.Y", time());;
$datadate = date("Y-m-d", $timerecording->start);
@@ -653,13 +715,52 @@ class TimerecordingReportController extends mfBaseController
} else {
}
+ $oldday = date('Y-m-d', $timerecording->start);
endforeach;
+ if ($homeoffice == 1) {
+ $homeofficesum++;
+ $homeoffice = 0;
+ }
+ if ($diet > 10800) {
+ if ($diet >= 43200) {
+ $diet = 43200;
+ }
+ $calcdiet = $dietbase / 12;
+ $calcdiet = ($diet / 3600) * $calcdiet;
+ $dietsum = $dietsum + $calcdiet;
+ }
+
+ $summseconds = $isSeconds - $mustSeconds;
+ $isorder = $isSeconds;
+ if ($isSeconds < 0) {
+ $isSeconds = $isSeconds * -1;
+ $isSeconds = "-" . sprintf('%02dh:%02dm', floor($isSeconds / 3600), floor($isSeconds / 60 % 60));
+ } else {
+ $isSeconds = sprintf('%02dh:%02dm', floor($isSeconds / 3600), floor($isSeconds / 60 % 60));
+ }
+ $summsecondsorder = $summseconds;
+ if ($summseconds < 0) {
+ $summseconds = $summseconds * -1;
+ $summseconds = "-" . sprintf('%02dh:%02dm', floor($summseconds / 3600), floor($summseconds / 60 % 60));
+ } else {
+ $summseconds = sprintf('%02dh:%02dm', floor($summseconds / 3600), floor($summseconds / 60 % 60));
+ }
$json['success'] = true;
$json['time']['auto_workinghours'] = $auto_workinghours;
- $json['time']['is'] = sprintf('%02dh:%02dm', floor($isSeconds / 3600), floor($isSeconds / 60 % 60));
+ $json['time']['is'] = $isSeconds;
+ $json['time']['isorder'] = $isorder;
+ $json['time']['isclean'] = $isSecondscleanarray;
$json['time']['must'] = sprintf('%02dh:%02dm', floor($mustSeconds / 3600), floor($mustSeconds / 60 % 60));
+ $json['time']['mustorder'] = $mustSeconds;
$json['time']['holidays'] = $holiDays;
$json['time']['plushours'] = sprintf('%02dh:%02dm', floor($plusHours / 3600), floor($plusHours / 60 % 60));
+ $json['time']['overtime_now'] = sprintf('%02dh:%02dm', floor($overtime_now / 3600), floor($overtime_now / 60 % 60));
+ $json['time']['overtime_noworder'] = $overtime_now;
+ $json['time']['homeoffice'] = $homeofficesum;
+ $json['time']['summseconds'] = $summseconds;
+ $json['time']['summsecondsorder'] = $summsecondsorder;
+ $json['time']['nlztimes'] = $nlzTimes;
+ $json['time']['diet'] = $dietsum;
$json['time']['daysum'] = $daysum;
$json['recordsFiltered'] = $responsecount;
$json['recordsTotal'] = $responsecount;
diff --git a/db/migrations/20240326191604_timerecording_category_add_field_unpaid.php b/db/migrations/20240326191604_timerecording_category_add_field_unpaid.php
new file mode 100644
index 000000000..47f64eaff
--- /dev/null
+++ b/db/migrations/20240326191604_timerecording_category_add_field_unpaid.php
@@ -0,0 +1,30 @@
+getEnvironment() == "thetool") {
+ $table = $this->table("TimerecordingCategory", ["signed" => true]);
+ $table->addColumn("unpaid", "integer", ["null" => false, "default" => '0', "after" => "businesstrip"]);
+ $table->update();
+ }
+
+ if ($this->getEnvironment() == "addressdb") {
+
+ }
+ }
+
+ public function down(): void
+ {
+ if ($this->getEnvironment() == "thetool") {
+ $this->table("TimerecordingCategory")->removeColumn("unpaid")->save();
+ }
+
+ if ($this->getEnvironment() == "addressdb") {
+ }
+ }
+}