From 44e02f756b0066f61e1bbea648f92ea23a0aac02 Mon Sep 17 00:00:00 2001 From: Florent Xicluna Date: Wed, 8 Feb 2012 16:33:04 +0100 Subject: [PATCH 001/780] =?UTF-8?q?[FIX]=C2=A0file=5Fopen=20should=20not?= =?UTF-8?q?=20search=20zip=20files=20outside=20its=20root=20directory.=20?= =?UTF-8?q?=20Fix=20the=20returned=20value=20with=20pathinfo=3DTrue.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit lp bug: https://launchpad.net/bugs/928507 fixed lp bug: https://launchpad.net/bugs/928376 fixed bzr revid: florent.xicluna@gmail.com-20120208153304-9443zx2z09bws10x --- openerp/tools/misc.py | 89 ++++++++++++++++++++++++------------------- 1 file changed, 49 insertions(+), 40 deletions(-) diff --git a/openerp/tools/misc.py b/openerp/tools/misc.py index a5c72900fc7..3c9210214b1 100644 --- a/openerp/tools/misc.py +++ b/openerp/tools/misc.py @@ -134,7 +134,7 @@ def file_open(name, mode="r", subdir='addons', pathinfo=False): @param name name of the file @param mode file open mode @param subdir subdirectory - @param pathinfo if True returns tupple (fileobject, filepath) + @param pathinfo if True returns tuple (fileobject, filepath) @return fileobject if pathinfo is False else (fileobject, filepath) """ @@ -142,44 +142,51 @@ def file_open(name, mode="r", subdir='addons', pathinfo=False): adps = addons.module.ad_paths rtp = os.path.normcase(os.path.abspath(config['root_path'])) - if name.replace(os.path.sep, '/').startswith('addons/'): + if os.path.isabs(name): + # It is an absolute path + # Is it below 'addons_path' or 'root_path'? + name = os.path.normcase(os.path.normpath(name)) + for root in adps + [rtp]: + if name.startswith(root): + base = root.rstrip(os.sep) + name = name[len(base) + 1:] + break + else: + # It is outside the OpenERP root: skip zipfile lookup. + base, name = os.path.split(name) + return _fileopen(name, mode=mode, basedir=base, pathinfo=pathinfo) + + if name.replace(os.sep, '/').startswith('addons/'): subdir = 'addons' - name = name[7:] + name2 = name[7:] + elif subdir: + name = os.path.join(subdir, name) + if name.replace(os.sep, '/').startswith('addons/'): + subdir = 'addons' + name2 = name[7:] + else: + name2 = name - # First try to locate in addons_path + # First, try to locate in addons_path if subdir: - subdir2 = subdir - if subdir2.replace(os.path.sep, '/').startswith('addons/'): - subdir2 = subdir2[7:] - - subdir2 = (subdir2 != 'addons' or None) and subdir2 - for adp in adps: try: - if subdir2: - fn = os.path.join(adp, subdir2, name) - else: - fn = os.path.join(adp, name) - fn = os.path.normpath(fn) - fo = file_open(fn, mode=mode, subdir=None, pathinfo=pathinfo) - if pathinfo: - return fo, fn - return fo + return _fileopen(name2, mode=mode, basedir=adp, + pathinfo=pathinfo) except IOError: pass - if subdir: - name = os.path.join(rtp, subdir, name) - else: - name = os.path.join(rtp, name) + # Second, try to locate in root_path + return _fileopen(name, mode=mode, basedir=rtp, pathinfo=pathinfo) - name = os.path.normpath(name) - # Check for a zipfile in the path - head = name - zipname = False +def _fileopen(path, mode, basedir, pathinfo): + head = os.path.normpath(path) + name = os.path.normpath(os.path.join(basedir, path)) name2 = False - while True: + zipname = False + # Check for a zipfile in the path, but stop at the 'basedir' level + while os.sep in head: head, tail = os.path.split(head) if not tail: break @@ -187,9 +194,10 @@ def file_open(name, mode="r", subdir='addons', pathinfo=False): zipname = os.path.join(tail, zipname) else: zipname = tail - if zipfile.is_zipfile(head+'.zip'): + zpath = os.path.join(basedir, head + '.zip') + if zipfile.is_zipfile(zpath): from cStringIO import StringIO - zfile = zipfile.ZipFile(head+'.zip') + zfile = zipfile.ZipFile(zpath) try: fo = StringIO() fo.write(zfile.read(os.path.join( @@ -197,20 +205,21 @@ def file_open(name, mode="r", subdir='addons', pathinfo=False): os.sep, '/'))) fo.seek(0) if pathinfo: - return fo, name + return (fo, name) return fo except Exception: - name2 = os.path.normpath(os.path.join(head + '.zip', zipname)) - pass - for i in (name2, name): - if i and os.path.isfile(i): - fo = file(i, mode) + name2 = os.path.normpath(os.path.join(zpath, zipname)) + # Look for a normal file + for fname in (name2, name): + if fname and os.path.isfile(fname): + fo = open(fname, mode) if pathinfo: - return fo, i + return (fo, fname) return fo - if os.path.splitext(name)[1] == '.rml': - raise IOError, 'Report %s doesn\'t exist or deleted : ' %str(name) - raise IOError, 'File not found : %s' % name + # Not found + if name.endswith('.rml'): + raise IOError('Report %r doesn\'t exist or deleted' % name) + raise IOError('File not found: %s' % name) #---------------------------------------------------------- From 69a5eca5b48740c44e35ac5b0285e22a17c5dd8d Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Wed, 8 Feb 2012 18:39:32 +0100 Subject: [PATCH 002/780] [IMP] Give precedence to module directories instead of zips while locating resources The previous behavior gave the precedence to zipped modules, without any apparent reason, and this is sub-optimal for several reasons: 1. The default is to have regular modules, not zipped modules, so looking first for a regular module is more efficient. 2. Keeping a zipped module next to a regular module with the same name is not a documented or supported feature. 3. Even if you were relying on this behavior having the extracted module take precedence is more practical: you could simply extract the zipped module to test a quick fix. We have another issue related to this feature because the code looking for zipped modules escapes the addons paths chroot and goes up to the filesystem root looking for a zip module at each step. This is described in bug 928376 and a fix for it should follow. lp bug: https://launchpad.net/bugs/928376 fixed bzr revid: odo@openerp.com-20120208173932-pwhz53vxxdzbo8ja --- openerp/modules/module.py | 25 ++++++++++++++----------- openerp/tools/misc.py | 24 +++++++++++++++--------- 2 files changed, 29 insertions(+), 20 deletions(-) diff --git a/openerp/modules/module.py b/openerp/modules/module.py index 58a4547ff07..3d3bc0d9adf 100644 --- a/openerp/modules/module.py +++ b/openerp/modules/module.py @@ -280,25 +280,28 @@ def get_module_as_zip(modulename, b64enc=True, src=True): def get_module_resource(module, *args): """Return the full path of a resource of the given module. - @param module: the module - @param args: the resource path components + :param module: module name + :param list(str) args: resource path components within module - @return: absolute path to the resource + :rtype: str + :return: absolute path to the resource TODO name it get_resource_path TODO make it available inside on osv object (self.get_resource_path) """ - a = get_module_path(module) - if not a: return False - resource_path = opj(a, *args) - if zipfile.is_zipfile( a +'.zip') : - zip = zipfile.ZipFile( a + ".zip") + mod_path = get_module_path(module) + if not mod_path: return False + resource_path = opj(mod_path, *args) + if os.path.isdir(mod_path): + # the module is a directory - ignore zip behavior + if os.path.exists(resource_path): + return resource_path + elif zipfile.is_zipfile(mod_path + '.zip'): + zip = zipfile.ZipFile( mod_path + ".zip") files = ['/'.join(f.split('/')[1:]) for f in zip.namelist()] resource_path = '/'.join(args) if resource_path in files: - return opj(a, resource_path) - elif os.path.exists(resource_path): - return resource_path + return opj(mod_path, resource_path) return False def get_module_icon(module): diff --git a/openerp/tools/misc.py b/openerp/tools/misc.py index a5c72900fc7..e0be5ffaef9 100644 --- a/openerp/tools/misc.py +++ b/openerp/tools/misc.py @@ -175,10 +175,22 @@ def file_open(name, mode="r", subdir='addons', pathinfo=False): name = os.path.normpath(name) - # Check for a zipfile in the path + # Give higher priority to module directories, which is + # a more common case than zipped modules. + if os.path.isfile(name): + fo = file(name, mode) + if pathinfo: + return fo, name + return fo + + # Support for loading modules in zipped form. + # This will not work for zipped modules that are sitting + # outside of known addons paths. head = name zipname = False - name2 = False + # FIXME: implement chrooting inside addons paths and fix + # for incorrect path_info behavior. Work in progress by + # Florent X linked to bug 928376 while True: head, tail = os.path.split(head) if not tail: @@ -200,14 +212,8 @@ def file_open(name, mode="r", subdir='addons', pathinfo=False): return fo, name return fo except Exception: - name2 = os.path.normpath(os.path.join(head + '.zip', zipname)) pass - for i in (name2, name): - if i and os.path.isfile(i): - fo = file(i, mode) - if pathinfo: - return fo, i - return fo + if os.path.splitext(name)[1] == '.rml': raise IOError, 'Report %s doesn\'t exist or deleted : ' %str(name) raise IOError, 'File not found : %s' % name From 55e7b8167e9705ddaabf388e8c95d15666a81827 Mon Sep 17 00:00:00 2001 From: "Vaibhav (OpenERP)" Date: Fri, 6 Apr 2012 11:43:30 +0530 Subject: [PATCH 003/780] [IMP] Web addon for SignIn/Out. bzr revid: vda@tinyerp.com-20120406061330-n80vyxgkr309ykba --- addons/hr_attendance/__openerp__.py | 4 + .../static/src/img/emp-in-disable.png | Bin 0 -> 1135 bytes .../hr_attendance/static/src/img/emp-in.png | Bin 0 -> 2153 bytes .../static/src/img/emp-out-disable.png | Bin 0 -> 1110 bytes .../hr_attendance/static/src/img/emp-out.png | Bin 0 -> 2062 bytes addons/hr_attendance/static/src/img/icon.png | Bin 0 -> 5938 bytes .../static/src/js/sign_in_out.js | 82 ++++++++++++++++++ .../static/src/xml/sign_in_out.xml | 28 ++++++ .../wizard/hr_attendance_sign_in_out.py | 1 + .../wizard/hr_attendance_sign_in_out_view.xml | 11 +-- 10 files changed, 121 insertions(+), 5 deletions(-) create mode 100644 addons/hr_attendance/static/src/img/emp-in-disable.png create mode 100644 addons/hr_attendance/static/src/img/emp-in.png create mode 100644 addons/hr_attendance/static/src/img/emp-out-disable.png create mode 100644 addons/hr_attendance/static/src/img/emp-out.png create mode 100644 addons/hr_attendance/static/src/img/icon.png create mode 100644 addons/hr_attendance/static/src/js/sign_in_out.js create mode 100644 addons/hr_attendance/static/src/xml/sign_in_out.xml diff --git a/addons/hr_attendance/__openerp__.py b/addons/hr_attendance/__openerp__.py index c903a87abc4..b25047638c8 100644 --- a/addons/hr_attendance/__openerp__.py +++ b/addons/hr_attendance/__openerp__.py @@ -54,5 +54,9 @@ actions(Sign in/Sign out) performed by them. 'installable': True, 'auto_install': False, 'certificate': '0063495605613', + + #web + "js": ["static/src/js/sign_in_out.js"], + 'qweb' : ["static/src/xml/sign_in_out.xml"], } # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/hr_attendance/static/src/img/emp-in-disable.png b/addons/hr_attendance/static/src/img/emp-in-disable.png new file mode 100644 index 0000000000000000000000000000000000000000..1968e0de46434949ddb12393f4f21895270a334c GIT binary patch literal 1135 zcmV-#1d#iQP)kdg00001b5ch_0Itp) z=>Px#0%A)?L;(MXkIcUS000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iyb&2sa_Q z3&GR?00Z+$L_t(Y$BmR*Y*b|s$A5Fq>Dk@ZQkF#u6eyrrg9t^agh&iZ;K55`)F3_( zUwsf`AjlK77^_l~#=GH35^rGS#XuiSj3(Zt2oDqqAxgypEiK({yW8Ef=ljNoJ-yh{ zmYJO7!vitH6I{_{Z0XG;RM}XoG zqXLHvedJKJl0I2zEPl7Y@GM`9HSv44eXyfpI1-OfCFPV;Nfk+wWVuK;Llg)kz^(C~ zh*hsXc_>#l{t9inUX8dojC`Pga*1|=(l%fL2gR}G^Q*fKrXvPlvhwLI+Ytw_xCkH! z4nmrCvXMGd)MFUHQ5sry#e=M40ftZv)^m57 zg`-lA&k<3s<70493?LW+x+C&Q9$+!;v@wK>i=*CM+&>DC@3lDm!&(%J0~iD$OBThD zU=vFTFl@#nPX~R1_@z^*C4p0tz@1%o+jkT7TL| zEh!9cB;gVRmpm7^M#%4Mz;cRS;)D#4#A>F0L4f@}AN4GM0_FCn#`XyC_=%|A*$OVKrAy=tl5y~*LsnmoN{Xo(e+r}0} zNYuoibgE;TkP5AmBq>cvMR4ieLro{L#RZAZ;Jo`002ovPDHLkV1o9X B3oQTu literal 0 HcmV?d00001 diff --git a/addons/hr_attendance/static/src/img/emp-in.png b/addons/hr_attendance/static/src/img/emp-in.png new file mode 100644 index 0000000000000000000000000000000000000000..26e3c01556b290949b104240e73fe43dc27b1229 GIT binary patch literal 2153 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 literal 0 HcmV?d00001 diff --git a/addons/hr_attendance/static/src/img/emp-out.png b/addons/hr_attendance/static/src/img/emp-out.png new file mode 100644 index 0000000000000000000000000000000000000000..d2a6cbb50137c404d3f188151bb64024c082b75a GIT binary patch literal 2062 zcmV+p2=VucP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iyb& z2ssF4I&?Mw00)jqL_t(o!?l)aY+c0_$A2^T-nTjNvtws-UhLR01rq`#aY8|rT1WsD zXe*J3N=T?dNG+9sR?rj?NaL6Uw?wj9K2+ip5fBz*q^c4~h`nMfS#U+-gecD9=LF(4 zes_t}ntkOg(5(Y+eYob#XmIsbD8E^usV-!l2X^~u&nk8j=Fy!EeJ>nGOQ z+S)G2o_(PJ>>!xCdCSJXU()!4U(K$XO(L13Saf;u8VV z70oLIl#0b1Y}>(cqOXV$1U^CF<9R+{WY_LpYWHV*uFZ{&e)5+s+so<~2 zCbu^)Z^rk1rIa8NO=AROLPShyEjkkfp<2GInHgne+rP{Cd4*u>6RizRO-tIUtExq7 zrIgY{Q=ybXL>2A?pdym$s4ZEf}U?%n&05m6$BFr2!%?+0fj;dB<1LUkY5w`0Q}AIpF5N?5;W zQ6XPEeb*IBmg4)~WDO9RP{q^~5mKo#-gxs3o_&7Ds{XI~^WUoyZrt?9udi8o?e_AS zY3bhoxw>)nO?aMHqM6BB0HC!d7K`)tJ8v<6-U8X%{rSGSnX|9Tjt!ZIAKq}`0RFsb z!~M74zV@m5MGa)LS&kp?W8eOLT;6mUjf)#6dH`B$j4|{a?qUCd{VcuWDi+q)OV#W- zY=7>V;}8ArfrS^$z{ZvhxBTL^U%uA3xKYB;DBt(#@9$@1WQ1&AmVtqjIF5}Ii{pD9 zz8^4W-hAdbacYhnq59Av;zy4NMVEtPxxVC)qxW7pGV=O40kpKVPzcAJmCLRvuDX7; z_B0x<815SB4*fuy0%C=FKg$5M_0YimCgRS+hPaNlG-&qHiEn9xC>lS2!p(w{9om-Yg zMMVV_6_ru)X~obBFS0NQU}y-H&x7lN)<{zm96N>pCNic@dY(>e{m*@gMD46%@#HiB z9UUF)>;CWBOE0|)*Y%WbTP1l3T014#sZu8dtrfWwUo!X8Pmy#wD$ApzFf;@=-;BEJ zE())|j=OFhp$H)$pbi@oTjIL^m=9~Fh2V}m?jSJX)w3$A1O%lNCr|bh0TGO0Qu|>T zB0%ugo5cG1P=^mgPY?9=A_D`^*@*-J$vf{P@yaU%O5p>3$=3<3Z~q{jPJbf@l8MAD zrBEWmz`!7}m_rzbr4X3OPA6grL~uU-7>*o4CT0+z90yY@;@x*202OQ2Fu$XNLJ5Qb z*DYR5CX;FY27qGG9h}g1Z*MQ@bb7MJPrQ64TCQ(GVuyN=zCP5kW5_MHpk8|odH;R% z?%l*YI}xqH7^>Hs0q8%dbY=l2c_4lKH%q#ji`7WEQ`PxSA9!&ocBuS zOWC^GMO0Q+5Rb>PEDNPnq<5u(C<&G0P`v*E{O5OIl_V1Y9^eAA)~_e?+ zojZ|O3}xF$c{%&P{POCrH=`I(W7%5$^e5M^C@V{eh^VOEPe_qc6ai!K%2H(Zd`4>K zOcLodGty~hRaP?ho_na+wr!eoY#Ze`h-HbJOb*s`bv^X;91y^~^g_qKp5O88hpy+V z88c>1zJj9I2h*lnxsub18;Cm&sbrE=B0=1?(P4-T4`e^x?<5`i^H$g(kd2L=r{}w&UP?0e%qRdp@ok_5Q(zdaD2PDQbLN6es~ycQ@+k zr%_*h6*+dC2t*>mIDA;ObLVe2ouwHifH}ZiAO(1JbqnVL%#eB6l=M1j_kQ>_u(7L`h=F=IYDc;LY5dBtKOQz)FZ8#+L;loRTF-VG>a zev?kmYt3ZZDsB6=SV?}^HWG_bwC%x>@$n}X?Ai0TV~K>+6^rNhAi0?F9Hf8T)YM#_ sOxA?p4h|0=y!`0VE`UwI<}>#G5B|MNh_viC#{d8T07*qoM6N<$f(9txod5s; literal 0 HcmV?d00001 diff --git a/addons/hr_attendance/static/src/img/icon.png b/addons/hr_attendance/static/src/img/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..297dc71c85c5fdd8deafabfbb46093e04adc32d1 GIT binary patch literal 5938 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 HxC&%52rYWz659b%5VwO|`_ zaaQ#=6u&oY2zu6@mqcZA?3^$LLA1@GkSu(6^PPQWZZY;7F6YC8a_lpM(DkSGftGO% z_um`BHhClkx;H`JSk~Ttd5GY({L&1e?@ro;X?i4Ydl);F;wRVRx9Bn&kc!o)Sl~z_ z5CQ#86V0KQ-(9hBGUwud@rXduz%Mk|H{?8!wKzZ-O|LnpQ?+E;o^A!~V>^k6D6xnd zIH(qQ2<1O5{oVuI+Z|4ljOkl$8fWCQoRVkuv)in~o164Wzg-7S+U)G*09}+29bg-k z6|fFK0<%QNWb+Fb+3iD13oqZpvlsX3_mojiiInYFH`6Hf7)O~;ahL_4ubvp9`%UGp z$4M(6d~&)2-lA0-nLOpnwZuxjB`(iIufhdS;V%yiTBR5ca;J7Iwk%4mY5;+dFI7V; zz7^=|Q!NMo{@GM4@(t6Bw4yNg>M1as7 z(YKyLW4AaK(X=h#HMD}7BWG+}9EgNBfcL11b-Jw{g-ZnBAypD%V{C=a_RP9+%&mXv zYA!=`cuYK?S`G+ECwenaSJ^Yf?T3E1pL`42z?_cH$B1^Uy`R%FUR#geTc;oQU4v5O zDWGtLejeaw9f<(a^=oi+1*;)Np4onst25!+{sHy+FbRRd zPn{b1<`{#;i4{Pd-v>#1N^|3=j~2yNm1MJzAOMP%14VIuUuBixf~dO?jso!wj36qN#&u}7i( z(&mmB*QfBxJUKMh_Wbz~@Oh@10!Aik%d(Qjwj{icpZ#2S^1pDcuy{pM!1qsjWuJci zcS>gZplI~L&iaGBn5~cfKOpe&@Q8B$d%XO5yaHmp{9-&j>^yw`@*g!m+W*Jk?rG=j z5cK~yWRfPA{WFmNH$m6a;X{D6k3B*_KmeDshpVrxwU<4Yr;lU)xdg?(CInSQ4TVNI HtLXm&e3x`` literal 0 HcmV?d00001 diff --git a/addons/hr_attendance/static/src/js/sign_in_out.js b/addons/hr_attendance/static/src/js/sign_in_out.js new file mode 100644 index 00000000000..0a0174d0a89 --- /dev/null +++ b/addons/hr_attendance/static/src/js/sign_in_out.js @@ -0,0 +1,82 @@ +openerp.hr_attendance = function(openerp) { + + openerp.hr_attendance.SignIn = openerp.web.Widget.extend({ + template: 'SignInNotifier', + start: function() { + this.$element.on('click', '.sign_in', this.getParent().on_sign_in_out); + } + }); + + openerp.hr_attendance.SignOut = openerp.web.Widget.extend({ + template: 'SignOutNotifier', + + start: function() { + this.$element.on('click', '.sign_out', this.getParent().on_sign_in_out); + } + }); + + openerp.hr_attendance.SignInOut = openerp.web.Widget.extend({ + template: "SignInOutNotifier", + init: function() { + this._super.apply(this, arguments); + this.dataset = new openerp.web.DataSetSearch( + this, + 'hr.employee', + this.session.user_context, + [['user_id','=', this.session.uid]]); + }, + + start: function() { + return this.dataset.read_slice(['state']).done(this.do_sign_in_out); + }, + + do_sign_in_out: function(user) { + if(_.isEmpty(user)) return; + if(user[0]['state'] === 'present') { + this.sign_out = new openerp.hr_attendance.SignOut(this); + this.sign_out.appendTo(this.$element); + } else { + this.sign_in = new openerp.hr_attendance.SignIn(this); + this.sign_in.appendTo(this.$element); + } + }, + + on_sign_in_out: function(evt) { + var self = this; + new openerp.web.DataSetSearch( + this, + 'ir.actions.act_window', + {}, + [['res_model', '=', 'hr.sign.in.out']]) + .read_slice().done(function(action) { + action = action[0]; + action.context = JSON.parse(action.context); + var action_manager = new openerp.web.ActionManager(self); + action_manager.do_action(action, self.on_close); + }); + }, + + on_close: function() { + if(this.sign_in) { + this.sign_in.destroy(); + this.sign_out = new openerp.hr_attendance.SignOut(this); + this.sign_out.appendTo(this.$element); + } else if(this.sign_out) { + this.sign_out.destroy(); + this.sign_in = new openerp.hr_attendance.SignIn(this); + this.sign_in.appendTo(this.$element); + } + } + }); + + openerp.web.UserMenu.include({ + do_update: function() { + var self = this; + this._super(); + this.update_promise.then(function() { + self.hr_sign_in_out = new openerp.hr_attendance.SignInOut(self); + self.hr_sign_in_out.appendTo(openerp.webclient.$element.find('.oe_systray')) + }); + } + }); +} diff --git a/addons/hr_attendance/static/src/xml/sign_in_out.xml b/addons/hr_attendance/static/src/xml/sign_in_out.xml new file mode 100644 index 00000000000..e28b93dfa6c --- /dev/null +++ b/addons/hr_attendance/static/src/xml/sign_in_out.xml @@ -0,0 +1,28 @@ + \ No newline at end of file diff --git a/addons/hr_attendance/wizard/hr_attendance_sign_in_out.py b/addons/hr_attendance/wizard/hr_attendance_sign_in_out.py index 55edb1406e8..15e8783d660 100644 --- a/addons/hr_attendance/wizard/hr_attendance_sign_in_out.py +++ b/addons/hr_attendance/wizard/hr_attendance_sign_in_out.py @@ -69,6 +69,7 @@ class hr_sign_in_out(osv.osv_memory): _columns = { 'name': fields.char('Employees name', size=32, required=True, readonly=True), 'state': fields.char('Current state', size=32, required=True, readonly=True), + 'date': fields.datetime('Date'), 'emp_id': fields.many2one('hr.employee', 'Empoyee ID', readonly=True), } diff --git a/addons/hr_attendance/wizard/hr_attendance_sign_in_out_view.xml b/addons/hr_attendance/wizard/hr_attendance_sign_in_out_view.xml index 5121a2d18a0..b729dd85e5b 100644 --- a/addons/hr_attendance/wizard/hr_attendance_sign_in_out_view.xml +++ b/addons/hr_attendance/wizard/hr_attendance_sign_in_out_view.xml @@ -10,15 +10,16 @@