feat: Equipment-System, Buchungsbearbeitung, Kundenadresse, LexOffice-Fix

- Vintage Modell hinzugefuegt
- Equipment Multi-Select (Neue Buchung + Bearbeitung)
- Kundenadresse in Formularen
- Bearbeiten-Seite fuer Buchungen
- Abbau-Zeiten in Formularen und Uebersicht
- Vertrag PDF nur bei Privatkunden
- LexOffice Kontakt-Erstellung Fix (BUSINESS)
- Zurueck-Pfeil auf Touren-Seite
This commit is contained in:
Julia Wehden
2026-03-19 16:21:55 +01:00
parent 0b6e429329
commit a2c95c70e7
79 changed files with 7396 additions and 538 deletions

View File

@@ -13,19 +13,46 @@ export interface CalendarEvent {
export class NextcloudCalendarService {
private client: any;
private initialized: boolean = false;
private initPromise: Promise<void> | null = null;
async initialize() {
if (this.initialized) return;
// Wenn bereits am Initialisieren, warte auf Abschluss
if (this.initPromise) {
return this.initPromise;
}
// Wenn bereits initialisiert, fertig
if (this.initialized && this.client) {
return Promise.resolve();
}
// Neue Initialisierung starten
this.initPromise = this._doInitialize();
try {
await this.initPromise;
} finally {
this.initPromise = null;
}
}
private async _doInitialize() {
const serverUrl = process.env.NEXTCLOUD_URL;
const username = process.env.NEXTCLOUD_USERNAME;
const password = process.env.NEXTCLOUD_PASSWORD;
console.log('🔍 Nextcloud credentials check:');
console.log(' URL:', serverUrl);
console.log(' Username:', username);
console.log(' Password length:', password?.length, 'chars');
if (!serverUrl || !username || !password) {
throw new Error('Nextcloud credentials not configured');
}
try {
console.log('⏳ Creating Nextcloud CalDAV client...');
this.client = await createDAVClient({
serverUrl: `${serverUrl}/remote.php/dav`,
credentials: {
@@ -37,10 +64,12 @@ export class NextcloudCalendarService {
});
this.initialized = true;
console.log('✅ Nextcloud CalDAV client initialized');
} catch (error) {
console.log('✅ Nextcloud CalDAV client initialized successfully');
} catch (error: any) {
console.error('❌ Failed to initialize Nextcloud CalDAV client:', error);
throw error;
this.initialized = false;
this.client = null;
throw new Error(`Nextcloud initialization failed: ${error.message}`);
}
}
@@ -120,22 +149,33 @@ export class NextcloudCalendarService {
throw new Error('No calendars found in Nextcloud');
}
const calendar = calendars[0];
// Suche nach "Buchungen" Kalender, sonst verwende ersten
let calendar = calendars.find((cal: any) =>
cal.displayName?.toLowerCase().includes('buchung')
);
if (!calendar) {
console.warn('⚠️ Kein "Buchungen"-Kalender gefunden, verwende:', calendars[0].displayName);
calendar = calendars[0];
} else {
console.log('✅ Verwende Kalender:', calendar.displayName);
}
const event: CalendarEvent = {
uid: `savethemoment-booking-${booking.id}`,
summary: `${booking.customerName} - ${booking.location?.name || 'Unbekannt'}`,
description: `
Buchung #${booking.id}
Buchung #${booking.bookingNumber || booking.id}
Kunde: ${booking.customerName}
E-Mail: ${booking.customerEmail}
Telefon: ${booking.customerPhone || 'N/A'}
Event-Typ: ${booking.eventType}
Event-Location: ${booking.eventLocation || booking.eventAddress}
Status: ${booking.status}
Fotobox: ${booking.photobox?.name || 'Keine Box'}
Fotobox: ${booking.photobox?.model || 'Keine Box'}
Standort: ${booking.location?.name || 'Unbekannt'}
Preis: ${booking.calculatedPrice || 0}
`.trim(),
location: booking.location?.address || '',
location: `${booking.eventAddress || ''}, ${booking.eventZip || ''} ${booking.eventCity || ''}`.trim(),
startDate: new Date(booking.eventDate),
endDate: new Date(new Date(booking.eventDate).getTime() + 4 * 60 * 60 * 1000),
status: booking.status,
@@ -143,10 +183,12 @@ Standort: ${booking.location?.name || 'Unbekannt'}
try {
await this.createEvent(calendar.url, event);
console.log('✅ Event in Nextcloud erstellt:', event.summary);
return event;
} catch (error) {
} catch (error: any) {
if (error.message?.includes('already exists') || error.response?.status === 412) {
await this.updateEvent(calendar.url, event);
console.log('✅ Event in Nextcloud aktualisiert:', event.summary);
return event;
}
throw error;
@@ -162,11 +204,20 @@ Standort: ${booking.location?.name || 'Unbekannt'}
throw new Error('No calendars found in Nextcloud');
}
const calendar = calendars[0];
// Suche nach "Buchungen" Kalender, sonst verwende ersten
let calendar = calendars.find((cal: any) =>
cal.displayName?.toLowerCase().includes('buchung')
);
if (!calendar) {
calendar = calendars[0];
}
const eventUid = `savethemoment-booking-${bookingId}`;
try {
await this.deleteEvent(calendar.url, eventUid);
console.log('✅ Event aus Nextcloud gelöscht:', eventUid);
} catch (error) {
console.error('Error removing booking from calendar:', error);
}