Skip to main content
iVentureTeam

package_m2m

Package names as tags on a transfer line, plus a synthetic No Package tag for the lines that are not in one. It is deliberately display only, and the code makes sure of that.

Siddharth JambukiyaSiddharth JambukiyaOdoo Techno-Functional Consultant
August 27, 2026Updated September 7, 20265 min read
Technical namepackage_m2m
Field typesmany2many
Viewslist, form
Modulestock, the Inventory app
Used in core1 occurrence, the packages column of the operations list in stock
VersionsOdoo 20.0, Odoo 19.0
No-code setupNo. It reads a picking-specific companion field and is intended as read-only
Alternativesmany2many_tags, package_m2o, sml_x2_many, stock_move_one2many

What the package tags cell does

A stock move can be split across several packages, and some of its quantity may not be packed at all. Showing that as a table would take a block of space on every line; showing only the package names loses the unpacked part.

This widget renders the packages as tags and then adds one more when needed. If the move has lines without a package, a synthetic No Package tag joins the real ones, so a glance at the column tells you both what is packed and that something is not.

It is meant to be read, not edited. The core view marks the field read-only, and the code backs that up: the widget's own initialization replaces the parent's rather than extending it, so none of the tags widget's editing behavior is set up.

What this means for your team

Partially packed moves are the case that causes disputes at the receiving end, because the paperwork says one thing and the pallet says another. Surfacing the unpacked remainder in the same column as the packages puts that on the screen of the person who can still fix it.

The read-only intent is worth respecting in customizations. Making the field editable in an inherited view will render an input that has none of the machinery behind it, because the widget never initialized it. If packages need editing, that belongs on the detailed operations rather than on this summary column.

Supported options in Odoo 19

The widget declares no options of its own. It spreads the tags widget's descriptor, so the options below are inherited, and it injects one related field it needs. In practice most of them are moot, because the field is intended to be read-only. Read from stock_package_m2m.js and the tags field, Odoo 19.0.

OptionTypeWhat it does
has_lines_without_result_packagecompanion fieldRead by literal name at setup. When true, a synthetic No Package tag is added after the real packages. Read once, so it does not react to later changes.(since Odoo 19.0)
nameinjected related fieldAdded by the descriptor so each package's short name is available. Tags print this rather than the display name.(since Odoo 19.0)
color_fieldfieldInherited from the tags widget. Names an integer field used to color the tags; the synthetic tag inherits whatever the last real package had.

The extra tag comes from a companion field. Whether the No Package tag appears is decided by a boolean on the move, read by literal name at setup. It is read once, so a change to that flag while the row is on screen does not add or remove the tag until the list is redrawn.

Working examples

The core usage

<field name="package_ids" widget="package_m2m"
       optional="show" readonly="1"
       groups="stock.group_tracking_lot" width="200px"/>

Read-only and group-gated. Both are part of the intended usage rather than incidental.

The companion field it reads

# on the move, read by literal name at setup
has_lines_without_result_package
# true adds the synthetic No Package tag

Not declared as a dependency, so the move must carry it for the extra tag to appear.

The plain tags widget

<field name="package_ids" widget="many2many_tags"/>

Editable and fully wired, but with no No Package tag and printing display names instead of package names.

A widget that deliberately never initializes its parent

Three details define this widget, and two of them are unusual enough to be worth stating plainly.

First, its initialization does not chain to the parent. It sets one property and stops, which means every hook the tags widget would normally install, including the ones that handle adding and removing tags, is never created. That is not an oversight to work around; it is why the field is declared read-only in the view. Treat the widget as a display component.

Second, the synthetic tag is built by copying the properties of the last real package in the list and then replacing its identifier and text. That is a pragmatic way to get a tag with the right shape, and it has a visible consequence: the No Package tag inherits whatever color and options that unrelated package had. On a move with no packages at all, there is no record to copy from.

Third, tags print the package's name field rather than its display name, and the descriptor injects that field into the related data so the view does not have to request it. That keeps the column narrow, because package display names carry additional context that would not fit.

Version compatibility

VersionStatusNotes
Odoo 20.0Partial / changedNot released. Reworked internally alongside the wider tags rework; the concept is unchanged.
Odoo 19.0VerifiedFirst version. Verified against the shipped source.
Odoo 18.0Not availableWidget does not exist.
Odoo 17.0Not availableWidget does not exist.
Odoo 16.0Not availableWidget does not exist.

Upgrade note. The widget is new in Odoo 19, with the rewritten operations list. On Odoo 18 and earlier the packages were shown differently on the transfer form, so an upgrade gains the column with the standard views and no migration is needed.

What is changing in Odoo 20

Odoo 20 is expected at Odoo Experience in Brussels, 24 to 26 September 2026. The development branch is unstable and this may still change; we re-verify the page after release.

Reworked alongside the tags components. The development branch changes this widget as part of the wider rework of how tags are built, in the same wave that reshaped other tag widgets in core. The No Package concept and the read-only intent are unchanged; the internals are not.

Common problems and fixes

SymptomCause and fix
The No Package tag never appearsThe move does not carry the companion flag, which is read by literal name and not declared as a dependency. Make sure the field exists and is loaded on the move.
The field cannot be editedIntended. The widget never initializes the tags widget's editing machinery, and the core view marks it read-only. Assign packages on the detailed operations instead.
Making it editable renders a broken inputSame cause: the parent initialization was never run. Leave the field read-only, or use the plain tags widget if editing is genuinely required.
The No Package tag has an odd colorIt copies the properties of the last real package in the list. Expected. It is a synthetic tag with no record of its own.
The column is missingThe user is not in the package tracking group, which gates the field in the core view. Enable package tracking and add the user to that group.
Tags show short names, not full onesThe widget prints the package's name field, injected as a related field, rather than its display name. Expected, and deliberate, to keep the column narrow.

Package tags cell vs the alternatives

WidgetBest forKey difference
package_m2mSeeing at a glance which packages a transfer line touches, and whether anything is unpackedAdds a synthetic No Package tag and is display only by design
many2many_tagsAn editable list of related records as tagsFully wired for editing, and no No Package concept
package_m2oA single package relationOne package rather than a set
sml_x2_manyAssigning packages on the detailed operationsWhere packages are actually set, rather than summarized
stock_move_one2manyThe list this column lives inThe list widget rather than a cell

Use the plain tags widget wherever packages should be editable, and remember it will not show the unpacked remainder. If the goal is to work on packages rather than to see them, the detailed operations list is the place, since that is where a package is actually assigned.

Frequently asked questions

What is the No Package tag?+
A synthetic tag with no record behind it, added when the move has lines that are not in a package. It is built by copying the last real package's tag properties and replacing its identifier and text.
Why can I not edit the packages here?+
The widget's initialization does not chain to the tags widget's own, so none of the editing behavior is set up. The core view marks the field read-only for that reason.
Why do the tags show short names?+
The widget prints the package's name field rather than its display name, and injects that field as a related field so the view does not have to load it. It keeps the column narrow.
Why does the No Package tag have a strange color?+
It inherits the properties of the last real package in the list, including anything derived from a color field. There is no record of its own to color.
Which versions have it?+
Odoo 19 onwards, introduced with the rewritten operations list. The development branch reworks its internals alongside the wider tags rework.

Packing that matches what the paperwork says

Packages, pallets and partially packed transfers are where warehouse accuracy is won or lost. We configure Odoo Inventory package handling and the documents that follow it, on versions 16 through 19.

Book a free consultation

How this page was produced

The missing parent initialization, the synthetic tag construction, the injected name field and the literal read of the companion flag were read from stock_package_m2m.js on the Odoo 19.0 branch, with the inherited behavior read from the tags field in web. The usage, its read-only attribute and its group restriction come from stock/views/stock_picking_views.xml. Version coverage comes from the absence of the file on 16.0, 17.0 and 18.0, and a comparison against the public development branch. Spotted an error? Tell us and we will correct the page.