From e6a4dc9afa6ce9ecac280f690dc29a312461a343 Mon Sep 17 00:00:00 2001 From: Josse Colpaert Date: Fri, 14 Feb 2014 10:15:40 +0100 Subject: [PATCH 1/3] [IMP] Refactor do prepare partial bzr revid: jco@openerp.com-20140214091540-01fna2riexun5m5x --- addons/stock/stock.py | 131 ++++++++++++++++++++++++------------------ 1 file changed, 75 insertions(+), 56 deletions(-) diff --git a/addons/stock/stock.py b/addons/stock/stock.py index 5e409242f50..3848ab5952e 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -930,74 +930,93 @@ class stock_picking(osv.osv): existing_package_ids = pack_operation_obj.search(cr, uid, [('picking_id', 'in', picking_ids)], context=context) if existing_package_ids: pack_operation_obj.unlink(cr, uid, existing_package_ids, context) - + for picking in self.browse(cr, uid, picking_ids, context=context): + packages = [] + reserved_move = {} + qtys_remaining = {} + + #Calculate packages, reserved quants, qtys of this picking's moves for move in picking.move_lines: if move.state not in ('assigned', 'confirmed'): continue - - #Check which of the reserved quants are entirely in packages (can be in separate method) - packages = list(set([x.package_id for x in move.reserved_quant_ids if x.package_id])) - done_packages = [] - for pack in packages: - cont = True - good_pack = False - test_pack = pack - while cont: - quants = pack_obj.get_content(cr, uid, [test_pack.id], context=context) - if all([x.reservation_id.id == move.id for x in quant_obj.browse(cr, uid, quants, context=context) if x.reservation_id]): - good_pack = test_pack.id - if test_pack.parent_id: - test_pack = test_pack.parent_id - else: - cont = False + packages += [x.package_id for x in move.reserved_quant_ids if x.package_id] + reserved_move[move.id] = set([x.id for x in move.reserved_quant_ids]) + if move.state == 'assigned': + qty = move.product_qty + else: + qty = 0 + for quant in move.reserved_quant_ids: + qty += quant.qty + #Add qty to qtys remaining + if qtys_remaining.get(move.product_id.id): + qtys_remaining[move.product_id.id] += qty + else: + qtys_remaining[move.product_id.id] = qty + + # Try to find as much as possible top-level packages that can be moved + done_packages = [] + for pack in packages: + cont = True + good_pack = False + test_pack = pack + while cont: + quants = pack_obj.get_content(cr, uid, [test_pack.id], context=context) + if all([x.reservation_id.id in [x.id for x in picking.move_lines] for x in quant_obj.browse(cr, uid, quants, context=context) if x.reservation_id]): + good_pack = test_pack.id + if test_pack.parent_id: + test_pack = test_pack.parent_id else: cont = False - if good_pack: - done_packages.append(good_pack) - done_packages = list(set(done_packages)) + else: + cont = False + if good_pack: + done_packages.append(good_pack) + done_packages = list(set(done_packages)) - #Create package operations - reserved = set([x.id for x in move.reserved_quant_ids]) - remaining_qty = move.product_qty - for pack in pack_obj.browse(cr, uid, done_packages, context=context): - quantl = pack_obj.get_content(cr, uid, [pack.id], context=context) - for quant in quant_obj.browse(cr, uid, quantl, context=context): - remaining_qty -= quant.qty - quants = set(pack_obj.get_content(cr, uid, [pack.id], context=context)) - reserved -= quants - pack_operation_obj.create(cr, uid, { + # Create pack operations for the top-level packages found + for pack in pack_obj.browse(cr, uid, done_packages, context=context): + quants = pack_obj.get_content(cr, uid, [pack.id], context=context) + for quant in quant_obj.browse(cr, uid, quants, context=context): + reserved_move[quant.reservation_id.id] -= set([quant.id]) + qtys_remaining[quant.product_id.id] -= quant.qty + pack_operation_obj.create(cr, uid, { 'picking_id': picking.id, 'package_id': pack.id, 'product_qty': 1.0, }, context=context) + + # Go through all remaining reserved quants and group by product, package, lot, owner + qtys_grouped = {} + for move in reserved_move.keys(): + for quant in quant_obj.browse(cr, uid, list(reserved_move[move]), context=context): + qtys_remaining[quant.product_id.id] -= quant.qty + key = (quant.product_id.id, quant.package_id.id, quant.lot_id.id, quant.owner_id.id) + if qtys_grouped.get(key): + qtys_grouped[key] += quant.qty + else: + qtys_grouped[key] = quant.qty + + # Add remaining qtys (in cases of force_assign for example) + for product in qtys_remaining.keys(): + if qtys_remaining[product] > 0: + key = (product, False, False, False) + if qtys_grouped.get(key): + qtys_grouped[key] += qtys_remaining[product] + else: + qtys_grouped[key] = qtys_remaining[product] - yet_to_reserve = list(reserved) - #Create operations based on quants - for quant in quant_obj.browse(cr, uid, yet_to_reserve, context=context): - qty = min(quant.qty, move.product_qty) - remaining_qty -= qty - pack_operation_obj.create(cr, uid, { - 'picking_id': picking.id, - 'product_qty': qty, - 'product_id': quant.product_id.id, - 'lot_id': quant.lot_id and quant.lot_id.id or False, - 'product_uom_id': quant.product_id.uom_id.id, - 'owner_id': quant.owner_id and quant.owner_id.id or False, - 'cost': quant.cost, - 'package_id': quant.package_id and quant.package_id.id or False, - }, context=context) - if move.state == 'assigned' and remaining_qty > 0: - #only add a line with remaining qty if we have all qty reserved (move is assigned) - #otherwise we may be in a case where we do a partial delivery with only a few - #available products and we don't want to propose to transfer everything - pack_operation_obj.create(cr, uid, { - 'picking_id': picking.id, - 'product_qty': remaining_qty, - 'product_id': move.product_id.id, - 'product_uom_id': move.product_id.uom_id.id, - 'cost': move.product_id.standard_price, - }, context=context) + # Create the necessary operations for the grouped quants and remaining qtys + for key in qtys_grouped.keys(): + pack_operation_obj.create(cr, uid, { + 'picking_id': picking.id, + 'product_qty': qtys_grouped[key], + 'product_id': key[0], + 'package_id': key[1], + 'lot_id': key[2], + 'owner_id': key[3], + 'product_uom_id': self.pool.get("product.product").browse(cr, uid, key[0], context=context).uom_id.id, + }, context=context) def do_unreserve(self, cr, uid, picking_ids, context=None): """ From 7503f786fbf78a866d57d43849cd1e0289731a32 Mon Sep 17 00:00:00 2001 From: Josse Colpaert Date: Fri, 14 Feb 2014 10:16:00 +0100 Subject: [PATCH 2/3] [IMP] Remove todo bzr revid: jco@openerp.com-20140214091600-whbwamq22asxcq4z --- addons/stock/stock.py | 1 - 1 file changed, 1 deletion(-) diff --git a/addons/stock/stock.py b/addons/stock/stock.py index 3848ab5952e..c5e8bd02fb2 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -921,7 +921,6 @@ class stock_picking(osv.osv): self.do_prepare_partial(cr, uid, picking_ids, context=context) def do_prepare_partial(self, cr, uid, picking_ids, context=None): - #TODO refactore me context = context or {} pack_operation_obj = self.pool.get('stock.pack.operation') pack_obj = self.pool.get("stock.quant.package") From ca99f5bd2443db61f17b1a63ea46f088758ee1fd Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Thu, 20 Feb 2014 09:35:19 +0100 Subject: [PATCH 3/3] [REF] some refactoring made during code review bzr revid: qdp-launchpad@openerp.com-20140220083519-13qlpr0zohplv8fa --- addons/stock/stock.py | 57 ++++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/addons/stock/stock.py b/addons/stock/stock.py index 0df52a7642d..384c93ee2d4 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -319,7 +319,7 @@ class stock_quant(osv.osv): self.write(cr, SUPERUSER_ID, toreserve, {'reservation_id': move.id, 'link_move_operation_id': link and link.id or False}, context=context) #check if move'state needs to be set as 'assigned' move.refresh() - if sum([q.qty for q in move.reserved_quant_ids]) == move.product_qty and move.state in ('confirmed', 'waiting'): + if move.reserved_availability == move.product_qty and move.state in ('confirmed', 'waiting'): self.pool.get('stock.move').write(cr, uid, [move.id], {'state': 'assigned'}, context=context) def quants_move(self, cr, uid, quants, move, lot_id=False, owner_id=False, src_package_id=False, dest_package_id=False, context=None): @@ -937,16 +937,16 @@ class stock_picking(osv.osv): pack_operation_obj = self.pool.get('stock.pack.operation') pack_obj = self.pool.get("stock.quant.package") quant_obj = self.pool.get("stock.quant") - #get list of existing packages and delete them + #get list of existing operations and delete them existing_package_ids = pack_operation_obj.search(cr, uid, [('picking_id', 'in', picking_ids)], context=context) if existing_package_ids: pack_operation_obj.unlink(cr, uid, existing_package_ids, context) - + for picking in self.browse(cr, uid, picking_ids, context=context): packages = [] reserved_move = {} qtys_remaining = {} - + #Calculate packages, reserved quants, qtys of this picking's moves for move in picking.move_lines: if move.state not in ('assigned', 'confirmed'): @@ -956,37 +956,38 @@ class stock_picking(osv.osv): if move.state == 'assigned': qty = move.product_qty else: - qty = 0 - for quant in move.reserved_quant_ids: - qty += quant.qty + qty = move.reserved_availability + #Add qty to qtys remaining if qtys_remaining.get(move.product_id.id): qtys_remaining[move.product_id.id] += qty else: qtys_remaining[move.product_id.id] = qty - + # Try to find as much as possible top-level packages that can be moved - done_packages = [] + top_lvl_packages = set() for pack in packages: - cont = True + loop = True good_pack = False test_pack = pack - while cont: + while loop: quants = pack_obj.get_content(cr, uid, [test_pack.id], context=context) - if all([x.reservation_id.id in [x.id for x in picking.move_lines] for x in quant_obj.browse(cr, uid, quants, context=context) if x.reservation_id]): + if all([(x.reservation_id and x.reservation_id.id in [x.id for x in picking.move_lines] or False) for x in quant_obj.browse(cr, uid, quants, context=context)]): good_pack = test_pack.id if test_pack.parent_id: test_pack = test_pack.parent_id else: - cont = False + #stop the loop when there's no parent package anymore + loop = False else: - cont = False + #stop the loop when the package test_pack is not totally reserved for moves of this picking + #(some quants may be reserved for other picking or not reserved at all) + loop = False if good_pack: - done_packages.append(good_pack) - done_packages = list(set(done_packages)) + top_lvl_packages.add(good_pack) # Create pack operations for the top-level packages found - for pack in pack_obj.browse(cr, uid, done_packages, context=context): + for pack in pack_obj.browse(cr, uid, list(top_lvl_packages), context=context): quants = pack_obj.get_content(cr, uid, [pack.id], context=context) for quant in quant_obj.browse(cr, uid, quants, context=context): reserved_move[quant.reservation_id.id] -= set([quant.id]) @@ -996,18 +997,18 @@ class stock_picking(osv.osv): 'package_id': pack.id, 'product_qty': 1.0, }, context=context) - + # Go through all remaining reserved quants and group by product, package, lot, owner qtys_grouped = {} - for move in reserved_move.keys(): - for quant in quant_obj.browse(cr, uid, list(reserved_move[move]), context=context): + for move, quant_set in reserved_move.items(): + for quant in quant_obj.browse(cr, uid, list(quant_set), context=context): qtys_remaining[quant.product_id.id] -= quant.qty key = (quant.product_id.id, quant.package_id.id, quant.lot_id.id, quant.owner_id.id) if qtys_grouped.get(key): qtys_grouped[key] += quant.qty else: qtys_grouped[key] = quant.qty - + # Add remaining qtys (in cases of force_assign for example) for product in qtys_remaining.keys(): if qtys_remaining[product] > 0: @@ -1018,15 +1019,15 @@ class stock_picking(osv.osv): qtys_grouped[key] = qtys_remaining[product] # Create the necessary operations for the grouped quants and remaining qtys - for key in qtys_grouped.keys(): + for key, qty in qtys_grouped.items(): pack_operation_obj.create(cr, uid, { - 'picking_id': picking.id, - 'product_qty': qtys_grouped[key], + 'picking_id': picking.id, + 'product_qty': qty, 'product_id': key[0], - 'package_id': key[1], + 'package_id': key[1], 'lot_id': key[2], - 'owner_id': key[3], - 'product_uom_id': self.pool.get("product.product").browse(cr, uid, key[0], context=context).uom_id.id, + 'owner_id': key[3], + 'product_uom_id': self.pool.get("product.product").browse(cr, uid, key[0], context=context).uom_id.id, }, context=context) def do_unreserve(self, cr, uid, picking_ids, context=None): @@ -1913,7 +1914,7 @@ class stock_move(osv.osv): for move in todo_moves: #then if the move isn't totally assigned, try to find quants without any specific domain if move.state != 'assigned': - qty_already_assigned = sum([q.qty for q in move.reserved_quant_ids]) + qty_already_assigned = move.reserved_availability qty = move.product_qty - qty_already_assigned quants = quant_obj.quants_get_prefered_domain(cr, uid, move.location_id, move.product_id, qty, domain=main_domain[move.id], prefered_domain=prefered_domain[move.id], fallback_domain=fallback_domain[move.id], restrict_lot_id=move.restrict_lot_id.id, restrict_partner_id=move.restrict_partner_id.id, context=context) quant_obj.quants_reserve(cr, uid, quants, move, context=context)