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