Bewerbungsstatus "Vertragsverhandlung" ergaenzt
Neue Station zwischen Vorstellungsgespraech und Einstellung - in der
Statusliste, der Gruppierung auf der Startseite, den Farbskalen (Lime,
zwischen dem Gelb des Gespraechs und dem Gruen der Einstellung), im
PDF-Export, in der Statistik und in der REST-API/OpenAPI.
Der Statistik-Funnel zaehlte bisher ever('Vorstellungsgespraech') +
ever('Einstellung') und damit eine Bewerbung, die beide Stationen
durchlaufen hat, doppelt. Mit einer weiteren Stufe waere das schlimmer
geworden, deshalb zaehlt der Funnel jetzt pro Bewerbung statt pro
Statuszeile: jede Stufe zaehlt eine Bewerbung genau einmal, ein spaeterer
Status impliziert die frueheren.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -62,7 +62,8 @@ const ART_OPTIONS = [
|
||||
const STATUS_OPTIONS = [
|
||||
'Entwurf', 'Gesendet', 'Eingangsbestätigung',
|
||||
'In Bearbeitung', 'Interessiert', 'Warten auf Rückmeldung', 'Warten auf meine Antwort',
|
||||
'Vorstellungsgespräch', 'Absage', 'Absage von meiner Seite', 'Einstellung', 'Keine Rückmeldung'
|
||||
'Vorstellungsgespräch', 'Vertragsverhandlung',
|
||||
'Absage', 'Absage von meiner Seite', 'Einstellung', 'Keine Rückmeldung'
|
||||
];
|
||||
// Base document types the user can provide as a foundation for AI tailoring
|
||||
const BASIS_TYP_OPTIONS = ['Anschreiben', 'Lebenslauf', 'Profil/Kurzprofil', 'Sonstiges'];
|
||||
@@ -1745,6 +1746,27 @@ initializeDatabase().then(async () => {
|
||||
const ever = (s) => verlaufMap[s] || 0;
|
||||
const cur = (s) => statusMap[s] || 0;
|
||||
|
||||
// Für den Funnel: welche Stationen hat JEDE Bewerbung durchlaufen. Eine
|
||||
// Stufe zählt eine Bewerbung genau einmal — ein späterer Status impliziert
|
||||
// die früheren (eine Einstellung ist auch ein geführtes Gespräch), und ein
|
||||
// Aufsummieren von ever() würde eine Bewerbung, die beide Stationen hat,
|
||||
// doppelt zählen.
|
||||
const stationen = new Map();
|
||||
const verlaufPaare = await dbAll(
|
||||
'SELECT DISTINCT bewerbung_id, status FROM status_verlauf WHERE user_id = ?', [U]
|
||||
);
|
||||
verlaufPaare.forEach((r) => {
|
||||
if (!stationen.has(r.bewerbung_id)) stationen.set(r.bewerbung_id, new Set());
|
||||
stationen.get(r.bewerbung_id).add(r.status);
|
||||
});
|
||||
const everAny = (...statusListe) => {
|
||||
let n = 0;
|
||||
for (const menge of stationen.values()) {
|
||||
if (statusListe.some((s) => menge.has(s))) n++;
|
||||
}
|
||||
return n;
|
||||
};
|
||||
|
||||
const entwuerfe = cur('Entwurf');
|
||||
const gesendet = total - entwuerfe;
|
||||
const gespraech = cur('Vorstellungsgespräch');
|
||||
@@ -1755,7 +1777,8 @@ initializeDatabase().then(async () => {
|
||||
const rueckStatus = [
|
||||
'Eingangsbestätigung', 'In Bearbeitung', 'Interessiert',
|
||||
'Warten auf Rückmeldung', 'Warten auf meine Antwort',
|
||||
'Vorstellungsgespräch', 'Absage', 'Absage von meiner Seite', 'Einstellung'
|
||||
'Vorstellungsgespräch', 'Vertragsverhandlung',
|
||||
'Absage', 'Absage von meiner Seite', 'Einstellung'
|
||||
];
|
||||
const antworten = rueckStatus.reduce((a, s) => a + cur(s), 0);
|
||||
|
||||
@@ -1763,13 +1786,15 @@ initializeDatabase().then(async () => {
|
||||
const antwortquote = gesendet > 0 ? Math.round((antworten / gesendet) * 100) : 0;
|
||||
const avgProMonat = byMonth.length > 0 ? Math.round((total / byMonth.length) * 10) / 10 : 0;
|
||||
|
||||
// Funnel: distinct applications that ever reached the stage. Einstellung
|
||||
// implies a Gespräch happened, so count those toward the Gespräch stage too.
|
||||
// Funnel: Bewerbungen, die die Stufe je erreicht haben. Ein späterer Status
|
||||
// impliziert die früheren — wer eingestellt wurde, hat auch verhandelt und
|
||||
// ein Gespräch geführt, selbst wenn diese Zwischenschritte nie erfasst wurden.
|
||||
const funnel = [
|
||||
{ label: 'Bewerbungen gesamt', count: total },
|
||||
{ label: 'Versendet', count: ever('Gesendet') || gesendet },
|
||||
{ label: 'Eingangsbestätigung', count: ever('Eingangsbestätigung') },
|
||||
{ label: 'Vorstellungsgespräch', count: ever('Vorstellungsgespräch') + ever('Einstellung') },
|
||||
{ label: 'Vorstellungsgespräch', count: everAny('Vorstellungsgespräch', 'Vertragsverhandlung', 'Einstellung') },
|
||||
{ label: 'Vertragsverhandlung', count: everAny('Vertragsverhandlung', 'Einstellung') },
|
||||
{ label: 'Einstellung', count: ever('Einstellung') }
|
||||
];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user