Merge lp:~elbati/hr-timesheet/adding_hr_attendance_analysis_7 into lp:~hr-core-editors/hr-timesheet/7.0

Proposed by Lorenzo Battistini
Status: Merged
Merged at revision: 44
Proposed branch: lp:~elbati/hr-timesheet/adding_hr_attendance_analysis_7
Merge into: lp:~hr-core-editors/hr-timesheet/7.0
Diff against target: 2739 lines (+2645/-0)
18 files modified
hr_attendance_analysis/AUTHORS.txt (+1/-0)
hr_attendance_analysis/__init__.py (+25/-0)
hr_attendance_analysis/__openerp__.py (+50/-0)
hr_attendance_analysis/company_view.xml (+17/-0)
hr_attendance_analysis/hr_attendance.py (+415/-0)
hr_attendance_analysis/hr_attendance_view.xml (+80/-0)
hr_attendance_analysis/i18n/hr_attendance_analysis.pot (+564/-0)
hr_attendance_analysis/i18n/it.po (+568/-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)
To merge this branch: bzr merge lp:~elbati/hr-timesheet/adding_hr_attendance_analysis_7
Reviewer Review Type Date Requested Status
Maxime Chambreuil (http://www.savoirfairelinux.com) Approve
Alexandre Fayolle - camptocamp code review, no test Needs Fixing
Guewen Baconnier @ Camptocamp code review, no test Approve
Review via email: mp+152403@code.launchpad.net

Description of the change

hr_attendance_analysis

Dynamic reports based on employee's attendances and contract's calendar.
Among other things, it lets you see the amount of working hours outside and inside the contract's working schedule (overtime).
It also provides a daily based report, showing the detailed and total hours compared to calendar hours.
Several analysis settings can be configured, like:
 - Tolerance for sign-in and sign-out
 - Attendances and overtimes roundings
 - Diffrent types of overtime, according to the overtime amount

To post a comment you must log in.
48. By Lorenzo Battistini

[FIX] __openerp__

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

I admit that I just did a quick eyeballing on the whole merge proposal, scrolling over some parts.

The feature seems very nice.

Here are some observations which are more nitpickings than real issues:

* Why is there a dependency on python 2.7?

l.146 from openerp.tools.translate instead of from tools.

l.162, what does means this 0.01666667 ?
 - the unit worth be precised in the `working_time_precision` field
 - 1.0 / 60 is more readable than 0.0166...

l.221, typo in the precision I think

l.227 the timedelta can be far easier to read with keyword arguments (timedelta(hours=precision)

l.268 using \ is to avoid, even more in arithmetic operations I think, just use the continuation inside parenthesis if the line is too long

    minutes = (datetime.minute / 60.0 +
               datetime.second / 60.0 / 60.0)

l.1937-1983 using dicts would be appropriate here instead if many elif

49. By Lorenzo Battistini

[fix] import

50. By Lorenzo Battistini

[fix] readable default value

51. By Lorenzo Battistini

[fix] typo

52. By Lorenzo Battistini

[fix] timedelta

53. By Lorenzo Battistini

[fix] avoid \

54. By Lorenzo Battistini

[fix] too many if

55. By Lorenzo Battistini

[add] comments

Revision history for this message
Lorenzo Battistini (elbati) wrote :

On 04/02/2013 02:37 PM, Guewen Baconnier @ Camptocamp wrote:
>
> * Why is there a dependency on python 2.7?

Because of timedelta.total_seconds()
<http://docs.python.org/2/library/datetime.html#datetime.timedelta.total_seconds>.

>
> l.146 from openerp.tools.translate instead of from tools.

Done

>
> l.162, what does means this 0.01666667 ?
> - the unit worth be precised in the `working_time_precision` field

How?

> - 1.0 / 60 is more readable than 0.0166...

Done

>
> l.221, typo in the precision I think

Done

>
> l.227 the timedelta can be far easier to read with keyword arguments (timedelta(hours=precision)

Done

>
> l.268 using \ is to avoid, even more in arithmetic operations I think, just use the continuation inside parenthesis if the line is too long
>
> minutes = (datetime.minute / 60.0 +
> datetime.second / 60.0 / 60.0)

Done

>
> l.1937-1983 using dicts would be appropriate here instead if many elif
>

Done

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

Thanks,

> On 04/02/2013 02:37 PM, Guewen Baconnier @ Camptocamp wrote:
> >
> > * Why is there a dependency on python 2.7?
>
> Because of timedelta.total_seconds()
> <http://docs.python.org/2/library/datetime.html#datetime.timedelta.total_secon
> ds>.
>

I don't know if discussions on python compatibility have been made for the community modules. My personal opinion is that we should stay with the same version than OpenERP itself, so 2.6 for OpenERP 7.0.

Furthermore, timedelta.total_seconds() can be replaced by:

    (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10**6

Beware to the division, you should enable true division with:

    from __future__ import division

>
> >
> > l.146 from openerp.tools.translate instead of from tools.
>
> Done
>
> >
> > l.162, what does means this 0.01666667 ?
> > - the unit worth be precised in the `working_time_precision` field
>
> How?

Sorry I wasn't accurate, I meant in the 'help' or string of the field.

A good practice is also to write the unit next to the assignments like that:

    _defaults = {
        'working_time_precision': 1.0 / 60 # seconds
        }

Thanks for your changes!
I put 'Needs Information' for your and community thoughts about the python compatibility.

review: Needs Information
56. By Lorenzo Battistini

[fix] total_seconds

57. By Lorenzo Battistini

[imp] comment

58. By Lorenzo Battistini

[imp] help

59. By Lorenzo Battistini

[imp] help

Revision history for this message
Lorenzo Battistini (elbati) wrote :

2013/4/29 Guewen Baconnier @ Camptocamp <email address hidden>

>
> I don't know if discussions on python compatibility have been made for the
> community modules. My personal opinion is that we should stay with the same
> version than OpenERP itself, so 2.6 for OpenERP 7.0.
>
>
I agree and removed timedelta.total_seconds

Sorry I wasn't accurate, I meant in the 'help' or string of the field.
>
> A good practice is also to write the unit next to the assignments like
> that:
>
> _defaults = {
> 'working_time_precision': 1.0 / 60 # seconds
> }
>
>
>
Done

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

Thanks for your changes!
Looks good to me!

review: Approve (code review, no test)
Revision history for this message
Alexandre Fayolle - camptocamp (alexandre-fayolle-c2c) wrote :

Nice module!

If the module does *not* mandate python2.7 in the end, then the description should be updated too. :-)

There are a couple of methods in there which are > 100 loc long, and which could do with some splitting, which will improve readability by removing the need for line wrapping stunts to stay within 80 cols. Candidates for refactoring:

* _get_attendance_duration
* print_calendar

review: Needs Fixing (code review, no test)
60. By Lorenzo Battistini

[fix] description

61. By Lorenzo Battistini

[ref] line length

Revision history for this message
Lorenzo Battistini (elbati) wrote :

On 05/27/2013 09:37 AM, Alexandre Fayolle - camptocamp wrote:
> If the module does *not* mandate python2.7 in the end, then the description should be updated too. :-)

Uh, right ;-)

> There are a couple of methods in there which are > 100 loc long, and which could do with some splitting, which will improve readability by removing the need for line wrapping stunts to stay within 80 cols.

Done some refactoring

Revision history for this message
Maxime Chambreuil (http://www.savoirfairelinux.com) (max3903) :
review: Approve

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-05-31 10:20:41 +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-05-31 10:20:41 +0000
11@@ -0,0 +1,25 @@
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 report
35+import wizard
36+import resource
37
38=== added file 'hr_attendance_analysis/__openerp__.py'
39--- hr_attendance_analysis/__openerp__.py 1970-01-01 00:00:00 +0000
40+++ hr_attendance_analysis/__openerp__.py 2013-05-31 10:20:41 +0000
41@@ -0,0 +1,50 @@
42+# -*- coding: utf-8 -*-
43+##############################################################################
44+#
45+# Copyright (C) 2011 Domsense srl (<http://www.domsense.com>)
46+# Copyright (C) 2011-2013 Agile Business Group sagl
47+# (<http://www.agilebg.com>)
48+#
49+# This program is free software: you can redistribute it and/or modify
50+# it under the terms of the GNU Affero General Public License as published
51+# by the Free Software Foundation, either version 3 of the License, or
52+# (at your option) any later version.
53+#
54+# This program is distributed in the hope that it will be useful,
55+# but WITHOUT ANY WARRANTY; without even the implied warranty of
56+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
57+# GNU Affero General Public License for more details.
58+#
59+# You should have received a copy of the GNU Affero General Public License
60+# along with this program. If not, see <http://www.gnu.org/licenses/>.
61+#
62+##############################################################################
63+{
64+ 'name': "HR - Attendance Analysis",
65+ 'version': '0.1',
66+ 'category': 'Generic Modules/Human Resources',
67+ 'description': """
68+Dynamic reports based on employee's attendances and contract's calendar.
69+Among other things, it lets you see the amount of working hours outside and inside the contract's working schedule (overtime).
70+It also provides a daily based report, showing the detailed and total hours compared to calendar hours.
71+Several analysis settings can be configured, like:
72+ - Tolerance for sign-in and sign-out
73+ - Attendances and overtimes roundings
74+ - Diffrent types of overtime, according to the overtime amount
75+""",
76+ 'author': 'Agile Business Group',
77+ 'website': 'http://www.agilebg.com',
78+ 'license': 'AGPL-3',
79+ "depends" : ['hr_attendance', 'hr_contract', 'hr_holidays', 'report_webkit'],
80+ "data" : [
81+ 'company_view.xml',
82+ 'hr_attendance_view.xml',
83+ 'reports.xml',
84+ 'wizard/print_calendar_report.xml',
85+ 'resource_view.xml',
86+ 'security/ir.model.access.csv',
87+ ],
88+ "demo" : [],
89+ "active": False,
90+ "installable": True
91+}
92
93=== added file 'hr_attendance_analysis/company_view.xml'
94--- hr_attendance_analysis/company_view.xml 1970-01-01 00:00:00 +0000
95+++ hr_attendance_analysis/company_view.xml 2013-05-31 10:20:41 +0000
96@@ -0,0 +1,17 @@
97+<?xml version="1.0" encoding="UTF-8"?>
98+<openerp>
99+ <data>
100+ <record id="view_company_form" model="ir.ui.view">
101+ <field name="inherit_id" ref="base.view_company_form"/>
102+ <field name="name">view.company.form</field>
103+ <field name="model">res.company</field>
104+ <field name="arch" type="xml">
105+ <page string="Configuration" position="inside">
106+ <group name="attendance_analysis_grp" string="Attendance analysis">
107+ <field name="working_time_precision" widget="float_time"/>
108+ </group>
109+ </page>
110+ </field>
111+ </record>
112+ </data>
113+</openerp>
114
115=== added file 'hr_attendance_analysis/hr_attendance.py'
116--- hr_attendance_analysis/hr_attendance.py 1970-01-01 00:00:00 +0000
117+++ hr_attendance_analysis/hr_attendance.py 2013-05-31 10:20:41 +0000
118@@ -0,0 +1,415 @@
119+# -*- coding: utf-8 -*-
120+##############################################################################
121+#
122+# Copyright (C) 2011 Domsense srl (<http://www.domsense.com>)
123+# Copyright (C) 2011-2013 Agile Business Group sagl
124+# (<http://www.agilebg.com>)
125+#
126+# This program is free software: you can redistribute it and/or modify
127+# it under the terms of the GNU Affero General Public License as published
128+# by the Free Software Foundation, either version 3 of the License, or
129+# (at your option) any later version.
130+#
131+# This program is distributed in the hope that it will be useful,
132+# but WITHOUT ANY WARRANTY; without even the implied warranty of
133+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
134+# GNU Affero General Public License for more details.
135+#
136+# You should have received a copy of the GNU Affero General Public License
137+# along with this program. If not, see <http://www.gnu.org/licenses/>.
138+#
139+##############################################################################
140+
141+from openerp.osv import fields, orm
142+from openerp.tools.translate import _
143+import time
144+from datetime import *
145+import math
146+from __future__ import division
147+
148+import pytz
149+
150+class res_company(orm.Model):
151+
152+ _inherit = 'res.company'
153+
154+ _columns = {
155+ 'working_time_precision': fields.float('Working time precision', help='The precision used to analyse working times over working schedule (hh:mm)', required=True)
156+ }
157+
158+ _defaults = {
159+ 'working_time_precision': 1.0 / 60 # hours
160+ }
161+
162+
163+class hr_attendance(orm.Model):
164+
165+ # ref: https://bugs.launchpad.net/openobject-client/+bug/887612
166+ # test: 0.9853 - 0.0085
167+ def float_time_convert(self, float_val):
168+ hours = math.floor(abs(float_val))
169+ mins = abs(float_val) - hours
170+ mins = round(mins * 60)
171+ if mins >= 60.0:
172+ hours = hours + 1
173+ mins = 0.0
174+ float_time = '%02d:%02d' % (hours,mins)
175+ return float_time
176+
177+ def float_to_datetime(self, float_val):
178+ str_float = self.float_time_convert(float_val)
179+ hours = int(str_float.split(':')[0])
180+ minutes = int(str_float.split(':')[1])
181+ days = 1
182+ if hours / 24 > 0:
183+ days += hours / 24
184+ hours = hours % 24
185+ return datetime(1900, 1, days, hours, minutes)
186+
187+ def float_to_timedelta(self, float_val):
188+ str_time = self.float_time_convert(float_val)
189+ return timedelta(0, int(str_time.split(':')[0]) * 60.0*60.0
190+ + int(str_time.split(':')[1]) * 60.0)
191+
192+ def total_seconds(self, td):
193+ return (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10**6
194+
195+ def time_difference(self, float_start_time, float_end_time):
196+ if float_end_time < float_start_time:
197+ raise osv.except_osv(_('Error'), _('End time %s < start time %s')
198+ % (str(float_end_time),str(float_start_time)))
199+ delta = self.float_to_datetime(float_end_time) - self.float_to_datetime(
200+ float_start_time)
201+ return self.total_seconds(delta) / 60.0 / 60.0
202+
203+ def time_sum(self, float_first_time, float_second_time):
204+ str_first_time = self.float_time_convert(float_first_time)
205+ first_timedelta = timedelta(0, int(str_first_time.split(':')[0]) * 60.0*60.0 +
206+ int(str_first_time.split(':')[1]) * 60.0)
207+ str_second_time = self.float_time_convert(float_second_time)
208+ second_timedelta = timedelta(0, int(str_second_time.split(':')[0]) * 60.0*60.0 +
209+ int(str_second_time.split(':')[1]) * 60.0)
210+ return self.total_seconds(first_timedelta + second_timedelta) / 60.0 / 60.0
211+
212+ def _split_long_attendances(self, start_datetime, duration):
213+ # start_datetime: datetime, duration: hours
214+ # returns [(datetime, hours)]
215+ res = []
216+ if duration > 24:
217+ res.append((start_datetime, 24))
218+ res.extend(self._split_long_attendances(
219+ start_datetime + timedelta(1), duration - 24))
220+ else:
221+ res.append((start_datetime, duration))
222+ return res
223+
224+ def _split_no_recursive_attendance(self, start_datetime, duration, precision=0.25):
225+ # start_datetime: datetime, duration: hours, precision: hours
226+ # returns [(datetime, hours)]
227+ res = []
228+ while (duration > precision):
229+ res.append((start_datetime, precision))
230+ start_datetime += timedelta(days=0,seconds=0,microseconds=0,milliseconds=0,
231+ minutes=0,precision)
232+ duration -= precision
233+ if duration > precision / 2.0:
234+ res.append((start_datetime, precision))
235+ return res
236+
237+ def _split_attendance(self, start_datetime, duration, precision=0.25):
238+ # start_datetime: datetime, duration: hours, precision: hours
239+ # returns [(datetime, hours)]
240+ res = []
241+ if duration > precision:
242+ res.append((start_datetime, precision))
243+ res.extend(self._split_attendance(start_datetime + timedelta(0,0,0,0,0,precision), duration - precision, precision))
244+ elif duration > precision / 2.0:
245+ res.append((start_datetime, precision))
246+ return res
247+
248+ def get_active_contracts(self, cr, uid, employee_id, date=datetime.now().strftime('%Y-%m-%d')):
249+ contract_pool = self.pool.get('hr.contract')
250+ active_contract_ids= contract_pool.search(cr, uid, [
251+ '&',
252+ ('employee_id', '=', employee_id),
253+ '|',
254+ '&',
255+ ('date_start', '<=', date),
256+ '|',
257+ ('date_end', '>=', date),
258+ ('date_end', '=', False),
259+ '&',
260+ '|',
261+ ('trial_date_start', '=', False),
262+ ('trial_date_start', '<=', date),
263+ '|',
264+ ('trial_date_end', '=', False),
265+ ('trial_date_end', '>=', date),
266+ ])
267+ if len(active_contract_ids) > 1:
268+ raise osv.except_osv(_('Error'), _(
269+ 'Too many active contracts for employee %s'
270+ ) % attendance.employee_id.name)
271+ return active_contract_ids
272+
273+ def _ceil_rounding(self, rounding, datetime):
274+ minutes = (datetime.minute / 60.0
275+ + datetime.second / 60.0 / 60.0)
276+ return math.ceil(minutes * rounding) / rounding
277+
278+ def _floor_rounding(self, rounding, datetime):
279+ minutes = (datetime.minute / 60.0
280+ + datetime.second / 60.0 / 60.0)
281+ return math.floor(minutes * rounding) / rounding
282+
283+ def _get_attendance_duration(self, cr, uid, ids, field_name, arg, context=None):
284+ res = {}
285+ contract_pool = self.pool.get('hr.contract')
286+ resource_pool = self.pool.get('resource.resource')
287+ attendance_pool = self.pool.get('resource.calendar.attendance')
288+ precision = self.pool.get('res.users').browse(cr, uid, uid).company_id.working_time_precision
289+ # 2012.10.16 LF FIX : Get timezone from context
290+ active_tz = pytz.timezone(context.get("tz","UTC") if context else "UTC")
291+ str_now = datetime.strftime(datetime.now(), '%Y-%m-%d %H:%M:%S')
292+ for attendance_id in ids:
293+ duration = 0.0
294+ outside_calendar_duration = 0.0
295+ inside_calendar_duration = 0.0
296+ attendance = self.browse(cr, uid, attendance_id)
297+ res[attendance.id] = {}
298+ # 2012.10.16 LF FIX : Attendance in context timezone
299+ attendance_start = datetime.strptime(
300+ attendance.name, '%Y-%m-%d %H:%M:%S'
301+ ).replace(tzinfo=pytz.utc).astimezone(active_tz)
302+ next_attendance_date = str_now
303+ # should we compute for sign out too?
304+ if attendance.action == 'sign_in':
305+ next_attendance_ids = self.search(cr, uid, [
306+ ('employee_id', '=', attendance.employee_id.id),
307+ ('name', '>', attendance.name)], order='name')
308+ if next_attendance_ids:
309+ next_attendance = self.browse(cr, uid, next_attendance_ids[0])
310+ if next_attendance.action == 'sign_in':
311+ # 2012.10.16 LF FIX : Attendance in context timezone
312+ raise osv.except_osv(_('Error'), _(
313+ 'Incongruent data: sign-in %s is followed by another sign-in'
314+ ) % attendance_start)
315+ next_attendance_date = next_attendance.name
316+ # 2012.10.16 LF FIX : Attendance in context timezone
317+ attendance_stop = datetime.strptime(
318+ next_attendance_date, '%Y-%m-%d %H:%M:%S'
319+ ).replace(tzinfo=pytz.utc).astimezone(active_tz)
320+ duration_delta = attendance_stop - attendance_start
321+ duration = self.total_seconds(duration_delta) / 60.0 / 60.0
322+ duration = round(duration / precision) * precision
323+ res[attendance.id]['duration'] = duration
324+ res[attendance.id]['end_datetime'] = next_attendance_date
325+ # If contract is not specified: working days = 24/7
326+ res[attendance.id]['inside_calendar_duration'] = duration
327+ res[attendance.id]['outside_calendar_duration'] = 0.0
328+
329+ active_contract_ids = self.get_active_contracts(
330+ cr, uid, attendance.employee_id.id, date=str_now[:10])
331+
332+ if active_contract_ids:
333+ contract = contract_pool.browse(cr, uid, active_contract_ids[0])
334+ if contract.working_hours:
335+ # TODO applicare prima arrotondamento o tolleranza?
336+ if contract.working_hours.attendance_rounding:
337+ float_attendance_rounding = float(contract.working_hours.attendance_rounding)
338+ rounded_start_hour = self._ceil_rounding(
339+ float_attendance_rounding, attendance_start)
340+ rounded_stop_hour = self._floor_rounding(
341+ float_attendance_rounding, attendance_stop)
342+
343+ if abs(1- rounded_start_hour) < 0.01: # if shift == 1 hour
344+ attendance_start = datetime(attendance_start.year, attendance_start.month,
345+ attendance_start.day, attendance_start.hour + 1)
346+ else:
347+ attendance_start = datetime(attendance_start.year, attendance_start.month,
348+ attendance_start.day, attendance_start.hour, int(round(rounded_start_hour * 60.0)))
349+
350+ attendance_stop = datetime(attendance_stop.year, attendance_stop.month,
351+ attendance_stop.day, attendance_stop.hour,
352+ int(round(rounded_stop_hour * 60.0)))
353+
354+ # again
355+ duration_delta = attendance_stop - attendance_start
356+ duration = self.total_seconds(duration_delta) / 60.0 / 60.0
357+ duration = round(duration / precision) * precision
358+ res[attendance.id]['duration'] = duration
359+
360+ res[attendance.id]['inside_calendar_duration'] = 0.0
361+ res[attendance.id]['outside_calendar_duration'] = 0.0
362+ calendar_id = contract.working_hours.id
363+ intervals_within = 0
364+
365+ # split attendance in intervals = precision
366+ # 2012.10.16 LF FIX : no recursion in split attendance
367+ splitted_attendances = self._split_no_recursive_attendance(
368+ attendance_start, duration, precision)
369+ counter = 0
370+ for atomic_attendance in splitted_attendances:
371+ counter += 1
372+ centered_attendance = atomic_attendance[0] + timedelta(
373+ 0,0,0,0,0, atomic_attendance[1] / 2.0)
374+ centered_attendance_hour = (
375+ centered_attendance.hour + centered_attendance.minute / 60.0
376+ + centered_attendance.second / 60.0 / 60.0
377+ )
378+ # check if centered_attendance is within a working schedule
379+ # 2012.10.16 LF FIX : weekday must be single character not int
380+ weekday_char = str(unichr(centered_attendance.weekday() + 48))
381+ matched_schedule_ids = attendance_pool.search(cr, uid, [
382+ '&',
383+ '|',
384+ ('date_from', '=', False),
385+ ('date_from','<=',centered_attendance.date()),
386+ '|',
387+ ('dayofweek', '=', False),
388+ ('dayofweek','=',weekday_char),
389+ ('calendar_id','=',calendar_id),
390+ ('hour_to','>=',centered_attendance_hour),
391+ ('hour_from','<=',centered_attendance_hour),
392+ ])
393+ if len(matched_schedule_ids) > 1:
394+ raise osv.except_osv(_('Error'),
395+ _('Wrongly configured working schedule with id %s') % str(calendar_id))
396+ if matched_schedule_ids:
397+ intervals_within += 1
398+ # sign in tolerance
399+ if intervals_within == 1:
400+ calendar_attendance = attendance_pool.browse(cr, uid, matched_schedule_ids[0])
401+ attendance_start_hour = (
402+ attendance_start.hour + attendance_start.minute / 60.0
403+ + attendance_start.second / 60.0 / 60.0
404+ )
405+ if attendance_start_hour >= (
406+ calendar_attendance.hour_from and
407+ (attendance_start_hour - (calendar_attendance.hour_from +
408+ calendar_attendance.tolerance_to)) < 0.01
409+ ): # handling float roundings (<=)
410+ additional_intervals = round(
411+ (attendance_start_hour - calendar_attendance.hour_from) / precision)
412+ intervals_within += additional_intervals
413+ res[attendance.id]['duration'] = self.time_sum(
414+ res[attendance.id]['duration'], additional_intervals * precision)
415+ # sign out tolerance
416+ if len(splitted_attendances) == counter:
417+ attendance_stop_hour = (
418+ attendance_stop.hour + attendance_stop.minute / 60.0
419+ + attendance_stop.second / 60.0 / 60.0
420+ )
421+ calendar_attendance = attendance_pool.browse(cr, uid, matched_schedule_ids[0])
422+ if attendance_stop_hour <= (
423+ calendar_attendance.hour_to and
424+ (attendance_stop_hour - (calendar_attendance.hour_to -
425+ calendar_attendance.tolerance_from)) > -0.01
426+ ): # handling float roundings (>=)
427+ additional_intervals = round(
428+ (calendar_attendance.hour_to - attendance_stop_hour) / precision)
429+ intervals_within += additional_intervals
430+ res[attendance.id]['duration'] = self.time_sum(
431+ res[attendance.id]['duration'], additional_intervals * precision)
432+
433+ res[attendance.id]['inside_calendar_duration'] = intervals_within * precision
434+ # make difference using time in order to avoid rounding errors
435+ # inside_calendar_duration can't be > duration
436+ res[attendance.id]['outside_calendar_duration'] = self.time_difference(
437+ res[attendance.id]['inside_calendar_duration'],
438+ res[attendance.id]['duration'])
439+
440+ if contract.working_hours.overtime_rounding:
441+ if res[attendance.id]['outside_calendar_duration']:
442+ overtime = res[attendance.id]['outside_calendar_duration']
443+ if contract.working_hours.overtime_rounding_tolerance:
444+ overtime = self.time_sum(overtime,
445+ contract.working_hours.overtime_rounding_tolerance)
446+ float_overtime_rounding = float(contract.working_hours.overtime_rounding)
447+ res[attendance.id]['outside_calendar_duration'] = math.floor(
448+ overtime * float_overtime_rounding) / float_overtime_rounding
449+
450+ return res
451+
452+ def _get_by_contracts(self, cr, uid, ids, context=None):
453+ attendance_ids = []
454+ attendance_pool = self.pool.get('hr.attendance')
455+ for contract in self.pool.get('hr.contract').browse(cr, uid, ids, context=context):
456+ att_ids = attendance_pool.search(cr, uid, [('employee_id', '=', contract.employee_id.id)])
457+ for att_id in att_ids:
458+ if att_id not in attendance_ids:
459+ attendance_ids.append(att_id)
460+ return attendance_ids
461+
462+ def _get_by_calendars(self, cr, uid, ids, context=None):
463+ attendance_ids = []
464+ attendance_pool = self.pool.get('hr.attendance')
465+ contract_pool = self.pool.get('hr.contract')
466+ for calendar in self.pool.get('resource.calendar').browse(cr, uid, ids, context=context):
467+ contract_ids = contract_pool.search(cr, uid, [('working_hours', '=', calendar.id)])
468+ att_ids = attendance_pool._get_by_contracts(cr, uid, contract_ids, context=None)
469+ for att_id in att_ids:
470+ if att_id not in attendance_ids:
471+ attendance_ids.append(att_id)
472+ return attendance_ids
473+
474+ def _get_by_calendar_attendances(self, cr, uid, ids, context=None):
475+ attendance_ids = []
476+ attendance_pool = self.pool.get('hr.attendance')
477+ for calendar_attendance in self.pool.get('resource.calendar.attendance').browse(cr, uid, ids, context=context):
478+ att_ids = attendance_pool._get_by_calendars(cr, uid, [calendar_attendance.calendar_id.id], context=None)
479+ for att_id in att_ids:
480+ if att_id not in attendance_ids:
481+ attendance_ids.append(att_id)
482+ return attendance_ids
483+
484+ def _get_attendances(self, cr, uid, ids, context=None):
485+ attendance_ids = []
486+ for attendance in self.browse(cr, uid, ids, context=context):
487+ if attendance.action == 'sign_in' and attendance.id not in attendance_ids:
488+ attendance_ids.append(attendance.id)
489+ elif attendance.action == 'sign_out':
490+ previous_attendance_ids = self.search(cr, uid, [
491+ ('employee_id', '=', attendance.employee_id.id),
492+ ('name', '<', attendance.name)], order='name')
493+ if previous_attendance_ids and previous_attendance_ids[len(previous_attendance_ids) - 1] not in attendance_ids:
494+ attendance_ids.append(previous_attendance_ids[len(previous_attendance_ids) - 1])
495+ return attendance_ids
496+
497+ _inherit = "hr.attendance"
498+
499+ _columns = {
500+ 'duration': fields.function(_get_attendance_duration, method=True, multi='duration', string="Attendance duration",
501+ store={
502+ 'hr.attendance': (_get_attendances, ['name', 'action', 'employee_id'], 20),
503+ 'hr.contract': (_get_by_contracts, ['employee_id', 'date_start', 'date_end', 'trial_date_start', 'trial_date_end', 'working_hours'], 20),
504+ 'resource.calendar': (_get_by_calendars, ['attendance_ids'], 20),
505+ 'resource.calendar.attendance': (_get_by_calendar_attendances, ['dayofweek', 'date_from', 'hour_from', 'hour_to', 'calendar_id'], 20),
506+ }
507+ ),
508+ 'end_datetime': fields.function(_get_attendance_duration, method=True, multi='duration', type="datetime", string="End date time",
509+ store={
510+ 'hr.attendance': (_get_attendances, ['name', 'action', 'employee_id'], 20),
511+ 'hr.contract': (_get_by_contracts, ['employee_id', 'date_start', 'date_end', 'trial_date_start', 'trial_date_end', 'working_hours'], 20),
512+ 'resource.calendar': (_get_by_calendars, ['attendance_ids'], 20),
513+ 'resource.calendar.attendance': (_get_by_calendar_attendances, ['dayofweek', 'date_from', 'hour_from', 'hour_to', 'calendar_id'], 20),
514+ }),
515+ 'outside_calendar_duration': fields.function(_get_attendance_duration, method=True, multi='duration',
516+ string="Overtime",
517+ store={
518+ 'hr.attendance': (_get_attendances, ['name', 'action', 'employee_id'], 20),
519+ 'hr.contract': (_get_by_contracts, ['employee_id', 'date_start', 'date_end', 'trial_date_start', 'trial_date_end', 'working_hours'], 20),
520+ 'resource.calendar': (_get_by_calendars, ['attendance_ids'], 20),
521+ 'resource.calendar.attendance': (_get_by_calendar_attendances, ['dayofweek', 'date_from', 'hour_from', 'hour_to', 'calendar_id'], 20),
522+ }),
523+ 'inside_calendar_duration': fields.function(_get_attendance_duration, method=True, multi='duration',
524+ string="Duration within working schedule",
525+ store={
526+ 'hr.attendance': (_get_attendances, ['name', 'action', 'employee_id'], 20),
527+ 'hr.contract': (_get_by_contracts, ['employee_id', 'date_start', 'date_end', 'trial_date_start', 'trial_date_end', 'working_hours'], 20),
528+ 'resource.calendar': (_get_by_calendars, ['attendance_ids'], 20),
529+ 'resource.calendar.attendance': (_get_by_calendar_attendances, ['dayofweek', 'date_from', 'hour_from', 'hour_to', 'calendar_id'], 20),
530+ }),
531+ }
532+
533+
534
535=== added file 'hr_attendance_analysis/hr_attendance_view.xml'
536--- hr_attendance_analysis/hr_attendance_view.xml 1970-01-01 00:00:00 +0000
537+++ hr_attendance_analysis/hr_attendance_view.xml 2013-05-31 10:20:41 +0000
538@@ -0,0 +1,80 @@
539+<?xml version="1.0" encoding="utf-8"?>
540+<openerp>
541+ <data>
542+
543+ <record id="view_attendance_form" model="ir.ui.view">
544+ <field name="name">hr.attendance.form</field>
545+ <field name="model">hr.attendance</field>
546+ <field name="inherit_id" ref="hr_attendance.view_attendance_form"></field>
547+ <field name="arch" type="xml">
548+ <field name="action_desc" position="after">
549+ <field name="duration" widget="float_time"/>
550+ <field name="outside_calendar_duration" widget="float_time"/>
551+ <field name="inside_calendar_duration" widget="float_time" />
552+ </field>
553+ </field>
554+ </record>
555+
556+ <record id="view_attendance_analysis" model="ir.ui.view">
557+ <field name="name">hr.attendance.analysis</field>
558+ <field name="model">hr.attendance</field>
559+ <field name="priority" eval="17"/>
560+ <field name="arch" type="xml">
561+ <tree string="Employee attendances analysis">
562+ <field name="employee_id" />
563+ <field name="name" string="Start date time"/>
564+ <field name="end_datetime"/>
565+ <field name="duration" sum="Total hours" widget="float_time"/>
566+ <field name="outside_calendar_duration" sum="Overtime" widget="float_time"/>
567+ <field name="inside_calendar_duration" sum="Within working schedule" widget="float_time" />
568+ <field name="day" invisible="1"/>
569+ </tree>
570+ </field>
571+ </record>
572+
573+ <record model="ir.ui.view" id="view_hr_attendance_filter">
574+ <field name="name">view_hr_attendance_filter</field>
575+ <field name="model">hr.attendance</field>
576+ <field name="arch" type="xml">
577+ <search string="Hr Attendance Search">
578+ <filter icon="terp-go-today" string="Today" name="today" domain="[('name::date','=',current_date)]" />
579+ <separator orientation="vertical"/>
580+ <field name="employee_id"/>
581+ <field name="name" string="Start date time"/>
582+ <field name="end_datetime"/>
583+ <newline/>
584+ <group expand="0" string="Group By...">
585+ <filter name="employee" string="Employee" icon="terp-personal" domain="[]" context="{'group_by':'employee_id'}"/>
586+ <separator orientation="vertical"/>
587+ <filter string="Day" icon="terp-go-today" domain="[]" context="{'group_by':'day'}"/>
588+ </group>
589+ </search>
590+ </field>
591+ </record>
592+
593+ <record model="ir.ui.view" id="view_hr_attendance_calendar">
594+ <field name="name">view_hr_attendance.calendar</field>
595+ <field name="model">hr.attendance</field>
596+ <field name="arch" type="xml">
597+ <calendar string="Calendar View" date_start="name" date_stop="end_datetime" color="employee_id">
598+ <field name="duration" />
599+ <field name="outside_calendar_duration" />
600+ <field name="inside_calendar_duration" />
601+ </calendar>
602+ </field>
603+ </record>
604+
605+ <record id="open_view_attendance" model="ir.actions.act_window">
606+ <field name="name">Attendances analysis</field>
607+ <field name="res_model">hr.attendance</field>
608+ <field name="view_type">form</field>
609+ <field name="view_mode">tree,form,calendar</field>
610+ <field name="domain">[('action', '=', 'sign_in')]</field>
611+ <field name="view_id" ref="view_attendance_analysis"/>
612+ <field name="search_view_id" ref="view_hr_attendance_filter" />
613+ </record>
614+ <menuitem action="open_view_attendance" id="menu_open_view_attendance" parent="hr_attendance.menu_hr_attendance" groups="base.group_hr_manager"/>
615+ <menuitem action="resource.action_resource_calendar_form" id="menu_view_resource_calendar" parent="hr_contract.next_id_56" sequence="1"/>
616+
617+ </data>
618+</openerp>
619
620=== added directory 'hr_attendance_analysis/i18n'
621=== added file 'hr_attendance_analysis/i18n/hr_attendance_analysis.pot'
622--- hr_attendance_analysis/i18n/hr_attendance_analysis.pot 1970-01-01 00:00:00 +0000
623+++ hr_attendance_analysis/i18n/hr_attendance_analysis.pot 2013-05-31 10:20:41 +0000
624@@ -0,0 +1,564 @@
625+# Translation of OpenERP Server.
626+# This file contains the translation of the following modules:
627+# * hr_attendance_analysis
628+#
629+msgid ""
630+msgstr ""
631+"Project-Id-Version: OpenERP Server 6.0.3\n"
632+"Report-Msgid-Bugs-To: support@openerp.com\n"
633+"POT-Creation-Date: 2011-12-23 10:03+0000\n"
634+"PO-Revision-Date: 2011-12-23 10:03+0000\n"
635+"Last-Translator: <>\n"
636+"Language-Team: \n"
637+"MIME-Version: 1.0\n"
638+"Content-Type: text/plain; charset=UTF-8\n"
639+"Content-Transfer-Encoding: \n"
640+"Plural-Forms: \n"
641+
642+#. module: hr_attendance_analysis
643+#: code:addons/hr_attendance_analysis/hr_attendance.py:123
644+#, python-format
645+msgid "Incongruent data"
646+msgstr ""
647+
648+#. module: hr_attendance_analysis
649+#: code:addons/hr_attendance_analysis/hr_attendance.py:87
650+#: code:addons/hr_attendance_analysis/hr_attendance.py:123
651+#: code:addons/hr_attendance_analysis/hr_attendance.py:189
652+#: code:addons/hr_attendance_analysis/wizard/print_calendar_report.py:58
653+#: code:addons/hr_attendance_analysis/wizard/print_calendar_report.py:129
654+#, python-format
655+msgid "Error"
656+msgstr ""
657+
658+#. module: hr_attendance_analysis
659+#: help:res.company,working_time_precision:0
660+msgid "The precision used to analyse working times over working schedule"
661+msgstr ""
662+
663+#. module: hr_attendance_analysis
664+#: view:hr.attendance:0
665+msgid "Group By..."
666+msgstr ""
667+
668+#. module: hr_attendance_analysis
669+#: code:addons/hr_attendance_analysis/report/calendar_report.py:47
670+#, python-format
671+msgid "Sunday"
672+msgstr ""
673+
674+#. module: hr_attendance_analysis
675+#: field:hr.attendance,end_datetime:0
676+msgid "End date time"
677+msgstr ""
678+
679+#. module: hr_attendance_analysis
680+#: view:hr.attendance:0
681+msgid "Today"
682+msgstr ""
683+
684+#. module: hr_attendance_analysis
685+#: view:hr.attendance:0
686+msgid "Within working schedule"
687+msgstr ""
688+
689+#. module: hr_attendance_analysis
690+#: selection:resource.calendar,attendance_rounding:0
691+#: selection:resource.calendar,leave_rounding:0
692+#: selection:resource.calendar,overtime_rounding:0
693+msgid "20"
694+msgstr ""
695+
696+#. module: hr_attendance_analysis
697+#: code:addons/hr_attendance_analysis/report/calendar_report.py:43
698+#, python-format
699+msgid "Friday"
700+msgstr ""
701+
702+#. module: hr_attendance_analysis
703+#: model:ir.model,name:hr_attendance_analysis.model_attendance_analysis_wizard_calendar_report
704+msgid "attendance_analysis.wizard.calendar_report"
705+msgstr ""
706+
707+#. module: hr_attendance_analysis
708+#: selection:resource.calendar,attendance_rounding:0
709+#: selection:resource.calendar,leave_rounding:0
710+#: selection:resource.calendar,overtime_rounding:0
711+msgid "8"
712+msgstr ""
713+
714+#. module: hr_attendance_analysis
715+#: view:hr.attendance:0
716+msgid "Day"
717+msgstr ""
718+
719+#. module: hr_attendance_analysis
720+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:36
721+msgid "Leave"
722+msgstr ""
723+
724+#. module: hr_attendance_analysis
725+#: field:resource.calendar.overtime.type,limit:0
726+msgid "Limit"
727+msgstr ""
728+
729+#. module: hr_attendance_analysis
730+#: selection:resource.calendar,attendance_rounding:0
731+#: selection:resource.calendar,leave_rounding:0
732+#: selection:resource.calendar,overtime_rounding:0
733+msgid "15"
734+msgstr ""
735+
736+#. module: hr_attendance_analysis
737+#: help:resource.calendar,attendance_rounding:0
738+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"
739+msgstr ""
740+
741+#. module: hr_attendance_analysis
742+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:80
743+msgid "Totals"
744+msgstr ""
745+
746+#. module: hr_attendance_analysis
747+#: help:resource.calendar.attendance,tolerance_to:0
748+msgid "Sign in done in the interval \"Work from + Tolerance to\" will be considered done at \"Work from\""
749+msgstr ""
750+
751+#. module: hr_attendance_analysis
752+#: field:resource.calendar.attendance,tolerance_from:0
753+msgid "Tolerance from"
754+msgstr ""
755+
756+#. module: hr_attendance_analysis
757+#: field:attendance_analysis.wizard.calendar_report,from_date:0
758+msgid "From date"
759+msgstr ""
760+
761+#. module: hr_attendance_analysis
762+#: code:addons/hr_attendance_analysis/hr_attendance.py:87
763+#, python-format
764+msgid "Too many active contracts for employee %s"
765+msgstr ""
766+
767+#. module: hr_attendance_analysis
768+#: view:hr.attendance:0
769+msgid "Calendar View"
770+msgstr ""
771+
772+#. module: hr_attendance_analysis
773+#: view:resource.calendar:0
774+msgid "Roundings"
775+msgstr ""
776+
777+#. module: hr_attendance_analysis
778+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:25
779+msgid "Third Sign In"
780+msgstr ""
781+
782+#. module: hr_attendance_analysis
783+#: model:ir.model,name:hr_attendance_analysis.model_hr_attendance
784+msgid "Attendance"
785+msgstr ""
786+
787+#. module: hr_attendance_analysis
788+#: constraint:res.company:0
789+msgid "Error! You can not create recursive companies."
790+msgstr ""
791+
792+#. module: hr_attendance_analysis
793+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:35
794+msgid "Negative"
795+msgstr ""
796+
797+#. module: hr_attendance_analysis
798+#: view:hr.attendance:0
799+msgid "Employee"
800+msgstr ""
801+
802+#. module: hr_attendance_analysis
803+#: view:resource.calendar:0
804+msgid "Type"
805+msgstr ""
806+
807+#. module: hr_attendance_analysis
808+#: view:hr.attendance:0
809+msgid "Hr Attendance Search"
810+msgstr ""
811+
812+#. module: hr_attendance_analysis
813+#: view:hr.attendance:0
814+msgid "Start date time"
815+msgstr ""
816+
817+#. module: hr_attendance_analysis
818+#: help:resource.calendar,overtime_rounding:0
819+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"
820+msgstr ""
821+
822+#. module: hr_attendance_analysis
823+#: field:resource.calendar,attendance_rounding:0
824+msgid "Attendance rounding"
825+msgstr ""
826+
827+#. module: hr_attendance_analysis
828+#: selection:resource.calendar,attendance_rounding:0
829+#: selection:resource.calendar,leave_rounding:0
830+#: selection:resource.calendar,overtime_rounding:0
831+msgid "3"
832+msgstr ""
833+
834+#. module: hr_attendance_analysis
835+#: constraint:hr.attendance:0
836+msgid "Error: Sign in (resp. Sign out) must follow Sign out (resp. Sign in)"
837+msgstr ""
838+
839+#. module: hr_attendance_analysis
840+#: view:res.company:0
841+msgid "Configuration"
842+msgstr ""
843+
844+#. module: hr_attendance_analysis
845+#: code:addons/hr_attendance_analysis/wizard/print_calendar_report.py:58
846+#, python-format
847+msgid "From date must be < to date"
848+msgstr ""
849+
850+#. module: hr_attendance_analysis
851+#: view:hr.attendance:0
852+msgid "Total hours"
853+msgstr ""
854+
855+#. module: hr_attendance_analysis
856+#: field:res.company,working_time_precision:0
857+msgid "Working time precision"
858+msgstr ""
859+
860+#. module: hr_attendance_analysis
861+#: view:hr.attendance:0
862+msgid "Employee attendances analysis"
863+msgstr ""
864+
865+#. module: hr_attendance_analysis
866+#: field:resource.calendar.attendance,tolerance_to:0
867+msgid "Tolerance to"
868+msgstr ""
869+
870+#. module: hr_attendance_analysis
871+#: help:resource.calendar,leave_rounding:0
872+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"
873+msgstr ""
874+
875+#. module: hr_attendance_analysis
876+#: model:ir.actions.report.xml,name:hr_attendance_analysis.attendance_analysis_report_id
877+msgid "Attendances Analysis"
878+msgstr ""
879+
880+#. module: hr_attendance_analysis
881+#: selection:resource.calendar,attendance_rounding:0
882+#: selection:resource.calendar,leave_rounding:0
883+#: selection:resource.calendar,overtime_rounding:0
884+msgid "30"
885+msgstr ""
886+
887+#. module: hr_attendance_analysis
888+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:110
889+#: model:ir.model,name:hr_attendance_analysis.model_resource_calendar_overtime_type
890+msgid "Overtime type"
891+msgstr ""
892+
893+#. module: hr_attendance_analysis
894+#: field:hr.attendance,inside_calendar_duration:0
895+msgid "Duration within working schedule"
896+msgstr ""
897+
898+#. module: hr_attendance_analysis
899+#: field:resource.calendar,leave_rounding:0
900+msgid "Leave rounding"
901+msgstr ""
902+
903+#. module: hr_attendance_analysis
904+#: field:resource.calendar.overtime.type,calendar_id:0
905+msgid "Calendar"
906+msgstr ""
907+
908+#. module: hr_attendance_analysis
909+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:32
910+msgid "Due"
911+msgstr ""
912+
913+#. module: hr_attendance_analysis
914+#: view:attendance_analysis.wizard.calendar_report:0
915+#: model:ir.actions.act_window,name:hr_attendance_analysis.action_wizard_calendar_report
916+#: model:ir.ui.menu,name:hr_attendance_analysis.menu_action_wizard_calendar_report
917+msgid "Attendances Analysis Calendar"
918+msgstr ""
919+
920+#. module: hr_attendance_analysis
921+#: selection:resource.calendar,attendance_rounding:0
922+#: selection:resource.calendar,leave_rounding:0
923+#: selection:resource.calendar,overtime_rounding:0
924+msgid "60"
925+msgstr ""
926+
927+#. module: hr_attendance_analysis
928+#: view:resource.calendar:0
929+#: field:resource.calendar,overtime_type_ids:0
930+msgid "Overtime types"
931+msgstr ""
932+
933+#. module: hr_attendance_analysis
934+#: code:addons/hr_attendance_analysis/report/calendar_report.py:35
935+#, python-format
936+msgid "Monday"
937+msgstr ""
938+
939+#. module: hr_attendance_analysis
940+#: field:attendance_analysis.wizard.calendar_report,employee_ids:0
941+msgid "unknown"
942+msgstr ""
943+
944+#. module: hr_attendance_analysis
945+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:18
946+msgid "First Sign Out"
947+msgstr ""
948+
949+#. module: hr_attendance_analysis
950+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:15
951+msgid "Day of week"
952+msgstr ""
953+
954+#. module: hr_attendance_analysis
955+#: field:resource.calendar,overtime_rounding_tolerance:0
956+msgid "Overtime rounding tolerance"
957+msgstr ""
958+
959+#. module: hr_attendance_analysis
960+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:29
961+msgid "Fourth Sign In"
962+msgstr ""
963+
964+#. module: hr_attendance_analysis
965+#: code:addons/hr_attendance_analysis/wizard/print_calendar_report.py:130
966+#, python-format
967+msgid "%s: 'Work to' is < 'Work from'"
968+msgstr ""
969+
970+#. module: hr_attendance_analysis
971+#: selection:resource.calendar,attendance_rounding:0
972+#: selection:resource.calendar,leave_rounding:0
973+#: selection:resource.calendar,overtime_rounding:0
974+msgid "2"
975+msgstr ""
976+
977+#. module: hr_attendance_analysis
978+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:10
979+msgid "Employee: "
980+msgstr ""
981+
982+#. module: hr_attendance_analysis
983+#: selection:resource.calendar,attendance_rounding:0
984+#: selection:resource.calendar,leave_rounding:0
985+#: selection:resource.calendar,overtime_rounding:0
986+msgid "6"
987+msgstr ""
988+
989+#. module: hr_attendance_analysis
990+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:14
991+msgid "Date"
992+msgstr ""
993+
994+#. module: hr_attendance_analysis
995+#: model:ir.module.module,shortdesc:hr_attendance_analysis.module_meta_information
996+msgid "HR - Attendance Analysis"
997+msgstr ""
998+
999+#. module: hr_attendance_analysis
1000+#: code:addons/hr_attendance_analysis/hr_attendance.py:190
1001+#, python-format
1002+msgid "Wrongly configured working schedule with id %s"
1003+msgstr ""
1004+
1005+#. module: hr_attendance_analysis
1006+#: model:ir.model,name:hr_attendance_analysis.model_res_company
1007+msgid "Companies"
1008+msgstr ""
1009+
1010+#. module: hr_attendance_analysis
1011+#: code:addons/hr_attendance_analysis/report/calendar_report.py:39
1012+#, python-format
1013+msgid "Wednesday"
1014+msgstr ""
1015+
1016+#. module: hr_attendance_analysis
1017+#: field:resource.calendar.overtime.type,name:0
1018+msgid "Type Description"
1019+msgstr ""
1020+
1021+#. module: hr_attendance_analysis
1022+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:17
1023+msgid "First Sign In"
1024+msgstr ""
1025+
1026+#. module: hr_attendance_analysis
1027+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:30
1028+msgid "Fourth Sign Out"
1029+msgstr ""
1030+
1031+#. module: hr_attendance_analysis
1032+#: model:ir.module.module,description:hr_attendance_analysis.module_meta_information
1033+msgid "\n"
1034+"Dynamic reports based on employee's attendances and contract's calendar.\n"
1035+"Among other things, it lets you see the amount of working hours outside and inside the contract's working schedule (overtime).\n"
1036+"It also provides a daily based report, showing the detailed and total hours compared to calendar hours.\n"
1037+""
1038+msgstr ""
1039+
1040+#. module: hr_attendance_analysis
1041+#: selection:resource.calendar,attendance_rounding:0
1042+#: selection:resource.calendar,leave_rounding:0
1043+#: selection:resource.calendar,overtime_rounding:0
1044+msgid "10"
1045+msgstr ""
1046+
1047+#. module: hr_attendance_analysis
1048+#: selection:resource.calendar,attendance_rounding:0
1049+#: selection:resource.calendar,leave_rounding:0
1050+#: selection:resource.calendar,overtime_rounding:0
1051+msgid "12"
1052+msgstr ""
1053+
1054+#. module: hr_attendance_analysis
1055+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:22
1056+msgid "Second Sign Out"
1057+msgstr ""
1058+
1059+#. module: hr_attendance_analysis
1060+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:34
1061+#: view:hr.attendance:0
1062+#: field:hr.attendance,outside_calendar_duration:0
1063+msgid "Overtime"
1064+msgstr ""
1065+
1066+#. module: hr_attendance_analysis
1067+#: model:ir.model,name:hr_attendance_analysis.model_resource_calendar_attendance
1068+msgid "Work Detail"
1069+msgstr ""
1070+
1071+#. module: hr_attendance_analysis
1072+#: help:resource.calendar.attendance,tolerance_from:0
1073+msgid "Sign out done in the interval \"Work to - Tolerance from\" will be considered done at \"Work to\""
1074+msgstr ""
1075+
1076+#. module: hr_attendance_analysis
1077+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:21
1078+msgid "Second Sign In"
1079+msgstr ""
1080+
1081+#. module: hr_attendance_analysis
1082+#: view:attendance_analysis.wizard.calendar_report:0
1083+msgid "Cancel"
1084+msgstr ""
1085+
1086+#. module: hr_attendance_analysis
1087+#: code:addons/hr_attendance_analysis/report/calendar_report.py:37
1088+#, python-format
1089+msgid "Tuesday"
1090+msgstr ""
1091+
1092+#. module: hr_attendance_analysis
1093+#: model:ir.actions.act_window,name:hr_attendance_analysis.open_view_attendance
1094+#: model:ir.ui.menu,name:hr_attendance_analysis.menu_open_view_attendance
1095+msgid "Attendances analysis"
1096+msgstr ""
1097+
1098+#. module: hr_attendance_analysis
1099+#: code:addons/hr_attendance_analysis/report/calendar_report.py:41
1100+#, python-format
1101+msgid "Thursday"
1102+msgstr ""
1103+
1104+#. module: hr_attendance_analysis
1105+#: view:attendance_analysis.wizard.calendar_report:0
1106+msgid "Print"
1107+msgstr ""
1108+
1109+#. module: hr_attendance_analysis
1110+#: model:ir.model,name:hr_attendance_analysis.model_resource_calendar
1111+msgid "Resource Calendar"
1112+msgstr ""
1113+
1114+#. module: hr_attendance_analysis
1115+#: field:hr.attendance,duration:0
1116+msgid "Attendance duration"
1117+msgstr ""
1118+
1119+#. module: hr_attendance_analysis
1120+#: selection:resource.calendar,attendance_rounding:0
1121+#: selection:resource.calendar,leave_rounding:0
1122+#: selection:resource.calendar,overtime_rounding:0
1123+msgid "1"
1124+msgstr ""
1125+
1126+#. module: hr_attendance_analysis
1127+#: field:attendance_analysis.wizard.calendar_report,to_date:0
1128+msgid "To date"
1129+msgstr ""
1130+
1131+#. module: hr_attendance_analysis
1132+#: selection:resource.calendar,attendance_rounding:0
1133+#: selection:resource.calendar,leave_rounding:0
1134+#: selection:resource.calendar,overtime_rounding:0
1135+msgid "5"
1136+msgstr ""
1137+
1138+#. module: hr_attendance_analysis
1139+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:33
1140+msgid "Working Hours"
1141+msgstr ""
1142+
1143+#. module: hr_attendance_analysis
1144+#: view:resource.calendar:0
1145+msgid "Types"
1146+msgstr ""
1147+
1148+#. module: hr_attendance_analysis
1149+#: field:resource.calendar,overtime_rounding:0
1150+msgid "Overtime rounding"
1151+msgstr ""
1152+
1153+#. module: hr_attendance_analysis
1154+#: view:attendance_analysis.wizard.calendar_report:0
1155+msgid "Employees"
1156+msgstr ""
1157+
1158+#. module: hr_attendance_analysis
1159+#: help:resource.calendar.overtime.type,limit:0
1160+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"
1161+msgstr ""
1162+
1163+#. module: hr_attendance_analysis
1164+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:26
1165+msgid "Third Sign Out"
1166+msgstr ""
1167+
1168+#. module: hr_attendance_analysis
1169+#: help:resource.calendar,overtime_rounding_tolerance:0
1170+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."
1171+msgstr ""
1172+
1173+#. module: hr_attendance_analysis
1174+#: field:resource.calendar.overtime.type,sequence:0
1175+msgid "Sequence"
1176+msgstr ""
1177+
1178+#. module: hr_attendance_analysis
1179+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:111
1180+msgid "Total"
1181+msgstr ""
1182+
1183+#. module: hr_attendance_analysis
1184+#: code:addons/hr_attendance_analysis/report/calendar_report.py:45
1185+#, python-format
1186+msgid "Saturday"
1187+msgstr ""
1188+
1189
1190=== added file 'hr_attendance_analysis/i18n/it.po'
1191--- hr_attendance_analysis/i18n/it.po 1970-01-01 00:00:00 +0000
1192+++ hr_attendance_analysis/i18n/it.po 2013-05-31 10:20:41 +0000
1193@@ -0,0 +1,568 @@
1194+# Translation of OpenERP Server.
1195+# This file contains the translation of the following modules:
1196+# * hr_attendance_analysis
1197+#
1198+msgid ""
1199+msgstr ""
1200+"Project-Id-Version: OpenERP Server 6.0.3\n"
1201+"Report-Msgid-Bugs-To: support@openerp.com\n"
1202+"POT-Creation-Date: 2011-12-23 10:04+0000\n"
1203+"PO-Revision-Date: 2011-12-23 11:18+0100\n"
1204+"Last-Translator: Lorenzo Battistini <lorenzo.battistini@agilebg.com>\n"
1205+"Language-Team: \n"
1206+"MIME-Version: 1.0\n"
1207+"Content-Type: text/plain; charset=UTF-8\n"
1208+"Content-Transfer-Encoding: 8bit\n"
1209+"Plural-Forms: \n"
1210+
1211+#. module: hr_attendance_analysis
1212+#: code:addons/hr_attendance_analysis/hr_attendance.py:123
1213+#, python-format
1214+msgid "Incongruent data: sign-in %s is followed by another sign-in"
1215+msgstr "Dati incongruenti: l'entrata %s è seguita da un'altra entrata"
1216+
1217+#. module: hr_attendance_analysis
1218+#: code:addons/hr_attendance_analysis/hr_attendance.py:87
1219+#: code:addons/hr_attendance_analysis/hr_attendance.py:123
1220+#: code:addons/hr_attendance_analysis/hr_attendance.py:189
1221+#: code:addons/hr_attendance_analysis/wizard/print_calendar_report.py:58
1222+#: code:addons/hr_attendance_analysis/wizard/print_calendar_report.py:129
1223+#, python-format
1224+msgid "Error"
1225+msgstr "Errore"
1226+
1227+#. module: hr_attendance_analysis
1228+#: help:res.company,working_time_precision:0
1229+msgid "The precision used to analyse working times over working schedule"
1230+msgstr "La precisione utilizzata per analizzare le ore lavorative rispetto al calendario di lavoro"
1231+
1232+#. module: hr_attendance_analysis
1233+#: view:hr.attendance:0
1234+msgid "Group By..."
1235+msgstr "Raggruppa per..."
1236+
1237+#. module: hr_attendance_analysis
1238+#: code:addons/hr_attendance_analysis/report/calendar_report.py:47
1239+#, python-format
1240+msgid "Sunday"
1241+msgstr "Domenica"
1242+
1243+#. module: hr_attendance_analysis
1244+#: field:hr.attendance,end_datetime:0
1245+msgid "End date time"
1246+msgstr "Data e ora di fine"
1247+
1248+#. module: hr_attendance_analysis
1249+#: view:hr.attendance:0
1250+msgid "Today"
1251+msgstr "Oggi"
1252+
1253+#. module: hr_attendance_analysis
1254+#: view:hr.attendance:0
1255+msgid "Within working schedule"
1256+msgstr "All'interno del calendario di lavoro"
1257+
1258+#. module: hr_attendance_analysis
1259+#: selection:resource.calendar,attendance_rounding:0
1260+#: selection:resource.calendar,leave_rounding:0
1261+#: selection:resource.calendar,overtime_rounding:0
1262+msgid "20"
1263+msgstr "20"
1264+
1265+#. module: hr_attendance_analysis
1266+#: code:addons/hr_attendance_analysis/report/calendar_report.py:43
1267+#, python-format
1268+msgid "Friday"
1269+msgstr "Venerdì"
1270+
1271+#. module: hr_attendance_analysis
1272+#: model:ir.model,name:hr_attendance_analysis.model_attendance_analysis_wizard_calendar_report
1273+msgid "attendance_analysis.wizard.calendar_report"
1274+msgstr "attendance_analysis.wizard.calendar_report"
1275+
1276+#. module: hr_attendance_analysis
1277+#: selection:resource.calendar,attendance_rounding:0
1278+#: selection:resource.calendar,leave_rounding:0
1279+#: selection:resource.calendar,overtime_rounding:0
1280+msgid "8"
1281+msgstr "8"
1282+
1283+#. module: hr_attendance_analysis
1284+#: view:hr.attendance:0
1285+msgid "Day"
1286+msgstr "Giorno"
1287+
1288+#. module: hr_attendance_analysis
1289+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:36
1290+msgid "Leave"
1291+msgstr "Assenza"
1292+
1293+#. module: hr_attendance_analysis
1294+#: field:resource.calendar.overtime.type,limit:0
1295+msgid "Limit"
1296+msgstr "Limite"
1297+
1298+#. module: hr_attendance_analysis
1299+#: selection:resource.calendar,attendance_rounding:0
1300+#: selection:resource.calendar,leave_rounding:0
1301+#: selection:resource.calendar,overtime_rounding:0
1302+msgid "15"
1303+msgstr "15"
1304+
1305+#. module: hr_attendance_analysis
1306+#: help:resource.calendar,attendance_rounding:0
1307+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"
1308+msgstr "Per esempio, utilizzando un arrotondamento = 15 minuti, ogni entrata verrà arrotondata al quarto d'ora successivo ed ogni uscita al quarto d'ora precedente"
1309+
1310+#. module: hr_attendance_analysis
1311+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:80
1312+msgid "Totals"
1313+msgstr "Totali"
1314+
1315+#. module: hr_attendance_analysis
1316+#: help:resource.calendar.attendance,tolerance_to:0
1317+msgid "Sign in done in the interval \"Work from + Tolerance to\" will be considered done at \"Work from\""
1318+msgstr "Le entrate effettuate nell'intervallo \"Lavoro da + Tolleranza a\" saranno considerate come fatte in \"Lavoro da\""
1319+
1320+#. module: hr_attendance_analysis
1321+#: field:resource.calendar.attendance,tolerance_from:0
1322+msgid "Tolerance from"
1323+msgstr "Tolleranza da"
1324+
1325+#. module: hr_attendance_analysis
1326+#: field:attendance_analysis.wizard.calendar_report,from_date:0
1327+msgid "From date"
1328+msgstr "Dalla data"
1329+
1330+#. module: hr_attendance_analysis
1331+#: code:addons/hr_attendance_analysis/hr_attendance.py:87
1332+#, python-format
1333+msgid "Too many active contracts for employee %s"
1334+msgstr "Troppi contratti attivi per il dipendente %s"
1335+
1336+#. module: hr_attendance_analysis
1337+#: view:hr.attendance:0
1338+msgid "Calendar View"
1339+msgstr "Vista calendario"
1340+
1341+#. module: hr_attendance_analysis
1342+#: view:resource.calendar:0
1343+msgid "Roundings"
1344+msgstr "Arrotondamenti"
1345+
1346+#. module: hr_attendance_analysis
1347+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:25
1348+msgid "Third Sign In"
1349+msgstr "Terza entrata"
1350+
1351+#. module: hr_attendance_analysis
1352+#: model:ir.model,name:hr_attendance_analysis.model_hr_attendance
1353+msgid "Attendance"
1354+msgstr "Presenze"
1355+
1356+#. module: hr_attendance_analysis
1357+#: constraint:res.company:0
1358+msgid "Error! You can not create recursive companies."
1359+msgstr "Errore! Non è possibile creare aziende ricorsive."
1360+
1361+#. module: hr_attendance_analysis
1362+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:35
1363+msgid "Negative"
1364+msgstr "Negativo"
1365+
1366+#. module: hr_attendance_analysis
1367+#: view:hr.attendance:0
1368+msgid "Employee"
1369+msgstr "Dipendente"
1370+
1371+#. module: hr_attendance_analysis
1372+#: view:resource.calendar:0
1373+msgid "Type"
1374+msgstr "Tipo"
1375+
1376+#. module: hr_attendance_analysis
1377+#: view:hr.attendance:0
1378+msgid "Hr Attendance Search"
1379+msgstr "HR cerca presenza"
1380+
1381+#. module: hr_attendance_analysis
1382+#: view:hr.attendance:0
1383+msgid "Start date time"
1384+msgstr "Data e ora di inizio"
1385+
1386+#. module: hr_attendance_analysis
1387+#: help:resource.calendar,overtime_rounding:0
1388+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"
1389+msgstr "Impostando un arrotondamento = 30 minuti, uno straordinario di 29 minuti sarà considerato come 0 minuti, 31 minuti come 30 minuti, 61 minuti come un'ora e così via"
1390+
1391+#. module: hr_attendance_analysis
1392+#: field:resource.calendar,attendance_rounding:0
1393+msgid "Attendance rounding"
1394+msgstr "Arrotondamento presenza"
1395+
1396+#. module: hr_attendance_analysis
1397+#: selection:resource.calendar,attendance_rounding:0
1398+#: selection:resource.calendar,leave_rounding:0
1399+#: selection:resource.calendar,overtime_rounding:0
1400+msgid "3"
1401+msgstr "3"
1402+
1403+#. module: hr_attendance_analysis
1404+#: constraint:hr.attendance:0
1405+msgid "Error: Sign in (resp. Sign out) must follow Sign out (resp. Sign in)"
1406+msgstr "Errore: una operazione di Entrata (Uscita) deve essere seguito da una Uscita (Entrata)"
1407+
1408+#. module: hr_attendance_analysis
1409+#: view:res.company:0
1410+msgid "Configuration"
1411+msgstr "Configurazione"
1412+
1413+#. module: hr_attendance_analysis
1414+#: code:addons/hr_attendance_analysis/wizard/print_calendar_report.py:58
1415+#, python-format
1416+msgid "From date must be < to date"
1417+msgstr "\"Dalla data\" deve essere < di \"alla data\""
1418+
1419+#. module: hr_attendance_analysis
1420+#: view:hr.attendance:0
1421+msgid "Total hours"
1422+msgstr "Ore totali"
1423+
1424+#. module: hr_attendance_analysis
1425+#: field:res.company,working_time_precision:0
1426+msgid "Working time precision"
1427+msgstr "Precisione orario lavorativo"
1428+
1429+#. module: hr_attendance_analysis
1430+#: view:hr.attendance:0
1431+msgid "Employee attendances analysis"
1432+msgstr "Analisi presenze dipendente"
1433+
1434+#. module: hr_attendance_analysis
1435+#: field:resource.calendar.attendance,tolerance_to:0
1436+msgid "Tolerance to"
1437+msgstr "Tolleranza a"
1438+
1439+#. module: hr_attendance_analysis
1440+#: help:resource.calendar,leave_rounding:0
1441+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"
1442+msgstr "Al contrario dell'arrotondamento straordinari, utilizzando un arrotondamento = 15 minuti, un'assenza di 1 minuto verrà considerata come di 15 minuti, 16 minuti come 30 minuti e così via"
1443+
1444+#. module: hr_attendance_analysis
1445+#: model:ir.actions.report.xml,name:hr_attendance_analysis.attendance_analysis_report_id
1446+msgid "Attendances Analysis"
1447+msgstr "Analisi presenze"
1448+
1449+#. module: hr_attendance_analysis
1450+#: selection:resource.calendar,attendance_rounding:0
1451+#: selection:resource.calendar,leave_rounding:0
1452+#: selection:resource.calendar,overtime_rounding:0
1453+msgid "30"
1454+msgstr "30"
1455+
1456+#. module: hr_attendance_analysis
1457+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:110
1458+#: model:ir.model,name:hr_attendance_analysis.model_resource_calendar_overtime_type
1459+msgid "Overtime type"
1460+msgstr "Tipo di straordinario"
1461+
1462+#. module: hr_attendance_analysis
1463+#: field:hr.attendance,inside_calendar_duration:0
1464+msgid "Duration within working schedule"
1465+msgstr "Durata all'interno del calendario lavorativo"
1466+
1467+#. module: hr_attendance_analysis
1468+#: field:resource.calendar,leave_rounding:0
1469+msgid "Leave rounding"
1470+msgstr "Arrotonamento assenza"
1471+
1472+#. module: hr_attendance_analysis
1473+#: field:resource.calendar.overtime.type,calendar_id:0
1474+msgid "Calendar"
1475+msgstr "Calendario"
1476+
1477+#. module: hr_attendance_analysis
1478+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:32
1479+msgid "Due"
1480+msgstr "Dovuto"
1481+
1482+#. module: hr_attendance_analysis
1483+#: view:attendance_analysis.wizard.calendar_report:0
1484+#: model:ir.actions.act_window,name:hr_attendance_analysis.action_wizard_calendar_report
1485+#: model:ir.ui.menu,name:hr_attendance_analysis.menu_action_wizard_calendar_report
1486+msgid "Attendances Analysis Calendar"
1487+msgstr "Calendario di analisi presenze"
1488+
1489+#. module: hr_attendance_analysis
1490+#: selection:resource.calendar,attendance_rounding:0
1491+#: selection:resource.calendar,leave_rounding:0
1492+#: selection:resource.calendar,overtime_rounding:0
1493+msgid "60"
1494+msgstr "60"
1495+
1496+#. module: hr_attendance_analysis
1497+#: view:resource.calendar:0
1498+#: field:resource.calendar,overtime_type_ids:0
1499+msgid "Overtime types"
1500+msgstr "Tipi di straordinario"
1501+
1502+#. module: hr_attendance_analysis
1503+#: code:addons/hr_attendance_analysis/report/calendar_report.py:35
1504+#, python-format
1505+msgid "Monday"
1506+msgstr "Lunedì"
1507+
1508+#. module: hr_attendance_analysis
1509+#: field:attendance_analysis.wizard.calendar_report,employee_ids:0
1510+msgid "unknown"
1511+msgstr "sconosciuto"
1512+
1513+#. module: hr_attendance_analysis
1514+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:18
1515+msgid "First Sign Out"
1516+msgstr "Prima uscita"
1517+
1518+#. module: hr_attendance_analysis
1519+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:15
1520+msgid "Day of week"
1521+msgstr "Giorno della settimana"
1522+
1523+#. module: hr_attendance_analysis
1524+#: field:resource.calendar,overtime_rounding_tolerance:0
1525+msgid "Overtime rounding tolerance"
1526+msgstr "Tolleranza arrotondamento straordinari"
1527+
1528+#. module: hr_attendance_analysis
1529+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:29
1530+msgid "Fourth Sign In"
1531+msgstr "Quarta entrata"
1532+
1533+#. module: hr_attendance_analysis
1534+#: code:addons/hr_attendance_analysis/wizard/print_calendar_report.py:130
1535+#, python-format
1536+msgid "%s: 'Work to' is < 'Work from'"
1537+msgstr "%s: 'Lavoro a' è < 'Lavoro da'"
1538+
1539+#. module: hr_attendance_analysis
1540+#: selection:resource.calendar,attendance_rounding:0
1541+#: selection:resource.calendar,leave_rounding:0
1542+#: selection:resource.calendar,overtime_rounding:0
1543+msgid "2"
1544+msgstr "2"
1545+
1546+#. module: hr_attendance_analysis
1547+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:10
1548+msgid "Employee: "
1549+msgstr "Dipendente:"
1550+
1551+#. module: hr_attendance_analysis
1552+#: selection:resource.calendar,attendance_rounding:0
1553+#: selection:resource.calendar,leave_rounding:0
1554+#: selection:resource.calendar,overtime_rounding:0
1555+msgid "6"
1556+msgstr "6"
1557+
1558+#. module: hr_attendance_analysis
1559+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:14
1560+msgid "Date"
1561+msgstr "Data"
1562+
1563+#. module: hr_attendance_analysis
1564+#: model:ir.module.module,shortdesc:hr_attendance_analysis.module_meta_information
1565+msgid "HR - Attendance Analysis"
1566+msgstr "HR - Analisi presenze"
1567+
1568+#. module: hr_attendance_analysis
1569+#: code:addons/hr_attendance_analysis/hr_attendance.py:190
1570+#, python-format
1571+msgid "Wrongly configured working schedule with id %s"
1572+msgstr "Calendario lavorativo con id %s configurato in modo scorretto"
1573+
1574+#. module: hr_attendance_analysis
1575+#: model:ir.model,name:hr_attendance_analysis.model_res_company
1576+msgid "Companies"
1577+msgstr "Aziende"
1578+
1579+#. module: hr_attendance_analysis
1580+#: code:addons/hr_attendance_analysis/report/calendar_report.py:39
1581+#, python-format
1582+msgid "Wednesday"
1583+msgstr "Mercoledì"
1584+
1585+#. module: hr_attendance_analysis
1586+#: field:resource.calendar.overtime.type,name:0
1587+msgid "Type Description"
1588+msgstr "Descrizione tipo"
1589+
1590+#. module: hr_attendance_analysis
1591+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:17
1592+msgid "First Sign In"
1593+msgstr "Prima entrata"
1594+
1595+#. module: hr_attendance_analysis
1596+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:30
1597+msgid "Fourth Sign Out"
1598+msgstr "Quarta uscita"
1599+
1600+#. module: hr_attendance_analysis
1601+#: model:ir.module.module,description:hr_attendance_analysis.module_meta_information
1602+msgid ""
1603+"\n"
1604+"Dynamic reports based on employee's attendances and contract's calendar.\n"
1605+"Among other things, it lets you see the amount of working hours outside and inside the contract's working schedule (overtime).\n"
1606+"It also provides a daily based report, showing the detailed and total hours compared to calendar hours.\n"
1607+msgstr ""
1608+"\n"
1609+"Dynamic reports based on employee's attendances and contract's calendar.\n"
1610+"Among other things, it lets you see the amount of working hours outside and inside the contract's working schedule (overtime).\n"
1611+"It also provides a daily based report, showing the detailed and total hours compared to calendar hours.\n"
1612+
1613+#. module: hr_attendance_analysis
1614+#: selection:resource.calendar,attendance_rounding:0
1615+#: selection:resource.calendar,leave_rounding:0
1616+#: selection:resource.calendar,overtime_rounding:0
1617+msgid "10"
1618+msgstr "10"
1619+
1620+#. module: hr_attendance_analysis
1621+#: selection:resource.calendar,attendance_rounding:0
1622+#: selection:resource.calendar,leave_rounding:0
1623+#: selection:resource.calendar,overtime_rounding:0
1624+msgid "12"
1625+msgstr "12"
1626+
1627+#. module: hr_attendance_analysis
1628+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:22
1629+msgid "Second Sign Out"
1630+msgstr "Seconda uscita"
1631+
1632+#. module: hr_attendance_analysis
1633+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:34
1634+#: view:hr.attendance:0
1635+#: field:hr.attendance,outside_calendar_duration:0
1636+msgid "Overtime"
1637+msgstr "Straordinario"
1638+
1639+#. module: hr_attendance_analysis
1640+#: model:ir.model,name:hr_attendance_analysis.model_resource_calendar_attendance
1641+msgid "Work Detail"
1642+msgstr "Dettagli del lavoro"
1643+
1644+#. module: hr_attendance_analysis
1645+#: help:resource.calendar.attendance,tolerance_from:0
1646+msgid "Sign out done in the interval \"Work to - Tolerance from\" will be considered done at \"Work to\""
1647+msgstr "Le uscite effettuate nell'intervallo \"Lavoro a - Tolleranza da\" saranno considerate come fatte in \"Lavoro a\""
1648+
1649+#. module: hr_attendance_analysis
1650+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:21
1651+msgid "Second Sign In"
1652+msgstr "Seconda entrata"
1653+
1654+#. module: hr_attendance_analysis
1655+#: view:attendance_analysis.wizard.calendar_report:0
1656+msgid "Cancel"
1657+msgstr "Annulla"
1658+
1659+#. module: hr_attendance_analysis
1660+#: code:addons/hr_attendance_analysis/report/calendar_report.py:37
1661+#, python-format
1662+msgid "Tuesday"
1663+msgstr "Martedì"
1664+
1665+#. module: hr_attendance_analysis
1666+#: model:ir.actions.act_window,name:hr_attendance_analysis.open_view_attendance
1667+#: model:ir.ui.menu,name:hr_attendance_analysis.menu_open_view_attendance
1668+msgid "Attendances analysis"
1669+msgstr "Analisi presenze"
1670+
1671+#. module: hr_attendance_analysis
1672+#: code:addons/hr_attendance_analysis/report/calendar_report.py:41
1673+#, python-format
1674+msgid "Thursday"
1675+msgstr "Giovedì"
1676+
1677+#. module: hr_attendance_analysis
1678+#: view:attendance_analysis.wizard.calendar_report:0
1679+msgid "Print"
1680+msgstr "Stampa"
1681+
1682+#. module: hr_attendance_analysis
1683+#: model:ir.model,name:hr_attendance_analysis.model_resource_calendar
1684+msgid "Resource Calendar"
1685+msgstr "Calendario risorse"
1686+
1687+#. module: hr_attendance_analysis
1688+#: field:hr.attendance,duration:0
1689+msgid "Attendance duration"
1690+msgstr "Durata presenza"
1691+
1692+#. module: hr_attendance_analysis
1693+#: selection:resource.calendar,attendance_rounding:0
1694+#: selection:resource.calendar,leave_rounding:0
1695+#: selection:resource.calendar,overtime_rounding:0
1696+msgid "1"
1697+msgstr "1"
1698+
1699+#. module: hr_attendance_analysis
1700+#: field:attendance_analysis.wizard.calendar_report,to_date:0
1701+msgid "To date"
1702+msgstr "Alla data"
1703+
1704+#. module: hr_attendance_analysis
1705+#: selection:resource.calendar,attendance_rounding:0
1706+#: selection:resource.calendar,leave_rounding:0
1707+#: selection:resource.calendar,overtime_rounding:0
1708+msgid "5"
1709+msgstr "5"
1710+
1711+#. module: hr_attendance_analysis
1712+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:33
1713+msgid "Working Hours"
1714+msgstr "Ore lavorative"
1715+
1716+#. module: hr_attendance_analysis
1717+#: view:resource.calendar:0
1718+msgid "Types"
1719+msgstr "Tipi"
1720+
1721+#. module: hr_attendance_analysis
1722+#: field:resource.calendar,overtime_rounding:0
1723+msgid "Overtime rounding"
1724+msgstr "Arrotondamento straordinario"
1725+
1726+#. module: hr_attendance_analysis
1727+#: view:attendance_analysis.wizard.calendar_report:0
1728+msgid "Employees"
1729+msgstr "Dipendenti"
1730+
1731+#. module: hr_attendance_analysis
1732+#: help:resource.calendar.overtime.type,limit:0
1733+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"
1734+msgstr "Limite, in ore, dello straordinario che può essere attribuito a questo tipo di straordinario in un giorno. L'eccedenza è attribuita al tipo successivo."
1735+
1736+#. module: hr_attendance_analysis
1737+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:26
1738+msgid "Third Sign Out"
1739+msgstr "Terza uscita"
1740+
1741+#. module: hr_attendance_analysis
1742+#: help:resource.calendar,overtime_rounding_tolerance:0
1743+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."
1744+msgstr "Lo straordinario può essere arrotondato usando una tolleranza. Con una tolleranza = 3 minuti e arrotondamento = 15 minuti, se il dipendente fa uno straordinario di 12 minuti, sarà considerato come 15 minuti."
1745+
1746+#. module: hr_attendance_analysis
1747+#: field:resource.calendar.overtime.type,sequence:0
1748+msgid "Sequence"
1749+msgstr "Sequenza"
1750+
1751+#. module: hr_attendance_analysis
1752+#: report:addons/hr_attendance_analysis/report/calendar_report.mako:111
1753+msgid "Total"
1754+msgstr "Totale"
1755+
1756+#. module: hr_attendance_analysis
1757+#: code:addons/hr_attendance_analysis/report/calendar_report.py:45
1758+#, python-format
1759+msgid "Saturday"
1760+msgstr "Sabato"
1761+
1762
1763=== added directory 'hr_attendance_analysis/report'
1764=== added file 'hr_attendance_analysis/report/__init__.py'
1765--- hr_attendance_analysis/report/__init__.py 1970-01-01 00:00:00 +0000
1766+++ hr_attendance_analysis/report/__init__.py 2013-05-31 10:20:41 +0000
1767@@ -0,0 +1,21 @@
1768+# -*- coding: utf-8 -*-
1769+##############################################################################
1770+#
1771+# Copyright (C) 2011 Agile Business Group sagl (<http://www.agilebg.com>)
1772+# Copyright (C) 2011 Domsense srl (<http://www.domsense.com>)
1773+#
1774+# This program is free software: you can redistribute it and/or modify
1775+# it under the terms of the GNU Affero General Public License as published
1776+# by the Free Software Foundation, either version 3 of the License, or
1777+# (at your option) any later version.
1778+#
1779+# This program is distributed in the hope that it will be useful,
1780+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1781+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1782+# GNU General Public License for more details.
1783+#
1784+# You should have received a copy of the GNU Affero General Public License
1785+# along with this program. If not, see <http://www.gnu.org/licenses/>.
1786+#
1787+##############################################################################
1788+import calendar_report
1789
1790=== added file 'hr_attendance_analysis/report/calendar_report.mako'
1791--- hr_attendance_analysis/report/calendar_report.mako 1970-01-01 00:00:00 +0000
1792+++ hr_attendance_analysis/report/calendar_report.mako 2013-05-31 10:20:41 +0000
1793@@ -0,0 +1,138 @@
1794+<html>
1795+<head>
1796+ <style type="text/css">
1797+ ${css}
1798+ </style>
1799+</head>
1800+<body>
1801+ <% setLang(objects[0].company_id.partner_id.lang) %>
1802+ <% from datetime import datetime %>
1803+ %for employee in objects :
1804+ <h2>${_("Employee: ")} ${ employee.name or ''|entity }</h2>
1805+ <table style="width:100%" border="1">
1806+ <thead style="border-bottom: solid; background-color: WhiteSmoke">
1807+ <tr style="page-break-inside: avoid">
1808+ <th style="text-align:left">${_("Date")}</th>
1809+ <th style="text-align:left">${_("Day of week")}</th>
1810+ %if max_per_day() >= 1:
1811+ <th style="text-align:left">${_("First Sign In")}</th>
1812+ <th style="text-align:left">${_("First Sign Out")}</th>
1813+ %endif
1814+ %if max_per_day() >= 2:
1815+ <th style="text-align:left">${_("Second Sign In")}</th>
1816+ <th style="text-align:left">${_("Second Sign Out")}</th>
1817+ %endif
1818+ %if max_per_day() >= 3:
1819+ <th style="text-align:left">${_("Third Sign In")}</th>
1820+ <th style="text-align:left">${_("Third Sign Out")}</th>
1821+ %endif
1822+ %if max_per_day() >= 4:
1823+ <th style="text-align:left">${_("Fourth Sign In")}</th>
1824+ <th style="text-align:left">${_("Fourth Sign Out")}</th>
1825+ %endif
1826+ <th style="text-align:right">${_("Due")}</th>
1827+ <th style="text-align:right">${_("Working Hours")}</th>
1828+ <th style="text-align:right">${_("Overtime")}</th>
1829+ <th style="text-align:right">${_("Negative")}</th>
1830+ <th style="text-align:right">${_("Leave")}</th>
1831+ </tr>
1832+ </thead>
1833+ <% first_done = 0 %>
1834+ %for day in sorted(days_by_employee(employee.id).iterkeys()) :
1835+ %if datetime.strptime(day, '%Y-%m-%d').day == 1 or not first_done:
1836+ <tr style="page-break-inside: avoid" >
1837+ <td colspan="15">
1838+ <strong>${ month_name(day) | entity }</strong>
1839+ </td>
1840+ </tr>
1841+ <% first_done = 1 %>
1842+ %endif
1843+ <tr style="page-break-inside: avoid">
1844+ <td style="text-align:left">${ formatLang(day, date=True) | entity }</td>
1845+ <td style="text-align:left">${ day_of_week(day) | entity }</td>
1846+ %if max_per_day() >= 1:
1847+ <td style="text-align:left">${ days_by_employee(employee.id)[day]['signin_1'] | entity }</td>
1848+ <td style="text-align:left">${ days_by_employee(employee.id)[day]['signout_1'] | entity }</td>
1849+ %endif
1850+ %if max_per_day() >= 2:
1851+ <td style="text-align:left">${ days_by_employee(employee.id)[day]['signin_2'] | entity }</td>
1852+ <td style="text-align:left">${ days_by_employee(employee.id)[day]['signout_2'] | entity }</td>
1853+ %endif
1854+ %if max_per_day() >= 3:
1855+ <td style="text-align:left">${ days_by_employee(employee.id)[day]['signin_3'] | entity }</td>
1856+ <td style="text-align:left">${ days_by_employee(employee.id)[day]['signout_3'] | entity }</td>
1857+ %endif
1858+ %if max_per_day() >= 4:
1859+ <td style="text-align:left">${ days_by_employee(employee.id)[day]['signin_4'] | entity }</td>
1860+ <td style="text-align:left">${ days_by_employee(employee.id)[day]['signout_4'] | entity }</td>
1861+ %endif
1862+ <td style="text-align:right">${ (days_by_employee(employee.id)[day]['due']) | entity }</td>
1863+ <td style="text-align:right">${ (days_by_employee(employee.id)[day]['attendances']) | entity }</td>
1864+ %if days_by_employee(employee.id)[day]['overtime'] != '00:00':
1865+ <td style="text-align:right; background-color:LightGreen">${ (days_by_employee(employee.id)[day]['overtime']) | entity }</td>
1866+ %else:
1867+ <td style="text-align:right">${ (days_by_employee(employee.id)[day]['overtime']) | entity }</td>
1868+ %endif
1869+ %if days_by_employee(employee.id)[day]['negative'] != '00:00':
1870+ <td style="text-align:right; background-color: Tomato">${ (days_by_employee(employee.id)[day]['negative']) | entity }</td>
1871+ %else:
1872+ <td style="text-align:right">${ (days_by_employee(employee.id)[day]['negative']) | entity }</td>
1873+ %endif
1874+ %if days_by_employee(employee.id)[day]['leaves'] != '00:00':
1875+ <td style="text-align:right; background-color: Silver">${ (days_by_employee(employee.id)[day]['leaves']) | entity }</td>
1876+ %else:
1877+ <td style="text-align:right">${ (days_by_employee(employee.id)[day]['leaves']) | entity }</td>
1878+ %endif
1879+ </tr>
1880+ %endfor
1881+ <tfoot style="font-weight:bold">
1882+ <tr style="page-break-inside: avoid">
1883+ <td style="text-align:left">${_("Totals")} </td>
1884+ <td></td>
1885+ %if max_per_day() >= 1:
1886+ <td></td>
1887+ <td></td>
1888+ %endif
1889+ %if max_per_day() >= 2:
1890+ <td></td>
1891+ <td></td>
1892+ %endif
1893+ %if max_per_day() >= 3:
1894+ <td></td>
1895+ <td></td>
1896+ %endif
1897+ %if max_per_day() >= 4:
1898+ <td></td>
1899+ <td></td>
1900+ %endif
1901+ <td style="border-top:1px solid #000; text-align:right">${ (totals_by_employee(employee.id)['total_due']) | entity }</td>
1902+ <td style="border-top:1px solid #000; text-align:right">${ (totals_by_employee(employee.id)['total_attendances']) | entity }</td>
1903+ <td style="border-top:1px solid #000; text-align:right">${ (totals_by_employee(employee.id)['total_overtime']) | entity }</td>
1904+ <td style="border-top:1px solid #000; text-align:right">${ (totals_by_employee(employee.id)['total_negative']) | entity }</td>
1905+ <td style="border-top:1px solid #000; text-align:right">${ (totals_by_employee(employee.id)['total_leaves']) | entity }</td>
1906+ </tr>
1907+ </tfoot>
1908+ </table>
1909+ <br/>
1910+ <table>
1911+ <thead>
1912+ <tr>
1913+ <th style="text-align:left">${_("Overtime type")}</th>
1914+ <th style="text-align:right">${_("Total")}</th>
1915+ </tr>
1916+ </thead>
1917+ %for type in totals_by_employee(employee.id)['total_types']:
1918+ <tr>
1919+ <td style="text-align:left">
1920+ ${type | entity}
1921+ </td>
1922+ <td style="text-align:right">
1923+ ${(totals_by_employee(employee.id)['total_types'][type]) | entity}
1924+ </td>
1925+ </tr>
1926+ %endfor
1927+ </table>
1928+ <p style="page-break-after:always; height: 1px"></p>
1929+ %endfor
1930+</body>
1931+</html>
1932
1933=== added file 'hr_attendance_analysis/report/calendar_report.py'
1934--- hr_attendance_analysis/report/calendar_report.py 1970-01-01 00:00:00 +0000
1935+++ hr_attendance_analysis/report/calendar_report.py 2013-05-31 10:20:41 +0000
1936@@ -0,0 +1,96 @@
1937+# -*- coding: utf-8 -*-
1938+##############################################################################
1939+#
1940+# Copyright (C) 2011 Agile Business Group sagl (<http://www.agilebg.com>)
1941+# Copyright (C) 2011 Domsense srl (<http://www.domsense.com>)
1942+#
1943+# This program is free software: you can redistribute it and/or modify
1944+# it under the terms of the GNU Affero General Public License as published
1945+# by the Free Software Foundation, either version 3 of the License, or
1946+# (at your option) any later version.
1947+#
1948+# This program is distributed in the hope that it will be useful,
1949+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1950+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1951+# GNU General Public License for more details.
1952+#
1953+# You should have received a copy of the GNU Affero General Public License
1954+# along with this program. If not, see <http://www.gnu.org/licenses/>.
1955+#
1956+##############################################################################
1957+
1958+import time
1959+from report import report_sxw
1960+from osv import osv
1961+from datetime import datetime
1962+from tools.translate import _
1963+
1964+class Parser(report_sxw.rml_parse):
1965+
1966+ def _get_day_of_week(self, day):
1967+ WEEKDAYS = {
1968+ 0: _('Monday'),
1969+ 1: _('Tuesday'),
1970+ 2: _('Wednesday'),
1971+ 3: _('Thursday'),
1972+ 4: _('Friday'),
1973+ 5: _('Saturday'),
1974+ 6: _('Sunday'),
1975+ }
1976+ dayofweek=''
1977+ weekday = datetime.strptime(day,'%Y-%m-%d').weekday()
1978+ return WEEKDAYS[weekday]
1979+
1980+ def _get_month_name(self, day):
1981+ str_month=''
1982+ month = datetime.strptime(day,'%Y-%m-%d').month
1983+ if month == 1:
1984+ str_month = _('January')
1985+ elif month == 2:
1986+ str_month = _('February')
1987+ elif month == 3:
1988+ str_month = _('March')
1989+ elif month == 4:
1990+ str_month = _('April')
1991+ elif month == 5:
1992+ str_month = _('May')
1993+ elif month == 6:
1994+ str_month = _('June')
1995+ elif month == 7:
1996+ str_month = _('July')
1997+ elif month == 8:
1998+ str_month = _('August')
1999+ elif month == 9:
2000+ str_month = _('September')
2001+ elif month == 10:
2002+ str_month = _('October')
2003+ elif month == 11:
2004+ str_month = _('November')
2005+ elif month == 12:
2006+ str_month = _('December')
2007+ return str_month
2008+
2009+ def _get_days_by_employee(self, employee_id):
2010+ return self.localcontext['data']['form']['days_by_employee'][str(employee_id)]
2011+
2012+ def _get_totals_by_employee(self, employee_id):
2013+ return self.localcontext['data']['form']['totals_by_employee'][str(employee_id)]
2014+
2015+ def _get_max_per_day(self):
2016+ return self.localcontext['data']['form']['max_number_of_attendances_per_day']
2017+
2018+ def __init__(self, cr, uid, name, context):
2019+ super(Parser, self).__init__(cr, uid, name, context)
2020+ self.localcontext.update({
2021+ 'time': time,
2022+ 'days_by_employee': self._get_days_by_employee,
2023+ 'totals_by_employee': self._get_totals_by_employee,
2024+ 'day_of_week': self._get_day_of_week,
2025+ 'max_per_day': self._get_max_per_day,
2026+ 'month_name': self._get_month_name,
2027+ })
2028+
2029+report_sxw.report_sxw('report.attendance_analysis.calendar_report',
2030+ 'attendance_analysis.calendar_report',
2031+ 'attendance_analysis/report/calendar_report.mako',
2032+ parser=Parser)
2033
2034=== added file 'hr_attendance_analysis/reports.xml'
2035--- hr_attendance_analysis/reports.xml 1970-01-01 00:00:00 +0000
2036+++ hr_attendance_analysis/reports.xml 2013-05-31 10:20:41 +0000
2037@@ -0,0 +1,86 @@
2038+<?xml version="1.0"?>
2039+<openerp>
2040+ <data><record id="attendances_landscape_header" model="ir.header_webkit">
2041+ <field name="footer_html"><![CDATA[
2042+<html>
2043+ <head>
2044+ <meta content="text/html; charset=UTF-8" http-equiv="content-type"/>
2045+ <script>
2046+ function subst() {
2047+ var vars={};
2048+ var x=document.location.search.substring(1).split('&');
2049+ for(var i in x) {var z=x[i].split('=',2);vars[z[0]] = unescape(z[1]);}
2050+ var x=['frompage','topage','page','webpage','section','subsection','subsubsection'];
2051+ for(var i in x) {
2052+ var y = document.getElementsByClassName(x[i]);
2053+ for(var j=0; j<y.length; ++j) y[j].textContent = vars[x[i]];
2054+ }
2055+ }
2056+ </script>
2057+ </head>
2058+ <% import datetime %>
2059+ <body style="border:0" onload="subst()">
2060+ <table style="border-top: 1px solid black; width: 1080px">
2061+ <tr style="border-collapse:collapse;">
2062+ <td style="text-align:left;font-size:10;width:350px;">${formatLang( str(datetime.datetime.today()), date_time=True)}</td>
2063+ <td style="text-align:center;font-size:10;width:350px;"></td>
2064+ <td style="text-align:right;font-size:10;width:350px;">Page&nbsp;<span class="page"/></td>
2065+ <td style="text-align:left;font-size:10;width:30px">&nbsp;of&nbsp;<span class="topage"/></td>
2066+ </tr>
2067+ </table>
2068+ </body>
2069+</html>]]></field>
2070+ <field name="orientation">Landscape</field>
2071+ <field name="format">A4</field>
2072+ <field name="html"><![CDATA[
2073+<html>
2074+ <head>
2075+ <meta content="text/html; charset=UTF-8" http-equiv="content-type"/>
2076+ <script>
2077+ function subst() {
2078+ var vars={};
2079+ var x=document.location.search.substring(1).split('&');
2080+ for(var i in x) {var z=x[i].split('=',2);vars[z[0]] = unescape(z[1]);}
2081+ var x=['frompage','topage','page','webpage','section','subsection','subsubsection'];
2082+ for(var i in x) {
2083+ var y = document.getElementsByClassName(x[i]);
2084+ for(var j=0; j<y.length; ++j) y[j].textContent = vars[x[i]];
2085+ }
2086+ }
2087+ </script>
2088+ <style type="text/css">
2089+ ${css}
2090+ </style>
2091+ </head>
2092+ <body style="border:0; margin: 0;" onload="subst()">
2093+ <table class="header" style="border-bottom: 0px solid black; width: 100%">
2094+ <tr>
2095+ <td><h1>${_("Attendances Analysis")} - ${objects[0].company_id.partner_id.name | entity}</h1></td>
2096+ </tr>
2097+ </table> ${_debug or ''|n}
2098+ </body>
2099+</html>]]>
2100+ </field>
2101+ <field name="css"><![CDATA[
2102+
2103+body, table, td, span, div {
2104+ font-family: Helvetica, Arial;
2105+}
2106+
2107+]]>
2108+ </field>
2109+ <field eval="20" name="margin_top"/>
2110+ <field name="name">Attendances Landscape Header</field>
2111+ </record>
2112+ <record id="attendance_analysis_report_id" model="ir.actions.report.xml">
2113+ <field name="name">Attendances Analysis</field>
2114+ <field name="type">ir.actions.report.xml</field>
2115+ <field name="model">hr.employee</field>
2116+ <field name="report_name">attendance_analysis.calendar_report</field>
2117+ <field name="report_rml">hr_attendance_analysis/report/calendar_report.mako</field>
2118+ <field name="report_type">webkit</field>
2119+ <field name="webkit_header" ref="attendances_landscape_header"/>
2120+ </record>
2121+ </data>
2122+</openerp>
2123+
2124
2125=== added file 'hr_attendance_analysis/resource.py'
2126--- hr_attendance_analysis/resource.py 1970-01-01 00:00:00 +0000
2127+++ hr_attendance_analysis/resource.py 2013-05-31 10:20:41 +0000
2128@@ -0,0 +1,102 @@
2129+# -*- coding: utf-8 -*-
2130+##############################################################################
2131+#
2132+# Copyright (C) 2011 Domsense srl (<http://www.domsense.com>)
2133+# Copyright (C) 2011-2013 Agile Business Group sagl
2134+# (<http://www.agilebg.com>)
2135+#
2136+# This program is free software: you can redistribute it and/or modify
2137+# it under the terms of the GNU Affero General Public License as published
2138+# by the Free Software Foundation, either version 3 of the License, or
2139+# (at your option) any later version.
2140+#
2141+# This program is distributed in the hope that it will be useful,
2142+# but WITHOUT ANY WARRANTY; without even the implied warranty of
2143+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2144+# GNU Affero General Public License for more details.
2145+#
2146+# You should have received a copy of the GNU Affero General Public License
2147+# along with this program. If not, see <http://www.gnu.org/licenses/>.
2148+#
2149+##############################################################################
2150+
2151+from openerp.osv import fields, orm
2152+
2153+class resource_calendar_attendance(orm.Model):
2154+ _inherit = "resource.calendar.attendance"
2155+ _columns = {
2156+ 'tolerance_from': fields.float('Tolerance from', size=8,
2157+ help='Sign out done in the interval "Work to - Tolerance from" will be considered done at "Work to"'),
2158+ 'tolerance_to': fields.float('Tolerance to', size=8,
2159+ help='Sign in done in the interval "Work from + Tolerance to" will be considered done at "Work from"'),
2160+ }
2161+
2162+
2163+class resource_calendar(orm.Model):
2164+ _inherit = "resource.calendar"
2165+ _columns = {
2166+ 'attendance_rounding': fields.selection([
2167+ ('60', '1'),
2168+ ('30', '2'),
2169+ ('20', '3'),
2170+ ('12', '5'),
2171+ ('10', '6'),
2172+ ('7.5', '8'),
2173+ ('6', '10'),
2174+ ('5', '12'),
2175+ ('4', '15'),
2176+ ('3', '20'),
2177+ ('2', '30'),
2178+ ('1', '60'),
2179+ ],
2180+ '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'),
2181+ #'attendance_rounding': fields.float('Attendance rounding', size=8,
2182+ #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'),
2183+ 'overtime_rounding': fields.selection([
2184+ ('60', '1'),
2185+ ('30', '2'),
2186+ ('20', '3'),
2187+ ('12', '5'),
2188+ ('10', '6'),
2189+ ('7.5', '8'),
2190+ ('6', '10'),
2191+ ('5', '12'),
2192+ ('4', '15'),
2193+ ('3', '20'),
2194+ ('2', '30'),
2195+ ('1', '60'),
2196+ ],
2197+ 'Overtime rounding',
2198+ 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'),
2199+ 'overtime_rounding_tolerance': fields.float('Overtime rounding tolerance', size=8,
2200+ 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.'),
2201+ 'leave_rounding': fields.selection([
2202+ ('60', '1'),
2203+ ('30', '2'),
2204+ ('20', '3'),
2205+ ('12', '5'),
2206+ ('10', '6'),
2207+ ('7.5', '8'),
2208+ ('6', '10'),
2209+ ('5', '12'),
2210+ ('4', '15'),
2211+ ('3', '20'),
2212+ ('2', '30'),
2213+ ('1', '60'),
2214+ ],
2215+ 'Leave rounding',
2216+ 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'),
2217+ 'overtime_type_ids': fields.one2many('resource.calendar.overtime.type', 'calendar_id', 'Overtime types'),
2218+ }
2219+
2220+class resource_calendar_overtime_range(orm.Model):
2221+ _name = 'resource.calendar.overtime.type'
2222+ _description = 'Overtime type'
2223+ _order = 'sequence'
2224+ _columns = {
2225+ 'sequence': fields.integer('Sequence', required=True),
2226+ 'name': fields.char('Type Description', size=64, required=True),
2227+ 'calendar_id': fields.many2one('resource.calendar', 'Calendar'),
2228+ 'limit': fields.float('Limit', size=8,
2229+ 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')
2230+ }
2231
2232=== added file 'hr_attendance_analysis/resource_view.xml'
2233--- hr_attendance_analysis/resource_view.xml 1970-01-01 00:00:00 +0000
2234+++ hr_attendance_analysis/resource_view.xml 2013-05-31 10:20:41 +0000
2235@@ -0,0 +1,52 @@
2236+<?xml version="1.0" encoding="utf-8"?>
2237+<openerp>
2238+ <data>
2239+
2240+ <record id="view_resource_calendar_attendance_form" model="ir.ui.view">
2241+ <field name="name">resource.calendar.attendance.form</field>
2242+ <field name="model">resource.calendar.attendance</field>
2243+ <field name="inherit_id" ref="resource.view_resource_calendar_attendance_form"></field>
2244+ <field name="arch" type="xml">
2245+ <field name="hour_from" position="after">
2246+ <field name="tolerance_to" widget="float_time"/>
2247+ </field>
2248+ <field name="hour_to" position="after">
2249+ <field name="tolerance_from" widget="float_time"/>
2250+ </field>
2251+ </field>
2252+ </record>
2253+ <record id="resource_calendar_form" model="ir.ui.view">
2254+ <field name="name">resource.calendar.form</field>
2255+ <field name="model">resource.calendar</field>
2256+ <field name="inherit_id" ref="resource.resource_calendar_form"></field>
2257+ <field name="arch" type="xml">
2258+ <field name="attendance_ids" position="after">
2259+ <notebook colspan="4">
2260+ <page string="Roundings">
2261+ <group colspan="4">
2262+ <field name="attendance_rounding"/>
2263+ <field name="leave_rounding"/>
2264+ <field name="overtime_rounding"/>
2265+ <field name="overtime_rounding_tolerance" widget="float_time"/>
2266+ </group>
2267+ </page>
2268+ <page string="Overtime types">
2269+ <field name="overtime_type_ids" colspan="4" nolabel="1">
2270+ <tree string="Types" editable="bottom">
2271+ <field name="sequence"/>
2272+ <field name="name"/>
2273+ <field name="limit" widget="float_time"/>
2274+ </tree>
2275+ <form string="Type">
2276+ <field name="sequence"/>
2277+ <field name="name"/>
2278+ <field name="limit" widget="float_time"/>
2279+ </form>
2280+ </field>
2281+ </page>
2282+ </notebook>
2283+ </field>
2284+ </field>
2285+ </record>
2286+ </data>
2287+</openerp>
2288
2289=== added directory 'hr_attendance_analysis/security'
2290=== added file 'hr_attendance_analysis/security/ir.model.access.csv'
2291--- hr_attendance_analysis/security/ir.model.access.csv 1970-01-01 00:00:00 +0000
2292+++ hr_attendance_analysis/security/ir.model.access.csv 2013-05-31 10:20:41 +0000
2293@@ -0,0 +1,3 @@
2294+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
2295+access_resource_calendar_overtime_type,resource.calendar.overtime.type,model_resource_calendar_overtime_type,base.group_system,1,1,1,1
2296+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
2297
2298=== added directory 'hr_attendance_analysis/wizard'
2299=== added file 'hr_attendance_analysis/wizard/__init__.py'
2300--- hr_attendance_analysis/wizard/__init__.py 1970-01-01 00:00:00 +0000
2301+++ hr_attendance_analysis/wizard/__init__.py 2013-05-31 10:20:41 +0000
2302@@ -0,0 +1,23 @@
2303+# -*- coding: utf-8 -*-
2304+##############################################################################
2305+#
2306+# Copyright (C) 2011 Domsense srl (<http://www.domsense.com>)
2307+# Copyright (C) 2011-2013 Agile Business Group sagl
2308+# (<http://www.agilebg.com>)
2309+#
2310+# This program is free software: you can redistribute it and/or modify
2311+# it under the terms of the GNU Affero General Public License as published
2312+# by the Free Software Foundation, either version 3 of the License, or
2313+# (at your option) any later version.
2314+#
2315+# This program is distributed in the hope that it will be useful,
2316+# but WITHOUT ANY WARRANTY; without even the implied warranty of
2317+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2318+# GNU Affero General Public License for more details.
2319+#
2320+# You should have received a copy of the GNU Affero General Public License
2321+# along with this program. If not, see <http://www.gnu.org/licenses/>.
2322+#
2323+##############################################################################
2324+
2325+import print_calendar_report
2326
2327=== added file 'hr_attendance_analysis/wizard/print_calendar_report.py'
2328--- hr_attendance_analysis/wizard/print_calendar_report.py 1970-01-01 00:00:00 +0000
2329+++ hr_attendance_analysis/wizard/print_calendar_report.py 2013-05-31 10:20:41 +0000
2330@@ -0,0 +1,366 @@
2331+# -*- coding: utf-8 -*-
2332+##############################################################################
2333+#
2334+# Copyright (C) 2011 Domsense srl (<http://www.domsense.com>)
2335+# Copyright (C) 2011-2013 Agile Business Group sagl
2336+# (<http://www.agilebg.com>)
2337+#
2338+# This program is free software: you can redistribute it and/or modify
2339+# it under the terms of the GNU Affero General Public License as published
2340+# by the Free Software Foundation, either version 3 of the License, or
2341+# (at your option) any later version.
2342+#
2343+# This program is distributed in the hope that it will be useful,
2344+# but WITHOUT ANY WARRANTY; without even the implied warranty of
2345+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2346+# GNU Affero General Public License for more details.
2347+#
2348+# You should have received a copy of the GNU Affero General Public License
2349+# along with this program. If not, see <http://www.gnu.org/licenses/>.
2350+#
2351+##############################################################################
2352+
2353+from openerp.osv import fields, orm
2354+from openerp.tools.translate import _
2355+from datetime import *
2356+import math
2357+import calendar
2358+
2359+class wizard_calendar_report(orm.TransientModel):
2360+
2361+ _columns = {
2362+ 'month': fields.selection([
2363+ ('1', 'January'),
2364+ ('2', 'February'),
2365+ ('3', 'March'),
2366+ ('4', 'April'),
2367+ ('5', 'May'),
2368+ ('6', 'June'),
2369+ ('7', 'July'),
2370+ ('8', 'August'),
2371+ ('9', 'September'),
2372+ ('10', 'October'),
2373+ ('11', 'November'),
2374+ ('12', 'December'),
2375+ ], 'Month'),
2376+ 'year': fields.integer('Year'),
2377+ 'from_date': fields.date('From date', required=True),
2378+ 'to_date': fields.date('To date', required=True),
2379+ 'employee_ids': fields.many2many('hr.employee', 'calendar_report_employee_rel', 'employee_id', 'report_id',
2380+ required=True),
2381+ }
2382+
2383+ _defaults = {
2384+ 'month': lambda * a: str(datetime.now().month),
2385+ 'year': lambda * a: datetime.now().year,
2386+ 'from_date': lambda * a: (datetime.now()-timedelta(30)).strftime('%Y-%m-%d'),
2387+ 'to_date': lambda * a: datetime.now().strftime('%Y-%m-%d'),
2388+ 'employee_ids': lambda s, cr, uid, c: s.pool.get('hr.employee').search(cr, uid, []),
2389+ }
2390+
2391+ _name = "attendance_analysis.wizard.calendar_report"
2392+
2393+ def on_change_month(self, cr, uid, id, str_month, year):
2394+ res = {}
2395+ if year and str_month:
2396+ month = int(str_month)
2397+ day = calendar.monthrange(year, month)[1]
2398+ to_date = date(year, month, day).strftime('%Y-%m-%d')
2399+ res= {'value':{'to_date': to_date, 'from_date': date(year, month, 1).strftime('%Y-%m-%d')}}
2400+ return res
2401+
2402+
2403+ def print_calendar(self, cr, uid, ids, context=None):
2404+ if context is None:
2405+ context = {}
2406+ attendance_pool = self.pool.get('hr.attendance')
2407+ contract_pool = self.pool.get('hr.contract')
2408+ holidays_pool = self.pool.get('hr.holidays')
2409+
2410+ days_by_employee = {}
2411+
2412+ form = self.read(cr, uid, ids)[0]
2413+ from_date = datetime.strptime(form['from_date'], '%Y-%m-%d')
2414+ to_date = datetime.strptime(form['to_date'], '%Y-%m-%d')
2415+ if from_date > to_date:
2416+ raise osv.except_osv(_('Error'), _('From date must be < to date'))
2417+ employee_ids=form['employee_ids']
2418+ delta = to_date - from_date
2419+ max_number_of_attendances_per_day = 0
2420+
2421+ for employee_id in employee_ids:
2422+ employee_id = str(employee_id)
2423+ days_by_employee[employee_id] = {}
2424+ day_count=0
2425+ while day_count <= delta.days:
2426+ current_date = from_date + timedelta(day_count)
2427+ current_total_attendances = 0.0
2428+ current_total_overtime = 0.0
2429+ current_total_leaves = 0.0
2430+ current_total_due = 24.0 # If contract is not specified: working days = 24/7
2431+ current_total_inside_calendar = 0.0
2432+ str_current_date = current_date.strftime('%Y-%m-%d')
2433+ days_by_employee[employee_id][str_current_date] = {
2434+ 'signin_1': '',
2435+ 'signout_1': '',
2436+ 'signin_2': '',
2437+ 'signout_2': '',
2438+ 'signin_3': '',
2439+ 'signout_3': '',
2440+ 'signin_4': '',
2441+ 'signout_4': '',
2442+ }
2443+ current_date_beginning = datetime.combine(current_date, time())
2444+ str_current_date_beginning = current_date_beginning.strftime(
2445+ '%Y-%m-%d %H:%M:%S')
2446+ current_date_end = datetime.combine(current_date, time())+ timedelta(1)
2447+ str_current_date_end = current_date_end.strftime('%Y-%m-%d %H:%M:%S')
2448+
2449+ attendance_ids = attendance_pool.search(cr, uid, [
2450+ ('employee_id','=',int(employee_id)),
2451+ ('name','>=',str_current_date_beginning),
2452+ ('name','<=',str_current_date_end),
2453+ ('action','=','sign_in'),
2454+ ])
2455+ # computing attendance totals
2456+ for attendance in attendance_pool.browse(cr, uid, attendance_ids):
2457+ current_total_attendances = attendance_pool.time_sum(
2458+ current_total_attendances,attendance.duration)
2459+ current_total_overtime = attendance_pool.time_sum(current_total_overtime,
2460+ attendance.outside_calendar_duration)
2461+ current_total_inside_calendar = attendance_pool.time_sum(
2462+ current_total_inside_calendar,
2463+ attendance.inside_calendar_duration)
2464+
2465+ #printing up to 4 attendances
2466+ if len(attendance_ids) < 5:
2467+ count = 1
2468+ for attendance in sorted(attendance_pool.browse(cr, uid, attendance_ids),
2469+ key=lambda x: x['name']):
2470+ days_by_employee[employee_id][str_current_date][
2471+ 'signin_'+str(count)] = attendance.name[11:16]
2472+ days_by_employee[employee_id][str_current_date][
2473+ 'signout_'+str(count)] = attendance.end_datetime[11:16]
2474+ count += 1
2475+ if len(attendance_ids) > max_number_of_attendances_per_day:
2476+ max_number_of_attendances_per_day = len(attendance_ids)
2477+
2478+ days_by_employee[employee_id][str_current_date][
2479+ 'attendances'
2480+ ] = current_total_attendances
2481+ days_by_employee[employee_id][str_current_date][
2482+ 'overtime'
2483+ ] = current_total_overtime
2484+
2485+ active_contract_ids = attendance_pool.get_active_contracts(
2486+ cr, uid, int(employee_id), date=str_current_date)
2487+ # computing due total
2488+ if active_contract_ids:
2489+ contract = contract_pool.browse(cr, uid, active_contract_ids[0])
2490+ if contract.working_hours and contract.working_hours.attendance_ids:
2491+ current_total_due = 0.0
2492+ for calendar_attendance in contract.working_hours.attendance_ids:
2493+ if ((
2494+ not calendar_attendance.dayofweek
2495+ or int(calendar_attendance.dayofweek) == current_date.weekday()
2496+ )
2497+ and (
2498+ not calendar_attendance.date_from or
2499+ datetime.strptime(calendar_attendance.date_from,'%Y-%m-%d')
2500+ <= current_date
2501+ )):
2502+ calendar_attendance_duration = attendance_pool.time_difference(
2503+ calendar_attendance.hour_from, calendar_attendance.hour_to)
2504+ if calendar_attendance_duration < 0:
2505+ raise osv.except_osv(_('Error'),
2506+ _("%s: 'Work to' is < 'Work from'")
2507+ % calendar_attendance.name)
2508+ current_total_due = attendance_pool.time_sum(current_total_due,
2509+ calendar_attendance_duration)
2510+
2511+ days_by_employee[employee_id][str_current_date]['due'] = current_total_due
2512+
2513+ # computing leaves
2514+ holidays_ids = holidays_pool.search(cr, uid, [
2515+ '&',
2516+ '&',
2517+ '|',
2518+ # leave begins today
2519+ '&',
2520+ ('date_from', '>=', str_current_date_beginning),
2521+ ('date_from', '<=', str_current_date_end),
2522+ '|',
2523+ # leave ends today
2524+ '&',
2525+ ('date_to', '<=', str_current_date_end),
2526+ ('date_to', '>=', str_current_date_beginning),
2527+ # leave is ongoing
2528+ '&',
2529+ ('date_from', '<', str_current_date_beginning),
2530+ ('date_to', '>', str_current_date_end),
2531+ ('state', '=', 'validate'),
2532+ ('employee_id', '=', int(employee_id)),
2533+ ])
2534+ for holiday in holidays_pool.browse(cr, uid, holidays_ids):
2535+ date_from = datetime.strptime(holiday.date_from, '%Y-%m-%d %H:%M:%S')
2536+ date_to = datetime.strptime(holiday.date_to, '%Y-%m-%d %H:%M:%S')
2537+ # if beginned before today
2538+ if date_from < current_date_beginning:
2539+ date_from = current_date_beginning
2540+ # if ends after today
2541+ if date_to > current_date_end:
2542+ date_to = current_date_end
2543+ current_total_leaves = attendance_pool.time_sum(
2544+ current_total_leaves,
2545+ (date_to - date_from).total_seconds() / 60.0 / 60.0)
2546+
2547+ days_by_employee[employee_id][str_current_date]['leaves'] = current_total_leaves
2548+ if current_total_leaves > days_by_employee[employee_id][
2549+ str_current_date]['due']:
2550+ days_by_employee[employee_id][str_current_date][
2551+ 'leaves'
2552+ ] = days_by_employee[employee_id][str_current_date]['due']
2553+ due_minus_leaves = attendance_pool.time_difference(
2554+ current_total_leaves, current_total_due)
2555+ if due_minus_leaves < current_total_inside_calendar:
2556+ days_by_employee[employee_id][str_current_date]['negative'] = 0.0
2557+ else:
2558+ days_by_employee[employee_id][str_current_date][
2559+ 'negative'
2560+ ] = attendance_pool.time_difference(
2561+ current_total_inside_calendar, due_minus_leaves)
2562+
2563+ if active_contract_ids:
2564+ contract = contract_pool.browse(cr, uid, active_contract_ids[0])
2565+ if contract.working_hours and contract.working_hours.leave_rounding:
2566+ float_rounding = float(contract.working_hours.leave_rounding)
2567+ days_by_employee[employee_id][str_current_date][
2568+ 'negative'
2569+ ] = math.floor(
2570+ days_by_employee[employee_id][str_current_date]['negative'] *
2571+ float_rounding
2572+ ) / float_rounding
2573+
2574+ day_count += 1
2575+
2576+ totals_by_employee = {}
2577+ for employee_id in days_by_employee:
2578+ totals_by_employee[employee_id] = {
2579+ 'total_attendances': 0.0,
2580+ 'total_overtime': 0.0,
2581+ 'total_negative': 0.0,
2582+ 'total_leaves': 0.0,
2583+ 'total_due': 0.0,
2584+ 'total_types': {},
2585+ }
2586+
2587+ for str_date in days_by_employee[employee_id]:
2588+ totals_by_employee[employee_id]['total_attendances'] = attendance_pool.time_sum(
2589+ totals_by_employee[employee_id]['total_attendances'],
2590+ days_by_employee[employee_id][str_date]['attendances'])
2591+ totals_by_employee[employee_id]['total_overtime'] = attendance_pool.time_sum(
2592+ totals_by_employee[employee_id]['total_overtime'],
2593+ days_by_employee[employee_id][str_date]['overtime'])
2594+ totals_by_employee[employee_id]['total_negative'] = attendance_pool.time_sum(
2595+ totals_by_employee[employee_id]['total_negative'],
2596+ days_by_employee[employee_id][str_date]['negative'])
2597+ totals_by_employee[employee_id]['total_leaves'] = attendance_pool.time_sum(
2598+ totals_by_employee[employee_id]['total_leaves'],
2599+ days_by_employee[employee_id][str_date]['leaves'])
2600+ totals_by_employee[employee_id]['total_due'] = attendance_pool.time_sum(
2601+ totals_by_employee[employee_id]['total_due'],
2602+ days_by_employee[employee_id][str_date]['due'])
2603+
2604+ # computing overtime types
2605+ active_contract_ids = attendance_pool.get_active_contracts(
2606+ cr, uid, int(employee_id), date=str_date)
2607+ if active_contract_ids:
2608+ contract = contract_pool.browse(cr, uid, active_contract_ids[0])
2609+ if contract.working_hours and contract.working_hours.overtime_type_ids:
2610+ sorted_types = sorted(
2611+ contract.working_hours.overtime_type_ids,
2612+ key=lambda k: k.sequence)
2613+ current_overtime = days_by_employee[employee_id][
2614+ str_date]['overtime']
2615+ for overtime_type in sorted_types:
2616+ if not totals_by_employee[employee_id]['total_types'].get(
2617+ overtime_type.name, False):
2618+ totals_by_employee[employee_id]['total_types'][
2619+ overtime_type.name] = 0.0
2620+ if current_overtime:
2621+ if current_overtime <= overtime_type.limit or not overtime_type.limit:
2622+ totals_by_employee[employee_id]['total_types'][
2623+ overtime_type.name] = attendance_pool.time_sum(
2624+ totals_by_employee[employee_id]
2625+ ['total_types'][overtime_type.name],
2626+ current_overtime)
2627+ current_overtime = 0.0
2628+ else:
2629+ totals_by_employee[employee_id]['total_types'][
2630+ overtime_type.name] = attendance_pool.time_sum(
2631+ totals_by_employee[employee_id]['total_types']
2632+ [overtime_type.name], overtime_type.limit)
2633+ current_overtime = attendance_pool.time_difference(overtime_type.limit,
2634+ current_overtime)
2635+
2636+ days_by_employee[employee_id][str_date][
2637+ 'attendances'
2638+ ] = attendance_pool.float_time_convert(
2639+ days_by_employee[employee_id][str_date]['attendances'])
2640+ days_by_employee[employee_id][str_date][
2641+ 'overtime'
2642+ ] = attendance_pool.float_time_convert(
2643+ days_by_employee[employee_id][str_date]['overtime'])
2644+ days_by_employee[employee_id][str_date][
2645+ 'negative'
2646+ ] = attendance_pool.float_time_convert(
2647+ days_by_employee[employee_id][str_date]['negative'])
2648+ days_by_employee[employee_id][str_date][
2649+ 'leaves'
2650+ ] = attendance_pool.float_time_convert(
2651+ days_by_employee[employee_id][str_date]['leaves'])
2652+ days_by_employee[employee_id][str_date][
2653+ 'due'
2654+ ] = attendance_pool.float_time_convert(
2655+ days_by_employee[employee_id][str_date]['due'])
2656+
2657+ totals_by_employee[employee_id][
2658+ 'total_attendances'
2659+ ] = attendance_pool.float_time_convert(
2660+ totals_by_employee[employee_id]['total_attendances'])
2661+ totals_by_employee[employee_id][
2662+ 'total_overtime'
2663+ ] = attendance_pool.float_time_convert(
2664+ totals_by_employee[employee_id]['total_overtime'])
2665+ totals_by_employee[employee_id][
2666+ 'total_negative'
2667+ ] = attendance_pool.float_time_convert(
2668+ totals_by_employee[employee_id]['total_negative'])
2669+ totals_by_employee[employee_id][
2670+ 'total_leaves'
2671+ ] = attendance_pool.float_time_convert(
2672+ totals_by_employee[employee_id]['total_leaves'])
2673+ totals_by_employee[employee_id][
2674+ 'total_due'
2675+ ] = attendance_pool.float_time_convert(
2676+ totals_by_employee[employee_id]['total_due'])
2677+
2678+ for overtime_type in totals_by_employee[employee_id]['total_types']:
2679+ totals_by_employee[employee_id]['total_types'][
2680+ overtime_type
2681+ ] = attendance_pool.float_time_convert(
2682+ totals_by_employee[employee_id]['total_types'][overtime_type])
2683+
2684+ datas = {'ids': employee_ids}
2685+ datas['model'] = 'hr.employee'
2686+ datas['form'] = {}
2687+ datas['form']['days_by_employee'] = days_by_employee
2688+ datas['form']['totals_by_employee'] = totals_by_employee
2689+ datas['form']['max_number_of_attendances_per_day'] = max_number_of_attendances_per_day
2690+
2691+ return {
2692+ 'type': 'ir.actions.report.xml',
2693+ 'report_name': 'attendance_analysis.calendar_report',
2694+ 'datas': datas,
2695+ }
2696+
2697
2698=== added file 'hr_attendance_analysis/wizard/print_calendar_report.xml'
2699--- hr_attendance_analysis/wizard/print_calendar_report.xml 1970-01-01 00:00:00 +0000
2700+++ hr_attendance_analysis/wizard/print_calendar_report.xml 2013-05-31 10:20:41 +0000
2701@@ -0,0 +1,38 @@
2702+<?xml version="1.0" encoding="utf-8"?>
2703+<openerp>
2704+ <data>
2705+
2706+ <record id="wizard_calendar_report" model="ir.ui.view">
2707+ <field name="name">Attendances Analysis Calendar</field>
2708+ <field name="model">attendance_analysis.wizard.calendar_report</field>
2709+ <field name="arch" type="xml">
2710+ <form string="Attendances Analysis Calendar">
2711+ <group colspan="4" height="400">
2712+ <field name="month" on_change="on_change_month(month, year)"/>
2713+ <field name="year" on_change="on_change_month(month, year)"/>
2714+ <field name="from_date"/>
2715+ <field name="to_date"/>
2716+ <separator colspan="4" string="Employees"/>
2717+ <field name="employee_ids" colspan="4" nolabel="1"/>
2718+ <separator colspan="4"/>
2719+ <button icon="gtk-cancel" special="cancel" string="Cancel" colspan="2"/>
2720+ <button icon="gtk-ok" name="print_calendar" string="Print" type="object" colspan="2"/>
2721+ </group>
2722+ </form>
2723+ </field>
2724+ </record>
2725+
2726+ <record id="action_wizard_calendar_report" model="ir.actions.act_window">
2727+ <field name="name">Attendances Analysis Calendar</field>
2728+ <field name="res_model">attendance_analysis.wizard.calendar_report</field>
2729+ <field name="view_type">form</field>
2730+ <field name="view_mode">form</field>
2731+ <field name="view_id" ref="wizard_calendar_report"/>
2732+ <field name="target">new</field>
2733+ </record>
2734+
2735+ <menuitem action="action_wizard_calendar_report"
2736+ id="menu_action_wizard_calendar_report"
2737+ parent="hr.menu_hr_reporting" />
2738+ </data>
2739+</openerp>

Subscribers

People subscribed via source and target branches