Skip to content

Commit

Permalink
Merge PR #357 into 14.0
Browse files Browse the repository at this point in the history
Signed-off-by etobella
  • Loading branch information
OCA-git-bot committed Oct 23, 2023
2 parents b90fbe2 + ff61454 commit 331a109
Show file tree
Hide file tree
Showing 9 changed files with 175 additions and 3 deletions.
28 changes: 27 additions & 1 deletion maintenance_plan/models/maintenance_equipment.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ class MaintenanceEquipment(models.Model):
string="Maintenance Plan Count",
store=True,
)
search_maintenance_plan_count = fields.Integer(
compute="_compute_search_maintenance_plan_count",
string="Maintenance All Plan Count",
)
maintenance_team_required = fields.Boolean(compute="_compute_team_required")
notes = fields.Text(string="Notes")

Expand All @@ -30,6 +34,15 @@ def _compute_maintenance_plan_count(self):
equipment.with_context(active_test=False).maintenance_plan_ids
)

@api.depends("maintenance_plan_ids")
def _compute_search_maintenance_plan_count(self):
for equipment in self:
equipment.search_maintenance_plan_count = (
self.env["maintenance.plan"]
.with_context(active_test=False)
.search_count([("search_equipment_id", "=", equipment.id)])
)

@api.depends("maintenance_plan_ids")
def _compute_team_required(self):
for equipment in self:
Expand All @@ -55,6 +68,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 +147,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
49 changes: 49 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,44 @@ 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")
search_equipment_id = fields.Many2one(
comodel_name="maintenance.equipment",
compute="_compute_search_equipment",
search="_search_search_equipment",
)

@api.model
def _search_search_equipment(self, operator, value):
if operator != "=" or not value:
raise ValueError(_("Unsupported search operator"))
plans = self.search([("generate_with_domain", "=", True)])
plan_ids = []
equipment = self.env["maintenance.equipment"].browse(value)
for plan in plans:
if equipment.filtered_domain(
safe_eval.safe_eval(
plan.generate_domain or "[]", plan._get_eval_context()
)
):
plan_ids.append(plan.id)
return ["|", ("equipment_id", "=", value), ("id", "in", plan_ids)]

@api.depends("equipment_id")
def _compute_search_equipment(self):
for record in self:
record.search_equipment_id = record.equipment_id

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 +248,13 @@ 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 or "[]", 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"))
2 changes: 1 addition & 1 deletion maintenance_plan/views/maintenance_equipment_views.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
>
<field
string="Plans"
name="maintenance_plan_count"
name="search_maintenance_plan_count"
widget="statinfo"
/>
</button>
Expand Down
12 changes: 11 additions & 1 deletion 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 Expand Up @@ -181,7 +191,7 @@
'default_equipment_id': active_id, 'hide_equipment_id': 0
}</field>
<field name="domain">['|', ('active', '=', True), ('active', '=',
False), ('equipment_id', '=', active_id)]
False), ('search_equipment_id', '=', active_id)]
</field>
</record>
<menuitem
Expand Down

0 comments on commit 331a109

Please sign in to comment.