Added Backend

This commit is contained in:
2026-01-06 12:07:43 +01:00
parent b013ef8f4b
commit 6f3d4c0bff
165 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,106 @@
// 🔧 Hilfsfunktionen
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("@")
return parts.length === 2 ? parts[1].toLowerCase() : null
}
// -------------------------------------------------------------
// 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 (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.length && contactMatch[0].customer) {
return {
customer: contactMatch[0].customer,
contact: contactMatch[0].id,
}
}
// 2⃣ Kunden anhand Domain vergleichen
const allCustomers = await server.db
.select({
id: customers.id,
infoData: customers.infoData,
})
.from(customers)
.where(eq(customers.tenant, tenantId))
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)
if (
sender === email ||
sender === invoiceEmail ||
senderDomain === emailDomain ||
senderDomain === invoiceDomain
) {
return { customer: c.id, contact: null }
}
}
return null
}
// -------------------------------------------------------------
// getNestedValue (für Sortierung & Suche im Backend)
// -------------------------------------------------------------
export function getNestedValue(obj: any, path: string): any {
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
// String Compare
if (typeof a === "string" && typeof b === "string") {
return a.localeCompare(b)
}
// Numerisch
return a < b ? -1 : 1
}