From dae14da820e34ad060326542f92cad46c69e42e6 Mon Sep 17 00:00:00 2001 From: lreficent Date: Thu, 16 Nov 2017 11:16:19 +0100 Subject: [PATCH] [10.0][FIX] stock_inventory_lockdown: locking unneded locations. --- stock_inventory_lockdown/__manifest__.py | 6 +- .../models/stock_inventory.py | 2 - stock_inventory_lockdown/models/stock_move.py | 19 +++++- .../tests/test_stock_inventory_lockdown.py | 65 +++++++++++++++---- 4 files changed, 74 insertions(+), 18 deletions(-) diff --git a/stock_inventory_lockdown/__manifest__.py b/stock_inventory_lockdown/__manifest__.py index 3196028d1..1d458eecd 100644 --- a/stock_inventory_lockdown/__manifest__.py +++ b/stock_inventory_lockdown/__manifest__.py @@ -5,13 +5,13 @@ { "name": "Inventory Lock Down", "summary": "Lock down stock locations during inventories.", - "version": "10.0.1.0.0", + "version": "10.0.1.0.1", "depends": ["stock"], - "author": "Numérigraphe,Eficent,Odoo Community Association (OCA)", + "author": "Numérigraphe, Eficent, Odoo Community Association (OCA)", "category": "Warehouse Management", "images": [ "images/move_error.png", "images/location_locked.png"], - 'license': 'AGPL-3', + "license": "AGPL-3", "installable": True, } diff --git a/stock_inventory_lockdown/models/stock_inventory.py b/stock_inventory_lockdown/models/stock_inventory.py index aab5010fd..b1302dfda 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 fbc1f2161..5655ddd6a 100644 --- a/stock_inventory_lockdown/models/stock_move.py +++ b/stock_inventory_lockdown/models/stock_move.py @@ -11,15 +11,32 @@ from odoo.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.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'): 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() + 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]): + 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( _('An inventory is being conducted at the following ' diff --git a/stock_inventory_lockdown/tests/test_stock_inventory_lockdown.py b/stock_inventory_lockdown/tests/test_stock_inventory_lockdown.py index 60e7c8785..f20b06340 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 odoo.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_draft() @@ -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()