Skip to content

Commit a24c5b3

Browse files
Merge pull request #20 from Escodoo/12.0-add-project_status_sla
[12.0][ADD] project_status_sla: add new module
2 parents c211819 + 5e7007e commit a24c5b3

22 files changed

+547
-2
lines changed

project_sla/models/project_task.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ def _update_sla_lines(self):
123123
):
124124
sla_line.status = "not_met"
125125

126-
if (sla_line.reached_date and sla_line.reached_date < sla_deadline):
126+
if sla_line.reached_date and sla_line.reached_date < sla_deadline:
127127
sla_line.status = "met"
128128
sla_lines.append(
129129
(
@@ -204,7 +204,8 @@ def _sync_all_sla_lines(self):
204204
and r.project_id.use_sla
205205
and (
206206
any(not p.reached_date for p in r.sla_line_ids)
207-
or not r.sla_line_ids)
207+
or not r.sla_line_ids
208+
)
208209
)
209210
)
210211
)

project_status_sla/README.rst

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
==================
2+
Project Status SLA
3+
==================
4+
5+
..
6+
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
7+
!! This file is generated by oca-gen-addon-readme !!
8+
!! changes will be overwritten. !!
9+
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
10+
!! source digest: sha256:0a0cd378a237876b5b3ec27927d63a9e10ef69d1dd9c027a7d92cfae15bb1a41
11+
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
12+
13+
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
14+
:target: https://odoo-community.org/page/development-status
15+
:alt: Beta
16+
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
17+
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
18+
:alt: License: AGPL-3
19+
.. |badge3| image:: https://img.shields.io/badge/github-Escodoo%2Fproject--addons-lightgray.png?logo=github
20+
:target: https://github.com/Escodoo/project-addons/tree/12.0/project_status_sla
21+
:alt: Escodoo/project-addons
22+
23+
|badge1| |badge2| |badge3|
24+
25+
This module adds SLA funcionality in Project Status module.
26+
27+
**Table of contents**
28+
29+
.. contents::
30+
:local:
31+
32+
Configuration
33+
=============
34+
35+
To configure this module, you need to:
36+
37+
#. Allow SLA for a Project
38+
39+
Allow SLA
40+
~~~~~~~~~~~~~~~
41+
42+
#. Go to Project > Configuration > Project Statuses SLA.
43+
#. Edit or create a new SLA.
44+
#. Select a Project.
45+
#. Select a Status.
46+
#. Select a days or hours for that SLA.
47+
48+
Usage
49+
=====
50+
51+
#. Go to *Project > Reports > Project Statuses SLA Lines * to see history SLA in Project.
52+
53+
Bug Tracker
54+
===========
55+
56+
Bugs are tracked on `GitHub Issues <https://github.com/Escodoo/project-addons/issues>`_.
57+
In case of trouble, please check there if your issue has already been reported.
58+
If you spotted it first, help us to smash it by providing a detailed and welcomed
59+
`feedback <https://github.com/Escodoo/project-addons/issues/new?body=module:%20project_status_sla%0Aversion:%2012.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
60+
61+
Do not contact contributors directly about support or help with technical issues.
62+
63+
Credits
64+
=======
65+
66+
Authors
67+
~~~~~~~
68+
69+
* Escodoo
70+
71+
Contributors
72+
~~~~~~~~~~~~
73+
74+
* `Escodoo <https://www.escodoo.com.br>`_:
75+
76+
* Marcel Savegnago <[email protected]>
77+
* Kaynnan Lemes <[email protected]>
78+
79+
Maintainers
80+
~~~~~~~~~~~
81+
82+
This module is part of the `Escodoo/project-addons <https://github.com/Escodoo/project-addons/tree/12.0/project_status_sla>`_ project on GitHub.
83+
84+
You are welcome to contribute.

project_status_sla/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from . import models

project_status_sla/__manifest__.py

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Copyright 2024 - TODAY, Escodoo
2+
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
3+
4+
{
5+
"name": "Project Status SLA",
6+
"summary": """
7+
Add SLA for Project Status""",
8+
"version": "12.0.1.0.0",
9+
"license": "AGPL-3",
10+
"author": "Escodoo",
11+
"website": "https://github.com/Escodoo/project-addons",
12+
"depends": [
13+
"project_status",
14+
],
15+
"data": [
16+
"data/project_status_sla_cron.xml",
17+
"security/ir.model.access.csv",
18+
"views/project_project.xml",
19+
"views/project_status_sla.xml",
20+
"views/project_status_sla_line.xml",
21+
],
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?xml version="1.0" encoding='UTF-8' ?>
2+
<odoo noupdate="1">
3+
<record model="ir.cron" id="project_status_sla_cron_alert">
4+
<field name="name">Generate Project Statuses SLA Alerts</field>
5+
<field name="model_id" ref="model_project_status_sla" />
6+
<field name="state">code</field>
7+
<field name="code">model.check_sla()</field>
8+
<field name="user_id" ref="base.user_root" />
9+
<field name="interval_number">5</field>
10+
<field name="interval_type">minutes</field>
11+
<field name="numbercall">-1</field>
12+
<field eval="False" name="doall" />
13+
</record>
14+
</odoo>

project_status_sla/models/__init__.py

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from . import project_project
2+
from . import project_status_sla
3+
from . import project_status_sla_line
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
# Copyright 2024 - TODAY, Kaynnan Lemes <[email protected]>
2+
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
3+
# flake8: noqa: B950
4+
5+
from odoo import _, fields, models
6+
7+
8+
class ProjectProject(models.Model):
9+
_inherit = "project.project"
10+
11+
sla_deadline = fields.Datetime(string="SLA Deadline")
12+
sla_expired = fields.Boolean(string="SLA Expired")
13+
14+
def _prepare_sla_message(self, sla_line, sla):
15+
"""Prepare the message to notify about the SLA status, including reached_date,
16+
SLA line ID, current stage, and estimated stage from project.status.sla."""
17+
current_stage = (
18+
self.project_status.name
19+
) # Assuming project_status is the current stage
20+
sla_stage = (
21+
sla.stage_id.name
22+
) # Fetching the estimated stage from project.status.sla
23+
24+
# Format the dates explicitly
25+
estimated_date = (
26+
sla_line.sla_deadline.strftime("%d/%m/%Y %H:%M")
27+
if sla_line.sla_deadline
28+
else "N/A"
29+
)
30+
reached_date = (
31+
sla_line.reached_date.strftime("%d/%m/%Y %H:%M")
32+
if sla_line.reached_date
33+
else "N/A"
34+
)
35+
36+
if self.sla_expired:
37+
message = _(
38+
"<p>The SLA for Project <b>%s</b> in Stage <b>%s</b> has been exceeded.</p>"
39+
"<p>Current Stage: <b>%s</b></p>"
40+
"<p>Estimated Stage: <b>%s</b></p>"
41+
"<p>SLA ID: <b>%s</b></p>"
42+
"<p>Estimated Date: <b>%s</b></p>"
43+
"<p>Reached Date: <b>%s</b></p>"
44+
% (
45+
self.name,
46+
current_stage,
47+
current_stage,
48+
sla_stage,
49+
sla.id,
50+
estimated_date,
51+
reached_date,
52+
)
53+
)
54+
else:
55+
message = _(
56+
"<p>The SLA for Project <b>%s</b> in Stage <b>%s</b> has been successfully met within the proposed deadline.</p>"
57+
"<p>Current Stage: <b>%s</b></p>"
58+
"<p>Estimated Stage: <b>%s</b></p>"
59+
"<p>SLA ID: <b>%s</b></p>"
60+
"<p>Estimated Date: <b>%s</b></p>"
61+
"<p>Reached Date: <b>%s</b></p>"
62+
% (
63+
self.name,
64+
current_stage,
65+
current_stage,
66+
sla_stage,
67+
sla.id,
68+
estimated_date,
69+
reached_date,
70+
)
71+
)
72+
return message
73+
74+
def _post_sla_message(self, sla_line, sla):
75+
"""Post a message to notify users about the SLA status, including additional information."""
76+
message = self._prepare_sla_message(sla_line, sla)
77+
self.message_post(
78+
body=message, message_type="notification", subtype="mail.mt_comment"
79+
)
80+
81+
def _prepare_sla_line_values(self, sla):
82+
"""Prepare the values to create an SLA line for the current project."""
83+
status = "not_met" if self.sla_expired else "met"
84+
return {
85+
"project_id": self.id,
86+
"stage_id": self.project_status.id, # Assuming project_status is the current stage
87+
"sla_id": sla.id,
88+
"sla_deadline": self.sla_deadline,
89+
"sla_expired": self.sla_expired,
90+
"reached_date": fields.Datetime.now(),
91+
"status": status,
92+
}
93+
94+
def _create_sla_line(self, sla):
95+
"""Create a new SLA line record for the project."""
96+
sla_line_vals = self._prepare_sla_line_values(sla)
97+
return self.env["project.status.sla.line"].create(sla_line_vals)
98+
99+
def _create_project_sla_history(self, sla):
100+
"""Create SLA history records for the project if not already present."""
101+
# Check if SLA history already exists for this project and SLA
102+
existing_history_count = self.env["project.status.sla.line"].search_count(
103+
[("sla_id", "=", sla.id)]
104+
)
105+
106+
# If history exists, do not create another one
107+
if existing_history_count:
108+
return
109+
110+
# Create new SLA line and post a notification message
111+
sla_line = self._create_sla_line(sla)
112+
self._post_sla_message(sla_line, sla)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# Copyright 2024 - TODAY, Kaynnan Lemes <[email protected]>
2+
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
3+
4+
import logging
5+
from datetime import timedelta
6+
7+
from odoo import api, fields, models
8+
9+
_logger = logging.getLogger(__name__)
10+
11+
12+
class ProjectStatusSLA(models.Model):
13+
_name = "project.status.sla"
14+
_description = "Project Status SLA"
15+
16+
project_id = fields.Many2one(
17+
comodel_name="project.project", string="Project", required=True
18+
)
19+
stage_id = fields.Many2one(
20+
comodel_name="project.status", string="Stage", required=True
21+
)
22+
days = fields.Integer(string="Days", default=0, required=True)
23+
hours = fields.Integer(string="Hours", default=0, required=True)
24+
note = fields.Char(string="Note")
25+
26+
@api.model
27+
def check_sla(self):
28+
"""Iterate through all SLAs and check the status for each project's SLA."""
29+
slas = self.search([])
30+
for sla in slas:
31+
sla._check_and_update_project_sla()
32+
33+
def _calculate_sla_deadline(self):
34+
"""Calculate the SLA deadline based on creation date, days, and hours."""
35+
return self.create_date + timedelta(days=self.days, hours=self.hours)
36+
37+
def _log_sla_status(self, project, deadline):
38+
"""Log important details related to SLA deadlines and expiration status."""
39+
_logger.info("Create Date: %s", self.create_date)
40+
_logger.info("Calculated Deadline: %s", deadline)
41+
_logger.info("Current Time: %s", fields.Datetime.now())
42+
_logger.info("Expired: %s", project.sla_expired)
43+
44+
def _check_and_update_project_sla(self):
45+
"""Check and update the project's SLA status based on the calculated deadline."""
46+
project = self.project_id
47+
deadline = self._calculate_sla_deadline()
48+
49+
# Update project SLA deadline
50+
project.sla_deadline = deadline
51+
52+
# Check if the SLA is expired
53+
project.sla_expired = deadline < fields.Datetime.now()
54+
55+
# Log the details of the SLA check
56+
self._log_sla_status(project, deadline)
57+
58+
# Create or update the project SLA history
59+
project._create_project_sla_history(self)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Copyright 2024 - TODAY, Kaynnan Lemes <[email protected]>
2+
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
3+
4+
from odoo import fields, models
5+
6+
7+
class ProjectStatusSLALine(models.Model):
8+
_name = "project.status.sla.line"
9+
_description = "Project Status SLA line"
10+
11+
project_id = fields.Many2one(
12+
comodel_name="project.project", string="Project", required=True
13+
)
14+
sla_id = fields.Many2one(comodel_name="project.status.sla", string="SLA")
15+
stage_id = fields.Many2one(
16+
comodel_name="project.status",
17+
string="Stage",
18+
)
19+
sla_deadline = fields.Datetime(string="SLA Deadline")
20+
sla_expired = fields.Boolean(string="SLA Expired")
21+
reached_date = fields.Datetime(string="Reached Date")
22+
status = fields.Selection(
23+
selection=[("not_met", "Not Met"), ("met", "Met")], string="Status"
24+
)
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
To configure this module, you need to:
2+
3+
#. Allow SLA for a Project
4+
5+
Allow SLA
6+
~~~~~~~~~~~~~~~
7+
8+
#. Go to Project > Configuration > Project Statuses SLA.
9+
#. Edit or create a new SLA.
10+
#. Select a Project.
11+
#. Select a Status.
12+
#. Select a days or hours for that SLA.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
* `Escodoo <https://www.escodoo.com.br>`_:
2+
3+
* Marcel Savegnago <[email protected]>
4+
* Kaynnan Lemes <[email protected]>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
This module adds SLA funcionality in Project Status module.

project_status_sla/readme/USAGE.rst

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
#. Go to *Project > Reports > Project Statuses SLA Lines * to see history SLA in Project.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
2+
access_project_status_sla_user,Access Project Status SLA User,model_project_status_sla,base.group_user,1,0,0,0
3+
access_project_status_sla_manager,Access Project Status SLA Manager,model_project_status_sla,project.group_project_manager,1,1,1,1
4+
access_project_status_sla_line_user,Access Project Status SLA Line User,model_project_status_sla_line,base.group_user,1,0,0,0
5+
access_project_status_sla_line_manager,Access Project Status SLA Line Manager,model_project_status_sla_line,project.group_project_manager,1,1,1,1
2.81 KB
Loading

project_status_sla/tests/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from . import test_project_status_sla

0 commit comments

Comments
 (0)