Change weekend deduction from 1.0 to 2.0 units

Co-authored-by: Kenearos <86194771+Kenearos@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2025-12-12 11:36:24 +00:00
parent 86cd0ae4a7
commit d6372fe2e2
11 changed files with 32 additions and 32 deletions

View file

@ -26,7 +26,7 @@ Added native Android mobile app for duty roster management with the same NRW Var
- Same WT-Tag classification - Same WT-Tag classification
- Same compensation rates (WT: 250€, WE: 450€) - Same compensation rates (WT: 250€, WE: 450€)
- Same threshold logic (≥ 2.0 WE units) - Same threshold logic (≥ 2.0 WE units)
- Same deduction rules (1.0 unit, Friday priority) - Same deduction rules (2.0 units, Friday priority)
- Same Variante 2 behavior (no WE compensation below threshold) - Same Variante 2 behavior (no WE compensation below threshold)
**Testing:** **Testing:**

View file

@ -26,7 +26,7 @@ Native Android-App für mobiles Dienstplan-Management. Siehe [android-app/README
- ✅ Automatische Erkennung von Wochenenden (FrSo), Feiertagen und Vortagen - ✅ Automatische Erkennung von Wochenenden (FrSo), Feiertagen und Vortagen
- ✅ Vergütungslogik: WT 250€, WE 450€ (nur ab Schwelle ≥ 2,0 WE-Einheiten) - ✅ Vergütungslogik: WT 250€, WE 450€ (nur ab Schwelle ≥ 2,0 WE-Einheiten)
- ✅ Abzug 1,0 WE-Einheit (Freitag-Priorität) nach Erreichen der Schwelle - ✅ Abzug 2,0 WE-Einheiten (Freitag-Priorität) nach Erreichen der Schwelle
- ✅ Vorbefüllte Monatsvorlagen mit allen Datumswerten - ✅ Vorbefüllte Monatsvorlagen mit allen Datumswerten
- ✅ Excel-kompatibel (ohne Office 365 Funktionen) - ✅ Excel-kompatibel (ohne Office 365 Funktionen)

View file

@ -30,7 +30,7 @@ Hinweise:
- **WE** (WE-Tag): - **WE** (WE-Tag):
- Wenn Monats-Summe WE-Einheiten < 2,0 Auszahlung 0 für alle WE-Einheiten. - Wenn Monats-Summe WE-Einheiten < 2,0 Auszahlung 0 für alle WE-Einheiten.
- Wenn Monats-Summe WE-Einheiten ≥ 2,0 → Auszahlung 450 €/WE-Einheit, - Wenn Monats-Summe WE-Einheiten ≥ 2,0 → Auszahlung 450 €/WE-Einheit,
anschließend Abzug genau 1,0 WE-Einheit (max. 1× pro Person/Monat). anschließend Abzug genau 2,0 WE-Einheiten (max. 1× pro Person/Monat).
- Abzugs-Priorität: zuerst aus Freitag-WE-Einheiten, Rest aus den übrigen WE-Einheiten (Sa/So/Feiertag/Vortag). Chronologie muss nicht nachgebildet werden; es genügt die Priorität nach Kategorie. - Abzugs-Priorität: zuerst aus Freitag-WE-Einheiten, Rest aus den übrigen WE-Einheiten (Sa/So/Feiertag/Vortag). Chronologie muss nicht nachgebildet werden; es genügt die Priorität nach Kategorie.
### Splits/Anteile ### Splits/Anteile
@ -51,7 +51,7 @@ Hinweise:
- Satz_WT = 250 - Satz_WT = 250
- Satz_WE = 450 - Satz_WE = 450
- WE_Schwelle = 2,0 - WE_Schwelle = 2,0
- Abzug_nach_WE_Schwelle = 1,0 - Abzug_nach_WE_Schwelle = 2,0
- BL_Auswahl = Dropdown (z. B. BW, BY, BE, …) - BL_Auswahl = Dropdown (z. B. BW, BY, BE, …)
- Monat_Auswahl = Datum (erster Tag des Zielmonats, z. B. 01.11.2025) - Monat_Auswahl = Datum (erster Tag des Zielmonats, z. B. 01.11.2025)
- Variante = 2 (fix auf „streng") - Variante = 2 (fix auf „streng")

View file

@ -20,7 +20,7 @@ Same as the Python/Excel implementation:
- **WT-Tag** (Weekday): All other days - **WT-Tag** (Weekday): All other days
- **WT compensation**: Always 250€ per unit - **WT compensation**: Always 250€ per unit
- **WE compensation**: Only paid if monthly total ≥ 2.0 WE units - **WE compensation**: Only paid if monthly total ≥ 2.0 WE units
- If threshold reached: 450€ per WE unit, then deduct exactly 1.0 WE unit - If threshold reached: 450€ per WE unit, then deduct exactly 2.0 WE units
- Deduction priority: Friday first, then other WE days - Deduction priority: Friday first, then other WE days
- Below threshold: 0€ for WE shifts - Below threshold: 0€ for WE shifts
@ -123,7 +123,7 @@ Edit `PayrollCalculator.kt` and modify the constants:
- `RATE_WT`: Weekday rate (default 250€) - `RATE_WT`: Weekday rate (default 250€)
- `RATE_WE`: Weekend rate (default 450€) - `RATE_WE`: Weekend rate (default 450€)
- `WE_THRESHOLD`: Threshold for WE compensation (default 2.0) - `WE_THRESHOLD`: Threshold for WE compensation (default 2.0)
- `DEDUCTION_AFTER_THRESHOLD`: Deduction amount (default 1.0) - `DEDUCTION_AFTER_THRESHOLD`: Deduction amount (default 2.0)
### Adding Holidays ### Adding Holidays

View file

@ -14,7 +14,7 @@ import kotlin.math.min
* - WT-Tag (Weekday): All other days * - WT-Tag (Weekday): All other days
* - WT compensation: Always 250 per unit * - WT compensation: Always 250 per unit
* - WE compensation: Only paid if monthly total >= 2.0 WE units (threshold) * - WE compensation: Only paid if monthly total >= 2.0 WE units (threshold)
* - If threshold reached: 450 per WE unit, then deduct exactly 1.0 WE unit * - If threshold reached: 450 per WE unit, then deduct exactly 2.0 WE units
* - Deduction priority: Friday first, then other WE days * - Deduction priority: Friday first, then other WE days
* - Below threshold: 0 for WE shifts (NOT converted to WT) * - Below threshold: 0 for WE shifts (NOT converted to WT)
*/ */
@ -24,7 +24,7 @@ class PayrollCalculator {
private const val RATE_WT = 250.0 // Satz_WT private const val RATE_WT = 250.0 // Satz_WT
private const val RATE_WE = 450.0 // Satz_WE private const val RATE_WE = 450.0 // Satz_WE
private const val WE_THRESHOLD = 2.0 // WE_Schwelle private const val WE_THRESHOLD = 2.0 // WE_Schwelle
private const val DEDUCTION_AFTER_THRESHOLD = 1.0 // Abzug_nach_WE_Schwelle private const val DEDUCTION_AFTER_THRESHOLD = 2.0 // Abzug_nach_WE_Schwelle
private const val TOLERANCE = 0.0001 // For floating-point comparisons private const val TOLERANCE = 0.0001 // For floating-point comparisons
} }

View file

@ -39,7 +39,7 @@ Die Web-App implementiert eine vereinfachte Logik:
2. **Bonusberechnung**: 2. **Bonusberechnung**:
- Mindestens **2.0 qualifizierende Tage** erforderlich - Mindestens **2.0 qualifizierende Tage** erforderlich
- Bei Erreichen: **1.0 qualifizierender Tag** wird abgezogen - Bei Erreichen: **2.0 qualifizierende Tage** werden abgezogen
- **Alle übrigen Tage** werden bezahlt: - **Alle übrigen Tage** werden bezahlt:
- Normale Tage (Mo-Do, kein Feiertag): 250€ - Normale Tage (Mo-Do, kein Feiertag): 250€
- Qualifizierende Tage: 450€ - Qualifizierende Tage: 450€
@ -56,7 +56,7 @@ Die ältere Implementierung nutzt eine andere Logik:
- **WT-Tage** werden **immer** mit 250€ vergütet - **WT-Tage** werden **immer** mit 250€ vergütet
- **WE-Tage** nur vergütet wenn ≥ 2.0 WE-Einheiten: - **WE-Tage** nur vergütet wenn ≥ 2.0 WE-Einheiten:
- Bei Erreichen: 450€ pro WE-Tag - Bei Erreichen: 450€ pro WE-Tag
- Dann Abzug von 1.0 WE-Einheit (Freitag-Priorität) - Dann Abzug von 2.0 WE-Einheiten (Freitag-Priorität)
- Unter Schwellenwert: WE-Dienste = 0€ (nicht als WT vergütet) - Unter Schwellenwert: WE-Dienste = 0€ (nicht als WT vergütet)
### Wichtiger Unterschied - Beispiel ### Wichtiger Unterschied - Beispiel
@ -168,7 +168,7 @@ adb install app/build/outputs/apk/debug/app-debug.apk
### Testfall 1: Schwellenwert genau erreicht ### Testfall 1: Schwellenwert genau erreicht
- 1 × Freitag (1.0) - 1 × Freitag (1.0)
- 1 × Samstag (1.0) - 1 × Samstag (1.0)
- Erwartung: 2.0 qualifizierende Tage → 1.0 abgezogen → 1.0 × 450€ = **450€** - Erwartung: 2.0 qualifizierende Tage → 2.0 abgezogen → 0.0 × 450€ = **0€**
### Testfall 2: Schwellenwert nicht erreicht ### Testfall 2: Schwellenwert nicht erreicht
- 1 × Samstag (1.0) - 1 × Samstag (1.0)
@ -179,13 +179,13 @@ adb install app/build/outputs/apk/debug/app-debug.apk
- 2 × Montag (2.0) - 2 × Montag (2.0)
- 2 × Samstag (2.0) - 2 × Samstag (2.0)
- Erwartung: - Erwartung:
- 2.0 qualifizierende → -1.0 Abzug → 1.0 bezahlt - 2.0 qualifizierende → -2.0 Abzug → 0.0 bezahlt
- Bonus: (2 × 250€) + (1 × 450€) = **950€** - Bonus: (2 × 250€) + (0 × 450€) = **500€**
### Testfall 4: Feiertag + Vortag ### Testfall 4: Feiertag + Vortag
- 1 × Donnerstag vor Karfreitag (qualifizierend!) - 1 × Donnerstag vor Karfreitag (qualifizierend!)
- 1 × Karfreitag (Feiertag, qualifizierend!) - 1 × Karfreitag (Feiertag, qualifizierend!)
- Erwartung: 2.0 qualifizierende → -1.0 → 1.0 × 450€ = **450€** - Erwartung: 2.0 qualifizierende → -2.0 → 0.0 × 450€ = **0€**
## Häufige Anpassungen ## Häufige Anpassungen
@ -203,14 +203,14 @@ this.RATE_WEEKEND = 500; // Statt 450
``` ```
### Abzug ändern (Web-App) ### Abzug ändern (Web-App)
Aktuell ist der Abzug fest auf 1.0 kodiert in `webapp/calculator.js`, Zeile 66: Aktuell ist der Abzug fest auf 2.0 kodiert in `webapp/calculator.js`, Zeile 112:
```javascript ```javascript
qualifyingDaysDeducted = 1.0; qualifyingDaysDeducted = 2.0;
``` ```
Um dies flexibel zu machen, könnte man hinzufügen: Um dies flexibel zu machen, könnte man hinzufügen:
```javascript ```javascript
this.DEDUCTION_AMOUNT = 1.0; // Im Constructor this.DEDUCTION_AMOUNT = 2.0; // Im Constructor
// Dann verwenden: // Dann verwenden:
qualifyingDaysDeducted = this.DEDUCTION_AMOUNT; qualifyingDaysDeducted = this.DEDUCTION_AMOUNT;
``` ```

View file

@ -61,7 +61,7 @@ def _populate_readme(ws):
rules = [ rules = [
"WE-Tag = Fr/Sa/So/Feiertag/Vortag (BL-abhängig).", "WE-Tag = Fr/Sa/So/Feiertag/Vortag (BL-abhängig).",
"Variante 2 (streng): WE werden nur vergütet, wenn im Monat ≥ 2,0 WE-Einheiten erreicht werden;", "Variante 2 (streng): WE werden nur vergütet, wenn im Monat ≥ 2,0 WE-Einheiten erreicht werden;",
"dann 450 €/WE und Abzug 1,0 (Freitag zuerst). WT werden immer mit 250 € vergütet.", "dann 450 €/WE und Abzug 2,0 (Freitag zuerst). WT werden immer mit 250 € vergütet.",
"Splits anteilig. Monat und Bundesland in 'Regeln' wählen.", "Splits anteilig. Monat und Bundesland in 'Regeln' wählen.",
"", "",
"Schritte:", "Schritte:",
@ -83,7 +83,7 @@ def _populate_rules(ws):
("Satz_WT", 250, "Euro für jeden Werktagsdienst (MoDo, sofern kein WE-Tag)"), ("Satz_WT", 250, "Euro für jeden Werktagsdienst (MoDo, sofern kein WE-Tag)"),
("Satz_WE", 450, "Euro für jeden WE-Tag (FrSo, Feiertag, Vortag Feiertag)"), ("Satz_WE", 450, "Euro für jeden WE-Tag (FrSo, Feiertag, Vortag Feiertag)"),
("WE_Schwelle", 2.0, "Ab dieser WE-Anzahl wird vergütet (sonst 0 €)"), ("WE_Schwelle", 2.0, "Ab dieser WE-Anzahl wird vergütet (sonst 0 €)"),
("Abzug_nach_WE_Schwelle", 1.0, "Einheiten, die nach Erreichen der Schwelle abgezogen werden"), ("Abzug_nach_WE_Schwelle", 2.0, "Einheiten, die nach Erreichen der Schwelle abgezogen werden"),
("BL_Auswahl", "NRW", "Bundesland (steuert Feiertage)"), ("BL_Auswahl", "NRW", "Bundesland (steuert Feiertage)"),
("Monat_Auswahl", date(2025, 11, 1), "Erster Tag des Zielmonats"), ("Monat_Auswahl", date(2025, 11, 1), "Erster Tag des Zielmonats"),
("Variante", 2, "Fix: 2 = streng (WE nur bei Schwelle ≥ 2,0)"), ("Variante", 2, "Fix: 2 = streng (WE nur bei Schwelle ≥ 2,0)"),

View file

@ -14,7 +14,7 @@ from collections import defaultdict
SATZ_WT = 250 # Euro für Werktag SATZ_WT = 250 # Euro für Werktag
SATZ_WE = 450 # Euro für Wochenende SATZ_WE = 450 # Euro für Wochenende
WE_SCHWELLE = 2.0 # Mindestanzahl WE-Dienste für Vergütung WE_SCHWELLE = 2.0 # Mindestanzahl WE-Dienste für Vergütung
ABZUG = 1.0 # Abzug nach Erreichen der Schwelle ABZUG = 2.0 # Abzug nach Erreichen der Schwelle
def load_holidays(wb): def load_holidays(wb):

View file

@ -21,7 +21,7 @@ Eine Web-Anwendung zur Berechnung von Bonuszahlungen für Wochenend- und Feierta
### Bonusberechnung ### Bonusberechnung
1. **Schwellenwert**: Mindestens **2.0 qualifizierende Tage** im Monat erforderlich 1. **Schwellenwert**: Mindestens **2.0 qualifizierende Tage** im Monat erforderlich
2. **Abzug**: Bei Erreichen des Schwellenwerts wird **1.0 qualifizierender Tag** abgezogen 2. **Abzug**: Bei Erreichen des Schwellenwerts werden **2.0 qualifizierende Tage** abgezogen
3. **Vergütung**: 3. **Vergütung**:
- Normale Tage: **250€** pro Tag - Normale Tage: **250€** pro Tag
- Qualifizierende Tage (WE/Feiertag): **450€** pro Tag - Qualifizierende Tage (WE/Feiertag): **450€** pro Tag
@ -34,9 +34,9 @@ Mitarbeiter hat im Monat:
**Berechnung**: **Berechnung**:
- Qualifizierende Tage: 3.0 (Schwellenwert erreicht ✓) - Qualifizierende Tage: 3.0 (Schwellenwert erreicht ✓)
- Abzug: -1.0 qualifizierender Tag - Abzug: -2.0 qualifizierende Tage
- Bezahlt: 3 normale Tage + 2 qualifizierende Tage - Bezahlt: 3 normale Tage + 1 qualifizierender Tag
- **Bonus**: (3 × 250€) + (2 × 450€) = **1.650€** - **Bonus**: (3 × 250€) + (1 × 450€) = **1.200€**
## Installation & Nutzung ## Installation & Nutzung

View file

@ -40,8 +40,8 @@ Automatische Test Suite für die Web-App.
### 3. Calculator - Bonusberechnung ### 3. Calculator - Bonusberechnung
**Schwellenwert-Tests:** **Schwellenwert-Tests:**
- ✅ Unter Schwellenwert (1.0 WE-Tag) → 0€ - ✅ Unter Schwellenwert (1.0 WE-Tag) → 0€
- ✅ Genau Schwellenwert (2.0 WE-Tage) → 450€ - ✅ Genau Schwellenwert (2.0 WE-Tage) → 0€
- ✅ Über Schwellenwert (3.0 WE-Tage) → 900€ - ✅ Über Schwellenwert (3.0 WE-Tage) → 450€
**Gemischte Dienste:** **Gemischte Dienste:**
- ✅ Normale Tage + WE-Tage korrekt berechnet - ✅ Normale Tage + WE-Tage korrekt berechnet
@ -84,8 +84,8 @@ Dienste:
Erwartung: Erwartung:
- Qualifizierende Tage: 2.0 - Qualifizierende Tage: 2.0
- Schwellenwert: ✅ Erreicht - Schwellenwert: ✅ Erreicht
- Abzug: -1.0 - Abzug: -2.0
- Bezahlt: 1.0 × 450€ = 450€ - Bezahlt: 0.0 × 450€ = 0€
``` ```
### Beispiel 2: Gemischte Dienste ### Beispiel 2: Gemischte Dienste
@ -96,8 +96,8 @@ Dienste:
Erwartung: Erwartung:
- Normale Tage: 2.0 × 250€ = 500€ - Normale Tage: 2.0 × 250€ = 500€
- Qualifizierende Tage: (2.0 - 1.0) × 450€ = 450€ - Qualifizierende Tage: (2.0 - 2.0) × 450€ = 0€
- Gesamt: 950€ - Gesamt: 500€
``` ```
### Beispiel 3: Halbe Dienste ### Beispiel 3: Halbe Dienste

View file

@ -108,8 +108,8 @@ class BonusCalculator {
let totalDeduction = 0; let totalDeduction = 0;
if (thresholdReached) { if (thresholdReached) {
// Deduct 1.0 qualifying day with Friday priority // Deduct 2.0 qualifying days with Friday priority
totalDeduction = 1.0; totalDeduction = 2.0;
// First deduct from Friday // First deduct from Friday
deductionFromFriday = Math.min(totalDeduction, qualifyingDaysFriday); deductionFromFriday = Math.min(totalDeduction, qualifyingDaysFriday);