Fix: Multi-Meter-Verbrauch auf Vertragslaufzeit clampen

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) <noreply@anthropic.com>
This commit is contained in:
2026-05-30 15:07:19 +02:00
parent b0e45c0ea0
commit 43aaf697a1
+14 -3
View File
@@ -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);