Skip to content

v18.0.0.22.0 - #355

Open
FherStk wants to merge 110 commits into
mainfrom
v18.0.0.22.0
Open

v18.0.0.22.0#355
FherStk wants to merge 110 commits into
mainfrom
v18.0.0.22.0

Conversation

@FherStk

@FherStk FherStk commented Jul 22, 2026

Copy link
Copy Markdown
Member

What's new:

Attendance and strikes:

  • Attendance statuses are now a separate model, and can be setup within the configuration entry at student's attendance section.
  • Strike motives are now a separate model, and can be setup within the configuration entry at coexistence section.

New color selector:

  • The integer native color selector has been changed to the char native color selector, which offers a complete color palette.
  • This new selector has been applied to the attendance templates, employee roles and departments.

Item 2:

  • xxx
  • yyy
  • zzz

Changes:

Strikes:

  • Now is possible to mark if the student has been kicked out from the classroom (false by default).
  • Strikes will be also visible within the history's session form.

Departments and teachers:

  • The department form has two fields: department chief and seminar chief. Also allows defining the roles, if the defaults are not OK.
  • Changing the chiefs affects their roles, and also the teacher's managers in the hierarchy.
  • The roles cannot be changed manually from the teacher form.
  • Top-level departments (VET, ASP, ESO/BTX...) can be used to define who is the head of studies and which role should be used.
  • Top-level departments can be defined by areas (ASP, Academic), affecting some roles (secretary).
  • Child departments can inherit their parent's manager.

Accounts:

The "Create Google Account" or "Suspend Google Account" mechanism has been improved. It will be clear that, if the teacher already have a work email but no user, it will just create the local user and sync it with the Google account (no new account will be created).

Search:

  • Diacritics will be ignored.

Withdrawal:

  • Withdrawal button removed, behavior included in the archival procedure, so alumni and withdrawal students will be set as archived, the standard Odoo procedure.
  • Same behavior as archiving a teacher, just archive the student and follow the wizard.
  • The user experience and the results are exactly the same as before, nothing changed for the user (except for the button removal).

Student's attendance reports:

  • Added a new pivot grid view, allowing custom reports and also data download (XLSX).
  • The 3 report generation wizards have been combined into a single one, and also simplified.
  • Added a new graphic view with two measures per student: absence % (default) and strike count.
  • Improvements to boost the performance and also the security related to the access rules.

Direct-debit invoicing (now requires an approved bank account):

  • Generating a direct-debit invoice for an unapproved/untrusted bank account now raises a clear error instead of silently attempting (and unreliably failing) to self-approve it at invoicing time.

Fixes:

Enrollment header (tutor group/study mismatch):

  • Added a server-side guard (sale.order._check_group_matches_study) preventing a destination group from a different study than the one selected for the enrollment.
  • Previously only enforced client-side (onchange), so a direct write (e.g. a tutor editing the form directly) could bypass it.

IBAN trust migration would have failed on a real production upgrade:

  • _backfill_iban_trust's only test coverage ran under test_enable=True, which happened to bypass the exact rights check (res.partner.bank._user_can_trust()) that blocks it for real. Fixed with an explicit install_mode=True context, matching how Odoo's own data loader always runs.

Legacy NULL boolean on ems.course silently unfixable by data resync:

  • One course row had a pre-existing SQL NULL on is_enrollment_default (predating the field's introduction) that a CSV re-sync can never correct on its own, since Odoo's ORM reads NULL and False as equivalent. Backfilled explicitly via a one-time migration.

LimeSurvey block "special" filter (asymmetric mutual exclusion):

  • Replaced two Boolean checkboxes (special_wpi_enrolled/special_subject_enrolled) with a single special_type radio field, making the mutual exclusion structural instead of logic-enforced. Previously, checking one after the other could silently revert the first with no feedback, and only in one direction.
  • A migration preserves the existing data.

Grade session sync guard (asymmetric with attendance template sibling):

  • ems.enrollment.unlink()'s grade-session sync hook now checks whether the student is still enrolled via another row before removing their grade lines, mirroring the equivalent guard its attendance-template sibling already had.
  • The only historical trigger (a duplicate enrollment row) is already prevented by the earlier unique-constraint fix, so this closes the asymmetry defensively rather than fixing an active issue.

ems.enrollment duplicate rows (student/group/subject):

  • Added a UNIQUE(student_id, group_id, subject_id) constraint on ems.enrollment.
  • A migration deduplicates the pre-existing duplicate rows first (kept the earliest row of each pair; all were field-identical duplicates).

Authorization templates (inconsistent level/study matching):

  • Unified two code paths (retroactive template apply, and live onchange sync) that used different logic (AND vs OR) when a template restricted both level and study.
  • Both now use AND consistently.

Portal IBAN renewal (bank account never trusted):

  • /my/documentacion/renew-iban now marks the underlying bank account as trusted (allow_out_payment), matching what the normal secretary-approval flow already did.
  • Previously, a family could satisfy the "valid IBAN registered" requirement to confirm enrollment while their bank account was never actually trusted, silently breaking downstream direct-debit invoicing for that student.
  • A migration backfills trust for every already-approved IBAN document affected by this gap.

Tutor guard (wrong-student's tutor got a generic error):

  • _is_blocked_tutor() now also checks has_access('write') for a tutor, so a tutor of a different student gets the same friendly error message a plain teacher gets, instead of a bare AccessError from the underlying access rule.
  • Uses Odoo's own access-check API (has_access) rather than re-deriving the rule's condition in Python, so this can't drift out of sync with security/rules/contacts.xml.

Student import (silent data-quality gaps now surfaced as warnings):

  • An Esfera group code with no matching EMS group, and a tutor row with no document number (which skips family-contact deduplication), are both still handled the same way as before — but now also appear as warnings in the import result summary, instead of only being discoverable by opening individual records afterward.

Enrollment uniqueness race condition (no DB-level backstop):

  • Added a partial unique index (sale_order.init()) enforcing the same "one active enrollment per student per course" rule the existing Python check already enforces, closing a theoretical race condition between two concurrent transactions.
  • create()/write() now translate the rare resulting database error into the same friendly message the existing check already shows, so the fix is invisible in normal use.

Internal changes:

Shared authorization-matching logic

  • Extracted a shared ems.authorization.template._matches_scope() predicate so the two authorization-matching code paths can't drift apart again.

data/custom __import__. prefix backlog closed:

  • Converted the last 140 XML records under data/custom/ (ems.planning, ems.course, ems.authorization.template, ir.sequence) to CSV, rescoped to the __import__. xmlid prefix via a new pre-migrate reconciliation step — centre-specific data no longer at risk of being deleted on a module upgrade.
  • One record type (sale.order.template.line resolved via a dynamic search= domain) stays XML as a confirmed, documented, permanent exception — enforced by a new test assertion.
  • data/custom/ is now explicitly documented as reapplied-every-upgrade config (matching data/cat/), with a narrow exclusion for fields the app itself mutates at runtime (e.g. ems.course.is_current).

Shared "still enrolled" check

  • Extracted ems.enrollment._ems_still_enrolled(), reused by both unlink() sync hooks, so future code needing the same "is this student still covered by a sibling enrollment" check doesn't have to duplicate the query.

Test coverage gap closed

  • Added the first test exercising the WorkPlace Internship branch of compute_survey_data — previously untested.

Portal controller test coverage

  • Added the first HttpCase-based controller test for controllers/portal_enrollment.py.

First browser tour for LimeSurvey blocks

  • Added the first tour test for ems.limesurvey_block's form (reached as a "form within a form" from the survey header), covering the new special_type radio field.
  • Caught two pre-existing, unrelated bugs affecting other views too: select doesn't work on a plain <select> field (use selectByLabel), and widget="code" fields need direct Ace-editor API calls, not the generic edit action.

Other changes:

  • Notification system if developing within a container, to warn about tests that cannot end because the browser is still connected to the development environment's EMS.
  • Every model has been documented, tested, optimized, and normalized (DTON).
  • General optimization and refactoring (including test code).
  • zzz

Item 2:

  • xxx
  • yyy
  • zzz

Related with:

@FherStk

FherStk commented Jul 30, 2026

Copy link
Copy Markdown
Member Author

/clean-changelog

1 similar comment
@FherStk

FherStk commented Jul 30, 2026

Copy link
Copy Markdown
Member Author

/clean-changelog

@FherStk

FherStk commented Jul 30, 2026

Copy link
Copy Markdown
Member Author

/clean-changelog

@FherStk

FherStk commented Jul 31, 2026

Copy link
Copy Markdown
Member Author

/deploy-check

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment