import { Request, Response } from 'express'; import { PrismaClient } from '@prisma/client'; import * as contractService from '../services/contract.service.js'; import * as contractCockpitService from '../services/contractCockpit.service.js'; import * as contractHistoryService from '../services/contractHistory.service.js'; import { ApiResponse, AuthRequest } from '../types/index.js'; const prisma = new PrismaClient(); export async function getContracts(req: AuthRequest, res: Response): Promise { try { const { customerId, type, status, search, page, limit, tree } = req.query; // Baumstruktur für Kundenansicht if (tree === 'true' && customerId) { const treeData = await contractService.getContractTreeForCustomer( parseInt(customerId as string) ); res.json({ success: true, data: treeData } as ApiResponse); return; } // Für Kundenportal-Benutzer: nur eigene + vertretene Kunden-Verträge anzeigen let customerIds: number[] | undefined; if (req.user?.isCustomerPortal && req.user.customerId) { // Eigene Customer-ID + alle vertretenen Kunden-IDs customerIds = [req.user.customerId, ...(req.user.representedCustomerIds || [])]; } const result = await contractService.getAllContracts({ customerId: customerId ? parseInt(customerId as string) : undefined, customerIds, // Wird nur für Kundenportal-Benutzer gesetzt type: type as any, status: status as any, search: search as string, page: page ? parseInt(page as string) : undefined, limit: limit ? parseInt(limit as string) : undefined, }); res.json({ success: true, data: result.contracts, pagination: result.pagination, } as ApiResponse); } catch (error) { res.status(500).json({ success: false, error: 'Fehler beim Laden der Verträge', } as ApiResponse); } } export async function getContract(req: AuthRequest, res: Response): Promise { try { const contract = await contractService.getContractById(parseInt(req.params.id)); if (!contract) { res.status(404).json({ success: false, error: 'Vertrag nicht gefunden', } as ApiResponse); return; } // Für Kundenportal-Benutzer: Zugriff nur auf eigene + vertretene Kunden-Verträge if (req.user?.isCustomerPortal && req.user.customerId) { const allowedCustomerIds = [req.user.customerId, ...(req.user.representedCustomerIds || [])]; if (!allowedCustomerIds.includes(contract.customerId)) { res.status(403).json({ success: false, error: 'Kein Zugriff auf diesen Vertrag', } as ApiResponse); return; } } res.json({ success: true, data: contract } as ApiResponse); } catch (error) { res.status(500).json({ success: false, error: 'Fehler beim Laden des Vertrags', } as ApiResponse); } } export async function createContract(req: Request, res: Response): Promise { try { const contract = await contractService.createContract(req.body); res.status(201).json({ success: true, data: contract } as ApiResponse); } catch (error) { res.status(400).json({ success: false, error: error instanceof Error ? error.message : 'Fehler beim Erstellen des Vertrags', } as ApiResponse); } } export async function updateContract(req: Request, res: Response): Promise { try { const contract = await contractService.updateContract(parseInt(req.params.id), req.body); res.json({ success: true, data: contract } as ApiResponse); } catch (error) { res.status(400).json({ success: false, error: error instanceof Error ? error.message : 'Fehler beim Aktualisieren des Vertrags', } as ApiResponse); } } export async function deleteContract(req: Request, res: Response): Promise { try { await contractService.deleteContract(parseInt(req.params.id)); res.json({ success: true, message: 'Vertrag gelöscht' } as ApiResponse); } catch (error) { res.status(400).json({ success: false, error: error instanceof Error ? error.message : 'Fehler beim Löschen des Vertrags', } as ApiResponse); } } export async function createFollowUp(req: AuthRequest, res: Response): Promise { try { const previousContractId = parseInt(req.params.id); // Vorgängervertrag laden für Vertragsnummer const previousContract = await prisma.contract.findUnique({ where: { id: previousContractId }, select: { contractNumber: true }, }); if (!previousContract) { res.status(404).json({ success: false, error: 'Vorgängervertrag nicht gefunden' } as ApiResponse); return; } const contract = await contractService.createFollowUpContract(previousContractId); const createdBy = req.user?.email || 'unbekannt'; // Historie-Eintrag für den Vorgängervertrag erstellen await contractHistoryService.createFollowUpHistoryEntry( previousContractId, contract.contractNumber, createdBy ); // Historie-Eintrag für den neuen Folgevertrag erstellen await contractHistoryService.createNewContractFromPredecessorEntry( contract.id, previousContract.contractNumber, createdBy ); res.status(201).json({ success: true, data: contract } as ApiResponse); } catch (error) { res.status(400).json({ success: false, error: error instanceof Error ? error.message : 'Fehler beim Erstellen des Folgevertrags', } as ApiResponse); } } export async function getContractPassword(req: Request, res: Response): Promise { try { const password = await contractService.getContractPassword(parseInt(req.params.id)); if (password === null) { res.status(404).json({ success: false, error: 'Kein Passwort hinterlegt', } as ApiResponse); return; } res.json({ success: true, data: { password } } as ApiResponse); } catch (error) { res.status(500).json({ success: false, error: 'Fehler beim Entschlüsseln des Passworts', } as ApiResponse); } } export async function getSimCardCredentials(req: Request, res: Response): Promise { try { const credentials = await contractService.getSimCardCredentials(parseInt(req.params.simCardId)); res.json({ success: true, data: credentials } as ApiResponse); } catch (error) { res.status(500).json({ success: false, error: 'Fehler beim Entschlüsseln der SIM-Karten-Daten', } as ApiResponse); } } export async function getInternetCredentials(req: Request, res: Response): Promise { try { const credentials = await contractService.getInternetCredentials(parseInt(req.params.id)); res.json({ success: true, data: credentials } as ApiResponse); } catch (error) { res.status(500).json({ success: false, error: 'Fehler beim Entschlüsseln des Internet-Passworts', } as ApiResponse); } } export async function getSipCredentials(req: Request, res: Response): Promise { try { const credentials = await contractService.getSipCredentials(parseInt(req.params.phoneNumberId)); res.json({ success: true, data: credentials } as ApiResponse); } catch (error) { res.status(500).json({ success: false, error: 'Fehler beim Entschlüsseln des SIP-Passworts', } as ApiResponse); } } // ==================== VERTRAGS-COCKPIT ==================== export async function getCockpit(req: AuthRequest, res: Response): Promise { try { const cockpitData = await contractCockpitService.getCockpitData(); res.json({ success: true, data: cockpitData } as ApiResponse); } catch (error) { console.error('Cockpit error:', error); res.status(500).json({ success: false, error: 'Fehler beim Laden des Vertrags-Cockpits', } as ApiResponse); } } // ==================== SNOOZE (VERTRAG ZURÜCKSTELLEN) ==================== export async function snoozeContract(req: Request, res: Response): Promise { try { const id = parseInt(req.params.id); const { nextReviewDate, months } = req.body; let reviewDate: Date | null = null; if (nextReviewDate) { // Explizites Datum angegeben reviewDate = new Date(nextReviewDate); } else if (months) { // Monate angegeben → berechne Datum reviewDate = new Date(); reviewDate.setMonth(reviewDate.getMonth() + months); } // Wenn beides leer → nextReviewDate wird auf null gesetzt (Snooze aufheben) const updated = await prisma.contract.update({ where: { id }, data: { nextReviewDate: reviewDate }, select: { id: true, contractNumber: true, nextReviewDate: true, }, }); res.json({ success: true, data: updated, message: reviewDate ? `Vertrag zurückgestellt bis ${reviewDate.toLocaleDateString('de-DE')}` : 'Zurückstellung aufgehoben', } as ApiResponse); } catch (error) { console.error('Snooze error:', error); res.status(500).json({ success: false, error: 'Fehler beim Zurückstellen des Vertrags', } as ApiResponse); } }