presik_pos/app/reporting.py

1120 lines
42 KiB
Python
Executable File

# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import os
import logging
import traceback
from datetime import datetime
from decimal import Decimal
import subprocess
import time
from .printing.protocols import FileSSH
try:
from escpos import printer
except ImportError as error:
logging.warning(f"Error importing ! {error}")
pyudev = None
try:
import pyudev
except ImportError as error:
logging.warning(f"Error importing ! {error}")
try:
import cups
except ImportError as error:
logging.warning(f"Error importing ! {error}")
__all__ = ['Receipt']
_ROW_CHARACTERS = 48
_DIGITS = 9
_PRINT_TAX_ID = False
_DIGITS_CODE_RECEIPT = 4
# Type Font Escpos
_FONT_A = 'a' # Normal Font
_FONT_B = 'b' # Condensed Font
OS_NAME = os.name
if OS_NAME == 'posix':
homex = 'HOME'
dirconfig = '.tryton/temp'
elif OS_NAME == 'nt':
homex = 'USERPROFILE'
dirconfig = 'AppData/Local/tryton/temp'
HOME_DIR = os.getenv(homex)
directory = os.path.join(HOME_DIR, dirconfig)
ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
image_test_file = os.path.join(ROOT_DIR, 'image_test.jpeg')
if not os.path.exists(directory):
os.makedirs(directory)
TEMP_INVOICE_FILE = os.path.join(directory, 'invoice.txt')
SSH_PORT = 23
def money(value):
if type(value) is int:
value = int(value)
return '{:,.0f}'.format(value)
dev_printers = {}
if os.name == 'posix' and os.path.exists('/dev/usb'):
for fl in os.listdir('/dev/usb'):
if 'lp' in fl:
dev_printers['usb'] = fl
class Receipt(object):
__name__ = 'frontend_pos.ticket'
def __init__(self, context={}, row_characters=None, logo=None, environment='retail'):
self._company = context.get('company')
self._sale_device = context.get('sale_device')
self._shop = context.get('shop')
self._street = context.get('street')
self._city = context.get('city')
self._phone = context.get('phone')
self._id_number = context.get('id_number')
self._regime_tax = context.get('regime_tax')
self._gta_info = context.get('gta_info')
self._authorizations = context.get('authorizations')
self._user = context.get('user')
self._footer = context.get('footer')
self._header = context.get('header')
self._printing_taxes = context.get('printing_taxes')
self._delta_locale = context.get('delta_locale')
self._environment = environment
self.order_copies = context.get('order_copies') or 0
self.invoice_copies = context.get('invoice_copies') or 0
self.order_kind = 'command' if environment == 'restaurant' else 'dispatch'
self._row_characters = _ROW_CHARACTERS
if context.get('row_characters'):
self._row_characters = int(context.get('row_characters'))
taxes_col = int(self._row_characters / 3)
self.taxes_col_width1 = taxes_col + 4
self.taxes_col_width2 = taxes_col - 3
self.taxes_col_width3 = taxes_col - 1
delivery_col = int(self._row_characters / 3)
self.delivery_col_width1 = delivery_col
self.delivery_col_width2 = delivery_col - 1
self.delivery_col_width3 = delivery_col - 1
payments_col = int(self._row_characters / 3)
self.payments_col_width1 = payments_col + 3
self.payments_col_width2 = payments_col - 2
self.payments_col_width3 = payments_col
order_col_width = int(self._row_characters / 3)
self.order_col_1 = order_col_width - 10
self.order_col_2 = order_col_width + 15
self.order_col_3 = order_col_width - 5
if self._row_characters <= 33:
self.order_col_1 = order_col_width - 6
self._show_position = context.get('show_position')
self._show_discount = context.get('show_discount')
self._print_lines_product = context.get('print_lines_product')
self._img_logo = logo if logo else None
# if logo:
# self._img_logo = StringIO(logo)
def printer_found(self):
return self._printer
def test_printer(self):
try:
if self._interface == 'usb':
if OS_NAME == 'posix':
self._printer = printer.File(
self._device, profile=self._profile)
elif OS_NAME == 'nt':
self._printer = printer.Win32Raw(self._device)
self._printer.open()
elif self._interface == 'network':
try:
host, port = self._device.split(":")
except Exception:
host, port = self._device, None
if port:
self._printer = printer.Network(host, port=int(port), timeout=15)
else:
self._printer = printer.Network(host, timeout=15)
elif self._interface == 'ssh':
self._printer = FileSSH(*self._device.split('@'))
self._printer.open()
if not self._printer:
return
self.print_enter()
try:
self._printer.image(image_test_file, center=True)
except Exception as e:
print(e, 'error')
self.print_enter()
self.print_header()
self._printer.ln(3)
self._printer.cut()
self._printer.cashdraw(2)
self._printer.close()
result = True
except Exception:
logging.exception(f'Error test impresion; interface: {self._interface} device: {self._device}')
result = False
return result
# self._printer.beep()
def config_printer(self, printer):
if dev_printers.get(printer['device']):
device = dev_printers[printer['device']]
else:
device = printer['device']
self._interface = printer['interface']
self._device = device
self._profile = printer['profile']
def check_status(self, interface, device):
status = False
if interface == "network":
if OS_NAME == 'posix':
command = "ping -c 1 "
response = subprocess.call(str(command + device).split(" "))
if response == 0:
status = True
else:
# "ping -n 1"
status = True
elif interface == "usb":
if OS_NAME == 'posix':
status = os.path.exists(device)
elif OS_NAME == 'nt':
status = True
return status
def close_printer(self):
# only close printer in interfaces correct
if self._interface == 'usb' and OS_NAME == 'nt':
self._printer.close()
def set_printer(self):
try:
if self._interface == 'usb':
if OS_NAME == 'posix':
self._printer = printer.File(
self._device, profile=self._profile)
elif OS_NAME == 'nt':
self._printer = printer.Win32Raw(self._device)
self._printer.open()
elif self._interface == 'network':
try:
host, port = self._device.split(":")
except Exception:
host, port = self._device, None
if port:
self._printer = printer.Network(host, port=int(port), timeout=5)
else:
self._printer = printer.Network(host, timeout=5)
if not self._printer:
msg = "Warning: Can not found Printer!"
logging.info("Warning: Can not found Printer!")
return msg
except Exception:
logging.exception(
"Warning: Printer error or device not found!")
logging.info(f'interface: {self._interface}, device: {self._device}')
def print_sale(self, sale, type_doc=None, open_box=False):
try:
# if call this function we can ommit line 216 to 238
msg = self.set_printer()
if msg:
return {"error": msg}
try:
if type_doc in ('invoice', 'quotation') or self._environment == 'retail':
self._print_sale(sale, type_doc, open_box)
else:
self._print_sale_verification(sale)
except Exception:
pass
self._printer.close()
except Exception:
logging.exception("Warning: Printer error or device not found!")
def _print_sale(self, sale, type_doc=None, open_box=False):
short = sale['short_invoice']
self.print_header(short)
self.print_body(sale, type_doc, short)
if not short:
if sale.get('cufe'):
self._printer.text('CUFE: ' + sale['cufe'])
if sale.get('qr_code'):
self.print_qrcode(sale['qr_code'])
self.print_footer(open_box, type_doc, sale['invoice_type'])
else:
self._printer.cut()
# self.print_extra_info(sale)
# if self._interface == 'cups':
# self._file.close()
# self.conn.printFile(self._printer_name, TEMP_INVOICE_FILE,
# 'POS Invoice', {})
# else:
# self._printer.close()
def _print_sale_verification(self, sale):
self.print_header_sale_verification(sale)
self.print_sale_lines(sale)
self.print_totals(sale, short=None, doc='sale_verification')
self._printer.ln(3)
self._printer.cut()
self._printer.ln(2)
# self._printer.close()
def print_line(self, *args):
text = ''
for arg in args:
text += arg + ' '
self._printer.text(text.rstrip())
def word_space(self, word, space, aling):
space = space - len(word)
if aling == 'right':
text = ' ' * space + word
elif aling == 'left':
text = word + ' ' * space
return text
def print_delivery_report(self, data):
self.set_printer()
self._printer.set(align='center')
self._printer.text('REPORTE DE ENTREGA DE DOMICILIARIOS')
self._printer.ln(2)
self.print_horinzontal_line()
self._printer.set(align='left')
name = data['name']
sale_date = data['sale_date']
self._printer.text(f'DOMICILIARIO: {name}')
self.print_enter()
self._printer.text(f'FECHA: {sale_date}')
self.print_enter()
self.print_horinzontal_line()
self.print_enter()
for sale in data['sales']:
sale_total = self.word_space(money(sale['total']), 9, 'right')
sale_number = self.word_space(sale['number'], 9, 'left')
address = sale['consumer_address']
character_address = self._row_characters - 20
if len(address) > character_address:
address = address[:character_address]
address = self.word_space(address, character_address, 'left')
self.print_line(sale_number, address, sale_total)
self._printer.ln(2)
total = money(data['total'])
self._printer.text(f'TOTAL: {total}')
self.print_enter()
self._printer.cut()
self._printer.ln(2)
self._printer.close()
def print_count_money(self, data):
self.set_printer()
self._printer.set(align='center')
self.print_enter()
self._printer.text('REPORTE DE DINERO EN CAJA')
self._printer.ln(2)
self.print_horinzontal_line()
self._printer.set(align='left')
type_ = data['type']
self._printer.text(f'TIPO: {type_}')
self.print_enter()
now = datetime.now()
print_date = now.strftime("%Y-%m-%d %H:%M %p")
self._printer.text(f'FECHA / HORA: {print_date}')
self.print_enter()
self.print_horinzontal_line()
self.print_enter()
self.print_col('Moneda', self.taxes_col_width1)
self.print_col('Cant.', self.taxes_col_width2)
self.print_col('Subtotal', self.taxes_col_width3)
self.print_enter()
for line in data['lines']:
self.print_col(str(line[0]), self.taxes_col_width1)
self.print_col(str(line[1]), self.taxes_col_width2)
self.print_col(str(line[2]), self.taxes_col_width3)
self.print_enter()
self.print_enter()
self._printer.set(custom_size=True, width=2, height=2, align='center')
_total = data['total']
self._printer.text(f'TOTAL: {_total}')
self.print_enter()
self._printer.cut()
self._printer.ln(2)
self._printer.close()
def print_header_sale_verification(self, sale):
title = 'VERIFICACION DE CUENTA'
msg = """ESTIMADO CLIENTE UNA VEZ REALICE EL \n PAGO DE LA CUENTA POR \n FAVOR EXIJA SU RESPECTIVA FACTURA \n PROPINA VOLUNTARIA"""
self._printer.ln(2)
self._printer.set(custom_size=True, width=2, height=2, align='center')
self._printer.text(title)
self.print_enter()
self.print_horinzontal_line('big')
self._printer.ln(2)
self._printer.set(align='center')
self._printer.text(msg)
self.print_enter()
self._printer.set(align='left')
self._printer.ln(2)
create_date = sale.get('create_date')
if create_date:
self._printer.text(f'FECHA: {create_date}')
self.print_enter()
salesman = sale.get('salesman')
if salesman:
self._printer.text(f'VENDEDOR: {salesman}')
self.print_enter()
comment = sale.get('comment')
if comment:
self._printer.text(f'NOTAS: {comment}')
self.print_enter()
table_assigned = sale.get('table_assigned')
if table_assigned:
self._printer.text(f'MESA: {table_assigned}')
self.print_enter()
position = sale.get('position')
if position:
self._printer.text(f'POSICION: {position}')
self.print_enter()
self.print_enter()
def print_logo(self):
try:
self._printer.set(align='center')
self._printer.image(self._img_logo, center=True)
self.print_enter()
except Exception:
pass
def print_qrcode(self, qrcode):
self._printer.qr(qrcode, center=True, size=5)
self.print_enter()
def print_tasks(self, data):
tasks_printed = []
for value in data:
try:
self._printer = None
self.config_printer(value['printer'])
self.set_printer()
if not self._printer:
logging.error('impresora no disponible error impresion tarea %s', str(value['printer']))
continue
title = value['sale'] + ' - ' + value['work_station']
self._printer.set(custom_size=True, width=2,
height=2, align='center')
self._printer.textln(title)
self._printer.set(bold=False, custom_size=True, width=1,
height=2, align='left')
self._printer.ln(2)
for ln in value['lines']:
line_ = str(int(ln['quantity'])) + ' ' + ln['name']
self._printer.textln(line_)
if ln.get('note'):
self._printer.textln('NOTA:' + ln.get('note'))
self._printer.ln(2)
tasks_printed.append(ln['task'])
self._printer.cut()
self._printer.close()
except Exception:
logging.exception('error tarea')
time.sleep(1)
return tasks_printed
def print_header(self, short=False):
if not short:
if self._img_logo:
self.print_logo()
self._printer.set(align='center')
if self._header != '' and self._header is not None:
self._printer.textln(self._header)
self._printer.textln(self._company)
self._printer.textln(self._shop)
if self._id_number:
self._printer.text('NIT:' + self._id_number)
if self._regime_tax:
self._printer.text(' ' + self._regime_tax)
self.print_enter()
if self._street:
self._printer.textln(self._street)
if not short:
if self._city:
self._printer.text(self._city)
if self._phone:
if self._city:
self._printer.text(' ')
self._printer.text('Telefono:' + self._phone)
if self._city or self._phone:
self.print_enter()
self._printer.ln(2)
def print_horinzontal_line(self, size=None):
if size == 'big':
row_characters = '-' * int(self._row_characters / 2)
else:
row_characters = '-' * self._row_characters
self._printer.textln(row_characters)
def print_horinzontal_double_line(self):
self._printer.text('=' * self._row_characters)
def print_enter(self):
self._printer.text('\n')
def print_split(self, left, right):
len_left = self._row_characters - len(right) - 1
left = left[:len_left]
if isinstance(left, bytes):
left = left.decode("utf-8")
if isinstance(right, bytes):
right = right.decode("utf-8")
left += (len_left - len(left) + 1) * ' '
self._printer.text(left)
self._printer.text(right)
self.print_enter()
def print_sale_lines(self, sale):
self.print_enter()
self.print_horinzontal_line()
self.print_split(' Articulo ', 'Subtotal ')
self.print_horinzontal_line()
len_row = self._row_characters - \
(_DIGITS_CODE_RECEIPT + 1) - (_DIGITS + 1)
for line in sale['lines']:
if line['taxes'] and _PRINT_TAX_ID:
tax_id = ' ' + str(line['taxes'][0].id)
else:
tax_id = ''
line_total = money(line['amount_w_tax']) + tax_id
discount = line.get('discount')
if self._show_discount and discount and Decimal(discount) > 0:
amount_w_tax = Decimal(line['amount_w_tax'])
discount = Decimal(discount)
initial = 'DCTO - ' + str(round(discount * 100, 0)) + '%'
if discount == 1:
line_total = 0
else:
line_total = amount_w_tax / (1 - discount)
discount = '-' + money(line_total - amount_w_tax)
line_total = money(line_total)
code = line['code'] or ' '
if line['quantity'] != 1:
length_name = self._row_characters - 11
first_line = code + ' ' + line['name'][:length_name]
if isinstance(first_line, bytes):
first_line = first_line.decode('utf-8')
self._printer.text(first_line + '\n')
unit_price_w_tax = str(round(line['unit_price_w_tax'], 2))
second_line = ' %s x %s' % (
line['quantity'], unit_price_w_tax)
second_line = second_line.encode('utf-8')
self.print_split(second_line, line_total)
if self._show_discount and discount:
self.print_split(initial, str(discount))
else:
if self._environment == 'retail':
line_pt = code + ' ' + line['name'][:len_row]
else:
line_pt = line['name'][:len_row]
self.print_split(line_pt, line_total)
if line['discount'] and Decimal(line['discount']) and self._show_discount:
self.print_split(initial, discount)
if line.get('reference'):
self._printer.textln('REF: ' + line['reference'])
def print_totals(self, sale, short=None, doc=None):
untaxed_amount = sale['untaxed_amount']
total_amount = sale['total_amount']
self.print_split('', '----------------')
self.print_split('Subtotal Base:', money(untaxed_amount))
self.print_split('Impuesto:', money(sale['tax_amount']))
self.print_split('', '----------------')
delivery_amount = sale.get('delivery_amount', 0)
tip_amount = sale.get('tip_amount', 0)
if not tip_amount and not delivery_amount:
self._printer.set(custom_size=True, height=2, bold=True)
self.print_split('Total:', money(total_amount))
self._printer.set(bold=False, height=1)
net_amount = sale['total_amount']
if not short:
self.print_enter()
if delivery_amount and delivery_amount > 0:
net_amount = net_amount + delivery_amount
if tip_amount and tip_amount > 0:
net_amount = net_amount + tip_amount
if tip_amount:
self.print_split('Propina:', money(tip_amount))
if delivery_amount:
self.print_split('Domicilio:', money(delivery_amount))
if tip_amount or delivery_amount:
self.print_horinzontal_line()
self._printer.set(custom_size=True, height=2, bold=True)
self.print_split('Valor Neto:', money(net_amount))
self._printer.set(bold=False, height=1)
self.print_enter()
if sale['cash_received']:
self.print_split('Recibido:', money(sale['cash_received']))
else:
pass
change = sale['change']
if sale['cash_received'] < net_amount:
# pending to remove
msg_residual = 'Pendiente:'
change = sale.get('residual_amount', 0)
else:
msg_residual = 'Cambio:'
if doc != 'sale_verification' and msg_residual == 'Cambio:':
self.print_split(msg_residual, money(change))
self.print_enter()
if not short:
order = sale.get('order')
if order:
self._printer.textln(f'CODIGO: {order}')
def _print_info_consumer(self, sale):
consumer = sale.get('consumer', None)
if consumer:
payment_method = sale.get('payment_method', None)
if consumer.get('name') or consumer.get('phone'):
consumer_name = consumer.get('name', None)
consumer_address = consumer.get('address', '')
consumer_phone = consumer.get('phone', '')
else:
# for remove this option
consumer_name = consumer.get('consumer_name', None)
consumer_address = consumer.get('consumer_address', '')
consumer_phone = consumer.get('consumer_phone', '')
self.print_horinzontal_line()
self.print_enter()
self._printer.set(align='center')
self._printer.textln('========== INFO CONSUMIDOR ==========')
self.print_enter()
self._printer.set(align='left')
self._printer.textln('NOMBRE: %s' % consumer_name)
self._printer.textln('DIRECCION: %s' % consumer_address)
self._printer.textln('TELEFONO: %s' % consumer_phone)
if payment_method and payment_method == 'terminal':
payment_method = '- PAGA CON DATAFONO'
elif payment_method and payment_method == 'all_paid':
payment_method = '- TODO PAGO'
elif payment_method and payment_method == 'partial_paid':
payment_method = '- PAGO PARCIAL'
else:
payment_method = '- PAGA EN EFECTIVO'
self._printer.text(f'MEDIO DE PAGO: {payment_method}')
self._printer.ln(2)
delivery_amount = money(sale.get('delivery_amount', 0))
self._printer.text(f'Domicilio: {delivery_amount}')
self._printer.ln(2)
def print_body(self, sale, type_doc='invoice', short=False):
self._printer.set(font=_FONT_B)
self._printer.set(align='left')
if type_doc == 'invoice':
if sale['number']:
if sale['total_amount'] >= 0:
self._printer.text(
'FACTURA DE VENTA No. ' + sale['number'])
else:
self._printer.text('NOTA CREDITO No. ' + sale['number'])
elif type_doc in ['order', 'delivery']:
self._printer.text('PEDIDO: ' + sale['order'])
self.print_enter()
self._printer.text('Fecha:%s' % sale['date'])
if sale.get('invoice_time'):
self._printer.text(' Hora:%s' % sale['invoice_time'])
self.print_enter()
if not short:
if sale.get('turn') and sale['turn'] != 0:
self._printer.text('Turno: %s - ' % str(sale['turn']))
self.print_enter()
self.print_horinzontal_line()
party_name = 'Cliente: %s ' % sale['party']
party_id_number = 'Id: %s' % sale.get('party_id_number', '')
if len(party_name + party_id_number) > self._row_characters:
self._printer.text(party_name)
self.print_enter()
self._printer.text(party_id_number)
else:
self._printer.text(party_name + party_id_number)
if not short:
if sale.get('party_address'):
self.print_enter()
self._printer.text('Direccion: %s' % sale['party_address'])
if sale.get('party_phone'):
self.print_enter()
self._printer.text('Telefono: %s' % sale['party_phone'])
if sale.get('payment_term'):
self.print_enter()
self._printer.text('Forma de Pago: %s' % sale['payment_term'])
self.print_enter()
self._print_info_consumer(sale)
self.print_sale_lines(sale)
self.print_totals(sale, short)
if not short:
self.print_horinzontal_line()
self.print_enter()
self._printer.set(align='left')
self._printer.text('DETALLE DE IMPUESTOS')
self.print_enter()
if self._printing_taxes:
self.print_col('Tipo', self.taxes_col_width1)
self.print_col('Base', self.taxes_col_width2)
self.print_col('Imp.', self.taxes_col_width3)
self.print_enter()
taxes = sale['taxes']
for tax in taxes:
self.print_col(str(taxes[tax]['name'])
+ ' ', self.taxes_col_width1)
self.print_col(
str(int(taxes[tax]['base'])), self.taxes_col_width2)
self.print_col(
str(int(taxes[tax]['tax'])), self.taxes_col_width3)
self.print_enter()
if not short:
self.print_enter()
self.print_horinzontal_line()
if sale.get('payments'):
self.print_enter()
self.print_col('MEDIO PAGO', self.payments_col_width1)
self.print_col('# APROB', self.payments_col_width2)
self.print_col('VALOR', self.payments_col_width3)
self.print_enter()
payments = sale['payments']
for p in payments:
self.print_col(str(p['name']) + ' ', self.payments_col_width1)
self.print_col(str(p['voucher']) + ' ',
self.payments_col_width2)
self.print_col(str(int(p['amount'])), self.payments_col_width3)
self.print_enter()
self.print_horinzontal_line()
no_products = 'No ITEMS: %s' % str(sale['num_products'])
self._printer.text(no_products)
self.print_enter()
comment = sale.get('comment')
if comment:
self.print_horinzontal_line()
self.print_enter()
self._printer.text(f'NOTAS: {comment}')
self.print_enter()
self.print_horinzontal_line()
register = 'CAJA No. %s' % self._sale_device
self._printer.text(register)
self.print_enter()
self._printer.text('CAJERO: %s' % self._user)
self.print_enter()
if sale.get('salesman'):
self._printer.text('VENDEDOR: %s' % sale['salesman'])
self.print_enter()
if not short:
if sale.get('channel'):
self._printer.text('CANAL DE VENTA: %s' % sale['channel'])
self.print_enter()
if sale.get('delivery_party'):
self._printer.text('DOMICILIARIO: %s' % sale['delivery_party'])
self.print_enter()
if self._show_position:
self._printer.text('POSICION: %s' % str(sale['position']))
self.print_enter()
if sale.get('table_assigned'):
self._printer.text('MESA: %s' % str(sale['table_assigned']))
self.print_enter()
self.print_horinzontal_line()
auth_kind = sale.get('auth_kind', None)
if auth_kind and sale['state'] not in ['draft']:
auth_data = self._authorizations[auth_kind]
self._printer.text(self.get_authorization(auth_data))
if not short:
self.print_enter()
if not short:
self._printer.text('Fecha de creacion: %s' % sale["create_date"])
self._printer.ln(2)
def print_extra_info(self, sale):
if sale.get('pos_notes'):
self.print_enter()
self.print_header()
self.print_horinzontal_line()
self.print_enter()
party_name = 'Cliente: %s ' % sale['party']
self._printer.text(party_name)
self.print_enter()
if self._show_position:
self._printer.text('Posicion: %s' % str(sale['position']))
self.print_enter()
if sale['state'] in ['draft']:
self._printer.text('Cotizacion: ', sale['order'])
else:
self._printer.text('Factura No. ' + sale['number'])
self.print_enter()
self._printer.text(str(sale.get('pos_notes')))
self.print_enter()
self.print_horinzontal_line()
self.print_enter()
self._printer.cut()
def print_col(self, x, l):
self._printer.text(x[:l] + (l - len(x)) * ' ')
def print_footer(self, open_box=False, type_doc=None, invoice_type=None):
if self._footer:
self._printer.text(self._footer)
self._printer.ln(2)
if type_doc == 'invoice':
if invoice_type == '1':
self._printer.textln('FACTURACION COMO SOFTWARE PROPIO')
elif invoice_type == 'P':
self._printer.textln('SISTEMA POS')
self._printer.textln('PROVEEDOR DE SOFTWARE PRESIK SAS')
self._printer.textln('NIT: 900803782-2')
self._printer.textln('www.presik.com')
self.print_enter()
self._printer.cut()
if open_box:
self._printer.cashdraw(2)
self.print_enter()
def print_orders(self, orders, reversion=None):
res = []
kind = self.order_kind
for order in orders:
try:
self._printer = None
if dev_printers.get(order['host']) and kind != 'command':
host = dev_printers[order['host']]
else:
host = order['host']
if order['interface'] == 'usb':
if OS_NAME == 'posix':
self._printer = printer.File(host)
self._printer.close()
self._printer.open()
elif OS_NAME == 'nt':
self._printer = printer.Win32Raw(host)
self._printer.open()
elif order['interface'] == 'network':
try:
host, port = host.split(":")
except Exception:
host, port = host, None
if port:
self._printer = printer.Network(host, port=int(port), timeout=15)
else:
self._printer = printer.Network(host, timeout=15)
elif order['interface'] == 'ssh':
self._printer = FileSSH(*host.split('@'))
if self._printer:
self._printer.open()
elif order['interface'] == 'cups':
pass
if not hasattr(self, '_printer') or not self._printer and self._environment != 'restaurant':
self.set_printer()
if not self._printer:
logging.info(
"Warning: Interface not found for printer!")
# res.append(None)
return False
logging.info("Info: Printer is OK!")
try:
result = self._print_order(order, reversion)
# if True:
if result:
res.extend(result)
elif order.get('lines_ids') and True:
res.extend(order['lines_ids'])
except Exception:
logging.exception('error de impresora')
self._printer.close()
time.sleep(1)
except Exception:
logging.exception('Can not found Printer!')
return res
def _print_order(self, order, reversion):
lines_printed = []
for copie in range(self.order_copies):
lines_printed = self.print_body_order(order, reversion)
self._print_info_consumer(order)
self._printer.cut()
return lines_printed
def print_body_order(self, order, reversion):
# Exists 2 types of order:
# command => For restaurants kitchens
# dispatch => For external dispatch
lines_printed = []
self._printer.set(font=_FONT_B)
self._printer.set(align='center')
turn = order.get('turn')
if turn:
self._printer.text('TURNO: %s' % str(turn))
self._printer.ln(2)
kind = order.get('kind', None)
_kind = ''
if self._environment != 'retail' and kind:
if kind == 'take_away':
_kind = 'PARA LLEVAR'
elif kind == 'to_table':
_kind = 'PARA MESA'
elif kind == 'delivery':
_kind = 'DOMICILIO'
self._printer.set(custom_size=True, width=2, height=2, align='center')
title = f'+ + + {_kind} + + +'
self._printer.text(title)
self.print_enter()
self._printer.set(custom_size=True, width=2, height=2, align='center')
self.print_enter()
self._printer.text(order['sale_number'])
self.print_enter()
self._printer.set(custom_size=False)
self._printer.set(align='left')
self.print_enter()
date_ = datetime.now().strftime("%Y-%m-%d %H:%M %p")
self._printer.text('FECHA: ' + date_)
self.print_enter()
table_assigned = order.get('table_assigned', None)
if table_assigned:
self.print_enter()
self._printer.set(custom_size=True, width=2,
height=2, align='center')
self._printer.text('MESA: %s' % table_assigned)
self.print_enter()
self._printer.set(align='left')
delivery_charge = order.get('delivery_charge', None)
if self.order_kind == 'dispatch' and delivery_charge:
self._printer.text('FACTURA: ' + order['number'])
self.print_enter()
_charge_to = 'Cliente'
if delivery_charge == 'company':
_charge_to = 'Empresa'
self._printer.text('CARGO DEL DOMICILIO: ' + _charge_to)
self.print_enter()
if self.order_kind == 'dispatch':
self._printer.text('FORMA DE PAGO: ' + order.get('payment_term', ''))
self.print_enter()
position = order.get('position')
if position:
self._printer.text('POSICION: %s' % str(position))
self.print_enter()
self._printer.text('VENDEDOR: %s' % order['salesman'])
self.print_enter()
self._printer.text('SUCURSAL: %s' % order['shop'])
self.print_enter()
self._printer.text('CLIENTE: %s' % order['party'])
self.print_enter()
if self.order_kind == 'dispatch':
self._printer.set(bold=True, height=2)
self._printer.text('VALOR: ' + str(order['total_amount']))
self._printer.set(bold=False, height=1)
self.print_enter()
if order.get('pos_notes'):
self._printer.text(order['pos_notes'])
self.print_enter()
self._printer.text('CAJA No: %s' % self._sale_device or '')
self.print_enter()
self.print_enter()
self._printer.set(align='center')
if self.order_kind == 'command':
self._printer.set(custom_size=True, width=2,
height=2, align='center')
if reversion:
self._printer.text('>> R E V E R S I O N <<')
self.print_enter()
col_width_name = self.order_col_2 + self.order_col_3
self._printer.set(align='left')
self._printer.set(custom_size=True, width=1, height=2)
if not self._print_lines_product:
self.print_horinzontal_double_line()
self.print_enter()
def print_lines_order(lines, group=False):
for line in lines:
try:
if self.order_kind == 'command':
self._printer.set(custom_size=True, width=1, height=2)
qty = ' ' + str(int(Decimal(line['quantity'])))
name = line['name']
if group:
name = ' ' + name
self.print_col(qty, self.order_col_1)
self.print_col(name, col_width_name)
if line['note']:
self.print_enter()
for msg_note in line['note'].split('\n'):
self._printer.text(f' NOTA -> {msg_note}')
self.print_enter()
if line.get('id'):
lines_printed.append(line['id'])
except Exception:
logging.exception(f'Error impresion linea de orden {str(line)}')
self.print_enter()
self.print_enter()
if isinstance(order['lines'], list):
print_lines_order(order['lines'])
else:
for cat in order['lines'].values():
self._printer.set(align='center', custom_size=True, width=1, height=2)
self._printer.text(cat['name'])
self._printer.ln()
print_lines_order(cat['lines'], group=True)
self._printer.ln()
self.print_enter()
self.print_horinzontal_double_line()
self.print_enter()
self._printer.set(custom_size=True, width=2, height=2, align='left')
self._printer.text('NOTA:')
self.print_enter()
if order['comment']:
self._printer.text(str(order['comment']))
self.print_enter()
self._printer.ln(2)
return lines_printed
# if self._environment != 'retail':
# self._printer.set(custom_size=True, width=2, height=2, align='center')
# title = f'+ + + {_kind} + + +'
# self._printer.text(title)
# self.print_enter()
# self.print_enter()
@classmethod
def get_authorization(cls, auth):
res = ''
kind = auth['kind']
start_date_auth = auth['start_date_auth']
from_auth = auth['from_auth']
to_auth = auth['to_auth']
number = auth['number']
if auth:
res = f"Autorizacion de facturacion {kind} No {number} del {start_date_auth}, habilita desde {from_auth} a {to_auth}"
return res
class CupsPrinter(object):
"Cups Printer"
__name__ = 'sale_pos_frontend.cups_printer'
def __init__(self, _file, row_characters):
self._file = _file
self.align = 'left'
self._row_characters = row_characters
def text(self, text):
self._text(text)
def set(self, align='left', font=_FONT_A):
if align:
self.align = align
if font:
self.font = font
def cut(self):
pass
def cashdraw(number):
pass
def _text(self, text):
start_spaces = ''
if self.align == 'center':
start_spaces = int((self._row_characters - len(text)) / 2) * ' '
elif self.align == 'right':
start_spaces = int(self._row_characters - len(text)) * ' '
else:
pass
text = start_spaces + text
self._file.write(text)
if __name__ == '__main__':
# Test for Escpos interface printer Linux
# Network example
# device = 'network', '192.168.0.33'
# Unix-like Usb example
device = ('usb', ' /dev/usb/lp1')
# Windows Usb example for printer name SATPOS
# device = 'usb', 'SATPOS'
# SSH example
# device = 'ssh', 'psk@123@192.168.20.25@22@/dev/usb/lp1'
example_dev = {
'interface': device[0],
'device': device[1],
'profile': 'TM-P80',
}
ctx_printing = {}
ctx_printing['company'] = 'OSCORP INC'
ctx_printing['sale_device'] = 'CAJA-10'
ctx_printing['shop'] = 'Shop Wall Boulevard'
ctx_printing['street'] = 'Cll 21 # 172-81. Central Park'
ctx_printing['user'] = 'Charles Chapplin'
ctx_printing['city'] = 'Dallas'
ctx_printing['zip'] = '0876'
ctx_printing['phone'] = '591 5513 455'
ctx_printing['id_number'] = '123456789-0'
ctx_printing['tax_regime'] = 'none'
receipt = Receipt(ctx_printing)
receipt.config_printer(example_dev)
receipt.test_printer()