From e2f3b32d29cb16e80ebda177c15d98101c74fed1 Mon Sep 17 00:00:00 2001 From: Matias Gibbons Date: Fri, 17 Apr 2026 01:03:42 -0300 Subject: [PATCH 1/2] =?UTF-8?q?[FIX]=20stock=5Fdeclared=5Fvalue:=20move=5F?= =?UTF-8?q?line.product=5Fuom=20=E2=86=92=20product=5Fuom=5Fid=20(v19=20co?= =?UTF-8?q?mpat)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In v19 the field stock.move.line.product_uom was renamed to product_uom_id. Four accesses in stock_declared_value/models/stock_picking.py still used the old name on move_line recordsets (stock.move.line), causing AttributeError when the _compute_declared_value method runs. Note: move_line.product_uom_qty (a distinct Float field) was NOT renamed — it keeps the same name in v19 and is left untouched. --- stock_declared_value/models/stock_picking.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/stock_declared_value/models/stock_picking.py b/stock_declared_value/models/stock_picking.py index 889d8a8eb..2969cdf97 100644 --- a/stock_declared_value/models/stock_picking.py +++ b/stock_declared_value/models/stock_picking.py @@ -43,18 +43,18 @@ def _compute_declared_value(self): so_qty_done = move_line.quantity # convert quantities if move line uom and sale line uom # are different - if move_line.product_uom != order_line.product_uom_id: - so_product_qty = move_line.product_uom._compute_quantity( + if move_line.product_uom_id != order_line.product_uom_id: + so_product_qty = move_line.product_uom_id._compute_quantity( move_line.product_uom_qty, order_line.product_uom_id ) - so_qty_done = move_line.product_uom._compute_quantity( + so_qty_done = move_line.product_uom_id._compute_quantity( move_line.quantity, order_line.product_uom_id ) picking_value += order_line.price_reduce_taxexcl * so_product_qty done_value += order_line.price_reduce_taxexcl * so_qty_done elif rec.picking_type_id.pricelist_id: pricelist = rec.picking_type_id.pricelist_id - price = rec.picking_type_id.pricelist_id.with_context(uom=move_line.product_uom.id)._price_get( + price = rec.picking_type_id.pricelist_id.with_context(uom=move_line.product_uom_id.id)._price_get( move_line.product_id, move_line.quantity or 1.0, partner=rec.partner_id.id )[rec.picking_type_id.pricelist_id.id] picking_value += price * move_line.product_uom_qty From cbe44220ebe8da0461d932ab14a1b7d09d3cdf25 Mon Sep 17 00:00:00 2001 From: Matias Gibbons Date: Tue, 21 Apr 2026 10:32:56 -0300 Subject: [PATCH 2/2] [FIX] stock_ux: location context crash + field `.reference` inexistente MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dos bugs en `_compute_product_uom_qty_location` (stock_move_line.py) que se disparan al abrir cualquier vista de stock.move.line filtrada por location: 1. `location[0]` asume que `location` es list/tuple/str. En Odoo 19 algunas vistas lo pasan como `int` (ID único de stock.location) → crashea con `TypeError: 'int' object is not subscriptable`. Ahora normaliza los 3 casos (int / list-tuple / str). 2. El lookup posterior usaba `browse(id).reference`, campo que NO existe en stock.location (en v18 tampoco, probablemente residuo de un rename muy viejo). Crasheaba con `AttributeError: 'stock.location' object has no attribute 'reference'`. Fijo a `.complete_name`, que es el campo consistente con la `search` posterior `('complete_name', 'ilike', location_name)`. Validado con ORM shell en 4 casos (int / list[int] / str / ""), todos retornan resultados consistentes y sin excepción. Co-Authored-By: Claude Opus 4.7 (1M context) --- stock_ux/__manifest__.py | 2 +- stock_ux/models/stock_move_line.py | 18 ++++++++++++------ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/stock_ux/__manifest__.py b/stock_ux/__manifest__.py index 3f70c02c4..61f12ed20 100644 --- a/stock_ux/__manifest__.py +++ b/stock_ux/__manifest__.py @@ -19,7 +19,7 @@ ############################################################################## { "name": "Stock UX", - "version": "19.0.1.3.0", + "version": "19.0.1.3.1", "category": "Warehouse Management", "sequence": 14, "summary": "", diff --git a/stock_ux/models/stock_move_line.py b/stock_ux/models/stock_move_line.py index 29831b404..a9c54fe47 100644 --- a/stock_ux/models/stock_move_line.py +++ b/stock_ux/models/stock_move_line.py @@ -36,12 +36,18 @@ def _compute_product_uom_qty_location(self): if not location: self.update({"product_uom_qty_location": 0.0}) return False - # because now we use location_id to select location, we have compelte - # location name. If y need we can use some code of - # _get_domain_locations on stock/product.py - location_name = location[0] - if isinstance(location[0], int): - location_name = self.env["stock.location"].browse(location[0]).reference + # `location` puede venir como int (ID único), list/tuple de ints, o string. + # En v19 algunas vistas lo pasan como int directo → location[0] explota. + if isinstance(location, int): + location_name = self.env["stock.location"].browse(location).complete_name + elif isinstance(location, (list, tuple)): + first = location[0] + location_name = ( + self.env["stock.location"].browse(first).complete_name + if isinstance(first, int) else first + ) + else: + location_name = location # string locations = self.env["stock.location"].search([("complete_name", "ilike", location_name)]) for rec in self: product_uom_qty_location = rec.quantity