This commit is contained in:
2025-12-08 12:15:20 +01:00
parent 1d3bf94b88
commit 428a002e9f
7 changed files with 495 additions and 427 deletions

View File

@@ -1,43 +1,67 @@
// 🔧 Hilfsfunktionen
import {FastifyInstance} from "fastify";
import { FastifyInstance } from "fastify"
import { eq, ilike, and } from "drizzle-orm"
import { contacts, customers } from "../../db/schema"
// -------------------------------------------------------------
// Extract Domain
// -------------------------------------------------------------
export function extractDomain(email: string) {
if (!email) return null
const parts = email.split('@')
const parts = email.split("@")
return parts.length === 2 ? parts[1].toLowerCase() : null
}
export async function findCustomerOrContactByEmailOrDomain(server:FastifyInstance, fromMail: string, tenantId: number) {
// -------------------------------------------------------------
// Kunde oder Kontakt anhand E-Mail oder Domain finden
// -------------------------------------------------------------
export async function findCustomerOrContactByEmailOrDomain(
server: FastifyInstance,
fromMail: string,
tenantId: number
) {
const sender = fromMail.toLowerCase()
const senderDomain = extractDomain(sender)
if (!senderDomain) return null
// 1⃣ Direkter Match über contacts
const { data: contactMatch } = await server.supabase
.from('contacts')
.select('id, customer')
.eq('email', sender)
.eq('tenant', tenantId)
.maybeSingle()
// 1⃣ Direkter Match über Contacts (email)
const contactMatch = await server.db
.select({
id: contacts.id,
customer: contacts.customer,
})
.from(contacts)
.where(
and(
eq(contacts.email, sender),
eq(contacts.tenant, tenantId)
)
)
.limit(1)
if (contactMatch?.customer) {
return { customer: contactMatch.customer, contact: contactMatch.id }
if (contactMatch.length && contactMatch[0].customer) {
return {
customer: contactMatch[0].customer,
contact: contactMatch[0].id,
}
}
// 2⃣ Kunden nach Domain oder Rechnungs-E-Mail durchsuchen
const { data: customers, error } = await server.supabase
.from('customers')
.select('id, infoData')
.eq('tenant', tenantId)
// 2⃣ Kunden anhand Domain vergleichen
const allCustomers = await server.db
.select({
id: customers.id,
infoData: customers.infoData,
})
.from(customers)
.where(eq(customers.tenant, tenantId))
if (error) {
server.log.error(`[Helpdesk] Fehler beim Laden der Kunden: ${error.message}`)
return null
}
for (const c of customers || []) {
for (const c of allCustomers) {
const info = c.infoData || {}
// @ts-ignore
const email = info.email?.toLowerCase()
//@ts-ignore
const invoiceEmail = info.invoiceEmail?.toLowerCase()
const emailDomain = extractDomain(email)
const invoiceDomain = extractDomain(invoiceEmail)
@@ -55,18 +79,28 @@ export async function findCustomerOrContactByEmailOrDomain(server:FastifyInstanc
return null
}
// -------------------------------------------------------------
// getNestedValue (für Sortierung & Suche im Backend)
// -------------------------------------------------------------
export function getNestedValue(obj: any, path: string): any {
return path.split('.').reduce((acc, part) => acc?.[part], obj);
return path
.split(".")
.reduce((acc, part) => (acc && acc[part] !== undefined ? acc[part] : undefined), obj)
}
// -------------------------------------------------------------
// compareValues (Sortierung für paginated)
// -------------------------------------------------------------
export function compareValues(a: any, b: any): number {
if (a === b) return 0;
if (a == null) return 1;
if (b == null) return -1;
if (a === b) return 0
if (a == null) return 1
if (b == null) return -1
if (typeof a === 'string' && typeof b === 'string') {
return a.localeCompare(b);
// String Compare
if (typeof a === "string" && typeof b === "string") {
return a.localeCompare(b)
}
return a < b ? -1 : 1;
}
// Numerisch
return a < b ? -1 : 1
}