Buchungskalender: Preisrechnung nachgeschärft (Summe, Kleinunternehmer, Vollständigkeit)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
knsoandClaude Opus 5.5 committed 2026-10-07 13:49:20 +00:00
1 parent 84e7a99f41
commit c38c8e7c13
2 files changed
+51 -9

No files matched your search

+23 -9
View File
@@ -15,9 +15,12 @@ function staffelPreis(staffeln, n) {
export function berechnePreis({ preise, von, bis, personen }) {
const n = naechte(von, bis)
const klein = preise.steuerart === 'kleinunternehmer'
const satzUe = klein ? 0 : preise.ustUebernachtung
const satzRe = klein ? 0 : preise.ustReinigung
const posten = []
const nachtPreis = staffelPreis(preise.staffeln, n)
posten.push({ text: `Übernachtung, ${n} Nächte`, menge: n, einzelCent: nachtPreis, ustProzent: preise.ustUebernachtung })
posten.push({ text: `Übernachtung, ${n} Nächte`, menge: n, einzelCent: nachtPreis, ustProzent: satzUe })
let basis = n * nachtPreis
const extra = Math.max(0, Number(personen) - Number(preise.personenInklusive))
if (extra > 0 && preise.aufpreisPersonNachtCent > 0) {
@@ -25,12 +28,12 @@ export function berechnePreis({ preise, von, bis, personen }) {
text: `Zusatzperson${extra > 1 ? 'en' : ''} (${extra}), ${n} Nächte`,
menge: extra * n,
einzelCent: preise.aufpreisPersonNachtCent,
ustProzent: preise.ustUebernachtung,
ustProzent: satzUe,
})
basis += extra * n * preise.aufpreisPersonNachtCent
}
if (preise.reinigungCent > 0) {
posten.push({ text: 'Endreinigung', menge: 1, einzelCent: preise.reinigungCent, ustProzent: preise.ustReinigung })
posten.push({ text: 'Endreinigung', menge: 1, einzelCent: preise.reinigungCent, ustProzent: satzRe })
}
if (preise.direktrabattProzent > 0) {
const rabatt = -Math.round((basis * preise.direktrabattProzent) / 100)
@@ -38,7 +41,7 @@ export function berechnePreis({ preise, von, bis, personen }) {
text: `Direktbuchungsrabatt ${preise.direktrabattProzent} %`,
menge: 1,
einzelCent: rabatt,
ustProzent: preise.ustUebernachtung,
ustProzent: satzUe,
})
}
return { naechte: n, posten, summen: summiere(posten, preise.steuerart) }
@@ -70,13 +73,13 @@ export function pruefePosten(posten, steuerart) {
if (!p || typeof p !== 'object') return fehler('Ungültiger Posten.')
const text = typeof p.text === 'string' ? p.text.trim() : ''
if (!text || text.length > textMax) return fehler(`Der Text eines Postens muss 1 bis ${textMax} Zeichen lang sein.`)
if (!Number.isInteger(p.menge) || p.menge < 1) return fehler('Die Menge muss eine positive ganze Zahl sein.')
if (!Number.isInteger(p.einzelCent)) return fehler('Der Einzelpreis ist ungültig.')
if (!Number.isSafeInteger(p.menge) || p.menge < 1 || p.menge > 1000) return fehler('Die Menge muss eine positive ganze Zahl sein.')
if (!Number.isSafeInteger(p.einzelCent) || Math.abs(p.einzelCent) > 10_000_000) return fehler('Der Einzelpreis ist ungültig.')
if (!SAETZE.includes(p.ustProzent)) return fehler('Der Steuersatz muss 0, 7 oder 19 sein.')
if (steuerart === 'kleinunternehmer' && p.ustProzent !== 0) return fehler('Bei Kleinunternehmern ist keine Umsatzsteuer erlaubt.')
sauber.push({ text, menge: p.menge, einzelCent: p.einzelCent, ustProzent: p.ustProzent })
}
if (sauber.reduce((a, p) => a + p.menge * p.einzelCent, 0) === 0) return fehler('Die Summe darf nicht 0 sein.')
if (sauber.reduce((a, p) => a + p.menge * p.einzelCent, 0) <= 0) return fehler('Die Summe muss größer als 0 sein.')
return { posten: sauber }
}
@@ -90,8 +93,19 @@ export function formatEuro(cent) {
export function preiseVollstaendig(preise) {
if (!preise || !Array.isArray(preise.staffeln) || preise.staffeln.length === 0) return false
if (!preise.staffeln.some((s) => s.abNaechten === 1)) return false
const ab = preise.staffeln.map((s) => s && s.abNaechten)
if (!ab.every((a) => Number.isInteger(a) && a > 0)) return false
if (new Set(ab).size !== ab.length || !ab.includes(1)) return false
if (!preise.staffeln.every((s) => Number.isInteger(s.preisProNachtCent) && s.preisProNachtCent > 0)) return false
if (!['regel', 'kleinunternehmer'].includes(preise.steuerart)) return false
return Number.isInteger(preise.personenInklusive) && preise.personenInklusive >= 1
if (!Number.isInteger(preise.personenInklusive) || preise.personenInklusive < 1) return false
const nn = (v) => Number.isInteger(v) && v >= 0
if (!nn(preise.reinigungCent) || !nn(preise.aufpreisPersonNachtCent)) return false
const r = preise.direktrabattProzent
if (!Number.isInteger(r) || r < 0 || r > 50) return false
if (preise.steuerart === 'regel') {
if (!SAETZE.includes(preise.ustUebernachtung)) return false
if (preise.reinigungCent > 0 && !SAETZE.includes(preise.ustReinigung)) return false
}
return true
}