Merge lp:~elbati/hr-timesheet/adding_hr_attendance_analysis_7 into lp:~hr-core-editors/hr-timesheet/7.0
- adding_hr_attendance_analysis_7
- Merge into 7.0
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 |
Related bugs: |
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 |
Commit message
Description of the change
hr_attendance_
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
- 48. By Lorenzo Battistini
-
[FIX] __openerp__
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote : | # |
- 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
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.
<http://
>
> l.146 from openerp.
Done
>
> l.162, what does means this 0.01666667 ?
> - the unit worth be precised in the `working_
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(
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
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.
> <http://
> 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.
(td.
Beware to the division, you should enable true division with:
from __future__ import division
>
> >
> > l.146 from openerp.
>
> Done
>
> >
> > l.162, what does means this 0.01666667 ?
> > - the unit worth be precised in the `working_
>
> 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 = {
}
Thanks for your changes!
I put 'Needs Information' for your and community thoughts about the python compatibility.
- 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
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.
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_
> }
>
>
>
Done
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote : | # |
Thanks for your changes!
Looks good to me!
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
* print_calendar
- 60. By Lorenzo Battistini
-
[fix] description
- 61. By Lorenzo Battistini
-
[ref] line length
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
Maxime Chambreuil (http://www.savoirfairelinux.com) (max3903) : | # |
Preview Diff
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 <span class="page"/></td> |
2065 | + <td style="text-align:left;font-size:10;width:30px"> of <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> |
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 ? time_precision` field
- the unit worth be precised in the `working_
- 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