feat(akquise): Berater-Mail sagt "beworben" und zeigt den Link
Betreff "Du wurdest beworben: <Titel>", Text "wir haben dich auf folgendes Projekt beworben", Link zum Projekt als ausgeschriebene Zeile in der Tabelle statt versteckt hinter "Zur Ausschreibung". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
eaef454442
commit
6772f34b4e
@@ -988,7 +988,8 @@ bei allen an). Ist er gesetzt, bekommt der Berater eine Mail von
|
|||||||
crm@perinco.de, sobald er in der Akquise einem Projekt zugeordnet wird - beim
|
crm@perinco.de, sobald er in der Akquise einem Projekt zugeordnet wird - beim
|
||||||
Anlegen und auch, wenn er später beim Bearbeiten dazukommt. Wer schon
|
Anlegen und auch, wenn er später beim Bearbeiten dazukommt. Wer schon
|
||||||
zugeordnet war, bekommt beim erneuten Speichern keine zweite Mail. Die Mail
|
zugeordnet war, bekommt beim erneuten Speichern keine zweite Mail. Die Mail
|
||||||
enthält die Projektdaten und den Link zur Ausschreibung; eine Antwort darauf
|
sagt, dass der Berater auf das Projekt beworben wurde, und enthält die
|
||||||
|
Projektdaten samt ausgeschriebenem Link zum Projekt; eine Antwort darauf
|
||||||
geht an den, der das Projekt eingetragen hat. Ohne hinterlegte Adresse geht
|
geht an den, der das Projekt eingetragen hat. Ohne hinterlegte Adresse geht
|
||||||
nichts heraus, der Haken zeigt dann einen Hinweis.
|
nichts heraus, der Haken zeigt dann einen Hinweis.
|
||||||
|
|
||||||
|
|||||||
+4
-2
@@ -393,8 +393,10 @@ Fremdschlüssel nicht.
|
|||||||
|
|
||||||
Seit 21.10.2026 verschickt das CRM selbst Mails - bisher nur eine Sorte: Wird in
|
Seit 21.10.2026 verschickt das CRM selbst Mails - bisher nur eine Sorte: Wird in
|
||||||
der Akquise ein Projekt eingetragen und dabei ein Berater ausgewählt, bekommt
|
der Akquise ein Projekt eingetragen und dabei ein Berater ausgewählt, bekommt
|
||||||
dieser eine Mail mit Titel, Endkunde, Anbieter, Tagessatz, Zeitraum, Link zur
|
dieser eine Mail: Betreff „Du wurdest beworben: ‹Titel›", im Text „wir haben
|
||||||
Ausschreibung und Beschreibung (gekürzt auf 1500 Zeichen).
|
dich auf folgendes Projekt beworben", dazu Titel, Endkunde, Anbieter, Kanal,
|
||||||
|
Tagessatz, Zeitraum, der **Link zum Projekt** ausgeschrieben, wer beworben hat
|
||||||
|
und die Beschreibung (gekürzt auf 1500 Zeichen).
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
sequenceDiagram
|
sequenceDiagram
|
||||||
|
|||||||
@@ -65,14 +65,20 @@ export function buildMessage(acquisition, consultantName) {
|
|||||||
['Projektpreis', formatEuro(acquisition.fixed_price)],
|
['Projektpreis', formatEuro(acquisition.fixed_price)],
|
||||||
['Zeitraum', period || null],
|
['Zeitraum', period || null],
|
||||||
['Laufzeit', acquisition.duration_days ? `${acquisition.duration_days} Tage` : null],
|
['Laufzeit', acquisition.duration_days ? `${acquisition.duration_days} Tage` : null],
|
||||||
['Eingetragen von', acquisition.created_by_name],
|
['Link zum Projekt', acquisition.link],
|
||||||
|
['Beworben von', acquisition.created_by_name],
|
||||||
].filter(([, value]) => value !== null && value !== undefined && value !== '');
|
].filter(([, value]) => value !== null && value !== undefined && value !== '');
|
||||||
|
|
||||||
|
// Der Link steht ausgeschrieben da - auch wer die Mail als Text liest, sieht ihn.
|
||||||
|
const cell = (label, value) =>
|
||||||
|
label === 'Link zum Projekt'
|
||||||
|
? `<a href="${escapeHtml(value)}">${escapeHtml(value)}</a>`
|
||||||
|
: escapeHtml(value);
|
||||||
const table = rows
|
const table = rows
|
||||||
.map(
|
.map(
|
||||||
([label, value]) =>
|
([label, value]) =>
|
||||||
`<tr><td style="padding:4px 16px 4px 0;color:#666;vertical-align:top">${escapeHtml(label)}</td>` +
|
`<tr><td style="padding:4px 16px 4px 0;color:#666;vertical-align:top">${escapeHtml(label)}</td>` +
|
||||||
`<td style="padding:4px 0">${escapeHtml(value)}</td></tr>`
|
`<td style="padding:4px 0;word-break:break-all">${cell(label, value)}</td></tr>`
|
||||||
)
|
)
|
||||||
.join('');
|
.join('');
|
||||||
|
|
||||||
@@ -85,11 +91,8 @@ export function buildMessage(acquisition, consultantName) {
|
|||||||
const html = [
|
const html = [
|
||||||
'<div style="font-family:Segoe UI,Arial,sans-serif;font-size:14px;color:#222">',
|
'<div style="font-family:Segoe UI,Arial,sans-serif;font-size:14px;color:#222">',
|
||||||
`<p>Hallo ${escapeHtml(firstName)},</p>`,
|
`<p>Hallo ${escapeHtml(firstName)},</p>`,
|
||||||
'<p>in der Akquise wurde ein neues Projekt eingetragen und dir zugeordnet:</p>',
|
'<p>wir haben dich auf folgendes Projekt <strong>beworben</strong>:</p>',
|
||||||
`<table style="border-collapse:collapse;font-size:14px">${table}</table>`,
|
`<table style="border-collapse:collapse;font-size:14px">${table}</table>`,
|
||||||
acquisition.link
|
|
||||||
? `<p><a href="${escapeHtml(acquisition.link)}">Zur Ausschreibung</a></p>`
|
|
||||||
: '',
|
|
||||||
description
|
description
|
||||||
? `<p style="white-space:pre-wrap;border-left:3px solid #ddd;padding-left:12px;color:#444">${escapeHtml(description)}</p>`
|
? `<p style="white-space:pre-wrap;border-left:3px solid #ddd;padding-left:12px;color:#444">${escapeHtml(description)}</p>`
|
||||||
: '',
|
: '',
|
||||||
@@ -99,7 +102,7 @@ export function buildMessage(acquisition, consultantName) {
|
|||||||
'</div>',
|
'</div>',
|
||||||
].join('');
|
].join('');
|
||||||
|
|
||||||
return { subject: `Neues Projekt für dich: ${acquisition.title}`, html };
|
return { subject: `Du wurdest beworben: ${acquisition.title}`, html };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -43,12 +43,16 @@ const message = buildMessage(
|
|||||||
},
|
},
|
||||||
'Jörg Müller'
|
'Jörg Müller'
|
||||||
);
|
);
|
||||||
check('Betreff mit Titel', message.subject === 'Neues Projekt für dich: SAP <script>');
|
check('Betreff mit Titel', message.subject === 'Du wurdest beworben: SAP <script>');
|
||||||
|
check('Sagt, dass beworben wurde', message.html.includes('<strong>beworben</strong>'));
|
||||||
check('Titel escaped', message.html.includes('SAP <script>') && !message.html.includes('<script>'));
|
check('Titel escaped', message.html.includes('SAP <script>') && !message.html.includes('<script>'));
|
||||||
check('Firma escaped', message.html.includes('ACME & Co'));
|
check('Firma escaped', message.html.includes('ACME & Co'));
|
||||||
check('Anrede mit Vorname', message.html.includes('Hallo Jörg,'));
|
check('Anrede mit Vorname', message.html.includes('Hallo Jörg,'));
|
||||||
check('Datum deutsch', message.html.includes('01.11.2026 bis 31.12.2026'));
|
check('Datum deutsch', message.html.includes('01.11.2026 bis 31.12.2026'));
|
||||||
check('Link enthalten', message.html.includes('href="https://example.com/p?a=1&b=2"'));
|
check(
|
||||||
|
'Link sichtbar',
|
||||||
|
message.html.includes('<a href="https://example.com/p?a=1&b=2">https://example.com/p?a=1&b=2</a>')
|
||||||
|
);
|
||||||
check('Leere Felder fehlen', !message.html.includes('Projektpreis'));
|
check('Leere Felder fehlen', !message.html.includes('Projektpreis'));
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
|
|||||||
Reference in New Issue
Block a user