diff --git a/addons/stock/__manifest__.py b/addons/stock/__manifest__.py index f5fde7a8ff9..ad51ea5df42 100644 --- a/addons/stock/__manifest__.py +++ b/addons/stock/__manifest__.py @@ -42,6 +42,7 @@ 'wizard/stock_scheduler_compute_views.xml', 'wizard/stock_immediate_transfer_views.xml', 'wizard/stock_backorder_confirmation_views.xml', + 'wizard/stock_overprocessed_transfer_views.xml', 'views/res_partner_views.xml', 'views/product_strategy_views.xml', diff --git a/addons/stock/models/stock_picking.py b/addons/stock/models/stock_picking.py index 4e295000523..33d4eeaabd1 100644 --- a/addons/stock/models/stock_picking.py +++ b/addons/stock/models/stock_picking.py @@ -601,6 +601,21 @@ class Picking(models.Model): 'context': self.env.context, } + if self._get_overprocessed_stock_moves() and not self._context.get('skip_overprocessed_check'): + view = self.env.ref('stock.view_overprocessed_transfer') + wiz = self.env['stock.overprocessed.transfer'].create({'picking_id': self.id}) + return { + 'type': 'ir.actions.act_window', + 'view_type': 'form', + 'view_mode': 'form', + 'res_model': 'stock.overprocessed.transfer', + 'views': [(view.id, 'form')], + 'view_id': view.id, + 'target': 'new', + 'res_id': wiz.id, + 'context': self.env.context, + } + # Check backorder should check for other barcodes if self._check_backorder(): return self.action_generate_backorder_wizard() @@ -652,6 +667,13 @@ class Picking(models.Model): for picking in self.filtered(lambda picking: picking.state not in ('done', 'cancel') and picking.move_lines): picking.action_confirm() + def _get_overprocessed_stock_moves(self): + self.ensure_one() + return self.move_lines.filtered( + lambda move: move.product_uom_qty != 0 and float_compare(move.quantity_done, move.product_uom_qty, + precision_rounding=move.product_uom.rounding) == 1 + ) + @api.multi def _create_backorder(self, backorder_moves=[]): """ Move all non-done lines into a new backorder picking. If the key 'do_only_split' is given in the context, then move all lines not in context.get('split', []) instead of all non-done lines. diff --git a/addons/stock/tests/test_move.py b/addons/stock/tests/test_move.py index d3587b78cc6..5ada90463c4 100644 --- a/addons/stock/tests/test_move.py +++ b/addons/stock/tests/test_move.py @@ -2369,11 +2369,12 @@ class StockMove(TransactionCase): def test_immediate_validate_6(self): """ Create a picking and simulates validate button effect. - This tests two cases: + This tests three cases: - if a user has processed no quantities and at least one product is tracked, he should specify lots - if a user has processed some quantities then it's ok because a backorder will be created for the ones not filled in + - if a user overprocesses a move he will be asked to confirm if this is ok """ picking_type = self.env.ref('stock.picking_type_in') picking_type.use_create_lots = True @@ -2422,6 +2423,11 @@ class StockMove(TransactionCase): self.assertTrue(isinstance(action, dict), 'Should open backorder wizard') self.assertEqual(action.get('res_model'), 'stock.backorder.confirmation') + product3_move.move_line_ids[0].qty_done = 2 + action = picking.button_validate() # should request confirmation + self.assertTrue(isinstance(action, dict), 'Should open overprocessing wizard') + self.assertEqual(action.get('res_model'), 'stock.overprocessed.transfer') + def test_set_quantity_done_1(self): move1 = self.env['stock.move'].create({ 'name': 'test_set_quantity_done_1', diff --git a/addons/stock/wizard/__init__.py b/addons/stock/wizard/__init__.py index 7e494f64cee..b07f880122e 100644 --- a/addons/stock/wizard/__init__.py +++ b/addons/stock/wizard/__init__.py @@ -6,3 +6,4 @@ from . import stock_change_product_qty from . import stock_scheduler_compute from . import stock_immediate_transfer from . import stock_backorder_confirmation +from . import stock_overprocessed_transfer diff --git a/addons/stock/wizard/stock_overprocessed_transfer.py b/addons/stock/wizard/stock_overprocessed_transfer.py new file mode 100644 index 00000000000..b77bd18f3e3 --- /dev/null +++ b/addons/stock/wizard/stock_overprocessed_transfer.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, fields, models, _ +from odoo.exceptions import UserError + + +class StockOverProcessedTransfer(models.TransientModel): + _name = 'stock.overprocessed.transfer' + + picking_id = fields.Many2one('stock.picking') + overprocessed_product_name = fields.Char(compute='_compute_overprocessed_product_name', + readonly=True) + + @api.multi + def _compute_overprocessed_product_name(self): + for wizard in self: + moves = wizard.picking_id._get_overprocessed_stock_moves() + wizard.overprocessed_product_name = moves[0].product_id.display_name + + @api.multi + def action_confirm(self): + self.ensure_one() + return self.picking_id.with_context(skip_overprocessed_check=True).button_validate() diff --git a/addons/stock/wizard/stock_overprocessed_transfer_views.xml b/addons/stock/wizard/stock_overprocessed_transfer_views.xml new file mode 100644 index 00000000000..196c767bcd0 --- /dev/null +++ b/addons/stock/wizard/stock_overprocessed_transfer_views.xml @@ -0,0 +1,22 @@ + + + + stock.overprocessed.transfer.view.form + stock.overprocessed.transfer + +
+

+ You have processed more than what was initially + planned for the product . +

+

+ Are you sure you want to validate this picking? +

+ +
+
+
+