Merge lp:~camptocamp/hr-timesheet/add-test-for-task-project-indicators-jge into lp:~hr-core-editors/hr-timesheet/7.0

Proposed by Nicolas Bessi - Camptocamp
Status: Merged
Merged at revision: 56
Proposed branch: lp:~camptocamp/hr-timesheet/add-test-for-task-project-indicators-jge
Merge into: lp:~hr-core-editors/hr-timesheet/7.0
Diff against target: 568 lines (+370/-69)
3 files modified
timesheet_task/__openerp__.py (+16/-5)
timesheet_task/project_task.py (+72/-64)
timesheet_task/test/task_timesheet_indicators.yml (+282/-0)
To merge this branch: bzr merge lp:~camptocamp/hr-timesheet/add-test-for-task-project-indicators-jge
Reviewer Review Type Date Requested Status
Guewen Baconnier @ Camptocamp code review Approve
Joël Grand-Guillaume @ camptocamp code review + tests Approve
Review via email: mp+186816@code.launchpad.net

Commit message

[IMP] in timesheet_task module:
    Fix propagation of indicator at project level when aa/timesheet line are altered
    Fix remaining_hours when a task is added on aa line without task

Add YAML tests
Improve tooltips of indicators

Description of the change

[IMP] in timesheet_task module:
    Fix propagation of indicator at project level when aa/timesheet line are altered
    Fix remaining_hours when a task is added on aa line without task

Add YAML tests
Improve tooltips of indicators

Please feel free to correct english.

To post a comment you must log in.
69. By Nicolas Bessi - Camptocamp

[REVERT] wrongly merged revisions

70. By Nicolas Bessi - Camptocamp

[FIX] comment english

Revision history for this message
Joël Grand-Guillaume @ camptocamp (jgrandguillaume-c2c) wrote :

LGTM, Thanks

review: Approve (code review + tests)
71. By Guewen Baconnier @ Camptocamp

[IMP] description in manifest, some typos and layout

72. By Guewen Baconnier @ Camptocamp

[FIX] no mutable in args

73. By Guewen Baconnier @ Camptocamp

[FIX] alignment

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

Pushed some nitpicker's changes.
LGTM, thanks

review: Approve (code review)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'timesheet_task/__openerp__.py'
--- timesheet_task/__openerp__.py 2013-04-03 11:20:21 +0000
+++ timesheet_task/__openerp__.py 2013-10-08 11:06:42 +0000
@@ -18,18 +18,29 @@
18# along with this program. If not, see <http://www.gnu.org/licenses/>.18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19#19#
20##############################################################################20##############################################################################
21{'name' : 'Analytic Task',21{'name' : 'Analytic Timesheet In Task',
22 'version' : '0.2',22 'version' : '0.2',
23 'author' : 'Camptocamp',23 'author' : 'Camptocamp',
24 'maintainer': 'Camptocamp - Acsone SA/NV',24 'maintainer': 'Camptocamp, Acsone SA/NV',
25 'category': 'Human Resources',25 'category': 'Human Resources',
26 'depends' : ['project', 'hr_timesheet_invoice'],26 'depends' : ['project', 'hr_timesheet_invoice'],
27 'description': """Replace project.task.work items linked to task27 'description': """
28 with hr.analytic.timesheet""",28Replace task work items (project.task.work) linked to task with
29timesheet lines (hr.analytic.timesheet).
30
31Unless the module project_timesheet, it allows to have only one single
32object that handles and records time spent by employees, making more
33coherence for the end user. This way, time entered through timesheet
34lines or tasks is the same. As long as a timesheet lines has an
35associated task, it will compute the related indicators.
36
37Used with the module hr_timesheet_task, it also allows users to complete
38task information through the timesheet sheet (hr.timesheet.sheet).
39 """,
29 'website': 'http://www.camptocamp.com',40 'website': 'http://www.camptocamp.com',
30 'data': ['project_task_view.xml'],41 'data': ['project_task_view.xml'],
31 'demo': [],42 'demo': [],
32 'test': [],43 'test': ['test/task_timesheet_indicators.yml'],
33 'installable': True,44 'installable': True,
34 'images' : [],45 'images' : [],
35 'auto_install': False,46 'auto_install': False,
3647
=== modified file 'timesheet_task/project_task.py'
--- timesheet_task/project_task.py 2013-08-14 15:05:12 +0000
+++ timesheet_task/project_task.py 2013-10-08 11:06:42 +0000
@@ -20,23 +20,23 @@
20##############################################################################20##############################################################################
2121
22from openerp.osv import orm, fields22from openerp.osv import orm, fields
23from openerp import SUPERUSER_ID
2324
24TASK_WATCHERS = ['work_ids', 'remaining_hours', 'planned_hours']25TASK_WATCHERS = ['work_ids', 'remaining_hours', 'effective_hours', 'planned_hours']
25TIMESHEET_WATCHERS = ['unit_amount', 'product_uom_id', 'account_id', 'to_invoice', 'task_id']26TIMESHEET_WATCHERS = ['unit_amount', 'product_uom_id', 'account_id', 'task_id']
2627
27class ProjectTask(orm.Model):28class ProjectTask(orm.Model):
28 _inherit = "project.task"29 _inherit = "project.task"
29 _name = "project.task"30 _name = "project.task"
3031
31
32 def _progress_rate(self, cr, uid, ids, names, arg, context=None):32 def _progress_rate(self, cr, uid, ids, names, arg, context=None):
33 """TODO improve code taken for OpenERP"""33 """TODO improve code taken for OpenERP"""
34 res = {}34 res = {}
35 cr.execute("""SELECT task_id, COALESCE(SUM(unit_amount),0) 35 cr.execute("""SELECT task_id, COALESCE(SUM(unit_amount),0)
36 FROM account_analytic_line 36 FROM account_analytic_line
37 WHERE task_id IN %s 37 WHERE task_id IN %s
38 GROUP BY task_id""", (tuple(ids),))38 GROUP BY task_id""", (tuple(ids),))
39 39
40 hours = dict(cr.fetchall())40 hours = dict(cr.fetchall())
41 for task in self.browse(cr, uid, ids, context=context):41 for task in self.browse(cr, uid, ids, context=context):
42 res[task.id] = {}42 res[task.id] = {}
@@ -51,47 +51,59 @@
51 return res51 return res
5252
5353
54 def _store_set_values(self, cr, uid, ids, fields, context=None):
55 # Hack to avoid redefining most of function fields of project.project model
56 # This is mainly due to the fact that orm _store_set_values use direct access to database.
57 # So when modifiy aa line the _store_set_values as it uses cursor directly to update tasks
58 # project triggers on task are not called
59 res = super(ProjectTask, self)._store_set_values(cr, uid, ids, fields, context=context)
60 for row in self.browse(cr, SUPERUSER_ID, ids, context=context):
61 project = row.project_id
62 project.write({'parent_id': project.parent_id.id})
63 return res
64
65
54 def _get_analytic_line(self, cr, uid, ids, context=None):66 def _get_analytic_line(self, cr, uid, ids, context=None):
55 result = []67 result = []
56 for aal in self.pool.get('account.analytic.line').browse(cr, uid, ids, context=context):68 for aal in self.pool.get('account.analytic.line').browse(cr, uid, ids, context=context):
57 if aal.task_id: result.append(aal.task_id.id)69 if aal.task_id: result.append(aal.task_id.id)
58 return result70 return result
5971
6072 _columns = {
61 _columns = {'work_ids': fields.one2many('hr.analytic.timesheet', 'task_id', 'Work done'),73 'work_ids': fields.one2many('hr.analytic.timesheet', 'task_id', 'Work done'),
62 74 'effective_hours': fields.function(_progress_rate, multi="progress", string='Time Spent',
6375 help="Computed using the sum of the task work done (timesheet lines "
64 'effective_hours': fields.function(_progress_rate, multi="progress", string='Time Spent',76 "associated on this task).",
65 help="Sum of spent hours of all tasks related to this project and its child projects.",77 store={'project.task': (lambda self, cr, uid, ids, c=None: ids, TASK_WATCHERS, 20),
66 store={'project.task': (lambda self, cr, uid, ids, c={}: ids, TASK_WATCHERS, 20),78 'account.analytic.line': (_get_analytic_line, TIMESHEET_WATCHERS, 20)}),
67 'account.analytic.line': (_get_analytic_line, TIMESHEET_WATCHERS, 20)}),79 'delay_hours': fields.function(_progress_rate, multi="progress", string='Deduced Hours',
6880 help="Computed as difference between planned hours by the project manager "
69 'delay_hours': fields.function(_progress_rate, multi="progress", string='Deduced Hours',81 "and the total hours of the task.",
70 help="Sum of spent hours with invoice factor of all tasks related to this project and its child projects.",82 store={'project.task': (lambda self, cr, uid, ids, c=None: ids, TASK_WATCHERS, 20),
71 store={'project.task': (lambda self, cr, uid, ids, c={}: ids, TASK_WATCHERS, 20),83 'account.analytic.line': (_get_analytic_line, TIMESHEET_WATCHERS, 20)}),
72 'account.analytic.line': (_get_analytic_line, TIMESHEET_WATCHERS, 20)}),84 'total_hours': fields.function(_progress_rate, multi="progress", string='Total Time',
7385 help="Computed as: Time Spent + Remaining Time.",
74 'total_hours': fields.function(_progress_rate, multi="progress", string='Total Time',86 store={'project.task': (lambda self, cr, uid, ids, c=None: ids, TASK_WATCHERS, 20),
75 help="Sum of total hours of all tasks related to this project and its child projects.",87 'account.analytic.line': (_get_analytic_line, TIMESHEET_WATCHERS, 20)}),
76 store={'project.task': (lambda self, cr, uid, ids, c={}: ids, TASK_WATCHERS, 20),88 'progress': fields.function(_progress_rate, multi="progress", string='Progress', type='float', group_operator="avg",
77 'account.analytic.line': (_get_analytic_line, TIMESHEET_WATCHERS, 20)}),89 help="If the task has a progress of 99.99% you should close the task if it's "
7890 "finished or reevaluate the time",
79 'progress': fields.function(_progress_rate, multi="progress", string='Progress', type='float', group_operator="avg",91 store={'project.task': (lambda self, cr, uid, ids, c=None: ids, TASK_WATCHERS, 20),
80 help="Percent of tasks closed according to the total of tasks todo.",92 'account.analytic.line': (_get_analytic_line, TIMESHEET_WATCHERS, 20)})
81 store={'project.task': (lambda self, cr, uid, ids, c={}: ids, TASK_WATCHERS, 20),93 }
82 'account.analytic.line': (_get_analytic_line, TIMESHEET_WATCHERS, 20)})}94
83
84 def write(self, cr, uid, ids, vals, context=None):95 def write(self, cr, uid, ids, vals, context=None):
85 res = super(ProjectTask, self).write(cr, uid, ids, vals, context=context)96 res = super(ProjectTask, self).write(cr, uid, ids, vals, context=context)
86 if vals.get('project_id'):97 if vals.get('project_id'):
87 ts_obj = self.pool.get('hr.analytic.timesheet')98 ts_obj = self.pool.get('hr.analytic.timesheet')
88 project_obj = self.pool.get('project.project')99 project_obj = self.pool.get('project.project')
89 project = project_obj.browse(cr, uid, vals['project_id'], context)100 project = project_obj.browse(cr, uid, vals['project_id'], context=context)
90 account_id = project.analytic_account_id.id101 account_id = project.analytic_account_id.id
91 for task in self.browse(cr, uid, ids, context=context):102 for task in self.browse(cr, uid, ids, context=context):
92 ts_obj.write(cr, uid, [w.id for w in task.work_ids], {'account_id': account_id}, context=context)103 ts_obj.write(cr, uid, [w.id for w in task.work_ids], {'account_id': account_id}, context=context)
93 return res104 return res
94105
106
95class HrAnalyticTimesheet(orm.Model):107class HrAnalyticTimesheet(orm.Model):
96 """108 """
97 Add field:109 Add field:
@@ -123,7 +135,8 @@
123 _name = "hr.analytic.timesheet"135 _name = "hr.analytic.timesheet"
124136
125 def on_change_unit_amount(self, cr, uid, sheet_id, prod_id, unit_amount, company_id,137 def on_change_unit_amount(self, cr, uid, sheet_id, prod_id, unit_amount, company_id,
126 unit=False, journal_id=False, task_id=False, to_invoice=False, context=None):138 unit=False, journal_id=False, task_id=False, to_invoice=False,
139 context=None):
127 res = super(HrAnalyticTimesheet, self).on_change_unit_amount(cr,140 res = super(HrAnalyticTimesheet, self).on_change_unit_amount(cr,
128 uid,141 uid,
129 sheet_id,142 sheet_id,
@@ -149,16 +162,17 @@
149 return dict.fromkeys(ids, False)162 return dict.fromkeys(ids, False)
150163
151 _columns = {164 _columns = {
152 'hr_analytic_timesheet_id': fields.function(_get_dummy_hr_analytic_timesheet_id, string='Related Timeline Id', type='boolean')165 'hr_analytic_timesheet_id': fields.function(_get_dummy_hr_analytic_timesheet_id,
166 string='Related Timeline Id',
167 type='boolean')
153 }168 }
154169
170
155class AccountAnalyticLine(orm.Model):171class AccountAnalyticLine(orm.Model):
156 """We add task_id on AA and manage update of linked task indicators"""172 """We add task_id on AA and manage update of linked task indicators"""
157 _inherit = "account.analytic.line"173 _inherit = "account.analytic.line"
158 _name = "account.analytic.line"174 _name = "account.analytic.line"
159175
160
161
162 _columns = {'task_id': fields.many2one('project.task', 'Task')}176 _columns = {'task_id': fields.many2one('project.task', 'Task')}
163177
164 def _check_task_project(self, cr, uid, ids):178 def _check_task_project(self, cr, uid, ids):
@@ -172,22 +186,22 @@
172 (_check_task_project, 'Error! Task must belong to the project.', ['task_id','account_id']),186 (_check_task_project, 'Error! Task must belong to the project.', ['task_id','account_id']),
173 ]187 ]
174188
175 def _compute_hours_with_factor(self, cr, uid, hours, factor_id, context=None):189
176 if not hours or not factor_id:190 def _trigger_projects(self, cr, uid, task_ids, context=None):
177 return 0.0191 t_obj = self.pool['project.task']
178 fact_obj = self.pool.get('hr_timesheet_invoice.factor')192 for task in t_obj.browse(cr, SUPERUSER_ID, task_ids, context=context):
179 factor = 100.0 - float(fact_obj.browse(cr, uid, factor_id).factor)193 project = task.project_id
180 return (float(hours) / 100.00) * factor194 project.write({'parent_id': project.parent_id.id})
195 return task_ids
181196
182 def _set_remaining_hours_create(self, cr, uid, vals, context=None):197 def _set_remaining_hours_create(self, cr, uid, vals, context=None):
183 if not vals.get('task_id'):198 if not vals.get('task_id'):
184 return199 return
185 hours = vals.get('unit_amount', 0.0)200 hours = vals.get('unit_amount', 0.0)
186 factor_id = vals.get('to_invoice')201 # We can not do a write else we will have a recursion error
187 comp_hours = self._compute_hours_with_factor(cr, uid, hours, factor_id, context)202 cr.execute('update project_task set remaining_hours=remaining_hours - %s where id=%s',
188 if comp_hours:203 (hours, vals['task_id']))
189 cr.execute('update project_task set remaining_hours=remaining_hours - %s where id=%s',204 self._trigger_projects(cr, uid, [vals['task_id']], context=context)
190 (comp_hours, vals['task_id']))
191 return vals205 return vals
192206
193 def _set_remaining_hours_write(self, cr, uid, ids, vals, context=None):207 def _set_remaining_hours_write(self, cr, uid, ids, vals, context=None):
@@ -196,8 +210,8 @@
196 for line in self.browse(cr, uid, ids):210 for line in self.browse(cr, uid, ids):
197 # in OpenERP if we set a value to nil vals become False211 # in OpenERP if we set a value to nil vals become False
198 old_task_id = line.task_id and line.task_id.id or None212 old_task_id = line.task_id and line.task_id.id or None
199 new_task_id = vals.get('task_id', old_task_id) # if no task_id in vals we assume it is equal to old213 # if no task_id in vals we assume it is equal to old
200214 new_task_id = vals.get('task_id', old_task_id)
201 # we look if value has changed215 # we look if value has changed
202 if (new_task_id != old_task_id) and old_task_id:216 if (new_task_id != old_task_id) and old_task_id:
203 self._set_remaining_hours_unlink(cr, uid, [line.id], context)217 self._set_remaining_hours_unlink(cr, uid, [line.id], context)
@@ -207,20 +221,19 @@
207 line.to_invoice and line.to_invoice.id or False),221 line.to_invoice and line.to_invoice.id or False),
208 'unit_amount': vals.get('unit_amount', line.unit_amount)}222 'unit_amount': vals.get('unit_amount', line.unit_amount)}
209 self._set_remaining_hours_create(cr, uid, data, context)223 self._set_remaining_hours_create(cr, uid, data, context)
224 self._trigger_projects(cr, uid, list(set([old_task_id, new_task_id])),
225 context=context)
210 return ids226 return ids
211 if new_task_id:227 if new_task_id:
212 hours = vals.get('unit_amount', line.unit_amount)228 hours = vals.get('unit_amount', line.unit_amount)
213 factor_id = vals.get('to_invoice', line.to_invoice and line.to_invoice.id or False)229 old_hours = line.unit_amount if old_task_id else 0.0
214 comp_hours = self._compute_hours_with_factor(cr, uid, hours, factor_id, context)230 # We can not do a write else we will have a recursion error
215 old_factor = line.to_invoice and line.to_invoice.id or False
216 old_comp_hours = self._compute_hours_with_factor(cr, uid, line.unit_amount,
217 old_factor, context)
218 # we always execute request because invoice factor can be set to gratis
219 cr.execute('update project_task set remaining_hours=remaining_hours - %s + (%s) where id=%s',231 cr.execute('update project_task set remaining_hours=remaining_hours - %s + (%s) where id=%s',
220 (comp_hours, old_comp_hours, new_task_id))232 (hours, old_hours, new_task_id))
233 self._trigger_projects(cr, uid, [new_task_id], context=context)
234
221 return ids235 return ids
222236
223
224 def _set_remaining_hours_unlink(self, cr, uid, ids, context=None):237 def _set_remaining_hours_unlink(self, cr, uid, ids, context=None):
225 if isinstance(ids, (int, long)):238 if isinstance(ids, (int, long)):
226 ids = [ids]239 ids = [ids]
@@ -228,15 +241,10 @@
228 if not line.task_id:241 if not line.task_id:
229 continue242 continue
230 hours = line.unit_amount or 0.0243 hours = line.unit_amount or 0.0
231 factor_id = line.to_invoice and line.to_invoice.id or False244 cr.execute('update project_task set remaining_hours=remaining_hours + %s where id=%s',
232 comp_hours = self._compute_hours_with_factor(cr, uid, hours, factor_id, context)245 (hours, line.task_id.id))
233 if comp_hours:
234 cr.execute('update project_task set remaining_hours=remaining_hours + %s where id=%s',
235 (comp_hours, line.task_id.id))
236 return ids246 return ids
237247
238
239
240 def create(self, cr, uid, vals, context=None):248 def create(self, cr, uid, vals, context=None):
241 if vals.get('task_id'):249 if vals.get('task_id'):
242 self._set_remaining_hours_create(cr, uid, vals, context)250 self._set_remaining_hours_create(cr, uid, vals, context)
243251
=== added directory 'timesheet_task/test'
=== added file 'timesheet_task/test/task_timesheet_indicators.yml'
--- timesheet_task/test/task_timesheet_indicators.yml 1970-01-01 00:00:00 +0000
+++ timesheet_task/test/task_timesheet_indicators.yml 2013-10-08 11:06:42 +0000
@@ -0,0 +1,282 @@
1-
2 Create a user 'HR Tester'
3-
4 !record {model: res.users, id: res_users_hrtester0}:
5 company_id: base.main_company
6 name: HR Tester
7 login: hr
8 password: hr
9 groups_id:
10 - base.group_hr_manager
11-
12 Create a product with type service used to specify employees designation
13-
14 !record {model: product.product, id: product_product_hrtester0}:
15 categ_id: product.product_category_6
16 cost_method: standard
17 mes_type: fixed
18 name: HR Tester service
19 standard_price: 10.0
20 type: service
21 uom_id: product.product_uom_hour
22 uom_po_id: product.product_uom_hour
23 volume: 0.0
24 warranty: 0.0
25 weight: 0.0
26 weight_net: 0.0
27-
28 Create an analytic journal for employees timesheet
29-
30 !record {model: account.analytic.journal, id: account_analytic_journal_hrtimesheettest0}:
31 company_id: base.main_company
32 name: HR Timesheet test
33 type: general
34-
35 Create an employee 'HR Tester' for user 'HR Tester'
36-
37 !record {model: hr.employee, id: hr_employee_hrtester0}:
38 name: HR Tester
39 user_id: res_users_hrtester0
40 product_id: product_product_hrtester0
41 journal_id: account_analytic_journal_hrtimesheettest0
42-
43 Create a timesheet invoice factor of 100%
44-
45 !record {model: hr_timesheet_invoice.factor, id: timesheet_invoice_factor0}:
46 name: 100%
47 customer_name: 100%
48 factor: 0.0
49-
50 Create a project 'Timesheet task and indicator tests'
51-
52 !record {model: project.project, id: project_project_timesheettest0}:
53 company_id: base.main_company
54 name: Timesheet task and indicator tests
55 to_invoice: timesheet_invoice_factor0
56-
57 Create a task 'Test timesheet records'
58-
59 !record {model: project.task, id: project_task_testtimesheetrecords0}:
60 date_start: !eval time.strftime('%Y-05-%d %H:%M:%S')
61 name: Test timesheet records
62 planned_hours: 200.0
63 project_id: project_project_timesheettest0
64 user_id: res_users_hrtester0
65-
66 The planned time on project should then be 200
67-
68 !assert {model: project.project, id: project_project_timesheettest0, string: planned_time_on_project_01}:
69 - planned_hours == 200.0
70-
71 The time spent on project should then be 0
72-
73 !assert {model: project.project, id: project_project_timesheettest0, string: time_spent_on_project_01}:
74 - effective_hours == 0.0
75-
76 Make a timesheet line of 10.0 on the project without task
77-
78 !python {model: hr.analytic.timesheet}: |
79 import time
80 project_obj = self.pool.get('project.project')
81 project = project_obj.browse(cr, uid, ref('project_project_timesheettest0'))
82 ts_line= {
83 'name': '/',
84 'user_id': ref('res_users_hrtester0'),
85 'date': time.strftime('%Y-%m-%d'),
86 'account_id': project.analytic_account_id.id,
87 'unit_amount': 10.0,
88 'journal_id': ref('account_analytic_journal_hrtimesheettest0'),
89 'to_invoice': ref('timesheet_invoice_factor0'),
90 }
91 ts = self.create(cr, uid, ts_line)
92 assert ts, "Timesheet has not been recorded correctly"
93-
94 The time spent on project should still be 0 as no task has been set
95-
96 !assert {model: project.project, id: project_project_timesheettest0}:
97 - effective_hours == 0.0
98-
99 Make a timesheet line of 10.0 on the project with a task assigned
100-
101 !python {model: hr.analytic.timesheet}: |
102 import time
103 project_obj = self.pool.get('project.project')
104 project = project_obj.browse(cr, uid, ref('project_project_timesheettest0'))
105 ts_line= {
106 'name': '/',
107 'user_id': ref('res_users_hrtester0'),
108 'date': time.strftime('%Y-%m-%d'),
109 'account_id': project.analytic_account_id.id,
110 'unit_amount': 10.0,
111 'task_id': ref('project_task_testtimesheetrecords0'),
112 'to_invoice': ref('timesheet_invoice_factor0'),
113 'journal_id': ref('account_analytic_journal_hrtimesheettest0'),
114 }
115 ts = self.create(cr, uid, ts_line)
116 assert ts, "Timesheet has not been recorded correctly"
117-
118 The time spent on the task should be 10.0
119-
120 !assert {model: project.task, id: project_task_testtimesheetrecords0, string: time_spent_on_task_01}:
121 - effective_hours == 10.0
122-
123 The remaining time on the task should be 190.0
124-
125 !assert {model: project.task, id: project_task_testtimesheetrecords0, string: remaining_time_on_task_01}:
126 - remaining_hours == 190.0
127-
128 The time spent on project should be 10.0
129-
130 !assert {model: project.project, id: project_project_timesheettest0, string: time_spent_on_project_02}:
131 - effective_hours == 10.0
132-
133 Make a timesheet line of 10.0 on the project without task, then assign one
134-
135 !python {model: hr.analytic.timesheet}: |
136 import time
137 project_obj = self.pool.get('project.project')
138 project = project_obj.browse(cr, uid, ref('project_project_timesheettest0'))
139 ts_line= {
140 'name': '/',
141 'user_id': ref('res_users_hrtester0'),
142 'date': time.strftime('%Y-%m-%d'),
143 'account_id': project.analytic_account_id.id,
144 'unit_amount': 10.0,
145 'to_invoice': ref('timesheet_invoice_factor0'),
146 'journal_id': ref('account_analytic_journal_hrtimesheettest0'),
147 }
148 ts = self.create(cr, uid, ts_line)
149 assert ts, "Timesheet has not been recorded correctly"
150 vals = {
151 'task_id': ref('project_task_testtimesheetrecords0')
152 }
153 result = self.write(cr, uid, ts, vals)
154-
155 The time spent on the task should be 20.0
156-
157 !assert {model: project.task, id: project_task_testtimesheetrecords0, string: time_spent_on_task_02}:
158 - effective_hours == 20.0
159-
160 The remaining time on the task should be 180.0
161-
162 !assert {model: project.task, id: project_task_testtimesheetrecords0, string: remaining_time_on_task_02}:
163 - remaining_hours == 180.0
164-
165 The time spent on project should be 20.0
166-
167 !assert {model: project.project, id: project_project_timesheettest0, string: time_spent_on_project_03}:
168 - effective_hours == 20.0
169-
170 Make a timesheet line of 10.0 with task, then remove the task
171-
172 !python {model: hr.analytic.timesheet}: |
173 import time
174 project_obj = self.pool.get('project.project')
175 project = project_obj.browse(cr, uid, ref('project_project_timesheettest0'))
176 task_obj = self.pool.get('project.task')
177 ts_line= {
178 'name': '/',
179 'user_id': ref('res_users_hrtester0'),
180 'date': time.strftime('%Y-%m-%d'),
181 'account_id': project.analytic_account_id.id,
182 'unit_amount': 10.0,
183 'task_id': ref('project_task_testtimesheetrecords0'),
184 'to_invoice': ref('timesheet_invoice_factor0'),
185 'journal_id': ref('account_analytic_journal_hrtimesheettest0'),
186 }
187 ts = self.create(cr, uid, ts_line)
188 assert ts, "Timesheet has not been recorded correctly"
189 task = task_obj.browse(cr, uid, ref('project_task_testtimesheetrecords0'))
190 assert task.effective_hours == 30.0, "Effective hours on task is not correct"
191 assert task.remaining_hours == 170.0, "Remaining hours on task is not correct"
192 project.refresh()
193 assert project.effective_hours == 30.0, "Effective hours on project is not correct"
194 vals = {
195 'task_id': False
196 }
197 result = self.write(cr, uid, ts, vals)
198-
199 The time spent on the task should be 20.0
200-
201 !assert {model: project.task, id: project_task_testtimesheetrecords0, string: time_spent_on_task_03}:
202 - effective_hours == 20.0
203-
204 The remaining time on the task should be 180.0
205-
206 !assert {model: project.task, id: project_task_testtimesheetrecords0, string: remaining_time_on_task_03}:
207 - remaining_hours == 180.0
208-
209 The time spent on project should be 20.0
210-
211 !assert {model: project.project, id: project_project_timesheettest0, string: time_spent_on_project_04}:
212 - effective_hours == 20.0
213-
214 Make a timesheet line of 10.0 with task, then delete the line
215-
216 !python {model: hr.analytic.timesheet}: |
217 import time
218 project_obj = self.pool.get('project.project')
219 project = project_obj.browse(cr, uid, ref('project_project_timesheettest0'))
220 task_obj = self.pool.get('project.task')
221 ts_line= {
222 'name': '/',
223 'user_id': ref('res_users_hrtester0'),
224 'date': time.strftime('%Y-%m-%d'),
225 'account_id': project.analytic_account_id.id,
226 'unit_amount': 10.0,
227 'task_id': ref('project_task_testtimesheetrecords0'),
228 'to_invoice': ref('timesheet_invoice_factor0'),
229 'journal_id': ref('account_analytic_journal_hrtimesheettest0'),
230 }
231 ts = self.create(cr, uid, ts_line)
232 assert ts, "Timesheet has not been recorded correctly"
233 task = task_obj.browse(cr, uid, ref('project_task_testtimesheetrecords0'))
234 assert task.effective_hours == 30.0, "Effective hours on task is not correct"
235 assert task.remaining_hours == 170.0, "Remaining hours on task is not correct"
236 project.refresh()
237 assert project.effective_hours == 30.0, "Effective hours on project is not correct"
238 result = self.unlink(cr, uid, [ts])
239-
240 The time spent on the task should be 20.0
241-
242 !assert {model: project.task, id: project_task_testtimesheetrecords0, string: time_spent_on_task_04}:
243 - effective_hours == 20.0
244-
245 The remaining time on the task should be 180.0
246-
247 !assert {model: project.task, id: project_task_testtimesheetrecords0, string: remaining_time_on_task_04}:
248 - remaining_hours == 180.0
249-
250 The time spent on project should be 20.0
251-
252 !assert {model: project.project, id: project_project_timesheettest0, string: time_spent_on_project_05}:
253 - effective_hours == 20.0
254-
255 Change the remaining hours of the task to 200.0
256-
257 !python {model: project.task}: |
258 task = self.browse(cr, uid, ref('project_task_testtimesheetrecords0'))
259 vals = {
260 'remaining_hours': 200.0,
261 }
262 result = self.write(cr, uid, [task.id], vals)
263-
264 The time spent on the task should still be 20.0
265-
266 !assert {model: project.task, id: project_task_testtimesheetrecords0, string: time_spent_on_task_05}:
267 - effective_hours == 20.0
268-
269 The remaining time on the task should be 200.0
270-
271 !assert {model: project.task, id: project_task_testtimesheetrecords0, string: remaining_time_on_task_05}:
272 - remaining_hours == 200.0
273-
274 The delay in hours on the task should be 20.0
275-
276 !assert {model: project.task, id: project_task_testtimesheetrecords0, string: delay_on_task_01}:
277 - delay_hours == 20.0
278-
279 The total on the task should be 220.0
280-
281 !assert {model: project.task, id: project_task_testtimesheetrecords0, string: total_time_on_task_01}:
282 - total_hours == 220.0

Subscribers

People subscribed via source and target branches