Skip to content

[FIX] docs: correct four statements about variants, packagings and categories - #20071

Open
Natalie-the-technician wants to merge 4 commits into
odoo:saas-19.4from
Natalie-the-technician:saas-19.4-fix-variants-packagings-categories
Open

Natalie-the-technician wants to merge 4 commits into
odoo:saas-19.4from
Natalie-the-technician:saas-19.4-fix-variants-packagings-categories

Conversation

@Natalie-the-technician

Copy link
Copy Markdown

This PR corrects three inaccurate statements and adds one missing one. All four were
verified against odoo/odoo saas-19.4 at commit cbed569e, both by reading the source
and by measuring on a freshly created database.

1. Sales / Variants: dynamic variants are not created by sales orders only

content/applications/sales/sales/products_prices/products/variants.rst:119

What it said: ":guilabel:Dynamically: Creates variants only when corresponding
attributes and values are added to a sales order."

Why that is wrong: product.template._create_product_variant() is called from seven
places outside of tests: two in the Sales app, three in eCommerce, one in Point of Sale,
and one in Purchase.

App Module File
Sales sale addons/sale/controllers/product_configurator.py:122
Sales sale_product_matrix addons/sale_product_matrix/models/sale_order.py:62
eCommerce website_sale addons/website_sale/controllers/main.py:835
eCommerce website_sale addons/website_sale/models/product_template.py:1114
eCommerce website_sale addons/website_sale/models/sale_order.py:707
Point of Sale point_of_sale addons/point_of_sale/models/product_template.py:81
Purchase purchase_product_matrix addons/purchase_product_matrix/models/purchase.py:49

(_create_first_product_variant() at addons/product/models/product_template.py:1448 also
calls it, but only to materialise the first variant when a product is copied, so it is not
an entry point for choosing a combination and is not counted here.)

Measured on a database with no Sales module installed (product, purchase, stock,
purchase_stock only): enabling the purchase "Variant Grid Entry" setting and filling two
cells of the grid created two dynamic variants. Odoo's own test asserts the same behaviour:
addons/purchase_product_matrix/tests/test_purchase_matrix.py:20 expects 7 variants where
the non-dynamic attributes alone would produce 4.

The sentence about Inventory was added because the opposite was measured on the same
database: confirming a purchase order and validating the incoming receipt created no
variant. There is no field in addons/stock that selects a combination of attribute
values — stock.move, stock.move.line, stock.quant and stock.lot all point at
product.product.

2. Inventory / Packaging: packagings are not product-specific

content/applications/inventory_and_mrp/inventory/product_management/configure/packaging.rst:10

What it said: packagings "must be configured on the individual product form. This is
because packagings are product specific, not generic."

Why that is wrong: the model product.packaging no longer exists in this version.
Searched the whole tree (643 addons directories plus odoo/addons):
grep -rn "_name = ['\"]product.packaging['\"]" addons/ odoo/ returns 0 hits.

A packaging is now an ordinary uom.uom record. The quantity it holds comes from
relative_factor/factor on that single global record
(addons/uom/models/uom_uom.py:17-43); uom.uom has neither product_id nor company_id.
Products reference the packagings they may use through product.template.uom_ids, a
many2many labelled "Packagings" (addons/product/models/product_template.py:159).

Measured: two different products were given the same packaging and both referenced the same
uom.uom record, so one packaging cannot hold a different quantity per product. The only
product-specific part is the barcode, carried by the helper model product.uom, whose
fields are allowed_uom_ids, barcode, company_id, product_id, uom_id — no quantity field.

3. Inventory / Packaging: the setting is called "Units of Measure & Packagings"

Same file, line 132.

What it said: to reveal the field, "tick the :guilabel:Product Packagings checkbox".

Why that is wrong: read from a running database, res.config.settings has no field whose
name contains "packaging". The setting is group_uom, labelled "Units of Measure &
Packagings"
, implying group uom.group_uom ("Manage Multiple Units of Measure"). The
category field carries groups="uom.group_uom" in view
stock.product_category_form_view_inherit.

The menu path was already correct and is unchanged: group_uom does appear in
stock.res_config_settings_view_form, inside the block titled "Products".

The same paragraph also referred to the field as "Reserve Packaging"; the field's actual
label is "Reserve Packagings" (product.category.packaging_reserve_method, options
"Reserve Only Full Packagings" and "Reserve Partial Packagings"). Aligned.

4. Accounting: product categories do not inherit from their parent category

content/applications/finance/accounting/get_started.rst, after the list of product category
fields.

What was missing: the page lists the accounting fields on the product category form but
never says what a subcategory does with them. The hierarchy does not carry them down, and
nothing on the page says so.

Measured on a fresh database. A parent category was created and every writable field set
to a deviating value, then a child category was created with parent_id pointing at it. For
all seven fields — expense account, income account, stock valuation account, price difference
account, stock variation account, costing method, inventory valuation — the child differed
from the parent and matched a category created with no parent at all. Changing the parent
afterwards had no effect either: the parent was moved to fifo and real_time while the
child stayed on standard and periodic.

The values come from the company. These fields are company_dependent and fall back to
ir.default; ir.property no longer exists in this version. Changing the company's expense
account propagated immediately to the child category and to categories created before the
change, while a category holding its own value kept it.

The note deliberately states only what was measured: no inheritance, filled in from the
company defaults, and later parent changes have no effect.

Checks

  • make fast succeeds. The warning count is unchanged from the base branch (1 warning,
    about the optional local odoo/odoo checkout, unrelated to these files).
  • make test reports the same 990 findings as the base branch, byte for byte. None of them
    concern the changed paragraphs.
  • The built HTML was checked for each change: the new wording is present and the old wording
    is gone.

The page stated that dynamic variants are created "only when
corresponding attributes and values are added to a sales order". That is
not accurate: product_template._create_product_variant() is called from
four places outside of Sales as well.

In odoo/odoo saas-19.4 (cbed569e):
  addons/sale/controllers/product_configurator.py:122
  addons/sale_product_matrix/models/sale_order.py:62
  addons/purchase_product_matrix/models/purchase.py:49
  addons/point_of_sale/models/product_template.py:81
  addons/website_sale/controllers/main.py:835

Verified on a database with no Sales module installed: enabling the
purchase "Variant Grid Entry" setting and filling two cells of the grid
created two dynamic variants. Odoo's own test asserts the same behaviour
(addons/purchase_product_matrix/tests/test_purchase_matrix.py:20).

The sentence about Inventory was added because the opposite was measured
as well: on the same database, confirming a purchase order and validating
the incoming receipt created no variant at all. Inventory has no field
anywhere that selects a combination of attribute values.
The page claimed that packagings "are product specific, not generic" and
that each one "must be configured on the individual product form". In
saas-19.4 that is no longer the case.

The model product.packaging no longer exists. Searched the whole
odoo/odoo saas-19.4 tree (643 addons directories plus odoo/addons):
  grep -rn "_name = ['\"]product.packaging['\"]" addons/ odoo/   -> 0 hits

A packaging is now an ordinary uom.uom record. The quantity it holds
comes from relative_factor/factor on that single global record
(addons/uom/models/uom_uom.py:17-43), and uom.uom has neither product_id
nor company_id. Products only reference the packagings they may use, via
product.template.uom_ids (labelled "Packagings",
addons/product/models/product_template.py:159).

Verified: two different products were given the same packaging and both
referenced the same uom.uom record, so the same packaging cannot hold a
different quantity per product. The only product-specific part is the
barcode, held by the helper model product.uom, which has no quantity
field at all (fields: allowed_uom_ids, barcode, company_id, product_id,
uom_id).
The note told the reader to tick a "Product Packagings" checkbox in the
Inventory settings. No such setting exists in saas-19.4.

Read from a running saas-19.4 database: res.config.settings has no field
whose name contains "packaging" at all. The setting that reveals the
field is group_uom, labelled "Units of Measure & Packagings", implying
group uom.group_uom ("Manage Multiple Units of Measure"). The category
field itself carries groups="uom.group_uom" in view
stock.product_category_form_view_inherit.

The menu path was already correct: group_uom does appear in
stock.res_config_settings_view_form, inside the block titled "Products".

Also aligned the field name in the first sentence with the label the
field actually has: "Reserve Packagings", not "Reserve Packaging"
(product.category.packaging_reserve_method, string "Reserve Packagings",
options "Reserve Only Full Packagings" and "Reserve Partial Packagings").
The page lists the accounting fields on the product category form, but
never says what happens with a subcategory. Users reasonably assume the
hierarchy carries the values down, and it does not.

Measured on a fresh saas-19.4 database. A parent category was created and
all writable fields were set to deviating values, then a child category
was created with parent_id pointing at it. For all seven fields
(expense, income, stock valuation and price difference accounts, stock
variation, costing method, inventory valuation) the child differed from
the parent and matched a category created with no parent at all. Changing
the parent afterwards also had no effect: the parent was moved to "fifo"
and "real_time" while the child stayed on "standard" and "periodic".

The values come from the company instead. The fields are
company_dependent and fall back to ir.default; ir.property no longer
exists in this version. Changing the company's expense account propagated
immediately to the child category and to categories created before the
change, while a category holding its own value kept it.

The note deliberately says only what was measured: no inheritance, filled
in from the company's defaults, and later parent changes have no effect.

The placement differs from the obvious one: the note is inserted directly
after the list of product category fields rather than after the sentence
about products inheriting from their category, because that sentence ends
with a colon introducing the next list and must not be split.
@robodoo

robodoo commented Sep 15, 2026

Copy link
Copy Markdown
Collaborator

Pull request status dashboard

@C3POdoo
C3POdoo requested review from a team September 15, 2026 10:40

@dade-odoo dade-odoo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @Natalie-the-technician , thanks for your contribution. I've suggested one minor wording change. Beyond that, it looks good from the accounting scope.

Comment on lines +220 to +222
Product categories do **not** inherit these fields from their parent category. A new
subcategory is filled in with the company's default values, and changing a field on a parent
category afterwards has no effect on its subcategories.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Product categories do **not** inherit these fields from their parent category. A new
subcategory is filled in with the company's default values, and changing a field on a parent
category afterwards has no effect on its subcategories.
Product categories do **not** inherit these fields from their parent category. New subcategories
are filled in with the company's default values, and changing a field on a parent category
afterwards has no effect on its subcategories.

@erjer-odoo erjer-odoo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved on behalf of the inventory scope.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants