Buchungskalender: Anfragen-Reiter – Erstattung und Fehlermeldungen

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
knsoandClaude Opus 5.5 committed 2026-10-07 14:12:37 +00:00
1 parent db9fc61894
commit 37cd312549
2 files changed
+21 -9

No files matched your search

+9 -8
View File
@@ -6,7 +6,8 @@
POST …/freigeben {posten,fristTage,nachricht} (=> { buchungsLink? }), …/ablehnen {text}, …/bezahlt, …/stornieren {grund,erstattungCent}.
Fremdtext (Gast, Nachricht) nur ueber textContent. render(panel, ctx) wie shop-tab-*.js. */
import { abschnitt, allgemeinerFehler, euroText, euroZuCent, fehlerKarte, feld, frage, h, zeigeFehler, datumText } from './shop-dom.js'
import { abschnitt, allgemeinerFehler, centZuEuro, euroZuCent, fehlerKarte, feld, frage, h, zeigeFehler, datumText } from './shop-dom.js'
import { fehlerFuerFormular } from './buchungen-fehler.js'
import { baueEditor, euroMitVorzeichen } from './buchungen-posten.js'
export const STATUS = {
@@ -142,7 +143,7 @@ export async function render(panel, ctx) {
feld('nachricht', 'Nachricht an den Gast (optional)', nachricht),
allgemeinerFehler())
const freigeben = h('button', {
type: 'button', class: 'kb-btn', 'data-aktion': 'freigeben', disabled: ctx.nurLesen && !ctx.abwickeln,
type: 'button', class: 'kb-btn', 'data-aktion': 'freigeben',
onclick: () => sendeFreigabe(a, editor, frist, nachricht, form, freigeben),
}, 'Freigeben')
const ablehnen = h('button', { type: 'button', class: 'kb-btn-outline', 'data-aktion': 'ablehnen', onclick: () => ablehnDialog(a, ablehnen) }, 'Ablehnen')
@@ -160,12 +161,12 @@ export async function render(panel, ctx) {
method: 'POST', body: { posten, fristTage: tage, nachricht: String(nachricht.value).trim() },
})
if (!ctx.aktuell()) return
ctx.zeigeMeldung('Freigegeben. Dein Gast hat den Buchungslink per Mail bekommen.', 'ok')
ctx.zeigeMeldung('Freigegeben. Der Buchungslink wurde an deinen Gast geschickt – falls die Mail nicht ankommt, kannst du ihn hier kopieren.', 'ok')
zeigeLink(antwort?.buchungsLink, a)
} catch (err) {
knopf.disabled = false
if (err.status === 409) zeigeFehler(form, { message: BELEGT, fehler: { _: BELEGT } })
else zeigeFehler(form, err)
else zeigeFehler(form, fehlerFuerFormular(err))
}
}
@@ -212,7 +213,7 @@ export async function render(panel, ctx) {
await zeigeListe()
} catch (err) {
ev.currentTarget.disabled = false
zeigeFehler(box, err)
zeigeFehler(box, fehlerFuerFormular(err))
}
},
}, 'Ablehnen'),
@@ -262,10 +263,10 @@ export async function render(panel, ctx) {
}
function stornoDialog(a, dialogEl, ausloeser) {
const online = a.bezahltVia === 'online'
const online = a.bezahltVia === 'stripe'
const grund = h('textarea', { id: 'bk-a-grund', rows: '3', maxlength: '500' })
const betrag = h('input', { type: 'text', inputmode: 'decimal', id: 'bk-a-erstattung', autocomplete: 'off' })
betrag.value = Number.isInteger(a.summen?.bruttoCent) ? `${Math.floor((a.summen.bruttoCent - (a.erstattetCent || 0)) / 100)},${String((a.summen.bruttoCent - (a.erstattetCent || 0)) % 100).padStart(2, '0')}` : ''
betrag.value = Number.isInteger(a.summen?.bruttoCent) ? centZuEuro(a.summen.bruttoCent - (a.erstattetCent || 0)) : ''
const box = frage('Buchung stornieren', h('p', { class: 'sh-hinweis' }, 'Der Gast bekommt eine Stornomail und eine Storno-Rechnung.'),
feld('grund', 'Grund', grund),
online ? feld('erstattungCent', 'Erstattung in Euro', betrag, 'Der Betrag geht an die Karte des Gastes zurück. 0 = keine Erstattung.') : null,
@@ -290,7 +291,7 @@ export async function render(panel, ctx) {
knopf.disabled = false
if (err.fehler === 'erstattung_fehlgeschlagen' || err.body?.fehler === 'erstattung_fehlgeschlagen') {
zeigeFehler(box, { message: 'Die Buchung ist storniert, aber die Erstattung ist fehlgeschlagen. Bitte versuch die Erstattung gleich noch einmal.', fehler: {} })
} else zeigeFehler(box, err)
} else zeigeFehler(box, fehlerFuerFormular(err))
}
},
}, 'Stornieren'),
+12 -1
View File
@@ -151,7 +151,7 @@ test('Gebucht: Rechnung-Link, „Als bezahlt (vor Ort)“, Storno ohne Erstattun
}))
test('Storno bei Online-Zahlung: Erstattungsbetrag wird gesendet', mit(server({
'GET /api/unterkunft/anfragen/a1': () => ({ body: gebucht({ status: 'bezahlt', zahlart: 'online', bezahltVia: 'online' }) }),
'GET /api/unterkunft/anfragen/a1': () => ({ body: gebucht({ status: 'bezahlt', zahlart: 'online', bezahltVia: 'stripe' }) }),
'POST /api/unterkunft/anfragen/a1/stornieren': () => ({ body: {} }),
}), async (fx) => {
const { panel } = await zeige(fx)
@@ -369,3 +369,14 @@ test('iCal: Import hinzufügen (POST), entfernen mit Rückfrage, Link erneuern m
await fx.ruhe()
assert.equal(posts(fx).filter((a) => a.url.includes('erneuern')).length, 1)
}))
test('Freigeben: Serverfehler 400 mit felder zeigt genau den Feldtext', mit(server({
'POST /api/unterkunft/anfragen/a1/freigeben': () => ({ status: 400, body: { fehler: 'ungueltig', felder: { posten: 'Die Summe muss größer als 0 sein.' } } }),
}), async (fx) => {
const { panel } = await zeige(fx)
await oeffne(fx, panel)
await fx.klick(aktion(fx, panel, 'freigeben'))
await fx.ruhe()
assert.equal(fx.text(fx.finde(panel, '[data-fehler="posten"]')), 'Die Summe muss größer als 0 sein.')
assert.equal(fx.text(fx.finde(panel, '[data-fehler="_"]')), '')
}))