mirror of
https://github.com/OCA/stock-logistics-warehouse.git
synced 2025-01-21 14:27:28 +02:00
[MIG] stock_inventory_preparation_filter: Migration to v13.0
This commit is contained in:
committed by
Ivàn Todorovich
parent
29a598a5db
commit
86ca74629e
@@ -14,39 +14,42 @@ Extended Inventory Preparation Filters
|
||||
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
|
||||
:alt: License: AGPL-3
|
||||
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fstock--logistics--warehouse-lightgray.png?logo=github
|
||||
:target: https://github.com/OCA/stock-logistics-warehouse/tree/12.0/stock_inventory_preparation_filter
|
||||
:target: https://github.com/OCA/stock-logistics-warehouse/tree/13.0/stock_inventory_preparation_filter
|
||||
:alt: OCA/stock-logistics-warehouse
|
||||
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
|
||||
:target: https://translation.odoo-community.org/projects/stock-logistics-warehouse-12-0/stock-logistics-warehouse-12-0-stock_inventory_preparation_filter
|
||||
:target: https://translation.odoo-community.org/projects/stock-logistics-warehouse-13-0/stock-logistics-warehouse-13-0-stock_inventory_preparation_filter
|
||||
:alt: Translate me on Weblate
|
||||
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png
|
||||
:target: https://runbot.odoo-community.org/runbot/153/12.0
|
||||
:target: https://runbot.odoo-community.org/runbot/153/13.0
|
||||
:alt: Try me on Runbot
|
||||
|
||||
|badge1| |badge2| |badge3| |badge4| |badge5|
|
||||
|
||||
Includes more options for making an inventory out of:
|
||||
|
||||
* Multiple products.
|
||||
* Products filtered by a domain.
|
||||
* Products of a category.
|
||||
* Multiple lots
|
||||
|
||||
It also allows to make an inventory based on scanned products, adding a line
|
||||
with product code and quantity.
|
||||
|
||||
**Table of contents**
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
|
||||
Known issues / Roadmap
|
||||
======================
|
||||
|
||||
* The widget domain is not displayed correctly, but this issue is related to
|
||||
Odoo. To avoid this malfunction, use the keyboard arrows to properly work
|
||||
with the domain option.
|
||||
|
||||
Bug Tracker
|
||||
===========
|
||||
|
||||
Bugs are tracked on `GitHub Issues <https://github.com/OCA/stock-logistics-warehouse/issues>`_.
|
||||
In case of trouble, please check there if your issue has already been reported.
|
||||
If you spotted it first, help us smashing it by providing a detailed and welcomed
|
||||
`feedback <https://github.com/OCA/stock-logistics-warehouse/issues/new?body=module:%20stock_inventory_preparation_filter%0Aversion:%2012.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
|
||||
`feedback <https://github.com/OCA/stock-logistics-warehouse/issues/new?body=module:%20stock_inventory_preparation_filter%0Aversion:%2013.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
|
||||
|
||||
Do not contact contributors directly about support or help with technical issues.
|
||||
|
||||
@@ -67,6 +70,7 @@ Contributors
|
||||
|
||||
* Pedro M. Baeza
|
||||
* David Vidal
|
||||
* Sergio Teruel
|
||||
|
||||
* Xavier Jimenez <xavier.jimenez@qubiq.es>
|
||||
|
||||
@@ -83,6 +87,6 @@ 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.
|
||||
|
||||
This module is part of the `OCA/stock-logistics-warehouse <https://github.com/OCA/stock-logistics-warehouse/tree/12.0/stock_inventory_preparation_filter>`_ project on GitHub.
|
||||
This module is part of the `OCA/stock-logistics-warehouse <https://github.com/OCA/stock-logistics-warehouse/tree/13.0/stock_inventory_preparation_filter>`_ project on GitHub.
|
||||
|
||||
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
|
||||
|
||||
@@ -5,13 +5,13 @@
|
||||
|
||||
{
|
||||
"name": "Extended Inventory Preparation Filters",
|
||||
"version": "12.0.1.1.0",
|
||||
"version": "13.0.1.0.0",
|
||||
"depends": ["stock"],
|
||||
"author": "AvanzOSC," "Tecnativa," "Odoo Community Association (OCA)",
|
||||
"category": "Inventory, Logistic, Storage",
|
||||
"website": "http://github.com/OCA/stock-logistics-warehouse",
|
||||
"summary": "More filters for inventory adjustments",
|
||||
"data": ["views/stock_inventory_view.xml", "security/ir.model.access.csv"],
|
||||
"data": ["views/stock_inventory_view.xml"],
|
||||
"installable": True,
|
||||
"license": "AGPL-3",
|
||||
}
|
||||
|
||||
@@ -1,53 +1,40 @@
|
||||
# Copyright 2015 AvanzOSC - Oihane Crucelaegi
|
||||
# Copyright 2015 Tecnativa - Pedro M. Baeza
|
||||
# Copyright 2020 Sergio Teruel <sergio.teruel@tecnativa.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.tools.safe_eval import safe_eval
|
||||
|
||||
from odoo.addons import decimal_precision as dp
|
||||
|
||||
|
||||
class StockInventoryEmptyLines(models.Model):
|
||||
_name = "stock.inventory.line.empty"
|
||||
_description = "Inventory Line Empty"
|
||||
|
||||
product_code = fields.Char(string="Product Code", required=True)
|
||||
product_qty = fields.Float(
|
||||
string="Quantity",
|
||||
required=True,
|
||||
default=1.0,
|
||||
digits=dp.get_precision("Product Unit of Measure"),
|
||||
)
|
||||
inventory_id = fields.Many2one(
|
||||
comodel_name="stock.inventory",
|
||||
string="Inventory",
|
||||
required=True,
|
||||
ondelete="cascade",
|
||||
)
|
||||
|
||||
|
||||
class StockInventory(models.Model):
|
||||
_inherit = "stock.inventory"
|
||||
|
||||
@api.model
|
||||
def _selection_filter(self):
|
||||
"""This function will return the list of filters allowed according to
|
||||
the options checked in 'Settings/Warehouse'.
|
||||
|
||||
:return: list of tuple
|
||||
"""
|
||||
res_filters = super(StockInventory, self)._selection_filter()
|
||||
res_filters.append(("categories", _("Selected Categories")))
|
||||
res_filters.append(("products", _("Selected Products")))
|
||||
res_filters.append(("domain", _("Filtered Products")))
|
||||
for res_filter in res_filters:
|
||||
if res_filter[0] == "lot":
|
||||
res_filters.append(("lots", _("Selected Lots")))
|
||||
break
|
||||
res_filters.append(("empty", _("Empty list")))
|
||||
return res_filters
|
||||
""" Get the list of filter allowed according to the options checked
|
||||
in 'Settings / Warehouse'. """
|
||||
res_filter = [
|
||||
("products", _("All products")),
|
||||
("categories", _("Selected Categories")),
|
||||
("domain", _("Filtered Products")),
|
||||
]
|
||||
if self.user_has_groups("stock.group_production_lot"):
|
||||
res_filter.append(("lots", _("Selected Lots")))
|
||||
return res_filter
|
||||
|
||||
filter = fields.Selection(
|
||||
string="Inventory of",
|
||||
selection="_selection_filter",
|
||||
required=True,
|
||||
default="products",
|
||||
help="If you do an entire inventory, you can choose 'All Products' and "
|
||||
"it will prefill the inventory with the current stock. If you "
|
||||
"only do some products (e.g. Cycle Counting) you can choose "
|
||||
"'Manual Selection of Products' and the system won't propose "
|
||||
"anything. You can also let the system propose for a single "
|
||||
"product / lot /... ",
|
||||
)
|
||||
categ_ids = fields.Many2many(
|
||||
comodel_name="product.category",
|
||||
relation="rel_inventories_categories",
|
||||
@@ -55,13 +42,6 @@ class StockInventory(models.Model):
|
||||
column2="category_id",
|
||||
string="Categories",
|
||||
)
|
||||
product_ids = fields.Many2many(
|
||||
comodel_name="product.product",
|
||||
relation="rel_inventories_products",
|
||||
column1="inventory_id",
|
||||
column2="product_id",
|
||||
string="Products",
|
||||
)
|
||||
lot_ids = fields.Many2many(
|
||||
comodel_name="stock.production.lot",
|
||||
relation="rel_inventories_lots",
|
||||
@@ -69,75 +49,21 @@ class StockInventory(models.Model):
|
||||
column2="lot_id",
|
||||
string="Lots",
|
||||
)
|
||||
empty_line_ids = fields.One2many(
|
||||
comodel_name="stock.inventory.line.empty",
|
||||
inverse_name="inventory_id",
|
||||
string="Capture Lines",
|
||||
)
|
||||
product_domain = fields.Char("Domain", default=[("name", "ilike", "")])
|
||||
|
||||
@api.model
|
||||
def _get_inventory_lines_values(self):
|
||||
self.ensure_one()
|
||||
vals = []
|
||||
product_obj = self.env["product.product"]
|
||||
inventory = self.new(self._convert_to_write(self.read()[0]))
|
||||
if self.filter in ("categories", "products"):
|
||||
if self.filter == "categories":
|
||||
products = product_obj.search(
|
||||
[("product_tmpl_id.categ_id", "in", self.categ_ids.ids)]
|
||||
)
|
||||
else: # filter = 'products'
|
||||
products = self.product_ids
|
||||
inventory.filter = "product"
|
||||
for product in products:
|
||||
inventory.product_id = product
|
||||
vals += super(StockInventory, inventory)._get_inventory_lines_values()
|
||||
elif self.filter == "lots":
|
||||
inventory.filter = "lot"
|
||||
for lot in self.lot_ids:
|
||||
inventory.lot_id = lot
|
||||
vals += super(StockInventory, inventory)._get_inventory_lines_values()
|
||||
elif self.filter == "domain":
|
||||
domain = safe_eval(self.product_domain)
|
||||
products = self.env["product.product"].search(domain)
|
||||
inventory.filter = "product"
|
||||
for product in products:
|
||||
inventory.product_id = product
|
||||
vals += super(StockInventory, inventory)._get_inventory_lines_values()
|
||||
elif self.filter == "empty":
|
||||
tmp_lines = {}
|
||||
for line in self.empty_line_ids:
|
||||
tmp_lines.setdefault(line.product_code, 0)
|
||||
tmp_lines[line.product_code] += line.product_qty
|
||||
self.empty_line_ids.unlink()
|
||||
inventory.filter = "product"
|
||||
# HACK: Make sure location is preserved
|
||||
inventory.location_id = self.location_id
|
||||
for product_code in tmp_lines.keys():
|
||||
product = product_obj.search(
|
||||
[
|
||||
"|",
|
||||
("default_code", "=", product_code),
|
||||
("barcode", "=", product_code),
|
||||
],
|
||||
limit=1,
|
||||
)
|
||||
if not product:
|
||||
continue
|
||||
inventory.product_id = product
|
||||
values = super(StockInventory, inventory)._get_inventory_lines_values()
|
||||
if values:
|
||||
values[0]["product_qty"] = tmp_lines[product_code]
|
||||
else:
|
||||
vals += [
|
||||
{
|
||||
"product_id": product.id,
|
||||
"product_qty": tmp_lines[product_code],
|
||||
"location_id": self.location_id.id,
|
||||
}
|
||||
]
|
||||
vals += values
|
||||
else:
|
||||
vals = super()._get_inventory_lines_values()
|
||||
return vals
|
||||
def _action_start(self):
|
||||
Product = self.env["product.product"]
|
||||
for inventory in self:
|
||||
products = Product.browse()
|
||||
if inventory.state != "draft":
|
||||
continue
|
||||
if inventory.filter == "categories":
|
||||
products = Product.search([("categ_id", "in", inventory.categ_ids.ids)])
|
||||
if inventory.filter == "lots":
|
||||
products = inventory.lot_ids.mapped("product_id")
|
||||
if inventory.filter == "domain":
|
||||
domain = safe_eval(inventory.product_domain)
|
||||
products = Product.search(domain)
|
||||
if products:
|
||||
inventory.product_ids = [(6, 0, products.ids)]
|
||||
return super()._action_start()
|
||||
|
||||
@@ -3,5 +3,6 @@
|
||||
|
||||
* Pedro M. Baeza
|
||||
* David Vidal
|
||||
* Sergio Teruel
|
||||
|
||||
* Xavier Jimenez <xavier.jimenez@qubiq.es>
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
Includes more options for making an inventory out of:
|
||||
|
||||
* Multiple products.
|
||||
* Products filtered by a domain.
|
||||
* Products of a category.
|
||||
* Multiple lots
|
||||
|
||||
It also allows to make an inventory based on scanned products, adding a line
|
||||
with product code and quantity.
|
||||
|
||||
3
stock_inventory_preparation_filter/readme/ROADMAP.rst
Normal file
3
stock_inventory_preparation_filter/readme/ROADMAP.rst
Normal file
@@ -0,0 +1,3 @@
|
||||
* The widget domain is not displayed correctly, but this issue is related to
|
||||
Odoo. To avoid this malfunction, use the keyboard arrows to properly work
|
||||
with the domain option.
|
||||
@@ -1,3 +0,0 @@
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_stock_inventory_line_empty_user,access_stock_inventory_line_empty_user,model_stock_inventory_line_empty,stock.group_stock_user,1,0,0,0
|
||||
access_stock_inventory_line_empty_manager,access_stock_inventory_line_empty_manager,model_stock_inventory_line_empty,stock.group_stock_manager,1,1,1,1
|
||||
|
@@ -367,65 +367,72 @@ ul.auto-toc {
|
||||
!! This file is generated by oca-gen-addon-readme !!
|
||||
!! changes will be overwritten. !!
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
|
||||
<p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/OCA/stock-logistics-warehouse/tree/12.0/stock_inventory_preparation_filter"><img alt="OCA/stock-logistics-warehouse" src="https://img.shields.io/badge/github-OCA%2Fstock--logistics--warehouse-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/stock-logistics-warehouse-12-0/stock-logistics-warehouse-12-0-stock_inventory_preparation_filter"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/153/12.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p>
|
||||
<p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/OCA/stock-logistics-warehouse/tree/13.0/stock_inventory_preparation_filter"><img alt="OCA/stock-logistics-warehouse" src="https://img.shields.io/badge/github-OCA%2Fstock--logistics--warehouse-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/stock-logistics-warehouse-13-0/stock-logistics-warehouse-13-0-stock_inventory_preparation_filter"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/153/13.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p>
|
||||
<p>Includes more options for making an inventory out of:</p>
|
||||
<ul class="simple">
|
||||
<li>Multiple products.</li>
|
||||
<li>Products filtered by a domain.</li>
|
||||
<li>Products of a category.</li>
|
||||
<li>Multiple lots</li>
|
||||
</ul>
|
||||
<p>It also allows to make an inventory based on scanned products, adding a line
|
||||
with product code and quantity.</p>
|
||||
<p><strong>Table of contents</strong></p>
|
||||
<div class="contents local topic" id="contents">
|
||||
<ul class="simple">
|
||||
<li><a class="reference internal" href="#bug-tracker" id="id1">Bug Tracker</a></li>
|
||||
<li><a class="reference internal" href="#credits" id="id2">Credits</a><ul>
|
||||
<li><a class="reference internal" href="#authors" id="id3">Authors</a></li>
|
||||
<li><a class="reference internal" href="#contributors" id="id4">Contributors</a></li>
|
||||
<li><a class="reference internal" href="#maintainers" id="id5">Maintainers</a></li>
|
||||
<li><a class="reference internal" href="#known-issues-roadmap" id="id1">Known issues / Roadmap</a></li>
|
||||
<li><a class="reference internal" href="#bug-tracker" id="id2">Bug Tracker</a></li>
|
||||
<li><a class="reference internal" href="#credits" id="id3">Credits</a><ul>
|
||||
<li><a class="reference internal" href="#authors" id="id4">Authors</a></li>
|
||||
<li><a class="reference internal" href="#contributors" id="id5">Contributors</a></li>
|
||||
<li><a class="reference internal" href="#maintainers" id="id6">Maintainers</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="known-issues-roadmap">
|
||||
<h1><a class="toc-backref" href="#id1">Known issues / Roadmap</a></h1>
|
||||
<ul class="simple">
|
||||
<li>The widget domain is not displayed correctly, but this issue is related to
|
||||
Odoo. To avoid this malfunction, use the keyboard arrows to properly work
|
||||
with the domain option.</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="bug-tracker">
|
||||
<h1><a class="toc-backref" href="#id1">Bug Tracker</a></h1>
|
||||
<h1><a class="toc-backref" href="#id2">Bug Tracker</a></h1>
|
||||
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/stock-logistics-warehouse/issues">GitHub Issues</a>.
|
||||
In case of trouble, please check there if your issue has already been reported.
|
||||
If you spotted it first, help us smashing it by providing a detailed and welcomed
|
||||
<a class="reference external" href="https://github.com/OCA/stock-logistics-warehouse/issues/new?body=module:%20stock_inventory_preparation_filter%0Aversion:%2012.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
|
||||
<a class="reference external" href="https://github.com/OCA/stock-logistics-warehouse/issues/new?body=module:%20stock_inventory_preparation_filter%0Aversion:%2013.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
|
||||
<p>Do not contact contributors directly about support or help with technical issues.</p>
|
||||
</div>
|
||||
<div class="section" id="credits">
|
||||
<h1><a class="toc-backref" href="#id2">Credits</a></h1>
|
||||
<h1><a class="toc-backref" href="#id3">Credits</a></h1>
|
||||
<div class="section" id="authors">
|
||||
<h2><a class="toc-backref" href="#id3">Authors</a></h2>
|
||||
<h2><a class="toc-backref" href="#id4">Authors</a></h2>
|
||||
<ul class="simple">
|
||||
<li>AvanzOSC</li>
|
||||
<li>Tecnativa</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="contributors">
|
||||
<h2><a class="toc-backref" href="#id4">Contributors</a></h2>
|
||||
<h2><a class="toc-backref" href="#id5">Contributors</a></h2>
|
||||
<ul class="simple">
|
||||
<li>Oihane Crucelaegui <<a class="reference external" href="mailto:oihanecrucelaegi@avanzosc.es">oihanecrucelaegi@avanzosc.es</a>></li>
|
||||
<li><a class="reference external" href="https://www.tecnativa.com">Tecnativa</a>:<ul>
|
||||
<li>Pedro M. Baeza</li>
|
||||
<li>David Vidal</li>
|
||||
<li>Sergio Teruel</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Xavier Jimenez <<a class="reference external" href="mailto:xavier.jimenez@qubiq.es">xavier.jimenez@qubiq.es</a>></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="maintainers">
|
||||
<h2><a class="toc-backref" href="#id5">Maintainers</a></h2>
|
||||
<h2><a class="toc-backref" href="#id6">Maintainers</a></h2>
|
||||
<p>This module is maintained by the OCA.</p>
|
||||
<a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a>
|
||||
<p>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.</p>
|
||||
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/stock-logistics-warehouse/tree/12.0/stock_inventory_preparation_filter">OCA/stock-logistics-warehouse</a> project on GitHub.</p>
|
||||
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/stock-logistics-warehouse/tree/13.0/stock_inventory_preparation_filter">OCA/stock-logistics-warehouse</a> project on GitHub.</p>
|
||||
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -11,15 +11,14 @@ class TestStockInventoryPreparationFilterCategories(common.TransactionCase):
|
||||
def setUp(self):
|
||||
super(TestStockInventoryPreparationFilterCategories, self).setUp()
|
||||
self.inventory_model = self.env["stock.inventory"]
|
||||
self.location = self.env.ref("stock.stock_location_stock")
|
||||
self.Product = self.env["product.product"]
|
||||
self.Category = self.env["product.category"]
|
||||
# Create some categories
|
||||
self.category = self.env["product.category"].create(
|
||||
{"name": "Category for inventory"}
|
||||
)
|
||||
self.category2 = self.env["product.category"].create(
|
||||
{"name": "Category for inventory 2"}
|
||||
)
|
||||
self.category = self.Category.create({"name": "Category for inventory"})
|
||||
self.category2 = self.Category.create({"name": "Category for inventory 2"})
|
||||
# Create some products in the category
|
||||
self.product1 = self.env["product.product"].create(
|
||||
self.product1 = self.Product.create(
|
||||
{
|
||||
"name": "Product for inventory 1",
|
||||
"type": "product",
|
||||
@@ -27,7 +26,7 @@ class TestStockInventoryPreparationFilterCategories(common.TransactionCase):
|
||||
"default_code": "PROD1-TEST",
|
||||
}
|
||||
)
|
||||
self.product2 = self.env["product.product"].create(
|
||||
self.product2 = self.Product.create(
|
||||
{
|
||||
"name": "Product for inventory 2",
|
||||
"type": "product",
|
||||
@@ -35,7 +34,7 @@ class TestStockInventoryPreparationFilterCategories(common.TransactionCase):
|
||||
"default_code": "PROD2-TEST",
|
||||
}
|
||||
)
|
||||
self.product3 = self.env["product.product"].create(
|
||||
self.product3 = self.Product.create(
|
||||
{
|
||||
"name": "Product for inventory 3",
|
||||
"type": "product",
|
||||
@@ -43,7 +42,7 @@ class TestStockInventoryPreparationFilterCategories(common.TransactionCase):
|
||||
"default_code": "PROD3-TEST",
|
||||
}
|
||||
)
|
||||
self.product_lot = self.env["product.product"].create(
|
||||
self.product_lot = self.Product.create(
|
||||
{
|
||||
"name": "Product for inventory with lots",
|
||||
"type": "product",
|
||||
@@ -51,7 +50,41 @@ class TestStockInventoryPreparationFilterCategories(common.TransactionCase):
|
||||
}
|
||||
)
|
||||
self.lot = self.env["stock.production.lot"].create(
|
||||
{"name": "Lot test", "product_id": self.product_lot.id}
|
||||
{
|
||||
"name": "Lot test",
|
||||
"product_id": self.product_lot.id,
|
||||
"company_id": self.env.user.company_id.id,
|
||||
}
|
||||
)
|
||||
# Add quants for products to ensure that inventory lines are created
|
||||
self.env["stock.quant"].create(
|
||||
[
|
||||
{
|
||||
"product_id": self.product1.id,
|
||||
"product_uom_id": self.product1.uom_id.id,
|
||||
"location_id": self.location.id,
|
||||
"quantity": 2.0,
|
||||
},
|
||||
{
|
||||
"product_id": self.product2.id,
|
||||
"product_uom_id": self.product2.uom_id.id,
|
||||
"location_id": self.location.id,
|
||||
"quantity": 2.0,
|
||||
},
|
||||
{
|
||||
"product_id": self.product3.id,
|
||||
"product_uom_id": self.product3.uom_id.id,
|
||||
"location_id": self.location.id,
|
||||
"quantity": 2.0,
|
||||
},
|
||||
{
|
||||
"product_id": self.product_lot.id,
|
||||
"product_uom_id": self.product_lot.uom_id.id,
|
||||
"location_id": self.location.id,
|
||||
"quantity": 2.0,
|
||||
"lot_id": self.lot.id,
|
||||
},
|
||||
]
|
||||
)
|
||||
# Add user to lot tracking group
|
||||
self.env.user.groups_id = [(4, self.env.ref("stock.group_production_lot").id)]
|
||||
@@ -59,93 +92,35 @@ class TestStockInventoryPreparationFilterCategories(common.TransactionCase):
|
||||
self.location = self.env["stock.location"].create(
|
||||
{"name": "Inventory tests", "usage": "internal"}
|
||||
)
|
||||
inventory = self.inventory_model.create(
|
||||
{
|
||||
"name": "Product1 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.location.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.location.id,
|
||||
},
|
||||
),
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"product_id": self.product_lot.id,
|
||||
"product_uom_id": self.env.ref("uom.product_uom_unit").id,
|
||||
"product_qty": 6.0,
|
||||
"location_id": self.location.id,
|
||||
"prod_lot_id": self.lot.id,
|
||||
},
|
||||
),
|
||||
],
|
||||
}
|
||||
self.test_products = (
|
||||
self.product1 + self.product2 + self.product3 + self.product_lot
|
||||
)
|
||||
inventory._action_done()
|
||||
|
||||
def test_inventory_category_filter(self):
|
||||
def test_inventory_filter(self):
|
||||
# Filter all products
|
||||
inventory = self.inventory_model.create(
|
||||
{
|
||||
"name": "Category inventory",
|
||||
"filter": "categories",
|
||||
"location_id": self.location.id,
|
||||
"categ_ids": [(6, 0, [self.category.id])],
|
||||
}
|
||||
{"name": "Inventory test", "filter": "products"}
|
||||
)
|
||||
inventory.action_start()
|
||||
self.assertEqual(len(inventory.line_ids), 2)
|
||||
line1 = inventory.line_ids[0]
|
||||
self.assertEqual(line1.product_id, self.product1)
|
||||
self.assertEqual(line1.theoretical_qty, 2.0)
|
||||
self.assertEqual(line1.location_id, self.location)
|
||||
line2 = inventory.line_ids[1]
|
||||
self.assertEqual(line2.product_id, self.product2)
|
||||
self.assertEqual(line2.theoretical_qty, 4.0)
|
||||
self.assertEqual(line2.location_id, self.location)
|
||||
|
||||
def test_inventory_products_filter(self):
|
||||
inventory = self.inventory_model.create(
|
||||
{
|
||||
"name": "Products inventory",
|
||||
"filter": "products",
|
||||
"location_id": self.location.id,
|
||||
"product_ids": [(6, 0, [self.product1.id, self.product2.id])],
|
||||
}
|
||||
self.assertTrue(self.test_products <= inventory.line_ids.mapped("product_id"))
|
||||
# Filter by categories
|
||||
inventory.action_cancel_draft()
|
||||
inventory.update(
|
||||
{"filter": "categories", "categ_ids": [(6, 0, [self.category.id])]}
|
||||
)
|
||||
inventory.action_start()
|
||||
self.assertEqual(len(inventory.line_ids), 2)
|
||||
line1 = inventory.line_ids[0]
|
||||
self.assertEqual(line1.product_id, self.product1)
|
||||
self.assertEqual(line1.theoretical_qty, 2.0)
|
||||
self.assertEqual(line1.location_id, self.location)
|
||||
line2 = inventory.line_ids[1]
|
||||
self.assertEqual(line2.product_id, self.product2)
|
||||
self.assertEqual(line2.theoretical_qty, 4.0)
|
||||
self.assertEqual(line2.location_id, self.location)
|
||||
self.assertEqual(len(inventory.line_ids), 3)
|
||||
# Filter by lots
|
||||
inventory.action_cancel_draft()
|
||||
inventory.update({"filter": "lots", "lot_ids": [(6, 0, self.lot.ids)]})
|
||||
inventory.action_start()
|
||||
self.assertEqual(len(inventory.line_ids), 1)
|
||||
|
||||
def test_inventory_domain_filter(self):
|
||||
inventory = self.inventory_model.create(
|
||||
{
|
||||
"name": "Domain inventory",
|
||||
"filter": "domain",
|
||||
"location_id": self.location.id,
|
||||
"product_domain": [("id", "=", self.product1.id)],
|
||||
}
|
||||
)
|
||||
@@ -154,53 +129,3 @@ class TestStockInventoryPreparationFilterCategories(common.TransactionCase):
|
||||
line1 = inventory.line_ids[0]
|
||||
self.assertEqual(line1.product_id, self.product1)
|
||||
self.assertEqual(line1.theoretical_qty, 2.0)
|
||||
self.assertEqual(line1.location_id, self.location)
|
||||
|
||||
def test_inventory_lots_filter(self):
|
||||
inventory = self.inventory_model.create(
|
||||
{
|
||||
"name": "Products inventory",
|
||||
"filter": "lots",
|
||||
"location_id": self.location.id,
|
||||
"lot_ids": [(6, 0, [self.lot.id])],
|
||||
}
|
||||
)
|
||||
inventory.action_start()
|
||||
self.assertEqual(len(inventory.line_ids), 1)
|
||||
line1 = inventory.line_ids[0]
|
||||
self.assertEqual(line1.product_id, self.product_lot)
|
||||
self.assertEqual(line1.prod_lot_id, self.lot)
|
||||
self.assertEqual(line1.theoretical_qty, 6.0)
|
||||
self.assertEqual(line1.location_id, self.location)
|
||||
|
||||
def test_inventory_empty_filter(self):
|
||||
inventory = self.inventory_model.create(
|
||||
{
|
||||
"name": "Products inventory",
|
||||
"filter": "empty",
|
||||
"location_id": self.location.id,
|
||||
"empty_line_ids": [
|
||||
(0, 0, {"product_code": "PROD1-TEST", "product_qty": 3.0}),
|
||||
(0, 0, {"product_code": "PROD2-TEST", "product_qty": 7.0}),
|
||||
(0, 0, {"product_code": "PROD3-TEST", "product_qty": 5.0}),
|
||||
(0, 0, {"product_code": "UNEXISTING-CODE", "product_qty": 0.0}),
|
||||
],
|
||||
}
|
||||
)
|
||||
inventory.action_start()
|
||||
self.assertEqual(len(inventory.line_ids), 3)
|
||||
line1 = inventory.line_ids[0]
|
||||
self.assertEqual(line1.product_id, self.product1)
|
||||
self.assertEqual(line1.theoretical_qty, 2.0)
|
||||
self.assertEqual(line1.product_qty, 3.0)
|
||||
self.assertEqual(line1.location_id, self.location)
|
||||
line2 = inventory.line_ids[1]
|
||||
self.assertEqual(line2.product_id, self.product2)
|
||||
self.assertEqual(line2.theoretical_qty, 4.0)
|
||||
self.assertEqual(line2.product_qty, 7.0)
|
||||
self.assertEqual(line2.location_id, self.location)
|
||||
line3 = inventory.line_ids[2]
|
||||
self.assertEqual(line3.product_id, self.product3)
|
||||
self.assertEqual(line3.theoretical_qty, 0.0)
|
||||
self.assertEqual(line3.product_qty, 5.0)
|
||||
self.assertEqual(line3.location_id, self.location)
|
||||
|
||||
@@ -1,48 +1,48 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
|
||||
<record model="ir.ui.view" id="stock_inventory_form">
|
||||
<field name="name">stock.inventory.form</field>
|
||||
<field name="model">stock.inventory</field>
|
||||
<field name="inherit_id" ref="stock.view_inventory_form" />
|
||||
<field name="arch" type="xml">
|
||||
<data>
|
||||
<notebook position="attributes">
|
||||
<attribute name="attrs" />
|
||||
</notebook>
|
||||
<xpath expr="//button[@name='action_reset_product_qty']/ancestor::*[position()=1]" position="attributes">
|
||||
<attribute name="attrs">{'invisible':[('state','=','draft')]}</attribute>
|
||||
</xpath>
|
||||
<field name="category_id" position="after">
|
||||
<field name="categ_ids"
|
||||
widget="many2many_tags"
|
||||
attrs="{'invisible':[('filter','!=','categories')]}" />
|
||||
</field>
|
||||
<field name="product_id" position="after">
|
||||
<field name="product_ids"
|
||||
widget="many2many_tags"
|
||||
attrs="{'invisible':[('filter','!=','products')]}" />
|
||||
</field>
|
||||
<field name="lot_id" position="after">
|
||||
<field name="lot_ids"
|
||||
attrs="{'invisible':[('filter','!=','lots')]}" />
|
||||
</field>
|
||||
<notebook position="before">
|
||||
<field name="product_domain" widget="domain" attrs="{'invisible': [('filter', '!=', 'domain')]}" options="{'model': 'product.product'}"/>
|
||||
</notebook>
|
||||
<notebook position="inside">
|
||||
<page string="Capture Lines"
|
||||
attrs="{'invisible':[('filter','!=','empty')]}">
|
||||
<field name="empty_line_ids" nolabel="1">
|
||||
<tree editable="bottom">
|
||||
<field name="product_code"/>
|
||||
<field name="product_qty"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
</notebook>
|
||||
</data>
|
||||
<record model="ir.ui.view" id="view_inventory_form">
|
||||
<field name="model">stock.inventory</field>
|
||||
<field name="inherit_id" ref="stock.view_inventory_form" />
|
||||
<field name="arch" type="xml">
|
||||
<field name="product_ids" position="attributes">
|
||||
<attribute
|
||||
name="attrs"
|
||||
>{'invisible': [('filter', '!=', 'products')]}</attribute>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<xpath expr="//field[@name='location_ids']/../.." position="before">
|
||||
<group>
|
||||
<group>
|
||||
<field
|
||||
name="filter"
|
||||
string="Inventory of"
|
||||
widget='radio'
|
||||
attrs="{'readonly': [('state', '!=', 'draft')]}"
|
||||
/>
|
||||
</group>
|
||||
</group>
|
||||
</xpath>
|
||||
<field name="location_ids" position="before">
|
||||
<field
|
||||
name="categ_ids"
|
||||
widget="many2many_tags"
|
||||
attrs="{'invisible':[('filter','!=','categories')]}"
|
||||
/>
|
||||
</field>
|
||||
<field name="location_ids" position="before">
|
||||
<field
|
||||
name="lot_ids"
|
||||
widget="many2many_tags"
|
||||
attrs="{'invisible':[('filter','!=','lots')]}"
|
||||
/>
|
||||
</field>
|
||||
<xpath expr="//field[@name='location_ids']/../.." position="after">
|
||||
<field
|
||||
name="product_domain"
|
||||
widget="domain"
|
||||
attrs="{'invisible': [('filter', '!=', 'domain')]}"
|
||||
options="{'model': 'product.product'}"
|
||||
/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
|
||||
Reference in New Issue
Block a user