mirror of
https://github.com/OCA/knowledge.git
synced 2026-01-03 18:17:46 -06:00
[ADD] document_page_project_task: add new module
This commit is contained in:
267
document_page_project_task/README.rst
Normal file
267
document_page_project_task/README.rst
Normal file
@@ -0,0 +1,267 @@
|
||||
==========================
|
||||
Document Page Project Task
|
||||
==========================
|
||||
|
||||
..
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
!! This file is generated by oca-gen-addon-readme !!
|
||||
!! changes will be overwritten. !!
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
!! source digest: sha256:792f27beb9e30e02336420e9ffafb95a1a3027dc4b2ff368b4d350c683de3b01
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
.. |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/licence-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%2Fknowledge-lightgray.png?logo=github
|
||||
:target: https://github.com/OCA/knowledge/tree/16.0/document_page_project_task
|
||||
:alt: OCA/knowledge
|
||||
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
|
||||
:target: https://translation.odoo-community.org/projects/knowledge-16-0/knowledge-16-0-document_page_project_task
|
||||
: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/knowledge&target_branch=16.0
|
||||
:alt: Try me on Runboat
|
||||
|
||||
|badge1| |badge2| |badge3| |badge4| |badge5|
|
||||
|
||||
This module extends the document page (wiki) functionality by allowing
|
||||
you to link them directly to project tasks.
|
||||
|
||||
Main Features
|
||||
-------------
|
||||
|
||||
- **Link Wiki Pages to Tasks**: Allows associating document pages to
|
||||
specific project tasks
|
||||
- **Automatic Project Filling**: When a task is selected, the related
|
||||
project is automatically filled
|
||||
- **Consistency Validation**: Ensures that the wiki page's project is
|
||||
always the same as the linked task's project
|
||||
- **Smart Filtering**: When a project is defined, only tasks from that
|
||||
project are displayed for selection
|
||||
- **Page Counter**: Displays the number of wiki pages linked to each
|
||||
task directly in the task view
|
||||
|
||||
Benefits
|
||||
--------
|
||||
|
||||
- Organize project documentation hierarchically (Project → Task → Wiki)
|
||||
- Keep documentation close to the work context (tasks)
|
||||
- Avoid inconsistencies between projects and tasks through automatic
|
||||
validations
|
||||
- Quickly access documentation related to a specific task
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
|
||||
This module requires:
|
||||
|
||||
- ``document_page_project``: Module that links document pages to
|
||||
projects
|
||||
- ``project``: Odoo's project management module
|
||||
|
||||
**Table of contents**
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
|
||||
Configuration
|
||||
=============
|
||||
|
||||
This module does not require additional configuration after
|
||||
installation. It works automatically once installed.
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
1. Go to the **Apps** menu
|
||||
2. Remove the "Apps" filter if necessary
|
||||
3. Search for "Document Page Project Task"
|
||||
4. Click **Install**
|
||||
|
||||
Prerequisites
|
||||
-------------
|
||||
|
||||
Make sure the following modules are installed:
|
||||
|
||||
- **Project** (base project module)
|
||||
- **Document Page Project** (links wiki pages to projects)
|
||||
|
||||
The system will automatically install the necessary dependencies during
|
||||
installation.
|
||||
|
||||
Permissions
|
||||
-----------
|
||||
|
||||
The module uses the same access permissions as the base modules:
|
||||
|
||||
- Users with access to **Projects** can view and create wiki pages
|
||||
linked to tasks
|
||||
- Users with access to **Documents/Knowledge** can manage wiki page
|
||||
content
|
||||
|
||||
No additional permission configuration is required.
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
This guide explains how to use the Document Page Project Task module to
|
||||
link wiki pages to project tasks.
|
||||
|
||||
Create a Wiki Page from a Task
|
||||
------------------------------
|
||||
|
||||
**Method 1: From the Task**
|
||||
|
||||
1. Go to the **Projects** module
|
||||
2. Open the desired project
|
||||
3. Select a task
|
||||
4. In the task view, locate the **Wiki Pages** button (book icon)
|
||||
5. Click the button to see linked pages or create a new one
|
||||
6. Click **Create** to add a new wiki page
|
||||
7. The task and project will be automatically filled
|
||||
|
||||
**Method 2: From the Wiki Page**
|
||||
|
||||
1. Go to the **Knowledge** or **Documents** module
|
||||
2. Create a new wiki page or edit an existing one
|
||||
3. In the page form, you will see the fields:
|
||||
|
||||
- **Project**: Select the project
|
||||
- **Task**: Select the task (only tasks from the selected project
|
||||
will be displayed)
|
||||
|
||||
4. When you select a task, the project will be automatically filled
|
||||
5. Save the page
|
||||
|
||||
Automatic Behaviors
|
||||
-------------------
|
||||
|
||||
**Automatic Project Filling**
|
||||
|
||||
When you select a task:
|
||||
|
||||
- The **Project** field is automatically filled with the task's project
|
||||
- This ensures consistency between task and project
|
||||
|
||||
**Task Filtering**
|
||||
|
||||
When a project is selected:
|
||||
|
||||
- Only tasks from that project appear in the selection list
|
||||
- This prevents selecting tasks from different projects
|
||||
|
||||
**Consistency Validation**
|
||||
|
||||
The system automatically validates that:
|
||||
|
||||
- If a task is linked, the project must also be defined
|
||||
- The wiki page's project must be the same as the linked task's project
|
||||
- If you try to link a task to a different project, the system will
|
||||
prevent the operation
|
||||
|
||||
**Automatic Cleanup**
|
||||
|
||||
When you change the project:
|
||||
|
||||
- If the linked task does not belong to the new project, it is
|
||||
automatically removed
|
||||
- This maintains data consistency
|
||||
|
||||
View Wiki Pages of a Task
|
||||
-------------------------
|
||||
|
||||
1. Access a project task
|
||||
2. At the top of the form, you will see the **Wiki Pages** button with a
|
||||
counter
|
||||
3. The displayed number indicates how many wiki pages are linked to the
|
||||
task
|
||||
4. Click the button to see all linked pages
|
||||
|
||||
Usage Examples
|
||||
--------------
|
||||
|
||||
**Example 1: Requirements Documentation**
|
||||
|
||||
1. Create a task "Define System Requirements"
|
||||
2. From the task, create a wiki page "Functional Requirements"
|
||||
3. Document the requirements in the wiki page
|
||||
4. The page will be linked to the task and project
|
||||
|
||||
**Example 2: Meeting Notes**
|
||||
|
||||
1. Create a task "Planning Meeting"
|
||||
2. Create a wiki page "Meeting Minutes"
|
||||
3. Document the discussed points
|
||||
4. The documentation will be organized and easy to find
|
||||
|
||||
**Example 3: Technical Specifications**
|
||||
|
||||
1. Create a task "Develop Module X"
|
||||
2. Create a wiki page "Technical Specification"
|
||||
3. Document the architecture and technical decisions
|
||||
4. Keep the documentation close to the task work
|
||||
|
||||
Tips
|
||||
----
|
||||
|
||||
- Use wiki pages to maintain contextual documentation related to
|
||||
specific tasks
|
||||
- The page counter on the task helps quickly identify tasks with
|
||||
documentation
|
||||
- When creating a page from the task, fields are automatically filled,
|
||||
saving time
|
||||
- Organize project documentation hierarchically: Project → Task → Wiki
|
||||
|
||||
Bug Tracker
|
||||
===========
|
||||
|
||||
Bugs are tracked on `GitHub Issues <https://github.com/OCA/knowledge/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/knowledge/issues/new?body=module:%20document_page_project_task%0Aversion:%2016.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
|
||||
=======
|
||||
|
||||
Authors
|
||||
-------
|
||||
|
||||
* Escodoo
|
||||
|
||||
Contributors
|
||||
------------
|
||||
|
||||
- `ESCODOO <https://escodoo.com.br>`__:
|
||||
|
||||
- Marcel Savegnago <marcel.savegnago@escodoo.com.br>
|
||||
|
||||
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.
|
||||
|
||||
.. |maintainer-marcelsavegnago| image:: https://github.com/marcelsavegnago.png?size=40px
|
||||
:target: https://github.com/marcelsavegnago
|
||||
:alt: marcelsavegnago
|
||||
|
||||
Current `maintainer <https://odoo-community.org/page/maintainer-role>`__:
|
||||
|
||||
|maintainer-marcelsavegnago|
|
||||
|
||||
This module is part of the `OCA/knowledge <https://github.com/OCA/knowledge/tree/16.0/document_page_project_task>`_ project on GitHub.
|
||||
|
||||
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
|
||||
1
document_page_project_task/__init__.py
Normal file
1
document_page_project_task/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import models
|
||||
16
document_page_project_task/__manifest__.py
Normal file
16
document_page_project_task/__manifest__.py
Normal file
@@ -0,0 +1,16 @@
|
||||
# Copyright 2025 Escodoo <https://escodoo.com.br>
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
{
|
||||
"name": "Document Page Project Task",
|
||||
"summary": "This module links document pages to project tasks",
|
||||
"version": "16.0.1.0.0",
|
||||
"category": "Project",
|
||||
"author": "Escodoo, Odoo Community Association (OCA)",
|
||||
"maintainers": ["marcelsavegnago"],
|
||||
"website": "https://github.com/OCA/knowledge",
|
||||
"license": "AGPL-3",
|
||||
"depends": ["document_page_project"],
|
||||
"data": ["views/document_page_views.xml", "views/project_task_views.xml"],
|
||||
"installable": True,
|
||||
}
|
||||
2
document_page_project_task/models/__init__.py
Normal file
2
document_page_project_task/models/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
from . import document_page
|
||||
from . import project_task
|
||||
67
document_page_project_task/models/document_page.py
Normal file
67
document_page_project_task/models/document_page.py
Normal file
@@ -0,0 +1,67 @@
|
||||
# Copyright 2025 Marcel Savegnago - Escodoo <https://escodoo.com.br>
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
|
||||
class DocumentPage(models.Model):
|
||||
_inherit = "document.page"
|
||||
|
||||
task_id = fields.Many2one(string="Task", comodel_name="project.task")
|
||||
|
||||
@api.onchange("task_id")
|
||||
def _onchange_task_id(self):
|
||||
"""Fill the project_id field with the task's related project."""
|
||||
if self.task_id and self.task_id.project_id:
|
||||
self.project_id = self.task_id.project_id
|
||||
|
||||
@api.onchange("project_id")
|
||||
def _onchange_project_id(self):
|
||||
"""Clear the task if the project is removed or changed and does not
|
||||
match the task's project."""
|
||||
if self.task_id:
|
||||
if not self.project_id or self.task_id.project_id != self.project_id:
|
||||
self.task_id = False
|
||||
|
||||
@api.constrains("task_id", "project_id")
|
||||
def _check_task_project_consistency(self):
|
||||
"""Ensure that the project is the same as the task's project when a
|
||||
task is defined."""
|
||||
for record in self:
|
||||
# If there is a task, there must be a project
|
||||
if record.task_id and not record.project_id:
|
||||
raise ValidationError(
|
||||
_(
|
||||
"When a task is linked, the project must be defined. "
|
||||
"Task '%(task)s' requires that the project be defined.",
|
||||
task=record.task_id.name,
|
||||
)
|
||||
)
|
||||
# If there is a task and project, they must be from the same project
|
||||
if record.task_id and record.project_id:
|
||||
if record.task_id.project_id != record.project_id:
|
||||
raise ValidationError(
|
||||
_(
|
||||
"The wiki document's project must be the same as the "
|
||||
"task's project. Task '%(task)s' belongs to project "
|
||||
"'%(task_project)s', but the document is associated "
|
||||
"with project '%(doc_project)s'.",
|
||||
task=record.task_id.name,
|
||||
task_project=record.task_id.project_id.name,
|
||||
doc_project=record.project_id.name,
|
||||
)
|
||||
)
|
||||
|
||||
@api.model
|
||||
def default_get(self, fields_list):
|
||||
"""Fill the project_id when the wiki is created with default_task_id
|
||||
in the context."""
|
||||
res = super().default_get(fields_list)
|
||||
if "default_task_id" in self.env.context and "project_id" in fields_list:
|
||||
task = self.env["project.task"].browse(
|
||||
self.env.context.get("default_task_id")
|
||||
)
|
||||
if task.exists() and task.project_id:
|
||||
res["project_id"] = task.project_id.id
|
||||
return res
|
||||
18
document_page_project_task/models/project_task.py
Normal file
18
document_page_project_task/models/project_task.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Copyright 2025 Marcel Savegnago - Escodoo <https://escodoo.com.br>
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class ProjectTask(models.Model):
|
||||
_inherit = "project.task"
|
||||
|
||||
document_page_ids = fields.One2many(
|
||||
string="Wiki Pages", comodel_name="document.page", inverse_name="task_id"
|
||||
)
|
||||
document_page_count = fields.Integer(compute="_compute_document_page_count")
|
||||
|
||||
@api.depends("document_page_ids")
|
||||
def _compute_document_page_count(self):
|
||||
for rec in self:
|
||||
rec.document_page_count = len(rec.document_page_ids)
|
||||
24
document_page_project_task/readme/CONFIGURE.md
Normal file
24
document_page_project_task/readme/CONFIGURE.md
Normal file
@@ -0,0 +1,24 @@
|
||||
This module does not require additional configuration after installation. It works automatically once installed.
|
||||
|
||||
## Installation
|
||||
|
||||
1. Go to the **Apps** menu
|
||||
2. Remove the "Apps" filter if necessary
|
||||
3. Search for "Document Page Project Task"
|
||||
4. Click **Install**
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Make sure the following modules are installed:
|
||||
* **Project** (base project module)
|
||||
* **Document Page Project** (links wiki pages to projects)
|
||||
|
||||
The system will automatically install the necessary dependencies during installation.
|
||||
|
||||
## Permissions
|
||||
|
||||
The module uses the same access permissions as the base modules:
|
||||
* Users with access to **Projects** can view and create wiki pages linked to tasks
|
||||
* Users with access to **Documents/Knowledge** can manage wiki page content
|
||||
|
||||
No additional permission configuration is required.
|
||||
2
document_page_project_task/readme/CONTRIBUTORS.md
Normal file
2
document_page_project_task/readme/CONTRIBUTORS.md
Normal file
@@ -0,0 +1,2 @@
|
||||
- [ESCODOO](https://escodoo.com.br):
|
||||
- Marcel Savegnago \<<marcel.savegnago@escodoo.com.br>\>
|
||||
22
document_page_project_task/readme/DESCRIPTION.md
Normal file
22
document_page_project_task/readme/DESCRIPTION.md
Normal file
@@ -0,0 +1,22 @@
|
||||
This module extends the document page (wiki) functionality by allowing you to link them directly to project tasks.
|
||||
|
||||
## Main Features
|
||||
|
||||
* **Link Wiki Pages to Tasks**: Allows associating document pages to specific project tasks
|
||||
* **Automatic Project Filling**: When a task is selected, the related project is automatically filled
|
||||
* **Consistency Validation**: Ensures that the wiki page's project is always the same as the linked task's project
|
||||
* **Smart Filtering**: When a project is defined, only tasks from that project are displayed for selection
|
||||
* **Page Counter**: Displays the number of wiki pages linked to each task directly in the task view
|
||||
|
||||
## Benefits
|
||||
|
||||
* Organize project documentation hierarchically (Project → Task → Wiki)
|
||||
* Keep documentation close to the work context (tasks)
|
||||
* Avoid inconsistencies between projects and tasks through automatic validations
|
||||
* Quickly access documentation related to a specific task
|
||||
|
||||
## Dependencies
|
||||
|
||||
This module requires:
|
||||
* `document_page_project`: Module that links document pages to projects
|
||||
* `project`: Odoo's project management module
|
||||
87
document_page_project_task/readme/USAGE.md
Normal file
87
document_page_project_task/readme/USAGE.md
Normal file
@@ -0,0 +1,87 @@
|
||||
This guide explains how to use the Document Page Project Task module to link wiki pages to project tasks.
|
||||
|
||||
## Create a Wiki Page from a Task
|
||||
|
||||
**Method 1: From the Task**
|
||||
|
||||
1. Go to the **Projects** module
|
||||
2. Open the desired project
|
||||
3. Select a task
|
||||
4. In the task view, locate the **Wiki Pages** button (book icon)
|
||||
5. Click the button to see linked pages or create a new one
|
||||
6. Click **Create** to add a new wiki page
|
||||
7. The task and project will be automatically filled
|
||||
|
||||
**Method 2: From the Wiki Page**
|
||||
|
||||
1. Go to the **Knowledge** or **Documents** module
|
||||
2. Create a new wiki page or edit an existing one
|
||||
3. In the page form, you will see the fields:
|
||||
* **Project**: Select the project
|
||||
* **Task**: Select the task (only tasks from the selected project will be displayed)
|
||||
4. When you select a task, the project will be automatically filled
|
||||
5. Save the page
|
||||
|
||||
## Automatic Behaviors
|
||||
|
||||
**Automatic Project Filling**
|
||||
|
||||
When you select a task:
|
||||
* The **Project** field is automatically filled with the task's project
|
||||
* This ensures consistency between task and project
|
||||
|
||||
**Task Filtering**
|
||||
|
||||
When a project is selected:
|
||||
* Only tasks from that project appear in the selection list
|
||||
* This prevents selecting tasks from different projects
|
||||
|
||||
**Consistency Validation**
|
||||
|
||||
The system automatically validates that:
|
||||
* If a task is linked, the project must also be defined
|
||||
* The wiki page's project must be the same as the linked task's project
|
||||
* If you try to link a task to a different project, the system will prevent the operation
|
||||
|
||||
**Automatic Cleanup**
|
||||
|
||||
When you change the project:
|
||||
* If the linked task does not belong to the new project, it is automatically removed
|
||||
* This maintains data consistency
|
||||
|
||||
## View Wiki Pages of a Task
|
||||
|
||||
1. Access a project task
|
||||
2. At the top of the form, you will see the **Wiki Pages** button with a counter
|
||||
3. The displayed number indicates how many wiki pages are linked to the task
|
||||
4. Click the button to see all linked pages
|
||||
|
||||
## Usage Examples
|
||||
|
||||
**Example 1: Requirements Documentation**
|
||||
|
||||
1. Create a task "Define System Requirements"
|
||||
2. From the task, create a wiki page "Functional Requirements"
|
||||
3. Document the requirements in the wiki page
|
||||
4. The page will be linked to the task and project
|
||||
|
||||
**Example 2: Meeting Notes**
|
||||
|
||||
1. Create a task "Planning Meeting"
|
||||
2. Create a wiki page "Meeting Minutes"
|
||||
3. Document the discussed points
|
||||
4. The documentation will be organized and easy to find
|
||||
|
||||
**Example 3: Technical Specifications**
|
||||
|
||||
1. Create a task "Develop Module X"
|
||||
2. Create a wiki page "Technical Specification"
|
||||
3. Document the architecture and technical decisions
|
||||
4. Keep the documentation close to the task work
|
||||
|
||||
## Tips
|
||||
|
||||
* Use wiki pages to maintain contextual documentation related to specific tasks
|
||||
* The page counter on the task helps quickly identify tasks with documentation
|
||||
* When creating a page from the task, fields are automatically filled, saving time
|
||||
* Organize project documentation hierarchically: Project → Task → Wiki
|
||||
BIN
document_page_project_task/static/description/icon.png
Normal file
BIN
document_page_project_task/static/description/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.2 KiB |
600
document_page_project_task/static/description/index.html
Normal file
600
document_page_project_task/static/description/index.html
Normal file
@@ -0,0 +1,600 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="generator" content="Docutils: https://docutils.sourceforge.io/" />
|
||||
<title>Document Page Project Task</title>
|
||||
<style type="text/css">
|
||||
|
||||
/*
|
||||
:Author: David Goodger (goodger@python.org)
|
||||
:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $
|
||||
:Copyright: This stylesheet has been placed in the public domain.
|
||||
|
||||
Default cascading style sheet for the HTML output of Docutils.
|
||||
Despite the name, some widely supported CSS2 features are used.
|
||||
|
||||
See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to
|
||||
customize this style sheet.
|
||||
*/
|
||||
|
||||
/* used to remove borders from tables and images */
|
||||
.borderless, table.borderless td, table.borderless th {
|
||||
border: 0 }
|
||||
|
||||
table.borderless td, table.borderless th {
|
||||
/* Override padding for "table.docutils td" with "! important".
|
||||
The right padding separates the table cells. */
|
||||
padding: 0 0.5em 0 0 ! important }
|
||||
|
||||
.first {
|
||||
/* Override more specific margin styles with "! important". */
|
||||
margin-top: 0 ! important }
|
||||
|
||||
.last, .with-subtitle {
|
||||
margin-bottom: 0 ! important }
|
||||
|
||||
.hidden {
|
||||
display: none }
|
||||
|
||||
.subscript {
|
||||
vertical-align: sub;
|
||||
font-size: smaller }
|
||||
|
||||
.superscript {
|
||||
vertical-align: super;
|
||||
font-size: smaller }
|
||||
|
||||
a.toc-backref {
|
||||
text-decoration: none ;
|
||||
color: black }
|
||||
|
||||
blockquote.epigraph {
|
||||
margin: 2em 5em ; }
|
||||
|
||||
dl.docutils dd {
|
||||
margin-bottom: 0.5em }
|
||||
|
||||
object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Uncomment (and remove this text!) to get bold-faced definition list terms
|
||||
dl.docutils dt {
|
||||
font-weight: bold }
|
||||
*/
|
||||
|
||||
div.abstract {
|
||||
margin: 2em 5em }
|
||||
|
||||
div.abstract p.topic-title {
|
||||
font-weight: bold ;
|
||||
text-align: center }
|
||||
|
||||
div.admonition, div.attention, div.caution, div.danger, div.error,
|
||||
div.hint, div.important, div.note, div.tip, div.warning {
|
||||
margin: 2em ;
|
||||
border: medium outset ;
|
||||
padding: 1em }
|
||||
|
||||
div.admonition p.admonition-title, div.hint p.admonition-title,
|
||||
div.important p.admonition-title, div.note p.admonition-title,
|
||||
div.tip p.admonition-title {
|
||||
font-weight: bold ;
|
||||
font-family: sans-serif }
|
||||
|
||||
div.attention p.admonition-title, div.caution p.admonition-title,
|
||||
div.danger p.admonition-title, div.error p.admonition-title,
|
||||
div.warning p.admonition-title, .code .error {
|
||||
color: red ;
|
||||
font-weight: bold ;
|
||||
font-family: sans-serif }
|
||||
|
||||
/* Uncomment (and remove this text!) to get reduced vertical space in
|
||||
compound paragraphs.
|
||||
div.compound .compound-first, div.compound .compound-middle {
|
||||
margin-bottom: 0.5em }
|
||||
|
||||
div.compound .compound-last, div.compound .compound-middle {
|
||||
margin-top: 0.5em }
|
||||
*/
|
||||
|
||||
div.dedication {
|
||||
margin: 2em 5em ;
|
||||
text-align: center ;
|
||||
font-style: italic }
|
||||
|
||||
div.dedication p.topic-title {
|
||||
font-weight: bold ;
|
||||
font-style: normal }
|
||||
|
||||
div.figure {
|
||||
margin-left: 2em ;
|
||||
margin-right: 2em }
|
||||
|
||||
div.footer, div.header {
|
||||
clear: both;
|
||||
font-size: smaller }
|
||||
|
||||
div.line-block {
|
||||
display: block ;
|
||||
margin-top: 1em ;
|
||||
margin-bottom: 1em }
|
||||
|
||||
div.line-block div.line-block {
|
||||
margin-top: 0 ;
|
||||
margin-bottom: 0 ;
|
||||
margin-left: 1.5em }
|
||||
|
||||
div.sidebar {
|
||||
margin: 0 0 0.5em 1em ;
|
||||
border: medium outset ;
|
||||
padding: 1em ;
|
||||
background-color: #ffffee ;
|
||||
width: 40% ;
|
||||
float: right ;
|
||||
clear: right }
|
||||
|
||||
div.sidebar p.rubric {
|
||||
font-family: sans-serif ;
|
||||
font-size: medium }
|
||||
|
||||
div.system-messages {
|
||||
margin: 5em }
|
||||
|
||||
div.system-messages h1 {
|
||||
color: red }
|
||||
|
||||
div.system-message {
|
||||
border: medium outset ;
|
||||
padding: 1em }
|
||||
|
||||
div.system-message p.system-message-title {
|
||||
color: red ;
|
||||
font-weight: bold }
|
||||
|
||||
div.topic {
|
||||
margin: 2em }
|
||||
|
||||
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
|
||||
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
|
||||
margin-top: 0.4em }
|
||||
|
||||
h1.title {
|
||||
text-align: center }
|
||||
|
||||
h2.subtitle {
|
||||
text-align: center }
|
||||
|
||||
hr.docutils {
|
||||
width: 75% }
|
||||
|
||||
img.align-left, .figure.align-left, object.align-left, table.align-left {
|
||||
clear: left ;
|
||||
float: left ;
|
||||
margin-right: 1em }
|
||||
|
||||
img.align-right, .figure.align-right, object.align-right, table.align-right {
|
||||
clear: right ;
|
||||
float: right ;
|
||||
margin-left: 1em }
|
||||
|
||||
img.align-center, .figure.align-center, object.align-center {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
table.align-center {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.align-left {
|
||||
text-align: left }
|
||||
|
||||
.align-center {
|
||||
clear: both ;
|
||||
text-align: center }
|
||||
|
||||
.align-right {
|
||||
text-align: right }
|
||||
|
||||
/* reset inner alignment in figures */
|
||||
div.align-right {
|
||||
text-align: inherit }
|
||||
|
||||
/* div.align-center * { */
|
||||
/* text-align: left } */
|
||||
|
||||
.align-top {
|
||||
vertical-align: top }
|
||||
|
||||
.align-middle {
|
||||
vertical-align: middle }
|
||||
|
||||
.align-bottom {
|
||||
vertical-align: bottom }
|
||||
|
||||
ol.simple, ul.simple {
|
||||
margin-bottom: 1em }
|
||||
|
||||
ol.arabic {
|
||||
list-style: decimal }
|
||||
|
||||
ol.loweralpha {
|
||||
list-style: lower-alpha }
|
||||
|
||||
ol.upperalpha {
|
||||
list-style: upper-alpha }
|
||||
|
||||
ol.lowerroman {
|
||||
list-style: lower-roman }
|
||||
|
||||
ol.upperroman {
|
||||
list-style: upper-roman }
|
||||
|
||||
p.attribution {
|
||||
text-align: right ;
|
||||
margin-left: 50% }
|
||||
|
||||
p.caption {
|
||||
font-style: italic }
|
||||
|
||||
p.credits {
|
||||
font-style: italic ;
|
||||
font-size: smaller }
|
||||
|
||||
p.label {
|
||||
white-space: nowrap }
|
||||
|
||||
p.rubric {
|
||||
font-weight: bold ;
|
||||
font-size: larger ;
|
||||
color: maroon ;
|
||||
text-align: center }
|
||||
|
||||
p.sidebar-title {
|
||||
font-family: sans-serif ;
|
||||
font-weight: bold ;
|
||||
font-size: larger }
|
||||
|
||||
p.sidebar-subtitle {
|
||||
font-family: sans-serif ;
|
||||
font-weight: bold }
|
||||
|
||||
p.topic-title {
|
||||
font-weight: bold }
|
||||
|
||||
pre.address {
|
||||
margin-bottom: 0 ;
|
||||
margin-top: 0 ;
|
||||
font: inherit }
|
||||
|
||||
pre.literal-block, pre.doctest-block, pre.math, pre.code {
|
||||
margin-left: 2em ;
|
||||
margin-right: 2em }
|
||||
|
||||
pre.code .ln { color: gray; } /* line numbers */
|
||||
pre.code, code { background-color: #eeeeee }
|
||||
pre.code .comment, code .comment { color: #5C6576 }
|
||||
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
|
||||
pre.code .literal.string, code .literal.string { color: #0C5404 }
|
||||
pre.code .name.builtin, code .name.builtin { color: #352B84 }
|
||||
pre.code .deleted, code .deleted { background-color: #DEB0A1}
|
||||
pre.code .inserted, code .inserted { background-color: #A3D289}
|
||||
|
||||
span.classifier {
|
||||
font-family: sans-serif ;
|
||||
font-style: oblique }
|
||||
|
||||
span.classifier-delimiter {
|
||||
font-family: sans-serif ;
|
||||
font-weight: bold }
|
||||
|
||||
span.interpreted {
|
||||
font-family: sans-serif }
|
||||
|
||||
span.option {
|
||||
white-space: nowrap }
|
||||
|
||||
span.pre {
|
||||
white-space: pre }
|
||||
|
||||
span.problematic, pre.problematic {
|
||||
color: red }
|
||||
|
||||
span.section-subtitle {
|
||||
/* font-size relative to parent (h1..h6 element) */
|
||||
font-size: 80% }
|
||||
|
||||
table.citation {
|
||||
border-left: solid 1px gray;
|
||||
margin-left: 1px }
|
||||
|
||||
table.docinfo {
|
||||
margin: 2em 4em }
|
||||
|
||||
table.docutils {
|
||||
margin-top: 0.5em ;
|
||||
margin-bottom: 0.5em }
|
||||
|
||||
table.footnote {
|
||||
border-left: solid 1px black;
|
||||
margin-left: 1px }
|
||||
|
||||
table.docutils td, table.docutils th,
|
||||
table.docinfo td, table.docinfo th {
|
||||
padding-left: 0.5em ;
|
||||
padding-right: 0.5em ;
|
||||
vertical-align: top }
|
||||
|
||||
table.docutils th.field-name, table.docinfo th.docinfo-name {
|
||||
font-weight: bold ;
|
||||
text-align: left ;
|
||||
white-space: nowrap ;
|
||||
padding-left: 0 }
|
||||
|
||||
/* "booktabs" style (no vertical lines) */
|
||||
table.docutils.booktabs {
|
||||
border: 0px;
|
||||
border-top: 2px solid;
|
||||
border-bottom: 2px solid;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
table.docutils.booktabs * {
|
||||
border: 0px;
|
||||
}
|
||||
table.docutils.booktabs th {
|
||||
border-bottom: thin solid;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
|
||||
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
|
||||
font-size: 100% }
|
||||
|
||||
ul.auto-toc {
|
||||
list-style-type: none }
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="document" id="document-page-project-task">
|
||||
<h1 class="title">Document Page Project Task</h1>
|
||||
|
||||
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
!! This file is generated by oca-gen-addon-readme !!
|
||||
!! changes will be overwritten. !!
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
!! source digest: sha256:792f27beb9e30e02336420e9ffafb95a1a3027dc4b2ff368b4d350c683de3b01
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
|
||||
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/knowledge/tree/16.0/document_page_project_task"><img alt="OCA/knowledge" src="https://img.shields.io/badge/github-OCA%2Fknowledge-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/knowledge-16-0/knowledge-16-0-document_page_project_task"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/knowledge&target_branch=16.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
|
||||
<p>This module extends the document page (wiki) functionality by allowing
|
||||
you to link them directly to project tasks.</p>
|
||||
<div class="section" id="main-features">
|
||||
<h1>Main Features</h1>
|
||||
<ul class="simple">
|
||||
<li><strong>Link Wiki Pages to Tasks</strong>: Allows associating document pages to
|
||||
specific project tasks</li>
|
||||
<li><strong>Automatic Project Filling</strong>: When a task is selected, the related
|
||||
project is automatically filled</li>
|
||||
<li><strong>Consistency Validation</strong>: Ensures that the wiki page’s project is
|
||||
always the same as the linked task’s project</li>
|
||||
<li><strong>Smart Filtering</strong>: When a project is defined, only tasks from that
|
||||
project are displayed for selection</li>
|
||||
<li><strong>Page Counter</strong>: Displays the number of wiki pages linked to each
|
||||
task directly in the task view</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="benefits">
|
||||
<h1>Benefits</h1>
|
||||
<ul class="simple">
|
||||
<li>Organize project documentation hierarchically (Project → Task → Wiki)</li>
|
||||
<li>Keep documentation close to the work context (tasks)</li>
|
||||
<li>Avoid inconsistencies between projects and tasks through automatic
|
||||
validations</li>
|
||||
<li>Quickly access documentation related to a specific task</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="dependencies">
|
||||
<h1>Dependencies</h1>
|
||||
<p>This module requires:</p>
|
||||
<ul class="simple">
|
||||
<li><tt class="docutils literal">document_page_project</tt>: Module that links document pages to
|
||||
projects</li>
|
||||
<li><tt class="docutils literal">project</tt>: Odoo’s project management module</li>
|
||||
</ul>
|
||||
<p><strong>Table of contents</strong></p>
|
||||
<div class="contents local topic" id="contents">
|
||||
<ul class="simple">
|
||||
<li><a class="reference internal" href="#configuration" id="toc-entry-1">Configuration</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="configuration">
|
||||
<h2><a class="toc-backref" href="#toc-entry-1">Configuration</a></h2>
|
||||
<p>This module does not require additional configuration after
|
||||
installation. It works automatically once installed.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="installation">
|
||||
<h1>Installation</h1>
|
||||
<ol class="arabic simple">
|
||||
<li>Go to the <strong>Apps</strong> menu</li>
|
||||
<li>Remove the “Apps” filter if necessary</li>
|
||||
<li>Search for “Document Page Project Task”</li>
|
||||
<li>Click <strong>Install</strong></li>
|
||||
</ol>
|
||||
</div>
|
||||
<div class="section" id="prerequisites">
|
||||
<h1>Prerequisites</h1>
|
||||
<p>Make sure the following modules are installed:</p>
|
||||
<ul class="simple">
|
||||
<li><strong>Project</strong> (base project module)</li>
|
||||
<li><strong>Document Page Project</strong> (links wiki pages to projects)</li>
|
||||
</ul>
|
||||
<p>The system will automatically install the necessary dependencies during
|
||||
installation.</p>
|
||||
</div>
|
||||
<div class="section" id="permissions">
|
||||
<h1>Permissions</h1>
|
||||
<p>The module uses the same access permissions as the base modules:</p>
|
||||
<ul class="simple">
|
||||
<li>Users with access to <strong>Projects</strong> can view and create wiki pages
|
||||
linked to tasks</li>
|
||||
<li>Users with access to <strong>Documents/Knowledge</strong> can manage wiki page
|
||||
content</li>
|
||||
</ul>
|
||||
<p>No additional permission configuration is required.</p>
|
||||
<div class="section" id="usage">
|
||||
<h2>Usage</h2>
|
||||
<p>This guide explains how to use the Document Page Project Task module to
|
||||
link wiki pages to project tasks.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="create-a-wiki-page-from-a-task">
|
||||
<h1>Create a Wiki Page from a Task</h1>
|
||||
<p><strong>Method 1: From the Task</strong></p>
|
||||
<ol class="arabic simple">
|
||||
<li>Go to the <strong>Projects</strong> module</li>
|
||||
<li>Open the desired project</li>
|
||||
<li>Select a task</li>
|
||||
<li>In the task view, locate the <strong>Wiki Pages</strong> button (book icon)</li>
|
||||
<li>Click the button to see linked pages or create a new one</li>
|
||||
<li>Click <strong>Create</strong> to add a new wiki page</li>
|
||||
<li>The task and project will be automatically filled</li>
|
||||
</ol>
|
||||
<p><strong>Method 2: From the Wiki Page</strong></p>
|
||||
<ol class="arabic simple">
|
||||
<li>Go to the <strong>Knowledge</strong> or <strong>Documents</strong> module</li>
|
||||
<li>Create a new wiki page or edit an existing one</li>
|
||||
<li>In the page form, you will see the fields:<ul>
|
||||
<li><strong>Project</strong>: Select the project</li>
|
||||
<li><strong>Task</strong>: Select the task (only tasks from the selected project
|
||||
will be displayed)</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>When you select a task, the project will be automatically filled</li>
|
||||
<li>Save the page</li>
|
||||
</ol>
|
||||
</div>
|
||||
<div class="section" id="automatic-behaviors">
|
||||
<h1>Automatic Behaviors</h1>
|
||||
<p><strong>Automatic Project Filling</strong></p>
|
||||
<p>When you select a task:</p>
|
||||
<ul class="simple">
|
||||
<li>The <strong>Project</strong> field is automatically filled with the task’s project</li>
|
||||
<li>This ensures consistency between task and project</li>
|
||||
</ul>
|
||||
<p><strong>Task Filtering</strong></p>
|
||||
<p>When a project is selected:</p>
|
||||
<ul class="simple">
|
||||
<li>Only tasks from that project appear in the selection list</li>
|
||||
<li>This prevents selecting tasks from different projects</li>
|
||||
</ul>
|
||||
<p><strong>Consistency Validation</strong></p>
|
||||
<p>The system automatically validates that:</p>
|
||||
<ul class="simple">
|
||||
<li>If a task is linked, the project must also be defined</li>
|
||||
<li>The wiki page’s project must be the same as the linked task’s project</li>
|
||||
<li>If you try to link a task to a different project, the system will
|
||||
prevent the operation</li>
|
||||
</ul>
|
||||
<p><strong>Automatic Cleanup</strong></p>
|
||||
<p>When you change the project:</p>
|
||||
<ul class="simple">
|
||||
<li>If the linked task does not belong to the new project, it is
|
||||
automatically removed</li>
|
||||
<li>This maintains data consistency</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="view-wiki-pages-of-a-task">
|
||||
<h1>View Wiki Pages of a Task</h1>
|
||||
<ol class="arabic simple">
|
||||
<li>Access a project task</li>
|
||||
<li>At the top of the form, you will see the <strong>Wiki Pages</strong> button with a
|
||||
counter</li>
|
||||
<li>The displayed number indicates how many wiki pages are linked to the
|
||||
task</li>
|
||||
<li>Click the button to see all linked pages</li>
|
||||
</ol>
|
||||
</div>
|
||||
<div class="section" id="usage-examples">
|
||||
<h1>Usage Examples</h1>
|
||||
<p><strong>Example 1: Requirements Documentation</strong></p>
|
||||
<ol class="arabic simple">
|
||||
<li>Create a task “Define System Requirements”</li>
|
||||
<li>From the task, create a wiki page “Functional Requirements”</li>
|
||||
<li>Document the requirements in the wiki page</li>
|
||||
<li>The page will be linked to the task and project</li>
|
||||
</ol>
|
||||
<p><strong>Example 2: Meeting Notes</strong></p>
|
||||
<ol class="arabic simple">
|
||||
<li>Create a task “Planning Meeting”</li>
|
||||
<li>Create a wiki page “Meeting Minutes”</li>
|
||||
<li>Document the discussed points</li>
|
||||
<li>The documentation will be organized and easy to find</li>
|
||||
</ol>
|
||||
<p><strong>Example 3: Technical Specifications</strong></p>
|
||||
<ol class="arabic simple">
|
||||
<li>Create a task “Develop Module X”</li>
|
||||
<li>Create a wiki page “Technical Specification”</li>
|
||||
<li>Document the architecture and technical decisions</li>
|
||||
<li>Keep the documentation close to the task work</li>
|
||||
</ol>
|
||||
</div>
|
||||
<div class="section" id="tips">
|
||||
<h1>Tips</h1>
|
||||
<ul class="simple">
|
||||
<li>Use wiki pages to maintain contextual documentation related to
|
||||
specific tasks</li>
|
||||
<li>The page counter on the task helps quickly identify tasks with
|
||||
documentation</li>
|
||||
<li>When creating a page from the task, fields are automatically filled,
|
||||
saving time</li>
|
||||
<li>Organize project documentation hierarchically: Project → Task → Wiki</li>
|
||||
</ul>
|
||||
<div class="section" id="bug-tracker">
|
||||
<h2>Bug Tracker</h2>
|
||||
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/knowledge/issues">GitHub Issues</a>.
|
||||
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
|
||||
<a class="reference external" href="https://github.com/OCA/knowledge/issues/new?body=module:%20document_page_project_task%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
|
||||
<p>Do not contact contributors directly about support or help with technical issues.</p>
|
||||
</div>
|
||||
<div class="section" id="credits">
|
||||
<h2>Credits</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="authors">
|
||||
<h1>Authors</h1>
|
||||
<ul class="simple">
|
||||
<li>Escodoo</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="contributors">
|
||||
<h1>Contributors</h1>
|
||||
<ul class="simple">
|
||||
<li><a class="reference external" href="https://escodoo.com.br">ESCODOO</a>:<ul>
|
||||
<li>Marcel Savegnago <<a class="reference external" href="mailto:marcel.savegnago@escodoo.com.br">marcel.savegnago@escodoo.com.br</a>></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="maintainers">
|
||||
<h1>Maintainers</h1>
|
||||
<p>This module is maintained by the OCA.</p>
|
||||
<a class="reference external image-reference" href="https://odoo-community.org">
|
||||
<img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" />
|
||||
</a>
|
||||
<p>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.</p>
|
||||
<p>Current <a class="reference external" href="https://odoo-community.org/page/maintainer-role">maintainer</a>:</p>
|
||||
<p><a class="reference external image-reference" href="https://github.com/marcelsavegnago"><img alt="marcelsavegnago" src="https://github.com/marcelsavegnago.png?size=40px" /></a></p>
|
||||
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/knowledge/tree/16.0/document_page_project_task">OCA/knowledge</a> project on GitHub.</p>
|
||||
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
2
document_page_project_task/tests/__init__.py
Normal file
2
document_page_project_task/tests/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
from . import test_project_task
|
||||
from . import test_document_page
|
||||
192
document_page_project_task/tests/test_document_page.py
Normal file
192
document_page_project_task/tests/test_document_page.py
Normal file
@@ -0,0 +1,192 @@
|
||||
# Copyright 2025 Marcel Savegnago - Escodoo <https://escodoo.com.br>
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo.exceptions import ValidationError
|
||||
from odoo.tests import common
|
||||
|
||||
|
||||
class TestDocumentPage(common.TransactionCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
|
||||
cls.Page = cls.env["document.page"]
|
||||
cls.Project = cls.env["project.project"]
|
||||
cls.Task = cls.env["project.task"]
|
||||
|
||||
cls.project1 = cls.Project.create({"name": "Project 1"})
|
||||
cls.project2 = cls.Project.create({"name": "Project 2"})
|
||||
cls.task1 = cls.Task.create({"name": "Task 1", "project_id": cls.project1.id})
|
||||
cls.task2 = cls.Task.create({"name": "Task 2", "project_id": cls.project2.id})
|
||||
|
||||
def test_onchange_task_id_fills_project(self):
|
||||
"""Test that when selecting a task, the project is automatically
|
||||
filled."""
|
||||
page = self.Page.new({"name": "Test Page"})
|
||||
page.task_id = self.task1
|
||||
page._onchange_task_id()
|
||||
|
||||
self.assertEqual(
|
||||
page.project_id,
|
||||
self.project1,
|
||||
"The project should be automatically filled with the task's project",
|
||||
)
|
||||
|
||||
def test_onchange_project_id_clears_task(self):
|
||||
"""Test that when changing the project to a different one, the task
|
||||
is cleared."""
|
||||
page = self.Page.new(
|
||||
{
|
||||
"name": "Test Page",
|
||||
"task_id": self.task1.id,
|
||||
"project_id": self.project1.id,
|
||||
}
|
||||
)
|
||||
page.project_id = self.project2
|
||||
page._onchange_project_id()
|
||||
|
||||
self.assertFalse(
|
||||
page.task_id,
|
||||
"The task should be cleared when the project changes to a different one",
|
||||
)
|
||||
|
||||
def test_onchange_project_id_clears_task_when_removed(self):
|
||||
"""Test that when removing the project, the task is cleared."""
|
||||
page = self.Page.new(
|
||||
{
|
||||
"name": "Test Page",
|
||||
"task_id": self.task1.id,
|
||||
"project_id": self.project1.id,
|
||||
}
|
||||
)
|
||||
page.project_id = False
|
||||
page._onchange_project_id()
|
||||
|
||||
self.assertFalse(
|
||||
page.task_id,
|
||||
"The task should be cleared when the project is removed",
|
||||
)
|
||||
|
||||
def test_default_get_with_task_in_context(self):
|
||||
"""Test that default_get fills the project when there is default_task_id
|
||||
in the context."""
|
||||
context = {"default_task_id": self.task1.id}
|
||||
fields_list = ["name", "project_id", "task_id"]
|
||||
defaults = self.Page.with_context(**context).default_get(fields_list)
|
||||
|
||||
self.assertEqual(
|
||||
defaults.get("project_id"),
|
||||
self.project1.id,
|
||||
"The project_id should be filled with the task's project in context",
|
||||
)
|
||||
self.assertEqual(
|
||||
defaults.get("task_id"),
|
||||
self.task1.id,
|
||||
"The task_id should be filled with the task from context",
|
||||
)
|
||||
|
||||
def test_constraint_task_project_consistency_valid(self):
|
||||
"""Test that the constraint allows task and project from the same
|
||||
project."""
|
||||
page = self.Page.create(
|
||||
{
|
||||
"name": "Test Page",
|
||||
"task_id": self.task1.id,
|
||||
"project_id": self.project1.id,
|
||||
}
|
||||
)
|
||||
|
||||
# Should not raise an exception
|
||||
self.assertTrue(page.exists())
|
||||
|
||||
def test_constraint_task_project_consistency_invalid(self):
|
||||
"""Test that the constraint prevents task and project from different
|
||||
projects."""
|
||||
page = self.Page.create(
|
||||
{
|
||||
"name": "Test Page",
|
||||
"task_id": self.task1.id,
|
||||
"project_id": self.project1.id,
|
||||
}
|
||||
)
|
||||
|
||||
# Trying to change the project to a different one should raise
|
||||
# ValidationError
|
||||
with self.assertRaises(ValidationError):
|
||||
page.project_id = self.project2
|
||||
|
||||
def test_constraint_task_project_consistency_no_task(self):
|
||||
"""Test that the constraint does not prevent when there is no task."""
|
||||
page = self.Page.create({"name": "Test Page", "project_id": self.project1.id})
|
||||
|
||||
# Should not raise an exception when there is no task
|
||||
self.assertTrue(page.exists())
|
||||
|
||||
def test_constraint_task_project_consistency_no_project(self):
|
||||
"""Test that the constraint prevents when there is a task but no
|
||||
project."""
|
||||
# Trying to create a page with a task but without a project should
|
||||
# raise ValidationError
|
||||
with self.assertRaises(ValidationError):
|
||||
self.Page.create({"name": "Test Page", "task_id": self.task1.id})
|
||||
|
||||
def test_constraint_task_requires_project(self):
|
||||
"""Test that when removing the project when there is a task, it should
|
||||
raise an error."""
|
||||
page = self.Page.create(
|
||||
{
|
||||
"name": "Test Page",
|
||||
"task_id": self.task1.id,
|
||||
"project_id": self.project1.id,
|
||||
}
|
||||
)
|
||||
|
||||
# Trying to remove the project when there is a task should raise
|
||||
# ValidationError
|
||||
with self.assertRaises(ValidationError):
|
||||
page.project_id = False
|
||||
|
||||
def test_create_page_with_task_sets_project(self):
|
||||
"""Test that when creating a page with a task, the project is set
|
||||
automatically."""
|
||||
# Create page with task_id and project_id defined together
|
||||
# (the onchange fills the project_id when task_id is defined in the
|
||||
# form)
|
||||
page = self.Page.create(
|
||||
{
|
||||
"name": "Test Page",
|
||||
"task_id": self.task1.id,
|
||||
"project_id": self.project1.id,
|
||||
}
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
page.project_id,
|
||||
self.project1,
|
||||
"The project should be the same as the task",
|
||||
)
|
||||
self.assertEqual(
|
||||
page.task_id,
|
||||
self.task1,
|
||||
"The task should be correctly associated",
|
||||
)
|
||||
|
||||
def test_write_task_changes_project(self):
|
||||
"""Test that when changing the task, the project should be updated."""
|
||||
page = self.Page.create(
|
||||
{
|
||||
"name": "Test Page",
|
||||
"task_id": self.task1.id,
|
||||
"project_id": self.project1.id,
|
||||
}
|
||||
)
|
||||
|
||||
# Change the task - the project should be updated to match
|
||||
page.write({"task_id": self.task2.id, "project_id": self.task2.project_id.id})
|
||||
|
||||
page.invalidate_recordset()
|
||||
self.assertEqual(
|
||||
page.project_id,
|
||||
self.project2,
|
||||
"The project should match the new task's project",
|
||||
)
|
||||
70
document_page_project_task/tests/test_project_task.py
Normal file
70
document_page_project_task/tests/test_project_task.py
Normal file
@@ -0,0 +1,70 @@
|
||||
# Copyright 2025 Marcel Savegnago - Escodoo <https://escodoo.com.br>
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo.tests import common
|
||||
|
||||
|
||||
class TestProjectTask(common.TransactionCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
|
||||
cls.Page = cls.env["document.page"]
|
||||
cls.Project = cls.env["project.project"]
|
||||
cls.Task = cls.env["project.task"]
|
||||
|
||||
cls.project = cls.Project.create({"name": "Test Project"})
|
||||
cls.task = cls.Task.create({"name": "Test Task", "project_id": cls.project.id})
|
||||
cls.default_page = cls.Page.create({"name": "My page"})
|
||||
|
||||
def test_page_count(self):
|
||||
"""Test the page counter on the task."""
|
||||
self.assertEqual(
|
||||
self.task.document_page_count,
|
||||
0,
|
||||
"Initial page count should be zero",
|
||||
)
|
||||
|
||||
# Set task_id and project_id together (the onchange fills project_id)
|
||||
self.default_page.write(
|
||||
{"task_id": self.task.id, "project_id": self.task.project_id.id}
|
||||
)
|
||||
self.task._compute_document_page_count()
|
||||
|
||||
self.assertEqual(
|
||||
self.task.document_page_count,
|
||||
1,
|
||||
"After associating task to document, the count should be one",
|
||||
)
|
||||
self.assertIn(
|
||||
self.default_page,
|
||||
self.task.document_page_ids,
|
||||
"The page should be in the list of document pages for the task",
|
||||
)
|
||||
|
||||
def test_page_count_multiple_pages(self):
|
||||
"""Test the counter with multiple pages."""
|
||||
page2 = self.Page.create(
|
||||
{
|
||||
"name": "Second page",
|
||||
"task_id": self.task.id,
|
||||
"project_id": self.task.project_id.id,
|
||||
}
|
||||
)
|
||||
page3 = self.Page.create(
|
||||
{
|
||||
"name": "Third page",
|
||||
"task_id": self.task.id,
|
||||
"project_id": self.task.project_id.id,
|
||||
}
|
||||
)
|
||||
|
||||
self.task._compute_document_page_count()
|
||||
|
||||
self.assertEqual(
|
||||
self.task.document_page_count,
|
||||
2,
|
||||
"Count should be two with two pages associated",
|
||||
)
|
||||
self.assertIn(page2, self.task.document_page_ids)
|
||||
self.assertIn(page3, self.task.document_page_ids)
|
||||
36
document_page_project_task/views/document_page_views.xml
Normal file
36
document_page_project_task/views/document_page_views.xml
Normal file
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" ?>
|
||||
<odoo>
|
||||
<record id="view_wiki_form_task" model="ir.ui.view">
|
||||
<field name="name">document.page.form - document_page_project_task</field>
|
||||
<field name="model">document.page</field>
|
||||
<field name="inherit_id" ref="document_page.view_wiki_form" />
|
||||
<field name="arch" type="xml">
|
||||
<field name="project_id" position="after">
|
||||
<field name="task_id" domain="[('project_id', '=', project_id)]" />
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
<record id="action_document_page_tasks" model="ir.actions.act_window">
|
||||
<field name="name">Task Wiki</field>
|
||||
<field name="res_model">document.page</field>
|
||||
<field
|
||||
name="domain"
|
||||
>[('type','=','content'), ('task_id', '=', active_id)]</field>
|
||||
<field name="context">{
|
||||
'default_type': 'content',
|
||||
'default_task_id': active_id}</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field
|
||||
name="view_ids"
|
||||
eval="[(5,0,0),
|
||||
(0,0,{'view_mode':'tree', 'view_id': ref('document_page.view_wiki_tree')}),
|
||||
(0,0,{'view_mode':'form', 'view_id': ref('document_page.view_wiki_form')})]"
|
||||
/>
|
||||
<field name="search_view_id" ref="document_page.view_wiki_filter" />
|
||||
<field name="help" type="html">
|
||||
<p class="oe_view_nocontent_create">
|
||||
Click to create a new web page.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
24
document_page_project_task/views/project_task_views.xml
Normal file
24
document_page_project_task/views/project_task_views.xml
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<record id="view_task_form2" model="ir.ui.view">
|
||||
<field name="name">project.task.form - document_page_project_task</field>
|
||||
<field name="model">project.task</field>
|
||||
<field name="inherit_id" ref="project.view_task_form2" />
|
||||
<field name="arch" type="xml">
|
||||
<div name="button_box" position="inside">
|
||||
<button
|
||||
class="oe_stat_button"
|
||||
type="action"
|
||||
name="%(action_document_page_tasks)d"
|
||||
icon="fa-book"
|
||||
>
|
||||
<field
|
||||
string="Wiki Pages"
|
||||
name="document_page_count"
|
||||
widget="statinfo"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -0,0 +1 @@
|
||||
../../../../document_page_project_task
|
||||
6
setup/document_page_project_task/setup.py
Normal file
6
setup/document_page_project_task/setup.py
Normal file
@@ -0,0 +1,6 @@
|
||||
import setuptools
|
||||
|
||||
setuptools.setup(
|
||||
setup_requires=['setuptools-odoo'],
|
||||
odoo_addon=True,
|
||||
)
|
||||
Reference in New Issue
Block a user