import * as moment from 'moment'; import { ConflictException, Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { FindManyOptions, FindOptionsWhere, LessThanOrEqual, Like, Repository, } from 'typeorm'; import { Modulo } from '../modulo/entity/modulo.entity'; import { Multa } from './entity/multa.entity'; import { Operador } from '../operador/entity/operador.entity'; import { Prestamo } from '../prestamo/entity/prestamo.entity'; import { Usuario } from '../usuario/entity/usuario.entity'; import { FullInformacionMultaView } from './entity/views/full-informacion-multa.view'; import { InformacionMultaView } from './entity/views/informacion-multa.view'; import { EquipoService } from '../equipo/equipo.service'; import { InstitucionInfraccionService } from '../institucion-infraccion/institucion-infraccion.service'; import { InstitucionUsuarioService } from '../institucion-usuario/institucion-usuario.service'; import { OperadorService } from '../operador/operador.service'; import { PrestamoService } from '../prestamo/prestamo.service'; import { UsuarioService } from '../usuario/usuario.service'; @Injectable() export class MultaService { constructor( @InjectRepository(Multa) private repository: Repository, @InjectRepository(FullInformacionMultaView) private fullInformacionMultaView: Repository, @InjectRepository(InformacionMultaView) private informacionMultaView: Repository, private equipoService: EquipoService, private institucionInfraccionService: InstitucionInfraccionService, private institucionUsuarioService: InstitucionUsuarioService, private operadorService: OperadorService, private prestamoService: PrestamoService, private usuarioService: UsuarioService, ) {} async create( operadorMulta: Operador, modulo: Modulo, prestamo: Prestamo, descripcion: string, semanasCastigo?: number, id_institucion_infraccion?: number, ): Promise<{ message: string }> { // Buscamos la infracción, si es que se mandó una, de lo contrario se asigna "Sin infracción" por default const institucionInfraccion = id_institucion_infraccion ? await this.institucionInfraccionService.findById( id_institucion_infraccion, ) : await this.institucionInfraccionService.findSinInfraccion( operadorMulta.institucion, ); const existeMulta = await this.findByPrestamo(prestamo); const fecha_fin = moment(); // Si ya existe una multa asignada a este préstamo significa que hubo un problema pero si se multo al usuario. Cortamos la función if (existeMulta) return; this.validacionMultaCancelacion(prestamo); // Si hay semanasCastigo agregamos el tiempo de multa correspondiente a la institución if (semanasCastigo) fecha_fin.add( semanasCastigo * modulo.institucion.dias_multa_retraso, 'd', ); // Si la institucionInfraccion no es "Sin infracción" if (institucionInfraccion.infraccion.id_infraccion != 1) // Agregamos el tiempo de multa correspondiente de la infracción enviada fecha_fin.add(institucionInfraccion.dias_multa, 'd'); // Creamos y guardamos un registro return this.repository .save( this.repository.create({ descripcion, fecha_fin: fecha_fin.toDate(), fecha_inicio: moment().toDate(), retraso: semanasCastigo ? true : false, institucionInfraccion, operadorMulta: id_institucion_infraccion ? operadorMulta : this.operadorService.sistema(), prestamo, }), ) .then((_) => // Multamos al usuario en todas las carreras a las que pertenece en esa institución this.institucionUsuarioService.updateMulta( operadorMulta.institucion, prestamo.institucionUsuario.usuario, true, ), ); } findAll( operador: Operador, filtros: { nombre?: string; pagina?: string; usuario?: string; }, ): Promise { const busqueda: FindOptionsWhere = { id_institucion: operador.institucion.id_institucion, }; const options: FindManyOptions = { order: { institucion: 'ASC', activo: 'DESC', fecha_fin: 'ASC', usuario: 'ASC', }, }; if (filtros.nombre) busqueda.nombre = Like(`%${filtros.nombre}%`); if (filtros.usuario) busqueda.usuario = Like(`%${filtros.usuario}%`); options.where = busqueda; if (filtros.pagina) { options.skip = (parseInt(filtros.pagina) - 1) * 25; options.take = 25; return this.fullInformacionMultaView .findAndCount(options) .then((infoMultas) => { const multas: Multa[] = []; for (let i = 0; i < infoMultas[0].length; i++) multas.push( this.repository.create(this.fullViewToMulta(infoMultas[0][i])), ); return [multas, infoMultas[1]]; }); } else return this.fullInformacionMultaView.find(options); } findAllActivasExpiradas(): Promise { return this.informacionMultaView .find({ where: { activo: 1, fecha_fin: LessThanOrEqual(moment().toDate()) }, }) .then((infoMultas) => { const multas: Multa[] = []; for (let i = 0; i < infoMultas.length; i++) multas.push( this.repository.create({ id_multa: infoMultas[i].id_multa, activo: infoMultas[i].activo === 1, fecha_fin: infoMultas[i].fecha_fin, retraso: infoMultas[i].retraso === 1, institucionInfraccion: { id_institucion_infraccion: infoMultas[i].id_institucion_infraccion, infraccion: { id_infraccion: infoMultas[i].id_infraccion }, institucion: { id_institucion: infoMultas[i].id_institucion }, }, operadorMulta: { id_operador: infoMultas[i].id_operador }, prestamo: { id_prestamo: infoMultas[i].id_prestamo, institucionUsuario: { usuario: { id_usuario: infoMultas[i].id_usuario }, }, }, }), ); return multas; }); } findAllByIdEquipo( operador: Operador, id_equipo: number, pagina: number, ): Promise<[Multa[], number]> { return this.equipoService.findById(id_equipo).then((equipo) => this.fullInformacionMultaView .findAndCount({ where: { id_equipo: equipo.id_equipo, id_institucion: operador.institucion.id_institucion, }, skip: (pagina - 1) * 25, take: 25, }) .then((infoMultas) => { const multas: Multa[] = []; for (let i = 0; i < infoMultas[0].length; i++) multas.push( this.repository.create(this.fullViewToMulta(infoMultas[0][i])), ); return [multas, infoMultas[1]]; }), ); } findAllByIdUsuario( operador: Operador, id_usuario: number, pagina: number, ): Promise<[Multa[], number]> { return this.usuarioService.findById(id_usuario).then((usuario) => this.fullInformacionMultaView .findAndCount({ where: { id_usuario: usuario.id_usuario, id_institucion: operador.institucion.id_institucion, }, skip: (pagina - 1) * 25, take: 25, }) .then((infoMultas) => { const multas: Multa[] = []; for (let i = 0; i < infoMultas[0].length; i++) multas.push( this.repository.create(this.fullViewToMulta(infoMultas[0][i])), ); return [multas, infoMultas[1]]; }), ); } findByPrestamo(prestamo: Prestamo): Promise { return this.repository.findOne({ select: ['id_multa'], where: { prestamo }, }); } findMultasActivasByUsuario(usuario: Usuario): Promise { return this.repository.find({ join: { alias: 'mu', innerJoin: { p: 'mu.prestamo', iu: 'p.institucionUsuario', u: 'iu.usuario', }, innerJoinAndSelect: { ii: 'mu.institucionInfraccion', i: 'ii.institucion', }, }, where: { activo: true, prestamo: { institucionUsuario: { usuario } } }, }); } private fullViewToMulta(infoMulta: FullInformacionMultaView): Multa { return this.repository.create({ id_multa: infoMulta.id_multa, activo: infoMulta.activo === 1, descripcion: infoMulta.descripcion, fecha_fin: infoMulta.fecha_fin, fecha_inicio: infoMulta.fecha_inicio, retraso: infoMulta.retraso === 1, institucionInfraccion: { id_institucion_infraccion: infoMulta.id_institucion_infraccion, infraccion: { id_infraccion: infoMulta.id_infraccion, infraccion: infoMulta.infraccion, }, }, operadorMulta: { id_operador: infoMulta.id_operador, operador: infoMulta.operador, institucion: { id_institucion: infoMulta.id_institucion, institucion: infoMulta.institucion, }, }, prestamo: { id_prestamo: infoMulta.id_prestamo, institucionUsuario: { usuario: { id_usuario: infoMulta.id_usuario, usuario: infoMulta.usuario, nombre: infoMulta.nombre, }, }, }, }); } async multaExtemporanea( operador: Operador, id_prestamo: number, descripcion: string, id_institucion_infraccion: number, ): Promise<{ message: string }> { const prestamo = await this.prestamoService.findById(id_prestamo); const institucionInfraccion = await this.institucionInfraccionService.findById( id_institucion_infraccion, ); const fecha_fin = moment(); // Validamos que este préstamo le pertenezca al operador if ( operador.institucion.id_institucion != prestamo.equipo.carrito.modulo.institucion.id_institucion ) throw new ConflictException( 'Este préstamo no pertenece a tu institución.', ); // Validamos que la infracción enviada no sea "Sin infracción" if (institucionInfraccion.infraccion.id_infraccion === 1) throw new ConflictException( 'No se puede asignar esta infracción manualmente.', ); this.validacionMultaCancelacion(prestamo); // Agregamos el tiempo de multa correspondiente de la infracción enviada fecha_fin.add(institucionInfraccion.dias_multa, 'd'); return this.findByPrestamo(prestamo) .then((existeMulta) => { // Validamos que no exista una multa con este préstamo if (existeMulta) throw new ConflictException( 'Ya existe una multa asignada a este préstamo.', ); // Creamos y guardamos un registro return this.repository.save( this.repository.create({ descripcion, fecha_fin: fecha_fin.toDate(), fecha_inicio: moment().toDate(), institucionInfraccion, operadorMulta: operador, prestamo, }), ); }) .then((_) => // Multamos al usuario en todas las carreras a las que pertenece en esa institución this.institucionUsuarioService.updateMulta( operador.institucion, prestamo.institucionUsuario.usuario, true, ), ); } async quitarMulta( admin: Operador, id_institucion_usuario: number, ): Promise<{ message: string }> { const institucionUsuario = await this.institucionUsuarioService.findById( id_institucion_usuario, ); const multa = await this.repository .createQueryBuilder('mu') .innerJoinAndSelect('mu.prestamo', 'p') .innerJoin( 'p.institucionUsuario', 'iu', 'iu.id_institucion_usuario = :id_institucion_usuario', { id_institucion_usuario: institucionUsuario.id_institucion_usuario }, ) .where('mu.activo = 1') .getOne(); // Validamos que este institucionUsuario le pertenezca al admin if ( admin.institucion.id_institucion != institucionUsuario.institucionCarrera.institucion.id_institucion ) throw new ConflictException( 'No puedes modificar la información este usuario porque no pertenece a tu institución.', ); // Quitamos la multa a todas las carreras del usuario en la institución del admin return this.institucionUsuarioService .updateMulta(admin.institucion, institucionUsuario.usuario, false) .then(async (_) => { if (multa) { multa.activo = false; await this.repository.save(multa); } return { message: 'Se guardaron los cambios correctamente.' }; }); } save(multa: Multa): Promise { return this.repository.save(multa); } private validacionMultaCancelacion(prestamo: Prestamo): void { // Validamos que este présstamo no haya sido cancelado por el usuario u operador if (prestamo.cancelado_operador || prestamo.cancelado_usuario) throw new ConflictException( 'No se puede multar a un usuario con un préstamo que fue cancelado.', ); } }