2013-12-20 16:30:57 +00:00
# -*- coding: utf-8 -*-
2014-02-10 13:31:09 +00:00
import commands
2013-12-20 16:30:57 +00:00
import logging
import simplejson
import os
2013-12-24 15:11:12 +00:00
import io
import base64
2013-12-20 16:30:57 +00:00
import openerp
import time
import random
2013-12-26 16:56:20 +00:00
import math
2014-01-30 18:21:09 +00:00
import md5
2013-12-20 16:30:57 +00:00
import openerp . addons . hw_proxy . controllers . main as hw_proxy
import subprocess
2014-02-06 14:05:24 +00:00
from threading import Thread , Lock
2014-01-26 18:35:00 +00:00
from Queue import Queue , Empty
2014-01-14 10:31:17 +00:00
try :
import usb . core
2014-01-16 10:17:55 +00:00
except ImportError :
2014-01-14 10:31:17 +00:00
usb = None
2014-01-28 11:33:09 +00:00
try :
from . . import escpos
from . . escpos import printer
2014-01-29 19:08:34 +00:00
from . . escpos import supported_devices
2014-01-28 11:33:09 +00:00
except ImportError :
escpos = printer = None
2013-12-24 15:11:12 +00:00
from PIL import Image
2013-12-20 16:30:57 +00:00
from openerp import http
from openerp . http import request
from openerp . addons . web . controllers . main import manifest_list , module_boot , html_template
2014-01-28 11:33:09 +00:00
from openerp . tools . translate import _
2013-12-20 16:30:57 +00:00
_logger = logging . getLogger ( __name__ )
2014-01-26 18:35:00 +00:00
class EscposDriver ( Thread ) :
def __init__ ( self ) :
Thread . __init__ ( self )
2014-01-26 19:40:55 +00:00
self . queue = Queue ( )
2014-02-06 14:05:24 +00:00
self . lock = Lock ( )
2014-01-26 18:35:00 +00:00
self . status = { ' status ' : ' connecting ' , ' messages ' : [ ] }
2014-01-29 16:32:59 +00:00
def connected_usb_devices ( self ) :
2014-01-13 09:23:22 +00:00
connected = [ ]
2014-01-29 16:32:59 +00:00
for device in supported_devices . device_list :
2014-01-13 09:23:22 +00:00
if usb . core . find ( idVendor = device [ ' vendor ' ] , idProduct = device [ ' product ' ] ) != None :
connected . append ( device )
return connected
2014-02-06 14:05:24 +00:00
def lockedstart ( self ) :
self . lock . acquire ( )
if not self . isAlive ( ) :
2014-02-10 13:31:09 +00:00
self . daemon = True
2014-02-06 14:05:24 +00:00
self . start ( )
self . lock . release ( )
2013-12-20 16:30:57 +00:00
2013-12-26 16:56:20 +00:00
def get_escpos_printer ( self ) :
2014-01-26 18:35:00 +00:00
try :
2014-01-29 16:32:59 +00:00
printers = self . connected_usb_devices ( )
2014-01-26 18:35:00 +00:00
if len ( printers ) > 0 :
self . set_status ( ' connected ' , ' Connected to ' + printers [ 0 ] [ ' name ' ] )
return escpos . printer . Usb ( printers [ 0 ] [ ' vendor ' ] , printers [ 0 ] [ ' product ' ] )
else :
self . set_status ( ' disconnected ' , ' Printer Not Found ' )
return None
except Exception as e :
self . set_status ( ' error ' , str ( e ) )
2013-12-26 16:56:20 +00:00
return None
2014-01-26 18:35:00 +00:00
def get_status ( self ) :
self . push_task ( ' status ' )
return self . status
2014-02-06 13:20:39 +00:00
def open_cashbox ( self , printer ) :
2014-01-26 18:35:00 +00:00
printer . cashdraw ( 2 )
printer . cashdraw ( 5 )
def set_status ( self , status , message = None ) :
if status == self . status [ ' status ' ] :
if message != None and message != self . status [ ' messages ' ] [ - 1 ] :
self . status [ ' messages ' ] . append ( message )
2014-01-24 17:31:19 +00:00
else :
2014-01-26 18:35:00 +00:00
self . status [ ' status ' ] = status
if message :
self . status [ ' messages ' ] = [ message ]
else :
self . status [ ' messages ' ] = [ ]
if status == ' error ' and message :
_logger . error ( ' ESC/POS Error: ' + message )
elif status == ' disconnected ' and message :
_logger . warning ( ' ESC/POS Device Disconnected: ' + message )
def run ( self ) :
2014-02-18 11:08:24 +00:00
if not escpos :
_logger . error ( ' ESC/POS cannot initialize, please verify system dependencies. ' )
return
2014-01-26 18:35:00 +00:00
while True :
try :
timestamp , task , data = self . queue . get ( True )
printer = self . get_escpos_printer ( )
if printer == None :
if task != ' status ' :
self . queue . put ( ( timestamp , task , data ) )
time . sleep ( 5 )
continue
elif task == ' receipt ' :
if timestamp > = time . time ( ) - 1 * 60 * 60 :
self . print_receipt_body ( printer , data )
printer . cut ( )
elif task == ' cashbox ' :
2014-02-06 13:20:39 +00:00
if timestamp > = time . time ( ) - 12 :
2014-01-26 18:35:00 +00:00
self . open_cashbox ( printer )
2014-02-10 13:31:09 +00:00
elif task == ' printstatus ' :
self . print_status ( printer )
2014-01-26 18:35:00 +00:00
elif task == ' status ' :
pass
except Exception as e :
self . set_status ( ' error ' , str ( e ) )
_logger . error ( e ) ;
def push_task ( self , task , data = None ) :
2014-02-06 14:05:24 +00:00
self . lockedstart ( )
2014-01-26 18:35:00 +00:00
self . queue . put ( ( time . time ( ) , task , data ) )
2014-02-10 13:31:09 +00:00
def print_status ( self , eprint ) :
localips = [ ' 0.0.0.0 ' , ' 127.0.0.1 ' , ' 127.0.1.1 ' ]
ips = [ c . split ( ' : ' ) [ 1 ] . split ( ' ' ) [ 0 ] for c in commands . getoutput ( " /sbin/ifconfig " ) . split ( ' \n ' ) if ' inet addr ' in c ]
ips = [ ip for ip in ips if ip not in localips ]
eprint . text ( ' \n \n ' )
eprint . set ( align = ' center ' , type = ' b ' , height = 2 , width = 2 )
eprint . text ( ' PosBox Status \n ' )
eprint . text ( ' \n ' )
eprint . set ( align = ' center ' )
if len ( ips ) == 0 :
eprint . text ( ' ERROR: Could not connect to LAN \n \n Please check that the PosBox is correc- \n tly connected with a network cable, \n that the LAN is setup with DHCP, and \n that network addresses are available ' )
elif len ( ips ) == 1 :
eprint . text ( ' IP Address \n ' + ips [ 0 ] + ' \n ' )
else :
eprint . text ( ' IP Addresses \n ' )
for ip in ips :
eprint . text ( ip + ' \n ' )
eprint . text ( ' \n \n ' )
eprint . cut ( )
2013-12-26 16:56:20 +00:00
def print_receipt_body ( self , eprint , receipt ) :
2013-12-20 16:30:57 +00:00
def check ( string ) :
return string != True and bool ( string ) and string . strip ( )
def price ( amount ) :
2013-12-26 16:56:20 +00:00
return ( " { 0:. " + str ( receipt [ ' precision ' ] [ ' price ' ] ) + " f} " ) . format ( amount )
def money ( amount ) :
return ( " { 0:. " + str ( receipt [ ' precision ' ] [ ' money ' ] ) + " f} " ) . format ( amount )
def quantity ( amount ) :
if math . floor ( amount ) != amount :
return ( " { 0:. " + str ( receipt [ ' precision ' ] [ ' quantity ' ] ) + " f} " ) . format ( amount )
else :
return str ( amount )
2013-12-20 16:30:57 +00:00
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 '
2014-01-06 14:54:46 +00:00
def print_taxes ( ) :
taxes = receipt [ ' tax_details ' ]
for tax in taxes :
eprint . text ( printline ( tax [ ' tax ' ] [ ' name ' ] , price ( tax [ ' amount ' ] ) , width = 40 , ratio = 0.6 ) )
2013-12-20 16:30:57 +00:00
2013-12-26 16:56:20 +00:00
# Receipt Header
2014-01-30 18:21:09 +00:00
if receipt [ ' company ' ] [ ' logo ' ] :
2014-02-06 15:14:32 +00:00
eprint . set ( align = ' center ' )
2014-01-30 18:21:09 +00:00
eprint . print_base64_image ( receipt [ ' company ' ] [ ' logo ' ] )
2013-12-26 16:56:20 +00:00
eprint . text ( ' \n ' )
else :
eprint . set ( align = ' center ' , type = ' b ' , height = 2 , width = 2 )
eprint . text ( receipt [ ' company ' ] [ ' name ' ] + ' \n ' )
eprint . set ( align = ' center ' , type = ' b ' )
if check ( receipt [ ' shop ' ] [ ' name ' ] ) :
eprint . text ( receipt [ ' shop ' ] [ ' name ' ] + ' \n ' )
if check ( receipt [ ' company ' ] [ ' contact_address ' ] ) :
2014-01-27 16:10:05 +00:00
eprint . text ( receipt [ ' company ' ] [ ' contact_address ' ] + ' \n ' )
2013-12-26 16:56:20 +00:00
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 ' )
2014-01-02 14:15:19 +00:00
if check ( receipt [ ' header ' ] ) :
eprint . text ( receipt [ ' header ' ] + ' \n ' )
2013-12-26 16:56:20 +00:00
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 ) )
2013-12-24 15:11:12 +00:00
else :
2013-12-26 16:56:20 +00:00
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 ( quantity ( line [ ' quantity ' ] ) + ' x ' + price ( line [ ' price ' ] ) , pricestr , ratio = 0.6 , indent = 2 ) )
2013-12-20 16:30:57 +00:00
else :
2013-12-26 16:56:20 +00:00
eprint . text ( printline ( quantity ( 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 money ( receipt [ ' subtotal ' ] ) != money ( receipt [ ' total_with_tax ' ] ) :
2013-12-20 16:30:57 +00:00
eprint . text ( printline ( ' ' , ' ------- ' ) ) ;
2013-12-26 17:08:30 +00:00
eprint . text ( printline ( _ ( ' Subtotal ' ) , money ( receipt [ ' subtotal ' ] ) , width = 40 , ratio = 0.6 ) )
2014-01-06 14:54:46 +00:00
print_taxes ( )
#eprint.text(printline(_('Taxes'),money(receipt['total_tax']),width=40, ratio=0.6))
2013-12-26 16:56:20 +00:00
taxincluded = False
# Total
eprint . text ( printline ( ' ' , ' ------- ' ) ) ;
eprint . set ( align = ' center ' , height = 2 )
2013-12-26 17:08:30 +00:00
eprint . text ( printline ( _ ( ' TOTAL ' ) , money ( receipt [ ' total_with_tax ' ] ) , width = 40 , ratio = 0.6 ) )
2013-12-26 16:56:20 +00:00
eprint . text ( ' \n \n ' ) ;
# Paymentlines
eprint . set ( align = ' center ' )
for line in receipt [ ' paymentlines ' ] :
eprint . text ( printline ( line [ ' journal ' ] , money ( line [ ' amount ' ] ) , ratio = 0.6 ) )
eprint . text ( ' \n ' ) ;
eprint . set ( align = ' center ' , height = 2 )
2013-12-26 17:08:30 +00:00
eprint . text ( printline ( _ ( ' CHANGE ' ) , money ( receipt [ ' change ' ] ) , width = 40 , ratio = 0.6 ) )
2013-12-26 16:56:20 +00:00
eprint . set ( align = ' center ' )
eprint . text ( ' \n ' ) ;
# Extra Payment info
if receipt [ ' total_discount ' ] != 0 :
2013-12-26 17:08:30 +00:00
eprint . text ( printline ( _ ( ' Discounts ' ) , money ( receipt [ ' total_discount ' ] ) , width = 40 , ratio = 0.6 ) )
2013-12-26 16:56:20 +00:00
if taxincluded :
2014-01-06 14:54:46 +00:00
print_taxes ( )
#eprint.text(printline(_('Taxes'),money(receipt['total_tax']),width=40, ratio=0.6))
2013-12-26 16:56:20 +00:00
# Footer
2014-01-02 14:15:19 +00:00
if check ( receipt [ ' footer ' ] ) :
eprint . text ( ' \n ' + receipt [ ' footer ' ] + ' \n \n ' )
2013-12-26 16:56:20 +00:00
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 ) )
2014-01-26 18:35:00 +00:00
driver = EscposDriver ( )
hw_proxy . drivers [ ' escpos ' ] = driver
2014-02-10 13:31:09 +00:00
driver . push_task ( ' printstatus ' )
2013-12-20 16:30:57 +00:00
2014-01-26 18:35:00 +00:00
class EscposProxy ( hw_proxy . Proxy ) :
2014-01-30 12:46:06 +00:00
@http.route ( ' /hw_proxy/open_cashbox ' , type = ' json ' , auth = ' none ' , cors = ' * ' )
2014-01-26 18:35:00 +00:00
def open_cashbox ( self ) :
_logger . info ( ' ESC/POS: OPEN CASHBOX ' )
driver . push_task ( ' cashbox ' )
2014-01-30 12:46:06 +00:00
@http.route ( ' /hw_proxy/print_receipt ' , type = ' json ' , auth = ' none ' , cors = ' * ' )
2014-01-26 18:35:00 +00:00
def print_receipt ( self , receipt ) :
_logger . info ( ' ESC/POS: PRINT RECEIPT ' )
driver . push_task ( ' receipt ' , receipt )