falta interfaz venta

This commit is contained in:
2025-01-24 21:31:37 -03:00
parent f8692ccdf0
commit 2b481e2ae2
13 changed files with 457 additions and 15 deletions

View File

@@ -0,0 +1,25 @@
using Entidades.Dto;
namespace AlquilaFacil.Builder;
public class OpcionVentaDtoBuilder: Builder<OpcionVentaDto>{
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;
}
}

View File

@@ -47,4 +47,9 @@ public class PrecontratoBuilder : Builder<Contrato> {
data.MesesDurationContrato = mesesDuracionContrato;
return this;
}
public PrecontratoBuilder SetOpcionVenta(bool tieneOpcionVenta){
data.Tieneopcionventa = tieneOpcionVenta == false?0Lu:1Lu;
return this;
}
}

View File

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

View File

@@ -1,12 +1,42 @@
using AlquilaFacil.Builder;
using Entidades;
using Entidades.Dto;
using Microsoft.AspNetCore.Mvc;
using Modelo;
namespace AlquilaFacil.Controllers;
[ApiController]
public class VentaController:ControllerBase {
[HttpPost("/api/ventas/ejercerOpcionVenta")]
public IActionResult EjercerOpcionVenta(long idcontrato) {
[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 IActionResult SubirRecibo([FromForm]IFormFile file, long idventa ) {
@@ -27,8 +57,71 @@ public class VentaController:ControllerBase {
}
[HttpGet("/api/contrato/tieneopcionventa")]
public IActionResult TieneOpcionVenta(long idcontrato) {
*/
[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});
}
}

View File

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

View File

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

View File

@@ -1,16 +1,19 @@
<script lang="ts">
let { onClose, onSubmit } : {
onClose: () => void,
onSubmit: (data: { opcionVenta: boolean; cantGarantes: number; mesesHastaAumento: number, mesesDuracionContrato:number }) => void
onSubmit: (data: { opcionVenta: boolean; cantGarantes: number; mesesHastaAumento: number, mesesDuracionContrato:number, montoOpcion:number, iddivisa:number }) => void
} = $props();
let opcionVenta: boolean = $state(false);
let cantGarantes: number = $state(0);
let mesesHastaAumento: number = $state(0);
let mesesDuracionContrato:number =$state(0);
let montoOpcion:number=$state(0);
let iddivisa:number=$state(0);
function handleSubmit(e:Event) {
e.preventDefault();
onSubmit({ opcionVenta, cantGarantes, mesesHastaAumento, mesesDuracionContrato });
onSubmit({ opcionVenta, cantGarantes, mesesHastaAumento, mesesDuracionContrato, montoOpcion, iddivisa });
onClose();
}
</script>
@@ -25,11 +28,23 @@
<form onsubmit={handleSubmit}>
<div class="modal-body">
<div class="form-group">
<div class="form-check">
<input type="checkbox" class="form-check-input" bind:checked={opcionVenta} id="opcionVenta" />
<label class="form-check-label" for="opcionVenta">Seleccionar Opcion de Venta</label>
</div>
{#if opcionVenta}
<div class="form-group">
<label for="montoOpcion">Definir monto</label>
<input type="number" class="form-control" bind:value={montoOpcion} id="montoOpcion">
</div>
<div class="form-group">
<label for="iddivisa">Seleccionar Divisa</label>
<select class="form-select" bind:value={iddivisa} id="iddivisa">
<option value="0">AR$</option>
<option value="1">US$</option>
</select>
</div>
{/if}
</div>
<div class="form-group">
<label for="cantGarantes">Cantidad de Garantes</label>

View File

@@ -3,9 +3,10 @@
import { onMount } from "svelte";
import ModalEstatico from "../Componentes/ModalEstatico.svelte";
import {urlG} from "../stores/urlStore";
import type { AltaDefectoDto, CanonDto, ContratoDto, ContratoPropiedadDto, DefectoDto, GaranteDto2 } from "../types";
import type { AltaDefectoDto, CanonDto, ContratoDto, ContratoPropiedadDto, DefectoDto, GaranteDto2, OpcionVentaDto } from "../types";
import ModalPedirDoc from "../Componentes/ModalPedirDoc.svelte";
import FormAltaDefecto from "../Componentes/FormAltaDefecto.svelte";
import { navigate } from "svelte-routing";
let token:string = sessionStorage.getItem("token")||"";
@@ -29,14 +30,60 @@
});
let defectos:DefectoDto[] = $state([]);
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("");
onMount(()=>{
getparams();
obtenerDatosACargar();
opcionVenta();
});
async function opcionVenta() {
try {
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;
ObtenerOpcionVentaDto();
return;
}
let data = await r.json();
modaldata = data.message;
return;
}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),
}
});
if (r.ok) {
let data = await r.json();
dtoVenta = data;
return
}
let data = await r.json();
modaldata = data.message;
}catch{
modaldata = "Fallo hacer la request";
}
}
async function obtenerDatosACargar() {
try {
const respPropiedad = fetch($urlG+"/api/contrato/inquilino?id="+contratoid, {
@@ -223,6 +270,25 @@
}
}
async function ejercerOpcionVenta() {
try {
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){
opcionVenta();
return;
}
} catch {
modaldata = "Fallo al intentar hacer la request";
}
}
</script>
<NavBarAutocompletable/>
@@ -374,8 +440,10 @@
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
@@ -384,10 +452,11 @@
<FormAltaDefecto onConfirm={cargarDefecto} idcontrato={prop.id} />
</div>
<div class="card-footer">
</div>
</div>
<br>
{/if}
<table class="table table-hover table-striped">
<thead>
<tr>
@@ -419,6 +488,55 @@
</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"
>
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}.
<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("/accion/13?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>
</div>
</div>
{/if}
</div>
</div>
</div>

View File

@@ -3,10 +3,11 @@
import NavBarAutocompletable from "../Componentes/NavBarAutocompletable.svelte";
import ModalEstatico from "../Componentes/ModalEstatico.svelte";
import {urlG} from "../stores/urlStore";
import type { CanonDto, ContratoDto, ContratoPropiedadDto, DefectoDto, GaranteDto2 } from "../types";
import type { CanonDto, ContratoDto, ContratoPropiedadDto, DefectoDto, GaranteDto2, OpcionVentaDto } from "../types";
import ModalConfirm from "../Componentes/ModalConfirm.svelte";
import ModalPedirDoc from "../Componentes/ModalPedirDoc.svelte";
import ModalNotificacion from "../Componentes/ModalNotificacion.svelte";
import { navigate } from "svelte-routing";
let token:string = sessionStorage.getItem("token")||"";
@@ -35,6 +36,8 @@
mesesDuracion:0,
});
let defectos:DefectoDto[] = $state([]);
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("");
@@ -43,8 +46,52 @@
getparams();
await obtenerDatosACargar();
max = canons.at(-1).mesNum||0;
opcionVenta();
});
async function opcionVenta() {
try {
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;
ObtenerOpcionVentaDto();
return;
}
let data = await r.json();
modaldata = data.message;
return;
}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),
}
});
if (r.ok) {
let data = await r.json();
dtoVenta = data;
return
}
let data = await r.json();
modaldata = data.message;
}catch{
modaldata = "Fallo hacer la request";
}
}
async function obtenerDatosACargar() {
try {
const respPropiedad = fetch($urlG+"/api/contrato/propietario?id="+contratoid, {
@@ -511,6 +558,50 @@
</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"
>
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}.
<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
</p>
<div class="d-flex">
<button class="btn btn-primary" disabled={!dtoVenta.fueEjercido} onclick={()=>navigate("/accion/13?idventa="+dtoVenta.id)}>
Ir a la pagina de la Venta
</button>
</div>
</div>
<div class="card-footer text-center">IdOpcionVenta: {dtoVenta.id}</div>
</div>
</div>
</div>
</div>
{/if}
</div>
</div>
</div>

View File

@@ -161,7 +161,8 @@
}
}
async function handleEnviarmensaje2(data: {opcionVenta:boolean, cantGarantes:number, mesesHastaAumento:number, mesesDuracionContrato:number}) {
async function handleEnviarmensaje2(data: {opcionVenta:boolean, cantGarantes:number,
mesesHastaAumento:number, mesesDuracionContrato:number, montoOpcion:number, iddivisa:number}) {
if (data.opcionVenta == null || data.cantGarantes <=0 || data.mesesHastaAumento<=0 || data.mesesDuracionContrato <=0) {
modaldata = "Estan mal cargados los datos del form";
return;
@@ -177,7 +178,9 @@
fechaprimernotificacion: fecha,
emailInquilino: Selmens.remitente,
emailPropietario: Selmens.receptor,
mesesDuracionContrato: data.mesesDuracionContrato
mesesDuracionContrato: data.mesesDuracionContrato,
montoOpcion: data.montoOpcion,
iddivisa: data.iddivisa
};
let responce = await fetch($urlG+"/api/contratos/precontrato", {

View File

@@ -144,4 +144,12 @@ export type ChartData = {
label: string,
data:string[],
}]
}
export type OpcionVentaDto = {
id:number,
monto:number,
divisa:string,
enOrden:boolean,
fueEjercido:boolean
}

View File

@@ -14,7 +14,7 @@ public class RepositorioContratos: RepositorioBase<RepositorioContratos> {
}
}
public bool CargaPrecontrato(Contrato? c = null, Notificacione? n = null) {
public bool CargaPrecontrato( Contrato? c = null, Notificacione? n = null) {
if (c == null || c.Habilitado == 1) return false;
if (n == null) return false;
var con = Context;
@@ -201,4 +201,39 @@ public class RepositorioContratos: RepositorioBase<RepositorioContratos> {
var con = Context;
return con.Contratos.Where(x=>x.Fechainicio.Year == year).Any();
}
public bool SetOpcionVenta(Venta v, long idcontrato) {
var con = Context;
var cont = con.Contratos.Include(x=>x.IdventaNavigation).FirstOrDefault(x=>x.Id == idcontrato);
if (cont != null) return false;
v.Id = (con.Ventas.Any()?con.Ventas.Count():0)+1;
cont.IdventaNavigation = v;
con.Ventas.Add(v);
return Guardar(con);
}
public bool CargaPrecontratoOpcionVenta(Contrato c, Notificacione n, Venta v) {
if (c == null || c.Habilitado == 1) return false;
if (n == null) return false;
var con = Context;
var prop = con.Propiedades.FirstOrDefault(x=>x.Id==c.Idpropiedad);
if (prop == null) return false;
prop.Idestado = 2;
c.Iddivisa = prop.Iddivisa;
c.Id = (con.Contratos.Any() ? con.Contratos.Max(x => x.Id) : 0) + 1;
c.Monto = prop.Monto;
v.Id = (con.Ventas.Any()?con.Ventas.Count():0)+1;
c.Idventa = v.Id;
con.Ventas.Add(v);
con.Contratos.Add(c);
con.Notificaciones.Add(n);
return Guardar(con);
}
}

View File

@@ -0,0 +1,26 @@
using Entidades;
using Microsoft.EntityFrameworkCore;
namespace Modelo;
public class RepositorioVentas: RepositorioBase<RepositorioVentas> {
public Contrato? ObtenerVentaPorContrato(long idcontrato) {
var con = Context;
var c = con.Contratos.Include(x=>x.Idcanons).Include(x=>x.IdventaNavigation).ThenInclude(x=>x.IddivisaNavigation)
.FirstOrDefault(x=>x.Id == idcontrato);
if (c == null || c.IdventaNavigation == null) return null;
return c;
}
public bool PatchVenta(Venta venta) {
var con = Context;
var a = con.Ventas.FirstOrDefault(x=>x.Id == venta.Id);
a.IdVendedor = venta.IdVendedor;
a.IdComprador = venta.IdComprador;
a.Idpropiedad = venta.Idpropiedad;
a.Fechainicio = venta.Fechainicio;
a.Idestado=2;
return Guardar(con);
}
}