specs/registration-notifications/spec.md: - MODIFIED: parent confirmation email sent on completion (alongside admin) - Bilingual body (de/en), QR-bill embedded inline, plain-text fallback - Language persisted as metadata.language in registration record tasks.md: - 6 sections: qrbill dep, language persistence, notify_parent() impl, wire into both completion sites (email agent + chat), tests, smoke test https://claude.ai/code/session_01LjjK7RjKVnC8bETtccfgna
4.3 KiB
4.3 KiB
1. Add qrbill Dependency
- 1.1 Add
qrbillto[project.dependencies]inpyproject.toml - 1.2 Run
uv lockto update the lockfile - 1.3 Verify
qrbillimports successfully in a smoke test or REPL
2. Persist Language in Registration Record
- 2.1 Update
ConversationStore._build_record()insrc/storage/json_store.pyto includelanguagefromstate.languagein themetadatadict - 2.2 Update
ConversationStore.save_registration()andsave_registration_version()signatures to accept/forwardstate(already does — confirm_build_recordreceives the full state) - 2.3 Add a test in
tests/test_storage.pyasserting that the saved record'smetadata.languagematchesstate.language
3. Add notify_parent() to AdminNotifier
- 3.1 Add a
_generate_qr_bill_png()static/class method toAdminNotifierusingqrbillwith fixed payment data:- IBAN:
CH14 0900 0000 4930 8018 8 - Payee: Familienverein Fällanden Spielgruppen, Huebwisstrase 5, 8117 Fällanden
- Amount:
80.00, Currency:CHF, Reference type: NON - Returns raw PNG
bytes
- IBAN:
- 3.2 Add bilingual string template dicts
_STRINGS_DEand_STRINGS_EN(module-level constants) covering all user-visible strings in the confirmation email (subject, section headers, fee labels, payment instructions text, closing) - 3.3 Add
_build_parent_html()method: renders full HTML confirmation email body using the appropriate string dict, embedding the QR image viacid:qrbill; includes registration summary and both monthly fee (informational) and CHF 80 registration fee (with IBAN text + QR reference) - 3.4 Add
_build_parent_text()method: renders the plain-text fallback, including all summary fields and IBAN/payee details in plain text (no image) - 3.5 Add
notify_parent()public method:- Parameters:
registration: RegistrationData,language: str = "de" - Select string dict based on
language; fall back to"de"for unknown values - Call
_generate_qr_bill_png()to get PNG bytes - Build MIME structure:
multipart/mixed>multipart/alternative> plain text part +multipart/related> HTML part + inline PNG (Content-Disposition: inline,Content-ID: <qrbill>) - Call
_send()withto=[registration.parent_guardian.email], emptycc, localised subject, the assembled MIME message - If
_smtp_hostis empty (dev mode), log and skip as withnotify_admin
- Parameters:
4. Wire notify_parent() into Completion Events
- 4.1 In
src/agent/core.py_handle_registration(): after the existingnotify_admin()try/except block, add a parallel try/except block callingself._notifier.notify_parent(registration=state.registration, language=state.language) - 4.2 In
chat_app.pyon_message(): after the existingnotify_admin()call inside the completion block, add a parallel try/except block calling_notifier.notify_parent(registration=state.registration, language=state.language) - 4.3 Verify both call sites log a warning (not an exception) on failure, and the registration completion path continues normally
5. Tests
- 5.1 Add
tests/test_notifier.pytests fornotify_parent():test_notify_parent_calls_send: mock_sendand assert it is called withto=[parent_email]test_notify_parent_german_subject: assert subject contains German text whenlanguage="de"test_notify_parent_english_subject: assert subject contains English text whenlanguage="en"test_notify_parent_unknown_language_falls_back_to_de: assertlanguage="fr"produces German subjecttest_notify_parent_no_smtp_skips_send: whensmtp_host="",_sendis NOT called
- 5.2 Add a test asserting that the plain-text body contains the IBAN string
CH14whensmtp_hostis empty (inspecting log or body build directly) - 5.3 Add a test for
_generate_qr_bill_png()asserting it returnsbyteswith non-zero length (requiresqrbillinstalled)
6. Manual Smoke Test
- 6.1 Run
chainlit run chat_app.pylocally (or the email poller), complete a registration end-to-end, and verify the parent confirmation email arrives with the inline QR image rendered correctly - 6.2 Verify the admin notification still arrives unchanged alongside the parent confirmation
- 6.3 Verify the saved
current.jsonfor the registration includesmetadata.language