import * as moment from 'moment'; import { ConflictException, Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { FindOptionsWhere, LessThanOrEqual, Like, Repository } from 'typeorm'; import { Multa } from './entity/multa.entity'; import { FullInformacionMultaView } from './entity/views/full-informacion-multa.view'; import { InformacionMultaView } from './entity/views/informacion-multa.view'; import { Modulo } from '../modulo/entity/modulo.entity'; import { Operador } from '../operador/entity/operador.entity'; import { Prestamo } from '../prestamo/entity/prestamo.entity'; import { Usuario } from '../usuario/entity/usuario.entity'; 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, retraso?: number, id_institucion_infraccion?: number, ) { const institucionInfraccion = id_institucion_infraccion ? await this.institucionInfraccionService.findById( id_institucion_infraccion, ) : // Asigno institucionInfraccion "Sin infracción" por default await this.institucionInfraccionService.findSinInfraccion( operadorMulta.institucion, ); // Creo registro de multa const nuevaMulta = this.repository.create({ descripcion, fecha_inicio: moment().toDate(), operadorMulta: id_institucion_infraccion ? operadorMulta : this.operadorService.sistema(), prestamo, institucionInfraccion, }); const existeMulta = await this.findByPrestamo(prestamo).catch( (err) => true, ); const fecha_fin = moment(); // Si ya tiene multa es que hubo un error en otra ocasión pero se creo la multa // correctamente esa vez if (existeMulta) return; this.validacionMultaCancelacion(prestamo); // Si no se mando un id_institucion_infraccion ni retraso saco error if (!id_institucion_infraccion && !retraso) throw new ConflictException( 'No se mandó ningún motivo para multar a este alumno.', ); // Si hay retraso lo agrego a la multa if (retraso) { nuevaMulta.retraso = true; fecha_fin.add(retraso * modulo.institucion.dias_multa_retraso, 'd'); } fecha_fin.add(institucionInfraccion.dias_multa, 'd'); nuevaMulta.fecha_fin = fecha_fin.toDate(); // Guardo la información return this.repository.save(nuevaMulta).then((_) => // Actualizo multas del usuario this.institucionUsuarioService.updateMulta( operadorMulta.institucion.id_institucion, prestamo.usuario.id_usuario, true, ), ); } async multaExtemporanea( operador: Operador, id_prestamo: number, descripcion: string, id_institucion_infraccion: number, ) { const prestamo = typeof id_prestamo === 'number' ? await this.prestamoService.findById(id_prestamo) : id_prestamo; const institucionInfraccion = await this.institucionInfraccionService.findById( id_institucion_infraccion, ); const fecha_fin = moment(); // Validamos que este prestamo 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 esta institución.', ); this.validacionMultaCancelacion(prestamo); fecha_fin.add(institucionInfraccion.dias_multa, 'd'); // Buscamos una multa con este préstamo return this.findByPrestamo(prestamo) .then((_) => // Creamos y guardamos registro this.repository.save( this.repository.create({ descripcion, fecha_fin: fecha_fin.toDate(), fecha_inicio: moment().toDate(), institucionInfraccion, operadorMulta: operador, prestamo, }), ), ) .then((_) => // Actualizo multas del usuario this.institucionUsuarioService.updateMulta( operador.institucion.id_institucion, prestamo.usuario.id_usuario, true, ), ); } findAllActivasExpiradas() { 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, usuario: { id_usuario: infoMultas[i].id_usuario }, }, }), ); return multas; }); } findAll( operador: Operador, filtros: { pagina: string; nombre?: string; usuario?: string; }, ) { const busqueda: FindOptionsWhere = {}; if (filtros.nombre) busqueda.nombre = Like(`%${filtros.nombre}%`); if (filtros.usuario) busqueda.usuario = Like(`%${filtros.usuario}%`); if (operador) busqueda.id_institucion = operador.institucion.id_institucion; return this.fullInformacionMultaView .findAndCount({ where: busqueda, order: { institucion: 'ASC', activo: 'DESC', fecha_fin: 'ASC', id_usuario: 'ASC', }, skip: (parseInt(filtros.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]]; }); } findAllByIdEquipo(operador: Operador, id_equipo: number, pagina: 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) { 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) { return this.repository .findOne({ select: ['id_multa'], where: { prestamo } }) .then((existeMulta) => { if (existeMulta) throw new ConflictException( 'Ya existe una multa asignada a este préstamo.', ); return existeMulta; }); } findMultasActivasByUsuario(usuario: Usuario) { return this.repository .createQueryBuilder('mu') .innerJoin('mu.prestamo', 'p') .innerJoin('p.usuario', 'u', 'u.id_usuario = :id_usuario', { id_usuario: usuario.id_usuario, }) .innerJoinAndSelect('mu.institucionInfraccion', 'ii') .innerJoinAndSelect('ii.institucion', 'i') .andWhere('mu.activo = 1') .getMany(); } private fullViewToMulta(infoMulta: FullInformacionMultaView) { 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, usuario: { id_usuario: infoMulta.id_usuario, usuario: infoMulta.usuario, nombre: infoMulta.nombre, }, }, }); } save(multa: Multa) { return this.repository.save(multa); } private validacionMultaCancelacion(prestamo: Prestamo) { // Validamos que este prestamo no haya sido cancelado poer 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.', ); } async quitarMulta(admin: Operador, id_institucion_usuario: number) { const institucionUsuario = await this.institucionUsuarioService.findById( id_institucion_usuario, ); const multa = await this.repository .createQueryBuilder('mu') .innerJoinAndSelect('mu.prestamo', 'p') .innerJoinAndSelect('p.usuario', 'u') .innerJoin( 'u.instituciones', 'is', 'is.id_institucion_usuario = :id_institucion_usuario', { id_institucion_usuario: institucionUsuario.id_institucion_usuario }, ) .where('mu.activo = 1') .getOne(); await this.institucionUsuarioService.updateMulta( admin.institucion.id_institucion, institucionUsuario.usuario.id_usuario, false, ); if (!multa) throw new ConflictException( 'Este usuario no tiene una multa activa en esta institución.', ); multa.activo = false; return this.repository .save(multa) .then((_) => ({ message: 'Se guardaron los cambios correctamente.' })); } }