[MIG] stock_inventory_preparation_filter: Migration to v13.0

This commit is contained in:
Sergio Teruel
2020-02-11 22:39:51 +01:00
parent 269eb9814e
commit 7a0da1c097
14 changed files with 248 additions and 327 deletions

View File

@@ -0,0 +1 @@
../../../../stock_inventory_preparation_filter

View File

@@ -0,0 +1,6 @@
import setuptools
setuptools.setup(
setup_requires=['setuptools-odoo'],
odoo_addon=True,
)

View File

@@ -14,39 +14,41 @@ 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.
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 +69,7 @@ Contributors
* Pedro M. Baeza
* David Vidal
* Sergio Teruel
* Xavier Jimenez <xavier.jimenez@qubiq.es>
@@ -83,6 +86,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.

View File

@@ -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",
}

View File

@@ -0,0 +1,40 @@
# Copyright 2020 Tecnativa - Sergio Teruel
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl).
from openupgradelib import openupgrade
def convert_m2o_to_x2m_fields(env):
openupgrade.m2o_to_x2m(
env.cr,
env["stock.inventory"],
"stock.inventory",
"location_ids",
openupgrade.get_legacy_name("location_id"),
)
openupgrade.m2o_to_x2m(
env.cr,
env["stock.inventory"],
"stock.inventory",
"product_ids",
openupgrade.get_legacy_name("product_id"),
)
openupgrade.m2o_to_x2m(
env.cr,
env["stock.inventory"],
"stock.inventory",
"categ_ids",
openupgrade.get_legacy_name("category_id"),
)
openupgrade.m2o_to_x2m(
env.cr,
env["stock.inventory"],
"stock.inventory",
"lot_ids",
openupgrade.get_legacy_name("lot_id"),
)
@openupgrade.migrate()
def migrate(env, version):
convert_m2o_to_x2m_fields(env)

View File

@@ -0,0 +1,18 @@
# Copyright 2020 Tecnativa - Sergio Teruel
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl).
from openupgradelib import openupgrade
column_renames = {
"stock_inventory": [
("location_id", None),
("product_id", None),
("category_id", None),
("lot_id", None),
]
}
@openupgrade.migrate()
def migrate(env, version):
openupgrade.rename_columns(env.cr, column_renames)

View File

@@ -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()

View File

@@ -3,5 +3,6 @@
* Pedro M. Baeza
* David Vidal
* Sergio Teruel
* Xavier Jimenez <xavier.jimenez@qubiq.es>

View File

@@ -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.

View File

@@ -0,0 +1,2 @@
* The widget domain is not displayed correctly, but this issue is related to
Odoo.

View File

@@ -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
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 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
3 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

View File

@@ -367,65 +367,71 @@ 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.</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 &lt;<a class="reference external" href="mailto:oihanecrucelaegi&#64;avanzosc.es">oihanecrucelaegi&#64;avanzosc.es</a>&gt;</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 &lt;<a class="reference external" href="mailto:xavier.jimenez&#64;qubiq.es">xavier.jimenez&#64;qubiq.es</a>&gt;</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>

View File

@@ -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)

View File

@@ -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>