Merge lp:~acsone-openerp/hr-timesheet/migration_hr_timesheet_taskV7 into lp:~hr-core-editors/hr-timesheet/7.0

Proposed by Laetitia Gangloff (Acsone)
Status: Merged
Approved by: Guewen Baconnier @ Camptocamp
Approved revision: 49
Merged at revision: 41
Proposed branch: lp:~acsone-openerp/hr-timesheet/migration_hr_timesheet_taskV7
Merge into: lp:~hr-core-editors/hr-timesheet/7.0
Diff against target: 1428 lines (+712/-403)
19 files modified
hr_timesheet_task/__init__.py (+15/-25)
hr_timesheet_task/__openerp__.py (+14/-10)
hr_timesheet_task/hr_analytic_timesheet_view.xml (+14/-27)
hr_timesheet_task/hr_timesheet_sheet_view.xml (+14/-12)
hr_timesheet_task/i18n/fr.po (+42/-0)
hr_timesheet_task/static/src/css/timesheet.css (+7/-0)
hr_timesheet_task/static/src/js/timesheet.js (+252/-0)
hr_timesheet_task/static/src/xml/timesheet.xml (+35/-0)
hr_timesheet_task/wizard/__init__.py (+0/-3)
hr_timesheet_task/wizard/associate_analytic_timesheet.py (+0/-48)
hr_timesheet_task/wizard/dissociate_analytic_timesheet.py (+0/-47)
hr_timesheet_task/wizard/hr_timesheet_invoice_create.py (+0/-46)
hr_timesheet_task/wizard/wizard_actions.xml (+0/-34)
timesheet_task/__init__.py (+15/-23)
timesheet_task/__openerp__.py (+12/-13)
timesheet_task/i18n/fr.po (+53/-0)
timesheet_task/project_task.py (+36/-49)
timesheet_task/project_task_view.xml (+203/-37)
timesheet_task/tmp_file_for_project_indicator.py (+0/-29)
To merge this branch: bzr merge lp:~acsone-openerp/hr-timesheet/migration_hr_timesheet_taskV7
Reviewer Review Type Date Requested Status
Stéphane Bidoul (Acsone) (community) code & test Approve
Yannick Vaucher @ Camptocamp code Approve
Nicolas Bessi - Camptocamp (community) Needs Fixing
Review via email: mp+154433@code.launchpad.net

Description of the change

Migration of the module hr_timesheet_task and following improvement:

-Add task column in "My Current Timesheet" view (updating existing qweb/js/css).

-In hr_analytic_timesheet_view.xml remove hr_timesheet.hr_timesheet_line_search record because it is already done in hr_timesheet_invoice (herited from timesheet_task).

-In task_id domain add ('project_id.analytic_account_id','=',account_id) to filter on task related to the selected project.

To post a comment you must log in.
43. By Stéphane Bidoul (Acsone)

[FIX] restore filters and change their labels now that we have more room in the new search widget

44. By Stéphane Bidoul (Acsone)

[IMP] remove tabs and cleanup whitespace, clarify comments and rename a variable for clarity

Revision history for this message
Stéphane Bidoul (Acsone) (sbi) wrote :

I pushed a fix to restore and slightly improve the Current Year/Month/Week filters.

I did manual testing and it works fine.

The code in timesheet.js is duplicating a lot of code of hr_timesheet_sheet, but there is no other way around unless proper hooks are inserted upstream.

review: Approve (approve)
Revision history for this message
Yannick Vaucher @ Camptocamp (yvaucher-c2c) wrote :

Hello,

There are some cleaning that could be done in .py files

-> Remove osv.memory
import orm and use orm.TransiantModel instead

from openerp.osv import osv, orm

class MyWizard(orm.TransientModel):

-> Remove useless class instantiations
like on l516 remove the "ProjectTask()".

And in XML, it would better to use simpler relative xpath when possible
like l535 could be "///field[@name='work_ids']" (if it had been done previously the change wouldn't have been needed)

Thanks

review: Needs Fixing (code)
Revision history for this message
Yannick Vaucher @ Camptocamp (yvaucher-c2c) wrote :

///field[@name='work_ids'] is //field[@name='work_ids'] :)

45. By Laetitia Gangloff (Acsone)

hr_timesheet_task/timesheet_task: replace some xpath by field in view. remove instanciation from project_task.py. Remove unused wizard and tmp_file. Rename aa_ids in timesheet_ids. Correct some issues with work_ids. Add french translation.

46. By Laetitia Gangloff (Acsone)

timesheet_task/hr_timesheet_task: correct label in translation. Cosmetic change in openerp.py

Revision history for this message
Laetitia Gangloff (Acsone) (laetitia-gangloff) wrote :

Hello,

we remove wizard from hr_timesheet_task because it is never used (not in __init__.py), and tmp_file from timesheet_task.
We remove useless class instantiations in project_task.py.
we change xpath to have a more readable and maintainable view.
we correct some problems with the work_ids (renamed in timesheet_ids).
we add french translations.

Regards

Revision history for this message
Stéphane Bidoul (Acsone) (sbi) :
review: Approve (code and test)
Revision history for this message
Stéphane Bidoul (Acsone) (sbi) wrote :

Hi Laetitia,

Can you add a comment to clarify the purpose and behavior of this code.
This looks tricky enough to warrant some comments :)

for col in ['effective_hours', 'planned_hours', 'total_hours', 'progress_rate']:
   assert project.project._columns[col].store['project.task'][1][2] == 'work_ids', _('work_ids seems to be not present in project.project')
   project.project._columns[col].store['project.task'][1][2] = 'timesheet_ids'

Nitpicking: redundant code in copy_data:

+ if default is None:
+ default = {}
+ default = default or {}

review: Needs Fixing (code)
Revision history for this message
Nicolas Bessi - Camptocamp (nbessi-c2c-deactivatedaccount) wrote :

The goal of timesheet_task is to replace projeck.task.work with aa lines.
In original __openerp__:
'description': """Replace project.task.work items linked to task
                   with hr.analytic.timesheet""",

We do not want to add a new relation named timesheet_ids. The goal is replace this base behavior else you have to maintain two vision of working and add a second set of indicator. I do not say that keeping work done + timesheet line relation is not a valid approach but it does not fit the original goal of the addon who was to get rid of project.task.work by replacing the relation.

review: Needs Fixing
Revision history for this message
Stéphane Bidoul (Acsone) (sbi) wrote :

Hi Nicolas,

The goal is not to add a new relation but indeed redefine work_ids to become a relation to hr.analytic.timesheet.

In the previous version, this was done by redefining work_ids, but OpenERP 7.0 now complains about this (see comments from Laetitia there: https://code.launchpad.net/~laetitia-gangloff/hr-timesheet/migrationV7/+merge/148260). Maybe this new behaviour of 7.0 can be considered a bug?

This is the reason we have to create this new field (and sort-of depreate work_ids).

Best regards,

-sbi

Revision history for this message
Nicolas Bessi - Camptocamp (nbessi-c2c-deactivatedaccount) wrote :

Hello,

Ok I see your point that is an annoying bug, I will propose to try to replace the view in XML instead of inheriting it and ensure it has a low priority. Eventually we can keep the inherit. I know it is a little nasty but I don't think there is a simple way to fix the root bug.

Regards

Nicolas

47. By Laetitia Gangloff (Acsone)

in timesheet_task replace XML view instead of inherited it.

Revision history for this message
Laetitia Gangloff (Acsone) (laetitia-gangloff) wrote :

Hello,

as you suggested, I replace the view instead of inheritting it.
In addition, I kept work_ids instead of a timesheet_ids.

Thanks

Revision history for this message
Yannick Vaucher @ Camptocamp (yvaucher-c2c) wrote :

Thanks for the work

I think you should just change the inheritances of deprecated alias osv.osv
On l864, l919, l928

And other to be removed as well if it exists

See osv.py
-----------------
# deprecated - for backward compatibility.
osv = Model
osv_memory = TransientModel
osv_abstract = AbstractModel # ;-)
-----------------

http://help.openerp.com/question/8112/about-deprecated-models-in-v7/

So you need to use orm.Model and for me we are good there.

The license could also be changed to AGPL if you have the time to do it.

Otherwise it's look good

Thanks

review: Needs Fixing
48. By Laetitia Gangloff (Acsone)

in project_task used osv.Model instead of osv.osv. Update licence part.

49. By Laetitia Gangloff (Acsone)

in project_task used orm.Model instead of osv.Model.

Revision history for this message
Laetitia Gangloff (Acsone) (laetitia-gangloff) wrote :

I use orm.Model instead of osv.osv and I try to update licence part.

Revision history for this message
Yannick Vaucher @ Camptocamp (yvaucher-c2c) wrote :

Ok thanks for your changes

LGTM now :)

review: Approve (code)
Revision history for this message
Stéphane Bidoul (Acsone) (sbi) :
review: Approve (code & test)
Revision history for this message
Stéphane Bidoul (Acsone) (sbi) wrote :

If there are no more comments, can someone with commit rights merge this one?

We have some additional improvements we would like to propose, but these are separate from the v7 migration and will be part of another MP on top of this one.

Thanks,

-sbi

Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote :

Done

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'hr_timesheet_task/__init__.py'
2--- hr_timesheet_task/__init__.py 2012-06-06 13:14:12 +0000
3+++ hr_timesheet_task/__init__.py 2013-04-03 11:31:22 +0000
4@@ -1,30 +1,20 @@
5 # -*- coding: utf-8 -*-
6 ##############################################################################
7 #
8-# Copyright (c) 2010 Camptocamp SA (http://www.camptocamp.com)
9-# All Right Reserved
10-#
11-# Author : Joel Grand-guillaume (Camptocamp)
12-#
13-# WARNING: This program as such is intended to be used by professional
14-# programmers who take the whole responsability of assessing all potential
15-# consequences resulting from its eventual inadequacies and bugs
16-# End users who are looking for a ready-to-use solution with commercial
17-# garantees and support are strongly adviced to contract a Free Software
18-# Service Company
19-#
20-# This program is Free Software; you can redistribute it and/or
21-# modify it under the terms of the GNU General Public License
22-# as published by the Free Software Foundation; either version 2
23-# of the License, or (at your option) any later version.
24-#
25-# This program is distributed in the hope that it will be useful,
26-# but WITHOUT ANY WARRANTY; without even the implied warranty of
27-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28-# GNU General Public License for more details.
29-#
30-# You should have received a copy of the GNU General Public License
31-# along with this program; if not, write to the Free Software
32-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
33+# Author : Joel Grand-guillaume (Camptocamp)
34+# Copyright 2013 Camptocamp SA
35+#
36+# This program is free software: you can redistribute it and/or modify
37+# it under the terms of the GNU Affero General Public License as
38+# published by the Free Software Foundation, either version 3 of the
39+# License, or (at your option) any later version.
40+#
41+# This program is distributed in the hope that it will be useful,
42+# but WITHOUT ANY WARRANTY; without even the implied warranty of
43+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
44+# GNU Affero General Public License for more details.
45+#
46+# You should have received a copy of the GNU Affero General Public License
47+# along with this program. If not, see <http://www.gnu.org/licenses/>.
48 #
49 ##############################################################################
50
51=== modified file 'hr_timesheet_task/__openerp__.py'
52--- hr_timesheet_task/__openerp__.py 2012-12-13 12:20:12 +0000
53+++ hr_timesheet_task/__openerp__.py 2013-04-03 11:31:22 +0000
54@@ -2,7 +2,7 @@
55 ##############################################################################
56 #
57 # Author: Nicolas Bessi
58-# Copyright 2012 Camptocamp SA
59+# Copyright 2013 Camptocamp SA
60 #
61 # This program is free software: you can redistribute it and/or modify
62 # it under the terms of the GNU Affero General Public License as
63@@ -19,21 +19,25 @@
64 #
65 ##############################################################################
66 {'name' : 'Task in time sheet',
67- 'version' : '0.1',
68+ 'version' : '0.2',
69 'author' : 'Camptocamp',
70- 'maintainer': 'Camptocamp',
71+ 'maintainer': 'Camptocamp - Acsone SA/NV',
72 'category': 'Human Resources',
73- 'complexity': "normal", #easy, normal, expert
74 'depends' : ['timesheet_task', 'hr_timesheet_sheet'],
75 'description': """Replace project.task.work items linked to task
76 with hr.analytic.timesheet""",
77 'website': 'http://www.camptocamp.com',
78- 'init_xml': [],
79- 'update_xml': ['hr_timesheet_sheet_view.xml', 'hr_analytic_timesheet_view.xml'],
80- 'demo_xml': [],
81- 'tests': [],
82- 'installable': False,
83+ 'data': ['hr_timesheet_sheet_view.xml', 'hr_analytic_timesheet_view.xml'],
84+ 'js' : ['static/src/js/timesheet.js'],
85+ 'css': ['static/src/css/timesheet.css',],
86+ 'qweb': ['static/src/xml/timesheet.xml'],
87+ 'demo': [],
88+ 'test': [],
89+ 'installable': True,
90 'images' : [],
91 'auto_install': False,
92 'license': 'AGPL-3',
93- 'application': True}
94\ No newline at end of file
95+ 'application': True,
96+}
97+
98+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
99
100=== modified file 'hr_timesheet_task/hr_analytic_timesheet_view.xml'
101--- hr_timesheet_task/hr_analytic_timesheet_view.xml 2012-10-23 15:06:03 +0000
102+++ hr_timesheet_task/hr_analytic_timesheet_view.xml 2013-04-03 11:31:22 +0000
103@@ -9,10 +9,10 @@
104 <field name="type">form</field>
105 <field name="inherit_id" ref="hr_timesheet.hr_timesheet_line_form"/>
106 <field name="arch" type="xml">
107- <xpath expr="/form/group/field[@name='user_id']" position="after">
108+ <field name="user_id" position="after">
109 <field name="task_id" context="{ 'account_id' : account_id}"
110- domain="[('state','=','open')]"/>
111- </xpath>
112+ domain="[('state','=','open'), ('project_id.analytic_account_id','=',account_id)]"/>
113+ </field>
114 </field>
115 </record>
116 <record id="hr_timesheet.hr_timesheet_line_tree" model="ir.ui.view">
117@@ -25,7 +25,7 @@
118 <field name="date" on_change="on_change_date(date)"/>
119 <field domain="[('type','=','normal')]" name="account_id"/>
120 <field name="task_id" context="{'account_id' : account_id}"
121- domain="[('state','=','open')]"/>
122+ domain="[('state','=','open'), ('project_id.analytic_account_id','=',account_id)]"/>
123 <field name="name"/>
124 <field name="unit_amount"
125 on_change="on_change_unit_amount(product_id, unit_amount, False, product_uom_id, journal_id)"
126@@ -52,9 +52,9 @@
127 <field name="inherit_id" ref="hr_timesheet.hr_timesheet_line_search"/>
128 <field name="type">search</field>
129 <field name="arch" type="xml">
130- <xpath expr="/search/group/field[@name='date']" position="after">
131+ <field name="date" position="after">
132 <field name="task_id"/>
133- </xpath>
134+ </field>
135 <xpath
136 expr="/search/group[@string='Group By...']/filter[@string='Analytic account']"
137 position="after">
138@@ -62,16 +62,17 @@
139 />
140 </xpath>
141 <!-- Add dates filter -->
142- <xpath expr="/search/group/filter[@name='today']" position="before">
143- <filter icon="terp-go-year" string=" Year "
144+ <xpath expr="/search/group" position="before">
145+ <separator orientation="vertical"/>
146+ <filter icon="terp-go-year" string="Current Year"
147 domain="[('date','&lt;=', time.strftime('%%Y-%%m-%%d')),('date','&gt;=',time.strftime('%%Y-01-01'))]"
148 help="Current Year"/>
149- <filter icon="terp-go-month" string=" Month " name="month"
150- domain="[('date','&lt;=',(datetime.date.today()+relativedelta(day=31)).strftime('%%Y-%%m-%%d')),('date','&gt;=',(datetime.date.today()-relativedelta(day=1)).strftime('%%Y-%%m-%%d'))]"
151+ <filter icon="terp-go-month" string="Current Month" name="month"
152+ domain="[('date','&lt;=',(context_today()+relativedelta(day=31)).strftime('%%Y-%%m-%%d')),('date','&gt;=',(context_today()-relativedelta(day=1)).strftime('%%Y-%%m-%%d'))]"
153 help="Current Month"/>
154- <filter icon="terp-go-week" string=" Week " separator="1" name="week"
155- domain="[('date','&gt;=',(datetime.date.today()+relativedelta(days=-6,weekday=0)).strftime('%%Y-%%m-%%d')),('date','&lt;=',(datetime.date.today()+relativedelta(weekday=6)).strftime('%%Y-%%m-%%d'))]"
156- help="Current week"/>
157+ <filter icon="terp-go-week" string="Current Week" separator="1" name="week"
158+ domain="[('date','&gt;=',(context_today()+relativedelta(days=-6,weekday=0)).strftime('%%Y-%%m-%%d')),('date','&lt;=',(context_today()+relativedelta(weekday=6)).strftime('%%Y-%%m-%%d'))]"
159+ help="Current Week"/>
160 </xpath>
161
162 </field>
163@@ -80,19 +81,5 @@
164 <record id="hr_timesheet.act_hr_timesheet_line_evry1_all_form" model="ir.actions.act_window">
165 <field name="context">{"search_default_user_id":uid, "search_default_week":1}</field>
166 </record>
167- <record id="hr_timesheet_line_search_to_invoice_filter" model="ir.ui.view">
168- <field name="name">hr.analytic.timesheet.search.toinvoice.filter</field>
169- <field name="model">hr.analytic.timesheet</field>
170- <field name="inherit_id" ref="hr_timesheet.hr_timesheet_line_search"/>
171- <field name="type">search</field>
172- <field name="arch" type="xml">
173- <xpath expr="/search/group[1]/filter[@name='today']" position="after">
174- <separator orientation="vertical"/>
175- <filter name="to_invoice" string="To Invoice" context="{'to_invoice': 1}"
176- domain="[('invoice_id','=',False),('to_invoice','&lt;&gt;',False)]"
177- icon="terp-dolar"/>
178- </xpath>
179- </field>
180- </record>
181 </data>
182 </openerp>
183
184=== modified file 'hr_timesheet_task/hr_timesheet_sheet_view.xml'
185--- hr_timesheet_task/hr_timesheet_sheet_view.xml 2012-10-23 15:06:03 +0000
186+++ hr_timesheet_task/hr_timesheet_sheet_view.xml 2013-04-03 11:31:22 +0000
187@@ -1,27 +1,29 @@
188 <?xml version="1.0" encoding="utf-8"?>
189 <openerp>
190 <data>
191+
192 <record id="view_hr_timesheet_sheet_filter_custom" model="ir.ui.view">
193 <field name="name">hr_timesheet_sheet.sheet.filter</field>
194 <field name="model">hr_timesheet_sheet.sheet</field>
195 <field name="inherit_id" ref="hr_timesheet_sheet.view_hr_timesheet_sheet_filter"/>
196 <field name="type">search</field>
197 <field name="arch" type="xml">
198- <xpath expr="/search/group/filter[@string='To Approve']" position="after">
199+ <filter name="to_approve" position="after">
200 <separator orientation="vertical"/>
201- <filter icon="terp-go-year" string=" Year "
202+ <filter icon="terp-go-year" string="Current Year"
203 domain="[('date_from','&lt;=', time.strftime('%%Y-%%m-%%d')),('date_from','&gt;=',time.strftime('%%Y-01-01'))]"
204 help="Current Year"/>
205- <filter icon="terp-go-month" string=" Month " name="month"
206- domain="[('date_from','&lt;=',(datetime.date.today()+relativedelta(day=31)).strftime('%%Y-%%m-%%d')),('date_from','&gt;=',(datetime.date.today()-relativedelta(day=1)).strftime('%%Y-%%m-%%d'))]"
207+ <filter icon="terp-go-month" string="Current Month" name="month"
208+ domain="[('date_from','&lt;=',(context_today()+relativedelta(day=31)).strftime('%%Y-%%m-%%d')),('date_from','&gt;=',(context_today()-relativedelta(day=1)).strftime('%%Y-%%m-%%d'))]"
209 help="Current Month"/>
210- <filter icon="terp-go-week" string=" Week " separator="1" name="week"
211- domain="[('date_from','&gt;=',(datetime.date.today()+relativedelta(days=-6,weekday=0)).strftime('%%Y-%%m-%%d')),('date_from','&lt;=',(datetime.date.today()+relativedelta(weekday=6)).strftime('%%Y-%%m-%%d'))]"
212- help="Current week"/>
213- </xpath>
214+ <filter icon="terp-go-week" string="Current Week" separator="1" name="week"
215+ domain="[('date_from','&gt;=',(context_today()+relativedelta(days=-6,weekday=0)).strftime('%%Y-%%m-%%d')),('date_from','&lt;=',(context_today()+relativedelta(weekday=6)).strftime('%%Y-%%m-%%d'))]"
216+ help="Current Week"/>
217+ </filter>
218
219 </field>
220 </record>
221+
222 <record id="hr_timesheet_sheet.act_hr_timesheet_sheet_form" model="ir.actions.act_window">
223 <field name="context">{'search_default_my_timesheet':1}</field>
224 </record>
225@@ -32,16 +34,16 @@
226 <field name="inherit_id" ref="hr_timesheet_sheet.hr_timesheet_sheet_form"/>
227 <field name="arch" type="xml">
228 <xpath
229- expr="/form/notebook/page[@string='Daily']/field[@name='timesheet_ids']/tree[@string='Timesheet Lines']/field[@name='account_id']"
230+ expr="/form/sheet/notebook/page[@string='Details']/field[@name='timesheet_ids']/tree[@string='Timesheet Activities']/field[@name='account_id']"
231 position="after">
232 <field name="task_id" context="{'account_id' : account_id}"
233- domain="[('state','=','open')]"/>
234+ domain="[('state','=','open'), ('project_id.analytic_account_id','=',account_id)]"/>
235 </xpath>
236 <xpath
237- expr="/form/notebook/page[@string='Daily']/field[@name='timesheet_ids']/form[@string='Timesheet Lines']/field[@name='account_id']"
238+ expr="/form/sheet/notebook/page[@string='Details']/field[@name='timesheet_ids']/form[@string='Timesheet Activities']/field[@name='account_id']"
239 position="after">
240 <field name="task_id" context="{'account_id' : account_id}"
241- domain="[('state','=','open')]"/>
242+ domain="[('state','=','open'), ('project_id.analytic_account_id','=',account_id)]"/>
243 </xpath>
244 </field>
245 </record>
246
247=== added directory 'hr_timesheet_task/i18n'
248=== added file 'hr_timesheet_task/i18n/fr.po'
249--- hr_timesheet_task/i18n/fr.po 1970-01-01 00:00:00 +0000
250+++ hr_timesheet_task/i18n/fr.po 2013-04-03 11:31:22 +0000
251@@ -0,0 +1,42 @@
252+# Translation of OpenERP Server.
253+# This file contains the translation of the following modules:
254+# * hr_timesheet_task
255+#
256+msgid ""
257+msgstr ""
258+"Project-Id-Version: OpenERP Server 7.0\n"
259+"Report-Msgid-Bugs-To: \n"
260+"POT-Creation-Date: 2013-03-28 15:37+0000\n"
261+"PO-Revision-Date: 2013-03-28 15:37+0000\n"
262+"Last-Translator: <>\n"
263+"Language-Team: \n"
264+"MIME-Version: 1.0\n"
265+"Content-Type: text/plain; charset=UTF-8\n"
266+"Content-Transfer-Encoding: \n"
267+"Plural-Forms: \n"
268+
269+#. module: hr_timesheet_task
270+#: view:hr.analytic.timesheet:0
271+#: view:hr_timesheet_sheet.sheet:0
272+msgid "Current Week"
273+msgstr "Semaine en cours"
274+
275+#. module: hr_timesheet_task
276+#: view:hr.analytic.timesheet:0
277+#: view:hr_timesheet_sheet.sheet:0
278+msgid "Current Year"
279+msgstr "Année en cours"
280+
281+#. module: hr_timesheet_task
282+#. openerp-web
283+#: code:addons/hr_timesheet_task/static/src/xml/timesheet.xml:8
284+#: view:hr.analytic.timesheet:0
285+#, python-format
286+msgid "Task"
287+msgstr "Tâche"
288+
289+#. module: hr_timesheet_task
290+#: view:hr.analytic.timesheet:0
291+#: view:hr_timesheet_sheet.sheet:0
292+msgid "Current Month"
293+msgstr "Mois en cours"
294
295=== added directory 'hr_timesheet_task/static'
296=== added directory 'hr_timesheet_task/static/src'
297=== added directory 'hr_timesheet_task/static/src/css'
298=== added file 'hr_timesheet_task/static/src/css/timesheet.css'
299--- hr_timesheet_task/static/src/css/timesheet.css 1970-01-01 00:00:00 +0000
300+++ hr_timesheet_task/static/src/css/timesheet.css 2013-04-03 11:31:22 +0000
301@@ -0,0 +1,7 @@
302+@charset "utf-8";
303+.openerp .oe_timesheet_weekly .oe_timesheet_weekly_task {
304+ text-align: left;
305+}
306+.openerp .oe_timesheet_weekly .oe_timesheet_task_col {
307+ text-align: left;
308+}
309\ No newline at end of file
310
311=== added directory 'hr_timesheet_task/static/src/js'
312=== added file 'hr_timesheet_task/static/src/js/timesheet.js'
313--- hr_timesheet_task/static/src/js/timesheet.js 1970-01-01 00:00:00 +0000
314+++ hr_timesheet_task/static/src/js/timesheet.js 2013-04-03 11:31:22 +0000
315@@ -0,0 +1,252 @@
316+openerp.hr_timesheet_task = function(instance) {
317+
318+ var module = instance.hr_timesheet_sheet
319+
320+ module.WeeklyTimesheet.include({
321+ events: {
322+ "click .oe_timesheet_weekly_account a": "go_to",
323+ "click .oe_timesheet_weekly_task a": "go_to_task",
324+ },
325+ go_to_task : function(event) {
326+ var id = JSON.parse($(event.target).data("task-id"));
327+ this.do_action({
328+ type: 'ir.actions.act_window',
329+ res_model: "project.task",
330+ res_id: id,
331+ views: [[false, 'form']],
332+ target: 'current'
333+ });
334+ },
335+ initialize_content: function() {
336+ var self = this;
337+ if (self.setting)
338+ return;
339+ // don't render anything until we have date_to and date_from
340+ if (!self.get("date_to") || !self.get("date_from"))
341+ return;
342+ this.destroy_content();
343+
344+ // it's important to use those vars to avoid race conditions
345+ var dates;
346+ var accounts;
347+ var account_names;
348+ var task_names;
349+ var default_get;
350+ return this.render_drop.add(new instance.web.Model("hr.analytic.timesheet").call("default_get", [
351+ ['account_id','task_id','general_account_id','journal_id','date','name','user_id','product_id','product_uom_id','to_invoice','amount','unit_amount'],
352+ new instance.web.CompoundContext({'user_id': self.get('user_id')})]).then(function(result) {
353+ default_get = result;
354+ // calculating dates
355+ dates = [];
356+ var start = self.get("date_from");
357+ var end = self.get("date_to");
358+ while (start <= end) {
359+ dates.push(start);
360+ start = start.clone().addDays(1);
361+ }
362+
363+ timesheet_lines = _(self.get("sheets")).chain()
364+ .map(function(el) {
365+ // much simpler to use only the id in all cases
366+ if (typeof(el.account_id) === "object")
367+ el.account_id = el.account_id[0];
368+ if (typeof(el.task_id) === "object")
369+ el.task_id = el.task_id[0];
370+ return el;
371+ }).value();
372+
373+ // group by account
374+ var timesheet_lines_by_account_id = _.groupBy(timesheet_lines, function(el) {
375+ return el.account_id;
376+ });
377+
378+ // group by account and task
379+ var timesheet_lines_by_account_id_task_id = _.groupBy(timesheet_lines, function(el) {
380+ return [el.account_id, el.task_id];
381+ });
382+
383+ var account_ids = _.map(_.keys(timesheet_lines_by_account_id), function(el) { return el === "false" ? false : Number(el) });
384+
385+ return new instance.web.Model("hr.analytic.timesheet").call("multi_on_change_account_id", [[], account_ids,
386+ new instance.web.CompoundContext({'user_id': self.get('user_id')})]).then(function(accounts_defaults) {
387+ accounts = _(timesheet_lines_by_account_id_task_id).chain().map(function(lines, account_id_task_id) {
388+ account_defaults = _.extend({}, default_get, (accounts_defaults[lines[0].account_id] || {}).value || {});
389+ // group by days
390+ var index = _.groupBy(lines, "date");
391+ var days = _.map(dates, function(date) {
392+ var day = {day: date, lines: index[instance.web.date_to_str(date)] || []};
393+ // add line where we will insert/remove hours
394+ var to_add = _.find(day.lines, function(line) { return line.name === self.description_line });
395+ if (to_add) {
396+ day.lines = _.without(day.lines, to_add);
397+ day.lines.unshift(to_add);
398+ } else {
399+ day.lines.unshift(_.extend(_.clone(account_defaults), {
400+ name: self.description_line,
401+ unit_amount: 0,
402+ date: instance.web.date_to_str(date),
403+ account_id: lines[0].account_id,
404+ task_id: lines[0].task_id,
405+ }));
406+ }
407+ return day;
408+ });
409+ return {account_task: account_id_task_id, account: lines[0].account_id, task: lines[0].task_id, days: days, account_defaults: account_defaults};
410+ }).value();
411+
412+ // we need the name_get of the analytic accounts
413+ return new instance.web.Model("account.analytic.account").call("name_get", [_.pluck(accounts, "account"),
414+ new instance.web.CompoundContext()]).then(function(result) {
415+ account_names = {};
416+ _.each(result, function(el) {
417+ account_names[el[0]] = el[1];
418+ });
419+ // we need the name_get of the tasks
420+ return new instance.web.Model("project.task").call("name_get", [_(accounts).chain().pluck("task").filter(function(el) { return el; }).value(),
421+ new instance.web.CompoundContext()]).then(function(result) {
422+ task_names = {};
423+ _.each(result, function(el) {
424+ task_names[el[0]] = el[1];
425+ });
426+ accounts = _.sortBy(accounts, function(el) {
427+ return account_names[el.account];
428+ });
429+ });
430+ });
431+ });
432+ })).then(function(result) {
433+ // we put all the gathered data in self, then we render
434+ self.dates = dates;
435+ self.accounts = accounts;
436+ self.account_names = account_names;
437+ self.task_names = task_names;
438+ self.default_get = default_get;
439+ //real rendering
440+ self.display_data();
441+ });
442+ },
443+ init_add_account: function() {
444+ var self = this;
445+ if (self.dfm)
446+ return;
447+ self.$(".oe_timesheet_weekly_add_row").show();
448+ self.dfm = new instance.web.form.DefaultFieldManager(self);
449+ self.dfm.extend_field_desc({
450+ account: {
451+ relation: "account.analytic.account",
452+ },
453+ task: {
454+ relation: "project.task",
455+ },
456+ });
457+ self.account_m2o = new instance.web.form.FieldMany2One(self.dfm, {
458+ attrs: {
459+ name: "account",
460+ type: "many2one",
461+ domain: [
462+ ['type','in',['normal', 'contract']],
463+ ['state', '<>', 'close'],
464+ ['use_timesheets','=',1],
465+ ],
466+ context: {
467+ default_use_timesheets: 1,
468+ default_type: "contract",
469+ },
470+ modifiers: '{"required": true}',
471+ },
472+ });
473+ self.task_m2o = new instance.web.form.FieldMany2One(self.dfm, {
474+ attrs: {
475+ name: "task",
476+ type: "many2one",
477+ domain: [
478+ // at this moment, it is always an empty list
479+ ['project_id.analytic_account_id','=',self.account_m2o.get_value()]
480+ ],
481+ },
482+ });
483+ self.task_m2o.prependTo(self.$(".oe_timesheet_weekly_add_row td"));
484+ self.account_m2o.prependTo(self.$(".oe_timesheet_weekly_add_row td"));
485+
486+ // when account_m2o loses focus, value can be changed,
487+ // update task_m2o to show only tasks related to the selected project
488+ self.account_m2o.$input.focusout(function(){
489+ var account_id = self.account_m2o.get_value();
490+ if (account_id === false) { return; }
491+ self.task_m2o.init(self.dfm, {
492+ attrs: {
493+ name: "task",
494+ type: "many2one",
495+ domain: [
496+ ['state','=','open'],
497+ // show only tasks linked to the selected project
498+ ['project_id.analytic_account_id','=',account_id],
499+ // ignore tasks already in the timesheet
500+ ['id', 'not in', _.pluck(self.accounts, "task")],
501+ ],
502+ context: {
503+ 'account_id': account_id,
504+ },
505+ },
506+ });
507+ });
508+
509+ self.$(".oe_timesheet_weekly_add_row button").click(function() {
510+ var id = self.account_m2o.get_value();
511+ if (id === false) {
512+ self.dfm.set({display_invalid_fields: true});
513+ return;
514+ }
515+ var ops = self.generate_o2m_value();
516+ new instance.web.Model("hr.analytic.timesheet").call("on_change_account_id", [[], id]).then(function(res) {
517+ var def = _.extend({}, self.default_get, res.value, {
518+ name: self.description_line,
519+ unit_amount: 0,
520+ date: instance.web.date_to_str(self.dates[0]),
521+ account_id: id,
522+ task_id: self.task_m2o.get_value(),
523+ });
524+ ops.push(def);
525+ self.set({"sheets": ops});
526+ });
527+ });
528+ },
529+ get_box: function(account, day_count) {
530+ return this.$('[data-account-task="' + account.account_task + '"][data-day-count="' + day_count + '"]');
531+ },
532+ get_total: function(account) {
533+ return this.$('[data-account-task-total="' + account.account_task + '"]');
534+ },
535+ generate_o2m_value: function() {
536+ var self = this;
537+ var ops = [];
538+
539+ _.each(self.accounts, function(account) {
540+ var auth_keys = _.extend(_.clone(account.account_defaults), {
541+ name: true, unit_amount: true, date: true, account_id: true, task_id: true,
542+ });
543+ _.each(account.days, function(day) {
544+ _.each(day.lines, function(line) {
545+ if (line.unit_amount !== 0) {
546+ var tmp = _.clone(line);
547+ tmp.id = undefined;
548+ _.each(line, function(v, k) {
549+ if (v instanceof Array) {
550+ tmp[k] = v[0];
551+ }
552+ });
553+ // we have to remove some keys, because analytic lines are shitty
554+ _.each(_.keys(tmp), function(key) {
555+ if (auth_keys[key] === undefined) {
556+ tmp[key] = undefined;
557+ }
558+ });
559+ ops.push(tmp);
560+ }
561+ });
562+ });
563+ });
564+ return ops;
565+ },
566+ });
567+};
568
569=== added directory 'hr_timesheet_task/static/src/xml'
570=== added file 'hr_timesheet_task/static/src/xml/timesheet.xml'
571--- hr_timesheet_task/static/src/xml/timesheet.xml 1970-01-01 00:00:00 +0000
572+++ hr_timesheet_task/static/src/xml/timesheet.xml 2013-04-03 11:31:22 +0000
573@@ -0,0 +1,35 @@
574+<?xml version="1.0" encoding="UTF-8"?>
575+
576+<templates>
577+ <t t-extend="hr_timesheet_sheet.WeeklyTimesheet">
578+
579+ <!-- Add a task column -->
580+ <t t-jquery="th.oe_timesheet_first_col" t-operation="after">
581+ <th class="oe_timesheet_task_col">Task</th>
582+ </t>
583+
584+ <!-- Replace all line created with the foreach to take account of task -->
585+ <t t-jquery="tr:not([class]):nth-child(n+2)" t-operation="replace">
586+ <tr t-foreach="widget.accounts" t-as="account">
587+ <td class="oe_timesheet_weekly_account"><a href="javascript:void(0)" t-att-data-id="JSON.stringify(account.account)"><t t-esc="widget.account_names[account.account]"/></a></td>
588+ <td class="oe_timesheet_weekly_task"><a href="javascript:void(0)" t-att-data-task-id="JSON.stringify(account.task)"><t t-esc="widget.task_names[account.task]" /></a></td>
589+ <t t-set="day_count" t-value="0"/>
590+ <t t-foreach="account.days" t-as="day">
591+ <td t-att-class="(Date.compare(day.day, Date.today()) === 0 ? 'oe_timesheet_weekly_today' : '')">
592+ <input t-if="!widget.get('effective_readonly')" class="oe_timesheet_weekly_input"
593+ t-att-data-account-task="account.account_task" t-att-data-day-count="day_count" type="text"/>
594+ <span t-if="widget.get('effective_readonly')" class="oe_timesheet_weekly_box"
595+ t-att-data-account-task="account.account_task" t-att-data-day-count="day_count"/>
596+ <t t-set="day_count" t-value="day_count + 1"/>
597+ </td>
598+ </t>
599+ <td t-att-data-account-task-total="account.account_task" class="oe_timesheet_total"> </td>
600+ </tr>
601+ </t>
602+
603+ <!-- Add line in the last tr before the first element -->
604+ <t t-jquery="tr.oe_timesheet_total > td:first-child" t-operation="after">
605+ <td> </td>
606+ </t>
607+ </t>
608+</templates>
609
610=== removed directory 'hr_timesheet_task/wizard'
611=== removed file 'hr_timesheet_task/wizard/__init__.py'
612--- hr_timesheet_task/wizard/__init__.py 2011-08-12 12:53:16 +0000
613+++ hr_timesheet_task/wizard/__init__.py 1970-01-01 00:00:00 +0000
614@@ -1,3 +0,0 @@
615-import associate_analytic_timesheet
616-import dissociate_analytic_timesheet
617-import hr_timesheet_invoice_create
618
619=== removed file 'hr_timesheet_task/wizard/associate_analytic_timesheet.py'
620--- hr_timesheet_task/wizard/associate_analytic_timesheet.py 2011-08-12 12:53:16 +0000
621+++ hr_timesheet_task/wizard/associate_analytic_timesheet.py 1970-01-01 00:00:00 +0000
622@@ -1,48 +0,0 @@
623-# -*- coding: utf-8 -*-
624-##############################################################################
625-#
626-# Author Guewen Baconnier. Copyright Camptocamp SA
627-#
628-##############################################################################
629-# WARNING: This program as such is intended to be used by professional
630-# programmers who take the whole responsability of assessing all potential
631-# consequences resulting from its eventual inadequacies and bugs
632-# End users who are looking for a ready-to-use solution with commercial
633-# garantees and support are strongly adviced to contract a Free Software
634-# Service Company
635-#
636-# This program is Free Software; you can redistribute it and/or
637-# modify it under the terms of the GNU General Public License
638-# as published by the Free Software Foundation; either version 2
639-# of the License, or (at your option) any later version.
640-#
641-# This program is distributed in the hope that it will be useful,
642-# but WITHOUT ANY WARRANTY; without even the implied warranty of
643-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
644-# GNU General Public License for more details.
645-#
646-# You should have received a copy of the GNU General Public License
647-# along with this program; if not, write to the Free Software
648-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
649-#
650-##############################################################################
651-
652-
653-from osv import osv
654-
655-
656-class AssociateInvoice(osv.osv_memory):
657- _inherit = 'associate.aal.to.invoice'
658-
659- def associate_aal(self, cr, uid, ids, context):
660- """ If the wizard is called from hr.analytic.timesheet (inherits account.analytic.line)
661- We get the account.analytic.line ids and call the wizard with them """
662- if context.get('active_model', False) == 'hr.analytic.timesheet':
663- at_obj = self.pool.get('hr.analytic.timesheet')
664- at_ids = context.get('active_ids', False)
665- aal_ids = [at.line_id.id for at in at_obj.browse(cr, uid, at_ids, context)]
666- context['active_ids'] = aal_ids
667-
668- return super(AssociateInvoice, self).associate_aal(cr, uid, ids, context)
669-
670-AssociateInvoice()
671
672=== removed file 'hr_timesheet_task/wizard/dissociate_analytic_timesheet.py'
673--- hr_timesheet_task/wizard/dissociate_analytic_timesheet.py 2011-08-12 12:53:16 +0000
674+++ hr_timesheet_task/wizard/dissociate_analytic_timesheet.py 1970-01-01 00:00:00 +0000
675@@ -1,47 +0,0 @@
676-# -*- coding: utf-8 -*-
677-##############################################################################
678-#
679-# Author Guewen Baconnier. Copyright Camptocamp SA
680-#
681-##############################################################################
682-# WARNING: This program as such is intended to be used by professional
683-# programmers who take the whole responsability of assessing all potential
684-# consequences resulting from its eventual inadequacies and bugs
685-# End users who are looking for a ready-to-use solution with commercial
686-# garantees and support are strongly adviced to contract a Free Software
687-# Service Company
688-#
689-# This program is Free Software; you can redistribute it and/or
690-# modify it under the terms of the GNU General Public License
691-# as published by the Free Software Foundation; either version 2
692-# of the License, or (at your option) any later version.
693-#
694-# This program is distributed in the hope that it will be useful,
695-# but WITHOUT ANY WARRANTY; without even the implied warranty of
696-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
697-# GNU General Public License for more details.
698-#
699-# You should have received a copy of the GNU General Public License
700-# along with this program; if not, write to the Free Software
701-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
702-#
703-##############################################################################
704-
705-
706-from osv import osv
707-
708-
709-class DissociateInvoice(osv.osv_memory):
710- _inherit = 'dissociate.aal.to.invoice'
711-
712- def dissociate_aal(self, cr, uid, ids, context):
713- """ If the wizard is called from hr.analytic.timesheet (inherits account.analytic.line)
714- We get the account.analytic.line ids and call the wizard with them """
715- if context.get('active_model', False) == 'hr.analytic.timesheet':
716- at_obj = self.pool.get('hr.analytic.timesheet')
717- at_ids = context.get('active_ids', False)
718- aal_ids = [at.line_id.id for at in at_obj.browse(cr, uid, at_ids, context)]
719- context['active_ids'] = aal_ids
720- return super(DissociateInvoice, self).dissociate_aal(cr, uid, ids, context)
721-
722-DissociateInvoice()
723
724=== removed file 'hr_timesheet_task/wizard/hr_timesheet_invoice_create.py'
725--- hr_timesheet_task/wizard/hr_timesheet_invoice_create.py 2011-08-12 12:53:16 +0000
726+++ hr_timesheet_task/wizard/hr_timesheet_invoice_create.py 1970-01-01 00:00:00 +0000
727@@ -1,46 +0,0 @@
728-# -*- coding: utf-8 -*-
729-##############################################################################
730-#
731-# Author Guewen Baconnier. Copyright Camptocamp SA
732-#
733-##############################################################################
734-# WARNING: This program as such is intended to be used by professional
735-# programmers who take the whole responsability of assessing all potential
736-# consequences resulting from its eventual inadequacies and bugs
737-# End users who are looking for a ready-to-use solution with commercial
738-# garantees and support are strongly adviced to contract a Free Software
739-# Service Company
740-#
741-# This program is Free Software; you can redistribute it and/or
742-# modify it under the terms of the GNU General Public License
743-# as published by the Free Software Foundation; either version 2
744-# of the License, or (at your option) any later version.
745-#
746-# This program is distributed in the hope that it will be useful,
747-# but WITHOUT ANY WARRANTY; without even the implied warranty of
748-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
749-# GNU General Public License for more details.
750-#
751-# You should have received a copy of the GNU General Public License
752-# along with this program; if not, write to the Free Software
753-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
754-#
755-##############################################################################
756-
757-from osv import osv
758-
759-
760-class hr_timesheet_invoice_create(osv.osv_memory):
761- _inherit = 'hr.timesheet.invoice.create'
762-
763- def do_create(self, cr, uid, ids, context=None):
764- """ If the wizard is called from hr.analytic.timesheet (inherits account.analytic.line)
765- We get the account.analytic.line ids and call the wizard with them """
766- if context.get('active_model', False) == 'hr.analytic.timesheet':
767- at_obj = self.pool.get('hr.analytic.timesheet')
768- at_ids = context.get('active_ids', False)
769- aal_ids = [at.line_id.id for at in at_obj.browse(cr, uid, at_ids, context)]
770- context['active_ids'] = aal_ids
771- return super(hr_timesheet_invoice_create, self).do_create(cr, uid, ids, context)
772-
773-hr_timesheet_invoice_create()
774
775=== removed file 'hr_timesheet_task/wizard/wizard_actions.xml'
776--- hr_timesheet_task/wizard/wizard_actions.xml 2011-08-12 12:53:16 +0000
777+++ hr_timesheet_task/wizard/wizard_actions.xml 1970-01-01 00:00:00 +0000
778@@ -1,34 +0,0 @@
779-<?xml version="1.0" encoding="utf-8"?>
780-<openerp>
781-<data>
782-
783- <act_window name="Associate Analytic Lines"
784- res_model="associate.aal.to.invoice"
785- src_model="hr.analytic.timesheet"
786- key2="client_action_multi"
787- view_mode="form"
788- view_type="form"
789- target="new"
790- id="action_associate_at_invoice"/>
791-
792- <act_window name="Dissociate Analytic Lines"
793- res_model="dissociate.aal.to.invoice"
794- src_model="hr.analytic.timesheet"
795- key2="client_action_multi"
796- view_mode="form"
797- view_type="form"
798- target="new"
799- id="action_dissociate_at_invoice"/>
800-
801- <record model="ir.values" id="hr_analytic_timesheet_invoice_create_values">
802- <field name="model_id" ref="model_hr_analytic_timesheet" />
803- <field name="object" eval="1" />
804- <field name="name">Invoice analytic lines</field>
805- <field name="key2">client_action_multi</field>
806- <field name="value" eval="'ir.actions.act_window,' + str(ref('hr_timesheet_invoice.action_hr_timesheet_invoice_create'))" />
807- <field name="key">action</field>
808- <field name="model">hr.analytic.timesheet</field>
809- </record>
810-
811-</data>
812-</openerp>
813
814=== modified file 'timesheet_task/__init__.py'
815--- timesheet_task/__init__.py 2012-06-06 13:14:12 +0000
816+++ timesheet_task/__init__.py 2013-04-03 11:31:22 +0000
817@@ -1,29 +1,21 @@
818 # -*- coding: utf-8 -*-
819 ##############################################################################
820 #
821-# author Nicolas Bessi
822-# Copyright Camptocamp 2012
823-#
824-# WARNING: This program as such is intended to be used by professional
825-# programmers who take the whole responsability of assessing all potential
826-# consequences resulting from its eventual inadequacies and bugs
827-# End users who are looking for a ready-to-use solution with commercial
828-# garantees and support are strongly adviced to contract a Free Software
829-# Service Company
830-#
831-# This program is Free Software; you can redistribute it and/or
832-# modify it under the terms of the GNU General Public License
833-# as published by the Free Software Foundation; either version 2
834-# of the License, or (at your option) any later version.
835-#
836-# This program is distributed in the hope that it will be useful,
837-# but WITHOUT ANY WARRANTY; without even the implied warranty of
838-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
839-# GNU General Public License for more details.
840-#
841-# You should have received a copy of the GNU General Public License
842-# along with this program; if not, write to the Free Software
843-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
844+# Author: Nicolas Bessi
845+# Copyright 2013 Camptocamp SA
846+#
847+# This program is free software: you can redistribute it and/or modify
848+# it under the terms of the GNU Affero General Public License as
849+# published by the Free Software Foundation, either version 3 of the
850+# License, or (at your option) any later version.
851+#
852+# This program is distributed in the hope that it will be useful,
853+# but WITHOUT ANY WARRANTY; without even the implied warranty of
854+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
855+# GNU Affero General Public License for more details.
856+#
857+# You should have received a copy of the GNU Affero General Public License
858+# along with this program. If not, see <http://www.gnu.org/licenses/>.
859 #
860 ##############################################################################
861 from . import project_task
862\ No newline at end of file
863
864=== modified file 'timesheet_task/__openerp__.py'
865--- timesheet_task/__openerp__.py 2012-12-13 12:20:12 +0000
866+++ timesheet_task/__openerp__.py 2013-04-03 11:31:22 +0000
867@@ -2,7 +2,7 @@
868 ##############################################################################
869 #
870 # Author: Nicolas Bessi
871-# Copyright 2012 Camptocamp SA
872+# Copyright 2013 Camptocamp SA
873 #
874 # This program is free software: you can redistribute it and/or modify
875 # it under the terms of the GNU Affero General Public License as
876@@ -19,23 +19,22 @@
877 #
878 ##############################################################################
879 {'name' : 'Analytic Task',
880- 'version' : '0.1',
881+ 'version' : '0.2',
882 'author' : 'Camptocamp',
883- 'maintainer': 'Camptocamp',
884+ 'maintainer': 'Camptocamp - Acsone SA/NV',
885 'category': 'Human Resources',
886- 'complexity': "normal", #easy, normal, expert
887- 'depends' : ['hr_timesheet', 'project', 'hr_timesheet_invoice'],
888+ 'depends' : ['project', 'hr_timesheet_invoice'],
889 'description': """Replace project.task.work items linked to task
890 with hr.analytic.timesheet""",
891 'website': 'http://www.camptocamp.com',
892- 'init_xml': [],
893- 'update_xml': ['project_task_view.xml'],
894- 'demo_xml': [],
895- 'tests': [],
896- 'installable': False,
897+ 'data': ['project_task_view.xml'],
898+ 'demo': [],
899+ 'test': [],
900+ 'installable': True,
901 'images' : [],
902 'auto_install': False,
903 'license': 'AGPL-3',
904- 'application': True}
905- #'icon': '/MODULE_NAME/static/src/images/XXX.png',
906-
907\ No newline at end of file
908+ 'application': True,
909+}
910+
911+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
912
913=== added directory 'timesheet_task/i18n'
914=== added file 'timesheet_task/i18n/fr.po'
915--- timesheet_task/i18n/fr.po 1970-01-01 00:00:00 +0000
916+++ timesheet_task/i18n/fr.po 2013-04-03 11:31:22 +0000
917@@ -0,0 +1,53 @@
918+# Translation of OpenERP Server.
919+# This file contains the translation of the following modules:
920+# * timesheet_task
921+#
922+msgid ""
923+msgstr ""
924+"Project-Id-Version: OpenERP Server 7.0\n"
925+"Report-Msgid-Bugs-To: \n"
926+"POT-Creation-Date: 2013-03-28 15:26+0000\n"
927+"PO-Revision-Date: 2013-03-28 15:26+0000\n"
928+"Last-Translator: <>\n"
929+"Language-Team: \n"
930+"MIME-Version: 1.0\n"
931+"Content-Type: text/plain; charset=UTF-8\n"
932+"Content-Transfer-Encoding: \n"
933+"Plural-Forms: \n"
934+
935+#. module: timesheet_task
936+#: field:account.analytic.line,task_id:0
937+#: model:ir.model,name:timesheet_task.model_project_task
938+msgid "Task"
939+msgstr "Tâche"
940+
941+#. module: timesheet_task
942+#: model:ir.model,name:timesheet_task.model_account_analytic_line
943+msgid "Analytic Line"
944+msgstr "Ligne analytique"
945+
946+#. module: timesheet_task
947+#: view:project.task:0
948+msgid "Total time"
949+msgstr "Temps total"
950+
951+#. module: timesheet_task
952+#: view:project.task:0
953+msgid "Task Work"
954+msgstr "Travail effectué"
955+
956+#. module: timesheet_task
957+#: field:project.task,timesheet_ids:0
958+msgid "Work done"
959+msgstr "Travail effectué"
960+
961+#. module: timesheet_task
962+#: model:ir.model,name:timesheet_task.model_hr_analytic_timesheet
963+msgid "Timesheet Line"
964+msgstr "Ligne de prestation"
965+
966+#. module: timesheet_task
967+#: view:project.task:0
968+msgid "Total cost"
969+msgstr "Coût total"
970+
971
972=== modified file 'timesheet_task/project_task.py'
973--- timesheet_task/project_task.py 2012-10-26 13:01:39 +0000
974+++ timesheet_task/project_task.py 2013-04-03 11:31:22 +0000
975@@ -1,38 +1,30 @@
976 # -*- coding: utf-8 -*-
977 ##############################################################################
978 #
979-# author Nicolas Bessi
980-# Copyright Camptocamp 2012
981-#
982-# WARNING: This program as such is intended to be used by professional
983-# programmers who take the whole responsability of assessing all potential
984-# consequences resulting from its eventual inadequacies and bugs
985-# End users who are looking for a ready-to-use solution with commercial
986-# garantees and support are strongly adviced to contract a Free Software
987-# Service Company
988-#
989-# This program is Free Software; you can redistribute it and/or
990-# modify it under the terms of the GNU General Public License
991-# as published by the Free Software Foundation; either version 2
992-# of the License, or (at your option) any later version.
993-#
994-# This program is distributed in the hope that it will be useful,
995-# but WITHOUT ANY WARRANTY; without even the implied warranty of
996-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
997-# GNU General Public License for more details.
998-#
999-# You should have received a copy of the GNU General Public License
1000-# along with this program; if not, write to the Free Software
1001-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1002+# Author: Nicolas Bessi
1003+# Copyright 2013 Camptocamp SA
1004+#
1005+# This program is free software: you can redistribute it and/or modify
1006+# it under the terms of the GNU Affero General Public License as
1007+# published by the Free Software Foundation, either version 3 of the
1008+# License, or (at your option) any later version.
1009+#
1010+# This program is distributed in the hope that it will be useful,
1011+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1012+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1013+# GNU Affero General Public License for more details.
1014+#
1015+# You should have received a copy of the GNU Affero General Public License
1016+# along with this program. If not, see <http://www.gnu.org/licenses/>.
1017 #
1018 ##############################################################################
1019
1020-from osv import osv, fields
1021+from openerp.osv import orm, fields
1022
1023 TASK_WATCHERS = ['work_ids', 'remaining_hours', 'planned_hours']
1024-AA_WATCHERS = ['unit_amount', 'product_uom_id', 'account_id', 'to_invoice', 'task_id']
1025+TIMESHEET_WATCHERS = ['unit_amount', 'product_uom_id', 'account_id', 'to_invoice', 'task_id']
1026
1027-class ProjectTask(osv.osv):
1028+class ProjectTask(orm.Model):
1029 _inherit = "project.task"
1030 _name = "project.task"
1031
1032@@ -53,8 +45,8 @@
1033 res[task.id]['delay_hours'] = res[task.id]['total_hours'] - task.planned_hours
1034 res[task.id]['progress'] = 0.0
1035 if (task.remaining_hours + hours.get(task.id, 0.0)):
1036- res[task.id]['progress'] = round(min(100.0 * hours.get(task.id, 0.0) / res[task.id]['total_hours'], 99.99),2)
1037- if task.state in ('done','cancelled'):
1038+ res[task.id]['progress'] = round(min(100.0 * hours.get(task.id, 0.0) / res[task.id]['total_hours'], 99.99), 2)
1039+ if task.state in ('done', 'cancelled'):
1040 res[task.id]['progress'] = 100.0
1041 return res
1042
1043@@ -67,26 +59,27 @@
1044
1045
1046 _columns = {'work_ids': fields.one2many('hr.analytic.timesheet', 'task_id', 'Work done'),
1047+
1048
1049 'effective_hours': fields.function(_progress_rate, multi="progress", method=True, string='Time Spent',
1050 help="Sum of spent hours of all tasks related to this project and its child projects.",
1051- store = {'project.task': (lambda self, cr, uid, ids, c={}: ids, TASK_WATCHERS, 20),
1052- 'account.analytic.line': (_get_analytic_line, AA_WATCHERS, 20)}),
1053+ store={'project.task': (lambda self, cr, uid, ids, c={}: ids, TASK_WATCHERS, 20),
1054+ 'account.analytic.line': (_get_analytic_line, TIMESHEET_WATCHERS, 20)}),
1055
1056 'delay_hours': fields.function(_progress_rate, multi="progress", method=True, string='Deduced Hours',
1057 help="Sum of spent hours with invoice factor of all tasks related to this project and its child projects.",
1058- store = {'project.task': (lambda self, cr, uid, ids, c={}: ids, TASK_WATCHERS, 20),
1059- 'account.analytic.line': (_get_analytic_line, AA_WATCHERS, 20)}),
1060+ store={'project.task': (lambda self, cr, uid, ids, c={}: ids, TASK_WATCHERS, 20),
1061+ 'account.analytic.line': (_get_analytic_line, TIMESHEET_WATCHERS, 20)}),
1062
1063 'total_hours': fields.function(_progress_rate, multi="progress", method=True, string='Total Time',
1064 help="Sum of total hours of all tasks related to this project and its child projects.",
1065- store = {'project.task': (lambda self, cr, uid, ids, c={}: ids, TASK_WATCHERS, 20),
1066- 'account.analytic.line': (_get_analytic_line, AA_WATCHERS, 20)}),
1067+ store={'project.task': (lambda self, cr, uid, ids, c={}: ids, TASK_WATCHERS, 20),
1068+ 'account.analytic.line': (_get_analytic_line, TIMESHEET_WATCHERS, 20)}),
1069
1070 'progress': fields.function(_progress_rate, multi="progress", method=True, string='Progress', type='float', group_operator="avg",
1071 help="Percent of tasks closed according to the total of tasks todo.",
1072- store = {'project.task': (lambda self, cr, uid, ids, c={}: ids, TASK_WATCHERS, 20),
1073- 'account.analytic.line': (_get_analytic_line, AA_WATCHERS, 20)})}
1074+ store={'project.task': (lambda self, cr, uid, ids, c={}: ids, TASK_WATCHERS, 20),
1075+ 'account.analytic.line': (_get_analytic_line, TIMESHEET_WATCHERS, 20)})}
1076
1077 def write(self, cr, uid, ids, vals, context=None):
1078 res = super(ProjectTask, self).write(cr, uid, ids, vals, context=context)
1079@@ -99,9 +92,7 @@
1080 ts_obj.write(cr, uid, [w.id for w in task.work_ids], {'account_id': account_id}, context=context)
1081 return res
1082
1083-ProjectTask()
1084-
1085-class HrAnalyticTimesheet(osv.osv):
1086+class HrAnalyticTimesheet(orm.Model):
1087 _inherit = "hr.analytic.timesheet"
1088 _name = "hr.analytic.timesheet"
1089
1090@@ -125,9 +116,7 @@
1091 res['value']['to_invoice'] = p.to_invoice.id
1092 return res
1093
1094-HrAnalyticTimesheet()
1095-
1096-class AccountAnalyticLine(osv.osv):
1097+class AccountAnalyticLine(orm.Model):
1098 """We add task_id on AA and manage update of linked task indicators"""
1099 _inherit = "account.analytic.line"
1100 _name = "account.analytic.line"
1101@@ -142,7 +131,7 @@
1102 return 0.0
1103 fact_obj = self.pool.get('hr_timesheet_invoice.factor')
1104 factor = 100.0 - float(fact_obj.browse(cr, uid, factor_id).factor)
1105- return (float(hours)/100.00)*factor
1106+ return (float(hours) / 100.00) * factor
1107
1108 def _set_remaining_hours_create(self, cr, uid, vals, context=None):
1109 if not vals.get('task_id'):
1110@@ -161,9 +150,9 @@
1111 for line in self.browse(cr, uid, ids):
1112 # in OpenERP if we set a value to nil vals become False
1113 old_task_id = line.task_id and line.task_id.id or None
1114- new_task_id = vals.get('task_id', old_task_id) #if no task_id in vals we assume it is equal to old
1115+ new_task_id = vals.get('task_id', old_task_id) # if no task_id in vals we assume it is equal to old
1116
1117- #we look if value has changed
1118+ # we look if value has changed
1119 if (new_task_id != old_task_id) and old_task_id:
1120 self._set_remaining_hours_unlink(cr, uid, [line.id], context)
1121 if new_task_id:
1122@@ -205,14 +194,12 @@
1123 def create(self, cr, uid, vals, context=None):
1124 if vals.get('task_id'):
1125 self._set_remaining_hours_create(cr, uid, vals, context)
1126- return super(AccountAnalyticLine,self).create(cr, uid, vals, context=context)
1127+ return super(AccountAnalyticLine, self).create(cr, uid, vals, context=context)
1128
1129 def write(self, cr, uid, ids, vals, context=None):
1130- self. _set_remaining_hours_write(cr, uid, ids, vals, context=context)
1131+ self._set_remaining_hours_write(cr, uid, ids, vals, context=context)
1132 return super(AccountAnalyticLine, self).write(cr, uid, ids, vals, context=context)
1133
1134 def unlink(self, cr, uid, ids, context=None):
1135 self._set_remaining_hours_unlink(cr, uid, ids, context)
1136 return super(AccountAnalyticLine, self).unlink(cr, uid, ids, context=context)
1137-
1138-AccountAnalyticLine()
1139
1140=== modified file 'timesheet_task/project_task_view.xml'
1141--- timesheet_task/project_task_view.xml 2012-06-06 13:14:12 +0000
1142+++ timesheet_task/project_task_view.xml 2013-04-03 11:31:22 +0000
1143@@ -1,46 +1,212 @@
1144 <openerp>
1145 <data>
1146- #---------------------------------------------------------------------------------------------------------
1147- # Adapt task views
1148- #---------------------------------------------------------------------------------------------------------
1149- <record id="view_task_form2" model="ir.ui.view">
1150+
1151+ #---------------------------------------------------------------------------------------------------------
1152+ # Adapt task views
1153+ #---------------------------------------------------------------------------------------------------------
1154+ <!-- Replace the view project.view_task_form2 instead of inheriting
1155+ it and set a low priority. This replacement is to avoid the following error:
1156+
1157+ ERROR timesheet openerp.osv.orm: Can't find field 'hours' in the following view parts
1158+ composing the view of object model 'project.task':
1159+ * project.task.form
1160+
1161+ Either you wrongly customized this view, or some modules bringing those views are not
1162+ compatible with your current data model ERROR timesheet openerp.addons.base.ir.ir_ui_view:
1163+ Can't render view for model: project.task -->
1164+
1165+ <record id="project.view_task_form2" model="ir.ui.view">
1166 <field name="name">project.task.form</field>
1167 <field name="model">project.task</field>
1168- <field name="inherit_id" ref="project.view_task_form2"/>
1169- <field name="type">form</field>
1170+ <field eval="1" name="priority" />
1171 <field name="arch" type="xml">
1172- <xpath expr="/form/notebook/page/field[@name='work_ids']" position="replace">
1173- <field colspan="4" name="work_ids" nolabel="1" attrs="{'invisible':[('state','in',['draft'])],'readonly':[('state','=','done')]}">
1174- <tree string="Task Work" editable="top">
1175- <field name="user_id" on_change="on_change_user_id(user_id)" required="1" invisible="1"/>
1176- <field name="name"/>
1177- <field name="unit_amount" on_change="on_change_unit_amount(product_id, unit_amount, False, product_uom_id,journal_id, parent.id, to_invoice)" sum="Total time" widget="float_time"/>
1178- <field name="date" on_change="on_change_date(date)"/>
1179- <field name="journal_id" invisible="1"/>
1180- <field domain="[('type','=','normal')]" name="account_id" invisible="1"/>
1181- <field name="product_id" on_change="on_change_unit_amount(product_id, unit_amount, False, product_uom_id,journal_id, parent.id, to_invoice)" required="1" domain="[('type','=','service')]" invisible="1"/>
1182- <field name="product_uom_id" on_change="on_change_unit_amount(product_id, unit_amount, False, product_uom_id,journal_id, parent.id, to_invoice)" invisible="1"/>
1183- <field name="amount" sum="Total cost" invisible="1"/>
1184- <field name="general_account_id" invisible="1"/>
1185- <field name="to_invoice" />
1186- </tree>
1187- <form string="Task Work" editable="top">
1188- <field name="user_id" on_change="on_change_user_id(user_id)" required="1"/>
1189- <field name="name" default_focus="1"/>
1190- <field name="unit_amount" on_change="on_change_unit_amount(product_id, unit_amount, False, product_uom_id,journal_id, parent.id, to_invoice)" sum="Total time" widget="float_time"/>
1191- <field name="date" on_change="on_change_date(date)"/>
1192- <field name="journal_id" invisible="1"/>
1193- <field domain="[('type','=','normal')]" name="account_id" invisible="1"/>
1194- <field name="product_id" on_change="on_change_unit_amount(product_id, unit_amount, False, product_uom_id,journal_id, parent.id, to_invoice)" required="1" domain="[('type','=','service')]" invisible="1"/>
1195- <field name="product_uom_id" on_change="on_change_unit_amount(product_id, unit_amount, False, product_uom_id,journal_id, parent.id, to_invoice)" invisible="1"/>
1196- <field name="amount" sum="Total cost" invisible="1"/>
1197- <field name="general_account_id" invisible="1"/>
1198- <field name="to_invoice" />
1199- </form>
1200- </field>
1201- </xpath>
1202+ <form string="Project" version="7.0">
1203+ <header>
1204+ <!-- <button name="do_open" string="Start Task" type="object"
1205+ states="draft,pending" class="oe_highlight"/> <button name="do_draft" string="Draft"
1206+ type="object" states="cancel,done"/> -->
1207+ <button name="project_task_reevaluate"
1208+ string="Reactivate" type="object" states="cancelled,done"
1209+ context="{'button_reactivate':True}" groups="base.group_user" />
1210+ <button name="action_close" string="Done"
1211+ type="object" states="draft,open,pending"
1212+ groups="base.group_user" />
1213+ <button name="do_cancel" string="Cancel Task"
1214+ type="object" states="draft,open,pending"
1215+ groups="base.group_user" />
1216+ <field name="stage_id" widget="statusbar"
1217+ clickable="True" />
1218+ </header>
1219+ <sheet string="Task">
1220+ <h1>
1221+ <field name="name" placeholder="Task summary..." />
1222+ </h1>
1223+ <group>
1224+ <group>
1225+ <field name="project_id"
1226+ on_change="onchange_project(project_id)"
1227+ context="{'default_use_tasks':1}" />
1228+ <field name="user_id"
1229+ attrs="{'readonly':[('state','in',['done', 'cancelled'])]}"
1230+ options='{"no_open": True}' />
1231+ <field name="planned_hours"
1232+ widget="float_time"
1233+ groups="project.group_time_work_estimation_tasks"
1234+ on_change="onchange_planned(planned_hours, effective_hours)" />
1235+ </group>
1236+ <group>
1237+ <field name="date_deadline"
1238+ attrs="{'readonly':[('state','in',['done', 'cancelled'])]}" />
1239+ <field name="categ_ids" widget="many2many_tags" />
1240+ <field name="progress" widget="progressbar"
1241+ groups="project.group_time_work_estimation_tasks"
1242+ attrs="{'invisible':[('state','=','cancelled')]}" />
1243+ </group>
1244+ </group>
1245+ <notebook>
1246+ <page string="Description">
1247+ <field name="description"
1248+ attrs="{'readonly':[('state','=','done')]}"
1249+ placeholder="Add a Description..." />
1250+ <field name="work_ids">
1251+ <tree string="Task Work"
1252+ editable="top">
1253+ <field name="user_id"
1254+ on_change="on_change_user_id(user_id)"
1255+ required="1" invisible="1" />
1256+ <field name="name" />
1257+ <field name="unit_amount"
1258+ on_change="on_change_unit_amount(product_id, unit_amount, False, product_uom_id,journal_id, parent.id, to_invoice)"
1259+ sum="Total time" widget="float_time" />
1260+ <field name="date"
1261+ on_change="on_change_date(date)" />
1262+ <field name="journal_id"
1263+ invisible="1" />
1264+ <field domain="[('type','=','normal')]"
1265+ name="account_id" invisible="1" />
1266+ <field name="product_id"
1267+ on_change="on_change_unit_amount(product_id, unit_amount, False, product_uom_id,journal_id, parent.id, to_invoice)"
1268+ required="1"
1269+ domain="[('type','=','service')]"
1270+ invisible="1" />
1271+ <field name="product_uom_id"
1272+ on_change="on_change_unit_amount(product_id, unit_amount, False, product_uom_id,journal_id, parent.id, to_invoice)"
1273+ invisible="1" />
1274+ <field name="amount" sum="Total cost"
1275+ invisible="1" />
1276+ <field name="general_account_id"
1277+ invisible="1" />
1278+ <field name="to_invoice" />
1279+ </tree>
1280+ <form string="Task Work"
1281+ editable="top">
1282+ <field name="user_id"
1283+ on_change="on_change_user_id(user_id)"
1284+ required="1" />
1285+ <field name="name"
1286+ default_focus="1" />
1287+ <field name="unit_amount"
1288+ on_change="on_change_unit_amount(product_id, unit_amount, False, product_uom_id,journal_id, parent.id, to_invoice)"
1289+ sum="Total time" widget="float_time" />
1290+ <field name="date"
1291+ on_change="on_change_date(date)" />
1292+ <field name="journal_id"
1293+ invisible="1" />
1294+ <field domain="[('type','=','normal')]"
1295+ name="account_id" invisible="1" />
1296+ <field name="product_id"
1297+ on_change="on_change_unit_amount(product_id, unit_amount, False, product_uom_id,journal_id, parent.id, to_invoice)"
1298+ required="1"
1299+ domain="[('type','=','service')]"
1300+ invisible="1" />
1301+ <field name="product_uom_id"
1302+ on_change="on_change_unit_amount(product_id, unit_amount, False, product_uom_id,journal_id, parent.id, to_invoice)"
1303+ invisible="1" />
1304+ <field name="amount" sum="Total cost"
1305+ invisible="1" />
1306+ <field name="general_account_id"
1307+ invisible="1" />
1308+ <field name="to_invoice" />
1309+ </form>
1310+ </field>
1311+ <group>
1312+ <group class="oe_subtotal_footer oe_right"
1313+ name="project_hours"
1314+ groups="project.group_time_work_estimation_tasks">
1315+ <field name="effective_hours"
1316+ widget="float_time" />
1317+ <label for="remaining_hours"
1318+ string="Remaining"
1319+ groups="project.group_time_work_estimation_tasks" />
1320+ <div>
1321+ <field name="remaining_hours"
1322+ widget="float_time"
1323+ attrs="{'readonly':[('state','in',('done','cancelled'))]}"
1324+ groups="project.group_time_work_estimation_tasks" />
1325+ </div>
1326+ <field name="total_hours"
1327+ widget="float_time"
1328+ class="oe_subtotal_footer_separator" />
1329+ </group>
1330+ </group>
1331+ <div class="oe_clear" />
1332+ </page>
1333+ <page string="Delegation"
1334+ groups="project.group_delegate_task">
1335+ <button
1336+ name="%(project.action_project_task_delegate)d"
1337+ string="Delegate" type="action"
1338+ states="pending,open,draft" groups="project.group_delegate_task" />
1339+ <separator string="Parent Tasks" />
1340+ <field name="parent_ids" />
1341+ <separator string="Delegated tasks" />
1342+ <field name="child_ids">
1343+ <tree string="Delegated tasks">
1344+ <field name="name" />
1345+ <field name="user_id" />
1346+ <field name="stage_id" />
1347+ <field name="state"
1348+ invisible="1" />
1349+ <field name="effective_hours"
1350+ widget="float_time" />
1351+ <field name="progress"
1352+ widget="progressbar" />
1353+ <field name="remaining_hours"
1354+ widget="float_time" />
1355+ <field name="date_deadline" />
1356+ </tree>
1357+ </field>
1358+ </page>
1359+ <page string="Extra Info"
1360+ attrs="{'readonly':[('state','=','done')]}">
1361+ <group col="4">
1362+ <field name="priority" groups="base.group_user" />
1363+ <field name="sequence" />
1364+ <field name="partner_id" />
1365+ <field name="state" invisible="1" />
1366+ <field name="company_id"
1367+ groups="base.group_multi_company"
1368+ widget="selection" />
1369+ </group>
1370+ <group>
1371+ <group string="Gantt View">
1372+ <field name="date_start" />
1373+ <field name="date_end" />
1374+ </group>
1375+ <group>
1376+ </group>
1377+ </group>
1378+ </page>
1379+ </notebook>
1380+ </sheet>
1381+ <div class="oe_chatter">
1382+ <field name="message_follower_ids" widget="mail_followers"
1383+ groups="base.group_user" />
1384+ <field name="message_ids" widget="mail_thread" />
1385+ </div>
1386+ </form>
1387 </field>
1388 </record>
1389-
1390+
1391 </data>
1392 </openerp>
1393\ No newline at end of file
1394
1395=== removed file 'timesheet_task/tmp_file_for_project_indicator.py'
1396--- timesheet_task/tmp_file_for_project_indicator.py 2012-06-06 13:14:12 +0000
1397+++ timesheet_task/tmp_file_for_project_indicator.py 1970-01-01 00:00:00 +0000
1398@@ -1,29 +0,0 @@
1399-def _progress_rate(self, cr, uid, ids, names, arg, context=None):
1400- """As OpenERP SA made a query for this function field (perf. reason obviously),
1401- I must overide it all."""
1402- result = {}.fromkeys(ids, 0.0)
1403- progress = {}
1404- if not ids:
1405- return res
1406- cr.execute('''SELECT project_id,
1407- sum(planned_hours) as sum_planned_hours,
1408- sum(total_hours) as sum_total_hours,
1409- sum(effective_hours) as sum_effective_hours,
1410- sum(remaining_hours) as remaining_hours,
1411- sum(deduced_hours) as deduced_hours
1412- FROM project_task
1413- WHERE project_id in %s
1414- AND state<>'cancelled'
1415- GROUP BY project_id''', (tuple(ids),))
1416-
1417- res = cr.dictfetchall()
1418- for stat in res:
1419- project = self.browse(cr, uid, res['project_id'], context=context)
1420- progr = (stat['sum_planned_hours'] and
1421- round(100.0 * stat['sum_total_hours'] / stat['sum_planned_hours'], 2) or 0.0),
1422- result[project.id] = {'planned_hours': stat['sum_planned_hours'],
1423- 'effective_hours': stat['sum_effective_hours'],
1424- 'total_hours': stat['sum_total_hours'],
1425- 'progress_rate': progr,
1426- 'deduced_hours': stat['sum_deduced_hours']}
1427- return res
1428\ No newline at end of file