OD311 unknown-qweb-template¶
A QWeb view or a report names a template no module in scope defines.
| Category | Severity | Series | Needs the index |
|---|---|---|---|
| Correctness | Error | all | yes |
What it reports¶
A literal t-call="x", or an <attribute name="t-call"> that sets one, in a <template> or a
QWeb ir.ui.view of a data file the manifest loads, when no module in the module's scope defines
x. A view defines x by its full XML id or its key. A template that only a module missing from
depends defines is reported too, naming that module. A module that Odoo always installs with
base, such as web, counts as in depends. A module that Odoo auto-installs with the calling
module counts too, as a render after the install finds it: OD210 sets out which ones
do. A render inside the install, such as from a hook, comes before that module loads, and a module
that a database skipped earlier stays out, so add it to depends when either applies. From
saas~17.1 a module with a countries list stays reported, as whether it installs rests on the
companies of the database: add it to depends.
Only a file Odoo loads defines a target: one the manifest lists under a key the module's series
reads, as OD502 tabulates, or one the module loads itself. A file whose name appears in
the module's Python code counts, whatever key lists it, as that code loads it (18.0
addons/hr/models/hr_employee.py:696). So does a chart template under data/template/, on every
series though Odoo reads one from saas~16.2. A file listed under a key Odoo loads nothing from, such
as other_files, counts unless a legacy key the series ignores lists it too, as it was meant to
load from there. 18.0 reads data and not update_xml (odoo/modules/loading.py:39-48), so a file
under update_xml and other_files counts as unlisted there, while 9.0
(openerp/modules/loading.py:60-64) and 10.0 (odoo/modules/loading.py:57-61) load it. A template
found only in any other file, tests/ and migrations/ included, counts as undefined: list that
file under data.
It also reports the report_name of an ir.actions.report, written by a <record> from 11.0 on or
by a <report> tag from 11.0 to 16.0, when its report_type renders QWeb: unset, which means
qweb-pdf, or any qweb-* text.
The rule matches the whole name and never adds the module of the view, so an undotted target can
only find a key, and that match stays silent on every series, while one that finds no key is
reported. From saas~18.4 Odoo finds such a key too (20.0
odoo/addons/base/models/ir_ui_view.py:1208). Through saas~18.3 it refuses any undotted name with
Invalid template id (18.0 odoo/addons/base/models/ir_ui_view.py:2107-2108), so a match on a key
hides a render that fails. From 10.0 a website lookup is exempt.
A <template> without id takes its XML id from t-name, the module added when undotted, so
<template t-name="sheet"> in module m answers to m.sheet and not to sheet. Beside an id,
t-name names nothing.
The root of a <template> with a non-empty inherit_id calls nothing, primary="True" or not:
Odoo renames that root to <data> and applies only its children, so its t-call never runs and is
not read. What its specs add is read. An empty inherit_id extends nothing, so that root keeps its
t-call.
A t-call on a spec calls nothing either: <t t-call="old.name" position="replace"/> locates that
call in the parent view, and OD310 reports it when the parent has none. A spec needs no
position, and a position="move" child of a spec locates too. What a spec holds is read, and so is
its <attribute name="t-call">. Any other t-call is read, whatever position it carries: from
19.0 on that is a parameter of the call, and earlier QWeb ignores it.
Why it matters¶
Odoo looks the target up when the t-call runs, and a target it cannot find fails the render. The
install does not check the name, so the error reaches the user who opens the report or the page, and
a t-call under a t-if only fails when that branch runs. When the template comes from a module
outside depends, the page renders where that module is installed and breaks where it is not. A
report is the same: it installs, and fails when someone prints it, even with a Python report model,
which gives the values and leaves the template required.
The rule leaves alone what only a render can tell: an expression such as {{ x }} or #{x}, a
numeric view id, and a path to an .xml file. A kanban arch runs its t-call in the web client,
against the templates of its own arch, so a view whose inheritance tree starts at a non-QWeb view is
not checked. For a module whose dependencies include one that is not indexed, such as an Enterprise
module, the rule stays silent on a target whose prefix names no indexed module, and on one that an
indexed module outside depends defines, since that dependency may load the module. It still
reports such a target when every module defining it depends on the calling module through indexed
modules, which no dependency can load, and a target no indexed module defines when its prefix names
an indexed one. Add the checkout of the dependency that is not indexed to --addons-path to check
these targets. The rule also stays silent on a target no module defines when an unread data
file may define it. Targets in Owl templates under static/src are OD605's.
On a report, the rule reads the last report_name and report_type of a record, and the last value
each has across the writes of the module and its dependencies, and only that write of report_name
reports. A demo write does not count for a data value, as a database may hold no demo data. A name
the field takes from an eval, ref, search, file or type, or a report_type that is any
other value, stays silent, and so does a blank, numeric or path name. report_file is never read:
no render path uses it. A <report> tag stays silent in a module of unknown series.
An override of ir.actions.report can handle a report by name and return before the template
renders, so the report prints with no template while the rule reports its report_name. In 20.0
stock_delivery prints chatter attachments that way
(addons/stock_delivery/models/ir_actions_report.py:59-87) and ships empty <template> shells
(addons/stock_delivery/report/shipping_reports.xml:5-6). Add such a shell, or suppress the finding.
Example¶
<template id="portal_invoice">
<t t-call="web.basic_layot">
<div class="page">Invoice</div>
</t>
</template>
The template is web.basic_layout, so the page fails as soon as it renders.
<template id="portal_invoice">
<t t-call="web.basic_layout">
<div class="page">Invoice</div>
</t>
</template>
A report fails the same way, when it prints. Its template is sale_portal.report_invoice:
<record id="action_report_invoice" model="ir.actions.report">
<field name="name">Invoice</field>
<field name="model">res.partner</field>
<field name="report_name">sale_portal.report_invoicing</field>
</record>
<record id="action_report_invoice" model="ir.actions.report">
<field name="name">Invoice</field>
<field name="model">res.partner</field>
<field name="report_name">sale_portal.report_invoice</field>
</record>