diff --git a/project_milestone_enhanced/__manifest__.py b/project_milestone_enhanced/__manifest__.py index 36ba567f..db6730ec 100644 --- a/project_milestone_enhanced/__manifest__.py +++ b/project_milestone_enhanced/__manifest__.py @@ -13,6 +13,7 @@ "data": [ "views/project_milestone.xml", "views/project.xml", + "views/task_stage.xml", ], "installable": True, } diff --git a/project_milestone_enhanced/i18n/fr.po b/project_milestone_enhanced/i18n/fr.po index 71b4bda8..7fbfb7da 100644 --- a/project_milestone_enhanced/i18n/fr.po +++ b/project_milestone_enhanced/i18n/fr.po @@ -6,8 +6,8 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 16.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-12-03 06:25+0000\n" -"PO-Revision-Date: 2024-12-03 06:25+0000\n" +"POT-Creation-Date: 2024-12-04 15:24+0000\n" +"PO-Revision-Date: 2024-12-04 15:24+0000\n" "Last-Translator: \n" "Language-Team: \n" "MIME-Version: 1.0\n" @@ -15,10 +15,40 @@ msgstr "" "Content-Transfer-Encoding: \n" "Plural-Forms: \n" +#. module: project_milestone_enhanced +#: model:ir.model.fields,field_description:project_milestone_enhanced.field_project_milestone__message_needaction +msgid "Action Needed" +msgstr "Nécessite une action" + #. module: project_milestone_enhanced #: model:ir.model.fields,field_description:project_milestone_enhanced.field_project_milestone__active msgid "Active" -msgstr "Actif" +msgstr "" + +#. module: project_milestone_enhanced +#: model:ir.model.fields,field_description:project_milestone_enhanced.field_project_milestone__activity_ids +msgid "Activities" +msgstr "" + +#. module: project_milestone_enhanced +#: model:ir.model.fields,field_description:project_milestone_enhanced.field_project_milestone__activity_exception_decoration +msgid "Activity Exception Decoration" +msgstr "" + +#. module: project_milestone_enhanced +#: model:ir.model.fields,field_description:project_milestone_enhanced.field_project_milestone__activity_state +msgid "Activity State" +msgstr "" + +#. module: project_milestone_enhanced +#: model:ir.model.fields,field_description:project_milestone_enhanced.field_project_milestone__activity_type_icon +msgid "Activity Type Icon" +msgstr "" + +#. module: project_milestone_enhanced +#: model:ir.ui.menu,name:project_milestone_enhanced.milestone_configuration_menu +msgid "All Milestones" +msgstr "Tous les jalons" #. module: project_milestone_enhanced #: model_terms:ir.ui.view,arch_db:project_milestone_enhanced.project_active_view_form @@ -34,13 +64,140 @@ msgid "" msgstr "" "Archiver un projet archivera automatiquement ses tâches et jalons. Voulez-vous continuer ?" +#. module: project_milestone_enhanced +#: model:ir.model.fields,field_description:project_milestone_enhanced.field_project_milestone__message_attachment_count +msgid "Attachment Count" +msgstr "Nombre de pièces jointes" + +#. module: project_milestone_enhanced +#: model:ir.model.fields,field_description:project_milestone_enhanced.field_project_task_type__closed +msgid "Closed" +msgstr "Clôturé" + +#. module: project_milestone_enhanced +#: model:ir.model.fields,field_description:project_milestone_enhanced.field_project_milestone__message_follower_ids +msgid "Followers" +msgstr "Abonnés" + +#. module: project_milestone_enhanced +#: model:ir.model.fields,field_description:project_milestone_enhanced.field_project_milestone__message_partner_ids +msgid "Followers (Partners)" +msgstr "Abonnés (Partenaires)" + +#. module: project_milestone_enhanced +#: model:ir.model.fields,help:project_milestone_enhanced.field_project_milestone__activity_type_icon +msgid "Font awesome icon e.g. fa-tasks" +msgstr "" + +#. module: project_milestone_enhanced +#: model_terms:ir.ui.view,arch_db:project_milestone_enhanced.project_milestone_view_search +msgid "Group By" +msgstr "" + +#. module: project_milestone_enhanced +#: model:ir.model.fields,field_description:project_milestone_enhanced.field_project_milestone__has_message +msgid "Has Message" +msgstr "A un message" + +#. module: project_milestone_enhanced +#: model:ir.model.fields,field_description:project_milestone_enhanced.field_project_milestone__activity_exception_icon +msgid "Icon" +msgstr "" + +#. module: project_milestone_enhanced +#: model:ir.model.fields,help:project_milestone_enhanced.field_project_milestone__activity_exception_icon +msgid "Icon to indicate an exception activity." +msgstr "" + +#. module: project_milestone_enhanced +#: model:ir.model.fields,help:project_milestone_enhanced.field_project_milestone__message_needaction +msgid "If checked, new messages require your attention." +msgstr "Si coché, de nouveaux messages demandent votre attention." + +#. module: project_milestone_enhanced +#: model:ir.model.fields,help:project_milestone_enhanced.field_project_milestone__message_has_error +#: model:ir.model.fields,help:project_milestone_enhanced.field_project_milestone__message_has_sms_error +msgid "If checked, some messages have a delivery error." +msgstr "Si coché, certains messages ont une erreur de livraison." + +#. module: project_milestone_enhanced +#: model:ir.model.fields,field_description:project_milestone_enhanced.field_project_milestone__message_is_follower +msgid "Is Follower" +msgstr "Est un abonné" + +#. module: project_milestone_enhanced +#: model:ir.model.fields,field_description:project_milestone_enhanced.field_project_milestone__message_main_attachment_id +msgid "Main Attachment" +msgstr "Pièce jointe principale" + +#. module: project_milestone_enhanced +#: model:ir.model.fields,field_description:project_milestone_enhanced.field_project_milestone__message_has_error +msgid "Message Delivery error" +msgstr "Erreur d'envoi du message" + +#. module: project_milestone_enhanced +#: model:ir.model.fields,field_description:project_milestone_enhanced.field_project_milestone__message_ids +msgid "Messages" +msgstr "" + #. module: project_milestone_enhanced #: model_terms:ir.ui.view,arch_db:project_milestone_enhanced.project_active_view_form msgid "Milestones" msgstr "Jalons" +#. module: project_milestone_enhanced +#: model:ir.model.fields,field_description:project_milestone_enhanced.field_project_milestone__my_activity_date_deadline +msgid "My Activity Deadline" +msgstr "" + +#. module: project_milestone_enhanced +#: model:ir.model.fields,field_description:project_milestone_enhanced.field_project_milestone__activity_date_deadline +msgid "Next Activity Deadline" +msgstr "" + +#. module: project_milestone_enhanced +#: model:ir.model.fields,field_description:project_milestone_enhanced.field_project_milestone__activity_summary +msgid "Next Activity Summary" +msgstr "" + +#. module: project_milestone_enhanced +#: model:ir.model.fields,field_description:project_milestone_enhanced.field_project_milestone__activity_type_id +msgid "Next Activity Type" +msgstr "" + +#. module: project_milestone_enhanced +#: model:ir.model.fields,field_description:project_milestone_enhanced.field_project_milestone__message_needaction_counter +msgid "Number of Actions" +msgstr "Nombre d'actions" + +#. module: project_milestone_enhanced +#: model:ir.model.fields,field_description:project_milestone_enhanced.field_project_milestone__message_has_error_counter +msgid "Number of errors" +msgstr "Nombre d'erreurs" + +#. module: project_milestone_enhanced +#: model:ir.model.fields,help:project_milestone_enhanced.field_project_milestone__message_needaction_counter +msgid "Number of messages requiring action" +msgstr "Nombre de messages nécessitant une action" + +#. module: project_milestone_enhanced +#: model:ir.model.fields,help:project_milestone_enhanced.field_project_milestone__message_has_error_counter +msgid "Number of messages with delivery error" +msgstr "Nombre de messages avec des erreurs d'envoi" + +#. module: project_milestone_enhanced +#: model:ir.model.fields,help:project_milestone_enhanced.field_project_milestone__progress +msgid "Percentage of Completed Tasks vs Incomplete Tasks." +msgstr "Pourcentage de tâches achevées par rapport aux tâches incomplètes." + +#. module: project_milestone_enhanced +#: model:ir.model.fields,field_description:project_milestone_enhanced.field_project_milestone__progress +msgid "Progress" +msgstr "Progression" + #. module: project_milestone_enhanced #: model:ir.model,name:project_milestone_enhanced.model_project_project +#: model_terms:ir.ui.view,arch_db:project_milestone_enhanced.project_milestone_view_search msgid "Project" msgstr "Projet" @@ -49,21 +206,68 @@ msgstr "Projet" msgid "Project Milestone" msgstr "Jalon du projet" +#. module: project_milestone_enhanced +#: model:ir.actions.act_window,name:project_milestone_enhanced.project_milestone_action +msgid "Project Milestones" +msgstr "Jalons du projet" + +#. module: project_milestone_enhanced +#: model:ir.model.fields,field_description:project_milestone_enhanced.field_project_milestone__activity_user_id +msgid "Responsible User" +msgstr "" + +#. module: project_milestone_enhanced +#: model:ir.model.fields,field_description:project_milestone_enhanced.field_project_milestone__message_has_sms_error +msgid "SMS Delivery error" +msgstr "Erreur d'envoi SMS" + +#. module: project_milestone_enhanced +#: model:ir.model.fields,field_description:project_milestone_enhanced.field_project_milestone__sequence +msgid "Sequence" +msgstr "Séquence" + #. module: project_milestone_enhanced #: model:ir.model.fields,field_description:project_milestone_enhanced.field_project_project__show_milestones msgid "Show milestones" msgstr "Afficher les jalons" +#. module: project_milestone_enhanced +#: model:ir.model.fields,help:project_milestone_enhanced.field_project_milestone__activity_state +msgid "" +"Status based on activities\n" +"Overdue: Due date is already passed\n" +"Today: Activity date is today\n" +"Planned: Future activities." +msgstr "Statut basé sur les activités\n" +"En retard : la date d'échéance est déjà dépassée\n" +"Aujourd'hui : la date de l'activité est aujourd'hui\n" +"Planifié : activités futures." + +#. module: project_milestone_enhanced +#: model:ir.model,name:project_milestone_enhanced.model_project_task_type +msgid "Task Stage" +msgstr "Étape de tâche" + #. module: project_milestone_enhanced #: model_terms:ir.ui.view,arch_db:project_milestone_enhanced.project_milestone_active_view_form msgid "Tasks" msgstr "Tâches" +#. module: project_milestone_enhanced +#: model:ir.model.fields,help:project_milestone_enhanced.field_project_task_type__closed +msgid "Tasks in this stage are considered closed." +msgstr "Les tâches dans cette étape sont considérées comme clôturées." + #. module: project_milestone_enhanced #: model:ir.model.fields,field_description:project_milestone_enhanced.field_project_milestone__active_toggle msgid "Toggle active" msgstr "Toggle actif" +#. module: project_milestone_enhanced +#: model:ir.model.fields,help:project_milestone_enhanced.field_project_milestone__activity_exception_decoration +msgid "Type of the exception activity on record." +msgstr "Type d'activité d'exception enregistrée." + #. module: project_milestone_enhanced #: model_terms:ir.ui.view,arch_db:project_milestone_enhanced.project_active_view_form #: model_terms:ir.ui.view,arch_db:project_milestone_enhanced.project_milestone_active_view_form @@ -76,4 +280,14 @@ msgid "" "Unarchiving a project automatically unarchives its tasks and milestones. Do " "you want to proceed ?" msgstr "" -""Désarchiver un projet désarchivera automatiquement ses tâches et jalons. Voulez-vous continuer ?" \ No newline at end of file +""Désarchiver un projet désarchivera automatiquement ses tâches et jalons. Voulez-vous continuer ?" + +#. module: project_milestone_enhanced +#: model:ir.model.fields,field_description:project_milestone_enhanced.field_project_milestone__website_message_ids +msgid "Website Messages" +msgstr "Messages du site web" + +#. module: project_milestone_enhanced +#: model:ir.model.fields,help:project_milestone_enhanced.field_project_milestone__website_message_ids +msgid "Website communication history" +msgstr "Historique de communication du site web" \ No newline at end of file diff --git a/project_milestone_enhanced/models/__init__.py b/project_milestone_enhanced/models/__init__.py index eb62378e..5b19a8c4 100644 --- a/project_milestone_enhanced/models/__init__.py +++ b/project_milestone_enhanced/models/__init__.py @@ -3,3 +3,4 @@ from . import project from . import project_milestone +from . import task_stage diff --git a/project_milestone_enhanced/models/project_milestone.py b/project_milestone_enhanced/models/project_milestone.py index 2a894745..c618903a 100644 --- a/project_milestone_enhanced/models/project_milestone.py +++ b/project_milestone_enhanced/models/project_milestone.py @@ -1,14 +1,22 @@ # Copyright 2023 - today Numigi (tm) and all its contributors (https://bit.ly/numigiens) # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). -from odoo import models, fields +from odoo import api, models, fields class ProjectMilestone(models.Model): - _inherit = "project.milestone" + _name = "project.milestone" + + _inherit = ['project.milestone', 'mail.thread', 'mail.activity.mixin'] active = fields.Boolean(string="Active", default=True) active_toggle = fields.Boolean(string="Toggle active", default=True) + sequence = fields.Integer() + progress = fields.Float( + compute="_compute_milestone_progress", + store=True, + help="Percentage of Completed Tasks vs Incomplete Tasks.", + ) def toggle_active(self): res = super(ProjectMilestone, self).toggle_active() @@ -38,3 +46,17 @@ def _milestone_not_active(self): self.filtered(lambda milestone: not milestone.active_toggle).write( {"active": False} ) + + @api.depends('task_ids.stage_id') + def _compute_milestone_progress(self): + total_tasks_count = 0.0 + closed_tasks_count = 0.0 + for record in self: + for task_record in record.task_ids: + total_tasks_count += 1 + if task_record.stage_id.closed: + closed_tasks_count += 1 + if total_tasks_count > 0: + record.progress = (closed_tasks_count / total_tasks_count) * 100 + else: + record.progress = 0.0 diff --git a/project_milestone_enhanced/models/task_stage.py b/project_milestone_enhanced/models/task_stage.py new file mode 100644 index 00000000..6f5f804d --- /dev/null +++ b/project_milestone_enhanced/models/task_stage.py @@ -0,0 +1,13 @@ +# Copyright 2023 - today Numigi (tm) and all its contributors (https://bit.ly/numigiens) +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +from odoo import models, fields + + +class ProjectTaskType(models.Model): + _inherit = 'project.task.type' + + closed = fields.Boolean( + help="Tasks in this stage are considered closed.", + default=False, + ) diff --git a/project_milestone_enhanced/tests/test_project.py b/project_milestone_enhanced/tests/test_project.py index f172a8ca..1c9951f2 100644 --- a/project_milestone_enhanced/tests/test_project.py +++ b/project_milestone_enhanced/tests/test_project.py @@ -1,42 +1,56 @@ # Copyright 2023 - today Numigi (tm) and all its contributors (https://bit.ly/numigiens) # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). -from odoo.tests.common import SavepointCase +from odoo.tests import common -class TestProject(SavepointCase): - @classmethod - def setUpClass(cls): - super().setUpClass() - cls.project = cls.env["project.project"].create( +class TestProject(common.TransactionCase): + def setUp(self): + super().setUp() + self.project = self.env["project.project"].create( {"name": "My Project", "allow_milestones": True} ) - cls.milestone = cls.env["project.milestone"].create( - {"name": "My Milestone", "project_id": cls.project.id} + self.milestone = self.env["project.milestone"].create( + {"name": "My Milestone", "project_id": self.project.id} ) - cls.milestone_2 = cls.env["project.milestone"].create( - {"name": "My Milestone 2", "project_id": cls.project.id} + self.milestone_2 = self.env["project.milestone"].create( + {"name": "My Milestone 2", "project_id": self.project.id} ) - cls.task = cls.env["project.task"].create( + self.task = self.env["project.task"].create( { "name": "My Task", - "project_id": cls.project.id, - "milestone_id": cls.milestone.id, + "project_id": self.project.id, + "milestone_id": self.milestone.id, } ) - cls.task_2 = cls.env["project.task"].create( + self.task_2 = self.env["project.task"].create( { "name": "My Task 1", - "project_id": cls.project.id, - "milestone_id": cls.milestone.id, + "project_id": self.project.id, + "milestone_id": self.milestone.id, "active": False, } ) + self.task_3 = self.env["project.task"].create( + { + "name": "My Task 2", + "project_id": self.project.id, + "milestone_id": self.milestone.id, + } + ) + + self.test_open_stage = self.env['project.task.type'].create( + {'name': 'TestOpenStage'} + ) + self.test_close_stage = self.env['project.task.type'].create( + {'name': 'TestCloseStage', 'closed': True} + ) + def test_copy_project(self): project = self.project.copy({}) tasks = project.with_context(active_test=False).task_ids @@ -69,3 +83,12 @@ def test_project_change_active(self): self.project.toggle_active() assert self.milestone.active assert not self.milestone_2.active + + def test_milestone_progress(self): + milestone1 = self.milestone + + self.task.stage_id = self.test_close_stage.id + self.assertEqual(milestone1.progress, 50) + + self.task_3.stage_id = self.test_close_stage.id + self.assertEqual(milestone1.progress, 100) diff --git a/project_milestone_enhanced/views/project.xml b/project_milestone_enhanced/views/project.xml index 1f328614..b0e21a3c 100644 --- a/project_milestone_enhanced/views/project.xml +++ b/project_milestone_enhanced/views/project.xml @@ -28,6 +28,7 @@ + diff --git a/project_milestone_enhanced/views/project_milestone.xml b/project_milestone_enhanced/views/project_milestone.xml index 5b257807..25a2aa7e 100644 --- a/project_milestone_enhanced/views/project_milestone.xml +++ b/project_milestone_enhanced/views/project_milestone.xml @@ -27,6 +27,75 @@ + + + + +
+ + + +
+
+
+ + + + + Project Milestone Sequence + project.milestone + 0 + 1 + + + + + Project Milestone List + project.milestone + + + + + + + + + + + + + Project Milestone Search + project.milestone + + + + + + + + + + + + + + Project Milestones + project.milestone + {'group_by': 'project_id'} + tree,form + + + + diff --git a/project_milestone_enhanced/views/task_stage.xml b/project_milestone_enhanced/views/task_stage.xml new file mode 100644 index 00000000..ed4cefa7 --- /dev/null +++ b/project_milestone_enhanced/views/task_stage.xml @@ -0,0 +1,14 @@ + + + + + project.task.type + + + + + + + + +