From 2ee06630b93c1f1ed2b0f785b52ac7ed18db5dbc Mon Sep 17 00:00:00 2001 From: duffyduck Date: Sat, 30 May 2026 14:39:05 +0200 Subject: [PATCH] =?UTF-8?q?Folgez=C3=A4hler-Forms:=20Checkbox=20"Alten=20Z?= =?UTF-8?q?=C3=A4hler=20deaktivieren"=20(default=20an)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Beide Folgezähler-Forms (Kundenakte MeterModal + Vertragsansicht SuccessorMeterForm) bekommen eine Checkbox, die standardmäßig angehakt ist. Beim Speichern wird der Vorgänger automatisch auf isActive=false gesetzt – ein-klick-fähiger Zählerwechsel. Backend: createMeter mit successorOf und addSuccessorMeter akzeptieren deactivatePredecessor (Default true). Co-Authored-By: Claude Opus 4.7 (1M context) --- backend/src/controllers/contract.controller.ts | 11 ++++++++++- backend/src/services/customer.service.ts | 14 ++++++++++++++ frontend/src/pages/contracts/ContractDetail.tsx | 14 +++++++++++++- frontend/src/pages/customers/CustomerDetail.tsx | 11 +++++++++++ frontend/src/services/api.ts | 2 +- 5 files changed, 49 insertions(+), 3 deletions(-) diff --git a/backend/src/controllers/contract.controller.ts b/backend/src/controllers/contract.controller.ts index 17fa3247..730b58c5 100644 --- a/backend/src/controllers/contract.controller.ts +++ b/backend/src/controllers/contract.controller.ts @@ -539,7 +539,7 @@ export async function getCockpit(req: AuthRequest, res: Response): Promise export async function addSuccessorMeter(req: AuthRequest, res: Response): Promise { try { const contractId = parseInt(req.params.id); - const { meterId, installedAt, finalReadingPrevious } = req.body; + const { meterId, installedAt, finalReadingPrevious, deactivatePredecessor } = req.body; const contract = await prisma.contract.findUnique({ where: { id: contractId }, @@ -648,6 +648,15 @@ export async function addSuccessorMeter(req: AuthRequest, res: Response): Promis ); } + // Alten Zähler deaktivieren (Default), sofern der Aufrufer das nicht + // explizit auf false setzt – ein-klick-fähiger Zählerwechsel. + if (predecessorMeterId && deactivatePredecessor !== false) { + await prisma.meter.update({ + where: { id: predecessorMeterId }, + data: { isActive: false }, + }); + } + await logChange({ req, action: 'CREATE', resourceType: 'ContractMeter', resourceId: contractMeter.id.toString(), diff --git a/backend/src/services/customer.service.ts b/backend/src/services/customer.service.ts index 5868e7f4..918f02d5 100644 --- a/backend/src/services/customer.service.ts +++ b/backend/src/services/customer.service.ts @@ -488,6 +488,10 @@ export async function createMeter( predecessorMeterId: number; installedAt?: string; finalReadingPrevious?: number; + // Default true im UI: alter Zähler wird nach dem Wechsel auf + // isActive=false gesetzt. Kann ausgeschaltet werden, wenn der alte + // Zähler aus irgendeinem Grund noch aktiv bleiben soll. + deactivatePredecessor?: boolean; }; } ) { @@ -622,6 +626,16 @@ export async function createMeter( data.successorOf.finalReadingPrevious, ); } + + // Alten Zähler deaktivieren (Default), sofern der Aufrufer das nicht + // explizit auf false setzt. Macht den typischen Zählerwechsel-Workflow + // ein-klick-fähig. + if (data.successorOf.deactivatePredecessor !== false) { + await prisma.meter.update({ + where: { id: predecessor.id }, + data: { isActive: false }, + }); + } } return created; diff --git a/frontend/src/pages/contracts/ContractDetail.tsx b/frontend/src/pages/contracts/ContractDetail.tsx index 10fa9995..ed90726f 100644 --- a/frontend/src/pages/contracts/ContractDetail.tsx +++ b/frontend/src/pages/contracts/ContractDetail.tsx @@ -361,6 +361,7 @@ function SuccessorMeterButton({ const [selectedMeterId, setSelectedMeterId] = useState(''); const [installedAt, setInstalledAt] = useState(new Date().toISOString().split('T')[0]); const [finalReading, setFinalReading] = useState(''); + const [deactivatePredecessor, setDeactivatePredecessor] = useState(true); const queryClient = useQueryClient(); const { data: metersData } = useQuery({ @@ -370,13 +371,14 @@ function SuccessorMeterButton({ }); const addMutation = useMutation({ - mutationFn: (data: { meterId: number; installedAt?: string; finalReadingPrevious?: number }) => + mutationFn: (data: { meterId: number; installedAt?: string; finalReadingPrevious?: number; deactivatePredecessor?: boolean }) => contractApi.addSuccessorMeter(contractId, data), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['contract'] }); setShowForm(false); setSelectedMeterId(''); setFinalReading(''); + setDeactivatePredecessor(true); }, }); @@ -451,6 +453,15 @@ function SuccessorMeterButton({ erfasst und fließt damit in die Verbrauchsberechnung ein.

)} +