Skip to content
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
107 changes: 107 additions & 0 deletions project_task_stage_state_sync/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
.. image:: https://odoo-community.org/readme-banner-image
:target: https://odoo-community.org/get-involved?utm_source=readme
:alt: Odoo Community Association

=============================================
Project Task Stage/State - Bidirectional Sync
=============================================

..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:92f5e5d8c27c7ac220d68e1fe3232afa4315e842af76fd342ce8f33cdac18b35
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

.. |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/license-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%2Fproject-lightgray.png?logo=github
:target: https://github.com/OCA/project/tree/19.0/project_task_stage_state_sync
:alt: OCA/project
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/project-19-0/project-19-0-project_task_stage_state_sync
: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/project&target_branch=19.0
:alt: Try me on Runboat

|badge1| |badge2| |badge3| |badge4| |badge5|

This module extends ``project_task_stage_state`` to complete the
bidirectional link between task states and stages.

``project_task_stage_state`` already handles the **Stage → State**
direction: moving a task to a stage updates its state to the one
configured on that stage.

This module adds the **State → Stage** direction: when a task's state
changes (manually or programmatically), the task is automatically moved
to the stage configured for that state.

The sync is configured per stage via a checkbox, so it can be enabled
selectively without affecting every stage in every project.

**Table of contents**

.. contents::
:local:

Configuration
=============

On each stage (Project → Configuration → Stages):

1. Set the **State** field to the state that moving to this stage should
assign.
2. Enable **Sync State → Stage** to also activate the reverse: tasks
whose state is set to that value will automatically move to this
stage.

**Uniqueness rule:** Only one stage per project may have *Sync State →
Stage* enabled for a given state value. Attempting to enable it on a
second stage that shares the same state and project will raise a
validation error naming the conflicting stage. Two different projects
are allowed to each have their own stage with sync enabled for the same
state — for example, both "Project A / Done" and "Project B / Done" can
independently have *Sync State → Stage* ticked for the *Done* state. The
uniqueness rule only applies within a single project.

Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/OCA/project/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/project/issues/new?body=module:%20project_task_stage_state_sync%0Aversion:%2019.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
=======

Contributors
------------

- Isabel Andreu <isabel.andreu@forgeflow.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/project <https://github.com/OCA/project/tree/19.0/project_task_stage_state_sync>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
3 changes: 3 additions & 0 deletions project_task_stage_state_sync/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to the OCA, you don't put a License [header] in init.py files.


from . import models
14 changes: 14 additions & 0 deletions project_task_stage_state_sync/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html

{
"name": "Project Task Stage/State - Bidirectional Sync",
"version": "19.0.1.0.0",
"category": "Project Management",
"summary": "Optionally move tasks to the matching stage when their state changes",
"author": "Odoo Community Association (OCA)",
"website": "https://github.com/OCA/project",
"license": "AGPL-3",
"installable": True,
"depends": ["project_task_stage_state"],
"data": ["views/project_task_type_views.xml"],
}
4 changes: 4 additions & 0 deletions project_task_stage_state_sync/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to the OCA, you don't put a License [header] in __init__.py files.


from . import project_task
from . import project_task_type
28 changes: 28 additions & 0 deletions project_task_stage_state_sync/models/project_task.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html

from odoo import models


class ProjectTask(models.Model):
_inherit = "project.task"

def _inverse_state(self):
res = super()._inverse_state()
self._sync_stage_from_state()
return res

def _sync_stage_from_state(self):
for task in self:
if task.stage_id.task_state == task.state:
continue
stage = task._find_stage_for_state(task.state)
if stage:
task.stage_id = stage

def _find_stage_for_state(self, state):
self.ensure_one()
if not state:
return self.env["project.task.type"]
return self.project_id.type_ids.filtered(
lambda s: s.task_state == state and s.sync_state_to_stage
)[:1]
41 changes: 41 additions & 0 deletions project_task_stage_state_sync/models/project_task_type.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html

from odoo import api, fields, models
from odoo.exceptions import ValidationError


class ProjectTaskType(models.Model):
_inherit = "project.task.type"

sync_state_to_stage = fields.Boolean(
string="Sync State → Stage",
help="If ticked, setting a task's state to the value configured above "
"will automatically move that task to this stage.",
)

@api.constrains("sync_state_to_stage", "task_state", "project_ids")
def _check_unique_sync_per_state_per_project(self):
for stage in self.filtered("sync_state_to_stage"):
if not stage.task_state:
continue
for project in stage.project_ids:
conflicting = project.type_ids.filtered(
lambda s, stage=stage: s.id != stage.id
and s.task_state == stage.task_state
and s.sync_state_to_stage
)
if conflicting:
state_label = dict(stage._get_task_states()).get(
stage.task_state, stage.task_state
)
raise ValidationError(
self.env._(
"Stage '%(conflicting_stage)s' in project '%(project)s' "
"is already configured to move tasks here when their state "
"is '%(state)s'. Only one stage per project can have "
"Sync State → Stage enabled for the same state value.",
conflicting_stage=conflicting[0].name,
project=project.name,
state=state_label,
)
)
3 changes: 3 additions & 0 deletions project_task_stage_state_sync/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[build-system]
requires = ["whool"]
build-backend = "whool.buildapi"
14 changes: 14 additions & 0 deletions project_task_stage_state_sync/readme/CONFIGURE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
On each stage (Project → Configuration → Stages):

1. Set the **State** field to the state that moving to this stage should assign.
2. Enable **Sync State → Stage** to also activate the reverse: tasks whose state
is set to that value will automatically move to this stage.

**Uniqueness rule:** Only one stage per project may have *Sync State → Stage*
enabled for a given state value. Attempting to enable it on a second stage that
shares the same state and project will raise a validation error naming the
conflicting stage. Two different projects are allowed to each
have their own stage with sync enabled for the same state — for example,
both "Project A / Done" and "Project B / Done" can independently have
*Sync State → Stage* ticked for the *Done* state. The uniqueness rule only
applies within a single project.
1 change: 1 addition & 0 deletions project_task_stage_state_sync/readme/CONTRIBUTORS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Isabel Andreu \<isabel.andreu@forgeflow.com\>
12 changes: 12 additions & 0 deletions project_task_stage_state_sync/readme/DESCRIPTION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
This module extends `project_task_stage_state` to complete the bidirectional
link between task states and stages.

`project_task_stage_state` already handles the **Stage → State** direction:
moving a task to a stage updates its state to the one configured on that stage.

This module adds the **State → Stage** direction: when a task's state changes
(manually or programmatically), the task is
automatically moved to the stage configured for that state.

The sync is configured per stage via a checkbox, so it can be enabled selectively
without affecting every stage in every project.
Loading
Loading