import prisma from '../lib/prisma.js'; import fs from 'fs'; import path from 'path'; import { assertValidDocumentPath } from '../utils/sanitize.js'; /** * Vollmachten für einen Kunden abrufen (wer darf diesen Kunden einsehen?) */ export async function getAuthorizationsForCustomer(customerId: number) { return prisma.representativeAuthorization.findMany({ where: { customerId }, include: { representative: { select: { id: true, customerNumber: true, firstName: true, lastName: true }, }, }, orderBy: { createdAt: 'desc' }, }); } /** * Vollmachten die ein Vertreter erhalten hat (welche Kunden darf er einsehen?) */ export async function getAuthorizationsForRepresentative(representativeId: number) { return prisma.representativeAuthorization.findMany({ where: { representativeId }, include: { customer: { select: { id: true, customerNumber: true, firstName: true, lastName: true }, }, }, orderBy: { createdAt: 'desc' }, }); } /** * Prüft ob ein Vertreter eine Vollmacht für einen Kunden hat */ export async function hasAuthorization(customerId: number, representativeId: number): Promise { const auth = await prisma.representativeAuthorization.findUnique({ where: { customerId_representativeId: { customerId, representativeId }, }, }); return auth?.isGranted === true; } /** * Vollmacht erteilen oder aktualisieren */ export async function grantAuthorization( customerId: number, representativeId: number, data: { source?: string; documentPath?: string; notes?: string } ) { // Pentest 26.7 (Defense-in-Depth): documentPath nur als /uploads/. assertValidDocumentPath(data.documentPath, 'documentPath'); return prisma.representativeAuthorization.upsert({ where: { customerId_representativeId: { customerId, representativeId }, }, update: { isGranted: true, grantedAt: new Date(), withdrawnAt: null, source: data.source, documentPath: data.documentPath ?? undefined, notes: data.notes ?? undefined, }, create: { customerId, representativeId, isGranted: true, grantedAt: new Date(), source: data.source || 'crm-backend', documentPath: data.documentPath, notes: data.notes, }, }); } /** * Vollmacht widerrufen + PDF löschen falls vorhanden */ export async function withdrawAuthorization(customerId: number, representativeId: number) { // Erst prüfen ob eine PDF vorhanden ist const existing = await prisma.representativeAuthorization.findUnique({ where: { customerId_representativeId: { customerId, representativeId } }, select: { documentPath: true }, }); // PDF vom Filesystem löschen if (existing?.documentPath) { try { const filePath = path.join(process.cwd(), existing.documentPath); if (fs.existsSync(filePath)) { fs.unlinkSync(filePath); } } catch (err) { console.error('Fehler beim Löschen der Vollmacht-PDF:', err); } } return prisma.representativeAuthorization.update({ where: { customerId_representativeId: { customerId, representativeId }, }, data: { isGranted: false, withdrawnAt: new Date(), documentPath: null, }, }); } /** * Vollmacht-Dokument (PDF) hochladen */ export async function updateAuthorizationDocument( customerId: number, representativeId: number, documentPath: string ) { // Wenn Dokument hochgeladen wird, gilt das als Vollmacht erteilen return prisma.representativeAuthorization.upsert({ where: { customerId_representativeId: { customerId, representativeId }, }, update: { documentPath, isGranted: true, grantedAt: new Date(), withdrawnAt: null, source: 'papier', }, create: { customerId, representativeId, documentPath, isGranted: true, grantedAt: new Date(), source: 'papier', }, }); } /** * Vollmacht-Dokument löschen */ export async function deleteAuthorizationDocument(customerId: number, representativeId: number) { // Prüfen ob die Vollmacht per Papier erteilt wurde const auth = await prisma.representativeAuthorization.findUnique({ where: { customerId_representativeId: { customerId, representativeId } }, select: { source: true, documentPath: true }, }); if (!auth) throw new Error('Vollmacht nicht gefunden'); // Datei löschen if (auth.documentPath) { try { const filePath = path.join(process.cwd(), auth.documentPath); if (fs.existsSync(filePath)) { fs.unlinkSync(filePath); } } catch (err) { console.error('Fehler beim Löschen der Vollmacht-PDF:', err); } } // Wenn per Papier erteilt → Vollmacht widerrufen // Wenn per Portal/Online erteilt → nur PDF entfernen, Vollmacht bleibt const withdrawData = auth.source === 'papier' ? { documentPath: null, isGranted: false, withdrawnAt: new Date() } : { documentPath: null }; return prisma.representativeAuthorization.update({ where: { customerId_representativeId: { customerId, representativeId } }, data: withdrawData, }); } /** * Alle genehmigten Vertreter-IDs für einen Kunden * (Welche Vertreter dürfen die Verträge dieses Kunden sehen?) */ export async function getAuthorizedRepresentativeIds(customerId: number): Promise { const auths = await prisma.representativeAuthorization.findMany({ where: { customerId, isGranted: true }, select: { representativeId: true }, }); return auths.map((a) => a.representativeId); } /** * Alle Kunden-IDs für die ein Vertreter eine Vollmacht hat */ export async function getAuthorizedCustomerIds(representativeId: number): Promise { const auths = await prisma.representativeAuthorization.findMany({ where: { representativeId, isGranted: true }, select: { customerId: true }, }); return auths.map((a) => a.customerId); } /** * Erstellt fehlende Vollmacht-Einträge für bestehende Vertreterbeziehungen * (wird aufgerufen wenn man den Tab aufruft) */ export async function ensureAuthorizationEntries(customerId: number) { // Alle aktiven Vertreter für diesen Kunden const representatives = await prisma.customerRepresentative.findMany({ where: { customerId, isActive: true }, select: { representativeId: true }, }); for (const rep of representatives) { // Erstelle Eintrag falls nicht vorhanden await prisma.representativeAuthorization.upsert({ where: { customerId_representativeId: { customerId, representativeId: rep.representativeId }, }, update: {}, // Nichts ändern wenn schon vorhanden create: { customerId, representativeId: rep.representativeId, isGranted: false, }, }); } }