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