# uvicorn app:app --host localhost --port 7860 --reload import sqlite3 import threading from queue import Queue from pydantic import BaseModel from fastapi.middleware.cors import CORSMiddleware from fastapi import FastAPI, HTTPException from fastapi.responses import FileResponse from reportlab.pdfgen import canvas from reportlab.lib.pagesizes import letter from reportlab.pdfbase import pdfmetrics from reportlab.pdfbase.ttfonts import TTFont from reportlab.platypus import Table, TableStyle from datetime import datetime import os app = FastAPI() app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) class DatabaseConnection: """ Clase para gestionar las conexiones a la base de datos con un pool. """ _instance = None _lock = threading.Lock() _connection_pool = Queue(maxsize=5) def __new__(cls): """ Crea una nueva instancia de la clase si no existe. """ with cls._lock: if cls._instance is None: cls._instance = super().__new__(cls) cls._instance.conn = cls._instance._create_connection() return cls._instance def _create_connection(self): """ Crea una conexión a la base de datos. """ if not self._connection_pool.empty(): return self._connection_pool.get() else: connection = sqlite3.connect("optica_copia.db") connection.row_factory = sqlite3.Row return connection def get_connection(self): """ Obtener el objeto de conexión de la base de datos. """ return self._instance._create_connection() def release_connection(self): """ Liberar la conexión de nuevo al pool. """ if self._instance is not None: self._connection_pool.put(self._instance.conn) self._instance.conn = None # Marcar la instancia como sin conexión # Cargar varias tipografías pdfmetrics.registerFont(TTFont("Craftcoke", "./font/Craftcoke.ttf")) pdfmetrics.registerFont(TTFont("Oregon", "./font/Oregon.ttf")) pdfmetrics.registerFont(TTFont("Roboto", "./font/Roboto.ttf")) # saludo @app.get("/") def read_root(): return {"mensaje": "API de la óptica del curso de ADS"} """ CREATE TABLE Roles ( id_rol INTEGER PRIMARY KEY AUTOINCREMENT, rol VARCHAR ) """ # get/roles -> obtener todos los roles con with connection as conn, manejo de errores @app.get("/roles") def get_roles(): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT * FROM Roles") roles = cursor.fetchall() if roles: return roles else: raise HTTPException(status_code=404, detail="Roles no encontrado") except Exception as e: print(e) return [] @app.get("/roles/{id_rol}") def get_rol(id_rol: int): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT * FROM Roles WHERE id_rol = ?", (id_rol,)) rol = cursor.fetchone() if rol: return rol else: raise HTTPException(status_code=404, detail="Rol no encontrado") except Exception as e: print(e) return [] # clase y metodo post para buscar rol por nombre class RolNombre(BaseModel): rol: str @app.post("/roles/busqueda") def buscar_rol(rol: RolNombre): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT * FROM Roles WHERE rol = ?", (rol.rol,)) rol = cursor.fetchone() # retornar el rol encontrado o un mensaje de error con HTTPException if rol: return rol else: raise HTTPException(status_code=404, detail="Rol no encontrado") except Exception as e: print(e) return [] # post/roles -> crear un rol con una clase pydantic class Rol(BaseModel): rol: str # post/roles -> crear un rol con una clase pydantic @app.post("/roles") def create_rol(rol: Rol): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute("INSERT INTO Roles (rol) VALUES (?)", (rol.rol,)) conn.commit() return {"mensaje": "Rol creado exitosamente"} except Exception as e: print(e) return [] # put/roles -> actualizar un rol con una clase pydantic class RolUpdate(BaseModel): id_rol: int rol: str @app.put("/roles") def update_rol(rol: RolUpdate): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute( "UPDATE Roles SET rol = ? WHERE id_rol = ?", (rol.rol, rol.id_rol) ) conn.commit() return {"mensaje": "Rol actualizado exitosamente"} except Exception as e: print(e) return [] # delete/roles -> eliminar un rol con una clase pydantic class RolDelete(BaseModel): id_rol: int @app.delete("/roles") def delete_rol(rol: RolDelete): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute("DELETE FROM Roles WHERE id_rol = ?", (rol.id_rol,)) conn.commit() return {"mensaje": "Rol eliminado exitosamente"} except Exception as e: print(e) return [] """ CREATE TABLE Usuario ( id_usuario INTEGER PRIMARY KEY AUTOINCREMENT, nombre_usuario VARCHAR, dni VARCHAR, clave VARCHAR, id_rol INTEGER REFERENCES Roles(id_rol), estado VARCHAR ) """ # get/usuarios -> obtener todos los usuarios con with connection as conn, manejo de errores @app.get("/usuarios") def get_usuarios(): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT * FROM Usuario") usuarios = cursor.fetchall() return usuarios except Exception as e: print(e) return [] # get/usuarios/{id_usuario} -> obtener un usuario por id @app.get("/usuarios/{id_usuario}") def get_usuario(id_usuario: int): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT * FROM Usuario WHERE id_usuario = ?", (id_usuario,)) usuario = cursor.fetchone() return usuario except Exception as e: print(e) return [] # metodo de busqueda de usuario por nombre con like, manejo de errores y clase pydantic class UsuarioNombre(BaseModel): nombre_usuario: str # post/usuarios/busqueda -> buscar usuario por nombre con like @app.post("/usuarios/busqueda") def buscar_usuario(usuario: UsuarioNombre): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute( "SELECT * FROM Usuario WHERE nombre_usuario LIKE ?", ["%" + usuario.nombre_usuario + "%"], ) usuario = cursor.fetchall() if usuario: return usuario else: raise HTTPException(status_code=404, detail="Usuario no encontrado") except Exception as e: print(e) return [] # post/usuarios -> crear un usuario con una clase pydantic class Usuario(BaseModel): nombre_usuario: str dni: str clave: str id_rol: int estado: str @app.post("/usuarios") def create_usuario(usuario: Usuario): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute( "INSERT INTO Usuario (nombre_usuario, dni, clave, id_rol, estado) VALUES (?, ?, ?, ?, ?)", ( usuario.nombre_usuario, usuario.dni, usuario.clave, usuario.id_rol, usuario.estado, ), ) conn.commit() return {"mensaje": "Usuario creado exitosamente"} except Exception as e: print(e) return [] # put/usuarios -> actualizar un usuario con una clase pydantic class UsuarioUpdate(BaseModel): id_usuario: int nombre_usuario: str dni: str clave: str id_rol: int estado: str @app.put("/usuarios") def update_usuario(usuario: UsuarioUpdate): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute( "UPDATE Usuario SET nombre_usuario = ?, dni = ?, clave = ?, id_rol = ?, estado = ? WHERE id_usuario = ?", ( usuario.nombre_usuario, usuario.dni, usuario.clave, usuario.id_rol, usuario.estado, usuario.id_usuario, ), ) conn.commit() return {"mensaje": "Usuario actualizado exitosamente"} except Exception as e: print(e) return [] # delete/usuarios -> eliminar un usuario con una clase pydantic class UsuarioDelete(BaseModel): id_usuario: int @app.delete("/usuarios") def delete_usuario(usuario: UsuarioDelete): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute( "DELETE FROM Usuario WHERE id_usuario = ?", (usuario.id_usuario,) ) conn.commit() return {"mensaje": "Usuario eliminado exitosamente"} except Exception as e: print(e) return [] """ CREATE TABLE Cliente ( id_cliente INTEGER PRIMARY KEY AUTOINCREMENT, nombres_y_apellidos VARCHAR, edad INTEGER, telefono INTEGER, direccion VARCHAR ) """ # get/clientes -> obtener todos los clientes con with connection as conn, manejo de errores @app.get("/clientes") def get_clientes(): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT * FROM Cliente") clientes = cursor.fetchall() return clientes except Exception as e: print(e) return [] @app.get("/clientes/{id_cliente}") def get_cliente(id_cliente: int): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT * FROM Cliente WHERE id_cliente = ?", (id_cliente,)) cliente = cursor.fetchone() return cliente except Exception as e: print(e) return [] # metodo de busqueda de cliente por nombre con like, manejo de errores y clase pydantic class ClienteNombre(BaseModel): nombres_y_apellidos: str @app.post("/clientes/busqueda") def get_cliente_busqueda(cliente: ClienteNombre): try: conn = DatabaseConnection().get_connection() cursor = conn.cursor() cursor.execute( "SELECT * FROM Cliente WHERE nombres_y_apellidos LIKE ?", ["%" + cliente.nombres_y_apellidos + "%"], ) cliente = cursor.fetchall() if cliente: return cliente else: raise HTTPException(status_code=404, detail="Cliente no encontrado") except Exception as e: print(e) return [] # post/clientes -> crear un cliente con una clase pydantic class Cliente(BaseModel): nombres_y_apellidos: str edad: int telefono: int direccion: str @app.post("/clientes") def create_cliente(cliente: Cliente): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute( "INSERT INTO Cliente (nombres_y_apellidos, edad, telefono, direccion) VALUES (?, ?, ?, ?)", ( cliente.nombres_y_apellidos, cliente.edad, cliente.telefono, cliente.direccion, ), ) conn.commit() return {"mensaje": "Cliente creado exitosamente"} except Exception as e: print(e) return [] # put/clientes -> actualizar un cliente con una clase pydantic class ClienteUpdate(BaseModel): id_cliente: int nombres_y_apellidos: str edad: int telefono: int direccion: str @app.put("/clientes") def update_cliente(cliente: ClienteUpdate): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute( "UPDATE Cliente SET nombres_y_apellidos = ?, edad = ?, telefono = ?, direccion = ? WHERE id_cliente = ?", ( cliente.nombres_y_apellidos, cliente.edad, cliente.telefono, cliente.direccion, cliente.id_cliente, ), ) conn.commit() return {"mensaje": "Cliente actualizado exitosamente"} except Exception as e: print(e) return [] # delete/clientes -> eliminar un cliente con una clase pydantic class ClienteDelete(BaseModel): id_cliente: int # delete/clientes -> eliminar un cliente con una clase pydantic @app.delete("/clientes") def delete_cliente(cliente: ClienteDelete): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute( "DELETE FROM Cliente WHERE id_cliente = ?", (cliente.id_cliente,) ) conn.commit() return {"mensaje": "Cliente eliminado exitosamente"} except Exception as e: print(e) return [] # Define tu clase Pydantic para el modelo de datos class PrescripcionId(BaseModel): id_prescripcion: int # Define tu método de búsqueda de cliente por id de prescripción con manejo de errores y clase Pydantic @app.post("/clientes/prescripcion") def get_cliente_por_prescripcion(prescripcion_id: PrescripcionId): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() # Consulta SQL para obtener el cliente a partir del id de la prescripción cursor.execute( """ SELECT c.* FROM Cliente c JOIN Medidas m ON c.id_cliente = m.id_cliente JOIN Prescripcion p ON m.id_medidas = p.id_medidas WHERE p.id_prescripcion = ? """, [prescripcion_id.id_prescripcion], ) cliente = cursor.fetchone() if cliente: return cliente else: raise HTTPException( status_code=404, detail="Cliente no encontrado para la prescripción proporcionada", ) except Exception as e: print(e) return [] """ CREATE TABLE Medidas ( id_medidas INTEGER PRIMARY KEY AUTOINCREMENT, Esfera_OD_lejos REAL, Cilindro_OD_lejos REAL, Eje_OD_lejos REAL, Agudeza_visual_OD_lejos REAL, Esfera_OI_lejos REAL, Cilindro_OI_lejos REAL, Eje_OI_lejos REAL, Agudeza_visual_OI_lejos REAL, Esfera_OD_cerca REAL, Cilindro_OD_cerca REAL, Eje_OD_cerca REAL, Agudeza_visual_OD_cerca REAL, Esfera_OI_cerca REAL, Cilindro_OI_cerca REAL, Eje_OI_cerca REAL, Agudeza_visual_OI_cerca REAL, id_cliente INTEGER REFERENCES Cliente(id_cliente) ) """ # get/medidas -> obtener todas las medidas con with connection as conn, manejo de errores @app.get("/medidas") def get_medidas(): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT * FROM Medidas") medidas = cursor.fetchall() return medidas except Exception as e: print(e) return [] # get/medidas/{id_medidas} -> obtener una medida por id @app.get("/medidas/{id_medidas}") def get_medida(id_medidas: int): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT * FROM Medidas WHERE id_medidas = ?", (id_medidas,)) medida = cursor.fetchone() return medida except Exception as e: print(e) return [] # metodo de busqueda que sea por id_cliente y retorne las medidas asociadas a ese cliente con clase y metodo post class MedidasCliente(BaseModel): id_cliente: int @app.post("/medidas/busqueda") def buscar_medida(medida: MedidasCliente): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute( "SELECT * FROM Medidas WHERE id_cliente = ?", (medida.id_cliente,), ) medida = cursor.fetchall() if medida: return medida else: raise HTTPException(status_code=404, detail="Medida no encontrada") except Exception as e: print(e) return [] # post/medidas -> crear una medida con una clase pydantic class Medida(BaseModel): Esfera_OD_lejos: float Cilindro_OD_lejos: float Eje_OD_lejos: float Agudeza_visual_OD_lejos: float Esfera_OI_lejos: float Cilindro_OI_lejos: float Eje_OI_lejos: float Agudeza_visual_OI_lejos: float Esfera_OD_cerca: float Cilindro_OD_cerca: float Eje_OD_cerca: float Agudeza_visual_OD_cerca: float Esfera_OI_cerca: float Cilindro_OI_cerca: float Eje_OI_cerca: float Agudeza_visual_OI_cerca: float id_cliente: int @app.post("/medidas") def create_medida(medida: Medida): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute( "INSERT INTO Medidas (Esfera_OD_lejos, Cilindro_OD_lejos, Eje_OD_lejos, Agudeza_visual_OD_lejos, Esfera_OI_lejos, Cilindro_OI_lejos, Eje_OI_lejos, Agudeza_visual_OI_lejos, Esfera_OD_cerca, Cilindro_OD_cerca, Eje_OD_cerca, Agudeza_visual_OD_cerca, Esfera_OI_cerca, Cilindro_OI_cerca, Eje_OI_cerca, Agudeza_visual_OI_cerca, id_cliente) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", [ medida.Esfera_OD_lejos, medida.Cilindro_OD_lejos, medida.Eje_OD_lejos, medida.Agudeza_visual_OD_lejos, medida.Esfera_OI_lejos, medida.Cilindro_OI_lejos, medida.Eje_OI_lejos, medida.Agudeza_visual_OI_lejos, medida.Esfera_OD_cerca, medida.Cilindro_OD_cerca, medida.Eje_OD_cerca, medida.Agudeza_visual_OD_cerca, medida.Esfera_OI_cerca, medida.Cilindro_OI_cerca, medida.Eje_OI_cerca, medida.Agudeza_visual_OI_cerca, medida.id_cliente, ], ) conn.commit() return {"mensaje": "Medida creada correctamente"} except Exception as e: print(e) return [] # put/medidas -> actualizar una medida con una clase pydantic class MedidaUpdate(BaseModel): id_medidas: int Esfera_OD_lejos: float Cilindro_OD_lejos: float Eje_OD_lejos: float Agudeza_visual_OD_lejos: float Esfera_OI_lejos: float Cilindro_OI_lejos: float Eje_OI_lejos: float Agudeza_visual_OI_lejos: float Esfera_OD_cerca: float Cilindro_OD_cerca: float Eje_OD_cerca: float Agudeza_visual_OD_cerca: float Esfera_OI_cerca: float Cilindro_OI_cerca: float Eje_OI_cerca: float Agudeza_visual_OI_cerca: float id_cliente: int # metodo put de medidas con manejo de errores @app.put("/medidas") def update_medida(medida: MedidaUpdate): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute( "UPDATE Medidas SET Esfera_OD_lejos = ?, Cilindro_OD_lejos = ?, Eje_OD_lejos = ?, Agudeza_visual_OD_lejos = ?, Esfera_OI_lejos = ?, Cilindro_OI_lejos = ?, Eje_OI_lejos = ?, Agudeza_visual_OI_lejos = ?, Esfera_OD_cerca = ?, Cilindro_OD_cerca = ?, Eje_OD_cerca = ?, Agudeza_visual_OD_cerca = ?, Esfera_OI_cerca = ?, Cilindro_OI_cerca = ?, Eje_OI_cerca = ?, Agudeza_visual_OI_cerca = ?, id_cliente = ? WHERE id_medidas = ?", [ medida.Esfera_OD_lejos, medida.Cilindro_OD_lejos, medida.Eje_OD_lejos, medida.Agudeza_visual_OD_lejos, medida.Esfera_OI_lejos, medida.Cilindro_OI_lejos, medida.Eje_OI_lejos, medida.Agudeza_visual_OI_lejos, medida.Esfera_OD_cerca, medida.Cilindro_OD_cerca, medida.Eje_OD_cerca, medida.Agudeza_visual_OD_cerca, medida.Esfera_OI_cerca, medida.Cilindro_OI_cerca, medida.Eje_OI_cerca, medida.Agudeza_visual_OI_cerca, medida.id_cliente, medida.id_medidas, ], ) conn.commit() return {"mensaje": "Medida actualizada correctamente"} except Exception as e: print(e) return [] # delete/medidas -> eliminar una medida con una clase pydantic class MedidaDelete(BaseModel): id_medidas: int # metodo delete de medidas con manejo de errores @app.delete("/medidas") def delete_medida(medida: MedidaDelete): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute( "DELETE FROM Medidas WHERE id_medidas = ?", (medida.id_medidas,) ) conn.commit() return {"mensaje": "Medida eliminada exitosamente"} except Exception as e: print(e) return [] """ CREATE TABLE Prescripcion ( id_prescripcion INTEGER PRIMARY KEY AUTOINCREMENT, id_medidas INTEGER REFERENCES Medidas(id_medidas), detalle_lunas VARCHAR, fecha VARCHAR ) """ # get/prescripciones -> obtener todas las prescripciones con with connection as conn, manejo de errores @app.get("/prescripciones") def get_prescripciones(): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT * FROM Prescripcion") prescripciones = cursor.fetchall() return prescripciones except Exception as e: print(e) return [] @app.get("/prescripciones/ultimoregistro") def get_prescripciones(): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute( "SELECT * FROM Prescripcion ORDER BY id_prescripcion DESC LIMIT 1;" ) prescripciones = cursor.fetchall() return prescripciones except Exception as e: print(e) return [] # get/prescripciones/{id_prescripcion} -> obtener una prescripcion por id @app.get("/prescripciones/{id_prescripcion}") def get_prescripcion(id_prescripcion: int): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute( "SELECT * FROM Prescripcion WHERE id_prescripcion = ?", (id_prescripcion,), ) prescripcion = cursor.fetchone() return prescripcion except Exception as e: print(e) return [] # post/prescripciones -> crear una prescripcion con una clase pydantic class Prescripcion(BaseModel): id_medidas: int detalle_lunas: str fecha: str # metodo post de prescripciones con manejo de errores @app.post("/prescripciones") def create_prescripcion(prescripcion: Prescripcion): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute( "INSERT INTO Prescripcion (id_medidas, detalle_lunas, fecha) VALUES (?, ?, ?)", ( prescripcion.id_medidas, prescripcion.detalle_lunas, prescripcion.fecha, ), ) conn.commit() return {"mensaje": "Prescripcion creada exitosamente"} except Exception as e: print(e) return [] # put/prescripciones -> actualizar una prescripcion con una clase pydantic class PrescripcionUpdate(BaseModel): id_prescripcion: int id_medidas: int detalle_lunas: str fecha: str # metodo put de prescripciones con manejo de errores @app.put("/prescripciones") def update_prescripcion(prescripcion: PrescripcionUpdate): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute( "UPDATE Prescripcion SET id_medidas = ?, detalle_lunas = ?, fecha = ? WHERE id_prescripcion = ?", ( prescripcion.id_medidas, prescripcion.detalle_lunas, prescripcion.fecha, prescripcion.id_prescripcion, ), ) conn.commit() return {"mensaje": "Prescripcion actualizada exitosamente"} except Exception as e: print(e) return [] # delete/prescripciones -> eliminar una prescripcion con una clase pydantic class PrescripcionDelete(BaseModel): id_prescripcion: int # metodo delete de prescripciones con manejo de errores @app.delete("/prescripciones") def delete_prescripcion(prescripcion: PrescripcionDelete): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute( "DELETE FROM Prescripcion WHERE id_prescripcion = ?", (prescripcion.id_prescripcion,), ) conn.commit() return {"mensaje": "Prescripcion eliminada exitosamente"} except Exception as e: print(e) return [] def obtener_datos_prescripcion(id_prescripcion): try: conn = DatabaseConnection().get_connection() cursor = conn.cursor() query = """ SELECT P.id_prescripcion, P.fecha AS fecha_prescripcion, P.detalle_lunas, Me.Esfera_OD_lejos, Me.Cilindro_OD_lejos, Me.Eje_OD_lejos, Me.Agudeza_visual_OD_lejos, Me.Esfera_OI_lejos, Me.Cilindro_OI_lejos, Me.Eje_OI_lejos, Me.Agudeza_visual_OI_lejos, Me.Esfera_OD_cerca, Me.Cilindro_OD_cerca, Me.Eje_OD_cerca, Me.Agudeza_visual_OD_cerca, Me.Esfera_OI_cerca, Me.Cilindro_OI_cerca, Me.Eje_OI_cerca, Me.Agudeza_visual_OI_cerca, C.id_cliente, C.nombres_y_apellidos, C.edad, C.telefono, C.direccion FROM Prescripcion AS P JOIN Medidas AS Me ON P.id_medidas = Me.id_medidas JOIN Cliente AS C ON Me.id_cliente = C.id_cliente WHERE P.id_prescripcion = ?; """ cursor.execute(query, (id_prescripcion,)) resultado = cursor.fetchone() return resultado except Exception as e: print(e) return [] class DatosPrescripcion: def __init__( self, id_prescripcion, fecha_prescripcion, detalle_lunas, esfera_od_lejos, cilindro_od_lejos, eje_od_lejos, agudeza_visual_od_lejos, esfera_oi_lejos, cilindro_oi_lejos, eje_oi_lejos, agudeza_visual_oi_lejos, esfera_od_cerca, cilindro_od_cerca, eje_od_cerca, agudeza_visual_od_cerca, esfera_oi_cerca, cilindro_oi_cerca, eje_oi_cerca, agudeza_visual_oi_cerca, id_cliente, nombres_y_apellidos, edad, telefono, direccion, ): self.id_prescripcion = id_prescripcion self.fecha_prescripcion = fecha_prescripcion self.detalle_lunas = detalle_lunas self.esfera_od_lejos = esfera_od_lejos self.cilindro_od_lejos = cilindro_od_lejos self.eje_od_lejos = eje_od_lejos self.agudeza_visual_od_lejos = agudeza_visual_od_lejos self.esfera_oi_lejos = esfera_oi_lejos self.cilindro_oi_lejos = cilindro_oi_lejos self.eje_oi_lejos = eje_oi_lejos self.agudeza_visual_oi_lejos = agudeza_visual_oi_lejos self.esfera_od_cerca = esfera_od_cerca self.cilindro_od_cerca = cilindro_od_cerca self.eje_od_cerca = eje_od_cerca self.agudeza_visual_od_cerca = agudeza_visual_od_cerca self.esfera_oi_cerca = esfera_oi_cerca self.cilindro_oi_cerca = cilindro_oi_cerca self.eje_oi_cerca = eje_oi_cerca self.agudeza_visual_oi_cerca = agudeza_visual_oi_cerca self.id_cliente = id_cliente self.nombres_y_apellidos_cliente = nombres_y_apellidos self.edad_cliente = edad self.telefono_cliente = telefono self.direccion_cliente = direccion def generar_pdf(self, filename): pdf = canvas.Canvas(filename) pdf.setFont("Oregon", 12) ubicacion_inicio = 780 # Posición inicial en y pdf.drawCentredString( 300, ubicacion_inicio, "OPTICA ARTE VISUAL - PRESCRIPCIÓN" ) pdf.drawString( 100, ubicacion_inicio - 40, f"Nombre del Cliente: {self.nombres_y_apellidos_cliente}", ) pdf.drawString( 100, ubicacion_inicio - 60, f"Datos del cliente: {self.direccion_cliente}" ) pdf.drawString( 100, ubicacion_inicio - 80, f"Número telefónico: {self.telefono_cliente}" ) pdf.drawString( 100, ubicacion_inicio - 100, f"Código de prescripción: {self.id_prescripcion}", ) pdf.drawString(100, ubicacion_inicio - 120, f"Fecha: {self.fecha_prescripcion}") pdf.drawString( 100, ubicacion_inicio - 140, f"Descripción: {self.detalle_lunas}" ) ubicacion_esfera = 150 # Posición inicial en x ubicacion_cilindro = ubicacion_esfera + 65 # Posición inicial en x + 65 ubicacion_eje = ubicacion_cilindro + 75 # Posición anterior en x + 75 ubicacion_agudeza = ubicacion_eje + 70 # Posición anterior en x + 70 tabla_medidas = ubicacion_inicio - 170 # Posición inicial en y pdf.drawString(ubicacion_esfera - 50, tabla_medidas, "Tabla de medidas:") # Para el ojo izquierdo de lejos pdf.drawString( ubicacion_esfera + 100, tabla_medidas - 20, "Ojo izquierdo de lejos" ) pdf.line( x1=ubicacion_esfera, y1=tabla_medidas - 25, x2=ubicacion_esfera + 300, y2=tabla_medidas - 25, ) pdf.drawString(ubicacion_esfera, tabla_medidas - 40, "Esfera") pdf.drawString(ubicacion_cilindro, tabla_medidas - 40, "Cilindro") pdf.drawString(ubicacion_eje, tabla_medidas - 40, "Eje") pdf.drawString(ubicacion_agudeza, tabla_medidas - 40, "Agudeza visual") pdf.drawString(ubicacion_esfera, tabla_medidas - 60, f"{self.esfera_oi_lejos}") pdf.drawString( ubicacion_cilindro, tabla_medidas - 60, f"{self.cilindro_oi_lejos}" ) pdf.drawString(ubicacion_eje, tabla_medidas - 60, f"{self.eje_oi_lejos}") pdf.drawString( ubicacion_agudeza, tabla_medidas - 60, f"{self.agudeza_visual_oi_lejos}" ) # Para el ojo derecho de lejos odl = tabla_medidas - 100 # Posición inicial en y pdf.drawString(ubicacion_esfera + 100, odl, "Ojo derecho de lejos") pdf.line(x1=ubicacion_esfera, y1=odl - 5, x2=ubicacion_esfera + 300, y2=odl - 5) pdf.drawString(ubicacion_esfera, odl - 20, "Esfera") pdf.drawString(ubicacion_cilindro, odl - 20, "Cilindro") pdf.drawString(ubicacion_eje, odl - 20, "Eje") pdf.drawString(ubicacion_agudeza, odl - 20, "Agudeza visual") pdf.drawString(ubicacion_esfera, odl - 40, f"{self.esfera_od_lejos}") pdf.drawString(ubicacion_cilindro, odl - 40, f"{self.cilindro_od_lejos}") pdf.drawString(ubicacion_eje, odl - 40, f"{self.eje_od_lejos}") pdf.drawString(ubicacion_agudeza, odl - 40, f"{self.agudeza_visual_od_lejos}") oic = odl - 80 # Posición inicial en y pdf.drawString(ubicacion_esfera + 100, oic, "Ojo izquierdo de cerca") pdf.line(x1=ubicacion_esfera, y1=oic - 5, x2=ubicacion_esfera + 300, y2=oic - 5) # Para el ojo izquierdo de cerca pdf.drawString(ubicacion_esfera, oic - 20, "Esfera") pdf.drawString(ubicacion_cilindro, oic - 20, "Cilindro") pdf.drawString(ubicacion_eje, oic - 20, "Eje") pdf.drawString(ubicacion_agudeza, oic - 20, "Agudeza visual") pdf.drawString(ubicacion_esfera, oic - 40, f"{self.esfera_oi_cerca}") pdf.drawString(ubicacion_cilindro, oic - 40, f"{self.cilindro_oi_cerca}") pdf.drawString(ubicacion_eje, oic - 40, f"{self.eje_oi_cerca}") pdf.drawString(ubicacion_agudeza, oic - 40, f"{self.agudeza_visual_oi_cerca}") odc = oic - 80 pdf.drawString(ubicacion_esfera + 100, odc, "Ojo derecho de cerca") pdf.line(x1=ubicacion_esfera, y1=odc - 5, x2=ubicacion_esfera + 300, y2=odc - 5) # Para el ojo derecho de cerca pdf.drawString(ubicacion_esfera, odc - 20, "Esfera") pdf.drawString(ubicacion_cilindro, odc - 20, "Cilindro") pdf.drawString(ubicacion_eje, odc - 20, "Eje") pdf.drawString(ubicacion_agudeza, odc - 20, "Agudeza visual") pdf.drawString(ubicacion_esfera, odc - 40, f"{self.esfera_od_cerca}") pdf.drawString(ubicacion_cilindro, odc - 40, f"{self.cilindro_od_cerca}") pdf.drawString(ubicacion_eje, odc - 40, f"{self.eje_od_cerca}") pdf.drawString(ubicacion_agudeza, odc - 40, f"{self.agudeza_visual_od_cerca}") # Calcular el centro de la página centro_pagina = pdf._pagesize[0] / 2 # Texto y línea centrados texto_firma = " Firma o sello: " ancho_texto = pdf.stringWidth(texto_firma, "Helvetica", 12) inicio_linea = centro_pagina - ancho_texto / 2 fin_linea = inicio_linea + ancho_texto # ubicacion en y dependiendo de la tabla de medidas firma_ubicacion = odc - 70 pdf.drawString(inicio_linea, firma_ubicacion, texto_firma) pdf.line(inicio_linea, firma_ubicacion - 50, fin_linea, firma_ubicacion - 50) pdf.save() print(f"PDF generado: {filename}") # crear endpoint para obtener los datos de la prescripción @app.get("/prescripcion/{id_prescripcion}") def obtener_datos_prescripcion_api(id_prescripcion: int): datos_prescripcion = obtener_datos_prescripcion(id_prescripcion) if datos_prescripcion: # Crear un objeto de la clase DatosPrescripcion obj_datos_prescripcion = DatosPrescripcion(*datos_prescripcion) return obj_datos_prescripcion else: raise HTTPException(status_code=404, detail="Prescripción no encontrada") # endpoint descargar prescripcion pdf con clase class PrescripcionPDF(BaseModel): id_prescripcion: int @app.post("/prescripcion/pdf") def obtener_pdf_prescripcion_api(prescripcion: PrescripcionPDF): datos_prescripcion = obtener_datos_prescripcion(prescripcion.id_prescripcion) if datos_prescripcion: # Crear un objeto de la clase DatosPrescripcion obj_datos_prescripcion = DatosPrescripcion(*datos_prescripcion) directorio_pdf = "pdf/prescripcion/" os.makedirs(directorio_pdf, exist_ok=True) # importar libreria de fecha de hoy from datetime import date # obtener la fecha de hoy fecha_hoy = date.today() # generar el nombre del archivo nombre_archivo = f"{directorio_pdf}prescripcion_{prescripcion.id_prescripcion}_{fecha_hoy}.pdf" obj_datos_prescripcion.generar_pdf(f"{nombre_archivo}") return FileResponse( nombre_archivo, media_type="application/pdf", filename=nombre_archivo ) else: raise HTTPException(status_code=404, detail="Prescripción no encontrada") # crear endpoint retornando la url del PDF con los datos de la prescripción @app.get("/prescripcion/pdf/{id_prescripcion}") def obtener_pdf_prescripcion(id_prescripcion: int): datos_prescripcion = obtener_datos_prescripcion(id_prescripcion) if datos_prescripcion: # Crear un objeto de la clase DatosPrescripcion obj_datos_prescripcion = DatosPrescripcion(*datos_prescripcion) directorio_pdf = "pdf/prescripcion/" os.makedirs(directorio_pdf, exist_ok=True) # importar libreria de fecha de hoy from datetime import date # obtener la fecha de hoy fecha_hoy = date.today() # generar el nombre del archivo nombre_archivo = ( f"{directorio_pdf}prescripcion_{id_prescripcion}_{fecha_hoy}.pdf" ) obj_datos_prescripcion.generar_pdf(f"{nombre_archivo}") return FileResponse(path=nombre_archivo) else: raise HTTPException(status_code=404, detail="Prescripción no encontrada") """ Table lunas_pedido { id_lunas_pedido INTEGER [primary key, unique, increment] id_prescripcion INTEGER [ref: > Prescripcion.id_prescripcion] precio REAL id_boleta INTEGER [ref: > boleta.id_boleta] descripcion VARCHAR cantidad INTEGER } """ # get @app.get("/lunas_pedido") def get_lunas_pedido(): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT * FROM lunas_pedido") lunas_pedido = cursor.fetchall() return lunas_pedido except Exception as e: print(e) return [] # post con pydantic class LunasPedido(BaseModel): id_prescripcion: int precio: float id_boleta: int descripcion: str cantidad: int @app.post("/lunas_pedido") def create_lunas_pedido(lunas_pedido: LunasPedido): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute( "INSERT INTO lunas_pedido (id_prescripcion, precio, id_boleta, descripcion, cantidad) VALUES (?, ?, ?, ?, ?)", ( lunas_pedido.id_prescripcion, lunas_pedido.precio, lunas_pedido.id_boleta, lunas_pedido.descripcion, lunas_pedido.cantidad, ), ) conn.commit() return {"mensaje": "Lunas_pedido creada exitosamente"} except Exception as e: print(e) return [] # put con pydantic class LunasPedidoUpdate(BaseModel): id_lunas_pedido: int id_prescripcion: int precio: float id_boleta: int descripcion: str cantidad: int @app.put("/lunas_pedido") def update_lunas_pedido(lunas_pedido: LunasPedidoUpdate): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute( "UPDATE lunas_pedido SET id_prescripcion = ?, precio = ?, id_boleta = ?, descripcion = ?, cantidad = ? WHERE id_lunas_pedido = ?", ( lunas_pedido.id_prescripcion, lunas_pedido.precio, lunas_pedido.id_boleta, lunas_pedido.descripcion, lunas_pedido.cantidad, lunas_pedido.id_lunas_pedido, ), ) conn.commit() return {"mensaje": "Lunas_pedido actualizada exitosamente"} except Exception as e: print(e) return [] # delete con pydantic class LunasPedidoDelete(BaseModel): id_lunas_pedido: int @app.delete("/lunas_pedido") def delete_lunas_pedido(lunas_pedido: LunasPedidoDelete): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute( "DELETE FROM lunas_pedido WHERE id_lunas_pedido = ?", (lunas_pedido.id_lunas_pedido,), ) conn.commit() return {"mensaje": "Lunas_pedido eliminada exitosamente"} except Exception as e: print(e) return [] """ CREATE TABLE Montura ( id_montura INTEGER PRIMARY KEY AUTOINCREMENT, nombre_montura VARCHAR, imagen VARCHAR, marca VARCHAR, color VARCHAR, material VARCHAR ) """ # get/monturas -> obtener todas las monturas con with connection as conn, manejo de errores @app.get("/monturas") def get_monturas(): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT * FROM Montura") monturas = cursor.fetchall() return monturas except Exception as e: print(e) return [] # get/monturas/{id_montura} -> obtener una montura por id @app.get("/monturas/{id_montura}") def get_montura(id_montura: int): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT * FROM Montura WHERE id_montura = ?", (id_montura,)) montura = cursor.fetchone() return montura except Exception as e: print(e) return [] # busqueda de montura por nombre con like, manejo de errores y clase pydantic class MonturaNombre(BaseModel): nombre_montura: str # post/monturas/busqueda -> buscar montura por nombre @app.post("/monturas/busqueda") def buscar_montura(montura: MonturaNombre): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute( "SELECT * FROM Montura WHERE nombre_montura LIKE ?", (montura.nombre_montura,), ) montura = cursor.fetchall() if montura: return montura else: raise HTTPException(status_code=404, detail="Montura no encontrada") except Exception as e: print(e) return [] # post/monturas -> crear una montura con una clase pydantic class Montura(BaseModel): nombre_montura: str imagen: str marca: str color: str material: str # metodo post de monturas con manejo de errores @app.post("/monturas") def create_montura(montura: Montura): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute( "INSERT INTO Montura (nombre_montura, imagen, marca, color, material) VALUES (?, ?, ?, ?, ?)", ( montura.nombre_montura, montura.imagen, montura.marca, montura.color, montura.material, ), ) conn.commit() return {"mensaje": "Montura creada exitosamente"} except Exception as e: print(e) return [] # put/monturas -> actualizar una montura con una clase pydantic class MonturaUpdate(BaseModel): id_montura: int nombre_montura: str imagen: str marca: str color: str material: str # metodo put de monturas con manejo de errores @app.put("/monturas") def update_montura(montura: MonturaUpdate): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute( "UPDATE Montura SET nombre_montura = ?, imagen = ?, marca = ?, color = ?, material = ? WHERE id_montura = ?", ( montura.nombre_montura, montura.imagen, montura.marca, montura.color, montura.material, montura.id_montura, ), ) conn.commit() return {"mensaje": "Montura actualizada exitosamente"} except Exception as e: print(e) return [] # delete/monturas -> eliminar una montura con una clase pydantic class MonturaDelete(BaseModel): id_montura: int # metodo delete de monturas con manejo de errores @app.delete("/monturas") def delete_montura(montura: MonturaDelete): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute( "DELETE FROM Montura WHERE id_montura = ?", (montura.id_montura,) ) conn.commit() return {"mensaje": "Montura eliminada exitosamente"} except Exception as e: print(e) return [] """ CREATE TABLE Montura_inventario ( id_montura_inventario INTEGER PRIMARY KEY AUTOINCREMENT, id_montura INTEGER REFERENCES Montura(id_montura), precio_unit REAL, stock INTEGER, codigo VARCHAR ) """ # get/monturas_inventario -> obtener todas las monturas_inventario con with connection as conn, manejo de errores @app.get("/monturas_inventario") def get_monturas_inventario(): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT * FROM Montura_inventario") monturas_inventario = cursor.fetchall() return monturas_inventario except Exception as e: print(e) return [] # get/monturas_inventario/{id_montura_inventario} -> obtener una montura_inventario por id @app.get("/monturas_inventario/{id_montura_inventario}") def get_montura_inventario(id_montura_inventario: int): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute( "SELECT * FROM Montura_inventario WHERE id_montura_inventario = ?", (id_montura_inventario,), ) montura_inventario = cursor.fetchone() return montura_inventario except Exception as e: print(e) return [] # post/monturas_inventario -> crear una montura_inventario con una clase pydantic class Montura_inventario(BaseModel): id_montura: int precio_unit: float stock: int codigo: str # metodo post de monturas_inventario con manejo de errores @app.post("/monturas_inventario") def create_montura_inventario(montura_inventario: Montura_inventario): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute( "INSERT INTO Montura_inventario (id_montura, precio_unit, stock, codigo) VALUES (?, ?, ?, ?)", ( montura_inventario.id_montura, montura_inventario.precio_unit, montura_inventario.stock, montura_inventario.codigo, ), ) conn.commit() return {"mensaje": "Montura_inventario creada exitosamente"} except Exception as e: print(e) return [] # busqueda de montura_inventario por codigo con like, manejo de errores y clase pydantic class Montura_inventarioCodigo(BaseModel): codigo: str # post/monturas_inventario/busqueda -> buscar una montura_inventario por codigo @app.post("/monturas_inventario/busqueda") def buscar_montura_inventario(montura_inventario: Montura_inventarioCodigo): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute( "SELECT * FROM Montura_inventario WHERE codigo LIKE ?", (montura_inventario.codigo,), ) montura_inventario = cursor.fetchall() if montura_inventario: return montura_inventario else: raise HTTPException( status_code=404, detail="Montura_inventario no encontrada" ) except Exception as e: print(e) return [] # put/monturas_inventario -> actualizar una montura_inventario con una clase pydantic class Montura_inventarioUpdate(BaseModel): id_montura_inventario: int id_montura: int precio_unit: float stock: int codigo: str # metodo put de monturas_inventario con manejo de errores @app.put("/monturas_inventario") def update_montura_inventario(montura_inventario: Montura_inventarioUpdate): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute( "UPDATE Montura_inventario SET id_montura = ?, precio_unit = ?, stock = ?, codigo = ? WHERE id_montura_inventario = ?", ( montura_inventario.id_montura, montura_inventario.precio_unit, montura_inventario.stock, montura_inventario.codigo, montura_inventario.id_montura_inventario, ), ) conn.commit() return {"mensaje": "Montura_inventario actualizada exitosamente"} except Exception as e: print(e) return [] # delete/monturas_inventario -> eliminar una montura_inventario con una clase pydantic class Montura_inventarioDelete(BaseModel): id_montura_inventario: int # metodo delete de monturas_inventario con manejo de errores @app.delete("/monturas_inventario") def delete_montura_inventario(montura_inventario: Montura_inventarioDelete): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute( "DELETE FROM Montura_inventario WHERE id_montura_inventario = ?", (montura_inventario.id_montura_inventario,), ) conn.commit() return {"mensaje": "Montura_inventario eliminada exitosamente"} except Exception as e: print(e) return [] """ CREATE TABLE boleta ( id_boleta INTEGER PRIMARY KEY AUTOINCREMENT, precio_total REAL, estado_recojo VARCHAR ) """ # get/boletas -> obtener todas las boletas con with connection as conn, manejo de errores @app.get("/boletas") def get_boletas(): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT * FROM boleta") boletas = cursor.fetchall() return boletas except Exception as e: print(e) return [] # get/boletas/{id_boleta} -> obtener una boleta por id @app.get("/boletas/{id_boleta}") def get_boleta(id_boleta: int): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT * FROM boleta WHERE id_boleta = ?", (id_boleta,)) boleta = cursor.fetchone() if boleta: return boleta else: raise HTTPException(status_code=404, detail="Boleta no encontrada") except Exception as e: print(e) return [] # post/boletas -> crear una boleta con una clase pydantic class Boleta(BaseModel): precio_total: float estado_recojo: str # metodo post de boletas con manejo de errores @app.post("/boletas") def create_boleta(boleta: Boleta): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute( "INSERT INTO boleta (precio_total, estado_recojo) VALUES (?, ?)", ( boleta.precio_total, boleta.estado_recojo, ), ) conn.commit() return {"mensaje": "Boleta creada exitosamente"} except Exception as e: print(e) return [] # put/boletas -> actualizar una boleta con una clase pydantic class BoletaUpdate(BaseModel): id_boleta: int precio_total: float estado_recojo: str # metodo put de boletas con manejo de errores @app.put("/boletas") def update_boleta(boleta: BoletaUpdate): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute( "UPDATE boleta SET precio_total = ?, estado_recojo = ? WHERE id_boleta = ?", ( boleta.precio_total, boleta.estado_recojo, boleta.id_boleta, ), ) conn.commit() return {"mensaje": "Boleta actualizada exitosamente"} except Exception as e: print(e) return [] # delete/boletas -> eliminar una boleta con una clase pydantic class BoletaDelete(BaseModel): id_boleta: int # metodo delete de boletas con manejo de errores @app.delete("/boletas") def delete_boleta(boleta: BoletaDelete): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute( "DELETE FROM boleta WHERE id_boleta = ?", (boleta.id_boleta,) ) conn.commit() return {"mensaje": "Boleta eliminada exitosamente"} except Exception as e: print(e) return [] def generar_boleta(idboleta, cliente, productos, adelanto, saldo): # crear directorio si no existe en pdf/boleta directorio_pdf = "pdf/boleta/" os.makedirs(directorio_pdf, exist_ok=True) # Crear un nombre de archivo único basado en la fecha y hora actual now = datetime.now() formatted_date_time = now.strftime("%Y%m%d%H%M%S") nombre_archivo = f"{directorio_pdf}boleta_{formatted_date_time}.pdf" # Inicializar el lienzo del PDF c = canvas.Canvas(nombre_archivo, pagesize=letter) ubicacion_inicio = 700 # Configurar la tipografía para la sección del cliente c.setFont("Craftcoke", 30) c.drawString(100, ubicacion_inicio, "Arte Visual") # Configurar la tipografía para la sección de productos c.setFont("Oregon", 12) c.drawString(420, ubicacion_inicio, "NOTA DE PEDIDO") # agregar numero de pedido con numero idboleta c.drawString(420, ubicacion_inicio - 20, f"N° {str(idboleta).zfill(12)}") c.drawString(100, ubicacion_inicio - 20, "Av. Los Héroes 632-S.J.M.") # agregar logo de whatsapp de 30x30 c.drawImage("./img/pdf/logo_whatsapp.jpg", 100, ubicacion_inicio - 43, 12, 12) c.drawString(115, ubicacion_inicio - 40, "902-501-054/ 968-600-415") # añadir fecha a la derecha c.drawString(420, ubicacion_inicio - 40, f"Fecha: {now.strftime('%d/%m/%Y')}") # Información del cliente c.drawString( 100, ubicacion_inicio - 60, f"Señor(a): {cliente['nombres_y_apellidos']}" ) c.drawString( 100, ubicacion_inicio - 80, f"Dirección: {cliente['direccion']}", ) c.drawString( 420, ubicacion_inicio - 80, f"Celular: {cliente['telefono']}", ) # Configurar la tipografía para la sección de productos c.setFont("Oregon", 10) c.drawString(100, ubicacion_inicio - 110, "Tabla de productos:") # Crear la tabla de productos productos_data = [["Cantidad", "Descripción", "P.Unitario", "Importe"]] for producto in productos: productos_data.append( [ producto["cantidad"], producto["descripcion"], f"S/.{producto['precio']:.2f}", f"S/.{producto['importe']:.2f}", ] ) # Configurar el estilo de la tabla style = TableStyle( [ ("BACKGROUND", (0, 0), (-1, 0), "grey"), ("TEXTCOLOR", (0, 0), (-1, 0), "white"), ("ALIGN", (0, 0), (-1, -1), "CENTER"), ("VALIGN", (0, 0), (-1, -1), "MIDDLE"), # Alineación vertical al centro ("FONTNAME", (0, 0), (-1, 0), "Oregon"), ("FONTNAME", (0, 1), (-1, -1), "Oregon"), ("BOTTOMPADDING", (0, 0), (-1, 0), 12), ("BACKGROUND", (0, 1), (-1, -1), "white"), ("GRID", (0, 0), (-1, -1), 1, "grey"), ] ) # Crear la tabla y aplicar el estilo table = Table(productos_data, colWidths=[50, 220, 80, 80]) table.setStyle(style) # Dibuja el título de la tabla c.drawString(100, ubicacion_inicio - 110, "Tabla de productos:") # Calcula la altura de la tabla altura_tabla = table.wrapOn(c, 400, ubicacion_inicio - 350)[1] # Dibuja la tabla table.drawOn(c, 100, ubicacion_inicio - 130 - altura_tabla) # Ajusta la ubicación de inicio para los elementos siguientes ubicacion_inicio = ubicacion_inicio - 130 - altura_tabla # Información de pago c.setFont("Oregon", 12) c.drawString(100, ubicacion_inicio - 40, f"Adelanto: S/.{adelanto:.2f}") c.drawString(250, ubicacion_inicio - 40, f"Saldo: S/.{saldo:.2f}") # Calcular el total total = adelanto + saldo c.drawString(450, ubicacion_inicio - 40, f"Total: S/.{total:.2f}") # Guardar y cerrar el archivo PDF c.save() print(f"Boleta generada como: {nombre_archivo}") return nombre_archivo def obtener_datos_boleta(id_boleta, adelanto): conn = DatabaseConnection().get_connection() cursor = conn.cursor() query = """ SELECT Cliente.nombres_y_apellidos, Cliente.direccion, Cliente.telefono, lunas_pedido.descripcion AS producto, lunas_pedido.precio AS precio_unitario, lunas_pedido.cantidad, boleta.precio_total AS adelanto, boleta.precio_total - COALESCE(SUM(lunas_pedido.precio * lunas_pedido.cantidad), 0) AS saldo, montura_pedido.id_montura_pedido, montura_pedido.cantidad AS cantidad_monturas, montura_inventario.precio_unit AS precio_unitario_monturas, montura.nombre_montura, montura.marca, montura.color, montura.material FROM boleta JOIN lunas_pedido ON boleta.id_boleta = lunas_pedido.id_boleta JOIN Prescripcion ON lunas_pedido.id_prescripcion = Prescripcion.id_prescripcion JOIN Medidas ON Prescripcion.id_medidas = Medidas.id_medidas JOIN Cliente ON Medidas.id_cliente = Cliente.id_cliente LEFT JOIN montura_pedido ON boleta.id_boleta = montura_pedido.id_boleta LEFT JOIN montura_inventario ON montura_pedido.id_montura_inventario = montura_inventario.id_montura_inventario LEFT JOIN montura ON montura_inventario.id_montura = montura.id_montura WHERE boleta.id_boleta = ? GROUP BY boleta.id_boleta """ cursor.execute(query, (id_boleta,)) datos = cursor.fetchone() conn.close() return datos def obtener_productos_por_boleta(id_boleta): # Conectarse a la base de datos SQLite conn = DatabaseConnection().get_connection() cursor = conn.cursor() # Consulta para monturas query_monturas = f""" SELECT mp.cantidad AS cantidad, mi.codigo AS codigo_montura, m.nombre_montura AS nombre_montura, m.marca, m.color, m.material, mi.precio_unit AS precio_unitario, (mi.precio_unit * mp.cantidad) AS importe FROM montura_pedido mp JOIN montura_inventario mi ON mp.id_montura_inventario = mi.id_montura_inventario JOIN montura m ON mi.id_montura = m.id_montura WHERE mp.id_boleta = {id_boleta}; """ cursor.execute(query_monturas) resultados_monturas = cursor.fetchall() # Consulta para lunas query_lunas = f""" SELECT lp.cantidad AS cantidad, p.detalle_lunas AS descripcion, lp.precio AS precio, (lp.precio * lp.cantidad) AS importe FROM lunas_pedido lp JOIN boleta b ON lp.id_boleta = b.id_boleta JOIN prescripcion p ON lp.id_prescripcion = p.id_prescripcion WHERE b.id_boleta = {id_boleta}; """ cursor.execute(query_lunas) resultados_lunas = cursor.fetchall() # Cerrar la conexión a la base de datos conn.close() # Crear un diccionario combinado con los resultados productos = [] print("Esta es la cantidad de monturas y lunas:") print(f"Monturas: {len(resultados_monturas)}") print(f"Lunas: {len(resultados_lunas)}") # validacion si hay monturas if len(resultados_monturas) > 0: # Agregar monturas al diccionario for resultado_montura in resultados_monturas: producto_montura = { "cantidad": resultado_montura[0], "descripcion": f"Código: {resultado_montura[1]}, \nNombre: {resultado_montura[2]}, \nMarca: {resultado_montura[3]}, \nColor: {resultado_montura[4]}, \nMaterial: {resultado_montura[5]}", "precio": resultado_montura[6], "importe": resultado_montura[7], } productos.append(producto_montura) # validacion si hay lunas if len(resultados_lunas) > 0: # Agregar lunas al diccionario for resultado_luna in resultados_lunas: producto_luna = { "cantidad": resultado_luna[0], "descripcion": resultado_luna[1], "precio": resultado_luna[2], "importe": resultado_luna[3], } productos.append(producto_luna) return productos def generar_boleta_desde_bd(id_boleta, adelanto): # Obtener datos de la boleta desde la base de datos datos = obtener_datos_boleta(id_boleta, adelanto) if datos: # Crear boleta usando los datos calculados cliente = { "nombres_y_apellidos": datos["nombres_y_apellidos"], "direccion": datos["direccion"], "telefono": datos["telefono"], } productos = obtener_productos_por_boleta(id_boleta) # Calcular total y saldo total = sum( [producto["cantidad"] * producto["precio"] for producto in productos] ) saldo = total - adelanto # Generar la boleta archivo_pdf_ok = generar_boleta(id_boleta, cliente, productos, adelanto, saldo) print(archivo_pdf_ok) else: print(f"No se encontraron datos para la boleta con ID {id_boleta}.") # endpoint retorna el pdf de la boleta con idboleta y adelanto @app.get("/boleta/descargarPDF/{id_boleta}/{adelanto}") def descargar_pdf_boleta_get(id_boleta: int, adelanto: float): try: directorio_pdf = "pdf/boleta/" now = datetime.now() formatted_date_time = now.strftime("%Y%m%d%H%M%S") nombre_archivo = f"{directorio_pdf}boleta_{formatted_date_time}.pdf" # crear pdf generar_boleta_desde_bd(id_boleta, adelanto) # validacion si existe el archivo o no y retorna el archivo pdf if os.path.exists(nombre_archivo): # return nombre_archivo return FileResponse( nombre_archivo, media_type="application/pdf", filename=nombre_archivo, ) else: raise HTTPException( status_code=404, detail="No se encontró la boleta solicitada" ) except Exception as e: print(e) return [] # crear endpoint retornando la url del PDF con los datos de la prescripción @app.get("/boleta/verPDF/{id_boleta}/{adelanto}") def ver_pdf_boleta_get(id_boleta: int, adelanto: float): try: directorio_pdf = "pdf/boleta/" formatted_date_time = datetime.now().strftime("%Y%m%d%H%M%S") nombre_archivo = f"{directorio_pdf}boleta_{formatted_date_time}.pdf" generar_boleta_desde_bd(id_boleta, adelanto) if os.path.exists(nombre_archivo): return FileResponse(path=nombre_archivo) else: raise HTTPException( status_code=404, detail="No se encontró la boleta solicitada" ) except Exception as e: print(e) return [] # clase boletaPDF para recibir los datos de la boleta class BoletaPDF(BaseModel): id_boleta: int adelanto: float # ruta para generar boleta en pdf con manejo de errores en caso no se encuentre la boleta @app.post("/boleta/descargarPDF") def descargar_boleta_pdf_post(boleta_pdf: BoletaPDF): try: directorio_pdf = "pdf/boleta/" now = datetime.now() formatted_date_time = now.strftime("%Y%m%d%H%M%S") nombre_archivo = f"{directorio_pdf}boleta_{formatted_date_time}.pdf" # crear pdf generar_boleta_desde_bd(boleta_pdf.id_boleta, boleta_pdf.adelanto) # validacion si existe el archivo o no if os.path.exists(nombre_archivo): return FileResponse( nombre_archivo, media_type="application/pdf", filename=nombre_archivo, ) else: raise HTTPException( status_code=404, detail="No se encontró la boleta solicitada" ) except Exception as e: print(e) return [] # get obtiene la ultima boleta creada @app.get("/boleta/ultima") def get_ultima_boleta(): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT * FROM boleta ORDER BY id_boleta DESC LIMIT 1") boleta = cursor.fetchone() return boleta except Exception as e: print(e) return [] """ CREATE TABLE montura_pedido ( id_montura_pedido INTEGER PRIMARY KEY AUTOINCREMENT, id_montura_inventario INTEGER REFERENCES Montura_inventario(id_montura_inventario), cantidad INTEGER, precio REAL, id_boleta INTEGER REFERENCES boleta(id_boleta) ) """ # get/monturas_pedidos -> obtener todas las monturas_pedidos con with connection as conn, manejo de errores @app.get("/monturas_pedidos") def get_monturas_pedidos(): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT * FROM montura_pedido") monturas_pedidos = cursor.fetchall() return monturas_pedidos except Exception as e: print(e) return [] # get/monturas_pedidos/{id_montura_pedido} -> obtener una montura_pedido por id @app.get("/monturas_pedidos/{id_montura_pedido}") def get_montura_pedido(id_montura_pedido: int): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute( "SELECT * FROM montura_pedido WHERE id_montura_pedido = ?", (id_montura_pedido,), ) montura_pedido = cursor.fetchone() return montura_pedido except Exception as e: print(e) return [] # post/monturas_pedidos -> crear una montura_pedido con una clase pydantic class Montura_pedido(BaseModel): id_montura_inventario: int cantidad: int precio: float id_boleta: int # metodo post de monturas_pedidos con manejo de errores @app.post("/monturas_pedidos") def create_montura_pedido(montura_pedido: Montura_pedido): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute( "INSERT INTO montura_pedido (id_montura_inventario, cantidad, precio, id_boleta) VALUES (?, ?, ?, ?)", ( montura_pedido.id_montura_inventario, montura_pedido.cantidad, montura_pedido.precio, montura_pedido.id_boleta, ), ) conn.commit() return {"mensaje": "Montura_pedido creada exitosamente"} except Exception as e: print(e) return [] # put/monturas_pedidos -> actualizar una montura_pedido con una clase pydantic class Montura_pedidoUpdate(BaseModel): id_montura_pedido: int id_montura_inventario: int cantidad: int precio: float id_boleta: int # metodo put de monturas_pedidos con manejo de errores @app.put("/monturas_pedidos") def update_montura_pedido(montura_pedido: Montura_pedidoUpdate): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute( "UPDATE montura_pedido SET id_montura_inventario = ?, cantidad = ?, precio = ?, id_boleta = ? WHERE id_montura_pedido = ?", ( montura_pedido.id_montura_inventario, montura_pedido.cantidad, montura_pedido.precio, montura_pedido.id_boleta, montura_pedido.id_montura_pedido, ), ) conn.commit() return {"mensaje": "Montura_pedido actualizada exitosamente"} except Exception as e: print(e) return [] # delete/monturas_pedidos -> eliminar una montura_pedido con una clase pydantic class Montura_pedidoDelete(BaseModel): id_montura_pedido: int # metodo delete de monturas_pedidos con manejo de errores @app.delete("/monturas_pedidos") def delete_montura_pedido(montura_pedido: Montura_pedidoDelete): try: with DatabaseConnection().get_connection() as conn: cursor = conn.cursor() cursor.execute( "DELETE FROM montura_pedido WHERE id_montura_pedido = ?", (montura_pedido.id_montura_pedido,), ) conn.commit() return {"mensaje": "Montura_pedido eliminada exitosamente"} except Exception as e: print(e) return []