From 4e9ddb6bce1d8b2c7664eab0f71c05027b118adc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edrei=20T=C3=A9llez?= Date: Mon, 3 Aug 2026 11:07:24 -0600 Subject: [PATCH] UX-013: endpoint PUT /carrito/mover-modulo para superadmin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Agrega MoverModuloCarritoDto y CarritoService.moverModulo() como método dedicado (no toca update() existente) que valida que el módulo destino pertenezca a la misma institución del carrito. Expone PUT /carrito/mover-modulo protegido con validarSuperAdmin. Co-authored-by: Cursor --- src/carrito/carrito.controller.ts | 27 +++++++++++++++++++++++ src/carrito/carrito.service.ts | 27 +++++++++++++++++++++++ src/carrito/dto/input/mover-modulo.dto.ts | 9 ++++++++ 3 files changed, 63 insertions(+) create mode 100644 src/carrito/dto/input/mover-modulo.dto.ts diff --git a/src/carrito/carrito.controller.ts b/src/carrito/carrito.controller.ts index ca7b51f..21f2c58 100644 --- a/src/carrito/carrito.controller.ts +++ b/src/carrito/carrito.controller.ts @@ -23,6 +23,7 @@ import { ValidarUsuarioService } from '../validar-usuario/validar-usuario.servic import { CarritoDto } from './dto/input/carrito.dto'; import { CarritosDto } from './dto/input/carritos.dto'; import { CreateCarritoDto } from './dto/input/create.dto'; +import { MoverModuloCarritoDto } from './dto/input/mover-modulo.dto'; import { UpdateCarritoDto } from './dto/input/update.dto'; import { MessageOutputDto } from '../dto/output/message.dto'; import { CarritoOutputDto } from './dto/output/carrito.dto'; @@ -183,4 +184,30 @@ export class CarritoController { body.numero_equipos, ); } + + @Serealize(MessageOutputDto) + @Put('mover-modulo') + @UseGuards(AuthGuard('jwt')) + @ApiOperation({ + description: + 'Mover un carrito a otro módulo de la misma institución (superadmin).', + }) + @ApiBearerAuth('jwt') + @ApiBody({ + description: 'Variables que necesita el endpoint.', + examples: { + ejemplo: { + value: { + id_carrito: 1, + id_modulo: 2, + }, + }, + }, + }) + moverModulo(@Request() req, @Body() body: MoverModuloCarritoDto) { + const superAdmin: Operador = req.user.operador; + + this.validarUsuarioService.validarSuperAdmin(superAdmin); + return this.carritoService.moverModulo(body.id_carrito, body.id_modulo); + } } diff --git a/src/carrito/carrito.service.ts b/src/carrito/carrito.service.ts index 50d7a16..5c4725a 100644 --- a/src/carrito/carrito.service.ts +++ b/src/carrito/carrito.service.ts @@ -1,4 +1,5 @@ import { + ConflictException, ForbiddenException, forwardRef, Inject, @@ -243,6 +244,32 @@ export class CarritoService { }); } + async moverModulo( + id_carrito: number, + id_modulo: number, + ): Promise<{ message: string }> { + const carrito = await this.findById(id_carrito); + const modulo = await this.moduloService.findById(id_modulo); + + // Validamos que el módulo destino no sea el módulo actual del carrito + if (carrito.modulo.id_modulo === modulo.id_modulo) + throw new ConflictException('Este carrito ya pertenece a este módulo.'); + // Validamos que el módulo destino pertenezca a la misma institución del carrito + if ( + carrito.modulo.institucion.id_institucion != + modulo.institucion.id_institucion + ) + throw new ForbiddenException( + 'No puedes mover este carrito a un módulo que no pertenece a la misma institución.', + ); + carrito.modulo = modulo; + return this.repository + .save(carrito) + .then((_) => ({ + message: 'Se movió correctamente el carrito de módulo.', + })); + } + private viewToCarrito(infoCarrito: InformacionCarritoView): Carrito { if (!infoCarrito) return null; return this.repository.create({ diff --git a/src/carrito/dto/input/mover-modulo.dto.ts b/src/carrito/dto/input/mover-modulo.dto.ts new file mode 100644 index 0000000..53e8765 --- /dev/null +++ b/src/carrito/dto/input/mover-modulo.dto.ts @@ -0,0 +1,9 @@ +import { IsInt } from 'class-validator'; + +export class MoverModuloCarritoDto { + @IsInt() + id_carrito: number; + + @IsInt() + id_modulo: number; +} -- 2.43.0