From 6bd5b64a0300481d77378261ac6c57024b18d7e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=A4fliger?= Date: Tue, 4 Nov 2025 11:28:50 +0100 Subject: [PATCH] no message --- Abrechnung/module.php | 208 +++++++++++++++++++++++------------------- 1 file changed, 113 insertions(+), 95 deletions(-) diff --git a/Abrechnung/module.php b/Abrechnung/module.php index 58206a6..6b50596 100644 --- a/Abrechnung/module.php +++ b/Abrechnung/module.php @@ -1,7 +1,7 @@ RegisterPropertyString('WaterMeters', '[]'); $this->RegisterPropertyString('Tariffs', '[]'); - // Variablen für Zeitraum und Status + // Variablen $this->RegisterVariableInteger('FromDate', 'Startdatum', '~UnixTimestamp', 1); $this->RegisterVariableInteger('ToDate', 'Enddatum', '~UnixTimestamp', 2); $this->RegisterVariableString('LastResult', 'Letzte Abrechnung', '', 3); @@ -25,25 +25,27 @@ class Abrechnung extends IPSModule // Abrechnungs-Button $this->RegisterScript('StartBilling', 'Abrechnung starten', "InstanceID . ", 'StartBilling', ''); ?>"); - // 🧾 Media-Objekt (PDF) anlegen + // 🧾 Media-Objekt für PDF-Ergebnis $this->RegisterMediaDocument('InvoicePDF', 'Letzte Rechnung', 'pdf'); } + public function ApplyChanges() + { + parent::ApplyChanges(); + IPS_LogMessage('Abrechnung', 'Modul geladen'); + } + private function RegisterMediaDocument($Ident, $Name, $Extension, $Position = 0) - { - $this->RegisterMedia(5, $Ident, $Name, $Extension, $Position); - } - - private function RegisterMedia($Type, $Ident, $Name, $Extension, $Position) { $mid = @IPS_GetObjectIDByIdent($Ident, $this->InstanceID); if ($mid === false) { - $mid = IPS_CreateMedia(5 /* Document */); + $mid = IPS_CreateMedia(5); // 5 = Document IPS_SetParent($mid, $this->InstanceID); IPS_SetIdent($mid, $Ident); IPS_SetName($mid, $Name); IPS_SetPosition($mid, $Position); IPS_SetMediaFile($mid, 'media/' . $mid . '.' . $Extension, false); + IPS_LogMessage('Abrechnung', 'Media-Datei erstellt: media/' . $mid . '.' . $Extension); } } @@ -58,25 +60,23 @@ class Abrechnung extends IPSModule break; case 'StartBilling': - IPS_LogMessage('Abrechnung', 'Starte Abrechnung...'); $pdfContent = $this->GenerateInvoices(); - - if ($pdfContent && strlen($pdfContent) > 100) { + if ($pdfContent) { $mediaID = $this->GetIDForIdent('InvoicePDF'); IPS_SetMediaContent($mediaID, base64_encode($pdfContent)); - IPS_LogMessage('Abrechnung', '✅ PDF erfolgreich im Media-Objekt gespeichert'); - - SetValue($this->GetIDForIdent('LastResult'), 'Abrechnung ' . date('Y-m-d H:i')); - echo "✅ Abrechnung erfolgreich erstellt."; + SetValue($this->GetIDForIdent('LastResult'), 'Abrechnung vom ' . date('d.m.Y H:i')); + IPS_LogMessage('Abrechnung', '✅ Abrechnung erfolgreich gespeichert'); + echo "✅ PDF erfolgreich erstellt."; } else { - IPS_LogMessage('Abrechnung', '❌ Fehler bei der PDF-Erstellung'); + IPS_LogMessage('Abrechnung', '❌ Fehler bei PDF-Erstellung'); echo "❌ Fehler bei der PDF-Erstellung"; } break; } } - // 🧾 Hauptfunktion: PDF erzeugen (wie in PDFReportMulti) + // ====================== PDF-Logik ====================== + public function GenerateInvoices() { $from = GetValue($this->GetIDForIdent('FromDate')); @@ -87,93 +87,111 @@ class Abrechnung extends IPSModule return false; } - $users = json_decode($this->ReadPropertyString('Users'), true); - $power = json_decode($this->ReadPropertyString('PowerMeters'), true); - $water = json_decode($this->ReadPropertyString('WaterMeters'), true); + $users = json_decode($this->ReadPropertyString('Users'), true); + $power = json_decode($this->ReadPropertyString('PowerMeters'), true); + $water = json_decode($this->ReadPropertyString('WaterMeters'), true); $tariffs = json_decode($this->ReadPropertyString('Tariffs'), true); - IPS_LogMessage('Abrechnung', 'Starte PDF-Erstellung mit TCPDF...'); - - // TCPDF initialisieren (wie im SymconReport) - $pdf = new TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false); - $pdf->SetCreator(PDF_CREATOR); - $pdf->SetAuthor('IPSymcon Abrechnung'); - $pdf->SetTitle('Zählerabrechnung'); - $pdf->SetSubject('Automatische Abrechnung'); - - $pdf->setPrintHeader(false); - $pdf->setFooterFont([PDF_FONT_NAME_DATA, '', PDF_FONT_SIZE_DATA]); - $pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED); - $pdf->SetMargins(PDF_MARGIN_LEFT, PDF_MARGIN_TOP - 15, PDF_MARGIN_RIGHT); - $pdf->SetAutoPageBreak(true, PDF_MARGIN_BOTTOM); - $pdf->SetFont('dejavusans', '', 10); - - // Jede Seite = Benutzer - foreach ($users as $user) { - $pdf->AddPage(); - - $pdf->writeHTML("

Rechnung für {$user['name']}

", true, false, true, false, ''); - $pdf->writeHTML("

{$user['address']}
{$user['city']}

", true, false, true, false, ''); - - $pdf->writeHTML(" - - - ", false, false, false, false, ''); - - $userMeters = array_merge( - array_filter($power, fn($m) => $m['user_id'] == $user['id']), - array_filter($water, fn($m) => $m['user_id'] == $user['id']) - ); - - $total = 0.0; - foreach ($userMeters as $m) { - $start = $this->GetValueAt($m['var_consumption'], $from); - $end = $this->GetValueAt($m['var_consumption'], $to); - if ($start === null || $end === null) continue; - - $diff = max(0, $end - $start); - $price = $this->GetTariffForMeter($tariffs, $from, $to, $m); - $cost = $diff * $price; - $total += $cost; - - $pdf->writeHTML(" - - - - - - - ", false, false, false, false, ''); - } - - $pdf->writeHTML("
ZählerStartEndeVerbrauchKosten (CHF)
{$m['name']}$start$end$diff" . number_format($cost, 2) . "

Gesamt: " . number_format($total, 2) . " CHF

", true, false, true, false, ''); + if (empty($users)) { + IPS_LogMessage('Abrechnung', 'Keine Benutzer vorhanden'); + return false; } - // Ausgabe als String (nicht auf Datei) - return $pdf->Output('Abrechnung.pdf', 'S'); // "S" = return as string + $pdf = new TCPDF('P', 'mm', 'A4', true, 'UTF-8', false); + $pdf->SetCreator('IPSymcon Abrechnung'); + $pdf->SetAuthor('Abrechnung Modul'); + $pdf->SetTitle('Zählerabrechnung'); + $pdf->SetMargins(15, 15, 15); + $pdf->SetAutoPageBreak(true, 20); + $pdf->SetFont('dejavusans', '', 10); + + foreach ($users as $user) { + $pdf->AddPage(); + $pdf->writeHTML("

Rechnung für {$user['name']}

"); + $pdf->writeHTML("

{$user['address']}
{$user['city']}

"); + $pdf->Ln(4); + + $pdf->writeHTML(" + + + + + + + + + "); + + $total = 0.0; + + // Stromzähler + foreach ($power as $m) { + if ($m['user_id'] != $user['id']) continue; + $total += $this->AddMeterToPDF($pdf, $m, $tariffs, $from, $to, 'Strombezug'); + } + + // Wasserzähler + foreach ($water as $m) { + if ($m['user_id'] != $user['id']) continue; + $type = $m['meter_type'] ?? 'Warmwasser'; + $total += $this->AddMeterToPDF($pdf, $m, $tariffs, $from, $to, $type); + } + + $pdf->writeHTML("
ZählerTypStartEndeVerbrauchTarif (Rp)Kosten (CHF)
"); + $pdf->Ln(5); + $pdf->writeHTML("

Gesamtsumme: " . number_format($total, 2) . " CHF

"); + } + + IPS_LogMessage('Abrechnung', 'PDF-Daten fertiggestellt'); + return $pdf->Output('Abrechnung.pdf', 'S'); + } + + private function AddMeterToPDF($pdf, $meter, $tariffs, $from, $to, $type) + { + $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; } private function GetValueAt(int $varId, int $timestamp) { $archiveID = @IPS_GetInstanceListByModuleID('{43192F0B-135B-4CE7-A0A7-1475603F3060}')[0]; - if (!$archiveID) return GetValue($varId); + if (!$archiveID || !IPS_VariableExists($varId)) return null; - $values = AC_GetLoggedValues($archiveID, $varId, $timestamp - 3600, $timestamp + 3600, 1); - if (count($values) > 0) return floatval($values[0]['Value']); - return GetValue($varId); - } - - private function GetTariffForMeter(array $tariffs, int $from, int $to, array $meter): float - { - $type = $meter['meter_type'] ?? 'Wärme'; - $tariff = 0.0; - foreach ($tariffs as $t) { - $start = strtotime($t['start']); - $end = strtotime($t['end']); - if ($from >= $start && $to <= $end && $t['unit_type'] == $type) { - $tariff = floatval($t['price']) / 100.0; - } + $values = @AC_GetLoggedValues($archiveID, $varId, $timestamp - 3600, $timestamp + 3600, 1); + if ($values && count($values) > 0) { + return floatval($values[0]['Value']); } - return $tariff; + return floatval(GetValue($varId)); } }