Compare commits

..

1 Commits

Author SHA1 Message Date
d7e682c1ec Configuration api print Calzabana 2025-09-21 14:32:58 -05:00
9 changed files with 528 additions and 44 deletions

BIN
Api/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

View File

@ -5,8 +5,9 @@ import sys
import json import json
from pydantic import BaseModel from pydantic import BaseModel
from datetime import datetime from datetime import datetime, timedelta
import tempfile import tempfile
from PIL import Image
from .qr_generator import QRCodeGenerator from .qr_generator import QRCodeGenerator
app = FastAPI( app = FastAPI(
@ -25,11 +26,16 @@ class Info(BaseModel):
def print_bill(data, address, waiter): def print_bill(data, address, waiter):
d = data d = data
# Crea una instancia de la impresora ficticia # Crea una instancia de la impresora ficticia
# printer = Network(str(address)) printer = Network(str(address))
# Abrir el cajo solo las impreroras que tiene esa funcion tambien puede ser 1
printer.cashdraw(2)
# printer.open() # printer.open()
printer = Dummy() # Imprimer logo
# printer = Dummy()
# Imprime el encabezado # Imprime el encabezado
printer.set(align='center', bold=False, height=1, width=1) printer.set(align='center', bold=False, height=1, width=1)
printer.image("/app/assets/logo.png")
printer.ln()
printer.text(d["shop_name"]+'\n') printer.text(d["shop_name"]+'\n')
printer.text(d["shop_nit"]+'\n') printer.text(d["shop_nit"]+'\n')
printer.text(d["shop_address"]+'\n') printer.text(d["shop_address"]+'\n')
@ -37,22 +43,21 @@ def print_bill(data, address, waiter):
printer.textln('===============================================') printer.textln('===============================================')
text = d['state'] text = d['state']
printer.textln(text) printer.textln(text)
if d['invoice'] and d['invoice']['resolution']: #if d['invoice'] and d['invoice']['resolution']:
text = "Resolucion de Facturacion # " + \ # text = "Resolucion de Facturacion # " + \
str(d['invoice']['resolution']['resolution_number']) \ # str(d['invoice']['resolution']['resolution_number']) \
+ "\nValida desde " + \ # + "\nValida desde " + \
d['invoice']['resolution']['valid_date_time_from'] + \ # d['invoice']['resolution']['valid_date_time_from'] + \
" hasta "+str(d['invoice']['resolution']['valid_date_time_to']) # " hasta "+str(d['invoice']['resolution']['valid_date_time_to'])
printer.textln(text) # printer.textln(text)
printer.ln() # printer.ln()
text = "Factura #: " + d['invoice']['invoice_number'] # text = "Factura #: " + d['invoice']['invoice_number']
printer.textln(text) # printer.textln(text)
printer.text("Cliente: " + d["party"]+'\n') printer.text("Cliente: " + d["party"]+'\n')
printer.text("CC/NIT: " + d["tax_identifier_code"]+'\n') printer.text("CC/NIT: " + d["tax_identifier_code"]+'\n')
printer.text("Direccion: " + d["address"]+'\n') printer.text("Direccion: " + d["address"]+'\n')
text = 'MESA: ' + str(d['table'] + "\n")
printer.text(text) printer.text(text)
printer.textln('===============================================') printer.textln('====================================')
printer.ln() printer.ln()
for line in d["lines"]: for line in d["lines"]:
if line['type'] != 'title': if line['type'] != 'title':
@ -67,8 +72,6 @@ def print_bill(data, address, waiter):
printer.textln('================================================') printer.textln('================================================')
text = "Descuento Realizado: "+str(d["total_discount"])+"\n" text = "Descuento Realizado: "+str(d["total_discount"])+"\n"
printer.text(text) printer.text(text)
text = "Propina: "+str(d["total_tip"])+"\n"
printer.text(text)
text = "Total (sin impuestos): "+str(d["untaxed_amount"])+"\n" text = "Total (sin impuestos): "+str(d["untaxed_amount"])+"\n"
printer.text(text) printer.text(text)
text = "Impuestos (INC): "+str(d["tax_amount"])+"\n" text = "Impuestos (INC): "+str(d["tax_amount"])+"\n"
@ -85,31 +88,29 @@ def print_bill(data, address, waiter):
printer.textln(text) printer.textln(text)
printer.set(align='center', bold=False, height=1, width=1) printer.set(align='center', bold=False, height=1, width=1)
printer.textln('==============================================\n') printer.textln('==============================================\n')
if d["fe_cufe"]: #if d["fe_cufe"]:
QR = QRCodeGenerator(d["fe_cufe"]).generate_qr() # QR = QRCodeGenerator(d["fe_cufe"]).generate_qr()
with tempfile.NamedTemporaryFile( # with tempfile.NamedTemporaryFile(
delete=True, suffix='.png', dir='/tmp') as temp_file: # delete=True, suffix='.png', dir='/tmp') as temp_file:
temp_filename = temp_file.name # temp_filename = temp_file.name
QR.save(temp_filename) # QR.save(temp_filename)
printer.image(f"{temp_filename}") # printer.image(f"{temp_filename}")
printer.set(align='left', bold=False, height=1, width=1) # printer.set(align='left', bold=False, height=1, width=1)
text = str("CUFE: " + d['cufe']) # text = str("CUFE: " + d['cufe'])
printer.textln(text) # printer.textln(text)
printer.set(align='center', bold=False, height=1, width=1) printer.set(align='center', bold=False, height=1, width=1)
printer.text("Sigue nuestras redes sociales\n")
printer.text("@bicipizza\n")
printer.text("Recuerde que la propina es voluntaria.\n")
printer.text("Gracias por visitarnos, vuelva pronto.\n") printer.text("Gracias por visitarnos, vuelva pronto.\n")
printer.text("SOFTWARE POTENCIADO POR ONECLUSTER.ORG.\n") printer.text("SOFTWARE POTENCIADO POR ONECLUSTER.COM.CO\n")
format_date_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S') adjusted_time = datetime.now() - timedelta(hours=5)
format_date_time = adjusted_time.strftime('%Y-%m-%d %H:%M:%S')
printer.text(str(format_date_time)+'\n') printer.text(str(format_date_time)+'\n')
if waiter: if waiter:
printer.text("Atendido Por: \n") printer.text("Atendido Por: \n")
printer.text(str(waiter)+'\n') printer.text(str(waiter)+'\n')
# Corta el papel (solo para impresoras que soportan esta función) # Corta el papel (solo para impresoras que soportan esta función)
# printer.cut() printer.cut()
# printer.close() printer.close()
# Obtiene el contenido del ticket de prueba # Obtiene el contenido del ticket de prueba
ticket_contenido = printer.output ticket_contenido = printer.output
# Imprime el contenido en la consola # Imprime el contenido en la consola

238
Api/main2.py Normal file
View File

@ -0,0 +1,238 @@
from fastapi import FastAPI, Response
from escpos.printer import Dummy
from escpos.printer import Network
import sys
import json
from pydantic import BaseModel
from datetime import datetime, timedelta
import tempfile
from .qr_generator import QRCodeGenerator
app = FastAPI(
title="Print Server FastAPI",
description="Server that receive request for printing",
version="0.0.1"
)
class Info(BaseModel):
content: str
ip_printer: str
user_name: str
def print_bill(data, address, waiter):
d = data
# Crea una instancia de la impresora ficticia
printer = Network(str(address))
# Abrir el cajo solo las impreroras que tiene esa funcion tambien puede ser 1
printer.cashdraw(2)
# printer.open()
# printer = Dummy()
# Imprime el encabezado
printer.set(align='center', bold=False, height=1, width=1)
printer.text(d["shop_name"]+'\n')
printer.text(d["shop_nit"]+'\n')
printer.text(d["shop_address"]+'\n')
printer.set(align='left', bold=False, height=1, width=1)
printer.textln('===============================================')
text = d['state']
printer.textln(text)
#if d['invoice'] and d['invoice']['resolution']:
# text = "Resolucion de Facturacion # " + \
# str(d['invoice']['resolution']['resolution_number']) \
# + "\nValida desde " + \
# d['invoice']['resolution']['valid_date_time_from'] + \
# " hasta "+str(d['invoice']['resolution']['valid_date_time_to'])
# printer.textln(text)
# printer.ln()
# text = "Factura #: " + d['invoice']['invoice_number']
# printer.textln(text)
printer.text("Cliente: " + d["party"]+'\n')
printer.text("CC/NIT: " + d["tax_identifier_code"]+'\n')
printer.text("Direccion: " + d["address"]+'\n')
printer.text(text)
printer.textln('===============================================')
printer.ln()
for line in d["lines"]:
if line['type'] != 'title':
text = line['product']
printer.text(text)
printer.ln()
text = str(line['quantity']) + " " + " $" + \
line["unit_price"] + "\n"
printer.text(text)
printer.set(align='right', bold=False, height=1, width=1)
printer.textln('================================================')
text = "Descuento Realizado: "+str(d["total_discount"])+"\n"
printer.text(text)
text = "Total (sin impuestos): "+str(d["untaxed_amount"])+"\n"
printer.text(text)
text = "Impuestos (INC): "+str(d["tax_amount"])+"\n"
printer.text(text)
text = "Total: "+str(d["total"])+"\n"
printer.text(text)
printer.ln()
if 'payments' in d.keys():
printer.textln("Pagos: ")
printer.textln('================================================')
for payment in d['payments']:
text = str(payment["statement"])+" $"+str(payment["amount"])
printer.textln(text)
printer.set(align='center', bold=False, height=1, width=1)
printer.textln('==============================================\n')
#if d["fe_cufe"]:
# QR = QRCodeGenerator(d["fe_cufe"]).generate_qr()
# with tempfile.NamedTemporaryFile(
# delete=True, suffix='.png', dir='/tmp') as temp_file:
# temp_filename = temp_file.name
# QR.save(temp_filename)
# printer.image(f"{temp_filename}")
# printer.set(align='left', bold=False, height=1, width=1)
# text = str("CUFE: " + d['cufe'])
# printer.textln(text)
printer.set(align='center', bold=False, height=1, width=1)
printer.text("Gracias por visitarnos, vuelva pronto.\n")
printer.text("SOFTWARE POTENCIADO POR ONECLUSTER.COM.CO\n")
adjusted_time = datetime.now() - timedelta(hours=5)
format_date_time = adjusted_time.strftime('%Y-%m-%d %H:%M:%S')
printer.text(str(format_date_time)+'\n')
if waiter:
printer.text("Atendido Por: \n")
printer.text(str(waiter)+'\n')
# Corta el papel (solo para impresoras que soportan esta función)
printer.cut()
printer.close()
# Obtiene el contenido del ticket de prueba
ticket_contenido = printer.output
# Imprime el contenido en la consola
sys.stdout.write(ticket_contenido.decode('utf-8', errors='ignore'))
def print_customer_order(data, address, waiter):
d = data
# Crea una instancia de la impresora ficticia
printer = Network(str(address))
printer.open()
# printer = Dummy()
# Imprime el encabezado
printer.set(align='center', bold=False, height=1, width=1)
format_date_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
printer.text(str(format_date_time)+'\n')
if waiter:
printer.text("Pedido Por: \n")
printer.text(str(waiter)+'\n')
printer.set(
align='center', bold=False, height=2, width=2, custom_size=True
)
printer.text('========================\n')
text = 'MESA: ' + str(d['table'] + "\n")
printer.text(text)
printer.text('========================\n')
printer.set(align='left', bold=False, height=6, width=6)
combination_pizza = False
pizza = 0
for line in d["lines"]:
if line['type'] != 'title':
if combination_pizza and pizza < 2:
printer.set(
align='center',
bold=False,
height=2,
width=2,
custom_size=True)
pizza += 1
elif pizza >= 2:
combination_pizza = False
printer.set(
align='left',
bold=False,
height=2,
width=2, custom_size=True
)
else:
printer.set(
align='left',
bold=False,
height=2,
width=2,
custom_size=True)
text = line['product'] + " " + str(line['quantity']) + "\n"
printer.text(text)
if line['description']:
text = line['description'] + "\n"
printer.text(text)
if pizza == 2:
printer.ln()
pizza = 0
combination_pizza = False
else:
printer.set(
align='left', bold=True, height=2, width=2, custom_size=True
)
printer.text("\nPIZZA COMBINADA\n")
combination_pizza = True
pizza = 0
# if d["deleted_lines"]:
# for line in d["deleted_lines"]:
# text = line['product'] + " " + str(
# line['quantity']) + " " + str(
# line['unit'])
# printer.text(text)
# Corta el papel (solo para impresoras que soportan esta función)
printer.cut()
printer.close()
# Obtiene el contenido del ticket de prueba
# ticket_contenido = printer.output
# Imprime el contenido en la consola
# sys.stdout.write(ticket_contenido.decode('utf-8', errors='replace'))
@app.post("/print_bill")
def print_ticket_bill(info: Info):
info = dict(info)
data = info["content"]
address = info["ip_printer"]
waiter = info["user_name"]
data = json.loads(data.replace("'", "\""))
print_bill(data, address, waiter)
message = "!Impresion Realizada!"
return Response(content=message, status_code=200)
@app.post("/order_kitchen")
def print_ticket_file_kitchen(info: Info):
info = dict(info)
data = info["content"]
address = info["ip_printer"]
waiter = info["user_name"]
data = json.loads(data.replace("'", "\""))
print_customer_order(data, address, waiter)
message = "!Impresion Realizada!"
return Response(content=message, status_code=200)
@app.post("/order_bar")
def print_ticket_file_bar(info: Info):
info = dict(info)
data = info["content"]
address = info["ip_printer"]
waiter = info["user_name"]
data = json.loads(data.replace("'", "\""))
print_customer_order(data, address, waiter)
message = "!Impresion Realizada!"
return Response(content=message, status_code=200)

View File

@ -1,18 +1,23 @@
# Usa una imagen base de Python
FROM python:3.11-slim FROM python:3.11-slim
# Establece el directorio de trabajo
WORKDIR /app WORKDIR /app
# Copia el archivo de requerimientos y lo instala # Instala dependencias para manejo de imágenes
COPY ./requirements.txt /tmp/ RUN apt-get update && apt-get install -y \
RUN pip install --no-cache-dir -r /tmp/requirements.txt libjpeg-dev \
zlib1g-dev \
&& rm -rf /var/lib/apt/lists/*
# Copia el código fuente # Crea directorio para assets
RUN mkdir -p /app/assets
# Copia requirements e instala dependencias
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copia el resto del código
COPY . . COPY . .
# Expone el puerto que usará FastAPI
EXPOSE 8000 EXPOSE 8000
# Comando de arranque
CMD ["uvicorn", "Api.main:app", "--host", "0.0.0.0", "--port", "8000"] CMD ["uvicorn", "Api.main:app", "--host", "0.0.0.0", "--port", "8000"]

0
assets/logo.png Normal file
View File

View File

@ -1,12 +1,17 @@
version: '3.8' version: '3.8'
services: services:
# Servicio de FastAPI
escpos: escpos:
build: . build:
context: .
dockerfile: Dockerfile
container_name: escpos container_name: escpos
command: uvicorn Api.main:app --host 0.0.0.0 --port 8000 --reload command: uvicorn Api.main:app --host 0.0.0.0 --port 8000 --reload
restart: always
volumes: volumes:
- .:/app - .:/app
- ./logo.png:/app/assets/logo.png # Monta el logo específicamente
ports: ports:
- "8050:8000" - "8050:8000"
environment:
- LOGO_PATH=/app/assets/logo.png # Variable de entorno opcional

BIN
logo.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

BIN
logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

235
main.py Normal file
View File

@ -0,0 +1,235 @@
from fastapi import FastAPI, Response
from escpos.printer import Dummy
from escpos.printer import Network
import sys
import json
from pydantic import BaseModel
from datetime import datetime
import tempfile
from .qr_generator import QRCodeGenerator
app = FastAPI(
title="Print Server FastAPI",
description="Server that receive request for printing",
version="0.0.1"
)
class Info(BaseModel):
content: str
ip_printer: str
user_name: str
def print_bill(data, address, waiter):
d = data
# Crea una instancia de la impresora ficticia
printer = Network(str(address))
# printer.open()
# printer = Dummy()
# Imprime el encabezado
printer.set(align='center', bold=False, height=1, width=1)
printer.text(d["shop_name"]+'\n')
printer.text(d["shop_nit"]+'\n')
printer.text(d["shop_address"]+'\n')
printer.set(align='left', bold=False, height=1, width=1)
printer.textln('===============================================')
text = d['state']
printer.textln(text)
if d['invoice'] and d['invoice']['resolution']:
text = "Resolucion de Facturacion # " + \
str(d['invoice']['resolution']['resolution_number']) \
+ "\nValida desde " + \
d['invoice']['resolution']['valid_date_time_from'] + \
" hasta "+str(d['invoice']['resolution']['valid_date_time_to'])
printer.textln(text)
printer.ln()
text = "Factura #: " + d['invoice']['invoice_number']
printer.textln(text)
printer.text("Cliente: " + d["party"]+'\n')
printer.text("CC/NIT: " + d["tax_identifier_code"]+'\n')
printer.text("Direccion: " + d["address"]+'\n')
printer.text(text)
printer.textln('===============================================')
printer.ln()
for line in d["lines"]:
if line['type'] != 'title':
text = line['product']
printer.text(text)
printer.ln()
text = str(line['quantity']) + " " + " $" + \
line["unit_price"] + "\n"
printer.text(text)
printer.set(align='right', bold=False, height=1, width=1)
printer.textln('================================================')
text = "Descuento Realizado: "+str(d["total_discount"])+"\n"
printer.text(text)
text = "Total (sin impuestos): "+str(d["untaxed_amount"])+"\n"
printer.text(text)
text = "Impuestos (INC): "+str(d["tax_amount"])+"\n"
printer.text(text)
text = "Total: "+str(d["total"])+"\n"
printer.text(text)
printer.ln()
if 'payments' in d.keys():
printer.textln("Pagos: ")
printer.textln('================================================')
for payment in d['payments']:
text = str(payment["statement"])+" $"+str(payment["amount"])
printer.textln(text)
printer.set(align='center', bold=False, height=1, width=1)
printer.textln('==============================================\n')
#if d["fe_cufe"]:
# QR = QRCodeGenerator(d["fe_cufe"]).generate_qr()
# with tempfile.NamedTemporaryFile(
# delete=True, suffix='.png', dir='/tmp') as temp_file:
# temp_filename = temp_file.name
# QR.save(temp_filename)
# printer.image(f"{temp_filename}")
# printer.set(align='left', bold=False, height=1, width=1)
# text = str("CUFE: " + d['cufe'])
# printer.textln(text)
printer.set(align='center', bold=False, height=1, width=1)
printer.text("Gracias por visitarnos, vuelva pronto.\n")
printer.text("SOFTWARE POTENCIADO POR ONECLUSTER.ORG.\n")
format_date_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
printer.text(str(format_date_time)+'\n')
if waiter:
printer.text("Atendido Por: \n")
printer.text(str(waiter)+'\n')
# Corta el papel (solo para impresoras que soportan esta función)
printer.cut()
printer.close()
# Obtiene el contenido del ticket de prueba
ticket_contenido = printer.output
# Imprime el contenido en la consola
sys.stdout.write(ticket_contenido.decode('utf-8', errors='ignore'))
def print_customer_order(data, address, waiter):
d = data
# Crea una instancia de la impresora ficticia
printer = Network(str(address))
printer.open()
# printer = Dummy()
# Imprime el encabezado
printer.set(align='center', bold=False, height=1, width=1)
format_date_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
printer.text(str(format_date_time)+'\n')
if waiter:
printer.text("Pedido Por: \n")
printer.text(str(waiter)+'\n')
printer.set(
align='center', bold=False, height=2, width=2, custom_size=True
)
printer.text('========================\n')
text = 'MESA: ' + str(d['table'] + "\n")
printer.text(text)
printer.text('========================\n')
printer.set(align='left', bold=False, height=6, width=6)
combination_pizza = False
pizza = 0
for line in d["lines"]:
if line['type'] != 'title':
if combination_pizza and pizza < 2:
printer.set(
align='center',
bold=False,
height=2,
width=2,
custom_size=True)
pizza += 1
elif pizza >= 2:
combination_pizza = False
printer.set(
align='left',
bold=False,
height=2,
width=2, custom_size=True
)
else:
printer.set(
align='left',
bold=False,
height=2,
width=2,
custom_size=True)
text = line['product'] + " " + str(line['quantity']) + "\n"
printer.text(text)
if line['description']:
text = line['description'] + "\n"
printer.text(text)
if pizza == 2:
printer.ln()
pizza = 0
combination_pizza = False
else:
printer.set(
align='left', bold=True, height=2, width=2, custom_size=True
)
printer.text("\nPIZZA COMBINADA\n")
combination_pizza = True
pizza = 0
# if d["deleted_lines"]:
# for line in d["deleted_lines"]:
# text = line['product'] + " " + str(
# line['quantity']) + " " + str(
# line['unit'])
# printer.text(text)
# Corta el papel (solo para impresoras que soportan esta función)
printer.cut()
printer.close()
# Obtiene el contenido del ticket de prueba
# ticket_contenido = printer.output
# Imprime el contenido en la consola
# sys.stdout.write(ticket_contenido.decode('utf-8', errors='replace'))
@app.post("/print_bill")
def print_ticket_bill(info: Info):
info = dict(info)
data = info["content"]
address = info["ip_printer"]
waiter = info["user_name"]
data = json.loads(data.replace("'", "\""))
print_bill(data, address, waiter)
message = "!Impresion Realizada!"
return Response(content=message, status_code=200)
@app.post("/order_kitchen")
def print_ticket_file_kitchen(info: Info):
info = dict(info)
data = info["content"]
address = info["ip_printer"]
waiter = info["user_name"]
data = json.loads(data.replace("'", "\""))
print_customer_order(data, address, waiter)
message = "!Impresion Realizada!"
return Response(content=message, status_code=200)
@app.post("/order_bar")
def print_ticket_file_bar(info: Info):
info = dict(info)
data = info["content"]
address = info["ip_printer"]
waiter = info["user_name"]
data = json.loads(data.replace("'", "\""))
print_customer_order(data, address, waiter)
message = "!Impresion Realizada!"
return Response(content=message, status_code=200)