changeset dca2bc7ae397 in modules/project:default
details: https://hg.tryton.org/modules/project?cmd=changeset;node=dca2bc7ae397
description:
        Make project status configurable

        issue7746
        review64411002
diffstat:

 CHANGELOG                         |    2 +
 __init__.py                       |    4 +
 doc/index.rst                     |   26 +++--
 exceptions.py                     |    4 +
 ir.py                             |   15 +++
 message.xml                       |   14 ++-
 setup.py                          |    4 +-
 tests/scenario_project_status.rst |   85 +++++++++++++++++
 tests/test_project.py             |   12 ++-
 view/work_form.xml                |    8 +-
 view/work_list.xml                |    2 +-
 view/work_list_children.xml       |    2 +-
 view/work_list_simple.xml         |    2 +-
 view/work_status_form.xml         |   24 +++++
 view/work_status_list.xml         |    8 +
 view/work_tree.xml                |    2 +-
 view/work_tree_simple.xml         |    2 +-
 work.py                           |  180 ++++++++++++++++++++++++++++++++-----
 work.xml                          |   95 +++++++++++--------
 19 files changed, 400 insertions(+), 91 deletions(-)

diffs (749 lines):

diff -r 6fb9a7793bdf -r dca2bc7ae397 CHANGELOG
--- a/CHANGELOG Sat Dec 14 10:47:54 2019 +0100
+++ b/CHANGELOG Tue Jan 28 11:45:54 2020 +0100
@@ -1,3 +1,5 @@
+* Make project status configurable
+
 Version 5.4.0 - 2019-11-04
 * Bug fixes (see mercurial logs for details)
 
diff -r 6fb9a7793bdf -r dca2bc7ae397 __init__.py
--- a/__init__.py       Sat Dec 14 10:47:54 2019 +0100
+++ b/__init__.py       Tue Jan 28 11:45:54 2020 +0100
@@ -2,6 +2,7 @@
 # this repository contains the full copyright notices and license terms.
 
 from trytond.pool import Pool
+from . import ir
 from . import work
 from . import timesheet
 from . import party
@@ -9,9 +10,12 @@
 
 def register():
     Pool.register(
+        # Before Work because status default value is read from WorkStatus
+        work.WorkStatus,
         work.Work,
         timesheet.Line,
         timesheet.Work,
+        ir.ActWindow,
         module='project', type_='model')
     Pool.register(
         party.PartyReplace,
diff -r 6fb9a7793bdf -r dca2bc7ae397 doc/index.rst
--- a/doc/index.rst     Sat Dec 14 10:47:54 2019 +0100
+++ b/doc/index.rst     Tue Jan 28 11:45:54 2020 +0100
@@ -4,7 +4,6 @@
 The Project module provides the concepts of project and task and the
 basis for simple project management.
 
-
 Work Effort
 ***********
 
@@ -12,19 +11,24 @@
 for instance to transform a task into a project if it gets bigger and need to
 be split. The following fields are defined on the model:
 
-
 - Name: The name of the Project/Task.
 - Type: Can be *Project* or *Task*.
-- State: Can be *Opened* or *Done*.
-- Parent and Children: Define the tree structure of projects and
-  tasks.
-- Party and Party Address: The optional party (and the contact
-  address) for which the project is made. Available on projects.
-- Timesheet Available: Register the work for timesheets.
+- Status: The current status of the work.
+- Parent and Children: Define the tree structure of projects and tasks.
+- Party and Party Address: The optional party (and the contact address) for
+  which the project is made. Available on projects.
+- Timesheet, start and end: Allow to enter timesheet for this work.
 - Effort: The estimated effort of a task.
-- Total Effort: Available on projects. Gives the total effort of the
-  sub-tasks (I.E. tasks of the project and tasks of the sub-projects)
-  of the current project.
+- Total Effort: Available on projects. Gives the total effort of the sub-tasks
+  (I.E. tasks of the project and tasks of the sub-projects) of the current
+  project.
 - Progress: The progression on the task.
 - Total Progress: Gives the total of progress of the sub-tasks.
 - Comment: A description.
+
+
+Work Status
+***********
+
+The Work Status defines the possible status of projects and tasks. A minimal
+progress can be defined to enforce on works in this status.
diff -r 6fb9a7793bdf -r dca2bc7ae397 exceptions.py
--- a/exceptions.py     Sat Dec 14 10:47:54 2019 +0100
+++ b/exceptions.py     Tue Jan 28 11:45:54 2020 +0100
@@ -6,3 +6,7 @@
 
 class WorkValidationError(ValidationError):
     pass
+
+
+class WorkProgressValidationError(WorkValidationError):
+    pass
diff -r 6fb9a7793bdf -r dca2bc7ae397 ir.py
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/ir.py     Tue Jan 28 11:45:54 2020 +0100
@@ -0,0 +1,15 @@
+# This file is part of Tryton.  The COPYRIGHT file at the top level of
+# this repository contains the full copyright notices and license terms.
+from trytond.pool import Pool, PoolMeta
+
+
+class ActWindow(metaclass=PoolMeta):
+    __name__ = 'ir.action.act_window'
+
+    def get_domains(self, name):
+        domains = super().get_domains(name)
+        if self.res_model == 'project.work':
+            pool = Pool()
+            WorkStatus = pool.get('project.work.status')
+            domains = WorkStatus.get_window_domains(self)
+        return domains
diff -r 6fb9a7793bdf -r dca2bc7ae397 message.xml
--- a/message.xml       Sat Dec 14 10:47:54 2019 +0100
+++ b/message.xml       Tue Jan 28 11:45:54 2020 +0100
@@ -3,14 +3,20 @@
 this repository contains the full copyright notices and license terms. -->
 <tryton>
     <data grouped="1">
-        <record model="ir.message" id="msg_work_invalid_parent_state">
-            <field name="text">To open work "%(child)s", you must open its 
parent "%(parent)s".</field>
+        <record model="ir.message" id="msg_work_invalid_progress_status">
+            <field name="text">To set work "%(work)s" in "%(status)s" status, 
you must increase its progress up to at least %(progress)s.</field>
         </record>
-        <record model="ir.message" id="msg_work_invalid_children_state">
-            <field name="text">To close work "%(parent)s", you must close its 
child "%(child)s".</field>
+        <record model="ir.message" id="msg_work_children_progress">
+            <field name="text">To complete work "%(work)s" you must complete 
also all its children.</field>
+        </record>
+        <record model="ir.message" id="msg_work_parent_progress">
+            <field name="text">To re-open work "%(work)s" you must re-open 
also its parent "%(parent)s".</field>
         </record>
         <record model="ir.message" id="msg_erase_party_opened_project">
             <field name="text">You cannot erase party "%(party)s" while they 
have opened projects with company "%(company)s".</field>
         </record>
+        <record model="ir.message" id="msg_domain_all">
+            <field name="text">All</field>
+        </record>
     </data>
 </tryton>
diff -r 6fb9a7793bdf -r dca2bc7ae397 setup.py
--- a/setup.py  Sat Dec 14 10:47:54 2019 +0100
+++ b/setup.py  Tue Jan 28 11:45:54 2020 +0100
@@ -57,6 +57,7 @@
         requires.append(get_require_version('trytond_%s' % dep))
 requires.append(get_require_version('trytond'))
 
+tests_require = [get_require_version('proteus')]
 dependency_links = []
 if minor_version % 2:
     dependency_links.append('https://trydevpi.tryton.org/')
@@ -84,7 +85,7 @@
     package_data={
         'trytond.modules.project': (info.get('xml', [])
             + ['tryton.cfg', 'view/*.xml', 'locale/*.po', 'icons/*.svg',
-                '*.fodt']),
+                '*.fodt', 'tests/*.rst']),
         },
     classifiers=[
         'Development Status :: 5 - Production/Stable',
@@ -134,4 +135,5 @@
     """,
     test_suite='tests',
     test_loader='trytond.test_loader:Loader',
+    tests_require=tests_require,
     )
diff -r 6fb9a7793bdf -r dca2bc7ae397 tests/scenario_project_status.rst
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/scenario_project_status.rst Tue Jan 28 11:45:54 2020 +0100
@@ -0,0 +1,85 @@
+=======================
+Project Status Scenario
+=======================
+
+Imports::
+
+    >>> from proteus import Model
+    >>> from trytond.tests.tools import activate_modules
+    >>> from trytond.modules.company.tests.tools import create_company
+
+Activate project::
+
+    >>> config = activate_modules('project')
+
+Create a company::
+
+    >>> _ = create_company()
+
+Create status::
+
+    >>> WorkStatus = Model.get('project.work.status')
+    >>> in_progress = WorkStatus(name="In-Progress", types=['project'])
+    >>> in_progress.progress = 0.1
+    >>> in_progress.save()
+    >>> open, = WorkStatus.find([('name', '=', "Open")])
+    >>> done, = WorkStatus.find([('name', '=', "Done")])
+
+Create a project with a task::
+
+    >>> Work = Model.get('project.work')
+
+    >>> project = Work(type='project', name="Project")
+    >>> project.status == open
+    True
+    >>> task = project.children.new(name="Task")
+    >>> task.status == open
+    True
+
+    >>> project.save()
+    >>> task, = project.children
+
+Open the project::
+
+    >>> project.status = in_progress
+    >>> project.progress
+    0.1
+    >>> project.save()
+
+Try to complete project without task::
+
+    >>> project.status = done
+    >>> project.progress
+    1.0
+    >>> project.save()  # doctest: +IGNORE_EXCEPTION_DETAIL
+    Traceback (most recent call last):
+        ...
+    WorkProgressValidationError: ...
+
+    >>> task.progress = 1
+    >>> task.save()
+    >>> project.save()
+
+Try to re-open task without project::
+
+    >>> task.progress = 0.5
+    >>> task.save()  # doctest: +IGNORE_EXCEPTION_DETAIL
+    Traceback (most recent call last):
+        ...
+    WorkProgressValidationError: ...
+
+Change progress with updating status::
+
+    >>> project.progress = 0.8
+    >>> project.save()  # doctest: +IGNORE_EXCEPTION_DETAIL
+    Traceback (most recent call last):
+        ...
+    WorkProgressValidationError: ...
+
+    >>> project.status = in_progress
+    >>> project.save()
+
+Re-open task::
+
+    >>> task.progress = 0.5
+    >>> task.save()
diff -r 6fb9a7793bdf -r dca2bc7ae397 tests/test_project.py
--- a/tests/test_project.py     Sat Dec 14 10:47:54 2019 +0100
+++ b/tests/test_project.py     Tue Jan 28 11:45:54 2020 +0100
@@ -1,11 +1,14 @@
 # This file is part of Tryton.  The COPYRIGHT file at the top level of
 # this repository contains the full copyright notices and license terms.
+import datetime
+import doctest
 import unittest
-import datetime
 
 import trytond.tests.test_tryton
+from trytond.pool import Pool
 from trytond.tests.test_tryton import ModuleTestCase, with_transaction
-from trytond.pool import Pool
+from trytond.tests.test_tryton import doctest_checker
+from trytond.tests.test_tryton import doctest_teardown
 from trytond.transaction import Transaction
 
 from trytond.modules.company.tests import create_company, set_company
@@ -187,4 +190,9 @@
     suite = trytond.tests.test_tryton.suite()
     suite.addTests(unittest.TestLoader().loadTestsFromTestCase(
             ProjectTestCase))
+    suite.addTests(doctest.DocFileSuite(
+            'scenario_project_status.rst',
+            tearDown=doctest_teardown, encoding='utf-8',
+            checker=doctest_checker,
+            optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
     return suite
diff -r 6fb9a7793bdf -r dca2bc7ae397 view/work_form.xml
--- a/view/work_form.xml        Sat Dec 14 10:47:54 2019 +0100
+++ b/view/work_form.xml        Tue Jan 28 11:45:54 2020 +0100
@@ -42,10 +42,10 @@
             <newline/>
             <separator name="comment" colspan="6"/>
             <field name="comment" colspan="6"/>
-            <group col="4" colspan="6" id="state_buttons">
-                <group col="2" colspan="2" id="state">
-                    <label name="state"/>
-                    <field name="state"/>
+            <group col="4" colspan="6" id="status_buttons">
+                <group col="2" colspan="2" id="status">
+                    <label name="status"/>
+                    <field name="status" widget="selection"/>
                 </group>
                 <group col="-1" colspan="2" id="buttons">
                 </group>
diff -r 6fb9a7793bdf -r dca2bc7ae397 view/work_list.xml
--- a/view/work_list.xml        Sat Dec 14 10:47:54 2019 +0100
+++ b/view/work_list.xml        Tue Jan 28 11:45:54 2020 +0100
@@ -6,6 +6,6 @@
     <field name="timesheet_duration"/>
     <field name="total_effort"/>
     <field name="type"/>
-    <field name="state"/>
+    <field name="status"/>
     <field name="total_progress" widget="progressbar" expand="1"/>
 </tree>
diff -r 6fb9a7793bdf -r dca2bc7ae397 view/work_list_children.xml
--- a/view/work_list_children.xml       Sat Dec 14 10:47:54 2019 +0100
+++ b/view/work_list_children.xml       Tue Jan 28 11:45:54 2020 +0100
@@ -6,5 +6,5 @@
     <field name="timesheet_duration"/>
     <field name="total_effort"/>
     <field name="type"/>
-    <field name="state"/>
+    <field name="status"/>
 </tree>
diff -r 6fb9a7793bdf -r dca2bc7ae397 view/work_list_simple.xml
--- a/view/work_list_simple.xml Sat Dec 14 10:47:54 2019 +0100
+++ b/view/work_list_simple.xml Tue Jan 28 11:45:54 2020 +0100
@@ -4,5 +4,5 @@
 <tree>
     <field name="rec_name" expand="1"/>
     <field name="type"/>
-    <field name="state"/>
+    <field name="status"/>
 </tree>
diff -r 6fb9a7793bdf -r dca2bc7ae397 view/work_status_form.xml
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/view/work_status_form.xml Tue Jan 28 11:45:54 2020 +0100
@@ -0,0 +1,24 @@
+<?xml version="1.0"?>
+<!-- This file is part of Tryton.  The COPYRIGHT file at the top level of
+this repository contains the full copyright notices and license terms. -->
+<form>
+    <label name="name"/>
+    <field name="name"/>
+    <group colspan="2" col="-1" id="checkboxes">
+        <label name="active"/>
+        <field name="active" xexpand="0" width="25"/>
+        <label name="default"/>
+        <field name="default" xexpand="0" width="25"/>
+        <label name="count"/>
+        <field name="count" xexpand="0" width="25"/>
+        <label name="sequence"/>
+        <field name="sequence"/>
+    </group>
+    <label name="types"/>
+    <field name="types" yexpand="0"/>
+    <label name="progress"/>
+    <group col="-1" id="progress">
+        <field name="progress" factor="100" xexpand="0"/>
+        <label name="progress" string="%" xalign="0.0" xexpand="1"/>
+    </group>
+</form>
diff -r 6fb9a7793bdf -r dca2bc7ae397 view/work_status_list.xml
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/view/work_status_list.xml Tue Jan 28 11:45:54 2020 +0100
@@ -0,0 +1,8 @@
+<?xml version="1.0"?>
+<!-- This file is part of Tryton.  The COPYRIGHT file at the top level of
+this repository contains the full copyright notices and license terms. -->
+<tree sequence="sequence">
+    <field name="name"/>
+    <field name="types"/>
+    <field name="default"/>
+</tree>
diff -r 6fb9a7793bdf -r dca2bc7ae397 view/work_tree.xml
--- a/view/work_tree.xml        Sat Dec 14 10:47:54 2019 +0100
+++ b/view/work_tree.xml        Tue Jan 28 11:45:54 2020 +0100
@@ -6,6 +6,6 @@
     <field name="timesheet_duration"/>
     <field name="total_effort"/>
     <field name="type"/>
-    <field name="state"/>
+    <field name="status"/>
     <field name="total_progress" widget="progressbar" expand="1"/>
 </tree>
diff -r 6fb9a7793bdf -r dca2bc7ae397 view/work_tree_simple.xml
--- a/view/work_tree_simple.xml Sat Dec 14 10:47:54 2019 +0100
+++ b/view/work_tree_simple.xml Tue Jan 28 11:45:54 2020 +0100
@@ -4,5 +4,5 @@
 <tree sequence="sequence">
     <field name="name" expand="1"/>
     <field name="type"/>
-    <field name="state"/>
+    <field name="status"/>
 </tree>
diff -r 6fb9a7793bdf -r dca2bc7ae397 work.py
--- a/work.py   Sat Dec 14 10:47:54 2019 +0100
+++ b/work.py   Tue Jan 28 11:45:54 2020 +0100
@@ -5,16 +5,115 @@
 
 from sql import Null
 
+from trytond.cache import Cache
 from trytond.i18n import gettext
-from trytond.model import ModelView, ModelSQL, fields, sequence_ordered, tree
-from trytond.pyson import Eval
+from trytond.model import (
+    ModelView, ModelSQL, fields, sequence_ordered, tree, DeactivableMixin)
 from trytond.transaction import Transaction
 from trytond.pool import Pool
+from trytond.pyson import Eval, PYSONEncoder
 from trytond.tools import reduce_ids, grouped_slice
 
-from .exceptions import WorkValidationError
+from .exceptions import WorkProgressValidationError
+
+
+class WorkStatus(DeactivableMixin, sequence_ordered(), ModelSQL, ModelView):
+    'Work Status'
+    __name__ = 'project.work.status'
+
+    _get_default_status_cache = Cache('project_work_status.get_default_status')
+    _get_window_domains_cache = Cache('project_work_status.get_window_domains')
+
+    types = fields.MultiSelection(
+        'get_types', "Types",
+        help="The type of works which can use this status.")
+    name = fields.Char("Name", required=True, translate=True)
+    progress = fields.Float(
+        "Progress",
+        domain=['OR',
+            ('progress', '=', None),
+            [
+                ('progress', '>=', 0),
+                ('progress', '<=', 1),
+                ],
+            ],
+        help="The minimum progress required for this status.")
+    default = fields.Boolean(
+        "Default",
+        help="Check to use as default status for the type.")
+    count = fields.Boolean(
+        "Count",
+        help="Check to show the number of works in this status.")
+
+    @classmethod
+    def get_types(cls):
+        pool = Pool()
+        Work = pool.get('project.work')
+        return Work.fields_get(['type'])['type']['selection']
 
-__all__ = ['Work']
+    @classmethod
+    def get_default_status(cls, type_=None):
+        if type_ is None:
+            return None
+        status = cls._get_default_status_cache.get(type_, -1)
+        if status != -1:
+            return status
+        records = cls.search([
+                ('types', 'in', type_),
+                ('default', '=', True)
+                ], limit=1)
+        if records:
+            status = records[0].id
+        else:
+            status = None
+        cls._get_default_status_cache.set(type, status)
+        return status
+
+    @classmethod
+    def create(cls, vlist):
+        cls._get_default_status_cache.clear()
+        cls._get_window_domains_cache.clear()
+        return super().create(vlist)
+
+    @classmethod
+    def write(cls, *args):
+        super().write(*args)
+        cls._get_default_status_cache.clear()
+        cls._get_window_domains_cache.clear()
+
+    @classmethod
+    def delete(cls, status):
+        cls._get_default_status_cache.clear()
+        cls._get_window_domains_cache.clear()
+        super().delete(status)
+
+    @classmethod
+    def get_window_domains(cls, action):
+        pool = Pool()
+        Data = pool.get('ir.model.data')
+        if action.id == Data.get_id('project', 'act_project_tree'):
+            return cls._get_window_domains([x[0] for x in cls.get_types()])
+        elif action.id == Data.get_id('project', 'act_project_form'):
+            return cls._get_window_domains(['project'])
+        elif action.id == Data.get_id('project', 'act_task_form'):
+            return cls._get_window_domains(['task'])
+
+    @classmethod
+    def _get_window_domains(cls, types):
+        key = tuple(sorted(types))
+        domains = cls._get_window_domains_cache.get(key)
+        if domains is not None:
+            return domains
+        encoder = PYSONEncoder()
+        domains = []
+        for status in cls.search([('types', 'in', types)]):
+            domain = encoder.encode([('status', '=', status.id)])
+            domains.append((status.name, domain, status.count))
+        if domains:
+            domains.append(
+                (gettext('project.msg_domain_all'), '[]', False))
+        cls._get_window_domains_cache.set(key, domains)
+        return domains
 
 
 class Work(sequence_ordered(), tree(separator='\\'), ModelSQL, ModelView):
@@ -94,10 +193,9 @@
             ('company', '=', Eval('company', -1)),
             ],
         depends=['company'])
-    state = fields.Selection([
-            ('opened', 'Opened'),
-            ('done', 'Done'),
-            ], 'State', required=True, select=True)
+    status = fields.Many2One(
+        'project.work.status', "Status", required=True, select=True,
+        domain=[('types', 'in', Eval('type'))], depends=['type'])
 
     @staticmethod
     def default_type():
@@ -107,9 +205,11 @@
     def default_company(cls):
         return Transaction().context.get('company')
 
-    @staticmethod
-    def default_state():
-        return 'opened'
+    @classmethod
+    def default_status(cls):
+        pool = Pool()
+        WorkStatus = pool.get('project.work.status')
+        return WorkStatus.get_default_status(cls.default_type())
 
     @classmethod
     def default_left(cls):
@@ -198,6 +298,25 @@
                         where=timesheet.id == work_id))
             table_project_work.drop_column('work')
 
+        # Migration from 5.4: replace state by status
+        table_project_work.not_null_action('state', action='remove')
+
+    @fields.depends('type', 'status')
+    def on_change_type(self):
+        pool = Pool()
+        WorkState = pool.get('project.work.status')
+        if (self.type
+                and (not self.status
+                    or self.type not in self.status.types)):
+            self.status = WorkState.get_default_status(self.type)
+
+    @fields.depends('status', 'progress')
+    def on_change_status(self):
+        if (self.status
+                and self.status.progress is not None
+                and self.status.progress > (self.progress or -1.0)):
+            self.progress = self.status.progress
+
     @classmethod
     def index_set_field(cls, name):
         index = super(Work, cls).index_set_field(name)
@@ -209,22 +328,33 @@
     def validate(cls, works):
         super(Work, cls).validate(works)
         for work in works:
-            work.check_state()
+            work.check_work_progress()
 
-    def check_state(self):
-        if (self.state == 'opened'
-                and (self.parent and self.parent.state == 'done')):
-            raise WorkValidationError(
-                gettext('project.msg_work_invalid_parent_state',
-                    child=self.rec_name,
+    def check_work_progress(self):
+        pool = Pool()
+        progress = -1 if self.progress is None else self.progress
+        if (self.status.progress is not None
+                and progress < self.status.progress):
+            Lang = pool.get('ir.lang')
+            lang = Lang.get()
+            raise WorkProgressValidationError(
+                gettext('project.msg_work_invalid_progress_status',
+                    work=self.rec_name,
+                    progress=lang.format('%.2f%%', self.status.progress * 100),
+                    status=self.status.rec_name))
+        if (self.status.progress == 1.0
+                and not all(c.progress == 1.0 for c in self.children)):
+            raise WorkProgressValidationError(
+                gettext('project.msg_work_children_progress',
+                    work=self.rec_name,
+                    status=self.status.rec_name))
+        if (self.parent
+                and self.parent.progress == 1.0
+                and not self.progress == 1.0):
+            raise WorkProgressValidationError(
+                gettext('project.msg_work_parent_progress',
+                    work=self.rec_name,
                     parent=self.parent.rec_name))
-        if self.state == 'done':
-            for child in self.children:
-                if child.state == 'opened':
-                    raise WorkValidationError(
-                        gettext('project.msg_work_invalid_children_state',
-                            parent=self.rec_name,
-                            child=child.rec_name))
 
     @property
     def effort_hours(self):
diff -r 6fb9a7793bdf -r dca2bc7ae397 work.xml
--- a/work.xml  Sat Dec 14 10:47:54 2019 +0100
+++ b/work.xml  Tue Jan 28 11:45:54 2020 +0100
@@ -3,6 +3,49 @@
 this repository contains the full copyright notices and license terms. -->
 <tryton>
     <data>
+        <record model="ir.ui.view" id="work_status_view_list">
+            <field name="model">project.work.status</field>
+            <field name="type">tree</field>
+            <field name="name">work_status_list</field>
+        </record>
+        <record model="ir.ui.view" id="work_status_view_form">
+            <field name="model">project.work.status</field>
+            <field name="type">form</field>
+            <field name="name">work_status_form</field>
+        </record>
+        <record model="ir.action.act_window" id="act_work_status">
+            <field name="name">Work Status</field>
+            <field name="res_model">project.work.status</field>
+        </record>
+        <record model="ir.action.act_window.view" id="act_work_status_view1">
+            <field name="sequence" eval="10"/>
+            <field name="view" ref="work_status_view_list"/>
+            <field name="act_window" ref="act_work_status"/>
+        </record>
+        <record model="ir.action.act_window.view" id="act_work_status_view2">
+            <field name="sequence" eval="20"/>
+            <field name="view" ref="work_status_view_form"/>
+            <field name="act_window" ref="act_work_status"/>
+        </record>
+        <menuitem parent="menu_configuration" sequence="20"
+            action="act_work_status" id="menu_work_status"/>
+
+        <record model="ir.model.access" id="access_work_status">
+            <field name="model" search="[('model', '=', 
'project.work.status')]"/>
+            <field name="perm_read" eval="True"/>
+            <field name="perm_write" eval="False"/>
+            <field name="perm_create" eval="False"/>
+            <field name="perm_delete" eval="False"/>
+        </record>
+        <record model="ir.model.access" id="access_work_status_admin">
+            <field name="model" search="[('model', '=', 
'project.work.status')]"/>
+            <field name="group" ref="group_project_admin"/>
+            <field name="perm_read" eval="True"/>
+            <field name="perm_write" eval="True"/>
+            <field name="perm_create" eval="True"/>
+            <field name="perm_delete" eval="True"/>
+        </record>
+
         <record model="ir.ui.view" id="work_view_tree">
             <field name="model">project.work</field>
             <field name="type">tree</field>
@@ -98,19 +141,6 @@
             <field name="view" ref="work_view_form"/>
             <field name="act_window" ref="act_project_tree"/>
         </record>
-        <record model="ir.action.act_window.domain" 
id="act_project_tree_opened">
-            <field name="name">Opened</field>
-            <field name="sequence" eval="10"/>
-            <field name="domain" eval="[('state', '=', 'opened')]" pyson="1"/>
-            <field name="count" eval="True"/>
-            <field name="act_window" ref="act_project_tree"/>
-        </record>
-        <record model="ir.action.act_window.domain" id="act_project_tree_done">
-            <field name="name">Done</field>
-            <field name="sequence" eval="20"/>
-            <field name="domain" eval="[('state', '=', 'done')]" pyson="1"/>
-            <field name="act_window" ref="act_project_tree"/>
-        </record>
         <menuitem parent="menu_project" action="act_project_tree"
             id="menu_project_tree" sequence="20"/>
 
@@ -132,19 +162,6 @@
             <field name="view" ref="work_view_form"/>
             <field name="act_window" ref="act_project_form"/>
         </record>
-        <record model="ir.action.act_window.domain" 
id="act_project_form_opened">
-            <field name="name">Opened</field>
-            <field name="sequence" eval="10"/>
-            <field name="domain" eval="[('state', '=', 'opened')]" pyson="1"/>
-            <field name="count" eval="True"/>
-            <field name="act_window" ref="act_project_form"/>
-        </record>
-        <record model="ir.action.act_window.domain" id="act_project_form_done">
-            <field name="name">Done</field>
-            <field name="sequence" eval="20"/>
-            <field name="domain" eval="[('state', '=', 'done')]" pyson="1"/>
-            <field name="act_window" ref="act_project_form"/>
-        </record>
         <menuitem parent="menu_project_tree" action="act_project_form"
             id="menu_project_form"/>
 
@@ -166,19 +183,6 @@
             <field name="view" ref="work_view_form"/>
             <field name="act_window" ref="act_task_form"/>
         </record>
-        <record model="ir.action.act_window.domain" id="act_task_form_opened">
-            <field name="name">Opened</field>
-            <field name="sequence" eval="10"/>
-            <field name="domain" eval="[('state', '=', 'opened')]" pyson="1"/>
-            <field name="count" eval="True"/>
-            <field name="act_window" ref="act_task_form"/>
-        </record>
-        <record model="ir.action.act_window.domain" id="act_task_form_done">
-            <field name="name">Done</field>
-            <field name="sequence" eval="20"/>
-            <field name="domain" eval="[('state', '=', 'done')]" pyson="1"/>
-            <field name="act_window" ref="act_task_form"/>
-        </record>
         <menuitem parent="menu_project_tree" action="act_task_form"
             id="menu_task_form"/>
 
@@ -226,4 +230,17 @@
         </record>
 
     </data>
+    <data noupdate="1">
+        <record model="project.work.status" id="work_open_status">
+            <field name="name">Open</field>
+            <field name="default" eval="True"/>
+            <field name="count" eval="True"/>
+            <field name="types" eval="['project', 'task']"/>
+        </record>
+        <record model="project.work.status" id="work_done_status">
+            <field name="name">Done</field>
+            <field name="progress" eval="1.0"/>
+            <field name="types" eval="['project', 'task']"/>
+        </record>
+    </data>
 </tryton>

Reply via email to