metatroncubeswdev 508bf27417 O2: mc_education_admission - public form through to enrolled student
Serves Demo Scene 2 end to end: mc.applicant with the stage pipeline
(Applied -> Document Verification -> Interview -> Offered -> Accepted
-> Enrolled/Rejected) on mail.thread, a public admission page on the
website, and a convert wizard that turns an accepted applicant into a
real mc.student + mc.enrollment with zero re-typing.

The public form uses Odoo's stock /website/form/<model> mechanism,
not a custom controller (CLAUDE.md sec 1.3 - writing a custom version
of stock infrastructure is a bug). Verified the real mechanism against
core source first rather than assuming: website_hr_recruitment's own
data/config_data.xml is the template this follows (ir.model.
website_form_access + ir.model.fields.formbuilder_whitelist()).

This is the module's actual security boundary, and it's worth being
explicit about why it holds. The generic controller creates the record
as SUPERUSER - normal ir.model.access rows do not apply to it at all.
The only thing stopping a submitter from setting state, student_id,
application_no or company_id is that those fields are not in the
formbuilder_whitelist() call in data/mc_applicant_website_form_data.xml
(every field defaults to website_form_blacklisted=True and stays that
way unless explicitly opted in). Confirmed this isn't just theoretical:
posted state=enrolled and application_no=HACKED-0001 directly at
/website/form/mc.applicant on a live instance, and the resulting
record came back with the model's own default state=applied and a
server-generated APP20260004 - the injected values were silently
dropped, exactly as the whitelist should do. Also exercised a real
file upload (birth certificate) and the full convert-to-student path
(guardian dedup by email, application_no -> student.application_no,
enrollment, attachment reparenting) via odoo shell against the live
container, not just read by inspection.

mc.student gets a new application_no field (_inherit from this
module, not O1 - it only makes sense where admission is installed)
so "the application number persists on the student" is a stored fact,
not just a claim in the demo script.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-11 11:55:48 -04:00

38 lines
1.9 KiB
XML

<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Populates the pipeline kanban so it reads as a real pipeline, not
an empty board, without pre-empting the live Scene 2 walkthrough
(Applied -> ... -> Enroll), which starts from a fresh public-form
submission during the demo itself. -->
<record id="demo_applicant_kavya_reddy" model="mc.applicant">
<field name="name">Kavya Reddy</field>
<field name="dob">2018-03-14</field>
<field name="program_id" ref="mc_education_base.demo_program_grade5"/>
<field name="guardian_name">Suresh Reddy</field>
<field name="guardian_relationship">father</field>
<field name="guardian_phone">+91 98450 11223</field>
<field name="guardian_email">suresh.reddy@example.com</field>
<field name="state">document_verification</field>
</record>
<record id="demo_applicant_ishaan_malhotra" model="mc.applicant">
<field name="name">Ishaan Malhotra</field>
<field name="dob">2015-07-22</field>
<field name="program_id" ref="mc_education_base.demo_program_grade8"/>
<field name="guardian_name">Priya Malhotra</field>
<field name="guardian_relationship">mother</field>
<field name="guardian_phone">+91 99000 44556</field>
<field name="guardian_email">priya.malhotra@example.com</field>
<field name="state">interview</field>
</record>
<record id="demo_applicant_emma_tremblay" model="mc.applicant">
<field name="name">Emma Tremblay</field>
<field name="dob">2018-11-02</field>
<field name="program_id" ref="mc_education_base.demo_program_grade5"/>
<field name="guardian_name">Marc Tremblay</field>
<field name="guardian_relationship">father</field>
<field name="guardian_phone">+1 519-555-0148</field>
<field name="guardian_email">marc.tremblay@example.com</field>
<field name="state">offered</field>
</record>
</odoo>