import { prisma } from './prisma'; import { sendInitialBookingEmail } from './email-service'; import { nextcloudCalendar } from './nextcloud-calendar'; import { lexofficeService } from './lexoffice'; import { generateContractFromTemplate } from './pdf-template-service'; export class BookingAutomationService { async runPostBookingActions(bookingId: string): Promise<{ emailSent: boolean; calendarSynced: boolean; lexofficeCreated: boolean; contractGenerated: boolean; errors: string[]; }> { const errors: string[] = []; let emailSent = false; let calendarSynced = false; let lexofficeCreated = false; let contractGenerated = false; try { const booking = await prisma.booking.findUnique({ where: { id: bookingId }, include: { location: true, photobox: true, bookingEquipment: { include: { equipment: true, }, }, }, }); if (!booking) { errors.push('Buchung nicht gefunden'); return { emailSent, calendarSynced, lexofficeCreated, contractGenerated, errors }; } let priceConfig = null; if (booking.photobox?.model && booking.locationId) { priceConfig = await prisma.priceConfig.findUnique({ where: { locationId_model: { locationId: booking.locationId, model: booking.photobox.model, }, }, }); } const bookingWithPriceConfig = { ...booking, priceConfig, }; console.log(`πŸ€– Automatische Aktionen fΓΌr Buchung ${booking.bookingNumber}...`); let quotationPdf: Buffer | null = null; let contractPdf: Buffer | null = null; // 1. LexOffice Contact + Quotation erstellen try { console.log(' πŸ’Ό Erstelle LexOffice-Kontakt und Angebot...'); const contactId = await lexofficeService.createContactFromBooking(bookingWithPriceConfig); console.log(` βœ… LexOffice-Kontakt erstellt: ${contactId}`); const quotationId = await lexofficeService.createQuotationFromBooking(bookingWithPriceConfig, contactId); console.log(` βœ… LexOffice-Angebot erstellt: ${quotationId}`); await prisma.booking.update({ where: { id: booking.id }, data: { lexofficeContactId: contactId, lexofficeOfferId: quotationId, }, }); quotationPdf = await lexofficeService.getQuotationPDF(quotationId); console.log(' βœ… Angebots-PDF heruntergeladen'); lexofficeCreated = true; } catch (error: any) { console.error(' ❌ LexOffice Fehler:', error.message); errors.push(`LexOffice: ${error.message}`); } // 2. Mietvertrag-PDF generieren try { console.log(' πŸ“„ Generiere Mietvertrag-PDF...'); contractPdf = await generateContractFromTemplate( bookingWithPriceConfig, booking.location, booking.photobox ); await prisma.booking.update({ where: { id: booking.id }, data: { contractGenerated: true, contractGeneratedAt: new Date(), }, }); console.log(' βœ… Mietvertrag-PDF generiert'); contractGenerated = true; } catch (error: any) { console.error(' ❌ PDF-Generierung Fehler:', error.message); errors.push(`PDF: ${error.message}`); } // 3. E-Mail mit Angebot + Vertrag versenden if (quotationPdf && contractPdf) { try { console.log(' πŸ“§ Sende E-Mail mit Angebot und Vertrag...'); await sendInitialBookingEmail(bookingWithPriceConfig, quotationPdf, contractPdf); await prisma.booking.update({ where: { id: booking.id }, data: { contractSentAt: new Date(), }, }); emailSent = true; console.log(' βœ… E-Mail gesendet'); } catch (error: any) { console.error(' ❌ E-Mail Fehler:', error.message); errors.push(`E-Mail: ${error.message}`); } } else { console.warn(' ⚠️ E-Mail nicht gesendet - PDFs fehlen'); errors.push('E-Mail: PDFs nicht verfΓΌgbar'); } // 4. Automatischer Nextcloud Kalender-Sync try { console.log(' πŸ“… Synchronisiere mit Nextcloud-Kalender...'); await nextcloudCalendar.syncBookingToCalendar(booking); await prisma.booking.update({ where: { id: booking.id }, data: { calendarSynced: true, calendarSyncedAt: new Date(), }, }); calendarSynced = true; console.log(' βœ… Kalender synchronisiert'); } catch (error: any) { console.error(' ❌ Kalender-Sync Fehler:', error.message); errors.push(`Kalender: ${error.message}`); } // 5. Admin-Benachrichtigung erstellen try { await prisma.notification.create({ data: { type: 'NEW_BOOKING', title: 'Neue Buchungsanfrage', message: `${booking.customerName} hat eine ${booking.photobox?.model || 'Fotobox'} fΓΌr ${booking.eventCity} am ${new Date(booking.eventDate).toLocaleDateString('de-DE')} angefragt.`, metadata: { bookingId: booking.id, bookingNumber: booking.bookingNumber, }, }, }); console.log(' βœ… Admin-Benachrichtigung erstellt'); } catch (error: any) { console.error(' ❌ Notification Fehler:', error.message); } console.log(`βœ… Automatische Aktionen abgeschlossen (${errors.length} Fehler)`); return { emailSent, calendarSynced, lexofficeCreated, contractGenerated, errors }; } catch (error: any) { console.error('❌ Booking Automation Fehler:', error); errors.push(error.message); return { emailSent, calendarSynced, lexofficeCreated, contractGenerated, errors }; } } } export const bookingAutomationService = new BookingAutomationService();