Skip to content

Referencias API

Documentación automática generada a partir del código fuente.

Logica

⚙️ TiendaServicios

Servicio para manejar la lógica de negocio de la tienda.

Source code in src/gerencia_app/servicios.py
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
class TiendaServicios:
    """
    Servicio para manejar la lógica de negocio de la tienda.
    """

    def __init__(self, almacenamiento_usuarios: JSONStorage, almacenamiento_productos: JSONStorage):
        self.almacenamiento_usuarios = almacenamiento_usuarios
        self.almacenamiento_productos = almacenamiento_productos

    def obtener_usuarios(self) -> List[Usuario]:
        """
        Trae y devuelve la lista de usuarios del almacenamiento (base de datos).
        """

        return self.almacenamiento_usuarios.load()

    def obtener_productos(self) -> List[Producto]:
        """
        Trae y devuelve la lista de productos del almacenamiento (base de datos).
        """

        return self.almacenamiento_productos.load()


    def obtener_usuario_por_id(self, id_usuario: int, lista_a_buscar: list[Usuario]) -> Usuario:
        """
        Trae y devuelve un usuario específico según su ID.
        Valida: el id del usuario.
        """

        if id_usuario <= 0:
            raise IdUsuarioInvalidoError(id_usuario)

        usuario: Usuario = next((este_usuario for este_usuario in lista_a_buscar if este_usuario.usuario_id == id_usuario), None)

        if not usuario:
            raise UsuarioNoEncontradoError(id_usuario)

        return usuario

    def obtener_producto_por_id(self, id_producto: int,lista_a_buscar: list[Producto]) -> Producto:
        """
        Trae y devuelve un producto específico según su ID.
        Valida: el id del producto.
        """

        if id_producto <= 0:
            raise IdProductoInvalidoError(id_producto)

        producto: Producto = next((este_producto for este_producto in lista_a_buscar if este_producto.producto_id == id_producto), None)

        if not producto:
            raise ProductoNoEncontradoError(id_producto)

        return producto

    def obtener_item_carrito_por_id(self, usuario: Usuario, id_producto: int) -> ItemCarrito:
        """
        Trae y devuelve un item específico del carrito de un usuario según el ID del producto.
        Valida: el id del usuario, el id del producto y si el producto está en el carrito.
        """

        item_carrito: ItemCarrito = next((este_item for este_item in usuario.carrito.items if este_item.producto_id == id_producto), None)

        return item_carrito


    def validar_usuario_gerente(self, usuario: Usuario) -> None:
        """
        Valida que un usuario específico tenga rol de gerente.
        """

        if usuario.rol != Rol.GERENTE:
            raise PermisoDenegadoError("Acceso denegado: Se requiere rol de Gerente")

    def validar_usuario_empleado(self, usuario: Usuario) -> None:
        """
        Valida que un usuario específico tenga rol de empleado.
        Valida: el id del usuario y su rol.
        """

        if usuario.rol != Rol.EMPLEADO:
            raise PermisoDenegadoError("Acceso denegado: Se requiere rol de Empleado")

    def validar_stock_suficiente(self, cantidad_solicitada: int, producto: Producto) -> None:
        """
        Valida que la cantidad solicitada de un producto no supere el stock disponible.
        Valida: la cantidad solicitada y el stock disponible.
        """

        if producto.stock < cantidad_solicitada:
            raise StockInsuficienteError(producto.producto_id, producto.stock) 

    def validar_carrito_no_vacio(self, lista: list[ItemCarrito]) -> None:
        """
        Valida que el carrito no esté vacío.
        """
        if not lista:
            raise CarritoVacioError() # Unica exepción que no recibe parámetros porque el mensaje de error es fijo ya que solo se da en un unico caso.

    def validar_lista_usuarios_no_vacia(self, usuarios: List[Usuario]) -> None:
        """
        Valida que la lista de usuarios no esté vacía antes de mostrarla.
        """
        if not usuarios:
            raise UsuarioNoEncontradoError("No hay usuarios en el sistema")

    def validar_lista_productos_no_vacia(self, productos: List[Producto]) -> None:
        """
        Valida que la lista de productos no esté vacía antes de mostrarla.
        """
        if not productos:
            raise ProductoNoEncontradoError("No hay productos en el inventario")

    def validar_cantidad_valida(self, cantidad: int) -> None:
        """
        Valida que la cantidad ingresada sea un número entero positivo.
        """
        if cantidad <= 0:
            raise CantidadInvalidaError(cantidad)


    def agregar_al_carrito(self, id_usuario: int, id_producto: int, cantidad: int) -> None:
        """
        Agrega un producto en especifico al carrito de un usuario en específico.
        Valida: Los permisos (solo empleados pueden usar el carrito) y stock.
        """

        self.validar_cantidad_valida(cantidad=cantidad)

        usuarios: list[Usuario] = self.obtener_usuarios()
        productos: list[Producto] = self.obtener_productos()

        usuario_actual: Usuario = self.obtener_usuario_por_id(id_usuario=id_usuario, lista_a_buscar=usuarios)
        self.validar_usuario_empleado(usuario = usuario_actual)

        producto: Producto = self.obtener_producto_por_id(id_producto=id_producto, lista_a_buscar=productos)
        self.validar_stock_suficiente(cantidad_solicitada=cantidad, producto=producto)

        item_existente: ItemCarrito = self.obtener_item_carrito_por_id(usuario=usuario_actual, id_producto=id_producto)

        if item_existente:
            item_existente.cantidad += cantidad
        else:
            nuevo_item: ItemCarrito = ItemCarrito(
                producto_id=producto.producto_id,
                nombre=producto.nombre,
                precio_unitario=producto.precio,
                cantidad=cantidad
            )
            usuario_actual.carrito.items.append(nuevo_item)

        self.almacenamiento_usuarios.save(usuarios)

    def facturar_carrito(self, id_usuario: int) -> None:
        """
        Se encarga de facturar el carrito de un usuario  y actualiza el inventario.
        Valida: el id del usuario, el stock y permiso de usuario (solo empleados pueden facturar).
        """

        usuarios: list[Usuario] = self.obtener_usuarios()
        productos: list[Producto] = self.obtener_productos()

        usuario_actual: Usuario = self.obtener_usuario_por_id(id_usuario=id_usuario, lista_a_buscar=usuarios)
        self.validar_usuario_empleado(usuario = usuario_actual)
        self.validar_carrito_no_vacio(usuario_actual.carrito.items)
        for item in usuario_actual.carrito.items:
            producto_en_inventario: Producto = self.obtener_producto_por_id(id_producto= item.producto_id, lista_a_buscar=productos)
            self.validar_stock_suficiente(cantidad_solicitada=item.cantidad, producto=producto_en_inventario)
            producto_en_inventario.stock -= item.cantidad

        usuario_actual.carrito.items = []

        self.almacenamiento_productos.save(productos)
        self.almacenamiento_usuarios.save(usuarios)

    def quitar_producto_del_carrito(self, id_usuario: int, id_producto: int) -> None:
        """
        Elimina un producto específico del carrito de un usuario.
        Valida: el id del usuario, el id del producto, el permiso de usuario (solo empleados pueden usar el carrito) y si el producto está en el carrito.
        """

        usuarios: list[Usuario] = self.obtener_usuarios()
        usuario_actual: Usuario = self.obtener_usuario_por_id(id_usuario=id_usuario, lista_a_buscar=usuarios)
        self.validar_usuario_empleado(usuario = usuario_actual)


        item_a_eliminar: ItemCarrito = self.obtener_item_carrito_por_id(usuario=usuario_actual, id_producto=id_producto)

        usuario_actual.carrito.items.remove(item_a_eliminar)
        self.almacenamiento_usuarios.save(usuarios)

    def agregar_stock_producto(self, id_gerente: int, id_producto: int, cantidad_a_agregar: int) -> None:
        """
        Agrega stock a un producto específico en el inventario.
        Valida: el id del gerente, el id del producto, la cantidad a agregar y permiso de usuario (solo gerentes pueden ejecutar esta acción).
        """

        productos: list[Producto] = self.obtener_productos()
        usuarios: list[Usuario] = self.obtener_usuarios()

        gerente: Usuario = self.obtener_usuario_por_id(id_usuario=id_gerente, lista_a_buscar=usuarios)
        self.validar_usuario_gerente(usuario = gerente)

        producto_a_actualizar: Producto = self.obtener_producto_por_id(id_producto=id_producto, lista_a_buscar=productos)
        self.validar_cantidad_valida(cantidad_a_agregar)

        producto_a_actualizar.stock += cantidad_a_agregar
        productos[productos.index(producto_a_actualizar)] = producto_a_actualizar # Index devuelve la posición del producto a actualizar en la lista de productos.
        self.almacenamiento_productos.save(productos)

    def crear_producto(self, id_gerente: int, nombre_nuevo_producto: str, precio_nuevo_producto: float, stock_nuevo_producto: int) -> None:
        """
        Crea un nuevo producto.
        Valida: el id del gerente, nombre, precio, stock y permiso de usuario (solo gerentes pueden ejecutarla).
        """

        productos: list[Producto] = self.obtener_productos()
        usuarios: list[Usuario] = self.obtener_usuarios()

        gerente: Usuario = self.obtener_usuario_por_id(id_usuario=id_gerente, lista_a_buscar=usuarios)
        self.validar_usuario_gerente(usuario = gerente)

        productos: list[Producto] = self.obtener_productos()

        if any(este_producto.nombre.lower() == nombre_nuevo_producto.lower() for este_producto in productos): #Any devuelve True si al menos un elemento del iterable cumple la condición
            raise ProductoYaExisteError(nombre_nuevo_producto)


        nuevo_id: int = max([este_producto.producto_id for este_producto in productos], default=0) + 1
        nuevo_producto: Producto = Producto(producto_id=nuevo_id, nombre=nombre_nuevo_producto, precio=precio_nuevo_producto, stock=stock_nuevo_producto)

        productos.append(nuevo_producto)
        self.almacenamiento_productos.save(productos)

    def crear_usuario(self, id_gerente: int, nombre_nuevo_usuario: str, rol_nuevo_usuario: Rol) -> None:
        """
        Crea un nuevo usuario.
        Valida: el id del gerente, nombre de usuario, rol y permiso de usuario (solo gerentes pueden ejecutarla).
        """

        usuarios: list[Usuario] = self.obtener_usuarios()

        gerente: Usuario = self.obtener_usuario_por_id(id_usuario=id_gerente, lista_a_buscar=usuarios)
        self.validar_usuario_gerente(usuario = gerente)

        if any(este_usuario.nombre_usuario.lower() == nombre_nuevo_usuario.lower() for este_usuario in usuarios):
            raise UsuarioYaExisteError(nombre_nuevo_usuario)

        nuevo_id: int = max([este_usuario.usuario_id for este_usuario in usuarios], default=0) + 1
        nuevo_usuario: Usuario = Usuario(usuario_id=nuevo_id, nombre_usuario=nombre_nuevo_usuario, rol=rol_nuevo_usuario)

        usuarios.append(nuevo_usuario)
        self.almacenamiento_usuarios.save(usuarios)

    def eliminar_producto(self, id_gerente: int, id_producto: int) -> None:
        """
        Elimina un producto del inventario.
        Valida: el id del gerente, el id del producto y permiso de usuario (solo gerentes pueden ejecutar esta acción).
        """
        usuarios: list[Usuario] = self.obtener_usuarios()
        gerente: Usuario = self.obtener_usuario_por_id(id_usuario=id_gerente, lista_a_buscar=usuarios)
        self.validar_usuario_gerente(usuario = gerente)

        productos: list[Producto] = self.obtener_productos()
        producto_a_eliminar: Producto =self.obtener_producto_por_id(id_producto=id_producto, lista_a_buscar=productos)

        productos.remove(producto_a_eliminar)
        self.almacenamiento_productos.save(productos)

    def eliminar_usuario(self, id_gerente: int, id_usuario: int) -> None:
        """
        Elimina un usuario del sistema.
        Valida: el id del gerente, el id del usuario y permiso de usuario (solo gerentes pueden ejecutar esta acción).
        """

        usuarios: list[Usuario] = self.obtener_usuarios()
        gerente: Usuario = self.obtener_usuario_por_id(id_usuario=id_gerente, lista_a_buscar=usuarios)
        self.validar_usuario_gerente(usuario = gerente)


        usuario_a_eliminar: Usuario = self.obtener_usuario_por_id(id_usuario=id_usuario, lista_a_buscar=usuarios)

        usuarios.remove(usuario_a_eliminar)
        self.almacenamiento_usuarios.save(usuarios)

    def mostrar_carrito(self, id_usuario: int) -> None:
        """
        Muestra el contenido del carrito de un usuario en forma de tabla usando Rich.
        Valida: Si el carrito está vacío.
        """

        console: Console = Console()

        usuarios: list[Usuario] = self.obtener_usuarios()
        usuario: Usuario = self.obtener_usuario_por_id(id_usuario=id_usuario, lista_a_buscar=usuarios)
        self.validar_carrito_no_vacio(usuario.carrito.items)

        tabla_carrito: Table = Table(title=f"Carrito de {usuario.nombre_usuario}", show_header=True, header_style="orange1") # show_header=True muestra el encabezado de la tabla y header_style le da estilo al encabezado
        tabla_carrito.add_column("ID Producto", style="cyan", width=12)
        tabla_carrito.add_column("Nombre", style="green", width=20)
        tabla_carrito.add_column("Precio Unitario", style="yellow", width=15)
        tabla_carrito.add_column("Cantidad", style="blue", width=10)
        tabla_carrito.add_column("Subtotal", style="red", width=15)

        total_carrito: float = 0
        for item in usuario.carrito.items:
            subtotal: float = item.precio_unitario * item.cantidad
            total_carrito += subtotal
            tabla_carrito.add_row(
                str(item.producto_id),
                item.nombre,
                f"${item.precio_unitario:.2f}", #El :.2f es para formatear el número a 2 decimales y si hay más de 2 decimales, los redondea.
                str(item.cantidad),
                f"${subtotal:.2f}"
            )

        console.print(tabla_carrito)
        console.print(f"\n[bold green]Total del carrito: ${total_carrito:.2f}[/bold green]")

    def mostrar_usuarios(self, id_gerente: int) -> None:
        """
        Muestra todos los usuarios del sistema en forma de tabla. 
        Valida: el id del gerente y permiso de usuario (solo gerentes pueden ejecutarla).
        """

        console: Console = Console()
        usuarios: list[Usuario] = self.obtener_usuarios()
        self.validar_lista_usuarios_no_vacia(usuarios=usuarios)

        gerente: Usuario = self.obtener_usuario_por_id(id_usuario=id_gerente, lista_a_buscar=usuarios)
        self.validar_usuario_gerente(usuario = gerente)

        table: Table = Table(title="Lista de Usuarios", show_header=True, header_style="bold magenta")
        table.add_column("ID", style="cyan", width=8)
        table.add_column("Nombre de Usuario", style="green", width=20)
        table.add_column("Rol", style="yellow", width=15)
        table.add_column("Items en Carrito", style="blue", width=15)

        for usuario in usuarios:
            cantidad_items: int = len(usuario.carrito.items)
            table.add_row(
                str(usuario.usuario_id),
                usuario.nombre_usuario,
                usuario.rol.value,
                str(cantidad_items)
            )

        console.print(table)

    def mostrar_productos(self, id_gerente: int) -> None:
        """
        Muestra todos los productos del inventario en forma de tabla. 
        Valida: el id del gerente y permiso de usuario (solo gerentes pueden ejecutarla).
        """

        console: Console = Console()

        usuarios: list[Usuario] = self.obtener_usuarios()
        gerente: Usuario = self.obtener_usuario_por_id(id_usuario=id_gerente, lista_a_buscar=usuarios)
        self.validar_usuario_gerente(usuario = gerente)

        productos: Producto = self.obtener_productos()
        self.validar_lista_productos_no_vacia(productos=productos)

        table: Table = Table(title="Inventario de Productos", show_header=True, header_style="pink1")
        table.add_column("ID", style="cyan", width=8)
        table.add_column("Nombre", style="green", width=25)
        table.add_column("Precio", style="yellow", width=12)
        table.add_column("Stock", style="blue", width=10)
        table.add_column("Valor Total", style="red", width=15)

        valor_total_inventario: float = 0
        for producto in productos:
            valor_producto: float = producto.precio * producto.stock
            valor_total_inventario += valor_producto

            table.add_row(
                str(producto.producto_id),
                producto.nombre,
                f"${producto.precio:.2f}",
                str(producto.stock),
                f"${valor_producto:.2f}"
            )

        console.print(table)
        console.print(f"\n[bold green]Valor Total del Inventario: ${valor_total_inventario:.2f}[/bold green]")

agregar_al_carrito(id_usuario, id_producto, cantidad)

Agrega un producto en especifico al carrito de un usuario en específico. Valida: Los permisos (solo empleados pueden usar el carrito) y stock.

Source code in src/gerencia_app/servicios.py
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
def agregar_al_carrito(self, id_usuario: int, id_producto: int, cantidad: int) -> None:
    """
    Agrega un producto en especifico al carrito de un usuario en específico.
    Valida: Los permisos (solo empleados pueden usar el carrito) y stock.
    """

    self.validar_cantidad_valida(cantidad=cantidad)

    usuarios: list[Usuario] = self.obtener_usuarios()
    productos: list[Producto] = self.obtener_productos()

    usuario_actual: Usuario = self.obtener_usuario_por_id(id_usuario=id_usuario, lista_a_buscar=usuarios)
    self.validar_usuario_empleado(usuario = usuario_actual)

    producto: Producto = self.obtener_producto_por_id(id_producto=id_producto, lista_a_buscar=productos)
    self.validar_stock_suficiente(cantidad_solicitada=cantidad, producto=producto)

    item_existente: ItemCarrito = self.obtener_item_carrito_por_id(usuario=usuario_actual, id_producto=id_producto)

    if item_existente:
        item_existente.cantidad += cantidad
    else:
        nuevo_item: ItemCarrito = ItemCarrito(
            producto_id=producto.producto_id,
            nombre=producto.nombre,
            precio_unitario=producto.precio,
            cantidad=cantidad
        )
        usuario_actual.carrito.items.append(nuevo_item)

    self.almacenamiento_usuarios.save(usuarios)

agregar_stock_producto(id_gerente, id_producto, cantidad_a_agregar)

Agrega stock a un producto específico en el inventario. Valida: el id del gerente, el id del producto, la cantidad a agregar y permiso de usuario (solo gerentes pueden ejecutar esta acción).

Source code in src/gerencia_app/servicios.py
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
def agregar_stock_producto(self, id_gerente: int, id_producto: int, cantidad_a_agregar: int) -> None:
    """
    Agrega stock a un producto específico en el inventario.
    Valida: el id del gerente, el id del producto, la cantidad a agregar y permiso de usuario (solo gerentes pueden ejecutar esta acción).
    """

    productos: list[Producto] = self.obtener_productos()
    usuarios: list[Usuario] = self.obtener_usuarios()

    gerente: Usuario = self.obtener_usuario_por_id(id_usuario=id_gerente, lista_a_buscar=usuarios)
    self.validar_usuario_gerente(usuario = gerente)

    producto_a_actualizar: Producto = self.obtener_producto_por_id(id_producto=id_producto, lista_a_buscar=productos)
    self.validar_cantidad_valida(cantidad_a_agregar)

    producto_a_actualizar.stock += cantidad_a_agregar
    productos[productos.index(producto_a_actualizar)] = producto_a_actualizar # Index devuelve la posición del producto a actualizar en la lista de productos.
    self.almacenamiento_productos.save(productos)

crear_producto(id_gerente, nombre_nuevo_producto, precio_nuevo_producto, stock_nuevo_producto)

Crea un nuevo producto. Valida: el id del gerente, nombre, precio, stock y permiso de usuario (solo gerentes pueden ejecutarla).

Source code in src/gerencia_app/servicios.py
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
def crear_producto(self, id_gerente: int, nombre_nuevo_producto: str, precio_nuevo_producto: float, stock_nuevo_producto: int) -> None:
    """
    Crea un nuevo producto.
    Valida: el id del gerente, nombre, precio, stock y permiso de usuario (solo gerentes pueden ejecutarla).
    """

    productos: list[Producto] = self.obtener_productos()
    usuarios: list[Usuario] = self.obtener_usuarios()

    gerente: Usuario = self.obtener_usuario_por_id(id_usuario=id_gerente, lista_a_buscar=usuarios)
    self.validar_usuario_gerente(usuario = gerente)

    productos: list[Producto] = self.obtener_productos()

    if any(este_producto.nombre.lower() == nombre_nuevo_producto.lower() for este_producto in productos): #Any devuelve True si al menos un elemento del iterable cumple la condición
        raise ProductoYaExisteError(nombre_nuevo_producto)


    nuevo_id: int = max([este_producto.producto_id for este_producto in productos], default=0) + 1
    nuevo_producto: Producto = Producto(producto_id=nuevo_id, nombre=nombre_nuevo_producto, precio=precio_nuevo_producto, stock=stock_nuevo_producto)

    productos.append(nuevo_producto)
    self.almacenamiento_productos.save(productos)

crear_usuario(id_gerente, nombre_nuevo_usuario, rol_nuevo_usuario)

Crea un nuevo usuario. Valida: el id del gerente, nombre de usuario, rol y permiso de usuario (solo gerentes pueden ejecutarla).

Source code in src/gerencia_app/servicios.py
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
def crear_usuario(self, id_gerente: int, nombre_nuevo_usuario: str, rol_nuevo_usuario: Rol) -> None:
    """
    Crea un nuevo usuario.
    Valida: el id del gerente, nombre de usuario, rol y permiso de usuario (solo gerentes pueden ejecutarla).
    """

    usuarios: list[Usuario] = self.obtener_usuarios()

    gerente: Usuario = self.obtener_usuario_por_id(id_usuario=id_gerente, lista_a_buscar=usuarios)
    self.validar_usuario_gerente(usuario = gerente)

    if any(este_usuario.nombre_usuario.lower() == nombre_nuevo_usuario.lower() for este_usuario in usuarios):
        raise UsuarioYaExisteError(nombre_nuevo_usuario)

    nuevo_id: int = max([este_usuario.usuario_id for este_usuario in usuarios], default=0) + 1
    nuevo_usuario: Usuario = Usuario(usuario_id=nuevo_id, nombre_usuario=nombre_nuevo_usuario, rol=rol_nuevo_usuario)

    usuarios.append(nuevo_usuario)
    self.almacenamiento_usuarios.save(usuarios)

eliminar_producto(id_gerente, id_producto)

Elimina un producto del inventario. Valida: el id del gerente, el id del producto y permiso de usuario (solo gerentes pueden ejecutar esta acción).

Source code in src/gerencia_app/servicios.py
279
280
281
282
283
284
285
286
287
288
289
290
291
292
def eliminar_producto(self, id_gerente: int, id_producto: int) -> None:
    """
    Elimina un producto del inventario.
    Valida: el id del gerente, el id del producto y permiso de usuario (solo gerentes pueden ejecutar esta acción).
    """
    usuarios: list[Usuario] = self.obtener_usuarios()
    gerente: Usuario = self.obtener_usuario_por_id(id_usuario=id_gerente, lista_a_buscar=usuarios)
    self.validar_usuario_gerente(usuario = gerente)

    productos: list[Producto] = self.obtener_productos()
    producto_a_eliminar: Producto =self.obtener_producto_por_id(id_producto=id_producto, lista_a_buscar=productos)

    productos.remove(producto_a_eliminar)
    self.almacenamiento_productos.save(productos)

eliminar_usuario(id_gerente, id_usuario)

Elimina un usuario del sistema. Valida: el id del gerente, el id del usuario y permiso de usuario (solo gerentes pueden ejecutar esta acción).

Source code in src/gerencia_app/servicios.py
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
def eliminar_usuario(self, id_gerente: int, id_usuario: int) -> None:
    """
    Elimina un usuario del sistema.
    Valida: el id del gerente, el id del usuario y permiso de usuario (solo gerentes pueden ejecutar esta acción).
    """

    usuarios: list[Usuario] = self.obtener_usuarios()
    gerente: Usuario = self.obtener_usuario_por_id(id_usuario=id_gerente, lista_a_buscar=usuarios)
    self.validar_usuario_gerente(usuario = gerente)


    usuario_a_eliminar: Usuario = self.obtener_usuario_por_id(id_usuario=id_usuario, lista_a_buscar=usuarios)

    usuarios.remove(usuario_a_eliminar)
    self.almacenamiento_usuarios.save(usuarios)

facturar_carrito(id_usuario)

Se encarga de facturar el carrito de un usuario y actualiza el inventario. Valida: el id del usuario, el stock y permiso de usuario (solo empleados pueden facturar).

Source code in src/gerencia_app/servicios.py
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
def facturar_carrito(self, id_usuario: int) -> None:
    """
    Se encarga de facturar el carrito de un usuario  y actualiza el inventario.
    Valida: el id del usuario, el stock y permiso de usuario (solo empleados pueden facturar).
    """

    usuarios: list[Usuario] = self.obtener_usuarios()
    productos: list[Producto] = self.obtener_productos()

    usuario_actual: Usuario = self.obtener_usuario_por_id(id_usuario=id_usuario, lista_a_buscar=usuarios)
    self.validar_usuario_empleado(usuario = usuario_actual)
    self.validar_carrito_no_vacio(usuario_actual.carrito.items)
    for item in usuario_actual.carrito.items:
        producto_en_inventario: Producto = self.obtener_producto_por_id(id_producto= item.producto_id, lista_a_buscar=productos)
        self.validar_stock_suficiente(cantidad_solicitada=item.cantidad, producto=producto_en_inventario)
        producto_en_inventario.stock -= item.cantidad

    usuario_actual.carrito.items = []

    self.almacenamiento_productos.save(productos)
    self.almacenamiento_usuarios.save(usuarios)

mostrar_carrito(id_usuario)

Muestra el contenido del carrito de un usuario en forma de tabla usando Rich. Valida: Si el carrito está vacío.

Source code in src/gerencia_app/servicios.py
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
def mostrar_carrito(self, id_usuario: int) -> None:
    """
    Muestra el contenido del carrito de un usuario en forma de tabla usando Rich.
    Valida: Si el carrito está vacío.
    """

    console: Console = Console()

    usuarios: list[Usuario] = self.obtener_usuarios()
    usuario: Usuario = self.obtener_usuario_por_id(id_usuario=id_usuario, lista_a_buscar=usuarios)
    self.validar_carrito_no_vacio(usuario.carrito.items)

    tabla_carrito: Table = Table(title=f"Carrito de {usuario.nombre_usuario}", show_header=True, header_style="orange1") # show_header=True muestra el encabezado de la tabla y header_style le da estilo al encabezado
    tabla_carrito.add_column("ID Producto", style="cyan", width=12)
    tabla_carrito.add_column("Nombre", style="green", width=20)
    tabla_carrito.add_column("Precio Unitario", style="yellow", width=15)
    tabla_carrito.add_column("Cantidad", style="blue", width=10)
    tabla_carrito.add_column("Subtotal", style="red", width=15)

    total_carrito: float = 0
    for item in usuario.carrito.items:
        subtotal: float = item.precio_unitario * item.cantidad
        total_carrito += subtotal
        tabla_carrito.add_row(
            str(item.producto_id),
            item.nombre,
            f"${item.precio_unitario:.2f}", #El :.2f es para formatear el número a 2 decimales y si hay más de 2 decimales, los redondea.
            str(item.cantidad),
            f"${subtotal:.2f}"
        )

    console.print(tabla_carrito)
    console.print(f"\n[bold green]Total del carrito: ${total_carrito:.2f}[/bold green]")

mostrar_productos(id_gerente)

Muestra todos los productos del inventario en forma de tabla. Valida: el id del gerente y permiso de usuario (solo gerentes pueden ejecutarla).

Source code in src/gerencia_app/servicios.py
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
def mostrar_productos(self, id_gerente: int) -> None:
    """
    Muestra todos los productos del inventario en forma de tabla. 
    Valida: el id del gerente y permiso de usuario (solo gerentes pueden ejecutarla).
    """

    console: Console = Console()

    usuarios: list[Usuario] = self.obtener_usuarios()
    gerente: Usuario = self.obtener_usuario_por_id(id_usuario=id_gerente, lista_a_buscar=usuarios)
    self.validar_usuario_gerente(usuario = gerente)

    productos: Producto = self.obtener_productos()
    self.validar_lista_productos_no_vacia(productos=productos)

    table: Table = Table(title="Inventario de Productos", show_header=True, header_style="pink1")
    table.add_column("ID", style="cyan", width=8)
    table.add_column("Nombre", style="green", width=25)
    table.add_column("Precio", style="yellow", width=12)
    table.add_column("Stock", style="blue", width=10)
    table.add_column("Valor Total", style="red", width=15)

    valor_total_inventario: float = 0
    for producto in productos:
        valor_producto: float = producto.precio * producto.stock
        valor_total_inventario += valor_producto

        table.add_row(
            str(producto.producto_id),
            producto.nombre,
            f"${producto.precio:.2f}",
            str(producto.stock),
            f"${valor_producto:.2f}"
        )

    console.print(table)
    console.print(f"\n[bold green]Valor Total del Inventario: ${valor_total_inventario:.2f}[/bold green]")

mostrar_usuarios(id_gerente)

Muestra todos los usuarios del sistema en forma de tabla. Valida: el id del gerente y permiso de usuario (solo gerentes pueden ejecutarla).

Source code in src/gerencia_app/servicios.py
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
def mostrar_usuarios(self, id_gerente: int) -> None:
    """
    Muestra todos los usuarios del sistema en forma de tabla. 
    Valida: el id del gerente y permiso de usuario (solo gerentes pueden ejecutarla).
    """

    console: Console = Console()
    usuarios: list[Usuario] = self.obtener_usuarios()
    self.validar_lista_usuarios_no_vacia(usuarios=usuarios)

    gerente: Usuario = self.obtener_usuario_por_id(id_usuario=id_gerente, lista_a_buscar=usuarios)
    self.validar_usuario_gerente(usuario = gerente)

    table: Table = Table(title="Lista de Usuarios", show_header=True, header_style="bold magenta")
    table.add_column("ID", style="cyan", width=8)
    table.add_column("Nombre de Usuario", style="green", width=20)
    table.add_column("Rol", style="yellow", width=15)
    table.add_column("Items en Carrito", style="blue", width=15)

    for usuario in usuarios:
        cantidad_items: int = len(usuario.carrito.items)
        table.add_row(
            str(usuario.usuario_id),
            usuario.nombre_usuario,
            usuario.rol.value,
            str(cantidad_items)
        )

    console.print(table)

obtener_item_carrito_por_id(usuario, id_producto)

Trae y devuelve un item específico del carrito de un usuario según el ID del producto. Valida: el id del usuario, el id del producto y si el producto está en el carrito.

Source code in src/gerencia_app/servicios.py
80
81
82
83
84
85
86
87
88
def obtener_item_carrito_por_id(self, usuario: Usuario, id_producto: int) -> ItemCarrito:
    """
    Trae y devuelve un item específico del carrito de un usuario según el ID del producto.
    Valida: el id del usuario, el id del producto y si el producto está en el carrito.
    """

    item_carrito: ItemCarrito = next((este_item for este_item in usuario.carrito.items if este_item.producto_id == id_producto), None)

    return item_carrito

obtener_producto_por_id(id_producto, lista_a_buscar)

Trae y devuelve un producto específico según su ID. Valida: el id del producto.

Source code in src/gerencia_app/servicios.py
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
def obtener_producto_por_id(self, id_producto: int,lista_a_buscar: list[Producto]) -> Producto:
    """
    Trae y devuelve un producto específico según su ID.
    Valida: el id del producto.
    """

    if id_producto <= 0:
        raise IdProductoInvalidoError(id_producto)

    producto: Producto = next((este_producto for este_producto in lista_a_buscar if este_producto.producto_id == id_producto), None)

    if not producto:
        raise ProductoNoEncontradoError(id_producto)

    return producto

obtener_productos()

Trae y devuelve la lista de productos del almacenamiento (base de datos).

Source code in src/gerencia_app/servicios.py
40
41
42
43
44
45
def obtener_productos(self) -> List[Producto]:
    """
    Trae y devuelve la lista de productos del almacenamiento (base de datos).
    """

    return self.almacenamiento_productos.load()

obtener_usuario_por_id(id_usuario, lista_a_buscar)

Trae y devuelve un usuario específico según su ID. Valida: el id del usuario.

Source code in src/gerencia_app/servicios.py
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
def obtener_usuario_por_id(self, id_usuario: int, lista_a_buscar: list[Usuario]) -> Usuario:
    """
    Trae y devuelve un usuario específico según su ID.
    Valida: el id del usuario.
    """

    if id_usuario <= 0:
        raise IdUsuarioInvalidoError(id_usuario)

    usuario: Usuario = next((este_usuario for este_usuario in lista_a_buscar if este_usuario.usuario_id == id_usuario), None)

    if not usuario:
        raise UsuarioNoEncontradoError(id_usuario)

    return usuario

obtener_usuarios()

Trae y devuelve la lista de usuarios del almacenamiento (base de datos).

Source code in src/gerencia_app/servicios.py
33
34
35
36
37
38
def obtener_usuarios(self) -> List[Usuario]:
    """
    Trae y devuelve la lista de usuarios del almacenamiento (base de datos).
    """

    return self.almacenamiento_usuarios.load()

quitar_producto_del_carrito(id_usuario, id_producto)

Elimina un producto específico del carrito de un usuario. Valida: el id del usuario, el id del producto, el permiso de usuario (solo empleados pueden usar el carrito) y si el producto está en el carrito.

Source code in src/gerencia_app/servicios.py
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
def quitar_producto_del_carrito(self, id_usuario: int, id_producto: int) -> None:
    """
    Elimina un producto específico del carrito de un usuario.
    Valida: el id del usuario, el id del producto, el permiso de usuario (solo empleados pueden usar el carrito) y si el producto está en el carrito.
    """

    usuarios: list[Usuario] = self.obtener_usuarios()
    usuario_actual: Usuario = self.obtener_usuario_por_id(id_usuario=id_usuario, lista_a_buscar=usuarios)
    self.validar_usuario_empleado(usuario = usuario_actual)


    item_a_eliminar: ItemCarrito = self.obtener_item_carrito_por_id(usuario=usuario_actual, id_producto=id_producto)

    usuario_actual.carrito.items.remove(item_a_eliminar)
    self.almacenamiento_usuarios.save(usuarios)

validar_cantidad_valida(cantidad)

Valida que la cantidad ingresada sea un número entero positivo.

Source code in src/gerencia_app/servicios.py
138
139
140
141
142
143
def validar_cantidad_valida(self, cantidad: int) -> None:
    """
    Valida que la cantidad ingresada sea un número entero positivo.
    """
    if cantidad <= 0:
        raise CantidadInvalidaError(cantidad)

validar_carrito_no_vacio(lista)

Valida que el carrito no esté vacío.

Source code in src/gerencia_app/servicios.py
117
118
119
120
121
122
def validar_carrito_no_vacio(self, lista: list[ItemCarrito]) -> None:
    """
    Valida que el carrito no esté vacío.
    """
    if not lista:
        raise CarritoVacioError() # Unica exepción que no recibe parámetros porque el mensaje de error es fijo ya que solo se da en un unico caso.

validar_lista_productos_no_vacia(productos)

Valida que la lista de productos no esté vacía antes de mostrarla.

Source code in src/gerencia_app/servicios.py
131
132
133
134
135
136
def validar_lista_productos_no_vacia(self, productos: List[Producto]) -> None:
    """
    Valida que la lista de productos no esté vacía antes de mostrarla.
    """
    if not productos:
        raise ProductoNoEncontradoError("No hay productos en el inventario")

validar_lista_usuarios_no_vacia(usuarios)

Valida que la lista de usuarios no esté vacía antes de mostrarla.

Source code in src/gerencia_app/servicios.py
124
125
126
127
128
129
def validar_lista_usuarios_no_vacia(self, usuarios: List[Usuario]) -> None:
    """
    Valida que la lista de usuarios no esté vacía antes de mostrarla.
    """
    if not usuarios:
        raise UsuarioNoEncontradoError("No hay usuarios en el sistema")

validar_stock_suficiente(cantidad_solicitada, producto)

Valida que la cantidad solicitada de un producto no supere el stock disponible. Valida: la cantidad solicitada y el stock disponible.

Source code in src/gerencia_app/servicios.py
108
109
110
111
112
113
114
115
def validar_stock_suficiente(self, cantidad_solicitada: int, producto: Producto) -> None:
    """
    Valida que la cantidad solicitada de un producto no supere el stock disponible.
    Valida: la cantidad solicitada y el stock disponible.
    """

    if producto.stock < cantidad_solicitada:
        raise StockInsuficienteError(producto.producto_id, producto.stock) 

validar_usuario_empleado(usuario)

Valida que un usuario específico tenga rol de empleado. Valida: el id del usuario y su rol.

Source code in src/gerencia_app/servicios.py
 99
100
101
102
103
104
105
106
def validar_usuario_empleado(self, usuario: Usuario) -> None:
    """
    Valida que un usuario específico tenga rol de empleado.
    Valida: el id del usuario y su rol.
    """

    if usuario.rol != Rol.EMPLEADO:
        raise PermisoDenegadoError("Acceso denegado: Se requiere rol de Empleado")

validar_usuario_gerente(usuario)

Valida que un usuario específico tenga rol de gerente.

Source code in src/gerencia_app/servicios.py
91
92
93
94
95
96
97
def validar_usuario_gerente(self, usuario: Usuario) -> None:
    """
    Valida que un usuario específico tenga rol de gerente.
    """

    if usuario.rol != Rol.GERENTE:
        raise PermisoDenegadoError("Acceso denegado: Se requiere rol de Gerente")

Modelos

👤 Usuario

Modelo para representar un usuario de la tienda, con su rol y carrito de compras.

Source code in src/gerencia_app/modelos/usuario.py
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
@dataclass
class Usuario:
    """
    Modelo para representar un usuario de la tienda, con su rol y carrito de compras.
    """

    usuario_id: int
    nombre_usuario: str
    rol: Rol
    carrito: Carrito = field(default_factory=Carrito)

    def __post_init__(self):
        """
        Validación de atributos.
        """
        if self.usuario_id <= 0:
            raise IdUsuarioInvalidoError(self.usuario_id)
        if not self.nombre_usuario.strip():
            raise NombreUsuarioInvalidoError(self.nombre_usuario)
        if self.rol not in [Rol.GERENTE, Rol.EMPLEADO]:
            raise PermisoDenegadoError("El rol especificado no es válido. Debe ser 'gerente' o 'empleado'.")

__post_init__()

Validación de atributos.

Source code in src/gerencia_app/modelos/usuario.py
21
22
23
24
25
26
27
28
29
30
def __post_init__(self):
    """
    Validación de atributos.
    """
    if self.usuario_id <= 0:
        raise IdUsuarioInvalidoError(self.usuario_id)
    if not self.nombre_usuario.strip():
        raise NombreUsuarioInvalidoError(self.nombre_usuario)
    if self.rol not in [Rol.GERENTE, Rol.EMPLEADO]:
        raise PermisoDenegadoError("El rol especificado no es válido. Debe ser 'gerente' o 'empleado'.")

🔐 Rol

Bases: Enum

Enum para definir los roles de los usuarios en la tienda.

Source code in src/gerencia_app/modelos/rol.py
 4
 5
 6
 7
 8
 9
10
class Rol(Enum):
    """
    Enum para definir los roles de los usuarios en la tienda.
    """

    GERENTE = "gerente"
    EMPLEADO = "empleado"

🛒 Carrito

Modelo para representar el carrito de compras de un usuario, contiene una lista de items.

Source code in src/gerencia_app/modelos/carrito.py
 6
 7
 8
 9
10
11
12
@dataclass
class Carrito:
    """
    Modelo para representar el carrito de compras de un usuario, contiene una lista de items.
    """

    items: List[ItemCarrito] = field(default_factory=list)

🛍️ Item Carrito

Modelo para representar un item dentro del carrito de compras y validar sus datos.

Source code in src/gerencia_app/modelos/item_carrito.py
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@dataclass
class ItemCarrito:
    """
    Modelo para representar un item dentro del carrito de compras y validar sus datos.
    """

    producto_id: int
    nombre: str
    precio_unitario: float
    cantidad: int

    def __post_init__(self):
        if self.producto_id <= 0:
            raise IdProductoInvalidoError(self.producto_id)
        if not self.nombre.strip():
            raise NombreProductoInvalidoError(self.nombre)
        if self.precio_unitario <= 0:
            raise CantidadInvalidaError(self.precio_unitario)

💎 Producto

Modelo para representar un producto en el inventario de la tienda.

Source code in src/gerencia_app/modelos/producto.py
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@dataclass
class Producto:
    """
    Modelo para representar un producto en el inventario de la tienda.
    """

    producto_id: int
    nombre: str
    precio: float
    stock: int

    def __post_init__(self):
        if self.producto_id <= 0:
            raise IdProductoInvalidoError(self.producto_id)
        if not self.nombre.strip():
            raise NombreProductoInvalidoError(self.nombre)
        if self.precio <= 0:
            raise CantidadInvalidaError(self.precio)
        if self.stock < 0:
            raise CantidadInvalidaError(self.stock)

Almacenamiento de data

📑 JSONStorage

Clase encargada de manejar el almacenamiento en formato JSON para cualquier modelo de datos.

Source code in src/gerencia_app/almacenamiento.py
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
class JSONStorage:
    """
    Clase encargada de manejar el almacenamiento en formato JSON para cualquier modelo de datos.
    """

    def __init__(self, base_a_guardar: Path, modelo_clase: Type[variable_universal]):
        self.base_a_guardar = base_a_guardar
        self.modelo_clase = modelo_clase

    def load(self) -> List[variable_universal]:
        """
        Carga los datos desde el archivo JSON y convierte cada diccionario a una instancia del modelo_clase
        Devuelve la lista de objetos.
        """
        if not self.base_a_guardar.exists():
            return []

        with open(self.base_a_guardar, "r", encoding="utf-8") as datos_en_la_base_de_datos:
            lista_diccionarios = json.load(datos_en_la_base_de_datos) 

        objetos_finales = []
        for mi_diccionario_actual in lista_diccionarios:
            if self.modelo_clase == Usuario:
                mi_diccionario_actual["rol"] = Rol(mi_diccionario_actual["rol"])

                lista_del_dict_de_carrito = mi_diccionario_actual.get("carrito", [])
                mi_diccionarios_item = [ItemCarrito(**cada_dict) for cada_dict in lista_del_dict_de_carrito] # "**cada_dict" hace que la llave se iguale con el contenido llave = contenido
                mi_diccionario_actual["carrito"] = Carrito(items=mi_diccionarios_item)

                objetos_finales.append(Usuario(**mi_diccionario_actual))
            else:
                objetos_finales.append(self.modelo_clase(**mi_diccionario_actual))

        return objetos_finales

    def save(self, items: List[variable_universal]) -> None:
        """
        Toma una lista de objetos, los convierte a diccionarios y los guarda en el archivo JSON.
        """

        self.base_a_guardar.parent.mkdir(parents=True, exist_ok=True) # Asegura que la carpeta exista antes de guardar el archivo

        datos_preparados = []
        for objetos in items:
            dicccionario_objetos = asdict(objetos) # asdict convierte TODA la jerarquía de objetos a diccionarios

            if "rol" in dicccionario_objetos:
                dicccionario_objetos["rol"] = objetos.rol.value

            if "carrito" in dicccionario_objetos:
                dicccionario_objetos["carrito"] = dicccionario_objetos["carrito"]["items"]

            datos_preparados.append(dicccionario_objetos)

        with open(self.base_a_guardar, "w", encoding="utf-8") as f:
            json.dump(datos_preparados, f, indent=4, ensure_ascii=False)

load()

Carga los datos desde el archivo JSON y convierte cada diccionario a una instancia del modelo_clase Devuelve la lista de objetos.

Source code in src/gerencia_app/almacenamiento.py
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
def load(self) -> List[variable_universal]:
    """
    Carga los datos desde el archivo JSON y convierte cada diccionario a una instancia del modelo_clase
    Devuelve la lista de objetos.
    """
    if not self.base_a_guardar.exists():
        return []

    with open(self.base_a_guardar, "r", encoding="utf-8") as datos_en_la_base_de_datos:
        lista_diccionarios = json.load(datos_en_la_base_de_datos) 

    objetos_finales = []
    for mi_diccionario_actual in lista_diccionarios:
        if self.modelo_clase == Usuario:
            mi_diccionario_actual["rol"] = Rol(mi_diccionario_actual["rol"])

            lista_del_dict_de_carrito = mi_diccionario_actual.get("carrito", [])
            mi_diccionarios_item = [ItemCarrito(**cada_dict) for cada_dict in lista_del_dict_de_carrito] # "**cada_dict" hace que la llave se iguale con el contenido llave = contenido
            mi_diccionario_actual["carrito"] = Carrito(items=mi_diccionarios_item)

            objetos_finales.append(Usuario(**mi_diccionario_actual))
        else:
            objetos_finales.append(self.modelo_clase(**mi_diccionario_actual))

    return objetos_finales

save(items)

Toma una lista de objetos, los convierte a diccionarios y los guarda en el archivo JSON.

Source code in src/gerencia_app/almacenamiento.py
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
def save(self, items: List[variable_universal]) -> None:
    """
    Toma una lista de objetos, los convierte a diccionarios y los guarda en el archivo JSON.
    """

    self.base_a_guardar.parent.mkdir(parents=True, exist_ok=True) # Asegura que la carpeta exista antes de guardar el archivo

    datos_preparados = []
    for objetos in items:
        dicccionario_objetos = asdict(objetos) # asdict convierte TODA la jerarquía de objetos a diccionarios

        if "rol" in dicccionario_objetos:
            dicccionario_objetos["rol"] = objetos.rol.value

        if "carrito" in dicccionario_objetos:
            dicccionario_objetos["carrito"] = dicccionario_objetos["carrito"]["items"]

        datos_preparados.append(dicccionario_objetos)

    with open(self.base_a_guardar, "w", encoding="utf-8") as f:
        json.dump(datos_preparados, f, indent=4, ensure_ascii=False)