Coverage for backend \ app \ Caja \ services \ cajaService.py: 80.58%
139 statements
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-29 16:13 -0500
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-29 16:13 -0500
1from app.Caja.repositories.cajaRepository import CajaRepository
2from app.configuracionGeneral.schemasGenerales import respuestaApi
3from app.configuracionGeneral.seguridadJWT import identificarUsuarioString
4from app.Usuarios.repositories.usuarioRepository import UsuarioRepository
5from fastapi import HTTPException
7from app.Caja.schemas.cajaSchemas import *
9class CajaService:
10 def __init__(self, dbSession):
11 self.dbSession = dbSession
12 self.repo = CajaRepository(dbSession)
14 def _attach_usuario(self, caja_obj):
15 """Asegura que la relación `usuario` esté poblada en la entidad `CajaHistorial` para serializarla."""
16 if not getattr(caja_obj, "usuario", None):
17 usuario_entity = UsuarioRepository(self.dbSession).obtenerUsuarioPorId(caja_obj.idUsuarioCaja)
18 if usuario_entity:
19 caja_obj.usuario = usuario_entity
20 return caja_obj
22 def crearCajaHistorial(self, cajaCrear: CajaCrearSchema, usuario: dict):
23 idUsuario = usuario.get("idUsuario")
24 actor = identificarUsuarioString(usuario)
25 # montoInicial es un número provisto por el cliente
26 monto_calc = round(float(cajaCrear.montoInicial), 2)
27 resultado = self.repo.crearCajaHistorial(monto_calc, idUsuario)
28 if isinstance(resultado, dict) and resultado.get("error"):
29 if resultado.get("error") == "caja_abierta_existente":
30 raise HTTPException(status_code=400, detail=f"Ya existe una caja abierta para el usuario {actor}")
31 if resultado.get("error") == "caja_ya_abierta_hoy":
32 raise HTTPException(status_code=400, detail=f"Ya existe una caja para hoy para el usuario {actor}")
33 # Añadir detalle con identificación del actor
34 resultado.detalle = f"Apertura por {actor}; montoInicialDeclarado: {monto_calc}"
35 self.dbSession.add(resultado)
36 self.dbSession.commit()
37 self.dbSession.refresh(resultado)
38 # Adjuntar usuario para serializar en la respuesta
39 resultado = self._attach_usuario(resultado)
40 data = CajaHistorialRespuestaSchema.from_orm(resultado)
41 mensaje = f"Caja abierta por {actor} (monto inicial: {data.montoInicialDeclarado})"
42 return respuestaApi(success=True, message=mensaje, data=data)
44 def cerrarCaja(self, idCaja: int, cerrar: CajaCerrarSchema, usuario: dict):
45 # permisos: solo Cajero (propietario) o Administrador pueden cerrar
46 rol = usuario.get("rol")
47 idUsuario = usuario.get("idUsuario")
48 caja = self.repo.obtenerPorId(idCaja)
49 if not caja:
50 raise HTTPException(status_code=404, detail="Caja no encontrada")
51 # Si la caja ya está cerrada, devolver respuestaApi con success=False, mensaje y la caja en data
52 if caja.estadoCaja == "CERRADA":
53 caja = self._attach_usuario(caja)
54 data = CajaHistorialRespuestaSchema.from_orm(caja)
55 return respuestaApi(success=False, message="La caja ya está cerrada", data=data)
56 monto_final = round(float(cerrar.montoFinal), 2)
57 actor = identificarUsuarioString(usuario)
59 # Cajero: solo puede cerrar SU caja abierta del día actual
60 if rol != "Administrador":
61 if caja.idUsuarioCaja != idUsuario:
62 raise HTTPException(status_code=403, detail="No tiene permisos para cerrar esta caja")
63 # Validar que la apertura sea hoy
64 from datetime import datetime
65 tz = datetime.now().astimezone()
66 hoy = datetime.now(tz.tzinfo).date()
67 if caja.fechaAperturaCaja.date() != hoy:
68 raise HTTPException(status_code=400, detail=f"Solo puede cerrar cajas abiertas hoy. Usuario: {actor}")
69 resultado = self.repo.cerrarCaja(idCaja, monto_final, closedBy=actor, admin=False)
70 else:
71 # Administrador: puede cerrar cualquier caja por id, enviando solo montoFinal
72 resultado = self.repo.cerrarCaja(idCaja, monto_final, closedBy=actor, admin=True)
74 if resultado is None:
75 raise HTTPException(status_code=404, detail="Caja no encontrada")
76 if isinstance(resultado, dict) and resultado.get("error") == "cierre_fuera_de_dia":
77 raise HTTPException(status_code=400, detail="La caja fue abierta en un día distinto")
78 if isinstance(resultado, dict) and resultado.get("error") == "caja_no_abierta":
79 raise HTTPException(status_code=400, detail="La caja no está abierta")
80 if isinstance(resultado, dict) and resultado.get("error") == "caja_ya_cerrada":
81 caja_obj = resultado.get("caja")
82 caja_obj = self._attach_usuario(caja_obj)
83 data = CajaHistorialRespuestaSchema.from_orm(caja_obj)
84 return respuestaApi(success=False, message="La caja ya está cerrada", data=data)
85 resultado = self._attach_usuario(resultado)
86 data = CajaHistorialRespuestaSchema.from_orm(resultado)
87 mensaje = f"Caja cerrada por {actor} (monto cierre declarado: {data.montoCierreDeclarado})"
88 return respuestaApi(success=True, message=mensaje, data=data)
92 def listarCajas(self, usuario: dict):
93 rol = usuario.get("rol")
94 idUsuario = usuario.get("idUsuario")
95 esAdmin = rol == "Administrador"
96 cajas = self.repo.listarCajas(idUsuario if not esAdmin else None, esAdmin)
97 if not cajas:
98 return respuestaApi(success=True, message="No se encontraron cajas", data=[])
99 # Adjuntar usuario en cada caja antes de serializar
100 for c in cajas:
101 self._attach_usuario(c)
102 data = [CajaHistorialRespuestaSchema.from_orm(c) for c in cajas]
103 return respuestaApi(success=True, message="Cajas encontradas", data=data)
105 def listarCajasHoy(self, usuario: dict):
106 rol = usuario.get("rol")
107 idUsuario = usuario.get("idUsuario")
108 esAdmin = rol == "Administrador"
109 cajas = self.repo.listarCajasHoy(idUsuario if not esAdmin else None, esAdmin)
110 if not cajas:
111 return respuestaApi(success=True, message="No se han abierto cajas hoy", data=[])
112 for c in cajas:
113 self._attach_usuario(c)
114 data = [CajaHistorialRespuestaSchema.from_orm(c) for c in cajas]
115 return respuestaApi(success=True, message="Cajas del día encontradas", data=data)
116 def listarTodasCajas(self, usuario: dict):
117 rol = usuario.get("rol")
118 if rol != "Administrador":
119 raise HTTPException(status_code=403, detail="Solo Administrador puede listar todas las cajas")
120 cajas = self.repo.listarCajas(None, True)
121 if not cajas:
122 return respuestaApi(success=True, message="No se encontraron cajas", data=[])
123 for c in cajas:
124 self._attach_usuario(c)
125 data = [CajaHistorialRespuestaSchema.from_orm(c) for c in cajas]
126 return respuestaApi(success=True, message="Cajas encontradas", data=data)
128 def filtrarCaja(self, idUsuario: int, fecha: date, usuario: dict):
129 # Solo Administrador puede usar este endpoint
130 rol = usuario.get("rol")
131 if rol != "Administrador":
132 raise HTTPException(status_code=403, detail="Solo Administrador puede filtrar cajas")
133 resultados = self.repo.filtrarCaja(idUsuario, fecha)
134 if not resultados:
135 return respuestaApi(success=True, message="No se encontraron cajas para los parámetros proporcionados", data=[])
136 for r in resultados:
137 self._attach_usuario(r)
138 data = [CajaHistorialRespuestaSchema.from_orm(r) for r in resultados]
139 return respuestaApi(success=True, message="Cajas encontradas", data=data)
141 def reabrirCaja(self, idCaja: int, usuario: dict):
142 # Solo Administrador puede reabrir cajas cerradas
143 rol = usuario.get("rol")
144 idUsuario = usuario.get("idUsuario")
145 if rol != "Administrador":
146 raise HTTPException(status_code=403, detail="Solo Administrador puede reabrir cajas")
147 caja = self.repo.obtenerPorId(idCaja)
148 if not caja:
149 raise HTTPException(status_code=404, detail="Caja no encontrada")
150 if caja.estadoCaja != "CERRADA":
151 data = CajaHistorialRespuestaSchema.from_orm(caja)
152 return respuestaApi(success=False, message="La caja no está cerrada", data=data)
153 reabierta_por = identificarUsuarioString(usuario)
154 resultado = self.repo.reabrirCaja(idCaja, reabiertaPor=reabierta_por)
155 if resultado is None:
156 raise HTTPException(status_code=404, detail="Caja no encontrada")
157 if isinstance(resultado, dict) and resultado.get("error") == "caja_no_cerrada":
158 caja_obj = resultado.get("caja")
159 caja_obj = self._attach_usuario(caja_obj)
160 data = CajaHistorialRespuestaSchema.from_orm(caja_obj)
161 return respuestaApi(success=False, message=f"La caja no está cerrada. Usuario: {reabierta_por}", data=data)
162 resultado = self._attach_usuario(resultado)
163 data = CajaHistorialRespuestaSchema.from_orm(resultado)
164 mensaje = f"Caja reabierta por {reabierta_por}"
165 return respuestaApi(success=True, message=mensaje, data=data)