Ravi Gadhia (OpenERP) has proposed merging
lp:~openerp-dev/openobject-addons/trunk-feature-hr_timesheet into
lp:openobject-addons.
Requested reviews:
OpenERP Core Team (openerp)
For more details, see:
https://code.launchpad.net/~openerp-dev/openobject-addons/trunk-feature-hr_timesheet/+merge/100359
Developed day and week view in hr_timesheet_sheet.
here is the pad for technical specification:
http://pad.openerp.com/rd-v62-project-task-236-Z07B0K1X
--
https://code.launchpad.net/~openerp-dev/openobject-addons/trunk-feature-hr_timesheet/+merge/100359
Your team OpenERP R&D Team is subscribed to branch
lp:~openerp-dev/openobject-addons/trunk-feature-hr_timesheet.
=== modified file 'hr_timesheet/hr_timesheet.py'
--- hr_timesheet/hr_timesheet.py 2012-02-14 12:25:20 +0000
+++ hr_timesheet/hr_timesheet.py 2012-04-02 06:22:20 +0000
@@ -187,6 +187,12 @@
'general_account_id': self._getGeneralAccount(cr, uid, context),
'journal_id': self._getAnalyticJournal(cr, uid, context),
}}
+
+ def default_get(self, cr, uid, fields, context=None):
+ data = super(hr_analytic_timesheet, self).default_get(cr, uid, fields, context=context)
+ if context.get('current_date'):
+ data['date'] = context['current_date']
+ return data
hr_analytic_timesheet()
=== modified file 'hr_timesheet/hr_timesheet_demo.xml'
--- hr_timesheet/hr_timesheet_demo.xml 2011-12-22 13:35:59 +0000
+++ hr_timesheet/hr_timesheet_demo.xml 2012-04-02 06:22:20 +0000
@@ -16,7 +16,7 @@
<record id="working_hours_requirements" model="hr.analytic.timesheet">
<field name="name">Requirements analysis and specification</field>
<field name="user_id" ref="base.user_root"/>
- <field eval="time.strftime('%Y-%m-%d')" name="date"/>
+ <field eval="(DateTime.today() - timedelta(days=DateTime.today().weekday()) + timedelta(days=1)).strftime('%Y-%m-%d')" name="date"/>
<field eval="2.00" name="unit_amount"/>
<field name="product_id" ref="product.product_consultant"/>
<field name="product_uom_id" ref="product.uom_hour"/>
@@ -29,7 +29,7 @@
<record id="working_hours_design" model="hr.analytic.timesheet">
<field name="name">Design and specification</field>
<field name="user_id" ref="base.user_root"/>
- <field eval="time.strftime('%Y-%m-%d')" name="date"/>
+ <field eval="(DateTime.today() - timedelta(days=DateTime.today().weekday()) + timedelta(days=2)).strftime('%Y-%m-%d')" name="date"/>
<field eval="1.00" name="unit_amount"/>
<field name="product_id" ref="product.product_consultant"/>
<field name="product_uom_id" ref="product.uom_hour"/>
@@ -42,7 +42,7 @@
<record id="working_hours_coding" model="hr.analytic.timesheet">
<field name="name">Coding and module testing</field>
<field name="user_id" ref="base.user_root"/>
- <field eval="time.strftime('%Y-%m-%d')" name="date"/>
+ <field eval="(DateTime.today() - timedelta(days=DateTime.today().weekday()) + timedelta(days=3)).strftime('%Y-%m-%d')" name="date"/>
<field eval="03.00" name="unit_amount"/>
<field name="product_id" ref="product.product_consultant"/>
<field name="product_uom_id" ref="product.uom_hour"/>
@@ -55,7 +55,7 @@
<record id="working_hours_testing" model="hr.analytic.timesheet">
<field name="name">Integration and system testing</field>
<field name="user_id" ref="base.user_root"/>
- <field eval="time.strftime('%Y-%m-%d')" name="date"/>
+ <field eval="(DateTime.today() - timedelta(days=DateTime.today().weekday()) + timedelta(days=4)).strftime('%Y-%m-%d')" name="date"/>
<field eval="01.00" name="unit_amount"/>
<field name="product_id" ref="product.product_consultant"/>
<field name="product_uom_id" ref="product.uom_hour"/>
@@ -68,7 +68,7 @@
<record id="working_hours_maintenance" model="hr.analytic.timesheet">
<field name="name">Delivery and maintenance</field>
<field name="user_id" ref="base.user_root"/>
- <field eval="time.strftime('%Y-%m-%d')" name="date"/>
+ <field eval="(DateTime.today() - timedelta(days=DateTime.today().weekday()) + timedelta(days=5)).strftime('%Y-%m-%d')" name="date"/>
<field eval="01.00" name="unit_amount"/>
<field name="product_id" ref="product.product_consultant"/>
<field name="product_uom_id" ref="product.uom_hour"/>
=== modified file 'hr_timesheet_sheet/__openerp__.py'
--- hr_timesheet_sheet/__openerp__.py 2012-02-13 15:27:55 +0000
+++ hr_timesheet_sheet/__openerp__.py 2012-04-02 06:22:20 +0000
@@ -71,5 +71,9 @@
'auto_install': False,
'certificate': '0073297700829',
'application': True,
+ #web
+ "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:
=== modified file 'hr_timesheet_sheet/hr_timesheet_sheet.py'
--- hr_timesheet_sheet/hr_timesheet_sheet.py 2012-03-13 15:03:47 +0000
+++ hr_timesheet_sheet/hr_timesheet_sheet.py 2012-04-02 06:22:20 +0000
@@ -26,6 +26,7 @@
from osv import fields, osv
from tools.translate import _
import netsvc
+mode = "day"
class one2many_mod2(fields.one2many):
def get(self, cr, obj, ids, name, user=None, offset=0, context=None, values=None):
@@ -74,21 +75,20 @@
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)
+ res5 = obj.read(cr, user, ids, ['date_current', 'view_mode'], context=context)
res6 = {}
for r in res5:
res6[r['id']] = r['date_current']
-
+ view_mode = r.get('view_mode', 'day')
ids2 = []
for id in ids:
dom = []
if id in res6:
- dom = [('date', '=', res6[id]), ('sheet_id', '=', id)]
+ dom = [('date', '=', res6[id]),('sheet_id', '=', id)]
+ if view_mode == "week":
+ dom = [('sheet_id', '=', id)]
ids2.extend(obj.pool.get(self._obj).search(cr, user,
dom, limit=self._limit))
res = {}
@@ -303,6 +303,14 @@
'date_current': (datetime.strptime(sheet.date_current, '%Y-%m-%d') + relativedelta(days=1)).strftime('%Y-%m-%d'),
}, context=context)
return True
+
+ def day(self, cr, uid, ids, context=None):
+ self.write(cr, uid, ids, {'view_mode': 'day'})
+ return True
+
+ def week(self, cr, uid, ids, context=None):
+ self.write(cr, uid, ids, {'view_mode': 'week'})
+ return True
def button_dummy(self, cr, uid, ids, context=None):
for sheet in self.browse(cr, uid, ids, context=context):
@@ -347,7 +355,7 @@
'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 lines',
readonly=True, states={
'draft': [('readonly', False)],
'new': [('readonly', False)]}
@@ -372,8 +380,10 @@
'account_ids': fields.one2many('hr_timesheet_sheet.sheet.account', 'sheet_id', 'Analytic accounts', readonly=True),
'company_id': fields.many2one('res.company', 'Company'),
'department_id':fields.many2one('hr.department','Department'),
+ 'view_mode' : fields.selection([
+ ('day', 'Day'),
+ ('week','week')], string="View Mode"),
}
-
def _default_date_from(self,cr, uid, context=None):
user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
r = user.company_id and user.company_id.timesheet_range or 'month'
@@ -401,6 +411,7 @@
return emp_ids and emp_ids[0] or False
_defaults = {
+ 'view_mode': 'day',
'date_from' : _default_date_from,
'date_current' : lambda *a: time.strftime('%Y-%m-%d'),
'date_to' : _default_date_to,
@@ -421,7 +432,20 @@
if cr.fetchall():
return False
return True
-
+
+ def _account_check(self, cr, uid, ids, context=None):
+ for sheet in self.browse(cr, uid, ids, context=context):
+ account_ids = []
+ for timesheet_line in sheet.timesheet_ids:
+ account_id = timesheet_line.line_id.account_id.id
+ if account_id in account_ids and sheet.view_mode == 'day':
+ return False
+ else:
+ account_ids.append(account_id)
+ 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:
@@ -432,6 +456,7 @@
_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']),
+ #(_account_check, 'Account name must be unique per timesheet lines !', ['timesheet_ids']),
]
def action_set_to_draft(self, cr, uid, ids, *args):
@@ -468,7 +493,7 @@
class hr_timesheet_line(osv.osv):
_inherit = "hr.analytic.timesheet"
-
+
def _get_default_date(self, cr, uid, context=None):
if context is None:
context = {}
@@ -511,6 +536,7 @@
return ts_line_ids
_columns = {
+ 'current_work_time': fields.datetime('Current work time'),
'sheet_id': fields.function(_sheet, string='Sheet',
type='many2one', relation='hr_timesheet_sheet.sheet',
store={
@@ -523,7 +549,21 @@
_defaults = {
'date': _get_default_date,
}
-
+ def work_start(self,cr, uid, ids, context=None):
+ ids_to_stop = self.search(cr, uid, [('current_work_time','!=',False)], context=context)
+ self.work_stop(cr, uid, ids_to_stop, context)
+ for work in self.browse(cr,uid,ids,context=context):
+ work.write({'current_work_time':time.strftime('%Y-%m-%d %H:%M:%S')})
+ return True
+
+ def work_stop(self, cr, uid, ids, context=None):
+ for work in self.browse(cr,uid,ids,context=context):
+ current_work_date = datetime.strptime(work.current_work_time, '%Y-%m-%d %H:%M:%S')
+ unit_amount = (datetime.now() - current_work_date).seconds / 360
+ unit_amount += work.unit_amount
+ work.write({'unit_amount':unit_amount,'current_work_time':False})
+ return True
+
def _check_sheet_state(self, cr, uid, ids, context=None):
if context is None:
context = {}
@@ -541,7 +581,7 @@
ids = [ids]
self._check(cr, uid, ids)
return super(hr_timesheet_line,self).unlink(cr, uid, ids,*args, **kwargs)
-
+
def _check(self, cr, uid, ids):
for att in self.browse(cr, uid, ids):
if att.sheet_id and att.sheet_id.state not in ('draft', 'new'):
@@ -609,6 +649,7 @@
def create(self, cr, uid, vals, context=None):
if context is None:
context = {}
+ print "create \n\n\n",vals, context
if 'sheet_id' in context:
ts = self.pool.get('hr_timesheet_sheet.sheet').browse(cr, uid, context['sheet_id'], context=context)
if ts.state not in ('draft', 'new'):
@@ -645,6 +686,16 @@
if att.sheet_id and att.sheet_id.state not in ('draft', 'new'):
raise osv.except_osv(_('Error !'), _('You cannot modify an entry in a confirmed timesheet !'))
return True
+
+ def work_start(self, cr, uid, ids, context=None):
+ if context is None:
+ context = {}
+ return True
+
+ def work_stop(self, cr, uid, ids, context=None):
+ if context is None:
+ context = {}
+ return True
hr_attendance()
=== modified file 'hr_timesheet_sheet/hr_timesheet_sheet_view.xml'
--- hr_timesheet_sheet/hr_timesheet_sheet_view.xml 2012-02-13 15:27:55 +0000
+++ hr_timesheet_sheet/hr_timesheet_sheet_view.xml 2012-04-02 06:22:20 +0000
@@ -77,9 +77,6 @@
<button name="button_dummy" string="Go to:" type="object" icon="terp-gtk-jump-to-ltr"/>
<field name="date_current" nolabel="1"/>
<label string=""/>
- <button icon="terp-gtk-go-back-ltr" name="date_previous" string="" type="object"/>
- <button name="date_today" string="Today" type="object" icon="terp-go-today"/>
- <button icon="terp-gtk-go-back-rtl" name="date_next" string="" type="object"/>
</group>
<field colspan="3" context="{'name':date_current,'user_id':user_id}" height="100" name="attendances_ids" nolabel="1">
@@ -95,13 +92,22 @@
<button name="sign_out" string="Sign Out" type="object" icon="terp-gtk-jump-to-rtl"/>
<field name="total_attendance_day" widget="float_time" colspan="4"/>
</group>
- <field colspan="4" context="{'date':date_current,'user_id':user_id}" domain="[('name','=',date_current)]" name="timesheet_ids" nolabel="1">
- <tree editable="top" string="Timesheet Lines">
- <field invisible="1" name="date"/>
- <field domain="[('type','=','normal'), ('state', '<>', 'close')]" name="account_id" on_change="on_change_account_id(account_id)"/>
- <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"/>
- <field name="to_invoice" widget="selection"/>
+ </page>
+ <page string="Work Details">
+ <field colspan="4" name="timesheet_ids" nolabel="1" widget="timesheet_track" context="{'current_date': date_current}" domain="[('view_mode','=','day'),('sheet_id','=',sheet_id),('date','=',date_current)]">
+ <button name="date_previous" string="" type="object"/>
+ <button name="date_next" string="" type="object"/>
+ <button name="day" string="" context="{'mode': 'day'}" type="object"/>
+ <button name="week" string="" context="{'mode': 'week'}" type="object"/>
+ <tree editable="top" >
+ <field invisible="1" name="date"/>
+ <field invisible="1" name="current_work_time" />
+ <field domain="[('type','=','normal'), ('state', '<>', 'close')]" name="account_id" on_change="on_change_account_id(account_id)" widget="selection"/>
+ <field name="name" widget="text"/>
+ <field name="unit_amount" sum="Total" on_change="on_change_unit_amount(product_id, unit_amount, False, product_uom_id,journal_id)" widget="float_time"/>
+ <button name="work_start" string="" icon="terp-project" type="object" attrs="{'invisible':[('current_work_time','!=',False)]}"/>
+ <button name="work_stop" string="" icon="STOCK_STOP" type="object" attrs="{'invisible':[('current_work_time','=',False)]}"/>
+ <field invisible="1" name="to_invoice" widget="selection"/>
<field invisible="1" name="journal_id"/>
<field invisible="1" name="product_id" domain="[('type','=','service')]" on_change="on_change_unit_amount(product_id, unit_amount, False, product_uom_id,journal_id)"/>
<field invisible="1" name="product_uom_id" on_change="on_change_unit_amount(product_id, unit_amount, False, product_uom_id,journal_id)"/>
=== added directory 'hr_timesheet_sheet/static/src/css'
=== added file 'hr_timesheet_sheet/static/src/css/timesheet.css'
--- hr_timesheet_sheet/static/src/css/timesheet.css 1970-01-01 00:00:00 +0000
+++ hr_timesheet_sheet/static/src/css/timesheet.css 2012-04-02 06:22:20 +0000
@@ -0,0 +1,242 @@
+.week_view_header{
+ color : black;
+ font-size: 10px;
+ text-transform: capitalize;
+ font-weight:normal;
+ font-family: Ubuntu, Helvetica, sans-serif;
+}
+.week_header{
+ color : #666666;
+ text-align: center !important;
+ font-size: 10px;
+ text-transform: capitalize;
+ font-weight:normal;
+ font-family: Ubuntu, Helvetica, sans-serif;
+}
+.week_view{
+ background: #EEE;
+}
+.timesheet-header th {
+ background: #EEE !important;
+ border: 1px solid #D5D5D5;
+ padding: 12px 12px;
+ margin: 15px 0 0 0;
+ -webkit-border-top-left-radius: 8px;
+ -webkit-border-top-right-radius: 8px;
+ -moz-border-radius-topleft: 8px;
+ -moz-border-radius-topright: 8px;
+ border-top-left-radius: 8px;
+ border-top-right-radius: 8px;
+ background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0.15, #F7F7F7), color-stop(0.58, #DFDFDF));
+ background-image: -moz-linear-gradient(center top, #F7F7F7 15%, #DFDFDF 58%);
+}
+
+.timesheet-header a.title {
+ background: none;
+ text-indent: 0px;
+ padding:2px;
+}
+.timesheet-header a.title span {
+ font-size: 14px;
+ color: #777;
+}
+
+.timesheet-header .view_selector {
+ display: inline;
+ height: 23px;
+ margin: 0;
+ /*vertical-align: middle;
+ padding: 1px 2px;*/
+}
+
+.view_selector ul.info {
+ float: left;
+ padding: 0;
+}
+
+.view_selector ul.pagination {
+ float: right;
+ /*margin: -5px 0 0 0;
+ padding: 0 */;
+}
+
+.view_selector li {
+ display: inline;
+ margin: 0;
+ padding: 0;
+}
+
+.view_selector li a {
+ background: url(../img/timesheetcontrols.gif?1329850867) no-repeat;
+ float: left;
+ text-indent: -9999px;
+ height: 23px;
+ padding-top: 0px;
+ font-size: 0;
+ border: 0;
+ overflow: hidden;
+ background-position: -241px -1px;
+ cursor: pointer;
+}
+
+.view_selector li a.previous {
+ width: 23px;
+ background-position: -241px -1px;
+}
+
+.view_selector li a.day {
+ width: 41px;
+ background-position: -264px -1px;
+}
+
+.view_selector li a.day_selected {
+ width: 41px;
+ background-position: -264px -47px;
+}
+
+.view_selector li a.week {
+ width: 49px;
+ background-position: -305px -1px;
+}
+
+.view_selector li a.week_selected {
+ width: 49px;
+ background-position: -305px -47px;
+}
+
+.view_selector li a.next {
+ width: 23px;
+ background-position: -379px -1px;
+}
+
+.view_selector a.homeicon {
+ float: right;
+ margin: 15px -20px 0 0;
+ padding: 0 0 0 10px;
+ font-size: 0.9em;
+ color: #999;
+ cursor: pointer;
+}
+
+.view_selector a.homeicon img {
+ padding-right: 2px;
+}
+
+a.graphic {
+ display: block;
+ padding: 0;
+ margin: 0;
+ overflow: hidden;
+ border: 0;
+ line-height: 0;
+ font-size: 0;
+ text-indent: -9999px;
+ text-decoration: none;
+ cursor: pointer;
+}
+
+.timesheet-entries {
+ width: 100;
+ border: 0;
+ margin: 0;
+ font-size: 1em;
+ line-height: 1.4em;
+ -webkit-border-bottom-left-radius: 8px;
+ -moz-border-radius-bottomleft: 8px;
+ border-bottom-left-radius: 8px;
+ -webkit-border-bottom-right-radius: 8px;
+ -moz-border-radius-bottomright: 8px;
+ border-bottom-right-radius: 8px;
+ border-collapse: separate;
+}
+
+.timesheet-entries .entry_controls {
+ display: none;
+ float: right;
+ margin-top: 5px;
+}
+
+.timesheet-entries a.edit {
+ float: left;
+ width: 38px;
+ height: 19px;
+ background: url(../img/timesheetcontrols.gif?1329935396) no-repeat -174px -1px;
+}
+
+.timesheet-entries a.delete {
+ float: left;
+ width: 21px;
+ height: 19px;
+ margin-left: 3px;
+ background: url(../img/timesheetcontrols.gif?1329935396) no-repeat -213px -1px;
+}
+
+.timesheet-footer {
+ background: #EEE !important;
+ border: 1px solid #D5D5D5;
+ -webkit-border-bottom-left-radius: 8px;
+ -moz-border-radius-bottomleft: 8px;
+ border-bottom-left-radius: 8px;
+ -webkit-border-bottom-right-radius: 8px;
+ -moz-border-radius-bottomright: 8px;
+ border-bottom-right-radius: 8px;
+}
+
+.timesheet-footer a.new_entry {
+ width: 83px;
+ height: 24px;
+ background: url(../img/timesheetcontrols.gif?1330113994) no-repeat -241px -72px
+}
+
+.timesheet-footer a.new_entry:hover {
+ background-position: -241px -96px;
+}
+
+.timesheet-footer a.new_row {
+ width: 78px;
+ height: 24px;
+ background: url(../img/timesheetcontrols.gif?1330113994) no-repeat -324px -72px
+}
+
+.week_view_input{
+ -moz-box-sizing: border-box;
+ background: none repeat scroll 0 0 white;
+ border: 1px solid #999999;
+ border-radius: 3px 3px 3px 3px;
+ color: #1F1F1F;
+ margin: 0 2px;
+ min-width: 90px;
+ padding: 0 2px;
+ text-align: center;
+ font-size: 13px;
+}
+
+.remove{
+ border: none;
+ height: 20px;
+ width: 20px;
+ background: url(../img/remove.png) no-repeat center center;
+ cursor: pointer;
+
+}
+.save{
+ border: none;
+ height: 20px;
+ width: 20px;
+ background: url(../img/save.png) no-repeat center center;
+ cursor: pointer;
+}
+
+
+.week_add_button {
+ display: block;
+ padding: 0;
+ margin: 0;
+ overflow: hidden;
+ border: 0;
+ line-height: 0;
+ font-size: 0;
+ text-indent: -9999px;
+ text-decoration: none;
+ cursor: pointer;
+}
\ No newline at end of file
=== added file 'hr_timesheet_sheet/static/src/img/save.png'
Binary files hr_timesheet_sheet/static/src/img/save.png 1970-01-01 00:00:00 +0000 and hr_timesheet_sheet/static/src/img/save.png 2012-04-02 06:22:20 +0000 differ
=== added file 'hr_timesheet_sheet/static/src/img/timesheetcontrols.gif'
Binary files hr_timesheet_sheet/static/src/img/timesheetcontrols.gif 1970-01-01 00:00:00 +0000 and hr_timesheet_sheet/static/src/img/timesheetcontrols.gif 2012-04-02 06:22:20 +0000 differ
=== added directory 'hr_timesheet_sheet/static/src/js'
=== added file 'hr_timesheet_sheet/static/src/js/timesheet.js'
--- hr_timesheet_sheet/static/src/js/timesheet.js 1970-01-01 00:00:00 +0000
+++ hr_timesheet_sheet/static/src/js/timesheet.js 2012-04-02 06:22:20 +0000
@@ -0,0 +1,471 @@
+openerp.hr_timesheet_sheet = function(openerp) {
+ var QWeb = openerp.web.qweb;
+ var _t = openerp.web._t;
+ openerp.hr_timesheet_sheet.TimesheetOne2Many = openerp.web.form.FieldOne2Many.extend({
+ load_views: function() {
+ this._super();
+ var self = this;
+ this.buttons = {};
+ _.each(this.node.children, function(node, index) {
+ self.buttons[node.attrs.name] = new (self.view.registry.get_object(node.tag))(self.view, node);
+ });
+ this.viewmanager.registry = this.viewmanager.registry.extend({
+ 'list': 'openerp.hr_timesheet_sheet.TimesheetListView'
+ });
+ }
+ });
+
+
+ openerp.hr_timesheet_sheet.TimesheetOne2ManyReadOnly = openerp.hr_timesheet_sheet.TimesheetOne2Many.extend({
+ force_readonly: true
+ });
+ openerp.hr_timesheet_sheet.TimesheetListView = openerp.web.form.One2ManyListView.extend({
+ _template: 'Timesheet.listview',
+
+ init: function() {
+ this._super.apply(this, arguments);
+ this.timesheet_mode = this.timesheet_mode || 'day';
+
+ _.extend(this.options, {
+ 'header': false,
+ 'pager': false,
+ 'action_buttons': false,
+ 'timesheet_mode': this.timesheet_mode
+ });
+ },
+ current_week:function(){
+ var self = this;
+ var date_from = openerp.web.str_to_date(self.dataset.parent_view.datarecord["date_from"]);
+ var date_to = openerp.web.str_to_date(self.dataset.parent_view.datarecord["date_to"]);
+ date_to.addDays(1)
+ var day = ["Sun","Mon","Tue","Wed","Thu","Fri","Sat"];
+ var current_week = [];
+ do{
+ current_week.push([day[date_from.getDay()]+" ",date_from.getDate()]);
+ }while (date_from.addDays(1).getDate() != date_to.getDate());
+ this.$element.find("#week_view").html(QWeb.render('week_view_temp', {'data':current_week}));
+ return current_week;
+ },
+
+ on_loaded: function() {
+ var self = this;
+ this._super.apply(this, arguments);
+
+ var self = this;
+ this.$element.find('.oe-listview-content')
+ .css('border', 'none')
+ .addClass('timesheet-entries');
+ _.each(this.dataset.o2m.buttons, function(node, key) {
+ self.$element.on('click', 'a.' + key, node.on_click);
+ });
+
+ this.$element.on('click', 'tfoot.timesheet-footer .graphic', this.do_add_record);
+
+ var $mode = this.$element.find('a.day, a.week');
+
+
+ $mode.click(function() {
+ self.timesheet_mode = $(this).hasClass('day') ? 'day': 'week';
+ if($(this).hasClass('day')) {
+ self.$element.find(".oe-list-footer").empty();
+ self.$element.find("#week_view").empty();
+ self.$element.find('a.previous,a.next').show();
+ self.$element.find('a.week').removeClass('week_selected');
+ $(this).addClass('day_selected');
+ self.$element.find(".timesheet-footer :hidden").show();
+ self.$element.find("#week_footer").remove()
+ } else {
+ self.$element.find(".view_selector").parent().attr('colspan',10);
+ self.$element.find('a.previous,a.next').hide();
+ self.$element.find('a.day').removeClass('day_selected');
+ $(this).addClass('week_selected');
+ self.current_week();
+ }
+ });
+ }
+ });
+ openerp.web.ListView.include({
+ reload_content: function(){
+ this._super();
+ if(this.$element.find('a.title span').length){
+ var date_from = openerp.web.str_to_date(this.dataset.parent_view.datarecord["date_from"]);
+ var date_to = openerp.web.str_to_date(this.dataset.parent_view.datarecord["date_to"]);
+ var date_current = openerp.web.str_to_date(this.dataset.parent_view.datarecord["date_current"]);
+ var month = [ "January", "February", "March", "April", "May", "June","July", "August", "September", "October", "November", "December" ];
+
+ var value = (this.timesheet_mode == "week")?
+ date_from.getDate()+" "+month[date_from.getMonth()]+" "+date_from.getFullYear()+" - "+
+ date_to.getDate()+" "+month[date_to.getMonth()]+" "+date_to.getFullYear():
+ date_current.getDate()+" "+month[date_current.getMonth()]+" "+date_current.getFullYear();
+ this.$element.find('a.title span').html(value);
+ }
+ }
+ });
+ openerp.web.ListView.List.include({
+ render: function() {
+ this._super();
+ if(this.view.model == 'hr.analytic.timesheet' && this.view.timesheet_mode == "week" ) {
+ this.$current.empty();
+ return new openerp.hr_timesheet_sheet.week(this).start();
+ }
+ }
+ });
+
+ openerp.hr_timesheet_sheet.week = openerp.web.Class.extend({
+ init: function ( parent ) {
+ this.$current = parent.$current;
+ this.columns = parent.columns;
+ this.dataset = parent.dataset;
+ this.options = parent.options;
+ this.records = parent.records;
+ this.view = parent.view;
+ this.current_week = [],this.onchange_columns = [],this.widgets = [],this.to_create_widgets=[];
+ this.property = openerp.hr_timesheet_sheet.week.Field.property_widget;
+ this.week_default_data;
+ },
+
+ start: function () {
+ this.get_current_week();
+ var self = this
+ $.when(this.dataset.default_get(_.keys(this.view.fields_view.fields))).then(function(res){
+ self.week_default_data = res;
+ self.render();
+ });
+ },
+ render: function () {
+ //group_by_date,acc_id,date_wise_total_value
+ var self = this,hr_table_entry = this.$current,render_data = this.group_by_data();
+ _.each(render_data["acc_id"],function(account_id){
+ var row_id = account_id.split(","),
+ sum_of_amount = 0,
+ render_all_input_td = _.str.sprintf("<td class = 'week_view_header' >%s</td>",row_id[1]);
+ hr_table_entry.append(_.str.sprintf("<tr id = row_%s></tr>", row_id[0]));
+ var selector = hr_table_entry.find("tr[id=row_" + row_id[0] + "]");
+
+ _.each(self.current_week,function(week_day){
+ var current_pro = render_data["group_by_date"][week_day.getDate()],widget_data = {};
+ if(current_pro && _.include(_.keys(current_pro),account_id)){
+ widget_data={
+ "u_id":current_pro[account_id][0]["id"].toString(),
+ "value":parseInt(current_pro[account_id][0]["unit_amount"]),
+ "type":"float",
+ "data":current_pro[account_id][0],
+ "disable":current_pro[account_id][0]["current_work_time"]?true:false
+ };
+ sum_of_amount += widget_data["value"];
+ }else{
+ widget_data={
+ "u_id" :row_id[0]+"_"+week_day.getDate()+"_"+ week_day.getMonth(),
+ "value" :"",
+ "type" :"float",
+ "data" :self.week_default_data,
+ "disable":false
+ };
+ }
+ if(!self.options.editable){
+ widget_data.disable = true;
+ }
+
+ widget = new (self.property.get_any([widget_data.type]))(selector,widget_data);
+ render_all_input_td = render_all_input_td + widget.render();
+ self.widgets.push(widget);
+ });
+ render_all_input_td = render_all_input_td + _.str.sprintf("<td class = 'week_view_header' id = 'total'> %s </td>",sum_of_amount);
+ render_all_input_td = render_all_input_td + "<td width = '8%' class='remove'></td>";
+ selector.append(render_all_input_td);
+ });
+ _.each(this.widgets,function(w){
+ w.start();
+ w.set_value(w.value);
+ });
+ self.$current.find("input[id^=]").change(function(){self.on_change($(this).attr("id"))});
+ self.$current.find(".remove").click(function(){
+ if (confirm(_t("Do you really want to remove this week line?"))) {
+ self.remove_element($(this).parent());
+ }
+ });
+ var button = (self.options.editable)?"<a class= 'week_add_button new_entry'>Add new entry</a>":"";
+ var tfooter = _.str.sprintf("<tr id ='week_footer'><td>%s</td>",button)
+ _.each(_.keys(render_data["date_wise_total_value"]),function(val){
+ tfooter +=_.str.sprintf("<td class = 'oe-list-footer'> %s </td>",render_data["date_wise_total_value"][val] || 0);
+ });
+ tfooter += "</tr>"
+ var element = self.dataset.parent_view.$element.find(".timesheet-footer");
+ element.find("tr").hide();
+ element.append(tfooter);
+ element.find(".week_add_button").click(function(){self.add_project();});
+ },
+ update_account_id: function(){
+ var self = this,acc_id = [];
+ var selection_account = self.view.visible_columns[0].selection;
+ _.each(this.$current.find("tr[id^=row_]"),function(tr){acc_id.push(($(tr).attr("id")).split("_")[1]);});
+ var acc_id = _.reject(selection_account,function(ff){
+ return _.include(acc_id,ff[0].toString());
+ });
+ return acc_id;
+ },
+
+ add_project:function(){
+ var self = this,render_all_input_td;
+ self.to_create_widgets = [];
+ if(!self.$current.find("#add_row").length){
+ var add_record ={
+ 'name' : self.view.visible_columns[0].name,
+ 'selection' : self.update_account_id()
+ }
+ hr_table_entry = this.$current;
+ hr_table_entry.append(_.str.sprintf("<tr id = %s></tr>", "add_row"));
+ var selector = hr_table_entry.find("tr[id=add_row]");
+ render_all_input_td = (QWeb.render('week_selection', {'widget':add_record}));
+ _.each(this.current_week,function(day){
+ var widget_data={
+ "u_id":"temp"+"_"+day.getDate()+"_"+day.getMonth(),
+ "value":"",
+ "type":"float",
+ "data":self.week_default_data,
+ "disable":false
+ };
+ widget = new (self.property.get_any([widget_data.type]))(selector,widget_data,self);
+ render_all_input_td = render_all_input_td + widget.render();
+ self.to_create_widgets.push(widget);
+ });
+ render_all_input_td = render_all_input_td + _.str.sprintf("<td class = 'week_view_header' id = 'total'> %s </td>","0");
+ render_all_input_td += "<td style='min-width:10px;' class='save'></td>";
+ selector.append(render_all_input_td);
+ _.each(self.to_create_widgets,function(w){w.start();});
+ selector.find("input[id^=]").change(function(){
+ var value = parseInt($(this).val());
+ if(isNaN(value) || value > 24){
+ $(this).val(" ")
+ }
+ });
+ selector.find(".save").click(function(){
+ $(this).removeClass("save");
+ $(this).addClass("remove");
+ $(this).unbind();
+ self.render_project(self.$current.find("#account_id option:selected"));
+ });
+ }
+ },
+ render_project: function(value){
+ var row_id = parseInt(value.val()),self = this;
+ this.$current.find("#add_row").find("input[id^=]").change(function(){self.on_change($(this).attr("id"));});
+ this.$current.find("#add_row").find(".remove").click(function(){
+ if (confirm(_t("Do you really want to remove this week line?"))) {
+ self.remove_element($(this).parent());
+ }
+ });
+ this.$current.find("#add_row").unbind();
+ this.$current.find("#add_row td:first-child").empty().text(value.text()).addClass('week_view_header');
+ this.$current.find("#add_row").attr("id","row_"+row_id);
+ _.each(self.to_create_widgets,function(w){
+ w.set_id(row_id+"_"+ w.u_id.substring(5,9));
+ w.u_id = row_id+"_"+ w.u_id.substring(5,9);
+ self.widgets.push(w);
+ if(!isNaN(w.get_value())){
+ self.on_change(w.u_id);
+ }
+ });
+ },
+ remove_element: function (tr) {
+ var self = this;
+ var td_to_remove = [];
+ _.each(tr.find("input[id^=]"),function(td){
+ var val = $(td).attr('id');
+ var widget = self.get_widget(val);
+ if(!isNaN(val)){
+ td_to_remove.push(parseInt(val));
+ }else if(openerp.web.BufferedDataSet.virtual_id_regex.test(val)){
+ td_to_remove.push(val);
+ }
+ self.update_footer(widget.index,- widget.value);
+ widget.on_change( -widget.value);
+ self.widgets.splice(_.indexOf(self.widgets, widget),1);
+ });
+ this.dataset.unlink(td_to_remove);
+ _.each(td_to_remove, function(id_of_rec){
+ self.records.remove(self.records.get(id_of_rec));
+ })
+ tr.remove();
+ },
+ update_footer: function(index,new_value){
+ var footer = this.dataset.parent_view.$element.find(".timesheet-footer tr:visible td:nth-child("+index+")")
+ footer.text(parseInt(footer.text()) + new_value)
+ },
+ get_widget: function(id){
+ return _.detect(this.widgets,function(w){return w.u_id.toString() === id.toString();});
+ },
+ on_change: function ( id ) {
+ var self = this,widget = this.get_widget(id);
+ var new_value = widget.get_value();
+ this.onchange_columns = [];
+
+ if(isNaN(new_value) || new_value < 0 || new_value > 24){widget.set_value(widget.value);}
+ else{
+ this.update_footer(widget.index,new_value - widget.value);
+ widget.on_change(new_value - widget.value);
+ if(!isNaN(widget.u_id) || openerp.web.BufferedDataSet.virtual_id_regex.test(widget.u_id)){
+ //to update record
+ var id = openerp.web.BufferedDataSet.virtual_id_regex.test(widget.u_id)
+ ? widget.u_id:parseInt(widget.u_id),data = {}
+ widget.data["unit_amount"] = new_value;
+ self.on_change_method(["unit_amount"],widget.data);
+ _.each(this.onchange_columns,function(cal){
+ data[cal] = widget.data[cal];
+ });
+ data["unit_amount"] = new_value;
+ this.dataset.write(id,data);
+ }else{
+ //to create record
+ self.onchange_columns = [];
+ var value_to_store = widget.u_id.split("_");
+ var date = _.detect(this.current_week,function(day){
+ return day.getDate() === parseInt(value_to_store[1]) && day.getMonth() === parseInt(value_to_store[2])
+ });
+ widget.data["account_id"] = value_to_store[0]
+ widget.data["unit_amount"] = new_value;
+ widget.data["name"] = " "
+ widget.data["date"] = openerp.web.date_to_str(date)
+ self.on_change_method(["account_id","unit_amount"],widget.data);
+ this.dataset.create(widget.data).pipe(function(r) {
+ widget.set_id(r.result);
+ widget.u_id = r.result;
+ self.records.add({id: r.result})
+ self.dataset.alter_ids([r.result].concat(self.dataset.ids));
+ self.$current.find("tr[data-id="+r.result+"]").remove()
+ self.$current.find("input[id=" + id + "]").change(function(){
+ self.on_change();
+ });
+ });
+ }
+ }
+ },
+ on_change_method: function(columns,data,new_value){
+ var self = this;
+ var col = _.detect(this.view.visible_columns,function(col){
+ return col.name === columns[0]
+ });
+ var onchange = _.str.trim(col.on_change);
+ var call = onchange.match(/^\s?(.*?)\((.*?)\)\s?$/);
+
+ var ajax = {
+ url: '/web/dataset/onchange',
+ async: false
+ };
+ data_to_parse = _.map(call[2].split(','), function(num){
+ var value = data[_.str.trim(num)]
+ value = isNaN(value)?value:parseInt(value);
+ if(_.isArray(value)){value = value[0];}
+ return value == null? false:value;
+ });
+ can_process_onchange = this.dataset.rpc(ajax, {
+ model: self.dataset.model,
+ method: call[1],
+ args: [(isNaN(data.u_id)? [] : [data.u_id])].concat(data_to_parse),
+ }).then(function(r) {
+ columns.shift();
+ _.extend(data,r.value);
+ self.onchange_columns = self.onchange_columns.concat(_.keys(r.value));
+ if(columns.length > 0){
+ self.on_change_method(columns,data);
+ }
+ });
+ },
+
+ group_by_data: function () {
+ var date_wise_total_value = {};
+ _.each(this.current_week,function(day){date_wise_total_value[day.getDate()] = "";});
+
+ var group_by_date = _.chain(this.records.records)
+ .pluck("attributes")
+ .groupBy(function (rec){ return rec["date"]})
+ .value();
+
+ _.each(_.keys(group_by_date),function(rec){
+ var date = new Date(rec).getDate();
+ date_wise_total_value[date] = _.chain(group_by_date[rec])
+ .pluck("unit_amount")
+ .reduce(function(prev, next){ return prev + next;})
+ .value();
+
+ group_by_date[date] = _.groupBy(group_by_date[rec],function (group_by_acc_id){ return group_by_acc_id["account_id"]});
+ delete group_by_date[rec];
+ });
+
+ var acc_id = _.chain(this.records.records)
+ .pluck("attributes")
+ .groupBy(function (rec){ return rec["account_id"]})
+ .keys()
+ .uniq()
+ .value();
+ return {
+ "group_by_date":group_by_date,
+ "acc_id":acc_id,
+ "date_wise_total_value":date_wise_total_value
+ };
+ },
+ get_current_week: function(){
+ var self = this;
+ var date_from = openerp.web.str_to_date(this.dataset.parent_view.datarecord["date_from"]);
+ var date_to = openerp.web.str_to_date(this.dataset.parent_view.datarecord["date_to"]);
+ do{self.current_week.push(new Date(date_from));
+ }while (date_from.addDays(1).getDate() != date_to.getDate());
+ this.current_week.push(date_to);
+ },
+
+ });
+ openerp.hr_timesheet_sheet.week.Field = openerp.web.Class.extend({
+ init: function(view, widget) {
+ this.$element = view;
+ this.data = widget.data;
+ this.u_id = widget.u_id;
+ this.type = widget.type;
+ this.value = widget.value;
+ this.disable = widget.disable;
+ this.columns = [];
+ this.index;
+ },
+ render: function() {return QWeb.render(this.template, {widget: this});}
+ });
+ openerp.hr_timesheet_sheet.week.integer = openerp.hr_timesheet_sheet.week.Field.extend({
+ template : "week_integer",
+ start: function () {
+ var self = this;
+ this.index = parseInt(this.$element.find("input[id='"+this.u_id+"']").parent().index()) + 1;
+ this.$element.find("input[id="+ this.u_id+"]")
+ .focus(function(){$(this).css({'background-color' : "yellow"});})
+ .blur(function() {$(this).css({'background-color' : ""});});
+ if(this.disable){this.$element.find("input[id="+ this.u_id+"]").attr("disabled", "disabled");}
+ },
+ on_change:function(value){
+ var total = parseInt(this.$element.find("#total").text()) + value;
+ this.$element.find("#total").text(total);
+ this.value = this.get_value();
+ },
+ set_value: function(value) {
+ this.$element.find("input[id=" + this.u_id + "]").val(value);
+ },
+ get_value: function() {
+ var val = this.$element.find("input[id=" + this.u_id + "]").val();
+ if(isNaN(val)){return NaN;}
+ return parseInt(val);
+ },
+ set_id: function(id){
+ var self = this;
+ this.$element.find("input[id=" + this.u_id + "]").attr("id",id);
+ this.$element.find("input[id=" + this.u_id + "]").unbind();
+ }
+ });
+
+ openerp.hr_timesheet_sheet.week.Field.property_widget = new openerp.web.Registry({
+ 'float' : 'openerp.hr_timesheet_sheet.week.integer'
+ });
+
+ openerp.web.form.widgets = openerp.web.form.widgets.extend({
+ 'timesheet_track': 'openerp.hr_timesheet_sheet.TimesheetOne2Many',
+ });
+
+ openerp.web.page.readonly = openerp.web.page.readonly.extend({
+ 'timesheet_track': 'openerp.hr_timesheet_sheet.TimesheetOne2ManyReadOnly',
+ });
+}
\ No newline at end of file
=== added directory 'hr_timesheet_sheet/static/src/xml'
=== added file 'hr_timesheet_sheet/static/src/xml/timesheet.xml'
--- hr_timesheet_sheet/static/src/xml/timesheet.xml 1970-01-01 00:00:00 +0000
+++ hr_timesheet_sheet/static/src/xml/timesheet.xml 2012-04-02 06:22:20 +0000
@@ -0,0 +1,87 @@
+<template>
+ <t t-extend="One2Many.listview" t-name="Timesheet.listview">
+ <t t-jquery="thead">
+ this.attr('class', this.attr('class') + ' timesheet-header');
+ </t>
+
+ <t t-jquery="thead" t-operation="append">
+ <tr>
+ <th t-att-colspan="columns_count">
+ <div class="view_selector">
+ <ul class="info">
+ <li>
+ <a class="date_previous previous">Previous</a>
+ </li>
+ <li>
+ <a class="title">
+ <span><t t-esc="fields_view.arch.attrs.string"/>
+ </span>
+ </a>
+ </li>
+ <li>
+ <a class="date_next next">Next</a>
+ </li>
+ </ul>
+ <ul class="pagination">
+ <li>
+ <a t-att-class="'day ' + (options.timesheet_mode === 'day' ? 'day_selected' : '')" data-mode="day">Day</a>
+ </li>
+ <li>
+ <a t-att-class="'week ' + (options.timesheet_mode === 'week' ? 'week_selected' : '')" data-mode="week">Week</a>
+ </li>
+ </ul>
+ <!-- <a class="homeicon today">
+ <img src="/hr_timesheet_sheet/static/src/img/timesheet_homeicon.gif" border="0"/>
+ <t t-if="options.timesheet_mode === 'day'">
+ Today
+ </t>
+ <t t-if="options.timesheet_mode !== 'day'">
+ This Week
+ </t>
+ </a> -->
+ </div>
+ </th>
+ </tr>
+ <tr id="week_view" class="week_view" colspan="10"> </tr>
+ </t>
+ <t t-jquery="tfoot.ui-widget-header">
+ this.attr('class', this.attr('class') + ' timesheet-footer');
+ </t>
+ <t t-jquery="tfoot > tr:last-child" t-operation="replace"/>
+
+ <t t-jquery="tfoot > tr td[t-if]:eq(1)" t-operation="append">
+ <a class="graphic new_entry">Add new entry</a>
+ </t>
+ </t>
+ <t t-name="week_view_temp">
+ <th width = "44%"> </th>
+ <th width = "8%" class = "week_header" t-foreach="data" t-as="date" ><t t-esc="date[0]"/><t t-esc="date[1]"/></th>
+ <th width = "8%" class = "week_header" >Total</th>
+ </t>
+
+ <t t-name="week_integer">
+ <td t-if="widget.disable">
+ <input class = "week_view_input" disabled="disabled" t-att-id = "widget.u_id" style="min-width:1px;" type="text" size="2" />
+ </td>
+ <td t-if="!widget.disable">
+ <input class = "week_view_input" t-att-id = "widget.u_id" style="min-width:1px;" type="text" size="2" />
+ </td>
+
+ </t>
+
+ <t t-name="week_selection">
+ <td>
+ <select t-att-id="widget.name" style = "width: 100%; height: 20px;" >
+ <t t-if="widget.selection" t-foreach="widget.selection" t-as="option">
+ <option
+ t-att-value=" typeof option === 'object' ? option[0] : option">
+ <t t-esc="typeof option === 'object' ? option[1] : option"/>
+ </option>
+ </t>
+ </select>
+ </td>
+ </t>
+
+
+
+</template>
\ No newline at end of file
_______________________________________________
Mailing list: https://launchpad.net/~openerp-dev-gtk
Post to : [email protected]
Unsubscribe : https://launchpad.net/~openerp-dev-gtk
More help : https://help.launchpad.net/ListHelp