forked from OCA/stock-logistics-warehouse
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[9.0][ADD] stock_inventory_exclude_sublocation (OCA#240)
* [ADD] stock_inventory_exclude_sublocation
- Loading branch information
1 parent
4332760
commit 3feb141
Showing
8 changed files
with
367 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg | ||
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html | ||
:alt: License: AGPL-3 | ||
|
||
=================================== | ||
Stock Inventory Exclude Sublocation | ||
=================================== | ||
|
||
This module extends the functionality of Inventory Adjustment to allow you to | ||
exclude all the sublocations when doing an inventory adjustment for a | ||
given location. | ||
|
||
Sometimes we just want to make an inventory adjustment of just one shelf, or | ||
space and forget about extra subdivisions in the location. In other cases we | ||
do inventories of smaller locations contained in our stock, so we don't want | ||
to count them again when doing an inventory adjustment of the parent location. | ||
E.g. if we apply a cycle count strategy. | ||
|
||
|
||
Usage | ||
===== | ||
|
||
To use this module, you simply need to: | ||
|
||
#. Create a new inventory adjustment. | ||
#. Select the option inventory of all products. | ||
#. Check the box "Exclude Sublocations". | ||
|
||
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas | ||
:alt: Try me on Runbot | ||
:target: https://runbot.odoo-community.org/runbot/153/9.0 | ||
|
||
|
||
Bug Tracker | ||
=========== | ||
|
||
Bugs are tracked on `GitHub Issues | ||
<https://github.com/OCA/{project_repo}/issues>`_. In case of trouble, please | ||
check there if your issue has already been reported. If you spotted it first, | ||
help us smash it by providing detailed and welcomed feedback. | ||
|
||
Credits | ||
======= | ||
|
||
Images | ||
------ | ||
|
||
* Odoo Community Association: `Icon <https://github.com/OCA/maintainer-tools/blob/master/template/module/static/description/icon.svg>`_. | ||
|
||
Contributors | ||
------------ | ||
|
||
* Lois Rilo Antelo <[email protected]> | ||
|
||
|
||
Maintainer | ||
---------- | ||
|
||
.. image:: https://odoo-community.org/logo.png | ||
:alt: Odoo Community Association | ||
:target: https://odoo-community.org | ||
|
||
This module is maintained by the OCA. | ||
|
||
OCA, or the Odoo Community Association, is a nonprofit organization whose | ||
mission is to support the collaborative development of Odoo features and | ||
promote its widespread use. | ||
|
||
To contribute to this module, please visit https://odoo-community.org. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
# -*- coding: utf-8 -*- | ||
# Copyright 2017 Eficent Business and IT Consulting Services S.L. | ||
# (http://www.eficent.com) | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). | ||
|
||
from . import models | ||
from . import tests |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# -*- coding: utf-8 -*- | ||
# Copyright 2017 Eficent Business and IT Consulting Services S.L. | ||
# (http://www.eficent.com) | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). | ||
{ | ||
"name": "Stock Inventory Exclude Sublocation", | ||
"summary": "Allow to perform inventories of a location without including " | ||
"its child locations.", | ||
"version": "9.0.1.0.0", | ||
"author": "Eficent," | ||
"Odoo Community Association (OCA)", | ||
"website": "https://github.com/OCA/stock-logistics-warehouse", | ||
"category": "Warehouse Management", | ||
"depends": ["stock"], | ||
"data": [ | ||
'views/stock_inventory_view.xml' | ||
], | ||
"license": "AGPL-3", | ||
'installable': True, | ||
'application': False, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
# -*- coding: utf-8 -*- | ||
# Copyright 2017 Eficent Business and IT Consulting Services S.L. | ||
# (http://www.eficent.com) | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). | ||
|
||
from . import stock_inventory |
53 changes: 53 additions & 0 deletions
53
stock_inventory_exclude_sublocation/models/stock_inventory.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
# -*- coding: utf-8 -*- | ||
# Copyright 2017 Eficent Business and IT Consulting Services S.L. | ||
# (http://www.eficent.com) | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). | ||
|
||
from openerp import fields, models, api | ||
|
||
|
||
class StockInventory(models.Model): | ||
_inherit = 'stock.inventory' | ||
|
||
exclude_sublocation = fields.Boolean(string='Exclude Sublocations', | ||
default=False) | ||
|
||
@api.model | ||
def _get_inventory_lines(self, inventory): | ||
if inventory.exclude_sublocation: | ||
product_obj = self.env['product.product'] | ||
domain = ' location_id = %s' | ||
args = (tuple(inventory.location_id.ids)) | ||
if inventory.partner_id: | ||
domain += ' and owner_id = %s' | ||
args += (inventory.partner_id.id,) | ||
if inventory.lot_id: | ||
domain += ' and lot_id = %s' | ||
args += (inventory.lot_id.id,) | ||
if inventory.product_id: | ||
domain += ' and product_id = %s' | ||
args += (inventory.product_id.id,) | ||
if inventory.package_id: | ||
domain += ' and package_id = %s' | ||
args += (inventory.package_id.id,) | ||
|
||
self.env.cr.execute(''' | ||
SELECT product_id, sum(qty) as product_qty, location_id, lot_id | ||
as prod_lot_id, package_id, owner_id as partner_id | ||
FROM stock_quant WHERE''' + domain + ''' | ||
GROUP BY product_id, location_id, lot_id, package_id, partner_id | ||
''', args) | ||
vals = [] | ||
for product_line in self.env.cr.dictfetchall(): | ||
for key, value in product_line.items(): | ||
if not value: | ||
product_line[key] = False | ||
product_line['inventory_id'] = inventory.id | ||
product_line['theoretical_qty'] = product_line['product_qty'] | ||
if product_line['product_id']: | ||
product = product_obj.browse(product_line['product_id']) | ||
product_line['product_uom_id'] = product.uom_id.id | ||
vals.append(product_line) | ||
return vals | ||
else: | ||
return super(StockInventory, self)._get_inventory_lines(inventory) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
# -*- coding: utf-8 -*- | ||
# Copyright 2017 Eficent Business and IT Consulting Services S.L. | ||
# (http://www.eficent.com) | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). | ||
|
||
from . import test_exclude_sublocation |
187 changes: 187 additions & 0 deletions
187
stock_inventory_exclude_sublocation/tests/test_exclude_sublocation.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,187 @@ | ||
# -*- coding: utf-8 -*- | ||
# Copyright 2017 Eficent Business and IT Consulting Services S.L. | ||
# (http://www.eficent.com) | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). | ||
|
||
import openerp.tests.common as common | ||
|
||
|
||
class TestStockInventoryExcludeSublocation(common.TransactionCase): | ||
|
||
def setUp(self): | ||
super(TestStockInventoryExcludeSublocation, self).setUp() | ||
self.inventory_model = self.env['stock.inventory'] | ||
self.location_model = self.env['stock.location'] | ||
self.lot_model = self.env['stock.production.lot'] | ||
self.quant_model = self.env['stock.quant'] | ||
self.package_model = self.env['stock.quant.package'] | ||
self.res_users_model = self.env['res.users'] | ||
|
||
self.company = self.env.ref('base.main_company') | ||
self.partner = self.ref('base.res_partner_4') | ||
self.grp_stock_manager = self.env.ref('stock.group_stock_manager') | ||
self.grp_tracking_owner = self.env.ref('stock.group_tracking_owner') | ||
self.grp_production_lot = self.env.ref('stock.group_production_lot') | ||
self.grp_tracking_lot = self.env.ref('stock.group_tracking_lot') | ||
|
||
self.user = self.res_users_model.create({ | ||
'name': 'Test Account User', | ||
'login': 'user_1', | ||
'password': 'demo', | ||
'email': '[email protected]', | ||
'company_id': self.company.id, | ||
'company_ids': [(4, self.company.id)], | ||
'groups_id': [(6, 0, [ | ||
self.grp_stock_manager.id, | ||
self.grp_tracking_owner.id, | ||
self.grp_production_lot.id, | ||
self.grp_tracking_lot.id | ||
])] | ||
}) | ||
|
||
self.product1 = self.env['product.product'].create({ | ||
'name': 'Product for parent location', | ||
'type': 'product', | ||
'default_code': 'PROD1', | ||
}) | ||
self.product2 = self.env['product.product'].create({ | ||
'name': 'Product for child location', | ||
'type': 'product', | ||
'default_code': 'PROD2', | ||
}) | ||
self.location = self.location_model.create({ | ||
'name': 'Inventory tests', | ||
'usage': 'internal', | ||
}) | ||
self.sublocation = self.location_model.create({ | ||
'name': 'Inventory sublocation test', | ||
'usage': 'internal', | ||
'location_id': self.location.id | ||
}) | ||
self.lot_a = self.lot_model.create({ | ||
'name': 'Lot for product1', | ||
'product_id': self.product1.id | ||
}) | ||
self.package = self.package_model.create({'name': 'PACK00TEST1'}) | ||
|
||
# Add a product in each location | ||
starting_inv = self.inventory_model.create({ | ||
'name': 'Starting inventory', | ||
'filter': 'product', | ||
'line_ids': [ | ||
(0, 0, { | ||
'product_id': self.product1.id, | ||
'product_uom_id': self.env.ref( | ||
"product.product_uom_unit").id, | ||
'product_qty': 2.0, | ||
'location_id': self.location.id, | ||
'prod_lot_id': self.lot_a.id | ||
}), | ||
(0, 0, { | ||
'product_id': self.product2.id, | ||
'product_uom_id': self.env.ref( | ||
"product.product_uom_unit").id, | ||
'product_qty': 4.0, | ||
'location_id': self.sublocation.id, | ||
'prod_lot_id': self.lot_a.id | ||
}), | ||
], | ||
}) | ||
starting_inv.action_done() | ||
|
||
def _create_inventory_all_products(self, name, location, | ||
exclude_sublocation): | ||
inventory = self.inventory_model.create({ | ||
'name': name, | ||
'filter': 'none', | ||
'location_id': location.id, | ||
'exclude_sublocation': exclude_sublocation | ||
}) | ||
return inventory | ||
|
||
def test_not_excluding_sublocations(self): | ||
'''Check if products in sublocations are included into the inventory | ||
if the excluding sublocations option is disabled.''' | ||
inventory_location = self._create_inventory_all_products( | ||
'location inventory', self.location, False) | ||
inventory_location.prepare_inventory() | ||
inventory_location.action_done() | ||
lines = inventory_location.line_ids | ||
self.assertEqual(len(lines), 2, 'Not all expected products are ' | ||
'included') | ||
|
||
def test_excluding_sublocations(self): | ||
'''Check if products in sublocations are not included if the exclude | ||
sublocations is enabled.''' | ||
inventory_location = self._create_inventory_all_products( | ||
'location inventory', self.location, True) | ||
inventory_sublocation = self._create_inventory_all_products( | ||
'sublocation inventory', self.sublocation, True) | ||
inventory_location.prepare_inventory() | ||
inventory_location.action_done() | ||
inventory_sublocation.prepare_inventory() | ||
inventory_sublocation.action_done() | ||
lines_location = inventory_location.line_ids | ||
lines_sublocation = inventory_sublocation.line_ids | ||
self.assertEqual(len(lines_location), 1, | ||
'The products in the sublocations are not excluded') | ||
self.assertEqual(len(lines_sublocation), 1, | ||
'The products in the sublocations are not excluded') | ||
|
||
def test_lot_excluding_sublocation(self): | ||
'''Check if the sublocations are excluded when using lots.''' | ||
inventory = self.inventory_model.sudo(self.user.id).create({ | ||
'name': 'Inventory lot', | ||
'filter': 'lot', | ||
'location_id': self.location.id, | ||
'lot_id': self.lot_a.id, | ||
'exclude_sublocation': True | ||
}) | ||
inventory.prepare_inventory() | ||
inventory.action_done() | ||
lines = inventory.line_ids | ||
self.assertEqual(len(lines), 1, 'The products in the sublocations are ' | ||
'not excluded with lots.') | ||
|
||
def test_product_and_owner_excluding_sublocation(self): | ||
'''Check if sublocations are excluded when filtering by owner and | ||
product.''' | ||
self.quant_model.create({ | ||
'product_id': self.product1.id, | ||
'location_id': self.location.id, | ||
'qty': 1, | ||
'owner_id': self.partner, | ||
}) | ||
inventory = self.inventory_model.sudo(self.user.id).create({ | ||
'name': 'Inventory lot', | ||
'filter': 'product_owner', | ||
'location_id': self.location.id, | ||
'product_id': self.product1.id, | ||
'partner_id': self.partner, | ||
'exclude_sublocation': True | ||
}) | ||
inventory.prepare_inventory() | ||
lines = inventory.line_ids | ||
self.assertEqual(len(lines), 1, | ||
'The products in the sublocations are ' | ||
'not excluded with product and owner filter.') | ||
|
||
def test_pack_excluding_sublocation(self): | ||
'''Check if sublocations are excluded when filtering by package.''' | ||
self.quant_model.create({ | ||
'product_id': self.product1.id, | ||
'location_id': self.location.id, | ||
'qty': 1, | ||
'package_id': self.package.id | ||
}) | ||
inventory = self.inventory_model.sudo(self.user.id).create({ | ||
'name': 'Inventory lot', | ||
'filter': 'pack', | ||
'location_id': self.location.id, | ||
'package_id': self.package.id, | ||
'exclude_sublocation': True | ||
}) | ||
inventory.prepare_inventory() | ||
lines = inventory.line_ids | ||
self.assertEqual(len(lines), 1, 'The products in the sublocations are ' | ||
'not excluded with package filter.') |
18 changes: 18 additions & 0 deletions
18
stock_inventory_exclude_sublocation/views/stock_inventory_view.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<!-- Copyright 2017 Eficent Business and IT Consulting Services S.L. | ||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). --> | ||
|
||
<odoo> | ||
|
||
<record id="view_inventory_form" model="ir.ui.view"> | ||
<field name="name">Inventory form view - cycle count extension </field> | ||
<field name="model">stock.inventory</field> | ||
<field name="inherit_id" ref="stock.view_inventory_form"/> | ||
<field name="arch" type="xml"> | ||
<field name="filter" position="after"> | ||
<field name="exclude_sublocation"/> | ||
</field> | ||
</field> | ||
</record> | ||
|
||
</odoo> |