Merge branch 'master' into fronkdev

This commit is contained in:
Frank Schubert
2024-04-18 14:05:22 +02:00
106 changed files with 10509 additions and 211 deletions

View File

@@ -472,159 +472,180 @@
var check = parseInt(iban.substr(2, 2));
var account = iban.substr(4);
var searchRange = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split('');
//var replaceRange = [];
var checkStr = account + cc + "00";
for(var i = 0; i <= 25; i++) {
checkStr = checkStr.replace(searchRange[i], i + 10);
};
// make checksum
var checksum = parseInt(checkStr.substr(0,1));
for(pos = 1; pos < checkStr.length; pos++) {
checksum *= 10;
checksum += parseInt(checkStr.substr(pos, 1));
checksum %= 97;
}
if(98 - checksum == check) {
return true;
} else {
return false;
}
}
function validateIbanBic(iban, bic) {
if(!iban) return false;
iban = iban.toUpperCase().replace(/\s+/, '');
$.post("<?=self::getUrl("Address", "api")?>", {
do: "validateIbanBic",
iban: iban,
bic: bic
},
function(success) {
if(success.status == "OK") {
var data = success.result;
$("#bank-error").hide();
$("#bank-error").text("");
if(data.iban_correct && data.bic_correct && (!data.iban_sus || data.iban_sus === "www")) {
bankdata_valid = true;
$('#addressForm').submit();
return;
}
var bank_error = [];
if(!data.iban_correct) {
$("#bank_account_iban").addClass("invalid");
bank_error.push("Ungültige IBAN!");
}
if(data.iban_sus && data.iban_sus !== "www") {
$("#bank_account_iban").addClass("invalid");
bank_error.push("IBAN verdächtig (" + data.iban_sus + ")!");
}
if(!data.bic_correct) {
$("#bank_account_bic").addClass("invalid");
bank_error.push("Ungültige BIC!");
if(Array.isArray(data.bic)) {
bank_error.push(" Mögliche korrekte BIC: " + data.bic.join(", "));
}
}
$("#bank-error").html(bank_error.join("<br />\n"));
$("#bank-error").show();
$('html, body').animate( {scrollTop: $('#billing-data').offset().top - 230}, 200);
} else {
$("#bank-error").text("Beim Validieren der Bankdaten ist ein Fehler aufgetreten.");
var searchRange = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split('');
//var replaceRange = [];
var checkStr = account + cc + "00";
for(var i = 0; i <= 25; i++) {
checkStr = checkStr.replace(searchRange[i], i + 10);
};
// make checksum
var checksum = parseInt(checkStr.substr(0,1));
for(pos = 1; pos < checkStr.length; pos++) {
checksum *= 10;
checksum += parseInt(checkStr.substr(pos, 1));
checksum %= 97;
}
},
"json"
);
return false;
}
$('#addressForm').submit(function(e) {
$("#error").hide();
$("#bank-error").hide();
if($('#billing_type').val() == "sepa") {
console.log("bankdata_valid (1): " + bankdata_valid);
if(bankdata_valid) {
return true;
}
if(!validateIbanFormat($("#bank_account_iban").val())) {
$("#error").show();
console.log("nope");
}
console.log("bankdata_valid: " + bankdata_valid);
if($("#bank_account_iban").val() != "<?=$address->bank_account_iban?>" || $("#bank_account_bic").val() != "<?=$address->bank_account_bic?>") {
validateIbanBic($("#bank_account_iban").val(), $("#bank_account_bic").val());
} else {
return true;
}
e.preventDefault();
return false;
if(98 - checksum == check) {
return true;
} else {
return false;
}
}
});
/*
* link autocomplete
*/
$('.link-autocomplete').autoComplete();
$('.link-autocomplete').keydown(function() {
if(event.keyCode == 13) {
event.preventDefault();
return false;
}
});
/*
* Links autocomplete
*/
$('.link-autocomplete').on("autocomplete.select", function(evt, item) {
autocompleteSelect(evt,item);
});
function autocompleteSelect(evt, item) {
if(item && item.value === 0) {
$('.link-autocomplete').autoComplete('set', null);
return;
function validateIbanBic(iban, bic) {
if(!iban) return false;
iban = iban.toUpperCase().replace(/\s+/, '');
$.post("<?=self::getUrl("Address", "api")?>", {
do: "validateIbanBic",
iban: iban,
bic: bic
},
function(success) {
if(success.status == "OK") {
var data = success.result;
$("#bank-error").hide();
$("#bank-error").text("");
if(data.iban_correct && data.bic_correct && (!data.iban_sus || data.iban_sus === "www")) {
bankdata_valid = true;
$('#addressForm').submit();
return;
}
var bank_error = [];
if(!data.iban_correct) {
$("#bank_account_iban").addClass("invalid");
bank_error.push("Ungültige IBAN!");
}
if(data.iban_sus && data.iban_sus !== "www") {
$("#bank_account_iban").addClass("invalid");
bank_error.push("IBAN verdächtig (" + data.iban_sus + ")!");
}
if(!data.bic_correct) {
$("#bank_account_bic").addClass("invalid");
bank_error.push("Ungültige BIC!");
if(Array.isArray(data.bic)) {
bank_error.push(" Mögliche korrekte BIC: " + data.bic.join(", "));
}
}
$("#bank-error").html(bank_error.join("<br />\n"));
$("#bank-error").show();
$('html, body').animate( {scrollTop: $('#billing-data').offset().top - 230}, 200);
} else {
$("#bank-error").text("Beim Validieren der Bankdaten ist ein Fehler aufgetreten.");
}
},
"json"
);
return false;
}
var match = evt.currentTarget.id.match(/links_(\d+)_address_id/);
var link_num = match[1];
if(!link_num) {
console.log("Couldn't find selected Address");
function formatIBAN(input) {
let iban = input.value.replace(/\s/g, '');
let formattedIBAN = '';
for (let i = 0; i < iban.length; i++) {
if (i > 0 && i % 4 === 0) {
formattedIBAN += ' ';
}
formattedIBAN += iban[i];
}
input.value = formattedIBAN;
}
addLink(Number(link_num) + 1);
}
function addLink(linknum) {
if(!linknum) {
console.log("no linknum");
return false;
$("#bank_account_iban").on("input", function () {
formatIBAN(this);
});
formatIBAN(document.getElementById('bank_account_iban'));
$('#addressForm').submit(function(e) {
$("#error").hide();
$("#bank-error").hide();
$("#bank_account_iban").val($("#bank_account_iban").val().replaceAll(/\s/g, ''));
if($('#billing_type').val() == "sepa") {
console.log("bankdata_valid (1): " + bankdata_valid);
if(bankdata_valid) {
return true;
}
if(!validateIbanFormat($("#bank_account_iban").val())) {
$("#error").show();
console.log("nope");
}
console.log("bankdata_valid: " + bankdata_valid);
if($("#bank_account_iban").val() != "<?=$address->bank_account_iban?>" || $("#bank_account_bic").val() != "<?=$address->bank_account_bic?>") {
validateIbanBic($("#bank_account_iban").val(), $("#bank_account_bic").val());
} else {
return true;
}
e.preventDefault();
return false;
}
});
/*
* link autocomplete
*/
$('.link-autocomplete').autoComplete();
$('.link-autocomplete').keydown(function() {
if(event.keyCode == 13) {
event.preventDefault();
return false;
}
});
/*
* Links autocomplete
*/
$('.link-autocomplete').on("autocomplete.select", function(evt, item) {
autocompleteSelect(evt,item);
});
function autocompleteSelect(evt, item) {
if(item && item.value === 0) {
$('.link-autocomplete').autoComplete('set', null);
return;
}
var match = evt.currentTarget.id.match(/links_(\d+)_address_id/);
var link_num = match[1];
if(!link_num) {
console.log("Couldn't find selected Address");
}
addLink(Number(link_num) + 1);
}
if($("#links_" + linknum + "_address_id").length) {
console.log("gibs scho");
return false;
}
var new_link = '<div class="form-group row" id="link-' + linknum + '"> \
function addLink(linknum) {
if(!linknum) {
console.log("no linknum");
return false;
}
if($("#links_" + linknum + "_address_id").length) {
console.log("gibs scho");
return false;
}
var new_link = '<div class="form-group row" id="link-' + linknum + '"> \
<label class="col-lg-2 col-form-label" for="links_' + linknum + '_address_id"></label> \
<div class="col-lg-6"> \
<div class="input-group mb-3"> \

View File

@@ -112,7 +112,13 @@
<td><?=$address->bank_account_owner?></td>
</tr><tr>
<th>IBAN</th>
<td><?=$address->bank_account_iban?></td>
<td><?php
$iban = $address->bank_account_iban;
$iban = preg_replace('/\s+/', '', $iban);
$iban = chunk_split($iban, 4, ' ');
$iban = trim($iban);
echo $iban;
?></td>
</tr><tr>
<th>BIC</th>
<td><?=$address->bank_account_bic?></td>

View File

@@ -175,6 +175,9 @@ if ($devices->power != "0.0") {
} else {
$power = $devices->devicetype->power;
}
foreach ($devicesall as $deviceall) {
$DevicesAll[$deviceall->id] = $deviceall->name;
}
?>
<div class="row">
<div class="col-12">
@@ -205,6 +208,12 @@ if ($devices->power != "0.0") {
<th>Geräte Hersteller</th>
<td><?= $devices->devicetype->devicemanufactor->name ?> </td>
</tr>
<?php if ($devices->parent_id) : ?>
<tr>
<th>Parent Device</th>
<td><a href="<?= self::getUrl("Device", "Detail", ["id" => $devices->parent_id]) ?>"><?= $DevicesAll[$devices->parent_id]?></a></td>
</tr>
<?php endif; ?>
<tr>
<th>Mac Adresse</th>
<td><?= $devices->mac ?> </td>
@@ -221,6 +230,7 @@ if ($devices->power != "0.0") {
<th>Leistung</th>
<td><?= $power ?> Watt</td>
</tr>
<tr>
<th>Bemerkung</th>
<td><?= nl2br($devices->comment) ?> </td>

View File

@@ -22,6 +22,10 @@ if (isset($_GET['returnto']) && $_GET['returnto'] == "device-detail") {
} else {
$cancelUrl = self::getUrl("Device");
}
foreach ($devices as $Device) {
$Devices[$Device->id] = $Device->name;
}
asort($Devices);
?>
<link href="<?= self::getResourcePath() ?>assets/css/datatables-std.css?<?= date('U') ?>" rel="stylesheet"
type="text/css"/>
@@ -80,6 +84,17 @@ 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="parent_id">Parent </label>
<div class="col-lg-10">
<select class="select2 form-control " name="parent_id" id="parent_id">
<option value="">&nbsp;</option>
<?php foreach ($Devices as $key => $value): ?>
<option value="<?= $key ?>" <?= ($device->parent_id == $key) ? "selected='selected'" : "" ?>><?= ($value) ?></option>
<?php endforeach; ?>
</select>
</div>
</div>
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="pop_id">Pop</label>
<div class="col-lg-10">

View File

@@ -0,0 +1,251 @@
<?php /** @noinspection PhpUndefinedClassInspection
* @var string $mfLayoutPackage
* @var TYPE_NAME $git_merge_ts
*/
//additional css /css/views/RaspberryDisplay.css
$JSGlobals = ["BASE_URL" => self::getUrl("Domain"),
"DASHBOARD_URL" => self::getUrl("Dashboard"),
"MFAPPNAME" => MFAPPNAME_SLUG,
"PAGE_TITLE" => "Domains",
"PATH" => [
["text" => MFAPPNAME_SLUG, "href" => self::getUrl("Dashboard")],
["text" => "Domain Management", "href" => self::getUrl("Domain")],
["text" => "Domains"]
],
"DOMAIN_API_URL" => self::getUrl("Domain/api"),
];
$additionalJS = ["plugins/vue/vue.js",
"plugins/axios/axios.min.js",
"plugins/vue/tt-components/tt-page-title.js",
"plugins/vue/tt-components/tt-table.js",
];
$additionalCSS = [
'plugins/vue/tt-components/css/tt-table.css',
];
include(realpath(dirname(__FILE__) . "/../../$mfLayoutPackage") . "/header.php"); ?>
<div id="app">
<!-- start page title -->
<tt-page-title :title="window['TT_CONFIG']['PAGE_TITLE']" :path="window['TT_CONFIG']['PATH']"></tt-page-title>
<tt-table :fetch-url="window['TT_CONFIG']['DOMAIN_API_URL'] + '?do=getDomains'" :table-config="domainsTableConfig"
small ref="table">
<template v-slot:top-buttons>
<button type="button" class="btn btn-primary" @click="reloadDomains">
<template v-if="reloadDomainsLoading">
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
</template>
<template v-else>
<i class="fas fa-sync-alt"></i>
Reload Domains
</template>
</button>
<div class="input-group">
<input type="text" class="form-control" v-model="checkDomainInput" placeholder="Neue Domain überprüfen">
<div class="input-group-append">
<button class="btn btn-primary" @click="checkDomainAvailability">
<template v-if="checkDomainLoading">
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
</template>
<template v-else>
<i class="fas fa-search"></i>
</template>
</button>
</div>
</template>
<!-- Slot to show DNS records button -->
<template v-slot:inwxroid="{ row }">
<button type="button" class="btn btn-primary" @click="showDnsRecordsModal(row.domain)"
:class="dnsRecordsModalLoading === row.domain ? 'disabled' : ''">
<template v-if="dnsRecordsModalLoading === row.domain">
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
</template>
<span v-else>DNS</span>
</button>
</template>
<!-- Slot to show if Domain is in Plesk -->
<template v-slot:pleskid="{ row }">
<i v-if="row.pleskId !== null" class="fas fa-check text-success"></i>
<i v-else class="fas fa-times text-danger"></i>
</template>
<!-- Convert all Dates to human readable format -->
<template v-slot:crdate="{ row }">{{ new Date(row.crDate * 1000).toLocaleDateString() }}</template>
<template v-slot:exdate="{ row }">{{ new Date(row.exDate * 1000).toLocaleDateString() }}</template>
<template v-slot:redate="{ row }">{{ new Date(row.reDate * 1000).toLocaleDateString() }}</template>
<template v-slot:update="{ row }">{{ new Date(row.upDate * 1000).toLocaleDateString() }}</template>
<!-- Registrant Admin Tech Billing from domainContacts -->
<template v-slot:registrant="{ row }">
{{ domainContacts[row.registrant] ? domainContacts[row.registrant]["name"] : '' }}
</template>
<template v-slot:admin="{ row }">{{ domainContacts[row.admin] ? domainContacts[row.admin]["name"] : ''}}
</template>
<template v-slot:tech="{ row }">{{ domainContacts[row.tech] ? domainContacts[row.tech]["name"] : ''}}
</template>
<template v-slot:billing="{ row }">{{ domainContacts[row.billing] ? domainContacts[row.billing]["name"] : ''}}
</template>
</tt-table>
<!-- Bootstrap Modal to query and show all DNS records for a domain -->
<div class="modal show d-block" tabindex="-1" role="dialog" style="background: rgba(0, 0, 0, 0.5);" ref="dnsRecordsModal" @click="dnsRecordsModal.domain = null" @keydown.esc="dnsRecordsModal.domain = null"
v-if="dnsRecordsModal.domain">
<div class="modal-dialog" role="document" style="max-width: fit-content" @click.stop>
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">DNS Records for {{ dnsRecordsModal.domain ?? '' }}</h5>
<button type="button" class="close" @click="dnsRecordsModal.domain = null">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<table class="tt-table table-striped table-bordered table-hover table-sm table-condensed">
<thead>
<tr>
<th>Record Class</th>
<th>Record Type</th>
<th>Record Host</th>
<th>Record Value</th>
<th>Record TTL</th>
</tr>
</thead>
<tbody>
<tr v-for="record in dnsRecordsModal.records">
<td>{{ record.class }}</td>
<td>{{ record.type }} {{ record.pri ? '(' + record.pri + ')' : '' }}</td>
<td>{{ record.host }}</td>
<td>{{ record.value }}</td>
<td>{{ record.ttl }}</td>
</tr>
</tbody>
</table>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" @click="dnsRecordsModal.domain = null">Close</button>
</div>
</div>
</div>
</div>
</div>
<script>
new Vue({
el: '#app',
data: {
window: window,
domainContacts: {},
reloadDomainsLoading: false,
dnsRecordsModalLoading: null,
dnsRecordsModal: {
domain: null,
records: []
},
checkDomainInput: '',
checkDomainResult: null,
checkDomainLoading: false
},
mounted() {
this.fetchDomainContacts()
},
computed: {
domainsTableConfig() {
const base = {
headers: [
{text: "ID", key: "inwxRoId", "filter": false},
{text: "Domain", key: "domain"},
{text: "Plesk", key: "pleskId", filter: false},
{text: "Created Date", key: "crDate", filter: false},
{text: "Expiration Date", key: "exDate", filter: false},
{text: "Renewal Date", key: "reDate", filter: false},
{text: "Updated Date", key: "upDate", filter: false},
{text: "Transfer Lock", key: "transferLock"},
{text: "Authorization Code", key: "authCode"},
{text: "Registrant ID", key: "registrant"},
{text: "Admin ID", key: "admin"},
{text: "Tech ID", key: "tech"},
{text: "Billing ID", key: "billing"},
{text: "Name Servers", key: "ns"}
],
tableHeader: 'Bestellungen',
}
const domainContactsSorted = Object.entries(this.domainContacts).sort(([, a], [, b]) => a.name.localeCompare(b.name))
const domainContactsFilterOptions = domainContactsSorted.map(([, contact]) => {
return {text: contact.name, value: contact.inwxRoId}
})
// for registrant admin tech billing set filter to select with domainContacts if domainContacts is not empty
if (Object.keys(this.domainContacts).length > 0) {
base.headers = base.headers.map(header => {
if (['registrant', 'admin', 'tech', 'billing'].includes(header.key)) {
header.filter = 'select'
header.filterOptions = domainContactsFilterOptions
}
return header
})
}
return base
}
},
methods: {
async showDnsRecordsModal(domain) {
this.dnsRecordsModalLoading = domain
this.dnsRecordsModal = {
domain: null,
records: []
}
const response = await axios.get(window['TT_CONFIG']['DOMAIN_API_URL'] + '?do=getDnsRecords&domain=' + domain)
this.dnsRecordsModal.domain = domain
this.dnsRecordsModal.records = response.data.map(record => {
if (typeof record.entries === 'object') {
record.value = record.entries[0]
} else {
record.value = record.target || record.txt || record.ip
}
if (record.type === 'SOA') {
record.value = record.mname + ' ' + record.rname + ' ' + record.serial + ' ' + record.refresh + ' ' + record.retry + ' ' + record.expire
}
return record
})
this.dnsRecordsModalLoading = null
this.$nextTick(() => {
this.$refs.dnsRecordsModal.focus()
})
},
async fetchDomainContacts() {
const response = await axios.get(window['TT_CONFIG']['DOMAIN_API_URL'] + '?do=getDomainContacts')
this.domainContacts = response.data
},
async reloadDomains() {
this.reloadDomainsLoading = true
const response = await axios.get(window['TT_CONFIG']['DOMAIN_API_URL'] + '?do=importAllDomains')
window.notify('success', response.data["importMessages"].join('<br>'))
await Promise.all([
this.fetchDomainContacts(),
this.$refs.table.fetchData(this.$refs.table.pagination.page)
])
this.reloadDomainsLoading = false
},
//TODO: make this cleaner
async checkDomainAvailability() {
this.checkDomainLoading = true
const response = await axios.get(window['TT_CONFIG']['DOMAIN_API_URL'] + '?do=checkDomain&domain=' + this.checkDomainInput)
const priceInformation = response.data.price.domain[this.checkDomainInput]
window.notify(response.data.status === 'free' ? 'success' : 'error',
`Domain ist ${response.data.status === 'free' ? 'verfügbar. Registrieren um' : 'nicht frei. Transfer um'} ${priceInformation.price}${priceInformation.currency}/${priceInformation.period === '1Y' ? 'Jahr' : priceInformation.period}`)
this.checkDomainLoading = false
}
}
})
</script>
<?php include(realpath(dirname(__FILE__) . "/../../$mfLayoutPackage") . "/footer.php"); ?>

View File

@@ -0,0 +1,244 @@
<?php include(realpath(dirname(__FILE__) . "/../../$mfLayoutPackage") . "/header.php"); ?>
<link href="<?= self::getResourcePath() ?>assets/css/select2-cstm.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"><a
href="<?= self::getUrl("FiberPlanDispatcher") ?>">Verteiler/Schächte</a></li>
<li class="breadcrumb-item active"><?= ($fiberplandispatchers->id) ? "bearbeiten" : "Neu" ?></li>
</ol>
</div>
<h4 class="page-title"><?= ($fiberplandispatchers->id) ? "Verteiler/Schacht bearbeiten" : "Neuer Verteiler/Schacht" ?></h4>
</div>
</div>
</div>
<!-- end page title -->
<?php
if (!$me->permissions->isAdmin) {
foreach ($networkaddresses as $networkaddress) {
if ($me->address->id == $networkaddress->address_id) {
$allowedNetworks[$networkaddress->network_id] = "ok";
}
}
}
?>
<style>
.fa-circle-plus {
color: #00b125;
cursor: pointer;
font-size: 17px;
margin-left: 5px;
}
.remove-sleeve {
cursor: pointer;
color: #ff0606;
font-size: 17px;
margin-left: 5px;
}
</style>
<div class="row">
<div class="col-lg-12">
<div class="card">
<div class="card-body">
<h4 class="header-title mb-2"><?= ($fiberplandispatchers->id) ? "Verteiler/Schacht bearbeiten" : "Neuer Verteiler/Schacht" ?></h4>
<div class="col-12">
<form class="form-horizontal" method="post"
action="<?= self::getUrl("FiberPlanDispatcher", "save") ?>">
<div class="card">
<div class="card-body">
<div class="row">
<div class="col-6">
<input type="hidden" name="id" value="<?= $fiberplandispatchers->id ?>"/>
<div class="form-group row">
<label class="col-lg-4 col-form-label" for="network_id">Netzgebiet
*</label>
<div class="col-lg-5">
<select class="select2 form-control "
name="network_id" id="network_id">
<option value="">&nbsp;</option>
<?php foreach ($networks as $key => $network):
if (!$me->permissions->isAdmin) {
if (!array_key_exists($network->id, $allowedNetworks)) {
continue;
}
}
?>
<option value="<?= $network->id ?>" <?= ($fiberplandispatchers->network_id == $network->id) ? "selected='selected'" : "" ?>><?= ($network->name) ?></option>
<?php endforeach; ?>
</select>
</div>
</div>
<div class="form-group row">
<label class="col-lg-4 col-form-label" for="gps_lat">Beschreibung
*</label>
<div class="col-lg-4">
<input type="text" required="required" step="any"
class="form-control" name="description" id="description"
value="<?= $fiberplandispatchers->description ?>">
</div>
</div>
<div class="form-group row">
<label class="col-lg-4 col-form-label" for="object_type">Objekt Typ
*</label>
<div class="col-lg-4">
<select class="select2 form-control" required="required"
name="object_type" id="object_type">
<option value="1" <?= ($fiberplandispatchers->object_type == '1') ? "selected='selected'" : "" ?>>
Verteiler
</option>
<option value="2" <?= ($fiberplandispatchers->object_type == '2') ? "selected='selected'" : "" ?>>
Schacht
</option>
<option value="3" <?= ($fiberplandispatchers->object_type == '3') ? "selected='selected'" : "" ?>>
Greenfield
</option>
</select>
</div>
</div>
<div class="form-group row">
<label class="col-lg-4 col-form-label" for="type">Typ</label>
<div class="col-lg-4">
<textarea id="type" name="type"
class="form-control"><?= $fiberplandispatchers->type ?></textarea>
</div>
</div>
<div class="form-group row">
<label class="col-lg-4 col-form-label" for="gps_lat">GPS
Breite/Länge</label>
<div class="col-lg-3">
<input type="number" step="any" class="form-control" name="gps_lat"
id="gps_lat" placeholder="GPS Breite"
value="<?= $fiberplandispatchers->gps_lat ?>">
</div>
<div class="col-lg-3">
<input type="number" step="any" class="form-control" name="gps_long"
id="gps_long" placeholder="GPS Länge"
value="<?= $fiberplandispatchers->gps_long ?>">
</div>
</div>
<div class="form-group row">
<label class="col-lg-4 col-form-label" for="comment">Kommentar</label>
<div class="col-lg-5">
<textarea id="comment" name="comment"
class="form-control"><?= $fiberplandispatchers->comment ?></textarea>
</div>
</div>
</div>
<div id="sleeves-main" class="col-6" <?= ($fiberplandispatchers->object_type == 2) ? "" : 'style="display:none"' ?>>
<div class="row">
<h4>Muffe(n) <i class="fa-regular fa-circle-plus add-sleeve"></i>
</h4>
</div>
<div id="sleeves-div">
<?php
if ($sleeves):
foreach ($sleeves as $sleeve) : ?>
<div class="form-group row">
<label class="col-lg-3 col-form-label"
>Muffe <i data-popid="5"
class="fa-regular fa-circle-minus remove-sleeve"></i></label>
<div class="col-lg-4">
<input type="text" required="required" step="any"
class="form-control" name="sleeves[]"
value="<?= $sleeve['name']; ?>">
</div>
</div>
<?php
endforeach;
endif;
?>
</div>
</div>
</div>
</div>
</div>
<div class="form-group row">
<label class="col-lg-2"></label>
<div class="col-lg-10">
<button type="submit" class="btn btn-primary">Speichern</button>
<a href="<?= self::getUrl("FiberPlanDispatcher") ?>">
<button type="button" class="btn btn-secondary">Abbrechen</button>
</a>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
<script type="text/javascript">
$("#network_id").select2({placeholder: ""});
$("#object_type").select2();
// disable mousewheel on a input number field when in focus
$('form').on('focus', 'input[type=number]', function (e) {
$(this).on('wheel.disableScroll', function (e) {
e.preventDefault()
})
});
$('form').on('blur', 'input[type=number]', function (e) {
$(this).off('wheel.disableScroll')
});
$(document).ready(function () {
$("body").on("click", ".remove-sleeve", function () {
$(this).closest('.form-group').remove();
});
$("body").on("change", "#object_type", function (){
if ($(this).val()=="2")
{
$('#sleeves-main').show()
}
else
{
$('#sleeves-main').hide()
$('#sleeves-div').empty()
}
});
$("body").on("click", ".add-sleeve", function () {
if ($('#sleeves-div').find('.form-group').length < 5) {
$('#sleeves-div').append(`<div class="form-group row">
<label class="col-lg-3 col-form-label"
>Muffe <i data-popid="5" class="fa-regular fa-circle-minus remove-sleeve"></i></label>
<div class="col-lg-4">
<input type="text" required="required" step="any"
class="form-control" name="sleeves[]"
value="">
</div>
</div>`);
}
})
})
;
</script>
<?php include(realpath(dirname(__FILE__) . "/../../$mfLayoutPackage") . "/footer.php"); ?>

View File

@@ -0,0 +1,122 @@
<?php
$objecttype[1] = 'Verteiler';
$objecttype[2] = 'Schacht';
$objecttype[3] = 'Greenfield';
?>
<?php include(realpath(dirname(__FILE__) . "/../../$mfLayoutPackage") . "/header.php"); ?>
<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">Verteiler und Schächte</li>
</ol>
</div>
<h4 class="page-title">Verteiler und Schächte</h4>
</div>
</div>
</div>
<!-- end page title -->
<div class="card">
<div class="card-body mb-3">
<div class="row">
<div class="col-12">
<div class="float-left">
<h4 class="header-title">Liste aller Verteiler und Schächte</h4>
</div>
<div class="float-right">
<a class="btn btn-primary mb-2" href="<?= self::getUrl("FiberPlanDispatcher", "add") ?>"><i
class="fas fa-plus"></i> Neuen Verteiler/Schacht anlegen</a>
</div>
</div>
</div>
<!-- --><?php //include(realpath(dirname(__FILE__) . "/../") . "/tpl/pagination.php"); ?>
<!-- --><?php //include(realpath(dirname(__FILE__) . "/../") . "/tpl/pagination-summary.php"); ?>
<table id="datatable" class="table table-striped table-hover table-sm">
<thead>
<tr>
<th class="text-center">Netzgebiet</th>
<th class="text-center">Beschreibung</th>
<th class="text-center">Objektart</th>
<th class="text-center">Type</th>
<th class="text-center">Koordinaten</th>
<th class="text-center">Kommentar</th>
<th class="edit-weight"></th>
</tr>
<tr id="filterrow">
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
</tr>
<thead>
<tbody>
<?php foreach ($fiberplandispatchers as $fiberplandispatcher): ?>
<?php
if ($fiberplandispatcher->gps_lat) {
$mapslink = '<a
title="Google-Maps: ' . $fiberplandispatcher->gps_lat . ' , ' . $fiberplandispatcher->gps_long . '"
class="mapsLink"
href="http://maps.google.com/?q=' . $fiberplandispatcher->gps_lat . ' , ' . $fiberplandispatcher->gps_long . '"
target="_blank">' . rtrim($fiberplandispatcher->gps_lat, 0) . ' , ' . rtrim($fiberplandispatcher->gps_long, 0) . '</a>';
} else {
$mapslink = 'N/A';
}
?>
<tr>
<td><?= $fiberplandispatcher->network->name ?></td>
<td><?= $fiberplandispatcher->description ?></td>
<td class="text-center"><?= $objecttype[$fiberplandispatcher->object_type] ?></td>
<td class="text-left"><?= nl2br($fiberplandispatcher->type) ?></td>
<td class="text-center"><?= $mapslink ?></td>
<td class="text-left"><?= nl2br($fiberplandispatcher->comment) ?></td>
<td style="text-align: left; letter-spacing: 4px; font-size: 1.1em;">
<a href="<?= self::getUrl("FiberPlanDispatcher", "edit", ["id" => $fiberplandispatcher->id]) ?>"><i
class="far fa-edit" title="Bearbeiten"></i></a>
<a href="<?= self::getUrl("FiberPlanDispatcher", "delete", ["id" => $fiberplandispatcher->id]) ?>"
onclick="if(!confirm('Verteiler/Schacht wirklich löschen?')) return false;"
class="text-danger"
title="Löschen"><i class="fas fa-trash"></i></a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
<script type="text/javascript">
var hidesearch = [6];
$(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

@@ -0,0 +1,530 @@
<?php include(realpath(dirname(__FILE__) . "/../../$mfLayoutPackage") . "/header.php"); ?>
<link href="<?= self::getResourcePath() ?>assets/css/datatables-std.css?<?= date('U') ?>" rel="stylesheet"
type="text/css"/>
<?php
$markers = [];
$typeOption[1] = "Einzel";
$typeOption[2] = "Schutzrohr";
$typeOption[3] = "Verband";
$starting_pointOption[1] = "Greenfield";
$starting_pointOption[2] = "POP";
$starting_pointOption[3] = "Building";
$starting_pointOption[4] = "Schacht-Verteiler";
$fiberplanpipestypes[1] = "Verteiler";
$fiberplanpipestypes[2] = "Schacht";
$fiberplanpipestypes[3] = "Greenfield";
$fiberplanpipestypes[4] = "Abzweigepunkt";
$dimension_v1Option[1] = "MR7";
$dimension_v1Option[2] = "MR14";
$dimension_v1Option[3] = "MR16";
$dimension_v1Option[4] = "MR20";
$dimension_v1Option[5] = "PE32";
$dimension_v1Option[6] = "PE40";
$dimension_v1Option[7] = "PE50";
$dimension_v1Option[8] = "KSR50";
$dimension_v1Option[9] = "KSR80";
$dimension_v1Option[10] = "KSR100";
$dimension_v2Option[1] = "Anzahl";
$dimension_v2Option[2] = "Dimenson";
$dimension_v2Option[3] = "Farben";
$state[10] = 'Geplant';
$state[20] = 'Umsetzung';
$state[30] = 'Fertiggestellt';
foreach ($pipworkeraddresses as $pipworkeraddress):
$Pipeworkers[$pipworkeraddress->id] = $pipworkeraddress->company;
endforeach;
foreach ($networks as $network):
$Network[$network->id] = $network->name;
endforeach;
$allNetworks[$fiberplanpipes->startpoint_network_id] = $Network[$fiberplanpipes->startpoint_network_id];
$allNetworks[$fiberplanpipes->endpoint_network_id] = $Network[$fiberplanpipes->endpoint_network_id];
if ($fiberplanpipes->address_id) {
$responsible = $Pipeworkers[$fiberplanpipes->address_id];
} else {
$responsible = "Person";
}
if ($fiberplanpipes->type == "3") {
$name = "";
if ($fiberplanpipes->fiberPlanPipeTemplate->pipe7x4 && $fiberplanpipes->fiberPlanPipeTemplate->pipe14x10) {
$name = $fiberplanpipes->fiberPlanPipeTemplate->fiberPlanPipeManufacturer->name . " " . $fiberplanpipes->fiberPlanPipeTemplate->pipe7x4 . "*7x4" . "/" . $fiberplanpipes->fiberPlanPipeTemplate->pipe14x10 . "*14x10";
} else if ($fiberplanpipes->fiberPlanPipeTemplate->pipe7x4) {
$name = $fiberplanpipes->fiberPlanPipeTemplate->fiberPlanPipeManufacturer->name . " " . $fiberplanpipes->fiberPlanPipeTemplate->pipe7x4 . "*7x4";
} else if ($fiberplanpipes->fiberPlanPipeTemplate->pipe14x10) {
$name = $fiberplanpipes->fiberPlanPipeTemplate->fiberPlanPipeManufacturer->name . " " . $fiberplanpipes->fiberPlanPipeTemplate->pipe14x10 . "*14x10";
}
$typeDescription = $name;
//
} else {
$typeDescription = $dimension_v1Option[$fiberplanpipes->type_description];
}
?>
<style>
#map {
height: 600px;
width: 100%;
}
.card-border {
border-left: 1px solid #428bca;
border-left-width: 5px;
border-radius: 3px;
}
.fiber-rack-div {
margin-top: 5px;
margin-bottom: 5px;
}
.fiber-color {
color: #0d6efd;
float: right;
margin-left: 5px;
}
.fiber-module-div {
padding-left: 5px;
padding-right: 5px;
margin-left: 5px;
margin-right: 5px;
margin-bottom: 5px;
border: 1px solid #e3e3e3;
}
.sp-border-rl {
padding-left: 5px;
padding-right: 5px;
}
.sp-table-border {
border: 1px solid #bfbfbf;
border-radius: 10px;
display: inline;
}
.sp-table-border > tbody {
padding: 10px;
}
.sp-table-border > thead td {
padding: 10px 0px 0px 0px;
font-weight: bold;
text-align: center;
font-size: 20px;
}
.sp-port-lines {
width: 50px;
border-top: 1px solid #000;
border-bottom: 1px solid #000;
}
#olt-splitter td {
height: 30px;
width: 150px;
border: 1px solid #bfbfbf;
margin-top: 15px;
display: block;
border-radius: 5px;
}
#olt-splitter-table thead {
padding: 10px 0px 0px 0px;
font-weight: bold;
font-size: 20px;
}
#olt-splitter-table thead td {
padding-top: 12px;
text-align: center;
}
.sp-splitter-count {
padding: 3px 10px 3px 10px;
width: 50px;
}
.sp-splitter-count-left {
padding: 3px 0px 3px 10px;
width: 50px;
}
.sp-splitter-count-right {
padding: 3px 10px 3px 0px;
width: 50px;
text-align: right;
}
.sp-splitter-count-edit {
-ms-user-select: None;
-moz-user-select: None;
-webkit-user-select: None;
user-select: None;
cursor: pointer;
}
.sp-splitter-count-show {
width: 46px;
display: inline-block;
text-align: center;
cursor: pointer;
text-decoration: underline;
padding-top: 2px;
-ms-user-select: None;
-moz-user-select: None;
-webkit-user-select: None;
user-select: None;
}
.sp-white-border {
border-color: #fff !important;
}
.sp-ont-text {
padding: 0px 5px 0px 5px;
}
.fa-circle-check {
color: #07ad2b;
}
.fa-circle-xmark {
color: #ff0000;
}
.fa-rotate-right {
color: #0d6efd;
cursor: pointer;
}
.ont-refresh-span, .ontdetail-refresh-span {
display: inline-block;
width: 20px;
margin-right: 50px;
min-height: 1px;
color: #0d6efd;
}
.text-decoration-underline {
text-decoration: underline;
cursor: pointer;
}
.condensed-ont th {
padding: 6px 0.85rem 6px 0.85rem !important;
}
.condensed-ont td {
padding: 6px 0.85rem 6px 0.85rem !important;
}
</style>
<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"><a href="<?= self::getUrl("FiberPlanPipe") ?>">Rohrverzeichnis</a>
</li>
<li class="breadcrumb-item active">Kabelverzeichnis Detail</li>
</ol>
</div>
<h4 class="page-title">Kabel: <span
class="font-weight-normal ml-1"><?= $fiberplanpipes->description ?></span>
<span class="ml-2">
<a href="<?= self::getUrl("FiberPlanPipe", "edit", ["id" => $fiberplanpipes->id, 'returnto' => "fiberplanpipe-detail"]) ?>">
<button class="btn btn-primary">Bearbeiten</button>
</a>
</span></h4>
</div>
</div>
</div>
<!-- end page title -->
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-body">
<div class="row">
<div class="col-4 card-border">
<div>
<h4>Allgemeine Informationen </h4>
</div>
<div>
<table class="table table-sm">
<tbody>
<tr>
<th class="w-50">Bezeichnung</th>
<td><?= $fiberplanpipes->description ?> </td>
</tr>
<tr>
<th>GisId</th>
<td><?= $fiberplanpipes->gisid ?> </td>
</tr>
<tr>
<th>Länge (m)</th>
<td>
<?= $fiberplanpipes->length ?> Meter
</td>
</tr>
<tr>
<th>Netzgebiet (e)</th>
<td><?= implode(', ', $allNetworks) ?> </td>
</tr>
<tr>
<th>Rohrtyp</th>
<td><?= $typeOption[$fiberplanpipes->type] ?></td>
</tr>
<tr>
<th>Rohrbezeichnung</th>
<td><?= $typeDescription ?> </td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="col-4 ">
<div>
<h4>&nbsp;</h4>
</div>
<table class="table table-sm">
<tbody>
<tr>
<th>Status</th>
<td><?= $state[$fiberplanpipes->status] ?> </td>
</tr>
<tr>
<th>Zuständig</th>
<td><?= $responsible ?> </td>
</tr>
<tr>
<th>Kontakt</th>
<td><?= $fiberplanpipes->responsible_text ?> </td>
</tr>
<tr>
<th>Bemerkung</th>
<td><?= nl2br($fiberplanpipes->comment) ?> </td>
</tr>
</tbody>
</table>
</div>
<div class="col-3 ">
</div>
</div>
<div class="row pb-3 pt-4 ">
<div class="col-12 text-center card-border">
<div>
<h4 class="text-left mb-3">Schematische Darstellung <i data-toggle="modal"
data-target="#pipemap"
class="fa-duotone fa-map-location-dot font-24"
style="--fa-primary-color: #fa0000; --fa-secondary-color: #232423;margin-left:5px;cursor:pointer"></i>
</h4>
</div>
<div class="ml-2">
<?php
if ($fiberplanpipeendpoints) :
$endpointcounter = count($fiberplanpipeendpoints);
$counter = 1;
foreach ($fiberplanpipeendpoints as $endpoint):
if ($endpoint->pop_id) {
$endpointname = '<a href="' . self::getUrl("Pop", "Detail", ["id" => $endpoint->pop->id]) . '" target="_blank">' . $endpoint->pop->name . '</a>';
$endpointtype = "Pop";
$gps_lat = $endpoint->pop->gps_lat;
$gps_long = $endpoint->pop->gps_long;
} elseif ($endpoint->fiberPlanDispatcher_id) {
$endpointname = $endpoint->fiberPlanDispatcher->description;
$endpointtype = $fiberplanpipestypes[$endpoint->fiberPlanDispatcher->object_type];
$gps_lat = $endpoint->fiberPlanDispatcher->gps_lat;
$gps_long = $endpoint->fiberPlanDispatcher->gps_long;
}
$coordinates = "";
if ($gps_lat) {
$coordinates = round($gps_lat, 5) . " , " . round($gps_long, 5);
$coordinates = '<a title="Google-Maps: ' . $coordinates . '" class="mapsLink" href="http://maps.google.com/?q=' . $coordinates . '" target="_blank">' . $coordinates . '</a>';
}
?>
<table class="sp-table-border float-left border-collapse: collapse;"
style="min-height: 150px;">
<thead style="display: inline;">
<tr>
<th colspan="3"
class="text-center font-15">
<div class="pt-2 pl-2 pr-2"><?= $endpointtype; ?></div>
</th>
</tr>
<tr>
<th colspan="3"
class="text-center font-15">
<div class="pl-2 pr-2"><?= $endpointname; ?></div>
</th>
</tr>
<tr>
<th colspan="3"
class="text-center font-13">
<div class="pb-2 pl-2 pr-2"><?= $coordinates ?></div>
</th>
</tr>
</thead>
<?php
if ($gps_lat) {
$markers[] = array(
"gps_lat" => $gps_lat,
"gps_long" => $gps_long,
"name" => $endpointname,
);
}
?>
</table>
<?php
if ($endpointcounter > $counter) :
?>
<table id="olt-port-table" class="float-left" style="width: 100px">
<thead>
<tr>
<td style="height:40px;"></td>
</tr>
</thead>
<tbody id="olt-ports">
<tr>
<td data-oltport="0"
class="font-13"><?= $fibers[$fiberplancables->fibers]['fibers']; ?></td>
</tr>
<tr>
<td data-oltport="0" class="sp-port-lines"
style="width: 70px; background-color: <?= $pipecolor; ?> ;height: <?= $pipeheight; ?>;"></td>
</tr>
<tr>
<td data-oltport="0" class="font-13"><?= $pipesub; ?>
</td>
</tr>
</tbody>
</table>
<?php
endif;
$counter++;
endforeach;
endif;
?>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="modal fade" id="pipemap" tabindex="-1" role="dialog" aria-labelledby="pipemap"
aria-hidden="true">
<div class="modal-dialog modal-dialog-centered modal-xl" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="pipemapLabel">Rohrverzeichnis</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div id="map"></div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Schließen</button>
</div>
</div>
</div>
</div>
<?php if ($markers) :
?>
<script type="text/javascript">
var marker;
var polylinec;
var polyline;
var map = L.map('map').setView([51.505, -0.09], 13);
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19
}).addTo(map);
L.MakiMarkers.accessToken = '<?=TT_MAPBOX_TILE_API_TOKEN?>';
$(document).ready(function () {
var locations = [<?php
$counter = 0;
$lat = 0;
$long = 0;
foreach ($markers as $marker):
if ($counter > 0) echo ',';
?>
['<?= $marker['name'] ?>', <?= $marker['gps_lat'] ?>, <?= $marker['gps_long'] ?>]
<?php
$lat = $lat + $marker['gps_lat'];
$long = $long + $marker['gps_long'];
$counter++;
endforeach;
$lat = $lat / $counter;
$long = $long / $counter;
?>
];
var startlat = <?=$lat ?>;
var startlong = <?=$long ?>;
console.log('<?=$lat . " " . $long ?>')
$('#pipemap').on('show.bs.modal', function (event) {
var button = $(event.relatedTarget);
map.remove();
map = L.map('map').setView([51.505, -0.09], 13);
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19
}).addTo(map);
var icon_name = "town";
var icon_color = "#ec98a2";
var icon = L.MakiMarkers.icon({icon: icon_name, color: icon_color, size: "l"});
var oldlat;
var oldlong;
map.setView([startlat, startlong], 14)
for (var i = 0; i < locations.length; i++) {
marker = new L.marker([locations[i][1], locations[i][2]]).addTo(map)
.bindPopup(locations[i][0]);
if (oldlong) {
polylinec = [
[oldlat, oldlong],
[locations[i][1], locations[i][2]]
];
polyline = L.polyline(polylinec, {color: 'red'}).addTo(map);
polyline = null;
console.log(polylinec);
}
oldlong = locations[i][2];
oldlat = locations[i][1];
}
});
$('#pipemap').on('shown.bs.modal', function (event) {
map.invalidateSize();
});
});
</script>
<?php endif; ?>
<?php include(realpath(dirname(__FILE__) . "/../../$mfLayoutPackage") . "/footer.php"); ?>

View File

@@ -0,0 +1,469 @@
<?php include(realpath(dirname(__FILE__) . "/../../$mfLayoutPackage") . "/header.php"); ?>
<link href="<?= self::getResourcePath() ?>assets/css/select2-cstm.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"><a
href="<?= self::getUrl("FiberPlanPipe") ?>">Rohrverzeichnisse</a></li>
<li class="breadcrumb-item active"><?= ($fiberplanpipes->id) ? "bearbeiten" : "Neu" ?></li>
</ol>
</div>
<h4 class="page-title"><?= ($fiberplanpipes->id) ? "Rohrverzeichnis bearbeiten" : "Neuer Rohrverzeichnis" ?></h4>
</div>
</div>
</div>
<style>
.fa-circle-plus {
color: #00b125;
cursor: pointer;
font-size: 17px;
float: right;
}
.remove-endpoint {
cursor: pointer;
color: #ff0606;
font-size: 17px;
float: right;
margin-left: 7px;
}
.fa-up {
color: #0d6efd;
font-size: 17px;
cursor: pointer;
float: right;
margin-left: 10px;
}
</style>
<?php
if (isset($_GET['returnto']) && $_GET['returnto'] == "fiberplanpipe-detail") {
$cancelUrl = self::getUrl("FiberPlanPipe", "Detail", ["id" => $fiberplanpipes->id]);
} else {
$cancelUrl = self::getUrl("FiberPlanPipe");
}
?>
<!-- end page title -->
<div class="row">
<div class="col-lg-12">
<div class="card">
<div class="card-body">
<h4 class="header-title mb-2"><?= ($fiberplanpipes->id) ? "Rohrverzeichnis bearbeiten" : "Neuer Rohrverzeichnis" ?></h4>
<form class="form-horizontal" method="post"
action="<?= self::getUrl("FiberPlanPipe", "save", ["returnto" => $_GET["returnto"]]) ?>">
<div class="card">
<div class="card-body">
<input type="hidden" name="id" value="<?= $fiberplanpipes->id ?>"/>
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="description">Bezeichnung * / Gis
Id</label>
<div class="col-lg-2">
<input required="required" type="text" id="description" name="description"
class="form-control"
value="<?= $fiberplanpipes->description ?>"/>
</div>
<div class="col-lg-1">
<input type="text" id="gisid" name="gisid" placeholder="Gis Id"
class="form-control"
value="<?= $fiberplanpipes->gisid ?>"/>
</div>
</div>
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="type">Type *</label>
<div class="col-lg-3">
<select required="required" id="type" name="type" class="select2 form-control">
<option value=""></option>
<option value="1" <?= ($fiberplanpipes->type == "1") ? "selected='selected'" : "" ?>>
Einzel
</option>
<option value="2" <?= ($fiberplanpipes->type == "2") ? "selected='selected'" : "" ?>>
Schutzrohr
</option>
<option value="3" <?= ($fiberplanpipes->type == "3") ? "selected='selected'" : "" ?>>
Verband
</option>
</select>
</div>
</div>
<div class="form-group row" id="dimesion-div"
style="<?= ($fiberplanpipes->type == "3") ? "display:none" : "" ?>">
<label class="col-lg-2 col-form-label" for="type_description">Dimension *</label>
<div class="col-lg-3">
<select required="required" <?= ($fiberplanpipes->type == "3") ? 'disabled="disabled"' : "" ?>
id="type_description" name="type_description"
class="select2 form-control">
<option value=""></option>
<option value="1" <?= ($fiberplanpipes->type_description == "1") ? "selected='selected'" : "" ?>>
MR7
</option>
<option value="2" <?= ($fiberplanpipes->type_description == "2") ? "selected='selected'" : "" ?>>
MR14
</option>
<option value="3" <?= ($fiberplanpipes->type_description == "3") ? "selected='selected'" : "" ?>>
MR16
</option>
<option value="4" <?= ($fiberplanpipes->type_description == "4") ? "selected='selected'" : "" ?>>
MR20
</option>
<option value="5" <?= ($fiberplanpipes->type_description == "5") ? "selected='selected'" : "" ?>>
PE32
</option>
<option value="6" <?= ($fiberplanpipes->type_description == "6") ? "selected='selected'" : "" ?>>
PE40
</option>
<option value="7" <?= ($fiberplanpipes->type_description == "7") ? "selected='selected'" : "" ?>>
PE50
</option>
<option value="8" <?= ($fiberplanpipes->type_description == "8") ? "selected='selected'" : "" ?>>
KSR50
</option>
<option value="9" <?= ($fiberplanpipes->type_description == "9") ? "selected='selected'" : "" ?>>
KSR80
</option>
<option value="10" <?= ($fiberplanpipes->type_description == "10") ? "selected='selected'" : "" ?>>
KSR100
</option>
</select>
</div>
</div>
<div class="form-group row" id="dimension-bundle-div"
style="<?= ($fiberplanpipes->type < "3" || !$fiberplanpipes->type) ? "display:none" : "" ?>">
<label class="col-lg-2 col-form-label" for="fiberplanpipetemplate_id">Multirohr
*</label>
<div class="col-lg-3">
<select <?= ($fiberplanpipes->type < "3" || !$fiberplanpipes->type) ? 'disabled="disabled"' : "" ?>
required="required" id="fiberplanpipetemplate_id"
name="fiberplanpipetemplate_id"
class="select2 form-control">
<option value=""></option>
<?php foreach ($fiberplanpipetemplates as $fiberplanpipetemplate) :
$name = "";
if ($fiberplanpipetemplate->pipe7x4 && $fiberplanpipetemplate->pipe14x10) {
$name = $fiberplanpipetemplate->name . " " . $fiberplanpipetemplate->pipe7x4 . "*7x4" . "/" . $fiberplanpipetemplate->pipe14x10 . "*14x10";
} else if ($fiberplanpipetemplate->pipe7x4) {
$name = $fiberplanpipetemplate->name . " " . $fiberplanpipetemplate->pipe7x4 . "*7x4";
} else if ($fiberplanpipetemplate->pipe14x10) {
$name = $fiberplanpipetemplate->name . " " . $fiberplanpipetemplate->pipe14x10 . "*14x10";
}
?>
<option <?= ($fiberplanpipetemplate->id == $fiberplanpipes->fiberPlanPipeTemplate_id) ? "selected='selected'" : "" ?>
value="<?= $fiberplanpipetemplate->id ?>"><?= $name ?></option>
<?php endforeach; ?>
</select>
</div>
</div>
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="length">Länge (m) *</label>
<div class="col-lg-1">
<input required="required" type="number" step="any" id="length" name="length"
class="form-control"
value="<?= $fiberplanpipes->length ?>"/>
</div>
</div>
<div id="endpoints">
<?php if ($fiberplanpipeendpoints) :
FiberPlanPipeModel::generateEndpoints($fiberplanpipeendpoints, $networks);
endif;
?>
</div>
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="status">Status *</label>
<div class="col-lg-2">
<select id="status" name="status" class="select2 form-control"
required="required">
<option value=""></option>
<option value="10" <?= ($fiberplanpipes->status == "10") ? "selected='selected'" : "" ?>>
Geplant
</option>
<option value="20" <?= ($fiberplanpipes->status == "20") ? "selected='selected'" : "" ?>>
Umsetzung
</option>
<option value="30" <?= ($fiberplanpipes->status == "30") ? "selected='selected'" : "" ?>>
Fertiggestellt
</option>
</select>
</div>
</div>
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="responsible">Zuständig</label>
<div class="col-lg-2">
<select id="responsible" name="responsible" class="select2 form-control">
<option value=""></option>
<option value="1" <?= ($fiberplanpipes->responsible == "1") ? "selected='selected'" : "" ?>>
Tiefbaufirma
</option>
<option value="2" <?= ($fiberplanpipes->responsible == "2") ? "selected='selected'" : "" ?>>
Person
</option>
</select>
</div>
<div id="responsible-div" class="col-lg-3"
style="<?= ($fiberplanpipes->responsible != "1") ? "display:none" : "" ?>">
<select id="address_id" name="address_id"
class="select2 form-control" <?= ($fiberplanpipes->responsible != "1") ? 'disabled="disabled"' : "" ?> >
<option value=""></option>
<?php foreach ($pipworkeraddresses as $pipworkeraddress): ?>
<option value="<?= $pipworkeraddress->id ?>" <?= ($fiberplanpipes->address_id == $pipworkeraddress->id) ? "selected='selected'" : "" ?>><?= $pipworkeraddress->company ?></option>
<?php endforeach; ?>
</select>
</div>
<div id="responsible_text-div" class="col-lg-3">
<input id="responsible_text" name="responsible_text"
value="<?= $fiberplanpipes->responsible_text ?>"
placeholder="Ansprechsperson"
class="form-control"/>
</div>
</div>
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="comment">Kommentar</label>
<div class="col-lg-3">
<textarea id="comment" name="comment"
class="form-control"><?= $fiberplanpipes->comment ?></textarea>
</div>
</div>
</div>
</div>
<div class="form-group row">
<label class="col-lg-2"></label>
<div class="col-lg-10">
<button type="submit" class="btn btn-primary">Speichern</button>
<a href="<?= $cancelUrl ?>">
<button type="button" class="btn btn-secondary">Abbrechen</button>
</a>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
<script type="text/javascript">
function checkendpoints() {
let endpointcounter = $('.endpoint-label').length;
let endpointtext;
$('.endpoint-label').each(function (index) {
$(this).find('.move-endpoint-up').remove();
if (index == 0) {
endpointtext = "Startpunkt";
$(this).find('.endpointsymbol').html('<i id="add-endpoint" class="fa-regular fa-circle-plus"></i>');
} else if (endpointcounter == 2) {
endpointtext = 'Standort ' + index;
$(this).closest('.endpoint-maindiv').find('.label-text').after('<i title="nach oben verschieben" class="fa-sharp fa-solid fa-up move-endpoint-up"></i>');
$(this).find('.endpointsymbol').html('');
} else if (index > 0) {
endpointtext = 'Standort ' + index;
$(this).closest('.endpoint-maindiv').find('.label-text').after('<i title="nach oben verschieben" class="fa-sharp fa-solid fa-up move-endpoint-up"></i>');
$(this).find('.endpointsymbol').html('<i class="fa-regular fa-circle-minus remove-endpoint"></i>');
}
$(this).find('.label-text').text(endpointtext + ' *');
});
}
$("body").on("change", ".endpoint_type,.endpoint_network_id ", function () {
const splitid = $(this).attr('id').split('_');
let thisid = splitid[0];
var options;
if ($.trim($("#" + thisid + "_endpoint_network_id").val()) != "" && $.trim($("#" + thisid + "_endpoint_type").val())) {
$.getJSON("<?= self::getUrl("FiberPlanPipe", "api", ['do' => 'getBuildingInfo']) ?>&network_id=" + $.trim($("#" + thisid + "_endpoint_network_id").val()) + "&bdtype=" + $.trim($("#" + thisid + "_endpoint_type").val()), {})
.done(function (data) {
$.each(data, function (k, val) {
options = options + '<option value="' + val.id + '">' + val.name + '</option>';
});
$("#" + thisid + "_mid-point-building").empty();
$("#" + thisid + "_mid-point-building").append('<select id=' + thisid + '_endpoint" required="required" name="endpoint[]" class="select2 form-control">' + options + '</select>');
$(".select2").select2({placeholder: ""});
});
}
});
$("body").on("click", ".move-endpoint-up", function () {
$(this).closest('.endpoint-maindiv').insertBefore($(this).closest('.endpoint-maindiv').prev());
checkendpoints();
});
$("body").on("click", ".remove-endpoint", function () {
let endpointcounter;
$(this).closest('.endpoint-maindiv').remove();
checkendpoints();
});
$("body").on("change", "#startpoint_type,#network_id", function () {
var options;
if ($.trim($("#network_id").val()) != "" && $.trim($("#startpoint_type").val())) {
$.getJSON("<?= self::getUrl("FiberPlanPipe", "api", ['do' => 'getBuildingInfo']) ?>&network_id=" + $.trim($("#network_id").val()) + "&bdtype=" + $.trim($("#startpoint_type").val()), {})
.done(function (data) {
$.each(data, function (k, val) {
options = options + '<option value="' + val.id + '">' + val.name + '</option>';
});
$('#starting-point-building').empty();
$('#starting-point-building').append('<select id="startpoint" required="required" name="startpoint" class="select2 form-control">' + options + '</select>');
$(".select2").select2({placeholder: ""});
});
}
});
$("body").on("change", "#entpoint_type,#network_id2", function () {
var options;
if ($.trim($("#network_id2").val()) != "" && $.trim($("#entpoint_type").val())) {
$.getJSON("<?= self::getUrl("FiberPlanPipe", "api", ['do' => 'getBuildingInfo']) ?>&network_id=" + $.trim($("#network_id2").val()) + "&bdtype=" + $.trim($("#entpoint_type").val()), {})
.done(function (data) {
$.each(data, function (k, val) {
options = options + '<option value="' + val.id + '">' + val.name + '</option>';
});
$('#end-point-building').empty();
$('#end-point-building').append('<select id="endpoint" name="endpoint" required="required" class="select2 form-control">' + options + '</select><input type="hidden" name="endpointid[]" value="">');
$(".select2").select2({placeholder: ""});
});
}
});
$("body").on("change", "#type", function () {
if ($(this).val() < 3) {
$('#dimesion-div').show();
$('#dimension-bundle-div').hide();
$("#type_description").prop("disabled", false);
$("#fiberplanpipetemplate_id").prop("disabled", true);
$(".select2").select2({placeholder: ""});
} else {
$('#dimesion-div').hide();
$('#dimension-bundle-div').show();
$("#type_description").prop("disabled", true);
$("#fiberplanpipetemplate_id").prop("disabled", false);
$(".select2").select2({placeholder: ""});
}
});
$("body").on("change", "#responsible", function () {
if ($(this).val() == 1) {
$('#responsible-div').show();
$("#address_id").prop("disabled", false);
$(".select2").select2({placeholder: ""});
} else {
$('#responsible-div').hide();
$("#address_id").prop("disabled", true);
$(".select2").select2({placeholder: ""});
}
});
// disable mousewheel on a input number field when in focus
$('form').on('focus', 'input[type=number]', function (e) {
$(this).on('wheel.disableScroll', function (e) {
e.preventDefault()
})
});
$('form').on('blur', 'input[type=number]', function (e) {
$(this).off('wheel.disableScroll')
});
$(document).ready(function () {
$(".select2").select2({placeholder: ""});
if ($.trim($("#network_id").val()) != "" && $.trim($("#startpoint_type").val())) {
$.getJSON("<?= self::getUrl("FiberPlanPipe", "api", ['do' => 'getBuildingInfo']) ?>&network_id=" + $.trim($("#network_id").val()) + "&bdtype=" + $.trim($("#startpoint_type").val()), {})
.done(function (data) {
var options;
$.each(data, function (k, val) {
if ($('#startpoint_type').data('startpoint') == val.id) {
options = options + '<option selected="selected" value="' + val.id + '">' + val.name + '</option>';
} else {
options = options + '<option value="' + val.id + '">' + val.name + '</option>';
}
});
$('#starting-point-building').empty();
$('#starting-point-building').append('<select id="startpoint" name="startpoint" required="required" class="select2 form-control">' + options + '</select>');
$(".select2").select2({placeholder: ""});
});
}
if ($.trim($("#network_id2").val()) != "" && $.trim($("#entpoint_type").val())) {
$.getJSON("<?= self::getUrl("FiberPlanPipe", "api", ['do' => 'getBuildingInfo']) ?>&network_id=" + $.trim($("#network_id2").val()) + "&bdtype=" + $.trim($("#entpoint_type").val()), {})
.done(function (data) {
var options;
$.each(data, function (k, val) {
if ($('#entpoint_type').data('endpoint') == val.id) {
options = options + '<option selected="selected" value="' + val.id + '">' + val.name + '</option>';
} else {
options = options + '<option value="' + val.id + '">' + val.name + '</option>';
}
});
$('#end-point-building').empty();
$('#end-point-building').append('<select id="endpoint" name="endpoint" required="required" class="select2 form-control">' + options + '</select>');
$(".select2").select2({placeholder: ""});
});
}
$("body").on("click", "#add-endpoint", function (event) {
let randid = Math.floor(Math.random() * 10000);
let endpointtype = $('#startpoint_type').html();
let endpointcounter = $('.endpoint-maindiv').length + 1;
let endpointuparrow = "";
let standorttext = "";
if (endpointcounter > 1) {
endpointuparrow = '<i title="nach oben verschieben" class="fa-sharp fa-solid fa-up move-endpoint-up"></i>';
}
if (endpointcounter <= 7) {
$('#endpoints').append(`<div class="form-group row endpoint-maindiv">
<label class="col-lg-2 col-form-label endpoint-label" for="` + randid + `_endpoint_network_id"><span class="label-text">Standort ` + $('.endpoint-maindiv').length + ` * </span>` + endpointuparrow + `<span class="endpointsymbol"><i class="fa-regular fa-circle-minus remove-endpoint"></i></span></label>
<div class="col-lg-2"><select id="` + randid + `_endpoint_network_id" required="required" name="endpoint_network_id[]"
class="select2 form-control endpoint_network_id">` + $('#network_id').html() + `</select></div>
<div class="col-lg-2 ">
<select id="` + randid + `_endpoint_type" name="endpoint_type[]" required="required"
class="select2 form-control endpoint_type" data-startpoint="" : "" >
<option value=""></option>
<option value="4">
Schacht-Verteiler
</option>
</select>
</div>
<div class="col-lg-2" id="` + randid + `_mid-point-building">
</div>
</div>`);
$('#' + randid + '_endpoint_network_id').val($('#network_id').val());
checkendpoints();
$(".select2").select2({placeholder: ""});
}
});
});
</script>
<?php include(realpath(dirname(__FILE__) . "/../../$mfLayoutPackage") . "/footer.php"); ?>

View File

@@ -0,0 +1,259 @@
<?php
$typeOption[1] = "Einzel";
$typeOption[2] = "Schutzrohr";
$typeOption[3] = "Verband";
$dimension_v1Option[1] = "MR7";
$dimension_v1Option[2] = "MR14";
$dimension_v1Option[3] = "MR16";
$dimension_v1Option[4] = "MR20";
$dimension_v1Option[5] = "PE32";
$dimension_v1Option[6] = "PE40";
$dimension_v1Option[7] = "PE50";
$dimension_v1Option[8] = "KSR50";
$dimension_v1Option[9] = "KSR80";
$dimension_v1Option[10] = "KSR100";
$dimension_v2Option[1] = "Anzahl";
$dimension_v2Option[2] = "Dimenson";
$dimension_v2Option[3] = "Farben";
$starting_pointOption[1] = "Greenfield";
$starting_pointOption[2] = "POP";
$starting_pointOption[3] = "Building";
$starting_pointOption[4] = "Schacht-Verteiler";
$statusOption[10] = "Geplant";
$statusOption[20] = "Umsetzung";
$statusOption[30] = "Fertiggestellt";
$responsibleOption[1] = "(F)";
$responsibleOption[2] = "(P)";
foreach ($networks as $network) {
$Network[$network->id] = $network->name;
}
foreach ($pipworkeraddresses as $pipworkeraddress) {
$Pipeworker[$pipworkeraddress->id] = $pipworkeraddress->company;
}
?>
<?php include(realpath(dirname(__FILE__) . "/../../$mfLayoutPackage") . "/header.php"); ?>
<link href="<?= self::getResourcePath() ?>assets/css/datatables-std.css?<?= date('U') ?>" rel="stylesheet"
type="text/css"/>
<!-- start page title -->
<style>
#map {
height: 600px;
width: 100%
}
</style>
<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">Rohrverzeichnisse</li>
</ol>
</div>
<h4 class="page-title">Rohrverzeichnisse</h4>
</div>
</div>
</div>
<!-- end page title -->
<div class="card">
<div class="card-body mb-3">
<div class="row">
<div class="col-12">
<div class="float-left">
<h4 class="header-title">Liste aller Rohrverzeichnisse</h4>
</div>
<div class="float-right">
<a class="btn btn-primary mb-2" href="<?= self::getUrl("FiberPlanPipe", "add") ?>"><i
class="fas fa-plus"></i> Neuen Rohrverzeichnis anlegen</a>
</div>
</div>
</div>
<table id="datatable" class="table table-striped table-hover table-sm font-13">
<thead>
<tr>
<th class="text-center">Bezeichnung</th>
<th class="text-center">Type/Bezeichnung</th>
<th class="text-center">Länge (m)</th>
<th>Netzgebiet(e)</th>
<th class="text-center">Anfangspunkt</th>
<th class="text-center">Endpunkt</th>
<th class="text-center">Zuständig</th>
<th class="text-center">Status</th>
<th class="edit-width"></th>
</tr>
<tr id="filterrow">
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<?php foreach ($fiberplanpipes as $fiberplanpipe):
if ($fiberplanpipe->type == "3") {
$name = "";
if ($fiberplanpipe->fiberPlanPipeTemplate->pipe7x4 && $fiberplanpipe->fiberPlanPipeTemplate->pipe14x10) {
$name = $fiberplanpipe->fiberPlanPipeTemplate->fiberPlanPipeManufacturer->name . " " . $fiberplanpipe->fiberPlanPipeTemplate->pipe7x4 . "*7x4" . "/" . $fiberplanpipe->fiberPlanPipeTemplate->pipe14x10 . "*14x10";
} else if ($fiberplanpipe->fiberPlanPipeTemplate->pipe7x4) {
$name = $fiberplanpipe->fiberPlanPipeTemplate->fiberPlanPipeManufacturer->name . " " . $fiberplanpipe->fiberPlanPipeTemplate->pipe7x4 . "*7x4";
} else if ($fiberplanpipe->fiberPlanPipeTemplate->pipe14x10) {
$name = $fiberplanpipe->fiberPlanPipeTemplate->fiberPlanPipeManufacturer->name . " " . $fiberplanpipe->fiberPlanPipeTemplate->pipe14x10 . "*14x10";
}
$typeDescription = $name;
//
} else {
$typeDescription = $dimension_v1Option[$fiberplanpipe->type_description];
}
$startpoint = '<span class="startpoint" data-toggle="modal" data-target="#pipemap" data-gpslat="' . $buildings[$fiberplanpipe->startpoint_type][$fiberplanpipe->startpoint]['gps_lat'] . '" data-gpslong="' . $buildings[$fiberplanpipe->startpoint_type][$fiberplanpipe->startpoint]['gps_long'] . '">' . $starting_pointOption[$fiberplanpipe->startpoint_type] . "/" . $buildings[$fiberplanpipe->startpoint_type][$fiberplanpipe->startpoint]['name'] . '</span>';
$endpoint = '<span class="endpoint" data-toggle="modal" data-target="#pipemap" data-gpslat="' . $buildings[$fiberplanpipe->entpoint_type][$fiberplanpipe->endpoint]['gps_lat'] . '" data-gpslong="' . $buildings[$fiberplanpipe->entpoint_type][$fiberplanpipe->endpoint]['gps_long'] . '">' . $starting_pointOption[$fiberplanpipe->entpoint_type] . "/" . $buildings[$fiberplanpipe->entpoint_type][$fiberplanpipe->endpoint]['name'] . '</span>';
$responsible = $responsibleOption[$fiberplanpipe->responsible];
if ($fiberplanpipe->address_id) {
$responsible .= " " . $Pipeworker[$fiberplanpipe->address_id];
if ($fiberplanpipe->responsible_text) {
$responsible .= " (" . $fiberplanpipe->responsible_text . ")";
}
} else {
$responsible .= " " . $fiberplanpipe->responsible_text;
}
if ($fiberplanpipe->startpoint_network_id == $fiberplanpipe->endpoint_network_id) {
$networkName = $Network[$fiberplanpipe->startpoint_network_id];
} else {
$networkName = $Network[$fiberplanpipe->startpoint_network_id] . " / " . $Network[$fiberplanpipe->endpoint_network_id];
}
?>
<tr>
<td><a href="<?= self::getUrl("FiberPlanPipe", "Detail", ["id" => $fiberplanpipe->id]) ?>"><?= $fiberplanpipe->description ?></a></td>
<td style="white-space: nowrap"><?= $typeOption[$fiberplanpipe->type] . " / " . $typeDescription ?></td>
<td class="text-center"><?= $fiberplanpipe->length ?></td>
<td><?= $networkName ?></td>
<td><?= $startpoint ?></td>
<td><?= $endpoint ?></td>
<td><?= $responsible ?></td>
<td><?= $statusOption[$fiberplanpipe->status] ?></td>
<td style="text-align: left; letter-spacing: 4px; font-size: 1.1em;">
<a href="<?= self::getUrl("FiberPlanPipe", "edit", ["id" => $fiberplanpipe->id]) ?>"><i
class="far fa-edit" title="Bearbeiten"></i></a>
<a href="<?= self::getUrl("FiberPlanPipe", "delete", ["id" => $fiberplanpipe->id]) ?>"
onclick="if(!confirm('Rohrverzeichnis wirklich löschen?')) return false;"
class="text-danger"
title="Löschen"><i class="fas fa-trash"></i></a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#pipemap">
Launch demo modal
</button>
</div>
</div>
</div>
</div>
<div class="modal fade" id="pipemap" tabindex="-1" role="dialog" aria-labelledby="pipemap"
aria-hidden="true">
<div class="modal-dialog modal-dialog-centered modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="pipemapLabel">Rohrverzeichnis</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div id="map"></div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Schließen</button>
</div>
</div>
</div>
</div>
<script type="text/javascript">
var startlat;
var startlong;
var endlat;
var endlong;
var startmarkertext;
var endmarkertext;
var marker;
var polylinec;
var polyline;
var map = L.map('map').setView([51.505, -0.09], 13);
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19
}).addTo(map);
L.MakiMarkers.accessToken = '<?=TT_MAPBOX_TILE_API_TOKEN?>';
var hidesearch = [2, 8];
var columnfilter = [7];
var columnoptions = '<option class="text-left" value="">Alle</option><option class="text-left" value="Geplant">Geplant</option><option class="text-left" value="Umsetzung">Umsetzung</option><option class="text-left" value="Fertiggestellt">Fertiggestellt</option>';
$(document).ready(function () {
$('#pipemap').on('show.bs.modal', function (event) {
var button = $(event.relatedTarget);
map.remove();
map = L.map('map').setView([51.505, -0.09], 13);
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19
}).addTo(map);
startlat = button.closest('tr').find('.startpoint').data('gpslat');
startlong = button.closest('tr').find('.startpoint').data('gpslong');
endlat = button.closest('tr').find('.endpoint').data('gpslat');
endlong = button.closest('tr').find('.endpoint').data('gpslong');
startmarkertext = button.closest('tr').find('.startpoint').text();
endmarkertext = button.closest('tr').find('.endpoint').text();
var icon_name = "town";
var icon_color = "#ec98a2";
var icon = L.MakiMarkers.icon({icon: icon_name, color: icon_color, size: "l"});
marker = L.marker([startlat, startlong]).addTo(map);
marker.bindPopup("" + startmarkertext);
map.setView([button.data('gpslat'), button.data('gpslong')], 13)
marker = L.marker([endlat, endlong]).addTo(map);
// marker = L.marker([endlat, endlong], {icon: icon}).addTo(map);
marker.bindPopup("" + endmarkertext);
polylinec = [
[startlat, startlong],
[endlat, endlong]
];
polyline = L.polyline(polylinec, {color: 'red'}).addTo(map);
});
$('#pipemap').on('shown.bs.modal', function (event) {
map.invalidateSize();
});
});
</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

@@ -0,0 +1,185 @@
<?php /** @noinspection PhpUndefinedClassInspection
* @var string $mfLayoutPackage
* @var TYPE_NAME $git_merge_ts
*/
//additional css /css/views/RaspberryDisplay.css
$JSGlobals = ["BASE_URL" => self::getUrl("Domain"),
"DASHBOARD_URL" => self::getUrl("Dashboard"),
"MFAPPNAME" => MFAPPNAME_SLUG,
"PAGE_TITLE" => "Historische Tickets",
"PATH" => [
["text" => MFAPPNAME_SLUG, "href" => self::getUrl("Dashboard")],
["text" => "Historische Tickets", "href" => self::getUrl("HistoricTicket")]
],
"HISTORIC_TICKET_API_URL" => self::getUrl("HistoricTicket/api"),
];
$additionalJS = ["plugins/vue/vue.js",
"plugins/axios/axios.min.js",
"plugins/vue/tt-components/tt-page-title.js",
"plugins/vue/tt-components/tt-table.js",
];
$additionalCSS = [
'plugins/vue/tt-components/css/tt-table.css',
];
include(realpath(dirname(__FILE__) . "/../../$mfLayoutPackage") . "/header.php"); ?>
<div id="app">
<!-- start page title -->
<tt-page-title :title="window['TT_CONFIG']['PAGE_TITLE']" :path="window['TT_CONFIG']['PATH']"></tt-page-title>
<tt-table :fetch-url="window['TT_CONFIG']['HISTORIC_TICKET_API_URL'] + '?do=getHistoricTickets'"
:table-config="historicTicketTableConfig"
small ref="table">
<template v-slot:top-buttons>
<!-- add input for global search with label and bootstrap class-->
<div class="input-group mb-3">
<input type="text" class="form-control" placeholder="Globale Suche" v-model="globalSearch" @keydown.enter="doGlobalSearch">
<div class="input-group-append">
<button class="btn btn-primary" type="button" @click="doGlobalSearch">Submit</button>
</div>
</div>
</template>
<template v-slot:first_name="{ row }">
{{ row.first_name }} {{ row.last_name }}
</template>
<template v-slot:ctime="{ row }">
{{ new Date(row.ctime * 1000).toLocaleString() }}
</template>
<template v-slot:ticket_number="{ row }">
<a href="#" @click="clickTicketNumber(row.ticket_number)">{{ row.ticket_number }}</a>
</template>
</tt-table>
<!-- Bootstrap Modal to show global search results -->
<div class="modal show d-block" tabindex="0" role="dialog" style="background: rgba(0, 0, 0, 0.5);" @click="globalSearchModal = false" @keydown.esc="globalSearchModal = false" ref="globalSearchModal"
v-if="globalSearchModal">
<div class="modal-dialog" role="document" @click.stop
style="width:fit-content;max-width: 80vw ; max-height: 80vh; overflow-y: auto;">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Suchergebnisse</h5>
<button type="button" class="close" @click="globalSearchModal = false">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<tt-table
:fetch-url="`${window['TT_CONFIG']['HISTORIC_TICKET_API_URL']}?do=findHistoricTicket&query=${globalSearch}`"
:table-config="globalSearchModalTableConfig"
small ref="table">
<template v-slot:ctime="{ row }">
{{ new Date(row.ctime * 1000).toLocaleString() }}
</template>
<template v-slot:ticket_number="{ row }">
<a href="#" @click="clickTicketNumber(row.ticket_number)">{{ row.ticket_number }}</a>
</template>
</tt-table>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" @click="globalSearchModal = false">Close</button>
</div>
</div>
</div>
</div>
<!-- Bootstrap Modal to show ticket messages -->
<div class="modal show d-block" tabindex="0" role="dialog" style="background: rgba(0, 0, 0, 0.5);" @click="selectedTicketNumber = null" @keydown.esc="selectedTicketNumber = null" ref="selectedTicketModal"
v-if="selectedTicketNumber">
<div class="modal-dialog" role="document" @click.stop
style="width:fit-content;max-width: 80vw ; max-height: 80vh; overflow-y: auto;">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Ticket {{ selectedTicketNumber }}</h5>
<button type="button" class="close" @click="selectedTicketNumber = null">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div v-if="selectedTicketData">
<h5>{{ selectedTicketData.ticket.subject }}</h5>
<p>{{ selectedTicketData.ticket.message }}</p>
<div v-for="message in selectedTicketData.messages">
<hr>
<h6>{{ new Date(message.ctime * 1000).toLocaleString()}}</h6>
<p style="word-break: break-all;" v-html="message.content?.replaceAll('\n', '<br>')"></p>
</div>
</div>
<div v-else class="spinner-border text-primary" role="status">
<span class="sr-only">Loading...</span>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
new Vue({
el: '#app',
data: {
window: window,
selectedTicketNumber: null,
selectedTicketData: null,
globalSearch: '',
globalSearchModal: false,
globalSearchModalTableConfig: {
headers: [
{text: 'Ticket Number', key: 'ticket_number', filter: false},
{text: 'Erstellt', key: 'ctime', filter: false},
{text: 'Subject', key: 'ticket_subject', filter: false},
{text: 'Message', key: 'ticket_message', filter: false},
],
tableHeader: 'Suchergebnisse',
},
historicTicketTableConfig: {
headers: [
{text: 'Ticket Number', key: 'ticket_number', filter: 'search'},
{text: 'Erstellt', key: 'ctime', filter: false},
{text: 'Subject', key: 'subject', filter: 'search'},
{text: 'Type', key: 'type', filter: 'search'},
{text: 'Status', key: 'status', filter: 'search'},
{text: 'Name', key: 'first_name', filter: 'search'},
{text: 'Email', key: 'email', filter: 'search'},
{text: 'Phone', key: 'phone', filter: 'search'},
],
defaultPageSize: 25,
tableHeader: 'Bestellungen',
}
},
methods: {
async doGlobalSearch() {
if (this.globalSearch.length > 0) {
this.globalSearchModal = true;
this.$nextTick(() => {
this.$refs.globalSearchModal.focus();
});
}
},
async clickTicketNumber(ticketNumber) {
this.globalSearchModal = false;
this.selectedTicketData = null;
this.selectedTicketNumber = ticketNumber;
const response = await axios.post(`${window['TT_CONFIG']['HISTORIC_TICKET_API_URL']}?do=getHistoricTicketMessages`, {ticketNumber});
this.selectedTicketData = response.data;
this.$nextTick(() => {
this.$refs.selectedTicketModal.focus();
});
}
}
})
</script>
<?php include(realpath(dirname(__FILE__) . "/../../$mfLayoutPackage") . "/footer.php"); ?>

View File

@@ -13,7 +13,6 @@ $monthger[10] = "Oktober";
$monthger[11] = "November";
$monthger[12] = "Dezember";
$time = time();
for ($i = 1; $i <= 25; $i++) {
$kw = date('W', $time);
$year = date('Y', $time);
@@ -196,7 +195,7 @@ $years[time() - 31536000] = date('Y', time() - 31536000);
</div>
</div>
<div class="col-lg-2 mb-2 businesstrip-div">
<div class="col-lg-2 mb-2 businesstrip-div businesstrip-check-div ">
<div class="form-check text-center mt-1">
<input class="form-check-input" type="checkbox" name="businesstrip"
@@ -211,6 +210,30 @@ $years[time() - 31536000] = date('Y', time() - 31536000);
placeholder="Ort"
class="form-control"/>
</div>
<div class="col-lg-2 car-div car-div-car" style="display:none">
<select id="timerecordingCar_id" name="timerecordingCar_id"
class="select2 form-control">
<option value="">Auto auswählen</option>
<?php foreach ($timerecordingCars as $timerecordingCar): ?>
<option value="<?= $timerecordingCar->id ?>"
data-mileagenow="<?= $timerecordingCar->mileage_now ?>"><?= $timerecordingCar->number_plate . " (" . $timerecordingCar->brand." ".$timerecordingCar->model . ")" ?></option>
</option>
<?php
endforeach; ?>
</select>
</div>
<div class="col-lg-1 car-div " style="display:none">
<input style="" type="number" id="mileage_start" name="mileage_start"
placeholder="KM Start"
class="form-control"/>
</div>
<div class="col-lg-1 car-div" style="display:none">
<input style="" type="number" id="mileage_end" name="mileage_end"
placeholder="KM Ende"
class="form-control"/>
</div>
</div>
<div class=" row mt-2">
<div class="col-lg-3 ">

View File

@@ -0,0 +1,154 @@
<?php include(realpath(dirname(__FILE__) . "/../../$mfLayoutPackage") . "/header.php");
?>
<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">Zeiterfassung Verrechnung</li>
</ol>
</div>
<h4 id="month" data-month="<?= $month ?>" class="page-title">Verrechnung/Abrechnung <?= $month ?></h4>
</div>
</div>
</div>
<!-- end page title -->
<div class="card">
<div class="card-body mb-3">
<div class="row">
<div class="col-12">
<div class="float-left">
<h4 class="header-title">Liste aller Mitarbeiter</h4>
</div>
</div>
</div>
<table id="datatable" class="table table-hover table-sm">
<thead>
<tr>
<th class="text-center">Mitarbeiter</th>
<th class="text-center">Personal Nr.</th>
<th class="text-center">Sollstunden</th>
<th class="text-center">Iststunden</th>
<th class="text-center">Sollabweichung</th>
<th class="text-center">Akuelle Gutstunden</th>
<th class="text-center">Akuelle Überstunden</th>
<?php if ($me->superexpertEnabled()): ?>
<th class="text-center">Black P. Stunden</th>
<?php endif; ?>
<th class="text-center">Nichtleistungszeiten</th>
<th class="text-center">Diäten</th>
<th class="text-center">Homeoffice Tage</th>
</tr>
<tr id="filterrow">
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<?php if ($me->superexpertEnabled()): ?>
<th></th>
<?php endif; ?>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<?php foreach ($timerecordings as $timerecording):
if (!empty($timerecording['data']['time']['daysum'])) {
$offdays = "";
$counter = 1;
foreach ($timerecording['data']['time']['daysum'] as $category => $value) {
if ($counter > 1) {
$offdays .= "</div>";
}
$offdays .= "<div>";
if ($value < 100) {
$offdays .= $category . ": " . $value . " Tag(e) ";
} else {
$offdays .= $category . ": " . sprintf('%02dh:%02dm', floor($value / 3600), floor($value / 60 % 60));
}
$counter++;
}
$offdays .= "</div>";
} else {
$offdays = "-";
}
?>
<tr>
<td><?= $timerecording['user_name'] ?></td>
<td class="text-center edit-width-large"><?= $timerecording['employee_number'] ?></td>
<td data-order="<?= $timerecording['data']['time']['mustorder'] ?>"
class="text-center"><?= $timerecording['data']['time']['must'] ?></td>
<td data-order="<?= $timerecording['data']['time']['isorder'] ?>"
class="text-center"><?= $timerecording['data']['time']['is'] ?></td>
<td data-order="<?= $timerecording['data']['time']['summsecondsorder'] ?>"
class="text-center"><?= $timerecording['data']['time']['summseconds'] ?></td>
<td data-order="<?= $timerecording['data']['time']['plushours_noworder'] ?>"
class="text-center"><?= $timerecording['data']['time']['plushours_now'] ?></td>
<td data-order="<?= $timerecording['data']['time']['overtime_noworder'] ?>"
class="text-center"><?= $timerecording['data']['time']['overtime_now'] ?></td>
<?php if ($me->superexpertEnabled()): ?>
<td data-order="<?= $timerecording['data']['time']['bpahours'] ?>"
class="text-center"><?= $timerecording['data']['time']['bpahours'] ?></td>
<?php endif; ?>
<td class=""><?= $offdays ?></td>
<td class="text-center"><?= number_format($timerecording['data']['time']['diet'], 2, ',', '.') . " €" ?></td>
<td class="text-center"><?= $timerecording['data']['time']['homeoffice'] ?> Tag(e)</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
<script type="text/javascript">
var hidesearch = [2, 3, 4, 5, 6, 8, 9];
<?php if ($me->superexpertEnabled()): ?>
hidesearch = [2, 3, 4, 5, 6, 7, 9, 10];
<?php endif; ?>
$(document).ready(function () {
$('.buttons-excel').closest('div').append('<div ><button id="month-complete" class="btn btn-danger margina">Monats Abschluss</button></div>');
$('.buttons-excel').closest('div').append('<div ><button id="bmd-export" class="btn btn-info margina">BMD Import</button></div>');
$('.buttons-excel').closest('div').append('<div ><button id="bmd-export-nlz" class="btn btn-info margina">BMD NLZ Import</button></div>');
$('body').on('click', '#bmd-export', function () {
window.open('<?= self::getUrl("TimerecordingBilling", "api", ['do' => 'generatebmdexport']) ?>&month=' + $('#month').data('month'), '_blank');
});
$('body').on('click', '#bmd-export-nlz', function () {
window.open('<?= self::getUrl("TimerecordingBilling", "api", ['do' => 'generatebmdexportnlz']) ?>&month=' + $('#month').data('month'), '_blank');
});
$('body').on('click', '#month-complete', function () {
if (confirm('Monat ' + $('#month').data('month') + ' wirklich abschließen?')) {
$.post("<?= self::getUrl("TimerecordingBilling", "api", ['do' => 'completemonth']) ?>", {
month: $.trim($('#month').data('month')),
ajax: 1
}).done(function (data) {
window.location.href = "<?= self::getUrl("TimerecordingBilling", "detailClosed", ['month' => $month]) ?>";
});
}
});
});
</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

@@ -0,0 +1,325 @@
<?php include(realpath(dirname(__FILE__) . "/../../$mfLayoutPackage") . "/header.php");
?>
<link href="<?= self::getResourcePath() ?>assets/css/datatables-std.css?<?= date('U') ?>" rel="stylesheet"
type="text/css"/>
<style>
.fa-arrow-right-from-bracket {
margin-top: 3px;
margin-right: 10px;
color: #2238d1;
cursor: pointer;
}
.filler {
width: 30px;
height: 1px;
}
.filler-0 {
width: 7px;
height: 1px;
}
#overtimeModal .table td, #overtimeModal .table th {
border: none;
}
@media (min-width: 992px) {
.modal-lg, .modal-xl {
max-width: 400px !important;
}
}
</style>
<!-- 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">Zeiterfassung Verrechnung</li>
</ol>
</div>
<h4 id="month" data-month="<?= $month ?>" class="page-title">Verrechnung/Abrechnung <?= $month ?></h4>
</div>
</div>
</div>
<!-- end page title -->
<div class="card">
<div class="card-body mb-3">
<div class="row">
<div class="col-12">
<div class="float-left">
<h4 class="header-title">Liste aller Mitarbeiter</h4>
</div>
</div>
</div>
<table id="datatable" class="table table-hover table-sm">
<thead>
<tr>
<th class="text-center">Mitarbeiter/PersNr.</th>
<th class="text-center">Leistungszeiten</th>
<th class="text-center">Nichtleistungszeiten</th>
<th class="text-center">Iststunden (NLZ+LZ)</th>
<th class="text-center">Sollstunden</th>
<th class="text-center">Sollabweichung</th>
<th class="text-center">Gesamt Überstunden</th>
<?php if ($me->superexpertEnabled()): ?>
<th class="text-center">Black P. Stunden</th>
<?php endif; ?>
<th class="text-center">Ü50</th>
<th class="text-center">Ü100</th>
<th class="text-center">Diäten</th>
<th class="text-center">Homeoffice</th>
</tr>
<tr id="filterrow">
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<?php if ($me->superexpertEnabled()): ?>
<th></th>
<?php endif; ?>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<?php foreach ($timerecordings as $timerecording):
$user = new User($timerecording->timerecordingEmployee->user->id);
$employee_number = (string)$user->getFlag('employee_number');
unset ($nlz);
if ($timerecording->nlz) {
$nlz_details = json_decode($timerecording->nlz, true);
foreach ($nlz_details as $key => $nlz_detail) {
if ($nlz_detail < 100) {
$nlz .= $key . ": " . $nlz_detail . " Tag(e)<br>";
} else {
$nlz .= $key . ": " . round($nlz_detail / 3600, 2) . " Stunden<br>";
}
}
} else {
$nlz = "";
}
?>
<tr>
<td class="text-nowrap">(<?= $employee_number ?>
) <?= $timerecording->timerecordingEmployee->user->name ?> </td>
<td class="text-center"><?= number_format(round($timerecording->ishours / 3600, 2), "2", ",", ".") ?></td>
<td class="text-center"><?= $nlz ?></td>
<td class="text-center"><?= number_format(round($timerecording->ishourssum / 3600, 2), "2", ",", ".") ?></td>
<td class="text-center"><?= number_format(round($timerecording->musthours / 3600, 2), "2", ",", ".") ?></td>
<td class="text-center"><?= (($timerecording->ishourssum - $timerecording->musthours) == 0) ? '<div class="filler-0 float-left"></div>' : '' ?><?= number_format(round(($timerecording->ishourssum - $timerecording->musthours) / 3600, 2), "2", ",", ".") ?>
<?= (($timerecording->ishourssum - $timerecording->musthours) > 0) ? '<i class="float-right fa-regular fa-arrow-right-from-bracket change-difference" data-toggle="modal" data-target="#overtimeModal" data-hours="' . number_format(round(($timerecording->ishourssum - $timerecording->musthours) / 3600, 2), "2", ",", ".") . '" data-id="' . $timerecording->id . '"></i>' : '<div class="filler float-right"></div>' ?></td>
<td class="text-center"><?= ($timerecording->timerecordingEmployee->overtime_now == 0) ? '<div class="filler-0 float-left"></div>' : '' ?><?= number_format(round($timerecording->timerecordingEmployee->overtime_now / 3600, 2), "2", ",", ".") ?>
<?= ($timerecording->timerecordingEmployee->overtime_now > 0) ? '<i class="float-right fa-regular fa-arrow-right-from-bracket change-overtime" data-toggle="modal" data-target="#overtimeModal" data-hours="' . number_format(round($timerecording->timerecordingEmployee->overtime_now / 3600, 2), "2", ",", ".") . '" data-id="' . $timerecording->id . '"></i>' : '<div class="filler float-right"></div>' ?></td>
<?php if ($me->superexpertEnabled()): ?>
<td class="text-center"><?= number_format(round($timerecording->timerecordingEmployee->bpahours / 3600, 2), "2", ",", ".") ?></td>
<?php endif; ?>
<td class="text-center"><?= number_format(round($timerecording->overtime50free / 3600, 2), "2", ",", ".") ?></td>
<td class="text-center"><?= number_format(round($timerecording->overtime100free / 3600, 2), "2", ",", ".") ?></td>
<td class="text-center"><?= number_format($timerecording->diet, 2, ',', '.') . " €" ?></td>
<td class="text-center"><?= $timerecording->homeoffice ?> Tag(e)</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
<div class="modal fade" id="overtimeModal" tabindex="-1" role="dialog"
aria-labelledby="overtimeModalInfoLabel"
aria-hidden="true" data-id="">
<div class="modal-dialog modal-dialog-centered modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="overtimeModal-title"></h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="row">
<div class="col-12">
<table class="table ">
<tr id="overtimes">
</tr>
<tr>
<th class="align-middle">Überstunden 50</th>
<td><input type="number" step="any" class="form-control change-overtime-value"
name="overtime50"
id="overtime50"></td>
</tr>
<tr>
<th class="text-nowrap align-middle">Überstunden 100</th>
<td><input type="number" step="any" class="form-control change-overtime-value"
name="overtime100"
id="overtime100"></td>
</tr>
<?php if ($me->superexpertEnabled()): ?>
<tr>
<th class="text-nowrap align-middle">Blackpig</th>
<td><input type="number" step="any" class="form-control change-overtime-value"
name="overtimebpa"
id="overtimebpa"></td>
</tr>
<?php endif; ?>
</table>
</div>
</div>
</div>
<div class="modal-footer">
<button id="submit-button" data-type="" type="button" class="btn btn-primary" data-dismiss="modal">
Speichern
<button type="button" class="btn btn-secondary" data-dismiss="modal">Schließen
</button>
</div>
</div>
</div>
</div>
<script type="text/javascript">
var hidesearch = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
<?php if ($me->superexpertEnabled()): ?>
hidesearch = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
<?php endif; ?>
$(document).ready(function () {
// $('.buttons-excel').closest('div').append('<div ><button id="month-complete" class="btn btn-danger margina">Monats Abschluss</button></div>');
$('.buttons-excel').closest('div').append('<div ><button id="bmd-export" class="btn btn-info margina">BMD Import</button></div>');
$('.buttons-excel').closest('div').append('<div ><button id="bmd-export-nlz" class="btn btn-info margina">BMD NLZ Import</button></div>');
$('body').on('click', '#bmd-export', function () {
window.open('<?= self::getUrl("TimerecordingBilling", "api", ['do' => 'generatebmdexportclosed']) ?>&month=' + $('#month').data('month'), '_blank');
});
$('body').on('click', '#bmd-export-nlz', function () {
window.open('<?= self::getUrl("TimerecordingBilling", "api", ['do' => 'generatebmdexportnlzclosed']) ?>&month=' + $('#month').data('month'), '_blank');
});
$('body').on('click', '#month-complete', function () {
if (confirm('Monat wirklich abschließen?')) {
$.post("<?= self::getUrl("TimerecordingBilling", "api", ['do' => 'completemonth']) ?>", {
month: $.trim($('#month').data('month')),
ajax: 1
}).done(function (data) {
});
}
});
$('#overtimeModal').on('shown.bs.modal', function (event) {
var button = $(event.relatedTarget);
if (button.hasClass('change-difference')) {
$('#overtimeModal-title').text('Mehrstunden Transfer');
$('#overtimeModal').data('id', button.data('id'));
$('#overtimes').html('<th>Mehrstunden:</th> <td id="overtime-hours" data-hours="' + button.data('hours') + '">' + button.data('hours') + ' (6,5)</td>');
$('#submit-button').data('type', 'difference');
}
if (button.hasClass('change-overtime')) {
$('#overtimeModal-title').text('Überstunden Transfer');
$('#overtimes').html('<th>Überstunden:</th> <td id="overtime-hours" data-hours="' + button.data('hours') + '">' + button.data('hours') + '</td>');
$('#submit-button').data('type', 'overtime');
$('#overtimeModal').data('id', button.data('id'));
}
$('.change-overtime-value').val('');
});
$('body').on('change', '.change-overtime-value', function () {
//$('#overtime-hours').data('hours') to float
var difference = 0;
$(".change-overtime-value").each(function (index) {
//check if float
var value = $(this).val().replace(",", ".");
// console.log(value);
if (isNaN(parseFloat(value))) {
} else {
difference += parseFloat(value);
}
});
var valdiff = difference - parseFloat($(this).val());
valdiff = Math.round(valdiff * 100) / 100;
console.log("valdif" + valdiff);
var hours = $('#overtime-hours').data('hours').replace(",", ".");
if (parseFloat(hours) < difference) {
difference = difference - parseFloat(hours)
difference = Math.round(difference * 100) / 100;
console.log(difference);
if (valdiff == 0) {
$(this).val(hours);
} else if (valdiff == parseFloat(hours)) {
$(this).val('0');
} else {
var calc = Math.round((hours - valdiff) * 100) / 100
$(this).val(calc);
}
} else {
hours = hours.replace(",", ".");
}
});
$('body').on('click', '#submit-button', function () {
var id = $('#overtimeModal').data('id');
var overtime50 = $('#overtime50').val();
var overtime100 = $('#overtime100').val();
var overtimebpa = $('#overtimebpa').val();
$.post("<?= self::getUrl("TimerecordingBilling", "api", ['do' => 'saveovertime']) ?>", {
id: id,
type: $(this).data('type'),
overtime50: overtime50,
overtime100: overtime100,
overtimebpa: overtimebpa,
ajax: 1
}).done(function (data) {
window.location.reload();
});
});
//$.post(insertUrl, {
// id: $.trim($('#id').val()),
// timerecordingCategory_id: $.trim($('#timerecordingCategory_id').val()),
// date: $.trim($('#date').val()),
// enddate: $.trim($('#enddate').val()),
// start: $.trim($('#start').val()),
// end: $.trim($('#end').val()),
// comment: $.trim($('#comment').val()),
// businesstrip: businesstrip,
// businesstrip_info: $.trim($('#businesstrip_info').val()),
// timerecordingCar_id: $.trim($('#timerecordingCar_id').val()),
// mileage_start: $.trim($('#mileage_start').val()),
// mileage_end: $.trim($('#mileage_end').val()),
// homeoffice: homeoffice,
// hourday: $.trim($('#timerecordingCategory_id').find(':selected').data('hourday')),
// ajax: 1
//}).done(function (data) {
// if (data.success) {
// window.location.href = '<?php //= self::getUrl("Timerecording") ?>//';
// } else {
// $('#error').html(data.error);
// }
//});
});
</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

@@ -0,0 +1,94 @@
<?php include(realpath(dirname(__FILE__) . "/../../$mfLayoutPackage") . "/header.php");
?>
<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">Zeiterfassung Verrechnung</li>
</ol>
</div>
<h4 class="page-title">Zeiterfassung Verrechnung/Abrechnung</h4>
</div>
</div>
</div>
<!-- end page title -->
<div class="card">
<div class="card-body mb-3">
<div class="row">
<div class="col-12">
<div class="float-left">
<h4 class="header-title">Liste aller Abrechnungsmonate</h4>
</div>
</div>
</div>
<table id="datatable" class="table table-hover table-sm">
<thead>
<tr>
<th class="text-center">Monat</th>
<th class="text-center">Abgeschlossen</th>
<th class="text-center">Abgeschlossen am</th>
<th class="text-center">Abgeschlossen von</th>
</tr>
<tr id="filterrow">
<th></th>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<?php
foreach ($months as $month):
if ($timerecordingbillings[ltrim($month, "0")]) {
$closetime = $timerecordingbillings[ltrim($month, "0")]->closetime;
$closetime = date("d.m.Y H:i", $closetime);
$closer = $timerecordingbillings[ltrim($month, "0")]->creator->name;
$closed = "Ja";
} else {
$closetime = "";
$closer = "";
$closed = "Nein";
}
?>
<tr>
<td class="text-center"><a
href="<?= self::getUrl("TimerecordingBilling", "detail", ["month" => $month]) ?>"> <?= $month ?></a>
</td>
<td class="text-center"><?= $closed ?></td>
<td class="text-center"><?= $closetime ?></td>
<td class="text-center"><?= $closer ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
<script type="text/javascript">
var hidesearch = [7];
$(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

@@ -0,0 +1,204 @@
<?php include(realpath(dirname(__FILE__) . "/../../$mfLayoutPackage") . "/header.php");
$initialApproval = date("Y-m-d H:i:s", $timerecordingcar->initial_approval);
$initialApprovalMonth = date("m", $timerecordingcar->initial_approval);
$firstApproval = strtotime('+' . $timerecordingcar->first_approval . 'years', strtotime($initialApproval));
if ($firstApproval < time()) {
$firstApproval = strtotime(date("Y-$initialApprovalMonth-01", time()));
if ($firstApproval < time()) {
$firstApproval = strtotime(date("Y-$initialApprovalMonth-01", strtotime('+1 year')));
}
}
$approval = date("m/Y", $firstApproval);
?>
<link href="<?= self::getResourcePath() ?>assets/css/datatables-std.css?<?= date('U') ?>" rel="stylesheet"
type="text/css"/>
<style>
table.dataTable.table-sm > thead > tr > th:not(.sorting_disabled) {
padding-right: 10px;
}
</style>
<!-- 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"><a href="<?= self::getUrl("TimerecordingCar") ?>">Fahrzeuge</a>
</li>
<li class="breadcrumb-item active"><?= $timerecordingcar->number_plate ?></li>
</ol>
</div>
<h4 class="page-title"><?= $timerecordingcar->brand . "/" . $timerecordingcar->model . " (" . $timerecordingcar->number_plate . ")" ?>
Detail
<span class="ml-2">
<a href="<?= self::getUrl("TimerecordingCar", "edit", ["id" => $timerecordingcar->id, 'returnto' => "detail"]) ?>">
<button class="btn btn-primary">Bearbeiten</button>
</a>
</span>
</h4>
</div>
</div>
</div>
<!-- end page title -->
<div class="card">
<div class="card-body mb-3">
<div class="row">
<div class="col-12 col-lg-5 card-border">
<div>
<h4>Fahrzeug Informationen </h4>
</div>
<div>
<table class="table table-sm">
<tbody>
<tr>
<th class="w-30">Marke</th>
<td><?= $timerecordingcar->brand ?></td>
</tr>
<tr>
<th>Model/Typ</th>
<td><?= $timerecordingcar->model ?></td>
</tr>
<tr>
<th>Erste §57a nach</th>
<td><?= ($timerecordingcar->first_approval) ? $timerecordingcar->first_approval . " Jahr(en)" : "-" ?></td>
</tr>
<tr>
<th>Fahrzeugverwalter</th>
<td><?= ($timerecordingcar->user_id) ? $timerecordingcar->user->name : "-" ?></td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="col-12 col-lg-5 card-border">
<div>
<h4>&nbsp;</h4>
</div>
<div>
<table class="table table-sm">
<tbody>
<tr>
<th>Fahrtenbuch</th>
<td><?= ($timerecordingcar->timerecording) ? "Ja" : "Nein" ?></td>
</tr>
<tr>
<th>Erstzulassung</th>
<td><?= ($timerecordingcar->initial_approval) ? date("m/Y", $timerecordingcar->initial_approval) : "-" ?></td>
</tr>
<tr>
<th>Nächste $57a</th>
<td><?= ($timerecordingcar->initial_approval) ? $approval : "-" ?></td>
</tr>
<tr>
<th class="w-30">Kilometerstand</th>
<td><?= ($timerecordingcar->mileage_now) ? $timerecordingcar->mileage_now . " KM" : "-" ?></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<div class="card">
<div class="card-body mb-3">
<div class="row">
<div class="col-12">
<div class="float-left">
<h4 class="header-title">Fahrtenbuch</h4>
</div>
<div class="float-right">
</div>
</div>
</div>
<table id="datatable" class="table table-striped table-hover table-sm">
<thead>
<tr>
<th class="text-center">Startkilometer</th>
<th class="text-center">Endkilometer</th>
<th class="text-center">Kilometer</th>
<th class="text-center">Fahrer</th>
<th class="text-center">Datum</th>
<th class="text-center">Zeit</th>
<th class="text-center">Ort</th>
<th class="edit-width"></th>
</tr>
<tr id="filterrow">
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<?php foreach ($timerecordings as $timerecording): ?>
<tr>
<td class="text-center"><?= $timerecording->mileage_start ?> KM</td>
<td class="text-center"><?= $timerecording->mileage_end ?> KM</td>
<td class="text-center"><?= $timerecording->mileage_end - $timerecording->mileage_start ?>KM
<td class="text-center"><?= $timerecording->user->name ?></td>
<td data-order="<?= $timerecording->start ?>"
class="text-center"><?= date("d.m.Y", $timerecording->start) ?></td>
<td class="text-center"><?= date("H:i", $timerecording->start) . " - " . date("H:i", $timerecording->end) ?></td>
</td>
<td class="text-center"><?= $timerecording->businesstrip_info ?></td>
</td>
<td style="text-align: left; letter-spacing: 4px; font-size: 1.1em;">
<!-- <a href="-->
<?php //= self::getUrl("TimerecordingCar", "edit", ["id" => $timerecordingcar->id]) ?><!--"><i-->
<!-- class="far fa-edit" title="Bearbeiten"></i></a>-->
<!-- <a href="-->
<?php //= self::getUrl("TimerecordingCar", "delete", ["id" => $timerecordingcar->id]) ?><!--"-->
<!-- onclick="if(!confirm('Auto wirklich löschen?')) return false;" class="text-danger"-->
<!-- title="Löschen"><i class="fas fa-trash"></i></a>-->
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
<script type="text/javascript">
var hidesearch = [7];
$(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

@@ -0,0 +1,169 @@
<?php include(realpath(dirname(__FILE__) . "/../../$mfLayoutPackage") . "/header.php");
if (isset($_GET['returnto']) && $_GET['returnto'] == "detail") {
$cancelUrl = self::getUrl("TimerecordingCar", "Detail", ["id" => $timerecordingcars->id]);
} else {
$cancelUrl = self::getUrl("TimerecordingCar");
}
foreach ($timerecordingusers as $timerecordinguser) {
$timerecordingUsers[$timerecordinguser->name] = $timerecordinguser->id;
}
ksort($timerecordingUsers);
?>
<link href="<?= self::getResourcePath() ?>assets/css/select2-cstm.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"><a
href="<?= self::getUrl("TimerecordingCar") ?>">Fahrzeuge</a></li>
<li class="breadcrumb-item active"><?= ($timerecordingcars->id) ? "bearbeiten" : "Neu" ?></li>
</ol>
</div>
<h4 class="page-title"><?= ($timerecordingcars->id) ? "Fahrzeug bearbeiten" : "Neues Fahrzeug" ?></h4>
</div>
</div>
</div>
<!-- end page title -->
<div class="row">
<div class="col-lg-12">
<div class="card bg-light">
<div class="card-body">
<h4 class="header-title mb-2"><?= ($timerecordingcars->id) ? "Fahrzeug bearbeiten" : "Neues Fahrzeug" ?></h4>
<form class="form-horizontal" method="post"
action="<?= self::getUrl("TimerecordingCar", "save", ["returnto" => $_GET["returnto"]]) ?>">
<div class="card no-shadow">
<div class="card-body">
<input type="hidden" name="id" value="<?= $timerecordingcars->id ?>"/>
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="number_plate">Kennzeichen *</label>
<div class="col-lg-1">
<input required="required" type="text" id="number_plate" name="number_plate"
class="form-control"
value="<?= $timerecordingcars->number_plate ?>"/>
</div>
</div>
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="brand">Fahrzeugverwalter</label>
<div class="col-lg-2">
<select id="user_id_select" name="user_id"
class="select2 form-control" required="required">
<option value="-">&nbsp</option>
<?php foreach ($timerecordingUsers as $key => $timerecordingUser): ?>
<option <?= ($timerecordingcars->user_id==$timerecordingUser) ? 'selected="selected' : "" ?> value="<?= $timerecordingUser ?>"><?= $key ?></option>
<?php
endforeach; ?>
</select>
</div>
</div>
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="brand">Marke *</label>
<div class="col-lg-3">
<input required="required" type="text" id="brand" name="brand"
class="form-control"
value="<?= $timerecordingcars->brand ?>"/>
</div>
</div>
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="model">Model/Typ *</label>
<div class="col-lg-3">
<input required="required" type="text" id="model" name="model"
class="form-control"
value="<?= $timerecordingcars->model ?>"/>
</div>
</div>
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="initial_approval">Erstzulassung</label>
<div class="col-lg-2">
<input type="month" id="initial_approval"
name="initial_approval"
class="form-control"
value="<?= ($timerecordingcars->initial_approval) ? date('Y-m', $timerecordingcars->initial_approval) : "" ?>"/>
</div>
</div>
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="first_approval">Erste §57a nach</label>
<div class="col-lg-2">
<select id="first_approval" name="first_approval" class="select2 form-control">
<option value=" ">&nbsp;</option>
<option value="1" <?= ($timerecordingcars->first_approval == "1") ? "selected='selected'" : "" ?>>
1 Jahr
</option>
<option value="2" <?= ($timerecordingcars->first_approval == "2") ? "selected='selected'" : "" ?>>
2 Jahren
</option>
<option value="3" <?= ($timerecordingcars->first_approval == "3") ? "selected='selected'" : "" ?>>
3 Jahren
</option>
<option value="4" <?= ($timerecordingcars->first_approval == "4") ? "selected='selected'" : "" ?>>
4 Jahren
</option>
<option value="5" <?= ($timerecordingcars->first_approval == "5") ? "selected='selected'" : "" ?>>
5 Jahren
</option>
</select>
</div>
</div>
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="mileage">Kilometerstand</label>
<div class="col-lg-1">
<input type="number" id="mileage" name="mileage"
class="form-control"
value="<?= $timerecordingcars->mileage ?>"/>
</div>
</div>
<div class="form-group row">
<label class="col-lg-2 col-form-label"
for="timerecording">Digitales Fahrtenbuch</label>
<div class="col-lg-3">
<div class="form-check">
<input id="timerecording"
class="form-check-input" <?= ($timerecordingcars->timerecording) ? 'checked="checked"' : '' ?>
type="checkbox" name="timerecording" value="1"/>
</div>
</div>
</div>
</div>
</div>
<div class="form-group row">
<label class="col-lg-2"></label>
<div class="col-lg-10">
<button type="submit" class="btn btn-primary">Speichern</button>
<a href="<?= $cancelUrl ?>">
<button type="button" class="btn btn-secondary">Abbrechen</button>
</a>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
<script type="text/javascript">
$(".select2").select2({placeholder: ""});
// disable mousewheel on a input number field when in focus
$('form').on('focus', 'input[type=number]', function (e) {
$(this).on('wheel.disableScroll', function (e) {
e.preventDefault()
})
});
$('form').on('blur', 'input[type=number]', function (e) {
$(this).off('wheel.disableScroll')
});
</script>
<?php include(realpath(dirname(__FILE__) . "/../../$mfLayoutPackage") . "/footer.php"); ?>

View File

@@ -0,0 +1,123 @@
<?php include(realpath(dirname(__FILE__) . "/../../$mfLayoutPackage") . "/header.php"); ?>
<link href="<?= self::getResourcePath() ?>assets/css/datatables-std.css?<?= date('U') ?>" rel="stylesheet"
type="text/css"/>
<style>
table.dataTable.table-sm > thead > tr > th:not(.sorting_disabled) {
padding-right: 10px;
}
</style>
<!-- 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">Fahrzeuge</li>
</ol>
</div>
<h4 class="page-title">Fahrzeuge</h4>
</div>
</div>
</div>
<!-- end page title -->
<div class="card">
<div class="card-body mb-3">
<div class="row">
<div class="col-12">
<div class="float-left">
<h4 class="header-title">Liste aller Fahrzeuge</h4>
</div>
<div class="float-right">
<a class="btn btn-primary mb-2" href="<?= self::getUrl("TimerecordingCar", "add") ?>"><i
class="fas fa-plus"></i> Neues Fahrzeug anlegen</a>
</div>
</div>
</div>
<table id="datatable" class="table table-striped table-hover table-sm">
<thead>
<tr>
<th class="text-center">Kennzeichen</th>
<th class="text-center">Fahrzeugverwalter</th>
<th class="text-center">Marke</th>
<th class="text-center">Model/Typ</th>
<th class="text-center">Erstzulassssung</th>
<th class="text-center">$57a</th>
<th class="text-center">Fahrtenbuch</th>
<th class="text-center">Kilometerstand</th>
<th class="edit-width"></th>
</tr>
<tr id="filterrow">
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<?php foreach ($timerecordingcars as $timerecordingcar):
$initialApproval = date("Y-m-d H:i:s", $timerecordingcar->initial_approval);
$initialApprovalMonth = date("m", $timerecordingcar->initial_approval);
$firstApproval = strtotime('+' . $timerecordingcar->first_approval . 'years', strtotime($initialApproval));
if ($firstApproval < time()) {
$firstApproval = strtotime(date("Y-$initialApprovalMonth-01", time()));
if ($firstApproval < time()) {
$firstApproval = strtotime(date("Y-$initialApprovalMonth-01", strtotime('+1 year')));
}
}
$approval = date("m/Y", $firstApproval);
?>
<tr>
<td>
<a href="<?= self::getUrl("TimerecordingCar", "detail", ["id" => $timerecordingcar->id]) ?>"> <?= $timerecordingcar->number_plate ?></a>
</td>
<td><?= ($timerecordingcar->user_id) ? $timerecordingcar->user->name : "-" ?></td>
<td><?= $timerecordingcar->brand ?></td>
<td><?= $timerecordingcar->model ?></td>
<td class="text-center"><?= ($timerecordingcar->initial_approval) ? date("m/Y", $timerecordingcar->initial_approval) : "-" ?></td>
<td class="text-center"><?= ($timerecordingcar->initial_approval) ? $approval : "-" ?></td>
<td class="text-center"><?= ($timerecordingcar->timerecording) ? "Ja" : "Nein" ?></td>
<td class="text-center"><?= ($timerecordingcar->mileage_now) ? number_format($timerecordingcar->mileage_now, 0, ',', '.')." KM" : "-" ?>
</td>
<td style="text-align: left; letter-spacing: 4px; font-size: 1.1em;">
<a href="<?= self::getUrl("TimerecordingCar", "edit", ["id" => $timerecordingcar->id]) ?>"><i
class="far fa-edit" title="Bearbeiten"></i></a>
<a href="<?= self::getUrl("TimerecordingCar", "delete", ["id" => $timerecordingcar->id]) ?>"
onclick="if(!confirm('Fahrzeug wirklich löschen?')) return false;" class="text-danger"
title="Löschen"><i class="fas fa-trash"></i></a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
<script type="text/javascript">
var hidesearch = [8];
var columnfilter = [6];
var columnoptions = '<option value=""></option><option value="Ja">Ja</option><option value="Nein">Nein</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

@@ -93,6 +93,17 @@
</div>
</div>
</div>
<div class="form-group row">
<label class="col-lg-2 col-form-label"
for="businesstrip">Unbezahlt</label>
<div class="col-lg-3">
<div class="form-check">
<input id="businesstrip"
class="form-check-input" <?php if ($timerecordingcategoriess->unpaid) echo 'checked="checked"'; ?>
type="checkbox" name="unpaid" 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>

View File

@@ -61,6 +61,17 @@ $daysSelect .= "</select>";
<div class="card no-shadow">
<div class="card-body">
<input type="hidden" name="id" value="<?= $timerecordingemployees->id ?>"/>
<div class="form-group row">
<label class="col-lg-2 col-form-label"
for="bmd_active">Aktive Verrechnung</label>
<div class="col-lg-3">
<div class="form-check">
<input id="bmd_active"
class="form-check-input" <?php if ($timerecordingemployees->bmd_active) echo 'checked="checked"'; ?>
type="checkbox" name="bmd_active" value="1"/>
</div>
</div>
</div>
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="user_id">Mitarbeiter *</label>
<div class="col-lg-3">
@@ -89,6 +100,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="enddate">Enddatum
Zeiterfassung</label>
<div class="col-lg-2">
<input type="date" id="enddate" name="enddate"
class="form-control"
value="<?= ($timerecordingemployees->enddate) ? date('Y-m-d', $timerecordingemployees->enddate): "" ?>"/>
</div>
</div>
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="birthday">Geburtstag</label>
<div class="col-lg-2">

View File

@@ -9,9 +9,14 @@ $type[3] = "Lehrling";
.border-dark {
border-color: #cbcbcb !important;
}
.border-bottom {
border-bottom: 1px dotted #adadad !important;
}
.inactive_empoyee {
background-color: #ff75756e !important;
}
</style>
<!-- start page title -->
<div class="row">
@@ -52,6 +57,9 @@ $type[3] = "Lehrling";
<th class="text-center">Sollstunden</th>
<th class="text-center">Mehrstunden</th>
<th class="text-center">Überstunden</th>
<?php if ($me->superexpertEnabled()): ?>
<th class="text-center">Black P. Stunden</th>
<?php endif; ?>
<th class="text-center">Offene Urlaube</th>
<th class="text-center edit-width">Schnellbuchung</th>
<th class="edit-width"></th>
@@ -62,6 +70,9 @@ $type[3] = "Lehrling";
<th></th>
<th></th>
<th></th>
<?php if ($me->superexpertEnabled()): ?>
<th></th>
<?php endif; ?>
<th></th>
<th></th>
<th></th>
@@ -97,7 +108,7 @@ $type[3] = "Lehrling";
}
?>
<tr>
<tr class="<?= ($timerecordingemployees[$timerecordinguser->id]['bmd_active'] == "0") ? "inactive_empoyee" : "" ?>">
<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>
@@ -105,8 +116,14 @@ $type[3] = "Lehrling";
<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"
data-order="<?= $timerecordingemployees[$timerecordinguser->id]['overtime_now'] ?>"><?= $overTime ?></td>
<?php if ($me->superexpertEnabled()): ?>
<td class="text-center"
data-order="<?= $timerecordingemployees[$timerecordinguser->id]['bpa_hours'] ?>"><?= sprintf('%02dh:%02dm', floor($timerecordingemployees[$timerecordinguser->id]['bpa_hours'] / 3600), floor($timerecordingemployees[$timerecordinguser->id]['bpa_hours'] / 60 % 60)) ?></td>
<?php endif; ?>
<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
@@ -126,7 +143,9 @@ $type[3] = "Lehrling";
<script type="text/javascript">
var hidesearch = [3, 4, 5, 6, 7, 9];
<?php if ($me->superexpertEnabled()): ?>
hidesearch = [3, 4, 5, 6, 7,8 ,10];
<?php endif; ?>
$(document).ready(function () {
});

View File

@@ -121,7 +121,7 @@ $years[time() - 31536000] = date('Y', time() - 31536000);
<input id="id" type="hidden" name="id" value=""/>
<div class="form-row">
<div class="form-group col-lg-2">
<label class="col-form-label" for="user_id">Buchungsart</label>
<label class="col-form-label" for="user_id">Mitarbeiter</label>
<select id="user_id_select" name="user_id"
class="select2 form-control" required="required">
@@ -220,7 +220,7 @@ $years[time() - 31536000] = date('Y', time() - 31536000);
</label>
</div>
</div>
<div class="col-lg-2 mb-2 businesstrip-div">
<div class="col-lg-2 mb-2 businesstrip-div businesstrip-check-div ">
<div class="form-check text-center mt-1">
<input class="form-check-input" type="checkbox" name="businesstrip"
@@ -235,8 +235,32 @@ $years[time() - 31536000] = date('Y', time() - 31536000);
placeholder="Ort"
class="form-control"/>
</div>
</div>
<div class="col-lg-2 car-div car-div-car" style="display:none">
<select id="timerecordingCar_id" name="timerecordingCar_id"
class="select2 form-control">
<option value="">Auto auswählen</option>
<?php foreach ($timerecordingCars as $timerecordingCar): ?>
<option value="<?= $timerecordingCar->id ?>"
data-mileagenow="<?= $timerecordingCar->mileage_now ?>"><?= $timerecordingCar->number_plate . " (" . $timerecordingCar->brand." ".$timerecordingCar->model . ")" ?></option>
</option>
<?php
endforeach; ?>
</select>
</div>
<div class="col-lg-1 car-div " style="display:none">
<input style="" type="number" id="mileage_start" name="mileage_start"
placeholder="KM Start"
class="form-control"/>
</div>
<div class="col-lg-1 car-div" style="display:none">
<input style="" type="number" id="mileage_end" name="mileage_end"
placeholder="KM Ende"
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>
@@ -245,16 +269,17 @@ $years[time() - 31536000] = date('Y', time() - 31536000);
</button>
</div>
</div>
<div class=" row mt-2">
<div class="col-lg-4" id="message-box">
</div>
<div class=" row mt-2">
<div class="col-lg-4" id="message-box">
</div>
</div>
</div>
</div>
</form>
</form>
</div>
<div class="card">
<div class="card-body mb-3">
<div class="form-group module-row row mb-3">
@@ -292,7 +317,7 @@ $years[time() - 31536000] = date('Y', time() - 31536000);
<div class="input-group">
<select id="datayear" class="form-control select2">
<?php foreach ($years as $key => $Year): ?>
<option <?= (date('Y', time()) == $Year) ? "selected='selsected'" : NULL ?>
<option <?= (date('Y', time()) == $Year) ? "selected='selected'" : NULL ?>
value="<?= $key ?>"><?= $Year ?></option>
<?php endforeach; ?>
</select>

View File

@@ -0,0 +1,160 @@
<?php /** @noinspection PhpUndefinedClassInspection
* @var string $mfLayoutPackage
* @var TYPE_NAME $git_merge_ts
*/
//additional css /css/views/RaspberryDisplay.css
$JSGlobals = ["BASE_URL" => self::getUrl("VoiceCallActive"),
"DASHBOARD_URL" => self::getUrl("Dashboard"),
"MFAPPNAME" => MFAPPNAME_SLUG,
"PAGE_TITLE" => "Active Voice Calls",
"PATH" => [
["text" => MFAPPNAME_SLUG, "href" => self::getUrl("Dashboard")],
["text" => "Active Voice Calls", "href" => self::getUrl("VoiceCallActive")]
],
"VOICE_CALL_ACTIVE_API_URL" => self::getUrl("VoiceCallActive/api"),
];
$additionalJS = ["plugins/vue/vue.js",
"plugins/axios/axios.min.js",
"plugins/vue/tt-components/tt-page-title.js",
"plugins/vue/tt-components/tt-table.js",
];
$additionalCSS = [
'plugins/vue/tt-components/css/tt-table.css',
];
include(realpath(dirname(__FILE__) . "/../../$mfLayoutPackage") . "/header.php"); ?>
<div id="app">
<tt-page-title :title="window['TT_CONFIG']['PAGE_TITLE']" :path="window['TT_CONFIG']['PATH']"></tt-page-title>
<tt-table :fetch-url="window['TT_CONFIG']['VOICE_CALL_ACTIVE_API_URL'] + '?do=getActiveCalls'" :table-config="VoiceCallActiveTableConfig"
small ref="table">
<template v-slot:top-buttons>
<button type="button" class="btn btn-primary" @click="refresh" data-toggle="tooltip" data-placement="bottom" title="Refreshing too often will run into API-Rate limits and will cause errors.">
<template v-if="refreshLoading">
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
</template>
<template v-else>
<i class="fas fa-sync-alt"></i>
Refresh
</template>
</button>
<div class="d-flex">
<label style="margin-bottom: 0 !important;">
<input type="checkbox" id="autoRefresh" data-toggle="toggle" data-size="lg" @change="clickedCheckBox(this.checked)">
<span class="ml-2">Auto Refresh (5sec)</span>
</label>
<span style="width: 50px"></span>
<div class="voice-yellow p-2">Ringing</div>
<div class="voice-red p-2">Outgoing</div>
<div class="voice-green p-2">Ingoing</div>
</div>
</template>
<template v-slot:answer_time="{ row }">
{{ !isNaN(new Date(row.answer_time)) ? new Date(row.answer_time).toLocaleString() : 'Call is not running' }}
</template>
<template v-slot:status="{ row }">
<i v-if="!row.dst_device_extension && row.status !== 'Ringing'" class="fas fa-phone-arrow-up-right"></i>
<i v-else-if="!row.dst_device_extension && row.status === 'Ringing'" class="fas fa-phone-arrow-up-right fa-shake"></i>
<i v-else-if="row.status === 'Ringing'" class="fas fa-phone-arrow-down-left fa-shake"></i>
<i v-else class="fas fa-phone-arrow-down-left"></i>
{{ row.status }}
</template>
</tt-table>
</div>
<!-- TODO: download from cdn to local -->
<link href="https://cdn.jsdelivr.net/gh/gitbrent/bootstrap4-toggle@3.6.1/css/bootstrap4-toggle.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/gh/gitbrent/bootstrap4-toggle@3.6.1/js/bootstrap4-toggle.min.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/momentjs/latest/moment.min.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/daterangepicker/daterangepicker.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/daterangepicker/daterangepicker.css" />
<style>
.voice-green {
background-color: #6CAE75 !important
}
.voice-yellow {
background-color: #E8E288 !important
}
.voice-red {
background-color: #FF8360 !important
}
.table-sm td {
padding: 4px !important;
}
</style>
<script>
new Vue({
el: '#app',
data: {
window: window,
VoiceCallActiveTableConfig: {
customRowClass: function (row) {
if (row.status.toLowerCase() === 'ringing') {
return 'voice-yellow';
}
if (!row.dst_device_extension) {
return 'voice-red';
}
if (row.status.toLowerCase() === 'answered') {
return 'voice-green';
}
},
headers: [
{text: 'Call ID', key: 'id', filter: false},
{text: 'Status', key: 'status', filter: false},
{text: 'Answer Time', key: 'answer_time', filter: false},
{text: 'Duration', key: 'duration', filter: false},
{text: 'Source', key: 'src', filter: false},
{text: 'Device Type', key: 'device_type', filter: false},
{text: 'Destination', key: 'localized_dst', filter: false},
{text: 'Destination User', key: 'dst_user', filter: false},
{text: 'Destination Device Extension', key: 'dst_device_extension', filter: false},
],
tableHeader: 'Active Voice Calls',
},
refreshLoading: false,
autoRefresh: null,
},
mounted() {
$('[data-toggle="tooltip"]').tooltip();
const _this = this;
$('#autoRefresh').change(function () {
console.log(this.checked);
if (this.checked) {
_this.autoRefresh = setInterval(function () {
_this.refresh();
}, 5000);
} else {
clearInterval(_this.autoRefresh);
}
})
},
methods: {
async refresh() {
this.refreshLoading = true;
this.$refs.table.loading = true;
await this.$refs.table.fetchData();
$('.tooltip').tooltip('hide');
this.$refs.table.loading = false;
this.refreshLoading = false;
},
}
})
</script>
<?php include(realpath(dirname(__FILE__) . "/../../$mfLayoutPackage") . "/footer.php"); ?>

View File

@@ -0,0 +1,89 @@
<?php /** @noinspection PhpUndefinedClassInspection
* @var string $mfLayoutPackage
* @var TYPE_NAME $git_merge_ts
*/
//additional css /css/views/RaspberryDisplay.css
$JSGlobals = ["BASE_URL" => self::getUrl("Domain"),
"DASHBOARD_URL" => self::getUrl("Dashboard"),
"MFAPPNAME" => MFAPPNAME_SLUG,
"PAGE_TITLE" => "Domains",
"PATH" => [
["text" => MFAPPNAME_SLUG, "href" => self::getUrl("Dashboard")],
["text" => "Voice Calls History", "href" => self::getUrl("VoiceCallHistory")]
],
"VOICE_CALL_HISTORY_API_URL" => self::getUrl("VoiceCallHistory/api"),
];
$additionalJS = ["plugins/vue/vue.js",
"plugins/axios/axios.min.js",
"plugins/vue/tt-components/tt-page-title.js",
"plugins/vue/tt-components/tt-table.js",
];
$additionalCSS = [
'plugins/vue/tt-components/css/tt-table.css',
];
include(realpath(dirname(__FILE__) . "/../../$mfLayoutPackage") . "/header.php"); ?>
<div id="app">
<tt-page-title :title="window['TT_CONFIG']['PAGE_TITLE']" :path="window['TT_CONFIG']['PATH']"></tt-page-title>
<tt-table :fetch-url="window['TT_CONFIG']['VOICE_CALL_HISTORY_API_URL'] + '?do=getCalls'" :table-config="VoiceCallHistoryTableConfig"
small ref="table">
<template v-slot:top-buttons>
<button type="button" class="btn btn-primary" @click="importCallsFromToday">
<template v-if="importCallsFromTodayLoading">
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
</template>
<template v-else>
<i class="fas fa-sync-alt"></i>
Re-Import Calls from Today
</template>
</button>
</template>
</tt-table>
</div>
<!-- TODO: download from cdn to local -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-select@1.13.14/dist/css/bootstrap-select.min.css">
<script type="text/javascript" src="https://cdn.jsdelivr.net/momentjs/latest/moment.min.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/daterangepicker/daterangepicker.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/daterangepicker/daterangepicker.css" />
<script>
new Vue({
el: '#app',
data: {
window: window,
VoiceCallHistoryTableConfig: {
headers: [
{text: "Call-ID", key: "uid"},
{text: "Voice Account", key: "voice_account"},
{text: "Time Range", key: "start", filter: "dateRange"},
{text: "Source", key: "source"},
{text: "Destination", key: "destination"},
{text: "Billable", key: "billable"},
{text: "Duration", key: "duration"},
],
tableHeader: 'Voice Call History',
},
importCallsFromTodayLoading: false,
},
mounted() {},
methods: {
async importCallsFromToday() {
this.importCallsFromTodayLoading = true;
const response = await axios.get(window['TT_CONFIG']['VOICE_CALL_HISTORY_API_URL'] + '?do=importCallsFromToday');
window.notify(response.data.status === 'success' ? 'success' : 'error', response.data.message);
await this.$refs.table.fetchData();
this.importCallsFromTodayLoading = false;
},
}
})
</script>
<?php include(realpath(dirname(__FILE__) . "/../../$mfLayoutPackage") . "/footer.php"); ?>

View File

@@ -40,9 +40,11 @@
<?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> Auswertung/Korrektur</a></li>
<li><a href="<?=self::getUrl("TimerecordingBilling")?>"><i class="far fa-fw fa-money-bill-1-wave text-info"></i> Verrechnung</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>
<li><a href="<?=self::getUrl("TimerecordingCar")?>"><i class="far fa-fw fa-sharp fa-regular fa-cars text-info"></i> Fahrzeugverwaltung</a></li>
<?php endif; ?>
</ul>
</li>
@@ -75,6 +77,7 @@
<?php if($me->is(["Admin"])): ?>
<li class="mobile-hide"><a href="<?=self::getUrl("OpenAccessId")?>"><i class="fad fa-fw fa-link-simple text-info"></i> Open Access IDs</a></li>
<li class="mobile-hide"><a href="<?=self::getUrl("Producttech")?>"><i class="fad fa-fw fa-microchip text-info"></i> Technologien</a></li>
<li class="mobile-hide"><a href="<?=self::getUrl("HistoricTicket")?>"><i class="fad fa-fw fa-headset text-info"></i> Historische Tickets</a></li>
<?php if($me->can("Fibu")): ?><li class="mobile-hide"><a href="<?=self::getUrl("Vatgroup")?>"><i class="fas fa-fw fa-circle-dollar-to-slot text-info"></i> Steuersätze</a></li><?php endif; ?>
<!--<li><a href="<?=self::getUrl("Contractconfig")?>"><i class="fad fa-gear text-info"></i> ContractConfig</a></li>-->
<?php endif; ?>
@@ -95,6 +98,9 @@
<?php if($me->is(["Admin","netowner","lineplanner","lineworker"]) && $me->can("Linework")): ?><li><a href="<?=self::getUrl("Linework")?>"><i class="fas fa-fw fa-ethernet text-info"></i> Leitungsbau</a></li><?php endif; ?>
<?php if($me->is(["Admin","netowner","netoperator","lineworker"]) && $me->can("Patching")): ?><li class="has-sub-submenu"><a href="<?=self::getUrl("Patching")?>"><i class="fas fa-fw fa-plug text-info"></i> Patchungen</a></li><?php endif; ?>
<?php if($me->is(["Admin","netowner","pipeplanner","lineplanner","pipeworker","netoperator","lineworker"]) && $me->can("Filestore")): ?><li><a href="<?=self::getUrl("Filestore")?>"><i class="fas fa-fw fa-file text-info"></i> Dateiablage</a></li><?php endif; ?>
<?php if($me->is(["Admin","netowner","pipeplanner","pipeplanner"]) && $me->is("employee")): ?><li><a href="<?=self::getUrl("FiberPlanDispatcher")?>"><i class="fas fa-building-circle-arrow-right text-info"></i> Verteiler und Schächte</a></li><?php endif; ?>
<?php if($me->is(["Admin","netowner","lineplanner","lineworker"]) && $me->is("employee")): ?><li><a href="<?=self::getUrl("FiberPlanPipe")?>"><i class="fas fa-pipe text-info pl-1"></i> Rohrverzeichnis</a></li><?php endif; ?>
<!-- --><?php //if($me->is(["Admin","netowner","lineplanner","lineworker"]) && $me->is("employee")): ?><!--<li><a href="--><?php //=self::getUrl("FiberPlanCable")?><!--"><i class="fas fa-pipe text-info pl-1"></i> Kabelverzeichnis</a></li>--><?php //endif; ?>
</ul>
</li>
<?php endif; ?>
@@ -107,6 +113,7 @@
<ul class="submenu">
<?php if($me->isAdmin() || $me->can("Cpeprovisioning")): ?><li><a href="<?=self::getUrl("Cpeprovisioning")?>"><i class="fad fa-fw fa-hdd text-info"></i> CPE Provisioning</a></li><?php endif; ?>
<?php if($me->isAdmin() || $me->can("Cpeshipping")): ?><li><a href="<?=self::getUrl("Cpeshipping")?>"><i class="fad fa-fw fa-shipping-fast text-info"></i> CPE Versand</a></li><?php endif; ?>
<?php if($me->isAdmin()) : ?><li><a href="<?=self::getUrl("Domain")?>"><i class="fad fa-fw fa-globe text-info"></i> Domains</a></li><?php endif; ?>
</ul>
</li>
<?php endif; ?>
@@ -117,8 +124,10 @@
<i class="fad fa-fw fa-phone"></i>Telefonie <div class="arrow-down"></div>
</a>
<ul class="submenu">
<?php if($me->isAdmin() || $me->can("Voipnumbering")): ?><li><a href="<?=self::getUrl("Voicenumberblock")?>"><i class="fad fa-fw fa-phone-office text-info"></i> Rufnummernblöcke</a></li><?php endif; ?>
<?php if($me->isAdmin() || $me->can("Voiceplan")): ?><li><a href="<?=self::getUrl("Voiceplan")?>"><i class="fas fa-fw fa-phone-arrow-up-right text-info"></i> Sprachtarife</a></li><?php endif; ?>
<?php if($me->isAdmin() || $me->can("Voipnumbering")): ?><li><a href="<?=self::getUrl("Voicenumberblock")?>"><i class="fad fa-fw fa-phone-office text-info"></i> Rufnummernblöcke</a></li><?php endif; ?>
<?php if($me->isAdmin() || $me->can("Voiceplan")): ?><li><a href="<?=self::getUrl("Voiceplan")?>"><i class="fas fa-fw fa-phone-arrow-up-right text-info"></i> Sprachtarife</a></li><?php endif; ?>
<?php if($me->isAdmin() || $me->can("VoiceCallHistory")): ?><li><a href="<?=self::getUrl("VoiceCallHistory")?>"><i class="fas fa-fw fa-phone-arrow-down-left text-info"></i> Voice Call History</a></li><?php endif; ?>
<?php if($me->isAdmin() || $me->can("VoiceCallActive")): ?><li><a href="<?=self::getUrl("VoiceCallActive")?>"><i class="fas fa-fw fa-phone-volume text-info"></i> Active Voice Calls</a></li><?php endif; ?>
</ul>
</li>
<?php endif; ?>
@@ -163,4 +172,4 @@
</div>
<!-- end container -->
</div>
<!-- end navbar-custom -->
<!-- end navbar-custom -->