From b9832f033796ca582d78167f4ae65012e73041f7 Mon Sep 17 00:00:00 2001 From: Antoine Van Elstraete Date: Wed, 11 Mar 2026 16:40:00 +0100 Subject: [PATCH] =?UTF-8?q?feat:=20leave=20balance=20calculation=20(cong?= =?UTF-8?q?=C3=A9s/RTT)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/business/leave_calc.py | 36 +++++++++++++++++++++++++++++++++ tests/test_leave_calc.py | 41 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 app/business/leave_calc.py create mode 100644 tests/test_leave_calc.py diff --git a/app/business/leave_calc.py b/app/business/leave_calc.py new file mode 100644 index 0000000..7624836 --- /dev/null +++ b/app/business/leave_calc.py @@ -0,0 +1,36 @@ +from app import db +from app.models import WorkEntry, LeaveBalance +import sqlalchemy as sa +from datetime import date + + +def compute_leave_used(year: int) -> dict[str, int]: + start = date(year, 1, 1) + end = date(year, 12, 31) + + conges = db.session.scalar( + sa.select(sa.func.count()).where( + WorkEntry.date.between(start, end), + WorkEntry.day_type == "CONGE", + ) + ) or 0 + + rtt = db.session.scalar( + sa.select(sa.func.count()).where( + WorkEntry.date.between(start, end), + WorkEntry.day_type == "RTT", + ) + ) or 0 + + return {"conges": conges, "rtt": rtt} + + +def get_or_create_balance(year: int) -> LeaveBalance: + balance = db.session.scalar( + sa.select(LeaveBalance).where(LeaveBalance.year == year) + ) + if balance is None: + balance = LeaveBalance(year=year) + db.session.add(balance) + db.session.commit() + return balance diff --git a/tests/test_leave_calc.py b/tests/test_leave_calc.py new file mode 100644 index 0000000..f69e4e0 --- /dev/null +++ b/tests/test_leave_calc.py @@ -0,0 +1,41 @@ +from app.business.leave_calc import compute_leave_used, get_or_create_balance +from app.models import WorkEntry, LeaveBalance +from app import db +from datetime import date +import sqlalchemy as sa + + +def test_compute_leave_used_conges(app): + with app.app_context(): + entries = [ + WorkEntry(date=date(2025, 1, 6), day_type="CONGE"), + WorkEntry(date=date(2025, 1, 7), day_type="CONGE"), + WorkEntry(date=date(2025, 1, 8), day_type="RTT"), + WorkEntry(date=date(2025, 1, 9), day_type="WORK"), + ] + for e in entries: + db.session.add(e) + db.session.commit() + + used = compute_leave_used(2025) + assert used["conges"] == 2 + assert used["rtt"] == 1 + + +def test_get_or_create_balance_creates_default(app): + with app.app_context(): + balance = get_or_create_balance(2025) + assert balance.year == 2025 + assert balance.conges_total == 28 + assert balance.rtt_total == 18 + + +def test_get_or_create_balance_returns_existing(app): + with app.app_context(): + existing = LeaveBalance(year=2025, conges_total=25, rtt_total=15) + db.session.add(existing) + db.session.commit() + + balance = get_or_create_balance(2025) + assert balance.conges_total == 25 + assert balance.rtt_total == 15