[IMP] stock: readd include exhausted product option

In the inventory adjustment form, readd (remove in 13.0)
the option to include exhausted product.

task-2115194

closes odoo/odoo#41239

Signed-off-by: Simon Lejeune (sle) <sle@openerp.com>
This commit is contained in:
ryv-odoo
2019-12-10 14:51:33 +00:00
parent 68518afe33
commit b5e24e9760
3 changed files with 146 additions and 4 deletions
+44 -4
View File
@@ -58,6 +58,10 @@ class Inventory(models.Model):
help="Allows to start with prefill counted quantity for each lines or "
"with all counted quantity set to zero.", default='counted',
selection=[('counted', 'Default to stock on hand'), ('zero', 'Default to zero')])
exhausted = fields.Boolean(
'Include Exhausted Products', readonly=True,
states={'draft': [('readonly', False)]},
help="Include also products with quantity of 0")
@api.onchange('company_id')
def _onchange_company_id(self):
@@ -206,8 +210,7 @@ class Inventory(models.Model):
return action
def _get_quantities(self):
"""
Return quantities group by product_id, location_id, lot_id, package_id and owner_id
"""Return quantities group by product_id, location_id, lot_id, package_id and owner_id
:return: a dict with keys as tuple of group by and quantity as value
:rtype: dict
@@ -240,9 +243,44 @@ class Inventory(models.Model):
quant['quantity'] for quant in quants
}
def _get_inventory_lines_values(self):
def _get_exhausted_inventory_lines_vals(self, non_exhausted_set):
"""Return the values of the inventory lines to create if the user
wants to include exhausted products. Exhausted products are products
without quantities or quantity equal to 0.
:param non_exhausted_set: set of tuple (product_id, location_id) of non exhausted product-location
:return: a list containing the `stock.inventory.line` values to create
:rtype: list
"""
Return the values of the inventory lines to create for this inventory.
self.ensure_one()
if self.product_ids:
product_ids = self.product_ids.ids
else:
product_ids = self.env['product.product'].search_read([
'|', ('company_id', '=', self.company_id.id), ('company_id', '=', False),
('type', '=', 'product'),
('active', '=', True)], ['id'])
product_ids = [p['id'] for p in product_ids]
if self.location_ids:
location_ids = self.location_ids.ids
else:
location_ids = self.env['stock.warehouse'].search([('company_id', '=', self.company_id.id)]).lot_stock_id.ids
vals = []
for product_id in product_ids:
for location_id in location_ids:
if ((product_id, location_id) not in non_exhausted_set):
vals.append({
'inventory_id': self.id,
'product_id': product_id,
'location_id': location_id,
'theoretical_qty': 0
})
return vals
def _get_inventory_lines_values(self):
"""Return the values of the inventory lines to create for this inventory.
:return: a list containing the `stock.inventory.line` values to create
:rtype: list
@@ -263,6 +301,8 @@ class Inventory(models.Model):
}
line_values['product_uom_id'] = self.env['product.product'].browse(product_id).uom_id.id
vals.append(line_values)
if self.exhausted:
vals += self._get_exhausted_inventory_lines_vals({(l['product_id'], l['location_id']) for l in vals})
return vals
+101
View File
@@ -701,3 +701,104 @@ class TestInventory(SavepointCase):
inventory_2.action_validate()
# Expect line of inventory 1 is still up to date
self.assertEqual(inventory_1.line_ids.outdated, False)
def test_inventory_include_exhausted_product(self):
""" Checks that exhausted product (quant not set or == 0) is added
to inventory line
(only for location_ids selected or, if not set, for each main location
(linked directly to the warehouse) of the current company)
when the option is active """
# location_ids SET + product_ids SET
inventory = self.env['stock.inventory'].create({
'name': 'loc SET - pro SET',
'exhausted': True,
'location_ids': [(4, self.stock_location.id)],
'product_ids': [(4, self.product1.id)],
})
inventory.action_start()
self.assertEqual(len(inventory.line_ids), 1)
self.assertEqual(inventory.line_ids.product_id.id, self.product1.id)
self.assertEqual(inventory.line_ids.theoretical_qty, 0)
self.assertEqual(inventory.line_ids.location_id.id, self.stock_location.id)
# location_ids SET + product_ids UNSET
inventory = self.env['stock.inventory'].create({
'name': 'loc SET - pro UNSET',
'exhausted': True,
'location_ids': [(4, self.stock_location.id)]
})
inventory.action_start()
line_ids_p1 = [l for l in inventory.line_ids if l['product_id']['id'] == self.product1.id]
line_ids_p2 = [l for l in inventory.line_ids if l['product_id']['id'] == self.product2.id]
self.assertEqual(len(line_ids_p1), 1)
self.assertEqual(len(line_ids_p2), 1)
self.assertEqual(line_ids_p1[0].location_id.id, self.stock_location.id)
self.assertEqual(line_ids_p2[0].location_id.id, self.stock_location.id)
# location_ids UNSET + product_ids SET
warehouse = self.env['stock.warehouse'].create({
'name': 'Warhouse',
'code': 'WAR'
})
child_loc = self.env['stock.location'].create({
'name': "ChildLOC",
'usage': 'internal',
'location_id': warehouse.lot_stock_id.id
})
inventory = self.env['stock.inventory'].create({
'name': 'loc UNSET - pro SET',
'exhausted': True,
'product_ids': [(4, self.product1.id)],
})
inventory.action_start()
line_ids = [l for l in inventory.line_ids if l['location_id']['id'] == warehouse.lot_stock_id.id]
self.assertEqual(len(line_ids), 1)
self.assertEqual(line_ids[0].theoretical_qty, 0)
self.assertEqual(line_ids[0].product_id.id, self.product1.id)
# Only the main location have a exhausted line
line_ids = [l for l in inventory.line_ids if l['location_id']['id'] == child_loc.id]
self.assertEqual(len(line_ids), 0)
# location_ids UNSET + product_ids UNSET
inventory = self.env['stock.inventory'].create({
'name': 'loc UNSET - pro UNSET',
'exhausted': True
})
inventory.action_start()
# Product1 & Product2 line with warehouse location
line_ids_p1 = [l for l in inventory.line_ids if l['product_id']['id'] == self.product1.id and l['location_id']['id'] == warehouse.lot_stock_id.id]
line_ids_p2 = [l for l in inventory.line_ids if l['product_id']['id'] == self.product2.id and l['location_id']['id'] == warehouse.lot_stock_id.id]
self.assertEqual(len(line_ids_p1), 1)
self.assertEqual(len(line_ids_p2), 1)
self.assertEqual(line_ids_p1[0].theoretical_qty, 0)
self.assertEqual(line_ids_p2[0].theoretical_qty, 0)
# location_ids SET + product_ids SET but when product in one locations but no the other
self.env['stock.quant'].create({
'product_id': self.product1.id,
'product_uom_id': self.uom_unit.id,
'location_id': self.stock_location.id,
'quantity': 10,
'reserved_quantity': 0,
})
inventory = self.env['stock.inventory'].create({
'name': 'loc SET - pro SET',
'exhausted': True,
'location_ids': [(4, self.stock_location.id), (4, warehouse.lot_stock_id.id)],
'product_ids': [(4, self.product1.id)],
})
inventory.action_start()
# need to have line for product1 for both location, one with quant the other not
line_ids_loc1 = [l for l in inventory.line_ids if l['location_id']['id'] == self.stock_location.id]
line_ids_loc2 = [l for l in inventory.line_ids if l['location_id']['id'] == warehouse.lot_stock_id.id]
self.assertEqual(len(line_ids_loc1), 1)
self.assertEqual(len(line_ids_loc2), 1)
self.assertEqual(line_ids_loc1[0].theoretical_qty, 10)
self.assertEqual(line_ids_loc2[0].theoretical_qty, 0)
@@ -181,6 +181,7 @@
groups="stock.group_stock_multi_locations"/>
<field name="product_ids" options="{'no_create': True}"
widget="many2many_tags"/>
<field name="exhausted"/>
</group>
<group>
<field name="company_id" groups="base.group_multi_company" options="{'no_create': True}"/>