Session 3-A - core models: community.school.term, .level (admin-defined, so the same module fits a Grade 1-12 school or a Beginner-Advanced language school with no code change), .class (auto-creates a linked slide.channel for LMS glue), .student, .enrollment, and .attendance, plus is_teacher on res.partner. Class enrolled_count and enrollment attendance_rate are stored/non-stored computes driven by the enrollment/attendance one2many chains. Session 3-B - teacher attendance + at-risk reporting: a portal page at /school/attendance (auth='user', scoped to classes where teacher_id matches the logged-in user's partner - works whether the teacher is an internal or portal user) with a roster and batch save, built as a v19 Interaction (same pattern as event_qr_ticketing's check-in page). Marking a student absent queues a configurable notice to the parent partner. Enrollment.is_at_risk flags students below a configurable attendance threshold (School settings page, same <app>/<block>/<setting> pattern as community_membership), plus an admin pivot attendance report and an At-Risk Students list. Verified against a live Odoo 19 + Postgres 16 container: 14/14 automated tests pass (class/slide-channel creation, enrolled_count tracking incl. withdrawal, attendance_rate and at-risk computation, unique enrollment+date constraint, absence email queuing), plus a full manual live run - created a term/level/class/student/enrollment via JSON-RPC, loaded the actual /school/attendance page as the teacher, POSTed a batch save marking the student absent, and confirmed both the attendance record and the queued "Absence notice" mail.mail record. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
26 lines
1.1 KiB
XML
26 lines
1.1 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
|
<odoo>
|
|
<data noupdate="1">
|
|
<record id="mail_template_absence_notice" model="mail.template">
|
|
<field name="name">School: Absence Notice</field>
|
|
<field name="model_id" ref="model_community_school_attendance"/>
|
|
<field name="subject">Absence notice: {{ object.enrollment_id.student_id.partner_id.name }}</field>
|
|
<field name="partner_to">{{ object.enrollment_id.student_id.parent_partner_id.id }}</field>
|
|
<field name="auto_delete" eval="True"/>
|
|
<field name="body_html" type="html">
|
|
<div style="margin: 0px; padding: 0px; font-size: 13px;">
|
|
<p>Dear <t t-out="object.enrollment_id.student_id.parent_partner_id.name or ''">Parent</t>,</p>
|
|
<p>
|
|
This is to let you know that
|
|
<t t-out="object.enrollment_id.student_id.partner_id.name or ''"/>
|
|
was marked absent from
|
|
<t t-out="object.class_id.name or ''"/>
|
|
on <t t-out="format_date(object.date)"/>.
|
|
</p>
|
|
<p t-if="object.notes">Notes: <t t-out="object.notes"/></p>
|
|
</div>
|
|
</field>
|
|
</record>
|
|
</data>
|
|
</odoo>
|