From 86cd0ae4a77e717a38075e56a4e5fe439d82178f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 12 Dec 2025 11:29:31 +0000 Subject: [PATCH 1/4] Initial plan From d6372fe2e25612edacdef64de48883b4ae8f61d8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 12 Dec 2025 11:36:24 +0000 Subject: [PATCH 2/4] Change weekend deduction from 1.0 to 2.0 units Co-authored-by: Kenearos <86194771+Kenearos@users.noreply.github.com> --- CHANGELOG.md | 2 +- README.md | 2 +- SPECIFICATION.md | 4 ++-- android-app/README.md | 4 ++-- .../dienstplan/nrw/data/PayrollCalculator.kt | 4 ++-- claude.md | 18 +++++++++--------- src/build_template.py | 4 ++-- src/calculate.py | 2 +- webapp/README.md | 8 ++++---- webapp/TEST_GUIDE.md | 12 ++++++------ webapp/calculator.js | 4 ++-- 11 files changed, 32 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bb01259..bb5283e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,7 +26,7 @@ Added native Android mobile app for duty roster management with the same NRW Var - Same WT-Tag classification - Same compensation rates (WT: 250€, WE: 450€) - 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) **Testing:** diff --git a/README.md b/README.md index 1b333c7..69e94b4 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Native Android-App für mobiles Dienstplan-Management. Siehe [android-app/README - ✅ Automatische Erkennung von Wochenenden (Fr–So), Feiertagen und Vortagen - ✅ 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 - ✅ Excel-kompatibel (ohne Office 365 Funktionen) diff --git a/SPECIFICATION.md b/SPECIFICATION.md index acbc563..6021df3 100644 --- a/SPECIFICATION.md +++ b/SPECIFICATION.md @@ -30,7 +30,7 @@ Hinweise: - **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 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. ### Splits/Anteile @@ -51,7 +51,7 @@ Hinweise: - Satz_WT = 250 - Satz_WE = 450 - WE_Schwelle = 2,0 -- Abzug_nach_WE_Schwelle = 1,0 +- Abzug_nach_WE_Schwelle = 2,0 - BL_Auswahl = Dropdown (z. B. BW, BY, BE, …) - Monat_Auswahl = Datum (erster Tag des Zielmonats, z. B. 01.11.2025) - Variante = 2 (fix auf „streng") diff --git a/android-app/README.md b/android-app/README.md index 7694129..062be7d 100644 --- a/android-app/README.md +++ b/android-app/README.md @@ -20,7 +20,7 @@ Same as the Python/Excel implementation: - **WT-Tag** (Weekday): All other days - **WT compensation**: Always 250€ per unit - **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 - Below threshold: 0€ for WE shifts @@ -123,7 +123,7 @@ Edit `PayrollCalculator.kt` and modify the constants: - `RATE_WT`: Weekday rate (default 250€) - `RATE_WE`: Weekend rate (default 450€) - `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 diff --git a/android-app/app/src/main/java/com/dienstplan/nrw/data/PayrollCalculator.kt b/android-app/app/src/main/java/com/dienstplan/nrw/data/PayrollCalculator.kt index 9323553..5d8f932 100644 --- a/android-app/app/src/main/java/com/dienstplan/nrw/data/PayrollCalculator.kt +++ b/android-app/app/src/main/java/com/dienstplan/nrw/data/PayrollCalculator.kt @@ -14,7 +14,7 @@ import kotlin.math.min * - WT-Tag (Weekday): All other days * - WT compensation: Always 250€ per unit * - 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 * - 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_WE = 450.0 // Satz_WE 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 } diff --git a/claude.md b/claude.md index 656cd19..9fde052 100644 --- a/claude.md +++ b/claude.md @@ -39,7 +39,7 @@ Die Web-App implementiert eine vereinfachte Logik: 2. **Bonusberechnung**: - 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: - Normale Tage (Mo-Do, kein Feiertag): 250€ - Qualifizierende Tage: 450€ @@ -56,7 +56,7 @@ Die ältere Implementierung nutzt eine andere Logik: - **WT-Tage** werden **immer** mit 250€ vergütet - **WE-Tage** nur vergütet wenn ≥ 2.0 WE-Einheiten: - 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) ### Wichtiger Unterschied - Beispiel @@ -168,7 +168,7 @@ adb install app/build/outputs/apk/debug/app-debug.apk ### Testfall 1: Schwellenwert genau erreicht - 1 × Freitag (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 - 1 × Samstag (1.0) @@ -179,13 +179,13 @@ adb install app/build/outputs/apk/debug/app-debug.apk - 2 × Montag (2.0) - 2 × Samstag (2.0) - Erwartung: - - 2.0 qualifizierende → -1.0 Abzug → 1.0 bezahlt - - Bonus: (2 × 250€) + (1 × 450€) = **950€** + - 2.0 qualifizierende → -2.0 Abzug → 0.0 bezahlt + - Bonus: (2 × 250€) + (0 × 450€) = **500€** ### Testfall 4: Feiertag + Vortag - 1 × Donnerstag vor Karfreitag (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 @@ -203,14 +203,14 @@ this.RATE_WEEKEND = 500; // Statt 450 ``` ### 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 -qualifyingDaysDeducted = 1.0; +qualifyingDaysDeducted = 2.0; ``` Um dies flexibel zu machen, könnte man hinzufügen: ```javascript -this.DEDUCTION_AMOUNT = 1.0; // Im Constructor +this.DEDUCTION_AMOUNT = 2.0; // Im Constructor // Dann verwenden: qualifyingDaysDeducted = this.DEDUCTION_AMOUNT; ``` diff --git a/src/build_template.py b/src/build_template.py index e62a4f7..7a6d1b5 100644 --- a/src/build_template.py +++ b/src/build_template.py @@ -61,7 +61,7 @@ def _populate_readme(ws): rules = [ "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;", - "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.", "", "Schritte:", @@ -83,7 +83,7 @@ def _populate_rules(ws): ("Satz_WT", 250, "Euro für jeden Werktagsdienst (Mo–Do, sofern kein WE-Tag)"), ("Satz_WE", 450, "Euro für jeden WE-Tag (Fr–So, Feiertag, Vortag Feiertag)"), ("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)"), ("Monat_Auswahl", date(2025, 11, 1), "Erster Tag des Zielmonats"), ("Variante", 2, "Fix: 2 = streng (WE nur bei Schwelle ≥ 2,0)"), diff --git a/src/calculate.py b/src/calculate.py index 1faa1f5..f2464e7 100644 --- a/src/calculate.py +++ b/src/calculate.py @@ -14,7 +14,7 @@ from collections import defaultdict SATZ_WT = 250 # Euro für Werktag SATZ_WE = 450 # Euro für Wochenende 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): diff --git a/webapp/README.md b/webapp/README.md index e3779fc..12e74a0 100644 --- a/webapp/README.md +++ b/webapp/README.md @@ -21,7 +21,7 @@ Eine Web-Anwendung zur Berechnung von Bonuszahlungen für Wochenend- und Feierta ### Bonusberechnung 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**: - Normale Tage: **250€** pro Tag - Qualifizierende Tage (WE/Feiertag): **450€** pro Tag @@ -34,9 +34,9 @@ Mitarbeiter hat im Monat: **Berechnung**: - Qualifizierende Tage: 3.0 (Schwellenwert erreicht ✓) -- Abzug: -1.0 qualifizierender Tag -- Bezahlt: 3 normale Tage + 2 qualifizierende Tage -- **Bonus**: (3 × 250€) + (2 × 450€) = **1.650€** +- Abzug: -2.0 qualifizierende Tage +- Bezahlt: 3 normale Tage + 1 qualifizierender Tag +- **Bonus**: (3 × 250€) + (1 × 450€) = **1.200€** ## Installation & Nutzung diff --git a/webapp/TEST_GUIDE.md b/webapp/TEST_GUIDE.md index 4ef68c1..b8e29f0 100644 --- a/webapp/TEST_GUIDE.md +++ b/webapp/TEST_GUIDE.md @@ -40,8 +40,8 @@ Automatische Test Suite für die Web-App. ### 3. Calculator - Bonusberechnung **Schwellenwert-Tests:** - ✅ Unter Schwellenwert (1.0 WE-Tag) → 0€ -- ✅ Genau Schwellenwert (2.0 WE-Tage) → 450€ -- ✅ Über Schwellenwert (3.0 WE-Tage) → 900€ +- ✅ Genau Schwellenwert (2.0 WE-Tage) → 0€ +- ✅ Über Schwellenwert (3.0 WE-Tage) → 450€ **Gemischte Dienste:** - ✅ Normale Tage + WE-Tage korrekt berechnet @@ -84,8 +84,8 @@ Dienste: Erwartung: - Qualifizierende Tage: 2.0 - Schwellenwert: ✅ Erreicht -- Abzug: -1.0 -- Bezahlt: 1.0 × 450€ = 450€ +- Abzug: -2.0 +- Bezahlt: 0.0 × 450€ = 0€ ``` ### Beispiel 2: Gemischte Dienste @@ -96,8 +96,8 @@ Dienste: Erwartung: - Normale Tage: 2.0 × 250€ = 500€ -- Qualifizierende Tage: (2.0 - 1.0) × 450€ = 450€ -- Gesamt: 950€ +- Qualifizierende Tage: (2.0 - 2.0) × 450€ = 0€ +- Gesamt: 500€ ``` ### Beispiel 3: Halbe Dienste diff --git a/webapp/calculator.js b/webapp/calculator.js index bc5c787..d705419 100644 --- a/webapp/calculator.js +++ b/webapp/calculator.js @@ -108,8 +108,8 @@ class BonusCalculator { let totalDeduction = 0; if (thresholdReached) { - // Deduct 1.0 qualifying day with Friday priority - totalDeduction = 1.0; + // Deduct 2.0 qualifying days with Friday priority + totalDeduction = 2.0; // First deduct from Friday deductionFromFriday = Math.min(totalDeduction, qualifyingDaysFriday); From 09ef077b677d4ade63d4fa32d259ea774eada25f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 12 Dec 2025 11:39:47 +0000 Subject: [PATCH 3/4] Update test expectations for 2.0 deduction Co-authored-by: Kenearos <86194771+Kenearos@users.noreply.github.com> --- .../dienstplan/nrw/PayrollCalculatorTest.kt | 22 ++-- test_deduction.py | 124 ++++++++++++++++++ webapp/test-suite.js | 30 ++--- 3 files changed, 150 insertions(+), 26 deletions(-) create mode 100644 test_deduction.py diff --git a/android-app/app/src/test/java/com/dienstplan/nrw/PayrollCalculatorTest.kt b/android-app/app/src/test/java/com/dienstplan/nrw/PayrollCalculatorTest.kt index 2403c0f..dbabf20 100644 --- a/android-app/app/src/test/java/com/dienstplan/nrw/PayrollCalculatorTest.kt +++ b/android-app/app/src/test/java/com/dienstplan/nrw/PayrollCalculatorTest.kt @@ -52,7 +52,7 @@ class PayrollCalculatorTest { /** * Test Case 2: Exactly at threshold (2.0 WE) - * Expected: WE payout = 450€ (1.0 unit after deduction), threshold reached + * Expected: WE payout = 0€ (0.0 units after deduction), threshold reached */ @Test fun testExactlyAtThreshold() { @@ -67,14 +67,14 @@ class PayrollCalculatorTest { val result = results[0] assertEquals(2.0, result.weTotal, 0.001) assertTrue(result.thresholdReached) - assertEquals(1.0, result.deductionTotal, 0.001) - assertEquals(1.0, result.wePaid, 0.001) - assertEquals(450.0, result.payoutWE, 0.001) + assertEquals(2.0, result.deductionTotal, 0.001) + assertEquals(0.0, result.wePaid, 0.001) + assertEquals(0.0, result.payoutWE, 0.001) } /** * Test Case 3: Over threshold (3.5 WE) - * Expected: WE payout = 1125€ (2.5 units after deduction) + * Expected: WE payout = 675€ (1.5 units after deduction) */ @Test fun testOverThreshold() { @@ -91,8 +91,8 @@ class PayrollCalculatorTest { val result = results[0] assertEquals(3.5, result.weTotal, 0.001) assertTrue(result.thresholdReached) - assertEquals(2.5, result.wePaid, 0.001) - assertEquals(1125.0, result.payoutWE, 0.001) + assertEquals(1.5, result.wePaid, 0.001) + assertEquals(675.0, result.payoutWE, 0.001) } /** @@ -115,8 +115,8 @@ class PayrollCalculatorTest { assertEquals(0.4, result.weFriday, 0.001) assertEquals(1.6, result.weOther, 0.001) assertEquals(0.4, result.deductionFriday, 0.001) // All Friday deducted first - assertEquals(0.6, result.deductionOther, 0.001) // Rest from other - assertEquals(1.0, result.wePaid, 0.001) + assertEquals(1.6, result.deductionOther, 0.001) // Rest from other (1.6 to reach 2.0 total) + assertEquals(0.0, result.wePaid, 0.001) } /** @@ -147,8 +147,8 @@ class PayrollCalculatorTest { // B: above threshold assertTrue(resultB.thresholdReached) assertEquals(2.5, resultB.weTotal, 0.001) - assertEquals(1.5, resultB.wePaid, 0.001) - assertEquals(675.0, resultB.payoutWE, 0.001) + assertEquals(0.5, resultB.wePaid, 0.001) + assertEquals(225.0, resultB.payoutWE, 0.001) } private fun parseDate(dateString: String): Date { diff --git a/test_deduction.py b/test_deduction.py new file mode 100644 index 0000000..b09ecfc --- /dev/null +++ b/test_deduction.py @@ -0,0 +1,124 @@ +#!/usr/bin/env python3 +""" +Test script to verify the weekend deduction change from 1.0 to 2.0 units. +""" + +from datetime import date +import sys +sys.path.insert(0, 'src') +from calculate import calculate_verguetung + +# Test case 1: Exactly 2.0 WE units (threshold reached) +# Expected: 2.0 WE - 2.0 deduction = 0.0 paid → 0€ for WE +print("=" * 60) +print("Test 1: Exactly 2.0 WE units (threshold reached)") +print("=" * 60) + +holidays = set() +plan_data = [ + (date(2025, 11, 7), "Alice"), # Friday (WE) + (date(2025, 11, 8), "Alice"), # Saturday (WE) +] + +results = calculate_verguetung(plan_data, holidays) +alice = results[0] +print(f"Employee: {alice['mitarbeiter']}") +print(f"WE Friday: {alice['we_freitag']}") +print(f"WE Other: {alice['we_andere']}") +print(f"WE Total: {alice['we_gesamt']}") +print(f"Threshold reached: {alice['schwelle_erreicht']}") +print(f"WE paid: {alice['we_bezahlt']}") +print(f"Payout WE: {alice['auszahlung_we']}€") +print(f"Payout Total: {alice['auszahlung_gesamt']}€") + +if alice['we_gesamt'] == 2.0 and alice['we_bezahlt'] == 0.0 and alice['auszahlung_we'] == 0: + print("✅ PASS: Correctly deducts 2.0 WE units, resulting in 0€") +else: + print(f"❌ FAIL: Expected 0€ for WE, got {alice['auszahlung_we']}€") + +# Test case 2: 3.0 WE units +# Expected: 3.0 WE - 2.0 deduction = 1.0 paid → 450€ +print("\n" + "=" * 60) +print("Test 2: 3.0 WE units") +print("=" * 60) + +plan_data = [ + (date(2025, 11, 7), "Bob"), # Friday (WE) + (date(2025, 11, 8), "Bob"), # Saturday (WE) + (date(2025, 11, 9), "Bob"), # Sunday (WE) +] + +results = calculate_verguetung(plan_data, holidays) +bob = results[0] +print(f"Employee: {bob['mitarbeiter']}") +print(f"WE Friday: {bob['we_freitag']}") +print(f"WE Other: {bob['we_andere']}") +print(f"WE Total: {bob['we_gesamt']}") +print(f"Threshold reached: {bob['schwelle_erreicht']}") +print(f"WE paid: {bob['we_bezahlt']}") +print(f"Payout WE: {bob['auszahlung_we']}€") +print(f"Payout Total: {bob['auszahlung_gesamt']}€") + +if bob['we_gesamt'] == 3.0 and bob['we_bezahlt'] == 1.0 and bob['auszahlung_we'] == 450: + print("✅ PASS: Correctly deducts 2.0 WE units, resulting in 450€") +else: + print(f"❌ FAIL: Expected 450€ for WE, got {bob['auszahlung_we']}€") + +# Test case 3: 1.0 WE unit (below threshold) +# Expected: No payment (threshold not reached) +print("\n" + "=" * 60) +print("Test 3: 1.0 WE units (below threshold)") +print("=" * 60) + +plan_data = [ + (date(2025, 11, 8), "Charlie"), # Saturday (WE) +] + +results = calculate_verguetung(plan_data, holidays) +charlie = results[0] +print(f"Employee: {charlie['mitarbeiter']}") +print(f"WE Total: {charlie['we_gesamt']}") +print(f"Threshold reached: {charlie['schwelle_erreicht']}") +print(f"WE paid: {charlie['we_bezahlt']}") +print(f"Payout WE: {charlie['auszahlung_we']}€") +print(f"Payout Total: {charlie['auszahlung_gesamt']}€") + +if charlie['we_gesamt'] == 1.0 and charlie['we_bezahlt'] == 0.0 and charlie['auszahlung_we'] == 0: + print("✅ PASS: Below threshold, no payment") +else: + print(f"❌ FAIL: Expected 0€, got {charlie['auszahlung_we']}€") + +# Test case 4: Mixed WT and WE (2 WT + 2 WE) +# Expected: WT always paid (500€), WE: 2.0 - 2.0 = 0 paid (0€), Total: 500€ +print("\n" + "=" * 60) +print("Test 4: 2.0 WT + 2.0 WE units") +print("=" * 60) + +plan_data = [ + (date(2025, 11, 3), "Diana"), # Monday (WT) + (date(2025, 11, 4), "Diana"), # Tuesday (WT) + (date(2025, 11, 7), "Diana"), # Friday (WE) + (date(2025, 11, 8), "Diana"), # Saturday (WE) +] + +results = calculate_verguetung(plan_data, holidays) +diana = results[0] +print(f"Employee: {diana['mitarbeiter']}") +print(f"WT units: {diana['wt_einheiten']}") +print(f"WE Total: {diana['we_gesamt']}") +print(f"Threshold reached: {diana['schwelle_erreicht']}") +print(f"WE paid: {diana['we_bezahlt']}") +print(f"Payout WT: {diana['auszahlung_wt']}€") +print(f"Payout WE: {diana['auszahlung_we']}€") +print(f"Payout Total: {diana['auszahlung_gesamt']}€") + +if diana['wt_einheiten'] == 2.0 and diana['auszahlung_wt'] == 500 and diana['we_bezahlt'] == 0.0 and diana['auszahlung_we'] == 0 and diana['auszahlung_gesamt'] == 500: + print("✅ PASS: WT paid (500€), WE deducted completely (0€), Total: 500€") +else: + print(f"❌ FAIL: Expected total 500€, got {diana['auszahlung_gesamt']}€") + +print("\n" + "=" * 60) +print("Test Summary") +print("=" * 60) +print("All tests verify that the deduction is now 2.0 WE units (not 1.0)") +print("This matches the business requirement from the issue.") diff --git a/webapp/test-suite.js b/webapp/test-suite.js index 4fff30b..03e85a9 100644 --- a/webapp/test-suite.js +++ b/webapp/test-suite.js @@ -204,9 +204,9 @@ runner.test('Berechnung: Genau 2.0 WE-Tage = 450€', (t) => { t.assertEqual(result.qualifyingDays, 2.0, 'Sollte 2.0 qualifizierende Tage haben'); t.assertTrue(result.thresholdReached, 'Schwellenwert sollte erreicht sein'); - t.assertEqual(result.qualifyingDaysDeducted, 1.0, 'Sollte 1.0 Tag abziehen'); - t.assertEqual(result.qualifyingDaysPaid, 1.0, 'Sollte 1.0 Tag bezahlen'); - t.assertEqual(result.totalBonus, 450, 'Bonus sollte 450€ sein'); + t.assertEqual(result.qualifyingDaysDeducted, 2.0, 'Sollte 2.0 Tage abziehen'); + t.assertEqual(result.qualifyingDaysPaid, 0.0, 'Sollte 0.0 Tage bezahlen'); + t.assertEqual(result.totalBonus, 0, 'Bonus sollte 0€ sein'); }); runner.test('Berechnung: 2x halbe WE-Dienste = 0€ (genau Schwelle, aber nach Abzug nichts)', (t) => { @@ -224,11 +224,11 @@ runner.test('Berechnung: 2x halbe WE-Dienste = 0€ (genau Schwelle, aber nach A t.assertEqual(result.qualifyingDays, 2.0, 'Sollte 2.0 qualifizierende Tage haben (4×0.5)'); t.assertTrue(result.thresholdReached, 'Schwellenwert sollte erreicht sein'); - t.assertEqual(result.qualifyingDaysPaid, 1.0, 'Sollte 1.0 Tag bezahlen nach Abzug'); - t.assertEqual(result.totalBonus, 450, 'Bonus sollte 450€ sein'); + t.assertEqual(result.qualifyingDaysPaid, 0.0, 'Sollte 0.0 Tage bezahlen nach Abzug'); + t.assertEqual(result.totalBonus, 0, 'Bonus sollte 0€ sein'); }); -runner.test('Berechnung: 3 WE-Tage = 900€', (t) => { +runner.test('Berechnung: 3 WE-Tage = 450€', (t) => { const holidays = new HolidayProvider(); const calculator = new BonusCalculator(holidays); @@ -241,8 +241,8 @@ runner.test('Berechnung: 3 WE-Tage = 900€', (t) => { const result = calculator.calculateMonthlyBonus(duties); t.assertEqual(result.qualifyingDays, 3.0, 'Sollte 3.0 qualifizierende Tage haben'); - t.assertEqual(result.qualifyingDaysPaid, 2.0, 'Sollte 2.0 Tage bezahlen (3-1)'); - t.assertEqual(result.totalBonus, 900, 'Bonus sollte 900€ sein (2×450€)'); + t.assertEqual(result.qualifyingDaysPaid, 1.0, 'Sollte 1.0 Tag bezahlen (3-2)'); + t.assertEqual(result.totalBonus, 450, 'Bonus sollte 450€ sein (1×450€)'); }); runner.test('Berechnung: Normale Tage + WE-Tage gemischt', (t) => { @@ -261,10 +261,10 @@ runner.test('Berechnung: Normale Tage + WE-Tage gemischt', (t) => { t.assertEqual(result.normalDays, 2.0, 'Sollte 2.0 normale Tage haben'); t.assertEqual(result.qualifyingDays, 2.0, 'Sollte 2.0 qualifizierende Tage haben'); t.assertEqual(result.normalDaysPaid, 2.0, 'Sollte 2.0 normale Tage bezahlen'); - t.assertEqual(result.qualifyingDaysPaid, 1.0, 'Sollte 1.0 qualifizierenden Tag bezahlen'); + t.assertEqual(result.qualifyingDaysPaid, 0.0, 'Sollte 0.0 qualifizierenden Tag bezahlen'); t.assertEqual(result.bonusNormalDays, 500, 'Normale Tage: 2×250€ = 500€'); - t.assertEqual(result.bonusQualifyingDays, 450, 'WE-Tage: 1×450€ = 450€'); - t.assertEqual(result.totalBonus, 950, 'Gesamt: 950€'); + t.assertEqual(result.bonusQualifyingDays, 0, 'WE-Tage: 0×450€ = 0€'); + t.assertEqual(result.totalBonus, 500, 'Gesamt: 500€'); }); runner.test('Berechnung: Halbe Dienste korrekt berechnet', (t) => { @@ -282,10 +282,10 @@ runner.test('Berechnung: Halbe Dienste korrekt berechnet', (t) => { t.assertEqual(result.normalDays, 0.5, 'Sollte 0.5 normale Tage haben'); t.assertEqual(result.qualifyingDays, 2.5, 'Sollte 2.5 qualifizierende Tage haben'); - t.assertEqual(result.qualifyingDaysPaid, 1.5, 'Sollte 1.5 qualifizierende Tage bezahlen'); + t.assertEqual(result.qualifyingDaysPaid, 0.5, 'Sollte 0.5 qualifizierende Tage bezahlen'); t.assertEqual(result.bonusNormalDays, 125, 'Normale Tage: 0.5×250€ = 125€'); - t.assertEqual(result.bonusQualifyingDays, 675, 'WE-Tage: 1.5×450€ = 675€'); - t.assertEqual(result.totalBonus, 800, 'Gesamt: 800€'); + t.assertEqual(result.bonusQualifyingDays, 225, 'WE-Tage: 0.5×450€ = 225€'); + t.assertEqual(result.totalBonus, 350, 'Gesamt: 350€'); }); runner.test('Berechnung: Feiertag + Vortag', (t) => { @@ -301,7 +301,7 @@ runner.test('Berechnung: Feiertag + Vortag', (t) => { t.assertEqual(result.qualifyingDays, 2.0, 'Sollte 2.0 qualifizierende Tage haben'); t.assertTrue(result.thresholdReached, 'Schwellenwert sollte erreicht sein'); - t.assertEqual(result.totalBonus, 450, 'Bonus sollte 450€ sein'); + t.assertEqual(result.totalBonus, 0, 'Bonus sollte 0€ sein'); }); runner.test('Berechnung: Keine Dienste = 0€', (t) => { From 57335915f558734f9c99d0a54c4f01bfc2c58ed8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 12 Dec 2025 11:40:01 +0000 Subject: [PATCH 4/4] Remove temporary test file --- test_deduction.py | 124 ---------------------------------------------- 1 file changed, 124 deletions(-) delete mode 100644 test_deduction.py diff --git a/test_deduction.py b/test_deduction.py deleted file mode 100644 index b09ecfc..0000000 --- a/test_deduction.py +++ /dev/null @@ -1,124 +0,0 @@ -#!/usr/bin/env python3 -""" -Test script to verify the weekend deduction change from 1.0 to 2.0 units. -""" - -from datetime import date -import sys -sys.path.insert(0, 'src') -from calculate import calculate_verguetung - -# Test case 1: Exactly 2.0 WE units (threshold reached) -# Expected: 2.0 WE - 2.0 deduction = 0.0 paid → 0€ for WE -print("=" * 60) -print("Test 1: Exactly 2.0 WE units (threshold reached)") -print("=" * 60) - -holidays = set() -plan_data = [ - (date(2025, 11, 7), "Alice"), # Friday (WE) - (date(2025, 11, 8), "Alice"), # Saturday (WE) -] - -results = calculate_verguetung(plan_data, holidays) -alice = results[0] -print(f"Employee: {alice['mitarbeiter']}") -print(f"WE Friday: {alice['we_freitag']}") -print(f"WE Other: {alice['we_andere']}") -print(f"WE Total: {alice['we_gesamt']}") -print(f"Threshold reached: {alice['schwelle_erreicht']}") -print(f"WE paid: {alice['we_bezahlt']}") -print(f"Payout WE: {alice['auszahlung_we']}€") -print(f"Payout Total: {alice['auszahlung_gesamt']}€") - -if alice['we_gesamt'] == 2.0 and alice['we_bezahlt'] == 0.0 and alice['auszahlung_we'] == 0: - print("✅ PASS: Correctly deducts 2.0 WE units, resulting in 0€") -else: - print(f"❌ FAIL: Expected 0€ for WE, got {alice['auszahlung_we']}€") - -# Test case 2: 3.0 WE units -# Expected: 3.0 WE - 2.0 deduction = 1.0 paid → 450€ -print("\n" + "=" * 60) -print("Test 2: 3.0 WE units") -print("=" * 60) - -plan_data = [ - (date(2025, 11, 7), "Bob"), # Friday (WE) - (date(2025, 11, 8), "Bob"), # Saturday (WE) - (date(2025, 11, 9), "Bob"), # Sunday (WE) -] - -results = calculate_verguetung(plan_data, holidays) -bob = results[0] -print(f"Employee: {bob['mitarbeiter']}") -print(f"WE Friday: {bob['we_freitag']}") -print(f"WE Other: {bob['we_andere']}") -print(f"WE Total: {bob['we_gesamt']}") -print(f"Threshold reached: {bob['schwelle_erreicht']}") -print(f"WE paid: {bob['we_bezahlt']}") -print(f"Payout WE: {bob['auszahlung_we']}€") -print(f"Payout Total: {bob['auszahlung_gesamt']}€") - -if bob['we_gesamt'] == 3.0 and bob['we_bezahlt'] == 1.0 and bob['auszahlung_we'] == 450: - print("✅ PASS: Correctly deducts 2.0 WE units, resulting in 450€") -else: - print(f"❌ FAIL: Expected 450€ for WE, got {bob['auszahlung_we']}€") - -# Test case 3: 1.0 WE unit (below threshold) -# Expected: No payment (threshold not reached) -print("\n" + "=" * 60) -print("Test 3: 1.0 WE units (below threshold)") -print("=" * 60) - -plan_data = [ - (date(2025, 11, 8), "Charlie"), # Saturday (WE) -] - -results = calculate_verguetung(plan_data, holidays) -charlie = results[0] -print(f"Employee: {charlie['mitarbeiter']}") -print(f"WE Total: {charlie['we_gesamt']}") -print(f"Threshold reached: {charlie['schwelle_erreicht']}") -print(f"WE paid: {charlie['we_bezahlt']}") -print(f"Payout WE: {charlie['auszahlung_we']}€") -print(f"Payout Total: {charlie['auszahlung_gesamt']}€") - -if charlie['we_gesamt'] == 1.0 and charlie['we_bezahlt'] == 0.0 and charlie['auszahlung_we'] == 0: - print("✅ PASS: Below threshold, no payment") -else: - print(f"❌ FAIL: Expected 0€, got {charlie['auszahlung_we']}€") - -# Test case 4: Mixed WT and WE (2 WT + 2 WE) -# Expected: WT always paid (500€), WE: 2.0 - 2.0 = 0 paid (0€), Total: 500€ -print("\n" + "=" * 60) -print("Test 4: 2.0 WT + 2.0 WE units") -print("=" * 60) - -plan_data = [ - (date(2025, 11, 3), "Diana"), # Monday (WT) - (date(2025, 11, 4), "Diana"), # Tuesday (WT) - (date(2025, 11, 7), "Diana"), # Friday (WE) - (date(2025, 11, 8), "Diana"), # Saturday (WE) -] - -results = calculate_verguetung(plan_data, holidays) -diana = results[0] -print(f"Employee: {diana['mitarbeiter']}") -print(f"WT units: {diana['wt_einheiten']}") -print(f"WE Total: {diana['we_gesamt']}") -print(f"Threshold reached: {diana['schwelle_erreicht']}") -print(f"WE paid: {diana['we_bezahlt']}") -print(f"Payout WT: {diana['auszahlung_wt']}€") -print(f"Payout WE: {diana['auszahlung_we']}€") -print(f"Payout Total: {diana['auszahlung_gesamt']}€") - -if diana['wt_einheiten'] == 2.0 and diana['auszahlung_wt'] == 500 and diana['we_bezahlt'] == 0.0 and diana['auszahlung_we'] == 0 and diana['auszahlung_gesamt'] == 500: - print("✅ PASS: WT paid (500€), WE deducted completely (0€), Total: 500€") -else: - print(f"❌ FAIL: Expected total 500€, got {diana['auszahlung_gesamt']}€") - -print("\n" + "=" * 60) -print("Test Summary") -print("=" * 60) -print("All tests verify that the deduction is now 2.0 WE units (not 1.0)") -print("This matches the business requirement from the issue.")