diff --git a/Abrechnung/module.php b/Abrechnung/module.php index 226fd49..ec3729c 100644 --- a/Abrechnung/module.php +++ b/Abrechnung/module.php @@ -45,39 +45,65 @@ class Abrechnung extends IPSModule IPS_SetName($mid, $Name); IPS_SetPosition($mid, $Position); IPS_SetMediaFile($mid, 'media/' . $mid . '.' . $Extension, false); + IPS_LogMessage('Abrechnung', 'Media-Datei erstellt: media/' . $mid . '.' . $Extension); } } - public function RequestAction($Ident, $Value) - { - switch ($Ident) { - case 'FromDate': - case 'ToDate': - SetValue($this->GetIDForIdent($Ident), $Value); - break; +public function RequestAction($Ident, $Value) +{ + IPS_LogMessage('Abrechnung', "RequestAction: $Ident"); - case 'StartBilling': - try { - $pdfContent = $this->GenerateInvoices(); - if ($pdfContent && strlen($pdfContent) > 100) { - $mediaID = $this->GetIDForIdent('InvoicePDF'); - IPS_SetMediaContent($mediaID, base64_encode($pdfContent)); - SetValue($this->GetIDForIdent('LastResult'), 'Abrechnung vom ' . date('d.m.Y H:i')); - echo "✅ PDF erfolgreich erstellt."; - } else { - echo "❌ Fehler bei der PDF-Erstellung."; - } - } catch (Throwable $e) { - echo "❌ Ausnahmefehler: " . $e->getMessage(); + switch ($Ident) { + case 'FromDate': + case 'ToDate': + SetValue($this->GetIDForIdent($Ident), $Value); + break; + + case 'StartBilling': + IPS_LogMessage('Abrechnung', 'Starte Abrechnung...'); + try { + $pdfContent = $this->GenerateInvoices(); + if ($pdfContent === false) { + IPS_LogMessage('Abrechnung', '❌ GenerateInvoices() lieferte false zurück'); + echo "❌ Fehler bei der PDF-Erstellung (GenerateInvoices)"; + return; } - break; - } + if ($pdfContent === null) { + IPS_LogMessage('Abrechnung', '❌ GenerateInvoices() gab null zurück'); + echo "❌ Fehler bei der PDF-Erstellung (leer)"; + return; + } + if (strlen($pdfContent) < 100) { + IPS_LogMessage('Abrechnung', '❌ PDF-Inhalt zu kurz: ' . strlen($pdfContent)); + echo "❌ Fehler bei der PDF-Erstellung (leeres PDF)"; + return; + } + + $mediaID = $this->GetIDForIdent('InvoicePDF'); + if (!$mediaID) { + IPS_LogMessage('Abrechnung', '❌ Media-ID nicht gefunden'); + echo "❌ Kein Media-Objekt vorhanden"; + return; + } + + IPS_SetMediaContent($mediaID, base64_encode($pdfContent)); + SetValue($this->GetIDForIdent('LastResult'), 'Abrechnung vom ' . date('d.m.Y H:i')); + IPS_LogMessage('Abrechnung', '✅ Abrechnung erfolgreich gespeichert (' . strlen($pdfContent) . ' Bytes)'); + echo "✅ PDF erfolgreich erstellt."; + + } catch (Throwable $e) { + IPS_LogMessage('Abrechnung', '💥 Exception in StartBilling: ' . $e->getMessage()); + echo "❌ Ausnahmefehler: " . $e->getMessage(); + } + break; } +} + // ====================== PDF-Logik ====================== - public function GenerateInvoices() - { +public function GenerateInvoices() +{ $from = GetValue($this->GetIDForIdent('FromDate')); $to = GetValue($this->GetIDForIdent('ToDate')); @@ -102,11 +128,9 @@ class Abrechnung extends IPSModule return $pdf->Output('Abrechnung.pdf', 'S'); } +} - // ====================================================== - // 🧱 Layout / PDF-Aufbau pro Benutzerseite - // ====================================================== - private function BuildUserInvoice($user, $power, $water, $tariffs, $from, $to) + private function BuildUserInvoice($user, $power, $water, $tariffs, $from, $to) { $stromRows = ''; $stromTotal = 0.0; @@ -220,60 +244,106 @@ class Abrechnung extends IPSModule return $html; } - // ====================================================== - // Archivwert-Funktion + Tarif-Logik (aus deinem funktionierenden Code) - // ====================================================== - private function GetValueAt(int $varId, int $timestamp, bool $nearestAfter = true) + private function AddMeterToPDF($pdf, $meter, $tariffs, $from, $to, $type) { - $archiveID = @IPS_GetInstanceListByModuleID('{43192F0B-135B-4CE7-A0A7-1475603F3060}')[0]; - if (!$archiveID || !IPS_VariableExists($varId)) { - return null; + $start = $this->GetValueAt($meter['var_consumption'], $from); + $end = $this->GetValueAt($meter['var_consumption'], $to); + if ($start === null || $end === null) return 0; + + $diff = max(0, $end - $start); + $tariffRp = $this->GetTariff($tariffs, $type, $from, $to); + $cost = ($tariffRp / 100) * $diff; + + $pdf->writeHTML(" + + {$meter['name']} + $type + $start + $end + $diff + $tariffRp + " . number_format($cost, 2) . " + ", false, false, false, false, ''); + + return $cost; + } + + private function GetTariff(array $tariffs, string $type, int $from, int $to): float + { + foreach ($tariffs as $t) { + $start = strtotime($t['start']); + $end = strtotime($t['end']); + if ($from >= $start && $to <= $end && strtolower($t['unit_type']) == strtolower($type)) { + return floatval($t['price']); + } } + // Kein passender Tarif gefunden + return 0.0; + } - $maxDays = 365; - $stepDays = 30; - $valueFound = null; +private function GetValueAt(int $varId, int $timestamp, bool $nearestAfter = true) +{ + $archiveID = @IPS_GetInstanceListByModuleID('{43192F0B-135B-4CE7-A0A7-1475603F3060}')[0]; + if (!$archiveID || !IPS_VariableExists($varId)) { + IPS_LogMessage('Abrechnung', "❌ Variable $varId oder Archiv $archiveID nicht gefunden"); + return null; + } - if ($nearestAfter) { - for ($offset = 0; $offset < $maxDays; $offset += $stepDays) { - $from = $timestamp + $offset * 86400; - $to = $from + $stepDays * 86400; - $values = @AC_GetLoggedValues($archiveID, $varId, $from, $to, 0); - if (!empty($values)) { - foreach ($values as $v) { - if ($v['TimeStamp'] >= $timestamp) { - $valueFound = floatval($v['Value']); - break 2; - } + $maxDays = 365; // maximal 1 Jahr suchen + $stepDays = 30; // in 30-Tage-Blöcken durchsuchen + $valueFound = null; + + if ($nearestAfter) { + // 🔹 Suche den ersten Wert NACH dem gewünschten Zeitpunkt + for ($offset = 0; $offset < $maxDays; $offset += $stepDays) { + $from = $timestamp + $offset * 86400; + $to = $from + $stepDays * 86400; + $values = @AC_GetLoggedValues($archiveID, $varId, $from, $to, 0); + if (!empty($values)) { + // ersten Wert nach Timestamp nehmen + foreach ($values as $v) { + if ($v['TimeStamp'] >= $timestamp) { + $valueFound = floatval($v['Value']); + break 2; } } } - } else { - for ($offset = 0; $offset < $maxDays; $offset += $stepDays) { - $from = $timestamp - ($offset + $stepDays) * 86400; - $to = $timestamp - $offset * 86400; - $values = @AC_GetLoggedValues($archiveID, $varId, $from, $to, 0); - if (!empty($values)) { - $last = null; - foreach ($values as $v) { - if ($v['TimeStamp'] <= $timestamp) { - $last = $v; - } else break; - } - if ($last !== null) { - $valueFound = floatval($last['Value']); + } + } else { + // 🔹 Suche den letzten Wert VOR dem gewünschten Zeitpunkt + for ($offset = 0; $offset < $maxDays; $offset += $stepDays) { + $from = $timestamp - ($offset + $stepDays) * 86400; + $to = $timestamp - $offset * 86400; + $values = @AC_GetLoggedValues($archiveID, $varId, $from, $to, 0); + if (!empty($values)) { + // letzten Wert vor Timestamp nehmen + $last = null; + foreach ($values as $v) { + if ($v['TimeStamp'] <= $timestamp) { + $last = $v; + } else { break; } } + if ($last !== null) { + $valueFound = floatval($last['Value']); + break; + } } } - - if ($valueFound === null) { - return floatval(GetValue($varId)); - } - return $valueFound; } + // 🔹 Falls nichts im Archiv: aktuellen Variablenwert nehmen + if ($valueFound === null) { + $fallback = floatval(GetValue($varId)); + IPS_LogMessage('Abrechnung', "⚠ Kein Archivwert für $varId gefunden – nutze aktuellen Wert ($fallback)"); + return $fallback; + } + + return $valueFound; +} + + private function AddMeterToPDFRow($meter, $tariffs, $from, $to, $type) { $rows = '';