diff --git a/Abrechnung/module.php b/Abrechnung/module.php index f015a5d..c179424 100644 --- a/Abrechnung/module.php +++ b/Abrechnung/module.php @@ -135,7 +135,7 @@ public function GenerateInvoices() $html = "
{$user['address']}
{$user['city']}
| Zähler | Typ | @@ -215,7 +215,7 @@ public function GenerateInvoices() return 0.0; } -private function GetValueAt(int $varId, int $timestamp, bool $nearestAfter = false) +private function GetValueAt(int $varId, int $timestamp) { $archiveID = @IPS_GetInstanceListByModuleID('{43192F0B-135B-4CE7-A0A7-1475603F3060}')[0]; if (!$archiveID || !IPS_VariableExists($varId)) { @@ -223,14 +223,22 @@ private function GetValueAt(int $varId, int $timestamp, bool $nearestAfter = fal return null; } - if ($nearestAfter) { - // Endwert: erster Wert >= Timestamp - $values = @AC_GetLoggedValues($archiveID, $varId, $timestamp, $timestamp + 86400, 1); - if ($values && count($values) > 0) return floatval($values[0]['Value']); - } else { - // Startwert: letzter Wert <= Timestamp - $values = @AC_GetLoggedValues($archiveID, $varId, 0, $timestamp, 1); - if ($values && count($values) > 0) return floatval($values[count($values)-1]['Value']); + // Letzter Wert <= Timestamp + $before = @AC_GetLoggedValues($archiveID, $varId, 0, $timestamp, 1); + $beforeVal = ($before && count($before) > 0) ? floatval($before[count($before)-1]['Value']) : null; + + // Erster Wert >= Timestamp + $after = @AC_GetLoggedValues($archiveID, $varId, $timestamp, time(), 1); + $afterVal = ($after && count($after) > 0) ? floatval($after[0]['Value']) : null; + + // Wert auswählen: Priorität nach Timestamp + if ($afterVal !== null) { + IPS_LogMessage('Abrechnung', "Variable $varId: Wert nach Timestamp gefunden = $afterVal"); + return $afterVal; + } + if ($beforeVal !== null) { + IPS_LogMessage('Abrechnung', "Variable $varId: Wert vor Timestamp gefunden = $beforeVal"); + return $beforeVal; } // Fallback auf aktuellen Wert @@ -241,68 +249,74 @@ private function GetValueAt(int $varId, int $timestamp, bool $nearestAfter = fal private function AddMeterToPDFRow($meter, $tariffs, $from, $to, $type) { + $startVal = $this->GetValueAt($meter['var_consumption'], $from); + $endVal = $this->GetValueAt($meter['var_consumption'], $to); + + IPS_LogMessage('Abrechnung', "Meter {$meter['name']} ($type) von " . date('d.m.Y H:i', $from) . " bis " . date('d.m.Y H:i', $to) . ": start=$startVal, end=$endVal"); + + if ($startVal === null || $endVal === null) return ['row' => '', 'value' => 0]; + + $totalDiff = max(0, $endVal - $startVal); + if ($totalDiff <= 0) return ['row' => '', 'value' => 0]; + $rows = ''; $totalCost = 0.0; - $currentTime = $from; - $startValTotal = $this->GetValueAt($meter['var_consumption'], $from, false); + // Alle Tarife dieses Typs prüfen + foreach ($tariffs as $t) { + if (strtolower($t['unit_type']) != strtolower($type)) continue; - IPS_LogMessage('Abrechnung', "Starte Abrechnung für Meter {$meter['name']} ($type) von " . date('d.m.Y H:i', $from) . " bis " . date('d.m.Y H:i', $to)); + $tariffStart = strtotime($t['start']); + $tariffEnd = strtotime($t['end']); - while ($currentTime < $to) { - // 1. Tarif zum aktuellen Zeitpunkt ermitteln - $activeTariff = null; - foreach ($tariffs as $t) { - if (strtolower($t['unit_type']) != strtolower($type)) continue; - $tStart = strtotime($t['start']); - $tEnd = strtotime($t['end']); - if ($currentTime >= $tStart && $currentTime < $tEnd) { - $activeTariff = $t; - break; - } - } + // Überschneidung mit Abrechnungszeitraum prüfen + if ($tariffEnd < $from || $tariffStart > $to) continue; - if ($activeTariff === null) { - IPS_LogMessage('Abrechnung', "⚠ Kein aktiver Tarif gefunden für $type am " . date('d.m.Y H:i', $currentTime)); - break; // Kein Tarif → Stop - } + // Überschneidung bestimmen + $sectionStart = max($from, $tariffStart); + $sectionEnd = min($to, $tariffEnd); + $sectionDuration = $sectionEnd - $sectionStart; + $totalDuration = $to - $from; - // 2. Zeitraum für diesen Tarif - $periodStart = $currentTime; - $periodEnd = min($to, strtotime($activeTariff['end'])); + if ($sectionDuration <= 0) continue; - // 3. Zählerstände für diesen Zeitraum ermitteln - $startVal = ($periodStart == $from) ? $startValTotal : $this->GetValueAt($meter['var_consumption'], $periodStart, false); - $endVal = $this->GetValueAt($meter['var_consumption'], $periodEnd, true); + // Verbrauch anteilig nach Dauer + $sectionFraction = $sectionDuration / $totalDuration; + $sectionDiff = $totalDiff * $sectionFraction; - $diff = max(0, $endVal - $startVal); - $tariffRp = floatval($activeTariff['price']); - $costCHF = ($tariffRp / 100) * $diff; + $tariffRp = floatval($t['price']); + $costCHF = ($tariffRp / 100) * $sectionDiff; - // 4. Zeile für PDF $rows .= "||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| {$meter['name']} | $type | -" . date('d.m.Y H:i', $periodStart) . " | -" . date('d.m.Y H:i', $periodEnd) . " | -" . number_format($startVal, 2) . " | -" . number_format($endVal, 2) . " | -" . number_format($diff, 2) . " | +" . date('d.m.Y H:i', $sectionStart) . " | +" . date('d.m.Y H:i', $sectionEnd) . " | +" . number_format($sectionDiff, 2) . " | " . number_format($tariffRp, 2) . " | " . number_format($costCHF, 2) . " |
| {$meter['name']} | +$type | +" . date('d.m.Y H:i', $from) . " | +" . date('d.m.Y H:i', $to) . " | +" . number_format($totalDiff, 2) . " | +0 | +0.00 | +