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) {
bool Habilitado = habilitado == 0?false:true;
bool Cancelado = cancelado == 0?false:true;
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,20 +1,20 @@
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});
if (Auth == "") return Unauthorized(new { esValido = false });
bool esValido = RepositorioUsuarios.Singleton.CheckToken(Email, Auth);
if (!esValido) return Unauthorized();
@@ -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) {
public IActionResult ListarAccionesPorGrupo([FromHeader(Name = "Auth")] string Auth,
[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")]
@@ -416,4 +420,4 @@ public class AdminController: ControllerBase
if (d.Domicilio=="")ret+="Campo Domicilio vacio\n";
return ret;
}
}
}

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;
}
}
}

File diff suppressed because it is too large Load Diff

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) {
if (Idcontrato <= 0) return BadRequest( new { message = "La id de contrato no puede ser menor o igual a 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();
}
}
@@ -26,19 +30,20 @@ public class DefectoController: ControllerBase {
if (cli == null) return Unauthorized();
Contrato? cont = RepositorioContratos.Singleton.ObtenerContratoPorId(Idcontrato);
if (cont == null) return BadRequest(new { message = "No hay contrato por esa id"});
if (cont == null) return BadRequest(new { message = "No hay contrato por esa id" });
if (cont.Dniinquilino != cli.Dni && cont.Dnipropietario != cli.Dni) return BadRequest(new { message = "no deberias tener acceso a esto"});
if (cont.Dniinquilino != cli.Dni && cont.Dnipropietario != cli.Dni) return BadRequest(new { message = "no deberias tener acceso a esto" });
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)
.SetId(i.Id)
.SetDesc(i.Descripcion)
.SetCosto(i.Costo)
.SetEstado(i.IdestadoNavigation.Descipcion)
.SetIdContrato(i.Idcontrato??0)
.SetIdContrato(i.Idcontrato ?? 0)
.SetPagaInquilino(i.Pagainquilino)
.SetDivisa(i.IddivisaNavigation.Signo)
.Build();
@@ -48,54 +53,58 @@ 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);
Cliente? cli = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);
if (cli == null) return Unauthorized();
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,
Iddivisa = data.Iddivisa,
Pagainquilino = data.Pagainquilino==0?0Lu:1Lu,
Pagainquilino = data.Pagainquilino == 0 ? 0Lu : 1Lu,
Idestado = 1,
};
var b = RepositorioDefectos.Singleton.AltaDefecto(defecto, cli.Dni);
return b ?Ok(new { message = "Se cargo el Defecto en el sistema"}):BadRequest(new { message ="No se pudo cargar el defecto en el sistema"});
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){
string ret ="";
private string ValidarDto(AltaDefectoDto d)
{
string ret = "";
if (d == null) return "Dto nulo";
if (d.Iddivisa <0 || d.Iddivisa>1) ret +="No son divisas validas\n";
if (d.Descripcion == "") ret+="La descripcion no puede estar vacia\n";
if (d.Idcontrato<=0)ret += "No puede haber un id de contrato igual o menor a 0\n";
if (d.Iddivisa < 0 || d.Iddivisa > 1) ret += "No son divisas validas\n";
if (d.Descripcion == "") ret += "La descripcion no puede estar vacia\n";
if (d.Idcontrato <= 0) ret += "No puede haber un id de contrato igual o menor a 0\n";
return ret;
}
[HttpPut("api/defecto/marcarpago")]
public IActionResult MarcarPago([FromHeader(Name = "Auth")] string Auth, long iddefecto = 0) {
[HttpPut("api/defecto/marcarpago")]
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);
if (cli==null) return Unauthorized();
if (cli == null) return Unauthorized();
if (iddefecto<=0) return BadRequest(new { message = "No hay canones con id 0 o menor"});
if (iddefecto <= 0) return BadRequest(new { message = "No hay canones con id 0 o menor" });
bool ret = RepositorioDefectos.Singleton.MarcarPago(iddefecto, cli.Dni);
return ret ?
Ok(new { message = "Se marco como pagado" }):BadRequest(new { message = "Fallo el acceso a la base de datos o no se encontro el defecto" });
Ok(new { message = "Se marco como pagado" }) : BadRequest(new { message = "Fallo el acceso a la base de datos o no se encontro el defecto" });
}
}

View File

@@ -5,44 +5,64 @@ 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);
if (validacion2 == false) return BadRequest(new { message = "No hay contratos en ese año"});
if (validacion2 == false) return BadRequest(new { message = "No hay contratos en ese año" });
var a = RepositorioEstadisticas.Singleton.ObtenerDataIniciadosPorAño(year);
return Ok(a);
}
[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");
if (validacion1 == false) return Unauthorized();
if (idcontrato<=0) return BadRequest(new {message = "No puede tener un id contrato menor o igual a 0"});
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" });
var ret = RepositorioEstadisticas.Singleton.ObtenerDatosPagosContrato(idcontrato);
return Ok(ret);
}
[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);
if (validacion2 == false) return BadRequest(new { message = "No hay contratos en ese año"});
var a = RepositorioEstadisticas.Singleton.TablaObtenerContratosIniciadosPorAño(year);
if (a == null) return BadRequest(new { message = "Fallo al obtener el contrato"});
List<InformesAlquiler> informe =new();
foreach (var i in a) {
var validacion2 = RepositorioContratos.Singleton.HayContratosEnAño(year);
if (validacion2 == false) return BadRequest(new { message = "No hay contratos en ese año" });
var a = RepositorioEstadisticas.Singleton.TablaObtenerContratosIniciadosPorAño(year);
if (a == null) return BadRequest(new { message = "Fallo al obtener el contrato" });
List<InformesAlquiler> informe = new();
foreach (var i in a)
{
var d = new InformesAlquilerBuilder()
.SetId(i.Id).SetUbicacion(i.IdpropiedadNavigation.Ubicacion)
.SetDivisa(i.IddivisaNavigation.Signo)
@@ -52,22 +72,24 @@ 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();
return Ok(a);
}
[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();
return Ok(a);
}
}
}

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

@@ -9,11 +9,12 @@ using System.Security.Cryptography;
namespace AlquilaFacil.Controllers;
[ApiController]
public class InquilinoController: ControllerBase
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,18 +26,20 @@ public class InquilinoController: ControllerBase
}
[HttpPost("api/inquilino")]
public IActionResult Post([FromBody] CrearClienteDto cid, [FromHeader(Name = "Auth")] string Auth) {
if (string.IsNullOrEmpty(Auth)) return BadRequest(new {message = "El String Auth Esta Vacio"});
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"});
if (ret3 == false) return BadRequest(new { message = "Falló el permiso" });
Cliente? rep = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);
if (rep == null) return Unauthorized();
var ret = verificarCrearUsuario(cid);
if (ret != "") return BadRequest(new {message = ret});
var cli = new Cliente {
if (ret != "") return BadRequest(new { message = ret });
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"});
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,8 +70,9 @@ 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("-","");
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
{
@@ -52,7 +52,27 @@ 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,21 +5,25 @@ 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"});
if (pag <= 0) return BadRequest(new { message = "no puede haber una pagina 0 o menor" });
pag-=1;
pag -= 1;
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"});
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,12 +58,13 @@ 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();
return Ok(c);
}
}
}

View File

@@ -7,79 +7,85 @@ 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);
if (cli == null) return BadRequest(new {message = "Fallo al intentar encontrar tu usuario (puede que te hayas logeado desde otro dispositivo?)"});
if (cli == null) return BadRequest(new { message = "Fallo al intentar encontrar tu usuario (puede que te hayas logeado desde otro dispositivo?)" });
IQueryable<Notificacione> notificaciones = RepositorioNotificaciones.Singleton.ObtenerNotificacionesDeUsuario(cli.Dni)
.Where(x=>x.Leido == leido);
.Where(x => x.Leido == leido);
List<NotificacionDto> noti = new();
foreach (Notificacione i in notificaciones) {
if(i.DniclienteNavigation == null || i.DniremitenteNavigation==null) return BadRequest(new { message = "Esta mal cargado el precontrato"});
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??"")
.SetAccion(i.Accion??"")
.SetMensaje(i.Mensaje??"")
.SetRemitente(i.DniremitenteNavigation.Email ?? "")
.SetAccion(i.Accion ?? "")
.SetMensaje(i.Mensaje ?? "")
.SetFecha(i.Fecha)
.SetPropiedad(i.Idpropiedad.ToString()??"")
.SetReceptor(i.DniclienteNavigation.Email??"")
.SetPropiedad(i.Idpropiedad.ToString() ?? "")
.SetReceptor(i.DniclienteNavigation.Email ?? "")
.Build();
noti.Add(dto);
}
return Ok(noti);
}
[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);
if (cli == null) return BadRequest(new {message = "Fallo al intentar encontrar tu usuario (puede que te hayas logeado desde otro dispositivo?)"});
if (cli == null) return BadRequest(new { message = "Fallo al intentar encontrar tu usuario (puede que te hayas logeado desde otro dispositivo?)" });
bool ret = RepositorioNotificaciones.Singleton.HayNotis(cli.Dni);
return Ok(new {message = ret});
return Ok(new { message = ret });
}
[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"});
if (nota.Fecha == null || String.IsNullOrWhiteSpace(nota.Email)) return BadRequest(new { message = "Faltan datos" });
Cliente? cli = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);
if (cli == null) return BadRequest(new {message = "El token de autorizacion no pertenese a ningun Usuario"});
if (cli == null) return BadRequest(new { message = "El token de autorizacion no pertenese a ningun Usuario" });
if (cli.Email != nota.Email) return BadRequest(new { message = "El token de autorizacion no corresponde a tu usuario" });
if (cli.Email != nota.Email) return BadRequest(new {message = "El token de autorizacion no corresponde a tu usuario"});
bool ret = RepositorioNotificaciones.Singleton.MarcarComoLeido(cli.Dni, nota.Fecha);
return ret ?
Ok(new{message = "Se Marco como leido"}):BadRequest(new{message = "Fallo al marcarse como leido"});
Ok(new { message = "Se Marco como leido" }) : BadRequest(new { message = "Fallo al marcarse como leido" });
}
[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"});
if (validacion1 == false) return BadRequest(new { message = "el token no corresponde a su usuario" });
if (data.Accion == "") return BadRequest(new{message = "El campo Accion esta vacio"});
if (data.Mensaje == "") return BadRequest(new {message = "El campo Mensaje esta vacio"});
if (data.Accion == "") return BadRequest(new { message = "El campo Accion esta vacio" });
if (data.Mensaje == "") return BadRequest(new { message = "El campo Mensaje esta vacio" });
Cliente? inq = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);
if (inq == null) return BadRequest(new { message = "no hay un usuario para el cual el token de autorizacion corresponda (vuelvase a logear)" });
Propiedade? prop = RepositorioPropiedades.Singleton.ObtenerPropiedadPorId(data.Propiedad);
if (prop == null || prop.Idestado != 1) return BadRequest(new{message="No hay una propiedad dada de alta para ese id"});
if (prop.DnipropietarioNavigation == null) return BadRequest(new{message="la propiedad no tiene propietario dado de alto ????"});
if (prop == null || prop.Idestado != 1) return BadRequest(new { message = "No hay una propiedad dada de alta para ese id" });
if (prop.DnipropietarioNavigation == null) return BadRequest(new { message = "la propiedad no tiene propietario dado de alto ????" });
var noti = new NotificacioneBuilder()
.SetAccion(data.Accion)
@@ -90,23 +96,24 @@ public class NotificacionesController: ControllerBase {
.SetIdpropiedad(prop.Id)
.SetFecha(DateTime.Now)
.Build();
var ret = RepositorioNotificaciones.Singleton.AltaNotificacion(noti);
return ret?
Ok(new {message = "Se envio la notificacion"}):BadRequest(new {message = "Fallo al intentar guardar la notificacion"});
return ret ?
Ok(new { message = "Se envio la notificacion" }) : BadRequest(new { message = "Fallo al intentar guardar la notificacion" });
}
[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");
if (validacion1 == false)return Unauthorized();
if (data.Mensaje == "") return BadRequest(new {message = "El campo Mensaje esta vacio"});
if (data.Idpropiedad <= 0) return BadRequest(new {message = "La id de propiedad no puede ser 0 o menor"});
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 12);
if (validacion1 == false) return Unauthorized();
if (data.Mensaje == "") return BadRequest(new { message = "El campo Mensaje esta vacio" });
if (data.Idpropiedad <= 0) return BadRequest(new { message = "La id de propiedad no puede ser 0 o menor" });
Contrato? cont = RepositorioContratos.Singleton.ObtenerContratoPorId(data.Idpropiedad);
if (cont == null || cont.DniinquilinoNavigation == null || cont.DnipropietarioNavigation == null || cont.IdpropiedadNavigation == null) return BadRequest(new { message = "no hay un contrato por esa id"});
if (cont == null || cont.DniinquilinoNavigation == null || cont.DnipropietarioNavigation == null || cont.IdpropiedadNavigation == null) return BadRequest(new { message = "no hay un contrato por esa id" });
var n = new NotificacioneBuilder()
.SetAccion("Notificacion Inquilino")
@@ -118,41 +125,42 @@ public class NotificacionesController: ControllerBase {
.SetFecha(DateTime.Now)
.Build();
var ret = RepositorioNotificaciones.Singleton.AltaNotificacion(n);
return ret?
Ok(new { message = "se envio el aviso" }):BadRequest(new { message = "Fallo al intentar enviar el aviso" });
return ret ?
Ok(new { message = "se envio el aviso" }) : BadRequest(new { message = "Fallo al intentar enviar el aviso" });
}
[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) {
return Unauthorized();
}
var validacion1 = RepositorioPermisos.Singleton.CheckPermisos(Auth, 16);
if (validacion1 == false)
{
return Unauthorized();
}
if (dto.Accion == "") return BadRequest(new{message = "El campo Accion esta vacio"});
if (dto.Mensaje == "") return BadRequest(new {message = "El campo Mensaje esta vacio"});
if (dto.Accion == "") return BadRequest(new { message = "El campo Accion esta vacio" });
if (dto.Mensaje == "") return BadRequest(new { message = "El campo Mensaje esta vacio" });
Cliente?cli = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);
Cliente? cli = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);
Propiedade? prop = RepositorioPropiedades.Singleton.ObtenerPropiedadPorId(dto.Propiedad);
if (prop == null) return BadRequest(new { message = "No hay una propiedad con id 0 o menor"});
if (prop == null) return BadRequest(new { message = "No hay una propiedad con id 0 o menor" });
var n = new NotificacioneBuilder()
.SetAccion("Consulta Compra")
.SetMensaje(dto.Mensaje)
.SetLeido(false)
.SetDnicliente(prop.Dnipropietario??0)
.SetDnicliente(prop.Dnipropietario ?? 0)
.SetDniremitente(cli.Dni)
.SetIdpropiedad(prop.Id)
.SetFecha(DateTime.Now)
.Build();
var ret2= RepositorioNotificaciones.Singleton.AltaNotificacion(n, cli.Dni);
return ret2?
Ok(new { message = "se envio el aviso" }):BadRequest(new { message = "Fallo al intentar enviar el aviso" });
var ret2 = RepositorioNotificaciones.Singleton.AltaNotificacion(n, cli.Dni);
return ret2 ?
Ok(new { message = "se envio el aviso" }) : BadRequest(new { message = "Fallo al intentar enviar el aviso" });
}
}
}

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,31 +31,35 @@ 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();
}
if (pag<=0) return BadRequest(new { message = "no existe una pagina 0"});
if (pag <= 0) return BadRequest(new { message = "no existe una pagina 0" });
pag-=1;
pag -= 1;
var props = RepositorioPropiedades.Singleton.ObtenerPropiedadesEnVenta(pag);
if (props == null) return BadRequest(new { message = "no tengo claro que fallo creo que no existen propiedades en venta"});
if (props == null) return BadRequest(new { message = "no tengo claro que fallo creo que no existen propiedades en venta" });
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,
Divisa = i.IddivisaNavigation.Signo,
Letra = i.Letra??"",
Letra = i.Letra ?? "",
Monto = i.Monto,
Piso = i.Piso??0,
Servicios =string.Join(", ", i.IdServicios.Select(s => s.Descripcion)),
Piso = i.Piso ?? 0,
Servicios = string.Join(", ", i.IdServicios.Select(s => s.Descripcion)),
Tipo = i.IdtipropiedadNavigation.Descripcion,
};
l.Add(p);
@@ -58,31 +67,35 @@ public class PropiedadesController: ControllerBase {
int cantpag = RepositorioPropiedades.Singleton.ObtenerPaginasDePropiedadesEnVenta();
return Ok(new { propiedades = l, cantpaginas = cantpag});
return Ok(new { propiedades = l, cantpaginas = cantpag });
}
[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();
}
Cliente? cli = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);
if (cli == null) return Unauthorized();
var props = RepositorioPropiedades.Singleton.ObtenerPropiedadesAVentaPorDni(cli.Dni);
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,
Iddivisa = i.Iddivisa,
letra = i.Letra??"",
letra = i.Letra ?? "",
Monto = (int)i.Monto, //mmmm
piso = i.Piso??0,
piso = i.Piso ?? 0,
Servicios = string.Join(", ", i.IdServicios.Select(x => x.Descripcion)),
Tipo = i.IdtipropiedadNavigation.Descripcion,
};
@@ -92,71 +105,79 @@ 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();
if (Id < 0) return BadRequest(new {message ="la id de propiedad no puede ser negativa"});
if (Id < 0) return BadRequest(new { message = "la id de propiedad no puede ser negativa" });
var ret = RepositorioPropiedades.Singleton.ObtenerPropiedadPorId(Id);
if (ret == null) return BadRequest(new {message ="No existe la propiedad"});
if (ret == null) return BadRequest(new { message = "No existe la propiedad" });
return Ok(ret);
}
[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();
if (estado < 0) return BadRequest(new {message = "No puede tener un numero menor a 0"});
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);
}
return Ok(new {message = cant});
return Ok(new { message = cant });
}
[HttpGet("api/propiedades/Propietario")]
public IActionResult ObtenerPropiedadesPorPropietario (
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);
if (validacion1 == false) return Unauthorized();
email = email.Trim();
if (String.IsNullOrEmpty(email)) return BadRequest(new {message ="falta campo email"});
if (String.IsNullOrEmpty(email)) return BadRequest(new { message = "falta campo email" });
IQueryable<PropiedadesDto> ret = RepositorioPropiedades.Singleton.ObtenerPropiedadesPorEmail(email);
return Ok(ret);
}
[HttpGet("api/propiedades/Propietario/Bajas")]
public IActionResult ObtenerPropiedadesPorPropietarioBajas (
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);
if (validacion1 == false) return Unauthorized();
email = email.Trim();
if (String.IsNullOrEmpty(email)) return BadRequest(new {message ="falta campo email"});
if (String.IsNullOrEmpty(email)) return BadRequest(new { message = "falta campo email" });
IQueryable<PropiedadesDto> ret = RepositorioPropiedades.Singleton.ObtenerPropiedadesDeBajaPorEmail(email);
return Ok(ret);
}
[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();
@@ -165,9 +186,10 @@ public class PropiedadesController: ControllerBase {
if (validacion2 != "") return BadRequest(new { message = validacion2 });
Cliente? cli = RepositorioPropietario.Singleton.ObtenerPropietarioPorEmail(propiedad.Email);
if (cli == null) return BadRequest(new { message = "El email no corresponde a un propietario"});
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,28 +200,33 @@ public class PropiedadesController: ControllerBase {
Iddivisa = propiedad.Iddivisa,
};
var ret = RepositorioPropiedades.Singleton.AñadirPropiedad(Prop);
return (ret)?
Ok(new { message = "Fue Cargado Correctamente"}) :
BadRequest(new { message = "Fallo al momento de añadir la propiedad a la base de datos"});
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);
if (validacion1 == false) return Unauthorized();
string validacion2 = ValidarPropiedad(propiedad);
if (validacion2 != "") return BadRequest(new { message = validacion2 });
Cliente? cli = RepositorioPropietario.Singleton.ObtenerPropietarioPorEmail(propiedad.Email);
if (cli == null) return BadRequest(new { message = "El email no corresponde a un propietario"});
if (cli == null) return BadRequest(new { message = "El email no corresponde a un propietario" });
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,
@@ -213,61 +240,64 @@ public class PropiedadesController: ControllerBase {
};
bool ret = RepositorioPropiedades.Singleton.PatchPropiedad(Prop, cli.Dni);
return (ret)?
Ok(new {message = "Fue modificado Correctamente"}):
BadRequest(new {message = "Fallo al modificar la base de datos"});
}
return (ret) ?
Ok(new { message = "Fue modificado Correctamente" }) :
BadRequest(new { message = "Fallo al modificar la base de datos" });
}
[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();
if (String.IsNullOrEmpty(email)) return BadRequest(new { message = "Fallo al identificarse el usuario"});
if (id <= 0) return BadRequest(new { message = "No es una id valida"});
if (String.IsNullOrEmpty(email)) return BadRequest(new { message = "Fallo al identificarse el usuario" });
if (id <= 0) return BadRequest(new { message = "No es una id valida" });
Cliente? propie = RepositorioPropietario.Singleton.ObtenerPropietarioPorEmail(email);
var ret = RepositorioPropiedades.Singleton.BajaPropiedad(id, propie);
return ret ?
Ok(new { message = $"Se Cambio el estado de la propiedad con id {id}"}):
BadRequest(new {message="Fallo al cambiar el estado de la propiedad"});
}
return ret ?
Ok(new { message = $"Se Cambio el estado de la propiedad con id {id}" }) :
BadRequest(new { message = "Fallo al cambiar el estado de la propiedad" });
}
[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();
if (Servicios.propiedadid <= 0) return BadRequest(new {message ="No puede tener una id negativa o cero"});
if (Servicios.idServicios.Count() < 1) return BadRequest(new {message ="Falta añadir servicios"});
if (Servicios.idServicios.Any(x => x<= 0)) return BadRequest(new {message ="No tienen haber ids negativas o cero de servicio"});
if (Servicios.propiedadid <= 0) return BadRequest(new { message = "No puede tener una id negativa o cero" });
if (Servicios.idServicios.Count() < 1) return BadRequest(new { message = "Falta añadir servicios" });
if (Servicios.idServicios.Any(x => x <= 0)) return BadRequest(new { message = "No tienen haber ids negativas o cero de servicio" });
var serv = RepositorioServicios.Singleton.ObtenerServiciosPorPropiedad(Servicios.propiedadid);
bool validacion2 = Servicios.idServicios.Any(x => serv.Contains(x));
if (validacion2 == true) return BadRequest(new {message ="Hay elementos repetidos"});
if (validacion2 == true) return BadRequest(new { message = "Hay elementos repetidos" });
bool ret = RepositorioPropiedades.
Singleton.AñadirServicioAPropiedad(Servicios.propiedadid, Servicios.idServicios);
return ret ?
Ok(new {message ="Los Servicios Se Cargaron correctamente a la propiedad"}) : BadRequest(new {message ="No se pudo Cargar los Servicios a la propiedad"});
Ok(new { message = "Los Servicios Se Cargaron correctamente a la propiedad" }) : BadRequest(new { message = "No se pudo Cargar los Servicios a la propiedad" });
}
[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();
if (servicio.propiedadid <= 0) return BadRequest(new {message ="No puede tener una id negativa o cero"});
if (servicio.idServicios.Count() < 1) return BadRequest(new {message ="Falta añadir servicios"});
if (servicio.idServicios.Any(x => x<= 0)) return BadRequest(new {message ="No tienen haber ids negativas o cero de servicio"});
if (servicio.propiedadid <= 0) return BadRequest(new { message = "No puede tener una id negativa o cero" });
if (servicio.idServicios.Count() < 1) return BadRequest(new { message = "Falta añadir servicios" });
if (servicio.idServicios.Any(x => x <= 0)) return BadRequest(new { message = "No tienen haber ids negativas o cero de servicio" });
Cliente? cli = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);
@@ -276,49 +306,51 @@ public class PropiedadesController: ControllerBase {
var repetidos = serv.Intersect(servicio.idServicios);
bool ret = RepositorioPropiedades.Singleton.BajaServiciosAPropiedad(servicio.propiedadid, servicio.idServicios, cli.Dni);
return ret ?
Ok(new {message ="Se Eliminaron los servicios seleccionados de la propiedad"}) : BadRequest(new {message ="Fallo al eliminarse los servicios de la propiedad"});
Ok(new { message = "Se Eliminaron los servicios seleccionados de la propiedad" }) : BadRequest(new { message = "Fallo al eliminarse los servicios de la propiedad" });
}
private string ValidarPropiedad(AltaPropiedadDto prop) {
private string ValidarPropiedad(AltaPropiedadDto prop)
{
if (prop == null) return "Esta mal formado el body de la request";
string ret = "";
if (String.IsNullOrEmpty(prop.Email)) ret += "Falta Definir un email de propietario\n";
if (prop.Canthabitaciones < 0) ret += "No se puede tener una cantidad de habitaciones negativa\n";
if (prop.Idtipropiedad <= 0) ret += "No tiene un tipo de propiedad asociada\n";
if (String.IsNullOrEmpty(prop.Ubicacion)) ret += "Tiene que definir la ubicacion de la propiedad\n";
if (prop.Monto<=1) ret += "El monto tiene que ser como minimo mayor a 0";
if (prop.Iddivisa<0 || prop.Iddivisa>1) ret += "se tiene que elejir entre AR$ y US$";
if (prop.Monto <= 1) ret += "El monto tiene que ser como minimo mayor a 0";
if (prop.Iddivisa < 0 || prop.Iddivisa > 1) ret += "se tiene que elejir entre AR$ y US$";
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 = "";
if (prop.id <1) ret += "No Cargo el dato de id";
if (prop.id < 1) ret += "No Cargo el dato de id";
if (String.IsNullOrEmpty(prop.Email)) ret += "Falta Definir un email de propietario\n";
if (prop.id <1 ) ret += "No puede haber una id menor a 1\n";
if (prop.id < 1) ret += "No puede haber una id menor a 1\n";
if (prop.Canthabitaciones < 0) ret += "No se puede tener una cantidad de habitaciones negativa\n";
if (prop.tipo <= 0) ret += "No tiene un tipo de propiedad asociada\n";
if (String.IsNullOrEmpty(prop.Ubicacion)) ret += "Tiene que definir la ubicacion de la propiedad\n";
if (prop.Monto<=1) ret += "El monto tiene que ser como minimo mayor a 0";
if (prop.Iddivisa<0 || prop.Iddivisa>1) ret += "se tiene que elejir entre AR$ y US$";
if (prop.Monto <= 1) ret += "El monto tiene que ser como minimo mayor a 0";
if (prop.Iddivisa < 0 || prop.Iddivisa > 1) ret += "se tiene que elejir entre AR$ y US$";
return 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();
@@ -22,8 +24,9 @@ public class PropietarioController: ControllerBase {
}
[HttpPost("api/propietario")]
public IActionResult AltaPropietario([FromBody]CrearClienteDto Propietario,
[FromHeader(Name = "Auth")] string Auth) {
public IActionResult AltaPropietario([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();
@@ -33,8 +36,9 @@ 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,15 +47,17 @@ 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);
return ret ?
Ok(new {message = "Se añadio el propietario exitosamente"}) : BadRequest();
return ret ?
Ok(new { message = "Se añadio el propietario exitosamente" }) : BadRequest();
}
[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,
@@ -69,11 +76,12 @@ public class PropietarioController: ControllerBase {
Contraseña = Encoding.UTF8.GetBytes(HacerHash(Propietario.contraseña))
};
var ret = RepositorioUsuarios.Singleton.ActualizarPropietario(cli);
return ret ?
Ok(new {message = "Se Modifico el propietario exitosamente"}) : BadRequest();
return ret ?
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,8 +95,9 @@ 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("-","");
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,27 +10,31 @@ 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"});
if (dto.Email == "") return BadRequest(new { message = "Falta dato Email" });
Cliente? cli = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);
if (cli == null) Unauthorized();
if (cli.Email != dto.Email) return BadRequest(new {message = "El token de autorizacion no corresponde a tu usuario"});
if (cli.Email != dto.Email) return BadRequest(new { message = "El token de autorizacion no corresponde a tu usuario" });
RepositorioNotificaciones.Singleton.MarcarComoLeido(cli.Dni, dto.Fecha);
Notificacione? n = RepositorioNotificaciones.Singleton.ObtenerNotificacionPorKeys(cli.Dni, dto.Fecha);
if (n == null) return BadRequest(new { message = "No se encuentra la notificacion"});
Notificacione? n = RepositorioNotificaciones.Singleton.ObtenerNotificacionPorKeys(cli.Dni, dto.Fecha);
if (n == null) return BadRequest(new { message = "No se encuentra la notificacion" });
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{
if (prop == null) return BadRequest(new { message = "No se encuentra una propiedad por ese id" });
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")
@@ -56,25 +59,27 @@ public class VentaController:ControllerBase {
.Build();
ret = RepositorioNotificaciones.Singleton.AltaNotificacion(noti);
}
return ret?
Ok(new { message = "Se inicio la venta"}):BadRequest(new { message ="fallo al iniciar la venta"});
return ret ?
Ok(new { message = "Se inicio la venta" }) : BadRequest(new { message = "fallo al iniciar la venta" });
}
[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();
}
if (dto.Email == "") return BadRequest(new { message = "Falta dato Email"});
if (dto.Email == "") return BadRequest(new { message = "Falta dato Email" });
Cliente? cli = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);
if (cli == null) Unauthorized();
if (cli.Email != dto.Email) return BadRequest(new {message = "El token de autorizacion no corresponde a tu usuario"});
if (cli.Email != dto.Email) return BadRequest(new { message = "El token de autorizacion no corresponde a tu usuario" });
RepositorioNotificaciones.Singleton.MarcarComoLeido(cli.Dni, dto.Fecha);
Notificacione? n = RepositorioNotificaciones.Singleton.ObtenerNotificacionPorKeys(cli.Dni, dto.Fecha);
Notificacione? n = RepositorioNotificaciones.Singleton.ObtenerNotificacionPorKeys(cli.Dni, dto.Fecha);
var noti = new NotificacioneBuilder()
.SetAccion("Notificacion")
.SetMensaje("El propietario no quiere vender")
@@ -84,90 +89,84 @@ public class VentaController:ControllerBase {
.SetIdpropiedad(n.Idpropiedad)
.SetFecha(DateTime.Now)
.Build();
var ret = RepositorioNotificaciones.Singleton.AltaNotificacion(noti);
return ret ?
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});
Ok(new { message = "Se Envio una notificacion" }) : BadRequest(new { message = "Fallo al Descartar Consulta" });
}
[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();
}
if (dto.iddivisa != 0 && dto.iddivisa!=1) return BadRequest(new { message = "no hay una divisa por esa id"});
if (dto.idpropiedad<=0) return BadRequest(new { message = "No hay propiedades con id 0 o menor"});
if (dto.monto<1) return BadRequest(new { message = "No se pueden hacer ventas por montos menores a 1"});
if (dto.iddivisa != 0 && dto.iddivisa != 1) return BadRequest(new { message = "no hay una divisa por esa id" });
if (dto.idpropiedad <= 0) return BadRequest(new { message = "No hay propiedades con id 0 o menor" });
if (dto.monto < 1) return BadRequest(new { message = "No se pueden hacer ventas por montos menores a 1" });
Cliente? cli = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);
if (cli == null) return Unauthorized();
Propiedade? prop = RepositorioPropiedades.Singleton.ObtenerPropiedadPorId(dto.idpropiedad);
if (prop == null) return BadRequest(new { message = "No hay propiedades por ese id"});
if (prop == null) return BadRequest(new { message = "No hay propiedades por ese id" });
if (cli.Dni != prop.Dnipropietario) return Unauthorized();
var ret = RepositorioVentas.Singleton.SetVenta(prop.Id, dto.monto, dto.iddivisa, cli.Dni);
return ret?
Ok(new { message = "Se puso la propiedad de venta"}) : BadRequest(new { message = "No se pudo poner a la Venta"});
return ret ?
Ok(new { message = "Se puso la propiedad de venta" }) : BadRequest(new { message = "No se pudo poner a la Venta" });
}
[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();
}
if (dto.iddivisa != 0 && dto.iddivisa!=1) return BadRequest(new { message = "no hay una divisa por esa id"});
if (dto.idpropiedad<=0) return BadRequest(new { message = "No hay propiedades con id 0 o menor"});
if (dto.monto<1) return BadRequest(new { message = "No se pueden hacer ventas por montos menores a 1"});
if (dto.iddivisa != 0 && dto.iddivisa != 1) return BadRequest(new { message = "no hay una divisa por esa id" });
if (dto.idpropiedad <= 0) return BadRequest(new { message = "No hay propiedades con id 0 o menor" });
if (dto.monto < 1) return BadRequest(new { message = "No se pueden hacer ventas por montos menores a 1" });
Cliente? cli = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);
if (cli == null) return Unauthorized();
Propiedade? prop = RepositorioPropiedades.Singleton.ObtenerPropiedadPorId(dto.idpropiedad);
if (prop == null) return BadRequest(new { message = "No hay propiedades por ese id"});
if (prop == null) return BadRequest(new { message = "No hay propiedades por ese id" });
if (cli.Dni != prop.Dnipropietario) return Unauthorized();
bool ret = RepositorioVentas.Singleton.UnSetVenta(prop.Id, dto.monto, dto.iddivisa, cli.Dni);
return ret?
Ok(new { message = "Se Bajo la propiedad de venta"}) : BadRequest(new { message = "No se pudo Bajar de venta"});
return ret ?
Ok(new { message = "Se Bajo la propiedad de venta" }) : BadRequest(new { message = "No se pudo Bajar de venta" });
}
[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"});
if (idcontrato <= 0) return BadRequest(new { message = "No pueden hacer cotratos con id 0 o menor" });
Cliente? cli = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);
if (cli == null) return Unauthorized();
Contrato? cont = RepositorioVentas.Singleton.ObtenerVentaPorContrato(idcontrato);
if (cont == null || cont.IdventaNavigation == null) return BadRequest(new { message = "no hay un contrato por esa id"});
if (cont.Tieneopcionventa == 0) return BadRequest(new { message = "No tiene opcion de venta"});
if (puedeEjercer(cont) == false) return BadRequest(new { message = "No cumple con los requisitos para ejercer la opcion de compra"});
if (cont == null || cont.IdventaNavigation == null) return BadRequest(new { message = "no hay un contrato por esa id" });
if (cont.Tieneopcionventa == 0) return BadRequest(new { message = "No tiene opcion de venta" });
if (puedeEjercer(cont) == false) return BadRequest(new { message = "No cumple con los requisitos para ejercer la opcion de compra" });
Venta venta = cont.IdventaNavigation;
venta.IdVendedor = cont.Dnipropietario;
@@ -177,31 +176,30 @@ public class VentaController:ControllerBase {
bool ret = RepositorioVentas.Singleton.PatchVenta(venta, cli.Dni);
return ret?
Ok(new { message = "Se ejercio la opcion de venta"}):
BadRequest(new { message = "No se pude ejercer la opcion de venta"});
return ret ?
Ok(new { message = "Se ejercio la opcion de venta" }) :
BadRequest(new { message = "No se pude ejercer la opcion de venta" });
}
[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) {
return Unauthorized();
}
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" });
if (idventa <= 0) return BadRequest(new { message = "Las id 0 o menor no son validas" });
Cliente? cli = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);
if (cli == null) return Unauthorized();
Venta? venta = RepositorioVentas.Singleton.ObtenerVentaPorId(idventa);
if (venta == null) return BadRequest(new { message = "no hay una venta por esa id"});
if (venta == null) return BadRequest(new { message = "no hay una venta por esa id" });
if (cli.Dni !=venta.IdComprador && cli.Dni != venta.IdVendedor) return Unauthorized();
if (cli.Dni != venta.IdComprador && cli.Dni != venta.IdVendedor) return Unauthorized();
if (file == null) return BadRequest(new { message = "Debe subir un archivo." });
if (file.ContentType != "application/pdf") return BadRequest(new { message = "El archivo debe ser un documento PDF." });
@@ -209,39 +207,45 @@ public class VentaController:ControllerBase {
string nuevoNombreArchivo = $"id:{venta.Id}-comprador:{venta.IdComprador}-vendedor:{venta.IdVendedor}-idprop:{venta.Idpropiedad}.pdf";
bool ret = await subirContrato(file, nuevoNombreArchivo);
if(ret == false) return BadRequest(new {message = "No se pudo subir el archivo"});
if (ret == false) return BadRequest(new { message = "No se pudo subir el archivo" });
ret = RepositorioVentas.Singleton.SetUrlRecibo(venta.Id, nuevoNombreArchivo, cli.Dni);
if (ret == false) return BadRequest(new { message = "no se pudo guardar el nombre del archivo subido"});
if (ret == false) return BadRequest(new { message = "no se pudo guardar el nombre del archivo subido" });
return Ok(new { message = "Se Subio el Recibo"});
return Ok(new { message = "Se Subio el Recibo" });
}
private readonly IMinioClient mc;
public VentaController(IMinioClient minioClient) {
public VentaController(IMinioClient minioClient)
{
mc = minioClient;
if (mc == null){
MinioConfigcus? mcon = JsonSerializer.Deserialize<MinioConfigcus>(System.IO.File.ReadAllText("./settings.json"))?? null;
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 {
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;
stream.Position = 0;
PutObjectArgs putbj = new PutObjectArgs()
.WithBucket("alquilafacil")
.WithObject(flname)
@@ -251,140 +255,140 @@ 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) {
return Unauthorized();
}
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"});
if (idventa <= 0) return BadRequest(new { message = "No existen ventas validas para la id 0" });
Cliente? cli = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);
if (cli == null) return Unauthorized();
Venta? venta = RepositorioVentas.Singleton.ObtenerVentaPorId(idventa);
if (venta == null) return BadRequest(new { message = "no hay una venta con esa id"});
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{
var memstream = new MemoryStream();
try
{
var memstream = new MemoryStream();
var goa = new GetObjectArgs()
.WithBucket("alquilafacil")
.WithObject(venta.UrlRecibo)
.WithCallbackStream(stream => {
memstream.Position=0;
.WithCallbackStream(stream =>
{
memstream.Position = 0;
stream.CopyTo(memstream);
});
});
mc.GetObjectAsync(goa).Wait();
memstream.Position = 0;
if (memstream.Length == 0) return BadRequest(new { message = "El archivo está vacío" });
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"});
return BadRequest(new { message = "Fallo al intentar obtener el archivo del almacenamiento o este no existe" });
}
}
[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) {
return Unauthorized();
}
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"});
if (idventa <= 0) return BadRequest(new { message = "No existen ventas validas para la id 0" });
Cliente? cli = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);
if (cli == null) return Unauthorized();
var ventas = RepositorioVentas.Singleton.ObtenerVentaPorId(idventa);
if (ventas == null) return BadRequest(new { message ="No hay una venta con ese id"});
if (ventas == null) return BadRequest(new { message = "No hay una venta con ese id" });
if (ventas.IdVendedor != cli.Dni) return Unauthorized();
bool ret = RepositorioVentas.Singleton.EfectuarVenta(idventa);
return ret ? Ok(new { message = "Se traspaso la propiedad"}): BadRequest(new { message = ""});
return ret ? Ok(new { message = "Se traspaso la propiedad" }) : BadRequest(new { message = "" });
}
[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();
}
}
if (idventa <= 0) return BadRequest(new { message = "No existen ventas validas para la id 0"});
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);
if (cli == null) return Unauthorized();
var ventas = RepositorioVentas.Singleton.ObtenerVentaPorId(idventa);
if (ventas == null) return BadRequest(new { message ="No hay una venta con ese id"});
if (ventas.IdVendedor !=cli.Dni && ventas.IdComprador != cli.Dni) return Unauthorized();
if (ventas == null) return BadRequest(new { message = "No hay una venta con ese id" });
if (ventas.IdVendedor != cli.Dni && ventas.IdComprador != cli.Dni) return Unauthorized();
var v = new VentasDtoBuilder()
.SetId(ventas.Id)
.SetMonto(ventas.Monto)
.SetDivisa(ventas.IddivisaNavigation.Signo)
.SetUbicacion(ventas.IdpropiedadNavigation.Ubicacion)
.SetNombreVendedor($"{ventas.IdVendedorNavigation.Nombre} {ventas.IdVendedorNavigation.Apellido}")
.SetIdVendedor(ventas.IdVendedor??0)
.SetNombreComprador($"{ventas.IdCompradorNavigation.Nombre} {ventas.IdCompradorNavigation.Apellido}")
.SetIdComprador(ventas.IdComprador??0)
.SetEstado(ventas.IdestadoNavigation.Descripcion??"")
.SetId(ventas.Id)
.SetMonto(ventas.Monto)
.SetDivisa(ventas.IddivisaNavigation.Signo)
.SetUbicacion(ventas.IdpropiedadNavigation.Ubicacion)
.SetNombreVendedor($"{ventas.IdVendedorNavigation.Nombre} {ventas.IdVendedorNavigation.Apellido}")
.SetIdVendedor(ventas.IdVendedor ?? 0)
.SetNombreComprador($"{ventas.IdCompradorNavigation.Nombre} {ventas.IdCompradorNavigation.Apellido}")
.SetIdComprador(ventas.IdComprador ?? 0)
.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();
var ventas = RepositorioVentas.Singleton.ObtenerVentasPorDni(cli.Dni);
if (ventas == null) return BadRequest(new { message ="no estas involucrado en ninguna venta o compra"});
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)
.SetDivisa(i.IddivisaNavigation.Signo)
.SetUbicacion(i.IdpropiedadNavigation.Ubicacion)
.SetNombreVendedor($"{i.IdVendedorNavigation.Nombre} {i.IdVendedorNavigation.Apellido}")
.SetIdVendedor(i.IdVendedor??0)
.SetNombreComprador($"{i.IdCompradorNavigation.Nombre} {i.IdCompradorNavigation.Apellido}")
.SetIdComprador(i.IdComprador??0)
.SetEstado(i.IdestadoNavigation.Descripcion??"")
.SetId(i.Id)
.SetMonto(i.Monto)
.SetDivisa(i.IddivisaNavigation.Signo)
.SetUbicacion(i.IdpropiedadNavigation.Ubicacion)
.SetNombreVendedor($"{i.IdVendedorNavigation.Nombre} {i.IdVendedorNavigation.Apellido}")
.SetIdVendedor(i.IdVendedor ?? 0)
.SetNombreComprador($"{i.IdCompradorNavigation.Nombre} {i.IdCompradorNavigation.Apellido}")
.SetIdComprador(i.IdComprador ?? 0)
.SetEstado(i.IdestadoNavigation.Descripcion ?? "")
.Build();
lista.Add(v);
}
@@ -392,43 +396,51 @@ 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();
}
}
if (idcontrato == 0) return BadRequest(new { message = "No existen contatos validos para la id 0"});
if (idcontrato == 0) return BadRequest(new { message = "No existen contatos validos para la id 0" });
Cliente? cli = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);
if (cli == null) return Unauthorized();
Contrato? cont = RepositorioVentas.Singleton.ObtenerVentaPorContrato(idcontrato);
if (cont == null) return BadRequest(new { message = "No hay un contrato por esa id"});
if (cont == null) return BadRequest(new { message = "No hay un contrato por esa id" });
var dto = new OpcionVentaDtoBuilder()
.SetId(cont.Idventa??0)
.SetId(cont.Idventa ?? 0)
.SetMonto(cont.IdventaNavigation.Monto)
.SetDivisa(cont.IdventaNavigation.IddivisaNavigation.Signo)
.SetEnOrden(puedeEjercer(cont))
.SetFueEjercido(cont.IdventaNavigation.Idestado??0)
.SetFueEjercido(cont.IdventaNavigation.Idestado ?? 0)
.Build();
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) {
if (canonConFechaMasTardia != null && canonConFechaMasTardia.Fecha.Year >= DateTime.Now.Year
&& canonConFechaMasTardia.Fecha.Month >= DateTime.Now.Month)
{
ret = true;
}else{
}
else
{
ret = false;
}
}
@@ -437,24 +449,27 @@ 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();
}
}
if (idcontrato == 0) return BadRequest(new { message = "No existen contatos validos para la id 0"});
if (idcontrato == 0) return BadRequest(new { message = "No existen contatos validos para la id 0" });
Cliente? cli = RepositorioUsuarios.Singleton.ObtenerClientePorToken(Auth);
if (cli == null) return Unauthorized();
Contrato? cont = RepositorioContratos.Singleton.ObtenerContratoPorId(idcontrato);
if (cont == null) return BadRequest(new { message = "No hay un contrato por esa id"});
if (cont.Dniinquilino !=cli.Dni && cont.Dnipropietario != cli.Dni) return Unauthorized();
if (cont == null) return BadRequest(new { message = "No hay un contrato por esa id" });
if (cont.Dniinquilino != cli.Dni && cont.Dnipropietario != cli.Dni) return Unauthorized();
return Ok( new { message = cont.Tieneopcionventa});
return Ok(new { message = cont.Tieneopcionventa });
}
}
}

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"
"usr": "nwFNMLJcn5m0owbzeXMs",
"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"
"usr": "nwFNMLJcn5m0owbzeXMs",
"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,12 +4,17 @@ using System.Text.Json.Serialization;
namespace Entidades;
public partial class Permiso
public partial class Permiso:IComponenteSeguridad
{
public int Id { get; set; }
public string Descripcion { get; set; } = null!;
[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

@@ -1,6 +1,10 @@
run:
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 .
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 .
./convert_to_pascalcase.sh
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,169 +1,201 @@
<script lang="ts">
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 InqPage from "./paginas/inquilino.svelte";
import PropPage from "./paginas/propietario.svelte";
import MisPropiedades from "./paginas/MisPropiedades.svelte";
import MisPropiedadesDeBaja from "./paginas/MisPropiedadesDeBaja.svelte";
import FrontAdmin from "./paginas/grupos/AdminG.svelte";
import FrontInformes from "./paginas/grupos/InformesG.svelte";
import FrontInquilino from "./paginas/grupos/InquilinoG.svelte";
import FrontPropietario from "./paginas/grupos/PropietarioG.svelte";
import PublicarPropiedad from "./paginas/PublicarPropiedad.svelte";
import BusquedaPropiedades from "./paginas/BusquedaPropiedades.svelte";
import AdminUsuarios from "./paginas/AdminUsuarios.svelte";
import AdminPropiedades from "./paginas/AdminPropiedades.svelte";
import Notificaciones from "./paginas/Notificaciones.svelte";
import ControlAlquileresInquilino from "./paginas/ControlAlquileresInquilino.svelte";
import ControlAlquileresPropietario from "./paginas/ControlAlquileresPropietario.svelte";
import ContratosPropietario from "./paginas/ContratosPropietario.svelte";
import ContratoInquilino from "./paginas/ContratoInquilino.svelte";
import Informes from "./paginas/Informes.svelte";
import CompraYVentas from "./paginas/CompraYVenta.svelte";
import Ventas from "./paginas/Ventas.svelte";
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 InqPage from "./paginas/inquilino.svelte";
import PropPage from "./paginas/propietario.svelte";
import MisPropiedades from "./paginas/MisPropiedades.svelte";
import MisPropiedadesDeBaja from "./paginas/MisPropiedadesDeBaja.svelte";
import FrontAdmin from "./paginas/grupos/AdminG.svelte";
import FrontInformes from "./paginas/grupos/InformesG.svelte";
import FrontInquilino from "./paginas/grupos/InquilinoG.svelte";
import FrontPropietario from "./paginas/grupos/PropietarioG.svelte";
import PublicarPropiedad from "./paginas/PublicarPropiedad.svelte";
import BusquedaPropiedades from "./paginas/BusquedaPropiedades.svelte";
import AdminUsuarios from "./paginas/AdminUsuarios.svelte";
import AdminPropiedades from "./paginas/AdminPropiedades.svelte";
import Notificaciones from "./paginas/Notificaciones.svelte";
import ControlAlquileresInquilino from "./paginas/ControlAlquileresInquilino.svelte";
import ControlAlquileresPropietario from "./paginas/ControlAlquileresPropietario.svelte";
import ContratosPropietario from "./paginas/ContratosPropietario.svelte";
import ContratoInquilino from "./paginas/ContratoInquilino.svelte";
import Informes from "./paginas/Informes.svelte";
import CompraYVentas from "./paginas/CompraYVenta.svelte";
import Ventas from "./paginas/Ventas.svelte";
import VerLogs from "./paginas/VerLogs.svelte";
import ControlPagos from "./paginas/ControlPagos.svelte";
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>
<!-- Plantilla path
<!-- Plantilla path
<Route path="">
<ProteRoute componente={}/>
</Route>
-->
<Route path="/" component={Login} />
<Route path="/Info" component={InfoPage} />
<Route path="/" component={Login} />
<Route path="/Info" component={InfoPage} />
<Route path="/Menu">
<ProteRoute componente={MenuPage} />
</Route>
<Route path="/Menu">
<ProteRoute componente={MenuPage} />
</Route>
<!--Publicar Prop
<!--Publicar Prop
iedad-->
<Route path="/accion/1">
<ProteRoute componente={PublicarPropiedad}/>
</Route>
<Route path="/accion/1">
<ProteRoute componente={PublicarPropiedad} />
</Route>
<!--Mis Propiedades-->
<Route path="/accion/2">
<ProteRoute componente={MisPropiedades}/>
</Route>
<!--Mis Propiedades-->
<Route path="/accion/2">
<ProteRoute componente={MisPropiedades} />
</Route>
<!--Buscar Propiedades-->
<Route path="/accion/3">
<ProteRoute componente={BusquedaPropiedades}/>
</Route>
<!--Buscar Propiedades-->
<Route path="/accion/3">
<ProteRoute componente={BusquedaPropiedades} />
</Route>
<!--Crear Cuenta Inquilino-->
<Route path="/accion/4">
<ProteRoute componente={InqPage}/>
</Route>
<!--Crear Cuenta Propietario-->
<Route path="/accion/5">
<ProteRoute componente={PropPage}/>
</Route>
<!--Crear Cuenta Inquilino-->
<Route path="/accion/4">
<ProteRoute componente={InqPage} />
</Route>
<!--Crear Cuenta Propietario-->
<Route path="/accion/6">
<ProteRoute componente={Informes}/>
</Route>
<Route path="/accion/5">
<ProteRoute componente={PropPage} />
</Route>
<!--Ver Logs-->
<Route path="/accion/7">
<ProteRoute componente={VerLogs}/>
</Route>
<!--Informes-->
<Route path="/accion/6">
<ProteRoute componente={Informes} />
</Route>
<!--Administrar Propiedades Dadas de Baja-->
<Route path="/accion/8">
<ProteRoute componente={MisPropiedadesDeBaja}/>
</Route>
<!--Ver Logs-->
<Route path="/accion/7">
<ProteRoute componente={VerLogs} />
</Route>
<!-- Pantalla Control Usuarios -->
<Route path="/accion/9">
<ProteRoute componente={AdminUsuarios}/>
</Route>
<!-- Pantalla Control Propiedades -->
<Route path="/accion/10">
<ProteRoute componente={AdminPropiedades}/>
</Route>
<!-- Pantalla Control Alquileres Inquilino -->
<Route path="/accion/11">
<ProteRoute componente={ControlAlquileresInquilino}/>
</Route>
<!-- Pantalla Control Alquileres Propietario -->
<Route path="/accion/12">
<ProteRoute componente={ControlAlquileresPropietario}/>
</Route>
<!--Administrar Propiedades Dadas de Baja-->
<Route path="/accion/8">
<ProteRoute componente={MisPropiedadesDeBaja} />
</Route>
<!-- Compra y Ventas -->
<Route path="/accion/13">
<ProteRoute componente={CompraYVentas}/>
</Route>
<!-- Pantalla Control Usuarios -->
<Route path="/accion/9">
<ProteRoute componente={AdminUsuarios} />
</Route>
<!-- Control Pago Contratos Incumplidos -->
<Route path="/accion/14">
<ProteRoute componente={ControlPagos}/>
</Route>
<!-- Pantalla Control Propiedades -->
<Route path="/accion/10">
<ProteRoute componente={AdminPropiedades} />
</Route>
<!-- VerPropiedadesEnVenta -->
<Route path="/accion/15">
<ProteRoute componente={MisPropiedadesEnVenta}/>
</Route>
<!-- Buscar Ventas -->
<Route path="/accion/16">
<ProteRoute componente={BuscarVentas}/>
</Route>
<!-- Pantalla Control Alquileres Inquilino -->
<Route path="/accion/11">
<ProteRoute componente={ControlAlquileresInquilino} />
</Route>
<!-- Pagina Ventas -->
<Route path="/Ventas">
<ProteRoute componente={Ventas}/>
</Route>
<!-- Pantalla Control Alquileres Propietario -->
<Route path="/accion/12">
<ProteRoute componente={ControlAlquileresPropietario} />
</Route>
<!--Paginas info Grupo-->
<Route path="/grupo/Inquilino">
<ProteRoute componente={FrontInquilino}/>
</Route>
<Route path="/grupo/Propietario">
<ProteRoute componente={FrontPropietario}/>
</Route>
<Route path="/grupo/Admin">
<ProteRoute componente={FrontAdmin}/>
</Route>
<Route path="/grupo/Informes">
<ProteRoute componente={FrontInformes}/>
</Route>
<!-- Compra y Ventas -->
<Route path="/accion/13">
<ProteRoute componente={CompraYVentas} />
</Route>
<!--Notificaciones-->
<Route path="/notificaciones">
<ProteRoute componente={Notificaciones}/>
</Route>
<!--Contratos Propietarios-->
<Route path="/propietario/contratos">
<ProteRoute componente={ContratosPropietario}/>
</Route>
<!-- Control Pago Contratos Incumplidos -->
<Route path="/accion/14">
<ProteRoute componente={ControlPagos} />
</Route>
<!--Contratos Inquilino-->
<Route path="/inquilino/contratos">
<ProteRoute componente={ContratoInquilino}/>
</Route>
<!-- VerPropiedadesEnVenta -->
<Route path="/accion/15">
<ProteRoute componente={MisPropiedadesEnVenta} />
</Route>
<!--Contratos Admin-->
<Route path="/admin/contratos">
<ProteRoute componente={ContratoAdmin}/>
</Route>
<!-- Buscar Ventas -->
<Route path="/accion/16">
<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} />
</Route>
<!--Paginas info Grupo-->
<Route path="/grupo/Inquilino">
<ProteRoute componente={FrontInquilino} />
</Route>
<Route path="/grupo/Propietario">
<ProteRoute componente={FrontPropietario} />
</Route>
<Route path="/grupo/Admin">
<ProteRoute componente={FrontAdmin} />
</Route>
<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} />
</Route>
<!--Contratos Inquilino-->
<Route path="/inquilino/contratos">
<ProteRoute componente={ContratoInquilino} />
</Route>
<!--Contratos Admin-->
<Route path="/admin/contratos">
<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,59 +1,56 @@
<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;
let chartContainer;
let instance;
onDestroy(() => {
if (instance) {
instance.destroy();
}
});
const createChart = () => {
if (instance) {
instance.destroy();
}
const ctx = chartContainer.getContext('2d');
instance = new Chart(ctx, {
type: typec,
data: {
labels: chartData.labels,
datasets: chartData.datasets.map(dataset => ({
label: dataset.label,
data: dataset.data.map(x => String(x)),
borderWidth: dataset.borderWidth
}))
},
options: {
responsive: true,
plugins: {
legend: {
position: 'top',
},
},
scales: {
x: {
beginAtZero: true,
},
y: {
beginAtZero: true,
},
},
},
onDestroy(() => {
if (instance) {
instance.destroy();
}
});
};
onMount(createChart);
$effect(createChart);
const createChart = () => {
if (instance) {
instance.destroy();
}
const ctx = chartContainer.getContext("2d");
instance = new Chart(ctx, {
type: typec,
data: {
labels: chartData.labels,
datasets: chartData.datasets.map((dataset) => ({
label: dataset.label,
data: dataset.data.map((x) => String(x)),
borderWidth: dataset.borderWidth,
})),
},
options: {
responsive: true,
plugins: {
legend: {
position: "top",
},
},
scales: {
x: {
beginAtZero: true,
},
y: {
beginAtZero: true,
},
},
},
});
};
onMount(createChart);
$effect(createChart);
</script>
<div class="card card-body">
<canvas bind:this={chartContainer}></canvas>
<canvas bind:this={chartContainer}></canvas>
</div>

View File

@@ -1,66 +1,283 @@
<script>
import { CardHeader, CardTitle, Button, Card, Input, Form, CardBody, FormGroup } from '@sveltestrap/sveltestrap';
import { navigate } from 'svelte-routing';
import { urlG } from "../stores/urlStore";
let email = $state("")
let contraseña = $state("")
let errorMessage = $state("")
// @ts-ignore
async function submitForm(event) {
event.preventDefault();
const data = {email, contraseña};
try{
const response = await fetch(String($urlG)+"/api/login",{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data),
credentials: "include"
});
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";
if (!response.ok){
const errorData = await response.json()
errorMessage = errorData.message;
return;
}
let email = $state("");
let contraseña = $state("");
let errorMessage = $state("");
const ret = await response.json();
localStorage.setItem('email', ret.email);
sessionStorage.setItem('token', ret.token);
//setTimeout(() => console.log("50ms") ,50);
navigate(ret.redirect);
} catch (e) {
// @ts-ignore
async function submitForm(event) {
event.preventDefault();
const data = { email, contraseña };
try {
const response = await fetch(String($urlG) + "/api/login", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data),
credentials: "include",
});
if (!response.ok) {
const errorData = await response.json();
errorMessage = errorData.message;
return;
}
const ret = await response.json();
localStorage.setItem("email", ret.email);
sessionStorage.setItem("token", ret.token);
//setTimeout(() => console.log("50ms") ,50);
navigate(ret.redirect);
} 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>
<CardHeader>
<CardTitle>Iniciar Sesión</CardTitle>
</CardHeader>
<CardBody>
<Form on:submit={submitForm}>
<FormGroup floating label="Email">
<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/>
</FormGroup>
<FormGroup>
<Button color="primary" type="submit">Ingresar</Button>
</FormGroup>
</Form>
{#if errorMessage}
<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>
{#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 onsubmit={(e) => submitForm(e)}>
<FormGroup floating label="Email">
<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
/>
</FormGroup>
<FormGroup>
<Button color="primary" type="submit">Ingresar</Button>
</FormGroup>
</Form>
{#if errorMessage}
<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>
</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}
</CardBody>
</Card>

View File

@@ -1,16 +1,17 @@
<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);
let cantGarantes: number = $state(0);
let garantes: GaranteDto[] = $state([]);
let showAddForm: boolean = $state(false);
// Nuevo garante temporal para el formulario.
let newGarante: GaranteDto = $state({
Dni: 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>
@@ -60,4 +74,4 @@
</div>
</div>
</div>
</div>
</div>

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,126 +1,183 @@
<script lang="ts">
import { Navbar, NavbarBrand, NavbarToggler, Nav, Collapse } from "@sveltestrap/sveltestrap";
import { onMount } from "svelte";
import { writable } from 'svelte/store';
import { link, links } from "svelte-routing";
import './css/popup.css';
import type { Grupo } from "../types";
import {
Navbar,
NavbarBrand,
NavbarToggler,
Nav,
Collapse,
Button,
} from "@sveltestrap/sveltestrap";
import { onMount } from "svelte";
import { writable } from "svelte/store";
import { link, links } from "svelte-routing";
import "./css/popup.css";
import type { Grupo } from "../types";
import { urlG } from "../stores/urlStore";
import { urlG } from "../stores/urlStore";
import { navigate } from "svelte-routing";
let isOpen: boolean = $state(false);
let hayNotis:boolean = $state(false);
const permisos = writable<Grupo[]>([]);
const email = localStorage.getItem('email');
const token = sessionStorage.getItem('token');
let isOpen: boolean = $state(false);
let hayNotis: boolean = $state(false);
async function obtenerPermisos(){
try {
const response = await fetch(String($urlG)+"/api/acciones",{
method: 'GET',
headers: {
'Auth' : String(token),
'Email' : String(email),
'Content-Type' : "application/json"
},
});
if (response.ok){
const json = await response.json();
permisos.set(json);
}
} catch (e) {
console.error(e);
}
}
onMount( () => {
obtenerPermisos();
obtenerNotis();
})
const permisos = writable<Grupo[]>([]);
const email = localStorage.getItem("email");
const token = sessionStorage.getItem("token");
async function obtenerNotis() {
try {
const responce = await fetch($urlG+"/api/notificaciones/haySinLeer", {
method: "GET",
headers: {
"Auth": String(token)
async function obtenerPermisos() {
try {
const response = await fetch(String($urlG) + "/api/acciones", {
method: "GET",
headers: {
Auth: String(token),
Email: String(email),
"Content-Type": "application/json",
},
});
if (response.ok) {
const json = await response.json();
permisos.set(json);
}
} catch (e) {
console.error(e);
}
});
if(responce.ok) {
let data = await responce.json();
hayNotis = data.message;
return;
}
} catch (e) {
console.error(e);
}
}
function redirijir(path: string){
navigate(path);
}
onMount(() => {
obtenerPermisos();
obtenerNotis();
});
let theme = $state(localStorage.getItem("theme") ?? "light");
const toggleTheme = () => {
theme = theme === "light" ? "dark" : "light";
document.body.setAttribute("data-bs-theme", theme);
localStorage.setItem("theme", theme);
};
async function obtenerNotis() {
try {
const responce = await fetch(
$urlG + "/api/notificaciones/haySinLeer",
{
method: "GET",
headers: {
Auth: String(token),
},
},
);
if (responce.ok) {
let data = await responce.json();
hayNotis = data.message;
return;
}
} catch (e) {
console.error(e);
}
}
function redirijir(path: string) {
navigate(path);
}
let theme = $state(localStorage.getItem("theme") ?? "light");
const toggleTheme = () => {
theme = theme === "light" ? "dark" : "light";
document.body.setAttribute("data-bs-theme", theme);
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>
<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;">
{#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="">
{#if hayNotis}
<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>
</div>
<NavbarToggler on:click={() => (isOpen = !isOpen)} />
<Collapse isOpen={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">
<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>
{/each}
</ul>
<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>
</div>
{/each}
</Nav>
</Collapse>
<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="" />
{#if hayNotis}
<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} 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"
>
<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>
{/each}
</ul>
</div>
</div>
{/each}
</Nav>
</Collapse>
</Navbar>

View File

@@ -1,38 +1,47 @@
<script lang="ts">
import { Navbar, NavbarBrand, NavbarToggler, NavItem, Nav, NavLink, Collapse } from "@sveltestrap/sveltestrap";
let isOpen:boolean =$state(false);
let theme = $state(localStorage.getItem("theme") ?? "light");
const toggleTheme = () => {
theme = theme === "light" ? "dark" : "light";
document.body.setAttribute("data-bs-theme", theme);
localStorage.setItem("theme", theme);
};
import {
Navbar,
NavbarBrand,
NavbarToggler,
NavItem,
Nav,
NavLink,
Collapse,
} from "@sveltestrap/sveltestrap";
let isOpen: boolean = $state(false);
let theme = $state(localStorage.getItem("theme") ?? "light");
const toggleTheme = () => {
theme = theme === "light" ? "dark" : "light";
document.body.setAttribute("data-bs-theme", theme);
localStorage.setItem("theme", theme);
};
</script>
<Navbar container="xxl" expand="md" color="dark-subtle">
<NavbarBrand href="/">
AlquilaFacil
</NavbarBrand>
<div>
<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>
</div>
<NavbarToggler on:click={() => (isOpen = !isOpen)} />
<Collapse isOpen={isOpen} navbar expand="md">
<Nav class="ms-auto" navbar>
<NavItem>
<NavLink href="/">Login</NavLink>
</NavItem>
<NavItem>
<NavLink href="/Info">Preguntas Frecuentes</NavLink>
</NavItem>
</Nav>
</Collapse>
<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;"
>
{#if theme === "light"}
<img src="/toggle-left.svg" alt="" />
{:else}
<img src="/toggle-right.svg" alt="" />
{/if}
</button>
</div>
<NavbarToggler on:click={() => (isOpen = !isOpen)} />
<Collapse {isOpen} navbar expand="md">
<Nav class="ms-auto" navbar>
<NavItem>
<NavLink href="/">Login</NavLink>
</NavItem>
<NavItem>
<NavLink href="/Info">Preguntas Frecuentes</NavLink>
</NavItem>
</Nav>
</Collapse>
</Navbar>

View File

@@ -1,18 +1,18 @@
<script lang="ts">
import { onMount } from "svelte";
import { onMount } from "svelte";
let {
currentPag,
cantpag,
queryPag,
centrado = false,
}: {
currentPag: number;
cantpag: number;
queryPag: (a: number) => void;
centrado: boolean;
} = $props();
let {currentPag,
cantpag,
queryPag,
centrado = false
}:{
currentPag: number,
cantpag: number,
queryPag: (a:number) => void,
centrado:boolean
} = $props();
function getVisiblePages() {
function getVisiblePages() {
if (!centrado || cantpag <= 5) {
return Array.from({ length: cantpag }, (_, i) => i + 1);
}
@@ -20,28 +20,56 @@
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>
</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>
{/each}
<li class="page-item {currentPag === cantpag ? 'disabled' : ''}">
<a class="page-link" href="#" onclick={() => currentPag < cantpag && queryPag(currentPag + 1)}>Siguiente</a>
</li>
</ul>
</nav>
{/if}
<nav aria-label="Paginador">
<ul class="pagination">
<li class="page-item {currentPag === 1 ? 'disabled' : ''}">
<button
class="page-link"
onclick={() => currentPag > 1 && queryPag(currentPag - 1)}
>
Anterior
</button>
</li>
{#each visiblePages as num}
<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' : ''}">
<button
class="page-link"
onclick={() =>
currentPag < cantpag && queryPag(currentPag + 1)}
>Siguiente</button
>
</li>
</ul>
</nav>
{/if}

View File

@@ -1,55 +1,59 @@
<script>
import { onMount } from 'svelte';
import { writable } from 'svelte/store';
import { onMount } from "svelte";
import { writable } from "svelte/store";
import { urlG } from "../stores/urlStore";
import { urlG } from "../stores/urlStore";
let { componente } = $props();
const isAuthenticated = writable(false);
const isVerified = writable(false);
const redirect = window.location.pathname;
const email = localStorage.getItem('email');
const token = sessionStorage.getItem('token');
const handleAccess = async () => {
try {
const response = await fetch($urlG+"/api/login/validar", {
method: 'POST',
headers: {
'Auth': String(token),
'Content-Type': 'application/json',
},
body: JSON.stringify({ email, redirect }),
credentials: "include"
});
let { componente } = $props();
if (response.ok) {
isAuthenticated.set(true); // Actualiza el store
}
} catch (error) {
console.error('Error durante la autenticación:', error);
} finally {
isVerified.set(true); // Marca la verificación como completada
}
};
onMount(() => {
handleAccess();
});
const isAuthenticated = writable(false);
const isVerified = writable(false);
const redirect = window.location.pathname;
const email = localStorage.getItem("email");
const token = sessionStorage.getItem("token");
const handleAccess = async () => {
try {
const response = await fetch($urlG + "/api/login/validar", {
method: "POST",
headers: {
Auth: String(token),
"Content-Type": "application/json",
},
body: JSON.stringify({ email, redirect }),
credentials: "include",
});
if (response.ok) {
isAuthenticated.set(true); // Actualiza el store
}
} catch (error) {
console.error("Error durante la autenticación:", error);
} finally {
isVerified.set(true); // Marca la verificación como completada
}
};
onMount(() => {
handleAccess();
});
</script>
{#if !$isVerified}
<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>
<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}
{@render componente()}
{/if}
{:else}
{#if $isAuthenticated}
{@render componente()}
{:else}
{window.location.replace('/')}
{/if}
{/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,34 +1,57 @@
<script lang="ts">
import { onMount } from "svelte";
import NavBarAutocompletable from "../Componentes/NavBarAutocompletable.svelte";
import type { Cliente, Grupo, UpdateCliente } from "../types";
import {urlG} from "../stores/urlStore";
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([]);
let Grupos: any[] = $state([]);
let modaldata = $state();
let token = sessionStorage.getItem("token");
let showAddmenu: boolean = $state(false);
let grupo:string = $state("");
let grupo: string = $state("");
let SelCliente: Cliente = $state(null);
let gruposopt: GrupoDto[] = $state([]);
onMount(() => {
cargaUsuarios();
ObtenerGrupos();
});
async function cargaUsuarios(){
try{
const response = await fetch($urlG+"/api/admin/clientes", {
async function ObtenerGrupos() {
try {
const ret = await fetch($urlG + "/api/admin/grupos", {
method: "GET",
headers: {
"Auth": String(token),
}
})
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),
},
});
if (response.ok) {
let data: Cliente[] = await response.json();
Clientes = data;
@@ -38,17 +61,19 @@
} catch {
modaldata = "fallo al intentar obtener la lista de clientes";
}
}
async function cargaGrupos(cli: Cliente){
async function cargaGrupos(cli: Cliente) {
try {
const response = await fetch($urlG+"/api/admin/clientes/grupo?Dni="+cli.dni, {
method: "GET",
headers: {
"Auth": String(token),
const response = await fetch(
$urlG + "/api/admin/clientes/grupo?Dni=" + cli.dni,
{
method: "GET",
headers: {
Auth: String(token),
},
},
});
if (response.ok){
);
if (response.ok) {
let data = await response.json();
Grupos = data;
showAddmenu = true;
@@ -62,45 +87,49 @@
}
}
async function bajaCliente(event:Event, cli:Cliente) {
//WIP añadir una flag para que muestre que no se pudo dar se alta/baja
async function bajaCliente(event: Event, cli: Cliente) {
event.stopPropagation();
try {
const response = await fetch($urlG+"/api/admin/cliente?Dni="+cli.dni, {
method: "DELETE",
headers: {
"Auth": String(token),
}
});
if(response.ok){
let data = await response.json();
modaldata = data.message;
const response = await fetch(
$urlG + "/api/admin/cliente?Dni=" + cli.dni,
{
method: "DELETE",
headers: {
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){
async function añadirGrupo(e: Event, cli: Cliente, grupo: string) {
e.preventDefault();
if (cli.dni == 0 || cli.email == "" || grupo == ""){
if (cli.dni == 0 || cli.email == "" || grupo == "") {
modaldata = "No se selecciono un cliente o Grupo";
return;
}
const email = cli.email;
try {
const response = await fetch($urlG+"/api/admin/cliente/addGrupo", {
method: "PATCH",
headers: {
"Auth": String(token),
'Content-Type' : 'application/json',
const response = await fetch(
$urlG + "/api/admin/cliente/addGrupo",
{
method: "PATCH",
headers: {
Auth: String(token),
"Content-Type": "application/json",
},
body: JSON.stringify({ email, grupo }),
},
body: JSON.stringify({email, grupo})
});
);
if (response.ok){
if (response.ok) {
let data = await response.json();
modaldata = data.message;
cargaGrupos(cli);
@@ -112,27 +141,32 @@
modaldata = "Falla la conexion al servidor";
}
}
async function BajaGrupo(e:Event, cli: Cliente, grupo:string){
async function BajaGrupo(e: Event, cli: Cliente, grupo: string) {
e.preventDefault();
if (cli.dni == 0 || cli.email == "" || grupo == ""){
if (cli.dni == 0 || cli.email == "" || grupo == "") {
modaldata = "No se selecciono un cliente o Grupo";
return;
}
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 (grupo === "Propietario") {
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", {
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){
if (response.ok) {
let data = await response.json();
modaldata = data.message;
cargaGrupos(cli);
@@ -145,20 +179,26 @@
}
}
let showModificarCliente:boolean = $state(false);
let datoscli:UpdateCliente = $state({dni:0, apellido:"", celular:"", domicilio:"", nombre:""});
let showModificarCliente: boolean = $state(false);
let datoscli: UpdateCliente = $state({
dni: 0,
apellido: "",
celular: "",
domicilio: "",
nombre: "",
});
async function abrirModalModificarCliente(e: Event, cli: Cliente) {
e.stopPropagation();
try {
const r = await fetch($urlG+"/api/admin/cliente?dni="+cli.dni, {
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){
if (r.ok) {
datoscli = data;
datoscli.dni = cli.dni;
showModificarCliente = true;
@@ -170,53 +210,100 @@
}
}
async function patchCliente(a:UpdateCliente) {
if (a.apellido =="" || a.celular=="" || a.domicilio=="" || a.nombre==""){
async function patchCliente(a: UpdateCliente) {
if (
a.apellido == "" ||
a.celular == "" ||
a.domicilio == "" ||
a.nombre == ""
) {
modaldata = "Hay campos vacios";
return;
}
let dto ={
let dto = {
apellido: a.apellido,
celular: a.celular,
domicilio: a.domicilio,
nombre: a.nombre,
}
try{
const r = await fetch($urlG+"/api/admin/cliente?dni="+a.dni, {
};
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),
});
let data = await r.json();
modaldata = data.message;
if (r.ok) cargaUsuarios();
}catch{
} catch {
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/>
<NavBarAutocompletable />
{#if modaldata}
<ModalEstatico payload={modaldata} close={()=> !!(modaldata = "")}/>
<ModalEstatico payload={modaldata} close={() => !!(modaldata = "")} />
{/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">
<div class="row">
<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">
<BarraHorizontalConTexto text="Clientes" />
<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>
@@ -227,33 +314,53 @@
</thead>
<tbody>
{#each Clientes as cli}
<tr onclick={() => cargaGrupos(cli)} in:fade>
<td>{cli.dni}</td>
<td>{cli.nombre}</td>
<td>{cli.email}</td>
<td>
{#if cli.habilitado}
<button class="btn btn-warning" onclick={(e) => bajaCliente(e, cli)}>
Baja
</button>
{:else}
<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>
</td>
</tr>
<tr onclick={() => cargaGrupos(cli)} in:fade>
<td>{cli.dni}</td>
<td>{cli.nombre}</td>
<td>{cli.email}</td>
<td>
{#if cli.habilitado}
<button
class="btn btn-warning"
onclick={(e) => bajaCliente(e, cli)}
>
Baja
</button>
{:else}
<button
class="btn btn-success"
onclick={(e) => bajaCliente(e, cli)}
>
Alta
</button>
{/if}
<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>
{/each}
</tbody>
</table>
</div>
</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">
<BarraHorizontalConTexto text="Grupos del Cliente Seleccionado" />
<table
class="table table-striped table-responsive table-sm table-bordered"
>
<thead>
<tr>
<th>Id</th>
@@ -262,45 +369,65 @@
</tr>
</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>
</tr>
{/each}
{#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
>
</tr>
{/each}
{:else if SelCliente != null}
<tr>
<td colspan="3">Este Cliente no tiene Grupos</td>
</tr>
<tr>
<td colspan="3">Este Cliente no tiene Grupos</td>
</tr>
{:else}
<tr>
<td colspan="3">Seleccione un cliente para ver sus grupos</td>
</tr>
<tr>
<td colspan="3"
>Seleccione un cliente para ver sus grupos</td
>
</tr>
{/if}
</tbody>
</table>
{#if showAddmenu}
<div in:fade>
<BarraHorizontalConTexto text="Añadir Grupos al Usuario"/>
<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>
</select>
</div>
<button class="btn btn-primary" type="submit">Añadir</button>
</form>
</div>
<div in:fade>
<BarraHorizontalConTexto text="Añadir Grupos al Usuario" />
<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}
>
{#each gruposopt as g}
<option value={g.nombre}>{g.nombre}</option>
{/each}
</select>
</div>
<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
@@ -313,4 +333,4 @@
</div>
</div>
</div>
</div>
</div>

View File

@@ -2,41 +2,55 @@
import NavBarAutocompletable from "../Componentes/NavBarAutocompletable.svelte";
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 { urlG } from "../stores/urlStore";
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";
let token:string = sessionStorage.getItem("token")||"";
let selMod:any =$state();
let showmodal:boolean = $state(false);
let canons:CanonDto[] = $state([]);
let token: string = sessionStorage.getItem("token") || "";
let selMod: any = $state();
let showmodal: boolean = $state(false);
let canons: CanonDto[] = $state([]);
let garantes: GaranteDto2[] = $state([]);
let prop:ContratoPropiedadDto = $state({
estado:"",
fechainicio:"",
id:0,
inquilino:"",
propietario:"",
tipoPropiedad:"",
ubicacion:"",
habitaciones:0,
piso:0,
letra:"",
mesesAumento:0,
mesesDuracion:0,
let prop: ContratoPropiedadDto = $state({
estado: "",
fechainicio: "",
id: 0,
inquilino: "",
propietario: "",
tipoPropiedad: "",
ubicacion: "",
habitaciones: 0,
piso: 0,
letra: "",
mesesAumento: 0,
mesesDuracion: 0,
});
let defectos:DefectoDto[] = $state([]);
let defectos: DefectoDto[] = $state([]);
let TieneOpcionVenta:boolean =$state(false);
let dtoVenta:OpcionVentaDto =$state({divisa:"", id:0, monto:0, enOrden:false, fueEjercido:false});
let TieneOpcionVenta: boolean = $state(false);
let dtoVenta: OpcionVentaDto = $state({
divisa: "",
id: 0,
monto: 0,
enOrden: false,
fueEjercido: false,
});
let modaldata:string = $state("");
let contratoid:string = $state("");
let modaldata: string = $state("");
let contratoid: string = $state("");
onMount(()=>{
onMount(() => {
getparams();
obtenerDatosACargar();
opcionVenta();
@@ -44,16 +58,21 @@
async function opcionVenta() {
try {
const r = await fetch($urlG+"/api/contrato/tieneopcionventa?idcontrato="+contratoid, {
method: "GET",
headers: {
"Auth": String(token),
}
});
if (r.ok){
const r = await fetch(
$urlG +
"/api/contrato/tieneopcionventa?idcontrato=" +
contratoid,
{
method: "GET",
headers: {
Auth: String(token),
},
},
);
if (r.ok) {
let data = await r.json();
TieneOpcionVenta = data.message;
if (TieneOpcionVenta){
if (TieneOpcionVenta) {
ObtenerOpcionVentaDto();
}
return;
@@ -61,58 +80,79 @@
let data = await r.json();
modaldata = data.message;
return;
}catch {
} catch {
modaldata = "Fallo hacer la request";
}
}
async function ObtenerOpcionVentaDto() {
try{
const r = await fetch($urlG+"/api/opcionventa?idcontrato="+contratoid, {
method: "GET",
headers: {
"Auth": String(token),
}
});
try {
const r = await fetch(
$urlG + "/api/opcionventa?idcontrato=" + contratoid,
{
method: "GET",
headers: {
Auth: String(token),
},
},
);
if (r.ok) {
let data = await r.json();
dtoVenta = data;
return
return;
}
let data = await r.json();
modaldata = data.message;
}catch{
} catch {
modaldata = "Fallo hacer la request";
}
}
async function obtenerDatosACargar() {
try {
const respPropiedad = fetch($urlG+"/api/contrato/inquilino?id="+contratoid, {
method: "GET",
headers: {
"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, {
method: "GET",
headers: {
"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]);
const respPropiedad = fetch(
$urlG + "/api/contrato/inquilino?id=" + contratoid,
{
method: "GET",
headers: {
Auth: String(token),
},
},
);
const respgarantes = fetch(
$urlG + "/api/contratos/garantes?idcontrato=" + contratoid,
{
method: "GET",
headers: {
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,
{
method: "GET",
headers: {
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,27 +163,29 @@
garantes = datosGarantes;
canons = datosCanons;
defectos = datosDefect;
} catch {
modaldata = "Fallo hacer las request";
}
}
function getparams(){
function getparams() {
const qs = window.location.search;
const par = new URLSearchParams(qs);
contratoid = par.get("id")||"";
}
contratoid = par.get("id") || "";
}
async function refreshCanon() {
try {
const ret = await fetch($urlG+"/api/contratos/canon?id="+contratoid, {
method: "GET",
headers: {
"Auth": String(token),
}
});
if (!ret.ok){
const ret = await fetch(
$urlG + "/api/contratos/canon?id=" + contratoid,
{
method: "GET",
headers: {
Auth: String(token),
},
},
);
if (!ret.ok) {
let data = await ret.json();
modaldata = data.message;
return;
@@ -155,94 +197,102 @@
modaldata = "No se pudo obtener la lista de canones actualizada";
}
}
async function verContrato() {
if (prop.id <= 0) {
modaldata = "no hay contratos con id 0 o menor";
return;
}
try {
const resp = await fetch ($urlG+"/api/contrato/DocumentoFinal?idcontrato="+prop.id, {
method: "GET",
headers: {
"Auth": String(token),
}
});
const resp = await fetch(
$urlG + "/api/contrato/DocumentoFinal?idcontrato=" + prop.id,
{
method: "GET",
headers: {
Auth: String(token),
},
},
);
if (!resp.ok) {
let blob = await resp.json();
modaldata=blob.message;
modaldata = blob.message;
return;
}
let blob = await resp.blob();
const blobUrl = URL.createObjectURL(blob);
window.open(blobUrl, '_blank');
setTimeout(() => URL.revokeObjectURL(blobUrl), 100000);
const blobUrl = URL.createObjectURL(blob);
window.open(blobUrl, "_blank");
setTimeout(() => URL.revokeObjectURL(blobUrl), 100000);
} catch {
modaldata= "fallo intentar hacer la request";
modaldata = "fallo intentar hacer la request";
}
}
async function realizarpago(mes: Date) {
try {
const ret = await fetch($urlG+"/api/contratos/realizarPago", {
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}),
body: JSON.stringify({ idcontrato: contratoid, fecha: mes }),
});
let data = await ret.json();
modaldata = data.message;
if (ret.ok){
refreshCanon()
if (ret.ok) {
refreshCanon();
return;
}
} catch {
modaldata = "Fallo al intentar hacer la request";
}
}
function generarTiket(mod:any) {
selMod = mod;
showmodal =true;
}
async function pedirdocumento(op:boolean) {
try {
const ret = await fetch($urlG+"/api/contrato/GenerarRecibo?html="+op, {
method: "POST",
headers: {
"Auth": String(token),
"Content-Type": "application/json",
},
body: JSON.stringify({fecha: selMod.mes, idcontrato: contratoid})
});
if (!ret.ok) {
let blob = await ret.json();
modaldata=blob.message;
return;
}
let blob = await ret.blob();
const blobUrl = URL.createObjectURL(blob);
window.open(blobUrl, '_blank');
setTimeout(() => URL.revokeObjectURL(blobUrl), 100000);
} catch {
modaldata = "Fallo al intentar hacer la request";
}
}
}
function generarTiket(mod: any) {
selMod = mod;
showmodal = true;
}
async function pedirdocumento(op: boolean) {
try {
const ret = await fetch(
$urlG + "/api/contrato/GenerarRecibo?html=" + op,
{
method: "POST",
headers: {
Auth: String(token),
"Content-Type": "application/json",
},
body: JSON.stringify({
fecha: selMod.mes,
idcontrato: contratoid,
}),
},
);
if (!ret.ok) {
let blob = await ret.json();
modaldata = blob.message;
return;
}
let blob = await ret.blob();
const blobUrl = URL.createObjectURL(blob);
window.open(blobUrl, "_blank");
setTimeout(() => URL.revokeObjectURL(blobUrl), 100000);
} catch {
modaldata = "Fallo al intentar hacer la request";
}
}
async function cargarDefecto(data: AltaDefectoDto) {
if(data.idcontrato ==0) data.idcontrato = prop.id;
if (data.idcontrato == 0) data.idcontrato = prop.id;
try {
const r = await fetch($urlG+"/api/defecto", {
const r = await fetch($urlG + "/api/defecto", {
method: "POST",
headers: {
"Auth": String(token),
Auth: String(token),
"Content-Type": "application/json",
},
body: JSON.stringify(data),
@@ -252,38 +302,45 @@
if (r.ok) {
refreshDefectos();
}
}catch{
} catch {
modaldata = "Fallo al intentar hacer la request";
}
}
async function refreshDefectos() {
try {
const r = await fetch($urlG+"/api/defectos?Idcontrato="+contratoid, {
method: "GET",
headers: {
"Auth": token,
}
});
let rr =await r.json();
const r = await fetch(
$urlG + "/api/defectos?Idcontrato=" + contratoid,
{
method: "GET",
headers: {
Auth: token,
},
},
);
let rr = await r.json();
defectos = rr;
} catch {
modaldata ="No se pudo pedir la lista de Defectos";
modaldata = "No se pudo pedir la lista de Defectos";
}
}
async function ejercerOpcionVenta() {
try {
const r = await fetch($urlG+"/api/ventas/ejercerOpcionVenta?idcontrato="+contratoid, {
method: "POST",
headers: {
"Auth": token,
}
});
const r = await fetch(
$urlG +
"/api/ventas/ejercerOpcionVenta?idcontrato=" +
contratoid,
{
method: "POST",
headers: {
Auth: token,
},
},
);
let data = await r.json();
modaldata =data.message;
if(r.ok){
modaldata = data.message;
if (r.ok) {
opcionVenta();
return;
}
@@ -293,14 +350,17 @@
}
</script>
<NavBarAutocompletable/>
<NavBarAutocompletable />
{#if modaldata}
<ModalEstatico payload={modaldata} close={()=>!!(modaldata = "")}/>
<ModalEstatico payload={modaldata} close={() => !!(modaldata = "")} />
{/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
@@ -362,14 +425,14 @@
</thead>
<tbody>
{#each garantes as g}
<tr>
<td>{g.dni}</td>
<td>{g.nombre}</td>
<td>{g.apellido}</td>
<td>{g.domicilio}</td>
<td>{g.domiciliolaboral}</td>
<td>{g.celular}</td>
</tr>
<tr>
<td>{g.dni}</td>
<td>{g.nombre}</td>
<td>{g.apellido}</td>
<td>{g.domicilio}</td>
<td>{g.domiciliolaboral}</td>
<td>{g.celular}</td>
</tr>
{/each}
</tbody>
</table>
@@ -386,7 +449,7 @@
aria-expanded="false"
aria-controls="collapseTwo"
>
Canons
Canones
</button>
</h2>
<div
@@ -398,27 +461,53 @@
<div class="accordion-body">
<div class="row">
{#each canons as canon}
<div class="col-6 mb-3">
<div class="card">
<div class="card-header text-center">
{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>
</div>
<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)}>
Generar Tiket
</button>
<div class="col-6 mb-3">
<div class="card">
<div class="card-header text-center">
{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>
</div>
<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)}
>
Generar Tiket
</button>
</div>
</div>
</div>
</div>
{/each}
</div>
</div>
@@ -442,102 +531,122 @@
class="accordion-collapse collapse"
aria-labelledby="ht"
data-bs-parent="#accordionExample"
>
>
<div class="accordion-body">
{#if prop.estado != "Terminado"}
<div class="card">
<div class="card-header">
Notificar Defecto en Propiedad
<div class="card">
<div class="card-header">
Notificar Defecto en Propiedad
</div>
<div class="card-body">
<FormAltaDefecto
onConfirm={cargarDefecto}
idcontrato={prop.id}
/>
</div>
<div class="card-footer"></div>
</div>
<div class="card-body">
<FormAltaDefecto onConfirm={cargarDefecto} idcontrato={prop.id} />
</div>
<div class="card-footer">
</div>
</div>
<br>
<br />
{/if}
<table class="table table-hover table-striped">
<thead>
<tr>
<th>Descripción</th>
<th>Costo</th>
<th>Estado</th>
<th>Paga Inquilino</th>
<th>Divisa</th>
</tr>
<tr>
<th>Descripción</th>
<th>Costo</th>
<th>Estado</th>
<th>Paga Inquilino</th>
<th>Divisa</th>
</tr>
</thead>
<tbody>
{#if defectos.length == 0}
<tr>
<td colspan="6">No hay defectos que mostrar</td>
</tr>
{:else}
{#each defectos as defecto}
<tr>
<td>{defecto.descripcion}</td>
<td>{defecto.costo}</td>
<td>{defecto.estado}</td>
<td>{defecto.pagainquilino}</td>
<td>{defecto.divisa}</td>
</tr>
{/each}
{/if}
{#if defectos.length == 0}
<tr>
<td colspan="6"
>No hay defectos que mostrar</td
>
</tr>
{:else}
{#each defectos as defecto}
<tr>
<td>{defecto.descripcion}</td>
<td>{defecto.costo}</td>
<td>{defecto.estado}</td>
<td>{defecto.pagainquilino}</td>
<td>{defecto.divisa}</td>
</tr>
{/each}
{/if}
</tbody>
</table>
</table>
</div>
</div>
</div>
{#if TieneOpcionVenta}
<div class="accordion-item">
<h2 class="accordion-header" id="hq">
<button
class="accordion-button collapsed"
type="button"
data-bs-toggle="collapse"
data-bs-target="#cq"
aria-expanded="false"
aria-controls="cq"
<div class="accordion-item">
<h2 class="accordion-header" id="hq">
<button
class="accordion-button collapsed"
type="button"
data-bs-toggle="collapse"
data-bs-target="#cq"
aria-expanded="false"
aria-controls="cq"
>
Opcion Compra
</button>
</h2>
<div
id="cq"
class="accordion-collapse collapse"
aria-labelledby="hq"
data-bs-parent="#accordionExample"
>
Opcion Venta
</button>
</h2>
<div
id="cq"
class="accordion-collapse collapse"
aria-labelledby="hq"
data-bs-parent="#accordionExample"
>
<div class="accordion-body">
<div class="card">
<div class="card-header">
Datos Opcion Venta
</div>
<div class="card-body">
<b>Monto</b>: {dtoVenta.divisa} {dtoVenta.monto}.
<div class="accordion-body">
<div class="card">
<div class="card-header">
Datos Opcion Compra
</div>
<div class="card-body">
<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
</p>
<div class="d-flex justify-content-between">
<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)}>
Ir a la pagina de la Venta
<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
</p>
<div class="d-flex justify-content-between">
<button
class="btn btn-primary"
disabled={dtoVenta.enOrden ==
false ||
dtoVenta.fueEjercido == true}
onclick={() => ejercerOpcionVenta()}
>
Ejercer
</button>
{/if}
{#if dtoVenta.fueEjercido}
<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>
<div class="card-footer text-center">IdOpcionVenta: {dtoVenta.id}</div>
</div>
</div>
</div>
</div>
{/if}
</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

@@ -4,39 +4,52 @@
import NavBarAutocompletable from "../Componentes/NavBarAutocompletable.svelte";
import FChart from "../Componentes/Estadisticas/fChart.svelte";
import ModalEstatico from "../Componentes/ModalEstatico.svelte";
import {urlG} from "../stores/urlStore";
import type { ChartData } from "../types";
import { urlG } from "../stores/urlStore";
import type { ChartData, IngresosDto } from "../types";
let token = sessionStorage.getItem("token")||"";
let token = sessionStorage.getItem("token") || "";
let y = $state(2025);
let cdata:ChartData|any = $state();
let aldata:{id:number, ubicacion:string, divisa:string}[]= $state([]);
let cdata: ChartData | any = $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 modaldata:string = $state("");
onMount(async() => {
let chartMesesDuracion: ChartData | any = $state();
let tablaMesesDuracion: {
meses: number;
repes: number;
semaforizacion: string;
}[] = $state([]);
let showModoDaltonico: boolean = $state(false);
let modaldata: string = $state("");
onMount(async () => {
await dataAlquileresporAño();
});
async function dataAlquileresporAño(year = 2025) {
try{
const rep = fetch($urlG+"/api/stats/alquileresIniciados?year="+year, {
method : "GET",
headers: {
"Auth": token,
}
});
const pre = fetch($urlG+"/api/tabla/alquileresIniciados?year="+year, {
method : "GET",
headers: {
"Auth": token,
}
});
let [r,p] = await Promise.all([rep, pre]);
try {
const rep = fetch(
$urlG + "/api/stats/alquileresIniciados?year=" + year,
{
method: "GET",
headers: {
Auth: token,
},
},
);
const pre = fetch(
$urlG + "/api/tabla/alquileresIniciados?year=" + year,
{
method: "GET",
headers: {
Auth: token,
},
},
);
let [r, p] = await Promise.all([rep, pre]);
let data = await r.json();
let data2 = await p.json();
@@ -44,77 +57,128 @@
cdata = data;
aldata = data2;
return;
}catch{
modaldata="Fallo al intentar alcanzar el servidor";
} catch {
modaldata = "Fallo al intentar alcanzar el servidor";
}
}
let visibleMesesDuracion:boolean = $state(false);
let visibleMesesDuracion: boolean = $state(false);
async function dataMesesDuracion() {
try{
const p1 = fetch($urlG+"/api/stats/duracionContrato", {
method : "GET",
try {
const p1 = fetch($urlG + "/api/stats/duracionContrato", {
method: "GET",
headers: {
"Auth": token,
}
Auth: token,
},
});
const p2 = fetch($urlG+"/api/tabla/duracionContrato", {
method : "GET",
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 [r1, r2] = await Promise.all([p1, p2]);
let [d1, d2] = await Promise.all([r1.json(), r2.json()]);
chartMesesDuracion = d1;
tablaMesesDuracion = d2;
}catch {
modaldata="Fallo al intentar alcanzar el servidor";
} catch {
modaldata = "Fallo al intentar alcanzar el servidor";
}
}
function toggleModoDaltonico() {
if (tablaMesesDuracion== null) return;
tablaMesesDuracion.forEach(item => {
if (item.semaforizacion === '🟢') {
item.semaforizacion = '🔵';
} else if (item.semaforizacion === '🔵') {
item.semaforizacion = '🟢';
function toggleModoDaltonico() {
if (tablaMesesDuracion == null) return;
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}
<ModalEstatico payload={modaldata} close={()=>!!(modaldata = "")} />
<ModalEstatico payload={modaldata} close={() => !!(modaldata = "")} />
{/if}
<NavBarAutocompletable/>
<NavBarAutocompletable />
<div class="container-fluid">
<div class="row mt-4" >
<BarraHorizontalConTexto text="Estadisticas"/>
<div class="row mt-4">
<BarraHorizontalConTexto text="Estadisticas" />
<div class="accordion" id="accordionExample">
<div class="accordion-item">
<h2 class="accordion-header" id="hea1">
<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
<button
class="accordion-button"
type="button"
data-bs-toggle="collapse"
data-bs-target="#c1"
aria-expanded="true"
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>
@@ -125,18 +189,18 @@
</thead>
<tbody>
{#each aldata as al}
<tr>
<td>{al.id}</td>
<td>{al.ubicacion}</td>
<td>{al.divisa}</td>
</tr>
<tr>
<td>{al.id}</td>
<td>{al.ubicacion}</td>
<td>{al.divisa}</td>
</tr>
{/each}
</tbody>
</table>
</div>
<div class="col">
{#if cdata}
<FChart chartData={cdata}/>
<FChart chartData={cdata} />
{/if}
</div>
</div>
@@ -144,27 +208,51 @@
</div>
<div class="accordion-item">
<h2 class="accordion-header" id="hea2">
<button class="accordion-button"
data-bs-toggle="collapse"
data-bs-target="#c2"
onclick={()=>{
if(visibleMesesDuracion === true){
visibleMesesDuracion=false;
return;
} else if (visibleMesesDuracion== false){
dataMesesDuracion();
}
}}
<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) {
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>
@@ -194,4 +370,4 @@
</div>
</div>
</div>
</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"}
@@ -565,4 +588,4 @@
</table>
{/if}
</div>
</div>
</div>

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

@@ -9,25 +9,25 @@
import PaginacionStepper from "../Componentes/PaginacionStepper.svelte";
let Logs: LogDto[] = $state([]);
let pagina:number = $state(1);
let token:string = sessionStorage.getItem("token")||"";
let modaldata:string = $state("");
let showmodal:boolean =$state(false);
let ll:LogDto|any = $state({});
let cantpag:number = $state(0);
let pagina: number = $state(1);
let token: string = sessionStorage.getItem("token") || "";
let modaldata: string = $state("");
let showmodal: boolean = $state(false);
let ll: LogDto | any = $state({});
let cantpag: number = $state(0);
onMount(()=>{
onMount(() => {
obtenerLogs();
obtenerPaginas();
});
async function obtenerPaginas() {
try{
const r = await fetch($urlG+"/api/Logs/cantPag", {
try {
const r = await fetch($urlG + "/api/Logs/cantPag", {
method: "GET",
headers: {
"Auth": token,
}
Auth: token,
},
});
let data = await r.json();
if (r.ok) {
@@ -41,12 +41,12 @@
}
async function obtenerLogs() {
try{
const r = await fetch($urlG+"/api/Logs?pag="+pagina, {
try {
const r = await fetch($urlG + "/api/Logs?pag=" + pagina, {
method: "GET",
headers: {
"Auth": token,
}
Auth: token,
},
});
let data = await r.json();
if (r.ok) {
@@ -63,49 +63,65 @@
ll = l;
showmodal = true;
}
function queryPag(a:number) {
function queryPag(a: number) {
pagina = a;
obtenerLogs();
}
</script>
<NavBarAutocompletable/>
<NavBarAutocompletable />
{#if modaldata}
<ModalEstatico payload={modaldata} close={()=>!!(modaldata = "")}/>
<ModalEstatico payload={modaldata} close={() => !!(modaldata = "")} />
{/if}
{#if showmodal}
<ModalLogs onClose={()=>!!(showmodal=!showmodal)} log={ll}/>
<ModalLogs onClose={() => !!(showmodal = !showmodal)} log={ll} />
{/if}
<div class="container-fluid mt-2">
<BarraHorizontalConTexto text={"Logs"}/>
<table class="table table-responsive table-hover table-striped">
<thead>
<tr>
<th>Fecha</th>
<th>Id Usuario</th>
<th>Accion</th>
<th></th>
</tr>
</thead>
<tbody>
{#each Logs as l}
<tr>
<td>{l.fecha}</td>
<td>{l.dniusuario}</td>
<td>{l.accion}</td>
<td>
<button class="btn btn-primary" onclick={()=>prepararModal(l)}>
Ver
</button>
</td>
</tr>
{/each}
</tbody>
</table>
<div class="d-flex justify-content-center">
<PaginacionStepper currentPag={pagina} {cantpag} {queryPag} centrado={true}/>
<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>
<th>Fecha</th>
<th>Id Usuario</th>
<th>Accion</th>
<th></th>
</tr>
</thead>
<tbody>
{#each Logs as l}
<tr>
<td>{l.fecha}</td>
<td>{l.dniusuario}</td>
<td>{l.accion}</td>
<td>
<button
class="btn btn-primary"
onclick={() => prepararModal(l)}
>
Ver
</button>
</td>
</tr>
{/each}
</tbody>
</table>
<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>

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

@@ -24,7 +24,7 @@ export type PropiedadVentaDto = {
export type AdminParametrosBusqueda = {
cantidadhabitaciones: number=0,
tipopropiedad: number=0,
tipopropiedad: number=0,
servicios: string="",
pag: number=1
}
@@ -77,7 +77,7 @@ export type MensajeDto = {
mensaje: string,
fecha: Date,
propiedad: string,
}
export type GaranteDto = {
@@ -187,9 +187,9 @@ export type LogDto = {
export type LogDetalleDto = {
fecha:Date,
dniusuario:number,
nombreTabla:string,
columna:string,
valorAnterior:string,
nombreTabla:string,
columna:string,
valorAnterior:string,
valorNuevo:string
}
@@ -208,14 +208,64 @@ export type setVenta = {
}
export type PatchPropiedad = {
id:number,
id:number,
ubicacion:string,
canthabitaciones:number,
piso:number,
letra:string,
email:string,
canthabitaciones:number,
piso:number,
letra:string,
email:string,
tipo:number,
servicios: string[],
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;
GenerarLog(con, dni, $"Añadido contrato");
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
@@ -98,4 +153,4 @@ public class RepositorioEstadisticas: RepositorioBase<RepositorioEstadisticas> {
}
}
}

View File

@@ -1,31 +1,106 @@
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();
}
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 IQueryable<GrupoAdmin> ObtenerGruposPorDni(long Dni) {
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;
Cliente? cli = con.Clientes.Include(x=>x.Idgrupos).FirstOrDefault(x=>x.Token == token);
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;
Grupo? gru = con.Grupos.FirstOrDefault(x=>x.Nombre == grupo);
Grupo? gru = con.Grupos.FirstOrDefault(x => x.Nombre == grupo);
if (gru == null) return false;
if (cli.Idgrupos.Contains(gru)) return true;
@@ -33,4 +108,4 @@ public class RepositorioGrupos: RepositorioBase<RepositorioGrupos> {
return false;
}
}
}

View File

@@ -21,9 +21,9 @@ 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(c => c.Dni == cli.Dni)
.SelectMany(c => c.Idgrupos)
.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();
/////////////////////////////////////////////////////////////////
//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);
/////////////////////////////////////////////////////////////////
.Where(x => x.Habilitado == true)
.Include(x => x.Idpermisos)
.Include(x => x.IdGrupoHijos)
.ThenInclude(x => x.Idpermisos)
.ToList();
Parallel.ForEach(permisos, (x, i) =>{
if (x.Id == idpermiso) {
foreach (var grupo in grupos)
{
var visitados = new HashSet<int>();
var todosLosPermisos = new HashSet<Permiso>();
grupo.ObtenerPermisos(todosLosPermisos, visitados);
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,43 +8,63 @@ 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,
p.iddivisa as Iddivisa
FROM Propiedades p
JOIN EstadoPropiedad ep ON p.idestado = 1
JOIN TipoPropiedad tp ON p.idtipropiedad = tp.id
JOIN Servicio_Propiedad sp on p.id =sp.idPropiedad
JOIN Servicios s on sp.idServicio =s.id
GROUP BY p.id
JOIN TipoPropiedad tp ON p.idtipropiedad = tp.id
JOIN Servicio_Propiedad sp on p.id =sp.idPropiedad
JOIN Servicios s on sp.idServicio =s.id
GROUP BY p.id
""";
var ret = Context.Database.SqlQuery<PropiedadesDto>(sqlq);
var ret = Context.Database.SqlQuery<PropiedadesDto>(sqlq);
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) {
Propiedade? prop = con.Propiedades.Include(x => x.DnipropietarioNavigation).FirstOrDefault(x => x.Id == Id);
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
@@ -62,18 +82,20 @@ public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
new MySqlParameter("@p_letra", prop.Letra),
new MySqlParameter("@p_dni_propietario", prop.Dnipropietario),
new MySqlParameter("@p_id_tipo_propiedad", prop.Idtipropiedad),
new MySqlParameter("@p_monto",prop.Monto),
new MySqlParameter("@p_monto", prop.Monto),
new MySqlParameter("@iddivisa", prop.Iddivisa),
filasInsertadasParam
);
return (int)filasInsertadasParam.Value == 1? true: false;
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);
Propiedade? propi = con.Propiedades.Include(x => x.IdServicios).FirstOrDefault(x => x.Id == prop.Id);
if (propi == null) return false;
propi.Canthabitaciones = prop.Canthabitaciones;
@@ -83,10 +105,11 @@ public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
propi.Letra = prop.Letra;
propi.Monto = prop.Monto;
propi.Iddivisa = prop.Iddivisa;
propi.IdServicios.Clear();
foreach(Servicio ser in prop.IdServicios) {
var servi = con.Servicios.FirstOrDefault(x=>x.Id == ser.Id);
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,46 +117,50 @@ 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
FROM Propiedades p
JOIN Clientes c ON c.dni = p.dnipropietario
JOIN TipoPropiedad tp ON tp.id = p.idtipropiedad
JOIN Clientes c ON c.dni = p.dnipropietario
JOIN TipoPropiedad tp ON tp.id = p.idtipropiedad
LEFT JOIN Servicio_Propiedad ps ON ps.idPropiedad = p.id
LEFT JOIN Servicios s ON s.Id = ps.idServicio
WHERE c.email = {email} AND p.idestado = 1
GROUP BY p.id
""";
var ret = Context.Database.SqlQuery<PropiedadesDto>(sqlq);
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
FROM Propiedades p
JOIN Clientes c ON c.dni = p.dnipropietario
JOIN TipoPropiedad tp ON tp.id = p.idtipropiedad
JOIN Clientes c ON c.dni = p.dnipropietario
JOIN TipoPropiedad tp ON tp.id = p.idtipropiedad
LEFT JOIN Servicio_Propiedad ps ON ps.idPropiedad = p.id
LEFT JOIN Servicios s ON s.Id = ps.idServicio
WHERE c.email = {email} AND p.idestado = 3
GROUP BY p.id
""";
var ret = Context.Database.SqlQuery<PropiedadesDto>(sqlq);
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,17 +170,21 @@ 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;
Propiedade? prop = con.Propiedades.FirstOrDefault(x=>x.Id == id);
Propiedade? prop = con.Propiedades.FirstOrDefault(x => x.Id == id);
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,36 +192,41 @@ 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);
if (prop == null||prop.Dnipropietario == 0) return false;
Propiedade? prop = con.Propiedades.FirstOrDefault(x => x.Id == id);
if (prop == null || prop.Dnipropietario == 0) return false;
prop.Idestado = prop.Idestado == 3 ? 1 : 3;
GenerarLog(con, dni, $"Baja propiedad: {prop.Id}");
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);
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);
}
}
GenerarLog(con, dni, $"Baja servicios a propiedad: {prop.Id}");
return Guardar(con);
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,
@@ -198,9 +234,9 @@ public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
p.iddivisa as Iddivisa
FROM Propiedades p
JOIN EstadoPropiedad ep ON p.idestado = 1
JOIN TipoPropiedad tp ON p.idtipropiedad = tp.id
JOIN Servicio_Propiedad sp on p.id =sp.idPropiedad
JOIN Servicios s on sp.idServicio =s.id
JOIN TipoPropiedad tp ON p.idtipropiedad = tp.id
JOIN Servicio_Propiedad sp on p.id =sp.idPropiedad
JOIN Servicios s on sp.idServicio =s.id
WHERE p.canthabitaciones = {habitaciones} AND p.idtipropiedad = {tipo}
AND EXISTS (
SELECT 1
@@ -211,30 +247,32 @@ public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
)
GROUP BY p.id
""";
var ret = Context.Database.SqlQuery<PropiedadesDto>(sqlq);
var ret = Context.Database.SqlQuery<PropiedadesDto>(sqlq);
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,
p.iddivisa as Iddivisa
FROM Propiedades p
JOIN EstadoPropiedad ep ON p.idestado = 1
JOIN TipoPropiedad tp ON p.idtipropiedad = tp.id
JOIN Servicio_Propiedad sp on p.id =sp.idPropiedad
JOIN Servicios s on sp.idServicio =s.id
JOIN TipoPropiedad tp ON p.idtipropiedad = tp.id
JOIN Servicio_Propiedad sp on p.id =sp.idPropiedad
JOIN Servicios s on sp.idServicio =s.id
WHERE p.canthabitaciones = {cantidadHabitaciones} AND p.idtipropiedad = {tipoPropiedad}
GROUP BY p.id
GROUP BY p.id
""";
var ret = Context.Database.SqlQuery<PropiedadesDto>(sqlq);
var ret = Context.Database.SqlQuery<PropiedadesDto>(sqlq);
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 = $"""
@@ -243,9 +281,9 @@ public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
p.iddivisa as Iddivisa
FROM Propiedades p
JOIN EstadoPropiedad ep ON p.idestado = 1
JOIN TipoPropiedad tp ON p.idtipropiedad = tp.id
JOIN Servicio_Propiedad sp on p.id =sp.idPropiedad
JOIN Servicios s on sp.idServicio =s.id
JOIN TipoPropiedad tp ON p.idtipropiedad = tp.id
JOIN Servicio_Propiedad sp on p.id =sp.idPropiedad
JOIN Servicios s on sp.idServicio =s.id
WHERE EXISTS (
SELECT 1
FROM Servicio_Propiedad sp2
@@ -253,50 +291,53 @@ public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
WHERE sp2.idPropiedad = p.id
AND FIND_IN_SET(s2.descripcion, {serviciosEscapados})
)
GROUP BY p.id
GROUP BY p.id
""";
var ret = Context.Database.SqlQuery<PropiedadesDto>(sqlq);
return ret;
}
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,
p.iddivisa as Iddivisa
FROM Propiedades p
JOIN EstadoPropiedad ep ON p.idestado = 1
JOIN TipoPropiedad tp ON p.idtipropiedad = tp.id
JOIN Servicio_Propiedad sp on p.id =sp.idPropiedad
JOIN Servicios s on sp.idServicio =s.id
WHERE p.canthabitaciones = {cantidadHabitaciones}
GROUP BY p.id
""";
var ret = Context.Database.SqlQuery<PropiedadesDto>(sqlq);
var ret = Context.Database.SqlQuery<PropiedadesDto>(sqlq);
return ret;
}
public IQueryable<PropiedadesDto> ObtenerPropiedesPorTipo(int tipoPropiedad) {
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,
p.iddivisa as Iddivisa
FROM Propiedades p
JOIN EstadoPropiedad ep ON p.idestado = 1
JOIN TipoPropiedad tp ON p.idtipropiedad = tp.id
JOIN Servicio_Propiedad sp on p.id =sp.idPropiedad
JOIN Servicios s on sp.idServicio =s.id
WHERE p.idtipropiedad = {tipoPropiedad}
GROUP BY p.id
JOIN TipoPropiedad tp ON p.idtipropiedad = tp.id
JOIN Servicio_Propiedad sp on p.id =sp.idPropiedad
JOIN Servicios s on sp.idServicio =s.id
WHERE p.canthabitaciones = {cantidadHabitaciones}
GROUP BY p.id
""";
var ret = Context.Database.SqlQuery<PropiedadesDto>(sqlq);
return ret;
var ret = Context.Database.SqlQuery<PropiedadesDto>(sqlq);
return ret;
}
public IQueryable<PropiedadesDto> ObtenerPropiedesPorHabitaciones_Servicios(int cantidadHabitaciones, string servicios) {
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,
p.iddivisa as Iddivisa
FROM Propiedades p
JOIN EstadoPropiedad ep ON p.idestado = 1
JOIN TipoPropiedad tp ON p.idtipropiedad = tp.id
JOIN Servicio_Propiedad sp on p.id =sp.idPropiedad
JOIN Servicios s on sp.idServicio =s.id
WHERE p.idtipropiedad = {tipoPropiedad}
GROUP BY p.id
""";
var ret = Context.Database.SqlQuery<PropiedadesDto>(sqlq);
return ret;
}
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,
@@ -304,9 +345,9 @@ public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
p.iddivisa as Iddivisa
FROM Propiedades p
JOIN EstadoPropiedad ep ON p.idestado = 1
JOIN TipoPropiedad tp ON p.idtipropiedad = tp.id
JOIN Servicio_Propiedad sp on p.id =sp.idPropiedad
JOIN Servicios s on sp.idServicio =s.id
JOIN TipoPropiedad tp ON p.idtipropiedad = tp.id
JOIN Servicio_Propiedad sp on p.id =sp.idPropiedad
JOIN Servicios s on sp.idServicio =s.id
WHERE p.canthabitaciones = {cantidadHabitaciones}
AND EXISTS (
SELECT 1
@@ -317,12 +358,13 @@ public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
)
GROUP BY p.id
""";
var ret = Context.Database.SqlQuery<PropiedadesDto>(sqlq);
return ret;
var ret = Context.Database.SqlQuery<PropiedadesDto>(sqlq);
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,
@@ -330,9 +372,9 @@ public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
p.iddivisa as Iddivisa
FROM Propiedades p
JOIN EstadoPropiedad ep ON p.idestado = 1
JOIN TipoPropiedad tp ON p.idtipropiedad = tp.id
JOIN Servicio_Propiedad sp on p.id =sp.idPropiedad
JOIN Servicios s on sp.idServicio =s.id
JOIN TipoPropiedad tp ON p.idtipropiedad = tp.id
JOIN Servicio_Propiedad sp on p.id =sp.idPropiedad
JOIN Servicios s on sp.idServicio =s.id
WHERE p.idtipropiedad = {tipoPropiedad}
AND EXISTS (
SELECT 1
@@ -343,119 +385,130 @@ public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
)
GROUP BY p.id
""";
var ret = Context.Database.SqlQuery<PropiedadesDto>(sqlq);
return ret;
var ret = Context.Database.SqlQuery<PropiedadesDto>(sqlq);
return ret;
}
public bool BajaPropiedades(string email) {
public bool BajaPropiedades(string email)
{
var con = Context;
try {
IQueryable<Propiedade> listprop = con.Propiedades.Where(x=>x.DnipropietarioNavigation.Email == email);
foreach (var item in listprop) {
try
{
IQueryable<Propiedade> listprop = con.Propiedades.Where(x => x.DnipropietarioNavigation.Email == email);
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,
p.iddivisa as Iddivisa
FROM Propiedades p
JOIN EstadoPropiedad ep ON p.idestado = 1
JOIN TipoPropiedad tp ON p.idtipropiedad = tp.id
JOIN Servicio_Propiedad sp on p.id =sp.idPropiedad
JOIN Servicios s on sp.idServicio =s.id
GROUP BY p.id
LIMIT 10 OFFSET {pag*10}
JOIN TipoPropiedad tp ON p.idtipropiedad = tp.id
JOIN Servicio_Propiedad sp on p.id =sp.idPropiedad
JOIN Servicios s on sp.idServicio =s.id
GROUP BY p.id
LIMIT 10 OFFSET {pag * 10}
""";
var ret = Context.Database.SqlQuery<PropiedadesDto>(sqlq);
var ret = Context.Database.SqlQuery<PropiedadesDto>(sqlq);
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,
p.iddivisa as Iddivisa
FROM Propiedades p
JOIN EstadoPropiedad ep ON p.idestado = ep.id
JOIN TipoPropiedad tp ON p.idtipropiedad = tp.id
JOIN Servicio_Propiedad sp on p.id =sp.idPropiedad
JOIN Servicios s on sp.idServicio =s.id
GROUP BY p.id
LIMIT 10 OFFSET {pag*10}
JOIN TipoPropiedad tp ON p.idtipropiedad = tp.id
JOIN Servicio_Propiedad sp on p.id =sp.idPropiedad
JOIN Servicios s on sp.idServicio =s.id
GROUP BY p.id
LIMIT 10 OFFSET {pag * 10}
""";
var ret = Singleton.Context.Database.SqlQuery<PropiedadesAdmin>(sqlq);
var ret = Singleton.Context.Database.SqlQuery<PropiedadesAdmin>(sqlq);
return ret;
}
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,
p.iddivisa as Iddivisa
FROM Propiedades p
JOIN EstadoPropiedad ep ON p.idestado = ep.id
JOIN TipoPropiedad tp ON p.idtipropiedad = tp.id
JOIN Servicio_Propiedad sp on p.id =sp.idPropiedad
JOIN Servicios s on sp.idServicio =s.id
JOIN TipoPropiedad tp ON p.idtipropiedad = tp.id
JOIN Servicio_Propiedad sp on p.id =sp.idPropiedad
JOIN Servicios s on sp.idServicio =s.id
WHERE p.canthabitaciones = {cantidadHabitaciones}
GROUP BY p.id
LIMIT 10 OFFSET {pag*10}
GROUP BY p.id
LIMIT 10 OFFSET {pag * 10}
""";
var ret = Singleton.Context.Database.SqlQuery<PropiedadesAdmin>(sqlq);
var ret = Singleton.Context.Database.SqlQuery<PropiedadesAdmin>(sqlq);
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,
p.iddivisa as Iddivisa
FROM Propiedades p
JOIN EstadoPropiedad ep ON p.idestado = ep.id
JOIN TipoPropiedad tp ON p.idtipropiedad = tp.id
JOIN Servicio_Propiedad sp on p.id =sp.idPropiedad
JOIN Servicios s on sp.idServicio =s.id
JOIN TipoPropiedad tp ON p.idtipropiedad = tp.id
JOIN Servicio_Propiedad sp on p.id =sp.idPropiedad
JOIN Servicios s on sp.idServicio =s.id
WHERE p.idtipropiedad = {tipoPropiedad}
GROUP BY p.id
LIMIT 10 OFFSET {pag*10}
GROUP BY p.id
LIMIT 10 OFFSET {pag * 10}
""";
var ret = Singleton.Context.Database.SqlQuery<PropiedadesAdmin>(sqlq);
var ret = Singleton.Context.Database.SqlQuery<PropiedadesAdmin>(sqlq);
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,
p.iddivisa as Iddivisa
FROM Propiedades p
JOIN EstadoPropiedad ep ON p.idestado = ep.id
JOIN TipoPropiedad tp ON p.idtipropiedad = tp.id
JOIN Servicio_Propiedad sp on p.id =sp.idPropiedad
JOIN Servicios s on sp.idServicio =s.id
JOIN TipoPropiedad tp ON p.idtipropiedad = tp.id
JOIN Servicio_Propiedad sp on p.id =sp.idPropiedad
JOIN Servicios s on sp.idServicio =s.id
WHERE p.canthabitaciones = {cantidadHabitaciones} AND p.idtipropiedad = {tipoPropiedad}
GROUP BY p.id
LIMIT 10 OFFSET {pag*10}
GROUP BY p.id
LIMIT 10 OFFSET {pag * 10}
""";
var ret = Singleton.Context.Database.SqlQuery<PropiedadesAdmin>(sqlq);
var ret = Singleton.Context.Database.SqlQuery<PropiedadesAdmin>(sqlq);
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 = $"""
@@ -464,9 +517,9 @@ public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
p.iddivisa as Iddivisa
FROM Propiedades p
JOIN EstadoPropiedad ep ON p.idestado = ep.id
JOIN TipoPropiedad tp ON p.idtipropiedad = tp.id
JOIN Servicio_Propiedad sp on p.id =sp.idPropiedad
JOIN Servicios s on sp.idServicio =s.id
JOIN TipoPropiedad tp ON p.idtipropiedad = tp.id
JOIN Servicio_Propiedad sp on p.id =sp.idPropiedad
JOIN Servicios s on sp.idServicio =s.id
WHERE EXISTS (
SELECT 1
FROM Servicio_Propiedad sp2
@@ -474,15 +527,16 @@ public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
WHERE sp2.idPropiedad = p.id
AND FIND_IN_SET(s2.descripcion, {serviciosEscapados})
)
GROUP BY p.id
LIMIT 10 OFFSET {pag*10}
GROUP BY p.id
LIMIT 10 OFFSET {pag * 10}
""";
var ret = Singleton.Context.Database.SqlQuery<PropiedadesAdmin>(sqlq);
var ret = Singleton.Context.Database.SqlQuery<PropiedadesAdmin>(sqlq);
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,
@@ -490,9 +544,9 @@ public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
p.iddivisa as Iddivisa
FROM Propiedades p
JOIN EstadoPropiedad ep ON p.idestado = ep.id
JOIN TipoPropiedad tp ON p.idtipropiedad = tp.id
JOIN Servicio_Propiedad sp on p.id =sp.idPropiedad
JOIN Servicios s on sp.idServicio =s.id
JOIN TipoPropiedad tp ON p.idtipropiedad = tp.id
JOIN Servicio_Propiedad sp on p.id =sp.idPropiedad
JOIN Servicios s on sp.idServicio =s.id
WHERE p.canthabitaciones = {cantidadHabitaciones}
AND EXISTS (
SELECT 1
@@ -502,14 +556,15 @@ public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
AND FIND_IN_SET(s2.descripcion, {serviciosEscapados})
)
GROUP BY p.id
LIMIT 10 OFFSET {pag*10}
LIMIT 10 OFFSET {pag * 10}
""";
var ret = Singleton.Context.Database.SqlQuery<PropiedadesAdmin>(sqlq);
return ret;
var ret = Singleton.Context.Database.SqlQuery<PropiedadesAdmin>(sqlq);
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,
@@ -517,9 +572,9 @@ public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
p.iddivisa as Iddivisa
FROM Propiedades p
JOIN EstadoPropiedad ep ON p.idestado = ep.id
JOIN TipoPropiedad tp ON p.idtipropiedad = tp.id
JOIN Servicio_Propiedad sp on p.id =sp.idPropiedad
JOIN Servicios s on sp.idServicio =s.id
JOIN TipoPropiedad tp ON p.idtipropiedad = tp.id
JOIN Servicio_Propiedad sp on p.id =sp.idPropiedad
JOIN Servicios s on sp.idServicio =s.id
WHERE p.idtipropiedad = {tipoPropiedad}
AND EXISTS (
SELECT 1
@@ -529,14 +584,15 @@ public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
AND FIND_IN_SET(s2.descripcion, {serviciosEscapados})
)
GROUP BY p.id
LIMIT 10 OFFSET {pag*10}
LIMIT 10 OFFSET {pag * 10}
""";
var ret = Singleton.Context.Database.SqlQuery<PropiedadesAdmin>(sqlq);
var ret = Singleton.Context.Database.SqlQuery<PropiedadesAdmin>(sqlq);
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,
@@ -544,9 +600,9 @@ public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
p.iddivisa as Iddivisa
FROM Propiedades p
JOIN EstadoPropiedad ep ON p.idestado = ep.id
JOIN TipoPropiedad tp ON p.idtipropiedad = tp.id
JOIN Servicio_Propiedad sp on p.id =sp.idPropiedad
JOIN Servicios s on sp.idServicio =s.id
JOIN TipoPropiedad tp ON p.idtipropiedad = tp.id
JOIN Servicio_Propiedad sp on p.id =sp.idPropiedad
JOIN Servicios s on sp.idServicio =s.id
WHERE p.canthabitaciones = {habitaciones} AND p.idtipropiedad = {tipo}
AND EXISTS (
SELECT 1
@@ -556,30 +612,35 @@ public class RepositorioPropiedades: RepositorioBase<RepositorioPropiedades> {
AND FIND_IN_SET(s2.descripcion, {serviciosEscapados})
)
GROUP BY p.id
LIMIT 10 OFFSET {pag*10}
LIMIT 10 OFFSET {pag * 10}
""";
var ret = Singleton.Context.Database.SqlQuery<PropiedadesAdmin>(sqlq);
var ret = Singleton.Context.Database.SqlQuery<PropiedadesAdmin>(sqlq);
return ret;
}
public int CuantasPaginas(int estado = 0) {
public int CuantasPaginas(int estado = 0)
{
var con = Context;
double inter;
int ret;
if (estado == 0){
inter = con.Propiedades.Count()/10.0;
} else {
inter = con.Propiedades.Where(x=>x.Idestado == estado).Count();
if (estado == 0)
{
inter = con.Propiedades.Count() / 10.0;
}
else
{
inter = con.Propiedades.Where(x => x.Idestado == estado).Count();
}
if (inter == 0.00) return 0;
ret = (int)Math.Ceiling(inter);
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){
query = query.Where(x=>x.Idestado == estado);
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,26 +677,29 @@ 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)
.Include(c=>c.IdtipropiedadNavigation)
.Where(x=>x.Idestado ==4 && !x.Venta.Any(x=>x.Idestado ==2))
.Skip(pag*10).Take(10);
var props = con.Propiedades.Include(x => x.IdServicios).Include(x => x.IddivisaNavigation)
.Include(c => c.IdtipropiedadNavigation)
.Where(x => x.Idestado == 4 && !x.Venta.Any(x => x.Idestado == 2))
.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();
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);
var l = con.Propiedades.Include(x => x.IdServicios).Include(x => x.IdtipropiedadNavigation)
.Where(x => x.Dnipropietario == dni && x.Idestado == 4);
return l;
}
}
}

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) {
Cliente? cli2 = con.Clientes.FirstOrDefault(x => x.Email == cli.Email);
if (cli2 != null)
{
grupo = con.Grupos.Find(2);
if (grupo == null || grupo.Id == 0) return false;
cli2.Idgrupos.Add(grupo);
@@ -23,7 +102,7 @@ public class RepositorioUsuarios: RepositorioBase<RepositorioUsuarios> {
grupo = con.Grupos.Find(2);
if (grupo == null || grupo.Id == 0) return false;
con.Clientes.Add(cli);
if (cli.Dni == 0) return false;
@@ -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);
@@ -48,7 +129,7 @@ public class RepositorioUsuarios: RepositorioBase<RepositorioUsuarios> {
grupo = con.Grupos.Find(1);
if (grupo == null || grupo.Id == 0) return false;
con.Clientes.Add(cli);
if (cli.Dni == 0) return false;
@@ -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,74 +151,96 @@ public class RepositorioUsuarios: RepositorioBase<RepositorioUsuarios> {
}
public bool CheckUsuario(LoginDto logindto) {
if (logindto.Contraseña ==null)return false;
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);
if (hashdb == Contraseña) return true;
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("-","");
return BitConverter.ToString(buf).Replace("-", "");
}
public bool CheckToken(string email, string token) {
var usu = Context.Clientes.FirstOrDefault(x => x.Email == email);
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);
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();
state.Break();
}
});
}
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});
Nombre = x.Nombre + " " + x.Apellido,
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,40 +265,47 @@ 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);
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);
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);
Cliente? cli = con.Clientes.Include(x => x.NotificacioneDniclienteNavigations).FirstOrDefault(x => x.Token == token);
if (cli == null|| cli.Dni == 0) return null;
if (cli == null || cli.Dni == 0) return null;
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);
var usu = con.Clientes.FirstOrDefault(x => x.Dni == dni);
if (usu == null) return false;
usu.Nombre = dto.Nombre;
usu.Apellido = dto.Apellido;
usu.Celular = dto.Celular;

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"