OD312 unknown-button-method¶
A button calls a method its model does not have.
| Category | Severity | Series | Needs the index |
|---|---|---|---|
| Correctness | Error | all | yes |
What it reports¶
A <button type="object" name="x"> in a view arch, with a literal name, where neither the classes
of the model, those of the models it inherits, nor BaseModel define x, or where only a module
missing from depends adds it. The model is the one at the button's position: the view's, the
comodel of the x2many field whose subview encloses it, also when an extension adds the subview
directly inside a field of the parent view, or the comodel of the <groupby> around it. An
extension shows only part of that position, so a button it places in a subview can be read
against the view's model: see why it matters. A module that Odoo always installs
with base, such as web, counts as in depends. A method of a model reached through _inherits
or delegate=True does not count, since the model gets that model's fields and not its methods. A
BaseModel method counts in every series, whichever series has it, but one BaseModel lost before
saas~11.5, such as create_workflow, counts only in the series that have it, and in none for a
module of unknown series.
A class defines a method with a def, in its body or under an if, try or with block there, or
with a class attribute whose value may be a method: a name, an attribute, a lambda, a conditional
expression, a subscript, or a call such as partialmethod(...), functools.partial(...) or
api.model(f). A field, as OD210 counts one, a models.Constraint, an Index or a
UniqueIndex defines none, and neither does plain data: a literal, an f-string, a list, a tuple, a
dict, a set or a comprehension.
A button on limit = 3 is reported, as is one on a field. Under a block the rule reads each def
and alias but not the body of a method, and a field there is not read.
Why it matters¶
From saas~13.1 Odoo validates the button when it loads the view, so a misspelled method stops the
install or the upgrade of the module. A demo file differs: see load
failures. Before saas~13.1 the view loads
and the button fails when a user clicks it. A method that a module outside depends adds exists
only where that module happens to be installed.
The rule stays silent when it cannot see every class or tell the model: a module whose dependencies
include one that is not indexed, such as an Enterprise module, a module that builds model names at
runtime, a model that is unknown or outside depends (OD201 and OD202
report those), and a class of the model, or of a model it inherits, with a plain Python base or an
_inherit no indexed module defines, or in a file that does not parse, which
counts as one the scan cannot read. Such a class of a model reached through _inherits or
delegate=True does not count, since those methods stay on that model. It also leaves alone a view
whose root is QWeb or is not indexed, a button with special or position, and a button an
extension anchors on or under a list, tree, kanban or column it does not reach through a
field, since that anchor may sit in the main view or in a subview: an xpath step with no axis, as in
//list or //list/button, or a spec with position, as in <list position="inside">.
An extension can place a button in a subview, and the rule reads the extension without its parent
view, so a correct button can be reported when the rule takes that subview for the main view. An
anchor is the element a spec locates, and the rule reads the buttons the spec adds there. It follows
the field an xpath names on the way to the anchor, or the field a spec adds a subview inside, and
reads the button against that field's comodel. It stays silent where it cannot tell the model: on
the list, tree, kanban or column anchors above, and in a subview added inside a field when a
subview of the inheritance tree is on a model that may have that field too, since a spec locates the
first field of that name anywhere. Otherwise it reads the view's model. Name the field on the way
in, as in //field[@name='line_ids']//button[@name='action_split'], and suppress the finding where
no such anchor exists.
A private name is OD313's. Names built at runtime, as with t-att-name, are not
checked.
Example¶
sale.order has no action_confirmm, so the module fails to install.