From 43aaf697a16bf8917097b190acc390e32e02f0c3 Mon Sep 17 00:00:00 2001 From: duffyduck Date: Sat, 30 May 2026 15:07:19 +0200 Subject: [PATCH] Fix: Multi-Meter-Verbrauch auf Vertragslaufzeit clampen MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bei Verträgen, die Vorgänger einer Folgevertrags-Kette sind, sind über ContractMeter auch Folgezähler verknüpft, die nach Vertragsende installiert wurden. Die Berechnung nahm cm.installedAt..cm.removedAt 1:1 ohne Clamp gegen Contract.startDate/endDate – damit flossen Zählerstände aus der Folgevertrags-Phase in den Verbrauch dieses Vertrags ein. Fix: meterStart = max(installedAt, contractStart), meterEnd = min(removedAt, contractEnd). Zähler komplett außerhalb der Laufzeit werden übersprungen. Co-Authored-By: Claude Opus 4.7 (1M context) --- frontend/src/utils/energyCalculations.ts | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/frontend/src/utils/energyCalculations.ts b/frontend/src/utils/energyCalculations.ts index e8034fd0..3ec1b5c7 100644 --- a/frontend/src/utils/energyCalculations.ts +++ b/frontend/src/utils/energyCalculations.ts @@ -262,13 +262,24 @@ export function calculateMultiMeterConsumption( let firstStart: MeterReading | undefined; let lastEnd: MeterReading | undefined; + const contractStartMs = new Date(startDate).getTime(); + const contractEndMs = new Date(endDate).getTime(); + for (const cm of contractMeters) { const readings = cm.meter?.readings || []; if (readings.length === 0) continue; - // Zeitraum für diesen Zähler bestimmen - const meterStart = cm.installedAt || startDate; - const meterEnd = cm.removedAt || endDate; + // Zeitraum für diesen Zähler bestimmen, GE-CLAMPED auf die Vertragslaufzeit. + // Ohne Clamp würden Folgezähler, die nach Vertragsende installiert wurden + // (typisch bei Vorgängerverträgen einer Folgevertrags-Kette), zukünftige + // Zählerstände in den Verbrauch dieses Vertrags einrechnen. + const installedMs = cm.installedAt ? new Date(cm.installedAt).getTime() : contractStartMs; + const removedMs = cm.removedAt ? new Date(cm.removedAt).getTime() : contractEndMs; + const meterStartMs = Math.max(installedMs, contractStartMs); + const meterEndMs = Math.min(removedMs, contractEndMs); + if (meterStartMs > meterEndMs) continue; // Zähler liegt komplett außerhalb der Laufzeit + const meterStart = new Date(meterStartMs).toISOString(); + const meterEnd = new Date(meterEndMs).toISOString(); const result = calculateConsumption(readings, meterStart, meterEnd, contractType);