This commit is contained in:
@@ -0,0 +1,148 @@
|
||||
from datetime import date, timedelta
|
||||
|
||||
from sqlalchemy import delete, select
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.models import User, WeeklyTargetRule
|
||||
|
||||
DEFAULT_REFERENCE_WEEK_START = date(1970, 1, 5) # Montag
|
||||
|
||||
|
||||
def monday_of(day: date) -> date:
|
||||
return day - timedelta(days=day.weekday())
|
||||
|
||||
|
||||
def week_starts_between(start_week_start: date, end_week_start: date) -> list[date]:
|
||||
weeks: list[date] = []
|
||||
current = start_week_start
|
||||
while current <= end_week_start:
|
||||
weeks.append(current)
|
||||
current += timedelta(days=7)
|
||||
return weeks
|
||||
|
||||
|
||||
def list_rules_for_user(db: Session, user_id: str) -> list[WeeklyTargetRule]:
|
||||
stmt = (
|
||||
select(WeeklyTargetRule)
|
||||
.where(WeeklyTargetRule.user_id == user_id)
|
||||
.order_by(WeeklyTargetRule.effective_from.asc())
|
||||
)
|
||||
return db.execute(stmt).scalars().all()
|
||||
|
||||
|
||||
def target_for_week(
|
||||
rules: list[WeeklyTargetRule],
|
||||
week_start: date,
|
||||
fallback_minutes: int,
|
||||
) -> int:
|
||||
target = fallback_minutes
|
||||
for rule in rules:
|
||||
if rule.effective_from <= week_start:
|
||||
target = rule.weekly_target_minutes
|
||||
else:
|
||||
break
|
||||
return target
|
||||
|
||||
|
||||
def target_map_for_weeks(
|
||||
rules: list[WeeklyTargetRule],
|
||||
week_starts: list[date],
|
||||
fallback_minutes: int,
|
||||
) -> dict[date, int]:
|
||||
result: dict[date, int] = {}
|
||||
for week_start in week_starts:
|
||||
result[week_start] = target_for_week(rules, week_start, fallback_minutes)
|
||||
return result
|
||||
|
||||
|
||||
def upsert_rule(db: Session, user_id: str, effective_from: date, weekly_target_minutes: int) -> None:
|
||||
stmt = select(WeeklyTargetRule).where(
|
||||
WeeklyTargetRule.user_id == user_id,
|
||||
WeeklyTargetRule.effective_from == effective_from,
|
||||
)
|
||||
rule = db.execute(stmt).scalar_one_or_none()
|
||||
|
||||
if rule:
|
||||
rule.weekly_target_minutes = weekly_target_minutes
|
||||
return
|
||||
|
||||
db.add(
|
||||
WeeklyTargetRule(
|
||||
user_id=user_id,
|
||||
effective_from=effective_from,
|
||||
weekly_target_minutes=weekly_target_minutes,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def ensure_user_has_default_target_rule(db: Session, user: User) -> None:
|
||||
stmt = select(WeeklyTargetRule.id).where(WeeklyTargetRule.user_id == user.id).limit(1)
|
||||
existing = db.execute(stmt).scalar_one_or_none()
|
||||
if existing:
|
||||
return
|
||||
|
||||
db.add(
|
||||
WeeklyTargetRule(
|
||||
user_id=user.id,
|
||||
effective_from=DEFAULT_REFERENCE_WEEK_START,
|
||||
weekly_target_minutes=user.weekly_target_minutes,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def ensure_all_users_have_default_target_rules(db: Session) -> None:
|
||||
users = db.execute(select(User)).scalars().all()
|
||||
changed = False
|
||||
for user in users:
|
||||
before_count = db.execute(
|
||||
select(WeeklyTargetRule.id).where(WeeklyTargetRule.user_id == user.id).limit(1)
|
||||
).scalar_one_or_none()
|
||||
if before_count:
|
||||
continue
|
||||
ensure_user_has_default_target_rule(db, user)
|
||||
changed = True
|
||||
|
||||
if changed:
|
||||
db.commit()
|
||||
|
||||
|
||||
def apply_weekly_target_change(
|
||||
db: Session,
|
||||
*,
|
||||
user: User,
|
||||
selected_week_start: date,
|
||||
new_target_minutes: int,
|
||||
scope: str,
|
||||
) -> None:
|
||||
rules = list_rules_for_user(db, user.id)
|
||||
fallback = user.weekly_target_minutes
|
||||
|
||||
if scope == "all_weeks":
|
||||
db.execute(delete(WeeklyTargetRule).where(WeeklyTargetRule.user_id == user.id))
|
||||
db.add(
|
||||
WeeklyTargetRule(
|
||||
user_id=user.id,
|
||||
effective_from=DEFAULT_REFERENCE_WEEK_START,
|
||||
weekly_target_minutes=new_target_minutes,
|
||||
)
|
||||
)
|
||||
return
|
||||
|
||||
if scope == "from_current_week":
|
||||
db.execute(
|
||||
delete(WeeklyTargetRule).where(
|
||||
WeeklyTargetRule.user_id == user.id,
|
||||
WeeklyTargetRule.effective_from >= selected_week_start,
|
||||
)
|
||||
)
|
||||
upsert_rule(db, user.id, selected_week_start, new_target_minutes)
|
||||
return
|
||||
|
||||
if scope == "current_week":
|
||||
next_week_start = selected_week_start + timedelta(days=7)
|
||||
target_next_week_before = target_for_week(rules, next_week_start, fallback)
|
||||
upsert_rule(db, user.id, selected_week_start, new_target_minutes)
|
||||
upsert_rule(db, user.id, next_week_start, target_next_week_before)
|
||||
return
|
||||
|
||||
raise ValueError("Ungueltiger Scope")
|
||||
Reference in New Issue
Block a user