// /opt/erp-system/app/billing/[customerId]/page.tsx 'use client'; import { useState, useEffect } from 'react'; import { useParams, useRouter } from 'next/navigation'; import { ArrowLeft, Printer } from 'lucide-react'; import { jsPDF } from 'jspdf'; import autoTable from 'jspdf-autotable'; export default function InvoiceDraftPage() { const params = useParams(); const router = useRouter(); const customerId = params.customerId; const [entries, setEntries] = useState([]); const [customer, setCustomer] = useState(null); const [settings, setSettings] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { if (customerId) fetchData(); }, [customerId]); const fetchData = async () => { const [billingRes, settingsRes] = await Promise.all([ fetch('/api/billing'), fetch('/api/settings') ]); if (billingRes.ok && settingsRes.ok) { const allEntries = await billingRes.json(); const filtered = allEntries.filter((e: any) => e.ticket.customerId === parseInt(customerId as string)); setEntries(filtered); if (filtered.length > 0) setCustomer(filtered[0].ticket.customer); setSettings(await settingsRes.json()); } setLoading(false); }; const handleUpdateEntry = async (id: number, field: string, value: any) => { const updatedEntries = entries.map(e => e.id === id ? { ...e, [field]: value } : e); setEntries(updatedEntries); const entry = updatedEntries.find(e => e.id === id); await fetch(`/api/time-entries/${id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ description: entry.description, durationMins: entry.durationMins }) }); }; const generatePDF = () => { const doc = new jsPDF(); const dateStr = new Date().toLocaleDateString('de-DE'); const invNo = `RE-${new Date().getFullYear()}-${Math.floor(1000 + Math.random() * 9000)}`; doc.setFontSize(20); doc.text(settings.companyName || "ERP SYSTEM", 14, 20); doc.setFontSize(9); doc.text(settings.companyInfo || "", 14, 30); doc.setFontSize(11); doc.text("Rechnung an:", 14, 55); doc.setFont("helvetica", "bold"); doc.text(customer.companyName || `${customer.firstName} ${customer.lastName}`, 14, 62); doc.setFont("helvetica", "normal"); doc.text(`${customer.address || ''}\n${customer.zipCode || ''} ${customer.city || ''}`, 14, 68); doc.text(`Datum: ${dateStr}`, 140, 62); doc.text(`Rechnungs-Nr: ${invNo}`, 140, 68); const tableData = entries.map(e => [ new Date(e.createdAt).toLocaleDateString('de-DE'), `${e.ticket.title}\n${e.description}`, (e.durationMins / 60).toFixed(2) + " h", settings.hourlyRate.toFixed(2) + " €", ((e.durationMins / 60) * settings.hourlyRate).toFixed(2) + " €" ]); autoTable(doc, { startY: 90, head: [['Datum', 'Leistung', 'Menge', 'Einzelpreis', 'Gesamt']], body: tableData, theme: 'striped', headStyles: { fillColor: [79, 70, 229] } }); const netTotal = entries.reduce((sum, e) => sum + (e.durationMins / 60 * settings.hourlyRate), 0); const tax = netTotal * (settings.taxRate / 100); const grossTotal = netTotal + tax; const finalY = (doc as any).lastAutoTable.finalY + 10; doc.text(`Netto Gesamt:`, 140, finalY); doc.text(`${netTotal.toFixed(2)} €`, 180, finalY, { align: 'right' }); doc.text(`USt. ${settings.taxRate}%:`, 140, finalY + 6); doc.text(`${tax.toFixed(2)} €`, 180, finalY + 6, { align: 'right' }); doc.setFont("helvetica", "bold"); doc.text(`Rechnungsbetrag:`, 140, finalY + 14); doc.text(`${grossTotal.toFixed(2)} €`, 180, finalY + 14, { align: 'right' }); doc.save(`Rechnung_${invNo}.pdf`); }; if (loading) return
Lade Entwurf...
; return (

Rechnung korrigieren

{entries.map((entry) => (
Beschreibung Minuten Betrag