[IMP] hr_timesheet_sheet: Added weekly sheet widget and removed a lot of hacks (date_current)
bzr revid: nicolas.vanhoren@openerp.com-20121009073056-1fzamwm2mms2tmhl
This commit is contained in:
@@ -65,5 +65,8 @@ The validation can be configured in the company:
|
||||
'installable': True,
|
||||
'auto_install': False,
|
||||
'application': True,
|
||||
'js': ['static/src/js/timesheet.js',],
|
||||
'css': ['static/src/css/timesheet.css',],
|
||||
'qweb': ['static/src/xml/timesheet.xml',],
|
||||
}
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
@@ -27,80 +27,6 @@ from osv import fields, osv
|
||||
from tools.translate import _
|
||||
import netsvc
|
||||
|
||||
class one2many_mod2(fields.one2many):
|
||||
def get(self, cr, obj, ids, name, user=None, offset=0, context=None, values=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
|
||||
if values is None:
|
||||
values = {}
|
||||
|
||||
# res6 = {id: date_current, ...}
|
||||
res6 = dict([(rec['id'], rec['date_current'])
|
||||
for rec in obj.read(cr, user, ids, ['date_current'], context=context)])
|
||||
|
||||
dom = []
|
||||
for c, id in enumerate(ids):
|
||||
if id in res6:
|
||||
if c: # skip first
|
||||
dom.insert(0 ,'|')
|
||||
dom.append('&')
|
||||
dom.append('&')
|
||||
dom.append(('name', '>=', res6[id]))
|
||||
dom.append(('name', '<=', res6[id]))
|
||||
dom.append(('sheet_id', '=', id))
|
||||
|
||||
ids2 = obj.pool.get(self._obj).search(cr, user, dom, limit=self._limit)
|
||||
|
||||
res = {}
|
||||
for i in ids:
|
||||
res[i] = []
|
||||
|
||||
for r in obj.pool.get(self._obj)._read_flat(cr, user, ids2, [self._fields_id], context=context, load='_classic_read'):
|
||||
if r[self._fields_id]:
|
||||
res[r[self._fields_id][0]].append(r['id'])
|
||||
return res
|
||||
|
||||
def set(self, cr, obj, id, field, values, user=None, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
|
||||
context = context.copy()
|
||||
context['sheet_id'] = id
|
||||
return super(one2many_mod2, self).set(cr, obj, id, field, values, user=user, context=context)
|
||||
|
||||
|
||||
class one2many_mod(fields.one2many):
|
||||
def get(self, cr, obj, ids, name, user=None, offset=0, context=None, values=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
|
||||
if values is None:
|
||||
values = {}
|
||||
|
||||
|
||||
res5 = obj.read(cr, user, ids, ['date_current'], context=context)
|
||||
res6 = {}
|
||||
for r in res5:
|
||||
res6[r['id']] = r['date_current']
|
||||
|
||||
ids2 = []
|
||||
for id in ids:
|
||||
dom = []
|
||||
if id in res6:
|
||||
dom = [('date', '=', res6[id]), ('sheet_id', '=', id)]
|
||||
ids2.extend(obj.pool.get(self._obj).search(cr, user,
|
||||
dom, limit=self._limit))
|
||||
res = {}
|
||||
for i in ids:
|
||||
res[i] = []
|
||||
for r in obj.pool.get(self._obj)._read_flat(cr, user, ids2,
|
||||
[self._fields_id], context=context, load='_classic_read'):
|
||||
if r[self._fields_id]:
|
||||
res[r[self._fields_id][0]].append(r['id'])
|
||||
|
||||
return res
|
||||
|
||||
class hr_timesheet_sheet(osv.osv):
|
||||
_name = "hr_timesheet_sheet.sheet"
|
||||
_inherit = "mail.thread"
|
||||
@@ -111,8 +37,7 @@ class hr_timesheet_sheet(osv.osv):
|
||||
def _total_attendances(self, cr, uid, ids, name, args, context=None):
|
||||
""" Get the total attendance for the timesheets
|
||||
Returns a dict like :
|
||||
{id: {'date_current': '2011-06-17',
|
||||
'total_per_day': {day: timedelta, ...},
|
||||
{id: {'total_per_day': {day: timedelta, ...},
|
||||
},
|
||||
...
|
||||
}
|
||||
@@ -122,7 +47,6 @@ class hr_timesheet_sheet(osv.osv):
|
||||
res = {}
|
||||
for sheet_id in ids:
|
||||
sheet = self.browse(cr, uid, sheet_id, context=context)
|
||||
date_current = sheet.date_current
|
||||
# field attendances_ids of hr_timesheet_sheet.sheet only
|
||||
# returns attendances of timesheet's current date
|
||||
attendance_ids = attendance_obj.search(cr, uid, [('sheet_id', '=', sheet_id)], context=context)
|
||||
@@ -143,20 +67,7 @@ class hr_timesheet_sheet(osv.osv):
|
||||
else:
|
||||
total_attendance[day] += attendance_interval
|
||||
|
||||
# if the delta is negative, it means that a sign out is missing
|
||||
# in a such case, we want to have the time to the end of the day
|
||||
# for a past date, and the time to now for the current date
|
||||
if total_attendance[day] < timedelta(0):
|
||||
if day == date_current:
|
||||
now = datetime.now()
|
||||
total_attendance[day] += timedelta(hours=now.hour,
|
||||
minutes=now.minute,
|
||||
seconds=now.second)
|
||||
else:
|
||||
total_attendance[day] += timedelta(days=1)
|
||||
|
||||
res[sheet_id] = {'date_current': date_current,
|
||||
'total_per_day': total_attendance}
|
||||
res[sheet_id] = {'total_per_day': total_attendance}
|
||||
return res
|
||||
|
||||
def _total_timesheet(self, cr, uid, ids, name, args, context=None):
|
||||
@@ -210,24 +121,16 @@ class hr_timesheet_sheet(osv.osv):
|
||||
|
||||
all_attendances_sheet = all_timesheet_attendances[id]
|
||||
|
||||
date_current = all_attendances_sheet['date_current']
|
||||
total_attendances_sheet = all_attendances_sheet['total_per_day']
|
||||
total_attendances_all_days = sum_all_days(total_attendances_sheet)
|
||||
total_attendances_day = total_attendances_sheet.get(date_current, timedelta(seconds=0))
|
||||
|
||||
total_timesheets_sheet = all_timesheet_lines[id]
|
||||
total_timesheets_all_days = sum_all_days(total_timesheets_sheet)
|
||||
total_timesheets_day = total_timesheets_sheet.get(date_current, timedelta(seconds=0))
|
||||
total_difference_all_days = total_attendances_all_days - total_timesheets_all_days
|
||||
total_difference_day = total_attendances_day - total_timesheets_day
|
||||
|
||||
res[id]['total_attendance'] = timedelta_to_hours(total_attendances_all_days)
|
||||
res[id]['total_timesheet'] = timedelta_to_hours(total_timesheets_all_days)
|
||||
res[id]['total_difference'] = timedelta_to_hours(total_difference_all_days)
|
||||
|
||||
res[id]['total_attendance_day'] = timedelta_to_hours(total_attendances_day)
|
||||
res[id]['total_timesheet_day'] = timedelta_to_hours(total_timesheets_day)
|
||||
res[id]['total_difference_day'] = timedelta_to_hours(total_difference_day)
|
||||
return res
|
||||
|
||||
def check_employee_attendance_state(self, cr, uid, sheet_id, context=None):
|
||||
@@ -277,44 +180,6 @@ class hr_timesheet_sheet(osv.osv):
|
||||
raise osv.except_osv(_('Warning!'), _('Please verify that the total difference of the sheet is lower than %.2f.') %(di,))
|
||||
return True
|
||||
|
||||
def date_today(self, cr, uid, ids, context=None):
|
||||
for sheet in self.browse(cr, uid, ids, context=context):
|
||||
if datetime.today() <= datetime.strptime(sheet.date_from, '%Y-%m-%d'):
|
||||
self.write(cr, uid, [sheet.id], {'date_current': sheet.date_from,}, context=context)
|
||||
elif datetime.now() >= datetime.strptime(sheet.date_to, '%Y-%m-%d'):
|
||||
self.write(cr, uid, [sheet.id], {'date_current': sheet.date_to,}, context=context)
|
||||
else:
|
||||
self.write(cr, uid, [sheet.id], {'date_current': time.strftime('%Y-%m-%d')}, context=context)
|
||||
return True
|
||||
|
||||
def date_previous(self, cr, uid, ids, context=None):
|
||||
for sheet in self.browse(cr, uid, ids, context=context):
|
||||
if datetime.strptime(sheet.date_current, '%Y-%m-%d') <= datetime.strptime(sheet.date_from, '%Y-%m-%d'):
|
||||
self.write(cr, uid, [sheet.id], {'date_current': sheet.date_from,}, context=context)
|
||||
else:
|
||||
self.write(cr, uid, [sheet.id], {
|
||||
'date_current': (datetime.strptime(sheet.date_current, '%Y-%m-%d') + relativedelta(days=-1)).strftime('%Y-%m-%d'),
|
||||
}, context=context)
|
||||
return True
|
||||
|
||||
def date_next(self, cr, uid, ids, context=None):
|
||||
for sheet in self.browse(cr, uid, ids, context=context):
|
||||
if datetime.strptime(sheet.date_current, '%Y-%m-%d') >= datetime.strptime(sheet.date_to, '%Y-%m-%d'):
|
||||
self.write(cr, uid, [sheet.id], {'date_current': sheet.date_to,}, context=context)
|
||||
else:
|
||||
self.write(cr, uid, [sheet.id], {
|
||||
'date_current': (datetime.strptime(sheet.date_current, '%Y-%m-%d') + relativedelta(days=1)).strftime('%Y-%m-%d'),
|
||||
}, context=context)
|
||||
return True
|
||||
|
||||
def button_dummy(self, cr, uid, ids, context=None):
|
||||
for sheet in self.browse(cr, uid, ids, context=context):
|
||||
if datetime.strptime(sheet.date_current, '%Y-%m-%d') <= datetime.strptime(sheet.date_from, '%Y-%m-%d'):
|
||||
self.write(cr, uid, [sheet.id], {'date_current': sheet.date_from,}, context=context)
|
||||
elif datetime.strptime(sheet.date_current, '%Y-%m-%d') >= datetime.strptime(sheet.date_to, '%Y-%m-%d'):
|
||||
self.write(cr, uid, [sheet.id], {'date_current': sheet.date_to,}, context=context)
|
||||
return True
|
||||
|
||||
def attendance_action_change(self, cr, uid, ids, context=None):
|
||||
hr_employee = self.pool.get('hr.employee')
|
||||
employee_ids = []
|
||||
@@ -329,14 +194,13 @@ class hr_timesheet_sheet(osv.osv):
|
||||
'user_id': fields.related('employee_id', 'user_id', type="many2one", relation="res.users", store=True, string="User", required=False, readonly=True),#fields.many2one('res.users', 'User', required=True, select=1, states={'confirm':[('readonly', True)], 'done':[('readonly', True)]}),
|
||||
'date_from': fields.date('Date from', required=True, select=1, readonly=True, states={'new':[('readonly', False)]}),
|
||||
'date_to': fields.date('Date to', required=True, select=1, readonly=True, states={'new':[('readonly', False)]}),
|
||||
'date_current': fields.date('Current date', required=True, select=1),
|
||||
'timesheet_ids' : one2many_mod('hr.analytic.timesheet', 'sheet_id',
|
||||
'Timesheet lines', domain=[('date', '=', time.strftime('%Y-%m-%d'))],
|
||||
'timesheet_ids' : fields.one2many('hr.analytic.timesheet', 'sheet_id',
|
||||
'Timesheet lines',
|
||||
readonly=True, states={
|
||||
'draft': [('readonly', False)],
|
||||
'new': [('readonly', False)]}
|
||||
),
|
||||
'attendances_ids' : one2many_mod2('hr.attendance', 'sheet_id', 'Attendances'),
|
||||
'attendances_ids' : fields.one2many('hr.attendance', 'sheet_id', 'Attendances'),
|
||||
'state' : fields.selection([
|
||||
('new', 'New'),
|
||||
('draft','Open'),
|
||||
@@ -346,9 +210,6 @@ class hr_timesheet_sheet(osv.osv):
|
||||
\n* The \'Confirmed\' state is used for to confirm the timesheet by user. \
|
||||
\n* The \'Done\' state is used when users timesheet is accepted by his/her senior.'),
|
||||
'state_attendance' : fields.related('employee_id', 'state', type='selection', selection=[('absent', 'Absent'), ('present', 'Present')], string='Current Status', readonly=True),
|
||||
'total_attendance_day': fields.function(_total, method=True, string='Total Attendance', multi="_total"),
|
||||
'total_timesheet_day': fields.function(_total, method=True, string='Total Timesheet', multi="_total"),
|
||||
'total_difference_day': fields.function(_total, method=True, string='Difference', multi="_total"),
|
||||
'total_attendance': fields.function(_total, method=True, string='Total Attendance', multi="_total"),
|
||||
'total_timesheet': fields.function(_total, method=True, string='Total Timesheet', multi="_total"),
|
||||
'total_difference': fields.function(_total, method=True, string='Difference', multi="_total"),
|
||||
@@ -386,7 +247,6 @@ class hr_timesheet_sheet(osv.osv):
|
||||
|
||||
_defaults = {
|
||||
'date_from' : _default_date_from,
|
||||
'date_current' : lambda *a: time.strftime('%Y-%m-%d'),
|
||||
'date_to' : _default_date_to,
|
||||
'state': 'new',
|
||||
'employee_id': _default_employee,
|
||||
@@ -406,16 +266,9 @@ class hr_timesheet_sheet(osv.osv):
|
||||
return False
|
||||
return True
|
||||
|
||||
def _date_current_check(self, cr, uid, ids, context=None):
|
||||
for sheet in self.browse(cr, uid, ids, context=context):
|
||||
if sheet.date_current < sheet.date_from or sheet.date_current > sheet.date_to:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
_constraints = [
|
||||
(_sheet_date, 'You cannot have 2 timesheets that overlaps !\nPlease use the menu \'My Current Timesheet\' to avoid this problem.', ['date_from','date_to']),
|
||||
(_date_current_check, 'You must select a Current date which is in the timesheet dates !', ['date_current']),
|
||||
]
|
||||
|
||||
def action_set_to_draft(self, cr, uid, ids, *args):
|
||||
@@ -498,7 +351,7 @@ class hr_timesheet_line(osv.osv):
|
||||
|
||||
_columns = {
|
||||
'sheet_id': fields.function(_sheet, string='Sheet',
|
||||
type='many2one', relation='hr_timesheet_sheet.sheet',
|
||||
type='many2one', relation='hr_timesheet_sheet.sheet', ondelete="cascade",
|
||||
store={
|
||||
'hr_timesheet_sheet.sheet': (_get_hr_timesheet_sheet, ['employee_id', 'date_from', 'date_to'], 10),
|
||||
'account.analytic.line': (_get_account_analytic_line, ['user_id', 'date'], 10),
|
||||
@@ -534,6 +387,10 @@ class hr_timesheet_line(osv.osv):
|
||||
raise osv.except_osv(_('Error!'), _('You cannot modify an entry in a confirmed timesheet.'))
|
||||
return True
|
||||
|
||||
def multi_on_change_account_id(self, cr, uid, ids, account_ids, context=None):
|
||||
return dict([(el, self.on_change_account_id(cr, uid, ids, el)) for el in account_ids])
|
||||
|
||||
|
||||
hr_timesheet_line()
|
||||
|
||||
class hr_attendance(osv.osv):
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
<field name="name">Sheet 1</field>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="employee_id" ref="hr.employee_fp" />
|
||||
<field eval="time.strftime('%Y-%m-%d')" name="date_current"/>
|
||||
</record>
|
||||
-->
|
||||
</data>
|
||||
|
||||
@@ -71,20 +71,13 @@
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="Weekly">
|
||||
<widget type="weekly_timesheet">
|
||||
</widget>
|
||||
</page>
|
||||
<page string="Daily">
|
||||
<group>
|
||||
<div>
|
||||
<button name="button_dummy" class="oe_inline" string="Go to" type="object" icon="terp-gtk-jump-to-ltr"/> :
|
||||
<field name="date_current" class="oe_inline"/>
|
||||
</div>
|
||||
<div align="right">
|
||||
<button class="oe_inline" icon="terp-gtk-go-back-ltr" name="date_previous" string="" type="object"/>
|
||||
<button class="oe_inline" name="date_today" string="Today" type="object" icon="terp-go-today"/>
|
||||
<button class="oe_inline" icon="terp-gtk-go-back-rtl" name="date_next" string="" type="object"/>
|
||||
</div>
|
||||
</group>
|
||||
<group colspan="4" col="3">
|
||||
<field context="{'name':date_current,'user_id':user_id}" name="attendances_ids" nolabel="1" groups="base.group_hr_attendance">
|
||||
<field context="{'user_id':user_id}" name="attendances_ids" nolabel="1" groups="base.group_hr_attendance">
|
||||
<tree string="Attendances" editable="bottom">
|
||||
<field name="name"/>
|
||||
<field name="action"/>
|
||||
@@ -101,9 +94,9 @@
|
||||
<group col="4">
|
||||
<field name="state_attendance" groups="base.group_hr_attendance"/>
|
||||
</group>
|
||||
<field colspan="4" context="{'date':date_current,'user_id':user_id}" domain="[('name','=',date_current)]" name="timesheet_ids" nolabel="1">
|
||||
<field colspan="4" context="{'user_id':user_id}" name="timesheet_ids" nolabel="1">
|
||||
<tree editable="top" string="Timesheet Lines">
|
||||
<field invisible="1" name="date"/>
|
||||
<field name="date"/>
|
||||
<field domain="[('type','in',['normal', 'contract']), ('state', '<>', 'close'),('use_timesheets','=',1)]" name="account_id" on_change="on_change_account_id(account_id)" context="{'default_use_timesheets': 1}"/>
|
||||
<field name="name"/>
|
||||
<field name="unit_amount" on_change="on_change_unit_amount(product_id, unit_amount, False, product_uom_id,journal_id)" widget="float_time"/>
|
||||
|
||||
@@ -46,7 +46,6 @@ class timesheet_report(osv.osv):
|
||||
'department_id':fields.many2one('hr.department','Department',readonly=True),
|
||||
'date_from': fields.date('Date from',readonly=True,),
|
||||
'date_to': fields.date('Date to',readonly=True),
|
||||
'date_current': fields.date('Current date', required=True),
|
||||
'state' : fields.selection([
|
||||
('new', 'New'),
|
||||
('draft','Draft'),
|
||||
@@ -62,13 +61,9 @@ class timesheet_report(osv.osv):
|
||||
create or replace view timesheet_report as (
|
||||
select
|
||||
min(aal.id) as id,
|
||||
htss.date_current,
|
||||
htss.name,
|
||||
htss.date_from,
|
||||
htss.date_to,
|
||||
to_char(htss.date_current,'YYYY') as year,
|
||||
to_char(htss.date_current,'MM') as month,
|
||||
to_char(htss.date_current, 'YYYY-MM-DD') as day,
|
||||
count(*) as nbr,
|
||||
aal.unit_amount as quantity,
|
||||
aal.amount as cost,
|
||||
@@ -77,18 +72,15 @@ class timesheet_report(osv.osv):
|
||||
(SELECT sum(day.total_difference)
|
||||
FROM hr_timesheet_sheet_sheet AS sheet
|
||||
LEFT JOIN hr_timesheet_sheet_sheet_day AS day
|
||||
ON (sheet.id = day.sheet_id
|
||||
AND day.name = sheet.date_current) where sheet.id=htss.id) as total_diff,
|
||||
ON (sheet.id = day.sheet_id) where sheet.id=htss.id) as total_diff,
|
||||
(SELECT sum(day.total_timesheet)
|
||||
FROM hr_timesheet_sheet_sheet AS sheet
|
||||
LEFT JOIN hr_timesheet_sheet_sheet_day AS day
|
||||
ON (sheet.id = day.sheet_id
|
||||
AND day.name = sheet.date_current) where sheet.id=htss.id) as total_timesheet,
|
||||
ON (sheet.id = day.sheet_id) where sheet.id=htss.id) as total_timesheet,
|
||||
(SELECT sum(day.total_attendance)
|
||||
FROM hr_timesheet_sheet_sheet AS sheet
|
||||
LEFT JOIN hr_timesheet_sheet_sheet_day AS day
|
||||
ON (sheet.id = day.sheet_id
|
||||
AND day.name = sheet.date_current) where sheet.id=htss.id) as total_attendance,
|
||||
ON (sheet.id = day.sheet_id) where sheet.id=htss.id) as total_attendance,
|
||||
aal.to_invoice,
|
||||
aal.general_account_id,
|
||||
htss.user_id,
|
||||
@@ -99,15 +91,11 @@ class timesheet_report(osv.osv):
|
||||
left join hr_analytic_timesheet as hat ON (hat.line_id=aal.id)
|
||||
left join hr_timesheet_sheet_sheet as htss ON (hat.line_id=htss.id)
|
||||
group by
|
||||
to_char(htss.date_current,'YYYY'),
|
||||
to_char(htss.date_current,'MM'),
|
||||
to_char(htss.date_current, 'YYYY-MM-DD'),
|
||||
aal.account_id,
|
||||
htss.date_from,
|
||||
htss.date_to,
|
||||
aal.unit_amount,
|
||||
aal.amount,
|
||||
htss.date_current,
|
||||
aal.to_invoice,
|
||||
aal.product_id,
|
||||
aal.general_account_id,
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
<field name="model">timesheet.report</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree colors="blue:state == 'draft';black:state in ('confirm','new');gray:state == 'cancel'" string="Timesheet">
|
||||
<field name="date_current" invisible="1"/>
|
||||
<field name="name" invisible="1"/>
|
||||
<field name="user_id" invisible="1"/>
|
||||
<field name="date_from" invisible="1"/>
|
||||
@@ -56,7 +55,6 @@
|
||||
<field name="product_id"/>
|
||||
<field name="department_id"/>
|
||||
<field name="company_id" groups="base.group_multi_company"/>
|
||||
<field name="date_current"/>
|
||||
<field name="date_to"/>
|
||||
<field name="date_from"/>
|
||||
</group>
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
|
||||
.openerp .oe_timesheet_weekly {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.openerp .oe_timesheet_weekly table {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.openerp .oe_timesheet_weekly td {
|
||||
padding-top: 15px;
|
||||
}
|
||||
|
||||
.openerp .oe_timesheet_weekly th {
|
||||
text-align: right;
|
||||
color: #069;
|
||||
font-family: 'Helvetica Neue', Arial, Verdana, 'Nimbus Sans L', sans-serif;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.openerp .oe_timesheet_weekly th.oe_timesheet_weekly_date_head {
|
||||
width: 60px;
|
||||
}
|
||||
|
||||
.openerp .oe_timesheet_weekly td {
|
||||
text-align: right;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.openerp .oe_timesheet_weekly .oe_timesheet_weekly_account {
|
||||
text-align: left;
|
||||
padding-right: 30px;
|
||||
}
|
||||
|
||||
.openerp .oe_timesheet_weekly td input.oe_timesheet_weekly_input {
|
||||
border: 1px solid #CCC;
|
||||
padding: 5px 2px !important;
|
||||
color: #666 !important;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
width: 38px;
|
||||
text-align: right;
|
||||
min-width: 0 !important;
|
||||
}
|
||||
|
||||
.openerp .oe_timesheet_weekly td .oe_timesheet_weekly_box {
|
||||
padding: 5px 2px !important;
|
||||
color: #666 !important;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
width: 38px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.openerp .oe_timesheet_weekly .oe_timesheet_weekly_adding_tot {
|
||||
display: table;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.openerp .oe_timesheet_weekly .oe_timesheet_weekly_adding {
|
||||
display: table-cell;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.openerp .oe_timesheet_weekly .oe_timesheet_weekly_tottot {
|
||||
display: table-cell;
|
||||
}
|
||||
|
||||
.openerp .oe_timesheet_weekly .oe_timesheet_weekly_add_row td {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.openerp .oe_timesheet_weekly .oe_timesheet_weekly_add_row .oe_form_field_many2one {
|
||||
display: inline-block;
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
.openerp .oe_timesheet_weekly_today {
|
||||
}
|
||||
@@ -0,0 +1,299 @@
|
||||
|
||||
openerp.hr_timesheet_sheet = function(instance) {
|
||||
var QWeb = instance.web.qweb;
|
||||
var _t = instance.web._t;
|
||||
|
||||
instance.hr_timesheet_sheet.WeeklyTimesheet = instance.web.form.FormWidget.extend(instance.web.form.ReinitializeWidgetMixin, {
|
||||
init: function() {
|
||||
this._super.apply(this, arguments);
|
||||
this.set({
|
||||
sheets: [],
|
||||
date_to: false,
|
||||
date_from: false,
|
||||
});
|
||||
this.field_manager.on("field_changed:timesheet_ids", this, this.query_sheets);
|
||||
this.field_manager.on("field_changed:date_from", this, function() {
|
||||
this.set({"date_from": instance.web.str_to_date(this.field_manager.get_field_value("date_from"))});
|
||||
});
|
||||
this.field_manager.on("field_changed:date_to", this, function() {
|
||||
this.set({"date_to": instance.web.str_to_date(this.field_manager.get_field_value("date_to"))});
|
||||
});
|
||||
this.field_manager.on("field_changed:user_id", this, function() {
|
||||
this.set({"user_id": this.field_manager.get_field_value("user_id")});
|
||||
});
|
||||
this.on("change:sheets", this, this.update_sheets);
|
||||
this.res_o2m_drop = new instance.web.DropMisordered();
|
||||
this.render_drop = new instance.web.DropMisordered();
|
||||
this.description_line = _t("/");
|
||||
},
|
||||
query_sheets: function() {
|
||||
var self = this;
|
||||
if (self.updating)
|
||||
return;
|
||||
var commands = this.field_manager.get_field_value("timesheet_ids");
|
||||
this.res_o2m_drop.add(new instance.web.Model(this.view.model).call("resolve_2many_commands", ["timesheet_ids", commands, [],
|
||||
new instance.web.CompoundContext()]))
|
||||
.then(function(result) {
|
||||
self.querying = true;
|
||||
self.set({sheets: result});
|
||||
self.querying = false;
|
||||
});
|
||||
},
|
||||
update_sheets: function() {
|
||||
var self = this;
|
||||
if (self.querying)
|
||||
return;
|
||||
self.updating = true;
|
||||
self.field_manager.set_values({timesheet_ids: self.get("sheets")}).then(function() {
|
||||
self.updating = false;
|
||||
});
|
||||
},
|
||||
initialize_field: function() {
|
||||
instance.web.form.ReinitializeWidgetMixin.initialize_field.call(this);
|
||||
var self = this;
|
||||
self.on("change:sheets", self, self.initialize_content);
|
||||
self.on("change:date_to", self, self.initialize_content);
|
||||
self.on("change:date_from", self, self.initialize_content);
|
||||
self.on("change:user_id", self, self.initialize_content);
|
||||
},
|
||||
initialize_content: function() {
|
||||
var self = this;
|
||||
if (self.setting)
|
||||
return;
|
||||
// don't render anything until we have date_to and date_from
|
||||
if (!self.get("date_to") || !self.get("date_from"))
|
||||
return;
|
||||
this.destroy_content();
|
||||
|
||||
// it's important to use those vars to avoid race conditions
|
||||
var dates;
|
||||
var accounts;
|
||||
var account_names;
|
||||
var default_get;
|
||||
return this.render_drop.add(new instance.web.Model("hr.analytic.timesheet").call("default_get", [
|
||||
['account_id','general_account_id', 'journal_id','date','name','user_id','product_id','product_uom_id','to_invoice','amount','unit_amount'],
|
||||
new instance.web.CompoundContext({'user_id': self.get('user_id')})]).pipe(function(result) {
|
||||
default_get = result;
|
||||
// calculating dates
|
||||
dates = [];
|
||||
var start = self.get("date_from");
|
||||
var end = self.get("date_to");
|
||||
while (start <= end) {
|
||||
dates.push(start);
|
||||
start = start.clone().addDays(1);
|
||||
}
|
||||
// group by account
|
||||
accounts = _(self.get("sheets")).chain()
|
||||
.map(function(el) {
|
||||
// much simpler to use only the id in all cases
|
||||
if (typeof(el.account_id) === "object")
|
||||
el.account_id = el.account_id[0];
|
||||
return el;
|
||||
})
|
||||
.groupBy("account_id").value();
|
||||
|
||||
var account_ids = _.map(_.keys(accounts), function(el) { return el === "false" ? false : Number(el) });
|
||||
|
||||
return new instance.web.Model("hr.analytic.timesheet").call("multi_on_change_account_id", [[], account_ids,
|
||||
new instance.web.CompoundContext({'user_id': self.get('user_id')})]).pipe(function(accounts_defaults) {
|
||||
accounts = _(accounts).chain().map(function(lines, account_id) {
|
||||
account_defaults = _.extend({}, default_get, accounts_defaults[account_id]);
|
||||
// group by days
|
||||
account_id = account_id === "false" ? false : Number(account_id);
|
||||
var index = _.groupBy(lines, "date");
|
||||
var days = _.map(dates, function(date) {
|
||||
var day = {day: date, lines: index[instance.web.date_to_str(date)] || []};
|
||||
// add line where we will insert/remove hours
|
||||
var to_add = _.find(day.lines, function(line) { return line.name === self.description_line });
|
||||
if (to_add) {
|
||||
day.lines = _.without(day.lines, to_add);
|
||||
day.lines.unshift(to_add);
|
||||
} else {
|
||||
day.lines.unshift(_.extend(_.clone(account_defaults), {
|
||||
name: self.description_line,
|
||||
unit_amount: 0,
|
||||
date: instance.web.date_to_str(date),
|
||||
account_id: account_id,
|
||||
}));
|
||||
}
|
||||
return day;
|
||||
});
|
||||
return {account: account_id, days: days, account_defaults: account_defaults};
|
||||
}).value();
|
||||
|
||||
// we need the name_get of the analytic accounts
|
||||
return new instance.web.Model("account.analytic.account").call("name_get", [_.pluck(accounts, "account"),
|
||||
new instance.web.CompoundContext()]).pipe(function(result) {
|
||||
account_names = {};
|
||||
_.each(result, function(el) {
|
||||
account_names[el[0]] = el[1];
|
||||
});
|
||||
accounts = _.sortBy(accounts, function(el) {
|
||||
return account_names[el.account];
|
||||
});
|
||||
});;
|
||||
});
|
||||
})).pipe(function(result) {
|
||||
// we put all the gathered data in self, then we render
|
||||
self.dates = dates;
|
||||
self.accounts = accounts;
|
||||
self.account_names = account_names;
|
||||
self.default_get = default_get;
|
||||
//real rendering
|
||||
self.display_data();
|
||||
});
|
||||
},
|
||||
destroy_content: function() {
|
||||
if (this.dfm) {
|
||||
this.dfm.destroy();
|
||||
this.dfm = undefined;
|
||||
}
|
||||
},
|
||||
display_data: function() {
|
||||
var self = this;
|
||||
self.$el.html(QWeb.render("hr_timesheet_sheet.WeeklyTimesheet", {widget: self}));
|
||||
_.each(self.accounts, function(account) {
|
||||
_.each(_.range(account.days.length), function(day_count) {
|
||||
if (!self.get('effective_readonly')) {
|
||||
self.get_box(account, day_count).val(self.sum_box(account, day_count)).change(function() {
|
||||
var num = Number($(this).val());
|
||||
if (isNaN(num)) {
|
||||
$(this).val(self.sum_box(account, day_count));
|
||||
} else {
|
||||
account.days[day_count].lines[0].unit_amount += num - self.sum_box(account, day_count);
|
||||
self.display_totals();
|
||||
self.sync();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
self.get_box(account, day_count).html(self.sum_box(account, day_count));
|
||||
}
|
||||
});
|
||||
});
|
||||
self.display_totals();
|
||||
self.$(".oe_timesheet_weekly_adding button").click(_.bind(this.init_add_account, this));
|
||||
},
|
||||
init_add_account: function() {
|
||||
var self = this;
|
||||
if (self.dfm)
|
||||
return;
|
||||
self.$(".oe_timesheet_weekly_add_row").show();
|
||||
self.dfm = new instance.web.form.DefaultFieldManager(self);
|
||||
self.dfm.extend_field_desc({
|
||||
account: {
|
||||
relation: "account.analytic.account",
|
||||
},
|
||||
});
|
||||
self.account_m2o = new instance.web.form.FieldMany2One(self.dfm, {
|
||||
attrs: {
|
||||
name: "account",
|
||||
type: "many2one",
|
||||
domain: [
|
||||
['type','in',['normal', 'contract']],
|
||||
['state', '<>', 'close'],
|
||||
['use_timesheets','=',1],
|
||||
['id', 'not in', _.pluck(self.accounts, "account")],
|
||||
],
|
||||
modifiers: '{"required": true}',
|
||||
},
|
||||
});
|
||||
self.account_m2o.prependTo(self.$(".oe_timesheet_weekly_add_row td"));
|
||||
self.$(".oe_timesheet_weekly_add_row button").click(function() {
|
||||
var id = self.account_m2o.get_value();
|
||||
if (id === false) {
|
||||
self.dfm.set({display_invalid_fields: true});
|
||||
return;
|
||||
}
|
||||
var ops = self.generate_o2m_value();
|
||||
new instance.web.Model("hr.analytic.timesheet").call("on_change_account_id", [[], id]).pipe(function(res) {
|
||||
var def = _.extend({}, self.default_get, res.value, {
|
||||
name: self.description_line,
|
||||
unit_amount: 0,
|
||||
date: instance.web.date_to_str(self.dates[0]),
|
||||
account_id: id,
|
||||
});
|
||||
ops.push(def);
|
||||
self.set({"sheets": ops});
|
||||
});
|
||||
});
|
||||
},
|
||||
get_box: function(account, day_count) {
|
||||
return this.$('[data-account="' + account.account + '"][data-day-count="' + day_count + '"]');
|
||||
},
|
||||
get_total: function(account) {
|
||||
return this.$('[data-account-total="' + account.account + '"]');
|
||||
},
|
||||
get_day_total: function(day_count) {
|
||||
return this.$('[data-day-total="' + day_count + '"]');
|
||||
},
|
||||
get_super_total: function() {
|
||||
return this.$('.oe_timesheet_weekly_supertotal');
|
||||
},
|
||||
sum_box: function(account, day_count) {
|
||||
var line_total = 0;
|
||||
_.each(account.days[day_count].lines, function(line) {
|
||||
line_total += line.unit_amount;
|
||||
});
|
||||
return line_total;
|
||||
},
|
||||
display_totals: function() {
|
||||
var self = this;
|
||||
var day_tots = _.map(_.range(self.dates.length), function() { return 0 });
|
||||
var super_tot = 0;
|
||||
_.each(self.accounts, function(account) {
|
||||
var acc_tot = 0;
|
||||
_.each(_.range(self.dates.length), function(day_count) {
|
||||
var sum = self.sum_box(account, day_count);
|
||||
acc_tot += sum;
|
||||
day_tots[day_count] += sum;
|
||||
super_tot += sum;
|
||||
});
|
||||
self.get_total(account).html(acc_tot);
|
||||
});
|
||||
_.each(_.range(self.dates.length), function(day_count) {
|
||||
self.get_day_total(day_count).html(day_tots[day_count]);
|
||||
});
|
||||
self.get_super_total().html(super_tot);
|
||||
},
|
||||
sync: function() {
|
||||
var self = this;
|
||||
self.setting = true;
|
||||
self.set({sheets: this.generate_o2m_value()});
|
||||
self.setting = false;
|
||||
},
|
||||
generate_o2m_value: function() {
|
||||
var self = this;
|
||||
var ops = [];
|
||||
|
||||
_.each(self.accounts, function(account) {
|
||||
var auth_keys = _.extend(_.clone(account.account_defaults), {
|
||||
name: true, unit_amount: true, date: true, account_id:true,
|
||||
});
|
||||
_.each(account.days, function(day) {
|
||||
_.each(day.lines, function(line) {
|
||||
if (line.unit_amount !== 0) {
|
||||
var tmp = _.clone(line);
|
||||
tmp.id = undefined;
|
||||
_.each(line, function(v, k) {
|
||||
if (v instanceof Array) {
|
||||
tmp[k] = v[0];
|
||||
}
|
||||
});
|
||||
// we have to remove some keys, because analytic lines are shitty
|
||||
_.each(_.keys(tmp), function(key) {
|
||||
if (auth_keys[key] === undefined) {
|
||||
tmp[key] = undefined;
|
||||
}
|
||||
});
|
||||
ops.push(tmp);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
return ops;
|
||||
},
|
||||
});
|
||||
|
||||
instance.web.form.custom_widgets.add('weekly_timesheet', 'instance.hr_timesheet_sheet.WeeklyTimesheet');
|
||||
|
||||
};
|
||||
@@ -0,0 +1,56 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<templates>
|
||||
<t t-name="hr_timesheet_sheet.WeeklyTimesheet">
|
||||
<div class="oe_timesheet_weekly">
|
||||
<table>
|
||||
<tr>
|
||||
<th> </th>
|
||||
<t t-foreach="widget.dates" t-as="date">
|
||||
<th t-att-class="'oe_timesheet_weekly_date_head' + (Date.compare(date, Date.today()) === 0 ? ' oe_timesheet_weekly_today' : '')">
|
||||
<t t-esc="date.toString('ddd')"/><br />
|
||||
<t t-esc="date.toString('MMM d')"/>
|
||||
</th>
|
||||
</t>
|
||||
<th class="oe_timesheet_weekly_date_head">TOTAL</th>
|
||||
</tr>
|
||||
<tr t-foreach="widget.accounts" t-as="account">
|
||||
<td class="oe_timesheet_weekly_account"><t t-esc="widget.account_names[account.account]"/></td>
|
||||
<t t-set="day_count" t-value="0"/>
|
||||
<t t-foreach="account.days" t-as="day">
|
||||
<td t-att-class="(Date.compare(day.day, Date.today()) === 0 ? 'oe_timesheet_weekly_today' : '')">
|
||||
<input t-if="!widget.get('effective_readonly')" class="oe_timesheet_weekly_input" t-att-data-account="account.account"
|
||||
t-att-data-day-count="day_count" type="text"/>
|
||||
<span t-if="widget.get('effective_readonly')" t-att-data-account="account.account"
|
||||
t-att-data-day-count="day_count" class="oe_timesheet_weekly_box"/>
|
||||
<t t-set="day_count" t-value="day_count + 1"/>
|
||||
</td>
|
||||
</t>
|
||||
<td t-att-data-account-total="account.account"> </td>
|
||||
</tr>
|
||||
<tr class="oe_timesheet_weekly_add_row" style="display: none">
|
||||
<td t-att-colspan="widget.dates.length + 2">
|
||||
<button>Add</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="oe_timesheet_weekly_adding_tot">
|
||||
<div class="oe_timesheet_weekly_adding"><button>Add Row</button></div>
|
||||
<div class="oe_timesheet_weekly_tottot"><span>TOTAL</span></div>
|
||||
</div>
|
||||
</td>
|
||||
<t t-set="day_count" t-value="0"/>
|
||||
<t t-foreach="widget.dates" t-as="date">
|
||||
<td t-att-class="(Date.compare(date, Date.today()) === 0 ? 'oe_timesheet_weekly_today' : '')">
|
||||
<span class="oe_timesheet_weekly_box" t-att-data-day-total="day_count">
|
||||
</span>
|
||||
<t t-set="day_count" t-value="day_count + 1"/>
|
||||
</td>
|
||||
</t>
|
||||
<td class="oe_timesheet_weekly_supertotal"> </td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
@@ -16,7 +16,6 @@
|
||||
I create a timesheet for employee "Quentin Paolinon".
|
||||
-
|
||||
!record {model: hr_timesheet_sheet.sheet, id: hr_timesheet_sheet_sheet_deddk0}:
|
||||
date_current: !eval time.strftime('%Y-%m-%d')
|
||||
date_from: !eval time.strftime('%Y-%m-01')
|
||||
name: Quentin Paolinon
|
||||
state: new
|
||||
@@ -34,30 +33,6 @@
|
||||
-
|
||||
!assert {model: hr.employee, id: hr.employee_qdp}:
|
||||
- state == 'present'
|
||||
-
|
||||
I want to check attendance and work of yesterday. I click on <- button.
|
||||
-
|
||||
!python {model: hr_timesheet_sheet.sheet}: |
|
||||
date_prev = self.date_previous(cr, uid, [ref('hr_timesheet_sheet_sheet_deddk0')], None)
|
||||
assert date_prev == True, "I See Previous Date Timesheet"
|
||||
-
|
||||
Then I click on "Today" button to fill today's timesheet.
|
||||
-
|
||||
!python {model: hr_timesheet_sheet.sheet}: |
|
||||
date_to = self.date_today(cr, uid, [ref('hr_timesheet_sheet_sheet_deddk0')], None)
|
||||
assert date_to == True, "I See Today Date Timesheet"
|
||||
-
|
||||
I can also move to next day by clicking on -> button.
|
||||
-
|
||||
!python {model: hr_timesheet_sheet.sheet}: |
|
||||
date_next = self.date_next(cr, uid, [ref('hr_timesheet_sheet_sheet_deddk0')], None)
|
||||
assert date_next == True, "I See Next Date Timesheet"
|
||||
-
|
||||
I want to go to a particular date and see attendance then I select the date and click on "Go to:" button.
|
||||
-
|
||||
!python {model: hr_timesheet_sheet.sheet}: |
|
||||
button_dumy = self.button_dummy(cr, uid, [ref('hr_timesheet_sheet_sheet_deddk0')], None)
|
||||
assert button_dumy == True, "I See Particular Date Attendance"
|
||||
-
|
||||
At the time of logout, I create attendance and perform "Sign Out".
|
||||
-
|
||||
|
||||
@@ -42,7 +42,6 @@ class hr_timesheet_current_open(osv.osv_memory):
|
||||
view_type = 'tree,form'
|
||||
domain = "[('id','in',["+','.join(map(str, ids))+"]),('user_id', '=', uid)]"
|
||||
elif len(ids)==1:
|
||||
ts.write(cr, uid, ids, {'date_current': time.strftime('%Y-%m-%d')}, context=context)
|
||||
domain = "[('user_id', '=', uid)]"
|
||||
else:
|
||||
domain = "[('user_id', '=', uid)]"
|
||||
|
||||
@@ -45,7 +45,6 @@
|
||||
Create a timesheet sheet for HR manager
|
||||
-
|
||||
!record {model: hr_timesheet_sheet.sheet, id: hr_timesheet_sheet_sheet_sheetforhrmanager0}:
|
||||
date_current: !eval time.strftime('%Y-05-%d')
|
||||
date_from: !eval "'%s-05-01' %(datetime.now().year)"
|
||||
date_to: !eval "'%s-05-31' %(datetime.now().year)"
|
||||
name: Sheet for hr manager
|
||||
|
||||
Reference in New Issue
Block a user