From c4a371959bd423f6d53a449f104d7ae79be82497 Mon Sep 17 00:00:00 2001 From: DavidJForgeFlow Date: Thu, 6 Oct 2022 15:28:51 +0200 Subject: [PATCH] [15.0][ADD] stock_inventory [15.0][IMP] stock_inventory: add product selection and fixup --- .../odoo/addons/stock_inventory | 1 + setup/stock_inventory/setup.py | 6 + stock_inventory/README.rst | 0 stock_inventory/__init__.py | 1 + stock_inventory/__manifest__.py | 20 ++ stock_inventory/models/__init__.py | 3 + stock_inventory/models/stock_inventory.py | 216 ++++++++++++ stock_inventory/models/stock_move_line.py | 7 + stock_inventory/models/stock_quant.py | 36 ++ stock_inventory/readme/CONTRIBUTORS.rst | 4 + stock_inventory/readme/DESCRIPTION.rst | 1 + stock_inventory/readme/USAGE.rst | 9 + stock_inventory/security/ir.model.access.csv | 3 + stock_inventory/tests/__init__.py | 1 + stock_inventory/tests/test_stock_inventory.py | 314 ++++++++++++++++++ stock_inventory/views/stock_inventory.xml | 154 +++++++++ stock_inventory/views/stock_move_line.xml | 29 ++ stock_inventory/views/stock_quant.xml | 16 + 18 files changed, 821 insertions(+) create mode 120000 setup/stock_inventory/odoo/addons/stock_inventory create mode 100644 setup/stock_inventory/setup.py create mode 100644 stock_inventory/README.rst create mode 100644 stock_inventory/__init__.py create mode 100644 stock_inventory/__manifest__.py create mode 100644 stock_inventory/models/__init__.py create mode 100644 stock_inventory/models/stock_inventory.py create mode 100644 stock_inventory/models/stock_move_line.py create mode 100644 stock_inventory/models/stock_quant.py create mode 100644 stock_inventory/readme/CONTRIBUTORS.rst create mode 100644 stock_inventory/readme/DESCRIPTION.rst create mode 100644 stock_inventory/readme/USAGE.rst create mode 100644 stock_inventory/security/ir.model.access.csv create mode 100644 stock_inventory/tests/__init__.py create mode 100644 stock_inventory/tests/test_stock_inventory.py create mode 100644 stock_inventory/views/stock_inventory.xml create mode 100644 stock_inventory/views/stock_move_line.xml create mode 100644 stock_inventory/views/stock_quant.xml diff --git a/setup/stock_inventory/odoo/addons/stock_inventory b/setup/stock_inventory/odoo/addons/stock_inventory new file mode 120000 index 000000000000..6a46dcae75fe --- /dev/null +++ b/setup/stock_inventory/odoo/addons/stock_inventory @@ -0,0 +1 @@ +../../../../stock_inventory \ No newline at end of file diff --git a/setup/stock_inventory/setup.py b/setup/stock_inventory/setup.py new file mode 100644 index 000000000000..28c57bb64031 --- /dev/null +++ b/setup/stock_inventory/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/stock_inventory/README.rst b/stock_inventory/README.rst new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/stock_inventory/__init__.py b/stock_inventory/__init__.py new file mode 100644 index 000000000000..0650744f6bc6 --- /dev/null +++ b/stock_inventory/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/stock_inventory/__manifest__.py b/stock_inventory/__manifest__.py new file mode 100644 index 000000000000..fc7c70b8abae --- /dev/null +++ b/stock_inventory/__manifest__.py @@ -0,0 +1,20 @@ +{ + "name": "Stock Inventory Adjustment", + "version": "15.0.1.0.0", + "license": "LGPL-3", + "maintainer": ["DavidJForgeFlow"], + "development_status": "Beta", + "category": "Inventory/Inventory", + "summary": "Allows to do an easier follow up of the Inventory Adjustments", + "author": "ForgeFlow, Odoo Community Association (OCA)", + "website": "https://github.com/OCA/stock-logistics-warehouse", + "depends": ["stock"], + "data": [ + "security/ir.model.access.csv", + "views/stock_inventory.xml", + "views/stock_quant.xml", + "views/stock_move_line.xml", + ], + "installable": True, + "application": False, +} diff --git a/stock_inventory/models/__init__.py b/stock_inventory/models/__init__.py new file mode 100644 index 000000000000..09732e334e94 --- /dev/null +++ b/stock_inventory/models/__init__.py @@ -0,0 +1,3 @@ +from . import stock_inventory +from . import stock_quant +from . import stock_move_line diff --git a/stock_inventory/models/stock_inventory.py b/stock_inventory/models/stock_inventory.py new file mode 100644 index 000000000000..cf01a33aa037 --- /dev/null +++ b/stock_inventory/models/stock_inventory.py @@ -0,0 +1,216 @@ +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError +from odoo.osv import expression + + +class InventoryAdjustmentsGroup(models.Model): + _name = "stock.inventory" + _description = "Inventory Adjustment Group" + _order = "date desc, id desc" + + name = fields.Char(required=True, default="Inventory", string="Inventory Reference") + + date = fields.Datetime(default=lambda self: fields.Datetime.now()) + + state = fields.Selection( + [("draft", "Draft"), ("in_progress", "In Progress"), ("done", "Done")], + default="draft", + ) + + owner_id = fields.Many2one( + "res.partner", "Owner", help="This is the owner of the inventory adjustment" + ) + + location_ids = fields.Many2many( + "stock.location", string="Locations", domain="[('usage', '=', 'internal')]" + ) + + product_selection = fields.Selection( + [ + ("all", "All Products"), + ("manual", "Manual Selection"), + ("category", "Product Category"), + ("one", "One Product"), + ("lot", "Lot/Serial Number"), + ], + default="all", + required=True, + ) + + product_ids = fields.Many2many("product.product", string="Products") + + stock_quant_ids = fields.Many2many("stock.quant", string="Inventory Adjustment") + + category_id = fields.Many2one("product.category", string="Product Category") + + lot_ids = fields.Many2many( + "stock.production.lot", + string="Lot/Serial Numbers", + ) + + stock_move_ids = fields.One2many( + "stock.move.line", + "inventory_adjustment_id", + string="Inventory Adjustments Done", + ) + + count_stock_quants = fields.Integer( + compute="_compute_count_stock_quants", string="Adjustments" + ) + + count_stock_quants_string = fields.Char( + compute="_compute_count_stock_quants", string="Adjustments" + ) + + count_stock_moves = fields.Integer( + compute="_compute_count_stock_moves", string="Stock Moves Lines" + ) + + @api.depends("stock_quant_ids") + def _compute_count_stock_quants(self): + self.count_stock_quants = len(self.stock_quant_ids) + count_todo = len( + self.stock_quant_ids.search( + [("id", "in", self.stock_quant_ids.ids), ("to_do", "=", "True")] + ) + ) + self.count_stock_quants_string = "{} / {}".format( + count_todo, self.count_stock_quants + ) + + @api.depends("stock_move_ids") + def _compute_count_stock_moves(self): + sm_ids = self.mapped("stock_move_ids").ids + self.count_stock_moves = len(sm_ids) + + def _get_quants(self, locations): + domain = [] + base_domain = self._get_base_domain(locations) + if self.product_selection == "all": + domain = self._get_domain_all_quants(base_domain) + elif self.product_selection == "manual": + domain = self._get_domain_manual_quants(base_domain) + elif self.product_selection == "one": + domain = self._get_domain_one_quant(base_domain) + elif self.product_selection == "lot": + domain = self._get_domain_lot_quants(base_domain) + elif self.product_selection == "category": + domain = self._get_domain_category_quants(base_domain) + return self.env["stock.quant"].search(domain) + + def _get_base_domain(self, locations): + return [ + "|", + ("location_id", "in", locations.mapped("id")), + ("location_id", "in", locations.child_ids.ids), + ] + + def _get_domain_all_quants(self, base_domain): + return base_domain + + def _get_domain_manual_quants(self, base_domain): + return expression.AND( + [base_domain, [("product_id", "in", self.product_ids.ids)]] + ) + + def _get_domain_one_quant(self, base_domain): + return expression.AND( + [ + base_domain, + [ + ("product_id", "in", self.product_ids.ids), + ], + ] + ) + + def _get_domain_lot_quants(self, base_domain): + return expression.AND( + [ + base_domain, + [ + ("product_id", "in", self.product_ids.ids), + ("lot_id", "in", self.lot_ids.ids), + ], + ] + ) + + def _get_domain_category_quants(self, base_domain): + return expression.AND( + [ + base_domain, + [ + "|", + ("product_id.categ_id", "=", self.category_id.id), + ("product_id.categ_id", "in", self.category_id.child_id.ids), + ], + ] + ) + + def action_state_to_in_progress(self): + active_rec = self.env["stock.inventory"].search( + [ + ("state", "=", "in_progress"), + "|", + ("location_ids", "in", self.location_ids.mapped("id")), + ("location_ids", "in", self.location_ids.child_ids.ids), + ], + limit=1, + ) + if active_rec: + raise ValidationError( + _( + "There's already an Adjustment in Process using one requested Location: %s" + ) + % active_rec.name + ) + self.state = "in_progress" + self.stock_quant_ids = self._get_quants(self.location_ids) + self.stock_quant_ids.update({"to_do": True}) + return + + def action_state_to_done(self): + self.state = "done" + self.stock_quant_ids.update({"to_do": True}) + return + + def action_state_to_draft(self): + self.state = "draft" + self.stock_quant_ids.update({"to_do": True}) + self.stock_quant_ids = None + return + + def action_view_inventory_adjustment(self): + result = self.env["stock.quant"].action_view_inventory() + ia_ids = self.mapped("stock_quant_ids").ids + result["domain"] = [("id", "in", ia_ids)] + result["search_view_id"] = self.env.ref("stock.quant_search_view").id + result["context"]["search_default_to_do"] = 1 + return result + + def action_view_stock_moves(self): + result = self.env["ir.actions.act_window"]._for_xml_id( + "stock_inventory.action_view_stock_move_line_inventory_tree" + ) + sm_ids = self.mapped("stock_move_ids").ids + result["domain"] = [("id", "in", sm_ids)] + result["context"] = [] + return result + + @api.constrains("product_selection", "product_ids") + def _check_one_product_in_product_selection(self): + for rec in self: + if len(rec.product_ids) > 1: + if rec.product_selection == "one": + raise ValidationError( + _( + "When 'Product Selection: One Product' is selected" + " you are only able to add one product." + ) + ) + elif rec.product_selection == "lot": + raise ValidationError( + _( + "When 'Product Selection: Lot Serial Number' is selected" + " you are only able to add one product." + ) + ) diff --git a/stock_inventory/models/stock_move_line.py b/stock_inventory/models/stock_move_line.py new file mode 100644 index 000000000000..9acebd9e526c --- /dev/null +++ b/stock_inventory/models/stock_move_line.py @@ -0,0 +1,7 @@ +from odoo import fields, models + + +class StockMoveLine(models.Model): + _inherit = "stock.move.line" + + inventory_adjustment_id = fields.Many2one("stock.inventory") diff --git a/stock_inventory/models/stock_quant.py b/stock_inventory/models/stock_quant.py new file mode 100644 index 000000000000..b53d7d8a1525 --- /dev/null +++ b/stock_inventory/models/stock_quant.py @@ -0,0 +1,36 @@ +from odoo import fields, models + + +class StockQuant(models.Model): + _inherit = "stock.quant" + + to_do = fields.Boolean(default=True) + + def _apply_inventory(self): + res = super()._apply_inventory() + record_moves = self.env["stock.move.line"] + for rec in self: + adjustment = ( + self.env["stock.inventory"] + .search([("state", "=", "in_progress")]) + .filtered( + lambda x: rec.location_id in x.location_ids + or rec.location_id in x.location_ids.child_ids + ) + ) + moves = record_moves.search( + [ + ("product_id", "=", rec.product_id.id), + ("lot_id", "=", rec.lot_id.id), + ("company_id", "=", rec.company_id.id), + "|", + ("location_id", "=", rec.location_id.id), + ("location_dest_id", "=", rec.location_id.id), + ], + order="create_date asc", + ) + move = moves[len(moves) - 1] + adjustment.stock_move_ids |= move + move.inventory_adjustment_id = adjustment + rec.to_do = False + return res diff --git a/stock_inventory/readme/CONTRIBUTORS.rst b/stock_inventory/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000000..8dd66508f510 --- /dev/null +++ b/stock_inventory/readme/CONTRIBUTORS.rst @@ -0,0 +1,4 @@ +* `ForgeFlow `_: + + * David Jiménez + * Guillem Casassas diff --git a/stock_inventory/readme/DESCRIPTION.rst b/stock_inventory/readme/DESCRIPTION.rst new file mode 100644 index 000000000000..ca91fe8f2dd0 --- /dev/null +++ b/stock_inventory/readme/DESCRIPTION.rst @@ -0,0 +1 @@ +This module allows to group Inventory Adjustments and have a group traceability (like before Odoo 15.0). diff --git a/stock_inventory/readme/USAGE.rst b/stock_inventory/readme/USAGE.rst new file mode 100644 index 000000000000..fc0e36c07ff9 --- /dev/null +++ b/stock_inventory/readme/USAGE.rst @@ -0,0 +1,9 @@ +Go to Inventory / Operations / Inventory Adjustments. Here you can see the list of Adjustment Grouped. +If you create a new Group, you can choose 2 types of product selection: +- All Products (all products from theselected locations). +- Manual Selection (choose manually each product in location). +- One Product (choose only one product in locations). +- Lot Serial Number (choose one product, any lots and locations). +- Product Category (choose one product category [childs also taken into account]). +When you start the adjustment (only one at a time) clicking on adjustments gets you to the view where adjustments are made. +From the group view, if you click on Stock Moves you can see the movements done (includes the 0 qty moves). diff --git a/stock_inventory/security/ir.model.access.csv b/stock_inventory/security/ir.model.access.csv new file mode 100644 index 000000000000..0dd1ae475bd3 --- /dev/null +++ b/stock_inventory/security/ir.model.access.csv @@ -0,0 +1,3 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_stock_inventory_user,stock.inventory,model_stock_inventory,base.group_user,1,0,0,0 +access_stock_inventory_manager,stock.inventory,model_stock_inventory,base.group_system,1,1,1,1 diff --git a/stock_inventory/tests/__init__.py b/stock_inventory/tests/__init__.py new file mode 100644 index 000000000000..64feb514fcd7 --- /dev/null +++ b/stock_inventory/tests/__init__.py @@ -0,0 +1 @@ +from . import test_stock_inventory diff --git a/stock_inventory/tests/test_stock_inventory.py b/stock_inventory/tests/test_stock_inventory.py new file mode 100644 index 000000000000..b02070a3c00e --- /dev/null +++ b/stock_inventory/tests/test_stock_inventory.py @@ -0,0 +1,314 @@ +# Copyright 2022 ForgeFlow S.L +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html + +from odoo.exceptions import ValidationError +from odoo.tests.common import TransactionCase + + +class TestStockInventory(TransactionCase): + def setUp(self): + super(TestStockInventory, self).setUp() + self.quant_model = self.env["stock.quant"] + self.move_model = self.env["stock.move.line"] + self.inventory_model = self.env["stock.inventory"] + self.location_model = self.env["stock.location"] + self.product_categ = self.env["product.category"].create({"name": "Test Categ"}) + self.product = self.env["product.product"].create( + { + "name": "Product 1 test", + "type": "product", + "tracking": "lot", + } + ) + self.product2 = self.env["product.product"].create( + { + "name": "Product 1 test", + "type": "product", + "categ_id": self.product_categ.id, + } + ) + self.lot_1 = self.env["stock.production.lot"].create( + { + "product_id": self.product.id, + "name": "Lot 1", + "company_id": self.env.company.id, + } + ) + self.lot_2 = self.env["stock.production.lot"].create( + { + "product_id": self.product.id, + "name": "Lot 2", + "company_id": self.env.company.id, + } + ) + self.lot_3 = self.env["stock.production.lot"].create( + { + "product_id": self.product.id, + "name": "Lot 3", + "company_id": self.env.company.id, + } + ) + self.location_src = self.env.ref("stock.stock_location_locations_virtual") + self.location_dst = self.env.ref("stock.stock_location_customers") + + self.location1 = self.location_model.create( + { + "name": "Location 1", + "usage": "internal", + "warehouse_id": self.location_src.id, + } + ) + self.location2 = self.location_model.create( + { + "name": "Location 2", + "usage": "internal", + "location_id": self.location_src.id, + } + ) + self.location3 = self.location_model.create( + { + "name": "Location 3", + "usage": "internal", + "location_id": self.location1.id, + } + ) + self.quant1 = self.quant_model.sudo().create( + { + "product_id": self.product.id, + "lot_id": self.lot_1.id, + "quantity": 100.0, + "location_id": self.location1.id, + } + ) + self.quant2 = self.quant_model.sudo().create( + { + "product_id": self.product.id, + "lot_id": self.lot_2.id, + "quantity": 100.0, + "location_id": self.location2.id, + } + ) + self.quant3 = self.quant_model.sudo().create( + { + "product_id": self.product.id, + "lot_id": self.lot_3.id, + "quantity": 100.0, + "location_id": self.location3.id, + } + ) + self.quant4 = self.quant_model.sudo().create( + { + "product_id": self.product2.id, + "quantity": 100.0, + "location_id": self.location3.id, + } + ) + + def test_01_all_locations(self): + inventory1 = self.inventory_model.create( + { + "name": "Inventory_Test_1", + "product_selection": "all", + "location_ids": [self.location1.id], + } + ) + inventory1.action_state_to_in_progress() + inventory2 = self.inventory_model.create( + { + "name": "Inventory_Test_2", + "product_selection": "all", + "location_ids": [self.location1.id], + } + ) + with self.assertRaises(ValidationError), self.cr.savepoint(): + inventory2.action_state_to_in_progress() + self.assertEqual(inventory1.state, "in_progress") + self.assertEqual( + inventory1.stock_quant_ids.ids, + [self.quant1.id, self.quant3.id, self.quant4.id], + ) + inventory1.action_state_to_draft() + self.assertEqual(inventory1.stock_quant_ids.ids, []) + inventory1.action_state_to_in_progress() + self.assertEqual(inventory1.count_stock_moves, 0) + self.assertEqual(inventory1.count_stock_quants, 3) + self.assertEqual(inventory1.count_stock_quants_string, "3 / 3") + inventory1.action_view_inventory_adjustment() + self.quant1.inventory_quantity = 92 + self.quant1.action_apply_inventory() + inventory1._compute_count_stock_quants() + inventory1.action_view_stock_moves() + self.assertEqual(inventory1.count_stock_moves, 1) + self.assertEqual(inventory1.count_stock_quants, 3) + self.assertEqual(inventory1.count_stock_quants_string, "2 / 3") + self.assertEqual(inventory1.stock_move_ids.qty_done, 8) + self.assertEqual(inventory1.stock_move_ids.product_id.id, self.product.id) + self.assertEqual(inventory1.stock_move_ids.lot_id.id, self.lot_1.id) + self.assertEqual(inventory1.stock_move_ids.location_id.id, self.location1.id) + inventory1.action_state_to_done() + + def test_02_manual_selection(self): + inventory1 = self.inventory_model.create( + { + "name": "Inventory_Test_3", + "product_selection": "manual", + "location_ids": [self.location1.id], + "product_ids": [self.product.id], + } + ) + inventory1.action_state_to_in_progress() + self.assertEqual(inventory1.state, "in_progress") + self.assertEqual( + inventory1.stock_quant_ids.ids, [self.quant1.id, self.quant3.id] + ) + inventory1.action_state_to_draft() + self.assertEqual(inventory1.stock_quant_ids.ids, []) + inventory1.action_state_to_in_progress() + self.assertEqual(inventory1.state, "in_progress") + self.assertEqual(inventory1.count_stock_moves, 0) + self.assertEqual(inventory1.count_stock_quants, 2) + self.assertEqual(inventory1.count_stock_quants_string, "2 / 2") + inventory1.action_view_inventory_adjustment() + self.quant3.inventory_quantity = 74 + self.quant3.action_apply_inventory() + inventory1._compute_count_stock_quants() + inventory1.action_view_stock_moves() + self.assertEqual(inventory1.count_stock_moves, 1) + self.assertEqual(inventory1.count_stock_quants, 2) + self.assertEqual(inventory1.count_stock_quants_string, "1 / 2") + self.assertEqual(inventory1.stock_move_ids.qty_done, 26) + self.assertEqual(inventory1.stock_move_ids.product_id.id, self.product.id) + self.assertEqual(inventory1.stock_move_ids.lot_id.id, self.lot_3.id) + self.assertEqual(inventory1.stock_move_ids.location_id.id, self.location3.id) + self.quant1.inventory_quantity = 65 + self.quant1.action_apply_inventory() + inventory1._compute_count_stock_quants() + self.assertEqual(inventory1.count_stock_moves, 2) + self.assertEqual(inventory1.count_stock_quants, 2) + self.assertEqual(inventory1.count_stock_quants_string, "0 / 2") + inventory1.action_state_to_done() + + def test_03_one_selection(self): + with self.assertRaises(ValidationError), self.cr.savepoint(): + inventory1 = self.inventory_model.create( + { + "name": "Inventory_Test_5", + "product_selection": "one", + "location_ids": [self.location1.id], + "product_ids": [self.product.id, self.product2.id], + } + ) + inventory1 = self.inventory_model.create( + { + "name": "Inventory_Test_5", + "product_selection": "one", + "location_ids": [self.location1.id], + "product_ids": [self.product.id], + } + ) + inventory1.action_state_to_in_progress() + inventory1.product_ids = [self.product.id] + self.assertEqual( + inventory1.stock_quant_ids.ids, [self.quant1.id, self.quant3.id] + ) + inventory1.action_state_to_draft() + self.assertEqual(inventory1.stock_quant_ids.ids, []) + inventory1.action_state_to_in_progress() + self.assertEqual(inventory1.state, "in_progress") + self.assertEqual(inventory1.count_stock_moves, 0) + self.assertEqual(inventory1.count_stock_quants, 2) + self.assertEqual(inventory1.count_stock_quants_string, "2 / 2") + inventory1.action_view_inventory_adjustment() + self.quant3.inventory_quantity = 74 + self.quant3.action_apply_inventory() + inventory1._compute_count_stock_quants() + inventory1.action_view_stock_moves() + self.assertEqual(inventory1.count_stock_moves, 1) + self.assertEqual(inventory1.count_stock_quants, 2) + self.assertEqual(inventory1.count_stock_quants_string, "1 / 2") + self.assertEqual(inventory1.stock_move_ids.qty_done, 26) + self.assertEqual(inventory1.stock_move_ids.product_id.id, self.product.id) + self.assertEqual(inventory1.stock_move_ids.lot_id.id, self.lot_3.id) + self.assertEqual(inventory1.stock_move_ids.location_id.id, self.location3.id) + self.quant1.inventory_quantity = 65 + self.quant1.action_apply_inventory() + inventory1._compute_count_stock_quants() + self.assertEqual(inventory1.count_stock_moves, 2) + self.assertEqual(inventory1.count_stock_quants, 2) + self.assertEqual(inventory1.count_stock_quants_string, "0 / 2") + inventory1.action_state_to_done() + + def test_04_lot_selection(self): + with self.assertRaises(ValidationError), self.cr.savepoint(): + inventory1 = self.inventory_model.create( + { + "name": "Inventory_Test_6", + "product_selection": "lot", + "location_ids": [self.location1.id], + "lot_ids": [self.lot_3.id], + "product_ids": [self.product.id, self.product2.id], + } + ) + inventory1 = self.inventory_model.create( + { + "name": "Inventory_Test_6", + "product_selection": "lot", + "location_ids": [self.location1.id], + "lot_ids": [self.lot_3.id], + "product_ids": [self.product.id], + } + ) + inventory1.product_ids = [self.product.id] + inventory1.action_state_to_in_progress() + self.assertEqual(inventory1.stock_quant_ids.ids, [self.quant3.id]) + inventory1.action_state_to_draft() + self.assertEqual(inventory1.stock_quant_ids.ids, []) + inventory1.action_state_to_in_progress() + self.assertEqual(inventory1.state, "in_progress") + self.assertEqual(inventory1.count_stock_moves, 0) + self.assertEqual(inventory1.count_stock_quants, 1) + self.assertEqual(inventory1.count_stock_quants_string, "1 / 1") + inventory1.action_view_inventory_adjustment() + self.quant3.inventory_quantity = 74 + self.quant3.action_apply_inventory() + inventory1._compute_count_stock_quants() + inventory1.action_view_stock_moves() + self.assertEqual(inventory1.count_stock_moves, 1) + self.assertEqual(inventory1.count_stock_quants, 1) + self.assertEqual(inventory1.count_stock_quants_string, "0 / 1") + self.assertEqual(inventory1.stock_move_ids.qty_done, 26) + self.assertEqual(inventory1.stock_move_ids.product_id.id, self.product.id) + self.assertEqual(inventory1.stock_move_ids.lot_id.id, self.lot_3.id) + self.assertEqual(inventory1.stock_move_ids.location_id.id, self.location3.id) + inventory1.action_state_to_done() + + def test_05_category_selection(self): + inventory1 = self.inventory_model.create( + { + "name": "Inventory_Test_7", + "product_selection": "category", + "location_ids": [self.location3.id], + "category_id": self.product_categ.id, + } + ) + inventory1.action_state_to_in_progress() + self.assertEqual(inventory1.stock_quant_ids.ids, [self.quant4.id]) + inventory1.action_state_to_draft() + self.assertEqual(inventory1.stock_quant_ids.ids, []) + inventory1.action_state_to_in_progress() + self.assertEqual(inventory1.state, "in_progress") + self.assertEqual(inventory1.count_stock_moves, 0) + self.assertEqual(inventory1.count_stock_quants, 1) + self.assertEqual(inventory1.count_stock_quants_string, "1 / 1") + inventory1.action_view_inventory_adjustment() + self.quant4.inventory_quantity = 74 + self.quant4.action_apply_inventory() + inventory1._compute_count_stock_quants() + inventory1.action_view_stock_moves() + self.assertEqual(inventory1.count_stock_moves, 1) + self.assertEqual(inventory1.count_stock_quants, 1) + self.assertEqual(inventory1.count_stock_quants_string, "0 / 1") + self.assertEqual(inventory1.stock_move_ids.qty_done, 26) + self.assertEqual(inventory1.stock_move_ids.product_id.id, self.product2.id) + self.assertEqual(inventory1.stock_move_ids.location_id.id, self.location3.id) + inventory1.action_state_to_done() diff --git a/stock_inventory/views/stock_inventory.xml b/stock_inventory/views/stock_inventory.xml new file mode 100644 index 000000000000..8093595039a4 --- /dev/null +++ b/stock_inventory/views/stock_inventory.xml @@ -0,0 +1,154 @@ + + + + stock.inventory.form.view + stock.inventory + 1000 + +
+
+
+ + +
+ + +
+
+
+ + + + + + + + + + + + + + +
+
+
+
+ + + stock.inventory.tree.view + stock.inventory + 1000 + + + + + + + + + + + Inventory Adjustment Group + stock.inventory + tree,form + + + + + +
diff --git a/stock_inventory/views/stock_move_line.xml b/stock_inventory/views/stock_move_line.xml new file mode 100644 index 000000000000..10961216f5e0 --- /dev/null +++ b/stock_inventory/views/stock_move_line.xml @@ -0,0 +1,29 @@ + + + stock.move.line.tree.view.inventory + stock.move.line + 1000 + + + + + + + + + + + + + + + + Stock Move Lines + stock.move.line + tree,form + + + diff --git a/stock_inventory/views/stock_quant.xml b/stock_inventory/views/stock_quant.xml new file mode 100644 index 000000000000..efa28e8875b0 --- /dev/null +++ b/stock_inventory/views/stock_quant.xml @@ -0,0 +1,16 @@ + + + stock.quant.search.not.done + stock.quant + + + + + + + +