summaryrefslogtreecommitdiff
path: root/addons
diff options
context:
space:
mode:
authorSimon Lejeune <sle@openerp.com>2017-07-19 17:18:28 +0200
committerSimon Lejeune <sle@openerp.com>2017-07-19 18:29:16 +0200
commitcc181711dd84df0584ea6d49d174265dade5ec9b (patch)
treee8b52f838a0c69be335bae8785e512a54acadad0 /addons
parent886137d0c813f3bbb8835a483549f54621449e43 (diff)
[FIX] stock: scrap: allow scrapping consumable
A previous revision[0] forbid to scrap consumables. The rationale at the time was that, since consumables do not have quant, scrapping them does not make sense. It appears that people use this feature on consumable for traceability reason, so we bring back the old behavior. A slight change was done in stock_scrap.py: if the product is a consumable, do not raise the error if the quantity to scrap is not available in stock for obvious reasons. Also, a leftover todo in the code indicate that we should unreserve the any move having reserved the scrapped product. This is actually already done, since this mechanism is in the move line `action_done` and a scrap uses a classical stock move and stock move lines. We introduce some test to prove that it is possible to scrap a stockable product and the quant are impacted, to scrap a consumable product and the stock is not impacted and to scrap something that was reseved by a move and that the move changes its state. [0] 86f08c091eea2a623ee6460562a750506cbdd585
Diffstat (limited to 'addons')
-rw-r--r--addons/stock/models/stock_picking.py4
-rw-r--r--addons/stock/models/stock_scrap.py14
-rw-r--r--addons/stock/tests/test_move.py67
-rw-r--r--addons/stock/views/stock_scrap_views.xml2
4 files changed, 75 insertions, 12 deletions
diff --git a/addons/stock/models/stock_picking.py b/addons/stock/models/stock_picking.py
index eea788a7a15..46b937546f7 100644
--- a/addons/stock/models/stock_picking.py
+++ b/addons/stock/models/stock_picking.py
@@ -778,8 +778,6 @@ class Picking(models.Model):
@api.multi
def button_scrap(self):
self.ensure_one()
- # only stockable products are scrapeable
- scrapeable_products = self.move_line_ids.mapped('product_id').filtered(lambda p: p.type == 'product')
return {
'name': _('Scrap'),
'view_type': 'form',
@@ -787,7 +785,7 @@ class Picking(models.Model):
'res_model': 'stock.scrap',
'view_id': self.env.ref('stock.stock_scrap_form_view2').id,
'type': 'ir.actions.act_window',
- 'context': {'default_picking_id': self.id, 'product_ids': scrapeable_products.ids},
+ 'context': {'default_picking_id': self.id, 'product_ids': self.move_line_ids.mapped('product_id').ids},
'target': 'new',
}
diff --git a/addons/stock/models/stock_scrap.py b/addons/stock/models/stock_scrap.py
index 4e0cad94729..839987cee2e 100644
--- a/addons/stock/models/stock_scrap.py
+++ b/addons/stock/models/stock_scrap.py
@@ -79,15 +79,15 @@ class StockScrap(models.Model):
def do_scrap(self):
for scrap in self:
move = self.env['stock.move'].create(scrap._prepare_move_values())
- quantity_in_stock = self.env['stock.quant']._get_quantity(
- self.product_id, self.location_id, lot_id=self.lot_id,
- package_id=self.package_id, owner_id=self.owner_id, strict=True
- )
- if quantity_in_stock < move.product_qty: # FIXME: float compare
- raise UserError(_('You cannot scrap a move without having available stock for %s. You can correct it with an inventory adjustment.') % move.product_id.name)
+ if self.product_id.type == 'product':
+ quantity_in_stock = self.env['stock.quant']._get_quantity(
+ self.product_id, self.location_id, lot_id=self.lot_id,
+ package_id=self.package_id, owner_id=self.owner_id, strict=True
+ )
+ if quantity_in_stock < move.product_qty: # FIXME: float compare
+ raise UserError(_('You cannot scrap a move without having available stock for %s. You can correct it with an inventory adjustment.') % move.product_id.name)
move.action_done()
scrap.write({'move_id': move.id, 'state': 'done'})
- # TODO: unreserve reserved
return True
def _prepare_move_values(self):
diff --git a/addons/stock/tests/test_move.py b/addons/stock/tests/test_move.py
index 04406847d7e..a29e2f00e65 100644
--- a/addons/stock/tests/test_move.py
+++ b/addons/stock/tests/test_move.py
@@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
-from odoo.tests.common import TransactionCase
from odoo.exceptions import UserError
+from odoo.tests.common import TransactionCase
class StockMove(TransactionCase):
@@ -30,6 +30,11 @@ class StockMove(TransactionCase):
'tracking': 'lot',
'categ_id': self.env.ref('product.product_category_all').id,
})
+ self.product4 = self.env['product.product'].create({
+ 'name': 'Product A',
+ 'type': 'consu',
+ 'categ_id': self.env.ref('product.product_category_all').id,
+ })
def test_in_1(self):
""" Receive products from a supplier. Check that a move line is created and that the
@@ -2220,3 +2225,63 @@ class StockMove(TransactionCase):
move1.product_id = self.product2
move1.onchange_product_id()
self.assertEqual(move1.product_uom_qty, 100)
+
+ def test_scrap_1(self):
+ """ Check the created stock move and the impact on quants when we scrap a
+ stockable product.
+ """
+ self.env['stock.quant']._update_available_quantity(self.product1, self.stock_location, 1)
+ scrap = self.env['stock.scrap'].create({
+ 'product_id': self.product1.id,
+ 'product_uom_id':self.product1.uom_id.id,
+ 'scrap_qty': 1,
+ })
+ self.assertEqual(scrap.state, 'done')
+ move = scrap.move_id
+ self.assertEqual(move.state, 'done')
+ self.assertEqual(move.quantity_done, 1)
+ self.assertEqual(move.scrapped, True)
+ self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product1, self.stock_location), 0)
+
+ def test_scrap_2(self):
+ """ Check the created stock move and the impact on quants when we scrap a
+ consumable product.
+ """
+ scrap = self.env['stock.scrap'].create({
+ 'product_id': self.product4.id,
+ 'product_uom_id':self.product4.uom_id.id,
+ 'scrap_qty': 1,
+ })
+ self.assertEqual(scrap.state, 'done')
+ move = scrap.move_id
+ self.assertEqual(move.state, 'done')
+ self.assertEqual(move.quantity_done, 1)
+ self.assertEqual(move.scrapped, True)
+ self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product4, self.stock_location), 0)
+
+ def test_scrap_3(self):
+ """ Scrap the product of a reserved move line. Check that the move line is
+ correctly deleted and that the associated stock move is not assigned anymore.
+ """
+ self.env['stock.quant']._update_available_quantity(self.product1, self.stock_location, 1)
+ move1 = self.env['stock.move'].create({
+ 'name': 'test_set_quantity_done_1',
+ 'location_id': self.stock_location.id,
+ 'location_dest_id': self.customer_location.id,
+ 'product_id': self.product1.id,
+ 'product_uom': self.uom_unit.id,
+ 'product_uom_qty': 1.0,
+ })
+ move1.action_confirm()
+ move1.action_assign()
+ self.assertEqual(move1.state, 'assigned')
+ self.assertEqual(len(move1.move_line_ids), 1)
+
+ scrap = self.env['stock.scrap'].create({
+ 'product_id': self.product1.id,
+ 'product_uom_id':self.product1.uom_id.id,
+ 'scrap_qty': 1,
+ })
+
+ self.assertEqual(move1.state, 'confirmed')
+ self.assertEqual(len(move1.move_line_ids), 0)
diff --git a/addons/stock/views/stock_scrap_views.xml b/addons/stock/views/stock_scrap_views.xml
index 12e74eca51f..fbd2684d80a 100644
--- a/addons/stock/views/stock_scrap_views.xml
+++ b/addons/stock/views/stock_scrap_views.xml
@@ -43,7 +43,7 @@
</div>
<group>
<group>
- <field name="product_id" domain="[('type', '=', 'product')]"/>
+ <field name="product_id"/>
<label for="scrap_qty"/>
<div class="o_row">
<field name="scrap_qty"/>