[IMP] point_of_sale: ESC/POS receipt printing

bzr revid: fva@openerp.com-20131220163057-9nu1u7hti0m8wo3h
This commit is contained in:
Frédéric van der Essen 2013-12-20 17:30:57 +01:00
parent 2fec901cb5
commit 293001c826
8 changed files with 232 additions and 2 deletions

View File

@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
# 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 <http://www.gnu.org/licenses/>.
#
##############################################################################
import controllers
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -0,0 +1,46 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
# 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 <http://www.gnu.org/licenses/>.
#
##############################################################################
{
'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:

View File

@ -0,0 +1,3 @@
import main
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -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

View File

@ -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');

View File

@ -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});
},

View File

@ -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,