From 293001c826e6b368ae8b3f95b204abf3919efc76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20van=20der=20Essen?= Date: Fri, 20 Dec 2013 17:30:57 +0100 Subject: [PATCH] [IMP] point_of_sale: ESC/POS receipt printing bzr revid: fva@openerp.com-20131220163057-9nu1u7hti0m8wo3h --- addons/hw_escpos/__init__.py | 25 +++ addons/hw_escpos/__openerp__.py | 46 ++++++ addons/hw_escpos/controllers/__init__.py | 3 + .../hw_escpos/controllers/logo_grayscale.png | Bin 0 -> 11377 bytes addons/hw_escpos/controllers/main.py | 143 ++++++++++++++++++ addons/hw_proxy/controllers/main.py | 13 +- addons/point_of_sale/static/src/js/devices.js | 1 + addons/point_of_sale/static/src/js/models.js | 3 +- 8 files changed, 232 insertions(+), 2 deletions(-) create mode 100644 addons/hw_escpos/__init__.py create mode 100644 addons/hw_escpos/__openerp__.py create mode 100644 addons/hw_escpos/controllers/__init__.py create mode 100644 addons/hw_escpos/controllers/logo_grayscale.png create mode 100644 addons/hw_escpos/controllers/main.py diff --git a/addons/hw_escpos/__init__.py b/addons/hw_escpos/__init__.py new file mode 100644 index 00000000000..a208bc1c551 --- /dev/null +++ b/addons/hw_escpos/__init__.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2010 Tiny SPRL (). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +import controllers + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: + diff --git a/addons/hw_escpos/__openerp__.py b/addons/hw_escpos/__openerp__.py new file mode 100644 index 00000000000..a6412061600 --- /dev/null +++ b/addons/hw_escpos/__openerp__.py @@ -0,0 +1,46 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2010 Tiny SPRL (). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + + +{ + 'name': 'ESC/POS Hardware Driver', + 'version': '1.0', + 'category': 'Hardware Drivers', + 'sequence': 6, + 'summary': 'Hardware Driver for ESC/POS Printers and Cashdrawers', + 'description': """ +ESC/POS Hardware Driver +======================= + +This module allows openerp to print with ESC/POS compatible printers and +to open ESC/POS controlled cashdrawers in the point of sale and other modules +that would need such functionality. + +""", + 'author': 'OpenERP SA', + 'depends': [], + 'test': [ + ], + 'installable': True, + 'auto_install': False, +} + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/hw_escpos/controllers/__init__.py b/addons/hw_escpos/controllers/__init__.py new file mode 100644 index 00000000000..b5f0bcc9ec6 --- /dev/null +++ b/addons/hw_escpos/controllers/__init__.py @@ -0,0 +1,3 @@ +import main +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: + diff --git a/addons/hw_escpos/controllers/logo_grayscale.png b/addons/hw_escpos/controllers/logo_grayscale.png new file mode 100644 index 0000000000000000000000000000000000000000..acc3fa43f77b49493c33effd8f1ce88b05108658 GIT binary patch literal 11377 zcmV-%ERNHOP)0040a1ONa4iPf3j00002VoOIv0RM-N z%)bBt010qNS#tmY3ljhU3ljkVnw%H_000McNliru-3kZ^I2n;ux~l*H03vinSad^g zZEa<4bO1wgWnpw>WFTUBAWdOzbYXURVIW6gYHDF}I5EZ7001BWNkls(O0%H8V*jJK2E%LQp^;>_Lr$AYuTypaGG4)vJ&CQ&a@K?$1TRt00J|h=3xy zAi+Qs4TLp>1PDn;LiU9uGnu`+tIqF_I#pd&y-asc&z97i=gE`IoT@r?>U__;zpqG0 zLJBFQgPgQ*2|@}f1bRpzg%kokq>w@ifgVywA%#E>DWs4>pobJvNFmTe3Mr%z=pls^ zQV8^em%<3BkW$GAmtbhXQh0tM3c8O__Y&cvh7B_ zWd@H>?YTarkN`xO)H1L`d-8-D5(vzOz@BD8L&w83UfJ8%Z zCszi3+sH>5#|?_Fqkvw+0e3_>*Yd3)&DC?8m&|#ELmFfqJ=Lll{H-W}I}Q%SK|@n! zGlxo<1XxJ-U4ri+)sfJ{XZcNzPkf3~5E$&|TwYB1?H=v~-r@U6hnSZ`Z~{k;pj=5GH4zkr~io31CpT&a}5oPwYfx#pIb$I7DPowxCckIMl*hvp7Xd^*{PP&lj z2omU+3fA@LlrxFe2FbyS+u5knR@@~d4%Yfxf=UUEIUU26f1QMN_@`5?M$JunU zIfu>qS5D(6+zY@$rjXzamT)eufW=qX&$rW><)XCk#GtL|%p6xYPDiK8ZB(;2;2|x@zFQgQmqg!a`EM^yb=s+OQ-P2rV5Zs}i z1cFOB$`v(-3fLuJa1&q3X>={Kc#`q}v~)hoU;B|u*3(7|_$B{I0x($5*Lgra`*Yls z!aXHA2Uy8(`Q4zb>e0NGldoUW!JoN-?E^5U*+f_d1%?|*x>&_$c%$FvIhiKT<~vF@ z9#GNUdkS{5iN7ki+FFZ5VxlV>vNPUNf{t^giKK^-Tu8kNz#nWeJ{hX=+Z4NZcKRV- zcSU%K!9!f6_fgSh7(B%`R&C>L9$^XP=m<0{dWcg=jB=(ifl=yD zGb5>|gbores5LYqY-cGN)l>}u^PEsZ`&}%`b0$w?P|X+>!=|y02L}M?i#W@DqD2K~ zvxCdpF}Ugl*x;G>fm)2lR#sv(sVk}8P5bJqA^aH=Df6zt!(Bc;?%ew zeI#+7Vgs`|k;D)X;C24Ur^r7e>^gqUulNuUr_g+|X^i4k+H)RXt;~k@#!E1Q+nL1w z02W`QhtGKw3TIX0gJ6)$=cx7a%YmXe3z^G}9G+(&u^jN3{(`@88P~gJ#C`?3z#_s{ zev65q0)YwWbTX2YnU0~%Yl$@aY%PZ~hPQd0IwkCz=rnPFe_-*!L5|p#7|Iu22yNyH z&fs@M3%q^;iz(xIu48qMSA386bEe0gmLSS?jOQu@oqUyz+(-;P#R4Bv>X(0#t^AhR zX`PcpiQeG{n0z+}q-cFv4vB?Dggf{#22n~}KDe22{1-3S>D%{^D5(LU>+;EKF4c1RcKAplqnG` z;!jARo16JBN<6_oA!Vc0T*|sZj5o-YV*C$3$^j`_;V^f!y?a^31RS@%BtZ|KU=eW- zu)VsBUk4T#%;Wfg2q}nh6DtRCQ%W@U($>ej?Bg*6bLq|#<}XsG*1_ZkB78A z=P{Id##vvJi}(=$Cbw}DhA*5cq|CIIPpfFdp}tnv@<(Ofmc<6TqnU5yX5L_o0=3OK zVw}$@Byxxpa%}LWEMNlNN`th|rgA3pN8TDVmQ@!3uuG zM31N4w%i}a6$74yC4m?huy_Es)Clfj4qe!;#uwSlHAK0Oa~0HWSD&B-SiycE!dAXQ zr|&Lh+{)zv(~KSR)5-^U8-NIlxRp2>78cj=+l+I%nMvyKDGr(3&BH+MestR;dNW_m z=(IYAD=E#}rDbpvOLH1|3@h@O=^AEd^rM&Yd*E*vfuo$i6d&7)G6caB`NJ z7Rb>fyvSl|iMSAyKo94$K*2IU?g=I{Xrhw}yvd2>Y-cH_53v1RU||-;zx;K+uk>@l z3g%{Umc7S0EaOB~Ug8wse6C;~FLAUR6k#H$QoprV{0cN4;$rtMT`9&x=gJEH$tVEg z+(A9x&%v`lhog(^6+WNGSj4^}-f;r+(ztGWKgiF)qMQ?Wp_j3niZ;^<>M750A6Frn z?9O%`QLg6pUJlVcS%0rlz#{2v<8DelF*&v{ALk3i3(KuRQpTrLx@XdeCxO@L8DN1= z65)+JJlIJpp@e$QVlK}ik^B&o5=tl`!b!C81tOfrR4RxPB}ysNIi9DHbnrDk$ScZz zs-aQILtMf=BvQ&rIpG-^5i}MextXyFUr967;l{5{7rUMuP!$@yG@ z=7vQV=UC3~kNr*tCB#{dM{!P}PEv=f z>hy38H}fvf(uM};e3&snoG3ryB#vhj6I_`{u!u{T!$-2jUuz@~e1X$=oS!fwgY;ux zeJsD`Kj{Wavu>IGREgkH_VI~9)VsaMWdgx{+|B1{$znZW&}XZYK=Kw}=BF7)mZE1l zkc@mED}klFsZK%RZsRx;IjK)ZGf5MpSc?&G!PT;XV<{P6b6j1{BOAB~!6}>wOb9^S zyJ|XHc#LN;nZRW}6Pi6X!FkN%b3BNyOp*!aa1CEzo@?wBY56rIIEtf~MrXz&!A>2X z$1izhP&aLY6F7n@m8Uqk0J7IK!6$j1TQZJZ#~U0msKHx89qA_DWHHb#5dFMQG?wBlqle(T%LFmOL&GQ+{n-PIOCasNrHr@ z*oG4rX$z~ja|TUF623p)*n%(dSMK*+e=Hk08yzFdAu16hNN@oclR0cyVA9CrlmK0M zS#*oZ(*+4Ca&o>79B-F=hhs91dbdbNW8Z>r?1QPExo%imkYfBP%O274`AD`9@f|)G zs5~x6P|fH*C8F5Z&J2hjwr1MS8|pY2D6;rJO4I(PhEa@UI_qg;33E7=S(KmyrqA0T zJe<^^g)P+ZJtnBT`gO+S>NZox&)MPD+)40ZzQhu$xsjfX@1Lv}+nX)Jq=61f`EO1i zfHa#-GqsB7MX~z0D+B_Q5qU^(g;JuAD=uC6FB4@moEo`5#@@2OqB=#4l<1t+$7}eC4bD9$YZQO2VP(@ifh@7?mp9oUNxU#sw;gED7ow$Mbal48tmsd zHc`UmT$}b>ckU5q1`qO4n)xo*y7#&s$shR&-F(emc^OzY;rmx_FzW)9;4(N|w3sEL zM3L?>^m~)pU%i>?jB%Et7(lnT>@LEZn(ZRon|l+16YK~V2g;0lw3CvbUk<-Mfg;i)&GAr++wZ984CMBie z5@c)7xGf_iu?9uS$u!SR?9DhLRxF^mvr^?hiGVP8LBF1c2HV*}g9;|eB$8?fo@6r{ zsi1}Be8vMxzksbH(Yc=v_RvZx(86dgrO_k2_g3L1Ssl+p=LOc#L!A9U42?3HIF-Xx zTv-BLbyO26M}&?f#+`H!V;v2AhUvuJ!$!C^5c`SQHyqcCjkDm5xd%PNgHG567`>1M1;^R%9HbF+NLqt{j0bfZeR3 zJixc@%(Ih=!c$}hj-HOcN{?A8!INxe7j+7{j!SMtiV;e%hx^$@1&v5gX=%HDT0OUN zat`9Uy*0M;Pc{%|61uC4>ln(GEwF$l7IQRHeNcBexy~N`NDl%-`OV1cL2c3BzeZm9NReX_W zvWz`U9S42j==R0CXs0se%#hR)&!Rc>O>j@Y#NHN3dw7<$NXn6(erS>kS3|~y-t#<7 zgbL-!^*+_s@mCYW$Z{$=(u2+t{zWIXlwwlO3?djLXk{fO819_ojN=i$l7@pE;4PM5 z5~0-N4)l97k{eNHF|W`~xlaYK=hDgaego7Uj4HtPQo;}ED$q8ZKWPQETX6g&_V)i? zmfGZv| ziSRCWA&Iy}52ec)$5M^ui8R-El7CQ7f-d5e5KYm>O^)JKPRO{m?I##);x+^k8j);e z4rjXl0Fzpt^T9R37T#i}Yr(KJ`#t=F*C|zC@YmlFY0O&pu!bn*9$U88SU9rZbo3jC zfo>hgDnLb$%9gT|ja)|Nv^S+2hpij!mJknnySu{G@Cunv(&JS5~kD4TlA!uMkEb^?Cx~h z+-v-i3Zj6?PR`?Wk0VZSCY#uWH(X|fYRQ;vRP}G3z;Klyf8dcut?zi#>EzFBqC9Q= zZh=W9hc?v~oSt(x-Q3RGzUGvv^jd)p9n#S^_)eaC-|Q9O4!xiEWtBXP+&~`Td35}a z96M*tc5BIgGzJMI-6{Yk35b0>$XaSBQ75_|F1u;;n7kr9%qx_!mP?t=2+EnuEp(*l z{k7^ik!gM162VLSjY>)YK^q_DOl3wBZgIXkcKRAn2;ct!9()C=G9;>@!YI}%P)DWSRGFnr#ml(6r)hE(< zm{-uK;s0?s5{ozyj^tUQ_&w};T5Cblf%iI(DozYBW^tNQ4!n0ci8a0z67C3%o&1S5 zN->F0PdnWKE4-zIc_+@Ug`d(xJsnI$(n&`OM?auymK?ej;M!fEPx0x~d|{YG1FU3b zFAAKIEBMT`oI_HRHElnCjjJauH!bmbl`a0la;DJ1$xLQ6_pvd+)610&QlRlPD*>I0 z8Ks09jW}oU1Z62kxy%Qh!3#X$*1xfkG2$L!9z3o!XQ*DEQGFPif`8yEV}D- zu#?ghQI~=YA=!lVox}t7S{vA-Rc@Rk$bXyDnZpd~U4xbIrKCjMw9bcFLkrWnL?zuM z#or3IAyn@&4ZOxPuGl9L)Ny>kLT}3i>wLwv1iRId10B4@SSE7;BPb!kcw$66Z!2iy z1m!6(Xy-}x(9RrACrTW_NUA)^vl2lM4H+T~Lh37x;98CzSXG%tL-$z;Y<_!$;*CproVWQD7ptX6 zdcwgZuF7GhJ96;p{5?ENf`|gIppC<+3Ty-WuCID@X$zf3Hw$0_-=u_zM8Oj;mwcMZ zD5{h)(8aIWKr>e{Ue!Sn>R9z2J_*jvvw3bvxzU%okmK@B85#`wK8te7Gs)5FZu5@R zo0T!0Xc5o7c!nw}{w3F$ukw&>FiARG1;RFDji#IgaaK~rd0ggN#zo4Vvj^!ow44?q zE~nNpm>&rGb^g^#2bDNsH9PpB;?WYFSsrD?0(6x*fG1eSzV23Dr;aZwGo1a-YkU@1 z`-rGJr1kUuqHFkHcio5f>h7Tqa>8HEa$h7(*h-R*70V2#t8f$l&uuQ3j8_+~t=r*r z749{*Z{OzFe_%5s_^dlp`ev>X4HUVM8Nxgc@G7PoM60u#iGd@*alXC5Vk(tFqp^p{ zM8T62Cw z!Ba%Jg64pkO%TBwhMQm_Bm0%-G#3!@DA-d_{oKK)@f^1MAMvbdQpMCi}fj6OOT+1saap99e-X}HHY&K>(M!xsc8ip>5)j1KdVa7 zb_5m%OQ`U@dpFI#aZb$Ka^9vwasB-?aekWPF}ZS2)2*`2ZRKbT4QQ<91-khFAMhlq zNCYu@rtl}BQ5F9|N-q%85ld#UohmGt@5oi~iI zgk5f?xe@ql$)oI=* z3Mu>?Hc^i^#MWX$N+_^K8@EwIm2!I>&XsP#CXwNjTRw-S9j^0J1iSdS@)3AbZc>H+ z3dZ@;bBa$U*684$~dY>&_WN#vPeZpXMS5e!7ma?9Y?X5jlg^r2J1f=~dJWL7+=tlFvXqPxc}% zYv}x&6WNh*)ZH9MQ$H5(a4b9BgZN!?1bS@-$5W(8dB+liHxU?~A7~v4YjaiBrxdn)v`naF}Y6B(gM8 zkihm4;jrH7>QJMG&mvQ((9g&dpZb|rhq7_pdaX`^RwFjK`=h@3b zB3b*1S;Qc~L*k6X$dGqr!)veWzjpZaD3#bM0_sGtq+dD9Sc1tm48~znM?D{M-EA@l zTc|{%oxMIcjxD{k@>NfPEANauI6#drQon&yNf3s=<_dL#saaQQ7W-7?KXE7nU85^a zeHl^2&v2&_oswFpAjUY3bmQUDQzu(gJe_kd$#{kXE%s2V~%bEuO<5a%1jvKD?g zhnI#(1@}P&`eD?jjf^YCW|L^_$5H_~!lUVRFo*gqkd?r84!B-+=XjVxO-Ak27RcAT zLYz~dy^)GQE}Di2G}E#AVs@Phrx8x>YgF)<|nDr%TKmf}K9QahjJpF`I2F#tfv)jnmRH|XW=?Yylvt+(BR#f6mi z(jio+oO0IHM@;zWBW3vDq;%-4Ec_;$ie(BTLi{@JbyI|zD zKDu}$u%7h+lb4`_QB3v0KOJZ~dDFvFC6Hh?HCf}uBr%l`>ioZlb5aC%5N!4N=WScU z2$gT%mxIkx*-=S~5ly2Up-MX6=cxc|uX@8EK&5zqvjSOs10}u-;A$?)GU_p|875U_ z`bBgX#F?N9@cFIMaW-Y`%A6V8(uGqy%c%4;@wHP-N3g(C^PG&PxXmhj#eq<%TSqn1 zvv;vcIky}|p_CZ`iN(2Jc}f!{|A@l2`WChZ4mOKp)4r`!BBRQ82*g;Z5?F^L%q8u# z_mCc4{TA5E)IOtwE-Tor}L_hTnJioL@Y3}3!@oKh~$ zAy!Eu>GYJ1v`aQ0lTmxMM{J|TO+&Qpv1e177C2o2VV;~$`|O*<&X@1>9U3MjDfN4t z_cPeTzCbp;q<&bm_)X8v4bI?w+?6JKVjwhillfU9-vO>?L!YI#VG4A+Q1Q9G2sFnm zw3;n>E{gEAIevkMsrA%@v)j~OM5CK%kQw9#|5kDClHQYSoRHe3RJc9Ybarrz>bRDA zwVrZUBj;l*J>cyU+1moG8epm_Tq#pFrr{yu5R*uPR}ytWxnNB1v+@h$n_+YjOBy8;cGc3F-QbLKk^aYHQ?XMKcDO_8etJ* zec4-?1+kTk^znUDr7vU(uhH4UZCtCC000ZfNkltH%e`Q|+u-121uW#!)68<1Xe8n-1?q)X{BG`EY9K z_LwRJl2SD8A>!6(%|}~$gf$*(vY;Emrx}%lgkaZqd)eLa&QGHmH9uQX_`ABo*3COv zKy$|D=v1VMP z7ntm0J4U~7^d7p3{%0rzqzFuA@`)@X4)7xmF57!vM|PBXRC`25J0)=(FSDIUPOWQ_ zy0qXa{z23=?+JRSwJW*C{gn?iLj8F84L1AN@-GH z@^bVRdQyr!CWU8#P8WCcOH5A8Aojl+XqVW|@mVYkx^G?WlpUw`yU9+z&t=?6SR^uE zD&s~~l{Y;t=f9ODL>@{&mu@-21sw3@X9*IF;ZAlaEueP|R-&Wx7)u%JZevL&Iv;0z zUgA<$0Bl{H;>lz4^M8#Pf2UmW(smMjD2sjGxql+1lFT;Nsxk#KU#-d#3I3HKElK_#v)+S%8;DRX+>-V zIQ)QK*fkQ1t69b)89^N5dprR}Gj^JT>Jl~bJqhDX;gYQ5A!)nK~!crD*R@+6_f??*P}eg8H@;&S+d(E|BcsZLPHSegUmti z73LO4^0?b&-2tYK&hPjLCwbI{&8%fT>#0Ylk~%JDf|6BIGtpYzMiBNLyD7`SmF#us zN$KORbAUf#5=El%ao(4qFW#X+h1MY!SXA+Q8i{9w`rkQ`mxvdsBt>aPv+s}tx=^N| z_fg61RH>#8PGO@S9-@IyrP7Ox%ne6wpSdz;87-1Q&c^pI?#7R&`H@jHKiIkF1 zRp5hC$OgJSptR%IFH5U#IM?WD`ncP0U(az|LZ#b5PULxH7tRrf64%~Cr;2pT7mR`g z)jY&UvW$6|v21nw1oaK>mPg?eLmTMM7ELgft9XF88_{M9&KA44f#WzvS>sU|UKWA~ z+jxou8l_4Wu!vJfEtg~U>NQXIk-7p-B^&Ayw(}DVrgAD06OG+G$3ChtX=5Z`C$|a~j| zS(K;=H#T94gsJi zp+1dI@&>EuL=bTs5$IH~l9w>iDMO=&9=gye!ww-SN5i5Uiz;du#c5O%50r4qWdrDJ zVnbkQ9WGf$8Inz`qnj8yCDc&O0ctsovwNxM=6_F<5uD7+M3sEt)wOXeu3NNGLp`&Y zt;$Ph&eQKwz2cnC=_Zk0L{Ew7;pw*bzk(*_GF_$7N(%Xg2C#|0^VFaKJ<5a}Il0bi zmS$-q@jCyagl1%(#U1Tv&s}Wnb>wDF;VUfUm@FYQ_KNQ3K4Mu9rMH=xBcmz$(V8g0 zpeWs~vVo1fL@OPPLPK*GJ3+S#Ux9&vKts|&2ZAQ1F@cFxq7@YCVMoY6kfwc8P~6kd zkQ|_svp7saBcB6B!{lE)N;Q=MSDQdb&_xRxQGF%DUDQ*-OpYc(d7A38 z$>;0*i#wP}2_}LSOyLUZsPe@lP{2WH@Bmi~VvjVz3%!)%w&&SKeNOi);h(AvL+-Sj zg*=h#+&U-va3(!LgT}aBQB!*5kAQ{QWsB*cY zl~MvRKZOX zI}y4NbkfP>95=g3r%F5y(mv|3=%$PW9n=&cy4&Hy9a+*=+o{B&N9AK=pK(&b>cmLf zo-(f5WSYZ8bPw8Yoki1n5tS?tAL^SqqK8LW=c`L=Qo~hg9T;YY-l_Q=XORs0v&gw} zs8ns2OeN`vUgR04nq9;v$`{L!BbC}@CwUloHB&5An zT8+p%1KG>h^1i3YGHMvO*LsIUZ`@xLVUxm6wz{dB&c>NRNgClwX80I|9cMu~Cii=$ zzP-rfs$%=S1q3?A4~%ABNP7p7<8MVlU$u}O(ARqp21nP5{UQ7R1LJDcnfj$r8jb4xlIf_U(a*Yi#4xgRn$zNFg19KzBUWI=@%V4xDTt zi)QM>7DXY2bg*!Auz(KLfI+xbJ*xts z$uF@prFqfr}8NFfb-pgRd3)js>Wmi$u$2uXms=#YgHXp=O-2kUkL{p z2F`?ZNRY^@oXRlsqqnm)P!}}8C>lKFEOd+liV%bp((t5QyV4FbW1L+q+MAwg(c~#9 zrLmv4h=d$Hq(eY-*VxI^szKO6rK3yUWS`ICF3~CVz545XJKO^y9TK9u#s+?y<7i_z zy_#gVr?#1Wj&*uMWdtV2^5bw1gmj4T^s$_OFaq7A6I7eT7!_!g(##lN(dP=P!tj}p z4hb@u$fPW7C5A1~EnZ_QCtwg^EF;mVVlud$)SOWvg>)$JbGs2pj%79zayY%(E3|P8 zIuR;xs>g-NEFm4bP|wx9HjIFtte@^}PG3l;l8{0=)Myxq?p|>F8#9M64=JRBNJnQ_ zb@dJ@q@hDvxC9}E6aqb@kU|Q99#Tjl4F~%Fw;4ElL{y$U00000NkvXXu0mjfh>v&k literal 0 HcmV?d00001 diff --git a/addons/hw_escpos/controllers/main.py b/addons/hw_escpos/controllers/main.py new file mode 100644 index 00000000000..ad343a511b5 --- /dev/null +++ b/addons/hw_escpos/controllers/main.py @@ -0,0 +1,143 @@ +# -*- coding: utf-8 -*- +import logging +import simplejson +import os +import openerp +import time +import random +import openerp.addons.hw_proxy.controllers.main as hw_proxy +import subprocess +import usb.core +import escpos +import escpos.printer + +from openerp import http +from openerp.http import request +from openerp.addons.web.controllers.main import manifest_list, module_boot, html_template + +_logger = logging.getLogger(__name__) + +class EscposDriver(hw_proxy.Proxy): + + supported_printers = [ + { 'vendor' : 0x04b8, 'product' : 0x0e03, 'name' : 'Epson TM-T20' } + ] + + @http.route('/hw_proxy/open_cashbox', type='json', auth='admin') + def open_cashbox(self): + print 'ESC/POS: OPEN CASHBOX' + + @http.route('/hw_proxy/print_receipt', type='json', auth='admin') + def print_receipt(self, receipt): + print 'ESC/POS: PRINT RECEIPT ' + str(receipt) + + printers = self.connected_usb_devices(self.supported_printers) + + def check(string): + return string != True and bool(string) and string.strip() + + def price(amount): + return "{0:.2f}".format(amount) + + def printline(left, right='', width=40, ratio=0.5, indent=0): + lwidth = int(width * ratio) + rwidth = width - lwidth + lwidth = lwidth - indent + + left = left[:lwidth] + if len(left) != lwidth: + left = left + ' ' * (lwidth - len(left)) + + right = right[-rwidth:] + if len(right) != rwidth: + right = ' ' * (rwidth - len(right)) + right + + return ' ' * indent + left + right + '\n' + + + if len(printers) > 0: + printer = printers[0] + + eprint = escpos.printer.Usb(printer['vendor'], printer['product']) + #eprint.image(os.path.join(os.path.dirname(__file__),'logo_grayscale.png')) + + # Receipt Header + eprint.set(align='center',type='b',height=2,width=2) + eprint.text(receipt['shop']['name'] + '\n') + + eprint.set(align='center',type='b') + if check(receipt['company']['name']): + eprint.text(receipt['company']['name'] + '\n') + if check(receipt['company']['contact_address']): + eprint.text(receipt['company']['contact address'] + '\n') + if check(receipt['company']['phone']): + eprint.text('Tel:' + receipt['company']['phone'] + '\n') + if check(receipt['company']['vat']): + eprint.text('VAT:' + receipt['company']['vat'] + '\n') + if check(receipt['company']['email']): + eprint.text(receipt['company']['email'] + '\n') + if check(receipt['company']['website']): + eprint.text(receipt['company']['website'] + '\n') + + if check(receipt['cashier']): + eprint.text('-'*32+'\n') + eprint.text('Served by '+receipt['cashier']+'\n') + + # Orderlines + eprint.text('\n\n') + eprint.set(align='center') + for line in receipt['orderlines']: + pricestr = price(line['price_display']) + if line['discount'] == 0 and line['unit_name'] == 'Unit(s)' and line['quantity'] == 1: + eprint.text(printline(line['product_name'],pricestr,ratio=0.6)) + else: + eprint.text(printline(line['product_name'],ratio=0.6)) + if line['discount'] != 0: + eprint.text(printline('Discount: '+str(line['discount'])+'%', ratio=0.6, indent=2)) + if line['unit_name'] == 'Unit(s)': + eprint.text( printline( str(line['quantity']) + ' x ' + price(line['price']), pricestr, ratio=0.6, indent=2)) + else: + eprint.text( printline( str(line['quantity']) + line['unit_name'] + ' x ' + price(line['price']), pricestr, ratio=0.6, indent=2)) + + # Subtotal if the taxes are not included + taxincluded = True + if price(receipt['subtotal']) != price(receipt['total_with_tax']): + eprint.text(printline('','-------')); + eprint.text(printline('Subtotal',price(receipt['subtotal']),width=40, ratio=0.6)) + eprint.text(printline('Taxes',price(receipt['total_tax']),width=40, ratio=0.6)) + taxincluded = False + + + # Total + eprint.text(printline('','-------')); + eprint.set(align='center',height=2) + eprint.text(printline(' TOTAL',price(receipt['total_with_tax']),width=40, ratio=0.6)) + eprint.text('\n\n'); + + # Paymentlines + eprint.set(align='center') + for line in receipt['paymentlines']: + eprint.text(printline(line['journal'], price(line['amount']), ratio=0.6)) + + eprint.text('\n'); + eprint.set(align='center',height=2) + eprint.text(printline(' CHANGE',price(receipt['change']),width=40, ratio=0.6)) + eprint.set(align='center') + eprint.text('\n'); + + # Extra Payment info + if receipt['total_discount'] != 0: + eprint.text(printline('Discounts',price(receipt['total_discount']),width=40, ratio=0.6)) + if taxincluded: + eprint.text(printline('Taxes',price(receipt['total_tax']),width=40, ratio=0.6)) + + # Footer + eprint.text(receipt['name']+'\n') + eprint.text( str(receipt['date']['date']).zfill(2) + +'/'+ str(receipt['date']['month']+1).zfill(2) + +'/'+ str(receipt['date']['year']).zfill(4) + +' '+ str(receipt['date']['hour']).zfill(2) + +':'+ str(receipt['date']['minute']).zfill(2) ) + eprint.cut() + return + diff --git a/addons/hw_proxy/controllers/main.py b/addons/hw_proxy/controllers/main.py index 4df01372846..c3e01a34822 100644 --- a/addons/hw_proxy/controllers/main.py +++ b/addons/hw_proxy/controllers/main.py @@ -5,6 +5,10 @@ import os import openerp import time import random +import subprocess +import usb.core +import escpos +import escpos.printer from openerp import http from openerp.http import request @@ -12,12 +16,19 @@ from openerp.addons.web.controllers.main import manifest_list, module_boot, html _logger = logging.getLogger(__name__) -class ProxyController(http.Controller): +class Proxy(http.Controller): def __init__(self): self.scale = 'closed' self.scale_weight = 0.0 pass + def connected_usb_devices(self,devices): + connected = [] + for device in devices: + if usb.core.find(idVendor=device['vendor'], idProduct=device['product']) != None: + connected.append(device) + return connected + @http.route('/hw_proxy/test_connection', type='json', auth='admin') def test_connection(self): _logger.info('Received Connection Test from the Point of Sale'); diff --git a/addons/point_of_sale/static/src/js/devices.js b/addons/point_of_sale/static/src/js/devices.js index a1d8e19aacc..a443c824087 100644 --- a/addons/point_of_sale/static/src/js/devices.js +++ b/addons/point_of_sale/static/src/js/devices.js @@ -331,6 +331,7 @@ function openerp_pos_devices(instance,module){ //module is instance.point_of_sal * } */ print_receipt: function(receipt){ + console.log('PRINT RECEIPT:', receipt); return this.message('print_receipt',{receipt: receipt}); }, diff --git a/addons/point_of_sale/static/src/js/models.js b/addons/point_of_sale/static/src/js/models.js index f269c9be348..f8ddc7cb056 100644 --- a/addons/point_of_sale/static/src/js/models.js +++ b/addons/point_of_sale/static/src/js/models.js @@ -845,7 +845,8 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal date: date.getDate(), // day of the month day: date.getDay(), // day of the week hour: date.getHours(), - minute: date.getMinutes() + minute: date.getMinutes() , + isostring: date.toISOString(), }, company:{ email: company.email,