From 3258d44d08cb0c129fdd8bff0fb36b15707e277b Mon Sep 17 00:00:00 2001 From: Josse Colpaert Date: Thu, 13 Feb 2014 19:12:15 +0100 Subject: [PATCH 01/14] [WIP] Take reserved quants into account for the matching between moves and ops bzr revid: jco@openerp.com-20140213181215-b6ckgmb1h9kkbrmt --- addons/stock/stock.py | 45 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/addons/stock/stock.py b/addons/stock/stock.py index 5e409242f50..b5a77e07e86 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -3420,6 +3420,7 @@ class stock_pack_operation(osv.osv): self.recompute_rem_qty_from_operation(cr, uid, [res_id], context=context) return res_id + def recompute_rem_qty_from_operation(self, cr, uid, op_ids, context=None): def _create_link_for_product(product_id, qty): qty_to_assign = qty @@ -3432,13 +3433,55 @@ class stock_pack_operation(osv.osv): if qty_to_assign <= 0: break + def _check_quants_reserve(ops): + if ops.package_id and not ops.product_id: + for quant in quant_obj.browse(cr, uid, package_obj.get_content(cr, uid, [ops.package_id]), context=context): + if quant.reservation_id and quant.reservation_id.id in [x.id for x in ops.picking.move_lines] and (not quants_done.get(quant.id)): + #Entire packages means entire quants + if not quants_done.get(quant.id): + quants_done[quant.id] = 0 + link_obj.create(cr, uid, {'move_id': quant.reservation_id.id, 'operation_id': ops.id, 'qty': qty}, context=context) + else: + # CHECK: Search necessary quants -> might pass through one of the quants_get functions instead + zeroquants = [x for x in quants_done.keys() if x == 0] + domain = [('reservation_id', 'in', [x.id for x in ops.picking_id.move_lines]), ('id', 'not in', zeroquants), + ('product_id', '=', ops.product_id.id)] + if ops.package_id: + domain += [('package_id', 'child_of', ops.package_id.id)] + else: + domain += [('package_id', '=', False)] + domain += [('owner_id', '=', ops.owner_id.id)] + quants = quant_obj.search(cr, uid, domain, context=context) + # Process quants until + qty = uom_obj._compute_qty(cr, uid, op.product_uom_id.id, op.product_qty, op.product_id.uom_id.id) + for quant in quant_obj.browse(cr, uid, quants, context=context): + quant_qty = quant.qty + if quants_done.get(quant.id): + quant_qty = quants_done[quant.id] + if quant_qty > qty: + qty_todo = qty + quants_done[quant.id] = quant_qty - qty + else: + qty_todo = quant_qty + quants_done[quant.id] = 0 + link_obj.create(cr, uid, {'move_id': quant.reservation_id.id, 'operation_id': ops.id, 'qty': qty_todo}, context=context) + + + link_obj = self.pool.get('stock.move.operation.link') uom_obj = self.pool.get('product.uom') package_obj = self.pool.get('stock.quant.package') - for op in self.browse(cr, uid, op_ids, context=context): + quant_obj = self.pool.get('stock.quant') + operations = self.browse(cr, uid, op_ids, context=context) + operations.sort(key = lambda x: ((x.package_id and not x.product_id) and -4 or 0) + (x.package_id and -2 or 0) + (x.lot_id and -1 or 0)) + quants_done = {} + for op in operations: to_unlink_ids = [x.id for x in op.linked_move_operation_ids] if to_unlink_ids: link_obj.unlink(cr, uid, to_unlink_ids, context=context) + _check_quants_reserve(op) + + for op in operations: if op.product_id: normalized_qty = uom_obj._compute_qty(cr, uid, op.product_uom_id.id, op.product_qty, op.product_id.uom_id.id) _create_link_for_product(op.product_id.id, normalized_qty) From c0222bc886087f2df34154eb9691c7630c10b24e Mon Sep 17 00:00:00 2001 From: Josse Colpaert Date: Fri, 14 Feb 2014 10:12:31 +0100 Subject: [PATCH 02/14] [WIP] Add comment for testing bzr revid: jco@openerp.com-20140214091231-92s13sb4uc697188 --- addons/stock/stock.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/addons/stock/stock.py b/addons/stock/stock.py index b5a77e07e86..b5b2ecb48d0 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -3488,6 +3488,8 @@ class stock_pack_operation(osv.osv): elif op.package_id: for product_id, qty in package_obj._get_all_products_quantities(cr, uid, op.package_id.id, context=context).items(): _create_link_for_product(product_id, qty) +# for op in operations: +# print [(y.qty, y.operation_id, y.move_id) for y in op.linked_move_operation_ids] def process_packaging(self, cr, uid, operation, quants, context=None): ''' Process the packaging of a given operation, after the quants have been moved. If there was not enough quants found From ca41bb872283fb2f7a1ec010e066d86fc1f2e574 Mon Sep 17 00:00:00 2001 From: Josse Colpaert Date: Fri, 14 Feb 2014 11:45:41 +0100 Subject: [PATCH 03/14] [IMP] take lots into account and do zero quants differently bzr revid: jco@openerp.com-20140214104541-h6lsckxs6uvgxu4z --- addons/stock/stock.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/addons/stock/stock.py b/addons/stock/stock.py index b5b2ecb48d0..984845c22e3 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -3443,13 +3443,14 @@ class stock_pack_operation(osv.osv): link_obj.create(cr, uid, {'move_id': quant.reservation_id.id, 'operation_id': ops.id, 'qty': qty}, context=context) else: # CHECK: Search necessary quants -> might pass through one of the quants_get functions instead - zeroquants = [x for x in quants_done.keys() if x == 0] - domain = [('reservation_id', 'in', [x.id for x in ops.picking_id.move_lines]), ('id', 'not in', zeroquants), + domain = [('reservation_id', 'in', [x.id for x in ops.picking_id.move_lines]), ('product_id', '=', ops.product_id.id)] if ops.package_id: domain += [('package_id', 'child_of', ops.package_id.id)] else: domain += [('package_id', '=', False)] + if ops.lot_id: + domain += [('lot_id', '=', ops.lot_id.id)] domain += [('owner_id', '=', ops.owner_id.id)] quants = quant_obj.search(cr, uid, domain, context=context) # Process quants until @@ -3457,6 +3458,8 @@ class stock_pack_operation(osv.osv): for quant in quant_obj.browse(cr, uid, quants, context=context): quant_qty = quant.qty if quants_done.get(quant.id): + if quants_done[quant.id] == 0: + continue quant_qty = quants_done[quant.id] if quant_qty > qty: qty_todo = qty From 17fa8b56b3d9ae7f7cdfd7bc7ed798ca42b24e10 Mon Sep 17 00:00:00 2001 From: Josse Colpaert Date: Fri, 14 Feb 2014 12:15:36 +0100 Subject: [PATCH 04/14] [WIP] Traverse reserved quants on moves instead of trying to search for quants bzr revid: jco@openerp.com-20140214111536-isyx81aa6mbqmhm4 --- addons/stock/stock.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/addons/stock/stock.py b/addons/stock/stock.py index 984845c22e3..7efcfea9696 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -3442,6 +3442,31 @@ class stock_pack_operation(osv.osv): quants_done[quant.id] = 0 link_obj.create(cr, uid, {'move_id': quant.reservation_id.id, 'operation_id': ops.id, 'qty': qty}, context=context) else: + qty = uom_obj._compute_qty(cr, uid, ops.product_uom_id.id, ops.product_qty, ops.product_id.uom_id.id) + #Check moves with same product + for move in [x for x in op.picking_id.move_lines if op.product_id.id == move.product_id.id]: + for quant in move.reserved_quant_ids: + #TODO: check child packages + bool = (not ops.package_id and quant.package_id == False) or (ops.package_id and quant.package_id.id == ops.package_id.id) + bool = bool and ((ops.lot_id and ops.lot_id.id == quant.lot_id.id) or not ops.lot_id) + bool = bool and ((ops.owner_id.id == quant.owner_id.id)) + if bool: + quant_qty = quant.qty + if quants_done.get(quant.id): + if quants_done[quant.id] == 0: + continue + quant_qty = quants_done[quant.id] + if quant_qty > qty: + qty_todo = qty + quants_done[quant.id] = quant_qty - qty + else: + qty_todo = quant_qty + quants_done[quant.id] = 0 + qty -= qty_todo + link_obj.create(cr, uid, {'move_id': quant.reservation_id.id, 'operation_id': ops.id, 'qty': qty_todo}, context=context) + + + # CHECK: Search necessary quants -> might pass through one of the quants_get functions instead domain = [('reservation_id', 'in', [x.id for x in ops.picking_id.move_lines]), ('product_id', '=', ops.product_id.id)] From 04c1e75d6253b3433095097d2b4d385626f028e5 Mon Sep 17 00:00:00 2001 From: Josse Colpaert Date: Fri, 14 Feb 2014 16:06:52 +0100 Subject: [PATCH 05/14] [WIP] Take care of remaining qtys bzr revid: jco@openerp.com-20140214150652-nl6izqtg56remcdh --- addons/stock/stock.py | 78 ++++++++++++++++++------------------------- 1 file changed, 33 insertions(+), 45 deletions(-) diff --git a/addons/stock/stock.py b/addons/stock/stock.py index 7efcfea9696..6244bb67573 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -3427,29 +3427,45 @@ class stock_pack_operation(osv.osv): for move in op.picking_id.move_lines: if move.product_id.id == product_id and move.state not in ['done', 'cancel']: qty_on_link = min(move.remaining_qty, qty_to_assign) + print 'Create remaining link:', qty_on_link link_obj.create(cr, uid, {'move_id': move.id, 'operation_id': op.id, 'qty': qty_on_link}, context=context) qty_to_assign -= qty_on_link move.refresh() if qty_to_assign <= 0: break + def _check_package_child_of(quant_pack, ops_pack): + if not quant_pack and not ops_pack: + return True + if not quant_pack or not ops_pack: + return False + check = False + check_pack = quant_pack + while not check and check_pack: + if check_pack.id == ops_pack.id: + check = True + check_pack = quant_pack.parent_id + return check + def _check_quants_reserve(ops): if ops.package_id and not ops.product_id: - for quant in quant_obj.browse(cr, uid, package_obj.get_content(cr, uid, [ops.package_id]), context=context): - if quant.reservation_id and quant.reservation_id.id in [x.id for x in ops.picking.move_lines] and (not quants_done.get(quant.id)): - #Entire packages means entire quants + for quant in quant_obj.browse(cr, uid, package_obj.get_content(cr, uid, [ops.package_id.id]), context=context): + if quant.reservation_id and quant.reservation_id.id in [x.id for x in ops.picking_id.move_lines] and (not quants_done.get(quant.id)): + #Entire packages means entire quants from those packages if not quants_done.get(quant.id): quants_done[quant.id] = 0 - link_obj.create(cr, uid, {'move_id': quant.reservation_id.id, 'operation_id': ops.id, 'qty': qty}, context=context) + link_obj.create(cr, uid, {'move_id': quant.reservation_id.id, 'operation_id': ops.id, 'qty': quant.qty}, context=context) else: qty = uom_obj._compute_qty(cr, uid, ops.product_uom_id.id, ops.product_qty, ops.product_id.uom_id.id) + print qty #Check moves with same product - for move in [x for x in op.picking_id.move_lines if op.product_id.id == move.product_id.id]: + for move in [x for x in ops.picking_id.move_lines if ops.product_id.id == x.product_id.id]: for quant in move.reserved_quant_ids: - #TODO: check child packages - bool = (not ops.package_id and quant.package_id == False) or (ops.package_id and quant.package_id.id == ops.package_id.id) - bool = bool and ((ops.lot_id and ops.lot_id.id == quant.lot_id.id) or not ops.lot_id) - bool = bool and ((ops.owner_id.id == quant.owner_id.id)) + if not qty > 0: + break + bool = _check_package_child_of(quant.package_id, ops.package_id) + bool = bool and ((ops.lot_id and ops.lot_id.id == quant.lot_id.id) or not ops.lot_id) + bool = bool and (ops.owner_id.id == quant.owner_id.id) if bool: quant_qty = quant.qty if quants_done.get(quant.id): @@ -3465,36 +3481,6 @@ class stock_pack_operation(osv.osv): qty -= qty_todo link_obj.create(cr, uid, {'move_id': quant.reservation_id.id, 'operation_id': ops.id, 'qty': qty_todo}, context=context) - - - # CHECK: Search necessary quants -> might pass through one of the quants_get functions instead - domain = [('reservation_id', 'in', [x.id for x in ops.picking_id.move_lines]), - ('product_id', '=', ops.product_id.id)] - if ops.package_id: - domain += [('package_id', 'child_of', ops.package_id.id)] - else: - domain += [('package_id', '=', False)] - if ops.lot_id: - domain += [('lot_id', '=', ops.lot_id.id)] - domain += [('owner_id', '=', ops.owner_id.id)] - quants = quant_obj.search(cr, uid, domain, context=context) - # Process quants until - qty = uom_obj._compute_qty(cr, uid, op.product_uom_id.id, op.product_qty, op.product_id.uom_id.id) - for quant in quant_obj.browse(cr, uid, quants, context=context): - quant_qty = quant.qty - if quants_done.get(quant.id): - if quants_done[quant.id] == 0: - continue - quant_qty = quants_done[quant.id] - if quant_qty > qty: - qty_todo = qty - quants_done[quant.id] = quant_qty - qty - else: - qty_todo = quant_qty - quants_done[quant.id] = 0 - link_obj.create(cr, uid, {'move_id': quant.reservation_id.id, 'operation_id': ops.id, 'qty': qty_todo}, context=context) - - link_obj = self.pool.get('stock.move.operation.link') uom_obj = self.pool.get('product.uom') @@ -3511,13 +3497,15 @@ class stock_pack_operation(osv.osv): for op in operations: if op.product_id: - normalized_qty = uom_obj._compute_qty(cr, uid, op.product_uom_id.id, op.product_qty, op.product_id.uom_id.id) - _create_link_for_product(op.product_id.id, normalized_qty) + #TODO: Remaining qty: UoM conversions are done twice + normalized_qty = uom_obj._compute_qty(cr, uid, op.product_uom_id.id, op.remaining_qty, op.product_id.uom_id.id) + if normalized_qty > 0: + _create_link_for_product(op.product_id.id, normalized_qty) elif op.package_id: - for product_id, qty in package_obj._get_all_products_quantities(cr, uid, op.package_id.id, context=context).items(): - _create_link_for_product(product_id, qty) -# for op in operations: -# print [(y.qty, y.operation_id, y.move_id) for y in op.linked_move_operation_ids] + prod_quants = self._get_remaining_prod_quantities(cr, uid, op, context=context) + for product_id, qty in prod_quants.items(): + if qty > 0: + _create_link_for_product(product_id, qty) def process_packaging(self, cr, uid, operation, quants, context=None): ''' Process the packaging of a given operation, after the quants have been moved. If there was not enough quants found From 7c96369a78f6662c24638eec4ed05a824384ef18 Mon Sep 17 00:00:00 2001 From: Josse Colpaert Date: Fri, 14 Feb 2014 16:47:27 +0100 Subject: [PATCH 06/14] [IMP] Clean print bzr revid: jco@openerp.com-20140214154727-12ahepj7lzk4f86o --- addons/stock/stock.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/addons/stock/stock.py b/addons/stock/stock.py index 6244bb67573..902f0e0a68a 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -3427,7 +3427,6 @@ class stock_pack_operation(osv.osv): for move in op.picking_id.move_lines: if move.product_id.id == product_id and move.state not in ['done', 'cancel']: qty_on_link = min(move.remaining_qty, qty_to_assign) - print 'Create remaining link:', qty_on_link link_obj.create(cr, uid, {'move_id': move.id, 'operation_id': op.id, 'qty': qty_on_link}, context=context) qty_to_assign -= qty_on_link move.refresh() @@ -3457,7 +3456,6 @@ class stock_pack_operation(osv.osv): link_obj.create(cr, uid, {'move_id': quant.reservation_id.id, 'operation_id': ops.id, 'qty': quant.qty}, context=context) else: qty = uom_obj._compute_qty(cr, uid, ops.product_uom_id.id, ops.product_qty, ops.product_id.uom_id.id) - print qty #Check moves with same product for move in [x for x in ops.picking_id.move_lines if ops.product_id.id == x.product_id.id]: for quant in move.reserved_quant_ids: From cec58497c271d5fe7f45913eee4ec37390558657 Mon Sep 17 00:00:00 2001 From: Josse Colpaert Date: Mon, 17 Feb 2014 11:52:25 +0100 Subject: [PATCH 07/14] [IMP] Refresh op bzr revid: jco@openerp.com-20140217105225-ey0hesbqbu14bstz --- addons/stock/stock.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/addons/stock/stock.py b/addons/stock/stock.py index 902f0e0a68a..cf6da7f3ddd 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -3446,7 +3446,7 @@ class stock_pack_operation(osv.osv): check_pack = quant_pack.parent_id return check - def _check_quants_reserve(ops): + def _check_quants_reserved(ops): if ops.package_id and not ops.product_id: for quant in quant_obj.browse(cr, uid, package_obj.get_content(cr, uid, [ops.package_id.id]), context=context): if quant.reservation_id and quant.reservation_id.id in [x.id for x in ops.picking_id.move_lines] and (not quants_done.get(quant.id)): @@ -3491,9 +3491,10 @@ class stock_pack_operation(osv.osv): to_unlink_ids = [x.id for x in op.linked_move_operation_ids] if to_unlink_ids: link_obj.unlink(cr, uid, to_unlink_ids, context=context) - _check_quants_reserve(op) + _check_quants_reserved(op) for op in operations: + op.refresh() if op.product_id: #TODO: Remaining qty: UoM conversions are done twice normalized_qty = uom_obj._compute_qty(cr, uid, op.product_uom_id.id, op.remaining_qty, op.product_id.uom_id.id) From ce657e58fe551982ea64595c6a5f1992a4cb4efb Mon Sep 17 00:00:00 2001 From: Josse Colpaert Date: Mon, 17 Feb 2014 14:24:18 +0100 Subject: [PATCH 08/14] [FIX] Remove bad line in packing yml bzr revid: jco@openerp.com-20140217132418-thq836sm4br7z4bj --- addons/stock/test/packing.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/addons/stock/test/packing.yml b/addons/stock/test/packing.yml index 4978d44750e..23b072fbf92 100644 --- a/addons/stock/test/packing.yml +++ b/addons/stock/test/packing.yml @@ -139,7 +139,6 @@ backorder_ids = self.search(cr, uid, [('backorder_id', '=', ref('delivery_order1'))], context=context) assert backorder_ids, "Backorder should have been created" self.do_prepare_partial(cr, uid, backorder_ids, context=context) - stock_pack = self.pool.get('stock.pack.operation').create(cr, uid, {'picking_id': backorder_ids[0], 'product_qty': 20}) self.action_assign(cr, uid, backorder_ids, context=context) self.do_transfer(cr, uid, backorder_ids, context=context) - From f546ce8ad339a2bb5d9deb7cc0b420057d110ca6 Mon Sep 17 00:00:00 2001 From: Josse Colpaert Date: Mon, 17 Feb 2014 15:32:22 +0100 Subject: [PATCH 09/14] [IMP] Quant should be transferred as a whole bzr revid: jco@openerp.com-20140217143222-scplxx05xhrct52w --- addons/stock/test/packingneg.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/stock/test/packingneg.yml b/addons/stock/test/packingneg.yml index 5f26c2f59ac..8887e9b5a56 100644 --- a/addons/stock/test/packingneg.yml +++ b/addons/stock/test/packingneg.yml @@ -106,7 +106,7 @@ elif rec.lot_id.name == 'Lot neg' and rec.location_id.id == ref('stock_location_customers'): assert ((rec.qty == 20 or rec.qty == 120) and not rec.package_id), "Should have 140 pieces (120+20) in customer location from pallet 2 and lot A" elif rec.package_id.name == 'Palneg 3' and rec.location_id.id == ref('stock_location_stock'): - assert rec.qty == 30 or rec.qty == 20, "Should have 30 and 20 pieces in stock on pallet 3" + assert rec.qty == 50, "Should have 30 and 20 pieces in stock on pallet 3" elif not rec.package_id and not rec.lot_id and rec.location_id.id == ref('stock_location_customers'): assert rec.qty == 10, "Should have 10 pieces in customer location from pallet 3" else: From 95b6ce63eb12865949fea7473eea93e268d003e0 Mon Sep 17 00:00:00 2001 From: Josse Colpaert Date: Tue, 18 Feb 2014 10:12:22 +0100 Subject: [PATCH 10/14] [FIX] Change remaining qty bzr revid: jco@openerp.com-20140218091222-so0xw06wy9y400z6 --- addons/stock/stock.py | 4 ++-- addons/stock/test/packingneg.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/addons/stock/stock.py b/addons/stock/stock.py index cf6da7f3ddd..85b50d35634 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -3343,11 +3343,11 @@ class stock_pack_operation(osv.osv): res = {} for ops in self.browse(cr, uid, ids, context=context): res[ops.id] = 0 - if ops.package_id: + if ops.package_id and not ops.product_id: #dont try to compute the remaining quantity for packages because it's not relevant (a package could include different products). #should use _get_remaining_prod_quantities instead continue - elif ops.product_id: + else: qty = ops.product_qty if ops.product_uom_id: qty = uom_obj._compute_qty(cr, uid, ops.product_uom_id.id, ops.product_qty, ops.product_id.uom_id.id) diff --git a/addons/stock/test/packingneg.yml b/addons/stock/test/packingneg.yml index 8887e9b5a56..3f663394bbd 100644 --- a/addons/stock/test/packingneg.yml +++ b/addons/stock/test/packingneg.yml @@ -106,7 +106,7 @@ elif rec.lot_id.name == 'Lot neg' and rec.location_id.id == ref('stock_location_customers'): assert ((rec.qty == 20 or rec.qty == 120) and not rec.package_id), "Should have 140 pieces (120+20) in customer location from pallet 2 and lot A" elif rec.package_id.name == 'Palneg 3' and rec.location_id.id == ref('stock_location_stock'): - assert rec.qty == 50, "Should have 30 and 20 pieces in stock on pallet 3" + assert rec.qty == 50 or rec.qty == 20 or rec.qty == 30, "Should have 30 and 20 pieces in stock on pallet 3" elif not rec.package_id and not rec.lot_id and rec.location_id.id == ref('stock_location_customers'): assert rec.qty == 10, "Should have 10 pieces in customer location from pallet 3" else: From 9df9382f122f33cfe8af049389cc6a35a56e01ba Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Mon, 24 Feb 2014 12:21:12 +0100 Subject: [PATCH 11/14] [REF] stock: refactoring made during code review bzr revid: qdp-launchpad@openerp.com-20140224112112-go4uj37htcv3zo4k --- addons/stock/stock.py | 16 +--------------- addons/stock/test/packing.yml | 6 ++++++ addons/stock/test/packingneg.yml | 2 +- 3 files changed, 8 insertions(+), 16 deletions(-) diff --git a/addons/stock/stock.py b/addons/stock/stock.py index c9e120db1df..2e6b2573290 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -3489,7 +3489,6 @@ class stock_pack_operation(osv.osv): self.recompute_rem_qty_from_operation(cr, uid, [res_id], context=context) return res_id - def recompute_rem_qty_from_operation(self, cr, uid, op_ids, context=None): def _create_link_for_product(product_id, qty): qty_to_assign = qty @@ -3502,19 +3501,6 @@ class stock_pack_operation(osv.osv): if qty_to_assign <= 0: break - def _check_package_child_of(quant_pack, ops_pack): - if not quant_pack and not ops_pack: - return True - if not quant_pack or not ops_pack: - return False - check = False - check_pack = quant_pack - while not check and check_pack: - if check_pack.id == ops_pack.id: - check = True - check_pack = quant_pack.parent_id - return check - def _check_quants_reserved(ops): if ops.package_id and not ops.product_id: for quant in quant_obj.browse(cr, uid, package_obj.get_content(cr, uid, [ops.package_id.id]), context=context): @@ -3530,7 +3516,7 @@ class stock_pack_operation(osv.osv): for quant in move.reserved_quant_ids: if not qty > 0: break - bool = _check_package_child_of(quant.package_id, ops.package_id) + bool = bool(pack_obj.search(cr, uid, [('id', 'child_of', [ops.package_id.id]), ('id', '=', quants.package_id.id)], context=context) bool = bool and ((ops.lot_id and ops.lot_id.id == quant.lot_id.id) or not ops.lot_id) bool = bool and (ops.owner_id.id == quant.owner_id.id) if bool: diff --git a/addons/stock/test/packing.yml b/addons/stock/test/packing.yml index 23b072fbf92..7bd9a3870ac 100644 --- a/addons/stock/test/packing.yml +++ b/addons/stock/test/packing.yml @@ -139,6 +139,12 @@ backorder_ids = self.search(cr, uid, [('backorder_id', '=', ref('delivery_order1'))], context=context) assert backorder_ids, "Backorder should have been created" self.do_prepare_partial(cr, uid, backorder_ids, context=context) + picking = self.browse(cr, uid backorder_ids[0]) + assert len(picking.pack_operation_ids) == 2, "Wrong number of pack operation" + assert picking.pack_operation_ids[0].produc_qty == 100, "Wrong quantity in pack operation" + assert picking.pack_operation_ids[0].package_id.name == 'Pallet 2', "Wrong pallet in pack operation" + assert picking.pack_operation_ids[1].produc_qty == 50, "Wrong quantity in pack operation" + assert picking.pack_operation_ids[1].package_id.name == 'Pallet 3', "Wrong pallet in pack operation" self.action_assign(cr, uid, backorder_ids, context=context) self.do_transfer(cr, uid, backorder_ids, context=context) - diff --git a/addons/stock/test/packingneg.yml b/addons/stock/test/packingneg.yml index 3f663394bbd..a36ba722527 100644 --- a/addons/stock/test/packingneg.yml +++ b/addons/stock/test/packingneg.yml @@ -106,7 +106,7 @@ elif rec.lot_id.name == 'Lot neg' and rec.location_id.id == ref('stock_location_customers'): assert ((rec.qty == 20 or rec.qty == 120) and not rec.package_id), "Should have 140 pieces (120+20) in customer location from pallet 2 and lot A" elif rec.package_id.name == 'Palneg 3' and rec.location_id.id == ref('stock_location_stock'): - assert rec.qty == 50 or rec.qty == 20 or rec.qty == 30, "Should have 30 and 20 pieces in stock on pallet 3" + assert rec.qty == 50, "Should have 50 pieces in stock on pallet 3" elif not rec.package_id and not rec.lot_id and rec.location_id.id == ref('stock_location_customers'): assert rec.qty == 10, "Should have 10 pieces in customer location from pallet 3" else: From 8a7d139a41346ef3333cac5d6c3365b720645fed Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Mon, 24 Feb 2014 14:19:18 +0100 Subject: [PATCH 12/14] [FIX] stock: fixed errors introduced during merge with trunk-wms bzr revid: qdp-launchpad@openerp.com-20140224131918-azyc8y3eonqafxdm --- addons/stock/stock.py | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/addons/stock/stock.py b/addons/stock/stock.py index 2e6b2573290..1bd499b0eda 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -3502,7 +3502,7 @@ class stock_pack_operation(osv.osv): break def _check_quants_reserved(ops): - if ops.package_id and not ops.product_id: + if ops.package_id and not ops.product_id: for quant in quant_obj.browse(cr, uid, package_obj.get_content(cr, uid, [ops.package_id.id]), context=context): if quant.reservation_id and quant.reservation_id.id in [x.id for x in ops.picking_id.move_lines] and (not quants_done.get(quant.id)): #Entire packages means entire quants from those packages @@ -3514,9 +3514,12 @@ class stock_pack_operation(osv.osv): #Check moves with same product for move in [x for x in ops.picking_id.move_lines if ops.product_id.id == x.product_id.id]: for quant in move.reserved_quant_ids: - if not qty > 0: + if not qty > 0: break - bool = bool(pack_obj.search(cr, uid, [('id', 'child_of', [ops.package_id.id]), ('id', '=', quants.package_id.id)], context=context) + if ops.package_id: + bool = quant.package_id and bool(package_obj.search(cr, uid, [('id', 'child_of', [ops.package_id.id]), ('id', '=', quant.package_id.id)], context=context)) or False + else: + bool = not quant.package_id.id bool = bool and ((ops.lot_id and ops.lot_id.id == quant.lot_id.id) or not ops.lot_id) bool = bool and (ops.owner_id.id == quant.owner_id.id) if bool: @@ -3534,20 +3537,26 @@ class stock_pack_operation(osv.osv): qty -= qty_todo link_obj.create(cr, uid, {'move_id': quant.reservation_id.id, 'operation_id': ops.id, 'qty': qty_todo}, context=context) - link_obj = self.pool.get('stock.move.operation.link') uom_obj = self.pool.get('product.uom') package_obj = self.pool.get('stock.quant.package') quant_obj = self.pool.get('stock.quant') - operations = self.browse(cr, uid, op_ids, context=context) - operations.sort(key = lambda x: ((x.package_id and not x.product_id) and -4 or 0) + (x.package_id and -2 or 0) + (x.lot_id and -1 or 0)) quants_done = {} + + operations = self.browse(cr, uid, op_ids, context=context) + operations.sort(key=lambda x: ((x.package_id and not x.product_id) and -4 or 0) + (x.package_id and -2 or 0) + (x.lot_id and -1 or 0)) + sorted_moves = [] for op in operations: + if not sorted_moves: + #sort moves in order to process first the ones that have already reserved quants + sorted_moves = op.picking_id.move_lines + sorted_moves.sort(key=lambda x: x.product_qty - x.reserved_availability) + to_unlink_ids = [x.id for x in op.linked_move_operation_ids] if to_unlink_ids: link_obj.unlink(cr, uid, to_unlink_ids, context=context) _check_quants_reserved(op) - + for op in operations: op.refresh() if op.product_id: From 96ffae6e6355ceea76baf13e08af2a8f72188aee Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Mon, 24 Feb 2014 15:05:12 +0100 Subject: [PATCH 13/14] [FIX] stock: typos bzr revid: qdp-launchpad@openerp.com-20140224140512-2r4ogs6ku1frtp3c --- addons/stock/stock.py | 10 +++++----- addons/stock/test/packing.yml | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/addons/stock/stock.py b/addons/stock/stock.py index 1bd499b0eda..36c665c6cbb 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -3517,12 +3517,12 @@ class stock_pack_operation(osv.osv): if not qty > 0: break if ops.package_id: - bool = quant.package_id and bool(package_obj.search(cr, uid, [('id', 'child_of', [ops.package_id.id]), ('id', '=', quant.package_id.id)], context=context)) or False + flag = quant.package_id and bool(package_obj.search(cr, uid, [('id', 'child_of', [ops.package_id.id]), ('id', '=', quant.package_id.id)], context=context)) or False else: - bool = not quant.package_id.id - bool = bool and ((ops.lot_id and ops.lot_id.id == quant.lot_id.id) or not ops.lot_id) - bool = bool and (ops.owner_id.id == quant.owner_id.id) - if bool: + flag = not quant.package_id.id + flag = flag and ((ops.lot_id and ops.lot_id.id == quant.lot_id.id) or not ops.lot_id) + flag = flag and (ops.owner_id.id == quant.owner_id.id) + if flag: quant_qty = quant.qty if quants_done.get(quant.id): if quants_done[quant.id] == 0: diff --git a/addons/stock/test/packing.yml b/addons/stock/test/packing.yml index 7bd9a3870ac..ac610112c80 100644 --- a/addons/stock/test/packing.yml +++ b/addons/stock/test/packing.yml @@ -139,11 +139,11 @@ backorder_ids = self.search(cr, uid, [('backorder_id', '=', ref('delivery_order1'))], context=context) assert backorder_ids, "Backorder should have been created" self.do_prepare_partial(cr, uid, backorder_ids, context=context) - picking = self.browse(cr, uid backorder_ids[0]) + picking = self.browse(cr, uid, backorder_ids[0]) assert len(picking.pack_operation_ids) == 2, "Wrong number of pack operation" - assert picking.pack_operation_ids[0].produc_qty == 100, "Wrong quantity in pack operation" + assert picking.pack_operation_ids[0].product_qty == 100, "Wrong quantity in pack operation" assert picking.pack_operation_ids[0].package_id.name == 'Pallet 2', "Wrong pallet in pack operation" - assert picking.pack_operation_ids[1].produc_qty == 50, "Wrong quantity in pack operation" + assert picking.pack_operation_ids[1].product_qty == 50, "Wrong quantity in pack operation" assert picking.pack_operation_ids[1].package_id.name == 'Pallet 3', "Wrong pallet in pack operation" self.action_assign(cr, uid, backorder_ids, context=context) self.do_transfer(cr, uid, backorder_ids, context=context) From 762248f8d7135831743e9c85a1c6cd914c7fa1e8 Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Mon, 24 Feb 2014 16:37:55 +0100 Subject: [PATCH 14/14] [FIX] stock: packing yaml tests fixed bzr revid: qdp-launchpad@openerp.com-20140224153755-m9n1efw5h8c2ihgf --- addons/stock/test/packing.yml | 7 +++---- addons/stock/test/packingneg.yml | 6 ++++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/addons/stock/test/packing.yml b/addons/stock/test/packing.yml index ac610112c80..c85e2b0d769 100644 --- a/addons/stock/test/packing.yml +++ b/addons/stock/test/packing.yml @@ -141,10 +141,9 @@ self.do_prepare_partial(cr, uid, backorder_ids, context=context) picking = self.browse(cr, uid, backorder_ids[0]) assert len(picking.pack_operation_ids) == 2, "Wrong number of pack operation" - assert picking.pack_operation_ids[0].product_qty == 100, "Wrong quantity in pack operation" - assert picking.pack_operation_ids[0].package_id.name == 'Pallet 2', "Wrong pallet in pack operation" - assert picking.pack_operation_ids[1].product_qty == 50, "Wrong quantity in pack operation" - assert picking.pack_operation_ids[1].package_id.name == 'Pallet 3', "Wrong pallet in pack operation" + for pack_op in picking.pack_operation_ids: + assert pack_op.product_qty == 1, "Wrong quantity in pack operation (%s found instead of 1)" % (pack_op.product_qty) + assert pack_op.package_id.name in ('Pallet 2', 'Pallet 3'), "Wrong pallet info in pack operation (%s found)" % (pack_op.package_id.name) self.action_assign(cr, uid, backorder_ids, context=context) self.do_transfer(cr, uid, backorder_ids, context=context) - diff --git a/addons/stock/test/packingneg.yml b/addons/stock/test/packingneg.yml index a36ba722527..d42cbfa52e2 100644 --- a/addons/stock/test/packingneg.yml +++ b/addons/stock/test/packingneg.yml @@ -93,10 +93,11 @@ !python {model: stock.picking}: | self.do_transfer(cr, uid, [ref('delivery_order_neg')], context=context) - - Check the quants that you have 120 pieces pallet 1 in customers, -20 pieces pallet 2 in stock and 120 and 20 with customers and 20/30 in stock, 10 in customers from pallet 3 + Check the quants that you have 120 pieces pallet 1 in customers, -20 pieces pallet 2 in stock, 120 + 20 pieces 2 in customer with lot, and a total quantity of 50 in stock from pallet 3 (should be 20+30, as it has been split by reservation), finally 10 in customers from pallet 3 - !python {model: stock.quant}: | reco_id = self.search(cr ,uid , [('product_id','=',ref('product_neg'))], context=context) + pallet_3_stock_qty = 0 for rec in self.browse(cr, uid, reco_id, context=context): if rec.package_id.name == 'Palneg 1' and rec.location_id.id == ref('stock_location_customers'): assert rec.qty == 120, "Should have 120 pieces on pallet 1" @@ -106,11 +107,12 @@ elif rec.lot_id.name == 'Lot neg' and rec.location_id.id == ref('stock_location_customers'): assert ((rec.qty == 20 or rec.qty == 120) and not rec.package_id), "Should have 140 pieces (120+20) in customer location from pallet 2 and lot A" elif rec.package_id.name == 'Palneg 3' and rec.location_id.id == ref('stock_location_stock'): - assert rec.qty == 50, "Should have 50 pieces in stock on pallet 3" + pallet_3_stock_qty += rec.qty elif not rec.package_id and not rec.lot_id and rec.location_id.id == ref('stock_location_customers'): assert rec.qty == 10, "Should have 10 pieces in customer location from pallet 3" else: assert False, "Unrecognized quant" + assert pallet_3_stock_qty == 50, "Should have 50 pieces in stock on pallet 3" - Create a picking for reconciling the negative quant -