List lifecycle polish and cycle batches, from live walkthrough feedback
Generating a call list is non-destructive by intent: the button reads Regenerate when an unused list exists and replaces it freely, with a confirmation only when the day already has recorded outcomes (which are always kept). The print view shows resolved calls' outcomes, offers generate/regenerate in place, and the home page links to the existing list. The day editor now supports adding calls after the fact (any roster student, with status/assessment/note), completing full editability: add, edit, delete. Cycle mode is now a true rolling rotation driven by non-skipped call counts: batches of n take the next students of the current pass, remainder batches come up short rather than wrapping, a new pass starts when everyone has been called, and the cycle continues across lists and class days. Live mode uses the same rule. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -320,6 +320,18 @@ def class_has_begun(session, course_id, day, now=None):
|
||||
return now.time() >= row.start_time
|
||||
|
||||
|
||||
def nonskipped_call_counts(session, course_id):
|
||||
"""Calls per student excluding skipped ones — a student's position
|
||||
in the cycle-mode pass. Pending list slots count: a printed line
|
||||
is a claim on being called."""
|
||||
rows = session.execute(
|
||||
select(Call.student_id, func.count())
|
||||
.where(Call.course_id == course_id, Call.status != STATUS_SKIPPED)
|
||||
.group_by(Call.student_id)
|
||||
).all()
|
||||
return dict(rows)
|
||||
|
||||
|
||||
def students_present(session, course_id, on_date):
|
||||
"""Active student-role enrollees minus those opted out for the date."""
|
||||
opted_out = select(OptOut.student_id).where(
|
||||
|
||||
Reference in New Issue
Block a user