Added Backend
This commit is contained in:
142
backend/src/routes/helpdesk.inbound.ts
Normal file
142
backend/src/routes/helpdesk.inbound.ts
Normal file
@@ -0,0 +1,142 @@
|
||||
// modules/helpdesk/helpdesk.inbound.routes.ts
|
||||
import { FastifyPluginAsync } from 'fastify'
|
||||
import { createConversation } from '../modules/helpdesk/helpdesk.conversation.service.js'
|
||||
import { addMessage } from '../modules/helpdesk/helpdesk.message.service.js'
|
||||
import { getOrCreateContact } from '../modules/helpdesk/helpdesk.contact.service.js'
|
||||
|
||||
/**
|
||||
* Öffentliche Route zum Empfang eingehender Kontaktformular-Nachrichten.
|
||||
* Authentifizierung: über `public_token` aus helpdesk_channel_instances
|
||||
*/
|
||||
|
||||
function extractDomain(email) {
|
||||
if (!email) return null
|
||||
const parts = email.split("@")
|
||||
return parts.length === 2 ? parts[1].toLowerCase() : null
|
||||
}
|
||||
|
||||
async function findCustomerOrContactByEmailOrDomain(server,fromMail, tenantId) {
|
||||
const sender = fromMail
|
||||
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()
|
||||
|
||||
if (contactMatch?.customer_id) return {
|
||||
customer: contactMatch.customer,
|
||||
contact: contactMatch.id
|
||||
}
|
||||
|
||||
// 2️⃣ Kunden laden, bei denen E-Mail oder Rechnungsmail passt
|
||||
const { data: customers, error } = await server.supabase
|
||||
.from("customers")
|
||||
.select("id, infoData")
|
||||
.eq("tenant", tenantId)
|
||||
|
||||
if (error) {
|
||||
console.error(`[Helpdesk] Fehler beim Laden der Kunden:`, error.message)
|
||||
return null
|
||||
}
|
||||
|
||||
// 3️⃣ Durch Kunden iterieren und prüfen
|
||||
for (const c of customers || []) {
|
||||
const info = c.infoData || {}
|
||||
const email = info.email?.toLowerCase()
|
||||
const invoiceEmail = info.invoiceEmail?.toLowerCase()
|
||||
|
||||
const emailDomain = extractDomain(email)
|
||||
const invoiceDomain = extractDomain(invoiceEmail)
|
||||
|
||||
// exakter Match oder Domain-Match
|
||||
if (
|
||||
sender === email ||
|
||||
sender === invoiceEmail ||
|
||||
senderDomain === emailDomain ||
|
||||
senderDomain === invoiceDomain
|
||||
) {
|
||||
return {customer: c.id, contact:null}
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
const helpdeskInboundRoutes: FastifyPluginAsync = async (server) => {
|
||||
// Öffentliche POST-Route
|
||||
server.post('/helpdesk/inbound/:public_token', async (req, res) => {
|
||||
const { public_token } = req.params as { public_token: string }
|
||||
const { email, phone, display_name, subject, message } = req.body as {
|
||||
email: string,
|
||||
phone: string,
|
||||
display_name: string
|
||||
subject: string
|
||||
message: string
|
||||
}
|
||||
|
||||
if (!message) {
|
||||
return res.status(400).send({ error: 'Message content required' })
|
||||
}
|
||||
|
||||
// 1️⃣ Kanalinstanz anhand des Tokens ermitteln
|
||||
const { data: channel, error: channelError } = await server.supabase
|
||||
.from('helpdesk_channel_instances')
|
||||
.select('*')
|
||||
.eq('public_token', public_token)
|
||||
.single()
|
||||
|
||||
if (channelError || !channel) {
|
||||
return res.status(404).send({ error: 'Invalid channel token' })
|
||||
}
|
||||
|
||||
const tenant_id = channel.tenant_id
|
||||
const channel_instance_id = channel.id
|
||||
|
||||
// @ts-ignore
|
||||
const {customer, contact: contactPerson} = await findCustomerOrContactByEmailOrDomain(server,email, tenant_id )
|
||||
|
||||
|
||||
// 2️⃣ Kontakt finden oder anlegen
|
||||
const contact = await getOrCreateContact(server, tenant_id, {
|
||||
email,
|
||||
phone,
|
||||
display_name,
|
||||
customer_id: customer,
|
||||
contact_id: contactPerson,
|
||||
})
|
||||
|
||||
// 3️⃣ Konversation erstellen
|
||||
const conversation = await createConversation(server, {
|
||||
tenant_id,
|
||||
contact,
|
||||
channel_instance_id,
|
||||
subject: subject ?? 'Kontaktformular Anfrage',
|
||||
customer_id: customer,
|
||||
contact_person_id: contactPerson
|
||||
})
|
||||
|
||||
// 4️⃣ Erste Nachricht hinzufügen
|
||||
await addMessage(server, {
|
||||
tenant_id,
|
||||
conversation_id: conversation.id,
|
||||
direction: 'incoming',
|
||||
payload: { type: 'text', text: message },
|
||||
raw_meta: { source: 'contact_form' },
|
||||
})
|
||||
|
||||
// (optional) Auto-Antwort oder Event hier ergänzen
|
||||
|
||||
return res.status(201).send({
|
||||
success: true,
|
||||
conversation_id: conversation.id,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export default helpdeskInboundRoutes
|
||||
Reference in New Issue
Block a user