Skip to content
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

TA#72212 [16.0][MIG] sale_project_milestone #393

Open
wants to merge 5 commits into
base: 16.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ jobs:
name: Setup Log Folder For Reports
command: sudo mkdir -p .log && sudo chmod 777 .log

# - run:
# name: Run Test
# command: docker-compose run --rm odoo run_pytest.sh
- run:
name: Run Test
command: docker-compose run --rm odoo run_pytest.sh

# - run:
# name: Codacy Coverage
Expand Down
2 changes: 1 addition & 1 deletion .docker_files/main/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"category": "Other",
"summary": "Install all addons required for testing.",
"depends": [
"sale_management",
"sale_project_milestone",
],
"installable": True,
}
2 changes: 2 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,7 @@ RUN gitoo install-all --conf_file /gitoo.yml --destination "${THIRD_PARTY_ADDONS

USER odoo

COPY sale_project_milestone /mnt/extra-addons/sale_project_milestone

COPY .docker_files/main /mnt/extra-addons/main
COPY .docker_files/odoo.conf /etc/odoo
6 changes: 6 additions & 0 deletions gitoo.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
- url: https://github.com/Numigi/odoo-project-addons
branch: "16.0"
includes:
- project_milestone_enhanced
- project_milestone_estimated_hours

- url: https://github.com/OCA/brand
branch: "16.0"
includes:
Expand Down
112 changes: 112 additions & 0 deletions sale_project_milestone/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
Sale Project Milestone
======================

.. contents:: Table of Contents

Context
-------
In vanilla Odoo, it is possible to generate tasks and projects when confirming a sales order.

Natively, Odoo allows to define milestones on tasks.

Description
-----------
This module allows to generate a milestone in a project when confirming a sales order (instead of generating a task).

Then, each task linked to this milestone is automatically linked to the sales order line.

Configuration
-------------
In the form view of a product of type service, I find new options under ``Service Tracking``.

* Create milestone in existing project
* Create milestone in new project

.. image:: static/description/product_service_tracking.png

Create milestone in existing project
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When selecting this option, a project must be selected.

.. image:: static/description/product_milestone_existing_project.png

Each sales order line will generate a new milestone in the selected project.

The title of milestone is the description of the sales order line.

Create milestone in new project
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When selecting this option, you may select a project template and / or a milestone template.

.. image:: static/description/product_milestone_new_project.png

Each sales order line will generate a new milestone in a project.

Milestone Template
******************
This field allows to select a milestone linked to a non-billable project.

If a milestone template is selected, it is used to create the new milestone for the sales order line.

All tasks and subtasks linked to the milestone template are copied into the new milestone.

Project Template
****************
If a project template is selected, a new project will be created based on this template.
Otherwise, a global project is created for the sales order.

If two lines in the same order use the same template project, the same project is reused for both lines.
This behavior is coherent with the option ``Create a task in a new project``.

Usage
-----
I create a new product with the option ``Create milestone in new project``.

I select a milestone template for this product and choose service policy ``Based on Milestones``.
I have set in advance tasks linked to the milestone template.

.. image:: static/description/product_with_milestone_template.png

.. image:: static/description/milestone_template_service_A_tasks.png

I create a second product with a different milestone template and choose service policy ``Based on Milestones``.
I have set in advance tasks linked to the milestone template.

.. image:: static/description/product_2_with_milestone_template.png*

.. image:: static/description/milestone_template_service_B_tasks.png

I create a sales order with the two products.

.. image:: static/description/sales_order_new.png

After confirming the sales order, I notice a smart button ``Milestones``.

.. image:: static/description/sales_order_milestones_button.png

After clicking on the button, two milestones are shown.

.. image:: static/description/milestones_list.png

Also, I have a smart button ``Tasks`` that shows all tasks linked to each milestone.

.. image:: static/description/smart_button_tasks.png

.. image:: static/description/milestone_tasks_list.png

After clicking on the first milestone, the related tasks are displayed.

.. image:: static/description/milestone_form.png

In the form view of a task, if I change the milestone, the related sales order line is updated.

.. image:: static/description/task_form_milestone_changed.png

Release
-------
Since version ``1.2.0`` of the module, we set False in the field sale order line if the milestone is removed from the task.
Also the filter on the sale order line field is improved according to the project and the milestone associated with the task.

Contributors
------------
* Numigi (tm) and all its contributors (https://bit.ly/numigiens)
4 changes: 4 additions & 0 deletions sale_project_milestone/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# 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 . import models

Check notice on line 4 in sale_project_milestone/__init__.py

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

sale_project_milestone/__init__.py#L4

'.models' imported but unused (F401)
24 changes: 24 additions & 0 deletions sale_project_milestone/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# 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).

{

Check warning on line 4 in sale_project_milestone/__manifest__.py

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

sale_project_milestone/__manifest__.py#L4

Statement seems to have no effect
"name": "Sale Project Milestone",
"version": "16.0.1.0.0",
"author": "Numigi",
"maintainer": "Numigi",
"website": "https://bit.ly/numigi-com",
"license": "LGPL-3",
"category": "Project",
"summary": "Generate project milestones from sales orders",
"depends": [
"project_milestone_estimated_hours",
"sale_timesheet",
],
"data": [
"views/product_template.xml",
"views/project_milestone.xml",
"views/project_task.xml",
"views/sale_order.xml",
],
"installable": True,
}
127 changes: 127 additions & 0 deletions sale_project_milestone/i18n/fr.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * sale_project_milestone
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-07-20 17:44+0000\n"
"PO-Revision-Date: 2022-07-20 13:47-0400\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"Language: fr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: \n"
"X-Generator: Poedit 2.3\n"

#. module: sale_project_milestone
#: selection:product.template,service_tracking:0
msgid "Create a new project but no task"
msgstr "Créer un nouveau projet sans tâche"

#. module: sale_project_milestone
#: selection:product.template,service_tracking:0
msgid "Create a task in a new project"
msgstr "Créer une tâche dans un nouveau projet"

#. module: sale_project_milestone
#: selection:product.template,service_tracking:0
msgid "Create a task in an existing project"
msgstr "Créer une tâche dans un projet existant"

#. module: sale_project_milestone
#: selection:product.template,service_tracking:0
msgid "Create milestone in existing project"
msgstr "Créer un jalon dans un projet existant"

#. module: sale_project_milestone
#: selection:product.template,service_tracking:0
msgid "Create milestone in new project"
msgstr "Créer un jalon dans un nouveau projet"

#. module: sale_project_milestone
#: selection:product.template,service_tracking:0
msgid "Don't create task"
msgstr "Ne pas créer une tâche"

#. module: sale_project_milestone
#: model:ir.model.fields,field_description:sale_project_milestone.field_sale_order__milestone_ids
#: model:ir.model.fields,field_description:sale_project_milestone.field_sale_order_line__milestone_id
msgid "Milestone"
msgstr "Jalon"

#. module: sale_project_milestone
#: model:ir.model.fields,field_description:sale_project_milestone.field_sale_order__milestone_count
msgid "Milestone Count"
msgstr "Nombre de jalons"

#. module: sale_project_milestone
#: model:ir.model.fields,field_description:sale_project_milestone.field_product_product__milestone_template_id
#: model:ir.model.fields,field_description:sale_project_milestone.field_product_template__milestone_template_id
msgid "Milestone Template"
msgstr "Modèle de jalon"

#. module: sale_project_milestone
#: model_terms:ir.ui.view,arch_db:sale_project_milestone.view_sale_order_milestone_form
msgid "Milestones"
msgstr "Jalons"

#. module: sale_project_milestone
#: model:ir.model.fields,help:sale_project_milestone.field_product_product__service_tracking
#: model:ir.model.fields,help:sale_project_milestone.field_product_template__service_tracking
msgid ""
"On Sales order confirmation, this product can generate a project and/or "
"task. From those, you can track the service you are selling."
msgstr ""
"Lors de la confirmation de la commande client, ce produit peut générer un "
"projet ou une tâche. Cela vous permet ainsi de suivre le service que vous "
"vendez."

#. module: sale_project_milestone
#: model:ir.model,name:sale_project_milestone.model_product_product
msgid "Product"
msgstr "Article"

#. module: sale_project_milestone
#: model:ir.model,name:sale_project_milestone.model_product_template
msgid "Product Template"
msgstr "Modèle d'article"

#. module: sale_project_milestone
#: model:ir.model,name:sale_project_milestone.model_project_milestone
msgid "Project Milestone"
msgstr "Jalon du projet"

#. module: sale_project_milestone
#: model:ir.model,name:sale_project_milestone.model_sale_order
msgid "Sale Order"
msgstr "Bon de commande"

#. module: sale_project_milestone
#: model:ir.model.fields,field_description:sale_project_milestone.field_project_milestone__order_id
msgid "Sales Order"
msgstr "Commande"

#. module: sale_project_milestone
#: model:ir.model.fields,field_description:sale_project_milestone.field_project_milestone__sale_line_id
msgid "Sales Order Item"
msgstr "Ligne de commande"

#. module: sale_project_milestone
#: model:ir.model,name:sale_project_milestone.model_sale_order_line
msgid "Sales Order Line"
msgstr "Ligne de commande"

#. module: sale_project_milestone
#: model:ir.model.fields,field_description:sale_project_milestone.field_product_product__service_tracking
#: model:ir.model.fields,field_description:sale_project_milestone.field_product_template__service_tracking
msgid "Service Tracking"
msgstr "Suivi du service"

#. module: sale_project_milestone
#: model:ir.model,name:sale_project_milestone.model_project_task
msgid "Task"
msgstr "Tâche"
12 changes: 12 additions & 0 deletions sale_project_milestone/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# 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 . import (

Check notice on line 4 in sale_project_milestone/models/__init__.py

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

sale_project_milestone/models/__init__.py#L4

'.product_template' imported but unused (F401)
product_template,
product_product,
project_milestone,
project_project,
project_task,
sale_order,
sale_order_line,
)
25 changes: 25 additions & 0 deletions sale_project_milestone/models/product_product.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# 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, api


class ProductProduct(models.Model):

_inherit = "product.product"

@api.onchange("service_tracking")
def _onchange_service_tracking(self):
res = super()._onchange_service_tracking()

if self.service_tracking == "milestone_existing_project":
self.project_template_id = False
self.milestone_template_id = False

elif self.service_tracking == "milestone_new_project":
self.project_id = False

else:
self.milestone_template_id = False

return res
38 changes: 38 additions & 0 deletions sale_project_milestone/models/product_template.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Copyright 2023 - 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 fields, models, api


class ProductTemplate(models.Model):

_inherit = "product.template"

service_tracking = fields.Selection(
selection_add=[
("milestone_existing_project", "Create milestone in existing project"),
("milestone_new_project", "Create milestone in new project"),
]
)
milestone_template_id = fields.Many2one(
"project.milestone",
string="Milestone Template",
company_dependent=True,
copy=True,
)

@api.onchange("service_tracking")
def _onchange_service_tracking(self):
res = super()._onchange_service_tracking()

if self.service_tracking == "milestone_existing_project":
self.project_template_id = False
self.milestone_template_id = False

elif self.service_tracking == "milestone_new_project":
self.project_id = False

else:
self.milestone_template_id = False

return res
Loading
Loading