Hustler-Stufe: P4-Aktionen im Pult erst ab Stufe 4 (rowModel-Parameter stufe, PultList reicht ihn durch)
Unterhalb von Stufe 4 sind canReply, canPaste, canApprovePreview und canStartBuild immer false: Antwort des Kunden einfügen, Als Mensch antworten / Jetzt senden, Freigeben & senden und Vorschau bauen verschwinden samt Feldern und Rückfragen, die Aktionsgruppe schließt sich ohne Lücke. P3-Aktionen (übernehmen, Kopieren & öffnen, als gesendet markieren, verwerfen, erledigt, E-Mail schreiben) bleiben. Bestehende P4-Tests laufen ausdrücklich auf Stufe 6; neue Tests prüfen Stufe 3 gerendert und bedient (Reihenfolge der Knöpfe, kein Feld, Esc, Verwerfen mit Rückfrage). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
7cd74a23d2
commit
5e48fbf264
5 files changed
+207
-15
No files matched your search
@@ -5,8 +5,13 @@ import { loadModule } from './load.mjs'
|
||||
// Reine Pult-Logik des Reiters „Freigabe“: Filter, Alter, Veraltet-Anzeige, sichere Links, Zeilenmodell, Kopieren & Öffnen
|
||||
const {
|
||||
PULT_KIND_LABELS, SENDABLE_KINDS, PULT_FILTERS, REPLY_KINDS, PASTE_KINDS, REPLY_TEXT_MAX, UNCERTAIN_TEXT,
|
||||
staleView, ageLabel, safeExternalUrl, mailtoHref, employeeName, rowModel, copyAndOpen, validateReplyText, charCount, actionErrorText, pasteDoneText,
|
||||
staleView, ageLabel, safeExternalUrl, mailtoHref, employeeName, rowModel: rowModelNachStufe, copyAndOpen, validateReplyText, charCount, actionErrorText, pasteDoneText,
|
||||
} = await loadModule('src/lib/workersPult.js')
|
||||
const { HUSTLER_STUFE } = await loadModule('src/lib/hustlerStufe.js')
|
||||
|
||||
// Stufen-Sperre (hustlerStufe.js): rowModel bietet die P4-Aktionen erst ab Stufe 4 an. Die Zusicherungen dieser Datei gelten für das volle Pult und laufen deshalb auf
|
||||
// Stufe 6 (P4 und Keller offen, Verhalten wie vor der Sperre). Was unterhalb von Stufe 4 gilt, prüft hustlerStufe.test.mjs.
|
||||
const rowModel = (item, ctx) => rowModelNachStufe(item, { stufe: 6, ...ctx })
|
||||
|
||||
const NOW = Date.parse('2026-10-19T09:00:00Z')
|
||||
const MIN = 60 * 1000
|
||||
@@ -462,3 +467,73 @@ test('pasteDoneText: neu und fortgesetzt melden das Einsortieren, doppelt meldet
|
||||
assert.equal(pasteDoneText({ status: 'doppelt' }), 'Diese Antwort war schon eingefügt.')
|
||||
for (const odd of [undefined, null, {}, 'doppelt', { status: 7 }]) assert.equal(pasteDoneText(odd), 'Eingefügt. Nora sortiert die Antwort ein.', String(odd))
|
||||
})
|
||||
|
||||
// ---------- Stufen-Sperre (hustlerStufe.js): rowModel auf Stufe 3 und Stufe 6 ----------
|
||||
|
||||
const ME = { id: 'u1', name: 'Justin' }
|
||||
const PROSPEKT = { $id: 'p1', name: 'Verein', email: 'x@verein.example', status: 'neu' }
|
||||
const eintrag = (extra) => ({ $id: 'e1', kind: 'plattform_antwort', status: 'offen', title: 'Titel', draft: 'Hallo', createdAt: '2026-10-19T08:00:00Z', sourceUrl: 'https://www.kleinanzeigen.de/s-anzeige/x/1-2-3', prospectId: 'p1', prospect: PROSPEKT, ...extra })
|
||||
const zeile = (item, s) => rowModelNachStufe(item, { me: ME, nowMs: NOW, employees: [], stufe: s })
|
||||
const P4 = ['canReply', 'canPaste', 'canApprovePreview', 'canStartBuild']
|
||||
const P3 = ['canClaim', 'canSend', 'canDiscard', 'canDone']
|
||||
const VORSCHAU = 'https://entwurf.project.webklar.com/verein'
|
||||
|
||||
test('rowModel auf Stufe 1 bis 3: canReply, canPaste, canApprovePreview und canStartBuild sind für jede Art und jeden Status false', () => {
|
||||
const kinds = Object.keys(PULT_KIND_LABELS)
|
||||
const states = ['offen', 'in_arbeit', 'veraltet', 'gesendet', 'verworfen', 'erledigt']
|
||||
for (const s of [1, 2, 3]) {
|
||||
for (const kind of kinds) {
|
||||
for (const status of states) {
|
||||
for (const extra of [{}, { claimedBy: 'mensch:u1' }, { claimedBy: 'mensch:u2' }, { prospect: null }]) {
|
||||
const item = eintrag({ kind, status, sourceUrl: kind === 'vorschau_freigabe' ? VORSCHAU : undefined, ...extra })
|
||||
const m = zeile(item, s)
|
||||
for (const key of P4) assert.equal(m[key], false, `Stufe ${s} ${kind}/${status} ${JSON.stringify(extra)}: ${key}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
test('rowModel auf Stufe 4, 6 und 9: die P4-Aktionen erscheinen wie vor der Sperre', () => {
|
||||
for (const s of [4, 6, 9]) {
|
||||
assert.equal(zeile(eintrag({ kind: 'mail_antwort' }), s).canReply, true, `Stufe ${s}`)
|
||||
assert.equal(zeile(eintrag({ kind: 'unsicher' }), s).canReply, true)
|
||||
assert.equal(zeile(eintrag({ kind: 'plattform_antwort', status: 'gesendet' }), s).canPaste, true)
|
||||
assert.equal(zeile(eintrag({ kind: 'plattform_antwort', status: 'verworfen' }), s).canPaste, false) // die Regeln selbst bleiben
|
||||
assert.equal(zeile(eintrag({ kind: 'vorschau_freigabe', sourceUrl: VORSCHAU }), s).canApprovePreview, true)
|
||||
assert.equal(zeile(eintrag({ kind: 'unsicher' }), s).canStartBuild, true)
|
||||
assert.equal(zeile(eintrag({ kind: 'unsicher', prospect: { ...PROSPEKT, status: 'gesperrt' } }), s).canStartBuild, false)
|
||||
assert.equal(zeile(eintrag({ kind: 'mail_antwort', claimedBy: 'mensch:u2', status: 'in_arbeit' }), s).canReply, false) // von einem Kollegen übernommen
|
||||
}
|
||||
})
|
||||
|
||||
test('rowModel: die P3-Aktionen sind auf Stufe 3 und 6 gleich; die Stufe ändert nur die vier P4-Felder', () => {
|
||||
const fixtures = []
|
||||
for (const kind of Object.keys(PULT_KIND_LABELS)) {
|
||||
for (const status of ['offen', 'in_arbeit', 'veraltet', 'gesendet', 'verworfen', 'erledigt']) fixtures.push(eintrag({ kind, status, sourceUrl: kind === 'vorschau_freigabe' ? VORSCHAU : undefined }))
|
||||
}
|
||||
fixtures.push(eintrag({ status: 'in_arbeit', claimedBy: 'mensch:u1' }), eintrag({ status: 'in_arbeit', claimedBy: 'mensch:u2' }), eintrag({ kind: 'mail_antwort', sourceUrl: '' }))
|
||||
for (const item of fixtures) {
|
||||
const gesperrt = zeile(item, 3); const offen = zeile(item, 6)
|
||||
for (const key of P3) assert.equal(gesperrt[key], offen[key], `${item.kind}/${item.status}: ${key}`)
|
||||
const ohneP4 = (m) => Object.fromEntries(Object.entries(m).filter(([k]) => !P4.includes(k)))
|
||||
assert.deepEqual(ohneP4(gesperrt), ohneP4(offen), `${item.kind}/${item.status}`)
|
||||
}
|
||||
// und konkret die P3-Aktionen auf Stufe 3
|
||||
const plattform = zeile(eintrag({}), 3)
|
||||
assert.deepEqual([plattform.canClaim, plattform.canSend, plattform.canDiscard, plattform.canDone], [true, true, true, false])
|
||||
assert.equal(plattform.sourceHref, 'https://www.kleinanzeigen.de/s-anzeige/x/1-2-3'); assert.equal(plattform.copyText, 'Hallo')
|
||||
const mail = zeile(eintrag({ kind: 'mail_antwort', sourceUrl: '' }), 3)
|
||||
assert.match(mail.mailtoHref, /^mailto:x@verein\.example\?/); assert.equal(mail.canSend, true)
|
||||
const unsicher = zeile(eintrag({ kind: 'unsicher' }), 3)
|
||||
assert.deepEqual([unsicher.canDone, unsicher.canDiscard, unsicher.canClaim], [true, true, true])
|
||||
const freigabe = zeile(eintrag({ kind: 'vorschau_freigabe', sourceUrl: VORSCHAU }), 3)
|
||||
assert.deepEqual([freigabe.canClaim, freigabe.canDiscard, freigabe.canDone, freigabe.canSend], [true, true, false, false])
|
||||
})
|
||||
|
||||
test('rowModel ohne Stufe gilt HUSTLER_STUFE (die Stufe der Produktion)', () => {
|
||||
const item = eintrag({ kind: 'mail_antwort' })
|
||||
assert.equal(rowModelNachStufe(item, { me: ME, nowMs: NOW, employees: [] }).canReply, HUSTLER_STUFE >= 4)
|
||||
assert.equal(rowModelNachStufe(item, { me: ME, nowMs: NOW, employees: [], stufe: undefined }).canReply, HUSTLER_STUFE >= 4)
|
||||
assert.equal(rowModelNachStufe(item, { me: ME, nowMs: NOW, employees: [], stufe: 'x' }).canReply, HUSTLER_STUFE >= 4)
|
||||
})
|
||||
Reference in new issue
Block a user