diff --git a/addons/mrp_product_expiry/__init__.py b/addons/mrp_product_expiry/__init__.py
index 961d779cf21..f7a591caed7 100644
--- a/addons/mrp_product_expiry/__init__.py
+++ b/addons/mrp_product_expiry/__init__.py
@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
+from . import models
from . import tests
from . import wizard
diff --git a/addons/mrp_product_expiry/models/__init__.py b/addons/mrp_product_expiry/models/__init__.py
new file mode 100644
index 00000000000..f75cb03c89b
--- /dev/null
+++ b/addons/mrp_product_expiry/models/__init__.py
@@ -0,0 +1,5 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from . import mrp_abstract_workorder
+from . import mrp_workorder
diff --git a/addons/mrp_product_expiry/models/mrp_abstract_workorder.py b/addons/mrp_product_expiry/models/mrp_abstract_workorder.py
new file mode 100644
index 00000000000..77bae4eb238
--- /dev/null
+++ b/addons/mrp_product_expiry/models/mrp_abstract_workorder.py
@@ -0,0 +1,31 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import models, _
+
+
+class MrpAbstractWorkorder(models.AbstractModel):
+ _inherit = 'mrp.abstract.workorder'
+
+ def _check_expired_lots(self):
+ # We use the 'skip_expired' context key to avoid to make the check when
+ # user already confirmed the wizard about using expired lots.
+ if self.env.context.get('skip_expired'):
+ return False
+ expired_lot_ids = self.raw_workorder_line_ids.filtered(lambda ml: ml.lot_id.product_expiry_alert).lot_id.ids
+ if expired_lot_ids:
+ return {
+ 'name': _('Confirmation'),
+ 'type': 'ir.actions.act_window',
+ 'res_model': 'expiry.picking.confirmation',
+ 'view_mode': 'form',
+ 'target': 'new',
+ 'context': self._get_expired_context(expired_lot_ids),
+ }
+
+ def _get_expired_context(self, expired_lot_ids):
+ context = dict(self.env.context)
+ context.update({
+ 'default_lot_ids': [(6, 0, expired_lot_ids)],
+ })
+ return context
diff --git a/addons/mrp_product_expiry/models/mrp_workorder.py b/addons/mrp_product_expiry/models/mrp_workorder.py
new file mode 100644
index 00000000000..9e7a04372de
--- /dev/null
+++ b/addons/mrp_product_expiry/models/mrp_workorder.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import models
+
+
+class MrpWorkorder(models.Model):
+ _inherit = 'mrp.workorder'
+
+ def record_production(self):
+ confirm_expired_lots = self._check_expired_lots()
+ if confirm_expired_lots:
+ return confirm_expired_lots
+ return super(MrpWorkorder, self).record_production()
+
+ def _get_expired_context(self, expired_lot_ids):
+ context = super(MrpWorkorder, self)._get_expired_context(expired_lot_ids)
+ context['default_workorder_id'] = self.id
+ return context
diff --git a/addons/mrp_product_expiry/tests/test_mrp_product_expiry.py b/addons/mrp_product_expiry/tests/test_mrp_product_expiry.py
index 209bde5886b..0633317f6b1 100644
--- a/addons/mrp_product_expiry/tests/test_mrp_product_expiry.py
+++ b/addons/mrp_product_expiry/tests/test_mrp_product_expiry.py
@@ -4,6 +4,7 @@
from datetime import datetime, timedelta
from odoo.addons.stock.tests.common import TestStockCommon
from odoo.tests.common import Form
+from odoo.exceptions import UserError
class TestStockProductionLot(TestStockCommon):
@@ -55,6 +56,23 @@ class TestStockProductionLot(TestStockCommon):
cls.location_stock = cls.env['stock.location'].browse(cls.stock_location)
+ # Creation of a routing
+ cls.workcenter = cls.env['mrp.workcenter'].create({
+ 'name': 'Bakery',
+ 'capacity': 2,
+ 'time_start': 10,
+ 'time_stop': 5,
+ 'time_efficiency': 80,
+ })
+ cls.routing = cls.env['mrp.routing'].create({'name': 'COOK'})
+ cls.operation = cls.env['mrp.routing.workcenter'].create({
+ 'name': 'Bake in the oven',
+ 'workcenter_id': cls.workcenter.id,
+ 'routing_id': cls.routing.id,
+ 'time_cycle': 15,
+ 'sequence': 1,
+ })
+
def test_01_product_produce(self):
""" Checks user doesn't get a confirmation wizard when they produces with
no expired components. """
@@ -99,3 +117,61 @@ class TestStockProductionLot(TestStockCommon):
# Producing must return a confirmation wizard.
self.assertNotEqual(res, None)
self.assertEqual(res['res_model'], 'expiry.picking.confirmation')
+
+ def test_03_workorder_without_expired_lot(self):
+ """ Checks user doesn't get a confirmation wizard when they makes a
+ workorder without expired components. """
+ # Set a routing on the BOM.
+ self.bom_apple_pie.routing_id = self.routing
+ # Creates the MO, starts it and plans the Work Order.
+ mo_form = Form(self.env['mrp.production'])
+ mo_form.product_id = self.product_apple_pie
+ mo_form.bom_id = self.bom_apple_pie
+ mo_form.product_qty = 1
+ mo = mo_form.save()
+ mo.action_confirm()
+ mo.button_plan()
+
+ wo = mo.workorder_ids[0]
+ wo.button_start()
+ # Set a non-expired lot.
+ wo.raw_workorder_line_ids.write({
+ 'qty_done': 3,
+ 'lot_id': self.lot_good_apple,
+ })
+
+ res = wo.record_production()
+ # Try to record the production using non-expired lot must not return a wizard.
+ self.assertEqual(res, True)
+ mo.button_mark_done()
+
+ def test_04_workorder_with_expired_lot(self):
+ """ Checks user doesn't get a confirmation wizard when they makes a
+ workorder without expired components. """
+ # Set a routing on the BOM.
+ self.bom_apple_pie.routing_id = self.routing
+ # Creates the MO, starts it and plans the Work Order.
+ mo_form = Form(self.env['mrp.production'])
+ mo_form.product_id = self.product_apple_pie
+ mo_form.bom_id = self.bom_apple_pie
+ mo_form.product_qty = 1
+ mo = mo_form.save()
+ mo.action_confirm()
+ mo.button_plan()
+
+ wo = mo.workorder_ids[0]
+ wo.button_start()
+ # Set an expired lot.
+ wo.raw_workorder_line_ids.write({
+ 'qty_done': 3,
+ 'lot_id': self.lot_expired_apple,
+ })
+
+ res = wo.record_production()
+ # Try to record the production using expired lot must return a
+ # confirmation wizard.
+ self.assertNotEqual(res, None)
+ self.assertEqual(res['res_model'], 'expiry.picking.confirmation')
+ with self.assertRaises(UserError):
+ # Cannot finish the MO as the Work Order is still ongoing.
+ mo.button_mark_done()
diff --git a/addons/mrp_product_expiry/wizard/confirm_expiry.py b/addons/mrp_product_expiry/wizard/confirm_expiry.py
index 3ff319729c5..d754c070253 100644
--- a/addons/mrp_product_expiry/wizard/confirm_expiry.py
+++ b/addons/mrp_product_expiry/wizard/confirm_expiry.py
@@ -8,10 +8,11 @@ class ConfirmExpiry(models.TransientModel):
_inherit = 'expiry.picking.confirmation'
produce_id = fields.Many2one('mrp.product.produce', readonly=True)
+ workorder_id = fields.Many2one('mrp.workorder', readonly=True)
@api.depends('lot_ids')
def _compute_descriptive_fields(self):
- if self.produce_id:
+ if self.produce_id or self.workorder_id:
# Shows expired lots only if we are more than one expired lot.
self.show_lots = len(self.lot_ids) > 1
if self.show_lots:
@@ -35,6 +36,9 @@ class ConfirmExpiry(models.TransientModel):
def confirm_produce(self):
return self.produce_id.with_context(skip_expired=True).do_produce()
+ def confirm_workorder(self):
+ return self.workorder_id.with_context(skip_expired=True).record_production()
+
def return_to_produce_wizard(self):
production = self.produce_id.production_id
action = production.open_produce_product()
diff --git a/addons/mrp_product_expiry/wizard/confirm_expiry_view.xml b/addons/mrp_product_expiry/wizard/confirm_expiry_view.xml
index 7a6444bd5c2..d483c624070 100644
--- a/addons/mrp_product_expiry/wizard/confirm_expiry_view.xml
+++ b/addons/mrp_product_expiry/wizard/confirm_expiry_view.xml
@@ -8,6 +8,7 @@
+
{'invisible': [('picking_ids', '=', [])]}
@@ -30,6 +31,12 @@
type="object"
attrs="{'invisible': [('produce_id', '=', False)]}"
class="btn-secondary"/>
+
+
diff --git a/addons/mrp_product_expiry/wizard/mrp_product_produce.py b/addons/mrp_product_expiry/wizard/mrp_product_produce.py
index 12def645ad9..fd6c6faade0 100644
--- a/addons/mrp_product_expiry/wizard/mrp_product_produce.py
+++ b/addons/mrp_product_expiry/wizard/mrp_product_produce.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
-from odoo import models, _
+from odoo import models
class MrpProductProduce(models.TransientModel):
@@ -13,24 +13,7 @@ class MrpProductProduce(models.TransientModel):
return confirm_expired_lots
return super(MrpProductProduce, self).do_produce()
- def _check_expired_lots(self):
- # We use the 'dont_check_expired' context key to avoid to make the check
- # when user did already confirmed the wizard about using expired lots.
- if self.env.context.get('dont_check_expired'):
- return False
- expired_lot_ids = []
- for line in self.raw_workorder_line_ids:
- if line.lot_id and line.lot_id.product_expiry_alert:
- expired_lot_ids += [line.lot_id.id]
- if expired_lot_ids:
- return {
- 'name': _('Confirmation'),
- 'type': 'ir.actions.act_window',
- 'res_model': 'expiry.picking.confirmation',
- 'view_mode': 'form',
- 'target': 'new',
- 'context': {
- 'default_produce_id': self.id,
- 'default_lot_ids': [(6, 0, expired_lot_ids)],
- }
- }
+ def _get_expired_context(self, expired_lot_ids):
+ context = super(MrpProductProduce, self)._get_expired_context(expired_lot_ids)
+ context['default_produce_id'] = self.id
+ return context