diff --git a/Aspnet/Builder/DtoBuilder/InformeAlquilerBuilder.cs b/Aspnet/Builder/DtoBuilder/InformeAlquilerBuilder.cs new file mode 100644 index 0000000..a0020ef --- /dev/null +++ b/Aspnet/Builder/DtoBuilder/InformeAlquilerBuilder.cs @@ -0,0 +1,17 @@ +using Entidades.Informes; + +namespace AlquilaFacil.Builder; +public class InformesAlquilerBuilder: Builder{ + public InformesAlquilerBuilder SetId(long id){ + data.Id = id; + return this; + } + public InformesAlquilerBuilder SetUbicacion(string Ubicacion){ + data.Ubicacion = Ubicacion; + return this; + } + public InformesAlquilerBuilder SetDivisa(string Divisa){ + data.Divisa = Divisa; + return this; + } +} \ No newline at end of file diff --git a/Aspnet/Controllers/EstadisticaController.cs b/Aspnet/Controllers/EstadisticaController.cs new file mode 100644 index 0000000..93db4df --- /dev/null +++ b/Aspnet/Controllers/EstadisticaController.cs @@ -0,0 +1,60 @@ +using AlquilaFacil.Builder; +using Entidades.Informes; +using Microsoft.AspNetCore.Mvc; +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) { + if (String.IsNullOrWhiteSpace(Auth)) return BadRequest(""); + var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Informes"); + 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.ObtenerDataIniciadosPorAño(year); + return Ok(a); + } + [HttpGet("api/tabla/alquileresIniciados")] + public IActionResult tablaalquileresIniciadosEsteAño([FromHeader(Name ="Auth")]string Auth, int year) { + if (String.IsNullOrWhiteSpace(Auth)) return BadRequest(""); + var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Informes"); + 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 informe =new(); + foreach (var i in a) { + var d = new InformesAlquilerBuilder() + .SetId(i.Id).SetUbicacion(i.IdpropiedadNavigation.Ubicacion) + .SetDivisa(i.IddivisaNavigation.Signo) + .Build(); + informe.Add(d); + } + return Ok(informe); + } + [HttpGet("api/stats/duracionContrato")] + public IActionResult DuracionContrato([FromHeader(Name ="Auth")]string Auth) { + if (String.IsNullOrWhiteSpace(Auth)) return BadRequest(""); + var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Informes"); + 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) { + if (String.IsNullOrWhiteSpace(Auth)) return BadRequest(""); + var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Informes"); + if (validacion1 == false) return Unauthorized(); + + var a = RepositorioEstadisticas.Singleton.TablaObtenerDataDuracionContratos(); + return Ok(a); + } +} \ No newline at end of file diff --git a/Aspnet/Controllers/ServiciosController.cs b/Aspnet/Controllers/ServiciosController.cs deleted file mode 100644 index fea5d8b..0000000 --- a/Aspnet/Controllers/ServiciosController.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Entidades; -using Entidades.Dto; -using Microsoft.AspNetCore.Http.HttpResults; -using Microsoft.AspNetCore.Mvc; -using Modelo; - -namespace AlquilaFacil.Controllers; - -[ApiController] -public class ServiciosController: ControllerBase { - -} \ No newline at end of file diff --git a/Entidades/Dto/Chart/Chartjs.cs b/Entidades/Dto/Chart/Chartjs.cs index 9c52544..c208dd5 100644 --- a/Entidades/Dto/Chart/Chartjs.cs +++ b/Entidades/Dto/Chart/Chartjs.cs @@ -16,14 +16,8 @@ public class Dataset public string Label { get; set; } =""; [JsonPropertyName("data")] - public List Data { get; set; }= new(); -/* - [JsonPropertyName("backgroundColor")] - public List BackgroundColor { get; set; } + public List Data { get; set; }= new(); - [JsonPropertyName("borderColor")] - public List BorderColor { get; set; } -*/ [JsonPropertyName("borderWidth")] public int BorderWidth { get; set; }=1; } diff --git a/Entidades/Informes/InfomesAlquiler.cs b/Entidades/Informes/InfomesAlquiler.cs new file mode 100644 index 0000000..a5900ff --- /dev/null +++ b/Entidades/Informes/InfomesAlquiler.cs @@ -0,0 +1,6 @@ +namespace Entidades.Informes; +public class InformesAlquiler { + public long Id { get; set; } + public string Ubicacion { get; set; }=""; + public string Divisa { get; set; }=""; +} \ No newline at end of file diff --git a/Entidades/Informes/InformeMeses.cs b/Entidades/Informes/InformeMeses.cs new file mode 100644 index 0000000..7442417 --- /dev/null +++ b/Entidades/Informes/InformeMeses.cs @@ -0,0 +1,17 @@ +namespace Entidades.Informes; +public class InformesMeses { + public int Meses { get; set; } + public int Repes{ get; set; } + public string Semaforizacion {get { + switch(Repes.CompareTo(2)){ + case 1: + return "🟢"; + case 0: + return "🟡"; + case -1: + return "🔴"; + default: + return ""; + } + }} +} \ No newline at end of file diff --git a/Front/bun.lockb b/Front/bun.lockb index 502d03b..dba69aa 100755 Binary files a/Front/bun.lockb and b/Front/bun.lockb differ diff --git a/Front/index.html b/Front/index.html index a051eac..89c9c3f 100644 --- a/Front/index.html +++ b/Front/index.html @@ -5,6 +5,7 @@ + - -
- -
\ No newline at end of file + }; + onMount(createChart); + $effect(createChart); + + + +
+ +
+ diff --git a/Front/src/paginas/Informes.svelte b/Front/src/paginas/Informes.svelte index 1a75d59..0802bd7 100644 --- a/Front/src/paginas/Informes.svelte +++ b/Front/src/paginas/Informes.svelte @@ -4,35 +4,183 @@ import NavBarAutocompletable from "../Componentes/NavBarAutocompletable.svelte"; import { Chart } from "chart.js"; import FChart from "../Componentes/Estadisticas/fChart.svelte"; + import ModalEstatico from "../Componentes/ModalEstatico.svelte"; + import {urlG} from "../stores/urlStore"; + import type { ChartData } from "../types"; + import { text } from "@sveltejs/kit"; - let cdata = $state(); + let token = sessionStorage.getItem("token")||""; + let y = $state(2025); - let myChart; - onMount(() => { + let cdata:ChartData|any = $state(); + let aldata:{id:number, ubicacion:string, divisa:string}|any = $state(); + + let chartMesesDuracion:ChartData|any = $state(); + let tablaMesesDuracion:{meses:number, repes:number, semaforizacion:string}|any = $state(); + + 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]); + + let data = await r.json(); + let data2 = await p.json(); + + cdata = data; + aldata = data2; + return; + }catch{ + modaldata="Fallo al intentar alcanzar el servidor"; + } + } + + let visibleMesesDuracion:boolean = $state(false); + async function dataMesesDuracion() { + try{ + const p1 = fetch($urlG+"/api/stats/duracionContrato", { + method : "GET", + headers: { + "Auth": token, + } + }); + const p2 = fetch($urlG+"/api/tabla/duracionContrato", { + method : "GET", + headers: { + "Auth": token, + } + }); + 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"; + } + } +{#if modaldata} + !!(modaldata = "")} /> +{/if} + -
-
-
- -
- - +
+
+ +
+
+

+

- - - - - -
#UbicacionDivisa
-
-
- + Alquileres en el ultimo año + + +
+
+
+
+ + +
+ + + + + + + + + + {#each aldata as al} + + + + + + {/each} + +
#UbicacionDivisa
{al.id}{al.ubicacion}{al.divisa}
+
+
+ {#if cdata} + + {/if} +
+
+
+
+
+

+ +

+
+
+
+

Objetivo: Mide la longitud de los contratos en meses y cuantos hay por cada longitud. por lo menos 2.

+ + + + + + + + + + {#each tablaMesesDuracion as mes} + + + + + + {/each} + +
Cantidad de mesesRepeticionesSemaforización
{mes.meses}{mes.repes}{mes.semaforizacion}
+
+
+ {#if chartMesesDuracion} + + {/if} +
+
+
+
- \ No newline at end of file diff --git a/Front/src/types.d.ts b/Front/src/types.d.ts index eaabcf9..b525e18 100644 --- a/Front/src/types.d.ts +++ b/Front/src/types.d.ts @@ -136,4 +136,12 @@ export type AltaDefectoDto ={ pagainquilino:number, iddivisa:number, idcontrato:number +} + +export type ChartData = { + labels: string[], + datasets: [{ + label: string, + data:string[], + }] } \ No newline at end of file diff --git a/Modelo/RepositorioContratos.cs b/Modelo/RepositorioContratos.cs index 3ae44dd..d371346 100644 --- a/Modelo/RepositorioContratos.cs +++ b/Modelo/RepositorioContratos.cs @@ -196,4 +196,9 @@ public class RepositorioContratos: RepositorioBase { .FirstOrDefault(x=>x.Id == idcontrato); return l; } + + public bool HayContratosEnAño(int year) { + var con = Context; + return con.Contratos.Where(x=>x.Fechainicio.Year == year).Any(); + } } diff --git a/Modelo/RepositorioEstadisticas.cs b/Modelo/RepositorioEstadisticas.cs new file mode 100644 index 0000000..c9100a0 --- /dev/null +++ b/Modelo/RepositorioEstadisticas.cs @@ -0,0 +1,72 @@ +using Entidades; +using Entidades.Informes; +using Microsoft.EntityFrameworkCore; + +namespace Modelo; +public class RepositorioEstadisticas: RepositorioBase { + public ChartData? ObtenerDataIniciadosPorAño(int year){ + var con = Context; + var contratosPorMes = con.Contratos + .Where(c => c.Habilitado == 1 && c.Fechainicio.Year == year) + .GroupBy(c => c.Fechainicio.Month) + .Select(g => new { Mes = g.Key, Cantidad = g.Count() }) + .OrderBy(x => x.Mes).ToList(); + + if (!contratosPorMes.Any()) return null; + + var data = new ChartData(); + data.Labels = ["Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"]; + + List ddd = new List(["0","0","0","0","0","0","0","0","0","0","0","0"]); + foreach (var contrato in contratosPorMes) { + ddd[contrato.Mes-1] = contrato.Cantidad.ToString(); + } + + Dataset dd = new(); + dd.Data = ddd; + dd.Label = $"Alquileres por Mes del año {year}"; + data.Datasets.Add(dd); + return data; + } + + public ChartData? ObtenerDataDuracionContratos() { + var con = Context; + var meses = con.Contratos.Where(x=>x.Habilitado ==1) + .GroupBy(x=>x.MesesDurationContrato).Select(g=> new {Duracion = g.Key, Cantidad = g.Count()}); + if(!meses.Any()) return null; + + var data = new ChartData(); + Dataset dd = new(); + + foreach (var mes in meses){ + data.Labels.Add(mes.Duracion.ToString()); + dd.Data.Add(mes.Cantidad.ToString()); + } + dd.Label="Duracion Contratos"; + data.Datasets.Add(dd); + return data; + } + + public IQueryable TablaObtenerContratosIniciadosPorAño(int year) { + var con = Context; + var contratosPorMes = con.Contratos.Include(x=>x.IddivisaNavigation).Include(x=>x.IdpropiedadNavigation) + .Where(c => c.Habilitado == 1 && c.Fechainicio.Year == year); + return contratosPorMes; + } + + public List TablaObtenerDataDuracionContratos() { + var con = Context; + var meses = con.Contratos.Where(x=>x.Habilitado ==1) + .GroupBy(x=>x.MesesDurationContrato).Select(g=> new {Duracion = g.Key, Cantidad = g.Count()}); + + List l = new(); + foreach (var mes in meses){ + l.Add(new InformesMeses{ + Meses = mes.Duracion, + Repes = mes.Cantidad + }); + } + return l; + + } +} \ No newline at end of file