Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 15 additions & 14 deletions maintenance_plan/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,10 @@ Despite Odoo's built-in recurrence functionality included in the
maintenance requests themselves (since 17.0), this module could be
needed for some reasons:

- Odoo implementation is javascript only
- Some companies already work with the existing "Maintenance Plan"
workflow
- Some modules are depending on this one
- Odoo implementation is javascript only
- Some companies already work with the existing "Maintenance Plan"
workflow
- Some modules are depending on this one

For reference, this module was initially set deprecated when migrated to
17.0:
Expand Down Expand Up @@ -131,16 +131,17 @@ Authors
Contributors
------------

- Akim Juillerat <akim.juillerat@camptocamp.com>
- Matteo Mazzoni <matteo@appcademy.tech>
- David Alonso <david.alonso@solvos.es>
- Adrià Gil Sorribes <adria.gil@forgeflow.com>
- Jordi Ballester Alomar <jordi.ballester@forgeflow.com>
- Lois Rilo <lois.rilo@forgeflow.com>
- Enric Tobella <enric.tobella@dixmit.com>
- Alexei Rivera <arivera@archeti.com>
- Yann Papouin <ypa@decgroupe.com>
- Yannick Payot <yannick.payot@acsone.eu>
- Akim Juillerat <akim.juillerat@camptocamp.com>
- Matteo Mazzoni <matteo@appcademy.tech>
- David Alonso <david.alonso@solvos.es>
- Adrià Gil Sorribes <adria.gil@forgeflow.com>
- Jordi Ballester Alomar <jordi.ballester@forgeflow.com>
- Lois Rilo <lois.rilo@forgeflow.com>
- Enric Tobella <enric.tobella@dixmit.com>
- Alexei Rivera <arivera@archeti.com>
- Yann Papouin <ypa@decgroupe.com>
- Yannick Payot <yannick.payot@acsone.eu>
- Carlos Espinosa <carlos.espinosa@ffp.mx>

Maintainers
-----------
Expand Down
2 changes: 1 addition & 1 deletion maintenance_plan/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
{
"name": "Maintenance Plan",
"summary": "Extends preventive maintenance planning",
"version": "19.0.1.0.0",
"version": "19.0.1.0.1",
"author": "Camptocamp SA, ForgeFlow, Odoo Community Association (OCA)",
"license": "AGPL-3",
"category": "Maintenance",
Expand Down
63 changes: 25 additions & 38 deletions maintenance_plan/hooks.py
Original file line number Diff line number Diff line change
@@ -1,47 +1,34 @@
# Copyright 2017 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

import logging

from odoo.exceptions import UserError
_logger = logging.getLogger(__name__)


def post_init_hook(env):
logging.getLogger("odoo.addons.maintenance_plan").info(
"Migrating existing preventive maintenance"
)
"""Create a maintenance plan for equipments that had an expected MTBF.

Odoo 19 removed ``maintenance.equipment.next_action_date`` and
``maintenance.equipment.mtbf``; the original migration relied on both and
raised ``AttributeError`` on install. We now derive the plan interval from
``expected_mtbf`` (expressed in days) and no longer try to tag a specific
preventive request by its (now inexistent) next action date.
"""
_logger.info("Migrating existing preventive maintenance")
equipments = env["maintenance.equipment"].search([("expected_mtbf", "!=", False)])

if equipments:
maintenance_kind = env["maintenance.kind"].create(
{"name": "Install", "active": True}
)

for equipment in equipments:
request = equipment.maintenance_ids.filtered(
lambda r, equipment=equipment: r.maintenance_type == "preventive"
and not r.stage_id.done
and r.request_date == equipment.next_action_date
)
if len(request) > 1:
raise UserError(
env._(
"You have multiple preventive maintenance requests on "
"equipment %(name)s next action date (%(date)s). "
"Please leave only one preventive request on the "
"date of equipment's next action to install the module.",
name=equipment.name,
date=equipment.next_action_date,
)
)
elif len(request) == 1:
request.write({"maintenance_kind_id": maintenance_kind.id})
env["maintenance.plan"].create(
{
"equipment_id": equipment.id,
"maintenance_kind_id": maintenance_kind.id,
"duration": equipment.mtbf,
"interval": equipment.expected_mtbf,
}
)
if not equipments:
return
maintenance_kind = env["maintenance.kind"].create(
{"name": "Install", "active": True}
)
env["maintenance.plan"].create(
[
{
"equipment_id": equipment.id,
"maintenance_kind_id": maintenance_kind.id,
"interval": equipment.expected_mtbf,
"interval_step": "day",
}
for equipment in equipments
]
)
1 change: 1 addition & 0 deletions maintenance_plan/readme/CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@
- Alexei Rivera \<<arivera@archeti.com>\>
- Yann Papouin \<<ypa@decgroupe.com>\>
- Yannick Payot \<<yannick.payot@acsone.eu>\>
- Carlos Espinosa \<<carlos.espinosa@ffp.mx>\>
1 change: 1 addition & 0 deletions maintenance_plan/static/description/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,7 @@ <h3><a class="toc-backref" href="#toc-entry-7">Contributors</a></h3>
<li>Alexei Rivera &lt;<a class="reference external" href="mailto:arivera&#64;archeti.com">arivera&#64;archeti.com</a>&gt;</li>
<li>Yann Papouin &lt;<a class="reference external" href="mailto:ypa&#64;decgroupe.com">ypa&#64;decgroupe.com</a>&gt;</li>
<li>Yannick Payot &lt;<a class="reference external" href="mailto:yannick.payot&#64;acsone.eu">yannick.payot&#64;acsone.eu</a>&gt;</li>
<li>Carlos Espinosa &lt;<a class="reference external" href="mailto:carlos.espinosa&#64;ffp.mx">carlos.espinosa&#64;ffp.mx</a>&gt;</li>
</ul>
</div>
<div class="section" id="maintainers">
Expand Down
1 change: 1 addition & 0 deletions maintenance_plan/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
from . import test_maintenance_plan
from . import test_maintenance_plan_domain
from . import test_post_init_hook
42 changes: 42 additions & 0 deletions maintenance_plan/tests/test_post_init_hook.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Copyright 2017 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo.tests.common import tagged

from odoo.addons.base.tests.common import BaseCommon

from ..hooks import post_init_hook


@tagged("post_install", "-at_install")
class TestPostInitHook(BaseCommon):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.equipment_obj = cls.env["maintenance.equipment"]
cls.plan_obj = cls.env["maintenance.plan"]

def test_post_init_hook_creates_plan_from_expected_mtbf(self):
"""A plan is created for each equipment with an expected MTBF."""
equipment = self.equipment_obj.create(
{"name": "Equipment with MTBF", "expected_mtbf": 30}
)
self.assertFalse(equipment.maintenance_plan_ids)

post_init_hook(self.env)

plans = self.plan_obj.search([("equipment_id", "=", equipment.id)])
self.assertEqual(len(plans), 1)
plan = plans
# Interval is derived from expected_mtbf, expressed in days.
self.assertEqual(plan.interval, 30)
self.assertEqual(plan.interval_step, "day")
self.assertEqual(plan.maintenance_kind_id.name, "Install")

def test_post_init_hook_ignores_equipment_without_mtbf(self):
"""Equipment without an expected MTBF gets no plan from the hook."""
equipment = self.equipment_obj.create({"name": "Equipment without MTBF"})

post_init_hook(self.env)

plans = self.plan_obj.search([("equipment_id", "=", equipment.id)])
self.assertFalse(plans)
Loading