diff --git a/pronote_sync/sources/pronote/ical.py b/pronote_sync/sources/pronote/ical.py index 4a279e5..f03183f 100644 --- a/pronote_sync/sources/pronote/ical.py +++ b/pronote_sync/sources/pronote/ical.py @@ -372,7 +372,8 @@ def generate_homework_id( :rtype: str """ payload = ( - f"{due_on.isoformat()}|{subject}|{','.join(sorted(teachers))}|{normalized_text}".encode() + f"{due_on.isoformat()}|{subject.casefold()}|" + f"{','.join(sorted(teacher.casefold() for teacher in teachers))}|{normalized_text}".encode() ) return hashlib.sha1(payload, usedforsecurity=False).hexdigest()[:12] @@ -399,7 +400,7 @@ def collect_homeworks(lessons: list[Lesson], target_date: date) -> list[Homework normalized_text = normalize_homework_text(block.text) key = ( lesson.subject.casefold(), - tuple(teacher.casefold() for teacher in lesson.teachers), + tuple(sorted(teacher.casefold() for teacher in lesson.teachers)), normalized_text, ) if key not in by_context: @@ -423,7 +424,7 @@ def collect_homeworks(lessons: list[Lesson], target_date: date) -> list[Homework normalized_text = normalize_homework_text(block.text) key = ( lesson.subject.casefold(), - tuple(teacher.casefold() for teacher in lesson.teachers), + tuple(sorted(teacher.casefold() for teacher in lesson.teachers)), normalized_text, ) if key not in by_context: diff --git a/tests/unit/test_ical.py b/tests/unit/test_ical.py index 37e7c28..2b0eb53 100644 --- a/tests/unit/test_ical.py +++ b/tests/unit/test_ical.py @@ -398,6 +398,36 @@ def test_collect_homeworks_keeps_distinct_subjects() -> None: assert {homework.subject for homework in homeworks} == {"Math", "Physique"} +def test_collect_homeworks_deduplicates_teacher_order_variants() -> None: + """Deux ordres d'enseignants équivalents ne créent pas de doublon. + + :return: None + """ + homework_block = HomeworkBlock( + kind="due", + date=date(2026, 9, 10), + text="Devoir commun", + html="
Devoir commun
", + ) + lesson = Lesson( + id="lesson1", + start=datetime(2026, 9, 10, 8, 0), + end=datetime(2026, 9, 10, 9, 0), + subject="Math", + teachers=("M. Martin", "M. Dupont"), + group=None, + content=None, + homework_blocks=(homework_block,), + ) + other_lesson = lesson.model_copy( + update={"id": "lesson2", "teachers": ("M. Dupont", "M. Martin")} + ) + + homeworks = collect_homeworks([lesson, other_lesson], target_date=date(2026, 9, 10)) + + assert len(homeworks) == 1 + + def test_parse_body_accepts_html_variants_and_sanitizes() -> None: """Les attributs HTML, les espaces et le contenu actif sont traités correctement.