Skip to content

Commit

Permalink
[IMP] maintenance_plan: Allow to generate generic plans for multiple …
Browse files Browse the repository at this point in the history
…equipments defined with a domain
  • Loading branch information
etobella committed Sep 23, 2023
1 parent 9e24778 commit f4c0aa2
Show file tree
Hide file tree
Showing 8 changed files with 132 additions and 1 deletion.
15 changes: 14 additions & 1 deletion maintenance_plan/models/maintenance_equipment.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,19 @@ def _check_company_id(self):
)
)

def _prepare_requests_from_plan(self, maintenance_plan, next_maintenance_date):
if self:
return self._prepare_request_from_plan(
maintenance_plan, next_maintenance_date
)
equipments = maintenance_plan._get_maintenance_equipments()
return [
equipment._prepare_request_from_plan(
maintenance_plan, next_maintenance_date
)
for equipment in equipments
]

def _prepare_request_from_plan(self, maintenance_plan, next_maintenance_date):
team_id = maintenance_plan.maintenance_team_id.id or self.maintenance_team_id.id
request_model = self.env["maintenance.request"]
Expand Down Expand Up @@ -121,7 +134,7 @@ def _create_new_request(self, mtn_plan):
# Create maintenance request until we reach planning horizon
while next_maintenance_date <= horizon_date:
if next_maintenance_date >= fields.Date.today():
vals = self._prepare_request_from_plan(mtn_plan, next_maintenance_date)
vals = self._prepare_requests_from_plan(mtn_plan, next_maintenance_date)
requests |= request_model.create(vals)
next_maintenance_date = next_maintenance_date + mtn_plan.get_relativedelta(
mtn_plan.interval, mtn_plan.interval_step or "year"
Expand Down
21 changes: 21 additions & 0 deletions maintenance_plan/models/maintenance_plan.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

from odoo import _, api, fields, models
from odoo.exceptions import UserError, ValidationError
from odoo.tools import safe_eval


class MaintenancePlan(models.Model):
Expand Down Expand Up @@ -81,6 +82,18 @@ class MaintenancePlan(models.Model):
skip_notify_follower_on_requests = fields.Boolean(
string="Do not notify to follower when creating requests?", default=True
)
generate_with_domain = fields.Boolean()
generate_domain = fields.Char(string="Apply on")

def _get_eval_context(self):
"""Prepare the context used when evaluating python code
:returns: dict -- evaluation context given to safe_eval
"""
return {
"datetime": safe_eval.datetime,
"dateutil": safe_eval.dateutil,
"time": safe_eval.time,
}

def name_get(self):
result = []
Expand Down Expand Up @@ -209,3 +222,11 @@ def button_manual_request_generation(self):
for plan in self:
equipment = plan.equipment_id
equipment._create_new_request(plan)

def _get_maintenance_equipments(self):
self.ensure_one()
if self.generate_with_domain and not self.equipment_id:
return self.env["maintenance.equipment"].search(
safe_eval.safe_eval(self.generate_domain, self._get_eval_context())
)
return [self.equipment_id]
4 changes: 4 additions & 0 deletions maintenance_plan/readme/USAGE.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,7 @@ planning horizon. Therefore, the maintenance manager can have a proper planning
of how many maintenance requests are programming for the future. Leaving planning
horizon to 0 will only create those maintenance request that are scheduled for
today.

We can also create maintenance requests from a plan using a domain for selecting the equipments.
This way, we might have a single plan that will generate all the requests.
In order to use it, we need to mark the `Generate with Domain` field.
1 change: 1 addition & 0 deletions maintenance_plan/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
from . import test_maintenance_plan
from . import test_maintenance_plan_domain
9 changes: 9 additions & 0 deletions maintenance_plan/tests/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,13 @@ def setUpClass(cls):
"planning_step": "month",
}
)
cls.maintenance_plan_5 = cls.maintenance_plan_obj.create(
{
"start_maintenance_date": today,
"interval": 1,
"interval_step": "month",
"maintenance_plan_horizon": 2,
"planning_step": "month",
}
)
cls.report_obj = cls.env["ir.actions.report"]
35 changes: 35 additions & 0 deletions maintenance_plan/tests/test_maintenance_plan.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,41 @@ def test_generate_requests2(self):
self.today_date + relativedelta(weeks=9),
)

def test_generate_requests_no_equipment(self):
self.cron.method_direct_trigger()
generated_requests = self.maintenance_request_obj.search(
[("maintenance_plan_id", "=", self.maintenance_plan_5.id)],
order="schedule_date asc",
)

self.assertEqual(len(generated_requests), 3)

# We set plan start_maintenanca_date to a future one. New requests should take
# into account this new date.

self.maintenance_plan_5.write(
{
"start_maintenance_date": fields.Date.to_string(
self.today_date + timedelta(weeks=9)
),
"maintenance_plan_horizon": 3,
}
)

self.cron.method_direct_trigger()

generated_requests = self.maintenance_request_obj.search(
[("maintenance_plan_id", "=", self.maintenance_plan_5.id)],
order="schedule_date asc",
)

self.assertEqual(len(generated_requests), 4)
self.assertEqual(
generated_requests[-1].request_date,
self.today_date + relativedelta(weeks=9),
)
self.assertFalse(generated_requests.mapped("equipment_id"))

def test_get_relativedelta(self):
plan = self.maintenance_plan_1
result = plan.get_relativedelta(1, "day")
Expand Down
38 changes: 38 additions & 0 deletions maintenance_plan/tests/test_maintenance_plan_domain.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Copyright 2023 Dixmit
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

import json

from odoo.addons.maintenance_plan.tests.common import TestMaintenancePlanBase


class TestMaintenancePlanDomain(TestMaintenancePlanBase):
def test_generate_requests_no_domain(self):
self.cron.method_direct_trigger()
generated_requests = self.maintenance_request_obj.search(
[("maintenance_plan_id", "=", self.maintenance_plan_5.id)],
order="schedule_date asc",
)

self.assertEqual(len(generated_requests), 3)
self.assertFalse(generated_requests.mapped("equipment_id"))

def test_generate_requests_domain(self):
equipment_2 = self.maintenance_equipment_obj.create({"name": "Laptop 2"})
self.maintenance_plan_5.write(
{
"generate_with_domain": True,
"generate_domain": json.dumps(
[("id", "in", [equipment_2.id, self.equipment_1.id])]
),
}
)
self.cron.method_direct_trigger()
generated_requests = self.maintenance_request_obj.search(
[("maintenance_plan_id", "=", self.maintenance_plan_5.id)],
order="schedule_date asc",
)

self.assertEqual(len(generated_requests), 6)
self.assertIn(equipment_2, generated_requests.mapped("equipment_id"))
self.assertIn(self.equipment_1, generated_requests.mapped("equipment_id"))
10 changes: 10 additions & 0 deletions maintenance_plan/views/maintenance_plan_views.xml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,16 @@
name="maintenance_team_id"
attrs="{'required': [('equipment_id', '=', False)]}"
/>
<field
name="generate_with_domain"
attrs="{'invisible': [('equipment_id', '!=', False)]}"
/>
<field
name="generate_domain"
widget="domain"
options="{'model': 'maintenance.equipment', 'in_dialog': True}"
attrs="{'invisible': ['|', ('equipment_id', '!=', False), ('generate_with_domain', '=', False)]}"
/>
</group>
<group>
<field name="skip_notify_follower_on_requests" />
Expand Down

0 comments on commit f4c0aa2

Please sign in to comment.