- Endzeiten bei CheckOut und Startzeiten bei CheckIn komplett entfernt

- Zeiten einzeln Ein- und Ausblendbar gemacht
- Quelle für Zeilenfarbe einstellbar gemacht
- Zeiten werden jetzt bei erreichen bzw überschreiten immer markiert (nur die Zeit)
- Nicht benötigte Spalten werden automatisch ausgeblendet
- Config Datei Ausgedünnt (Bitte komplette Epirent-Settings (nicht Login) Sektion ersetzen
This commit is contained in:
2025-10-10 09:36:11 +02:00
parent 0ff0c0d55e
commit 91c0a2d9d9
5 changed files with 718 additions and 488 deletions

View File

@@ -10,215 +10,250 @@ use chillerlan\QRCode\{
require('../vendor/autoload.php');
$options = new QROptions([
'imageBase64' => false,
'qrCodeHeight' => 75,
'qrCodeWidth' => 75,
'version' => -1,
'quietzoneSize' => 1
]);
]);
$Epi = new Epirent();
$result = $Epi->requestEpiApi('/v1/packingnote/open?isco=False&cl=' . Epirent_Mandant);
$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,
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;
}
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) {
// Prüfen, ob $data_output ein Array ist
if (is_array($data_output)) {
usort($data_output, function ($a, $b) {
// Konvertiere time_start von Millisekunden in Sekunden
$timeStartA = $a->time_end / 1000; // Zeit in Sekunden
$timeStartB = $b->time_end / 1000;
// Kombiniere date_start mit time_start
$datetimeA = strtotime($a->date_end) + $timeStartA;
$datetimeB = strtotime($b->date_end) + $timeStartB;
// Vergleich für die Sortierung
$timeEndA = $a->time_end / 1000;
$timeEndB = $b->time_end / 1000;
$datetimeA = strtotime($a->date_end) + $timeEndA;
$datetimeB = strtotime($b->date_end) + $timeEndB;
return $datetimeA <=> $datetimeB;
});
// Sortierte Daten ausgeben oder weiterverarbeiten
// print_r($data_output);
} else {
echo "Daten konnten nicht verarbeitet werden.";
}
}
/** ---------- Tabelle ---------- */
foreach ($data_output as $packingjob) {
if ($packingjob->is_archived != true) {
//get OrderDetails
// OrderDetails
$result = $Epi->requestEpiApi('/v1/order/' . $packingjob->order_pk . '?cl=' . Epirent_Mandant);
$orderdetail_output = json_decode($result)->payload[0];
// get PackingNote Details
// PackingNote Details
$PackingNoteDetailResult = $Epi->requestEpiApi('/v1/packingnote/' . $packingjob->primary_key . '?cl=' . Epirent_Mandant);
$PackingNote_data_output = json_decode($PackingNoteDetailResult)->payload[0];
$NachbereitungsTimeDetail;
$PackingNoteDetail = json_decode($PackingNoteDetailResult)->payload[0];
// Zeit-Slots aus dem Schedule
$NachbereitungsTimeDetail = null;
$RePackagingTimeDetail = null;
foreach ($orderdetail_output->order_schedule as $scheduledetail) {
if (UsePackingNoteDateForCheckin) {
$tempTimeObject = new stdClass();
$tempTimeObject->date_end = $PackingNote_data_output->date_redelivery;
$tempTimeObject->time_end = $PackingNote_data_output->time_redelivery;
print($PackingNote_data_output->time_redelivery);
$NachbereitungsTimeDetail = $tempTimeObject;
} else {
if ($scheduledetail->name == Rueckpacken_Zeitvariable) {
if ($scheduledetail->name == Nachbereitung_Zeitvariable) {
$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);
// --- 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');
}
$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) {
// Override-Flag wie bei Checkout: Dispo-Ende erzwingen
$source = CheckIn_UseDispoEndForRowMarking ? 1 : (int)CheckInRowMarkSource;
echo "<tr class='text-dark bg-warning'>";
} else if ($date < $today) {
echo "<tr class=' bg-danger'>";
} else {
echo "<tr>";
}
$markDate = resolveRowMarkDateCheckIn(
$packingjob,
$NachbereitungsTimeDetail,
$RePackagingTimeDetail,
$PackingNoteDetail,
$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) {
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 {
echo "<td>" . $packingjob->packingnote_no . "</td>";
}
echo "<td>" . $packingjob->contact->name . "</td>";
echo "<td>" . $packingjob->event . "</td>";
if(!HideCheckOutTimeOnCheckin){
if ($NachbereitungsTimeDetail->date_start != null) {
// Zeitspalte öffnen, wenn mindestens eine Anzeige aktiv ist
if (ShowCheckInTimeOnCheckin || ShowNachbereitungTimeOnCheckin || ShowRePackagingTimeOnCheckin || ShowReDeliveryTimeOnCheckin) {
echo "<td>";
if(!HideDispoTimes){
echo "<small>" . date_format(new \DateTime($packingjob->date_start), 'd.m.Y') . " " . getTimeFromSeconds($packingjob->time_start) . "</small><br>";
}
echo "<i>" . date_format(new \DateTime($NachbereitungsTimeDetail->date_start), 'd.m.Y') . " " . getTimeFromSeconds($NachbereitungsTimeDetail->time_start) . "</i></td>";
} else if(!HideDispoTimes){
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>";
if(!HideDispoTimes){
echo "<small>" . date_format(new \DateTime($packingjob->date_end), 'd.m.Y') . " " . getTimeFromSeconds($packingjob->time_end) . "</small><br>";
}
echo "<i>" . date_format(new \DateTime($NachbereitungsTimeDetail->date_end), 'd.m.Y') . " " . getTimeFromSeconds($NachbereitungsTimeDetail->time_end) . "</i></td>";
} else if(!HideDispoTimes){
echo "<td>" . date_format(new \DateTime($packingjob->date_end), 'd.m.Y') . " " . getTimeFromSeconds($packingjob->time_end) . "</td>";
// Nachbereitung (START) — wie von dir bereits genutzt
if (ShowNachbereitungTimeOnCheckin && $NachbereitungsTimeDetail && $NachbereitungsTimeDetail->date_start != null) {
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);
}
if (ShowCheckInTimeOnCheckin || ShowNachbereitungTimeOnCheckin || ShowRePackagingTimeOnCheckin || ShowReDeliveryTimeOnCheckin) {
echo "</td>";
}
// Fortschritt
echo "<td>";
if ($packingjob->is_all_in ==0) {
if ($packingjob->is_all_in == 0) {
echo "<span class='badge badge-success'>";
} else {
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>';
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>';
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>";
if(ShowShippingIcons){
if(UseShippingStatus){
if(($PackingNote_data_output->status==ShippingInOrganizedStatus)||($PackingNote_data_output->status==ShippingOrganizedStatus)){
echo "<td style='color:#66FF00; text-align:center;'>";
}else{
echo "<td style='text-align:center;'>";
}
if($PackingNote_data_output->is_self_redeliver){
echo '<i class="fa-solid fa-person-walking fa-lg"></i>';
} else{
if(preg_match('/'.KurierContainsText.'/i',$PackingNote_data_output->shipping_in)){
echo '<i class="fa-solid fa-hand-holding-dollar fa-lg"></i>';
// 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(preg_match('/'.SpeditionContainsText.'/i',$PackingNote_data_output->shipping_in)){
echo '<i class="fa-solid fa-truck fa-lg"></i>';
}
if(preg_match('/'.DHLContainsText.'/i',$PackingNote_data_output->shipping_in)){
echo '<i class="fa-brands fa-dhl fa-2xl"></i>';
}
if(preg_match('/'.LKWContainsText.'/i',$PackingNote_data_output->shipping_in)){
echo '<i class="fa-solid fa-industry fa-lg"></i><i class="fa-solid fa-truck fa-lg"></i>';
}
if(preg_match('/'.TransporterContainsText.'/i',$PackingNote_data_output->shipping_in)){
echo '<i class="fa-solid fa-industry fa-lg"></i><i class="fa-solid fa-van-shuttle fa-lg"></i>';
}
if(preg_match('/'.PKWContainsText.'/i',$PackingNote_data_output->shipping_in)){
echo '<i class="fa-solid fa-industry fa-lg"></i><i class="fa-solid fa-car fa-lg"></i>';
if ($PackingNoteDetail->is_self_redeliver) {
echo '<i class="fa-solid fa-person-walking fa-lg"></i>';
} else {
if (preg_match('/' . KurierContainsText . '/i', $PackingNoteDetail->shipping_in)) {
echo '<i class="fa-solid fa-hand-holding-dollar fa-lg"></i>';
}
if (preg_match('/' . SpeditionContainsText . '/i', $PackingNoteDetail->shipping_in)) {
echo '<i class="fa-solid fa-truck fa-lg"></i>';
}
if (preg_match('/' . DHLContainsText . '/i', $PackingNoteDetail->shipping_in)) {
echo '<i class="fa-brands fa-dhl fa-2xl"></i>';
}
if (preg_match('/' . LKWContainsText . '/i', $PackingNoteDetail->shipping_in)) {
echo '<i class="fa-solid fa-industry fa-lg"></i><i class="fa-solid fa-truck fa-lg"></i>';
}
if (preg_match('/' . TransporterContainsText . '/i', $PackingNoteDetail->shipping_in)) {
echo '<i class="fa-solid fa-industry fa-lg"></i><i class="fa-solid fa-van-shuttle fa-lg"></i>';
}
if (preg_match('/' . PKWContainsText . '/i', $PackingNoteDetail->shipping_in)) {
echo '<i class="fa-solid fa-industry fa-lg"></i><i class="fa-solid fa-car fa-lg"></i>';
}
}
echo "</td>";
}
echo "</td>";
}
echo "</tr>";
}
echo "</tr>";
}
}
}
}
function getTimeFromSeconds(string $timestring) {
$hours = floor($timestring / 3600);
$mins = floor($timestring / 60 % 60);
$secs = floor($timestring % 60);
$mins = floor($timestring / 60 % 60);
$secs = floor($timestring % 60);
$timeFormat = sprintf('%02d:%02d', $hours, $mins);
return $timeFormat;
}