Merge lp:~camptocamp/hr-timesheet/full-fill-timesheet-account-type-vre into lp:~hr-core-editors/hr-timesheet/6.1

Proposed by Vincent Renaville@camptocamp
Status: Superseded
Proposed branch: lp:~camptocamp/hr-timesheet/full-fill-timesheet-account-type-vre
Merge into: lp:~hr-core-editors/hr-timesheet/6.1
Diff against target: 7196 lines (+4884/-1282) (has conflicts)
65 files modified
hr_attendance_analysis/AUTHORS.txt (+1/-0)
hr_attendance_analysis/__init__.py (+26/-0)
hr_attendance_analysis/__openerp__.py (+51/-0)
hr_attendance_analysis/company_view.xml (+17/-0)
hr_attendance_analysis/hr_attendance.py (+419/-0)
hr_attendance_analysis/hr_attendance_view.xml (+80/-0)
hr_attendance_analysis/hr_contract.py (+56/-0)
hr_attendance_analysis/i18n/hr_attendance_analysis.pot (+564/-0)
hr_attendance_analysis/i18n/it.po (+611/-0)
hr_attendance_analysis/report/__init__.py (+21/-0)
hr_attendance_analysis/report/calendar_report.mako (+138/-0)
hr_attendance_analysis/report/calendar_report.py (+96/-0)
hr_attendance_analysis/reports.xml (+86/-0)
hr_attendance_analysis/resource.py (+102/-0)
hr_attendance_analysis/resource_view.xml (+52/-0)
hr_attendance_analysis/security/ir.model.access.csv (+3/-0)
hr_attendance_analysis/wizard/__init__.py (+23/-0)
hr_attendance_analysis/wizard/print_calendar_report.py (+366/-0)
hr_attendance_analysis/wizard/print_calendar_report.xml (+38/-0)
hr_timesheet_fulfill/__init__.py (+18/-25)
hr_timesheet_fulfill/__openerp__.py (+39/-50)
hr_timesheet_fulfill/wizard/__init__.py (+3/-0)
hr_timesheet_fulfill/wizard/timesheet_fulfill.py (+36/-44)
hr_timesheet_fulfill/wizard/timesheet_fulfill_view.xml (+55/-40)
hr_timesheet_holidays/__openerp__.py (+1/-1)
hr_timesheet_improvement/__init__.py (+22/-0)
hr_timesheet_improvement/__openerp__.py (+50/-0)
hr_timesheet_improvement/hr_attendance.py (+98/-0)
hr_timesheet_improvement/hr_timesheet.py (+51/-0)
hr_timesheet_improvement/hr_timesheet_view.xml (+17/-0)
hr_timesheet_print/__openerp__.py (+1/-1)
hr_timesheet_reminder/__init__.py (+15/-26)
hr_timesheet_reminder/__openerp__.py (+41/-43)
hr_timesheet_reminder/company.py (+51/-49)
hr_timesheet_reminder/hr_employee.py (+42/-53)
hr_timesheet_reminder/hr_employee_view.xml (+0/-1)
hr_timesheet_reminder/reminder.py (+100/-88)
hr_timesheet_reminder/report/__init__.py (+16/-25)
hr_timesheet_reminder/report/timesheet_status.py (+63/-65)
hr_timesheet_reminder/report/timesheet_status.rml (+157/-163)
hr_timesheet_reminder/timesheet_report.xml (+10/-10)
hr_timesheet_reminder/wizard/reminder_config.py (+37/-45)
hr_timesheet_reminder/wizard/reminder_config_view.xml (+38/-28)
hr_timesheet_reminder/wizard/reminder_status.py (+35/-44)
hr_timesheet_reminder/wizard/reminder_status_view.xml (+22/-21)
hr_timesheet_task/__init__.py (+15/-25)
hr_timesheet_task/__openerp__.py (+13/-9)
hr_timesheet_task/hr_analytic_timesheet_view.xml (+15/-28)
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 (+25/-15)
timesheet_task/i18n/fr.po (+53/-0)
timesheet_task/project_task.py (+145/-104)
timesheet_task/project_task_view.xml (+203/-37)
timesheet_task/test/task_timesheet_indicators.yml (+282/-0)
timesheet_task/tmp_file_for_project_indicator.py (+0/-29)
Text conflict in hr_timesheet_reminder/company.py
To merge this branch: bzr merge lp:~camptocamp/hr-timesheet/full-fill-timesheet-account-type-vre
Reviewer Review Type Date Requested Status
Yannick Vaucher @ Camptocamp Needs Resubmitting
Joël Grand-Guillaume @ camptocamp code review, no tests Needs Fixing
Review via email: mp+194368@code.launchpad.net

This proposal has been superseded by a proposal from 2013-11-21.

Description of the change

change type from normal to contract to match project linked analytic account instead of standard analytic account

To post a comment you must log in.
Revision history for this message
Joël Grand-Guillaume @ camptocamp (jgrandguillaume-c2c) wrote :

Hi,

Thanks for the contribs, I see a conflict here, can you check please ?

Regards,

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

You might want to resubmit with only rev 58

rev 49 to 57 are certainly not meant to be in this MP

review: Needs Resubmitting
59. By Vincent Renaville@camptocamp

[FIX] change type test to be more generic

Unmerged revisions

59. By Vincent Renaville@camptocamp

[FIX] change type test to be more generic

58. By Vincent Renaville@camptocamp

[FIX] change type from normal to contract to match project linked analytic account instead of standard analytic account

57. By Launchpad Translations on behalf of hr-core-editors

Launchpad automatic translations update.

56. By Nicolas Bessi - Camptocamp

[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

55. By Launchpad Translations on behalf of hr-core-editors

Launchpad automatic translations update.

54. By Yannick Vaucher @ Camptocamp

[FIX] hr-timesheet - add a dummy hr_analytic_timesheet_id field on hr.analytic.timesheet to be able to write name and project_id on project.task as project.task write method

53. By Lorenzo Battistini

[fix] if no next_attendance_ids found, avoid useless computations

52. By Lorenzo Battistini

[IMP] hr_attendance_analysis - summary

51. By Lorenzo Battistini

[FIX] consider attendances of type 'action' while searching for previous sign in

50. By Laetitia Gangloff (Acsone)

[FIX] fix the bug lp:1200183. allow duplicate contract. contract without trial period is not active contract

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory 'hr_attendance_analysis'
2=== added file 'hr_attendance_analysis/AUTHORS.txt'
3--- hr_attendance_analysis/AUTHORS.txt 1970-01-01 00:00:00 +0000
4+++ hr_attendance_analysis/AUTHORS.txt 2013-11-07 15:51:52 +0000
5@@ -0,0 +1,1 @@
6+Lorenzo Battistini <lorenzo.battistini@agilebg.com>
7
8=== added file 'hr_attendance_analysis/__init__.py'
9--- hr_attendance_analysis/__init__.py 1970-01-01 00:00:00 +0000
10+++ hr_attendance_analysis/__init__.py 2013-11-07 15:51:52 +0000
11@@ -0,0 +1,26 @@
12+# -*- coding: utf-8 -*-
13+##############################################################################
14+#
15+# Copyright (C) 2011 Domsense srl (<http://www.domsense.com>)
16+# Copyright (C) 2011-2013 Agile Business Group sagl
17+# (<http://www.agilebg.com>)
18+#
19+# This program is free software: you can redistribute it and/or modify
20+# it under the terms of the GNU Affero General Public License as published
21+# by the Free Software Foundation, either version 3 of the License, or
22+# (at your option) any later version.
23+#
24+# This program is distributed in the hope that it will be useful,
25+# but WITHOUT ANY WARRANTY; without even the implied warranty of
26+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27+# GNU Affero General Public License for more details.
28+#
29+# You should have received a copy of the GNU Affero General Public License
30+# along with this program. If not, see <http://www.gnu.org/licenses/>.
31+#
32+##############################################################################
33+import hr_attendance
34+import hr_contract
35+import report
36+import wizard
37+import resource
38
39=== added file 'hr_attendance_analysis/__openerp__.py'
40--- hr_attendance_analysis/__openerp__.py 1970-01-01 00:00:00 +0000
41+++ hr_attendance_analysis/__openerp__.py 2013-11-07 15:51:52 +0000
42@@ -0,0 +1,51 @@
43+# -*- coding: utf-8 -*-
44+##############################################################################
45+#
46+# Copyright (C) 2011 Domsense srl (<http://www.domsense.com>)
47+# Copyright (C) 2011-2013 Agile Business Group sagl
48+# (<http://www.agilebg.com>)
49+#
50+# This program is free software: you can redistribute it and/or modify
51+# it under the terms of the GNU Affero General Public License as published
52+# by the Free Software Foundation, either version 3 of the License, or
53+# (at your option) any later version.
54+#
55+# This program is distributed in the hope that it will be useful,
56+# but WITHOUT ANY WARRANTY; without even the implied warranty of
57+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
58+# GNU Affero General Public License for more details.
59+#
60+# You should have received a copy of the GNU Affero General Public License
61+# along with this program. If not, see <http://www.gnu.org/licenses/>.
62+#
63+##############################################################################
64+{
65+ 'name': "HR - Attendance Analysis",
66+ 'version': '0.1',
67+ 'category': 'Generic Modules/Human Resources',
68+ 'summary': "Dynamic reports based on employee's attendances and contract's calendar",
69+ 'description': """
70+Dynamic reports based on employee's attendances and contract's calendar.
71+Among other things, it lets you see the amount of working hours outside and inside the contract's working schedule (overtime).
72+It also provides a daily based report, showing the detailed and total hours compared to calendar hours.
73+Several analysis settings can be configured, like:
74+ - Tolerance for sign-in and sign-out
75+ - Attendances and overtimes roundings
76+ - Diffrent types of overtime, according to the overtime amount
77+""",
78+ 'author': 'Agile Business Group',
79+ 'website': 'http://www.agilebg.com',
80+ 'license': 'AGPL-3',
81+ "depends" : ['hr_attendance', 'hr_contract', 'hr_holidays', 'report_webkit'],
82+ "data" : [
83+ 'company_view.xml',
84+ 'hr_attendance_view.xml',
85+ 'reports.xml',
86+ 'wizard/print_calendar_report.xml',
87+ 'resource_view.xml',
88+ 'security/ir.model.access.csv',
89+ ],
90+ "demo" : [],
91+ "active": False,
92+ "installable": True
93+}
94
95=== added file 'hr_attendance_analysis/company_view.xml'
96--- hr_attendance_analysis/company_view.xml 1970-01-01 00:00:00 +0000
97+++ hr_attendance_analysis/company_view.xml 2013-11-07 15:51:52 +0000
98@@ -0,0 +1,17 @@
99+<?xml version="1.0" encoding="UTF-8"?>
100+<openerp>
101+ <data>
102+ <record id="view_company_form" model="ir.ui.view">
103+ <field name="inherit_id" ref="base.view_company_form"/>
104+ <field name="name">view.company.form</field>
105+ <field name="model">res.company</field>
106+ <field name="arch" type="xml">
107+ <page string="Configuration" position="inside">
108+ <group name="attendance_analysis_grp" string="Attendance analysis">
109+ <field name="working_time_precision" widget="float_time"/>
110+ </group>
111+ </page>
112+ </field>
113+ </record>
114+ </data>
115+</openerp>
116
117=== added file 'hr_attendance_analysis/hr_attendance.py'
118--- hr_attendance_analysis/hr_attendance.py 1970-01-01 00:00:00 +0000
119+++ hr_attendance_analysis/hr_attendance.py 2013-11-07 15:51:52 +0000
120@@ -0,0 +1,419 @@
121+# -*- coding: utf-8 -*-
122+##############################################################################
123+#
124+# Copyright (C) 2011 Domsense srl (<http://www.domsense.com>)
125+# Copyright (C) 2011-2013 Agile Business Group sagl
126+# (<http://www.agilebg.com>)
127+#
128+# This program is free software: you can redistribute it and/or modify
129+# it under the terms of the GNU Affero General Public License as published
130+# by the Free Software Foundation, either version 3 of the License, or
131+# (at your option) any later version.
132+#
133+# This program is distributed in the hope that it will be useful,
134+# but WITHOUT ANY WARRANTY; without even the implied warranty of
135+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
136+# GNU Affero General Public License for more details.
137+#
138+# You should have received a copy of the GNU Affero General Public License
139+# along with this program. If not, see <http://www.gnu.org/licenses/>.
140+#
141+##############################################################################
142+
143+from __future__ import division
144+from openerp.osv import fields, orm
145+from openerp.tools.translate import _
146+import time
147+from datetime import *
148+import math
149+
150+import pytz
151+
152+class res_company(orm.Model):
153+
154+ _inherit = 'res.company'
155+
156+ _columns = {
157+ 'working_time_precision': fields.float('Working time precision', help='The precision used to analyse working times over working schedule (hh:mm)', required=True)
158+ }
159+
160+ _defaults = {
161+ 'working_time_precision': 1.0 / 60 # hours
162+ }
163+
164+
165+class hr_attendance(orm.Model):
166+
167+ # ref: https://bugs.launchpad.net/openobject-client/+bug/887612
168+ # test: 0.9853 - 0.0085
169+ def float_time_convert(self, float_val):
170+ hours = math.floor(abs(float_val))
171+ mins = abs(float_val) - hours
172+ mins = round(mins * 60)
173+ if mins >= 60.0:
174+ hours = hours + 1
175+ mins = 0.0
176+ float_time = '%02d:%02d' % (hours,mins)
177+ return float_time
178+
179+ def float_to_datetime(self, float_val):
180+ str_float = self.float_time_convert(float_val)
181+ hours = int(str_float.split(':')[0])
182+ minutes = int(str_float.split(':')[1])
183+ days = 1
184+ if hours / 24 > 0:
185+ days += hours / 24
186+ hours = hours % 24
187+ return datetime(1900, 1, int(days), hours, minutes)
188+
189+ def float_to_timedelta(self, float_val):
190+ str_time = self.float_time_convert(float_val)
191+ return timedelta(0, int(str_time.split(':')[0]) * 60.0*60.0
192+ + int(str_time.split(':')[1]) * 60.0)
193+
194+ def total_seconds(self, td):
195+ return (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10**6
196+
197+ def time_difference(self, float_start_time, float_end_time):
198+ if float_end_time < float_start_time:
199+ raise orm.except_orm(_('Error'), _('End time %s < start time %s')
200+ % (str(float_end_time),str(float_start_time)))
201+ delta = self.float_to_datetime(float_end_time) - self.float_to_datetime(
202+ float_start_time)
203+ return self.total_seconds(delta) / 60.0 / 60.0
204+
205+ def time_sum(self, float_first_time, float_second_time):
206+ str_first_time = self.float_time_convert(float_first_time)
207+ first_timedelta = timedelta(0, int(str_first_time.split(':')[0]) * 60.0*60.0 +
208+ int(str_first_time.split(':')[1]) * 60.0)
209+ str_second_time = self.float_time_convert(float_second_time)
210+ second_timedelta = timedelta(0, int(str_second_time.split(':')[0]) * 60.0*60.0 +
211+ int(str_second_time.split(':')[1]) * 60.0)
212+ return self.total_seconds(first_timedelta + second_timedelta) / 60.0 / 60.0
213+
214+ def _split_long_attendances(self, start_datetime, duration):
215+ # start_datetime: datetime, duration: hours
216+ # returns [(datetime, hours)]
217+ res = []
218+ if duration > 24:
219+ res.append((start_datetime, 24))
220+ res.extend(self._split_long_attendances(
221+ start_datetime + timedelta(1), duration - 24))
222+ else:
223+ res.append((start_datetime, duration))
224+ return res
225+
226+ def _split_no_recursive_attendance(self, start_datetime, duration, precision=0.25):
227+ # start_datetime: datetime, duration: hours, precision: hours
228+ # returns [(datetime, hours)]
229+ res = []
230+ while (duration > precision):
231+ res.append((start_datetime, precision))
232+ start_datetime += timedelta(days=0, seconds=0, microseconds=0, milliseconds=0,
233+ minutes=0, hours=precision)
234+ duration -= precision
235+ if duration > precision / 2.0:
236+ res.append((start_datetime, precision))
237+ return res
238+
239+ def _split_attendance(self, start_datetime, duration, precision=0.25):
240+ # start_datetime: datetime, duration: hours, precision: hours
241+ # returns [(datetime, hours)]
242+ res = []
243+ if duration > precision:
244+ res.append((start_datetime, precision))
245+ res.extend(self._split_attendance(start_datetime + timedelta(0,0,0,0,0,precision), duration - precision, precision))
246+ elif duration > precision / 2.0:
247+ res.append((start_datetime, precision))
248+ return res
249+
250+ def get_active_contracts(self, cr, uid, employee_id, date=datetime.now().strftime('%Y-%m-%d')):
251+ contract_pool = self.pool.get('hr.contract')
252+ active_contract_ids= contract_pool.search(cr, uid, [
253+ '&',
254+ ('employee_id', '=', employee_id),
255+ '|',
256+ '&',
257+ ('date_start', '<=', date),
258+ '|',
259+ ('date_end', '>=', date),
260+ ('date_end', '=', False),
261+ '&',
262+ '&',
263+ ('trial_date_start', '!=', False),
264+ ('trial_date_start', '<=', date),
265+ '&',
266+ ('trial_date_end', '!=', False),
267+ ('trial_date_end', '>=', date),
268+ ])
269+ if len(active_contract_ids) > 1:
270+ employee = self.pool.get('hr.employee').browse(cr,uid,employee_id)
271+ raise orm.except_orm(_('Error'), _(
272+ 'Too many active contracts for employee %s'
273+ ) % employee.name)
274+ return active_contract_ids
275+
276+ def _ceil_rounding(self, rounding, datetime):
277+ minutes = (datetime.minute / 60.0
278+ + datetime.second / 60.0 / 60.0)
279+ return math.ceil(minutes * rounding) / rounding
280+
281+ def _floor_rounding(self, rounding, datetime):
282+ minutes = (datetime.minute / 60.0
283+ + datetime.second / 60.0 / 60.0)
284+ return math.floor(minutes * rounding) / rounding
285+
286+ def _get_attendance_duration(self, cr, uid, ids, field_name, arg, context=None):
287+ res = {}
288+ contract_pool = self.pool.get('hr.contract')
289+ resource_pool = self.pool.get('resource.resource')
290+ attendance_pool = self.pool.get('resource.calendar.attendance')
291+ precision = self.pool.get('res.users').browse(cr, uid, uid).company_id.working_time_precision
292+ # 2012.10.16 LF FIX : Get timezone from context
293+ active_tz = pytz.timezone(context.get("tz","UTC") if context else "UTC")
294+ str_now = datetime.strftime(datetime.now(), '%Y-%m-%d %H:%M:%S')
295+ for attendance_id in ids:
296+ duration = 0.0
297+ outside_calendar_duration = 0.0
298+ inside_calendar_duration = 0.0
299+ attendance = self.browse(cr, uid, attendance_id)
300+ res[attendance.id] = {}
301+ # 2012.10.16 LF FIX : Attendance in context timezone
302+ attendance_start = datetime.strptime(
303+ attendance.name, '%Y-%m-%d %H:%M:%S'
304+ ).replace(tzinfo=pytz.utc).astimezone(active_tz)
305+ next_attendance_date = str_now
306+ next_attendance_ids = False
307+ # should we compute for sign out too?
308+ if attendance.action == 'sign_in':
309+ next_attendance_ids = self.search(cr, uid, [
310+ ('employee_id', '=', attendance.employee_id.id),
311+ ('name', '>', attendance.name)], order='name')
312+ if next_attendance_ids:
313+ next_attendance = self.browse(cr, uid, next_attendance_ids[0])
314+ if next_attendance.action == 'sign_in':
315+ # 2012.10.16 LF FIX : Attendance in context timezone
316+ raise orm.except_orm(_('Error'), _(
317+ 'Incongruent data: sign-in %s is followed by another sign-in'
318+ ) % attendance_start)
319+ next_attendance_date = next_attendance.name
320+ # 2012.10.16 LF FIX : Attendance in context timezone
321+ attendance_stop = datetime.strptime(
322+ next_attendance_date, '%Y-%m-%d %H:%M:%S'
323+ ).replace(tzinfo=pytz.utc).astimezone(active_tz)
324+ duration_delta = attendance_stop - attendance_start
325+ duration = self.total_seconds(duration_delta) / 60.0 / 60.0
326+ duration = round(duration / precision) * precision
327+ res[attendance.id]['duration'] = duration
328+ res[attendance.id]['end_datetime'] = next_attendance_date
329+ # If contract is not specified: working days = 24/7
330+ res[attendance.id]['inside_calendar_duration'] = duration
331+ res[attendance.id]['outside_calendar_duration'] = 0.0
332+
333+ active_contract_ids = self.get_active_contracts(
334+ cr, uid, attendance.employee_id.id, date=str_now[:10])
335+
336+ if active_contract_ids and next_attendance_ids:
337+ contract = contract_pool.browse(cr, uid, active_contract_ids[0])
338+ if contract.working_hours:
339+ # TODO applicare prima arrotondamento o tolleranza?
340+ if contract.working_hours.attendance_rounding:
341+ float_attendance_rounding = float(contract.working_hours.attendance_rounding)
342+ rounded_start_hour = self._ceil_rounding(
343+ float_attendance_rounding, attendance_start)
344+ rounded_stop_hour = self._floor_rounding(
345+ float_attendance_rounding, attendance_stop)
346+
347+ if abs(1- rounded_start_hour) < 0.01: # if shift == 1 hour
348+ attendance_start = datetime(attendance_start.year, attendance_start.month,
349+ attendance_start.day, attendance_start.hour + 1)
350+ else:
351+ attendance_start = datetime(attendance_start.year, attendance_start.month,
352+ attendance_start.day, attendance_start.hour, int(round(rounded_start_hour * 60.0)))
353+
354+ attendance_stop = datetime(attendance_stop.year, attendance_stop.month,
355+ attendance_stop.day, attendance_stop.hour,
356+ int(round(rounded_stop_hour * 60.0)))
357+
358+ # again
359+ duration_delta = attendance_stop - attendance_start
360+ duration = self.total_seconds(duration_delta) / 60.0 / 60.0
361+ duration = round(duration / precision) * precision
362+ res[attendance.id]['duration'] = duration
363+
364+ res[attendance.id]['inside_calendar_duration'] = 0.0
365+ res[attendance.id]['outside_calendar_duration'] = 0.0
366+ calendar_id = contract.working_hours.id
367+ intervals_within = 0
368+
369+ # split attendance in intervals = precision
370+ # 2012.10.16 LF FIX : no recursion in split attendance
371+ splitted_attendances = self._split_no_recursive_attendance(
372+ attendance_start, duration, precision)
373+ counter = 0
374+ for atomic_attendance in splitted_attendances:
375+ counter += 1
376+ centered_attendance = atomic_attendance[0] + timedelta(
377+ 0,0,0,0,0, atomic_attendance[1] / 2.0)
378+ centered_attendance_hour = (
379+ centered_attendance.hour + centered_attendance.minute / 60.0
380+ + centered_attendance.second / 60.0 / 60.0
381+ )
382+ # check if centered_attendance is within a working schedule
383+ # 2012.10.16 LF FIX : weekday must be single character not int
384+ weekday_char = str(unichr(centered_attendance.weekday() + 48))
385+ matched_schedule_ids = attendance_pool.search(cr, uid, [
386+ '&',
387+ '|',
388+ ('date_from', '=', False),
389+ ('date_from','<=',centered_attendance.date()),
390+ '|',
391+ ('dayofweek', '=', False),
392+ ('dayofweek','=',weekday_char),
393+ ('calendar_id','=',calendar_id),
394+ ('hour_to','>=',centered_attendance_hour),
395+ ('hour_from','<=',centered_attendance_hour),
396+ ])
397+ if len(matched_schedule_ids) > 1:
398+ raise orm.except_orm(_('Error'),
399+ _('Wrongly configured working schedule with id %s') % str(calendar_id))
400+ if matched_schedule_ids:
401+ intervals_within += 1
402+ # sign in tolerance
403+ if intervals_within == 1:
404+ calendar_attendance = attendance_pool.browse(cr, uid, matched_schedule_ids[0])
405+ attendance_start_hour = (
406+ attendance_start.hour + attendance_start.minute / 60.0
407+ + attendance_start.second / 60.0 / 60.0
408+ )
409+ if attendance_start_hour >= (
410+ calendar_attendance.hour_from and
411+ (attendance_start_hour - (calendar_attendance.hour_from +
412+ calendar_attendance.tolerance_to)) < 0.01
413+ ): # handling float roundings (<=)
414+ additional_intervals = round(
415+ (attendance_start_hour - calendar_attendance.hour_from) / precision)
416+ intervals_within += additional_intervals
417+ res[attendance.id]['duration'] = self.time_sum(
418+ res[attendance.id]['duration'], additional_intervals * precision)
419+ # sign out tolerance
420+ if len(splitted_attendances) == counter:
421+ attendance_stop_hour = (
422+ attendance_stop.hour + attendance_stop.minute / 60.0
423+ + attendance_stop.second / 60.0 / 60.0
424+ )
425+ calendar_attendance = attendance_pool.browse(cr, uid, matched_schedule_ids[0])
426+ if attendance_stop_hour <= (
427+ calendar_attendance.hour_to and
428+ (attendance_stop_hour - (calendar_attendance.hour_to -
429+ calendar_attendance.tolerance_from)) > -0.01
430+ ): # handling float roundings (>=)
431+ additional_intervals = round(
432+ (calendar_attendance.hour_to - attendance_stop_hour) / precision)
433+ intervals_within += additional_intervals
434+ res[attendance.id]['duration'] = self.time_sum(
435+ res[attendance.id]['duration'], additional_intervals * precision)
436+
437+ res[attendance.id]['inside_calendar_duration'] = intervals_within * precision
438+ # make difference using time in order to avoid rounding errors
439+ # inside_calendar_duration can't be > duration
440+ res[attendance.id]['outside_calendar_duration'] = self.time_difference(
441+ res[attendance.id]['inside_calendar_duration'],
442+ res[attendance.id]['duration'])
443+
444+ if contract.working_hours.overtime_rounding:
445+ if res[attendance.id]['outside_calendar_duration']:
446+ overtime = res[attendance.id]['outside_calendar_duration']
447+ if contract.working_hours.overtime_rounding_tolerance:
448+ overtime = self.time_sum(overtime,
449+ contract.working_hours.overtime_rounding_tolerance)
450+ float_overtime_rounding = float(contract.working_hours.overtime_rounding)
451+ res[attendance.id]['outside_calendar_duration'] = math.floor(
452+ overtime * float_overtime_rounding) / float_overtime_rounding
453+
454+ return res
455+
456+ def _get_by_contracts(self, cr, uid, ids, context=None):
457+ attendance_ids = []
458+ attendance_pool = self.pool.get('hr.attendance')
459+ for contract in self.pool.get('hr.contract').browse(cr, uid, ids, context=context):
460+ att_ids = attendance_pool.search(cr, uid, [('employee_id', '=', contract.employee_id.id)])
461+ for att_id in att_ids:
462+ if att_id not in attendance_ids:
463+ attendance_ids.append(att_id)
464+ return attendance_ids
465+
466+ def _get_by_calendars(self, cr, uid, ids, context=None):
467+ attendance_ids = []
468+ attendance_pool = self.pool.get('hr.attendance')
469+ contract_pool = self.pool.get('hr.contract')
470+ for calendar in self.pool.get('resource.calendar').browse(cr, uid, ids, context=context):
471+ contract_ids = contract_pool.search(cr, uid, [('working_hours', '=', calendar.id)])
472+ att_ids = attendance_pool._get_by_contracts(cr, uid, contract_ids, context=None)
473+ for att_id in att_ids:
474+ if att_id not in attendance_ids:
475+ attendance_ids.append(att_id)
476+ return attendance_ids
477+
478+ def _get_by_calendar_attendances(self, cr, uid, ids, context=None):
479+ attendance_ids = []
480+ attendance_pool = self.pool.get('hr.attendance')
481+ for calendar_attendance in self.pool.get('resource.calendar.attendance').browse(cr, uid, ids, context=context):
482+ att_ids = attendance_pool._get_by_calendars(cr, uid, [calendar_attendance.calendar_id.id], context=None)
483+ for att_id in att_ids:
484+ if att_id not in attendance_ids:
485+ attendance_ids.append(att_id)
486+ return attendance_ids
487+
488+ def _get_attendances(self, cr, uid, ids, context=None):
489+ attendance_ids = []
490+ for attendance in self.browse(cr, uid, ids, context=context):
491+ if attendance.action == 'sign_in' and attendance.id not in attendance_ids:
492+ attendance_ids.append(attendance.id)
493+ elif attendance.action == 'sign_out':
494+ previous_attendance_ids = self.search(cr, uid, [
495+ ('employee_id', '=', attendance.employee_id.id),
496+ ('name', '<', attendance.name),
497+ ('action', '=', 'sign_in'),
498+ ], order='name')
499+ if previous_attendance_ids and previous_attendance_ids[len(previous_attendance_ids) - 1] not in attendance_ids:
500+ attendance_ids.append(previous_attendance_ids[len(previous_attendance_ids) - 1])
501+ return attendance_ids
502+
503+ _inherit = "hr.attendance"
504+
505+ _columns = {
506+ 'duration': fields.function(_get_attendance_duration, method=True, multi='duration', string="Attendance duration",
507+ store={
508+ 'hr.attendance': (_get_attendances, ['name', 'action', 'employee_id'], 20),
509+ 'hr.contract': (_get_by_contracts, ['employee_id', 'date_start', 'date_end', 'trial_date_start', 'trial_date_end', 'working_hours'], 20),
510+ 'resource.calendar': (_get_by_calendars, ['attendance_ids'], 20),
511+ 'resource.calendar.attendance': (_get_by_calendar_attendances, ['dayofweek', 'date_from', 'hour_from', 'hour_to', 'calendar_id'], 20),
512+ }
513+ ),
514+ 'end_datetime': fields.function(_get_attendance_duration, method=True, multi='duration', type="datetime", string="End date time",
515+ store={
516+ 'hr.attendance': (_get_attendances, ['name', 'action', 'employee_id'], 20),
517+ 'hr.contract': (_get_by_contracts, ['employee_id', 'date_start', 'date_end', 'trial_date_start', 'trial_date_end', 'working_hours'], 20),
518+ 'resource.calendar': (_get_by_calendars, ['attendance_ids'], 20),
519+ 'resource.calendar.attendance': (_get_by_calendar_attendances, ['dayofweek', 'date_from', 'hour_from', 'hour_to', 'calendar_id'], 20),
520+ }),
521+ 'outside_calendar_duration': fields.function(_get_attendance_duration, method=True, multi='duration',
522+ string="Overtime",
523+ store={
524+ 'hr.attendance': (_get_attendances, ['name', 'action', 'employee_id'], 20),
525+ 'hr.contract': (_get_by_contracts, ['employee_id', 'date_start', 'date_end', 'trial_date_start', 'trial_date_end', 'working_hours'], 20),
526+ 'resource.calendar': (_get_by_calendars, ['attendance_ids'], 20),
527+ 'resource.calendar.attendance': (_get_by_calendar_attendances, ['dayofweek', 'date_from', 'hour_from', 'hour_to', 'calendar_id'], 20),
528+ }),
529+ 'inside_calendar_duration': fields.function(_get_attendance_duration, method=True, multi='duration',
530+ string="Duration within working schedule",
531+ store={
532+ 'hr.attendance': (_get_attendances, ['name', 'action', 'employee_id'], 20),
533+ 'hr.contract': (_get_by_contracts, ['employee_id', 'date_start', 'date_end', 'trial_date_start', 'trial_date_end', 'working_hours'], 20),
534+ 'resource.calendar': (_get_by_calendars, ['attendance_ids'], 20),
535+ 'resource.calendar.attendance': (_get_by_calendar_attendances, ['dayofweek', 'date_from', 'hour_from', 'hour_to', 'calendar_id'], 20),
536+ }),
537+ }
538+
539+
540
541=== added file 'hr_attendance_analysis/hr_attendance_view.xml'
542--- hr_attendance_analysis/hr_attendance_view.xml 1970-01-01 00:00:00 +0000
543+++ hr_attendance_analysis/hr_attendance_view.xml 2013-11-07 15:51:52 +0000
544@@ -0,0 +1,80 @@
545+<?xml version="1.0" encoding="utf-8"?>
546+<openerp>
547+ <data>
548+
549+ <record id="view_attendance_form" model="ir.ui.view">
550+ <field name="name">hr.attendance.form</field>
551+ <field name="model">hr.attendance</field>
552+ <field name="inherit_id" ref="hr_attendance.view_attendance_form"></field>
553+ <field name="arch" type="xml">
554+ <field name="action_desc" position="after">
555+ <field name="duration" widget="float_time"/>
556+ <field name="outside_calendar_duration" widget="float_time"/>
557+ <field name="inside_calendar_duration" widget="float_time" />
558+ </field>
559+ </field>
560+ </record>
561+
562+ <record id="view_attendance_analysis" model="ir.ui.view">
563+ <field name="name">hr.attendance.analysis</field>
564+ <field name="model">hr.attendance</field>
565+ <field name="priority" eval="17"/>
566+ <field name="arch" type="xml">
567+ <tree string="Employee attendances analysis">
568+ <field name="employee_id" />
569+ <field name="name" string="Start date time"/>
570+ <field name="end_datetime"/>
571+ <field name="duration" sum="Total hours" widget="float_time"/>
572+ <field name="outside_calendar_duration" sum="Overtime" widget="float_time"/>
573+ <field name="inside_calendar_duration" sum="Within working schedule" widget="float_time" />
574+ <field name="day" invisible="1"/>
575+ </tree>
576+ </field>
577+ </record>
578+
579+ <record model="ir.ui.view" id="view_hr_attendance_filter">
580+ <field name="name">view_hr_attendance_filter</field>
581+ <field name="model">hr.attendance</field>
582+ <field name="arch" type="xml">
583+ <search string="Hr Attendance Search">
584+ <filter icon="terp-go-today" string="Today" name="today" domain="[('name::date','=',current_date)]" />
585+ <separator orientation="vertical"/>
586+ <field name="employee_id"/>
587+ <field name="name" string="Start date time"/>
588+ <field name="end_datetime"/>
589+ <newline/>
590+ <group expand="0" string="Group By...">
591+ <filter name="employee" string="Employee" icon="terp-personal" domain="[]" context="{'group_by':'employee_id'}"/>
592+ <separator orientation="vertical"/>
593+ <filter string="Day" icon="terp-go-today" domain="[]" context="{'group_by':'day'}"/>
594+ </group>
595+ </search>
596+ </field>
597+ </record>
598+
599+ <record model="ir.ui.view" id="view_hr_attendance_calendar">
600+ <field name="name">view_hr_attendance.calendar</field>
601+ <field name="model">hr.attendance</field>
602+ <field name="arch" type="xml">
603+ <calendar string="Calendar View" date_start="name" date_stop="end_datetime" color="employee_id">
604+ <field name="duration" />
605+ <field name="outside_calendar_duration" />
606+ <field name="inside_calendar_duration" />
607+ </calendar>
608+ </field>
609+ </record>
610+
611+ <record id="open_view_attendance" model="ir.actions.act_window">
612+ <field name="name">Attendances analysis</field>
613+ <field name="res_model">hr.attendance</field>
614+ <field name="view_type">form</field>
615+ <field name="view_mode">tree,form,calendar</field>
616+ <field name="domain">[('action', '=', 'sign_in')]</field>
617+ <field name="view_id" ref="view_attendance_analysis"/>
618+ <field name="search_view_id" ref="view_hr_attendance_filter" />
619+ </record>
620+ <menuitem action="open_view_attendance" id="menu_open_view_attendance" parent="hr_attendance.menu_hr_attendance" groups="base.group_hr_manager"/>
621+ <menuitem action="resource.action_resource_calendar_form" id="menu_view_resource_calendar" parent="hr_contract.next_id_56" sequence="1"/>
622+
623+ </data>
624+</openerp>
625
626=== added file 'hr_attendance_analysis/hr_contract.py'
627--- hr_attendance_analysis/hr_contract.py 1970-01-01 00:00:00 +0000
628+++ hr_attendance_analysis/hr_contract.py 2013-11-07 15:51:52 +0000
629@@ -0,0 +1,56 @@
630+# -*- coding: utf-8 -*-
631+##############################################################################
632+#
633+# Authors: Stéphane Bidoul & Laetitia Gangloff
634+# Copyright (c) 2013 Acsone SA/NV (http://www.acsone.eu)
635+# All Rights Reserved
636+#
637+# WARNING: This program as such is intended to be used by professional
638+# programmers who take the whole responsibility of assessing all potential
639+# consequences resulting from its eventual inadequacies and bugs.
640+# End users who are looking for a ready-to-use solution with commercial
641+# guarantees and support are strongly advised to contact a Free Software
642+# Service Company.
643+#
644+# This program is free software: you can redistribute it and/or modify
645+# it under the terms of the GNU Affero General Public License as
646+# published by the Free Software Foundation, either version 3 of the
647+# License, or (at your option) any later version.
648+#
649+# This program is distributed in the hope that it will be useful,
650+# but WITHOUT ANY WARRANTY; without even the implied warranty of
651+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
652+# GNU Affero General Public License for more details.
653+#
654+# You should have received a copy of the GNU Affero General Public License
655+# along with this program. If not, see <http://www.gnu.org/licenses/>.
656+#
657+##############################################################################
658+import datetime
659+
660+from openerp.osv import fields, orm
661+
662+
663+class hr_contract(orm.Model):
664+ _inherit = 'hr.contract'
665+
666+ def copy(self, cr, uid, id, defaults, context=None):
667+ """
668+ When duplicate a contract set the start date to the last end date + 1 day.
669+ If the last end date is False, do nothing
670+ """
671+ contract = self.browse(cr, uid, id, context=context)
672+ end_date_contract_id = self.search(cr, uid, [('employee_id', '=', contract.employee_id.id), ], limit=1, order='date_end desc', context=context)
673+ last_end_date = False
674+ if end_date_contract_id:
675+ contract = self.browse(cr, uid, end_date_contract_id, context=context)
676+ last_end_date = contract[0].date_end
677+
678+ if last_end_date:
679+ defaults['date_start'] = datetime.datetime.strftime(datetime.datetime.strptime(last_end_date, "%Y-%m-%d") + datetime.timedelta(days=1), "%Y-%m-%d")
680+ defaults['date_end'] = False
681+ defaults['trial_date_start'] = False
682+ defaults['trial_date_end'] = False
683+ return super(hr_contract, self).copy(cr, uid, id, defaults, context=context)
684+
685+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
686
687=== added directory 'hr_attendance_analysis/i18n'
688=== added file 'hr_attendance_analysis/i18n/hr_attendance_analysis.pot'
689--- hr_attendance_analysis/i18n/hr_attendance_analysis.pot 1970-01-01 00:00:00 +0000
690+++ hr_attendance_analysis/i18n/hr_attendance_analysis.pot 2013-11-07 15:51:52 +0000
691@@ -0,0 +1,564 @@
692+# Translation of OpenERP Server.
693+# This file contains the translation of the following modules:
694+# * hr_attendance_analysis
695+#
696+msgid ""
697+msgstr ""
698+"Project-Id-Version: OpenERP Server 6.0.3\n"
699+"Report-Msgid-Bugs-To: support@openerp.com\n"
700+"POT-Creation-Date: 2011-12-23 10:03+0000\n"
701+"PO-Revision-Date: 2011-12-23 10:03+0000\n"
702+"Last-Translator: <>\n"
703+"Language-Team: \n"
704+"MIME-Version: 1.0\n"
705+"Content-Type: text/plain; charset=UTF-8\n"
706+"Content-Transfer-Encoding: \n"
707+"Plural-Forms: \n"
708+
709+#. module: hr_attendance_analysis
710+#: code:addons/hr_attendance_analysis/hr_attendance.py:123
711+#, python-format
712+msgid "Incongruent data"
713+msgstr ""
714+
715+#. module: hr_attendance_analysis
716+#: code:addons/hr_attendance_analysis/hr_attendance.py:87
717+#: code:addons/hr_attendance_analysis/hr_attendance.py:123
718+#: code:addons/hr_attendance_analysis/hr_attendance.py:189
719+#: code:addons/hr_attendance_analysis/wizard/print_calendar_report.py:58
720+#: code:addons/hr_attendance_analysis/wizard/print_calendar_report.py:129
721+#, python-format
722+msgid "Error"
723+msgstr ""
724+
725+#. module: hr_attendance_analysis
726+#: help:res.company,working_time_precision:0
727+msgid "The precision used to analyse working times over working schedule"
728+msgstr ""
729+
730+#. module: hr_attendance_analysis
731+#: view:hr.attendance:0
732+msgid "Group By..."
733+msgstr ""
734+
735+#. module: hr_attendance_analysis
736+#: code:addons/hr_attendance_analysis/report/calendar_report.py:47
737+#, python-format
738+msgid "Sunday"
739+msgstr ""
740+
741+#. module: hr_attendance_analysis
742+#: field:hr.attendance,end_datetime:0
743+msgid "End date time"
744+msgstr ""
745+
746+#. module: hr_attendance_analysis
747+#: view:hr.attendance:0
748+msgid "Today"
749+msgstr ""
750+
751+#. module: hr_attendance_analysis
752+#: view:hr.attendance:0
753+msgid "Within working schedule"
754+msgstr ""
755+
756+#. module: hr_attendance_analysis
757+#: selection:resource.calendar,attendance_rounding:0
758+#: selection:resource.calendar,leave_rounding:0
759+#: selection:resource.calendar,overtime_rounding:0
760+msgid "20"
761+msgstr ""
762+
763+#. module: hr_attendance_analysis
764+#: code:addons/hr_attendance_analysis/report/calendar_report.py:43
765+#, python-format
766+msgid "Friday"
767+msgstr ""
768+
769+#. module: hr_attendance_analysis
770+#: model:ir.model,name:hr_attendance_analysis.model_attendance_analysis_wizard_calendar_report
771+msgid "attendance_analysis.wizard.calendar_report"
772+msgstr ""
773+
774+#. module: hr_attendance_analysis
775+#: selection:resource.calendar,attendance_rounding:0
776+#: selection:resource.calendar,leave_rounding:0
777+#: selection:resource.calendar,overtime_rounding:0
778+msgid "8"
779+msgstr ""
780+
781+#. module: hr_attendance_analysis
782+#: view:hr.attendance:0
783+msgid "Day"
784+msgstr ""
785+
786+#. module: hr_attendance_analysis
787+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:36
788+msgid "Leave"
789+msgstr ""
790+
791+#. module: hr_attendance_analysis
792+#: field:resource.calendar.overtime.type,limit:0
793+msgid "Limit"
794+msgstr ""
795+
796+#. module: hr_attendance_analysis
797+#: selection:resource.calendar,attendance_rounding:0
798+#: selection:resource.calendar,leave_rounding:0
799+#: selection:resource.calendar,overtime_rounding:0
800+msgid "15"
801+msgstr ""
802+
803+#. module: hr_attendance_analysis
804+#: help:resource.calendar,attendance_rounding:0
805+msgid "For instance, using rounding = 15 minutes, every sign in will be rounded to the following quarter hour and every sign out to the previous quarter hour"
806+msgstr ""
807+
808+#. module: hr_attendance_analysis
809+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:80
810+msgid "Totals"
811+msgstr ""
812+
813+#. module: hr_attendance_analysis
814+#: help:resource.calendar.attendance,tolerance_to:0
815+msgid "Sign in done in the interval \"Work from + Tolerance to\" will be considered done at \"Work from\""
816+msgstr ""
817+
818+#. module: hr_attendance_analysis
819+#: field:resource.calendar.attendance,tolerance_from:0
820+msgid "Tolerance from"
821+msgstr ""
822+
823+#. module: hr_attendance_analysis
824+#: field:attendance_analysis.wizard.calendar_report,from_date:0
825+msgid "From date"
826+msgstr ""
827+
828+#. module: hr_attendance_analysis
829+#: code:addons/hr_attendance_analysis/hr_attendance.py:87
830+#, python-format
831+msgid "Too many active contracts for employee %s"
832+msgstr ""
833+
834+#. module: hr_attendance_analysis
835+#: view:hr.attendance:0
836+msgid "Calendar View"
837+msgstr ""
838+
839+#. module: hr_attendance_analysis
840+#: view:resource.calendar:0
841+msgid "Roundings"
842+msgstr ""
843+
844+#. module: hr_attendance_analysis
845+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:25
846+msgid "Third Sign In"
847+msgstr ""
848+
849+#. module: hr_attendance_analysis
850+#: model:ir.model,name:hr_attendance_analysis.model_hr_attendance
851+msgid "Attendance"
852+msgstr ""
853+
854+#. module: hr_attendance_analysis
855+#: constraint:res.company:0
856+msgid "Error! You can not create recursive companies."
857+msgstr ""
858+
859+#. module: hr_attendance_analysis
860+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:35
861+msgid "Negative"
862+msgstr ""
863+
864+#. module: hr_attendance_analysis
865+#: view:hr.attendance:0
866+msgid "Employee"
867+msgstr ""
868+
869+#. module: hr_attendance_analysis
870+#: view:resource.calendar:0
871+msgid "Type"
872+msgstr ""
873+
874+#. module: hr_attendance_analysis
875+#: view:hr.attendance:0
876+msgid "Hr Attendance Search"
877+msgstr ""
878+
879+#. module: hr_attendance_analysis
880+#: view:hr.attendance:0
881+msgid "Start date time"
882+msgstr ""
883+
884+#. module: hr_attendance_analysis
885+#: help:resource.calendar,overtime_rounding:0
886+msgid "Setting rounding = 30 minutes, an overtime of 29 minutes will be considered as 0 minutes, 31 minutes as 30 minutes, 61 minutes as 1 hour and so on"
887+msgstr ""
888+
889+#. module: hr_attendance_analysis
890+#: field:resource.calendar,attendance_rounding:0
891+msgid "Attendance rounding"
892+msgstr ""
893+
894+#. module: hr_attendance_analysis
895+#: selection:resource.calendar,attendance_rounding:0
896+#: selection:resource.calendar,leave_rounding:0
897+#: selection:resource.calendar,overtime_rounding:0
898+msgid "3"
899+msgstr ""
900+
901+#. module: hr_attendance_analysis
902+#: constraint:hr.attendance:0
903+msgid "Error: Sign in (resp. Sign out) must follow Sign out (resp. Sign in)"
904+msgstr ""
905+
906+#. module: hr_attendance_analysis
907+#: view:res.company:0
908+msgid "Configuration"
909+msgstr ""
910+
911+#. module: hr_attendance_analysis
912+#: code:addons/hr_attendance_analysis/wizard/print_calendar_report.py:58
913+#, python-format
914+msgid "From date must be < to date"
915+msgstr ""
916+
917+#. module: hr_attendance_analysis
918+#: view:hr.attendance:0
919+msgid "Total hours"
920+msgstr ""
921+
922+#. module: hr_attendance_analysis
923+#: field:res.company,working_time_precision:0
924+msgid "Working time precision"
925+msgstr ""
926+
927+#. module: hr_attendance_analysis
928+#: view:hr.attendance:0
929+msgid "Employee attendances analysis"
930+msgstr ""
931+
932+#. module: hr_attendance_analysis
933+#: field:resource.calendar.attendance,tolerance_to:0
934+msgid "Tolerance to"
935+msgstr ""
936+
937+#. module: hr_attendance_analysis
938+#: help:resource.calendar,leave_rounding:0
939+msgid "On the contrary of overtime rounding, using rounding = 15 minutes, a leave of 1 minute will be considered as 15 minutes, 16 minutes as 30 minutes and so on"
940+msgstr ""
941+
942+#. module: hr_attendance_analysis
943+#: model:ir.actions.report.xml,name:hr_attendance_analysis.attendance_analysis_report_id
944+msgid "Attendances Analysis"
945+msgstr ""
946+
947+#. module: hr_attendance_analysis
948+#: selection:resource.calendar,attendance_rounding:0
949+#: selection:resource.calendar,leave_rounding:0
950+#: selection:resource.calendar,overtime_rounding:0
951+msgid "30"
952+msgstr ""
953+
954+#. module: hr_attendance_analysis
955+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:110
956+#: model:ir.model,name:hr_attendance_analysis.model_resource_calendar_overtime_type
957+msgid "Overtime type"
958+msgstr ""
959+
960+#. module: hr_attendance_analysis
961+#: field:hr.attendance,inside_calendar_duration:0
962+msgid "Duration within working schedule"
963+msgstr ""
964+
965+#. module: hr_attendance_analysis
966+#: field:resource.calendar,leave_rounding:0
967+msgid "Leave rounding"
968+msgstr ""
969+
970+#. module: hr_attendance_analysis
971+#: field:resource.calendar.overtime.type,calendar_id:0
972+msgid "Calendar"
973+msgstr ""
974+
975+#. module: hr_attendance_analysis
976+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:32
977+msgid "Due"
978+msgstr ""
979+
980+#. module: hr_attendance_analysis
981+#: view:attendance_analysis.wizard.calendar_report:0
982+#: model:ir.actions.act_window,name:hr_attendance_analysis.action_wizard_calendar_report
983+#: model:ir.ui.menu,name:hr_attendance_analysis.menu_action_wizard_calendar_report
984+msgid "Attendances Analysis Calendar"
985+msgstr ""
986+
987+#. module: hr_attendance_analysis
988+#: selection:resource.calendar,attendance_rounding:0
989+#: selection:resource.calendar,leave_rounding:0
990+#: selection:resource.calendar,overtime_rounding:0
991+msgid "60"
992+msgstr ""
993+
994+#. module: hr_attendance_analysis
995+#: view:resource.calendar:0
996+#: field:resource.calendar,overtime_type_ids:0
997+msgid "Overtime types"
998+msgstr ""
999+
1000+#. module: hr_attendance_analysis
1001+#: code:addons/hr_attendance_analysis/report/calendar_report.py:35
1002+#, python-format
1003+msgid "Monday"
1004+msgstr ""
1005+
1006+#. module: hr_attendance_analysis
1007+#: field:attendance_analysis.wizard.calendar_report,employee_ids:0
1008+msgid "unknown"
1009+msgstr ""
1010+
1011+#. module: hr_attendance_analysis
1012+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:18
1013+msgid "First Sign Out"
1014+msgstr ""
1015+
1016+#. module: hr_attendance_analysis
1017+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:15
1018+msgid "Day of week"
1019+msgstr ""
1020+
1021+#. module: hr_attendance_analysis
1022+#: field:resource.calendar,overtime_rounding_tolerance:0
1023+msgid "Overtime rounding tolerance"
1024+msgstr ""
1025+
1026+#. module: hr_attendance_analysis
1027+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:29
1028+msgid "Fourth Sign In"
1029+msgstr ""
1030+
1031+#. module: hr_attendance_analysis
1032+#: code:addons/hr_attendance_analysis/wizard/print_calendar_report.py:130
1033+#, python-format
1034+msgid "%s: 'Work to' is < 'Work from'"
1035+msgstr ""
1036+
1037+#. module: hr_attendance_analysis
1038+#: selection:resource.calendar,attendance_rounding:0
1039+#: selection:resource.calendar,leave_rounding:0
1040+#: selection:resource.calendar,overtime_rounding:0
1041+msgid "2"
1042+msgstr ""
1043+
1044+#. module: hr_attendance_analysis
1045+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:10
1046+msgid "Employee: "
1047+msgstr ""
1048+
1049+#. module: hr_attendance_analysis
1050+#: selection:resource.calendar,attendance_rounding:0
1051+#: selection:resource.calendar,leave_rounding:0
1052+#: selection:resource.calendar,overtime_rounding:0
1053+msgid "6"
1054+msgstr ""
1055+
1056+#. module: hr_attendance_analysis
1057+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:14
1058+msgid "Date"
1059+msgstr ""
1060+
1061+#. module: hr_attendance_analysis
1062+#: model:ir.module.module,shortdesc:hr_attendance_analysis.module_meta_information
1063+msgid "HR - Attendance Analysis"
1064+msgstr ""
1065+
1066+#. module: hr_attendance_analysis
1067+#: code:addons/hr_attendance_analysis/hr_attendance.py:190
1068+#, python-format
1069+msgid "Wrongly configured working schedule with id %s"
1070+msgstr ""
1071+
1072+#. module: hr_attendance_analysis
1073+#: model:ir.model,name:hr_attendance_analysis.model_res_company
1074+msgid "Companies"
1075+msgstr ""
1076+
1077+#. module: hr_attendance_analysis
1078+#: code:addons/hr_attendance_analysis/report/calendar_report.py:39
1079+#, python-format
1080+msgid "Wednesday"
1081+msgstr ""
1082+
1083+#. module: hr_attendance_analysis
1084+#: field:resource.calendar.overtime.type,name:0
1085+msgid "Type Description"
1086+msgstr ""
1087+
1088+#. module: hr_attendance_analysis
1089+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:17
1090+msgid "First Sign In"
1091+msgstr ""
1092+
1093+#. module: hr_attendance_analysis
1094+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:30
1095+msgid "Fourth Sign Out"
1096+msgstr ""
1097+
1098+#. module: hr_attendance_analysis
1099+#: model:ir.module.module,description:hr_attendance_analysis.module_meta_information
1100+msgid "\n"
1101+"Dynamic reports based on employee's attendances and contract's calendar.\n"
1102+"Among other things, it lets you see the amount of working hours outside and inside the contract's working schedule (overtime).\n"
1103+"It also provides a daily based report, showing the detailed and total hours compared to calendar hours.\n"
1104+""
1105+msgstr ""
1106+
1107+#. module: hr_attendance_analysis
1108+#: selection:resource.calendar,attendance_rounding:0
1109+#: selection:resource.calendar,leave_rounding:0
1110+#: selection:resource.calendar,overtime_rounding:0
1111+msgid "10"
1112+msgstr ""
1113+
1114+#. module: hr_attendance_analysis
1115+#: selection:resource.calendar,attendance_rounding:0
1116+#: selection:resource.calendar,leave_rounding:0
1117+#: selection:resource.calendar,overtime_rounding:0
1118+msgid "12"
1119+msgstr ""
1120+
1121+#. module: hr_attendance_analysis
1122+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:22
1123+msgid "Second Sign Out"
1124+msgstr ""
1125+
1126+#. module: hr_attendance_analysis
1127+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:34
1128+#: view:hr.attendance:0
1129+#: field:hr.attendance,outside_calendar_duration:0
1130+msgid "Overtime"
1131+msgstr ""
1132+
1133+#. module: hr_attendance_analysis
1134+#: model:ir.model,name:hr_attendance_analysis.model_resource_calendar_attendance
1135+msgid "Work Detail"
1136+msgstr ""
1137+
1138+#. module: hr_attendance_analysis
1139+#: help:resource.calendar.attendance,tolerance_from:0
1140+msgid "Sign out done in the interval \"Work to - Tolerance from\" will be considered done at \"Work to\""
1141+msgstr ""
1142+
1143+#. module: hr_attendance_analysis
1144+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:21
1145+msgid "Second Sign In"
1146+msgstr ""
1147+
1148+#. module: hr_attendance_analysis
1149+#: view:attendance_analysis.wizard.calendar_report:0
1150+msgid "Cancel"
1151+msgstr ""
1152+
1153+#. module: hr_attendance_analysis
1154+#: code:addons/hr_attendance_analysis/report/calendar_report.py:37
1155+#, python-format
1156+msgid "Tuesday"
1157+msgstr ""
1158+
1159+#. module: hr_attendance_analysis
1160+#: model:ir.actions.act_window,name:hr_attendance_analysis.open_view_attendance
1161+#: model:ir.ui.menu,name:hr_attendance_analysis.menu_open_view_attendance
1162+msgid "Attendances analysis"
1163+msgstr ""
1164+
1165+#. module: hr_attendance_analysis
1166+#: code:addons/hr_attendance_analysis/report/calendar_report.py:41
1167+#, python-format
1168+msgid "Thursday"
1169+msgstr ""
1170+
1171+#. module: hr_attendance_analysis
1172+#: view:attendance_analysis.wizard.calendar_report:0
1173+msgid "Print"
1174+msgstr ""
1175+
1176+#. module: hr_attendance_analysis
1177+#: model:ir.model,name:hr_attendance_analysis.model_resource_calendar
1178+msgid "Resource Calendar"
1179+msgstr ""
1180+
1181+#. module: hr_attendance_analysis
1182+#: field:hr.attendance,duration:0
1183+msgid "Attendance duration"
1184+msgstr ""
1185+
1186+#. module: hr_attendance_analysis
1187+#: selection:resource.calendar,attendance_rounding:0
1188+#: selection:resource.calendar,leave_rounding:0
1189+#: selection:resource.calendar,overtime_rounding:0
1190+msgid "1"
1191+msgstr ""
1192+
1193+#. module: hr_attendance_analysis
1194+#: field:attendance_analysis.wizard.calendar_report,to_date:0
1195+msgid "To date"
1196+msgstr ""
1197+
1198+#. module: hr_attendance_analysis
1199+#: selection:resource.calendar,attendance_rounding:0
1200+#: selection:resource.calendar,leave_rounding:0
1201+#: selection:resource.calendar,overtime_rounding:0
1202+msgid "5"
1203+msgstr ""
1204+
1205+#. module: hr_attendance_analysis
1206+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:33
1207+msgid "Working Hours"
1208+msgstr ""
1209+
1210+#. module: hr_attendance_analysis
1211+#: view:resource.calendar:0
1212+msgid "Types"
1213+msgstr ""
1214+
1215+#. module: hr_attendance_analysis
1216+#: field:resource.calendar,overtime_rounding:0
1217+msgid "Overtime rounding"
1218+msgstr ""
1219+
1220+#. module: hr_attendance_analysis
1221+#: view:attendance_analysis.wizard.calendar_report:0
1222+msgid "Employees"
1223+msgstr ""
1224+
1225+#. module: hr_attendance_analysis
1226+#: help:resource.calendar.overtime.type,limit:0
1227+msgid "Limit, in hours, of overtime that can be imputed to this type of overtime in a day. The surplus is imputed to the subsequent type"
1228+msgstr ""
1229+
1230+#. module: hr_attendance_analysis
1231+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:26
1232+msgid "Third Sign Out"
1233+msgstr ""
1234+
1235+#. module: hr_attendance_analysis
1236+#: help:resource.calendar,overtime_rounding_tolerance:0
1237+msgid "Overtime can be rounded using a tolerance. Using tolerance = 3 minutes and rounding = 15 minutes, if employee does overtime of 12 minutes, it will be considered as 15 minutes."
1238+msgstr ""
1239+
1240+#. module: hr_attendance_analysis
1241+#: field:resource.calendar.overtime.type,sequence:0
1242+msgid "Sequence"
1243+msgstr ""
1244+
1245+#. module: hr_attendance_analysis
1246+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:111
1247+msgid "Total"
1248+msgstr ""
1249+
1250+#. module: hr_attendance_analysis
1251+#: code:addons/hr_attendance_analysis/report/calendar_report.py:45
1252+#, python-format
1253+msgid "Saturday"
1254+msgstr ""
1255+
1256
1257=== added file 'hr_attendance_analysis/i18n/it.po'
1258--- hr_attendance_analysis/i18n/it.po 1970-01-01 00:00:00 +0000
1259+++ hr_attendance_analysis/i18n/it.po 2013-11-07 15:51:52 +0000
1260@@ -0,0 +1,611 @@
1261+# Translation of OpenERP Server.
1262+# This file contains the translation of the following modules:
1263+# * hr_attendance_analysis
1264+#
1265+msgid ""
1266+msgstr ""
1267+"Project-Id-Version: OpenERP Server 6.0.3\n"
1268+"Report-Msgid-Bugs-To: support@openerp.com\n"
1269+"POT-Creation-Date: 2011-12-23 10:03+0000\n"
1270+"PO-Revision-Date: 2013-09-22 17:18+0000\n"
1271+"Last-Translator: Lorenzo Battistini - Agile BG "
1272+"<lorenzo.battistini@agilebg.com>\n"
1273+"Language-Team: \n"
1274+"MIME-Version: 1.0\n"
1275+"Content-Type: text/plain; charset=UTF-8\n"
1276+"Content-Transfer-Encoding: 8bit\n"
1277+"X-Launchpad-Export-Date: 2013-10-16 05:12+0000\n"
1278+"X-Generator: Launchpad (build 16799)\n"
1279+
1280+#. module: hr_attendance_analysis
1281+#: code:addons/hr_attendance_analysis/hr_attendance.py:123
1282+#, python-format
1283+msgid "Incongruent data"
1284+msgstr ""
1285+
1286+#. module: hr_attendance_analysis
1287+#: code:addons/hr_attendance_analysis/hr_attendance.py:87
1288+#: code:addons/hr_attendance_analysis/hr_attendance.py:123
1289+#: code:addons/hr_attendance_analysis/hr_attendance.py:189
1290+#: code:addons/hr_attendance_analysis/wizard/print_calendar_report.py:58
1291+#: code:addons/hr_attendance_analysis/wizard/print_calendar_report.py:129
1292+#, python-format
1293+msgid "Error"
1294+msgstr "Errore"
1295+
1296+#. module: hr_attendance_analysis
1297+#: help:res.company,working_time_precision:0
1298+msgid "The precision used to analyse working times over working schedule"
1299+msgstr ""
1300+"La precisione utilizzata per analizzare le ore lavorative rispetto al "
1301+"calendario di lavoro"
1302+
1303+#. module: hr_attendance_analysis
1304+#: view:hr.attendance:0
1305+msgid "Group By..."
1306+msgstr "Raggruppa per..."
1307+
1308+#. module: hr_attendance_analysis
1309+#: code:addons/hr_attendance_analysis/report/calendar_report.py:47
1310+#, python-format
1311+msgid "Sunday"
1312+msgstr "Domenica"
1313+
1314+#. module: hr_attendance_analysis
1315+#: field:hr.attendance,end_datetime:0
1316+msgid "End date time"
1317+msgstr "Data e ora di fine"
1318+
1319+#. module: hr_attendance_analysis
1320+#: view:hr.attendance:0
1321+msgid "Today"
1322+msgstr "Oggi"
1323+
1324+#. module: hr_attendance_analysis
1325+#: view:hr.attendance:0
1326+msgid "Within working schedule"
1327+msgstr "All'interno del calendario di lavoro"
1328+
1329+#. module: hr_attendance_analysis
1330+#: selection:resource.calendar,attendance_rounding:0
1331+#: selection:resource.calendar,leave_rounding:0
1332+#: selection:resource.calendar,overtime_rounding:0
1333+msgid "20"
1334+msgstr "20"
1335+
1336+#. module: hr_attendance_analysis
1337+#: code:addons/hr_attendance_analysis/report/calendar_report.py:43
1338+#, python-format
1339+msgid "Friday"
1340+msgstr "Venerdì"
1341+
1342+#. module: hr_attendance_analysis
1343+#: model:ir.model,name:hr_attendance_analysis.model_attendance_analysis_wizard_calendar_report
1344+msgid "attendance_analysis.wizard.calendar_report"
1345+msgstr "attendance_analysis.wizard.calendar_report"
1346+
1347+#. module: hr_attendance_analysis
1348+#: selection:resource.calendar,attendance_rounding:0
1349+#: selection:resource.calendar,leave_rounding:0
1350+#: selection:resource.calendar,overtime_rounding:0
1351+msgid "8"
1352+msgstr "8"
1353+
1354+#. module: hr_attendance_analysis
1355+#: view:hr.attendance:0
1356+msgid "Day"
1357+msgstr "Giorno"
1358+
1359+#. module: hr_attendance_analysis
1360+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:36
1361+msgid "Leave"
1362+msgstr "Assenza"
1363+
1364+#. module: hr_attendance_analysis
1365+#: field:resource.calendar.overtime.type,limit:0
1366+msgid "Limit"
1367+msgstr "Limite"
1368+
1369+#. module: hr_attendance_analysis
1370+#: selection:resource.calendar,attendance_rounding:0
1371+#: selection:resource.calendar,leave_rounding:0
1372+#: selection:resource.calendar,overtime_rounding:0
1373+msgid "15"
1374+msgstr "15"
1375+
1376+#. module: hr_attendance_analysis
1377+#: help:resource.calendar,attendance_rounding:0
1378+msgid ""
1379+"For instance, using rounding = 15 minutes, every sign in will be rounded to "
1380+"the following quarter hour and every sign out to the previous quarter hour"
1381+msgstr ""
1382+"Per esempio, utilizzando un arrotondamento = 15 minuti, ogni entrata verrà "
1383+"arrotondata al quarto d'ora successivo ed ogni uscita al quarto d'ora "
1384+"precedente"
1385+
1386+#. module: hr_attendance_analysis
1387+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:80
1388+msgid "Totals"
1389+msgstr "Totali"
1390+
1391+#. module: hr_attendance_analysis
1392+#: help:resource.calendar.attendance,tolerance_to:0
1393+msgid ""
1394+"Sign in done in the interval \"Work from + Tolerance to\" will be considered "
1395+"done at \"Work from\""
1396+msgstr ""
1397+"Le entrate effettuate nell'intervallo \"Lavoro da + Tolleranza a\" saranno "
1398+"considerate come fatte in \"Lavoro da\""
1399+
1400+#. module: hr_attendance_analysis
1401+#: field:resource.calendar.attendance,tolerance_from:0
1402+msgid "Tolerance from"
1403+msgstr "Tolleranza da"
1404+
1405+#. module: hr_attendance_analysis
1406+#: field:attendance_analysis.wizard.calendar_report,from_date:0
1407+msgid "From date"
1408+msgstr "Dalla data"
1409+
1410+#. module: hr_attendance_analysis
1411+#: code:addons/hr_attendance_analysis/hr_attendance.py:87
1412+#, python-format
1413+msgid "Too many active contracts for employee %s"
1414+msgstr "Troppi contratti attivi per il dipendente %s"
1415+
1416+#. module: hr_attendance_analysis
1417+#: view:hr.attendance:0
1418+msgid "Calendar View"
1419+msgstr "Vista calendario"
1420+
1421+#. module: hr_attendance_analysis
1422+#: view:resource.calendar:0
1423+msgid "Roundings"
1424+msgstr "Arrotondamenti"
1425+
1426+#. module: hr_attendance_analysis
1427+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:25
1428+msgid "Third Sign In"
1429+msgstr "Terza entrata"
1430+
1431+#. module: hr_attendance_analysis
1432+#: model:ir.model,name:hr_attendance_analysis.model_hr_attendance
1433+msgid "Attendance"
1434+msgstr "Presenze"
1435+
1436+#. module: hr_attendance_analysis
1437+#: constraint:res.company:0
1438+msgid "Error! You can not create recursive companies."
1439+msgstr "Errore! Non è possibile creare aziende ricorsive."
1440+
1441+#. module: hr_attendance_analysis
1442+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:35
1443+msgid "Negative"
1444+msgstr "Negativo"
1445+
1446+#. module: hr_attendance_analysis
1447+#: view:hr.attendance:0
1448+msgid "Employee"
1449+msgstr "Dipendente"
1450+
1451+#. module: hr_attendance_analysis
1452+#: view:resource.calendar:0
1453+msgid "Type"
1454+msgstr "Tipo"
1455+
1456+#. module: hr_attendance_analysis
1457+#: view:hr.attendance:0
1458+msgid "Hr Attendance Search"
1459+msgstr "HR cerca presenza"
1460+
1461+#. module: hr_attendance_analysis
1462+#: view:hr.attendance:0
1463+msgid "Start date time"
1464+msgstr "Data e ora di inizio"
1465+
1466+#. module: hr_attendance_analysis
1467+#: help:resource.calendar,overtime_rounding:0
1468+msgid ""
1469+"Setting rounding = 30 minutes, an overtime of 29 minutes will be considered "
1470+"as 0 minutes, 31 minutes as 30 minutes, 61 minutes as 1 hour and so on"
1471+msgstr ""
1472+"Impostando un arrotondamento = 30 minuti, uno straordinario di 29 minuti "
1473+"sarà considerato come 0 minuti, 31 minuti come 30 minuti, 61 minuti come "
1474+"un'ora e così via"
1475+
1476+#. module: hr_attendance_analysis
1477+#: field:resource.calendar,attendance_rounding:0
1478+msgid "Attendance rounding"
1479+msgstr "Arrotondamento presenza"
1480+
1481+#. module: hr_attendance_analysis
1482+#: selection:resource.calendar,attendance_rounding:0
1483+#: selection:resource.calendar,leave_rounding:0
1484+#: selection:resource.calendar,overtime_rounding:0
1485+msgid "3"
1486+msgstr "3"
1487+
1488+#. module: hr_attendance_analysis
1489+#: constraint:hr.attendance:0
1490+msgid "Error: Sign in (resp. Sign out) must follow Sign out (resp. Sign in)"
1491+msgstr ""
1492+"Errore: una operazione di Entrata (Uscita) deve essere seguito da una Uscita "
1493+"(Entrata)"
1494+
1495+#. module: hr_attendance_analysis
1496+#: view:res.company:0
1497+msgid "Configuration"
1498+msgstr "Configurazione"
1499+
1500+#. module: hr_attendance_analysis
1501+#: code:addons/hr_attendance_analysis/wizard/print_calendar_report.py:58
1502+#, python-format
1503+msgid "From date must be < to date"
1504+msgstr "\"Dalla data\" deve essere < di \"alla data\""
1505+
1506+#. module: hr_attendance_analysis
1507+#: view:hr.attendance:0
1508+msgid "Total hours"
1509+msgstr "Ore totali"
1510+
1511+#. module: hr_attendance_analysis
1512+#: field:res.company,working_time_precision:0
1513+msgid "Working time precision"
1514+msgstr "Precisione orario lavorativo"
1515+
1516+#. module: hr_attendance_analysis
1517+#: view:hr.attendance:0
1518+msgid "Employee attendances analysis"
1519+msgstr "Analisi presenze dipendente"
1520+
1521+#. module: hr_attendance_analysis
1522+#: field:resource.calendar.attendance,tolerance_to:0
1523+msgid "Tolerance to"
1524+msgstr "Tolleranza a"
1525+
1526+#. module: hr_attendance_analysis
1527+#: help:resource.calendar,leave_rounding:0
1528+msgid ""
1529+"On the contrary of overtime rounding, using rounding = 15 minutes, a leave "
1530+"of 1 minute will be considered as 15 minutes, 16 minutes as 30 minutes and "
1531+"so on"
1532+msgstr ""
1533+"Al contrario dell'arrotondamento straordinari, utilizzando un arrotondamento "
1534+"= 15 minuti, un'assenza di 1 minuto verrà considerata come di 15 minuti, 16 "
1535+"minuti come 30 minuti e così via"
1536+
1537+#. module: hr_attendance_analysis
1538+#: model:ir.actions.report.xml,name:hr_attendance_analysis.attendance_analysis_report_id
1539+msgid "Attendances Analysis"
1540+msgstr "Analisi presenze"
1541+
1542+#. module: hr_attendance_analysis
1543+#: selection:resource.calendar,attendance_rounding:0
1544+#: selection:resource.calendar,leave_rounding:0
1545+#: selection:resource.calendar,overtime_rounding:0
1546+msgid "30"
1547+msgstr "30"
1548+
1549+#. module: hr_attendance_analysis
1550+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:110
1551+#: model:ir.model,name:hr_attendance_analysis.model_resource_calendar_overtime_type
1552+msgid "Overtime type"
1553+msgstr "Tipo di straordinario"
1554+
1555+#. module: hr_attendance_analysis
1556+#: field:hr.attendance,inside_calendar_duration:0
1557+msgid "Duration within working schedule"
1558+msgstr "Durata all'interno del calendario lavorativo"
1559+
1560+#. module: hr_attendance_analysis
1561+#: field:resource.calendar,leave_rounding:0
1562+msgid "Leave rounding"
1563+msgstr "Arrotonamento assenza"
1564+
1565+#. module: hr_attendance_analysis
1566+#: field:resource.calendar.overtime.type,calendar_id:0
1567+msgid "Calendar"
1568+msgstr "Calendario"
1569+
1570+#. module: hr_attendance_analysis
1571+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:32
1572+msgid "Due"
1573+msgstr "Dovuto"
1574+
1575+#. module: hr_attendance_analysis
1576+#: view:attendance_analysis.wizard.calendar_report:0
1577+#: model:ir.actions.act_window,name:hr_attendance_analysis.action_wizard_calendar_report
1578+#: model:ir.ui.menu,name:hr_attendance_analysis.menu_action_wizard_calendar_report
1579+msgid "Attendances Analysis Calendar"
1580+msgstr "Calendario di analisi presenze"
1581+
1582+#. module: hr_attendance_analysis
1583+#: selection:resource.calendar,attendance_rounding:0
1584+#: selection:resource.calendar,leave_rounding:0
1585+#: selection:resource.calendar,overtime_rounding:0
1586+msgid "60"
1587+msgstr "60"
1588+
1589+#. module: hr_attendance_analysis
1590+#: view:resource.calendar:0
1591+#: field:resource.calendar,overtime_type_ids:0
1592+msgid "Overtime types"
1593+msgstr "Tipi di straordinario"
1594+
1595+#. module: hr_attendance_analysis
1596+#: code:addons/hr_attendance_analysis/report/calendar_report.py:35
1597+#, python-format
1598+msgid "Monday"
1599+msgstr "Lunedì"
1600+
1601+#. module: hr_attendance_analysis
1602+#: field:attendance_analysis.wizard.calendar_report,employee_ids:0
1603+msgid "unknown"
1604+msgstr "sconosciuto"
1605+
1606+#. module: hr_attendance_analysis
1607+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:18
1608+msgid "First Sign Out"
1609+msgstr "Prima uscita"
1610+
1611+#. module: hr_attendance_analysis
1612+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:15
1613+msgid "Day of week"
1614+msgstr "Giorno della settimana"
1615+
1616+#. module: hr_attendance_analysis
1617+#: field:resource.calendar,overtime_rounding_tolerance:0
1618+msgid "Overtime rounding tolerance"
1619+msgstr "Tolleranza arrotondamento straordinari"
1620+
1621+#. module: hr_attendance_analysis
1622+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:29
1623+msgid "Fourth Sign In"
1624+msgstr "Quarta entrata"
1625+
1626+#. module: hr_attendance_analysis
1627+#: code:addons/hr_attendance_analysis/wizard/print_calendar_report.py:130
1628+#, python-format
1629+msgid "%s: 'Work to' is < 'Work from'"
1630+msgstr "%s: 'Lavoro a' è < 'Lavoro da'"
1631+
1632+#. module: hr_attendance_analysis
1633+#: selection:resource.calendar,attendance_rounding:0
1634+#: selection:resource.calendar,leave_rounding:0
1635+#: selection:resource.calendar,overtime_rounding:0
1636+msgid "2"
1637+msgstr "2"
1638+
1639+#. module: hr_attendance_analysis
1640+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:10
1641+msgid "Employee: "
1642+msgstr "Dipendente: "
1643+
1644+#. module: hr_attendance_analysis
1645+#: selection:resource.calendar,attendance_rounding:0
1646+#: selection:resource.calendar,leave_rounding:0
1647+#: selection:resource.calendar,overtime_rounding:0
1648+msgid "6"
1649+msgstr "6"
1650+
1651+#. module: hr_attendance_analysis
1652+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:14
1653+msgid "Date"
1654+msgstr "Data"
1655+
1656+#. module: hr_attendance_analysis
1657+#: model:ir.module.module,shortdesc:hr_attendance_analysis.module_meta_information
1658+msgid "HR - Attendance Analysis"
1659+msgstr "HR - Analisi presenze"
1660+
1661+#. module: hr_attendance_analysis
1662+#: code:addons/hr_attendance_analysis/hr_attendance.py:190
1663+#, python-format
1664+msgid "Wrongly configured working schedule with id %s"
1665+msgstr "Calendario lavorativo con id %s configurato in modo scorretto"
1666+
1667+#. module: hr_attendance_analysis
1668+#: model:ir.model,name:hr_attendance_analysis.model_res_company
1669+msgid "Companies"
1670+msgstr "Aziende"
1671+
1672+#. module: hr_attendance_analysis
1673+#: code:addons/hr_attendance_analysis/report/calendar_report.py:39
1674+#, python-format
1675+msgid "Wednesday"
1676+msgstr "Mercoledì"
1677+
1678+#. module: hr_attendance_analysis
1679+#: field:resource.calendar.overtime.type,name:0
1680+msgid "Type Description"
1681+msgstr "Descrizione tipo"
1682+
1683+#. module: hr_attendance_analysis
1684+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:17
1685+msgid "First Sign In"
1686+msgstr "Prima entrata"
1687+
1688+#. module: hr_attendance_analysis
1689+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:30
1690+msgid "Fourth Sign Out"
1691+msgstr "Quarta uscita"
1692+
1693+#. module: hr_attendance_analysis
1694+#: model:ir.module.module,description:hr_attendance_analysis.module_meta_information
1695+msgid ""
1696+"\n"
1697+"Dynamic reports based on employee's attendances and contract's calendar.\n"
1698+"Among other things, it lets you see the amount of working hours outside and "
1699+"inside the contract's working schedule (overtime).\n"
1700+"It also provides a daily based report, showing the detailed and total hours "
1701+"compared to calendar hours.\n"
1702+msgstr ""
1703+"\n"
1704+"Dynamic reports based on employee's attendances and contract's calendar.\n"
1705+"Among other things, it lets you see the amount of working hours outside and "
1706+"inside the contract's working schedule (overtime).\n"
1707+"It also provides a daily based report, showing the detailed and total hours "
1708+"compared to calendar hours.\n"
1709+
1710+#. module: hr_attendance_analysis
1711+#: selection:resource.calendar,attendance_rounding:0
1712+#: selection:resource.calendar,leave_rounding:0
1713+#: selection:resource.calendar,overtime_rounding:0
1714+msgid "10"
1715+msgstr "10"
1716+
1717+#. module: hr_attendance_analysis
1718+#: selection:resource.calendar,attendance_rounding:0
1719+#: selection:resource.calendar,leave_rounding:0
1720+#: selection:resource.calendar,overtime_rounding:0
1721+msgid "12"
1722+msgstr "12"
1723+
1724+#. module: hr_attendance_analysis
1725+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:22
1726+msgid "Second Sign Out"
1727+msgstr "Seconda uscita"
1728+
1729+#. module: hr_attendance_analysis
1730+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:34
1731+#: view:hr.attendance:0
1732+#: field:hr.attendance,outside_calendar_duration:0
1733+msgid "Overtime"
1734+msgstr "Straordinario"
1735+
1736+#. module: hr_attendance_analysis
1737+#: model:ir.model,name:hr_attendance_analysis.model_resource_calendar_attendance
1738+msgid "Work Detail"
1739+msgstr "Dettagli del lavoro"
1740+
1741+#. module: hr_attendance_analysis
1742+#: help:resource.calendar.attendance,tolerance_from:0
1743+msgid ""
1744+"Sign out done in the interval \"Work to - Tolerance from\" will be "
1745+"considered done at \"Work to\""
1746+msgstr ""
1747+"Le uscite effettuate nell'intervallo \"Lavoro a - Tolleranza da\" saranno "
1748+"considerate come fatte in \"Lavoro a\""
1749+
1750+#. module: hr_attendance_analysis
1751+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:21
1752+msgid "Second Sign In"
1753+msgstr "Seconda entrata"
1754+
1755+#. module: hr_attendance_analysis
1756+#: view:attendance_analysis.wizard.calendar_report:0
1757+msgid "Cancel"
1758+msgstr "Annulla"
1759+
1760+#. module: hr_attendance_analysis
1761+#: code:addons/hr_attendance_analysis/report/calendar_report.py:37
1762+#, python-format
1763+msgid "Tuesday"
1764+msgstr "Martedì"
1765+
1766+#. module: hr_attendance_analysis
1767+#: model:ir.actions.act_window,name:hr_attendance_analysis.open_view_attendance
1768+#: model:ir.ui.menu,name:hr_attendance_analysis.menu_open_view_attendance
1769+msgid "Attendances analysis"
1770+msgstr "Analisi presenze"
1771+
1772+#. module: hr_attendance_analysis
1773+#: code:addons/hr_attendance_analysis/report/calendar_report.py:41
1774+#, python-format
1775+msgid "Thursday"
1776+msgstr "Giovedì"
1777+
1778+#. module: hr_attendance_analysis
1779+#: view:attendance_analysis.wizard.calendar_report:0
1780+msgid "Print"
1781+msgstr "Stampa"
1782+
1783+#. module: hr_attendance_analysis
1784+#: model:ir.model,name:hr_attendance_analysis.model_resource_calendar
1785+msgid "Resource Calendar"
1786+msgstr "Calendario risorse"
1787+
1788+#. module: hr_attendance_analysis
1789+#: field:hr.attendance,duration:0
1790+msgid "Attendance duration"
1791+msgstr "Durata presenza"
1792+
1793+#. module: hr_attendance_analysis
1794+#: selection:resource.calendar,attendance_rounding:0
1795+#: selection:resource.calendar,leave_rounding:0
1796+#: selection:resource.calendar,overtime_rounding:0
1797+msgid "1"
1798+msgstr "1"
1799+
1800+#. module: hr_attendance_analysis
1801+#: field:attendance_analysis.wizard.calendar_report,to_date:0
1802+msgid "To date"
1803+msgstr "Alla data"
1804+
1805+#. module: hr_attendance_analysis
1806+#: selection:resource.calendar,attendance_rounding:0
1807+#: selection:resource.calendar,leave_rounding:0
1808+#: selection:resource.calendar,overtime_rounding:0
1809+msgid "5"
1810+msgstr "5"
1811+
1812+#. module: hr_attendance_analysis
1813+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:33
1814+msgid "Working Hours"
1815+msgstr "Ore lavorative"
1816+
1817+#. module: hr_attendance_analysis
1818+#: view:resource.calendar:0
1819+msgid "Types"
1820+msgstr "Tipi"
1821+
1822+#. module: hr_attendance_analysis
1823+#: field:resource.calendar,overtime_rounding:0
1824+msgid "Overtime rounding"
1825+msgstr "Arrotondamento straordinario"
1826+
1827+#. module: hr_attendance_analysis
1828+#: view:attendance_analysis.wizard.calendar_report:0
1829+msgid "Employees"
1830+msgstr "Dipendenti"
1831+
1832+#. module: hr_attendance_analysis
1833+#: help:resource.calendar.overtime.type,limit:0
1834+msgid ""
1835+"Limit, in hours, of overtime that can be imputed to this type of overtime in "
1836+"a day. The surplus is imputed to the subsequent type"
1837+msgstr ""
1838+"Limite, in ore, dello straordinario che può essere attribuito a questo tipo "
1839+"di straordinario in un giorno. L'eccedenza è attribuita al tipo successivo."
1840+
1841+#. module: hr_attendance_analysis
1842+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:26
1843+msgid "Third Sign Out"
1844+msgstr "Terza uscita"
1845+
1846+#. module: hr_attendance_analysis
1847+#: help:resource.calendar,overtime_rounding_tolerance:0
1848+msgid ""
1849+"Overtime can be rounded using a tolerance. Using tolerance = 3 minutes and "
1850+"rounding = 15 minutes, if employee does overtime of 12 minutes, it will be "
1851+"considered as 15 minutes."
1852+msgstr ""
1853+"Lo straordinario può essere arrotondato usando una tolleranza. Con una "
1854+"tolleranza = 3 minuti e arrotondamento = 15 minuti, se il dipendente fa uno "
1855+"straordinario di 12 minuti, sarà considerato come 15 minuti."
1856+
1857+#. module: hr_attendance_analysis
1858+#: field:resource.calendar.overtime.type,sequence:0
1859+msgid "Sequence"
1860+msgstr "Sequenza"
1861+
1862+#. module: hr_attendance_analysis
1863+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:111
1864+msgid "Total"
1865+msgstr "Totale"
1866+
1867+#. module: hr_attendance_analysis
1868+#: code:addons/hr_attendance_analysis/report/calendar_report.py:45
1869+#, python-format
1870+msgid "Saturday"
1871+msgstr "Sabato"
1872
1873=== added directory 'hr_attendance_analysis/report'
1874=== added file 'hr_attendance_analysis/report/__init__.py'
1875--- hr_attendance_analysis/report/__init__.py 1970-01-01 00:00:00 +0000
1876+++ hr_attendance_analysis/report/__init__.py 2013-11-07 15:51:52 +0000
1877@@ -0,0 +1,21 @@
1878+# -*- coding: utf-8 -*-
1879+##############################################################################
1880+#
1881+# Copyright (C) 2011 Agile Business Group sagl (<http://www.agilebg.com>)
1882+# Copyright (C) 2011 Domsense srl (<http://www.domsense.com>)
1883+#
1884+# This program is free software: you can redistribute it and/or modify
1885+# it under the terms of the GNU Affero General Public License as published
1886+# by the Free Software Foundation, either version 3 of the License, or
1887+# (at your option) any later version.
1888+#
1889+# This program is distributed in the hope that it will be useful,
1890+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1891+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1892+# GNU General Public License for more details.
1893+#
1894+# You should have received a copy of the GNU Affero General Public License
1895+# along with this program. If not, see <http://www.gnu.org/licenses/>.
1896+#
1897+##############################################################################
1898+import calendar_report
1899
1900=== added file 'hr_attendance_analysis/report/calendar_report.mako'
1901--- hr_attendance_analysis/report/calendar_report.mako 1970-01-01 00:00:00 +0000
1902+++ hr_attendance_analysis/report/calendar_report.mako 2013-11-07 15:51:52 +0000
1903@@ -0,0 +1,138 @@
1904+<html>
1905+<head>
1906+ <style type="text/css">
1907+ ${css}
1908+ </style>
1909+</head>
1910+<body>
1911+ <% setLang(objects[0].company_id.partner_id.lang) %>
1912+ <% from datetime import datetime %>
1913+ %for employee in objects :
1914+ <h2>${_("Employee: ")} ${ employee.name or ''|entity }</h2>
1915+ <table style="width:100%" border="1">
1916+ <thead style="border-bottom: solid; background-color: WhiteSmoke">
1917+ <tr style="page-break-inside: avoid">
1918+ <th style="text-align:left">${_("Date")}</th>
1919+ <th style="text-align:left">${_("Day of week")}</th>
1920+ %if max_per_day() >= 1:
1921+ <th style="text-align:left">${_("First Sign In")}</th>
1922+ <th style="text-align:left">${_("First Sign Out")}</th>
1923+ %endif
1924+ %if max_per_day() >= 2:
1925+ <th style="text-align:left">${_("Second Sign In")}</th>
1926+ <th style="text-align:left">${_("Second Sign Out")}</th>
1927+ %endif
1928+ %if max_per_day() >= 3:
1929+ <th style="text-align:left">${_("Third Sign In")}</th>
1930+ <th style="text-align:left">${_("Third Sign Out")}</th>
1931+ %endif
1932+ %if max_per_day() >= 4:
1933+ <th style="text-align:left">${_("Fourth Sign In")}</th>
1934+ <th style="text-align:left">${_("Fourth Sign Out")}</th>
1935+ %endif
1936+ <th style="text-align:right">${_("Due")}</th>
1937+ <th style="text-align:right">${_("Working Hours")}</th>
1938+ <th style="text-align:right">${_("Overtime")}</th>
1939+ <th style="text-align:right">${_("Negative")}</th>
1940+ <th style="text-align:right">${_("Leave")}</th>
1941+ </tr>
1942+ </thead>
1943+ <% first_done = 0 %>
1944+ %for day in sorted(days_by_employee(employee.id).iterkeys()) :
1945+ %if datetime.strptime(day, '%Y-%m-%d').day == 1 or not first_done:
1946+ <tr style="page-break-inside: avoid" >
1947+ <td colspan="15">
1948+ <strong>${ month_name(day) | entity }</strong>
1949+ </td>
1950+ </tr>
1951+ <% first_done = 1 %>
1952+ %endif
1953+ <tr style="page-break-inside: avoid">
1954+ <td style="text-align:left">${ formatLang(day, date=True) | entity }</td>
1955+ <td style="text-align:left">${ day_of_week(day) | entity }</td>
1956+ %if max_per_day() >= 1:
1957+ <td style="text-align:left">${ days_by_employee(employee.id)[day]['signin_1'] | entity }</td>
1958+ <td style="text-align:left">${ days_by_employee(employee.id)[day]['signout_1'] | entity }</td>
1959+ %endif
1960+ %if max_per_day() >= 2:
1961+ <td style="text-align:left">${ days_by_employee(employee.id)[day]['signin_2'] | entity }</td>
1962+ <td style="text-align:left">${ days_by_employee(employee.id)[day]['signout_2'] | entity }</td>
1963+ %endif
1964+ %if max_per_day() >= 3:
1965+ <td style="text-align:left">${ days_by_employee(employee.id)[day]['signin_3'] | entity }</td>
1966+ <td style="text-align:left">${ days_by_employee(employee.id)[day]['signout_3'] | entity }</td>
1967+ %endif
1968+ %if max_per_day() >= 4:
1969+ <td style="text-align:left">${ days_by_employee(employee.id)[day]['signin_4'] | entity }</td>
1970+ <td style="text-align:left">${ days_by_employee(employee.id)[day]['signout_4'] | entity }</td>
1971+ %endif
1972+ <td style="text-align:right">${ (days_by_employee(employee.id)[day]['due']) | entity }</td>
1973+ <td style="text-align:right">${ (days_by_employee(employee.id)[day]['attendances']) | entity }</td>
1974+ %if days_by_employee(employee.id)[day]['overtime'] != '00:00':
1975+ <td style="text-align:right; background-color:LightGreen">${ (days_by_employee(employee.id)[day]['overtime']) | entity }</td>
1976+ %else:
1977+ <td style="text-align:right">${ (days_by_employee(employee.id)[day]['overtime']) | entity }</td>
1978+ %endif
1979+ %if days_by_employee(employee.id)[day]['negative'] != '00:00':
1980+ <td style="text-align:right; background-color: Tomato">${ (days_by_employee(employee.id)[day]['negative']) | entity }</td>
1981+ %else:
1982+ <td style="text-align:right">${ (days_by_employee(employee.id)[day]['negative']) | entity }</td>
1983+ %endif
1984+ %if days_by_employee(employee.id)[day]['leaves'] != '00:00':
1985+ <td style="text-align:right; background-color: Silver">${ (days_by_employee(employee.id)[day]['leaves']) | entity }</td>
1986+ %else:
1987+ <td style="text-align:right">${ (days_by_employee(employee.id)[day]['leaves']) | entity }</td>
1988+ %endif
1989+ </tr>
1990+ %endfor
1991+ <tfoot style="font-weight:bold">
1992+ <tr style="page-break-inside: avoid">
1993+ <td style="text-align:left">${_("Totals")} </td>
1994+ <td></td>
1995+ %if max_per_day() >= 1:
1996+ <td></td>
1997+ <td></td>
1998+ %endif
1999+ %if max_per_day() >= 2:
2000+ <td></td>
2001+ <td></td>
2002+ %endif
2003+ %if max_per_day() >= 3:
2004+ <td></td>
2005+ <td></td>
2006+ %endif
2007+ %if max_per_day() >= 4:
2008+ <td></td>
2009+ <td></td>
2010+ %endif
2011+ <td style="border-top:1px solid #000; text-align:right">${ (totals_by_employee(employee.id)['total_due']) | entity }</td>
2012+ <td style="border-top:1px solid #000; text-align:right">${ (totals_by_employee(employee.id)['total_attendances']) | entity }</td>
2013+ <td style="border-top:1px solid #000; text-align:right">${ (totals_by_employee(employee.id)['total_overtime']) | entity }</td>
2014+ <td style="border-top:1px solid #000; text-align:right">${ (totals_by_employee(employee.id)['total_negative']) | entity }</td>
2015+ <td style="border-top:1px solid #000; text-align:right">${ (totals_by_employee(employee.id)['total_leaves']) | entity }</td>
2016+ </tr>
2017+ </tfoot>
2018+ </table>
2019+ <br/>
2020+ <table>
2021+ <thead>
2022+ <tr>
2023+ <th style="text-align:left">${_("Overtime type")}</th>
2024+ <th style="text-align:right">${_("Total")}</th>
2025+ </tr>
2026+ </thead>
2027+ %for type in totals_by_employee(employee.id)['total_types']:
2028+ <tr>
2029+ <td style="text-align:left">
2030+ ${type | entity}
2031+ </td>
2032+ <td style="text-align:right">
2033+ ${(totals_by_employee(employee.id)['total_types'][type]) | entity}
2034+ </td>
2035+ </tr>
2036+ %endfor
2037+ </table>
2038+ <p style="page-break-after:always; height: 1px"></p>
2039+ %endfor
2040+</body>
2041+</html>
2042
2043=== added file 'hr_attendance_analysis/report/calendar_report.py'
2044--- hr_attendance_analysis/report/calendar_report.py 1970-01-01 00:00:00 +0000
2045+++ hr_attendance_analysis/report/calendar_report.py 2013-11-07 15:51:52 +0000
2046@@ -0,0 +1,96 @@
2047+# -*- coding: utf-8 -*-
2048+##############################################################################
2049+#
2050+# Copyright (C) 2011 Agile Business Group sagl (<http://www.agilebg.com>)
2051+# Copyright (C) 2011 Domsense srl (<http://www.domsense.com>)
2052+#
2053+# This program is free software: you can redistribute it and/or modify
2054+# it under the terms of the GNU Affero General Public License as published
2055+# by the Free Software Foundation, either version 3 of the License, or
2056+# (at your option) any later version.
2057+#
2058+# This program is distributed in the hope that it will be useful,
2059+# but WITHOUT ANY WARRANTY; without even the implied warranty of
2060+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2061+# GNU General Public License for more details.
2062+#
2063+# You should have received a copy of the GNU Affero General Public License
2064+# along with this program. If not, see <http://www.gnu.org/licenses/>.
2065+#
2066+##############################################################################
2067+
2068+import time
2069+from report import report_sxw
2070+from osv import osv
2071+from datetime import datetime
2072+from tools.translate import _
2073+
2074+class Parser(report_sxw.rml_parse):
2075+
2076+ def _get_day_of_week(self, day):
2077+ WEEKDAYS = {
2078+ 0: _('Monday'),
2079+ 1: _('Tuesday'),
2080+ 2: _('Wednesday'),
2081+ 3: _('Thursday'),
2082+ 4: _('Friday'),
2083+ 5: _('Saturday'),
2084+ 6: _('Sunday'),
2085+ }
2086+ dayofweek=''
2087+ weekday = datetime.strptime(day,'%Y-%m-%d').weekday()
2088+ return WEEKDAYS[weekday]
2089+
2090+ def _get_month_name(self, day):
2091+ str_month=''
2092+ month = datetime.strptime(day,'%Y-%m-%d').month
2093+ if month == 1:
2094+ str_month = _('January')
2095+ elif month == 2:
2096+ str_month = _('February')
2097+ elif month == 3:
2098+ str_month = _('March')
2099+ elif month == 4:
2100+ str_month = _('April')
2101+ elif month == 5:
2102+ str_month = _('May')
2103+ elif month == 6:
2104+ str_month = _('June')
2105+ elif month == 7:
2106+ str_month = _('July')
2107+ elif month == 8:
2108+ str_month = _('August')
2109+ elif month == 9:
2110+ str_month = _('September')
2111+ elif month == 10:
2112+ str_month = _('October')
2113+ elif month == 11:
2114+ str_month = _('November')
2115+ elif month == 12:
2116+ str_month = _('December')
2117+ return str_month
2118+
2119+ def _get_days_by_employee(self, employee_id):
2120+ return self.localcontext['data']['form']['days_by_employee'][str(employee_id)]
2121+
2122+ def _get_totals_by_employee(self, employee_id):
2123+ return self.localcontext['data']['form']['totals_by_employee'][str(employee_id)]
2124+
2125+ def _get_max_per_day(self):
2126+ return self.localcontext['data']['form']['max_number_of_attendances_per_day']
2127+
2128+ def __init__(self, cr, uid, name, context):
2129+ super(Parser, self).__init__(cr, uid, name, context)
2130+ self.localcontext.update({
2131+ 'time': time,
2132+ 'days_by_employee': self._get_days_by_employee,
2133+ 'totals_by_employee': self._get_totals_by_employee,
2134+ 'day_of_week': self._get_day_of_week,
2135+ 'max_per_day': self._get_max_per_day,
2136+ 'month_name': self._get_month_name,
2137+ })
2138+
2139+report_sxw.report_sxw('report.attendance_analysis.calendar_report',
2140+ 'attendance_analysis.calendar_report',
2141+ 'attendance_analysis/report/calendar_report.mako',
2142+ parser=Parser)
2143
2144=== added file 'hr_attendance_analysis/reports.xml'
2145--- hr_attendance_analysis/reports.xml 1970-01-01 00:00:00 +0000
2146+++ hr_attendance_analysis/reports.xml 2013-11-07 15:51:52 +0000
2147@@ -0,0 +1,86 @@
2148+<?xml version="1.0"?>
2149+<openerp>
2150+ <data><record id="attendances_landscape_header" model="ir.header_webkit">
2151+ <field name="footer_html"><![CDATA[
2152+<html>
2153+ <head>
2154+ <meta content="text/html; charset=UTF-8" http-equiv="content-type"/>
2155+ <script>
2156+ function subst() {
2157+ var vars={};
2158+ var x=document.location.search.substring(1).split('&');
2159+ for(var i in x) {var z=x[i].split('=',2);vars[z[0]] = unescape(z[1]);}
2160+ var x=['frompage','topage','page','webpage','section','subsection','subsubsection'];
2161+ for(var i in x) {
2162+ var y = document.getElementsByClassName(x[i]);
2163+ for(var j=0; j<y.length; ++j) y[j].textContent = vars[x[i]];
2164+ }
2165+ }
2166+ </script>
2167+ </head>
2168+ <% import datetime %>
2169+ <body style="border:0" onload="subst()">
2170+ <table style="border-top: 1px solid black; width: 1080px">
2171+ <tr style="border-collapse:collapse;">
2172+ <td style="text-align:left;font-size:10;width:350px;">${formatLang( str(datetime.datetime.today()), date_time=True)}</td>
2173+ <td style="text-align:center;font-size:10;width:350px;"></td>
2174+ <td style="text-align:right;font-size:10;width:350px;">Page&nbsp;<span class="page"/></td>
2175+ <td style="text-align:left;font-size:10;width:30px">&nbsp;of&nbsp;<span class="topage"/></td>
2176+ </tr>
2177+ </table>
2178+ </body>
2179+</html>]]></field>
2180+ <field name="orientation">Landscape</field>
2181+ <field name="format">A4</field>
2182+ <field name="html"><![CDATA[
2183+<html>
2184+ <head>
2185+ <meta content="text/html; charset=UTF-8" http-equiv="content-type"/>
2186+ <script>
2187+ function subst() {
2188+ var vars={};
2189+ var x=document.location.search.substring(1).split('&');
2190+ for(var i in x) {var z=x[i].split('=',2);vars[z[0]] = unescape(z[1]);}
2191+ var x=['frompage','topage','page','webpage','section','subsection','subsubsection'];
2192+ for(var i in x) {
2193+ var y = document.getElementsByClassName(x[i]);
2194+ for(var j=0; j<y.length; ++j) y[j].textContent = vars[x[i]];
2195+ }
2196+ }
2197+ </script>
2198+ <style type="text/css">
2199+ ${css}
2200+ </style>
2201+ </head>
2202+ <body style="border:0; margin: 0;" onload="subst()">
2203+ <table class="header" style="border-bottom: 0px solid black; width: 100%">
2204+ <tr>
2205+ <td><h1>${_("Attendances Analysis")} - ${objects[0].company_id.partner_id.name | entity}</h1></td>
2206+ </tr>
2207+ </table> ${_debug or ''|n}
2208+ </body>
2209+</html>]]>
2210+ </field>
2211+ <field name="css"><![CDATA[
2212+
2213+body, table, td, span, div {
2214+ font-family: Helvetica, Arial;
2215+}
2216+
2217+]]>
2218+ </field>
2219+ <field eval="20" name="margin_top"/>
2220+ <field name="name">Attendances Landscape Header</field>
2221+ </record>
2222+ <record id="attendance_analysis_report_id" model="ir.actions.report.xml">
2223+ <field name="name">Attendances Analysis</field>
2224+ <field name="type">ir.actions.report.xml</field>
2225+ <field name="model">hr.employee</field>
2226+ <field name="report_name">attendance_analysis.calendar_report</field>
2227+ <field name="report_rml">hr_attendance_analysis/report/calendar_report.mako</field>
2228+ <field name="report_type">webkit</field>
2229+ <field name="webkit_header" ref="attendances_landscape_header"/>
2230+ </record>
2231+ </data>
2232+</openerp>
2233+
2234
2235=== added file 'hr_attendance_analysis/resource.py'
2236--- hr_attendance_analysis/resource.py 1970-01-01 00:00:00 +0000
2237+++ hr_attendance_analysis/resource.py 2013-11-07 15:51:52 +0000
2238@@ -0,0 +1,102 @@
2239+# -*- coding: utf-8 -*-
2240+##############################################################################
2241+#
2242+# Copyright (C) 2011 Domsense srl (<http://www.domsense.com>)
2243+# Copyright (C) 2011-2013 Agile Business Group sagl
2244+# (<http://www.agilebg.com>)
2245+#
2246+# This program is free software: you can redistribute it and/or modify
2247+# it under the terms of the GNU Affero General Public License as published
2248+# by the Free Software Foundation, either version 3 of the License, or
2249+# (at your option) any later version.
2250+#
2251+# This program is distributed in the hope that it will be useful,
2252+# but WITHOUT ANY WARRANTY; without even the implied warranty of
2253+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2254+# GNU Affero General Public License for more details.
2255+#
2256+# You should have received a copy of the GNU Affero General Public License
2257+# along with this program. If not, see <http://www.gnu.org/licenses/>.
2258+#
2259+##############################################################################
2260+
2261+from openerp.osv import fields, orm
2262+
2263+class resource_calendar_attendance(orm.Model):
2264+ _inherit = "resource.calendar.attendance"
2265+ _columns = {
2266+ 'tolerance_from': fields.float('Tolerance from', size=8,
2267+ help='Sign out done in the interval "Work to - Tolerance from" will be considered done at "Work to"'),
2268+ 'tolerance_to': fields.float('Tolerance to', size=8,
2269+ help='Sign in done in the interval "Work from + Tolerance to" will be considered done at "Work from"'),
2270+ }
2271+
2272+
2273+class resource_calendar(orm.Model):
2274+ _inherit = "resource.calendar"
2275+ _columns = {
2276+ 'attendance_rounding': fields.selection([
2277+ ('60', '1'),
2278+ ('30', '2'),
2279+ ('20', '3'),
2280+ ('12', '5'),
2281+ ('10', '6'),
2282+ ('7.5', '8'),
2283+ ('6', '10'),
2284+ ('5', '12'),
2285+ ('4', '15'),
2286+ ('3', '20'),
2287+ ('2', '30'),
2288+ ('1', '60'),
2289+ ],
2290+ 'Attendance rounding', help='For instance, using rounding = 15 minutes, every sign in will be rounded to the following quarter hour and every sign out to the previous quarter hour'),
2291+ #'attendance_rounding': fields.float('Attendance rounding', size=8,
2292+ #help='For instance, using rounding = 15 minutes, every sign in will be rounded to the following quarter hour and every sign out to the previous quarter hour'),
2293+ 'overtime_rounding': fields.selection([
2294+ ('60', '1'),
2295+ ('30', '2'),
2296+ ('20', '3'),
2297+ ('12', '5'),
2298+ ('10', '6'),
2299+ ('7.5', '8'),
2300+ ('6', '10'),
2301+ ('5', '12'),
2302+ ('4', '15'),
2303+ ('3', '20'),
2304+ ('2', '30'),
2305+ ('1', '60'),
2306+ ],
2307+ 'Overtime rounding',
2308+ help='Setting rounding = 30 minutes, an overtime of 29 minutes will be considered as 0 minutes, 31 minutes as 30 minutes, 61 minutes as 1 hour and so on'),
2309+ 'overtime_rounding_tolerance': fields.float('Overtime rounding tolerance', size=8,
2310+ help='Overtime can be rounded using a tolerance. Using tolerance = 3 minutes and rounding = 15 minutes, if employee does overtime of 12 minutes, it will be considered as 15 minutes.'),
2311+ 'leave_rounding': fields.selection([
2312+ ('60', '1'),
2313+ ('30', '2'),
2314+ ('20', '3'),
2315+ ('12', '5'),
2316+ ('10', '6'),
2317+ ('7.5', '8'),
2318+ ('6', '10'),
2319+ ('5', '12'),
2320+ ('4', '15'),
2321+ ('3', '20'),
2322+ ('2', '30'),
2323+ ('1', '60'),
2324+ ],
2325+ 'Leave rounding',
2326+ help='On the contrary of overtime rounding, using rounding = 15 minutes, a leave of 1 minute will be considered as 15 minutes, 16 minutes as 30 minutes and so on'),
2327+ 'overtime_type_ids': fields.one2many('resource.calendar.overtime.type', 'calendar_id', 'Overtime types'),
2328+ }
2329+
2330+class resource_calendar_overtime_range(orm.Model):
2331+ _name = 'resource.calendar.overtime.type'
2332+ _description = 'Overtime type'
2333+ _order = 'sequence'
2334+ _columns = {
2335+ 'sequence': fields.integer('Sequence', required=True),
2336+ 'name': fields.char('Type Description', size=64, required=True),
2337+ 'calendar_id': fields.many2one('resource.calendar', 'Calendar'),
2338+ 'limit': fields.float('Limit', size=8,
2339+ help='Limit, in hours, of overtime that can be imputed to this type of overtime in a day. The surplus is imputed to the subsequent type')
2340+ }
2341
2342=== added file 'hr_attendance_analysis/resource_view.xml'
2343--- hr_attendance_analysis/resource_view.xml 1970-01-01 00:00:00 +0000
2344+++ hr_attendance_analysis/resource_view.xml 2013-11-07 15:51:52 +0000
2345@@ -0,0 +1,52 @@
2346+<?xml version="1.0" encoding="utf-8"?>
2347+<openerp>
2348+ <data>
2349+
2350+ <record id="view_resource_calendar_attendance_form" model="ir.ui.view">
2351+ <field name="name">resource.calendar.attendance.form</field>
2352+ <field name="model">resource.calendar.attendance</field>
2353+ <field name="inherit_id" ref="resource.view_resource_calendar_attendance_form"></field>
2354+ <field name="arch" type="xml">
2355+ <field name="hour_from" position="after">
2356+ <field name="tolerance_to" widget="float_time"/>
2357+ </field>
2358+ <field name="hour_to" position="after">
2359+ <field name="tolerance_from" widget="float_time"/>
2360+ </field>
2361+ </field>
2362+ </record>
2363+ <record id="resource_calendar_form" model="ir.ui.view">
2364+ <field name="name">resource.calendar.form</field>
2365+ <field name="model">resource.calendar</field>
2366+ <field name="inherit_id" ref="resource.resource_calendar_form"></field>
2367+ <field name="arch" type="xml">
2368+ <field name="attendance_ids" position="after">
2369+ <notebook colspan="4">
2370+ <page string="Roundings">
2371+ <group colspan="4">
2372+ <field name="attendance_rounding"/>
2373+ <field name="leave_rounding"/>
2374+ <field name="overtime_rounding"/>
2375+ <field name="overtime_rounding_tolerance" widget="float_time"/>
2376+ </group>
2377+ </page>
2378+ <page string="Overtime types">
2379+ <field name="overtime_type_ids" colspan="4" nolabel="1">
2380+ <tree string="Types" editable="bottom">
2381+ <field name="sequence"/>
2382+ <field name="name"/>
2383+ <field name="limit" widget="float_time"/>
2384+ </tree>
2385+ <form string="Type">
2386+ <field name="sequence"/>
2387+ <field name="name"/>
2388+ <field name="limit" widget="float_time"/>
2389+ </form>
2390+ </field>
2391+ </page>
2392+ </notebook>
2393+ </field>
2394+ </field>
2395+ </record>
2396+ </data>
2397+</openerp>
2398
2399=== added directory 'hr_attendance_analysis/security'
2400=== added file 'hr_attendance_analysis/security/ir.model.access.csv'
2401--- hr_attendance_analysis/security/ir.model.access.csv 1970-01-01 00:00:00 +0000
2402+++ hr_attendance_analysis/security/ir.model.access.csv 2013-11-07 15:51:52 +0000
2403@@ -0,0 +1,3 @@
2404+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
2405+access_resource_calendar_overtime_type,resource.calendar.overtime.type,model_resource_calendar_overtime_type,base.group_system,1,1,1,1
2406+access_hr_resource_calendar_overtime_type_user,hr.employee.resource.calendar.overtime.type.user,model_resource_calendar_overtime_type,base.group_hr_user,1,1,1,1
2407
2408=== added directory 'hr_attendance_analysis/wizard'
2409=== added file 'hr_attendance_analysis/wizard/__init__.py'
2410--- hr_attendance_analysis/wizard/__init__.py 1970-01-01 00:00:00 +0000
2411+++ hr_attendance_analysis/wizard/__init__.py 2013-11-07 15:51:52 +0000
2412@@ -0,0 +1,23 @@
2413+# -*- coding: utf-8 -*-
2414+##############################################################################
2415+#
2416+# Copyright (C) 2011 Domsense srl (<http://www.domsense.com>)
2417+# Copyright (C) 2011-2013 Agile Business Group sagl
2418+# (<http://www.agilebg.com>)
2419+#
2420+# This program is free software: you can redistribute it and/or modify
2421+# it under the terms of the GNU Affero General Public License as published
2422+# by the Free Software Foundation, either version 3 of the License, or
2423+# (at your option) any later version.
2424+#
2425+# This program is distributed in the hope that it will be useful,
2426+# but WITHOUT ANY WARRANTY; without even the implied warranty of
2427+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2428+# GNU Affero General Public License for more details.
2429+#
2430+# You should have received a copy of the GNU Affero General Public License
2431+# along with this program. If not, see <http://www.gnu.org/licenses/>.
2432+#
2433+##############################################################################
2434+
2435+import print_calendar_report
2436
2437=== added file 'hr_attendance_analysis/wizard/print_calendar_report.py'
2438--- hr_attendance_analysis/wizard/print_calendar_report.py 1970-01-01 00:00:00 +0000
2439+++ hr_attendance_analysis/wizard/print_calendar_report.py 2013-11-07 15:51:52 +0000
2440@@ -0,0 +1,366 @@
2441+# -*- coding: utf-8 -*-
2442+##############################################################################
2443+#
2444+# Copyright (C) 2011 Domsense srl (<http://www.domsense.com>)
2445+# Copyright (C) 2011-2013 Agile Business Group sagl
2446+# (<http://www.agilebg.com>)
2447+#
2448+# This program is free software: you can redistribute it and/or modify
2449+# it under the terms of the GNU Affero General Public License as published
2450+# by the Free Software Foundation, either version 3 of the License, or
2451+# (at your option) any later version.
2452+#
2453+# This program is distributed in the hope that it will be useful,
2454+# but WITHOUT ANY WARRANTY; without even the implied warranty of
2455+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2456+# GNU Affero General Public License for more details.
2457+#
2458+# You should have received a copy of the GNU Affero General Public License
2459+# along with this program. If not, see <http://www.gnu.org/licenses/>.
2460+#
2461+##############################################################################
2462+
2463+from openerp.osv import fields, orm
2464+from openerp.tools.translate import _
2465+from datetime import *
2466+import math
2467+import calendar
2468+
2469+class wizard_calendar_report(orm.TransientModel):
2470+
2471+ _columns = {
2472+ 'month': fields.selection([
2473+ ('1', 'January'),
2474+ ('2', 'February'),
2475+ ('3', 'March'),
2476+ ('4', 'April'),
2477+ ('5', 'May'),
2478+ ('6', 'June'),
2479+ ('7', 'July'),
2480+ ('8', 'August'),
2481+ ('9', 'September'),
2482+ ('10', 'October'),
2483+ ('11', 'November'),
2484+ ('12', 'December'),
2485+ ], 'Month'),
2486+ 'year': fields.integer('Year'),
2487+ 'from_date': fields.date('From date', required=True),
2488+ 'to_date': fields.date('To date', required=True),
2489+ 'employee_ids': fields.many2many('hr.employee', 'calendar_report_employee_rel', 'employee_id', 'report_id',
2490+ required=True),
2491+ }
2492+
2493+ _defaults = {
2494+ 'month': lambda * a: str(datetime.now().month),
2495+ 'year': lambda * a: datetime.now().year,
2496+ 'from_date': lambda * a: (datetime.now()-timedelta(30)).strftime('%Y-%m-%d'),
2497+ 'to_date': lambda * a: datetime.now().strftime('%Y-%m-%d'),
2498+ 'employee_ids': lambda s, cr, uid, c: s.pool.get('hr.employee').search(cr, uid, []),
2499+ }
2500+
2501+ _name = "attendance_analysis.wizard.calendar_report"
2502+
2503+ def on_change_month(self, cr, uid, id, str_month, year):
2504+ res = {}
2505+ if year and str_month:
2506+ month = int(str_month)
2507+ day = calendar.monthrange(year, month)[1]
2508+ to_date = date(year, month, day).strftime('%Y-%m-%d')
2509+ res= {'value':{'to_date': to_date, 'from_date': date(year, month, 1).strftime('%Y-%m-%d')}}
2510+ return res
2511+
2512+
2513+ def print_calendar(self, cr, uid, ids, context=None):
2514+ if context is None:
2515+ context = {}
2516+ attendance_pool = self.pool.get('hr.attendance')
2517+ contract_pool = self.pool.get('hr.contract')
2518+ holidays_pool = self.pool.get('hr.holidays')
2519+
2520+ days_by_employee = {}
2521+
2522+ form = self.read(cr, uid, ids)[0]
2523+ from_date = datetime.strptime(form['from_date'], '%Y-%m-%d')
2524+ to_date = datetime.strptime(form['to_date'], '%Y-%m-%d')
2525+ if from_date > to_date:
2526+ raise orm.except_orm(_('Error'), _('From date must be < to date'))
2527+ employee_ids=form['employee_ids']
2528+ delta = to_date - from_date
2529+ max_number_of_attendances_per_day = 0
2530+
2531+ for employee_id in employee_ids:
2532+ employee_id = str(employee_id)
2533+ days_by_employee[employee_id] = {}
2534+ day_count=0
2535+ while day_count <= delta.days:
2536+ current_date = from_date + timedelta(day_count)
2537+ current_total_attendances = 0.0
2538+ current_total_overtime = 0.0
2539+ current_total_leaves = 0.0
2540+ current_total_due = 24.0 # If contract is not specified: working days = 24/7
2541+ current_total_inside_calendar = 0.0
2542+ str_current_date = current_date.strftime('%Y-%m-%d')
2543+ days_by_employee[employee_id][str_current_date] = {
2544+ 'signin_1': '',
2545+ 'signout_1': '',
2546+ 'signin_2': '',
2547+ 'signout_2': '',
2548+ 'signin_3': '',
2549+ 'signout_3': '',
2550+ 'signin_4': '',
2551+ 'signout_4': '',
2552+ }
2553+ current_date_beginning = datetime.combine(current_date, time())
2554+ str_current_date_beginning = current_date_beginning.strftime(
2555+ '%Y-%m-%d %H:%M:%S')
2556+ current_date_end = datetime.combine(current_date, time())+ timedelta(1)
2557+ str_current_date_end = current_date_end.strftime('%Y-%m-%d %H:%M:%S')
2558+
2559+ attendance_ids = attendance_pool.search(cr, uid, [
2560+ ('employee_id','=',int(employee_id)),
2561+ ('name','>=',str_current_date_beginning),
2562+ ('name','<=',str_current_date_end),
2563+ ('action','=','sign_in'),
2564+ ])
2565+ # computing attendance totals
2566+ for attendance in attendance_pool.browse(cr, uid, attendance_ids):
2567+ current_total_attendances = attendance_pool.time_sum(
2568+ current_total_attendances,attendance.duration)
2569+ current_total_overtime = attendance_pool.time_sum(current_total_overtime,
2570+ attendance.outside_calendar_duration)
2571+ current_total_inside_calendar = attendance_pool.time_sum(
2572+ current_total_inside_calendar,
2573+ attendance.inside_calendar_duration)
2574+
2575+ #printing up to 4 attendances
2576+ if len(attendance_ids) < 5:
2577+ count = 1
2578+ for attendance in sorted(attendance_pool.browse(cr, uid, attendance_ids),
2579+ key=lambda x: x['name']):
2580+ days_by_employee[employee_id][str_current_date][
2581+ 'signin_'+str(count)] = attendance.name[11:16]
2582+ days_by_employee[employee_id][str_current_date][
2583+ 'signout_'+str(count)] = attendance.end_datetime[11:16]
2584+ count += 1
2585+ if len(attendance_ids) > max_number_of_attendances_per_day:
2586+ max_number_of_attendances_per_day = len(attendance_ids)
2587+
2588+ days_by_employee[employee_id][str_current_date][
2589+ 'attendances'
2590+ ] = current_total_attendances
2591+ days_by_employee[employee_id][str_current_date][
2592+ 'overtime'
2593+ ] = current_total_overtime
2594+
2595+ active_contract_ids = attendance_pool.get_active_contracts(
2596+ cr, uid, int(employee_id), date=str_current_date)
2597+ # computing due total
2598+ if active_contract_ids:
2599+ contract = contract_pool.browse(cr, uid, active_contract_ids[0])
2600+ if contract.working_hours and contract.working_hours.attendance_ids:
2601+ current_total_due = 0.0
2602+ for calendar_attendance in contract.working_hours.attendance_ids:
2603+ if ((
2604+ not calendar_attendance.dayofweek
2605+ or int(calendar_attendance.dayofweek) == current_date.weekday()
2606+ )
2607+ and (
2608+ not calendar_attendance.date_from or
2609+ datetime.strptime(calendar_attendance.date_from,'%Y-%m-%d')
2610+ <= current_date
2611+ )):
2612+ calendar_attendance_duration = attendance_pool.time_difference(
2613+ calendar_attendance.hour_from, calendar_attendance.hour_to)
2614+ if calendar_attendance_duration < 0:
2615+ raise orm.except_orm(_('Error'),
2616+ _("%s: 'Work to' is < 'Work from'")
2617+ % calendar_attendance.name)
2618+ current_total_due = attendance_pool.time_sum(current_total_due,
2619+ calendar_attendance_duration)
2620+
2621+ days_by_employee[employee_id][str_current_date]['due'] = current_total_due
2622+
2623+ # computing leaves
2624+ holidays_ids = holidays_pool.search(cr, uid, [
2625+ '&',
2626+ '&',
2627+ '|',
2628+ # leave begins today
2629+ '&',
2630+ ('date_from', '>=', str_current_date_beginning),
2631+ ('date_from', '<=', str_current_date_end),
2632+ '|',
2633+ # leave ends today
2634+ '&',
2635+ ('date_to', '<=', str_current_date_end),
2636+ ('date_to', '>=', str_current_date_beginning),
2637+ # leave is ongoing
2638+ '&',
2639+ ('date_from', '<', str_current_date_beginning),
2640+ ('date_to', '>', str_current_date_end),
2641+ ('state', '=', 'validate'),
2642+ ('employee_id', '=', int(employee_id)),
2643+ ])
2644+ for holiday in holidays_pool.browse(cr, uid, holidays_ids):
2645+ date_from = datetime.strptime(holiday.date_from, '%Y-%m-%d %H:%M:%S')
2646+ date_to = datetime.strptime(holiday.date_to, '%Y-%m-%d %H:%M:%S')
2647+ # if beginned before today
2648+ if date_from < current_date_beginning:
2649+ date_from = current_date_beginning
2650+ # if ends after today
2651+ if date_to > current_date_end:
2652+ date_to = current_date_end
2653+ current_total_leaves = attendance_pool.time_sum(
2654+ current_total_leaves,
2655+ (date_to - date_from).total_seconds() / 60.0 / 60.0)
2656+
2657+ days_by_employee[employee_id][str_current_date]['leaves'] = current_total_leaves
2658+ if current_total_leaves > days_by_employee[employee_id][
2659+ str_current_date]['due']:
2660+ days_by_employee[employee_id][str_current_date][
2661+ 'leaves'
2662+ ] = days_by_employee[employee_id][str_current_date]['due']
2663+ due_minus_leaves = attendance_pool.time_difference(
2664+ current_total_leaves, current_total_due)
2665+ if due_minus_leaves < current_total_inside_calendar:
2666+ days_by_employee[employee_id][str_current_date]['negative'] = 0.0
2667+ else:
2668+ days_by_employee[employee_id][str_current_date][
2669+ 'negative'
2670+ ] = attendance_pool.time_difference(
2671+ current_total_inside_calendar, due_minus_leaves)
2672+
2673+ if active_contract_ids:
2674+ contract = contract_pool.browse(cr, uid, active_contract_ids[0])
2675+ if contract.working_hours and contract.working_hours.leave_rounding:
2676+ float_rounding = float(contract.working_hours.leave_rounding)
2677+ days_by_employee[employee_id][str_current_date][
2678+ 'negative'
2679+ ] = math.floor(
2680+ days_by_employee[employee_id][str_current_date]['negative'] *
2681+ float_rounding
2682+ ) / float_rounding
2683+
2684+ day_count += 1
2685+
2686+ totals_by_employee = {}
2687+ for employee_id in days_by_employee:
2688+ totals_by_employee[employee_id] = {
2689+ 'total_attendances': 0.0,
2690+ 'total_overtime': 0.0,
2691+ 'total_negative': 0.0,
2692+ 'total_leaves': 0.0,
2693+ 'total_due': 0.0,
2694+ 'total_types': {},
2695+ }
2696+
2697+ for str_date in days_by_employee[employee_id]:
2698+ totals_by_employee[employee_id]['total_attendances'] = attendance_pool.time_sum(
2699+ totals_by_employee[employee_id]['total_attendances'],
2700+ days_by_employee[employee_id][str_date]['attendances'])
2701+ totals_by_employee[employee_id]['total_overtime'] = attendance_pool.time_sum(
2702+ totals_by_employee[employee_id]['total_overtime'],
2703+ days_by_employee[employee_id][str_date]['overtime'])
2704+ totals_by_employee[employee_id]['total_negative'] = attendance_pool.time_sum(
2705+ totals_by_employee[employee_id]['total_negative'],
2706+ days_by_employee[employee_id][str_date]['negative'])
2707+ totals_by_employee[employee_id]['total_leaves'] = attendance_pool.time_sum(
2708+ totals_by_employee[employee_id]['total_leaves'],
2709+ days_by_employee[employee_id][str_date]['leaves'])
2710+ totals_by_employee[employee_id]['total_due'] = attendance_pool.time_sum(
2711+ totals_by_employee[employee_id]['total_due'],
2712+ days_by_employee[employee_id][str_date]['due'])
2713+
2714+ # computing overtime types
2715+ active_contract_ids = attendance_pool.get_active_contracts(
2716+ cr, uid, int(employee_id), date=str_date)
2717+ if active_contract_ids:
2718+ contract = contract_pool.browse(cr, uid, active_contract_ids[0])
2719+ if contract.working_hours and contract.working_hours.overtime_type_ids:
2720+ sorted_types = sorted(
2721+ contract.working_hours.overtime_type_ids,
2722+ key=lambda k: k.sequence)
2723+ current_overtime = days_by_employee[employee_id][
2724+ str_date]['overtime']
2725+ for overtime_type in sorted_types:
2726+ if not totals_by_employee[employee_id]['total_types'].get(
2727+ overtime_type.name, False):
2728+ totals_by_employee[employee_id]['total_types'][
2729+ overtime_type.name] = 0.0
2730+ if current_overtime:
2731+ if current_overtime <= overtime_type.limit or not overtime_type.limit:
2732+ totals_by_employee[employee_id]['total_types'][
2733+ overtime_type.name] = attendance_pool.time_sum(
2734+ totals_by_employee[employee_id]
2735+ ['total_types'][overtime_type.name],
2736+ current_overtime)
2737+ current_overtime = 0.0
2738+ else:
2739+ totals_by_employee[employee_id]['total_types'][
2740+ overtime_type.name] = attendance_pool.time_sum(
2741+ totals_by_employee[employee_id]['total_types']
2742+ [overtime_type.name], overtime_type.limit)
2743+ current_overtime = attendance_pool.time_difference(overtime_type.limit,
2744+ current_overtime)
2745+
2746+ days_by_employee[employee_id][str_date][
2747+ 'attendances'
2748+ ] = attendance_pool.float_time_convert(
2749+ days_by_employee[employee_id][str_date]['attendances'])
2750+ days_by_employee[employee_id][str_date][
2751+ 'overtime'
2752+ ] = attendance_pool.float_time_convert(
2753+ days_by_employee[employee_id][str_date]['overtime'])
2754+ days_by_employee[employee_id][str_date][
2755+ 'negative'
2756+ ] = attendance_pool.float_time_convert(
2757+ days_by_employee[employee_id][str_date]['negative'])
2758+ days_by_employee[employee_id][str_date][
2759+ 'leaves'
2760+ ] = attendance_pool.float_time_convert(
2761+ days_by_employee[employee_id][str_date]['leaves'])
2762+ days_by_employee[employee_id][str_date][
2763+ 'due'
2764+ ] = attendance_pool.float_time_convert(
2765+ days_by_employee[employee_id][str_date]['due'])
2766+
2767+ totals_by_employee[employee_id][
2768+ 'total_attendances'
2769+ ] = attendance_pool.float_time_convert(
2770+ totals_by_employee[employee_id]['total_attendances'])
2771+ totals_by_employee[employee_id][
2772+ 'total_overtime'
2773+ ] = attendance_pool.float_time_convert(
2774+ totals_by_employee[employee_id]['total_overtime'])
2775+ totals_by_employee[employee_id][
2776+ 'total_negative'
2777+ ] = attendance_pool.float_time_convert(
2778+ totals_by_employee[employee_id]['total_negative'])
2779+ totals_by_employee[employee_id][
2780+ 'total_leaves'
2781+ ] = attendance_pool.float_time_convert(
2782+ totals_by_employee[employee_id]['total_leaves'])
2783+ totals_by_employee[employee_id][
2784+ 'total_due'
2785+ ] = attendance_pool.float_time_convert(
2786+ totals_by_employee[employee_id]['total_due'])
2787+
2788+ for overtime_type in totals_by_employee[employee_id]['total_types']:
2789+ totals_by_employee[employee_id]['total_types'][
2790+ overtime_type
2791+ ] = attendance_pool.float_time_convert(
2792+ totals_by_employee[employee_id]['total_types'][overtime_type])
2793+
2794+ datas = {'ids': employee_ids}
2795+ datas['model'] = 'hr.employee'
2796+ datas['form'] = {}
2797+ datas['form']['days_by_employee'] = days_by_employee
2798+ datas['form']['totals_by_employee'] = totals_by_employee
2799+ datas['form']['max_number_of_attendances_per_day'] = max_number_of_attendances_per_day
2800+
2801+ return {
2802+ 'type': 'ir.actions.report.xml',
2803+ 'report_name': 'attendance_analysis.calendar_report',
2804+ 'datas': datas,
2805+ }
2806+
2807
2808=== added file 'hr_attendance_analysis/wizard/print_calendar_report.xml'
2809--- hr_attendance_analysis/wizard/print_calendar_report.xml 1970-01-01 00:00:00 +0000
2810+++ hr_attendance_analysis/wizard/print_calendar_report.xml 2013-11-07 15:51:52 +0000
2811@@ -0,0 +1,38 @@
2812+<?xml version="1.0" encoding="utf-8"?>
2813+<openerp>
2814+ <data>
2815+
2816+ <record id="wizard_calendar_report" model="ir.ui.view">
2817+ <field name="name">Attendances Analysis Calendar</field>
2818+ <field name="model">attendance_analysis.wizard.calendar_report</field>
2819+ <field name="arch" type="xml">
2820+ <form string="Attendances Analysis Calendar">
2821+ <group colspan="4" height="400">
2822+ <field name="month" on_change="on_change_month(month, year)"/>
2823+ <field name="year" on_change="on_change_month(month, year)"/>
2824+ <field name="from_date"/>
2825+ <field name="to_date"/>
2826+ <separator colspan="4" string="Employees"/>
2827+ <field name="employee_ids" colspan="4" nolabel="1"/>
2828+ <separator colspan="4"/>
2829+ <button icon="gtk-cancel" special="cancel" string="Cancel" colspan="2"/>
2830+ <button icon="gtk-ok" name="print_calendar" string="Print" type="object" colspan="2"/>
2831+ </group>
2832+ </form>
2833+ </field>
2834+ </record>
2835+
2836+ <record id="action_wizard_calendar_report" model="ir.actions.act_window">
2837+ <field name="name">Attendances Analysis Calendar</field>
2838+ <field name="res_model">attendance_analysis.wizard.calendar_report</field>
2839+ <field name="view_type">form</field>
2840+ <field name="view_mode">form</field>
2841+ <field name="view_id" ref="wizard_calendar_report"/>
2842+ <field name="target">new</field>
2843+ </record>
2844+
2845+ <menuitem action="action_wizard_calendar_report"
2846+ id="menu_action_wizard_calendar_report"
2847+ parent="hr.menu_hr_reporting" />
2848+ </data>
2849+</openerp>
2850
2851=== modified file 'hr_timesheet_fulfill/__init__.py'
2852--- hr_timesheet_fulfill/__init__.py 2011-08-12 12:53:16 +0000
2853+++ hr_timesheet_fulfill/__init__.py 2013-11-07 15:51:52 +0000
2854@@ -1,32 +1,25 @@
2855 # -*- coding: utf-8 -*-
2856 ##############################################################################
2857 #
2858-# Copyright (c) 2011 Camptocamp SA (http://www.camptocamp.com)
2859-# All Right Reserved
2860-#
2861-# Author : Guewen Baconnier (Camptocamp)
2862-#
2863-# WARNING: This program as such is intended to be used by professional
2864-# programmers who take the whole responsability of assessing all potential
2865-# consequences resulting from its eventual inadequacies and bugs
2866-# End users who are looking for a ready-to-use solution with commercial
2867-# garantees and support are strongly adviced to contract a Free Software
2868-# Service Company
2869-#
2870-# This program is Free Software; you can redistribute it and/or
2871-# modify it under the terms of the GNU General Public License
2872-# as published by the Free Software Foundation; either version 2
2873-# of the License, or (at your option) any later version.
2874-#
2875-# This program is distributed in the hope that it will be useful,
2876-# but WITHOUT ANY WARRANTY; without even the implied warranty of
2877-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2878-# GNU General Public License for more details.
2879-#
2880-# You should have received a copy of the GNU General Public License
2881-# along with this program; if not, write to the Free Software
2882-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
2883+# Author: Guewen Baconnier (Camptocamp)
2884+# Author: Vincent Renaville
2885+# Copyright 2012 Camptocamp SA
2886+#
2887+# This program is free software: you can redistribute it and/or modify
2888+# it under the terms of the GNU Affero General Public License as
2889+# published by the Free Software Foundation, either version 3 of the
2890+# License, or (at your option) any later version.
2891+#
2892+# This program is distributed in the hope that it will be useful,
2893+# but WITHOUT ANY WARRANTY; without even the implied warranty of
2894+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2895+# GNU Affero General Public License for more details.
2896+#
2897+# You should have received a copy of the GNU Affero General Public License
2898+# along with this program. If not, see <http://www.gnu.org/licenses/>.
2899 #
2900 ##############################################################################
2901
2902 import wizard
2903+
2904+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
2905
2906=== modified file 'hr_timesheet_fulfill/__openerp__.py'
2907--- hr_timesheet_fulfill/__openerp__.py 2011-08-12 12:53:16 +0000
2908+++ hr_timesheet_fulfill/__openerp__.py 2013-11-07 15:51:52 +0000
2909@@ -1,57 +1,46 @@
2910 # -*- coding: utf-8 -*-
2911 ##############################################################################
2912 #
2913-# Copyright (c) 2011 Camptocamp SA (http://www.camptocamp.com)
2914-# All Right Reserved
2915-#
2916-# Author : Guewen Baconnier (Camptocamp)
2917-# Author : Vincent Renaville
2918-#
2919-# WARNING: This program as such is intended to be used by professional
2920-# programmers who take the whole responsability of assessing all potential
2921-# consequences resulting from its eventual inadequacies and bugs
2922-# End users who are looking for a ready-to-use solution with commercial
2923-# garantees and support are strongly adviced to contract a Free Software
2924-# Service Company
2925-#
2926-# This program is Free Software; you can redistribute it and/or
2927-# modify it under the terms of the GNU General Public License
2928-# as published by the Free Software Foundation; either version 2
2929-# of the License, or (at your option) any later version.
2930-#
2931-# This program is distributed in the hope that it will be useful,
2932-# but WITHOUT ANY WARRANTY; without even the implied warranty of
2933-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2934-# GNU General Public License for more details.
2935-#
2936-# You should have received a copy of the GNU General Public License
2937-# along with this program; if not, write to the Free Software
2938-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
2939+# Author: Guewen Baconnier (Camptocamp)
2940+# Author: Vincent Renaville
2941+# Copyright 2012 Camptocamp SA
2942+#
2943+# This program is free software: you can redistribute it and/or modify
2944+# it under the terms of the GNU Affero General Public License as
2945+# published by the Free Software Foundation, either version 3 of the
2946+# License, or (at your option) any later version.
2947+#
2948+# This program is distributed in the hope that it will be useful,
2949+# but WITHOUT ANY WARRANTY; without even the implied warranty of
2950+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2951+# GNU Affero General Public License for more details.
2952+#
2953+# You should have received a copy of the GNU Affero General Public License
2954+# along with this program. If not, see <http://www.gnu.org/licenses/>.
2955 #
2956 ##############################################################################
2957
2958-
2959-{
2960- "name" : "Timesheet fullfill wizard",
2961- "version" : "1.0",
2962- "author" : "Camptocamp",
2963- "category" : "Generic Modules/Human Resources",
2964- "description":
2965-"""
2966-Add a wizard into timesheet allowing people to complete a long period of time with the given values.
2967-This is mainly useful to handle a long period of time like holidays.
2968-Known limitation:
2969- - Will complete all day between dates
2970-""",
2971- "website": "http://camptocamp.com",
2972- "depends" : [
2973- "hr_timesheet_sheet",
2974- ],
2975- "init_xml" : [],
2976- "demo_xml" : [],
2977- "update_xml" : [
2978- 'wizard/timesheet_fulfill_view.xml',
2979- ],
2980- "active": False,
2981- "installable": True
2982+{'name' : 'Timesheet Fullfill Wizard',
2983+ 'version' : '1.0',
2984+ 'category' : 'Generic Modules/Human Resources',
2985+ 'description':
2986+ '''
2987+ Add a wizard into timesheet allowing people to complete a long period of time with the given values.
2988+ This is mainly useful to handle a long period of time like holidays.
2989+ Known limitation:
2990+ - Will complete all day between dates
2991+ ''',
2992+ 'author' : 'Camptocamp',
2993+ 'website': 'http://camptocamp.com',
2994+ 'depends' : ['hr_timesheet_sheet',],
2995+ 'data' : [
2996+ 'wizard/timesheet_fulfill_view.xml',
2997+ ],
2998+ 'demo' : [],
2999+ 'test' : [],
3000+ 'installable': True,
3001+ 'auto_install' : False,
3002+ 'application' : False,
3003 }
3004+
3005+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
3006
3007=== modified file 'hr_timesheet_fulfill/wizard/__init__.py'
3008--- hr_timesheet_fulfill/wizard/__init__.py 2011-08-12 12:53:16 +0000
3009+++ hr_timesheet_fulfill/wizard/__init__.py 2013-11-07 15:51:52 +0000
3010@@ -1,1 +1,4 @@
3011+
3012 import timesheet_fulfill
3013+
3014+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
3015\ No newline at end of file
3016
3017=== modified file 'hr_timesheet_fulfill/wizard/timesheet_fulfill.py'
3018--- hr_timesheet_fulfill/wizard/timesheet_fulfill.py 2011-09-01 13:44:19 +0000
3019+++ hr_timesheet_fulfill/wizard/timesheet_fulfill.py 2013-11-07 15:51:52 +0000
3020@@ -1,41 +1,29 @@
3021 # -*- coding: utf-8 -*-
3022 ##############################################################################
3023 #
3024-# Copyright (c) 2011 Camptocamp SA (http://www.camptocamp.com)
3025-# All Right Reserved
3026-#
3027-# Author : Guewen Baconnier (Camptocamp)
3028-# Author : Vincent Renaville
3029-#
3030-# WARNING: This program as such is intended to be used by professional
3031-# programmers who take the whole responsability of assessing all potential
3032-# consequences resulting from its eventual inadequacies and bugs
3033-# End users who are looking for a ready-to-use solution with commercial
3034-# garantees and support are strongly adviced to contract a Free Software
3035-# Service Company
3036-#
3037-# This program is Free Software; you can redistribute it and/or
3038-# modify it under the terms of the GNU General Public License
3039-# as published by the Free Software Foundation; either version 2
3040-# of the License, or (at your option) any later version.
3041-#
3042-# This program is distributed in the hope that it will be useful,
3043-# but WITHOUT ANY WARRANTY; without even the implied warranty of
3044-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3045-# GNU General Public License for more details.
3046-#
3047-# You should have received a copy of the GNU General Public License
3048-# along with this program; if not, write to the Free Software
3049-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
3050+# Author: Guewen Baconnier (Camptocamp)
3051+# Author: Vincent Renaville
3052+# Copyright 2012 Camptocamp SA
3053+#
3054+# This program is free software: you can redistribute it and/or modify
3055+# it under the terms of the GNU Affero General Public License as
3056+# published by the Free Software Foundation, either version 3 of the
3057+# License, or (at your option) any later version.
3058+#
3059+# This program is distributed in the hope that it will be useful,
3060+# but WITHOUT ANY WARRANTY; without even the implied warranty of
3061+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3062+# GNU Affero General Public License for more details.
3063+#
3064+# You should have received a copy of the GNU Affero General Public License
3065+# along with this program. If not, see <http://www.gnu.org/licenses/>.
3066 #
3067 ##############################################################################
3068
3069-
3070-from osv import fields, osv
3071+from openerp.osv import fields, osv, orm
3072 from tools.translate import _
3073 from datetime import datetime, timedelta
3074
3075-
3076 def get_number_days_between_dates(date_from, date_to):
3077 datetime_from = datetime.strptime(date_from, '%Y-%m-%d')
3078 datetime_to = datetime.strptime(date_to, '%Y-%m-%d')
3079@@ -44,7 +32,7 @@
3080 return difference.days + 1
3081
3082
3083-class FulfillTimesheet(osv.osv_memory):
3084+class HrTimesheetFulfill(orm.TransientModel):
3085 _name = 'hr.timesheet.fulfill'
3086 _description = "Wizard to fill-in timesheet for many days"
3087
3088@@ -52,16 +40,19 @@
3089 'date_from': fields.date('Date From', required=True),
3090 'date_to': fields.date('Date To', required=True),
3091 'description': fields.char('Description', size=100, required=True),
3092- 'nb_hours': fields.float('Hours per day', digits=(2, 2), required=True),
3093+ 'nb_hours': fields.float('Hours per Day', digits=(2, 2), required=True),
3094 'analytic_account_id': fields.many2one('account.analytic.account',
3095 'Analytic Account', required=True,
3096- domain="[('type', '=', 'normal'),"
3097+ domain="[('type', '=', 'contract'),"
3098 "('state', '!=', 'pending'),"
3099 "('state', '!=', 'close')]"),
3100- 'task_id':fields.many2one('project.task','Task', required=False)
3101- }
3102-
3103- def fulfill_timesheet(self, cr, uid, ids, context):
3104+ 'task_id':fields.many2one('project.task', 'Task', required=False)
3105+ }
3106+
3107+ def fulfill_timesheet(self, cr, uid, ids, context=None):
3108+ if context is None:
3109+ context = {}
3110+
3111 employee_obj = self.pool.get('hr.employee')
3112 timesheet_obj = self.pool.get('hr_timesheet_sheet.sheet')
3113 al_ts_obj = self.pool.get('hr.analytic.timesheet')
3114@@ -117,23 +108,23 @@
3115 'sheet_id': timesheet.id,
3116 'journal_id': journal_id,
3117 }
3118-
3119 on_change_values = al_ts_obj.\
3120 on_change_unit_amount(cr, uid, False, product_id,
3121 wizard.nb_hours, employee.company_id.id,
3122- task_id=wizard.task_id.id,
3123+# task_id=wizard.task_id.id,
3124 unit=unit_id, journal_id=journal_id,
3125 context=context)
3126 if on_change_values:
3127 res.update(on_change_values['value'])
3128 al_ts_obj.create(cr, uid, res, context)
3129-
3130 # If there is no other attendances, create it
3131 # create the attendances:
3132- existing_attendances = attendance_obj\
3133- .search(cr, uid, [('name', '=', datetime_current),
3134- ('employee_id', '=', employee_id)])
3135-
3136+# print attendance_obj.read(cr,uid,['name'])
3137+ existing_attendances=0
3138+ att_id= attendance_obj.search(cr, uid, [('employee_id', '=', employee_id)])
3139+ for record in attendance_obj.read(cr,uid,att_id,['name']):
3140+ if record['name'].startswith( datetime_current ):
3141+ existing_attendances=1
3142 if not existing_attendances:
3143 att_date_start = datetime_current + " 00:00:00"
3144 att_start = {
3145@@ -154,6 +145,7 @@
3146 }
3147 attendance_obj.create(cr, uid, att_start, context)
3148 attendance_obj.create(cr, uid, att_end, context)
3149+
3150 return {'type': 'ir.actions.act_window_close'}
3151
3152-FulfillTimesheet()
3153+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
3154
3155=== modified file 'hr_timesheet_fulfill/wizard/timesheet_fulfill_view.xml'
3156--- hr_timesheet_fulfill/wizard/timesheet_fulfill_view.xml 2011-08-12 12:53:16 +0000
3157+++ hr_timesheet_fulfill/wizard/timesheet_fulfill_view.xml 2013-11-07 15:51:52 +0000
3158@@ -1,43 +1,58 @@
3159 <?xml version="1.0" encoding="utf-8"?>
3160 <openerp>
3161- <data>
3162-
3163- <record id="view_hr_timesheet_fulfill_form" model="ir.ui.view">
3164- <field name="name">hr.timesheet.fulfill.form</field>
3165- <field name="model">hr.timesheet.fulfill</field>
3166- <field name="type">form</field>
3167- <field name="arch" type="xml">
3168- <form string="Enter the dates : ALL days between those dates will be completed.">
3169- <field name="date_from"/>
3170- <field name="date_to"/>
3171- <field name="analytic_account_id"/>
3172- <field name="task_id" domain="[('state','!=','cancel'),('state','!=','done')" context="{'account_id':analytic_account_id}"/>
3173- <field name="nb_hours" widget="float_time"/>
3174- <field name="description" colspan="4"/>
3175- <group colspan="4" col="6">
3176- <button icon="gtk-cancel" special="cancel" string="Cancel"/>
3177- <button icon="gtk-ok" string="Fill in Timesheet" name="fulfill_timesheet" type="object"/>
3178- </group>
3179- </form>
3180- </field>
3181- </record>
3182-
3183- <record id="action_hr_timesheet_fulfill" model="ir.actions.act_window">
3184- <field name="name">Fill in Timesheet</field>
3185- <field name="res_model">hr.timesheet.fulfill</field>
3186- <field name="view_type">form</field>
3187- <field name="view_mode">form</field>
3188- <field name="view_id" ref="view_hr_timesheet_fulfill_form"/>
3189- <field name="target">new</field>
3190- </record>
3191-
3192- <record id="ir_action_hr_timesheet_fulfill_wizard" model="ir.values">
3193- <field name="key2">client_action_multi</field>
3194- <field name="model">hr_timesheet_sheet.sheet</field>
3195- <field name="name">Fill in Timesheet</field>
3196- <field eval="'ir.actions.act_window,%d'%action_hr_timesheet_fulfill" name="value"/>
3197- <field eval="True" name="object"/>
3198- </record>
3199-
3200-</data>
3201+ <data>
3202+
3203+ <record id="view_hr_timesheet_fulfill_form" model="ir.ui.view">
3204+ <field name="name">hr.timesheet.fulfill.form</field>
3205+ <field name="model">hr.timesheet.fulfill</field>
3206+ <field name="arch" type="xml">
3207+ <form string="Enter the dates : ALL days between those dates will be completed." version="7.0">
3208+ <group>
3209+ <group>
3210+ <field name="date_from"/>
3211+ </group>
3212+ <group>
3213+ <field name="date_to"/>
3214+ </group>
3215+ </group>
3216+ <group>
3217+ <group>
3218+ <field name="analytic_account_id"/>
3219+ </group>
3220+ <group>
3221+ <field name="task_id" domain="[('state','!=','cancel'),('state','!=','done')]" context="{'account_id':analytic_account_id}"/>
3222+ </group>
3223+ </group>
3224+ <group>
3225+ <field name="nb_hours" widget="float_time"/>
3226+ </group>
3227+ <group colspan="4">
3228+ <field name="description"/>
3229+ </group>
3230+ <footer>
3231+ <button icon="gtk-cancel" special="cancel" string="Cancel"/>
3232+ <button icon="gtk-ok" string="Fill in Timesheet" name="fulfill_timesheet" type="object"/>
3233+ </footer>
3234+ </form>
3235+ </field>
3236+ </record>
3237+
3238+ <record id="action_hr_timesheet_fulfill" model="ir.actions.act_window">
3239+ <field name="name">Fill in Timesheet</field>
3240+ <field name="res_model">hr.timesheet.fulfill</field>
3241+ <field name="view_type">form</field>
3242+ <field name="view_mode">form</field>
3243+ <field name="view_id" ref="view_hr_timesheet_fulfill_form"/>
3244+ <field name="target">new</field>
3245+ </record>
3246+
3247+ <record id="ir_action_hr_timesheet_fulfill_wizard" model="ir.values">
3248+ <field name="key2">client_action_multi</field>
3249+ <field name="model">hr_timesheet_sheet.sheet</field>
3250+ <field name="name">Fill in Timesheet</field>
3251+ <field eval="'ir.actions.act_window,%d'%action_hr_timesheet_fulfill" name="value"/>
3252+ <field eval="True" name="object"/>
3253+ </record>
3254+
3255+ </data>
3256 </openerp>
3257
3258=== modified file 'hr_timesheet_holidays/__openerp__.py'
3259--- hr_timesheet_holidays/__openerp__.py 2011-08-12 12:53:16 +0000
3260+++ hr_timesheet_holidays/__openerp__.py 2013-11-07 15:51:52 +0000
3261@@ -55,5 +55,5 @@
3262 'company_view.xml',
3263 ],
3264 "active": False,
3265- "installable": True
3266+ 'installable': False
3267 }
3268
3269=== added directory 'hr_timesheet_improvement'
3270=== added file 'hr_timesheet_improvement/__init__.py'
3271--- hr_timesheet_improvement/__init__.py 1970-01-01 00:00:00 +0000
3272+++ hr_timesheet_improvement/__init__.py 2013-11-07 15:51:52 +0000
3273@@ -0,0 +1,22 @@
3274+# -*- coding: utf-8 -*-
3275+##############################################################################
3276+#
3277+# Author : Yannick Vaucher (Camptocamp)
3278+# Copyright 2013 Camptocamp SA
3279+#
3280+# This program is free software: you can redistribute it and/or modify
3281+# it under the terms of the GNU Affero General Public License as
3282+# published by the Free Software Foundation, either version 3 of the
3283+# License, or (at your option) any later version.
3284+#
3285+# This program is distributed in the hope that it will be useful,
3286+# but WITHOUT ANY WARRANTY; without even the implied warranty of
3287+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3288+# GNU Affero General Public License for more details.
3289+#
3290+# You should have received a copy of the GNU Affero General Public License
3291+# along with this program. If not, see <http://www.gnu.org/licenses/>.
3292+#
3293+##############################################################################
3294+import hr_timesheet
3295+import hr_attendance
3296
3297=== added file 'hr_timesheet_improvement/__openerp__.py'
3298--- hr_timesheet_improvement/__openerp__.py 1970-01-01 00:00:00 +0000
3299+++ hr_timesheet_improvement/__openerp__.py 2013-11-07 15:51:52 +0000
3300@@ -0,0 +1,50 @@
3301+# -*- coding: utf-8 -*-
3302+##############################################################################
3303+#
3304+# Authors: Yannick Vaucher (Camptocamp)
3305+# Vincent Renaville (Camptocamp)
3306+# Copyright 2013 Camptocamp SA
3307+#
3308+# This program is free software: you can redistribute it and/or modify
3309+# it under the terms of the GNU Affero General Public License as
3310+# published by the Free Software Foundation, either version 3 of the
3311+# License, or (at your option) any later version.
3312+#
3313+# This program is distributed in the hope that it will be useful,
3314+# but WITHOUT ANY WARRANTY; without even the implied warranty of
3315+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3316+# GNU Affero General Public License for more details.
3317+#
3318+# You should have received a copy of the GNU Affero General Public License
3319+# along with this program. If not, see <http://www.gnu.org/licenses/>.
3320+#
3321+##############################################################################
3322+{'name' : 'Timesheet improvements',
3323+ 'version' : '0.1',
3324+ 'author' : 'Camptocamp',
3325+ 'maintainer': 'Camptocamp',
3326+ 'category': 'Human Resources',
3327+ 'depends' : ['hr_timesheet_sheet'],
3328+ 'description': """
3329+ Modifies timesheet behavior:
3330+ - Ensure a DESC order on timesheet lines
3331+ - Set default date for manually entering attendance to max attendance date
3332+ - Redefine constraint on timesheets to check alternation of 'sign in' and
3333+ 'sign out' only on current timesheet instead of doing it on all timesheets
3334+ of the employee
3335+ """,
3336+ 'website': 'http://www.camptocamp.com',
3337+ 'data': ['hr_timesheet_view.xml'],
3338+ 'js' : [],
3339+ 'css': [],
3340+ 'qweb': [],
3341+ 'demo': [],
3342+ 'test': [],
3343+ 'installable': True,
3344+ 'images' : [],
3345+ 'auto_install': False,
3346+ 'license': 'AGPL-3',
3347+ 'application': True,
3348+}
3349+
3350+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
3351
3352=== added file 'hr_timesheet_improvement/hr_attendance.py'
3353--- hr_timesheet_improvement/hr_attendance.py 1970-01-01 00:00:00 +0000
3354+++ hr_timesheet_improvement/hr_attendance.py 2013-11-07 15:51:52 +0000
3355@@ -0,0 +1,98 @@
3356+# -*- coding: utf-8 -*-
3357+##############################################################################
3358+#
3359+# Authors: Yannick Vaucher (Camptocamp)
3360+# Vincent Renaville (Camptocamp)
3361+# Copyright 2013 Camptocamp SA
3362+#
3363+# This program is free software: you can redistribute it and/or modify
3364+# it under the terms of the GNU Affero General Public License as
3365+# published by the Free Software Foundation, either version 3 of the
3366+# License, or (at your option) any later version.
3367+#
3368+# This program is distributed in the hope that it will be useful,
3369+# but WITHOUT ANY WARRANTY; without even the implied warranty of
3370+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3371+# GNU Affero General Public License for more details.
3372+#
3373+# You should have received a copy of the GNU Affero General Public License
3374+# along with this program. If not, see <http://www.gnu.org/licenses/>.
3375+#
3376+##############################################################################
3377+import time
3378+
3379+from openerp.osv import orm
3380+from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT
3381+
3382+
3383+class HrAttendance(orm.Model):
3384+ """
3385+ Alter the default date for manual setting
3386+ """
3387+ _inherit = "hr.attendance"
3388+
3389+ def _default_date(self, cr, uid, context=None):
3390+ sheet_id = context.get('sheet_id')
3391+ if not sheet_id:
3392+ return time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
3393+
3394+ ts_obj = self.pool.get('hr_timesheet_sheet.sheet')
3395+ timesheet = ts_obj.browse(cr, uid, sheet_id, context=context)
3396+
3397+ dates = [a.name for a in timesheet.attendances_ids]
3398+
3399+ if not dates:
3400+ return timesheet.date_from
3401+
3402+ return max(dates)
3403+ """
3404+ Check sign in signout in the same timesheet only
3405+ """
3406+
3407+ def _altern_si_so(self, cr, uid, ids, context=None):
3408+ """ Alternance sign_in/sign_out check.
3409+ Previous (if exists) must be of opposite action.
3410+ Next (if exists) must be of opposite action.
3411+ """
3412+ sheet_obj = self.pool.get('hr_timesheet_sheet.sheet')
3413+ for att in self.browse(cr, uid, ids, context=context):
3414+ sheet_id = sheet_obj.search(
3415+ cr, uid, [
3416+ ('employee_id', '=', att.employee_id.id),
3417+ ('date_from', '<=', att.name),
3418+ ('date_to', '>=', att.name),
3419+ ],
3420+ limit=1,
3421+ context=context)
3422+ sheet_id = sheet_id and sheet_id[0] or False
3423+
3424+ # search and browse for first previous and first next records
3425+ prev_att_ids = self.search(cr, uid, [('employee_id', '=', att.employee_id.id),
3426+ ('sheet_id', '=', sheet_id),
3427+ ('name', '<', att.name),
3428+ ('action', 'in', ('sign_in', 'sign_out'))],
3429+ limit=1, order='name DESC',
3430+ context=context)
3431+ next_add_ids = self.search(cr, uid, [('employee_id', '=', att.employee_id.id),
3432+ ('sheet_id', '=', sheet_id),
3433+ ('name', '>', att.name),
3434+ ('action', 'in', ('sign_in', 'sign_out'))],
3435+ limit=1, order='name ASC',
3436+ context=context)
3437+ prev_atts = self.browse(cr, uid, prev_att_ids, context=context)
3438+ next_atts = self.browse(cr, uid, next_add_ids, context=context)
3439+ # check for alternance, return False if at least one condition is not satisfied
3440+ if prev_atts and prev_atts[0].action == att.action: # previous exists and is same action
3441+ return False
3442+ if next_atts and next_atts[0].action == att.action: # next exists and is same action
3443+ return False
3444+ if (not prev_atts) and (not next_atts) and att.action != 'sign_in': # first attendance must be sign_in
3445+ return False
3446+ return True
3447+
3448+ _constraints = [(_altern_si_so, 'Error ! Sign in (resp. Sign out) must follow Sign out (resp. Sign in)', ['action'])]
3449+
3450+ _defaults = {
3451+ 'name': _default_date,
3452+ }
3453+
3454
3455=== added file 'hr_timesheet_improvement/hr_timesheet.py'
3456--- hr_timesheet_improvement/hr_timesheet.py 1970-01-01 00:00:00 +0000
3457+++ hr_timesheet_improvement/hr_timesheet.py 2013-11-07 15:51:52 +0000
3458@@ -0,0 +1,51 @@
3459+# -*- coding: utf-8 -*-
3460+##############################################################################
3461+#
3462+# Author : Yannick Vaucher (Camptocamp)
3463+# Copyright 2013 Camptocamp SA
3464+#
3465+# This program is free software: you can redistribute it and/or modify
3466+# it under the terms of the GNU Affero General Public License as
3467+# published by the Free Software Foundation, either version 3 of the
3468+# License, or (at your option) any later version.
3469+#
3470+# This program is distributed in the hope that it will be useful,
3471+# but WITHOUT ANY WARRANTY; without even the implied warranty of
3472+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3473+# GNU Affero General Public License for more details.
3474+#
3475+# You should have received a copy of the GNU Affero General Public License
3476+# along with this program. If not, see <http://www.gnu.org/licenses/>.
3477+#
3478+##############################################################################
3479+from openerp.osv import orm, fields
3480+
3481+class HrAnalyticTimesheet(orm.Model):
3482+ """
3483+ Set order by line date and analytic account name instead of id
3484+ We create related stored values as _order cannot be used on inherited columns
3485+ """
3486+ _inherit = "hr.analytic.timesheet"
3487+ _order = "date_aal DESC, account_name ASC"
3488+
3489+ def _get_account_analytic_line(self, cr, uid, ids, context=None):
3490+ ts_line_ids = self.pool.get('hr.analytic.timesheet').search(cr, uid, [('line_id', 'in', ids)])
3491+ return ts_line_ids
3492+
3493+ def _get_account_analytic_account(self, cr, uid, ids, context=None):
3494+ ts_line_ids = self.pool.get('hr.analytic.timesheet').search(cr, uid, [('account_id', 'in', ids)])
3495+ return ts_line_ids
3496+
3497+ _columns = {
3498+ 'date_aal': fields.related('line_id', 'date', string="Analytic Line Date", type='date',
3499+ store={
3500+ 'account.analytic.line': (_get_account_analytic_line, ['date'], 10),
3501+ 'hr.analytic.timesheet': (lambda self,cr,uid,ids,context=None: ids, None, 10),
3502+ }),
3503+ 'account_name': fields.related('account_id', 'name', string="Analytic Account Name", type='char', size=256,
3504+ store={
3505+ 'account.analytic.account': (_get_account_analytic_account, ['name'], 10),
3506+ 'hr.analytic.timesheet': (lambda self,cr,uid,ids,context=None: ids, None, 10),
3507+ }
3508+ ),
3509+ }
3510
3511=== added file 'hr_timesheet_improvement/hr_timesheet_view.xml'
3512--- hr_timesheet_improvement/hr_timesheet_view.xml 1970-01-01 00:00:00 +0000
3513+++ hr_timesheet_improvement/hr_timesheet_view.xml 2013-11-07 15:51:52 +0000
3514@@ -0,0 +1,17 @@
3515+<?xml version="1.0" encoding="utf-8"?>
3516+<openerp>
3517+ <data>
3518+
3519+ <record id="hr_timesheet_sheet_form_pass_active_id" model="ir.ui.view">
3520+ <field name="name">hr.timesheet.sheet.form</field>
3521+ <field name="model">hr_timesheet_sheet.sheet</field>
3522+ <field name="inherit_id" ref="hr_timesheet_sheet.hr_timesheet_sheet_form" />
3523+ <field name="arch" type="xml">
3524+ <field name="attendances_ids" position="attributes">
3525+ <attribute name="context">{'employee_id': employee_id, 'user_id':user_id, 'sheet_id':active_id}</attribute>
3526+ </field>
3527+ </field>
3528+ </record>
3529+
3530+ </data>
3531+</openerp>
3532
3533=== modified file 'hr_timesheet_print/__openerp__.py'
3534--- hr_timesheet_print/__openerp__.py 2012-12-12 10:35:35 +0000
3535+++ hr_timesheet_print/__openerp__.py 2013-11-07 15:51:52 +0000
3536@@ -40,5 +40,5 @@
3537 "report.xml",
3538 ],
3539 "active": False,
3540- "installable": True
3541+ 'installable': True
3542 }
3543
3544=== modified file 'hr_timesheet_reminder/__init__.py'
3545--- hr_timesheet_reminder/__init__.py 2011-08-12 12:53:16 +0000
3546+++ hr_timesheet_reminder/__init__.py 2013-11-07 15:51:52 +0000
3547@@ -1,32 +1,21 @@
3548 # -*- coding: utf-8 -*-
3549 ##############################################################################
3550 #
3551-# Copyright (c) 2011 Camptocamp SA (http://www.camptocamp.com)
3552-# All Right Reserved
3553-#
3554-# Author : Arnaud Wüst (Camptocamp)
3555-# Author : Guewen Baconnier (Camptocamp)
3556-#
3557-# WARNING: This program as such is intended to be used by professional
3558-# programmers who take the whole responsability of assessing all potential
3559-# consequences resulting from its eventual inadequacies and bugs
3560-# End users who are looking for a ready-to-use solution with commercial
3561-# garantees and support are strongly adviced to contract a Free Software
3562-# Service Company
3563-#
3564-# This program is Free Software; you can redistribute it and/or
3565-# modify it under the terms of the GNU General Public License
3566-# as published by the Free Software Foundation; either version 2
3567-# of the License, or (at your option) any later version.
3568-#
3569-# This program is distributed in the hope that it will be useful,
3570-# but WITHOUT ANY WARRANTY; without even the implied warranty of
3571-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3572-# GNU General Public License for more details.
3573-#
3574-# You should have received a copy of the GNU General Public License
3575-# along with this program; if not, write to the Free Software
3576-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
3577+# Author: Arnaud Wüst (Camptocamp)
3578+# Copyright 2011-2012 Camptocamp SA
3579+#
3580+# This program is free software: you can redistribute it and/or modify
3581+# it under the terms of the GNU Affero General Public License as
3582+# published by the Free Software Foundation, either version 3 of the
3583+# License, or (at your option) any later version.
3584+#
3585+# This program is distributed in the hope that it will be useful,
3586+# but WITHOUT ANY WARRANTY; without even the implied warranty of
3587+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3588+# GNU Affero General Public License for more details.
3589+#
3590+# You should have received a copy of the GNU Affero General Public License
3591+# along with this program. If not, see <http://www.gnu.org/licenses/>.
3592 #
3593 ##############################################################################
3594
3595
3596=== modified file 'hr_timesheet_reminder/__openerp__.py'
3597--- hr_timesheet_reminder/__openerp__.py 2011-08-12 12:53:16 +0000
3598+++ hr_timesheet_reminder/__openerp__.py 2013-11-07 15:51:52 +0000
3599@@ -1,54 +1,52 @@
3600 # -*- coding: utf-8 -*-
3601 ##############################################################################
3602 #
3603-# Copyright (c) 2011 Camptocamp SA (http://www.camptocamp.com)
3604-# All Right Reserved
3605-#
3606-# Author : Arnaud Wüst (Camptocamp)
3607-# Author : Nicolas Bessi (Camptocamp)
3608-# Author : Guewen Baconnier (Camptocamp)
3609-#
3610-# WARNING: This program as such is intended to be used by professional
3611-# programmers who take the whole responsability of assessing all potential
3612-# consequences resulting from its eventual inadequacies and bugs
3613-# End users who are looking for a ready-to-use solution with commercial
3614-# garantees and support are strongly adviced to contract a Free Software
3615-# Service Company
3616-#
3617-# This program is Free Software; you can redistribute it and/or
3618-# modify it under the terms of the GNU General Public License
3619-# as published by the Free Software Foundation; either version 2
3620-# of the License, or (at your option) any later version.
3621-#
3622-# This program is distributed in the hope that it will be useful,
3623-# but WITHOUT ANY WARRANTY; without even the implied warranty of
3624-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3625-# GNU General Public License for more details.
3626-#
3627-# You should have received a copy of the GNU General Public License
3628-# along with this program; if not, write to the Free Software
3629-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
3630+# Author: Arnaud Wüst (Camptocamp)
3631+# Author: Nicolas Bessi (Camptocamp)
3632+# Author: Guewen Baconnier (Camptocamp) (port to v7)
3633+# Copyright 2011-2012 Camptocamp SA
3634+#
3635+# This program is free software: you can redistribute it and/or modify
3636+# it under the terms of the GNU Affero General Public License as
3637+# published by the Free Software Foundation, either version 3 of the
3638+# License, or (at your option) any later version.
3639+#
3640+# This program is distributed in the hope that it will be useful,
3641+# but WITHOUT ANY WARRANTY; without even the implied warranty of
3642+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3643+# GNU Affero General Public License for more details.
3644+#
3645+# You should have received a copy of the GNU Affero General Public License
3646+# along with this program. If not, see <http://www.gnu.org/licenses/>.
3647 #
3648 ##############################################################################
3649
3650-
3651 {
3652- "name" : "Timesheet Reminder",
3653- "version" : "2.0",
3654- "author" : "Camptocamp",
3655- "category" : "",
3656- "website" : "http://www.camptocamp.com",
3657+ "name": "Timesheet Reminder",
3658+ "version": "2.0",
3659+ "author": "Camptocamp",
3660+ "license": 'AGPL-3',
3661+ "category": "",
3662+ "website": "http://www.camptocamp.com",
3663 "description": """
3664-Timesheet Reports Module:
3665- * Add a menu in Human Resources / Configuration / Timesheet Reminder. It allows to send automatic emails to those who did not complete their timesheet in the last 5 weeks.
3666- * Per employee, you can choose to send the reminder or not.
3667- * Add a report in Human Resources / Reporting / Timesheet / Timesheet Status which displays the state of the last 5 timesheets for all users per company.
3668-
3669-This module replaces the modules c2c_timesheet_reports in TinyERP 4 and OpenERP 5.
3670+Timesheet Reports Module
3671+========================
3672+
3673+ * Add a menu in `Human Resources / Configuration
3674+ / Timesheet Reminder`.
3675+ It allows to send automatic emails to those who did
3676+ not complete their timesheet in the last 5 weeks.
3677+ * Per employee, you can choose to send the reminder or not.
3678+ * Add a report in `Human Resources / Reporting / Timesheet
3679+ / Timesheet Status` which displays the state of the last
3680+ 5 timesheets for all users per company.
3681+
3682+This module replaces the modules c2c_timesheet_reports
3683+of TinyERP 4 and OpenERP 5.
3684 """,
3685- "depends" : ["hr_timesheet_sheet"],
3686- "init_xml" : [],
3687- "update_xml" : [
3688+ "depends": ["hr_timesheet_sheet"],
3689+ "init_xml": [],
3690+ "update_xml": [
3691 'security/ir.model.access.csv',
3692 'wizard/reminder_config_view.xml',
3693 'wizard/reminder_status_view.xml',
3694@@ -56,5 +54,5 @@
3695 'timesheet_report.xml',
3696 ],
3697 "active": False,
3698- "installable": True
3699+ 'installable': True
3700 }
3701
3702=== modified file 'hr_timesheet_reminder/company.py'
3703--- hr_timesheet_reminder/company.py 2012-12-13 08:25:08 +0000
3704+++ hr_timesheet_reminder/company.py 2013-11-07 15:51:52 +0000
3705@@ -1,43 +1,32 @@
3706 # -*- coding: utf-8 -*-
3707 ##############################################################################
3708 #
3709-# Copyright (c) 2011 Camptocamp SA (http://www.camptocamp.com)
3710-# All Right Reserved
3711-#
3712-# Author : Arnaud Wüst (Camptocamp)
3713-# Author : Guewen Baconnier (Camptocamp)
3714-#
3715-# WARNING: This program as such is intended to be used by professional
3716-# programmers who take the whole responsability of assessing all potential
3717-# consequences resulting from its eventual inadequacies and bugs
3718-# End users who are looking for a ready-to-use solution with commercial
3719-# garantees and support are strongly adviced to contract a Free Software
3720-# Service Company
3721-#
3722-# This program is Free Software; you can redistribute it and/or
3723-# modify it under the terms of the GNU General Public License
3724-# as published by the Free Software Foundation; either version 2
3725-# of the License, or (at your option) any later version.
3726-#
3727-# This program is distributed in the hope that it will be useful,
3728-# but WITHOUT ANY WARRANTY; without even the implied warranty of
3729-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3730-# GNU General Public License for more details.
3731-#
3732-# You should have received a copy of the GNU General Public License
3733-# along with this program; if not, write to the Free Software
3734-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
3735+# Author: Arnaud Wüst (Camptocamp)
3736+# Author: Guewen Baconnier (Camptocamp)
3737+# Copyright 2011-2012 Camptocamp SA
3738+#
3739+# This program is free software: you can redistribute it and/or modify
3740+# it under the terms of the GNU Affero General Public License as
3741+# published by the Free Software Foundation, either version 3 of the
3742+# License, or (at your option) any later version.
3743+#
3744+# This program is distributed in the hope that it will be useful,
3745+# but WITHOUT ANY WARRANTY; without even the implied warranty of
3746+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3747+# GNU Affero General Public License for more details.
3748+#
3749+# You should have received a copy of the GNU Affero General Public License
3750+# along with this program. If not, see <http://www.gnu.org/licenses/>.
3751 #
3752 ##############################################################################
3753
3754-
3755-from datetime import date, datetime
3756-from dateutil.relativedelta import *
3757-from osv import fields, osv
3758-from tools.translate import _
3759-
3760-
3761-class res_company(osv.osv):
3762+from datetime import datetime
3763+from dateutil.relativedelta import relativedelta, MO, SU
3764+from openerp.osv import osv, orm
3765+from openerp.tools.translate import _
3766+
3767+
3768+class res_company(orm.Model):
3769 _inherit = 'res.company'
3770
3771 def get_reminder_recipients(self, cr, uid, ids, context=None):
3772@@ -46,12 +35,25 @@
3773
3774 employee_obj = self.pool.get('hr.employee')
3775
3776+<<<<<<< TREE
3777 for company in self.browse(cr, uid, ids, context=context):
3778 employee_ids = employee_obj.search(
3779 cr, uid,
3780 [('company_id', '=', company.id),
3781 ('active', '=', True)],
3782 context=context)
3783+=======
3784+ for company in self.browse(cr, uid, ids, context=context):
3785+ employee_ids = employee_obj.search(
3786+ cr, uid,
3787+ [('company_id', '=', company.id),
3788+ ('receive_timesheet_alerts', '=', True)],
3789+ context=context)
3790+
3791+ if not employee_ids:
3792+ continue
3793+
3794+>>>>>>> MERGE-SOURCE
3795 employees = employee_obj.browse(cr, uid, employee_ids, context=context)
3796
3797 #periods
3798@@ -62,24 +64,26 @@
3799 # for each employee
3800 for employee in employees:
3801 # is timesheet for a period not confirmed ?
3802- for p_index in range(len(periods)):
3803- period = periods[p_index]
3804+ for period in periods:
3805 status = employee_obj.compute_timesheet_status(cr, uid, employee.id, period, context)
3806
3807 # if there is a missing sheet or a draft sheet
3808 # and the user can receive alerts
3809 # then we must alert the user
3810- if status in ['Missing', 'Draft'] and employee.receive_timesheet_alerts:
3811+ if status in ['Missing', 'Draft']:
3812 res[company.id].append(employee)
3813- break # no need to go further for this user, he is now added in the list, go to the next one
3814+ # no need to go further for this user,
3815+ # he is now added in the list, go to the next one
3816+ break
3817 return res
3818
3819 def compute_timesheet_periods(self, cr, uid, company, date, periods_number=5, context=None):
3820 """ return the timeranges to display. This is the 5 last timesheets"""
3821 periods = []
3822- last_start_date, last_end_date = self.get_last_period_dates(cr, uid, company, date, context=context)
3823+ last_start_date, last_end_date = self.get_last_period_dates(
3824+ cr, uid, company, date, context=context)
3825 for cpt in range(periods_number):
3826- #find the delta between last_XXX_date to XXX_date
3827+ # find the delta between last_XXX_date to XXX_date
3828 if company.timesheet_range == 'month':
3829 delta = relativedelta(months=-cpt)
3830 elif company.timesheet_range == 'week':
3831@@ -87,7 +91,9 @@
3832 elif company.timesheet_range == 'year':
3833 delta = relativedelta(years=-cpt)
3834 else:
3835- raise osv.except_osv(_('Error'), _('Unknow timesheet range: %s') % (company.timesheet_range,))
3836+ raise osv.except_osv(
3837+ _('Error'),
3838+ _('Unknow timesheet range: %s') % company.timesheet_range)
3839
3840 start_date = last_start_date + delta
3841 end_date = last_end_date + delta
3842@@ -97,26 +103,22 @@
3843
3844 def get_last_period_dates(self, cr, uid, company, date, context=None):
3845 """ return the start date and end date of the last period to display """
3846-
3847+
3848 # return the first day and last day of the month
3849 if company.timesheet_range == 'month':
3850 start_date = date
3851- end_date = start_date + relativedelta(months = +1)
3852+ end_date = start_date + relativedelta(months=+1)
3853
3854 #return the first and last days of the week
3855 elif company.timesheet_range == 'week':
3856 # get monday of current week
3857 start_date = date + relativedelta(weekday=MO(-1))
3858- # get sunday of current week
3859+ # get sunday of current week
3860 end_date = date + relativedelta(weekday=SU(+1))
3861
3862 # return the first and last days of the year
3863 else:
3864- start_date = datetime(date.year, 1, 1)
3865+ start_date = datetime(date.year, 1, 1)
3866 end_date = datetime(date.year, 12, 31)
3867
3868-
3869 return start_date, end_date
3870-
3871-
3872-res_company()
3873
3874=== modified file 'hr_timesheet_reminder/hr_employee.py'
3875--- hr_timesheet_reminder/hr_employee.py 2011-09-01 13:44:19 +0000
3876+++ hr_timesheet_reminder/hr_employee.py 2013-11-07 15:51:52 +0000
3877@@ -1,47 +1,38 @@
3878 # -*- coding: utf-8 -*-
3879 ##############################################################################
3880 #
3881-# Copyright (c) 2011 Camptocamp SA (http://www.camptocamp.com)
3882-# All Right Reserved
3883-#
3884-# Author : Arnaud Wüst (Camptocamp)
3885-# Author : Guewen Baconnier (Camptocamp)
3886-#
3887-# WARNING: This program as such is intended to be used by professional
3888-# programmers who take the whole responsability of assessing all potential
3889-# consequences resulting from its eventual inadequacies and bugs
3890-# End users who are looking for a ready-to-use solution with commercial
3891-# garantees and support are strongly adviced to contract a Free Software
3892-# Service Company
3893-#
3894-# This program is Free Software; you can redistribute it and/or
3895-# modify it under the terms of the GNU General Public License
3896-# as published by the Free Software Foundation; either version 2
3897-# of the License, or (at your option) any later version.
3898-#
3899-# This program is distributed in the hope that it will be useful,
3900-# but WITHOUT ANY WARRANTY; without even the implied warranty of
3901-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3902-# GNU General Public License for more details.
3903-#
3904-# You should have received a copy of the GNU General Public License
3905-# along with this program; if not, write to the Free Software
3906-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
3907+# Author: Arnaud Wüst (Camptocamp)
3908+# Author: Guewen Baconnier (Camptocamp) (port to v7)
3909+# Copyright 2011-2012 Camptocamp SA
3910+#
3911+# This program is free software: you can redistribute it and/or modify
3912+# it under the terms of the GNU Affero General Public License as
3913+# published by the Free Software Foundation, either version 3 of the
3914+# License, or (at your option) any later version.
3915+#
3916+# This program is distributed in the hope that it will be useful,
3917+# but WITHOUT ANY WARRANTY; without even the implied warranty of
3918+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3919+# GNU Affero General Public License for more details.
3920+#
3921+# You should have received a copy of the GNU Affero General Public License
3922+# along with this program. If not, see <http://www.gnu.org/licenses/>.
3923 #
3924 ##############################################################################
3925-from datetime import *
3926-
3927-from osv import fields, osv
3928-
3929-
3930-class hr_employee(osv.osv):
3931+
3932+from openerp.osv import fields, orm
3933+from openerp.tools import DEFAULT_SERVER_DATE_FORMAT
3934+
3935+
3936+class hr_employee(orm.Model):
3937 _inherit = 'hr.employee'
3938+
3939 _columns = {
3940- 'receive_timesheet_alerts': fields.boolean('Receive Timesheet Alerts'),
3941+ 'receive_timesheet_alerts': fields.boolean('Receive Timesheet Alerts'),
3942 }
3943
3944 _defaults = {
3945- 'receive_timesheet_alerts': lambda *a: True,
3946+ 'receive_timesheet_alerts': True,
3947 }
3948
3949 def compute_timesheet_status(self, cr, uid, ids, period, context):
3950@@ -50,35 +41,33 @@
3951 status = 'Error'
3952
3953 if isinstance(ids, list):
3954+ assert len(ids) == 1, "Only 1 ID expected"
3955 ids = ids[0]
3956
3957 employee = self.browse(cr, uid, ids, context=context)
3958
3959- time_from = period[0]
3960- time_to = period[1]
3961-
3962- # does the timesheet exsists in db and what is its status?
3963- timeformat = "%Y-%m-%d"
3964- str_date_from = time_from.strftime(timeformat)
3965- str_date_to = time_to.strftime(timeformat)
3966-
3967- cr.execute("""SELECT state, date_from, date_to
3968- FROM hr_timesheet_sheet_sheet
3969- WHERE employee_id = %s
3970- AND date_from >= %s
3971- AND date_to <= %s""",
3972+ time_from, time_to = period
3973+
3974+ # does the timesheet exists in db and what is its status?
3975+ str_date_from = time_from.strftime(DEFAULT_SERVER_DATE_FORMAT)
3976+ str_date_to = time_to.strftime(DEFAULT_SERVER_DATE_FORMAT)
3977+
3978+ cr.execute(
3979+ """SELECT state, date_from, date_to
3980+ FROM hr_timesheet_sheet_sheet
3981+ WHERE employee_id = %s
3982+ AND date_from >= %s
3983+ AND date_to <= %s""",
3984 (employee.id, str_date_from, str_date_to))
3985 sheets = cr.dictfetchall()
3986
3987- #the timesheet does not exists in db
3988+ # the timesheet does not exists in db
3989 if not sheets:
3990 status = 'Missing'
3991
3992- if len(sheets) > 0:
3993+ else:
3994 status = 'Confirmed'
3995- for s in sheets:
3996- if s['state'] == 'draft':
3997+ for sheet in sheets:
3998+ if sheet['state'] == 'draft':
3999 status = 'Draft'
4000 return status
4001-
4002-hr_employee()
4003
4004=== modified file 'hr_timesheet_reminder/hr_employee_view.xml'
4005--- hr_timesheet_reminder/hr_employee_view.xml 2011-08-12 12:53:16 +0000
4006+++ hr_timesheet_reminder/hr_employee_view.xml 2013-11-07 15:51:52 +0000
4007@@ -5,7 +5,6 @@
4008 <field name="name">hr.timesheet.employee.rmnd_form</field>
4009 <field name="inherit_id" ref="hr_timesheet.hr_timesheet_employee_extd_form"/>
4010 <field name="model">hr.employee</field>
4011- <field name="type">form</field>
4012 <field name="arch" type="xml">
4013 <field name="journal_id" widget="selection" position="after">
4014 <field name="receive_timesheet_alerts"/>
4015
4016=== modified file 'hr_timesheet_reminder/reminder.py'
4017--- hr_timesheet_reminder/reminder.py 2011-09-01 13:44:19 +0000
4018+++ hr_timesheet_reminder/reminder.py 2013-11-07 15:51:52 +0000
4019@@ -1,157 +1,170 @@
4020 # -*- coding: utf-8 -*-
4021 ##############################################################################
4022 #
4023-# Copyright (c) 2011 Camptocamp SA (http://www.camptocamp.com)
4024-# All Right Reserved
4025-#
4026-# Author : Arnaud Wüst (Camptocamp)
4027-# Author : Guewen Baconnier (Camptocamp)
4028-#
4029-# WARNING: This program as such is intended to be used by professional
4030-# programmers who take the whole responsability of assessing all potential
4031-# consequences resulting from its eventual inadequacies and bugs
4032-# End users who are looking for a ready-to-use solution with commercial
4033-# garantees and support are strongly adviced to contract a Free Software
4034-# Service Company
4035-#
4036-# This program is Free Software; you can redistribute it and/or
4037-# modify it under the terms of the GNU General Public License
4038-# as published by the Free Software Foundation; either version 2
4039-# of the License, or (at your option) any later version.
4040-#
4041-# This program is distributed in the hope that it will be useful,
4042-# but WITHOUT ANY WARRANTY; without even the implied warranty of
4043-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4044-# GNU General Public License for more details.
4045-#
4046-# You should have received a copy of the GNU General Public License
4047-# along with this program; if not, write to the Free Software
4048-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
4049+# Author: Arnaud Wüst (Camptocamp)
4050+# Author: Guewen Baconnier (Camptocamp) (port to v7)
4051+# Copyright 2011-2012 Camptocamp SA
4052+#
4053+# This program is free software: you can redistribute it and/or modify
4054+# it under the terms of the GNU Affero General Public License as
4055+# published by the Free Software Foundation, either version 3 of the
4056+# License, or (at your option) any later version.
4057+#
4058+# This program is distributed in the hope that it will be useful,
4059+# but WITHOUT ANY WARRANTY; without even the implied warranty of
4060+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4061+# GNU Affero General Public License for more details.
4062+#
4063+# You should have received a copy of the GNU Affero General Public License
4064+# along with this program. If not, see <http://www.gnu.org/licenses/>.
4065 #
4066 ##############################################################################
4067
4068-import tools
4069-import time
4070-
4071 from datetime import datetime, timedelta
4072-from osv import fields, osv
4073-from tools.translate import _
4074-
4075-class reminder(osv.osv):
4076+from openerp.osv import fields, orm
4077+from openerp.tools.translate import _
4078+from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT
4079+
4080+
4081+class reminder(orm.Model):
4082 _name = "hr.timesheet.reminder"
4083 _description = "Handle the scheduling of timesheet reminders"
4084
4085 _columns = {
4086- 'reply_to': fields.char('Reply To', size=100),
4087- 'message': fields.text('Message'),
4088- 'subject': fields.char('Subject', size=200),
4089+ 'reply_to': fields.char('Reply To'),
4090+ 'message': fields.html('Message'),
4091+ 'subject': fields.char('Subject'),
4092 }
4093
4094- #default cron (the one created if missing)
4095+ # default cron (the one created if missing)
4096 cron = {'active': False,
4097 'priority': 1,
4098 'interval_number': 1,
4099 'interval_type': 'weeks',
4100- 'nextcall': time.strftime("%Y-%m-%d %H:%M:%S",
4101- (datetime.today()
4102- + timedelta(days=1)).timetuple()), # tomorrow same time
4103+ 'nextcall': False, # to set on the creation of the cron
4104 'numbercall': -1,
4105- 'doall': True,
4106+ 'doall': False,
4107 'model': 'hr.timesheet.reminder',
4108 'function': 'run',
4109 'args': '()',
4110 }
4111
4112- #default message (the one created if missing)
4113+ # default message (the one created if missing)
4114 message = {'reply_to': 'spam@camptocamp.com'}
4115
4116 def run(self, cr, uid, context=None):
4117 """ find the reminder recipients and send them an email """
4118- context = context or {}
4119-
4120 company_obj = self.pool.get('res.company')
4121- #get all companies
4122+ # get all companies
4123 company_ids = company_obj.search(cr, uid, [], context=context)
4124
4125- #for each company, get all recipients
4126+ # for each company, get all recipients
4127 recipients = []
4128- company_recipients = company_obj.get_reminder_recipients(cr, uid, company_ids, context=context)
4129- for company_id, rec in company_recipients.iteritems():
4130+ company_recipients = company_obj.get_reminder_recipients(
4131+ cr, uid, company_ids, context=context)
4132+ for rec in company_recipients.itervalues():
4133 recipients += rec
4134
4135- #get the message to send
4136+ # get the message to send
4137 message_id = self.get_message_id(cr, uid, context)
4138 message_data = self.browse(cr, uid, message_id, context=context)
4139
4140- #send them email if they have an email defined
4141- emails = []
4142+ # send them email if they have an email defined
4143 for employee in recipients:
4144- if employee.work_email:
4145- emails.append(employee.work_email)
4146-
4147- if emails:
4148- tools.email_send(message_data.reply_to, [], message_data.subject, message_data.message, email_bcc=emails)
4149-
4150- def get_cron_id(self, cr, uid, context):
4151+ if not employee.work_email:
4152+ continue
4153+ vals = {
4154+ 'state': 'outgoing',
4155+ 'subject': message_data.subject,
4156+ 'body_html': message_data.message,
4157+ 'email_to': employee.work_email,
4158+ 'email_from': message_data.reply_to,
4159+ }
4160+ self.pool.get('mail.mail').create(cr, uid, vals, context=context)
4161+
4162+ return True
4163+
4164+ def get_cron_id(self, cr, uid, context=None):
4165 """return the reminder cron's id. Create one if the cron does not exists """
4166+ if context is None:
4167+ context = {}
4168 cron_obj = self.pool.get('ir.cron')
4169 # find the cron that send messages
4170- cron_id = cron_obj.search(cr, uid, [('function', 'ilike', self.cron['function']),
4171- ('model', 'ilike', self.cron['model'])],
4172- context={'active_test': False})
4173- if cron_id:
4174- cron_id = cron_id[0]
4175+ ctx = dict(context, active_test=False)
4176+ cron_ids = cron_obj.search(
4177+ cr, uid,
4178+ [('function', 'ilike', self.cron['function']),
4179+ ('model', 'ilike', self.cron['model'])],
4180+ context=ctx)
4181+
4182+ cron_id = None
4183+ if cron_ids:
4184+ cron_id = cron_ids[0]
4185
4186 # the cron does not exists
4187- if not cron_id:
4188- self.cron['name'] = _('timesheet status reminder')
4189- cron_id = cron_obj.create(cr, uid, self.cron, context)
4190+ if cron_id is None:
4191+ vals = dict(self.cron,
4192+ name=_('timesheet status reminder'),
4193+ nextcall=self._cron_nextcall())
4194+
4195+ cron_id = cron_obj.create(cr, uid, vals, context=context)
4196
4197 return cron_id
4198
4199- def get_message_id(self, cr, uid, context):
4200- """ return the message'id. create one if the message does not exists """
4201+ @staticmethod
4202+ def _cron_nextcall():
4203+ tomorrow = datetime.today() + timedelta(days=1)
4204+ return tomorrow.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
4205+
4206+ def get_message_id(self, cr, uid, context=None):
4207+ """ return the message's id. create one if the message does not exists """
4208 #there is only one line in db, let's get it
4209- message_id = self.search(cr, uid, [], limit=1, context=context)
4210+ message_ids = self.search(cr, uid, [], limit=1, context=context)
4211
4212- if message_id:
4213- message_id = message_id[0]
4214+ message_id = None
4215+ if message_ids:
4216+ message_id = message_ids[0]
4217
4218 #the message does not exists
4219- if not message_id:
4220- #translate
4221- self.message['subject'] = _('Timesheet Reminder')
4222- self.message['message'] = _('At least one of your last timesheets is still in draft or is missing. Please take time to complete and confirm it.')
4223+ if message_id is None:
4224+ vals = dict(self.message,
4225+ subject=_('Timesheet Reminder'),
4226+ message=_(
4227+ 'At least one of your last timesheets is still '
4228+ 'in draft or is missing. Please take time to '
4229+ 'complete and confirm it.'))
4230
4231- message_id = self.create(cr, uid, self.message, context)
4232+ message_id = self.create(cr, uid, vals, context)
4233
4234 return message_id
4235
4236- def get_config(self, cr, uid, context):
4237+ def get_config(self, cr, uid, context=None):
4238 """return the reminder config from the db """
4239
4240 cron_id = self.get_cron_id(cr, uid, context)
4241
4242- cron_data = self.pool.get('ir.cron').browse(cr, uid, cron_id)
4243+ cron_data = self.pool.get('ir.cron').browse(
4244+ cr, uid, cron_id, context=context)
4245
4246- #there is only one line in db, let's get it
4247- message_id = self.get_message_id(cr, uid, context)
4248- message_data = self.browse(cr, uid, message_id)
4249+ # there is only one line in db, let's get it
4250+ message_id = self.get_message_id(cr, uid, context=context)
4251+ message_data = self.browse(cr, uid, message_id, context=context)
4252 return {'reminder_active': cron_data.active,
4253 'interval_type': cron_data.interval_type,
4254 'interval_number': cron_data.interval_number,
4255 'reply_to': message_data.reply_to,
4256 'message': message_data.message,
4257 'subject': message_data.subject,
4258- 'nextcall': cron_data.nextcall,
4259+ 'nextcall': self._cron_nextcall(),
4260 }
4261
4262- def save_config(self, cr, uid, ids, datas, context):
4263+ def save_config(self, cr, uid, ids, datas, context=None):
4264 """save the reminder config """
4265
4266 #modify the cron
4267- cron_id = self.get_cron_id(cr, uid, context)
4268- self.pool.get('ir.cron').write(cr, uid, [cron_id],
4269+ cron_id = self.get_cron_id(cr, uid, context=context)
4270+ self.pool.get('ir.cron').write(
4271+ cr, uid, [cron_id],
4272 {'active': datas['reminder_active'],
4273 'interval_number': datas['interval_number'],
4274 'interval_type': datas['interval_type'],
4275@@ -159,11 +172,10 @@
4276 context=context)
4277 #modify the message
4278 message_id = ids or self.get_message_id(cr, uid, context)
4279- self.write(cr, uid, [message_id],
4280+ self.write(
4281+ cr, uid, [message_id],
4282 {'reply_to': datas['reply_to'],
4283 'message': datas['message'],
4284 'subject': datas['subject'],
4285 }, context=context)
4286 return True
4287-
4288-reminder()
4289
4290=== modified file 'hr_timesheet_reminder/report/__init__.py'
4291--- hr_timesheet_reminder/report/__init__.py 2011-08-12 12:53:16 +0000
4292+++ hr_timesheet_reminder/report/__init__.py 2013-11-07 15:51:52 +0000
4293@@ -1,31 +1,22 @@
4294 # -*- coding: utf-8 -*-
4295 ##############################################################################
4296 #
4297-# Copyright (c) Camptocamp SA
4298-# Author: Arnaud WÃŒst
4299-#
4300-#
4301-#
4302-# WARNING: This program as such is intended to be used by professional
4303-# programmers who take the whole responsability of assessing all potential
4304-# consequences resulting from its eventual inadequacies and bugs
4305-# End users who are looking for a ready-to-use solution with commercial
4306-# garantees and support are strongly adviced to contract a Free Software
4307-# Service Company
4308-#
4309-# This program is Free Software; you can redistribute it and/or
4310-# modify it under the terms of the GNU General Public License
4311-# as published by the Free Software Foundation; either version 2
4312-# of the License, or (at your option) any later version.
4313-#
4314-# This program is distributed in the hope that it will be useful,
4315-# but WITHOUT ANY WARRANTY; without even the implied warranty of
4316-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4317-# GNU General Public License for more details.
4318-#
4319-# You should have received a copy of the GNU General Public License
4320-# along with this program; if not, write to the Free Software
4321-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
4322+# Author: Arnaud Wüst (Camptocamp)
4323+# Copyright 2011-2012 Camptocamp SA
4324+#
4325+# This program is free software: you can redistribute it and/or modify
4326+# it under the terms of the GNU Affero General Public License as
4327+# published by the Free Software Foundation, either version 3 of the
4328+# License, or (at your option) any later version.
4329+#
4330+# This program is distributed in the hope that it will be useful,
4331+# but WITHOUT ANY WARRANTY; without even the implied warranty of
4332+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4333+# GNU Affero General Public License for more details.
4334+#
4335+# You should have received a copy of the GNU Affero General Public License
4336+# along with this program. If not, see <http://www.gnu.org/licenses/>.
4337 #
4338 ##############################################################################
4339+
4340 import timesheet_status
4341
4342=== modified file 'hr_timesheet_reminder/report/timesheet_status.py'
4343--- hr_timesheet_reminder/report/timesheet_status.py 2011-09-01 13:44:19 +0000
4344+++ hr_timesheet_reminder/report/timesheet_status.py 2013-11-07 15:51:52 +0000
4345@@ -1,47 +1,40 @@
4346 # -*- coding: utf-8 -*-
4347 ##############################################################################
4348 #
4349-# Copyright (c) Camptocamp SA
4350-# Author: Arnaud WÃŒst
4351-# Author: Guewen Baconnier
4352-#
4353-#
4354-#
4355-# WARNING: This program as such is intended to be used by professional
4356-# programmers who take the whole responsability of assessing all potential
4357-# consequences resulting from its eventual inadequacies and bugs
4358-# End users who are looking for a ready-to-use solution with commercial
4359-# garantees and support are strongly adviced to contract a Free Software
4360-# Service Company
4361-#
4362-# This program is Free Software; you can redistribute it and/or
4363-# modify it under the terms of the GNU General Public License
4364-# as published by the Free Software Foundation; either version 2
4365-# of the License, or (at your option) any later version.
4366-#
4367-# This program is distributed in the hope that it will be useful,
4368-# but WITHOUT ANY WARRANTY; without even the implied warranty of
4369-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4370-# GNU General Public License for more details.
4371-#
4372-# You should have received a copy of the GNU General Public License
4373-# along with this program; if not, write to the Free Software
4374-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
4375+# Author: Arnaud Wüst (Camptocamp)
4376+# Author: Guewen Baconnier (Camptocamp) (port to v7)
4377+# Copyright 2011-2012 Camptocamp SA
4378+#
4379+# This program is free software: you can redistribute it and/or modify
4380+# it under the terms of the GNU Affero General Public License as
4381+# published by the Free Software Foundation, either version 3 of the
4382+# License, or (at your option) any later version.
4383+#
4384+# This program is distributed in the hope that it will be useful,
4385+# but WITHOUT ANY WARRANTY; without even the implied warranty of
4386+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4387+# GNU Affero General Public License for more details.
4388+#
4389+# You should have received a copy of the GNU Affero General Public License
4390+# along with this program. If not, see <http://www.gnu.org/licenses/>.
4391 #
4392 ##############################################################################
4393
4394 import time
4395
4396 from datetime import datetime
4397-from report import report_sxw
4398+from openerp.report import report_sxw
4399+from openerp.tools import DEFAULT_SERVER_DATE_FORMAT
4400+from openerp.tools.translate import _
4401
4402
4403 class timesheet_status(report_sxw.rml_parse):
4404 _name = 'report.timesheet.reminder.status'
4405
4406- def __init__(self, cr, uid, name, context):
4407- super(timesheet_status, self).__init__(cr, uid, name, context)
4408+ def __init__(self, cr, uid, name, context=None):
4409+ super(timesheet_status, self).__init__(cr, uid, name, context=context)
4410 self.data = {}
4411+ self.end_date = None
4412 self.localcontext.update({
4413 'compute': self.compute,
4414 'time': time,
4415@@ -60,64 +53,65 @@
4416 """compute all datas and do all the calculations before to start the rml rendering
4417 - objects are companies
4418 """
4419- #init the data array
4420+ # init the data array
4421 self.data = {}
4422 for o in objects:
4423 self.data[o.id] = {}
4424- #get the list of employees ids to treat
4425+ # get the list of employees ids to treat
4426 for o in objects:
4427 self.data[o.id]['employees'] = self._compute_employees_list(o)
4428
4429- #get the time range for each company
4430+ # get the time range for each company
4431+ end_date = datetime.strptime(self.end_date, DEFAULT_SERVER_DATE_FORMAT)
4432 for o in objects:
4433- self.data[o.id]['time_ranges'] = \
4434- self._compute_periods(o, datetime.strptime(self.end_date, "%Y-%m-%d"))
4435+ self.data[o.id]['time_ranges'] = self._compute_periods(o, end_date)
4436
4437- #get the status of each timesheet for each employee
4438+ # get the status of each timesheet for each employee
4439 for o in objects:
4440 self.data[o.id]['sheet_status'] = self._compute_all_status(o)
4441
4442 def _compute_employees_list(self, company):
4443- """ return a dictionnary of lists of employees ids linked to the companies (param company) """
4444+ """ return a dictionnary of lists of employees ids linked
4445+ to the companies (param company) """
4446 employee_obj = self.pool.get('hr.employee')
4447 employee_ids = employee_obj.search(self.cr, self.uid,
4448 [('company_id', '=', company.id),
4449 ('active', '=', True)],
4450 context=self.localcontext)
4451- return employee_obj.browse(self.cr, self.uid, employee_ids, context=self.localcontext)
4452+ return employee_obj.browse(
4453+ self.cr, self.uid, employee_ids, context=self.localcontext)
4454
4455 def _get_last_period_dates(self, company, date):
4456 """ return the start date of the last period to display """
4457- return self.pool.get('res.company').\
4458- get_last_period_dates(self.cr, self.uid, company, date, context=self.localcontext)
4459+ return self.pool.get('res.company').get_last_period_dates(
4460+ self.cr,
4461+ self.uid,
4462+ company,
4463+ date,
4464+ context=self.localcontext)
4465
4466 def _compute_periods(self, company, date):
4467 """ return the timeranges to display. This is the 5 last timesheets """
4468- return self.pool.get('res.company').\
4469- compute_timesheet_periods(self.cr, self.uid, company, date, context=self.localcontext)
4470+ return self.pool.get('res.company').compute_timesheet_periods(
4471+ self.cr,
4472+ self.uid,
4473+ company,
4474+ date,
4475+ context=self.localcontext)
4476
4477 def get_title(self, obj):
4478 """ return the title of the main table """
4479- last_id = len(self.data[obj.id]['time_ranges']) - 1
4480- start_date = time.strptime(str(self.data[obj.id]['time_ranges'][last_id][0]),
4481- "%Y-%m-%d %H:%M:%S")
4482- start_date = time.strftime("%d.%m.%Y", start_date)
4483-
4484- end_date = time.strptime(str(self.data[obj.id]['time_ranges'][0][1]),
4485- "%Y-%m-%d %H:%M:%S")
4486- end_date = time.strftime("%d.%m.%Y", end_date)
4487-
4488- return obj.name + ", " + start_date + " to " + end_date
4489+ timerange = self.data[obj.id]['time_ranges']
4490+ start_date = self.formatLang(timerange[-1][0], date=True)
4491+ end_date = self.formatLang(timerange[0][1], date=True)
4492+
4493+ return obj.name + ", " + start_date + _(" to ") + end_date
4494
4495 def get_timerange_title(self, obj, cpt):
4496 """ return a header text for a periods column """
4497- start_date = self.data[obj.id]['time_ranges'][cpt][0]
4498- start_date = time.strptime(str(start_date), "%Y-%m-%d %H:%M:%S")
4499- start_date = time.strftime("%d.%m.%Y", start_date)
4500-
4501- end_date = self.data[obj.id]['time_ranges'][cpt][1]
4502- end_date = time.strptime(str(end_date), "%Y-%m-%d %H:%M:%S")
4503- end_date = time.strftime("%d.%m.%Y", end_date)
4504+ timerange = self.data[obj.id]['time_ranges'][cpt]
4505+ start_date = self.formatLang(timerange[0], date=True)
4506+ end_date = self.formatLang(timerange[1], date=True)
4507
4508 return start_date + "\n " + end_date
4509
4510@@ -131,21 +125,25 @@
4511
4512 def _compute_timesheet_status(self, employee_id, period):
4513 """ return the timesheet status for a user and a period """
4514- return self.pool.get('hr.employee').\
4515- compute_timesheet_status(self.cr, self.uid, employee_id, period, context=self.localcontext)
4516+ return self.pool.get('hr.employee').compute_timesheet_status(
4517+ self.cr,
4518+ self.uid,
4519+ employee_id,
4520+ period,
4521+ context=self.localcontext)
4522
4523- def _compute_all_status(self, o):
4524+ def _compute_all_status(self, obj):
4525 """ compute all status for all employees for all periods """
4526 result = {}
4527
4528 #for each periods
4529- for p_index in range(len(self.data[o.id]['time_ranges'])):
4530+ for p_index, period in enumerate(self.data[obj.id]['time_ranges']):
4531 result[p_index] = {}
4532- period = self.data[o.id]['time_ranges'][p_index]
4533 #for each employees
4534- for employee in self.data[o.id]['employees']:
4535+ for employee in self.data[obj.id]['employees']:
4536 #compute the status
4537- result[p_index][employee.id] = self._compute_timesheet_status(employee.id, period)
4538+ result[p_index][employee.id] = self._compute_timesheet_status(
4539+ employee.id, period)
4540
4541 return result
4542
4543
4544=== modified file 'hr_timesheet_reminder/report/timesheet_status.rml'
4545--- hr_timesheet_reminder/report/timesheet_status.rml 2011-08-12 12:53:16 +0000
4546+++ hr_timesheet_reminder/report/timesheet_status.rml 2013-11-07 15:51:52 +0000
4547@@ -1,165 +1,159 @@
4548 <?xml version="1.0"?>
4549 <document filename="timesheet_status.pdf">
4550-##############################################################################
4551-#
4552-# Copyright (c) Camptocamp SA
4553-# Author: Arnaud Wüst
4554-#
4555-#
4556-# WARNING: This program as such is intended to be used by professional
4557-# programmers who take the whole responsability of assessing all potential
4558-# consequences resulting from its eventual inadequacies and bugs
4559-# End users who are looking for a ready-to-use solution with commercial
4560-# garantees and support are strongly adviced to contract a Free Software
4561-# Service Company
4562-#
4563-# This program is Free Software; you can redistribute it and/or
4564-# modify it under the terms of the GNU General Public License
4565-# as published by the Free Software Foundation; either version 2
4566-# of the License, or (at your option) any later version.
4567-#
4568-# This program is distributed in the hope that it will be useful,
4569-# but WITHOUT ANY WARRANTY; without even the implied warranty of
4570-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4571-# GNU General Public License for more details.
4572-#
4573-# You should have received a copy of the GNU General Public License
4574-# along with this program; if not, write to the Free Software
4575-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
4576-#
4577-##############################################################################
4578-
4579- <!-- Process all datas -->
4580- <template pageSize="(21cm,29.7cm)" title="Timesheet Status" author="Camptocamp" allowSplitting="20">
4581-
4582-
4583- <!-- PAGE: template of all pages (= all pages except first and last if defined)-->
4584- <pageTemplate id="all">
4585- <pageGraphics>
4586- <setFont name="Helvetica-Bold" size="9"/>
4587-
4588- <!--Header-->
4589- <drawString x="1.2cm" y="28.1cm">[[ company.name ]]</drawString>
4590- <drawString x="17.0cm" y="28.1cm">Timesheet Status</drawString>
4591-
4592- <lineMode width="0.7"/>
4593- <lines>1.2cm 28.0cm 19.8cm 28.0cm</lines>
4594-
4595- <!-- Footer -->
4596- <setFont name="Helvetica" size="9"/>
4597- <drawString x="1.2cm" y="1.3cm"> [[ time.strftime("%m-%d-%y %H:%M", time.localtime()) ]]</drawString>
4598- <drawString x="18.8cm" y="1.3cm">Page <pageNumber/></drawString>
4599-
4600- </pageGraphics>
4601- <frame id="all" x1="1.2cm" y1="1.7cm" width="18.6cm" height="25.8cm"/>
4602- </pageTemplate>
4603-
4604- </template>
4605- <stylesheet>
4606-
4607- <!--TABLE: standard table type "columns" (which means there is a title, a header of fields names and then lines of values) -->
4608- <blockTableStyle id="std">
4609- <blockAlignment value="LEFT"/>
4610- <blockValign value="TOP"/>
4611- <blockBottomPadding length="4"/>
4612- <blockFont name="Helvetica" size="9" start="0,0" stop="-1,-1"/>
4613-
4614- <!-- first line: table name, fake as it was only one cell. grey bg -->
4615- <lineStyle kind="BOX" colorName="black" start="0,0" stop="-1,0"/>
4616- <blockBackground colorName="#cccccc" start="0,0" stop="-1,0"/>
4617- <blockFont name="Helvetica" size="9" start="0,0" stop="-1,0"/>
4618- <!-- second line: header of columns -->
4619- <lineStyle kind="GRID" colorName="black" start="0,1" stop="-1,1"/>
4620- <blockFont name="Helvetica-Oblique" start="0,1" stop="-1,1"/>
4621- <!-- next lines: light grey lines, strong black columns separator, reduce padding to write more data in cells -->
4622- <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="0,2" stop="-1,-1"/>
4623- <lineStyle kind="LINEAFTER" colorName="black" start="0,2" stop="-1,-1"/>
4624- <!-- last line: line below -->
4625- <lineStyle kind="OUTLINE" colorName="black" start="0,0" stop="-1,-1"/>
4626- <!-- all columns centered except the first two (1 system columns + employee) -->
4627- <blockAlignment value="CENTER" start="2,1" stop="-1,-1" />
4628-
4629- </blockTableStyle>
4630-
4631- <!-- default para in tables -->
4632- <paraStyle name="std"
4633- fontName="Helvetica"
4634- fontSize="9"
4635- alignment="LEFT"
4636- />
4637-
4638- <paraStyle name="Confirmed"
4639- fontName="Helvetica"
4640- fontSize="9"
4641- alignment="CENTER"
4642- backColor="green"
4643- textColor="white"
4644- />
4645-
4646- <paraStyle name="Missing"
4647- fontName="Helvetica"
4648- fontSize="9"
4649- alignment="CENTER"
4650- backColor="red"
4651- textColor="white"
4652- />
4653-
4654- <paraStyle name="Draft"
4655- fontName="Helvetica"
4656- fontSize="9"
4657- alignment="CENTER"
4658- backColor="orange"
4659- textColor="black"
4660- />
4661-
4662- <paraStyle name="Error"
4663- fontName="Helvetica"
4664- fontSize="9"
4665- alignment="CENTER"
4666- textColor="red"
4667- />
4668-
4669- <paraStyle name="Not in Company"
4670- fontName="Helvetica"
4671- fontSize="9"
4672- alignment="CENTER"
4673- textColor="lightgrey"
4674- />
4675-
4676-
4677- </stylesheet>
4678-
4679- <story>
4680-
4681- [[repeatIn(objects, 'o')]]
4682- <blockTable style="std" repeatRows="2" colWidths="0,5cm,2.7cm,2.7cm,2.7cm,2.7cm,2.7cm" >
4683-
4684- <tr>
4685- <td/>
4686- <td>[[get_title(o)]]</td>
4687- </tr>
4688-
4689- <tr>
4690- <td/>
4691- <td>Employees</td>
4692- <td>[[ get_timerange_title(o, 4) ]]</td>
4693- <td>[[ get_timerange_title(o, 3) ]]</td>
4694- <td>[[ get_timerange_title(o, 2) ]]</td>
4695- <td>[[ get_timerange_title(o, 1) ]]</td>
4696- <td>[[ get_timerange_title(o, 0) ]]</td>
4697- </tr>
4698-
4699- <tr>
4700- <td>[[repeatIn(get_user_list(o),'u')]]</td>
4701- <td><para style="std">[[ u.name ]]</para></td>
4702- <td><para>[[ setTag('para','para',{'style':get_timesheet_status(o, u, 4)}) ]][[ get_timesheet_status(o, u, 4) ]]</para></td>
4703- <td><para>[[ setTag('para','para',{'style':get_timesheet_status(o, u, 3)}) ]][[ get_timesheet_status(o, u, 3) ]]</para></td>
4704- <td><para>[[ setTag('para','para',{'style':get_timesheet_status(o, u, 2)}) ]][[ get_timesheet_status(o, u, 2) ]]</para></td>
4705- <td><para>[[ setTag('para','para',{'style':get_timesheet_status(o, u, 1)}) ]][[ get_timesheet_status(o, u, 1) ]]</para></td>
4706- <td><para>[[ setTag('para','para',{'style':get_timesheet_status(o, u, 0)}) ]][[ get_timesheet_status(o, u, 0) ]]</para></td>
4707- </tr>
4708-
4709- </blockTable>
4710-
4711- </story>
4712- </document>
4713+ <!--
4714+ ##############################################################################
4715+ #
4716+ # Author: Arnaud Wüst (Camptocamp)
4717+ # Copyright 2011-2012 Camptocamp SA
4718+ #
4719+ # This program is free software: you can redistribute it and/or modify
4720+ # it under the terms of the GNU Affero General Public License as
4721+ # published by the Free Software Foundation, either version 3 of the
4722+ # License, or (at your option) any later version.
4723+ #
4724+ # This program is distributed in the hope that it will be useful,
4725+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
4726+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4727+ # GNU Affero General Public License for more details.
4728+ #
4729+ # You should have received a copy of the GNU Affero General Public License
4730+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
4731+ #
4732+ ##############################################################################
4733+ -->
4734+
4735+
4736+ <!-- Process all datas -->
4737+ <template pageSize="(21cm,29.7cm)" title="Timesheet Status" author="Camptocamp" allowSplitting="20">
4738+
4739+
4740+ <!-- PAGE: template of all pages (= all pages except first and last if defined)-->
4741+ <pageTemplate id="all">
4742+ <pageGraphics>
4743+ <setFont name="Helvetica-Bold" size="9"/>
4744+
4745+ <!--Header-->
4746+ <drawString x="1.2cm" y="28.1cm">[[ company.name ]]</drawString>
4747+ <drawString x="17.0cm" y="28.1cm">Timesheet Status</drawString>
4748+
4749+ <lineMode width="0.7"/>
4750+ <lines>1.2cm 28.0cm 19.8cm 28.0cm</lines>
4751+
4752+ <!-- Footer -->
4753+ <setFont name="Helvetica" size="9"/>
4754+ <drawString x="1.2cm" y="1.3cm"> [[ time.strftime("%m-%d-%y %H:%M", time.localtime()) ]]</drawString>
4755+ <drawString x="18.8cm" y="1.3cm">Page <pageNumber/></drawString>
4756+
4757+ </pageGraphics>
4758+ <frame id="all" x1="1.2cm" y1="1.7cm" width="18.6cm" height="25.8cm"/>
4759+ </pageTemplate>
4760+
4761+ </template>
4762+ <stylesheet>
4763+
4764+ <!--TABLE: standard table type "columns" (which means there is a title, a header of fields names and then lines of values) -->
4765+ <blockTableStyle id="std">
4766+ <blockAlignment value="LEFT"/>
4767+ <blockValign value="TOP"/>
4768+ <blockBottomPadding length="4"/>
4769+ <blockFont name="Helvetica" size="9" start="0,0" stop="-1,-1"/>
4770+
4771+ <!-- first line: table name, fake as it was only one cell. grey bg -->
4772+ <lineStyle kind="BOX" colorName="black" start="0,0" stop="-1,0"/>
4773+ <blockBackground colorName="#cccccc" start="0,0" stop="-1,0"/>
4774+ <blockFont name="Helvetica" size="9" start="0,0" stop="-1,0"/>
4775+ <!-- second line: header of columns -->
4776+ <lineStyle kind="GRID" colorName="black" start="0,1" stop="-1,1"/>
4777+ <blockFont name="Helvetica-Oblique" start="0,1" stop="-1,1"/>
4778+ <!-- next lines: light grey lines, strong black columns separator, reduce padding to write more data in cells -->
4779+ <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="0,2" stop="-1,-1"/>
4780+ <lineStyle kind="LINEAFTER" colorName="black" start="0,2" stop="-1,-1"/>
4781+ <!-- last line: line below -->
4782+ <lineStyle kind="OUTLINE" colorName="black" start="0,0" stop="-1,-1"/>
4783+ <!-- all columns centered except the first two (1 system columns + employee) -->
4784+ <blockAlignment value="CENTER" start="2,1" stop="-1,-1" />
4785+
4786+ </blockTableStyle>
4787+
4788+ <!-- default para in tables -->
4789+ <paraStyle name="std"
4790+ fontName="Helvetica"
4791+ fontSize="9"
4792+ alignment="LEFT"
4793+ />
4794+
4795+ <paraStyle name="Confirmed"
4796+ fontName="Helvetica"
4797+ fontSize="9"
4798+ alignment="CENTER"
4799+ backColor="green"
4800+ textColor="white"
4801+ />
4802+
4803+ <paraStyle name="Missing"
4804+ fontName="Helvetica"
4805+ fontSize="9"
4806+ alignment="CENTER"
4807+ backColor="red"
4808+ textColor="white"
4809+ />
4810+
4811+ <paraStyle name="Draft"
4812+ fontName="Helvetica"
4813+ fontSize="9"
4814+ alignment="CENTER"
4815+ backColor="orange"
4816+ textColor="black"
4817+ />
4818+
4819+ <paraStyle name="Error"
4820+ fontName="Helvetica"
4821+ fontSize="9"
4822+ alignment="CENTER"
4823+ textColor="red"
4824+ />
4825+
4826+ <paraStyle name="Not in Company"
4827+ fontName="Helvetica"
4828+ fontSize="9"
4829+ alignment="CENTER"
4830+ textColor="lightgrey"
4831+ />
4832+
4833+
4834+ </stylesheet>
4835+
4836+ <story>
4837+
4838+ [[repeatIn(objects, 'o')]]
4839+ <blockTable style="std" repeatRows="2" colWidths="0,5cm,2.7cm,2.7cm,2.7cm,2.7cm,2.7cm" >
4840+
4841+ <tr>
4842+ <td/>
4843+ <td>[[get_title(o)]]</td>
4844+ </tr>
4845+
4846+ <tr>
4847+ <td/>
4848+ <td>Employees</td>
4849+ <td>[[ get_timerange_title(o, 4) ]]</td>
4850+ <td>[[ get_timerange_title(o, 3) ]]</td>
4851+ <td>[[ get_timerange_title(o, 2) ]]</td>
4852+ <td>[[ get_timerange_title(o, 1) ]]</td>
4853+ <td>[[ get_timerange_title(o, 0) ]]</td>
4854+ </tr>
4855+
4856+ <tr>
4857+ <td>[[repeatIn(get_user_list(o),'u')]]</td>
4858+ <td><para style="std">[[ u.name ]]</para></td>
4859+ <td><para>[[ setTag('para', 'para', {'style': get_timesheet_status(o, u, 4)}) ]][[ get_timesheet_status(o, u, 4) ]]</para></td>
4860+ <td><para>[[ setTag('para', 'para', {'style': get_timesheet_status(o, u, 3)}) ]][[ get_timesheet_status(o, u, 3) ]]</para></td>
4861+ <td><para>[[ setTag('para', 'para', {'style': get_timesheet_status(o, u, 2)}) ]][[ get_timesheet_status(o, u, 2) ]]</para></td>
4862+ <td><para>[[ setTag('para', 'para', {'style': get_timesheet_status(o, u, 1)}) ]][[ get_timesheet_status(o, u, 1) ]]</para></td>
4863+ <td><para>[[ setTag('para', 'para', {'style': get_timesheet_status(o, u, 0)}) ]][[ get_timesheet_status(o, u, 0) ]]</para></td>
4864+ </tr>
4865+
4866+ </blockTable>
4867+
4868+ </story>
4869+</document>
4870
4871=== modified file 'hr_timesheet_reminder/timesheet_report.xml'
4872--- hr_timesheet_reminder/timesheet_report.xml 2011-08-12 12:53:16 +0000
4873+++ hr_timesheet_reminder/timesheet_report.xml 2013-11-07 15:51:52 +0000
4874@@ -1,15 +1,15 @@
4875 <?xml version="1.0"?>
4876 <openerp>
4877- <data>
4878- <report
4879- id="timesheet_status"
4880- string="Timesheet Status"
4881- model="res.company"
4882- name="timesheet.reminder.status"
4883- rml="hr_timesheet_reminder/report/timesheet_status.rml"
4884- auto="False"
4885+ <data>
4886+ <report
4887+ id="timesheet_status"
4888+ string="Timesheet Status"
4889+ model="res.company"
4890+ name="timesheet.reminder.status"
4891+ rml="hr_timesheet_reminder/report/timesheet_status.rml"
4892+ auto="False"
4893 header="True"
4894 menu="False"/>
4895-
4896- </data>
4897+
4898+ </data>
4899 </openerp>
4900
4901=== modified file 'hr_timesheet_reminder/wizard/reminder_config.py'
4902--- hr_timesheet_reminder/wizard/reminder_config.py 2011-08-12 12:53:16 +0000
4903+++ hr_timesheet_reminder/wizard/reminder_config.py 2013-11-07 15:51:52 +0000
4904@@ -1,53 +1,48 @@
4905 # -*- coding: utf-8 -*-
4906 ##############################################################################
4907 #
4908-# Copyright (c) 2011 Camptocamp SA (http://www.camptocamp.com)
4909-# All Right Reserved
4910-#
4911-# Author : Guewen Baconnier (Camptocamp)
4912-# Author : Arnaud Wüst (Camptocamp)
4913-#
4914-# WARNING: This program as such is intended to be used by professional
4915-# programmers who take the whole responsability of assessing all potential
4916-# consequences resulting from its eventual inadequacies and bugs
4917-# End users who are looking for a ready-to-use solution with commercial
4918-# garantees and support are strongly adviced to contract a Free Software
4919-# Service Company
4920-#
4921-# This program is Free Software; you can redistribute it and/or
4922-# modify it under the terms of the GNU General Public License
4923-# as published by the Free Software Foundation; either version 2
4924-# of the License, or (at your option) any later version.
4925-#
4926-# This program is distributed in the hope that it will be useful,
4927-# but WITHOUT ANY WARRANTY; without even the implied warranty of
4928-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4929-# GNU General Public License for more details.
4930-#
4931-# You should have received a copy of the GNU General Public License
4932-# along with this program; if not, write to the Free Software
4933-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
4934+# Author: Arnaud Wüst (Camptocamp)
4935+# Author: Guewen Baconnier (Camptocamp) (port to v7)
4936+# Copyright 2011-2012 Camptocamp SA
4937+#
4938+# This program is free software: you can redistribute it and/or modify
4939+# it under the terms of the GNU Affero General Public License as
4940+# published by the Free Software Foundation, either version 3 of the
4941+# License, or (at your option) any later version.
4942+#
4943+# This program is distributed in the hope that it will be useful,
4944+# but WITHOUT ANY WARRANTY; without even the implied warranty of
4945+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4946+# GNU Affero General Public License for more details.
4947+#
4948+# You should have received a copy of the GNU Affero General Public License
4949+# along with this program. If not, see <http://www.gnu.org/licenses/>.
4950 #
4951 ##############################################################################
4952
4953-from osv import osv, fields
4954-
4955-
4956-class reminder_config(osv.osv_memory):
4957+from openerp.osv import orm, fields
4958+
4959+
4960+class reminder_config(orm.TransientModel):
4961 _name = 'hr.timesheet.reminder.config'
4962
4963 _columns = {
4964 'reminder_active': fields.boolean('Reminder Active'),
4965- 'interval_type': fields.selection([('days','Day(s)'), ('weeks', 'Week(s)'), ('months', 'Month(s)')],
4966- 'Periodicity Unit',),
4967- 'interval_number': fields.integer('Periodicity Quantity',),
4968- 'nextcall': fields.datetime('Next Run',),
4969- 'message': fields.text('Message', required=True),
4970- 'subject': fields.char('Subject', size=200, required=True),
4971- 'reply_to': fields.char('Reply To', size=100, required=True),
4972+ 'interval_type': fields.selection(
4973+ [('days', 'Day(s)'),
4974+ ('weeks', 'Week(s)'),
4975+ ('months', 'Month(s)')],
4976+ 'Periodicity Unit'),
4977+ 'interval_number': fields.integer('Periodicity Quantity'),
4978+ 'nextcall': fields.datetime('Next Run'),
4979+ 'message': fields.html('Message', required=True),
4980+ 'subject': fields.char('Subject', required=True),
4981+ 'reply_to': fields.char('Reply To', required=True),
4982 }
4983
4984 def _check_interval_number(self, cr, uid, ids, context=None):
4985+ """This constraint should always have 1 id, we are in a TransientModel"""
4986+ assert len(ids) == 1, "Only 1 ID expected"
4987 obj = self.browse(cr, uid, ids[0], context=context)
4988 if obj.interval_number < 1:
4989 return False
4990@@ -60,23 +55,22 @@
4991 def default_get(self, cr, uid, fields, context=None):
4992 res = super(reminder_config, self).default_get(cr, uid, fields, context=context)
4993 data = self.pool.get('hr.timesheet.reminder').\
4994- get_config(cr, uid, context)
4995+ get_config(cr, uid, context=context)
4996 res.update(data)
4997 return res
4998
4999- def run(self, cr, uid, ids, context):
5000+ def run(self, cr, uid, ids, context=None):
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches

to all changes: