From f4fe98c92b19d6dcbfdb4fb14d82d3d974e182be Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Thu, 17 Dec 2020 13:03:37 +0000 Subject: [PATCH] [FIX] stock: fix check of package all in move lines The `groupby` function is used to builds groups of(product, lot) keys and their corresponding move lines / quants. `groupby` groups *consecutive* keys, which is why the input is sorted by the keys. `sorted` on recordsets keys will not sort as we would expect in this particular situation, as the comparison operators on records act as Set Comparison operators on the record ids, i.e. to compare the sets superset/subset relationships: ``` >>> env["product.product"].browse(1) < env["product.product"].browse(2) False >>> env["product.product"].browse(1) < env["product.product"].browse([1, 2]) True ``` Example of sorted on stock.move.line records, where the product id 7313 is both in the slots 4 and 12 instead of being consecutive: ``` >>> [l.product_id.id for l in sorted(lines, key=itemgetter('product_id'))] [7436, 7437, 7352, 7423, 7313, 7351, 7423, 7424, 7320, 7398, 7312, 7352, 7313, 7436, 7437, 7442, 7443, 7320, 7423, 7424, 7318, 7396, 7368, 7355, 7316] ``` Now when we group by id the 2 ids 7313 are correctly placed together in slots 1 and 2: ``` >>> [l.product_id.id for l in sorted(lines, key=attrgetter('product_id.id'))] [7312, 7313, 7313, 7316, 7318, 7320, 7320, 7351, 7352, 7352, 7355, 7368, 7396, 7398, 7423, 7423, 7423, 7424, 7424, 7436, 7436, 7437, 7437, 7442, 7443] ``` This commit aims to sort by "id" of the related records, to ensure the same (product, lot) couples are consecutive. closes odoo/odoo#71276 X-original-commit: d53d8bdf789e8f79ea4d531d944686abb59d6a26 Signed-off-by: Arnold Moyaux --- addons/stock/models/stock_picking.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/addons/stock/models/stock_picking.py b/addons/stock/models/stock_picking.py index 60d8c36cbd9..f646b0abf1f 100644 --- a/addons/stock/models/stock_picking.py +++ b/addons/stock/models/stock_picking.py @@ -6,7 +6,7 @@ import time from ast import literal_eval from datetime import date, timedelta from itertools import groupby -from operator import itemgetter +from operator import attrgetter, itemgetter from odoo import SUPERUSER_ID, _, api, fields, models from odoo.addons.stock.models.stock_move import PROCUREMENT_PRIORITIES @@ -804,14 +804,15 @@ class Picking(models.Model): all_in = True pack_move_lines = self.move_line_ids.filtered(lambda ml: ml.package_id == package) keys = ['product_id', 'lot_id'] + keys_ids = ["{}.id".format(fname) for fname in keys] precision_digits = self.env['decimal.precision'].precision_get('Product Unit of Measure') grouped_quants = {} - for k, g in groupby(sorted(package.quant_ids, key=itemgetter(*keys)), key=itemgetter(*keys)): + for k, g in groupby(sorted(package.quant_ids, key=attrgetter(*keys_ids)), key=itemgetter(*keys)): grouped_quants[k] = sum(self.env['stock.quant'].concat(*list(g)).mapped('quantity')) grouped_ops = {} - for k, g in groupby(sorted(pack_move_lines, key=itemgetter(*keys)), key=itemgetter(*keys)): + for k, g in groupby(sorted(pack_move_lines, key=attrgetter(*keys_ids)), key=itemgetter(*keys)): grouped_ops[k] = sum(self.env['stock.move.line'].concat(*list(g)).mapped('product_qty')) if any(not float_is_zero(grouped_quants.get(key, 0) - grouped_ops.get(key, 0), precision_digits=precision_digits) for key in grouped_quants) \ or any(not float_is_zero(grouped_ops.get(key, 0) - grouped_quants.get(key, 0), precision_digits=precision_digits) for key in grouped_ops):