forked from elmau/empresa-libre
Imprimir ticket
This commit is contained in:
parent
3e323678d7
commit
fad45cb502
|
@ -1,6 +1,6 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
#~ import falcon
|
import os
|
||||||
import re
|
import re
|
||||||
import smtplib
|
import smtplib
|
||||||
import ssl
|
import ssl
|
||||||
|
@ -13,8 +13,8 @@ from email.mime.text import MIMEText
|
||||||
from email import encoders
|
from email import encoders
|
||||||
from email.utils import formatdate
|
from email.utils import formatdate
|
||||||
|
|
||||||
import os
|
|
||||||
import requests
|
import requests
|
||||||
|
from escpos import printer
|
||||||
|
|
||||||
from reportlab.platypus import BaseDocTemplate, Frame, PageTemplate, Image
|
from reportlab.platypus import BaseDocTemplate, Frame, PageTemplate, Image
|
||||||
from reportlab.lib import colors
|
from reportlab.lib import colors
|
||||||
|
@ -949,3 +949,92 @@ class SeaFileAPI(object):
|
||||||
resp = requests.get(url, headers=self._headers)
|
resp = requests.get(url, headers=self._headers)
|
||||||
return resp.json()
|
return resp.json()
|
||||||
|
|
||||||
|
|
||||||
|
class PrintTicket(object):
|
||||||
|
LINE = '------------------------------------------------\n'
|
||||||
|
TITLES = 'CANT. U ARTICULO P.U. TOTAL\n'
|
||||||
|
LEYENDA = 'GRACIAS POR SU COMPRA\n\nGuarde este ticket para cualquier ' \
|
||||||
|
'aclaración.\nComprobante simplificado de operación con\npúblico en ' \
|
||||||
|
'general de acuerdo al Art. 37\nFracc II inc. v del Reglamento del\n' \
|
||||||
|
'Código Fiscal de la Federación.\n\n'
|
||||||
|
|
||||||
|
def __init__(self, info):
|
||||||
|
self.p = self._init_printer(info)
|
||||||
|
|
||||||
|
def _init_printer(self, info):
|
||||||
|
try:
|
||||||
|
if info['ip']:
|
||||||
|
p = printer.Network(info['ip'])
|
||||||
|
else:
|
||||||
|
p = printer.Usb(*info['usb'])
|
||||||
|
p.codepage = 'cp850'
|
||||||
|
return p
|
||||||
|
except Exception as e:
|
||||||
|
print (e)
|
||||||
|
return
|
||||||
|
|
||||||
|
def _set(self, *data):
|
||||||
|
self.p.set(*data)
|
||||||
|
return
|
||||||
|
|
||||||
|
def _t(self, text):
|
||||||
|
self.p.text(text)
|
||||||
|
return
|
||||||
|
|
||||||
|
def _l(self):
|
||||||
|
self._t(self.LINE)
|
||||||
|
return
|
||||||
|
|
||||||
|
def printer(self, data):
|
||||||
|
if self.p is None:
|
||||||
|
return False
|
||||||
|
|
||||||
|
self._emisor(data['emisor'])
|
||||||
|
self._receptor(data['receptor'])
|
||||||
|
self._ticket(data['ticket'])
|
||||||
|
self._products(data['products'])
|
||||||
|
self._footer(data['ticket'])
|
||||||
|
self.p.cut()
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _emisor(self, data):
|
||||||
|
self._set('center', 'B', 'B', 2, 2)
|
||||||
|
self._t(data['name'])
|
||||||
|
self._set('center', 'B', 'B', 2)
|
||||||
|
self._t(data['rfc'])
|
||||||
|
self._set('center', 'A')
|
||||||
|
self._t(data['address'])
|
||||||
|
return
|
||||||
|
|
||||||
|
def _receptor(self, data):
|
||||||
|
self._set('center', 'B', 'B', 2)
|
||||||
|
self._t(data['name'])
|
||||||
|
return
|
||||||
|
|
||||||
|
def _ticket(self, data):
|
||||||
|
self._set('left', 'B', 'B', 2)
|
||||||
|
self._t(data['title'])
|
||||||
|
self._set('left', 'A')
|
||||||
|
self._t(data['date'])
|
||||||
|
return
|
||||||
|
|
||||||
|
def _products(self, data):
|
||||||
|
self._l()
|
||||||
|
self._t(self.TITLES)
|
||||||
|
self._l()
|
||||||
|
for p in data:
|
||||||
|
self._t(p)
|
||||||
|
self._l()
|
||||||
|
self._t('Total artículos: {}\n'.format(len(data)))
|
||||||
|
self._l()
|
||||||
|
return
|
||||||
|
|
||||||
|
def _footer(self, data):
|
||||||
|
self._set('right', 'B', 'B', 2)
|
||||||
|
self._t(data['total'])
|
||||||
|
self._set('center', 'A')
|
||||||
|
self._t(data['letters'])
|
||||||
|
self._t(self.LEYENDA)
|
||||||
|
self._set('center', 'A', 'B')
|
||||||
|
self._t('empresalibre.net')
|
||||||
|
return
|
|
@ -36,7 +36,7 @@ import pyqrcode
|
||||||
from dateutil import parser
|
from dateutil import parser
|
||||||
|
|
||||||
from .helper import CaseInsensitiveDict, NumLet, SendMail, TemplateInvoice, \
|
from .helper import CaseInsensitiveDict, NumLet, SendMail, TemplateInvoice, \
|
||||||
SeaFileAPI
|
SeaFileAPI, PrintTicket
|
||||||
from settings import DEBUG, MV, log, template_lookup, COMPANIES, DB_SAT, \
|
from settings import DEBUG, MV, log, template_lookup, COMPANIES, DB_SAT, \
|
||||||
PATH_XSLT, PATH_XSLTPROC, PATH_OPENSSL, PATH_TEMPLATES, PATH_MEDIA, PRE, \
|
PATH_XSLT, PATH_XSLTPROC, PATH_OPENSSL, PATH_TEMPLATES, PATH_MEDIA, PRE, \
|
||||||
PATH_XMLSEC, TEMPLATE_CANCEL, DEFAULT_SAT_PRODUCTO, DECIMALES, DIR_FACTURAS
|
PATH_XMLSEC, TEMPLATE_CANCEL, DEFAULT_SAT_PRODUCTO, DECIMALES, DIR_FACTURAS
|
||||||
|
@ -1705,12 +1705,12 @@ class ImportFacturaLibreGambas(object):
|
||||||
('cfdifacturas', 'Facturas'),
|
('cfdifacturas', 'Facturas'),
|
||||||
('categorias', 'Categorias'),
|
('categorias', 'Categorias'),
|
||||||
('productos', 'Productos'),
|
('productos', 'Productos'),
|
||||||
# ~ ('tickets', 'Tickets'),
|
('tickets', 'Tickets'),
|
||||||
)
|
)
|
||||||
for source, target in tables:
|
for source, target in tables:
|
||||||
data[target] = self._get_table(source)
|
data[target] = self._get_table(source)
|
||||||
|
|
||||||
# ~ data['Socios'] += self._clientes
|
data['Socios'] += self._clientes
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
@ -2505,3 +2505,8 @@ class ImportFacturaLibre(object):
|
||||||
|
|
||||||
data.append(new)
|
data.append(new)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
def print_ticket(data, info):
|
||||||
|
p = PrintTicket(info)
|
||||||
|
return p.printer(data)
|
||||||
|
|
|
@ -268,6 +268,8 @@ class StorageEngine(object):
|
||||||
return main.Tickets.cancel(values)
|
return main.Tickets.cancel(values)
|
||||||
if opt == 'invoice':
|
if opt == 'invoice':
|
||||||
return main.Tickets.invoice(values)
|
return main.Tickets.invoice(values)
|
||||||
|
if opt == 'print':
|
||||||
|
return main.Tickets.printer(values)
|
||||||
|
|
||||||
def get_tickets(self, values):
|
def get_tickets(self, values):
|
||||||
return main.Tickets.get_by(values)
|
return main.Tickets.get_by(values)
|
||||||
|
|
|
@ -17,7 +17,7 @@ if __name__ == '__main__':
|
||||||
from controllers import util
|
from controllers import util
|
||||||
from settings import log, VERSION, PATH_CP, COMPANIES, PRE, CURRENT_CFDI, \
|
from settings import log, VERSION, PATH_CP, COMPANIES, PRE, CURRENT_CFDI, \
|
||||||
INIT_VALUES, DEFAULT_PASSWORD, DECIMALES, IMPUESTOS, DEFAULT_SAT_PRODUCTO, \
|
INIT_VALUES, DEFAULT_PASSWORD, DECIMALES, IMPUESTOS, DEFAULT_SAT_PRODUCTO, \
|
||||||
CANCEL_SIGNATURE
|
CANCEL_SIGNATURE, PUBLIC
|
||||||
|
|
||||||
|
|
||||||
FORMAT = '{0:.2f}'
|
FORMAT = '{0:.2f}'
|
||||||
|
@ -4328,6 +4328,63 @@ class Tickets(BaseModel):
|
||||||
doc = util.to_pdf(data, data['emisor']['rfc'])
|
doc = util.to_pdf(data, data['emisor']['rfc'])
|
||||||
return doc, name
|
return doc, name
|
||||||
|
|
||||||
|
def _format_ticket(self, id):
|
||||||
|
emisor = util.get_dict(Emisor.select().dicts()[0])
|
||||||
|
ticket = Tickets.select().where(Tickets.id==id).dicts()[0]
|
||||||
|
products = TicketsDetalle.get_by_print(id)
|
||||||
|
|
||||||
|
emisor['name'] = '{}\n'.format(emisor['nombre'])
|
||||||
|
emisor['rfc'] = 'RFC: {}\n'.format(emisor['rfc'])
|
||||||
|
interior = ''
|
||||||
|
if emisor['no_interior']:
|
||||||
|
interior = ', {}'.format(emisor['no_interior'])
|
||||||
|
colonia = ''
|
||||||
|
if emisor['colonia']:
|
||||||
|
colonia = ', Col. {}'.format(emisor['colonia'])
|
||||||
|
municipio = ''
|
||||||
|
if emisor['municipio']:
|
||||||
|
municipio = ', {}'.format(emisor['municipio'])
|
||||||
|
estado = ''
|
||||||
|
if emisor['estado']:
|
||||||
|
estado = ', {}'.format(emisor['estado'])
|
||||||
|
cp = ''
|
||||||
|
if emisor['codigo_postal']:
|
||||||
|
cp = ', C.P. {}'.format(emisor['codigo_postal'])
|
||||||
|
pais = ''
|
||||||
|
if emisor['pais']:
|
||||||
|
pais = ', {}'.format(emisor['pais'])
|
||||||
|
direccion = '{} {}{}{}{}{}{}{}\n\n'.format(emisor['calle'],
|
||||||
|
emisor['no_exterior'], interior, colonia, municipio, estado, cp,
|
||||||
|
pais)
|
||||||
|
emisor['address'] = direccion
|
||||||
|
|
||||||
|
ticket['title'] = 'Ticket: {}{}\n\n'.format(ticket['serie'],
|
||||||
|
ticket['folio'])
|
||||||
|
ticket['date'] = 'Fecha y hora: {}\n'.format(ticket['fecha'])
|
||||||
|
ticket['letters'] = '{}\n\n'.format(
|
||||||
|
util.to_letters(ticket['total'], 'peso'))
|
||||||
|
ticket['total'] = 'TOTAL: $ {:>12,.2f}\n\n'.format(ticket['total'])
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'emisor': emisor,
|
||||||
|
'receptor': {'name': '{}\n\n'.format(PUBLIC)},
|
||||||
|
'ticket': ticket,
|
||||||
|
'products': products,
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def printer(cls, values):
|
||||||
|
id = int(values['id'])
|
||||||
|
info = {'ip': '', 'usb': (int('1ba0', 16), int('2204', 16))}
|
||||||
|
data = cls._format_ticket(cls, id)
|
||||||
|
result = util.print_ticket(data, info)
|
||||||
|
msg = 'Ticket impreso correctamente'
|
||||||
|
if not result:
|
||||||
|
msg = 'Asegurate de que la impresora este conectada y funcionando.'
|
||||||
|
result = {'ok': result, 'msg': msg}
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
class TicketsDetalle(BaseModel):
|
class TicketsDetalle(BaseModel):
|
||||||
ticket = ForeignKeyField(Tickets)
|
ticket = ForeignKeyField(Tickets)
|
||||||
|
@ -4356,6 +4413,21 @@ class TicketsDetalle(BaseModel):
|
||||||
|
|
||||||
return precio_final
|
return precio_final
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_by_print(cls, id):
|
||||||
|
products = TicketsDetalle.select().where(TicketsDetalle.ticket==id)
|
||||||
|
lines = []
|
||||||
|
for p in products:
|
||||||
|
price_with_tax = cls._with_tax(cls, p)
|
||||||
|
importe = round(price_with_tax * float(p.cantidad), DECIMALES)
|
||||||
|
l = '{:>6,.2f} {:<4} {:<14} {:>9,.2f} {:>10,.2f}\n'.format(
|
||||||
|
p.cantidad, p.producto.unidad.name, p.descripcion,
|
||||||
|
price_with_tax, importe
|
||||||
|
)
|
||||||
|
lines.append(l)
|
||||||
|
|
||||||
|
return lines
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_by_ticket(cls, id):
|
def get_by_ticket(cls, id):
|
||||||
data = []
|
data = []
|
||||||
|
|
|
@ -117,4 +117,5 @@ IMPUESTOS = {
|
||||||
DEFAULT_SAT_PRODUCTO = '01010101'
|
DEFAULT_SAT_PRODUCTO = '01010101'
|
||||||
DIR_FACTURAS = 'facturas'
|
DIR_FACTURAS = 'facturas'
|
||||||
USAR_TOKEN = False
|
USAR_TOKEN = False
|
||||||
CANCEL_SIGNATURE = False
|
CANCEL_SIGNATURE = False
|
||||||
|
PUBLIC = 'Público en general'
|
|
@ -651,11 +651,38 @@ function ticket_notes_key_up(){
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function print_ticket(id){
|
||||||
|
var data = new Object()
|
||||||
|
data['opt'] = 'print'
|
||||||
|
data['id'] = id
|
||||||
|
|
||||||
|
webix.ajax().post('tickets', data, {
|
||||||
|
error:function(text, data, XmlHttpRequest){
|
||||||
|
msg = 'Ocurrio un error, consulta a soporte técnico'
|
||||||
|
msg_error(msg)
|
||||||
|
},
|
||||||
|
success:function(text, data, XmlHttpRequest){
|
||||||
|
values = data.json();
|
||||||
|
if(values.ok){
|
||||||
|
msg_ok(values.msg)
|
||||||
|
}else{
|
||||||
|
msg_error(values.msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function grid_tickets_click(id, e, node){
|
function grid_tickets_click(id, e, node){
|
||||||
//~ var row = this.getItem(id)
|
|
||||||
if(id.column == 'pdf'){
|
if(id.column == 'pdf'){
|
||||||
//~ window.open('/doc/tpdf/' + id, '_blank')
|
//~ window.open('/doc/tpdf/' + id, '_blank')
|
||||||
get_ticket_pdf(id)
|
get_ticket_pdf(id.row)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if(id.column == 'print'){
|
||||||
|
print_ticket(id.row)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -38,7 +38,7 @@ var grid_tickets_cols = [
|
||||||
{id: "cliente", header: ["Razón Social", {content: "selectFilter"}],
|
{id: "cliente", header: ["Razón Social", {content: "selectFilter"}],
|
||||||
fillspace:true, sort:"string", hidden: true},
|
fillspace:true, sort:"string", hidden: true},
|
||||||
{id: 'pdf', header: 'PDF', adjust: 'data', template: get_icon('pdf')},
|
{id: 'pdf', header: 'PDF', adjust: 'data', template: get_icon('pdf')},
|
||||||
{id: 'print', header: 'I', adjust: 'data', template: get_icon('print')},
|
{id: 'print', header: '', adjust: 'data', template: get_icon('print')},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue