From 5b2b24f8249e5f4afeb2a7d316a1e0992a3296d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=A4fliger?= Date: Wed, 5 Nov 2025 08:43:06 +0100 Subject: [PATCH] no message --- Abrechnung/module.php | 191 +++++++++++++++++------------------------- 1 file changed, 77 insertions(+), 114 deletions(-) diff --git a/Abrechnung/module.php b/Abrechnung/module.php index 6f8849a..3e8ab31 100644 --- a/Abrechnung/module.php +++ b/Abrechnung/module.php @@ -284,168 +284,131 @@ private function AddMeterToPDFRow($meter, $tariffs, $from, $to, $type) { $rows = ''; $totalCost = 0.0; - $varId = $meter['var_consumption']; - IPS_LogMessage('Abrechnung', "🔧 [AddMeterToPDFRow] Start für Zähler '{$meter['name']}' (Typ: {$type}), Zeitraum: " . date('d.m.Y H:i', $from) . " - " . date('d.m.Y H:i', $to) . ", VarID={$varId}"); + + IPS_LogMessage('Abrechnung', "🔧 [AddMeterToPDFRow] Starte für '{$meter['name']}' (Typ: {$type}) von " . date('d.m.Y H:i', $from) . " bis " . date('d.m.Y H:i', $to)); if (!IPS_VariableExists($varId)) { - IPS_LogMessage('Abrechnung', "❌ [AddMeterToPDFRow] Variable {$varId} für {$meter['name']} nicht gefunden"); + IPS_LogMessage('Abrechnung', "❌ Variable {$varId} für {$meter['name']} nicht gefunden"); return ['row' => '', 'value' => 0]; } - // --- Relevante Tarife nach Typ filtern (LOGGING ONLY) --- + // 1️⃣ Relevante Tarife für diese Verbrauchsart finden $filteredTariffs = array_filter($tariffs, function ($t) use ($type) { - $tariffType = strtolower(trim($t['unit_type'] ?? '')); - $typeNorm = strtolower(trim($type)); - - $map = [ - 'strombezug' => ['strom', 'strombezug', 'stromzähler', 'stromverbrauch'], - 'warmwasser' => ['warmwasser', 'wasser', 'hww'], - 'kaltwasser' => ['kaltwasser', 'wasser', 'kww'], - 'wärme' => ['wärme', 'heizung', 'heat'] - ]; - return in_array($tariffType, $map[$typeNorm] ?? []) || $tariffType === $typeNorm; + return strtolower(trim($t['unit_type'] ?? '')) === strtolower(trim($type)); }); - IPS_LogMessage('Abrechnung', "🔹 [AddMeterToPDFRow] passende Tarife für '{$type}': " . count($filteredTariffs)); - if (empty($filteredTariffs)) { - IPS_LogMessage('Abrechnung', "⚠ [AddMeterToPDFRow] Keine passenden Tarife für Typ '{$type}' gefunden → 0 Rp"); + IPS_LogMessage('Abrechnung', "⚠ Keine passenden Tarife für {$type} gefunden"); return ['row' => '', 'value' => 0]; } - // --- Tarife sicher in Zeiträume umwandeln (LOGGING ONLY) --- + // 2️⃣ Zeitlich 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']); - IPS_LogMessage('Abrechnung', sprintf( - " 🕓 Tariffenster: %s → %s | Preis: %s Rp | unit_type='%s'", - $t['start_ts'] ? date('d.m.Y H:i', $t['start_ts']) : '❌', - $t['end_ts'] ? date('d.m.Y H:i', $t['end_ts']) : '❌', - isset($t['price']) ? str_replace('.', ',', (string)$t['price']) : '❌', - $t['unit_type'] ?? '—' - )); } unset($t); - - // Sortiere Tarife nach Startzeit (unverändert) usort($filteredTariffs, fn($a, $b) => $a['start_ts'] <=> $b['start_ts']); - $current = $from; - $segIndex = 1; + // 3️⃣ Startpunkt setzen + $currentStart = $from; + $segmentIndex = 1; - while ($current < $to) { - IPS_LogMessage('Abrechnung', "➡️ [AddMeterToPDFRow] Segment {$segIndex} START: " . date('d.m.Y H:i', $current)); + // Schleife bis Abrechnungsende + while ($currentStart < $to) { - // Finde aktiven Tarif für diesen Zeitpunkt (unverändert) + 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 $activeTariff = null; foreach ($filteredTariffs as $t) { - if ($t['start_ts'] <= $current && $current <= $t['end_ts']) { + if ($t['start_ts'] <= $currentStart && $currentStart < $t['end_ts']) { $activeTariff = $t; break; } } - // Wenn kein aktiver Tarif, nimm nächsten oder rechne 0 Rp (unverändert) + // 🔹 Falls kein Tarif aktiv → 0 Rp if (!$activeTariff) { - $nextStart = $to; - foreach ($filteredTariffs as $t) { - if ($t['start_ts'] > $current && $t['start_ts'] < $nextStart) { - $nextStart = $t['start_ts']; - } - } - $segmentEnd = min($nextStart, $to); - $tariffPrice = 0.0; - $tariffLabel = 'kein Tarif'; - IPS_LogMessage('Abrechnung', " ⚠ Kein aktiver Tarif → 0 Rp bis " . date('d.m.Y H:i', $segmentEnd)); - } else { - $segmentEnd = min($activeTariff['end_ts'], $to); - $tariffPrice = floatval($activeTariff['price']); - $tariffLabel = number_format($tariffPrice, 2, ',', ''); - IPS_LogMessage('Abrechnung', sprintf( - " ✅ Aktiver Tarif: %.3f Rp | gültig bis %s | SegmentEnd=%s", - $tariffPrice, - date('d.m.Y H:i', $activeTariff['end_ts']), - date('d.m.Y H:i', $segmentEnd) - )); + IPS_LogMessage('Abrechnung', "⚠ Kein Tarif aktiv bei " . date('d.m.Y H:i', $currentStart) . " → 0 Rp"); + $activeTariff = [ + 'start_ts' => $currentStart, + 'end_ts' => $to, + 'price' => 0.0, + 'unit_type'=> $type + ]; } - // Sicherheitsnetz (unverändert) - if ($segmentEnd <= $current) { - IPS_LogMessage('Abrechnung', " ⚠ segmentEnd <= current (" . date('d.m.Y H:i', $segmentEnd) . " <= " . date('d.m.Y H:i', $current) . "), Abbruch der Schleife."); + $tariffEnd = $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)); break; } - // --- Verbrauch für diesen Zeitraum (unverändert) --- - IPS_LogMessage('Abrechnung', " 🔎 Hole Startwert @ " . date('d.m.Y H:i', $current) . " (nearestAfter=true)"); - $startVal = $this->GetValueAt($varId, $current, true); - - IPS_LogMessage('Abrechnung', " 🔎 Hole Endwert @ " . date('d.m.Y H:i', $segmentEnd) . " (nearestAfter=true)"); - $endVal = $this->GetValueAt($varId, $segmentEnd, true); - - if ($startVal === null || $endVal === null) { - IPS_LogMessage('Abrechnung', " ⚠ Keine Werte gefunden (startVal=" . var_export($startVal, true) . ", endVal=" . var_export($endVal, true) . ") → Segment übersprungen"); - $current = $segmentEnd + 1; - $segIndex++; - continue; - } - - $diff = max(0, $endVal - $startVal); - $costCHF = round(($tariffPrice / 100) * $diff, 2); - $totalCost += $costCHF; + // 🔹 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=%s, Kosten=%.2f CHF", - $segIndex, $startVal, $endVal, $diff, $tariffLabel, $costCHF + " 📊 Segment %d: Start=%.3f, Ende=%.3f, Verbrauch=%.3f, Tarif=%.3f Rp → %.2f CHF", + $segmentIndex, $startValue, $endValue, $verbrauch, $tariffPrice, $kosten )); - // --- Ausgabezeile (unverändert) --- + // 🔹 Zeile erzeugen $rows .= " {$meter['name']} {$type} - " . date('d.m.Y H:i', $current) . " + " . date('d.m.Y H:i', $currentStart) . " " . date('d.m.Y H:i', $segmentEnd) . " - " . number_format($startVal, 2) . " - " . number_format($endVal, 2) . " - " . number_format($diff, 2) . " - " . $tariffLabel . " - " . number_format($costCHF, 2) . " + " . number_format($startValue, 2) . " + " . number_format($endValue, 2) . " + " . number_format($verbrauch, 2) . " + {$tariffLabel} + " . number_format($kosten, 2) . " "; - $current = $segmentEnd + 1; // unverändert - $segIndex++; + // 🔹 Falls Tarif endet → nächster Zyklus startet am Ende des Tarifs + if ($tariffEnd < $to) { + $currentStart = $tariffEnd; + } else { + break; // Letztes Segment erreicht + } + + $segmentIndex++; } - // --- Falls nichts berechnet wurde (unverändert) --- - if ($rows == '') { - IPS_LogMessage('Abrechnung', "⚠ [AddMeterToPDFRow] Keine Segmente berechnet – Fallback-Zeile mit 0 Rp"); - $startVal = $this->GetValueAt($varId, $from, false); - $endVal = $this->GetValueAt($varId, $to, true); - $diff = max(0, $endVal - $startVal); - IPS_LogMessage('Abrechnung', sprintf( - " 🔁 Fallback: Start=%.3f (@%s), Ende=%.3f (@%s), Verbrauch=%.3f", - $startVal, date('d.m.Y H:i', $from), - $endVal, date('d.m.Y H:i', $to), - $diff - )); - $rows = " - - {$meter['name']} - {$type} - " . date('d.m.Y H:i', $from) . " - " . date('d.m.Y H:i', $to) . " - " . number_format($startVal, 2) . " - " . number_format($endVal, 2) . " - " . number_format($diff, 2) . " - 0 - 0.00 - "; - } - - IPS_LogMessage('Abrechnung', sprintf("✅ [AddMeterToPDFRow] Fertig für '%s' (%s): Total=%.2f CHF", - $meter['name'], $type, $totalCost - )); + IPS_LogMessage('Abrechnung', sprintf("✅ [AddMeterToPDFRow] Fertig: %.2f CHF total, %d Segmente", $totalCost, $segmentIndex - 1)); return ['row' => $rows, 'value' => $totalCost]; }