Merge lp:~camptocamp/hr-timesheet/7.0-hr_timesheet_reminder-migr into lp:~hr-core-editors/hr-timesheet/7.0

Proposed by Guewen Baconnier @ Camptocamp
Status: Merged
Merged at revision: 40
Proposed branch: lp:~camptocamp/hr-timesheet/7.0-hr_timesheet_reminder-migr
Merge into: lp:~hr-core-editors/hr-timesheet/7.0
Diff against target: 1734 lines (+626/-669)
14 files modified
hr_timesheet_reminder/__init__.py (+15/-26)
hr_timesheet_reminder/__openerp__.py (+41/-43)
hr_timesheet_reminder/company.py (+50/-57)
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)
To merge this branch: bzr merge lp:~camptocamp/hr-timesheet/7.0-hr_timesheet_reminder-migr
Reviewer Review Type Date Requested Status
Alexandre Fayolle - camptocamp code review, no test Approve
Review via email: mp+139655@code.launchpad.net

Commit message

[MIGR] migration of hr_timesheet_reminder to OpenERP v7

Description of the change

Migration to OpenERP version 7 of the addon hr_timesheet_reminder.

 * change of license from GPLv2 to AGPLv3
 * replace openerp.tools.email_send by 'mail.mail'
 * the dates were not displayed on the report
 * migrate the views using the new layout
 * formatting and styling
 * fix bug: lp:1089390
 * fix a small issue on the nextcall of the cron which was initialized not 'tomorrow' but approximately the next day of the server date

To post a comment you must log in.
47. By Guewen Baconnier @ Camptocamp <email address hidden>

[MRG] from lp:hr-timesheet/7.0

48. By Guewen Baconnier @ Camptocamp <email address hidden>

[MIGR] set installable to True

49. By Guewen Baconnier @ Camptocamp <email address hidden>

[FIX] license in timesheet_status.rml, formatting

Revision history for this message
Alexandre Fayolle - camptocamp (alexandre-fayolle-c2c) wrote :

line 263: if status in ['Missing', 'Draft'] and employee.receive_timesheet_alerts
The second part of the test should be moved out to the outer loop (just after line 253) or even better to the search domain (line 243) : that way we don't make further queries for employees who don't recevie timesheet alerts (or am I missing something?)

653 + def _cron_nextcall():
654 + now = datetime.today() + timedelta(days=1)
655 + return time.strftime(
656 + DEFAULT_SERVER_DATETIME_FORMAT,
657 + now.timetuple())

1 -> I'd rename 'now' to 'tomorrow' or 'when'
2. why not use now.strftime(DEFAULT_SERVER_DATETIME_FORMAT) (or tomorrow.strftime...) instead of time.strftime(...) ?

There are probably a number of 'import time' which can be removed (pylint will tell you about unused imports)

607 + 'body_html': '<pre>%s</pre>' % message_data.message,

I expect mail clients to be fairly tolerant in what they accept, but this makes me uncomfortable.

Have you tested what happens if the user has typed in:

* html (e.g. "fill your timesheet <b>now!</b>")
* a raw text message with HTML special chars inside (e.g: "I'm very disapointed you did not fill your timesheet <:-( I'll make sure your manager is notified & takes proper action.

Best chance would be to allow the edition of the body of the message with a rich text editor. Is there such widget available in the oerp7 client ?

803 -# Author: Arnaud WÃŒst

-> Mojibake! (but you fixed it)

1638 + 'date': time.strftime('%Y-%m-%d'),
Is there not a constant defining this format?

review: Needs Information (a few suggestions from code quick read)
50. By Guewen Baconnier @ Camptocamp <email address hidden>

[FIX] use a correct name for a local variable, use tomorrow.strftime instead of time.strftime, so get rid of 'import time'

51. By Guewen Baconnier @ Camptocamp <email address hidden>

[FIX] use fields.date.today() instead of time.strftime() for a default date

52. By Guewen Baconnier @ Camptocamp <email address hidden>

[IMP] use a html field instead of a text field for the message

53. By Guewen Baconnier @ Camptocamp <email address hidden>

[FIX] skip earlier the employees who do not receive the timesheet alerts, avoid unecessary computations/queries

54. By Guewen Baconnier @ Camptocamp <email address hidden>

[FIX] remove unused import

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

You are right on all the points. I fixed them in my proposal.

Some comments:

 * There is now a fields.html. I use it now for the message. As a bonus, we gain a rich editing of the reminder message (yippee, 'Please take time to complete and confirm your timesheet' in *bold*).

 * Learned the word Mojibake today :-)

 * there is a constant for '%Y-%m-%d' but there is even better for the default values of date and datetime:
   fields.date.today() and fields.datetime.now() (there is also fields.date.context_today() and fields.date.context_timestamp() converted to the client timezone)

Revision history for this message
Alexandre Fayolle - camptocamp (alexandre-fayolle-c2c) wrote :

Yay !

<off-topic>
Mojibake (pronounce modjibaké in fr_FR) is one of these useful words I enjoy sharing :-)

For other illustrated funny / rare french words, you may want to check out http://brouillaminiscribbles.tumblr.com/
</off-topic>

review: Approve (code review, no test)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'hr_timesheet_reminder/__init__.py'
--- hr_timesheet_reminder/__init__.py 2011-08-12 12:53:16 +0000
+++ hr_timesheet_reminder/__init__.py 2012-12-13 17:06:20 +0000
@@ -1,32 +1,21 @@
1# -*- coding: utf-8 -*-1# -*- coding: utf-8 -*-
2##############################################################################2##############################################################################
3#3#
4# Copyright (c) 2011 Camptocamp SA (http://www.camptocamp.com)4# Author: Arnaud Wüst (Camptocamp)
5# All Right Reserved5# Copyright 2011-2012 Camptocamp SA
6#6#
7# Author : Arnaud Wüst (Camptocamp)7# This program is free software: you can redistribute it and/or modify
8# Author : Guewen Baconnier (Camptocamp)8# it under the terms of the GNU Affero General Public License as
9#9# published by the Free Software Foundation, either version 3 of the
10# WARNING: This program as such is intended to be used by professional10# License, or (at your option) any later version.
11# programmers who take the whole responsability of assessing all potential11#
12# consequences resulting from its eventual inadequacies and bugs12# This program is distributed in the hope that it will be useful,
13# End users who are looking for a ready-to-use solution with commercial13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# garantees and support are strongly adviced to contract a Free Software14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# Service Company15# GNU Affero General Public License for more details.
16#16#
17# This program is Free Software; you can redistribute it and/or17# You should have received a copy of the GNU Affero General Public License
18# modify it under the terms of the GNU General Public License18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19# as published by the Free Software Foundation; either version 2
20# of the License, or (at your option) any later version.
21#
22# This program is distributed in the hope that it will be useful,
23# but WITHOUT ANY WARRANTY; without even the implied warranty of
24# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25# GNU General Public License for more details.
26#
27# You should have received a copy of the GNU General Public License
28# along with this program; if not, write to the Free Software
29# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30#19#
31##############################################################################20##############################################################################
3221
3322
=== modified file 'hr_timesheet_reminder/__openerp__.py'
--- hr_timesheet_reminder/__openerp__.py 2012-12-13 12:20:12 +0000
+++ hr_timesheet_reminder/__openerp__.py 2012-12-13 17:06:20 +0000
@@ -1,54 +1,52 @@
1# -*- coding: utf-8 -*-1# -*- coding: utf-8 -*-
2##############################################################################2##############################################################################
3#3#
4# Copyright (c) 2011 Camptocamp SA (http://www.camptocamp.com)4# Author: Arnaud Wüst (Camptocamp)
5# All Right Reserved5# Author: Nicolas Bessi (Camptocamp)
6#6# Author: Guewen Baconnier (Camptocamp) (port to v7)
7# Author : Arnaud Wüst (Camptocamp)7# Copyright 2011-2012 Camptocamp SA
8# Author : Nicolas Bessi (Camptocamp)8#
9# Author : Guewen Baconnier (Camptocamp)9# This program is free software: you can redistribute it and/or modify
10#10# it under the terms of the GNU Affero General Public License as
11# WARNING: This program as such is intended to be used by professional11# published by the Free Software Foundation, either version 3 of the
12# programmers who take the whole responsability of assessing all potential12# License, or (at your option) any later version.
13# consequences resulting from its eventual inadequacies and bugs13#
14# End users who are looking for a ready-to-use solution with commercial14# This program is distributed in the hope that it will be useful,
15# garantees and support are strongly adviced to contract a Free Software15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# Service Company16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17#17# GNU Affero General Public License for more details.
18# This program is Free Software; you can redistribute it and/or18#
19# modify it under the terms of the GNU General Public License19# You should have received a copy of the GNU Affero General Public License
20# as published by the Free Software Foundation; either version 220# along with this program. If not, see <http://www.gnu.org/licenses/>.
21# of the License, or (at your option) any later version.
22#
23# This program is distributed in the hope that it will be useful,
24# but WITHOUT ANY WARRANTY; without even the implied warranty of
25# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26# GNU General Public License for more details.
27#
28# You should have received a copy of the GNU General Public License
29# along with this program; if not, write to the Free Software
30# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
31#21#
32##############################################################################22##############################################################################
3323
34
35{24{
36 "name" : "Timesheet Reminder",25 "name": "Timesheet Reminder",
37 "version" : "2.0",26 "version": "2.0",
38 "author" : "Camptocamp",27 "author": "Camptocamp",
39 "category" : "",28 "license": 'AGPL-3',
40 "website" : "http://www.camptocamp.com",29 "category": "",
30 "website": "http://www.camptocamp.com",
41 "description": """31 "description": """
42Timesheet Reports Module:32Timesheet Reports Module
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========================
44 * Per employee, you can choose to send the reminder or not.34
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
4636 / Timesheet Reminder`.
47This module replaces the modules c2c_timesheet_reports in TinyERP 4 and OpenERP 5.37 It allows to send automatic emails to those who did
38 not complete their timesheet in the last 5 weeks.
39 * Per employee, you can choose to send the reminder or not.
40 * Add a report in `Human Resources / Reporting / Timesheet
41 / Timesheet Status` which displays the state of the last
42 5 timesheets for all users per company.
43
44This module replaces the modules c2c_timesheet_reports
45of TinyERP 4 and OpenERP 5.
48 """,46 """,
49 "depends" : ["hr_timesheet_sheet"],47 "depends": ["hr_timesheet_sheet"],
50 "init_xml" : [],48 "init_xml": [],
51 "update_xml" : [49 "update_xml": [
52 'security/ir.model.access.csv',50 'security/ir.model.access.csv',
53 'wizard/reminder_config_view.xml',51 'wizard/reminder_config_view.xml',
54 'wizard/reminder_status_view.xml',52 'wizard/reminder_status_view.xml',
@@ -56,5 +54,5 @@
56 'timesheet_report.xml',54 'timesheet_report.xml',
57 ],55 ],
58 "active": False,56 "active": False,
59 'installable': False57 'installable': True
60}58}
6159
=== modified file 'hr_timesheet_reminder/company.py'
--- hr_timesheet_reminder/company.py 2011-09-01 13:44:19 +0000
+++ hr_timesheet_reminder/company.py 2012-12-13 17:06:20 +0000
@@ -1,57 +1,50 @@
1# -*- coding: utf-8 -*-1# -*- coding: utf-8 -*-
2##############################################################################2##############################################################################
3#3#
4# Copyright (c) 2011 Camptocamp SA (http://www.camptocamp.com)4# Author: Arnaud Wüst (Camptocamp)
5# All Right Reserved5# Author: Guewen Baconnier (Camptocamp)
6#6# Copyright 2011-2012 Camptocamp SA
7# Author : Arnaud Wüst (Camptocamp)7#
8# Author : Guewen Baconnier (Camptocamp)8# This program is free software: you can redistribute it and/or modify
9#9# it under the terms of the GNU Affero General Public License as
10# WARNING: This program as such is intended to be used by professional10# published by the Free Software Foundation, either version 3 of the
11# programmers who take the whole responsability of assessing all potential11# License, or (at your option) any later version.
12# consequences resulting from its eventual inadequacies and bugs12#
13# End users who are looking for a ready-to-use solution with commercial13# This program is distributed in the hope that it will be useful,
14# garantees and support are strongly adviced to contract a Free Software14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# Service Company15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16#16# GNU Affero General Public License for more details.
17# This program is Free Software; you can redistribute it and/or17#
18# modify it under the terms of the GNU General Public License18# You should have received a copy of the GNU Affero General Public License
19# as published by the Free Software Foundation; either version 219# along with this program. If not, see <http://www.gnu.org/licenses/>.
20# of the License, or (at your option) any later version.
21#
22# This program is distributed in the hope that it will be useful,
23# but WITHOUT ANY WARRANTY; without even the implied warranty of
24# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25# GNU General Public License for more details.
26#
27# You should have received a copy of the GNU General Public License
28# along with this program; if not, write to the Free Software
29# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30#20#
31##############################################################################21##############################################################################
3222
3323from datetime import datetime
34from datetime import date, datetime24from dateutil.relativedelta import relativedelta, MO, SU
35from dateutil.relativedelta import *25from openerp.osv import osv, orm
36from osv import fields, osv26from openerp.tools.translate import _
37from tools.translate import _27
3828
3929class res_company(orm.Model):
40class res_company(osv.osv):
41 _inherit = 'res.company'30 _inherit = 'res.company'
4231
43 def get_reminder_recipients(self, cr, uid, ids, context=None):32 def get_reminder_recipients(self, cr, uid, ids, context=None):
44 """Return the list of users that must receive the email"""33 """Return the list of users that must receive the email"""
45 res = {}.fromkeys(ids, [])34 res = dict((company_id, []) for company_id in ids)
35
46 employee_obj = self.pool.get('hr.employee')36 employee_obj = self.pool.get('hr.employee')
4737
48 companies = self.browse(cr, uid, ids, context=context)38 for company in self.browse(cr, uid, ids, context=context):
4939 employee_ids = employee_obj.search(
50 for company in companies:40 cr, uid,
51 employee_ids = employee_obj.search(cr, uid,41 [('company_id', '=', company.id),
52 [('company_id', '=', company.id),42 ('receive_timesheet_alerts', '=', True)],
53 ('active', '=', True)],43 context=context)
54 context=context)44
45 if not employee_ids:
46 continue
47
55 employees = employee_obj.browse(cr, uid, employee_ids, context=context)48 employees = employee_obj.browse(cr, uid, employee_ids, context=context)
5649
57 #periods50 #periods
@@ -62,24 +55,26 @@
62 # for each employee55 # for each employee
63 for employee in employees:56 for employee in employees:
64 # is timesheet for a period not confirmed ?57 # is timesheet for a period not confirmed ?
65 for p_index in range(len(periods)):58 for period in periods:
66 period = periods[p_index]
67 status = employee_obj.compute_timesheet_status(cr, uid, employee.id, period, context)59 status = employee_obj.compute_timesheet_status(cr, uid, employee.id, period, context)
6860
69 # if there is a missing sheet or a draft sheet61 # if there is a missing sheet or a draft sheet
70 # and the user can receive alerts62 # and the user can receive alerts
71 # then we must alert the user63 # then we must alert the user
72 if status in ['Missing', 'Draft'] and employee.receive_timesheet_alerts:64 if status in ['Missing', 'Draft']:
73 res[company.id].append(employee)65 res[company.id].append(employee)
74 break # no need to go further for this user, he is now added in the list, go to the next one66 # no need to go further for this user,
67 # he is now added in the list, go to the next one
68 break
75 return res69 return res
7670
77 def compute_timesheet_periods(self, cr, uid, company, date, periods_number=5, context=None):71 def compute_timesheet_periods(self, cr, uid, company, date, periods_number=5, context=None):
78 """ return the timeranges to display. This is the 5 last timesheets"""72 """ return the timeranges to display. This is the 5 last timesheets"""
79 periods = []73 periods = []
80 last_start_date, last_end_date = self.get_last_period_dates(cr, uid, company, date, context=context)74 last_start_date, last_end_date = self.get_last_period_dates(
75 cr, uid, company, date, context=context)
81 for cpt in range(periods_number):76 for cpt in range(periods_number):
82 #find the delta between last_XXX_date to XXX_date77 # find the delta between last_XXX_date to XXX_date
83 if company.timesheet_range == 'month':78 if company.timesheet_range == 'month':
84 delta = relativedelta(months=-cpt)79 delta = relativedelta(months=-cpt)
85 elif company.timesheet_range == 'week':80 elif company.timesheet_range == 'week':
@@ -87,7 +82,9 @@
87 elif company.timesheet_range == 'year':82 elif company.timesheet_range == 'year':
88 delta = relativedelta(years=-cpt)83 delta = relativedelta(years=-cpt)
89 else:84 else:
90 raise osv.except_osv(_('Error'), _('Unknow timesheet range: %s') % (company.timesheet_range,))85 raise osv.except_osv(
86 _('Error'),
87 _('Unknow timesheet range: %s') % company.timesheet_range)
9188
92 start_date = last_start_date + delta89 start_date = last_start_date + delta
93 end_date = last_end_date + delta90 end_date = last_end_date + delta
@@ -97,26 +94,22 @@
9794
98 def get_last_period_dates(self, cr, uid, company, date, context=None):95 def get_last_period_dates(self, cr, uid, company, date, context=None):
99 """ return the start date and end date of the last period to display """96 """ return the start date and end date of the last period to display """
100 97
101 # return the first day and last day of the month98 # return the first day and last day of the month
102 if company.timesheet_range == 'month':99 if company.timesheet_range == 'month':
103 start_date = date100 start_date = date
104 end_date = start_date + relativedelta(months = +1)101 end_date = start_date + relativedelta(months=+1)
105102
106 #return the first and last days of the week103 #return the first and last days of the week
107 elif company.timesheet_range == 'week':104 elif company.timesheet_range == 'week':
108 # get monday of current week105 # get monday of current week
109 start_date = date + relativedelta(weekday=MO(-1))106 start_date = date + relativedelta(weekday=MO(-1))
110 # get sunday of current week 107 # get sunday of current week
111 end_date = date + relativedelta(weekday=SU(+1))108 end_date = date + relativedelta(weekday=SU(+1))
112109
113 # return the first and last days of the year110 # return the first and last days of the year
114 else:111 else:
115 start_date = datetime(date.year, 1, 1) 112 start_date = datetime(date.year, 1, 1)
116 end_date = datetime(date.year, 12, 31)113 end_date = datetime(date.year, 12, 31)
117114
118
119 return start_date, end_date115 return start_date, end_date
120
121
122res_company()
123116
=== modified file 'hr_timesheet_reminder/hr_employee.py'
--- hr_timesheet_reminder/hr_employee.py 2011-09-01 13:44:19 +0000
+++ hr_timesheet_reminder/hr_employee.py 2012-12-13 17:06:20 +0000
@@ -1,47 +1,38 @@
1# -*- coding: utf-8 -*-1# -*- coding: utf-8 -*-
2##############################################################################2##############################################################################
3#3#
4# Copyright (c) 2011 Camptocamp SA (http://www.camptocamp.com)4# Author: Arnaud Wüst (Camptocamp)
5# All Right Reserved5# Author: Guewen Baconnier (Camptocamp) (port to v7)
6#6# Copyright 2011-2012 Camptocamp SA
7# Author : Arnaud Wüst (Camptocamp)7#
8# Author : Guewen Baconnier (Camptocamp)8# This program is free software: you can redistribute it and/or modify
9#9# it under the terms of the GNU Affero General Public License as
10# WARNING: This program as such is intended to be used by professional10# published by the Free Software Foundation, either version 3 of the
11# programmers who take the whole responsability of assessing all potential11# License, or (at your option) any later version.
12# consequences resulting from its eventual inadequacies and bugs12#
13# End users who are looking for a ready-to-use solution with commercial13# This program is distributed in the hope that it will be useful,
14# garantees and support are strongly adviced to contract a Free Software14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# Service Company15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16#16# GNU Affero General Public License for more details.
17# This program is Free Software; you can redistribute it and/or17#
18# modify it under the terms of the GNU General Public License18# You should have received a copy of the GNU Affero General Public License
19# as published by the Free Software Foundation; either version 219# along with this program. If not, see <http://www.gnu.org/licenses/>.
20# of the License, or (at your option) any later version.
21#
22# This program is distributed in the hope that it will be useful,
23# but WITHOUT ANY WARRANTY; without even the implied warranty of
24# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25# GNU General Public License for more details.
26#
27# You should have received a copy of the GNU General Public License
28# along with this program; if not, write to the Free Software
29# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30#20#
31##############################################################################21##############################################################################
32from datetime import *22
3323from openerp.osv import fields, orm
34from osv import fields, osv24from openerp.tools import DEFAULT_SERVER_DATE_FORMAT
3525
3626
37class hr_employee(osv.osv):27class hr_employee(orm.Model):
38 _inherit = 'hr.employee'28 _inherit = 'hr.employee'
29
39 _columns = {30 _columns = {
40 'receive_timesheet_alerts': fields.boolean('Receive Timesheet Alerts'),31 'receive_timesheet_alerts': fields.boolean('Receive Timesheet Alerts'),
41 }32 }
4233
43 _defaults = {34 _defaults = {
44 'receive_timesheet_alerts': lambda *a: True,35 'receive_timesheet_alerts': True,
45 }36 }
4637
47 def compute_timesheet_status(self, cr, uid, ids, period, context):38 def compute_timesheet_status(self, cr, uid, ids, period, context):
@@ -50,35 +41,33 @@
50 status = 'Error'41 status = 'Error'
5142
52 if isinstance(ids, list):43 if isinstance(ids, list):
44 assert len(ids) == 1, "Only 1 ID expected"
53 ids = ids[0]45 ids = ids[0]
5446
55 employee = self.browse(cr, uid, ids, context=context)47 employee = self.browse(cr, uid, ids, context=context)
5648
57 time_from = period[0]49 time_from, time_to = period
58 time_to = period[1]50
59 51 # does the timesheet exists in db and what is its status?
60 # does the timesheet exsists in db and what is its status?52 str_date_from = time_from.strftime(DEFAULT_SERVER_DATE_FORMAT)
61 timeformat = "%Y-%m-%d"53 str_date_to = time_to.strftime(DEFAULT_SERVER_DATE_FORMAT)
62 str_date_from = time_from.strftime(timeformat)54
63 str_date_to = time_to.strftime(timeformat)55 cr.execute(
6456 """SELECT state, date_from, date_to
65 cr.execute("""SELECT state, date_from, date_to57 FROM hr_timesheet_sheet_sheet
66 FROM hr_timesheet_sheet_sheet58 WHERE employee_id = %s
67 WHERE employee_id = %s59 AND date_from >= %s
68 AND date_from >= %s60 AND date_to <= %s""",
69 AND date_to <= %s""",
70 (employee.id, str_date_from, str_date_to))61 (employee.id, str_date_from, str_date_to))
71 sheets = cr.dictfetchall()62 sheets = cr.dictfetchall()
7263
73 #the timesheet does not exists in db64 # the timesheet does not exists in db
74 if not sheets:65 if not sheets:
75 status = 'Missing'66 status = 'Missing'
7667
77 if len(sheets) > 0:68 else:
78 status = 'Confirmed'69 status = 'Confirmed'
79 for s in sheets:70 for sheet in sheets:
80 if s['state'] == 'draft':71 if sheet['state'] == 'draft':
81 status = 'Draft'72 status = 'Draft'
82 return status73 return status
83
84hr_employee()
8574
=== modified file 'hr_timesheet_reminder/hr_employee_view.xml'
--- hr_timesheet_reminder/hr_employee_view.xml 2011-08-12 12:53:16 +0000
+++ hr_timesheet_reminder/hr_employee_view.xml 2012-12-13 17:06:20 +0000
@@ -5,7 +5,6 @@
5 <field name="name">hr.timesheet.employee.rmnd_form</field>5 <field name="name">hr.timesheet.employee.rmnd_form</field>
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"/>
7 <field name="model">hr.employee</field>7 <field name="model">hr.employee</field>
8 <field name="type">form</field>
9 <field name="arch" type="xml">8 <field name="arch" type="xml">
10 <field name="journal_id" widget="selection" position="after">9 <field name="journal_id" widget="selection" position="after">
11 <field name="receive_timesheet_alerts"/>10 <field name="receive_timesheet_alerts"/>
1211
=== modified file 'hr_timesheet_reminder/reminder.py'
--- hr_timesheet_reminder/reminder.py 2011-09-01 13:44:19 +0000
+++ hr_timesheet_reminder/reminder.py 2012-12-13 17:06:20 +0000
@@ -1,157 +1,170 @@
1# -*- coding: utf-8 -*-1# -*- coding: utf-8 -*-
2##############################################################################2##############################################################################
3#3#
4# Copyright (c) 2011 Camptocamp SA (http://www.camptocamp.com)4# Author: Arnaud Wüst (Camptocamp)
5# All Right Reserved5# Author: Guewen Baconnier (Camptocamp) (port to v7)
6#6# Copyright 2011-2012 Camptocamp SA
7# Author : Arnaud Wüst (Camptocamp)7#
8# Author : Guewen Baconnier (Camptocamp)8# This program is free software: you can redistribute it and/or modify
9#9# it under the terms of the GNU Affero General Public License as
10# WARNING: This program as such is intended to be used by professional10# published by the Free Software Foundation, either version 3 of the
11# programmers who take the whole responsability of assessing all potential11# License, or (at your option) any later version.
12# consequences resulting from its eventual inadequacies and bugs12#
13# End users who are looking for a ready-to-use solution with commercial13# This program is distributed in the hope that it will be useful,
14# garantees and support are strongly adviced to contract a Free Software14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# Service Company15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16#16# GNU Affero General Public License for more details.
17# This program is Free Software; you can redistribute it and/or17#
18# modify it under the terms of the GNU General Public License18# You should have received a copy of the GNU Affero General Public License
19# as published by the Free Software Foundation; either version 219# along with this program. If not, see <http://www.gnu.org/licenses/>.
20# of the License, or (at your option) any later version.
21#
22# This program is distributed in the hope that it will be useful,
23# but WITHOUT ANY WARRANTY; without even the implied warranty of
24# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25# GNU General Public License for more details.
26#
27# You should have received a copy of the GNU General Public License
28# along with this program; if not, write to the Free Software
29# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30#20#
31##############################################################################21##############################################################################
3222
33import tools
34import time
35
36from datetime import datetime, timedelta23from datetime import datetime, timedelta
37from osv import fields, osv24from openerp.osv import fields, orm
38from tools.translate import _25from openerp.tools.translate import _
3926from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT
40class reminder(osv.osv):27
28
29class reminder(orm.Model):
41 _name = "hr.timesheet.reminder"30 _name = "hr.timesheet.reminder"
42 _description = "Handle the scheduling of timesheet reminders"31 _description = "Handle the scheduling of timesheet reminders"
4332
44 _columns = {33 _columns = {
45 'reply_to': fields.char('Reply To', size=100),34 'reply_to': fields.char('Reply To'),
46 'message': fields.text('Message'),35 'message': fields.html('Message'),
47 'subject': fields.char('Subject', size=200),36 'subject': fields.char('Subject'),
48 }37 }
4938
50 #default cron (the one created if missing)39 # default cron (the one created if missing)
51 cron = {'active': False,40 cron = {'active': False,
52 'priority': 1,41 'priority': 1,
53 'interval_number': 1,42 'interval_number': 1,
54 'interval_type': 'weeks',43 'interval_type': 'weeks',
55 'nextcall': time.strftime("%Y-%m-%d %H:%M:%S",44 'nextcall': False, # to set on the creation of the cron
56 (datetime.today()
57 + timedelta(days=1)).timetuple()), # tomorrow same time
58 'numbercall': -1,45 'numbercall': -1,
59 'doall': True,46 'doall': False,
60 'model': 'hr.timesheet.reminder',47 'model': 'hr.timesheet.reminder',
61 'function': 'run',48 'function': 'run',
62 'args': '()',49 'args': '()',
63 }50 }
6451
65 #default message (the one created if missing)52 # default message (the one created if missing)
66 message = {'reply_to': 'spam@camptocamp.com'}53 message = {'reply_to': 'spam@camptocamp.com'}
6754
68 def run(self, cr, uid, context=None):55 def run(self, cr, uid, context=None):
69 """ find the reminder recipients and send them an email """56 """ find the reminder recipients and send them an email """
70 context = context or {}
71
72 company_obj = self.pool.get('res.company')57 company_obj = self.pool.get('res.company')
73 #get all companies58 # get all companies
74 company_ids = company_obj.search(cr, uid, [], context=context)59 company_ids = company_obj.search(cr, uid, [], context=context)
7560
76 #for each company, get all recipients61 # for each company, get all recipients
77 recipients = []62 recipients = []
78 company_recipients = company_obj.get_reminder_recipients(cr, uid, company_ids, context=context)63 company_recipients = company_obj.get_reminder_recipients(
79 for company_id, rec in company_recipients.iteritems():64 cr, uid, company_ids, context=context)
65 for rec in company_recipients.itervalues():
80 recipients += rec66 recipients += rec
8167
82 #get the message to send68 # get the message to send
83 message_id = self.get_message_id(cr, uid, context)69 message_id = self.get_message_id(cr, uid, context)
84 message_data = self.browse(cr, uid, message_id, context=context)70 message_data = self.browse(cr, uid, message_id, context=context)
8571
86 #send them email if they have an email defined72 # send them email if they have an email defined
87 emails = []
88 for employee in recipients:73 for employee in recipients:
89 if employee.work_email:74 if not employee.work_email:
90 emails.append(employee.work_email)75 continue
9176 vals = {
92 if emails:77 'state': 'outgoing',
93 tools.email_send(message_data.reply_to, [], message_data.subject, message_data.message, email_bcc=emails)78 'subject': message_data.subject,
9479 'body_html': message_data.message,
95 def get_cron_id(self, cr, uid, context):80 'email_to': employee.work_email,
81 'email_from': message_data.reply_to,
82 }
83 self.pool.get('mail.mail').create(cr, uid, vals, context=context)
84
85 return True
86
87 def get_cron_id(self, cr, uid, context=None):
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 """
89 if context is None:
90 context = {}
97 cron_obj = self.pool.get('ir.cron')91 cron_obj = self.pool.get('ir.cron')
98 # find the cron that send messages92 # find the cron that send messages
99 cron_id = cron_obj.search(cr, uid, [('function', 'ilike', self.cron['function']),93 ctx = dict(context, active_test=False)
100 ('model', 'ilike', self.cron['model'])],94 cron_ids = cron_obj.search(
101 context={'active_test': False})95 cr, uid,
102 if cron_id:96 [('function', 'ilike', self.cron['function']),
103 cron_id = cron_id[0]97 ('model', 'ilike', self.cron['model'])],
98 context=ctx)
99
100 cron_id = None
101 if cron_ids:
102 cron_id = cron_ids[0]
104103
105 # the cron does not exists104 # the cron does not exists
106 if not cron_id:105 if cron_id is None:
107 self.cron['name'] = _('timesheet status reminder')106 vals = dict(self.cron,
108 cron_id = cron_obj.create(cr, uid, self.cron, context)107 name=_('timesheet status reminder'),
108 nextcall=self._cron_nextcall())
109
110 cron_id = cron_obj.create(cr, uid, vals, context=context)
109111
110 return cron_id112 return cron_id
111113
112 def get_message_id(self, cr, uid, context):114 @staticmethod
113 """ return the message'id. create one if the message does not exists """115 def _cron_nextcall():
116 tomorrow = datetime.today() + timedelta(days=1)
117 return tomorrow.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
118
119 def get_message_id(self, cr, uid, context=None):
120 """ return the message's id. create one if the message does not exists """
114 #there is only one line in db, let's get it121 #there is only one line in db, let's get it
115 message_id = self.search(cr, uid, [], limit=1, context=context)122 message_ids = self.search(cr, uid, [], limit=1, context=context)
116123
117 if message_id:124 message_id = None
118 message_id = message_id[0]125 if message_ids:
126 message_id = message_ids[0]
119127
120 #the message does not exists128 #the message does not exists
121 if not message_id:129 if message_id is None:
122 #translate130 vals = dict(self.message,
123 self.message['subject'] = _('Timesheet Reminder')131 subject=_('Timesheet Reminder'),
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=_(
133 'At least one of your last timesheets is still '
134 'in draft or is missing. Please take time to '
135 'complete and confirm it.'))
125136
126 message_id = self.create(cr, uid, self.message, context)137 message_id = self.create(cr, uid, vals, context)
127138
128 return message_id139 return message_id
129140
130 def get_config(self, cr, uid, context):141 def get_config(self, cr, uid, context=None):
131 """return the reminder config from the db """142 """return the reminder config from the db """
132143
133 cron_id = self.get_cron_id(cr, uid, context)144 cron_id = self.get_cron_id(cr, uid, context)
134145
135 cron_data = self.pool.get('ir.cron').browse(cr, uid, cron_id)146 cron_data = self.pool.get('ir.cron').browse(
147 cr, uid, cron_id, context=context)
136148
137 #there is only one line in db, let's get it149 # there is only one line in db, let's get it
138 message_id = self.get_message_id(cr, uid, context)150 message_id = self.get_message_id(cr, uid, context=context)
139 message_data = self.browse(cr, uid, message_id)151 message_data = self.browse(cr, uid, message_id, context=context)
140 return {'reminder_active': cron_data.active,152 return {'reminder_active': cron_data.active,
141 'interval_type': cron_data.interval_type,153 'interval_type': cron_data.interval_type,
142 'interval_number': cron_data.interval_number,154 'interval_number': cron_data.interval_number,
143 'reply_to': message_data.reply_to,155 'reply_to': message_data.reply_to,
144 'message': message_data.message,156 'message': message_data.message,
145 'subject': message_data.subject,157 'subject': message_data.subject,
146 'nextcall': cron_data.nextcall,158 'nextcall': self._cron_nextcall(),
147 }159 }
148160
149 def save_config(self, cr, uid, ids, datas, context):161 def save_config(self, cr, uid, ids, datas, context=None):
150 """save the reminder config """162 """save the reminder config """
151163
152 #modify the cron164 #modify the cron
153 cron_id = self.get_cron_id(cr, uid, context)165 cron_id = self.get_cron_id(cr, uid, context=context)
154 self.pool.get('ir.cron').write(cr, uid, [cron_id],166 self.pool.get('ir.cron').write(
167 cr, uid, [cron_id],
155 {'active': datas['reminder_active'],168 {'active': datas['reminder_active'],
156 'interval_number': datas['interval_number'],169 'interval_number': datas['interval_number'],
157 'interval_type': datas['interval_type'],170 'interval_type': datas['interval_type'],
@@ -159,11 +172,10 @@
159 context=context)172 context=context)
160 #modify the message173 #modify the message
161 message_id = ids or self.get_message_id(cr, uid, context)174 message_id = ids or self.get_message_id(cr, uid, context)
162 self.write(cr, uid, [message_id],175 self.write(
176 cr, uid, [message_id],
163 {'reply_to': datas['reply_to'],177 {'reply_to': datas['reply_to'],
164 'message': datas['message'],178 'message': datas['message'],
165 'subject': datas['subject'],179 'subject': datas['subject'],
166 }, context=context)180 }, context=context)
167 return True181 return True
168
169reminder()
170182
=== modified file 'hr_timesheet_reminder/report/__init__.py'
--- hr_timesheet_reminder/report/__init__.py 2011-08-12 12:53:16 +0000
+++ hr_timesheet_reminder/report/__init__.py 2012-12-13 17:06:20 +0000
@@ -1,31 +1,22 @@
1# -*- coding: utf-8 -*-1# -*- coding: utf-8 -*-
2##############################################################################2##############################################################################
3#3#
4# Copyright (c) Camptocamp SA4# Author: Arnaud Wüst (Camptocamp)
5# Author: Arnaud WÃŒst5# Copyright 2011-2012 Camptocamp SA
6#6#
7#7# This program is free software: you can redistribute it and/or modify
8#8# it under the terms of the GNU Affero General Public License as
9# WARNING: This program as such is intended to be used by professional9# published by the Free Software Foundation, either version 3 of the
10# programmers who take the whole responsability of assessing all potential10# License, or (at your option) any later version.
11# consequences resulting from its eventual inadequacies and bugs11#
12# End users who are looking for a ready-to-use solution with commercial12# This program is distributed in the hope that it will be useful,
13# garantees and support are strongly adviced to contract a Free Software13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# Service Company14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15#15# GNU Affero General Public License for more details.
16# This program is Free Software; you can redistribute it and/or16#
17# modify it under the terms of the GNU General Public License17# You should have received a copy of the GNU Affero General Public License
18# as published by the Free Software Foundation; either version 218# along with this program. If not, see <http://www.gnu.org/licenses/>.
19# of the License, or (at your option) any later version.
20#
21# This program is distributed in the hope that it will be useful,
22# but WITHOUT ANY WARRANTY; without even the implied warranty of
23# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24# GNU General Public License for more details.
25#
26# You should have received a copy of the GNU General Public License
27# along with this program; if not, write to the Free Software
28# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29#19#
30##############################################################################20##############################################################################
21
31import timesheet_status22import timesheet_status
3223
=== modified file 'hr_timesheet_reminder/report/timesheet_status.py'
--- hr_timesheet_reminder/report/timesheet_status.py 2011-09-01 13:44:19 +0000
+++ hr_timesheet_reminder/report/timesheet_status.py 2012-12-13 17:06:20 +0000
@@ -1,47 +1,40 @@
1# -*- coding: utf-8 -*-1# -*- coding: utf-8 -*-
2##############################################################################2##############################################################################
3#3#
4# Copyright (c) Camptocamp SA4# Author: Arnaud Wüst (Camptocamp)
5# Author: Arnaud WÃŒst5# Author: Guewen Baconnier (Camptocamp) (port to v7)
6# Author: Guewen Baconnier6# Copyright 2011-2012 Camptocamp SA
7#7#
8#8# This program is free software: you can redistribute it and/or modify
9#9# it under the terms of the GNU Affero General Public License as
10# WARNING: This program as such is intended to be used by professional10# published by the Free Software Foundation, either version 3 of the
11# programmers who take the whole responsability of assessing all potential11# License, or (at your option) any later version.
12# consequences resulting from its eventual inadequacies and bugs12#
13# End users who are looking for a ready-to-use solution with commercial13# This program is distributed in the hope that it will be useful,
14# garantees and support are strongly adviced to contract a Free Software14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# Service Company15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16#16# GNU Affero General Public License for more details.
17# This program is Free Software; you can redistribute it and/or17#
18# modify it under the terms of the GNU General Public License18# You should have received a copy of the GNU Affero General Public License
19# as published by the Free Software Foundation; either version 219# along with this program. If not, see <http://www.gnu.org/licenses/>.
20# of the License, or (at your option) any later version.
21#
22# This program is distributed in the hope that it will be useful,
23# but WITHOUT ANY WARRANTY; without even the implied warranty of
24# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25# GNU General Public License for more details.
26#
27# You should have received a copy of the GNU General Public License
28# along with this program; if not, write to the Free Software
29# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30#20#
31##############################################################################21##############################################################################
3222
33import time23import time
3424
35from datetime import datetime25from datetime import datetime
36from report import report_sxw26from openerp.report import report_sxw
27from openerp.tools import DEFAULT_SERVER_DATE_FORMAT
28from openerp.tools.translate import _
3729
3830
39class timesheet_status(report_sxw.rml_parse):31class timesheet_status(report_sxw.rml_parse):
40 _name = 'report.timesheet.reminder.status'32 _name = 'report.timesheet.reminder.status'
4133
42 def __init__(self, cr, uid, name, context):34 def __init__(self, cr, uid, name, context=None):
43 super(timesheet_status, self).__init__(cr, uid, name, context)35 super(timesheet_status, self).__init__(cr, uid, name, context=context)
44 self.data = {}36 self.data = {}
37 self.end_date = None
45 self.localcontext.update({38 self.localcontext.update({
46 'compute': self.compute,39 'compute': self.compute,
47 'time': time,40 'time': time,
@@ -60,64 +53,65 @@
60 """compute all datas and do all the calculations before to start the rml rendering53 """compute all datas and do all the calculations before to start the rml rendering
61 - objects are companies54 - objects are companies
62 """55 """
63 #init the data array56 # init the data array
64 self.data = {}57 self.data = {}
65 for o in objects:58 for o in objects:
66 self.data[o.id] = {}59 self.data[o.id] = {}
67 #get the list of employees ids to treat60 # get the list of employees ids to treat
68 for o in objects:61 for o in objects:
69 self.data[o.id]['employees'] = self._compute_employees_list(o)62 self.data[o.id]['employees'] = self._compute_employees_list(o)
7063
71 #get the time range for each company64 # get the time range for each company
65 end_date = datetime.strptime(self.end_date, DEFAULT_SERVER_DATE_FORMAT)
72 for o in objects:66 for o in objects:
73 self.data[o.id]['time_ranges'] = \67 self.data[o.id]['time_ranges'] = self._compute_periods(o, end_date)
74 self._compute_periods(o, datetime.strptime(self.end_date, "%Y-%m-%d"))
7568
76 #get the status of each timesheet for each employee69 # get the status of each timesheet for each employee
77 for o in objects:70 for o in objects:
78 self.data[o.id]['sheet_status'] = self._compute_all_status(o)71 self.data[o.id]['sheet_status'] = self._compute_all_status(o)
7972
80 def _compute_employees_list(self, company):73 def _compute_employees_list(self, company):
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
75 to the companies (param company) """
82 employee_obj = self.pool.get('hr.employee')76 employee_obj = self.pool.get('hr.employee')
83 employee_ids = employee_obj.search(self.cr, self.uid,77 employee_ids = employee_obj.search(self.cr, self.uid,
84 [('company_id', '=', company.id),78 [('company_id', '=', company.id),
85 ('active', '=', True)],79 ('active', '=', True)],
86 context=self.localcontext)80 context=self.localcontext)
87 return employee_obj.browse(self.cr, self.uid, employee_ids, context=self.localcontext)81 return employee_obj.browse(
82 self.cr, self.uid, employee_ids, context=self.localcontext)
8883
89 def _get_last_period_dates(self, company, date):84 def _get_last_period_dates(self, company, date):
90 """ return the start date of the last period to display """85 """ return the start date of the last period to display """
91 return self.pool.get('res.company').\86 return self.pool.get('res.company').get_last_period_dates(
92 get_last_period_dates(self.cr, self.uid, company, date, context=self.localcontext)87 self.cr,
88 self.uid,
89 company,
90 date,
91 context=self.localcontext)
9392
94 def _compute_periods(self, company, date):93 def _compute_periods(self, company, date):
95 """ return the timeranges to display. This is the 5 last timesheets """94 """ return the timeranges to display. This is the 5 last timesheets """
96 return self.pool.get('res.company').\95 return self.pool.get('res.company').compute_timesheet_periods(
97 compute_timesheet_periods(self.cr, self.uid, company, date, context=self.localcontext)96 self.cr,
97 self.uid,
98 company,
99 date,
100 context=self.localcontext)
98101
99 def get_title(self, obj):102 def get_title(self, obj):
100 """ return the title of the main table """103 """ return the title of the main table """
101 last_id = len(self.data[obj.id]['time_ranges']) - 1104 timerange = self.data[obj.id]['time_ranges']
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)
103 "%Y-%m-%d %H:%M:%S")106 end_date = self.formatLang(timerange[0][1], date=True)
104 start_date = time.strftime("%d.%m.%Y", start_date)107
105108 return obj.name + ", " + start_date + _(" to ") + end_date
106 end_date = time.strptime(str(self.data[obj.id]['time_ranges'][0][1]),
107 "%Y-%m-%d %H:%M:%S")
108 end_date = time.strftime("%d.%m.%Y", end_date)
109
110 return obj.name + ", " + start_date + " to " + end_date
111109
112 def get_timerange_title(self, obj, cpt):110 def get_timerange_title(self, obj, cpt):
113 """ return a header text for a periods column """111 """ return a header text for a periods column """
114 start_date = self.data[obj.id]['time_ranges'][cpt][0]112 timerange = self.data[obj.id]['time_ranges'][cpt]
115 start_date = time.strptime(str(start_date), "%Y-%m-%d %H:%M:%S")113 start_date = self.formatLang(timerange[0], date=True)
116 start_date = time.strftime("%d.%m.%Y", start_date)114 end_date = self.formatLang(timerange[1], date=True)
117
118 end_date = self.data[obj.id]['time_ranges'][cpt][1]
119 end_date = time.strptime(str(end_date), "%Y-%m-%d %H:%M:%S")
120 end_date = time.strftime("%d.%m.%Y", end_date)
121115
122 return start_date + "\n " + end_date116 return start_date + "\n " + end_date
123117
@@ -131,21 +125,25 @@
131125
132 def _compute_timesheet_status(self, employee_id, period):126 def _compute_timesheet_status(self, employee_id, period):
133 """ return the timesheet status for a user and a period """127 """ return the timesheet status for a user and a period """
134 return self.pool.get('hr.employee').\128 return self.pool.get('hr.employee').compute_timesheet_status(
135 compute_timesheet_status(self.cr, self.uid, employee_id, period, context=self.localcontext)129 self.cr,
130 self.uid,
131 employee_id,
132 period,
133 context=self.localcontext)
136134
137 def _compute_all_status(self, o):135 def _compute_all_status(self, obj):
138 """ compute all status for all employees for all periods """136 """ compute all status for all employees for all periods """
139 result = {}137 result = {}
140138
141 #for each periods139 #for each periods
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']):
143 result[p_index] = {}141 result[p_index] = {}
144 period = self.data[o.id]['time_ranges'][p_index]
145 #for each employees142 #for each employees
146 for employee in self.data[o.id]['employees']:143 for employee in self.data[obj.id]['employees']:
147 #compute the status144 #compute the status
148 result[p_index][employee.id] = self._compute_timesheet_status(employee.id, period)145 result[p_index][employee.id] = self._compute_timesheet_status(
146 employee.id, period)
149147
150 return result148 return result
151149
152150
=== modified file 'hr_timesheet_reminder/report/timesheet_status.rml'
--- hr_timesheet_reminder/report/timesheet_status.rml 2011-08-12 12:53:16 +0000
+++ hr_timesheet_reminder/report/timesheet_status.rml 2012-12-13 17:06:20 +0000
@@ -1,165 +1,159 @@
1<?xml version="1.0"?>1<?xml version="1.0"?>
2<document filename="timesheet_status.pdf">2<document filename="timesheet_status.pdf">
3##############################################################################3 <!--
4#4 ##############################################################################
5# Copyright (c) Camptocamp SA5 #
6# Author: Arnaud Wüst6 # Author: Arnaud Wüst (Camptocamp)
7#7 # Copyright 2011-2012 Camptocamp SA
8#8 #
9# WARNING: This program as such is intended to be used by professional9 # This program is free software: you can redistribute it and/or modify
10# programmers who take the whole responsability of assessing all potential10 # it under the terms of the GNU Affero General Public License as
11# consequences resulting from its eventual inadequacies and bugs11 # published by the Free Software Foundation, either version 3 of the
12# End users who are looking for a ready-to-use solution with commercial12 # License, or (at your option) any later version.
13# garantees and support are strongly adviced to contract a Free Software13 #
14# Service Company14 # This program is distributed in the hope that it will be useful,
15#15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16# This program is Free Software; you can redistribute it and/or16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# modify it under the terms of the GNU General Public License17 # GNU Affero General Public License for more details.
18# as published by the Free Software Foundation; either version 218 #
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
20#20 # along with this program. If not, see <http://www.gnu.org/licenses/>.
21# This program is distributed in the hope that it will be useful,21 #
22# but WITHOUT ANY WARRANTY; without even the implied warranty of22 ##############################################################################
23# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the23 -->
24# GNU General Public License for more details.24
25#25
26# You should have received a copy of the GNU General Public License26 <!-- Process all datas -->
27# along with this program; if not, write to the Free Software27 <template pageSize="(21cm,29.7cm)" title="Timesheet Status" author="Camptocamp" allowSplitting="20">
28# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.28
29#29
30##############################################################################30 <!-- PAGE: template of all pages (= all pages except first and last if defined)-->
3131 <pageTemplate id="all">
32 <!-- Process all datas -->32 <pageGraphics>
33 <template pageSize="(21cm,29.7cm)" title="Timesheet Status" author="Camptocamp" allowSplitting="20">33 <setFont name="Helvetica-Bold" size="9"/>
34 34
35 35 <!--Header-->
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>
37 <pageTemplate id="all">37 <drawString x="17.0cm" y="28.1cm">Timesheet Status</drawString>
38 <pageGraphics>38
39 <setFont name="Helvetica-Bold" size="9"/>39 <lineMode width="0.7"/>
40 40 <lines>1.2cm 28.0cm 19.8cm 28.0cm</lines>
41 <!--Header-->41
42 <drawString x="1.2cm" y="28.1cm">[[ company.name ]]</drawString>42 <!-- Footer -->
43 <drawString x="17.0cm" y="28.1cm">Timesheet Status</drawString>43 <setFont name="Helvetica" size="9"/>
4444 <drawString x="1.2cm" y="1.3cm"> [[ time.strftime("%m-%d-%y %H:%M", time.localtime()) ]]</drawString>
45 <lineMode width="0.7"/>45 <drawString x="18.8cm" y="1.3cm">Page <pageNumber/></drawString>
46 <lines>1.2cm 28.0cm 19.8cm 28.0cm</lines>46
47 47 </pageGraphics>
48 <!-- Footer -->48 <frame id="all" x1="1.2cm" y1="1.7cm" width="18.6cm" height="25.8cm"/>
49 <setFont name="Helvetica" size="9"/>49 </pageTemplate>
50 <drawString x="1.2cm" y="1.3cm"> [[ time.strftime("%m-%d-%y %H:%M", time.localtime()) ]]</drawString>50
51 <drawString x="18.8cm" y="1.3cm">Page <pageNumber/></drawString>51 </template>
52 52 <stylesheet>
53 </pageGraphics>53
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) -->
55 </pageTemplate>55 <blockTableStyle id="std">
56 56 <blockAlignment value="LEFT"/>
57 </template>57 <blockValign value="TOP"/>
58 <stylesheet>58 <blockBottomPadding length="4"/>
5959 <blockFont name="Helvetica" size="9" start="0,0" stop="-1,-1"/>
60 <!--TABLE: standard table type "columns" (which means there is a title, a header of fields names and then lines of values) --> 60
61 <blockTableStyle id="std">61 <!-- first line: table name, fake as it was only one cell. grey bg -->
62 <blockAlignment value="LEFT"/>62 <lineStyle kind="BOX" colorName="black" start="0,0" stop="-1,0"/>
63 <blockValign value="TOP"/>63 <blockBackground colorName="#cccccc" start="0,0" stop="-1,0"/>
64 <blockBottomPadding length="4"/>64 <blockFont name="Helvetica" size="9" start="0,0" stop="-1,0"/>
65 <blockFont name="Helvetica" size="9" start="0,0" stop="-1,-1"/>65 <!-- second line: header of columns -->
66 66 <lineStyle kind="GRID" colorName="black" start="0,1" stop="-1,1"/>
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"/>
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 -->
69 <blockBackground colorName="#cccccc" start="0,0" stop="-1,0"/>69 <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="0,2" stop="-1,-1"/>
70 <blockFont name="Helvetica" size="9" start="0,0" stop="-1,0"/>70 <lineStyle kind="LINEAFTER" colorName="black" start="0,2" stop="-1,-1"/>
71 <!-- second line: header of columns -->71 <!-- last line: line below -->
72 <lineStyle kind="GRID" colorName="black" start="0,1" stop="-1,1"/>72 <lineStyle kind="OUTLINE" colorName="black" start="0,0" stop="-1,-1"/>
73 <blockFont name="Helvetica-Oblique" start="0,1" stop="-1,1"/>73 <!-- all columns centered except the first two (1 system columns + employee) -->
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" />
75 <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="0,2" stop="-1,-1"/> 75
76 <lineStyle kind="LINEAFTER" colorName="black" start="0,2" stop="-1,-1"/>76 </blockTableStyle>
77 <!-- last line: line below -->77
78 <lineStyle kind="OUTLINE" colorName="black" start="0,0" stop="-1,-1"/>78 <!-- default para in tables -->
79 <!-- all columns centered except the first two (1 system columns + employee) -->79 <paraStyle name="std"
80 <blockAlignment value="CENTER" start="2,1" stop="-1,-1" />80 fontName="Helvetica"
81 81 fontSize="9"
82 </blockTableStyle>82 alignment="LEFT"
8383 />
84 <!-- default para in tables -->84
85 <paraStyle name="std"85 <paraStyle name="Confirmed"
86 fontName="Helvetica" 86 fontName="Helvetica"
87 fontSize="9"87 fontSize="9"
88 alignment="LEFT"88 alignment="CENTER"
89 />89 backColor="green"
90 90 textColor="white"
91 <paraStyle name="Confirmed"91 />
92 fontName="Helvetica"92
93 fontSize="9"93 <paraStyle name="Missing"
94 alignment="CENTER"94 fontName="Helvetica"
95 backColor="green"95 fontSize="9"
96 textColor="white"96 alignment="CENTER"
97 />97 backColor="red"
9898 textColor="white"
99 <paraStyle name="Missing"99 />
100 fontName="Helvetica"100
101 fontSize="9"101 <paraStyle name="Draft"
102 alignment="CENTER"102 fontName="Helvetica"
103 backColor="red"103 fontSize="9"
104 textColor="white"104 alignment="CENTER"
105 />105 backColor="orange"
106106 textColor="black"
107 <paraStyle name="Draft"107 />
108 fontName="Helvetica"108
109 fontSize="9"109 <paraStyle name="Error"
110 alignment="CENTER"110 fontName="Helvetica"
111 backColor="orange"111 fontSize="9"
112 textColor="black"112 alignment="CENTER"
113 />113 textColor="red"
114114 />
115 <paraStyle name="Error"115
116 fontName="Helvetica"116 <paraStyle name="Not in Company"
117 fontSize="9"117 fontName="Helvetica"
118 alignment="CENTER"118 fontSize="9"
119 textColor="red"119 alignment="CENTER"
120 />120 textColor="lightgrey"
121121 />
122 <paraStyle name="Not in Company"122
123 fontName="Helvetica"123
124 fontSize="9"124 </stylesheet>
125 alignment="CENTER"125
126 textColor="lightgrey"126 <story>
127 />127
128128 [[repeatIn(objects, 'o')]]
129 129 <blockTable style="std" repeatRows="2" colWidths="0,5cm,2.7cm,2.7cm,2.7cm,2.7cm,2.7cm" >
130 </stylesheet>130
131 131 <tr>
132 <story> 132 <td/>
133 133 <td>[[get_title(o)]]</td>
134 [[repeatIn(objects, 'o')]]134 </tr>
135 <blockTable style="std" repeatRows="2" colWidths="0,5cm,2.7cm,2.7cm,2.7cm,2.7cm,2.7cm" >135
136136 <tr>
137 <tr> 137 <td/>
138 <td/>138 <td>Employees</td>
139 <td>[[get_title(o)]]</td>139 <td>[[ get_timerange_title(o, 4) ]]</td>
140 </tr>140 <td>[[ get_timerange_title(o, 3) ]]</td>
141141 <td>[[ get_timerange_title(o, 2) ]]</td>
142 <tr>142 <td>[[ get_timerange_title(o, 1) ]]</td>
143 <td/>143 <td>[[ get_timerange_title(o, 0) ]]</td>
144 <td>Employees</td>144 </tr>
145 <td>[[ get_timerange_title(o, 4) ]]</td>145
146 <td>[[ get_timerange_title(o, 3) ]]</td>146 <tr>
147 <td>[[ get_timerange_title(o, 2) ]]</td>147 <td>[[repeatIn(get_user_list(o),'u')]]</td>
148 <td>[[ get_timerange_title(o, 1) ]]</td>148 <td><para style="std">[[ u.name ]]</para></td>
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>
150 </tr>150 <td><para>[[ setTag('para', 'para', {'style': get_timesheet_status(o, u, 3)}) ]][[ get_timesheet_status(o, u, 3) ]]</para></td>
151151 <td><para>[[ setTag('para', 'para', {'style': get_timesheet_status(o, u, 2)}) ]][[ get_timesheet_status(o, u, 2) ]]</para></td>
152 <tr> 152 <td><para>[[ setTag('para', 'para', {'style': get_timesheet_status(o, u, 1)}) ]][[ get_timesheet_status(o, u, 1) ]]</para></td>
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>
154 <td><para style="std">[[ u.name ]]</para></td>154 </tr>
155 <td><para>[[ setTag('para','para',{'style':get_timesheet_status(o, u, 4)}) ]][[ get_timesheet_status(o, u, 4) ]]</para></td>155
156 <td><para>[[ setTag('para','para',{'style':get_timesheet_status(o, u, 3)}) ]][[ get_timesheet_status(o, u, 3) ]]</para></td>156 </blockTable>
157 <td><para>[[ setTag('para','para',{'style':get_timesheet_status(o, u, 2)}) ]][[ get_timesheet_status(o, u, 2) ]]</para></td>157
158 <td><para>[[ setTag('para','para',{'style':get_timesheet_status(o, u, 1)}) ]][[ get_timesheet_status(o, u, 1) ]]</para></td>158 </story>
159 <td><para>[[ setTag('para','para',{'style':get_timesheet_status(o, u, 0)}) ]][[ get_timesheet_status(o, u, 0) ]]</para></td>159</document>
160 </tr>
161
162 </blockTable>
163
164 </story>
165 </document>
166160
=== modified file 'hr_timesheet_reminder/timesheet_report.xml'
--- hr_timesheet_reminder/timesheet_report.xml 2011-08-12 12:53:16 +0000
+++ hr_timesheet_reminder/timesheet_report.xml 2012-12-13 17:06:20 +0000
@@ -1,15 +1,15 @@
1<?xml version="1.0"?>1<?xml version="1.0"?>
2<openerp>2<openerp>
3 <data>3 <data>
4 <report4 <report
5 id="timesheet_status"5 id="timesheet_status"
6 string="Timesheet Status"6 string="Timesheet Status"
7 model="res.company"7 model="res.company"
8 name="timesheet.reminder.status"8 name="timesheet.reminder.status"
9 rml="hr_timesheet_reminder/report/timesheet_status.rml"9 rml="hr_timesheet_reminder/report/timesheet_status.rml"
10 auto="False"10 auto="False"
11 header="True"11 header="True"
12 menu="False"/>12 menu="False"/>
13 13
14 </data>14 </data>
15</openerp>15</openerp>
1616
=== modified file 'hr_timesheet_reminder/wizard/reminder_config.py'
--- hr_timesheet_reminder/wizard/reminder_config.py 2011-08-12 12:53:16 +0000
+++ hr_timesheet_reminder/wizard/reminder_config.py 2012-12-13 17:06:20 +0000
@@ -1,53 +1,48 @@
1# -*- coding: utf-8 -*-1# -*- coding: utf-8 -*-
2##############################################################################2##############################################################################
3#3#
4# Copyright (c) 2011 Camptocamp SA (http://www.camptocamp.com)4# Author: Arnaud Wüst (Camptocamp)
5# All Right Reserved5# Author: Guewen Baconnier (Camptocamp) (port to v7)
6#6# Copyright 2011-2012 Camptocamp SA
7# Author : Guewen Baconnier (Camptocamp)7#
8# Author : Arnaud Wüst (Camptocamp)8# This program is free software: you can redistribute it and/or modify
9#9# it under the terms of the GNU Affero General Public License as
10# WARNING: This program as such is intended to be used by professional10# published by the Free Software Foundation, either version 3 of the
11# programmers who take the whole responsability of assessing all potential11# License, or (at your option) any later version.
12# consequences resulting from its eventual inadequacies and bugs12#
13# End users who are looking for a ready-to-use solution with commercial13# This program is distributed in the hope that it will be useful,
14# garantees and support are strongly adviced to contract a Free Software14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# Service Company15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16#16# GNU Affero General Public License for more details.
17# This program is Free Software; you can redistribute it and/or17#
18# modify it under the terms of the GNU General Public License18# You should have received a copy of the GNU Affero General Public License
19# as published by the Free Software Foundation; either version 219# along with this program. If not, see <http://www.gnu.org/licenses/>.
20# of the License, or (at your option) any later version.
21#
22# This program is distributed in the hope that it will be useful,
23# but WITHOUT ANY WARRANTY; without even the implied warranty of
24# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25# GNU General Public License for more details.
26#
27# You should have received a copy of the GNU General Public License
28# along with this program; if not, write to the Free Software
29# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30#20#
31##############################################################################21##############################################################################
3222
33from osv import osv, fields23from openerp.osv import orm, fields
3424
3525
36class reminder_config(osv.osv_memory):26class reminder_config(orm.TransientModel):
37 _name = 'hr.timesheet.reminder.config'27 _name = 'hr.timesheet.reminder.config'
3828
39 _columns = {29 _columns = {
40 'reminder_active': fields.boolean('Reminder Active'),30 'reminder_active': fields.boolean('Reminder Active'),
41 'interval_type': fields.selection([('days','Day(s)'), ('weeks', 'Week(s)'), ('months', 'Month(s)')],31 'interval_type': fields.selection(
42 'Periodicity Unit',),32 [('days', 'Day(s)'),
43 'interval_number': fields.integer('Periodicity Quantity',),33 ('weeks', 'Week(s)'),
44 'nextcall': fields.datetime('Next Run',),34 ('months', 'Month(s)')],
45 'message': fields.text('Message', required=True),35 'Periodicity Unit'),
46 'subject': fields.char('Subject', size=200, required=True),36 'interval_number': fields.integer('Periodicity Quantity'),
47 'reply_to': fields.char('Reply To', size=100, required=True),37 'nextcall': fields.datetime('Next Run'),
38 'message': fields.html('Message', required=True),
39 'subject': fields.char('Subject', required=True),
40 'reply_to': fields.char('Reply To', required=True),
48 }41 }
4942
50 def _check_interval_number(self, cr, uid, ids, context=None):43 def _check_interval_number(self, cr, uid, ids, context=None):
44 """This constraint should always have 1 id, we are in a TransientModel"""
45 assert len(ids) == 1, "Only 1 ID expected"
51 obj = self.browse(cr, uid, ids[0], context=context)46 obj = self.browse(cr, uid, ids[0], context=context)
52 if obj.interval_number < 1:47 if obj.interval_number < 1:
53 return False48 return False
@@ -60,23 +55,22 @@
60 def default_get(self, cr, uid, fields, context=None):55 def default_get(self, cr, uid, fields, context=None):
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)
62 data = self.pool.get('hr.timesheet.reminder').\57 data = self.pool.get('hr.timesheet.reminder').\
63 get_config(cr, uid, context)58 get_config(cr, uid, context=context)
64 res.update(data)59 res.update(data)
65 return res60 return res
6661
67 def run(self, cr, uid, ids, context):62 def run(self, cr, uid, ids, context=None):
68 """ execute the timesheets check and send emails """63 """ execute the timesheets check and send emails """
69 reminder_obj = self.pool.get('hr.timesheet.reminder')64 reminder_obj = self.pool.get('hr.timesheet.reminder')
70 reminder_obj.run(cr, uid, context=context)65 reminder_obj.run(cr, uid, context=context)
71 return {'type': 'ir.actions.act_window_close'}66 return {'type': 'ir.actions.act_window_close'}
7267
73 def save(self, cr, uid, ids, context):68 def save(self, cr, uid, ids, context=None):
74 """ save defined settings in db """69 """ save defined settings in db """
75
76 # get the wizard datas70 # get the wizard datas
77 wizard = self.browse(cr, uid, ids, context=context)[0]71 wizard = self.browse(cr, uid, ids[0], context=context)
7872
79 #retrieve the default cron values73 # retrieve the default cron values
80 reminder_obj = self.pool.get('hr.timesheet.reminder')74 reminder_obj = self.pool.get('hr.timesheet.reminder')
8175
82 values = {}.fromkeys(wizard._columns.keys(), False)76 values = {}.fromkeys(wizard._columns.keys(), False)
@@ -85,5 +79,3 @@
8579
86 reminder_obj.save_config(cr, uid, False, values, context=context)80 reminder_obj.save_config(cr, uid, False, values, context=context)
87 return {'type': 'ir.actions.act_window_close'}81 return {'type': 'ir.actions.act_window_close'}
88
89reminder_config()
9082
=== modified file 'hr_timesheet_reminder/wizard/reminder_config_view.xml'
--- hr_timesheet_reminder/wizard/reminder_config_view.xml 2011-08-12 12:53:16 +0000
+++ hr_timesheet_reminder/wizard/reminder_config_view.xml 2012-12-13 17:06:20 +0000
@@ -5,29 +5,39 @@
5 <record id="view_hr_timesheet_reminder_config_form" model="ir.ui.view">5 <record id="view_hr_timesheet_reminder_config_form" model="ir.ui.view">
6 <field name="name">hr.timesheet.reminder.config.form</field>6 <field name="name">hr.timesheet.reminder.config.form</field>
7 <field name="model">hr.timesheet.reminder.config</field>7 <field name="model">hr.timesheet.reminder.config</field>
8 <field name="type">form</field>
9 <field name="arch" type="xml">8 <field name="arch" type="xml">
10 <form string="Timesheet Reminder">9 <form string="Timesheet Reminder" version="7.0">
11 <group colspan="4" col="4" string="Periodicity" >10 <sheet>
12 <field name="reminder_active" />11 <group>
13 <newline/>12 <separator string="Periodicity" colspan="4"/>
14 <field name="nextcall" attrs="{'required':[('reminder_active','==',True)]}"/>13 <field name="reminder_active" />
15 <newline/>14 <newline/>
16 <field name="interval_number" string="Then send message every" attrs="{'required':[('reminder_active','==',True)]}"/>15 <field name="nextcall" attrs="{'required':[('reminder_active','==',True)]}"/>
17 <field name="interval_type" nolabel="1" attrs="{'required':[('reminder_active','==',True)]}"/>16 <newline/>
18 </group>17 <label for="interval_number" string="Then send message every"/>
1918 <div>
20 <group colspan="4" col="2" string="Message">19 <field name="interval_number" class="oe_inline"
21 <field name="reply_to"/>20 attrs="{'required':[('reminder_active','==',True)]}"/>
22 <field name="subject"/>21 <field name="interval_type" nolabel="1" class="oe_inline"
23 <field name="message" height="200"/>22 attrs="{'required':[('reminder_active','==',True)]}"/>
24 </group>23 </div>
2524 </group>
26 <group colspan="4" col="6">25
27 <button icon="gtk-cancel" special="cancel" string="Cancel"/>26 <group col="2">
28 <button icon="gtk-ok" string="Save configuration" name="save" type="object"/>27 <separator string="Message" colspan="4"/>
29 <button icon="gtk-ok" string="Run now" name="run" type="object"/>28 <field name="reply_to"/>
30 </group>29 <field name="subject"/>
30 <field name="message" height="200"/>
31 </group>
32 </sheet>
33
34 <footer>
35 <button name="save" string="Save configuration" colspan="1"
36 type="object" class="oe_highlight"/> or
37 <button name="run" string="Run now" colspan="1"
38 type="object" class="oe_highlight"/> or
39 <button special="cancel" string="Cancel" class="oe_link"/>
40 </footer>
31 </form>41 </form>
32 </field>42 </field>
33 </record>43 </record>
@@ -42,11 +52,11 @@
42 </record>52 </record>
4353
44 <menuitem id="menu_hr_timesheet_reminder_config"54 <menuitem id="menu_hr_timesheet_reminder_config"
45 icon="STOCK_PRINT"55 icon="STOCK_PRINT"
46 action="action_hr_timesheet_reminder_config"56 action="action_hr_timesheet_reminder_config"
47 parent="hr.menu_hr_configuration"57 parent="hr.menu_hr_configuration"
48 name="Timesheet Reminder"58 name="Timesheet Reminder"
49 groups="base.group_hr_manager"/>59 groups="base.group_hr_manager"/>
5060
51</data>61 </data>
52</openerp>62</openerp>
5363
=== modified file 'hr_timesheet_reminder/wizard/reminder_status.py'
--- hr_timesheet_reminder/wizard/reminder_status.py 2011-11-07 13:58:29 +0000
+++ hr_timesheet_reminder/wizard/reminder_status.py 2012-12-13 17:06:20 +0000
@@ -1,67 +1,58 @@
1# -*- coding: utf-8 -*-1# -*- coding: utf-8 -*-
2##############################################################################2##############################################################################
3#3#
4# Copyright (c) 2011 Camptocamp SA (http://www.camptocamp.com)4# Author: Arnaud Wüst (Camptocamp)
5# All Right Reserved5# Author: Guewen Baconnier (Camptocamp) (port to v7)
6#6# Copyright 2011-2012 Camptocamp SA
7# Author : Guewen Baconnier (Camptocamp)7#
8#8# This program is free software: you can redistribute it and/or modify
9# WARNING: This program as such is intended to be used by professional9# it under the terms of the GNU Affero General Public License as
10# programmers who take the whole responsability of assessing all potential10# published by the Free Software Foundation, either version 3 of the
11# consequences resulting from its eventual inadequacies and bugs11# License, or (at your option) any later version.
12# End users who are looking for a ready-to-use solution with commercial12#
13# garantees and support are strongly adviced to contract a Free Software13# This program is distributed in the hope that it will be useful,
14# Service Company14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15#15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# This program is Free Software; you can redistribute it and/or16# GNU Affero General Public License for more details.
17# modify it under the terms of the GNU General Public License17#
18# as published by the Free Software Foundation; either version 218# You should have received a copy of the GNU Affero General Public License
19# of the License, or (at your option) any later version.19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20#
21# This program is distributed in the hope that it will be useful,
22# but WITHOUT ANY WARRANTY; without even the implied warranty of
23# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24# GNU General Public License for more details.
25#
26# You should have received a copy of the GNU General Public License
27# along with this program; if not, write to the Free Software
28# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29#20#
30##############################################################################21##############################################################################
3122
32import time23from openerp.osv import orm, fields
3324
34from osv import osv, fields25
3526class reminder_status(orm.TransientModel):
36
37class reminder_status(osv.osv_memory):
38 _name = 'hr.timesheet.reminder.status'27 _name = 'hr.timesheet.reminder.status'
3928
40 _columns = {29 _columns = {
41 'company_ids': fields.many2many('res.company', 'reminder_company_rel', 'wid', 'rid', 'Company'),30 'company_ids': fields.many2many(
31 'res.company',
32 'reminder_company_rel',
33 'wid',
34 'rid',
35 string='Company'),
42 'date': fields.date('End Date', required=True),36 'date': fields.date('End Date', required=True),
43 }37 }
4438
45 _defaults = {39 _defaults = {
46 'date': lambda *a: time.strftime('%Y-%m-%d'),40 'date': lambda *a: fields.date.today(),
47 }41 }
4842
49 def print_report(self, cr, uid, ids, context):43 def print_report(self, cr, uid, ids, context=None):
50 if context is None:44 form_values = self.read(
51 context = {}45 cr, uid, ids[0], ['company_ids', 'date'], context=context)
5246
53 form_values = self.read(cr, uid, ids, ['company_ids', 'date'])[0]47 # when no company is selected, select them all
54
55 if not form_values['company_ids']:48 if not form_values['company_ids']:
56 form_values['company_ids'] = self.pool.get('res.company').\49 form_values['company_ids'] = self.pool.get('res.company').\
57 search(cr, uid, [], context=context)50 search(cr, uid, [], context=context)
51
58 data = {'ids': form_values['company_ids'],52 data = {'ids': form_values['company_ids'],
59 'model': 'res.company',53 'model': 'res.company',
60 'form': {}}54 'form': form_values}
61 data['form'].update(form_values)
6255
63 return {'type': 'ir.actions.report.xml',56 return {'type': 'ir.actions.report.xml',
64 'report_name': 'timesheet.reminder.status',57 'report_name': 'timesheet.reminder.status',
65 'datas': data}58 'datas': data}
66
67reminder_status()
6859
=== modified file 'hr_timesheet_reminder/wizard/reminder_status_view.xml'
--- hr_timesheet_reminder/wizard/reminder_status_view.xml 2011-08-12 12:53:16 +0000
+++ hr_timesheet_reminder/wizard/reminder_status_view.xml 2012-12-13 17:06:20 +0000
@@ -5,23 +5,24 @@
5 <record id="view_hr_timesheet_reminder_status_form" model="ir.ui.view">5 <record id="view_hr_timesheet_reminder_status_form" model="ir.ui.view">
6 <field name="name">hr.timesheet.reminder.status.form</field>6 <field name="name">hr.timesheet.reminder.status.form</field>
7 <field name="model">hr.timesheet.reminder.status</field>7 <field name="model">hr.timesheet.reminder.status</field>
8 <field name="type">form</field>
9 <field name="arch" type="xml">8 <field name="arch" type="xml">
10 <form string="Reminder Status">9 <form string="Reminder Status" version="7.0">
11 <group colspan="4" col="4" string="Parameter">10 <sheet>
12 <separator string="End Date (display the 5 timesheets previous to this date)" colspan="4"/>11 <group>
13 <field name="date" colspan="4" nolabel="1" width="400" />12 <label for="date" string="End Date (display the 5 timesheets previous to this date)"/>
14 </group>13 <field name="date" colspan="4" nolabel="1" width="400" />
14 </group>
1515
16 <group colspan="4" col="4" string="Filter">16 <group>
17 <separator string="Filter by a Company (leave empty to select all companies)" colspan="4"/>17 <separator string="Companies" colspan="4"/>
18 <field name="company_ids" colspan="4" nolabel="1"/>18 <label for="company_ids" colspan="4" string="Filter by a Company (leave empty to select all companies)"/>
19 <newline/>19 <field name="company_ids" colspan="4" nolabel="1"/>
20 </group>20 </group>
21 <group colspan="4" col="6">21 </sheet>
22 <button icon="gtk-cancel" special="cancel" string="Cancel"/>22 <footer>
23 <button icon="gtk-print" string="Print" name="print_report" type="object" colspan="2" default_focus="1" />23 <button name="print_report" string="Print" colspan="1" type="object" class="oe_highlight"/> or
24 </group>24 <button special="cancel" string="Cancel" class="oe_link"/>
25 </footer>
25 </form>26 </form>
26 </field>27 </field>
27 </record>28 </record>
@@ -36,11 +37,11 @@
36 </record>37 </record>
3738
38 <menuitem id="menu_hr_timesheet_reminder_status"39 <menuitem id="menu_hr_timesheet_reminder_status"
39 icon="STOCK_PRINT"40 icon="STOCK_PRINT"
40 action="action_hr_timesheet_reminder_status"41 action="action_hr_timesheet_reminder_status"
41 parent="hr_timesheet.menu_hr_reporting_timesheet"42 parent="hr.menu_hr_reporting_timesheet"
42 name="Timesheet Status"43 name="Timesheet Status"
43 groups="base.group_hr_manager"/>44 groups="base.group_hr_manager"/>
4445
45</data>46 </data>
46</openerp>47</openerp>

Subscribers

People subscribed via source and target branches