Repository navigation
Conversation
The 20.0 skeleton bumps ruff v0.13.0 -> v0.16.8, whose default rule set is much wider. .ruff.toml only ever said extend-select, so that drift silently switched on whole families the repo never chose. Pinning select to ruff's classic default reproduces exactly what v0.13.0 enforced on 19.0. Assisted-by: Claude Opus 5
OCA's 20.0 branch is 19.0 plus a commit flipping installable to False, so the
module history is already present and nothing needed replaying -- unlike the
orphan skeletons in other repos. FROM_VER is origin/19.0, which is what
production pins (erp/odoo-19/prod/repos.yaml), not the diverged
ledoent/19.0-mig-mis_builder.
* 20.0 merged ir.model.access and ir.rule into one ir.access model. The 23 ACL
rows and the global multi-company rule become security/ir.access.csv (24
rows, none dropped) and mis_builder_security.xml goes away. Same for the
budget and demo modules' XML-declared ACLs and their 4 global rules.
* odoo/tools/safe_eval.py is a package in 20.0, and compile_codeobj is missing
from safe_eval/evaluation.py's __all__ -- so the package's star re-export
does not carry it and importing it from odoo.tools.safe_eval raises
ImportError. Imported from the submodule.
* The legacy "<>" domain operator is gone; 20.0 accepts only "!=". aep.py built
("debit", "<>", 0.0) domains, which now raise ValueError at search time.
* ir.actions.report.report_file no longer exists, so the xlsx report record
failed to load.
* Char fields *named* `name` now copy with a "(copy)" suffix unless copy is
declared (orm/fields_textual.py:529-533). mis.report.kpi, .subkpi and .query
all constrain name to a valid python identifier, so duplicating a report
raised ValidationError. Those three declare copy=True explicitly.
* pytz is rejected by .pylintrc-mandatory and is no longer in Odoo's own
requirements. _utc_midnight moves to zoneinfo; pytz's
localize(..., is_dst=False) resolved the ambiguous DST fall-back hour to
standard time, which zoneinfo spells fold=1.
* Owl 3: useState -> proxy, useSubEnv from @web/owl2/utils, and `static props`
-> props = useProps({t.*}). SearchModel's constructor takes a wider service
bag now and calls usePlugin() internally, so field/name/tree_processor are
supplied as well -- core's WithSearch is the reference. The field widget also
had to declare props at all, since Owl 3 only materialises declared ones; it
is bound to the `id` field, so props.record.resId replaces the props.value
read, which had been dead since standardFieldProps stopped carrying value.
* env.clear() is deprecated in 20.0 in favour of transaction.clear, and OCA's
checklog gate turns that DeprecationWarning into a job failure even though
every test passes.
* t-esc -> t-out, and 17 fa-* icons -> Material Symbols (20.0 ships no
FontAwesome).
* Dropped the dead "qweb" manifest key and made the summary one line.
100 tests pass.
Assisted-by: Claude Opus 5
dnplkndll
force-pushed
the
20.0-mig-mis_builder
branch
2 times, most recently
from
October 1, 2026 15:08
45fcd6e to
3680945
Compare
… branches Assisted-by: Claude Opus 5
Previewing any MIS report died client-side with
TypeError: Cannot read properties of undefined (reading 'mis_report_data')
at MisReportWidget.template_mis_builder_MisReportWidget
Owl 3 renders a template with `{this}` as the ENTIRE context. A bare
identifier is not a component member any more, it is undefined -- so
`state.mis_report_data` read a property off nothing and took the widget down
before it drew a single row. 23 sites across the widget and the annotation
dialog: `state`, `props`, and every handler (`refresh`, `printPdf`,
`exportXls`, `drilldown`, `annotate`, `remove_annotation`, ...).
`this` is also the *whole* context, so GLOBALS are not in scope either. With
the members fixed the widget rendered and then threw
`Cannot read properties of undefined (reading 'stringify')` on
`JSON.stringify(cell.drilldown_arg)`. Core 20.0 uses JSON.stringify in zero
templates and keeps it in JS, so this adds a `drilldownArg(cell)` helper and
calls that instead.
Left bare deliberately: `notes`, `cell`, `row` and friends are bound by t-set
and t-foreach in these same templates, and prefixing them would break the
loops.
Why the MIG missed it: upgrade_code's owl3-migration `upgrade_this` sub-task
only matches components declaring `static template = "..."`. This widget does
`MisReportWidget.template = "mis_builder.MisReportWidget"` -- an assignment --
so the sub-task matched nothing and prefixed none of it. The 100 python tests
stayed green throughout; the module ships no JS tests, and only rendering the
widget can see this.
Found by walking the migrated production copy in a browser, which is also how
the same bug was found in dms.
Assisted-by: Claude Opus 5
dnplkndll
force-pushed
the
20.0-mig-mis_builder
branch
from
October 3, 2026 14:41
8ed21cd to
cbf08f6
Compare
…filter Follow-up to cbf08f6, which converted this template to `this.` but missed the DateTimeInput node. Owl 3's render context is `{this}` only, so a bare identifier is undefined: value="state.pivot_date" -> TypeError reading 'pivot_date' onChange.bind="onDateTimeChanged" -> TypeError reading 'bind' Both are inside `t-if="this.showPivotDate"`, and `widget_show_pivot_date` defaults to False -- so the node had never rendered on 20.0 and the earlier pass had nothing to fail against. Enabling the picker on any instance makes Preview die client-side with an Oops dialog. Verified in a browser against a copy of production on the 20.0 image: the report renders, and setting the base date to 12/31/2025 re-anchors both columns (NET INCOME 15,848.49 YTD-2026 -> -3,075.49 FY2025 vs 28,783.42 FY2024) with a clean console.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Port of
mis_builder(and themis_builder_budget/mis_builder_demoACL conversions) from 19.0 to 20.0. Depends onreport_xlsx(OCA/reporting-engine#1203) anddate_range(ledoent/server-ux#7), both pinned intest-requirements.txt— that pin is what makesDetect unreleased dependenciesred.100 tests pass for
mis_builder, 18 formis_builder_budget.OCA's
20.0branch here is 19.0 plus a commit flippinginstallabletoFalse, so the module history is already present and nothing needed replaying — unlike the orphan skeletons in other repos. FROM_VER isorigin/19.0, which is what production pins, not the divergedledoent/19.0-mig-mis_builder.Non-mechanical adaptations worth flagging
ir.model.access+ir.rule→ oneir.accessmodel. 23 ACL rows plus the global multi-company rule become a 24-rowsecurity/ir.access.csv; audited against the original, nothing dropped. Same conversion for the budget and demo modules' XML-declared ACLs and their four global rules.odoo/tools/safe_eval.pyis a package in 20.0, andcompile_codeobjis missing fromsafe_eval/evaluation.py's__all__— so the package's star re-export does not carry it and importing it fromodoo.tools.safe_evalraisesImportError. Imported from the submodule instead.The legacy
<>domain operator is gone; 20.0 accepts only!=.aep.pybuilt("debit", "<>", 0.0)domains, which now raiseValueErrorat search time.ir.actions.report.report_fileno longer exists, so the xlsx report record failed to load the module.Charfields namednamenow copy with a "(copy)" suffix unlesscopyis declared (orm/fields_textual.py:529-533).mis.report.kpi,.subkpiand.queryall constrainnameto a valid python identifier, so duplicating a report raisedValidationError. Those three now declarecopy=Trueexplicitly.pytz→zoneinfo.pytzis rejected by.pylintrc-mandatoryand is no longer in Odoo's ownrequirements.txt. The subtlety:localize(..., is_dst=False)resolved the ambiguous DST fall-back hour to standard time, whichzoneinfospellsfold=1— not a plainreplace(tzinfo=...).Owl 3.
useState→proxy,useSubEnvfrom@web/owl2/utils,static props→props = useProps({t.*}).SearchModel's constructor takes a wider service bag now and callsusePlugin()internally, sofield/name/tree_processorare supplied too — core'sWithSearchis the only in-core reference for building one. The field widget also had to declare props at all, since Owl 3 only materialises declared ones; it is bound to theidfield, soprops.record.resIdreplaces theprops.valueread, which had been dead sincestandardFieldPropsstopped carryingvalue.t-esc→t-out, and 17fa-*icons → Material Symbols (20.0 ships no FontAwesome in any form)..ruff.tomlpinsselectto ruff's classic default: the skeleton bumps ruff v0.13.0 → v0.16.8, whose much wider default silently switched on whole families the repo never chose, since the file only ever saidextend-select.AI-assisted (Claude Code); every change reviewed, tested, and owned by the author.