Files
AlquilaFacil/Front/src/paginas/ContratosPropietario.svelte
T

680 lines
25 KiB
Svelte

<script lang="ts">
import { onMount } from "svelte";
import NavBarAutocompletable from "../Componentes/NavBarAutocompletable.svelte";
import ModalEstatico from "../Componentes/ModalEstatico.svelte";
import {urlG} from "../stores/urlStore";
import type { CanonDto, ChartData, 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";
import FChart from "../Componentes/Estadisticas/fChart.svelte";
let token:string = sessionStorage.getItem("token")||"";
let interes:number = $state(0);
let selMod:any =$state();
let showmodal:boolean = $state(false);
let shownotif:boolean = $state(false);
let chartData:ChartData|any = $state();
let max:number=$state(0);
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 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(async ()=>{
getparams();
await obtenerDatosACargar();
max = canons.at(-1).mesNum||0;
opcionVenta();
await setChartData();
});
async function setChartData() {
try{
const r = await fetch($urlG+"/api/contrato/stats?idcontrato="+contratoid, {
method: "GET",
headers: {
"Auth": String(token),
}
});
let data = await r.json();
if (r.ok){
chartData = data;
return;
}
modaldata = data.message;
}catch{
modaldata = "no se pudo obtener el chartdata";
}
}
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;
if (TieneOpcionVenta){
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, {
method: "GET",
headers: {
"Auth": token,
}
});
const respgarantes = fetch($urlG+"/api/contratos/garantes?idcontrato="+contratoid, {
method: "GET",
headers: {
"Auth": token,
}
});
const respCanons = fetch($urlG+"/api/contratos/canon?id="+contratoid, {
method: "GET",
headers: {
"Auth": 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();
const datosCanons = await c.json();
const datosDefect = await d.json();
prop = datosPropiedad;
garantes = datosGarantes;
canons = datosCanons;
defectos = datosDefect;
} catch {
modaldata = "Fallo hacer las request";
}
}
function getparams(){
const qs = window.location.search;
const par = new URLSearchParams(qs);
contratoid = par.get("id")||"";
}
async function submitnuevosCanones(e: Event) {
e.preventDefault();
try {
const ret = await fetch($urlG+"/api/contratos/crearcanons",{
method: "POST",
headers: {
"Auth" : String(token),
"Content-Type": "application/json",
},
body: JSON.stringify({idcontrato: contratoid, aumento: interes})
});
let data = await ret.json();
modaldata = data.message;
if (ret.ok) {
refreshCanon();
}
} catch {
modaldata = "Fallo al intentar alcanzar el servidor";
}
}
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),
}
});
if (!resp.ok) {
let blob = await resp.json();
modaldata=blob.message;
return;
}
let blob = await resp.blob();
const blobUrl = URL.createObjectURL(blob);
window.open(blobUrl, '_blank');
setTimeout(() => URL.revokeObjectURL(blobUrl), 100000);
} catch {
modaldata= "fallo intentar hacer la request";
}
}
async function refreshCanon() {
try {
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;
}
let data = await ret.json();
canons = data;
return;
} catch {
modaldata = "No se pudo obtener la lista de canones actualizada";
}
}
async function marcarPago(mes: Date) {
try {
const ret = await fetch($urlG+"/api/contratos/marcarPago", {
method: "POST",
headers: {
"Auth": String(token),
"Content-Type": "application/json",
},
body: JSON.stringify({idcontrato:contratoid, fecha:mes}),
});
let data = await ret.json();
modaldata = data.message;
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";
}
}
async function EscribirNotificacion(message:string) {
if (message =="") {
modaldata = "no se puede enviar un mensaje vacio";
return;
}
try {
const r = await fetch($urlG+"/api/notificarInquilino", {
method: "POST",
headers: {
"Auth": String(token),
"Content-Type": "application/json",
},
body: JSON.stringify({
mensaje: message,
idpropiedad: prop.id
})
});
let data = await r.json();
modaldata = data.message;
} catch {
modaldata ="No se pudo enviar el mensaje";
}
}
function abrirModalNotif() {
shownotif = true;
}
async function marcarDefectoPago(defecto: DefectoDto) {
try{
const r = await fetch($urlG+"/api/defecto/marcarpago?iddefecto="+defecto.id, {
method: "PUT",
headers: {
"Auth": String(token),
"Content-Type": "application/json",
},
});
let dr = await r.json();
modaldata = dr.message;
if (r.ok) {
refreshDefectos();
}
}catch {
modaldata = "No se pudo marcar como pago";
}
}
async function refreshDefectos() {
try {
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";
}
}
function generarCSVEstadistica() {
let contenido = ["Categorias", ...chartData.datasets.map((d: { label: any; }) => d.label)].join(",") + "\n";
chartData.labels.forEach((label: any, index: string | number) => {
let fila = [label, ...chartData.datasets.map((d: { data: { [x: string]: any; }; }) => d.data[index])].join(",");
contenido += fila + "\n";
});
contenido += "\n";
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 ? "Si" : "No"].join(",");
contenido += fila + "\n";
});
}
let blob = new Blob([contenido], { type: "text/csv" });
let url = URL.createObjectURL(blob);
let a = document.createElement("a");
a.href = url;
a.download = "chart_data.csv";
a.click();
URL.revokeObjectURL(url);
}
</script>
<NavBarAutocompletable/>
{#if modaldata}
<ModalEstatico payload={modaldata} close={()=>!!(modaldata = "")}/>
{/if}
{#if showmodal}
<ModalPedirDoc onClose={()=>showmodal=false} onSubmit={pedirdocumento} />
{/if}
{#if shownotif}
<ModalNotificacion onCancel={()=>shownotif = false} onConfirm={EscribirNotificacion}/>
{/if}
<div class="container-fluid mt-4 d-flex">
<div class="col-md-4 me-4">
<div class="card">
<div class="card-header text-center">Propiedad</div>
<div class="card-body">
<p><b>Tipo:</b> {prop.tipoPropiedad}</p>
<p><b>Ubicación:</b> {prop.ubicacion}</p>
<p><b>Propietario:</b> {prop.propietario}</p>
<p><b>Inquilino:</b> {prop.inquilino}</p>
<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>Estado:</b> {prop.estado}</p>
<div class="d-flex justify-content-between">
<button class="btn btn-secondary" onclick={verContrato}>
Ver Contrato
</button>
<button class="btn btn-warning" onclick={abrirModalNotif}>
Enviar Notificacion
</button>
</div>
</div>
<div class="card-footer text-center">
IdContrato: {prop.id}
</div>
</div>
</div>
<div class="col d-flex flex-column">
<div class="accordion mb-4" id="accordionExample">
<div class="accordion-item">
<h2 class="accordion-header" id="headingOne">
<button
class="accordion-button"
type="button"
data-bs-toggle="collapse"
data-bs-target="#collapseOne"
aria-expanded="true"
aria-controls="collapseOne"
>
Garantes
</button>
</h2>
<div
id="collapseOne"
class="accordion-collapse collapse show"
aria-labelledby="headingOne"
data-bs-parent="#accordionExample"
>
<div class="accordion-body">
<table class="table table-striped table-hover">
<thead>
<tr>
<th>Dni</th>
<th>Nombre</th>
<th>Apellido</th>
<th>Domicilio</th>
<th>Dom. Laboral</th>
<th>Celular</th>
</tr>
</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>
{/each}
</tbody>
</table>
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header" id="h6">
<button class="accordion-button collapsed"
data-bs-toggle="collapse"
data-bs-target="#c6"
aria-expanded="false"
aria-controls="c6">
Estadisticas
</button>
</h2>
<div id="c6" class="accordion-collapse collapse"
data-bs-parent="#accordionExample">
<div class="accordion-body d-flex justify-content-center" >
<div style="width: 500px; height: auto;">
{#if chartData != null}
<FChart {chartData} typec="doughnut" />
{/if}
<button class="btn btn-secondary mt-2" onclick={generarCSVEstadistica}>
Exportar CSV
</button>
</div>
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header" id="headingTwo">
<button
class="accordion-button collapsed"
type="button"
data-bs-toggle="collapse"
data-bs-target="#collapseTwo"
aria-expanded="false"
aria-controls="collapseTwo"
>
Canons
</button>
</h2>
<div
id="collapseTwo"
class="accordion-collapse collapse"
aria-labelledby="headingTwo"
data-bs-parent="#accordionExample"
>
<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-warning btn-xs" disabled={canon.pago} onclick={()=>marcarPago(canon.mes)}>
Marcar Pago
</button>
<button class="btn btn-info btn-xs" disabled={!canon.pago} onclick={()=> generarTiket(canon)}>
Generar Tiket
</button>
</div>
</div>
</div>
{/each}
{#if max < prop.mesesDuracion}
<div class="card">
<div class="card-header text-center">
Definir el interés para los siguientes Canones
</div>
<div class="card-body">
<form>
<div class="input-group">
<input
class="form-control"
type="number"
id="interes"
bind:value={interes}
min="0"
/>
<span class="input-group-text" id="basic-addon2">%</span>
</div>
<br />
<button
class="btn btn-primary"
type="submit"
onclick={(e) => submitnuevosCanones(e)}
>
Enviar
</button>
</form>
</div>
</div>
{/if}
</div>
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header" id="ht">
<button
class="accordion-button collapsed"
type="button"
data-bs-toggle="collapse"
data-bs-target="#ct"
aria-expanded="false"
aria-controls="ct"
>
Defectos
</button>
</h2>
<div
id="ct"
class="accordion-collapse collapse"
aria-labelledby="ht"
data-bs-parent="#accordionExample"
>
<div class="accordion-body">
<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>
<th></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>
<td>
{#if defecto.estado !== "Pagado"}
<button class="btn btn-secondary" onclick={()=>marcarDefectoPago(defecto)}>Marcar Pago</button>
{/if}
</td>
</tr>
{/each}
{/if}
</tbody>
</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"
>
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("/Ventas?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>