Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| bef9de2c71 | |||
| 8a9d7bee75 | |||
| b963ab9ca1 | |||
| a71d401864 | |||
| 18b91cc4a5 | |||
| bc76739320 | |||
| df620a4897 | |||
| e1d9e01fdb | |||
| feb4be6621 | |||
| 5a88d0780a | |||
| ecf9db4a13 | |||
| e4283df099 | |||
| 6e5e63adc5 | |||
| d8123ef332 | |||
| c26b54c08b | |||
| 81a3967b0e | |||
| 14bae6c9ef | |||
| 43bc416554 | |||
| b81164279f | |||
| 345d22958f | |||
| 20805c11db | |||
| 957d52dd21 | |||
| f8c8725622 | |||
| f8fba4275d | |||
| 5912bc29ac | |||
| 36944c71bf | |||
| 91c0a2d9d9 | |||
| 0ff0c0d55e | |||
| 1358e17ac3 | |||
| 4ce1578bb5 | |||
| 72dac40753 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1 +1,3 @@
|
|||||||
config.php
|
config.php
|
||||||
|
.vscode
|
||||||
|
sftp.json
|
||||||
@@ -1,113 +1,250 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
require('config.php');
|
require('config.php');
|
||||||
|
|
||||||
require('vendor/autoload.php');
|
require('vendor/autoload.php');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
?>
|
?>
|
||||||
|
|
||||||
|
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="de">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
|
<title>Aufgabenmonitor</title>
|
||||||
<title>Aufgabenmonitor</title>
|
|
||||||
|
|
||||||
<!-- Bootstrap -->
|
<!-- Bootstrap -->
|
||||||
<link rel="stylesheet" href="vendor/twbs/bootstrap/dist/css/bootstrap.min.css" >
|
<link rel="stylesheet" href="vendor/twbs/bootstrap/dist/css/bootstrap.min.css">
|
||||||
<script src="scripts/jquery-3.5.1.min.js"></script>
|
<link href="css/sticky-footer.css" rel="stylesheet">
|
||||||
<link href="css/sticky-footer.css" rel="stylesheet">
|
|
||||||
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
|
|
||||||
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
|
|
||||||
<!--[if lt IE 9]>
|
|
||||||
<script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
|
|
||||||
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
|
|
||||||
<![endif]-->
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
|
||||||
$(document).ready(function(){
|
|
||||||
refreshAufgabenTable();
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
function refreshAufgabenTable(){
|
<style>
|
||||||
$('#AufgabenTableHolder').load('sources/getAufgabenTable.php', function(){
|
body { background-color: #000; }
|
||||||
setTimeout(refreshAufgabenTable, 30000);
|
.tableFixHead { overflow:auto; }
|
||||||
});
|
.tableFixHead thead th {
|
||||||
}
|
position: sticky;
|
||||||
// function refreshCheckInTable(){
|
top: 0;
|
||||||
// $('#getCheckInTableHolder').load('sources/getCheckInTable.php', function(){
|
z-index: 1;
|
||||||
// setTimeout(refreshCheckInTable, 5000);
|
background-color: #212529; /* .table-dark head */
|
||||||
// });
|
}
|
||||||
// }
|
.table-dark td, .table-dark th { vertical-align: middle; }
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
</head>
|
|
||||||
<body style="background-color: black;">
|
|
||||||
|
|
||||||
<div class="container-fluid">
|
<script src="scripts/jquery-3.5.1.min.js"></script>
|
||||||
<div class="row">
|
</head>
|
||||||
<div class="col-lg">
|
<body>
|
||||||
<h2 class="text-light">Aufgaben</h2>
|
|
||||||
<table class="table table-dark">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th scope="col">#</th>
|
|
||||||
<th scope="col">Bearbeiter</th>
|
|
||||||
<th scope="col">Aufgabe</th>
|
|
||||||
<th scope="col">Zieldatum</th>
|
|
||||||
<th scope="col">Priorität</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody id="AufgabenTableHolder">
|
|
||||||
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</header>
|
|
||||||
|
|
||||||
|
<div class="container-fluid py-3">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12">
|
||||||
|
<h2 class="text-light mb-3">Aufgaben</h2>
|
||||||
|
|
||||||
|
<!-- SCROLL CONTAINER -->
|
||||||
|
<div id="aufgaben-scroll" class="tableFixHead">
|
||||||
|
<table id="aufgaben-table" class="table table-dark table-striped table-hover mb-0">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col" style="width:6%">#</th>
|
||||||
|
<th scope="col" style="width:24%">Bearbeiter</th>
|
||||||
|
<th scope="col" style="width:40%">Aufgabe</th>
|
||||||
|
<th scope="col" style="width:15%">Ziel</th>
|
||||||
|
<th scope="col" style="width:15%">Prio</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="AufgabenTableHolder">
|
||||||
|
<!-- wird via AJAX gefüllt -->
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<!-- /SCROLL CONTAINER -->
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Bootstrap JS -->
|
||||||
|
<script src="vendor/twbs/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
|
|
||||||
|
<!-- === Scroll/Reload Script (wie bei CheckIn/CheckOut) === -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
/* ===========================
|
||||||
|
Feature-Toggle aus PHP
|
||||||
|
=========================== */
|
||||||
|
const SCROLL_FLAGS = {
|
||||||
|
aufgaben: <?php echo (defined('EnableScrollingAufgaben') && EnableScrollingAufgaben) ? 'true' : 'false'; ?>
|
||||||
|
};
|
||||||
|
|
||||||
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
|
function isEnabled() { return !!SCROLL_FLAGS.aufgaben; }
|
||||||
<script src="https://code.jquery.com/jquery-1.12.4.min.js" integrity="sha384-nvAa0+6Qg9clwYCGGPpDQLVpLNn0fRaROjHqs13t4Ggj3Ez50XnGQqc/r8MhnRDZ" crossorigin="anonymous"></script>
|
|
||||||
<!-- Include all compiled plugins (below), or include individual files as needed -->
|
/* ===========================
|
||||||
<script src="vendor/twbs/bootstrap/dist/js/bootstrap.min.js" integrity="sha384-aJ21OjlMXNL5UyIl/XNwTMqvzeRMZH2w8c5cRVpzpU8Y5bApTppSuUkhZXN0VxHd" crossorigin="anonymous"></script>
|
Höhe der Scroll-Container
|
||||||
</body>
|
- Voller Viewport ab Oberkante
|
||||||
|
=========================== */
|
||||||
|
function sizeScrollContainers() {
|
||||||
|
const node = document.querySelector('#aufgaben-scroll');
|
||||||
|
if (!node) return;
|
||||||
|
const rect = node.getBoundingClientRect();
|
||||||
|
const bottomMargin = 16;
|
||||||
|
const minH = 120;
|
||||||
|
const available = window.innerHeight - rect.top - bottomMargin;
|
||||||
|
node.style.maxHeight = Math.max(minH, available) + 'px';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===========================
|
||||||
|
Scroll-/Interaktionsstatus
|
||||||
|
=========================== */
|
||||||
|
const scrollState = new WeakMap(); // { userActive:boolean, autoTimer:number|null, loopHeight:number }
|
||||||
|
|
||||||
|
function ensureState(el) {
|
||||||
|
if (!scrollState.get(el)) scrollState.set(el, { userActive: false, autoTimer: null, loopHeight: 0 });
|
||||||
|
return scrollState.get(el);
|
||||||
|
}
|
||||||
|
|
||||||
|
function attachScrollGuards($scroller) {
|
||||||
|
const el = $scroller.get(0);
|
||||||
|
if (!el || el.__guardsBound) return;
|
||||||
|
if (!isEnabled()) return;
|
||||||
|
const state = ensureState(el);
|
||||||
|
|
||||||
|
const markActive = () => {
|
||||||
|
state.userActive = true;
|
||||||
|
clearTimeout(state._quietT);
|
||||||
|
state._quietT = setTimeout(() => { state.userActive = false; }, 800);
|
||||||
|
stopAutoScroll($scroller);
|
||||||
|
};
|
||||||
|
|
||||||
|
$scroller.on('wheel touchstart touchmove keydown mousedown mouseenter', markActive);
|
||||||
|
$scroller.on('mouseleave', () => setTimeout(() => maybeStartAutoScroll($scroller), 600));
|
||||||
|
el.__guardsBound = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===========================
|
||||||
|
Nahtloser Loop (Clone)
|
||||||
|
=========================== */
|
||||||
|
function buildSeamlessLoop($table, $scroller) {
|
||||||
|
$table.find('tbody.__loopClone').remove();
|
||||||
|
|
||||||
|
const scEl = $scroller.get(0);
|
||||||
|
const st = ensureState(scEl);
|
||||||
|
st.loopHeight = 0;
|
||||||
|
|
||||||
|
if (!isEnabled()) return;
|
||||||
|
|
||||||
|
const $main = $table.find('tbody').first();
|
||||||
|
if ($main.length === 0 || $main.children().length === 0) return;
|
||||||
|
|
||||||
|
const needScroll = $main.get(0).offsetHeight > scEl.clientHeight + 1;
|
||||||
|
if (!needScroll) return;
|
||||||
|
|
||||||
|
const $clone = $main.clone(false, false).addClass('__loopClone').attr('aria-hidden', 'true');
|
||||||
|
$table.append($clone);
|
||||||
|
st.loopHeight = $main.get(0).offsetHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===========================
|
||||||
|
Auto-Scroll
|
||||||
|
=========================== */
|
||||||
|
function startAutoScroll($scroller, speedPx = 1, stepMs = 40) {
|
||||||
|
const el = $scroller.get(0);
|
||||||
|
if (!isEnabled()) return;
|
||||||
|
|
||||||
|
const st = ensureState(el);
|
||||||
|
if (st.autoTimer) return;
|
||||||
|
if (st.loopHeight <= 0) return;
|
||||||
|
|
||||||
|
const tick = () => {
|
||||||
|
if (st.userActive) { stopAutoScroll($scroller); return; }
|
||||||
|
el.scrollTop += speedPx;
|
||||||
|
if (el.scrollTop >= st.loopHeight) el.scrollTop -= st.loopHeight;
|
||||||
|
};
|
||||||
|
|
||||||
|
st.autoTimer = setInterval(tick, stepMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopAutoScroll($scroller) {
|
||||||
|
const el = $scroller.get(0);
|
||||||
|
const st = ensureState(el);
|
||||||
|
if (st.autoTimer) {
|
||||||
|
clearInterval(st.autoTimer);
|
||||||
|
st.autoTimer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function maybeStartAutoScroll($scroller) {
|
||||||
|
const el = $scroller.get(0);
|
||||||
|
if (!isEnabled()) { stopAutoScroll($scroller); return; }
|
||||||
|
const st = ensureState(el);
|
||||||
|
if (st.userActive) return;
|
||||||
|
if (st.loopHeight > 0) startAutoScroll($scroller, 1, 80);
|
||||||
|
else stopAutoScroll($scroller);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===========================
|
||||||
|
Smart AJAX Reload
|
||||||
|
=========================== */
|
||||||
|
function smartLoad($scroller, $table, $target, url, intervalMs) {
|
||||||
|
const scEl = $scroller.get(0);
|
||||||
|
const st = ensureState(scEl);
|
||||||
|
|
||||||
|
const oldLoop = st.loopHeight > 0 ? st.loopHeight : Math.max(1, scEl.scrollHeight - scEl.clientHeight);
|
||||||
|
const posInLoop = st.loopHeight > 0 ? (scEl.scrollTop % oldLoop) : scEl.scrollTop;
|
||||||
|
const posRatio = Math.min(1, posInLoop / oldLoop);
|
||||||
|
|
||||||
|
$target.load(url, function () {
|
||||||
|
buildSeamlessLoop($table, $scroller);
|
||||||
|
|
||||||
|
if (st.loopHeight > 0 && isEnabled()) {
|
||||||
|
const newPos = Math.floor(posRatio * st.loopHeight);
|
||||||
|
if (Math.abs(scEl.scrollTop - newPos) > 1) {
|
||||||
|
requestAnimationFrame(() => { scEl.scrollTop = newPos; });
|
||||||
|
}
|
||||||
|
stopAutoScroll($scroller);
|
||||||
|
startAutoScroll($scroller, 1, 80);
|
||||||
|
} else {
|
||||||
|
if (scEl.scrollTop !== 0) requestAnimationFrame(() => { scEl.scrollTop = 0; });
|
||||||
|
stopAutoScroll($scroller);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(() => smartLoad($scroller, $table, $target, url, intervalMs), intervalMs);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===========================
|
||||||
|
Initialisierung
|
||||||
|
=========================== */
|
||||||
|
$(document).ready(function () {
|
||||||
|
sizeScrollContainers();
|
||||||
|
$(window).on('resize', function () {
|
||||||
|
sizeScrollContainers();
|
||||||
|
const $scroller = $('#aufgaben-scroll');
|
||||||
|
const $table = $('#aufgaben-table');
|
||||||
|
buildSeamlessLoop($table, $scroller);
|
||||||
|
maybeStartAutoScroll($scroller);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Guards nur aktivieren, wenn Scrolling erlaubt
|
||||||
|
if (isEnabled()) attachScrollGuards($('#aufgaben-scroll'));
|
||||||
|
|
||||||
|
// Erstladen
|
||||||
|
(function init() {
|
||||||
|
const $scroller = $('#aufgaben-scroll');
|
||||||
|
const $table = $('#aufgaben-table');
|
||||||
|
const $target = $('#AufgabenTableHolder');
|
||||||
|
const url = 'sources/getAufgabenTable.php';
|
||||||
|
const interval = 60000;
|
||||||
|
|
||||||
|
$target.load(url, function () {
|
||||||
|
buildSeamlessLoop($table, $scroller);
|
||||||
|
maybeStartAutoScroll($scroller);
|
||||||
|
setTimeout(() => smartLoad($scroller, $table, $target, url, interval), interval);
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
|
// (Optional – hier nicht benötigt, aber gelassen falls du später etwas anzeigst)
|
||||||
function getTimeFromSeconds(string $timestring) {
|
function getTimeFromSeconds(string $timestring) {
|
||||||
|
$hours = floor($timestring / 3600);
|
||||||
$hours = floor($timestring / 3600);
|
$mins = floor($timestring / 60 % 60);
|
||||||
$mins = floor($timestring / 60 % 60);
|
$timeFormat = sprintf('%02d:%02d', $hours, $mins);
|
||||||
$secs = floor($timestring % 60);
|
return $timeFormat;
|
||||||
|
|
||||||
$timeFormat = sprintf('%02d:%02d', $hours, $mins);
|
|
||||||
|
|
||||||
return $timeFormat;
|
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ public function requestEpiApi(string $requestString){
|
|||||||
$requestUrl = Epirent_Connectionprotocol."://".Epirent_Server.":".Epirent_Port.$requestString;
|
$requestUrl = Epirent_Connectionprotocol."://".Epirent_Server.":".Epirent_Port.$requestString;
|
||||||
$response = $client->request('GET', $requestUrl,[
|
$response = $client->request('GET', $requestUrl,[
|
||||||
'headers' =>[
|
'headers' =>[
|
||||||
'X-EPI-NO-SESSION' => 'True',
|
'X-EPI-NO-SESSION' => 'true',
|
||||||
'X-EPI-ACC-TOK' => Epirent_Token
|
'X-EPI-ACC-TOK' => Epirent_Token
|
||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
require('config.php');
|
require('config.php');
|
||||||
require('EpiApi.php');
|
require('EpiApi.php');
|
||||||
require('vendor/autoload.php');
|
require('vendor/autoload.php');
|
||||||
|
|
||||||
$Epi = new Epirent();
|
$Epi = new Epirent();
|
||||||
|
|
||||||
?>
|
?>
|
||||||
|
|
||||||
|
|
||||||
@@ -21,155 +19,426 @@ $Epi = new Epirent();
|
|||||||
<!-- Bootstrap -->
|
<!-- Bootstrap -->
|
||||||
<link rel="stylesheet" href="vendor/twbs/bootstrap/dist/css/bootstrap.min.css" >
|
<link rel="stylesheet" href="vendor/twbs/bootstrap/dist/css/bootstrap.min.css" >
|
||||||
<script src="scripts/jquery-3.5.1.min.js"></script>
|
<script src="scripts/jquery-3.5.1.min.js"></script>
|
||||||
<link href="css/sticky-footer.css" rel="stylesheet">
|
<link href="css/sticky-footer.css" rel="stylesheet">
|
||||||
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
|
<script src="https://kit.fontawesome.com/93d71de8bc.js" crossorigin="anonymous"></script>
|
||||||
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
|
<style>
|
||||||
<!--[if lt IE 9]>
|
@media (min-width: 1800px) {
|
||||||
<script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
|
.row {
|
||||||
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
|
flex-wrap: nowrap; /* verhindert Umbruch */
|
||||||
<![endif]-->
|
}
|
||||||
|
|
||||||
|
/* Checkout + Checkin: je 45% */
|
||||||
|
.row > .col-sm:nth-child(1),
|
||||||
|
.row > .col-sm:nth-child(2) {
|
||||||
|
flex: 0 0 35%;
|
||||||
|
max-width: 35%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Aufgaben: 10% */
|
||||||
|
.row > .col-sm:nth-child(3) {
|
||||||
|
flex: 0 0 30%;
|
||||||
|
max-width: 30%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.table td, .table th {
|
||||||
|
padding: .25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
// Dynamische Höhe: Wrapper exakt bis Viewport-Unterkante
|
// === PHP-Flags in JS bringen ===
|
||||||
|
const SCROLL_FLAGS = {
|
||||||
|
checkout: <?php echo (defined('EnableScrollingCheckOut') && EnableScrollingCheckOut) ? 'true' : 'false'; ?>,
|
||||||
|
checkin: <?php echo (defined('EnableScrollingCheckIn') && EnableScrollingCheckIn) ? 'true' : 'false'; ?>,
|
||||||
|
aufgaben: <?php echo (defined('EnableScrollingAufgaben') && EnableScrollingAufgaben) ? 'true' : 'false'; ?>
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mapping: DOM-ID -> Flag-Key
|
||||||
|
const SCROLLER_KEYS = new Map([
|
||||||
|
['checkout-scroll', 'checkout'],
|
||||||
|
['checkin-scroll', 'checkin'],
|
||||||
|
['aufgaben-scroll', 'aufgaben']
|
||||||
|
]);
|
||||||
|
const TABLE_KEYS = new Map([
|
||||||
|
['checkout-table', 'checkout'],
|
||||||
|
['checkin-table', 'checkin'],
|
||||||
|
['aufgaben-table', 'aufgaben']
|
||||||
|
]);
|
||||||
|
|
||||||
|
function keyForEl(el, map) {
|
||||||
|
if (!el || !el.id) return null;
|
||||||
|
return map.get(el.id) || null;
|
||||||
|
}
|
||||||
|
function isEnabledByEl(el) {
|
||||||
|
const k = keyForEl(el, SCROLLER_KEYS);
|
||||||
|
return !!(k && SCROLL_FLAGS[k]);
|
||||||
|
}
|
||||||
|
function isEnabledByKey(key) {
|
||||||
|
return !!SCROLL_FLAGS[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
// === Höhe der Scroll-Container: nebeneinander = volle Höhe; gestapelt = Drittel ===
|
||||||
function sizeScrollContainers() {
|
function sizeScrollContainers() {
|
||||||
$('.tableFixHead').each(function () {
|
const nodes = [
|
||||||
const rect = this.getBoundingClientRect();
|
document.querySelector('#checkout-scroll'),
|
||||||
const bottomMargin = 16; // kleiner Abstand zum Rand
|
document.querySelector('#checkin-scroll'),
|
||||||
const available = window.innerHeight - rect.top - bottomMargin;
|
document.querySelector('#aufgaben-scroll')
|
||||||
this.style.maxHeight = (available > 120 ? available : 120) + 'px';
|
].filter(Boolean);
|
||||||
|
|
||||||
|
if (nodes.length === 0) return;
|
||||||
|
|
||||||
|
// Ermitteln, ob alles in einer Zeile (nebeneinander) oder gestapelt
|
||||||
|
const tops = nodes.map(n => n.getBoundingClientRect().top);
|
||||||
|
const ROW_TOL = 8; // px
|
||||||
|
const uniqueRows = [];
|
||||||
|
tops.forEach(t => {
|
||||||
|
const exists = uniqueRows.some(rt => Math.abs(rt - t) <= ROW_TOL);
|
||||||
|
if (!exists) uniqueRows.push(t);
|
||||||
|
});
|
||||||
|
const isOneRow = uniqueRows.length === 1;
|
||||||
|
|
||||||
|
const bottomMargin = 16;
|
||||||
|
const minH = 120;
|
||||||
|
|
||||||
|
nodes.forEach(node => {
|
||||||
|
// Wenn Scrolling für diesen Bereich deaktiviert ist, Höhe trotzdem setzen (wie gefordert)
|
||||||
|
const rect = node.getBoundingClientRect();
|
||||||
|
if (isOneRow) {
|
||||||
|
const available = window.innerHeight - rect.top - bottomMargin;
|
||||||
|
node.style.maxHeight = Math.max(minH, available) + 'px';
|
||||||
|
} else {
|
||||||
|
const third = Math.floor(window.innerHeight / 3) - bottomMargin;
|
||||||
|
node.style.maxHeight = Math.max(minH, third) + 'px';
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lädt tbody via AJAX und erhält die Scrollposition relativ zum unteren Rand
|
// === Scroll-/Interaktionsstatus je Scroller ===
|
||||||
function smartLoad($scroller, $target, url, intervalMs) {
|
const scrollState = new WeakMap(); // { userActive:boolean, autoTimer:number|null, loopHeight:number }
|
||||||
const scroller = $scroller.get(0);
|
|
||||||
// Abstand vom unteren Rand merken (wichtiger als absolute scrollTop)
|
function ensureState(el) {
|
||||||
const fromBottomBefore = scroller.scrollHeight - scroller.clientHeight - scroller.scrollTop;
|
if (!scrollState.get(el)) scrollState.set(el, { userActive: false, autoTimer: null, loopHeight: 0 });
|
||||||
|
return scrollState.get(el);
|
||||||
|
}
|
||||||
|
|
||||||
|
function attachScrollGuards($scroller) {
|
||||||
|
const el = $scroller.get(0);
|
||||||
|
if (!el || el.__guardsBound) return;
|
||||||
|
if (!isEnabledByEl(el)) return; // nur wenn Feature aktiv
|
||||||
|
const state = ensureState(el);
|
||||||
|
|
||||||
|
const markActive = () => {
|
||||||
|
state.userActive = true;
|
||||||
|
clearTimeout(state._quietT);
|
||||||
|
state._quietT = setTimeout(() => { state.userActive = false; }, 800);
|
||||||
|
stopAutoScroll($scroller);
|
||||||
|
};
|
||||||
|
|
||||||
|
$scroller.on('wheel touchstart touchmove keydown mousedown mouseenter', markActive);
|
||||||
|
$scroller.on('mouseleave', () => setTimeout(() => maybeStartAutoScroll($scroller), 600));
|
||||||
|
el.__guardsBound = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// === Loop aufbauen: nahtloses Doppel nur bei Bedarf & nur wenn aktiv ===
|
||||||
|
function buildSeamlessLoop($table, $scroller) {
|
||||||
|
$table.find('tbody.__loopClone').remove();
|
||||||
|
|
||||||
|
const scEl = $scroller.get(0);
|
||||||
|
const enabled = isEnabledByEl(scEl);
|
||||||
|
const st = ensureState(scEl);
|
||||||
|
st.loopHeight = 0;
|
||||||
|
|
||||||
|
if (!enabled) return; // deaktiviert -> keine Loops
|
||||||
|
|
||||||
|
const $main = $table.find('tbody').first();
|
||||||
|
if ($main.length === 0 || $main.children().length === 0) return;
|
||||||
|
|
||||||
|
const needScroll = $main.get(0).offsetHeight > scEl.clientHeight + 1;
|
||||||
|
if (!needScroll) return;
|
||||||
|
|
||||||
|
const $clone = $main.clone(false, false).addClass('__loopClone').attr('aria-hidden', 'true');
|
||||||
|
$table.append($clone);
|
||||||
|
st.loopHeight = $main.get(0).offsetHeight; // Höhe des Original-Inhalts als Loop-Länge
|
||||||
|
}
|
||||||
|
|
||||||
|
// === Auto-Scroll (nahtlos) ===
|
||||||
|
function startAutoScroll($scroller, speedPx = 1, stepMs = 40) {
|
||||||
|
const el = $scroller.get(0);
|
||||||
|
if (!isEnabledByEl(el)) return;
|
||||||
|
|
||||||
|
const st = ensureState(el);
|
||||||
|
if (st.autoTimer) return; // schon aktiv
|
||||||
|
if (st.loopHeight <= 0) return; // kein Overflow => nicht scrollen
|
||||||
|
|
||||||
|
const tick = () => {
|
||||||
|
if (st.userActive) { stopAutoScroll($scroller); return; }
|
||||||
|
el.scrollTop += speedPx;
|
||||||
|
if (el.scrollTop >= st.loopHeight) {
|
||||||
|
el.scrollTop -= st.loopHeight;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
st.autoTimer = setInterval(tick, stepMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopAutoScroll($scroller) {
|
||||||
|
const el = $scroller.get(0);
|
||||||
|
const st = ensureState(el);
|
||||||
|
if (st.autoTimer) {
|
||||||
|
clearInterval(st.autoTimer);
|
||||||
|
st.autoTimer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function maybeStartAutoScroll($scroller) {
|
||||||
|
const el = $scroller.get(0);
|
||||||
|
if (!isEnabledByEl(el)) { stopAutoScroll($scroller); return; }
|
||||||
|
const st = ensureState(el);
|
||||||
|
if (st.userActive) return;
|
||||||
|
if (st.loopHeight > 0) startAutoScroll($scroller, 1, 80);
|
||||||
|
else stopAutoScroll($scroller);
|
||||||
|
}
|
||||||
|
|
||||||
|
// === AJAX-Reload: relative Position innerhalb der Loop erhalten ===
|
||||||
|
function smartLoad($scroller, $table, $target, url, intervalMs) {
|
||||||
|
const scEl = $scroller.get(0);
|
||||||
|
const st = ensureState(scEl);
|
||||||
|
const enabled = isEnabledByEl(scEl);
|
||||||
|
|
||||||
|
const oldLoop = st.loopHeight > 0 ? st.loopHeight : Math.max(1, scEl.scrollHeight - scEl.clientHeight);
|
||||||
|
const posInLoop = st.loopHeight > 0 ? (scEl.scrollTop % oldLoop) : scEl.scrollTop;
|
||||||
|
const posRatio = Math.min(1, posInLoop / oldLoop);
|
||||||
|
|
||||||
$target.load(url, function () {
|
$target.load(url, function () {
|
||||||
// Nach dem Ersetzen: dieselbe Distanz zum unteren Rand wiederherstellen
|
if (enabled) {
|
||||||
const newScrollTop = scroller.scrollHeight - scroller.clientHeight - fromBottomBefore;
|
buildSeamlessLoop($table, $scroller);
|
||||||
// Begrenzen, falls weniger Inhalt
|
if (st.loopHeight > 0) {
|
||||||
scroller.scrollTop = Math.max(0, newScrollTop);
|
const newPos = Math.floor(posRatio * st.loopHeight);
|
||||||
|
if (Math.abs(scEl.scrollTop - newPos) > 1) {
|
||||||
|
requestAnimationFrame(() => { scEl.scrollTop = newPos; });
|
||||||
|
}
|
||||||
|
stopAutoScroll($scroller);
|
||||||
|
startAutoScroll($scroller, 1, 80);
|
||||||
|
} else {
|
||||||
|
if (scEl.scrollTop !== 0) requestAnimationFrame(() => { scEl.scrollTop = 0; });
|
||||||
|
stopAutoScroll($scroller);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$table.find('tbody.__loopClone').remove();
|
||||||
|
stopAutoScroll($scroller);
|
||||||
|
if (scEl.scrollTop !== 0) requestAnimationFrame(() => { scEl.scrollTop = 0; });
|
||||||
|
}
|
||||||
|
|
||||||
// Nächstes Update planen
|
setTimeout(() => smartLoad($scroller, $table, $target, url, intervalMs), intervalMs);
|
||||||
setTimeout(function () {
|
|
||||||
smartLoad($scroller, $target, url, intervalMs);
|
|
||||||
}, intervalMs);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// === Initialisierung ===
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
sizeScrollContainers();
|
sizeScrollContainers();
|
||||||
$(window).on('resize', sizeScrollContainers);
|
|
||||||
|
|
||||||
// Initial laden + Auto-Refresh, jeweils eigener Scroller
|
$(window).on('resize', function () {
|
||||||
smartLoad($('#checkout-scroll'), $('#getCheckOutTableHolder'), 'sources/getCheckOutTable.php', 5000);
|
sizeScrollContainers();
|
||||||
smartLoad($('#checkin-scroll'), $('#getCheckInTableHolder'), 'sources/getCheckInTable.php', 5000);
|
['#checkout', '#checkin', '#aufgaben'].forEach(prefix => {
|
||||||
smartLoad($('#aufgaben-scroll'), $('#AufgabenTableHolder'), 'sources/getAufgabenTable.php', 30000);
|
const $scroller = $(`${prefix}-scroll`);
|
||||||
|
const $table = $(`${prefix}-table`);
|
||||||
|
buildSeamlessLoop($table, $scroller);
|
||||||
|
maybeStartAutoScroll($scroller);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Guards nur für aktivierte Scroller
|
||||||
|
[['#checkout-scroll','checkout'], ['#checkin-scroll','checkin'], ['#aufgaben-scroll','aufgaben']].forEach(([sel,key]) => {
|
||||||
|
if (isEnabledByKey(key)) attachScrollGuards($(sel));
|
||||||
|
});
|
||||||
|
|
||||||
|
// Erstladen je Tabelle
|
||||||
|
function initOne(scrollerSel, tableSel, tbodySel, url, ms, key) {
|
||||||
|
const $scroller = $(scrollerSel);
|
||||||
|
const $table = $(tableSel);
|
||||||
|
const $target = $(tbodySel);
|
||||||
|
const enabled = isEnabledByKey(key);
|
||||||
|
|
||||||
|
$target.load(url, function () {
|
||||||
|
if (enabled) {
|
||||||
|
buildSeamlessLoop($table, $scroller);
|
||||||
|
maybeStartAutoScroll($scroller);
|
||||||
|
} else {
|
||||||
|
$table.find('tbody.__loopClone').remove();
|
||||||
|
stopAutoScroll($scroller);
|
||||||
|
}
|
||||||
|
setTimeout(() => smartLoad($scroller, $table, $target, url, ms), ms);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
initOne('#checkout-scroll', '#checkout-table', '#getCheckOutTableHolder', 'sources/getCheckOutTable.php', 10000, 'checkout');
|
||||||
|
initOne('#checkin-scroll', '#checkin-table', '#getCheckInTableHolder', 'sources/getCheckInTable.php', 10000, 'checkin');
|
||||||
|
initOne('#aufgaben-scroll', '#aufgaben-table', '#AufgabenTableHolder', 'sources/getAufgabenTable.php', 60000, 'aufgaben');
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
/* Scroll-Wrapper je Tabelle */
|
/* Scroll-Wrapper je Tabelle */
|
||||||
.tableFixHead {
|
.tableFixHead {
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
/* Höhe wird per JS dynamisch gesetzt, damit genau bis zum Viewport-Ende gescrollt wird */
|
/* Höhe wird per JS dynamisch gesetzt, damit genau bis zum Viewport-Ende gescrollt wird */
|
||||||
max-height: 60vh; /* Fallback */
|
max-height: 60vh; /* Fallback */
|
||||||
border: 1px solid rgba(255,255,255,.1);
|
border: 1px solid rgba(255,255,255,.1);
|
||||||
border-radius: .25rem;
|
border-radius: .25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sticky Header */
|
/* Sticky Header */
|
||||||
.tableFixHead thead th {
|
.tableFixHead thead th {
|
||||||
position: sticky;
|
position: sticky;
|
||||||
top: 0;
|
top: 0;
|
||||||
z-index: 2; /* über Body-Zellen */
|
z-index: 2; /* über Body-Zellen */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Saubere Hintergrundfarbe für sticky Header (Bootstrap .table-dark) */
|
/* Saubere Hintergrundfarbe für sticky Header (Bootstrap .table-dark) */
|
||||||
.table-dark thead th {
|
.table-dark thead th {
|
||||||
background-color: #212529; /* gleiche Farbe wie .table-dark header */
|
background-color: #212529; /* gleiche Farbe wie .table-dark header */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Optional: dünne Trennlinien */
|
/* Optional: dünne Trennlinien */
|
||||||
.table-dark tbody tr + tr td {
|
.table-dark tbody tr + tr td {
|
||||||
border-top: 1px solid rgba(255,255,255,.08);
|
border-top: 1px solid rgba(255,255,255,.08);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body style="background-color: black;">
|
<body style="margin-bottom:0px; background-color: black;">
|
||||||
|
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm">
|
<div class="col-sm" style="padding: 5px !important;">
|
||||||
<h2 class="text-light">Check-Out</h2>
|
<h2 class="text-light">Check-Out</h2>
|
||||||
<div class="tableFixHead" id="checkout-scroll">
|
<div class="tableFixHead" id="checkout-scroll">
|
||||||
<table class="table table-dark mb-0" id="checkout-table">
|
<table class="table table-dark mb-0" id="checkout-table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="col">#</th>
|
<th scope="col">#</th>
|
||||||
<th scope="col">Kunde</th>
|
<th scope="col">Kunde</th>
|
||||||
<th scope="col">Event</th>
|
<th scope="col">Event</th>
|
||||||
<th scope="col">Dispo-Start<br><i>VB-Start</i></th>
|
|
||||||
<?php
|
<?php
|
||||||
|
if(ShowCheckoutTimeOnCheckout || ShowVorbereitungTimeOnCheckout||ShowPackagingTimeOnCheckout || ShowDeliveryTimeOnCheckout || ShowDispoEndOnCheckin){
|
||||||
if(!HideCheckInTimeOnCheckout){
|
echo '<th scope="col">';
|
||||||
echo "<th scope='col'>Dispo-Ende<br><i>VB-Ende</i></th>";
|
}
|
||||||
}
|
|
||||||
?>
|
if(ShowCheckoutTimeOnCheckout){
|
||||||
<th scope="col">Status</th>
|
echo "Checkout-Start";
|
||||||
</tr>
|
}
|
||||||
</thead>
|
if(ShowVorbereitungTimeOnCheckout){
|
||||||
<tbody id="getCheckOutTableHolder"></tbody>
|
if(ShowCheckoutTimeOnCheckout){echo "<br>";}
|
||||||
</table>
|
echo "VB-Start";
|
||||||
</div>
|
}
|
||||||
</div>
|
if(ShowPackagingTimeOnCheckout){
|
||||||
|
if(ShowCheckoutTimeOnCheckout||ShowVorbereitungTimeOnCheckout){echo "<br>";}
|
||||||
<div class="col-sm">
|
echo "Packen";
|
||||||
<h2 class="text-light">Check-In</h2>
|
}
|
||||||
<div class="tableFixHead" id="checkin-scroll">
|
if(ShowDeliveryTimeOnCheckout){
|
||||||
<table class="table table-dark mb-0" id="checkin-table">
|
if(ShowCheckoutTimeOnCheckout || ShowVorbereitungTimeOnCheckout||ShowPackagingTimeOnCheckout){echo "<br>";}
|
||||||
<thead>
|
echo "Liefern";
|
||||||
<tr>
|
}
|
||||||
<th scope="col">#</th>
|
if(ShowDispoStartOnCheckout){
|
||||||
<th scope="col">Kunde</th>
|
if(ShowCheckoutTimeOnCheckout || ShowVorbereitungTimeOnCheckout||ShowPackagingTimeOnCheckout || ShowDeliveryTimeOnCheckout){echo "<br>";}
|
||||||
<th scope="col">Event</th>
|
echo "Auftrag Start";
|
||||||
<?php
|
}
|
||||||
|
if(ShowCheckoutTimeOnCheckout || ShowVorbereitungTimeOnCheckout||ShowPackagingTimeOnCheckout || ShowDeliveryTimeOnCheckout || ShowDispoStartOnCheckout){
|
||||||
if(!HideCheckOutTimeOnCheckin){
|
echo '</th>';
|
||||||
echo "<th scope='col'>Dispo-Start<br><i>RP-Start</i></th>";
|
}
|
||||||
}
|
|
||||||
?>
|
?>
|
||||||
<th scope="col">Dispo-Ende<br><i>RP-Ende</i></th>
|
<th scope="col">Status</th>
|
||||||
<th scope="col">Status</th>
|
<?php
|
||||||
</tr>
|
if(ShowShippingIcons){
|
||||||
</thead>
|
echo "<th scope='col'>Shipping</th>";
|
||||||
<tbody id="getCheckInTableHolder"></tbody>
|
}
|
||||||
</table>
|
?>
|
||||||
</div>
|
</tr>
|
||||||
</div>
|
</thead>
|
||||||
|
<tbody id="getCheckOutTableHolder"></tbody>
|
||||||
<div class="col-sm">
|
</table>
|
||||||
<h2 class="text-light">Aufgaben</h2>
|
</div>
|
||||||
<div class="tableFixHead" id="aufgaben-scroll">
|
|
||||||
<table class="table table-dark mb-0" id="aufgaben-table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th scope="col">#</th>
|
|
||||||
<th scope="col">Bearbeiter</th>
|
|
||||||
<th scope="col">Aufgabe</th>
|
|
||||||
<th scope="col">Zieldatum</th>
|
|
||||||
<th scope="col">Priorität</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody id="AufgabenTableHolder"></tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="col-sm" style="padding: 5px !important;">
|
||||||
|
<h2 class="text-light">Check-In</h2>
|
||||||
|
<div class="tableFixHead" id="checkin-scroll">
|
||||||
|
<table class="table table-dark mb-0" id="checkin-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col">#</th>
|
||||||
|
<th scope="col">Kunde</th>
|
||||||
|
<th scope="col">Event</th> <?php
|
||||||
|
if(ShowCheckInTimeOnCheckin || ShowNachbereitungTimeOnCheckin ||ShowRePackagingTimeOnCheckin || ShowReDeliveryTimeOnCheckin){
|
||||||
|
echo '<th scope="col">';
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ShowCheckInTimeOnCheckin){
|
||||||
|
echo "CheckIn";
|
||||||
|
}
|
||||||
|
if(ShowNachbereitungTimeOnCheckin){
|
||||||
|
if(ShowCheckInTimeOnCheckin){echo "<br>";}
|
||||||
|
echo "Nachbereitung";
|
||||||
|
}
|
||||||
|
if(ShowRePackagingTimeOnCheckin){
|
||||||
|
if(ShowCheckInTimeOnCheckin||ShowNachbereitungTimeOnCheckin){echo "<br>";}
|
||||||
|
echo "Zurückpacken";
|
||||||
|
}
|
||||||
|
if(ShowReDeliveryTimeOnCheckin){
|
||||||
|
if(ShowCheckInTimeOnCheckin || ShowNachbereitungTimeOnCheckin||ShowRePackagingTimeOnCheckin){echo "<br>";}
|
||||||
|
echo "Rückliefern";
|
||||||
|
}
|
||||||
|
if(ShowDispoEndOnCheckin){
|
||||||
|
if(ShowCheckInTimeOnCheckin || ShowNachbereitungTimeOnCheckin||ShowRePackagingTimeOnCheckin | ShowReDeliveryTimeOnCheckin){echo "<br>";}
|
||||||
|
echo "Auftrag Ende";
|
||||||
|
}
|
||||||
|
if(ShowCheckInTimeOnCheckin || ShowNachbereitungTimeOnCheckin||ShowRePackagingTimeOnCheckin || ShowReDeliveryTimeOnCheckin || ShowDispoEndOnCheckin){
|
||||||
|
echo '</th>';
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<th scope="col">Status</th>
|
||||||
|
<?php
|
||||||
|
if(ShowShippingIcons){
|
||||||
|
echo "<th scope='col'>Shipping</th>";
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="getCheckInTableHolder"></tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-sm" style="padding: 5px !important;">
|
||||||
|
<h2 class="text-light">Aufgaben</h2>
|
||||||
|
<div class="tableFixHead" id="aufgaben-scroll">
|
||||||
|
<table class="table table-dark mb-0" id="aufgaben-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col">#</th>
|
||||||
|
<th scope="col">Bearbeiter</th>
|
||||||
|
<th scope="col">Aufgabe</th>
|
||||||
|
<th scope="col">Ziel</th>
|
||||||
|
<th scope="col">Prio</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="AufgabenTableHolder"></tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -182,7 +451,6 @@ $Epi = new Epirent();
|
|||||||
|
|
||||||
|
|
||||||
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
|
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
|
||||||
<script src="https://code.jquery.com/jquery-1.12.4.min.js" integrity="sha384-nvAa0+6Qg9clwYCGGPpDQLVpLNn0fRaROjHqs13t4Ggj3Ez50XnGQqc/r8MhnRDZ" crossorigin="anonymous"></script>
|
|
||||||
<!-- Include all compiled plugins (below), or include individual files as needed -->
|
<!-- Include all compiled plugins (below), or include individual files as needed -->
|
||||||
<script src="vendor/twbs/bootstrap/dist/js/bootstrap.min.js" integrity="sha384-aJ21OjlMXNL5UyIl/XNwTMqvzeRMZH2w8c5cRVpzpU8Y5bApTppSuUkhZXN0VxHd" crossorigin="anonymous"></script>
|
<script src="vendor/twbs/bootstrap/dist/js/bootstrap.min.js" integrity="sha384-aJ21OjlMXNL5UyIl/XNwTMqvzeRMZH2w8c5cRVpzpU8Y5bApTppSuUkhZXN0VxHd" crossorigin="anonymous"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
503
Packmonitor.php
503
Packmonitor.php
@@ -1,9 +1,4 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
|
||||||
error_reporting(E_ALL);
|
|
||||||
|
|
||||||
|
|
||||||
require('config.php');
|
require('config.php');
|
||||||
require('EpiApi.php');
|
require('EpiApi.php');
|
||||||
require('vendor/autoload.php');
|
require('vendor/autoload.php');
|
||||||
@@ -14,143 +9,391 @@ $Epi = new Epirent();
|
|||||||
|
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
|
<title>Packmonitor</title>
|
||||||
<title>Packmonitor</title>
|
|
||||||
|
|
||||||
<!-- Bootstrap -->
|
<!-- Bootstrap -->
|
||||||
<link rel="stylesheet" href="vendor/twbs/bootstrap/dist/css/bootstrap.min.css" >
|
<link rel="stylesheet" href="vendor/twbs/bootstrap/dist/css/bootstrap.min.css">
|
||||||
<script src="scripts/jquery-3.5.1.min.js"></script>
|
<script src="scripts/jquery-3.5.1.min.js"></script>
|
||||||
<link href="css/sticky-footer.css" rel="stylesheet">
|
<link href="css/sticky-footer.css" rel="stylesheet">
|
||||||
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
|
<script src="https://kit.fontawesome.com/93d71de8bc.js" crossorigin="anonymous"></script>
|
||||||
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
|
|
||||||
<!--[if lt IE 9]>
|
|
||||||
<script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
|
|
||||||
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
|
|
||||||
<![endif]-->
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$(document).ready(function () {
|
/* ===========================
|
||||||
refreshCheckOutTable();
|
Feature-Toggles aus PHP
|
||||||
refreshCheckInTable();
|
=========================== */
|
||||||
});
|
const SCROLL_FLAGS = {
|
||||||
|
checkout: <?php echo (defined('EnableScrollingCheckOut') && EnableScrollingCheckOut) ? 'true' : 'false'; ?>,
|
||||||
|
checkin: <?php echo (defined('EnableScrollingCheckIn') && EnableScrollingCheckIn) ? 'true' : 'false'; ?>
|
||||||
|
};
|
||||||
|
|
||||||
function refreshCheckOutTable() {
|
const SCROLLER_KEYS = new Map([
|
||||||
$('#getCheckOutTableHolder').load('sources/getCheckOutTable.php', function () {
|
['checkout-scroll', 'checkout'],
|
||||||
setTimeout(refreshCheckOutTable, 5000);
|
['checkin-scroll', 'checkin']
|
||||||
});
|
]);
|
||||||
|
|
||||||
|
function keyForEl(el) { return el && el.id ? SCROLLER_KEYS.get(el.id) : null; }
|
||||||
|
function isEnabledByEl(el) { const k = keyForEl(el); return !!(k && SCROLL_FLAGS[k]); }
|
||||||
|
function isEnabledByKey(key) { return !!SCROLL_FLAGS[key]; }
|
||||||
|
|
||||||
|
/* ===========================
|
||||||
|
Höhe der Scroll-Container
|
||||||
|
- 2 nebeneinander: volle Höhe bis Viewport-Ende
|
||||||
|
- gestapelt: je 1/2 Fensterhöhe
|
||||||
|
=========================== */
|
||||||
|
function sizeScrollContainers() {
|
||||||
|
const nodes = [
|
||||||
|
document.querySelector('#checkout-scroll'),
|
||||||
|
document.querySelector('#checkin-scroll')
|
||||||
|
].filter(Boolean);
|
||||||
|
|
||||||
|
if (!nodes.length) return;
|
||||||
|
|
||||||
|
const tops = nodes.map(n => n.getBoundingClientRect().top);
|
||||||
|
const ROW_TOL = 8;
|
||||||
|
const firstTop = tops[0];
|
||||||
|
const isOneRow = tops.every(t => Math.abs(t - firstTop) <= ROW_TOL);
|
||||||
|
|
||||||
|
const bottomMargin = 16;
|
||||||
|
const minH = 120;
|
||||||
|
|
||||||
|
nodes.forEach(node => {
|
||||||
|
const rect = node.getBoundingClientRect();
|
||||||
|
if (isOneRow) {
|
||||||
|
const available = window.innerHeight - rect.top - bottomMargin;
|
||||||
|
node.style.maxHeight = Math.max(minH, available) + 'px';
|
||||||
|
} else {
|
||||||
|
const half = Math.floor(window.innerHeight / 2) - bottomMargin;
|
||||||
|
node.style.maxHeight = Math.max(minH, half) + 'px';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===========================
|
||||||
|
Scroll-/Interaktionsstatus
|
||||||
|
=========================== */
|
||||||
|
const scrollState = new WeakMap(); // { userActive:boolean, autoTimer:number|null, loopHeight:number }
|
||||||
|
|
||||||
|
function ensureState(el) {
|
||||||
|
if (!scrollState.get(el)) scrollState.set(el, { userActive: false, autoTimer: null, loopHeight: 0 });
|
||||||
|
return scrollState.get(el);
|
||||||
|
}
|
||||||
|
|
||||||
|
function attachScrollGuards($scroller) {
|
||||||
|
const el = $scroller.get(0);
|
||||||
|
if (!el || el.__guardsBound) return;
|
||||||
|
if (!isEnabledByEl(el)) return;
|
||||||
|
const state = ensureState(el);
|
||||||
|
|
||||||
|
const markActive = () => {
|
||||||
|
state.userActive = true;
|
||||||
|
clearTimeout(state._quietT);
|
||||||
|
state._quietT = setTimeout(() => { state.userActive = false; }, 800);
|
||||||
|
stopAutoScroll($scroller);
|
||||||
|
};
|
||||||
|
|
||||||
|
$scroller.on('wheel touchstart touchmove keydown mousedown mouseenter', markActive);
|
||||||
|
$scroller.on('mouseleave', () => setTimeout(() => maybeStartAutoScroll($scroller), 600));
|
||||||
|
el.__guardsBound = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===========================
|
||||||
|
Nahtloser Loop (Clone)
|
||||||
|
=========================== */
|
||||||
|
function buildSeamlessLoop($table, $scroller) {
|
||||||
|
$table.find('tbody.__loopClone').remove();
|
||||||
|
|
||||||
|
const scEl = $scroller.get(0);
|
||||||
|
const enabled = isEnabledByEl(scEl);
|
||||||
|
const st = ensureState(scEl);
|
||||||
|
st.loopHeight = 0;
|
||||||
|
|
||||||
|
if (!enabled) return;
|
||||||
|
|
||||||
|
const $main = $table.find('tbody').first();
|
||||||
|
if ($main.length === 0 || $main.children().length === 0) return;
|
||||||
|
|
||||||
|
const needScroll = $main.get(0).offsetHeight > scEl.clientHeight + 1;
|
||||||
|
if (!needScroll) return;
|
||||||
|
|
||||||
|
const $clone = $main.clone(false, false).addClass('__loopClone').attr('aria-hidden', 'true');
|
||||||
|
$table.append($clone);
|
||||||
|
st.loopHeight = $main.get(0).offsetHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===========================
|
||||||
|
Auto-Scroll
|
||||||
|
=========================== */
|
||||||
|
function startAutoScroll($scroller, speedPx = 1, stepMs = 40) {
|
||||||
|
const el = $scroller.get(0);
|
||||||
|
if (!isEnabledByEl(el)) return;
|
||||||
|
|
||||||
|
const st = ensureState(el);
|
||||||
|
if (st.autoTimer) return;
|
||||||
|
if (st.loopHeight <= 0) return;
|
||||||
|
|
||||||
|
const tick = () => {
|
||||||
|
if (st.userActive) { stopAutoScroll($scroller); return; }
|
||||||
|
el.scrollTop += speedPx;
|
||||||
|
if (el.scrollTop >= st.loopHeight) el.scrollTop -= st.loopHeight;
|
||||||
|
};
|
||||||
|
|
||||||
|
st.autoTimer = setInterval(tick, stepMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopAutoScroll($scroller) {
|
||||||
|
const el = $scroller.get(0);
|
||||||
|
const st = ensureState(el);
|
||||||
|
if (st.autoTimer) {
|
||||||
|
clearInterval(st.autoTimer);
|
||||||
|
st.autoTimer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function maybeStartAutoScroll($scroller) {
|
||||||
|
const el = $scroller.get(0);
|
||||||
|
if (!isEnabledByEl(el)) { stopAutoScroll($scroller); return; }
|
||||||
|
const st = ensureState(el);
|
||||||
|
if (st.userActive) return;
|
||||||
|
if (st.loopHeight > 0) startAutoScroll($scroller, 1, 40);
|
||||||
|
else stopAutoScroll($scroller);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===========================
|
||||||
|
Smart AJAX Reload
|
||||||
|
=========================== */
|
||||||
|
function smartLoad($scroller, $table, $target, url, intervalMs) {
|
||||||
|
const scEl = $scroller.get(0);
|
||||||
|
const st = ensureState(scEl);
|
||||||
|
const enabled = isEnabledByEl(scEl);
|
||||||
|
|
||||||
|
const oldLoop = st.loopHeight > 0 ? st.loopHeight : Math.max(1, scEl.scrollHeight - scEl.clientHeight);
|
||||||
|
const posInLoop = st.loopHeight > 0 ? (scEl.scrollTop % oldLoop) : scEl.scrollTop;
|
||||||
|
const posRatio = Math.min(1, posInLoop / oldLoop);
|
||||||
|
|
||||||
|
$target.load(url, function () {
|
||||||
|
if (enabled) {
|
||||||
|
buildSeamlessLoop($table, $scroller);
|
||||||
|
if (st.loopHeight > 0) {
|
||||||
|
const newPos = Math.floor(posRatio * st.loopHeight);
|
||||||
|
if (Math.abs(scEl.scrollTop - newPos) > 1) {
|
||||||
|
requestAnimationFrame(() => { scEl.scrollTop = newPos; });
|
||||||
|
}
|
||||||
|
stopAutoScroll($scroller);
|
||||||
|
startAutoScroll($scroller, 1, 40);
|
||||||
|
} else {
|
||||||
|
if (scEl.scrollTop !== 0) requestAnimationFrame(() => { scEl.scrollTop = 0; });
|
||||||
|
stopAutoScroll($scroller);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$table.find('tbody.__loopClone').remove();
|
||||||
|
stopAutoScroll($scroller);
|
||||||
|
if (scEl.scrollTop !== 0) requestAnimationFrame(() => { scEl.scrollTop = 0; });
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(() => smartLoad($scroller, $table, $target, url, intervalMs), intervalMs);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===========================
|
||||||
|
Initialisierung
|
||||||
|
=========================== */
|
||||||
|
$(document).ready(function () {
|
||||||
|
sizeScrollContainers();
|
||||||
|
|
||||||
|
$(window).on('resize', function () {
|
||||||
|
sizeScrollContainers();
|
||||||
|
['#checkout', '#checkin'].forEach(prefix => {
|
||||||
|
const $scroller = $(`${prefix}-scroll`);
|
||||||
|
const $table = $(`${prefix}-table`);
|
||||||
|
buildSeamlessLoop($table, $scroller);
|
||||||
|
maybeStartAutoScroll($scroller);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Guards nur für aktivierte Scroller
|
||||||
|
[['#checkout-scroll','checkout'], ['#checkin-scroll','checkin']].forEach(([sel,key]) => {
|
||||||
|
if (isEnabledByKey(key)) attachScrollGuards($(sel));
|
||||||
|
});
|
||||||
|
|
||||||
|
// Erstladen je Tabelle
|
||||||
|
function initOne(scrollerSel, tableSel, tbodySel, url, ms, key) {
|
||||||
|
const $scroller = $(scrollerSel);
|
||||||
|
const $table = $(tableSel);
|
||||||
|
const $target = $(tbodySel);
|
||||||
|
const enabled = isEnabledByKey(key);
|
||||||
|
|
||||||
|
$target.load(url, function () {
|
||||||
|
if (enabled) {
|
||||||
|
buildSeamlessLoop($table, $scroller);
|
||||||
|
maybeStartAutoScroll($scroller);
|
||||||
|
} else {
|
||||||
|
$table.find('tbody.__loopClone').remove();
|
||||||
|
stopAutoScroll($scroller);
|
||||||
|
}
|
||||||
|
setTimeout(() => smartLoad($scroller, $table, $target, url, ms), ms);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
initOne('#checkout-scroll', '#checkout-table', '#getCheckOutTableHolder', 'sources/getCheckOutTable.php', 10000, 'checkout');
|
||||||
|
initOne('#checkin-scroll', '#checkin-table', '#getCheckInTableHolder', 'sources/getCheckInTable.php', 10000, 'checkin');
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<style>
|
||||||
|
/* Scroll-Wrapper je Tabelle */
|
||||||
|
.tableFixHead {
|
||||||
|
overflow-y: auto;
|
||||||
|
/* Höhe wird per JS dynamisch gesetzt, damit genau bis zum Viewport-Ende gescrollt wird */
|
||||||
|
max-height: 60vh; /* Fallback */
|
||||||
|
border: 1px solid rgba(255,255,255,.1);
|
||||||
|
border-radius: .25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sticky Header */
|
||||||
|
.tableFixHead thead th {
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
z-index: 2; /* über Body-Zellen */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Saubere Hintergrundfarbe für sticky Header (Bootstrap .table-dark) */
|
||||||
|
.table-dark thead th {
|
||||||
|
background-color: #212529; /* gleiche Farbe wie .table-dark header */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Optional: dünne Trennlinien */
|
||||||
|
.table-dark tbody tr + tr td {
|
||||||
|
border-top: 1px solid rgba(255,255,255,.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
body { background-color: black; margin-bottom: 0; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row">
|
||||||
|
<!-- Check-Out -->
|
||||||
|
<div class="col-xl">
|
||||||
|
<h2 class="text-light">Check-Out</h2>
|
||||||
|
<div class="tableFixHead" id="checkout-scroll">
|
||||||
|
<table class="table table-dark mb-0" id="checkout-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col">#</th>
|
||||||
|
<th scope="col">Kunde</th>
|
||||||
|
<th scope="col">Event</th>
|
||||||
|
<?php
|
||||||
|
if(ShowCheckoutTimeOnCheckout || ShowVorbereitungTimeOnCheckout||ShowPackagingTimeOnCheckout || ShowDeliveryTimeOnCheckout || ShowDispoEndOnCheckin){
|
||||||
|
echo '<th scope="col">';
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ShowCheckoutTimeOnCheckout){
|
||||||
|
echo "Checkout-Start";
|
||||||
}
|
}
|
||||||
function refreshCheckInTable() {
|
if(ShowVorbereitungTimeOnCheckout){
|
||||||
$('#getCheckInTableHolder').load('sources/getCheckInTable.php', function () {
|
if(ShowCheckoutTimeOnCheckout){echo "<br>";}
|
||||||
setTimeout(refreshCheckInTable, 5000);
|
echo "VB-Start";
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
if(ShowPackagingTimeOnCheckout){
|
||||||
|
if(ShowCheckoutTimeOnCheckout||ShowVorbereitungTimeOnCheckout){echo "<br>";}
|
||||||
|
echo "Packen";
|
||||||
|
}
|
||||||
|
if(ShowDeliveryTimeOnCheckout){
|
||||||
|
if(ShowCheckoutTimeOnCheckout || ShowVorbereitungTimeOnCheckout||ShowPackagingTimeOnCheckout){echo "<br>";}
|
||||||
|
echo "Liefern";
|
||||||
|
}
|
||||||
|
if(ShowDispoStartOnCheckout){
|
||||||
|
if(ShowCheckoutTimeOnCheckout || ShowVorbereitungTimeOnCheckout||ShowPackagingTimeOnCheckout || ShowDeliveryTimeOnCheckout){echo "<br>";}
|
||||||
|
echo "Auftrag Start";
|
||||||
|
}
|
||||||
|
if(ShowCheckoutTimeOnCheckout || ShowVorbereitungTimeOnCheckout||ShowPackagingTimeOnCheckout || ShowDeliveryTimeOnCheckout || ShowDispoStartOnCheckout){
|
||||||
|
echo '</th>';
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
<th scope="col">Status</th>
|
||||||
|
<?php
|
||||||
|
if(ShowShippingIcons){
|
||||||
|
echo "<th scope='col'>Shipping</th>";
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="getCheckOutTableHolder"></tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Check-In -->
|
||||||
|
<div class="col-xl">
|
||||||
|
<h2 class="text-light">Check-In</h2>
|
||||||
|
<div class="tableFixHead" id="checkin-scroll">
|
||||||
|
<table class="table table-dark mb-0" id="checkin-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col">#</th>
|
||||||
|
<th scope="col">Kunde</th>
|
||||||
|
<th scope="col">Event</th>
|
||||||
|
<?php
|
||||||
|
if(ShowCheckInTimeOnCheckin || ShowNachbereitungTimeOnCheckin ||ShowRePackagingTimeOnCheckin || ShowReDeliveryTimeOnCheckin){
|
||||||
|
echo '<th scope="col">';
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ShowCheckInTimeOnCheckin){
|
||||||
|
echo "CheckIn";
|
||||||
|
}
|
||||||
|
if(ShowNachbereitungTimeOnCheckin){
|
||||||
|
if(ShowCheckInTimeOnCheckin){echo "<br>";}
|
||||||
|
echo "Nachbereitung";
|
||||||
|
}
|
||||||
|
if(ShowRePackagingTimeOnCheckin){
|
||||||
|
if(ShowCheckInTimeOnCheckin||ShowNachbereitungTimeOnCheckin){echo "<br>";}
|
||||||
|
echo "Zurückpacken";
|
||||||
|
}
|
||||||
|
if(ShowReDeliveryTimeOnCheckin){
|
||||||
|
if(ShowCheckInTimeOnCheckin || ShowNachbereitungTimeOnCheckin||ShowRePackagingTimeOnCheckin){echo "<br>";}
|
||||||
|
echo "Rückliefern";
|
||||||
|
}
|
||||||
|
if(ShowDispoEndOnCheckin){
|
||||||
|
if(ShowCheckInTimeOnCheckin || ShowNachbereitungTimeOnCheckin||ShowRePackagingTimeOnCheckin | ShowReDeliveryTimeOnCheckin){echo "<br>";}
|
||||||
|
echo "Auftrag Ende";
|
||||||
|
}
|
||||||
|
if(ShowCheckInTimeOnCheckin || ShowNachbereitungTimeOnCheckin||ShowRePackagingTimeOnCheckin || ShowReDeliveryTimeOnCheckin || ShowDispoEndOnCheckin){
|
||||||
|
echo '</th>';
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
<th scope="col">Status</th>
|
||||||
|
<?php
|
||||||
|
if(ShowShippingIcons){
|
||||||
|
echo "<th scope='col'>Shipping</th>";
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="getCheckInTableHolder"></tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
</script>
|
|
||||||
|
|
||||||
</head>
|
|
||||||
<body style="background-color: black;">
|
|
||||||
|
|
||||||
<div class="container-fluid">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-lg">
|
|
||||||
<h2 class="text-light">Check-Out
|
|
||||||
<?php
|
|
||||||
if (CheckOut_FutureDays != -1) {
|
|
||||||
echo "in den nächsten " . CheckOut_FutureDays . " Tagen";
|
|
||||||
}
|
|
||||||
?></h2>
|
|
||||||
<table class="table table-dark">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th scope="col">#</th>
|
|
||||||
<th scope="col">Kunde</th>
|
|
||||||
<th scope="col">Event</th>
|
|
||||||
<th scope="col">Dispo-Start<br><i>VB-Start</i></th>
|
|
||||||
<?php
|
|
||||||
|
|
||||||
if(!HideCheckInTimeOnCheckout){
|
|
||||||
echo "<th scope='col'>Dispo-Ende<br><i>VB-Ende</i></th>";
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
<th scope="col">Status</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody id="getCheckOutTableHolder">
|
|
||||||
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class="col-lg">
|
|
||||||
<h2 class="text-light">Check-In
|
|
||||||
<?php
|
|
||||||
if (CheckIn_FutureDays != -1) {
|
|
||||||
echo "in den nächsten " . CheckIn_FutureDays . " Tagen";
|
|
||||||
}
|
|
||||||
?></h2>
|
|
||||||
<table class="table table-dark">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th scope="col">#</th>
|
|
||||||
<th scope="col">Kunde</th>
|
|
||||||
<th scope="col">Event</th>
|
|
||||||
|
|
||||||
<?php
|
|
||||||
|
|
||||||
if(!HideCheckOutTimeOnCheckin){
|
|
||||||
echo "<th scope='col'>Dispo-Start<br><i>RP-Start</i></th>";
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
<th scope="col">Dispo-Ende<br><i>RP-Ende</i></th>
|
|
||||||
<th scope="col">Status</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody id="getCheckInTableHolder">
|
|
||||||
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</header>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<script src="vendor/twbs/bootstrap/dist/js/bootstrap.min.js" crossorigin="anonymous"></script>
|
||||||
|
</body>
|
||||||
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
|
|
||||||
<script src="https://code.jquery.com/jquery-1.12.4.min.js" integrity="sha384-nvAa0+6Qg9clwYCGGPpDQLVpLNn0fRaROjHqs13t4Ggj3Ez50XnGQqc/r8MhnRDZ" crossorigin="anonymous"></script>
|
|
||||||
<!-- Include all compiled plugins (below), or include individual files as needed -->
|
|
||||||
<script src="vendor/twbs/bootstrap/dist/js/bootstrap.min.js" integrity="sha384-aJ21OjlMXNL5UyIl/XNwTMqvzeRMZH2w8c5cRVpzpU8Y5bApTppSuUkhZXN0VxHd" crossorigin="anonymous"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
function getTimeFromSeconds(string $timestring) {
|
function getTimeFromSeconds(string $timestring) {
|
||||||
|
$hours = floor($timestring / 3600);
|
||||||
$hours = floor($timestring / 3600);
|
$mins = floor($timestring / 60 % 60);
|
||||||
$mins = floor($timestring / 60 % 60);
|
return sprintf('%02d:%02d', $hours, $mins);
|
||||||
$secs = floor($timestring % 60);
|
|
||||||
|
|
||||||
$timeFormat = sprintf('%02d:%02d', $hours, $mins);
|
|
||||||
|
|
||||||
return $timeFormat;
|
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|||||||
31
README.MD
31
README.MD
@@ -1,8 +1,8 @@
|
|||||||
# EPIWebview
|
# EPIWebview
|
||||||
|
|
||||||
**aktuellste stable Version:** 1.5.0
|
- **aktuellste stable Version:** 1.9.0
|
||||||
**Lizenz:** Creative Commons Attribution-NonCommercial-ShareAlike 4.0 (CC BY-NC-SA 4.0). Einsehbar unter: (LICENSE.MD)
|
- **Lizenz:** Creative Commons Attribution-NonCommercial-ShareAlike 4.0 (CC BY-NC-SA 4.0). Einsehbar unter: (LICENSE.MD)
|
||||||
**Kompatibilität:** Erweiterung für **Epirent** und **CrewBrain**
|
- **Kompatibilität:** Erweiterung für **Epirent** und **CrewBrain**
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@ Die Anwendung ist speziell für den Einsatz in Lagerprozessen entwickelt.
|
|||||||
|
|
||||||
- **Check-In / Check-Out Übersicht**: Lagermonitor
|
- **Check-In / Check-Out Übersicht**: Lagermonitor
|
||||||
- **Integration mit Epirent API**: Vollständig kompatibel mit bestehenden Epirent-Systemen.
|
- **Integration mit Epirent API**: Vollständig kompatibel mit bestehenden Epirent-Systemen.
|
||||||
- **Integration mit Crewbrain**: Anzeige einer Aufgabenliste aus CrewBrain
|
- **Integration mit Crewbrain**: Anzeige einer Aufgabenliste aus CrewBraingit
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -25,7 +25,8 @@ Die Anwendung ist speziell für den Einsatz in Lagerprozessen entwickelt.
|
|||||||
|
|
||||||
## Systemanforderungen
|
## Systemanforderungen
|
||||||
|
|
||||||
- **Server:** PHP ≥ 8.1, Apache oder Nginx
|
- **Server:** PHP ≥ 8.2, Apache oder Nginx
|
||||||
|
- Achtung !!: Für die Return of Invest Funktion oder den Warengruppencheck / Imagechecks sollten in der php.ini die max_execution_time und die maximale Dateigröße deutlich nach oben korrigiert werden. Die ROI Funktion kann gut und gerne 20 Minuten laden!
|
||||||
- **Client:** Aktueller Browser (Chrome, Edge, Firefox, Safari)
|
- **Client:** Aktueller Browser (Chrome, Edge, Firefox, Safari)
|
||||||
- **Datenquelle:** Bestehende Epirent-Installation mit aktivierter API sowie optional CrewBrain
|
- **Datenquelle:** Bestehende Epirent-Installation mit aktivierter API sowie optional CrewBrain
|
||||||
|
|
||||||
@@ -36,12 +37,20 @@ Die Anwendung ist speziell für den Einsatz in Lagerprozessen entwickelt.
|
|||||||
1. Repository klonen oder Dateien ins Webverzeichnis kopieren:
|
1. Repository klonen oder Dateien ins Webverzeichnis kopieren:
|
||||||
```bash
|
```bash
|
||||||
git clone http://srvgitea01.vtm.zone:3000/epi/EpiWebview
|
git clone http://srvgitea01.vtm.zone:3000/epi/EpiWebview
|
||||||
|
2. Config-Seite unter /dist/editconfig.php aufrufen, notwendige Einstellungen vornehmen -> Speichern. Wichtig! Verzeichnis muss für Webserver beschreibbar sein!
|
||||||
|
3. Alternativ: example.config.php nach config.php kopieren! (example.config.php darf nicht gelöscht werden!)
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Update
|
||||||
|
|
||||||
|
1. Repository klonen oder Dateien ins Webverzeichnis kopieren, dabei alte Dateien löschen (bis auf config.php):
|
||||||
|
```bash
|
||||||
|
git clone http://srvgitea01.vtm.zone:3000/epi/EpiWebview
|
||||||
|
2. Einmalig die Config-Seite aufrufen und speichern drücken. Dadurch werden geupdatete Config-Felder übernommen
|
||||||
|
|
||||||
|
|
||||||
## Changelog
|
## Changelog
|
||||||
### Änderungen in Version 1.5.0
|
Verschoben in Releases (Git)
|
||||||
|
|
||||||
**Neu:**
|
|
||||||
- Die Spalte **„CheckIn“** kann beim **Checkout** ausgeblendet werden.
|
|
||||||
- Die Spalte **„CheckOut“** kann beim **Checkin** ausgeblendet werden.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -2,6 +2,9 @@
|
|||||||
"require": {
|
"require": {
|
||||||
"guzzlehttp/guzzle": "^7.0",
|
"guzzlehttp/guzzle": "^7.0",
|
||||||
"twbs/bootstrap": "^4.5",
|
"twbs/bootstrap": "^4.5",
|
||||||
"chillerlan/php-qrcode": "^5.0"
|
"chillerlan/php-qrcode": "^5.0",
|
||||||
|
"phpoffice/phpspreadsheet": "^5.1",
|
||||||
|
"tecnickcom/tc-lib-pdf": "^8.1",
|
||||||
|
"tecnickcom/tcpdf": "^6.10"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
1419
composer.lock
generated
1419
composer.lock
generated
File diff suppressed because it is too large
Load Diff
1324
dist/ROI.php
vendored
Normal file
1324
dist/ROI.php
vendored
Normal file
File diff suppressed because it is too large
Load Diff
413
dist/editconfig.php
vendored
Normal file
413
dist/editconfig.php
vendored
Normal file
@@ -0,0 +1,413 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Config-Editor für EPI Webview
|
||||||
|
* - Liest ../config.php (falls vorhanden) und ../example.config.php
|
||||||
|
* - Zeigt editierbare Felder für alle Keys aus example.config.php
|
||||||
|
* - Zeigt veraltete (nur in config.php existierende) Keys rot & disabled
|
||||||
|
* - Speichert Werte zurück nach ../config.php
|
||||||
|
*/
|
||||||
|
|
||||||
|
error_reporting(E_ALL);
|
||||||
|
|
||||||
|
// ---- Dateipfade anpassen falls nötig ----
|
||||||
|
$CONFIG_FILE = realpath(__DIR__ . '/../config.php') ?: (__DIR__ . '/../config.php');
|
||||||
|
$EXAMPLE_FILE = realpath(__DIR__ . '/../example.config.php') ?: (__DIR__ . '/../example.config.php');
|
||||||
|
|
||||||
|
// ---- Hilfsfunktionen: Parsing ----
|
||||||
|
function parse_define_file(string $file): array {
|
||||||
|
if (!is_file($file)) return ['defines' => [], 'order' => [], 'ui' => []];
|
||||||
|
|
||||||
|
$lines = file($file, FILE_IGNORE_NEW_LINES);
|
||||||
|
$defines = [];
|
||||||
|
$order = [];
|
||||||
|
$ui = [];
|
||||||
|
|
||||||
|
// BOM entfernen, falls vorhanden
|
||||||
|
if (isset($lines[0])) {
|
||||||
|
$lines[0] = preg_replace('/^\xEF\xBB\xBF/', '', $lines[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Regex
|
||||||
|
$reDefine = '/^\s*define\(\s*([\'"])([^\'"]+)\1\s*,\s*(.+?)\s*\)\s*;\s*(?:(?:\/\/|#)\s*(.*))?$/u';
|
||||||
|
$reSection = '/^\s*\/\/\s*@section\s*:\s*(.+)\s*$/iu';
|
||||||
|
$reHR = '/^\s*\/\/\s*@hr\s*$/iu';
|
||||||
|
$reNote = '/^\s*\/\/\s*@note\s*:\s*(.+)\s*$/iu';
|
||||||
|
|
||||||
|
foreach ($lines as $ln) {
|
||||||
|
// Meta-Kommentare zuerst prüfen (UI-Struktur)
|
||||||
|
if (preg_match($reSection, $ln, $m)) {
|
||||||
|
$ui[] = ['kind' => 'section', 'title' => trim($m[1])];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (preg_match($reHR, $ln)) {
|
||||||
|
$ui[] = ['kind' => 'hr'];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (preg_match($reNote, $ln, $m)) {
|
||||||
|
$ui[] = ['kind' => 'note', 'text' => trim($m[1])];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// define(…) Zeilen
|
||||||
|
if (!preg_match($reDefine, $ln, $m)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$name = $m[2];
|
||||||
|
$rawValueExpr = trim($m[3]);
|
||||||
|
$inlineC = isset($m[4]) ? trim($m[4]) : '';
|
||||||
|
|
||||||
|
// Typ bestimmen
|
||||||
|
$type = 'string';
|
||||||
|
$valForForm = '';
|
||||||
|
$raw = rtrim($rawValueExpr, ',');
|
||||||
|
|
||||||
|
if (preg_match('/^(true|false)$/i', $raw)) {
|
||||||
|
$type = 'bool';
|
||||||
|
$valForForm = (strtolower($raw) === 'true');
|
||||||
|
} elseif (preg_match('/^[+-]?\d+$/', $raw)) {
|
||||||
|
$type = 'int';
|
||||||
|
$valForForm = (int)$raw;
|
||||||
|
} elseif (preg_match('/^([\'"])(.*)\1$/s', $raw, $mm)) {
|
||||||
|
$type = 'string';
|
||||||
|
$valForForm = stripcslashes($mm[2]);
|
||||||
|
} else {
|
||||||
|
$type = 'string';
|
||||||
|
$valForForm = $raw;
|
||||||
|
}
|
||||||
|
|
||||||
|
$defines[$name] = [
|
||||||
|
'name' => $name,
|
||||||
|
'type' => $type,
|
||||||
|
'value' => $valForForm,
|
||||||
|
'raw' => $rawValueExpr,
|
||||||
|
'comment' => $inlineC,
|
||||||
|
'line' => $ln,
|
||||||
|
];
|
||||||
|
$order[] = $name;
|
||||||
|
// Wichtig: define auch in die UI-Reihenfolge aufnehmen
|
||||||
|
$ui[] = ['kind' => 'define', 'name' => $name];
|
||||||
|
}
|
||||||
|
|
||||||
|
return ['defines' => $defines, 'order' => $order, 'ui' => $ui];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function php_export_define_value(string $type, $value): string {
|
||||||
|
// Baut den rechten Teil von define('X', <HIER>);
|
||||||
|
if ($type === 'bool') {
|
||||||
|
return $value ? 'true' : 'false';
|
||||||
|
}
|
||||||
|
if ($type === 'int') {
|
||||||
|
return (string)intval($value);
|
||||||
|
}
|
||||||
|
// String:
|
||||||
|
// einfache Quotes nehmen und escapen
|
||||||
|
$escaped = str_replace("'", "\\'", (string)$value);
|
||||||
|
return "'" . $escaped . "'";
|
||||||
|
}
|
||||||
|
|
||||||
|
function h(?string $s): string { return htmlspecialchars((string)$s ?? '', ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); }
|
||||||
|
|
||||||
|
// ---- Dateien parsen ----
|
||||||
|
$example = parse_define_file($EXAMPLE_FILE);
|
||||||
|
$current = parse_define_file($CONFIG_FILE);
|
||||||
|
|
||||||
|
// Keys klassifizieren
|
||||||
|
$exampleKeys = array_keys($example['defines']);
|
||||||
|
$currentKeys = array_keys($current['defines']);
|
||||||
|
|
||||||
|
$deprecatedKeys = array_values(array_diff($currentKeys, $exampleKeys)); // nur in config.php
|
||||||
|
$newKeys = array_values(array_diff($exampleKeys, $currentKeys)); // nur in example (neu)
|
||||||
|
$sharedKeys = array_values(array_intersect($exampleKeys, $currentKeys));
|
||||||
|
|
||||||
|
// Beim Rendern: Reihenfolge aus example beibehalten
|
||||||
|
$renderKeys = $example['order'];
|
||||||
|
|
||||||
|
// ---- POST: Speichern ----
|
||||||
|
$message = '';
|
||||||
|
$err = '';
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['__save_config']) && isset($_POST['cfg']) && is_array($_POST['cfg'])) {
|
||||||
|
|
||||||
|
$incoming = $_POST['cfg']; // ['NAME' => valueString/checkbox etc.]
|
||||||
|
|
||||||
|
// Build neuer config.php Inhalt:
|
||||||
|
$out = [];
|
||||||
|
$out[] = "<?php";
|
||||||
|
$out[] = "// Diese Datei wurde durch den Epi Webview Config-Editor erzeugt/aktualisiert.";
|
||||||
|
$out[] = "// Bearbeite Werte bevorzugt über die Weboberfläche.";
|
||||||
|
$out[] = "";
|
||||||
|
|
||||||
|
// --- Inhalt in der Reihenfolge & Struktur der example.config.php ---
|
||||||
|
foreach ($example['ui'] as $item) {
|
||||||
|
if ($item['kind'] === 'section') {
|
||||||
|
$out[] = "// @section: " . $item['title'];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ($item['kind'] === 'hr') {
|
||||||
|
$out[] = "// @hr";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ($item['kind'] === 'note') {
|
||||||
|
$out[] = "// @note: " . $item['text'];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ($item['kind'] !== 'define') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$label = $item['name'];
|
||||||
|
$ex = $example['defines'][$label] ?? null;
|
||||||
|
if (!$ex) continue;
|
||||||
|
|
||||||
|
$type = $ex['type']; // Typ an example orientieren
|
||||||
|
$tooltip = $ex['comment'] ?? '';
|
||||||
|
|
||||||
|
// Wert aus POST übernehmen (Checkbox-Fix: existiert das Feld?)
|
||||||
|
if ($type === 'bool') {
|
||||||
|
$bool = array_key_exists($label, $incoming);
|
||||||
|
$valueForDefine = php_export_define_value('bool', $bool);
|
||||||
|
} elseif ($type === 'int') {
|
||||||
|
$raw = $incoming[$label] ?? '';
|
||||||
|
$valueForDefine = php_export_define_value('int', $raw);
|
||||||
|
} else {
|
||||||
|
$raw = $incoming[$label] ?? '';
|
||||||
|
$valueForDefine = php_export_define_value('string', $raw);
|
||||||
|
}
|
||||||
|
|
||||||
|
$line = "define('{$label}', {$valueForDefine});";
|
||||||
|
if (!empty($tooltip)) {
|
||||||
|
$line .= " // " . $tooltip; // Kommentare als Tooltip auch in config.php mitführen
|
||||||
|
}
|
||||||
|
$out[] = $line;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated Block (nur in aktueller config.php vorhanden, nicht in example)
|
||||||
|
if (!empty($deprecatedKeys)) {
|
||||||
|
$out[] = "";
|
||||||
|
$out[] = "// --- Veraltete/entfernte Parameter (nur Referenz, werden nicht mehr genutzt) ---";
|
||||||
|
foreach ($deprecatedKeys as $key) {
|
||||||
|
$c = $current['defines'][$key];
|
||||||
|
$valueForDefine = php_export_define_value($c['type'], $c['value']);
|
||||||
|
$line = "// define('{$c['name']}', {$valueForDefine});";
|
||||||
|
if (!empty($c['comment'])) {
|
||||||
|
$line .= " // " . $c['comment'];
|
||||||
|
}
|
||||||
|
$out[] = $line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$out[] = "?>";
|
||||||
|
$content = implode("\n", $out) . "\n";
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (false === file_put_contents($CONFIG_FILE, $content)) {
|
||||||
|
$err = "Konnte config.php nicht schreiben: " . h($CONFIG_FILE);
|
||||||
|
} else {
|
||||||
|
$message = "Konfiguration gespeichert.";
|
||||||
|
// Nach dem Speichern neu parsen, damit UI aktuell ist
|
||||||
|
$current = parse_define_file($CONFIG_FILE);
|
||||||
|
$currentKeys = array_keys($current['defines']);
|
||||||
|
$deprecatedKeys = array_values(array_diff($currentKeys, $exampleKeys));
|
||||||
|
$sharedKeys = array_values(array_intersect($exampleKeys, $currentKeys));
|
||||||
|
}
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
$err = "Fehler beim Schreiben: " . h($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ---- Werte für Formular vorbereiten ----
|
||||||
|
// Für jeden example-Key: Formularwert = aus aktueller config (falls vorhanden), sonst example default
|
||||||
|
function valueForForm(array $example, array $current, string $key) {
|
||||||
|
$ex = $example['defines'][$key] ?? null;
|
||||||
|
$cu = $current['defines'][$key] ?? null;
|
||||||
|
$type = $ex ? $ex['type'] : ($cu ? $cu['type'] : 'string');
|
||||||
|
$comment = $ex && $ex['comment'] !== '' ? $ex['comment'] : ($cu['comment'] ?? '');
|
||||||
|
|
||||||
|
if ($cu) {
|
||||||
|
$val = $cu['value'];
|
||||||
|
} else {
|
||||||
|
$val = $ex['value'];
|
||||||
|
}
|
||||||
|
return [$type, $val, $comment];
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="de">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
|
||||||
|
<meta name="description" content="Konfiguration bearbeiten" />
|
||||||
|
<meta name="author" content="" />
|
||||||
|
<title>Konfiguration – Epi Webview</title>
|
||||||
|
|
||||||
|
<link href="css/styles.css" rel="stylesheet" />
|
||||||
|
<link href="https://cdn.datatables.net/1.10.20/css/dataTables.bootstrap4.min.css" rel="stylesheet" crossorigin="anonymous" />
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/js/all.min.js" crossorigin="anonymous"></script>
|
||||||
|
<script src="js/jquery-3.5.1.min.js"></script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.deprecated { color: #c62828; }
|
||||||
|
.cfg-help { margin-left: .35rem; cursor: help; }
|
||||||
|
.form-group { margin-bottom: .75rem; }
|
||||||
|
.small-muted { font-size:.85rem; color:#6c757d; }
|
||||||
|
.checkbox-inline { display:flex; align-items:center; gap:.5rem; }
|
||||||
|
.cfg-label { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; }
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$(function(){
|
||||||
|
// Tooltips (Bootstrap 4)
|
||||||
|
$('[data-toggle="tooltip"]').tooltip();
|
||||||
|
|
||||||
|
// Side UI nachladen wie in deinem Template
|
||||||
|
loadSidenav();
|
||||||
|
loadFooter();
|
||||||
|
});
|
||||||
|
function loadSidenav(){
|
||||||
|
$('#layoutSidenav_nav').load('../sources/getSidenav.php');
|
||||||
|
}
|
||||||
|
function loadFooter(){
|
||||||
|
$('#footerholder').load('../sources/getFooter.php');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body class="sb-nav-fixed">
|
||||||
|
<nav class="sb-topnav navbar navbar-expand navbar-dark bg-dark">
|
||||||
|
<a class="navbar-brand" href="index.php">Epi Webview</a>
|
||||||
|
<button class="btn btn-link btn-sm order-1 order-lg-0" id="sidebarToggle" type="button"><i class="fas fa-bars"></i></button>
|
||||||
|
<ul class="navbar-nav ml-auto ml-md-0"></ul>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div id="layoutSidenav">
|
||||||
|
<div id="layoutSidenav_nav"></div>
|
||||||
|
<div id="layoutSidenav_content">
|
||||||
|
<main>
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h1 class="mt-4">Konfiguration</h1>
|
||||||
|
<ol class="breadcrumb mb-4">
|
||||||
|
<li class="breadcrumb-item active">Dashboard / Konfiguration</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<?php if ($message): ?>
|
||||||
|
<div class="alert alert-success"><?= h($message) ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php if ($err): ?>
|
||||||
|
<div class="alert alert-danger"><?= h($err) ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<div class="card mb-4">
|
||||||
|
<div class="card-header">
|
||||||
|
<i class="fas fa-sliders-h mr-1"></i>
|
||||||
|
Einstellungen
|
||||||
|
<span class="small-muted">( <code><?=h(basename($CONFIG_FILE))?></code> Source: <code><?=h(basename($EXAMPLE_FILE))?></code>)</span>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<form method="post">
|
||||||
|
<input type="hidden" name="__save_config" value="1" />
|
||||||
|
|
||||||
|
<?php foreach ($example['ui'] as $item): ?>
|
||||||
|
<?php
|
||||||
|
if ($item['kind'] === 'section') {
|
||||||
|
echo '<h5 class="mt-3">'.h($item['title']).'</h5>';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ($item['kind'] === 'hr') {
|
||||||
|
echo '<hr />';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ($item['kind'] === 'note') {
|
||||||
|
echo '<p class="small-muted">'.h($item['text']).'</p>';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ($item['kind'] !== 'define') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$key = $item['name'];
|
||||||
|
// Nur Keys rendern, die in example vorkommen
|
||||||
|
if (!isset($example['defines'][$key])) continue;
|
||||||
|
|
||||||
|
[$type, $val, $tooltip] = valueForForm($example, $current, $key);
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="cfg-label" for="cfg_<?=h($key)?>">
|
||||||
|
<?= h($key) ?>
|
||||||
|
<?php if ($tooltip): ?>
|
||||||
|
<i class="far fa-question-circle cfg-help"
|
||||||
|
data-toggle="tooltip" data-placement="right"
|
||||||
|
title="<?=h($tooltip)?>"></i>
|
||||||
|
<?php endif; ?>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<?php if ($type === 'bool'): ?>
|
||||||
|
<div class="checkbox-inline">
|
||||||
|
<input type="checkbox"
|
||||||
|
id="cfg_<?=h($key)?>"
|
||||||
|
name="cfg[<?=h($key)?>]"
|
||||||
|
value="1" <?= $val ? 'checked' : '' ?> />
|
||||||
|
<span><?= $val ? 'Aktiviert' : 'Deaktiviert' ?></span>
|
||||||
|
</div>
|
||||||
|
<?php elseif ($type === 'int'): ?>
|
||||||
|
<input type="number" step="1" class="form-control"
|
||||||
|
id="cfg_<?=h($key)?>"
|
||||||
|
name="cfg[<?=h($key)?>]"
|
||||||
|
value="<?=h((string)$val)?>" />
|
||||||
|
<?php else: ?>
|
||||||
|
<input type="text" class="form-control"
|
||||||
|
id="cfg_<?=h($key)?>"
|
||||||
|
name="cfg[<?=h($key)?>]"
|
||||||
|
value="<?=h((string)$val)?>" />
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php endforeach; ?>
|
||||||
|
|
||||||
|
<?php if (!empty($deprecatedKeys)): ?>
|
||||||
|
<hr />
|
||||||
|
<h5 class="deprecated">Veraltete Parameter (nur in <code><?=h(basename($CONFIG_FILE))?></code>, nicht mehr in <code><?=h(basename($EXAMPLE_FILE))?></code>)</h5>
|
||||||
|
<?php foreach ($deprecatedKeys as $key): ?>
|
||||||
|
<?php $c = $current['defines'][$key]; ?>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="cfg-label deprecated" for="dep_<?=h($key)?>">
|
||||||
|
<?= h($key) ?>
|
||||||
|
<?php if (!empty($c['comment'])): ?>
|
||||||
|
<i class="far fa-question-circle cfg-help" data-toggle="tooltip" data-placement="right" title="<?=h($c['comment'])?>"></i>
|
||||||
|
<?php endif; ?>
|
||||||
|
</label>
|
||||||
|
<input type="text" class="form-control is-invalid" id="dep_<?=h($key)?>" value="<?=
|
||||||
|
h($c['type']==='bool' ? ($c['value']?'true':'false') : (string)$c['value'])
|
||||||
|
?>" disabled />
|
||||||
|
<div class="invalid-feedback">Dieser Parameter ist in der aktuellen Version nicht mehr vorgesehen.</div>
|
||||||
|
</div>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<div class="mt-4">
|
||||||
|
<button type="submit" class="btn btn-primary"><i class="fas fa-save mr-1"></i> Speichern</button>
|
||||||
|
<span class="small-muted ml-2">Speichert nach <code><?=h($CONFIG_FILE)?></code></span>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
<div id="footerholder"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.bundle.min.js" crossorigin="anonymous"></script>
|
||||||
|
<script src="js/scripts.js"></script>
|
||||||
|
<script>
|
||||||
|
// Sidebar Toggle (falls benötigt)
|
||||||
|
$('#sidebarToggle').on('click', function(){ $('body').toggleClass('sb-sidenav-toggled'); });
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
128
dist/groupofgoodscheck.php
vendored
Normal file
128
dist/groupofgoodscheck.php
vendored
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require('../config.php');
|
||||||
|
require('../EpiApi.php');
|
||||||
|
require_once __DIR__ . '/../vendor/autoload.php';
|
||||||
|
date_default_timezone_set('Europe/Berlin');
|
||||||
|
|
||||||
|
$Epi = new Epirent();
|
||||||
|
$productList = json_decode($Epi->requestEpiApi('/v1/product/all?ia=true&ir=true&cl=' . Epirent_Mandant))->payload;
|
||||||
|
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="de">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
|
||||||
|
<title>Imagecheck - EpiWebview</title>
|
||||||
|
|
||||||
|
<!-- Styles -->
|
||||||
|
<link href="css/styles.css" rel="stylesheet" />
|
||||||
|
<link href="https://cdn.datatables.net/1.10.20/css/dataTables.bootstrap4.min.css" rel="stylesheet" crossorigin="anonymous" />
|
||||||
|
|
||||||
|
<!-- JS -->
|
||||||
|
<script src="js/jquery-3.5.1.min.js"></script>
|
||||||
|
<script src="https://kit.fontawesome.com/93d71de8bc.js" crossorigin="anonymous"></script>
|
||||||
|
<script src="https://cdn.datatables.net/1.10.20/js/jquery.dataTables.min.js"></script>
|
||||||
|
<script src="https://cdn.datatables.net/1.10.20/js/dataTables.bootstrap4.min.js"></script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.opacity-50 {
|
||||||
|
opacity: .5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card .h2,
|
||||||
|
.card .display-4 {
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kpi-updated {
|
||||||
|
font-size: .82rem;
|
||||||
|
opacity: .85;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$(function() {
|
||||||
|
$('#layoutSidenav_nav').load('../sources/getSidenav.php');
|
||||||
|
$('#footerholder').load('../sources/getFooter.php');
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body class="sb-nav-fixed">
|
||||||
|
<nav class="sb-topnav navbar navbar-expand navbar-dark bg-dark">
|
||||||
|
<a class="navbar-brand" href="index.php">Epi Webview</a>
|
||||||
|
<button class="btn btn-link btn-sm order-1 order-lg-0" id="sidebarToggle"><i class="fas fa-bars"></i></button>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div id="layoutSidenav">
|
||||||
|
<div id="layoutSidenav_nav"></div>
|
||||||
|
<div id="layoutSidenav_content">
|
||||||
|
<main>
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h1 class="mt-4">Warengruppenprüfung</h1>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="card mb-4">
|
||||||
|
<div class="card-header d-flex justify-content-between align-items-center">
|
||||||
|
<div><i class="fas fa-table mr-1"></i> Zeigt welche Artikel keine Warengruppe haben</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table id="dataTable" class="table table-bordered" width="100%" cellspacing="0">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>#</th>
|
||||||
|
<th>PN</th>
|
||||||
|
<th>Name</th>
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php
|
||||||
|
foreach ($productList as $product) {
|
||||||
|
|
||||||
|
if( count($product->group_of_goods) == 0 || $product->group_of_goods ==null){
|
||||||
|
|
||||||
|
echo "<tr>";
|
||||||
|
echo "<td>" . htmlspecialchars($product->primary_key) . "</td>";
|
||||||
|
echo "<td>" . htmlspecialchars($product->product_no) . "</td>";
|
||||||
|
echo "<td>" . htmlspecialchars($product->name) . "</td>";
|
||||||
|
echo "</tr>";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
<div id="footerholder"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Bootstrap Bundle -->
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.bundle.min.js" crossorigin="anonymous"></script>
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
$('#dataTable').DataTable({
|
||||||
|
"pageLength": 25,
|
||||||
|
"language": {
|
||||||
|
"url": "//cdn.datatables.net/plug-ins/1.10.20/i18n/German.json"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
128
dist/imagecheck.php
vendored
Normal file
128
dist/imagecheck.php
vendored
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require('../config.php');
|
||||||
|
require('../EpiApi.php');
|
||||||
|
require_once __DIR__ . '/../vendor/autoload.php';
|
||||||
|
date_default_timezone_set('Europe/Berlin');
|
||||||
|
|
||||||
|
$Epi = new Epirent();
|
||||||
|
$productList = json_decode($Epi->requestEpiApi('/v1/product/all?ia=true&ir=true&cl=' . Epirent_Mandant))->payload;
|
||||||
|
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="de">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
|
||||||
|
<title>Imagecheck - EpiWebview</title>
|
||||||
|
|
||||||
|
<!-- Styles -->
|
||||||
|
<link href="css/styles.css" rel="stylesheet" />
|
||||||
|
<link href="https://cdn.datatables.net/1.10.20/css/dataTables.bootstrap4.min.css" rel="stylesheet" crossorigin="anonymous" />
|
||||||
|
|
||||||
|
<!-- JS -->
|
||||||
|
<script src="js/jquery-3.5.1.min.js"></script>
|
||||||
|
<script src="https://kit.fontawesome.com/93d71de8bc.js" crossorigin="anonymous"></script>
|
||||||
|
<script src="https://cdn.datatables.net/1.10.20/js/jquery.dataTables.min.js"></script>
|
||||||
|
<script src="https://cdn.datatables.net/1.10.20/js/dataTables.bootstrap4.min.js"></script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.opacity-50 {
|
||||||
|
opacity: .5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card .h2,
|
||||||
|
.card .display-4 {
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kpi-updated {
|
||||||
|
font-size: .82rem;
|
||||||
|
opacity: .85;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$(function() {
|
||||||
|
$('#layoutSidenav_nav').load('../sources/getSidenav.php');
|
||||||
|
$('#footerholder').load('../sources/getFooter.php');
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body class="sb-nav-fixed">
|
||||||
|
<nav class="sb-topnav navbar navbar-expand navbar-dark bg-dark">
|
||||||
|
<a class="navbar-brand" href="index.php">Epi Webview</a>
|
||||||
|
<button class="btn btn-link btn-sm order-1 order-lg-0" id="sidebarToggle"><i class="fas fa-bars"></i></button>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div id="layoutSidenav">
|
||||||
|
<div id="layoutSidenav_nav"></div>
|
||||||
|
<div id="layoutSidenav_content">
|
||||||
|
<main>
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h1 class="mt-4">Imagecheck</h1>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="card mb-4">
|
||||||
|
<div class="card-header d-flex justify-content-between align-items-center">
|
||||||
|
<div><i class="fas fa-table mr-1"></i> Zeigt welche Artikel keine Bilder haben</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table id="dataTable" class="table table-bordered" width="100%" cellspacing="0">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>#</th>
|
||||||
|
<th>PN</th>
|
||||||
|
<th>Name</th>
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php
|
||||||
|
foreach ($productList as $product) {
|
||||||
|
$hasImages=(json_decode($Epi->requestEpiApi('/v1/product/image/'.$product->primary_key.'?cl=' . Epirent_Mandant))->payload_length);
|
||||||
|
if( $hasImages == 0 || $hasImages ==null){
|
||||||
|
|
||||||
|
echo "<tr>";
|
||||||
|
echo "<td>" . htmlspecialchars($product->primary_key) . "</td>";
|
||||||
|
echo "<td>" . htmlspecialchars($product->product_no) . "</td>";
|
||||||
|
echo "<td>" . htmlspecialchars($product->name) . "</td>";
|
||||||
|
echo "</tr>";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
<div id="footerholder"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Bootstrap Bundle -->
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.bundle.min.js" crossorigin="anonymous"></script>
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
$('#dataTable').DataTable({
|
||||||
|
"pageLength": 25,
|
||||||
|
"language": {
|
||||||
|
"url": "//cdn.datatables.net/plug-ins/1.10.20/i18n/German.json"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
209
dist/index.php
vendored
209
dist/index.php
vendored
@@ -1,141 +1,78 @@
|
|||||||
|
<?php
|
||||||
|
// index.php – Dashboard Startseite (lädt Teil-HTMLs wie die Auftragsliste, ohne Auto-Refresh)
|
||||||
|
require('../config.php');
|
||||||
|
require('../EpiApi.php');
|
||||||
|
?>
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="de">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
|
||||||
<meta name="description" content="" />
|
<title>Dashboard - EpiWebview</title>
|
||||||
<meta name="author" content="" />
|
|
||||||
<title>Dashboard - EpiWebview</title>
|
<!-- Styles -->
|
||||||
<link href="css/styles.css" rel="stylesheet" />
|
<link href="css/styles.css" rel="stylesheet" />
|
||||||
<link href="https://cdn.datatables.net/1.10.20/css/dataTables.bootstrap4.min.css" rel="stylesheet" crossorigin="anonymous" />
|
<link href="https://cdn.datatables.net/1.10.20/css/dataTables.bootstrap4.min.css" rel="stylesheet" crossorigin="anonymous" />
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/js/all.min.js" crossorigin="anonymous"></script>
|
|
||||||
<script src="js/jquery-3.5.1.min.js"></script>
|
<!-- JS (nur 1x jQuery laden) -->
|
||||||
<script type="text/javascript">
|
<script src="js/jquery-3.5.1.min.js"></script>
|
||||||
|
<script src="https://kit.fontawesome.com/93d71de8bc.js" crossorigin="anonymous"></script>
|
||||||
|
|
||||||
$(document).ready(function(){
|
<style>
|
||||||
refreshOrderTable();
|
.opacity-50 { opacity: .5; }
|
||||||
loadSidenav();
|
.card .h2, .card .display-4 { font-weight: 700; }
|
||||||
loadFooter();
|
.kpi-updated { font-size: .82rem; opacity: .85; }
|
||||||
});
|
</style>
|
||||||
function refreshOrderTable(){
|
|
||||||
$('#OrderTableHolder').load('../sources/getOrders.php', function(){
|
<script>
|
||||||
setTimeout(refreshOrderTable, 5000);
|
// Einmalige Loads – analog zur Auftragsliste
|
||||||
});
|
$(function () {
|
||||||
}
|
loadSidenav();
|
||||||
function loadSidenav(){
|
loadFooter();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
function loadSidenav() {
|
||||||
$('#layoutSidenav_nav').load('../sources/getSidenav.php');
|
$('#layoutSidenav_nav').load('../sources/getSidenav.php');
|
||||||
}
|
}
|
||||||
function loadFooter(){
|
|
||||||
|
function loadFooter() {
|
||||||
$('#footerholder').load('../sources/getFooter.php');
|
$('#footerholder').load('../sources/getFooter.php');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
</script>
|
</head>
|
||||||
</head>
|
|
||||||
<body class="sb-nav-fixed">
|
<body class="sb-nav-fixed">
|
||||||
<nav class="sb-topnav navbar navbar-expand navbar-dark bg-dark">
|
<nav class="sb-topnav navbar navbar-expand navbar-dark bg-dark">
|
||||||
<a class="navbar-brand" href="index.php">Epi Webview</a>
|
<a class="navbar-brand" href="index.php">Epi Webview</a>
|
||||||
<button class="btn btn-link btn-sm order-1 order-lg-0" id="sidebarToggle" href="#"><i class="fas fa-bars"></i></button>
|
<button class="btn btn-link btn-sm order-1 order-lg-0" id="sidebarToggle"><i class="fas fa-bars"></i></button>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div id="layoutSidenav">
|
||||||
|
<div id="layoutSidenav_nav"></div>
|
||||||
|
<div id="layoutSidenav_content">
|
||||||
|
<main>
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h1 class="mt-4">Dashboard</h1>
|
||||||
|
<ol class="breadcrumb mb-4">
|
||||||
|
<li class="breadcrumb-item active">Dashboard</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</nav>
|
|
||||||
<div id="layoutSidenav">
|
|
||||||
<div id="layoutSidenav_nav">
|
</div>
|
||||||
</nav>
|
</main>
|
||||||
</div>
|
<div id="footerholder"></div>
|
||||||
<div id="layoutSidenav_content">
|
</div>
|
||||||
<main>
|
</div>
|
||||||
<div class="container-fluid">
|
|
||||||
<h1 class="mt-4">Dashboard</h1>
|
<!-- Bootstrap Bundle (Popper inkl.) -->
|
||||||
<ol class="breadcrumb mb-4">
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.bundle.min.js" crossorigin="anonymous"></script>
|
||||||
<li class="breadcrumb-item active">Dashboard</li>
|
</body>
|
||||||
</ol>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-xl-3 col-md-6">
|
|
||||||
<div class="card bg-primary text-white mb-4">
|
|
||||||
<div class="card-body">Primary Card</div>
|
|
||||||
<div class="card-footer d-flex align-items-center justify-content-between">
|
|
||||||
<a class="small text-white stretched-link" href="#">View Details</a>
|
|
||||||
<div class="small text-white"><i class="fas fa-angle-right"></i></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-xl-3 col-md-6">
|
|
||||||
<div class="card bg-warning text-white mb-4">
|
|
||||||
<div class="card-body">Warning Card</div>
|
|
||||||
<div class="card-footer d-flex align-items-center justify-content-between">
|
|
||||||
<a class="small text-white stretched-link" href="#">View Details</a>
|
|
||||||
<div class="small text-white"><i class="fas fa-angle-right"></i></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-xl-3 col-md-6">
|
|
||||||
<div class="card bg-success text-white mb-4">
|
|
||||||
<div class="card-body">Success Card</div>
|
|
||||||
<div class="card-footer d-flex align-items-center justify-content-between">
|
|
||||||
<a class="small text-white stretched-link" href="#">View Details</a>
|
|
||||||
<div class="small text-white"><i class="fas fa-angle-right"></i></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-xl-3 col-md-6">
|
|
||||||
<div class="card bg-danger text-white mb-4">
|
|
||||||
<div class="card-body">Danger Card</div>
|
|
||||||
<div class="card-footer d-flex align-items-center justify-content-between">
|
|
||||||
<a class="small text-white stretched-link" href="#">View Details</a>
|
|
||||||
<div class="small text-white"><i class="fas fa-angle-right"></i></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-xl-6">
|
|
||||||
<div class="card mb-4">
|
|
||||||
<div class="card-header">
|
|
||||||
<i class="fas fa-chart-area mr-1"></i>
|
|
||||||
Area Chart Example
|
|
||||||
</div>
|
|
||||||
<div class="card-body"><canvas id="myAreaChart" width="100%" height="40"></canvas></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-xl-6">
|
|
||||||
<div class="card mb-4">
|
|
||||||
<div class="card-header">
|
|
||||||
<i class="fas fa-chart-bar mr-1"></i>
|
|
||||||
Bar Chart Example
|
|
||||||
</div>
|
|
||||||
<div class="card-body"><canvas id="myBarChart" width="100%" height="40"></canvas></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="card mb-4">
|
|
||||||
<div class="card-header">
|
|
||||||
<i class="fas fa-table mr-1"></i>
|
|
||||||
Aufträge
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="table-responsive" id="OrderTableHolder">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
<div id="footerholder"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<script src="js/jquery-3.5.1.min.js"></script>
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.bundle.min.js" crossorigin="anonymous"></script>
|
|
||||||
<script src="js/scripts.js"></script>
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.min.js" crossorigin="anonymous"></script>
|
|
||||||
<script src="assets/demo/chart-area-demo.js"></script>
|
|
||||||
<script src="assets/demo/chart-bar-demo.js"></script>
|
|
||||||
<script src="https://cdn.datatables.net/1.10.20/js/jquery.dataTables.min.js" crossorigin="anonymous"></script>
|
|
||||||
<script src="https://cdn.datatables.net/1.10.20/js/dataTables.bootstrap4.min.js" crossorigin="anonymous"></script>
|
|
||||||
<script src="assets/demo/datatables-demo.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
378
dist/insurance.php
vendored
Normal file
378
dist/insurance.php
vendored
Normal file
@@ -0,0 +1,378 @@
|
|||||||
|
<?php
|
||||||
|
// insurance.php – Versicherungsgeräte (liegt in /dist)
|
||||||
|
require('../config.php');
|
||||||
|
require('../EpiApi.php');
|
||||||
|
require_once __DIR__ . '/../vendor/autoload.php'; // PhpSpreadsheet Autoload
|
||||||
|
date_default_timezone_set('Europe/Berlin');
|
||||||
|
|
||||||
|
$Epi = new Epirent();
|
||||||
|
|
||||||
|
function formatEuro(float $amount): string {
|
||||||
|
$formatted = number_format(abs($amount), 2, ',', '.') . ' €';
|
||||||
|
return $amount < 0 ? '-' . $formatted : $formatted;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* =========================
|
||||||
|
Excel-Export: Konfiguration
|
||||||
|
========================= */
|
||||||
|
$EXCEL_CUSTOM_HEADER = [
|
||||||
|
['EpiWebview – Versicherungsgeräte'],
|
||||||
|
['Exportdatum: ' . date('d.m.Y H:i') . ' | Mandant: ' . (defined('Epirent_Mandant') ? Epirent_Mandant : '')]
|
||||||
|
];
|
||||||
|
$EXCEL_COLS = ['#','Name','Warengruppe(n)','Versicherung netto','Seriennummer','Anschaffung','Kaufpreis','Besitzer'];
|
||||||
|
|
||||||
|
/* =========================
|
||||||
|
1) Daten einmalig holen & Zeilen bauen
|
||||||
|
========================= */
|
||||||
|
$result = $Epi->requestEpiApi('/v1/product/all?ia=true&ir=true&cl=' . Epirent_Mandant);
|
||||||
|
$productList = json_decode($result)->payload;
|
||||||
|
|
||||||
|
$filteredProductArray = [];
|
||||||
|
foreach ($productList as $product) {
|
||||||
|
if ($product->is_stock_control && $product->is_stock_single_entry && !$product->is_virtual) {
|
||||||
|
if (!empty($product->stock_data[0]->stock_rent) && $product->stock_data[0]->stock_rent > 0) {
|
||||||
|
$filteredProductArray[] = $product;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$rows = [];
|
||||||
|
foreach ($filteredProductArray as $filteredProduct) {
|
||||||
|
$detailRes = $Epi->requestEpiApi('/v1/product/' . $filteredProduct->primary_key . '?cl=' . Epirent_Mandant);
|
||||||
|
$insuredProduct = json_decode($detailRes)->payload[0] ?? null;
|
||||||
|
|
||||||
|
if (!$insuredProduct || empty($insuredProduct->pricing) || !isset($insuredProduct->pricing->insurance_net)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ((float)$insuredProduct->pricing->insurance_net == 0.0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Materials
|
||||||
|
$MaterialList = "";
|
||||||
|
if (!empty($insuredProduct->materials)) {
|
||||||
|
foreach ($insuredProduct->materials as $material) {
|
||||||
|
if ($MaterialList !== "") $MaterialList .= ", ";
|
||||||
|
if (!empty($material->is_free_material) && $material->is_free_material) {
|
||||||
|
$MaterialList .= $material->name;
|
||||||
|
} else {
|
||||||
|
$materialResult = $Epi->requestEpiApi('/v1/product/' . $material->mat_product_pk . '?cl=' . Epirent_Mandant);
|
||||||
|
$materialProductObject = json_decode($materialResult)->payload[0] ?? null;
|
||||||
|
$MaterialList .= $materialProductObject ? $materialProductObject->name : '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warengruppen
|
||||||
|
$groupOfGoodsList = "";
|
||||||
|
if (!empty($insuredProduct->group_of_goods)) {
|
||||||
|
foreach ($insuredProduct->group_of_goods as $groupOfGoods) {
|
||||||
|
if ($groupOfGoodsList !== "") $groupOfGoodsList .= ", ";
|
||||||
|
$groupOfGoodsList .= str_replace(";", "->", $groupOfGoods->sequence_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Geräte (Stocks) nur einmal je Produkt
|
||||||
|
$stockRes = $Epi->requestEpiApi('/v1/stock/filter?ppk=' . $insuredProduct->primary_key . '&cl=' . Epirent_Mandant);
|
||||||
|
$deviceStockObjectArray = json_decode($stockRes)->payload ?? [];
|
||||||
|
|
||||||
|
//Sortiere alle Geräte aus die "Nicht Versichert" im Status stehen haben
|
||||||
|
foreach ($deviceStockObjectArray as $device) {
|
||||||
|
if($device->condition=="Nicht Versichert"){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
//Sortiere jetzt die Geräte aus, die Nicht aussortiert wurden
|
||||||
|
if(!$device->is_sorted_out){
|
||||||
|
$rows[] = [
|
||||||
|
'pk' => $insuredProduct->product_no,
|
||||||
|
'name' => $insuredProduct->name,
|
||||||
|
'materials' => $MaterialList,
|
||||||
|
'groups' => $groupOfGoodsList,
|
||||||
|
'insurance_net' => (float)$insuredProduct->pricing->insurance_net,
|
||||||
|
'serial_no' => (string)($device->serial_no ?? ''),
|
||||||
|
'date_purchase' => (string)($device->date_purchase ?? ''),
|
||||||
|
'purchase_price'=> (float)($device->purchase_price ?? 0.0),
|
||||||
|
'owner' => (string)($device->owner ?? ''),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* =========================
|
||||||
|
2) XLSX sofort erzeugen (ohne setCellValueByColumnAndRow)
|
||||||
|
========================= */
|
||||||
|
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Style\Alignment;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Cell\DataType;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Shared\Date as ExcelDate;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Style\Fill;
|
||||||
|
|
||||||
|
$exportDir = __DIR__ . '/exports';
|
||||||
|
if (!is_dir($exportDir)) {
|
||||||
|
@mkdir($exportDir, 0775, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
$timestamp = date('Ymd_His');
|
||||||
|
$excelFileName = "Versicherungsgeraete_{$timestamp}.xlsx";
|
||||||
|
$excelFilePath = $exportDir . '/' . $excelFileName;
|
||||||
|
$excelDownloadUrl = 'exports/' . $excelFileName;
|
||||||
|
|
||||||
|
$spreadsheet = new Spreadsheet();
|
||||||
|
$sheet = $spreadsheet->getActiveSheet();
|
||||||
|
$sheet->setTitle('Versicherungsgeräte');
|
||||||
|
|
||||||
|
// kleine Helfer zum Adressieren per Spaltenbuchstaben
|
||||||
|
$cell = function(int $colIndex, int $rowIndex): string {
|
||||||
|
return Coordinate::stringFromColumnIndex($colIndex) . $rowIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
$colCount = count($EXCEL_COLS);
|
||||||
|
$lastCol = Coordinate::stringFromColumnIndex($colCount);
|
||||||
|
|
||||||
|
// Spaltenindex-Konstanten für Summen
|
||||||
|
$INSURANCE_COL = 4; // "Versicherung netto"
|
||||||
|
$PURCHASE_COL = 7; // "Kaufpreis"
|
||||||
|
|
||||||
|
// Custom Header
|
||||||
|
$rowIdx = 1;
|
||||||
|
foreach ($EXCEL_CUSTOM_HEADER as $hdrLine) {
|
||||||
|
$text = implode(' ', $hdrLine);
|
||||||
|
$sheet->setCellValue($cell(1, $rowIdx), $text);
|
||||||
|
$sheet->mergeCells($cell(1, $rowIdx) . ':' . $cell($colCount, $rowIdx));
|
||||||
|
$sheet->getStyle($cell(1, $rowIdx) . ':' . $cell($colCount, $rowIdx))
|
||||||
|
->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER);
|
||||||
|
$sheet->getStyle($cell(1, $rowIdx) . ':' . $cell($colCount, $rowIdx))
|
||||||
|
->getFont()->setBold(true)->setSize($rowIdx === 1 ? 14 : 11);
|
||||||
|
$rowIdx++;
|
||||||
|
}
|
||||||
|
$rowIdx++;
|
||||||
|
|
||||||
|
// Tabellen-Header
|
||||||
|
foreach ($EXCEL_COLS as $i => $label) {
|
||||||
|
$addr = $cell($i+1, $rowIdx);
|
||||||
|
$sheet->setCellValue($addr, $label);
|
||||||
|
$sheet->getStyle($addr)->getFont()->setBold(true);
|
||||||
|
$sheet->getStyle($addr)->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER);
|
||||||
|
$sheet->getColumnDimension(Coordinate::stringFromColumnIndex($i+1))->setAutoSize(true);
|
||||||
|
}
|
||||||
|
$headerRow = $rowIdx;
|
||||||
|
$rowIdx++;
|
||||||
|
|
||||||
|
// Daten
|
||||||
|
$dataStartRow = $rowIdx;
|
||||||
|
foreach ($rows as $r) {
|
||||||
|
$c = 1;
|
||||||
|
|
||||||
|
// #
|
||||||
|
$sheet->setCellValue($cell($c++, $rowIdx), $r['pk']);
|
||||||
|
|
||||||
|
// Name (+ Materials)
|
||||||
|
$nameOut = $r['name'] . ($r['materials'] ? " | {$r['materials']}" : "");
|
||||||
|
$sheet->setCellValue($cell($c++, $rowIdx), $nameOut);
|
||||||
|
|
||||||
|
// Warengruppen
|
||||||
|
$sheet->setCellValue($cell($c++, $rowIdx), $r['groups']);
|
||||||
|
|
||||||
|
// Versicherung netto (numerisch, EU-Format)
|
||||||
|
$sheet->setCellValueExplicit($cell($c, $rowIdx), (float)$r['insurance_net'], DataType::TYPE_NUMERIC);
|
||||||
|
$sheet->getStyle($cell($c, $rowIdx))->getNumberFormat()->setFormatCode('#,##0.00 [$€-de-DE]');
|
||||||
|
$c++;
|
||||||
|
|
||||||
|
// Seriennummer
|
||||||
|
$sheet->setCellValue($cell($c++, $rowIdx), $r['serial_no']);
|
||||||
|
|
||||||
|
// Anschaffung (Datum)
|
||||||
|
$excelDate = '';
|
||||||
|
if (!empty($r['date_purchase'])) {
|
||||||
|
$ts = strtotime($r['date_purchase']);
|
||||||
|
if ($ts !== false) {
|
||||||
|
$excelDate = ExcelDate::PHPToExcel($ts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($excelDate !== '') {
|
||||||
|
$sheet->setCellValue($cell($c, $rowIdx), $excelDate);
|
||||||
|
$sheet->getStyle($cell($c, $rowIdx))->getNumberFormat()->setFormatCode('dd.mm.yyyy');
|
||||||
|
} else {
|
||||||
|
$sheet->setCellValue($cell($c, $rowIdx), '');
|
||||||
|
}
|
||||||
|
$c++;
|
||||||
|
|
||||||
|
// Kaufpreis (numerisch, EU-Format)
|
||||||
|
$sheet->setCellValueExplicit($cell($c, $rowIdx), abs((float)$r['purchase_price']), DataType::TYPE_NUMERIC);
|
||||||
|
$sheet->getStyle($cell($c, $rowIdx))->getNumberFormat()->setFormatCode('#,##0.00 [$€-de-DE]');
|
||||||
|
$c++;
|
||||||
|
|
||||||
|
// Besitzer
|
||||||
|
$sheet->setCellValue($cell($c++, $rowIdx), $r['owner']);
|
||||||
|
|
||||||
|
$rowIdx++;
|
||||||
|
}
|
||||||
|
$dataEndRow = $rowIdx - 1;
|
||||||
|
|
||||||
|
/* === Summenzeile mit grauer Hinterlegung === */
|
||||||
|
$totalRow = $rowIdx + 1;
|
||||||
|
|
||||||
|
// Label in Spalte A
|
||||||
|
$sheet->setCellValue($cell(1, $totalRow), 'Gesamtsummen:');
|
||||||
|
$sheet->getStyle($cell(1, $totalRow))->getFont()->setBold(true);
|
||||||
|
|
||||||
|
// SUM-Formel Versicherung netto (Spalte 4)
|
||||||
|
$insColLetter = Coordinate::stringFromColumnIndex($INSURANCE_COL);
|
||||||
|
$sheet->setCellValue(
|
||||||
|
$cell($INSURANCE_COL, $totalRow),
|
||||||
|
"=SUM({$insColLetter}{$dataStartRow}:{$insColLetter}{$dataEndRow})"
|
||||||
|
);
|
||||||
|
$sheet->getStyle($cell($INSURANCE_COL, $totalRow))
|
||||||
|
->getNumberFormat()->setFormatCode('#,##0.00 [$€-de-DE]');
|
||||||
|
$sheet->getStyle($cell($INSURANCE_COL, $totalRow))->getFont()->setBold(true);
|
||||||
|
|
||||||
|
// SUM-Formel Kaufpreis (Spalte 7)
|
||||||
|
$purColLetter = Coordinate::stringFromColumnIndex($PURCHASE_COL);
|
||||||
|
$sheet->setCellValue(
|
||||||
|
$cell($PURCHASE_COL, $totalRow),
|
||||||
|
"=SUM({$purColLetter}{$dataStartRow}:{$purColLetter}{$dataEndRow})"
|
||||||
|
);
|
||||||
|
$sheet->getStyle($cell($PURCHASE_COL, $totalRow))
|
||||||
|
->getNumberFormat()->setFormatCode('#,##0.00 [$€-de-DE]');
|
||||||
|
$sheet->getStyle($cell($PURCHASE_COL, $totalRow))->getFont()->setBold(true);
|
||||||
|
|
||||||
|
// graue Hinterlegung über die ganze Summenzeile
|
||||||
|
$sheet->getStyle($cell(1, $totalRow) . ':' . $cell($colCount, $totalRow))
|
||||||
|
->getFill()->setFillType(Fill::FILL_SOLID)->getStartColor()->setARGB('FFEFEFEF');
|
||||||
|
|
||||||
|
// Filter + Freeze
|
||||||
|
$sheet->setAutoFilter("A{$headerRow}:{$lastCol}{$headerRow}");
|
||||||
|
$sheet->freezePane("A" . ($headerRow + 1));
|
||||||
|
|
||||||
|
// Datei speichern
|
||||||
|
$writer = new Xlsx($spreadsheet);
|
||||||
|
$writer->save($excelFilePath);
|
||||||
|
|
||||||
|
/* =========================
|
||||||
|
3) HTML-Ausgabe (Tabelle aus $rows) + Download-Link
|
||||||
|
========================= */
|
||||||
|
|
||||||
|
// Summen für HTML
|
||||||
|
$totalInsurance = array_sum(array_column($rows, 'insurance_net'));
|
||||||
|
$totalPurchase = array_sum(array_map(fn($r) => abs($r['purchase_price']), $rows));
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="de">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
|
||||||
|
<title>Dashboard - EpiWebview</title>
|
||||||
|
|
||||||
|
<!-- Styles -->
|
||||||
|
<link href="css/styles.css" rel="stylesheet" />
|
||||||
|
<link href="https://cdn.datatables.net/1.10.20/css/dataTables.bootstrap4.min.css" rel="stylesheet" crossorigin="anonymous" />
|
||||||
|
|
||||||
|
<!-- JS -->
|
||||||
|
<script src="js/jquery-3.5.1.min.js"></script>
|
||||||
|
<script src="https://kit.fontawesome.com/93d71de8bc.js" crossorigin="anonymous"></script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.opacity-50 { opacity: .5; }
|
||||||
|
.card .h2, .card .display-4 { font-weight: 700; }
|
||||||
|
.kpi-updated { font-size: .82rem; opacity: .85; }
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$(function () {
|
||||||
|
$('#layoutSidenav_nav').load('../sources/getSidenav.php');
|
||||||
|
$('#footerholder').load('../sources/getFooter.php');
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body class="sb-nav-fixed">
|
||||||
|
<nav class="sb-topnav navbar navbar-expand navbar-dark bg-dark">
|
||||||
|
<a class="navbar-brand" href="index.php">Epi Webview</a>
|
||||||
|
<button class="btn btn-link btn-sm order-1 order-lg-0" id="sidebarToggle"><i class="fas fa-bars"></i></button>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div id="layoutSidenav">
|
||||||
|
<div id="layoutSidenav_nav"></div>
|
||||||
|
<div id="layoutSidenav_content">
|
||||||
|
<main>
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h1 class="mt-4">Versicherung</h1>
|
||||||
|
<ol class="breadcrumb mb-4">
|
||||||
|
<li class="breadcrumb-item active">Versicherung</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<div class="card mb-4">
|
||||||
|
<div class="card-header d-flex justify-content-between align-items-center">
|
||||||
|
<div><i class="fas fa-table mr-1"></i> Versicherungsgeräte</div>
|
||||||
|
<a class="btn btn-sm btn-success" href="<?php echo htmlspecialchars($excelDownloadUrl); ?>">
|
||||||
|
<i class="fas fa-file-excel"></i> Export nach Excel
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-bordered" id="dataTable" width="100%" cellspacing="0">
|
||||||
|
<tr>
|
||||||
|
<th scope="col">#</th>
|
||||||
|
<th scope="col">Name</th>
|
||||||
|
<th scope="col">Warengruppe(n)</th>
|
||||||
|
<th scope="col">Versicherung netto</th>
|
||||||
|
<th scope="col">Seriennummer</th>
|
||||||
|
<th scope="col">Anschaffung</th>
|
||||||
|
<th scope="col">Kaufpreis</th>
|
||||||
|
<th scope="col">Besitzer</th>
|
||||||
|
</tr>
|
||||||
|
<?php foreach ($rows as $r): ?>
|
||||||
|
<tr>
|
||||||
|
<th><?php echo htmlspecialchars((string) $r['pk']); ?></th>
|
||||||
|
<th>
|
||||||
|
<?php
|
||||||
|
echo htmlspecialchars($r['name']);
|
||||||
|
if (!empty($r['materials'])) {
|
||||||
|
echo "<br><small>" . htmlspecialchars($r['materials']) . "</small>";
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</th>
|
||||||
|
<th><?php echo htmlspecialchars($r['groups']); ?></th>
|
||||||
|
<th><?php echo formatEuro((float)$r['insurance_net']); ?></th>
|
||||||
|
<th><?php echo htmlspecialchars($r['serial_no']); ?></th>
|
||||||
|
<th>
|
||||||
|
<?php
|
||||||
|
$purchaseDateOut = '';
|
||||||
|
if (!empty($r['date_purchase'])) {
|
||||||
|
try { $purchaseDateOut = date_format(new \DateTime($r['date_purchase']), 'd.m.Y'); } catch (\Throwable $e) {}
|
||||||
|
}
|
||||||
|
echo htmlspecialchars($purchaseDateOut);
|
||||||
|
?>
|
||||||
|
</th>
|
||||||
|
<th><?php echo formatEuro(abs((float)$r['purchase_price'])); ?></th>
|
||||||
|
<th><?php echo htmlspecialchars($r['owner']); ?></th>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
|
||||||
|
<!-- Summenzeile in HTML -->
|
||||||
|
<tr style="font-weight:bold; background:#f8f9fa;">
|
||||||
|
<td colspan="3" class="text-right">Gesamtsummen:</td>
|
||||||
|
<td><?php echo formatEuro($totalInsurance); ?></td>
|
||||||
|
<td></td>
|
||||||
|
<td></td>
|
||||||
|
<td><?php echo formatEuro($totalPurchase); ?></td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
<div id="footerholder"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Bootstrap Bundle -->
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.bundle.min.js" crossorigin="anonymous"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
155
dist/labelprint.php
vendored
Normal file
155
dist/labelprint.php
vendored
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require('../config.php');
|
||||||
|
require('../EpiApi.php');
|
||||||
|
require_once __DIR__ . '/../vendor/autoload.php';
|
||||||
|
date_default_timezone_set('Europe/Berlin');
|
||||||
|
|
||||||
|
$Epi = new Epirent();
|
||||||
|
$productList = json_decode($Epi->requestEpiApi('/v1/product/all?ia=true&ir=true&cl=' . Epirent_Mandant))->payload;
|
||||||
|
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="de">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
|
||||||
|
<title>Labelprint - EpiWebview</title>
|
||||||
|
|
||||||
|
<!-- Styles -->
|
||||||
|
<link href="css/styles.css" rel="stylesheet" />
|
||||||
|
<link href="https://cdn.datatables.net/1.10.20/css/dataTables.bootstrap4.min.css" rel="stylesheet" crossorigin="anonymous" />
|
||||||
|
|
||||||
|
<!-- JS -->
|
||||||
|
<script src="js/jquery-3.5.1.min.js"></script>
|
||||||
|
<script src="https://kit.fontawesome.com/93d71de8bc.js" crossorigin="anonymous"></script>
|
||||||
|
<script src="https://cdn.datatables.net/1.10.20/js/jquery.dataTables.min.js"></script>
|
||||||
|
<script src="https://cdn.datatables.net/1.10.20/js/dataTables.bootstrap4.min.js"></script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.opacity-50 {
|
||||||
|
opacity: .5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card .h2,
|
||||||
|
.card .display-4 {
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kpi-updated {
|
||||||
|
font-size: .82rem;
|
||||||
|
opacity: .85;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$(function() {
|
||||||
|
$('#layoutSidenav_nav').load('../sources/getSidenav.php');
|
||||||
|
$('#footerholder').load('../sources/getFooter.php');
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body class="sb-nav-fixed">
|
||||||
|
<nav class="sb-topnav navbar navbar-expand navbar-dark bg-dark">
|
||||||
|
<a class="navbar-brand" href="index.php">Epi Webview</a>
|
||||||
|
<button class="btn btn-link btn-sm order-1 order-lg-0" id="sidebarToggle"><i class="fas fa-bars"></i></button>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div id="layoutSidenav">
|
||||||
|
<div id="layoutSidenav_nav"></div>
|
||||||
|
<div id="layoutSidenav_content">
|
||||||
|
<main>
|
||||||
|
<div class="container-fluid">
|
||||||
|
<h1 class="mt-4">Labelprint</h1>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="card mb-4">
|
||||||
|
<div class="card-header d-flex justify-content-between align-items-center">
|
||||||
|
<div><i class="fas fa-table mr-1"></i> Labelprint</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table id="dataTable" class="table table-bordered" width="100%" cellspacing="0">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>#</th>
|
||||||
|
<th>PN</th>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Aktionen</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php
|
||||||
|
foreach ($productList as $product) {
|
||||||
|
if (!$product->is_rent & $product->is_sale){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
echo "<tr>";
|
||||||
|
echo "<td>" . htmlspecialchars($product->primary_key) . "</td>";
|
||||||
|
echo "<td>" . htmlspecialchars($product->product_no) . "</td>";
|
||||||
|
echo "<td>" . htmlspecialchars($product->name) . "</td>";
|
||||||
|
echo "
|
||||||
|
<td>
|
||||||
|
<a class='btn btn-sm btn-outline-primary'
|
||||||
|
target='_blank'
|
||||||
|
href='../sources/getProductLabel.php?id=" . urlencode($product->primary_key) . "'>
|
||||||
|
Export
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<input type='number'
|
||||||
|
id='nrInput_" . htmlspecialchars($product->primary_key) . "'
|
||||||
|
min='1' max='9999'
|
||||||
|
style='width:70px; margin-left:6px; text-align:center;'
|
||||||
|
placeholder='#'>
|
||||||
|
|
||||||
|
<a class='btn btn-sm btn-outline-secondary'
|
||||||
|
target='_blank'
|
||||||
|
id='exportWithIdBtn_" . htmlspecialchars($product->primary_key) . "'
|
||||||
|
href='#'
|
||||||
|
onclick=\"
|
||||||
|
var nr = document.getElementById('nrInput_" . htmlspecialchars($product->primary_key) . "').value;
|
||||||
|
if(nr) {
|
||||||
|
this.href = '../sources/getProductLabel.php?id=" . urlencode($product->primary_key) . "&nr=' + encodeURIComponent(nr);
|
||||||
|
} else {
|
||||||
|
alert('Bitte eine Nummer zwischen 1 und 9999 eingeben.');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
\">
|
||||||
|
Export mit ID
|
||||||
|
</a>
|
||||||
|
</td>";
|
||||||
|
echo "</tr>";
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
<div id="footerholder"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Bootstrap Bundle -->
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.bundle.min.js" crossorigin="anonymous"></script>
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
$('#dataTable').DataTable({
|
||||||
|
"pageLength": 25,
|
||||||
|
"language": {
|
||||||
|
"url": "//cdn.datatables.net/plug-ins/1.10.20/i18n/German.json"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
@@ -1,39 +1,92 @@
|
|||||||
<?php
|
<?php
|
||||||
//EPIRENT CONNECTION EINSTELLUNGEN//
|
// @section: Epirent – Verbindung
|
||||||
define('Epirent_Server', 'xxx');
|
define('Epirent_Server', 'xxx');
|
||||||
define('Epirent_Connectionprotocol', 'http');
|
define('Epirent_Connectionprotocol', 'http');
|
||||||
define('Epirent_Port', '8080');
|
define('Epirent_Port', '8080');
|
||||||
define('Epirent_Token', 'xxx');
|
define('Epirent_Token', 'xxx');
|
||||||
define('Epirent_Mandant', '0'); //NORMALERWEISE 0
|
define('Epirent_Mandant', '0'); //NORMALERWEISE 0
|
||||||
|
// @hr
|
||||||
//CREWBRAIN CONNECTION EINSTELLUNGEN-NUR AUSFÜLLEN WENN GEWÜNSCHT//
|
// @section: Crewbrain Verbindung
|
||||||
|
// @note: Nur ausfüllen wenn gewünscht
|
||||||
define('CrewBrain_Username', 'xxx');
|
define('CrewBrain_Username', 'xxx');
|
||||||
define('CrewBrain_password', 'xxx');
|
define('CrewBrain_password', 'xxx');
|
||||||
define('CrewBrain_Server', 'xxx.crewbrain.com');
|
define('CrewBrain_Server', 'xxx.crewbrain.com');
|
||||||
define('CrewBrain_Connectionprotocol', 'https');
|
define('CrewBrain_Connectionprotocol', 'https');
|
||||||
define('CrewBrain_TaskListID', 6);
|
define('CrewBrain_TaskListID', 6);
|
||||||
|
|
||||||
//CREWBRAIN SPEZIFISCHE EINSTELLUNGEN (AUFGABENLISTE)//
|
|
||||||
define('Enable_QR_Code_CrewBrainAufgaben', true);
|
define('Enable_QR_Code_CrewBrainAufgaben', true);
|
||||||
|
// @hr
|
||||||
//EPIRENT SPEZIFISCHE EINSTELLUNGEN (CHECK IN & CHECK OUT)
|
// @section: Epirent-Spezifische Einstellungen
|
||||||
define('Enable_QR_Code_CheckOut', false); //Zeigt statt der Packscheinnummer einen Scanbaren QR Code für den CheckOut an
|
define('Enable_QR_Code_CheckOut', false); //Zeigt statt der Packscheinnummer einen Scanbaren QR Code für den CheckOut an
|
||||||
define('Enable_QR_Code_CheckIn', false); //Zeigt statt der Packscheinnummer einen Scanbaren QR Code für den CheckIn an
|
define('Enable_QR_Code_CheckIn', false); //Zeigt statt der Packscheinnummer einen Scanbaren QR Code für den CheckIn an
|
||||||
define('Vorbereitungs_Zeitvariable', 'Packen'); //Name des zu verwendenden Zeitabschnitts, der Zusätzlich zur DispoZeit beim Check Out Angezeigt werden soll
|
define('Vorbereitungs_Zeitvariable', 'Packen'); //Name des zu verwendenden Zeitabschnitts, der Zusätzlich zur DispoZeit beim Check Out Angezeigt werden soll
|
||||||
define('Rueckpacken_Zeitvariable', 'Rückpacken'); //Name des zu verwendenden Zeitabschnitts, der Zusätzlich zur DispoZeit beim Check In Angezeigt werden soll
|
define('Nachbereitung_Zeitvariable', 'Rückpacken'); //Name des zu verwendenden Zeitabschnitts aus dem Auftrag, der die Nachbereitung angibt
|
||||||
|
define('Rückpacken_Zeitvariable', 'Rückpacken'); //Name des zu verwendenden Zeitabschnitts aus dem Auftrag, der das Rückpacken angibt.
|
||||||
|
define('UseDeliveredForCheckOutCompleted', true); //Nutzt statt dem erfolgreichen abschließen eines Packscheins durch ausbuchen das erfolgreiche Liefern (Geliefert != 00.00.00)
|
||||||
|
define('EnableScrollingCheckOut', true); //Aktiviert das automatische Scrollen der CheckOut Liste
|
||||||
|
define('EnableScrollingCheckIn', true); //Aktiviert das automatische Scrollen der CheckIn Liste
|
||||||
|
define('EnableScrollingAufgaben', true); //Aktiviert das automatische Scrollen der Aufgabenliste
|
||||||
|
// @note: -------------------- CheckOutRowMarkSource: Konfig Zusände --------------------
|
||||||
|
// @note: 1 = $packingjob->date_start (Packjob Start)
|
||||||
|
// @note: 2 = $VorbereitungsTimeDetail->date_start (Vorbereitung Start)
|
||||||
|
// @note: 3 = $PackingNoteDetail->date_packing (Packen Zeit)
|
||||||
|
// @note: 4 = $PackingNoteDetail->date_delivery (Delivery Zeit)
|
||||||
|
// @note: 5 = $order->date_start (Dispo Start Zeit)
|
||||||
|
define('CheckOutRowMarkSource', 4);
|
||||||
|
|
||||||
define('UsePackingNoteDateForCheckout', true); // Nutzt statt den Zeitabscnitten aus dem Auftrag die Informationen aus dem Packschein für den Checkout. Wenn die UseDispo Variablen false sind, werden diese Variablen für das Rowmarking genutzt falls "true".
|
// @note: -------------------- CheckInRowMarkSource: Konfig Zusände --------------------
|
||||||
define('UsePackingNoteDateForCheckin', true); // Nutzt statt den Zeitabscnitten aus dem Auftrag die Informationen aus dem Packschein für den Checkout. Wenn die UseDispo Variablen false sind, werden diese Variablen für das Rowmarking genutzt falls "true".
|
// @note: 1 = $packingjob->date_end (Packjob Ende)
|
||||||
|
// @note: 2 = $NachbereitungssTimeDetail->date_start (Nachbereitung Start)
|
||||||
|
// @note: 3 = $RePackagingTimeDetail->date_start (Rückpacken Zeit AUS AUFTRAG)
|
||||||
|
// @note: 4 = $PackingNoteDetail->date_redelivery (ReDelivery Zeit)
|
||||||
|
// @note: 5 = $order->date_end (Dispo End Zeit)
|
||||||
|
define('CheckInRowMarkSource', 4);
|
||||||
|
|
||||||
define('CheckOut_UseDispoStartForRowMarking', false); //else: Use Same Variable as "Vorbereitung Zeitvariable" | Konfiguration, welche Zeit für die Zeilenmarkierung beim CheckOut Verwendet werden soll
|
|
||||||
define('CheckIn_UseDispoEndForRowMarking', false); //else: Use Same Variable as "Rueckpacken Zeitvariable" | Konfiguration, welche Zeit für die Zeilenmarkierung beim Check In Verwendet werden soll
|
define('CheckIn_UseDispoEndForRowMarking', false); //else: Use Same Variable as "Rueckpacken Zeitvariable" | Konfiguration, welche Zeit für die Zeilenmarkierung beim Check In Verwendet werden soll
|
||||||
|
|
||||||
define('HideCheckInTimeOnCheckout', true); //Versteckt die CheckIn Zeit im Checkout
|
define('ShowCheckoutTimeOnCheckout', true); //Zeigt die Checkout Zeit im Checkout
|
||||||
define('HideCheckOutTimeOnCheckin', true); //Versteckt die CheckOut Zeit im CheckIn
|
define('ShowVorbereitungTimeOnCheckout', true); //Zeigt die Vorbereitungs Zeitvariable im Checkout
|
||||||
|
define('ShowPackagingTimeOnCheckout', true); //Zeigt die Packenzeit im Checkout
|
||||||
|
define('ShowDeliveryTimeOnCheckout', true); //Zeigt die Lieferzeit im Checkout
|
||||||
|
define('ShowDispoStartOnCheckout', true); //Zeigt die DispoStart im Checkout
|
||||||
|
define('ShowTimesOnCheckout', true); //Aktiviert das anzeigen der Uhrzeit im Checkout
|
||||||
|
|
||||||
|
// @hr
|
||||||
|
define('ShowCheckInTimeOnCheckin', true); //Zeigt die CheckIn Zeit im CheckIn
|
||||||
|
define('ShowNachbereitungTimeOnCheckin', true); //Zeigt die Nachbereitungs Zeitvariable im CheckIn
|
||||||
|
define('ShowRePackagingTimeOnCheckin', true); //Zeigt die Rückpackzeit im Checkin <br><b>Achtung: Zeit nur Im Auftrag festlegbar</b>
|
||||||
|
define('ShowReDeliveryTimeOnCheckin', true); //Zeigt die geplante Rücklieferung im Checkin
|
||||||
|
define('ShowDispoEndOnCheckin', true); //Zeigt die DispoEnd Zeit im CheckIn
|
||||||
|
define('ShowTimesOnCheckin', true); //Aktiviert das anzeigen der Uhrzeit im CheckIn
|
||||||
|
|
||||||
|
// @section: Epirent-Spezifische Einstellungen - Shipping
|
||||||
|
define('ShowShippingIcons', true); //Zeigt Lieferung / Rücklieferungs Icons an
|
||||||
|
define('KurierContainsText', 'Kurier'); //Text, der in der Versandart enthalten sein muss (enthält), damit diese als KURIER erkannt wird.
|
||||||
|
define('SpeditionContainsText', 'Spedition'); //Text, der in der Versandart enthalten sein muss (enthält), damit diese als SPEDITION erkannt wird.
|
||||||
|
define('DHLContainsText', 'DHL'); //Text, der in der Versandart enthalten sein muss (enthält), damit diese als DHL erkannt wird.
|
||||||
|
define('LKWContainsText', 'LKW'); //Text, der in der Versandart enthalten sein muss (enthält), damit diese als eigener LKW erkannt wird.
|
||||||
|
define('TransporterContainsText', 'Sprinter'); //Text, der in der Versandart enthalten sein muss (enthält), damit diese als eigener Transporter erkannt wird.
|
||||||
|
define('PKWContainsText', 'PKW'); //Text, der in der Versandart enthalten sein muss (enthält), damit diese als eigener PKW erkannt wird.
|
||||||
|
// @hr
|
||||||
|
// @note: Informationen zu den Icons: Die Icons basieren auf FontAwesome und bestehen aus drei Teilen: Sammlung (fa-solid), Icon (fa-truck) und Größe (fa-lg). Weitere Informationen bitte der FA-Doku entnehmen
|
||||||
|
define('KurierIcon', 'fa-solid fa-hand-holding-dollar fa-lg');
|
||||||
|
define('SpeditionIcon', 'fa-solid fa-truck fa-lg');
|
||||||
|
define('DHLIcon', 'fa-brands fa-dhl fa-2xl');
|
||||||
|
define('LKWIcon', 'fa-solid fa-truck fa-lg');
|
||||||
|
define('TransporterIcon', 'fa-solid fa-van-shuttle fa-lg');
|
||||||
|
define('PKWIcon', 'fa-solid fa-car fa-lg');
|
||||||
|
define('SelbstabholerIcon', 'fa-solid fa-person-walking fa-lg');
|
||||||
|
|
||||||
|
define('UseShippingStatus', true); //Nutzt den Packscheinstatus als Shipping Status. Hierdurch können die Icons unter verschiedenen Vorraussetzungen Grün werden, wenn der Versand organisiert wurde
|
||||||
|
define('ShippingOutOrganizedStatus', 'Hinversand OK'); //Packschein Status (EpirentDropdown) der Gematcht werden muss, dass der Hinversand Organisiert / Bestellt wurde
|
||||||
|
define('ShippingInOrganizedStatus', 'Rückversand OK'); //Packschein Status (EpirentDropdown) der Gematcht werden muss, dass der Rückversand Organisiert / Bestellt wurde
|
||||||
|
define('ShippingOrganizedStatus', 'Versand OK'); //Packschein Status (EpirentDropdown) der Gematcht werden muss, dass der komplette Versand Organisiert / Bestellt wurde
|
||||||
|
|
||||||
|
// @section: Epirent-Spezifische Einstellungen - Anzeigesortierung
|
||||||
define('CheckOut_FutureDays', -1); // Konfiguration, wie viele Tage in der Zukunft der CheckOut angezeigt werden soll. '-1' zeigt alle an. Abhängig von der Variablen CheckOut_UseDispoStartForRowMarking
|
define('CheckOut_FutureDays', -1); // Konfiguration, wie viele Tage in der Zukunft der CheckOut angezeigt werden soll. '-1' zeigt alle an. Abhängig von der Variablen CheckOut_UseDispoStartForRowMarking
|
||||||
define('CheckIn_FutureDays', -1); // Konfiguration, wie viele Tage in der Zukunft der CheckIn angezeigt werden soll. '-1' zeigt alle an. Abhängig von der Variablen CheckIn_UseDispoEndForRowMarking
|
define('CheckIn_FutureDays', -1); // Konfiguration, wie viele Tage in der Zukunft der CheckIn angezeigt werden soll. '-1' zeigt alle an. Abhängig von der Variablen CheckIn_UseDispoEndForRowMarking
|
||||||
define('SortCheckOut', 2); // Konfiguration, welcher Datensatz für die Sortierung Verwendet werden soll. Möglichkeiten '1': Packscheinnummer / '2': Dispostart
|
define('SortCheckOut', 2); // Konfiguration, welcher Datensatz für die Sortierung Verwendet werden soll. Möglichkeiten '1': Packscheinnummer / '2': Dispostart
|
||||||
define('SortCheckIn', 2); // Konfiguration, welcher Datensatz für die Sortierung Verwendet werden soll. Möglichkeiten '1': Packscheinnummer / '2': Dispoende
|
define('SortCheckIn', 2); // Konfiguration, welcher Datensatz für die Sortierung Verwendet werden soll. Möglichkeiten '1': Packscheinnummer / '2': Dispoende
|
||||||
|
// @section: Epirent-Spezifische Einstellungen - Labeldruck
|
||||||
|
define('Labelprint_Logopath', '/../src/assets/img/logo.png'); //Pfad zum Logo für den Etikettendruck
|
||||||
|
define('Labelprint_Addresstext', '<b>VT-Media</b><br/>Augsburger Straße 22<br/>87672 Roßhaupten<br/>info@vt-media.de<br/>vt-media.de<br/>08367/4619-990'); //Text der im Adressfeld der Etiketten angezeigt wird. max 6 Zeilen Empfohlen. Umbruch mit <br>. Fett mit <b>Text</b>
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -3,22 +3,35 @@
|
|||||||
<editor-bookmarks xmlns="http://www.netbeans.org/ns/editor-bookmarks/2" lastBookmarkId="0"/>
|
<editor-bookmarks xmlns="http://www.netbeans.org/ns/editor-bookmarks/2" lastBookmarkId="0"/>
|
||||||
<open-files xmlns="http://www.netbeans.org/ns/projectui-open-files/2">
|
<open-files xmlns="http://www.netbeans.org/ns/projectui-open-files/2">
|
||||||
<group>
|
<group>
|
||||||
|
<file>file:/C:/xampp/htdocs/EpiWebview/sources/getCheckOutCards.php</file>
|
||||||
|
<file>file:/C:/xampp/htdocs/EpiWebview/dist/index.html</file>
|
||||||
<file>file:/C:/xampp/htdocs/EpiWebview/.git/config</file>
|
<file>file:/C:/xampp/htdocs/EpiWebview/.git/config</file>
|
||||||
<file>file:/C:/xampp/htdocs/EpiWebview/PackAufgabenMonitor.php</file>
|
|
||||||
<file>file:/C:/xampp/htdocs/EpiWebview/sources/getSidenav.php</file>
|
|
||||||
<file>file:/C:/xampp/htdocs/EpiWebview/dist/index.php</file>
|
<file>file:/C:/xampp/htdocs/EpiWebview/dist/index.php</file>
|
||||||
<file>file:/C:/xampp/htdocs/EpiWebview/sources/getOrderDetails.php</file>
|
<file>file:/C:/xampp/htdocs/EpiWebview/sources/getOrderDetails.php</file>
|
||||||
<file>file:/C:/xampp/htdocs/EpiWebview/config.php</file>
|
<file>file:/C:/xampp/htdocs/EpiWebview/dist/css/styles.css</file>
|
||||||
<file>file:/C:/xampp/htdocs/EpiWebview/EpiApi.php</file>
|
|
||||||
<file>file:/C:/xampp/htdocs/EpiWebview/sources/getOrders.php</file>
|
|
||||||
<file>file:/C:/xampp/htdocs/EpiWebview/Aufgabenmonitor.php</file>
|
<file>file:/C:/xampp/htdocs/EpiWebview/Aufgabenmonitor.php</file>
|
||||||
|
<file>file:/C:/xampp/htdocs/EpiWebview/dist/layout-sidenav-light.html</file>
|
||||||
|
<file>file:/C:/xampp/htdocs/EpiWebview/dist/editconfig.php</file>
|
||||||
<file>file:/C:/xampp/htdocs/EpiWebview/composer.json</file>
|
<file>file:/C:/xampp/htdocs/EpiWebview/composer.json</file>
|
||||||
<file>file:/C:/xampp/htdocs/EpiWebview/sources/getCheckInTable.php</file>
|
<file>file:/C:/xampp/htdocs/EpiWebview/sources/getCheckInTable.php</file>
|
||||||
<file>file:/C:/xampp/htdocs/EpiWebview/CrewbrainApi.php</file>
|
<file>file:/C:/xampp/htdocs/EpiWebview/CrewbrainApi.php</file>
|
||||||
|
<file>file:/C:/xampp/htdocs/EpiWebview/example.config.php</file>
|
||||||
<file>file:/C:/xampp/htdocs/EpiWebview/composer.lock</file>
|
<file>file:/C:/xampp/htdocs/EpiWebview/composer.lock</file>
|
||||||
<file>file:/C:/xampp/htdocs/EpiWebview/info.php</file>
|
<file>file:/C:/xampp/htdocs/EpiWebview/info.php</file>
|
||||||
<file>file:/C:/xampp/htdocs/EpiWebview/Packmonitor.php</file>
|
<file>file:/C:/xampp/htdocs/EpiWebview/Packmonitor.php</file>
|
||||||
<file>file:/C:/xampp/htdocs/EpiWebview/index.php</file>
|
<file>file:/C:/xampp/htdocs/EpiWebview/index.php</file>
|
||||||
|
<file>file:/C:/xampp/htdocs/EpiWebview/.gitignore</file>
|
||||||
|
<file>file:/C:/xampp/htdocs/EpiWebview/PackAufgabenMonitor.php</file>
|
||||||
|
<file>file:/C:/xampp/htdocs/EpiWebview/sources/getSidenav.php</file>
|
||||||
|
<file>file:/C:/xampp/htdocs/EpiWebview/README.MD</file>
|
||||||
|
<file>file:/C:/xampp/htdocs/EpiWebview/config.php</file>
|
||||||
|
<file>file:/C:/xampp/htdocs/EpiWebview/EpiApi.php</file>
|
||||||
|
<file>file:/C:/xampp/htdocs/EpiWebview/sources/getOrders.php</file>
|
||||||
|
<file>file:/C:/xampp/htdocs/EpiWebview/sources/getCheckInCards.php</file>
|
||||||
|
<file>file:/C:/xampp/htdocs/EpiWebview/dist/orders.php</file>
|
||||||
|
<file>file:/C:/xampp/htdocs/EpiWebview/dist/insurance.php</file>
|
||||||
|
<file>file:/C:/xampp/htdocs/EpiWebview/LICENSE.MD</file>
|
||||||
|
<file>file:/C:/xampp/htdocs/EpiWebview/vendor/autoload.php</file>
|
||||||
<file>file:/C:/xampp/htdocs/EpiWebview/sources/getAufgabenTable.php</file>
|
<file>file:/C:/xampp/htdocs/EpiWebview/sources/getAufgabenTable.php</file>
|
||||||
<file>file:/C:/xampp/htdocs/EpiWebview/sources/getCheckOutTable.php</file>
|
<file>file:/C:/xampp/htdocs/EpiWebview/sources/getCheckOutTable.php</file>
|
||||||
</group>
|
</group>
|
||||||
|
|||||||
@@ -62,9 +62,13 @@ foreach ($data_output as $aufgabe) {
|
|||||||
}
|
}
|
||||||
echo "<td>";
|
echo "<td>";
|
||||||
|
|
||||||
|
$i=0;
|
||||||
foreach($AufgabeDetail->Responsibles as $bearbeiter){
|
foreach($AufgabeDetail->Responsibles as $bearbeiter){
|
||||||
echo $bearbeiter->Name;
|
echo $bearbeiter->Name;
|
||||||
|
if($i>0){
|
||||||
|
echo ", ";
|
||||||
|
}
|
||||||
|
$i++;
|
||||||
}
|
}
|
||||||
echo "</td>";
|
echo "</td>";
|
||||||
echo "<td>" . $aufgabe->Titel . "</td>";
|
echo "<td>" . $aufgabe->Titel . "</td>";
|
||||||
|
|||||||
198
sources/getCheckInCards.php
Normal file
198
sources/getCheckInCards.php
Normal file
@@ -0,0 +1,198 @@
|
|||||||
|
<?php
|
||||||
|
// ../sources/getCheckInCards.php
|
||||||
|
error_reporting(E_ALL);
|
||||||
|
require('../config.php');
|
||||||
|
require('../EpiApi.php');
|
||||||
|
|
||||||
|
$Epi = new Epirent();
|
||||||
|
|
||||||
|
use chillerlan\QRCode\{ QRCode, QROptions };
|
||||||
|
require('../vendor/autoload.php');
|
||||||
|
|
||||||
|
const APP_TZ = 'Europe/Berlin';
|
||||||
|
|
||||||
|
/** ---------- Helpers (wie in deiner Check-In-Datei) ---------- */
|
||||||
|
function dt(?string $s): ?DateTimeImmutable {
|
||||||
|
if (!$s) return null;
|
||||||
|
try { return new DateTimeImmutable($s, new DateTimeZone(APP_TZ)); }
|
||||||
|
catch (Throwable $e) { return null; }
|
||||||
|
}
|
||||||
|
function dayStart(DateTimeImmutable $d): DateTimeImmutable {
|
||||||
|
return $d->setTime(0, 0, 0);
|
||||||
|
}
|
||||||
|
function rowClassForDate(?DateTimeImmutable $markDate, ?DateTimeImmutable $today): string {
|
||||||
|
if (!$markDate || !$today) return '';
|
||||||
|
if ($markDate == $today) return 'text-dark bg-warning';
|
||||||
|
if ($markDate < $today) return 'bg-danger';
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Row-Marking Quelle (Check-In) – identisch zu deiner Tabelle:
|
||||||
|
* 1 = $packingjob->date_end
|
||||||
|
* 2 = $NachbereitungsTimeDetail->date_start
|
||||||
|
* 3 = $RePackagingTimeDetail->date_start
|
||||||
|
* 4 = $PackingNoteDetail->date_redelivery
|
||||||
|
* Fallback: $packingjob->date_end
|
||||||
|
*/
|
||||||
|
function resolveRowMarkDateCheckIn(
|
||||||
|
$packingjob,
|
||||||
|
$NachbereitungsTimeDetail,
|
||||||
|
$RePackagingTimeDetail,
|
||||||
|
$PackingNoteDetail,
|
||||||
|
int $source
|
||||||
|
): ?DateTimeImmutable {
|
||||||
|
$candidate = null;
|
||||||
|
switch ($source) {
|
||||||
|
case 1: $candidate = dt($packingjob->date_end ?? null); break;
|
||||||
|
case 2: $candidate = dt($NachbereitungsTimeDetail->date_start ?? null); break;
|
||||||
|
case 3: $candidate = dt($RePackagingTimeDetail->date_start ?? null); break;
|
||||||
|
case 4: $candidate = dt($PackingNoteDetail->date_redelivery ?? null); break;
|
||||||
|
case 5: $candidate = dt($DispoTimeDetail->date_end ?? null); break;
|
||||||
|
default: $candidate = null; break;
|
||||||
|
}
|
||||||
|
if (!$candidate) {
|
||||||
|
$candidate = dt($packingjob->date_end ?? null);
|
||||||
|
}
|
||||||
|
return $candidate ? dayStart($candidate) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** ---------- Daten holen (wie in deiner Check-In-Datei) ---------- */
|
||||||
|
// Offene Packingnotes für Check-IN-Seite: isco=False
|
||||||
|
$result = $Epi->requestEpiApi('/v1/packingnote/open?isco=False&cl=' . Epirent_Mandant);
|
||||||
|
$data_output = json_decode($result)->payload ?? [];
|
||||||
|
|
||||||
|
/** ---------- Zähler ---------- */
|
||||||
|
$today = dayStart(new DateTimeImmutable('today', new DateTimeZone(APP_TZ)));
|
||||||
|
|
||||||
|
$limit = null;
|
||||||
|
if (CheckIn_FutureDays != -1) {
|
||||||
|
$limit = $today->modify('+' . (int)CheckIn_FutureDays . ' day');
|
||||||
|
}
|
||||||
|
|
||||||
|
$cntOverdue = 0;
|
||||||
|
$cntToday = 0;
|
||||||
|
$cntFuture = 0;
|
||||||
|
|
||||||
|
/** ---------- Zählen mit exakt deiner Logik ---------- */
|
||||||
|
foreach ($data_output as $packingjob) {
|
||||||
|
if ($packingjob->is_archived == true) continue;
|
||||||
|
|
||||||
|
// OrderDetails (für Nachbereitung / Rückpacken)
|
||||||
|
$orderRes = $Epi->requestEpiApi('/v1/order/' . $packingjob->order_pk . '?cl=' . Epirent_Mandant);
|
||||||
|
$orderdetail_output = json_decode($orderRes)->payload[0] ?? null;
|
||||||
|
|
||||||
|
// PackingNote Details (für Redelivery)
|
||||||
|
$pnRes = $Epi->requestEpiApi('/v1/packingnote/' . $packingjob->primary_key . '?cl=' . Epirent_Mandant);
|
||||||
|
$PackingNoteDetail = json_decode($pnRes)->payload[0] ?? null;
|
||||||
|
|
||||||
|
// Zeit-Slots aus dem Schedule
|
||||||
|
$NachbereitungsTimeDetail = null;
|
||||||
|
$RePackagingTimeDetail = null;
|
||||||
|
$DispoTimeDetail = null;
|
||||||
|
if ($orderdetail_output && !empty($orderdetail_output->order_schedule)) {
|
||||||
|
foreach ($orderdetail_output->order_schedule as $scheduledetail) {
|
||||||
|
if ($scheduledetail->name == Nachbereitung_Zeitvariable) {
|
||||||
|
$NachbereitungsTimeDetail = $scheduledetail;
|
||||||
|
}
|
||||||
|
if ($scheduledetail->name == Rückpacken_Zeitvariable) {
|
||||||
|
$RePackagingTimeDetail = $scheduledetail;
|
||||||
|
}
|
||||||
|
if ($scheduledetail->name == "Dispo") {
|
||||||
|
$DispoTimeDetail = $scheduledetail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Row-Mark Source (mit Override-Flag)
|
||||||
|
$source = CheckIn_UseDispoEndForRowMarking ? 1 : (int)CheckInRowMarkSource;
|
||||||
|
|
||||||
|
$markDate = resolveRowMarkDateCheckIn(
|
||||||
|
$packingjob,
|
||||||
|
$NachbereitungsTimeDetail,
|
||||||
|
$RePackagingTimeDetail,
|
||||||
|
$PackingNoteDetail,
|
||||||
|
$source
|
||||||
|
);
|
||||||
|
if (!$markDate) continue;
|
||||||
|
|
||||||
|
// Fenster berücksichtigen (gleich wie in deiner Tabelle)
|
||||||
|
if (CheckIn_FutureDays != -1 && $limit && $markDate > $limit) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zählen
|
||||||
|
if ($markDate < $today) {
|
||||||
|
$cntOverdue++;
|
||||||
|
} elseif ($markDate == $today) {
|
||||||
|
$cntToday++;
|
||||||
|
} else {
|
||||||
|
$cntFuture++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$ts = (new DateTimeImmutable('now', new DateTimeZone(APP_TZ)))->format('H:i:s');
|
||||||
|
?>
|
||||||
|
<h3 class="mb-3">
|
||||||
|
<span class="badge badge-secondary d-block w-100 py-2 text-center">CheckIn</span>
|
||||||
|
</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xl-4 col-md-6">
|
||||||
|
<div class="card bg-danger text-white mb-4">
|
||||||
|
<div class="card-body d-flex justify-content-between align-items-center">
|
||||||
|
<div>
|
||||||
|
<div class="small">Überfällige CheckIns</div>
|
||||||
|
<div class="h2 mb-0"><?= (int)$cntOverdue ?></div>
|
||||||
|
</div>
|
||||||
|
<i class="fa-solid fa-triangle-exclamation fa-2x" style="opacity:.6"></i>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer d-flex justify-content-between">
|
||||||
|
<span class="small text-white-50">Stand <?= htmlspecialchars($ts) ?></span>
|
||||||
|
<span class="small">bis <?= htmlspecialchars($today->format('d.m.Y')) ?></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-xl-4 col-md-6">
|
||||||
|
<div class="card bg-warning text-dark mb-4">
|
||||||
|
<div class="card-body d-flex justify-content-between align-items-center">
|
||||||
|
<div>
|
||||||
|
<div class="small">Heutige CheckIns</div>
|
||||||
|
<div class="h2 mb-0"><?= (int)$cntToday ?></div>
|
||||||
|
</div>
|
||||||
|
<i class="fa-solid fa-boxes-packing fa-2x" style="opacity:.6"></i>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer d-flex justify-content-between">
|
||||||
|
<span class="small text-muted">Stand <?= htmlspecialchars($ts) ?></span>
|
||||||
|
<span class="small"><?= htmlspecialchars($today->format('d.m.Y')) ?></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-xl-4 col-md-6">
|
||||||
|
<div class="card bg-success text-white mb-4">
|
||||||
|
<div class="card-body d-flex justify-content-between align-items-center">
|
||||||
|
<div>
|
||||||
|
<div class="small">
|
||||||
|
Zukünftige CheckIns
|
||||||
|
<?php if (CheckIn_FutureDays != -1 && $limit): ?>
|
||||||
|
(≤ <?= htmlspecialchars($limit->format('d.m.Y')) ?>)
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
<div class="h2 mb-0"><?= (int)$cntFuture ?></div>
|
||||||
|
</div>
|
||||||
|
<i class="fa-solid fa-forward-step fa-2x" style="opacity:.6"></i>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer d-flex justify-content-between">
|
||||||
|
<span class="small text-white-50">Stand <?= htmlspecialchars($ts) ?></span>
|
||||||
|
<span class="small">
|
||||||
|
<?php if (CheckIn_FutureDays == -1): ?>
|
||||||
|
unbegrenzt
|
||||||
|
<?php else: ?>
|
||||||
|
bis <?= htmlspecialchars($limit->format('d.m.Y')) ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -10,148 +10,274 @@ use chillerlan\QRCode\{
|
|||||||
|
|
||||||
require('../vendor/autoload.php');
|
require('../vendor/autoload.php');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
$options = new QROptions([
|
$options = new QROptions([
|
||||||
'imageBase64' => false,
|
'imageBase64' => false,
|
||||||
'qrCodeHeight' => 75,
|
'qrCodeHeight' => 75,
|
||||||
'qrCodeWidth' => 75,
|
'qrCodeWidth' => 75,
|
||||||
'version' => -1,
|
'version' => -1,
|
||||||
'quietzoneSize' => 1
|
'quietzoneSize' => 1
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
||||||
$Epi = new Epirent();
|
$Epi = new Epirent();
|
||||||
|
|
||||||
|
|
||||||
$result = $Epi->requestEpiApi('/v1/packingnote/open?isco=False&cl=' . Epirent_Mandant);
|
$result = $Epi->requestEpiApi('/v1/packingnote/open?isco=False&cl=' . Epirent_Mandant);
|
||||||
|
|
||||||
$data_output = json_decode($result)->payload;
|
$data_output = json_decode($result)->payload;
|
||||||
|
|
||||||
|
/** ---------- Helpers & Marking (analog Checkout) ---------- */
|
||||||
|
const APP_TZ = 'Europe/Berlin';
|
||||||
|
|
||||||
|
function dt(?string $s): ?DateTimeImmutable {
|
||||||
|
if (!$s) return null;
|
||||||
|
try {
|
||||||
|
return new DateTimeImmutable($s, new DateTimeZone(APP_TZ));
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function dayStart(DateTimeImmutable $d): DateTimeImmutable {
|
||||||
|
return $d->setTime(0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function rowClassForDate(?DateTimeImmutable $markDate, ?DateTimeImmutable $today): string {
|
||||||
|
if (!$markDate || !$today) return '';
|
||||||
|
if ($markDate == $today) return 'text-dark bg-warning';
|
||||||
|
if ($markDate < $today) return 'bg-danger';
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Row-Marking Quelle (Check-In):
|
||||||
|
* 1 = $packingjob->date_end
|
||||||
|
* 2 = $NachbereitungsTimeDetail->date_start
|
||||||
|
* 3 = $RePackagingTimeDetail->date_start
|
||||||
|
* 4 = $PackingNoteDetail->date_redelivery
|
||||||
|
* Fallback: $packingjob->date_end
|
||||||
|
*/
|
||||||
|
function resolveRowMarkDateCheckIn(
|
||||||
|
$packingjob,
|
||||||
|
$NachbereitungsTimeDetail,
|
||||||
|
$RePackagingTimeDetail,
|
||||||
|
$PackingNoteDetail,
|
||||||
|
$DispoTimeDetail,
|
||||||
|
int $source
|
||||||
|
): ?DateTimeImmutable {
|
||||||
|
$candidate = null;
|
||||||
|
switch ($source) {
|
||||||
|
case 1: $candidate = dt($packingjob->date_end ?? null); break;
|
||||||
|
case 2: $candidate = dt($NachbereitungsTimeDetail->date_start ?? null); break;
|
||||||
|
case 3: $candidate = dt($RePackagingTimeDetail->date_start ?? null); break;
|
||||||
|
case 4: $candidate = dt($PackingNoteDetail->date_redelivery ?? null); break;
|
||||||
|
case 5: $candidate = dt($DispoTimeDetail->date_end ?? null); break;
|
||||||
|
|
||||||
|
default: $candidate = null; break;
|
||||||
|
}
|
||||||
|
if (!$candidate) {
|
||||||
|
$candidate = dt($packingjob->date_end ?? null);
|
||||||
|
}
|
||||||
|
return $candidate ? dayStart($candidate) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function echoMarkedTimeLine(?string $dateStr, ?int $timeSeconds, DateTimeImmutable $today, $ReturnTime): void {
|
||||||
|
if (!$dateStr) return;
|
||||||
|
$d = dt($dateStr);
|
||||||
|
if (!$d) return;
|
||||||
|
|
||||||
|
$mark = dayStart($d);
|
||||||
|
$cls = rowClassForDate($mark, $today);
|
||||||
|
|
||||||
|
echo $cls ? "<span class=\"{$cls}\">" : "";
|
||||||
|
echo date_format(new \DateTime($dateStr), 'd.m.Y');
|
||||||
|
if ($ReturnTime) {
|
||||||
|
echo " " . getTimeFromSeconds((string)$timeSeconds);
|
||||||
|
}
|
||||||
|
echo $cls ? "</span>" : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/** ---------- Sortierung nach Ende ---------- */
|
||||||
if (SortCheckIn == 2) {
|
if (SortCheckIn == 2) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Prüfen, ob $data_output ein Array ist
|
|
||||||
if (is_array($data_output)) {
|
if (is_array($data_output)) {
|
||||||
usort($data_output, function ($a, $b) {
|
usort($data_output, function ($a, $b) {
|
||||||
// Konvertiere time_start von Millisekunden in Sekunden
|
$timeEndA = $a->time_end / 1000;
|
||||||
$timeStartA = $a->time_end / 1000; // Zeit in Sekunden
|
$timeEndB = $b->time_end / 1000;
|
||||||
$timeStartB = $b->time_end / 1000;
|
$datetimeA = strtotime($a->date_end) + $timeEndA;
|
||||||
|
$datetimeB = strtotime($b->date_end) + $timeEndB;
|
||||||
// Kombiniere date_start mit time_start
|
|
||||||
$datetimeA = strtotime($a->date_end) + $timeStartA;
|
|
||||||
$datetimeB = strtotime($b->date_end) + $timeStartB;
|
|
||||||
|
|
||||||
// Vergleich für die Sortierung
|
|
||||||
return $datetimeA <=> $datetimeB;
|
return $datetimeA <=> $datetimeB;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Sortierte Daten ausgeben oder weiterverarbeiten
|
|
||||||
// print_r($data_output);
|
|
||||||
} else {
|
} else {
|
||||||
echo "Daten konnten nicht verarbeitet werden.";
|
echo "Daten konnten nicht verarbeitet werden.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** ---------- Tabelle ---------- */
|
||||||
|
|
||||||
foreach ($data_output as $packingjob) {
|
foreach ($data_output as $packingjob) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if ($packingjob->is_archived != true) {
|
if ($packingjob->is_archived != true) {
|
||||||
|
|
||||||
//get OrderDetails
|
// OrderDetails
|
||||||
$result = $Epi->requestEpiApi('/v1/order/' . $packingjob->order_pk . '?cl=' . Epirent_Mandant);
|
$result = $Epi->requestEpiApi('/v1/order/' . $packingjob->order_pk . '?cl=' . Epirent_Mandant);
|
||||||
|
|
||||||
$orderdetail_output = json_decode($result)->payload[0];
|
$orderdetail_output = json_decode($result)->payload[0];
|
||||||
|
|
||||||
$NachbereitungsTimeDetail;
|
// PackingNote Details
|
||||||
|
$PackingNoteDetailResult = $Epi->requestEpiApi('/v1/packingnote/' . $packingjob->primary_key . '?cl=' . Epirent_Mandant);
|
||||||
|
$PackingNoteDetail = json_decode($PackingNoteDetailResult)->payload[0];
|
||||||
|
|
||||||
|
// Zeit-Slots aus dem Schedule
|
||||||
|
$NachbereitungsTimeDetail = null;
|
||||||
|
$RePackagingTimeDetail = null;
|
||||||
|
$DispoTimeDetail = null;
|
||||||
foreach ($orderdetail_output->order_schedule as $scheduledetail) {
|
foreach ($orderdetail_output->order_schedule as $scheduledetail) {
|
||||||
|
if ($scheduledetail->name == Nachbereitung_Zeitvariable) {
|
||||||
if ($scheduledetail->name == Rueckpacken_Zeitvariable) {
|
|
||||||
$NachbereitungsTimeDetail = $scheduledetail;
|
$NachbereitungsTimeDetail = $scheduledetail;
|
||||||
}
|
}
|
||||||
}
|
if ($scheduledetail->name == Rückpacken_Zeitvariable) {
|
||||||
|
$RePackagingTimeDetail = $scheduledetail;
|
||||||
|
|
||||||
//End Of get Order Details
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (CheckIn_UseDispoEndForRowMarking || ($NachbereitungsTimeDetail->date_start == null)) {
|
|
||||||
$date = new DateTime($packingjob->date_end);
|
|
||||||
} else {
|
|
||||||
$date = new DateTime($NachbereitungsTimeDetail->date_start);
|
|
||||||
}
|
|
||||||
$date->setTime(0, 0, 0);
|
|
||||||
$today = new DateTime();
|
|
||||||
$today->setTime(0, 0, 0);
|
|
||||||
$todayFilter = new DateTime();
|
|
||||||
$todayFilter->setTime(0, 0, 0);
|
|
||||||
if (CheckIn_FutureDays == -1 || $date <= ($todayFilter->modify('+' . CheckIn_FutureDays . ' day'))) {
|
|
||||||
//prüfe, ob entweder unbegrenzte (-1) Anzeige Aktiv ist, oder das Datum kleiner oder Gleich heute + Zukunftsspanne ist
|
|
||||||
|
|
||||||
if ($date == $today) {
|
|
||||||
|
|
||||||
echo "<tr class='text-dark bg-warning'>";
|
|
||||||
} else if ($date < $today) {
|
|
||||||
echo "<tr class=' bg-danger'>";
|
|
||||||
} else {
|
|
||||||
echo "<tr>";
|
|
||||||
}
|
}
|
||||||
|
if ($scheduledetail->name == "Dispo") {
|
||||||
|
$DispoTimeDetail = $scheduledetail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Row-Marking bestimmen (konfigurierbar, analog Checkout) ---
|
||||||
|
$today = dayStart(new DateTimeImmutable('today', new DateTimeZone(APP_TZ)));
|
||||||
|
$limit = null;
|
||||||
|
if (CheckIn_FutureDays != -1) {
|
||||||
|
$limit = $today->modify('+' . (int)CheckIn_FutureDays . ' day');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Override-Flag wie bei Checkout: Dispo-Ende erzwingen
|
||||||
|
$source = CheckIn_UseDispoEndForRowMarking ? 1 : (int)CheckInRowMarkSource;
|
||||||
|
|
||||||
|
$markDate = resolveRowMarkDateCheckIn(
|
||||||
|
$packingjob,
|
||||||
|
$NachbereitungsTimeDetail,
|
||||||
|
$RePackagingTimeDetail,
|
||||||
|
$PackingNoteDetail,
|
||||||
|
$DispoTimeDetail,
|
||||||
|
$source
|
||||||
|
);
|
||||||
|
|
||||||
|
if (CheckIn_FutureDays == -1 || ($markDate && (!$limit || $markDate <= $limit))) {
|
||||||
|
$trClass = rowClassForDate($markDate, $today);
|
||||||
|
echo $trClass ? "<tr class='{$trClass}'>" : "<tr>";
|
||||||
|
|
||||||
|
// QR / Kopfspalten
|
||||||
if (Enable_QR_Code_CheckIn) {
|
if (Enable_QR_Code_CheckIn) {
|
||||||
echo "<td>" . '<div style="width: 5vb;">' . (new QRCode($options))->render($packingjob->packingnote_no) . "</div></td>";
|
echo "<td><div style=\"width: 5vb;\">" . (new QRCode($options))->render($packingjob->packingnote_no) . "</div></td>";
|
||||||
} else {
|
} else {
|
||||||
echo "<td>" . $packingjob->packingnote_no . "</td>";
|
echo "<td>" . $packingjob->packingnote_no . "</td>";
|
||||||
}
|
}
|
||||||
echo "<td>" . $packingjob->contact->name . "</td>";
|
echo "<td>" . $packingjob->contact->name . "</td>";
|
||||||
echo "<td>" . $packingjob->event . "</td>";
|
echo "<td>" . $packingjob->event . "</td>";
|
||||||
if(!HideCheckOutTimeOnCheckin){
|
|
||||||
if ($NachbereitungsTimeDetail->date_start != null) {
|
// Zeitspalte öffnen, wenn mindestens eine Anzeige aktiv ist
|
||||||
echo "<td><small>" . date_format(new \DateTime($packingjob->date_start), 'd.m.Y') . " " . getTimeFromSeconds($packingjob->time_start) . "</small><br><i>" . date_format(new \DateTime($NachbereitungsTimeDetail->date_start), 'd.m.Y') . " " . getTimeFromSeconds($NachbereitungsTimeDetail->time_start) . "</i></td>";
|
if (ShowCheckInTimeOnCheckin || ShowNachbereitungTimeOnCheckin || ShowRePackagingTimeOnCheckin || ShowReDeliveryTimeOnCheckin || ShowDispoEndOnCheckin) {
|
||||||
} else {
|
echo "<td>";
|
||||||
echo "<td>" . date_format(new \DateTime($packingjob->date_start), 'd.m.Y') . " " . getTimeFromSeconds($packingjob->time_start) . "</td>";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Dispo-Ende (Check-In Termin) — ENDE korrekt verwendet
|
||||||
|
if (ShowCheckInTimeOnCheckin && $packingjob->date_end != null) {
|
||||||
|
echoMarkedTimeLine($packingjob->date_end, (int)$packingjob->time_end, $today, ShowTimesOnCheckin);
|
||||||
}
|
}
|
||||||
if ($NachbereitungsTimeDetail->date_end != null) {
|
|
||||||
echo "<td><small>" . date_format(new \DateTime($packingjob->date_end), 'd.m.Y') . " " . getTimeFromSeconds($packingjob->time_end) . "</small><br><i>" . date_format(new \DateTime($NachbereitungsTimeDetail->date_end), 'd.m.Y') . " " . getTimeFromSeconds($NachbereitungsTimeDetail->time_end) . "</i></td>";
|
// Nachbereitung (START) — wie von dir bereits genutzt
|
||||||
} else {
|
if (ShowNachbereitungTimeOnCheckin && $NachbereitungsTimeDetail && $NachbereitungsTimeDetail->date_start != null) {
|
||||||
echo "<td>" . date_format(new \DateTime($packingjob->date_end), 'd.m.Y') . " " . getTimeFromSeconds($packingjob->time_end) . "</td>";
|
if (ShowCheckInTimeOnCheckin) echo "<br>";
|
||||||
|
echoMarkedTimeLine($NachbereitungsTimeDetail->date_start, (int)$NachbereitungsTimeDetail->time_start, $today, ShowTimesOnCheckin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Rückpacken (START)
|
||||||
|
if (ShowRePackagingTimeOnCheckin && $RePackagingTimeDetail && $RePackagingTimeDetail->date_start != null) {
|
||||||
|
if (ShowCheckInTimeOnCheckin || ShowNachbereitungTimeOnCheckin) echo "<br>";
|
||||||
|
echoMarkedTimeLine($RePackagingTimeDetail->date_start, (int)$RePackagingTimeDetail->time_start, $today, ShowTimesOnCheckin);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rücklieferung (REDELIVERY) — delivery ↔ redelivery gespiegelt
|
||||||
|
if (ShowReDeliveryTimeOnCheckin && $PackingNoteDetail && $PackingNoteDetail->date_redelivery != null) {
|
||||||
|
if (ShowCheckInTimeOnCheckin || ShowNachbereitungTimeOnCheckin || ShowRePackagingTimeOnCheckin) echo "<br>";
|
||||||
|
echoMarkedTimeLine($PackingNoteDetail->date_redelivery, (int)$PackingNoteDetail->time_redelivery, $today, ShowTimesOnCheckin);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dispo Ende
|
||||||
|
if (ShowDispoEndOnCheckin && $DispoTimeDetail && $DispoTimeDetail->date_end != null) {
|
||||||
|
if (ShowCheckInTimeOnCheckin || ShowNachbereitungTimeOnCheckin || ShowRePackagingTimeOnCheckin || ShowReDeliveryTimeOnCheckin) echo "<br>";
|
||||||
|
echoMarkedTimeLine($DispoTimeDetail->date_end, (int)$DispoTimeDetail->time_end, $today, ShowTimesOnCheckin);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ShowCheckInTimeOnCheckin || ShowNachbereitungTimeOnCheckin || ShowRePackagingTimeOnCheckin || ShowReDeliveryTimeOnCheckin || ShowDispoEndOnCheckin) {
|
||||||
|
echo "</td>";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fortschritt
|
||||||
echo "<td>";
|
echo "<td>";
|
||||||
|
if ($packingjob->is_all_in == 0) {
|
||||||
|
|
||||||
|
|
||||||
if ($packingjob->is_all_in ==0) {
|
|
||||||
echo "<span class='badge badge-success'>";
|
echo "<span class='badge badge-success'>";
|
||||||
} else {
|
} else {
|
||||||
|
echo '<div class="progress"><div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" style="width: ' .
|
||||||
echo '<div class="progress"><div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" style="width: '.(( $packingjob->pieces_sum_total - abs($packingjob->is_all_out) - abs($packingjob->is_all_in)) / ($packingjob->pieces_sum_total - $packingjob ->is_all_out)) *100 .'%" aria-valuenow="' .( $packingjob->pieces_sum_total - abs($packingjob->is_all_out) - abs($packingjob->is_all_in)) . '" aria-valuemin="0" aria-valuemax="' . ($packingjob->pieces_sum_total - $packingjob ->is_all_out). '"></div></div>';
|
(( $packingjob->pieces_sum_total - abs($packingjob->is_all_out) - abs($packingjob->is_all_in)) / ($packingjob->pieces_sum_total - $packingjob->is_all_out)) * 100 .
|
||||||
|
'%" aria-valuenow="' . ( $packingjob->pieces_sum_total - abs($packingjob->is_all_out) - abs($packingjob->is_all_in)) .
|
||||||
|
'" aria-valuemin="0" aria-valuemax="' . ($packingjob->pieces_sum_total - $packingjob->is_all_out) . '"></div></div>';
|
||||||
echo "<span class='badge badge-info'>";
|
echo "<span class='badge badge-info'>";
|
||||||
}
|
}
|
||||||
|
echo ( $packingjob->pieces_sum_total - abs($packingjob->is_all_out) - abs($packingjob->is_all_in)) . "/" . ($packingjob->pieces_sum_total - $packingjob->is_all_out) . " (" . $packingjob->pieces_sum_total . ")";
|
||||||
echo ( $packingjob->pieces_sum_total - abs($packingjob->is_all_out) - abs($packingjob->is_all_in)) . "/" . ($packingjob->pieces_sum_total - $packingjob ->is_all_out) . " (" . $packingjob->pieces_sum_total.")";
|
echo "</span></td>";
|
||||||
echo "</span><td>";
|
|
||||||
|
// Shipping-Icons (inbound)
|
||||||
|
if (ShowShippingIcons) {
|
||||||
|
if (UseShippingStatus) {
|
||||||
|
if (($PackingNoteDetail->status == ShippingInOrganizedStatus) || ($PackingNoteDetail->status == ShippingOrganizedStatus)) {
|
||||||
|
echo "<td style='color:#66FF00; text-align:center;'>";
|
||||||
|
} else {
|
||||||
|
echo "<td style='text-align:center;'>";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($PackingNoteDetail->is_self_redeliver) {
|
||||||
|
echo '<i class="'.SelbstabholerIcon.'"></i>';
|
||||||
|
} else {
|
||||||
|
if (preg_match('/' . KurierContainsText . '/i', $PackingNoteDetail->shipping_in)) {
|
||||||
|
echo '<i class="'.KurierIcon.'"></i>';
|
||||||
|
}
|
||||||
|
if (preg_match('/' . SpeditionContainsText . '/i', $PackingNoteDetail->shipping_in)) {
|
||||||
|
echo '<i class="'.SpeditionIcon.'"></i>';
|
||||||
|
}
|
||||||
|
if (preg_match('/' . DHLContainsText . '/i', $PackingNoteDetail->shipping_in)) {
|
||||||
|
echo '<i class="'.DHLIcon.'"></i>';
|
||||||
|
}
|
||||||
|
if (preg_match('/' . LKWContainsText . '/i', $PackingNoteDetail->shipping_in)) {
|
||||||
|
echo '<i class="fa-solid fa-industry fa-lg"></i><i class="'.LKWIcon.'"></i>';
|
||||||
|
}
|
||||||
|
if (preg_match('/' . TransporterContainsText . '/i', $PackingNoteDetail->shipping_in)) {
|
||||||
|
echo '<i class="fa-solid fa-industry fa-lg"></i><i class="'.TransporterIcon.'"></i>';
|
||||||
|
}
|
||||||
|
if (preg_match('/' . PKWContainsText . '/i', $PackingNoteDetail->shipping_in)) {
|
||||||
|
echo '<i class="fa-solid fa-industry fa-lg"></i><i class="'.PKWIcon.'"></i>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
echo "</td>";
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "</tr>";
|
||||||
|
}
|
||||||
|
|
||||||
echo "</tr>";
|
echo "</tr>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTimeFromSeconds(string $timestring) {
|
function getTimeFromSeconds($seconds): string {
|
||||||
|
if ($seconds === null || $seconds === '') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
$hours = floor($timestring / 3600);
|
// robust normalisieren: String/Float -> Float -> gerundet -> Int
|
||||||
$mins = floor($timestring / 60 % 60);
|
$seconds = (int) round((float) $seconds);
|
||||||
$secs = floor($timestring % 60);
|
|
||||||
|
|
||||||
$timeFormat = sprintf('%02d:%02d', $hours, $mins);
|
if ($seconds < 0) {
|
||||||
|
$seconds = 0; // oder: return ''; je nach gewünschtem Verhalten
|
||||||
|
}
|
||||||
|
|
||||||
return $timeFormat;
|
// reine Integer-Arithmetik, keine impliziten float->int Casts
|
||||||
|
$hours = intdiv($seconds, 3600);
|
||||||
|
$mins = intdiv($seconds % 3600, 60);
|
||||||
|
|
||||||
|
return sprintf('%02d:%02d', $hours, $mins);
|
||||||
}
|
}
|
||||||
|
|
||||||
?>
|
|
||||||
189
sources/getCheckOutCards.php
Normal file
189
sources/getCheckOutCards.php
Normal file
@@ -0,0 +1,189 @@
|
|||||||
|
<?php
|
||||||
|
// sources/getCheckoutTable.php – zählt statt Tabellenausgabe drei KPIs als Karten
|
||||||
|
error_reporting(E_ALL);
|
||||||
|
require('../config.php');
|
||||||
|
require('../EpiApi.php');
|
||||||
|
|
||||||
|
$Epi = new Epirent();
|
||||||
|
|
||||||
|
const APP_TZ = 'Europe/Berlin';
|
||||||
|
|
||||||
|
/** ---- Helpers (aus deiner bisherigen Datei) ---- */
|
||||||
|
function dt(?string $s): ?DateTimeImmutable {
|
||||||
|
if (!$s) return null;
|
||||||
|
try { return new DateTimeImmutable($s, new DateTimeZone(APP_TZ)); }
|
||||||
|
catch (Throwable $e) { return null; }
|
||||||
|
}
|
||||||
|
function dayStart(DateTimeImmutable $d): DateTimeImmutable {
|
||||||
|
return $d->setTime(0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Quelle für das Markierungsdatum (identisch zu deiner Liste):
|
||||||
|
* 1 = $packingjob->date_start
|
||||||
|
* 2 = $VorbereitungsTimeDetail->date_start
|
||||||
|
* 3 = $PackingNoteDetail->date_packing
|
||||||
|
* 4 = $PackingNoteDetail->date_delivery
|
||||||
|
* Fallback: $packingjob->date_start
|
||||||
|
*/
|
||||||
|
function resolveRowMarkDate($packingjob, $VorbereitungsTimeDetail, $PackingNoteDetail, int $source): ?DateTimeImmutable {
|
||||||
|
$candidate = null;
|
||||||
|
switch ($source) {
|
||||||
|
case 1: $candidate = dt($packingjob->date_start ?? null); break;
|
||||||
|
case 2: $candidate = dt($VorbereitungsTimeDetail->date_start ?? null); break;
|
||||||
|
case 3: $candidate = dt($PackingNoteDetail->date_packing ?? null); break;
|
||||||
|
case 4: $candidate = dt($PackingNoteDetail->date_delivery ?? null); break;
|
||||||
|
default:$candidate = null; break;
|
||||||
|
}
|
||||||
|
if (!$candidate) $candidate = dt($packingjob->date_start ?? null);
|
||||||
|
return $candidate ? dayStart($candidate) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** ---- Daten laden wie bisher (Checkout-Quelle) ---- */
|
||||||
|
if (UseDeliveredForCheckOutCompleted) {
|
||||||
|
// isco=False -> Checkout-Ansicht offen
|
||||||
|
$result = $Epi->requestEpiApi('/v1/packingnote/open?isco=False&cl=' . Epirent_Mandant);
|
||||||
|
} else {
|
||||||
|
// isci=False -> Alternative Logik (wie in deiner Datei)
|
||||||
|
$result = $Epi->requestEpiApi('/v1/packingnote/open?isci=False&cl=' . Epirent_Mandant);
|
||||||
|
}
|
||||||
|
$data_output = json_decode($result)->payload ?? [];
|
||||||
|
|
||||||
|
/** ---- Zähler vorbereiten ---- */
|
||||||
|
$today = dayStart(new DateTimeImmutable('today', new DateTimeZone(APP_TZ)));
|
||||||
|
$limit = null; // optionales Fenster wie in deiner Liste
|
||||||
|
if (CheckOut_FutureDays != -1) {
|
||||||
|
$limit = $today->modify('+' . (int)CheckOut_FutureDays . ' day');
|
||||||
|
}
|
||||||
|
|
||||||
|
$cntOverdue = 0;
|
||||||
|
$cntToday = 0;
|
||||||
|
$cntFuture = 0;
|
||||||
|
|
||||||
|
/** ---- Iteration identisch zur bisherigen Logik ---- */
|
||||||
|
foreach ($data_output as $packingjob) {
|
||||||
|
|
||||||
|
// Details nur holen, wenn nötig & wie gehabt
|
||||||
|
$PackingNoteDetail = null;
|
||||||
|
if ($packingjob->is_archived != true && UseDeliveredForCheckOutCompleted) {
|
||||||
|
$PackingNoteDetailResult = $Epi->requestEpiApi('/v1/packingnote/' . $packingjob->primary_key . '?cl=' . Epirent_Mandant);
|
||||||
|
$PackingNoteDetail = json_decode($PackingNoteDetailResult)->payload[0] ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Aufnahmebedingung exakt wie bei dir:
|
||||||
|
if (
|
||||||
|
$packingjob->is_archived != true
|
||||||
|
&& (
|
||||||
|
!UseDeliveredForCheckOutCompleted
|
||||||
|
|| ($PackingNoteDetail && ($PackingNoteDetail->date_delivered !== "0000-00-00" || (int)$PackingNoteDetail->time_delivered !== 0))
|
||||||
|
)
|
||||||
|
&& ($PackingNoteDetail && (int)$PackingNoteDetail->is_all_out !== 0)
|
||||||
|
) {
|
||||||
|
// OrderDetails (für Vorbereitungszeit)
|
||||||
|
$result = $Epi->requestEpiApi('/v1/order/' . $packingjob->order_pk . '?cl=' . Epirent_Mandant);
|
||||||
|
$orderdetail_output = (json_decode($result)->payload[0] ?? null);
|
||||||
|
|
||||||
|
// PackingNoteDetail nachladen, falls oben noch nicht geholt
|
||||||
|
if (!UseDeliveredForCheckOutCompleted) {
|
||||||
|
$PackingNoteDetailResult = $Epi->requestEpiApi('/v1/packingnote/' . $packingjob->primary_key . '?cl=' . Epirent_Mandant);
|
||||||
|
$PackingNoteDetail = json_decode($PackingNoteDetailResult)->payload[0] ?? null;
|
||||||
|
if (!$PackingNoteDetail) continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vorbereitungs-Zeitdetail ermitteln
|
||||||
|
$VorbereitungsTimeDetail = null;
|
||||||
|
if ($orderdetail_output && !empty($orderdetail_output->order_schedule)) {
|
||||||
|
foreach ($orderdetail_output->order_schedule as $scheduledetail) {
|
||||||
|
if ($scheduledetail->name == Vorbereitungs_Zeitvariable) {
|
||||||
|
$VorbereitungsTimeDetail = $scheduledetail;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Markierungsdatum wie in der Tabelle
|
||||||
|
$markDate = resolveRowMarkDate($packingjob, $VorbereitungsTimeDetail, $PackingNoteDetail, (int)CheckOutRowMarkSource);
|
||||||
|
if (!$markDate) continue;
|
||||||
|
|
||||||
|
// Optionales Zukunftsfenster berücksichtigen (wie bisher)
|
||||||
|
if (CheckOut_FutureDays != -1 && $limit && $markDate > $limit) {
|
||||||
|
// außerhalb des Fensters ignorieren
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zählen
|
||||||
|
if ($markDate < $today) {
|
||||||
|
$cntOverdue++;
|
||||||
|
} elseif ($markDate == $today) {
|
||||||
|
$cntToday++;
|
||||||
|
} else { // $markDate > $today
|
||||||
|
$cntFuture++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zeitstempel für die Karten
|
||||||
|
$ts = (new DateTimeImmutable('now', new DateTimeZone(APP_TZ)))->format('H:i:s');
|
||||||
|
|
||||||
|
/** ---- Ausgabe: 3 Bootstrap-Karten ---- */
|
||||||
|
?>
|
||||||
|
<h3 class="mb-3">
|
||||||
|
<span class="badge badge-secondary d-block w-100 py-2 text-center">Checkout</span>
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<div class="col-xl-4 col-md-6">
|
||||||
|
<div class="card bg-danger text-white mb-4">
|
||||||
|
<div class="card-body d-flex justify-content-between align-items-center">
|
||||||
|
<div>
|
||||||
|
<div class="small">Überfällige CheckOuts</div>
|
||||||
|
<div class="h2 mb-0"><?= (int)$cntOverdue ?></div>
|
||||||
|
</div>
|
||||||
|
<i class="fa-solid fa-triangle-exclamation fa-2x" style="opacity:.6"></i>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer d-flex justify-content-between">
|
||||||
|
<span class="small text-white-50">Stand <?= htmlspecialchars($ts) ?></span>
|
||||||
|
<span class="small">bis <?= htmlspecialchars($today->format('d.m.Y')) ?></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-xl-4 col-md-6">
|
||||||
|
<div class="card bg-warning text-dark mb-4">
|
||||||
|
<div class="card-body d-flex justify-content-between align-items-center">
|
||||||
|
<div>
|
||||||
|
<div class="small">Heutige CheckOuts</div>
|
||||||
|
<div class="h2 mb-0"><?= (int)$cntToday ?></div>
|
||||||
|
</div>
|
||||||
|
<i class="fa-solid fa-dolly fa-2x" style="opacity:.6"></i>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer d-flex justify-content-between">
|
||||||
|
<span class="small text-muted">Stand <?= htmlspecialchars($ts) ?></span>
|
||||||
|
<span class="small"><?= htmlspecialchars($today->format('d.m.Y')) ?></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-xl-4 col-md-6">
|
||||||
|
<div class="card bg-success text-white mb-4">
|
||||||
|
<div class="card-body d-flex justify-content-between align-items-center">
|
||||||
|
<div>
|
||||||
|
<div class="small">Zukünftige CheckOuts<?= (CheckOut_FutureDays != -1 ? ' (≤ '.$limit->format('d.m.Y').')' : '') ?></div>
|
||||||
|
<div class="h2 mb-0"><?= (int)$cntFuture ?></div>
|
||||||
|
</div>
|
||||||
|
<i class="fa-solid fa-forward-step fa-2x" style="opacity:.6"></i>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer d-flex justify-content-between">
|
||||||
|
<span class="small text-white-50">Stand <?= htmlspecialchars($ts) ?></span>
|
||||||
|
<span class="small">
|
||||||
|
<?php if (CheckOut_FutureDays == -1): ?>
|
||||||
|
unbegrenzt
|
||||||
|
<?php else: ?>
|
||||||
|
bis <?= htmlspecialchars($limit->format('d.m.Y')) ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
|
||||||
error_reporting(E_ALL);
|
error_reporting(E_ALL);
|
||||||
require('../config.php');
|
require('../config.php');
|
||||||
require('../EpiApi.php');
|
require('../EpiApi.php');
|
||||||
@@ -19,20 +20,67 @@ $options = new QROptions([
|
|||||||
'quietzoneSize' => 1
|
'quietzoneSize' => 1
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
||||||
$Epi = new Epirent();
|
$Epi = new Epirent();
|
||||||
|
|
||||||
|
const APP_TZ = 'Europe/Berlin';
|
||||||
|
|
||||||
$result = $Epi->requestEpiApi('/v1/packingnote/open?isci=False&cl=' . Epirent_Mandant);
|
/** Hilfsfunktionen für die Row-Marking-Logik (ohne weitere Änderungen am Rest) */
|
||||||
|
function dt(?string $s): ?DateTimeImmutable {
|
||||||
|
if (!$s)
|
||||||
|
return null;
|
||||||
|
try {
|
||||||
|
return new DateTimeImmutable($s, new DateTimeZone(APP_TZ));
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function dayStart(DateTimeImmutable $d): DateTimeImmutable {
|
||||||
|
return $d->setTime(0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveRowMarkDate($packingjob, $VorbereitungsTimeDetail, $PackingNoteDetail, $DispoTimeDetail, int $source): ?DateTimeImmutable {
|
||||||
|
$candidate = null;
|
||||||
|
switch ($source) {
|
||||||
|
case 1: $candidate = dt($packingjob->date_start ?? null);
|
||||||
|
break;
|
||||||
|
case 2: $candidate = dt($VorbereitungsTimeDetail->date_start ?? null);
|
||||||
|
break;
|
||||||
|
case 3: $candidate = dt($PackingNoteDetail->date_packing ?? null);
|
||||||
|
break;
|
||||||
|
case 4: $candidate = dt($PackingNoteDetail->date_delivery ?? null);
|
||||||
|
break;
|
||||||
|
case 5: $candidate = dt($DispoTimeDetail->date_start ?? null);
|
||||||
|
break;
|
||||||
|
default: $candidate = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!$candidate) {
|
||||||
|
$candidate = dt($packingjob->date_start ?? null);
|
||||||
|
}
|
||||||
|
return $candidate ? dayStart($candidate) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function rowClassForDate(?DateTimeImmutable $markDate, ?DateTimeImmutable $today): string {
|
||||||
|
if (!$markDate || !$today)
|
||||||
|
return '';
|
||||||
|
if ($markDate == $today)
|
||||||
|
return 'text-dark bg-warning';
|
||||||
|
if ($markDate < $today)
|
||||||
|
return 'bg-danger';
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (UseDeliveredForCheckOutCompleted) {
|
||||||
|
$result = $Epi->requestEpiApi('/v1/packingnote/open?isci=true&cl=' . Epirent_Mandant);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$result = $Epi->requestEpiApi('/v1/packingnote/open?isci=False&cl=' . Epirent_Mandant);
|
||||||
|
}
|
||||||
$data_output = json_decode($result)->payload;
|
$data_output = json_decode($result)->payload;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (SortCheckOut == 2) {
|
if (SortCheckOut == 2) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Prüfen, ob $data_output ein Array ist
|
// Prüfen, ob $data_output ein Array ist
|
||||||
if (is_array($data_output)) {
|
if (is_array($data_output)) {
|
||||||
usort($data_output, function ($a, $b) {
|
usort($data_output, function ($a, $b) {
|
||||||
@@ -57,45 +105,60 @@ if (SortCheckOut == 2) {
|
|||||||
|
|
||||||
foreach ($data_output as $packingjob) {
|
foreach ($data_output as $packingjob) {
|
||||||
|
|
||||||
|
$PackingNoteDetail = null;
|
||||||
|
|
||||||
|
if ($packingjob->is_archived != true && UseDeliveredForCheckOutCompleted) {
|
||||||
|
$PackingNoteDetailResult = $Epi->requestEpiApi('/v1/packingnote/' . $packingjob->primary_key . '?cl=' . Epirent_Mandant);
|
||||||
|
$PackingNoteDetail = json_decode($PackingNoteDetailResult)->payload[0];
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
if ($packingjob->is_archived != true) {
|
($packingjob->is_archived ?? false) != true
|
||||||
|
&& (
|
||||||
|
((int)($PackingNoteDetail->is_all_out ?? 0)) !== 0
|
||||||
|
|| (($PackingNoteDetail->date_delivered ?? "0000-00-00") === "0000-00-00"
|
||||||
|
|| (int)($PackingNoteDetail->time_delivered ?? 0) === 0)
|
||||||
|
)
|
||||||
|
) {
|
||||||
//get OrderDetails
|
//get OrderDetails
|
||||||
$result = $Epi->requestEpiApi('/v1/order/' . $packingjob->order_pk . '?cl=' . Epirent_Mandant);
|
$result = $Epi->requestEpiApi('/v1/order/' . $packingjob->order_pk . '?cl=' . Epirent_Mandant);
|
||||||
|
|
||||||
$orderdetail_output = json_decode($result)->payload[0];
|
$orderdetail_output = json_decode($result)->payload[0];
|
||||||
|
|
||||||
$VorbereitungsTimeDetail;
|
// get PackingNote Details, aber nur wenn nicht schon vor der schleife geholt.
|
||||||
|
if (!UseDeliveredForCheckOutCompleted) {
|
||||||
|
$PackingNoteDetailResult = $Epi->requestEpiApi('/v1/packingnote/' . $packingjob->primary_key . '?cl=' . Epirent_Mandant);
|
||||||
|
$PackingNoteDetail = json_decode($PackingNoteDetailResult)->payload[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
$VorbereitungsTimeDetail = null;
|
||||||
|
$DispoTimeDetail = null;
|
||||||
|
|
||||||
foreach ($orderdetail_output->order_schedule as $scheduledetail) {
|
foreach ($orderdetail_output->order_schedule as $scheduledetail) {
|
||||||
|
|
||||||
if ($scheduledetail->name == Vorbereitungs_Zeitvariable) {
|
if ($scheduledetail->name == Vorbereitungs_Zeitvariable) {
|
||||||
$VorbereitungsTimeDetail = $scheduledetail;
|
$VorbereitungsTimeDetail = $scheduledetail;
|
||||||
}
|
}
|
||||||
}
|
if($scheduledetail->name == "Dispo"){
|
||||||
//End Of get Order Details
|
$DispoTimeDetail = $scheduledetail;
|
||||||
|
}
|
||||||
if (CheckOut_UseDispoStartForRowMarking || ($VorbereitungsTimeDetail->date_start == null)) {
|
|
||||||
$date = new DateTime($packingjob->date_start);
|
|
||||||
} else {
|
|
||||||
$date = new DateTime($VorbereitungsTimeDetail->date_start);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$date->setTime(0, 0, 0);
|
// --- Row-Marking Datum bestimmen (konfigurierbar) ---
|
||||||
$today = new DateTime();
|
$today = dayStart(new DateTimeImmutable('today', new DateTimeZone(APP_TZ)));
|
||||||
$today->setTime(0, 0, 0);
|
$todayFilter = $today; // für die Window-Berechnung
|
||||||
|
$limit = null;
|
||||||
|
if (CheckOut_FutureDays != -1) {
|
||||||
|
$limit = $todayFilter->modify('+' . (int) CheckOut_FutureDays . ' day');
|
||||||
|
}
|
||||||
|
|
||||||
$todayFilter = new DateTime();
|
$markDate = resolveRowMarkDate($packingjob, $VorbereitungsTimeDetail, $PackingNoteDetail, $DispoTimeDetail, (int) CheckOutRowMarkSource);
|
||||||
$todayFilter->setTime(0, 0, 0);
|
|
||||||
if (CheckOut_FutureDays == -1 || $date <= ($todayFilter->modify('+' . CheckOut_FutureDays . ' day'))) {
|
|
||||||
//prüfe, ob entweder unbegrenzte (-1) Anzeige Aktiv ist, oder das Datum kleiner oder Gleich heute + Zukunftsspanne ist
|
|
||||||
if ($date == $today) {
|
|
||||||
|
|
||||||
echo "<tr class='text-dark bg-warning'>";
|
if (CheckOut_FutureDays == -1 || ($markDate && $markDate <= $limit)) {
|
||||||
} else if ($date < $today) {
|
$trClass = rowClassForDate($markDate, $today);
|
||||||
echo "<tr class=' bg-danger'>";
|
|
||||||
|
if ($trClass) {
|
||||||
|
echo "<tr class='{$trClass}'>";
|
||||||
} else {
|
} else {
|
||||||
echo "<tr>";
|
echo "<tr>";
|
||||||
}
|
}
|
||||||
@@ -107,20 +170,60 @@ foreach ($data_output as $packingjob) {
|
|||||||
}
|
}
|
||||||
echo "<td>" . $packingjob->contact->name . "</td>";
|
echo "<td>" . $packingjob->contact->name . "</td>";
|
||||||
echo "<td>" . $packingjob->event . "</td>";
|
echo "<td>" . $packingjob->event . "</td>";
|
||||||
if ($VorbereitungsTimeDetail->date_start != null) {
|
|
||||||
echo "<td><small>" . date_format(new \DateTime($packingjob->date_start), 'd.m.Y') . " " . getTimeFromSeconds($packingjob->time_start) . "</small><br><i>" . date_format(new \DateTime($VorbereitungsTimeDetail->date_start), 'd.m.Y') . " " . getTimeFromSeconds($VorbereitungsTimeDetail->time_start) . "</i></td>";
|
|
||||||
} else {
|
|
||||||
echo "<td>" . date_format(new \DateTime($packingjob->date_start), 'd.m.Y') . " " . getTimeFromSeconds($packingjob->time_start) . "</td>";
|
|
||||||
}
|
|
||||||
if(!HideCheckInTimeOnCheckout){
|
|
||||||
if (($VorbereitungsTimeDetail->date_end != null)) {
|
|
||||||
echo "<td><small>" . date_format(new \DateTime($packingjob->date_end), 'd.m.Y') . " " . getTimeFromSeconds($packingjob->time_end) . "</small><br><i>" . date_format(new \DateTime($VorbereitungsTimeDetail->date_end), 'd.m.Y') . " " . getTimeFromSeconds($VorbereitungsTimeDetail->time_end) . "</i></td>";
|
|
||||||
} else {
|
|
||||||
echo "<td>" . date_format(new \DateTime($packingjob->date_end), 'd.m.Y') . " " . getTimeFromSeconds($packingjob->time_end) . "</td>";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
echo "<td>";
|
|
||||||
|
|
||||||
|
if (ShowCheckoutTimeOnCheckout || ShowVorbereitungTimeOnCheckout || ShowPackagingTimeOnCheckout || ShowDeliveryTimeOnCheckout || ShowDispoStartOnCheckout) { echo "<td>";}
|
||||||
|
|
||||||
|
|
||||||
|
if (ShowCheckoutTimeOnCheckout && $packingjob->date_start != null) {
|
||||||
|
echoMarkedTimeLine($packingjob->date_start, (int) $packingjob->time_start, $today, ShowTimesOnCheckout);
|
||||||
|
}
|
||||||
|
if (ShowVorbereitungTimeOnCheckout && $VorbereitungsTimeDetail && $VorbereitungsTimeDetail->date_start != null) {
|
||||||
|
if (ShowCheckoutTimeOnCheckout) {
|
||||||
|
echo "<br>";
|
||||||
|
}
|
||||||
|
|
||||||
|
if($packingjob->is_all_out != 0){
|
||||||
|
echoMarkedTimeLine($VorbereitungsTimeDetail->date_start, (int) $VorbereitungsTimeDetail->time_start, $today, ShowTimesOnCheckout);
|
||||||
|
}else{
|
||||||
|
echo "<span class='bg-success text-light'>";
|
||||||
|
echo date_format(new \DateTime($VorbereitungsTimeDetail->date_start), 'd.m.Y');
|
||||||
|
if($VorbereitungsTimeDetail->time_start){echo " ".getTimeFromSeconds((string) $VorbereitungsTimeDetail->time_start);}
|
||||||
|
echo "</span>";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
if (ShowPackagingTimeOnCheckout && $PackingNoteDetail && $PackingNoteDetail->date_packing != null) {
|
||||||
|
if (ShowCheckoutTimeOnCheckout || ShowVorbereitungTimeOnCheckout) {
|
||||||
|
echo "<br>";
|
||||||
|
}
|
||||||
|
if($packingjob->is_all_out != 0){
|
||||||
|
echoMarkedTimeLine($PackingNoteDetail->date_packing, (int) $PackingNoteDetail->time_packing, $today, ShowTimesOnCheckout);
|
||||||
|
}else{
|
||||||
|
echo "<span class='bg-success text-light'>";
|
||||||
|
echo date_format(new \DateTime($PackingNoteDetail->date_packing), 'd.m.Y');
|
||||||
|
if($PackingNoteDetail->time_packing){echo " ".getTimeFromSeconds((string) $PackingNoteDetail->time_packing);}
|
||||||
|
echo "</span>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ShowDeliveryTimeOnCheckout && $PackingNoteDetail && $PackingNoteDetail->date_delivery != null) {
|
||||||
|
if (ShowCheckoutTimeOnCheckout || ShowVorbereitungTimeOnCheckout || ShowPackagingTimeOnCheckout) {
|
||||||
|
echo "<br>";
|
||||||
|
}
|
||||||
|
echoMarkedTimeLine($PackingNoteDetail->date_delivery, (int) $PackingNoteDetail->time_delivery, $today, ShowTimesOnCheckout);
|
||||||
|
}
|
||||||
|
if (ShowDispoStartOnCheckout && $DispoTimeDetail->date_start && $DispoTimeDetail->time_start != null) {
|
||||||
|
if (ShowCheckoutTimeOnCheckout || ShowVorbereitungTimeOnCheckout || ShowPackagingTimeOnCheckout || ShowDeliveryTimeOnCheckout) {
|
||||||
|
echo "<br>";
|
||||||
|
}
|
||||||
|
echoMarkedTimeLine($DispoTimeDetail->date_start, (int) $DispoTimeDetail->time_start, $today, ShowTimesOnCheckout);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ShowCheckoutTimeOnCheckout || ShowVorbereitungTimeOnCheckout || ShowPackagingTimeOnCheckout || ShowDeliveryTimeOnCheckout || ShowDispoStartOnCheckout) {
|
||||||
|
echo "</td>";
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "<td>";
|
||||||
|
|
||||||
if ($packingjob->is_all_out == 0) {
|
if ($packingjob->is_all_out == 0) {
|
||||||
echo "<span class='badge badge-success'>";
|
echo "<span class='badge badge-success'>";
|
||||||
@@ -132,21 +235,95 @@ foreach ($data_output as $packingjob) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
echo ($packingjob->pieces_sum_total - abs($packingjob->is_all_out)) . "/" . $packingjob->pieces_sum_total;
|
echo ($packingjob->pieces_sum_total - abs($packingjob->is_all_out)) . "/" . $packingjob->pieces_sum_total;
|
||||||
echo "</span><td>";
|
echo "</span></td>";
|
||||||
|
|
||||||
|
if (ShowShippingIcons) {
|
||||||
|
|
||||||
|
if (UseShippingStatus) {
|
||||||
|
if (($PackingNoteDetail->status == ShippingOutOrganizedStatus) || ($PackingNoteDetail->status == ShippingOrganizedStatus)) {
|
||||||
|
echo "<td style='color:#66FF00; text-align:center;'>";
|
||||||
|
} else {
|
||||||
|
echo "<td style='text-align:center;'>";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($PackingNoteDetail->is_self_pickup) {
|
||||||
|
echo '<i class="'.SelbstabholerIcon.'"></i>';
|
||||||
|
} else {
|
||||||
|
if (preg_match('/' . KurierContainsText . '/i', $PackingNoteDetail->shipping_out)) {
|
||||||
|
echo '<i class="'.KurierIcon.'"></i>';
|
||||||
|
}
|
||||||
|
if (preg_match('/' . SpeditionContainsText . '/i', $PackingNoteDetail->shipping_out)) {
|
||||||
|
echo '<i class="'.SpeditionIcon.'"></i>';
|
||||||
|
}
|
||||||
|
if (preg_match('/' . DHLContainsText . '/i', $PackingNoteDetail->shipping_out)) {
|
||||||
|
echo '<i class="'.DHLIcon.'"></i>';
|
||||||
|
}
|
||||||
|
if (preg_match('/' . LKWContainsText . '/i', $PackingNoteDetail->shipping_out)) {
|
||||||
|
echo '<i class="fa-solid fa-industry fa-lg"></i><i class="'.LKWIcon.'"></i>';
|
||||||
|
}
|
||||||
|
if (preg_match('/' . TransporterContainsText . '/i', $PackingNoteDetail->shipping_out)) {
|
||||||
|
echo '<i class="fa-solid fa-industry fa-lg"></i><i class="'.TransporterIcon.'"></i>';
|
||||||
|
}
|
||||||
|
if (preg_match('/' . PKWContainsText . '/i', $PackingNoteDetail->shipping_out)) {
|
||||||
|
echo '<i class="fa-solid fa-industry fa-lg"></i><i class="'.PKWIcon.'"></i>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
echo "</td>";
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "</tr>";
|
||||||
|
}
|
||||||
|
|
||||||
echo "</tr>";
|
echo "</tr>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function echoMarkedTimeLine(?string $dateStr, ?int $timeSeconds, DateTimeImmutable $today, $ReturnTime): void {
|
||||||
|
if (!$dateStr)
|
||||||
|
return;
|
||||||
|
$d = dt($dateStr);
|
||||||
|
if (!$d)
|
||||||
|
return;
|
||||||
|
|
||||||
|
$mark = dayStart($d);
|
||||||
|
$cls = rowClassForDate($mark, $today);
|
||||||
|
|
||||||
|
echo $cls ? "<span class=\"{$cls}\">" : "";
|
||||||
|
echo date_format(new \DateTime($dateStr), 'd.m.Y');
|
||||||
|
if($ReturnTime){echo " ".getTimeFromSeconds((string) $timeSeconds);}
|
||||||
|
echo $cls ? "</span>" : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
function getTimeFromSeconds(string $timestring) {
|
function getTimeFromSeconds(string $timestring) {
|
||||||
|
|
||||||
$hours = floor($timestring / 3600);
|
$hours = floor($timestring / 3600);
|
||||||
$mins = floor($timestring / 60 % 60);
|
$mins = floor(round($timestring / 60 % 60));
|
||||||
$secs = floor($timestring % 60);
|
$secs = floor(round($timestring % 60));
|
||||||
|
|
||||||
$timeFormat = sprintf('%02d:%02d', $hours, $mins);
|
$timeFormat = sprintf('%02d:%02d', $hours, $mins);
|
||||||
|
|
||||||
return $timeFormat;
|
return $timeFormat;
|
||||||
|
}*/
|
||||||
|
function getTimeFromSeconds($seconds): string {
|
||||||
|
if ($seconds === null || $seconds === '') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// robust normalisieren: String/Float -> Float -> gerundet -> Int
|
||||||
|
$seconds = (int) round((float) $seconds);
|
||||||
|
|
||||||
|
if ($seconds < 0) {
|
||||||
|
$seconds = 0; // oder: return ''; je nach gewünschtem Verhalten
|
||||||
|
}
|
||||||
|
|
||||||
|
// reine Integer-Arithmetik, keine impliziten float->int Casts
|
||||||
|
$hours = intdiv($seconds, 3600);
|
||||||
|
$mins = intdiv($seconds % 3600, 60);
|
||||||
|
|
||||||
|
return sprintf('%02d:%02d', $hours, $mins);
|
||||||
}
|
}
|
||||||
|
|
||||||
?>
|
|
||||||
|
?>
|
||||||
|
|||||||
877
sources/getProductLabel.php
Normal file
877
sources/getProductLabel.php
Normal file
@@ -0,0 +1,877 @@
|
|||||||
|
<?php
|
||||||
|
error_reporting(E_ALL & ~E_DEPRECATED);
|
||||||
|
|
||||||
|
require('../config.php');
|
||||||
|
require('../EpiApi.php');
|
||||||
|
require_once __DIR__ . '/../vendor/autoload.php';
|
||||||
|
require_once __DIR__ . '/../vendor/tecnickcom/tcpdf/tcpdf.php';
|
||||||
|
date_default_timezone_set('Europe/Berlin');
|
||||||
|
$id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
|
||||||
|
$deviceNumber = (!empty($_GET['nr'])) ? '--' . trim($_GET['nr']) : '';
|
||||||
|
|
||||||
|
$Epi = new Epirent();
|
||||||
|
$product =json_decode($Epi->requestEpiApi('/v1/product/'.$id.'?cl=' . Epirent_Mandant))->payload[0];
|
||||||
|
$productImage =json_decode($Epi->requestEpiApi('/v1/product/image/'.$id.'?cl=' . Epirent_Mandant))->payload[0]->image_data;
|
||||||
|
|
||||||
|
|
||||||
|
function s(?string $v): string { return trim((string)$v); }
|
||||||
|
function fnum(?float $v, int $dec = 2): string {
|
||||||
|
if ($v === null) return '';
|
||||||
|
$n = number_format((float)$v, $dec, ',', '.');
|
||||||
|
return rtrim(rtrim($n, '0'), ',');
|
||||||
|
}
|
||||||
|
|
||||||
|
//Set Variables
|
||||||
|
$productName = $product->name;
|
||||||
|
$productNumber = $product->product_no;
|
||||||
|
|
||||||
|
$bruttoWeightSum = $product->tech_data->weight_gro;
|
||||||
|
|
||||||
|
$bundle = buildBundleForProduct($Epi, $product);
|
||||||
|
|
||||||
|
/** Test-Daten
|
||||||
|
*/
|
||||||
|
$dimsBHT =$product->tech_data->width_gro." x ".$product->tech_data->depth_gro." x ".$product->tech_data->height_gro;
|
||||||
|
$volume = ((float)$product->tech_data->height_gro * (float)$product->tech_data->width_gro * (float)$product->tech_data->depth_gro)* 0.000001;
|
||||||
|
$storageLoc = $product->product_data->storage_location_nearby;
|
||||||
|
|
||||||
|
/** Layout */
|
||||||
|
$PAGE_SIZE = 'A4';
|
||||||
|
$MARGIN_LEFT = 8;
|
||||||
|
$MARGIN_TOP = 8;
|
||||||
|
$MARGIN_RIGHT = 8;
|
||||||
|
$MARGIN_BOTTOM = 10;
|
||||||
|
|
||||||
|
$CELL_PAD = 1.6;
|
||||||
|
$LINE_GRAY = '#efefef';
|
||||||
|
|
||||||
|
$LEVEL_MIN = 1; $LEVEL_MAX = 5;
|
||||||
|
$INDENT_PX_PER_LEVEL = 10;
|
||||||
|
$BASE_FONT_PX = 10;
|
||||||
|
$FONT_STEP_PX = 1.5;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** TCPDF */
|
||||||
|
$pdf = new TCPDF('P', 'mm', $PAGE_SIZE, true, 'UTF-8', false);
|
||||||
|
|
||||||
|
// 1) Pfade sauber
|
||||||
|
$fontDir = realpath(__DIR__ . '/../src/assets/font') . '/';
|
||||||
|
$tcpdfFontsDir = defined('K_PATH_FONTS') ? K_PATH_FONTS : (dirname((new \ReflectionClass('TCPDF'))->getFileName()) . '/fonts/');
|
||||||
|
|
||||||
|
// 2) Rechte (einmalig sicherstellen)
|
||||||
|
// -> hast du schon gefixt
|
||||||
|
|
||||||
|
// 3) TTFs registrieren und Rückgabewerte merken
|
||||||
|
$fontReg = file_exists($fontDir.'Hurme3/HurmeGeometricSans3-Regular.ttf')
|
||||||
|
? TCPDF_FONTS::addTTFfont($fontDir.'Hurme3/HurmeGeometricSans3-Regular.ttf', 'TrueTypeUnicode', '', 96)
|
||||||
|
: false;
|
||||||
|
$fontBold = file_exists($fontDir.'Hurme1/HurmeGeometricSans1-Bold.ttf')
|
||||||
|
? TCPDF_FONTS::addTTFfont($fontDir.'Hurme1/HurmeGeometricSans1-Bold.ttf', 'TrueTypeUnicode', '', 96)
|
||||||
|
: false;
|
||||||
|
$fontItal = file_exists($fontDir.'Hurme3/HurmeGeometricSans3-Italic.ttf')
|
||||||
|
? TCPDF_FONTS::addTTFfont($fontDir.'Hurme3/HurmeGeometricSans3-Italic.ttf', 'TrueTypeUnicode', '', 96)
|
||||||
|
: false;
|
||||||
|
$fontBI = file_exists($fontDir.'Hurme1/HurmeGeometricSans1-BoldItalic.ttf')
|
||||||
|
? TCPDF_FONTS::addTTFfont($fontDir.'Hurme1/HurmeGeometricSans1-BoldItalic.ttf', 'TrueTypeUnicode', '', 96)
|
||||||
|
: false;
|
||||||
|
|
||||||
|
// 4) Fallback setzen
|
||||||
|
$baseFont = $fontReg ?: 'dejavusans';
|
||||||
|
|
||||||
|
// 5) Header/Footer und Defaults
|
||||||
|
$pdf->setHeaderFont([$baseFont, '', 10]);
|
||||||
|
$pdf->setFooterFont([$baseFont, '', 9]);
|
||||||
|
$pdf->SetDefaultMonospacedFont('courier');
|
||||||
|
|
||||||
|
// 6) *** AB JETZT KEIN dejavusans MEHR SETZEN! ***
|
||||||
|
$pdf->SetFont($baseFont, '', 10.5);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$pdf->SetCreator('VT-Media EpiWebview');
|
||||||
|
$pdf->SetAuthor('VT-Media');
|
||||||
|
$pdf->SetTitle('Kistenetikett '.$productName);
|
||||||
|
$pdf->SetSubject('Kistenetikett');
|
||||||
|
|
||||||
|
$pdf->setPrintHeader(false);
|
||||||
|
$pdf->setPrintFooter(false);
|
||||||
|
$pdf->SetMargins($MARGIN_LEFT, $MARGIN_TOP, $MARGIN_RIGHT);
|
||||||
|
$pdf->SetAutoPageBreak(true, $MARGIN_BOTTOM);
|
||||||
|
$pdf->setImageScale(1.0);
|
||||||
|
$pdf->setFontSubsetting(true);
|
||||||
|
$pdf->setCellPadding($CELL_PAD);
|
||||||
|
|
||||||
|
$pdf->AddPage();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// --- LOGO in fester Box mit Rahmen, zentriert & verzerrungsfrei ---
|
||||||
|
$logoPath = __DIR__ . Labelprint_Logopath;
|
||||||
|
|
||||||
|
$startX = $pdf->GetX();
|
||||||
|
$startY = $pdf->GetY();
|
||||||
|
|
||||||
|
// feste Rahmen-Größe (in mm)
|
||||||
|
$frameW = 38.0; // Gesamtbreite des Rahmens
|
||||||
|
$frameH = 20; // Gesamthöhe des Rahmens
|
||||||
|
$frameOffsetX = 1.4; // Abstand vom linken Margin (wie vorher genutzt)
|
||||||
|
$frameOffsetY = 1.5; // Abstand von oben (wie vorher genutzt)
|
||||||
|
|
||||||
|
// Rahmen-Position
|
||||||
|
$frameX = $startX + $frameOffsetX;
|
||||||
|
$frameY = $startY + $frameOffsetY;
|
||||||
|
|
||||||
|
// Rahmen zeichnen
|
||||||
|
$pdf->SetLineWidth(0.3);
|
||||||
|
$pdf->Rect($frameX, $frameY, $frameW, $frameH, 'D');
|
||||||
|
|
||||||
|
// Logo innerhalb des Rahmens mit Innenabstand
|
||||||
|
$innerPad = 1.2; // mm Luft im Rahmen
|
||||||
|
$maxW = $frameW - 2 * $innerPad;
|
||||||
|
$maxH = $frameH - 2 * $innerPad;
|
||||||
|
|
||||||
|
if (is_file($logoPath)) {
|
||||||
|
// Seitenverhältnis ermitteln
|
||||||
|
$imgWpx = $imgHpx = 0;
|
||||||
|
if (@list($imgWpx, $imgHpx) = @getimagesize($logoPath)) {
|
||||||
|
$ratio = ($imgHpx > 0) ? ($imgWpx / $imgHpx) : 1.0;
|
||||||
|
|
||||||
|
// proportional in den Rahmen einpassen
|
||||||
|
if ($maxW / $maxH > $ratio) {
|
||||||
|
$drawH = $maxH;
|
||||||
|
$drawW = $maxH * $ratio;
|
||||||
|
} else {
|
||||||
|
$drawW = $maxW;
|
||||||
|
$drawH = $maxW / $ratio;
|
||||||
|
}
|
||||||
|
|
||||||
|
// zentrieren
|
||||||
|
$imgX = $frameX + ($frameW - $drawW) / 2;
|
||||||
|
$imgY = $frameY + ($frameH - $drawH) / 2;
|
||||||
|
|
||||||
|
// ausgeben
|
||||||
|
$pdf->Image($logoPath, $imgX, $imgY, $drawW, $drawH, '', '', '', false, 300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$afterLogoX = $frameX + $frameW - 1.4; // gleicher Abstand wie zuvor, jetzt basierend auf Rahmenbreite
|
||||||
|
$afterLogoBottomY = $frameY + $frameH; // falls du unten bündig etwas brauchst
|
||||||
|
$pdf->SetXY($afterLogoX, $startY); // Cursor rechts neben dem Logo positionieren
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$addrHtml = '
|
||||||
|
<div style="line-height:1.25; font-size:6px; margin:0; padding:0;">'.Labelprint_Addresstext.'</div>';
|
||||||
|
// Feste Box rechts neben dem Logo (direkt bündig)
|
||||||
|
$addrBoxW = 30.0; // feste Breite (mm)
|
||||||
|
$addrBoxH = 20.0; // feste Höhe (mm)
|
||||||
|
$addrPad = 0.5; // Innenabstand Inhalt → Rahmen (mm)
|
||||||
|
|
||||||
|
// bündig rechts neben dem Logo-Rahmen starten
|
||||||
|
$addrX = $frameX + $frameW; // kein zusätzlicher Abstand
|
||||||
|
$addrY = $startY+1.5; // gleiche Oberkante wie Logo
|
||||||
|
|
||||||
|
// 1) festen Rahmen zeichnen
|
||||||
|
$pdf->SetLineWidth(0.3);
|
||||||
|
$pdf->Rect($addrX, $addrY, $addrBoxW, $addrBoxH, 'D');
|
||||||
|
|
||||||
|
// 2) HTML-Inhalt in die Box schreiben, mit Clipping (Überhang wird abgeschnitten)
|
||||||
|
$pdf->StartTransform();
|
||||||
|
$pdf->Rect($addrX, $addrY, $addrBoxW, $addrBoxH, 'CNZ'); // Clip auf Box setzen
|
||||||
|
|
||||||
|
$pdf->writeHTMLCell(
|
||||||
|
$addrBoxW - 2*$addrPad, // feste Breite des Inhalts
|
||||||
|
$addrBoxH - 2*$addrPad, // feste Höhe des Inhalts
|
||||||
|
$addrX + $addrPad, // x mit Innenabstand
|
||||||
|
$addrY + $addrPad, // y mit Innenabstand
|
||||||
|
$addrHtml, // dein HTML
|
||||||
|
0, // kein Border (Rahmen haben wir schon)
|
||||||
|
0, // ln
|
||||||
|
false, // fill
|
||||||
|
true, // reseth
|
||||||
|
'L', // align
|
||||||
|
true // autopadding
|
||||||
|
);
|
||||||
|
|
||||||
|
$pdf->StopTransform();
|
||||||
|
|
||||||
|
// Cursor steht bereits auf: $pdf->SetXY($addrX + $addrBoxW, $addrY);
|
||||||
|
|
||||||
|
// 1) HTML OHNE border (sonst Doppelrahmen)
|
||||||
|
$productionHtml = '
|
||||||
|
<div style="line-height:1.3; font-size:8px; margin:0; padding:0;">
|
||||||
|
<b>Produktion</b><br/><br><br><br>
|
||||||
|
</div>';
|
||||||
|
|
||||||
|
// 2) Feste Box rechts neben der Adress-Box
|
||||||
|
$prodX = $addrX + $addrBoxW; // bündig rechts neben Adresse
|
||||||
|
$prodY = $addrY; // gleiche Oberkante
|
||||||
|
// Breite: restliche Seitenbreite bis zum rechten Rand
|
||||||
|
$prodW = $pdf->getPageWidth() - $MARGIN_RIGHT - $prodX+2;
|
||||||
|
// Höhe: fix (anpassen nach Wunsch)
|
||||||
|
$prodH = 20.0; // mm
|
||||||
|
$prodPad = 0; // Innenabstand
|
||||||
|
|
||||||
|
// 3) EIN sichtbarer Rahmen zeichnen
|
||||||
|
$pdf->SetLineWidth(0.3);
|
||||||
|
$pdf->Rect($prodX, $prodY, $prodW, $prodH, 'D');
|
||||||
|
|
||||||
|
// 4) Inhalt in die Box schreiben und clippen (Überhang abgeschnitten)
|
||||||
|
$pdf->StartTransform();
|
||||||
|
$pdf->Rect($prodX, $prodY, $prodW, $prodH, 'CNZ'); // Clip auf Box setzen
|
||||||
|
|
||||||
|
$pdf->writeHTMLCell(
|
||||||
|
$prodW - 2*$prodPad, // feste Breite des Inhalts
|
||||||
|
$prodH - 2*$prodPad, // feste Höhe des Inhalts
|
||||||
|
$prodX + $prodPad, // x mit Innenabstand
|
||||||
|
$prodY + $prodPad, // y mit Innenabstand
|
||||||
|
$productionHtml, // Inhalt (ohne border!)
|
||||||
|
0, // kein Border (Rahmen haben wir schon)
|
||||||
|
0, // ln
|
||||||
|
false, // fill
|
||||||
|
true, // reseth
|
||||||
|
'L', // align
|
||||||
|
true // autopadding
|
||||||
|
);
|
||||||
|
|
||||||
|
$pdf->StopTransform();
|
||||||
|
|
||||||
|
// 5) (Optional) Cursor direkt rechts neben der Box positionieren
|
||||||
|
$pdf->SetXY($prodX + $prodW, $prodY);
|
||||||
|
|
||||||
|
// === Name-Box: feste Größe, Text bricht, kein Doppelrahmen ===
|
||||||
|
|
||||||
|
// Breite: gesamte Restbreite bis zum rechten Rand (unter Adresse + Produktion)
|
||||||
|
$nameX = $frameX; // beginnt rechts neben dem Logo/Adressbereich
|
||||||
|
$nameW = $pdf->getPageWidth() - $MARGIN_RIGHT - $nameX-65.2;
|
||||||
|
|
||||||
|
// Höhe & Padding der Box (anpassen nach Wunsch)
|
||||||
|
$nameBoxH = 18.2; // mm - feste Höhe
|
||||||
|
$namePad = 1.5; // mm - Innenabstand
|
||||||
|
|
||||||
|
// Y: direkt unter die höhere der beiden Boxen (Adresse vs. Produktion)
|
||||||
|
$yAfterRow = max($addrY + $addrBoxH, $prodY + $prodH) + 0.0; // +2 mm Abstand
|
||||||
|
$nameY = $yAfterRow;
|
||||||
|
|
||||||
|
// Inhalt OHNE border (sonst Doppelrahmen)
|
||||||
|
$nameHtml = '
|
||||||
|
<div style="font-size:15px; font-weight:700; line-height:1.3; margin:0; padding:0;">' . htmlspecialchars($productName) . '
|
||||||
|
</div>';
|
||||||
|
|
||||||
|
// 1) Sichtbaren Rahmen zeichnen (feste Größe)
|
||||||
|
$pdf->SetLineWidth(0.3);
|
||||||
|
$pdf->Rect($nameX, $nameY, $nameW, $nameBoxH, 'D');
|
||||||
|
|
||||||
|
// 2) Inhalt in die Box schreiben und clippen
|
||||||
|
$pdf->StartTransform();
|
||||||
|
$pdf->Rect($nameX, $nameY, $nameW, $nameBoxH, 'CNZ'); // Clip auf Box setzen
|
||||||
|
|
||||||
|
$pdf->writeHTMLCell(
|
||||||
|
$nameW - 2*$namePad, // feste Breite für den Text
|
||||||
|
$nameBoxH - 2*$namePad, // feste Höhe für den Text
|
||||||
|
$nameX + $namePad, // x mit Innenabstand
|
||||||
|
$nameY + $namePad, // y mit Innenabstand
|
||||||
|
$nameHtml,
|
||||||
|
0, // kein HTML-Border
|
||||||
|
0, // ln
|
||||||
|
false, // fill
|
||||||
|
true, // reseth
|
||||||
|
'L', // align
|
||||||
|
true // autopadding
|
||||||
|
);
|
||||||
|
|
||||||
|
$pdf->StopTransform();
|
||||||
|
|
||||||
|
// Optional: Cursor unter die Box setzen (falls du danach im Fluss weitermachen willst)
|
||||||
|
$pdf->SetXY($nameX, $nameY + $nameBoxH);
|
||||||
|
|
||||||
|
// 1) Box-Geometrie (immer gleich groß)
|
||||||
|
$pnBoxW = 67.0; // mm – Gesamtbreite der Box
|
||||||
|
$pnBoxH = 18.2; // mm – Gesamthöhe der Box
|
||||||
|
$pnBoxPad = 2.0; // mm – Innenabstand innerhalb der Box
|
||||||
|
|
||||||
|
// Position der Box (aktuell am rechten Rand oben; passe frei an)
|
||||||
|
$pnBoxX = $pdf->getPageWidth() - $MARGIN_RIGHT - $pnBoxW+1.8; // bündig am rechten Rand
|
||||||
|
$pnBoxY = $startY+21.5; // gleiche Oberkante wie Kopf
|
||||||
|
|
||||||
|
// 2) Sichtbaren Rahmen zeichnen (einmalig)
|
||||||
|
$pdf->SetLineWidth(0.3);
|
||||||
|
$pdf->Rect($pnBoxX, $pnBoxY, $pnBoxW, $pnBoxH, 'D');
|
||||||
|
|
||||||
|
// 3) Clipping aktivieren, damit Inhalt in der Box bleibt
|
||||||
|
$pdf->StartTransform();
|
||||||
|
$pdf->Rect($pnBoxX, $pnBoxY, $pnBoxW, $pnBoxH, 'CNZ'); // Clip auf die Box
|
||||||
|
|
||||||
|
// 4) Produktnummer: frei verschiebbar innerhalb der Box
|
||||||
|
$pnCombined = trim($productNumber . $deviceNumber);
|
||||||
|
$pnText = htmlspecialchars($pnCombined !== '' ? $pnCombined : 'N/A');
|
||||||
|
|
||||||
|
// Offsets innerhalb der Box – hier stellst du die Position ein
|
||||||
|
$pnTextOffsetX = 2.0; // mm von linker Innenkante
|
||||||
|
$pnTextOffsetY = 1; // mm von oberer Innenkante
|
||||||
|
$pnTextW = $pnBoxW - 2*$pnBoxPad; // nutzbare Breite
|
||||||
|
$pnTextH = 8.0; // feste Höhe für den PN-Textbereich (mm)
|
||||||
|
|
||||||
|
$pnHtml = '
|
||||||
|
<div style="font-size:20px; line-height:1.25; margin:0; padding:0;">
|
||||||
|
'.$pnText.'
|
||||||
|
</div>';
|
||||||
|
|
||||||
|
// PN-Text rendern (ohne HTML-Border!)
|
||||||
|
$pdf->writeHTMLCell(
|
||||||
|
$pnTextW, // Breite Textbereich
|
||||||
|
$pnTextH, // Höhe Textbereich
|
||||||
|
$pnBoxX + $pnBoxPad + $pnTextOffsetX, // X in der Box
|
||||||
|
$pnBoxY + $pnBoxPad + $pnTextOffsetY, // Y in der Box
|
||||||
|
$pnHtml,
|
||||||
|
0, 0, false, true, 'L', true
|
||||||
|
);
|
||||||
|
|
||||||
|
// 5) QR-Code: frei verschiebbar innerhalb der Box, verzerrungsfrei per size
|
||||||
|
$qrData = trim((string)($productNumber . $deviceNumber));
|
||||||
|
if ($qrData === '') {
|
||||||
|
$qrData = 'N/A';
|
||||||
|
}
|
||||||
|
|
||||||
|
$qrSize = 16.0; // mm – Kantenlänge des QR
|
||||||
|
$qrOffsetX = $pnBoxW - $pnBoxPad - $qrSize - 2.0; // mm von linker Innenkante
|
||||||
|
$qrOffsetY = $pnBoxH - $pnBoxPad - $qrSize +0.6; // mm von oberer Innenkante
|
||||||
|
|
||||||
|
$qrX = $pnBoxX + $qrOffsetX;
|
||||||
|
$qrY = $pnBoxY + $qrOffsetY;
|
||||||
|
|
||||||
|
$qrStyle = [
|
||||||
|
'border' => 0,
|
||||||
|
'vpadding' => 0,
|
||||||
|
'hpadding' => 0,
|
||||||
|
'fgcolor' => [0,0,0],
|
||||||
|
'bgcolor' => false,
|
||||||
|
];
|
||||||
|
|
||||||
|
// QR rendern (Warnings/Deprecated für diesen Block stumm schalten)
|
||||||
|
$_old_reporting = error_reporting();
|
||||||
|
error_reporting($_old_reporting & ~(E_WARNING | E_DEPRECATED | E_NOTICE));
|
||||||
|
$pdf->write2DBarcode($qrData, 'QRCODE,H', $qrX, $qrY, $qrSize, $qrSize, $qrStyle, 'N');
|
||||||
|
error_reporting($_old_reporting);
|
||||||
|
|
||||||
|
// 6) Clipping beenden
|
||||||
|
$pdf->StopTransform();
|
||||||
|
|
||||||
|
// 7) Optional: Cursor unter die PN-Box setzen, falls du im Fluss weiter willst
|
||||||
|
$pdf->SetXY($pnBoxX, $pnBoxY + $pnBoxH);
|
||||||
|
|
||||||
|
/** Bundle */
|
||||||
|
|
||||||
|
$bundleHeader = '<div style=" background-color: black; color: white; font-size:10px; font-weight:700;line-height:1.4; margin:4px 0 3px 0;"> Bundleinhalt</div>';
|
||||||
|
$pdf->writeHTMLCell(70, 50, 7.65, 46, $bundleHeader, 0, 0, 0, true, 'L', true);
|
||||||
|
$bundleHeaderFillable = '<div style="border: 1px solid black; line-heigt:0.6"></div>';
|
||||||
|
//$pdf->writeHTMLCell(130.8, 39.8, 74.5, 46, $bundleHeaderFillable, 0, 0, 0, false, 'L', true);
|
||||||
|
drawFixedBox($pdf, 76.0, 47.7, 127.8, 4.65);
|
||||||
|
|
||||||
|
|
||||||
|
$bundleRows = '';
|
||||||
|
|
||||||
|
$BASE_FONT_PX = 10.0; // Level 1
|
||||||
|
$FONT_STEP_PX = 1.5; // je Ebene kleiner
|
||||||
|
$MIN_FONT_PX = 6.0;
|
||||||
|
$LINE_HEIGHT_BASE = 1.15; // Basis Zeilenhöhe
|
||||||
|
$LINE_HEIGHT_STEP = 0.05; // je Ebene etwas kompakter
|
||||||
|
$ROW_PAD_V_MM = 0.5; // vertikales Padding je Zeile
|
||||||
|
$ROW_PAD_H_MM = 0.8; // horizontales Padding
|
||||||
|
$WEIGHT_PAD_RIGHT_MM = 1.6; // mehr Abstand zum rechten Rand
|
||||||
|
$INDENT_MM_PER_LVL = 2.8; // Einrückung je Ebene in mm (stabil!)
|
||||||
|
|
||||||
|
foreach ($bundle as $item) {
|
||||||
|
$qty = (int)($item['qty'] ?? 1);
|
||||||
|
$text = htmlspecialchars($item['text'] ?? '');
|
||||||
|
$lvl = max($LEVEL_MIN, min($LEVEL_MAX, (int)($item['level'] ?? 1)));
|
||||||
|
$wkg = isset($item['weight_kg']) ? (float)$item['weight_kg'] : null;
|
||||||
|
|
||||||
|
$textFontPx = max($MIN_FONT_PX, $BASE_FONT_PX - ($lvl - 1) * $FONT_STEP_PX);
|
||||||
|
$weightFontPx = max($MIN_FONT_PX, $BASE_FONT_PX - ($lvl - 1) * $FONT_STEP_PX);
|
||||||
|
$lineHeight = max(1.0, $LINE_HEIGHT_BASE - ($lvl - 1) * $LINE_HEIGHT_STEP);
|
||||||
|
|
||||||
|
// Einrückung robust über mm – aber nur Tabelle nutzen, wenn > 0 mm
|
||||||
|
$indentMm = max(0, ($lvl - 1) * $INDENT_MM_PER_LVL);
|
||||||
|
|
||||||
|
// Name-Spalte: ohne Spacer-Tabelle bei Level 1 (indent=0), sonst mit
|
||||||
|
if ($indentMm > 0) {
|
||||||
|
$nameCellHtml = '
|
||||||
|
<table cellspacing="0" cellpadding="0" width="100%">
|
||||||
|
<tr>
|
||||||
|
<td style="width:'.$indentMm.'mm; padding:0; margin:0;"></td>
|
||||||
|
<td style="font-size:'.$textFontPx.'px; line-height:'.$lineHeight.'; padding:0; margin:0;">'.$text.'</td>
|
||||||
|
</tr>
|
||||||
|
</table>';
|
||||||
|
} else {
|
||||||
|
// Level 1: direkt rendern
|
||||||
|
$nameCellHtml = '<span style="font-size:'.$textFontPx.'px; line-height:'.$lineHeight.';">'.$text.'</span>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$bundleRows .= '
|
||||||
|
<tr>
|
||||||
|
<!-- Anzahl -->
|
||||||
|
<td style="
|
||||||
|
width:12%;
|
||||||
|
text-align:right;
|
||||||
|
vertical-align:middle;
|
||||||
|
font-size:'.$textFontPx.'px;
|
||||||
|
line-height:'.$lineHeight.';
|
||||||
|
padding:'.$ROW_PAD_V_MM.'mm '.$ROW_PAD_H_MM.'mm '.$ROW_PAD_V_MM.'mm '.$ROW_PAD_H_MM.'mm;">
|
||||||
|
'.$qty.'
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<!-- Name mit Einrückung -->
|
||||||
|
<td style="
|
||||||
|
width:68%;
|
||||||
|
vertical-align:middle;
|
||||||
|
padding:'.$ROW_PAD_V_MM.'mm '.$ROW_PAD_H_MM.'mm;">
|
||||||
|
'.$nameCellHtml.'
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<!-- Gewicht rechts mit extra Innenabstand -->
|
||||||
|
<td style="
|
||||||
|
width:20%;
|
||||||
|
text-align:right;
|
||||||
|
vertical-align:middle;
|
||||||
|
font-size:'.$weightFontPx.'px;
|
||||||
|
line-height:'.$lineHeight.';
|
||||||
|
padding:'.$ROW_PAD_V_MM.'mm '.$WEIGHT_PAD_RIGHT_MM.'mm '.$ROW_PAD_V_MM.'mm '.$ROW_PAD_H_MM.'mm;">
|
||||||
|
'.($wkg !== null ? fnum($wkg).' kg' : '').'
|
||||||
|
</td>
|
||||||
|
</tr>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$bundleHtml = '
|
||||||
|
<table cellspacing="0" cellpadding="0" style="border:1px solid #000; border-collapse:collapse;" width="100%">
|
||||||
|
<tbody>'.$bundleRows.'</tbody>
|
||||||
|
</table>';
|
||||||
|
|
||||||
|
$pdf->writeHTMLCell(
|
||||||
|
$pdf->getPageWidth() - 12.4,
|
||||||
|
0,
|
||||||
|
7.8,
|
||||||
|
50.8,
|
||||||
|
$bundleHtml,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
true,
|
||||||
|
'L',
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** ---------- Meta-Block dynamisch unterhalb der Bundle-Tabelle ---------- */
|
||||||
|
|
||||||
|
// Höhe der zuletzt gerenderten Bundle-Tabelle holen
|
||||||
|
$bundleH = $pdf->getLastH();
|
||||||
|
|
||||||
|
// Y-Position direkt nach der Bundle-Tabelle (mit 3 mm Abstand)
|
||||||
|
$metaY = 47.6 + $bundleH; // 50 = dein bisheriges Y der Bundle-Tabelle
|
||||||
|
$metaX = $MARGIN_LEFT;
|
||||||
|
$metaW = $pdf->getPageWidth() - $MARGIN_LEFT - $MARGIN_RIGHT;
|
||||||
|
|
||||||
|
// Falls Meta-Block zu nah am Seitenende wäre → neue Seite
|
||||||
|
$usableBottom = $pdf->getPageHeight() - $MARGIN_BOTTOM;
|
||||||
|
if ($metaY > $usableBottom - 40) { // 40 mm Puffer für Meta
|
||||||
|
$pdf->AddPage();
|
||||||
|
$metaY = $MARGIN_TOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Inhalt wie gehabt ---
|
||||||
|
$leftMeta = '
|
||||||
|
<table cellspacing="0" cellpadding="'.$CELL_PAD.'" width="100%">
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
<!-- Maße -->
|
||||||
|
<tr>
|
||||||
|
<!-- Zusammengefasste linke Zelle: hat Rahmen, innen KEIN Rahmen -->
|
||||||
|
<td width="58%" border="1" style="padding-left:20px;">
|
||||||
|
<table cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||||
|
<tr>
|
||||||
|
<td width="64%">Maße <small>L x B x H</small></td>
|
||||||
|
<td width="36%">in cm</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
<!-- rechte Zelle mit Wert -->
|
||||||
|
<td width="42%" border="1"><b> '.htmlspecialchars($dimsBHT).'</b></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<!-- Gewicht -->
|
||||||
|
<tr>
|
||||||
|
<td width="58%" border="1" style="padding-left:20px;">
|
||||||
|
<table cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||||
|
<tr>
|
||||||
|
<td width="64%">Gewicht</td>
|
||||||
|
<td width="36%">in Kg</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
<td width="42%" border="1"><b> '.fnum($bruttoWeightSum).' Kg</b></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<!-- Volumen -->
|
||||||
|
<tr>
|
||||||
|
<td width="58%" border="1" style="padding-left:20px;">
|
||||||
|
<table cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||||
|
<tr>
|
||||||
|
<td width="64%">Volumen</td>
|
||||||
|
<td width="36%">in m³</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
<td width="42%" border="1"><b> '.fnum($volume, 2).' m³</b></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<!-- Lagerplatz mit innerer Tabelle (optisch perfekt ausgerichtet) -->
|
||||||
|
<tr>
|
||||||
|
<td width="30%" border="1" style="padding-left:20px;">
|
||||||
|
<table cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||||
|
<tr>
|
||||||
|
<td width="100%">Lagerplatz</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
<td width="70%" border="1"><b> '.htmlspecialchars($storageLoc).'</b></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>';
|
||||||
|
|
||||||
|
// ---- Koordinaten der Meta-Zeile bestimmen (nimm deine Werte) ----
|
||||||
|
// Falls du sie schon berechnet hast, nutze deine $metaX, $metaY, $metaW.
|
||||||
|
// Beispiel, wie du sie meist setzt:
|
||||||
|
$metaX = $MARGIN_LEFT;
|
||||||
|
$metaW = $pdf->getPageWidth() - $MARGIN_LEFT - $MARGIN_RIGHT;
|
||||||
|
// $metaY hast du zuvor als Ziel-Y für den Meta-Block berechnet:
|
||||||
|
/// $metaY = ... (z.B. 50 + $bundleH + 3);
|
||||||
|
|
||||||
|
// ---- Spaltenbreiten wie in deinem metaWrap: 62% | 2% | 36% ----
|
||||||
|
$leftW = $metaW * 0.62;
|
||||||
|
$gapW = $metaW * 0.02;
|
||||||
|
$rightW = $metaW * 0.36;
|
||||||
|
|
||||||
|
// Obere linke Ecke der rechten Spalte:
|
||||||
|
$rightX = $metaX + $leftW + $gapW;
|
||||||
|
$rightY = $metaY;
|
||||||
|
|
||||||
|
// ---- Fester Rahmen in der rechten Spalte ----
|
||||||
|
$frameOuterPad = 1.0; // mm: Abstand vom Spaltenrand
|
||||||
|
$frameW = $rightW - 2*$frameOuterPad+8; // Rahmenbreite
|
||||||
|
$frameH = 24.38; // mm: feste Rahmenhöhe, nach Wunsch
|
||||||
|
$frameX = $rightX + $frameOuterPad-5.2;
|
||||||
|
$frameY = $rightY + $frameOuterPad+0.5;
|
||||||
|
|
||||||
|
$pdf->SetLineWidth(0.3);
|
||||||
|
$pdf->Rect($frameX, $frameY, $frameW, $frameH, 'D'); // der feste Rahmen
|
||||||
|
|
||||||
|
// ---- Base64-Bild zentriert & verzerrungsfrei in den Rahmen ----
|
||||||
|
$tmpImg = tempnam(sys_get_temp_dir(), 'epi_') . '.png';
|
||||||
|
file_put_contents($tmpImg, base64_decode($productImage));
|
||||||
|
|
||||||
|
list($imgWpx, $imgHpx) = getimagesize($tmpImg);
|
||||||
|
$imgRatio = ($imgHpx > 0) ? ($imgWpx / $imgHpx) : 1.0;
|
||||||
|
|
||||||
|
$innerPad = 2.0; // mm: Innenabstand im Rahmen
|
||||||
|
$maxW = $frameW - 2*$innerPad;
|
||||||
|
$maxH = $frameH - 2*$innerPad;
|
||||||
|
|
||||||
|
// proportional einpassen
|
||||||
|
if ($maxW / $maxH > $imgRatio) {
|
||||||
|
$drawH = $maxH;
|
||||||
|
$drawW = $maxH * $imgRatio;
|
||||||
|
} else {
|
||||||
|
$drawW = $maxW;
|
||||||
|
$drawH = $maxW / $imgRatio;
|
||||||
|
}
|
||||||
|
|
||||||
|
// zentrieren
|
||||||
|
$imgX = $frameX + ($frameW - $drawW) / 2;
|
||||||
|
$imgY = $frameY + ($frameH - $drawH) / 2;
|
||||||
|
|
||||||
|
$pdf->Image($tmpImg, $imgX, $imgY, $drawW, $drawH, '', '', '', false, 300);
|
||||||
|
@unlink($tmpImg);
|
||||||
|
|
||||||
|
$metaWrap = '
|
||||||
|
<table cellspacing="0" cellpadding="0" border="0" width="100%" style="margin-top:2px;">
|
||||||
|
<tr>
|
||||||
|
<td width="62%">'.$leftMeta.'</td>
|
||||||
|
<td width="2%"></td>
|
||||||
|
<td width="36%">'.$rightMeta.'</td>
|
||||||
|
</tr>
|
||||||
|
</table>';
|
||||||
|
|
||||||
|
// Meta-Block exakt an berechneter Position ausgeben
|
||||||
|
$pdf->writeHTMLCell($metaW, 0, $metaX, $metaY, $metaWrap, 0, 0, 0, true, 'L', true);
|
||||||
|
/** Output */
|
||||||
|
// Falls trotz allem vorher etwas ausgegeben wurde (Warnings), Buffer leeren:
|
||||||
|
if (ob_get_length()) { ob_end_clean(); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Äußerer Rahmen, Größenberechnung
|
||||||
|
|
||||||
|
// 1) Höhe der META-Zelle (zuletzt geschrieben) holen:
|
||||||
|
$metaH = $pdf->getLastH();
|
||||||
|
|
||||||
|
// 2) Y der Bundle-Tabelle kennst du (50.8 in deinem Code) + deren Höhe:
|
||||||
|
$bundleY = 50.8; // dein fixer Y für die Bundle-Tabelle
|
||||||
|
// $bundleH hast du bereits oben: $bundleH = $pdf->getLastH();
|
||||||
|
|
||||||
|
// 3) Bottom-Kanten aller Boxen berechnen:
|
||||||
|
$bottoms = [
|
||||||
|
$frameY + $frameH, // Logo-Box
|
||||||
|
$addrY + $addrBoxH, // Adress-Box
|
||||||
|
$prodY + $prodH, // Produktion-Box
|
||||||
|
$nameY + $nameBoxH, // Name-Box
|
||||||
|
$pnBoxY + $pnBoxH, // PN/QR-Box
|
||||||
|
$bundleY + $bundleH, // Bundle-Tabelle
|
||||||
|
$metaY + $metaH, // Meta-Block (linke Tabelle + rechter Bildrahmen)
|
||||||
|
];
|
||||||
|
|
||||||
|
// 4) Start-Y des Contentbereichs: oben an deinem Kopf beginnen
|
||||||
|
$outerY = min($frameY, $addrY, $prodY, $nameY, $pnBoxY, 46.0 /*Bundle-Header-Y*/, $metaY);
|
||||||
|
|
||||||
|
// 5) Untere Kante ist die größte Bottom-Kante:
|
||||||
|
$outerBottom = max($bottoms);
|
||||||
|
|
||||||
|
// 6) Außenrahmen-Geometrie:
|
||||||
|
$outerX = $MARGIN_LEFT+1.2;
|
||||||
|
$outerW = $pdf->getPageWidth() - $MARGIN_LEFT - $MARGIN_RIGHT+1;
|
||||||
|
$outerH = max(2, $outerBottom - $outerY)-1.2; // Mindeshöhe absichern
|
||||||
|
|
||||||
|
// 7) Dicke Linie zeichnen (z.B. 1.2 mm)
|
||||||
|
drawFixedBox($pdf, $outerX, $outerY, $outerW, $outerH, 1, '', 0, false);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$filename = 'Kistenetikett_'.preg_replace('/\s+/', '_', trim($productName)).'_'.$productNumber.$deviceNumber.'_'.date('Ymd_His').'.pdf';
|
||||||
|
$pdf->Output($filename, 'I');
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Zeichnet eine flexible, leere oder beschriftete Box mit TCPDF.
|
||||||
|
*
|
||||||
|
* @param TCPDF $pdf Referenz auf dein TCPDF-Objekt
|
||||||
|
* @param float $x Linke obere Ecke (mm)
|
||||||
|
* @param float $y Obere Position (mm)
|
||||||
|
* @param float $w Breite (mm)
|
||||||
|
* @param float $h Höhe (mm)
|
||||||
|
* @param float $border Linienstärke in mm (z. B. 0.3)
|
||||||
|
* @param string $text (Optional) Inhalt oder Beschriftung
|
||||||
|
* @param float $pad Innenabstand in mm
|
||||||
|
* @param bool $fill true = grau hinterlegt, false = leer
|
||||||
|
* @param string|null $style (Optional) Linienstil – 'solid', 'dashed', 'dotted'
|
||||||
|
*/
|
||||||
|
function drawFixedBox(
|
||||||
|
TCPDF $pdf,
|
||||||
|
float $x,
|
||||||
|
float $y,
|
||||||
|
float $w,
|
||||||
|
float $h,
|
||||||
|
float $border = 0.3,
|
||||||
|
string $text = '',
|
||||||
|
float $pad = 1.5,
|
||||||
|
bool $fill = false,
|
||||||
|
?string $style = 'solid'
|
||||||
|
): void {
|
||||||
|
// Farbe für Füllung (hellgrau, wenn aktiviert)
|
||||||
|
$fillColor = [240, 240, 240];
|
||||||
|
|
||||||
|
// Linienstil (falls angegeben)
|
||||||
|
switch ($style) {
|
||||||
|
case 'dashed':
|
||||||
|
$pdf->SetLineStyle(['width' => $border, 'dash' => '3,2']);
|
||||||
|
break;
|
||||||
|
case 'dotted':
|
||||||
|
$pdf->SetLineStyle(['width' => $border, 'dash' => '1,2']);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$pdf->SetLineWidth($border);
|
||||||
|
$pdf->SetLineStyle(['width' => $border]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1) Rahmen (und ggf. Füllung)
|
||||||
|
if ($fill) {
|
||||||
|
$pdf->SetFillColorArray($fillColor);
|
||||||
|
$pdf->Rect($x, $y, $w, $h, 'DF'); // Draw + Fill
|
||||||
|
} else {
|
||||||
|
$pdf->Rect($x, $y, $w, $h, 'D'); // nur Rahmen
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2) Optionaler Textinhalt – sauber eingepasst
|
||||||
|
if (trim($text) !== '') {
|
||||||
|
$pdf->StartTransform();
|
||||||
|
$pdf->Rect($x, $y, $w, $h, 'CNZ'); // Clip auf Box setzen
|
||||||
|
|
||||||
|
$pdf->writeHTMLCell(
|
||||||
|
$w - 2*$pad, $h - 2*$pad,
|
||||||
|
$x + $pad, $y + $pad,
|
||||||
|
'<div style="font-size:9px; line-height:1.2;">'.htmlspecialchars($text).'</div>',
|
||||||
|
0, 0, false, true, 'L', true
|
||||||
|
);
|
||||||
|
|
||||||
|
$pdf->StopTransform();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Linienstil zurücksetzen
|
||||||
|
$pdf->SetLineStyle(['width' => 0.3, 'dash' => 0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Produkt-Details mit Cache holen (vermeidet doppelte API-Calls).
|
||||||
|
*
|
||||||
|
* @param Epirent $Epi
|
||||||
|
* @param int|string $productPk
|
||||||
|
* @param array $cache Referenz-Array für Produkt-Cache
|
||||||
|
* @return object|null
|
||||||
|
*/
|
||||||
|
function fetchProductDetailCached($Epi, $productPk, array &$cache) {
|
||||||
|
$key = (string)$productPk;
|
||||||
|
if (isset($cache[$key])) {
|
||||||
|
return $cache[$key];
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
$res = $Epi->requestEpiApi('/v1/product/' . $key . '?cl=' . Epirent_Mandant);
|
||||||
|
$payload = json_decode($res, false);
|
||||||
|
$prod = $payload->payload[0] ?? null;
|
||||||
|
if ($prod) {
|
||||||
|
$cache[$key] = $prod;
|
||||||
|
return $prod;
|
||||||
|
}
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
// optional: loggen
|
||||||
|
}
|
||||||
|
$cache[$key] = null;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Rekursive Hilfsfunktion: fügt Materialien (und deren Submaterialien) zu $bundle hinzu
|
||||||
|
* und summiert alle Bruttogewichte in $bruttoWeightSum.
|
||||||
|
*
|
||||||
|
* @param Epirent $Epi
|
||||||
|
* @param array $materials Materialliste (vom Produkt)
|
||||||
|
* @param int $level aktuelle Ebene (1..MAX_BUNDLE_LEVEL)
|
||||||
|
* @param array &$bundle Ergebnisliste (wird befüllt)
|
||||||
|
* @param array &$cache Produkt-Cache
|
||||||
|
* @param array &$seenStack Schutz gegen Zyklen (Stack von Produkt-Keys)
|
||||||
|
* @param float $qtyMultiplier Multiplikator für Mengen aus übergeordneten Ebenen
|
||||||
|
* @param float &$bruttoWeightSum Summiert alle weight_gro-Werte × Menge
|
||||||
|
*/
|
||||||
|
function addMaterialsRecursive($Epi, array $materials, int $level, array &$bundle, array &$cache, array &$seenStack, float $qtyMultiplier = 1.0): void
|
||||||
|
{
|
||||||
|
global $bruttoWeightSum;
|
||||||
|
|
||||||
|
$MAX_BUNDLE_LEVEL = 5;
|
||||||
|
if ($level > $MAX_BUNDLE_LEVEL || empty($materials)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($materials as $mat) {
|
||||||
|
$isFree = !empty($mat->is_free_material);
|
||||||
|
$amount = isset($mat->amount) ? (float)$mat->amount : 1.0;
|
||||||
|
$effQty = $amount * $qtyMultiplier;
|
||||||
|
|
||||||
|
// 🟢 1. FREIES MATERIAL → nur Name + Menge, kein weiterer Drilldown
|
||||||
|
if ($isFree) {
|
||||||
|
$name = isset($mat->name) ? (string)$mat->name : '(Unbenanntes freies Material)';
|
||||||
|
$bundle[] = [
|
||||||
|
'qty' => $effQty,
|
||||||
|
'text' => $name,
|
||||||
|
'level' => $level,
|
||||||
|
'weight_kg' => null,
|
||||||
|
];
|
||||||
|
continue; // ⬅️ ganz wichtig: hier abbrechen
|
||||||
|
}
|
||||||
|
|
||||||
|
// 🟡 2. "Normales" Produkt-Material
|
||||||
|
$childPk = $mat->mat_product_pk ?? null;
|
||||||
|
if (!$childPk) {
|
||||||
|
$bundle[] = [
|
||||||
|
'qty' => $effQty,
|
||||||
|
'text' => '(Unbekanntes Material)',
|
||||||
|
'level' => $level,
|
||||||
|
'weight_kg' => null,
|
||||||
|
];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zyklen-Schutz
|
||||||
|
$childKey = (string)$childPk;
|
||||||
|
if (in_array($childKey, $seenStack, true)) {
|
||||||
|
$bundle[] = [
|
||||||
|
'qty' => $effQty,
|
||||||
|
'text' => '[Zyklus erkannt bei Produkt ' . $childKey . ']',
|
||||||
|
'level' => $level,
|
||||||
|
'weight_kg' => null,
|
||||||
|
];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Produktdetail abrufen (Cache-basiert)
|
||||||
|
$child = fetchProductDetailCached($Epi, $childPk, $cache);
|
||||||
|
|
||||||
|
// Basisinfos
|
||||||
|
$childName = $child->name ?? ('Produkt ' . $childKey);
|
||||||
|
$childWeightNet = $child->tech_data->weight_net ?? null;
|
||||||
|
$childWeightGross = $child->tech_data->weight_gro ?? null;
|
||||||
|
$childNumber = $child->product_no ?? null;
|
||||||
|
|
||||||
|
// 🧮 Bruttogewicht zur globalen Summe addieren
|
||||||
|
if (!empty($childWeightGross)) {
|
||||||
|
$bruttoWeightSum += $effQty * (float)$childWeightGross;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 📦 Anzeige: Artikelnummer in Klammern voranstellen
|
||||||
|
$displayName = $childNumber ? '(' . $childNumber . ') ' . $childName : $childName;
|
||||||
|
|
||||||
|
$bundle[] = [
|
||||||
|
'qty' => $effQty,
|
||||||
|
'text' => (string)$displayName,
|
||||||
|
'level' => $level,
|
||||||
|
'weight_kg' => $childWeightNet ? (float)$childWeightNet : null,
|
||||||
|
];
|
||||||
|
|
||||||
|
// 🔁 Rekursion für Sub-Materialien
|
||||||
|
if ($child && !empty($child->materials) && $level < $MAX_BUNDLE_LEVEL) {
|
||||||
|
$seenStack[] = $childKey;
|
||||||
|
addMaterialsRecursive($Epi, (array)$child->materials, $level + 1, $bundle, $cache, $seenStack, $effQty);
|
||||||
|
array_pop($seenStack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Einstieg: Baut das Bundle eines Produkts bis Tiefe MAX_BUNDLE_LEVEL
|
||||||
|
* und liefert zusätzlich die Bruttogewichtsumme zurück.
|
||||||
|
*
|
||||||
|
* @param Epirent $Epi
|
||||||
|
* @param object $product
|
||||||
|
* @param float &$bruttoWeightSum Rückgabe der aufsummierten weight_gro
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function buildBundleForProduct($Epi, $product, float &$bruttoWeightSum = 0.0): array
|
||||||
|
{
|
||||||
|
$bundle = [];
|
||||||
|
$cache = [];
|
||||||
|
$seen = [];
|
||||||
|
$materials = isset($product->materials) ? (array)$product->materials : [];
|
||||||
|
|
||||||
|
addMaterialsRecursive($Epi, $materials, 1, $bundle, $cache, $seen, 1.0, $bruttoWeightSum);
|
||||||
|
return $bundle;
|
||||||
|
}
|
||||||
@@ -8,10 +8,30 @@
|
|||||||
Dashboard
|
Dashboard
|
||||||
</a>
|
</a>
|
||||||
<a class="nav-link" href=orders.php>
|
<a class="nav-link" href=orders.php>
|
||||||
<div class="sb-nav-link-icon"><i class="fas fa-tachometer-alt"></i></div>
|
<div class="sb-nav-link-icon"><i class="fas fa-money-bill-wave"></i></div>
|
||||||
Aufträge
|
Aufträge
|
||||||
</a>
|
</a>
|
||||||
|
<a class="nav-link" href=insurance.php>
|
||||||
|
<div class="sb-nav-link-icon"><i class="fas fa-car-burst"></i></div>
|
||||||
|
Versicherung
|
||||||
|
</a>
|
||||||
|
<a class="nav-link" href=labelprint.php>
|
||||||
|
<div class="sb-nav-link-icon"><i class="fas fa-tags"></i></div>
|
||||||
|
Labelprint
|
||||||
|
</a>
|
||||||
|
<a class="nav-link" href=imagecheck.php>
|
||||||
|
<div class="sb-nav-link-icon"><i class="fas fa-image"></i></div>
|
||||||
|
Imagecheck
|
||||||
|
</a>
|
||||||
|
<a class="nav-link" href=groupofgoodscheck.php>
|
||||||
|
<div class="sb-nav-link-icon"><i class="fas fa-layer-group"></i></div>
|
||||||
|
Warengruppencheck
|
||||||
|
</a>
|
||||||
|
<a class="nav-link" href=ROI.php>
|
||||||
|
<div class="sb-nav-link-icon"><i class="fas fa-comment-dollar"></i></div>
|
||||||
|
Return-Of-Invest
|
||||||
|
</a>
|
||||||
|
|
||||||
<div class="sb-sidenav-menu-heading">Addons</div>
|
<div class="sb-sidenav-menu-heading">Addons</div>
|
||||||
<a class="nav-link" target="_blank" href="../Packmonitor.php">
|
<a class="nav-link" target="_blank" href="../Packmonitor.php">
|
||||||
<div class="sb-nav-link-icon"><i class="fas fa-box-open"></i></div>
|
<div class="sb-nav-link-icon"><i class="fas fa-box-open"></i></div>
|
||||||
@@ -25,6 +45,13 @@
|
|||||||
<div class="sb-nav-link-icon"><i class="fas fa-list"></i></div>
|
<div class="sb-nav-link-icon"><i class="fas fa-list"></i></div>
|
||||||
Pack- & Aufgabenmonitor
|
Pack- & Aufgabenmonitor
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="sb-sidenav-menu-heading">Config</div>
|
||||||
|
<a class="nav-link" href=editconfig.php>
|
||||||
|
<div class="sb-nav-link-icon"><i class="fas fa-tachometer-alt"></i></div>
|
||||||
|
Config
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="sb-sidenav-footer">
|
<div class="sb-sidenav-footer">
|
||||||
|
|||||||
BIN
src/assets/font/Hurme1/HurmeGeometricSans1-Black.ttf
Normal file
BIN
src/assets/font/Hurme1/HurmeGeometricSans1-Black.ttf
Normal file
Binary file not shown.
BIN
src/assets/font/Hurme1/HurmeGeometricSans1-BlackOblique.ttf
Normal file
BIN
src/assets/font/Hurme1/HurmeGeometricSans1-BlackOblique.ttf
Normal file
Binary file not shown.
BIN
src/assets/font/Hurme1/HurmeGeometricSans1-Bold.ttf
Normal file
BIN
src/assets/font/Hurme1/HurmeGeometricSans1-Bold.ttf
Normal file
Binary file not shown.
BIN
src/assets/font/Hurme1/HurmeGeometricSans1-BoldOblique.ttf
Normal file
BIN
src/assets/font/Hurme1/HurmeGeometricSans1-BoldOblique.ttf
Normal file
Binary file not shown.
BIN
src/assets/font/Hurme1/HurmeGeometricSans1-Hairline.ttf
Normal file
BIN
src/assets/font/Hurme1/HurmeGeometricSans1-Hairline.ttf
Normal file
Binary file not shown.
BIN
src/assets/font/Hurme1/HurmeGeometricSans1-HairlineOblique.ttf
Normal file
BIN
src/assets/font/Hurme1/HurmeGeometricSans1-HairlineOblique.ttf
Normal file
Binary file not shown.
BIN
src/assets/font/Hurme1/HurmeGeometricSans1-Light.ttf
Normal file
BIN
src/assets/font/Hurme1/HurmeGeometricSans1-Light.ttf
Normal file
Binary file not shown.
BIN
src/assets/font/Hurme1/HurmeGeometricSans1-LightOblique.ttf
Normal file
BIN
src/assets/font/Hurme1/HurmeGeometricSans1-LightOblique.ttf
Normal file
Binary file not shown.
BIN
src/assets/font/Hurme1/HurmeGeometricSans1-Regular.ttf
Normal file
BIN
src/assets/font/Hurme1/HurmeGeometricSans1-Regular.ttf
Normal file
Binary file not shown.
BIN
src/assets/font/Hurme1/HurmeGeometricSans1-RegularOblique.ttf
Normal file
BIN
src/assets/font/Hurme1/HurmeGeometricSans1-RegularOblique.ttf
Normal file
Binary file not shown.
BIN
src/assets/font/Hurme1/HurmeGeometricSans1-SemiBold.ttf
Normal file
BIN
src/assets/font/Hurme1/HurmeGeometricSans1-SemiBold.ttf
Normal file
Binary file not shown.
BIN
src/assets/font/Hurme1/HurmeGeometricSans1-SemiBoldOblique.ttf
Normal file
BIN
src/assets/font/Hurme1/HurmeGeometricSans1-SemiBoldOblique.ttf
Normal file
Binary file not shown.
BIN
src/assets/font/Hurme1/HurmeGeometricSans1-Thin.ttf
Normal file
BIN
src/assets/font/Hurme1/HurmeGeometricSans1-Thin.ttf
Normal file
Binary file not shown.
BIN
src/assets/font/Hurme1/HurmeGeometricSans1-ThinOblique.ttf
Normal file
BIN
src/assets/font/Hurme1/HurmeGeometricSans1-ThinOblique.ttf
Normal file
Binary file not shown.
BIN
src/assets/font/Hurme3/HurmeGeometricSans3-Black.ttf
Normal file
BIN
src/assets/font/Hurme3/HurmeGeometricSans3-Black.ttf
Normal file
Binary file not shown.
BIN
src/assets/font/Hurme3/HurmeGeometricSans3-BlackOblique.ttf
Normal file
BIN
src/assets/font/Hurme3/HurmeGeometricSans3-BlackOblique.ttf
Normal file
Binary file not shown.
BIN
src/assets/font/Hurme3/HurmeGeometricSans3-Bold.ttf
Normal file
BIN
src/assets/font/Hurme3/HurmeGeometricSans3-Bold.ttf
Normal file
Binary file not shown.
BIN
src/assets/font/Hurme3/HurmeGeometricSans3-BoldOblique.ttf
Normal file
BIN
src/assets/font/Hurme3/HurmeGeometricSans3-BoldOblique.ttf
Normal file
Binary file not shown.
BIN
src/assets/font/Hurme3/HurmeGeometricSans3-Hairline.ttf
Normal file
BIN
src/assets/font/Hurme3/HurmeGeometricSans3-Hairline.ttf
Normal file
Binary file not shown.
BIN
src/assets/font/Hurme3/HurmeGeometricSans3-HairlineOblique.ttf
Normal file
BIN
src/assets/font/Hurme3/HurmeGeometricSans3-HairlineOblique.ttf
Normal file
Binary file not shown.
BIN
src/assets/font/Hurme3/HurmeGeometricSans3-Light.ttf
Normal file
BIN
src/assets/font/Hurme3/HurmeGeometricSans3-Light.ttf
Normal file
Binary file not shown.
BIN
src/assets/font/Hurme3/HurmeGeometricSans3-LightOblique.ttf
Normal file
BIN
src/assets/font/Hurme3/HurmeGeometricSans3-LightOblique.ttf
Normal file
Binary file not shown.
BIN
src/assets/font/Hurme3/HurmeGeometricSans3-Regular.ttf
Normal file
BIN
src/assets/font/Hurme3/HurmeGeometricSans3-Regular.ttf
Normal file
Binary file not shown.
BIN
src/assets/font/Hurme3/HurmeGeometricSans3-RegularOblique.ttf
Normal file
BIN
src/assets/font/Hurme3/HurmeGeometricSans3-RegularOblique.ttf
Normal file
Binary file not shown.
BIN
src/assets/font/Hurme3/HurmeGeometricSans3-SemiBold.ttf
Normal file
BIN
src/assets/font/Hurme3/HurmeGeometricSans3-SemiBold.ttf
Normal file
Binary file not shown.
BIN
src/assets/font/Hurme3/HurmeGeometricSans3-SemiBoldOblique.ttf
Normal file
BIN
src/assets/font/Hurme3/HurmeGeometricSans3-SemiBoldOblique.ttf
Normal file
Binary file not shown.
BIN
src/assets/font/Hurme3/HurmeGeometricSans3-Thin.ttf
Normal file
BIN
src/assets/font/Hurme3/HurmeGeometricSans3-Thin.ttf
Normal file
Binary file not shown.
BIN
src/assets/font/Hurme3/HurmeGeometricSans3-ThinOblique.ttf
Normal file
BIN
src/assets/font/Hurme3/HurmeGeometricSans3-ThinOblique.ttf
Normal file
Binary file not shown.
BIN
src/assets/img/logo.png
Normal file
BIN
src/assets/img/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 30 KiB |
10663
src/fa/css/all.css
Normal file
10663
src/fa/css/all.css
Normal file
File diff suppressed because it is too large
Load Diff
9
src/fa/css/all.min.css
vendored
Normal file
9
src/fa/css/all.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
2219
src/fa/css/brands.css
Normal file
2219
src/fa/css/brands.css
Normal file
File diff suppressed because it is too large
Load Diff
6
src/fa/css/brands.min.css
vendored
Normal file
6
src/fa/css/brands.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
8361
src/fa/css/fontawesome.css
vendored
Normal file
8361
src/fa/css/fontawesome.css
vendored
Normal file
File diff suppressed because it is too large
Load Diff
8
src/fa/css/fontawesome.min.css
vendored
Normal file
8
src/fa/css/fontawesome.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
31
src/fa/css/regular.css
Normal file
31
src/fa/css/regular.css
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
/*!
|
||||||
|
* Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com
|
||||||
|
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||||
|
* Copyright 2025 Fonticons, Inc.
|
||||||
|
*/
|
||||||
|
:root, :host {
|
||||||
|
--fa-family-classic: "Font Awesome 7 Free";
|
||||||
|
--fa-font-regular: normal 400 1em/1 var(--fa-family-classic);
|
||||||
|
/* deprecated: this older custom property will be removed next major release */
|
||||||
|
--fa-style-family-classic: var(--fa-family-classic);
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Font Awesome 7 Free";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: block;
|
||||||
|
src: url("../webfonts/fa-regular-400.woff2");
|
||||||
|
}
|
||||||
|
.far {
|
||||||
|
--fa-family: var(--fa-family-classic);
|
||||||
|
--fa-style: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-classic {
|
||||||
|
--fa-family: var(--fa-family-classic);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-regular {
|
||||||
|
--fa-style: 400;
|
||||||
|
}
|
||||||
6
src/fa/css/regular.min.css
vendored
Normal file
6
src/fa/css/regular.min.css
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
/*!
|
||||||
|
* Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com
|
||||||
|
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||||
|
* Copyright 2025 Fonticons, Inc.
|
||||||
|
*/
|
||||||
|
:host,:root{--fa-family-classic:"Font Awesome 7 Free";--fa-font-regular:normal 400 1em/1 var(--fa-family-classic);--fa-style-family-classic:var(--fa-family-classic)}@font-face{font-family:"Font Awesome 7 Free";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-regular-400.woff2)}.far{--fa-style:400}.fa-classic,.far{--fa-family:var(--fa-family-classic)}.fa-regular{--fa-style:400}
|
||||||
31
src/fa/css/solid.css
Normal file
31
src/fa/css/solid.css
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
/*!
|
||||||
|
* Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com
|
||||||
|
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||||
|
* Copyright 2025 Fonticons, Inc.
|
||||||
|
*/
|
||||||
|
:root, :host {
|
||||||
|
--fa-family-classic: "Font Awesome 7 Free";
|
||||||
|
--fa-font-solid: normal 900 1em/1 var(--fa-family-classic);
|
||||||
|
/* deprecated: this older custom property will be removed next major release */
|
||||||
|
--fa-style-family-classic: var(--fa-family-classic);
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Font Awesome 7 Free";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 900;
|
||||||
|
font-display: block;
|
||||||
|
src: url("../webfonts/fa-solid-900.woff2");
|
||||||
|
}
|
||||||
|
.fas {
|
||||||
|
--fa-family: var(--fa-family-classic);
|
||||||
|
--fa-style: 900;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-classic {
|
||||||
|
--fa-family: var(--fa-family-classic);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-solid {
|
||||||
|
--fa-style: 900;
|
||||||
|
}
|
||||||
6
src/fa/css/solid.min.css
vendored
Normal file
6
src/fa/css/solid.min.css
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
/*!
|
||||||
|
* Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com
|
||||||
|
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||||
|
* Copyright 2025 Fonticons, Inc.
|
||||||
|
*/
|
||||||
|
:host,:root{--fa-family-classic:"Font Awesome 7 Free";--fa-font-solid:normal 900 1em/1 var(--fa-family-classic);--fa-style-family-classic:var(--fa-family-classic)}@font-face{font-family:"Font Awesome 7 Free";font-style:normal;font-weight:900;font-display:block;src:url(../webfonts/fa-solid-900.woff2)}.fas{--fa-style:900}.fa-classic,.fas{--fa-family:var(--fa-family-classic)}.fa-solid{--fa-style:900}
|
||||||
556
src/fa/css/svg-with-js.css
Normal file
556
src/fa/css/svg-with-js.css
Normal file
@@ -0,0 +1,556 @@
|
|||||||
|
/*!
|
||||||
|
* Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com
|
||||||
|
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||||
|
* Copyright 2025 Fonticons, Inc.
|
||||||
|
*/
|
||||||
|
:root, :host {
|
||||||
|
--fa-font-solid: normal 900 1em/1 "Font Awesome 7 Free";
|
||||||
|
--fa-font-regular: normal 400 1em/1 "Font Awesome 7 Free";
|
||||||
|
--fa-font-light: normal 300 1em/1 "Font Awesome 7 Pro";
|
||||||
|
--fa-font-thin: normal 100 1em/1 "Font Awesome 7 Pro";
|
||||||
|
--fa-font-duotone: normal 900 1em/1 "Font Awesome 7 Duotone";
|
||||||
|
--fa-font-duotone-regular: normal 400 1em/1 "Font Awesome 7 Duotone";
|
||||||
|
--fa-font-duotone-light: normal 300 1em/1 "Font Awesome 7 Duotone";
|
||||||
|
--fa-font-duotone-thin: normal 100 1em/1 "Font Awesome 7 Duotone";
|
||||||
|
--fa-font-brands: normal 400 1em/1 "Font Awesome 7 Brands";
|
||||||
|
--fa-font-sharp-solid: normal 900 1em/1 "Font Awesome 7 Sharp";
|
||||||
|
--fa-font-sharp-regular: normal 400 1em/1 "Font Awesome 7 Sharp";
|
||||||
|
--fa-font-sharp-light: normal 300 1em/1 "Font Awesome 7 Sharp";
|
||||||
|
--fa-font-sharp-thin: normal 100 1em/1 "Font Awesome 7 Sharp";
|
||||||
|
--fa-font-sharp-duotone-solid: normal 900 1em/1 "Font Awesome 7 Sharp Duotone";
|
||||||
|
--fa-font-sharp-duotone-regular: normal 400 1em/1 "Font Awesome 7 Sharp Duotone";
|
||||||
|
--fa-font-sharp-duotone-light: normal 300 1em/1 "Font Awesome 7 Sharp Duotone";
|
||||||
|
--fa-font-sharp-duotone-thin: normal 100 1em/1 "Font Awesome 7 Sharp Duotone";
|
||||||
|
--fa-font-slab-regular: normal 400 1em/1 "Font Awesome 7 Slab";
|
||||||
|
--fa-font-slab-press-regular: normal 400 1em/1 "Font Awesome 7 Slab Press";
|
||||||
|
--fa-font-whiteboard-semibold: normal 600 1em/1 "Font Awesome 7 Whiteboard";
|
||||||
|
--fa-font-thumbprint-light: normal 300 1em/1 "Font Awesome 7 Thumbprint";
|
||||||
|
--fa-font-notdog-solid: normal 900 1em/1 "Font Awesome 7 Notdog";
|
||||||
|
--fa-font-notdog-duo-solid: normal 900 1em/1 "Font Awesome 7 Notdog Duo";
|
||||||
|
--fa-font-etch-solid: normal 900 1em/1 "Font Awesome 7 Etch";
|
||||||
|
--fa-font-jelly-regular: normal 400 1em/1 "Font Awesome 7 Jelly";
|
||||||
|
--fa-font-jelly-fill-regular: normal 400 1em/1 "Font Awesome 7 Jelly Fill";
|
||||||
|
--fa-font-jelly-duo-regular: normal 400 1em/1 "Font Awesome 7 Jelly Duo";
|
||||||
|
--fa-font-chisel-regular: normal 400 1em/1 "Font Awesome 7 Chisel";
|
||||||
|
--fa-font-utility-semibold: normal 600 1em/1 "Font Awesome 7 Utility";
|
||||||
|
--fa-font-utility-duo-semibold: normal 600 1em/1 "Font Awesome 7 Utility Duo";
|
||||||
|
--fa-font-utility-fill-semibold: normal 600 1em/1 "Font Awesome 7 Utility Fill";
|
||||||
|
}
|
||||||
|
|
||||||
|
.svg-inline--fa {
|
||||||
|
box-sizing: content-box;
|
||||||
|
display: var(--fa-display, inline-block);
|
||||||
|
height: 1em;
|
||||||
|
overflow: visible;
|
||||||
|
vertical-align: -0.125em;
|
||||||
|
width: var(--fa-width, 1.25em);
|
||||||
|
}
|
||||||
|
.svg-inline--fa.fa-2xs {
|
||||||
|
vertical-align: 0.1em;
|
||||||
|
}
|
||||||
|
.svg-inline--fa.fa-xs {
|
||||||
|
vertical-align: 0em;
|
||||||
|
}
|
||||||
|
.svg-inline--fa.fa-sm {
|
||||||
|
vertical-align: -0.0714285714em;
|
||||||
|
}
|
||||||
|
.svg-inline--fa.fa-lg {
|
||||||
|
vertical-align: -0.2em;
|
||||||
|
}
|
||||||
|
.svg-inline--fa.fa-xl {
|
||||||
|
vertical-align: -0.25em;
|
||||||
|
}
|
||||||
|
.svg-inline--fa.fa-2xl {
|
||||||
|
vertical-align: -0.3125em;
|
||||||
|
}
|
||||||
|
.svg-inline--fa.fa-pull-left,
|
||||||
|
.svg-inline--fa .fa-pull-start {
|
||||||
|
float: inline-start;
|
||||||
|
margin-inline-end: var(--fa-pull-margin, 0.3em);
|
||||||
|
}
|
||||||
|
.svg-inline--fa.fa-pull-right,
|
||||||
|
.svg-inline--fa .fa-pull-end {
|
||||||
|
float: inline-end;
|
||||||
|
margin-inline-start: var(--fa-pull-margin, 0.3em);
|
||||||
|
}
|
||||||
|
.svg-inline--fa.fa-li {
|
||||||
|
width: var(--fa-li-width, 2em);
|
||||||
|
inset-inline-start: calc(-1 * var(--fa-li-width, 2em));
|
||||||
|
inset-block-start: 0.25em; /* syncing vertical alignment with Web Font rendering */
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-layers-counter, .fa-layers-text {
|
||||||
|
display: inline-block;
|
||||||
|
position: absolute;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-layers {
|
||||||
|
display: inline-block;
|
||||||
|
height: 1em;
|
||||||
|
position: relative;
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: -0.125em;
|
||||||
|
width: var(--fa-width, 1.25em);
|
||||||
|
}
|
||||||
|
.fa-layers .svg-inline--fa {
|
||||||
|
inset: 0;
|
||||||
|
margin: auto;
|
||||||
|
position: absolute;
|
||||||
|
transform-origin: center center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-layers-text {
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
transform-origin: center center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-layers-counter {
|
||||||
|
background-color: var(--fa-counter-background-color, #ff253a);
|
||||||
|
border-radius: var(--fa-counter-border-radius, 1em);
|
||||||
|
box-sizing: border-box;
|
||||||
|
color: var(--fa-inverse, #fff);
|
||||||
|
line-height: var(--fa-counter-line-height, 1);
|
||||||
|
max-width: var(--fa-counter-max-width, 5em);
|
||||||
|
min-width: var(--fa-counter-min-width, 1.5em);
|
||||||
|
overflow: hidden;
|
||||||
|
padding: var(--fa-counter-padding, 0.25em 0.5em);
|
||||||
|
right: var(--fa-right, 0);
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
top: var(--fa-top, 0);
|
||||||
|
transform: scale(var(--fa-counter-scale, 0.25));
|
||||||
|
transform-origin: top right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-layers-bottom-right {
|
||||||
|
bottom: var(--fa-bottom, 0);
|
||||||
|
right: var(--fa-right, 0);
|
||||||
|
top: auto;
|
||||||
|
transform: scale(var(--fa-layers-scale, 0.25));
|
||||||
|
transform-origin: bottom right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-layers-bottom-left {
|
||||||
|
bottom: var(--fa-bottom, 0);
|
||||||
|
left: var(--fa-left, 0);
|
||||||
|
right: auto;
|
||||||
|
top: auto;
|
||||||
|
transform: scale(var(--fa-layers-scale, 0.25));
|
||||||
|
transform-origin: bottom left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-layers-top-right {
|
||||||
|
top: var(--fa-top, 0);
|
||||||
|
right: var(--fa-right, 0);
|
||||||
|
transform: scale(var(--fa-layers-scale, 0.25));
|
||||||
|
transform-origin: top right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-layers-top-left {
|
||||||
|
left: var(--fa-left, 0);
|
||||||
|
right: auto;
|
||||||
|
top: var(--fa-top, 0);
|
||||||
|
transform: scale(var(--fa-layers-scale, 0.25));
|
||||||
|
transform-origin: top left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-1x {
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-2x {
|
||||||
|
font-size: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-3x {
|
||||||
|
font-size: 3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-4x {
|
||||||
|
font-size: 4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-5x {
|
||||||
|
font-size: 5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-6x {
|
||||||
|
font-size: 6em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-7x {
|
||||||
|
font-size: 7em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-8x {
|
||||||
|
font-size: 8em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-9x {
|
||||||
|
font-size: 9em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-10x {
|
||||||
|
font-size: 10em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-2xs {
|
||||||
|
font-size: calc(10 / 16 * 1em); /* converts a 10px size into an em-based value that's relative to the scale's 16px base */
|
||||||
|
line-height: calc(1 / 10 * 1em); /* sets the line-height of the icon back to that of it's parent */
|
||||||
|
vertical-align: calc((6 / 10 - 0.375) * 1em); /* vertically centers the icon taking into account the surrounding text's descender */
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-xs {
|
||||||
|
font-size: calc(12 / 16 * 1em); /* converts a 12px size into an em-based value that's relative to the scale's 16px base */
|
||||||
|
line-height: calc(1 / 12 * 1em); /* sets the line-height of the icon back to that of it's parent */
|
||||||
|
vertical-align: calc((6 / 12 - 0.375) * 1em); /* vertically centers the icon taking into account the surrounding text's descender */
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-sm {
|
||||||
|
font-size: calc(14 / 16 * 1em); /* converts a 14px size into an em-based value that's relative to the scale's 16px base */
|
||||||
|
line-height: calc(1 / 14 * 1em); /* sets the line-height of the icon back to that of it's parent */
|
||||||
|
vertical-align: calc((6 / 14 - 0.375) * 1em); /* vertically centers the icon taking into account the surrounding text's descender */
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-lg {
|
||||||
|
font-size: calc(20 / 16 * 1em); /* converts a 20px size into an em-based value that's relative to the scale's 16px base */
|
||||||
|
line-height: calc(1 / 20 * 1em); /* sets the line-height of the icon back to that of it's parent */
|
||||||
|
vertical-align: calc((6 / 20 - 0.375) * 1em); /* vertically centers the icon taking into account the surrounding text's descender */
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-xl {
|
||||||
|
font-size: calc(24 / 16 * 1em); /* converts a 24px size into an em-based value that's relative to the scale's 16px base */
|
||||||
|
line-height: calc(1 / 24 * 1em); /* sets the line-height of the icon back to that of it's parent */
|
||||||
|
vertical-align: calc((6 / 24 - 0.375) * 1em); /* vertically centers the icon taking into account the surrounding text's descender */
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-2xl {
|
||||||
|
font-size: calc(32 / 16 * 1em); /* converts a 32px size into an em-based value that's relative to the scale's 16px base */
|
||||||
|
line-height: calc(1 / 32 * 1em); /* sets the line-height of the icon back to that of it's parent */
|
||||||
|
vertical-align: calc((6 / 32 - 0.375) * 1em); /* vertically centers the icon taking into account the surrounding text's descender */
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-width-auto {
|
||||||
|
--fa-width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-fw,
|
||||||
|
.fa-width-fixed {
|
||||||
|
--fa-width: 1.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-ul {
|
||||||
|
list-style-type: none;
|
||||||
|
margin-inline-start: var(--fa-li-margin, 2.5em);
|
||||||
|
padding-inline-start: 0;
|
||||||
|
}
|
||||||
|
.fa-ul > li {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-li {
|
||||||
|
inset-inline-start: calc(-1 * var(--fa-li-width, 2em));
|
||||||
|
position: absolute;
|
||||||
|
text-align: center;
|
||||||
|
width: var(--fa-li-width, 2em);
|
||||||
|
line-height: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Heads Up: Bordered Icons will not be supported in the future!
|
||||||
|
- This feature will be deprecated in the next major release of Font Awesome (v8)!
|
||||||
|
- You may continue to use it in this version *v7), but it will not be supported in Font Awesome v8.
|
||||||
|
*/
|
||||||
|
/* Notes:
|
||||||
|
* --@{v.$css-prefix}-border-width = 1/16 by default (to render as ~1px based on a 16px default font-size)
|
||||||
|
* --@{v.$css-prefix}-border-padding =
|
||||||
|
** 3/16 for vertical padding (to give ~2px of vertical whitespace around an icon considering it's vertical alignment)
|
||||||
|
** 4/16 for horizontal padding (to give ~4px of horizontal whitespace around an icon)
|
||||||
|
*/
|
||||||
|
.fa-border {
|
||||||
|
border-color: var(--fa-border-color, #eee);
|
||||||
|
border-radius: var(--fa-border-radius, 0.1em);
|
||||||
|
border-style: var(--fa-border-style, solid);
|
||||||
|
border-width: var(--fa-border-width, 0.0625em);
|
||||||
|
box-sizing: var(--fa-border-box-sizing, content-box);
|
||||||
|
padding: var(--fa-border-padding, 0.1875em 0.25em);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-pull-left,
|
||||||
|
.fa-pull-start {
|
||||||
|
float: inline-start;
|
||||||
|
margin-inline-end: var(--fa-pull-margin, 0.3em);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-pull-right,
|
||||||
|
.fa-pull-end {
|
||||||
|
float: inline-end;
|
||||||
|
margin-inline-start: var(--fa-pull-margin, 0.3em);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-beat {
|
||||||
|
animation-name: fa-beat;
|
||||||
|
animation-delay: var(--fa-animation-delay, 0s);
|
||||||
|
animation-direction: var(--fa-animation-direction, normal);
|
||||||
|
animation-duration: var(--fa-animation-duration, 1s);
|
||||||
|
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||||
|
animation-timing-function: var(--fa-animation-timing, ease-in-out);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-bounce {
|
||||||
|
animation-name: fa-bounce;
|
||||||
|
animation-delay: var(--fa-animation-delay, 0s);
|
||||||
|
animation-direction: var(--fa-animation-direction, normal);
|
||||||
|
animation-duration: var(--fa-animation-duration, 1s);
|
||||||
|
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||||
|
animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.28, 0.84, 0.42, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-fade {
|
||||||
|
animation-name: fa-fade;
|
||||||
|
animation-delay: var(--fa-animation-delay, 0s);
|
||||||
|
animation-direction: var(--fa-animation-direction, normal);
|
||||||
|
animation-duration: var(--fa-animation-duration, 1s);
|
||||||
|
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||||
|
animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-beat-fade {
|
||||||
|
animation-name: fa-beat-fade;
|
||||||
|
animation-delay: var(--fa-animation-delay, 0s);
|
||||||
|
animation-direction: var(--fa-animation-direction, normal);
|
||||||
|
animation-duration: var(--fa-animation-duration, 1s);
|
||||||
|
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||||
|
animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-flip {
|
||||||
|
animation-name: fa-flip;
|
||||||
|
animation-delay: var(--fa-animation-delay, 0s);
|
||||||
|
animation-direction: var(--fa-animation-direction, normal);
|
||||||
|
animation-duration: var(--fa-animation-duration, 1s);
|
||||||
|
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||||
|
animation-timing-function: var(--fa-animation-timing, ease-in-out);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-shake {
|
||||||
|
animation-name: fa-shake;
|
||||||
|
animation-delay: var(--fa-animation-delay, 0s);
|
||||||
|
animation-direction: var(--fa-animation-direction, normal);
|
||||||
|
animation-duration: var(--fa-animation-duration, 1s);
|
||||||
|
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||||
|
animation-timing-function: var(--fa-animation-timing, linear);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-spin {
|
||||||
|
animation-name: fa-spin;
|
||||||
|
animation-delay: var(--fa-animation-delay, 0s);
|
||||||
|
animation-direction: var(--fa-animation-direction, normal);
|
||||||
|
animation-duration: var(--fa-animation-duration, 2s);
|
||||||
|
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||||
|
animation-timing-function: var(--fa-animation-timing, linear);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-spin-reverse {
|
||||||
|
--fa-animation-direction: reverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-pulse,
|
||||||
|
.fa-spin-pulse {
|
||||||
|
animation-name: fa-spin;
|
||||||
|
animation-direction: var(--fa-animation-direction, normal);
|
||||||
|
animation-duration: var(--fa-animation-duration, 1s);
|
||||||
|
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||||
|
animation-timing-function: var(--fa-animation-timing, steps(8));
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-reduced-motion: reduce) {
|
||||||
|
.fa-beat,
|
||||||
|
.fa-bounce,
|
||||||
|
.fa-fade,
|
||||||
|
.fa-beat-fade,
|
||||||
|
.fa-flip,
|
||||||
|
.fa-pulse,
|
||||||
|
.fa-shake,
|
||||||
|
.fa-spin,
|
||||||
|
.fa-spin-pulse {
|
||||||
|
animation: none !important;
|
||||||
|
transition: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes fa-beat {
|
||||||
|
0%, 90% {
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
45% {
|
||||||
|
transform: scale(var(--fa-beat-scale, 1.25));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes fa-bounce {
|
||||||
|
0% {
|
||||||
|
transform: scale(1, 1) translateY(0);
|
||||||
|
}
|
||||||
|
10% {
|
||||||
|
transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0);
|
||||||
|
}
|
||||||
|
30% {
|
||||||
|
transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em));
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0);
|
||||||
|
}
|
||||||
|
57% {
|
||||||
|
transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em));
|
||||||
|
}
|
||||||
|
64% {
|
||||||
|
transform: scale(1, 1) translateY(0);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: scale(1, 1) translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes fa-fade {
|
||||||
|
50% {
|
||||||
|
opacity: var(--fa-fade-opacity, 0.4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes fa-beat-fade {
|
||||||
|
0%, 100% {
|
||||||
|
opacity: var(--fa-beat-fade-opacity, 0.4);
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale(var(--fa-beat-fade-scale, 1.125));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes fa-flip {
|
||||||
|
50% {
|
||||||
|
transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes fa-shake {
|
||||||
|
0% {
|
||||||
|
transform: rotate(-15deg);
|
||||||
|
}
|
||||||
|
4% {
|
||||||
|
transform: rotate(15deg);
|
||||||
|
}
|
||||||
|
8%, 24% {
|
||||||
|
transform: rotate(-18deg);
|
||||||
|
}
|
||||||
|
12%, 28% {
|
||||||
|
transform: rotate(18deg);
|
||||||
|
}
|
||||||
|
16% {
|
||||||
|
transform: rotate(-22deg);
|
||||||
|
}
|
||||||
|
20% {
|
||||||
|
transform: rotate(22deg);
|
||||||
|
}
|
||||||
|
32% {
|
||||||
|
transform: rotate(-12deg);
|
||||||
|
}
|
||||||
|
36% {
|
||||||
|
transform: rotate(12deg);
|
||||||
|
}
|
||||||
|
40%, 100% {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes fa-spin {
|
||||||
|
0% {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.fa-rotate-90 {
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-rotate-180 {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-rotate-270 {
|
||||||
|
transform: rotate(270deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-flip-horizontal {
|
||||||
|
transform: scale(-1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-flip-vertical {
|
||||||
|
transform: scale(1, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-flip-both,
|
||||||
|
.fa-flip-horizontal.fa-flip-vertical {
|
||||||
|
transform: scale(-1, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-rotate-by {
|
||||||
|
transform: rotate(var(--fa-rotate-angle, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
.svg-inline--fa .fa-primary {
|
||||||
|
fill: var(--fa-primary-color, currentColor);
|
||||||
|
opacity: var(--fa-primary-opacity, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.svg-inline--fa .fa-secondary {
|
||||||
|
fill: var(--fa-secondary-color, currentColor);
|
||||||
|
opacity: var(--fa-secondary-opacity, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.svg-inline--fa.fa-swap-opacity .fa-primary {
|
||||||
|
opacity: var(--fa-secondary-opacity, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.svg-inline--fa.fa-swap-opacity .fa-secondary {
|
||||||
|
opacity: var(--fa-primary-opacity, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.svg-inline--fa mask .fa-primary,
|
||||||
|
.svg-inline--fa mask .fa-secondary {
|
||||||
|
fill: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.svg-inline--fa.fa-inverse {
|
||||||
|
fill: var(--fa-inverse, #fff);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-stack {
|
||||||
|
display: inline-block;
|
||||||
|
height: 2em;
|
||||||
|
line-height: 2em;
|
||||||
|
position: relative;
|
||||||
|
vertical-align: middle;
|
||||||
|
width: 2.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-inverse {
|
||||||
|
color: var(--fa-inverse, #fff);
|
||||||
|
}
|
||||||
|
|
||||||
|
.svg-inline--fa.fa-stack-1x {
|
||||||
|
--fa-width: 1.25em;
|
||||||
|
height: 1em;
|
||||||
|
width: var(--fa-width);
|
||||||
|
}
|
||||||
|
.svg-inline--fa.fa-stack-2x {
|
||||||
|
--fa-width: 2.5em;
|
||||||
|
height: 2em;
|
||||||
|
width: var(--fa-width);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-stack-1x,
|
||||||
|
.fa-stack-2x {
|
||||||
|
inset: 0;
|
||||||
|
margin: auto;
|
||||||
|
position: absolute;
|
||||||
|
z-index: var(--fa-stack-z-index, auto);
|
||||||
|
}
|
||||||
6
src/fa/css/svg-with-js.min.css
vendored
Normal file
6
src/fa/css/svg-with-js.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
182
src/fa/css/svg.css
Normal file
182
src/fa/css/svg.css
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
/*!
|
||||||
|
* Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com
|
||||||
|
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||||
|
* Copyright 2025 Fonticons, Inc.
|
||||||
|
*/
|
||||||
|
:root, :host {
|
||||||
|
--fa-font-solid: normal 900 1em/1 "Font Awesome 7 Free";
|
||||||
|
--fa-font-regular: normal 400 1em/1 "Font Awesome 7 Free";
|
||||||
|
--fa-font-light: normal 300 1em/1 "Font Awesome 7 Pro";
|
||||||
|
--fa-font-thin: normal 100 1em/1 "Font Awesome 7 Pro";
|
||||||
|
--fa-font-duotone: normal 900 1em/1 "Font Awesome 7 Duotone";
|
||||||
|
--fa-font-duotone-regular: normal 400 1em/1 "Font Awesome 7 Duotone";
|
||||||
|
--fa-font-duotone-light: normal 300 1em/1 "Font Awesome 7 Duotone";
|
||||||
|
--fa-font-duotone-thin: normal 100 1em/1 "Font Awesome 7 Duotone";
|
||||||
|
--fa-font-brands: normal 400 1em/1 "Font Awesome 7 Brands";
|
||||||
|
--fa-font-sharp-solid: normal 900 1em/1 "Font Awesome 7 Sharp";
|
||||||
|
--fa-font-sharp-regular: normal 400 1em/1 "Font Awesome 7 Sharp";
|
||||||
|
--fa-font-sharp-light: normal 300 1em/1 "Font Awesome 7 Sharp";
|
||||||
|
--fa-font-sharp-thin: normal 100 1em/1 "Font Awesome 7 Sharp";
|
||||||
|
--fa-font-sharp-duotone-solid: normal 900 1em/1 "Font Awesome 7 Sharp Duotone";
|
||||||
|
--fa-font-sharp-duotone-regular: normal 400 1em/1 "Font Awesome 7 Sharp Duotone";
|
||||||
|
--fa-font-sharp-duotone-light: normal 300 1em/1 "Font Awesome 7 Sharp Duotone";
|
||||||
|
--fa-font-sharp-duotone-thin: normal 100 1em/1 "Font Awesome 7 Sharp Duotone";
|
||||||
|
--fa-font-slab-regular: normal 400 1em/1 "Font Awesome 7 Slab";
|
||||||
|
--fa-font-slab-press-regular: normal 400 1em/1 "Font Awesome 7 Slab Press";
|
||||||
|
--fa-font-whiteboard-semibold: normal 600 1em/1 "Font Awesome 7 Whiteboard";
|
||||||
|
--fa-font-thumbprint-light: normal 300 1em/1 "Font Awesome 7 Thumbprint";
|
||||||
|
--fa-font-notdog-solid: normal 900 1em/1 "Font Awesome 7 Notdog";
|
||||||
|
--fa-font-notdog-duo-solid: normal 900 1em/1 "Font Awesome 7 Notdog Duo";
|
||||||
|
--fa-font-etch-solid: normal 900 1em/1 "Font Awesome 7 Etch";
|
||||||
|
--fa-font-jelly-regular: normal 400 1em/1 "Font Awesome 7 Jelly";
|
||||||
|
--fa-font-jelly-fill-regular: normal 400 1em/1 "Font Awesome 7 Jelly Fill";
|
||||||
|
--fa-font-jelly-duo-regular: normal 400 1em/1 "Font Awesome 7 Jelly Duo";
|
||||||
|
--fa-font-chisel-regular: normal 400 1em/1 "Font Awesome 7 Chisel";
|
||||||
|
--fa-font-utility-semibold: normal 600 1em/1 "Font Awesome 7 Utility";
|
||||||
|
--fa-font-utility-duo-semibold: normal 600 1em/1 "Font Awesome 7 Utility Duo";
|
||||||
|
--fa-font-utility-fill-semibold: normal 600 1em/1 "Font Awesome 7 Utility Fill";
|
||||||
|
}
|
||||||
|
|
||||||
|
.svg-inline--fa {
|
||||||
|
box-sizing: content-box;
|
||||||
|
display: var(--fa-display, inline-block);
|
||||||
|
height: 1em;
|
||||||
|
overflow: visible;
|
||||||
|
vertical-align: -0.125em;
|
||||||
|
width: var(--fa-width, 1.25em);
|
||||||
|
}
|
||||||
|
.svg-inline--fa.fa-2xs {
|
||||||
|
vertical-align: 0.1em;
|
||||||
|
}
|
||||||
|
.svg-inline--fa.fa-xs {
|
||||||
|
vertical-align: 0em;
|
||||||
|
}
|
||||||
|
.svg-inline--fa.fa-sm {
|
||||||
|
vertical-align: -0.0714285714em;
|
||||||
|
}
|
||||||
|
.svg-inline--fa.fa-lg {
|
||||||
|
vertical-align: -0.2em;
|
||||||
|
}
|
||||||
|
.svg-inline--fa.fa-xl {
|
||||||
|
vertical-align: -0.25em;
|
||||||
|
}
|
||||||
|
.svg-inline--fa.fa-2xl {
|
||||||
|
vertical-align: -0.3125em;
|
||||||
|
}
|
||||||
|
.svg-inline--fa.fa-li {
|
||||||
|
width: var(--fa-li-width, 2em);
|
||||||
|
inset-inline-start: calc(-1 * var(--fa-li-width, 2em));
|
||||||
|
inset-block-start: 0.25em; /* syncing vertical alignment with Web Font rendering */
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-layers-counter, .fa-layers-text {
|
||||||
|
display: inline-block;
|
||||||
|
position: absolute;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-layers {
|
||||||
|
display: inline-block;
|
||||||
|
height: 1em;
|
||||||
|
position: relative;
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: -0.125em;
|
||||||
|
width: var(--fa-width, 1.25em);
|
||||||
|
}
|
||||||
|
.fa-layers .svg-inline--fa {
|
||||||
|
inset: 0;
|
||||||
|
margin: auto;
|
||||||
|
position: absolute;
|
||||||
|
transform-origin: center center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-layers-text {
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
transform-origin: center center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-layers-counter {
|
||||||
|
background-color: var(--fa-counter-background-color, #ff253a);
|
||||||
|
border-radius: var(--fa-counter-border-radius, 1em);
|
||||||
|
box-sizing: border-box;
|
||||||
|
color: var(--fa-inverse, #fff);
|
||||||
|
line-height: var(--fa-counter-line-height, 1);
|
||||||
|
max-width: var(--fa-counter-max-width, 5em);
|
||||||
|
min-width: var(--fa-counter-min-width, 1.5em);
|
||||||
|
overflow: hidden;
|
||||||
|
padding: var(--fa-counter-padding, 0.25em 0.5em);
|
||||||
|
right: var(--fa-right, 0);
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
top: var(--fa-top, 0);
|
||||||
|
transform: scale(var(--fa-counter-scale, 0.25));
|
||||||
|
transform-origin: top right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-layers-bottom-right {
|
||||||
|
bottom: var(--fa-bottom, 0);
|
||||||
|
right: var(--fa-right, 0);
|
||||||
|
top: auto;
|
||||||
|
transform: scale(var(--fa-layers-scale, 0.25));
|
||||||
|
transform-origin: bottom right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-layers-bottom-left {
|
||||||
|
bottom: var(--fa-bottom, 0);
|
||||||
|
left: var(--fa-left, 0);
|
||||||
|
right: auto;
|
||||||
|
top: auto;
|
||||||
|
transform: scale(var(--fa-layers-scale, 0.25));
|
||||||
|
transform-origin: bottom left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-layers-top-right {
|
||||||
|
top: var(--fa-top, 0);
|
||||||
|
right: var(--fa-right, 0);
|
||||||
|
transform: scale(var(--fa-layers-scale, 0.25));
|
||||||
|
transform-origin: top right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-layers-top-left {
|
||||||
|
left: var(--fa-left, 0);
|
||||||
|
right: auto;
|
||||||
|
top: var(--fa-top, 0);
|
||||||
|
transform: scale(var(--fa-layers-scale, 0.25));
|
||||||
|
transform-origin: top left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.svg-inline--fa .fa-primary {
|
||||||
|
fill: var(--fa-primary-color, currentColor);
|
||||||
|
opacity: var(--fa-primary-opacity, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.svg-inline--fa .fa-secondary {
|
||||||
|
fill: var(--fa-secondary-color, currentColor);
|
||||||
|
opacity: var(--fa-secondary-opacity, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.svg-inline--fa.fa-swap-opacity .fa-primary {
|
||||||
|
opacity: var(--fa-secondary-opacity, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.svg-inline--fa.fa-swap-opacity .fa-secondary {
|
||||||
|
opacity: var(--fa-primary-opacity, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.svg-inline--fa mask .fa-primary,
|
||||||
|
.svg-inline--fa mask .fa-secondary {
|
||||||
|
fill: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.svg-inline--fa.fa-inverse {
|
||||||
|
fill: var(--fa-inverse, #fff);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-stack-1x,
|
||||||
|
.fa-stack-2x {
|
||||||
|
inset: 0;
|
||||||
|
margin: auto;
|
||||||
|
position: absolute;
|
||||||
|
z-index: var(--fa-stack-z-index, auto);
|
||||||
|
}
|
||||||
6
src/fa/css/svg.min.css
vendored
Normal file
6
src/fa/css/svg.min.css
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
/*!
|
||||||
|
* Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com
|
||||||
|
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||||
|
* Copyright 2025 Fonticons, Inc.
|
||||||
|
*/
|
||||||
|
:host,:root{--fa-font-solid:normal 900 1em/1 "Font Awesome 7 Free";--fa-font-regular:normal 400 1em/1 "Font Awesome 7 Free";--fa-font-light:normal 300 1em/1 "Font Awesome 7 Pro";--fa-font-thin:normal 100 1em/1 "Font Awesome 7 Pro";--fa-font-duotone:normal 900 1em/1 "Font Awesome 7 Duotone";--fa-font-duotone-regular:normal 400 1em/1 "Font Awesome 7 Duotone";--fa-font-duotone-light:normal 300 1em/1 "Font Awesome 7 Duotone";--fa-font-duotone-thin:normal 100 1em/1 "Font Awesome 7 Duotone";--fa-font-brands:normal 400 1em/1 "Font Awesome 7 Brands";--fa-font-sharp-solid:normal 900 1em/1 "Font Awesome 7 Sharp";--fa-font-sharp-regular:normal 400 1em/1 "Font Awesome 7 Sharp";--fa-font-sharp-light:normal 300 1em/1 "Font Awesome 7 Sharp";--fa-font-sharp-thin:normal 100 1em/1 "Font Awesome 7 Sharp";--fa-font-sharp-duotone-solid:normal 900 1em/1 "Font Awesome 7 Sharp Duotone";--fa-font-sharp-duotone-regular:normal 400 1em/1 "Font Awesome 7 Sharp Duotone";--fa-font-sharp-duotone-light:normal 300 1em/1 "Font Awesome 7 Sharp Duotone";--fa-font-sharp-duotone-thin:normal 100 1em/1 "Font Awesome 7 Sharp Duotone";--fa-font-slab-regular:normal 400 1em/1 "Font Awesome 7 Slab";--fa-font-slab-press-regular:normal 400 1em/1 "Font Awesome 7 Slab Press";--fa-font-whiteboard-semibold:normal 600 1em/1 "Font Awesome 7 Whiteboard";--fa-font-thumbprint-light:normal 300 1em/1 "Font Awesome 7 Thumbprint";--fa-font-notdog-solid:normal 900 1em/1 "Font Awesome 7 Notdog";--fa-font-notdog-duo-solid:normal 900 1em/1 "Font Awesome 7 Notdog Duo";--fa-font-etch-solid:normal 900 1em/1 "Font Awesome 7 Etch";--fa-font-jelly-regular:normal 400 1em/1 "Font Awesome 7 Jelly";--fa-font-jelly-fill-regular:normal 400 1em/1 "Font Awesome 7 Jelly Fill";--fa-font-jelly-duo-regular:normal 400 1em/1 "Font Awesome 7 Jelly Duo";--fa-font-chisel-regular:normal 400 1em/1 "Font Awesome 7 Chisel";--fa-font-utility-semibold:normal 600 1em/1 "Font Awesome 7 Utility";--fa-font-utility-duo-semibold:normal 600 1em/1 "Font Awesome 7 Utility Duo";--fa-font-utility-fill-semibold:normal 600 1em/1 "Font Awesome 7 Utility Fill"}.svg-inline--fa{box-sizing:content-box;display:var(--fa-display,inline-block);height:1em;overflow:visible;vertical-align:-.125em;width:var(--fa-width,1.25em)}.svg-inline--fa.fa-2xs{vertical-align:.1em}.svg-inline--fa.fa-xs{vertical-align:0}.svg-inline--fa.fa-sm{vertical-align:-.0714285714em}.svg-inline--fa.fa-lg{vertical-align:-.2em}.svg-inline--fa.fa-xl{vertical-align:-.25em}.svg-inline--fa.fa-2xl{vertical-align:-.3125em}.svg-inline--fa.fa-li{width:var(--fa-li-width,2em);inset-inline-start:calc(var(--fa-li-width, 2em)*-1);inset-block-start:.25em}.fa-layers-counter,.fa-layers-text{display:inline-block;position:absolute;text-align:center}.fa-layers{display:inline-block;height:1em;position:relative;text-align:center;vertical-align:-.125em;width:var(--fa-width,1.25em)}.fa-layers .svg-inline--fa{inset:0;margin:auto;position:absolute;transform-origin:center center}.fa-layers-text{left:50%;top:50%;transform:translate(-50%,-50%);transform-origin:center center}.fa-layers-counter{background-color:var(--fa-counter-background-color,#ff253a);border-radius:var(--fa-counter-border-radius,1em);box-sizing:border-box;color:var(--fa-inverse,#fff);line-height:var(--fa-counter-line-height,1);max-width:var(--fa-counter-max-width,5em);min-width:var(--fa-counter-min-width,1.5em);overflow:hidden;padding:var(--fa-counter-padding,.25em .5em);right:var(--fa-right,0);text-overflow:ellipsis;top:var(--fa-top,0);transform:scale(var(--fa-counter-scale,.25));transform-origin:top right}.fa-layers-bottom-right{bottom:var(--fa-bottom,0);right:var(--fa-right,0);top:auto;transform:scale(var(--fa-layers-scale,.25));transform-origin:bottom right}.fa-layers-bottom-left{bottom:var(--fa-bottom,0);left:var(--fa-left,0);right:auto;top:auto;transform:scale(var(--fa-layers-scale,.25));transform-origin:bottom left}.fa-layers-top-right{top:var(--fa-top,0);right:var(--fa-right,0);transform:scale(var(--fa-layers-scale,.25));transform-origin:top right}.fa-layers-top-left{left:var(--fa-left,0);right:auto;top:var(--fa-top,0);transform:scale(var(--fa-layers-scale,.25));transform-origin:top left}.svg-inline--fa .fa-primary{fill:var(--fa-primary-color,currentColor);opacity:var(--fa-primary-opacity,1)}.svg-inline--fa .fa-secondary{fill:var(--fa-secondary-color,currentColor)}.svg-inline--fa .fa-secondary,.svg-inline--fa.fa-swap-opacity .fa-primary{opacity:var(--fa-secondary-opacity,.4)}.svg-inline--fa.fa-swap-opacity .fa-secondary{opacity:var(--fa-primary-opacity,1)}.svg-inline--fa mask .fa-primary,.svg-inline--fa mask .fa-secondary{fill:#000}.svg-inline--fa.fa-inverse{fill:var(--fa-inverse,#fff)}.fa-stack-1x,.fa-stack-2x{inset:0;margin:auto;position:absolute;z-index:var(--fa-stack-z-index,auto)}
|
||||||
27
src/fa/css/v4-font-face.css
Normal file
27
src/fa/css/v4-font-face.css
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
/*!
|
||||||
|
* Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com
|
||||||
|
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||||
|
* Copyright 2025 Fonticons, Inc.
|
||||||
|
*/
|
||||||
|
@font-face {
|
||||||
|
font-family: "FontAwesome";
|
||||||
|
font-display: block;
|
||||||
|
src: url("../webfonts/fa-solid-900.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: "FontAwesome";
|
||||||
|
font-display: block;
|
||||||
|
src: url("../webfonts/fa-brands-400.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: "FontAwesome";
|
||||||
|
font-display: block;
|
||||||
|
src: url("../webfonts/fa-regular-400.woff2") format("woff2");
|
||||||
|
unicode-range: U+F003, U+F006, U+F014, U+F016-F017, U+F01A-F01B, U+F01D, U+F022, U+F03E, U+F044, U+F046, U+F05C-F05D, U+F06E, U+F070, U+F087-F088, U+F08A, U+F094, U+F096-F097, U+F09D, U+F0A0, U+F0A2, U+F0A4-F0A7, U+F0C5, U+F0C7, U+F0E5-F0E6, U+F0EB, U+F0F6-F0F8, U+F10C, U+F114-F115, U+F118-F11A, U+F11C-F11D, U+F133, U+F147, U+F14E, U+F150-F152, U+F185-F186, U+F18E, U+F190-F192, U+F196, U+F1C1-F1C9, U+F1D9, U+F1DB, U+F1E3, U+F1EA, U+F1F7, U+F1F9, U+F20A, U+F247-F248, U+F24A, U+F24D, U+F255-F25B, U+F25D, U+F271-F274, U+F278, U+F27B, U+F28C, U+F28E, U+F29C, U+F2B5, U+F2B7, U+F2BA, U+F2BC, U+F2BE, U+F2C0-F2C1, U+F2C3, U+F2D0, U+F2D2, U+F2D4, U+F2DC;
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: "FontAwesome";
|
||||||
|
font-display: block;
|
||||||
|
src: url("../webfonts/fa-v4compatibility.woff2") format("woff2");
|
||||||
|
unicode-range: U+F041, U+F047, U+F065-F066, U+F07D-F07E, U+F080, U+F08B, U+F08E, U+F090, U+F09A, U+F0AC, U+F0AE, U+F0B2, U+F0D0, U+F0D6, U+F0E4, U+F0EC, U+F10A-F10B, U+F123, U+F13E, U+F148-F149, U+F14C, U+F156, U+F15E, U+F160-F161, U+F163, U+F175-F178, U+F195, U+F1F8, U+F219, U+F27A;
|
||||||
|
}
|
||||||
6
src/fa/css/v4-font-face.min.css
vendored
Normal file
6
src/fa/css/v4-font-face.min.css
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
/*!
|
||||||
|
* Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com
|
||||||
|
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||||
|
* Copyright 2025 Fonticons, Inc.
|
||||||
|
*/
|
||||||
|
@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-solid-900.woff2) format("woff2")}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-brands-400.woff2) format("woff2")}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-regular-400.woff2) format("woff2");unicode-range:u+f003,u+f006,u+f014,u+f016-f017,u+f01a-f01b,u+f01d,u+f022,u+f03e,u+f044,u+f046,u+f05c-f05d,u+f06e,u+f070,u+f087-f088,u+f08a,u+f094,u+f096-f097,u+f09d,u+f0a0,u+f0a2,u+f0a4-f0a7,u+f0c5,u+f0c7,u+f0e5-f0e6,u+f0eb,u+f0f6-f0f8,u+f10c,u+f114-f115,u+f118-f11a,u+f11c-f11d,u+f133,u+f147,u+f14e,u+f150-f152,u+f185-f186,u+f18e,u+f190-f192,u+f196,u+f1c1-f1c9,u+f1d9,u+f1db,u+f1e3,u+f1ea,u+f1f7,u+f1f9,u+f20a,u+f247-f248,u+f24a,u+f24d,u+f255-f25b,u+f25d,u+f271-f274,u+f278,u+f27b,u+f28c,u+f28e,u+f29c,u+f2b5,u+f2b7,u+f2ba,u+f2bc,u+f2be,u+f2c0-f2c1,u+f2c3,u+f2d0,u+f2d2,u+f2d4,u+f2dc}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-v4compatibility.woff2) format("woff2");unicode-range:u+f041,u+f047,u+f065-f066,u+f07d-f07e,u+f080,u+f08b,u+f08e,u+f090,u+f09a,u+f0ac,u+f0ae,u+f0b2,u+f0d0,u+f0d6,u+f0e4,u+f0ec,u+f10a-f10b,u+f123,u+f13e,u+f148-f149,u+f14c,u+f156,u+f15e,u+f160-f161,u+f163,u+f175-f178,u+f195,u+f1f8,u+f219,u+f27a}
|
||||||
2818
src/fa/css/v4-shims.css
Normal file
2818
src/fa/css/v4-shims.css
Normal file
File diff suppressed because it is too large
Load Diff
6
src/fa/css/v4-shims.min.css
vendored
Normal file
6
src/fa/css/v4-shims.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
23
src/fa/css/v5-font-face.css
Normal file
23
src/fa/css/v5-font-face.css
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
/*!
|
||||||
|
* Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com
|
||||||
|
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||||
|
* Copyright 2025 Fonticons, Inc.
|
||||||
|
*/
|
||||||
|
@font-face {
|
||||||
|
font-family: "Font Awesome 5 Brands";
|
||||||
|
font-display: block;
|
||||||
|
font-weight: 400;
|
||||||
|
src: url("../webfonts/fa-brands-400.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: "Font Awesome 5 Free";
|
||||||
|
font-display: block;
|
||||||
|
font-weight: 900;
|
||||||
|
src: url("../webfonts/fa-solid-900.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: "Font Awesome 5 Free";
|
||||||
|
font-display: block;
|
||||||
|
font-weight: 400;
|
||||||
|
src: url("../webfonts/fa-regular-400.woff2") format("woff2");
|
||||||
|
}
|
||||||
6
src/fa/css/v5-font-face.min.css
vendored
Normal file
6
src/fa/css/v5-font-face.min.css
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
/*!
|
||||||
|
* Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com
|
||||||
|
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||||
|
* Copyright 2025 Fonticons, Inc.
|
||||||
|
*/
|
||||||
|
@font-face{font-family:"Font Awesome 5 Brands";font-display:block;font-weight:400;src:url(../webfonts/fa-brands-400.woff2) format("woff2")}@font-face{font-family:"Font Awesome 5 Free";font-display:block;font-weight:900;src:url(../webfonts/fa-solid-900.woff2) format("woff2")}@font-face{font-family:"Font Awesome 5 Free";font-display:block;font-weight:400;src:url(../webfonts/fa-regular-400.woff2) format("woff2")}
|
||||||
BIN
src/fa/webfonts/fa-brands-400.woff2
Normal file
BIN
src/fa/webfonts/fa-brands-400.woff2
Normal file
Binary file not shown.
BIN
src/fa/webfonts/fa-regular-400.woff2
Normal file
BIN
src/fa/webfonts/fa-regular-400.woff2
Normal file
Binary file not shown.
BIN
src/fa/webfonts/fa-solid-900.woff2
Normal file
BIN
src/fa/webfonts/fa-solid-900.woff2
Normal file
Binary file not shown.
BIN
src/fa/webfonts/fa-v4compatibility.woff2
Normal file
BIN
src/fa/webfonts/fa-v4compatibility.woff2
Normal file
Binary file not shown.
18
vendor/autoload.php
vendored
18
vendor/autoload.php
vendored
@@ -2,6 +2,24 @@
|
|||||||
|
|
||||||
// autoload.php @generated by Composer
|
// autoload.php @generated by Composer
|
||||||
|
|
||||||
|
if (PHP_VERSION_ID < 50600) {
|
||||||
|
if (!headers_sent()) {
|
||||||
|
header('HTTP/1.1 500 Internal Server Error');
|
||||||
|
}
|
||||||
|
$err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
|
||||||
|
if (!ini_get('display_errors')) {
|
||||||
|
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
|
||||||
|
fwrite(STDERR, $err);
|
||||||
|
} elseif (!headers_sent()) {
|
||||||
|
echo $err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trigger_error(
|
||||||
|
$err,
|
||||||
|
E_USER_ERROR
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
require_once __DIR__ . '/composer/autoload_real.php';
|
require_once __DIR__ . '/composer/autoload_real.php';
|
||||||
|
|
||||||
return ComposerAutoloaderInitab00f29709bdbfe3a1abd7d2d66d569c::getLoader();
|
return ComposerAutoloaderInitab00f29709bdbfe3a1abd7d2d66d569c::getLoader();
|
||||||
|
|||||||
851
vendor/chillerlan/php-qrcode/.idea/codeStyles/Project.xml
generated
vendored
851
vendor/chillerlan/php-qrcode/.idea/codeStyles/Project.xml
generated
vendored
@@ -1,851 +0,0 @@
|
|||||||
<component name="ProjectCodeStyleConfiguration">
|
|
||||||
<code_scheme name="Project" version="173">
|
|
||||||
<option name="AUTODETECT_INDENTS" value="false" />
|
|
||||||
<option name="OTHER_INDENT_OPTIONS">
|
|
||||||
<value>
|
|
||||||
<option name="USE_TAB_CHARACTER" value="true" />
|
|
||||||
<option name="SMART_TABS" value="true" />
|
|
||||||
</value>
|
|
||||||
</option>
|
|
||||||
<option name="RIGHT_MARGIN" value="130" />
|
|
||||||
<CssCodeStyleSettings>
|
|
||||||
<option name="HEX_COLOR_LOWER_CASE" value="true" />
|
|
||||||
<option name="HEX_COLOR_SHORT_FORMAT" value="true" />
|
|
||||||
<option name="KEEP_SINGLE_LINE_BLOCKS" value="true" />
|
|
||||||
<option name="SPACE_BEFORE_OPENING_BRACE" value="false" />
|
|
||||||
</CssCodeStyleSettings>
|
|
||||||
<DB2CodeStyleSettings version="6">
|
|
||||||
<option name="USE_GENERAL_STYLE" value="false" />
|
|
||||||
<option name="TYPE_CASE" value="3" />
|
|
||||||
<option name="CUSTOM_TYPE_CASE" value="3" />
|
|
||||||
<option name="ALIAS_CASE" value="4" />
|
|
||||||
<option name="BUILT_IN_CASE" value="0" />
|
|
||||||
<option name="QUERY_TRUE_INDENT" value="false" />
|
|
||||||
<option name="QUERY_ALIGN_ELEMENTS" value="false" />
|
|
||||||
<option name="QUERY_ALIGN_LINE_COMMENTS" value="false" />
|
|
||||||
<option name="INSERT_EL_COMMA" value="2" />
|
|
||||||
<option name="SET_EL_WRAP" value="0" />
|
|
||||||
<option name="SET_EL_COMMA" value="0" />
|
|
||||||
<option name="WITH_EL_WRAP" value="0" />
|
|
||||||
<option name="WITH_EL_COMMA" value="0" />
|
|
||||||
<option name="SELECT_EL_WRAP" value="3" />
|
|
||||||
<option name="SELECT_EL_COMMA" value="2" />
|
|
||||||
<option name="FROM_EL_WRAP" value="2" />
|
|
||||||
<option name="FROM_EL_COMMA" value="2" />
|
|
||||||
<option name="FROM_PLACE_ON" value="10" />
|
|
||||||
<option name="WHERE_EL_WRAP" value="3" />
|
|
||||||
<option name="WHERE_EL_BOUND" value="2" />
|
|
||||||
<option name="ORDER_EL_COMMA" value="2" />
|
|
||||||
<option name="TABLE_OPENING" value="1" />
|
|
||||||
<option name="TABLE_CONTENT" value="2" />
|
|
||||||
<option name="TABLE_CLOSING" value="3" />
|
|
||||||
<option name="TABLE_ALTER_INSTRUCTION_ALIGN" value="false" />
|
|
||||||
<option name="POST_OPT_WRAP_1" value="true" />
|
|
||||||
<option name="POST_OPT_ALIGN" value="false" />
|
|
||||||
<option name="ROUTINE_ARG_COMMA" value="2" />
|
|
||||||
<option name="ROUTINE_ARG_ALIGN_TYPES" value="true" />
|
|
||||||
<option name="IMP_DECLARE_EL_WRAP" value="1" />
|
|
||||||
<option name="IMP_IF_THEN_WRAP_THEN" value="true" />
|
|
||||||
<option name="CORTEGE_SPACE_BEFORE_L_PAREN" value="false" />
|
|
||||||
<option name="EXPR_CASE_WHEN_WRAP" value="false" />
|
|
||||||
<option name="EXPR_CASE_THEN_WRAP" value="true" />
|
|
||||||
<option name="PRIMARY_KEY_NAME_TEMPLATE" value="{table}_{columns}_pk" />
|
|
||||||
</DB2CodeStyleSettings>
|
|
||||||
<DerbyCodeStyleSettings version="6">
|
|
||||||
<option name="USE_GENERAL_STYLE" value="false" />
|
|
||||||
<option name="TYPE_CASE" value="3" />
|
|
||||||
<option name="CUSTOM_TYPE_CASE" value="3" />
|
|
||||||
<option name="ALIAS_CASE" value="4" />
|
|
||||||
<option name="BUILT_IN_CASE" value="0" />
|
|
||||||
<option name="QUERY_TRUE_INDENT" value="false" />
|
|
||||||
<option name="QUERY_ALIGN_ELEMENTS" value="false" />
|
|
||||||
<option name="QUERY_ALIGN_LINE_COMMENTS" value="false" />
|
|
||||||
<option name="INSERT_EL_COMMA" value="2" />
|
|
||||||
<option name="SET_EL_WRAP" value="0" />
|
|
||||||
<option name="SET_EL_COMMA" value="0" />
|
|
||||||
<option name="WITH_EL_WRAP" value="0" />
|
|
||||||
<option name="WITH_EL_COMMA" value="0" />
|
|
||||||
<option name="SELECT_EL_WRAP" value="3" />
|
|
||||||
<option name="SELECT_EL_COMMA" value="2" />
|
|
||||||
<option name="FROM_EL_WRAP" value="2" />
|
|
||||||
<option name="FROM_EL_COMMA" value="2" />
|
|
||||||
<option name="FROM_PLACE_ON" value="10" />
|
|
||||||
<option name="WHERE_EL_WRAP" value="3" />
|
|
||||||
<option name="WHERE_EL_BOUND" value="2" />
|
|
||||||
<option name="ORDER_EL_COMMA" value="2" />
|
|
||||||
<option name="TABLE_OPENING" value="1" />
|
|
||||||
<option name="TABLE_CONTENT" value="2" />
|
|
||||||
<option name="TABLE_CLOSING" value="3" />
|
|
||||||
<option name="TABLE_ALTER_INSTRUCTION_ALIGN" value="false" />
|
|
||||||
<option name="POST_OPT_WRAP_1" value="true" />
|
|
||||||
<option name="POST_OPT_ALIGN" value="false" />
|
|
||||||
<option name="ROUTINE_ARG_COMMA" value="2" />
|
|
||||||
<option name="ROUTINE_ARG_ALIGN_TYPES" value="true" />
|
|
||||||
<option name="IMP_DECLARE_EL_WRAP" value="1" />
|
|
||||||
<option name="IMP_IF_THEN_WRAP_THEN" value="true" />
|
|
||||||
<option name="CORTEGE_SPACE_BEFORE_L_PAREN" value="false" />
|
|
||||||
<option name="EXPR_CASE_WHEN_WRAP" value="false" />
|
|
||||||
<option name="EXPR_CASE_THEN_WRAP" value="true" />
|
|
||||||
<option name="PRIMARY_KEY_NAME_TEMPLATE" value="{table}_{columns}_pk" />
|
|
||||||
</DerbyCodeStyleSettings>
|
|
||||||
<H2CodeStyleSettings version="6">
|
|
||||||
<option name="USE_GENERAL_STYLE" value="false" />
|
|
||||||
<option name="TYPE_CASE" value="3" />
|
|
||||||
<option name="CUSTOM_TYPE_CASE" value="3" />
|
|
||||||
<option name="ALIAS_CASE" value="4" />
|
|
||||||
<option name="BUILT_IN_CASE" value="0" />
|
|
||||||
<option name="QUERY_TRUE_INDENT" value="false" />
|
|
||||||
<option name="QUERY_ALIGN_ELEMENTS" value="false" />
|
|
||||||
<option name="QUERY_ALIGN_LINE_COMMENTS" value="false" />
|
|
||||||
<option name="INSERT_EL_COMMA" value="2" />
|
|
||||||
<option name="SET_EL_WRAP" value="0" />
|
|
||||||
<option name="SET_EL_COMMA" value="0" />
|
|
||||||
<option name="WITH_EL_WRAP" value="0" />
|
|
||||||
<option name="WITH_EL_COMMA" value="0" />
|
|
||||||
<option name="SELECT_EL_WRAP" value="3" />
|
|
||||||
<option name="SELECT_EL_COMMA" value="2" />
|
|
||||||
<option name="FROM_EL_WRAP" value="2" />
|
|
||||||
<option name="FROM_EL_COMMA" value="2" />
|
|
||||||
<option name="FROM_PLACE_ON" value="10" />
|
|
||||||
<option name="WHERE_EL_WRAP" value="3" />
|
|
||||||
<option name="WHERE_EL_BOUND" value="2" />
|
|
||||||
<option name="ORDER_EL_COMMA" value="2" />
|
|
||||||
<option name="TABLE_OPENING" value="1" />
|
|
||||||
<option name="TABLE_CONTENT" value="2" />
|
|
||||||
<option name="TABLE_CLOSING" value="3" />
|
|
||||||
<option name="TABLE_ALTER_INSTRUCTION_ALIGN" value="false" />
|
|
||||||
<option name="POST_OPT_WRAP_1" value="true" />
|
|
||||||
<option name="POST_OPT_ALIGN" value="false" />
|
|
||||||
<option name="ROUTINE_ARG_COMMA" value="2" />
|
|
||||||
<option name="ROUTINE_ARG_ALIGN_TYPES" value="true" />
|
|
||||||
<option name="IMP_DECLARE_EL_WRAP" value="1" />
|
|
||||||
<option name="IMP_IF_THEN_WRAP_THEN" value="true" />
|
|
||||||
<option name="CORTEGE_SPACE_BEFORE_L_PAREN" value="false" />
|
|
||||||
<option name="EXPR_CASE_WHEN_WRAP" value="false" />
|
|
||||||
<option name="EXPR_CASE_THEN_WRAP" value="true" />
|
|
||||||
<option name="PRIMARY_KEY_NAME_TEMPLATE" value="{table}_{columns}_pk" />
|
|
||||||
</H2CodeStyleSettings>
|
|
||||||
<HSQLCodeStyleSettings version="6">
|
|
||||||
<option name="USE_GENERAL_STYLE" value="false" />
|
|
||||||
<option name="TYPE_CASE" value="3" />
|
|
||||||
<option name="CUSTOM_TYPE_CASE" value="3" />
|
|
||||||
<option name="ALIAS_CASE" value="4" />
|
|
||||||
<option name="BUILT_IN_CASE" value="0" />
|
|
||||||
<option name="QUERY_TRUE_INDENT" value="false" />
|
|
||||||
<option name="QUERY_ALIGN_ELEMENTS" value="false" />
|
|
||||||
<option name="QUERY_ALIGN_LINE_COMMENTS" value="false" />
|
|
||||||
<option name="INSERT_EL_COMMA" value="2" />
|
|
||||||
<option name="SET_EL_WRAP" value="0" />
|
|
||||||
<option name="SET_EL_COMMA" value="0" />
|
|
||||||
<option name="WITH_EL_WRAP" value="0" />
|
|
||||||
<option name="WITH_EL_COMMA" value="0" />
|
|
||||||
<option name="SELECT_EL_WRAP" value="3" />
|
|
||||||
<option name="SELECT_EL_COMMA" value="2" />
|
|
||||||
<option name="FROM_EL_WRAP" value="2" />
|
|
||||||
<option name="FROM_EL_COMMA" value="2" />
|
|
||||||
<option name="FROM_PLACE_ON" value="10" />
|
|
||||||
<option name="WHERE_EL_WRAP" value="3" />
|
|
||||||
<option name="WHERE_EL_BOUND" value="2" />
|
|
||||||
<option name="ORDER_EL_COMMA" value="2" />
|
|
||||||
<option name="TABLE_OPENING" value="1" />
|
|
||||||
<option name="TABLE_CONTENT" value="2" />
|
|
||||||
<option name="TABLE_CLOSING" value="3" />
|
|
||||||
<option name="TABLE_ALTER_INSTRUCTION_ALIGN" value="false" />
|
|
||||||
<option name="POST_OPT_WRAP_1" value="true" />
|
|
||||||
<option name="POST_OPT_ALIGN" value="false" />
|
|
||||||
<option name="ROUTINE_ARG_COMMA" value="2" />
|
|
||||||
<option name="ROUTINE_ARG_ALIGN_TYPES" value="true" />
|
|
||||||
<option name="IMP_DECLARE_EL_WRAP" value="1" />
|
|
||||||
<option name="IMP_IF_THEN_WRAP_THEN" value="true" />
|
|
||||||
<option name="CORTEGE_SPACE_BEFORE_L_PAREN" value="false" />
|
|
||||||
<option name="EXPR_CASE_WHEN_WRAP" value="false" />
|
|
||||||
<option name="EXPR_CASE_THEN_WRAP" value="true" />
|
|
||||||
<option name="PRIMARY_KEY_NAME_TEMPLATE" value="{table}_{columns}_pk" />
|
|
||||||
</HSQLCodeStyleSettings>
|
|
||||||
<HTMLCodeStyleSettings>
|
|
||||||
<option name="HTML_ATTRIBUTE_WRAP" value="0" />
|
|
||||||
<option name="HTML_TEXT_WRAP" value="0" />
|
|
||||||
<option name="HTML_ENFORCE_QUOTES" value="true" />
|
|
||||||
</HTMLCodeStyleSettings>
|
|
||||||
<JSCodeStyleSettings version="0">
|
|
||||||
<option name="FORCE_SEMICOLON_STYLE" value="true" />
|
|
||||||
<option name="ALIGN_OBJECT_PROPERTIES" value="2" />
|
|
||||||
<option name="ALIGN_VAR_STATEMENTS" value="1" />
|
|
||||||
<option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
|
|
||||||
<option name="SPACE_BEFORE_CLASS_LBRACE" value="false" />
|
|
||||||
<option name="USE_DOUBLE_QUOTES" value="false" />
|
|
||||||
<option name="FORCE_QUOTE_STYlE" value="true" />
|
|
||||||
<option name="ENFORCE_TRAILING_COMMA" value="WhenMultiline" />
|
|
||||||
<option name="IMPORTS_WRAP" value="1" />
|
|
||||||
<option name="SPACE_BEFORE_ASYNC_ARROW_LPAREN" value="false" />
|
|
||||||
</JSCodeStyleSettings>
|
|
||||||
<MSSQLCodeStyleSettings version="6">
|
|
||||||
<option name="USE_GENERAL_STYLE" value="false" />
|
|
||||||
<option name="TYPE_CASE" value="3" />
|
|
||||||
<option name="CUSTOM_TYPE_CASE" value="3" />
|
|
||||||
<option name="ALIAS_CASE" value="4" />
|
|
||||||
<option name="BUILT_IN_CASE" value="0" />
|
|
||||||
<option name="QUERY_TRUE_INDENT" value="false" />
|
|
||||||
<option name="QUERY_ALIGN_ELEMENTS" value="false" />
|
|
||||||
<option name="QUERY_ALIGN_LINE_COMMENTS" value="false" />
|
|
||||||
<option name="INSERT_EL_COMMA" value="2" />
|
|
||||||
<option name="SET_EL_WRAP" value="0" />
|
|
||||||
<option name="SET_EL_COMMA" value="0" />
|
|
||||||
<option name="WITH_EL_WRAP" value="0" />
|
|
||||||
<option name="WITH_EL_COMMA" value="0" />
|
|
||||||
<option name="SELECT_EL_WRAP" value="3" />
|
|
||||||
<option name="SELECT_EL_COMMA" value="2" />
|
|
||||||
<option name="FROM_EL_WRAP" value="2" />
|
|
||||||
<option name="FROM_EL_COMMA" value="2" />
|
|
||||||
<option name="FROM_PLACE_ON" value="10" />
|
|
||||||
<option name="WHERE_EL_WRAP" value="3" />
|
|
||||||
<option name="WHERE_EL_BOUND" value="2" />
|
|
||||||
<option name="ORDER_EL_COMMA" value="2" />
|
|
||||||
<option name="TABLE_OPENING" value="1" />
|
|
||||||
<option name="TABLE_CONTENT" value="2" />
|
|
||||||
<option name="TABLE_CLOSING" value="3" />
|
|
||||||
<option name="TABLE_ALTER_INSTRUCTION_ALIGN" value="false" />
|
|
||||||
<option name="POST_OPT_WRAP_1" value="true" />
|
|
||||||
<option name="POST_OPT_ALIGN" value="false" />
|
|
||||||
<option name="ROUTINE_ARG_COMMA" value="2" />
|
|
||||||
<option name="ROUTINE_ARG_ALIGN_TYPES" value="true" />
|
|
||||||
<option name="IMP_DECLARE_EL_WRAP" value="1" />
|
|
||||||
<option name="IMP_IF_THEN_WRAP_THEN" value="true" />
|
|
||||||
<option name="CORTEGE_SPACE_BEFORE_L_PAREN" value="false" />
|
|
||||||
<option name="EXPR_CASE_WHEN_WRAP" value="false" />
|
|
||||||
<option name="EXPR_CASE_THEN_WRAP" value="true" />
|
|
||||||
<option name="PRIMARY_KEY_NAME_TEMPLATE" value="{table}_{columns}_pk" />
|
|
||||||
</MSSQLCodeStyleSettings>
|
|
||||||
<MySQLCodeStyleSettings version="6">
|
|
||||||
<option name="USE_GENERAL_STYLE" value="false" />
|
|
||||||
<option name="TYPE_CASE" value="3" />
|
|
||||||
<option name="CUSTOM_TYPE_CASE" value="3" />
|
|
||||||
<option name="ALIAS_CASE" value="4" />
|
|
||||||
<option name="BUILT_IN_CASE" value="0" />
|
|
||||||
<option name="QUERY_TRUE_INDENT" value="false" />
|
|
||||||
<option name="QUERY_ALIGN_ELEMENTS" value="false" />
|
|
||||||
<option name="QUERY_ALIGN_LINE_COMMENTS" value="false" />
|
|
||||||
<option name="INSERT_EL_COMMA" value="2" />
|
|
||||||
<option name="SET_EL_WRAP" value="0" />
|
|
||||||
<option name="SET_EL_COMMA" value="0" />
|
|
||||||
<option name="WITH_EL_WRAP" value="0" />
|
|
||||||
<option name="WITH_EL_COMMA" value="0" />
|
|
||||||
<option name="SELECT_EL_WRAP" value="3" />
|
|
||||||
<option name="SELECT_EL_COMMA" value="2" />
|
|
||||||
<option name="FROM_EL_WRAP" value="2" />
|
|
||||||
<option name="FROM_EL_COMMA" value="2" />
|
|
||||||
<option name="FROM_PLACE_ON" value="10" />
|
|
||||||
<option name="WHERE_EL_WRAP" value="3" />
|
|
||||||
<option name="WHERE_EL_BOUND" value="2" />
|
|
||||||
<option name="ORDER_EL_COMMA" value="2" />
|
|
||||||
<option name="TABLE_OPENING" value="1" />
|
|
||||||
<option name="TABLE_CONTENT" value="2" />
|
|
||||||
<option name="TABLE_CLOSING" value="3" />
|
|
||||||
<option name="TABLE_ALTER_INSTRUCTION_ALIGN" value="false" />
|
|
||||||
<option name="POST_OPT_WRAP_1" value="true" />
|
|
||||||
<option name="POST_OPT_ALIGN" value="false" />
|
|
||||||
<option name="ROUTINE_ARG_COMMA" value="2" />
|
|
||||||
<option name="ROUTINE_ARG_ALIGN_TYPES" value="true" />
|
|
||||||
<option name="IMP_DECLARE_EL_WRAP" value="1" />
|
|
||||||
<option name="IMP_IF_THEN_WRAP_THEN" value="true" />
|
|
||||||
<option name="CORTEGE_SPACE_BEFORE_L_PAREN" value="false" />
|
|
||||||
<option name="EXPR_CASE_WHEN_WRAP" value="false" />
|
|
||||||
<option name="EXPR_CASE_THEN_WRAP" value="true" />
|
|
||||||
<option name="PRIMARY_KEY_NAME_TEMPLATE" value="{table}_{columns}_pk" />
|
|
||||||
</MySQLCodeStyleSettings>
|
|
||||||
<OracleCodeStyleSettings version="6">
|
|
||||||
<option name="USE_GENERAL_STYLE" value="false" />
|
|
||||||
<option name="TYPE_CASE" value="3" />
|
|
||||||
<option name="CUSTOM_TYPE_CASE" value="3" />
|
|
||||||
<option name="ALIAS_CASE" value="4" />
|
|
||||||
<option name="BUILT_IN_CASE" value="0" />
|
|
||||||
<option name="QUERY_TRUE_INDENT" value="false" />
|
|
||||||
<option name="QUERY_ALIGN_ELEMENTS" value="false" />
|
|
||||||
<option name="QUERY_ALIGN_LINE_COMMENTS" value="false" />
|
|
||||||
<option name="INSERT_EL_COMMA" value="2" />
|
|
||||||
<option name="SET_EL_WRAP" value="0" />
|
|
||||||
<option name="SET_EL_COMMA" value="0" />
|
|
||||||
<option name="WITH_EL_WRAP" value="0" />
|
|
||||||
<option name="WITH_EL_COMMA" value="0" />
|
|
||||||
<option name="SELECT_EL_WRAP" value="3" />
|
|
||||||
<option name="SELECT_EL_COMMA" value="2" />
|
|
||||||
<option name="FROM_EL_WRAP" value="2" />
|
|
||||||
<option name="FROM_EL_COMMA" value="2" />
|
|
||||||
<option name="FROM_PLACE_ON" value="10" />
|
|
||||||
<option name="WHERE_EL_WRAP" value="3" />
|
|
||||||
<option name="WHERE_EL_BOUND" value="2" />
|
|
||||||
<option name="ORDER_EL_COMMA" value="2" />
|
|
||||||
<option name="TABLE_OPENING" value="1" />
|
|
||||||
<option name="TABLE_CONTENT" value="2" />
|
|
||||||
<option name="TABLE_CLOSING" value="3" />
|
|
||||||
<option name="TABLE_ALTER_INSTRUCTION_ALIGN" value="false" />
|
|
||||||
<option name="POST_OPT_WRAP_1" value="true" />
|
|
||||||
<option name="POST_OPT_ALIGN" value="false" />
|
|
||||||
<option name="ROUTINE_ARG_COMMA" value="2" />
|
|
||||||
<option name="ROUTINE_ARG_ALIGN_TYPES" value="true" />
|
|
||||||
<option name="IMP_DECLARE_EL_WRAP" value="1" />
|
|
||||||
<option name="IMP_IF_THEN_WRAP_THEN" value="true" />
|
|
||||||
<option name="CORTEGE_SPACE_BEFORE_L_PAREN" value="false" />
|
|
||||||
<option name="EXPR_CASE_WHEN_WRAP" value="false" />
|
|
||||||
<option name="EXPR_CASE_THEN_WRAP" value="true" />
|
|
||||||
<option name="PRIMARY_KEY_NAME_TEMPLATE" value="{table}_{columns}_pk" />
|
|
||||||
</OracleCodeStyleSettings>
|
|
||||||
<PHPCodeStyleSettings>
|
|
||||||
<option name="ALIGN_KEY_VALUE_PAIRS" value="true" />
|
|
||||||
<option name="ALIGN_PHPDOC_PARAM_NAMES" value="true" />
|
|
||||||
<option name="ALIGN_PHPDOC_COMMENTS" value="true" />
|
|
||||||
<option name="ALIGN_ASSIGNMENTS" value="true" />
|
|
||||||
<option name="CONCAT_SPACES" value="false" />
|
|
||||||
<option name="COMMA_AFTER_LAST_ARRAY_ELEMENT" value="true" />
|
|
||||||
<option name="PHPDOC_BLANK_LINE_BEFORE_TAGS" value="true" />
|
|
||||||
<option name="PHPDOC_BLANK_LINES_AROUND_PARAMETERS" value="true" />
|
|
||||||
<option name="PHPDOC_WRAP_LONG_LINES" value="true" />
|
|
||||||
<option name="LOWER_CASE_BOOLEAN_CONST" value="true" />
|
|
||||||
<option name="LOWER_CASE_NULL_CONST" value="true" />
|
|
||||||
<option name="ELSE_IF_STYLE" value="COMBINE" />
|
|
||||||
<option name="FIELDS_DEFAULT_VISIBILITY" value="protected" />
|
|
||||||
<option name="BLANK_LINES_BEFORE_RETURN_STATEMENT" value="1" />
|
|
||||||
<option name="KEEP_RPAREN_AND_LBRACE_ON_ONE_LINE" value="true" />
|
|
||||||
<option name="ALIGN_CLASS_CONSTANTS" value="true" />
|
|
||||||
<option name="KEEP_BLANK_LINES_AFTER_LBRACE" value="1" />
|
|
||||||
<option name="SPACE_BEFORE_CLOSURE_LEFT_PARENTHESIS" value="false" />
|
|
||||||
<option name="FORCE_SHORT_DECLARATION_ARRAY_STYLE" value="true" />
|
|
||||||
<option name="SPACE_AROUND_ASSIGNMENT_IN_DECLARE" value="true" />
|
|
||||||
<option name="SPACE_AFTER_COLON_IN_RETURN_TYPE" value="false" />
|
|
||||||
<option name="PHPDOC_USE_FQCN" value="true" />
|
|
||||||
<option name="MULTILINE_CHAINED_CALLS_SEMICOLON_ON_NEW_LINE" value="true" />
|
|
||||||
<option name="PREFER_TEMPLATE_INDENTS" value="true" />
|
|
||||||
</PHPCodeStyleSettings>
|
|
||||||
<PostgresCodeStyleSettings version="6">
|
|
||||||
<option name="USE_GENERAL_STYLE" value="false" />
|
|
||||||
<option name="TYPE_CASE" value="3" />
|
|
||||||
<option name="CUSTOM_TYPE_CASE" value="3" />
|
|
||||||
<option name="ALIAS_CASE" value="4" />
|
|
||||||
<option name="BUILT_IN_CASE" value="0" />
|
|
||||||
<option name="QUERY_TRUE_INDENT" value="false" />
|
|
||||||
<option name="QUERY_ALIGN_ELEMENTS" value="false" />
|
|
||||||
<option name="QUERY_ALIGN_LINE_COMMENTS" value="false" />
|
|
||||||
<option name="INSERT_EL_COMMA" value="2" />
|
|
||||||
<option name="SET_EL_WRAP" value="0" />
|
|
||||||
<option name="SET_EL_COMMA" value="0" />
|
|
||||||
<option name="WITH_EL_WRAP" value="0" />
|
|
||||||
<option name="WITH_EL_COMMA" value="0" />
|
|
||||||
<option name="SELECT_EL_WRAP" value="3" />
|
|
||||||
<option name="SELECT_EL_COMMA" value="2" />
|
|
||||||
<option name="FROM_EL_WRAP" value="2" />
|
|
||||||
<option name="FROM_EL_COMMA" value="2" />
|
|
||||||
<option name="FROM_PLACE_ON" value="10" />
|
|
||||||
<option name="WHERE_EL_WRAP" value="3" />
|
|
||||||
<option name="WHERE_EL_BOUND" value="2" />
|
|
||||||
<option name="ORDER_EL_COMMA" value="2" />
|
|
||||||
<option name="TABLE_OPENING" value="1" />
|
|
||||||
<option name="TABLE_CONTENT" value="2" />
|
|
||||||
<option name="TABLE_CLOSING" value="3" />
|
|
||||||
<option name="TABLE_ALTER_INSTRUCTION_ALIGN" value="false" />
|
|
||||||
<option name="POST_OPT_WRAP_1" value="true" />
|
|
||||||
<option name="POST_OPT_ALIGN" value="false" />
|
|
||||||
<option name="ROUTINE_ARG_COMMA" value="2" />
|
|
||||||
<option name="ROUTINE_ARG_ALIGN_TYPES" value="true" />
|
|
||||||
<option name="IMP_DECLARE_EL_WRAP" value="1" />
|
|
||||||
<option name="IMP_IF_THEN_WRAP_THEN" value="true" />
|
|
||||||
<option name="CORTEGE_SPACE_BEFORE_L_PAREN" value="false" />
|
|
||||||
<option name="EXPR_CASE_WHEN_WRAP" value="false" />
|
|
||||||
<option name="EXPR_CASE_THEN_WRAP" value="true" />
|
|
||||||
<option name="PRIMARY_KEY_NAME_TEMPLATE" value="{table}_{columns}_pk" />
|
|
||||||
</PostgresCodeStyleSettings>
|
|
||||||
<SQLiteCodeStyleSettings version="6">
|
|
||||||
<option name="USE_GENERAL_STYLE" value="false" />
|
|
||||||
<option name="TYPE_CASE" value="3" />
|
|
||||||
<option name="CUSTOM_TYPE_CASE" value="3" />
|
|
||||||
<option name="ALIAS_CASE" value="4" />
|
|
||||||
<option name="BUILT_IN_CASE" value="0" />
|
|
||||||
<option name="QUERY_TRUE_INDENT" value="false" />
|
|
||||||
<option name="QUERY_ALIGN_ELEMENTS" value="false" />
|
|
||||||
<option name="QUERY_ALIGN_LINE_COMMENTS" value="false" />
|
|
||||||
<option name="INSERT_EL_COMMA" value="2" />
|
|
||||||
<option name="SET_EL_WRAP" value="0" />
|
|
||||||
<option name="SET_EL_COMMA" value="0" />
|
|
||||||
<option name="WITH_EL_WRAP" value="0" />
|
|
||||||
<option name="WITH_EL_COMMA" value="0" />
|
|
||||||
<option name="SELECT_EL_WRAP" value="3" />
|
|
||||||
<option name="SELECT_EL_COMMA" value="2" />
|
|
||||||
<option name="FROM_EL_WRAP" value="2" />
|
|
||||||
<option name="FROM_EL_COMMA" value="2" />
|
|
||||||
<option name="FROM_PLACE_ON" value="10" />
|
|
||||||
<option name="WHERE_EL_WRAP" value="3" />
|
|
||||||
<option name="WHERE_EL_BOUND" value="2" />
|
|
||||||
<option name="ORDER_EL_COMMA" value="2" />
|
|
||||||
<option name="TABLE_OPENING" value="1" />
|
|
||||||
<option name="TABLE_CONTENT" value="2" />
|
|
||||||
<option name="TABLE_CLOSING" value="3" />
|
|
||||||
<option name="TABLE_ALTER_INSTRUCTION_ALIGN" value="false" />
|
|
||||||
<option name="POST_OPT_WRAP_1" value="true" />
|
|
||||||
<option name="POST_OPT_ALIGN" value="false" />
|
|
||||||
<option name="ROUTINE_ARG_COMMA" value="2" />
|
|
||||||
<option name="ROUTINE_ARG_ALIGN_TYPES" value="true" />
|
|
||||||
<option name="IMP_DECLARE_EL_WRAP" value="1" />
|
|
||||||
<option name="IMP_IF_THEN_WRAP_THEN" value="true" />
|
|
||||||
<option name="CORTEGE_SPACE_BEFORE_L_PAREN" value="false" />
|
|
||||||
<option name="EXPR_CASE_WHEN_WRAP" value="false" />
|
|
||||||
<option name="EXPR_CASE_THEN_WRAP" value="true" />
|
|
||||||
<option name="PRIMARY_KEY_NAME_TEMPLATE" value="{table}_{columns}_pk" />
|
|
||||||
</SQLiteCodeStyleSettings>
|
|
||||||
<SqlCodeStyleSettings version="6">
|
|
||||||
<option name="TYPE_CASE" value="3" />
|
|
||||||
<option name="CUSTOM_TYPE_CASE" value="3" />
|
|
||||||
<option name="ALIAS_CASE" value="4" />
|
|
||||||
<option name="BUILT_IN_CASE" value="0" />
|
|
||||||
<option name="QUERY_TRUE_INDENT" value="false" />
|
|
||||||
<option name="QUERY_ALIGN_ELEMENTS" value="false" />
|
|
||||||
<option name="QUERY_ALIGN_LINE_COMMENTS" value="false" />
|
|
||||||
<option name="INSERT_EL_COMMA" value="2" />
|
|
||||||
<option name="SET_EL_WRAP" value="0" />
|
|
||||||
<option name="SET_EL_COMMA" value="0" />
|
|
||||||
<option name="WITH_EL_WRAP" value="0" />
|
|
||||||
<option name="WITH_EL_COMMA" value="0" />
|
|
||||||
<option name="SELECT_EL_WRAP" value="3" />
|
|
||||||
<option name="SELECT_EL_COMMA" value="2" />
|
|
||||||
<option name="SELECT_ALIGN_AS" value="false" />
|
|
||||||
<option name="FROM_EL_WRAP" value="2" />
|
|
||||||
<option name="FROM_EL_COMMA" value="2" />
|
|
||||||
<option name="FROM_PLACE_ON" value="10" />
|
|
||||||
<option name="WHERE_EL_WRAP" value="3" />
|
|
||||||
<option name="WHERE_EL_BOUND" value="2" />
|
|
||||||
<option name="ORDER_EL_COMMA" value="2" />
|
|
||||||
<option name="TABLE_OPENING" value="1" />
|
|
||||||
<option name="TABLE_CONTENT" value="2" />
|
|
||||||
<option name="TABLE_CLOSING" value="3" />
|
|
||||||
<option name="TABLE_ALTER_INSTRUCTION_ALIGN" value="false" />
|
|
||||||
<option name="POST_OPT_WRAP_1" value="true" />
|
|
||||||
<option name="POST_OPT_ALIGN" value="false" />
|
|
||||||
<option name="ROUTINE_ARG_COMMA" value="2" />
|
|
||||||
<option name="ROUTINE_ARG_ALIGN_TYPES" value="true" />
|
|
||||||
<option name="IMP_DECLARE_EL_WRAP" value="1" />
|
|
||||||
<option name="IMP_IF_THEN_INDENT_THEN_ELSE" value="true" />
|
|
||||||
<option name="IMP_IF_THEN_INDENT_END" value="true" />
|
|
||||||
<option name="CORTEGE_SPACE_BEFORE_L_PAREN" value="false" />
|
|
||||||
<option name="EXPR_CASE_WHEN_WRAP" value="false" />
|
|
||||||
<option name="PRIMARY_KEY_NAME_TEMPLATE" value="{table}_{columns}_pk" />
|
|
||||||
<option name="ALIGN_AS_IN_SELECT_STATEMENT" value="false" />
|
|
||||||
<option name="NEW_LINE_BEFORE_THEN" value="false" />
|
|
||||||
<option name="INDENT_SELECT_INTO_CLAUSE" value="true" />
|
|
||||||
</SqlCodeStyleSettings>
|
|
||||||
<SybaseCodeStyleSettings version="6">
|
|
||||||
<option name="USE_GENERAL_STYLE" value="false" />
|
|
||||||
<option name="TYPE_CASE" value="3" />
|
|
||||||
<option name="CUSTOM_TYPE_CASE" value="3" />
|
|
||||||
<option name="ALIAS_CASE" value="4" />
|
|
||||||
<option name="BUILT_IN_CASE" value="0" />
|
|
||||||
<option name="QUERY_TRUE_INDENT" value="false" />
|
|
||||||
<option name="QUERY_ALIGN_ELEMENTS" value="false" />
|
|
||||||
<option name="QUERY_ALIGN_LINE_COMMENTS" value="false" />
|
|
||||||
<option name="INSERT_EL_COMMA" value="2" />
|
|
||||||
<option name="SET_EL_WRAP" value="0" />
|
|
||||||
<option name="SET_EL_COMMA" value="0" />
|
|
||||||
<option name="WITH_EL_WRAP" value="0" />
|
|
||||||
<option name="WITH_EL_COMMA" value="0" />
|
|
||||||
<option name="SELECT_EL_WRAP" value="3" />
|
|
||||||
<option name="SELECT_EL_COMMA" value="2" />
|
|
||||||
<option name="FROM_EL_WRAP" value="2" />
|
|
||||||
<option name="FROM_EL_COMMA" value="2" />
|
|
||||||
<option name="FROM_PLACE_ON" value="10" />
|
|
||||||
<option name="WHERE_EL_WRAP" value="3" />
|
|
||||||
<option name="WHERE_EL_BOUND" value="2" />
|
|
||||||
<option name="ORDER_EL_COMMA" value="2" />
|
|
||||||
<option name="TABLE_OPENING" value="1" />
|
|
||||||
<option name="TABLE_CONTENT" value="2" />
|
|
||||||
<option name="TABLE_CLOSING" value="3" />
|
|
||||||
<option name="TABLE_ALTER_INSTRUCTION_ALIGN" value="false" />
|
|
||||||
<option name="POST_OPT_WRAP_1" value="true" />
|
|
||||||
<option name="POST_OPT_ALIGN" value="false" />
|
|
||||||
<option name="ROUTINE_ARG_COMMA" value="2" />
|
|
||||||
<option name="ROUTINE_ARG_ALIGN_TYPES" value="true" />
|
|
||||||
<option name="IMP_DECLARE_EL_WRAP" value="1" />
|
|
||||||
<option name="IMP_IF_THEN_WRAP_THEN" value="true" />
|
|
||||||
<option name="CORTEGE_SPACE_BEFORE_L_PAREN" value="false" />
|
|
||||||
<option name="EXPR_CASE_WHEN_WRAP" value="false" />
|
|
||||||
<option name="EXPR_CASE_THEN_WRAP" value="true" />
|
|
||||||
<option name="PRIMARY_KEY_NAME_TEMPLATE" value="{table}_{columns}_pk" />
|
|
||||||
</SybaseCodeStyleSettings>
|
|
||||||
<XML>
|
|
||||||
<option name="XML_ATTRIBUTE_WRAP" value="0" />
|
|
||||||
<option name="XML_TEXT_WRAP" value="0" />
|
|
||||||
<option name="XML_KEEP_WHITE_SPACES_INSIDE_CDATA" value="true" />
|
|
||||||
</XML>
|
|
||||||
<codeStyleSettings language="DB2">
|
|
||||||
<indentOptions>
|
|
||||||
<option name="USE_TAB_CHARACTER" value="true" />
|
|
||||||
<option name="SMART_TABS" value="true" />
|
|
||||||
<option name="KEEP_INDENTS_ON_EMPTY_LINES" value="true" />
|
|
||||||
</indentOptions>
|
|
||||||
</codeStyleSettings>
|
|
||||||
<codeStyleSettings language="Derby">
|
|
||||||
<indentOptions>
|
|
||||||
<option name="USE_TAB_CHARACTER" value="true" />
|
|
||||||
<option name="SMART_TABS" value="true" />
|
|
||||||
<option name="KEEP_INDENTS_ON_EMPTY_LINES" value="true" />
|
|
||||||
</indentOptions>
|
|
||||||
</codeStyleSettings>
|
|
||||||
<codeStyleSettings language="H2">
|
|
||||||
<indentOptions>
|
|
||||||
<option name="USE_TAB_CHARACTER" value="true" />
|
|
||||||
<option name="SMART_TABS" value="true" />
|
|
||||||
<option name="KEEP_INDENTS_ON_EMPTY_LINES" value="true" />
|
|
||||||
</indentOptions>
|
|
||||||
</codeStyleSettings>
|
|
||||||
<codeStyleSettings language="HSQLDB">
|
|
||||||
<indentOptions>
|
|
||||||
<option name="USE_TAB_CHARACTER" value="true" />
|
|
||||||
<option name="SMART_TABS" value="true" />
|
|
||||||
<option name="KEEP_INDENTS_ON_EMPTY_LINES" value="true" />
|
|
||||||
</indentOptions>
|
|
||||||
</codeStyleSettings>
|
|
||||||
<codeStyleSettings language="HTML">
|
|
||||||
<option name="SOFT_MARGINS" value="130" />
|
|
||||||
<indentOptions>
|
|
||||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
|
||||||
<option name="USE_TAB_CHARACTER" value="true" />
|
|
||||||
<option name="SMART_TABS" value="true" />
|
|
||||||
</indentOptions>
|
|
||||||
</codeStyleSettings>
|
|
||||||
<codeStyleSettings language="JSON">
|
|
||||||
<indentOptions>
|
|
||||||
<option name="INDENT_SIZE" value="4" />
|
|
||||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
|
||||||
<option name="USE_TAB_CHARACTER" value="true" />
|
|
||||||
<option name="SMART_TABS" value="true" />
|
|
||||||
</indentOptions>
|
|
||||||
</codeStyleSettings>
|
|
||||||
<codeStyleSettings language="JavaScript">
|
|
||||||
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
|
|
||||||
<option name="ELSE_ON_NEW_LINE" value="true" />
|
|
||||||
<option name="WHILE_ON_NEW_LINE" value="true" />
|
|
||||||
<option name="CATCH_ON_NEW_LINE" value="true" />
|
|
||||||
<option name="FINALLY_ON_NEW_LINE" value="true" />
|
|
||||||
<option name="ALIGN_MULTILINE_CHAINED_METHODS" value="true" />
|
|
||||||
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
|
|
||||||
<option name="ALIGN_MULTILINE_BINARY_OPERATION" value="true" />
|
|
||||||
<option name="ALIGN_MULTILINE_TERNARY_OPERATION" value="true" />
|
|
||||||
<option name="ALIGN_MULTILINE_ARRAY_INITIALIZER_EXPRESSION" value="true" />
|
|
||||||
<option name="SPACE_BEFORE_IF_PARENTHESES" value="false" />
|
|
||||||
<option name="SPACE_BEFORE_WHILE_PARENTHESES" value="false" />
|
|
||||||
<option name="SPACE_BEFORE_FOR_PARENTHESES" value="false" />
|
|
||||||
<option name="SPACE_BEFORE_CATCH_PARENTHESES" value="false" />
|
|
||||||
<option name="SPACE_BEFORE_SWITCH_PARENTHESES" value="false" />
|
|
||||||
<option name="SPACE_BEFORE_METHOD_LBRACE" value="false" />
|
|
||||||
<option name="SPACE_BEFORE_IF_LBRACE" value="false" />
|
|
||||||
<option name="SPACE_BEFORE_ELSE_LBRACE" value="false" />
|
|
||||||
<option name="SPACE_BEFORE_WHILE_LBRACE" value="false" />
|
|
||||||
<option name="SPACE_BEFORE_FOR_LBRACE" value="false" />
|
|
||||||
<option name="SPACE_BEFORE_DO_LBRACE" value="false" />
|
|
||||||
<option name="SPACE_BEFORE_SWITCH_LBRACE" value="false" />
|
|
||||||
<option name="SPACE_BEFORE_TRY_LBRACE" value="false" />
|
|
||||||
<option name="SPACE_BEFORE_CATCH_LBRACE" value="false" />
|
|
||||||
<option name="SPACE_BEFORE_FINALLY_LBRACE" value="false" />
|
|
||||||
<option name="SPACE_BEFORE_ELSE_KEYWORD" value="false" />
|
|
||||||
<option name="SPACE_BEFORE_WHILE_KEYWORD" value="false" />
|
|
||||||
<option name="SPACE_BEFORE_CATCH_KEYWORD" value="false" />
|
|
||||||
<option name="SPACE_BEFORE_FINALLY_KEYWORD" value="false" />
|
|
||||||
<option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" />
|
|
||||||
<option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" />
|
|
||||||
<option name="ARRAY_INITIALIZER_WRAP" value="1" />
|
|
||||||
<option name="ARRAY_INITIALIZER_LBRACE_ON_NEXT_LINE" value="true" />
|
|
||||||
<option name="ARRAY_INITIALIZER_RBRACE_ON_NEXT_LINE" value="true" />
|
|
||||||
<option name="PLACE_ASSIGNMENT_SIGN_ON_NEXT_LINE" value="true" />
|
|
||||||
<option name="IF_BRACE_FORCE" value="3" />
|
|
||||||
<option name="DOWHILE_BRACE_FORCE" value="3" />
|
|
||||||
<option name="WHILE_BRACE_FORCE" value="3" />
|
|
||||||
<option name="FOR_BRACE_FORCE" value="3" />
|
|
||||||
<indentOptions>
|
|
||||||
<option name="USE_TAB_CHARACTER" value="true" />
|
|
||||||
<option name="SMART_TABS" value="true" />
|
|
||||||
</indentOptions>
|
|
||||||
</codeStyleSettings>
|
|
||||||
<codeStyleSettings language="Markdown">
|
|
||||||
<indentOptions>
|
|
||||||
<option name="USE_TAB_CHARACTER" value="true" />
|
|
||||||
<option name="SMART_TABS" value="true" />
|
|
||||||
</indentOptions>
|
|
||||||
</codeStyleSettings>
|
|
||||||
<codeStyleSettings language="MySQL">
|
|
||||||
<indentOptions>
|
|
||||||
<option name="USE_TAB_CHARACTER" value="true" />
|
|
||||||
<option name="SMART_TABS" value="true" />
|
|
||||||
<option name="KEEP_INDENTS_ON_EMPTY_LINES" value="true" />
|
|
||||||
</indentOptions>
|
|
||||||
</codeStyleSettings>
|
|
||||||
<codeStyleSettings language="Oracle">
|
|
||||||
<indentOptions>
|
|
||||||
<option name="USE_TAB_CHARACTER" value="true" />
|
|
||||||
<option name="SMART_TABS" value="true" />
|
|
||||||
<option name="KEEP_INDENTS_ON_EMPTY_LINES" value="true" />
|
|
||||||
</indentOptions>
|
|
||||||
</codeStyleSettings>
|
|
||||||
<codeStyleSettings language="PHP">
|
|
||||||
<option name="KEEP_BLANK_LINES_IN_DECLARATIONS" value="1" />
|
|
||||||
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
|
|
||||||
<option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="1" />
|
|
||||||
<option name="BLANK_LINES_AFTER_PACKAGE" value="1" />
|
|
||||||
<option name="BLANK_LINES_BEFORE_IMPORTS" value="0" />
|
|
||||||
<option name="BLANK_LINES_AFTER_CLASS_HEADER" value="1" />
|
|
||||||
<option name="BLANK_LINES_BEFORE_CLASS_END" value="1" />
|
|
||||||
<option name="CLASS_BRACE_STYLE" value="1" />
|
|
||||||
<option name="METHOD_BRACE_STYLE" value="1" />
|
|
||||||
<option name="ELSE_ON_NEW_LINE" value="true" />
|
|
||||||
<option name="WHILE_ON_NEW_LINE" value="true" />
|
|
||||||
<option name="CATCH_ON_NEW_LINE" value="true" />
|
|
||||||
<option name="FINALLY_ON_NEW_LINE" value="true" />
|
|
||||||
<option name="SPECIAL_ELSE_IF_TREATMENT" value="true" />
|
|
||||||
<option name="ALIGN_MULTILINE_CHAINED_METHODS" value="true" />
|
|
||||||
<option name="ALIGN_MULTILINE_PARAMETERS_IN_CALLS" value="true" />
|
|
||||||
<option name="ALIGN_MULTILINE_BINARY_OPERATION" value="true" />
|
|
||||||
<option name="ALIGN_MULTILINE_TERNARY_OPERATION" value="true" />
|
|
||||||
<option name="ALIGN_MULTILINE_EXTENDS_LIST" value="true" />
|
|
||||||
<option name="ALIGN_MULTILINE_ARRAY_INITIALIZER_EXPRESSION" value="true" />
|
|
||||||
<option name="ALIGN_GROUP_FIELD_DECLARATIONS" value="true" />
|
|
||||||
<option name="SPACE_BEFORE_IF_PARENTHESES" value="false" />
|
|
||||||
<option name="SPACE_BEFORE_WHILE_PARENTHESES" value="false" />
|
|
||||||
<option name="SPACE_BEFORE_FOR_PARENTHESES" value="false" />
|
|
||||||
<option name="SPACE_BEFORE_CATCH_PARENTHESES" value="false" />
|
|
||||||
<option name="SPACE_BEFORE_SWITCH_PARENTHESES" value="false" />
|
|
||||||
<option name="SPACE_BEFORE_CLASS_LBRACE" value="false" />
|
|
||||||
<option name="SPACE_BEFORE_METHOD_LBRACE" value="false" />
|
|
||||||
<option name="SPACE_BEFORE_IF_LBRACE" value="false" />
|
|
||||||
<option name="SPACE_BEFORE_ELSE_LBRACE" value="false" />
|
|
||||||
<option name="SPACE_BEFORE_WHILE_LBRACE" value="false" />
|
|
||||||
<option name="SPACE_BEFORE_FOR_LBRACE" value="false" />
|
|
||||||
<option name="SPACE_BEFORE_DO_LBRACE" value="false" />
|
|
||||||
<option name="SPACE_BEFORE_SWITCH_LBRACE" value="false" />
|
|
||||||
<option name="SPACE_BEFORE_TRY_LBRACE" value="false" />
|
|
||||||
<option name="SPACE_BEFORE_CATCH_LBRACE" value="false" />
|
|
||||||
<option name="SPACE_BEFORE_FINALLY_LBRACE" value="false" />
|
|
||||||
<option name="CALL_PARAMETERS_LPAREN_ON_NEXT_LINE" value="true" />
|
|
||||||
<option name="CALL_PARAMETERS_RPAREN_ON_NEXT_LINE" value="true" />
|
|
||||||
<option name="METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE" value="true" />
|
|
||||||
<option name="METHOD_PARAMETERS_RPAREN_ON_NEXT_LINE" value="true" />
|
|
||||||
<option name="PARENTHESES_EXPRESSION_LPAREN_WRAP" value="true" />
|
|
||||||
<option name="PARENTHESES_EXPRESSION_RPAREN_WRAP" value="true" />
|
|
||||||
<option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" />
|
|
||||||
<option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" />
|
|
||||||
<option name="FOR_STATEMENT_RPAREN_ON_NEXT_LINE" value="true" />
|
|
||||||
<option name="ARRAY_INITIALIZER_WRAP" value="1" />
|
|
||||||
<option name="ARRAY_INITIALIZER_LBRACE_ON_NEXT_LINE" value="true" />
|
|
||||||
<option name="ARRAY_INITIALIZER_RBRACE_ON_NEXT_LINE" value="true" />
|
|
||||||
<option name="PLACE_ASSIGNMENT_SIGN_ON_NEXT_LINE" value="true" />
|
|
||||||
<option name="IF_BRACE_FORCE" value="3" />
|
|
||||||
<option name="DOWHILE_BRACE_FORCE" value="3" />
|
|
||||||
<option name="WHILE_BRACE_FORCE" value="3" />
|
|
||||||
<option name="FOR_BRACE_FORCE" value="3" />
|
|
||||||
<indentOptions>
|
|
||||||
<option name="USE_TAB_CHARACTER" value="true" />
|
|
||||||
<option name="SMART_TABS" value="true" />
|
|
||||||
</indentOptions>
|
|
||||||
<arrangement>
|
|
||||||
<rules>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<CONST />
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<FIELD />
|
|
||||||
<PUBLIC />
|
|
||||||
<STATIC />
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<FIELD />
|
|
||||||
<PROTECTED />
|
|
||||||
<STATIC />
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<FIELD />
|
|
||||||
<PRIVATE />
|
|
||||||
<STATIC />
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<FIELD />
|
|
||||||
<PUBLIC />
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<FIELD />
|
|
||||||
<PROTECTED />
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<FIELD />
|
|
||||||
<PRIVATE />
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<CONSTRUCTOR />
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<METHOD />
|
|
||||||
<PUBLIC />
|
|
||||||
<STATIC />
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<METHOD />
|
|
||||||
<PROTECTED />
|
|
||||||
<STATIC />
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<METHOD />
|
|
||||||
<PRIVATE />
|
|
||||||
<STATIC />
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<METHOD />
|
|
||||||
<PUBLIC />
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<METHOD />
|
|
||||||
<PROTECTED />
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<METHOD />
|
|
||||||
<PRIVATE />
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<TRAIT />
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<INTERFACE />
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<CLASS />
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
</rules>
|
|
||||||
</arrangement>
|
|
||||||
</codeStyleSettings>
|
|
||||||
<codeStyleSettings language="PostgreSQL">
|
|
||||||
<indentOptions>
|
|
||||||
<option name="USE_TAB_CHARACTER" value="true" />
|
|
||||||
<option name="SMART_TABS" value="true" />
|
|
||||||
<option name="KEEP_INDENTS_ON_EMPTY_LINES" value="true" />
|
|
||||||
</indentOptions>
|
|
||||||
</codeStyleSettings>
|
|
||||||
<codeStyleSettings language="SQL">
|
|
||||||
<indentOptions>
|
|
||||||
<option name="USE_TAB_CHARACTER" value="true" />
|
|
||||||
<option name="SMART_TABS" value="true" />
|
|
||||||
<option name="KEEP_INDENTS_ON_EMPTY_LINES" value="true" />
|
|
||||||
</indentOptions>
|
|
||||||
</codeStyleSettings>
|
|
||||||
<codeStyleSettings language="SQLite">
|
|
||||||
<indentOptions>
|
|
||||||
<option name="USE_TAB_CHARACTER" value="true" />
|
|
||||||
<option name="SMART_TABS" value="true" />
|
|
||||||
<option name="KEEP_INDENTS_ON_EMPTY_LINES" value="true" />
|
|
||||||
</indentOptions>
|
|
||||||
</codeStyleSettings>
|
|
||||||
<codeStyleSettings language="Sybase">
|
|
||||||
<indentOptions>
|
|
||||||
<option name="USE_TAB_CHARACTER" value="true" />
|
|
||||||
<option name="SMART_TABS" value="true" />
|
|
||||||
<option name="KEEP_INDENTS_ON_EMPTY_LINES" value="true" />
|
|
||||||
</indentOptions>
|
|
||||||
</codeStyleSettings>
|
|
||||||
<codeStyleSettings language="TSQL">
|
|
||||||
<indentOptions>
|
|
||||||
<option name="USE_TAB_CHARACTER" value="true" />
|
|
||||||
<option name="SMART_TABS" value="true" />
|
|
||||||
<option name="KEEP_INDENTS_ON_EMPTY_LINES" value="true" />
|
|
||||||
</indentOptions>
|
|
||||||
</codeStyleSettings>
|
|
||||||
<codeStyleSettings language="XML">
|
|
||||||
<indentOptions>
|
|
||||||
<option name="USE_TAB_CHARACTER" value="true" />
|
|
||||||
<option name="SMART_TABS" value="true" />
|
|
||||||
</indentOptions>
|
|
||||||
</codeStyleSettings>
|
|
||||||
</code_scheme>
|
|
||||||
</component>
|
|
||||||
5
vendor/chillerlan/php-qrcode/.idea/codeStyles/codeStyleConfig.xml
generated
vendored
5
vendor/chillerlan/php-qrcode/.idea/codeStyles/codeStyleConfig.xml
generated
vendored
@@ -1,5 +0,0 @@
|
|||||||
<component name="ProjectCodeStyleConfiguration">
|
|
||||||
<state>
|
|
||||||
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
|
||||||
</state>
|
|
||||||
</component>
|
|
||||||
27
vendor/chillerlan/php-qrcode/.idea/inspectionProfiles/Project_Default.xml
generated
vendored
27
vendor/chillerlan/php-qrcode/.idea/inspectionProfiles/Project_Default.xml
generated
vendored
@@ -1,27 +0,0 @@
|
|||||||
<component name="InspectionProjectProfileManager">
|
|
||||||
<profile version="1.0">
|
|
||||||
<option name="myName" value="Project Default" />
|
|
||||||
<inspection_tool class="JSAccessibilityCheck" enabled="true" level="WARNING" enabled_by_default="true" editorAttributes="WARNING_ATTRIBUTES" />
|
|
||||||
<inspection_tool class="MessDetectorValidationInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
|
||||||
<inspection_tool class="PhpAssignmentInConditionInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
|
||||||
<inspection_tool class="PhpCSValidationInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
|
||||||
<inspection_tool class="PhpComposerExtensionStubsInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
|
||||||
<inspection_tool class="PhpDivisionByZeroInspection" enabled="true" level="WARNING" enabled_by_default="true" />
|
|
||||||
<inspection_tool class="PhpInternalEntityUsedInspection" enabled="true" level="INFO" enabled_by_default="true" />
|
|
||||||
<inspection_tool class="PhpMethodOrClassCallIsNotCaseSensitiveInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
|
||||||
<inspection_tool class="PhpMissingDocCommentInspection" enabled="true" level="INFO" enabled_by_default="true" />
|
|
||||||
<inspection_tool class="PhpMissingParentCallMagicInspection" enabled="false" level="WARNING" enabled_by_default="false">
|
|
||||||
<option name="ENABLE_FOR_SLEEP" value="false" />
|
|
||||||
<option name="ENABLE_FOR_WAKEUP" value="false" />
|
|
||||||
</inspection_tool>
|
|
||||||
<inspection_tool class="PhpMultipleClassesDeclarationsInOneFile" enabled="true" level="WARNING" enabled_by_default="true" />
|
|
||||||
<inspection_tool class="PhpStatementHasEmptyBodyInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
|
||||||
<inspection_tool class="PhpUsageOfSilenceOperatorInspection" enabled="true" level="STFU!" enabled_by_default="true" />
|
|
||||||
<inspection_tool class="PhpVoidFunctionResultUsedInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
|
||||||
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
|
|
||||||
<option name="processCode" value="true" />
|
|
||||||
<option name="processLiterals" value="true" />
|
|
||||||
<option name="processComments" value="true" />
|
|
||||||
</inspection_tool>
|
|
||||||
</profile>
|
|
||||||
</component>
|
|
||||||
41
vendor/chillerlan/php-qrcode/README.md
vendored
41
vendor/chillerlan/php-qrcode/README.md
vendored
@@ -13,24 +13,24 @@ It also features a QR Code reader based on a [PHP port](https://github.com/khana
|
|||||||
[![Packagist downloads][downloads-badge]][downloads]
|
[![Packagist downloads][downloads-badge]][downloads]
|
||||||
[![Documentation][readthedocs-badge]][readthedocs]
|
[![Documentation][readthedocs-badge]][readthedocs]
|
||||||
|
|
||||||
[php-badge]: https://img.shields.io/packagist/php-v/chillerlan/php-qrcode?logo=php&color=8892BF
|
[php-badge]: https://img.shields.io/packagist/php-v/chillerlan/php-qrcode?logo=php&color=8892BF&logoColor=fff
|
||||||
[php]: https://www.php.net/supported-versions.php
|
[php]: https://www.php.net/supported-versions.php
|
||||||
[packagist-badge]: https://img.shields.io/packagist/v/chillerlan/php-qrcode.svg?logo=packagist
|
[packagist-badge]: https://img.shields.io/packagist/v/chillerlan/php-qrcode.svg?logo=packagist&logoColor=fff
|
||||||
[packagist]: https://packagist.org/packages/chillerlan/php-qrcode
|
[packagist]: https://packagist.org/packages/chillerlan/php-qrcode
|
||||||
[gh-action-badge]: https://img.shields.io/github/actions/workflow/status/chillerlan/php-qrcode/ci.yml?branch=v5.0.x&logo=github
|
[gh-action-badge]: https://img.shields.io/github/actions/workflow/status/chillerlan/php-qrcode/ci.yml?branch=v5.0.x&logo=github&logoColor=fff
|
||||||
[gh-action]: https://github.com/chillerlan/php-qrcode/actions/workflows/ci.yml?query=branch%3Amain
|
[gh-action]: https://github.com/chillerlan/php-qrcode/actions/workflows/ci.yml?query=branch%3Amain
|
||||||
[coverage-badge]: https://img.shields.io/codecov/c/github/chillerlan/php-qrcode/v5.0.x?logo=codecov
|
[coverage-badge]: https://img.shields.io/codecov/c/github/chillerlan/php-qrcode/v5.0.x?logo=codecov&logoColor=fff
|
||||||
[coverage]: https://app.codecov.io/gh/chillerlan/php-qrcode/tree/v5.0.x
|
[coverage]: https://app.codecov.io/gh/chillerlan/php-qrcode/tree/v5.0.x
|
||||||
[codacy-badge]: https://img.shields.io/codacy/grade/edccfc4fe5a34b74b1c53ee03f097b8d/v5.0.x?logo=codacy
|
[codacy-badge]: https://img.shields.io/codacy/grade/edccfc4fe5a34b74b1c53ee03f097b8d/v5.0.x?logo=codacy&logoColor=fff
|
||||||
[codacy]: https://app.codacy.com/gh/chillerlan/php-qrcode/dashboard?branch=v5.0.x
|
[codacy]: https://app.codacy.com/gh/chillerlan/php-qrcode/dashboard?branch=v5.0.x
|
||||||
[downloads-badge]: https://img.shields.io/packagist/dt/chillerlan/php-qrcode?logo=packagist
|
[downloads-badge]: https://img.shields.io/packagist/dt/chillerlan/php-qrcode?logo=packagist&logoColor=fff
|
||||||
[downloads]: https://packagist.org/packages/chillerlan/php-qrcode/stats
|
[downloads]: https://packagist.org/packages/chillerlan/php-qrcode/stats
|
||||||
[readthedocs-badge]: https://img.shields.io/readthedocs/php-qrcode/v5.0.x?logo=readthedocs
|
[readthedocs-badge]: https://img.shields.io/readthedocs/php-qrcode/v5.0.x?logo=readthedocs&logoColor=fff
|
||||||
[readthedocs]: https://php-qrcode.readthedocs.io/en/v5.0.x/
|
[readthedocs]: https://php-qrcode.readthedocs.io/en/v5.0.x/
|
||||||
|
|
||||||
## Overview
|
# Overview
|
||||||
|
|
||||||
### Features
|
## Features
|
||||||
|
|
||||||
- Creation of [Model 2 QR Codes](https://www.qrcode.com/en/codes/model12.html), [Version 1 to 40](https://www.qrcode.com/en/about/version.html)
|
- Creation of [Model 2 QR Codes](https://www.qrcode.com/en/codes/model12.html), [Version 1 to 40](https://www.qrcode.com/en/about/version.html)
|
||||||
- [ECC Levels](https://www.qrcode.com/en/about/error_correction.html) L/M/Q/H supported
|
- [ECC Levels](https://www.qrcode.com/en/about/error_correction.html) L/M/Q/H supported
|
||||||
@@ -52,7 +52,7 @@ It also features a QR Code reader based on a [PHP port](https://github.com/khana
|
|||||||
- QR Code reader (via GD and ImageMagick)
|
- QR Code reader (via GD and ImageMagick)
|
||||||
|
|
||||||
|
|
||||||
### Requirements
|
## Requirements
|
||||||
|
|
||||||
- PHP 7.4+
|
- PHP 7.4+
|
||||||
- [`ext-mbstring`](https://www.php.net/manual/book.mbstring.php)
|
- [`ext-mbstring`](https://www.php.net/manual/book.mbstring.php)
|
||||||
@@ -65,16 +65,21 @@ It also features a QR Code reader based on a [PHP port](https://github.com/khana
|
|||||||
For the QRCode reader, either `ext-gd` or `ext-imagick` is required!
|
For the QRCode reader, either `ext-gd` or `ext-imagick` is required!
|
||||||
|
|
||||||
|
|
||||||
## Documentation
|
# Documentation
|
||||||
|
|
||||||
- The user manual is at https://php-qrcode.readthedocs.io/ ([sources](https://github.com/chillerlan/php-qrcode/tree/v5.0.x/docs))
|
- The user manual is at https://php-qrcode.readthedocs.io/ ([sources](https://github.com/chillerlan/php-qrcode/tree/v5.0.x/docs))
|
||||||
- An API documentation created with [phpDocumentor](https://www.phpdoc.org/) can be found at https://chillerlan.github.io/php-qrcode/
|
- An API documentation created with [phpDocumentor](https://www.phpdoc.org/) can be found at https://chillerlan.github.io/php-qrcode/
|
||||||
- The documentation for the `QROptions` container can be found here: [chillerlan/php-settings-container](https://github.com/chillerlan/php-settings-container#readme)
|
- The documentation for the `QROptions` container can be found here: [chillerlan/php-settings-container](https://github.com/chillerlan/php-settings-container#readme)
|
||||||
|
|
||||||
|
**Important: Please use the examples from the branch that matches your installed php-qrcode version (
|
||||||
|
[v4.x](https://github.com/chillerlan/php-qrcode/tree/v4.3.x/examples),
|
||||||
|
[v5.x](https://github.com/chillerlan/php-qrcode/tree/v5.0.x/examples),
|
||||||
|
[dev-main](https://github.com/chillerlan/php-qrcode/tree/main/examples)
|
||||||
|
)!**
|
||||||
|
|
||||||
## Installation with [composer](https://getcomposer.org)
|
## Installation with [composer](https://getcomposer.org)
|
||||||
|
|
||||||
See [the installation guide](https://php-qrcode.readthedocs.io/en/v5.0.x/Usage-Installation.html) for more info!
|
See [the installation guide](https://php-qrcode.readthedocs.io/en/v5.0.x/Usage/Installation.html) for more info!
|
||||||
|
|
||||||
|
|
||||||
### Terminal
|
### Terminal
|
||||||
@@ -117,7 +122,7 @@ Also, have a look [in the examples folder](https://github.com/chillerlan/php-qrc
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|
||||||
### Reading QR Codes
|
## Reading QR Codes
|
||||||
|
|
||||||
Using the built-in QR Code reader is pretty straight-forward:
|
Using the built-in QR Code reader is pretty straight-forward:
|
||||||
|
|
||||||
@@ -139,30 +144,30 @@ catch(Throwable $e){
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## Shameless advertising
|
# Shameless advertising
|
||||||
|
|
||||||
Hi, please check out some of my other projects that are way cooler than qrcodes!
|
Hi, please check out some of my other projects that are way cooler than qrcodes!
|
||||||
|
|
||||||
- [js-qrcode](https://github.com/chillerlan/js-qrcode) - a javascript port of this library
|
- [js-qrcode](https://github.com/chillerlan/js-qrcode) - a javascript port of this library
|
||||||
- [php-authenticator](https://github.com/chillerlan/php-authenticator) - a Google Authenticator implementation (see [authenticator example](https://github.com/chillerlan/php-qrcode/blob/v5.0.x/examples/authenticator.php))
|
- [php-authenticator](https://github.com/chillerlan/php-authenticator) - a Google Authenticator implementation (see [authenticator example](https://github.com/chillerlan/php-qrcode/blob/v5.0.x/examples/authenticator.php))
|
||||||
- [php-httpinterface](https://github.com/chillerlan/php-httpinterface) - a PSR-7/15/17/18 implemetation
|
- [php-httpinterface](https://github.com/chillerlan/php-httpinterface) - a PSR-7/15/17/18 implemetation
|
||||||
- [php-oauth-core](https://github.com/chillerlan/php-oauth-core) - an OAuth 1/2 client library along with a bunch of [providers](https://github.com/chillerlan/php-oauth-providers)
|
- [php-oauth](https://github.com/chillerlan/php-oauth) - an OAuth 1/2 client library, fully PSR-7/PSR-17/PSR-18 compatible
|
||||||
- [php-database](https://github.com/chillerlan/php-database) - a database client & querybuilder for MySQL, Postgres, SQLite, MSSQL, Firebird
|
- [php-database](https://github.com/chillerlan/php-database) - a database client & querybuilder for MySQL, Postgres, SQLite, MSSQL, Firebird
|
||||||
- [php-tootbot](https://github.com/php-tootbot/tootbot-template) - a Mastodon bot library (see [@dwil](https://github.com/php-tootbot/dwil))
|
- [php-tootbot](https://github.com/php-tootbot/tootbot-template) - a Mastodon bot library (see [@dwil](https://github.com/php-tootbot/dwil))
|
||||||
|
|
||||||
|
|
||||||
## Disclaimer!
|
# Disclaimer!
|
||||||
|
|
||||||
I don't take responsibility for molten CPUs, misled applications, failed log-ins etc.. Use at your own risk!
|
I don't take responsibility for molten CPUs, misled applications, failed log-ins etc.. Use at your own risk!
|
||||||
|
|
||||||
|
|
||||||
### License notice
|
## License notice
|
||||||
|
|
||||||
- Parts of this code are [ported to PHP](https://github.com/codemasher/php-qrcode-decoder) from the [ZXing project](https://github.com/zxing/zxing) and licensed under the [Apache License, Version 2.0](./NOTICE).
|
- Parts of this code are [ported to PHP](https://github.com/codemasher/php-qrcode-decoder) from the [ZXing project](https://github.com/zxing/zxing) and licensed under the [Apache License, Version 2.0](./NOTICE).
|
||||||
- [The documentation](https://github.com/chillerlan/php-qrcode/tree/v5.0.x/docs) is licensed under the [Creative Commons Attribution 4.0 International (CC BY 4.0) License](https://creativecommons.org/licenses/by/4.0/).
|
- [The documentation](https://github.com/chillerlan/php-qrcode/tree/v5.0.x/docs) is licensed under the [Creative Commons Attribution 4.0 International (CC BY 4.0) License](https://creativecommons.org/licenses/by/4.0/).
|
||||||
|
|
||||||
|
|
||||||
### Trademark Notice
|
## Trademark Notice
|
||||||
|
|
||||||
The word "QR Code" is a registered trademark of *DENSO WAVE INCORPORATED*<br>
|
The word "QR Code" is a registered trademark of *DENSO WAVE INCORPORATED*<br>
|
||||||
https://www.qrcode.com/en/faq.html#patentH2Title
|
https://www.qrcode.com/en/faq.html#patentH2Title
|
||||||
|
|||||||
35
vendor/chillerlan/php-qrcode/composer.json
vendored
35
vendor/chillerlan/php-qrcode/composer.json
vendored
@@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
|
"$schema": "https://getcomposer.org/schema.json",
|
||||||
"name": "chillerlan/php-qrcode",
|
"name": "chillerlan/php-qrcode",
|
||||||
"description": "A QR code generator and reader with a user friendly API. PHP 7.4+",
|
"description": "A QR Code generator and reader with a user-friendly API. PHP 7.4+",
|
||||||
"homepage": "https://github.com/chillerlan/php-qrcode",
|
"homepage": "https://github.com/chillerlan/php-qrcode",
|
||||||
"license": [
|
"license": [
|
||||||
"MIT", "Apache-2.0"
|
"MIT", "Apache-2.0"
|
||||||
@@ -32,6 +33,12 @@
|
|||||||
"homepage":"https://github.com/chillerlan/php-qrcode/graphs/contributors"
|
"homepage":"https://github.com/chillerlan/php-qrcode/graphs/contributors"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "Ko-Fi",
|
||||||
|
"url": "https://ko-fi.com/codemasher"
|
||||||
|
}
|
||||||
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"docs": "https://php-qrcode.readthedocs.io",
|
"docs": "https://php-qrcode.readthedocs.io",
|
||||||
"issues": "https://github.com/chillerlan/php-qrcode/issues",
|
"issues": "https://github.com/chillerlan/php-qrcode/issues",
|
||||||
@@ -42,15 +49,18 @@
|
|||||||
"require": {
|
"require": {
|
||||||
"php": "^7.4 || ^8.0",
|
"php": "^7.4 || ^8.0",
|
||||||
"ext-mbstring": "*",
|
"ext-mbstring": "*",
|
||||||
"chillerlan/php-settings-container": "^2.1.4 || ^3.1"
|
"chillerlan/php-settings-container": "^2.1.6 || ^3.2.1"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"chillerlan/php-authenticator": "^4.1 || ^5.1",
|
"ext-fileinfo": "*",
|
||||||
"phan/phan": "^5.4",
|
"chillerlan/php-authenticator": "^4.3.1 || ^5.2.1",
|
||||||
|
"phan/phan": "^5.5.1",
|
||||||
|
"phpcompatibility/php-compatibility": "10.x-dev",
|
||||||
"phpunit/phpunit": "^9.6",
|
"phpunit/phpunit": "^9.6",
|
||||||
"phpmd/phpmd": "^2.15",
|
"phpmd/phpmd": "^2.15",
|
||||||
"setasign/fpdf": "^1.8.2",
|
"setasign/fpdf": "^1.8.2",
|
||||||
"squizlabs/php_codesniffer": "^3.8"
|
"slevomat/coding-standard": "^8.23.0",
|
||||||
|
"squizlabs/php_codesniffer": "^4.0.0"
|
||||||
},
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
"chillerlan/php-authenticator": "Yet another Google authenticator! Also creates URIs for mobile apps.",
|
"chillerlan/php-authenticator": "Yet another Google authenticator! Also creates URIs for mobile apps.",
|
||||||
@@ -59,21 +69,26 @@
|
|||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"chillerlan\\QRCode\\": "src/"
|
"chillerlan\\QRCode\\": "src"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload-dev": {
|
"autoload-dev": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"chillerlan\\QRCodeTest\\": "tests/"
|
"chillerlan\\QRCodeTest\\": "tests"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"phpunit": "@php vendor/bin/phpunit",
|
"phan": "@php vendor/bin/phan",
|
||||||
"phan": "@php vendor/bin/phan"
|
"phpcs": "@php vendor/bin/phpcs",
|
||||||
|
"phpmd": "@php vendor/bin/phpmd src text ./phpmd.xml.dist",
|
||||||
|
"phpunit": "@php vendor/bin/phpunit"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"lock": false,
|
"lock": false,
|
||||||
"sort-packages": true,
|
"sort-packages": true,
|
||||||
"platform-check": true
|
"platform-check": true,
|
||||||
|
"allow-plugins": {
|
||||||
|
"dealerdirect/phpcodesniffer-composer-installer": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ class GDLuminanceSource extends LuminanceSourceAbstract{
|
|||||||
*
|
*
|
||||||
* @throws \chillerlan\QRCode\Decoder\QRCodeDecoderException
|
* @throws \chillerlan\QRCode\Decoder\QRCodeDecoderException
|
||||||
*/
|
*/
|
||||||
public function __construct($gdImage, SettingsContainerInterface $options = null){
|
public function __construct($gdImage, ?SettingsContainerInterface $options = null){
|
||||||
|
|
||||||
/** @noinspection PhpFullyQualifiedNameUsageInspection */
|
/** @noinspection PhpFullyQualifiedNameUsageInspection */
|
||||||
if(
|
if(
|
||||||
@@ -85,12 +85,12 @@ class GDLuminanceSource extends LuminanceSourceAbstract{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @inheritDoc */
|
/** @inheritDoc */
|
||||||
public static function fromFile(string $path, SettingsContainerInterface $options = null):self{
|
public static function fromFile(string $path, ?SettingsContainerInterface $options = null):self{
|
||||||
return new self(imagecreatefromstring(file_get_contents(self::checkFile($path))), $options);
|
return new self(imagecreatefromstring(file_get_contents(self::checkFile($path))), $options);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @inheritDoc */
|
/** @inheritDoc */
|
||||||
public static function fromBlob(string $blob, SettingsContainerInterface $options = null):self{
|
public static function fromBlob(string $blob, ?SettingsContainerInterface $options = null):self{
|
||||||
return new self(imagecreatefromstring($blob), $options);
|
return new self(imagecreatefromstring($blob), $options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ final class GenericGFPoly{
|
|||||||
* @throws \chillerlan\QRCode\QRCodeException if argument is null or empty, or if leading coefficient is 0 and this
|
* @throws \chillerlan\QRCode\QRCodeException if argument is null or empty, or if leading coefficient is 0 and this
|
||||||
* is not a constant polynomial (that is, it is not the monomial "0")
|
* is not a constant polynomial (that is, it is not the monomial "0")
|
||||||
*/
|
*/
|
||||||
public function __construct(array $coefficients, int $degree = null){
|
public function __construct(array $coefficients, ?int $degree = null){
|
||||||
$degree ??= 0;
|
$degree ??= 0;
|
||||||
|
|
||||||
if(empty($coefficients)){
|
if(empty($coefficients)){
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ class IMagickLuminanceSource extends LuminanceSourceAbstract{
|
|||||||
/**
|
/**
|
||||||
* IMagickLuminanceSource constructor.
|
* IMagickLuminanceSource constructor.
|
||||||
*/
|
*/
|
||||||
public function __construct(Imagick $imagick, SettingsContainerInterface $options = null){
|
public function __construct(Imagick $imagick, ?SettingsContainerInterface $options = null){
|
||||||
parent::__construct($imagick->getImageWidth(), $imagick->getImageHeight(), $options);
|
parent::__construct($imagick->getImageWidth(), $imagick->getImageHeight(), $options);
|
||||||
|
|
||||||
$this->imagick = $imagick;
|
$this->imagick = $imagick;
|
||||||
@@ -63,12 +63,12 @@ class IMagickLuminanceSource extends LuminanceSourceAbstract{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @inheritDoc */
|
/** @inheritDoc */
|
||||||
public static function fromFile(string $path, SettingsContainerInterface $options = null):self{
|
public static function fromFile(string $path, ?SettingsContainerInterface $options = null):self{
|
||||||
return new self(new Imagick(self::checkFile($path)), $options);
|
return new self(new Imagick(self::checkFile($path)), $options);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @inheritDoc */
|
/** @inheritDoc */
|
||||||
public static function fromBlob(string $blob, SettingsContainerInterface $options = null):self{
|
public static function fromBlob(string $blob, ?SettingsContainerInterface $options = null):self{
|
||||||
$im = new Imagick;
|
$im = new Imagick;
|
||||||
$im->readImageBlob($blob);
|
$im->readImageBlob($blob);
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ abstract class LuminanceSourceAbstract implements LuminanceSourceInterface{
|
|||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function __construct(int $width, int $height, SettingsContainerInterface $options = null){
|
public function __construct(int $width, int $height, ?SettingsContainerInterface $options = null){
|
||||||
$this->width = $width;
|
$this->width = $width;
|
||||||
$this->height = $height;
|
$this->height = $height;
|
||||||
$this->options = ($options ?? new QROptions);
|
$this->options = ($options ?? new QROptions);
|
||||||
@@ -57,7 +57,10 @@ abstract class LuminanceSourceAbstract implements LuminanceSourceInterface{
|
|||||||
return $this->height;
|
return $this->height;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @inheritDoc */
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
* @throws \chillerlan\QRCode\Decoder\QRCodeDecoderException
|
||||||
|
*/
|
||||||
public function getRow(int $y):array{
|
public function getRow(int $y):array{
|
||||||
|
|
||||||
if($y < 0 || $y >= $this->getHeight()){
|
if($y < 0 || $y >= $this->getHeight()){
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ final class MaskPattern{
|
|||||||
*/
|
*/
|
||||||
public function __construct(int $maskPattern){
|
public function __construct(int $maskPattern){
|
||||||
|
|
||||||
if((0b111 & $maskPattern) !== $maskPattern){
|
if(($maskPattern & 0b111) !== $maskPattern){
|
||||||
throw new QRCodeException('invalid mask pattern');
|
throw new QRCodeException('invalid mask pattern');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
namespace chillerlan\QRCode\Data;
|
namespace chillerlan\QRCode\Data;
|
||||||
|
|
||||||
use chillerlan\QRCode\Common\{BitBuffer, Mode};
|
use chillerlan\QRCode\Common\{BitBuffer, Mode};
|
||||||
use function array_flip, ceil, intdiv, str_split;
|
use function ceil, intdiv, preg_match, strpos;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Alphanumeric mode: 0 to 9, A to Z, space, $ % * + - . / :
|
* Alphanumeric mode: 0 to 9, A to Z, space, $ % * + - . / :
|
||||||
@@ -24,16 +24,9 @@ final class AlphaNum extends QRDataModeAbstract{
|
|||||||
/**
|
/**
|
||||||
* ISO/IEC 18004:2000 Table 5
|
* ISO/IEC 18004:2000 Table 5
|
||||||
*
|
*
|
||||||
* @var int[]
|
* @var string
|
||||||
*/
|
*/
|
||||||
private const CHAR_TO_ORD = [
|
private const CHAR_MAP = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:';
|
||||||
'0' => 0, '1' => 1, '2' => 2, '3' => 3, '4' => 4, '5' => 5, '6' => 6, '7' => 7,
|
|
||||||
'8' => 8, '9' => 9, 'A' => 10, 'B' => 11, 'C' => 12, 'D' => 13, 'E' => 14, 'F' => 15,
|
|
||||||
'G' => 16, 'H' => 17, 'I' => 18, 'J' => 19, 'K' => 20, 'L' => 21, 'M' => 22, 'N' => 23,
|
|
||||||
'O' => 24, 'P' => 25, 'Q' => 26, 'R' => 27, 'S' => 28, 'T' => 29, 'U' => 30, 'V' => 31,
|
|
||||||
'W' => 32, 'X' => 33, 'Y' => 34, 'Z' => 35, ' ' => 36, '$' => 37, '%' => 38, '*' => 39,
|
|
||||||
'+' => 40, '-' => 41, '.' => 42, '/' => 43, ':' => 44,
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
@@ -51,18 +44,7 @@ final class AlphaNum extends QRDataModeAbstract{
|
|||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
public static function validateString(string $string):bool{
|
public static function validateString(string $string):bool{
|
||||||
|
return (bool)preg_match('/^[A-Z\d %$*+\-.:\/]+$/', $string);
|
||||||
if($string === ''){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach(str_split($string) as $chr){
|
|
||||||
if(!isset(self::CHAR_TO_ORD[$chr])){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -78,12 +60,15 @@ final class AlphaNum extends QRDataModeAbstract{
|
|||||||
|
|
||||||
// encode 2 characters in 11 bits
|
// encode 2 characters in 11 bits
|
||||||
for($i = 0; ($i + 1) < $len; $i += 2){
|
for($i = 0; ($i + 1) < $len; $i += 2){
|
||||||
$bitBuffer->put((self::CHAR_TO_ORD[$this->data[$i]] * 45 + self::CHAR_TO_ORD[$this->data[($i + 1)]]), 11);
|
$bitBuffer->put(
|
||||||
|
($this->ord($this->data[$i]) * 45 + $this->ord($this->data[($i + 1)])),
|
||||||
|
11,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// encode a remaining character in 6 bits
|
// encode a remaining character in 6 bits
|
||||||
if($i < $len){
|
if($i < $len){
|
||||||
$bitBuffer->put(self::CHAR_TO_ORD[$this->data[$i]], 6);
|
$bitBuffer->put($this->ord($this->data[$i]), 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
@@ -95,19 +80,7 @@ final class AlphaNum extends QRDataModeAbstract{
|
|||||||
* @throws \chillerlan\QRCode\Data\QRCodeDataException
|
* @throws \chillerlan\QRCode\Data\QRCodeDataException
|
||||||
*/
|
*/
|
||||||
public static function decodeSegment(BitBuffer $bitBuffer, int $versionNumber):string{
|
public static function decodeSegment(BitBuffer $bitBuffer, int $versionNumber):string{
|
||||||
$length = $bitBuffer->read(self::getLengthBits($versionNumber));
|
$length = $bitBuffer->read(self::getLengthBits($versionNumber));
|
||||||
$charmap = array_flip(self::CHAR_TO_ORD);
|
|
||||||
|
|
||||||
// @todo
|
|
||||||
$toAlphaNumericChar = function(int $ord) use ($charmap):string{
|
|
||||||
|
|
||||||
if(isset($charmap[$ord])){
|
|
||||||
return $charmap[$ord];
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new QRCodeDataException('invalid character value: '.$ord);
|
|
||||||
};
|
|
||||||
|
|
||||||
$result = '';
|
$result = '';
|
||||||
// Read two characters at a time
|
// Read two characters at a time
|
||||||
while($length > 1){
|
while($length > 1){
|
||||||
@@ -116,9 +89,9 @@ final class AlphaNum extends QRDataModeAbstract{
|
|||||||
throw new QRCodeDataException('not enough bits available'); // @codeCoverageIgnore
|
throw new QRCodeDataException('not enough bits available'); // @codeCoverageIgnore
|
||||||
}
|
}
|
||||||
|
|
||||||
$nextTwoCharsBits = $bitBuffer->read(11);
|
$nextTwoCharsBits = $bitBuffer->read(11);
|
||||||
$result .= $toAlphaNumericChar(intdiv($nextTwoCharsBits, 45));
|
$result .= self::chr(intdiv($nextTwoCharsBits, 45));
|
||||||
$result .= $toAlphaNumericChar($nextTwoCharsBits % 45);
|
$result .= self::chr($nextTwoCharsBits % 45);
|
||||||
$length -= 2;
|
$length -= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,10 +101,36 @@ final class AlphaNum extends QRDataModeAbstract{
|
|||||||
throw new QRCodeDataException('not enough bits available'); // @codeCoverageIgnore
|
throw new QRCodeDataException('not enough bits available'); // @codeCoverageIgnore
|
||||||
}
|
}
|
||||||
|
|
||||||
$result .= $toAlphaNumericChar($bitBuffer->read(6));
|
$result .= self::chr($bitBuffer->read(6));
|
||||||
}
|
}
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws \chillerlan\QRCode\Data\QRCodeDataException
|
||||||
|
*/
|
||||||
|
private function ord(string $chr):int{
|
||||||
|
/** @phan-suppress-next-line PhanParamSuspiciousOrder */
|
||||||
|
$ord = strpos(self::CHAR_MAP, $chr);
|
||||||
|
|
||||||
|
if($ord === false){
|
||||||
|
throw new QRCodeDataException('invalid character'); // @codeCoverageIgnore
|
||||||
|
}
|
||||||
|
|
||||||
|
return $ord;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws \chillerlan\QRCode\Data\QRCodeDataException
|
||||||
|
*/
|
||||||
|
private static function chr(int $ord):string{
|
||||||
|
|
||||||
|
if($ord < 0 || $ord > 44){
|
||||||
|
throw new QRCodeDataException('invalid character code'); // @codeCoverageIgnore
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::CHAR_MAP[$ord];
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
28
vendor/chillerlan/php-qrcode/src/Data/ECI.php
vendored
28
vendor/chillerlan/php-qrcode/src/Data/ECI.php
vendored
@@ -34,6 +34,7 @@ final class ECI extends QRDataModeAbstract{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
|
* @throws \chillerlan\QRCode\Data\QRCodeDataException
|
||||||
* @noinspection PhpMissingParentConstructorInspection
|
* @noinspection PhpMissingParentConstructorInspection
|
||||||
*/
|
*/
|
||||||
public function __construct(int $encoding){
|
public function __construct(int $encoding){
|
||||||
@@ -107,7 +108,7 @@ final class ECI extends QRDataModeAbstract{
|
|||||||
$id = ((($firstByte & 0b00011111) << 16) | $bitBuffer->read(16));
|
$id = ((($firstByte & 0b00011111) << 16) | $bitBuffer->read(16));
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
throw new QRCodeDataException(sprintf('error decoding ECI value first byte: %08b', $firstByte)); // @codeCoverageIgnore
|
throw new QRCodeDataException(sprintf('error decoding ECI value first byte: %08b', $firstByte));// @codeCoverageIgnore
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ECICharset($id);
|
return new ECICharset($id);
|
||||||
@@ -128,17 +129,12 @@ final class ECI extends QRDataModeAbstract{
|
|||||||
public static function decodeSegment(BitBuffer $bitBuffer, int $versionNumber):string{
|
public static function decodeSegment(BitBuffer $bitBuffer, int $versionNumber):string{
|
||||||
$eciCharset = self::parseValue($bitBuffer);
|
$eciCharset = self::parseValue($bitBuffer);
|
||||||
$nextMode = $bitBuffer->read(4);
|
$nextMode = $bitBuffer->read(4);
|
||||||
|
$data = self::decodeModeSegment($nextMode, $bitBuffer, $versionNumber);
|
||||||
if($nextMode !== Mode::BYTE){
|
$encoding = $eciCharset->getName();
|
||||||
throw new QRCodeDataException(sprintf('ECI designator followed by invalid mode: "%04b"', $nextMode));
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = Byte::decodeSegment($bitBuffer, $versionNumber);
|
|
||||||
$encoding = $eciCharset->getName();
|
|
||||||
|
|
||||||
if($encoding === null){
|
if($encoding === null){
|
||||||
// The spec isn't clear on this mode; see
|
// The spec isn't clear on this mode; see
|
||||||
// section 6.4.5: t does not say which encoding to assuming
|
// section 6.4.5: it does not say which encoding to assuming
|
||||||
// upon decoding. I have seen ISO-8859-1 used as well as
|
// upon decoding. I have seen ISO-8859-1 used as well as
|
||||||
// Shift_JIS -- without anything like an ECI designator to
|
// Shift_JIS -- without anything like an ECI designator to
|
||||||
// give a hint.
|
// give a hint.
|
||||||
@@ -152,4 +148,18 @@ final class ECI extends QRDataModeAbstract{
|
|||||||
return mb_convert_encoding($data, mb_internal_encoding(), $encoding);
|
return mb_convert_encoding($data, mb_internal_encoding(), $encoding);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws \chillerlan\QRCode\Data\QRCodeDataException
|
||||||
|
*/
|
||||||
|
private static function decodeModeSegment(int $mode, BitBuffer $bitBuffer, int $versionNumber):string{
|
||||||
|
|
||||||
|
switch(true){
|
||||||
|
case $mode === Mode::NUMBER: return Number::decodeSegment($bitBuffer, $versionNumber);
|
||||||
|
case $mode === Mode::ALPHANUM: return AlphaNum::decodeSegment($bitBuffer, $versionNumber);
|
||||||
|
case $mode === Mode::BYTE: return Byte::decodeSegment($bitBuffer, $versionNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new QRCodeDataException(sprintf('ECI designator followed by invalid mode: "%04b"', $mode));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
12
vendor/chillerlan/php-qrcode/src/Data/Hanzi.php
vendored
12
vendor/chillerlan/php-qrcode/src/Data/Hanzi.php
vendored
@@ -13,7 +13,7 @@ namespace chillerlan\QRCode\Data;
|
|||||||
use chillerlan\QRCode\Common\{BitBuffer, Mode};
|
use chillerlan\QRCode\Common\{BitBuffer, Mode};
|
||||||
use Throwable;
|
use Throwable;
|
||||||
use function chr, implode, intdiv, is_string, mb_convert_encoding, mb_detect_encoding,
|
use function chr, implode, intdiv, is_string, mb_convert_encoding, mb_detect_encoding,
|
||||||
mb_detect_order, mb_internal_encoding, mb_strlen, ord, sprintf, strlen;
|
mb_internal_encoding, mb_strlen, ord, sprintf, strlen;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hanzi (simplified Chinese) mode, GBT18284-2000: 13-bit double-byte characters from the GB2312/GB18030 character set
|
* Hanzi (simplified Chinese) mode, GBT18284-2000: 13-bit double-byte characters from the GB2312/GB18030 character set
|
||||||
@@ -64,11 +64,15 @@ final class Hanzi extends QRDataModeAbstract{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
|
* @throws \chillerlan\QRCode\Data\QRCodeDataException
|
||||||
*/
|
*/
|
||||||
public static function convertEncoding(string $string):string{
|
public static function convertEncoding(string $string):string{
|
||||||
mb_detect_order([mb_internal_encoding(), 'UTF-8', 'GB2312', 'GB18030', 'CP936', 'EUC-CN', 'HZ']);
|
|
||||||
|
|
||||||
$detected = mb_detect_encoding($string, null, true);
|
$detected = mb_detect_encoding(
|
||||||
|
$string,
|
||||||
|
[mb_internal_encoding(), 'UTF-8', 'GB2312', 'GB18030', 'CP936', 'EUC-CN', 'HZ'],
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
if($detected === false){
|
if($detected === false){
|
||||||
throw new QRCodeDataException('mb_detect_encoding error');
|
throw new QRCodeDataException('mb_detect_encoding error');
|
||||||
@@ -199,7 +203,7 @@ final class Hanzi extends QRDataModeAbstract{
|
|||||||
$length--;
|
$length--;
|
||||||
}
|
}
|
||||||
|
|
||||||
return mb_convert_encoding(implode($buffer), mb_internal_encoding(), self::ENCODING);
|
return mb_convert_encoding(implode('', $buffer), mb_internal_encoding(), self::ENCODING);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ namespace chillerlan\QRCode\Data;
|
|||||||
use chillerlan\QRCode\Common\{BitBuffer, Mode};
|
use chillerlan\QRCode\Common\{BitBuffer, Mode};
|
||||||
use Throwable;
|
use Throwable;
|
||||||
use function chr, implode, intdiv, is_string, mb_convert_encoding, mb_detect_encoding,
|
use function chr, implode, intdiv, is_string, mb_convert_encoding, mb_detect_encoding,
|
||||||
mb_detect_order, mb_internal_encoding, mb_strlen, ord, sprintf, strlen;
|
mb_internal_encoding, mb_strlen, ord, sprintf, strlen;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Kanji mode: 13-bit double-byte characters from the Shift-JIS character set
|
* Kanji mode: 13-bit double-byte characters from the Shift-JIS character set
|
||||||
@@ -57,11 +57,10 @@ final class Kanji extends QRDataModeAbstract{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
|
* @throws \chillerlan\QRCode\Data\QRCodeDataException
|
||||||
*/
|
*/
|
||||||
public static function convertEncoding(string $string):string{
|
public static function convertEncoding(string $string):string{
|
||||||
mb_detect_order([mb_internal_encoding(), 'UTF-8', 'SJIS', 'SJIS-2004']);
|
$detected = mb_detect_encoding($string, [mb_internal_encoding(), 'UTF-8', 'SJIS', 'SJIS-2004'], true);
|
||||||
|
|
||||||
$detected = mb_detect_encoding($string, null, true);
|
|
||||||
|
|
||||||
if($detected === false){
|
if($detected === false){
|
||||||
throw new QRCodeDataException('mb_detect_encoding error');
|
throw new QRCodeDataException('mb_detect_encoding error');
|
||||||
@@ -185,7 +184,7 @@ final class Kanji extends QRDataModeAbstract{
|
|||||||
$length--;
|
$length--;
|
||||||
}
|
}
|
||||||
|
|
||||||
return mb_convert_encoding(implode($buffer), mb_internal_encoding(), self::ENCODING);
|
return mb_convert_encoding(implode('', $buffer), mb_internal_encoding(), self::ENCODING);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
60
vendor/chillerlan/php-qrcode/src/Data/Number.php
vendored
60
vendor/chillerlan/php-qrcode/src/Data/Number.php
vendored
@@ -11,7 +11,7 @@
|
|||||||
namespace chillerlan\QRCode\Data;
|
namespace chillerlan\QRCode\Data;
|
||||||
|
|
||||||
use chillerlan\QRCode\Common\{BitBuffer, Mode};
|
use chillerlan\QRCode\Common\{BitBuffer, Mode};
|
||||||
use function array_flip, ceil, intdiv, str_split, substr, unpack;
|
use function ceil, intdiv, substr, unpack;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Numeric mode: decimal digits 0 to 9
|
* Numeric mode: decimal digits 0 to 9
|
||||||
@@ -21,13 +21,6 @@ use function array_flip, ceil, intdiv, str_split, substr, unpack;
|
|||||||
*/
|
*/
|
||||||
final class Number extends QRDataModeAbstract{
|
final class Number extends QRDataModeAbstract{
|
||||||
|
|
||||||
/**
|
|
||||||
* @var int[]
|
|
||||||
*/
|
|
||||||
private const NUMBER_TO_ORD = [
|
|
||||||
'0' => 0, '1' => 1, '2' => 2, '3' => 3, '4' => 4, '5' => 5, '6' => 6, '7' => 7, '8' => 8, '9' => 9,
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
@@ -44,18 +37,7 @@ final class Number extends QRDataModeAbstract{
|
|||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
public static function validateString(string $string):bool{
|
public static function validateString(string $string):bool{
|
||||||
|
return (bool)preg_match('/^\d+$/', $string);
|
||||||
if($string === ''){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach(str_split($string) as $chr){
|
|
||||||
if(!isset(self::NUMBER_TO_ORD[$chr])){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -95,12 +77,20 @@ final class Number extends QRDataModeAbstract{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* get the code for the given numeric string
|
* get the code for the given numeric string
|
||||||
|
*
|
||||||
|
* @throws \chillerlan\QRCode\Data\QRCodeDataException
|
||||||
*/
|
*/
|
||||||
private function parseInt(string $string):int{
|
private function parseInt(string $string):int{
|
||||||
$num = 0;
|
$num = 0;
|
||||||
|
|
||||||
foreach(unpack('C*', $string) as $chr){
|
$ords = unpack('C*', $string);
|
||||||
$num = ($num * 10 + $chr - 48);
|
|
||||||
|
if($ords === false){
|
||||||
|
throw new QRCodeDataException('unpack() error');
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach($ords as $ord){
|
||||||
|
$num = ($num * 10 + $ord - 48);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $num;
|
return $num;
|
||||||
@@ -112,19 +102,7 @@ final class Number extends QRDataModeAbstract{
|
|||||||
* @throws \chillerlan\QRCode\Data\QRCodeDataException
|
* @throws \chillerlan\QRCode\Data\QRCodeDataException
|
||||||
*/
|
*/
|
||||||
public static function decodeSegment(BitBuffer $bitBuffer, int $versionNumber):string{
|
public static function decodeSegment(BitBuffer $bitBuffer, int $versionNumber):string{
|
||||||
$length = $bitBuffer->read(self::getLengthBits($versionNumber));
|
$length = $bitBuffer->read(self::getLengthBits($versionNumber));
|
||||||
$charmap = array_flip(self::NUMBER_TO_ORD);
|
|
||||||
|
|
||||||
// @todo
|
|
||||||
$toNumericChar = function(int $ord) use ($charmap):string{
|
|
||||||
|
|
||||||
if(isset($charmap[$ord])){
|
|
||||||
return $charmap[$ord];
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new QRCodeDataException('invalid character value: '.$ord);
|
|
||||||
};
|
|
||||||
|
|
||||||
$result = '';
|
$result = '';
|
||||||
// Read three digits at a time
|
// Read three digits at a time
|
||||||
while($length >= 3){
|
while($length >= 3){
|
||||||
@@ -139,9 +117,9 @@ final class Number extends QRDataModeAbstract{
|
|||||||
throw new QRCodeDataException('error decoding numeric value');
|
throw new QRCodeDataException('error decoding numeric value');
|
||||||
}
|
}
|
||||||
|
|
||||||
$result .= $toNumericChar(intdiv($threeDigitsBits, 100));
|
$result .= intdiv($threeDigitsBits, 100);
|
||||||
$result .= $toNumericChar(intdiv($threeDigitsBits, 10) % 10);
|
$result .= (intdiv($threeDigitsBits, 10) % 10);
|
||||||
$result .= $toNumericChar($threeDigitsBits % 10);
|
$result .= ($threeDigitsBits % 10);
|
||||||
|
|
||||||
$length -= 3;
|
$length -= 3;
|
||||||
}
|
}
|
||||||
@@ -158,8 +136,8 @@ final class Number extends QRDataModeAbstract{
|
|||||||
throw new QRCodeDataException('error decoding numeric value');
|
throw new QRCodeDataException('error decoding numeric value');
|
||||||
}
|
}
|
||||||
|
|
||||||
$result .= $toNumericChar(intdiv($twoDigitsBits, 10));
|
$result .= intdiv($twoDigitsBits, 10);
|
||||||
$result .= $toNumericChar($twoDigitsBits % 10);
|
$result .= ($twoDigitsBits % 10);
|
||||||
}
|
}
|
||||||
elseif($length === 1){
|
elseif($length === 1){
|
||||||
// One digit left over to read
|
// One digit left over to read
|
||||||
@@ -173,7 +151,7 @@ final class Number extends QRDataModeAbstract{
|
|||||||
throw new QRCodeDataException('error decoding numeric value');
|
throw new QRCodeDataException('error decoding numeric value');
|
||||||
}
|
}
|
||||||
|
|
||||||
$result .= $toNumericChar($digitBits);
|
$result .= $digitBits;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
|
|||||||
@@ -195,7 +195,7 @@ final class QRData{
|
|||||||
|
|
||||||
// guess the version number within the given range
|
// guess the version number within the given range
|
||||||
for($version = $this->options->versionMin; $version <= $this->options->versionMax; $version++){
|
for($version = $this->options->versionMin; $version <= $this->options->versionMax; $version++){
|
||||||
if($total <= $this->maxBitsForEcc[$version]){
|
if($total <= ($this->maxBitsForEcc[$version] - 4)){
|
||||||
return new Version($version);
|
return new Version($version);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -207,7 +207,7 @@ final class QRData{
|
|||||||
/**
|
/**
|
||||||
* creates a BitBuffer and writes the string data to it
|
* creates a BitBuffer and writes the string data to it
|
||||||
*
|
*
|
||||||
* @throws \chillerlan\QRCode\QRCodeException on data overflow
|
* @throws \chillerlan\QRCode\Data\QRCodeDataException on data overflow
|
||||||
*/
|
*/
|
||||||
private function writeBitBuffer():void{
|
private function writeBitBuffer():void{
|
||||||
$MAX_BITS = $this->eccLevel->getMaxBitsForVersion($this->version);
|
$MAX_BITS = $this->eccLevel->getMaxBitsForVersion($this->version);
|
||||||
|
|||||||
@@ -175,7 +175,7 @@ class QRMatrix{
|
|||||||
*
|
*
|
||||||
* @return int[][]|bool[][]
|
* @return int[][]|bool[][]
|
||||||
*/
|
*/
|
||||||
public function getMatrix(bool $boolean = null):array{
|
public function getMatrix(?bool $boolean = null):array{
|
||||||
|
|
||||||
if($boolean !== true){
|
if($boolean !== true){
|
||||||
return $this->matrix;
|
return $this->matrix;
|
||||||
@@ -195,7 +195,7 @@ class QRMatrix{
|
|||||||
* @see \chillerlan\QRCode\Data\QRMatrix::getMatrix()
|
* @see \chillerlan\QRCode\Data\QRMatrix::getMatrix()
|
||||||
* @codeCoverageIgnore
|
* @codeCoverageIgnore
|
||||||
*/
|
*/
|
||||||
public function matrix(bool $boolean = null):array{
|
public function matrix(?bool $boolean = null):array{
|
||||||
return $this->getMatrix($boolean);
|
return $this->getMatrix($boolean);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -387,7 +387,7 @@ class QRMatrix{
|
|||||||
* 7 # 3
|
* 7 # 3
|
||||||
* 6 5 4
|
* 6 5 4
|
||||||
*/
|
*/
|
||||||
public function checkNeighbours(int $x, int $y, int $M_TYPE = null):int{
|
public function checkNeighbours(int $x, int $y, ?int $M_TYPE = null):int{
|
||||||
$bits = 0;
|
$bits = 0;
|
||||||
|
|
||||||
foreach($this::neighbours as $bit => [$ix, $iy]){
|
foreach($this::neighbours as $bit => [$ix, $iy]){
|
||||||
@@ -463,6 +463,7 @@ class QRMatrix{
|
|||||||
|
|
||||||
for($c = 0; $c < 3; $c++){
|
for($c = 0; $c < 3; $c++){
|
||||||
for($i = 0; $i < 8; $i++){
|
for($i = 0; $i < 8; $i++){
|
||||||
|
// phpcs:ignore
|
||||||
$this->set( $h[$c][0] , ($h[$c][1] + $i), false, $this::M_SEPARATOR);
|
$this->set( $h[$c][0] , ($h[$c][1] + $i), false, $this::M_SEPARATOR);
|
||||||
$this->set(($v[$c][0] - $i), $v[$c][1] , false, $this::M_SEPARATOR);
|
$this->set(($v[$c][0] - $i), $v[$c][1] , false, $this::M_SEPARATOR);
|
||||||
}
|
}
|
||||||
@@ -552,7 +553,7 @@ class QRMatrix{
|
|||||||
*
|
*
|
||||||
* ISO/IEC 18004:2000 Section 8.9
|
* ISO/IEC 18004:2000 Section 8.9
|
||||||
*/
|
*/
|
||||||
public function setFormatInfo(MaskPattern $maskPattern = null):self{
|
public function setFormatInfo(?MaskPattern $maskPattern = null):self{
|
||||||
$this->maskPattern = $maskPattern;
|
$this->maskPattern = $maskPattern;
|
||||||
$bits = 0; // sets all format fields to false (test mode)
|
$bits = 0; // sets all format fields to false (test mode)
|
||||||
|
|
||||||
@@ -678,7 +679,7 @@ class QRMatrix{
|
|||||||
*
|
*
|
||||||
* @throws \chillerlan\QRCode\Data\QRCodeDataException
|
* @throws \chillerlan\QRCode\Data\QRCodeDataException
|
||||||
*/
|
*/
|
||||||
public function setLogoSpace(int $width, int $height = null, int $startX = null, int $startY = null):self{
|
public function setLogoSpace(int $width, ?int $height = null, ?int $startX = null, ?int $startY = null):self{
|
||||||
$height ??= $width;
|
$height ??= $width;
|
||||||
|
|
||||||
// if width and height happen to be negative or 0 (default value), just return - nothing to do
|
// if width and height happen to be negative or 0 (default value), just return - nothing to do
|
||||||
|
|||||||
@@ -415,7 +415,7 @@ final class BitMatrix extends QRMatrix{
|
|||||||
* @codeCoverageIgnore
|
* @codeCoverageIgnore
|
||||||
* @throws \chillerlan\QRCode\Data\QRCodeDataException
|
* @throws \chillerlan\QRCode\Data\QRCodeDataException
|
||||||
*/
|
*/
|
||||||
public function setQuietZone(int $quietZoneSize = null):self{
|
public function setQuietZone(?int $quietZoneSize = null):self{
|
||||||
throw new QRCodeDataException('not supported');
|
throw new QRCodeDataException('not supported');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -423,7 +423,7 @@ final class BitMatrix extends QRMatrix{
|
|||||||
* @codeCoverageIgnore
|
* @codeCoverageIgnore
|
||||||
* @throws \chillerlan\QRCode\Data\QRCodeDataException
|
* @throws \chillerlan\QRCode\Data\QRCodeDataException
|
||||||
*/
|
*/
|
||||||
public function setLogoSpace(int $width, int $height = null, int $startX = null, int $startY = null):self{
|
public function setLogoSpace(int $width, ?int $height = null, ?int $startX = null, ?int $startY = null):self{
|
||||||
throw new QRCodeDataException('not supported');
|
throw new QRCodeDataException('not supported');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ final class Decoder{
|
|||||||
private ?EccLevel $eccLevel = null;
|
private ?EccLevel $eccLevel = null;
|
||||||
private ?MaskPattern $maskPattern = null;
|
private ?MaskPattern $maskPattern = null;
|
||||||
private BitBuffer $bitBuffer;
|
private BitBuffer $bitBuffer;
|
||||||
|
private Detector $detector;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decodes a QR Code represented as a BitMatrix.
|
* Decodes a QR Code represented as a BitMatrix.
|
||||||
@@ -37,7 +38,8 @@ final class Decoder{
|
|||||||
* @throws \Throwable|\chillerlan\QRCode\Decoder\QRCodeDecoderException
|
* @throws \Throwable|\chillerlan\QRCode\Decoder\QRCodeDecoderException
|
||||||
*/
|
*/
|
||||||
public function decode(LuminanceSourceInterface $source):DecoderResult{
|
public function decode(LuminanceSourceInterface $source):DecoderResult{
|
||||||
$matrix = (new Detector($source))->detect();
|
$this->detector = new Detector($source);
|
||||||
|
$matrix = $this->detector->detect();
|
||||||
|
|
||||||
try{
|
try{
|
||||||
// clone the BitMatrix to avoid errors in case we run into mirroring
|
// clone the BitMatrix to avoid errors in case we run into mirroring
|
||||||
@@ -148,6 +150,7 @@ final class Decoder{
|
|||||||
'data' => $result,
|
'data' => $result,
|
||||||
'version' => $this->version,
|
'version' => $this->version,
|
||||||
'eccLevel' => $this->eccLevel,
|
'eccLevel' => $this->eccLevel,
|
||||||
|
'finderPatterns' => $this->detector->getFinderPatterns(),
|
||||||
'maskPattern' => $this->maskPattern,
|
'maskPattern' => $this->maskPattern,
|
||||||
'structuredAppendParity' => $parityData,
|
'structuredAppendParity' => $parityData,
|
||||||
'structuredAppendSequence' => $symbolSequence,
|
'structuredAppendSequence' => $symbolSequence,
|
||||||
|
|||||||
@@ -20,13 +20,14 @@ use function property_exists;
|
|||||||
* applies to 2D barcode formats. For now, it contains the raw bytes obtained
|
* applies to 2D barcode formats. For now, it contains the raw bytes obtained
|
||||||
* as well as a String interpretation of those bytes, if applicable.
|
* as well as a String interpretation of those bytes, if applicable.
|
||||||
*
|
*
|
||||||
* @property \chillerlan\QRCode\Common\BitBuffer $rawBytes
|
* @property \chillerlan\QRCode\Common\BitBuffer $rawBytes
|
||||||
* @property string $data
|
* @property string $data
|
||||||
* @property \chillerlan\QRCode\Common\Version $version
|
* @property \chillerlan\QRCode\Common\Version $version
|
||||||
* @property \chillerlan\QRCode\Common\EccLevel $eccLevel
|
* @property \chillerlan\QRCode\Common\EccLevel $eccLevel
|
||||||
* @property \chillerlan\QRCode\Common\MaskPattern $maskPattern
|
* @property \chillerlan\QRCode\Common\MaskPattern $maskPattern
|
||||||
* @property int $structuredAppendParity
|
* @property int $structuredAppendParity
|
||||||
* @property int $structuredAppendSequence
|
* @property int $structuredAppendSequence
|
||||||
|
* @property \chillerlan\QRCode\Detector\FinderPattern[] $finderPatterns
|
||||||
*/
|
*/
|
||||||
final class DecoderResult{
|
final class DecoderResult{
|
||||||
|
|
||||||
@@ -37,11 +38,13 @@ final class DecoderResult{
|
|||||||
private string $data = '';
|
private string $data = '';
|
||||||
private int $structuredAppendParity = -1;
|
private int $structuredAppendParity = -1;
|
||||||
private int $structuredAppendSequence = -1;
|
private int $structuredAppendSequence = -1;
|
||||||
|
/** @var \chillerlan\QRCode\Detector\FinderPattern[] */
|
||||||
|
private array $finderPatterns = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DecoderResult constructor.
|
* DecoderResult constructor.
|
||||||
*/
|
*/
|
||||||
public function __construct(iterable $properties = null){
|
public function __construct(?iterable $properties = null){
|
||||||
|
|
||||||
if(!empty($properties)){
|
if(!empty($properties)){
|
||||||
|
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ final class ReedSolomonDecoder{
|
|||||||
while($longerBlocksStartAt >= 0){
|
while($longerBlocksStartAt >= 0){
|
||||||
$numCodewords = count($result[$longerBlocksStartAt][1]);
|
$numCodewords = count($result[$longerBlocksStartAt][1]);
|
||||||
|
|
||||||
if($numCodewords == $shorterBlocksTotalCodewords){
|
if($numCodewords === $shorterBlocksTotalCodewords){
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -256,7 +256,7 @@ final class AlignmentPatternFinder{
|
|||||||
$i++;
|
$i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if($i == $maxI || $stateCount[1] > $maxCount){
|
if($i === $maxI || $stateCount[1] > $maxCount){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,6 +269,7 @@ final class AlignmentPatternFinder{
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// phpcs:ignore
|
||||||
if((5 * abs(($stateCount[0] + $stateCount[1] + $stateCount[2]) - $originalStateCountTotal)) >= (2 * $originalStateCountTotal)){
|
if((5 * abs(($stateCount[0] + $stateCount[1] + $stateCount[2]) - $originalStateCountTotal)) >= (2 * $originalStateCountTotal)){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user