1 # -*- coding: utf-8 -*-
2 ##############################################################################
4 # OpenERP, Open Source Management Solution
5 # Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU Affero General Public License as
9 # published by the Free Software Foundation, either version 3 of the
10 # License, or (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU Affero General Public License for more details.
17 # You should have received a copy of the GNU Affero General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
20 ##############################################################################
23 from datetime import datetime, timedelta
24 from dateutil.relativedelta import relativedelta
28 from report.interface import report_rml
29 from report.interface import toxml
31 from report import report_sxw
32 from tools import ustr
33 from tools.translate import _
35 one_day = relativedelta(days=1)
36 month2name = [0, 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
40 minutes = int(round((h - hours) * 60, 0))
41 return '%02dh%02d' % (hours, minutes)
43 def lengthmonth(year, month):
44 if month == 2 and ((year % 4 == 0) and ((year % 100 != 0) or (year % 400 == 0))):
46 return [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month]
48 class report_custom(report_rml):
50 def create_xml(self, cr, uid, ids, datas, context=None):
51 obj_emp = pooler.get_pool(cr.dbname).get('hr.employee')
54 month = datetime(datas['form']['year'], datas['form']['month'], 1)
55 emp_ids = context.get('active_ids', [])
56 user_xml = ['<month>%s</month>' % _(month2name[month.month]), '<year>%s</year>' % month.year]
58 for emp in obj_emp.read(cr, uid, emp_ids, ['name']):
59 stop, days_xml = False, []
65 ''' % (ustr(toxml(emp['name'])))
66 today, tomor = month, month + one_day
67 while today.month == month.month:
68 #### Work hour calculation
70 select action, att.name
71 from hr_employee as emp inner join hr_attendance as att
72 on emp.id = att.employee_id
73 where att.name between %s and %s and emp.id = %s
76 cr.execute(sql, (today.strftime('%Y-%m-%d %H:%M:%S'), tomor.strftime('%Y-%m-%d %H:%M:%S'), emp['id']))
77 attendences = cr.dictfetchall()
79 # Fake sign ins/outs at week ends, to take attendances across week ends into account
80 if attendences and attendences[0]['action'] == 'sign_out':
81 attendences.insert(0, {'name': today.strftime('%Y-%m-%d %H:%M:%S'), 'action':'sign_in'})
82 if attendences and attendences[-1]['action'] == 'sign_in':
83 attendences.append({'name': tomor.strftime('%Y-%m-%d %H:%M:%S'), 'action':'sign_out'})
84 # sum up the attendances' durations
86 for att in attendences:
87 dt = datetime.strptime(att['name'], '%Y-%m-%d %H:%M:%S')
88 if ldt and att['action'] == 'sign_out':
89 wh += (float((dt - ldt).seconds)/60/60)
92 # Week xml representation
94 today_xml = '<day num="%s"><wh>%s</wh></day>' % ((today - month).days+1, (wh))
95 dy=(today - month).days+1
96 days_xml.append(today_xml)
97 today, tomor = tomor, tomor + one_day
98 user_xml.append(user_repr % '\n'.join(days_xml))
100 rpt_obj = pooler.get_pool(cr.dbname).get('hr.employee')
101 rml_obj=report_sxw.rml_parse(cr, uid, rpt_obj._name,context)
105 <company>%s</company>
107 ''' % (str(rml_obj.formatLang(time.strftime("%Y-%m-%d"),date=True))+' ' + str(time.strftime("%H:%M")),pooler.get_pool(cr.dbname).get('res.users').browse(cr,uid,uid).company_id.name)
109 first_date = str(month)
110 som = datetime.strptime(first_date, '%Y-%m-%d %H:%M:%S')
111 eom = som + timedelta(int(dy)-1)
115 date_xml.append('<days>')
116 if day_diff.days>=30:
117 date_xml += ['<dayy number="%d" name="%s" cell="%d"/>' % (x, _(som.replace(day=x).strftime('%a')),x-som.day+1) for x in range(som.day, lengthmonth(som.year, som.month)+1)]
119 if day_diff.days>=(lengthmonth(som.year, som.month)-som.day):
120 date_xml += ['<dayy number="%d" name="%s" cell="%d"/>' % (x, _(som.replace(day=x).strftime('%a')),x-som.day+1) for x in range(som.day, lengthmonth(som.year, som.month)+1)]
122 date_xml += ['<dayy number="%d" name="%s" cell="%d"/>' % (x, _(som.replace(day=x).strftime('%a')),x-som.day+1) for x in range(som.day, eom.day+1)]
124 day_diff1=day_diff.days-cell+1
131 month_dict[j]=som.strftime('%B')
136 if day_diff1 > lengthmonth(year,i+month): # Not on 30 else you have problems when entering 01-01-2009 for example
137 som1=datetime.date(year,month+i,1)
138 date_xml += ['<dayy number="%d" name="%s" cell="%d"/>' % (x, _(som1.replace(day=x).strftime('%a')),cell+x) for x in range(1, lengthmonth(year,i+month)+1)]
141 month_dict[j]=som1.strftime('%B')
145 som1=datetime.date(year,month+i,1)
146 date_xml += ['<dayy number="%d" name="%s" cell="%d"/>' % (x, _(som1.replace(day=x).strftime('%a')),cell+x) for x in range(1, eom.day+1)]
149 month_dict[j]=som1.strftime('%B')
152 day_diff1=day_diff1-x
159 som1=datetime.date(years,i,1)
160 date_xml += ['<dayy number="%d" name="%s" cell="%d"/>' % (x, _(som1.replace(day=x).strftime('%a')),cell+x) for x in range(1, lengthmonth(years,i)+1)]
163 month_dict[j]=som1.strftime('%B')
167 som1=datetime.date(years,i,1)
170 month_dict[j]=som1.strftime('%B')
171 date_xml += ['<dayy number="%d" name="%s" cell="%d"/>' % (x, _(som1.replace(day=x).strftime('%a')),cell+x) for x in range(1, eom.day+1)]
174 day_diff1=day_diff1-x
175 date_xml.append('</days>')
176 date_xml.append('<cols>3.5cm%s</cols>\n' % (',0.74cm' * (int(dy))))
177 xml = '''<?xml version="1.0" encoding="UTF-8" ?>
184 ''' % (header_xml,_('Attendances By Month'),'\n'.join(user_xml),date_xml)
187 report_custom('report.hr.attendance.bymonth', 'hr.employee', '', 'addons/hr_attendance/report/bymonth.xsl')
189 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: