diff --git a/pronote_sync/sources/pronote/ical.py b/pronote_sync/sources/pronote/ical.py index 4e7ecc3..0bf16e7 100644 --- a/pronote_sync/sources/pronote/ical.py +++ b/pronote_sync/sources/pronote/ical.py @@ -370,7 +370,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] @@ -397,7 +398,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: @@ -421,7 +422,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 9a91eeb..4f62c53 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.