# 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 '{:,.2f}'.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) consumer_name = consumer.get('name', None) consumer_address = consumer.get('address', '') consumer_phone = consumer.get('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()