Listado de promociones

This commit is contained in:
Juan Pablo Vial
2025-04-22 18:34:23 -04:00
parent 90b05ca25c
commit 966b341b65
4 changed files with 210 additions and 55 deletions

View File

@ -18,30 +18,33 @@
}
draw() {}
prices(units) {
const prices = []
units.forEach(unit => {
let price = unit.valor ?? (unit.precio?.valor ?? 0)
let amount = 1
let diff = 0
unit.promotions?.forEach(promotion => {
return units.map(unit => {
let price = unit.valor ?? (unit.precio?.valor ?? 0)
const broker = price / (1 - this.commission)
const promotions = unit.promotions?.map(promotion => {
if (promotion.type === 1) {
diff += promotion.amount
return
return {
name: promotion.description,
type: promotion.type,
amount: promotion.amount,
final: broker + promotion.amount
}
}
amount /= 1/(1 - promotion.amount)
})
amount = 1 - amount
price += diff
prices.push({
return {
name: promotion.description,
type: promotion.type,
amount: promotion.amount,
final: broker / (1 - promotion.amount)
}
}) ?? []
return {
id: unit.id,
base: price,
commission: this.commission,
broker: price / (1 - this.commission),
amount,
final: price / (1 - this.commission) / (1 - amount)
})
broker,
promotions
}
})
return prices
}
}
</script>

View File

@ -7,7 +7,6 @@
<th class="center aligned">Cantidad</th>
<th class="right aligned" style="text-decoration: overline">Precio Base</th>
<th class="right aligned" style="text-decoration: overline">Comisión</th>
<th class="right aligned" style="text-decoration: overline">Porcentaje</th>
<th class="right aligned" style="text-decoration: overline">Precio Operador</th>
<th class="right aligned" style="text-decoration: overline">Precio Final</th>
</tr>
@ -63,16 +62,78 @@
`Max: ${formatters.ufs.format(Math.max(...prices.map(p => p.broker)))}`,
`Desv: ${formatters.ufs.format(Stat.standardDeviation(prices.map(p => p.broker)))}`
].join("\n").replaceAll(' ', '&nbsp;')
const amount_tooltip = [
`Min: ${formatters.percent.format(Math.min(...prices.map(p => p.amount)))}`,
`Max: ${formatters.percent.format(Math.max(...prices.map(p => p.amount)))}`,
`Desv: ${formatters.percent.format(Stat.standardDeviation(prices.map(p => p.amount)))}`
].join("\n").replaceAll(' ', '&nbsp;')
const final_tooltip = [
`Min: UF ${formatters.ufs.format(Math.min(...prices.map(p => p.final)))}`,
`Max: UF ${formatters.ufs.format(Math.max(...prices.map(p => p.final)))}`,
`Desv: UF ${formatters.ufs.format(Stat.standardDeviation(prices.map(p => p.final)))}`
].join("\n").replaceAll(' ', '&nbsp;')
let promotions = {}
prices.map(price => price.promotions).forEach(promotionArray => {
promotionArray.forEach(p => {
if (!Object.hasOwn(promotions, p.name)) {
promotions[p.name] = {
name: p.name,
type: p.type,
amount: [],
final: []
}
}
promotions[p.name].amount.push(p.amount)
promotions[p.name].final.push(p.final)
})
})
promotions = Object.values(promotions)
let subTable = false
if (promotions.length > 0) {
promotions = promotions.map(p => {
return {
name: p.name,
type: p.type,
amount: {
min: Math.min(...p.amount),
max: Math.max(...p.amount),
desv: Stat.standardDeviation(p.amount),
mean: Stat.mean(p.amount)
},
final: {
min: Math.min(...p.final),
max: Math.max(...p.final),
desv: Stat.standardDeviation(p.final),
mean: Stat.mean(p.final)
}
}
})
subTable = document.createElement('table')
subTable.className = 'ui table'
const subTHead = document.createElement('thead')
promotions.forEach(p => {
subTHead.insertAdjacentHTML('beforeend', [
'<tr>',
'<th class="center aligned">Nombre</th>',
'<th class="center aligned">Forma</th>',
'<th class="right aligned">Precio Final</th>',
'</tr>'
].join("\n"))
})
const subTbody = document.createElement('tbody')
promotions.forEach(p => {
const amount_tooltip = [
`Min: ${p.type === 1 ? 'UF ' + formatters.ufs.format(p.amount.min) : formatters.percent.format(p.amount.min)}`,
`Max: ${p.type === 1 ? 'UF ' + formatters.ufs.format(p.amount.max) : formatters.percent.format(p.amount.max)}`,
`Desv: ${p.type === 1 ? 'UF ' + formatters.ufs.format(p.amount.desv) : formatters.percent.format(p.amount.desv)}`
].join("\n").replaceAll(' ', '&nbsp;')
const final_tooltip = [
`Min: UF ${formatters.ufs.format(p.final.min)}`,
`Max: UF ${formatters.ufs.format(p.final.max)}`,
`Desv: UF ${formatters.ufs.format(p.final.desv)}`
].join("\n").replaceAll(' ', '&nbsp;')
subTbody.insertAdjacentHTML('beforeend', [
'<tr>',
`<td class="center aligned">${p.name}</td>`,
`<td class="right aligned"><span data-tooltip="${amount_tooltip}" data-position="right center" data-variation="wide multiline">${p.type === 1 ? 'UF ' + formatters.ufs.format(p.amount.mean) : formatters.percent.format(p.amount.mean)}</td>`,
`<td class="right aligned"><span data-tooltip="${final_tooltip}" data-position="right center" data-variation="wide multiline">UF ${formatters.ufs.format(p.final.mean)}</td></td>`,
'</tr>'
].join("\n"))
})
subTable.appendChild(subTHead).appendChild(subTbody)
}
tbody.innerHTML += [
`<tr>`,
@ -83,8 +144,7 @@
`<td class="right aligned"><span data-tooltip="${base_tooltip}" data-position="right center" data-variation="wide multiline">UF ${formatters.ufs.format(Stat.mean(prices.map(p => p.base)))}</span></td>`,
`<td class="right aligned"><span data-tooltip="${commission_tooltip}" data-position="right center" data-variation="wide multiline">${formatters.percent.format(Stat.mean(prices.map(p => p.commission)))}</span></td>`,
`<td class="right aligned"><span data-tooltip="${broker_tooltip}" data-position="right center" data-variation="wide multiline">UF ${formatters.ufs.format(Stat.mean(prices.map(p => p.broker)))}</span></td>`,
`<td class="right aligned"><span data-tooltip="${amount_tooltip}" data-position="right center" data-variation="wide multiline">${formatters.percent.format(Stat.mean(prices.map(p => p.amount)))}</span></td>`,
`<td class="right aligned"><span data-tooltip="${final_tooltip}" data-position="right center" data-variation="wide multiline">UF ${formatters.ufs.format(Stat.mean(prices.map(p => p.final)))}</span></td>`,
`<td class="right aligned">${subTable ? subTable.outerHTML : `UF ${formatters.ufs.format(Stat.mean(prices.map(p => p.broker)))}`}</td>`,
`</tr>`
].join("\n")
})

View File

@ -6,8 +6,7 @@
<th class="right aligned" style="text-decoration: overline">Precio Base</th>
<th class="right aligned" style="text-decoration: overline">Comisión</th>
<th class="right aligned" style="text-decoration: overline">Precio Operador</th>
<th class="right aligned" style="text-decoration: overline">Porcentaje</th>
<th class="right aligned" style="text-decoration: overline">Precio Final</th>
<th class="right aligned" style="text-decoration: overline">Promociones</th>
</tr>
</thead>
<tbody></tbody>
@ -46,16 +45,77 @@
`Max: ${formatters.ufs.format(Math.max(...prices.map(p => p.broker)))}`,
`Desv: ${formatters.ufs.format(Stat.standardDeviation(prices.map(p => p.broker)))}`
].join("\n").replaceAll(' ', '&nbsp;')
const amount_tooltip = [
`Min: ${formatters.percent.format(Math.min(...prices.map(p => p.amount)))}`,
`Max: ${formatters.percent.format(Math.max(...prices.map(p => p.amount)))}`,
`Desv: ${formatters.percent.format(Stat.standardDeviation(prices.map(p => p.amount)))}`
].join("\n").replaceAll(' ', '&nbsp;')
const final_tooltip = [
`Min: UF ${formatters.ufs.format(Math.min(...prices.map(p => p.final)))}`,
`Max: UF ${formatters.ufs.format(Math.max(...prices.map(p => p.final)))}`,
`Desv: UF ${formatters.ufs.format(Stat.standardDeviation(prices.map(p => p.final)))}`
].join("\n").replaceAll(' ', '&nbsp;')
let promotions = {}
prices.map(price => price.promotions).forEach(promotionArray => {
promotionArray.forEach(p => {
if (!Object.hasOwn(promotions, p.name)) {
promotions[p.name] = {
name: p.name,
type: p.type,
amount: [],
final: []
}
}
promotions[p.name].amount.push(p.amount)
promotions[p.name].final.push(p.final)
})
})
promotions = Object.values(promotions)
let subTable = false
if (promotions.length > 0) {
promotions = promotions.map(p => {
return {
name: p.name,
type: p.type,
amount: {
min: Math.min(...p.amount),
max: Math.max(...p.amount),
desv: Stat.standardDeviation(p.amount),
mean: Stat.mean(p.amount)
},
final: {
min: Math.min(...p.final),
max: Math.max(...p.final),
desv: Stat.standardDeviation(p.final),
mean: Stat.mean(p.final)
}
}
})
subTable = document.createElement('table')
subTable.className = 'ui table'
const subTHead = document.createElement('thead')
promotions.forEach(p => {
subTHead.insertAdjacentHTML('beforeend', [
'<tr>',
'<th class="center aligned">Nombre</th>',
'<th class="center aligned">Forma</th>',
'<th class="right aligned">Precio Final</th>',
'</tr>'
].join("\n"))
})
const subTbody = document.createElement('tbody')
promotions.forEach(p => {
const amount_tooltip = [
`Min: ${p.type === 1 ? 'UF ' + formatters.ufs.format(p.amount.min) : formatters.percent.format(p.amount.min)}`,
`Max: ${p.type === 1 ? 'UF ' + formatters.ufs.format(p.amount.max) : formatters.percent.format(p.amount.max)}`,
`Desv: ${p.type === 1 ? 'UF ' + formatters.ufs.format(p.amount.desv) : formatters.percent.format(p.amount.desv)}`
].join("\n").replaceAll(' ', '&nbsp;')
const final_tooltip = [
`Min: UF ${formatters.ufs.format(p.final.min)}`,
`Max: UF ${formatters.ufs.format(p.final.max)}`,
`Desv: UF ${formatters.ufs.format(p.final.desv)}`
].join("\n").replaceAll(' ', '&nbsp;')
subTbody.insertAdjacentHTML('beforeend', [
'<tr>',
`<td class="center aligned">${p.name}</td>`,
`<td class="right aligned"><span data-tooltip="${amount_tooltip}" data-position="right center" data-variation="wide multiline">${p.type === 1 ? formatters.ufs.format(p.amount.mean) : formatters.percent.format(p.amount.mean)}</td>`,
`<td class="right aligned"><span data-tooltip="${final_tooltip}" data-position="right center" data-variation="wide multiline">UF ${formatters.ufs.format(p.final.mean)}</td></td>`,
'</tr>'
].join("\n"))
})
subTable.appendChild(subTHead).appendChild(subTbody)
}
tbody.innerHTML += [
`<tr>`,
@ -64,8 +124,7 @@
`<td class="right aligned"><span data-tooltip="${base_tooltip}" data-position="right center" data-variation="wide multiline">UF ${formatters.ufs.format(Stat.mean(prices.map(p => p.base)))}</span></td>`,
`<td class="right aligned"><span data-tooltip="${commission_tooltip}" data-position="right center" data-variation="wide multiline">${formatters.percent.format(Stat.mean(prices.map(p => p.commission)))}</span></td>`,
`<td class="right aligned"><span data-tooltip="${broker_tooltip}" data-position="right center" data-variation="wide multiline">UF ${formatters.ufs.format(Stat.mean(prices.map(p => p.broker)))}</span></td>`,
`<td class="right aligned"><span data-tooltip="${amount_tooltip}" data-position="right center" data-variation="wide multiline">${formatters.percent.format(Stat.mean(prices.map(p => p.amount)))}</span></td>`,
`<td class="right aligned"><span data-tooltip="${final_tooltip}" data-position="right center" data-variation="wide multiline">UF ${formatters.ufs.format(Stat.mean(prices.map(p => p.final)))}</span></td>`,
`<td class="right aligned">${subTable ? subTable.outerHTML : `UF ${formatters.ufs.format(Stat.mean(prices.map(p => p.broker)))}`}</td>`,
`</tr>`
].join("\n")
})

View File

@ -9,13 +9,15 @@
<th>Tipología</th>
<th>Piso</th>
<th>Orientación</th>
<th>m&#0178;</th>
<th>m&#0178; Interior</th>
<th>m&#0178; Terraza</th>
<th>m&#0178; Vendibles</th>
<th>m&#0178; Total</th>
<th class="right aligned">Precio Base</th>
<th class="right aligned">Comisión</th>
<th class="right aligned">Precio Operador</th>
<th class="right aligned">UF/</th>
<th class="right aligned">Porcentaje</th>
<th class="right aligned">Precio Final</th>
<th class="right aligned">Promociones</th>
</tr>
</thead>
<tbody></tbody>
@ -36,13 +38,15 @@
'tipologia',
'piso',
'orientacion',
'metros_interior',
'metros_terraza',
'metros',
'metros_total',
'precio_base',
'commission',
'precio_operador',
'UF/m²',
'porcentaje',
'precio_final',
'promociones',
]
constructor(commission) {
super(commission)
@ -86,7 +90,7 @@
title: 'Lista de Precios - {{ $contract->broker->name }} - {{ $contract->project->descripcion }} - {{ (new DateTime())->format('Y-m-d') }}',
download: 'open',
exportOptions: {
columns: ['tipo', 'unidad', 'tipologia', 'piso', 'orientacion', 'metros', 'precio_operador', 'porcentaje', 'precio_final']
columns: ['tipo', 'unidad', 'tipologia', 'piso', 'orientacion', 'metros_interior', 'metros_terraza', 'metros', 'metros_total', 'precio_operador', 'promociones']
.map(column => this.columns.indexOf(column)),
rows: (idx, data, node) => {
return data[this.columns.indexOf('estado')] === 'Libre'
@ -117,6 +121,35 @@
units.forEach(unidad => {
const tipo = unidad.proyecto_tipo_unidad.tipo_unidad.descripcion
const price = prices.find(p => p.id === unidad.id)
let subTable = false
if (price.promotions.length > 0) {
subTable = document.createElement('table')
subTable.className = 'ui table'
const subTHead = document.createElement('thead')
price.promotions.forEach(p => {
subTHead.insertAdjacentHTML('beforeend', [
'<tr>',
'<th class="center aligned">Nombre</th>',
'<th class="center aligned">Forma</th>',
'<th class="right aligned">Precio Final</th>',
'</tr>'
].join("\n"))
})
const subTBody = document.createElement('tbody')
price.promotions.forEach(p => {
subTBody.insertAdjacentHTML('beforeend', [
'<tr>',
`<td class="center aligned">${p.name}</td>`,
`<td class="right aligned">${p.type === 1 ? 'UF ' + formatters.ufs.format(p.amount) : formatters.percent.format(p.amount)}</td>`,
`<td class="right aligned">UF ${formatters.ufs.format(p.final)}</td>`,
'</tr>'
].join("\n"))
})
subTable.appendChild(subTHead).appendChild(subTBody)
}
tableData.push([
unidad.sold ? `<span class="ui yellow text">Vendida</span>` : 'Libre',
tipo.charAt(0).toUpperCase() + tipo.slice(1),
@ -126,15 +159,15 @@
unidad.proyecto_tipo_unidad.tipologia,
unidad.piso,
unidad.orientacion,
formatters.ufs.format(unidad.proyecto_tipo_unidad.util) ?? 0,
formatters.ufs.format(unidad.proyecto_tipo_unidad.terraza) ?? 0,
formatters.ufs.format(unidad.proyecto_tipo_unidad.vendible) ?? 0,
formatters.ufs.format(unidad.proyecto_tipo_unidad.superficie) ?? 0,
'UF ' + formatters.ufs.format(price.base ?? 0),
formatters.percent.format(price.commission ?? 0),
'UF ' + formatters.ufs.format(price.broker ?? 0),
formatters.ufs.format(price.broker / unidad.proyecto_tipo_unidad.vendible),
formatters.percent.format(price.amount ?? 0),
'UF ' + formatters.ufs.format(price.final ?? 0),
unidad.promotion?.start_date ?? '',
unidad.promotion?.end_date ?? '',
subTable ? subTable.outerHTML : 'UF ' + formatters.ufs.format(price.broker ?? 0),
])
})
table.rows.add(tableData)