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