[IMP] mrp_product_expiry: wo confirmation

With product_expiry, when a workorder is done, we check if there is
expired lot in components. If it is, we ask confirmation to the user.

Task #1938656

closes odoo/odoo#36680

Signed-off-by: Simon Lejeune (sle) <sle@openerp.com>
This commit is contained in:
svs-odoo
2019-10-25 13:50:37 +00:00
parent a953898837
commit 1455e130c9
8 changed files with 149 additions and 23 deletions
+1
View File
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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()
@@ -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()
@@ -8,6 +8,7 @@
<xpath expr="//field[@name='description']" position="after">
<field name="picking_ids" invisible="1"/>
<field name="produce_id" invisible="1"/>
<field name="workorder_id" invisible="1"/>
</xpath>
<xpath expr="//button[@name='process']" position="attributes">
<attribute name="attrs">{'invisible': [('picking_ids', '=', [])]}</attribute>
@@ -30,6 +31,12 @@
type="object"
attrs="{'invisible': [('produce_id', '=', False)]}"
class="btn-secondary"/>
<!-- From a Workorder -->
<button name="confirm_workorder"
string="Confirm"
type="object"
attrs="{'invisible': [('workorder_id', '=', False)]}"
class="btn-primary"/>
</xpath>
</field>
</record>
@@ -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