Create module mrp_workorder_lock_planning

This commit is contained in:
Akim Juillerat
2023-02-07 17:50:41 +01:00
parent 21e1770a47
commit d90571b85f
12 changed files with 239 additions and 0 deletions

View File

@@ -0,0 +1 @@
to be generated

View File

@@ -0,0 +1 @@
from . import models

View File

@@ -0,0 +1,21 @@
# Copyright 2023 Camptocamp SA
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
{
"name": "MRP Workorder Lock Planning",
"summary": "Lock the planning of a MRP workorder to avoid rescheduling",
"version": "15.0.1.0.0",
"development_status": "Beta",
"category": "Manufacturing/Manufacturing",
"website": "https://github.com/OCA/manufacture",
"author": "Camptocamp, Odoo Community Association (OCA)",
"maintainers": ["grindtildeath"],
"license": "AGPL-3",
"application": False,
"installable": True,
"depends": [
"mrp",
],
"data": [
"views/mrp_workorder.xml",
],
}

View File

@@ -0,0 +1 @@
from . import mrp_workorder

View File

@@ -0,0 +1,45 @@
# Copyright 2023 Camptocamp SA
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError
class MrpWorkorder(models.Model):
_inherit = "mrp.workorder"
lock_planning = fields.Boolean(
help="If set, any change to the planning will be restricted",
readonly=True,
)
@api.constrains("lock_planning")
def _check_lock_planning(self):
for workorder in self:
if not workorder.lock_planning:
continue
if not (workorder.date_planned_start and workorder.date_planned_finished):
raise ValidationError(
_("Cannot lock planning of workorder if workorder is not planned")
)
@api.constrains(
"date_planned_start",
"date_planned_finished",
"duration_expected",
"workcenter_id",
)
def _check_lock_planning_fields(self):
for workorder in self:
if not workorder.lock_planning:
continue
raise ValidationError(
_(
"Workorder is locked and modification of Scheduled dates, "
"Expected duration or Workcenter is not allowed. "
"Please unlock the planning first."
)
)
def toggle_lock_planning(self):
self.ensure_one()
self.lock_planning = not self.lock_planning

View File

@@ -0,0 +1 @@
* Akim Juillerat <akim.juillerat@camptocamp.com>

View File

@@ -0,0 +1,4 @@
This module allows to lock the planning of workorders to avoid
any unintended rescheduling.
A Lock/Unlock button will be displayed once a workorder is planned.

View File

@@ -0,0 +1,37 @@
# Copyright 2023 Camptocamp SA
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
from odoo.exceptions import ValidationError
from odoo.tests import Form, TransactionCase
class TestMrpWorkorderLockDatePlanned(TransactionCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.bom_with_routing = cls.env.ref("mrp.mrp_bom_drawer_rout")
cls.product_with_routing = (
cls.bom_with_routing.product_tmpl_id.product_variant_id
)
@classmethod
def _create_manufacturing_order(cls, qty=1.0):
mo_form = Form(cls.env["mrp.production"])
mo_form.product_id = cls.product_with_routing
mo_form.bom_id = cls.bom_with_routing
mo_form.product_qty = qty
return mo_form.save()
def test_lock_planning_cannot_lock(self):
mo = self._create_manufacturing_order()
mo.action_confirm()
with self.assertRaisesRegex(ValidationError, "Cannot lock planning"):
mo.workorder_ids[0].toggle_lock_planning()
def test_lock_planning_is_locked(self):
mo = self._create_manufacturing_order()
mo.action_confirm()
mo.button_plan()
mo.workorder_ids[0].toggle_lock_planning()
self.assertTrue(mo.workorder_ids[0].lock_planning)
with self.assertRaisesRegex(ValidationError, "Workorder is locked"):
mo.button_unplan()

View File

@@ -0,0 +1,121 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record model="ir.ui.view" id="mrp_production_workorder_tree_editable_view_inherit">
<field name="name">mrp.production.work.order.tree.editable.inherit</field>
<field name="model">mrp.workorder</field>
<field
name="inherit_id"
ref="mrp.mrp_production_workorder_tree_editable_view"
/>
<field name="arch" type="xml">
<field name="date_planned_start" position="before">
<field name="lock_planning" invisible="1" />
<button
name="toggle_lock_planning"
type="object"
class="fa fa-unlock"
title="Lock planning"
string="Lock"
attrs="{'invisible': ['|', '|', ('lock_planning', '=', True), ('date_planned_start', '=', False),('date_planned_finished', '=', False)]}"
/>
<button
name="toggle_lock_planning"
type="object"
class="fa fa-lock text-danger"
title="Unlock planning"
string="Unlock"
attrs="{'invisible': [('lock_planning', '=', False)]}"
/>
</field>
<field name="date_planned_start" position="attributes">
<attribute
name="attrs"
>{'readonly': [('lock_planning', '=', True)]}</attribute>
<attribute name="force_save">1</attribute>
</field>
<field name="date_planned_finished" position="attributes">
<attribute
name="attrs"
>{'readonly': [('lock_planning', '=', True)]}</attribute>
<attribute name="force_save">1</attribute>
</field>
<field name="duration_expected" position="attributes">
<attribute
name="attrs"
>{'readonly': [('lock_planning', '=', True)]}</attribute>
<attribute name="force_save">1</attribute>
</field>
<field name="workcenter_id" position="attributes">
<attribute
name="attrs"
>{'readonly': [('lock_planning', '=', True)]}</attribute>
<attribute name="force_save">1</attribute>
</field>
</field>
</record>
<record model="ir.ui.view" id="mrp_production_workorder_form_view_inherit">
<field name="name">mrp.production.work.order.form.inherit</field>
<field name="model">mrp.workorder</field>
<field name="inherit_id" ref="mrp.mrp_production_workorder_form_view_inherit" />
<field name="arch" type="xml">
<xpath expr="//field[@name='json_popover']" position="after">
<field name="lock_planning" invisible="1" />
<button
name="toggle_lock_planning"
type="object"
class="fa fa-unlock"
title="Lock planning"
string="Lock"
attrs="{'invisible': ['|', '|', ('lock_planning', '=', True), ('date_planned_start', '=', False),('date_planned_finished', '=', False)]}"
/>
<button
name="toggle_lock_planning"
type="object"
class="fa fa-lock text-danger"
title="Unlock planning"
string="Unlock"
attrs="{'invisible': [('lock_planning', '=', False)]}"
/>
</xpath>
<field name="date_planned_start" position="attributes">
<attribute
name="attrs"
>{'readonly': [('lock_planning', '=', True)]}</attribute>
<attribute name="force_save">1</attribute>
</field>
<field name="date_planned_finished" position="attributes">
<attribute
name="attrs"
>{'readonly': [('lock_planning', '=', True)]}</attribute>
<attribute name="force_save">1</attribute>
</field>
<field name="duration_expected" position="attributes">
<attribute
name="attrs"
>{'readonly': [('lock_planning', '=', True)]}</attribute>
<attribute name="force_save">1</attribute>
</field>
<field name="workcenter_id" position="attributes">
<attribute
name="attrs"
>{'readonly': [('lock_planning', '=', True)]}</attribute>
<attribute name="force_save">1</attribute>
</field>
</field>
</record>
<record id="mrp_workorder_view_gantt_inherit" model="ir.ui.view">
<field name="name">mrp.workorder.view.gantt.inherit</field>
<field name="model">mrp.workorder</field>
<field name="inherit_id" ref="mrp.mrp_workorder_view_gantt" />
<field name="arch" type="xml">
<field name="json_popover" position="after">
<field name="lock_planning" />
</field>
<xpath expr="//ul" position="inside">
<li t-if="lock_planning" class="text-danger"><span
class="fa fa-lock"
> </span><strong>Locked planning</strong></li>
</xpath>
</field>
</record>
</odoo>

View File

@@ -0,0 +1 @@
../../../../mrp_workorder_lock_planning

View File

@@ -0,0 +1,6 @@
import setuptools
setuptools.setup(
setup_requires=['setuptools-odoo'],
odoo_addon=True,
)