Separacion de objetos

This commit is contained in:
Juan Pablo Vial
2025-01-17 00:07:45 -03:00
parent 055bf6ab20
commit d74beb5518
5 changed files with 1199 additions and 1027 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,388 @@
<script>
class Factura {
props = {
id: 0,
venta: null,
index: 0,
proporcion: 0,
emisor: {
rut: '',
nombre: '',
direccion: '',
comuna: ''
},
receptor: {
rut: '',
nombre: '',
direccion: '',
comuna: ''
},
fecha: null,
unidades: {
unidad: null,
descripcion: '',
precio: 0,
prorrateo: 0
},
detalle: {
base: 0,
terreno: 0,
neto: 0,
iva: 0,
bruto: 0,
descuento: 0,
total: 0
},
total: {
neto: 0,
exento: 0,
iva: 0,
total: 0
},
uf: {
fecha: null,
valor: 0
}
}
constructor(props) {
this.props = props
}
get saved() {
return this.props.id > 0
}
draw() {
return {
divider: () => {
return '<div class="ui divider" data-index="'+this.props.index+'"></div>'
},
factura: ({formatters = {date, pesos, ufs, percent}}) => {
return [
this.draw().divider(this.props.index),
`<div class="factura" data-index="${this.props.index}">`,
'<div class="ui compact grid">',
this.draw().cabecera(),
this.draw().propietario({formatters}),
this.draw().table({formatters}),
this.draw().totales({formatters}),
this.draw().guardar(),
'</div>',
'</div>'
].join("\n")
},
cabecera: () => {
return [
'<div class="two columns row">',
this.draw().inmobiliaria(),
this.draw().rut(),
'</div>'
].join("\n")
},
inmobiliaria: () => {
return [
'<div class="twelve wide column">',
'<strong>'+this.props.emisor.nombre.toUpperCase()+'</strong><br/>',
'GIRO: <br/>',
`Dirección: ${this.props.emisor.direccion}, ${this.props.emisor.comuna}`,
'</div>',
].join("\n")
},
rut: () => {
return [
'<div class="four wide column">',
'<div class="ui center aligned red segment">',
'<strong>',
`RUT:${this.props.emisor.rut.toUpperCase()}<br/>`,
'FACTURA ELECTRÓNICA<br/>',
`N° #${this.props.venta.id}${this.props.index}`,
'</strong>',
'</div>',
'</div>'
].join("\n")
},
propietario: ({formatters}) => {
return [
'<div class="row">',
'<table class="ui table">',
'<tr>'+
'<td class="grey"><strong>Señor(es)</strong></td>',
'<td>'+this.props.receptor.nombre+'</td>',
'<td class="grey"><strong>RUT</strong></td>',
'<td>'+this.props.receptor.rut.toUpperCase()+'</td>',
'</tr>',
'<tr>',
'<td class="grey"><strong>Giro</strong></td>',
'<td>Otras Actividades Profesionales</td>',
'<td class="grey"><strong>Fecha Emisión</strong></td>',
'<td>'+formatters.date.format(this.props.fecha)+'</td>',
'</tr>',
'<tr>',
'<td class="grey"><strong>Dirección</strong></td>',
'<td>'+this.props.receptor.direccion+'</td>',
'<td class="grey"><strong>Comuna</strong></td>',
'<td>'+this.props.receptor.comuna.toUpperCase()+'</td>',
'</tr>',
'</table>',
'</div>'
].join("\n")
},
table: ({formatters}) => {
return [
'<div class="row">',
'<table class="ui celled table">',
'<thead>',
'<tr class="grey">',
'<th class="center aligned" colspan="6">DETALLES</th>',
'</tr>',
'<tr class="grey">',
'<th>N°</th>',
'<th class="center aligned">Descripción</th>',
'<th class="center aligned">Cant/Unidad</th>',
'<th class="center aligned">Prec. Unit.</th>',
'<th class="center aligned">Ind</th>',
'<th class="center aligned">Total</th>',
'</tr>',
'</thead>',
'<tbody>',
this.draw().unidades({formatters}),
'</tbody>',
'<tfoot>',
'<tr>',
'<td colspan="6">',
'<br />',
'<br />',
'<br />',
'<br />',
'</td>',
'</tr>',
'</tfoot>',
'</table>',
'</div>'
].join("\n")
},
unidades: ({formatters}) => {
const unidadesData = []
let no = 1
const classes = [
'',
'',
'center aligned',
'right aligned',
'center aligned',
'right aligned'
]
this.props.unidades.forEach(unidad => {
unidadesData.push(this.draw().unidad({
unidad,
no: no++,
classes,
formatters
}))
})
unidadesData.push(this.draw().resumen({
no,
classes,
formatters
}))
return unidadesData.join("\n")
},
unidad: ({unidad, no, classes, formatters}) => {
const descuento = Math.round(this.props.detalle.terreno * unidad.prorrateo)
const bruto = unidad.precio - descuento
const neto = bruto / 1.19
const data = [
no,
unidad.descripcion,
'1 UNID',
formatters.pesos.format(neto * this.props.proporcion),
'AF',
formatters.pesos.format(neto * this.props.proporcion)
]
const row = ['<tr>']
data.forEach((value, i) => {
const cell = ['<td']
if (classes[i] !== '') {
cell.push(' class="' + classes[i] + '"')
}
cell.push('>'+value+'</td>')
row.push(cell.join(''))
})
row.push('</tr>')
return row.join('')
},
resumen: ({no, classes, formatters}) => {
const emptyTerreno = '<div class="ui tiny red horizontal circular label">0</div>'
const data = [
no,
'Valor con Terreno: $' + formatters.pesos.format(this.props.detalle.base) + ' - Menos valor terreno: $' + ((this.props.detalle.terreno > 0) ? formatters.pesos.format(-this.props.detalle.terreno) : emptyTerreno) + '<br />' +
'Base imponible (Neto): $' + formatters.pesos.format(this.props.detalle.neto) + '<br />' +
'IVA: $' + formatters.pesos.format(this.props.detalle.iva) + '<br />' +
'SUBTOTAL (Bruto): $' + formatters.pesos.format(this.props.detalle.bruto) + '<br />' +
'Mas valor terreno: $' + ((this.props.detalle.terreno > 0) ? formatters.pesos.format(this.props.detalle.terreno) : emptyTerreno) + '<br />' +
'TOTAL (Escritura): $' + formatters.pesos.format(this.props.detalle.total) + '; ' + formatters.ufs.format(this.props.venta.valor * this.props.proporcion) + ' UF<br /><br />' +
'Descuento Terreno: ' + ((this.props.detalle.terreno > 0) ? formatters.percent.format(this.props.detalle.descuento * 100) : emptyTerreno) + '%<br /><br />' +
'UF (' + formatters.date.format(this.props.uf.fecha) + '): $' + formatters.ufs.format(this.props.uf.valor),
'1 UNID',
formatters.pesos.format(this.props.detalle.terreno),
'EX',
formatters.pesos.format(this.props.detalle.terreno),
]
const row = ['<tr class="top aligned">']
data.forEach((value, i) => {
const cell = ['<td']
if (classes[i] !== '') {
cell.push(' class="'+classes[i]+'"')
}
cell.push('>'+value+'</td>')
row.push(cell.join(''))
})
return row.join('')
},
totales: ({formatters}) => {
return [
'<div class="row">',
'<div class="ten wide column"></div>',
'<div class="six wide column">',
'<table class="ui celled very compact table">',
'<thead>',
'<tr>',
'<th class="center aligned grey" colspan="2">TOTALES</th>',
'</tr>',
'</thead>',
'<tbody>',
'<tr>',
'<td class="grey">Monto Neto</td>',
'<td class="right aligned" id="neto">'+formatters.pesos.format(this.props.total.neto)+'</td>',
'</tr>',
'<tr>',
'<td class="grey">Monto Exento</td>',
'<td class="right aligned" id="exento">'+formatters.pesos.format(this.props.total.exento)+'</td>',
'</tr>',
'<tr>',
'<td class="grey">19% IVA</td>',
'<td class="right aligned" id="iva">'+formatters.pesos.format(this.props.total.iva)+'</td>',
'</tr>',
'<tr>',
'<td class="grey">Monto Total</td>',
'<td class="right aligned"><strong id="total">'+formatters.pesos.format(this.props.total.total)+'</strong></td>',
'</tr>',
'</tbody>',
'</table>',
'</div>',
'</div>'
].join("\n")
},
guardar: () => {
if (this.props.saved) {
return [
'<div class="row">',
'<div class="fourteen wide column"></div>',
'<div class="two wide center aligned column">',
'<div class="ui green message">',
'<i class="check icon"></i>',
'Guardada',
'</div>',
'</div>',
'</div>'
].join("\n")
}
return [
'<div class="row">',
'<div class="right aligned sixteen wide column">',
`<button class="ui primary button guardar" data-index="${this.props.index}">Guardar</button>`,
'</div>',
'</div>'
].join("\n")
}
}
}
watch() {
return {
save: () => {
document.querySelector(`button[data-index="${this.props.index}"]`).addEventListener('click', clickEvent => {
const index = clickEvent.currentTarget.getAttribute('data-index')
facturas.save().factura(index)
})
}
}
}
save() {
let url = '{{$urls->api}}/venta/{{$venta->id}}/facturas/add'
if (this.saved) {
url = `{{$urls->api}}/venta/{{$venta->id}}/facturas/${this.props.id}/edit`
}
const method = 'post'
const body = new FormData()
body.set('venta_id', this.props.venta_id)
body.set('index', this.props.index)
body.set('proporcion', this.props.proporcion)
body.set('cliente', JSON.stringify(this.props.receptor))
body.set('terreno', this.props.terreno)
body.set('unidades', JSON.stringify(this.props.unidades))
body.set('fecha', [this.props.fecha.getFullYear(), this.props.fecha.getMonth()+1, this.props.fecha.getDate()].join('-'))
body.set('detalle', JSON.stringify(this.props.detalle))
body.set('total', JSON.stringify(this.props.total))
body.set('uf', JSON.stringify(this.props.uf))
return APIClient.fetch(url, {method, body}).then(response => {
if (!response) {
return
}
return response.json().then(json => {
if (json.success) {
this.props.id = json.factura.id
facturas.draw().facturas()
}
})
})
}
update() {
return {
venta: venta => {
this.props.venta = venta.props
this.props.fecha = venta.props.facturas.fecha
this.props.uf.fecha = venta.props.uf.fecha
this.props.uf.valor = venta.props.uf.valor
this.update().propietario(venta.props.propietarios.find(propietario => propietario.props.index === this.props.index))
this.update().unidades(venta.props.unidades)
this.props.detalle.total = venta.props.valor * this.props.proporcion * venta.props.uf.valor
this.update().detalle(venta.props.facturas.terreno.valor * venta.prorrateo)
this.props.total.exento = this.props.detalle.terreno
this.props.total.iva = this.props.detalle.iva
this.props.detalle.descuento = venta.prorrateo * this.props.proporcion
},
detalle: terreno => {
this.props.detalle.terreno = terreno * this.props.proporcion
this.props.detalle.bruto = this.props.detalle.total - this.props.detalle.terreno
this.props.detalle.neto = this.props.detalle.bruto / 1.19
this.props.detalle.iva = this.props.detalle.neto * 0.19
this.props.detalle.base = this.props.detalle.neto + this.props.detalle.terreno
},
unidades: unidades => {
this.props.unidades = []
let neto = 0
unidades.forEach(unidad => {
this.props.unidades.push({
unidad: unidad,
descripcion: unidad.descripcion(this.props.proporcion),
precio: unidad.props.valor * this.props.uf.valor * this.props.proporcion,
prorrateo: unidad.props.prorrateo * this.props.proporcion
})
neto += unidad.props.valor
})
this.props.total.neto = neto
},
propietario: propietario => {
this.props.proporcion = propietario.props.proporcion
this.props.receptor = {
rut: propietario.props.rut,
nombre: propietario.props.nombre,
direccion: propietario.props.direccion,
comuna: propietario.comuna
}
}
}
}
}
</script>

View File

@ -0,0 +1,189 @@
<script>
class Propietario {
props = {
index: 0,
proporcion: 0,
rut: '',
nombre: '',
direccion: '',
comuna: ''
}
constructor(props) {
this.props = props
}
get comuna() {
return $('#comuna_propietario'+this.props.index).dropdown('get text') ?? this.props.comuna
}
update() {
return {
proporcion: (valor) => {
this.props.proporcion = valor
facturas.venta.update().totalPropietarios()
facturas.draw().facturas()
},
rut: rut => {
this.props.rut = rut
facturas.venta.update().totalPropietarios()
facturas.draw().facturas()
},
nombre: nombre => {
this.props.nombre = nombre
facturas.venta.update().totalPropietarios()
facturas.draw().facturas()
},
direccion: direccion => {
this.props.direccion = direccion
facturas.venta.update().totalPropietarios()
facturas.draw().facturas()
},
comuna: comuna => {
this.props.comuna = comuna
facturas.venta.update().totalPropietarios()
facturas.draw().facturas()
},
}
}
watch() {
return {
propietario: () => {
this.watch().proporcion()
this.watch().rut()
this.watch().nombre()
this.watch().direccion()
this.watch().comuna()
},
proporcion: () => {
document.getElementById('proporcion'+this.props.index).addEventListener('input', inputEvent => {
const newValue = inputEvent.currentTarget.value / 100
if (newValue === this.props.proporcion) {
return
}
const saldo = facturas.venta.props.propietarios.reduce((sum, propietario) => sum + propietario.props.proporcion, 0) - this.props.proporcion
if (saldo + newValue > 1) {
return
}
this.update().proporcion(newValue)
})
},
rut: () => {
document.getElementById('rut'+this.props.index).addEventListener('input', inputEvent => {
const rut = inputEvent.currentTarget.value
if (rut === this.props.rut) {
return
}
this.update().rut(rut)
})
},
nombre: () => {
document.getElementById('propietario'+this.props.index).addEventListener('input', inputEvent => {
const nombre = inputEvent.currentTarget.value
if (nombre === this.props.nombre) {
return
}
this.update().nombre(nombre)
})
},
direccion: () => {
document.getElementById('direccion_propietario'+this.props.index).addEventListener('input', inputEvent => {
const direccion = inputEvent.currentTarget.value
if (direccion === this.props.direccion) {
return
}
this.update().direccion(direccion)
})
},
comuna: () => {
if ($('#comuna_propietario'+this.props.index).dropdown('get value')) {
return
}
$('#comuna_propietario'+this.props.index).dropdown({
fireOnInit: true,
forceSelection: true,
onChange: (value, text) => {
this.update().comuna(value)
}
})
},
}
}
draw() {
return {
propietario: () => {
const output = [`<div class="fields" data-index="${this.props.index}">`]
output.push(this.draw().proporcion())
output.push(this.draw().rut())
output.push(this.draw().nombre())
output.push('</div>')
output.push(`<div class="fields" data-index="${this.props.index}">`)
output.push('<div class="three wide field"></div>')
output.push(this.draw().direccion())
output.push(this.draw().comuna())
output.push('</div>')
return output.join("\n")
},
proporcion: () => {
return [
'<div class="two wide field">',
`<label for="proporcion${this.props.index}">Proporción Factura</label>`,
'<div class="ui right labeled input">',
`<input type="number" name="proporcion${this.props.index}" id="proporcion${this.props.index}" value="${this.props.proporcion*100}" max="100" min="0" />`,
'<div class="ui basic icon label">',
'<i class="percent icon"></i>',
'</div>',
'</div>',
'</div>',
].join("\n")
},
rut: () => {
return [
'<div class="three wide field">',
`<label for="rut${this.props.index}">RUT</label>`,
'<div class="ui input">',
`<input type="text" name="rut${this.props.index}" id="rut${this.props.index}" value="${this.props.rut.toUpperCase()}" />`,
'</div>',
'</div>',
].join("\n")
},
nombre: () => {
return [
'<div class="six wide field">',
`<label for="propietario${this.props.index}">Propietario</label>`,
'<div class="ui input">',
`<input type="text" name="propietario${this.props.index}" id="propietario${this.props.index}" value="${this.props.nombre}" />`,
'</div>',
'</div>',
].join("\n")
},
direccion: () => {
return [
'<div class="six wide field">',
`<label for="direccion_propietario${this.props.index}">Dirección</label>`,
'<div class="ui input">',
`<input type="text" name="direccion_propietario${this.props.index}" id="direccion_propietario${this.props.index}" value="${this.props.direccion}" />`,
'</div>',
'</div>',
].join("\n")
},
comuna: () => {
return [
'<div class="three wide field">',
`<label for="comuna_propietario${this.props.index}">Comuna</label>`,
`<div class="ui search selection dropdown" id="comuna_propietario${this.props.index}">`,
`<input type="hidden" name="comuna_propietario${this.props.index}" value="${this.props.comuna}" />`,
'<i class="dropdown icon"></i>',
'<div class="default text">Comuna</div>',
'<div class="menu">',
@foreach ($comunas as $comuna)
'<div class="item" data-value="{{ $comuna->id }}">{{ $comuna->descripcion }}</div>',
@endforeach
'</div>',
'</div>',
'</div>',
].join("\n")
},
}
}
}
</script>

View File

@ -0,0 +1,125 @@
<script>
class Unidad {
props = {
id: 0,
tipo: '',
descripcion: '',
prorrateo: 0,
propiedad_unidad_id: 0,
valor: 0
}
constructor(props) {
this.props = props
}
descripcion(proporcion = 1) {
return [this.props.tipo, this.props.descripcion, `[UF ${facturas.formatters.ufs.format(this.props.valor * proporcion)}]`].join(' ')
}
update() {
return {
precio: newValue => {
const url = '{{$urls->api}}/ventas/propiedades/unidad/' + this.props.propiedad_unidad_id + '/edit'
const method = 'post'
const body = new FormData()
body.set('valor', newValue)
return fetchAPI(url, {method, body}).then(response => {
if (!response) {
return
}
return response.json().then(json => {
if (!json.edited) {
return
}
this.props.valor = parseFloat(json.input.valor)
})
})
},
prorrateo: newValue => {
const url = '{{$urls->api}}/ventas/unidad/' + this.props.id + '/prorrateo'
const method = 'post'
const body = new FormData()
body.set('prorrateo', newValue)
return fetchAPI(url, {method, body}).then(response => {
if (!response) {
return
}
return response.json().then(json => {
if (!json.edited) {
return
}
this.props.prorrateo = json.input.prorrateo
document.getElementById('prorrateo'+this.props.id).parentElement.parentElement.innerHTML = ''
})
})
}
}
}
watch() {
return {
unidad: () => {
this.watch().precio()
this.watch().prorrateo()
},
precio: () => {
document.getElementById('precio'+this.props.propiedad_unidad_id).addEventListener('change', changeEvent => {
const newValue = changeEvent.currentTarget.value
if (newValue === this.props.valor) {
return
}
this.update().precio(newValue).then(() => {
facturas.venta.update().totalUnidades()
facturas.draw().facturas()
})
})
},
prorrateo: () => {
const input = document.getElementById('prorrateo'+this.props.id)
if (input === null) {
return
}
input.addEventListener('change', changeEvent => {
const newValue = changeEvent.currentTarget.value
if (newValue === this.props.prorrateo) {
return
}
this.update().prorrateo(newValue).then(() => {
facturas.venta.update().totalUnidades()
facturas.draw().facturas()
})
})
}
}
}
draw() {
return {
precio: () => {
return [
'<div class="three wide field">',
'<label for="precio'+this.props.propiedad_unidad_id+'">Precio<br /> '+this.props.tipo+' '+this.props.descripcion+'</label>',
'<div class="ui left labeled input" id="input'+this.props.propiedad_unidad_id+'">',
'<div class="ui basic label">UF</div>',
'<input class="price" type="text" name="precio'+this.props.propiedad_unidad_id+'" id="precio'+this.props.propiedad_unidad_id+'" data-id="'+this.props.propiedad_unidad_id+'" value="'+this.props.valor+'" />',
'</div>',
'</div>'
].join("\n")
},
prorrateo: () => {
const output = []
output.push('<div class="three wide field">')
if (this.props.prorrateo === 0) {
output.push(...[
'<label for="prorrateo'+this.props.id+'">Prorrateo<br /> '+this.props.tipo+' '+this.props.descripcion+'</label>',
'<div class="ui right labeled input">',
'<input class="prorrateo" type="text" id="prorrateo'+this.props.id+'" value="'+this.props.prorrateo+'" />',
'<div class="ui basic label">%</div>',
'</div>'
])
}
output.push('</div>')
return output.join("\n")
}
}
}
}
</script>

View File

@ -0,0 +1,474 @@
<script>
class Venta {
props = {
id: 0,
fecha: null,
last: {
november: null
},
valor: 0,
inmobiliaria: {
rut: '',
nombre: '',
direccion: '',
comuna: ''
},
proyecto: {
id: 0
},
uf: {
fecha: null,
valor: 0
},
ipc: {
fecha: null,
valor: 0
},
unidades: [],
facturas: {
fecha: null,
terreno: {
fecha: null,
valor: 0
},
facturas: []
},
propietarios: [],
estado: {
fecha: null
}
}
constructor(props) {
this.props = props
}
get prorrateo() {
return this.props.unidades.reduce((sum, unidad) => sum + unidad.props.prorrateo, 0.0)
}
update() {
return {
propietarios: count => {
const diff = count - this.props.propietarios.length
if (diff > 0) {
const m = this.props.propietarios.length / count
let p = 1
this.props.propietarios.forEach((propietario, index) => {
this.props.propietarios[index].props.proporcion = parseFloat((this.props.propietarios[index].props.proporcion * m * 100).toFixed(0)) / 100
p -= this.props.propietarios[index].props.proporcion
})
p /= diff
for (let i = 0; i < diff; i ++) {
this.add().propietario({
rut: '',
nombre: '',
proporcion: (p*100).toFixed(0)/100,
direccion: '',
comuna: ''
})
}
document.getElementById('propietarios').innerHTML = this.draw().propietarios()
this.watch().propietarios()
this.update().facturas()
return
}
for (let i = this.props.propietarios.length - 1; i >= count; i --) {
this.remove().propietario(i)
}
},
fecha: date => {
this.props.uf.fecha = date
const url = '{{$urls->api}}/money/uf'
const method = 'post'
const body = new FormData()
body.set('fecha', [date.getFullYear(), date.getMonth()+1, date.getDate()].join('-'))
return fetchAPI(url, {method, body}).then(response => {
if (!response) {
return
}
return response.json().then(json => {
if (typeof json.uf === 'undefined') {
return
}
this.props.uf.valor = json.uf
return this.update().ipc()
})
})
},
fechaFacturas: date => {
if (this.props.facturas.fecha === date) {
return
}
this.props.facturas.fecha = date
this.update().facturas()
return new Promise(resolve => resolve())
},
totalUnidades: () => {
const unidades = this.props.unidades.reduce((sum, unidad) => sum + unidad.props.valor, 0)
const diff = parseFloat((this.props.valor - unidades).toFixed(4))
const $total = $('#total_unidades')
if (diff === 0) {
$total.html('')
return
}
$total.html('<div class="ui error compact message">' +
'<div class="header">' +
'<i class="exclamation triangle icon"></i>' +
'Diferencia Promesa - Precio Unidades</div>' +
'UF ' + facturas.formatters.ufs.format(diff) +
'</div>')
$total.find('.ui.message').css('display', 'inline-block')
this.props.facturas.forEach(factura => {
factura.update().unidades(this.props.unidades)
})
},
totalPropietarios: () => {
this.props.propietarios.forEach(propietario => {
const index = propietario.props.index
const factura = this.props.facturas.facturas.find(factura => factura.props.index === index)
factura.update().venta(this)
})
},
terreno: newValue => {
const date = this.props.last.november
const url = '{{$urls->api}}/proyecto/{{$venta->proyecto()->id}}/terreno/edit'
const method = 'post'
const body = new FormData()
body.set('valor', newValue)
body.set('fecha', [date.getFullYear(), date.getMonth()+1, date.getDate()].join('-'))
return fetchAPI(url, {method, body}).then(response => {
if (!response) {
return
}
return response.json().then(json => {
if (!json.success) {
return
}
this.props.facturas.terreno.fecha = new Date(json.terreno.fecha)
this.props.facturas.terreno.valor = parseInt(json.terreno.valor)
document.getElementById('terreno').parentElement.parentElement.remove()
this.update().ipc()
})
})
},
ipc: () => {
const mesAnterior = new Date([this.props.facturas.fecha.getFullYear(), this.props.facturas.fecha.getMonth()-1, '1'].join('-'))
if (this.props.last.november.getMonth() === mesAnterior.getMonth() && this.props.last.november.getFullYear() === mesAnterior.getFullYear()) {
return
}
const url = '{{$urls->api}}/money/ipc'
const method = 'post'
const body = new FormData()
body.set('start', [this.props.last.november.getFullYear(), this.props.last.november.getMonth()+1, this.props.last.november.getDate()].join('-'))
body.set('end', [mesAnterior.getFullYear(), mesAnterior.getMonth()+1, mesAnterior.getDate()].join('-'))
return fetchAPI(url, {method, body}).then(response => {
if (!response) {
return
}
return response.json().then(json => {
this.props.ipc = json.ipc
this.props.facturas.terreno.valor *= (1 + parseFloat(json.ipc.valor))
this.update().facturas()
})
})
},
facturas: () => {
this.props.facturas.facturas.forEach(factura => {
factura.update().venta(this)
})
},
form: () => {
// fecha
// unidades
// valor total unidades
// terreno
// propietarios
// ipc no disponible
}
}
}
watch() {
return {
venta: () => {
this.watch().fecha()
this.watch().fechaFacturas()
this.watch().unidades()
this.watch().terreno()
this.watch().cantidad()
this.watch().propietarios()
this.update().totalUnidades()
},
fecha: () => {
const cdo = structuredClone(calendar_date_options)
cdo['initialDate'] = this.props.estado.fecha
cdo['onChange'] = (date, text, mode) => {
this.update().fecha(date).then(() => {
facturas.draw().facturas()
})
}
$('#fecha_uf').calendar(cdo)
},
fechaFacturas: () => {
const cdo = structuredClone(calendar_date_options)
cdo['initialDate'] = this.props.estado.fecha
cdo['onChange'] = (date, text, mode) => {
this.update().fechaFacturas(date).then(() => {
facturas.draw().facturas()
})
}
$('#fecha_facturas').calendar(cdo)
},
unidades: () => {
this.props.unidades.forEach(unidad => {
unidad.watch().unidad()
})
},
terreno: () => {
const terreno = document.getElementById('terreno')
if (typeof terreno === 'undefined' || terreno === null) {
return
}
terreno.addEventListener('change', changeEvent => {
const newValue = changeEvent.currentTarget.value
if (newValue === this.props.facturas.terreno.valor) {
return
}
this.update().terreno(newValue)
})
},
cantidad: () => {
document.getElementById('cantidad_propietarios').addEventListener('change', changeEvent => {
const count = changeEvent.currentTarget.value
const diff = count - this.props.propietarios.length
if (diff === 0) {
return
}
this.update().propietarios(count)
this.update().totalPropietarios()
facturas.draw().facturas()
})
},
propietarios: () => {
this.props.propietarios.forEach(propietario => {
propietario.watch().propietario()
})
}
}
}
draw() {
return {
venta: ufFormatter => {
return [
this.draw().value(ufFormatter),
this.draw().form(),
this.draw().ipc()
].join("\n")
},
value: ufFormatter => {
return [
'<div class="ui grid">',
'<div class="three wide column">',
'<div class="ui very segment">',
'Valor Venta: UF ' + ufFormatter.format(this.props.valor),
'</div>',
'</div>',
'</div>'
].join("\n")
},
form: () => {
const output = []
output.push('<form id="venta_form" class="ui form">')
output.push(this.draw().fecha())
output.push(this.draw().fechaFactura())
output.push(this.draw().precios())
output.push(this.draw().prorrateos())
output.push('<div class="ui very basic segment" id="total_unidades"></div>')
output.push(this.draw().terreno())
output.push(...[
'<div class="two wide field">',
'<label for="propietarios">Propietarios</label>',
'<input type="number" name="cantidad_propietarios" id="cantidad_propietarios" min="1" value="1" />',
'</div>',
])
output.push('<div id="propietarios">')
output.push(this.draw().propietarios())
output.push('</div>')
output.push('</form>')
return output.join("\n")
},
fecha: () => {
return [
'<div class="three wide field">',
'<label for="fecha_uf">Fecha UF</label>',
'<div class="ui calendar" id="fecha_uf">',
'<div class="ui right icon input">',
'<input type="text" name="fecha_uf" />',
'<i class="calendar icon"></i>',
'</div>',
'</div>',
'</div>',
].join("\n")
},
fechaFactura: () => {
return [
'<div class="three wide field">',
'<label for="fecha_uf">Fecha Facturas</label>',
'<div class="ui calendar" id="fecha_facturas">',
'<div class="ui right icon input">',
'<input type="text" name="fecha_facturas" />',
'<i class="calendar icon"></i>',
'</div>',
'</div>',
'</div>',
].join("\n")
},
precios: () => {
const output = []
output.push('<div class="fields">')
this.props.unidades.forEach(unidad => {
output.push(unidad.draw().precio())
})
output.push('</div>')
return output.join("\n")
},
prorrateos: () => {
const output = []
output.push('<div class="fields">')
this.props.unidades.forEach(unidad => {
output.push(unidad.draw().prorrateo())
})
output.push('</div>')
return output.join("\n")
},
terreno: () => {
const output = []
if (typeof this.props.facturas.terreno.fecha === 'undefined' || this.props.facturas.terreno.fecha === null || this.props.facturas.terreno.fecha.getTime() < 0 || this.props.facturas.terreno.fecha < this.props.last.november) {
output.push(...[
'<div class="four wide field">',
'<label for="terreno">Valor Terreno al '+this.props.last.november.toString()+'</label>',
'<div class="ui left labeled input">',
'<div class="ui basic label">$</div>',
'<input type="number" id="terreno" />',
'</div>',
'</div>'
])
}
return output.join("\n")
},
propietarios: () => {
const output = []
this.props.propietarios.forEach(propietario => {
output.push(propietario.draw().propietario())
})
return output.join("\n")
},
ipc: () => {
if (!(this.props.fecha > this.props.facturas.terreno.fecha && this.props.facturas.terreno.valor === 0)) {
return ''
}
return [
'<div class="ui compact icon error message">',
'<i class="exclamation triangle icon"></i>',
'<div class="content">',
'IPC no disponible para este mes.',
'</div>',
'</div>'
].join("\n")
},
facturas: formatters => {
const output = []
this.props.facturas.facturas.forEach((factura, index) => {
output.push(factura.draw().factura({formatters}))
})
return output.join("\n")
}
}
}
add() {
return {
propietario: ({rut, nombre, proporcion, direccion, comuna}) => {
const index = this.props.propietarios.length + 1
const propietario = new Propietario({index, proporcion, rut, nombre, direccion, comuna})
this.props.propietarios.push(propietario)
this.add().factura(propietario)
return propietario
},
factura: propietario => {
const factura = new Factura({
id: 0,
venta: this.props,
index: propietario.props.index,
proporcion: propietario.props.proporcion,
emisor: {
rut: this.props.inmobiliaria.rut,
nombre: this.props.inmobiliaria.nombre,
direccion: this.props.inmobiliaria.direccion,
comuna: this.props.inmobiliaria.comuna
},
receptor: {
rut: '',
nombre: '',
direccion: '',
comuna: ''
},
unidades: [],
detalle: {
total: this.props.valor * this.props.uf.valor * propietario.props.proporcion,
base: 0,
terreno: 0,
neto: 0,
iva: 0,
bruto: 0,
descuento: 0,
},
total: {
neto: 0,
exento: 0,
iva: 0,
total: this.props.valor * this.props.uf.valor * propietario.props.proporcion
},
uf: this.props.uf
})
factura.update().venta(this)
this.props.facturas.facturas.push(factura)
}
}
}
remove() {
return {
propietario: index => {
if (index <= 0) {
return
}
const P1 = this.props.propietarios.reduce((sum, propietario) => sum + propietario.props.proporcion, 0)
const propietario = this.props.propietarios.splice(index, 1)[0]
const P2 = this.props.propietarios.reduce((sum, propietario) => sum + propietario.props.proporcion, 0)
document.querySelectorAll("[data-index='"+propietario.props.index+"']").forEach(field => {
field.remove()
})
this.remove().factura(index)
},
factura: index => {
this.props.facturas.splice(index, 1)
document.getElementById('facturas').querySelectorAll("[data-index='"+(index+1)+"']").forEach(factura => {
factura.remove()
})
}
}
}
save() {
return {
factura: ({index}) => {
const factura = this.props.facturas[index]
return factura.save()
}
}
}
}
</script>