Merge branch 'master' into fronkdev

This commit is contained in:
Frank Schubert
2024-03-12 15:42:35 +01:00
58 changed files with 3172 additions and 872 deletions

2
.gitignore vendored
View File

@@ -11,6 +11,8 @@ todo
files/*
vendor/
data/
logs/
xdebug_traces/
phinx.php
*.sql

View File

@@ -1,105 +1,71 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title><?=MFAPPNAME_FULL?></title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<!-- App favicon -->
<link rel="shortcut icon" href="<?=self::getResourcePath()?>assets/images/favicon.ico">
<head>
<meta charset="utf-8" />
<title><?=MFAPPNAME_FULL?></title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<!-- App favicon -->
<link rel="shortcut icon" href="<?=self::getResourcePath()?>assets/images/favicon.ico">
<!-- App css -->
<link href="<?=self::getResourcePath()?>fontawesome/css/all.min.css?<?=date('U')?>" rel="stylesheet" type="text/css" />
<link href="<?=self::getResourcePath()?>assets/css/bootstrap.min.css?<?=date('U')?>" rel="stylesheet" type="text/css" />
<link href="<?=self::getResourcePath()?>assets/css/icons.css" rel="stylesheet" type="text/css" />
<link href="<?=self::getResourcePath()?>assets/css/app.css?<?=date('U')?>" rel="stylesheet" type="text/css" />
<link href="<?=self::getResourcePath()?>assets/css/leaflet.css" rel="stylesheet" type="text/css" />
<link href="<?=self::getResourcePath()?>assets/css/thetool.css?<?=date('U')?>" rel="stylesheet" type="text/css" />
<link href="<?=self::getResourcePath()?>assets/libs/select2/select2.min.css" rel="stylesheet" type="text/css" />
<link href="<?=self::getResourcePath()?>assets/css/bootstrap-select.min.css" rel="stylesheet" type="text/css" />
<link href="<?=self::getResourcePath()?>css/bootstrap-datepicker3.min.css" rel="stylesheet" type="text/css" />
<link href="<?=self::getResourcePath()?>plugins/summernote/summernote-bs4.css" rel="stylesheet" type="text/css" />
<link href="<?=self::getResourcePath()?>datatables/datatables.min.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="<?=self::getResourcePath()?>js/jquery.min.js"></script>
<script type="text/javascript" src="<?=self::getResourcePath()?>assets/libs/select2/select2.min.js"></script>
<script type="text/javascript" src="<?=self::getResourcePath()?>js/bootstrap-datepicker.min.js"></script>
<script type="text/javascript" src="<?=self::getResourcePath()?>js/bootstrap-datepicker.de.min.js"></script>
<script type="text/javascript" src="<?=self::getResourcePath()?>assets/js/geo/geo.js"></script>
<script type="text/javascript" src="<?=self::getResourcePath()?>assets/js/leaflet.js"></script>
<script type="text/javascript" src="<?=self::getResourcePath()?>assets/js/leaflet.MakiMarkers.js"></script>
<script type="text/javascript" src="<?=self::getResourcePath()?>js/popper.min.js"></script>
<script type="text/javascript" src="<?=self::getResourcePath()?>js/bootstrap.min.js"></script>
<script type="text/javascript" src="<?=self::getResourcePath()?>assets/js/bootstrap-select.min.js"></script>
<script type="text/javascript" src="<?=self::getResourcePath()?>js/bootstrap-autocomplete.min.js"></script>
<script type="text/javascript" src="<?=self::getResourcePath()?>datatables/datatables.min.js"></script>
<?php if(MFAPPNAME == "devthetool"): ?>
<!-- App css -->
<link href="<?=self::getResourcePath()?>fontawesome/css/all.min.css?<?=date('U')?>" rel="stylesheet" type="text/css" />
<link href="<?=self::getResourcePath()?>assets/css/bootstrap.min.css?<?=date('U')?>" rel="stylesheet" type="text/css" />
<link href="<?=self::getResourcePath()?>assets/css/icons.css" rel="stylesheet" type="text/css" />
<link href="<?=self::getResourcePath()?>assets/css/app.css?<?=date('U')?>" rel="stylesheet" type="text/css" />
<link href="<?=self::getResourcePath()?>assets/css/leaflet.css" rel="stylesheet" type="text/css" />
<link href="<?=self::getResourcePath()?>assets/css/thetool.css?<?=date('U')?>" rel="stylesheet" type="text/css" />
<link href="<?=self::getResourcePath()?>assets/libs/select2/select2.min.css" rel="stylesheet" type="text/css" />
<link href="<?=self::getResourcePath()?>assets/css/bootstrap-select.min.css" rel="stylesheet" type="text/css" />
<link href="<?=self::getResourcePath()?>css/bootstrap-datepicker3.min.css" rel="stylesheet" type="text/css" />
<link href="<?=self::getResourcePath()?>plugins/summernote/summernote-bs4.css" rel="stylesheet" type="text/css" />
<link href="<?=self::getResourcePath()?>plugins/notification/notify.min.css" rel="stylesheet" type="text/css" />
<link href="<?=self::getResourcePath()?>datatables/datatables.min.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="<?=self::getResourcePath()?>js/jquery.min.js"></script>
<script type="text/javascript" src="<?=self::getResourcePath()?>assets/libs/select2/select2.min.js"></script>
<script type="text/javascript" src="<?=self::getResourcePath()?>js/bootstrap-datepicker.min.js"></script>
<script type="text/javascript" src="<?=self::getResourcePath()?>js/bootstrap-datepicker.de.min.js"></script>
<script type="text/javascript" src="<?=self::getResourcePath()?>assets/js/geo/geo.js"></script>
<script type="text/javascript" src="<?=self::getResourcePath()?>assets/js/leaflet.js"></script>
<script type="text/javascript" src="<?=self::getResourcePath()?>assets/js/leaflet.MakiMarkers.js"></script>
<script type="text/javascript" src="<?=self::getResourcePath()?>js/popper.min.js"></script>
<script type="text/javascript" src="<?=self::getResourcePath()?>js/bootstrap.min.js"></script>
<script type="text/javascript" src="<?=self::getResourcePath()?>assets/js/bootstrap-select.min.js"></script>
<script type="text/javascript" src="<?=self::getResourcePath()?>js/bootstrap-autocomplete.min.js"></script>
<script type="text/javascript" src="<?=self::getResourcePath()?>datatables/datatables.min.js"></script>
<script type="text/javascript" src="<?=self::getResourcePath()?>plugins/notification/notify.js"></script>
<script type="text/javascript">
window.mfNotify = <?=isset($mfNotify) ? json_encode($mfNotify) : "null"; ?>;
window.TT_CONFIG = {};
<?php
if(isset($JSGlobals) && is_array($JSGlobals) && count($JSGlobals)):
foreach($JSGlobals as $key => $value): ?>
window.TT_CONFIG.<?=$key?> = <?=is_array($value) ? json_encode($value) : "'$value'"; ?>;
<?php endforeach; endif;?>
</script>
<?php if(MFAPPNAME == "devthetool"): ?>
<style type="text/css">
body {
border-left: 8px dashed #f672a7;
}
body {
border-left: 8px dashed #f672a7;
}
</style>
<?php endif; ?>
<?php endif; ?>
</head>
</head>
<body>
<!-- Navigation Bar-->
<header id="topnav">
<?php include(realpath(dirname(__FILE__)."/")."/topbar.php"); ?>
<?php include(realpath(dirname(__FILE__)."/")."/menu.php"); ?>
</header>
<!-- End Navigation Bar-->
<body>
<!-- Navigation Bar-->
<header id="topnav">
<?php include(realpath(dirname(__FILE__)."/")."/topbar.php"); ?>
<?php include(realpath(dirname(__FILE__)."/")."/menu.php"); ?>
</header>
<!-- End Navigation Bar-->
<div class="wrapper">
<div class="container-fluid">
<?php if(isset($_flash_set) && $_flash_set == true): ?>
<?php if(isset($mfError) && !empty($mfError)): ?>
<div class="row mr-1">
<div class="col-md-1"></div>
<div class="col-md-10 alert alert-danger alert-dismissible">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
<h5><i class="icon fas fa-ban"></i> Fehler</h5>
<?=$mfError?>
</div>
</div>
<?php endif; ?>
<?php if(isset($mfWarning) && !empty($mfWarning)): ?>
<div class="row mr-1">
<div class="col-md-1"></div>
<div class="col-md-10 alert alert-warning alert-dismissible">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
<h5><i class="icon fas fa-exclamation-triangle"></i> Warnung</h5>
<?=$mfWarning?>
</div>
</div>
<?php endif; ?>
<?php if(isset($mfInfo) && !empty($mfInfo)): ?>
<div class="row mr-1">
<div class="col-md-1"></div>
<div class="col-md-10 alert alert-info alert-dismissible">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
<h5><i class="icon fas fa-info"></i> Info</h5>
<?=$mfInfo?>
</div>
</div>
<?php endif; ?>
<?php if(isset($mfSuccess) && !empty($mfSuccess)): ?>
<div class="row mr-1">
<div class="col-md-1"></div>
<div class="col-md-10 alert alert-success alert-dismissible">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
<h5><i class="icon fas fa-check"></i> Erfolgreich</h5>
<?=$mfSuccess?>
</div>
</div>
<?php endif; ?>
<?php endif; ?>
<div class="container-fluid">

View File

@@ -177,8 +177,18 @@ if (isset($_GET['returnto']) && $_GET['returnto'] == "device-detail") {
</select>
</div>
</div>
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="autobackup">Autobackup</label>
<div class="col-lg-10">
<div class="custom-control custom-switch mt-1">
<input type="checkbox" <?= ($device->autobackup == "1") ? "checked='checked'" : "" ?> class="custom-control-input" value="1" id="autobackup" name="autobackup">
<label class="custom-control-label no-user-select" for="autobackup">(Es wird täglich um 24:00 ein Device Backup erstellt)</label>
</div>
</div>
</div>
<?php endif; ?>
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="serial">Seriennummer</label>
<div class="col-lg-10">

View File

@@ -67,7 +67,7 @@ $pagination_entity_name = "Device";
<th></th>
<th></th>
<th></th>
<th></th>
<th class="pr-1"></th>
<th></th>
</tr>
</thead>
@@ -97,7 +97,9 @@ $pagination_entity_name = "Device";
} else {
$backup = '<i class="fa-regular fa-ban" title="Kein Configbackup"><span style="display: none">N/A</span></i>';
}
if ($device->autobackup==1) {
$backup = '<i class="fa-regular fa-circle-a mr-1"><span style="display: none">Auto</span></i>'.$backup;
}
if ($device->pop->id) {
$destination = '<a href="' . self::getUrl("Pop", "Detail", ["id" => $device->pop->id]) . '">' . $device->pop->name . '</a>';
} else if ($device->addr_street) {
@@ -153,7 +155,7 @@ $pagination_entity_name = "Device";
var columndefs = {type: 'ip-address', targets: 4};
var columnfilter = [9];
var columnoptions = '<option value=""></option><option value="OK">OK</option><option value="AGED">AGED</option><option value="N/A">N/A</option>';
var columnoptions = '<option value=""></option><option value="OK">OK</option><option value="AGED">AGED</option><option value="N/A">N/A</option><option value="Auto">AUTO</option>';
$(document).ready(function () {
});

View File

@@ -206,10 +206,8 @@ $pagination_entity_name = "Pops";
markers[building.id] = marker;
});
console.log(all_coords);
// calculate center position
mapCenterPos = GetCenterFromDegrees(all_coords);
console.log(mapCenterPos);
buildingMap.setView(mapCenterPos, 12);
return true;
@@ -228,7 +226,6 @@ $pagination_entity_name = "Pops";
filter: filter
}, function (success) {
if (success.status == "OK") {
console.log(success);
if (Array.isArray(success.result.buildings)) {
buildings = success.result.buildings;

View File

@@ -18,7 +18,7 @@ for ($i = 1; $i <= 25; $i++) {
$kw = date('W', $time);
$year = date('Y', $time);
$timestamp_montag = strtotime("{$year}-W{$kw}");
$timestamp_freitag = strtotime("{$year}-W{$kw}-5");
$timestamp_freitag = strtotime("{$year}-W{$kw}-7");
$weeks[$time] = "KW" . $kw . " " . $year . " (" . date('d.m', $timestamp_montag) . "-" . date('d.m', $timestamp_freitag) . ")";
$time = $time - 604800;
}
@@ -126,7 +126,9 @@ $years[time() - 31536000] = date('Y', time() - 31536000);
data-approval="<?= $timerecordingCategories->approval ?>"
data-comment="<?= $timerecordingCategories->require_comment ?>"
data-hourday="<?= $timerecordingCategories->hourday ?>"
data-businesstrip="<?= $timerecordingCategories->businesstrip ?>"><?= $timerecordingCategories->name ?></option>
data-businesstrip="<?= $timerecordingCategories->businesstrip ?>"
data-homeoffice="<?= ($timerecordingCategories->hourday == 1) ? 1 : 0 ?>"><?= $timerecordingCategories->name ?></option>
</option>
<?php
endif;
endforeach; ?>
@@ -176,33 +178,50 @@ $years[time() - 31536000] = date('Y', time() - 31536000);
<label class="col-form-label" for="comment">Anmerkung</label>
<input type="text" id="comment" name="comment" class="form-control"/>
</div>
<div class="form-group col-lg-4" id="div-calc-overtime" style="display:none">
<label class="col-form-label mobile-hide" for="comment">&nbsp;</label>
<div class=" d-block" style="padding: 0.45rem 0.9rem;" id="calc-overtime"></div>
</div>
</div>
<div class="row" id="businesstrip-div">
<div class="col-lg-2 mb-2">
<div class="row">
<div class="col-lg-1 mb-2" id="homeoffice-div">
<div class="form-check text-center mt-1">
<input class="form-check-input" type="checkbox" name="businesstrip" value=""
id="businesstrip">
<label class="form-check-label" for="businesstrip" value="1">
<input class="form-check-input" type="checkbox" name="homeoffice"
id="homeoffice" value="1">
<label class="form-check-label" for="homeoffice">
Homeoffice
</label>
</div>
</div>
<div class="col-lg-2 mb-2 businesstrip-div">
<div class="form-check text-center mt-1">
<input class="form-check-input" type="checkbox" name="businesstrip"
id="businesstrip" value="1">
<label class="form-check-label" for="businesstrip">
Dienstreise > 12KM
</label>
</div>
</div>
<div class="col-lg-2">
<div class="col-lg-2 businesstrip-div">
<input style="display:none" type="text" id="businesstrip_info" name="businesstrip_info"
placeholder="Ort"
class="form-control"/>
</div>
</div>
<div class=" row mt-2">
<div class="col-lg-2 ">
<div class="col-lg-3 ">
<button id="submit-button" type="submit" class="btn btn-primary">Speichern</button>
<button id="cancel-button" type="button" class="btn btn-secondary" style="display:none">
Abbrechen
</button>
<button style="display:none" id="auto-workinghours-button" type="button" class="btn btn-dark">
Arbeitswoche verbuchen
</button>
</div>
</div>
</div>
@@ -290,7 +309,7 @@ $years[time() - 31536000] = date('Y', time() - 31536000);
</div>
<div class="col text-center">
<div class="input-group ">
<label class="col-form-label form-control fixed-state"><span
<label id="plushours-label" class="col-form-label form-control fixed-state"><span
class="text-bold">Gutzeit: </span><span
id="plushours"
class="ml-1 text-normal"></span></label>
@@ -338,7 +357,10 @@ $years[time() - 31536000] = date('Y', time() - 31536000);
let insertUrl = "<?= self::getUrl("Timerecording", "save") ?>";
let deleteUrl = "<?= self::getUrl("Timerecording", "delete") ?>";
let requestUrl = "<?= self::getUrl("Timerecording", "api", ['do' => 'getTimerecordings']) ?>";
let autoWorkinghoursUrl = "<?= self::getUrl("Timerecording", "api", ['do' => 'fillWorkinghours']) ?>";
let checkWorkinghoursUrl = "<?= self::getUrl("Timerecording", "api", ['do' => 'checkWorkinghours']) ?>";
</script>
<script type="text/javascript"
src="<?= self::getResourcePath() ?>js/pages/timerecording/index.js?<?= date('U') ?>"></script>

View File

@@ -0,0 +1,408 @@
<?php include(realpath(dirname(__FILE__) . "/../../$mfLayoutPackage") . "/header.php");
$daysgerm = array("So", "Mo", "Di", "Mi", "Do", "Fr", "Sa");
?>
<link href="<?= self::getResourcePath() ?>assets/css/select2-cstm.css?<?= date('U') ?>" rel="stylesheet"
type="text/css"/>
<style>
.fc-event {
border-radius: 2px;
border: none;
cursor: move;
font-size: 13px;
margin: 3px 7px;
padding: 3px 5px;
text-align: center;
}
.fc-toolbar {
@media (max-width: 767px) {
flex-direction: column;
.fc-toolbar-chunk {
margin-bottom: 12px;
}
}
}
.fc .fc-button-primary:focus {
box-shadow: none;
}
.fc .fc-button:focus {
box-shadow: none;
outline: 0px;
}
.fc .fc-button-primary:not(:disabled).fc-button-active:focus, .fc .fc-button-primary:not(:disabled):active:focus {
box-shadow: none;
}
.popper, .tooltip {
position: absolute;
z-index: 9999;
/* background: #FFC107; */
color: #0f5be9;
width: auto;
/* border-radius: 3px; */
/* box-shadow: 0 0 1px rgba(0, 0, 0, 0.5); */
padding: 10px;
text-align: center;
opacity: 0.9;
}
.tooltip-inner {
max-width: 500px;
padding: 0.4rem 0.8rem;
color: #fff;
text-align: center;
background-color: #2c3e50;
border-radius: 0.2rem;
}
.style5 .tooltip {
background: #1E252B;
color: #FFFFFF;
max-width: 200px;
width: auto;
font-size: .8rem;
padding: .5em 1em;
}
.popper .popper__arrow,
.tooltip .tooltip-arrow {
width: 0;
height: 0;
border-style: solid;
position: absolute;
margin: 5px;
}
.tooltip .tooltip-arrow,
.popper .popper__arrow {
border-color: #FFC107;
}
.style5 .tooltip .tooltip-arrow {
border-color: #1E252B;
}
.popper[x-placement^="top"],
.tooltip[x-placement^="top"] {
margin-bottom: 5px;
}
.popper[x-placement^="top"] .popper__arrow,
.tooltip[x-placement^="top"] .tooltip-arrow {
border-width: 5px 5px 0 5px;
border-left-color: transparent;
border-right-color: transparent;
border-bottom-color: transparent;
bottom: -5px;
left: calc(50% - 5px);
margin-top: 0;
margin-bottom: 0;
}
.popper[x-placement^="bottom"],
.tooltip[x-placement^="bottom"] {
margin-top: 5px;
}
.tooltip[x-placement^="bottom"] .tooltip-arrow,
.popper[x-placement^="bottom"] .popper__arrow {
border-width: 0 5px 5px 5px;
border-left-color: transparent;
border-right-color: transparent;
border-top-color: transparent;
top: -5px;
left: calc(50% - 5px);
margin-top: 0;
margin-bottom: 0;
}
.tooltip[x-placement^="right"],
.popper[x-placement^="right"] {
margin-left: 5px;
}
.popper[x-placement^="right"] .popper__arrow,
.tooltip[x-placement^="right"] .tooltip-arrow {
border-width: 5px 5px 5px 0;
border-left-color: transparent;
border-top-color: transparent;
border-bottom-color: transparent;
left: -5px;
top: calc(50% - 5px);
margin-left: 0;
margin-right: 0;
}
.popper[x-placement^="left"],
.tooltip[x-placement^="left"] {
margin-right: 5px;
}
.popper[x-placement^="left"] .popper__arrow,
.tooltip[x-placement^="left"] .tooltip-arrow {
border-width: 5px 0 5px 5px;
border-top-color: transparent;
border-right-color: transparent;
border-bottom-color: transparent;
right: -5px;
top: calc(50% - 5px);
margin-left: 0;
margin-right: 0;
}
</style>
<script type="text/javascript"
src="<?= self::getResourcePath() ?>assets/js/calendar/moment/moment.min.js?<?= date('U') ?>"></script>
<script type="text/javascript"
src="<?= self::getResourcePath() ?>assets/js/calendar/index.global.min.js?<?= date('U') ?>"></script>
<script type="text/javascript"
src="<?= self::getResourcePath() ?>assets/js/calendar/moment/index.global.min.js?<?= date('U') ?>"></script>
<script type="text/javascript"
src="<?= self::getResourcePath() ?>assets/js/calendar/locales-all.global.min.js?<?= date('U') ?>"></script>
<script type="text/javascript"
src="<?= self::getResourcePath() ?>assets/js/calendar/tooltip.min.js?<?= date('U') ?>"></script>
<script>
document.addEventListener('DOMContentLoaded', function () {
let requestUrl = "<?= self::getUrl("TimerecordingReport", "api", ['do' => 'getTimerecordings', 'datatype' => '3', 'datayear' => time()]) ?>";
var cindex = 1;
var holiDays = [];
var birthdays = [];
<?php
$counter = 1;
foreach ($timerecordingholidays as $timerecordingholiday) :?>
holiDays.push({
id: <?= $counter ?>,
start: '<?= date("Y-m-d", $timerecordingholiday->timestamp) ?>',
end: '<?= date("Y-m-d", $timerecordingholiday->timestamp) ?>',
title: '<?= $timerecordingholiday->description ?>',
description: '<?= $timerecordingholiday->description ?>'
});
<?php
$counter++;
endforeach;
foreach ($timerecordingemployees as $timerecordingemployee) :
if ($timerecordingemployee->birthday) :
$year = date("Y", time());
$year = $year - 1;
$Byear = date("Y", $timerecordingemployee->birthday);
for ($i = 0; $i < 5; $i++) :
$age = $year - $Byear;
?>
birthdays.push({
id: <?= $counter ?>,
start: '<?= date("$year-m-d", $timerecordingemployee->birthday) ?>',
end: '<?= date("$year-m-d", $timerecordingemployee->birthday) ?>',
title: '<?= $timerecordingemployee->user->name ?> (<?= $age ?>)',
description: 'Geburtstag <?= $timerecordingemployee->user->name ?> (<?= $age ?>)'
});
<?php
$year++;
endfor;
$counter++;
endif;
endforeach; ?>
cindex = <?= $counter ?>;
$.getJSON(requestUrl, function (data) {
}).done(function (json) {
var bgcolors = ['rgba(251, 71, 71,0.2)', 'rgba(253, 126, 20, 0.25)', 'rgba(91, 71, 251, 0.2)', 'rgba(71, 251, 151, 0.2)', 'rgba(251, 71, 194, 0.2)', 'rgba(20, 251, 253, 0.25)'];
//read data from json
var json = json.data;
var holidays = [];
var colorcount = 0;
var oldname = "";
$.each(json, function (index, value) {
if (oldname != value.user.user) {
colorcount++;
if (colorcount > 5) {
colorcount = 0;
}
oldname = value.user.user;
}
if (value.hourday.hourday!='5') {
holidays.push({
id: cindex,
backgroundColor: bgcolors[colorcount],
start: value.cstart.cstart,
end: value.cend.cend,
title: value.ccategory.ccategory + " " + value.user.user,
description: value.ccategory.ccategory + " " + value.user.user
});
cindex++;
}
oldname = value.user.user;
});
var initialLocaleCode = 'en';
var calendarEl = document.getElementById('fullcalendar');
var containerEl = document.getElementById('external-events');
var localeSelectorEl = document.getElementById('locale-selector');
var curYear = '2024';
var curMonth = '02';
// Calendar Event Source
// Birthday Events Source
var holiDayEvents = {
id: 1,
backgroundColor: 'rgba(255, 0, 0 , 1)',
borderColor: 'rgba(255, 0, 0 , 1)',
textColor: '#fff',
events: holiDays
};
var holidayEvents = {
id: 7,
backgroundColor: 'rgba(0,204,204,.25)',
borderColor: 'rgb(8 241 8)',
textColor: '#000',
events: holidays
};
var birthdayEvents = {
id: 5,
backgroundColor: 'rgb(68 15 241 / 76%)',
borderColor: 'rgb(68 15 241 / 76%)',
textColor: '#fff',
events: birthdays
};
var initialLocaleCode = 'en';
var calendarEl = document.getElementById('calendar');
var calendar = new FullCalendar.Calendar(calendarEl, {
locale: 'de',
headerToolbar: {
left: "prev,today,next",
center: 'title',
right: 'dayGridMonth,timeGridWeek,timeGridDay,listMonth'
},
eventDidMount: function (info) {
var tooltip = new Tooltip(info.el, {
title: info.event.extendedProps.description,
placement: 'top',
trigger: 'hover',
container: 'body'
});
},
editable: true,
droppable: true, // this allows things to be dropped onto the calendar
fixedWeekCount: true,
// height: 300,
initialView: 'dayGridMonth',
timeZone: 'UTC',
hiddenDays: [],
navLinks: 'true',
events: [],
height: 800,
eventSources: [birthdayEvents, holiDayEvents, holidayEvents]
});
calendar.render();
});
});
</script>
<style>
.edit-button {
color: #007bff;
cursor: pointer;
}
.approved-open {
background-color: #fdb751 !important;
color: #000;
border-radius: 5px;
}
.approved-closed {
background-color: #96ff68 !important;
color: #000;
border-radius: 5px;
padding-top: 2px;
}
.fa-clock {
color: #ff9b00;
font-size: 15px;
}
.edit-placeholder {
height: 15px;
width: 22px;
display: inline-block;
}
.fa-square-check {
color: #23b900;
font-size: 17px;
vertical-align: middle;
margin-bottom: 2px;
margin-right: 3px;
}
</style>
<link href="<?= self::getResourcePath() ?>assets/css/datatables-std.css?<?= date('U') ?>" rel="stylesheet"
type="text/css"/>
<!-- start page title -->
<div class="row">
<div class="col-12">
<div class="page-title-box">
<div class="page-title-right">
<ol class="breadcrumb m-0">
<li class="breadcrumb-item"><a href="<?= self::getUrl("Dashboard") ?>"><?= MFAPPNAME_SLUG ?></a>
</li>
<li class="breadcrumb-item active">Abwesenheitskalender</li>
</ol>
</div>
<h4 class="page-title">Abwesenheitskalender</h4>
</div>
</div>
</div>
<!-- end page title -->
<div class="card text-center">
<div class="card-body mb-3 ">
<div class="row ">
<div class="col-12">
<div class="float-left">
<h4 class="header-title">Abwesenheitskalender</h4>
</div>
</div>
</div>
<div class="row justify-content-center">
<div class="col-12 col-lg-10">
<div id='calendar'></div>
</div>
</div>
</div>
</div>
</div>
</div>
<script type="text/javascript">
var hidesearch = [2, 3, 4, 8];
var columnfilter = [7];
var columnoptions = '<option value=""></option><option value="Offen">Offen</option><option value="Genehmigt">Genehmigt</option><option value="Abgelehnt">Abgelehnt</option>';
$(document).ready(function () {
});
</script>
<script type="text/javascript"
src="<?= self::getResourcePath() ?>assets/js/datatables-std.js?<?= date('U') ?>"></script>
<?php include(realpath(dirname(__FILE__) . "/../../$mfLayoutPackage") . "/footer.php"); ?>

View File

@@ -65,7 +65,8 @@
<label class="col-lg-2 col-form-label" for="approval">Genehmigungspflichtig</label>
<div class="col-lg-3">
<div class="form-check">
<input id="approval" class="form-check-input" <?php if ($timerecordingcategoriess->approval) echo 'checked="checked"'; ?>
<input id="approval"
class="form-check-input" <?php if ($timerecordingcategoriess->approval) echo 'checked="checked"'; ?>
type="checkbox" name="approval" value="1" id="olt">
</div>
</div>
@@ -75,25 +76,30 @@
Pflichtfeld</label>
<div class="col-lg-3">
<div class="form-check">
<input id="require_comment" class="form-check-input" <?php if ($timerecordingcategoriess->require_comment) echo 'checked="checked"'; ?>
<input id="require_comment"
class="form-check-input" <?php if ($timerecordingcategoriess->require_comment) echo 'checked="checked"'; ?>
type="checkbox" name="require_comment" value="1">
</div>
</div>
</div>
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="businesstrip">Dienstreisemöglichkeit</label>
<label class="col-lg-2 col-form-label"
for="businesstrip">Dienstreisemöglichkeit</label>
<div class="col-lg-3">
<div class="form-check">
<input id="businesstrip" class="form-check-input" <?php if ($timerecordingcategoriess->businesstrip) echo 'checked="checked"'; ?>
<input id="businesstrip"
class="form-check-input" <?php if ($timerecordingcategoriess->businesstrip) echo 'checked="checked"'; ?>
type="checkbox" name="businesstrip" value="1">
</div>
</div>
</div>
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="only_admin">Nur für Buchhaltung zu buchen</label>
<label class="col-lg-2 col-form-label" for="only_admin">Nur für Buchhaltung zu
buchen</label>
<div class="col-lg-3">
<div class="form-check">
<input id="only_admin" class="form-check-input" <?php if ($timerecordingcategoriess->only_admin) echo 'checked="checked"'; ?>
<input id="only_admin"
class="form-check-input" <?php if ($timerecordingcategoriess->only_admin) echo 'checked="checked"'; ?>
type="checkbox" name="only_admin" value="1">
</div>
</div>
@@ -130,6 +136,15 @@
$('form').on('blur', 'input[type=number]', function (e) {
$(this).off('wheel.disableScroll')
});
$(document).ready(function () {
$("body").on("change", "#hourday", function () {
if ($(this).val() == 5) {
$("#only_admin").prop("checked", true);
} else {
}
});
$("#hourday").change();
});
</script>
<?php include(realpath(dirname(__FILE__) . "/../../$mfLayoutPackage") . "/footer.php"); ?>

View File

@@ -33,7 +33,7 @@
</div>
</div>
</div>
<table id="datatable" class="table table-striped table-hover table-sm">
<table id="datatable" class="table table-hover table-sm">
<thead>
<tr>
<th class="text-center">Beizeichnung</th>

View File

@@ -89,6 +89,15 @@ $daysSelect .= "</select>";
value="<?= ($timerecordingemployees->startdate) ? date('Y-m-d', $timerecordingemployees->startdate): "" ?>"/>
</div>
</div>
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="birthday">Geburtstag</label>
<div class="col-lg-2">
<input type="date" id="birthday" name="birthday"
class="form-control"
value="<?= ($timerecordingemployees->birthday) ? date('Y-m-d', $timerecordingemployees->birthday): "" ?>"/>
</div>
</div>
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="holidays">Initiale Urlaubstage</label>
<div class="col-lg-1">
@@ -106,6 +115,14 @@ $daysSelect .= "</select>";
value="<?= str_replace(".", ",", $timerecordingemployees->plushours / 3600) ?>"/>
</div>
</div>
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="overtime">Initiale Überstunden</label>
<div class="col-lg-1">
<input type="text" id="overtime" name="overtime"
class="form-control"
value="<?= str_replace(".", ",", $timerecordingemployees->overtime / 3600) ?>"/>
</div>
</div>
<div class="form-group row">
<label class="col-lg-2 col-form-label"
for="auto_workinghours">Schnellbuchung</label>
@@ -186,7 +203,6 @@ $daysSelect .= "</select>";
function checktime() {
var sum = 0;
$(".wtime").each(function (index) {
console.log($(this).find('.timeend').val());
var newdatestart = new Date('2020/01/01 ' + $(this).find('.timestart').val() + ':00');
var newdateend = new Date('2020/01/01 ' + $(this).find('.timeend').val() + ':00');
var differenz = (newdateend - newdatestart) / 1000;

View File

@@ -5,6 +5,14 @@ $type[3] = "Lehrling";
?>
<link href="<?= self::getResourcePath() ?>assets/css/datatables-std.css?<?= date('U') ?>" rel="stylesheet"
type="text/css"/>
<style>
.border-dark {
border-color: #cbcbcb !important;
}
.border-bottom {
border-bottom: 1px dotted #adadad !important;
}
</style>
<!-- start page title -->
<div class="row">
<div class="col-12">
@@ -34,7 +42,7 @@ $type[3] = "Lehrling";
</div>
</div>
<div class="col-lg-12">
<table id="datatable" class="table table-striped table-hover table-sm">
<table id="datatable" class="table table-hover table-sm">
<thead>
<tr>
<th class="text-center">Mitarbeiter</th>
@@ -42,6 +50,9 @@ $type[3] = "Lehrling";
<th class="text-center">Start Zeitaufzeichnung</th>
<th class="text-center">Sollzeiten</th>
<th class="text-center">Sollstunden</th>
<th class="text-center">Mehrstunden</th>
<th class="text-center">Überstunden</th>
<th class="text-center">Offene Urlaube</th>
<th class="text-center edit-width">Schnellbuchung</th>
<th class="edit-width"></th>
</tr>
@@ -53,6 +64,9 @@ $type[3] = "Lehrling";
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
@@ -65,14 +79,34 @@ $type[3] = "Lehrling";
} else {
$sum = "";
}
if ($timerecordingemployees[$timerecordinguser->id]['plushours_now'] < 0) {
$plusHours = $timerecordingemployees[$timerecordinguser->id]['plushours_now'] * -1;
$plusHours = "-" . sprintf('%02dh:%02dm', floor($plusHours / 3600), floor($plusHours / 60 % 60));
} else {
$plusHours = $timerecordingemployees[$timerecordinguser->id]['plushours_now'];
$plusHours = sprintf('%02dh:%02dm', floor($plusHours / 3600), floor($plusHours / 60 % 60));
}
if ($timerecordingemployees[$timerecordinguser->id]['overtime_now'] < 0) {
$overTime = $timerecordingemployees[$timerecordinguser->id]['overtime_now'] * -1;
$overTime = "-" . sprintf('%02dh:%02dm', floor($overTime / 3600), floor($overTime / 60 % 60));
} else {
$overTime = $timerecordingemployees[$timerecordinguser->id]['overtime_now'];
$overTime = sprintf('%02dh:%02dm', floor($overTime / 3600), floor($overTime / 60 % 60));
}
?>
<tr>
<td><?= $timerecordinguser->name ?></td>
<td><?= $type[$timerecordingemployees[$timerecordinguser->id]['type']] ?></td>
<td class="text-center"><?= ($timerecordingemployees[$timerecordinguser->id]['startdate']) ? date("d.m.Y", $timerecordingemployees[$timerecordinguser->id]['startdate']) : "-" ?></td>
<td class="text-center"><?= ($timerecordingworkinghours) ? $timerecordingworkinghours[$timerecordinguser->id]['datetimetext'] : "" ?></td>
<td class="text-center text-nowrap"><?= ($timerecordingworkinghours) ? $timerecordingworkinghours[$timerecordinguser->id]['datetimetext'] : "" ?></td>
<td class="text-center"><?= $sum ?></td>
<td class="text-center"
data-order="<?= ($timerecordingemployees[$timerecordinguser->id]['plushours_now']) ? $timerecordingemployees[$timerecordinguser->id]['plushours_now'] : 0 ?>"><?= $plusHours ?></td>
<td class="text-center" data-order="<?= $timerecordingemployees[$timerecordinguser->id]['overtime_now'] ?>"><?= $overTime ?></td>
<td class="text-center" data-order="<?= ($timerecordingemployees[$timerecordinguser->id]['holidays_now']) ? $timerecordingemployees[$timerecordinguser->id]['holidays_now'] : '' ?>"><?= ($timerecordingemployees[$timerecordinguser->id]['holidays_now']) ? $timerecordingemployees[$timerecordinguser->id]['holidays_now'] . ' Tage' : '' ?> </td>
<td class="text-center"><?= ($timerecordingemployees[$timerecordinguser->id]['auto_workinghours'] == '1') ? 'Ja' : 'Nein' ?></td>
<td style="text-align: left; letter-spacing: 4px; font-size: 1.1em;">
<a href="<?= self::getUrl("TimerecordingEmployee", "edit", ['id' => $timerecordingemployees[$timerecordinguser->id]['id'], "userid" => $timerecordinguser->id]) ?>"><i
@@ -91,7 +125,7 @@ $type[3] = "Lehrling";
<script type="text/javascript">
var hidesearch = [6];
var hidesearch = [3, 4, 5, 6, 7, 9];
$(document).ready(function () {

View File

@@ -37,7 +37,7 @@ $daysgerm = array("So", "Mo", "Di", "Mi", "Do", "Fr", "Sa");
</div>
</div>
</div>
<table id="datatable" class="table table-striped table-hover table-sm">
<table id="datatable" class="table table-hover table-sm">
<thead>
<tr>
<th style="width: 200px;" class="text-center">Datum</th>

View File

@@ -182,9 +182,9 @@ $daysgerm = array("So", "Mo", "Di", "Mi", "Do", "Fr", "Sa");
<script type="text/javascript">
var hidesearch = [2, 3, 4, 8];
var columnfilter = [7];
var columnoptions = '<option value=""></option><option value="Offen">Offen</option><option value="Genehmigt">Genehmigt</option><option value="Abgelehnt">Abgelehnt</option>';
var columnoptions = '<option value=""></option><option selected="selected" value="Offen">Offen</option><option value="Genehmigt">Genehmigt</option><option value="Abgelehnt">Abgelehnt</option>';
$(document).ready(function () {
$('#selectsearch').change();
});
</script>

View File

@@ -23,7 +23,7 @@ for ($i = 1; $i <= 25; $i++) {
$kw = date('W', $time);
$year = date('Y', $time);
$timestamp_montag = strtotime("{$year}-W{$kw}");
$timestamp_freitag = strtotime("{$year}-W{$kw}-5");
$timestamp_freitag = strtotime("{$year}-W{$kw}-7");
$weeks[$time] = "KW" . $kw . " " . $year . " (" . date('d.m', $timestamp_montag) . "-" . date('d.m', $timestamp_freitag) . ")";
$time = $time - 604800;
@@ -93,6 +93,9 @@ $years[time() - 31536000] = date('Y', time() - 31536000);
background-color: #d0fbd9;
}
.form-check-label {
margin-top: 2px;
}
</style>
<!-- start page title -->
<div class="row">
@@ -102,10 +105,10 @@ $years[time() - 31536000] = date('Y', time() - 31536000);
<ol class="breadcrumb m-0">
<li class="breadcrumb-item"><a href="<?= self::getUrl("Dashboard") ?>"><?= MFAPPNAME_SLUG ?></a>
</li>
<li class="breadcrumb-item active">Buchungen</li>
<li class="breadcrumb-item active">Auswertungen/Korrekturen</li>
</ol>
</div>
<h4 class="page-title">Buchungen</h4>
<h4 class="page-title">Auswertungen/Korrekturen</h4>
</div>
</div>
</div>
@@ -139,7 +142,9 @@ $years[time() - 31536000] = date('Y', time() - 31536000);
<option value="<?= $timerecordingCategories->id ?>"
data-approval="<?= $timerecordingCategories->approval ?>"
data-comment="<?= $timerecordingCategories->require_comment ?>"
data-hourday="<?= $timerecordingCategories->hourday ?>"><?= $timerecordingCategories->name ?></option>
data-hourday="<?= $timerecordingCategories->hourday ?>"
data-businesstrip="<?= $timerecordingCategories->businesstrip ?>"
data-homeoffice="<?= ($timerecordingCategories->hourday == 1) ? 1 : 0 ?>"><?= $timerecordingCategories->name ?></option>
<?php
endforeach; ?>
</select>
@@ -184,30 +189,72 @@ $years[time() - 31536000] = date('Y', time() - 31536000);
</div>
</div>
<div class="form-group col-lg-2">
<label class="col-form-label" for="comment">Anmerkung</label>
<input type="text" id="comment" name="comment" class="form-control"
<div id="days-div" class="col-lg-1" style="display:none">
<div class="form-row">
<div class="form-group col">
<label class=" col-form-label" for="days">Anzahl Tage</label>
<input type="number" id="days" name="days" class="form-control "
placeholder=""/>
</div>
</div>
</div>
<div class="form-group col-lg-2">
<label class="col-form-label" for="comment">Anmerkung</label>
<input type="text" id="comment" name="comment" class="form-control">
</div>
<div class="form-group col-lg-2" id="div-calc-overtime" style="display:none">
<label class="col-form-label mobile-hide" for="comment">&nbsp;</label>
<div class=" d-block" style="padding: 0.45rem 0.9rem;" id="calc-overtime"></div>
</div>
</div>
</div>
<div class=" row mt-2">
<div class="col-lg-2 ">
<button id="submit-button" type="submit" class="btn btn-primary">Speichern</button>
<button id="cancel-button" type="button" class="btn btn-secondary" style="display:none">Abbrechen
</button>
</div>
</div>
<div class=" row mt-2">
<div class="col-lg-4" id="message-box">
<div class="row">
<div class="col-lg-1 mb-2" id="homeoffice-div">
<div class="form-check text-center mt-1">
<input class="form-check-input" type="checkbox" name="homeoffice"
id="homeoffice" value="1">
<label class="form-check-label" for="homeoffice">
Homeoffice
</label>
</div>
</div>
<div class="col-lg-2 mb-2 businesstrip-div">
<div class="form-check text-center mt-1">
<input class="form-check-input" type="checkbox" name="businesstrip"
id="businesstrip" value="1">
<label class="form-check-label" for="businesstrip">
Dienstreise > 12KM
</label>
</div>
</div>
<div class="col-lg-2 businesstrip-div">
<input style="display:none" type="text" id="businesstrip_info" name="businesstrip_info"
placeholder="Ort"
class="form-control"/>
</div>
</div>
<div class=" row mt-2">
<div class="col-lg-2 ">
<button id="submit-button" type="submit" class="btn btn-primary">Speichern</button>
<button id="cancel-button" type="button" class="btn btn-secondary" style="display:none">
Abbrechen
</button>
</div>
</div>
<div class=" row mt-2">
<div class="col-lg-4" id="message-box">
</div>
</div>
</div>
</div>
</form>
</div>
<div class="card">
<div class="card-body mb-3">
<div class="form-group module-row row mb-3">
@@ -271,32 +318,32 @@ $years[time() - 31536000] = date('Y', time() - 31536000);
</div>
</div>
</div>
<!-- <div class="col-lg-3">-->
<!-- <div class="form-row">-->
<!-- <div class="col text-center">-->
<!-- <div class="input-group ">-->
<!-- <label class="col-form-label form-control fixed-state"><span-->
<!-- class="text-bold">Urlaubstage: </span><span id="holidays"-->
<!-- class="ml-1 text-normal"></span></label>-->
<!-- </div>-->
<!-- </div>-->
<!-- <div class="col text-center">-->
<!-- <div class="input-group ">-->
<!-- <label class="col-form-label form-control fixed-state"><span-->
<!-- class="text-bold">Gutzeit: </span><span-->
<!-- id="plushours"-->
<!-- class="ml-1 text-normal"></span></label>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- <div class="col-lg-3">-->
<!-- <div class="form-row">-->
<!-- <div class="col text-center">-->
<!-- <div class="input-group ">-->
<!-- <label class="col-form-label form-control fixed-state"><span-->
<!-- class="text-bold">Urlaubstage: </span><span id="holidays"-->
<!-- class="ml-1 text-normal"></span></label>-->
<!-- </div>-->
<!-- </div>-->
<!-- <div class="col text-center">-->
<!-- <div class="input-group ">-->
<!-- <label class="col-form-label form-control fixed-state"><span-->
<!-- class="text-bold">Gutzeit: </span><span-->
<!-- id="plushours"-->
<!-- class="ml-1 text-normal"></span></label>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
</div>
<table id="datatable" class="table table-hover table-sm">
<thead>
<tr>
<th class="text-center text-nowrap ">Mitarbeiter</th>
<th style="min-width: 250px;" class="text-center text-nowrap ">Mitarbeiter</th>
<th style="width: 200px;" class="text-center text-nowrap ">Datum</th>
<th class="text-nowrap edit-width text-center">Von</th>
<th class="text-nowrap edit-width text-center">Bis</th>
@@ -332,7 +379,8 @@ $years[time() - 31536000] = date('Y', time() - 31536000);
let insertUrl = "<?= self::getUrl("Timerecording", "save") ?>";
let deleteUrl = "<?= self::getUrl("Timerecording", "delete") ?>";
let requestUrl = "<?= self::getUrl("TimerecordingReport", "api", ['do' => 'getTimerecordings']) ?>";
let requestTimesUrl = "<?= self::getUrl("TimerecordingReport", "api", ['do' => 'getTimerecordingsTimes']) ?>";
let checkWorkinghoursUrl = "<?= self::getUrl("Timerecording", "api", ['do' => 'checkWorkinghours']) ?>";
</script>
<script type="text/javascript"

View File

@@ -1,129 +1,87 @@
<?/** @var TYPE_NAME $git_merge_ts */?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title><?=MFAPPNAME_FULL?></title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<!-- App favicon -->
<link rel="shortcut icon" href="<?=self::getResourcePath()?>assets/images/favicon.ico">
<head>
<meta charset="utf-8" />
<title><?=MFAPPNAME_FULL?></title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<!-- App favicon -->
<link rel="shortcut icon" href="<?=self::getResourcePath()?>assets/images/favicon.ico">
<!-- App css -->
<link href="<?=self::getResourcePath()?>fontawesome/css/all.min.css?<?=$git_merge_ts?>" rel="stylesheet" type="text/css" />
<link href="<?=self::getResourcePath()?>assets/css/bootstrap.min.css?<?=$git_merge_ts?>" rel="stylesheet" type="text/css" />
<link href="<?=self::getResourcePath()?>assets/css/icons.css" rel="stylesheet" type="text/css" />
<link href="<?=self::getResourcePath()?>assets/css/app.css?<?=$git_merge_ts?>" rel="stylesheet" type="text/css" />
<link href="<?=self::getResourcePath()?>assets/css/leaflet.css" rel="stylesheet" type="text/css" />
<link href="<?=self::getResourcePath()?>assets/css/thetool.css?<?=$git_merge_ts?>" rel="stylesheet" type="text/css" />
<link href="<?=self::getResourcePath()?>assets/libs/select2/select2.min.css" rel="stylesheet" type="text/css" />
<link href="<?=self::getResourcePath()?>assets/css/bootstrap-select.min.css" rel="stylesheet" type="text/css" />
<link href="<?=self::getResourcePath()?>css/bootstrap-datepicker3.min.css" rel="stylesheet" type="text/css" />
<link href="<?=self::getResourcePath()?>plugins/summernote/summernote-bs4.css" rel="stylesheet" type="text/css" />
<link href="<?=self::getResourcePath()?>datatables/datatables.min.css?<?=$git_merge_ts?>" rel="stylesheet" type="text/css" />
<?php if(isset($additionalCSS) && is_array($additionalCSS) && count($additionalCSS)): ?>
<?php foreach($additionalCSS as $css): ?>
<!-- App css -->
<link href="<?=self::getResourcePath()?>fontawesome/css/all.min.css?<?=$git_merge_ts?>" rel="stylesheet" type="text/css" />
<link href="<?=self::getResourcePath()?>assets/css/bootstrap.min.css?<?=$git_merge_ts?>" rel="stylesheet" type="text/css" />
<link href="<?=self::getResourcePath()?>assets/css/icons.css" rel="stylesheet" type="text/css" />
<link href="<?=self::getResourcePath()?>assets/css/app.css?<?=$git_merge_ts?>" rel="stylesheet" type="text/css" />
<link href="<?=self::getResourcePath()?>assets/css/leaflet.css" rel="stylesheet" type="text/css" />
<link href="<?=self::getResourcePath()?>assets/css/thetool.css?<?=$git_merge_ts?>" rel="stylesheet" type="text/css" />
<link href="<?=self::getResourcePath()?>assets/libs/select2/select2.min.css" rel="stylesheet" type="text/css" />
<link href="<?=self::getResourcePath()?>assets/css/bootstrap-select.min.css" rel="stylesheet" type="text/css" />
<link href="<?=self::getResourcePath()?>css/bootstrap-datepicker3.min.css" rel="stylesheet" type="text/css" />
<link href="<?=self::getResourcePath()?>plugins/summernote/summernote-bs4.css" rel="stylesheet" type="text/css" />
<link href="<?=self::getResourcePath()?>plugins/notification/notify.min.css" rel="stylesheet" type="text/css" />
<link href="<?=self::getResourcePath()?>datatables/datatables.min.css?<?=$git_merge_ts?>" rel="stylesheet" type="text/css" />
<?php if(isset($additionalCSS) && is_array($additionalCSS) && count($additionalCSS)): ?>
<?php foreach($additionalCSS as $css): ?>
<link rel="stylesheet" href="<?=self::getResourcePath()?><?=$css?>?<?=$git_merge_ts?>" />
<?php endforeach; ?>
<?php endif; ?>
<script type="text/javascript" src="<?=self::getResourcePath()?>js/jquery.min.js"></script>
<script type="text/javascript" src="<?=self::getResourcePath()?>assets/libs/select2/select2.full.min.js"></script>
<script type="text/javascript" src="<?=self::getResourcePath()?>js/bootstrap-datepicker.min.js"></script>
<script type="text/javascript" src="<?=self::getResourcePath()?>js/bootstrap-datepicker.de.min.js"></script>
<script type="text/javascript" src="<?=self::getResourcePath()?>assets/js/geo/geo.js"></script>
<script type="text/javascript" src="<?=self::getResourcePath()?>assets/js/leaflet.js"></script>
<script type="text/javascript" src="<?=self::getResourcePath()?>assets/js/leaflet.MakiMarkers.js"></script>
<script type="text/javascript" src="<?=self::getResourcePath()?>js/popper.min.js"></script>
<script type="text/javascript" src="<?=self::getResourcePath()?>js/bootstrap.min.js"></script>
<script type="text/javascript" src="<?=self::getResourcePath()?>assets/js/bootstrap-select.min.js"></script>
<script type="text/javascript" src="<?=self::getResourcePath()?>js/bootstrap-autocomplete.min.js"></script>
<script type="text/javascript" src="<?=self::getResourcePath()?>datatables/datatables.min.js?<?=$git_merge_ts?>"></script>
<?php endforeach; ?>
<?php endif; ?>
<?php if(isset($JSGlobals) && is_array($JSGlobals) && count($JSGlobals)): ?>
<script type="text/javascript">
window.TT_CONFIG = {};
<?php foreach($JSGlobals as $key => $value): ?>
window.TT_CONFIG.<?=$key?> = <?=is_array($value) ? json_encode($value) : "'$value'"; ?>;
<?php endforeach; ?>
</script>
<?php endif; ?>
<?php if(isset($additionalJS) && is_array($additionalJS) && count($additionalJS)): ?>
<?php foreach($additionalJS as $js): ?>
<script type="text/javascript" src="<?=self::getResourcePath()?>js/jquery.min.js"></script>
<script type="text/javascript" src="<?=self::getResourcePath()?>assets/libs/select2/select2.full.min.js"></script>
<script type="text/javascript" src="<?=self::getResourcePath()?>js/bootstrap-datepicker.min.js"></script>
<script type="text/javascript" src="<?=self::getResourcePath()?>js/bootstrap-datepicker.de.min.js"></script>
<script type="text/javascript" src="<?=self::getResourcePath()?>assets/js/geo/geo.js"></script>
<script type="text/javascript" src="<?=self::getResourcePath()?>assets/js/leaflet.js"></script>
<script type="text/javascript" src="<?=self::getResourcePath()?>assets/js/leaflet.MakiMarkers.js"></script>
<script type="text/javascript" src="<?=self::getResourcePath()?>js/popper.min.js"></script>
<script type="text/javascript" src="<?=self::getResourcePath()?>js/bootstrap.min.js"></script>
<script type="text/javascript" src="<?=self::getResourcePath()?>assets/js/bootstrap-select.min.js"></script>
<script type="text/javascript" src="<?=self::getResourcePath()?>js/bootstrap-autocomplete.min.js"></script>
<script type="text/javascript" src="<?=self::getResourcePath()?>datatables/datatables.min.js?<?=$git_merge_ts?>"></script>
<script type="text/javascript" src="<?=self::getResourcePath()?>plugins/notification/notify.js"></script>
<script type="text/javascript">
window.mfNotify = <?=isset($mfNotify) ? json_encode($mfNotify) : "null"; ?>;
window.TT_CONFIG = {};
<?php
if(isset($JSGlobals) && is_array($JSGlobals) && count($JSGlobals)):
foreach($JSGlobals as $key => $value): ?>
window.TT_CONFIG.<?=$key?> = <?=is_array($value) ? json_encode($value) : "'$value'"; ?>;
<?php endforeach; endif;?>
</script>
<?php if(isset($additionalJS) && is_array($additionalJS) && count($additionalJS)): ?>
<?php foreach($additionalJS as $js): ?>
<script src="<?=self::getResourcePath()?><?=$js?>?<?=$git_merge_ts?>"></script>
<?php endforeach; ?>
<?php endif; ?>
<?php if(MFAPPNAME == "devthetool"): ?>
<?php endforeach; ?>
<?php endif; ?>
<?php if(MFAPPNAME == "devthetool"): ?>
<style type="text/css">
body {
border-left: 8px dashed #f672a7;
}
body {
border-left: 8px dashed #f672a7;
}
</style>
<?php endif; ?>
<?php endif; ?>
</head>
<body>
<script type="text/javascript">
baseurl = '<?=self::getResourcePath()?>';
</script>
<!-- Navigation Bar-->
<header id="topnav">
<?php include(realpath(dirname(__FILE__)."/")."/topbar.php"); ?>
<?php include(realpath(dirname(__FILE__)."/")."/menu.php"); ?>
</header>
<!-- End Navigation Bar-->
</head>
<body>
<script type="text/javascript">
baseurl = '<?=self::getResourcePath()?>';
</script>
<!-- Navigation Bar-->
<header id="topnav">
<?php include(realpath(dirname(__FILE__)."/")."/topbar.php"); ?>
<?php include(realpath(dirname(__FILE__)."/")."/menu.php"); ?>
</header>
<!-- End Navigation Bar-->
<div class="wrapper pl-0 pl-lg-1 pr-0 pr-lg-1 ">
<div class="container-fluid">
<?php if(isset($_flash_set) && $_flash_set == true): ?>
<?php if(isset($mfError) && !empty($mfError)): ?>
<div class="row mr-1">
<div class="col-md-1"></div>
<div class="col-md-10 alert alert-danger alert-dismissible">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
<h5><i class="icon fas fa-ban"></i> Fehler</h5>
<?=$mfError?>
</div>
</div>
<?php endif; ?>
<?php if(isset($mfWarning) && !empty($mfWarning)): ?>
<div class="row mr-1">
<div class="col-md-1"></div>
<div class="col-md-10 alert alert-warning alert-dismissible">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
<h5><i class="icon fas fa-exclamation-triangle"></i> Warnung</h5>
<?=$mfWarning?>
</div>
</div>
<?php endif; ?>
<?php if(isset($mfInfo) && !empty($mfInfo)): ?>
<div class="row mr-1">
<div class="col-md-1"></div>
<div class="col-md-10 alert alert-info alert-dismissible">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
<h5><i class="icon fas fa-info"></i> Info</h5>
<?=$mfInfo?>
</div>
</div>
<?php endif; ?>
<?php if(isset($mfSuccess) && !empty($mfSuccess)): ?>
<div class="row mr-1">
<div class="col-md-1"></div>
<div class="col-md-10 alert alert-success alert-dismissible">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
<h5><i class="icon fas fa-check"></i> Erfolgreich</h5>
<?=$mfSuccess?>
</div>
</div>
<?php endif; ?>
<?php endif; ?>
<div class="container-fluid">

View File

@@ -36,9 +36,10 @@
<li class="has-submenu"><a href="#"><i class="far fa-fw fa-calendar-clock"></i>Zeiterfassung <div class="arrow-down"></div></a>
<ul class="submenu">
<li><a href="<?=self::getUrl("Timerecording")?>"><i class="far fa-fw fa-calendar text-info"></i> Buchungen</a></li>
<li><a href="<?=self::getUrl("TimerecordingCalendar")?>"><i class="far fa-fw fa-calendar-days text-info"></i> Abwesenheitskalender</a></li>
<?php if ($me->can('Fibu')): ?>
<li><a href="<?=self::getUrl("TimerecordingPermit")?>"><i class="far fa-fw fa-calendar-check text-info"></i> Freigaben</a></li>
<li><a href="<?=self::getUrl("TimerecordingReport")?>"><i class="far fa-fw fa-chart-pie text-info"></i> Auswertungen</a></li>
<li><a href="<?=self::getUrl("TimerecordingReport")?>"><i class="far fa-fw fa-chart-pie text-info"></i> Auswertung/Korrektur</a></li>
<li><a href="<?=self::getUrl("TimerecordingCategory")?>"><i class="far fa-fw fa-list text-info"></i> Buchungsarten</a></li>
<li><a href="<?=self::getUrl("TimerecordingHoliday")?>"><i class="far fa-fw fa-umbrella-beach text-info"></i> Feiertage</a></li>
<li><a href="<?=self::getUrl("TimerecordingEmployee")?>"><i class="far fa-fw fa-user text-info"></i> Personaladministration</a></li>

View File

@@ -32,46 +32,46 @@ class AddressModel {
public $sepa_date;
public $allow_contact;
public $allow_spin;
public $note;
public $create_by;
public $edit_by;
public $create;
public $edit;
public static function create(Array $data) {
public static function create(array $data) {
$model = new Address();
foreach($data as $field => $value) {
if(property_exists(get_called_class(), $field)) {
foreach ($data as $field => $value) {
if (property_exists(get_called_class(), $field)) {
$model->$field = $value;
}
}
$me = new User();
$me->loadMe();
if(!is_numeric($model->create_by) && !$model->create_by) {
if (!is_numeric($model->create_by) && !$model->create_by) {
$model->create_by = $me->id;
}
if(!is_numeric($model->edit_by) && !$model->edit_by) {
if (!is_numeric($model->edit_by) && !$model->edit_by) {
$model->edit_by = $me->id;
}
if(!array_key_exists("note", $data)) {
if (!array_key_exists("note", $data)) {
$model->note = "";
}
return $model;
}
public static function getFirst($filter = null) {
$db = FronkDB::singleton();
$where = self::getSqlFilter($filter);
//mfLoghandler::singleton()->debug($where);
$sql = "SELECT Address.* FROM Address
LEFT JOIN Addresstype ON (Addresstype.address_id = Address.id)
LEFT JOIN Country ON (Country.id = Address.country_id)
@@ -80,14 +80,14 @@ class AddressModel {
ORDER BY company, lastname, firstname, zip, city, Address.id
LIMIT 1
";
$res = $db->query($sql);
//$res = $db->select("Address", "*", "$where ORDER BY company, lastname, firstname, zip, city LIMIT 1");
if($db->num_rows($res)) {
if ($db->num_rows($res)) {
$data = $db->fetch_object($res);
$item = new Address($data);
if($item->id) {
if ($item->id) {
return $item;
} else {
return null;
@@ -95,83 +95,83 @@ class AddressModel {
}
return null;
}
public static function getOne($id) {
if(!is_numeric($id) || !$id) {
if (!is_numeric($id) || !$id) {
throw new Exception("Invalid number", 400);
}
$item = [];
$db = FronkDB::singleton();
$res = $db->select("Address", "*", "id=$id LIMIT 1");
if($db->num_rows($res)) {
if ($db->num_rows($res)) {
$data = $db->fetch_object($res);
$item = new Address($data);
}
return $item;
}
public static function getAll() {
$items = [];
$db = FronkDB::singleton();
$res = $db->select("Address", "*");
if($db->num_rows($res)) {
while($data = $db->fetch_object($res)) {
if ($db->num_rows($res)) {
while ($data = $db->fetch_object($res)) {
$items[] = new Address($data);
}
}
return $items;
}
public static function getLastCustomerNumber() {
$db = FronkDB::singleton();
$res = $db->select("Address","customer_number", "customer_number > 0 AND customer_number < 200000 ORDER BY customer_number DESC LIMIT 1");
if($db->num_rows($res)) {
$res = $db->select("Address", "customer_number", "customer_number > 0 AND customer_number < 200000 ORDER BY customer_number DESC LIMIT 1");
if ($db->num_rows($res)) {
$data = $db->fetch_object($res);
if($data->customer_number + 1 >= 200000) {
$res = $db->select("Address","customer_number", "customer_number > 0 ORDER BY customer_number DESC LIMIT 1");
if ($data->customer_number + 1 >= 200000) {
$res = $db->select("Address", "customer_number", "customer_number > 0 ORDER BY customer_number DESC LIMIT 1");
$data = $db->fetch_object($res);
return $data->customer_number;
}
return $data->customer_number;
}
return false;
}
public static function byNetwork($network_id, $addresstype) {
if(!is_numeric($network_id) || !$network_id) {
if (!is_numeric($network_id) || !$network_id) {
return false;
}
$db = FronkDB::singleton();
$addresses = [];
// get all addresses of network
$sql = "SELECT Address.id as id FROM `Address`
LEFT JOIN NetworkAddress ON (NetworkAddress.address_id = Address.id)
WHERE NetworkAddress.type = '$addresstype'
AND network_id = $network_id
GROUP BY id";
$res = $db->query($sql);
if($db->num_rows($res)) {
while($data = $db->fetch_object($res)) {
if ($db->num_rows($res)) {
while ($data = $db->fetch_object($res)) {
$addresses[] = new Address($data->id);
}
}
return $addresses;
}
public static function count($filter) {
$db = FronkDB::singleton();
$where = self::getSqlFilter($filter);
$sql = "SELECT COUNT(*) as cnt FROM (
SELECT Address.id as address_id
@@ -182,21 +182,21 @@ class AddressModel {
GROUP BY Address.id
) as tbl";
//mfLoghandler::singleton()->debug($sql);
$res = $db->query($sql);
if($db->num_rows($res)) {
if ($db->num_rows($res)) {
$data = $db->fetch_object($res);
return (int)$data->cnt;
}
return 0;
}
public static function search($filter, $limit = false) {
//var_dump($filter);exit;
$items = [];
$db = FronkDB::singleton();
$where = self::getSqlFilter($filter);
$have = [];
/*$sql = "SELECT Address.* FROM Address, Addresstype
@@ -210,20 +210,20 @@ class AddressModel {
WHERE $where
GROUP BY Address.id
ORDER BY company, lastname, firstname, zip, city, Address.id";
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'];
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)) {
if ($db->num_rows($res)) {
while ($data = $db->fetch_object($res)) {
$items[] = new Address($data);
//$have[] = $data->id;
}
@@ -241,29 +241,29 @@ class AddressModel {
}
}
}*/
return $items;
}
private static function getSqlFilter($filter) {
$where = "1=1 ";
//var_dump($filter);exit;
if(array_key_exists("customer_number", $filter)) {
if (array_key_exists("customer_number", $filter)) {
$cn = $filter["customer_number"];
if(is_numeric($cn)) {
if (is_numeric($cn)) {
$where .= " AND customer_number=$cn";
} elseif($cn === true) {
} elseif ($cn === true) {
$where .= " AND customer_number > 0";
} elseif($cn === false || $cn === null) {
} elseif ($cn === false || $cn === null) {
$where .= " AND customer_number IS NULL";
}
}
if(array_key_exists("fibu_account_number", $filter)) {
if (array_key_exists("fibu_account_number", $filter)) {
$fan = $filter["fibu_account_number"];
if($fan) {
if(is_numeric($fan)) {
if ($fan) {
if (is_numeric($fan)) {
$where .= " AND fibu_account_number=$fan";
} else {
$fan = FronkDB::singleton()->escape($fan);
@@ -271,159 +271,167 @@ class AddressModel {
}
}
}
if(array_key_exists("fibu_supplier_number", $filter)) {
if (array_key_exists("fibu_supplier_number", $filter)) {
$fsn = $filter["fibu_supplier_number"];
if(is_numeric($fsn)) {
if (is_numeric($fsn)) {
$where .= " AND fibu_supplier_number=$fsn";
}
}
if(array_key_exists("fibu_or_supplier_account_number", $filter)) {
if (array_key_exists("fibu_or_supplier_account_number", $filter)) {
$fsn = $filter["fibu_or_supplier_account_number"];
if($fsn) {
if ($fsn) {
$where .= " AND (fibu_account_number LIKE '$fsn' OR fibu_supplier_number LIKE '$fsn')";
}
}
if(array_key_exists("fibu_primary_account", $filter)) {
if (array_key_exists("fibu_primary_account", $filter)) {
$fpa = $filter["fibu_primary_account"];
if($fpa) {
if ($fpa) {
$where .= " AND fibu_primary_account=1";
} else {
$where .= " AND fibu_primary_account=0";
}
}
if(array_key_exists("customer_or_fibu_numbers", $filter)) {
if (array_key_exists("customer_or_fibu_numbers", $filter)) {
$cn = $filter["customer_or_fibu_numbers"];
if($cn === true) {
if ($cn === true) {
$where .= " AND (customer_number > 0 OR fibu_account_number > 0 OR fibu_supplier_number > 0)";
} elseif($cn === false || $cn === null) {
} elseif ($cn === false || $cn === null) {
$where .= " AND customer_number IS NULL AND fibu_account_number IS NULL AND fibu_supplier_number IS NULL";
}
}
if(array_key_exists("spin", $filter)) {
if (array_key_exists("spin", $filter)) {
$spin = FronkDB::singleton()->escape($filter["spin"]);
if($spin) {
if ($spin) {
$where .= " AND spin='$spin'";
}
}
if(array_key_exists("company", $filter)) {
if (array_key_exists("company", $filter)) {
$company = FronkDB::singleton()->escape($filter["company"]);
if($company) {
if ($company) {
$where .= " AND company like '%$company%'";
}
}
if(array_key_exists("firstname", $filter)) {
if (array_key_exists("firstname", $filter)) {
$firstname = FronkDB::singleton()->escape($filter["firstname"]);
if($firstname) {
if ($firstname) {
$where .= " AND firstname like '%$firstname%'";
}
}
if(array_key_exists("lastname", $filter)) {
if (array_key_exists("lastname", $filter)) {
$lastname = FronkDB::singleton()->escape($filter["lastname"]);
if($lastname) {
if ($lastname) {
$where .= " AND lastname like '%$lastname%'";
}
}
if(array_key_exists("mergedName", $filter)) {
if (array_key_exists("mergedName", $filter)) {
$name = FronkDB::singleton()->escape($filter["mergedName"]);
if($name) {
if ($name) {
$where .= " AND (CONCAT(firstname, ' ', lastname) like '%$name%' OR CONCAT(lastname, ' ', firstname) like '%$name%' )";
}
}
if(array_key_exists("street", $filter)) {
if (array_key_exists("street", $filter)) {
$street = FronkDB::singleton()->escape($filter["street"]);
if($street) {
if ($street) {
$where .= " AND street like '%$street%'";
}
}
if(array_key_exists("zip", $filter)) {
if (array_key_exists("zip", $filter)) {
$zip = FronkDB::singleton()->escape($filter["zip"]);
if($zip) {
if ($zip) {
$where .= " AND zip like '%$zip%'";
}
}
if(array_key_exists("city", $filter)) {
if (array_key_exists("city", $filter)) {
$city = FronkDB::singleton()->escape($filter["city"]);
if($city) {
if ($city) {
$where .= " AND city like '%$city%'";
}
}
if(array_key_exists("country", $filter)) {
if (array_key_exists("country", $filter)) {
$country = FronkDB::singleton()->escape($filter["country"]);
if($country) {
if ($country) {
$where .= " AND (Country.name like '%$country%' OR Country.isocode = '$country')";
}
}
if(array_key_exists("email", $filter)) {
if (array_key_exists("email", $filter)) {
$email = FronkDB::singleton()->escape($filter["email"]);
if($email) {
if ($email) {
$where .= " AND email like '%$email%'";
}
}
if(array_key_exists("pfm", $filter)) {
if (array_key_exists("pfm", $filter)) {
$pfm = FronkDB::singleton()->escape($filter["pfm"]);
if($pfm) {
if ($pfm) {
$where .= " AND (phone like '%$pfm%' OR fax like '%$pfm%' OR mobile like '%$pfm%' )";
}
}
if(array_key_exists("billing_type", $filter)) {
if (array_key_exists("billing_type", $filter)) {
$billing_type = FronkDB::singleton()->escape($filter["billing_type"]);
if($billing_type) {
if ($billing_type) {
$where .= " AND billing_type='$billing_type'";
}
}
if (array_key_exists("id", $filter)) {
$id = $filter["id"];
if (is_numeric($id)) {
$where .= " AND Address.id=$id";
} elseif (is_array($id) && count($id)) {
$where .= " AND Address.id IN (" . implode(",", $id) . ")";
}
}
/*
* Address Type
*/
if(array_key_exists("addresstype", $filter) && is_array($filter['addresstype']) && count($filter['addresstype'])) {
if (array_key_exists("addresstype", $filter) && is_array($filter['addresstype']) && count($filter['addresstype'])) {
$at = $filter['addresstype'];
$in = [];
foreach(TT_ROLES as $role) {
if(in_array($role, $at)) {
foreach (TT_ROLES as $role) {
if (in_array($role, $at)) {
$in[] = "Addresstype.type = '$role'";
}
}
$or = "";
if(count($in)) {
if (count($in)) {
$or = implode(" OR ", $in);
$where .= " AND ( $or )";
}
}
//var_dump($filter);exit;
if(array_key_exists("parent_id", $filter)) {
if (array_key_exists("parent_id", $filter)) {
$parentid = $filter['parent_id'];
if($parentid === null || $parent_id == "null") {
if ($parentid === null || $parent_id == "null") {
$where .= " AND parent_id IS NULL";
} elseif(is_numeric($parentid)) {
} elseif (is_numeric($parentid)) {
$where .= " AND parent_id=$parentid";
}
}
if(array_key_exists("create_by", $filter)) {
if (array_key_exists("create_by", $filter)) {
$create_by = $filter['create_by'];
if(is_numeric($create_by)) {
if (is_numeric($create_by)) {
$where .= " AND Address.create_by=$create_by";
} elseif(is_array($create_by) && count($create_by)) {
$where .= " AND Address.create_by IN (". implode(",",$create_by).")";
} elseif (is_array($create_by) && count($create_by)) {
$where .= " AND Address.create_by IN (" . implode(",", $create_by) . ")";
}
}
/*
@@ -433,42 +441,42 @@ class AddressModel {
$where .= " AND parent_id IS NULL";
}
}*/
if(array_key_exists("create>", $filter)) {
if (array_key_exists("create>", $filter)) {
$create = $filter['create>'];
if(is_numeric($create)) {
if (is_numeric($create)) {
$where .= " AND Address.create > $create";
}
}
if(array_key_exists("create<", $filter)) {
if (array_key_exists("create<", $filter)) {
$create = $filter['create<'];
if(is_numeric($create)) {
if (is_numeric($create)) {
$where .= " AND Address.create < $create";
}
}
if(array_key_exists("edit>", $filter)) {
if (array_key_exists("edit>", $filter)) {
$edit = $filter['edit>'];
if(is_numeric($edit)) {
if (is_numeric($edit)) {
$where .= " AND Address.edit > $edit";
}
}
if(array_key_exists("edit<", $filter)) {
if (array_key_exists("edit<", $filter)) {
$edit = $filter['edit<'];
if(is_numeric($edit)) {
if (is_numeric($edit)) {
$where .= " AND Address.edit < $edit";
}
}
// custom where clause
if(array_key_exists("add-where", $filter)) {
$where .= " ".$filter['add-where'];
if (array_key_exists("add-where", $filter)) {
$where .= " " . $filter['add-where'];
}
//var_dump($filter, $where);exit;
return $where;
}
}
}

View File

@@ -21,6 +21,7 @@ class DeviceApicontroller extends mfBaseApicontroller
$deviceReturn[$key]['serial'] = $device->serial;
$deviceReturn[$key]['last_config_backup'] = $device->last_config_backup;
$deviceReturn[$key]['manufactor'] = $device->devicetype->devicemanufactor->name;
$deviceReturn[$key]['autobackup'] = $device->autobackup;
}

View File

@@ -250,30 +250,57 @@ class DashboardController extends mfBaseController {
return $orders;
//var_dump($orders);exit;
}
private function getPartnerOrdersByStatus($preordercampaign_id = [], $gemeinde_id = false) {
$orders = [];
if($gemeinde_id) {
if ($gemeinde_id) {
$preorders = PreorderModel::searchActive(["preordercampaign_id" => $preordercampaign_id, "gemeinde_id" => $gemeinde_id]);
} else {
$preorders = PreorderModel::searchActive(["preordercampaign_id" => $preordercampaign_id]);
$preorders = PreorderModel::searchActive(["preordercampaign_id" => $preordercampaign_id], false, false, true);
}
foreach($preorders as $preorder) {
$name = $preorder->partner->getCompanyOrName();
if(!$name) $name = "Kein Partner";
if(!array_key_exists($name, $orders)) {
$preorderStatus = PreorderstatusModel::getAll();
$preorderStatus = array_column($preorderStatus, null, 'id');
$partners = [];
// log add partnerids from preorders
$parnerIDs = [];
foreach ($preorders as $preorder) {
if (!in_array($preorder->partner_id, $parnerIDs))
$parnerIDs[] = $preorder->partner_id;
}
foreach ($preorders as $preorder) {
$partnerId = $preorder->partner_id;
if (!array_key_exists($partnerId, $partners) && $partnerId !== null) {
$partner = AddressModel::getFirst(["id" => $partnerId]);
$partners[$partnerId] = $partner->getCompanyOrName();
$name = $partners[$partnerId];
} else if ($partnerId === null) {
$name = "Kein Partner";
} else {
$name = $partners[$partnerId];
}
if (!array_key_exists($name, $orders)) {
$orders[$name] = [];
$orders[$name]["total"] = 0;
}
if(!array_key_exists($preorder->status->id, $orders[$name])) {
$orders[$name][$preorder->status->id] = 0;
$status_id = $preorder->status_id;
$status_code = $preorderStatus[$status_id]->code;
if (!array_key_exists($preorder->status_id, $orders[$name])) {
$orders[$name][$preorder->status_id] = 0;
}
$orders[$name][$preorder->status->id]++;
$orders[$name][$preorder->status_id]++;
$orders[$name]["total"]++;
}
//var_dump($orders);exit;
return $orders;
}

View File

@@ -102,6 +102,8 @@ class DeviceController extends mfBaseController
$data = [];
$data['name'] = trim($r->name);
$data['devicetype_id'] = $r->devicetype_id;
$data['autobackup'] = trim($r->autobackup);
if (trim($r->pop_id) == "0") {
$data['pop_id'] = NULL;
} else {
@@ -127,6 +129,9 @@ class DeviceController extends mfBaseController
$data['gps_lat'] = $r->gps_lat;
$data['gps_long'] = $r->gps_long;
}
if ($data['autobackup'] != "1") {
$data['autobackup'] = "0";
}
$data['ip'] = $r->ip;
$data['mac'] = $r->mac;
$data['serial'] = $r->serial;

View File

@@ -16,6 +16,7 @@ class DeviceModel
public $gps_lat = null;
public $addr_city = null;
public $gps_long = null;
public $autobackup = null;
public $create_by = null;
public $snmp_version = null;
public $edit_by = null;

View File

@@ -350,11 +350,11 @@ class PreorderModel {
return self::count($filter);
}
public static function searchActive($filter = [], $limit = false, $returnDBRessource = false) {
if(!is_array($filter)) return false;
if(!array_key_exists("deleted", $filter)) {
public static function searchActive($filter = [], $limit = false, $returnDBRessource = false, $returnArray = false) {
if (!is_array($filter)) return false;
if (!array_key_exists("deleted", $filter)) {
$filter["deleted"] = null;
}
@@ -362,8 +362,8 @@ class PreorderModel {
&& !array_key_exists("<status_id", $filter) && !array_key_exists(">status_id", $filter) && !array_key_exists("status_id", $filter) ) {
$filter["<status_code"] = 899;
}
return self::search($filter, $limit, $returnDBRessource);
return self::search($filter, $limit, $returnDBRessource, $returnArray);
}
public static function count($filter) {
@@ -387,8 +387,8 @@ class PreorderModel {
}
return 0;
}
public static function search($filter = [], $limit = false, $returnDBRessource = false) {
public static function search($filter = [], $limit = false, $returnDBRessource = false, $returnArray = false) {
$items = [];
$db = FronkDB::singleton();
@@ -425,9 +425,13 @@ class PreorderModel {
if($returnDBRessource) {
return $res;
}
while($data = $db->fetch_object($res)) {
$items[] = new Preorder($data);
while ($data = $db->fetch_object($res)) {
if ($returnArray) {
$items[] = $data;
} else {
$items[] = new Preorder($data);
}
}
}
return $items;

View File

@@ -60,13 +60,12 @@ class RaspberryDisplayController extends mfBaseController
}
protected function getConfig() {
$ip = $_SERVER['REMOTE_ADDR'];
$hostname = $this->request->hostname;
$displays = RaspberryDisplayModel::getByHostnameAndIp($hostname, $ip);
$displays = RaspberryDisplayModel::getByHostname($hostname);
if ($displays === null) {
die("No display found for this hostname and ip:" . $hostname . " X " . $ip);
die("No display found for this hostname and ip:" . $hostname . " X ");
}
return array_map(function ($display) {
@@ -82,7 +81,7 @@ class RaspberryDisplayController extends mfBaseController
protected function apiAction() {
$do = $this->request->do;
if (!$this->me->is("employee") && !in_array($do, ["getDisplays", "change", "reboot"])) {
if ($do !== "getConfig" && !$this->me->is("employee")) {
$this->redirect("dashboard");
}

View File

@@ -29,11 +29,11 @@ class RaspberryDisplayModel
return null;
}
public static function getByHostnameAndIp($hostname, $ip)
public static function getByHostname($hostname)
{
$db = FronkDB::singleton();
$res = $db->select("RaspberryDisplay", "*", "hostname = '$hostname' AND ip_address = '$ip'");
$res = $db->select("RaspberryDisplay", "*", "hostname = '$hostname'");
//fetch 2 rows
if ($db->num_rows($res)) {

View File

@@ -18,6 +18,9 @@ class TimerecordingController extends mfBaseController
protected function indexAction()
{
$this->updatePlushours($this->me->id);
$this->updateHolidays($this->me->id);
$timerecordingCategoriess = TimerecordingCategoryModel::getAll();
$this->layout()->set("timerecordingCategoriess", $timerecordingCategoriess);
$this->layout()->setTemplate("Timerecording/Index");
@@ -30,6 +33,7 @@ class TimerecordingController extends mfBaseController
$dataweek = $this->request->dataweek;
$datamonth = $this->request->datamonth;
$datayear = $this->request->datayear;
$ajax = $this->request->ajax;
$data = [];
@@ -37,10 +41,16 @@ class TimerecordingController extends mfBaseController
case "getTimerecordings":
$return = $this->getTimerecordingsApi($datatype, $dataweek, $datamonth, $datayear);
break;
case "fillWorkinghours":
$return = $this->fillWorkinghours($dataweek);
break;
case "checkWorkinghours":
$return = $this->checkWorkingHours($ajax);
break;
default:
$return = false;
}
echo $do;
if (!is_array($return) || !count($return)) {
$data = ["status" => "error"];
$this->returnJson($data);
@@ -86,6 +96,9 @@ class TimerecordingController extends mfBaseController
} else {
$userid = $this->me->id;
}
if (!$endtime) {
$endtime = strtotime(date("Y-m-d", $starttime) . " 23:59:00");
}
$searchArray = ['user_id' => $userid, 'starttime' => $starttime, 'endtime' => $endtime];
if ($id) {
@@ -102,23 +115,177 @@ class TimerecordingController extends mfBaseController
return $result;
}
protected function updateOpenTimerecording()
{
$r = $this->request;
$date = strtotime($r->date . " 23:59:00");
if ($r->user_id) {
$userid = $r->user_id;
} else {
$userid = $this->me->id;
}
$searchArray = ['user_id' => $userid, 'type' => 'opentimerecording'];
$timerecordings = TimerecordingModel::search($searchArray);
$timerecordingssave = new Timerecording($timerecordings[0]->id);
$data = [];
$data['end'] = $date;
$timerecordingssave->update($data);
$id = $timerecordingssave->save();
if ($timerecordingssave->id) {
if ($r->ajax == 1) {
$message = "Buchung erfolgreich angelegt";
$result['state'] = "success";
$result['message'] = "$message";
echo json_encode($result);
die();
}
} else {
if ($r->ajax == 1) {
$message = "Buchung konnte nicht angelegt werden";
$result['state'] = "error";
$result['error'] = "$message";
echo json_encode($result);
die();
}
}
}
protected function checkWorkingHours($ajax = 0)
{
$r = $this->request;
$starttime = strtotime($r->date . " " . $r->start . ":00");
$endtime = strtotime($r->date . " " . $r->end . ":00");
$date = $r->date;
if ($r->user_id) {
$userid = $r->user_id;
} else {
$userid = $this->me->id;
}
$workinghours = TimerecordingEmployeeWorkingHourModel::search(['user_id' => $userid]);
$realHolidays = TimerecordingHolidayModel::getAll();
foreach ($realHolidays as $realHoliday) {
$realholiDay[date('Y-m-d', $realHoliday->timestamp)] = $realHoliday->timestamp;
}
if ($realholiDay[$date]) {
$result['state'] = "error";
$result['error'] = "Kein Zeitausgleich an einem Feiertag möglich";
echo json_encode($result);
die();
}
foreach ($workinghours as $workinghour) {
$whstart = strtotime(date('Y-m-d', time()) . " " . $workinghour->start . ":00");
$whend = strtotime(date('Y-m-d', time()) . " " . $workinghour->end . ":00");
if (!$workingHours[$workinghour->day]) {
$workingHours[$workinghour->day] = $whend - $whstart;
} else {
$workingHours[$workinghour->day] = $workingHours[$workinghour->day] + $whend - $whstart;
}
}
if (!$workingHours[date("w", $starttime)]) {
$result['state'] = "error";
$result['error'] = "Kein Zeitausgleich außerhalb der Arbeitszeiten möglich";
echo json_encode($result);
die();
}
$maxTime = $workingHours[date("w", $starttime)];
$isTime = $endtime - $starttime;
$cleanTime = $isTime;
if ($maxTime < $isTime) {
$result['state'] = "error";
$result['error'] = "Zeitausgleich kann maximal " . sprintf('%02dh:%02dm', floor($maxTime / 3600), floor($maxTime / 60 % 60)) . " an diesem Tag betragen.";
echo json_encode($result);
die();
}
$employee = TimerecordingEmployeeModel::search(['user_id' => $userid]);
$plushours = $employee[0]->plushours_now * 1.25;
$overtime = $employee[0]->overtime * 1.5;
$overtimesum = $plushours + $overtime;
if ($overtimesum < $isTime) {
if ($overtimesum < 0) {
$overtimesum = 0;
}
$result['state'] = "error";
$result['error'] = "Maximal verfügbarer ZA: " . sprintf('%02dh:%02dm', floor($overtimesum / 3600), floor($overtimesum / 60 % 60)) . ".";
echo json_encode($result);
die();
}
if ($plushours >= $isTime) {
$isTime = $isTime * 0.8;
$return['hours'] = $isTime;
} elseif ($plushours <= 0) {
$isTime = $isTime * 0.66666666666666666666666666666667;
$return ['hours_overtime'] = $isTime;
} else {
$isTime25 = $plushours;
$isTime50 = $isTime - $plushours;
$isTime25 = $isTime25 * 0.8;
$isTime50 = $isTime50 * 0.66666666666666666666666666666667;
$isTime = $isTime25 + $isTime50;
$return['hours'] = $isTime25;
$return['hours_overtime'] = $isTime50;
}
if ($ajax == 1) {
if ($r->ajax == 1) {
if ($isTime<0) {
$isTime = 0;
}
if ($cleanTime<0) {
$cleanTime = 0;
}
$result['state'] = "success";
$result['message'] = "<span class='text-bold'>Abzug:</span> " . sprintf('%02dh:%02dm', floor($isTime / 3600), floor($isTime / 60 % 60)) . " <span class='text-bold ml-1'>Zeitwert:</span> " . sprintf('%02dh:%02dm', floor($cleanTime / 3600), floor($cleanTime / 60 % 60));
echo json_encode($result);
die();
}
} else {
return $return;
}
}
protected function saveAction()
{
$r = $this->request;
$id = $r->id;
$enddate = $r->enddate;
if (!$enddate && $r->start && $r->end) {
$hourday = $r->hourday;
if ($hourday == 4) {
$this->updateOpenTimerecording();
}
$data = [];
if ($hourday == 1 || $hourday == 6) {
$starttime = strtotime($r->date . " " . $r->start . ":00");
$endtime = strtotime($r->date . " " . $r->end . ":00");
} elseif ($enddate) {
if ($hourday == 6) {
$data = $this->checkWorkingHours();
}
} elseif ($hourday == 2) {
$starttime = strtotime($r->date . " 00:00:00");
$endtime = strtotime($enddate . " 23:59:00");
} else if (!$enddate && !$r->start && !$r->end) {
} else if ($hourday == 3) {
$starttime = strtotime($r->date . " 00:00:00");
$endtime = NULL;
} else if ($hourday == 5) {
$starttime = strtotime($r->date . " 00:00:00");
$endtime = strtotime($r->date . " 23:59:00");
}
$result = $this->checkTimerecording($starttime, $endtime, $id);
if ($hourday != 5) {
$result = $this->checkTimerecording($starttime, $endtime, $id);
}
if ($result['state'] == "error") {
if ($r->ajax == 1) {
echo json_encode($result);
@@ -140,28 +307,73 @@ class TimerecordingController extends mfBaseController
$mode = "add";
}
$data = [];
if ($r->user_id) {
$data['user_id'] = $r->user_id;
} else {
$data['user_id'] = $this->me->id;
}
$data['start'] = $starttime;
$data['end'] = $endtime;
$data['timerecordingCategory_id'] = trim($r->timerecordingCategory_id);
$data['comment'] = trim($r->comment);
$data['businesstrip'] = $r->businesstrip;
$data['businesstrip_info'] = $r->businesstrip_info;
$data['homeoffice'] = $r->homeoffice;
$data['days'] = $r->days;
if (!$data['businesstrip'] || $data['businesstrip'] == "false") {
$data['businesstrip'] = 0;
}
if (!$data['homeoffice'] || $data['homeoffice'] == "false") {
$data['homeoffice'] = 0;
}
if (!$data['days'] || $data['days'] == "false") {
$data['days'] = 0;
}
if ($r->businesstrip == 1 && !$r->businesstrip_info) {
$result['state'] = "error";
$result['error'] = "Dienstreiseort darf nicht leer sein";
echo json_encode($result);
die();
}
if (!$data['businesstrip_info']) {
$data['businesstrip_info'] = NULL;
}
if (!$data['user_id']) {
if ($r->ajax == 1) {
$result['state'] = "error";
$result['error'] = "Benutzer darf nicht leer sein";
echo json_encode($result);
die();
}
$this->layout()->setFlash("Benutzer darf nicht leer sein", "error");
$this->redirect("Timerecording");
}
if ($data['start'] < 1577833200) {
if ($r->ajax == 1) {
$result['state'] = "error";
$result['error'] = "Ungültige Startzeit";
echo json_encode($result);
die();
}
$this->layout()->setFlash("Ungültige Startzeit", "error");
$this->redirect("Timerecording");
}
if ($data['end'] && $data['end'] < 1577833200) {
if ($r->ajax == 1) {
$result['state'] = "error";
$result['error'] = "Ungültige Endzeit";
echo json_encode($result);
die();
}
$this->layout()->setFlash("Ungültige Endzeit", "error");
$this->redirect("Timerecording");
}
if (!$data['timerecordingCategory_id']) {
$data['timerecordingCategory_id'] = NULL;
@@ -195,7 +407,7 @@ class TimerecordingController extends mfBaseController
}
if ($id) {
$timerecordingCategoriess = TimerecordingCategoryModel::search(['id' => $data['timerecordingCategory_id']]);
if ($timerecordingCategoriess[0]->approval == "1") {
if ($timerecordingCategoriess[0]->approval == "1" && !$r->user_id) {
$body = 'Beantrag von: ' . $this->me->name . '
';
$body .= 'Buchungsart: ' . $timerecordingCategoriess[0]->name . '
@@ -204,14 +416,27 @@ class TimerecordingController extends mfBaseController
$body .= 'von: ' . date("d.m.Y H:i", $data['start']) . ' bis: ' . date("H:i", $data['end']);
} else if ($timerecordingCategoriess[0]->hourday == "2") {
$body .= 'von: ' . date("d.m.Y", $data['start']) . ' bis: ' . date("d.m.Y", $data['end']);
} else if ($timerecordingCategoriess[0]->hourday == "6") {
$body .= 'von: ' . date("d.m.Y H:i", $data['start']) . ' bis: ' . date("H:i", $data['end']);
}
$email = new Emailnotification();
$email->setSubject('Antrag für ' . $timerecordingCategoriess[0]->name . ' erstellt');
$email->setBody($body);
$email->setFrom('zeiterfassung@xinon.at', 'Xinon Zeiterfassung');
$email->setTo('daniel.spitzer@inode.at');
$email->setFrom(TT_TIMERECORDING_EMAIL, TT_TIMERECORDING_EMAIL_NAME);
$email->setTo($this->me->email);
$email->send();
$email = new Emailnotification();
$email->setSubject('Antrag für ' . $timerecordingCategoriess[0]->name . ' erstellt (' . $this->me->name . ')');
$email->setBody($body);
$email->setFrom(TT_TIMERECORDING_EMAIL, TT_TIMERECORDING_EMAIL_NAME);
$email->setTo(TT_TIMERECORDING_EMAIL);
$email->send();
}
if ($data['timerecordingCategory_id'] == "3" || $timerecordingCategoriess[0]->hourday == "5") {
$this->updateHolidays($data['user_id']);
}
$this->updatePlushours($data['user_id']);
}
if ($mode == "edit") {
@@ -229,22 +454,149 @@ class TimerecordingController extends mfBaseController
$this->redirect("Timerecording");
}
public function updateHolidays($userid)
{
$employee = TimerecordingEmployeeModel::search(['user_id' => $userid]);
if ($employee) {
$employee = $employee[0];
$holidays = $employee->holidays;
$holidays_now = $employee->holidays_now;
$holidays_timestamp = $employee->holidays_timestamp;
$workinghours = TimerecordingEmployeeWorkingHourModel::search(['user_id' => $userid]);
$realHolidays = TimerecordingHolidayModel::getAll();
foreach ($realHolidays as $realHoliday) {
$realholiDay[date('Y-m-d', $realHoliday->timestamp)] = $realHoliday->timestamp;
}
if (!$holidays_timestamp) {
//$holidays_timestamp = $employee->startdate;
$holidays_timestamp = strtotime('2024-01-01 00:00:00');
$holidays_now = $holidays;
}
$timerecordings = TimerecordingModel::search(['user_id' => $userid, 'start' => $holidays_timestamp, 'timerecordingCategory_id' => 3]);
$timerecordingscorrections = TimerecordingModel::search(['user_id' => $userid, 'start' => $holidays_timestamp, 'days' => 1]);
foreach ($timerecordings as $timerecording) {
$daycounter = ($timerecording->end - $timerecording->start) / 86400;
$daycounter = intval(round($daycounter, 0, PHP_ROUND_HALF_DOWN));
$daycounter = $daycounter * 86400;
if (is_int($daycounter)) {
for ($i = 86400; $i <= $daycounter; $i = $i + 86400) {
$holidayDays[date("Y-m-d", $timerecording->start + $i - 86400)] = 1;
}
}
}
protected function getTimerecordingsApi($datatype, $dataweek, $datamonth, $datayear)
foreach ($workinghours as $workinghour) {
$whstart = strtotime(date('Y-m-d', time()) . " " . $workinghour->start . ":00");
$whend = strtotime(date('Y-m-d', time()) . " " . $workinghour->end . ":00");
if (!$workingHours[$workinghour->day]) {
$workingHours[$workinghour->day] = $whend - $whstart;
} else {
$workingHours[$workinghour->day] = $workingHours[$workinghour->day] + $whend - $whstart;
}
}
//check if holiday is already in the list
foreach ($holidayDays as $key => $holidayDay) {
if (($realholiDay[$key])) {
} else if ($workingHours[date('w', strtotime($key))]) {
$holidays_now--;
}
}
foreach ($timerecordingscorrections as $timerecordingscorrection) {
$holidays_now = $holidays_now + $timerecordingscorrection->days;
}
if ($holidays_now != $employee->holidays_now) {
$employeeupdate = new TimerecordingEmployee($employee->id);
$data = [];
$data['holidays_now'] = $holidays_now;
$employeeupdate->update($data);
$employeeupdate->save();
}
}
}
public function updatePlushours($userid)
{
$employee = TimerecordingEmployeeModel::search(['user_id' => $userid]);
if ($employee) {
$employee = $employee[0];
$plushours = $employee->plushours;
$plushours_now = $employee->plushours_now;
$plushours_timestamp = $employee->plushours_timestamp;
$overtime = $employee->overtime;
$overtime_now = $employee->overtime_now;
$overtime_timestamp = $employee->overtime_timestamp;
if (!$plushours_timestamp) {
$plushours_timestamp = $employee->startdate;
$plushours_now = $plushours;
}
if (!$overtime_timestamp) {
$overtime_timestamp = $employee->startdate;
$overtime_now = $overtime;
}
$endtime = time() - 86400;
$endtime = date("Y-m-d", $endtime);
$endtime = strtotime($endtime . " 23:59:00");
if ($plushours_timestamp > 0) {
$return = $this->getTimerecordingsApi(5, null, null, null, $plushours_timestamp, $endtime, $userid);
$diffTime = $return['is'] - $return['must'];
$plushours_now = $plushours_now + $diffTime;
} else {
$diffTime = 0;
}
$minushours = 0;
$minushoursovertime = 0;
$timerecordings = TimerecordingModel::search(['user_id' => $userid, 'start' => $plushours_timestamp, 'hours' => 1]);
foreach ($timerecordings as $timerecording) {
if ($timerecording->hours) {
$timediff = $timerecording->hours;
$minushours = $minushours + $timediff;
}
if ($timerecording->hours_overtime) {
$timediffovertime = $timerecording->hours_overtime;
$minushoursovertime = $minushoursovertime + $timediffovertime;
}
}
$plushours_now = $plushours_now - $minushours;
$diffTime = $diffTime - $minushours;
$overtime_now = $overtime_now - $minushoursovertime;
if ($employee->plushours_now != $plushours_now || $employee->overtime_now != $overtime_now) {
$employeeupdate = new TimerecordingEmployee($employee->id);
$data = [];
$data['plushours_now'] = $plushours_now;
$data['overtime_now'] = $overtime_now;
$employeeupdate->update($data);
$employeeupdate->save();
}
}
}
protected function getTimerecordingsApi($datatype, $dataweek, $datamonth, $datayear, $startime = null, $endtime = null, $userid = null)
{
$mustSeconds = 0;
$isSeconds = 0;
$holiDays = 0;
$plusHours = 0;
$rows = [];
$employee = TimerecordingEmployeeModel::search(['user_id' => $this->me->id]);
if ($employee) {
$holiDays = $employee[0]->holidays;
$plusHours = $employee[0]->plushours;
$startdate = time();
if (!$userid) {
$userid = $this->me->id;
}
$workinghours = TimerecordingEmployeeWorkingHourModel::search(['user_id' => $this->me->id]);
$rows = [];
$employee = TimerecordingEmployeeModel::search(['user_id' => $userid]);
if ($employee) {
$holiDays = $employee[0]->holidays_now;
$plusHours = $employee[0]->plushours_now;
$auto_workinghours = $employee[0]->auto_workinghours;
$startdate = $employee[0]->startdate;
$overtime = $employee[0]->overtime_now;
}
$workinghours = TimerecordingEmployeeWorkingHourModel::search(['user_id' => $userid]);
$holidays = TimerecordingHolidayModel::getAll();
foreach ($workinghours as $workinghour) {
@@ -265,8 +617,9 @@ class TimerecordingController extends mfBaseController
$year = date('Y', $dataweek);
$timestamp_montag = strtotime("{$year}-W{$kw}");
$timestamp_sonntag = strtotime("{$year}-W{$kw}-7");
$firstdate = strtotime(date("Y-m-d", $timestamp_montag) . " 00:00:00");
$lastdate = strtotime(date("Y-m-d", $timestamp_sonntag) . ' 23:59:59');
$searchArray = ['user_id' => $this->me->id, 'start' => $timestamp_montag, 'end' => $lastdate];
$searchArray = ['user_id' => $userid, 'start' => $timestamp_montag, 'end' => $lastdate];
$daycounter = '0';
@@ -274,7 +627,7 @@ class TimerecordingController extends mfBaseController
for ($i = 1; $i <= 7; $i++) {
$dDate = date('Y-m-d', $timestamp);
$dDay = date('w', $timestamp);
if (!$holiDay[$dDate]) {
if (!$holiDay[$dDate] && $dDate >= date('Y-m-d', $startdate)) {
$mustSeconds = $mustSeconds + $workingHours[$dDay];
}
@@ -285,7 +638,23 @@ class TimerecordingController extends mfBaseController
$lastdate = strtotime(date("Y-m-t", $datamonth));
$daycount = date("t", $datamonth);
$lastdate = strtotime(date("Y-m-d", $lastdate) . ' 23:59:59');
$searchArray = ['user_id' => $this->me->id, 'start' => $firstdate, 'end' => $lastdate];
$searchArray = ['user_id' => $userid, 'start' => $firstdate, 'end' => $lastdate];
$timestamp = $firstdate;
for ($i = 1; $i <= $daycount; $i++) {
$dDate = date('Y-m-d', $timestamp);
$dDay = date('w', $timestamp);
if (!$holiDay[$dDate] && $dDate >= date('Y-m-d', $startdate)) {
$mustSeconds = $mustSeconds + $workingHours[$dDay];
}
$timestamp = $timestamp + 86400;
}
} else if ($datatype == 3) {
$firstdate = strtotime(date("Y-01-01", $datayear));
$lastdate = strtotime(date("Y-12-31 23:59:59", $datayear));
$daycount = date("t", $datamonth);
$lastdate = strtotime(date("Y-m-d", $lastdate) . ' 23:59:59');
$searchArray = ['user_id' => $userid, 'start' => $firstdate, 'end' => $lastdate];
$timestamp = $firstdate;
for ($i = 1; $i <= $daycount; $i++) {
@@ -294,17 +663,15 @@ class TimerecordingController extends mfBaseController
if (!$holiDay[$dDate]) {
$mustSeconds = $mustSeconds + $workingHours[$dDay];
}
$timestamp = $timestamp + 86400;
}
} else if ($datatype == 3) {
$firstdate = strtotime(date("Y-01-01", $datayear));
$lastdate = strtotime(date("Y-12-31 23:59:59", $datayear));
$daycount = date("t", $datamonth);
$lastdate = strtotime(date("Y-m-d", $lastdate) . ' 23:59:59');
$searchArray = ['user_id' => $this->me->id, 'start' => $firstdate, 'end' => $lastdate];
} else if ($datatype == 5) {
$firstdate = $startime;
$lastdate = $endtime;
$timediff = $lastdate - $firstdate;
$daycount = $timediff / 86400;
$daycount = round($daycount, 0, PHP_ROUND_HALF_DOWN);
$searchArray = ['user_id' => $userid, 'start' => $firstdate, 'end' => $lastdate];
$timestamp = $firstdate;
for ($i = 1; $i <= $daycount; $i++) {
@@ -343,7 +710,8 @@ class TimerecordingController extends mfBaseController
$sum = sprintf("%02d", $hours) . ":" . sprintf("%02d", $minutes);
$day = $daysgerm[date("w", $timerecording->start)];
$isSeconds = $isSeconds + $seconds;
} else if ($timerecording->timerecordingCategory->hourday == 2) {
} 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);
$enddate = date("Y-m-d", $timerecording->end);
@@ -356,23 +724,111 @@ class TimerecordingController extends mfBaseController
} else {
$endtimecalc = $timerecording->end;
}
if ($firstdate > $timerecording->start) {
$starttimecalc = $firstdate;
} else {
$starttimecalc = $timerecording->start;
}
$summcounter = 0;
for ($i = $timerecording->start; $i <= $endtimecalc; $i = $i + 86400) {
$savecounter = 0;
$sumdays = 0;
for ($i = $starttimecalc; $i <= $endtimecalc; $i = $i + 86400) {
$holidaycounter = $workingHours[date("w", $i)];
$isSeconds = $isSeconds + $holidaycounter;
$summcounter = $summcounter + $holidaycounter;
$daycheck = date("Y-m-d", $i);
if (!$holiDay[$daycheck]) {
if ($holidaycounter) {
$isSeconds = $isSeconds + $holidaycounter;
$summcounter = $summcounter + $holidaycounter;
$sumdays++;
}
}
if ($savecounter == 1000) {
echo $savecounter;
die();
}
$savecounter++;
}
$seconds = $summcounter;
$minutes = floor(($seconds % 3600) / 60);
$hours = floor($seconds / 3600);
// $sum = sprintf("%02d", $hours) . ":" . sprintf("%02d", $minutes);
if ($sumdays == 1 || $sumdays == 0) {
$sum = $sumdays . " Tag";
} else if ($sumdays > 1) {
$sum = $sumdays . " Tage";
}
} 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);
$enddatetemp = date("Y-m-d", time());
$enddatetemp = strtotime($enddatetemp . " 23:59:59");
$enddate = date("Y-m-d", $enddatetemp + 7200);
$start = "-";
$end = "-";
$day = $daysgerm[date("w", $timerecording->start)];
if ($lastdate < time()) {
$endtimecalc = $lastdate;
} else {
$endtimecalc = time();
}
$summcounter = 0;
if ($firstdate > $timerecording->start) {
$starttimecalc = $firstdate;
} else {
$starttimecalc = $timerecording->start;
}
$summcounter = 0;
$savecounter = 0;
// echo $starttimecalc."<br>";
for ($i = $starttimecalc; $i <= $endtimecalc; $i = $i + 86400) {
$holidaycounter = $workingHours[$timerecording->user_id][date("w", $i)];
$daycheck = date("Y-m-d", $i);
if (!$holiDay[$daycheck]) {
$isSeconds = $isSeconds + $holidaycounter;
$summcounter = $summcounter + $holidaycounter;;
}
if ($savecounter == 1000) {
echo $savecounter;
die();
}
$savecounter++;
}
$seconds = $summcounter;
$minutes = floor(($seconds % 3600) / 60);
$hours = floor($seconds / 3600);
$sum = sprintf("%02d", $hours) . ":" . sprintf("%02d", $minutes);
} else if ($timerecording->timerecordingCategory->hourday == 3 || $timerecording->timerecordingCategory->hourday == 4) {
} else if ($timerecording->timerecordingCategory->hourday == 5) {
$date = date("d.m.Y", $timerecording->start);
$datadate = date("Y-m-d", $timerecording->start);
$start = "-";
$end = "-";
$day = $daysgerm[date("w", $timerecording->start)];
if ($timerecording->days > 0) {
if ($timerecording->days == 1) {
$sum = "+" . $timerecording->days . " Tag";
} else {
$sum = "+" . $timerecording->days . " Tage";
}
} else {
if ($timerecording->days == -1) {
$sum = $timerecording->days . " Tag";
} else {
$sum = $timerecording->days . " Tage";
}
}
} else if ($timerecording->timerecordingCategory->hourday == 6) {
$date = date("d.m.Y", $timerecording->start);
$datadate = date("Y-m-d", $timerecording->start);
$start = date("H:i", $timerecording->start);
$end = date("H:i", $timerecording->end);
// $seconds = $timerecording->hours;
$seconds = $timerecording->end - $timerecording->start;
$minutes = floor(($seconds % 3600) / 60);
$hours = floor($seconds / 3600);
$sum = "-" . sprintf("%02d", $hours) . ":" . sprintf("%02d", $minutes);
$day = $daysgerm[date("w", $timerecording->start)];
$isSeconds = $isSeconds + $seconds;
}
if ($timerecording->timerecordingCategory->approval == 1 && $timerecording->approved == 0) {
@@ -381,6 +837,18 @@ class TimerecordingController extends mfBaseController
$state = '<i class="fa-regular fa-circle-check mr-1"></i>';
}
$edit = "";
if ($timerecording->businesstrip == 1) {
$category = "<span>" . $timerecording->timerecordingCategory->name . "</span><span class='text-bold ml-1'> (Dienstreise: " . $timerecording->businesstrip_info . ")</span>";
} else if ($timerecording->homeoffice == 1) {
$category = "<span>" . $timerecording->timerecordingCategory->name . "</span><span class='text-bold ml-1'> (Homeoffice)</span>";
} else {
$category = $timerecording->timerecordingCategory->name;
}
if ($timerecording->timerecordingCategory->hourday == 3 && !$timerecording->end) {
$category = $category . "<span class='text-bold ml-2'>(offen)</span>";
}
if ($timerecording->completed == 0 && $timerecording->timerecordingCategory->only_admin == 0):
if ($timerecording->approved == 0) :
$edit = '<i class="far fa-edit edit-button" data-id="' . $timerecording->id . '"
@@ -390,6 +858,9 @@ class TimerecordingController extends mfBaseController
data-end="' . $end . '"
data-enddate="' . $enddate . '"
data-comment="' . $timerecording->comment . '"
data-businesstrip="' . $timerecording->businesstrip . '"
data-businesstripinfo="' . $timerecording->businesstrip_info . '"
data-homeoffice="' . $timerecording->homeoffice . '"
title="Bearbeiten"></i>';
else :
$edit .= '<div class="edit-placeholder"></div>';
@@ -403,35 +874,136 @@ class TimerecordingController extends mfBaseController
'start' => array('start' => $start, 'order' => $start),
'end' => array('end' => $end, 'order' => $end),
'sum' => array('sum' => $sum, 'order' => $sum),
'category' => array('category' => $timerecording->timerecordingCategory->name, 'order' => $timerecording->timerecordingCategory->name),
'category' => array('category' => $category, 'order' => $timerecording->timerecordingCategory->name),
'comment' => array('comment' => $timerecording->comment, 'order' => $timerecording->comment),
'edit' => array('edit' => $edit, 'order' => $edit),
);
}
endforeach;
$json['success'] = true;
$json['time']['is'] = sprintf('%02dh:%02dm', floor($isSeconds / 3600), floor($isSeconds / 60 % 60));
$json['time']['must'] = sprintf('%02dh:%02dm', floor($mustSeconds / 3600), floor($mustSeconds / 60 % 60));
$json['time']['holidays'] = $holiDays;
$json['time']['plushours'] = sprintf('%02dh:%02dm', floor($plusHours / 3600), floor($plusHours / 60 % 60));
$json['data'] = $rows;
$json['recordsFiltered'] = $responsecount;
$json['recordsTotal'] = $responsecount;
$json = json_encode($json);
echo trim($json);
die();
if ($datatype == 5) {
$response['is'] = $isSeconds;
$response['must'] = $mustSeconds;
return $response;
} else {
$plusHours = $overtime + $plusHours;
if ($plusHours < 0) {
$plusHours = $plusHours * -1;
$plusHours = "-" . sprintf('%02dh:%02dm', floor($plusHours / 3600), floor($plusHours / 60 % 60));
} else {
$plusHours = sprintf('%02dh:%02dm', floor($plusHours / 3600), floor($plusHours / 60 % 60));
}
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));
}
$json['success'] = true;
$json['time']['auto_workinghours'] = $auto_workinghours;
$json['time']['is'] = $isSeconds;
$json['time']['must'] = sprintf('%02dh:%02dm', floor($mustSeconds / 3600), floor($mustSeconds / 60 % 60));
$json['time']['holidays'] = $holiDays;
$json['time']['plushours'] = $plusHours;
$json['data'] = $rows;
$json['recordsFiltered'] = $responsecount;
$json['recordsTotal'] = $responsecount;
$json = json_encode($json);
echo trim($json);
die();
}
}
protected function fillWorkinghours($dataweek)
{
$employee = TimerecordingEmployeeModel::search(['user_id' => $this->me->id]);
if ($employee) {
$auto_workinghours = $employee[0]->auto_workinghours;
}
if ($auto_workinghours == 0) {
$result['state'] = "error";
$result['error'] = "Automatische Arbeitszeiten sind deaktiviert";
echo json_encode($result);
die();
}
$workinghours = TimerecordingEmployeeWorkingHourModel::search(['user_id' => $this->me->id]);
$holidays = TimerecordingHolidayModel::getAll();
foreach ($workinghours as $workinghour) {
$workingHours[$workinghour->day][] = array('start' => $workinghour->start, 'end' => $workinghour->end);
}
foreach ($holidays as $holiday) {
$holiDay[date('Y-m-d', $holiday->timestamp)] = $holiday->timestamp;
}
$kw = date('W', $dataweek);
$year = date('Y', $dataweek);
$timestamp_montag = strtotime("{$year}-W{$kw}");
$timestamp_sonntag = strtotime("{$year}-W{$kw}-7");
$firstdate = strtotime(date("Y-m-d", $timestamp_montag) . " 00:00:00");
$lastdate = strtotime(date("Y-m-d", $timestamp_sonntag) . ' 23:59:59');
$searchArray = ['user_id' => $this->me->id, 'start' => $firstdate, 'end' => $lastdate];
$timerecording = TimerecordingModel::search($searchArray);
$daycounter = '0';
$update = false;
$timestamp = $timestamp_montag;
for ($i = 1; $i <= 7; $i++) {
$dDate = date('Y-m-d', $timestamp);
$dDay = date('w', $timestamp);
if (!$holiDay[$dDate]) {
if ($workingHours[$dDay]) {
foreach ($workingHours[$dDay] as $workingHour) {
$starttime = strtotime($dDate . " " . $workingHour['start'] . ":00");
$endtime = strtotime($dDate . " " . $workingHour['end'] . ":00");
$check = $this->checkTimerecording($starttime, $endtime);
if ($employee[0]->startdate <= $starttime) {
if ($check['state'] == "success") {
$update = 1;
$data = [];
$data['user_id'] = $this->me->id;
$data['start'] = $starttime;
$data['end'] = $endtime;
$data['timerecordingCategory_id'] = 1;
$data['comment'] = "Automatisch eingetragen";
$data['businesstrip'] = 0;
$data['businesstrip_info'] = NULL;
$timerecordings = TimerecordingModel::create($data);
$id = $timerecordings->save();
}
}
}
}
}
$timestamp = $timestamp + 86400;;
}
if ($update) {
$this->updatePlushours($this->me->id);
$this->updateHolidays($this->me->id);
}
}
protected function deleteAction()
{
$id = $this->request->id;
$timerecordings = new Timerecording($id);
$userid = $timerecordings->user_id;
if (!$timerecordings->id || $timerecordings->id != $id) {
$this->layout()->setFlash("Buchung nicht gefunden.", "error");
$this->redirect("Timerecording");
}
$timerecordings->delete();
$this->updateHolidays($userid);
$this->updatePlushours($userid);
if ($this->request->ajax == 1) {
die();
}

View File

@@ -5,7 +5,13 @@ class TimerecordingModel
private $user_id;
private $start;
private $end;
private $hours;
private $hours_overtime;
private $days;
private $timerecordingCategory_id;
private $businesstrip;
private $businesstrip_info;
private $homeoffice;
private $comment;
private $approved;
private $completed;
@@ -122,7 +128,7 @@ class TimerecordingModel
$items = [];
$db = FronkDB::singleton();
$where = self::getSqlFilter($filter);
$res = $db->select("Timerecording", "*", "$where");
$res = $db->select("Timerecording", "*", "$where ");
if ($db->num_rows($res)) {
while ($data = $db->fetch_object($res)) {
$items[] = new Timerecording($data);
@@ -133,7 +139,7 @@ class TimerecordingModel
private static function getSqlFilter($filter)
{
$where = "1=1 ";
$where = "1=1";
if (array_key_exists("user_id", $filter)) {
$userid = $filter['user_id'];
@@ -145,19 +151,48 @@ class TimerecordingModel
$start = $filter['start'];
$end = $filter['end'];
if (is_numeric($start) && is_numeric($end)) {
$where .= " AND `start` > $start AND `start` < $end";
$where .= " AND ((`start` >= $start AND `start` <= $end) OR (`end` >= $start AND `end` <= $end) OR `end` is NULL) ORDER by user_id ASC";
}
}
if (array_key_exists("start", $filter) && array_key_exists("timerecordingCategory_id", $filter)) {
$start = $filter['start'];
$timerecordingCategory_id = $filter['timerecordingCategory_id'];
if (is_numeric($start) && is_numeric($timerecordingCategory_id)) {
$where .= " AND `start` >= $start AND `timerecordingCategory_id` = $timerecordingCategory_id ORDER by start ASC";
}
}
if (array_key_exists("start", $filter) && array_key_exists("hours", $filter)) {
$start = $filter['start'];
if (is_numeric($start)) {
$where .= " AND `start` >= $start AND (`hours`>0 or `hours_overtime`>0) ORDER by start ASC";
}
}
if (array_key_exists("start", $filter) && array_key_exists("days", $filter)) {
$days = $filter['days'];
$start = $filter['start'];
if ($days === 1) {
$where .= " AND `start` >= $start AND `days` !=0 ORDER by start ASC";
}
}
if (array_key_exists("starttime", $filter) && array_key_exists("endtime", $filter)) {
$starttime = $filter['starttime'];
$endtime = $filter['endtime'];
$id = $filter['id'];
if (is_numeric($starttime) && is_numeric($endtime)) {
$where .= " AND ((`start` <= $starttime AND `end` >= $starttime ) || (`start` >= $endtime AND `end` <= $endtime) || (`start` >= $starttime AND `end` >= $starttime AND `start` <= $endtime AND `end` <= $endtime))";
if ($id && is_numeric($id)) {
$where .= " AND `id` != $id";
}
$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";
//var_dump($where);exit;
}
}
if (array_key_exists("type", $filter)) {
$type = $filter['type'];
if ($type === "opentimerecording") {
$where .= " AND `end` IS NULL ORDER by start DESC LIMIT 1";
}
}
//

View File

@@ -0,0 +1,28 @@
<?php
class TimerecordingCalendarController extends mfBaseController
{
protected function init()
{
$this->needlogin = true;
$me = new User();
$me->loadMe();
$this->me = $me;
$this->layout()->set("me", $me);
if (!$me->is(["employee"])) {
$this->redirect("Dashboard");
}
}
protected function indexAction()
{
$timerecordingholidays = TimerecordingHolidayModel::getAll();
$this->layout()->set("timerecordingholidays", $timerecordingholidays);
$timerecordingemployees = TimerecordingEmployeeModel::getAll();
$this->layout()->set("timerecordingemployees", $timerecordingemployees);
$this->layout()->setTemplate("TimerecordingCalendar/Index");
}
}

View File

@@ -9,7 +9,7 @@ class TimerecordingCategoryModel
private $require_comment;
private $only_admin;
private $businesstrip;
public static $hourday_definition = array(1 => "Uhrzeit (von/bis)", 2 => "Tage (von/bis)", 3 => "Startdatum", 4 => "Enddatum");
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)");
public static $approval_definition = array(0 => "Nein", 1 => "Ja");
public static $require_comment_definition = array(0 => "Nein", 1 => "Ja");
public static $businesstrip_definition = array(0 => "Nein", 1 => "Ja");

View File

@@ -101,6 +101,12 @@ class TimerecordingEmployeeController extends mfBaseController
if (is_numeric($plushours)) {
$plushours = $plushours * 3600;
}
$overtime = $r->overtime;
$overtime = str_replace(',', '.', $overtime);
if (is_numeric($overtime)) {
$overtime = $overtime * 3600;
}
$data = [];
$data['user_id'] = trim($r->user_id);
@@ -109,8 +115,18 @@ class TimerecordingEmployeeController extends mfBaseController
$data['plushours'] = $plushours;
$data['startdate'] = strtotime($r->startdate);
$data['type'] = trim($r->type);
$data['overtime'] = $overtime;
#
if (!$data['overtime']) {
$data['overtime'] = 0;
}
if ($r->birthday) {
$data['birthday'] = strtotime($r->birthday);
} else {
$data['birthday'] = null;
}
if (!$data['user_id']) {
$this->layout()->setFlash("Mitarbeiter darf nicht leer sein", "error");
$this->redirect("TimerecordingEmployee");

View File

@@ -6,8 +6,17 @@ class TimerecordingEmployeeModel
private $type;
private $auto_workinghours;
private $holidays;
private $holidays_now;
private $holidays_timestamp;
private $plushours;
private $plushours_now;
private $plushours_timestamp;
private $overtime;
private $overtime_now;
private $overtime_timestamp;
private $bpahours;
private $startdate;
private $birthday;
public static function find($data)
@@ -138,6 +147,9 @@ class TimerecordingEmployeeModel
$where .= " AND user_id=$userid";
}
}
if (array_key_exists("startdate", $filter)) {
$where .= " AND startdate is not null";
}
//var_dump($filter, $where);exit;
return $where;

View File

@@ -103,6 +103,8 @@ class TimerecordingEmployeeWorkingHourModel
$secondcounter = 0;
while ($data = $db->fetch_array($res)) {
$dayHours[$data['user_id']][$data['day']][] = $data['start'] . " - " . $data['end'];
if ($olduser != $data['user_id']) {
if ($counter > 0) {
$secondcounter = 0;
@@ -121,7 +123,6 @@ class TimerecordingEmployeeWorkingHourModel
if (!$datetimetext) {
$datetimetext = $daysshort[$data['day']];
}
echo $oldstart . $data['start'];
if (($oldstart != $data['start'] || $oldend != $data['end']) && $oldend) {
$datetimetext .= " - " . $daysshort[$oldday] . " " . $oldstart . " - " . $oldend;
$datetimetext .= "<br> " . $daysshort[$data['day']];
@@ -139,6 +140,51 @@ class TimerecordingEmployeeWorkingHourModel
$datetimetext = TimerecordingEmployeeWorkingHourModel::cleardays($datetimetext);
$items[$olduser]['datetimetext'] = $datetimetext;
}
foreach ($dayHours as $key => $dayHour) {
foreach ($dayHour as $key2 => $dayHour2) {
$dayhours[$key][$key2] = implode("<br>", $dayHour2);
}
}
foreach ($dayhours as $key => $dayhour) {
$oldday = false;
$oldstring = false;
$counter = 0;
$oldkey = false;
$oldkey2 = false;
foreach ($dayhour as $key2 => $dayhour2) {
if ($oldday != $key2) {
if ($oldstring != $dayhour2 || $key2!=$oldkey2+1) {
if ($oldkey2) {
$daysitems[$key][$counter]['end'] = $oldkey2;
$counter++;
}
$daysitems[$key][$counter]['start'] = $key2;
}
$daysitems[$key][$counter]['string'] = $dayhour2;
}
$oldkey2 = $key2;
$oldkey = $key;
$oldstring = $dayhour2;
}
$daysitems[$key][$counter]['end'] = $key2;
}
foreach ($daysitems as $key => $daysitem) {
$datetimetext = "";
foreach ($daysitem as $key2 => $daysItem) {
if ($daysItem['start'] != $daysItem['end']) {
$datetimetext .= '<div class="d-table border-bottom border-dark"><div class="d-table-cell w-50 align-middle pr-2 ">' . $daysshort[$daysItem['start']] . "-" . $daysshort[$daysItem['end']] . '</div><div class="d-table-cell">' . $daysItem['string'] . '</div></div>';
} else {
$datetimetext .= '<div class="d-table border-bottom border-dark"><div class="d-table-cell w-50 align-middle pr-2 ">' . $daysshort[$daysItem['start']] . '</div><div class="d-table-cell">' . $daysItem['string'] . '</div></div>';
}
}
$items[$key]['datetimetext'] = $datetimetext;
}
return $items;
}
@@ -153,7 +199,6 @@ class TimerecordingEmployeeWorkingHourModel
public static function getFirst()
{
$db = FronkDB::singleton();
$where = self::getSqlFilter($filter);
$res = $db->select("TimerecordingEmployeeWorkingHour", "*", "$where ");
if ($db->num_rows($res)) {

View File

@@ -56,7 +56,7 @@ class TimerecordingPermitController extends mfBaseController
$body .= 'Buchungsart: ' . $timerecordingCategoriess[0]->name . '
';
if ($timerecordingCategoriess[0]->hourday == "1") {
$body .= 'von: ' . date("d.m.Y H:i", $timerecordings->start) . ' bis: ' . date("H:i", $timerecordings->end). '
$body .= 'von: ' . date("d.m.Y H:i", $timerecordings->start) . ' bis: ' . date("H:i", $timerecordings->end) . '
';
} else if ($timerecordingCategoriess[0]->hourday == "2") {
@@ -69,9 +69,16 @@ class TimerecordingPermitController extends mfBaseController
$email = new Emailnotification();
$email->setSubject('Antrag für ' . $timerecordingCategoriess[0]->name . ' ' . $sendtext);
$email->setBody($body);
$email->setFrom('zeiterfassung@xinon.at', 'Xinon Zeiterfassung');
$email->setFrom(TT_TIMERECORDING_EMAIL, TT_TIMERECORDING_EMAIL_NAME);
$email->setTo($user->email);
$email->send();
$email = new Emailnotification();
$email->setSubject('Antrag für ' . $timerecordingCategoriess[0]->name . ' ' . $sendtext . ' (' . $user->name . ')');
$email->setBody($body);
$email->setFrom(TT_TIMERECORDING_EMAIL, TT_TIMERECORDING_EMAIL_NAME);
$email->setTo(TT_TIMERECORDING_EMAIL);
$email->send();
}
protected function approveAction()

View File

@@ -11,7 +11,7 @@ class TimerecordingReportController extends mfBaseController
$this->me = $me;
$this->layout()->set("me", $me);
if (!$me->can(["Fibu"])) {
if (!$me->is(["employee"])) {
$this->redirect("Dashboard");
}
}
@@ -41,6 +41,9 @@ class TimerecordingReportController extends mfBaseController
case "getTimerecordings":
$return = $this->getTimerecordingsApi($datatype, $dataweek, $datamonth, $datayear);
break;
case "getTimerecordingsTimes":
$return = $this->getTimerecordingsTimes($datatype, $dataweek, $datamonth, $datayear);
break;
default:
$return = false;
}
@@ -74,10 +77,10 @@ class TimerecordingReportController extends mfBaseController
$whstart = strtotime(date('Y-m-d', time()) . " " . $workinghour->start . ":00");
$whend = strtotime(date('Y-m-d', time()) . " " . $workinghour->end . ":00");
if (!$workingHours[$workinghour->day]) {
$workingHours[$workinghour->day] = $whend - $whstart;
if (!$workingHours[$workinghour->user_id][$workinghour->day]) {
$workingHours[$workinghour->user_id][$workinghour->day] = $whend - $whstart;
} else {
$workingHours[$workinghour->day] = $workingHours[$workinghour->day] + $whend - $whstart;
$workingHours[$workinghour->user_id][$workinghour->day] = $workingHours[$workinghour->user_id][$workinghour->day] + $whend - $whstart;
}
}
foreach ($holidays as $holiday) {
@@ -89,6 +92,7 @@ class TimerecordingReportController extends mfBaseController
$year = date('Y', $dataweek);
$timestamp_montag = strtotime("{$year}-W{$kw}");
$timestamp_sonntag = strtotime("{$year}-W{$kw}-7");
$firstdate = strtotime(date("Y-m-d", $timestamp_montag) . " 00:00:00");
$lastdate = strtotime(date("Y-m-d", $timestamp_sonntag) . ' 23:59:59');
$searchArray = ['start' => $timestamp_montag, 'end' => $lastdate];
@@ -99,7 +103,7 @@ class TimerecordingReportController extends mfBaseController
$dDate = date('Y-m-d', $timestamp);
$dDay = date('w', $timestamp);
if (!$holiDay[$dDate]) {
$mustSeconds = $mustSeconds + $workingHours[$dDay];
// $mustSeconds = $mustSeconds + $workingHours[$dDay];
}
$timestamp = $timestamp + 86400;
@@ -116,7 +120,7 @@ class TimerecordingReportController extends mfBaseController
$dDate = date('Y-m-d', $timestamp);
$dDay = date('w', $timestamp);
if (!$holiDay[$dDate]) {
$mustSeconds = $mustSeconds + $workingHours[$dDay];
// $mustSeconds = $mustSeconds + $workingHours[$dDay];
}
$timestamp = $timestamp + 86400;
}
@@ -128,6 +132,318 @@ class TimerecordingReportController extends mfBaseController
$searchArray = ['start' => $firstdate, 'end' => $lastdate];
$timestamp = $firstdate;
for ($i = 1; $i <= $daycount; $i++) {
$dDate = date('Y-m-d', $timestamp);
$dDay = date('w', $timestamp);
if (!$holiDay[$dDate]) {
//$mustSeconds = $mustSeconds + $workingHours[$dDay];
}
$timestamp = $timestamp + 86400;
}
}
$daysgerm = array("So", "Mo", "Di", "Mi", "Do", "Fr", "Sa");
$timerecordingcategories = TimerecordingCategoryModel::getAll();
$timerecordings = TimerecordingModel::search($searchArray);
$responsecount = count($timerecordings);
foreach ($timerecordings as $timerecording):
$state = "";
$enddate = "";
$sum = "-";
$day = "";
$orderdate = $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);
$end = date("H:i", $timerecording->end);
$seconds = $timerecording->end - $timerecording->start;
$minutes = floor(($seconds % 3600) / 60);
$hours = floor($seconds / 3600);
$sum = sprintf("%02d", $hours) . ":" . sprintf("%02d", $minutes);
$day = $daysgerm[date("w", $timerecording->start)];
$isSeconds = $isSeconds + $seconds;
} 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);
$enddate = date("Y-m-d", $timerecording->end + 7200);
$start = "-";
$end = "-";
$day = $daysgerm[date("w", $timerecording->start)];
if ($lastdate < $timerecording->end) {
$endtimecalc = $lastdate;
} else {
$endtimecalc = $timerecording->end;
}
if ($firstdate > $timerecording->start) {
$starttimecalc = $firstdate;
} else {
$starttimecalc = $timerecording->start;
}
$summcounter = 0;
$savecounter = 0;
$sumdays = 0;
// echo $starttimecalc."<br>";
for ($i = $starttimecalc; $i <= $endtimecalc; $i = $i + 86400) {
$holidaycounter = $workingHours[$timerecording->user_id][date("w", $i)];
$daycheck = date("Y-m-d", $i);
if (!$holiDay[$daycheck]) {
if ($holidaycounter) {
$isSeconds = $isSeconds + $holidaycounter;
$summcounter = $summcounter + $holidaycounter;
$sumdays++;
}
}
if ($savecounter == 1000) {
echo $savecounter;
die();
}
$savecounter++;
}
$seconds = $summcounter;
$minutes = floor(($seconds % 3600) / 60);
$hours = floor($seconds / 3600);
// $sum = sprintf("%02d", $hours) . ":" . sprintf("%02d", $minutes);
if ($sumdays == 1 || $sumdays == 0) {
$sum = $sumdays . " Tag";
} else if ($sumdays > 1) {
$sum = $sumdays . " Tage";
}
} 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);
$enddatetemp = date("Y-m-d", time());
$enddatetemp = strtotime($enddatetemp . " 23:59:59");
$enddate = date("Y-m-d", $enddatetemp + 7200);
$start = "-";
$end = "-";
$day = $daysgerm[date("w", $timerecording->start)];
if ($lastdate < time()) {
$endtimecalc = $lastdate;
} else {
$endtimecalc = time();
}
$summcounter = 0;
if ($firstdate > $timerecording->start) {
$starttimecalc = $firstdate;
} else {
$starttimecalc = $timerecording->start;
}
$summcounter = 0;
$savecounter = 0;
// echo $starttimecalc."<br>";
for ($i = $starttimecalc; $i <= $endtimecalc; $i = $i + 86400) {
$holidaycounter = $workingHours[$timerecording->user_id][date("w", $i)];
$daycheck = date("Y-m-d", $i);
if (!$holiDay[$daycheck]) {
$isSeconds = $isSeconds + $holidaycounter;
$summcounter = $summcounter + $holidaycounter;;
}
if ($savecounter == 1000) {
echo $savecounter;
die();
}
$savecounter++;
}
$seconds = $summcounter;
$minutes = floor(($seconds % 3600) / 60);
$hours = floor($seconds / 3600);
$sum = sprintf("%02d", $hours) . ":" . sprintf("%02d", $minutes);
} else if ($timerecording->timerecordingCategory->hourday == 5) {
$date = date("d.m.Y", $timerecording->start);
$start = "-";
$end = "-";
$day = $daysgerm[date("w", $timerecording->start)];
if ($timerecording->days > 0) {
if ($timerecording->days == 1) {
$sum = "+" . $timerecording->days . " Tag";
} else {
$sum = "+" . $timerecording->days . " Tage";
}
} else {
if ($timerecording->days == -1) {
$sum = $timerecording->days . " Tag";
} else {
$sum = $timerecording->days . " Tage";
}
}
} else if ($timerecording->timerecordingCategory->hourday == 6) {
$date = date("d.m.Y", $timerecording->start);
$datadate = date("Y-m-d", $timerecording->start);
$start = date("H:i", $timerecording->start);
$end = date("H:i", $timerecording->end);
// $seconds = $timerecording->hours;
$seconds = $timerecording->end - $timerecording->start;
$minutes = floor(($seconds % 3600) / 60);
$hours = floor($seconds / 3600);
$sum = "-" . sprintf("%02d", $hours) . ":" . sprintf("%02d", $minutes);
$day = $daysgerm[date("w", $timerecording->start)];
$isSeconds = $isSeconds + $seconds;
}
if ($timerecording->timerecordingCategory->approval == 1 && $timerecording->approved == 0) {
$state = '<i class="fa-regular fa-clock mr-1"></i>';
} else if ($timerecording->timerecordingCategory->approval == 1 && $timerecording->approved == 1) {
$state = '<i class="fa-regular fa-circle-check mr-1"></i>';
}
$edit = "";
if ($timerecording->businesstrip == 1) {
$category = "<span>" . $timerecording->timerecordingCategory->name . "</span><span class='text-bold ml-1'> (Dienstreise: " . $timerecording->businesstrip_info . ")</span>";
} else if ($timerecording->homeoffice == 1) {
$category = "<span>" . $timerecording->timerecordingCategory->name . "</span><span class='text-bold ml-1'> (Homeoffice)</span>";
} else {
$category = $timerecording->timerecordingCategory->name;
}
if ($timerecording->timerecordingCategory->hourday == 3 && !$timerecording->end) {
$category = $category . " <span class='text-bold ml-1'>(Offen)</span>";
}
if ($timerecording->completed == 0):
if ($timerecording->approved == 0) :
$edit = '<i class="far fa-edit edit-button" data-id="' . $timerecording->id . '"
data-date="' . $datadate . '"
data-category="' . $timerecording->timerecordingCategory->id . '"
data-start="' . $start . '"
data-end="' . $end . '"
data-enddate="' . $enddate . '"
data-comment="' . $timerecording->comment . '"
data-userid="' . $timerecording->user_id . '"
data-businesstrip="' . $timerecording->businesstrip . '"
data-businesstripinfo="' . $timerecording->businesstrip_info . '"
data-homeoffice="' . $timerecording->homeoffice . '"
data-days="' . $timerecording->days . '"
title="Bearbeiten"></i>';
else :
$edit .= '<div class="edit-placeholder"></div>';
endif;
$edit .= '<i data-id="' . $timerecording->id . '" class="fas fa-trash text-danger delete-item" ></i>';
endif;
if ($datatype == 3 && $timerecording->timerecordingCategory->hourday == 1) {
} else {
$rows[] = array(
'user' => array('user' => $timerecording->user->name, 'order' => $timerecording->user->name),
'date' => array('date' => $state . $day . " " . $date, 'order' => $orderdate),
'start' => array('start' => $start, 'order' => $start),
'end' => array('end' => $end, 'order' => $end),
'sum' => array('sum' => $sum, 'order' => $sum),
'cstart' => array('cstart' => $datadate, 'order' => $datadate),
'cend' => array('cend' => $enddate, 'order' => $enddate),
'ccategory' => array('ccategory' => $timerecording->timerecordingCategory->name, 'order' => $timerecording->timerecordingCategory->name),
'category' => array('category' => $category, 'order' => $timerecording->timerecordingCategory->name),
'comment' => array('comment' => $timerecording->comment, 'order' => $timerecording->comment),
'edit' => array('edit' => $edit, 'order' => $edit),
'hourday' => array('hourday' => $timerecording->timerecordingCategory->hourday, 'order' => $timerecording->timerecordingCategory->hourday),
);
}
endforeach;
$json['success'] = true;
$json['time']['is'] = sprintf('%02dh:%02dm', floor($isSeconds / 3600), floor($isSeconds / 60 % 60));
$json['time']['must'] = sprintf('%02dh:%02dm', floor($mustSeconds / 3600), floor($mustSeconds / 60 % 60));
$json['time']['holidays'] = $holiDays;
$json['time']['plushours'] = sprintf('%02dh:%02dm', floor($plusHours / 3600), floor($plusHours / 60 % 60));
$json['data'] = $rows;
$json['recordsFiltered'] = $responsecount;
$json['recordsTotal'] = $responsecount;
$json = json_encode($json);
echo trim($json);
die();
}
protected function getTimerecordingsTimes($datatype, $dataweek, $datamonth, $datayear)
{
$r = $this->request;
$mustSeconds = 0;
$isSeconds = 0;
$holiDays = 0;
$plusHours = 0;
$rows = [];
$employee = TimerecordingEmployeeModel::search(['user_id' => $r->user_id]);
if ($employee) {
$holiDays = $employee[0]->holidays;
$plusHours = $employee[0]->plushours;
$auto_workinghours = $employee[0]->auto_workinghours;
$startdate = $employee[0]->startdate;
}
$workinghours = TimerecordingEmployeeWorkingHourModel::search(['user_id' => $r->user_id]);
$holidays = TimerecordingHolidayModel::getAll();
foreach ($workinghours as $workinghour) {
$whstart = strtotime(date('Y-m-d', time()) . " " . $workinghour->start . ":00");
$whend = strtotime(date('Y-m-d', time()) . " " . $workinghour->end . ":00");
if (!$workingHours[$workinghour->day]) {
$workingHours[$workinghour->day] = $whend - $whstart;
} else {
$workingHours[$workinghour->day] = $workingHours[$workinghour->day] + $whend - $whstart;
}
}
foreach ($holidays as $holiday) {
$holiDay[date('Y-m-d', $holiday->timestamp)] = $holiday->timestamp;
}
if ($datatype == 1) {
$kw = date('W', $dataweek);
$year = date('Y', $dataweek);
$timestamp_montag = strtotime("{$year}-W{$kw}");
$timestamp_sonntag = strtotime("{$year}-W{$kw}-7");
$firstdate = strtotime(date("Y-m-d", $timestamp_montag) . " 00:00:00");
$lastdate = strtotime(date("Y-m-d", $timestamp_sonntag) . ' 23:59:59');
$searchArray = ['user_id' => $r->user_id, 'start' => $timestamp_montag, 'end' => $lastdate];
$daycounter = '0';
$timestamp = $timestamp_montag;
for ($i = 1; $i <= 7; $i++) {
$dDate = date('Y-m-d', $timestamp);
$dDay = date('w', $timestamp);
if (!$holiDay[$dDate] && $dDate >= date('Y-m-d', $startdate)) {
$mustSeconds = $mustSeconds + $workingHours[$dDay];
}
$timestamp = $timestamp + 86400;
}
} else if ($datatype == 2) {
$firstdate = strtotime(date("Y-m-01", $datamonth));
$lastdate = strtotime(date("Y-m-t", $datamonth));
$daycount = date("t", $datamonth);
$lastdate = strtotime(date("Y-m-d", $lastdate) . ' 23:59:59');
$searchArray = ['user_id' => $r->user_id, 'start' => $firstdate, 'end' => $lastdate];
$timestamp = $firstdate;
for ($i = 1; $i <= $daycount; $i++) {
$dDate = date('Y-m-d', $timestamp);
$dDay = date('w', $timestamp);
if (!$holiDay[$dDate] && $dDate >= date('Y-m-d', $startdate)) {
$mustSeconds = $mustSeconds + $workingHours[$dDay];
}
$timestamp = $timestamp + 86400;
}
} else if ($datatype == 3) {
$firstdate = strtotime(date("Y-01-01", $datayear));
$lastdate = strtotime(date("Y-12-31 23:59:59", $datayear));
$daycount = date("t", $datamonth);
$lastdate = strtotime(date("Y-m-d", $lastdate) . ' 23:59:59');
$searchArray = ['user_id' => $r->user_id, 'start' => $firstdate, 'end' => $lastdate];
$timestamp = $firstdate;
for ($i = 1; $i <= $daycount; $i++) {
$dDate = date('Y-m-d', $timestamp);
$dDay = date('w', $timestamp);
@@ -164,7 +480,7 @@ class TimerecordingReportController extends mfBaseController
$sum = sprintf("%02d", $hours) . ":" . sprintf("%02d", $minutes);
$day = $daysgerm[date("w", $timerecording->start)];
$isSeconds = $isSeconds + $seconds;
} else if ($timerecording->timerecordingCategory->hourday == 2) {
} 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);
$enddate = date("Y-m-d", $timerecording->end);
@@ -177,23 +493,67 @@ class TimerecordingReportController extends mfBaseController
} else {
$endtimecalc = $timerecording->end;
}
if ($firstdate > $timerecording->start) {
$starttimecalc = $firstdate;
} else {
$starttimecalc = $timerecording->start;
}
$summcounter = 0;
for ($i = $timerecording->start; $i <= $endtimecalc; $i = $i + 86400) {
$savecounter = 0;
for ($i = $starttimecalc; $i <= $endtimecalc; $i = $i + 86400) {
$holidaycounter = $workingHours[date("w", $i)];
$isSeconds = $isSeconds + $holidaycounter;
$summcounter = $summcounter + $holidaycounter;
if ($savecounter == 1000) {
echo $savecounter;
die();
}
$savecounter++;
}
$seconds = $summcounter;
$minutes = floor(($seconds % 3600) / 60);
$hours = floor($seconds / 3600);
$sum = sprintf("%02d", $hours) . ":" . sprintf("%02d", $minutes);
} else if ($timerecording->timerecordingCategory->hourday == 3 || $timerecording->timerecordingCategory->hourday == 4) {
$date = date("d.m.Y", $timerecording->start);
} 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);
$start = "-";
$end = "-";
$day = $daysgerm[date("w", $timerecording->start)];
if ($lastdate < $timerecording->end) {
$endtimecalc = $lastdate;
} else {
$endtimecalc = $timerecording->end;
}
if ($firstdate > $timerecording->start) {
$starttimecalc = $firstdate;
} else {
$starttimecalc = $timerecording->start;
}
$summcounter = 0;
$savecounter = 0;
for ($i = $starttimecalc; $i <= $endtimecalc; $i = $i + 86400) {
$holidaycounter = $workingHours[date("w", $i)];
$isSeconds = $isSeconds + $holidaycounter;
$summcounter = $summcounter + $holidaycounter;
if ($savecounter == 1000) {
echo $savecounter;
die();
}
$savecounter++;
}
$seconds = $summcounter;
$minutes = floor(($seconds % 3600) / 60);
$hours = floor($seconds / 3600);
$sum = sprintf("%02d", $hours) . ":" . sprintf("%02d", $minutes);
} else if ($timerecording->timerecordingCategory->hourday == 5) {
$start = "-";
$end = "-";
$day = $daysgerm[date("w", $timerecording->start)];
$sum = $timerecording->days . " Tage";
}
if ($timerecording->timerecordingCategory->approval == 1 && $timerecording->approved == 0) {
@@ -202,6 +562,16 @@ class TimerecordingReportController extends mfBaseController
$state = '<i class="fa-regular fa-circle-check mr-1"></i>';
}
$edit = "";
if ($timerecording->businesstrip == 1) {
$category = "<span>" . $timerecording->timerecordingCategory->name . "</span><span class='text-bold ml-2'> (Dienstreise: " . $timerecording->businesstrip_info . ")</span>";
} else {
$category = $timerecording->timerecordingCategory->name;
}
if ($timerecording->timerecordingCategory->hourday == 3 && !$timerecording->end) {
$category = $category . "<span class='text-bold ml-2'>(offen)</span>";
}
if ($timerecording->completed == 0 && $timerecording->timerecordingCategory->only_admin == 0):
if ($timerecording->approved == 0) :
$edit = '<i class="far fa-edit edit-button" data-id="' . $timerecording->id . '"
@@ -211,7 +581,8 @@ class TimerecordingReportController extends mfBaseController
data-end="' . $end . '"
data-enddate="' . $enddate . '"
data-comment="' . $timerecording->comment . '"
data-userid="' . $timerecording->user_id . '"
data-businesstrip="' . $timerecording->businesstrip . '"
data-businesstripinfo="' . $timerecording->businesstrip_info . '"
title="Bearbeiten"></i>';
else :
$edit .= '<div class="edit-placeholder"></div>';
@@ -220,24 +591,15 @@ class TimerecordingReportController extends mfBaseController
endif;
if ($datatype == 3 && $timerecording->timerecordingCategory->hourday == 1) {
} else {
$rows[] = array(
'user' => array('user' => $timerecording->user->name, 'order' => $timerecording->user->name),
'date' => array('date' => $state . $day . " " . $date, 'order' => $orderdate),
'start' => array('start' => $start, 'order' => $start),
'end' => array('end' => $end, 'order' => $end),
'sum' => array('sum' => $sum, 'order' => $sum),
'category' => array('category' => $timerecording->timerecordingCategory->name, 'order' => $timerecording->timerecordingCategory->name),
'comment' => array('comment' => $timerecording->comment, 'order' => $timerecording->comment),
'edit' => array('edit' => $edit, 'order' => $edit),
);
}
endforeach;
$json['success'] = true;
$json['time']['auto_workinghours'] = $auto_workinghours;
$json['time']['is'] = sprintf('%02dh:%02dm', floor($isSeconds / 3600), floor($isSeconds / 60 % 60));
$json['time']['must'] = sprintf('%02dh:%02dm', floor($mustSeconds / 3600), floor($mustSeconds / 60 % 60));
$json['time']['holidays'] = $holiDays;
$json['time']['plushours'] = sprintf('%02dh:%02dm', floor($plusHours / 3600), floor($plusHours / 60 % 60));
$json['data'] = $rows;
$json['recordsFiltered'] = $responsecount;
$json['recordsTotal'] = $responsecount;
$json = json_encode($json);

View File

@@ -0,0 +1,41 @@
<?php
declare(strict_types=1);
use Phinx\Migration\AbstractMigration;
final class TimerecordingEmployeeAddFieldOvertime extends AbstractMigration
{
public function up(): void
{
if($this->getEnvironment() == "thetool") {
$table = $this->table("TimerecordingEmployee", ["signed" => true]);
$table->addColumn("overtime", "integer", ["null" => false, "default" => '0', "after" => "plushours_now"]);
$table->addColumn("overtime_now", "integer", ["null" => false, "default" => '0', "after" => "plushours_now"]);
$table->addColumn("overtime_timestamp", "integer", ["null" => true, "after" => "overtime_now"]);
$table->addColumn("holidays_timestamp", "integer", ["null" => true, "after" => "holidays_now"]);
$table->addColumn("plushours_timestamp", "integer", ["null" => true, "after" => "plushours_now"]);
$table->addColumn("birthday", "integer", ["null" => true, "after" => "startdate"]);
$table->addColumn("bpahours", "integer", ["null" => false, "default" => '0', "after" => "overtime"]);
$table->changeColumn('holidays_now', 'integer', ["null" => false, "default" => '0']);
$table->changeColumn('plushours_now', 'integer', ["null" => false, "default" => '0']);
$table->update();
}
if($this->getEnvironment() == "addressdb") {
}
}
public function down(): void
{
if($this->getEnvironment() == "thetool") {
$this->table("TimerecordingEmployee")->removeColumn("overtime")->save();
}
if($this->getEnvironment() == "addressdb") {
}
}
}

View File

@@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
use Phinx\Migration\AbstractMigration;
final class TimerecordingAddFieldsHomeoffice extends AbstractMigration
{
public function up(): void
{
if($this->getEnvironment() == "thetool") {
$table = $this->table("Timerecording", ["signed" => true]);
$table->addColumn("homeoffice", "integer", ["null" => false, "default" => '0', "after" => "businesstrip_info"]);
$table->update();
}
if($this->getEnvironment() == "addressdb") {
}
}
public function down(): void
{
if($this->getEnvironment() == "thetool") {
$this->table("Timerecording")->removeColumn("homeoffice")->save();
}
if($this->getEnvironment() == "addressdb") {
}
}
}

View File

@@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
use Phinx\Migration\AbstractMigration;
final class TimerecordingAddFieldsDays extends AbstractMigration
{
public function up(): void
{
if($this->getEnvironment() == "thetool") {
$table = $this->table("Timerecording", ["signed" => true]);
$table->addColumn("days", "integer", ["null" => false, "default" => '0', "after" => "end"]);
$table->update();
}
if($this->getEnvironment() == "addressdb") {
}
}
public function down(): void
{
if($this->getEnvironment() == "thetool") {
$this->table("Timerecording")->removeColumn("days")->save();
}
if($this->getEnvironment() == "addressdb") {
}
}
}

View File

@@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
use Phinx\Migration\AbstractMigration;
final class TimerecordingAddFieldEnddate extends AbstractMigration
{
public function up(): void
{
if($this->getEnvironment() == "thetool") {
$table = $this->table("TimerecordingEmployee", ["signed" => true]);
$table->addColumn("enddate", "integer", ["null" => true,"default" => NULL, "after" => "startdate"]);
$table->update();
}
if($this->getEnvironment() == "addressdb") {
}
}
public function down(): void
{
if($this->getEnvironment() == "thetool") {
$this->table("TimerecordingEmployee")->removeColumn("enddate")->save();
}
if($this->getEnvironment() == "addressdb") {
}
}
}

View File

@@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
use Phinx\Migration\AbstractMigration;
final class TimerecordingAddFieldHours extends AbstractMigration
{
public function up(): void
{
if ($this->getEnvironment() == "thetool") {
$table = $this->table("Timerecording", ["signed" => true]);
$table->addColumn("hours", "integer", ["null" => true, "default" => NULL, "after" => "end"]);
$table->update();
}
if ($this->getEnvironment() == "addressdb") {
}
}
public function down(): void
{
if ($this->getEnvironment() == "thetool") {
$this->table("Timerecording")->removeColumn("hours")->save();
}
if ($this->getEnvironment() == "addressdb") {
}
}
}

View File

@@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
use Phinx\Migration\AbstractMigration;
final class DeviceAddFieldAutobackup extends AbstractMigration
{
public function up(): void
{
if($this->getEnvironment() == "thetool") {
$table = $this->table("Device", ["signed" => true]);
$table->addColumn("autobackup", "integer", ["null" => false, "default" => '0', "after" => "last_config_backup"]);
$table->update();
}
if($this->getEnvironment() == "addressdb") {
}
}
public function down(): void
{
if($this->getEnvironment() == "thetool") {
$this->table("Device")->removeColumn("autobackup")->save();
}
if($this->getEnvironment() == "addressdb") {
}
}
}

View File

@@ -0,0 +1,32 @@
<?php
declare(strict_types=1);
use Phinx\Migration\AbstractMigration;
final class TimerecordingAddFieldHoursOvertime extends AbstractMigration
{
public function up(): void
{
if ($this->getEnvironment() == "thetool") {
$table = $this->table("Timerecording", ["signed" => true]);
$table->addColumn("hours_overtime", "integer", ["null" => true, "default" => NULL, "after" => "hours"]);
$table->update();
}
if($this->getEnvironment() == "addressdb") {
}
}
public function down(): void
{
if ($this->getEnvironment() == "thetool") {
$this->table("Timerecording")->removeColumn("hours_overtime")->save();
}
if($this->getEnvironment() == "addressdb") {
}
}
}

View File

@@ -4,7 +4,7 @@ services:
php:
image: debian-php2
ports:
- 80:80
- "80:80"
volumes:
- ./docker/apache2/000-default.conf:/etc/apache2/sites-available/000-default.conf
- ./:/var/www/html
@@ -18,14 +18,19 @@ services:
- MYSQL_USER=luca
- MYSQL_PASSWORD=junghan5
volumes:
- ./docker/mysql/data:/var/lib/mysql
- ./docker/mysql/data:/var/lib/mysql
- ./docker/mysql/conf.d:/etc/mysql/conf.d
- ./docker/mysql/logs:/var/log/mysql
ports:
- "3306:3306"
adminer:
image: adminer
ports:
- 8080:8080
- "8080:8080"
volumes:
- ./docker/adminer.php.ini:/etc/php/7.4/cli/conf.d/php.local.ini
volumes:
vendor:

View File

@@ -0,0 +1,34 @@
param(
[string]$compressedFile
)
# Load .NET assembly for file handling
Add-Type -AssemblyName System.IO.Compression.FileSystem
# Resolve absolute path of the compressed file
$absoluteCompressedFile = Resolve-Path $compressedFile
# Generate file names
$workingDir = Split-Path $absoluteCompressedFile
$uncompressedFile = Join-Path $workingDir ($compressedFile -replace '^\.\\', '' -replace '\.sql\.gz$', '_uncompressed.sql')
$modifiedFile = Join-Path $workingDir ($compressedFile -replace '^\.\\', '' -replace '\.sql\.gz$', '_modified.sql')
$recompressedFile = Join-Path $workingDir ($compressedFile -replace '^\.\\', '' -replace '\.gz$', '_modified.sql.gz')
# Decompress .sql.gz file using .NET Framework
[System.IO.Compression.ZipFile]::ExtractToDirectory($absoluteCompressedFile, $workingDir)
# Read content of uncompressed file
$content = Get-Content -Path $uncompressedFile -Raw
# Replace text
$content = $content -replace 'utf8mb4_0900_ai_ci', 'utf8mb4_general_ci'
# Write modified content to file
Set-Content -Path $modifiedFile -Value $content -Encoding UTF8
# Compress .sql file back to .sql.gz using .NET Framework
[System.IO.Compression.ZipFile]::CreateFromDirectory($workingDir, $recompressedFile)
# Cleanup: Optionally, you can remove the uncompressed and modified files if you don't need them anymore
# Remove-Item $uncompressedFile
# Remove-Item $modifiedFile

View File

@@ -0,0 +1,21 @@
param(
[string]$compressedFile
)
# Generate file names
$uncompressedFile = $compressedFile -replace '\.sql\.gz$', '_uncompressed.sql'
$modifiedFile = $compressedFile -replace '\.sql\.gz$', '_modified.sql'
$recompressedFile = $compressedFile -replace '\.gz$', '_modified.sql.gz'
# Decompress .sql.gz file using 7-Zip
& "C:\Program Files\7-Zip\7z.exe" x -so $compressedFile | Set-Content -Path $uncompressedFile -Encoding UTF8
# Replace text using PowerShell
(Get-Content $uncompressedFile) -replace "utf8mb4_0900_ai_ci", "utf8mb4_general_ci" | Set-Content $modifiedFile -Encoding UTF8
# Compress .sql file back to .sql.gz using 7-Zip
& "C:\Program Files\7-Zip\7z.exe" a -tgzip $recompressedFile $modifiedFile
# Cleanup: Optionally, you can remove the uncompressed and modified files if you don't need them anymore
#Remove-Item $uncompressedFile
#Remove-Item $modifiedFile

3
docker/adminer.php.ini Normal file
View File

@@ -0,0 +1,3 @@
post_max_size = 516M
upload_max_filesize = 516M
memory_limit = 2G

View File

@@ -0,0 +1,9 @@
<VirtualHost *:80>
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html/public
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
<Directory /var/www/html>
AllowOverride All
</Directory>
</VirtualHost>

View File

@@ -44,7 +44,7 @@ $l['preorder.provision'] = "Vorsorgeanschluss";
$l['preorder.order'] = "Vollanschluss";
$l['preorder.reorder'] = "Nachbestellung";
$l['preorder.single-dwelling'] = "Einfahmilienhaus";
$l['preorder.single-dwelling'] = "Einfamilienhaus";
$l['preorder.multi-dwelling'] = "Mehrfamilienhaus";
$l['preorder.apartment-building'] = "Mehrparteienhaus";
$l['preorder.apartment'] = "Wohneinheit in Mehrparteienhaus";

View File

@@ -2,309 +2,285 @@
class mfLayout {
private $log;
private $tvars = array();
private $template = "cli";
private $package = "default";
private $inline;
private $returnValue;
protected static $instance;
private $log;
private $tvars = array();
private $template = "cli";
private $package = "default";
private $inline;
private $returnValue;
protected static $instance;
public function __construct() {
$this->log = mfLoghandler::singleton();
$this->inline = new stdClass();
public function __construct() {
$this->log = mfLoghandler::singleton();
$this->inline = new stdClass();
if (!defined("LAYOUT_DEFAULTPACKAGE")) {
$this->package = "default";
} else {
$this->package = LAYOUT_DEFAULTPACKAGE;
}
if (method_exists($this, "init")) {
$this->init();
}
}
public static function singleton($param = false) {
if (!isset(self::$instance)) {
$c = __CLASS__;
self::$instance = new $c($param);
}
return self::$instance;
}
public function set($name, $value) {
$this->tvars[$name] = $value;
}
public function get($name) {
if(array_key_exists($name, $this->tvars)) {
return $this->tvars[$name];
}
return null;
}
public function setPackage($package) {
$this->package = $package;
}
public function setTemplate($template) {
$this->template = $template;
}
private function setReturnValue($value) {
$this->returnValue = $value;
}
public function getReturnedValue() {
return $this->returnValue;
}
private function getTplPath() {
return VIEWDIR . "/" . $this->package . "/" . $this->template . ".php";
}
public function templatePathExists() {
return file_exists($this->getTplPath());
}
public function render() {
$this->defaultLayoutvariables();
$tpl_path = $this->getTplPath();
if(!is_file($tpl_path)) {
$tpl_path = VIEWDIR . "/default/" . $this->template . ".php";
}
foreach ($this->tvars as $name => $value) {
if ($name === "this")
continue;
$$name = $value;
}
ob_end_clean();
ob_start();
include($tpl_path);
return ob_get_clean();
}
public function display() {
echo $this->render();
}
public function renderPDF($filename = false, $extraPdfArgs = false) {
$html = $this->render();
if (!$filename)
$filename = date('U') . "-" . rand(1000, 9999) . ".pdf";
$wk = new mfWkhtmltopdf($html);
$pdfargs = "";
if ($extraPdfArgs) {
$pdfargs .= " $extraPdfArgs";
}
$filename = $wk->generate($filename, $pdfargs);
if (!$filename) {
throw new Exception("Error generating PDF document.");
}
$file = PDFOUTPUTPATH . "/$filename";
return $file;
}
public function displayPDF($filename = false, $extraPdfArgs = false) {
$filepath = $this->renderPDF($filename, $extraPdfArgs);
if (!$filename && strpos($filepath, "/") !== false) {
$path_parts = explode("/", $filepath);
$filename = end($path_parts);
}
header('Content-Type: application/octet-stream');
header('Content-disposition: attachment; filename=' . $filename);
header('Content-Transfer-Encoding: binary');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Content-Type: ' . mime_content_type($filepath));
header("Content-Length: " . filesize($filepath));
readfile($filepath);
exit;
}
public function setFlash($msg, $type = "info") {
// info, warning, error
if (!$msg) {
return true;
}
if ($type == "error") {
$_SESSION[MFAPPNAME . '_mfError'] = $msg;
} elseif ($type == "warning" || $type == "warn") {
$_SESSION[MFAPPNAME . '_mfWarning'] = $msg;
} elseif ($type == "success") {
$_SESSION[MFAPPNAME . '_mfSuccess'] = $msg;
} else {
$_SESSION[MFAPPNAME . '_mfInfo'] = $msg;
}
return true;
}
private function defaultLayoutvariables() {
$this->set('mfLayoutPackage', $this->package);
if (isset($_SESSION[MFAPPNAME . '_mfError'])) {
$this->set("mfError", $_SESSION[MFAPPNAME . '_mfError']);
$this->set("_flash_set", true);
unset($_SESSION[MFAPPNAME . '_mfError']);
}
if (isset($_SESSION[MFAPPNAME . '_mfWarning'])) {
$this->set("mfWarning", $_SESSION[MFAPPNAME . '_mfWarning']);
$this->set("_flash_set", true);
unset($_SESSION[MFAPPNAME . '_mfWarning']);
}
if (isset($_SESSION[MFAPPNAME . '_mfInfo'])) {
$this->set("mfInfo", $_SESSION[MFAPPNAME . '_mfInfo']);
$this->set("_flash_set", true);
unset($_SESSION[MFAPPNAME . '_mfInfo']);
}
if (isset($_SESSION[MFAPPNAME . '_mfSuccess'])) {
$this->set("mfSuccess", $_SESSION[MFAPPNAME . '_mfSuccess']);
$this->set("_flash_set", true);
unset($_SESSION[MFAPPNAME . '_mfSuccess']);
}
}
/*
* Begin inline functions
*/
public static function strtrim($string, $chars) {
if (strlen($string) <= $chars)
return $string;
return substr($string, 0, $chars) . "...";
}
// produces url for generating links
public static function getUrl($mod, $action = null, $param = null) {
if (!$mod) {
return "";
}
if (MFUSEFANCYURLS) {
// use fancy urls
$url = MFFANCYBASEURL;
if ($mod) {
$url .= "/$mod";
if ($action) {
$url .= "/$action";
if (!defined("LAYOUT_DEFAULTPACKAGE")) {
$this->package = "default";
} else {
$this->package = LAYOUT_DEFAULTPACKAGE;
}
if (method_exists($this, "init")) {
$this->init();
}
}
$url = preg_replace('#//#', '/', $url);
} else {
// no fancy urls
$url = "?action=$mod";
if ($action) {
$url .= "_$action";
}
}
if (is_array($param) && count($param)) {
$url .= (MFUSEFANCYURLS) ? "/?" : "&amp;";
$param_qs = http_build_query($param);
$url .= "$param_qs";
}
return $url;
}
public static function getResourcePath() {
if (MFUSEFANCYURLS) {
$path = MFFANCYBASEURL;
if (substr($path, -1, 1) != "/") {
$path .= "/";
}
} else {
$path = "";
}
return $path;
}
public function cycle() {
$args = func_get_args();
if (is_array($this->inline->cycle) && count($this->inline->cycle)) {
if (array_diff($this->inline->cycle, $args)) { // if different, start new cycle
$this->inline->cycle = $args;
$this->inline->cyclecount = 0;
}
} else {
$this->inline->cycle = $args;
$this->inline->cyclecount = 0;
public static function singleton($param = false) {
if (!isset(self::$instance)) {
$c = __CLASS__;
self::$instance = new $c($param);
}
return self::$instance;
}
if ($this->inline->cyclecount >= count($this->inline->cycle)) {
$this->inline->cyclecount = 0;
public function set($name, $value) {
$this->tvars[$name] = $value;
}
return $this->inline->cycle[$this->inline->cyclecount++];
}
public function get($name) {
if(array_key_exists($name, $this->tvars)) {
return $this->tvars[$name];
}
return null;
}
public function setPackage($package) {
$this->package = $package;
}
public function setTemplate($template) {
$this->template = $template;
}
private function setReturnValue($value) {
$this->returnValue = $value;
}
public function getReturnedValue() {
return $this->returnValue;
}
private function getTplPath() {
return VIEWDIR . "/" . $this->package . "/" . $this->template . ".php";
}
public function templatePathExists() {
return file_exists($this->getTplPath());
}
public function render() {
$this->defaultLayoutvariables();
$tpl_path = $this->getTplPath();
if(!is_file($tpl_path)) {
$tpl_path = VIEWDIR . "/default/" . $this->template . ".php";
}
foreach ($this->tvars as $name => $value) {
if ($name === "this")
continue;
$$name = $value;
}
ob_end_clean();
ob_start();
include($tpl_path);
return ob_get_clean();
}
public function display() {
echo $this->render();
}
public function renderPDF($filename = false, $extraPdfArgs = false) {
$html = $this->render();
if (!$filename)
$filename = date('U') . "-" . rand(1000, 9999) . ".pdf";
$wk = new mfWkhtmltopdf($html);
$pdfargs = "";
if ($extraPdfArgs) {
$pdfargs .= " $extraPdfArgs";
}
$filename = $wk->generate($filename, $pdfargs);
if (!$filename) {
throw new Exception("Error generating PDF document.");
}
$file = PDFOUTPUTPATH . "/$filename";
return $file;
}
public function displayPDF($filename = false, $extraPdfArgs = false) {
$filepath = $this->renderPDF($filename, $extraPdfArgs);
if (!$filename && strpos($filepath, "/") !== false) {
$path_parts = explode("/", $filepath);
$filename = end($path_parts);
}
header('Content-Type: application/octet-stream');
header('Content-disposition: attachment; filename=' . $filename);
header('Content-Transfer-Encoding: binary');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Content-Type: ' . mime_content_type($filepath));
header("Content-Length: " . filesize($filepath));
readfile($filepath);
exit;
}
public function setFlash($msg, $type = "info") {
// info, warning, error
if (!$msg) {
return true;
}
$_SESSION[MFAPPNAME . '_mfNotify'] = array("type" => $type, "message" => $msg);
return true;
}
private function defaultLayoutvariables() {
$this->set('mfLayoutPackage', $this->package);
if (isset($_SESSION[MFAPPNAME . '_mfNotify'])) {
$this->set("mfNotify", $_SESSION[MFAPPNAME . '_mfNotify']);
unset($_SESSION[MFAPPNAME . '_mfNotify']);
}
}
/*
* Begin inline functions
*/
public static function strtrim($string, $chars) {
if (strlen($string) <= $chars)
return $string;
return substr($string, 0, $chars) . "...";
}
// produces url for generating links
public static function getUrl($mod, $action = null, $param = null) {
if (!$mod) {
return "";
}
if (MFUSEFANCYURLS) {
// use fancy urls
$url = MFFANCYBASEURL;
if ($mod) {
$url .= "/$mod";
if ($action) {
$url .= "/$action";
}
}
$url = preg_replace('#//#', '/', $url);
} else {
// no fancy urls
$url = "?action=$mod";
if ($action) {
$url .= "_$action";
}
}
if (is_array($param) && count($param)) {
$url .= (MFUSEFANCYURLS) ? "/?" : "&amp;";
$param_qs = http_build_query($param);
$url .= "$param_qs";
}
return $url;
}
public static function getResourcePath() {
if (MFUSEFANCYURLS) {
$path = MFFANCYBASEURL;
if (substr($path, -1, 1) != "/") {
$path .= "/";
}
} else {
$path = "";
}
return $path;
}
public function cycle() {
$args = func_get_args();
if (is_array($this->inline->cycle) && count($this->inline->cycle)) {
if (array_diff($this->inline->cycle, $args)) { // if different, start new cycle
$this->inline->cycle = $args;
$this->inline->cyclecount = 0;
}
} else {
$this->inline->cycle = $args;
$this->inline->cyclecount = 0;
}
if ($this->inline->cyclecount >= count($this->inline->cycle)) {
$this->inline->cyclecount = 0;
}
return $this->inline->cycle[$this->inline->cyclecount++];
}
}
function mfLayoutInclude($filename, $folder = "") {
global $mfLayoutPackage;
if($folder) {
$folder = $folder."/";
}
global $mfLayoutPackage;
$inc_path = VIEWDIR . "/" . LAYOUT_DEFAULTPACKAGE . "/" . $folder . $filename;
if(!file_exists($inc_path)) {
$inc_path = VIEWDIR . "/default/" . $folder . $filename;
}
if($folder) {
$folder = $folder."/";
}
include $inc_path;
$inc_path = VIEWDIR . "/" . LAYOUT_DEFAULTPACKAGE . "/" . $folder . $filename;
if(!file_exists($inc_path)) {
$inc_path = VIEWDIR . "/default/" . $folder . $filename;
}
include $inc_path;
}
/*
* global variable $lang to avoid loading it every time it's accessed
*/
if(!isset($lang)) {
$lang = [];
$lang = [];
}
$last_translation_failed = false;
function __($_string, $prefix = null) {
global $lang;
global $last_translation_failed;
$last_translation_failed = false;
$string = str_replace(["Ä","Ö","Ü","ß","ä","ö","ü","ß"], ["ae","oe","ue","ss","ae","oe","ue", "ss"], strtolower($_string));
if(!$lang) {
//mfLoghandler::singleton()->debug("Loading language file for __() function");
include(BASEDIR . "/lang/de.php");
}
if($prefix) {
$string = "$prefix.$string";
}
if (array_key_exists($string, $lang['de'])) {
return $lang['de'][$string];
}
$last_translation_failed = true;
return $string;
global $lang;
global $last_translation_failed;
$last_translation_failed = false;
$string = str_replace(["Ä","Ö","Ü","ß","ä","ö","ü","ß"], ["ae","oe","ue","ss","ae","oe","ue", "ss"], strtolower($_string));
if(!$lang) {
//mfLoghandler::singleton()->debug("Loading language file for __() function");
include(BASEDIR . "/lang/de.php");
}
if($prefix) {
$string = "$prefix.$string";
}
if (array_key_exists($string, $lang['de'])) {
return $lang['de'][$string];
}
$last_translation_failed = true;
return $string;
}
function __last_translation_failed() {
global $last_translation_failed;
return $last_translation_failed;
}
global $last_translation_failed;
return $last_translation_failed;
}

View File

@@ -107,7 +107,7 @@ table.dataTable > tbody > tr.child span.dtr-data {
font-size: 15px;
}
.fa-circle-check {
.fa-circle-check,.fa-circle-a {
color: #23b900;
font-size: 15px;
}
@@ -125,26 +125,39 @@ table.dataTable.table-sm > thead > tr > th:not(.sorting_disabled) {
width: unset;
display: table-cell;
}
.deny-button
{
.deny-button {
color: #f00;
}
.edit-td {
text-align: left;
letter-spacing: 12px;
font-size: 1.1em;
}
.display-calendar
{
color:#0d6efd;
.display-calendar {
color: #0d6efd;
font-size: 30px;
margin-right:10px;
margin-right: 10px;
cursor: pointer;
}
.active-calendar
{
color:#25b343;
.active-calendar {
color: #25b343;
}
.select2-minw {
min-width: 150px;
}
.no-user-select {
-ms-user-select: None;
-moz-user-select: None;
-webkit-user-select: None;
user-select: None;
}
@media (max-width: 1200px) {
.fa-circle-xmark, .fa-ban, .fa-trash, .fa-edit, .fa-square-check, .fa-arrows-up-down-left-right {
font-size: 25px;
@@ -212,17 +225,21 @@ table.dataTable.table-sm > thead > tr > th:not(.sorting_disabled) {
font-size: 14px;
margin: 12px 3px 7px 0px;
}
.display-calendar
{
font-size:35px;
margin-top:5px;
margin-right:10px;
margin-bottom:20px;
.display-calendar {
font-size: 35px;
margin-top: 5px;
margin-right: 10px;
margin-bottom: 20px;
}
.label-calendar
{
margin-top:7px;
.label-calendar {
margin-top: 7px;
}
.select2-minw {
min-width: unset;
}
}
@@ -270,10 +287,11 @@ table.dataTable.dtr-inline.collapsed > tbody > tr.parent > td:first-child:before
transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out;
transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out, -webkit-box-shadow .15s ease-in-out;
}
table.dataTable.table-hover>tbody>tr:hover>* {
table.dataTable.table-hover > tbody > tr:hover > * {
box-shadow: none;
}
table.dataTable.table-striped>tbody>tr:nth-of-type(2n+1)>* {
box-shadow: none;
table.dataTable.table-striped > tbody > tr:nth-of-type(2n+1) > * {
box-shadow: none;
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,6 @@
/*!
FullCalendar Moment Plugin v6.1.10
Docs & License: https://fullcalendar.io/docs/moment-plugin
(c) 2023 Adam Shaw
*/
FullCalendar.Moment=function(e,t,l,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}var r=a(l);function u(e,t,l,n){let a;return"local"===t?a=r.default(e):"UTC"===t?a=r.default.utc(e):r.default.tz?a=r.default.tz(e,t):(a=r.default.utc(e),null!=l&&a.utcOffset(l)),a.locale(n),a}function o(e){return t=>t?e.format(t):""}var d=t.createPlugin({name:"@fullcalendar/moment",cmdFormatter:function(e,t){let l=function e(t){let l=t.match(/^(.*?)\{(.*)\}(.*)$/);if(l){let t=e(l[2]);return{head:l[1],middle:t,tail:l[3],whole:l[1]+t.whole+l[3]}}return{head:null,middle:null,tail:null,whole:t}}(e);if(t.end){let e=u(t.start.array,t.timeZone,t.start.timeZoneOffset,t.localeCodes[0]),n=u(t.end.array,t.timeZone,t.end.timeZoneOffset,t.localeCodes[0]);return function e(t,l,n,a){if(t.middle){let r=l(t.head),u=e(t.middle,l,n,a),o=l(t.tail),d=n(t.head),i=e(t.middle,l,n,a),f=n(t.tail);if(r===d&&o===f)return r+(u===i?u:u+a+i)+o}let r=l(t.whole),u=n(t.whole);if(r===u)return r;return r+a+u}(l,o(e),o(n),t.defaultSeparator)}return u(t.date.array,t.timeZone,t.date.timeZoneOffset,t.localeCodes[0]).format(l.whole)}});return t.globalPlugins.push(d),e.default=d,e.toMoment=function(e,t){if(!(t instanceof n.CalendarImpl))throw new Error("must supply a CalendarApi instance");let{dateEnv:l}=t.getCurrentData();return u(e,l.timeZone,null,l.locale.codes[0])},e.toMomentDuration=function(e){return r.default.duration(e)},Object.defineProperty(e,"__esModule",{value:!0}),e}({},FullCalendar,moment,FullCalendar.Internal);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -69,7 +69,7 @@ table = $('#datatable').DataTable({
"dom": cstmdom,
"ajax": {
"url": requestUrl,
"type": "GET",
"type": "POST",
"data": function (d) {
$('.display-calendar').each(function (index) {
if ($(this).hasClass('active-calendar')) {
@@ -86,6 +86,14 @@ table = $('#datatable').DataTable({
$('#must-time').text(json.time.must);
$('#holidays').text(json.time.holidays);
$('#plushours').text(json.time.plushours);
if ($("#plushours").text().includes("-")) {
$('#plushours-label').css('background-color', '#fda7a7');
} else {
$('#plushours-label').css('background-color', '#d0fbd9');
}
if (json.time.auto_workinghours == "1") {
$('#auto-workinghours-button').show();
}
return json.data;
}
@@ -127,7 +135,7 @@ table = $('#datatable').DataTable({
_: "comment.comment",
"sort": "comment.order"
},
className: "text-center"
className: "text-left"
}, {
"data": {
_: "edit.edit",
@@ -182,8 +190,14 @@ $(document).ready(function () {
$(this).prop("required", true);
$(this).prop("min", $('#date').val());
$(this).val($('#date').val());
})
} else if (parseInt($(this).find(':selected').data('hourday')) === 1) {
});
$("#div-calc-overtime").hide();
} else if (parseInt($(this).find(':selected').data('hourday')) === 1 || parseInt($(this).find(':selected').data('hourday')) === 6) {
if (parseInt($(this).find(':selected').data('hourday')) === 6) {
$("#div-calc-overtime").show();
} else {
$("#div-calc-overtime").hide();
}
$("#endtime-div").show();
$("#endtime-div").find('input').each(function () {
$(this).prop("required", true);
@@ -202,6 +216,7 @@ $(document).ready(function () {
$(this).prop("disabled", true);
});
$("#div-calc-overtime").hide();
$("#enddate-div").hide();
$("#enddate-div").find('input').each(function () {
$(this).prop("required", false);
@@ -214,6 +229,26 @@ $(document).ready(function () {
} else {
$('#comment').prop("required", false);
}
if (parseInt($(this).find(':selected').data('businesstrip')) === 1) {
$('.businesstrip-div').show();
$('#businesstrip').prop("checked", false);
$('#businesstrip_info').val('');
$('#businesstrip_info').hide();
} else {
$('.businesstrip-div').hide();
$('#businesstrip').prop("checked", false);
$('#businesstrip_info').val('');
$('#businesstrip_info').hide();
}
if (parseInt($(this).find(':selected').data('homeoffice')) === 1) {
$('#homeoffice-div').show();
$('#homeoffice').prop("checked", false);
} else {
$('#homeoffice').prop("checked", false);
$('#homeoffice-div').hide();
}
});
$("body").on("change", "#date", function () {
if ($('#enddate-div').css('display') === "block") {
@@ -233,6 +268,25 @@ $(document).ready(function () {
$('#end').prop("min", $('#start').val());
});
$("body").on("change", "#start,#end,#date,#timerecordingCategory_id", function () {
if (parseInt($('#timerecordingCategory_id').find(':selected').data('hourday')) === 6) {
$.post(checkWorkinghoursUrl, {
date: $.trim($('#date').val()),
start: $.trim($('#start').val()),
end: $.trim($('#end').val()),
ajax: 1
}).done(function (data) {
var result = $.parseJSON(data);
if (result.state === "success") {
$('#calc-overtime').html(result.message);
}
if (result.state === "error") {
$('#calc-overtime').html('<div class="text-danger text-bold">' + result.error + '</div>');
}
});
}
});
$("body").on("click", ".edit-button", function () {
$('#submit-button').hide().removeClass('btn-primary').addClass('btn-danger').show();
$('#submit-button').text('Ändern');
@@ -242,8 +296,22 @@ $(document).ready(function () {
$('#date').val($(this).data('date'));
$('#start').val($(this).data('start'));
$('#end').val($(this).data('end'));
$('#end').prop("min", $('#start').val());
$('#enddate').val($(this).data('enddate'));
$('#enddate').prop("min", $('#date').val());
$('#comment').val($(this).data('comment'));
if ($(this).data('businesstrip') == 1) {
$('#businesstrip').prop("checked", true);
$('#businesstrip_info').val($(this).data('businesstripinfo'));
$('#businesstrip_info').show();
$('#businesstrip_info').prop('required', true);
$('#homeoffice-div').hide();
}
if ($(this).data('homeoffice') == 1) {
$('.businesstrip-div').hide();
$('#homeoffice').prop("checked", true);
$('#homeoffice-div').show();
}
$('.alert-success').remove();
window.scrollTo(0, 0);
});
@@ -252,6 +320,12 @@ $(document).ready(function () {
$('#submit-button').text('Speichern');
$('#cancel-button').hide();
$('#id').val('');
$('.businesstrip-div').hide();
$('#businesstrip').prop("checked", false);
$('#businesstrip_info').val('');
$('#businesstrip_info').hide();
$('#homeoffice').prop("checked", false);
$('#timerecordingCategory_id').change();
});
$("body").on("change", "#dataweek,#datamonth,#datayear", function () {
@@ -286,11 +360,56 @@ $(document).ready(function () {
if ($(this).prop('checked') == true) {
$('#businesstrip_info').show();
$('#businesstrip_info').prop('required', true);
$('#homeoffice').prop('checked', false);
$('#homeoffice-div').hide();
} else {
$('#businesstrip_info').hide();
$('#businesstrip_info').val('');
$('#businesstrip_info').prop('required', false);
$('#timerecordingCategory_id').change();
}
});
$("body").on("click", "#homeoffice", function () {
if ($(this).prop('checked') == true) {
$('#businesstrip').prop('checked', false);
$('.businesstrip-div').hide();
$('#businesstrip_info').hide();
$('#businesstrip_info').val('');
$('#businesstrip_info').prop('required', false);
} else {
$('#timerecordingCategory_id').change();
}
});
$("body").on("click", "#auto-workinghours-button", function () {
var timestamp = $('#dataweek').val() * 1000
const date = new Date(timestamp);
var day = date.getDay(),
diff = date.getDate() - day + (day == 0 ? -6 : 1);
diff = date.getDate() - day + (day == 0 ? -6 : 1);
var monday = new Date(date.setDate(diff));
monday = monday.getTime();
monday = new Date(monday);
monday = monday.toLocaleDateString('de-DE');
//last day of week
var sunday = new Date(date.setDate(diff + 6));
sunday = sunday.getTime();
sunday = new Date(sunday);
sunday = sunday.toLocaleDateString('de-DE');
if (confirm('Sollen die Arbeitszeiten von ' + monday + ' bis ' + sunday + ' automatisch eingetragen werden?')) {
$.post(autoWorkinghoursUrl, {
dataweek: $.trim($('#dataweek').val()),
ajax: 1
}).done(function (data) {
table.ajax.reload();
});
}
@@ -309,6 +428,14 @@ $(document).ready(function () {
$('form').submit(function (e) {
e.preventDefault();
$('#alert-box').remove();
var businesstrip = false;
var homeoffice = false;
if ($('#businesstrip').prop('checked') == true) {
businesstrip = 1;
}
if ($('#homeoffice').prop('checked') == true) {
homeoffice = 1;
}
$.post(insertUrl, {
id: $.trim($('#id').val()),
timerecordingCategory_id: $.trim($('#timerecordingCategory_id').val()),
@@ -317,6 +444,10 @@ $(document).ready(function () {
start: $.trim($('#start').val()),
end: $.trim($('#end').val()),
comment: $.trim($('#comment').val()),
businesstrip: businesstrip,
businesstrip_info: $.trim($('#businesstrip_info').val()),
homeoffice: homeoffice,
hourday: $.trim($('#timerecordingCategory_id').find(':selected').data('hourday')),
ajax: 1
}).done(function (data) {
var result = $.parseJSON(data);
@@ -328,6 +459,10 @@ $(document).ready(function () {
<h5><i class="icon fas fa-check"></i> Erfolgreich</h5>
` + result.message + `</div>
</div>`);
$('#businesstrip').prop('checked', false);
$('#businesstrip_info').hide();
$('#businesstrip_info').val('');
$('#businesstrip_info').prop('required', false);
}
if (result.state === "error") {
$('.wrapper .container-fluid').prepend(`<div id="alert-box" class="row">
@@ -345,5 +480,6 @@ $(document).ready(function () {
table.ajax.reload();
});
});
$('#timerecordingCategory_id').change();
})
;

View File

@@ -29,8 +29,13 @@ $('#filterrow th').each(function (i) {
if (hidesearch.includes($(this).index())) {
} else if (columnfilter.includes($(this).index())) {
$(this).html('<select style="padding: 0;height: 28px;;text-align: center;" id="selectsearch" class="form-control form-control-select form-control-special" data-index="' + i + '">' + columnoptions + '</select>');
} else if ($(this).index() == 0) {
var options = '<option value="">Alle</option>';
$('#user_id_select').find('option').each(function () {
options += '<option data-userid="' + $(this).val() + '" value="' + $(this).text() + '">' + $(this).text() + '</option>';
});
$(this).html('<select id="selectsearch" class="form-control form-control-select form-control-special select2 select2-minw" data-index="' + i + '">' + options + '</select>');
} else {
$(this).html('<input type="text" placeholder="' + title + '" class="form-control" data-index="' + i + '" value="" />');
@@ -61,7 +66,7 @@ table = $('#datatable').DataTable({
$('#datatable_filter').append('<i id="clear_cookie" class="fas fa-times clear-fa" title="Filter löschen" aria-hidden="true" ></i>');
$('#clear_cookie').click(function () {
$('#filterrow input').val('');
$('#filterrow select').val('');
$('#filterrow select').val('').change();
table.search('').columns().search('').draw();
});
},
@@ -85,6 +90,7 @@ table = $('#datatable').DataTable({
$('#must-time').text(json.time.must);
$('#holidays').text(json.time.holidays);
$('#plushours').text(json.time.plushours);
$('#selectsearch').change();
return json.data;
}
@@ -133,7 +139,7 @@ table = $('#datatable').DataTable({
_: "comment.comment",
"sort": "comment.order"
},
className: "text-center"
className: "text-left"
}, {
"data": {
_: "edit.edit",
@@ -177,6 +183,7 @@ if (state) {
$(document).ready(function () {
$(".select2").select2();
$("body").on("change", "#timerecordingCategory_id", function () {
if (parseInt($(this).find(':selected').data('hourday')) === 2) {
$("#endtime-div").hide();
@@ -188,8 +195,16 @@ $(document).ready(function () {
$(this).prop("required", true);
$(this).prop("min", $('#date').val());
$(this).val($('#date').val());
})
} else if (parseInt($(this).find(':selected').data('hourday')) === 1) {
});
$('#days-div').hide();
$('#days').prop("required", false);
$("#div-calc-overtime").hide();
} else if (parseInt($(this).find(':selected').data('hourday')) === 1 || parseInt($(this).find(':selected').data('hourday')) === 6) {
if (parseInt($(this).find(':selected').data('hourday')) === 6) {
$("#div-calc-overtime").show();
} else {
$("#div-calc-overtime").hide();
}
$("#endtime-div").show();
$("#endtime-div").find('input').each(function () {
$(this).prop("required", true);
@@ -200,26 +215,67 @@ $(document).ready(function () {
$(this).prop("required", false);
$(this).prop("min", '');
$(this).val('');
})
});
$('#days-div').hide();
$('#days').prop("required", false);
} else if (parseInt($(this).find(':selected').data('hourday')) === 3 || parseInt($(this).find(':selected').data('hourday')) === 4) {
$("#endtime-div").hide();
$("#endtime-div").find('input').each(function () {
$(this).prop("required", false);
$(this).prop("disabled", true);
});
$("#div-calc-overtime").hide();
$("#enddate-div").hide();
$("#enddate-div").find('input').each(function () {
$(this).prop("required", false);
$(this).prop("min", '');
$(this).val('');
});
$('#days-div').hide();
$('#days').prop("required", false);
} else if (parseInt($(this).find(':selected').data('hourday')) === 5) {
$("#endtime-div").hide();
$("#endtime-div").find('input').each(function () {
$(this).prop("required", false);
$(this).prop("disabled", true);
});
$("#enddate-div").hide();
$("#enddate-div").find('input').each(function () {
$(this).prop("required", false);
$(this).prop("min", '');
$(this).val('');
})
});
$('#days-div').show();
$('#days').prop("required", true);
}
if (parseInt($(this).find(':selected').data('comment')) === 1) {
$('#comment').prop("required", true);
} else {
$('#comment').prop("required", false);
}
if (parseInt($(this).find(':selected').data('businesstrip')) === 1) {
$('.businesstrip-div').show();
$('#businesstrip').prop("checked", false);
$('#businesstrip_info').val('');
$('#businesstrip_info').hide();
} else {
$('.businesstrip-div').hide();
$('#businesstrip').prop("checked", false);
$('#businesstrip_info').val('');
$('#businesstrip_info').hide();
}
if (parseInt($(this).find(':selected').data('homeoffice')) === 1) {
$('#homeoffice-div').show();
$('#homeoffice').prop("checked", false);
} else {
$('#homeoffice').prop("checked", false);
$('#homeoffice-div').hide();
}
});
$("body").on("change", "#date", function () {
if ($('#enddate-div').css('display') === "block") {
@@ -238,6 +294,27 @@ $(document).ready(function () {
}
$('#end').prop("min", $('#start').val());
});
$("body").on("change", "#start,#end,#date,#timerecordingCategory_id,#user_id_select", function () {
if (parseInt($('#timerecordingCategory_id').find(':selected').data('hourday')) === 6) {
var userid;
userid = $('#user_id_select').val();
$.post(checkWorkinghoursUrl, {
user_id: userid,
date: $.trim($('#date').val()),
start: $.trim($('#start').val()),
end: $.trim($('#end').val()),
ajax: 1
}).done(function (data) {
var result = $.parseJSON(data);
if (result.state === "success") {
$('#calc-overtime').html(result.message);
}
if (result.state === "error") {
$('#calc-overtime').html('<div class="text-danger text-bold">' + result.error + '</div>');
}
});
}
});
$("body").on("click", ".edit-button", function () {
$('#submit-button').hide().removeClass('btn-primary').addClass('btn-danger').show();
@@ -254,24 +331,74 @@ $(document).ready(function () {
$('#date').val($(this).data('date'));
$('#start').val($(this).data('start'));
$('#end').val($(this).data('end'));
$('#end').prop("min", $('#start').val());
$('#days').val($(this).data('days'));
$('#enddate').val($(this).data('enddate'));
$('#enddate').prop("min", $('#date').val());
$('#comment').val($(this).data('comment'));
if ($(this).data('businesstrip') == 1) {
$('#businesstrip').prop("checked", true);
$('#businesstrip_info').val($(this).data('businesstripinfo'));
$('#businesstrip_info').show();
$('#businesstrip_info').prop('required', true);
$('#homeoffice-div').hide();
}
if ($(this).data('homeoffice') == 1) {
$('.businesstrip-div').hide();
$('#homeoffice').prop("checked", true);
$('#homeoffice-div').show();
}
$('.alert-success').remove();
window.scrollTo(0, 0);
});
$("body").on("click", "#cancel-button", function () {
$('#submit-button').hide().removeClass('btn-danger').addClass('btn-primary').show();
$('#submit-button').text('Speichern');
$('#cancel-button').hide();
$('#user_id_select').prop('disabled', false);
$('#user_id_input').prop('disabled', true);
$('#user_id_select').change();
$('#timerecordingCategory_id').val($(this).data('category')).change();
$('#timerecordingCategory_id').change();
$('#id').val('');
$('.businesstrip-div').hide();
$('#businesstrip').prop("checked", false);
$('#businesstrip_info').val('');
$('#businesstrip_info').hide();
$('#homeoffice').prop("checked", false);
$('#timerecordingCategory_id').change();
});
$("body").on("change", "#dataweek,#datamonth,#datayear", function () {
table.ajax.reload(null, false);
});
$("body").on("change", "#selectsearch", function () {
var datatype;
if (!$(this).val()) {
$('#must-time').text('N/A');
$('#is-time').text('N/A');
} else {
$('.display-calendar').each(function (index) {
if ($(this).hasClass('active-calendar')) {
datatype = $(this).data('datatype');
}
});
if (datatype == 1 || datatype == 2) {
$.post(requestTimesUrl, {
id: $.trim($(this).data('id')),
datatype: datatype,
user_id: $(this).find(':selected').data('userid'),
dataweek: $('#dataweek').val(),
datamonth: $('#datamonth').val(),
ajax: 1
}).done(function (data) {
var json = $.parseJSON(data);
$('#must-time').text(json.time.must);
$('#is-time').text(json.time.is);
});
}
}
});
$("body").on("click", ".display-calendar", function () {
$('.display-calendar').each(function (index) {
$(this).removeClass('active-calendar');
@@ -297,6 +424,38 @@ $(document).ready(function () {
$(".select2").select2();
table.ajax.reload(null, false);
});
$("body").on("click", "#businesstrip", function () {
if ($(this).prop('checked') == true) {
$('#businesstrip_info').show();
$('#businesstrip_info').prop('required', true);
$('#homeoffice').prop('checked', false);
$('#homeoffice-div').hide();
} else {
$('#businesstrip_info').hide();
$('#businesstrip_info').val('');
$('#businesstrip_info').prop('required', false);
$('#timerecordingCategory_id').change();
}
});
$("body").on("click", "#homeoffice", function () {
if ($(this).prop('checked') == true) {
$('#businesstrip').prop('checked', false);
$('.businesstrip-div').hide();
$('#businesstrip_info').hide();
$('#businesstrip_info').val('');
$('#businesstrip_info').prop('required', false);
} else {
$('#timerecordingCategory_id').change();
}
});
$("body").on("click", ".delete-item", function () {
if (confirm('Buchung wirklich löschen?')) {
$.post(deleteUrl, {
@@ -312,10 +471,15 @@ $(document).ready(function () {
e.preventDefault();
$('#alert-box').remove();
var userid;
if ($.trim($('#id').val())) {
userid = $('#user_id_input').val();
userid = $('#user_id_select').val();
var businesstrip = false;
var homeoffice = false;
if ($('#businesstrip').prop('checked') == true) {
businesstrip = 1;
}
if ($('#homeoffice').prop('checked') == true) {
homeoffice = 1;
}
$.post(insertUrl, {
id: $.trim($('#id').val()),
user_id: userid,
@@ -324,7 +488,12 @@ $(document).ready(function () {
enddate: $.trim($('#enddate').val()),
start: $.trim($('#start').val()),
end: $.trim($('#end').val()),
days: $.trim($('#days').val()),
comment: $.trim($('#comment').val()),
businesstrip: businesstrip,
businesstrip_info: $.trim($('#businesstrip_info').val()),
homeoffice: homeoffice,
hourday: $.trim($('#timerecordingCategory_id').find(':selected').data('hourday')),
ajax: 1
}).done(function (data) {
var result = $.parseJSON(data);
@@ -336,6 +505,10 @@ $(document).ready(function () {
<h5><i class="icon fas fa-check"></i> Erfolgreich</h5>
` + result.message + `</div>
</div>`);
$('#businesstrip').prop('checked', false);
$('#businesstrip_info').hide();
$('#businesstrip_info').val('');
$('#businesstrip_info').prop('required', false);
}
if (result.state === "error") {
$('.wrapper .container-fluid').prepend(`<div id="alert-box" class="row">
@@ -356,5 +529,7 @@ $(document).ready(function () {
table.ajax.reload(null, false);
});
});
$('#timerecordingCategory_id').change();
})
;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,26 @@
<?php
//require 'vendor/autoload.php';
require("../config/config.php");
define('FRONKDB_SQLDEBUG', false);
error_reporting(E_ALL & ~(E_NOTICE | E_STRICT | E_DEPRECATED));
require_once(LIBDIR . "/mvcfronk/mfRouter/mfRouter.php");
require_once(LIBDIR . "/mvcfronk/mfBase/mfBaseModel.php");
require_once(LIBDIR . "/mvcfronk/mfBase/mfBaseController.php");
$me = new User(154);
define("INTERNAL_USER_ID", $me->id);
define("INTERNAL_USER_USERNAME", $me->username);
$timerecordingemployees = TimerecordingEmployeeModel::search(['startdate' => 1]);
//var_dump($timerecordingemployees);
foreach ($timerecordingemployees as $timerecordingemployee) {
$employee = new TimerecordingController();
$employee->updatePlushours($timerecordingemployee->user_id);
}