-
-
Notifications
You must be signed in to change notification settings - Fork 166
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[17.0][MIG] maintenance_plan: Migration to 17.0 #414
Merged
OCA-git-bot
merged 112 commits into
OCA:17.0
from
FernandoRomera:17.0-mig-maintenance_plan
Aug 8, 2024
Merged
Changes from all commits
Commits
Show all changes
112 commits
Select commit
Hold shift + click to select a range
d296e6c
[ADD] maintenance_plan module (#2)
grindtildeath 9b9813f
[FIX] maintenance_plan: README try me on runbot link
pedrobaeza 225fde2
[MIG] maintenance_plan: Migration to 11.0
bestmazzo 95edee4
[FIX] maintenance_plan: prevent preventive request cron crashing when…
dalonsod 0a2b3ea
[MIG] maintenance_plan: Migration to 12.0
dalonsod ac937bf
Added translation using Weblate (Spanish)
lromero-solvos bcb0fcf
Translated using Weblate (Spanish)
lromero-solvos fd716aa
Added translation using Weblate (Chinese (Simplified))
liweijie0812 f795f91
[FIX] maintenance_plan: cron generated request should inherit equipme…
dalonsod 8a9569b
[FIX] maintenance_plan: next_maintenance_date should be stored
dalonsod 10cd585
[12.0][IMP] maintenance_plan
AdriaGForgeFlow bc4d4fa
[11.0][IMP] maintenance_plan: Return the created requests
etobella ea14a88
[12.0][FIX] maintenance_project_plan
etobella d0ab0fe
[12.0][FIX] default equipment_id in plans
7931358
[12.0][IMP] maintenance_plan: Add team on plans
etobella ebe16c1
[FIX] maintenance_plan: prevent False as display name when name is empty
dalonsod 39b8a82
Translated using Weblate (Spanish)
dalonsod 152f8b8
[IMP] maintenance_plan: black, isort
NuriaXifre 6a5739d
[13.0][MIG] maintenance_plan
NuriaXifre 0effcc2
[12.0][IMP] maintenance_plan: no equipment
2ae1f3e
[FIX]maintenance_plan migration scripts not applicable in v13
AaronHForgeFlow e565d08
[13.0][IMP] maintenance_plan: make maintenance plan multi-company com…
LoisRForgeFlow 0fb7131
maintenance_plan: manual version bump
LoisRForgeFlow 357e12c
[IMP] maintenance_plan: black, isort, prettier
dalonsod 61f5718
[MIG] maintenance_plan: Migration to 14.0
dalonsod eba10d2
Added translation using Weblate (Italian)
mymage d190cd6
Translated using Weblate (Italian)
mymage eff1ae6
[FIX] maintenance_plan: Remake the computation of next date
etobella 9e6604d
Translated using Weblate (Italian)
mymage b07a3ae
[IMP] maintenance_plan: next maintenance date tweaks
LoisRForgeFlow ba31d37
Translated using Weblate (Italian)
mymage a84e03b
[IMP] maintenance_plan: black, isort, prettier
BernatPForgeFlow 488779f
[MIG] maintenance_plan: Migration to 15.0
BernatPForgeFlow 85d45d2
[UPD] Update maintenance_plan.pot
44861e4
[UPD] README.rst
OCA-git-bot 87f114a
[FIX] maintenance_plan: fix new request date when plan start date is …
mariadforgeflow 03e362d
maintenance_plan 15.0.1.0.1
OCA-git-bot 8f5d16c
[FIX] maintenance_plan: avoid error if planning_step is not defined
MiquelRForgeFlow 0f542b6
[IMP] maintenance_plan: add chatter
mariadforgeflow 68f2d79
[UPD] Update maintenance_plan.pot
62ab917
maintenance_plan 15.0.1.1.0
OCA-git-bot ccb1f1c
Update translation files
oca-transbot f011bf4
maintenance_plan 15.0.1.1.1
OCA-git-bot 030bdfd
[15.0][FIX] maintenance_plan generate requests for inactive equipment
sergiocorato c461ef6
maintenance_plan 15.0.1.1.2
OCA-git-bot 9bafbb8
Translated using Weblate (Italian)
mymage 3c05e38
Translated using Weblate (Italian)
mymage f0e884a
[REF] moving function get_relativedelta to method
mymage 3d430c4
Added translation using Weblate (Portuguese)
pedrocs-exo ecacc91
Translated using Weblate (Portuguese)
pedrocs-exo 1042be0
Translated using Weblate (Portuguese)
pedrocs-exo 7ab750c
[UPD] Update maintenance_plan.pot
30aed71
maintenance_plan 15.0.1.2.0
OCA-git-bot 16ca967
Update translation files
weblate 579769f
Translated using Weblate (Italian)
mymage 937590f
Translated using Weblate (Italian)
mymage 53025bb
Translated using Weblate (Italian)
francesco-ooops d4fdec7
Translated using Weblate (Italian)
francesco-ooops b1ebfca
Translated using Weblate (Italian)
francesco-ooops e82ffaf
Translated using Weblate (Italian)
mymage 5909f6d
Translated using Weblate (Italian)
mymage 30d8ea9
[FIX] maintenance_plan: fix maintence request form view
kluna1998 fb0a701
[UPD] Update maintenance_plan.pot
ede4c25
maintenance_plan 15.0.1.3.0
OCA-git-bot 3f18f14
Update translation files
weblate d00535e
[IMP] maintenance_plan: Add instructions to request report.
victoralmau b789989
[UPD] Update maintenance_plan.pot
17ecdcd
maintenance_plan 15.0.1.4.0
OCA-git-bot 7af9381
Update translation files
weblate d4c5eda
[IMP] maintenance_plan: Add Generate requests for current threshold b…
victoralmau f4982e5
[UPD] Update maintenance_plan.pot
32b71d6
maintenance_plan 15.0.1.5.0
OCA-git-bot 0cd4df0
Update translation files
weblate d2d23f3
[IMP] maintenance_plan: Set planned_hours in request from plan if mai…
victoralmau 3b1493c
maintenance_plan 15.0.1.5.1
OCA-git-bot 339ac3b
[IMP] maintenance_plan: Skip assigned mail + Activity mail of the req…
victoralmau 61f216d
[UPD] Update maintenance_plan.pot
c6856dc
maintenance_plan 15.0.1.6.0
OCA-git-bot dc0746a
Update translation files
weblate 0699a70
[IMP] maintenance_plan: Change tests to allow inheritance
victoralmau 8dfb607
maintenance_plan 15.0.1.6.1
OCA-git-bot 78714e7
Translated using Weblate (Italian)
mymage 43f83d8
Translated using Weblate (Italian)
mymage 13e9895
Translated using Weblate (Italian)
mymage da9f923
[IMP] maintenance_plan: Add rules to maintenance.plan to view records…
victoralmau 660082b
maintenance_plan 15.0.1.7.0
OCA-git-bot 92ee685
Translated using Weblate (Italian)
francesco-ooops d0a4555
Translated using Weblate (Italian)
francesco-ooops 4699fdf
Translated using Weblate (Italian)
francesco-ooops 36c0bf8
Translated using Weblate (Spanish)
Ivorra78 dbeae46
Translated using Weblate (Spanish)
Ivorra78 7204025
Translated using Weblate (Italian)
francesco-ooops 2a71c9f
Translated using Weblate (Italian)
mymage 28db409
[UPD] README.rst
OCA-git-bot 7fbe6ce
Translated using Weblate (Spanish)
Ivorra78 404b723
[UPD] Update maintenance_plan.pot
5d4a28d
Update translation files
weblate 7a47d7c
[IMP] maintenance_plan: Add freeze_time to prevent errors in tests
victoralmau f841a90
[BOT] post-merge updates
OCA-git-bot 1af9f04
[IMP] maintenance_plan: Allow to generate generic plans for multiple …
etobella 6c08011
[FIX] maintenance_plan: The search must work with newIds
etobella 59c1219
[IMP] maintenance_plan: Add Team filter
etobella f2cfd78
[FIX] maintenance_plan: adapt tests
etobella fb15d40
[UPD] Update maintenance_plan.pot
f1f8e32
[BOT] post-merge updates
OCA-git-bot e15baf8
Update translation files
weblate d9c7fef
Translated using Weblate (Italian)
mymage 9fb9b89
[MIG] maintenance_plan: Migration to 16.0
alexeirivera87 6fe6c84
[UPD] Update maintenance_plan.pot
f1d5547
Translated using Weblate (Spanish)
Ivorra78 dea209f
[IMP] maintenance_plan: pre-commit auto fixes
FernandoRomera 9f99863
[MIG] maintenance_plan: Migration to 17.0
FernandoRomera File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
================ | ||
Maintenance Plan | ||
================ | ||
|
||
.. | ||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | ||
!! This file is generated by oca-gen-addon-readme !! | ||
!! changes will be overwritten. !! | ||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | ||
!! source digest: sha256:51d1395956daf1de19f24abe40f89528841450822d90006b04a75e26f1913828 | ||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | ||
|
||
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png | ||
:target: https://odoo-community.org/page/development-status | ||
:alt: Beta | ||
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png | ||
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html | ||
:alt: License: AGPL-3 | ||
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fmaintenance-lightgray.png?logo=github | ||
:target: https://github.com/OCA/maintenance/tree/17.0/maintenance_plan | ||
:alt: OCA/maintenance | ||
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png | ||
:target: https://translation.odoo-community.org/projects/maintenance-17-0/maintenance-17-0-maintenance_plan | ||
:alt: Translate me on Weblate | ||
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png | ||
:target: https://runboat.odoo-community.org/builds?repo=OCA/maintenance&target_branch=17.0 | ||
:alt: Try me on Runboat | ||
|
||
|badge1| |badge2| |badge3| |badge4| |badge5| | ||
|
||
This module extends the functionality of Odoo Maintenance module by | ||
allowing an equipment to have different preventive maintenance kinds. | ||
|
||
**Table of contents** | ||
|
||
.. contents:: | ||
:local: | ||
|
||
Installation | ||
============ | ||
|
||
Install the module. | ||
|
||
Should you already use the maintenance module and have equipments with | ||
field 'Preventive Maintenance Frequency' defined, a new maintenance plan | ||
will be automatically created on these equipments with maintenance kind | ||
'Install'. | ||
|
||
Moreover if a Request of type 'preventive' exists, whose stage isn't | ||
marked as 'Request done', and has a Request Date matching the | ||
equipment's 'Next Preventive Maintenance', the request will be updated | ||
with the 'Install' maintenance kind. | ||
|
||
Make sure you don't have multiple 'preventive' requests at a stage which | ||
isn't marked as 'Request done' and on the same 'Request date' as the | ||
equipment or the module installation will fail with a User Error. | ||
|
||
Usage | ||
===== | ||
|
||
Instead of defining a period and duration for only one preventive | ||
maintenance per equipment, you can define multiple preventive | ||
maintenance kind for each equipment. | ||
|
||
Maintenance Kinds have to be defined through the configuration menu. | ||
Their name have to be unique and can be set as active or inactive, | ||
should these not be used anymore. | ||
|
||
On any equipment over the maintenance tab, the maintenance plan be | ||
accessible, allowing to add different maintenance kind with their own | ||
frequency and duration. The next maintenance date will then be computed | ||
automatically according to the start's date and the frequency defined, | ||
but the maintenance request won't be created automatically as is the | ||
case in Odoo's Maintenance module. In the plan there's also a field | ||
allowing the user to set the maintenance horizon, insert the | ||
instructions to follow on the maintenance that will be forwarded to the | ||
maintenance request generated from the plan. | ||
|
||
This module uses the original Cron job of Odoo's Maintenance module to | ||
generate maintenance requests. To do so, it takes into account the | ||
planning horizon and generates all maintenance requests whose schedule | ||
date would fall inside that 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. | ||
|
||
Bug Tracker | ||
=========== | ||
|
||
Bugs are tracked on `GitHub Issues <https://github.com/OCA/maintenance/issues>`_. | ||
In case of trouble, please check there if your issue has already been reported. | ||
If you spotted it first, help us to smash it by providing a detailed and welcomed | ||
`feedback <https://github.com/OCA/maintenance/issues/new?body=module:%20maintenance_plan%0Aversion:%2017.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_. | ||
|
||
Do not contact contributors directly about support or help with technical issues. | ||
|
||
Credits | ||
======= | ||
|
||
Authors | ||
------- | ||
|
||
* Camptocamp SA | ||
* ForgeFlow | ||
|
||
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> | ||
|
||
Maintainers | ||
----------- | ||
|
||
This module is maintained by the OCA. | ||
|
||
.. image:: https://odoo-community.org/logo.png | ||
:alt: Odoo Community Association | ||
:target: https://odoo-community.org | ||
|
||
OCA, or the Odoo Community Association, is a nonprofit organization whose | ||
mission is to support the collaborative development of Odoo features and | ||
promote its widespread use. | ||
|
||
This module is part of the `OCA/maintenance <https://github.com/OCA/maintenance/tree/17.0/maintenance_plan>`_ project on GitHub. | ||
|
||
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
from . import models | ||
from .hooks import post_init_hook |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
# Copyright 2017 Camptocamp SA | ||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). | ||
{ | ||
"name": "Maintenance Plan", | ||
"summary": "Extends preventive maintenance planning", | ||
"version": "17.0.1.0.0", | ||
"author": "Camptocamp SA, ForgeFlow, Odoo Community Association (OCA)", | ||
"license": "AGPL-3", | ||
"category": "Maintenance", | ||
"website": "https://github.com/OCA/maintenance", | ||
"images": [], | ||
"depends": ["base_maintenance"], | ||
"data": [ | ||
"security/ir.model.access.csv", | ||
"security/maintenance_security.xml", | ||
"data/ir_cron.xml", | ||
"views/maintenance_kind_views.xml", | ||
"views/maintenance_plan_views.xml", | ||
"views/maintenance_equipment_views.xml", | ||
"views/report_maintenance_request.xml", | ||
], | ||
"external_dependencies": {"python": ["python-dateutil"]}, | ||
"demo": ["demo/demo_maintenance_plan.xml"], | ||
"post_init_hook": "post_init_hook", | ||
"installable": True, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<?xml version="1.0" encoding='UTF-8' ?> | ||
<odoo> | ||
<record id="maintenance_requests_cron" model="ir.cron"> | ||
<field name="name">Maintenance: generate preventive maintenance requests</field> | ||
<field name="model_id" ref="model_maintenance_equipment" /> | ||
<field name="state">code</field> | ||
<field name="code">model._cron_generate_requests()</field> | ||
<field name="interval_number">1</field> | ||
<field name="interval_type">days</field> | ||
<field name="numbercall">-1</field> | ||
<field name="doall" eval="False" /> | ||
</record> | ||
</odoo> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
<?xml version="1.0" encoding="utf-8" ?> | ||
<odoo noupdate="1"> | ||
<!-- Maintenance kinds --> | ||
<record id="maintenance_kind_monthly" model="maintenance.kind"> | ||
<field name="name">Monthly</field> | ||
<field name="active" eval="True" /> | ||
</record> | ||
<record id="maintenance_kind_weekly" model="maintenance.kind"> | ||
<field name="name">Weekly</field> | ||
<field name="active" eval="True" /> | ||
</record> | ||
<!-- Maintenance plans --> | ||
<record id="maintenance_plan_monthly_monitor1" model="maintenance.plan"> | ||
<field name="equipment_id" ref="maintenance.equipment_monitor1" /> | ||
<field name="maintenance_kind_id" ref="maintenance_kind_monthly" /> | ||
<field name="interval">1</field> | ||
<field name="interval_step">month</field> | ||
<field name="duration">2</field> | ||
<field name="maintenance_plan_horizon">2</field> | ||
<field name="planning_step">month</field> | ||
</record> | ||
<record id="maintenance_plan_monthly_monitor4" model="maintenance.plan"> | ||
<field name="equipment_id" ref="maintenance.equipment_monitor4" /> | ||
<field name="maintenance_kind_id" ref="maintenance_kind_monthly" /> | ||
<field name="interval">1</field> | ||
<field name="interval_step">month</field> | ||
<field name="duration">2</field> | ||
<field name="maintenance_plan_horizon">2</field> | ||
<field name="planning_step">month</field> | ||
</record> | ||
<record id="maintenance_plan_monthly_monitor6" model="maintenance.plan"> | ||
<field name="equipment_id" ref="maintenance.equipment_monitor6" /> | ||
<field name="maintenance_kind_id" ref="maintenance_kind_monthly" /> | ||
<field name="interval">1</field> | ||
<field name="interval_step">month</field> | ||
<field name="duration">2</field> | ||
<field name="maintenance_plan_horizon">1</field> | ||
<field name="planning_step">month</field> | ||
</record> | ||
<record id="maintenance_plan_monthly_printer1" model="maintenance.plan"> | ||
<field name="equipment_id" ref="maintenance.equipment_printer1" /> | ||
<field name="maintenance_kind_id" ref="maintenance_kind_monthly" /> | ||
<field name="interval">1</field> | ||
<field name="interval_step">month</field> | ||
<field name="duration">4</field> | ||
<field name="maintenance_plan_horizon">3</field> | ||
<field name="planning_step">month</field> | ||
</record> | ||
<record id="maintenance_plan_weekly_printer1" model="maintenance.plan"> | ||
<field name="equipment_id" ref="maintenance.equipment_printer1" /> | ||
<field name="maintenance_kind_id" ref="maintenance_kind_weekly" /> | ||
<field name="interval">7</field> | ||
<field name="duration">2</field> | ||
<field name="maintenance_plan_horizon">1</field> | ||
<field name="planning_step">month</field> | ||
</record> | ||
</odoo> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
# Copyright 2017 Camptocamp SA | ||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). | ||
|
||
import logging | ||
|
||
from odoo import _ | ||
from odoo.exceptions import UserError | ||
|
||
|
||
def post_init_hook(env): | ||
logging.getLogger("odoo.addons.maintenance_plan").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( | ||
_( | ||
"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, | ||
} | ||
) |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why this change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
B023 Function definition does not bind loop variable `equipment
https://docs.astral.sh/ruff/rules/function-uses-loop-variable/`
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see, it is a new requirement from ruff 👍