diff --git a/addons/hw_escpos/controllers/logo_grayscale.png b/addons/hw_escpos/controllers/logo_grayscale.png deleted file mode 100644 index acc3fa43f77..00000000000 Binary files a/addons/hw_escpos/controllers/logo_grayscale.png and /dev/null differ diff --git a/addons/hw_escpos/controllers/main.py b/addons/hw_escpos/controllers/main.py index c4031417357..fbc79865297 100644 --- a/addons/hw_escpos/controllers/main.py +++ b/addons/hw_escpos/controllers/main.py @@ -123,7 +123,8 @@ class EscposDriver(hw_proxy.Proxy): eprint.text(receipt['company']['email'] + '\n') if check(receipt['company']['website']): eprint.text(receipt['company']['website'] + '\n') - + if check(receipt['header']): + eprint.text(receipt['header']+'\n') if check(receipt['cashier']): eprint.text('-'*32+'\n') eprint.text('Served by '+receipt['cashier']+'\n') @@ -177,6 +178,8 @@ class EscposDriver(hw_proxy.Proxy): eprint.text(printline(_('Taxes'),money(receipt['total_tax']),width=40, ratio=0.6)) # Footer + if check(receipt['footer']): + eprint.text('\n'+receipt['footer']+'\n\n') eprint.text(receipt['name']+'\n') eprint.text( str(receipt['date']['date']).zfill(2) +'/'+ str(receipt['date']['month']+1).zfill(2) diff --git a/addons/hw_proxy/controllers/main.py b/addons/hw_proxy/controllers/main.py index c3e01a34822..9b8e87bb4ac 100644 --- a/addons/hw_proxy/controllers/main.py +++ b/addons/hw_proxy/controllers/main.py @@ -136,6 +136,17 @@ class Proxy(http.Controller): def print_receipt(self, receipt): print 'print_receipt' + str(receipt) + @http.route('/hw_proxy/is_scanner_connected', type='json', auth='admin') + def print_receipt(self, receipt): + print 'is_scanner_connected?' + return False + + @http.route('/hw_proxy/scanner', type='json', auth='admin') + def print_receipt(self, receipt): + print 'scanner' + time.sleep(10) + return '' + @http.route('/hw_proxy/log', type='json', auth='admin') def log(self, arguments): _logger.info(' '.join(str(v) for v in arguments)) diff --git a/addons/hw_scanner/__init__.py b/addons/hw_scanner/__init__.py new file mode 100644 index 00000000000..a208bc1c551 --- /dev/null +++ b/addons/hw_scanner/__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_scanner/__openerp__.py b/addons/hw_scanner/__openerp__.py new file mode 100644 index 00000000000..9007304f2ae --- /dev/null +++ b/addons/hw_scanner/__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': 'Barcode Scanner Hardware Driver', + 'version': '1.0', + 'category': 'Hardware Drivers', + 'sequence': 6, + 'summary': 'Hardware Driver for Barcode Scanners', + 'description': """ +Barcode Scanner Hardware Driver +================================ + +This module allows the web client to access a remotely installed barcode +scanner, and is used by the posbox to provide barcode scanner support to the +point of sale module. + +""", + 'author': 'OpenERP SA', + 'depends': [], + 'test': [ + ], + 'installable': True, + 'auto_install': False, +} + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/hw_scanner/controllers/__init__.py b/addons/hw_scanner/controllers/__init__.py new file mode 100644 index 00000000000..b5f0bcc9ec6 --- /dev/null +++ b/addons/hw_scanner/controllers/__init__.py @@ -0,0 +1,3 @@ +import main +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: + diff --git a/addons/hw_scanner/controllers/main.py b/addons/hw_scanner/controllers/main.py new file mode 100644 index 00000000000..82e940cc5c3 --- /dev/null +++ b/addons/hw_scanner/controllers/main.py @@ -0,0 +1,125 @@ +# -*- coding: utf-8 -*- +import logging +import os +from os import listdir +from os.path import join +import openerp +import openerp.addons.hw_proxy.controllers.main as hw_proxy +from openerp.tools.translate import _ + +from openerp import http +from openerp.http import request + +_logger = logging.getLogger(__name__) + +from evdev import InputDevice, ecodes, categorize, list_devices +from select import select + +class ScannerDriver(hw_proxy.Proxy): + def __init__(self): + self.input_dir = '/dev/input/by-id/' + self.keymap = { + 2: ("1","!"), + 3: ("2","@"), + 4: ("3","#"), + 5: ("4","$"), + 6: ("5","%"), + 7: ("6","^"), + 8: ("7","&"), + 9: ("8","*"), + 10:("9","("), + 11:("0",")"), + 12:("-","_"), + 13:("=","+"), + # 14 BACKSPACE + # 15 TAB + 16:("q","Q"), + 17:("w","W"), + 18:("e","E"), + 19:("r","R"), + 20:("t","T"), + 21:("y","Y"), + 22:("u","U"), + 23:("i","I"), + 24:("o","O"), + 25:("p","P"), + 26:("[","{"), + 27:("]","}"), + # 28 ENTER + # 29 LEFT_CTRL + 30:("a","A"), + 31:("s","S"), + 32:("d","D"), + 33:("f","F"), + 34:("g","G"), + 35:("h","H"), + 36:("j","J"), + 37:("k","K"), + 38:("l","L"), + 39:(";",":"), + 40:("'","\""), + 41:("`","~"), + # 42 LEFT SHIFT + 43:("\\","|"), + 44:("z","Z"), + 45:("x","X"), + 46:("c","C"), + 47:("v","V"), + 48:("b","B"), + 49:("n","N"), + 50:("m","M"), + 51:(",","<"), + 52:(".",">"), + 53:("/","?"), + # 54 RIGHT SHIFT + 57:(" "," "), + } + + def get_device(self): + devices = [ device for device in listdir(self.input_dir)] + keyboards = [ device for device in devices if 'kbd' in device ] + scanners = [ device for device in devices if ('barcode' in device.lower()) or ('scanner' in device.lower()) ] + if len(scanners) > 0: + return InputDevice(join(self.input_dir,scanners[0])) + elif len(keyboards) > 0: + return InputDevice(join(self.input_dir,keyboards[0])) + else: + return None + + @http.route('/hw_proxy/is_scanner_connected', type='http', auth='admin') + def is_scanner_connected(self): + return self.get_device() != None + + @http.route('/hw_proxy/scanner', type='http', auth='admin') + def scanner(self): + device = self.get_device() + barcode = [] + shift = False + if not device: + return '' + else: + device.grab() + while True: + r,w,x = select([device],[],[],10) + if len(r) == 0: # timeout + device.ungrab() + return '' + for event in device.read(): + if event.type == ecodes.EV_KEY: + if event.value == 1: # keydown events + print categorize(event) + if event.code in self.keymap: + if shift: + barcode.append(self.keymap[event.code][1]) + else: + barcode.append(self.keymap[event.code][0]) + elif event.code == 42 or event.code == 54: # SHIFT + shift = True + elif event.code == 28: # ENTER + device.ungrab() + return ''.join(barcode); + elif event.value == 0: #keyup events + if event.code == 42 or event.code == 54: # LEFT SHIFT + shift = False + + diff --git a/addons/point_of_sale/point_of_sale.py b/addons/point_of_sale/point_of_sale.py index e34207cbdc3..78f5b0d8417 100644 --- a/addons/point_of_sale/point_of_sale.py +++ b/addons/point_of_sale/point_of_sale.py @@ -58,13 +58,15 @@ class pos_config(osv.osv): help="Accounting journal used to post sales entries."), 'iface_self_checkout' : fields.boolean('Self Checkout Mode', help="Check this if this point of sale should open by default in a self checkout mode. If unchecked, OpenERP uses the normal cashier mode by default."), - 'iface_cashdrawer' : fields.boolean('Cashdrawer Interface'), - 'iface_payment_terminal' : fields.boolean('Payment Terminal Interface'), - 'iface_electronic_scale' : fields.boolean('Electronic Scale Interface'), - 'iface_vkeyboard' : fields.boolean('Virtual KeyBoard Interface'), - 'iface_print_via_proxy' : fields.boolean('Print via Proxy'), + 'iface_cashdrawer' : fields.boolean('Cashdrawer',help="Automatically open the cashdrawer"), + 'iface_payment_terminal' : fields.boolean('Payment Terminal', help="Enables Payment Terminal integration"), + 'iface_electronic_scale' : fields.boolean('Electronic Scale', help="Enables Electronic Scale integration"), + 'iface_vkeyboard' : fields.boolean('Virtual KeyBoard', help="Enables an integrated Virtual Keyboard"), + 'iface_print_via_proxy' : fields.boolean('Print via Proxy', help="Bypass browser printing and prints via the hardware proxy"), 'iface_invoicing': fields.boolean('Invoicing',help='Enables invoice generation from the Point of Sale'), 'iface_big_scrollbars': fields.boolean('Large Scrollbars',help='For imprecise industrial touchscreens'), + 'receipt_header': fields.text('Receipt Header',help="A short text that will be inserted as a header in the printed receipt"), + 'receipt_footer': fields.text('Receipt Footer',help="A short text that will be inserted as a footer in the printed receipt"), 'state' : fields.selection(POS_CONFIG_STATE, 'Status', required=True, readonly=True), 'sequence_id' : fields.many2one('ir.sequence', 'Order IDs Sequence', readonly=True, diff --git a/addons/point_of_sale/point_of_sale_view.xml b/addons/point_of_sale/point_of_sale_view.xml index bdd59f98a49..af98eb698f0 100644 --- a/addons/point_of_sale/point_of_sale_view.xml +++ b/addons/point_of_sale/point_of_sale_view.xml @@ -786,7 +786,7 @@ - + @@ -796,10 +796,14 @@ - + + + + + diff --git a/addons/point_of_sale/static/src/js/models.js b/addons/point_of_sale/static/src/js/models.js index 2d2965f3117..7ac2f42212e 100644 --- a/addons/point_of_sale/static/src/js/models.js +++ b/addons/point_of_sale/static/src/js/models.js @@ -138,6 +138,7 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal 'iface_self_checkout', 'iface_led', 'iface_cashdrawer', 'iface_payment_terminal', 'iface_electronic_scale', 'iface_barscan', 'iface_vkeyboard', 'iface_print_via_proxy','iface_cashdrawer','iface_invoicing','iface_big_scrollbars', + 'receipt_header','receipt_footer', 'state','sequence_id','session_ids'], [['id','=', self.pos_session.config_id[0]]] ); @@ -869,6 +870,8 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal client: client ? client.name : null , invoice_id: null, //TODO cashier: cashier ? cashier.name : null, + header: this.pos.config.receipt_header || '', + footer: this.pos.config.receipt_footer || '', precision: { price: 2, money: 2,