[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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user