107 lines
3.2 KiB
TypeScript
107 lines
3.2 KiB
TypeScript
// 🔧 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
|
||
}
|