From 0090332c70cf5cc0c2314d58348728548e61e7c9 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 4 Oct 2026 20:53:48 +0000 Subject: [PATCH] Terminplaner TP2 C7a: Nachbesserung 1 Co-Authored-By: Claude Sonnet 5.5 --- public/termine-view.js | 7 +++++-- test/termineFragebogenView.test.js | 25 +++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/public/termine-view.js b/public/termine-view.js index 98dc6d4..e399750 100644 --- a/public/termine-view.js +++ b/public/termine-view.js @@ -516,7 +516,7 @@ const nameSchluessel = (name) => leerzeichenEins(name).normalize('NFC').toLowerC * Namen: getrimmt, Leerraum zusammengefasst, auf MAX.ressourcenName gekuerzt, ohne Leere und ohne Doppelte (Gross-/Kleinschreibung zaehlt * nicht, die erste Schreibweise gilt), hoechstens LIMITS.ressourcen. Zuordnung: gleiche Namen behalten ID und Plan; uebrige alte Eintraege * werden in ihrer Reihenfolge den uebrigen Namen zugeteilt (umbenannt, ID und Plan bleiben); weitere Namen bekommen eine neue ID und eine - * Kopie des Plans des ersten Eintrags (ohne Eintrag: leerer Plan). Alle Eintraege sind aktiv. Ergebnis in der Reihenfolge der Namen: + * Kopie des Plans des ersten behaltenen oder umbenannten Eintrags, gleich wo der neue Name steht (ohne solchen Eintrag: leerer Plan). Alle Eintraege sind aktiv. Ergebnis in der Reihenfolge der Namen: * { ressourcen, entfernt: IDs der weggefallenen Eintraege, neu: IDs der neuen }. Die Eintraege tragen nur Felder, die der Server aus dem * Client uebernimmt (kein feedToken, den vergibt und behaelt der Server). Die Zuordnung der Leistungen setzt der Aufrufer. */ @@ -545,6 +545,9 @@ export function ressourcenAusNamen({ bisher, typ, namen, neueId: erzeugeId = (be const uebrige = alt.filter((r) => frei.has(r)) sauber.forEach((name, i) => { if (zugeteilt[i] === null && uebrige.length > 0) zugeteilt[i] = uebrige.shift() }) + // Vorlage fuer neue Namen: Plan des ersten behaltenen oder umbenannten Eintrags (unabhaengig davon, wo ein neuer Name in der Liste steht) + const vorlagePlan = zugeteilt.find(Boolean)?.plan + const belegt = new Set(alt.map((r) => r.id)) const ressourcen = [] const neu = [] @@ -560,7 +563,7 @@ export function ressourcenAusNamen({ bisher, typ, namen, neueId: erzeugeId = (be if (typeof id !== 'string' || belegt.has(id)) throw new Error(`neueId lieferte keine freie ID: ${String(id).slice(0, 40)}`) belegt.add(id) neu.push(id) - plan = ressourcen[0]?.plan + plan = vorlagePlan } ressourcen.push({ id, typ: art, name, aktiv: true, plan: structuredClone(plan !== null && typeof plan === 'object' ? plan : {}) }) }) diff --git a/test/termineFragebogenView.test.js b/test/termineFragebogenView.test.js index e290fe8..c7fb3bf 100644 --- a/test/termineFragebogenView.test.js +++ b/test/termineFragebogenView.test.js @@ -142,6 +142,31 @@ test('ressourcenAusNamen: übrige alte Einträge werden der Reihe nach umbenannt assert.deepEqual(gemischt.neu, []) }) +test('ressourcenAusNamen: ein neuer Name vor einem behaltenen bekommt trotzdem dessen Plan (Vorlage unabhängig von der Reihenfolge)', () => { + const bisher = [{ id: 'r_anna0001', typ: 'person', name: 'Anna', aktiv: true, plan: { 1: [['09:00', '12:00']] } }] + const erg = ressourcenAusNamen({ bisher, typ: 'person', namen: ['Ben', 'Anna'], neueId: zaehler() }) + assert.deepEqual(namenVon(erg.ressourcen), ['Ben', 'Anna']) + const [ben, anna] = erg.ressourcen + assert.equal(anna.id, 'r_anna0001', 'Anna behält ihre ID') + assert.deepEqual(anna.plan, { 1: [['09:00', '12:00']] }, 'und ihren Plan') + assert.equal(ben.id, 'r_test0001') + assert.deepEqual(ben.plan, { 1: [['09:00', '12:00']] }, 'Ben bekommt Annas Plan, nicht einen leeren') + assert.notEqual(ben.plan, anna.plan, 'als Kopie') + ben.plan[1].push(['14:00', '16:00']) + assert.equal(anna.plan[1].length, 1, 'Änderungen an Ben verändern Anna nicht') + assert.equal(bisher[0].plan[1].length, 1, 'und nicht den alten Eintrag') + assert.deepEqual(erg.neu, ['r_test0001']) + assert.deepEqual(erg.entfernt, []) + // mehrere neue Namen vor dem behaltenen, und ein umbenannter alter Eintrag liefert die Vorlage ebenso + const drei = ressourcenAusNamen({ bisher, typ: 'person', namen: ['Ben', 'Cem', 'Anna'], neueId: zaehler() }) + assert.deepEqual(drei.ressourcen.map((r) => r.plan), [bisher[0].plan, bisher[0].plan, bisher[0].plan]) + const umbenannt = ressourcenAusNamen({ bisher, typ: 'person', namen: ['Ben', 'Cem'], neueId: zaehler() }) + assert.deepEqual(idsVon(umbenannt.ressourcen), ['r_anna0001', 'r_test0001'], 'Anna wird zu Ben, Cem ist neu') + assert.deepEqual(umbenannt.ressourcen.map((r) => r.plan), [bisher[0].plan, bisher[0].plan]) + // ohne bisherigen Eintrag gibt es keine Vorlage: leerer Plan + assert.deepEqual(ressourcenAusNamen({ bisher: [], typ: 'person', namen: ['Ben', 'Cem'], neueId: zaehler() }).ressourcen.map((r) => r.plan), [{}, {}]) +}) + test('ressourcenAusNamen: trimmt, entfernt Leere und Doppelte ohne Rücksicht auf Groß-/Kleinschreibung', () => { const erg = ressourcenAusNamen({ bisher: [], typ: 'person', namen: [' Anna ', '', ' ', 'anna', 'ANNA', 'Ben', ' Ben', null, undefined, 5], neueId: zaehler() }) assert.deepEqual(namenVon(erg.ressourcen), ['Anna', 'Ben'], 'die erste Schreibweise gilt')