1e221a3c2c
- Reisezeit 0 -> Vertriebsunterstützung 0 - Reisezeit < 2h -> Vertriebsunterstützung = Reisezeit (Feld gesperrt) - Reisezeit >= 2h -> Vertriebsunterstützung 2h, aber editierbar - Regel zentral in lib/calc.ts (applyVertriebsregel), im Formular interaktiv und in der API-Validierung erzwungen Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
79 lines
2.4 KiB
TypeScript
79 lines
2.4 KiB
TypeScript
// Reine Hilfsfunktionen für Datum-/Zeit-Berechnungen (ohne DB-Zugriff).
|
||
|
||
const WOCHENTAGE = [
|
||
'Sonntag',
|
||
'Montag',
|
||
'Dienstag',
|
||
'Mittwoch',
|
||
'Donnerstag',
|
||
'Freitag',
|
||
'Samstag',
|
||
];
|
||
|
||
/** "HH:MM" → Minuten seit Mitternacht, oder null bei ungültiger Eingabe. */
|
||
export function parseHM(hm: string): number | null {
|
||
const m = /^(\d{1,2}):(\d{2})$/.exec(hm ?? '');
|
||
if (!m) return null;
|
||
const h = Number(m[1]);
|
||
const min = Number(m[2]);
|
||
if (h < 0 || h > 23 || min < 0 || min > 59) return null;
|
||
return h * 60 + min;
|
||
}
|
||
|
||
/**
|
||
* Differenz zwischen Beginn und Ende in dezimalen Stunden.
|
||
* Gibt 0 zurück, wenn eine Zeit ungültig ist. Ende vor Beginn ⇒ 0.
|
||
*/
|
||
export function toDecimalHours(beginn: string, ende: string): number {
|
||
const b = parseHM(beginn);
|
||
const e = parseHM(ende);
|
||
if (b === null || e === null) return 0;
|
||
const diff = e - b;
|
||
if (diff <= 0) return 0;
|
||
return diff / 60;
|
||
}
|
||
|
||
/** Mehrarbeit = Arbeitszeit − 8 Stunden − Pause (kann negativ sein). */
|
||
export function mehrarbeit(arbeitszeitStd: number, pauseStd: number): number {
|
||
return arbeitszeitStd - 8 - pauseStd;
|
||
}
|
||
|
||
/** True, wenn sowohl Beginn als auch Ende gültige Uhrzeiten sind (beide angegeben). */
|
||
export function hatZeiten(beginn: string, ende: string): boolean {
|
||
return parseHM(beginn) !== null && parseHM(ende) !== null;
|
||
}
|
||
|
||
/** True, wenn die Vertriebsunterstützung bei dieser Reisezeit frei änderbar ist (Reisezeit ≥ 2h). */
|
||
export function vertriebEditierbar(reisezeit: number): boolean {
|
||
return reisezeit >= 2;
|
||
}
|
||
|
||
/**
|
||
* Vertriebsunterstützung an die Reisezeit koppeln:
|
||
* Reisezeit = 0 → 0
|
||
* 0 < Reisezeit < 2 → = Reisezeit
|
||
* Reisezeit ≥ 2 → vorhandener Wert (änderbar), Standard 2
|
||
*/
|
||
export function applyVertriebsregel(reisezeit: number, vorhanden: number): number {
|
||
if (reisezeit <= 0) return 0;
|
||
if (reisezeit < 2) return reisezeit;
|
||
return vorhanden;
|
||
}
|
||
|
||
/** Deutscher Wochentagsname für ein "YYYY-MM-DD"-Datum, oder "" bei ungültig. */
|
||
export function weekdayName(datum: string): string {
|
||
const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(datum ?? '');
|
||
if (!m) return '';
|
||
const d = new Date(Number(m[1]), Number(m[2]) - 1, Number(m[3]));
|
||
if (isNaN(d.getTime())) return '';
|
||
return WOCHENTAGE[d.getDay()];
|
||
}
|
||
|
||
/** Dezimalstunden deutsch formatieren, z.B. 0.5 → "0,5". */
|
||
export function formatHours(value: number): string {
|
||
return value.toLocaleString('de-DE', {
|
||
minimumFractionDigits: 1,
|
||
maximumFractionDigits: 2,
|
||
});
|
||
}
|