import { config } from '../config.js' import { createAppwriteUser, createDocument, deleteDocument, getCustomerByEmail, getDocument, getPortalAccessByCustomerId, listDocuments, updateAppwriteUserEmail, updateAppwriteUserPassword, deleteAppwriteUser, updateDocument, Query, } from './appwriteAdmin.js' function readPortalPassword(customer) { if (customer?.portalPassword) return customer.portalPassword // Fallback: Altbestand, bei dem das Passwort noch in den Notizen lag const notes = customer?.notes || '' const match = notes.match(/^__portalPassword__:([^\n]+)/) return match ? match[1] : '' } function notesWithoutPortalPassword(notes) { return (notes || '').replace(/^__portalPassword__:[^\n]*\n?/, '').trim() } function sanitizeCustomer(customer, { portalPassword } = {}) { const storedPassword = portalPassword || readPortalPassword(customer) return { $id: customer.$id, code: customer.code || '', name: customer.name || '', location: customer.location || '', email: customer.email || '', phone: customer.phone || '', companyName: customer.companyName || '', portalAccessEnabled: Boolean(customer.portalAccessEnabled), appwriteUserId: customer.appwriteUserId || '', customerStatus: customer.customerStatus || '', archived: Boolean(customer.archived), portalPassword: storedPassword || '', } } async function ensurePortalAccess(customerId, appwriteUserId) { const now = new Date().toISOString() let portalAccess = await getPortalAccessByCustomerId(customerId) if (portalAccess) { portalAccess = await updateDocument(config.collections.customerPortalAccess, portalAccess.$id, { enabled: true, appwriteUserId, passwordSet: true, }) } else { portalAccess = await createDocument(config.collections.customerPortalAccess, { customerId, enabled: true, appwriteUserId, passwordSet: true, }) } return portalAccess } export async function createCustomerWithPortalAccess(payload) { const { code = '', name, location = '', email, phone = '', password, } = payload || {} if (!name?.trim()) { const error = new Error('Name ist erforderlich') error.status = 400 throw error } if (!email?.trim()) { const error = new Error('E-Mail ist erforderlich') error.status = 400 throw error } if (!password || password.length < 8) { const error = new Error('Passwort muss mindestens 8 Zeichen haben') error.status = 400 throw error } const existing = await getCustomerByEmail(email.trim()) if (existing) { const error = new Error('Ein Kunde mit dieser E-Mail existiert bereits') error.status = 409 throw error } const appwriteUser = await createAppwriteUser({ email: email.trim(), password, name: name.trim(), }) const now = new Date().toISOString() let customer try { customer = await createDocument(config.collections.customers, { code: code.trim(), name: name.trim(), location: location.trim(), email: email.trim(), phone: phone.trim(), portalPassword: password, portalAccessEnabled: true, appwriteUserId: appwriteUser.$id, customerStatus: 'active', createdAt: now, updatedAt: now, }) await ensurePortalAccess(customer.$id, appwriteUser.$id) } catch (err) { try { await deleteAppwriteUser(appwriteUser.$id) } catch { /* ignore rollback failure */ } throw err } return { customer: sanitizeCustomer(customer, { portalPassword: password }), } } export async function updateCustomerWithPortalAccess(customerId, payload) { const customer = await getDocument(config.collections.customers, customerId).catch(() => null) if (!customer) { const error = new Error('Kunde nicht gefunden') error.status = 404 throw error } const { code, name, location, email, phone, password, } = payload || {} const nextEmail = (email ?? customer.email ?? '').trim() if (!nextEmail) { const error = new Error('E-Mail ist erforderlich') error.status = 400 throw error } if (password && password.length < 8) { const error = new Error('Passwort muss mindestens 8 Zeichen haben') error.status = 400 throw error } const normalizedPassword = typeof password === 'string' && password.trim().length > 0 ? password : undefined if (nextEmail.toLowerCase() !== (customer.email || '').trim().toLowerCase()) { const existing = await getCustomerByEmail(nextEmail) if (existing && existing.$id !== customerId) { const error = new Error('Ein anderer Kunde nutzt diese E-Mail bereits') error.status = 409 throw error } } let appwriteUserId = customer.appwriteUserId || '' let portalPassword if (!appwriteUserId && nextEmail && normalizedPassword) { const appwriteUser = await createAppwriteUser({ email: nextEmail, password: normalizedPassword, name: (name ?? customer.name ?? nextEmail).trim(), }) appwriteUserId = appwriteUser.$id portalPassword = normalizedPassword } else if (appwriteUserId) { if (nextEmail && nextEmail !== customer.email) { await updateAppwriteUserEmail(appwriteUserId, nextEmail) } if (normalizedPassword) { await updateAppwriteUserPassword(appwriteUserId, normalizedPassword) portalPassword = normalizedPassword } } else if (normalizedPassword) { const error = new Error('Portal-Login fehlt � bitte E-Mail setzen und Passwort erneut speichern') error.status = 400 throw error } const now = new Date().toISOString() const nextPortalPassword = normalizedPassword || readPortalPassword(customer) || undefined // Legacy-Prefix aus den Notizen entfernen, Passwort liegt jetzt im eigenen Feld const cleanedNotes = notesWithoutPortalPassword(customer.notes) const notesChanged = cleanedNotes !== (customer.notes || '') const updated = await updateDocument(config.collections.customers, customerId, { ...(code !== undefined ? { code: String(code).trim() } : {}), ...(name !== undefined ? { name: String(name).trim() } : {}), ...(location !== undefined ? { location: String(location).trim() } : {}), email: nextEmail, ...(phone !== undefined ? { phone: String(phone).trim() } : {}), ...(nextPortalPassword ? { portalPassword: nextPortalPassword } : {}), ...(notesChanged ? { notes: cleanedNotes } : {}), // CRM-Stufe (lead/customer/lost) nicht ueberschreiben - nur setzen, wenn leer ...(appwriteUserId ? { appwriteUserId, portalAccessEnabled: true, ...(customer.customerStatus ? {} : { customerStatus: 'active' }), } : {}), updatedAt: now, }) if (appwriteUserId) { await ensurePortalAccess(customerId, appwriteUserId) } return { customer: sanitizeCustomer(updated, portalPassword ? { portalPassword } : {}), } } export async function listCustomersForAdmin() { const customers = await listDocuments(config.collections.customers, [Query.orderAsc('name')]) return customers.map((customer) => sanitizeCustomer(customer)) } export async function deleteCustomerWithPortalAccess(customerId) { const customer = await getDocument(config.collections.customers, customerId) .catch(() => null) if (!customer) { const error = new Error('Kunde nicht gefunden') error.status = 404 throw error } const portalAccess = await getPortalAccessByCustomerId(customerId) if (portalAccess) { await deleteDocument( config.collections.customerPortalAccess, portalAccess.$id ) } await deleteDocument(config.collections.customers, customerId) if (customer.appwriteUserId) { await deleteAppwriteUser(customer.appwriteUserId).catch(() => {}) } return { success: true } }