Buchungskalender: Abgleich – T22/K34 passen zu den Vorlagen, Config-Werte geprüft
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
fbd07b3d8c
commit
c3eef4747d
2 files changed
+32
-12
No files matched your search
@@ -12,14 +12,14 @@ import { ladeEinstellungen, speichereEinstellungen } from './speicher.js'
|
||||
* portalFeatures-Dokuments): anfrage (JSON), anfrageStatus ('' | offen | angenommen | abgelehnt | zurueckgezogen), anfrageAt,
|
||||
* anfrageEntschiedenAt, anfrageEntschiedenVon, anfrageBegruendung. Sperre je Projekt: uk-anfrage:<projectId>.
|
||||
* Fehler an den Kunden tragen status (4xx) und einen deutschen Text (Du-Form), optional err.body.code und err.fehler (je Feld).
|
||||
* Mails: T22 ans Team (Anfrage eingegangen), K34 an den Kunden (Entscheidung); die Vorlagen kommen aus Task 20.
|
||||
* Mails: T22 ans Team (Anfrage eingegangen), K34 an den Kunden (Entscheidung).
|
||||
*/
|
||||
|
||||
export const ANFRAGE_OFFEN_TEXT = 'Deine Anfrage für den Buchungskalender ist noch nicht freigegeben.'
|
||||
|
||||
export const ARTEN = ['ferienwohnung', 'monteurzimmer', 'pension', 'sonstiges']
|
||||
export const ART_NAMEN = { ferienwohnung: 'Ferienwohnung oder Ferienhaus', monteurzimmer: 'Monteurwohnung', pension: 'Pension oder Gästezimmer', sonstiges: 'Sonstiges' }
|
||||
/** Das Portal sendet und liest 'monteur' (ui-erwartungen.md); gespeichert wird 'monteurzimmer'. */
|
||||
/** Das Portal sendet 'monteurzimmer'; 'monteur' (aeltere Fassung, ui-erwartungen.md) wird weiter als Alias angenommen und gelesen. */
|
||||
const ART_ALIAS = { monteur: 'monteurzimmer' }
|
||||
export const PORTALE = ['booking', 'airbnb']
|
||||
export const PORTAL_NAMEN = { booking: 'Booking.com', airbnb: 'Airbnb', andere: 'Portale (ohne Angabe)' }
|
||||
@@ -43,7 +43,7 @@ const MELDUNG = {
|
||||
const stop = (status, text, code) => Object.assign(new Error(text), { status, ...(code ? { body: { code } } : {}) })
|
||||
const istObjekt = (wert) => wert !== null && typeof wert === 'object' && !Array.isArray(wert)
|
||||
|
||||
/** Versand (nur fuer Tests austauschbar: die Vorlagen K34 und T22 liegen auf einem anderen Strang). */
|
||||
/** Versand (nur fuer Tests austauschbar). */
|
||||
export const _versand = {
|
||||
admin: (nachricht) => sendAdminNotice(nachricht),
|
||||
kunde: (an, nachricht) => sendCustomerMail(an, nachricht),
|
||||
@@ -193,10 +193,13 @@ async function meldeTeam({ customerId, projectId, project, anfrage, person }) {
|
||||
kunde_name: kundeName || 'Kunde',
|
||||
email: person?.email || '',
|
||||
projekt: project?.projectName || projectId,
|
||||
art: ART_NAMEN[anfrage.art],
|
||||
einheiten: String(anfrage.einheiten),
|
||||
portale: anfrage.portale.length ? anfrage.portale.map((p) => PORTAL_NAMEN[p]).join(', ') : 'keine',
|
||||
nachricht: anfrage.nachricht || '–',
|
||||
// die Vorlage T22 kennt nur kunde_name, email, projekt, nachricht, woms_url: die Angaben stehen zusammen in der Nachricht
|
||||
nachricht: [
|
||||
`Art: ${ART_NAMEN[anfrage.art]}`,
|
||||
`Einheiten: ${anfrage.einheiten}`,
|
||||
`Portale: ${anfrage.portale.length ? anfrage.portale.map((p) => PORTAL_NAMEN[p]).join(', ') : 'keine'}`,
|
||||
...(anfrage.nachricht ? ['', anfrage.nachricht] : []),
|
||||
].join('\n'),
|
||||
woms_url: `${config.womsBaseUrl}/customers/${encodeURIComponent(customerId)}?tab=funktionen`,
|
||||
},
|
||||
})
|
||||
|
||||
@@ -17,6 +17,7 @@ const { config } = await import('../server/config.js')
|
||||
const { startTestApp, send, rawGet, post: rawPost } = await import('./support/testApp.js')
|
||||
const { customerCookie, kundenansichtCookie, seedFixtures, customers } = await import('./support/fixtures.js')
|
||||
const { deleteDocument } = await import('../server/services/appwriteAdmin.js')
|
||||
const { renderMail } = await import('../server/services/mailTemplates.js')
|
||||
const af = await import('../server/services/unterkunft/anfrageFunktion.js')
|
||||
const { freischaltbar } = await import('../server/services/unterkunft/freischaltung.js')
|
||||
const { unterkunftTicketDetails } = await import('../server/services/unterkunft/ticketDetails.js')
|
||||
@@ -43,15 +44,17 @@ const status = (opts = { cookie }) => send('GET', `/api/unterkunft/status?projec
|
||||
const entscheide = (b, opts = staff) => rawPost(`/api/team/unterkunft/c1/anfrage`, { projectId: P, ...b }, opts)
|
||||
const einst = () => aw.docs('ukEinstellungen').get(FEATURE) ?? null
|
||||
|
||||
// Mails: Vorlagen K34/T22 liegen auf einem anderen Strang, der Test prueft nur den Aufruf
|
||||
const aufrufe = { admin: [], kunde: [], adminFehler: false, kundeFehler: false }
|
||||
// Mails: die Aufrufe werden festgehalten und gegen die echten Vorlagen K34/T22 gerendert (problems muss leer bleiben)
|
||||
const aufrufe = { admin: [], kunde: [], probleme: [], adminFehler: false, kundeFehler: false }
|
||||
af._versand.admin = async (m) => {
|
||||
aufrufe.admin.push(m)
|
||||
aufrufe.probleme.push(...renderMail(m.template, m.values, m.blocks ?? {}).problems.map((x) => `${m.template}: ${x}`))
|
||||
if (aufrufe.adminFehler) throw new Error('SMTP')
|
||||
return { sent: true }
|
||||
}
|
||||
af._versand.kunde = async (an, m) => {
|
||||
aufrufe.kunde.push({ an, ...m })
|
||||
aufrufe.probleme.push(...renderMail(m.template, m.values, m.blocks ?? {}).problems.map((x) => `${m.template}: ${x}`))
|
||||
if (aufrufe.kundeFehler) throw new Error('SMTP')
|
||||
}
|
||||
|
||||
@@ -60,6 +63,7 @@ beforeEach(async () => {
|
||||
Object.assign(config.unterkunft, vorher, { mode: 'pilot', pilotEmails: [customers.c1.email] })
|
||||
resetUnterkunftRoutesForTests()
|
||||
aufrufe.admin.length = 0
|
||||
aufrufe.probleme.length = 0
|
||||
aufrufe.kunde.length = 0
|
||||
aufrufe.adminFehler = aufrufe.kundeFehler = false
|
||||
aw.seed('websiteProjects', { $id: P, customerId: 'c1', projectName: 'Donau', archived: false })
|
||||
@@ -101,9 +105,7 @@ test('Anfrage stellen: gespeichert, T22 ans Team, Status-Block fuer state off',
|
||||
assert.equal(aufrufe.admin.length, 1)
|
||||
assert.equal(aufrufe.admin[0].template, 'T22')
|
||||
assert.equal(aufrufe.admin[0].values.projekt, 'Donau')
|
||||
assert.equal(aufrufe.admin[0].values.einheiten, '3')
|
||||
assert.equal(aufrufe.admin[0].values.art, 'Monteurwohnung')
|
||||
assert.equal(aufrufe.admin[0].values.portale, 'Booking.com, Airbnb')
|
||||
assert.match(aufrufe.admin[0].values.nachricht, /^Art: Monteurwohnung\nEinheiten: 3\nPortale: Booking\.com, Airbnb/)
|
||||
assert.equal(aufrufe.admin[0].values.woms_url, `${config.womsBaseUrl}/customers/c1?tab=funktionen`)
|
||||
assert.equal(aufrufe.kunde.length, 0)
|
||||
const s = (await status()).body.anfrage
|
||||
@@ -307,3 +309,18 @@ test('ticketDetails: siteKey, Snippet, Schritte, Verweis, Anfrage; wirft nie', a
|
||||
const viaConfig = await config.features.unterkunft.ticket.details({ doc: doc(), project: {}, customer: null, feature: { key: 'Buchungskalender' } })
|
||||
assert.ok(viaConfig.includes('abcdefghijklmnop'))
|
||||
})
|
||||
|
||||
test('T22 und K34 (angenommen und abgelehnt) passen zu den Vorlagen: keine Platzhalter-Probleme', async () => {
|
||||
assert.equal((await stelle({ nachricht: 'Hallo\nZeile 2' })).status, 200)
|
||||
assert.equal((await entscheide({ entscheidung: 'ablehnen', begruendung: 'Passt nicht.' })).status, 200)
|
||||
assert.equal((await stelle()).status, 200)
|
||||
assert.equal((await entscheide({ entscheidung: 'annehmen' })).status, 200)
|
||||
assert.deepEqual(aufrufe.admin.map((m) => m.template), ['T22', 'T22'])
|
||||
assert.deepEqual(aufrufe.kunde.map((m) => m.template), ['K34', 'K34'])
|
||||
assert.deepEqual(aufrufe.probleme, [])
|
||||
const t22 = renderMail('T22', aufrufe.admin[0].values, {})
|
||||
assert.match(t22.text, /Art: Ferienwohnung oder Ferienhaus/)
|
||||
assert.match(t22.text, /Hallo/)
|
||||
const k34 = renderMail('K34', aufrufe.kunde[1].values, aufrufe.kunde[1].blocks)
|
||||
assert.match(k34.text, /199 €/)
|
||||
})
|
||||
Reference in new issue
Block a user