diff --git a/server/mail-templates/T01 Neue Chatnachricht.html b/server/mail-templates/T01 Neue Chatnachricht.html index e3b522e..9638f3b 100644 --- a/server/mail-templates/T01 Neue Chatnachricht.html +++ b/server/mail-templates/T01 Neue Chatnachricht.html @@ -7,7 +7,7 @@ Betreff: Neue Portalnachricht von {{kunde_name}} Absender: „WEBklar Kundenportal“ Empfänger: kenso@webklar.com, andrej@webklar.com - Platzhalter: {{kunde_name}}, {{nachricht}} + Platzhalter: {{kunde_name}}, {{nachricht}}, {{team_link}} --> @@ -35,12 +35,12 @@ a{color:#111111;}
Neue Nachricht
{{kunde_name}} hat im Kundenportal geschrieben -
Im Admin-Bereich antworten →
-Tab „Chat“. Höchstens eine Benachrichtigung je Kunde alle 15 Minuten. +
Im Ticketsystem antworten →
+Kunden → Chat. Höchstens eine Benachrichtigung je Kunde alle 15 Minuten.   -Automatische Benachrichtigung aus dem WEBklar Kundenportal · Admin-Bereich +Automatische Benachrichtigung aus dem WEBklar Kundenportal · Ticketsystem diff --git a/server/mail-templates/T02 Neues Abo.html b/server/mail-templates/T02 Neues Abo.html index aa15589..4e8bad3 100644 --- a/server/mail-templates/T02 Neues Abo.html +++ b/server/mail-templates/T02 Neues Abo.html @@ -52,7 +52,7 @@ a{color:#111111;}   -Automatische Benachrichtigung aus dem WEBklar Kundenportal · Admin-Bereich +Automatische Benachrichtigung aus dem WEBklar Kundenportal · Ticketsystem diff --git a/server/mail-templates/T03 Angebot nicht mehr offen.html b/server/mail-templates/T03 Angebot nicht mehr offen.html index 573d2b0..b7154fe 100644 --- a/server/mail-templates/T03 Angebot nicht mehr offen.html +++ b/server/mail-templates/T03 Angebot nicht mehr offen.html @@ -39,7 +39,7 @@ a{color:#111111;}   -Automatische Benachrichtigung aus dem WEBklar Kundenportal · Admin-Bereich +Automatische Benachrichtigung aus dem WEBklar Kundenportal · Ticketsystem diff --git a/server/mail-templates/T04 Zahlung fehlgeschlagen.html b/server/mail-templates/T04 Zahlung fehlgeschlagen.html index a84e210..a7e9443 100644 --- a/server/mail-templates/T04 Zahlung fehlgeschlagen.html +++ b/server/mail-templates/T04 Zahlung fehlgeschlagen.html @@ -39,7 +39,7 @@ a{color:#111111;}   -Automatische Benachrichtigung aus dem WEBklar Kundenportal · Admin-Bereich +Automatische Benachrichtigung aus dem WEBklar Kundenportal · Ticketsystem diff --git a/server/mail-templates/T05 Kuendigung Stripe.html b/server/mail-templates/T05 Kuendigung Stripe.html index 5501aa1..f10ec1e 100644 --- a/server/mail-templates/T05 Kuendigung Stripe.html +++ b/server/mail-templates/T05 Kuendigung Stripe.html @@ -40,7 +40,7 @@ a{color:#111111;}   -Automatische Benachrichtigung aus dem WEBklar Kundenportal · Admin-Bereich +Automatische Benachrichtigung aus dem WEBklar Kundenportal · Ticketsystem diff --git a/server/mail-templates/T06 Kuendigung zurueckgenommen.html b/server/mail-templates/T06 Kuendigung zurueckgenommen.html index 18a23ad..9d9792a 100644 --- a/server/mail-templates/T06 Kuendigung zurueckgenommen.html +++ b/server/mail-templates/T06 Kuendigung zurueckgenommen.html @@ -39,7 +39,7 @@ a{color:#111111;}   -Automatische Benachrichtigung aus dem WEBklar Kundenportal · Admin-Bereich +Automatische Benachrichtigung aus dem WEBklar Kundenportal · Ticketsystem diff --git a/server/mail-templates/T07 Abo beendet.html b/server/mail-templates/T07 Abo beendet.html index 16c2dea..c20dd48 100644 --- a/server/mail-templates/T07 Abo beendet.html +++ b/server/mail-templates/T07 Abo beendet.html @@ -41,7 +41,7 @@ a{color:#111111;}   -Automatische Benachrichtigung aus dem WEBklar Kundenportal · Admin-Bereich +Automatische Benachrichtigung aus dem WEBklar Kundenportal · Ticketsystem diff --git a/server/mail-templates/T08 Kuendigung eingegangen.html b/server/mail-templates/T08 Kuendigung eingegangen.html index f4533e9..e5bc57b 100644 --- a/server/mail-templates/T08 Kuendigung eingegangen.html +++ b/server/mail-templates/T08 Kuendigung eingegangen.html @@ -87,7 +87,7 @@ a{color:#111111;}   -Automatische Benachrichtigung aus dem WEBklar Kundenportal · Admin-Bereich +Automatische Benachrichtigung aus dem WEBklar Kundenportal · Ticketsystem diff --git a/server/mail-templates/T09 Widerruf eingegangen.html b/server/mail-templates/T09 Widerruf eingegangen.html index 56ee548..f86d414 100644 --- a/server/mail-templates/T09 Widerruf eingegangen.html +++ b/server/mail-templates/T09 Widerruf eingegangen.html @@ -61,7 +61,7 @@ a{color:#111111;} - + @@ -84,7 +84,7 @@ a{color:#111111;}   -Automatische Benachrichtigung aus dem WEBklar Kundenportal · Admin-Bereich +Automatische Benachrichtigung aus dem WEBklar Kundenportal · Ticketsystem diff --git a/server/mail-templates/T10 Uebernahmegutschrift beantragt.html b/server/mail-templates/T10 Uebernahmegutschrift beantragt.html index 2f69925..900a95f 100644 --- a/server/mail-templates/T10 Uebernahmegutschrift beantragt.html +++ b/server/mail-templates/T10 Uebernahmegutschrift beantragt.html @@ -44,7 +44,7 @@ a{color:#111111;}   -Automatische Benachrichtigung aus dem WEBklar Kundenportal · Admin-Bereich +Automatische Benachrichtigung aus dem WEBklar Kundenportal · Ticketsystem diff --git a/server/mail-templates/T11 Antwort auf Rueckfrage.html b/server/mail-templates/T11 Antwort auf Rueckfrage.html index 06cb677..694b5f8 100644 --- a/server/mail-templates/T11 Antwort auf Rueckfrage.html +++ b/server/mail-templates/T11 Antwort auf Rueckfrage.html @@ -45,7 +45,7 @@ a{color:#111111;}   -Automatische Benachrichtigung aus dem WEBklar Kundenportal · Admin-Bereich +Automatische Benachrichtigung aus dem WEBklar Kundenportal · Ticketsystem diff --git a/server/mail-templates/T12 Wechsel.html b/server/mail-templates/T12 Wechsel.html index 980fb37..69cc100 100644 --- a/server/mail-templates/T12 Wechsel.html +++ b/server/mail-templates/T12 Wechsel.html @@ -60,7 +60,7 @@ a{color:#111111;}   -Automatische Benachrichtigung aus dem WEBklar Kundenportal · Admin-Bereich +Automatische Benachrichtigung aus dem WEBklar Kundenportal · Ticketsystem diff --git a/server/mail-templates/T13 Speicher-Aufgabe.html b/server/mail-templates/T13 Speicher-Aufgabe.html index 05bc856..7d56a2c 100644 --- a/server/mail-templates/T13 Speicher-Aufgabe.html +++ b/server/mail-templates/T13 Speicher-Aufgabe.html @@ -38,11 +38,11 @@ a{color:#111111;}
Kunde{{name}}
E-Mail{{email}}
Stripe-Abo{{stripe_abo_id}}
Postfächer{{postfaecher_hinweis}}
Neue Gesamtgröße{{neue_groesse_gb}} GB (5 GB inklusive + {{pakete}} Pakete Zusatzspeicher zu 5 GB)
Fällig{{faellig}}
- + - + @@ -50,13 +50,13 @@ a{color:#111111;} - +   -Automatische Benachrichtigung aus dem WEBklar Kundenportal · Admin-Bereich +Automatische Benachrichtigung aus dem WEBklar Kundenportal · Ticketsystem diff --git a/server/mail-templates/T14 Loeschfristen.html b/server/mail-templates/T14 Loeschfristen.html index 3de7724..852be5d 100644 --- a/server/mail-templates/T14 Loeschfristen.html +++ b/server/mail-templates/T14 Loeschfristen.html @@ -41,7 +41,7 @@ a{color:#111111;}   -Automatische Benachrichtigung aus dem WEBklar Kundenportal · Admin-Bereich +Automatische Benachrichtigung aus dem WEBklar Kundenportal · Ticketsystem diff --git a/server/mail-templates/T16 Funktion bestellt.html b/server/mail-templates/T16 Funktion bestellt.html index 306e137..e9b715f 100644 --- a/server/mail-templates/T16 Funktion bestellt.html +++ b/server/mail-templates/T16 Funktion bestellt.html @@ -46,7 +46,7 @@ a{color:#111111;}   -Automatische Benachrichtigung aus dem WEBklar Kundenportal · Admin-Bereich +Automatische Benachrichtigung aus dem WEBklar Kundenportal · Ticketsystem diff --git a/server/services/mailer.js b/server/services/mailer.js index 22f834e..04f208f 100644 --- a/server/services/mailer.js +++ b/server/services/mailer.js @@ -62,7 +62,12 @@ export async function sendChatNotification(customer, text) { const mail = render({ template: 'T01', - values: { kunde_name: customer.name || customer.email || 'Kunde', nachricht: text }, + values: { + kunde_name: customer.name || customer.email || 'Kunde', + nachricht: text, + // Knopf "Im Ticketsystem antworten": Messenger mit dem Gespraech dieses Kunden + team_link: `${config.womsBaseUrl}/customers/chat?kunde=${encodeURIComponent(customer.$id)}`, + }, }) await mailer.sendMail({ from: `"${TEAM_SENDER}" <${config.smtp.from}>`, diff --git a/server/services/takeoverCredits.js b/server/services/takeoverCredits.js index 8b25ff4..64d6688 100644 --- a/server/services/takeoverCredits.js +++ b/server/services/takeoverCredits.js @@ -383,6 +383,10 @@ export function customerView(doc) { } } +/** Antrag im Ticketsystem: Kunden-Reiter "Gutschriften" mit geoeffnetem Antrag (Team-Mails T10, T11). */ +const teamCreditLink = (doc) => + `${config.womsBaseUrl}/customers/${encodeURIComponent(doc.customerId)}?tab=gutschriften&antrag=${encodeURIComponent(doc.$id)}` + // --------------------------------------------------------------------------- // Kunde: Antrag stellen, Rueckfrage beantworten // --------------------------------------------------------------------------- @@ -457,7 +461,7 @@ export async function createTakeoverRequest({ customer, input, uploads, consentI email: input.email, ...summary, nachricht: input.message, - admin_link: `${config.publicBaseUrl}/admin.html?gutschrift=${encodeURIComponent(doc.$id)}`, + admin_link: teamCreditLink(doc), }, blocks: { nachricht: Boolean(input.message) }, }) @@ -486,7 +490,7 @@ export async function answerQuestion({ customer, doc, message, uploads }) { antrag_nr: shortRef(doc.$id), antwort: text || '(ohne Text)', neue_nachweise: added.map((f) => f.name).join(', '), - admin_link: `${config.publicBaseUrl}/admin.html?gutschrift=${encodeURIComponent(doc.$id)}`, + admin_link: teamCreditLink(doc), }, blocks: { neue_nachweise: added.length > 0 }, }) diff --git a/test/adminPanelGone.test.js b/test/adminPanelGone.test.js index fe2de12..81c9112 100644 --- a/test/adminPanelGone.test.js +++ b/test/adminPanelGone.test.js @@ -51,11 +51,8 @@ test('Admin-Panel und alte Admin-Schnittstellen sind weg', () => { }) test('keine Verweise mehr auf admin.html, kalkulation.html oder /api/portal-admin in server/ und public/', () => { - // Mail-Vorlagen und ihre Links stellt Task 3 um (eigener Test in mailTemplates.test.js) - const skip = [path.join(root, 'server/mail-templates/'), path.join(root, 'server/services/takeoverCredits.js')] const hits = [] for (const file of [...filesUnder(path.join(root, 'server')), ...filesUnder(path.join(root, 'public'))]) { - if (skip.some((s) => file.startsWith(s))) continue readFileSync(file, 'utf8').split('\n').forEach((line, i) => { if (/admin\.html|kalkulation\.html|\/api\/portal-admin/.test(line)) hits.push(`${path.relative(root, file)}:${i + 1}`) }) diff --git a/test/mailTemplates.test.js b/test/mailTemplates.test.js index 373cd1a..440585e 100644 --- a/test/mailTemplates.test.js +++ b/test/mailTemplates.test.js @@ -498,3 +498,28 @@ test('T07: Hinweis auf nicht genutzte Arbeitszeit nur im Block wartung', () => { assert.match(h.text, /Gebuchter Zusatzspeicher endet mit dem Abo\./) assert.doesNotMatch(h.text, /Arbeitszeit|Stundenkontingent|Restguthaben/) }) + +// Etappe 4: das Admin-Panel ist abgeschaltet, Team-Mails fuehren ins Ticketsystem +const TEAM_FOOTER = ['T01', 'T02', 'T03', 'T04', 'T05', 'T06', 'T07', 'T08', 'T09', 'T10', 'T11', 'T12', 'T13', 'T14', 'T16'] + +test('keine Vorlage verlinkt admin.html oder nennt den Admin-Bereich', () => { + for (const id of EXPECTED) { + const source = readFileSync(new URL(loadTemplate(id).file, DIR), 'utf8') + assert.ok(!source.includes('admin.html'), `${id}: admin.html`) + assert.ok(!source.includes('Admin-Bereich'), `${id}: Admin-Bereich`) + } +}) + +test('Fusszeile der Team-Mails: Ticketsystem', () => { + for (const id of TEAM_FOOTER) { + const tpl = loadTemplate(id) + const mail = renderMail(id, sampleValues(tpl), allBlocks(tpl, true)) + assert.match(mail.html, /Automatische Benachrichtigung aus dem WEBklar Kundenportal · ]*>Ticketsystem<\/a>/, id) + } +}) + +test('T01: Knopf antwortet im Ticketsystem beim Kunden (team_link)', () => { + const mail = renderMail('T01', { kunde_name: 'Berta', nachricht: 'Hallo', team_link: 'https://ticket.webklar.com/customers/chat?kunde=c1' }) + assert.deepEqual(mail.problems, []) + assert.match(mail.html, /]*>Im Ticketsystem antworten →<\/a>/) +}) diff --git a/test/teamMailLinks.test.js b/test/teamMailLinks.test.js new file mode 100644 index 0000000..19a16ed --- /dev/null +++ b/test/teamMailLinks.test.js @@ -0,0 +1,73 @@ +import { test, after, beforeEach } from 'node:test' +import assert from 'node:assert/strict' +import os from 'node:os' +import path from 'node:path' +import { mkdtempSync } from 'node:fs' +import { startAppwriteMock } from './support/appwriteMock.js' +import { startFakeStripe } from './support/fakeStripe.js' +import { useTestEnv } from './support/testEnv.js' +import { schemaKeys } from './support/schema.js' +import { mailSink } from './support/mailSink.js' + +// Etappe 4: Team-Mails oeffnen das Ticketsystem (Chat beim Kunden, Antrag im Kunden-Reiter Gutschriften) +process.env.TAKEOVER_UPLOAD_DIR = mkdtempSync(path.join(os.tmpdir(), 'team-mail-links-')) +process.env.CHAT_NOTIFY_EMAILS = 'team@webklar.invalid' +const aw = await startAppwriteMock({ + schema: { subscriptions: schemaKeys('subscriptions'), takeoverCredits: schemaKeys('takeoverCredits') }, +}) +const st = await startFakeStripe() +useTestEnv({ appwriteUrl: aw.url, stripeUrl: st.url }) +const { seedFixtures, hostingDoc, customers } = await import('./support/fixtures.js') +const { setMailTransportForTests, sendChatNotification } = await import('../server/services/mailer.js') +const { createTakeoverRequest, answerQuestion } = await import('../server/services/takeoverCredits.js') +after(() => { + setMailTransportForTests(null) + return Promise.all([aw.close(), st.close()]) +}) + +seedFixtures(aw) +aw.seed('subscriptions', hostingDoc) +let sink +beforeEach(() => { + sink = mailSink() + setMailTransportForTests(sink) +}) + +const teamMail = (subject) => sink.sent.find((m) => m.to.some((t) => t.address === 'team@webklar.invalid') && subject.test(m.subject)) +const input = { + email: 'k@example.invalid', + services: ['hosting'], + provider: 'Altanbieter', + domain: '', + invoiceAmountCents: 12000, + billingMonths: 12, + paidUntil: '2027-01-31', + message: '', +} + +test('T01 antwortet im Ticketsystem beim Kunden', async () => { + const res = await sendChatNotification({ $id: 'c1', name: 'Berta' }, 'Hallo') + assert.deepEqual(res, { sent: true }) + const mail = teamMail(/Neue Portalnachricht von Berta/) + assert.ok(mail) + assert.match(mail.html, /href="https:\/\/ticket\.webklar\.com\/customers\/chat\?kunde=c1"[^>]*>Im Ticketsystem antworten →<\/a>/) + assert.match(mail.html, /href="https:\/\/ticket\.webklar\.com\/customers"[^>]*>Ticketsystem<\/a>/) + assert.doesNotMatch(mail.html, /admin\.html|Admin-Bereich/) +}) + +test('T10/T11 oeffnen den Antrag im Kunden-Reiter Gutschriften', async () => { + const doc = await createTakeoverRequest({ customer: customers.c1, input, uploads: [], consentIp: '127.0.0.1' }) + const link = `https://ticket.webklar.com/customers/c1?tab=gutschriften&antrag=${doc.$id}` + const t10 = teamMail(/Übernahmegutschrift/) + assert.ok(t10, sink.sent.map((m) => m.subject).join(' | ')) + assert.ok(t10.html.includes(`href="${link}"`), 'T10-Link') + assert.doesNotMatch(t10.html, /admin\.html|Admin-Bereich/) + + aw.seed('takeoverCredits', { ...aw.docs('takeoverCredits').get(doc.$id), status: 'rueckfrage' }) + sink.sent.length = 0 + await answerQuestion({ customer: customers.c1, doc: aw.docs('takeoverCredits').get(doc.$id), message: 'Hier die Antwort', uploads: [] }) + const t11 = sink.sent.find((m) => m.to.some((t) => t.address === 'team@webklar.invalid')) + assert.ok(t11) + assert.ok(t11.html.includes(`href="${link}"`), 'T11-Link') + assert.doesNotMatch(t11.html, /admin\.html|Admin-Bereich/) +})