Compare commits
2 Commits
f8fba4275d
...
957d52dd21
| Author | SHA1 | Date | |
|---|---|---|---|
| 957d52dd21 | |||
| f8c8725622 |
@@ -12,7 +12,7 @@ public function requestEpiApi(string $requestString){
|
||||
$requestUrl = Epirent_Connectionprotocol."://".Epirent_Server.":".Epirent_Port.$requestString;
|
||||
$response = $client->request('GET', $requestUrl,[
|
||||
'headers' =>[
|
||||
'X-EPI-NO-SESSION' => 'True',
|
||||
'X-EPI-NO-SESSION' => 'true',
|
||||
'X-EPI-ACC-TOK' => Epirent_Token
|
||||
]
|
||||
]);
|
||||
|
||||
@@ -249,8 +249,8 @@ $Epi = new Epirent();
|
||||
});
|
||||
}
|
||||
|
||||
initOne('#checkout-scroll', '#checkout-table', '#getCheckOutTableHolder', 'sources/getCheckOutTable.php', 5000, 'checkout');
|
||||
initOne('#checkin-scroll', '#checkin-table', '#getCheckInTableHolder', 'sources/getCheckInTable.php', 5000, 'checkin');
|
||||
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>
|
||||
|
||||
@@ -238,8 +238,8 @@ $Epi = new Epirent();
|
||||
});
|
||||
}
|
||||
|
||||
initOne('#checkout-scroll', '#checkout-table', '#getCheckOutTableHolder', 'sources/getCheckOutTable.php', 5000, 'checkout');
|
||||
initOne('#checkin-scroll', '#checkin-table', '#getCheckInTableHolder', 'sources/getCheckInTable.php', 5000, 'checkin');
|
||||
initOne('#checkout-scroll', '#checkout-table', '#getCheckOutTableHolder', 'sources/getCheckOutTable.php', 10000, 'checkout');
|
||||
initOne('#checkin-scroll', '#checkin-table', '#getCheckInTableHolder', 'sources/getCheckInTable.php', 10000, 'checkin');
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ Die Anwendung ist speziell für den Einsatz in Lagerprozessen entwickelt.
|
||||
1. Repository klonen oder Dateien ins Webverzeichnis kopieren:
|
||||
```bash
|
||||
git clone http://srvgitea01.vtm.zone:3000/epi/EpiWebview
|
||||
|
||||
2. Dashboard Aufrufen und auf die Config-Seite wechseln, notwendige Einstellungen vornehmen.
|
||||
## Changelog
|
||||
Verschoben in Releases (Git)
|
||||
---
|
||||
214
dist/index.php
vendored
214
dist/index.php
vendored
@@ -1,148 +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>
|
||||
<html lang="en">
|
||||
<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="" />
|
||||
<meta name="author" content="" />
|
||||
<title>Dashboard - EpiWebview</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>
|
||||
<script src="https://kit.fontawesome.com/93d71de8bc.js" crossorigin="anonymous"></script>
|
||||
<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>
|
||||
|
||||
<link href="/src/fa/css/fontawesome.css" rel="stylesheet" />
|
||||
<link href="/src/fa/css/brands.css" rel="stylesheet" />
|
||||
<link href="/src/fa/css/solid.css" rel="stylesheet" />
|
||||
<link href="/src/fa/css/sharp-thin.css" rel="stylesheet" />
|
||||
<link href="/src/fa/css/sharp-duotone-thin.css" rel="stylesheet" />
|
||||
<script type="text/javascript">
|
||||
|
||||
|
||||
$(document).ready(function(){
|
||||
refreshOrderTable();
|
||||
loadSidenav();
|
||||
loadFooter();
|
||||
});
|
||||
function refreshOrderTable(){
|
||||
$('#OrderTableHolder').load('../sources/getOrders.php', function(){
|
||||
setTimeout(refreshOrderTable, 5000);
|
||||
});
|
||||
}
|
||||
function loadSidenav(){
|
||||
<!-- 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 (nur 1x jQuery laden) -->
|
||||
<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>
|
||||
// Einmalige Loads – analog zur Auftragsliste
|
||||
$(function () {
|
||||
loadSidenav();
|
||||
loadFooter();
|
||||
|
||||
});
|
||||
|
||||
function loadSidenav() {
|
||||
$('#layoutSidenav_nav').load('../sources/getSidenav.php');
|
||||
}
|
||||
function loadFooter(){
|
||||
}
|
||||
|
||||
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" href="#"><i class="fas fa-bars"></i></button>
|
||||
}
|
||||
|
||||
|
||||
</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">Dashboard</h1>
|
||||
<ol class="breadcrumb mb-4">
|
||||
<li class="breadcrumb-item active">Dashboard</li>
|
||||
</ol>
|
||||
|
||||
|
||||
|
||||
|
||||
</nav>
|
||||
<div id="layoutSidenav">
|
||||
<div id="layoutSidenav_nav">
|
||||
</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>
|
||||
<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>
|
||||
|
||||
|
||||
</div>
|
||||
</main>
|
||||
<div id="footerholder"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bootstrap Bundle (Popper inkl.) -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.bundle.min.js" crossorigin="anonymous"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
193
sources/getCheckInCards.php
Normal file
193
sources/getCheckInCards.php
Normal file
@@ -0,0 +1,193 @@
|
||||
<?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;
|
||||
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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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>
|
||||
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>
|
||||
@@ -71,6 +71,7 @@ function rowClassForDate(?DateTimeImmutable $markDate, ?DateTimeImmutable $today
|
||||
|
||||
if (UseDeliveredForCheckOutCompleted) {
|
||||
$result = $Epi->requestEpiApi('/v1/packingnote/open?isco=False&cl=' . Epirent_Mandant);
|
||||
|
||||
} else {
|
||||
$result = $Epi->requestEpiApi('/v1/packingnote/open?isci=False&cl=' . Epirent_Mandant);
|
||||
}
|
||||
@@ -107,15 +108,17 @@ foreach ($data_output as $packingjob) {
|
||||
if ($packingjob->is_archived != true && UseDeliveredForCheckOutCompleted) {
|
||||
$PackingNoteDetailResult = $Epi->requestEpiApi('/v1/packingnote/' . $packingjob->primary_key . '?cl=' . Epirent_Mandant);
|
||||
$PackingNoteDetail = json_decode($PackingNoteDetailResult)->payload[0];
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (
|
||||
$packingjob->is_archived != true
|
||||
if (
|
||||
($packingjob->is_archived ?? false) != true
|
||||
&& (
|
||||
!UseDeliveredForCheckOutCompleted
|
||||
|| ($PackingNoteDetail->date_delivered !== "0000-00-00" || (int)$PackingNoteDetail->time_delivered !== 0)
|
||||
((int)($PackingNoteDetail->is_all_out ?? 0)) !== 0
|
||||
|| (($PackingNoteDetail->date_delivered ?? "0000-00-00") === "0000-00-00"
|
||||
|| (int)($PackingNoteDetail->time_delivered ?? 0) === 0)
|
||||
)
|
||||
&& (int)$PackingNoteDetail->is_all_out !== 0
|
||||
) {
|
||||
//get OrderDetails
|
||||
$result = $Epi->requestEpiApi('/v1/order/' . $packingjob->order_pk . '?cl=' . Epirent_Mandant);
|
||||
|
||||
Reference in New Issue
Block a user