This commit is contained in:
Home Assistant Version Control
2026-09-25 04:10:30 +00:00
parent 56c80f896e
commit ad634c1b84
60 changed files with 2895 additions and 794 deletions
+41 -4
View File
@@ -146,6 +146,14 @@ def _build_children_summary(coordinator: TaskMateCoordinator, common: dict) -> l
for c in children:
committed_amount = committed.get(c.id, 0)
lvl = coordinator.level_info(c)
# Weekly targets (#883): {chore_id: done so far this week} for the
# chores that have one, so a card can render "2/3 this week" without
# its own pass over completions. Empty — and so absent — for most.
weekly_progress = {
ch.id: coordinator.weekly_completion_count(ch.id, c.id)
for ch in common["chores"]
if int(getattr(ch, "weekly_target", 0) or 0) > 0
}
summary.append(
{
"level": lvl["level"],
@@ -195,6 +203,7 @@ def _build_children_summary(coordinator: TaskMateCoordinator, common: dict) -> l
"quests": coordinator.quest_progress_for_child(c.id),
"avatar_options": coordinator.avatar_options_for_child(c),
"challenges": coordinator.challenge_progress_for_child(c.id),
**({"weekly_chore_progress": weekly_progress} if weekly_progress else {}),
}
)
return summary
@@ -243,6 +252,11 @@ def _build_chores_list(coordinator: TaskMateCoordinator, common: dict) -> list[d
daily_limit = getattr(c, "daily_limit", 1)
if daily_limit != 1:
record["daily_limit"] = daily_limit
# Weekly target (#883) — off for almost every chore, so it only goes
# into the record when a family actually uses one.
weekly_target = int(getattr(c, "weekly_target", 0) or 0)
if weekly_target:
record["weekly_target"] = weekly_target
claim_allowance_minutes = getattr(c, "claim_allowance_minutes", 0) or 0
if claim_allowance_minutes:
record["claim_allowance_minutes"] = claim_allowance_minutes
@@ -355,6 +369,27 @@ def _build_chore_availability(coordinator: TaskMateCoordinator, common: dict) ->
return availability
def _completion_award(completion, recalculated: int) -> int:
"""What a completion is worth, recorded rather than re-derived.
Approved: what the child was actually paid, weekend multiplier included.
Re-deriving it from the chore reported the chore's *current* points, so
re-pricing a chore rewrote every past completion of it.
Pending: what the child was promised at submission, including a speed
bonus or roulette multiplier that may no longer apply — the same figure
approval will pay.
Neither recorded (a completion from before those fields existed): fall
back to the caller's calculation.
"""
if completion.approved:
return completion.points_awarded
if completion.submitted_points is not None:
return completion.submitted_points
return recalculated
def _build_todays_completions(common: dict) -> list[dict]:
"""Build today's completions (both approved and pending)."""
now = dt_util.now()
@@ -391,7 +426,7 @@ def _build_todays_completions(common: dict) -> list[dict]:
if comp.child_id == "__parent__"
else (child_lookup[comp.child_id].name if comp.child_id in child_lookup else ""),
"chore_name": display_name,
"points": display_points,
"points": _completion_award(comp, display_points),
"approved": comp.approved,
"completed_at": comp.completed_at.isoformat()
if hasattr(comp.completed_at, "isoformat")
@@ -573,7 +608,7 @@ def _build_recent_completions(common: dict, limit: int = 35) -> list[dict]:
if comp.child_id == "__parent__"
else (child_lookup[comp.child_id].name if comp.child_id in child_lookup else ""),
"chore_name": matched_chore.name if matched_chore else "",
"points": display_points,
"points": _completion_award(comp, display_points),
"approved": comp.approved,
"completed_at": comp.completed_at.isoformat()
if hasattr(comp.completed_at, "isoformat")
@@ -657,7 +692,9 @@ def _build_recent_transactions(common: dict, limit: int = 20) -> list[dict]:
"reward_id": rc.reward_id,
"reward_name": reward.name,
"reward_icon": reward.icon or "mdi:gift",
"points": -reward.cost,
# An approved purchase is worth what it cost that day, not what
# the reward has been re-priced to since.
"points": -(rc.approved_cost if rc.approved and rc.approved_cost is not None else reward.cost),
"approved": rc.approved,
"created_at": timestamp.isoformat() if hasattr(timestamp, "isoformat") else str(timestamp),
}
@@ -1378,7 +1415,7 @@ class PendingApprovalsSensor(TaskMateBaseSensor):
"child_id": child.id,
"chore_name": chore_name,
"chore_id": chore.id,
"points": pts,
"points": _completion_award(comp, pts),
"time_category": chore.time_category,
"completed_at": comp.completed_at.isoformat(),
"bonus_subtask_id": bonus_subtask_id,