Ein namentlich adressiertes Schreiben landet bei der Person, die den Vorgang kennt, statt in der Poststelle. Am Vorgang laesst sich jetzt ein Kontakt aus dem Verzeichnis als Ansprechpartner benennen; die Sachstandsanfrage redet ihn an, und sein Name steht ueber der Behoerde. Die Sachstandsanfrage konnte das schon - sie bekam den Namen nur nie uebergeben. entwurf.ts lud einen der verknuepften Kontakte und verwarf ihn wieder. Wer angeredet wird, ist jetzt eine Entscheidung und kein Zufall. Aufbau: - Migration: ansprechpartnerId am Vorgang (SetNull - ein Vorgang darf nicht daran haengen, dass es den Kontakt noch gibt) und anrede am Kontakt. - Die Anrede als reine Funktion in kontakte/anrede.ts. Geraten wird nie: ohne hinterlegte Anrede wird mit vollem Namen angeredet. Ein leerer Name mit gesetzter Anrede faellt auf die allgemeine Anrede zurueck - "Sehr geehrte Frau ," darf nie herausgehen. - Der Wechsel des Ansprechpartners steht mit NAMEN im Protokoll. Zwei cuids nebeneinander waeren protokolliert, aber nicht nachvollziehbar, und nachvollziehbar war die Anforderung. - Der Ansprechpartner wird gegen die Akte geprueft, bevor er gespeichert wird - sein Name steht anschliessend im Briefkopf. Nebenbei behoben: Der Schreiben-Editor verwarf die empfaengerAnschrift aus dem Entwurf, sein State startete immer leer. Jetzt kommt die Anschrift des Ansprechpartners im Formular an. Geprueft: neun Einheitstests fuer die Anrede, fuenf End-to-End-Tests von der Auswahl bis zum Protokolleintrag. Refs #9
165 lines
6.1 KiB
TypeScript
165 lines
6.1 KiB
TypeScript
import { expect, test } from '@playwright/test'
|
|
import { PrismaClient } from '@prisma/client'
|
|
import { anmelden } from './hilfen'
|
|
|
|
/**
|
|
* Ansprechpartner am Vorgang — gegen die echte Anwendung.
|
|
*
|
|
* Geprüft wird die Zusage, um die es geht: Ein Schreiben zum Vorgang
|
|
* redet die Sachbearbeiterin namentlich an und trägt ihren Namen über
|
|
* der Behörde — ohne benannten Ansprechpartner bleibt alles beim Alten.
|
|
*/
|
|
|
|
const KENNUNG = 'Prüfhausen Partner'
|
|
|
|
async function mitDb<T>(arbeit: (db: PrismaClient) => Promise<T>): Promise<T> {
|
|
const db = new PrismaClient()
|
|
try {
|
|
return await arbeit(db)
|
|
} finally {
|
|
await db.$disconnect()
|
|
}
|
|
}
|
|
|
|
async function aufraeumen(): Promise<void> {
|
|
await mitDb(async (db) => {
|
|
await db.vorgang.deleteMany({ where: { titel: { contains: KENNUNG } } })
|
|
await db.kontakt.deleteMany({ where: { name: { contains: KENNUNG } } })
|
|
})
|
|
}
|
|
|
|
test.describe('Ansprechpartner am Vorgang', () => {
|
|
test.beforeAll(async () => {
|
|
await aufraeumen()
|
|
await mitDb(async (db) => {
|
|
const betreute = await db.betreute.findMany({
|
|
where: { geloeschtAm: null },
|
|
select: { id: true },
|
|
})
|
|
for (const person of betreute) {
|
|
await db.kontakt.create({
|
|
data: {
|
|
betreuteId: person.id,
|
|
name: `${KENNUNG} Petra Sachs`,
|
|
organisation: `${KENNUNG} Bezirk`,
|
|
rolle: 'SACHBEARBEITER_BEZIRK',
|
|
anrede: 'FRAU',
|
|
telefon: '0921 604-1234',
|
|
strasse: 'Cottenbacher Str. 23',
|
|
plz: '95445',
|
|
ort: 'Bayreuth',
|
|
},
|
|
})
|
|
await db.vorgang.create({
|
|
data: {
|
|
betreuteId: person.id,
|
|
titel: `${KENNUNG} Antrag auf Hilfe zur Pflege`,
|
|
kategorie: 'SOZIALHILFE',
|
|
status: 'WARTET_AUF_DRITTE',
|
|
gegenstelle: `${KENNUNG} Bezirk`,
|
|
aktenzeichen: 'HzP 2026/4711',
|
|
},
|
|
})
|
|
}
|
|
})
|
|
})
|
|
|
|
test.afterAll(async () => {
|
|
await aufraeumen()
|
|
})
|
|
|
|
test('bleibt ohne benannten Ansprechpartner bei der allgemeinen Anrede', async ({ page }) => {
|
|
await anmelden(page)
|
|
await page.goto('/vorgaenge')
|
|
await page.getByRole('link', { name: new RegExp(`${KENNUNG} Antrag`) }).first().click()
|
|
await page.waitForURL(/\/vorgaenge\/[a-z0-9]+$/)
|
|
|
|
await expect(page.getByText('Keiner benannt', { exact: false }).first()).toBeVisible()
|
|
|
|
await page.getByRole('button', { name: 'Sachstandsanfrage erzeugen' }).click()
|
|
const text = await page.locator('textarea#sachstand-text').inputValue()
|
|
expect(text).toContain('Sehr geehrte Damen und Herren,')
|
|
})
|
|
|
|
test('lässt einen Kontakt als Ansprechpartner wählen und zeigt ihn an', async ({ page }) => {
|
|
await anmelden(page)
|
|
await page.goto('/vorgaenge')
|
|
await page.getByRole('link', { name: new RegExp(`${KENNUNG} Antrag`) }).first().click()
|
|
await page.waitForURL(/\/vorgaenge\/[a-z0-9]+$/)
|
|
|
|
await page
|
|
.locator('select[name="ansprechpartnerId"]')
|
|
.selectOption({ label: `${KENNUNG} Petra Sachs · ${KENNUNG} Bezirk` })
|
|
await page.getByRole('button', { name: 'Speichern' }).click()
|
|
await expect(page.getByText('Der Vorgang ist gespeichert.')).toBeVisible()
|
|
|
|
await page.reload()
|
|
const inhalt = await page.locator('body').innerText()
|
|
// Vor dem Anruf weiß man, wen man fragt — samt Durchwahl.
|
|
expect(inhalt).toContain(`${KENNUNG} Petra Sachs`)
|
|
expect(inhalt).toContain('0921 604-1234')
|
|
})
|
|
|
|
test('redet die Sachstandsanfrage namentlich an', async ({ page }) => {
|
|
await anmelden(page)
|
|
await page.goto('/vorgaenge')
|
|
await page.getByRole('link', { name: new RegExp(`${KENNUNG} Antrag`) }).first().click()
|
|
await page.waitForURL(/\/vorgaenge\/[a-z0-9]+$/)
|
|
|
|
await page.getByRole('button', { name: 'Sachstandsanfrage erzeugen' }).click()
|
|
const text = await page.locator('textarea#sachstand-text').inputValue()
|
|
expect(text).toContain('Sehr geehrte Frau Sachs,')
|
|
expect(text).not.toContain('Sehr geehrte Damen und Herren,')
|
|
// Der Name steht über der Behörde.
|
|
const zeilen = text.split('\n')
|
|
expect(zeilen[0]).toContain('Petra Sachs')
|
|
})
|
|
|
|
test('übernimmt Name und Anschrift in das Schreiben zum Vorgang', async ({ page }) => {
|
|
const vorgangId = await mitDb(async (db) => {
|
|
const vorgang = await db.vorgang.findFirst({
|
|
where: { titel: { contains: KENNUNG }, ansprechpartnerId: { not: null } },
|
|
select: { id: true },
|
|
})
|
|
return vorgang?.id ?? ''
|
|
})
|
|
expect(vorgangId).not.toBe('')
|
|
|
|
await anmelden(page)
|
|
await page.goto(`/schreiben/neu?art=SACHSTAND&vorgangId=${vorgangId}`)
|
|
|
|
await expect(page.locator('textarea#text')).toBeVisible()
|
|
const text = await page.locator('textarea#text').inputValue()
|
|
expect(text).toContain('Sehr geehrte Frau Sachs,')
|
|
|
|
// Empfänger und Anschrift sind vorbelegt, nichts abzutippen.
|
|
await expect(page.locator('input[name="empfaengerName"]').first()).toHaveValue(
|
|
`${KENNUNG} Petra Sachs`,
|
|
)
|
|
expect(await page.locator('textarea#empfaengerAnschrift').first().inputValue()).toContain(
|
|
'95445 Bayreuth',
|
|
)
|
|
})
|
|
|
|
test('hält den Wechsel des Ansprechpartners mit Namen im Protokoll fest', async ({ page }) => {
|
|
await anmelden(page)
|
|
await page.goto('/vorgaenge')
|
|
await page.getByRole('link', { name: new RegExp(`${KENNUNG} Antrag`) }).first().click()
|
|
await page.waitForURL(/\/vorgaenge\/[a-z0-9]+$/)
|
|
|
|
// Zurück auf „keiner benannt" — der Wechsel muss nachvollziehbar sein.
|
|
await page.locator('select[name="ansprechpartnerId"]').selectOption('')
|
|
await page.getByRole('button', { name: 'Speichern' }).click()
|
|
await expect(page.getByText('Der Vorgang ist gespeichert.')).toBeVisible()
|
|
|
|
// Im Protokoll steht der Name, nicht die Id: Zwei cuids nebeneinander
|
|
// sind protokolliert, aber nicht nachvollziehbar.
|
|
await page.goto('/protokoll')
|
|
// textContent statt innerText: Die Felderliste steckt in einem
|
|
// zugeklappten <details>.
|
|
const protokoll = (await page.locator('body').textContent()) ?? ''
|
|
expect(protokoll).toContain('ansprechpartner')
|
|
expect(protokoll).toContain(`${KENNUNG} Petra Sachs`)
|
|
})
|
|
})
|