From bf4dfcdab6afd24f858821d9b140d5eb8d697db4 Mon Sep 17 00:00:00 2001 From: hveficent Date: Tue, 7 Jan 2020 09:34:06 +0100 Subject: [PATCH] [IMP] stock_inventory_discrepancy: black, isort --- stock_inventory_discrepancy/__manifest__.py | 22 +- .../models/stock_inventory.py | 69 ++-- .../models/stock_inventory_line.py | 38 ++- .../models/stock_location.py | 11 +- .../models/stock_warehouse.py | 11 +- .../readme/CONTRIBUTORS.rst | 2 +- .../stock_inventory_discrepancy_security.xml | 2 +- .../tests/test_inventory_discrepancy.py | 321 ++++++++++-------- .../views/stock_inventory_view.xml | 2 +- .../views/stock_location_view.xml | 2 +- .../views/stock_warehouse_view.xml | 2 +- 11 files changed, 269 insertions(+), 213 deletions(-) diff --git a/stock_inventory_discrepancy/__manifest__.py b/stock_inventory_discrepancy/__manifest__.py index 9f58845ac..619e4cf29 100644 --- a/stock_inventory_discrepancy/__manifest__.py +++ b/stock_inventory_discrepancy/__manifest__.py @@ -1,24 +1,22 @@ -# Copyright 2017 Eficent Business and IT Consulting Services S.L. -# (http://www.eficent.com) +# Copyright 2017-2020 ForgeFlow S.L. (http://www.forgeflow.com) # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). { "name": "Stock Inventory Discrepancy", "summary": "Adds the capability to show the discrepancy of every line in " - "an inventory and to block the inventory validation when the " - "discrepancy is over a user defined threshold.", + "an inventory and to block the inventory validation when the " + "discrepancy is over a user defined threshold.", "version": "12.0.1.0.0", - "author": "Eficent, " - "Odoo Community Association (OCA)", + "author": "ForgeFlow, Odoo Community Association (OCA)", "website": "https://github.com/OCA/stock-logistics-warehouse", "category": "Warehouse Management", "depends": ["stock"], "data": [ - 'security/stock_inventory_discrepancy_security.xml', - 'views/stock_inventory_view.xml', - 'views/stock_warehouse_view.xml', - 'views/stock_location_view.xml', + "security/stock_inventory_discrepancy_security.xml", + "views/stock_inventory_view.xml", + "views/stock_warehouse_view.xml", + "views/stock_location_view.xml", ], "license": "AGPL-3", - 'installable': True, - 'application': False, + "installable": True, + "application": False, } diff --git a/stock_inventory_discrepancy/models/stock_inventory.py b/stock_inventory_discrepancy/models/stock_inventory.py index fd3204246..d2c39234f 100644 --- a/stock_inventory_discrepancy/models/stock_inventory.py +++ b/stock_inventory_discrepancy/models/stock_inventory.py @@ -1,69 +1,76 @@ -# Copyright 2017 Eficent Business and IT Consulting Services S.L. +# Copyright 2017-2020 ForgeFlow S.L. # (http://www.eficent.com) # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). -from odoo import api, fields, models, _ +from odoo import _, api, fields, models from odoo.exceptions import UserError class StockInventory(models.Model): - _inherit = 'stock.inventory' + _inherit = "stock.inventory" INVENTORY_STATE_SELECTION = [ - ('draft', 'Draft'), - ('cancel', 'Cancelled'), - ('confirm', 'In Progress'), - ('pending', 'Pending to Approve'), - ('done', 'Validated')] + ("draft", "Draft"), + ("cancel", "Cancelled"), + ("confirm", "In Progress"), + ("pending", "Pending to Approve"), + ("done", "Validated"), + ] state = fields.Selection( selection=INVENTORY_STATE_SELECTION, - string='Status', readonly=True, index=True, copy=False, + string="Status", + readonly=True, + index=True, + copy=False, help="States of the Inventory Adjustment:\n" - "- Draft: Inventory not started.\n" - "- In Progress: Inventory in execution.\n" - "- Pending to Approve: Inventory have some discrepancies " - "greater than the predefined threshold and it's waiting for the " - "Control Manager approval.\n" - "- Validated: Inventory Approved.") + "- Draft: Inventory not started.\n" + "- In Progress: Inventory in execution.\n" + "- Pending to Approve: Inventory have some discrepancies " + "greater than the predefined threshold and it's waiting for the " + "Control Manager approval.\n" + "- Validated: Inventory Approved.", + ) over_discrepancy_line_count = fields.Integer( - string='Number of Discrepancies Over Threshold', - compute='_compute_over_discrepancy_line_count', - store=True) + string="Number of Discrepancies Over Threshold", + compute="_compute_over_discrepancy_line_count", + store=True, + ) @api.multi - @api.depends('line_ids.product_qty', 'line_ids.theoretical_qty') + @api.depends("line_ids.product_qty", "line_ids.theoretical_qty") def _compute_over_discrepancy_line_count(self): for inventory in self: lines = inventory.line_ids.filtered( - lambda line: line.discrepancy_percent > line. - discrepancy_threshold + lambda line: line.discrepancy_percent > line.discrepancy_threshold ) inventory.over_discrepancy_line_count = len(lines) @api.multi def action_over_discrepancies(self): - self.write({'state': 'pending'}) + self.write({"state": "pending"}) def _check_group_inventory_validation_always(self): grp_inv_val = self.env.ref( - 'stock_inventory_discrepancy.group_' - 'stock_inventory_validation_always') + "stock_inventory_discrepancy.group_" "stock_inventory_validation_always" + ) if grp_inv_val in self.env.user.groups_id: return True else: raise UserError( - _('The Qty Update is over the Discrepancy Threshold.\n ' - 'Please, contact a user with rights to perform ' - 'this action.') + _( + "The Qty Update is over the Discrepancy Threshold.\n " + "Please, contact a user with rights to perform " + "this action." + ) ) def _action_done(self): for inventory in self: - if (inventory.over_discrepancy_line_count and - inventory.line_ids.filtered( - lambda t: t.discrepancy_threshold > 0.0)): - if inventory.env.context.get('normal_view', False): + if inventory.over_discrepancy_line_count and inventory.line_ids.filtered( + lambda t: t.discrepancy_threshold > 0.0 + ): + if inventory.env.context.get("normal_view", False): inventory.action_over_discrepancies() return True else: diff --git a/stock_inventory_discrepancy/models/stock_inventory_line.py b/stock_inventory_discrepancy/models/stock_inventory_line.py index 16bd44530..456200849 100644 --- a/stock_inventory_discrepancy/models/stock_inventory_line.py +++ b/stock_inventory_discrepancy/models/stock_inventory_line.py @@ -1,41 +1,46 @@ -# Copyright 2017 Eficent Business and IT Consulting Services S.L. +# Copyright 2017-2020 ForgeFlow S.L. # (http://www.eficent.com) # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). -from odoo.addons import decimal_precision as dp from odoo import api, fields, models +from odoo.addons import decimal_precision as dp + class StockInventoryLine(models.Model): - _inherit = 'stock.inventory.line' + _inherit = "stock.inventory.line" discrepancy_qty = fields.Float( - string='Discrepancy', - compute='_compute_discrepancy', + string="Discrepancy", + compute="_compute_discrepancy", help="The difference between the actual qty counted and the " - "theoretical quantity on hand.", - digits=dp.get_precision('Product Unit of Measure'), default=0) + "theoretical quantity on hand.", + digits=dp.get_precision("Product Unit of Measure"), + default=0, + ) discrepancy_percent = fields.Float( - string='Discrepancy percent (%)', - compute='_compute_discrepancy', + string="Discrepancy percent (%)", + compute="_compute_discrepancy", digits=(3, 2), help="The discrepancy expressed in percent with theoretical quantity " - "as basis") + "as basis", + ) discrepancy_threshold = fields.Float( - string='Threshold (%)', + string="Threshold (%)", digits=(3, 2), help="Maximum Discrepancy Rate Threshold", - compute='_compute_discrepancy_threshold') + compute="_compute_discrepancy_threshold", + ) @api.multi - @api.depends('theoretical_qty', 'product_qty') + @api.depends("theoretical_qty", "product_qty") def _compute_discrepancy(self): for line in self: line.discrepancy_qty = line.product_qty - line.theoretical_qty if line.theoretical_qty: line.discrepancy_percent = 100 * abs( - (line.product_qty - line.theoretical_qty) / - line.theoretical_qty) + (line.product_qty - line.theoretical_qty) / line.theoretical_qty + ) elif not line.theoretical_qty and line.product_qty: line.discrepancy_percent = 100.0 @@ -44,8 +49,7 @@ class StockInventoryLine(models.Model): for line in self: whs = line.location_id.get_warehouse() if line.location_id.discrepancy_threshold > 0.0: - line.discrepancy_threshold = line.location_id.\ - discrepancy_threshold + line.discrepancy_threshold = line.location_id.discrepancy_threshold elif whs.discrepancy_threshold > 0.0: line.discrepancy_threshold = whs.discrepancy_threshold else: diff --git a/stock_inventory_discrepancy/models/stock_location.py b/stock_inventory_discrepancy/models/stock_location.py index 5e09fee4e..9da29738d 100644 --- a/stock_inventory_discrepancy/models/stock_location.py +++ b/stock_inventory_discrepancy/models/stock_location.py @@ -1,4 +1,4 @@ -# Copyright 2017 Eficent Business and IT Consulting Services S.L. +# Copyright 2017-2020 ForgeFlow S.L. # (http://www.eficent.com) # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). @@ -6,11 +6,12 @@ from odoo import fields, models class StockLocation(models.Model): - _inherit = 'stock.location' + _inherit = "stock.location" discrepancy_threshold = fields.Float( - string='Maximum Discrepancy Rate Threshold', + string="Maximum Discrepancy Rate Threshold", digits=(3, 2), help="Maximum Discrepancy Rate allowed for any product when doing " - "an Inventory Adjustment. Thresholds defined in Locations have " - "preference over Warehouse's ones.") + "an Inventory Adjustment. Thresholds defined in Locations have " + "preference over Warehouse's ones.", + ) diff --git a/stock_inventory_discrepancy/models/stock_warehouse.py b/stock_inventory_discrepancy/models/stock_warehouse.py index f27476544..7284603e1 100644 --- a/stock_inventory_discrepancy/models/stock_warehouse.py +++ b/stock_inventory_discrepancy/models/stock_warehouse.py @@ -1,4 +1,4 @@ -# Copyright 2017 Eficent Business and IT Consulting Services S.L. +# Copyright 2017-2020 ForgeFlow S.L. # (http://www.eficent.com) # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). @@ -6,11 +6,12 @@ from odoo import fields, models class StockWarehouse(models.Model): - _inherit = 'stock.warehouse' + _inherit = "stock.warehouse" discrepancy_threshold = fields.Float( - string='Maximum Discrepancy Rate Threshold', + string="Maximum Discrepancy Rate Threshold", digits=(3, 2), help="Maximum Discrepancy Rate allowed for any product when doing " - "an Inventory Adjustment. Threshold defined in involved Location " - "has preference.") + "an Inventory Adjustment. Threshold defined in involved Location " + "has preference.", + ) diff --git a/stock_inventory_discrepancy/readme/CONTRIBUTORS.rst b/stock_inventory_discrepancy/readme/CONTRIBUTORS.rst index 260cd5370..43adb24a7 100644 --- a/stock_inventory_discrepancy/readme/CONTRIBUTORS.rst +++ b/stock_inventory_discrepancy/readme/CONTRIBUTORS.rst @@ -1,3 +1,3 @@ -* Lois Rilo +* Lois Rilo * Andreas Dian Sukarno Putro * Bhavesh Odedra diff --git a/stock_inventory_discrepancy/security/stock_inventory_discrepancy_security.xml b/stock_inventory_discrepancy/security/stock_inventory_discrepancy_security.xml index 527dad6b3..b0f079de9 100644 --- a/stock_inventory_discrepancy/security/stock_inventory_discrepancy_security.xml +++ b/stock_inventory_discrepancy/security/stock_inventory_discrepancy_security.xml @@ -1,5 +1,5 @@ - diff --git a/stock_inventory_discrepancy/tests/test_inventory_discrepancy.py b/stock_inventory_discrepancy/tests/test_inventory_discrepancy.py index dc0004793..c48da0460 100644 --- a/stock_inventory_discrepancy/tests/test_inventory_discrepancy.py +++ b/stock_inventory_discrepancy/tests/test_inventory_discrepancy.py @@ -1,172 +1,217 @@ -# Copyright 2017 Eficent Business and IT Consulting Services S.L. +# Copyright 2017-2020 ForgeFlow S.L. # (http://www.eficent.com) # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). -from odoo.tests.common import TransactionCase from odoo.exceptions import UserError +from odoo.tests.common import TransactionCase class TestInventoryDiscrepancy(TransactionCase): def setUp(self, *args, **kwargs): super(TestInventoryDiscrepancy, self).setUp(*args, **kwargs) - self.obj_wh = self.env['stock.warehouse'] - self.obj_location = self.env['stock.location'] - self.obj_inventory = self.env['stock.inventory'] - self.obj_product = self.env['product.product'] - self.obj_warehouse = self.env['stock.warehouse'] - self.obj_upd_qty_wizard = self.env['stock.change.product.qty'] + self.obj_wh = self.env["stock.warehouse"] + self.obj_location = self.env["stock.location"] + self.obj_inventory = self.env["stock.inventory"] + self.obj_product = self.env["product.product"] + self.obj_warehouse = self.env["stock.warehouse"] + self.obj_upd_qty_wizard = self.env["stock.change.product.qty"] - self.product1 = self.obj_product.create({ - 'name': 'Test Product 1', - 'type': 'product', - 'default_code': 'PROD1', - }) - self.product2 = self.obj_product.create({ - 'name': 'Test Product 2', - 'type': 'product', - 'default_code': 'PROD2', - }) - self.test_loc = self.obj_location.create({ - 'name': 'Test Location', - 'usage': 'internal', - 'discrepancy_threshold': 0.1 - }) - self.test_wh = self.obj_warehouse.create({ - 'name': 'Test WH', - 'code': 'T', - 'discrepancy_threshold': 0.2 - }) + self.product1 = self.obj_product.create( + {"name": "Test Product 1", "type": "product", "default_code": "PROD1"} + ) + self.product2 = self.obj_product.create( + {"name": "Test Product 2", "type": "product", "default_code": "PROD2"} + ) + self.test_loc = self.obj_location.create( + {"name": "Test Location", "usage": "internal", "discrepancy_threshold": 0.1} + ) + self.test_wh = self.obj_warehouse.create( + {"name": "Test WH", "code": "T", "discrepancy_threshold": 0.2} + ) self.obj_location._parent_store_compute() # Create Stock manager able to force validation on inventories. - group_stock_man = self.env.ref('stock.group_stock_manager') + group_stock_man = self.env.ref("stock.group_stock_manager") group_inventory_all = self.env.ref( - 'stock_inventory_discrepancy.' - 'group_stock_inventory_validation_always') - self.manager = self.env['res.users'].create({ - 'name': 'Test Manager', - 'login': 'manager', - 'email': 'test.manager@example.com', - 'groups_id': [(6, 0, [group_stock_man.id, group_inventory_all.id])] - }) - group_stock_user = self.env.ref('stock.group_stock_user') - self.user = self.env['res.users'].create({ - 'name': 'Test User', - 'login': 'user', - 'email': 'test.user@example.com', - 'groups_id': [(6, 0, [group_stock_user.id])] - }) + "stock_inventory_discrepancy." "group_stock_inventory_validation_always" + ) + self.manager = self.env["res.users"].create( + { + "name": "Test Manager", + "login": "manager", + "email": "test.manager@example.com", + "groups_id": [(6, 0, [group_stock_man.id, group_inventory_all.id])], + } + ) + group_stock_user = self.env.ref("stock.group_stock_user") + self.user = self.env["res.users"].create( + { + "name": "Test User", + "login": "user", + "email": "test.user@example.com", + "groups_id": [(6, 0, [group_stock_user.id])], + } + ) - starting_inv = self.obj_inventory.create({ - 'name': 'Starting inventory', - 'filter': 'product', - 'line_ids': [ - (0, 0, { - 'product_id': self.product1.id, - 'product_uom_id': self.env.ref( - "uom.product_uom_unit").id, - 'product_qty': 2.0, - 'location_id': self.test_loc.id, - }), - (0, 0, { - 'product_id': self.product2.id, - 'product_uom_id': self.env.ref( - "uom.product_uom_unit").id, - 'product_qty': 4.0, - 'location_id': self.test_loc.id, - }), - ], - }) + starting_inv = self.obj_inventory.create( + { + "name": "Starting inventory", + "filter": "product", + "line_ids": [ + ( + 0, + 0, + { + "product_id": self.product1.id, + "product_uom_id": self.env.ref("uom.product_uom_unit").id, + "product_qty": 2.0, + "location_id": self.test_loc.id, + }, + ), + ( + 0, + 0, + { + "product_id": self.product2.id, + "product_uom_id": self.env.ref("uom.product_uom_unit").id, + "product_qty": 4.0, + "location_id": self.test_loc.id, + }, + ), + ], + } + ) starting_inv.action_force_done() def test_compute_discrepancy(self): """Tests if the discrepancy is correctly computed. """ - inventory = self.obj_inventory.create({ - 'name': 'Test Discrepancy Computation', - 'location_id': self.test_loc.id, - 'filter': 'none', - 'line_ids': [ - (0, 0, { - 'product_id': self.product1.id, - 'product_uom_id': self.env.ref( - "uom.product_uom_unit").id, - 'product_qty': 3.0, - 'location_id': self.test_loc.id, - }), - (0, 0, { - 'product_id': self.product2.id, - 'product_uom_id': self.env.ref( - "uom.product_uom_unit").id, - 'product_qty': 3.0, - 'location_id': self.test_loc.id, - }) - ], - }) - self.assertEqual(inventory.line_ids[0].discrepancy_qty, 1.0, - 'Wrong Discrepancy qty computation.') - self.assertEqual(inventory.line_ids[1].discrepancy_qty, - 1.0, - 'Wrong Discrepancy qty computation.') + inventory = self.obj_inventory.create( + { + "name": "Test Discrepancy Computation", + "location_id": self.test_loc.id, + "filter": "none", + "line_ids": [ + ( + 0, + 0, + { + "product_id": self.product1.id, + "product_uom_id": self.env.ref("uom.product_uom_unit").id, + "product_qty": 3.0, + "location_id": self.test_loc.id, + }, + ), + ( + 0, + 0, + { + "product_id": self.product2.id, + "product_uom_id": self.env.ref("uom.product_uom_unit").id, + "product_qty": 3.0, + "location_id": self.test_loc.id, + }, + ), + ], + } + ) + self.assertEqual( + inventory.line_ids[0].discrepancy_qty, + 1.0, + "Wrong Discrepancy qty computation.", + ) + self.assertEqual( + inventory.line_ids[1].discrepancy_qty, + -1.0, + "Wrong Discrepancy qty computation.", + ) def test_discrepancy_validation(self): """Tests the new workflow""" - inventory = self.obj_inventory.create({ - 'name': 'Test Forcing Validation Method', - 'location_id': self.test_loc.id, - 'filter': 'none', - 'line_ids': [ - (0, 0, { - 'product_id': self.product1.id, - 'product_uom_id': self.env.ref( - "uom.product_uom_unit").id, - 'product_qty': 3.0, - 'location_id': self.test_loc.id, - }), - ], - }) - self.assertEqual(inventory.state, 'draft', - 'Testing Inventory wrongly configurated') - self.assertEqual(inventory.line_ids.discrepancy_threshold, 0.1, - 'Threshold wrongly computed in Inventory Line.') - inventory.with_context({'normal_view': True}).action_validate() - self.assertEqual(inventory.over_discrepancy_line_count, 1, - 'Computation of over-discrepancies failed.') - self.assertEqual(inventory.state, 'pending', - 'Inventory Adjustment not changing to Pending to ' - 'Approve.') + inventory = self.obj_inventory.create( + { + "name": "Test Forcing Validation Method", + "location_id": self.test_loc.id, + "filter": "none", + "line_ids": [ + ( + 0, + 0, + { + "product_id": self.product1.id, + "product_uom_id": self.env.ref("uom.product_uom_unit").id, + "product_qty": 3.0, + "location_id": self.test_loc.id, + }, + ) + ], + } + ) + self.assertEqual( + inventory.state, "draft", "Testing Inventory wrongly configurated" + ) + self.assertEqual( + inventory.line_ids.discrepancy_threshold, + 0.1, + "Threshold wrongly computed in Inventory Line.", + ) + inventory.with_context({"normal_view": True}).action_validate() + self.assertEqual( + inventory.over_discrepancy_line_count, + 1, + "Computation of over-discrepancies failed.", + ) + self.assertEqual( + inventory.state, + "pending", + "Inventory Adjustment not changing to Pending to " "Approve.", + ) inventory.sudo(self.manager).action_force_done() - self.assertEqual(inventory.state, 'done', - 'Forcing the validation of the inventory adjustment ' - 'not working properly.') + self.assertEqual( + inventory.state, + "done", + "Forcing the validation of the inventory adjustment " + "not working properly.", + ) def test_warehouse_threshold(self): """Tests the behaviour if the threshold is set on the WH.""" - inventory = self.obj_inventory.create({ - 'name': 'Test Threshold Defined in WH', - 'location_id': self.test_wh.view_location_id.id, - 'filter': 'none', - 'line_ids': [ - (0, 0, { - 'product_id': self.product1.id, - 'product_uom_id': self.env.ref( - "uom.product_uom_unit").id, - 'product_qty': 3.0, - 'location_id': self.test_wh.lot_stock_id.id, - }), - ], - }) - self.assertEqual(inventory.line_ids.discrepancy_threshold, 0.2, - 'Threshold wrongly computed in Inventory Line.') + inventory = self.obj_inventory.create( + { + "name": "Test Threshold Defined in WH", + "location_id": self.test_wh.view_location_id.id, + "filter": "none", + "line_ids": [ + ( + 0, + 0, + { + "product_id": self.product1.id, + "product_uom_id": self.env.ref("uom.product_uom_unit").id, + "product_qty": 3.0, + "location_id": self.test_wh.lot_stock_id.id, + }, + ) + ], + } + ) + self.assertEqual( + inventory.line_ids.discrepancy_threshold, + 0.2, + "Threshold wrongly computed in Inventory Line.", + ) def test_update_qty_user_error(self): """Test if a user error raises when a stock user tries to update the qty for a product and the correction is a discrepancy over the threshold.""" - upd_qty = self.obj_upd_qty_wizard.sudo(self.user).create({ - 'product_id': self.product1.id, - 'product_tmpl_id': self.product1.product_tmpl_id.id, - 'new_quantity': 10.0, - 'location_id': self.test_loc.id, - }) + upd_qty = self.obj_upd_qty_wizard.sudo(self.user).create( + { + "product_id": self.product1.id, + "product_tmpl_id": self.product1.product_tmpl_id.id, + "new_quantity": 10.0, + "location_id": self.test_loc.id, + } + ) with self.assertRaises(UserError): upd_qty.change_product_qty() diff --git a/stock_inventory_discrepancy/views/stock_inventory_view.xml b/stock_inventory_discrepancy/views/stock_inventory_view.xml index 1561ba6a0..7f688ac69 100644 --- a/stock_inventory_discrepancy/views/stock_inventory_view.xml +++ b/stock_inventory_discrepancy/views/stock_inventory_view.xml @@ -1,5 +1,5 @@ - diff --git a/stock_inventory_discrepancy/views/stock_location_view.xml b/stock_inventory_discrepancy/views/stock_location_view.xml index 644e866f2..f04ace36e 100644 --- a/stock_inventory_discrepancy/views/stock_location_view.xml +++ b/stock_inventory_discrepancy/views/stock_location_view.xml @@ -1,5 +1,5 @@ - diff --git a/stock_inventory_discrepancy/views/stock_warehouse_view.xml b/stock_inventory_discrepancy/views/stock_warehouse_view.xml index 8e497a894..bc617867a 100644 --- a/stock_inventory_discrepancy/views/stock_warehouse_view.xml +++ b/stock_inventory_discrepancy/views/stock_warehouse_view.xml @@ -1,5 +1,5 @@ -