diff --git a/stock_location_lockdown/__init__.py b/stock_location_lockdown/__init__.py index 9cf531149..79e06e260 100644 --- a/stock_location_lockdown/__init__.py +++ b/stock_location_lockdown/__init__.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright 2018 Akretion # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). diff --git a/stock_location_lockdown/__manifest__.py b/stock_location_lockdown/__manifest__.py index 26c16a473..ae60d7d20 100644 --- a/stock_location_lockdown/__manifest__.py +++ b/stock_location_lockdown/__manifest__.py @@ -1,14 +1,13 @@ -# -*- coding: utf-8 -*- # Copyright 2018 Akretion # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). { "name": "Stock Location Lockdown", - "summary": "Prevent to add stock on flagged locations", + "summary": "Prevent to add stock on locked locations", "author": "Akretion, Odoo Community Association (OCA)", "website": "https://github.com/OCA/stock-logistics-warehouse", "category": "Warehouse", - "version": "10.0.1.1.0", + "version": "12.0.1.0.0", "license": "AGPL-3", "application": False, "installable": True, diff --git a/stock_location_lockdown/models/__init__.py b/stock_location_lockdown/models/__init__.py index 28f630281..d081518d5 100644 --- a/stock_location_lockdown/models/__init__.py +++ b/stock_location_lockdown/models/__init__.py @@ -1,5 +1,4 @@ -# -*- coding: utf-8 -*- -# Copyright 2018 Akretion +# Copyright 2019 Akretion # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from . import stock_location diff --git a/stock_location_lockdown/models/stock_location.py b/stock_location_lockdown/models/stock_location.py index 965144e8b..8be21735a 100644 --- a/stock_location_lockdown/models/stock_location.py +++ b/stock_location_lockdown/models/stock_location.py @@ -1,8 +1,8 @@ -# -*- coding: utf-8 -*- -# Copyright 2018 Akretion +# Copyright 2019 Akretion # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import fields, models +from odoo import fields, models, _ +from odoo.exceptions import UserError class StockLocation(models.Model): @@ -12,3 +12,20 @@ class StockLocation(models.Model): help="if this box is checked, putting stock on this location won't be " "allowed. Usually used for a virtual location that has " "childrens.") + + # Raise error if the location that you're trying to block + # has already got quants + def write(self, values): + res = super().write(values) + + if ('block_stock_entrance' in values + and values['block_stock_entrance']): + # Unlink zero quants before checking + # if there are quants on the location + self.env['stock.quant']._unlink_zero_quants() + if self.mapped('quant_ids'): + raise UserError( + _("It is impossible to prohibit this location from\ + receiving products as it already contains some.") + ) + return res diff --git a/stock_location_lockdown/models/stock_quant.py b/stock_location_lockdown/models/stock_quant.py index 89b6b45ef..05ad42ce9 100644 --- a/stock_location_lockdown/models/stock_quant.py +++ b/stock_location_lockdown/models/stock_quant.py @@ -1,5 +1,4 @@ -# -*- coding: utf-8 -*- -# Copyright 2018 Akretion +# Copyright 2019 Akretion # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from odoo import api, models, _ @@ -9,8 +8,10 @@ from odoo.exceptions import ValidationError class StockQuant(models.Model): _inherit = 'stock.quant' + # Raise an error when trying to change a quant + # which corresponding stock location is blocked @api.constrains('location_id') - def _check_location_blocked(self): + def check_location_blocked(self): for record in self: if record.location_id.block_stock_entrance: raise ValidationError( diff --git a/stock_location_lockdown/tests/__init__.py b/stock_location_lockdown/tests/__init__.py index 26c695414..2f0a9ad06 100644 --- a/stock_location_lockdown/tests/__init__.py +++ b/stock_location_lockdown/tests/__init__.py @@ -1,5 +1,4 @@ -# -*- coding: utf-8 -*- -# Copyright 2018 Akretion +# Copyright 2019 Akretion # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from . import test_block_stock_location_entrance diff --git a/stock_location_lockdown/tests/test_block_stock_location_entrance.py b/stock_location_lockdown/tests/test_block_stock_location_entrance.py index 51dc3938f..c31582aae 100644 --- a/stock_location_lockdown/tests/test_block_stock_location_entrance.py +++ b/stock_location_lockdown/tests/test_block_stock_location_entrance.py @@ -1,8 +1,7 @@ -# -*- coding: utf-8 -*- -# Copyright 2018 Akretion France +# Copyright 2019 Akretion France # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo.exceptions import ValidationError +from odoo.exceptions import ValidationError, UserError from odoo.tests.common import TransactionCase @@ -10,42 +9,78 @@ class TestStockLocationLockdown(TransactionCase): def setUp(self, *args, **kwargs): super(TestStockLocationLockdown, self).setUp(*args, **kwargs) - self.main_stock_location = self.env.ref('stock.stock_location_stock') - self.main_stock_location.block_stock_entrance = True + + # Create a new stock location with no quants and blocked stock entrance + new_loc = {'name': 'location_test', 'usage': 'internal'} + self.new_stock_location = self.env['stock.location'].create(new_loc) + self.new_stock_location.block_stock_entrance = True + self.supplier_location = self.env.ref('stock.stock_location_suppliers') self.customer_location = self.env.ref('stock.stock_location_customers') + + # Call an existing product and force no Lot/Serial Number tracking self.product = self.env.ref('product.product_product_27') + self.product.tracking = 'none' + + # Catch the first quant's stock location + self.stock_location = self.env['stock.quant'].search([])[0].location_id def test_transfer_stock_in_locked_location(self): """ Test to move stock within a location that should not accept - Stock entrance. + stock entrance. """ move_vals = { 'location_id': self.supplier_location.id, - 'location_dest_id': self.main_stock_location.id, + 'location_dest_id': self.new_stock_location.id, 'product_id': self.product.id, 'product_uom_qty': self.product.qty_available + 1, 'product_uom': 1, 'name': 'test', + 'move_line_ids': [(0, 0, { + 'product_id': self.product.id, + 'product_uom_qty': 0, + 'product_uom_id': 1, + 'qty_done': self.product.qty_available + 1, + 'location_id': self.supplier_location.id, + 'location_dest_id': self.new_stock_location.id, + })] } stock_move = self.env['stock.move'].create(move_vals) + with self.assertRaises(ValidationError): - stock_move.action_done() + stock_move._action_done() def test_transfer_stock_out_locked_location(self): """ - Test to move stock within a location that should not accept - Stock entrance. + Test to move stock out from a location that should not accept + stock removal. """ move_vals = { - 'location_id': self.main_stock_location.id, + 'location_id': self.new_stock_location.id, 'location_dest_id': self.customer_location.id, 'product_id': self.product.id, 'product_uom_qty': self.product.qty_available + 1, 'product_uom': 1, 'name': 'test', + 'move_line_ids': [(0, 0, { + 'product_id': self.product.id, + 'product_uom_qty': 0, + 'product_uom_id': 1, + 'qty_done': self.product.qty_available + 1, + 'location_id': self.supplier_location.id, + 'location_dest_id': self.new_stock_location.id, + })] } stock_move = self.env['stock.move'].create(move_vals) + with self.assertRaises(ValidationError): - stock_move.action_done() + stock_move._action_done() + + def test_block_location_with_quants(self): + """ + Test to click on block_stock_entrance checkbox in a location + that should not be blocked because it has already got quants + """ + with self.assertRaises(UserError): + self.stock_location.write({'block_stock_entrance': True})