Spaces:
Runtime error
Runtime error
JairoDanielMT
commited on
Commit
路
cf6c24f
1
Parent(s):
f5bc31c
add column cantidad in lunas_pedido and generate boleta and prescripcion pdf
Browse files- .gitignore +4 -1
- app.py +376 -4
- font/Craftcoke.ttf +0 -0
- font/Oregon.ttf +0 -0
- font/Roboto.ttf +0 -0
- img/pdf/logo_whatsapp.jpg +0 -0
- optica_copia.db +0 -0
- pdf/boleta/boleta_20231209182421.pdf +0 -0
- pdf/prescripcion/prescripcion_1_2023-12-09.pdf +0 -0
.gitignore
CHANGED
@@ -2,4 +2,7 @@ __pycache__
|
|
2 |
.vscode
|
3 |
Optica.session.sql
|
4 |
test.py
|
5 |
-
test2.py
|
|
|
|
|
|
|
|
2 |
.vscode
|
3 |
Optica.session.sql
|
4 |
test.py
|
5 |
+
test2.py
|
6 |
+
test3.py
|
7 |
+
test4.py
|
8 |
+
test5.py
|
app.py
CHANGED
@@ -1,3 +1,4 @@
|
|
|
|
1 |
import sqlite3
|
2 |
import threading
|
3 |
from queue import Queue
|
@@ -6,7 +7,12 @@ from fastapi.middleware.cors import CORSMiddleware
|
|
6 |
from fastapi import FastAPI, HTTPException
|
7 |
from fastapi.responses import FileResponse
|
8 |
from reportlab.pdfgen import canvas
|
9 |
-
|
|
|
|
|
|
|
|
|
|
|
10 |
|
11 |
app = FastAPI()
|
12 |
|
@@ -46,7 +52,7 @@ class DatabaseConnection:
|
|
46 |
if not self._connection_pool.empty():
|
47 |
return self._connection_pool.get()
|
48 |
else:
|
49 |
-
connection = sqlite3.connect("
|
50 |
connection.row_factory = sqlite3.Row
|
51 |
return connection
|
52 |
|
@@ -65,6 +71,12 @@ class DatabaseConnection:
|
|
65 |
self._instance.conn = None # Marcar la instancia como sin conexi贸n
|
66 |
|
67 |
|
|
|
|
|
|
|
|
|
|
|
|
|
68 |
# saludo
|
69 |
@app.get("/")
|
70 |
def read_root():
|
@@ -700,6 +712,7 @@ CREATE TABLE Prescripcion (
|
|
700 |
id_medidas INTEGER REFERENCES Medidas(id_medidas),
|
701 |
detalle_lunas VARCHAR,
|
702 |
fecha VARCHAR
|
|
|
703 |
)
|
704 |
"""
|
705 |
|
@@ -932,7 +945,7 @@ class DatosPrescripcion:
|
|
932 |
|
933 |
def generar_pdf(self, filename):
|
934 |
pdf = canvas.Canvas(filename)
|
935 |
-
pdf.setFont("
|
936 |
ubicacion_inicio = 780 # Posici贸n inicial en y
|
937 |
pdf.drawCentredString(
|
938 |
300, ubicacion_inicio, "OPTICA ARTE VISUAL - PRESCRIPCI脫N"
|
@@ -1053,6 +1066,35 @@ def obtener_datos_prescripcion_api(id_prescripcion: int):
|
|
1053 |
raise HTTPException(status_code=404, detail="Prescripci贸n no encontrada")
|
1054 |
|
1055 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1056 |
# crear endpoint retornando la url del PDF con los datos de la prescripci贸n
|
1057 |
@app.get("/prescripcion/pdf/{id_prescripcion}")
|
1058 |
def obtener_pdf_prescripcion(id_prescripcion: int):
|
@@ -1060,13 +1102,17 @@ def obtener_pdf_prescripcion(id_prescripcion: int):
|
|
1060 |
if datos_prescripcion:
|
1061 |
# Crear un objeto de la clase DatosPrescripcion
|
1062 |
obj_datos_prescripcion = DatosPrescripcion(*datos_prescripcion)
|
|
|
|
|
1063 |
# importar libreria de fecha de hoy
|
1064 |
from datetime import date
|
1065 |
|
1066 |
# obtener la fecha de hoy
|
1067 |
fecha_hoy = date.today()
|
1068 |
# generar el nombre del archivo
|
1069 |
-
nombre_archivo =
|
|
|
|
|
1070 |
|
1071 |
obj_datos_prescripcion.generar_pdf(f"{nombre_archivo}")
|
1072 |
return FileResponse(f"{nombre_archivo}")
|
@@ -1074,6 +1120,117 @@ def obtener_pdf_prescripcion(id_prescripcion: int):
|
|
1074 |
raise HTTPException(status_code=404, detail="Prescripci贸n no encontrada")
|
1075 |
|
1076 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1077 |
"""
|
1078 |
CREATE TABLE Montura (
|
1079 |
id_montura INTEGER PRIMARY KEY AUTOINCREMENT,
|
@@ -1491,6 +1648,221 @@ def delete_boleta(boleta: BoletaDelete):
|
|
1491 |
return []
|
1492 |
|
1493 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1494 |
"""
|
1495 |
CREATE TABLE montura_pedido (
|
1496 |
id_montura_pedido INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
|
1 |
+
# uvicorn app:app --host localhost --port 7860 --reload
|
2 |
import sqlite3
|
3 |
import threading
|
4 |
from queue import Queue
|
|
|
7 |
from fastapi import FastAPI, HTTPException
|
8 |
from fastapi.responses import FileResponse
|
9 |
from reportlab.pdfgen import canvas
|
10 |
+
from reportlab.lib.pagesizes import letter
|
11 |
+
from reportlab.pdfbase import pdfmetrics
|
12 |
+
from reportlab.pdfbase.ttfonts import TTFont
|
13 |
+
from reportlab.platypus import Table, TableStyle
|
14 |
+
from datetime import datetime
|
15 |
+
import os
|
16 |
|
17 |
app = FastAPI()
|
18 |
|
|
|
52 |
if not self._connection_pool.empty():
|
53 |
return self._connection_pool.get()
|
54 |
else:
|
55 |
+
connection = sqlite3.connect("optica_copia.db")
|
56 |
connection.row_factory = sqlite3.Row
|
57 |
return connection
|
58 |
|
|
|
71 |
self._instance.conn = None # Marcar la instancia como sin conexi贸n
|
72 |
|
73 |
|
74 |
+
# Cargar varias tipograf铆as
|
75 |
+
pdfmetrics.registerFont(TTFont("Craftcoke", "./font/Craftcoke.ttf"))
|
76 |
+
pdfmetrics.registerFont(TTFont("Oregon", "./font/Oregon.ttf"))
|
77 |
+
pdfmetrics.registerFont(TTFont("Roboto", "./font/Roboto.ttf"))
|
78 |
+
|
79 |
+
|
80 |
# saludo
|
81 |
@app.get("/")
|
82 |
def read_root():
|
|
|
712 |
id_medidas INTEGER REFERENCES Medidas(id_medidas),
|
713 |
detalle_lunas VARCHAR,
|
714 |
fecha VARCHAR
|
715 |
+
|
716 |
)
|
717 |
"""
|
718 |
|
|
|
945 |
|
946 |
def generar_pdf(self, filename):
|
947 |
pdf = canvas.Canvas(filename)
|
948 |
+
pdf.setFont("Oregon", 12)
|
949 |
ubicacion_inicio = 780 # Posici贸n inicial en y
|
950 |
pdf.drawCentredString(
|
951 |
300, ubicacion_inicio, "OPTICA ARTE VISUAL - PRESCRIPCI脫N"
|
|
|
1066 |
raise HTTPException(status_code=404, detail="Prescripci贸n no encontrada")
|
1067 |
|
1068 |
|
1069 |
+
# endpoint descargar prescripcion pdf con clase
|
1070 |
+
class PrescripcionPDF(BaseModel):
|
1071 |
+
id_prescripcion: int
|
1072 |
+
|
1073 |
+
|
1074 |
+
@app.post("/prescripcion/pdf")
|
1075 |
+
def obtener_pdf_prescripcion_api(prescripcion: PrescripcionPDF):
|
1076 |
+
datos_prescripcion = obtener_datos_prescripcion(prescripcion.id_prescripcion)
|
1077 |
+
if datos_prescripcion:
|
1078 |
+
# Crear un objeto de la clase DatosPrescripcion
|
1079 |
+
obj_datos_prescripcion = DatosPrescripcion(*datos_prescripcion)
|
1080 |
+
directorio_pdf = "pdf/prescripcion/"
|
1081 |
+
os.makedirs(directorio_pdf, exist_ok=True)
|
1082 |
+
# importar libreria de fecha de hoy
|
1083 |
+
from datetime import date
|
1084 |
+
|
1085 |
+
# obtener la fecha de hoy
|
1086 |
+
fecha_hoy = date.today()
|
1087 |
+
# generar el nombre del archivo
|
1088 |
+
nombre_archivo = f"{directorio_pdf}prescripcion_{prescripcion.id_prescripcion}_{fecha_hoy}.pdf"
|
1089 |
+
|
1090 |
+
obj_datos_prescripcion.generar_pdf(f"{nombre_archivo}")
|
1091 |
+
return FileResponse(
|
1092 |
+
nombre_archivo, media_type="application/pdf", filename=nombre_archivo
|
1093 |
+
)
|
1094 |
+
else:
|
1095 |
+
raise HTTPException(status_code=404, detail="Prescripci贸n no encontrada")
|
1096 |
+
|
1097 |
+
|
1098 |
# crear endpoint retornando la url del PDF con los datos de la prescripci贸n
|
1099 |
@app.get("/prescripcion/pdf/{id_prescripcion}")
|
1100 |
def obtener_pdf_prescripcion(id_prescripcion: int):
|
|
|
1102 |
if datos_prescripcion:
|
1103 |
# Crear un objeto de la clase DatosPrescripcion
|
1104 |
obj_datos_prescripcion = DatosPrescripcion(*datos_prescripcion)
|
1105 |
+
directorio_pdf = "pdf/prescripcion/"
|
1106 |
+
os.makedirs(directorio_pdf, exist_ok=True)
|
1107 |
# importar libreria de fecha de hoy
|
1108 |
from datetime import date
|
1109 |
|
1110 |
# obtener la fecha de hoy
|
1111 |
fecha_hoy = date.today()
|
1112 |
# generar el nombre del archivo
|
1113 |
+
nombre_archivo = (
|
1114 |
+
f"{directorio_pdf}prescripcion_{id_prescripcion}_{fecha_hoy}.pdf"
|
1115 |
+
)
|
1116 |
|
1117 |
obj_datos_prescripcion.generar_pdf(f"{nombre_archivo}")
|
1118 |
return FileResponse(f"{nombre_archivo}")
|
|
|
1120 |
raise HTTPException(status_code=404, detail="Prescripci贸n no encontrada")
|
1121 |
|
1122 |
|
1123 |
+
"""
|
1124 |
+
Table lunas_pedido {
|
1125 |
+
id_lunas_pedido INTEGER [primary key, unique, increment]
|
1126 |
+
id_prescripcion INTEGER [ref: > Prescripcion.id_prescripcion]
|
1127 |
+
precio REAL
|
1128 |
+
id_boleta INTEGER [ref: > boleta.id_boleta]
|
1129 |
+
descripcion VARCHAR
|
1130 |
+
cantidad INTEGER
|
1131 |
+
}
|
1132 |
+
"""
|
1133 |
+
|
1134 |
+
|
1135 |
+
# get
|
1136 |
+
@app.get("/lunas_pedido")
|
1137 |
+
def get_lunas_pedido():
|
1138 |
+
try:
|
1139 |
+
with DatabaseConnection().get_connection() as conn:
|
1140 |
+
cursor = conn.cursor()
|
1141 |
+
cursor.execute("SELECT * FROM lunas_pedido")
|
1142 |
+
lunas_pedido = cursor.fetchall()
|
1143 |
+
return lunas_pedido
|
1144 |
+
except Exception as e:
|
1145 |
+
print(e)
|
1146 |
+
return []
|
1147 |
+
|
1148 |
+
|
1149 |
+
# post con pydantic
|
1150 |
+
class LunasPedido(BaseModel):
|
1151 |
+
id_prescripcion: int
|
1152 |
+
precio: float
|
1153 |
+
id_boleta: int
|
1154 |
+
descripcion: str
|
1155 |
+
cantidad: int
|
1156 |
+
|
1157 |
+
|
1158 |
+
@app.post("/lunas_pedido")
|
1159 |
+
def create_lunas_pedido(lunas_pedido: LunasPedido):
|
1160 |
+
try:
|
1161 |
+
with DatabaseConnection().get_connection() as conn:
|
1162 |
+
cursor = conn.cursor()
|
1163 |
+
cursor.execute(
|
1164 |
+
"INSERT INTO lunas_pedido (id_prescripcion, precio, id_boleta, descripcion, cantidad) VALUES (?, ?, ?, ?, ?)",
|
1165 |
+
(
|
1166 |
+
lunas_pedido.id_prescripcion,
|
1167 |
+
lunas_pedido.precio,
|
1168 |
+
lunas_pedido.id_boleta,
|
1169 |
+
lunas_pedido.descripcion,
|
1170 |
+
lunas_pedido.cantidad,
|
1171 |
+
),
|
1172 |
+
)
|
1173 |
+
conn.commit()
|
1174 |
+
return {"mensaje": "Lunas_pedido creada exitosamente"}
|
1175 |
+
except Exception as e:
|
1176 |
+
print(e)
|
1177 |
+
return []
|
1178 |
+
|
1179 |
+
|
1180 |
+
# put con pydantic
|
1181 |
+
class LunasPedidoUpdate(BaseModel):
|
1182 |
+
id_lunas_pedido: int
|
1183 |
+
id_prescripcion: int
|
1184 |
+
precio: float
|
1185 |
+
id_boleta: int
|
1186 |
+
descripcion: str
|
1187 |
+
cantidad: int
|
1188 |
+
|
1189 |
+
|
1190 |
+
@app.put("/lunas_pedido")
|
1191 |
+
def update_lunas_pedido(lunas_pedido: LunasPedidoUpdate):
|
1192 |
+
try:
|
1193 |
+
with DatabaseConnection().get_connection() as conn:
|
1194 |
+
cursor = conn.cursor()
|
1195 |
+
cursor.execute(
|
1196 |
+
"UPDATE lunas_pedido SET id_prescripcion = ?, precio = ?, id_boleta = ?, descripcion = ?, cantidad = ? WHERE id_lunas_pedido = ?",
|
1197 |
+
(
|
1198 |
+
lunas_pedido.id_prescripcion,
|
1199 |
+
lunas_pedido.precio,
|
1200 |
+
lunas_pedido.id_boleta,
|
1201 |
+
lunas_pedido.descripcion,
|
1202 |
+
lunas_pedido.cantidad,
|
1203 |
+
lunas_pedido.id_lunas_pedido,
|
1204 |
+
),
|
1205 |
+
)
|
1206 |
+
conn.commit()
|
1207 |
+
return {"mensaje": "Lunas_pedido actualizada exitosamente"}
|
1208 |
+
except Exception as e:
|
1209 |
+
print(e)
|
1210 |
+
return []
|
1211 |
+
|
1212 |
+
|
1213 |
+
# delete con pydantic
|
1214 |
+
class LunasPedidoDelete(BaseModel):
|
1215 |
+
id_lunas_pedido: int
|
1216 |
+
|
1217 |
+
|
1218 |
+
@app.delete("/lunas_pedido")
|
1219 |
+
def delete_lunas_pedido(lunas_pedido: LunasPedidoDelete):
|
1220 |
+
try:
|
1221 |
+
with DatabaseConnection().get_connection() as conn:
|
1222 |
+
cursor = conn.cursor()
|
1223 |
+
cursor.execute(
|
1224 |
+
"DELETE FROM lunas_pedido WHERE id_lunas_pedido = ?",
|
1225 |
+
(lunas_pedido.id_lunas_pedido,),
|
1226 |
+
)
|
1227 |
+
conn.commit()
|
1228 |
+
return {"mensaje": "Lunas_pedido eliminada exitosamente"}
|
1229 |
+
except Exception as e:
|
1230 |
+
print(e)
|
1231 |
+
return []
|
1232 |
+
|
1233 |
+
|
1234 |
"""
|
1235 |
CREATE TABLE Montura (
|
1236 |
id_montura INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
|
1648 |
return []
|
1649 |
|
1650 |
|
1651 |
+
def generar_boleta(idboleta, cliente, productos, adelanto, saldo):
|
1652 |
+
# crear directorio si no existe en pdf/boleta
|
1653 |
+
directorio_pdf = "pdf/boleta/"
|
1654 |
+
os.makedirs(directorio_pdf, exist_ok=True)
|
1655 |
+
# Crear un nombre de archivo 煤nico basado en la fecha y hora actual
|
1656 |
+
now = datetime.now()
|
1657 |
+
formatted_date_time = now.strftime("%Y%m%d%H%M%S")
|
1658 |
+
nombre_archivo = f"{directorio_pdf}boleta_{formatted_date_time}.pdf"
|
1659 |
+
|
1660 |
+
# Inicializar el lienzo del PDF
|
1661 |
+
c = canvas.Canvas(nombre_archivo, pagesize=letter)
|
1662 |
+
ubicacion_inicio = 700
|
1663 |
+
# Configurar la tipograf铆a para la secci贸n del cliente
|
1664 |
+
c.setFont("Craftcoke", 30)
|
1665 |
+
c.drawString(100, ubicacion_inicio, "Arte Visual")
|
1666 |
+
|
1667 |
+
# Configurar la tipograf铆a para la secci贸n de productos
|
1668 |
+
c.setFont("Oregon", 12)
|
1669 |
+
c.drawString(420, ubicacion_inicio, "NOTA DE PEDIDO")
|
1670 |
+
# agregar numero de pedido con numero idboleta
|
1671 |
+
c.drawString(420, ubicacion_inicio - 20, f"N掳 {str(idboleta).zfill(12)}")
|
1672 |
+
c.drawString(100, ubicacion_inicio - 20, "Av. Los H茅roes 632-S.J.M.")
|
1673 |
+
# agregar logo de whatsapp de 30x30
|
1674 |
+
c.drawImage("./img/pdf/logo_whatsapp.jpg", 100, ubicacion_inicio - 43, 12, 12)
|
1675 |
+
c.drawString(115, ubicacion_inicio - 40, "902-501-054/ 968-600-415")
|
1676 |
+
# a帽adir fecha a la derecha
|
1677 |
+
c.drawString(420, ubicacion_inicio - 40, f"Fecha: {now.strftime('%d/%m/%Y')}")
|
1678 |
+
# Informaci贸n del cliente
|
1679 |
+
c.drawString(
|
1680 |
+
100, ubicacion_inicio - 60, f"Se帽or(a): {cliente['nombres_y_apellidos']}"
|
1681 |
+
)
|
1682 |
+
c.drawString(
|
1683 |
+
100,
|
1684 |
+
ubicacion_inicio - 80,
|
1685 |
+
f"Direcci贸n: {cliente['direccion']}",
|
1686 |
+
)
|
1687 |
+
c.drawString(
|
1688 |
+
420,
|
1689 |
+
ubicacion_inicio - 80,
|
1690 |
+
f"Celular: {cliente['telefono']}",
|
1691 |
+
)
|
1692 |
+
|
1693 |
+
# Configurar la tipograf铆a para la secci贸n de productos
|
1694 |
+
c.setFont("Oregon", 10)
|
1695 |
+
c.drawString(100, ubicacion_inicio - 110, "Tabla de productos:")
|
1696 |
+
|
1697 |
+
# Crear la tabla de productos
|
1698 |
+
productos_data = [["Cantidad", "Descripci贸n", "P.Unitario", "Importe"]]
|
1699 |
+
for producto in productos:
|
1700 |
+
productos_data.append(
|
1701 |
+
[
|
1702 |
+
producto["cantidad"],
|
1703 |
+
producto["descripcion"],
|
1704 |
+
f"S/.{producto['precio']:.2f}",
|
1705 |
+
f"S/.{producto['importe']:.2f}",
|
1706 |
+
]
|
1707 |
+
)
|
1708 |
+
|
1709 |
+
# Configurar el estilo de la tabla
|
1710 |
+
|
1711 |
+
style = TableStyle(
|
1712 |
+
[
|
1713 |
+
("BACKGROUND", (0, 0), (-1, 0), "grey"),
|
1714 |
+
("TEXTCOLOR", (0, 0), (-1, 0), "white"),
|
1715 |
+
("ALIGN", (0, 0), (-1, -1), "CENTER"),
|
1716 |
+
("FONTNAME", (0, 0), (-1, 0), "Oregon"),
|
1717 |
+
("FONTNAME", (0, 1), (-1, -1), "Oregon"),
|
1718 |
+
("BOTTOMPADDING", (0, 0), (-1, 0), 12),
|
1719 |
+
("BACKGROUND", (0, 1), (-1, -1), "white"),
|
1720 |
+
("GRID", (0, 0), (-1, -1), 1, "grey"),
|
1721 |
+
]
|
1722 |
+
)
|
1723 |
+
|
1724 |
+
# Crear la tabla y aplicar el estilo
|
1725 |
+
table = Table(productos_data, colWidths=[50, 220, 80, 80])
|
1726 |
+
table.setStyle(style)
|
1727 |
+
|
1728 |
+
# Dibuja el t铆tulo de la tabla
|
1729 |
+
c.drawString(100, ubicacion_inicio - 110, "Tabla de productos:")
|
1730 |
+
|
1731 |
+
# Calcula la altura de la tabla
|
1732 |
+
altura_tabla = table.wrapOn(c, 400, ubicacion_inicio - 350)[1]
|
1733 |
+
|
1734 |
+
# Dibuja la tabla
|
1735 |
+
table.drawOn(c, 100, ubicacion_inicio - 130 - altura_tabla)
|
1736 |
+
|
1737 |
+
# Ajusta la ubicaci贸n de inicio para los elementos siguientes
|
1738 |
+
ubicacion_inicio = ubicacion_inicio - 130 - altura_tabla
|
1739 |
+
|
1740 |
+
# Informaci贸n de pago
|
1741 |
+
c.setFont("Oregon", 12)
|
1742 |
+
c.drawString(100, ubicacion_inicio - 40, f"Adelanto: S/.{adelanto:.2f}")
|
1743 |
+
c.drawString(250, ubicacion_inicio - 40, f"Saldo: S/.{saldo:.2f}")
|
1744 |
+
|
1745 |
+
# Calcular el total
|
1746 |
+
total = adelanto + saldo
|
1747 |
+
c.drawString(450, ubicacion_inicio - 40, f"Total: S/.{total:.2f}")
|
1748 |
+
|
1749 |
+
# Guardar y cerrar el archivo PDF
|
1750 |
+
c.save()
|
1751 |
+
|
1752 |
+
print(f"Boleta generada como: {nombre_archivo}")
|
1753 |
+
return nombre_archivo
|
1754 |
+
|
1755 |
+
|
1756 |
+
def obtener_datos_boleta(id_boleta, adelanto):
|
1757 |
+
conn = DatabaseConnection().get_connection()
|
1758 |
+
cursor = conn.cursor()
|
1759 |
+
query = """
|
1760 |
+
SELECT
|
1761 |
+
Cliente.nombres_y_apellidos,
|
1762 |
+
Cliente.direccion,
|
1763 |
+
Cliente.telefono,
|
1764 |
+
lunas_pedido.descripcion AS producto,
|
1765 |
+
lunas_pedido.precio AS precio_unitario,
|
1766 |
+
lunas_pedido.cantidad,
|
1767 |
+
boleta.precio_total AS adelanto,
|
1768 |
+
boleta.precio_total - COALESCE(SUM(lunas_pedido.precio * lunas_pedido.cantidad), 0) AS saldo,
|
1769 |
+
montura_pedido.id_montura_pedido,
|
1770 |
+
montura_pedido.cantidad AS cantidad_monturas,
|
1771 |
+
montura_inventario.precio_unit AS precio_unitario_monturas,
|
1772 |
+
montura.nombre_montura,
|
1773 |
+
montura.marca,
|
1774 |
+
montura.color,
|
1775 |
+
montura.material
|
1776 |
+
FROM boleta
|
1777 |
+
JOIN lunas_pedido ON boleta.id_boleta = lunas_pedido.id_boleta
|
1778 |
+
JOIN Prescripcion ON lunas_pedido.id_prescripcion = Prescripcion.id_prescripcion
|
1779 |
+
JOIN Medidas ON Prescripcion.id_medidas = Medidas.id_medidas
|
1780 |
+
JOIN Cliente ON Medidas.id_cliente = Cliente.id_cliente
|
1781 |
+
LEFT JOIN montura_pedido ON boleta.id_boleta = montura_pedido.id_boleta
|
1782 |
+
LEFT JOIN montura_inventario ON montura_pedido.id_montura_inventario = montura_inventario.id_montura_inventario
|
1783 |
+
LEFT JOIN montura ON montura_inventario.id_montura = montura.id_montura
|
1784 |
+
WHERE boleta.id_boleta = ?
|
1785 |
+
GROUP BY boleta.id_boleta
|
1786 |
+
"""
|
1787 |
+
|
1788 |
+
cursor.execute(query, (id_boleta,))
|
1789 |
+
datos = cursor.fetchone()
|
1790 |
+
|
1791 |
+
conn.close()
|
1792 |
+
|
1793 |
+
return datos
|
1794 |
+
|
1795 |
+
|
1796 |
+
def generar_boleta_desde_bd(id_boleta, adelanto):
|
1797 |
+
# Obtener datos de la boleta desde la base de datos
|
1798 |
+
datos = obtener_datos_boleta(id_boleta, adelanto)
|
1799 |
+
|
1800 |
+
if datos:
|
1801 |
+
# Calcular total y saldo
|
1802 |
+
total = sum([datos["precio_unitario"] * datos["cantidad"]])
|
1803 |
+
saldo = total - adelanto
|
1804 |
+
|
1805 |
+
# Crear boleta usando los datos calculados
|
1806 |
+
cliente = {
|
1807 |
+
"nombres_y_apellidos": datos["nombres_y_apellidos"],
|
1808 |
+
"direccion": datos["direccion"],
|
1809 |
+
"telefono": datos["telefono"],
|
1810 |
+
}
|
1811 |
+
|
1812 |
+
productos = [
|
1813 |
+
{
|
1814 |
+
"cantidad": datos["cantidad"],
|
1815 |
+
"descripcion": datos["producto"],
|
1816 |
+
"precio": datos["precio_unitario"],
|
1817 |
+
"importe": datos["precio_unitario"] * datos["cantidad"],
|
1818 |
+
}
|
1819 |
+
]
|
1820 |
+
|
1821 |
+
# Incluir informaci贸n de monturas si est谩 disponible
|
1822 |
+
if "id_montura_pedido" in datos:
|
1823 |
+
productos.append(
|
1824 |
+
{
|
1825 |
+
"cantidad": datos["cantidad_monturas"],
|
1826 |
+
"descripcion": f"{datos['nombre_montura']} - {datos['marca']} ({datos['color']}, {datos['material']})",
|
1827 |
+
"precio": datos["precio_unitario_monturas"],
|
1828 |
+
"importe": datos["precio_unitario_monturas"]
|
1829 |
+
* datos["cantidad_monturas"],
|
1830 |
+
}
|
1831 |
+
)
|
1832 |
+
|
1833 |
+
# Generar la boleta
|
1834 |
+
archivo_pdf_ok = generar_boleta(id_boleta, cliente, productos, adelanto, saldo)
|
1835 |
+
print(archivo_pdf_ok)
|
1836 |
+
else:
|
1837 |
+
print(f"No se encontraron datos para la boleta con ID {id_boleta}.")
|
1838 |
+
|
1839 |
+
|
1840 |
+
# clase boletaPDF para recibir los datos de la boleta
|
1841 |
+
class BoletaPDF(BaseModel):
|
1842 |
+
id_boleta: int
|
1843 |
+
adelanto: float
|
1844 |
+
|
1845 |
+
|
1846 |
+
# ruta para generar boleta en pdf con manejo de errores en caso no se encuentre la boleta
|
1847 |
+
@app.post("/boleta/pdf")
|
1848 |
+
def generar_boleta_pdf(boleta_pdf: BoletaPDF):
|
1849 |
+
try:
|
1850 |
+
directorio_pdf = "pdf/boleta/"
|
1851 |
+
now = datetime.now()
|
1852 |
+
formatted_date_time = now.strftime("%Y%m%d%H%M%S")
|
1853 |
+
nombre_archivo = f"{directorio_pdf}boleta_{formatted_date_time}.pdf"
|
1854 |
+
# crear pdf
|
1855 |
+
generar_boleta_desde_bd(boleta_pdf.id_boleta, boleta_pdf.adelanto)
|
1856 |
+
return FileResponse(
|
1857 |
+
nombre_archivo, media_type="application/pdf", filename=nombre_archivo
|
1858 |
+
)
|
1859 |
+
except:
|
1860 |
+
raise HTTPException(
|
1861 |
+
status_code=404,
|
1862 |
+
detail=f"No se encontr贸 la boleta con ID {boleta_pdf.id_boleta}",
|
1863 |
+
)
|
1864 |
+
|
1865 |
+
|
1866 |
"""
|
1867 |
CREATE TABLE montura_pedido (
|
1868 |
id_montura_pedido INTEGER PRIMARY KEY AUTOINCREMENT,
|
font/Craftcoke.ttf
ADDED
Binary file (36.4 kB). View file
|
|
font/Oregon.ttf
ADDED
Binary file (139 kB). View file
|
|
font/Roboto.ttf
ADDED
Binary file (159 kB). View file
|
|
img/pdf/logo_whatsapp.jpg
ADDED
optica_copia.db
ADDED
Binary file (49.2 kB). View file
|
|
pdf/boleta/boleta_20231209182421.pdf
ADDED
The diff for this file is too large to render.
See raw diff
|
|
pdf/prescripcion/prescripcion_1_2023-12-09.pdf
ADDED
Binary file (26.9 kB). View file
|
|