diff --git a/project_ux/README.rst b/project_ux/README.rst deleted file mode 100644 index b1cfba6c..00000000 --- a/project_ux/README.rst +++ /dev/null @@ -1,81 +0,0 @@ -.. |company| replace:: ADHOC SA - -.. |company_logo| image:: https://raw.githubusercontent.com/ingadhoc/maintainer-tools/master/resources/adhoc-logo.png - :alt: ADHOC SA - :target: https://www.adhoc.com.ar - -.. |icon| image:: https://raw.githubusercontent.com/ingadhoc/maintainer-tools/master/resources/adhoc-icon.png - -.. image:: https://img.shields.io/badge/license-AGPL--3-blue.png - :target: https://www.gnu.org/licenses/agpl - :alt: License: AGPL-3 - -========== -Project UX -========== - - -Several improvements to project: - -#. Change default behavior when click on the project card in the kanban view, now will go to the project form view instead of the project task kanban view. -#. Add a boolean toggle button called "Don't send stage email" that gives the user the chance to avoid sending the email if the stage has an automatic template set. After the stage changes, this value returns to false if the stage has an email template. -#. Add a button "i" in the card kanban view that links directly to the proyect updates. -#. Adds: - - 2 new filters: "Is Task"& "Is Sub-Task" - - 1 new agroupation: "Parent-Task" -#. Re-incorporates the wizard that allows to select an existing task to be converted as a sub-task in the sub-task tab (allows converting existing tasks to sub-tasks) -#. Incorporates a tab inside the project form view called "Task stages" that allows to select (or create) the task stages that will apply to that project. -#. Incorporates an option inside the tasks stage configurations that allows to automatically set a state to the tasks when they are moved to these stages. -#. Re-incorporate the field is_closed in the tasks, under the label "Folded in kanban" -#. Subtasks are created visible in the project's kanban view by default (display_in_project = True). - -Installation -============ - -To install this module, you need to: - -#. Just install the module. - -Configuration -============= - -To configure this module, you need to: - -#. Nothing to configure - -Usage -===== - -#. Just Use the module. - -.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas - :alt: Try me on Runbot - :target: http://runbot.adhoc.com.ar/ - -Bug Tracker -=========== - -Bugs are tracked on `GitHub Issues -`_. In case of trouble, please -check there if your issue has already been reported. If you spotted it first, -help us smashing it by providing a detailed and welcomed feedback. - -Credits -======= - -Images ------- - -* |company| |icon| - -Contributors ------------- - -Maintainer ----------- - -|company_logo| - -This module is maintained by the |company|. - -To contribute to this module, please visit https://www.adhoc.com.ar. diff --git a/project_ux/__init__.py b/project_ux/__init__.py deleted file mode 100644 index d0337769..00000000 --- a/project_ux/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -############################################################################## -# For copyright and license notices, see __manifest__.py file in module root -# directory -############################################################################## -from . import models diff --git a/project_ux/__manifest__.py b/project_ux/__manifest__.py deleted file mode 100644 index 50d4c3c5..00000000 --- a/project_ux/__manifest__.py +++ /dev/null @@ -1,48 +0,0 @@ -############################################################################## -# -# Copyright (C) 2015 ADHOC SA (http://www.adhoc.com.ar) -# All Rights Reserved. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## -{ - "name": "Project UX", - "version": "19.0.2.2.0", - "category": "Project Management", - "sequence": 14, - "author": "ADHOC SA", - "website": "www.adhoc.com.ar", - "license": "AGPL-3", - "images": [], - "depends": [ - "project", - "project_enterprise", - ], - "data": [ - "views/project_task_views.xml", - "views/project_project_views.xml", - "views/project_task_type_views.xml", - ], - "assets": { - "web.assets_backend": [ - "project_ux/static/src/**/*.js", - "project_ux/static/src/**/*.xml", - ], - }, - "demo": [], - "installable": False, - "auto_install": False, - "application": False, -} diff --git a/project_ux/i18n/es.po b/project_ux/i18n/es.po deleted file mode 100644 index 83f0a308..00000000 --- a/project_ux/i18n/es.po +++ /dev/null @@ -1,169 +0,0 @@ -# Translation of Odoo Server. -# This file contains the translation of the following modules: -# * project_ux -# -# Translators: -# Juan José Scarafía , 2025 -# ADHOC - Bot , 2025 -# -msgid "" -msgstr "" -"Project-Id-Version: Odoo Server 19.0+e\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-06-29 14:39+0000\n" -"PO-Revision-Date: 2026-06-30 15:01+0000\n" -"Last-Translator: BAF \n" -"Language-Team: Spanish \n" -"Language: es\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: \n" -"Plural-Forms: nplurals=3; plural=(n == 1) ? 0 : ((n != 0 && n % 1000000 == " -"0) ? 1 : 2);\n" -"X-Generator: Weblate 5.10.4\n" - -#. module: project_ux -#: model_terms:ir.ui.view,arch_db:project_ux.view_project_kanban -msgid "" -msgstr "" - -#. module: project_ux -#: model:ir.model.fields,field_description:project_ux.field_project_project__display_name -#: model:ir.model.fields,field_description:project_ux.field_project_task__display_name -#: model:ir.model.fields,field_description:project_ux.field_project_task_type__display_name -msgid "Display Name" -msgstr "Nombre para mostrar" - -#. module: project_ux -#: model:ir.model.fields,field_description:project_ux.field_project_task__dont_send_stage_email -msgid "Don't Send Stage Email" -msgstr "No enviar plantilla automatica en cambio de etapa" - -#. module: project_ux -#: model:ir.model.fields,field_description:project_ux.field_project_task__is_closed -msgid "Folded in Kanban" -msgstr "Estado cerrado" - -#. module: project_ux -#: model:ir.model.fields,field_description:project_ux.field_project_project__id -#: model:ir.model.fields,field_description:project_ux.field_project_task__id -#: model:ir.model.fields,field_description:project_ux.field_project_task_type__id -msgid "ID" -msgstr "ID" - -#. module: project_ux -#: model_terms:ir.ui.view,arch_db:project_ux.view_task_search_form -msgid "Is Sub-Task" -msgstr "Es Sub-Tarea" - -#. module: project_ux -#: model_terms:ir.ui.view,arch_db:project_ux.view_task_search_form -msgid "Is Task" -msgstr "Es Tarea" - -#. module: project_ux -#: model_terms:ir.ui.view,arch_db:project_ux.view_task_search_form -msgid "Parent Task" -msgstr "Tarea padre" - -#. module: project_ux -#: model:ir.model,name:project_ux.model_project_project -msgid "Project" -msgstr "Proyecto" - -#. module: project_ux -#: model_terms:ir.ui.view,arch_db:project_ux.task_type_edit_inherited -msgid "Select a state..." -msgstr "" - -#. module: project_ux -#: model:ir.model.fields,field_description:project_ux.field_project_project__show_task_id -#: model:ir.model.fields,field_description:project_ux.field_project_task__show_task_id -msgid "Show Task ID" -msgstr "Mostrar ID de tareas" - -#. module: project_ux -#: model_terms:ir.ui.view,arch_db:project_ux.edit_project -msgid "Show the task ID in the task form title and breadcrumb" -msgstr "" -"Mostrar el ID de la tarea en el título del formulario de tarea y en la ruta " -"de navegación (breadcrumb)" - -#. module: project_ux -#: model:ir.model.fields,field_description:project_ux.field_project_task_type__state_change -msgid "State Change" -msgstr "Cambio de estado" - -#. module: project_ux -#: model:ir.model,name:project_ux.model_project_task -msgid "Task" -msgstr "Tarea" - -#. module: project_ux -#: model_terms:ir.ui.view,arch_db:project_ux.view_task_search_form -msgid "Task ID" -msgstr "ID de tarea" - -#. module: project_ux -#: model:ir.model,name:project_ux.model_project_task_type -msgid "Task Stage" -msgstr "Etapa de la tarea" - -#. module: project_ux -#: model:ir.model.fields,field_description:project_ux.field_project_task_type__task_state -msgid "Task State" -msgstr "Estado de la tarea" - -#. module: project_ux -#: model_terms:ir.ui.view,arch_db:project_ux.edit_project -msgid "Tasks Stages" -msgstr "Etapas de tareas" - -#. module: project_ux -#: model:ir.model.fields,help:project_ux.field_project_task__display_name -msgid "" -"Use these keywords in the title to set new tasks:\n" -"\n" -" #tags Set tags on the task\n" -" @user Assign the task to a user\n" -" ! Set the task a medium priority\n" -" !! Set the task a high priority\n" -" !!! Set the task a urgent priority\n" -"\n" -" Make sure to use the right format and order e.g. Improve the " -"configuration screen #feature #v16 @Mitchell !" -msgstr "" -"Utiliza estas palabras clave en el título para establecer nuevas tareas:\n" -"\n" -" 30 h Asignar 30 horas a la tarea\n" -" #etiquetas Asignar etiquetas a la tarea\n" -" @usuario Asignar la tarea a un usuario\n" -" ! Asignar prioridad media a la tarea\n" -" !! Asignar prioridad alta a la tarea\n" -" !!! Asignar prioridad urgente a la tarea\n" -"\n" -" Asegúrate de utilizar el formato y el orden correcto, por ejemplo: " -"¡Mejorar la pantalla de configuración 5 h #función #v16 @Mitchell!" - -#. module: project_ux -#: model:ir.model.fields,help:project_ux.field_project_task__dont_send_stage_email -msgid "" -"When the task's stage changes, if the stage has an automatic template set, " -"no email will be send. After the stage changes, this value returns to False " -"so that new stage changes will send emails." -msgstr "" -"Si cambia la tarea de etapa, si la etapa de destino tiene una plantilla de " -"correo electrónico asignada dicha plantilla no será enviada. Una vez " -"desplazada la tarea a dicha etapa, este valor se reestablece a falso y se " -"reestablecerá el envío de las plantillas de correo electrónico." - -#. module: project_ux -#: model:ir.model.fields,help:project_ux.field_project_task_type__state_change -msgid "" -"When the task's stage changes, if the state change is checked it will change " -"the state of the task into the state selected" -msgstr "" -"Cuando se cambie una tarea de etapa, si la etapa tiene configurado un estado " -"de tarea por defecto, cambiará el estado de las tareas al configurado dentro " -"de la etapa." diff --git a/project_ux/i18n/project_ux.pot b/project_ux/i18n/project_ux.pot deleted file mode 100644 index a7007532..00000000 --- a/project_ux/i18n/project_ux.pot +++ /dev/null @@ -1,140 +0,0 @@ -# Translation of Odoo Server. -# This file contains the translation of the following modules: -# * project_ux -# -msgid "" -msgstr "" -"Project-Id-Version: Odoo Server 19.0+e\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-06-29 14:39+0000\n" -"PO-Revision-Date: 2026-06-29 14:39+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_ux -#: model_terms:ir.ui.view,arch_db:project_ux.view_project_kanban -msgid "" -msgstr "" - -#. module: project_ux -#: model:ir.model.fields,field_description:project_ux.field_project_project__display_name -#: model:ir.model.fields,field_description:project_ux.field_project_task__display_name -#: model:ir.model.fields,field_description:project_ux.field_project_task_type__display_name -msgid "Display Name" -msgstr "" - -#. module: project_ux -#: model:ir.model.fields,field_description:project_ux.field_project_task__dont_send_stage_email -msgid "Don't Send Stage Email" -msgstr "" - -#. module: project_ux -#: model:ir.model.fields,field_description:project_ux.field_project_task__is_closed -msgid "Folded in Kanban" -msgstr "" - -#. module: project_ux -#: model:ir.model.fields,field_description:project_ux.field_project_project__id -#: model:ir.model.fields,field_description:project_ux.field_project_task__id -#: model:ir.model.fields,field_description:project_ux.field_project_task_type__id -msgid "ID" -msgstr "" - -#. module: project_ux -#: model_terms:ir.ui.view,arch_db:project_ux.view_task_search_form -msgid "Is Sub-Task" -msgstr "" - -#. module: project_ux -#: model_terms:ir.ui.view,arch_db:project_ux.view_task_search_form -msgid "Is Task" -msgstr "" - -#. module: project_ux -#: model_terms:ir.ui.view,arch_db:project_ux.view_task_search_form -msgid "Parent Task" -msgstr "" - -#. module: project_ux -#: model:ir.model,name:project_ux.model_project_project -msgid "Project" -msgstr "" - -#. module: project_ux -#: model_terms:ir.ui.view,arch_db:project_ux.task_type_edit_inherited -msgid "Select a state..." -msgstr "" - -#. module: project_ux -#: model:ir.model.fields,field_description:project_ux.field_project_project__show_task_id -#: model:ir.model.fields,field_description:project_ux.field_project_task__show_task_id -msgid "Show Task ID" -msgstr "" - -#. module: project_ux -#: model_terms:ir.ui.view,arch_db:project_ux.edit_project -msgid "Show the task ID in the task form title and breadcrumb" -msgstr "" - -#. module: project_ux -#: model:ir.model.fields,field_description:project_ux.field_project_task_type__state_change -msgid "State Change" -msgstr "" - -#. module: project_ux -#: model:ir.model,name:project_ux.model_project_task -msgid "Task" -msgstr "" - -#. module: project_ux -#: model_terms:ir.ui.view,arch_db:project_ux.view_task_search_form -msgid "Task ID" -msgstr "" - -#. module: project_ux -#: model:ir.model,name:project_ux.model_project_task_type -msgid "Task Stage" -msgstr "" - -#. module: project_ux -#: model:ir.model.fields,field_description:project_ux.field_project_task_type__task_state -msgid "Task State" -msgstr "" - -#. module: project_ux -#: model_terms:ir.ui.view,arch_db:project_ux.edit_project -msgid "Tasks Stages" -msgstr "" - -#. module: project_ux -#: model:ir.model.fields,help:project_ux.field_project_task__display_name -msgid "" -"Use these keywords in the title to set new tasks:\n" -"\n" -" #tags Set tags on the task\n" -" @user Assign the task to a user\n" -" ! Set the task a medium priority\n" -" !! Set the task a high priority\n" -" !!! Set the task a urgent priority\n" -"\n" -" Make sure to use the right format and order e.g. Improve the configuration screen #feature #v16 @Mitchell !" -msgstr "" - -#. module: project_ux -#: model:ir.model.fields,help:project_ux.field_project_task__dont_send_stage_email -msgid "" -"When the task's stage changes, if the stage has an automatic template set, " -"no email will be send. After the stage changes, this value returns to False " -"so that new stage changes will send emails." -msgstr "" - -#. module: project_ux -#: model:ir.model.fields,help:project_ux.field_project_task_type__state_change -msgid "" -"When the task's stage changes, if the state change is checked it will change" -" the state of the task into the state selected" -msgstr "" diff --git a/project_ux/i18n/ru.po b/project_ux/i18n/ru.po deleted file mode 100644 index b9e9e97d..00000000 --- a/project_ux/i18n/ru.po +++ /dev/null @@ -1,122 +0,0 @@ -# Translation of Odoo Server. -# This file contains the translation of the following modules: -# * project_stage -# -# Translators: -# Juan José Scarafía , 2019 -# -msgid "" -msgstr "" -"Project-Id-Version: Odoo Server 12.0\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-12-26 00:39+0000\n" -"PO-Revision-Date: 2019-07-17 22:55+0000\n" -"Last-Translator: Juan José Scarafía , 2019\n" -"Language-Team: Russian (https://www.transifex.com/adhoc/teams/46451/ru/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: \n" -"Language: ru\n" -"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);\n" - -#. module: project_stage -#: model_terms:ir.ui.view,arch_db:project_stage.project_stage_form -msgid "Add a description..." -msgstr "" - -#. module: project_stage -#: model:ir.model.fields,field_description:project_stage.field_project_stage__create_uid -msgid "Created by" -msgstr "" - -#. module: project_stage -#: model:ir.model.fields,field_description:project_stage.field_project_stage__create_date -msgid "Created on" -msgstr "" - -#. module: project_stage -#: model:ir.model.fields,field_description:project_stage.field_project_stage__case_default -msgid "Default for New Projects" -msgstr "" - -#. module: project_stage -#: model:ir.model.fields,field_description:project_stage.field_project_stage__description -msgid "Description" -msgstr "Описание" - -#. module: project_stage -#: model:ir.model.fields,field_description:project_stage.field_project_stage__display_name -msgid "Display Name" -msgstr "" - -#. module: project_stage -#: model:ir.model.fields,field_description:project_stage.field_project_stage__fold -msgid "Folded in Kanban View" -msgstr "" - -#. module: project_stage -#: model:ir.model.fields,field_description:project_stage.field_project_stage__id -msgid "ID" -msgstr "" - -#. module: project_stage -#: model:ir.model.fields,help:project_stage.field_project_stage__case_default -msgid "" -"If you check this field, this stage will be proposed by default on each new " -"project. It will not assign this stage to existing projects." -msgstr "" - -#. module: project_stage -#: model:ir.model.fields,field_description:project_stage.field_project_stage____last_update -msgid "Last Modified on" -msgstr "" - -#. module: project_stage -#: model:ir.model.fields,field_description:project_stage.field_project_stage__write_uid -msgid "Last Updated by" -msgstr "" - -#. module: project_stage -#: model:ir.model.fields,field_description:project_stage.field_project_stage__write_date -msgid "Last Updated on" -msgstr "" - -#. module: project_stage -#: model:ir.model,name:project_stage.model_project_project -msgid "Project" -msgstr "" - -#. module: project_stage -#: model:ir.model,name:project_stage.model_project_stage -#: model_terms:ir.ui.view,arch_db:project_stage.project_stage_form -msgid "Project Stage" -msgstr "" - -#. module: project_stage -#: model:ir.actions.act_window,name:project_stage.action_project_stage -#: model:ir.ui.menu,name:project_stage.project_stages -msgid "Project Stages" -msgstr "" - -#. module: project_stage -#: model:ir.model.fields,field_description:project_stage.field_project_stage__sequence -msgid "Sequence" -msgstr "" - -#. module: project_stage -#: model:ir.model.fields,field_description:project_stage.field_project_project__stage_id -#: model_terms:ir.ui.view,arch_db:project_stage.project_search -msgid "Stage" -msgstr "" - -#. module: project_stage -#: model:ir.model.fields,field_description:project_stage.field_project_stage__name -msgid "Stage Name" -msgstr "" - -#. module: project_stage -#: model:ir.model.fields,help:project_stage.field_project_stage__fold -msgid "" -"This stage is folded in the kanban view whenthere are no records in that " -"stage to display." -msgstr "" diff --git a/project_ux/models/__init__.py b/project_ux/models/__init__.py deleted file mode 100644 index cc9f3090..00000000 --- a/project_ux/models/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -############################################################################## -############################################################################## -# For copyright and license notices, see __manifest__.py file in module root -# directory -############################################################################## -from . import project_project -from . import project_task_type -from . import project_task diff --git a/project_ux/models/project_project.py b/project_ux/models/project_project.py deleted file mode 100644 index ec0a0a8a..00000000 --- a/project_ux/models/project_project.py +++ /dev/null @@ -1,13 +0,0 @@ -############################################################################## -# For copyright and license notices, see __manifest__.py file in module root -# directory -############################################################################## -from odoo import fields, models - - -class ProjectProject(models.Model): - _inherit = "project.project" - - show_task_id = fields.Boolean( - string="Show Task ID", - ) diff --git a/project_ux/models/project_task.py b/project_ux/models/project_task.py deleted file mode 100644 index 5e23329e..00000000 --- a/project_ux/models/project_task.py +++ /dev/null @@ -1,148 +0,0 @@ -############################################################################## -# For copyright and license notices, see __manifest__.py file in module root -# directory -############################################################################## -from odoo import api, fields, models -from odoo.fields import Domain - -CLOSED_STATES = { - "1_done": "Done", - "1_canceled": "Canceled", -} - - -class Task(models.Model): - _inherit = "project.task" - - @api.model - def _get_id_prefix_domain(self, prefix): - enabled_domain = Domain("project_id.show_task_id", "=", True) - max_task_id = self.search([("project_id.show_task_id", "=", True)], order="id desc", limit=1).id - if not max_task_id: - return Domain.FALSE - - prefix_int = int(prefix) - prefix_domains = [Domain.AND([enabled_domain, Domain("id", "=", prefix_int)])] - factor = 10 - while prefix_int * factor <= max_task_id: - prefix_domains.append( - Domain.AND( - [ - enabled_domain, - Domain("id", ">=", prefix_int * factor), - Domain("id", "<", (prefix_int + 1) * factor), - ] - ) - ) - factor *= 10 - return Domain.OR(prefix_domains) - - display_in_project = fields.Boolean(default=True) - - @api.depends("project_id") - def _compute_display_in_project(self): - """We always want subtasks to be displayed in the project pipeline. - By default Odoo hides subtasks that share the same project as their - parent, making them invisible in kanban/list views. We override to - always set True so every task is visible. Users can still manually - hide individual tasks using the 'Hide in pipeline' button. - """ - for task in self: - task.display_in_project = True - - @api.model_create_multi - def create(self, vals_list): - """Force display_in_project=True on creation. - Odoo's views pass 'default_display_in_project': False in the context - when creating subtasks, which overrides both the field default and the - compute. We force it here so subtasks are always visible in the - pipeline. - """ - for vals in vals_list: - vals["display_in_project"] = True - return super().create(vals_list) - - show_task_id = fields.Boolean(related="project_id.show_task_id", readonly=True) - dont_send_stage_email = fields.Boolean( - string="Don't Send Stage Email", - default=False, - help="When the task's stage changes, if the stage has an automatic template set, " - "no email will be send. After the stage changes, this value returns to False so that " - "new stage changes will send emails.", - ) - is_closed = fields.Boolean(related="stage_id.fold", string="Folded in Kanban", index=True) - - @api.depends("name", "project_id.show_task_id") - def _compute_display_name(self): - super()._compute_display_name() - for task in self: - if task.project_id.show_task_id and task.id and task.display_name: - task.display_name = f"{task.display_name} (#{task.id})" - - def onchange(self, values, field_names, fields_spec): - result = super().onchange(values, field_names, fields_spec) - # In the quick-create (My Tasks, project kanban) the "Task Title" input - # is bound to display_name and is only inversed into `name` on save. - # Because this module makes display_name depend on project_id (to append - # the task id), changing the project recomputes display_name from the - # still-empty `name`, blanking the title the user just typed. Restore the - # typed value in the onchange result so it survives the project change. - typed_title = values.get("display_name") - if ( - "project_id" in (field_names or []) - and typed_title - and not values.get("name") - and not result.get("value", {}).get("display_name") - ): - result.setdefault("value", {})["display_name"] = typed_title - return result - - @api.model - def _search_display_name(self, operator, value): - domain = super()._search_display_name(operator, value) - normalized_name = (value or "").strip() - if normalized_name.startswith("#"): - normalized_name = normalized_name[1:].strip() - - if normalized_name.isdigit() and operator in ("ilike", "like", "=ilike", "=like"): - return Domain.OR([domain, self._get_id_prefix_domain(normalized_name)]) - - return domain - - def _track_template(self, changes): - task = self[0] - res = super()._track_template(changes) - if "stage_id" in changes and task.stage_id.mail_template_id: - res["stage_id"] = ( - task.stage_id.mail_template_id, - { - "message_type": "comment", - "auto_delete_keep_log": False, - "subtype_id": self.env["ir.model.data"]._xmlid_to_res_id("mail.mt_comment"), - "email_layout_xmlid": "mail.mail_notification_light", - }, - ) - if "stage_id" in res and task.dont_send_stage_email and task.stage_id.mail_template_id: - res.pop("stage_id") - task.dont_send_stage_email = False - return res - - @api.depends("stage_id", "depend_on_ids.state", "project_id.allow_task_dependencies") - def _compute_state(self): - for task in self: - dependent_open_tasks = [] - if task.allow_task_dependencies: - dependent_open_tasks = [ - dependent_task for dependent_task in task.depend_on_ids if dependent_task.state not in CLOSED_STATES - ] - # if one of the blocking task is in a blocking state - if dependent_open_tasks: - # here we check that the blocked task is not already in a closed state (if the task is already done we don't put it in waiting state) - if task.state not in CLOSED_STATES: - task.state = "04_waiting_normal" - # if the task as no blocking dependencies and is in waiting_normal, the task goes back to in progress - elif task.state not in CLOSED_STATES: - task.state = "01_in_progress" - if task.stage_id.task_state: - task.state = task.stage_id.task_state - task._inverse_state() diff --git a/project_ux/models/project_task_type.py b/project_ux/models/project_task_type.py deleted file mode 100644 index c5e7a42a..00000000 --- a/project_ux/models/project_task_type.py +++ /dev/null @@ -1,27 +0,0 @@ -############################################################################## -# For copyright and license notices, see __manifest__.py file in module root -# directory -############################################################################## -from odoo import api, fields, models -from odoo.exceptions import UserError - - -class ProjectTaskType(models.Model): - _inherit = "project.task.type" - - state_change = fields.Boolean( - default=False, - help="When the task's stage changes, if the state change is checked it will change the state of the task into the state selected", - ) - - task_state = fields.Selection( - selection=lambda self: self.env["project.task"].fields_get(allfields=["state"])["state"]["selection"] - ) - - @api.constrains("state_change", "task_state") - def _check_task_state(self): - for record in self: - if record.state_change and not record.task_state: - raise UserError( - "The state to which the task should change cannot be empty if 'state change' is checked" - ) diff --git a/project_ux/static/src/js/project_task_control_panel_patch.js b/project_ux/static/src/js/project_task_control_panel_patch.js deleted file mode 100644 index 282913fa..00000000 --- a/project_ux/static/src/js/project_task_control_panel_patch.js +++ /dev/null @@ -1,23 +0,0 @@ -import { patch } from "@web/core/utils/patch"; -import { ProjectTaskControlPanel } from "@project/views/project_task_control_panel/project_task_control_panel"; -import { hasSubtaskLeaf } from "./subtask_domain"; - -patch(ProjectTaskControlPanel.prototype, { - /** - * The "Is Sub-Task" filter forces sub-tasks to be visible: the model drops - * the `display_in_project` restriction while that filter is active (see - * project_task_list_model_patch). While it is active the "Show Sub-Tasks" - * toggle has no real effect. - */ - get isSubtaskFilterActive() { - return hasSubtaskLeaf(this.env.searchModel.domain); - }, - - /** - * State the toggle is painted with: also selected when the filter forces - * it, to avoid the confusing "off but showing sub-tasks" state. - */ - get effectiveShowSubtasks() { - return this.state.showSubtasks || this.isSubtaskFilterActive; - }, -}); diff --git a/project_ux/static/src/js/project_task_list_model_patch.js b/project_ux/static/src/js/project_task_list_model_patch.js deleted file mode 100644 index 413ebeb5..00000000 --- a/project_ux/static/src/js/project_task_list_model_patch.js +++ /dev/null @@ -1,25 +0,0 @@ -import { patch } from "@web/core/utils/patch"; -import { Domain } from "@web/core/domain"; -import { ProjectTaskRelationalModel } from "@project/views/project_task_relational_model"; -import { hasSubtaskLeaf } from "./subtask_domain"; - -patch(ProjectTaskRelationalModel.prototype, { - /** - * When the user filters explicitly by sub-tasks ("Is Sub-Task" filter), - * the core still hides them while the "Show Sub-Tasks" mode is off: it - * injects `display_in_project = True`, which is False for any sub-task - * sharing its parent's project. The result is an empty list with no hint, - * so the sub-task looks like it does not exist. - * - * If the sub-task filter is active, drop that leaf to honor the filter and - * show the sub-tasks without requiring the user to toggle the display mode - * by hand. - */ - _processSearchDomain(domain) { - const processed = super._processSearchDomain(domain); - if (hasSubtaskLeaf(domain)) { - return Domain.removeDomainLeaves(processed, ["display_in_project"]).toList({}); - } - return processed; - }, -}); diff --git a/project_ux/static/src/js/subtask_domain.js b/project_ux/static/src/js/subtask_domain.js deleted file mode 100644 index 570545c8..00000000 --- a/project_ux/static/src/js/subtask_domain.js +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Whether a search domain explicitly restricts results to sub-tasks, i.e. it - * contains a `parent_id != False` leaf (as emitted by the "Is Sub-Task" - * filter). Walks the domain in list form, including nested sub-domains. - * - * @param {Array} domain domain in list form - * @returns {boolean} - */ -export function hasSubtaskLeaf(domain) { - if (!Array.isArray(domain)) { - return false; - } - for (const item of domain) { - if (!Array.isArray(item)) { - continue; - } - if (item.length === 3) { - if (item[0] === "parent_id" && item[1] === "!=" && item[2] === false) { - return true; - } - } else if (hasSubtaskLeaf(item)) { - return true; - } - } - return false; -} diff --git a/project_ux/static/src/xml/project_task_control_panel.xml b/project_ux/static/src/xml/project_task_control_panel.xml deleted file mode 100644 index 9c44022b..00000000 --- a/project_ux/static/src/xml/project_task_control_panel.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - effectiveShowSubtasks ? 'selected' : '' - - - - - - effectiveShowSubtasks ? 'selected' : '' - - - - diff --git a/project_ux/tests/__init__.py b/project_ux/tests/__init__.py deleted file mode 100644 index 41f2124c..00000000 --- a/project_ux/tests/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from . import test_project_task -from . import test_project_task_type -from . import test_project_project diff --git a/project_ux/tests/test_project_project.py b/project_ux/tests/test_project_project.py deleted file mode 100644 index 99921169..00000000 --- a/project_ux/tests/test_project_project.py +++ /dev/null @@ -1,28 +0,0 @@ -from odoo.tests.common import TransactionCase - - -class TestProjectProject(TransactionCase): - def setUp(self): - super().setUp() - self.Project = self.env["project.project"] - - def test_create_project_modal_button_opens_form(self): - """The "Create project" button of the New modal must open the project - form (via the standard get_formview_action), not the task pipeline - (action_view_tasks). - """ - view = self.env.ref("project.project_project_view_form_simplified_footer") - combined_arch = view.get_combined_arch() - self.assertIn('name="get_formview_action"', combined_arch) - self.assertNotIn('name="action_view_tasks"', combined_arch) - - def test_get_formview_action_lands_on_project_form(self): - """get_formview_action opens the created project's own form.""" - project = self.Project.create({"name": "New Project"}) - - action = project.get_formview_action() - - self.assertEqual(action["res_model"], "project.project") - self.assertEqual(action["res_id"], project.id) - self.assertEqual(action["target"], "current") - self.assertTrue(any(view_type == "form" for __, view_type in action["views"])) diff --git a/project_ux/tests/test_project_task.py b/project_ux/tests/test_project_task.py deleted file mode 100644 index 24f9a75f..00000000 --- a/project_ux/tests/test_project_task.py +++ /dev/null @@ -1,118 +0,0 @@ -from odoo.tests import Form -from odoo.tests.common import TransactionCase - - -class TestTaskModel(TransactionCase): - def setUp(self): - super(TestTaskModel, self).setUp() - self.Project = self.env["project.project"] - self.Task = self.env["project.task"] - self.Stage = self.env["project.task.type"] - self.Template = self.env["mail.template"] - - mail_template = self.Template.create( - { - "name": "Test Template", - "email_from": "test@example.com", - "subject": "Test Subject", - "body_html": "

Test Body

", - } - ) - - self.test_stage = self.Stage.create({"name": "Test Stage", "mail_template_id": mail_template.id}) - self.test_project = self.Project.create({"name": "Test Project"}) - - self.test_task = self.Task.create( - { - "name": "Test Task", - "project_id": self.test_project.id, - "stage_id": self.test_stage.id, - "state": "01_in_progress", - } - ) - - def test_compute_state_with_dependencies(self): - """Test _compute_state method when dependencies are present""" - dependent_task = self.Task.create( - {"name": "Dependent Task", "stage_id": self.test_stage.id, "state": "01_in_progress"} - ) - self.test_task.write({"depend_on_ids": [(4, dependent_task.id)], "allow_task_dependencies": True}) - self.test_task._compute_state() - self.assertEqual(self.test_task.state, "04_waiting_normal") - dependent_task.state = "1_done" - self.test_task._compute_state() - self.assertEqual(self.test_task.state, "01_in_progress") - - def test_task_display_name_shows_id_when_enabled_on_project(self): - self.assertEqual(self.test_task.display_name, "Test Task") - - self.test_project.show_task_id = True - - self.assertEqual(self.test_task.display_name, f"Test Task (#{self.test_task.id})") - - def test_task_display_name_hides_id_when_disabled_on_project(self): - self.test_project.show_task_id = True - self.assertEqual(self.test_task.display_name, f"Test Task (#{self.test_task.id})") - - self.test_project.show_task_id = False - - self.assertEqual(self.test_task.display_name, "Test Task") - - def test_name_search_finds_task_by_plain_id_when_enabled_on_project(self): - self.test_project.show_task_id = True - - result = self.Task.name_search(str(self.test_task.id), limit=1) - - self.assertEqual(result, [(self.test_task.id, f"Test Task (#{self.test_task.id})")]) - - def test_name_search_finds_task_by_hash_prefixed_id_when_enabled_on_project(self): - self.test_project.show_task_id = True - - result = self.Task.name_search(f"#{self.test_task.id}", limit=1) - - self.assertEqual(result, [(self.test_task.id, f"Test Task (#{self.test_task.id})")]) - - def test_name_search_finds_tasks_by_id_prefix_when_enabled_on_project(self): - self.test_project.show_task_id = True - - tasks = self.test_task - while tasks[-1].id < 10: - tasks |= self.Task.create( - { - "name": f"Test Task {len(tasks)}", - "project_id": self.test_project.id, - "stage_id": self.test_stage.id, - "state": "01_in_progress", - } - ) - - prefix = str(tasks[-1].id)[:-1] - result_ids = [task_id for task_id, __ in self.Task.name_search(prefix, limit=20)] - - self.assertIn(tasks[-1].id, result_ids) - - def test_name_search_does_not_find_task_by_id_when_disabled_on_project(self): - result_ids = [task_id for task_id, __ in self.Task.name_search(str(self.test_task.id), limit=20)] - - self.assertNotIn(self.test_task.id, result_ids) - - def _check_quick_create_keeps_title(self, title): - """Quick-create binds the "Task Title" to display_name (not name). - Selecting/changing the project must not wipe a title already typed. - """ - with Form(self.Task, view="project.quick_create_task_form") as task_form: - task_form.display_name = title - task_form.project_id = self.test_project - self.assertEqual(task_form.display_name, title) - task = task_form.record - self.assertEqual(task.name, title) - self.assertEqual(task.project_id, self.test_project) - - def test_quick_create_keeps_title_when_selecting_project(self): - self._check_quick_create_keeps_title("My Title") - - def test_quick_create_keeps_title_when_project_shows_task_id(self): - # The title must survive the project onchange even though display_name - # depends on project_id.show_task_id. - self.test_project.show_task_id = True - self._check_quick_create_keeps_title("Another Title") diff --git a/project_ux/tests/test_project_task_type.py b/project_ux/tests/test_project_task_type.py deleted file mode 100644 index 87fe2284..00000000 --- a/project_ux/tests/test_project_task_type.py +++ /dev/null @@ -1,13 +0,0 @@ -from odoo.exceptions import UserError -from odoo.tests.common import TransactionCase - - -class TestProjectTaskType(TransactionCase): - def setUp(self): - super(TestProjectTaskType, self).setUp() - self.ProjectTaskType = self.env["project.task.type"] - - def test_state_change_constraint_error(self): - """Test that UserError is raised when state_change is True and task_state is empty""" - with self.assertRaises(UserError): - self.ProjectTaskType.create({"name": "Test Task Type", "state_change": True, "task_state": ""}) diff --git a/project_ux/views/project_project_views.xml b/project_ux/views/project_project_views.xml deleted file mode 100644 index 3d19129f..00000000 --- a/project_ux/views/project_project_views.xml +++ /dev/null @@ -1,78 +0,0 @@ - - - - - project.project.kanban - project.project - - - - - - - - - o_kanban_dashboard o_project_kanban o_emphasize_colors - - - -
- - - - - -
-
-
-
- - - project.project.form - project.project - - - - - - - - - - - - - - - - - - - - - project.group_project_user - - - - - - - - - - - - project.project.view.form.simplified.open.form - project.project - - - - get_formview_action - - - - -
diff --git a/project_ux/views/project_task_type_views.xml b/project_ux/views/project_task_type_views.xml deleted file mode 100644 index 251a5517..00000000 --- a/project_ux/views/project_task_type_views.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - project.task.type.form.inherited - project.task.type - - - - - - - - diff --git a/project_ux/views/project_task_views.xml b/project_ux/views/project_task_views.xml deleted file mode 100644 index e966989d..00000000 --- a/project_ux/views/project_task_views.xml +++ /dev/null @@ -1,81 +0,0 @@ - - - - - project.task2.inherit - project.task - - - - - - - - - - - # - - - - many2many - - - - - - project.task.kanban.inherit - project.task - - 90 - primary - - - - - - - - - project.task.search.inherit - project.task - - - - - - - - - - - - - - - - - - - - - - [('project_id', '=', active_id)] - { - 'default_project_id': active_id, - 'show_project_update': True, - 'search_default_is_task': 1, - } - - - - project.task.view.form - project.task - - - - [] - - - -