105 Commits

Author SHA1 Message Date
6bc32da996 Merge pull request 'dev' (#90) from dev into main
Reviewed-on: #90
2025-08-05 16:46:14 -03:00
0b6bf0ba40 fix: repetida timestamp para el ingreso de contrato 2025-08-05 16:42:25 -03:00
83dffcad72 modificados los lugares donde se muestra opcion venta 2025-08-01 02:14:54 -03:00
a84367cd60 correjido un typo 2025-07-29 02:04:30 -03:00
afe39d1c80 cambie un conteiner fluid por container 2025-07-29 02:03:36 -03:00
f08743ac55 Merge pull request 'v2 ing soft' (#89) from dev into main
Reviewed-on: #89
2025-07-28 20:20:56 -03:00
a30e42d06f cambiado canons a canones 2025-07-28 20:00:10 -03:00
76582013c4 arreglado autotab en el pin input 2025-07-27 19:48:30 -03:00
7bb6c6abc2 carga de contratos por admin funcional 2025-07-27 18:14:36 -03:00
c180c8ef80 fix: esto arregla todos los warnings de svelte 2025-07-27 13:53:57 -03:00
a5f78673d4 primera parte de añadir lo de contratos 2025-07-27 04:00:39 -03:00
5d944b0ee4 añadido front para que el admin suba el contrato 2025-07-26 02:42:30 -03:00
98414a5ec7 correjido posible desreferenciacion nula 2025-07-25 23:29:48 -03:00
b7b7b80072 añadida informacion a la pantalla de añadirgarantes 2025-07-25 03:13:04 -03:00
ff63497b61 solucionado tema de que no salian datos en meses antiguos 2025-07-24 20:40:19 -03:00
caa654a078 comentado writeline 2025-07-23 19:37:24 -03:00
fef97e1d05 Sacada tilde del sí porque daba problemas con libreoffice 2025-07-23 02:15:20 -03:00
5444b1dda3 correjido mensaje del log 2025-07-23 02:14:28 -03:00
4e5c209584 añadido logging de cerrar sesion + invalidacion de token 2025-07-23 02:13:14 -03:00
4ab98a0a2e eliminado el SystemBytes 2025-07-23 01:09:25 -03:00
2435ae803e fix: correjidos mensajes de error 2025-07-20 00:34:42 -03:00
a7355ea540 fix: contador de meses 2025-07-20 00:34:17 -03:00
af3933480d fix: se logeaban usuario desactivados 2025-07-20 00:33:22 -03:00
eceefba391 correjidos componentesw para usar el enter como submit 2025-07-17 00:16:28 -03:00
e7b2115d6f eliminado codigo test 2025-07-17 00:16:13 -03:00
84a99a1590 Bueno elimine la necesidad de usar un storeprocedure 2025-07-17 00:15:24 -03:00
98dbc8c865 añadido nuevo crear grupo 2025-06-21 01:33:23 -03:00
f6dc641508 le doy permiso a ver grupos al p 19 2025-06-21 01:32:43 -03:00
e5d17c3a38 añadido tercera estadistica 2025-05-31 01:06:59 -03:00
616c9503bc añadido skeleton del codigo para pagos/ingresos 2025-05-30 00:08:46 -03:00
da7f0cf167 corregido limite de chars 2025-05-29 21:34:42 -03:00
e0a636ac85 arreglado lo de que se parseaban grupos extra 2025-05-29 21:34:19 -03:00
374540a424 qa 2025-05-24 01:11:17 -03:00
e6937c65ca falta testear nomas 2025-05-22 19:38:35 -03:00
033acc1016 eliminados bastantes checkgrupo 2025-05-22 17:35:24 -03:00
3a477e8dc5 refactor 2025-05-22 16:58:26 -03:00
76f5c3a9e9 eliminadas llamadas a checkgrupos 2025-05-22 15:49:00 -03:00
779ab9b982 eliiminado codigo muerto 2025-05-22 15:41:46 -03:00
6f3d985960 1. Update first controller:
- Add new method `CaminarContraAdmin` for changing contrasection
- Include HTTP PATCH handler
- Use camelCase for class names
2. Update second controller:
- Update method name from `caminarContraseña` to `caminarContraAdmin`
- Fix message "contraseña" to be more precise ("contraseña correcta")
3. Update modal component:
- Change `handleSubmit` event from `submit` (JS) to `POST` (Svelte)
- Ensure form validation in JavaScript
4. Update page admin/users to use CardLink for links
2025-05-22 15:23:49 -03:00
b4a1d5c0c5 avanzando 2025-05-22 00:59:14 -03:00
c51382b565 fix: no se actualizaba la lista de permisos 2025-05-21 00:37:25 -03:00
faa3f386a9 Update UsuarioController.cs 2025-05-21 00:26:54 -03:00
deb4b90c18 refactor ahora es recuperar cuenta 2025-05-21 00:01:02 -03:00
f0da8143eb Update LoginPanel.svelte 2025-05-20 23:19:34 -03:00
c3aa0db42d añadido coso 2025-05-20 22:06:09 -03:00
e3fa663ffa me traigo todos los cambios del recuperar cuenta y set email respaldo 2025-05-20 00:36:12 -03:00
02add8907e Esta todo a medio hacerse pero quiero versionar esto ya para no perder
nada
2025-05-08 01:00:34 -03:00
6f6d8a4e8c refactor del Fchart 2025-05-07 15:30:31 -03:00
1a5006e832 Añade la capacidad de que setes un mail de recuperacion 2025-05-07 15:30:05 -03:00
61eacc5533 Update bun.lockb 2025-05-07 15:29:11 -03:00
c825d737fc Fix database connection handling in AlquilaFacilContext
Improved error handling when loading database connection,
replaced custom context class with Dictionary<string,string>,
and added null checks for safer configuration.
2025-05-05 22:59:34 -03:00
f7d52041ba Format code with proper spacing and brackets 2025-05-05 22:45:45 -03:00
fddafd5234 Add recovery email field to Cliente entity 2025-05-05 21:36:36 -03:00
ca44b3cf84 ahora solo ve los grupos activos tanto en la resolucion de permisos como
en el front
2025-05-05 18:48:05 -03:00
139b855c2c feat: login usuario 2025-05-05 17:48:05 -03:00
4f44581503 Add user profile button to navigation bar 2025-05-05 13:25:01 -03:00
402c98eb6b ya estaba implementado 2025-05-05 12:45:01 -03:00
11f4d38f8b Remplazados algunos checkgrupos faltan 8 2025-04-28 21:08:18 -03:00
6194e5b4b9 Refactor code formatting 2025-04-28 20:41:39 -03:00
b6d78747c8 Replace RepositorioGrupos with RepositorioPermisos 2025-04-28 20:24:22 -03:00
5df52d8426 ahi le cambie los checkgrupo por checkpermiso 2025-04-28 18:32:49 -03:00
2304e7b54b cambiado que use permisos 2025-04-28 17:41:43 -03:00
2dd72bf070 Update App.svelte 2025-04-28 17:41:26 -03:00
6926221353 eliminado checkgrupos en notificaciones controller 2025-04-28 17:27:02 -03:00
0961618e40 lol ahora si usa composite bien 2025-04-28 17:15:12 -03:00
99591b8cc2 bueno ya esta implemntado todo lo de permisos de forma recursiva 2025-04-25 19:46:18 -03:00
8e385a4710 eliminado wip 2025-04-25 18:02:48 -03:00
b2f45baec7 ahora lista usando profundidad 2025-04-25 16:23:10 -03:00
190f9a8e10 bruh estaba la relacion al revez 2025-04-25 14:52:16 -03:00
25e399a5b3 fix: mejorado espacio vertical que ocupa la tabla 2025-04-25 13:47:13 -03:00
36b8f03421 eliminado un wip 2025-04-25 13:46:40 -03:00
c5a0eb70b8 duplica la funcion con gestion permisos 2025-04-25 13:36:41 -03:00
1d3784d848 creado toggle habilitar grupo y correjido un par de bugs de
modalestatico
2025-04-25 13:06:19 -03:00
fdcb74bb11 feat: crea todas las entidades para mergearlas con meld 2025-04-25 11:35:36 -03:00
df751ead57 añadido un bit de habilitado 2025-04-25 11:23:42 -03:00
eeb2ff1c65 ahora esta la gestion de permisos 2025-04-22 21:00:58 -03:00
e118a3acd2 falta poner los fetch 2025-04-21 19:37:03 -03:00
524a315dc1 refactor de admin usuarios 2025-04-21 16:33:11 -03:00
4e5e0a4f6f ahora las opciones de grupos corresponden a las que existen en vez de
ser hardcode
2025-04-21 16:32:50 -03:00
b75f672b0a arreglado bug que no salia el nombre del grupo 2025-04-21 16:23:15 -03:00
de9ff8f0b3 skeleton para pagina grupo creado por usuario 2025-04-21 16:02:05 -03:00
543bc9e5a6 Añadido soporte para crear grupos nuevos 2025-04-21 16:01:15 -03:00
ffb860688d analizado que necesito hacer de aca en adelante
- [ ] una pagina de grupo default
- [ ] los permisos resuelvan los de subgrupos
2025-04-21 01:09:53 -03:00
b98fde72ca hecha funcionalida de modificar grupos 2025-04-18 23:54:27 -03:00
701f699c55 primer inicio del modal 2025-04-17 13:45:35 -03:00
c1a27baedd avansando más 2025-04-17 13:24:07 -03:00
6fb6ade153 add concurrently 2025-04-14 17:28:28 -03:00
bb995d1587 fix: el checkbox no guardaba estado 2025-04-07 15:30:10 -03:00
483a2b5409 fix: ahora no hace autoscroll hacia arriba 2025-04-07 14:55:37 -03:00
eadeeb2b08 potencial codigo duplicado 2025-04-07 14:44:51 -03:00
2ad084cf19 añadido boton para cerrar sesion 2025-04-07 14:27:01 -03:00
0036f48d19 primeros pasos en añadir las cosas que pide el profe 2025-03-31 23:27:25 -03:00
790cc31f93 refactor porque era ilejible 2025-03-31 19:38:42 -03:00
25f77f6f48 primera edicion de un archivo para cambiar grupos a permisos 2025-03-14 02:43:41 -03:00
b3ffa657f5 añadido endpoint para crear permisos 2025-03-14 02:33:59 -03:00
878583664e añadido que logee la ip y los logins 2025-03-05 20:28:03 -03:00
24c6e43f2d añadido cors para ipv6 2025-03-05 20:27:44 -03:00
b898c6911c Merge pull request 'main' (#70) from main into dev
Reviewed-on: #70
2025-03-05 19:16:26 -03:00
befe0f2848 Merge pull request 'deploy-local-de-la-v1-del-sistema' (#68) from deploy-local-de-la-v1-del-sistema into main
Reviewed-on: #68
2025-03-05 19:15:45 -03:00
8f494b383a arreglado colapsed 2025-03-05 19:13:23 -03:00
09f41c00cd faltaba query al servidor para tener los garantes 2025-03-05 19:13:13 -03:00
dda1032685 cambios para tener composite 2025-03-05 19:12:02 -03:00
21724a372f añado bootstrap como dependencia para que carge sin conexion 2025-03-05 19:08:11 -03:00
6c58c6da78 cambios en el acceso no me preocupo porque queda tocar esto 2025-03-05 19:07:20 -03:00
22d68d4ce9 mal uso de la palabra acá
Signed-off-by: fede <federico.nicolas.polidoro@gmail.com>
2025-02-17 17:11:18 -03:00
91 changed files with 7008 additions and 2126 deletions

View File

@@ -1,74 +1,94 @@
using Entidades.Dto;
namespace AlquilaFacil.Builder;
public class ContratoPropiedadDtoBuilder : Builder<ContratoPropiedadDto>{
public ContratoPropiedadDtoBuilder SetId(long id ){
public class ContratoPropiedadDtoBuilder : Builder<ContratoPropiedadDto>
{
public ContratoPropiedadDtoBuilder SetId(long id)
{
data.id = id;
return this;
}
public ContratoPropiedadDtoBuilder SetUbicacion(string ub){
public ContratoPropiedadDtoBuilder SetUbicacion(string ub)
{
data.Ubicacion = ub;
return this;
}
public ContratoPropiedadDtoBuilder SetTipo(string tipo){
public ContratoPropiedadDtoBuilder SetTipo(string tipo)
{
data.TipoPropiedad = tipo;
return this;
}
public ContratoPropiedadDtoBuilder SetFechaInicio(DateTime fec) {
public ContratoPropiedadDtoBuilder SetFechaInicio(DateTime fec)
{
data.Fechainicio = fec;
return this;
}
public ContratoPropiedadDtoBuilder SetInquilino(string inquilino){
public ContratoPropiedadDtoBuilder SetInquilino(string inquilino)
{
data.Inquilino = inquilino;
return this;
}
public ContratoPropiedadDtoBuilder SetPropietario(string propietario){
public ContratoPropiedadDtoBuilder SetPropietario(string propietario)
{
data.Propietario = propietario;
return this;
}
public ContratoPropiedadDtoBuilder SetEstado(ulong habilitado, ulong cancelado) {
public ContratoPropiedadDtoBuilder SetEstado(ulong habilitado, ulong cancelado)
{
bool Habilitado = habilitado == 0 ? false : true;
bool Cancelado = cancelado == 0 ? false : true;
if (Habilitado == true && Cancelado == false){
if (Habilitado == true && Cancelado == false)
{
data.Estado = "Alquiler Iniciado";
} else if (Cancelado == true && Habilitado == false) {
}
else if (Cancelado == true && Habilitado == false)
{
data.Estado = "Nunca Empezo Esta Cancelado";
} else if (Habilitado == false && Cancelado ==false){
}
else if (Habilitado == false && Cancelado == false)
{
data.Estado = "Esta en Proceso";
} else if (Habilitado == true && Cancelado == true){
}
else if (Habilitado == true && Cancelado == true)
{
data.Estado = "Terminado";
}
return this;
}
public ContratoPropiedadDtoBuilder SetHabitaciones(int habitaciones){
public ContratoPropiedadDtoBuilder SetHabitaciones(int habitaciones)
{
data.Habitaciones = habitaciones;
return this;
}
public ContratoPropiedadDtoBuilder SetPiso(int piso){
public ContratoPropiedadDtoBuilder SetPiso(int piso)
{
data.Piso = piso;
return this;
}
public ContratoPropiedadDtoBuilder SetLetra(string letra){
public ContratoPropiedadDtoBuilder SetLetra(string letra)
{
data.Letra = letra;
return this;
}
public ContratoPropiedadDtoBuilder SetMesesAumento(int mesesAumento){
public ContratoPropiedadDtoBuilder SetMesesAumento(int mesesAumento)
{
data.MesesAumento = mesesAumento;
return this;
}
public ContratoPropiedadDtoBuilder SetMesesDuracion(int mesesDurationContrato) {
public ContratoPropiedadDtoBuilder SetMesesDuracion(int mesesDurationContrato)
{
data.MesesDuracion = mesesDurationContrato;
return this;
}

View File

@@ -0,0 +1,50 @@
using Entidades.Dto;
namespace AlquilaFacil.Builder;
public class GrupoDtoBuilder : Builder<GrupoDto>
{
public GrupoDtoBuilder ConNombre(string nombre)
{
data.Nombre = nombre;
return this;
}
public GrupoDtoBuilder ConHabilitado(bool habilitado)
{
data.Habilitado = habilitado;
return this;
}
public GrupoDtoBuilder ConIdGrupo(int id)
{
data.idgrupo = id;
return this;
}
public GrupoDtoBuilder ConGruposIncluidos(HashSet<string> grupos)
{
data.GruposIncluidos = grupos;
return this;
}
public GrupoDtoBuilder ConPermisos(List<PermisoDto> permisos)
{
data.Permisos = permisos;
return this;
}
}
public class PermisoDtoBuilder : Builder<PermisoDto>
{
public PermisoDtoBuilder ConId(int id)
{
data.Id = id;
return this;
}
public PermisoDtoBuilder ConDescripcion(string descripcion)
{
data.Descripcion = descripcion;
return this;
}
}

View File

@@ -0,0 +1,41 @@
using Entidades.Dto;
namespace AlquilaFacil.Builder;
public class UsuarioDtoBuilder : Builder<UsuarioDto>
{
public UsuarioDtoBuilder SetDni(long dni)
{
data.Dni = dni;
return this;
}
public UsuarioDtoBuilder SetNombre(string nombre)
{
data.Nombre = nombre;
return this;
}
public UsuarioDtoBuilder SetApellido(string apellido)
{
data.Apellido = apellido;
return this;
}
public UsuarioDtoBuilder SetDomicilio(string domicilio)
{
data.Domicilio = domicilio;
return this;
}
public UsuarioDtoBuilder SetCelular(string celular)
{
data.Celular = celular;
return this;
}
public UsuarioDtoBuilder SetEmail(string email)
{
data.Email = email;
return this;
}
public UsuarioDtoBuilder SetEmailRecuperacion(string? email)
{
data.EmailRecuperacion = email ?? "";
return this;
}
}

View File

@@ -0,0 +1,15 @@
using Entidades;
public class PermisoBuilder : Builder<Permiso>
{
public PermisoBuilder SetDescripcion(string desc)
{
data.Descripcion = desc;
return this;
}
public PermisoBuilder SetID(int id)
{
data.Id = id;
return this;
}
}

View File

@@ -1,17 +1,17 @@
using System.ComponentModel.DataAnnotations;
using Entidades.Dto;
using Microsoft.AspNetCore.Mvc;
using Modelo;
using System.Text.Json;
using Entidades;
namespace AlquilaFacil.Controllers;
[ApiController]
public class AccionesController: ControllerBase {
public class AccionesController : ControllerBase
{
[HttpGet("api/acciones")]
public IActionResult ListarAccionesPorUsuario([FromHeader(Name ="Email")] string Email, [FromHeader(Name = "Auth")] string Auth) {
public IActionResult ListarAccionesPorUsuario([FromHeader(Name = "Email")] string Email, [FromHeader(Name = "Auth")] string Auth)
{
if (Email == "" || Email == null) return BadRequest();
if (Auth == "") return Unauthorized(new { esValido = false });
@@ -24,9 +24,11 @@ public class AccionesController: ControllerBase {
return Ok(Permisos);
}
[HttpPost("api/acciones/grupo")]
public IActionResult ListarAccionesPorGrupo([FromHeader(Name = "Auth")] string Auth,
[FromBody] AccionesPorGrupoDto req) {
[FromBody] AccionesPorGrupoDto req)
{
if (string.IsNullOrEmpty(Auth)) return BadRequest();
bool esValido = RepositorioUsuarios.Singleton.CheckToken(req.Email, Auth);
if (esValido == false) return BadRequest(esValido);
@@ -37,4 +39,35 @@ public class AccionesController: ControllerBase {
var permisos = RepositorioGrupos.Singleton.ListarPermisosDeGrupo(req.Grupo);
return Ok(permisos);
}
/*
[HttpPost("api/acciones/crear")] //creo que es codido duplicado
public IActionResult CrearAcciones([FromHeader(Name = "Auth")] string Auth,
[FromBody] CrearAccionesDto req)
{
if (string.IsNullOrEmpty(Auth)) return BadRequest();
Cliente? cli = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);
if (cli == null) return Unauthorized();
var ret = RepositorioPermisos.Singleton.CheckPermisos(Auth, 1); //wip lo voy a usar para crear el permiso que va
if (ret == false) return Unauthorized();
if (string.IsNullOrWhiteSpace(req.Descripcion))
{
return BadRequest(new { message = "La descripción no puede estar vacía" });
}
if (req.Descripcion.Length > 25)
{
return BadRequest(new { message = "La descripción no puede ser mayor a 25 caracteres" });
}
var per = new Permiso
{
Descripcion = req.Descripcion,
};
var ret2 = RepositorioPermisos.Singleton.CrearPermiso(per);
return ret2 ? Ok(new { message = "se creo correctamente" }) : BadRequest(new { message = "No se pudo crear el permiso" });
}
*/
}

View File

@@ -47,7 +47,7 @@ public class AdminController: ControllerBase
[HttpGet("api/contratos/controlPagos/propiedad")]
public IActionResult obtenerPropiedad([FromHeader(Name = "Auth")] string Auth, int id = 0) {
if (String.IsNullOrEmpty(Auth)) return Unauthorized();
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Admin");
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 14);
if (validacion1 == false) return Unauthorized();
if (id <= 0) return BadRequest(new { message = "No hay propiedades con id igual o menor a 0"});
@@ -89,7 +89,7 @@ public class AdminController: ControllerBase
[HttpGet("/api/admin/contrato/verDocumento")]
public IActionResult verDocumento([FromHeader(Name = "Auth")] string Auth, int idcontrato = 0){
if (String.IsNullOrWhiteSpace(Auth)) return BadRequest("");
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Admin");
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 14);
if (validacion1 == false) return Unauthorized();
if (idcontrato <= 0) return BadRequest(new {message = "La id no puede ser igual o menor a 0"});
@@ -123,7 +123,7 @@ public class AdminController: ControllerBase
[HttpGet("api/admin/contrato/canons")]
public IActionResult ObtenerCanones([FromHeader(Name="Auth")]string Auth, int id = 0){
if (String.IsNullOrEmpty(Auth)) return Unauthorized();
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Admin");
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 14);
if (validacion1 == false) return Unauthorized();
var cont = RepositorioContratos.Singleton.ObtenerContratoPorId(id);
@@ -161,7 +161,7 @@ public class AdminController: ControllerBase
[HttpPost("api/admin/contrato/marcarPago")]
public IActionResult realizarPago([FromHeader(Name="Auth")]string Auth, MarcarPagoDto dto) {
if (String.IsNullOrEmpty(Auth)) return Unauthorized();
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Admin");
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 14);
if (validacion1 == false) return Unauthorized();
if (dto.Idcontrato<=0) return BadRequest(new { message = "No puede existir un contrato con id 0 o menor"});
@@ -188,7 +188,7 @@ public class AdminController: ControllerBase
[HttpPost("api/admin/notificarInquilino")]
public IActionResult NotificarInquilino([FromHeader(Name ="Auth")]string Auth, NotificarAdmin data){
if (String.IsNullOrEmpty(Auth)) return Unauthorized();
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Admin");
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 14);
if (validacion1 == false) return Unauthorized();
Cliente? cli = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);
@@ -269,6 +269,7 @@ public class AdminController: ControllerBase
BadRequest(new { message = "Fallo al guardar los datos"});
}
public record GrupoI_D(int Id, string Descripcion);
[HttpGet("api/admin/clientes/grupo")]
public IActionResult GetGruposByCliente([FromHeader(Name ="Auth")]string Auth, [FromQuery]long Dni){
if (String.IsNullOrEmpty(Auth)) return Unauthorized();
@@ -277,9 +278,10 @@ public class AdminController: ControllerBase
if (Dni <= 0) return BadRequest(new {message = "No puede tener un dni con numero negativo o cero"});
IEnumerable<GrupoAdmin> list = RepositorioGrupos.Singleton.ObtenerGruposPorDni(Dni);
IEnumerable<GrupoI_D> list = RepositorioGrupos.Singleton.ObtenerGruposPorDni(Dni).Select(x=> new GrupoI_D(x.Id,x.Nombre));
return Ok(list);
}
[HttpPatch("api/admin/cliente/addGrupo")]
public IActionResult AddGrupoACliente([FromHeader(Name = "Auth")]string Auth, [FromBody]EmailGrupo data){
if (String.IsNullOrEmpty(Auth)) return Unauthorized();
@@ -362,7 +364,9 @@ public class AdminController: ControllerBase
}
// lo da de baja si no tiene el grupo propietario y no tiene alquileres pendientes
var ret = RepositorioUsuarios.Singleton.BajaCliente(Dni);
return Ok(ret);
return ret ?
Ok(new { message = "Cliente ha sido modificado" }) :
BadRequest(new { message = "No se pudo modificar al cliente" });
}
[HttpDelete("api/admin/propiedad")]

View File

@@ -0,0 +1,353 @@
using Microsoft.AspNetCore.Mvc;
using AlquilaFacil.Config;
using Modelo;
using Entidades.Dto;
using Entidades;
using Minio;
using Minio.DataModel;
using Minio.DataModel.Args;
using Minio.Exceptions;
using System.Text.Json;
[ApiController]
public class CargarContratoAdminController: ControllerBase{
[HttpGet("api/admin/contrato/data")]
public IActionResult GetData([FromHeader(Name ="Auth")]string Auth) {
var cli = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);
if (cli == null) return BadRequest(new { message = "No hay usuario por ese token"});
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 20);
if (validacion1 == false) return Unauthorized();
var divisas = RepositorioDivisas.Singleton.ObtenerDivisas();
var propiedades = RepositorioPropiedades.Singleton.ListarPropiedades().ToList()
.Select(x=> new {id = x.id,
ubicacion = x.Ubicacion});
var inquilinos = RepositorioInquilinos.Singleton.GetInquilinos().ToList()
.Select(x=>new {dni=x.Dni, nombre = x.Nombre});
var propietarios = RepositorioPropietario.Singleton.GetPropietarios().ToList()
.Select(x=>new {dni=x.Dni, nombre = x.Nombre});
return Ok(new {divisas,
propiedades,
inquilinos,
propietarios});
}
[HttpGet("api/admin/contrato/propieades")]
public IActionResult GetPropiedadesPorPropietario([FromHeader(Name ="Auth")]string Auth, long dnipropietario){
var cli = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);
if (cli == null) return BadRequest(new { message = "No hay usuario por ese token"});
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 20);
if (validacion1 == false) return Unauthorized();
var propiedades = RepositorioPropiedades.Singleton.ObtenerPropiedadEnAlquilerPorDni(dnipropietario);
return Ok(propiedades);
}
[HttpPost("api/admin/contrato/carga")]
public async Task<IActionResult> CargaContrato([FromHeader(Name="Auth")]string Auth) {
var cli = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);
if (cli == null) return BadRequest(new { message = "No hay usuario por ese token"});
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 20);
if (validacion1 == false) return Unauthorized();
if (!Request.HasFormContentType) {
return BadRequest(new { message = "La solicitud debe contener datos de formulario (FormData)." });
}
var formData = await Request.ReadFormAsync();
if (formData == null) {
return BadRequest(new { message = "No se pudieron leer los datos del formulario." });
}
var archivoContrato = Request.Form.Files.FirstOrDefault(x=>x.Name =="archivoContrato");
if (archivoContrato == null) return BadRequest(new { message = "Falto Subir el archivo" });
if (archivoContrato.ContentType != "application/pdf") {
return BadRequest(new { message = "El archivo debe ser un PDF." });
}
Contrato? cont; IActionResult? req;
(cont, req) = ParseContratoFromForm(formData);
if (req != null && cont == null) return req;
var ret = RepositorioContratos.Singleton.AdminCargaContrato(cont, cli.Dni);
if(ret == false) return BadRequest( new {message = "No se pudo cargar el contrato" });
var inq = RepositorioUsuarios.Singleton.ObtenerClientePorDni(cont.Dniinquilino??0);
cont = RepositorioContratos.Singleton.ObtenerContrato(inq.Email, cont.Idpropiedad ?? 0);
if (cont == null) return BadRequest(new { message = "No se pudo recuperar el contrato" });
string nuevoNombreArchivo = $"id:{cont.Id}-inq:{cont.Dniinquilino}-propi:{cont.Dnipropietario}-idprop:{cont.Idpropiedad}.pdf";
ret = await subirContrato(archivoContrato, nuevoNombreArchivo);
if (ret == false) return BadRequest(new { message = "No se pudo subir el archivo" });
ret = RepositorioContratos.Singleton.AddUrl(cont.Id, nuevoNombreArchivo);
if (ret == false) return BadRequest(new { message = "No se pudo guardar la url del contrato" });
ret = RepositorioContratos.Singleton.GenerarCanones(cont.Id, cli.Dni);
if (ret == false) return BadRequest( new { message = "Fallo al generar canones" });
var noti = new NotificacioneBuilder()
.SetDniremitente(int.Parse(cli.Dni.ToString()))
.SetIdpropiedad(cont.Idpropiedad ?? 0)
.SetDnicliente(cont.Dniinquilino ?? 0)
.SetAccion("Notificacion")
.SetMensaje($"Contrato Cargado desde Administracion")
.SetFecha(DateTime.Now)
.SetLeido(false)
.Build();
var noti2 = new NotificacioneBuilder()
.SetDniremitente(int.Parse(cli.Dni.ToString()))
.SetIdpropiedad(cont.Idpropiedad ?? 0)
.SetDnicliente(cont.Dnipropietario ?? 0)
.SetAccion("Notificacion")
.SetMensaje($"Contrato Cargado desde Administracion")
.SetFecha(DateTime.Now)
.SetLeido(false)
.Build();
ret = RepositorioNotificaciones.Singleton.AltaNotificacion(noti);
if (ret == false) return BadRequest( new { message = "No se pudo entregar la notificacion al inquilino" });
ret = RepositorioNotificaciones.Singleton.AltaNotificacion(noti2);
if (ret == false) return BadRequest( new { message = "No se pudo entregar la notificacion al propietario" });
return Ok(new { message = "Se cargo el contrato" });
}
private (Contrato? contratoDto, IActionResult? errorResult) ParseContratoFromForm(IFormCollection formData) {
if (formData == null) {
return (null, BadRequest(new { message = "No se pudieron leer los datos del formulario." }));
}
bool TryParseInt(string? value, out int result) => int.TryParse(value, out result);
bool TryParseLong(string? value, out long result) => long.TryParse(value, out result);
bool TryParseDecimal(string? value, out decimal result) => decimal.TryParse(value, out result);
bool TryParseBool(string? value, out bool result) => bool.TryParse(value, out result);
int cantGarantMin = 0;
if (formData.TryGetValue("cantgarantemin", out var cantGarantMinValues) &&
!string.IsNullOrEmpty(cantGarantMinValues.FirstOrDefault()) &&
!TryParseInt(cantGarantMinValues.FirstOrDefault(), out cantGarantMin)) {
return (null, BadRequest(new { message = "Campo 'cantgarantemin' inválido." }));
}
if (cantGarantMin<1) return (null, BadRequest(new { message = "Minimo 1 garante" }));
if (!formData.TryGetValue("dniinquilino", out var dniInqValues) ||
string.IsNullOrEmpty(dniInqValues.FirstOrDefault()) ||
!TryParseLong(dniInqValues.FirstOrDefault(), out long dniInquilino)) {
return (null, BadRequest(new { message = "Campo 'dniinquilino' inválido o faltante." }));
}
if (dniInquilino<=0) return (null, BadRequest(new { message = "No pueden haber dni 0 o menor" }));
if (!formData.TryGetValue("dnipropietario", out var dniPropValues) ||
string.IsNullOrEmpty(dniPropValues.FirstOrDefault()) ||
!TryParseLong(dniPropValues.FirstOrDefault(), out long dniPropietario)) {
return (null, BadRequest(new { message = "Campo 'dnipropietario' inválido o faltante." }));
}
if (dniPropietario<=0) return (null, BadRequest(new { message = "No pueden haber dni 0 o menor" }));
if (!formData.TryGetValue("iddivisa", out var idDivisaValues) ||
string.IsNullOrEmpty(idDivisaValues.FirstOrDefault()) ||
!TryParseInt(idDivisaValues.FirstOrDefault(), out int idDivisa)) {
return (null, BadRequest(new { message = "Campo 'iddivisa' inválido o faltante." }));
}
if (!formData.TryGetValue("idpropiedad", out var idPropValues) ||
string.IsNullOrEmpty(idPropValues.FirstOrDefault()) ||
!TryParseInt(idPropValues.FirstOrDefault(), out int idPropiedad)) {
return (null, BadRequest(new { message = "Campo 'idpropiedad' inválido o faltante." }));
}
if (!formData.TryGetValue("mesesDurationContrato", out var mesesDurValues) ||
string.IsNullOrEmpty(mesesDurValues.FirstOrDefault()) ||
!TryParseInt(mesesDurValues.FirstOrDefault(), out int mesesDuration)) {
return (null, BadRequest(new { message = "Campo 'mesesDurationContrato' inválido o faltante." }));
}
if (mesesDuration <= 0){
return (null, BadRequest(new { message = "No se cargaron los meses de duracion del contrato" }));
}
int mesesHastaAumento = 0;
if (formData.TryGetValue("mesesHastaAumento", out var mesesHastaValues) &&
!string.IsNullOrEmpty(mesesHastaValues.FirstOrDefault())) {
if (!TryParseInt(mesesHastaValues.FirstOrDefault(), out mesesHastaAumento))
{
return (null, BadRequest(new { message = "Campo 'mesesHastaAumento' inválido." }));
}
}
if (mesesHastaAumento <= 0){
return (null, BadRequest(new { message = "No se cargaron los meses hasta el aumento" }));
}
if (mesesDuration<mesesHastaAumento) return (null, BadRequest( new { message = "El contrato no puede durar menos que el tiempo hasta el aumento" } ));
if (!formData.TryGetValue("monto", out var montoValues) ||
string.IsNullOrEmpty(montoValues.FirstOrDefault()) ||
!TryParseDecimal(montoValues.FirstOrDefault(), out decimal monto)) {
return (null, BadRequest(new { message = "Campo 'monto' inválido o faltante." }));
}
if (monto <= 0.0m){
return (null, BadRequest(new { message = "No se cargo el monto de alquiler" }));
}
bool tieneOpcionVenta = false;
if (formData.TryGetValue("tieneopcionventa", out var tieneOpcionValues) &&
!string.IsNullOrEmpty(tieneOpcionValues.FirstOrDefault())) {
if (!TryParseBool(tieneOpcionValues.FirstOrDefault(), out tieneOpcionVenta)) {
return (null, BadRequest(new { message = "Campo 'tieneopcionventa' inválido." }));
}
}
int divisaOpcionVenta = 0;
decimal montoOpcionVenta = 0m;
if (tieneOpcionVenta) {
if (formData.TryGetValue("divisaOpcionVenta", out var divisaOpcValues) &&
!string.IsNullOrEmpty(divisaOpcValues.FirstOrDefault())) {
if (!TryParseInt(divisaOpcValues.FirstOrDefault(), out int divisaOpcParsed)) {
return (null, BadRequest(new { message = "Campo 'divisaOpcionVenta' inválido." }));
}
divisaOpcionVenta = divisaOpcParsed;
}
if (formData.TryGetValue("montoOpcionVenta", out var montoOpcValues) &&
!string.IsNullOrEmpty(montoOpcValues.FirstOrDefault())) {
if (!TryParseDecimal(montoOpcValues.FirstOrDefault(), out decimal montoOpcParsed)) {
return (null, BadRequest(new { message = "Campo 'montoOpcionVenta' inválido." }));
}
montoOpcionVenta = montoOpcParsed;
}
}
if (montoOpcionVenta <= 0.0m && tieneOpcionVenta){
return (null, BadRequest(new { message = "No se cargo el monto de la opcion de venta" }));
}
var cont = new Contrato{
Cancelado=0,
Habilitado=0,
Cantgarantemin=cantGarantMin,
Dniinquilino=dniInquilino,
Dnipropietario=dniPropietario,
Fechainicio=DateTime.Now,
Iddivisa=idDivisa,
Idpropiedad=idPropiedad,
Monto=monto,
MesesDurationContrato = mesesDuration,
MesesHastaAumento=mesesHastaAumento,
Idgarantes = ParseGarantes(formData),
Tieneopcionventa=tieneOpcionVenta?1ul:0ul,
};
if(cont.Tieneopcionventa==1ul){
cont.IdventaNavigation = new Venta{
Idestado = 1,
Monto= montoOpcionVenta,
Iddivisa = divisaOpcionVenta
};
}
return (cont, null);
}
private Garante[] ParseGarantes(IFormCollection formData) {
var garantes = new List<Garante>();
var garanteKeys = formData.Keys.Where(k => k.StartsWith("garantes[")).ToList();
var garanteCount = garanteKeys.Count / 6;
for (int i = 0; i < garanteCount; i++) {
int dni = 0;
if (formData.TryGetValue($"garantes[{i}].dni", out var dniValue) &&
!string.IsNullOrEmpty(dniValue.FirstOrDefault()))
{
int.TryParse(dniValue.FirstOrDefault(), out dni);
}
var nombre = formData.TryGetValue($"garantes[{i}].nombre", out var nombreValue) ? nombreValue.ToString() ?? "" : "";
var apellido = formData.TryGetValue($"garantes[{i}].apellido", out var apellidoValue) ? apellidoValue.ToString() ?? "" : "";
var domicilio = formData.TryGetValue($"garantes[{i}].domicilio", out var domicilioValue) ? domicilioValue.ToString() ?? "" : "";
var celular = formData.TryGetValue($"garantes[{i}].celular", out var celularValue) ? celularValue.ToString() ?? "" : "";
var domicilioLaboral = formData.TryGetValue($"garantes[{i}].domicilioLaboral", out var domLaboralValue) ? domLaboralValue.ToString() ?? "" : "";
var garante = new Garante{
Dni = dni,
Nombre = nombre,
Apellido = apellido,
Domicilio = domicilio,
Celular = celular,
Domiciliolaboral = domicilioLaboral
};
garantes.Add(garante);
}
return garantes.ToArray();
}
private readonly IMinioClient mc;
public CargarContratoAdminController(IMinioClient minioClient)
{
mc = minioClient;
if (mc == null)
{
MinioConfigcus? mcon = JsonSerializer.Deserialize<MinioConfigcus>(System.IO.File.ReadAllText("./settings.json")) ?? null;
if (mcon == null) throw new Exception();
mc = new MinioClient().WithCredentials(mcon.usr, mcon.scrt)
.WithEndpoint("0.0.0.0:9000")
.WithSSL(false)
.Build();
}
}
private async Task<bool> subirContrato(IFormFile f, string flname) {
try {
var buck = new BucketExistsArgs().WithBucket("alquilafacil");
bool encontrado = await mc.BucketExistsAsync(buck).ConfigureAwait(false);
if (!encontrado) {
var mb = new MakeBucketArgs().WithBucket("alquilafacil");
await mc.MakeBucketAsync(mb).ConfigureAwait(false);
}
using (var stream = new MemoryStream()) {
await f.CopyToAsync(stream);
stream.Position = 0;
PutObjectArgs putbj = new PutObjectArgs()
.WithBucket("alquilafacil")
.WithObject(flname)
.WithStreamData(stream)
.WithContentType("application/pdf")
.WithObjectSize(stream.Length);
await mc.PutObjectAsync(putbj);
}
return true;
} catch (Exception e) {
Console.Error.WriteLine(e.Message);
return false;
}
}
}

View File

@@ -15,15 +15,19 @@ using Modelo;
namespace AlquilaFacil.Controllers;
[ApiController]
public class ContratoController: ControllerBase {
public class ContratoController : ControllerBase
{
[HttpPost("api/contrato/GenerarRecibo")]
public ActionResult GenerarRecibo([FromHeader(Name="Auth")]string Auth, MarcarPagoDto dto, bool html= true) {
public ActionResult GenerarRecibo([FromHeader(Name = "Auth")] string Auth, MarcarPagoDto dto, bool html = true)
{
if (String.IsNullOrEmpty(Auth)) return Unauthorized();
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Propietario");
if (validacion1 == false){
validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Inquilino");
if (validacion1 == false) {
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 11);
if (validacion1 == false)
{
validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 12);
if (validacion1 == false)
{
return Unauthorized();
}
}
@@ -52,10 +56,13 @@ public class ContratoController: ControllerBase {
var dof = new DocumentoFacade();
MemoryStream? memstr = new();
if (html){
if (html)
{
dof.GenerarHtml(cdb, can.IdreciboNavigation, memstr);
return File(memstr, "text/html", "Recibo.html");
} else {
}
else
{
dof.GenerarPdf(cdb, can.IdreciboNavigation, memstr);
return File(memstr, "application/pdf", "Recibo.pdf");
}
@@ -63,9 +70,10 @@ public class ContratoController: ControllerBase {
}
[HttpPost("api/contratos/marcarPago")]
public IActionResult marcarPago([FromHeader(Name="Auth")]string Auth, MarcarPagoDto dto) {
public IActionResult marcarPago([FromHeader(Name = "Auth")] string Auth, MarcarPagoDto dto)
{
if (String.IsNullOrEmpty(Auth)) return Unauthorized();
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Propietario");
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 12);
if (validacion1 == false) return Unauthorized();
if (dto.Idcontrato <= 0) return BadRequest(new { message = "No puede existir un contrato con id 0 o menor" });
@@ -80,7 +88,8 @@ public class ContratoController: ControllerBase {
Canon? c = RepositorioCanons.Singleton.ObtenerCanonContrato(dto.fecha, dto.Idcontrato);
if (c == null) return BadRequest(new { message = "no hay un canon por esa id" });
Recibo re = new Recibo{
Recibo re = new Recibo
{
Monto = c.Monto,
Fecha = DateTime.Now,
};
@@ -92,9 +101,10 @@ public class ContratoController: ControllerBase {
}
[HttpPost("api/contratos/realizarPago")]
public IActionResult realizarPago([FromHeader(Name="Auth")]string Auth, MarcarPagoDto dto) {
public IActionResult realizarPago([FromHeader(Name = "Auth")] string Auth, MarcarPagoDto dto)
{
if (String.IsNullOrEmpty(Auth)) return Unauthorized();
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Inquilino");
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 11);
if (validacion1 == false) return Unauthorized();
if (dto.Idcontrato <= 0) return BadRequest(new { message = "No puede existir un contrato con id 0 o menor" });
@@ -109,7 +119,8 @@ public class ContratoController: ControllerBase {
Canon? c = RepositorioCanons.Singleton.ObtenerCanonContrato(dto.fecha, dto.Idcontrato);
if (c == null) return BadRequest(new { message = "no hay un canon por esa id" });
Recibo re = new Recibo{
Recibo re = new Recibo
{
Monto = c.Monto,
Fecha = DateTime.Now,
};
@@ -120,9 +131,10 @@ public class ContratoController: ControllerBase {
}
[HttpPost("api/contratos/crearcanons")]
public IActionResult crearCanons([FromHeader(Name="Auth")]string Auth, CrearCanonsDto dto){
public IActionResult crearCanons([FromHeader(Name = "Auth")] string Auth, CrearCanonsDto dto)
{
if (String.IsNullOrEmpty(Auth)) return Unauthorized();
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Propietario");
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 12);
if (validacion1 == false) return Unauthorized();
Cliente? cli = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);
if (cli == null) return Unauthorized();
@@ -139,12 +151,15 @@ public class ContratoController: ControllerBase {
}
[HttpGet("api/contratos/canon")]
public ActionResult getCanons([FromHeader(Name="Auth")]string Auth, int id = 0) {
public ActionResult getCanons([FromHeader(Name = "Auth")] string Auth, int id = 0)
{
if (String.IsNullOrEmpty(Auth)) return Unauthorized();
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Propietario");
if (validacion1 == false){
validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Inquilino");
if (validacion1 == false) {
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 11);
if (validacion1 == false)
{
validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 12);
if (validacion1 == false)
{
return Unauthorized();
}
}
@@ -163,13 +178,16 @@ public class ContratoController: ControllerBase {
List<CanonDto> d = new();
foreach (var i in list) {
foreach (var i in list)
{
int totalMeses = (i.Fecha.Year - cont.Fechainicio.Year) * 12 + (i.Fecha.Month - cont.Fechainicio.Month);
int mesNum = totalMeses + 1;
var c = new CanonDtoBuilder()
.SetId(i.Id)
.SetPago(i.Idrecibo == null ? false : true)
.SetDivisa(divisa == "" ? "Ugh esta mal cargado la divisa en el contrato" : divisa)
.SetMes(i.Fecha)
.SetMesNum(int.Parse((i.Fecha.Month - cont.Fechainicio.Month).ToString()) + 1)
.SetMesNum(mesNum)
.SetMonto(i.Monto)
.Build();
d.Add(c);
@@ -179,9 +197,10 @@ public class ContratoController: ControllerBase {
}
[HttpGet("api/contratos/propietario")]
public IActionResult ObtenerContratosPorPropietario([FromHeader(Name="Auth")]string Auth) {
public IActionResult ObtenerContratosPorPropietario([FromHeader(Name = "Auth")] string Auth)
{
if (String.IsNullOrEmpty(Auth)) return Unauthorized();
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Propietario");
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 12);
if (validacion1 == false) return Unauthorized();
Cliente? cli = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);
@@ -190,7 +209,8 @@ public class ContratoController: ControllerBase {
var list = RepositorioContratos.Singleton.ObtenerContratosDePropietario(cli.Dni);
List<ContratoDto> dtos = new();
foreach (var i in list) {
foreach (var i in list)
{
if (i.DniinquilinoNavigation == null || i.IdpropiedadNavigation == null
|| i.DnipropietarioNavigation == null) continue;
@@ -209,9 +229,10 @@ public class ContratoController: ControllerBase {
}
[HttpGet("api/contrato/propietario")]
public IActionResult ObtenerContratoPorPropietarioPorId([FromHeader(Name="Auth")]string Auth, int id=0) {
public IActionResult ObtenerContratoPorPropietarioPorId([FromHeader(Name = "Auth")] string Auth, int id = 0)
{
if (String.IsNullOrEmpty(Auth)) return Unauthorized();
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Propietario");
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 12);
if (validacion1 == false) return Unauthorized();
Cliente? cli = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);
@@ -242,9 +263,10 @@ public class ContratoController: ControllerBase {
}
[HttpGet("api/contratos/inquilino")]
public IActionResult ObtenerContratosPorInquilino([FromHeader(Name="Auth")]string Auth) {
public IActionResult ObtenerContratosPorInquilino([FromHeader(Name = "Auth")] string Auth)
{
if (String.IsNullOrEmpty(Auth)) return Unauthorized();
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Inquilino");
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 11);
if (validacion1 == false) return Unauthorized();
Cliente? cli = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);
@@ -253,7 +275,8 @@ public class ContratoController: ControllerBase {
var list = RepositorioContratos.Singleton.ObtenerContratosDeInquilino(cli.Dni);
List<ContratoDto> dtos = new();
foreach (var i in list) {
foreach (var i in list)
{
if (i.DniinquilinoNavigation == null || i.IdpropiedadNavigation == null
|| i.DnipropietarioNavigation == null) continue;
@@ -272,9 +295,10 @@ public class ContratoController: ControllerBase {
}
[HttpGet("api/contrato/inquilino")]
public IActionResult ObtenerContratoPorInquilinoPorId([FromHeader(Name="Auth")]string Auth, int id=0) {
public IActionResult ObtenerContratoPorInquilinoPorId([FromHeader(Name = "Auth")] string Auth, int id = 0)
{
if (String.IsNullOrEmpty(Auth)) return Unauthorized();
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Inquilino");
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 11);
if (validacion1 == false) return Unauthorized();
Cliente? cli = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);
@@ -305,10 +329,9 @@ public class ContratoController: ControllerBase {
}
[HttpPost("api/contratos/precontrato")]
public IActionResult IniciarPrecontrato([FromHeader(Name = "Auth")]string Auth, [FromBody] PrecontratoDto dto) {
public IActionResult IniciarPrecontrato([FromHeader(Name = "Auth")] string Auth, [FromBody] PrecontratoDto dto)
{
if (String.IsNullOrEmpty(Auth)) return Unauthorized();
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Propietario");
if (validacion1 == false) return Unauthorized();
string validacion2 = ValidarDtoPrecontrato(dto);
if (validacion2 != "") return BadRequest(new { message = validacion2 });
@@ -351,10 +374,14 @@ public class ContratoController: ControllerBase {
.Build();
bool ret;
if (dto.TieneOpcionVenta==false){
if (dto.TieneOpcionVenta == false)
{
ret = RepositorioContratos.Singleton.CargaPrecontrato(cli.Dni, precontrato, notificacion);
} else {
Venta v = new Venta{
}
else
{
Venta v = new Venta
{
Idestado = 1,
Iddivisa = dto.iddivisa,
Monto = dto.MontoOpcion,
@@ -362,19 +389,54 @@ public class ContratoController: ControllerBase {
ret = RepositorioContratos.Singleton.CargaPrecontratoOpcionVenta(precontrato, notificacion, v, cli.Dni);
}
if (ret) {
if (ret == false) return BadRequest(new { message = "No se pudo cargar el precontrato" });
if (ret)
{
ret = RepositorioNotificaciones.Singleton.MarcarComoLeido(cli.Dni, DateTime.Parse(dto.fechaprimernotificacion));
}
return (ret) ?
Ok(new { message = "Se Cargo el precontrato y envio una notificacion al inquilino" }) :
BadRequest(new {message = "No se pudo cargar el precontrato"});
BadRequest(new { message = "No se pudo enviar la notificacion" });
}
[HttpGet("api/precontrato/preCargaGarantes/data")]
public IActionResult ObtenerDatosParaMostrarleAlInquilinoPreCargaGarantes([FromHeader(Name="Auth")]string Auth, int propiedadId){
if (propiedadId<=0) return BadRequest(new { message = "Numero de propiedad inexistente"});
var cli = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);
if (cli == null) return BadRequest(new { message = "No hay cliente por ese token" });
Contrato? contrato = RepositorioContratos.Singleton.ObtenerPreContratoPorIdDePropiedadyCliente(cli, propiedadId);
if (contrato == null) return BadRequest(new {message = "no se pudo encontrar los datos del precontrato"});
PreContratoDataDto d = new PreContratoDataDto
{
TieneOpcionDeVenta = contrato.Tieneopcionventa == 1,
MontoOpcionDeVenta = contrato.Tieneopcionventa == 1 && contrato.IdventaNavigation != null
? contrato.IdventaNavigation.Monto
: null,
MonedaOpcionDeVenta = contrato.Tieneopcionventa == 1
&& contrato.IdventaNavigation != null
&& contrato.IdventaNavigation.IddivisaNavigation != null
? contrato.IdventaNavigation.IddivisaNavigation.Signo
: null,
DuracionEnMeses = contrato.MesesDurationContrato,
FrecuenciaAumentoEnMeses = contrato.MesesHastaAumento
};
return Ok(d);
}
[HttpPut("api/contratos/addGarantes")]
public IActionResult AddGarantes([FromHeader(Name = "Auth")]string Auth, AltaGarantesDto dto) {
public IActionResult AddGarantes([FromHeader(Name = "Auth")] string Auth, AltaGarantesDto dto)
{
if (String.IsNullOrWhiteSpace(Auth)) return BadRequest("");
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Inquilino");
if (validacion1 == false) return Unauthorized();
var validacion2 = ValidarDtoAltaGarantes(dto);
if (validacion2 != "") return BadRequest(new { message = validacion2 });
@@ -389,14 +451,16 @@ public class ContratoController: ControllerBase {
Cliente? propi = RepositorioPropietario.Singleton.ObtenerPropietarioPorIdPropiedad(dto.Idpropiedad);
if (propi == null) return BadRequest(new { message = "No se encuentra el propietario de la propiedad" });
foreach (var i in dto.garantes) {
foreach (var i in dto.garantes)
{
string validacion3 = ValidarDtoGarante(i);
if (validacion3 != "") return BadRequest(new { message = validacion3 });
}
List<Garante> gar = new();
foreach (var i in dto.garantes) {
foreach (var i in dto.garantes)
{
Garante g = new GaranteBuilder()
.SetNombre(i.Nombre)
.SetApellido(i.Apellido)
@@ -412,8 +476,9 @@ public class ContratoController: ControllerBase {
if (contr == null) return BadRequest(new { message = "No existe el contrato o ya fue activado" });
var ret = RepositorioContratos.Singleton.CargaGarantes(gar, dto.EmailInquilino, dto.Idpropiedad, cli.Dni);
if (ret) {
Console.WriteLine(dto.fecha);
if (ret)
{
//Console.WriteLine(dto.fecha);
RepositorioNotificaciones.Singleton.MarcarComoLeido(cli.Dni, dto.fecha);
var noti = new NotificacioneBuilder()
@@ -432,10 +497,9 @@ public class ContratoController: ControllerBase {
}
[HttpPut("api/contratos/cancelar")]
public IActionResult CancelarPrecontrato([FromHeader(Name = "Auth")]string Auth, CancelarPrecontratoDto dto) {
public IActionResult CancelarPrecontrato([FromHeader(Name = "Auth")] string Auth, CancelarPrecontratoDto dto)
{
if (String.IsNullOrWhiteSpace(Auth)) return BadRequest("");
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Propietario");
if (validacion1 == false) return Unauthorized();
var validacion2 = ValidarCancelarDto(dto);
if (validacion2 != "") return BadRequest(new { message = validacion2 });
@@ -455,10 +519,12 @@ public class ContratoController: ControllerBase {
if (inq == null) return BadRequest(new { message = "No hay un inquilino por ese email" });
var ret = RepositorioContratos.Singleton.CancelarPrecontrato(dto.EmailInquilino, dto.idpropiedad, cli.Dni);
if (ret) {
if (ret)
{
prop.Idestado = 1;
ret = RepositorioPropiedades.Singleton.PatchPropiedad(prop, pro.Dni);
if (ret){
if (ret)
{
RepositorioNotificaciones.Singleton.MarcarComoLeido(pro.Dni, dto.fecha);
var noti = new NotificacioneBuilder()
.SetAccion("ContratoCancelado")
@@ -470,24 +536,30 @@ public class ContratoController: ControllerBase {
.SetLeido(false)
.Build();
ret = RepositorioNotificaciones.Singleton.AltaNotificacion(noti);
if (ret){
if (ret)
{
return Ok(new { message = "Se cancelo el precontrato" });
}else{
}
else
{
return Ok(new { message = "Se cancelo el precontrato, pero no se pudo notificar al inquilino" });
}
}else{
}
else
{
return BadRequest(new { message = "No se pudo setear la propiedad como Disponible en busqueda" });
}
}else{
}
else
{
return BadRequest(new { message = "Se fallo al intentar cancelar el precontrato" });
}
}
[HttpGet("api/contratos/precontrato/listaGarantes")]
public IActionResult ObtenerListaGarantes([FromHeader(Name = "Auth")]string Auth, long idcontrato = 0, [FromQuery] string EmailPropietario = "" ) {
public IActionResult ObtenerListaGarantes([FromHeader(Name = "Auth")] string Auth, long idcontrato = 0, [FromQuery] string EmailPropietario = "")
{
if (String.IsNullOrWhiteSpace(Auth)) return BadRequest("");
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Propietario");
if (validacion1 == false) return Unauthorized();
if (idcontrato == 0 || EmailPropietario == "") return BadRequest(new { message = "Estan mal cargados los datos" });
Cliente? cli = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);
@@ -496,9 +568,11 @@ public class ContratoController: ControllerBase {
Contrato? contr = RepositorioContratos.Singleton.ObtenerPreContratoPorId(idcontrato);
if (contr == null) return BadRequest(new { message = "No hay un precontrato por esa id" });
if (contr.Dnipropietario != cli.Dni) return BadRequest(new { message = "No Coinside los datos del token con el propietario en el precontrato" });
LinkedList<GaranteDto> list = new();
foreach (var i in contr.Idgarantes) {
foreach (var i in contr.Idgarantes)
{
list.AddFirst(new GaranteDtoBuilder()
.SetCelular(i.Celular)
.SetDni(i.Dni)
@@ -512,9 +586,11 @@ public class ContratoController: ControllerBase {
}
private readonly IMinioClient mc;
public ContratoController(IMinioClient minioClient) {
public ContratoController(IMinioClient minioClient)
{
mc = minioClient;
if (mc == null){
if (mc == null)
{
MinioConfigcus? mcon = JsonSerializer.Deserialize<MinioConfigcus>(System.IO.File.ReadAllText("./settings.json")) ?? null;
if (mcon == null) throw new Exception();
@@ -526,16 +602,16 @@ public class ContratoController: ControllerBase {
}
[HttpPost("api/contratos/subirContrato")]
public async Task<IActionResult> subirContrato([FromHeader(Name = "Auth")]string Auth, [FromForm]long idcontrato, [FromForm]DateTime ubicarnotificacion, IFormFile contrato) {
public async Task<IActionResult> subirContrato([FromHeader(Name = "Auth")] string Auth, [FromForm] long idcontrato, [FromForm] DateTime ubicarnotificacion, IFormFile contrato)
{
if (String.IsNullOrWhiteSpace(Auth)) return BadRequest("");
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Propietario");
if (validacion1 == false) return Unauthorized();
if (idcontrato <= 0) return BadRequest(new { message = "No puede tener un id contrato menor o igual a 0" });
Contrato? contr = RepositorioContratos.Singleton.ObtenerPreContratoPorId(idcontrato);
if (contr == null) return BadRequest(new { message = "No hay precontrato por esa id" });
if (contr.Dniinquilino == 0 || contr.Dnipropietario == 0 || contr.Idpropiedad == 0 ||
contr.Dniinquilino == null || contr.Dnipropietario == null || contr.Idpropiedad == null) {
contr.Dniinquilino == null || contr.Dnipropietario == null || contr.Idpropiedad == null)
{
return BadRequest(new { message = "Estan mal cargados los datos del precontrato comunicate con un administrador" });
}
@@ -570,15 +646,20 @@ public class ContratoController: ControllerBase {
return (ret) ?
Ok(new { message = "se notifico al futuro inquilino" }) : BadRequest(new { message = "No se pudo enviar la notificacion" });
}
[HttpGet("api/contrato/DocumentoFinal")]
public IActionResult ObtenerContratoFinal ([FromHeader(Name = "Auth")]string Auth, [FromQuery]long idcontrato) {
public IActionResult ObtenerContratoFinal([FromHeader(Name = "Auth")] string Auth, [FromQuery] long idcontrato)
{
if (String.IsNullOrWhiteSpace(Auth)) return BadRequest("");
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Inquilino");
if (validacion1 == false){
validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Propietario");
if (validacion1 == false) return Unauthorized();
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 11);
if (validacion1 == false)
{
validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 12);
if (validacion1 == false)
{
return Unauthorized();
}
}
if (idcontrato <= 0) return BadRequest(new { message = "La id no puede ser igual o menor a 0" });
@@ -590,13 +671,15 @@ public class ContratoController: ControllerBase {
if (cli == null) return BadRequest(new { message = "No hay un cliente por ese token" });
if (cli.Dni != contr.Dniinquilino && cli.Dni != contr.Dnipropietario) return BadRequest(new { message = "El token no corresponde con el del inquilino" });
try{
try
{
var memstream = new MemoryStream();
var goa = new GetObjectArgs()
.WithBucket("alquilafacil")
.WithObject(contr.UrlContrato)
.WithCallbackStream(stream => {
.WithCallbackStream(stream =>
{
memstream.Position = 0;
stream.CopyTo(memstream);
});
@@ -608,20 +691,18 @@ public class ContratoController: ControllerBase {
return File(memstream, "application/pdf", contr.UrlContrato);
} catch (Exception e){
}
catch (Exception e)
{
Console.Error.WriteLine(e);
return BadRequest(new { message = "Fallo al intentar obtener el archivo del almacenamiento o este no existe" });
}
}
[HttpGet("api/contrato/getdocumento")]
public IActionResult ObtenerContrato([FromHeader(Name = "Auth")]string Auth, [FromQuery]long idcontrato) {
public IActionResult ObtenerContrato([FromHeader(Name = "Auth")] string Auth, [FromQuery] long idcontrato)
{
if (String.IsNullOrWhiteSpace(Auth)) return BadRequest("");
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Inquilino");
if (validacion1 == false){
validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Propietario");
if (validacion1 == false) return Unauthorized();
}
if (idcontrato <= 0) return BadRequest(new { message = "La id no puede ser igual o menor a 0" });
@@ -633,13 +714,15 @@ public class ContratoController: ControllerBase {
if (cli.Dni != contr.Dniinquilino) return BadRequest(new { message = "El token no corresponde con el del inquilino" });
string nuevoNombreArchivo = $"id:{contr.Id}-inq:{contr.Dniinquilino}-propi:{contr.Dnipropietario}-idprop:{contr.Idpropiedad}.pdf";
try{
try
{
var memstream = new MemoryStream();
var goa = new GetObjectArgs()
.WithBucket("alquilafacil")
.WithObject(nuevoNombreArchivo)
.WithCallbackStream(stream => {
.WithCallbackStream(stream =>
{
memstream.Position = 0;
stream.CopyTo(memstream);
});
@@ -651,7 +734,9 @@ public class ContratoController: ControllerBase {
return File(memstream, "application/pdf", nuevoNombreArchivo);
} catch (Exception e){
}
catch (Exception e)
{
Console.Error.WriteLine(e);
return BadRequest(new { message = "Fallo al intentar obtener el archivo del almacenamiento o este no existe" });
}
@@ -659,10 +744,9 @@ public class ContratoController: ControllerBase {
}
[HttpPost("api/contratos/aceptarContrato")]
public IActionResult AceptarContrato([FromHeader(Name = "Auth")]string Auth, [FromBody] AceptarContratoDto dto){
public IActionResult AceptarContrato([FromHeader(Name = "Auth")] string Auth, [FromBody] AceptarContratoDto dto)
{
if (String.IsNullOrWhiteSpace(Auth)) return BadRequest();
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Inquilino");
if (validacion1 == false) return Unauthorized();
if (dto.Idcontrato <= 0) return BadRequest(new { message = "La id no puede ser igual o menor a 0" });
@@ -696,10 +780,9 @@ public class ContratoController: ControllerBase {
}
[HttpPut("api/contratos/rechazarPreContrato")]
public IActionResult CancelarContrato([FromHeader(Name = "Auth")]string Auth, [FromBody] RechazarPreContrato dto ) {
public IActionResult CancelarContrato([FromHeader(Name = "Auth")] string Auth, [FromBody] RechazarPreContrato dto)
{
if (String.IsNullOrWhiteSpace(Auth)) return BadRequest();
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Inquilino");
if (validacion1 == false) return Unauthorized();
if (dto.Idcontrato <= 0) return BadRequest(new { message = "La id no puede ser igual o menor a 0" });
@@ -730,16 +813,20 @@ public class ContratoController: ControllerBase {
BadRequest(new { message = "No se pudo cancelar" });
}
private async Task<bool> subirContrato(IFormFile f, string flname) {
try {
private async Task<bool> subirContrato(IFormFile f, string flname)
{
try
{
var buck = new BucketExistsArgs().WithBucket("alquilafacil");
bool encontrado = await mc.BucketExistsAsync(buck).ConfigureAwait(false);
if(!encontrado){
if (!encontrado)
{
var mb = new MakeBucketArgs().WithBucket("alquilafacil");
await mc.MakeBucketAsync(mb).ConfigureAwait(false);
}
using (var stream = new MemoryStream()){
using (var stream = new MemoryStream())
{
await f.CopyToAsync(stream);
stream.Position = 0;
PutObjectArgs putbj = new PutObjectArgs()
@@ -751,28 +838,42 @@ public class ContratoController: ControllerBase {
await mc.PutObjectAsync(putbj);
}
return true;
} catch (Exception e ) {
}
catch (Exception e)
{
Console.Error.WriteLine(e.Message);
return false;
}
}
[HttpGet("api/contratos/garantes")]
public IActionResult ObtenerGarantes([FromHeader(Name ="Auth")] string Auth, int idcontrato) {
public IActionResult ObtenerGarantes([FromHeader(Name = "Auth")] string Auth, int idcontrato)
{
if (String.IsNullOrWhiteSpace(Auth)) return BadRequest();
if(idcontrato <= 0) return BadRequest();
if (idcontrato <= 0) return BadRequest(new { message = "No puede ser un contrato id menor a 0" });
Cliente? cli = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);
if (cli == null) return BadRequest();
if (cli == null) return BadRequest(new { message = "No existe el cliente para el token" });
Contrato? cont = RepositorioContratos.Singleton.ObtenerContratoPorId(idcontrato);
if (cont == null) return BadRequest();
if (cont == null) return BadRequest(new { message = "El contrato no existe" });
if (cont.Dniinquilino != cli.Dni && cont.Dnipropietario != cli.Dni) return BadRequest();
bool esInquilinoOPropietario = (cont.Dniinquilino ?? 0) == cli.Dni || (cont.Dnipropietario ?? 0) == cli.Dni;
bool tienePermiso = RepositorioPermisos.Singleton.CheckPermisos(Auth, 14);
if (esInquilinoOPropietario == false)
{
return BadRequest(new { message = "No tiene acceso a este path" });
}
else if (tienePermiso == false && esInquilinoOPropietario == false)
{
return BadRequest(new { message = "No tiene acceso a este path de admin" });
}
var list = cont.Idgarantes;
List<GaranteDto> l = new();
foreach (var i in list) {
foreach (var i in list)
{
l.Add(new GaranteDtoBuilder()
.SetCelular(i.Celular)
.SetDni(i.Dni)
@@ -785,7 +886,8 @@ public class ContratoController: ControllerBase {
return Ok(l);
}
private string ValidarCancelarDto(CancelarPrecontratoDto dto) {
private string ValidarCancelarDto(CancelarPrecontratoDto dto)
{
if (dto == null) return "dto nulo";
string ret = "";
@@ -796,7 +898,8 @@ public class ContratoController: ControllerBase {
return ret;
}
private string ValidarDtoGarante(GaranteDto g) {
private string ValidarDtoGarante(GaranteDto g)
{
string ret = "";
if (g == null) return "dto nulo";
@@ -809,7 +912,8 @@ public class ContratoController: ControllerBase {
return ret;
}
private string ValidarDtoAltaGarantes(AltaGarantesDto dto){
private string ValidarDtoAltaGarantes(AltaGarantesDto dto)
{
string ret = "";
if (dto == null) return "dto nulo";
@@ -819,7 +923,8 @@ public class ContratoController: ControllerBase {
return ret;
}
private string ValidarDtoPrecontrato( PrecontratoDto dto) {
private string ValidarDtoPrecontrato(PrecontratoDto dto)
{
string ret = "";
if (dto == null) return "dto nulo";

View File

@@ -7,17 +7,21 @@ using Modelo;
namespace AlquilaFacil.Controllers;
[ApiController]
public class DefectoController: ControllerBase {
public class DefectoController : ControllerBase
{
[HttpGet("api/defectos")]
public IActionResult ObtenerDefectosEnContrato([FromHeader(Name = "Auth")] string Auth, long Idcontrato = 0) {
public IActionResult ObtenerDefectosEnContrato([FromHeader(Name = "Auth")] string Auth, long Idcontrato = 0)
{
if (Idcontrato <= 0) return BadRequest(new { message = "La id de contrato no puede ser menor o igual a 0" });
if (String.IsNullOrEmpty(Auth)) return Unauthorized();
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Propietario");
if (validacion1 == false){
validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Inquilino");
if (validacion1 == false) {
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 12);
if (validacion1 == false)
{
validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 11);
if (validacion1 == false)
{
return Unauthorized();
}
}
@@ -32,7 +36,8 @@ public class DefectoController: ControllerBase {
var l = RepositorioDefectos.Singleton.ObtenerDefectosPorIdContrato(Idcontrato);
List<DefectoDto> ll = new();
foreach (var i in l){
foreach (var i in l)
{
var n = new DefectoDtoBuilder()
.SetId(i.Id)
.SetDesc(i.Descripcion)
@@ -48,9 +53,10 @@ public class DefectoController: ControllerBase {
}
[HttpPost("api/defecto")]
public IActionResult AltaDefecto([FromHeader(Name = "Auth")] string Auth, AltaDefectoDto data) {
public IActionResult AltaDefecto([FromHeader(Name = "Auth")] string Auth, AltaDefectoDto data)
{
if (String.IsNullOrEmpty(Auth)) return Unauthorized();
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Inquilino");
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 11);
if (validacion1 == false) return Unauthorized();
Cliente? cli = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);
@@ -59,7 +65,8 @@ public class DefectoController: ControllerBase {
string r = ValidarDto(data);
if (r != "") return BadRequest(new { message = r });
Defecto defecto = new Defecto{
Defecto defecto = new Defecto
{
Costo = data.Costo,
Descripcion = data.Descripcion,
Idcontrato = data.Idcontrato,
@@ -72,7 +79,8 @@ public class DefectoController: ControllerBase {
return b ? Ok(new { message = "Se cargo el Defecto en el sistema" }) : BadRequest(new { message = "No se pudo cargar el defecto en el sistema" });
}
private string ValidarDto(AltaDefectoDto d){
private string ValidarDto(AltaDefectoDto d)
{
string ret = "";
if (d == null) return "Dto nulo";
@@ -84,9 +92,10 @@ public class DefectoController: ControllerBase {
}
[HttpPut("api/defecto/marcarpago")]
public IActionResult MarcarPago([FromHeader(Name = "Auth")] string Auth, long iddefecto = 0) {
public IActionResult MarcarPago([FromHeader(Name = "Auth")] string Auth, long iddefecto = 0)
{
if (String.IsNullOrEmpty(Auth)) return Unauthorized();
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Propietario");
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 12);
if (validacion1 == false) return Unauthorized();
Cliente? cli = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);

View File

@@ -5,11 +5,28 @@ using Modelo;
namespace AlquilaFacil.Controllers;
[ApiController]
public class EstadisticaController: ControllerBase {
[HttpGet("api/stats/alquileresIniciados")]
public IActionResult alquileresIniciadosEsteAño([FromHeader(Name ="Auth")]string Auth, int year) {
public class EstadisticaController : ControllerBase
{
[HttpGet("/api/stats/Pagos")]
public IActionResult EstadisticasPagos([FromHeader(Name ="Auth")] string Auth, int year){
if (String.IsNullOrWhiteSpace(Auth)) return BadRequest("");
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Informes");
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 6);
if (validacion1 == false) return Unauthorized();
ChartData stats;
List<InformePagos> tabla;
(stats, tabla) = RepositorioEstadisticas.Singleton.InformePagos(year);
return Ok(new { chart = stats, tabla = tabla});
}
[HttpGet("api/stats/alquileresIniciados")]
public IActionResult alquileresIniciadosEsteAño([FromHeader(Name = "Auth")] string Auth, int year)
{
if (String.IsNullOrWhiteSpace(Auth)) return BadRequest("");
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 6);
if (validacion1 == false) return Unauthorized();
var validacion2 = RepositorioContratos.Singleton.HayContratosEnAño(year);
@@ -19,9 +36,10 @@ public class EstadisticaController: ControllerBase {
}
[HttpGet("api/contrato/stats")]
public IActionResult ObtenerMesesPagos([FromHeader(Name ="Auth")]string Auth, long idcontrato=0){
public IActionResult ObtenerMesesPagos([FromHeader(Name = "Auth")] string Auth, long idcontrato = 0)
{
if (String.IsNullOrWhiteSpace(Auth)) return BadRequest("");
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Propietario");
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 12);
if (validacion1 == false) return Unauthorized();
if (idcontrato <= 0) return BadRequest(new { message = "No puede tener un id contrato menor o igual a 0" });
@@ -31,9 +49,10 @@ public class EstadisticaController: ControllerBase {
}
[HttpGet("api/tabla/alquileresIniciados")]
public IActionResult tablaalquileresIniciadosEsteAño([FromHeader(Name ="Auth")]string Auth, int year) {
public IActionResult tablaalquileresIniciadosEsteAño([FromHeader(Name = "Auth")] string Auth, int year)
{
if (String.IsNullOrWhiteSpace(Auth)) return BadRequest("");
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Informes");
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 6);
if (validacion1 == false) return Unauthorized();
var validacion2 = RepositorioContratos.Singleton.HayContratosEnAño(year);
@@ -42,7 +61,8 @@ public class EstadisticaController: ControllerBase {
if (a == null) return BadRequest(new { message = "Fallo al obtener el contrato" });
List<InformesAlquiler> informe = new();
foreach (var i in a) {
foreach (var i in a)
{
var d = new InformesAlquilerBuilder()
.SetId(i.Id).SetUbicacion(i.IdpropiedadNavigation.Ubicacion)
.SetDivisa(i.IddivisaNavigation.Signo)
@@ -52,9 +72,10 @@ public class EstadisticaController: ControllerBase {
return Ok(informe);
}
[HttpGet("api/stats/duracionContrato")]
public IActionResult DuracionContrato([FromHeader(Name ="Auth")]string Auth) {
public IActionResult DuracionContrato([FromHeader(Name = "Auth")] string Auth)
{
if (String.IsNullOrWhiteSpace(Auth)) return BadRequest("");
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Informes");
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 6);
if (validacion1 == false) return Unauthorized();
var a = RepositorioEstadisticas.Singleton.ObtenerDataDuracionContratos();
@@ -62,9 +83,10 @@ public class EstadisticaController: ControllerBase {
}
[HttpGet("api/tabla/duracionContrato")]
public IActionResult TablaDuracionContrato([FromHeader(Name ="Auth")]string Auth) {
public IActionResult TablaDuracionContrato([FromHeader(Name = "Auth")] string Auth)
{
if (String.IsNullOrWhiteSpace(Auth)) return BadRequest("");
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Informes");
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 6);
if (validacion1 == false) return Unauthorized();
var a = RepositorioEstadisticas.Singleton.TablaObtenerDataDuracionContratos();

View File

@@ -0,0 +1,86 @@
using Microsoft.AspNetCore.Mvc;
using Modelo;
using AlquilaFacil.Builder;
using Entidades;
using Entidades.Dto;
namespace AlquilaFacil.Controllers;
[ApiController]
public class GruposController : ControllerBase
{
[HttpGet("api/admin/grupos")]
public IActionResult ObtenerGrupos([FromHeader(Name = "Auth")] string Auth)
{
var ret = RepositorioPermisos.Singleton.CheckPermisos(Auth, 18) ||
RepositorioPermisos.Singleton.CheckPermisos(Auth, 9) ||
RepositorioPermisos.Singleton.CheckPermisos(Auth, 19);
if (ret == false) return BadRequest(new { message = "No tiene permiso para ver todos los grupos" });
Cliente? cli = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);
if (cli == null) return BadRequest(new { message = "No hay un cliente por el token que enviaste" });
var grupos = RepositorioGrupos.Singleton.ListarTodosLosGrupos()
.Select(g => new GrupoDtoBuilder()
.ConNombre(g.Nombre)
.ConIdGrupo(g.Id)
.ConHabilitado(g.Habilitado ?? false)
.ConGruposIncluidos(new HashSet<string>(g.IdGrupoHijos
.Select(id => id.Nombre ?? "")))
.ConPermisos(g.Idpermisos.Select(p => new PermisoDtoBuilder()
.ConId(p.Id)
.ConDescripcion(p.Descripcion)
.Build())
.ToList())
.Build())
.ToList();
return Ok(grupos);
}
[HttpPatch("/api/grupo")]
public IActionResult PatchGrupo([FromHeader(Name = "Auth")] string Auth, GrupoDto grupo)
{
var ret = RepositorioPermisos.Singleton.CheckPermisos(Auth, 18);
if (ret == false) return BadRequest(new { message = "No tiene permiso para Gestionar grupos" });
Cliente? cli = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);
if (cli == null) return BadRequest(new { message = "No hay un cliente por el token que enviaste" });
bool ret2 = RepositorioGrupos.Singleton.PatchGrupo(grupo, cli);
return ret2 ? Ok(new { message = "Se Modifico el grupo" }) : BadRequest(new { message = "Fallo al editar el grupo" });
}
[HttpPost("/api/grupo")]
public IActionResult PostGrupo([FromHeader(Name = "Auth")] string Auth, GrupoDto grupo)
{
var ret = RepositorioPermisos.Singleton.CheckPermisos(Auth, 18);
if (ret == false) return BadRequest(new { message = "No tiene permiso para Gestionar grupos" });
Cliente? cli = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);
if (cli == null) return BadRequest(new { message = "No hay un cliente por el token que enviaste" });
if (grupo.Nombre.Length > 12)
{
return BadRequest(new { message = "El nombre del grupo no puede superar los 12 caracteres" });
}
bool ret2 = RepositorioGrupos.Singleton.AddGrupo(grupo, cli);
return ret2 ? Ok(new { message = "Se Añadio el grupo" }) : BadRequest(new { message = "Fallo al añadirse el grupo" });
}
[HttpDelete("/api/grupo")]
public IActionResult DeleteGrupo([FromHeader(Name = "Auth")] string Auth, [FromQuery] int id)
{
var ret = RepositorioPermisos.Singleton.CheckPermisos(Auth, 18);
if (ret == false) return BadRequest(new { message = "No tiene permiso para Gestionar grupos" });
Cliente? cli = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);
if (cli == null) return BadRequest(new { message = "No hay un cliente por el token que enviaste" });
if (id <= 0) return BadRequest(new { message = "El ID del grupo debe ser mayor que cero" });
var (ret2, estado) = RepositorioGrupos.Singleton.ToggleGrupo(id, cli);
return ret2
? Ok(new { message = (estado ? "Grupo habilitado exitosamente" : "Grupo deshabilitado exitosamente") })
: BadRequest(new { message = "No se pudo cambiar el estado del grupo" });
}
}

View File

@@ -13,7 +13,8 @@ public class InquilinoController: ControllerBase
{
[HttpGet("api/inquilino")]
public IActionResult Get([FromHeader(Name = "Auth")] string Auth) {
public IActionResult Get([FromHeader(Name = "Auth")] string Auth)
{
if (!string.IsNullOrEmpty(Auth)) return BadRequest();
var ret = RepositorioPermisos.Singleton.CheckPermisos(Auth, 9);
@@ -25,7 +26,8 @@ public class InquilinoController: ControllerBase
}
[HttpPost("api/inquilino")]
public IActionResult Post([FromBody] CrearClienteDto cid, [FromHeader(Name = "Auth")] string Auth) {
public IActionResult Post([FromBody] CrearClienteDto cid, [FromHeader(Name = "Auth")] string Auth)
{
if (string.IsNullOrEmpty(Auth)) return BadRequest(new { message = "El String Auth Esta Vacio" });
var ret3 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 4);
if (ret3 == false) return BadRequest(new { message = "Falló el permiso" });
@@ -36,7 +38,8 @@ public class InquilinoController: ControllerBase
var ret = verificarCrearUsuario(cid);
if (ret != "") return BadRequest(new { message = ret });
var cli = new Cliente {
var cli = new Cliente
{
Dni = cid.dni,
Nombre = cid.nombre,
Domicilio = cid.domicilio,
@@ -45,13 +48,15 @@ public class InquilinoController: ControllerBase
Email = cid.email,
Contraseña = Encoding.UTF8.GetBytes(HacerHash(cid.contraseña)),
Habilitado = 1,
EmailRecuperacion = cid.email,
};
bool ret2 = RepositorioUsuarios.Singleton.AltaInquilino(cli, rep.Dni);
return (ret2) ? Ok(new { message = "Se dio de alta la cuenta" }) : BadRequest(new { message = "Fallo Dar de Alta El inquilino" });
}
private string verificarCrearUsuario(CrearClienteDto cid) {
private string verificarCrearUsuario(CrearClienteDto cid)
{
string msg = "";
if (cid.email == string.Empty) msg += "Falta ingresar el email\n";
@@ -65,7 +70,8 @@ public class InquilinoController: ControllerBase
return msg;
}
private string HacerHash(string pass){
private string HacerHash(string pass)
{
var buf = SHA256.HashData(Encoding.UTF8.GetBytes(pass));
return BitConverter.ToString(buf).Replace("-", "");
}

View File

@@ -19,7 +19,7 @@ public class LoginController: ControllerBase
if (!usuario) return Unauthorized(new {message = "El usuario no existe o la contraseña es incorrecta"});
string tokenString = GenerarToken(loginDto);
RepositorioUsuarios.Singleton.GuardarToken(loginDto, tokenString);
RepositorioUsuarios.Singleton.GuardarToken(loginDto, tokenString, Request.HttpContext.Connection.RemoteIpAddress);
var cookieOptions = new CookieOptions
{
@@ -53,6 +53,26 @@ public class LoginController: ControllerBase
}
[HttpDelete("/api/logout")]
public IActionResult CerrarSesion([FromHeader(Name = "Auth")]string Auth){
var cli = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);
if (cli == null ) return BadRequest(new { message = "No hay un cliente con ese token" });
var log = new LoginDto {
Email = cli.Email,
Contraseña = "",
};
string tokenString = GenerarToken(log);
try{
RepositorioUsuarios.Singleton.GuardarToken(log, tokenString, Request.HttpContext.Connection.RemoteIpAddress, "Cerrar Sesión");
} catch {
return BadRequest( new { message = "Fallo al cambiar el token" } );
}
return Ok(new { message = "Se Cerro la sesion" });
}
private string GenerarToken(LoginDto loginDto){
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes("ffb2cdc15d472e41a5b626e294c45020");

View File

@@ -5,12 +5,14 @@ using Modelo;
namespace AlquilaFacil.Controllers;
[ApiController]
public class LogsController: ControllerBase {
public class LogsController : ControllerBase
{
[HttpGet("/api/Logs")]
public IActionResult ObtenerLogs([FromHeader(Name = "Auth")] string Auth, int pag=1) {
public IActionResult ObtenerLogs([FromHeader(Name = "Auth")] string Auth, int pag = 1)
{
if (String.IsNullOrEmpty(Auth)) return Unauthorized();
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Informes");
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 7);
if (validacion1 == false) return Unauthorized();
if (pag <= 0) return BadRequest(new { message = "no puede haber una pagina 0 o menor" });
@@ -18,8 +20,10 @@ public class LogsController: ControllerBase {
var l = RepositorioLogs.Singleton.ObtenerLogsPaginado(pag);
List<LogDto> ll = new();
foreach (var i in l) {
ll.Add(new LogDto{
foreach (var i in l)
{
ll.Add(new LogDto
{
Fecha = i.Fecha,
Accion = i.Accion,
Dniusuario = i.Dniusuario,
@@ -29,16 +33,19 @@ public class LogsController: ControllerBase {
}
[HttpGet("/api/Logs/detalle")]
public IActionResult ObtenerLogs([FromHeader(Name = "Auth")] string Auth, [FromQuery]DateTime fecha, [FromQuery]long idusuario) {
public IActionResult ObtenerLogs([FromHeader(Name = "Auth")] string Auth, [FromQuery] DateTime fecha, [FromQuery] long idusuario)
{
if (String.IsNullOrEmpty(Auth)) return Unauthorized();
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Informes");
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 7);
if (validacion1 == false) return Unauthorized();
if (idusuario <= 0) return BadRequest(new { message = "no puede haber un id 0 o menor" });
var l = RepositorioLogs.Singleton.ObtenerDetallesLogs(fecha, idusuario);
List<LogDetalleDto> ll = new();
foreach (var i in l) {
ll.Add(new LogDetalleDto{
foreach (var i in l)
{
ll.Add(new LogDetalleDto
{
Fecha = i.Fecha,
Dniusuario = i.Dniusuario,
NombreTabla = i.NombreTabla,
@@ -51,9 +58,10 @@ public class LogsController: ControllerBase {
}
[HttpGet("/api/Logs/cantPag")]
public IActionResult cantidadPaginas([FromHeader(Name = "Auth")] string Auth){
public IActionResult cantidadPaginas([FromHeader(Name = "Auth")] string Auth)
{
if (String.IsNullOrEmpty(Auth)) return Unauthorized();
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Informes");
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 7);
if (validacion1 == false) return Unauthorized();
int c = RepositorioLogs.Singleton.ObtenerCantidadPaginas();

View File

@@ -7,9 +7,11 @@ using Modelo;
namespace AlquilaFacil.Controllers;
[ApiController]
public class NotificacionesController: ControllerBase {
public class NotificacionesController : ControllerBase
{
[HttpGet("api/notificaciones")]
public IActionResult GetNotificaciones([FromHeader(Name ="Auth")]string Auth, bool leido = false) {
public IActionResult GetNotificaciones([FromHeader(Name = "Auth")] string Auth, bool leido = false)
{
if (string.IsNullOrEmpty(Auth)) return Unauthorized();
var cli = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);
@@ -20,7 +22,8 @@ public class NotificacionesController: ControllerBase {
List<NotificacionDto> noti = new();
foreach (Notificacione i in notificaciones) {
foreach (Notificacione i in notificaciones)
{
if (i.DniclienteNavigation == null || i.DniremitenteNavigation == null) return BadRequest(new { message = "Esta mal cargado el precontrato" });
var dto = new NotificacionDtoBuilder()
.SetRemitente(i.DniremitenteNavigation.Email ?? "")
@@ -38,7 +41,8 @@ public class NotificacionesController: ControllerBase {
}
[HttpGet("api/notificaciones/haySinLeer")]
public IActionResult GetHayNotis([FromHeader(Name ="Auth")]string Auth) {
public IActionResult GetHayNotis([FromHeader(Name = "Auth")] string Auth)
{
if (String.IsNullOrWhiteSpace(Auth)) return Unauthorized();
var cli = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);
@@ -49,7 +53,8 @@ public class NotificacionesController: ControllerBase {
}
[HttpPut("api/notificaciones")]
public IActionResult MarcarComoLeido([FromHeader(Name = "Auth")]string Auth, NotificacionMarcarLeidoDto nota) {
public IActionResult MarcarComoLeido([FromHeader(Name = "Auth")] string Auth, NotificacionMarcarLeidoDto nota)
{
if (String.IsNullOrWhiteSpace(Auth)) return Unauthorized();
if (nota.Fecha == null || String.IsNullOrWhiteSpace(nota.Email)) return BadRequest(new { message = "Faltan datos" });
@@ -66,7 +71,8 @@ public class NotificacionesController: ControllerBase {
}
[HttpPost("api/notificaciones/consultaAlquiler")]
public IActionResult ConsultaAlquiler([FromHeader(Name ="Auth")]string Auth, [FromBody] AltaNotificacionDto data) {
public IActionResult ConsultaAlquiler([FromHeader(Name = "Auth")] string Auth, [FromBody] AltaNotificacionDto data)
{
if (String.IsNullOrWhiteSpace(Auth)) return Unauthorized();
bool validacion1 = RepositorioUsuarios.Singleton.CheckToken(data.Remitente, Auth);
if (validacion1 == false) return BadRequest(new { message = "el token no corresponde a su usuario" });
@@ -97,9 +103,10 @@ public class NotificacionesController: ControllerBase {
}
[HttpPost("api/notificarInquilino")]
public IActionResult NotificarInq([FromHeader(Name ="Auth")]string Auth, [FromBody] AvisoInquilinoDto data) {
public IActionResult NotificarInq([FromHeader(Name = "Auth")] string Auth, [FromBody] AvisoInquilinoDto data)
{
if (String.IsNullOrWhiteSpace(Auth)) return Unauthorized();
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Propietario");
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 12);
if (validacion1 == false) return Unauthorized();
if (data.Mensaje == "") return BadRequest(new { message = "El campo Mensaje esta vacio" });
@@ -123,14 +130,15 @@ public class NotificacionesController: ControllerBase {
}
[HttpPost("api/notificar/ConsultaCompra")]
public IActionResult EnviarConsultaCompra([FromHeader(Name ="Auth")]string Auth, AltaNotificacionDto dto) {
public IActionResult EnviarConsultaCompra([FromHeader(Name = "Auth")] string Auth, AltaNotificacionDto dto)
{
if (String.IsNullOrWhiteSpace(Auth)) return Unauthorized();
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Propietario");
if (validacion1 == false){
validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Inquilino");
if (validacion1 == false) {
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 16);
if (validacion1 == false)
{
return Unauthorized();
}
}
if (dto.Accion == "") return BadRequest(new { message = "El campo Accion esta vacio" });

View File

@@ -0,0 +1,61 @@
using Microsoft.AspNetCore.Mvc;
using Modelo;
using Entidades;
using Entidades.Dto;
using AlquilaFacil.Builder;
namespace AlquilaFacil.Controllers;
[ApiController]
public class PermisoController : ControllerBase
{
[HttpPost("api/permisos")]
public IActionResult CrearPermiso([FromHeader(Name = "Auth")] string Auth, PermisoDto perm)
{
var ret1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 17);
if (ret1 == false) return BadRequest(new { message = "No tienes permiso para esto" });
Cliente? cli = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);
if (cli == null) return BadRequest(new { message = "No hay un cliente por el token que enviaste" });
if (String.IsNullOrWhiteSpace(perm.Descripcion)) return BadRequest(new { message = "No puede tener una descripcion vacia" });
if (perm.Descripcion.Length > 25) return BadRequest(new { message = "la descripcion no puede tener más de 25 caractéres" });
var permiso = new PermisoBuilder().SetDescripcion(perm.Descripcion).Build();
var ret = RepositorioPermisos.Singleton.CrearPermiso(permiso, cli);
return ret ? Ok() : BadRequest();
}
[HttpPatch("api/permisos")]
public IActionResult PatchPermiso([FromHeader(Name = "Auth")] string Auth, PermisoDto perm)
{
var ret1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 17);
if (ret1 == false) return BadRequest(new { message = "No tienes permiso para esto" });
Cliente? cli = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);
if (cli == null) return BadRequest(new { message = "No hay un cliente por el token que enviaste" });
if (perm.Id <= 0) return BadRequest(new { message = "No puede haber una id 0 o menor" });
if (String.IsNullOrWhiteSpace(perm.Descripcion)) return BadRequest(new { message = "No puede tener una descripcion vacia" });
if (perm.Descripcion.Length > 25) return BadRequest(new { message = "la descripcion no puede tener más de 25 caractéres" });
var permiso = new PermisoBuilder().SetDescripcion(perm.Descripcion).SetID(perm.Id).Build();
var ret = RepositorioPermisos.Singleton.PatchPermiso(permiso, cli);
return ret ? Ok() : BadRequest();
}
[HttpGet("/api/permisos/todos")]
public IActionResult ObtenerTodosLosPermisos([FromHeader(Name = "Auth")] string Auth)
{
var ret = RepositorioPermisos.Singleton.CheckPermisos(Auth, 18);
if (ret == false) return BadRequest(new { message = "No tiene permiso para ver Todos los permisos" });
var permisos = RepositorioPermisos.Singleton.ListarPermisos();
var perms = permisos.Select(permiso => new PermisoDtoBuilder()
.ConId(permiso.Id)
.ConDescripcion(permiso.Descripcion)
.Build());
return Ok(perms);
}
}

View File

@@ -6,9 +6,11 @@ using Modelo;
namespace AlquilaFacil.Controllers;
[ApiController]
public class PropiedadesController: ControllerBase {
public class PropiedadesController : ControllerBase
{
[HttpGet("api/propiedades")]
public IActionResult ListarPropiedades([FromHeader(Name = "Auth")] string Auth, int pag = 0) {
public IActionResult ListarPropiedades([FromHeader(Name = "Auth")] string Auth, int pag = 0)
{
if (String.IsNullOrEmpty(Auth)) return Unauthorized();
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 10);
if (validacion1 == false) validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 2);
@@ -16,9 +18,12 @@ public class PropiedadesController: ControllerBase {
IQueryable<PropiedadesDto> ret;
if (pag == 0){
if (pag == 0)
{
ret = RepositorioPropiedades.Singleton.ListarPropiedades();
} else{
}
else
{
ret = RepositorioPropiedades.Singleton.ListarPropiedadesPorPagina(pag);
}
@@ -26,9 +31,11 @@ public class PropiedadesController: ControllerBase {
}
[HttpGet("/api/propiedades/Venta")]
public IActionResult ObtenerPropiedadesParaVenta([FromHeader(Name = "Auth")] string Auth, int pag = 0) {
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Propietario");
if (validacion1 == false) {
public IActionResult ObtenerPropiedadesParaVenta([FromHeader(Name = "Auth")] string Auth, int pag = 0)
{
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 16);
if (validacion1 == false)
{
return Unauthorized();
}
@@ -41,8 +48,10 @@ public class PropiedadesController: ControllerBase {
List<PropiedadesVentaDto> l = new();
foreach (var i in props) {
var p = new PropiedadesVentaDto{
foreach (var i in props)
{
var p = new PropiedadesVentaDto
{
Id = i.Id,
Ubicacion = i.Ubicacion,
Canthabitaciones = i.Canthabitaciones,
@@ -62,9 +71,11 @@ public class PropiedadesController: ControllerBase {
}
[HttpGet("api/propiedades/Venta/Propietario")]
public IActionResult ObtenerPropiedadesVentaDePropietario( [FromHeader(Name = "Auth")] string Auth){
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Propietario");
if (validacion1 == false) {
public IActionResult ObtenerPropiedadesVentaDePropietario([FromHeader(Name = "Auth")] string Auth)
{
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 15);
if (validacion1 == false)
{
return Unauthorized();
}
@@ -74,8 +85,10 @@ public class PropiedadesController: ControllerBase {
var props = RepositorioPropiedades.Singleton.ObtenerPropiedadesAVentaPorDni(cli.Dni);
List<PropiedadesDto> ll = new();
foreach (var i in props) {
var a = new PropiedadesDto {
foreach (var i in props)
{
var a = new PropiedadesDto
{
id = i.Id,
Ubicacion = i.Ubicacion,
canthabitaciones = i.Canthabitaciones,
@@ -92,7 +105,8 @@ public class PropiedadesController: ControllerBase {
}
[HttpGet("api/propiedad")]
public IActionResult ObtenerPropiedadPorId(int Id, [FromHeader(Name = "Auth")] string Auth) {
public IActionResult ObtenerPropiedadPorId(int Id, [FromHeader(Name = "Auth")] string Auth)
{
if (String.IsNullOrEmpty(Auth)) return Unauthorized();
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 10);
if (validacion1 == false) return Unauthorized();
@@ -105,7 +119,8 @@ public class PropiedadesController: ControllerBase {
}
[HttpGet("api/propiedad/cantPagina")]
public IActionResult ObtenerCantidadDePaginas([FromHeader(Name = "Auth")] string Auth, int estado = 0) {
public IActionResult ObtenerCantidadDePaginas([FromHeader(Name = "Auth")] string Auth, int estado = 0)
{
if (String.IsNullOrEmpty(Auth)) return Unauthorized();
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 10);
if (validacion1 == false) return Unauthorized();
@@ -113,9 +128,12 @@ public class PropiedadesController: ControllerBase {
if (estado < 0) return BadRequest(new { message = "No puede tener un numero menor a 0" });
int cant;
if(estado == 0){
if (estado == 0)
{
cant = RepositorioPropiedades.Singleton.CuantasPaginas();
}else{
}
else
{
cant = RepositorioPropiedades.Singleton.CuantasPaginas(estado);
}
@@ -126,7 +144,8 @@ public class PropiedadesController: ControllerBase {
[HttpGet("api/propiedades/Propietario")]
public IActionResult ObtenerPropiedadesPorPropietario(
[FromHeader(Name = "Email")] string email,
[FromHeader(Name = "Auth")] string Auth) {
[FromHeader(Name = "Auth")] string Auth)
{
if (String.IsNullOrEmpty(Auth)) return Unauthorized();
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 2);
@@ -142,7 +161,8 @@ public class PropiedadesController: ControllerBase {
[HttpGet("api/propiedades/Propietario/Bajas")]
public IActionResult ObtenerPropiedadesPorPropietarioBajas(
[FromHeader(Name = "Email")] string email,
[FromHeader(Name = "Auth")] string Auth) {
[FromHeader(Name = "Auth")] string Auth)
{
if (String.IsNullOrEmpty(Auth)) return Unauthorized();
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 8);
@@ -156,7 +176,8 @@ public class PropiedadesController: ControllerBase {
}
[HttpPost("api/propiedad")]
public IActionResult AltaPropiedad([FromBody] AltaPropiedadDto propiedad, [FromHeader(Name = "Auth")] string Auth) {
public IActionResult AltaPropiedad([FromBody] AltaPropiedadDto propiedad, [FromHeader(Name = "Auth")] string Auth)
{
if (String.IsNullOrEmpty(Auth)) return Unauthorized();
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 1);
if (validacion1 == false) return Unauthorized();
@@ -167,7 +188,8 @@ public class PropiedadesController: ControllerBase {
Cliente? cli = RepositorioPropietario.Singleton.ObtenerPropietarioPorEmail(propiedad.Email);
if (cli == null) return BadRequest(new { message = "El email no corresponde a un propietario" });
Propiedade Prop = new Propiedade{
Propiedade Prop = new Propiedade
{
Canthabitaciones = propiedad.Canthabitaciones,
Dnipropietario = cli.Dni,
Idtipropiedad = propiedad.Idtipropiedad,
@@ -178,14 +200,18 @@ public class PropiedadesController: ControllerBase {
Iddivisa = propiedad.Iddivisa,
};
var ret = RepositorioPropiedades.Singleton.AñadirPropiedad(Prop);
Cliente? responsable = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);
if (cli == null) return Unauthorized();
var ret = RepositorioPropiedades.Singleton.AñadirPropiedad(Prop, responsable.Dni);
return (ret) ?
Ok(new { message = "Fue Cargado Correctamente" }) :
BadRequest(new { message = "Fallo al momento de añadir la propiedad a la base de datos" });
}
[HttpPatch("api/propiedad")]
public IActionResult PatchPropiedad([FromBody] PatchPropiedadDto propiedad, [FromHeader(Name = "Auth")] string Auth) {
public IActionResult PatchPropiedad([FromBody] PatchPropiedadDto propiedad, [FromHeader(Name = "Auth")] string Auth)
{
if (String.IsNullOrEmpty(Auth)) return Unauthorized();
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 2);
@@ -199,7 +225,8 @@ public class PropiedadesController: ControllerBase {
List<Servicio> servs = RepositorioServicios.Singleton.ObtenerServiciosPorDescripcion(propiedad.Servicios);
Propiedade Prop = new Propiedade{
Propiedade Prop = new Propiedade
{
Id = propiedad.id,
Canthabitaciones = propiedad.Canthabitaciones,
Dnipropietario = cli.Dni,
@@ -219,7 +246,8 @@ public class PropiedadesController: ControllerBase {
}
[HttpDelete("api/propiedad")]
public IActionResult BajaPropiedad(int id, [FromHeader(Name = "Auth")] string Auth, [FromHeader(Name = "Email")] string email){
public IActionResult BajaPropiedad(int id, [FromHeader(Name = "Auth")] string Auth, [FromHeader(Name = "Email")] string email)
{
if (String.IsNullOrEmpty(Auth)) return Unauthorized();
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 2);
if (validacion1 == false) return Unauthorized();
@@ -236,7 +264,8 @@ public class PropiedadesController: ControllerBase {
}
[HttpPut("api/propiedades/addServicio")]
public IActionResult AñadirServicio([FromBody] ServicioAPropiedadDto Servicios, [FromHeader(Name = "Auth")] string Auth) {
public IActionResult AñadirServicio([FromBody] ServicioAPropiedadDto Servicios, [FromHeader(Name = "Auth")] string Auth)
{
if (String.IsNullOrEmpty(Auth)) return Unauthorized();
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 2);
if (validacion1 == false) return Unauthorized();
@@ -260,7 +289,8 @@ public class PropiedadesController: ControllerBase {
}
[HttpPut("api/propiedades/RmServicio")]
public IActionResult EliminarServicio([FromBody] ServicioAPropiedadDto servicio, [FromHeader(Name = "Auth")] string Auth) {
public IActionResult EliminarServicio([FromBody] ServicioAPropiedadDto servicio, [FromHeader(Name = "Auth")] string Auth)
{
if (String.IsNullOrEmpty(Auth)) return Unauthorized();
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 2);
if (validacion1 == false) return Unauthorized();
@@ -282,7 +312,8 @@ public class PropiedadesController: ControllerBase {
}
private string ValidarPropiedad(AltaPropiedadDto prop) {
private string ValidarPropiedad(AltaPropiedadDto prop)
{
if (prop == null) return "Esta mal formado el body de la request";
string ret = "";
@@ -301,7 +332,8 @@ public class PropiedadesController: ControllerBase {
return ret;
}
private string ValidarPropiedad(PatchPropiedadDto prop) {
private string ValidarPropiedad(PatchPropiedadDto prop)
{
if (prop == null) return "Esta mal formado el body de la request";
string ret = "";

View File

@@ -9,10 +9,12 @@ using Modelo;
namespace AlquilaFacil.Controllers;
[ApiController]
public class PropietarioController: ControllerBase {
public class PropietarioController : ControllerBase
{
[HttpGet("api/propietario")]
public IActionResult ObtenerPropietarioPorDni(long Dni, [FromHeader(Name ="Auth")] string Auth) {
public IActionResult ObtenerPropietarioPorDni(long Dni, [FromHeader(Name = "Auth")] string Auth)
{
if (String.IsNullOrEmpty(Auth)) return Unauthorized();
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 14);
if (validacion1 == false) return Unauthorized();
@@ -23,7 +25,8 @@ public class PropietarioController: ControllerBase {
[HttpPost("api/propietario")]
public IActionResult AltaPropietario([FromBody] CrearClienteDto Propietario,
[FromHeader(Name = "Auth")] string Auth) {
[FromHeader(Name = "Auth")] string Auth)
{
if (String.IsNullOrEmpty(Auth)) return Unauthorized();
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 5);
if (validacion1 == false) return Unauthorized();
@@ -34,7 +37,8 @@ public class PropietarioController: ControllerBase {
string validacion2 = verificarCrearUsuario(Propietario);
if (validacion2 != "") return BadRequest(validacion2);
var cli = new Cliente {
var cli = new Cliente
{
Dni = Propietario.dni,
Nombre = Propietario.nombre,
Domicilio = Propietario.domicilio,
@@ -43,6 +47,7 @@ public class PropietarioController: ControllerBase {
Email = Propietario.email,
Contraseña = Encoding.UTF8.GetBytes(HacerHash(Propietario.contraseña)),
Habilitado = 1,
EmailRecuperacion = Propietario.email,
};
bool ret = RepositorioUsuarios.Singleton.AltaPropietario(cli, rep.Dni);
@@ -51,7 +56,8 @@ public class PropietarioController: ControllerBase {
}
[HttpPatch("api/propietarios")]
public IActionResult PatchPropietario([FromBody]CrearClienteDto Propietario, [FromHeader(Name = "Auth")] string Auth){
public IActionResult PatchPropietario([FromBody] CrearClienteDto Propietario, [FromHeader(Name = "Auth")] string Auth)
{
if (String.IsNullOrEmpty(Auth)) return Unauthorized();
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 5);
if (validacion1 == false) return Unauthorized();
@@ -59,7 +65,8 @@ public class PropietarioController: ControllerBase {
string validacion2 = verificarCrearUsuario(Propietario);
if (validacion2 != "") return BadRequest(validacion2);
var cli = new Cliente {
var cli = new Cliente
{
Dni = Propietario.dni,
Nombre = Propietario.nombre,
Domicilio = Propietario.domicilio,
@@ -73,7 +80,8 @@ public class PropietarioController: ControllerBase {
Ok(new { message = "Se Modifico el propietario exitosamente" }) : BadRequest();
}
private string verificarCrearUsuario(CrearClienteDto cid) {
private string verificarCrearUsuario(CrearClienteDto cid)
{
string msg = "";
if (cid.email == string.Empty) msg += "Falta ingresar el email\n";
@@ -87,7 +95,8 @@ public class PropietarioController: ControllerBase {
return msg;
}
private string HacerHash(string pass){
private string HacerHash(string pass)
{
var buf = SHA256.HashData(Encoding.UTF8.GetBytes(pass));
return BitConverter.ToString(buf).Replace("-", "");
}

View File

@@ -0,0 +1,177 @@
using AlquilaFacil.Builder;
using Microsoft.AspNetCore.Mvc;
using Modelo;
using Entidades;
using AlquilaFacil.Emailer.Sender;
namespace AlquilaFacil.Controllers;
[ApiController]
public class UsuarioController : ControllerBase
{
[HttpGet("/api/usuario")]
public IActionResult ObtenerInfoUsuario([FromHeader(Name = "Auth")] string Auth)
{
Cliente? cli = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);
if (cli == null) return BadRequest(new { message = "No hay un usuari por ese token" });
var usu = new UsuarioDtoBuilder()
.SetNombre(cli.Nombre).SetApellido(cli.Apellido)
.SetEmail(cli.Email).SetCelular(cli.Celular)
.SetDni(cli.Dni).SetDomicilio(cli.Domicilio)
.SetEmailRecuperacion(cli.EmailRecuperacion)
.Build();
return Ok(usu);
}
public class bodyCambiarContraseña
{
public string contraseña { get; set; } = "";
}
[HttpPatch("/api/usuario")]
public IActionResult CambiarPass([FromHeader(Name = "Auth")] string Auth, [FromBody] bodyCambiarContraseña body)
{
Cliente? cli = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);
if (cli == null) return BadRequest(new { message = "No hay un usuario por ese token" });
if (body.contraseña.Length < 8) return BadRequest(new { message = "Tiene que tener por lo menos 8 caracteres" });
bool ret = RepositorioUsuarios.Singleton.CambiarContraseña(body.contraseña, cli);
return ret ? Ok(new { message = "Contraseña cambiada con éxito" }) : BadRequest(new { message = "No se pudo cambiar la contraseña" });
}
public class bodyCambiarContraAdmin : bodyCambiarContraseña
{
public long Dni { get; set; }
}
[HttpPatch("/api/admin/contraseña")]
public IActionResult CambiarPassAdmin([FromHeader(Name = "Auth")] string Auth, [FromBody] bodyCambiarContraAdmin body)
{
var ret = RepositorioPermisos.Singleton.CheckPermisos(Auth, 9);
if (!ret) return BadRequest(new { message = "No tienes permisos para cambiar contraseñas de usuario" });
if (body.contraseña.Length < 8 || string.IsNullOrWhiteSpace(body.contraseña)) return BadRequest(new { message = "La contraseña debe tener al menos 8 caracteres y no puede estar vacía" });
if (body.Dni <= 0) return BadRequest(new { message = "El DNI no puede estar vacío" });
Cliente? usu = RepositorioUsuarios.Singleton.ObtenerClientePorDni(body.Dni);
if (usu == null) return BadRequest(new { message = "No existe un usuario con ese DNI" });
ret = RepositorioUsuarios.Singleton.CambiarContraseña(body.contraseña, usu);
return ret ? Ok(new { message = "Contraseña cambiada con éxito" }) : BadRequest(new { message = "No se pudo cambiar la contraseña" });
}
public record SetEmail(string EmailRecuperacion);
[HttpPut("/api/usuario/emailrecuperacion")]
public IActionResult CambiarPass([FromHeader(Name = "Auth")] string Auth, [FromBody] SetEmail setemail)
{
Cliente? cli = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);
if (cli == null) return BadRequest(new { message = "No hay un usuario por ese token" });
string emailrecuperacion = setemail.EmailRecuperacion;
if (!emailrecuperacion.Contains("@")) return BadRequest(new { message = "Tiene que ser un email" });
bool ret = RepositorioUsuarios.Singleton.SetEmailRecuperacion(emailrecuperacion, cli);
if (ret == false) return BadRequest(new { message = "No se pudo actualizar el email de recuperación" });
Task.Run(() =>
{
AvisoEmailSender s = new();
s.Send(cli.Email, setemail.EmailRecuperacion);
});
return Ok(new { message = "Email de recuperación actualizado con éxito" });
}
public record RecuperarUsuarioDto(string Email, string EmailRecuperacion);
[HttpPost("/api/recuperarUsuario")]
public IActionResult RecuperarUsuario([FromBody] RecuperarUsuarioDto mails)
{
bool check = RepositorioUsuarios.Singleton.CheckEmailRecuperacion(mails.Email, mails.EmailRecuperacion);
if (check == false) return BadRequest(new { message = "El email no corresponde al email de recuperacion" });
string pin = "";
var ran = new Random();
for (int i = 0; i < 6; i++) pin += ran.Next(0, 10);
bool ret = RepositorioUsuarios.Singleton.SetF2aPin(pin, mails.Email);
if (ret == false) return BadRequest(new { message = "no se pudo generar/guardar el codigo 2fa" });
Task.Run(() =>
{
OtpEmailSender s = new();
s.Send(mails.EmailRecuperacion, mails.Email, pin);
});
return Ok(new { message = $"Se envio un email de recuperacion a {mails.EmailRecuperacion}" });
}
public record ingreso2fa(string Pin, string Email);
[HttpPost("/api/ingresar2fa")]
public IActionResult IngresarUsuario([FromBody] ingreso2fa data)
{
if (!data.Email.Contains("@")) return BadRequest(new { message = "Tiene que ser un email" });
if (data.Pin.Length != 6) return BadRequest(new { message = "el pin tiene que tener 6 digitos" });
(bool check, long Dni) = RepositorioUsuarios.Singleton.Check2fa(data.Email, data.Pin);
if (check == false) return BadRequest(new { message = "El pin es incorrecto" });
var cli = RepositorioUsuarios.Singleton.ObtenerClientePorDni(Dni);
//esto literalmente no se puede triggerear pero lo pongo para evitar una warning
if (cli == null) return BadRequest(new { message = "El usuario no existe" });
return Ok(new { token = cli.Token });
}
public record Crearusuario(long Dni, string Nombre, string Apellido, string Domicilio, string Celular,
string Email, string Contraseña, string? EmailRecuperacion, List<int> grupos);
[HttpPost("api/crearusuario")]
public IActionResult CrearUsuario([FromHeader(Name ="Auth")] string Auth, [FromBody] Crearusuario cu)
{
var ret = RepositorioPermisos.Singleton.CheckPermisos(Auth, 19);
if (!ret) return BadRequest(new { message = "No tienes permisos para Crear un usuario" });
Cliente? cli = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);
if (cli == null) return BadRequest(new { message = "No hay un usuario por ese token" });
string rett = "";
if (cu.Dni <= 0)
rett += "No puede haber un documento con numero menor o igual a 0";
if (cu.Apellido.Length > 20)
rett += "Apellido excede los 20 caracteres. ";
if (cu.Nombre.Length > 20)
rett += "Nombre excede los 20 caracteres. ";
if (cu.Celular.Length > 40)
rett += "Celular excede los 40 caracteres. ";
if (cu.Domicilio.Length > 40)
rett += "Domicilio excede los 40 caracteres. ";
if (cu.Email.Length > 50)
rett += "Email excede los 50 caracteres. ";
if (cu.EmailRecuperacion?.Length > 50)
rett += "Email de recuperación excede los 50 caracteres. ";
if (rett != "") return BadRequest(new { message = rett });
Cliente clii = new Cliente
{
Habilitado = 1,
Dni = cu.Dni,
Nombre = cu.Nombre,
Apellido = cu.Apellido,
Celular = cu.Celular,
Email = cu.Email,
EmailRecuperacion = ((cu.EmailRecuperacion ?? "").Length == 0) ? cu.Email : cu.EmailRecuperacion,
Domicilio = cu.Domicilio
};
var rettt = RepositorioUsuarios.Singleton.AltaUsuario(cli.Dni, clii, cu.Contraseña, cu.grupos);
return rettt
? Ok(new { message = "Usuario creado exitosamente." })
: BadRequest(new { message = "Hubo un error al crear el usuario." }); }
}

View File

@@ -1,5 +1,3 @@
using System.Configuration;
using System.Formats.Asn1;
using System.Text.Json;
using AlquilaFacil.Builder;
using AlquilaFacil.Config;
@@ -12,12 +10,15 @@ using Modelo;
namespace AlquilaFacil.Controllers;
[ApiController]
public class VentaController:ControllerBase {
public class VentaController : ControllerBase
{
[HttpPost("api/venta/AceptarConsultaVenta")]
public IActionResult AceptarConsultaVenta([FromHeader(Name="Auth")]string Auth, NotificacionMarcarLeidoDto dto) {
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Propietario");
if (validacion1 == false) {
public IActionResult AceptarConsultaVenta([FromHeader(Name = "Auth")] string Auth, NotificacionMarcarLeidoDto dto)
{
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 15);
if (validacion1 == false)
{
return Unauthorized();
}
if (dto.Email == "") return BadRequest(new { message = "Falta dato Email" });
@@ -32,7 +33,8 @@ public class VentaController:ControllerBase {
Propiedade? prop = RepositorioPropiedades.Singleton.ObtenerPropiedadPorId(n.Idpropiedad);
if (prop == null) return BadRequest(new { message = "No se encuentra una propiedad por ese id" });
Venta? v = new Venta{
Venta? v = new Venta
{
Fechainicio = DateTime.Now,
IdVendedor = prop.Dnipropietario,
IdComprador = n.Dniremitente,
@@ -44,7 +46,8 @@ public class VentaController:ControllerBase {
};
bool ret = RepositorioVentas.Singleton.IniciarVenta(v, cli.Dni);
if (ret){
if (ret)
{
var noti = new NotificacioneBuilder()
.SetAccion("Notificacion")
.SetMensaje("Debe Realizar el pago para que se registre el traspaso de la propiedad")
@@ -61,9 +64,11 @@ public class VentaController:ControllerBase {
}
[HttpPost("api/venta/CancelarConsultaVenta")]
public IActionResult CancelarConsultaVenta([FromHeader(Name="Auth")]string Auth, NotificacionMarcarLeidoDto dto) {
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Propietario");
if (validacion1 == false) {
public IActionResult CancelarConsultaVenta([FromHeader(Name = "Auth")] string Auth, NotificacionMarcarLeidoDto dto)
{
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 15);
if (validacion1 == false)
{
return Unauthorized();
}
@@ -90,23 +95,13 @@ public class VentaController:ControllerBase {
Ok(new { message = "Se Envio una notificacion" }) : BadRequest(new { message = "Fallo al Descartar Consulta" });
}
[HttpGet("/api/propiedad/EstaALaVenta")]
public IActionResult EstaALaVenta([FromHeader(Name="Auth")]string Auth, int idprop=0) {
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Propietario");
if (validacion1 == false) {
return Unauthorized();
}
if (idprop<=0) return BadRequest(new { message = "No hay propiedades con id 0 o menor"});
Propiedade? prop = RepositorioPropiedades.Singleton.ObtenerPropiedadPorId(idprop);
if (prop == null) return BadRequest(new { message = "No hay propiedades por ese id"});
return Ok(new { EstaAVenta = prop.Idestado ==4?true:false});
}
[HttpPut("/api/propiedad/setPropiedadAVenta")]
public IActionResult setPropiedadAVenta([FromHeader(Name="Auth")]string Auth, SetVentaDto dto) {
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Propietario");
if (validacion1 == false) {
public IActionResult setPropiedadAVenta([FromHeader(Name = "Auth")] string Auth, SetVentaDto dto)
{
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 2);
var validacion2 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 8);
if (validacion1 == false || validacion2 == false)
{
return Unauthorized();
}
@@ -128,9 +123,11 @@ public class VentaController:ControllerBase {
}
[HttpPut("/api/propiedad/unsetPropiedadAVenta")]
public IActionResult unsetPropiedadAVenta([FromHeader(Name="Auth")]string Auth, SetVentaDto dto) {
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Propietario");
if (validacion1 == false) {
public IActionResult unsetPropiedadAVenta([FromHeader(Name = "Auth")] string Auth, SetVentaDto dto)
{
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 15);
if (validacion1 == false)
{
return Unauthorized();
}
@@ -154,9 +151,11 @@ public class VentaController:ControllerBase {
}
[HttpPost("/api/ventas/ejercerOpcionVenta")]
public IActionResult EjercerOpcionVenta([FromHeader(Name="Auth")]string Auth, [FromQuery]long idcontrato=0) {
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Inquilino");
if (validacion1 == false) {
public IActionResult EjercerOpcionVenta([FromHeader(Name = "Auth")] string Auth, [FromQuery] long idcontrato = 0)
{
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 11);
if (validacion1 == false)
{
return Unauthorized();
}
if (idcontrato <= 0) return BadRequest(new { message = "No pueden hacer cotratos con id 0 o menor" });
@@ -183,15 +182,14 @@ public class VentaController:ControllerBase {
}
[HttpPost("/api/ventas/subirReciboPago")]
public async Task<IActionResult> SubirRecibo([FromHeader(Name="Auth")]string Auth, IFormFile file, long idventa ) {
public async Task<IActionResult> SubirRecibo([FromHeader(Name = "Auth")] string Auth, IFormFile file, long idventa)
{
if (String.IsNullOrWhiteSpace(Auth)) return Unauthorized();
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Propietario");
if (validacion1 == false){
validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Inquilino");
if (validacion1 == false) {
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 13);
if (validacion1 == false)
{
return Unauthorized();
}
}
if (idventa <= 0) return BadRequest(new { message = "Las id 0 o menor no son validas" });
@@ -218,9 +216,11 @@ public class VentaController:ControllerBase {
}
private readonly IMinioClient mc;
public VentaController(IMinioClient minioClient) {
public VentaController(IMinioClient minioClient)
{
mc = minioClient;
if (mc == null){
if (mc == null)
{
MinioConfigcus? mcon = JsonSerializer.Deserialize<MinioConfigcus>(System.IO.File.ReadAllText("./settings.json")) ?? null;
if (mcon == null) throw new Exception();
@@ -230,16 +230,20 @@ public class VentaController:ControllerBase {
.Build();
}
}
private async Task<bool> subirContrato(IFormFile f, string flname) {
try {
private async Task<bool> subirContrato(IFormFile f, string flname)
{
try
{
var buck = new BucketExistsArgs().WithBucket("alquilafacil");
bool encontrado = await mc.BucketExistsAsync(buck).ConfigureAwait(false);
if(!encontrado){
if (!encontrado)
{
var mb = new MakeBucketArgs().WithBucket("alquilafacil");
await mc.MakeBucketAsync(mb).ConfigureAwait(false);
}
using (var stream = new MemoryStream()){
using (var stream = new MemoryStream())
{
await f.CopyToAsync(stream);
stream.Position = 0;
PutObjectArgs putbj = new PutObjectArgs()
@@ -251,21 +255,22 @@ public class VentaController:ControllerBase {
await mc.PutObjectAsync(putbj);
}
return true;
} catch (Exception e ) {
}
catch (Exception e)
{
Console.Error.WriteLine(e.Message);
return false;
}
}
[HttpGet("/api/ventas/verRecibo")]
public IActionResult verRecibo([FromHeader(Name="Auth")]string Auth, long idventa=0){
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Propietario");
if (validacion1 == false){
validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Inquilino");
if (validacion1 == false) {
public IActionResult verRecibo([FromHeader(Name = "Auth")] string Auth, long idventa = 0)
{
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 13);
if (validacion1 == false)
{
return Unauthorized();
}
}
if (idventa <= 0) return BadRequest(new { message = "No existen ventas validas para la id 0" });
Cliente? cli = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);
@@ -275,13 +280,15 @@ public class VentaController:ControllerBase {
if (venta == null) return BadRequest(new { message = "no hay una venta con esa id" });
if (cli.Dni != venta.IdComprador && cli.Dni != venta.IdVendedor) return Unauthorized();
try{
try
{
var memstream = new MemoryStream();
var goa = new GetObjectArgs()
.WithBucket("alquilafacil")
.WithObject(venta.UrlRecibo)
.WithCallbackStream(stream => {
.WithCallbackStream(stream =>
{
memstream.Position = 0;
stream.CopyTo(memstream);
});
@@ -293,7 +300,9 @@ public class VentaController:ControllerBase {
return File(memstream, "application/pdf", venta.UrlRecibo);
} catch (Exception e){
}
catch (Exception e)
{
Console.Error.WriteLine(e);
return BadRequest(new { message = "Fallo al intentar obtener el archivo del almacenamiento o este no existe" });
}
@@ -301,14 +310,13 @@ public class VentaController:ControllerBase {
[HttpPost("/api/ventas/propietarioverifica")]
public IActionResult PropietarioVerifica([FromHeader(Name="Auth")]string Auth, long idventa=0) {
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Propietario");
if (validacion1 == false){
validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Inquilino");
if (validacion1 == false) {
public IActionResult PropietarioVerifica([FromHeader(Name = "Auth")] string Auth, long idventa = 0)
{
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 13);
if (validacion1 == false)
{
return Unauthorized();
}
}
if (idventa <= 0) return BadRequest(new { message = "No existen ventas validas para la id 0" });
Cliente? cli = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);
@@ -324,14 +332,10 @@ public class VentaController:ControllerBase {
[HttpGet("/api/venta")]
public IActionResult ObtenerVenta([FromHeader(Name="Auth")]string Auth, long idventa=0) {
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Propietario");
if (validacion1 == false){
validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Inquilino");
if (validacion1 == false) {
return Unauthorized();
}
}
public IActionResult ObtenerVenta([FromHeader(Name = "Auth")] string Auth, long idventa = 0)
{
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 13);
if (idventa <= 0) return BadRequest(new { message = "No existen ventas validas para la id 0" });
Cliente? cli = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);
@@ -353,19 +357,18 @@ public class VentaController:ControllerBase {
.SetEstado(ventas.IdestadoNavigation.Descripcion ?? "")
.Build();
return Ok(new { data = v, iscomprador = (ventas.IdComprador==cli.Dni)?true:false,
necesitaRecibo = ventas.UrlRecibo==null?true:false});
return Ok(new
{
data = v,
iscomprador = (ventas.IdComprador == cli.Dni) ? true : false,
necesitaRecibo = ventas.UrlRecibo == null ? true : false
});
}
[HttpGet("/api/ventas")]
public IActionResult ObtenerVentas([FromHeader(Name="Auth")]string Auth) {
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Propietario");
if (validacion1 == false){
validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Inquilino");
if (validacion1 == false) {
return Unauthorized();
}
}
public IActionResult ObtenerVentas([FromHeader(Name = "Auth")] string Auth)
{
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 13);
Cliente? cli = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);
if (cli == null) return Unauthorized();
@@ -374,7 +377,8 @@ public class VentaController:ControllerBase {
if (ventas == null) return BadRequest(new { message = "no estas involucrado en ninguna venta o compra" });
List<VentasDto> lista = new();
foreach (var i in ventas) {
foreach (var i in ventas)
{
var v = new VentasDtoBuilder()
.SetId(i.Id)
.SetMonto(i.Monto)
@@ -392,11 +396,14 @@ public class VentaController:ControllerBase {
}
[HttpGet("/api/opcionventa")]
public IActionResult ObtenerDto([FromHeader(Name="Auth")]string Auth, long idcontrato=0) {
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Propietario");
if (validacion1 == false){
validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Inquilino");
if (validacion1 == false) {
public IActionResult ObtenerDto([FromHeader(Name = "Auth")] string Auth, long idcontrato = 0)
{
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 11);
if (validacion1 == false)
{
validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 12);
if (validacion1 == false)
{
return Unauthorized();
}
}
@@ -419,16 +426,21 @@ public class VentaController:ControllerBase {
return Ok(dto);
}
private bool puedeEjercer(Contrato c) {
private bool puedeEjercer(Contrato c)
{
bool ret = c.Idcanons.All(x => x.Pagado == 1);
if (ret) {
if (ret)
{
var canonConFechaMasTardia = c.Idcanons.OrderByDescending(x => x.Fecha).FirstOrDefault();
if (canonConFechaMasTardia != null && canonConFechaMasTardia.Fecha.Year >= DateTime.Now.Year
&& canonConFechaMasTardia.Fecha.Month >= DateTime.Now.Month) {
&& canonConFechaMasTardia.Fecha.Month >= DateTime.Now.Month)
{
ret = true;
}else{
}
else
{
ret = false;
}
}
@@ -437,11 +449,14 @@ public class VentaController:ControllerBase {
}
[HttpGet("/api/contrato/tieneopcionventa")]
public IActionResult TieneOpcionVenta([FromHeader(Name="Auth")]string Auth, long idcontrato=0) {
var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Propietario");
if (validacion1 == false){
validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Inquilino");
if (validacion1 == false) {
public IActionResult TieneOpcionVenta([FromHeader(Name = "Auth")] string Auth, long idcontrato = 0)
{
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 11);
if (validacion1 == false)
{
validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 12);
if (validacion1 == false)
{
return Unauthorized();
}
}

View File

@@ -0,0 +1,38 @@
using System.Net.Mail;
namespace AlquilaFacil.Emailer.Builder;
public class EmailBuilder
{
private MailMessage _message = new();
public EmailBuilder To(string to)
{
_message.To.Add(to);
return this;
}
public EmailBuilder Subject(string subject)
{
_message.Subject = subject;
return this;
}
public EmailBuilder Body(string email, string pin, string modo = "2fa")
{
_message.IsBodyHtml = true;
switch (modo)
{
case "2fa":
_message.Body = new HtmlGenerator().GenerarMail2fa(email, pin);
break;
case "aviso":
_message.Body = new HtmlGenerator().AvisoSetEmail(email, pin);
break;
default:
break;
}
return this;
}
public MailMessage Build() => _message;
}

View File

@@ -0,0 +1,112 @@
namespace AlquilaFacil.Emailer.Builder;
public class HtmlGenerator
{
public string GenerarMail2fa(string emailUsuario, string pin)
{
var msg = $"""
<!doctype html>
<html>
<body>
<div
style='background-color:#000000;color:#FFFFFF;font-family:"Iowan Old Style", "Palatino Linotype", "URW Palladio L", P052, serif;font-size:16px;font-weight:400;letter-spacing:0.15008px;line-height:1.5;margin:0;padding:32px 0;min-height:100%;width:100%'
>
<table
align="center"
width="100%"
style="margin:0 auto;max-width:600px;background-color:#000000"
role="presentation"
cellspacing="0"
cellpadding="0"
border="0"
>
<tbody>
<tr style="width:100%">
<td>
<div
style="color:#ffffff;font-size:16px;font-weight:normal;text-align:center;padding:16px 24px 16px 24px"
>
Aqui esta su codigo OTP:
</div>
<h1
style='font-weight:bold;text-align:center;margin:0;font-family:"Nimbus Mono PS", "Courier New", "Cutive Mono", monospace;font-size:32px;padding:16px 24px 16px 24px'
>
{pin}
</h1>
<div
style="color:#868686;font-size:16px;font-weight:normal;text-align:center;padding:16px 24px 16px 24px"
>
Este codigo es del usuario con email:{emailUsuario}
</div>
<div
style="color:#868686;font-size:14px;font-weight:normal;text-align:center;padding:16px 24px 16px 24px"
>
Si no sabes para que es el email, ignoralo.
</div>
</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
""";
return msg;
}
public string AvisoSetEmail(string emailUsuario, string emailreq)
{
var msg = $"""
<!doctype html>
<html>
<body>
<div
style='background-color:#000000;color:#FFFFFF;font-family:"Iowan Old Style", "Palatino Linotype", "URW Palladio L", P052, serif;font-size:16px;font-weight:400;letter-spacing:0.15008px;line-height:1.5;margin:0;padding:32px 0;min-height:100%;width:100%'
>
<table
align="center"
width="100%"
style="margin:0 auto;max-width:600px;background-color:#000000"
role="presentation"
cellspacing="0"
cellpadding="0"
border="0"
>
<tbody>
<tr style="width:100%">
<td>
<div
style="color:#ffffff;font-size:16px;font-weight:normal;text-align:center;padding:16px 24px 16px 24px"
>
Aviso:
</div>
<h1
style='font-weight:bold;text-align:center;margin:0;font-family:"Nimbus Mono PS", "Courier New", "Cutive Mono", monospace;font-size:32px;padding:16px 24px 16px 24px'
>
Se seteo este email : {emailreq}, como email de respaldo
</h1>
<div
style="color:#868686;font-size:16px;font-weight:normal;text-align:center;padding:16px 24px 16px 24px"
>
</div>
<div
style="color:#868686;font-size:14px;font-weight:normal;text-align:center;padding:16px 24px 16px 24px"
>
Si no sabes para que es el email, ignoralo.
</div>
</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
""";
return msg;
}
}

View File

@@ -0,0 +1,11 @@
namespace AlquilaFacil.Emailer.Sender;
using AlquilaFacil.Emailer.Builder;
public class AvisoEmailSender : EmailSender
{
public void Send(string emailusu, string emailreq)
{
var mail = new EmailBuilder().Body(emailusu, emailreq, "aviso").To(emailreq).Subject("AvisoEmail").Build();
base.Send(mail);
}
}

View File

@@ -0,0 +1,50 @@
using System.Net.Mail;
using System.Net;
using System.Text.Json;
namespace AlquilaFacil.Emailer.Sender;
public class EmailSender
{
protected static SmtpClient? smtp = null;
protected void configSmtp(MailMessage mail)
{
var jsonContent = File.ReadAllText("settings.json");
var options = JsonSerializer.Deserialize<Dictionary<string, string>>(jsonContent);
if (options == null) return;
bool check = options.ContainsKey("smtpHost");
check = options.ContainsKey("smtpPort");
check = options.ContainsKey("emailAddr");
check = options.ContainsKey("emailPass");
if (check == false) return;
mail.Sender = new MailAddress(options["emailAddr"]);
mail.From = new MailAddress(options["emailAddr"]);
if (null != smtp) return;
smtp = new();
smtp.DeliveryMethod = SmtpDeliveryMethod.Network;
smtp.EnableSsl = true;
smtp.Host = options["smtpHost"];
smtp.Port = int.Parse(options["smtpPort"].ToString());
smtp.Credentials = new NetworkCredential(options["emailAddr"], options["emailPass"]);
}
public virtual void Send(MailMessage message)
{
configSmtp(message);
if (smtp == null) return;
try
{
smtp.Send(message);
message.Dispose();
}
catch (Exception)
{
throw;
}
}
}

View File

@@ -0,0 +1,13 @@
namespace AlquilaFacil.Emailer.Sender;
using AlquilaFacil.Emailer.Builder;
public class OtpEmailSender : EmailSender
{
public void Send(string To, string email, string pin)
{
var mail = new EmailBuilder().To(To).Body(email, pin).Subject("Mail de Recuperacion").Build();
base.Send(mail);
}
}

View File

@@ -35,6 +35,15 @@ builder.Services.AddCors(options =>
.AllowAnyMethod()
.AllowCredentials();
});
options.AddPolicy("AllowSvelteAppv6",
builder =>
{
builder.WithOrigins("http://[::1]:5173")
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials();
});
});
var app = builder.Build();

View File

@@ -1,4 +1,9 @@
{
"usr": "nwFNMLJcn5m0owbzeXMs",
"scrt":"Mf9HxTir5mIGwWSBtQXd6DRK2k00V0EyXk7QTu70"
"scrt": "Mf9HxTir5mIGwWSBtQXd6DRK2k00V0EyXk7QTu70",
"connectiondb": "Server=127.0.0.1;Port=3306;Database=AlquilaFacil;Uid=AlquilaFacil;Pwd=.n@9c2ve*0,b1ETv].Kipa/~pR~V;Connection Timeout=5;SslMode=none",
"smtpHost": "smtp.gmail.com",
"smtpPort": "587",
"emailAddr": "emailerpasillo@gmail.com",
"emailPass": "hgwa mznx xuff exws"
}

View File

@@ -1,4 +1,9 @@
{
"usr": "nwFNMLJcn5m0owbzeXMs",
"scrt":"Mf9HxTir5mIGwWSBtQXd6DRK2k00V0EyXk7QTu70"
"scrt": "Mf9HxTir5mIGwWSBtQXd6DRK2k00V0EyXk7QTu70",
"connectiondb": "Server=127.0.0.1;Port=3306;Database=AlquilaFacil;Uid=AlquilaFacil;Pwd=.n@9c2ve*0,b1ETv].Kipa/~pR~V;Connection Timeout=5;SslMode=none",
"smtpHost": "smtp.gmail.com",
"smtpPort": "587",
"emailAddr": "emailerpasillo@gmail.com",
"emailPass": "hgwa mznx xuff exws"
}

View File

@@ -1,5 +1,7 @@
using System;
using System;
using System.Collections.Generic;
using System.Text.Json;
using Microsoft.EntityFrameworkCore;
namespace Entidades;
@@ -54,9 +56,29 @@ public partial class AlquilaFacilContext : DbContext
public virtual DbSet<Venta> Ventas { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
#warning To protect potentially sensitive information in your connection string, you should move it out of source code. You can avoid scaffolding the connection string by using the Name= syntax to read it from configuration - see https://go.microsoft.com/fwlink/?linkid=2131148. For more guidance on storing connection strings, see https://go.microsoft.com/fwlink/?LinkId=723263.
=> optionsBuilder.UseMySQL("Server=127.0.0.1;Port=3306;Database=AlquilaFacil;Uid=AlquilaFacil;Pwd=.n@9c2ve*0,b1ETv].Kipa/~pR~V;Connection Timeout=5;SslMode=none");
{
if (!optionsBuilder.IsConfigured)
{
try
{
var jsonContent = File.ReadAllText("settings.json");
var options = JsonSerializer.Deserialize<Dictionary<string, string>>(jsonContent);
if (options != null && options.ContainsKey("connectiondb"))
{
optionsBuilder.UseMySQL(options["connectiondb"]);
}
else
{
throw new Exception("No se encontró la clave 'connectiondb' en el archivo settings.json");
}
}
catch (Exception ex)
{
Console.WriteLine($"Error al configurar la conexión a la base de datos: {ex.Message}");
throw;
}
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Canon>(entity =>
@@ -111,6 +133,12 @@ public partial class AlquilaFacilContext : DbContext
entity.Property(e => e.Email)
.HasMaxLength(50)
.HasColumnName("email");
entity.Property(e => e.EmailRecuperacion)
.HasMaxLength(50)
.HasColumnName("emailRecuperacion");
entity.Property(e => e.F2a)
.HasMaxLength(6)
.HasColumnName("f2a");
entity.Property(e => e.Habilitado)
.HasDefaultValueSql("b'1'")
.HasColumnType("bit(1)")
@@ -416,9 +444,49 @@ public partial class AlquilaFacilContext : DbContext
entity.Property(e => e.Id)
.HasColumnType("int(11)")
.HasColumnName("id");
entity.Property(e => e.Habilitado)
.IsRequired()
.HasDefaultValueSql("'1'")
.HasColumnName("habilitado");
entity.Property(e => e.Nombre)
.HasMaxLength(12)
.HasColumnName("nombre");
entity.HasMany(d => d.IdGrupoHijos).WithMany(p => p.IdGrupoPadres)
.UsingEntity<Dictionary<string, object>>(
"GrupoSubgrupo",
r => r.HasOne<Grupo>().WithMany()
.HasForeignKey("IdGrupoHijo")
.HasConstraintName("Grupo_Subgrupo_ibfk_2"),
l => l.HasOne<Grupo>().WithMany()
.HasForeignKey("IdGrupoPadre")
.HasConstraintName("Grupo_Subgrupo_ibfk_1"),
j =>
{
j.HasKey("IdGrupoPadre", "IdGrupoHijo").HasName("PRIMARY");
j.ToTable("Grupo_Subgrupo");
j.HasIndex(new[] { "IdGrupoHijo" }, "IdGrupoHijo");
j.IndexerProperty<int>("IdGrupoPadre").HasColumnType("int(11)");
j.IndexerProperty<int>("IdGrupoHijo").HasColumnType("int(11)");
});
entity.HasMany(d => d.IdGrupoPadres).WithMany(p => p.IdGrupoHijos)
.UsingEntity<Dictionary<string, object>>(
"GrupoSubgrupo",
r => r.HasOne<Grupo>().WithMany()
.HasForeignKey("IdGrupoPadre")
.HasConstraintName("Grupo_Subgrupo_ibfk_1"),
l => l.HasOne<Grupo>().WithMany()
.HasForeignKey("IdGrupoHijo")
.HasConstraintName("Grupo_Subgrupo_ibfk_2"),
j =>
{
j.HasKey("IdGrupoPadre", "IdGrupoHijo").HasName("PRIMARY");
j.ToTable("Grupo_Subgrupo");
j.HasIndex(new[] { "IdGrupoHijo" }, "IdGrupoHijo");
j.IndexerProperty<int>("IdGrupoPadre").HasColumnType("int(11)");
j.IndexerProperty<int>("IdGrupoHijo").HasColumnType("int(11)");
});
});
modelBuilder.Entity<Log>(entity =>

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
namespace Entidades;
@@ -23,6 +23,11 @@ public partial class Cliente
public ulong Habilitado { get; set; }
public string? EmailRecuperacion { get; set; }
public string? F2a { get; set; }
public virtual ICollection<Contrato> ContratoDniinquilinoNavigations { get; set; } = new List<Contrato>();
public virtual ICollection<Contrato> ContratoDnipropietarioNavigations { get; set; } = new List<Contrato>();

View File

@@ -0,0 +1,5 @@
namespace Entidades.Dto;
public class CrearAccionesDto
{
public string Descripcion { get; set; } = "";
}

View File

@@ -0,0 +1,16 @@
namespace Entidades.Dto;
public class GrupoDto
{
public int idgrupo { get; set; }
public string Nombre { get; set; } = "";
public bool Habilitado { get; set; } = false;
public HashSet<string> GruposIncluidos { get; set; } = [];
public List<PermisoDto> Permisos { get; set; } = [];
}
public class PermisoDto
{
public int Id { get; set; }
public string Descripcion { get; set; } = "";
}

View File

@@ -0,0 +1,7 @@
public class PreContratoDataDto{
public bool TieneOpcionDeVenta { get; set; }
public decimal? MontoOpcionDeVenta { get; set; }
public string? MonedaOpcionDeVenta { get; set; }
public int DuracionEnMeses { get; set; }
public int? FrecuenciaAumentoEnMeses { get; set; }
}

View File

@@ -0,0 +1,6 @@
namespace Entidades.Dto;
public class PropietarioDto{
public string Nombre {get; set;} = "";
public long Dni {get; set;}
public string Apellido {get; set;} = "";
}

View File

@@ -0,0 +1,12 @@
namespace Entidades.Dto;
public class UsuarioDto
{
public long Dni { get; set; }
public string Nombre { get; set; } = null!;
public string Apellido { get; set; } = null!;
public string Domicilio { get; set; } = null!;
public string Celular { get; set; } = null!;
public string Email { get; set; } = null!;
public string? EmailRecuperacion { get; set; } = null!;
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
namespace Entidades;

View File

@@ -1,17 +1,42 @@
using System;
using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace Entidades;
public partial class Grupo
public partial class Grupo : IComponenteSeguridad
{
public int Id { get; set; }
public string Nombre { get; set; } = null!;
public bool? Habilitado { get; set; }
[JsonIgnore]
public virtual ICollection<Grupo> IdGrupoHijos { get; set; } = new List<Grupo>();
[JsonIgnore]
public virtual ICollection<Grupo> IdGrupoPadres { get; set; } = new List<Grupo>();
[JsonIgnore]
public virtual ICollection<Cliente> Idclientes { get; set; } = new List<Cliente>();
public virtual ICollection<Permiso> Idpermisos { get; set; } = new List<Permiso>();
public void ObtenerPermisos(HashSet<Permiso> permisos, HashSet<int> visitados)
{
if (visitados.Contains(Id)) return;
visitados.Add(Id);
if (this.Habilitado == false) return;
var componentes = new List<IComponenteSeguridad>();
componentes.AddRange(Idpermisos);
componentes.AddRange(IdGrupoHijos);
foreach (var componente in componentes)
{
componente.ObtenerPermisos(permisos, visitados);
}
}
}

View File

@@ -0,0 +1,9 @@
namespace Entidades.Informes;
public class InformePagos
{
public int Mes { get; set; }
public int Realizados { get; set; }
public int Atrasados {get;set;}
public int Sin_realizar {get;set;}
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
namespace Entidades;

View File

@@ -4,7 +4,7 @@ using System.Text.Json.Serialization;
namespace Entidades;
public partial class Permiso
public partial class Permiso:IComponenteSeguridad
{
public int Id { get; set; }
@@ -12,4 +12,9 @@ public partial class Permiso
[JsonIgnore]
public virtual ICollection<Grupo> Idgrupos { get; set; } = new List<Grupo>();
public void ObtenerPermisos(HashSet<Permiso> permisos, HashSet<int> visitados)
{
permisos.Add(this);
}
}

View File

@@ -0,0 +1,5 @@
namespace Entidades;
public interface IComponenteSeguridad {
public void ObtenerPermisos(HashSet<Permiso> permisos, HashSet<int> visitados);
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
namespace Entidades;

View File

@@ -4,3 +4,7 @@ run:
clean:
rm *.cs
table:
dotnet ef dbcontext scaffold "Server=127.0.0.1;Port=3306;Database=AlquilaFacil;Uid=AlquilaFacil;Pwd=.n@9c2ve*0,b1ETv].Kipa/~pR~V;Connection Timeout=5;SslMode=none" MySql.EntityFrameworkCore -o ./tmp
./convert_to_pascalcase.sh

Binary file not shown.

View File

@@ -9,6 +9,7 @@
"version": "0.0.0",
"dependencies": {
"@sveltestrap/sveltestrap": "^6.2.8",
"bootstrap": "^5.3.3",
"chartjs": "^0.3.24",
"svelte-routing": "^2.13.0"
},
@@ -206,6 +207,25 @@
"node": ">= 0.4"
}
},
"node_modules/bootstrap": {
"version": "5.3.3",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz",
"integrity": "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/twbs"
},
{
"type": "opencollective",
"url": "https://opencollective.com/bootstrap"
}
],
"license": "MIT",
"peerDependencies": {
"@popperjs/core": "^2.11.8"
}
},
"node_modules/chartjs": {
"version": "0.3.24",
"license": "MIT"

View File

@@ -22,6 +22,7 @@
},
"dependencies": {
"@sveltestrap/sveltestrap": "^6.2.8",
"bootstrap": "^5.3.3",
"chartjs": "^0.3.24",
"svelte-routing": "^2.13.0"
}

21
Front/public/edit.svg Normal file
View File

@@ -0,0 +1,21 @@
<!--
category: Design
tags: [pencil, change, update]
version: "1.0"
unicode: "ea98"
-->
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M7 7h-1a2 2 0 0 0 -2 2v9a2 2 0 0 0 2 2h9a2 2 0 0 0 2 -2v-1" />
<path d="M20.385 6.585a2.1 2.1 0 0 0 -2.97 -2.97l-8.415 8.385v3h3l8.385 -8.415z" />
<path d="M16 5l3 3" />
</svg>

After

Width:  |  Height:  |  Size: 481 B

19
Front/public/key.svg Normal file
View File

@@ -0,0 +1,19 @@
<!--
tags: [password, login, authentication, secure]
version: "1.0"
unicode: "eac7"
-->
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M16.555 3.843l3.602 3.602a2.877 2.877 0 0 1 0 4.069l-2.643 2.643a2.877 2.877 0 0 1 -4.069 0l-.301 -.301l-6.558 6.558a2 2 0 0 1 -1.239 .578l-.175 .008h-1.172a1 1 0 0 1 -.993 -.883l-.007 -.117v-1.172a2 2 0 0 1 .467 -1.284l.119 -.13l.414 -.414h2v-2h2v-2l2.144 -2.144l-.301 -.301a2.877 2.877 0 0 1 0 -4.069l2.643 -2.643a2.877 2.877 0 0 1 4.069 0z" />
<path d="M15 9h.01" />
</svg>

After

Width:  |  Height:  |  Size: 679 B

21
Front/public/logout.svg Normal file
View File

@@ -0,0 +1,21 @@
<!--
category: System
tags: [exit, shut, unplug, close]
version: "1.4"
unicode: "eba8"
-->
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M14 8v-2a2 2 0 0 0 -2 -2h-7a2 2 0 0 0 -2 2v12a2 2 0 0 0 2 2h7a2 2 0 0 0 2 -2v-2" />
<path d="M9 12h12l-3 -3" />
<path d="M18 15l3 -3" />
</svg>

After

Width:  |  Height:  |  Size: 451 B

20
Front/public/plus.svg Normal file
View File

@@ -0,0 +1,20 @@
<!--
category: Math
tags: [add, create, new, "+"]
version: "1.0"
unicode: "eb0b"
-->
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M12 5l0 14" />
<path d="M5 12l14 0" />
</svg>

After

Width:  |  Height:  |  Size: 345 B

1
Front/public/user.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-user"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M8 7a4 4 0 1 0 8 0a4 4 0 0 0 -8 0" /><path d="M6 21v-2a4 4 0 0 1 4 -4h4a4 4 0 0 1 4 4v2" /></svg>

After

Width:  |  Height:  |  Size: 411 B

View File

@@ -1,9 +1,10 @@
<script lang="ts">
import "bootstrap/dist/css/bootstrap.min.css";
import Login from "./paginas/login.svelte";
import { Router, Route, link } from 'svelte-routing';
import MenuPage from './paginas/menu.svelte';
import ProteRoute from './Componentes/RutaProtegida.svelte';
import InfoPage from './paginas/info.svelte';
import { Router, Route, link } from "svelte-routing";
import MenuPage from "./paginas/menu.svelte";
import ProteRoute from "./Componentes/RutaProtegida.svelte";
import InfoPage from "./paginas/info.svelte";
import InqPage from "./paginas/inquilino.svelte";
import PropPage from "./paginas/propietario.svelte";
import MisPropiedades from "./paginas/MisPropiedades.svelte";
@@ -29,6 +30,12 @@
import ContratoAdmin from "./paginas/ContratoAdmin.svelte";
import BuscarVentas from "./paginas/BuscarVentas.svelte";
import MisPropiedadesEnVenta from "./paginas/MisPropiedadesEnVenta.svelte";
import AdminGrupos from "./paginas/AdminGrupos.svelte";
import OtroG from "./paginas/grupos/OtroG.svelte";
import GestionPemisos from "./paginas/GestionPemisos.svelte";
import UsuarioPanel from "./paginas/UsuarioPanel.svelte";
import CrearUsuario from "./paginas/CrearUsuario.svelte";
import CargarContratoAdmin from "./paginas/CargarContratoAdmin.svelte";
</script>
<Router>
@@ -41,7 +48,6 @@
<Route path="/" component={Login} />
<Route path="/Info" component={InfoPage} />
<Route path="/Menu">
<ProteRoute componente={MenuPage} />
</Route>
@@ -72,7 +78,7 @@
<ProteRoute componente={PropPage} />
</Route>
<!--Crear Cuenta Propietario-->
<!--Informes-->
<Route path="/accion/6">
<ProteRoute componente={Informes} />
</Route>
@@ -127,6 +133,26 @@
<ProteRoute componente={BuscarVentas} />
</Route>
<!-- Creacion Permisos -->
<Route path="/accion/17">
<ProteRoute componente={GestionPemisos} />
</Route>
<!-- Gestion Grupos -->
<Route path="/accion/18">
<ProteRoute componente={AdminGrupos} />
</Route>
<!-- Crear Usuario -->
<Route path="/accion/19">
<ProteRoute componente={CrearUsuario} />
</Route>
<!-- Cargar Contrato Admin -->
<Route path="/accion/20">
<ProteRoute componente={CargarContratoAdmin}/>
</Route>
<!-- Pagina Ventas -->
<Route path="/Ventas">
<ProteRoute componente={Ventas} />
@@ -145,12 +171,19 @@
<Route path="/grupo/Informes">
<ProteRoute componente={FrontInformes} />
</Route>
<Route path="/grupo/:id" let:params>
<ProteRoute componente={{ OtroG, params }} />
</Route>
<!--Notificaciones-->
<Route path="/notificaciones">
<ProteRoute componente={Notificaciones} />
</Route>
<Route path="/usuario">
<ProteRoute componente={UsuarioPanel} />
</Route>
<!--Contratos Propietarios-->
<Route path="/propietario/contratos">
<ProteRoute componente={ContratosPropietario} />
@@ -166,4 +199,3 @@
<ProteRoute componente={ContratoAdmin} />
</Route>
</Router>

View File

@@ -0,0 +1,41 @@
<script>
import { onMount } from "svelte";
let isHovered = $state(false);
let { handleclick } = $props();
function handleMouseEnter() {
isHovered = true;
}
function handleMouseLeave() {
isHovered = false;
}
</script>
<button
class="position-fixed bottom-0 end-0 m-3 p-3 bg-secondary rounded-circle transition-element border"
class:rotated={isHovered}
class:active={isHovered}
style="width: 5rem; height: 5rem;"
onmouseenter={handleMouseEnter}
onmouseleave={handleMouseLeave}
onclick={handleclick}
>
<img
src="/plus.svg"
alt="añadir"
style="width: 2.5rem; height: 2.5rem; filter: invert(1);"
/>
</button>
<style>
.transition-element {
transition: transform 0.3s ease-in-out;
}
.rotated {
transform: rotate(90deg);
}
</style>

View File

@@ -1,13 +1,12 @@
<script>
import { onDestroy, onMount } from 'svelte';
import Chart from 'chart.js/auto';
import { onDestroy, onMount } from "svelte";
import { Chart } from "chart.js/auto";
let {chartData, typec='bar'} = $props();
let { chartData, typec = "bar" } = $props();
let chartContainer;
let instance;
onDestroy(() => {
if (instance) {
instance.destroy();
@@ -19,22 +18,22 @@
instance.destroy();
}
const ctx = chartContainer.getContext('2d');
const ctx = chartContainer.getContext("2d");
instance = new Chart(ctx, {
type: typec,
data: {
labels: chartData.labels,
datasets: chartData.datasets.map(dataset => ({
datasets: chartData.datasets.map((dataset) => ({
label: dataset.label,
data: dataset.data.map(x => String(x)),
borderWidth: dataset.borderWidth
}))
data: dataset.data.map((x) => String(x)),
borderWidth: dataset.borderWidth,
})),
},
options: {
responsive: true,
plugins: {
legend: {
position: 'top',
position: "top",
},
},
scales: {
@@ -50,10 +49,8 @@
};
onMount(createChart);
$effect(createChart);
</script>
<div class="card card-body">
<canvas bind:this={chartContainer}></canvas>
</div>

View File

@@ -1,11 +1,23 @@
<script>
import { CardHeader, CardTitle, Button, Card, Input, Form, CardBody, FormGroup } from '@sveltestrap/sveltestrap';
import { navigate } from 'svelte-routing';
import {
CardHeader,
CardTitle,
Button,
Card,
Input,
Form,
CardBody,
FormGroup,
Modal,
} from "@sveltestrap/sveltestrap";
import { navigate } from "svelte-routing";
import { urlG } from "../stores/urlStore";
import ModalEstatico from "./ModalEstatico.svelte";
import { parse } from "svelte/compiler";
let email = $state("")
let contraseña = $state("")
let errorMessage = $state("")
let email = $state("");
let contraseña = $state("");
let errorMessage = $state("");
// @ts-ignore
async function submitForm(event) {
@@ -14,53 +26,258 @@
const data = { email, contraseña };
try {
const response = await fetch(String($urlG) + "/api/login", {
method: 'POST',
method: "POST",
headers: {
'Content-Type': 'application/json'
"Content-Type": "application/json",
},
body: JSON.stringify(data),
credentials: "include"
credentials: "include",
});
if (!response.ok) {
const errorData = await response.json()
const errorData = await response.json();
errorMessage = errorData.message;
return;
}
const ret = await response.json();
localStorage.setItem('email', ret.email);
sessionStorage.setItem('token', ret.token);
localStorage.setItem("email", ret.email);
sessionStorage.setItem("token", ret.token);
//setTimeout(() => console.log("50ms") ,50);
navigate(ret.redirect);
} catch (e) {
} catch (e) {}
}
let showrecuperarmodal = $state(false);
let modaldata = $state("");
let emailr = $state("");
let emailrecovery = $state("");
async function SubmitRecuperarContraseñaEmail(e) {
e.preventDefault();
if (emailrecovery == "") emailrecovery = emailr;
try {
const req = await fetch($urlG + "/api/recuperarUsuario", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
Email: emailr,
EmailRecuperacion: emailrecovery,
}),
});
const data = await req.json();
showrecuperarmodal = false;
if (req.ok) {
showf2amodal = true;
return;
}
//hago esto para que no puedan haber errores en caso de que intente recuperar 1 cuenta, aborte y intente recuperar una segunda
emailr = "";
emailrecovery = "";
//
modaldata = data.message;
} catch {
modaldata = "Fallo al hacer la request";
}
}
let showf2amodal = $state(false);
async function submitf2a(e) {
e.preventDefault();
const inputs = document.querySelectorAll(".otp-input");
let otppin = "";
inputs.forEach((x) => {
otppin += x.value.trim();
});
if (otppin.length != 6) {
modaldata = "la longitud del pin es incorrecta";
return;
}
if (emailr == "") {
modaldata = "Fallo vuelva a intentar";
return;
}
try {
const req = await fetch($urlG + "/api/ingresar2fa", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ Pin: otppin, Email: emailr }),
});
const data = await req.json();
if (req.ok) {
sessionStorage.setItem("token", data.token);
localStorage.setItem("email", emailr);
showf2amodal = false;
navigate("/usuario");
}
} catch {
modaldata = "Fallo al hacer la request";
}
}
function handleInput(index) {
const otpInputs = document.querySelectorAll(".otp-input");
console.log(otpInputs);
if (index === 5) return;
otpInputs[index+1].focus();
}
</script>
<Card class="position-sticky top-50 start-50 translate-middle-x border border-success" style="width: 20rem; height: auto;" theme="auto" outline>
{#if modaldata}
<ModalEstatico close={() => !!(modaldata = "")} payload={modaldata} />
{/if}
<Card
class="position-sticky top-50 start-50 translate-middle-x border border-success"
style="width: 20rem; height: auto;"
theme="auto"
outline
>
<CardHeader>
<CardTitle>Iniciar Sesión</CardTitle>
</CardHeader>
<CardBody>
<Form on:submit={submitForm}>
<Form onsubmit={(e) => submitForm(e)}>
<FormGroup floating label="Email">
<Input type="email" placeholder="ejemplo@mail.com" bind:value={email} required/>
<Input
type="email"
placeholder="ejemplo@mail.com"
bind:value={email}
required
/>
</FormGroup>
<FormGroup floating label="Contraseña">
<Input type="password" placeholder="*********" bind:value={contraseña} required/>
<Input
type="password"
placeholder="*********"
bind:value={contraseña}
required
/>
</FormGroup>
<FormGroup>
<Button color="primary" type="submit">Ingresar</Button>
</FormGroup>
</Form>
{#if errorMessage}
<div class='alert alert-warning alert-dismissible fade show' role='alert'>
<div
class="alert alert-warning alert-dismissible fade show"
role="alert"
>
<strong>{errorMessage}</strong>
<button type="button" class="btn-close close" aria-label="Close" data-bs-dismiss="alert"></button>
<button
type="button"
class="btn-close close"
aria-label="Close"
data-bs-dismiss="alert"
></button>
</div>
{/if}
<hr />
<button class="btn btn-link" onclick={() => {showrecuperarmodal = true; window.scrollTo(0,0);}}
>Recuperar Cuenta</button
>
</CardBody>
</Card>
{#if showf2amodal}
<div
class="modal"
tabindex="-1"
style="display: block; background-color: rgba(0, 0, 0, 0.3);"
>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Recuperar Cuenta</h5>
</div>
<form onsubmit={submitf2a}>
<div class="modal-body">
<div class="mb-3">
<label for="f2a" class="form-label">
Ingrese el codigo que tendria que haber llegado a su email
</label>
<div class="d-flex gap-2 justify-content-center">
{#each Array(6) as _, i}
<input
type="text"
class="form-control text-center otp-input"
maxlength="1"
inputmode="numeric"
pattern="[0-9]*"
style="width: 3rem;"
oninput={()=> handleInput(i)}
/>
{/each}
</div>
</div>
</div>
<div class="modal-footer d-flex">
<button type="submit" class="btn btn-primary">
Enviar
</button>
</div>
</form>
</div>
</div>
</div>
{/if}
{#if showrecuperarmodal}
<div
class="modal"
tabindex="-1"
style="display: block; background-color: rgba(0, 0, 0, 0.3);"
>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Recuperar Cuenta</h5>
<button
type="button"
class="btn-close"
aria-label="Close"
onclick={() => (showrecuperarmodal = false)}
></button>
</div>
<div class="modal-body">
<form onsubmit={SubmitRecuperarContraseñaEmail}>
<div class="mb-3">
<label for="Email" class="form-label">Email*</label>
<input
type="email"
class="form-control"
id="Email"
placeholder="Ingresa tu email"
required
bind:value={emailr}
/>
</div>
<div class="mb-3">
<label for="recoveryEmail" class="form-label"
>Email Recuperacion</label
>
<input
type="email"
class="form-control"
id="recoveryEmail"
placeholder="Ingresa tu email de recuperacion"
bind:value={emailrecovery}
/>
</div>
<div class="d-grid gap-2">
<button type="submit" class="btn btn-primary"
>Enviar</button
>
</div>
</form>
</div>
</div>
</div>
</div>
{/if}

View File

@@ -1,10 +1,11 @@
<script lang="ts">
import type { GaranteDto } from "../types";
import type { GaranteDto, PreContratoData } from "../types";
let { onClose, onSubmit, maxGarantes }: {
let { onClose, onSubmit, maxGarantes, datosprecontrato }: {
onClose: () => void,
onSubmit: (garantes: GaranteDto[]) => void,
maxGarantes: number
maxGarantes: number,
datosprecontrato: PreContratoData,
} = $props();
let cantGarantes: number = $state(0);
@@ -21,6 +22,7 @@
Domiciliolaboral: ""
});
function handleSubmit(e: Event) {
e.preventDefault();
onSubmit(garantes);
@@ -48,6 +50,7 @@
}
</script>
<div class="modal fade show" tabindex="-1" role="dialog" style="display: block; background-color: rgba(0, 0, 0, 0.5);">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
@@ -55,6 +58,43 @@
<h5 class="modal-title">Nuevo Alquiler - Garantes</h5>
<button class="btn-close" onclick={onClose} aria-label="Close"></button>
</div>
<div class="card">
<div class="card-body">
<h5>Detalles del Precontrato</h5>
<hr />
<!-- Opción de Venta -->
<div class="mb-3">
<p class="form-label"><strong>Opción de Venta:</strong></p>
<div>
{#if datosprecontrato.tieneOpcionDeVenta}
<span class="badge bg-success" id="tieneOpcionDeVenta"></span>
{:else}
<span class="badge bg-secondary" id="noTieneOpcionDeVenta">No</span>
{/if}
</div>
</div>
{#if datosprecontrato.tieneOpcionDeVenta}
<!-- Monto y Moneda de Opción de Venta (visible solo si hay opción) -->
<div class="mb-3" id="opcionVentaDetalles">
<p class="form-label"><strong>Monto de Opción de Venta:</strong></p>
<p class="form-control-plaintext" id="montoOpcionDeVenta">{datosprecontrato.montoOpcionDeVenta} {datosprecontrato.monedaOpcionDeVenta}</p>
</div>
{/if}
<!-- Duración del Contrato -->
<div class="mb-3">
<p class="form-label"><strong>Duración del Contrato:</strong></p>
<p class="form-control-plaintext" id="duracionEnMeses">{datosprecontrato.duracionEnMeses} Meses</p>
</div>
<!-- Frecuencia de Aumento -->
<div class="mb-3">
<p class="form-label"><strong>Frecuencia de Aumento:</strong></p>
<p class="form-control-plaintext" id="frecuenciaAumentoEnMeses">Cada {datosprecontrato.frecuenciaAumentoEnMeses} meses</p>
</div>
</div>
</div>
<form onsubmit={handleSubmit}>
<div class="modal-body">
<div class="mb-3">
@@ -74,39 +114,32 @@
<div class="form-group mt-3">
<h6>Añadir Garante</h6>
<div class="mb-2">
<label>DNI</label>
<input type="number" class="form-control" bind:value={newGarante.Dni} required />
<label for="dni">DNI</label>
<input type="number" class="form-control" bind:value={newGarante.Dni} name="dni" id="dni" required />
</div>
<div class="mb-2">
<label>Nombre</label>
<input type="text" class="form-control" bind:value={newGarante.Nombre} required />
<label for="nombre">Nombre</label>
<input type="text" class="form-control" bind:value={newGarante.Nombre} name="nombre" id="nombre" required />
</div>
<div class="mb-2">
<label>Apellido</label>
<input type="text" class="form-control" bind:value={newGarante.Apellido} required />
<label for="apellido">Apellido</label>
<input type="text" class="form-control" bind:value={newGarante.Apellido} name="apellido" id="apellido" required />
</div>
<div class="mb-2">
<label>Domicilio</label>
<input type="text" class="form-control" bind:value={newGarante.Domicilio} required />
<label for="domicilio">Domicilio</label>
<input type="text" class="form-control" bind:value={newGarante.Domicilio} name="domicilio" id="domicilio" required />
</div>
<div class="mb-2">
<label>Celular</label>
<input type="text" class="form-control" bind:value={newGarante.Celular} required />
<label for="celular">Celular</label>
<input type="text" class="form-control" bind:value={newGarante.Celular} name="celular" id="celular" required />
</div>
<div class="mb-2">
<label>Domicilio Laboral</label>
<input type="text" class="form-control" bind:value={newGarante.Domiciliolaboral} required />
<label for="domicilioLaboral">Domicilio Laboral</label>
<input type="text" class="form-control" bind:value={newGarante.Domiciliolaboral} name="domicilioLaboral" id="domicilioLaboral" required />
</div>
<div class="d-flex justify-content-between">
<button
class="btn btn-secondary"
type="button"
onclick={() => (showAddForm = false)}
>
Cancelar
</button>
<button class="btn btn-primary" type="button" onclick={addGarante}>
Confirmar
<button class="btn btn-success" type="button" onclick={addGarante}>
Añadir
</button>
</div>
</div>
@@ -115,7 +148,7 @@
<!-- Tabla de garantes -->
{#if cantGarantes > 0}
<div class="form-group mt-3">
<label>Lista de Garantes</label>
<p>Lista de Garantes</p>
<table class="table table-striped table-bordered">
<thead>
<tr>

View File

@@ -0,0 +1,137 @@
<script lang="ts">
import type { GrupoDto, PermisoDto } from "../types";
let {
onClose,
grupos,
permisos,
onSubmit,
}: {
onClose: () => void;
grupos: GrupoDto[];
permisos: PermisoDto[];
onSubmit: (a: GrupoDto) => void;
} = $props();
let data: GrupoDto = $state({
gruposIncluidos: [],
idgrupo: 0,
nombre: "",
permisos: [],
});
const handleSubmit = (e: Event) => {
e.preventDefault();
data.gruposIncluidos = grupos
.filter(
(grupo) =>
(
document.getElementById(
`grupo-${grupo.idgrupo}`,
) as HTMLInputElement
)?.checked,
)
.map((grupo) => grupo.nombre);
data.permisos = permisos.filter(
(permiso) =>
(
document.getElementById(
`permiso-${permiso.id}`,
) as HTMLInputElement
)?.checked,
);
onSubmit(data);
onClose();
};
let nombreGrupo = "";
</script>
<div
class="modal show d-block"
tabindex="-1"
role="dialog"
style="background: rgba(0, 0, 0, 0.5)"
aria-labelledby="exampleModalLabel"
aria-hidden="true"
>
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Añadir Grupo</h5>
<button
type="button"
class="btn-close"
aria-label="Close"
onclick={onClose}
></button>
</div>
<div class="modal-body">
<div class="mb-3">
<label for="nombre-grupo" class="form-label"
>Nombre del Grupo:</label
>
<input
type="text"
class="form-control"
id="nombre-grupo"
maxlength="12"
bind:value={data.nombre}
placeholder="Ingrese el nombre del grupo"
/>
<p class="fs-6 fw-light mt-1">
Cantidad de caracteres: {data.nombre.length} / 12
</p>
</div>
<div class="mb-3">
<h6>Incluir en Grupos:</h6>
{#each grupos as grupo}
<div class="form-check">
<input
type="checkbox"
class="form-check-input"
id={`grupo-${grupo.idgrupo}`}
checked={data.gruposIncluidos?.includes(
grupo.nombre,
)}
/>
<label
class="form-check-label"
for={`grupo-${grupo.idgrupo}`}
>
{grupo.nombre}
</label>
</div>
{/each}
</div>
<div>
<h6>Asignar Permisos:</h6>
{#each permisos as permiso}
<div class="form-check">
<input
type="checkbox"
class="form-check-input"
id={`permiso-${permiso.id}`}
checked={data.permisos?.some(
(p) => p.id === permiso.id,
)}
/>
<label
class="form-check-label"
for={`permiso-${permiso.id}`}
>
{permiso.descripcion}
</label>
</div>
{/each}
</div>
</div>
<div class="modal-footer d-flex justify-content-center">
<button class="btn btn-primary w-100" onclick={handleSubmit}
>Guardar Grupo</button
>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,110 @@
<script lang="ts">
import type { GrupoDto, PermisoDto } from "../types";
let {
onClose,
data = $bindable(),
grupos,
permisos,
onSubmit,
}: {
onClose: () => void;
data: GrupoDto;
grupos: GrupoDto[];
permisos: PermisoDto[];
onSubmit: (a: GrupoDto) => void;
} = $props();
const handleSubmit = (e: Event) => {
e.preventDefault();
data.gruposIncluidos = grupos
.filter(
(grupo) =>
document.getElementById(`grupo-${grupo.idgrupo}`)?.checked,
)
.map((grupo) => grupo.nombre);
data.permisos = permisos.filter(
(permiso) =>
document.getElementById(`permiso-${permiso.id}`)?.checked,
);
onSubmit(data);
onClose();
};
</script>
<div
class="modal show d-block"
tabindex="-1"
role="dialog"
style="background: rgba(0, 0, 0, 0.5)"
aria-labelledby="exampleModalLabel"
aria-hidden="true"
>
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">
Selecciona una opción
</h5>
<button
type="button"
class="btn-close"
aria-label="Close"
onclick={onClose}
></button>
</div>
<form onsubmit={(e) => handleSubmit(e)}>
<div class="modal-body">
<div class="mb-3">
<h6>Grupos:</h6>
{#each grupos as grupo}
<div class="form-check">
<input
type="checkbox"
class="form-check-input"
id={`grupo-${grupo.idgrupo}`}
checked={data.gruposIncluidos?.includes(
grupo.nombre,
)}
/>
<label
class="form-check-label"
for={`grupo-${grupo.idgrupo}`}
>
{grupo.nombre}
</label>
</div>
{/each}
</div>
<div>
<h6>Permisos:</h6>
{#each permisos as permiso}
<div class="form-check">
<input
type="checkbox"
class="form-check-input"
id={`permiso-${permiso.id}`}
checked={data.permisos?.some(
(p) => p.id === permiso.id,
)}
/>
<label
class="form-check-label"
for={`permiso-${permiso.id}`}
>
{permiso.descripcion}
</label>
</div>
{/each}
</div>
</div>
<div class="modal-footer d-flex justify-content-center">
<button class="btn btn-primary w-100" type="submit"
>Guardar</button
>
</div>
</form>
</div>
</div>
</div>

View File

@@ -0,0 +1,88 @@
<script lang="ts">
import { onMount } from "svelte";
import type { PermisoDto } from "../types";
let {
permiso = $bindable(),
onClose,
onSubmit,
modalTitle = "Modificar Permiso",
}: {
permiso: PermisoDto;
onClose: (a: string) => void;
onSubmit: (arg0: PermisoDto) => void;
modalTitle: string;
} = $props();
const maxChars = $state(25);
let remaining: number = $state(25);
const ogdesc: string = permiso.descripcion;
function saveChanges(e:Event) {
e.preventDefault();
onSubmit(permiso);
onClose(ogdesc);
}
function updateRemaining(event: Event) {
const inputValue = (event.target as HTMLInputElement).value;
permiso.descripcion = inputValue;
remaining = maxChars - inputValue.length;
}
$effect(() => {
remaining = maxChars - permiso.descripcion.length;
});
</script>
<div
class="modal show fade d-block"
tabindex="-1"
aria-labelledby="textModalLabel"
style="background-color: rgba(0, 0, 0, 0.3);"
>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="textModalLabel">{modalTitle}</h5>
<button
type="button"
class="btn-close"
aria-label="Close"
onclick={() => onClose(ogdesc)}
></button>
</div>
<form onsubmit={(e)=>saveChanges(e)}>
<div class="modal-body">
<div class="mb-3">
<label for="textInput" class="form-label">Descripcion</label
>
<input
type="text"
class="form-control"
id="textInput"
value={permiso.descripcion}
maxlength={maxChars}
oninput={updateRemaining}
/>
<small class="form-text text-muted">
{remaining} caracteres restantes de {maxChars}
</small>
</div>
</div>
<div class="modal-footer">
<button
type="button"
class="btn btn-secondary"
onclick={() => onClose(ogdesc)}>Cerrar</button
>
<button
type="submit"
class="btn btn-primary"
>Guardar</button
>
</div>
</form>
</div>
</div>
</div>

View File

@@ -51,8 +51,22 @@
<td style="word-wrap: break-word;">{d.fecha}</td>
<td style="word-wrap: break-word;">{d.nombreTabla}</td>
<td style="word-wrap: break-word;">{d.columna}</td>
<td style="word-wrap: break-word;">{d.valorAnterior}</td>
<td style="word-wrap: break-word;">{d.valorNuevo}</td>
<td style="word-wrap: break-word;">
{#if d.columna == "Contraseña"}
*
{:else}
{d.valorAnterior}
{/if}
</td>
<td style="word-wrap: break-word;">
{#if d.columna == "Contraseña"}
*
{:else}
{d.valorNuevo}
{/if}
</td>
</tr>
{/each}
</tbody>

View File

@@ -0,0 +1,57 @@
<script lang="ts">
let {
close,
submit,
}: { close: () => void; submit: (e: Event, pass: string) => void } =
$props();
let password: string = $state("");
function handleSubmit(e: Event) {
e.preventDefault();
submit(e, password);
}
</script>
<div
class="modal fade show d-block"
tabindex="-1"
style="background-color: rgba(0,0,0,0.5);"
>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Restablecer Contraseña</h5>
<button
type="button"
class="btn-close"
aria-label="Close"
onclick={close}
></button>
</div>
<div class="modal-body">
<form onsubmit={handleSubmit}>
<div class="mb-3">
<label for="password" class="form-label"
>Contraseña</label
>
<input
type="password"
id="password"
class="form-control"
minlength="8"
required
bind:value={password}
/>
<div class="form-text">
La contraseña debe tener al menos 8 caracteres.
</div>
</div>
<button type="submit" class="btn btn-primary"
>Guardar</button
>
</form>
</div>
</div>
</div>
</div>

View File

@@ -59,7 +59,7 @@
disabled={!contratoDescargado}
/>
<label class="form-check-label" for="leiContratoCheckbox">
Firme el contrato con el agente de la inmobiliaria
Leí el contrato con el agente de la inmobiliaria
</label>
</div>
</div>

View File

@@ -1,9 +1,16 @@
<script lang="ts">
import { Navbar, NavbarBrand, NavbarToggler, Nav, Collapse } from "@sveltestrap/sveltestrap";
import {
Navbar,
NavbarBrand,
NavbarToggler,
Nav,
Collapse,
Button,
} from "@sveltestrap/sveltestrap";
import { onMount } from "svelte";
import { writable } from 'svelte/store';
import { writable } from "svelte/store";
import { link, links } from "svelte-routing";
import './css/popup.css';
import "./css/popup.css";
import type { Grupo } from "../types";
import { urlG } from "../stores/urlStore";
@@ -13,17 +20,17 @@
let hayNotis: boolean = $state(false);
const permisos = writable<Grupo[]>([]);
const email = localStorage.getItem('email');
const token = sessionStorage.getItem('token');
const email = localStorage.getItem("email");
const token = sessionStorage.getItem("token");
async function obtenerPermisos() {
try {
const response = await fetch(String($urlG) + "/api/acciones", {
method: 'GET',
method: "GET",
headers: {
'Auth' : String(token),
'Email' : String(email),
'Content-Type' : "application/json"
Auth: String(token),
Email: String(email),
"Content-Type": "application/json",
},
});
if (response.ok) {
@@ -33,23 +40,25 @@
}
} catch (e) {
console.error(e);
}
}
onMount(() => {
obtenerPermisos();
obtenerNotis();
})
});
async function obtenerNotis() {
try {
const responce = await fetch($urlG+"/api/notificaciones/haySinLeer", {
const responce = await fetch(
$urlG + "/api/notificaciones/haySinLeer",
{
method: "GET",
headers: {
"Auth": String(token)
}
});
Auth: String(token),
},
},
);
if (responce.ok) {
let data = await responce.json();
hayNotis = data.message;
@@ -57,7 +66,6 @@
}
} catch (e) {
console.error(e);
}
}
@@ -72,50 +80,99 @@
localStorage.setItem("theme", theme);
};
async function cerrarSesion() {
try{
const req = await fetch($urlG+"/api/logout", {
method: "DELETE",
headers: {
"Auth": token || "",
}
});
}finally{
localStorage.removeItem("email");
sessionStorage.removeItem("token");
navigate("/");
}
}
</script>
<Navbar container="xxl" expand="md" color="dark-subtle">
<NavbarBrand href="/">
AlquilaFacil
</NavbarBrand>
<div>
<Navbar class="border-bottom" container="xxl" expand="md" color="dark-subtle">
<NavbarBrand href="/">AlquilaFacil</NavbarBrand>
<div class="d-flex gap-2">
<div class="badge" style="background-color: turquoise;" use:links>
<a href="/Menu">
<img src="/home.svg" alt="Volver al Menú" />
</a>
</div>
<button class="badge btn" onclick={toggleTheme} style="background-color: cadetblue;">
<button
class="badge btn"
onclick={toggleTheme}
style="background-color: cadetblue;"
>
{#if theme === "light"}
<img src="/toggle-left.svg" alt="" />
{:else}
<img src="/toggle-right.svg" alt="" />
{/if}
</button>
<button class="badge btn btn-info position-relative" onclick={()=>navigate("/notificaciones")}>
<img src="/bell.svg" alt="">
<button
class="badge btn btn-info position-relative"
onclick={() => navigate("/notificaciones")}
>
<img src="/bell.svg" alt="" />
{#if hayNotis}
<span class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-danger">
<span
class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-danger"
>
!
<span class="visually-hidden">unread messages</span>
</span>
{/if}
</button>
<button
class="btn badge"
onclick={() => navigate("/usuario")}
style="background-color: wheat;"
>
<img src="/user.svg" alt="usuario" />
</button>
<div class="vr"></div>
<button class="badge btn btn-danger" onclick={cerrarSesion}>
<img src="/logout.svg" alt="CerrarSesion" />
</button>
</div>
<NavbarToggler on:click={() => (isOpen = !isOpen)} />
<Collapse isOpen={isOpen} navbar expand="md">
<Collapse {isOpen} navbar expand="md">
<Nav class="ms-auto" navbar>
{#each $permisos as item}
<div class="dropdown">
<div class="btn-group" style="margin-left: 3px; margin-top: 3px">
<button class="btn btn-secondary" onclick={() => redirijir("/grupo/"+item.nombre)} >{item.nombre}</button>
<button class="btn btn-secondary dropdown-toggle dropdown-toggle-split" type="button" data-bs-toggle="dropdown" aria-expanded="false">
<div
class="btn-group"
style="margin-left: 3px; margin-top: 3px"
>
<button
class="btn btn-secondary"
onclick={() => redirijir("/grupo/" + item.nombre)}
>{item.nombre}</button
>
<button
class="btn btn-secondary dropdown-toggle dropdown-toggle-split"
type="button"
data-bs-toggle="dropdown"
aria-expanded="false"
>
<span class="visually-hidden">Toggle Dropdown</span>
</button>
<ul class="dropdown-menu dropdown-menu-end" use:links>
{#each item.idpermisos as perm}
<a class="dropdown-item link-underline-opacity-0 link-underline" href="/accion/{perm.id}" >{perm.descripcion}</a>
<li><hr class="dropdown-divider"></li>
<a
class="dropdown-item link-underline-opacity-0 link-underline"
href="/accion/{perm.id}"
>{perm.descripcion}</a
>
<li><hr class="dropdown-divider" /></li>
{/each}
</ul>
</div>

View File

@@ -1,5 +1,13 @@
<script lang="ts">
import { Navbar, NavbarBrand, NavbarToggler, NavItem, Nav, NavLink, Collapse } from "@sveltestrap/sveltestrap";
import {
Navbar,
NavbarBrand,
NavbarToggler,
NavItem,
Nav,
NavLink,
Collapse,
} from "@sveltestrap/sveltestrap";
let isOpen: boolean = $state(false);
let theme = $state(localStorage.getItem("theme") ?? "light");
@@ -10,13 +18,14 @@
};
</script>
<Navbar container="xxl" expand="md" color="dark-subtle">
<NavbarBrand href="/">
AlquilaFacil
</NavbarBrand>
<Navbar class="border-bottom" container="xxl" expand="md" color="dark-subtle">
<NavbarBrand href="/">AlquilaFacil</NavbarBrand>
<div>
<button class="badge btn" onclick={toggleTheme} style="background-color: cadetblue;">
<button
class="badge btn"
onclick={toggleTheme}
style="background-color: cadetblue;"
>
{#if theme === "light"}
<img src="/toggle-left.svg" alt="" />
{:else}
@@ -25,7 +34,7 @@
</button>
</div>
<NavbarToggler on:click={() => (isOpen = !isOpen)} />
<Collapse isOpen={isOpen} navbar expand="md">
<Collapse {isOpen} navbar expand="md">
<Nav class="ms-auto" navbar>
<NavItem>
<NavLink href="/">Login</NavLink>

View File

@@ -1,15 +1,15 @@
<script lang="ts">
import { onMount } from "svelte";
let {currentPag,
let {
currentPag,
cantpag,
queryPag,
centrado = false
centrado = false,
}: {
currentPag: number,
cantpag: number,
queryPag: (a:number) => void,
centrado:boolean
currentPag: number;
cantpag: number;
queryPag: (a: number) => void;
centrado: boolean;
} = $props();
function getVisiblePages() {
@@ -20,27 +20,55 @@
if (currentPag <= 3) {
return [1, 2, 3, 4, 5];
} else if (currentPag >= cantpag - 2) {
return [cantpag - 4, cantpag - 3, cantpag - 2, cantpag - 1, cantpag];
return [
cantpag - 4,
cantpag - 3,
cantpag - 2,
cantpag - 1,
cantpag,
];
} else {
return [currentPag - 2, currentPag - 1, currentPag, currentPag + 1, currentPag + 2];
return [
currentPag - 2,
currentPag - 1,
currentPag,
currentPag + 1,
currentPag + 2,
];
}
}
let visiblePages = $derived.by(getVisiblePages);
</script>
{#if cantpag > 1}
<nav aria-label="Paginador">
<ul class="pagination">
<li class="page-item {currentPag === 1 ? 'disabled' : ''}">
<a class="page-link" href="#" onclick={() => currentPag > 1 && queryPag(currentPag - 1)}>Anterior</a>
<button
class="page-link"
onclick={() => currentPag > 1 && queryPag(currentPag - 1)}
>
Anterior
</button>
</li>
{#each visiblePages as num}
<li class="page-item"><a class="page-link" class:active={currentPag === num} href="#" onclick={()=>queryPag(num)}>{String(num)}</a></li>
<li class="page-item">
<button
class="page-link"
class:active={currentPag === num}
onclick={() => queryPag(num)}
>
{String(num)}
</button>
</li>
{/each}
<li class="page-item {currentPag === cantpag ? 'disabled' : ''}">
<a class="page-link" href="#" onclick={() => currentPag < cantpag && queryPag(currentPag + 1)}>Siguiente</a>
<button
class="page-link"
onclick={() =>
currentPag < cantpag && queryPag(currentPag + 1)}
>Siguiente</button
>
</li>
</ul>
</nav>

View File

@@ -1,6 +1,6 @@
<script>
import { onMount } from 'svelte';
import { writable } from 'svelte/store';
import { onMount } from "svelte";
import { writable } from "svelte/store";
import { urlG } from "../stores/urlStore";
@@ -10,26 +10,26 @@
const isVerified = writable(false);
const redirect = window.location.pathname;
const email = localStorage.getItem('email');
const token = sessionStorage.getItem('token');
const email = localStorage.getItem("email");
const token = sessionStorage.getItem("token");
const handleAccess = async () => {
try {
const response = await fetch($urlG + "/api/login/validar", {
method: 'POST',
method: "POST",
headers: {
'Auth': String(token),
'Content-Type': 'application/json',
Auth: String(token),
"Content-Type": "application/json",
},
body: JSON.stringify({ email, redirect }),
credentials: "include"
credentials: "include",
});
if (response.ok) {
isAuthenticated.set(true); // Actualiza el store
}
} catch (error) {
console.error('Error durante la autenticación:', error);
console.error("Error durante la autenticación:", error);
} finally {
isVerified.set(true); // Marca la verificación como completada
}
@@ -41,15 +41,19 @@
</script>
{#if !$isVerified}
<div class="d-flex justify-content-center position-absolute top-50 start-50">
<div
class="d-flex justify-content-center position-absolute top-50 start-50"
>
<div class="spinner-border" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</div>
{:else if $isAuthenticated}
{#if typeof componente === "object" && componente !== null}
<componente.OtroG id={componente.params.id} />
{:else}
{#if $isAuthenticated}
{@render componente()}
{/if}
{:else}
{window.location.replace('/')}
{/if}
{window.location.replace("/")}
{/if}

View File

@@ -0,0 +1,247 @@
<script lang="ts">
import { onMount } from "svelte";
import NavBarAutocompletable from "../Componentes/NavBarAutocompletable.svelte";
import type { GrupoDto, PermisoDto } from "../types";
import { urlG } from "../stores/urlStore";
import ModalEstatico from "../Componentes/ModalEstatico.svelte";
import ModalEditarGrupo from "../Componentes/ModalEditarGrupo.svelte";
import BarraHorizontalConTexto from "../Componentes/BarraHorizontalConTexto.svelte";
import BotonEsquina from "../Componentes/BotonEsquina.svelte";
import ModalAadirGrupo from "../Componentes/ModalAñadirGrupo.svelte";
const token: string = sessionStorage.getItem("token") || "";
let grupos: GrupoDto[] = $state([]);
let modaldat: string = $state("");
let showmodaladd = $state(false);
onMount(() => {
ObtenerGrupos();
obtenerPermisos();
});
async function ObtenerGrupos() {
try {
const ret = await fetch($urlG + "/api/admin/grupos", {
method: "GET",
headers: {
Auth: token,
},
});
if (!ret.ok) {
modaldat = "Fallo Al intentar hacer la request";
return;
}
grupos = await ret.json();
} catch {
modaldat = "Fallo Al intentar hacer la request";
}
}
let selgru: GrupoDto = $state({
gruposIncluidos: [],
idgrupo: 0,
habilitado: false,
nombre: "",
permisos: [],
});
let showModal: boolean = $state(false);
function setModalEditar(data: GrupoDto) {
selgru = data;
showModal = true;
}
async function submitedit(a: GrupoDto) {
let b = a;
try {
let req = await fetch($urlG + "/api/grupo", {
method: "PATCH",
headers: {
Auth: token,
"Content-Type": "application/json",
},
body: JSON.stringify(b),
});
const resp = await req.json();
modaldat = resp.message;
if (req.ok) {
ObtenerGrupos();
}
} catch {
modaldat = "Fallo al hacer la request";
}
}
let permisos: PermisoDto[] = $state([]);
async function obtenerPermisos() {
try {
let a = await fetch($urlG + "/api/permisos/todos", {
method: "GET",
headers: {
Auth: token,
},
});
if (!a.ok) {
modaldat = "Fallo al obtener los permisos";
return;
}
permisos = await a.json();
} catch {
modaldat = "Fallo Al intentar hacer la request";
}
}
async function submitGrupo(a: GrupoDto) {
let b = a;
try {
let req = await fetch($urlG + "/api/grupo", {
method: "POST",
headers: {
Auth: token,
"Content-Type": "application/json",
},
body: JSON.stringify(b),
});
const resp = await req.json();
modaldat = resp.message;
if (req.ok) {
ObtenerGrupos();
}
} catch {
modaldat = "Fallo al hacer la request";
}
}
async function togglegrupo(grupo: GrupoDto) {
try {
const req = await fetch($urlG + "/api/grupo?id=" + grupo.idgrupo, {
method: "DELETE",
headers: {
Auth: token,
},
});
if (req.ok) {
grupo.habilitado = !grupo.habilitado;
}
modaldat = (await req.json()).message;
ObtenerGrupos();
} catch {
modaldat = "Fallo al hacer la request";
}
}
</script>
{#if modaldat != ""}
<ModalEstatico payload={modaldat} close={() => !!(modaldat = "")} />
{/if}
{#if showModal}
<ModalEditarGrupo
bind:data={selgru}
{permisos}
{grupos}
onClose={() => (showModal = false)}
onSubmit={submitedit}
/>
{/if}
<NavBarAutocompletable />
<div class="container mt-2">
<BarraHorizontalConTexto text="Gestionar Grupos" />
{#if grupos.length == 0}
<div class="text-center">
<div class="spinner-border" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</div>
{:else}
{#if showmodaladd}
<ModalAadirGrupo
onClose={() => (showmodaladd = false)}
{grupos}
{permisos}
onSubmit={submitGrupo}
/>
{/if}
{#each grupos as grupo}
<div class="accordion mt-2">
<div class="accordion-item">
<h2 class="accordion-header">
<button
class="accordion-button collapsed"
type="button"
data-bs-toggle="collapse"
data-bs-target={`#${grupo.idgrupo}`}
aria-expanded="false"
aria-controls={grupo.idgrupo}
>
{grupo.nombre}
<span
class="ms-1 badge text-bg-secondary position-relative"
style="top: -5px;"
>
{grupo.habilitado
? "Habilitado"
: "Desabilitado"}
</span>
</button>
</h2>
<div id={grupo.idgrupo} class="accordion-collapse collapse">
<div class="accordion-body">
<div class="row">
<div class="col-6">
<h5>Grupos Incluidos</h5>
<ul class="list-group">
{#if grupo.gruposIncluidos.length == 0}
<li class="list-group-item">
No hay grupos incluidos
</li>
{:else}
{#each grupo.gruposIncluidos as grupoIncluido}
<li class="list-group-item">
{grupoIncluido}
</li>
{/each}
{/if}
</ul>
</div>
<div class="col-6">
<h5>Permisos</h5>
<ul class="list-group">
{#if grupo.permisos.length == 0}
<li class="list-group-item">
No hay grupos incluidos
</li>
{:else}
{#each grupo.permisos as permiso}
<li class="list-group-item">
{permiso.descripcion}
</li>
{/each}
{/if}
</ul>
</div>
</div>
<hr />
<div class="d-flex justify-content-between">
<button
class="btn btn-primary"
onclick={() => setModalEditar(grupo)}
>Editar</button
>
<button
class="btn"
class:btn-danger={grupo.habilitado}
class:btn-success={!grupo.habilitado}
onclick={() => togglegrupo(grupo)}
>
{#if grupo.habilitado}Baja{:else}Alta{/if}
</button>
</div>
</div>
</div>
</div>
</div>
{/each}
<BotonEsquina handleclick={() => (showmodaladd = true)} />
{/if}
</div>

View File

@@ -1,13 +1,14 @@
<script lang="ts">
import { onMount } from "svelte";
import NavBarAutocompletable from "../Componentes/NavBarAutocompletable.svelte";
import type { Cliente, Grupo, UpdateCliente } from "../types";
import type { Cliente, Grupo, GrupoDto, UpdateCliente } from "../types";
import { urlG } from "../stores/urlStore";
import ModalEstatico from "../Componentes/ModalEstatico.svelte";
import BarraHorizontalConTexto from "../Componentes/BarraHorizontalConTexto.svelte";
import { fade, fly } from "svelte/transition";
import ModalModificarPropietarios from "../Componentes/ModalModificarPropietarios.svelte";
import { CardLink } from "@sveltestrap/sveltestrap";
import { CardLink, Modal } from "@sveltestrap/sveltestrap";
import ModalRestablecerContra from "../Componentes/ModalRestablecerContra.svelte";
let Clientes: Cliente[] = $state([]);
let Grupos: any[] = $state([]);
@@ -18,17 +19,39 @@
let grupo: string = $state("");
let SelCliente: Cliente = $state(null);
let gruposopt: GrupoDto[] = $state([]);
onMount(() => {
cargaUsuarios();
ObtenerGrupos();
});
async function ObtenerGrupos() {
try {
const ret = await fetch($urlG + "/api/admin/grupos", {
method: "GET",
headers: {
Auth: token || "",
},
});
if (!ret.ok) {
modaldata = "Fallo Al intentar hacer la request";
return;
}
gruposopt = await ret.json();
} catch {
modaldata = "Fallo Al intentar hacer la request";
}
}
async function cargaUsuarios() {
try {
const response = await fetch($urlG + "/api/admin/clientes", {
method: "GET",
headers: {
"Auth": String(token),
}
})
Auth: String(token),
},
});
if (response.ok) {
let data: Cliente[] = await response.json();
Clientes = data;
@@ -38,16 +61,18 @@
} catch {
modaldata = "fallo al intentar obtener la lista de clientes";
}
}
async function cargaGrupos(cli: Cliente) {
try {
const response = await fetch($urlG+"/api/admin/clientes/grupo?Dni="+cli.dni, {
const response = await fetch(
$urlG + "/api/admin/clientes/grupo?Dni=" + cli.dni,
{
method: "GET",
headers: {
"Auth": String(token),
Auth: String(token),
},
});
},
);
if (response.ok) {
let data = await response.json();
Grupos = data;
@@ -63,25 +88,26 @@
}
async function bajaCliente(event: Event, cli: Cliente) {
//WIP añadir una flag para que muestre que no se pudo dar se alta/baja
event.stopPropagation();
try {
const response = await fetch($urlG+"/api/admin/cliente?Dni="+cli.dni, {
const response = await fetch(
$urlG + "/api/admin/cliente?Dni=" + cli.dni,
{
method: "DELETE",
headers: {
"Auth": String(token),
}
});
if(response.ok){
Auth: String(token),
},
},
);
let data = await response.json();
modaldata = data.message;
if (response.ok) {
cli.habilitado = !cli.habilitado;
cargaUsuarios();
}
} catch {
modaldata = "";
modaldata = "Fallo al hacer la request";
}
}
async function añadirGrupo(e: Event, cli: Cliente, grupo: string) {
e.preventDefault();
@@ -91,14 +117,17 @@
}
const email = cli.email;
try {
const response = await fetch($urlG+"/api/admin/cliente/addGrupo", {
const response = await fetch(
$urlG + "/api/admin/cliente/addGrupo",
{
method: "PATCH",
headers: {
"Auth": String(token),
'Content-Type' : 'application/json',
Auth: String(token),
"Content-Type": "application/json",
},
body: JSON.stringify({email, grupo})
});
body: JSON.stringify({ email, grupo }),
},
);
if (response.ok) {
let data = await response.json();
@@ -120,16 +149,21 @@
}
const email = cli.email;
if (grupo === "Propietario") {
if (confirm("Sos propietario si te desactivas de ese rol tus propiedades se van a dar de baja, Estas seguro?") == false) return;
if (
confirm(
"Sos propietario si te desactivas de ese rol tus propiedades se van a dar de baja, Estas seguro?",
) == false
)
return;
}
try {
const response = await fetch($urlG + "/api/admin/cliente/rmGrupo", {
method: "PATCH",
headers: {
"Auth": String(token),
'Content-Type' : 'application/json',
Auth: String(token),
"Content-Type": "application/json",
},
body: JSON.stringify({email, grupo})
body: JSON.stringify({ email, grupo }),
});
if (response.ok) {
@@ -146,7 +180,13 @@
}
let showModificarCliente: boolean = $state(false);
let datoscli:UpdateCliente = $state({dni:0, apellido:"", celular:"", domicilio:"", nombre:""});
let datoscli: UpdateCliente = $state({
dni: 0,
apellido: "",
celular: "",
domicilio: "",
nombre: "",
});
async function abrirModalModificarCliente(e: Event, cli: Cliente) {
e.stopPropagation();
@@ -154,8 +194,8 @@
const r = await fetch($urlG + "/api/admin/cliente?dni=" + cli.dni, {
method: "GET",
headers: {
"Auth": token||"",
}
Auth: token || "",
},
});
let data = await r.json();
if (r.ok) {
@@ -171,7 +211,12 @@
}
async function patchCliente(a: UpdateCliente) {
if (a.apellido =="" || a.celular=="" || a.domicilio=="" || a.nombre==""){
if (
a.apellido == "" ||
a.celular == "" ||
a.domicilio == "" ||
a.nombre == ""
) {
modaldata = "Hay campos vacios";
return;
}
@@ -180,13 +225,13 @@
celular: a.celular,
domicilio: a.domicilio,
nombre: a.nombre,
}
};
try {
const r = await fetch($urlG + "/api/admin/cliente?dni=" + a.dni, {
method: "PATCH",
headers: {
"Auth": token||"",
"Content-Type": "application/json"
Auth: token || "",
"Content-Type": "application/json",
},
body: JSON.stringify(dto),
});
@@ -197,6 +242,36 @@
modaldata = "Falla la conexion al servidor";
}
}
let restablecercontracli: Cliente | null = $state(null);
let showmodalrestablecercontra: boolean = $state(false);
async function handleRestablecerContraseña(e: Event, pass: string) {
e.preventDefault();
try {
const req = await fetch($urlG + "/api/admin/contraseña", {
method: "PATCH",
headers: {
Auth: token || "",
"Content-Type": "application/json",
},
body: JSON.stringify({
Dni: restablecercontracli?.dni,
contraseña: pass,
}),
});
const js = await req.json();
showmodalrestablecercontra = false;
restablecercontracli = null;
modaldata = js.message;
} catch {
modaldata = "Falla la conexion al servidor";
}
}
function triggermodalcontra(cli: Cliente) {
restablecercontracli = cli;
showmodalrestablecercontra = true;
}
</script>
<NavBarAutocompletable />
@@ -206,8 +281,18 @@
{/if}
{#if showModificarCliente}
<ModalModificarPropietarios datos={datoscli} onCancel={()=>!!(showModificarCliente = false)}
onConfirm={patchCliente}/>
<ModalModificarPropietarios
datos={datoscli}
onCancel={() => !!(showModificarCliente = false)}
onConfirm={patchCliente}
/>
{/if}
{#if showmodalrestablecercontra}
<ModalRestablecerContra
close={() => (showmodalrestablecercontra = false)}
submit={handleRestablecerContraseña}
/>
{/if}
<div class="content-fluid align-items-start">
@@ -215,8 +300,10 @@
<div class="col ms-2">
<BarraHorizontalConTexto text="Clientes" />
<div style="height:70vh; overflow-y: auto; max-width: 100%">
<table class="table table-responsive table-striped table-hover table-bordered">
<div style="height:85vh; overflow-y: auto; max-width: 100%">
<table
class="table table-responsive table-striped table-hover table-bordered"
>
<thead>
<tr>
<th>Dni</th>
@@ -233,16 +320,34 @@
<td>{cli.email}</td>
<td>
{#if cli.habilitado}
<button class="btn btn-warning" onclick={(e) => bajaCliente(e, cli)}>
<button
class="btn btn-warning"
onclick={(e) => bajaCliente(e, cli)}
>
Baja
</button>
{:else}
<button class="btn btn-success" onclick={(e) => bajaCliente(e, cli)}>
<button
class="btn btn-success"
onclick={(e) => bajaCliente(e, cli)}
>
Alta
</button>
{/if}
<button class="btn btn-secondary" onclick={(e)=>abrirModalModificarCliente(e, cli)}>
Modificar
<button
class="btn btn-secondary"
onclick={(e) =>
abrirModalModificarCliente(e, cli)}
>
<img src="/edit.svg" alt="Editar" />
</button>
<button
class="btn btn-info"
onclick={() => triggermodalcontra(cli)}
><img
src="/key.svg"
alt="RestablecerContraseña"
/>
</button>
</td>
</tr>
@@ -253,7 +358,9 @@
</div>
<div class="col me-2 ps-0">
<BarraHorizontalConTexto text="Grupos del Cliente Seleccionado" />
<table class="table table-striped table-responsive table-sm table-bordered">
<table
class="table table-striped table-responsive table-sm table-bordered"
>
<thead>
<tr>
<th>Id</th>
@@ -263,12 +370,21 @@
</thead>
<tbody>
{#if Grupos.length > 0}
{#each Grupos as g}
<tr in:fade>
<td>{g.id}</td>
<td>{g.descripcion}</td>
<td><button class="btn btn-outline-danger" onclick={(e)=>BajaGrupo(e, SelCliente, g.descripcion)}>Baja</button></td>
<td
><button
class="btn btn-outline-danger"
onclick={(e) =>
BajaGrupo(
e,
SelCliente,
g.descripcion,
)}>Baja</button
></td
>
</tr>
{/each}
{:else if SelCliente != null}
@@ -277,7 +393,9 @@
</tr>
{:else}
<tr>
<td colspan="3">Seleccione un cliente para ver sus grupos</td>
<td colspan="3"
>Seleccione un cliente para ver sus grupos</td
>
</tr>
{/if}
</tbody>
@@ -286,21 +404,30 @@
{#if showAddmenu}
<div in:fade>
<BarraHorizontalConTexto text="Añadir Grupos al Usuario" />
<form class="card card-body" onsubmit={(e) => añadirGrupo(e,SelCliente, grupo)}>
<form
class="card card-body"
onsubmit={(e) => añadirGrupo(e, SelCliente, grupo)}
>
<div class="mb-3">
<label for="userRole" class="form-label">Seleccionar Grupo</label>
<select id="userRole" class="form-select" bind:value={grupo}>
<option value="Propietario">Propietario</option>
<option value="Inquilino">Inquilino</option>
<option value="Admin">Admin</option>
<option value="Informes">Informes</option>
<label for="userRole" class="form-label"
>Seleccionar Grupo</label
>
<select
id="userRole"
class="form-select"
bind:value={grupo}
>
{#each gruposopt as g}
<option value={g.nombre}>{g.nombre}</option>
{/each}
</select>
</div>
<button class="btn btn-primary" type="submit">Añadir</button>
<button class="btn btn-primary" type="submit"
>Añadir</button
>
</form>
</div>
{/if}
</div>
</div>
</div>

View File

@@ -0,0 +1,551 @@
<script>
import { onMount } from 'svelte';
import NavBarAutocompletable from '../Componentes/NavBarAutocompletable.svelte';
import { urlG } from '../stores/urlStore';
import ModalEstatico from '../Componentes/ModalEstatico.svelte';
let contrato = $state({
id: 0,
cantgarantemin: 0,
dniinquilino: 0n,
dnipropietario: 0n,
iddivisa: 0,
idpropiedad: 0,
mesesDurationContrato: 0,
mesesHastaAumento: 0,
monto: 0,
tieneopcionventa: false,
archivoContrato: null,
divisaOpcionVenta: 0,
montoOpcionVenta: 0,
garantes: []
});
let modaldata = $state("");
let token = sessionStorage.getItem("token");
let busquedaDivisa = $state('');
let busquedaDivisaOpVenta = $state('');
let busquedaPropiedad = $state('');
let busquedaInquilino = $state('');
let busquedaPropietario = $state('');
let divisas = $state([]);
let propiedades = $state([]);
let inquilinos = $state([]);
let propietarios = $state([]);
$effect(() => {
const currentLength = contrato.garantes.length;
if (contrato.cantgarantemin > currentLength) {
// Agregar garantes faltantes
for (let i = currentLength; i < contrato.cantgarantemin; i++) {
contrato.garantes = [...contrato.garantes, {
dni: '',
nombre: '',
apellido: '',
domicilio: '',
celular: '',
domicilioLaboral: ''
}];
}
} else if (contrato.cantgarantemin < currentLength) {
// Remover garantes excedentes
contrato.garantes = contrato.garantes.slice(0, contrato.cantgarantemin);
}
});
onMount(async () => {
obtenerDatos();
});
async function obtenerDatos(){
try{
const req = await fetch($urlG + "/api/admin/contrato/data", {
method: "GET",
headers: {
"Auth": token || "",
}
});
const data = await req.json();
if (req.ok){
({ divisas, propiedades, inquilinos, propietarios } = data);
return;
}
modaldata = data.message;
}catch{
modaldata = "Fallo la request";
}
}
function handleFileChange(event) {
const file = event.target.files[0];
if (file) {
contrato.archivoContrato = file;
}
}
let divisasFiltradas = $derived(
divisas.filter(d =>
!busquedaDivisa ||
d.signo?.toLowerCase().includes(busquedaDivisa.toLowerCase()) ||
d.id.toString().includes(busquedaDivisa)
)
);
let divisasFiltradasOpVenta = $derived(
divisas.filter(d =>
!busquedaDivisaOpVenta ||
d.signo?.toLowerCase().includes(busquedaDivisaOpVenta.toLowerCase()) ||
d.id.toString().includes(busquedaDivisaOpVenta)
)
);
let propiedadesFiltradas = $derived(
propiedades.filter(p =>
!busquedaPropiedad ||
p.ubicacion?.toLowerCase().includes(busquedaPropiedad.toLowerCase()) ||
p.id.toString().includes(busquedaPropiedad)
)
);
let inquilinosFiltrados = $derived(
inquilinos.filter(i =>
!busquedaInquilino ||
i.nombre?.toLowerCase().includes(busquedaInquilino.toLowerCase()) ||
i.dni.toString().includes(busquedaInquilino)
)
);
let propietariosFiltrados = $derived(
propietarios.filter(p =>
!busquedaPropietario ||
p.nombre?.toLowerCase().includes(busquedaPropietario.toLowerCase()) ||
p.dni.toString().includes(busquedaPropietario)
)
);
async function handleSubmit(e) {
e.preventDefault();
const formData = new FormData();
formData.append('cantgarantemin', contrato.cantgarantemin.toString());
formData.append('dniinquilino', contrato.dniinquilino.toString());
formData.append('dnipropietario', contrato.dnipropietario.toString());
formData.append('iddivisa', contrato.iddivisa.toString());
formData.append('idpropiedad', contrato.idpropiedad.toString());
formData.append('mesesDurationContrato', contrato.mesesDurationContrato.toString());
formData.append('mesesHastaAumento', contrato.mesesHastaAumento.toString());
formData.append('monto', contrato.monto.toString());
formData.append('tieneopcionventa', contrato.tieneopcionventa.toString());
contrato.garantes.forEach((garante, index) => {
formData.append(`garantes[${index}].dni`, garante.dni);
formData.append(`garantes[${index}].nombre`, garante.nombre);
formData.append(`garantes[${index}].apellido`, garante.apellido);
formData.append(`garantes[${index}].domicilio`, garante.domicilio);
formData.append(`garantes[${index}].celular`, garante.celular);
formData.append(`garantes[${index}].domicilioLaboral`, garante.domicilioLaboral);
});
if (contrato.tieneopcionventa) {
formData.append('divisaOpcionVenta', contrato.divisaOpcionVenta.toString());
formData.append('montoOpcionVenta', contrato.montoOpcionVenta.toString());
}
// Agregar el archivo si existe
if (contrato.archivoContrato) {
formData.append('archivoContrato', contrato.archivoContrato);
}
try {
const response = await fetch($urlG + '/api/admin/contrato/carga', {
method: 'POST',
headers: {
"Auth": token || "",
},
body: formData
});
const data = await response.json();
if (response.ok) {
contrato = {
id: 0,
cantgarantemin: 0,
dniinquilino: 0n,
dnipropietario: 0n,
iddivisa: 0,
idpropiedad: 0,
mesesDurationContrato: 0,
mesesHastaAumento: 0,
monto: 0,
tieneopcionventa: false,
archivoContrato: null,
divisaOpcionVenta: 0,
montoOpcionVenta: 0,
garantes: []
};
}
modaldata = data.message;
} catch (error) {
modaldata = "Fallo al hacer la request";
}
}
async function actualizarPropiedades(dnipropietario){
try{
const req = await fetch($urlG + "/api/admin/contrato/propieades?dnipropietario="+ dnipropietario, {
method: "GET",
headers:{
"Auth": token || "",
}
});
const data = await req.json();
if (req.ok){
propiedades = data;
return;
}
modaldata = data.message;
}catch{
modaldata = "Fallo al hacer la request";
}
}
function actualizarGarante(index, campo, valor) {
contrato.garantes[index] = { ...contrato.garantes[index], [campo]: valor };
}
</script>
<NavBarAutocompletable/>
{#if modaldata}
<ModalEstatico payload={modaldata} close={()=>!!(modaldata = "")}/>
{/if}
<div class="container mt-4">
<h2>Alta de Contrato</h2>
<form onsubmit={handleSubmit}>
<div class="row mb-3">
<label for="dniinquilino" class="col-sm-3 col-form-label">Inquilino</label>
<div class="col-sm-9">
<div class="input-group">
<input
type="text"
class="form-control"
placeholder="Buscar inquilino (DNI o nombre)..."
bind:value={busquedaInquilino}
/>
<select
class="form-select"
id="dniinquilino"
bind:value={contrato.dniinquilino}
required
>
<option value="">Seleccionar Inquilino...</option>
{#each inquilinosFiltrados as inq}
<option value={inq.dni}>{inq.nombre} | {inq.dni}</option>
{/each}
</select>
</div>
</div>
</div>
<div class="row mb-3">
<label for="dnipropietario" class="col-sm-3 col-form-label">Propietario</label>
<div class="col-sm-9">
<div class="input-group">
<input
type="text"
class="form-control"
placeholder="Buscar propietario (DNI o nombre)..."
bind:value={busquedaPropietario}
/>
<select
class="form-select"
id="dnipropietario"
bind:value={contrato.dnipropietario}
required
onchange={()=>actualizarPropiedades(contrato.dnipropietario)}
>
<option value="">Seleccionar Propietario...</option>
{#each propietariosFiltrados as prop}
<option value={prop.dni}>{prop.nombre} | {prop.dni}</option>
{/each}
</select>
</div>
</div>
</div>
<div class="row mb-3">
<label for="monto" class="col-sm-3 col-form-label">Monto del Contrato</label>
<div class="col-sm-9">
<input
type="number"
step="0.01"
min="1"
class="form-control"
id="monto"
bind:value={contrato.monto}
required
/>
</div>
</div>
<div class="row mb-3">
<label for="mesesDurationContrato" class="col-sm-3 col-form-label">Duración (meses)</label>
<div class="col-sm-9">
<input
type="number"
min="1"
class="form-control"
id="mesesDurationContrato"
bind:value={contrato.mesesDurationContrato}
required
/>
</div>
</div>
<div class="row mb-3">
<label for="mesesHastaAumento" class="col-sm-3 col-form-label">Meses hasta Aumento</label>
<div class="col-sm-9">
<input
type="number"
min="1"
class="form-control"
id="mesesHastaAumento"
bind:value={contrato.mesesHastaAumento}
/>
</div>
</div>
<div class="row mb-3">
<label for="cantgarantemin" class="col-sm-3 col-form-label">Cantidad Garantes Mínimos</label>
<div class="col-sm-9">
<input
type="number"
min="0"
max="100"
class="form-control"
id="cantgarantemin"
bind:value={contrato.cantgarantemin}
/>
</div>
</div>
{#if contrato.cantgarantemin > 0}
<div class="row mb-3">
<div class="col-12">
<h5>Garantes</h5>
<div class="table-responsive">
<table class="table table-bordered">
<thead>
<tr>
<th>DNI</th>
<th>Nombre</th>
<th>Apellido</th>
<th>Domicilio</th>
<th>Celular</th>
<th>Domicilio Laboral</th>
</tr>
</thead>
<tbody>
{#each contrato.garantes as garante, i}
<tr>
<td>
<input
type="text"
class="form-control"
placeholder="DNI"
min="0"
max="99999999"
bind:value={garante.dni}
oninput={(e) => actualizarGarante(i, 'dni', e.target.value)}
/>
</td>
<td>
<input
type="text"
class="form-control"
minlength="1"
placeholder="Nombre"
bind:value={garante.nombre}
oninput={(e) => actualizarGarante(i, 'nombre', e.target.value)}
/>
</td>
<td>
<input
type="text"
class="form-control"
placeholder="Apellido"
bind:value={garante.apellido}
oninput={(e) => actualizarGarante(i, 'apellido', e.target.value)}
/>
</td>
<td>
<input
type="text"
class="form-control"
placeholder="Domicilio"
bind:value={garante.domicilio}
oninput={(e) => actualizarGarante(i, 'domicilio', e.target.value)}
/>
</td>
<td>
<input
type="text"
class="form-control"
placeholder="Celular"
bind:value={garante.celular}
oninput={(e) => actualizarGarante(i, 'celular', e.target.value)}
/>
</td>
<td>
<input
type="text"
class="form-control"
placeholder="Domicilio Laboral"
bind:value={garante.domicilioLaboral}
oninput={(e) => actualizarGarante(i, 'domicilioLaboral', e.target.value)}
/>
</td>
</tr>
{/each}
</tbody>
</table>
</div>
</div>
</div>
{/if}
<div class="row mb-3">
<label for="archivoContrato" class="col-sm-3 col-form-label">Archivo del Contrato</label>
<div class="col-sm-9">
<input
type="file"
class="form-control"
id="archivoContrato"
accept=".pdf,.doc,.docx,.jpg,.jpeg,.png"
onchange={handleFileChange}
/>
{#if contrato.archivoContrato}
<small class="text-muted">Archivo seleccionado: {contrato.archivoContrato.name}</small>
{/if}
</div>
</div>
<div class="row mb-3">
<label for="iddivisa" class="col-sm-3 col-form-label">Divisa</label>
<div class="col-sm-9">
<div class="input-group">
<input
type="text"
class="form-control"
placeholder="Buscar divisa..."
bind:value={busquedaDivisa}
/>
<select
class="form-select"
id="iddivisa"
bind:value={contrato.iddivisa}
required
>
<option value="">Seleccionar Divisa...</option>
{#each divisasFiltradas as divisa}
<option value={divisa.id}>{divisa.signo}</option>
{/each}
</select>
</div>
</div>
</div>
<div class="row mb-3">
<label for="idpropiedad" class="col-sm-3 col-form-label">Propiedad</label>
<div class="col-sm-9">
<div class="input-group">
<input
type="text"
class="form-control"
placeholder="Buscar propiedad (ID o dirección)..."
bind:value={busquedaPropiedad}
/>
<select
class="form-select"
id="idpropiedad"
bind:value={contrato.idpropiedad}
required
>
<option value="">Seleccionar Propiedad...</option>
{#each propiedadesFiltradas as propiedad}
<option value={propiedad.id}>{propiedad.id} - {propiedad.ubicacion}</option>
{/each}
</select>
</div>
</div>
</div>
<div class="row mb-3">
<div class="col-sm-9 offset-sm-3">
<div class="form-check">
<input
class="form-check-input"
type="checkbox"
bind:checked={contrato.tieneopcionventa}
id="tieneopcionventa"
/>
<label class="form-check-label" for="tieneopcionventa">
Tiene Opción de Venta
</label>
</div>
</div>
</div>
{#if contrato.tieneopcionventa}
<div class="row mb-3">
<label for="divisaOpcionVenta" class="col-sm-3 col-form-label">Divisa Opción Venta</label>
<div class="col-sm-9">
<div class="input-group">
<input
type="text"
class="form-control"
placeholder="Buscar divisa..."
bind:value={busquedaDivisaOpVenta}
/>
<select
class="form-select"
id="divisaOpcionVenta"
bind:value={contrato.divisaOpcionVenta}
required
>
<option value="">Seleccionar Divisa...</option>
{#each divisasFiltradasOpVenta as divisa}
<option value={divisa.id}>{divisa.signo}</option>
{/each}
</select>
</div>
</div>
</div>
<div class="row mb-3">
<label for="montoOpcionVenta" class="col-sm-3 col-form-label">Monto Opción Venta</label>
<div class="col-sm-9">
<input
type="number"
step="0.01"
class="form-control"
id="montoOpcionVenta"
bind:value={contrato.montoOpcionVenta}
required
/>
</div>
</div>
{/if}
<div class="row mb-3">
<div class="col-sm-9 offset-sm-3">
<button type="submit" class="btn btn-primary">Guardar Contrato</button>
</div>
</div>
</form>
</div>

View File

@@ -33,9 +33,29 @@
onMount(()=>{
getparams();
obtenerDatosACargar();
getgarantes();
});
async function getgarantes() {
try{
const ret = await fetch($urlG+"/api/contratos/garantes"+"?idcontrato="+contratoid,{
method: "GET",
headers: {
"Auth": token
},
});
if (!ret.ok){
let data = await ret.json();
modaldata = data.message;
return;
}
let data = await ret.json();
garantes = data;
return;
}catch{
modaldata = "No se pudo obtener la lista de garantes actualizada";
}
}
async function refreshCanon() {
try {
const ret = await fetch($urlG+"/api/admin/contrato/canons?id="+contratoid, {
@@ -273,7 +293,7 @@
aria-expanded="true"
aria-controls="collapseTwo"
>
Canons
Canones
</button>
</h2>
<div

View File

@@ -3,7 +3,15 @@
import { onMount } from "svelte";
import ModalEstatico from "../Componentes/ModalEstatico.svelte";
import { urlG } from "../stores/urlStore";
import type { AltaDefectoDto, CanonDto, ContratoDto, ContratoPropiedadDto, DefectoDto, GaranteDto2, OpcionVentaDto } from "../types";
import type {
AltaDefectoDto,
CanonDto,
ContratoDto,
ContratoPropiedadDto,
DefectoDto,
GaranteDto2,
OpcionVentaDto,
} from "../types";
import ModalPedirDoc from "../Componentes/ModalPedirDoc.svelte";
import FormAltaDefecto from "../Componentes/FormAltaDefecto.svelte";
import { navigate } from "svelte-routing";
@@ -31,7 +39,13 @@
let defectos: DefectoDto[] = $state([]);
let TieneOpcionVenta: boolean = $state(false);
let dtoVenta:OpcionVentaDto =$state({divisa:"", id:0, monto:0, enOrden:false, fueEjercido:false});
let dtoVenta: OpcionVentaDto = $state({
divisa: "",
id: 0,
monto: 0,
enOrden: false,
fueEjercido: false,
});
let modaldata: string = $state("");
let contratoid: string = $state("");
@@ -44,12 +58,17 @@
async function opcionVenta() {
try {
const r = await fetch($urlG+"/api/contrato/tieneopcionventa?idcontrato="+contratoid, {
const r = await fetch(
$urlG +
"/api/contrato/tieneopcionventa?idcontrato=" +
contratoid,
{
method: "GET",
headers: {
"Auth": String(token),
}
});
Auth: String(token),
},
},
);
if (r.ok) {
let data = await r.json();
TieneOpcionVenta = data.message;
@@ -68,16 +87,19 @@
async function ObtenerOpcionVentaDto() {
try {
const r = await fetch($urlG+"/api/opcionventa?idcontrato="+contratoid, {
const r = await fetch(
$urlG + "/api/opcionventa?idcontrato=" + contratoid,
{
method: "GET",
headers: {
"Auth": String(token),
}
});
Auth: String(token),
},
},
);
if (r.ok) {
let data = await r.json();
dtoVenta = data;
return
return;
}
let data = await r.json();
modaldata = data.message;
@@ -88,31 +110,49 @@
async function obtenerDatosACargar() {
try {
const respPropiedad = fetch($urlG+"/api/contrato/inquilino?id="+contratoid, {
const respPropiedad = fetch(
$urlG + "/api/contrato/inquilino?id=" + contratoid,
{
method: "GET",
headers: {
"Auth": String(token),
}
});
const respgarantes = fetch($urlG+"/api/contratos/garantes?idcontrato="+contratoid, {
Auth: String(token),
},
},
);
const respgarantes = fetch(
$urlG + "/api/contratos/garantes?idcontrato=" + contratoid,
{
method: "GET",
headers: {
"Auth": String(token),
}
});
const respCanons = fetch($urlG+"/api/contratos/canon?id="+contratoid, {
Auth: String(token),
"Content-Type": "application/json",
},
},
);
const respCanons = fetch(
$urlG + "/api/contratos/canon?id=" + contratoid,
{
method: "GET",
headers: {
"Auth": String(token),
}
});
const respoDefect = fetch($urlG+"/api/defectos?Idcontrato="+contratoid, {
Auth: String(token),
},
},
);
const respoDefect = fetch(
$urlG + "/api/defectos?Idcontrato=" + contratoid,
{
method: "GET",
headers: {
"Auth": token,
}
});
const [p, g, c, d] = await Promise.all([respPropiedad, respgarantes, respCanons, respoDefect]);
Auth: token,
},
},
);
const [p, g, c, d] = await Promise.all([
respPropiedad,
respgarantes,
respCanons,
respoDefect,
]);
const datosPropiedad = await p.json();
const datosGarantes = await g.json();
@@ -123,7 +163,6 @@
garantes = datosGarantes;
canons = datosCanons;
defectos = datosDefect;
} catch {
modaldata = "Fallo hacer las request";
}
@@ -137,12 +176,15 @@
async function refreshCanon() {
try {
const ret = await fetch($urlG+"/api/contratos/canon?id="+contratoid, {
const ret = await fetch(
$urlG + "/api/contratos/canon?id=" + contratoid,
{
method: "GET",
headers: {
"Auth": String(token),
}
});
Auth: String(token),
},
},
);
if (!ret.ok) {
let data = await ret.json();
modaldata = data.message;
@@ -162,12 +204,15 @@
return;
}
try {
const resp = await fetch ($urlG+"/api/contrato/DocumentoFinal?idcontrato="+prop.id, {
const resp = await fetch(
$urlG + "/api/contrato/DocumentoFinal?idcontrato=" + prop.id,
{
method: "GET",
headers: {
"Auth": String(token),
}
});
Auth: String(token),
},
},
);
if (!resp.ok) {
let blob = await resp.json();
@@ -177,7 +222,7 @@
let blob = await resp.blob();
const blobUrl = URL.createObjectURL(blob);
window.open(blobUrl, '_blank');
window.open(blobUrl, "_blank");
setTimeout(() => URL.revokeObjectURL(blobUrl), 100000);
} catch {
modaldata = "fallo intentar hacer la request";
@@ -189,7 +234,7 @@
const ret = await fetch($urlG + "/api/contratos/realizarPago", {
method: "POST",
headers: {
"Auth": String(token),
Auth: String(token),
"Content-Type": "application/json",
},
body: JSON.stringify({ idcontrato: contratoid, fecha: mes }),
@@ -197,7 +242,7 @@
let data = await ret.json();
modaldata = data.message;
if (ret.ok) {
refreshCanon()
refreshCanon();
return;
}
} catch {
@@ -205,7 +250,6 @@
}
}
function generarTiket(mod: any) {
selMod = mod;
showmodal = true;
@@ -213,15 +257,21 @@
async function pedirdocumento(op: boolean) {
try {
const ret = await fetch($urlG+"/api/contrato/GenerarRecibo?html="+op, {
const ret = await fetch(
$urlG + "/api/contrato/GenerarRecibo?html=" + op,
{
method: "POST",
headers: {
"Auth": String(token),
Auth: String(token),
"Content-Type": "application/json",
},
body: JSON.stringify({fecha: selMod.mes, idcontrato: contratoid})
});
body: JSON.stringify({
fecha: selMod.mes,
idcontrato: contratoid,
}),
},
);
if (!ret.ok) {
let blob = await ret.json();
modaldata = blob.message;
@@ -229,7 +279,7 @@
}
let blob = await ret.blob();
const blobUrl = URL.createObjectURL(blob);
window.open(blobUrl, '_blank');
window.open(blobUrl, "_blank");
setTimeout(() => URL.revokeObjectURL(blobUrl), 100000);
} catch {
modaldata = "Fallo al intentar hacer la request";
@@ -242,7 +292,7 @@
const r = await fetch($urlG + "/api/defecto", {
method: "POST",
headers: {
"Auth": String(token),
Auth: String(token),
"Content-Type": "application/json",
},
body: JSON.stringify(data),
@@ -259,28 +309,35 @@
async function refreshDefectos() {
try {
const r = await fetch($urlG+"/api/defectos?Idcontrato="+contratoid, {
const r = await fetch(
$urlG + "/api/defectos?Idcontrato=" + contratoid,
{
method: "GET",
headers: {
"Auth": token,
}
});
Auth: token,
},
},
);
let rr = await r.json();
defectos = rr;
} catch {
modaldata = "No se pudo pedir la lista de Defectos";
}
}
async function ejercerOpcionVenta() {
try {
const r = await fetch($urlG+"/api/ventas/ejercerOpcionVenta?idcontrato="+contratoid, {
const r = await fetch(
$urlG +
"/api/ventas/ejercerOpcionVenta?idcontrato=" +
contratoid,
{
method: "POST",
headers: {
"Auth": token,
}
});
Auth: token,
},
},
);
let data = await r.json();
modaldata = data.message;
if (r.ok) {
@@ -300,7 +357,10 @@
{/if}
{#if showmodal}
<ModalPedirDoc onClose={()=>showmodal=false} onSubmit={pedirdocumento} />
<ModalPedirDoc
onClose={() => (showmodal = false)}
onSubmit={pedirdocumento}
/>
{/if}
<div class="container-fluid mt-4 d-flex">
@@ -315,7 +375,10 @@
<p><b>Habitaciones:</b> {prop.habitaciones}</p>
<p><b>Piso:</b> {prop.piso}</p>
<p><b>Letra:</b> {prop.letra}</p>
<p><b>Fecha Inicio:</b> {String(prop.fechainicio).split("T")[0]}</p>
<p>
<b>Fecha Inicio:</b>
{String(prop.fechainicio).split("T")[0]}
</p>
<p><b>Estado:</b> {prop.estado}</p>
<button class="btn btn-secondary" onclick={verContrato}>
Ver Contrato
@@ -386,7 +449,7 @@
aria-expanded="false"
aria-controls="collapseTwo"
>
Canons
Canones
</button>
</h2>
<div
@@ -404,16 +467,42 @@
{canon.mesNum}/{prop.mesesDuracion}
</div>
<div class="card-body">
<p><strong>Mes:</strong> {String(canon.mes).split("T")[0]}</p>
<p><strong>Monto:</strong> {canon.monto}</p>
<p><strong>Divisa:</strong> {canon.divisa}</p>
<p><strong>Pago:</strong> {canon.pago ? "Sí" : "No"}</p>
<p>
<strong>Mes:</strong>
{String(canon.mes).split(
"T",
)[0]}
</p>
<p>
<strong>Monto:</strong>
{canon.monto}
</p>
<p>
<strong>Divisa:</strong>
{canon.divisa}
</p>
<p>
<strong>Pago:</strong>
{canon.pago ? "Sí" : "No"}
</p>
</div>
<div class="card-footer d-flex justify-content-between">
<button class="btn btn-primary btn-xs" disabled={canon.pago} onclick={()=>realizarpago(canon.mes)}>
<div
class="card-footer d-flex justify-content-between"
>
<button
class="btn btn-primary btn-xs"
disabled={canon.pago}
onclick={() =>
realizarpago(canon.mes)}
>
Pagar
</button>
<button class="btn btn-info btn-xs" disabled={!canon.pago} onclick={()=> generarTiket(canon)}>
<button
class="btn btn-info btn-xs"
disabled={!canon.pago}
onclick={() =>
generarTiket(canon)}
>
Generar Tiket
</button>
</div>
@@ -443,7 +532,6 @@
aria-labelledby="ht"
data-bs-parent="#accordionExample"
>
<div class="accordion-body">
{#if prop.estado != "Terminado"}
<div class="card">
@@ -451,13 +539,14 @@
Notificar Defecto en Propiedad
</div>
<div class="card-body">
<FormAltaDefecto onConfirm={cargarDefecto} idcontrato={prop.id} />
<FormAltaDefecto
onConfirm={cargarDefecto}
idcontrato={prop.id}
/>
</div>
<div class="card-footer">
<div class="card-footer"></div>
</div>
</div>
<br>
<br />
{/if}
<table class="table table-hover table-striped">
<thead>
@@ -472,7 +561,9 @@
<tbody>
{#if defectos.length == 0}
<tr>
<td colspan="6">No hay defectos que mostrar</td>
<td colspan="6"
>No hay defectos que mostrar</td
>
</tr>
{:else}
{#each defectos as defecto}
@@ -491,7 +582,6 @@
</div>
</div>
{#if TieneOpcionVenta}
<div class="accordion-item">
<h2 class="accordion-header" id="hq">
<button
@@ -502,7 +592,7 @@
aria-expanded="false"
aria-controls="cq"
>
Opcion Venta
Opcion Compra
</button>
</h2>
<div
@@ -514,26 +604,45 @@
<div class="accordion-body">
<div class="card">
<div class="card-header">
Datos Opcion Venta
Datos Opcion Compra
</div>
<div class="card-body">
<b>Monto</b>: {dtoVenta.divisa} {dtoVenta.monto}.
<b>Monto</b>: {dtoVenta.divisa}
{dtoVenta.monto}.
<p class="mt-2 text-muted">
Para poder ejercer la opcion de venta necesitas estar en el mismo mes que el ultimo pago y haber pagado todos los canones
Para poder ejercer la opcion de venta
necesitas estar en el mismo mes que el
ultimo pago y haber pagado todos los
canones
</p>
<div class="d-flex justify-content-between">
<button class="btn btn-primary" disabled={dtoVenta.enOrden==false || dtoVenta.fueEjercido == true} onclick={()=>ejercerOpcionVenta()}>
<button
class="btn btn-primary"
disabled={dtoVenta.enOrden ==
false ||
dtoVenta.fueEjercido == true}
onclick={() => ejercerOpcionVenta()}
>
Ejercer
</button>
{#if dtoVenta.fueEjercido}
<button class="btn btn-secondary" onclick={()=>navigate("/Ventas?idventa="+dtoVenta.id)}>
<button
class="btn btn-secondary"
onclick={() =>
navigate(
"/Ventas?idventa=" +
dtoVenta.id,
)}
>
Ir a la pagina de la Venta
</button>
{/if}
</div>
</div>
<div class="card-footer text-center">IdOpcionVenta: {dtoVenta.id}</div>
<div class="card-footer text-center">
IdOpcionVenta: {dtoVenta.id}
</div>
</div>
</div>
</div>

View File

@@ -363,7 +363,7 @@
if (canons.length > 0) {
contenido += "ID,Mes Num,Mes,Monto,Divisa,Pago\n";
canons.forEach(c => {
let fila = [c.id, c.mesNum, String(c.mes).split("T")[0], c.monto, c.divisa, c.pago ? "Sí" : "No"].join(",");
let fila = [c.id, c.mesNum, String(c.mes).split("T")[0], c.monto, c.divisa, c.pago ? "Si" : "No"].join(",");
contenido += fila + "\n";
});
}
@@ -505,7 +505,7 @@
aria-expanded="false"
aria-controls="collapseTwo"
>
Canons
Canones
</button>
</h2>
<div
@@ -642,7 +642,7 @@
aria-expanded="false"
aria-controls="cq"
>
Opcion Venta
Opcion Compra
</button>
</h2>
<div
@@ -654,13 +654,13 @@
<div class="accordion-body">
<div class="card">
<div class="card-header">
Datos Opcion Venta
Datos Opcion Compra
</div>
<div class="card-body">
<b>Monto</b>: {dtoVenta.divisa} {dtoVenta.monto}.
<p class="mt-2 text-muted">
Para que el inquilino pueda ejercer la opcion de venta necesitas estar en el mismo mes que el ultimo pago y haber pagado todos los canones
Para que el inquilino pueda ejercer la opcion de Compra necesitas estar en el mismo mes que el ultimo pago y haber pagado todos los canones
</p>
<div class="d-flex">
<button class="btn btn-primary" disabled={!dtoVenta.fueEjercido} onclick={()=>navigate("/Ventas?idventa="+dtoVenta.id)}>

View File

@@ -0,0 +1,173 @@
<script lang="ts">
import { onMount } from "svelte";
import BarraHorizontalConTexto from "../Componentes/BarraHorizontalConTexto.svelte";
import ModalEstatico from "../Componentes/ModalEstatico.svelte";
import NavBarAutocompletable from "../Componentes/NavBarAutocompletable.svelte";
import { urlG } from "../stores/urlStore";
import type { CrearUsuario, Grupo, GrupoDto } from "../types";
let formData: CrearUsuario = $state({
Dni: 0,
Nombre: '',
Apellido: '',
Domicilio: '',
Celular: '',
Email: '',
Contraseña: '',
EmailRecuperacion: null,
grupos: []
});
let token = sessionStorage.getItem("token");
let grupos: GrupoDto[] = $state([]);
let modaldata: string = $state("");
onMount(async ()=>{
obtenerGrupos();
});
async function obtenerGrupos(){
try {
const req = await fetch($urlG+ "/api/admin/grupos", {
method: "GET",
headers: {
"Auth": token,
}
});
let data = await req.json();
if (req.ok){
grupos= data;
} else{
modaldata = data.message;
}
} catch{
modaldata = "Fallo al hacer la request";
}
}
const resetForm = () => {
formData = {
Dni: 0,
Nombre: '',
Apellido: '',
Domicilio: '',
Celular: '',
Email: '',
Contraseña: '',
EmailRecuperacion: null,
grupos: []
};
};
async function handleSubmit(e:Event){
e.preventDefault();
try{
const req = await fetch($urlG +"/api/crearusuario", {
method: "POST",
headers: {
"Auth": token,
"Content-Type": "Application/json"
},
body: JSON.stringify(formData)
});
let data = await req.json();
modaldata = data.message;
if (req.ok){
resetForm();
}
}catch {
modaldata = "Fallo al hacer la request";
}
}
const toggleGrupo = (id: number) => {
const index = formData.grupos.indexOf(id);
if (index === -1) {
formData.grupos = [...formData.grupos, id];
} else {
formData.grupos = formData.grupos.filter(g => g !== id);
}
};
</script>
{#if modaldata}
<ModalEstatico payload={modaldata} close={()=>!!(modaldata="")}/>
{/if}
<NavBarAutocompletable/>
<div class="container mt-4">
<BarraHorizontalConTexto text="Crear Usuario" />
<form onsubmit={(e)=>handleSubmit(e)} class="row g-3 mt-2" id="formcrearusu">
<!-- DNI -->
<div class="col-md-6">
<label for="dni" class="form-label">DNI</label>
<input type="number" min="0" max="99999999" id="dni" bind:value={formData.Dni} class="form-control" required />
</div>
<!-- Nombre -->
<div class="col-md-6">
<label for="nombre" class="form-label">Nombre</label>
<input type="text" id="nombre" bind:value={formData.Nombre} class="form-control" maxlength="20" required/>
</div>
<!-- Apellido -->
<div class="col-md-6">
<label for="apellido" class="form-label">Apellido</label>
<input type="text" id="apellido" bind:value={formData.Apellido} class="form-control" maxlength="20" required/>
</div>
<!-- Domicilio -->
<div class="col-md-6">
<label for="domicilio" class="form-label">Domicilio</label>
<input type="text" id="domicilio" bind:value={formData.Domicilio} class="form-control" maxlength="40" required/>
</div>
<!-- Celular -->
<div class="col-md-6">
<label for="celular" class="form-label">Celular</label>
<input type="tel" id="celular" bind:value={formData.Celular} class="form-control" maxlength="40" required/>
</div>
<!-- Email -->
<div class="col-md-6">
<label for="email" class="form-label">Email</label>
<input type="email" id="email" bind:value={formData.Email} class="form-control" maxlength="50" required/>
</div>
<!-- Email Recuperación -->
<div class="col-md-6">
<label for="recuperacion" class="form-label">Email de Recuperación</label>
<input type="email" id="recuperacion" bind:value={formData.EmailRecuperacion} class="form-control" maxlength="50" />
</div>
<!-- Contraseña -->
<div class="col-md-6">
<label for="contrasena" class="form-label">Contraseña</label>
<input type="password" id="contrasena" bind:value={formData.Contraseña} class="form-control" required minlength="8"/>
</div>
<!-- Grupos -->
<div class="col-md-6">
<p class="form-label">Selecciona Grupos</p>
<div class="d-flex flex-wrap gap-2">
{#each grupos as grupo}
<button
type="button"
class="btn {formData.grupos.includes(grupo.idgrupo) ? 'btn-primary' : 'btn-outline-secondary'}"
onclick={() => toggleGrupo(grupo.idgrupo)}
>
{grupo.nombre}
</button>
{/each}
</div>
</div>
<!-- Botón -->
<div class="col-12 mt-3">
<button type="submit" class="btn btn-success">Crear Usuario</button>
</div>
</form>
</div>

View File

@@ -0,0 +1,183 @@
<script lang="ts">
import { onMount } from "svelte";
import NavBarAutocompletable from "../Componentes/NavBarAutocompletable.svelte";
import type { GrupoDto, PermisoDto } from "../types";
import { urlG } from "../stores/urlStore";
import ModalEstatico from "../Componentes/ModalEstatico.svelte";
import BarraHorizontalConTexto from "../Componentes/BarraHorizontalConTexto.svelte";
import BotonEsquina from "../Componentes/BotonEsquina.svelte";
import ModalEditarPermiso from "../Componentes/ModalEditarPermiso.svelte";
const token: string = sessionStorage.getItem("token") || "";
let permisos: PermisoDto[] = $state([]);
let selpermiso: PermisoDto = $state({ descripcion: "", id: 0 });
let modaldat: string = $state("");
let showmodaladd = $state(false);
let showmodaledit = $state(false);
onMount(() => {
obtenerPermisos();
});
async function submitedit(a: GrupoDto) {
let b = a;
try {
let req = await fetch($urlG + "/api/grupo", {
method: "PATCH",
headers: {
Auth: token,
"Content-Type": "application/json",
},
body: JSON.stringify(b),
});
const resp = await req.json();
modaldat = resp.message;
if (req.ok) {
obtenerPermisos;
}
} catch {
modaldat = "Fallo al hacer la request";
}
}
async function obtenerPermisos() {
try {
let a = await fetch($urlG + "/api/permisos/todos", {
method: "GET",
headers: {
Auth: token,
},
});
if (!a.ok) {
modaldat = "Fallo al obtener los permisos";
return;
}
permisos = await a.json();
} catch {
modaldat = "Fallo Al intentar hacer la request";
}
}
async function NuevoPermiso(a: PermisoDto) {
let b = a;
try {
const req = await fetch($urlG + "/api/permisos", {
method: "POST",
headers: {
Auth: token,
"Content-Type": "application/json",
},
body: JSON.stringify(b),
});
if (req.ok) {
obtenerPermisos();
return;
}
modaldat = "Hubieron problemas creando el permiso";
return;
} catch {
modaldat = "Fallo al hacer la request";
}
}
async function PatchPermiso(a: PermisoDto) {
let b = a;
try {
const req = await fetch($urlG + "/api/permisos", {
method: "PATCH",
headers: {
Auth: token,
"Content-Type": "application/json",
},
body: JSON.stringify(b),
});
if (req.ok) {
obtenerPermisos();
return;
}
modaldat = "Hubieron problemas editando el permiso";
return;
} catch {
modaldat = "Fallo al hacer la request";
}
}
</script>
{#if modaldat != ""}
<ModalEstatico payload={modaldat} close={() => !!(modaldat = "")} />
{/if}
<NavBarAutocompletable />
<div class="container-fluid mt-2">
<BarraHorizontalConTexto text="Gestionar Permisos" />
{#if permisos.length == 0}
<div class="text-center">
<div class="spinner-border" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</div>
{:else}
<div class="position-relative z-1">
<BotonEsquina handleclick={() => (showmodaladd = true)} />
</div>
{#if showmodaladd}
<ModalEditarPermiso
onClose={() => (showmodaladd = false)}
permiso={{ descripcion: "", id: 0 }}
onSubmit={NuevoPermiso}
modalTitle="Nuevo Permiso"
/>
{/if}
{#if showmodaledit}
<div class="position-relative z-2">
<ModalEditarPermiso
onClose={(a: string) => {
showmodaledit = false;
selpermiso.descripcion = a;
}}
bind:permiso={selpermiso}
onSubmit={PatchPermiso}
modalTitle="Modificar Permiso"
/>
</div>
{/if}
<div class="card mb-3">
<div class="card-body">
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th scope="col">ID</th>
<th scope="col">Descripción</th>
<th scope="col">Acciones</th>
</tr>
</thead>
<tbody>
{#each permisos as permiso}
<tr>
<td>{permiso.id}</td>
<td>{permiso.descripcion}</td>
<td>
<div
class="d-flex justify-content-between"
>
<button
class="btn btn-warning btn-sm"
onclick={() => {
showmodaledit = true;
selpermiso = permiso;
}}>Editar</button
>
</div>
</td>
</tr>
{/each}
</tbody>
</table>
</div>
</div>
</div>
{/if}
</div>

View File

@@ -5,17 +5,24 @@
import FChart from "../Componentes/Estadisticas/fChart.svelte";
import ModalEstatico from "../Componentes/ModalEstatico.svelte";
import { urlG } from "../stores/urlStore";
import type { ChartData } from "../types";
import type { ChartData, IngresosDto } from "../types";
let token = sessionStorage.getItem("token") || "";
let y = $state(2025);
let cdata: ChartData | any = $state();
let aldata:{id:number, ubicacion:string, divisa:string}[]= $state([]);
let aldata: { id: number; ubicacion: string; divisa: string }[] = $state(
[],
);
let chartMesesDuracion: ChartData | any = $state();
let tablaMesesDuracion:{meses:number, repes:number, semaforizacion:string}[] = $state([]);
let tablaMesesDuracion: {
meses: number;
repes: number;
semaforizacion: string;
}[] = $state([]);
let showModoDaltonico: boolean = $state(false);
let modaldata: string = $state("");
onMount(async () => {
@@ -24,18 +31,24 @@
async function dataAlquileresporAño(year = 2025) {
try {
const rep = fetch($urlG+"/api/stats/alquileresIniciados?year="+year, {
const rep = fetch(
$urlG + "/api/stats/alquileresIniciados?year=" + year,
{
method: "GET",
headers: {
"Auth": token,
}
});
const pre = fetch($urlG+"/api/tabla/alquileresIniciados?year="+year, {
Auth: token,
},
},
);
const pre = fetch(
$urlG + "/api/tabla/alquileresIniciados?year=" + year,
{
method: "GET",
headers: {
"Auth": token,
}
});
Auth: token,
},
},
);
let [r, p] = await Promise.all([rep, pre]);
let data = await r.json();
@@ -55,17 +68,17 @@
const p1 = fetch($urlG + "/api/stats/duracionContrato", {
method: "GET",
headers: {
"Auth": token,
}
Auth: token,
},
});
const p2 = fetch($urlG + "/api/tabla/duracionContrato", {
method: "GET",
headers: {
"Auth": token,
}
Auth: token,
},
});
let [r1, r2] = await Promise.all([p1, p2]);
let [d1,d2] = await Promise.all([r1.json(), r2.json()])
let [d1, d2] = await Promise.all([r1.json(), r2.json()]);
chartMesesDuracion = d1;
tablaMesesDuracion = d2;
} catch {
@@ -76,14 +89,45 @@
function toggleModoDaltonico() {
if (tablaMesesDuracion == null) return;
tablaMesesDuracion.forEach(item => {
if (item.semaforizacion === '🟢') {
item.semaforizacion = '🔵';
} else if (item.semaforizacion === '🔵') {
item.semaforizacion = '🟢';
tablaMesesDuracion.forEach((item) => {
if (item.semaforizacion === "🟢") {
item.semaforizacion = "🔵";
} else if (item.semaforizacion === "🔵") {
item.semaforizacion = "🟢";
}
});
}
const nombresMeses = [
"Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio",
"Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"
];
let ingresos: IngresosDto[] = $state([]);
let chartingresos: ChartData | null = $state(null);
let yearr:number = $state(0);
async function getIngresos(year:number) {
try{
const req = await fetch($urlG+"/api/stats/Pagos?year="+year, {
method:"GET",
headers: {
"Auth": token || "",
},
});
const data = await req.json();
if (req.ok){
ingresos = data.tabla.map(item => ({
...item,
mes: nombresMeses[Number(item.mes) - 1]
}));
chartingresos = data.chart;
} else {
modaldata = data.message;
}
}catch{
modaldata="Fallo la req para obtener ingresos";
}
}
</script>
{#if modaldata}
@@ -98,23 +142,43 @@
<div class="accordion" id="accordionExample">
<div class="accordion-item">
<h2 class="accordion-header" id="hea1">
<button class="accordion-button"
<button
class="accordion-button"
type="button"
data-bs-toggle="collapse"
data-bs-target="#c1"
aria-expanded="true"
aria-controls="c1">
Alquileres en el ultimo año
aria-controls="c1"
>
Alquileres Por Mes
</button>
</h2>
<div class="accordion-collapse collapse show" id="c1" data-bs-parent="#accordionExample">
<div
class="accordion-collapse collapse show"
id="c1"
data-bs-parent="#accordionExample"
>
<div class="accordion-body row">
<div class="col">
<div class="d-flex input-group">
<input class="form-control" type="number" bind:value={y}>
<button class="btn btn-primary" onclick={()=>dataAlquileresporAño(y)}><img src="/zoom.svg" alt="lupa" aria-label="Lupa">Buscar</button>
<input
class="form-control"
type="number"
bind:value={y}
/>
<button
class="btn btn-primary"
onclick={() => dataAlquileresporAño(y)}
><img
src="/zoom.svg"
alt="lupa"
aria-label="Lupa"
/>Buscar</button
>
</div>
<p class="text-muted">
Todos los Alquileres de un año mostrados por mes
</p>
<table class="table table-hover">
<thead>
<tr>
@@ -144,27 +208,51 @@
</div>
<div class="accordion-item">
<h2 class="accordion-header" id="hea2">
<button class="accordion-button"
<button
class="accordion-button collapsed"
type="button"
data-bs-toggle="collapse"
data-bs-target="#c2"
aria-expanded="false"
aria-controls="c2"
onclick={() => {
if (visibleMesesDuracion === true) {
visibleMesesDuracion = false;
return;
} else if (visibleMesesDuracion== false){
} else if (visibleMesesDuracion === false) {
visibleMesesDuracion = true;
showModoDaltonico = false;
dataMesesDuracion();
}
}}
>
Meses De Duracion
</button>
</h2>
<div class="accordion-collapse collapse" id="c2" data-bs-parent="#accordionExample">
<div
class="accordion-collapse collapse"
id="c2"
data-bs-parent="#accordionExample"
>
<div class="accordion-body row">
<div class="col">
<p class="text-muted">Objetivo: <i>Mide la longitud de los contratos en meses y cuantos hay por cada longitud. por lo menos 2.</i></p>
<input class="form-check-input" type="checkbox" onclick={toggleModoDaltonico}> Activar Modo Daltónico
<p class="text-muted">
Objetivo: <i
>Mide la longitud de los contratos en meses
y cuantos hay por cada longitud. por lo
menos 2.</i
>
</p>
<input
class="form-check-input"
type="checkbox"
onclick={() => {
showModoDaltonico = !showModoDaltonico;
toggleModoDaltonico();
}}
checked={showModoDaltonico}
/>
Activar Modo Daltónico
<table class="table table-hover">
<thead>
<tr>
@@ -186,7 +274,95 @@
</div>
<div class="col-md-4">
{#if chartMesesDuracion}
<FChart chartData={chartMesesDuracion} typec="pie"/>
<FChart
chartData={chartMesesDuracion}
typec="pie"
/>
{/if}
</div>
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header">
<button class="accordion-button collapsed"
type="button"
data-bs-toggle="collapse"
data-bs-target="#c3"
aria-expanded="false"
aria-controls="c3"
onclick={async ()=> {
if (yearr ==0){
yearr = new Date().getFullYear();
getIngresos(yearr);
} else if (yearr != 0){
yearr = 0;
}}}
>
Estado Pagos por Mes
</button>
</h2>
<div class="accordion-collapse collapse" id="c3"
data-bs-parent="#accordionExample"
>
<div class="accordion-body row">
<div class="col">
<div class="d-flex input-group">
<input
class="form-control"
type="number"
bind:value={yearr}
/>
<button
class="btn btn-primary"
onclick={() => getIngresos(yearr)}
><img
src="/zoom.svg"
alt="lupa"
aria-label="Lupa"
/>Buscar</button
>
</div>
<p class="text-muted">
Todos los canones ya sean pagados, Pagados Atrasados o Sin Realizar
</p>
{#if ingresos.length == 0}
<div class="d-flex justify-content-center align-items-center mt-3">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Cargando...</span>
</div>
</div>
{:else}
<table class="table table-striped table-hover">
<thead>
<tr>
<th>Mes</th>
<th>Pagos Realizados</th>
<th>Pagos Atrasados</th>
<th>Pagos Sin Realizar</th>
</tr>
</thead>
<tbody>
{#each ingresos as i }
<tr>
<td>{i.mes}</td>
<td>{i.realizados}</td>
<td>{i.atrasados}</td>
<td>{i.sin_realizar}</td>
</tr>
{/each}
</tbody>
</table>
{/if}
</div>
<div class="col">
{#if chartingresos != null}
<FChart
chartData={chartingresos}
typec="line"
/>
{/if}
</div>
</div>

View File

@@ -1,7 +1,7 @@
<script lang="ts">
import { onMount } from "svelte";
import NavBarAutocompletable from "../Componentes/NavBarAutocompletable.svelte";
import type { GaranteDto, MensajeDto } from "../types";
import type { GaranteDto, MensajeDto, PreContratoData } from "../types";
import ModalEstatico from "../Componentes/ModalEstatico.svelte";
import { urlG } from "../stores/urlStore";
import ModalConfirm from "../Componentes/ModalConfirm.svelte";
@@ -113,6 +113,7 @@
if (mensaje.accion === "Carge Garantes") {
Selmens = { ...mensaje };
setCantGarantes = Number(Selmens.mensaje.split(" ").reverse()[1]);
ObtenerDatosPreContrato();
return;
}
@@ -467,6 +468,28 @@
}
showConsultaCompra = false; Selmens.accion = "";
}
let datosprecontrato: PreContratoData = $state({});
async function ObtenerDatosPreContrato(){
try {
const req = await fetch($urlG + "/api/precontrato/preCargaGarantes/data?propiedadId="+Selmens.propiedad, {
method: 'GET',
headers: {
"Auth": token || "",
}
});
const data = await req.json();
if (req.ok){
datosprecontrato = data;
return;
}
modaldata = data.message;
} catch {
modaldata = "Fallo al obtener los datos del precontrato";
}
}
</script>
<NavBarAutocompletable/>
@@ -478,7 +501,7 @@
{#if Selmens.accion == "Nuevo Alquiler" }
<ModalPrecontrato onClose={() => (Selmens.accion = "")} onSubmit={handleEnviarmensaje2} />
{:else if Selmens.accion == "Carge Garantes"}
<ModalAddGarantes maxGarantes={setCantGarantes} onClose={() => (Selmens.accion = "")} onSubmit={handleEnviarmensaje3}/>
<ModalAddGarantes maxGarantes={setCantGarantes} onClose={() => (Selmens.accion = "")} onSubmit={handleEnviarmensaje3} {datosprecontrato}/>
{:else if Selmens.accion == "Check y Contrato"}
<ModalCheckYContrato {garantes} men={Selmens} onCancel={handleCancelPrecontrato} onClose={() => (Selmens.accion = "")} onConfirm={handleEnviarmensaje4}/>
{:else if Selmens.accion == "Aceptar Contrato"}

View File

@@ -0,0 +1,296 @@
<script lang="ts">
import { onMount } from "svelte";
import NavBarAutocompletable from "../Componentes/NavBarAutocompletable.svelte";
import BarraHorizontalConTexto from "../Componentes/BarraHorizontalConTexto.svelte";
import type { ClientePanel } from "../types";
import { urlG } from "../stores/urlStore";
import ModalEstatico from "../Componentes/ModalEstatico.svelte";
let token: string = sessionStorage.getItem("token") || "";
let user: ClientePanel | null = $state(null);
let showmodal: boolean = $state(false);
let showrecuperacionset: boolean = $state(false);
let modaldata: string = $state("");
onMount(async () => {
fetchusuario();
});
async function fetchusuario() {
try {
let req = await fetch($urlG + "/api/usuario", {
method: "GET",
headers: {
Auth: token,
},
});
if (!req.ok) {
modaldata = (await req.json()).message;
return;
}
user = await req.json();
} catch {
modaldata = "no se pudo hacer la request";
}
}
async function submitpass(e: Event) {
e.preventDefault();
const target = e.target as HTMLFormElement;
const passwordInput = target.querySelector(
"#contraseña",
) as HTMLInputElement;
const password = passwordInput.value;
try {
let req = await fetch($urlG + "/api/usuario", {
method: "PATCH",
headers: { Auth: token, "Content-Type": "application/json" },
body: JSON.stringify({ contraseña: password }),
});
showmodal = false;
modaldata = (await req.json()).message;
return;
} catch {
modaldata = "no se pudo hacer la request";
}
}
async function submitemail(e: Event) {
e.preventDefault();
const t = e.target as HTMLFormElement;
const emailinput = t.querySelector(
"#emailRecuperacion",
) as HTMLInputElement;
const email: string = emailinput.value;
try {
let req = await fetch($urlG + "/api/usuario/emailrecuperacion", {
method: "PUT",
headers: { Auth: token, "Content-Type": "Application/json" },
body: JSON.stringify({ EmailRecuperacion: email }),
});
showmodal = false;
modaldata = (await req.json()).message;
if (req.ok) {
fetchusuario();
}
showrecuperacionset = false;
} catch {
modaldata = "no se pudo hacer la request";
showrecuperacionset = false;
}
}
</script>
{#if modaldata}
<ModalEstatico close={() => !!(modaldata = "")} payload={modaldata} />
{/if}
<NavBarAutocompletable />
<div class="mt-2">
<BarraHorizontalConTexto text="Panel de Usuario" />
</div>
<div
class="container d-flex justify-content-center align-items-center flex-column mt-2 mx-auto"
>
<!-- Información del Usuario -->
<div class="w-75 mb-4">
<div class="card">
<div class="card-header bg-primary text-white">
<h5 class="mb-0">Información Personal</h5>
</div>
<div class="card-body">
{#if !user}
<div class="d-flex justify-content-center my-5">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Cargando...</span>
</div>
</div>
{:else}
<div class="mb-3">
<h6 class="text-muted fw-bold">DNI</h6>
<p class="lead">{user.dni}</p>
</div>
<div class="mb-3">
<h6 class="text-muted fw-bold">Nombre</h6>
<p class="lead">{user.nombre}</p>
</div>
<div class="mb-3">
<h6 class="text-muted fw-bold">Apellido</h6>
<p class="lead">{user.apellido}</p>
</div>
<div class="mb-3">
<h6 class="text-muted fw-bold">Domicilio</h6>
<p class="lead">{user.domicilio}</p>
</div>
<div class="mb-3">
<h6 class="text-muted fw-bold">Celular</h6>
<p class="lead">{user.celular}</p>
</div>
<div class="mb-3">
<h6 class="text-muted fw-bold">Correo Electrónico</h6>
<p class="lead">{user.email}</p>
</div>
<div class="mb-3">
<button
class="btn btn-primary"
onclick={() => (showmodal = true)}
>Cambiar Contraseña</button
>
</div>
{/if}
</div>
</div>
</div>
<!-- Esto es un modal para el cambio de contraseña -->
{#if showmodal}
<div
class="modal show d-block"
tabindex="-1"
style="background-color: rgba(0,0,0,0.3);"
>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Ingrese información</h5>
<button
type="button"
class="btn-close"
onclick={() => (showmodal = false)}
aria-label="Close"
></button>
</div>
<form onsubmit={submitpass}>
<div class="modal-body">
<div class="mb-3">
<div class="mb-3 text-muted">
<small
>La contraseña debe tener al menos 8
caracteres</small
>
</div>
<label for="contraseña" class="form-label"
>Contraseña</label
>
<input
type="text"
class="form-control"
id="contraseña"
placeholder="********"
/>
</div>
</div>
<div
class="modal-footer d-flex justify-content-between"
>
<button
type="button"
class="btn btn-secondary"
onclick={() => (showmodal = false)}
>Cerrar</button
>
<button type="submit" class="btn btn-primary"
>Guardar cambios</button
>
</div>
</form>
</div>
</div>
</div>
{/if}
<!-- Información de Correo de Recuperación -->
<div class="w-75 mb-4">
<div class="card">
<div class="card-header bg-secondary text-white">
<h5 class="mb-0">Correo de Recuperación</h5>
</div>
<div class="card-body">
{#if !user}
<div class="d-flex justify-content-center my-5">
<div class="spinner-border text-info" role="status">
<span class="visually-hidden">Cargando...</span>
</div>
</div>
{:else}
<div class="mb-3">
<h6 class="text-muted fw-bold">
Email de Recuperación
</h6>
<p class="lead">
{user.emailRecuperacion || "No configurado"}
</p>
</div>
<div class="mb-3">
<button
class="btn btn-secondary text-white"
onclick={() => (showrecuperacionset = true)}
>Actualizar Email de Recuperación</button
>
</div>
{#if showrecuperacionset}
<div
class="modal show d-block"
tabindex="-1"
style="background-color: rgba(0,0,0,0.3);"
>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">
Actualizar Email de Recuperación
</h5>
<button
type="button"
class="btn-close"
onclick={() =>
(showrecuperacionset = false)}
aria-label="Close"
></button>
</div>
<form onsubmit={(e) => submitemail(e)}>
<div class="modal-body">
<div class="mb-3">
<label
for="emailRecuperacion"
class="form-label"
>Email de Recuperación</label
>
<input
type="email"
class="form-control"
id="emailRecuperacion"
placeholder="correo@ejemplo.com"
/>
</div>
</div>
<div
class="modal-footer d-flex justify-content-between"
>
<button
type="button"
class="btn btn-secondary"
onclick={() =>
(showrecuperacionset = false)}
>Cancelar</button
>
<button
type="submit"
class="btn btn-primary"
>Guardar</button
>
</div>
</form>
</div>
</div>
</div>
{/if}
{/if}
</div>
</div>
</div>
</div>

View File

@@ -26,8 +26,8 @@
const r = await fetch($urlG + "/api/Logs/cantPag", {
method: "GET",
headers: {
"Auth": token,
}
Auth: token,
},
});
let data = await r.json();
if (r.ok) {
@@ -45,8 +45,8 @@
const r = await fetch($urlG + "/api/Logs?pag=" + pagina, {
method: "GET",
headers: {
"Auth": token,
}
Auth: token,
},
});
let data = await r.json();
if (r.ok) {
@@ -81,6 +81,10 @@
<div class="container-fluid mt-2">
<BarraHorizontalConTexto text={"Logs"} />
<div
class="table-container"
style="height: 80vh; overflow-y: auto; margin-bottom: 2.5rem;"
>
<table class="table table-responsive table-hover table-striped">
<thead>
<tr>
@@ -97,7 +101,10 @@
<td>{l.dniusuario}</td>
<td>{l.accion}</td>
<td>
<button class="btn btn-primary" onclick={()=>prepararModal(l)}>
<button
class="btn btn-primary"
onclick={() => prepararModal(l)}
>
Ver
</button>
</td>
@@ -105,7 +112,16 @@
{/each}
</tbody>
</table>
<div class="d-flex justify-content-center">
<PaginacionStepper currentPag={pagina} {cantpag} {queryPag} centrado={true}/>
<div
class="fixed-bottom w-100 d-flex justify-content-center border-top py-2"
style="background-color: rgba(0,0,0,0.5);"
>
<PaginacionStepper
currentPag={pagina}
{cantpag}
{queryPag}
centrado={true}
/>
</div>
</div>
</div>

View File

@@ -0,0 +1,15 @@
<script lang="ts">
import ListaAcciones from "../../Componentes/ListaAcciones.svelte";
import NavBarAutocompletable from "../../Componentes/NavBarAutocompletable.svelte";
let { id }: { id: string } = $props();
</script>
<NavBarAutocompletable />
<div class="container mt-5">
<div class="text-center mb-4">
<h1>Menu grupo: {id}</h1>
</div>
{#key id}
<ListaAcciones />
{/key}
</div>

50
Front/src/types.d.ts vendored
View File

@@ -219,3 +219,53 @@ export type PatchPropiedad = {
monto:number,
iddivisa:number
}
export type GrupoDto = {
idgrupo:number,
nombre:string,
habilitado:boolean
gruposIncluidos:string[],
permisos:PermisoDto[]
}
export type PermisoDto = {
id:number,
descripcion:string
}
export type ClientePanel = {
dni:number,
nombre:string,
apellido:string,
domicilio:string,
celular:string,
email:string,
emailRecuperacion:string|null
}
export type IngresosDto = {
mes:number,
realizados:number,
atrasados:number,
sin_realizar:number
}
export type CrearUsuario = {
Dni: number;
Nombre: string;
Apellido: string;
Domicilio: string;
Celular: string;
Email: string;
Contraseña: string;
EmailRecuperacion?: string | null;
grupos: number[];
}
export type PreContratoData = {
tieneOpcionDeVenta: boolean;
montoOpcionDeVenta?: number;
monedaOpcionDeVenta?: string;
duracionEnMeses: number;
frecuenciaAumentoEnMeses?: number | null;
};

View File

@@ -1,3 +1,4 @@
using System.Net;
using Entidades;
using Microsoft.EntityFrameworkCore;
@@ -28,6 +29,31 @@ public class AuditoriaFacade {
_persistenciaDeLog.GuardarLog(log, log.LogDetalles);
}
internal void GenerarLogLogin(long dni, string v, IPAddress? remoteIpAddress) {
var fechaActual = DateTime.Now;
var log = new Log{
Fecha = fechaActual,
Dniusuario = dni,
Accion = v
};
log.LogDetalles = new List<LogDetalle>([
new LogDetalle{
Id = 1,
Dniusuario = dni,
Fecha = fechaActual,
NombreTabla = "Logs",
Columna = "Login",
ValorAnterior = "",
ValorNuevo = $"Se Accedio con la direccion ip: {remoteIpAddress?.ToString() ?? "Desconocida"}",
}
]);
_persistenciaDeLog.GuardarLog(log, log.LogDetalles);
}
private List<LogDetalle> ProcesarCambios(IEnumerable<Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry> cambios,
DateTime fechaActual, long dniUsuario) {

View File

@@ -4,6 +4,81 @@ using Microsoft.EntityFrameworkCore;
namespace Modelo;
public class RepositorioContratos: RepositorioBase<RepositorioContratos> {
public bool GenerarCanones(long id = 0, long dni=0){
if (id == 0) return false;
var con = Context;
var cont = con.Contratos.Include(x=>x.IdpropiedadNavigation).FirstOrDefault(x=>x.Id == id && x.Cancelado == 0 && x.Habilitado == 0);
if (cont == null) return false;
cont.Habilitado = 1;
cont.Fechainicio = DateTime.Now;
var fecha = cont.Fechainicio;
cont.IdpropiedadNavigation.Monto = cont.Monto;
if (cont.MesesDurationContrato < cont.MesesHastaAumento)
{
for (int i = 0; i < cont.MesesDurationContrato; i++)
{
Canon can = new Canon
{
Fecha = fecha.AddMonths(i),
Monto = cont.IdpropiedadNavigation.Monto,
Pagado = 0,
};
can.Id = (con.Canons.Any() ? con.Canons.Count() : 0) + 1 + i;
con.Canons.Add(can);
cont.Idcanons.Add(can);
}
}
else
{
for (int i = 0; i < cont.MesesHastaAumento; i++)
{
Canon can = new Canon
{
Fecha = fecha.AddMonths(i),
Monto = cont.IdpropiedadNavigation.Monto,
Pagado = 0,
};
can.Id = (con.Canons.Any() ? con.Canons.Count() : 0) + 1 + i;
con.Canons.Add(can);
cont.Idcanons.Add(can);
}
}
// GenerarLog(con, dni, "Creacion de Canones");
return Guardar(con);
}
public bool AdminCargaContrato(Contrato? cont, long dni){
if (cont == null) return false;
var con = Context;
cont.Id = (con.Contratos.Any() ? con.Contratos.Max(x => x.Id) : 0) + 1;
foreach(Garante g in cont.Idgarantes){
g.Id = (con.Garantes.Any()?con.Garantes.Max(x=>x.Id): 0) + 1;
}
if (cont.IdventaNavigation != null){
cont.IdventaNavigation.Id = (con.Ventas.Any()?con.Ventas.Count():0)+1;
con.Ventas.Add(cont.IdventaNavigation);
}
var prop = con.Propiedades.FirstOrDefault(x=>x.Id == cont.Idpropiedad);
if (prop == null)return false;
prop.Idestado = 2;
con.Contratos.Add(cont);
GenerarLog(con, dni, "Carga del contrato por parte de admin");
return Guardar(con);
}
public IQueryable<Contrato>? ObtenerContratosPorEmailInquilino(string email) {
var con = Context;
try{
@@ -102,13 +177,15 @@ public class RepositorioContratos: RepositorioBase<RepositorioContratos> {
return contr;
}
public bool AddUrl(long id, string nuevoNombreArchivo, long dni) {
public bool AddUrl(long id, string nuevoNombreArchivo, long dni =0) {
var con = Context;
Contrato? contrato = con.Contratos
.FirstOrDefault(x=>x.Id == id);
if (contrato == null) return false;
contrato.UrlContrato = nuevoNombreArchivo;
if (dni != 0 ){
GenerarLog(con, dni, $"Añadido contrato");
}
return Guardar(con);
}
@@ -168,6 +245,16 @@ public class RepositorioContratos: RepositorioBase<RepositorioContratos> {
return Guardar(con);
}
public Contrato? ObtenerPreContratoPorIdDePropiedadyCliente(Cliente cli, int propiedadid){
var con = Context;
var cont = con.Contratos.Where(x=>x.Habilitado == 0ul && x.Cancelado == 0ul)
.Include(x=>x.IdventaNavigation)
.ThenInclude(x=>x.IddivisaNavigation)
.FirstOrDefault(x => x.Dniinquilino == cli.Dni && x.Idpropiedad == propiedadid);
return cont;
}
public IQueryable<Contrato> ObtenerContratosDePropietario(long dni) {
var con = Context;
var l = con.Contratos

View File

@@ -0,0 +1,10 @@
using Entidades;
namespace Modelo;
public class RepositorioDivisas: RepositorioBase<RepositorioDivisas> {
public List<Divisa> ObtenerDivisas(){
var con = Context;
var divisas = con.Divisas.ToList();
return divisas;
}
}

View File

@@ -4,6 +4,61 @@ using Microsoft.EntityFrameworkCore;
namespace Modelo;
public class RepositorioEstadisticas: RepositorioBase<RepositorioEstadisticas> {
public (ChartData, List<InformePagos>) InformePagos(int year) {
var con = Context;
ChartData data = new();
List<string> meses = ["Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"];
data.Labels = meses;
var canonData = con.Canons.Where(x => x.Fecha.Year == year)
.Include(x => x.IdreciboNavigation)
.Select(x => new {
Mes = x.Fecha.Month,
Pagado = x.Pagado,
CanonFecha = x.Fecha,
ReciboFecha = x.IdreciboNavigation != null ? x.IdreciboNavigation.Fecha : (DateTime?)null
})
.ToList();
var groupedData = canonData
.GroupBy(x => x.Mes)
.Select(g => new InformePagos {
Mes = g.Key,
Realizados = g.Count(x => x.Pagado == 1 && x.ReciboFecha.HasValue && x.ReciboFecha <= x.CanonFecha),
Atrasados = g.Count(x => x.Pagado == 1 && x.ReciboFecha.HasValue && x.ReciboFecha > x.CanonFecha),
Sin_realizar = g.Count(x => x.Pagado == 0)
})
.ToList();
List<InformePagos> lst = Enumerable.Range(1, 12)
.Select(mes => groupedData.FirstOrDefault(x => x.Mes == mes) ?? new InformePagos {
Mes = mes,
Realizados = 0,
Atrasados = 0,
Sin_realizar = 0
})
.ToList();
data.Datasets.Add(new Dataset {
Label = "Realizados",
Data = lst.Select(x => x.Realizados.ToString()).ToList()
});
data.Datasets.Add(new Dataset {
Label = "Atrasados",
Data = lst.Select(x => x.Atrasados.ToString()).ToList()
});
data.Datasets.Add(new Dataset {
Label = "Sin_realizar",
Data = lst.Select(x => x.Sin_realizar.ToString()).ToList()
});
return (data, lst);
}
public ChartData? ObtenerDataIniciadosPorAño(int year){
var con = Context;
var contratosPorMes = con.Contratos

View File

@@ -1,26 +1,101 @@
using Entidades;
using Entidades.Admin;
using Entidades.Dto;
using Microsoft.EntityFrameworkCore;
namespace Modelo;
public class RepositorioGrupos: RepositorioBase<RepositorioGrupos> {
public IQueryable<Permiso> ListarPermisosDeGrupo(string grupo) {
public class RepositorioGrupos : RepositorioBase<RepositorioGrupos>
{
public bool AddGrupo(GrupoDto grupo, Cliente cli)
{
var con = Context;
return con.Grupos.Where(x=>x.Nombre == grupo).SelectMany(x => x.Idpermisos);
var g = new Grupo
{
Id = con.Grupos.Max(x => x.Id) + 1,
Nombre = grupo.Nombre,
IdGrupoHijos = con.Grupos.Where(x => grupo.GruposIncluidos.Contains(x.Nombre)).ToList(),
Idpermisos = con.Permisos.Where(x => grupo.Permisos.Select(x => x.Id).Contains(x.Id)).ToList(),
};
con.Grupos.Add(g);
GenerarLog(con, cli.Dni, $"Alta Grupo: {g.Nombre}");
return Guardar(con);
}
public bool PatchGrupo(GrupoDto grupo, Cliente cli)
{
var con = Context;
var g = con.Grupos
.Include(x => x.IdGrupoHijos)
.Include(x => x.Idpermisos).FirstOrDefault(x => x.Id == grupo.idgrupo);
if (g == null)
{
return false;
}
var listg = grupo.GruposIncluidos.ToList();
if (grupo.GruposIncluidos != null)
{
g.IdGrupoHijos = con.Grupos.Where(x => listg.Contains(x.Nombre)).ToList();
}
public IQueryable<GrupoAdmin> ObtenerGruposPorDni(long Dni) {
if (grupo.Permisos != null)
{
g.Idpermisos = con.Permisos.Where(x => grupo.Permisos.Select(p => p.Id).Contains(x.Id)).ToList();
}
GenerarLog(con, cli.Dni, "Patch Grupo");
return Guardar(con);
}
public (bool, bool) ToggleGrupo(int id, Cliente cli)
{
var con = Context;
var grupos = con.Clientes.Where(x=>x.Dni == Dni).SelectMany(x=>x.Idgrupos)
.Select(x=> new GrupoAdmin{
Id = x.Id,
Descripcion = x.Nombre,
});
var grupo = con.Grupos.FirstOrDefault(x => x.Id == id);
if (grupo == null) return (false, false);
if (grupo.Habilitado == null) grupo.Habilitado = false;
grupo.Habilitado = !grupo.Habilitado;
GenerarLog(con, cli.Dni, $"Se dio de {(grupo.Habilitado == true ? "alta" : "baja")} el grupo: {id}");
return (Guardar(con), grupo.Habilitado ?? false);
}
public IQueryable<Grupo> ListarTodosLosGrupos()
{
var con = Context;
var grupos = con.Grupos.Include(x => x.IdGrupoHijos).ThenInclude(x => x.Idpermisos).Include(x => x.Idpermisos);
return grupos;
}
public bool CheckGrupos(string token, string grupo){
public IQueryable<Permiso> ListarPermisosDeGrupo(string grupo)
{
var con = Context;
var listg = con.Grupos
.Where(x => x.Habilitado == true)
.Include(x => x.Idpermisos)
.Include(x => x.IdGrupoHijos)
.ThenInclude(x => x.Idpermisos).ToList();
var g = listg.FirstOrDefault(x => x.Nombre == grupo);
if (g == null) return Enumerable.Empty<Permiso>().AsQueryable();
var permisos = new HashSet<Permiso>();
var visitados = new HashSet<int>();
g.ObtenerPermisos(permisos, visitados);
return permisos.AsQueryable();
}
public List<Grupo> ObtenerGruposPorDni(long Dni)
{
var con = Context;
var grupos = con.Clientes.Where(x => x.Dni == Dni).SelectMany(x => x.Idgrupos).ToList();
return grupos;
}
public bool CheckGrupos(string token, string grupo)
{
var con = Context;
Cliente? cli = con.Clientes.Include(x => x.Idgrupos).FirstOrDefault(x => x.Token == token);
if (cli == null) return false;

View File

@@ -21,7 +21,7 @@ public class RepositorioLogs: RepositorioBase<RepositorioLogs> {
return d.LogDetalles.OrderBy(x=>x.Id);
}
public IQueryable<Log>? ObtenerLogsPaginado(int pag) {
public IQueryable<Log> ObtenerLogsPaginado(int pag) {
var con = Context;
var l = con.Logs.OrderByDescending(x=>x.Fecha).Skip(10*pag).Take(10);
return l;

View File

@@ -3,50 +3,91 @@ using Entidades;
using Microsoft.EntityFrameworkCore;
namespace Modelo;
public class RepositorioPermisos: RepositorioBase<RepositorioPermisos> {
public object? ListarPermisos(string email) {
public class RepositorioPermisos : RepositorioBase<RepositorioPermisos>
{
public IQueryable<Grupo>? ListarPermisos(string email)
{
var con = Context;
Cliente? cli = con.Clientes.Include(x => x.Idgrupos).FirstOrDefault(c => c.Email == email);
if (cli == null) return null;
// Obtener todos los grupos del cliente
var list = con.Clientes
.Where(c => c.Dni == cli.Dni)
.SelectMany(c => c.Idgrupos)
.Include(x=> x.Idpermisos);
.Where(x => x.Habilitado == true)
.Include(x => x.Idpermisos)
.Include(x => x.IdGrupoHijos).ThenInclude(x => x.Idpermisos);
// Cargamos todos los subgrupos de forma recursiva
foreach (var grupo in list)
{
var visitados = new HashSet<int>();
var todosLosPermisos = new HashSet<Permiso>();
grupo.ObtenerPermisos(todosLosPermisos, visitados);
grupo.Idpermisos = todosLosPermisos.ToList();
}
return list;
}
public bool CheckPermisos(string token, int idpermiso){
public List<Permiso> ListarPermisos()
{
return Context.Permisos.ToList();
}
public bool CheckPermisos(string token, int idpermiso)
{
var con = Context;
bool tienePermiso = false;
//checkeo que el token corresponda a un usuario
Cliente? cli = con.Clientes.FirstOrDefault(x => x.Token == token);
if (cli == null || cli.Dni == 0) return false;
// obtengo una lista de los permisos
var permisos = con.Clientes
var grupos = con.Clientes
.Where(x => x.Dni == cli.Dni)
.SelectMany(x => x.Idgrupos)
.SelectMany(x => x.Idpermisos)
.Distinct();
.Where(x => x.Habilitado == true)
.Include(x => x.Idpermisos)
.Include(x => x.IdGrupoHijos)
.ThenInclude(x => x.Idpermisos)
.ToList();
/////////////////////////////////////////////////////////////////
//Esto esta comentado porque antes pasaba el string del path de la url, es una mala idea a muchos niveles
// abajo un comentario viejo mio
/////////////////////////////////////////////////////////////////
//me inspiré y hice un regex pero si eliminaba los primeros 8(?) caracteres del string era lo mismo
//Match match = Regex.Match(path, @"^/accion/(\d+)$");
//int.TryParse(match.Groups[1].Value, out int idpermiso);
/////////////////////////////////////////////////////////////////
foreach (var grupo in grupos)
{
var visitados = new HashSet<int>();
var todosLosPermisos = new HashSet<Permiso>();
grupo.ObtenerPermisos(todosLosPermisos, visitados);
Parallel.ForEach(permisos, (x, i) =>{
if (x.Id == idpermiso) {
if (todosLosPermisos.Any(p => p.Id == idpermiso))
{
tienePermiso = true;
break;
}
}
});
return tienePermiso;
}
public bool CrearPermiso(Permiso per, Cliente cli)
{
var con = Context;
per.Id = con.Permisos.Any() ? con.Permisos.Max(x => x.Id) + 1 : 1;
con.Permisos.Add(per);
GenerarLog(con, cli.Dni, $"Creado Permiso {per.Descripcion}");
return Guardar(con);
}
public bool PatchPermiso(Permiso per, Cliente cli)
{
var con = Context;
var perm = con.Permisos.FirstOrDefault(x => x.Id == per.Id);
if (perm == null) return false;
perm.Descripcion = per.Descripcion;
GenerarLog(con, cli.Dni, $"Editado Permiso {per.Id}");
return Guardar(con);
}
}

View File

@@ -8,9 +8,17 @@ using Microsoft.Identity.Client;
using Modelo;
using MySql.Data.MySqlClient;
public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
public class RepositorioPropiedades : RepositorioBase<RepositorioPropiedades>
{
public IQueryable<PropiedadesDto> ListarPropiedades(){
public List<Propiedade> ObtenerPropiedadEnAlquilerPorDni(long dni){
var con = Context;
var propiedades = con.Propiedades.Where(x=>x.Dnipropietario == dni && x.Idestado == 1).ToList();
return propiedades;
}
public IQueryable<PropiedadesDto> ListarPropiedades()
{
FormattableString sqlq = $"""
SELECT DISTINCT p.id, p.ubicacion, p.canthabitaciones, p.piso, p.letra, tp.descripcion AS Tipo,
GROUP_CONCAT(DISTINCT s.descripcion SEPARATOR ', ') AS Servicios, p.monto as Monto,
@@ -27,24 +35,36 @@ public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
return ret;
}
public Propiedade? ObtenerPropiedadPorId(int Id) {
public Propiedade? ObtenerPropiedadPorId(int Id)
{
var con = Context;
Propiedade? prop = con.Propiedades.Include(x => x.DnipropietarioNavigation).FirstOrDefault(x => x.Id == Id);
if (prop == null || prop.Id == 0) {
if (prop == null || prop.Id == 0)
{
return null;
}
return prop;
}
public bool AñadirPropiedad(Propiedade? prop) {
public bool AñadirPropiedad(Propiedade? prop, long dni = 0)
{
if (prop == null) return false;
var con = Context;
if (string.IsNullOrEmpty(prop.Letra)) prop.Letra = "_";
prop.Id = (con.Propiedades.Count()!=0) ? con.Propiedades.Count() + 1 : 1;
prop.Idestado = 1;
con.Propiedades.Add(prop);
if (dni!=0) GenerarLog(con, dni, $"Se guardo la propiedad");
return Guardar(con);
/*
var filasInsertadasParam = new MySqlParameter("@p_filas_insertadas", SqlDbType.Int)
{
Direction = ParameterDirection.Output
@@ -68,9 +88,11 @@ public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
);
return (int)filasInsertadasParam.Value == 1 ? true : false;
*/
}
public bool PatchPropiedad(Propiedade prop, long dni) {
public bool PatchPropiedad(Propiedade prop, long dni)
{
var con = Context;
Propiedade? propi = con.Propiedades.Include(x => x.IdServicios).FirstOrDefault(x => x.Id == prop.Id);
@@ -85,7 +107,8 @@ public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
propi.Iddivisa = prop.Iddivisa;
propi.IdServicios.Clear();
foreach(Servicio ser in prop.IdServicios) {
foreach (Servicio ser in prop.IdServicios)
{
var servi = con.Servicios.FirstOrDefault(x => x.Id == ser.Id);
if (servi == null) return false;
propi.IdServicios.Add(servi);
@@ -94,7 +117,8 @@ public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
return Guardar(con);
}
public IQueryable<PropiedadesDto> ObtenerPropiedadesPorEmail(string email) {
public IQueryable<PropiedadesDto> ObtenerPropiedadesPorEmail(string email)
{
FormattableString sqlq = $"""
SELECT p.id, p.ubicacion as Ubicacion, p.canthabitaciones, p.piso, p.letra, tp.descripcion as Tipo, GROUP_CONCAT(IFNULL(s.descripcion, '') SEPARATOR ', ') AS Servicios, p.monto as Monto,
p.iddivisa as Iddivisa
@@ -111,7 +135,8 @@ public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
return ret;
}
public IQueryable<PropiedadesDto> ObtenerPropiedadesDeBajaPorEmail(string email) {
public IQueryable<PropiedadesDto> ObtenerPropiedadesDeBajaPorEmail(string email)
{
FormattableString sqlq = $"""
SELECT p.id, p.ubicacion as Ubicacion, p.canthabitaciones, p.piso, p.letra, tp.descripcion as Tipo, GROUP_CONCAT(IFNULL(s.descripcion, '') SEPARATOR ', ') AS Servicios, p.monto as Monto,
p.iddivisa as Iddivisa
@@ -128,12 +153,14 @@ public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
return ret;
}
public bool AñadirServicioAPropiedad(int idprop, List<int> idserv){
public bool AñadirServicioAPropiedad(int idprop, List<int> idserv)
{
var con = Context;
Propiedade? prop = con.Propiedades.Find(idprop);
if (prop == null) return false;
foreach (int id in idserv) {
foreach (int id in idserv)
{
Servicio? servicio = con.Servicios.Find(id);
if (servicio == null) return false;
@@ -143,7 +170,8 @@ public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
return Guardar(con);
}
public bool BajaPropiedad(int id, Cliente? cli) {
public bool BajaPropiedad(int id, Cliente? cli)
{
if (cli == null) return false;
var con = Context;
@@ -151,9 +179,12 @@ public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
if (prop == null) return false;
if (prop.Dnipropietario != cli.Dni) return false;
if(prop.Idestado == 1){
if (prop.Idestado == 1)
{
prop.Idestado = 3;
}else{
}
else
{
prop.Idestado = 1;
}
GenerarLog(con, cli.Dni, $"Baja propiedad: {prop.Id}");
@@ -161,7 +192,8 @@ public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
}
public bool BajaPropiedad(int id, long dni) {
public bool BajaPropiedad(int id, long dni)
{
var con = Context;
Propiedade? prop = con.Propiedades.FirstOrDefault(x => x.Id == id);
@@ -172,17 +204,20 @@ public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
return Guardar(con);
}
public bool BajaServiciosAPropiedad(int idprop, List<int> idserv, long dni) {
public bool BajaServiciosAPropiedad(int idprop, List<int> idserv, long dni)
{
var con = Context;
Propiedade? prop = con.Propiedades.Include(x => x.IdServicios).FirstOrDefault(x => x.Id == idprop);
if (prop == null) return false;
foreach (int id in idserv) {
foreach (int id in idserv)
{
Servicio? servicio = con.Servicios.Find(id);
if (servicio == null) return false;
if (prop.IdServicios.Contains(servicio)){
if (prop.IdServicios.Contains(servicio))
{
prop.IdServicios.Remove(servicio);
}
}
@@ -190,7 +225,8 @@ public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
return Guardar(con);
}
public IQueryable<PropiedadesDto> ObtenerPropiedesPorHabitaciones_Tipo_Servicios(int habitaciones, int tipo, string servicios) {
public IQueryable<PropiedadesDto> ObtenerPropiedesPorHabitaciones_Tipo_Servicios(int habitaciones, int tipo, string servicios)
{
string serviciosEscapados = string.Join(",", servicios.Split(',').Select(s => s.Trim()));
FormattableString sqlq = $"""
SELECT DISTINCT p.id, p.ubicacion, p.canthabitaciones, p.piso, p.letra, tp.descripcion AS Tipo,
@@ -216,7 +252,8 @@ public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
return ret;
}
public IQueryable<PropiedadesDto> ObtenerPropiedesPorHabitaciones_Tipo(int cantidadHabitaciones, int tipoPropiedad) {
public IQueryable<PropiedadesDto> ObtenerPropiedesPorHabitaciones_Tipo(int cantidadHabitaciones, int tipoPropiedad)
{
FormattableString sqlq = $"""
SELECT DISTINCT p.id, p.ubicacion, p.canthabitaciones, p.piso, p.letra, tp.descripcion AS Tipo,
GROUP_CONCAT(DISTINCT s.descripcion SEPARATOR ', ') AS Servicios, p.monto as Monto,
@@ -234,7 +271,8 @@ public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
return ret;
}
public IQueryable<PropiedadesDto> ObtenerPropiedesPorServicios(string servicios) {
public IQueryable<PropiedadesDto> ObtenerPropiedesPorServicios(string servicios)
{
string serviciosEscapados = string.Join(",", servicios.Split(',').Select(s => s.Trim()));
FormattableString sqlq = $"""
@@ -260,7 +298,8 @@ public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
return ret;
}
public IQueryable<PropiedadesDto> ObtenerPropiedesPorHabitaciones(int cantidadHabitaciones) {
public IQueryable<PropiedadesDto> ObtenerPropiedesPorHabitaciones(int cantidadHabitaciones)
{
FormattableString sqlq = $"""
SELECT DISTINCT p.id, p.ubicacion, p.canthabitaciones, p.piso, p.letra, tp.descripcion AS Tipo,
GROUP_CONCAT(DISTINCT s.descripcion SEPARATOR ', ') AS Servicios, p.monto as Monto,
@@ -278,7 +317,8 @@ public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
return ret;
}
public IQueryable<PropiedadesDto> ObtenerPropiedesPorTipo(int tipoPropiedad) {
public IQueryable<PropiedadesDto> ObtenerPropiedesPorTipo(int tipoPropiedad)
{
FormattableString sqlq = $"""
SELECT DISTINCT p.id, p.ubicacion, p.canthabitaciones, p.piso, p.letra, tp.descripcion AS Tipo,
GROUP_CONCAT(DISTINCT s.descripcion SEPARATOR ', ') AS Servicios, p.monto as Monto,
@@ -296,7 +336,8 @@ public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
return ret;
}
public IQueryable<PropiedadesDto> ObtenerPropiedesPorHabitaciones_Servicios(int cantidadHabitaciones, string servicios) {
public IQueryable<PropiedadesDto> ObtenerPropiedesPorHabitaciones_Servicios(int cantidadHabitaciones, string servicios)
{
string serviciosEscapados = string.Join(",", servicios.Split(',').Select(s => s.Trim()));
FormattableString sqlq = $"""
SELECT DISTINCT p.id, p.ubicacion, p.canthabitaciones, p.piso, p.letra, tp.descripcion AS Tipo,
@@ -322,7 +363,8 @@ public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
return ret;
}
public IQueryable<PropiedadesDto> ObtenerPropiedesPorTipo_Servicios(int tipoPropiedad, string servicios) {
public IQueryable<PropiedadesDto> ObtenerPropiedesPorTipo_Servicios(int tipoPropiedad, string servicios)
{
string serviciosEscapados = string.Join(",", servicios.Split(',').Select(s => s.Trim()));
FormattableString sqlq = $"""
SELECT DISTINCT p.id, p.ubicacion, p.canthabitaciones, p.piso, p.letra, tp.descripcion AS Tipo,
@@ -348,20 +390,26 @@ public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
return ret;
}
public bool BajaPropiedades(string email) {
public bool BajaPropiedades(string email)
{
var con = Context;
try {
try
{
IQueryable<Propiedade> listprop = con.Propiedades.Where(x => x.DnipropietarioNavigation.Email == email);
foreach (var item in listprop) {
foreach (var item in listprop)
{
item.Idestado = 3;
}
} catch {
}
catch
{
return false;
}
return Guardar(con);
}
public IQueryable<PropiedadesDto> ListarPropiedadesPorPagina(int pag) {
public IQueryable<PropiedadesDto> ListarPropiedadesPorPagina(int pag)
{
FormattableString sqlq = $"""
SELECT DISTINCT p.id, p.ubicacion, p.canthabitaciones, p.piso, p.letra, tp.descripcion AS Tipo,
GROUP_CONCAT(DISTINCT s.descripcion SEPARATOR ', ') AS Servicios, p.monto as Monto,
@@ -379,7 +427,8 @@ public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
return ret;
}
///////////////ADMIN
public IQueryable<PropiedadesAdmin> ListarPropiedadesPorPaginaAdmin(int pag) {
public IQueryable<PropiedadesAdmin> ListarPropiedadesPorPaginaAdmin(int pag)
{
FormattableString sqlq = $"""
SELECT DISTINCT p.id, p.ubicacion, p.canthabitaciones, p.piso, p.letra, tp.descripcion AS Tipo,
GROUP_CONCAT(DISTINCT s.descripcion SEPARATOR ', ') AS Servicios, p.monto as Monto, ep.descripcion AS Estado,
@@ -398,7 +447,8 @@ public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
}
public IQueryable<PropiedadesAdmin> ObtenerPropiedesPorHabitacionesPaginado(int cantidadHabitaciones, int pag) {
public IQueryable<PropiedadesAdmin> ObtenerPropiedesPorHabitacionesPaginado(int cantidadHabitaciones, int pag)
{
FormattableString sqlq = $"""
SELECT DISTINCT p.id, p.ubicacion, p.canthabitaciones, p.piso, p.letra, tp.descripcion AS Tipo,
GROUP_CONCAT(DISTINCT s.descripcion SEPARATOR ', ') AS Servicios, p.monto as Monto, ep.descripcion AS Estado,
@@ -417,7 +467,8 @@ public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
return ret;
}
public IQueryable<PropiedadesAdmin> ObtenerPropiedesPorTipoPaginado(int tipoPropiedad, int pag) {
public IQueryable<PropiedadesAdmin> ObtenerPropiedesPorTipoPaginado(int tipoPropiedad, int pag)
{
FormattableString sqlq = $"""
SELECT DISTINCT p.id, p.ubicacion, p.canthabitaciones, p.piso, p.letra, tp.descripcion AS Tipo,
GROUP_CONCAT(DISTINCT s.descripcion SEPARATOR ', ') AS Servicios, p.monto as Monto, ep.descripcion AS Estado,
@@ -436,7 +487,8 @@ public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
return ret;
}
public IQueryable<PropiedadesAdmin> ObtenerPropiedesPorHabitaciones_TipoPaginado(int cantidadHabitaciones, int tipoPropiedad, int pag) {
public IQueryable<PropiedadesAdmin> ObtenerPropiedesPorHabitaciones_TipoPaginado(int cantidadHabitaciones, int tipoPropiedad, int pag)
{
FormattableString sqlq = $"""
SELECT DISTINCT p.id, p.ubicacion, p.canthabitaciones, p.piso, p.letra, tp.descripcion AS Tipo,
GROUP_CONCAT(DISTINCT s.descripcion SEPARATOR ', ') AS Servicios, p.monto as Monto, ep.descripcion AS Estado,
@@ -455,7 +507,8 @@ public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
return ret;
}
public IQueryable<PropiedadesAdmin> ObtenerPropiedesPorServiciosPaginado(string servicios, int pag) {
public IQueryable<PropiedadesAdmin> ObtenerPropiedesPorServiciosPaginado(string servicios, int pag)
{
string serviciosEscapados = string.Join(",", servicios.Split(',').Select(s => s.Trim()));
FormattableString sqlq = $"""
@@ -482,7 +535,8 @@ public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
return ret;
}
public IQueryable<PropiedadesAdmin> ObtenerPropiedesPorHabitaciones_Servicios_Paginado(int cantidadHabitaciones, string servicios, int pag) {
public IQueryable<PropiedadesAdmin> ObtenerPropiedesPorHabitaciones_Servicios_Paginado(int cantidadHabitaciones, string servicios, int pag)
{
string serviciosEscapados = string.Join(",", servicios.Split(',').Select(s => s.Trim()));
FormattableString sqlq = $"""
SELECT DISTINCT p.id, p.ubicacion, p.canthabitaciones, p.piso, p.letra, tp.descripcion AS Tipo,
@@ -509,7 +563,8 @@ public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
return ret;
}
public IQueryable<PropiedadesAdmin> ObtenerPropiedesPorTipo_Servicios_Paginado(int tipoPropiedad, string servicios, int pag) {
public IQueryable<PropiedadesAdmin> ObtenerPropiedesPorTipo_Servicios_Paginado(int tipoPropiedad, string servicios, int pag)
{
string serviciosEscapados = string.Join(",", servicios.Split(',').Select(s => s.Trim()));
FormattableString sqlq = $"""
SELECT DISTINCT p.id, p.ubicacion, p.canthabitaciones, p.piso, p.letra, tp.descripcion AS Tipo,
@@ -536,7 +591,8 @@ public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
return ret;
}
public IQueryable<PropiedadesAdmin> ObtenerPropiedesPorHabitaciones_Tipo_Servicios_Paginado(int habitaciones, int tipo, string servicios, int pag) {
public IQueryable<PropiedadesAdmin> ObtenerPropiedesPorHabitaciones_Tipo_Servicios_Paginado(int habitaciones, int tipo, string servicios, int pag)
{
string serviciosEscapados = string.Join(",", servicios.Split(',').Select(s => s.Trim()));
FormattableString sqlq = $"""
SELECT DISTINCT p.id, p.ubicacion, p.canthabitaciones, p.piso, p.letra, tp.descripcion AS Tipo,
@@ -563,14 +619,18 @@ public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
return ret;
}
public int CuantasPaginas(int estado = 0) {
public int CuantasPaginas(int estado = 0)
{
var con = Context;
double inter;
int ret;
if (estado == 0){
if (estado == 0)
{
inter = con.Propiedades.Count() / 10.0;
} else {
}
else
{
inter = con.Propiedades.Where(x => x.Idestado == estado).Count();
}
if (inter == 0.00) return 0;
@@ -579,7 +639,8 @@ public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
return ret;
}
public int CuantasPaginasBusqueda(int habitaciones, string servicios, int tipoPropiedad, int estado) {
public int CuantasPaginasBusqueda(int habitaciones, string servicios, int tipoPropiedad, int estado)
{
int registrosPorPagina = 10;
var query = Context.Propiedades
@@ -588,19 +649,23 @@ public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
.Include(p => p.IdServicios)
.AsQueryable();
if (habitaciones > 0) {
if (habitaciones > 0)
{
query = query.Where(p => p.Canthabitaciones == habitaciones);
}
if (estado > 0){
if (estado > 0)
{
query = query.Where(x => x.Idestado == estado);
}
if (tipoPropiedad > 0) {
if (tipoPropiedad > 0)
{
query = query.Where(p => p.Idtipropiedad == tipoPropiedad);
}
if (!string.IsNullOrWhiteSpace(servicios)) {
if (!string.IsNullOrWhiteSpace(servicios))
{
var listaServicios = servicios.Split(',').Select(s => s.Trim()).ToList();
query = query.Where(p =>
p.IdServicios.Any(sp =>
@@ -612,7 +677,8 @@ public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
return (int)Math.Ceiling((double)totalRegistros / registrosPorPagina);
}
public IQueryable<Propiedade>? ObtenerPropiedadesEnVenta(int pag){
public IQueryable<Propiedade>? ObtenerPropiedadesEnVenta(int pag)
{
var con = Context;
var props = con.Propiedades.Include(x => x.IdServicios).Include(x => x.IddivisaNavigation)
@@ -621,14 +687,16 @@ public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
.Skip(pag * 10).Take(10);
return props;
}
public int ObtenerPaginasDePropiedadesEnVenta(){
public int ObtenerPaginasDePropiedadesEnVenta()
{
var con = Context;
var props = con.Propiedades.Where(x => x.Idestado == 4 && !x.Venta.Any(x => x.Idestado == 2)).Count();
return (int)Math.Ceiling((double)props / 10);
}
public IQueryable<Propiedade> ObtenerPropiedadesAVentaPorDni(long dni) {
public IQueryable<Propiedade> ObtenerPropiedadesAVentaPorDni(long dni)
{
var con = Context;
var l = con.Propiedades.Include(x => x.IdServicios).Include(x => x.IdtipropiedadNavigation)
.Where(x => x.Dnipropietario == dni && x.Idestado == 4);

View File

@@ -1,10 +1,20 @@
using System;
using Entidades;
using Entidades.Dto;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion.Internal;
using Modelo;
public class RepositorioPropietario: RepositorioBase<RepositorioPropietario> {
public IQueryable<PropietarioDto> GetPropietarios() {
FormattableString sqlq =
$"""
SELECT I.Dni, I.Nombre, I.Apellido FROM Clientes I
JOIN cliente_Grupos cg on cg.idcliente = I.Dni
WHERE cg.idgrupo = 1;
""";
return Context.Database.SqlQuery<PropietarioDto>(sqlq);
}
public Cliente? ObtenerPropietarioPorDni(long Dni){
if (Dni < 1) return null;

View File

@@ -4,17 +4,96 @@ using Entidades.Dto;
using Entidades;
using Microsoft.EntityFrameworkCore;
using Entidades.Admin;
using System.Net;
using Modelo.Facade;
namespace Modelo;
public class RepositorioUsuarios: RepositorioBase<RepositorioUsuarios> {
public bool AltaInquilino(Cliente cli, long dni) {
public class RepositorioUsuarios : RepositorioBase<RepositorioUsuarios>
{
public bool AltaUsuario(long Dni, Cliente clii, string Contraseña, List<int> grupos)
{
var con = Context;
foreach (int i in grupos)
{
var g = con.Grupos.FirstOrDefault(x => x.Id == i);
clii.Idgrupos.Add(g);
}
clii.Contraseña = Encoding.UTF8.GetBytes(HacerHash(Contraseña));
con.Clientes.Add(clii);
base.GenerarLog(con, Dni, "Creacion de usuario");
return Guardar(con);
}
public (bool, long) Check2fa(string Email, string Pin)
{
var con = Context;
var cli = con.Clientes.FirstOrDefault(x => x.Email == Email);
if (cli == null || cli.F2a == null) return (false, 0);
if (cli.F2a != Pin) return (false, 0);
return (true, cli.Dni);
}
public bool SetF2aPin(string pin, string Email)
{
if (pin.Length != 6) return false;
var con = Context;
var cli = con.Clientes.FirstOrDefault(x => x.Email == Email);
if (cli == null) return false;
cli.F2a = pin;
//no Necesita logs esto
return Guardar(con);
}
public bool CheckEmailRecuperacion(string Email, string EmailRecuperacion)
{
var con = Context;
Cliente cli = con.Clientes.FirstOrDefault(x => x.Email == Email);
if (cli == null) return false;
if (cli.EmailRecuperacion == EmailRecuperacion)
{
base.GenerarLog(con, cli.Dni, "Intento de recuperar Usuario");
return true;
}
return false;
}
public bool SetEmailRecuperacion(string emailrecuperacion, Cliente cli)
{
var con = Context;
Cliente clii = con.Clientes.FirstOrDefault(x => x.Dni == cli.Dni);
if (clii == null) return false;
clii.EmailRecuperacion = emailrecuperacion;
base.GenerarLog(con, cli.Dni, "Set email Recuperacion");
return Guardar(con);
}
public bool CambiarContraseña(string pass, Cliente cli)
{
var con = Context;
var clii = con.Clientes.FirstOrDefault(x => x.Dni == cli.Dni);
if (clii == null) return false;
clii.Contraseña = Encoding.UTF8.GetBytes(HacerHash(pass));
this.GenerarLog(con, cli.Dni, "Modificada contraseña");
return Guardar(con);
}
public bool AltaInquilino(Cliente cli, long dni)
{
var con = Context;
Grupo? grupo;
//check por si la cuenta ya existe (puede ser propietario)
Cliente? cli2 = con.Clientes.FirstOrDefault(x => x.Email == cli.Email);
if (cli2 != null) {
if (cli2 != null)
{
grupo = con.Grupos.Find(2);
if (grupo == null || grupo.Id == 0) return false;
cli2.Idgrupos.Add(grupo);
@@ -33,13 +112,15 @@ public class RepositorioUsuarios: RepositorioBase<RepositorioUsuarios> {
return Guardar(con);
}
public bool AltaPropietario(Cliente cli, long dni) {
public bool AltaPropietario(Cliente cli, long dni)
{
var con = Context;
Grupo? grupo;
//check por si la cuenta ya existe (puede ser propietario)
Cliente? cli2 = con.Clientes.Find(cli.Dni);
if (cli2 != null) {
if (cli2 != null)
{
grupo = con.Grupos.Find(1);
if (grupo == null || grupo.Id == 0) return false;
cli2.Idgrupos.Add(grupo);
@@ -58,7 +139,8 @@ public class RepositorioUsuarios: RepositorioBase<RepositorioUsuarios> {
return Guardar(con);
}
public bool ActualizarPropietario(Cliente cli) {
public bool ActualizarPropietario(Cliente cli)
{
var con = Context;
Cliente? cliOld = con.Clientes.Find(cli.Dni);
if (cliOld == null) return false;
@@ -69,13 +151,15 @@ public class RepositorioUsuarios: RepositorioBase<RepositorioUsuarios> {
}
public bool CheckUsuario(LoginDto logindto) {
public bool CheckUsuario(LoginDto logindto)
{
if (logindto.Contraseña == null) return false;
Cliente? usu = Context.Clientes.FirstOrDefault(a => a.Email == logindto.Email && a.Habilitado == 1ul);
if (usu == null) return false;
string Contraseña = HacerHash(logindto.Contraseña);
Cliente? usu = Context.Clientes.FirstOrDefault(a => a.Email == logindto.Email);
if (usu == null) return false;
string hashdb = Encoding.UTF8.GetString(usu.Contraseña);
@@ -83,34 +167,49 @@ public class RepositorioUsuarios: RepositorioBase<RepositorioUsuarios> {
return false;
}
private string HacerHash(string pass) {
private string HacerHash(string pass)
{
var buf = SHA256.HashData(Encoding.UTF8.GetBytes(pass));
return BitConverter.ToString(buf).Replace("-", "");
}
public bool CheckToken(string email, string token) {
public bool CheckToken(string email, string token)
{
var usu = Context.Clientes.FirstOrDefault(x => x.Email == email);
if (usu == null) return false;
return usu.Token == token;
}
public void GuardarToken(LoginDto login, string tokenString) {
public void GuardarToken(LoginDto login, string tokenString, System.Net.IPAddress? remoteIpAddress, string? logout = null)
{
var con = Context;
var usu = con.Clientes.FirstOrDefault(x => x.Email == login.Email);
if (usu == null) return;
usu.Token = tokenString;
GenerarLog(con, usu.Dni, logout!=null? logout : "Login", remoteIpAddress);
Guardar(con);
}
public bool CheckGrupo(string email, string grupo) {
private void GenerarLog(AlquilaFacilContext con, long dni, string v, IPAddress? remoteIpAddress)
{
var Auditoria = new AuditoriaFacade(con);
Auditoria.GenerarLogLogin(dni, v, remoteIpAddress);
}
public bool CheckGrupo(string email, string grupo)
{
var con = Context;
var usu = con.Clientes.Include(x => x.Idgrupos).FirstOrDefault(x => x.Email == email);
bool ret = false;
if (usu != null && usu.Idgrupos != null) {
Parallel.ForEach(usu.Idgrupos, (idGrupo, state) => {
if (idGrupo.Nombre == grupo) {
if (usu != null && usu.Idgrupos != null)
{
Parallel.ForEach(usu.Idgrupos, (idGrupo, state) =>
{
if (idGrupo.Nombre == grupo)
{
ret = true;
state.Break();
}
@@ -120,23 +219,28 @@ public class RepositorioUsuarios: RepositorioBase<RepositorioUsuarios> {
return ret;
}
public IEnumerable<Entidades.Admin.UsuarioAdmin> GetClientes(){
public IEnumerable<Entidades.Admin.UsuarioAdmin> GetClientes()
{
var con = Context;
var list = con.Clientes.ToList().Select(x => new Entidades.Admin.UsuarioAdmin {
var list = con.Clientes.ToList().Select(x => new Entidades.Admin.UsuarioAdmin
{
Dni = x.Dni,
Email = x.Email,
Nombre = x.Nombre + " " + x.Apellido,
Habilitado = x.Habilitado});
Habilitado = x.Habilitado
});
return list;
}
public bool AñadirClienteAGrupo(string email, string grupo, long dni) {
public bool AñadirClienteAGrupo(string email, string grupo, long dni)
{
var con = Context;
var cli = con.Clientes.Include(x => x.Idgrupos).FirstOrDefault(x => x.Email == email);
var gru = con.Grupos.FirstOrDefault(x => x.Nombre == grupo);
if (cli == null || gru == null) {
if (cli == null || gru == null)
{
return false;
}
@@ -145,13 +249,15 @@ public class RepositorioUsuarios: RepositorioBase<RepositorioUsuarios> {
return Guardar(con);
}
public bool EliminarClienteAGrupo(string email, string grupo, long dniresponsable) {
public bool EliminarClienteAGrupo(string email, string grupo, long dniresponsable)
{
var con = Context;
var cli = con.Clientes.Include(x => x.Idgrupos).FirstOrDefault(x => x.Email == email);
var gru = con.Grupos.FirstOrDefault(x => x.Nombre == grupo);
if (cli == null || gru == null) {
if (cli == null || gru == null)
{
return false;
}
cli.Idgrupos.Remove(gru);
@@ -159,28 +265,34 @@ public class RepositorioUsuarios: RepositorioBase<RepositorioUsuarios> {
return Guardar(con);
}
public bool BajaCliente(long dni) {
public bool BajaCliente(long dni)
{
var con = Context;
Cliente? cli = con.Clientes.Include(x => x.Idgrupos).FirstOrDefault(x => x.Dni == dni);
if (cli == null) return false;
if (cli.Habilitado == 0) {
if (cli.Habilitado == 0)
{
cli.Habilitado = 1;
} else {
}
else
{
cli.Habilitado = 0;
}
GenerarLog(con, cli.Dni, $"Baja cliente id: {cli.Dni}");
return Guardar(con);
}
public Cliente? ObtenerClientePorDni(long dni) {
public Cliente? ObtenerClientePorDni(long dni)
{
var con = Context;
Cliente? cli = con.Clientes.FirstOrDefault(x => x.Dni == dni);
return cli;
}
public Cliente? ObtenerClientePorToken(string token) {
public Cliente? ObtenerClientePorToken(string token)
{
var con = Context;
Cliente? cli = con.Clientes.Include(x => x.NotificacioneDniclienteNavigations).FirstOrDefault(x => x.Token == token);
@@ -188,7 +300,8 @@ public class RepositorioUsuarios: RepositorioBase<RepositorioUsuarios> {
return cli;
}
public bool PatchUsuario(UpdateUsuarioAdmin dto, long dni, long responsabledni) {
public bool PatchUsuario(UpdateUsuarioAdmin dto, long dni, long responsabledni)
{
var con = Context;
var usu = con.Clientes.FirstOrDefault(x => x.Dni == dni);
if (usu == null) return false;

View File

@@ -1,2 +1,2 @@
run:
dotnet watch run --project Aspnet/AlquilaFacil.csproj
bunx concurrently "dotnet watch run --project Aspnet/AlquilaFacil.csproj" "make -C ./Front"