Moodle Grade Sync
Grades recorded in Moodle, through the gradebook, assignment submissions, or quiz attempts, flow into OpenEduCat's gradebook automatically. Every 15 minutes, the sync service checks for changes. Records that haven't changed are skipped. When something changes, the OEC record is updated and gradebook totals are recomputed.
Moodle is the authoritative source for learning data. When a conflict exists, Moodle wins. The sync prevents infinite write loops by setting a connector_no_export flag on the Odoo environment during all pull operations.
Supported Grade Sources
Four grade sources from Moodle, each pulled via a specific WS function and written to a specific OEC model.
| Grade source | Moodle WS function | OEC target model | Notes |
|---|---|---|---|
| Gradebook grades | gradereport_user_get_grade_items | op.result.line / gradebook.line | All grade items from the Moodle gradebook. Course totals and category subtotals are skipped to prevent double-counting. |
| Assignment submissions | mod_assign_get_grades | op.exam.attendees | Full assignment submission grade. Uses since=0 for a complete pull. Null grades are skipped, a missing submission does not write 0. |
| Quiz best-grades | mod_quiz_get_user_best_grade | op.exam.attendees | Best attempt only, not per-attempt history. Quiz IDs stored with +1,000,000 offset to avoid hash collision with grade item IDs. |
| Course completion | core_completion_get_course_completion_status | moodle.mapping.extra_data | Stored as "complete" or "incomplete" string in the enrollment mapping row. Does not change OEC enrollment state directly. |
Grade Pipeline
What happens inside SyncGrades.pull_all_combined() on every cron run.
Cron fires (every 15 min)
_cron_grade_pull on the moodle.instance model iterates all active instances.
Fetch grade items from Moodle
SyncGrades._prefetch_mappings() loads all student mappings in one query into _student_map. Then gradereport_user_get_grade_items is called per Moodle course.
Hash comparison
SHA-256 of (grade_raw:grade_max) is compared against moodle.mapping.sync_hash. Unchanged grades skip all OEC writes.
OEC record creation
Community path: op.exam.session → op.exam → op.exam.attendees + op.result.line. Enterprise path (if openeducat_grading installed): grading.assignment → gradebook.gradebook → gradebook.line.
Gradebook recompute
_recompute_gradebooks() calls calculate_percentage() and student_Grade_override() once across all affected gradebooks, not per-grade-item.
Completion sync
SyncCompletion runs after grade pull, updating enrollment mapping extra_data with complete/incomplete per student-course pair.
Sync Frequency and Triggers
Cron (default)
Every 15 minutes
_cron_grade_pull runs on all active instances. Lightweight due to hash-skip on unchanged records.
Manual trigger
Immediate
"Pull Grades Now" button on the Moodle Instance form in Odoo, or call action_pull_grades_now() via RPC.
Manual wizard
On demand
The Sync Wizard supports a dry-run preview before committing any grade writes to OEC.
Conflict resolution
Moodle is authoritative for learning data. If a grade exists in OEC and the Moodle pull returns a different value, the Moodle value overwrites OEC on the next pull. To prevent the write from triggering a push back to Moodle (which would create an infinite loop), all pull services set connector_no_export=True on the Odoo environment in their constructor:
self.env = env(context=dict(env.context, connector_no_export=True))Every write() hook on OEC models checks this flag before enqueueing a push job.
Community vs Enterprise Grade Path
The sync service detects which OEC edition is installed and writes grades to the appropriate model.
Requires openeducat_exam module. Creates an op.exam.session → op.exam → op.exam.attendees + op.result.line hierarchy. Exam state is advanced via sudo().act_held() because the state field is readonly on the model.
Requires openeducat_grading module (takes priority if both installed). Creates a grading.assignment → gradebook.gradebook → gradebook.line hierarchy. Calls calculate_percentage() and student_Grade_override() once per batch, not per grade item.
Grade Sync Configuration
These fields on the Moodle Instance record in Odoo control grade sync behavior.
| Field | Default | Description |
|---|---|---|
| Pull Gradebook Grades | On | Enable/disable the gradereport_user_get_grade_items pull |
| Pull Assignment Grades | On | Enable/disable the mod_assign_get_grades pull |
| Pull Quiz Grades | On | Enable/disable the mod_quiz_get_user_best_grade pull |
| Grade Scale Type | percentage | How grades are stored in OEC: percentage, letter, or points |
| Pass Threshold (%) | 50.0 | Below this percentage → fail state in community exam creation |
| Grade Scale | (empty) | Letter grade bands from moodle.grade.scale.line (e.g., A=90-100) |
| Pull Completion Status | On | Run SyncCompletion after each grade pull cycle |
Grade Sync, Frequently Asked Questions
Technical questions about the Moodle → OEC grade pipeline.
Ready to Transform Your Grade Sync?
See how OpenEduCat frees up time so every student gets the attention they deserve.
Try it free for 15 days. No credit card required.