diff --git a/Abrechnung/module.php b/Abrechnung/module.php index 3e8ab31..858e616 100644 --- a/Abrechnung/module.php +++ b/Abrechnung/module.php @@ -293,7 +293,10 @@ private function AddMeterToPDFRow($meter, $tariffs, $from, $to, $type) return ['row' => '', 'value' => 0]; } - // 1️⃣ Relevante Tarife für diese Verbrauchsart finden + // Zeitzone setzen, um strtotime()-Abweichungen zu vermeiden + date_default_timezone_set('Europe/Zurich'); + + // 1️⃣ Relevante Tarife nach Typ filtern $filteredTariffs = array_filter($tariffs, function ($t) use ($type) { return strtolower(trim($t['unit_type'] ?? '')) === strtolower(trim($type)); }); @@ -303,40 +306,53 @@ private function AddMeterToPDFRow($meter, $tariffs, $from, $to, $type) return ['row' => '', 'value' => 0]; } - // 2️⃣ Zeitlich sortieren + // 2️⃣ Zeitstempel konvertieren und sortieren foreach ($filteredTariffs as &$t) { $t['start_ts'] = is_numeric($t['start']) ? intval($t['start']) : strtotime($t['start']); $t['end_ts'] = is_numeric($t['end']) ? intval($t['end']) : strtotime($t['end']); + + if (!$t['start_ts'] || !$t['end_ts']) { + IPS_LogMessage('Abrechnung', "⚠ Ungültiger Tarifzeitraum in Tarifdefinition: " . json_encode($t)); + } else { + IPS_LogMessage('Abrechnung', sprintf( + " 🕓 Tarif gültig von %s bis %s @ %.3f Rp", + date('d.m.Y H:i', $t['start_ts']), + date('d.m.Y H:i', $t['end_ts']), + floatval($t['price']) + )); + } } unset($t); + usort($filteredTariffs, fn($a, $b) => $a['start_ts'] <=> $b['start_ts']); - // 3️⃣ Startpunkt setzen + // 3️⃣ Abrechnungslogik starten $currentStart = $from; $segmentIndex = 1; - // Schleife bis Abrechnungsende while ($currentStart < $to) { + IPS_LogMessage('Abrechnung', "➡️ Segment {$segmentIndex} Startzeit: " . date('d.m.Y H:i', $currentStart)); - IPS_LogMessage('Abrechnung', "➡️ Segment $segmentIndex: Beginne bei " . date('d.m.Y H:i', $currentStart)); - - // 🔹 Nächsten geloggten Wert nach Startzeit holen - $startValue = $this->GetValueAt($varId, $currentStart, true); - if ($startValue === null) { - IPS_LogMessage('Abrechnung', "⚠ Kein Startwert gefunden bei " . date('d.m.Y H:i', $currentStart)); - break; - } - - // 🔹 Aktiven Tarif bestimmen + // Aktiven Tarif bestimmen $activeTariff = null; foreach ($filteredTariffs as $t) { - if ($t['start_ts'] <= $currentStart && $currentStart < $t['end_ts']) { + $startTs = intval($t['start_ts']); + $endTs = intval($t['end_ts']); + + if ($startTs === 0 || $endTs === 0) continue; + + if ($startTs <= $currentStart && $currentStart < $endTs) { $activeTariff = $t; + IPS_LogMessage('Abrechnung', sprintf( + " ✅ Aktiver Tarif gefunden: %.2f Rp (gültig %s → %s)", + floatval($t['price']), + date('d.m.Y H:i', $startTs), + date('d.m.Y H:i', $endTs) + )); break; } } - // 🔹 Falls kein Tarif aktiv → 0 Rp if (!$activeTariff) { IPS_LogMessage('Abrechnung', "⚠ Kein Tarif aktiv bei " . date('d.m.Y H:i', $currentStart) . " → 0 Rp"); $activeTariff = [ @@ -347,44 +363,37 @@ private function AddMeterToPDFRow($meter, $tariffs, $from, $to, $type) ]; } - $tariffEnd = $activeTariff['end_ts']; + $tariffEnd = intval($activeTariff['end_ts']); $tariffPrice = floatval($activeTariff['price']); $tariffLabel = number_format($tariffPrice, 2, ',', ''); - IPS_LogMessage('Abrechnung', sprintf( - " 🧾 Aktiver Tarif: %.3f Rp (%s - %s)", - $tariffPrice, - date('d.m.Y H:i', $activeTariff['start_ts']), - date('d.m.Y H:i', $activeTariff['end_ts']) - )); - - // 🔹 Prüfen, ob Tarif vor Abrechnungsende endet - if ($tariffEnd < $to) { - // Tarif endet vor Rechnungsende → Segment bis Tarifende abrechnen - $segmentEnd = $tariffEnd; - } else { - // Tarif reicht bis oder über Rechnungsende → letztes Segment - $segmentEnd = $to; - } - - // 🔹 Nächsten Archivwert nach Segmentende lesen - $endValue = $this->GetValueAt($varId, $segmentEnd, true); - if ($endValue === null) { - IPS_LogMessage('Abrechnung', "⚠ Kein Endwert gefunden bei " . date('d.m.Y H:i', $segmentEnd)); + // Archivwerte abrufen + $startValue = $this->GetValueAt($varId, $currentStart, true); + if ($startValue === null) { + IPS_LogMessage('Abrechnung', "⚠ Kein Startwert für " . date('d.m.Y H:i', $currentStart)); break; } - // 🔹 Verbrauch und Kosten + // Wenn Tarif endet vor Rechnungsende → Segment bis Tarifende + $segmentEnd = ($tariffEnd < $to) ? $tariffEnd : $to; + + $endValue = $this->GetValueAt($varId, $segmentEnd, true); + if ($endValue === null) { + IPS_LogMessage('Abrechnung', "⚠ Kein Endwert für " . date('d.m.Y H:i', $segmentEnd)); + break; + } + + // Verbrauch und Kosten $verbrauch = max(0, $endValue - $startValue); $kosten = round(($tariffPrice / 100) * $verbrauch, 2); $totalCost += $kosten; IPS_LogMessage('Abrechnung', sprintf( - " 📊 Segment %d: Start=%.3f, Ende=%.3f, Verbrauch=%.3f, Tarif=%.3f Rp → %.2f CHF", + " 📊 Segment %d: %.3f → %.3f (Δ=%.3f) | Tarif=%.3f Rp | Kosten=%.2f CHF", $segmentIndex, $startValue, $endValue, $verbrauch, $tariffPrice, $kosten )); - // 🔹 Zeile erzeugen + // Tabellenzeile $rows .= "