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 @@ + + + +
+
+
+
+ +
+

Verrechnung/Abrechnung

+
+
+
+ + +
+
+
+
+
+

Liste aller Mitarbeiter

+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + $value) { + if ($counter > 1) { + $offdays .= "
"; + } + $offdays .= $category . ": " . $value . " Tag(e) "; + $counter++; + } + } else { + $offdays = "keine"; + } + ?> + + + + + + + + + + + + + +
MitarbeiterPersonal Nr.SollstundenIststundenSollabweichungAkuelle ÜberstundenNichtleistungszeitenDiätenHomeoffice Tage
+ € + 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 @@ + + + +
+
+
+
+ +
+

Zeiterfassung Verrechnung/Abrechnung

+
+
+
+ + + +
+
+
+
+
+

Liste aller Abrechnungsmonate

+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
MonatAbgeschlossenAbgeschlossen amAbgeschlossen von
$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 @@ +
+ +
+
+ unpaid) echo 'checked="checked"'; ?> + type="checkbox" name="unpaid" value="1"> +
+
+
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") { + } + } +}