diff --git a/PackAufgabenMonitor.php b/PackAufgabenMonitor.php index 2f00a77..79663b9 100644 --- a/PackAufgabenMonitor.php +++ b/PackAufgabenMonitor.php @@ -120,7 +120,7 @@ $Epi = new Epirent(); const el = $scroller.get(0); const st = ensureState(el); if (st.userActive) return; - if (st.loopHeight > 0) startAutoScroll($scroller, 1, 40); + if (st.loopHeight > 0) startAutoScroll($scroller, 1, 80); else stopAutoScroll($scroller); } @@ -147,7 +147,7 @@ $Epi = new Epirent(); } // Auto-Scroll (wieder) starten stopAutoScroll($scroller); - startAutoScroll($scroller, 1, 40); + startAutoScroll($scroller, 1, 80); } else { // kein Overflow -> ganz oben und Auto-Scroll aus if (scEl.scrollTop !== 0) requestAnimationFrame(() => { scEl.scrollTop = 0; }); @@ -239,25 +239,31 @@ $Epi = new Epirent(); # Kunde Event - + '; } - if (UsePackingNoteDateForCheckout) { - echo "
Packen-Start"; - } else { - echo "
VB-Start"; - } - if (!HideCheckInTimeOnCheckout) { - if(!HideDispoTimes){ - echo "Dispo-Ende
VB-Ende"; - }else{ - echo "VB-Ende"; - - } - + + if(ShowCheckoutTimeOnCheckout){ + echo "Dispo-Start"; + } + if(ShowVorbereitungTimeOnCheckout){ + if(ShowCheckoutTimeOnCheckout){echo "
";} + echo "VB-Start"; + } + if(ShowPackagingTimeOnCheckout){ + if(ShowCheckoutTimeOnCheckout||ShowVorbereitungTimeOnCheckout){echo "
";} + echo "Packen"; + } + if(ShowDeliveryTimeOnCheckout){ + if(ShowCheckoutTimeOnCheckout || ShowVorbereitungTimeOnCheckout||ShowPackagingTimeOnCheckout){echo "
";} + echo "Liefern"; + } + if(ShowCheckoutTimeOnCheckout || ShowVorbereitungTimeOnCheckout||ShowPackagingTimeOnCheckout || ShowDeliveryTimeOnCheckout){ + echo ''; } + ?> Status # Kunde - Event - -Dispo-Start
RP-Start"; -} - -if(!HideDispoTimes){ - echo "Dispo-Ende"; -}else{ - echo ""; -} -if (UsePackingNoteDateForCheckin) { - echo "
Rücklieferung"; -} else { - echo "
RP-Ende"; -} -?> + Event '; + } + + if(ShowCheckInTimeOnCheckin){ + echo "Dispo-Ende"; + } + if(ShowNachbereitungTimeOnCheckin){ + if(ShowCheckInTimeOnCheckin){echo "
";} + echo "Nachbereitung"; + } + if(ShowRePackagingTimeOnCheckin){ + if(ShowCheckInTimeOnCheckin||ShowNachbereitungTimeOnCheckin){echo "
";} + echo "Zurückpacken"; + } + if(ShowReDeliveryTimeOnCheckin){ + if(ShowCheckInTimeOnCheckin || ShowNachbereitungTimeOnCheckin||ShowRePackagingTimeOnCheckin){echo "
";} + echo "Rückliefern"; + } + if(ShowCheckInTimeOnCheckin || ShowNachbereitungTimeOnCheckin||ShowRePackagingTimeOnCheckin || ShowReDeliveryTimeOnCheckin){ + echo ''; + } + + ?> diff --git a/Packmonitor.php b/Packmonitor.php index 407b618..3734753 100644 --- a/Packmonitor.php +++ b/Packmonitor.php @@ -1,7 +1,4 @@ - - - - - - Packmonitor + + + + + Packmonitor - - - - - + + + + + - - - + + $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 === + // Klont den ersten als __loopClone ans Tabellenende, wenn Inhalt > Sichtbereich. + function buildSeamlessLoop($table, $scroller) { + $table.find('tbody.__loopClone').remove(); -
-
-
-

Check-Out -

- - - - - - - "; - } else { - echo "
VB-Start"; - } - if (!HideCheckInTimeOnCheckout) { - if(!HideDispoTimes){ - echo ""; - }else{ - echo ""; + const $main = $table.find('tbody').first(); + const scEl = $scroller.get(0); + const st = ensureState(scEl); + if ($main.length === 0 || $main.children().length === 0) { + st.loopHeight = 0; + return; } - + + const mainH = $main.get(0).offsetHeight; + const needScroll = mainH > scEl.clientHeight + 1; + + if (!needScroll) { + st.loopHeight = 0; + return; + } + + const $clone = $main.clone(false, false).addClass('__loopClone').attr('aria-hidden', 'true'); + $table.append($clone); + st.loopHeight = mainH; // Höhe des Original-Inhalts als Loop-Länge + } + + // === Auto-Scroll (nahtlos) === + function startAutoScroll($scroller, speedPx = 1, stepMs = 40) { + const el = $scroller.get(0); + 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; + // Nahtlos: sobald wir das Ende des Original-Blocks überschreiten, ziehen wir loopHeight ab + 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); + const st = ensureState(el); + if (st.userActive) return; + if (st.loopHeight > 0) startAutoScroll($scroller, 1, 40); + else stopAutoScroll($scroller); + } + + // === AJAX-Reload: relative Position innerhalb der Loop erhalten === + // Wir merken die Position modulo loopHeight; nach dem Reload setzen wir proportional um. + 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 () { + // Loop neu bewerten/aufbauen + buildSeamlessLoop($table, $scroller); + + if (st.loopHeight > 0) { + // Neue relative Position setzen (proportional) + const newPos = Math.floor(posRatio * st.loopHeight); + if (Math.abs(scEl.scrollTop - newPos) > 1) { + // rAF für flüssiges Setzen außerhalb des load()-Layouts + requestAnimationFrame(() => { scEl.scrollTop = newPos; }); + } + // Auto-Scroll (wieder) starten + stopAutoScroll($scroller); + startAutoScroll($scroller, 1, 40); + } else { + // kein Overflow -> ganz oben und Auto-Scroll aus + 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(); + // Nach Layoutwechsel neu entscheiden (nur 2 Tabellen) + ['#checkout', '#checkin'].forEach(prefix => { + const $scroller = $(`${prefix}-scroll`); + const $table = $(`${prefix}-table`); + buildSeamlessLoop($table, $scroller); + maybeStartAutoScroll($scroller); + }); + }); + + // Guards pro Scroller (nur 2) + attachScrollGuards($('#checkout-scroll')); + attachScrollGuards($('#checkin-scroll')); + + // Erstladen je Tabelle: laden -> Loop bauen -> ggf. Auto-Scroll -> zyklisch refreshen + function initOne(scrollerSel, tableSel, tbodySel, url, ms) { + const $scroller = $(scrollerSel); + const $table = $(tableSel); + const $target = $(tbodySel); + + $target.load(url, function () { + buildSeamlessLoop($table, $scroller); + maybeStartAutoScroll($scroller); + setTimeout(() => smartLoad($scroller, $table, $target, url, ms), ms); + }); + } + + initOne('#checkout-scroll', '#checkout-table', '#getCheckOutTableHolder', 'sources/getCheckOutTable.php', 5000); + initOne('#checkin-scroll', '#checkin-table', '#getCheckInTableHolder', 'sources/getCheckInTable.php', 5000); + }); + + + + + + +
+
+ +
+

Check-Out

+
+
#KundeEvent - Packen-StartDispo-Ende
VB-Ende
VB-Ende
+ + + + + + '; } + + if(ShowCheckoutTimeOnCheckout){ + echo "Dispo-Start"; + } + if(ShowVorbereitungTimeOnCheckout){ + if(ShowCheckoutTimeOnCheckout){echo "
";} + echo "VB-Start"; + } + if(ShowPackagingTimeOnCheckout){ + if(ShowCheckoutTimeOnCheckout||ShowVorbereitungTimeOnCheckout){echo "
";} + echo "Packen"; + } + if(ShowDeliveryTimeOnCheckout){ + if(ShowCheckoutTimeOnCheckout || ShowVorbereitungTimeOnCheckout||ShowPackagingTimeOnCheckout){echo "
";} + echo "Liefern"; + } + if(ShowCheckoutTimeOnCheckout || ShowVorbereitungTimeOnCheckout||ShowPackagingTimeOnCheckout || ShowDeliveryTimeOnCheckout){ + echo ''; + } + ?> - - Shipping"; - } - ?> - - - - - -
#KundeEventStatus
- - - - -
-
-

Check-In -

- - - - - - - -Dispo-Start
RP-Start"; -} - -if(!HideDispoTimes){ - echo ""; -} else { - echo "
RP-Ende"; -} -?> - - - - - Shipping"; - } - ?> - - - - - -
#KundeEventDispo-Ende"; -}else{ - echo ""; -} -if (UsePackingNoteDateForCheckin) { - echo "
Rücklieferung
Status
-
-
- - - - - - - + Status + Shipping"; + } + ?> + + + + +
+ + +
+

Check-In

+
+ + + + + + + '; + } + + if(ShowCheckInTimeOnCheckin){ + echo "Dispo-Ende"; + } + if(ShowNachbereitungTimeOnCheckin){ + if(ShowCheckInTimeOnCheckin){echo "
";} + echo "Nachbereitung"; + } + if(ShowRePackagingTimeOnCheckin){ + if(ShowCheckInTimeOnCheckin||ShowNachbereitungTimeOnCheckin){echo "
";} + echo "Zurückpacken"; + } + if(ShowReDeliveryTimeOnCheckin){ + if(ShowCheckInTimeOnCheckin || ShowNachbereitungTimeOnCheckin||ShowRePackagingTimeOnCheckin){echo "
";} + echo "Rückliefern"; + } + if(ShowCheckInTimeOnCheckin || ShowNachbereitungTimeOnCheckin||ShowRePackagingTimeOnCheckin || ShowReDeliveryTimeOnCheckin){ + echo ''; + } + + ?> + + Shipping"; + } + ?> + + + +
#KundeEventStatus
+
+
+ - - - - - - - + + \ No newline at end of file +?> diff --git a/example.config.php b/example.config.php index 2871c97..93ffa5d 100644 --- a/example.config.php +++ b/example.config.php @@ -20,18 +20,38 @@ define('Enable_QR_Code_CrewBrainAufgaben', true); 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('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, der Zusätzlich zur DispoZeit beim Check In Angezeigt werden soll +define('Rückpacken_Zeitvariable', 'Rückpacken'); -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". -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". +/** -------------------- Row-Marking: Konfig Zusände -------------------- + * 1 = $packingjob->date_start (Dispo Start) + * 2 = $VorbereitungsTimeDetail->date_start (Vorbereitung Start) + * 3 = $PackingNoteDetail->date_packing (Packen Zeit) + * 4 = $PackingNoteDetail->date_delivery (Delivery Zeit) + */ +define('CheckOutRowMarkSource', 4); + +/** -------------------- Row-Marking: Konfig Zusände -------------------- + * 1 = $packingjob->date_end (Dispo Ende) + * 2 = $NachbereitungssTimeDetail->date_start (Nachbereitung Start) + * 3 = $RePackagingTimeDetail->date_start (Rückpacken Zeit AUS AUFTRAG) + * 4 = $PackingNoteDetail->date_redelivery (ReDelivery 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('HideCheckInTimeOnCheckout', true); //Versteckt die CheckIn Zeit im Checkout -define('HideCheckOutTimeOnCheckin', true); //Versteckt die CheckOut Zeit im CheckIn +define('ShowCheckoutTimeOnCheckout', true); +define('ShowVorbereitungTimeOnCheckout', true); +define('ShowPackagingTimeOnCheckout', true); +define('ShowDeliveryTimeOnCheckout', true); +define('ShowTimesOnCheckout', true); -define('HideDispoTimes', true); //Versteckt Dispo-Zeiten Komplett aus den Listen +define('ShowCheckInTimeOnCheckin', true); +define('ShowNachbereitungTimeOnCheckin', true); +define('ShowRePackagingTimeOnCheckin', true); +define('ShowReDeliveryTimeOnCheckin', true); +define('ShowTimesOnCheckin', true); 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. diff --git a/sources/getCheckInTable.php b/sources/getCheckInTable.php index 8074cef..9259102 100644 --- a/sources/getCheckInTable.php +++ b/sources/getCheckInTable.php @@ -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 ? "" : ""; + echo date_format(new \DateTime($dateStr), 'd.m.Y'); + if ($ReturnTime) { + echo " " . getTimeFromSeconds((string)$timeSeconds); + } + echo $cls ? "" : ""; +} + +/** ---------- 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 ""; - } else if ($date < $today) { - echo ""; - } else { - echo ""; - } + $markDate = resolveRowMarkDateCheckIn( + $packingjob, + $NachbereitungsTimeDetail, + $RePackagingTimeDetail, + $PackingNoteDetail, + $source + ); + + if (CheckIn_FutureDays == -1 || ($markDate && (!$limit || $markDate <= $limit))) { + $trClass = rowClassForDate($markDate, $today); + echo $trClass ? "" : ""; + + // QR / Kopfspalten if (Enable_QR_Code_CheckIn) { - echo "" . '
' . (new QRCode($options))->render($packingjob->packingnote_no) . "
"; + echo "
" . (new QRCode($options))->render($packingjob->packingnote_no) . "
"; } else { echo "" . $packingjob->packingnote_no . ""; } echo "" . $packingjob->contact->name . ""; echo "" . $packingjob->event . ""; - if(!HideCheckOutTimeOnCheckin){ - if ($NachbereitungsTimeDetail->date_start != null) { + + // Zeitspalte öffnen, wenn mindestens eine Anzeige aktiv ist + if (ShowCheckInTimeOnCheckin || ShowNachbereitungTimeOnCheckin || ShowRePackagingTimeOnCheckin || ShowReDeliveryTimeOnCheckin) { echo ""; - if(!HideDispoTimes){ - echo "" . date_format(new \DateTime($packingjob->date_start), 'd.m.Y') . " " . getTimeFromSeconds($packingjob->time_start) . "
"; - } - echo "" . date_format(new \DateTime($NachbereitungsTimeDetail->date_start), 'd.m.Y') . " " . getTimeFromSeconds($NachbereitungsTimeDetail->time_start) . ""; - - } else if(!HideDispoTimes){ - echo "" . date_format(new \DateTime($packingjob->date_start), 'd.m.Y') . " " . getTimeFromSeconds($packingjob->time_start) . ""; } + + // 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 ""; - if(!HideDispoTimes){ - echo "" . date_format(new \DateTime($packingjob->date_end), 'd.m.Y') . " " . getTimeFromSeconds($packingjob->time_end) . "
"; - } - echo "" . date_format(new \DateTime($NachbereitungsTimeDetail->date_end), 'd.m.Y') . " " . getTimeFromSeconds($NachbereitungsTimeDetail->time_end) . ""; - - - } else if(!HideDispoTimes){ - echo "" . date_format(new \DateTime($packingjob->date_end), 'd.m.Y') . " " . getTimeFromSeconds($packingjob->time_end) . ""; + + // Nachbereitung (START) — wie von dir bereits genutzt + if (ShowNachbereitungTimeOnCheckin && $NachbereitungsTimeDetail && $NachbereitungsTimeDetail->date_start != null) { + if (ShowCheckInTimeOnCheckin) echo "
"; + echoMarkedTimeLine($NachbereitungsTimeDetail->date_start, (int)$NachbereitungsTimeDetail->time_start, $today, ShowTimesOnCheckin); } + + // Rückpacken (START) + if (ShowRePackagingTimeOnCheckin && $RePackagingTimeDetail && $RePackagingTimeDetail->date_start != null) { + if (ShowCheckInTimeOnCheckin || ShowNachbereitungTimeOnCheckin) echo "
"; + 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 "
"; + echoMarkedTimeLine($PackingNoteDetail->date_redelivery, (int)$PackingNoteDetail->time_redelivery, $today, ShowTimesOnCheckin); + } + + if (ShowCheckInTimeOnCheckin || ShowNachbereitungTimeOnCheckin || ShowRePackagingTimeOnCheckin || ShowReDeliveryTimeOnCheckin) { + echo ""; + } + + // Fortschritt echo ""; - - - - if ($packingjob->is_all_in ==0) { + if ($packingjob->is_all_in == 0) { echo ""; } else { - - echo '
'; - + echo '
'; echo ""; } - - 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 ""; - - if(ShowShippingIcons){ - - if(UseShippingStatus){ - if(($PackingNote_data_output->status==ShippingInOrganizedStatus)||($PackingNote_data_output->status==ShippingOrganizedStatus)){ - echo ""; - }else{ - echo ""; - } - - if($PackingNote_data_output->is_self_redeliver){ - echo ''; - } else{ - if(preg_match('/'.KurierContainsText.'/i',$PackingNote_data_output->shipping_in)){ - echo ''; + // Shipping-Icons (inbound) + if (ShowShippingIcons) { + if (UseShippingStatus) { + if (($PackingNoteDetail->status == ShippingInOrganizedStatus) || ($PackingNoteDetail->status == ShippingOrganizedStatus)) { + echo ""; + } else { + echo ""; } - if(preg_match('/'.SpeditionContainsText.'/i',$PackingNote_data_output->shipping_in)){ - echo ''; - } - if(preg_match('/'.DHLContainsText.'/i',$PackingNote_data_output->shipping_in)){ - echo ''; - } - if(preg_match('/'.LKWContainsText.'/i',$PackingNote_data_output->shipping_in)){ - echo ''; - } - if(preg_match('/'.TransporterContainsText.'/i',$PackingNote_data_output->shipping_in)){ - echo ''; - } - if(preg_match('/'.PKWContainsText.'/i',$PackingNote_data_output->shipping_in)){ - echo ''; + + if ($PackingNoteDetail->is_self_redeliver) { + echo ''; + } else { + if (preg_match('/' . KurierContainsText . '/i', $PackingNoteDetail->shipping_in)) { + echo ''; + } + if (preg_match('/' . SpeditionContainsText . '/i', $PackingNoteDetail->shipping_in)) { + echo ''; + } + if (preg_match('/' . DHLContainsText . '/i', $PackingNoteDetail->shipping_in)) { + echo ''; + } + if (preg_match('/' . LKWContainsText . '/i', $PackingNoteDetail->shipping_in)) { + echo ''; + } + if (preg_match('/' . TransporterContainsText . '/i', $PackingNoteDetail->shipping_in)) { + echo ''; + } + if (preg_match('/' . PKWContainsText . '/i', $PackingNoteDetail->shipping_in)) { + echo ''; + } } + echo ""; } - echo ""; - - } - + + echo ""; + } + echo ""; } - - } } } 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; } - diff --git a/sources/getCheckOutTable.php b/sources/getCheckOutTable.php index 57b971e..04401d0 100644 --- a/sources/getCheckOutTable.php +++ b/sources/getCheckOutTable.php @@ -1,5 +1,6 @@ 1 ]); - $Epi = new Epirent(); -if(UseDeliveredForCheckOutCompleted){ - $result = $Epi->requestEpiApi('/v1/packingnote/open?isco=False&cl=' . Epirent_Mandant); +const APP_TZ = 'Europe/Berlin'; -}else{ -$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, 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; +} + +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?isco=False&cl=' . Epirent_Mandant); +} else { + $result = $Epi->requestEpiApi('/v1/packingnote/open?isci=False&cl=' . Epirent_Mandant); } $data_output = json_decode($result)->payload; - - if (SortCheckOut == 2) { - - // Prüfen, ob $data_output ein Array ist if (is_array($data_output)) { usort($data_output, function ($a, $b) { @@ -60,70 +102,54 @@ if (SortCheckOut == 2) { foreach ($data_output as $packingjob) { + $PackingNoteDetail = null; -$PackingNote_data_output; - -if($packingjob->is_archived != true && UseDeliveredForCheckOutCompleted){ - $PackingNoteDetailResult = $Epi->requestEpiApi('/v1/packingnote/' . $packingjob->primary_key . '?cl=' . Epirent_Mandant); - $PackingNote_data_output = json_decode($PackingNoteDetailResult)->payload[0]; -} - - if ($packingjob->is_archived != true && (!UseDeliveredForCheckOutCompleted || ($PackingNote_data_output->date_delivered == "0000-00-00" && $PackingNote_data_output->time_delivered == 0))) { + 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 + && ( + !UseDeliveredForCheckOutCompleted + || ($PackingNoteDetail->date_delivered !== "0000-00-00" || (int)$PackingNoteDetail->time_delivered !== 0) + ) + && (int)$PackingNoteDetail->is_all_out !== 0 +) { //get OrderDetails $result = $Epi->requestEpiApi('/v1/order/' . $packingjob->order_pk . '?cl=' . Epirent_Mandant); - $orderdetail_output = json_decode($result)->payload[0]; - // get PackingNote Details - if(!UseDeliveredForCheckOutCompleted){ - $PackingNoteDetailResult = $Epi->requestEpiApi('/v1/packingnote/' . $packingjob->primary_key . '?cl=' . Epirent_Mandant); - $PackingNote_data_output = json_decode($PackingNoteDetailResult)->payload[0]; + // 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; + + $VorbereitungsTimeDetail = null; foreach ($orderdetail_output->order_schedule as $scheduledetail) { - - - if (UsePackingNoteDateForCheckout) { - - $tempTimeObject = new stdClass(); - $tempTimeObject->date_start = $PackingNote_data_output->date_packing; - $tempTimeObject->time_start = $PackingNote_data_output->time_packing; - - $VorbereitungsTimeDetail = $tempTimeObject; - } else { - if ($scheduledetail->name == Vorbereitungs_Zeitvariable) { - $VorbereitungsTimeDetail = $scheduledetail; - } + if ($scheduledetail->name == Vorbereitungs_Zeitvariable) { + $VorbereitungsTimeDetail = $scheduledetail; } } - //End Of get Order Details - if (CheckOut_UseDispoStartForRowMarking || ($VorbereitungsTimeDetail->date_start == null)) { - $date = new DateTime($packingjob->date_start); - } else if(UseDeliveredForCheckOutCompleted ){ - { - $date = new DateTime($PackingNote_data_output->date_delivery); - - } - }else{ - $date = new DateTime($VorbereitungsTimeDetail->date_start); + // --- Row-Marking Datum bestimmen (konfigurierbar) --- + $today = dayStart(new DateTimeImmutable('today', new DateTimeZone(APP_TZ))); + $todayFilter = $today; // für die Window-Berechnung + $limit = null; + if (CheckOut_FutureDays != -1) { + $limit = $todayFilter->modify('+' . (int) CheckOut_FutureDays . ' day'); } - $date->setTime(0, 0, 0); - $today = new DateTime(); - $today->setTime(0, 0, 0); + $markDate = resolveRowMarkDate($packingjob, $VorbereitungsTimeDetail, $PackingNoteDetail, (int) CheckOutRowMarkSource); - $todayFilter = new DateTime(); - $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) { + if (CheckOut_FutureDays == -1 || ($markDate && $markDate <= $limit)) { + $trClass = rowClassForDate($markDate, $today); - echo ""; - } else if ($date < $today) { - echo ""; + if ($trClass) { + echo ""; } else { echo ""; } @@ -136,61 +162,37 @@ if($packingjob->is_archived != true && UseDeliveredForCheckOutCompleted){ echo "" . $packingjob->contact->name . ""; echo "" . $packingjob->event . ""; - + if (ShowCheckoutTimeOnCheckout || ShowVorbereitungTimeOnCheckout || ShowPackagingTimeOnCheckout || ShowDeliveryTimeOnCheckout) { echo "";} + - if(UseDeliveredForCheckOutCompleted){ - - if (CheckOut_UseDispoStartForRowMarking || ($VorbereitungsTimeDetail->date_start == null)) { - $date = new DateTime($packingjob->date_start); - } else { - $date = new DateTime($VorbereitungsTimeDetail->date_start); - } - - if ($date == $today) { - - echo ""; - } else if ($date < $today) { - echo ""; - } else { - echo ""; + 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 "
"; + } + echoMarkedTimeLine($VorbereitungsTimeDetail->date_start, (int) $VorbereitungsTimeDetail->time_start, $today, ShowTimesOnCheckout); + } + if (ShowPackagingTimeOnCheckout && $PackingNoteDetail && $PackingNoteDetail->date_packing != null) { + if (ShowCheckoutTimeOnCheckout || ShowVorbereitungTimeOnCheckout) { + echo "
"; + } + echoMarkedTimeLine($PackingNoteDetail->date_packing, (int) $PackingNoteDetail->time_packing, $today, ShowTimesOnCheckout); + } + if (ShowDeliveryTimeOnCheckout && $PackingNoteDetail && $PackingNoteDetail->date_delivery != null) { + if (ShowCheckoutTimeOnCheckout || ShowVorbereitungTimeOnCheckout || ShowPackagingTimeOnCheckout) { + echo "
"; + } + echoMarkedTimeLine($PackingNoteDetail->date_delivery, (int) $PackingNoteDetail->time_delivery, $today, ShowTimesOnCheckout); + } + + + if (ShowCheckoutTimeOnCheckout || ShowVorbereitungTimeOnCheckout || ShowPackagingTimeOnCheckout || ShowDeliveryTimeOnCheckout) { + echo ""; } - - }else{ echo ""; - - } - - if ($VorbereitungsTimeDetail->date_start != null) { - - if(!HideDispoTimes){ - echo "".date_format(new \DateTime($packingjob->date_start), 'd.m.Y') . " " . getTimeFromSeconds($packingjob->time_start) . "
"; - } - echo "" . date_format(new \DateTime($VorbereitungsTimeDetail->date_start), 'd.m.Y') . " " . getTimeFromSeconds($VorbereitungsTimeDetail->time_start) . ""; - - - - } else if(!HideDispoTimes){ - date_format(new \DateTime($packingjob->date_start), 'd.m.Y') . " " . getTimeFromSeconds($packingjob->time_start) . ""; - } - - - - if (!HideCheckInTimeOnCheckout) { - if (($VorbereitungsTimeDetail->date_end != null)) { - - if(!HideDispoTimes){ - - echo "" . date_format(new \DateTime($packingjob->date_end), 'd.m.Y') . " " . getTimeFromSeconds($packingjob->time_end) . "
"; - } - echo "" . date_format(new \DateTime($VorbereitungsTimeDetail->date_end), 'd.m.Y') . " " . getTimeFromSeconds($VorbereitungsTimeDetail->time_end) . ""; - - } else if(!HideDispoTimes){ - echo date_format(new \DateTime($packingjob->date_end), 'd.m.Y') . " " . getTimeFromSeconds($packingjob->time_end) . ""; - } - } - echo ""; - if ($packingjob->is_all_out == 0) { echo ""; @@ -203,52 +205,65 @@ if($packingjob->is_archived != true && UseDeliveredForCheckOutCompleted){ echo ($packingjob->pieces_sum_total - abs($packingjob->is_all_out)) . "/" . $packingjob->pieces_sum_total; echo ""; - - if(ShowShippingIcons){ - - if(UseShippingStatus){ - if(($PackingNote_data_output->status==ShippingOutOrganizedStatus)||($PackingNote_data_output->status==ShippingOrganizedStatus)){ - echo ""; - }else{ - echo ""; - } - - if($PackingNote_data_output->is_self_pickup){ - echo ''; - } else{ - if(preg_match('/'.KurierContainsText.'/i',$PackingNote_data_output->shipping_out)){ - echo ''; + if (ShowShippingIcons) { + + if (UseShippingStatus) { + if (($PackingNoteDetail->status == ShippingOutOrganizedStatus) || ($PackingNoteDetail->status == ShippingOrganizedStatus)) { + echo ""; + } else { + echo ""; } - if(preg_match('/'.SpeditionContainsText.'/i',$PackingNote_data_output->shipping_out)){ - echo ''; - } - if(preg_match('/'.DHLContainsText.'/i',$PackingNote_data_output->shipping_out)){ - echo ''; - } - if(preg_match('/'.LKWContainsText.'/i',$PackingNote_data_output->shipping_out)){ - echo ''; - } - if(preg_match('/'.TransporterContainsText.'/i',$PackingNote_data_output->shipping_out)){ - echo ''; - } - if(preg_match('/'.PKWContainsText.'/i',$PackingNote_data_output->shipping_out)){ - echo ''; + + if ($PackingNoteDetail->is_self_pickup) { + echo ''; + } else { + if (preg_match('/' . KurierContainsText . '/i', $PackingNoteDetail->shipping_out)) { + echo ''; + } + if (preg_match('/' . SpeditionContainsText . '/i', $PackingNoteDetail->shipping_out)) { + echo ''; + } + if (preg_match('/' . DHLContainsText . '/i', $PackingNoteDetail->shipping_out)) { + echo ''; + } + if (preg_match('/' . LKWContainsText . '/i', $PackingNoteDetail->shipping_out)) { + echo ''; + } + if (preg_match('/' . TransporterContainsText . '/i', $PackingNoteDetail->shipping_out)) { + echo ''; + } + if (preg_match('/' . PKWContainsText . '/i', $PackingNoteDetail->shipping_out)) { + echo ''; + } } + echo ""; } - echo ""; - - } - - echo ""; - } - - + + echo ""; + } + echo ""; } } } +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 ? "" : ""; + echo date_format(new \DateTime($dateStr), 'd.m.Y'); + if($ReturnTime){echo " ".getTimeFromSeconds((string) $timeSeconds);} + echo $cls ? "" : ""; +} + function getTimeFromSeconds(string $timestring) { $hours = floor($timestring / 3600); @@ -260,4 +275,4 @@ function getTimeFromSeconds(string $timestring) { return $timeFormat; } -?> \ No newline at end of file +?>