From f712a81a5982c086d893f2bede9b91cfda0ef967 Mon Sep 17 00:00:00 2001 From: lreficent Date: Thu, 16 Nov 2017 11:16:19 +0100 Subject: [PATCH 1/4] [9.0][FIX] stock_inventory_lockdown: locking unneded locations. --- stock_inventory_lockdown/__openerp__.py | 2 +- stock_inventory_lockdown/models/stock_inventory.py | 2 -- stock_inventory_lockdown/models/stock_move.py | 11 ++++++++++- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/stock_inventory_lockdown/__openerp__.py b/stock_inventory_lockdown/__openerp__.py index e8c5e3e56..7142448fc 100644 --- a/stock_inventory_lockdown/__openerp__.py +++ b/stock_inventory_lockdown/__openerp__.py @@ -5,7 +5,7 @@ { "name": "Inventory Lock Down", "summary": "Lock down stock locations during inventories.", - "version": "9.0.1.0.1", + "version": "9.0.1.0.2", "depends": ["stock"], "author": "Numérigraphe,Eficent,Odoo Community Association (OCA)", "category": "Warehouse Management", diff --git a/stock_inventory_lockdown/models/stock_inventory.py b/stock_inventory_lockdown/models/stock_inventory.py index ef4643f18..73ab67df9 100644 --- a/stock_inventory_lockdown/models/stock_inventory.py +++ b/stock_inventory_lockdown/models/stock_inventory.py @@ -26,6 +26,4 @@ class StockInventory(models.Model): location_domain = [ ('location_id', 'child_of', location_ids.ids), ('usage', 'in', ['internal', 'transit'])] - if locations_ids: - location_domain.append(('location_id', 'child_of', locations_ids)) return self.env['stock.location'].search(location_domain) diff --git a/stock_inventory_lockdown/models/stock_move.py b/stock_inventory_lockdown/models/stock_move.py index 493a3eb07..46876213c 100644 --- a/stock_inventory_lockdown/models/stock_move.py +++ b/stock_inventory_lockdown/models/stock_move.py @@ -11,15 +11,24 @@ from openerp.exceptions import ValidationError class StockMove(models.Model): _inherit = 'stock.move' + @api.multi + def _get_reserved_locations(self): + self.ensure_one() + return self.reserved_quant_ids.mapped('location_id') + \ + self.split_from.reserved_quant_ids.mapped('location_id') + @api.constrains('location_dest_id', 'location_id', 'state') def _check_locked_location(self): for move in self.filtered(lambda m: m.state != 'draft'): locked_location_ids = self.env[ 'stock.inventory']._get_locations_open_inventories( [move.location_dest_id.id, move.location_id.id]) + reserved_locs = move._get_reserved_locations() if (locked_location_ids and move.product_id.property_stock_inventory not in [ - move.location_dest_id, move.location_id]): + move.location_dest_id, move.location_id] and + (move.location_dest_id in locked_location_ids or + any([l in locked_location_ids for l in reserved_locs]))): location_names = locked_location_ids.mapped('complete_name') raise ValidationError( _('An inventory is being conducted at the following ' From 917041818682b53231935753d3eba17d653d7c90 Mon Sep 17 00:00:00 2001 From: lreficent Date: Thu, 16 Nov 2017 15:02:30 +0100 Subject: [PATCH 2/4] add test case --- .../tests/test_stock_inventory_lockdown.py | 65 +++++++++++++++---- 1 file changed, 53 insertions(+), 12 deletions(-) diff --git a/stock_inventory_lockdown/tests/test_stock_inventory_lockdown.py b/stock_inventory_lockdown/tests/test_stock_inventory_lockdown.py index cfcb7dfeb..d144985ef 100644 --- a/stock_inventory_lockdown/tests/test_stock_inventory_lockdown.py +++ b/stock_inventory_lockdown/tests/test_stock_inventory_lockdown.py @@ -10,10 +10,14 @@ from openerp.addons.stock.tests.common import TestStockCommon class StockInventoryLocationTest(TestStockCommon): def setUp(self): super(StockInventoryLocationTest, self).setUp() - # Make a new location + # Make a new location with a parent and a child. + self.new_parent_location = self.env['stock.location'].create( + {'name': 'Test parent location', + 'usage': 'internal'}) self.new_location = self.env['stock.location'].create( {'name': 'Test location', - 'usage': 'internal'}) + 'usage': 'internal', + 'location_id': self.new_parent_location.id}) self.new_sublocation = self.env['stock.location'].create( {'name': 'Test sublocation', 'usage': 'internal', @@ -23,6 +27,10 @@ class StockInventoryLocationTest(TestStockCommon): {'location_id': self.new_location.id, 'product_id': self.productA.id, 'qty': 10.0}) + self.env['stock.quant'].create( + {'location_id': self.new_parent_location.id, + 'product_id': self.productB.id, + 'qty': 5.0}) # Prepare an inventory self.inventory = self.env['stock.inventory'].create( {'name': 'Lock down location', @@ -31,6 +39,16 @@ class StockInventoryLocationTest(TestStockCommon): self.inventory.prepare_inventory() self.assertTrue(self.inventory.line_ids, 'The inventory is empty.') + def create_stock_move(self, product, origin_id=False, dest_id=False): + return self.env['stock.move'].create({ + 'name': 'Test move lock down', + 'product_id': product.id, + 'product_uom_qty': 10.0, + 'product_uom': product.uom_id.id, + 'location_id': origin_id or self.supplier_location, + 'location_dest_id': dest_id or self.customer_location, + }) + def test_update_parent_location(self): """Updating the parent of a location is OK if no inv. in progress.""" self.inventory.action_cancel_inventory() @@ -73,14 +91,37 @@ class StockInventoryLocationTest(TestStockCommon): location=line.location_id.id).qty_available, 22.0) def test_move(self): - """Stock move must be forbidden during inventory""" - move = self.env['stock.move'].create({ - 'name': 'Test move lock down', - 'product_id': self.productA.id, - 'product_uom_qty': 10.0, - 'product_uom': self.productA.uom_id.id, - 'location_id': self.inventory.location_id.id, - 'location_dest_id': self.customer_location - }) + """Stock moves must be forbidden during inventory from/to inventoried + location.""" + move1 = self.create_stock_move( + self.productA, origin_id=self.inventory.location_id.id) + move1.action_confirm() with self.assertRaises(ValidationError): - move.action_done() + move1.action_assign() + move1.action_done() + move2 = self.create_stock_move( + self.productA, dest_id=self.inventory.location_id.id) + with self.assertRaises(ValidationError): + move2.action_confirm() + move2.action_assign() + move2.action_done() + + def test_move_reserved_quants(self): + """Shipping stock should be allowed or not depending on reserved + quants' locations. + * move1: quants are fetched from the parent location. + * move2: quants are fetched from 'new location' which is being + inventoried.""" + move1 = self.create_stock_move( + self.productB, self.new_parent_location.id) + move1.action_confirm() + move1.action_assign() + move1.action_done() + self.assertEqual( + move1.state, 'done', 'Move has not been completed') + move2 = self.create_stock_move( + self.productA, self.new_parent_location.id) + move2.action_confirm() + with self.assertRaises(ValidationError): + move2.action_assign() + move2.action_done() From a7c850e27d2e24130e293b561d3bb8d5bdd51969 Mon Sep 17 00:00:00 2001 From: lreficent Date: Thu, 16 Nov 2017 18:39:22 +0100 Subject: [PATCH 3/4] travis --- stock_inventory_lockdown/models/stock_move.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stock_inventory_lockdown/models/stock_move.py b/stock_inventory_lockdown/models/stock_move.py index 46876213c..e84875239 100644 --- a/stock_inventory_lockdown/models/stock_move.py +++ b/stock_inventory_lockdown/models/stock_move.py @@ -15,7 +15,7 @@ class StockMove(models.Model): def _get_reserved_locations(self): self.ensure_one() return self.reserved_quant_ids.mapped('location_id') + \ - self.split_from.reserved_quant_ids.mapped('location_id') + self.split_from.reserved_quant_ids.mapped('location_id') @api.constrains('location_dest_id', 'location_id', 'state') def _check_locked_location(self): From c5bbee161e97b1586383c70f48b47e34f7db6b01 Mon Sep 17 00:00:00 2001 From: lreficent Date: Wed, 27 Dec 2017 15:36:43 +0100 Subject: [PATCH 4/4] fix consider operations --- stock_inventory_lockdown/models/stock_move.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/stock_inventory_lockdown/models/stock_move.py b/stock_inventory_lockdown/models/stock_move.py index e84875239..08834c29f 100644 --- a/stock_inventory_lockdown/models/stock_move.py +++ b/stock_inventory_lockdown/models/stock_move.py @@ -17,6 +17,12 @@ class StockMove(models.Model): return self.reserved_quant_ids.mapped('location_id') + \ self.split_from.reserved_quant_ids.mapped('location_id') + @api.multi + def _get_dest_locations(self): + self.ensure_one() + return self.linked_move_operation_ids.mapped( + 'operation_id.location_dest_id') + @api.constrains('location_dest_id', 'location_id', 'state') def _check_locked_location(self): for move in self.filtered(lambda m: m.state != 'draft'): @@ -24,10 +30,12 @@ class StockMove(models.Model): 'stock.inventory']._get_locations_open_inventories( [move.location_dest_id.id, move.location_id.id]) reserved_locs = move._get_reserved_locations() + dest_locs = move._get_dest_locations() if (locked_location_ids and move.product_id.property_stock_inventory not in [ move.location_dest_id, move.location_id] and (move.location_dest_id in locked_location_ids or + any([l in locked_location_ids for l in dest_locs]) or any([l in locked_location_ids for l in reserved_locs]))): location_names = locked_location_ids.mapped('complete_name') raise ValidationError(