Mejoras en Facturacion

This commit is contained in:
2023-11-30 18:40:15 -03:00
parent f2efb41977
commit 04478afa2f
14 changed files with 310 additions and 24 deletions

View File

@ -42,6 +42,26 @@
</span>
</td>
</tr>
<tr>
<td>Terreno</td>
<td>
<table class="ui very basic striped table">
<tr>
<td>
{{$format->number($proyecto->terreno->superficie, 2)}}m&#0178;
</td>
<td>
{{$format->pesos($proyecto->terreno->valor)}} ({{$proyecto->terreno->fecha?->format('d-m-Y')}})
</td>
<td>
<a href="{{$urls->base}}/proyecto/{{$proyecto->id}}/terreno">
<i class="edit icon"></i>
</a>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td>Superficies</td>
<td>

View File

@ -0,0 +1,5 @@
@extends('layout.base')
@push('page_content')
@endpush

View File

@ -13,6 +13,9 @@
{{$venta->propiedad()->summary()}}
</a>
</h2>
<div class="ui very basic segment">
Valor Venta: {{$format->ufs($venta->valor)}}
</div>
<form id="venta_form" class="ui form">
<div class="two wide field">
<label for="proporcion">Proporción Factura</label>
@ -27,13 +30,37 @@
@foreach ($venta->propiedad()->unidades as $unidad)
<div class="three wide field">
<label for="precio{{$unidad->pu_id}}">Precio {{ucwords($unidad->proyectoTipoUnidad->tipoUnidad->descripcion)}} {{$unidad->descripcion}}</label>
<div class="ui right labeled input">
<div class="ui right labeled input" id="input{{$unidad->pu_id}}">
<input class="price" type="text" name="precio{{$unidad->pu_id}}" id="precio{{$unidad->pu_id}}" data-id="{{$unidad->pu_id}}" value="{{($unidad->valor > 0) ? $unidad->valor : $unidad->precio($venta->currentEstado()->fecha)->valor}}" />
<div class="ui basic label">UF</div>
</div>
</div>
@endforeach
</div>
<div class="fields">
@foreach($venta->propiedad()->unidades as $unidad)
<div class="three wide field">
@if ($unidad->prorrateo === 0.0)
<label for="prorrateo{{$unidad->id}}">Prorrateo {{ucwords($unidad->proyectoTipoUnidad->tipoUnidad->descripcion)}} {{$unidad->descripcion}}</label>
<div class="ui right labeled input" id="prorrateo{{$unidad->id}}">
<input class="prorrateo" type="text" data-id="{{$unidad->id}}" value="{{$unidad->prorrateo}}" />
<div class="ui basic label">%</div>
</div>
@endif
</div>
@endforeach
</div>
<div class="ui very basic segment" id="total_unidades"></div>
@php $lastDic = new DateTimeImmutable((new DateTimeImmutable())->sub(new DateInterval('P1Y'))->format('31-12-Y')); @endphp
@if (!isset($venta->proyecto()->terreno->fecha) or $venta->proyecto()->terreno->fecha < $lastDic)
<div class="four wide field">
<label for="terreno">Valor Terreno al {{$lastDic->format('d-m-Y')}}</label>
<div class="ui left labeled input">
<div class="ui basic label">$</div>
<input type="number" id="terreno" />
</div>
</div>
@endif
</form>
<div class="ui divider"></div>
<div id="factura">
@ -44,7 +71,7 @@
{{mb_strtoupper($venta->proyecto()->inmobiliaria()->nombreCompleto())}}
</strong><br/>
GIRO: <br/>
Dirección:
Dirección: {{$venta->proyecto()->direccion()->simple()}}
</div>
<div class="four wide column">
<div class="ui center aligned red segment">
@ -148,12 +175,14 @@
totales: {},
proporcion: 1,
precio: {{$UF->transform($venta->currentEstado()->fecha, $venta->valor)}},
terreno: {{$IPC->readjust($venta->proyecto()->terreno->valor, $venta->proyecto()->terreno->date, $venta->currentEstado()->fecha)}},
terreno: {{(isset($venta->proyecto()->terreno->fecha) and $venta->proyecto()->terreno->fecha > $lastDic) ?
$IPC->readjust($venta->proyecto()->terreno->valor, $venta->proyecto()->terreno->fecha, $venta->currentEstado()->fecha) : 0}},
uf: {{$UF->get($venta->currentEstado()->fecha)}},
unidades: JSON.parse('{!! json_encode(array_map(function(Incoviba\Model\Venta\PropiedadUnidad $unidad) use ($venta, $UF, $format) {
$precio = ($unidad->valor > 0) ? $unidad->valor : $unidad->precio($venta->currentEstado()->fecha)->valor;
return [
'pu_id' => $unidad->pu_id,
'id' => $unidad->id,
'pid' => $unidad->pu_id,
'descripcion' => ucwords($unidad->proyectoTipoUnidad->tipoUnidad->descripcion) . ' ' . $unidad->descripcion,
'precio' => $precio,
'base' => $UF->transform($venta->currentEstado()->fecha, $precio),
@ -168,6 +197,8 @@
const percentFormatter = new Intl.NumberFormat('es-CL', {maximumFractionDigits: 5, minimumFractionDigits: 5})
let terreno = 0
let prorrateo = 0
let totalUnidades = 0
let precioUnidades = 0
let c = 1
const classes = [
'',
@ -178,6 +209,8 @@
'right aligned'
]
this.unidades.forEach(unidad => {
totalUnidades += unidad.base
precioUnidades += unidad.precio
const descuento = this.terreno * unidad.prorrateo
terreno += descuento
prorrateo += unidad.prorrateo
@ -203,6 +236,13 @@
})
tbody.append(row)
})
$('#total_unidades')
.attr('class', 'ui compact segment ' + ((totalUnidades.toFixed(2) !== this.precio.toFixed(2)) ? 'inverted red' : 'inverted green'))
.html('Total Unidades: ' + ufFormatter.format(precioUnidades) + ' UF' +
((totalUnidades.toFixed(2) !== this.precio.toFixed(2)) ? '; Diferencia: ' + ufFormatter.format({{$venta->valor}} - precioUnidades) + ' UF' : ''))
if (totalUnidades.toFixed(2) !== this.precio.toFixed(2)) {
this.highlight()
}
const bruto = this.precio - terreno
const base = bruto / 1.19
const iva = base * .19
@ -210,15 +250,16 @@
const total = subtotal + terreno
const totalUF = total / this.uf
const emptyTerreno = '<div class="ui tiny red horizontal circular label">0</div>'
const data = [
c,
'Valor con Terreno ' + pesoFormatter.format((base + terreno) * this.proporcion) + ' - Menos valor terreno ' + pesoFormatter.format(-terreno * this.proporcion) + '<br />' +
'Valor con Terreno ' + pesoFormatter.format((base + terreno) * this.proporcion) + ' - Menos valor terreno ' + ((terreno > 0) ? pesoFormatter.format(-terreno * this.proporcion) : emptyTerreno) + '<br />' +
'Base imponible ' + pesoFormatter.format(base * this.proporcion) + '<br />' +
'IVA ' + pesoFormatter.format(iva * this.proporcion) + '<br />' +
'SUBTOTAL ' + pesoFormatter.format(subtotal * this.proporcion) + '<br />' +
'Mas valor terreno ' + pesoFormatter.format(terreno * this.proporcion) + '<br />' +
'Mas valor terreno ' + ((terreno > 0) ? pesoFormatter.format(terreno * this.proporcion) : emptyTerreno) + '<br />' +
'TOTAL ' + pesoFormatter.format(total * this.proporcion) + ';' + ufFormatter.format(totalUF * this.proporcion) + ' UF<br /><br />' +
'Descuento Terreno: ' + percentFormatter.format(prorrateo * 100) + '%<br /><br />' +
'Descuento Terreno: ' + ((terreno > 0) ? percentFormatter.format(prorrateo * 100) : emptyTerreno) + '%<br /><br />' +
'UF: ' + ufFormatter.format(this.uf),
'1 UNID',
pesoFormatter.format(terreno * this.proporcion),
@ -244,7 +285,8 @@
update: function() {
return {
price: (id, value) => {
const idx = this.unidades.findIndex(unidad => unidad.pu_id === id)
this.unhighlight()
const idx = this.unidades.findIndex(unidad => unidad.pid === id)
if (idx === -1) {
return
}
@ -263,11 +305,59 @@
if (!json.edited) {
return
}
const idx = this.unidades.findIndex(unidad => unidad.pu_id === json.propiedad_unidad_id)
const idx = this.unidades.findIndex(unidad => unidad.pid === json.propiedad_unidad_id)
this.unidades[idx].precio = parseInt(json.input.valor)
this.unidades[idx].base = parseFloat(json.input.valor * this.unidades[idx].base / old_value)
this.build()
})
},
terreno: value => {
const url = '{{$urls->api}}/proyecto/{{$venta->proyecto()->id}}/terreno/edit'
const data = new FormData()
data.set('valor', value)
data.set('fecha', '{{$lastDic->format('Y-m-d')}}')
return fetchAPI(url, {method: 'post', body: data}).then(response => {
if (response.ok) {
return response.json()
}
}).then(json => {
if (!json.edited) {
return
}
this.terreno = parseInt(json.input.valor)
const data = new FormData()
data.set('start', '{{$lastDic->format('Y-m-d')}}')
data.set('end', '{{$venta->currentEstado()->fecha->sub(new DateInterval('P1M'))->format('Y-m-d')}}')
const url = '{{$urls->api}}/money/ipc'
return fetchAPI(url, {method: 'post', body: data}).then(response => {
if (response.ok) {
return response.json()
}
}).then(json => {
this.terreno *= (1 + parseFloat(json.ipc))
this.build()
})
})
},
prorrateo: (id, value) => {
if (parseFloat(value) === 0) {
return
}
const url = '{{$urls->api}}/ventas/unidad/' + id + '/prorrateo'
const data = new FormData()
data.set('prorrateo', value)
return fetchAPI(url, {method: 'post', body: data}).then(response => {
if (response.ok) {
return response.json()
}
}).then(json => {
if (!json.edited) {
return
}
const idx = this.unidades.findIndex(unidad => unidad.id === json.unidad_id)
this.unidades[idx].prorrateo = parseFloat(json.input.prorrateo)
this.build()
})
}
}
},
@ -283,16 +373,46 @@
this.build()
})
},
prices: (class_name) => {
prices: class_name => {
$(class_name).change(event => {
const val = $(event.currentTarget).val()
const id = $(event.currentTarget).data('id')
this.update().price(id, val)
})
},
prorrateo: class_name => {
$(class_name).change(event => {
const val = $(event.currentTarget).val()
const id = $(event.currentTarget).data('id')
this.update().prorrateo(id, val)
})
},
terreno: id => {
$(id).change(event => {
const val = $(event.currentTarget).val()
this.update().terreno(val).then(() => {
$(id).parent().parent().hide()
})
})
}
}
},
setup: function({form_id, tbody_id, input_id, prices_class, totales_ids}) {
highlight: function() {
const pid = this.unidades[0].pid
const input = $('#input' + pid)
input.addClass('error')
input.find('.label').addClass('red')
input.attr('data-content', 'Valor total no es igual a valor de venta')
input.popup()
},
unhighlight: function() {
const pid = this.unidades[0].pid
const input = $('#input' + pid)
input.removeClass('error')
input.find('.label').removeClass('red')
input.removeAttr('data-content')
},
setup: function({form_id, tbody_id, input_id, prices_class, prorrateo_class, terreno_id, totales_ids}) {
$(form_id).submit(event => {
event.preventDefault()
return false
@ -302,12 +422,16 @@
this.proporcion = $(input_id).val() / 100
this.watch().proporcion(input_id)
this.watch().prices(prices_class)
this.watch().prorrateo(prorrateo_class)
@if (!isset($venta->proyecto()->terreno->fecha) or $venta->proyecto()->terreno->fecha <= $lastDic)
this.watch().terreno(terreno_id)
@endif
this.build()
}
}
$(document).ready(() => {
factura.setup({form_id: '#venta_form', tbody_id: '#unidades', input_id: '#proporcion',
prices_class: '.price', totales_ids: {
prices_class: '.price', prorrateo_class: '.prorrateo', terreno_id: '#terreno', totales_ids: {
afecto: '#neto',
exento: '#exento',
iva: '#iva',

View File

@ -112,15 +112,15 @@
}
}).then(data => {
if (data.total > 0) {
const progress = this.draw().progress(data.ventas.length)
this.data.id = data.proyecto.id
this.data.proyecto = data.proyecto.descripcion
this.data.venta_ids = data.ventas
const promises = []
data.ventas.forEach(venta_id => {
const promise = this.get().venta(venta_id)
/*promise.then(() => {
this.draw().ventas(true)
})*/
const promise = this.get().venta(venta_id).then(() => {
progress.progress('increment')
})
promises.push(promise)
})
Promise.all(promises).then(() => {
@ -185,6 +185,26 @@
parent.show()
parent.find('.item.proyecto').click(this.actions().get)
},
progress: cantidad => {
const parent = $(this.ids.proyectos)
parent.html('')
const progress = $('<div></div>').addClass('ui active progress').append(
$('<div></div>').addClass('bar').append(
$('<div></div>').addClass('centered progress')
)
).append(
$('<div></div>').addClass('label').html('Cargando datos')
)
progress.progress({
total: cantidad,
label: 'ratio',
text: {
ratio: '{value} de {total} ({percent}%)'
}
})
parent.append(progress)
return progress
},
ventas: (loading = false) => {
const title = $(this.ids.title)
const parent = $(this.ids.proyectos)

View File

@ -12,6 +12,10 @@
<a href="{{$urls->base}}/venta/{{$venta->id}}/escritura/firmar">
Firmar
</a>
<br />
<a href="{{$urls->base}}/ventas/factura/{{$venta->id}}">
Factura
</a>
</div>
@else
<div class="ui segment">