Skip to main content
iVentureTeam

package_m2o

The many2one that Inventory uses for packages. package_m2o looks like a plain relation field until you notice the names it displays change with the transfer's state and context.

Siddharth JambukiyaSiddharth JambukiyaOdoo Techno-Functional Consultant
August 12, 2026Updated August 12, 20266 min read
Technical namepackage_m2o
Field typesmany2one
Viewsform, list
Modulestock (Inventory app)
Used in core12 occurrences across 2 modules: stock and stock_picking_batch
VersionsOdoo 20.0, Odoo 19.0
No-code setupNo. It ships preconfigured on Inventory views; applying it elsewhere is an XML change.
Alternativesmany2one, res_partner_many2one, many2one_uom

What the Package field does

Packages in Odoo Inventory can nest: a box goes on a pallet, the pallet into a container. A package's plain name, PACK0000123, tells a warehouse worker very little about where it sits in that hierarchy. This widget exists to show the right amount of that hierarchy at the right moment.

Structurally it is the standard many2one component wrapped with package awareness, wired on the source and destination package columns of detailed operations and batch transfer lines. The wrapping does three things: it forwards display flags to the server so the package's display name expands into its chain, it shortens names again once a transfer is done, and it fixes the awkward moment where a newly created package shows as Unnamed because its name comes from a sequence the client has not seen yet.

What this means for your team

The widget encodes a warehouse truth: how much package context a person needs depends on what they are doing. While picking, the full chain, which pallet, which box, prevents wrong grabs at the shelf. Once the transfer is done, the chain is history and the short name keeps lists readable. Odoo made that a display rule so each screen does not have to relitigate it, and custom warehouse views should inherit the same thinking instead of reinventing package name formatting.

The second business relevant behavior is creation flow. Warehouse packages are typically named by sequence, and operators create them on the fly mid transfer. The widget's create dialog saves and reloads immediately so the operator sees PACK0000124, not a blank, which sounds cosmetic until you watch someone try to tell two Unnamed packages apart on a busy dock. Small UI guarantees like this are why we keep custom inventory screens on core widgets wherever possible.

Supported options in Odoo 19

Verified against stock_package_m2o.js in the Odoo 19.0 stock module. The widget builds its registry entry through buildM2OFieldDescription, so its declared options are exactly the many2one set, inherited wholesale, including two that the base extractProps reads without declaring. The package specific switches are context keys, covered in the note below.

OptionTypeWhat it does
no_openbooleanInherited from many2one: suppresses the internal link so clicking never navigates to the package form. Common on operational screens where opening records mid picking is a distraction.
no_createbooleanInherited: removes every creation path from the autocomplete, for operations where packages must pre-exist.
no_quick_createbooleanInherited: removes inline creation from typed text while keeping the dialog path, which here is the save and reload dialog described above.
no_create_editbooleanInherited: removes the Create and Edit dialog entry while keeping quick create.
search_thresholdnumberInherited: minimum typed characters before the search fires, instead of searching on focus. Useful on databases with tens of thousands of packages.
placeholder_fieldfield nameInherited: a char field on the record supplying a dynamic placeholder for the empty state.
can_scan_barcodebooleanInherited and undocumented: read by the base extractProps without appearing in the declared options, it flags the field as barcode scannable for Odoo's scanning flows.
create_name_fieldfield nameInherited and undocumented: which field on stock.quant.package receives typed text on quick create. Rarely useful for sequence named packages, but it is read by the shared extract.(default: name)

The package behavior is driven by context, not options. The view passes context="{'show_src_package': True}" or show_dest_package on the field, the widget forwards those flags plus the record's done state into the field context, and stock.quant.package's server side display name computation reads them: source flag renders the package's full chain, destination flag the destination chain, done state the bare name. Options in the table below tune the many2one behavior itself.

Working examples

How core wires the destination package column

<field name="result_package_id"
       widget="package_m2o"
       context="{'show_dest_package': True}"/>

Source package with the full hierarchy shown

<field name="package_id"
       widget="package_m2o"
       context="{'show_src_package': True}"/>

Locking down package creation on a custom view

<field name="package_id"
       widget="package_m2o"
       options="{'no_create': True, 'no_open': True}"/>

All the many2one lockdown patterns apply unchanged, because the widget inherits the full option set.

Context flags, done state and the Unnamed fix

The display name round trip. The widget merges its two display flags and an is_done boolean, true when the parent record's state is done or cancel, into the field's context. Server side, stock.quant.package computes display_name from exactly those keys: done wins and returns the plain name, otherwise the destination or source complete name is returned when its flag is set. Client side there is a second guard: when the record is done and the value still contains a chain, the widget splits on the separator and keeps the last segment. Belt and suspenders, one server side, one client side.

The create dialog override. The autocomplete's create and edit path swaps in a dialog whose save handler saves with an immediate reload, then pushes the reloaded name back into the field. Package names come from sequences assigned at save time, which is why without the reload the UI shows Unnamed until the whole transfer is saved.

Undocumented inherited knobs. Because the base many2one extractProps is reused verbatim, two options absent from the declared list still work: can_scan_barcode, which core's barcode flows use, and create_name_field, which redirects what the typed text becomes on quick create. Both ride along into any view using this widget.

Version compatibility

VersionStatusNotes
Odoo 20.0In developmentNot released. Internal refactor only on the development branch; behavior unchanged. Details below.
Odoo 19.0VerifiedVerified against the shipped source. First version where the widget exists.
Odoo 18.0Not availableWidget absent from the 18.0 tree. Package columns render as plain many2one fields.

Upgrade note. This widget does not exist in Odoo 18: the file and registration appear in 19.0, where package columns previously rendered as plain many2one fields. Custom 18 views cannot reference it, and after migrating to 19 the specialized rendering arrives by simply using the core views, or adding the widget to custom ones.

What is changing in Odoo 20

Odoo 20 is expected at Odoo Experience in Brussels, 24 to 26 September 2026, and these observations come from the public development branch, which remains changeable until feature freeze. We re-verify the page against the shipped release.

No behavior changes are visible for this widget. The master diff is a mechanical refactor: props declarations migrate to the new schema system, the dialog subclass moves inline, and the many2one props are re-declared in the new style with an explicit note that the base field still uses the old declaration. Context flags, done state collapsing, the create and reload flow and the inherited option set all survive unchanged.

One thing to watch is indirect: this widget inherits whatever the many2one family does in 20, so option level changes to the base field would flow through. Nothing of that kind is visible in the current branch state.

Common problems and fixes

SymptomCause and fix
Package shows its full chain where you expected the short nameThe field's context carries show_src_package or show_dest_package, and the record is not done. Drop the context flag on that view if the chain is unwanted.
Package names suddenly shortened after validating a transferDone and canceled records collapse to the last name segment, server and client side. Expected. Open the package record itself to see its position in the hierarchy.
New package briefly named Unnamed in a custom flowA custom creation path bypasses the widget's save and reload dialog, so the sequence name has not been fetched. Create through the field's own dialog, or reload the record after creation in your flow.
The widget errors outside Inventory modelsIt is built for stock.quant.package relations and its display logic assumes that model's context contract. Use a plain many2one for other relations.
View referencing package_m2o fails on Odoo 18The widget only exists from 19.0. Drop the widget attribute on 18, or upgrade; the field works as a standard many2one meanwhile.
Users create junk packages from the dropdownQuick create is open by default, as on any many2one. Add no_create, or no_quick_create to force the dialog path.

Package field vs the alternatives

WidgetBest forKey difference
package_m2oPackage fields on move lines and batch transfersContext aware hierarchy names plus the create and reload fix
many2oneAny other relation on custom warehouse viewsNo package context contract, plain display names
res_partner_many2onePartner fields with company autocompleteSame pattern of a specialized many2one, tuned for partners instead
many2one_uomUnit of measure fields next to quantitiesAnother specialized many2one, packaged with quantity awareness

Within Inventory screens the choice is usually made for you: core already applies the right widget per column. The table matters when building custom warehouse views, where the specialized package rendering versus a plain relation is an actual decision.

Frequently asked questions

What is the package_m2o widget in Odoo?+
The Inventory app's specialized many2one for package fields on move lines and batch transfers. It renders stock.quant.package relations with context aware names, showing the package hierarchy during operations and the short name once the transfer is done.
Why does the same package display differently on different screens?+
The view's context decides. With show_src_package or show_dest_package in the field context, the server returns the package's complete chain; without them, or once the record is done or canceled, it returns the plain name. The widget also trims chains client side on done records.
Does package_m2o support the normal many2one options?+
All of them: the widget builds on the shared many2one description, so no_create, no_open, no_quick_create, no_create_edit, search_threshold and placeholder_field work unchanged, plus the undocumented can_scan_barcode and create_name_field that the base extract reads.
Why did my new package show as Unnamed in a custom screen?+
Package names come from a sequence assigned at save. The widget's own create dialog saves with an immediate reload so the real name appears; custom creation flows that skip that reload show Unnamed until the next save. Reload the created record and the name resolves.
Can I use package_m2o in Odoo 18?+
No. The widget was introduced in Odoo 19; the 18 tree has no trace of it, and package columns there are plain many2one fields. Views must not reference it before 19.
Can I use package_m2o on my own model?+
Only for fields relating to stock.quant.package, because the display behavior is a contract with that model's display name computation. For other relations it adds nothing over many2one.
Does package_m2o change in Odoo 20?+
The development branch shows only internal restructuring, with the context contract, done state behavior and inherited options intact. Since it inherits from the many2one family, base field changes in 20 would flow through, and we re-verify after the September 2026 release.

Warehouse screens slowing the floor down?

Package hierarchies, batch pickings and barcode flows only feel effortless when the views are tuned to how your floor actually moves stock. We build and refine Odoo Inventory operations, custom move line views, scanning flows, package logic, keeping core widgets and upgrade paths intact.

Book a free consultation

How this page was produced

Verified by reading stock_package_m2o.js in the Odoo 19.0 stock module, the shared many2one_field.js that supplies the inherited options through buildM2OFieldDescription and extractM2OFieldProps, and the stock.quant.package display name computation on the server side, which confirmed the context key contract end to end. The 18.0 tree was searched to establish the widget's absence there, and the public development branch was diffed for the Odoo 20 section. Corrections welcome via our contact page.