JairoDanielMT commited on
Commit
64271c7
·
1 Parent(s): cbdd31c

mejoras dividiendo el proyecto en partes

Browse files
.gitignore CHANGED
@@ -8,3 +8,6 @@ test4.py
8
  test5.py
9
  test6.py
10
  .venv
 
 
 
 
8
  test5.py
9
  test6.py
10
  .venv
11
+ # añadimos los archivos que queremos ignorar optica_copia.db optica.db
12
+ optica.db
13
+ optica_copia.db
Optica.session.sql DELETED
@@ -1,4 +0,0 @@
1
- SELECT *
2
- FROM Prescripcion
3
- ORDER BY id_prescripcion DESC
4
- LIMIT 1;
 
 
 
 
 
app.py CHANGED
@@ -1,27 +1,7 @@
1
  # uvicorn app:app --host localhost --port 7860 --reload
2
- # librerias propias del lenguaje
3
- from datetime import datetime
4
- from datetime import date
5
- import os
6
-
7
- # librerias para la API
8
- from pydantic import BaseModel
9
- from fastapi import FastAPI, HTTPException
10
- from fastapi.middleware.cors import CORSMiddleware
11
- from fastapi.responses import FileResponse
12
-
13
- # librerias para el pdf
14
- from reportlab.pdfgen import canvas
15
- from reportlab.lib.pagesizes import letter
16
- from reportlab.pdfbase import pdfmetrics
17
- from reportlab.pdfbase.ttfonts import TTFont
18
- from reportlab.platypus import Table, TableStyle
19
-
20
- # importar librerias para la conexion a la base de datos
21
- from queue import Queue
22
- import sqlite3
23
- import threading
24
-
25
 
26
  app = FastAPI()
27
 
@@ -34,57 +14,25 @@ app.add_middleware(
34
  allow_headers=["*"],
35
  )
36
 
37
-
38
- class DatabaseConnection:
39
- """
40
- Clase para gestionar las conexiones a la base de datos con un pool.
41
- """
42
-
43
- _instance = None
44
- _lock = threading.Lock()
45
- _connection_pool = Queue(maxsize=5)
46
-
47
- def __new__(cls):
48
- """
49
- Crea una nueva instancia de la clase si no existe.
50
- """
51
- with cls._lock:
52
- if cls._instance is None:
53
- cls._instance = super().__new__(cls)
54
- cls._instance.conn = cls._instance._create_connection()
55
- return cls._instance
56
-
57
- def _create_connection(self):
58
- """
59
- Crea una conexión a la base de datos.
60
- """
61
- if not self._connection_pool.empty():
62
- return self._connection_pool.get()
63
- else:
64
- connection = sqlite3.connect("optica_copia.db")
65
- connection.row_factory = sqlite3.Row
66
- return connection
67
-
68
- def get_connection(self):
69
- """
70
- Obtener el objeto de conexión de la base de datos.
71
- """
72
- return self._instance._create_connection()
73
-
74
- def release_connection(self):
75
- """
76
- Liberar la conexión de nuevo al pool.
77
- """
78
- if self._instance is not None:
79
- self._connection_pool.put(self._instance.conn)
80
- self._instance.conn = None # Marcar la instancia como sin conexión
81
-
82
-
83
  # Cargar varias tipografías
84
  pdfmetrics.registerFont(TTFont("Craftcoke", "./font/Craftcoke.ttf"))
85
  pdfmetrics.registerFont(TTFont("Oregon", "./font/Oregon.ttf"))
86
  pdfmetrics.registerFont(TTFont("Roboto", "./font/Roboto.ttf"))
87
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
 
89
  # saludo
90
  @app.get("/")
@@ -92,2151 +40,5 @@ def read_root():
92
  return {"mensaje": "API de la óptica del curso de ADS"}
93
 
94
 
95
- """
96
- CREATE TABLE Roles (
97
- id_rol INTEGER PRIMARY KEY AUTOINCREMENT,
98
- rol VARCHAR
99
- )
100
- """
101
-
102
-
103
- # get/roles -> obtener todos los roles con with connection as conn, manejo de errores
104
- @app.get("/roles")
105
- def get_roles():
106
- try:
107
- with DatabaseConnection().get_connection() as conn:
108
- cursor = conn.cursor()
109
- cursor.execute("SELECT * FROM Roles")
110
- roles = cursor.fetchall()
111
- if roles:
112
- return roles
113
- else:
114
- raise HTTPException(status_code=404, detail="Roles no encontrado")
115
- except Exception as e:
116
- print(e)
117
- return []
118
-
119
-
120
- @app.get("/roles/{id_rol}")
121
- def get_rol(id_rol: int):
122
- try:
123
- with DatabaseConnection().get_connection() as conn:
124
- cursor = conn.cursor()
125
- cursor.execute("SELECT * FROM Roles WHERE id_rol = ?", (id_rol,))
126
- rol = cursor.fetchone()
127
- if rol:
128
- return rol
129
- else:
130
- raise HTTPException(status_code=404, detail="Rol no encontrado")
131
- except Exception as e:
132
- print(e)
133
- return []
134
-
135
-
136
- # clase y metodo post para buscar rol por nombre
137
- class RolNombre(BaseModel):
138
- rol: str
139
-
140
-
141
- @app.post("/roles/busqueda")
142
- def buscar_rol(rol: RolNombre):
143
- try:
144
- with DatabaseConnection().get_connection() as conn:
145
- cursor = conn.cursor()
146
- cursor.execute("SELECT * FROM Roles WHERE rol = ?", (rol.rol,))
147
- rol = cursor.fetchone()
148
- # retornar el rol encontrado o un mensaje de error con HTTPException
149
- if rol:
150
- return rol
151
- else:
152
- raise HTTPException(status_code=404, detail="Rol no encontrado")
153
- except Exception as e:
154
- print(e)
155
- return []
156
-
157
-
158
- # post/roles -> crear un rol con una clase pydantic
159
- class Rol(BaseModel):
160
- rol: str
161
-
162
-
163
- # post/roles -> crear un rol con una clase pydantic
164
- @app.post("/roles")
165
- def create_rol(rol: Rol):
166
- try:
167
- with DatabaseConnection().get_connection() as conn:
168
- cursor = conn.cursor()
169
- cursor.execute("INSERT INTO Roles (rol) VALUES (?)", (rol.rol,))
170
- conn.commit()
171
- return {"mensaje": "Rol creado exitosamente"}
172
- except Exception as e:
173
- print(e)
174
- return []
175
-
176
-
177
- # put/roles -> actualizar un rol con una clase pydantic
178
- class RolUpdate(BaseModel):
179
- id_rol: int
180
- rol: str
181
-
182
-
183
- @app.put("/roles")
184
- def update_rol(rol: RolUpdate):
185
- try:
186
- with DatabaseConnection().get_connection() as conn:
187
- cursor = conn.cursor()
188
- cursor.execute(
189
- "UPDATE Roles SET rol = ? WHERE id_rol = ?", (rol.rol, rol.id_rol)
190
- )
191
- conn.commit()
192
- return {"mensaje": "Rol actualizado exitosamente"}
193
- except Exception as e:
194
- print(e)
195
- return []
196
-
197
-
198
- # delete/roles -> eliminar un rol con una clase pydantic
199
- class RolDelete(BaseModel):
200
- id_rol: int
201
-
202
-
203
- @app.delete("/roles")
204
- def delete_rol(rol: RolDelete):
205
- try:
206
- with DatabaseConnection().get_connection() as conn:
207
- cursor = conn.cursor()
208
- cursor.execute("DELETE FROM Roles WHERE id_rol = ?", (rol.id_rol,))
209
- conn.commit()
210
- return {"mensaje": "Rol eliminado exitosamente"}
211
- except Exception as e:
212
- print(e)
213
- return []
214
-
215
-
216
- """
217
- CREATE TABLE Usuario (
218
- id_usuario INTEGER PRIMARY KEY AUTOINCREMENT,
219
- nombre_usuario VARCHAR,
220
- dni VARCHAR,
221
- clave VARCHAR,
222
- id_rol INTEGER REFERENCES Roles(id_rol),
223
- estado VARCHAR
224
- )
225
- """
226
-
227
-
228
- # get/usuarios -> obtener todos los usuarios con with connection as conn, manejo de errores
229
- @app.get("/usuarios")
230
- def get_usuarios():
231
- try:
232
- with DatabaseConnection().get_connection() as conn:
233
- cursor = conn.cursor()
234
- cursor.execute("SELECT * FROM Usuario")
235
- usuarios = cursor.fetchall()
236
- return usuarios
237
- except Exception as e:
238
- print(e)
239
- return []
240
-
241
-
242
- # get/usuarios/{id_usuario} -> obtener un usuario por id
243
- @app.get("/usuarios/{id_usuario}")
244
- def get_usuario(id_usuario: int):
245
- try:
246
- with DatabaseConnection().get_connection() as conn:
247
- cursor = conn.cursor()
248
- cursor.execute("SELECT * FROM Usuario WHERE id_usuario = ?", (id_usuario,))
249
- usuario = cursor.fetchone()
250
- return usuario
251
- except Exception as e:
252
- print(e)
253
- return []
254
-
255
-
256
- # metodo de busqueda de usuario por nombre con like, manejo de errores y clase pydantic
257
- class UsuarioNombre(BaseModel):
258
- nombre_usuario: str
259
-
260
-
261
- # post/usuarios/busqueda -> buscar usuario por nombre con like
262
- @app.post("/usuarios/busqueda")
263
- def buscar_usuario(usuario: UsuarioNombre):
264
- try:
265
- with DatabaseConnection().get_connection() as conn:
266
- cursor = conn.cursor()
267
- cursor.execute(
268
- "SELECT * FROM Usuario WHERE nombre_usuario LIKE ?",
269
- ["%" + usuario.nombre_usuario + "%"],
270
- )
271
- usuario = cursor.fetchall()
272
- if usuario:
273
- return usuario
274
- else:
275
- raise HTTPException(status_code=404, detail="Usuario no encontrado")
276
- except Exception as e:
277
- print(e)
278
- return []
279
-
280
-
281
- # post/usuarios -> crear un usuario con una clase pydantic
282
- class Usuario(BaseModel):
283
- nombre_usuario: str
284
- dni: str
285
- clave: str
286
- id_rol: int
287
- estado: str
288
-
289
-
290
- @app.post("/usuarios")
291
- def create_usuario(usuario: Usuario):
292
- try:
293
- with DatabaseConnection().get_connection() as conn:
294
- cursor = conn.cursor()
295
- cursor.execute(
296
- "INSERT INTO Usuario (nombre_usuario, dni, clave, id_rol, estado) VALUES (?, ?, ?, ?, ?)",
297
- (
298
- usuario.nombre_usuario,
299
- usuario.dni,
300
- usuario.clave,
301
- usuario.id_rol,
302
- usuario.estado,
303
- ),
304
- )
305
- conn.commit()
306
- return {"mensaje": "Usuario creado exitosamente"}
307
- except Exception as e:
308
- print(e)
309
- return []
310
-
311
-
312
- # put/usuarios -> actualizar un usuario con una clase pydantic
313
- class UsuarioUpdate(BaseModel):
314
- id_usuario: int
315
- nombre_usuario: str
316
- dni: str
317
- clave: str
318
- id_rol: int
319
- estado: str
320
-
321
-
322
- @app.put("/usuarios")
323
- def update_usuario(usuario: UsuarioUpdate):
324
- try:
325
- with DatabaseConnection().get_connection() as conn:
326
- cursor = conn.cursor()
327
- cursor.execute(
328
- "UPDATE Usuario SET nombre_usuario = ?, dni = ?, clave = ?, id_rol = ?, estado = ? WHERE id_usuario = ?",
329
- (
330
- usuario.nombre_usuario,
331
- usuario.dni,
332
- usuario.clave,
333
- usuario.id_rol,
334
- usuario.estado,
335
- usuario.id_usuario,
336
- ),
337
- )
338
- conn.commit()
339
- return {"mensaje": "Usuario actualizado exitosamente"}
340
- except Exception as e:
341
- print(e)
342
- return []
343
-
344
-
345
- # delete/usuarios -> eliminar un usuario con una clase pydantic
346
- class UsuarioDelete(BaseModel):
347
- id_usuario: int
348
-
349
-
350
- @app.delete("/usuarios")
351
- def delete_usuario(usuario: UsuarioDelete):
352
- try:
353
- with DatabaseConnection().get_connection() as conn:
354
- cursor = conn.cursor()
355
- cursor.execute(
356
- "DELETE FROM Usuario WHERE id_usuario = ?", (usuario.id_usuario,)
357
- )
358
- conn.commit()
359
- return {"mensaje": "Usuario eliminado exitosamente"}
360
- except Exception as e:
361
- print(e)
362
- return []
363
-
364
-
365
- """
366
- CREATE TABLE Cliente (
367
- id_cliente INTEGER PRIMARY KEY AUTOINCREMENT,
368
- nombres_y_apellidos VARCHAR,
369
- edad INTEGER,
370
- telefono INTEGER,
371
- direccion VARCHAR
372
- )
373
- """
374
-
375
-
376
- # get/clientes -> obtener todos los clientes con with connection as conn, manejo de errores
377
- @app.get("/clientes")
378
- def get_clientes():
379
- try:
380
- with DatabaseConnection().get_connection() as conn:
381
- cursor = conn.cursor()
382
- cursor.execute("SELECT * FROM Cliente")
383
- clientes = cursor.fetchall()
384
- return clientes
385
- except Exception as e:
386
- print(e)
387
- return []
388
-
389
-
390
- @app.get("/clientes/{id_cliente}")
391
- def get_cliente(id_cliente: int):
392
- try:
393
- with DatabaseConnection().get_connection() as conn:
394
- cursor = conn.cursor()
395
- cursor.execute("SELECT * FROM Cliente WHERE id_cliente = ?", (id_cliente,))
396
- cliente = cursor.fetchone()
397
- return cliente
398
- except Exception as e:
399
- print(e)
400
- return []
401
-
402
-
403
- # metodo de busqueda de cliente por nombre con like, manejo de errores y clase pydantic
404
- class ClienteNombre(BaseModel):
405
- nombres_y_apellidos: str
406
-
407
-
408
- @app.post("/clientes/busqueda")
409
- def post_cliente_busqueda(cliente: ClienteNombre):
410
- try:
411
- conn = DatabaseConnection().get_connection()
412
- cursor = conn.cursor()
413
- cursor.execute(
414
- "SELECT * FROM Cliente WHERE nombres_y_apellidos LIKE ?",
415
- ["%" + cliente.nombres_y_apellidos + "%"],
416
- )
417
- cliente = cursor.fetchall()
418
- if cliente:
419
- return cliente
420
- else:
421
- raise HTTPException(status_code=404, detail="Cliente no encontrado")
422
- except Exception as e:
423
- print(e)
424
- return []
425
-
426
-
427
- # post/clientes -> crear un cliente con una clase pydantic
428
- class Cliente(BaseModel):
429
- nombres_y_apellidos: str
430
- edad: int
431
- telefono: int
432
- direccion: str
433
-
434
-
435
- @app.post("/clientes")
436
- def create_cliente(cliente: Cliente):
437
- try:
438
- with DatabaseConnection().get_connection() as conn:
439
- cursor = conn.cursor()
440
- cursor.execute(
441
- "INSERT INTO Cliente (nombres_y_apellidos, edad, telefono, direccion) VALUES (?, ?, ?, ?)",
442
- (
443
- cliente.nombres_y_apellidos,
444
- cliente.edad,
445
- cliente.telefono,
446
- cliente.direccion,
447
- ),
448
- )
449
- conn.commit()
450
- return {"mensaje": "Cliente creado exitosamente"}
451
- except Exception as e:
452
- print(e)
453
- return []
454
-
455
-
456
- # put/clientes -> actualizar un cliente con una clase pydantic
457
- class ClienteUpdate(BaseModel):
458
- id_cliente: int
459
- nombres_y_apellidos: str
460
- edad: int
461
- telefono: int
462
- direccion: str
463
-
464
-
465
- @app.put("/clientes")
466
- def update_cliente(cliente: ClienteUpdate):
467
- try:
468
- with DatabaseConnection().get_connection() as conn:
469
- cursor = conn.cursor()
470
- cursor.execute(
471
- "UPDATE Cliente SET nombres_y_apellidos = ?, edad = ?, telefono = ?, direccion = ? WHERE id_cliente = ?",
472
- (
473
- cliente.nombres_y_apellidos,
474
- cliente.edad,
475
- cliente.telefono,
476
- cliente.direccion,
477
- cliente.id_cliente,
478
- ),
479
- )
480
- conn.commit()
481
- return {"mensaje": "Cliente actualizado exitosamente"}
482
- except Exception as e:
483
- print(e)
484
- return []
485
-
486
-
487
- # delete/clientes -> eliminar un cliente con una clase pydantic
488
- class ClienteDelete(BaseModel):
489
- id_cliente: int
490
-
491
-
492
- # delete/clientes -> eliminar un cliente con una clase pydantic
493
- @app.delete("/clientes")
494
- def delete_cliente(cliente: ClienteDelete):
495
- try:
496
- with DatabaseConnection().get_connection() as conn:
497
- cursor = conn.cursor()
498
- cursor.execute(
499
- "DELETE FROM Cliente WHERE id_cliente = ?", (cliente.id_cliente,)
500
- )
501
- conn.commit()
502
- return {"mensaje": "Cliente eliminado exitosamente"}
503
- except Exception as e:
504
- print(e)
505
- return []
506
-
507
-
508
- # Define tu clase Pydantic para el modelo de datos
509
- class PrescripcionId(BaseModel):
510
- id_prescripcion: int
511
-
512
-
513
- # Define tu método de búsqueda de cliente por id de prescripción con manejo de errores y clase Pydantic
514
- @app.post("/clientes/prescripcion")
515
- def get_cliente_por_prescripcion(prescripcion_id: PrescripcionId):
516
- try:
517
- with DatabaseConnection().get_connection() as conn:
518
- cursor = conn.cursor()
519
- # Consulta SQL para obtener el cliente a partir del id de la prescripción
520
- cursor.execute(
521
- """
522
- SELECT c.*
523
- FROM Cliente c
524
- JOIN Medidas m ON c.id_cliente = m.id_cliente
525
- JOIN Prescripcion p ON m.id_medidas = p.id_medidas
526
- WHERE p.id_prescripcion = ?
527
- """,
528
- [prescripcion_id.id_prescripcion],
529
- )
530
-
531
- cliente = cursor.fetchone()
532
-
533
- if cliente:
534
- return cliente
535
- else:
536
- raise HTTPException(
537
- status_code=404,
538
- detail="Cliente no encontrado para la prescripción proporcionada",
539
- )
540
-
541
- except Exception as e:
542
- print(e)
543
- return []
544
-
545
-
546
- """
547
- CREATE TABLE Medidas (
548
- id_medidas INTEGER PRIMARY KEY AUTOINCREMENT,
549
- Esfera_OD_lejos REAL,
550
- Cilindro_OD_lejos REAL,
551
- Eje_OD_lejos REAL,
552
- Agudeza_visual_OD_lejos REAL,
553
- Esfera_OI_lejos REAL,
554
- Cilindro_OI_lejos REAL,
555
- Eje_OI_lejos REAL,
556
- Agudeza_visual_OI_lejos REAL,
557
- Esfera_OD_cerca REAL,
558
- Cilindro_OD_cerca REAL,
559
- Eje_OD_cerca REAL,
560
- Agudeza_visual_OD_cerca REAL,
561
- Esfera_OI_cerca REAL,
562
- Cilindro_OI_cerca REAL,
563
- Eje_OI_cerca REAL,
564
- Agudeza_visual_OI_cerca REAL,
565
- id_cliente INTEGER REFERENCES Cliente(id_cliente)
566
- )
567
- """
568
-
569
-
570
- # get/medidas -> obtener todas las medidas con with connection as conn, manejo de errores
571
- @app.get("/medidas")
572
- def get_medidas():
573
- try:
574
- with DatabaseConnection().get_connection() as conn:
575
- cursor = conn.cursor()
576
- cursor.execute("SELECT * FROM Medidas")
577
- medidas = cursor.fetchall()
578
- return medidas
579
- except Exception as e:
580
- print(e)
581
- return []
582
-
583
-
584
- # get/medidas/{id_medidas} -> obtener una medida por id
585
- @app.get("/medidas/{id_medidas}")
586
- def get_medida(id_medidas: int):
587
- try:
588
- with DatabaseConnection().get_connection() as conn:
589
- cursor = conn.cursor()
590
- cursor.execute("SELECT * FROM Medidas WHERE id_medidas = ?", (id_medidas,))
591
- medida = cursor.fetchone()
592
- return medida
593
- except Exception as e:
594
- print(e)
595
- return []
596
-
597
-
598
- # metodo de busqueda que sea por id_cliente y retorne las medidas asociadas a ese cliente con clase y metodo post
599
- class MedidasCliente(BaseModel):
600
- id_cliente: int
601
-
602
-
603
- @app.post("/medidas/busqueda")
604
- def buscar_medida(medida: MedidasCliente):
605
- try:
606
- with DatabaseConnection().get_connection() as conn:
607
- cursor = conn.cursor()
608
- cursor.execute(
609
- "SELECT * FROM Medidas WHERE id_cliente = ?",
610
- (medida.id_cliente,),
611
- )
612
- medida = cursor.fetchall()
613
- if medida:
614
- return medida
615
- else:
616
- raise HTTPException(status_code=404, detail="Medida no encontrada")
617
- except Exception as e:
618
- print(e)
619
- return []
620
-
621
-
622
- # post/medidas -> crear una medida con una clase pydantic
623
- class Medida(BaseModel):
624
- Esfera_OD_lejos: float
625
- Cilindro_OD_lejos: float
626
- Eje_OD_lejos: float
627
- Agudeza_visual_OD_lejos: float
628
- Esfera_OI_lejos: float
629
- Cilindro_OI_lejos: float
630
- Eje_OI_lejos: float
631
- Agudeza_visual_OI_lejos: float
632
- Esfera_OD_cerca: float
633
- Cilindro_OD_cerca: float
634
- Eje_OD_cerca: float
635
- Agudeza_visual_OD_cerca: float
636
- Esfera_OI_cerca: float
637
- Cilindro_OI_cerca: float
638
- Eje_OI_cerca: float
639
- Agudeza_visual_OI_cerca: float
640
- id_cliente: int
641
-
642
-
643
- @app.post("/medidas")
644
- def create_medida(medida: Medida):
645
- try:
646
- with DatabaseConnection().get_connection() as conn:
647
- cursor = conn.cursor()
648
- cursor.execute(
649
- "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 (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
650
- [
651
- medida.Esfera_OD_lejos,
652
- medida.Cilindro_OD_lejos,
653
- medida.Eje_OD_lejos,
654
- medida.Agudeza_visual_OD_lejos,
655
- medida.Esfera_OI_lejos,
656
- medida.Cilindro_OI_lejos,
657
- medida.Eje_OI_lejos,
658
- medida.Agudeza_visual_OI_lejos,
659
- medida.Esfera_OD_cerca,
660
- medida.Cilindro_OD_cerca,
661
- medida.Eje_OD_cerca,
662
- medida.Agudeza_visual_OD_cerca,
663
- medida.Esfera_OI_cerca,
664
- medida.Cilindro_OI_cerca,
665
- medida.Eje_OI_cerca,
666
- medida.Agudeza_visual_OI_cerca,
667
- medida.id_cliente,
668
- ],
669
- )
670
- conn.commit()
671
- return {"mensaje": "Medida creada correctamente"}
672
- except Exception as e:
673
- print(e)
674
- return []
675
-
676
-
677
- # put/medidas -> actualizar una medida con una clase pydantic
678
- class MedidaUpdate(BaseModel):
679
- id_medidas: int
680
- Esfera_OD_lejos: float
681
- Cilindro_OD_lejos: float
682
- Eje_OD_lejos: float
683
- Agudeza_visual_OD_lejos: float
684
- Esfera_OI_lejos: float
685
- Cilindro_OI_lejos: float
686
- Eje_OI_lejos: float
687
- Agudeza_visual_OI_lejos: float
688
- Esfera_OD_cerca: float
689
- Cilindro_OD_cerca: float
690
- Eje_OD_cerca: float
691
- Agudeza_visual_OD_cerca: float
692
- Esfera_OI_cerca: float
693
- Cilindro_OI_cerca: float
694
- Eje_OI_cerca: float
695
- Agudeza_visual_OI_cerca: float
696
- id_cliente: int
697
-
698
-
699
- # metodo put de medidas con manejo de errores
700
- @app.put("/medidas")
701
- def update_medida(medida: MedidaUpdate):
702
- try:
703
- with DatabaseConnection().get_connection() as conn:
704
- cursor = conn.cursor()
705
- cursor.execute(
706
- "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 = ?",
707
- [
708
- medida.Esfera_OD_lejos,
709
- medida.Cilindro_OD_lejos,
710
- medida.Eje_OD_lejos,
711
- medida.Agudeza_visual_OD_lejos,
712
- medida.Esfera_OI_lejos,
713
- medida.Cilindro_OI_lejos,
714
- medida.Eje_OI_lejos,
715
- medida.Agudeza_visual_OI_lejos,
716
- medida.Esfera_OD_cerca,
717
- medida.Cilindro_OD_cerca,
718
- medida.Eje_OD_cerca,
719
- medida.Agudeza_visual_OD_cerca,
720
- medida.Esfera_OI_cerca,
721
- medida.Cilindro_OI_cerca,
722
- medida.Eje_OI_cerca,
723
- medida.Agudeza_visual_OI_cerca,
724
- medida.id_cliente,
725
- medida.id_medidas,
726
- ],
727
- )
728
- conn.commit()
729
- return {"mensaje": "Medida actualizada correctamente"}
730
- except Exception as e:
731
- print(e)
732
- return []
733
-
734
-
735
- # delete/medidas -> eliminar una medida con una clase pydantic
736
- class MedidaDelete(BaseModel):
737
- id_medidas: int
738
-
739
-
740
- # metodo delete de medidas con manejo de errores
741
- @app.delete("/medidas")
742
- def delete_medida(medida: MedidaDelete):
743
- try:
744
- with DatabaseConnection().get_connection() as conn:
745
- cursor = conn.cursor()
746
- cursor.execute(
747
- "DELETE FROM Medidas WHERE id_medidas = ?", (medida.id_medidas,)
748
- )
749
- conn.commit()
750
- return {"mensaje": "Medida eliminada exitosamente"}
751
- except Exception as e:
752
- print(e)
753
- return []
754
-
755
-
756
- """
757
- CREATE TABLE Prescripcion (
758
- id_prescripcion INTEGER PRIMARY KEY AUTOINCREMENT,
759
- id_medidas INTEGER REFERENCES Medidas(id_medidas),
760
- detalle_lunas VARCHAR,
761
- fecha VARCHAR
762
-
763
- )
764
- """
765
-
766
-
767
- # get/prescripciones -> obtener todas las prescripciones con with connection as conn, manejo de errores
768
- @app.get("/prescripciones")
769
- def get_prescripciones():
770
- try:
771
- with DatabaseConnection().get_connection() as conn:
772
- cursor = conn.cursor()
773
- cursor.execute("SELECT * FROM Prescripcion")
774
- prescripciones = cursor.fetchall()
775
- return prescripciones
776
- except Exception as e:
777
- print(e)
778
- return []
779
-
780
-
781
- @app.get("/prescripciones/ultimoregistro")
782
- def get_prescripciones():
783
- try:
784
- with DatabaseConnection().get_connection() as conn:
785
- cursor = conn.cursor()
786
- cursor.execute(
787
- "SELECT * FROM Prescripcion ORDER BY id_prescripcion DESC LIMIT 1;"
788
- )
789
- prescripciones = cursor.fetchall()
790
- return prescripciones
791
- except Exception as e:
792
- print(e)
793
- return []
794
-
795
-
796
- # get/prescripciones/{id_prescripcion} -> obtener una prescripcion por id
797
- @app.get("/prescripciones/{id_prescripcion}")
798
- def get_prescripcion(id_prescripcion: int):
799
- try:
800
- with DatabaseConnection().get_connection() as conn:
801
- cursor = conn.cursor()
802
- cursor.execute(
803
- "SELECT * FROM Prescripcion WHERE id_prescripcion = ?",
804
- (id_prescripcion,),
805
- )
806
- prescripcion = cursor.fetchone()
807
- return prescripcion
808
- except Exception as e:
809
- print(e)
810
- return []
811
-
812
-
813
- class Prescripcion(BaseModel):
814
- id_medidas: int
815
- detalle_lunas: str
816
- fecha: str
817
-
818
-
819
- # post prescripcion con pydantic con retorna la todos los datos de la prescripcion
820
- @app.post("/prescripcion/ultimoRegistro")
821
- def post_prescripcion(prescripcion: Prescripcion):
822
- try:
823
- with DatabaseConnection().get_connection() as conn:
824
- cursor = conn.cursor()
825
- cursor.execute(
826
- "INSERT INTO Prescripcion (id_medidas, detalle_lunas, fecha) VALUES (?, ?, ?)",
827
- (
828
- prescripcion.id_medidas,
829
- prescripcion.detalle_lunas,
830
- prescripcion.fecha,
831
- ),
832
- )
833
- conn.commit()
834
- cursor.execute(
835
- "SELECT * FROM Prescripcion ORDER BY id_prescripcion DESC LIMIT 1;"
836
- )
837
- prescripciones = cursor.fetchall()
838
- return prescripciones
839
- except Exception as e:
840
- print(e)
841
- return []
842
-
843
-
844
- # metodo post de prescripciones con manejo de errores
845
- @app.post("/prescripciones")
846
- def create_prescripcion(prescripcion: Prescripcion):
847
- try:
848
- with DatabaseConnection().get_connection() as conn:
849
- cursor = conn.cursor()
850
- cursor.execute(
851
- "INSERT INTO Prescripcion (id_medidas, detalle_lunas, fecha) VALUES (?, ?, ?)",
852
- (
853
- prescripcion.id_medidas,
854
- prescripcion.detalle_lunas,
855
- prescripcion.fecha,
856
- ),
857
- )
858
- conn.commit()
859
- return {"mensaje": "Prescripcion creada exitosamente"}
860
- except Exception as e:
861
- print(e)
862
- return []
863
-
864
-
865
- # put/prescripciones -> actualizar una prescripcion con una clase pydantic
866
- class PrescripcionUpdate(BaseModel):
867
- id_prescripcion: int
868
- id_medidas: int
869
- detalle_lunas: str
870
- fecha: str
871
-
872
-
873
- # metodo put de prescripciones con manejo de errores
874
- @app.put("/prescripciones")
875
- def update_prescripcion(prescripcion: PrescripcionUpdate):
876
- try:
877
- with DatabaseConnection().get_connection() as conn:
878
- cursor = conn.cursor()
879
- cursor.execute(
880
- "UPDATE Prescripcion SET id_medidas = ?, detalle_lunas = ?, fecha = ? WHERE id_prescripcion = ?",
881
- (
882
- prescripcion.id_medidas,
883
- prescripcion.detalle_lunas,
884
- prescripcion.fecha,
885
- prescripcion.id_prescripcion,
886
- ),
887
- )
888
- conn.commit()
889
- return {"mensaje": "Prescripcion actualizada exitosamente"}
890
- except Exception as e:
891
- print(e)
892
- return []
893
-
894
-
895
- # delete/prescripciones -> eliminar una prescripcion con una clase pydantic
896
- class PrescripcionDelete(BaseModel):
897
- id_prescripcion: int
898
-
899
-
900
- # metodo delete de prescripciones con manejo de errores
901
- @app.delete("/prescripciones")
902
- def delete_prescripcion(prescripcion: PrescripcionDelete):
903
- try:
904
- with DatabaseConnection().get_connection() as conn:
905
- cursor = conn.cursor()
906
- cursor.execute(
907
- "DELETE FROM Prescripcion WHERE id_prescripcion = ?",
908
- (prescripcion.id_prescripcion,),
909
- )
910
- conn.commit()
911
- return {"mensaje": "Prescripcion eliminada exitosamente"}
912
- except Exception as e:
913
- print(e)
914
- return []
915
-
916
-
917
- def obtener_datos_prescripcion(id_prescripcion):
918
- try:
919
- conn = DatabaseConnection().get_connection()
920
- cursor = conn.cursor()
921
- query = """
922
- SELECT
923
- P.id_prescripcion,
924
- P.fecha AS fecha_prescripcion,
925
- P.detalle_lunas,
926
- Me.Esfera_OD_lejos,
927
- Me.Cilindro_OD_lejos,
928
- Me.Eje_OD_lejos,
929
- Me.Agudeza_visual_OD_lejos,
930
- Me.Esfera_OI_lejos,
931
- Me.Cilindro_OI_lejos,
932
- Me.Eje_OI_lejos,
933
- Me.Agudeza_visual_OI_lejos,
934
- Me.Esfera_OD_cerca,
935
- Me.Cilindro_OD_cerca,
936
- Me.Eje_OD_cerca,
937
- Me.Agudeza_visual_OD_cerca,
938
- Me.Esfera_OI_cerca,
939
- Me.Cilindro_OI_cerca,
940
- Me.Eje_OI_cerca,
941
- Me.Agudeza_visual_OI_cerca,
942
- C.id_cliente,
943
- C.nombres_y_apellidos,
944
- C.edad,
945
- C.telefono,
946
- C.direccion
947
- FROM
948
- Prescripcion AS P
949
- JOIN
950
- Medidas AS Me ON P.id_medidas = Me.id_medidas
951
- JOIN
952
- Cliente AS C ON Me.id_cliente = C.id_cliente
953
- WHERE
954
- P.id_prescripcion = ?;
955
- """
956
- cursor.execute(query, (id_prescripcion,))
957
- resultado = cursor.fetchone()
958
- return resultado
959
- except Exception as e:
960
- print(e)
961
- return []
962
-
963
-
964
- # crear endpoint para obtener los datos de la prescripción
965
- @app.get("/prescripcion/{id_prescripcion}")
966
- def obtener_datos_prescripcion_api(id_prescripcion: int):
967
- datos_prescripcion = obtener_datos_prescripcion(id_prescripcion)
968
- if datos_prescripcion:
969
- # Crear un objeto de la clase DatosPrescripcion
970
- obj_datos_prescripcion = DatosPrescripcion(*datos_prescripcion)
971
- return obj_datos_prescripcion
972
- else:
973
- raise HTTPException(status_code=404, detail="Prescripción no encontrada")
974
-
975
-
976
- class DatosPrescripcion:
977
- def __init__(
978
- self,
979
- id_prescripcion,
980
- fecha_prescripcion,
981
- detalle_lunas,
982
- esfera_od_lejos,
983
- cilindro_od_lejos,
984
- eje_od_lejos,
985
- agudeza_visual_od_lejos,
986
- esfera_oi_lejos,
987
- cilindro_oi_lejos,
988
- eje_oi_lejos,
989
- agudeza_visual_oi_lejos,
990
- esfera_od_cerca,
991
- cilindro_od_cerca,
992
- eje_od_cerca,
993
- agudeza_visual_od_cerca,
994
- esfera_oi_cerca,
995
- cilindro_oi_cerca,
996
- eje_oi_cerca,
997
- agudeza_visual_oi_cerca,
998
- id_cliente,
999
- nombres_y_apellidos,
1000
- edad,
1001
- telefono,
1002
- direccion,
1003
- ):
1004
- """
1005
- Clase que representa los datos de una prescripción.
1006
-
1007
- Args:
1008
- id_prescripcion (int): El ID de la prescripción.
1009
- fecha_prescripcion (str): La fecha de la prescripción.
1010
- detalle_lunas (str): Los detalles de las lentes.
1011
- esfera_od_lejos (float): El valor de la esfera para el ojo derecho en visión lejana.
1012
- cilindro_od_lejos (float): El valor del cilindro para el ojo derecho en visión lejana.
1013
- eje_od_lejos (int): El valor del eje para el ojo derecho en visión lejana.
1014
- agudeza_visual_od_lejos (str): La agudeza visual para el ojo derecho en visión lejana.
1015
- esfera_oi_lejos (float): El valor de la esfera para el ojo izquierdo en visión lejana.
1016
- cilindro_oi_lejos (float): El valor del cilindro para el ojo izquierdo en visión lejana.
1017
- eje_oi_lejos (int): El valor del eje para el ojo izquierdo en visión lejana.
1018
- agudeza_visual_oi_lejos (str): La agudeza visual para el ojo izquierdo en visión lejana.
1019
- esfera_od_cerca (float): El valor de la esfera para el ojo derecho en visión cercana.
1020
- cilindro_od_cerca (float): El valor del cilindro para el ojo derecho en visión cercana.
1021
- eje_od_cerca (int): El valor del eje para el ojo derecho en visión cercana.
1022
- agudeza_visual_od_cerca (str): La agudeza visual para el ojo derecho en visión cercana.
1023
- esfera_oi_cerca (float): El valor de la esfera para el ojo izquierdo en visión cercana.
1024
- cilindro_oi_cerca (float): El valor del cilindro para el ojo izquierdo en visión cercana.
1025
- eje_oi_cerca (int): El valor del eje para el ojo izquierdo en visión cercana.
1026
- agudeza_visual_oi_cerca (str): La agudeza visual para el ojo izquierdo en visión cercana.
1027
- id_cliente (int): El ID del cliente.
1028
- nombres_y_apellidos (str): Los nombres y apellidos del cliente.
1029
- edad (int): La edad del cliente.
1030
- telefono (str): El número de teléfono del cliente.
1031
- direccion (str): La dirección del cliente.
1032
- """
1033
- self.id_prescripcion = id_prescripcion
1034
- self.fecha_prescripcion = fecha_prescripcion
1035
- self.detalle_lunas = detalle_lunas
1036
- self.esfera_od_lejos = esfera_od_lejos
1037
- self.cilindro_od_lejos = cilindro_od_lejos
1038
- self.eje_od_lejos = eje_od_lejos
1039
- self.agudeza_visual_od_lejos = agudeza_visual_od_lejos
1040
- self.esfera_oi_lejos = esfera_oi_lejos
1041
- self.cilindro_oi_lejos = cilindro_oi_lejos
1042
- self.eje_oi_lejos = eje_oi_lejos
1043
- self.agudeza_visual_oi_lejos = agudeza_visual_oi_lejos
1044
- self.esfera_od_cerca = esfera_od_cerca
1045
- self.cilindro_od_cerca = cilindro_od_cerca
1046
- self.eje_od_cerca = eje_od_cerca
1047
- self.agudeza_visual_od_cerca = agudeza_visual_od_cerca
1048
- self.esfera_oi_cerca = esfera_oi_cerca
1049
- self.cilindro_oi_cerca = cilindro_oi_cerca
1050
- self.eje_oi_cerca = eje_oi_cerca
1051
- self.agudeza_visual_oi_cerca = agudeza_visual_oi_cerca
1052
- self.id_cliente = id_cliente
1053
- self.nombres_y_apellidos_cliente = nombres_y_apellidos
1054
- self.edad_cliente = edad
1055
- self.telefono_cliente = telefono
1056
- self.direccion_cliente = direccion
1057
-
1058
- def generar_pdf(self, filename):
1059
- """
1060
- Genera un archivo PDF con los datos de la prescripción.
1061
-
1062
- Args:
1063
- filename (str): El nombre del archivo PDF a generar.
1064
- """
1065
- pdf = canvas.Canvas(filename)
1066
- pdf.setFont("Oregon", 12)
1067
- ubicacion_inicio = 780 # Posición inicial en y
1068
- pdf.drawCentredString(
1069
- 300, ubicacion_inicio, "OPTICA ARTE VISUAL - PRESCRIPCIÓN"
1070
- )
1071
- pdf.drawString(
1072
- 100,
1073
- ubicacion_inicio - 40,
1074
- f"Nombre del Cliente: {self.nombres_y_apellidos_cliente}",
1075
- )
1076
- pdf.drawString(
1077
- 100, ubicacion_inicio - 60, f"Datos del cliente: {self.direccion_cliente}"
1078
- )
1079
- pdf.drawString(
1080
- 100, ubicacion_inicio - 80, f"Número telefónico: {self.telefono_cliente}"
1081
- )
1082
- pdf.drawString(
1083
- 100,
1084
- ubicacion_inicio - 100,
1085
- f"Código de prescripción: {self.id_prescripcion}",
1086
- )
1087
- pdf.drawString(100, ubicacion_inicio - 120, f"Fecha: {self.fecha_prescripcion}")
1088
- pdf.drawString(
1089
- 100, ubicacion_inicio - 140, f"Descripción: {self.detalle_lunas}"
1090
- )
1091
- ubicacion_esfera = 150 # Posición inicial en x
1092
- ubicacion_cilindro = ubicacion_esfera + 65 # Posición inicial en x + 65
1093
- ubicacion_eje = ubicacion_cilindro + 75 # Posición anterior en x + 75
1094
- ubicacion_agudeza = ubicacion_eje + 70 # Posición anterior en x + 70
1095
- tabla_medidas = ubicacion_inicio - 170 # Posición inicial en y
1096
-
1097
- pdf.drawString(ubicacion_esfera - 50, tabla_medidas, "Tabla de medidas:")
1098
- # Para el ojo izquierdo de lejos
1099
- pdf.drawString(
1100
- ubicacion_esfera + 100, tabla_medidas - 20, "Ojo izquierdo de lejos"
1101
- )
1102
- pdf.line(
1103
- x1=ubicacion_esfera,
1104
- y1=tabla_medidas - 25,
1105
- x2=ubicacion_esfera + 300,
1106
- y2=tabla_medidas - 25,
1107
- )
1108
- pdf.drawString(ubicacion_esfera, tabla_medidas - 40, "Esfera")
1109
- pdf.drawString(ubicacion_cilindro, tabla_medidas - 40, "Cilindro")
1110
- pdf.drawString(ubicacion_eje, tabla_medidas - 40, "Eje")
1111
- pdf.drawString(ubicacion_agudeza, tabla_medidas - 40, "Agudeza visual")
1112
- pdf.drawString(ubicacion_esfera, tabla_medidas - 60, f"{self.esfera_oi_lejos}")
1113
- pdf.drawString(
1114
- ubicacion_cilindro, tabla_medidas - 60, f"{self.cilindro_oi_lejos}"
1115
- )
1116
- pdf.drawString(ubicacion_eje, tabla_medidas - 60, f"{self.eje_oi_lejos}")
1117
- pdf.drawString(
1118
- ubicacion_agudeza, tabla_medidas - 60, f"{self.agudeza_visual_oi_lejos}"
1119
- )
1120
- # Para el ojo derecho de lejos
1121
- odl = tabla_medidas - 100 # Posición inicial en y
1122
- pdf.drawString(ubicacion_esfera + 100, odl, "Ojo derecho de lejos")
1123
- pdf.line(x1=ubicacion_esfera, y1=odl - 5, x2=ubicacion_esfera + 300, y2=odl - 5)
1124
- pdf.drawString(ubicacion_esfera, odl - 20, "Esfera")
1125
- pdf.drawString(ubicacion_cilindro, odl - 20, "Cilindro")
1126
- pdf.drawString(ubicacion_eje, odl - 20, "Eje")
1127
- pdf.drawString(ubicacion_agudeza, odl - 20, "Agudeza visual")
1128
- pdf.drawString(ubicacion_esfera, odl - 40, f"{self.esfera_od_lejos}")
1129
- pdf.drawString(ubicacion_cilindro, odl - 40, f"{self.cilindro_od_lejos}")
1130
- pdf.drawString(ubicacion_eje, odl - 40, f"{self.eje_od_lejos}")
1131
- pdf.drawString(ubicacion_agudeza, odl - 40, f"{self.agudeza_visual_od_lejos}")
1132
-
1133
- oic = odl - 80 # Posición inicial en y
1134
- pdf.drawString(ubicacion_esfera + 100, oic, "Ojo izquierdo de cerca")
1135
- pdf.line(x1=ubicacion_esfera, y1=oic - 5, x2=ubicacion_esfera + 300, y2=oic - 5)
1136
- # Para el ojo izquierdo de cerca
1137
- pdf.drawString(ubicacion_esfera, oic - 20, "Esfera")
1138
- pdf.drawString(ubicacion_cilindro, oic - 20, "Cilindro")
1139
- pdf.drawString(ubicacion_eje, oic - 20, "Eje")
1140
- pdf.drawString(ubicacion_agudeza, oic - 20, "Agudeza visual")
1141
- pdf.drawString(ubicacion_esfera, oic - 40, f"{self.esfera_oi_cerca}")
1142
- pdf.drawString(ubicacion_cilindro, oic - 40, f"{self.cilindro_oi_cerca}")
1143
- pdf.drawString(ubicacion_eje, oic - 40, f"{self.eje_oi_cerca}")
1144
- pdf.drawString(ubicacion_agudeza, oic - 40, f"{self.agudeza_visual_oi_cerca}")
1145
- odc = oic - 80
1146
- pdf.drawString(ubicacion_esfera + 100, odc, "Ojo derecho de cerca")
1147
- pdf.line(x1=ubicacion_esfera, y1=odc - 5, x2=ubicacion_esfera + 300, y2=odc - 5)
1148
- # Para el ojo derecho de cerca
1149
- pdf.drawString(ubicacion_esfera, odc - 20, "Esfera")
1150
- pdf.drawString(ubicacion_cilindro, odc - 20, "Cilindro")
1151
- pdf.drawString(ubicacion_eje, odc - 20, "Eje")
1152
- pdf.drawString(ubicacion_agudeza, odc - 20, "Agudeza visual")
1153
- pdf.drawString(ubicacion_esfera, odc - 40, f"{self.esfera_od_cerca}")
1154
- pdf.drawString(ubicacion_cilindro, odc - 40, f"{self.cilindro_od_cerca}")
1155
- pdf.drawString(ubicacion_eje, odc - 40, f"{self.eje_od_cerca}")
1156
- pdf.drawString(ubicacion_agudeza, odc - 40, f"{self.agudeza_visual_od_cerca}")
1157
-
1158
- # Calcular el centro de la página
1159
- centro_pagina = pdf._pagesize[0] / 2
1160
-
1161
- # Texto y línea centrados
1162
- texto_firma = " Firma o sello: "
1163
- ancho_texto = pdf.stringWidth(texto_firma, "Helvetica", 12)
1164
- inicio_linea = centro_pagina - ancho_texto / 2
1165
- fin_linea = inicio_linea + ancho_texto
1166
- # ubicacion en y dependiendo de la tabla de medidas
1167
- firma_ubicacion = odc - 70
1168
- pdf.drawString(inicio_linea, firma_ubicacion, texto_firma)
1169
- pdf.line(inicio_linea, firma_ubicacion - 50, fin_linea, firma_ubicacion - 50)
1170
-
1171
- pdf.save()
1172
- print(f"PDF generado: {filename}")
1173
-
1174
-
1175
- # endpoint descargar prescripcion pdf con clase
1176
- class PrescripcionPDF(BaseModel):
1177
- id_prescripcion: int
1178
-
1179
-
1180
- @app.post("/prescripcion/pdf")
1181
- def obtener_pdf_prescripcion_api(prescripcion: PrescripcionPDF):
1182
- datos_prescripcion = obtener_datos_prescripcion(prescripcion.id_prescripcion)
1183
- if datos_prescripcion:
1184
- # Crear un objeto de la clase DatosPrescripcion
1185
- obj_datos_prescripcion = DatosPrescripcion(*datos_prescripcion)
1186
- directorio_pdf = "pdf/prescripcion/"
1187
- os.makedirs(directorio_pdf, exist_ok=True)
1188
- # obtener la fecha de hoy
1189
- fecha_hoy = date.today()
1190
- # generar el nombre del archivo
1191
- nombre_archivo = f"{directorio_pdf}prescripcion_{prescripcion.id_prescripcion}_{fecha_hoy}.pdf"
1192
-
1193
- obj_datos_prescripcion.generar_pdf(f"{nombre_archivo}")
1194
- return FileResponse(
1195
- nombre_archivo, media_type="application/pdf", filename=nombre_archivo
1196
- )
1197
- else:
1198
- raise HTTPException(status_code=404, detail="Prescripción no encontrada")
1199
-
1200
-
1201
- # crear endpoint retornando la url del PDF con los datos de la prescripción
1202
- @app.get("/prescripcion/pdf/{id_prescripcion}")
1203
- def ver_prescripcion_pdf(id_prescripcion: int):
1204
- datos_prescripcion = obtener_datos_prescripcion(id_prescripcion)
1205
- if datos_prescripcion:
1206
- # Crear un objeto de la clase DatosPrescripcion
1207
- obj_datos_prescripcion = DatosPrescripcion(*datos_prescripcion)
1208
- directorio_pdf = "pdf/prescripcion/"
1209
- os.makedirs(directorio_pdf, exist_ok=True)
1210
- # obtener la fecha de hoy
1211
- fecha_hoy = date.today()
1212
- # generar el nombre del archivo
1213
- nombre_archivo = (
1214
- f"{directorio_pdf}prescripcion_{id_prescripcion}_{fecha_hoy}.pdf"
1215
- )
1216
- obj_datos_prescripcion.generar_pdf(f"{nombre_archivo}")
1217
- return FileResponse(path=nombre_archivo)
1218
- else:
1219
- raise HTTPException(status_code=404, detail="Prescripción no encontrada")
1220
-
1221
-
1222
- # metodo get pdf de prescripcion
1223
- @app.get("/prescripcion/descargarPDF/{id_prescripcion}")
1224
- def descargar_prescripcion_pdf(id_prescripcion: int):
1225
- datos_prescripcion = obtener_datos_prescripcion(id_prescripcion)
1226
- if datos_prescripcion:
1227
- # Crear un objeto de la clase DatosPrescripcion
1228
- obj_datos_prescripcion = DatosPrescripcion(*datos_prescripcion)
1229
- directorio_pdf = "pdf/prescripcion/"
1230
- os.makedirs(directorio_pdf, exist_ok=True)
1231
- # obtener la fecha de hoy
1232
- fecha_hoy = date.today()
1233
- # generar el nombre del archivo
1234
- nombre_archivo = (
1235
- f"{directorio_pdf}prescripcion_{id_prescripcion}_{fecha_hoy}.pdf"
1236
- )
1237
- obj_datos_prescripcion.generar_pdf(f"{nombre_archivo}")
1238
- return FileResponse(
1239
- path=nombre_archivo, media_type="application/pdf", filename=nombre_archivo
1240
- )
1241
- else:
1242
- raise HTTPException(status_code=404, detail="Prescripción no encontrada")
1243
-
1244
-
1245
- """
1246
- Table lunas_pedido {
1247
- id_lunas_pedido INTEGER [primary key, unique, increment]
1248
- id_prescripcion INTEGER [ref: > Prescripcion.id_prescripcion]
1249
- precio REAL
1250
- id_boleta INTEGER [ref: > boleta.id_boleta]
1251
- descripcion VARCHAR
1252
- cantidad INTEGER
1253
- }
1254
- """
1255
-
1256
-
1257
- # get
1258
- @app.get("/lunas_pedido")
1259
- def get_lunas_pedido():
1260
- try:
1261
- with DatabaseConnection().get_connection() as conn:
1262
- cursor = conn.cursor()
1263
- cursor.execute("SELECT * FROM lunas_pedido")
1264
- lunas_pedido = cursor.fetchall()
1265
- return lunas_pedido
1266
- except Exception as e:
1267
- print(e)
1268
- return []
1269
-
1270
-
1271
- # post con pydantic
1272
- class LunasPedido(BaseModel):
1273
- id_prescripcion: int
1274
- precio: float
1275
- id_boleta: int
1276
- descripcion: str
1277
- cantidad: int
1278
-
1279
-
1280
- @app.post("/lunas_pedido")
1281
- def create_lunas_pedido(lunas_pedido: LunasPedido):
1282
- try:
1283
- with DatabaseConnection().get_connection() as conn:
1284
- cursor = conn.cursor()
1285
- cursor.execute(
1286
- "INSERT INTO lunas_pedido (id_prescripcion, precio, id_boleta, descripcion, cantidad) VALUES (?, ?, ?, ?, ?)",
1287
- (
1288
- lunas_pedido.id_prescripcion,
1289
- lunas_pedido.precio,
1290
- lunas_pedido.id_boleta,
1291
- lunas_pedido.descripcion,
1292
- lunas_pedido.cantidad,
1293
- ),
1294
- )
1295
- conn.commit()
1296
- return {"mensaje": "Lunas_pedido creada exitosamente"}
1297
- except Exception as e:
1298
- print(e)
1299
- return []
1300
-
1301
-
1302
- # put con pydantic
1303
- class LunasPedidoUpdate(BaseModel):
1304
- id_lunas_pedido: int
1305
- id_prescripcion: int
1306
- precio: float
1307
- id_boleta: int
1308
- descripcion: str
1309
- cantidad: int
1310
-
1311
-
1312
- @app.put("/lunas_pedido")
1313
- def update_lunas_pedido(lunas_pedido: LunasPedidoUpdate):
1314
- try:
1315
- with DatabaseConnection().get_connection() as conn:
1316
- cursor = conn.cursor()
1317
- cursor.execute(
1318
- "UPDATE lunas_pedido SET id_prescripcion = ?, precio = ?, id_boleta = ?, descripcion = ?, cantidad = ? WHERE id_lunas_pedido = ?",
1319
- (
1320
- lunas_pedido.id_prescripcion,
1321
- lunas_pedido.precio,
1322
- lunas_pedido.id_boleta,
1323
- lunas_pedido.descripcion,
1324
- lunas_pedido.cantidad,
1325
- lunas_pedido.id_lunas_pedido,
1326
- ),
1327
- )
1328
- conn.commit()
1329
- return {"mensaje": "Lunas_pedido actualizada exitosamente"}
1330
- except Exception as e:
1331
- print(e)
1332
- return []
1333
-
1334
-
1335
- # delete con pydantic
1336
- class LunasPedidoDelete(BaseModel):
1337
- id_lunas_pedido: int
1338
-
1339
-
1340
- @app.delete("/lunas_pedido")
1341
- def delete_lunas_pedido(lunas_pedido: LunasPedidoDelete):
1342
- try:
1343
- with DatabaseConnection().get_connection() as conn:
1344
- cursor = conn.cursor()
1345
- cursor.execute(
1346
- "DELETE FROM lunas_pedido WHERE id_lunas_pedido = ?",
1347
- (lunas_pedido.id_lunas_pedido,),
1348
- )
1349
- conn.commit()
1350
- return {"mensaje": "Lunas_pedido eliminada exitosamente"}
1351
- except Exception as e:
1352
- print(e)
1353
- return []
1354
-
1355
-
1356
- """
1357
- CREATE TABLE Montura (
1358
- id_montura INTEGER PRIMARY KEY AUTOINCREMENT,
1359
- nombre_montura VARCHAR,
1360
- imagen VARCHAR,
1361
- marca VARCHAR,
1362
- color VARCHAR,
1363
- material VARCHAR
1364
- )
1365
- """
1366
-
1367
-
1368
- # get/monturas -> obtener todas las monturas con with connection as conn, manejo de errores
1369
- @app.get("/monturas")
1370
- def get_monturas():
1371
- try:
1372
- with DatabaseConnection().get_connection() as conn:
1373
- cursor = conn.cursor()
1374
- cursor.execute("SELECT * FROM Montura")
1375
- monturas = cursor.fetchall()
1376
- return monturas
1377
- except Exception as e:
1378
- print(e)
1379
- return []
1380
-
1381
-
1382
- # get/monturas/{id_montura} -> obtener una montura por id
1383
- @app.get("/monturas/{id_montura}")
1384
- def get_montura(id_montura: int):
1385
- try:
1386
- with DatabaseConnection().get_connection() as conn:
1387
- cursor = conn.cursor()
1388
- cursor.execute("SELECT * FROM Montura WHERE id_montura = ?", (id_montura,))
1389
- montura = cursor.fetchone()
1390
- return montura
1391
- except Exception as e:
1392
- print(e)
1393
- return []
1394
-
1395
-
1396
- # busqueda de montura por nombre con like, manejo de errores y clase pydantic
1397
- class MonturaNombre(BaseModel):
1398
- nombre_montura: str
1399
-
1400
-
1401
- # post/monturas/busqueda -> buscar montura por nombre
1402
- @app.post("/monturas/busqueda")
1403
- def buscar_montura(montura: MonturaNombre):
1404
- try:
1405
- with DatabaseConnection().get_connection() as conn:
1406
- cursor = conn.cursor()
1407
- cursor.execute(
1408
- "SELECT * FROM Montura WHERE nombre_montura LIKE ?",
1409
- (montura.nombre_montura,),
1410
- )
1411
- montura = cursor.fetchall()
1412
- if montura:
1413
- return montura
1414
- else:
1415
- raise HTTPException(status_code=404, detail="Montura no encontrada")
1416
- except Exception as e:
1417
- print(e)
1418
- return []
1419
-
1420
-
1421
- # post/monturas -> crear una montura con una clase pydantic
1422
- class Montura(BaseModel):
1423
- nombre_montura: str
1424
- imagen: str
1425
- marca: str
1426
- color: str
1427
- material: str
1428
-
1429
-
1430
- # metodo post de monturas con manejo de errores
1431
- @app.post("/monturas")
1432
- def create_montura(montura: Montura):
1433
- try:
1434
- with DatabaseConnection().get_connection() as conn:
1435
- cursor = conn.cursor()
1436
- cursor.execute(
1437
- "INSERT INTO Montura (nombre_montura, imagen, marca, color, material) VALUES (?, ?, ?, ?, ?)",
1438
- (
1439
- montura.nombre_montura,
1440
- montura.imagen,
1441
- montura.marca,
1442
- montura.color,
1443
- montura.material,
1444
- ),
1445
- )
1446
- conn.commit()
1447
- return {"mensaje": "Montura creada exitosamente"}
1448
- except Exception as e:
1449
- print(e)
1450
- return []
1451
-
1452
-
1453
- # put/monturas -> actualizar una montura con una clase pydantic
1454
- class MonturaUpdate(BaseModel):
1455
- id_montura: int
1456
- nombre_montura: str
1457
- imagen: str
1458
- marca: str
1459
- color: str
1460
- material: str
1461
-
1462
-
1463
- # metodo put de monturas con manejo de errores
1464
- @app.put("/monturas")
1465
- def update_montura(montura: MonturaUpdate):
1466
- try:
1467
- with DatabaseConnection().get_connection() as conn:
1468
- cursor = conn.cursor()
1469
- cursor.execute(
1470
- "UPDATE Montura SET nombre_montura = ?, imagen = ?, marca = ?, color = ?, material = ? WHERE id_montura = ?",
1471
- (
1472
- montura.nombre_montura,
1473
- montura.imagen,
1474
- montura.marca,
1475
- montura.color,
1476
- montura.material,
1477
- montura.id_montura,
1478
- ),
1479
- )
1480
- conn.commit()
1481
- return {"mensaje": "Montura actualizada exitosamente"}
1482
- except Exception as e:
1483
- print(e)
1484
- return []
1485
-
1486
-
1487
- # delete/monturas -> eliminar una montura con una clase pydantic
1488
- class MonturaDelete(BaseModel):
1489
- id_montura: int
1490
-
1491
-
1492
- # metodo delete de monturas con manejo de errores
1493
- @app.delete("/monturas")
1494
- def delete_montura(montura: MonturaDelete):
1495
- try:
1496
- with DatabaseConnection().get_connection() as conn:
1497
- cursor = conn.cursor()
1498
- cursor.execute(
1499
- "DELETE FROM Montura WHERE id_montura = ?", (montura.id_montura,)
1500
- )
1501
- conn.commit()
1502
- return {"mensaje": "Montura eliminada exitosamente"}
1503
- except Exception as e:
1504
- print(e)
1505
- return []
1506
-
1507
-
1508
- """
1509
- CREATE TABLE Montura_inventario (
1510
- id_montura_inventario INTEGER PRIMARY KEY AUTOINCREMENT,
1511
- id_montura INTEGER REFERENCES Montura(id_montura),
1512
- precio_unit REAL,
1513
- stock INTEGER,
1514
- codigo VARCHAR
1515
- )
1516
- """
1517
-
1518
-
1519
- # get/monturas_inventario -> obtener todas las monturas_inventario con with connection as conn, manejo de errores
1520
- @app.get("/monturas_inventario")
1521
- def get_monturas_inventario():
1522
- try:
1523
- with DatabaseConnection().get_connection() as conn:
1524
- cursor = conn.cursor()
1525
- cursor.execute("SELECT * FROM Montura_inventario")
1526
- monturas_inventario = cursor.fetchall()
1527
- return monturas_inventario
1528
- except Exception as e:
1529
- print(e)
1530
- return []
1531
-
1532
-
1533
- # get/monturas_inventario/{id_montura_inventario} -> obtener una montura_inventario por id
1534
- @app.get("/monturas_inventario/{id_montura_inventario}")
1535
- def get_montura_inventario(id_montura_inventario: int):
1536
- try:
1537
- with DatabaseConnection().get_connection() as conn:
1538
- cursor = conn.cursor()
1539
- cursor.execute(
1540
- "SELECT * FROM Montura_inventario WHERE id_montura_inventario = ?",
1541
- (id_montura_inventario,),
1542
- )
1543
- montura_inventario = cursor.fetchone()
1544
- return montura_inventario
1545
- except Exception as e:
1546
- print(e)
1547
- return []
1548
-
1549
-
1550
- # post/monturas_inventario -> crear una montura_inventario con una clase pydantic
1551
- class Montura_inventario(BaseModel):
1552
- id_montura: int
1553
- precio_unit: float
1554
- stock: int
1555
- codigo: str
1556
-
1557
-
1558
- # metodo post de monturas_inventario con manejo de errores
1559
- @app.post("/monturas_inventario")
1560
- def create_montura_inventario(montura_inventario: Montura_inventario):
1561
- try:
1562
- with DatabaseConnection().get_connection() as conn:
1563
- cursor = conn.cursor()
1564
- cursor.execute(
1565
- "INSERT INTO Montura_inventario (id_montura, precio_unit, stock, codigo) VALUES (?, ?, ?, ?)",
1566
- (
1567
- montura_inventario.id_montura,
1568
- montura_inventario.precio_unit,
1569
- montura_inventario.stock,
1570
- montura_inventario.codigo,
1571
- ),
1572
- )
1573
- conn.commit()
1574
- return {"mensaje": "Montura_inventario creada exitosamente"}
1575
- except Exception as e:
1576
- print(e)
1577
- return []
1578
-
1579
-
1580
- # busqueda de montura_inventario por codigo con like, manejo de errores y clase pydantic
1581
- class Montura_inventarioCodigo(BaseModel):
1582
- codigo: str
1583
-
1584
-
1585
- # post/monturas_inventario/busqueda -> buscar una montura_inventario por codigo
1586
- @app.post("/monturas_inventario/busqueda")
1587
- def buscar_montura_inventario(montura_inventario: Montura_inventarioCodigo):
1588
- try:
1589
- with DatabaseConnection().get_connection() as conn:
1590
- cursor = conn.cursor()
1591
- cursor.execute(
1592
- "SELECT * FROM Montura_inventario WHERE codigo LIKE ?",
1593
- (montura_inventario.codigo,),
1594
- )
1595
- montura_inventario = cursor.fetchall()
1596
- if montura_inventario:
1597
- return montura_inventario
1598
- else:
1599
- raise HTTPException(
1600
- status_code=404, detail="Montura_inventario no encontrada"
1601
- )
1602
- except Exception as e:
1603
- print(e)
1604
- return []
1605
-
1606
-
1607
- # put/monturas_inventario -> actualizar una montura_inventario con una clase pydantic
1608
- class Montura_inventarioUpdate(BaseModel):
1609
- id_montura_inventario: int
1610
- id_montura: int
1611
- precio_unit: float
1612
- stock: int
1613
- codigo: str
1614
-
1615
-
1616
- # metodo put de monturas_inventario con manejo de errores
1617
- @app.put("/monturas_inventario")
1618
- def update_montura_inventario(montura_inventario: Montura_inventarioUpdate):
1619
- try:
1620
- with DatabaseConnection().get_connection() as conn:
1621
- cursor = conn.cursor()
1622
- cursor.execute(
1623
- "UPDATE Montura_inventario SET id_montura = ?, precio_unit = ?, stock = ?, codigo = ? WHERE id_montura_inventario = ?",
1624
- (
1625
- montura_inventario.id_montura,
1626
- montura_inventario.precio_unit,
1627
- montura_inventario.stock,
1628
- montura_inventario.codigo,
1629
- montura_inventario.id_montura_inventario,
1630
- ),
1631
- )
1632
- conn.commit()
1633
- return {"mensaje": "Montura_inventario actualizada exitosamente"}
1634
- except Exception as e:
1635
- print(e)
1636
- return []
1637
-
1638
-
1639
- # delete/monturas_inventario -> eliminar una montura_inventario con una clase pydantic
1640
- class Montura_inventarioDelete(BaseModel):
1641
- id_montura_inventario: int
1642
-
1643
-
1644
- # metodo delete de monturas_inventario con manejo de errores
1645
- @app.delete("/monturas_inventario")
1646
- def delete_montura_inventario(montura_inventario: Montura_inventarioDelete):
1647
- try:
1648
- with DatabaseConnection().get_connection() as conn:
1649
- cursor = conn.cursor()
1650
- cursor.execute(
1651
- "DELETE FROM Montura_inventario WHERE id_montura_inventario = ?",
1652
- (montura_inventario.id_montura_inventario,),
1653
- )
1654
- conn.commit()
1655
- return {"mensaje": "Montura_inventario eliminada exitosamente"}
1656
- except Exception as e:
1657
- print(e)
1658
- return []
1659
-
1660
-
1661
- """
1662
- CREATE TABLE boleta (
1663
- id_boleta INTEGER PRIMARY KEY AUTOINCREMENT,
1664
- precio_total REAL,
1665
- estado_recojo VARCHAR
1666
- )
1667
- """
1668
-
1669
-
1670
- # get/boletas -> obtener todas las boletas con with connection as conn, manejo de errores
1671
- @app.get("/boletas")
1672
- def get_boletas():
1673
- try:
1674
- with DatabaseConnection().get_connection() as conn:
1675
- cursor = conn.cursor()
1676
- cursor.execute("SELECT * FROM boleta")
1677
- boletas = cursor.fetchall()
1678
- return boletas
1679
- except Exception as e:
1680
- print(e)
1681
- return []
1682
-
1683
-
1684
- # get/boletas/{id_boleta} -> obtener una boleta por id
1685
- @app.get("/boletas/{id_boleta}")
1686
- def get_boleta(id_boleta: int):
1687
- try:
1688
- with DatabaseConnection().get_connection() as conn:
1689
- cursor = conn.cursor()
1690
- cursor.execute("SELECT * FROM boleta WHERE id_boleta = ?", (id_boleta,))
1691
- boleta = cursor.fetchone()
1692
- if boleta:
1693
- return boleta
1694
- else:
1695
- raise HTTPException(status_code=404, detail="Boleta no encontrada")
1696
- except Exception as e:
1697
- print(e)
1698
- return []
1699
-
1700
-
1701
- # post/boletas -> crear una boleta con una clase pydantic
1702
- class Boleta(BaseModel):
1703
- precio_total: float
1704
- estado_recojo: str
1705
-
1706
-
1707
- # metodo post de boletas con manejo de errores
1708
- @app.post("/boletas")
1709
- def create_boleta(boleta: Boleta):
1710
- try:
1711
- with DatabaseConnection().get_connection() as conn:
1712
- cursor = conn.cursor()
1713
- cursor.execute(
1714
- "INSERT INTO boleta (precio_total, estado_recojo) VALUES (?, ?)",
1715
- (
1716
- boleta.precio_total,
1717
- boleta.estado_recojo,
1718
- ),
1719
- )
1720
- conn.commit()
1721
- return {"mensaje": "Boleta creada exitosamente"}
1722
- except Exception as e:
1723
- print(e)
1724
- return []
1725
-
1726
-
1727
- # put/boletas -> actualizar una boleta con una clase pydantic
1728
- class BoletaUpdate(BaseModel):
1729
- id_boleta: int
1730
- precio_total: float
1731
- estado_recojo: str
1732
-
1733
-
1734
- # metodo put de boletas con manejo de errores
1735
- @app.put("/boletas")
1736
- def update_boleta(boleta: BoletaUpdate):
1737
- try:
1738
- with DatabaseConnection().get_connection() as conn:
1739
- cursor = conn.cursor()
1740
- cursor.execute(
1741
- "UPDATE boleta SET precio_total = ?, estado_recojo = ? WHERE id_boleta = ?",
1742
- (
1743
- boleta.precio_total,
1744
- boleta.estado_recojo,
1745
- boleta.id_boleta,
1746
- ),
1747
- )
1748
- conn.commit()
1749
- return {"mensaje": "Boleta actualizada exitosamente"}
1750
- except Exception as e:
1751
- print(e)
1752
- return []
1753
-
1754
-
1755
- # delete/boletas -> eliminar una boleta con una clase pydantic
1756
- class BoletaDelete(BaseModel):
1757
- id_boleta: int
1758
-
1759
-
1760
- # metodo delete de boletas con manejo de errores
1761
- @app.delete("/boletas")
1762
- def delete_boleta(boleta: BoletaDelete):
1763
- try:
1764
- with DatabaseConnection().get_connection() as conn:
1765
- cursor = conn.cursor()
1766
- cursor.execute(
1767
- "DELETE FROM boleta WHERE id_boleta = ?", (boleta.id_boleta,)
1768
- )
1769
- conn.commit()
1770
- return {"mensaje": "Boleta eliminada exitosamente"}
1771
- except Exception as e:
1772
- print(e)
1773
- return []
1774
-
1775
-
1776
- def generar_boleta(idboleta, cliente, productos, adelanto, saldo):
1777
- # crear directorio si no existe en pdf/boleta
1778
- directorio_pdf = "pdf/boleta/"
1779
- os.makedirs(directorio_pdf, exist_ok=True)
1780
- # Crear un nombre de archivo único basado en la fecha y hora actual
1781
- now = datetime.now()
1782
- formatted_date_time = now.strftime("%Y%m%d%H%M%S")
1783
- nombre_archivo = f"{directorio_pdf}boleta_{formatted_date_time}.pdf"
1784
-
1785
- # Inicializar el lienzo del PDF
1786
- c = canvas.Canvas(nombre_archivo, pagesize=letter)
1787
- ubicacion_inicio = 700
1788
- # Configurar la tipografía para la sección del cliente
1789
- c.setFont("Craftcoke", 30)
1790
- c.drawString(100, ubicacion_inicio, "Arte Visual")
1791
-
1792
- # Configurar la tipografía para la sección de productos
1793
- c.setFont("Oregon", 12)
1794
- c.drawString(420, ubicacion_inicio, "NOTA DE PEDIDO")
1795
- # agregar numero de pedido con numero idboleta
1796
- c.drawString(420, ubicacion_inicio - 20, f"N° {str(idboleta).zfill(12)}")
1797
- c.drawString(100, ubicacion_inicio - 20, "Av. Los Héroes 632-S.J.M.")
1798
- # agregar logo de whatsapp de 30x30
1799
- c.drawImage("./img/pdf/logo_whatsapp.jpg", 100, ubicacion_inicio - 43, 12, 12)
1800
- c.drawString(115, ubicacion_inicio - 40, "902-501-054/ 968-600-415")
1801
- # añadir fecha a la derecha
1802
- c.drawString(420, ubicacion_inicio - 40, f"Fecha: {now.strftime('%d/%m/%Y')}")
1803
- # Información del cliente
1804
- c.drawString(
1805
- 100, ubicacion_inicio - 60, f"Señor(a): {cliente['nombres_y_apellidos']}"
1806
- )
1807
- c.drawString(
1808
- 100,
1809
- ubicacion_inicio - 80,
1810
- f"Dirección: {cliente['direccion']}",
1811
- )
1812
- c.drawString(
1813
- 420,
1814
- ubicacion_inicio - 80,
1815
- f"Celular: {cliente['telefono']}",
1816
- )
1817
-
1818
- # Configurar la tipografía para la sección de productos
1819
- c.setFont("Oregon", 10)
1820
- c.drawString(100, ubicacion_inicio - 110, "Tabla de productos:")
1821
-
1822
- # Crear la tabla de productos
1823
- productos_data = [["Cantidad", "Descripción", "P.Unitario", "Importe"]]
1824
- for producto in productos:
1825
- productos_data.append(
1826
- [
1827
- producto["cantidad"],
1828
- producto["descripcion"],
1829
- f"S/.{producto['precio']:.2f}",
1830
- f"S/.{producto['importe']:.2f}",
1831
- ]
1832
- )
1833
-
1834
- # Configurar el estilo de la tabla
1835
- style = TableStyle(
1836
- [
1837
- ("BACKGROUND", (0, 0), (-1, 0), "grey"),
1838
- ("TEXTCOLOR", (0, 0), (-1, 0), "white"),
1839
- ("ALIGN", (0, 0), (-1, -1), "CENTER"),
1840
- ("VALIGN", (0, 0), (-1, -1), "MIDDLE"), # Alineación vertical al centro
1841
- ("FONTNAME", (0, 0), (-1, 0), "Oregon"),
1842
- ("FONTNAME", (0, 1), (-1, -1), "Oregon"),
1843
- ("BOTTOMPADDING", (0, 0), (-1, 0), 12),
1844
- ("BACKGROUND", (0, 1), (-1, -1), "white"),
1845
- ("GRID", (0, 0), (-1, -1), 1, "grey"),
1846
- ]
1847
- )
1848
-
1849
- # Crear la tabla y aplicar el estilo
1850
- table = Table(productos_data, colWidths=[50, 220, 80, 80])
1851
- table.setStyle(style)
1852
-
1853
- # Dibuja el título de la tabla
1854
- c.drawString(100, ubicacion_inicio - 110, "Tabla de productos:")
1855
-
1856
- # Calcula la altura de la tabla
1857
- altura_tabla = table.wrapOn(c, 400, ubicacion_inicio - 350)[1]
1858
-
1859
- # Dibuja la tabla
1860
- table.drawOn(c, 100, ubicacion_inicio - 130 - altura_tabla)
1861
-
1862
- # Ajusta la ubicación de inicio para los elementos siguientes
1863
- ubicacion_inicio = ubicacion_inicio - 130 - altura_tabla
1864
-
1865
- # Información de pago
1866
- c.setFont("Oregon", 12)
1867
- c.drawString(100, ubicacion_inicio - 40, f"Adelanto: S/.{adelanto:.2f}")
1868
- c.drawString(250, ubicacion_inicio - 40, f"Saldo: S/.{saldo:.2f}")
1869
-
1870
- # Calcular el total
1871
- total = adelanto + saldo
1872
- c.drawString(450, ubicacion_inicio - 40, f"Total: S/.{total:.2f}")
1873
-
1874
- # Guardar y cerrar el archivo PDF
1875
- c.save()
1876
-
1877
- print(f"Boleta generada como: {nombre_archivo}")
1878
- return nombre_archivo
1879
-
1880
-
1881
- def obtener_datos_boleta(id_boleta, adelanto):
1882
- conn = DatabaseConnection().get_connection()
1883
- cursor = conn.cursor()
1884
- query = """
1885
- SELECT
1886
- Cliente.nombres_y_apellidos,
1887
- Cliente.direccion,
1888
- Cliente.telefono,
1889
- lunas_pedido.descripcion AS producto,
1890
- lunas_pedido.precio AS precio_unitario,
1891
- lunas_pedido.cantidad,
1892
- boleta.precio_total AS adelanto,
1893
- boleta.precio_total - COALESCE(SUM(lunas_pedido.precio * lunas_pedido.cantidad), 0) AS saldo,
1894
- montura_pedido.id_montura_pedido,
1895
- montura_pedido.cantidad AS cantidad_monturas,
1896
- montura_inventario.precio_unit AS precio_unitario_monturas,
1897
- montura.nombre_montura,
1898
- montura.marca,
1899
- montura.color,
1900
- montura.material
1901
- FROM boleta
1902
- JOIN lunas_pedido ON boleta.id_boleta = lunas_pedido.id_boleta
1903
- JOIN Prescripcion ON lunas_pedido.id_prescripcion = Prescripcion.id_prescripcion
1904
- JOIN Medidas ON Prescripcion.id_medidas = Medidas.id_medidas
1905
- JOIN Cliente ON Medidas.id_cliente = Cliente.id_cliente
1906
- LEFT JOIN montura_pedido ON boleta.id_boleta = montura_pedido.id_boleta
1907
- LEFT JOIN montura_inventario ON montura_pedido.id_montura_inventario = montura_inventario.id_montura_inventario
1908
- LEFT JOIN montura ON montura_inventario.id_montura = montura.id_montura
1909
- WHERE boleta.id_boleta = ?
1910
- GROUP BY boleta.id_boleta
1911
- """
1912
-
1913
- cursor.execute(query, (id_boleta,))
1914
- datos = cursor.fetchone()
1915
-
1916
- conn.close()
1917
-
1918
- return datos
1919
-
1920
-
1921
- def obtener_productos_por_boleta(id_boleta):
1922
- # Conectarse a la base de datos SQLite
1923
- conn = DatabaseConnection().get_connection()
1924
- cursor = conn.cursor()
1925
-
1926
- # Consulta para monturas
1927
- query_monturas = f"""
1928
- SELECT
1929
- mp.cantidad AS cantidad,
1930
- mi.codigo AS codigo_montura,
1931
- m.nombre_montura AS nombre_montura,
1932
- m.marca,
1933
- m.color,
1934
- m.material,
1935
- mi.precio_unit AS precio_unitario,
1936
- (mi.precio_unit * mp.cantidad) AS importe
1937
- FROM
1938
- montura_pedido mp
1939
- JOIN
1940
- montura_inventario mi ON mp.id_montura_inventario = mi.id_montura_inventario
1941
- JOIN
1942
- montura m ON mi.id_montura = m.id_montura
1943
- WHERE
1944
- mp.id_boleta = {id_boleta};
1945
- """
1946
-
1947
- cursor.execute(query_monturas)
1948
- resultados_monturas = cursor.fetchall()
1949
-
1950
- # Consulta para lunas
1951
- query_lunas = f"""
1952
- SELECT
1953
- lp.cantidad AS cantidad,
1954
- p.detalle_lunas AS descripcion,
1955
- lp.precio AS precio,
1956
- (lp.precio * lp.cantidad) AS importe
1957
- FROM
1958
- lunas_pedido lp
1959
- JOIN
1960
- boleta b ON lp.id_boleta = b.id_boleta
1961
- JOIN
1962
- prescripcion p ON lp.id_prescripcion = p.id_prescripcion
1963
- WHERE
1964
- b.id_boleta = {id_boleta};
1965
- """
1966
-
1967
- cursor.execute(query_lunas)
1968
- resultados_lunas = cursor.fetchall()
1969
- # Cerrar la conexión a la base de datos
1970
- conn.close()
1971
-
1972
- # Crear un diccionario combinado con los resultados
1973
- productos = []
1974
- print("Esta es la cantidad de monturas y lunas:")
1975
- print(f"Monturas: {len(resultados_monturas)}")
1976
- print(f"Lunas: {len(resultados_lunas)}")
1977
- # validacion si hay monturas
1978
- if len(resultados_monturas) > 0:
1979
- # Agregar monturas al diccionario
1980
- for resultado_montura in resultados_monturas:
1981
- producto_montura = {
1982
- "cantidad": resultado_montura[0],
1983
- "descripcion": f"Código: {resultado_montura[1]}, \nNombre: {resultado_montura[2]}, \nMarca: {resultado_montura[3]}, \nColor: {resultado_montura[4]}, \nMaterial: {resultado_montura[5]}",
1984
- "precio": resultado_montura[6],
1985
- "importe": resultado_montura[7],
1986
- }
1987
- productos.append(producto_montura)
1988
- # validacion si hay lunas
1989
- if len(resultados_lunas) > 0:
1990
- # Agregar lunas al diccionario
1991
- for resultado_luna in resultados_lunas:
1992
- producto_luna = {
1993
- "cantidad": resultado_luna[0],
1994
- "descripcion": resultado_luna[1],
1995
- "precio": resultado_luna[2],
1996
- "importe": resultado_luna[3],
1997
- }
1998
- productos.append(producto_luna)
1999
-
2000
- return productos
2001
-
2002
-
2003
- def generar_boleta_desde_bd(id_boleta, adelanto):
2004
- # Obtener datos de la boleta desde la base de datos
2005
- datos = obtener_datos_boleta(id_boleta, adelanto)
2006
-
2007
- if datos:
2008
- # Crear boleta usando los datos calculados
2009
- cliente = {
2010
- "nombres_y_apellidos": datos["nombres_y_apellidos"],
2011
- "direccion": datos["direccion"],
2012
- "telefono": datos["telefono"],
2013
- }
2014
- productos = obtener_productos_por_boleta(id_boleta)
2015
- # Calcular total y saldo
2016
- total = sum(
2017
- [producto["cantidad"] * producto["precio"] for producto in productos]
2018
- )
2019
- saldo = total - adelanto
2020
- # Generar la boleta
2021
- archivo_pdf_ok = generar_boleta(id_boleta, cliente, productos, adelanto, saldo)
2022
- print(archivo_pdf_ok)
2023
- else:
2024
- print(f"No se encontraron datos para la boleta con ID {id_boleta}.")
2025
-
2026
-
2027
- # endpoint retorna el pdf de la boleta con idboleta y adelanto
2028
- @app.get("/boleta/descargarPDF/{id_boleta}/{adelanto}")
2029
- def descargar_pdf_boleta_get(id_boleta: int, adelanto: float):
2030
- try:
2031
- directorio_pdf = "pdf/boleta/"
2032
- now = datetime.now()
2033
- formatted_date_time = now.strftime("%Y%m%d%H%M%S")
2034
- nombre_archivo = f"{directorio_pdf}boleta_{formatted_date_time}.pdf"
2035
- # crear pdf
2036
- generar_boleta_desde_bd(id_boleta, adelanto)
2037
- # validacion si existe el archivo o no y retorna el archivo pdf
2038
- if os.path.exists(nombre_archivo):
2039
- # return nombre_archivo
2040
- return FileResponse(
2041
- nombre_archivo,
2042
- media_type="application/pdf",
2043
- filename=nombre_archivo,
2044
- )
2045
- else:
2046
- raise HTTPException(
2047
- status_code=404, detail="No se encontró la boleta solicitada"
2048
- )
2049
- except Exception as e:
2050
- print(e)
2051
- return []
2052
-
2053
-
2054
- # crear endpoint retornando la url del PDF con los datos de la prescripción
2055
- @app.get("/boleta/verPDF/{id_boleta}/{adelanto}")
2056
- def ver_pdf_boleta_get(id_boleta: int, adelanto: float):
2057
- try:
2058
- directorio_pdf = "pdf/boleta/"
2059
- formatted_date_time = datetime.now().strftime("%Y%m%d%H%M%S")
2060
- nombre_archivo = f"{directorio_pdf}boleta_{formatted_date_time}.pdf"
2061
- generar_boleta_desde_bd(id_boleta, adelanto)
2062
- if os.path.exists(nombre_archivo):
2063
- return FileResponse(path=nombre_archivo)
2064
- else:
2065
- raise HTTPException(
2066
- status_code=404, detail="No se encontró la boleta solicitada"
2067
- )
2068
- except Exception as e:
2069
- print(e)
2070
- return []
2071
-
2072
-
2073
- # clase boletaPDF para recibir los datos de la boleta
2074
- class BoletaPDF(BaseModel):
2075
- id_boleta: int
2076
- adelanto: float
2077
-
2078
-
2079
- # ruta para generar boleta en pdf con manejo de errores en caso no se encuentre la boleta
2080
- @app.post("/boleta/descargarPDF")
2081
- def descargar_boleta_pdf_post(boleta_pdf: BoletaPDF):
2082
- try:
2083
- directorio_pdf = "pdf/boleta/"
2084
- now = datetime.now()
2085
- formatted_date_time = now.strftime("%Y%m%d%H%M%S")
2086
- nombre_archivo = f"{directorio_pdf}boleta_{formatted_date_time}.pdf"
2087
- # crear pdf
2088
- generar_boleta_desde_bd(boleta_pdf.id_boleta, boleta_pdf.adelanto)
2089
- # validacion si existe el archivo o no
2090
- if os.path.exists(nombre_archivo):
2091
- return FileResponse(
2092
- nombre_archivo,
2093
- media_type="application/pdf",
2094
- filename=nombre_archivo,
2095
- )
2096
- else:
2097
- raise HTTPException(
2098
- status_code=404, detail="No se encontró la boleta solicitada"
2099
- )
2100
- except Exception as e:
2101
- print(e)
2102
- return []
2103
-
2104
-
2105
- # get obtiene la ultima boleta creada
2106
- @app.get("/boleta/ultima")
2107
- def get_ultima_boleta():
2108
- try:
2109
- with DatabaseConnection().get_connection() as conn:
2110
- cursor = conn.cursor()
2111
- cursor.execute("SELECT * FROM boleta ORDER BY id_boleta DESC LIMIT 1")
2112
- boleta = cursor.fetchone()
2113
- return boleta
2114
- except Exception as e:
2115
- print(e)
2116
- return []
2117
-
2118
-
2119
- """
2120
- CREATE TABLE montura_pedido (
2121
- id_montura_pedido INTEGER PRIMARY KEY AUTOINCREMENT,
2122
- id_montura_inventario INTEGER REFERENCES Montura_inventario(id_montura_inventario),
2123
- cantidad INTEGER,
2124
- precio REAL,
2125
- id_boleta INTEGER REFERENCES boleta(id_boleta)
2126
- )
2127
- """
2128
-
2129
-
2130
- # get/monturas_pedidos -> obtener todas las monturas_pedidos con with connection as conn, manejo de errores
2131
- @app.get("/monturas_pedidos")
2132
- def get_monturas_pedidos():
2133
- try:
2134
- with DatabaseConnection().get_connection() as conn:
2135
- cursor = conn.cursor()
2136
- cursor.execute("SELECT * FROM montura_pedido")
2137
- monturas_pedidos = cursor.fetchall()
2138
- return monturas_pedidos
2139
- except Exception as e:
2140
- print(e)
2141
- return []
2142
-
2143
-
2144
- # get/monturas_pedidos/{id_montura_pedido} -> obtener una montura_pedido por id
2145
- @app.get("/monturas_pedidos/{id_montura_pedido}")
2146
- def get_montura_pedido(id_montura_pedido: int):
2147
- try:
2148
- with DatabaseConnection().get_connection() as conn:
2149
- cursor = conn.cursor()
2150
- cursor.execute(
2151
- "SELECT * FROM montura_pedido WHERE id_montura_pedido = ?",
2152
- (id_montura_pedido,),
2153
- )
2154
- montura_pedido = cursor.fetchone()
2155
- return montura_pedido
2156
- except Exception as e:
2157
- print(e)
2158
- return []
2159
-
2160
-
2161
- # post/monturas_pedidos -> crear una montura_pedido con una clase pydantic
2162
- class Montura_pedido(BaseModel):
2163
- id_montura_inventario: int
2164
- cantidad: int
2165
- precio: float
2166
- id_boleta: int
2167
-
2168
-
2169
- # metodo post de monturas_pedidos con manejo de errores
2170
- @app.post("/monturas_pedidos")
2171
- def create_montura_pedido(montura_pedido: Montura_pedido):
2172
- try:
2173
- with DatabaseConnection().get_connection() as conn:
2174
- cursor = conn.cursor()
2175
- cursor.execute(
2176
- "INSERT INTO montura_pedido (id_montura_inventario, cantidad, precio, id_boleta) VALUES (?, ?, ?, ?)",
2177
- (
2178
- montura_pedido.id_montura_inventario,
2179
- montura_pedido.cantidad,
2180
- montura_pedido.precio,
2181
- montura_pedido.id_boleta,
2182
- ),
2183
- )
2184
- conn.commit()
2185
- return {"mensaje": "Montura_pedido creada exitosamente"}
2186
- except Exception as e:
2187
- print(e)
2188
- return []
2189
-
2190
-
2191
- # put/monturas_pedidos -> actualizar una montura_pedido con una clase pydantic
2192
- class Montura_pedidoUpdate(BaseModel):
2193
- id_montura_pedido: int
2194
- id_montura_inventario: int
2195
- cantidad: int
2196
- precio: float
2197
- id_boleta: int
2198
-
2199
-
2200
- # metodo put de monturas_pedidos con manejo de errores
2201
- @app.put("/monturas_pedidos")
2202
- def update_montura_pedido(montura_pedido: Montura_pedidoUpdate):
2203
- try:
2204
- with DatabaseConnection().get_connection() as conn:
2205
- cursor = conn.cursor()
2206
- cursor.execute(
2207
- "UPDATE montura_pedido SET id_montura_inventario = ?, cantidad = ?, precio = ?, id_boleta = ? WHERE id_montura_pedido = ?",
2208
- (
2209
- montura_pedido.id_montura_inventario,
2210
- montura_pedido.cantidad,
2211
- montura_pedido.precio,
2212
- montura_pedido.id_boleta,
2213
- montura_pedido.id_montura_pedido,
2214
- ),
2215
- )
2216
- conn.commit()
2217
- return {"mensaje": "Montura_pedido actualizada exitosamente"}
2218
- except Exception as e:
2219
- print(e)
2220
- return []
2221
-
2222
-
2223
- # delete/monturas_pedidos -> eliminar una montura_pedido con una clase pydantic
2224
- class Montura_pedidoDelete(BaseModel):
2225
- id_montura_pedido: int
2226
-
2227
-
2228
- # metodo delete de monturas_pedidos con manejo de errores
2229
- @app.delete("/monturas_pedidos")
2230
- def delete_montura_pedido(montura_pedido: Montura_pedidoDelete):
2231
- try:
2232
- with DatabaseConnection().get_connection() as conn:
2233
- cursor = conn.cursor()
2234
- cursor.execute(
2235
- "DELETE FROM montura_pedido WHERE id_montura_pedido = ?",
2236
- (montura_pedido.id_montura_pedido,),
2237
- )
2238
- conn.commit()
2239
- return {"mensaje": "Montura_pedido eliminada exitosamente"}
2240
- except Exception as e:
2241
- print(e)
2242
- return []
 
1
  # uvicorn app:app --host localhost --port 7860 --reload
2
+ from library.librerias import *
3
+ from database.conexion import DatabaseConnection
4
+ from routers.routers import *
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
 
6
  app = FastAPI()
7
 
 
14
  allow_headers=["*"],
15
  )
16
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
  # Cargar varias tipografías
18
  pdfmetrics.registerFont(TTFont("Craftcoke", "./font/Craftcoke.ttf"))
19
  pdfmetrics.registerFont(TTFont("Oregon", "./font/Oregon.ttf"))
20
  pdfmetrics.registerFont(TTFont("Roboto", "./font/Roboto.ttf"))
21
 
22
+ # Routers
23
+
24
+ app.router.include_router(roles.router)
25
+ app.router.include_router(usuarios.router)
26
+ app.router.include_router(clientes.router)
27
+ app.router.include_router(medidas.router)
28
+ app.router.include_router(prescripciones.router)
29
+ app.router.include_router(lunas_pedido.router)
30
+ app.router.include_router(monturas.router)
31
+ app.router.include_router(monturas_inventario.router)
32
+ app.router.include_router(boletas.router)
33
+ app.router.include_router(comprobante_pago.router)
34
+ app.router.include_router(monturas_pedido.router)
35
+
36
 
37
  # saludo
38
  @app.get("/")
 
40
  return {"mensaje": "API de la óptica del curso de ADS"}
41
 
42
 
43
+ if __name__ == "__main__":
44
+ os.system('uvicorn app:app --host "localhost" --port 7860 --reload')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
database/conexion.py ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from library.librerias import sqlite3, Queue, threading
2
+
3
+
4
+ class DatabaseConnection:
5
+ """
6
+ Clase para gestionar las conexiones a la base de datos con un pool.
7
+ """
8
+
9
+ _instance = None
10
+ _lock = threading.Lock()
11
+ _connection_pool = Queue(maxsize=5)
12
+
13
+ def __new__(cls):
14
+ """
15
+ Crea una nueva instancia de la clase si no existe.
16
+ """
17
+ with cls._lock:
18
+ if cls._instance is None:
19
+ cls._instance = super().__new__(cls)
20
+ cls._instance.conn = cls._instance._create_connection()
21
+ return cls._instance
22
+
23
+ def _create_connection(self):
24
+ """
25
+ Crea una conexión a la base de datos.
26
+ """
27
+ if not self._connection_pool.empty():
28
+ return self._connection_pool.get()
29
+ else:
30
+ connection = sqlite3.connect("database/opticaDB.db")
31
+ connection.row_factory = sqlite3.Row
32
+ return connection
33
+
34
+ def get_connection(self):
35
+ """
36
+ Obtener el objeto de conexión de la base de datos.
37
+ """
38
+ return self._instance._create_connection()
39
+
40
+ def release_connection(self):
41
+ """
42
+ Liberar la conexión de nuevo al pool.
43
+ """
44
+ if self._instance is not None:
45
+ self._connection_pool.put(self._instance.conn)
46
+ self._instance.conn = None # Marcar la instancia como sin conexión
database/opticaDB.db ADDED
Binary file (49.2 kB). View file
 
library/librerias.py ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # librerias propias del lenguaje
2
+ from datetime import datetime
3
+ from datetime import date
4
+ import os
5
+
6
+ # librerias para la API
7
+ from pydantic import BaseModel
8
+ from fastapi import FastAPI, HTTPException
9
+ from fastapi.middleware.cors import CORSMiddleware
10
+ from fastapi.responses import FileResponse
11
+ from fastapi import APIRouter, Depends, status
12
+ import uvicorn
13
+
14
+ # librerias para el pdf
15
+ from reportlab.pdfgen import canvas
16
+ from reportlab.lib.pagesizes import letter
17
+ from reportlab.pdfbase import pdfmetrics
18
+ from reportlab.pdfbase.ttfonts import TTFont
19
+ from reportlab.platypus import Table, TableStyle
20
+
21
+ # importar librerias para la conexion a la base de datos
22
+ from queue import Queue
23
+ import sqlite3
24
+ import threading
25
+
26
+
27
+ # clase para la conexion a la base de datos
28
+ from database.conexion import DatabaseConnection
pdf/boleta/boleta_20240106130310.pdf ADDED
The diff for this file is too large to render. See raw diff
 
pdf/boleta/boleta_20240106130328.pdf ADDED
The diff for this file is too large to render. See raw diff
 
pdf/boleta/boleta_20240106130349.pdf ADDED
The diff for this file is too large to render. See raw diff
 
pdf/prescripcion/prescripcion_1_2024-01-06.pdf ADDED
Binary file (26.9 kB). View file
 
routers/boletas.py ADDED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from library.librerias import *
2
+
3
+ router = APIRouter(
4
+ prefix="/boletas",
5
+ tags=["Boletas"],
6
+ responses={404: {"description": "No encontrado"}},
7
+ )
8
+
9
+
10
+ """
11
+ CREATE TABLE boleta (
12
+ id_boleta INTEGER PRIMARY KEY AUTOINCREMENT,
13
+ precio_total REAL,
14
+ estado_recojo VARCHAR
15
+ )
16
+ """
17
+
18
+
19
+ # get/boletas -> obtener todas las boletas con with connection as conn, manejo de errores
20
+ @router.get("/")
21
+ def get_boletas():
22
+ try:
23
+ with DatabaseConnection().get_connection() as conn:
24
+ cursor = conn.cursor()
25
+ cursor.execute("SELECT * FROM boleta")
26
+ boletas = cursor.fetchall()
27
+ return boletas
28
+ except Exception as e:
29
+ print(e)
30
+ return []
31
+
32
+
33
+ # get/boletas/{id_boleta} -> obtener una boleta por id
34
+ @router.get("/{id_boleta}")
35
+ def get_boleta(id_boleta: int):
36
+ try:
37
+ with DatabaseConnection().get_connection() as conn:
38
+ cursor = conn.cursor()
39
+ cursor.execute("SELECT * FROM boleta WHERE id_boleta = ?", (id_boleta,))
40
+ boleta = cursor.fetchone()
41
+ if boleta:
42
+ return boleta
43
+ else:
44
+ raise HTTPException(status_code=404, detail="Boleta no encontrada")
45
+ except Exception as e:
46
+ print(e)
47
+ return []
48
+
49
+
50
+ # post/boletas -> crear una boleta con una clase pydantic
51
+ class Boleta(BaseModel):
52
+ precio_total: float
53
+ estado_recojo: str
54
+
55
+
56
+ # metodo post de boletas con manejo de errores
57
+ @router.post("/")
58
+ def create_boleta(boleta: Boleta):
59
+ try:
60
+ with DatabaseConnection().get_connection() as conn:
61
+ cursor = conn.cursor()
62
+ cursor.execute(
63
+ "INSERT INTO boleta (precio_total, estado_recojo) VALUES (?, ?)",
64
+ (
65
+ boleta.precio_total,
66
+ boleta.estado_recojo,
67
+ ),
68
+ )
69
+ conn.commit()
70
+ return {"mensaje": "Boleta creada exitosamente"}
71
+ except Exception as e:
72
+ print(e)
73
+ return []
74
+
75
+
76
+ # put/boletas -> actualizar una boleta con una clase pydantic
77
+ class BoletaUpdate(BaseModel):
78
+ id_boleta: int
79
+ precio_total: float
80
+ estado_recojo: str
81
+
82
+
83
+ # metodo put de boletas con manejo de errores
84
+ @router.put("/")
85
+ def update_boleta(boleta: BoletaUpdate):
86
+ try:
87
+ with DatabaseConnection().get_connection() as conn:
88
+ cursor = conn.cursor()
89
+ cursor.execute(
90
+ "UPDATE boleta SET precio_total = ?, estado_recojo = ? WHERE id_boleta = ?",
91
+ (
92
+ boleta.precio_total,
93
+ boleta.estado_recojo,
94
+ boleta.id_boleta,
95
+ ),
96
+ )
97
+ conn.commit()
98
+ return {"mensaje": "Boleta actualizada exitosamente"}
99
+ except Exception as e:
100
+ print(e)
101
+ return []
102
+
103
+
104
+ # delete/boletas -> eliminar una boleta con una clase pydantic
105
+ class BoletaDelete(BaseModel):
106
+ id_boleta: int
107
+
108
+
109
+ # metodo delete de boletas con manejo de errores
110
+ @router.delete("/")
111
+ def delete_boleta(boleta: BoletaDelete):
112
+ try:
113
+ with DatabaseConnection().get_connection() as conn:
114
+ cursor = conn.cursor()
115
+ cursor.execute(
116
+ "DELETE FROM boleta WHERE id_boleta = ?", (boleta.id_boleta,)
117
+ )
118
+ conn.commit()
119
+ return {"mensaje": "Boleta eliminada exitosamente"}
120
+ except Exception as e:
121
+ print(e)
122
+ return []
routers/clientes.py ADDED
@@ -0,0 +1,188 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from library.librerias import *
2
+
3
+ router = APIRouter(
4
+ prefix="/clientes",
5
+ tags=["Clientes"],
6
+ responses={404: {"description": "No encontrado"}},
7
+ )
8
+
9
+
10
+ """
11
+ CREATE TABLE Cliente (
12
+ id_cliente INTEGER PRIMARY KEY AUTOINCREMENT,
13
+ nombres_y_apellidos VARCHAR,
14
+ edad INTEGER,
15
+ telefono INTEGER,
16
+ direccion VARCHAR
17
+ )
18
+ """
19
+
20
+
21
+ # get/clientes -> obtener todos los clientes con with connection as conn, manejo de errores
22
+ @router.get("/")
23
+ def get_clientes():
24
+ try:
25
+ with DatabaseConnection().get_connection() as conn:
26
+ cursor = conn.cursor()
27
+ cursor.execute("SELECT * FROM Cliente")
28
+ clientes = cursor.fetchall()
29
+ return clientes
30
+ except Exception as e:
31
+ print(e)
32
+ return []
33
+
34
+
35
+ @router.get("/{id_cliente}")
36
+ def get_cliente(id_cliente: int):
37
+ try:
38
+ with DatabaseConnection().get_connection() as conn:
39
+ cursor = conn.cursor()
40
+ cursor.execute("SELECT * FROM Cliente WHERE id_cliente = ?", (id_cliente,))
41
+ cliente = cursor.fetchone()
42
+ return cliente
43
+ except Exception as e:
44
+ print(e)
45
+ return []
46
+
47
+
48
+ # metodo de busqueda de cliente por nombre con like, manejo de errores y clase pydantic
49
+ class ClienteNombre(BaseModel):
50
+ nombres_y_apellidos: str
51
+
52
+
53
+ @router.post("/busqueda")
54
+ def post_cliente_busqueda(cliente: ClienteNombre):
55
+ try:
56
+ conn = DatabaseConnection().get_connection()
57
+ cursor = conn.cursor()
58
+ cursor.execute(
59
+ "SELECT * FROM Cliente WHERE nombres_y_apellidos LIKE ?",
60
+ ["%" + cliente.nombres_y_apellidos + "%"],
61
+ )
62
+ cliente = cursor.fetchall()
63
+ if cliente:
64
+ return cliente
65
+ else:
66
+ raise HTTPException(status_code=404, detail="Cliente no encontrado")
67
+ except Exception as e:
68
+ print(e)
69
+ return []
70
+
71
+
72
+ # post/clientes -> crear un cliente con una clase pydantic
73
+ class Cliente(BaseModel):
74
+ nombres_y_apellidos: str
75
+ edad: int
76
+ telefono: int
77
+ direccion: str
78
+
79
+
80
+ @router.post("/")
81
+ def create_cliente(cliente: Cliente):
82
+ try:
83
+ with DatabaseConnection().get_connection() as conn:
84
+ cursor = conn.cursor()
85
+ cursor.execute(
86
+ "INSERT INTO Cliente (nombres_y_apellidos, edad, telefono, direccion) VALUES (?, ?, ?, ?)",
87
+ (
88
+ cliente.nombres_y_apellidos,
89
+ cliente.edad,
90
+ cliente.telefono,
91
+ cliente.direccion,
92
+ ),
93
+ )
94
+ conn.commit()
95
+ return {"mensaje": "Cliente creado exitosamente"}
96
+ except Exception as e:
97
+ print(e)
98
+ return []
99
+
100
+
101
+ # put/clientes -> actualizar un cliente con una clase pydantic
102
+ class ClienteUpdate(BaseModel):
103
+ id_cliente: int
104
+ nombres_y_apellidos: str
105
+ edad: int
106
+ telefono: int
107
+ direccion: str
108
+
109
+
110
+ @router.put("/")
111
+ def update_cliente(cliente: ClienteUpdate):
112
+ try:
113
+ with DatabaseConnection().get_connection() as conn:
114
+ cursor = conn.cursor()
115
+ cursor.execute(
116
+ "UPDATE Cliente SET nombres_y_apellidos = ?, edad = ?, telefono = ?, direccion = ? WHERE id_cliente = ?",
117
+ (
118
+ cliente.nombres_y_apellidos,
119
+ cliente.edad,
120
+ cliente.telefono,
121
+ cliente.direccion,
122
+ cliente.id_cliente,
123
+ ),
124
+ )
125
+ conn.commit()
126
+ return {"mensaje": "Cliente actualizado exitosamente"}
127
+ except Exception as e:
128
+ print(e)
129
+ return []
130
+
131
+
132
+ # delete/clientes -> eliminar un cliente con una clase pydantic
133
+ class ClienteDelete(BaseModel):
134
+ id_cliente: int
135
+
136
+
137
+ # delete/clientes -> eliminar un cliente con una clase pydantic
138
+ @router.delete("/")
139
+ def delete_cliente(cliente: ClienteDelete):
140
+ try:
141
+ with DatabaseConnection().get_connection() as conn:
142
+ cursor = conn.cursor()
143
+ cursor.execute(
144
+ "DELETE FROM Cliente WHERE id_cliente = ?", (cliente.id_cliente,)
145
+ )
146
+ conn.commit()
147
+ return {"mensaje": "Cliente eliminado exitosamente"}
148
+ except Exception as e:
149
+ print(e)
150
+ return []
151
+
152
+
153
+ # Define tu clase Pydantic para el modelo de datos
154
+ class PrescripcionId(BaseModel):
155
+ id_prescripcion: int
156
+
157
+
158
+ # Define tu método de búsqueda de cliente por id de prescripción con manejo de errores y clase Pydantic
159
+ @router.post("/prescripcion")
160
+ def get_cliente_por_prescripcion(prescripcion_id: PrescripcionId):
161
+ try:
162
+ with DatabaseConnection().get_connection() as conn:
163
+ cursor = conn.cursor()
164
+ # Consulta SQL para obtener el cliente a partir del id de la prescripción
165
+ cursor.execute(
166
+ """
167
+ SELECT c.*
168
+ FROM Cliente c
169
+ JOIN Medidas m ON c.id_cliente = m.id_cliente
170
+ JOIN Prescripcion p ON m.id_medidas = p.id_medidas
171
+ WHERE p.id_prescripcion = ?
172
+ """,
173
+ [prescripcion_id.id_prescripcion],
174
+ )
175
+
176
+ cliente = cursor.fetchone()
177
+
178
+ if cliente:
179
+ return cliente
180
+ else:
181
+ raise HTTPException(
182
+ status_code=404,
183
+ detail="Cliente no encontrado para la prescripción proporcionada",
184
+ )
185
+
186
+ except Exception as e:
187
+ print(e)
188
+ return []
routers/comprobante_pago.py ADDED
@@ -0,0 +1,355 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from library.librerias import *
2
+
3
+ router = APIRouter(
4
+ prefix="/comprobante_pago",
5
+ tags=["Comprobante Pago"],
6
+ responses={404: {"description": "No encontrado"}},
7
+ )
8
+
9
+ # Cargar varias tipografías
10
+ pdfmetrics.registerFont(TTFont("Craftcoke", "./font/Craftcoke.ttf"))
11
+ pdfmetrics.registerFont(TTFont("Oregon", "./font/Oregon.ttf"))
12
+ pdfmetrics.registerFont(TTFont("Roboto", "./font/Roboto.ttf"))
13
+
14
+
15
+ def generar_boleta(idboleta, cliente, productos, adelanto, saldo):
16
+ # crear directorio si no existe en pdf/boleta
17
+ directorio_pdf = "pdf/boleta/"
18
+ os.makedirs(directorio_pdf, exist_ok=True)
19
+ # Crear un nombre de archivo único basado en la fecha y hora actual
20
+ now = datetime.now()
21
+ formatted_date_time = now.strftime("%Y%m%d%H%M%S")
22
+ nombre_archivo = f"{directorio_pdf}boleta_{formatted_date_time}.pdf"
23
+
24
+ # Inicializar el lienzo del PDF
25
+ c = canvas.Canvas(nombre_archivo, pagesize=letter)
26
+ ubicacion_inicio = 700
27
+ # Configurar la tipografía para la sección del cliente
28
+ c.setFont("Craftcoke", 30)
29
+ c.drawString(100, ubicacion_inicio, "Arte Visual")
30
+
31
+ # Configurar la tipografía para la sección de productos
32
+ c.setFont("Oregon", 12)
33
+ c.drawString(420, ubicacion_inicio, "NOTA DE PEDIDO")
34
+ # agregar numero de pedido con numero idboleta
35
+ c.drawString(420, ubicacion_inicio - 20, f"N° {str(idboleta).zfill(12)}")
36
+ c.drawString(100, ubicacion_inicio - 20, "Av. Los Héroes 632-S.J.M.")
37
+ # agregar logo de whatsapp de 30x30
38
+ c.drawImage("./img/pdf/logo_whatsapp.jpg", 100, ubicacion_inicio - 43, 12, 12)
39
+ c.drawString(115, ubicacion_inicio - 40, "902-501-054/ 968-600-415")
40
+ # añadir fecha a la derecha
41
+ c.drawString(420, ubicacion_inicio - 40, f"Fecha: {now.strftime('%d/%m/%Y')}")
42
+ # Información del cliente
43
+ c.drawString(
44
+ 100, ubicacion_inicio - 60, f"Señor(a): {cliente['nombres_y_apellidos']}"
45
+ )
46
+ c.drawString(
47
+ 100,
48
+ ubicacion_inicio - 80,
49
+ f"Dirección: {cliente['direccion']}",
50
+ )
51
+ c.drawString(
52
+ 420,
53
+ ubicacion_inicio - 80,
54
+ f"Celular: {cliente['telefono']}",
55
+ )
56
+
57
+ # Configurar la tipografía para la sección de productos
58
+ c.setFont("Oregon", 10)
59
+ c.drawString(100, ubicacion_inicio - 110, "Tabla de productos:")
60
+
61
+ # Crear la tabla de productos
62
+ productos_data = [["Cantidad", "Descripción", "P.Unitario", "Importe"]]
63
+ for producto in productos:
64
+ productos_data.append(
65
+ [
66
+ producto["cantidad"],
67
+ producto["descripcion"],
68
+ f"S/.{producto['precio']:.2f}",
69
+ f"S/.{producto['importe']:.2f}",
70
+ ]
71
+ )
72
+
73
+ # Configurar el estilo de la tabla
74
+ style = TableStyle(
75
+ [
76
+ ("BACKGROUND", (0, 0), (-1, 0), "grey"),
77
+ ("TEXTCOLOR", (0, 0), (-1, 0), "white"),
78
+ ("ALIGN", (0, 0), (-1, -1), "CENTER"),
79
+ ("VALIGN", (0, 0), (-1, -1), "MIDDLE"), # Alineación vertical al centro
80
+ ("FONTNAME", (0, 0), (-1, 0), "Oregon"),
81
+ ("FONTNAME", (0, 1), (-1, -1), "Oregon"),
82
+ ("BOTTOMPADDING", (0, 0), (-1, 0), 12),
83
+ ("BACKGROUND", (0, 1), (-1, -1), "white"),
84
+ ("GRID", (0, 0), (-1, -1), 1, "grey"),
85
+ ]
86
+ )
87
+
88
+ # Crear la tabla y aplicar el estilo
89
+ table = Table(productos_data, colWidths=[50, 220, 80, 80])
90
+ table.setStyle(style)
91
+
92
+ # Dibuja el título de la tabla
93
+ c.drawString(100, ubicacion_inicio - 110, "Tabla de productos:")
94
+
95
+ # Calcula la altura de la tabla
96
+ altura_tabla = table.wrapOn(c, 400, ubicacion_inicio - 350)[1]
97
+
98
+ # Dibuja la tabla
99
+ table.drawOn(c, 100, ubicacion_inicio - 130 - altura_tabla)
100
+
101
+ # Ajusta la ubicación de inicio para los elementos siguientes
102
+ ubicacion_inicio = ubicacion_inicio - 130 - altura_tabla
103
+
104
+ # Información de pago
105
+ c.setFont("Oregon", 12)
106
+ c.drawString(100, ubicacion_inicio - 40, f"Adelanto: S/.{adelanto:.2f}")
107
+ c.drawString(250, ubicacion_inicio - 40, f"Saldo: S/.{saldo:.2f}")
108
+
109
+ # Calcular el total
110
+ total = adelanto + saldo
111
+ c.drawString(450, ubicacion_inicio - 40, f"Total: S/.{total:.2f}")
112
+
113
+ # Guardar y cerrar el archivo PDF
114
+ c.save()
115
+
116
+ print(f"Boleta generada como: {nombre_archivo}")
117
+ return nombre_archivo
118
+
119
+
120
+ def obtener_datos_boleta(id_boleta, adelanto):
121
+ conn = DatabaseConnection().get_connection()
122
+ cursor = conn.cursor()
123
+ query = """
124
+ SELECT
125
+ Cliente.nombres_y_apellidos,
126
+ Cliente.direccion,
127
+ Cliente.telefono,
128
+ lunas_pedido.descripcion AS producto,
129
+ lunas_pedido.precio AS precio_unitario,
130
+ lunas_pedido.cantidad,
131
+ boleta.precio_total AS adelanto,
132
+ boleta.precio_total - COALESCE(SUM(lunas_pedido.precio * lunas_pedido.cantidad), 0) AS saldo,
133
+ montura_pedido.id_montura_pedido,
134
+ montura_pedido.cantidad AS cantidad_monturas,
135
+ montura_inventario.precio_unit AS precio_unitario_monturas,
136
+ montura.nombre_montura,
137
+ montura.marca,
138
+ montura.color,
139
+ montura.material
140
+ FROM boleta
141
+ JOIN lunas_pedido ON boleta.id_boleta = lunas_pedido.id_boleta
142
+ JOIN Prescripcion ON lunas_pedido.id_prescripcion = Prescripcion.id_prescripcion
143
+ JOIN Medidas ON Prescripcion.id_medidas = Medidas.id_medidas
144
+ JOIN Cliente ON Medidas.id_cliente = Cliente.id_cliente
145
+ LEFT JOIN montura_pedido ON boleta.id_boleta = montura_pedido.id_boleta
146
+ LEFT JOIN montura_inventario ON montura_pedido.id_montura_inventario = montura_inventario.id_montura_inventario
147
+ LEFT JOIN montura ON montura_inventario.id_montura = montura.id_montura
148
+ WHERE boleta.id_boleta = ?
149
+ GROUP BY boleta.id_boleta
150
+ """
151
+
152
+ cursor.execute(query, (id_boleta,))
153
+ datos = cursor.fetchone()
154
+
155
+ conn.close()
156
+
157
+ return datos
158
+
159
+
160
+ def obtener_productos_por_boleta(id_boleta):
161
+ # Conectarse a la base de datos SQLite
162
+ conn = DatabaseConnection().get_connection()
163
+ cursor = conn.cursor()
164
+
165
+ # Consulta para monturas
166
+ query_monturas = f"""
167
+ SELECT
168
+ mp.cantidad AS cantidad,
169
+ mi.codigo AS codigo_montura,
170
+ m.nombre_montura AS nombre_montura,
171
+ m.marca,
172
+ m.color,
173
+ m.material,
174
+ mi.precio_unit AS precio_unitario,
175
+ (mi.precio_unit * mp.cantidad) AS importe
176
+ FROM
177
+ montura_pedido mp
178
+ JOIN
179
+ montura_inventario mi ON mp.id_montura_inventario = mi.id_montura_inventario
180
+ JOIN
181
+ montura m ON mi.id_montura = m.id_montura
182
+ WHERE
183
+ mp.id_boleta = {id_boleta};
184
+ """
185
+
186
+ cursor.execute(query_monturas)
187
+ resultados_monturas = cursor.fetchall()
188
+
189
+ # Consulta para lunas
190
+ query_lunas = f"""
191
+ SELECT
192
+ lp.cantidad AS cantidad,
193
+ p.detalle_lunas AS descripcion,
194
+ lp.precio AS precio,
195
+ (lp.precio * lp.cantidad) AS importe
196
+ FROM
197
+ lunas_pedido lp
198
+ JOIN
199
+ boleta b ON lp.id_boleta = b.id_boleta
200
+ JOIN
201
+ prescripcion p ON lp.id_prescripcion = p.id_prescripcion
202
+ WHERE
203
+ b.id_boleta = {id_boleta};
204
+ """
205
+
206
+ cursor.execute(query_lunas)
207
+ resultados_lunas = cursor.fetchall()
208
+ # Cerrar la conexión a la base de datos
209
+ conn.close()
210
+
211
+ # Crear un diccionario combinado con los resultados
212
+ productos = []
213
+ print("Esta es la cantidad de monturas y lunas:")
214
+ print(f"Monturas: {len(resultados_monturas)}")
215
+ print(f"Lunas: {len(resultados_lunas)}")
216
+ # validacion si hay monturas
217
+ if len(resultados_monturas) > 0:
218
+ # Agregar monturas al diccionario
219
+ for resultado_montura in resultados_monturas:
220
+ producto_montura = {
221
+ "cantidad": resultado_montura[0],
222
+ "descripcion": f"Código: {resultado_montura[1]}, \nNombre: {resultado_montura[2]}, \nMarca: {resultado_montura[3]}, \nColor: {resultado_montura[4]}, \nMaterial: {resultado_montura[5]}",
223
+ "precio": resultado_montura[6],
224
+ "importe": resultado_montura[7],
225
+ }
226
+ productos.append(producto_montura)
227
+ # validacion si hay lunas
228
+ if len(resultados_lunas) > 0:
229
+ # Agregar lunas al diccionario
230
+ for resultado_luna in resultados_lunas:
231
+ producto_luna = {
232
+ "cantidad": resultado_luna[0],
233
+ "descripcion": resultado_luna[1],
234
+ "precio": resultado_luna[2],
235
+ "importe": resultado_luna[3],
236
+ }
237
+ productos.append(producto_luna)
238
+
239
+ return productos
240
+
241
+
242
+ def generar_boleta_desde_bd(id_boleta, adelanto):
243
+ # Obtener datos de la boleta desde la base de datos
244
+ datos = obtener_datos_boleta(id_boleta, adelanto)
245
+
246
+ if datos:
247
+ # Crear boleta usando los datos calculados
248
+ cliente = {
249
+ "nombres_y_apellidos": datos["nombres_y_apellidos"],
250
+ "direccion": datos["direccion"],
251
+ "telefono": datos["telefono"],
252
+ }
253
+ productos = obtener_productos_por_boleta(id_boleta)
254
+ # Calcular total y saldo
255
+ total = sum(
256
+ [producto["cantidad"] * producto["precio"] for producto in productos]
257
+ )
258
+ saldo = total - adelanto
259
+ # Generar la boleta
260
+ archivo_pdf_ok = generar_boleta(id_boleta, cliente, productos, adelanto, saldo)
261
+ print(archivo_pdf_ok)
262
+ else:
263
+ print(f"No se encontraron datos para la boleta con ID {id_boleta}.")
264
+
265
+
266
+ # endpoint retorna el pdf de la boleta con idboleta y adelanto
267
+ @router.get("/descargarPDF/{id_boleta}/{adelanto}")
268
+ def descargar_pdf_boleta_get(id_boleta: int, adelanto: float):
269
+ try:
270
+ directorio_pdf = "pdf/boleta/"
271
+ now = datetime.now()
272
+ formatted_date_time = now.strftime("%Y%m%d%H%M%S")
273
+ nombre_archivo = f"{directorio_pdf}boleta_{formatted_date_time}.pdf"
274
+ # crear pdf
275
+ generar_boleta_desde_bd(id_boleta, adelanto)
276
+ # validacion si existe el archivo o no y retorna el archivo pdf
277
+ if os.path.exists(nombre_archivo):
278
+ # return nombre_archivo
279
+ return FileResponse(
280
+ nombre_archivo,
281
+ media_type="application/pdf",
282
+ filename=nombre_archivo,
283
+ )
284
+ else:
285
+ raise HTTPException(
286
+ status_code=404, detail="No se encontró la boleta solicitada"
287
+ )
288
+ except Exception as e:
289
+ print(e)
290
+ return []
291
+
292
+
293
+ # crear endpoint retornando la url del PDF con los datos de la prescripción
294
+ @router.get("/verPDF/{id_boleta}/{adelanto}")
295
+ def ver_pdf_boleta_get(id_boleta: int, adelanto: float):
296
+ try:
297
+ directorio_pdf = "pdf/boleta/"
298
+ formatted_date_time = datetime.now().strftime("%Y%m%d%H%M%S")
299
+ nombre_archivo = f"{directorio_pdf}boleta_{formatted_date_time}.pdf"
300
+ generar_boleta_desde_bd(id_boleta, adelanto)
301
+ if os.path.exists(nombre_archivo):
302
+ return FileResponse(path=nombre_archivo)
303
+ else:
304
+ raise HTTPException(
305
+ status_code=404, detail="No se encontró la boleta solicitada"
306
+ )
307
+ except Exception as e:
308
+ print(e)
309
+ return []
310
+
311
+
312
+ # clase boletaPDF para recibir los datos de la boleta
313
+ class BoletaPDF(BaseModel):
314
+ id_boleta: int
315
+ adelanto: float
316
+
317
+
318
+ # ruta para generar boleta en pdf con manejo de errores en caso no se encuentre la boleta
319
+ @router.post("/descargarPDF")
320
+ def descargar_boleta_pdf_post(boleta_pdf: BoletaPDF):
321
+ try:
322
+ directorio_pdf = "pdf/boleta/"
323
+ now = datetime.now()
324
+ formatted_date_time = now.strftime("%Y%m%d%H%M%S")
325
+ nombre_archivo = f"{directorio_pdf}boleta_{formatted_date_time}.pdf"
326
+ # crear pdf
327
+ generar_boleta_desde_bd(boleta_pdf.id_boleta, boleta_pdf.adelanto)
328
+ # validacion si existe el archivo o no
329
+ if os.path.exists(nombre_archivo):
330
+ return FileResponse(
331
+ nombre_archivo,
332
+ media_type="application/pdf",
333
+ filename=nombre_archivo,
334
+ )
335
+ else:
336
+ raise HTTPException(
337
+ status_code=404, detail="No se encontró la boleta solicitada"
338
+ )
339
+ except Exception as e:
340
+ print(e)
341
+ return []
342
+
343
+
344
+ # get obtiene la ultima boleta creada
345
+ @router.get("/ultima")
346
+ def get_ultima_boleta():
347
+ try:
348
+ with DatabaseConnection().get_connection() as conn:
349
+ cursor = conn.cursor()
350
+ cursor.execute("SELECT * FROM boleta ORDER BY id_boleta DESC LIMIT 1")
351
+ boleta = cursor.fetchone()
352
+ return boleta
353
+ except Exception as e:
354
+ print(e)
355
+ return []
routers/lunas_pedido.py ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from library.librerias import *
2
+
3
+ router = APIRouter(
4
+ prefix="/lunas_pedido",
5
+ tags=["Lunas Pedido"],
6
+ responses={404: {"description": "No encontrado"}},
7
+ )
8
+
9
+
10
+ """
11
+ Table lunas_pedido {
12
+ id_lunas_pedido INTEGER [primary key, unique, increment]
13
+ id_prescripcion INTEGER [ref: > Prescripcion.id_prescripcion]
14
+ precio REAL
15
+ id_boleta INTEGER [ref: > boleta.id_boleta]
16
+ descripcion VARCHAR
17
+ cantidad INTEGER
18
+ }
19
+ """
20
+
21
+
22
+ # get
23
+ @router.get("/")
24
+ def get_lunas_pedido():
25
+ try:
26
+ with DatabaseConnection().get_connection() as conn:
27
+ cursor = conn.cursor()
28
+ cursor.execute("SELECT * FROM lunas_pedido")
29
+ lunas_pedido = cursor.fetchall()
30
+ return lunas_pedido
31
+ except Exception as e:
32
+ print(e)
33
+ return []
34
+
35
+
36
+ # post con pydantic
37
+ class LunasPedido(BaseModel):
38
+ id_prescripcion: int
39
+ precio: float
40
+ id_boleta: int
41
+ descripcion: str
42
+ cantidad: int
43
+
44
+
45
+ @router.post("/")
46
+ def create_lunas_pedido(lunas_pedido: LunasPedido):
47
+ try:
48
+ with DatabaseConnection().get_connection() as conn:
49
+ cursor = conn.cursor()
50
+ cursor.execute(
51
+ "INSERT INTO lunas_pedido (id_prescripcion, precio, id_boleta, descripcion, cantidad) VALUES (?, ?, ?, ?, ?)",
52
+ (
53
+ lunas_pedido.id_prescripcion,
54
+ lunas_pedido.precio,
55
+ lunas_pedido.id_boleta,
56
+ lunas_pedido.descripcion,
57
+ lunas_pedido.cantidad,
58
+ ),
59
+ )
60
+ conn.commit()
61
+ return {"mensaje": "Lunas_pedido creada exitosamente"}
62
+ except Exception as e:
63
+ print(e)
64
+ return []
65
+
66
+
67
+ # put con pydantic
68
+ class LunasPedidoUpdate(BaseModel):
69
+ id_lunas_pedido: int
70
+ id_prescripcion: int
71
+ precio: float
72
+ id_boleta: int
73
+ descripcion: str
74
+ cantidad: int
75
+
76
+
77
+ @router.put("/")
78
+ def update_lunas_pedido(lunas_pedido: LunasPedidoUpdate):
79
+ try:
80
+ with DatabaseConnection().get_connection() as conn:
81
+ cursor = conn.cursor()
82
+ cursor.execute(
83
+ "UPDATE lunas_pedido SET id_prescripcion = ?, precio = ?, id_boleta = ?, descripcion = ?, cantidad = ? WHERE id_lunas_pedido = ?",
84
+ (
85
+ lunas_pedido.id_prescripcion,
86
+ lunas_pedido.precio,
87
+ lunas_pedido.id_boleta,
88
+ lunas_pedido.descripcion,
89
+ lunas_pedido.cantidad,
90
+ lunas_pedido.id_lunas_pedido,
91
+ ),
92
+ )
93
+ conn.commit()
94
+ return {"mensaje": "Lunas_pedido actualizada exitosamente"}
95
+ except Exception as e:
96
+ print(e)
97
+ return []
98
+
99
+
100
+ # delete con pydantic
101
+ class LunasPedidoDelete(BaseModel):
102
+ id_lunas_pedido: int
103
+
104
+
105
+ @router.delete("/")
106
+ def delete_lunas_pedido(lunas_pedido: LunasPedidoDelete):
107
+ try:
108
+ with DatabaseConnection().get_connection() as conn:
109
+ cursor = conn.cursor()
110
+ cursor.execute(
111
+ "DELETE FROM lunas_pedido WHERE id_lunas_pedido = ?",
112
+ (lunas_pedido.id_lunas_pedido,),
113
+ )
114
+ conn.commit()
115
+ return {"mensaje": "Lunas_pedido eliminada exitosamente"}
116
+ except Exception as e:
117
+ print(e)
118
+ return []
routers/medidas.py ADDED
@@ -0,0 +1,217 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from library.librerias import *
2
+
3
+ router = APIRouter(
4
+ prefix="/medidas",
5
+ tags=["Medidas"],
6
+ responses={404: {"description": "No encontrado"}},
7
+ )
8
+
9
+
10
+ """
11
+ CREATE TABLE Medidas (
12
+ id_medidas INTEGER PRIMARY KEY AUTOINCREMENT,
13
+ Esfera_OD_lejos REAL,
14
+ Cilindro_OD_lejos REAL,
15
+ Eje_OD_lejos REAL,
16
+ Agudeza_visual_OD_lejos REAL,
17
+ Esfera_OI_lejos REAL,
18
+ Cilindro_OI_lejos REAL,
19
+ Eje_OI_lejos REAL,
20
+ Agudeza_visual_OI_lejos REAL,
21
+ Esfera_OD_cerca REAL,
22
+ Cilindro_OD_cerca REAL,
23
+ Eje_OD_cerca REAL,
24
+ Agudeza_visual_OD_cerca REAL,
25
+ Esfera_OI_cerca REAL,
26
+ Cilindro_OI_cerca REAL,
27
+ Eje_OI_cerca REAL,
28
+ Agudeza_visual_OI_cerca REAL,
29
+ id_cliente INTEGER REFERENCES Cliente(id_cliente)
30
+ )
31
+ """
32
+
33
+
34
+ # get/medidas -> obtener todas las medidas con with connection as conn, manejo de errores
35
+ @router.get("/")
36
+ def get_medidas():
37
+ try:
38
+ with DatabaseConnection().get_connection() as conn:
39
+ cursor = conn.cursor()
40
+ cursor.execute("SELECT * FROM Medidas")
41
+ medidas = cursor.fetchall()
42
+ return medidas
43
+ except Exception as e:
44
+ print(e)
45
+ return []
46
+
47
+
48
+ # get/medidas/{id_medidas} -> obtener una medida por id
49
+ @router.get("/{id_medidas}")
50
+ def get_medida(id_medidas: int):
51
+ try:
52
+ with DatabaseConnection().get_connection() as conn:
53
+ cursor = conn.cursor()
54
+ cursor.execute("SELECT * FROM Medidas WHERE id_medidas = ?", (id_medidas,))
55
+ medida = cursor.fetchone()
56
+ return medida
57
+ except Exception as e:
58
+ print(e)
59
+ return []
60
+
61
+
62
+ # metodo de busqueda que sea por id_cliente y retorne las medidas asociadas a ese cliente con clase y metodo post
63
+ class MedidasCliente(BaseModel):
64
+ id_cliente: int
65
+
66
+
67
+ @router.post("/busqueda")
68
+ def buscar_medida(medida: MedidasCliente):
69
+ try:
70
+ with DatabaseConnection().get_connection() as conn:
71
+ cursor = conn.cursor()
72
+ cursor.execute(
73
+ "SELECT * FROM Medidas WHERE id_cliente = ?",
74
+ (medida.id_cliente,),
75
+ )
76
+ medida = cursor.fetchall()
77
+ if medida:
78
+ return medida
79
+ else:
80
+ raise HTTPException(status_code=404, detail="Medida no encontrada")
81
+ except Exception as e:
82
+ print(e)
83
+ return []
84
+
85
+
86
+ # post/medidas -> crear una medida con una clase pydantic
87
+ class Medida(BaseModel):
88
+ Esfera_OD_lejos: float
89
+ Cilindro_OD_lejos: float
90
+ Eje_OD_lejos: float
91
+ Agudeza_visual_OD_lejos: float
92
+ Esfera_OI_lejos: float
93
+ Cilindro_OI_lejos: float
94
+ Eje_OI_lejos: float
95
+ Agudeza_visual_OI_lejos: float
96
+ Esfera_OD_cerca: float
97
+ Cilindro_OD_cerca: float
98
+ Eje_OD_cerca: float
99
+ Agudeza_visual_OD_cerca: float
100
+ Esfera_OI_cerca: float
101
+ Cilindro_OI_cerca: float
102
+ Eje_OI_cerca: float
103
+ Agudeza_visual_OI_cerca: float
104
+ id_cliente: int
105
+
106
+
107
+ @router.post("/")
108
+ def create_medida(medida: Medida):
109
+ try:
110
+ with DatabaseConnection().get_connection() as conn:
111
+ cursor = conn.cursor()
112
+ cursor.execute(
113
+ "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 (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
114
+ [
115
+ medida.Esfera_OD_lejos,
116
+ medida.Cilindro_OD_lejos,
117
+ medida.Eje_OD_lejos,
118
+ medida.Agudeza_visual_OD_lejos,
119
+ medida.Esfera_OI_lejos,
120
+ medida.Cilindro_OI_lejos,
121
+ medida.Eje_OI_lejos,
122
+ medida.Agudeza_visual_OI_lejos,
123
+ medida.Esfera_OD_cerca,
124
+ medida.Cilindro_OD_cerca,
125
+ medida.Eje_OD_cerca,
126
+ medida.Agudeza_visual_OD_cerca,
127
+ medida.Esfera_OI_cerca,
128
+ medida.Cilindro_OI_cerca,
129
+ medida.Eje_OI_cerca,
130
+ medida.Agudeza_visual_OI_cerca,
131
+ medida.id_cliente,
132
+ ],
133
+ )
134
+ conn.commit()
135
+ return {"mensaje": "Medida creada correctamente"}
136
+ except Exception as e:
137
+ print(e)
138
+ return []
139
+
140
+
141
+ # put/medidas -> actualizar una medida con una clase pydantic
142
+ class MedidaUpdate(BaseModel):
143
+ id_medidas: int
144
+ Esfera_OD_lejos: float
145
+ Cilindro_OD_lejos: float
146
+ Eje_OD_lejos: float
147
+ Agudeza_visual_OD_lejos: float
148
+ Esfera_OI_lejos: float
149
+ Cilindro_OI_lejos: float
150
+ Eje_OI_lejos: float
151
+ Agudeza_visual_OI_lejos: float
152
+ Esfera_OD_cerca: float
153
+ Cilindro_OD_cerca: float
154
+ Eje_OD_cerca: float
155
+ Agudeza_visual_OD_cerca: float
156
+ Esfera_OI_cerca: float
157
+ Cilindro_OI_cerca: float
158
+ Eje_OI_cerca: float
159
+ Agudeza_visual_OI_cerca: float
160
+ id_cliente: int
161
+
162
+
163
+ # metodo put de medidas con manejo de errores
164
+ @router.put("/")
165
+ def update_medida(medida: MedidaUpdate):
166
+ try:
167
+ with DatabaseConnection().get_connection() as conn:
168
+ cursor = conn.cursor()
169
+ cursor.execute(
170
+ "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 = ?",
171
+ [
172
+ medida.Esfera_OD_lejos,
173
+ medida.Cilindro_OD_lejos,
174
+ medida.Eje_OD_lejos,
175
+ medida.Agudeza_visual_OD_lejos,
176
+ medida.Esfera_OI_lejos,
177
+ medida.Cilindro_OI_lejos,
178
+ medida.Eje_OI_lejos,
179
+ medida.Agudeza_visual_OI_lejos,
180
+ medida.Esfera_OD_cerca,
181
+ medida.Cilindro_OD_cerca,
182
+ medida.Eje_OD_cerca,
183
+ medida.Agudeza_visual_OD_cerca,
184
+ medida.Esfera_OI_cerca,
185
+ medida.Cilindro_OI_cerca,
186
+ medida.Eje_OI_cerca,
187
+ medida.Agudeza_visual_OI_cerca,
188
+ medida.id_cliente,
189
+ medida.id_medidas,
190
+ ],
191
+ )
192
+ conn.commit()
193
+ return {"mensaje": "Medida actualizada correctamente"}
194
+ except Exception as e:
195
+ print(e)
196
+ return []
197
+
198
+
199
+ # delete/medidas -> eliminar una medida con una clase pydantic
200
+ class MedidaDelete(BaseModel):
201
+ id_medidas: int
202
+
203
+
204
+ # metodo delete de medidas con manejo de errores
205
+ @router.delete("/")
206
+ def delete_medida(medida: MedidaDelete):
207
+ try:
208
+ with DatabaseConnection().get_connection() as conn:
209
+ cursor = conn.cursor()
210
+ cursor.execute(
211
+ "DELETE FROM Medidas WHERE id_medidas = ?", (medida.id_medidas,)
212
+ )
213
+ conn.commit()
214
+ return {"mensaje": "Medida eliminada exitosamente"}
215
+ except Exception as e:
216
+ print(e)
217
+ return []
routers/monturas.py ADDED
@@ -0,0 +1,158 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from library.librerias import *
2
+
3
+ router = APIRouter(
4
+ prefix="/monturas",
5
+ tags=["Monturas"],
6
+ responses={404: {"description": "No encontrado"}},
7
+ )
8
+
9
+ """
10
+ CREATE TABLE Montura (
11
+ id_montura INTEGER PRIMARY KEY AUTOINCREMENT,
12
+ nombre_montura VARCHAR,
13
+ imagen VARCHAR,
14
+ marca VARCHAR,
15
+ color VARCHAR,
16
+ material VARCHAR
17
+ )
18
+ """
19
+
20
+
21
+ # get/monturas -> obtener todas las monturas con with connection as conn, manejo de errores
22
+ @router.get("/")
23
+ def get_monturas():
24
+ try:
25
+ with DatabaseConnection().get_connection() as conn:
26
+ cursor = conn.cursor()
27
+ cursor.execute("SELECT * FROM Montura")
28
+ monturas = cursor.fetchall()
29
+ return monturas
30
+ except Exception as e:
31
+ print(e)
32
+ return []
33
+
34
+
35
+ # get/monturas/{id_montura} -> obtener una montura por id
36
+ @router.get("/{id_montura}")
37
+ def get_montura(id_montura: int):
38
+ try:
39
+ with DatabaseConnection().get_connection() as conn:
40
+ cursor = conn.cursor()
41
+ cursor.execute("SELECT * FROM Montura WHERE id_montura = ?", (id_montura,))
42
+ montura = cursor.fetchone()
43
+ return montura
44
+ except Exception as e:
45
+ print(e)
46
+ return []
47
+
48
+
49
+ # busqueda de montura por nombre con like, manejo de errores y clase pydantic
50
+ class MonturaNombre(BaseModel):
51
+ nombre_montura: str
52
+
53
+
54
+ # post/monturas/busqueda -> buscar montura por nombre
55
+ @router.post("/busqueda")
56
+ def buscar_montura(montura: MonturaNombre):
57
+ try:
58
+ with DatabaseConnection().get_connection() as conn:
59
+ cursor = conn.cursor()
60
+ cursor.execute(
61
+ "SELECT * FROM Montura WHERE nombre_montura LIKE ?",
62
+ (montura.nombre_montura,),
63
+ )
64
+ montura = cursor.fetchall()
65
+ if montura:
66
+ return montura
67
+ else:
68
+ raise HTTPException(status_code=404, detail="Montura no encontrada")
69
+ except Exception as e:
70
+ print(e)
71
+ return []
72
+
73
+
74
+ # post/monturas -> crear una montura con una clase pydantic
75
+ class Montura(BaseModel):
76
+ nombre_montura: str
77
+ imagen: str
78
+ marca: str
79
+ color: str
80
+ material: str
81
+
82
+
83
+ # metodo post de monturas con manejo de errores
84
+ @router.post("/")
85
+ def create_montura(montura: Montura):
86
+ try:
87
+ with DatabaseConnection().get_connection() as conn:
88
+ cursor = conn.cursor()
89
+ cursor.execute(
90
+ "INSERT INTO Montura (nombre_montura, imagen, marca, color, material) VALUES (?, ?, ?, ?, ?)",
91
+ (
92
+ montura.nombre_montura,
93
+ montura.imagen,
94
+ montura.marca,
95
+ montura.color,
96
+ montura.material,
97
+ ),
98
+ )
99
+ conn.commit()
100
+ return {"mensaje": "Montura creada exitosamente"}
101
+ except Exception as e:
102
+ print(e)
103
+ return []
104
+
105
+
106
+ # put/monturas -> actualizar una montura con una clase pydantic
107
+ class MonturaUpdate(BaseModel):
108
+ id_montura: int
109
+ nombre_montura: str
110
+ imagen: str
111
+ marca: str
112
+ color: str
113
+ material: str
114
+
115
+
116
+ # metodo put de monturas con manejo de errores
117
+ @router.put("/")
118
+ def update_montura(montura: MonturaUpdate):
119
+ try:
120
+ with DatabaseConnection().get_connection() as conn:
121
+ cursor = conn.cursor()
122
+ cursor.execute(
123
+ "UPDATE Montura SET nombre_montura = ?, imagen = ?, marca = ?, color = ?, material = ? WHERE id_montura = ?",
124
+ (
125
+ montura.nombre_montura,
126
+ montura.imagen,
127
+ montura.marca,
128
+ montura.color,
129
+ montura.material,
130
+ montura.id_montura,
131
+ ),
132
+ )
133
+ conn.commit()
134
+ return {"mensaje": "Montura actualizada exitosamente"}
135
+ except Exception as e:
136
+ print(e)
137
+ return []
138
+
139
+
140
+ # delete/monturas -> eliminar una montura con una clase pydantic
141
+ class MonturaDelete(BaseModel):
142
+ id_montura: int
143
+
144
+
145
+ # metodo delete de monturas con manejo de errores
146
+ @router.delete("/")
147
+ def delete_montura(montura: MonturaDelete):
148
+ try:
149
+ with DatabaseConnection().get_connection() as conn:
150
+ cursor = conn.cursor()
151
+ cursor.execute(
152
+ "DELETE FROM Montura WHERE id_montura = ?", (montura.id_montura,)
153
+ )
154
+ conn.commit()
155
+ return {"mensaje": "Montura eliminada exitosamente"}
156
+ except Exception as e:
157
+ print(e)
158
+ return []
routers/monturas_inventario.py ADDED
@@ -0,0 +1,160 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from library.librerias import *
2
+
3
+ router = APIRouter(
4
+ prefix="/monturas_inventario",
5
+ tags=["Monturas Inventario"],
6
+ responses={404: {"description": "No encontrado"}},
7
+ )
8
+
9
+
10
+ """
11
+ CREATE TABLE Montura_inventario (
12
+ id_montura_inventario INTEGER PRIMARY KEY AUTOINCREMENT,
13
+ id_montura INTEGER REFERENCES Montura(id_montura),
14
+ precio_unit REAL,
15
+ stock INTEGER,
16
+ codigo VARCHAR
17
+ )
18
+ """
19
+
20
+
21
+ # get/monturas_inventario -> obtener todas las monturas_inventario con with connection as conn, manejo de errores
22
+ @router.get("/")
23
+ def get_monturas_inventario():
24
+ try:
25
+ with DatabaseConnection().get_connection() as conn:
26
+ cursor = conn.cursor()
27
+ cursor.execute("SELECT * FROM Montura_inventario")
28
+ monturas_inventario = cursor.fetchall()
29
+ return monturas_inventario
30
+ except Exception as e:
31
+ print(e)
32
+ return []
33
+
34
+
35
+ # get/monturas_inventario/{id_montura_inventario} -> obtener una montura_inventario por id
36
+ @router.get("/{id_montura_inventario}")
37
+ def get_montura_inventario(id_montura_inventario: int):
38
+ try:
39
+ with DatabaseConnection().get_connection() as conn:
40
+ cursor = conn.cursor()
41
+ cursor.execute(
42
+ "SELECT * FROM Montura_inventario WHERE id_montura_inventario = ?",
43
+ (id_montura_inventario,),
44
+ )
45
+ montura_inventario = cursor.fetchone()
46
+ return montura_inventario
47
+ except Exception as e:
48
+ print(e)
49
+ return []
50
+
51
+
52
+ # post/monturas_inventario -> crear una montura_inventario con una clase pydantic
53
+ class Montura_inventario(BaseModel):
54
+ id_montura: int
55
+ precio_unit: float
56
+ stock: int
57
+ codigo: str
58
+
59
+
60
+ # metodo post de monturas_inventario con manejo de errores
61
+ @router.post("/")
62
+ def create_montura_inventario(montura_inventario: Montura_inventario):
63
+ try:
64
+ with DatabaseConnection().get_connection() as conn:
65
+ cursor = conn.cursor()
66
+ cursor.execute(
67
+ "INSERT INTO Montura_inventario (id_montura, precio_unit, stock, codigo) VALUES (?, ?, ?, ?)",
68
+ (
69
+ montura_inventario.id_montura,
70
+ montura_inventario.precio_unit,
71
+ montura_inventario.stock,
72
+ montura_inventario.codigo,
73
+ ),
74
+ )
75
+ conn.commit()
76
+ return {"mensaje": "Montura_inventario creada exitosamente"}
77
+ except Exception as e:
78
+ print(e)
79
+ return []
80
+
81
+
82
+ # busqueda de montura_inventario por codigo con like, manejo de errores y clase pydantic
83
+ class Montura_inventarioCodigo(BaseModel):
84
+ codigo: str
85
+
86
+
87
+ # post/monturas_inventario/busqueda -> buscar una montura_inventario por codigo
88
+ @router.post("/busqueda")
89
+ def buscar_montura_inventario(montura_inventario: Montura_inventarioCodigo):
90
+ try:
91
+ with DatabaseConnection().get_connection() as conn:
92
+ cursor = conn.cursor()
93
+ cursor.execute(
94
+ "SELECT * FROM Montura_inventario WHERE codigo LIKE ?",
95
+ (montura_inventario.codigo,),
96
+ )
97
+ montura_inventario = cursor.fetchall()
98
+ if montura_inventario:
99
+ return montura_inventario
100
+ else:
101
+ raise HTTPException(
102
+ status_code=404, detail="Montura_inventario no encontrada"
103
+ )
104
+ except Exception as e:
105
+ print(e)
106
+ return []
107
+
108
+
109
+ # put/monturas_inventario -> actualizar una montura_inventario con una clase pydantic
110
+ class Montura_inventarioUpdate(BaseModel):
111
+ id_montura_inventario: int
112
+ id_montura: int
113
+ precio_unit: float
114
+ stock: int
115
+ codigo: str
116
+
117
+
118
+ # metodo put de monturas_inventario con manejo de errores
119
+ @router.put("/")
120
+ def update_montura_inventario(montura_inventario: Montura_inventarioUpdate):
121
+ try:
122
+ with DatabaseConnection().get_connection() as conn:
123
+ cursor = conn.cursor()
124
+ cursor.execute(
125
+ "UPDATE Montura_inventario SET id_montura = ?, precio_unit = ?, stock = ?, codigo = ? WHERE id_montura_inventario = ?",
126
+ (
127
+ montura_inventario.id_montura,
128
+ montura_inventario.precio_unit,
129
+ montura_inventario.stock,
130
+ montura_inventario.codigo,
131
+ montura_inventario.id_montura_inventario,
132
+ ),
133
+ )
134
+ conn.commit()
135
+ return {"mensaje": "Montura_inventario actualizada exitosamente"}
136
+ except Exception as e:
137
+ print(e)
138
+ return []
139
+
140
+
141
+ # delete/monturas_inventario -> eliminar una montura_inventario con una clase pydantic
142
+ class Montura_inventarioDelete(BaseModel):
143
+ id_montura_inventario: int
144
+
145
+
146
+ # metodo delete de monturas_inventario con manejo de errores
147
+ @router.delete("/")
148
+ def delete_montura_inventario(montura_inventario: Montura_inventarioDelete):
149
+ try:
150
+ with DatabaseConnection().get_connection() as conn:
151
+ cursor = conn.cursor()
152
+ cursor.execute(
153
+ "DELETE FROM Montura_inventario WHERE id_montura_inventario = ?",
154
+ (montura_inventario.id_montura_inventario,),
155
+ )
156
+ conn.commit()
157
+ return {"mensaje": "Montura_inventario eliminada exitosamente"}
158
+ except Exception as e:
159
+ print(e)
160
+ return []
routers/monturas_pedido.py ADDED
@@ -0,0 +1,133 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from library.librerias import *
2
+
3
+ router = APIRouter(
4
+ prefix="/monturas_pedido",
5
+ tags=["Monturas Pedido"],
6
+ responses={404: {"description": "No encontrado"}},
7
+ )
8
+
9
+
10
+ """
11
+ CREATE TABLE montura_pedido (
12
+ id_montura_pedido INTEGER PRIMARY KEY AUTOINCREMENT,
13
+ id_montura_inventario INTEGER REFERENCES Montura_inventario(id_montura_inventario),
14
+ cantidad INTEGER,
15
+ precio REAL,
16
+ id_boleta INTEGER REFERENCES boleta(id_boleta)
17
+ )
18
+ """
19
+
20
+
21
+ # get/monturas_pedidos -> obtener todas las monturas_pedidos con with connection as conn, manejo de errores
22
+ @router.get("/")
23
+ def get_monturas_pedidos():
24
+ try:
25
+ with DatabaseConnection().get_connection() as conn:
26
+ cursor = conn.cursor()
27
+ cursor.execute("SELECT * FROM montura_pedido")
28
+ monturas_pedidos = cursor.fetchall()
29
+ return monturas_pedidos
30
+ except Exception as e:
31
+ print(e)
32
+ return []
33
+
34
+
35
+ # get/monturas_pedidos/{id_montura_pedido} -> obtener una montura_pedido por id
36
+ @router.get("/{id_montura_pedido}")
37
+ def get_montura_pedido(id_montura_pedido: int):
38
+ try:
39
+ with DatabaseConnection().get_connection() as conn:
40
+ cursor = conn.cursor()
41
+ cursor.execute(
42
+ "SELECT * FROM montura_pedido WHERE id_montura_pedido = ?",
43
+ (id_montura_pedido,),
44
+ )
45
+ montura_pedido = cursor.fetchone()
46
+ return montura_pedido
47
+ except Exception as e:
48
+ print(e)
49
+ return []
50
+
51
+
52
+ # post/monturas_pedidos -> crear una montura_pedido con una clase pydantic
53
+ class Montura_pedido(BaseModel):
54
+ id_montura_inventario: int
55
+ cantidad: int
56
+ precio: float
57
+ id_boleta: int
58
+
59
+
60
+ # metodo post de monturas_pedidos con manejo de errores
61
+ @router.post("/")
62
+ def create_montura_pedido(montura_pedido: Montura_pedido):
63
+ try:
64
+ with DatabaseConnection().get_connection() as conn:
65
+ cursor = conn.cursor()
66
+ cursor.execute(
67
+ "INSERT INTO montura_pedido (id_montura_inventario, cantidad, precio, id_boleta) VALUES (?, ?, ?, ?)",
68
+ (
69
+ montura_pedido.id_montura_inventario,
70
+ montura_pedido.cantidad,
71
+ montura_pedido.precio,
72
+ montura_pedido.id_boleta,
73
+ ),
74
+ )
75
+ conn.commit()
76
+ return {"mensaje": "Montura_pedido creada exitosamente"}
77
+ except Exception as e:
78
+ print(e)
79
+ return []
80
+
81
+
82
+ # put/monturas_pedidos -> actualizar una montura_pedido con una clase pydantic
83
+ class Montura_pedidoUpdate(BaseModel):
84
+ id_montura_pedido: int
85
+ id_montura_inventario: int
86
+ cantidad: int
87
+ precio: float
88
+ id_boleta: int
89
+
90
+
91
+ # metodo put de monturas_pedidos con manejo de errores
92
+ @router.put("/")
93
+ def update_montura_pedido(montura_pedido: Montura_pedidoUpdate):
94
+ try:
95
+ with DatabaseConnection().get_connection() as conn:
96
+ cursor = conn.cursor()
97
+ cursor.execute(
98
+ "UPDATE montura_pedido SET id_montura_inventario = ?, cantidad = ?, precio = ?, id_boleta = ? WHERE id_montura_pedido = ?",
99
+ (
100
+ montura_pedido.id_montura_inventario,
101
+ montura_pedido.cantidad,
102
+ montura_pedido.precio,
103
+ montura_pedido.id_boleta,
104
+ montura_pedido.id_montura_pedido,
105
+ ),
106
+ )
107
+ conn.commit()
108
+ return {"mensaje": "Montura_pedido actualizada exitosamente"}
109
+ except Exception as e:
110
+ print(e)
111
+ return []
112
+
113
+
114
+ # delete/monturas_pedidos -> eliminar una montura_pedido con una clase pydantic
115
+ class Montura_pedidoDelete(BaseModel):
116
+ id_montura_pedido: int
117
+
118
+
119
+ # metodo delete de monturas_pedidos con manejo de errores
120
+ @router.delete("/")
121
+ def delete_montura_pedido(montura_pedido: Montura_pedidoDelete):
122
+ try:
123
+ with DatabaseConnection().get_connection() as conn:
124
+ cursor = conn.cursor()
125
+ cursor.execute(
126
+ "DELETE FROM montura_pedido WHERE id_montura_pedido = ?",
127
+ (montura_pedido.id_montura_pedido,),
128
+ )
129
+ conn.commit()
130
+ return {"mensaje": "Montura_pedido eliminada exitosamente"}
131
+ except Exception as e:
132
+ print(e)
133
+ return []
routers/prescripciones.py ADDED
@@ -0,0 +1,503 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from library.librerias import *
2
+
3
+ router = APIRouter(
4
+ prefix="/prescripciones",
5
+ tags=["Prescripciones"],
6
+ responses={404: {"description": "No encontrado"}},
7
+ )
8
+
9
+
10
+ # Cargar varias tipografías
11
+ pdfmetrics.registerFont(TTFont("Craftcoke", "./font/Craftcoke.ttf"))
12
+ pdfmetrics.registerFont(TTFont("Oregon", "./font/Oregon.ttf"))
13
+ pdfmetrics.registerFont(TTFont("Roboto", "./font/Roboto.ttf"))
14
+
15
+ """
16
+ CREATE TABLE Prescripcion (
17
+ id_prescripcion INTEGER PRIMARY KEY AUTOINCREMENT,
18
+ id_medidas INTEGER REFERENCES Medidas(id_medidas),
19
+ detalle_lunas VARCHAR,
20
+ fecha VARCHAR
21
+
22
+ )
23
+ """
24
+
25
+
26
+ # get/prescripciones -> obtener todas las prescripciones con with connection as conn, manejo de errores
27
+ @router.get("/")
28
+ def get_prescripciones():
29
+ try:
30
+ with DatabaseConnection().get_connection() as conn:
31
+ cursor = conn.cursor()
32
+ cursor.execute("SELECT * FROM Prescripcion")
33
+ prescripciones = cursor.fetchall()
34
+ return prescripciones
35
+ except Exception as e:
36
+ print(e)
37
+ return []
38
+
39
+
40
+ @router.get("/ultimoregistro")
41
+ def get_prescripciones():
42
+ try:
43
+ with DatabaseConnection().get_connection() as conn:
44
+ cursor = conn.cursor()
45
+ cursor.execute(
46
+ "SELECT * FROM Prescripcion ORDER BY id_prescripcion DESC LIMIT 1;"
47
+ )
48
+ prescripciones = cursor.fetchall()
49
+ return prescripciones
50
+ except Exception as e:
51
+ print(e)
52
+ return []
53
+
54
+
55
+ # get/prescripciones/{id_prescripcion} -> obtener una prescripcion por id
56
+ @router.get("/{id_prescripcion}")
57
+ def get_prescripcion(id_prescripcion: int):
58
+ try:
59
+ with DatabaseConnection().get_connection() as conn:
60
+ cursor = conn.cursor()
61
+ cursor.execute(
62
+ "SELECT * FROM Prescripcion WHERE id_prescripcion = ?",
63
+ (id_prescripcion,),
64
+ )
65
+ prescripcion = cursor.fetchone()
66
+ return prescripcion
67
+ except Exception as e:
68
+ print(e)
69
+ return []
70
+
71
+
72
+ class Prescripcion(BaseModel):
73
+ id_medidas: int
74
+ detalle_lunas: str
75
+ fecha: str
76
+
77
+
78
+ # post prescripcion con pydantic con retorna la todos los datos de la prescripcion
79
+ @router.post("/ultimoRegistro")
80
+ def post_prescripcion(prescripcion: Prescripcion):
81
+ try:
82
+ with DatabaseConnection().get_connection() as conn:
83
+ cursor = conn.cursor()
84
+ cursor.execute(
85
+ "INSERT INTO Prescripcion (id_medidas, detalle_lunas, fecha) VALUES (?, ?, ?)",
86
+ (
87
+ prescripcion.id_medidas,
88
+ prescripcion.detalle_lunas,
89
+ prescripcion.fecha,
90
+ ),
91
+ )
92
+ conn.commit()
93
+ cursor.execute(
94
+ "SELECT * FROM Prescripcion ORDER BY id_prescripcion DESC LIMIT 1;"
95
+ )
96
+ prescripciones = cursor.fetchall()
97
+ return prescripciones
98
+ except Exception as e:
99
+ print(e)
100
+ return []
101
+
102
+
103
+ # metodo post de prescripciones con manejo de errores
104
+ @router.post("/")
105
+ def create_prescripcion(prescripcion: Prescripcion):
106
+ try:
107
+ with DatabaseConnection().get_connection() as conn:
108
+ cursor = conn.cursor()
109
+ cursor.execute(
110
+ "INSERT INTO Prescripcion (id_medidas, detalle_lunas, fecha) VALUES (?, ?, ?)",
111
+ (
112
+ prescripcion.id_medidas,
113
+ prescripcion.detalle_lunas,
114
+ prescripcion.fecha,
115
+ ),
116
+ )
117
+ conn.commit()
118
+ return {"mensaje": "Prescripcion creada exitosamente"}
119
+ except Exception as e:
120
+ print(e)
121
+ return []
122
+
123
+
124
+ # put/prescripciones -> actualizar una prescripcion con una clase pydantic
125
+ class PrescripcionUpdate(BaseModel):
126
+ id_prescripcion: int
127
+ id_medidas: int
128
+ detalle_lunas: str
129
+ fecha: str
130
+
131
+
132
+ # metodo put de prescripciones con manejo de errores
133
+ @router.put("/")
134
+ def update_prescripcion(prescripcion: PrescripcionUpdate):
135
+ try:
136
+ with DatabaseConnection().get_connection() as conn:
137
+ cursor = conn.cursor()
138
+ cursor.execute(
139
+ "UPDATE Prescripcion SET id_medidas = ?, detalle_lunas = ?, fecha = ? WHERE id_prescripcion = ?",
140
+ (
141
+ prescripcion.id_medidas,
142
+ prescripcion.detalle_lunas,
143
+ prescripcion.fecha,
144
+ prescripcion.id_prescripcion,
145
+ ),
146
+ )
147
+ conn.commit()
148
+ return {"mensaje": "Prescripcion actualizada exitosamente"}
149
+ except Exception as e:
150
+ print(e)
151
+ return []
152
+
153
+
154
+ # delete/prescripciones -> eliminar una prescripcion con una clase pydantic
155
+ class PrescripcionDelete(BaseModel):
156
+ id_prescripcion: int
157
+
158
+
159
+ # metodo delete de prescripciones con manejo de errores
160
+ @router.delete("/")
161
+ def delete_prescripcion(prescripcion: PrescripcionDelete):
162
+ try:
163
+ with DatabaseConnection().get_connection() as conn:
164
+ cursor = conn.cursor()
165
+ cursor.execute(
166
+ "DELETE FROM Prescripcion WHERE id_prescripcion = ?",
167
+ (prescripcion.id_prescripcion,),
168
+ )
169
+ conn.commit()
170
+ return {"mensaje": "Prescripcion eliminada exitosamente"}
171
+ except Exception as e:
172
+ print(e)
173
+ return []
174
+
175
+
176
+ def obtener_datos_prescripcion(id_prescripcion):
177
+ try:
178
+ conn = DatabaseConnection().get_connection()
179
+ cursor = conn.cursor()
180
+ query = """
181
+ SELECT
182
+ P.id_prescripcion,
183
+ P.fecha AS fecha_prescripcion,
184
+ P.detalle_lunas,
185
+ Me.Esfera_OD_lejos,
186
+ Me.Cilindro_OD_lejos,
187
+ Me.Eje_OD_lejos,
188
+ Me.Agudeza_visual_OD_lejos,
189
+ Me.Esfera_OI_lejos,
190
+ Me.Cilindro_OI_lejos,
191
+ Me.Eje_OI_lejos,
192
+ Me.Agudeza_visual_OI_lejos,
193
+ Me.Esfera_OD_cerca,
194
+ Me.Cilindro_OD_cerca,
195
+ Me.Eje_OD_cerca,
196
+ Me.Agudeza_visual_OD_cerca,
197
+ Me.Esfera_OI_cerca,
198
+ Me.Cilindro_OI_cerca,
199
+ Me.Eje_OI_cerca,
200
+ Me.Agudeza_visual_OI_cerca,
201
+ C.id_cliente,
202
+ C.nombres_y_apellidos,
203
+ C.edad,
204
+ C.telefono,
205
+ C.direccion
206
+ FROM
207
+ Prescripcion AS P
208
+ JOIN
209
+ Medidas AS Me ON P.id_medidas = Me.id_medidas
210
+ JOIN
211
+ Cliente AS C ON Me.id_cliente = C.id_cliente
212
+ WHERE
213
+ P.id_prescripcion = ?;
214
+ """
215
+ cursor.execute(query, (id_prescripcion,))
216
+ resultado = cursor.fetchone()
217
+ return resultado
218
+ except Exception as e:
219
+ print(e)
220
+ return []
221
+
222
+
223
+ # crear endpoint para obtener los datos de la prescripción
224
+ @router.get("/prescripcion/{id_prescripcion}")
225
+ def obtener_datos_prescripcion_api(id_prescripcion: int):
226
+ datos_prescripcion = obtener_datos_prescripcion(id_prescripcion)
227
+ if datos_prescripcion:
228
+ # Crear un objeto de la clase DatosPrescripcion
229
+ obj_datos_prescripcion = DatosPrescripcion(*datos_prescripcion)
230
+ return obj_datos_prescripcion
231
+ else:
232
+ raise HTTPException(status_code=404, detail="Prescripción no encontrada")
233
+
234
+
235
+ class DatosPrescripcion:
236
+ def __init__(
237
+ self,
238
+ id_prescripcion,
239
+ fecha_prescripcion,
240
+ detalle_lunas,
241
+ esfera_od_lejos,
242
+ cilindro_od_lejos,
243
+ eje_od_lejos,
244
+ agudeza_visual_od_lejos,
245
+ esfera_oi_lejos,
246
+ cilindro_oi_lejos,
247
+ eje_oi_lejos,
248
+ agudeza_visual_oi_lejos,
249
+ esfera_od_cerca,
250
+ cilindro_od_cerca,
251
+ eje_od_cerca,
252
+ agudeza_visual_od_cerca,
253
+ esfera_oi_cerca,
254
+ cilindro_oi_cerca,
255
+ eje_oi_cerca,
256
+ agudeza_visual_oi_cerca,
257
+ id_cliente,
258
+ nombres_y_apellidos,
259
+ edad,
260
+ telefono,
261
+ direccion,
262
+ ):
263
+ """
264
+ Clase que representa los datos de una prescripción.
265
+
266
+ Args:
267
+ id_prescripcion (int): El ID de la prescripción.
268
+ fecha_prescripcion (str): La fecha de la prescripción.
269
+ detalle_lunas (str): Los detalles de las lentes.
270
+ esfera_od_lejos (float): El valor de la esfera para el ojo derecho en visión lejana.
271
+ cilindro_od_lejos (float): El valor del cilindro para el ojo derecho en visión lejana.
272
+ eje_od_lejos (int): El valor del eje para el ojo derecho en visión lejana.
273
+ agudeza_visual_od_lejos (str): La agudeza visual para el ojo derecho en visión lejana.
274
+ esfera_oi_lejos (float): El valor de la esfera para el ojo izquierdo en visión lejana.
275
+ cilindro_oi_lejos (float): El valor del cilindro para el ojo izquierdo en visión lejana.
276
+ eje_oi_lejos (int): El valor del eje para el ojo izquierdo en visión lejana.
277
+ agudeza_visual_oi_lejos (str): La agudeza visual para el ojo izquierdo en visión lejana.
278
+ esfera_od_cerca (float): El valor de la esfera para el ojo derecho en visión cercana.
279
+ cilindro_od_cerca (float): El valor del cilindro para el ojo derecho en visión cercana.
280
+ eje_od_cerca (int): El valor del eje para el ojo derecho en visión cercana.
281
+ agudeza_visual_od_cerca (str): La agudeza visual para el ojo derecho en visión cercana.
282
+ esfera_oi_cerca (float): El valor de la esfera para el ojo izquierdo en visión cercana.
283
+ cilindro_oi_cerca (float): El valor del cilindro para el ojo izquierdo en visión cercana.
284
+ eje_oi_cerca (int): El valor del eje para el ojo izquierdo en visión cercana.
285
+ agudeza_visual_oi_cerca (str): La agudeza visual para el ojo izquierdo en visión cercana.
286
+ id_cliente (int): El ID del cliente.
287
+ nombres_y_apellidos (str): Los nombres y apellidos del cliente.
288
+ edad (int): La edad del cliente.
289
+ telefono (str): El número de teléfono del cliente.
290
+ direccion (str): La dirección del cliente.
291
+ """
292
+ self.id_prescripcion = id_prescripcion
293
+ self.fecha_prescripcion = fecha_prescripcion
294
+ self.detalle_lunas = detalle_lunas
295
+ self.esfera_od_lejos = esfera_od_lejos
296
+ self.cilindro_od_lejos = cilindro_od_lejos
297
+ self.eje_od_lejos = eje_od_lejos
298
+ self.agudeza_visual_od_lejos = agudeza_visual_od_lejos
299
+ self.esfera_oi_lejos = esfera_oi_lejos
300
+ self.cilindro_oi_lejos = cilindro_oi_lejos
301
+ self.eje_oi_lejos = eje_oi_lejos
302
+ self.agudeza_visual_oi_lejos = agudeza_visual_oi_lejos
303
+ self.esfera_od_cerca = esfera_od_cerca
304
+ self.cilindro_od_cerca = cilindro_od_cerca
305
+ self.eje_od_cerca = eje_od_cerca
306
+ self.agudeza_visual_od_cerca = agudeza_visual_od_cerca
307
+ self.esfera_oi_cerca = esfera_oi_cerca
308
+ self.cilindro_oi_cerca = cilindro_oi_cerca
309
+ self.eje_oi_cerca = eje_oi_cerca
310
+ self.agudeza_visual_oi_cerca = agudeza_visual_oi_cerca
311
+ self.id_cliente = id_cliente
312
+ self.nombres_y_apellidos_cliente = nombres_y_apellidos
313
+ self.edad_cliente = edad
314
+ self.telefono_cliente = telefono
315
+ self.direccion_cliente = direccion
316
+
317
+ def generar_pdf(self, filename):
318
+ """
319
+ Genera un archivo PDF con los datos de la prescripción.
320
+
321
+ Args:
322
+ filename (str): El nombre del archivo PDF a generar.
323
+ """
324
+ pdf = canvas.Canvas(filename)
325
+ pdf.setFont("Oregon", 12)
326
+ ubicacion_inicio = 780 # Posición inicial en y
327
+ pdf.drawCentredString(
328
+ 300, ubicacion_inicio, "OPTICA ARTE VISUAL - PRESCRIPCIÓN"
329
+ )
330
+ pdf.drawString(
331
+ 100,
332
+ ubicacion_inicio - 40,
333
+ f"Nombre del Cliente: {self.nombres_y_apellidos_cliente}",
334
+ )
335
+ pdf.drawString(
336
+ 100, ubicacion_inicio - 60, f"Datos del cliente: {self.direccion_cliente}"
337
+ )
338
+ pdf.drawString(
339
+ 100, ubicacion_inicio - 80, f"Número telefónico: {self.telefono_cliente}"
340
+ )
341
+ pdf.drawString(
342
+ 100,
343
+ ubicacion_inicio - 100,
344
+ f"Código de prescripción: {self.id_prescripcion}",
345
+ )
346
+ pdf.drawString(100, ubicacion_inicio - 120, f"Fecha: {self.fecha_prescripcion}")
347
+ pdf.drawString(
348
+ 100, ubicacion_inicio - 140, f"Descripción: {self.detalle_lunas}"
349
+ )
350
+ ubicacion_esfera = 150 # Posición inicial en x
351
+ ubicacion_cilindro = ubicacion_esfera + 65 # Posición inicial en x + 65
352
+ ubicacion_eje = ubicacion_cilindro + 75 # Posición anterior en x + 75
353
+ ubicacion_agudeza = ubicacion_eje + 70 # Posición anterior en x + 70
354
+ tabla_medidas = ubicacion_inicio - 170 # Posición inicial en y
355
+
356
+ pdf.drawString(ubicacion_esfera - 50, tabla_medidas, "Tabla de medidas:")
357
+ # Para el ojo izquierdo de lejos
358
+ pdf.drawString(
359
+ ubicacion_esfera + 100, tabla_medidas - 20, "Ojo izquierdo de lejos"
360
+ )
361
+ pdf.line(
362
+ x1=ubicacion_esfera,
363
+ y1=tabla_medidas - 25,
364
+ x2=ubicacion_esfera + 300,
365
+ y2=tabla_medidas - 25,
366
+ )
367
+ pdf.drawString(ubicacion_esfera, tabla_medidas - 40, "Esfera")
368
+ pdf.drawString(ubicacion_cilindro, tabla_medidas - 40, "Cilindro")
369
+ pdf.drawString(ubicacion_eje, tabla_medidas - 40, "Eje")
370
+ pdf.drawString(ubicacion_agudeza, tabla_medidas - 40, "Agudeza visual")
371
+ pdf.drawString(ubicacion_esfera, tabla_medidas - 60, f"{self.esfera_oi_lejos}")
372
+ pdf.drawString(
373
+ ubicacion_cilindro, tabla_medidas - 60, f"{self.cilindro_oi_lejos}"
374
+ )
375
+ pdf.drawString(ubicacion_eje, tabla_medidas - 60, f"{self.eje_oi_lejos}")
376
+ pdf.drawString(
377
+ ubicacion_agudeza, tabla_medidas - 60, f"{self.agudeza_visual_oi_lejos}"
378
+ )
379
+ # Para el ojo derecho de lejos
380
+ odl = tabla_medidas - 100 # Posición inicial en y
381
+ pdf.drawString(ubicacion_esfera + 100, odl, "Ojo derecho de lejos")
382
+ pdf.line(x1=ubicacion_esfera, y1=odl - 5, x2=ubicacion_esfera + 300, y2=odl - 5)
383
+ pdf.drawString(ubicacion_esfera, odl - 20, "Esfera")
384
+ pdf.drawString(ubicacion_cilindro, odl - 20, "Cilindro")
385
+ pdf.drawString(ubicacion_eje, odl - 20, "Eje")
386
+ pdf.drawString(ubicacion_agudeza, odl - 20, "Agudeza visual")
387
+ pdf.drawString(ubicacion_esfera, odl - 40, f"{self.esfera_od_lejos}")
388
+ pdf.drawString(ubicacion_cilindro, odl - 40, f"{self.cilindro_od_lejos}")
389
+ pdf.drawString(ubicacion_eje, odl - 40, f"{self.eje_od_lejos}")
390
+ pdf.drawString(ubicacion_agudeza, odl - 40, f"{self.agudeza_visual_od_lejos}")
391
+
392
+ oic = odl - 80 # Posición inicial en y
393
+ pdf.drawString(ubicacion_esfera + 100, oic, "Ojo izquierdo de cerca")
394
+ pdf.line(x1=ubicacion_esfera, y1=oic - 5, x2=ubicacion_esfera + 300, y2=oic - 5)
395
+ # Para el ojo izquierdo de cerca
396
+ pdf.drawString(ubicacion_esfera, oic - 20, "Esfera")
397
+ pdf.drawString(ubicacion_cilindro, oic - 20, "Cilindro")
398
+ pdf.drawString(ubicacion_eje, oic - 20, "Eje")
399
+ pdf.drawString(ubicacion_agudeza, oic - 20, "Agudeza visual")
400
+ pdf.drawString(ubicacion_esfera, oic - 40, f"{self.esfera_oi_cerca}")
401
+ pdf.drawString(ubicacion_cilindro, oic - 40, f"{self.cilindro_oi_cerca}")
402
+ pdf.drawString(ubicacion_eje, oic - 40, f"{self.eje_oi_cerca}")
403
+ pdf.drawString(ubicacion_agudeza, oic - 40, f"{self.agudeza_visual_oi_cerca}")
404
+ odc = oic - 80
405
+ pdf.drawString(ubicacion_esfera + 100, odc, "Ojo derecho de cerca")
406
+ pdf.line(x1=ubicacion_esfera, y1=odc - 5, x2=ubicacion_esfera + 300, y2=odc - 5)
407
+ # Para el ojo derecho de cerca
408
+ pdf.drawString(ubicacion_esfera, odc - 20, "Esfera")
409
+ pdf.drawString(ubicacion_cilindro, odc - 20, "Cilindro")
410
+ pdf.drawString(ubicacion_eje, odc - 20, "Eje")
411
+ pdf.drawString(ubicacion_agudeza, odc - 20, "Agudeza visual")
412
+ pdf.drawString(ubicacion_esfera, odc - 40, f"{self.esfera_od_cerca}")
413
+ pdf.drawString(ubicacion_cilindro, odc - 40, f"{self.cilindro_od_cerca}")
414
+ pdf.drawString(ubicacion_eje, odc - 40, f"{self.eje_od_cerca}")
415
+ pdf.drawString(ubicacion_agudeza, odc - 40, f"{self.agudeza_visual_od_cerca}")
416
+
417
+ # Calcular el centro de la página
418
+ centro_pagina = pdf._pagesize[0] / 2
419
+
420
+ # Texto y línea centrados
421
+ texto_firma = " Firma o sello: "
422
+ ancho_texto = pdf.stringWidth(texto_firma, "Helvetica", 12)
423
+ inicio_linea = centro_pagina - ancho_texto / 2
424
+ fin_linea = inicio_linea + ancho_texto
425
+ # ubicacion en y dependiendo de la tabla de medidas
426
+ firma_ubicacion = odc - 70
427
+ pdf.drawString(inicio_linea, firma_ubicacion, texto_firma)
428
+ pdf.line(inicio_linea, firma_ubicacion - 50, fin_linea, firma_ubicacion - 50)
429
+
430
+ pdf.save()
431
+ print(f"PDF generado: {filename}")
432
+
433
+
434
+ # endpoint descargar prescripcion pdf con clase
435
+ class PrescripcionPDF(BaseModel):
436
+ id_prescripcion: int
437
+
438
+
439
+ @router.post("/prescripcion/pdf")
440
+ def obtener_pdf_prescripcion_api(prescripcion: PrescripcionPDF):
441
+ datos_prescripcion = obtener_datos_prescripcion(prescripcion.id_prescripcion)
442
+ if datos_prescripcion:
443
+ # Crear un objeto de la clase DatosPrescripcion
444
+ obj_datos_prescripcion = DatosPrescripcion(*datos_prescripcion)
445
+ directorio_pdf = "pdf/prescripcion/"
446
+ os.makedirs(directorio_pdf, exist_ok=True)
447
+ # obtener la fecha de hoy
448
+ fecha_hoy = date.today()
449
+ # generar el nombre del archivo
450
+ nombre_archivo = f"{directorio_pdf}prescripcion_{prescripcion.id_prescripcion}_{fecha_hoy}.pdf"
451
+
452
+ obj_datos_prescripcion.generar_pdf(f"{nombre_archivo}")
453
+ return FileResponse(
454
+ nombre_archivo, media_type="routerlication/pdf", filename=nombre_archivo
455
+ )
456
+ else:
457
+ raise HTTPException(status_code=404, detail="Prescripción no encontrada")
458
+
459
+
460
+ # crear endpoint retornando la url del PDF con los datos de la prescripción
461
+ @router.get("/prescripcion/pdf/{id_prescripcion}")
462
+ def ver_prescripcion_pdf(id_prescripcion: int):
463
+ datos_prescripcion = obtener_datos_prescripcion(id_prescripcion)
464
+ if datos_prescripcion:
465
+ # Crear un objeto de la clase DatosPrescripcion
466
+ obj_datos_prescripcion = DatosPrescripcion(*datos_prescripcion)
467
+ directorio_pdf = "pdf/prescripcion/"
468
+ os.makedirs(directorio_pdf, exist_ok=True)
469
+ # obtener la fecha de hoy
470
+ fecha_hoy = date.today()
471
+ # generar el nombre del archivo
472
+ nombre_archivo = (
473
+ f"{directorio_pdf}prescripcion_{id_prescripcion}_{fecha_hoy}.pdf"
474
+ )
475
+ obj_datos_prescripcion.generar_pdf(f"{nombre_archivo}")
476
+ return FileResponse(path=nombre_archivo)
477
+ else:
478
+ raise HTTPException(status_code=404, detail="Prescripción no encontrada")
479
+
480
+
481
+ # metodo get pdf de prescripcion
482
+ @router.get("/prescripcion/descargarPDF/{id_prescripcion}")
483
+ def descargar_prescripcion_pdf(id_prescripcion: int):
484
+ datos_prescripcion = obtener_datos_prescripcion(id_prescripcion)
485
+ if datos_prescripcion:
486
+ # Crear un objeto de la clase DatosPrescripcion
487
+ obj_datos_prescripcion = DatosPrescripcion(*datos_prescripcion)
488
+ directorio_pdf = "pdf/prescripcion/"
489
+ os.makedirs(directorio_pdf, exist_ok=True)
490
+ # obtener la fecha de hoy
491
+ fecha_hoy = date.today()
492
+ # generar el nombre del archivo
493
+ nombre_archivo = (
494
+ f"{directorio_pdf}prescripcion_{id_prescripcion}_{fecha_hoy}.pdf"
495
+ )
496
+ obj_datos_prescripcion.generar_pdf(f"{nombre_archivo}")
497
+ return FileResponse(
498
+ path=nombre_archivo,
499
+ media_type="routerlication/pdf",
500
+ filename=nombre_archivo,
501
+ )
502
+ else:
503
+ raise HTTPException(status_code=404, detail="Prescripción no encontrada")
routers/roles.py ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from library.librerias import *
2
+
3
+ router = APIRouter(
4
+ prefix="/roles", tags=["Roles"], responses={404: {"description": "No encontrado"}}
5
+ )
6
+
7
+ """
8
+ CREATE TABLE Roles (
9
+ id_rol INTEGER PRIMARY KEY AUTOINCREMENT,
10
+ rol VARCHAR
11
+ )
12
+ """
13
+
14
+
15
+ @router.get("/")
16
+ def get_roles():
17
+ try:
18
+ with DatabaseConnection().get_connection() as conn:
19
+ cursor = conn.cursor()
20
+ cursor.execute("SELECT * FROM Roles")
21
+ roles = cursor.fetchall()
22
+ if roles:
23
+ return roles
24
+ else:
25
+ raise HTTPException(status_code=404, detail="Roles no encontrado")
26
+ except Exception as e:
27
+ print(e)
28
+ return []
29
+
30
+
31
+ @router.get("/{id_rol}")
32
+ def get_rol(id_rol: int):
33
+ try:
34
+ with DatabaseConnection().get_connection() as conn:
35
+ cursor = conn.cursor()
36
+ cursor.execute("SELECT * FROM Roles WHERE id_rol = ?", (id_rol,))
37
+ rol = cursor.fetchone()
38
+ if rol:
39
+ return rol
40
+ else:
41
+ raise HTTPException(status_code=404, detail="Rol no encontrado")
42
+ except Exception as e:
43
+ print(e)
44
+ return []
45
+
46
+
47
+ class RolNombre(BaseModel):
48
+ rol: str
49
+
50
+
51
+ @router.post("/busqueda")
52
+ def buscar_rol(rol: RolNombre):
53
+ try:
54
+ with DatabaseConnection().get_connection() as conn:
55
+ cursor = conn.cursor()
56
+ cursor.execute("SELECT * FROM Roles WHERE rol = ?", (rol.rol,))
57
+ rol = cursor.fetchone()
58
+ # retornar el rol encontrado o un mensaje de error con HTTPException
59
+ if rol:
60
+ return rol
61
+ else:
62
+ raise HTTPException(status_code=404, detail="Rol no encontrado")
63
+ except Exception as e:
64
+ print(e)
65
+ return []
66
+
67
+
68
+ # post/roles -> crear un rol con una clase pydantic
69
+ class Rol(BaseModel):
70
+ rol: str
71
+
72
+
73
+ # post/roles -> crear un rol con una clase pydantic
74
+ @router.post("/")
75
+ def create_rol(rol: Rol):
76
+ try:
77
+ with DatabaseConnection().get_connection() as conn:
78
+ cursor = conn.cursor()
79
+ cursor.execute("INSERT INTO Roles (rol) VALUES (?)", (rol.rol,))
80
+ conn.commit()
81
+ return {"mensaje": "Rol creado exitosamente"}
82
+ except Exception as e:
83
+ print(e)
84
+ return []
85
+
86
+
87
+ # put/roles -> actualizar un rol con una clase pydantic
88
+ class RolUpdate(BaseModel):
89
+ id_rol: int
90
+ rol: str
91
+
92
+
93
+ @router.put("/")
94
+ def update_rol(rol: RolUpdate):
95
+ try:
96
+ with DatabaseConnection().get_connection() as conn:
97
+ cursor = conn.cursor()
98
+ cursor.execute(
99
+ "UPDATE Roles SET rol = ? WHERE id_rol = ?", (rol.rol, rol.id_rol)
100
+ )
101
+ conn.commit()
102
+ return {"mensaje": "Rol actualizado exitosamente"}
103
+ except Exception as e:
104
+ print(e)
105
+ return []
106
+
107
+
108
+ # delete/roles -> eliminar un rol con una clase pydantic
109
+ class RolDelete(BaseModel):
110
+ id_rol: int
111
+
112
+
113
+ @router.delete("/")
114
+ def delete_rol(rol: RolDelete):
115
+ try:
116
+ with DatabaseConnection().get_connection() as conn:
117
+ cursor = conn.cursor()
118
+ cursor.execute("DELETE FROM Roles WHERE id_rol = ?", (rol.id_rol,))
119
+ conn.commit()
120
+ return {"mensaje": "Rol eliminado exitosamente"}
121
+ except Exception as e:
122
+ print(e)
123
+ return []
routers/routers.py ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from routers import (
2
+ comprobante_pago,
3
+ roles,
4
+ usuarios,
5
+ clientes,
6
+ medidas,
7
+ prescripciones,
8
+ lunas_pedido,
9
+ monturas,
10
+ monturas_inventario,
11
+ boletas,
12
+ monturas_pedido,
13
+ )
routers/usuarios.py ADDED
@@ -0,0 +1,155 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from library.librerias import *
2
+
3
+ router = APIRouter(
4
+ prefix="/usuarios",
5
+ tags=["Usuarios"],
6
+ responses={404: {"description": "No encontrado"}},
7
+ )
8
+
9
+ """
10
+ CREATE TABLE Usuario (
11
+ id_usuario INTEGER PRIMARY KEY AUTOINCREMENT,
12
+ nombre_usuario VARCHAR,
13
+ dni VARCHAR,
14
+ clave VARCHAR,
15
+ id_rol INTEGER REFERENCES Roles(id_rol),
16
+ estado VARCHAR
17
+ )
18
+ """
19
+
20
+
21
+ # get/usuarios -> obtener todos los usuarios con with connection as conn, manejo de errores
22
+ @router.get("/")
23
+ def get_usuarios():
24
+ try:
25
+ with DatabaseConnection().get_connection() as conn:
26
+ cursor = conn.cursor()
27
+ cursor.execute("SELECT * FROM Usuario")
28
+ usuarios = cursor.fetchall()
29
+ return usuarios
30
+ except Exception as e:
31
+ print(e)
32
+ return []
33
+
34
+
35
+ # get/usuarios/{id_usuario} -> obtener un usuario por id
36
+ @router.get("/{id_usuario}")
37
+ def get_usuario(id_usuario: int):
38
+ try:
39
+ with DatabaseConnection().get_connection() as conn:
40
+ cursor = conn.cursor()
41
+ cursor.execute("SELECT * FROM Usuario WHERE id_usuario = ?", (id_usuario,))
42
+ usuario = cursor.fetchone()
43
+ return usuario
44
+ except Exception as e:
45
+ print(e)
46
+ return []
47
+
48
+
49
+ # metodo de busqueda de usuario por nombre con like, manejo de errores y clase pydantic
50
+ class UsuarioNombre(BaseModel):
51
+ nombre_usuario: str
52
+
53
+
54
+ # post/usuarios/busqueda -> buscar usuario por nombre con like
55
+ @router.post("/busqueda")
56
+ def buscar_usuario(usuario: UsuarioNombre):
57
+ try:
58
+ with DatabaseConnection().get_connection() as conn:
59
+ cursor = conn.cursor()
60
+ cursor.execute(
61
+ "SELECT * FROM Usuario WHERE nombre_usuario LIKE ?",
62
+ ["%" + usuario.nombre_usuario + "%"],
63
+ )
64
+ usuario = cursor.fetchall()
65
+ if usuario:
66
+ return usuario
67
+ else:
68
+ raise HTTPException(status_code=404, detail="Usuario no encontrado")
69
+ except Exception as e:
70
+ print(e)
71
+ return []
72
+
73
+
74
+ # post/usuarios -> crear un usuario con una clase pydantic
75
+ class Usuario(BaseModel):
76
+ nombre_usuario: str
77
+ dni: str
78
+ clave: str
79
+ id_rol: int
80
+ estado: str
81
+
82
+
83
+ @router.post("/")
84
+ def create_usuario(usuario: Usuario):
85
+ try:
86
+ with DatabaseConnection().get_connection() as conn:
87
+ cursor = conn.cursor()
88
+ cursor.execute(
89
+ "INSERT INTO Usuario (nombre_usuario, dni, clave, id_rol, estado) VALUES (?, ?, ?, ?, ?)",
90
+ (
91
+ usuario.nombre_usuario,
92
+ usuario.dni,
93
+ usuario.clave,
94
+ usuario.id_rol,
95
+ usuario.estado,
96
+ ),
97
+ )
98
+ conn.commit()
99
+ return {"mensaje": "Usuario creado exitosamente"}
100
+ except Exception as e:
101
+ print(e)
102
+ return []
103
+
104
+
105
+ # put/usuarios -> actualizar un usuario con una clase pydantic
106
+ class UsuarioUpdate(BaseModel):
107
+ id_usuario: int
108
+ nombre_usuario: str
109
+ dni: str
110
+ clave: str
111
+ id_rol: int
112
+ estado: str
113
+
114
+
115
+ @router.put("/")
116
+ def update_usuario(usuario: UsuarioUpdate):
117
+ try:
118
+ with DatabaseConnection().get_connection() as conn:
119
+ cursor = conn.cursor()
120
+ cursor.execute(
121
+ "UPDATE Usuario SET nombre_usuario = ?, dni = ?, clave = ?, id_rol = ?, estado = ? WHERE id_usuario = ?",
122
+ (
123
+ usuario.nombre_usuario,
124
+ usuario.dni,
125
+ usuario.clave,
126
+ usuario.id_rol,
127
+ usuario.estado,
128
+ usuario.id_usuario,
129
+ ),
130
+ )
131
+ conn.commit()
132
+ return {"mensaje": "Usuario actualizado exitosamente"}
133
+ except Exception as e:
134
+ print(e)
135
+ return []
136
+
137
+
138
+ # delete/usuarios -> eliminar un usuario con una clase pydantic
139
+ class UsuarioDelete(BaseModel):
140
+ id_usuario: int
141
+
142
+
143
+ @router.delete("/")
144
+ def delete_usuario(usuario: UsuarioDelete):
145
+ try:
146
+ with DatabaseConnection().get_connection() as conn:
147
+ cursor = conn.cursor()
148
+ cursor.execute(
149
+ "DELETE FROM Usuario WHERE id_usuario = ?", (usuario.id_usuario,)
150
+ )
151
+ conn.commit()
152
+ return {"mensaje": "Usuario eliminado exitosamente"}
153
+ except Exception as e:
154
+ print(e)
155
+ return []