diff --git a/.docker_files/main/__manifest__.py b/.docker_files/main/__manifest__.py
index 539880fc..104fe594 100644
--- a/.docker_files/main/__manifest__.py
+++ b/.docker_files/main/__manifest__.py
@@ -13,6 +13,7 @@
"depends": [
"project",
"project_task_date_planned",
+ "project_task_description_template",
"project_task_full_text_search",
"project_type_advanced",
"project_default_task_stage",
diff --git a/Dockerfile b/Dockerfile
index 5396fbbb..16fc3d05 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -15,10 +15,12 @@ USER odoo
COPY project_stage_allow_timesheet mnt/extra-addons/project_stage_allow_timesheet
COPY project_task_date_planned /mnt/extra-addons/project_task_date_planned
+COPY project_task_description_template /mnt/extra-addons/project_task_description_template
COPY project_task_full_text_search /mnt/extra-addons/project_task_full_text_search
COPY project_type_advanced /mnt/extra-addons/project_type_advanced
COPY project_default_task_stage /mnt/extra-addons/project_default_task_stage
+
COPY .docker_files/main /mnt/extra-addons/main
COPY .docker_files/odoo.conf /etc/odoo
diff --git a/project_task_description_template/README.rst b/project_task_description_template/README.rst
new file mode 100644
index 00000000..4c7d43fb
--- /dev/null
+++ b/project_task_description_template/README.rst
@@ -0,0 +1,34 @@
+Project Task Description Templates
+==================================
+This module allows to autocomplete descriptions on tasks.
+
+.. contents:: Table of Contents
+
+Context
+-------
+When using ``Projects`` for field interventions for example, the description of tasks is very repetitive.
+It is therefore convenient to automatically fill the description with a template.
+
+Usage
+-----
+As ``Project / Manager``, I go to ``Project / Configuration / Task Description Templates``.
+
+I find the list of description templates.
+
+.. image:: static/description/description_template_list.png
+
+Each record contains a name and a HTML description.
+
+.. image:: static/description/description_template_form.png
+
+In the form view of a task, I can select a description template.
+
+.. image:: static/description/task_form.png
+
+The description is automatically copied from the template.
+
+.. image:: static/description/task_form_description_filled.png
+
+Contributors
+------------
+* Numigi (tm) and all its contributors (https://bit.ly/numigiens)
diff --git a/project_task_description_template/__init__.py b/project_task_description_template/__init__.py
new file mode 100644
index 00000000..d6a63ca0
--- /dev/null
+++ b/project_task_description_template/__init__.py
@@ -0,0 +1,4 @@
+# Copyright 2024-today Numigi and all its contributors (https://bit.ly/numigiens)
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from . import models
diff --git a/project_task_description_template/__manifest__.py b/project_task_description_template/__manifest__.py
new file mode 100644
index 00000000..5aaaeb12
--- /dev/null
+++ b/project_task_description_template/__manifest__.py
@@ -0,0 +1,20 @@
+# Copyright 2024-today Numigi and all its contributors (https://bit.ly/numigiens)
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+{
+ "name": "Project Task Description Template",
+ "version": "16.0.1.0.0",
+ "author": "Numigi",
+ "maintainer": "Numigi",
+ "website": "https://www.numigi.com",
+ "license": "LGPL-3",
+ "category": "Project",
+ "summary": "Autocomplete task descriptions from templates",
+ "depends": ["project"],
+ "data": [
+ "security/ir.model.access.csv",
+ "views/project_task_views.xml",
+ "views/task_description_template_views.xml",
+ ],
+ "installable": True,
+}
diff --git a/project_task_description_template/i18n/fr.po b/project_task_description_template/i18n/fr.po
new file mode 100644
index 00000000..bcf64a94
--- /dev/null
+++ b/project_task_description_template/i18n/fr.po
@@ -0,0 +1,104 @@
+# Translation of Odoo Server.
+# This file contains the translation of the following modules:
+# * project_task_description_template
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Odoo Server 16.0\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2024-11-22 13:35+0000\n"
+"PO-Revision-Date: 2024-11-22 13:35+0000\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: \n"
+"Plural-Forms: \n"
+
+#. module: project_task_description_template
+#: model:ir.model.fields,field_description:project_task_description_template.field_project_task_description_template__active
+msgid "Active"
+msgstr "Actif"
+
+#. module: project_task_description_template
+#: model_terms:ir.ui.view,arch_db:project_task_description_template.project_task_description_template_search
+msgid "Archived"
+msgstr "Archivé"
+
+#. module: project_task_description_template
+#: model:ir.model.fields,field_description:project_task_description_template.field_project_task_description_template__create_uid
+msgid "Created by"
+msgstr "Créé par"
+
+#. module: project_task_description_template
+#: model:ir.model.fields,field_description:project_task_description_template.field_project_task_description_template__create_date
+msgid "Created on"
+msgstr "Créé le"
+
+#. module: project_task_description_template
+#: model:ir.model.fields,field_description:project_task_description_template.field_project_task_description_template__description
+msgid "Description"
+msgstr ""
+
+#. module: project_task_description_template
+#: model:ir.model.fields,field_description:project_task_description_template.field_project_task__description_template_id
+msgid "Description Template"
+msgstr "Modèle de description"
+
+#. module: project_task_description_template
+#: model:ir.model.fields,field_description:project_task_description_template.field_project_task_description_template__display_name
+msgid "Display Name"
+msgstr "Nom affiché"
+
+#. module: project_task_description_template
+#: model:ir.model.fields,field_description:project_task_description_template.field_project_task_description_template__id
+msgid "ID"
+msgstr ""
+
+#. module: project_task_description_template
+#: model:ir.model.fields,field_description:project_task_description_template.field_project_task_description_template____last_update
+msgid "Last Modified on"
+msgstr "Dernière modification le"
+
+#. module: project_task_description_template
+#: model:ir.model.fields,field_description:project_task_description_template.field_project_task_description_template__write_uid
+msgid "Last Updated by"
+msgstr "Dernière mise à jour par"
+
+#. module: project_task_description_template
+#: model:ir.model.fields,field_description:project_task_description_template.field_project_task_description_template__write_date
+msgid "Last Updated on"
+msgstr "Dernière mise à jour le"
+
+#. module: project_task_description_template
+#: model:ir.model.fields,field_description:project_task_description_template.field_project_task_description_template__name
+msgid "Name"
+msgstr "Nom"
+
+#. module: project_task_description_template
+#: model:ir.model,name:project_task_description_template.model_project_task_description_template
+msgid "Project Task Description Template"
+msgstr "Modèles de description de tâches"
+
+#. module: project_task_description_template
+#: model:ir.model.fields,field_description:project_task_description_template.field_project_task_description_template__sequence
+msgid "Sequence"
+msgstr "Séquence"
+
+#. module: project_task_description_template
+#: model:ir.model,name:project_task_description_template.model_project_task
+msgid "Task"
+msgstr "Tâche"
+
+#. module: project_task_description_template
+#: model_terms:ir.ui.view,arch_db:project_task_description_template.project_task_description_template_form
+msgid "Task Description Template"
+msgstr "Modèle de description de tâche"
+
+#. module: project_task_description_template
+#: model:ir.actions.act_window,name:project_task_description_template.project_task_description_template_action
+#: model:ir.ui.menu,name:project_task_description_template.project_task_description_template_menu
+#: model_terms:ir.ui.view,arch_db:project_task_description_template.project_task_description_template_list
+#: model_terms:ir.ui.view,arch_db:project_task_description_template.project_task_description_template_search
+msgid "Task Description Templates"
+msgstr "Modèles de description de tâches"
diff --git a/project_task_description_template/models/__init__.py b/project_task_description_template/models/__init__.py
new file mode 100644
index 00000000..a4e313f5
--- /dev/null
+++ b/project_task_description_template/models/__init__.py
@@ -0,0 +1,5 @@
+# Copyright 2024-today Numigi and all its contributors (https://bit.ly/numigiens)
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from . import project_task
+from . import project_task_description_template
diff --git a/project_task_description_template/models/project_task.py b/project_task_description_template/models/project_task.py
new file mode 100644
index 00000000..aebd2b8e
--- /dev/null
+++ b/project_task_description_template/models/project_task.py
@@ -0,0 +1,18 @@
+# Copyright 2024-today Numigi and all its contributors (https://bit.ly/numigiens)
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from odoo import api, fields, models
+
+
+class ProjectTask(models.Model):
+
+ _inherit = "project.task"
+
+ description_template_id = fields.Many2one(
+ "project.task.description.template", ondelete="restrict"
+ )
+
+ @api.onchange("description_template_id")
+ def _onchange_description_template(self):
+ if self.description_template_id:
+ self.description = self.description_template_id.description
diff --git a/project_task_description_template/models/project_task_description_template.py b/project_task_description_template/models/project_task_description_template.py
new file mode 100644
index 00000000..58add8f7
--- /dev/null
+++ b/project_task_description_template/models/project_task_description_template.py
@@ -0,0 +1,16 @@
+# Copyright 2024-today Numigi and all its contributors (https://bit.ly/numigiens)
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from odoo import fields, models
+
+
+class ProjectTaskDescriptionTemplate(models.Model):
+
+ _name = "project.task.description.template"
+ _description = "Project Task Description Template"
+ _order = "sequence"
+
+ name = fields.Char(required=True)
+ description = fields.Html()
+ active = fields.Boolean(default=True)
+ sequence = fields.Integer()
diff --git a/project_task_description_template/security/ir.model.access.csv b/project_task_description_template/security/ir.model.access.csv
new file mode 100644
index 00000000..d10b0446
--- /dev/null
+++ b/project_task_description_template/security/ir.model.access.csv
@@ -0,0 +1,3 @@
+id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink
+access_project_task_description_template_user,project_task_description_template_user,model_project_task_description_template,base.group_user,1,0,0,0
+access_project_task_description_template_manager,project_task_description_template_manager,model_project_task_description_template,project.group_project_manager,1,1,1,1
diff --git a/project_task_description_template/static/description/description_template_form.png b/project_task_description_template/static/description/description_template_form.png
new file mode 100644
index 00000000..89fd2c2f
Binary files /dev/null and b/project_task_description_template/static/description/description_template_form.png differ
diff --git a/project_task_description_template/static/description/description_template_list.png b/project_task_description_template/static/description/description_template_list.png
new file mode 100644
index 00000000..7491d504
Binary files /dev/null and b/project_task_description_template/static/description/description_template_list.png differ
diff --git a/project_task_description_template/static/description/icon.png b/project_task_description_template/static/description/icon.png
new file mode 100644
index 00000000..92a86b10
Binary files /dev/null and b/project_task_description_template/static/description/icon.png differ
diff --git a/project_task_description_template/static/description/task_form.png b/project_task_description_template/static/description/task_form.png
new file mode 100644
index 00000000..12c0ba2b
Binary files /dev/null and b/project_task_description_template/static/description/task_form.png differ
diff --git a/project_task_description_template/static/description/task_form_description_filled.png b/project_task_description_template/static/description/task_form_description_filled.png
new file mode 100644
index 00000000..d763a5cc
Binary files /dev/null and b/project_task_description_template/static/description/task_form_description_filled.png differ
diff --git a/project_task_description_template/tests/__init__.py b/project_task_description_template/tests/__init__.py
new file mode 100644
index 00000000..f1892a60
--- /dev/null
+++ b/project_task_description_template/tests/__init__.py
@@ -0,0 +1,4 @@
+# Copyright 2024-today Numigi and all its contributors (https://bit.ly/numigiens)
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from . import test_project_task
diff --git a/project_task_description_template/tests/test_project_task.py b/project_task_description_template/tests/test_project_task.py
new file mode 100644
index 00000000..bb2dbbc0
--- /dev/null
+++ b/project_task_description_template/tests/test_project_task.py
@@ -0,0 +1,20 @@
+# Copyright 2024-today Numigi and all its contributors (https://bit.ly/numigiens)
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from odoo.tests import Form
+from odoo.tests.common import TransactionCase
+
+
+class TestProjectTask(TransactionCase):
+ @classmethod
+ def setUpClass(cls):
+ super().setUpClass()
+ cls.template = cls.env["project.task.description.template"].create(
+ {"name": "My Template", "description": "Lorem Ipsum"}
+ )
+ cls.task = cls.env["project.task"].create({"name": "My Task"})
+
+ def test_onchange_description_template(self):
+ with Form(self.task) as task_form:
+ task_form.description_template_id = self.template
+ assert self.task.description == self.template.description
diff --git a/project_task_description_template/views/project_task_views.xml b/project_task_description_template/views/project_task_views.xml
new file mode 100644
index 00000000..e33116e3
--- /dev/null
+++ b/project_task_description_template/views/project_task_views.xml
@@ -0,0 +1,15 @@
+
+
+
+
+ Task form: Add description template
+ project.task
+
+
+
+
+
+
+
+
+
diff --git a/project_task_description_template/views/task_description_template_views.xml b/project_task_description_template/views/task_description_template_views.xml
new file mode 100644
index 00000000..e8f21f31
--- /dev/null
+++ b/project_task_description_template/views/task_description_template_views.xml
@@ -0,0 +1,60 @@
+
+
+
+
+ Task Description Template Form
+ project.task.description.template
+
+
+
+
+
+
+ Task Description Template List
+ project.task.description.template
+
+
+
+
+
+
+
+
+
+
+ Task Description Template Search
+ project.task.description.template
+
+
+
+
+
+
+
+
+
+ Task Description Templates
+ project.task.description.template
+ tree,form
+
+
+
+
+