diff --git a/Aspnet/Builder/DtoBuilder/OpcionVentaDtoBuilder.cs b/Aspnet/Builder/DtoBuilder/OpcionVentaDtoBuilder.cs new file mode 100644 index 0000000..8df2256 --- /dev/null +++ b/Aspnet/Builder/DtoBuilder/OpcionVentaDtoBuilder.cs @@ -0,0 +1,25 @@ +using Entidades.Dto; + +namespace AlquilaFacil.Builder; +public class OpcionVentaDtoBuilder: Builder{ + public OpcionVentaDtoBuilder SetId(long id) { + data.Id = id; + return this; + } + public OpcionVentaDtoBuilder SetMonto(decimal monto) { + data.Monto = monto; + return this; + } + public OpcionVentaDtoBuilder SetDivisa(string divisa) { + data.Divisa = divisa; + return this; + } + public OpcionVentaDtoBuilder SetEnOrden(bool v) { + data.EnOrden = v; + return this; + } + public OpcionVentaDtoBuilder SetFueEjercido(int idestado) { + data.FueEjercido = idestado==1?false:true; + return this; + } +} \ No newline at end of file diff --git a/Aspnet/Builder/DtoBuilder/VentasDtoBuilder.cs b/Aspnet/Builder/DtoBuilder/VentasDtoBuilder.cs new file mode 100644 index 0000000..38a7f25 --- /dev/null +++ b/Aspnet/Builder/DtoBuilder/VentasDtoBuilder.cs @@ -0,0 +1,41 @@ +using Entidades.Dto; + +namespace AlquilaFacil.Builder; +public class VentasDtoBuilder: Builder { + public VentasDtoBuilder SetId(long id) { + data.Id = id; + return this; + } + public VentasDtoBuilder SetMonto(decimal monto) { + data.Monto = monto; + return this; + } + public VentasDtoBuilder SetDivisa(string divisa) { + data.Divisa = divisa; + return this; + } + public VentasDtoBuilder SetUbicacion(string ubicacion) { + data.Ubicacion = ubicacion; + return this; + } + public VentasDtoBuilder SetNombreVendedor(string nombre) { + data.NombreVendedor = nombre; + return this; + } + public VentasDtoBuilder SetIdVendedor(long idVendedor) { + data.IdVendedor = idVendedor; + return this; + } + public VentasDtoBuilder SetNombreComprador(string nombre) { + data.NombreComprador = nombre; + return this; + } + public VentasDtoBuilder SetIdComprador(long Id) { + data.IdComprador = Id; + return this; + } + public VentasDtoBuilder SetEstado(string estado) { + data.Estado = estado; + return this; + } +} \ No newline at end of file diff --git a/Aspnet/Builder/PrecontratoBuilder.cs b/Aspnet/Builder/PrecontratoBuilder.cs index 5e58b57..5d20313 100644 --- a/Aspnet/Builder/PrecontratoBuilder.cs +++ b/Aspnet/Builder/PrecontratoBuilder.cs @@ -47,4 +47,9 @@ public class PrecontratoBuilder : Builder { data.MesesDurationContrato = mesesDuracionContrato; return this; } + + public PrecontratoBuilder SetOpcionVenta(bool tieneOpcionVenta){ + data.Tieneopcionventa = tieneOpcionVenta == false?0Lu:1Lu; + return this; + } } \ No newline at end of file diff --git a/Aspnet/Controllers/ContratoController.cs b/Aspnet/Controllers/ContratoController.cs index fa6c146..6c6e822 100644 --- a/Aspnet/Controllers/ContratoController.cs +++ b/Aspnet/Controllers/ContratoController.cs @@ -336,6 +336,7 @@ public class ContratoController: ControllerBase { .SetPropiedad(p.Id) .SetFecha(DateTime.Parse(dto.fechaprimernotificacion)) .SetMesesDuracion(dto.MesesDuracionContrato) + .SetOpcionVenta(dto.TieneOpcionVenta) .Build(); @@ -349,7 +350,18 @@ public class ContratoController: ControllerBase { .SetMensaje($"El propietario {propi.Nombre} {propi.Apellido} te requiere que carges informacion de {dto.CantidadGarantes} Garantes") .Build(); - var ret = RepositorioContratos.Singleton.CargaPrecontrato(precontrato, notificacion); + bool ret; + if (dto.TieneOpcionVenta==false){ + ret = RepositorioContratos.Singleton.CargaPrecontrato(precontrato, notificacion); + } else { + Venta v = new Venta{ + Idestado = 1, + Iddivisa = dto.iddivisa, + Monto = dto.MontoOpcion, + }; + ret = RepositorioContratos.Singleton.CargaPrecontratoOpcionVenta(precontrato, notificacion, v); + } + if (ret) { ret = RepositorioNotificaciones.Singleton.MarcarComoLeido(cli.Dni, DateTime.Parse(dto.fechaprimernotificacion)); } @@ -816,6 +828,7 @@ public class ContratoController: ControllerBase { if (dto.MesesHastaAumento <= 0) ret += "No puede tener 0 o menos meses hasta el aumento\n"; if (dto.MesesDuracionContrato <= 0) ret += "No puede tener 0 o menos meses de duracion\n"; if (dto.MesesDuracionContrato < dto.MesesHastaAumento) ret += "el tiempo hasta aumento no puede ser mayor de \n"; + if (dto.TieneOpcionVenta == true && dto.MontoOpcion <=0) ret +="No puede tener un monto de venta negativo o 0"; return ret; } diff --git a/Aspnet/Controllers/VentaController.cs b/Aspnet/Controllers/VentaController.cs new file mode 100644 index 0000000..b9857dd --- /dev/null +++ b/Aspnet/Controllers/VentaController.cs @@ -0,0 +1,321 @@ +using System.Configuration; +using System.Formats.Asn1; +using System.Text.Json; +using AlquilaFacil.Builder; +using AlquilaFacil.Config; +using Entidades; +using Entidades.Dto; +using Microsoft.AspNetCore.Mvc; +using Minio; +using Minio.DataModel.Args; +using Modelo; + +namespace AlquilaFacil.Controllers; +[ApiController] +public class VentaController:ControllerBase { + + [HttpPost("/api/ventas/ejercerOpcionVenta")] + public IActionResult EjercerOpcionVenta([FromHeader(Name="Auth")]string Auth, [FromQuery]long idcontrato=0) { + var validacion1 = RepositorioGrupos.Singleton.CheckGrupos(Auth, "Inquilino"); + if (validacion1 == false) { + return Unauthorized(); + } + 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"}); + + Venta venta = cont.IdventaNavigation; + venta.IdVendedor = cont.Dnipropietario; + venta.IdComprador = cont.Dniinquilino; + venta.Idpropiedad = cont.Idpropiedad; + venta.Fechainicio = DateTime.Now; + + bool ret = RepositorioVentas.Singleton.PatchVenta(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 SubirRecibo([FromHeader(Name="Auth")]string Auth, [FromForm]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(); + } + } + + 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 (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." }); + if (!Path.GetExtension(file.FileName).Equals(".pdf", StringComparison.OrdinalIgnoreCase)) return BadRequest(new { message = "El archivo debe tener la extensión .pdf." }); + + 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"}); + + ret = RepositorioVentas.Singleton.SetUrlRecibo(venta.Id, nuevoNombreArchivo); + if (ret == false) return BadRequest(new { message = "no se pudo guardar el nombre del archivo subido"}); + + return Ok(new { message = "Se Subio el Recibo"}); + + } + private readonly IMinioClient mc; + public VentaController(IMinioClient minioClient) { + mc = minioClient; + if (mc == null){ + MinioConfigcus? mcon = JsonSerializer.Deserialize(System.IO.File.ReadAllText("./settings.json"))?? null; + if (mcon == null) throw new Exception(); + + mc = new MinioClient().WithCredentials(mcon.usr, mcon.scrt) + .WithEndpoint("192.168.1.11:9000") + .WithSSL(false) + .Build(); + } + } + private async Task 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; + } + } + + [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(); + } + } + 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 (cli.Dni != venta.IdComprador && cli.Dni != venta.IdVendedor) return Unauthorized(); + + try{ + var memstream = new MemoryStream(); + + var goa = new GetObjectArgs() + .WithBucket("alquilafacil") + .WithObject(venta.UrlRecibo) + .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){ + Console.Error.WriteLine(e); + 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(); + } + } + 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) return Unauthorized(); + + bool ret = RepositorioVentas.Singleton.EfectuarVenta(idventa); + 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"}); + + 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(); + + 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??"") + .Build(); + + 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(); + } + } + + 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"}); + + List lista = new(); + 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??"") + .Build(); + lista.Add(v); + } + return Ok(lista); + } + + [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) { + return Unauthorized(); + } + } + 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"}); + + var dto = new OpcionVentaDtoBuilder() + .SetId(cont.Idventa??0) + .SetMonto(cont.IdventaNavigation.Monto) + .SetDivisa(cont.IdventaNavigation.IddivisaNavigation.Signo) + .SetEnOrden(puedeEjercer(cont)) + .SetFueEjercido(cont.IdventaNavigation.Idestado??0) + .Build(); + + return Ok(dto); + } + + private bool puedeEjercer(Contrato c) { + bool ret = c.Idcanons.All(x => x.Pagado == 1); + + 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) { + ret = true; + }else{ + ret = false; + } + } + + return ret; + } + + [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) { + return Unauthorized(); + } + } + + 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(); + + return Ok( new { message = cont.Tieneopcionventa}); + } +} \ No newline at end of file diff --git a/Entidades/Alquilafacilcontext.cs b/Entidades/Alquilafacilcontext.cs index afd29c8..286427c 100644 --- a/Entidades/Alquilafacilcontext.cs +++ b/Entidades/Alquilafacilcontext.cs @@ -670,6 +670,9 @@ public partial class AlquilaFacilContext : DbContext entity.Property(e => e.Monto) .HasPrecision(12) .HasColumnName("monto"); + entity.Property(e => e.UrlRecibo) + .HasColumnType("text") + .HasColumnName("urlRecibo"); entity.HasOne(d => d.IdCompradorNavigation).WithMany(p => p.VentaIdCompradorNavigations) .HasForeignKey(d => d.IdComprador) diff --git a/Entidades/Dto/OpcionVentaDto.cs b/Entidades/Dto/OpcionVentaDto.cs new file mode 100644 index 0000000..3f11e1d --- /dev/null +++ b/Entidades/Dto/OpcionVentaDto.cs @@ -0,0 +1,8 @@ +namespace Entidades.Dto; +public class OpcionVentaDto{ + public long Id { get; set;} + public decimal Monto { get; set;} + public string Divisa { get; set;} =""; + public bool EnOrden { get; set;} + public bool FueEjercido { get; set; } +} \ No newline at end of file diff --git a/Entidades/Dto/PrecontratoDto.cs b/Entidades/Dto/PrecontratoDto.cs index 650e075..d1a76fa 100644 --- a/Entidades/Dto/PrecontratoDto.cs +++ b/Entidades/Dto/PrecontratoDto.cs @@ -8,4 +8,6 @@ public class PrecontratoDto { public bool TieneOpcionVenta { get; set; } public string fechaprimernotificacion { get; set; } = ""; public int MesesDuracionContrato { get; set; } + public Decimal MontoOpcion {get; set; } + public int iddivisa { get; set; } } \ No newline at end of file diff --git a/Entidades/Dto/VentasDto.cs b/Entidades/Dto/VentasDto.cs new file mode 100644 index 0000000..5ee9937 --- /dev/null +++ b/Entidades/Dto/VentasDto.cs @@ -0,0 +1,12 @@ +namespace Entidades.Dto; +public class VentasDto { + public long Id { get; set; } + public decimal Monto { get; set; } + public string Divisa { get; set; }=""; + public string Ubicacion { get; set; }=""; + public string NombreVendedor { get; set; }=""; + public long IdVendedor { get; set; } + public string NombreComprador { get; set; }=""; + public long IdComprador { get; set; } + public string Estado { get; set; }=""; +} \ No newline at end of file diff --git a/Entidades/Venta.cs b/Entidades/Venta.cs index 200b45c..b5c5b81 100644 --- a/Entidades/Venta.cs +++ b/Entidades/Venta.cs @@ -17,12 +17,14 @@ public partial class Venta public int? Idpropiedad { get; set; } - public DateTime Fechainicio { get; set; } + public DateTime? Fechainicio { get; set; } public DateTime? Fechafinal { get; set; } public int Iddivisa { get; set; } + public string? UrlRecibo { get; set; } + public virtual ICollection Contratos { get; set; } = new List(); public virtual Cliente? IdCompradorNavigation { get; set; } diff --git a/Front/src/App.svelte b/Front/src/App.svelte index 8575022..d5c2f3f 100644 --- a/Front/src/App.svelte +++ b/Front/src/App.svelte @@ -21,7 +21,9 @@ 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 Informes from "./paginas/Informes.svelte"; + import CompraYVentas from "./paginas/CompraYVenta.svelte"; + import Ventas from "./paginas/Ventas.svelte"; @@ -95,6 +97,16 @@ + + + + + + + + + + diff --git a/Front/src/Componentes/ModalPrecontrato.svelte b/Front/src/Componentes/ModalPrecontrato.svelte index 6f04d38..a44bdf9 100644 --- a/Front/src/Componentes/ModalPrecontrato.svelte +++ b/Front/src/Componentes/ModalPrecontrato.svelte @@ -1,16 +1,19 @@ @@ -25,11 +28,23 @@