fix(exam): blank total only for absent AND unmarked; flip status on mark
A roster student starts 'absent' and a direct mark would otherwise still show a blank total. Now total is blank only when absent with no marks; recording a mark advances the submission out of absent/unmatched to 'marking'. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
a1d297ac30
commit
62234dbbcb
@ -187,8 +187,14 @@ def _assemble_results(ctx: ExamContext, batch: Dict[str, Any]) -> Dict[str, Any]
|
|||||||
results = []
|
results = []
|
||||||
for s in submissions: # every submission incl. absent → A7
|
for s in submissions: # every submission incl. absent → A7
|
||||||
sub_marks = by_sub.get(s["id"], {})
|
sub_marks = by_sub.get(s["id"], {})
|
||||||
is_absent = s.get("status") == "absent"
|
# Blank total ONLY for a genuine no-show (absent AND nothing marked). A student with any
|
||||||
total = None if is_absent else sum(v or 0 for v in sub_marks.values())
|
# mark gets a real total regardless of status; a present-but-unmarked student totals 0.
|
||||||
|
if sub_marks:
|
||||||
|
total = sum(v or 0 for v in sub_marks.values())
|
||||||
|
elif s.get("status") == "absent":
|
||||||
|
total = None
|
||||||
|
else:
|
||||||
|
total = 0
|
||||||
results.append({
|
results.append({
|
||||||
"submission_id": s["id"],
|
"submission_id": s["id"],
|
||||||
"student_id": s.get("student_id"),
|
"student_id": s.get("student_id"),
|
||||||
@ -248,7 +254,7 @@ async def upsert_mark(
|
|||||||
# Derive batch_id from the submission (as-user read → also enforces the caller owns the batch
|
# Derive batch_id from the submission (as-user read → also enforces the caller owns the batch
|
||||||
# the submission belongs to). The client never supplies the RLS scoping key directly.
|
# the submission belongs to). The client never supplies the RLS scoping key directly.
|
||||||
submission = _first(
|
submission = _first(
|
||||||
ctx.supabase.table("student_submissions").select("id, batch_id").eq("id", body.submission_id).limit(1).execute()
|
ctx.supabase.table("student_submissions").select("id, batch_id, status").eq("id", body.submission_id).limit(1).execute()
|
||||||
)
|
)
|
||||||
if not submission:
|
if not submission:
|
||||||
raise HTTPException(status_code=404, detail="Submission not found")
|
raise HTTPException(status_code=404, detail="Submission not found")
|
||||||
@ -273,6 +279,12 @@ async def upsert_mark(
|
|||||||
upserted = _first(ctx.supabase.table("mark_entries").upsert(row).execute())
|
upserted = _first(ctx.supabase.table("mark_entries").upsert(row).execute())
|
||||||
if not upserted:
|
if not upserted:
|
||||||
raise HTTPException(status_code=500, detail="Failed to upsert mark")
|
raise HTTPException(status_code=500, detail="Failed to upsert mark")
|
||||||
|
|
||||||
|
# A marked student is, by definition, not absent — advance the submission out of the
|
||||||
|
# no-submission states so results/queue reflect that marking has started.
|
||||||
|
if submission.get("status") in ("absent", "unmatched"):
|
||||||
|
ctx.supabase.table("student_submissions").update({"status": "marking"}).eq("id", body.submission_id).execute()
|
||||||
|
|
||||||
return upserted
|
return upserted
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -233,6 +233,17 @@ def test_upsert_mark_derives_batch_and_roundtrips():
|
|||||||
assert sum(1 for m in store["mark_entries"] if m["id"] == "mk-1") == 1
|
assert sum(1 for m in store["mark_entries"] if m["id"] == "mk-1") == 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_upsert_mark_flips_absent_submission_to_marking():
|
||||||
|
store = _batch_with_cohort() # sub2 starts 'absent'
|
||||||
|
c = make_client(store)
|
||||||
|
c.put("/api/exam/marks/mk-2", json={"submission_id": "sub2", "question_id": "q1", "awarded_marks": 2})
|
||||||
|
sub2 = next(s for s in store["student_submissions"] if s["id"] == "sub2")
|
||||||
|
assert sub2["status"] == "marking"
|
||||||
|
# results now show a real total for the (formerly absent) marked student
|
||||||
|
res = {r["submission_id"]: r for r in c.get("/api/exam/batches/b1/results").json()["results"]}
|
||||||
|
assert res["sub2"]["total"] == 2
|
||||||
|
|
||||||
|
|
||||||
def test_upsert_mark_submission_404():
|
def test_upsert_mark_submission_404():
|
||||||
c = make_client(_batch_with_cohort())
|
c = make_client(_batch_with_cohort())
|
||||||
assert c.put("/api/exam/marks/mk-x", json={"submission_id": "nope", "question_id": "q1", "awarded_marks": 1}).status_code == 404
|
assert c.put("/api/exam/marks/mk-x", json={"submission_id": "nope", "question_id": "q1", "awarded_marks": 1}).status_code == 404
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user