diff --git a/app/resources/views/proyectos/brokers/contracts/show.blade.php b/app/resources/views/proyectos/brokers/contracts/show.blade.php
index d0d0d14..8222756 100644
--- a/app/resources/views/proyectos/brokers/contracts/show.blade.php
+++ b/app/resources/views/proyectos/brokers/contracts/show.blade.php
@@ -47,6 +47,136 @@
})
}
}
+ class GroupedTableHandler extends TableHandler {
+ promotions = {
+ names: new Set(),
+ values: []
+ }
+ process() {
+ return {
+ prices: prices => {
+ 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)
+ })
+ })
+ return promotions
+ },
+ promotions: () => {
+ return {
+ names: promotions => {
+ Object.keys(promotions).forEach(name => {
+ this.add().promotion().name(name)
+ })
+ },
+ values: ({promotions, formatters}) => {
+ const temp = Object.values(promotions)
+ if (temp.length > 0) {
+ const data = temp.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)
+ }
+ }
+ })
+ this.add().promotion().values({promotions: data, formatters})
+ return
+ }
+ this.promotions.values.push([])
+ }
+ }
+ }
+ }
+ }
+ add() {
+ return {
+ promotion: () => {
+ return {
+ name: name => {
+ this.promotions.names.add(name)
+ },
+ values: ({promotions, formatters}) => {
+ this.promotions.values.push(promotions.map(promotion => {
+ const amount_tooltip = [
+ `Min: ${promotion.type === 1 ? 'UF ' + formatters.ufs.format(promotion.amount.min) : formatters.percent.format(promotion.amount.min)}`,
+ `Max: ${promotion.type === 1 ? 'UF ' + formatters.ufs.format(promotion.amount.max) : formatters.percent.format(promotion.amount.max)}`,
+ `Desv: ${promotion.type === 1 ? 'UF ' + formatters.ufs.format(promotion.amount.desv) : formatters.percent.format(promotion.amount.desv)}`
+ ].join("\n").replaceAll(' ', ' ')
+ const final_tooltip = [
+ `Min: UF ${formatters.ufs.format(promotion.final.min)}`,
+ `Max: UF ${formatters.ufs.format(promotion.final.max)}`,
+ `Desv: UF ${formatters.ufs.format(promotion.final.desv)}`
+ ].join("\n").replaceAll(' ', ' ')
+ return {
+ name: promotion.name,
+ value: [
+ `
${promotion.type === 1 ? formatters.ufs.format(promotion.amount.mean) : formatters.percent.format(promotion.amount.mean)} | `,
+ `UF ${formatters.ufs.format(promotion.final.mean)} | `,
+ ].join("\n")
+ }
+ }))
+ }
+ }
+ }
+ }
+ }
+ build() {
+ return {
+ promotions: (table, tbody) => {
+ if (this.promotions.names.size > 0) {
+ const title = document.getElementById(this.ids.promotions)
+ title.innerHTML = this.promotions.names.size > 0 ? Array.from(this.promotions.names)[0] : ''
+ title.setAttribute('colspan', '2')
+ if (this.promotions.names.size > 1) {
+ const thead = table.querySelector('thead')
+ Array.from(this.promotions.names).slice(1).forEach(name => {
+ thead.insertAdjacentHTML('beforeend', `${name} | `)
+ })
+ }
+ const trs = tbody.querySelectorAll('tr')
+ this.promotions.values.forEach((row, i) => {
+ const tr = trs[i]
+ const td = tr.querySelector('td.promotions')
+ if (row.length === 0) {
+ td.setAttribute('colspan', 2 * this.promotions.names.size)
+ return
+ }
+ td.remove()
+ this.promotions.names.forEach(name => {
+ const index = row.findIndex(r => r.name === name)
+ if (index === -1) {
+ tr.insertAdjacentHTML('beforeend', ' | ')
+ return
+ }
+ tr.insertAdjacentHTML('beforeend', row[index].value)
+ })
+ })
+ }
+ }
+ }
+ }
+ }
@endprepend
diff --git a/app/resources/views/proyectos/brokers/contracts/show/linea.blade.php b/app/resources/views/proyectos/brokers/contracts/show/linea.blade.php
index 8ef7067..3536b89 100644
--- a/app/resources/views/proyectos/brokers/contracts/show/linea.blade.php
+++ b/app/resources/views/proyectos/brokers/contracts/show/linea.blade.php
@@ -8,7 +8,7 @@
Precio Base |
Comisión |
Precio Operador |
- Precio Final |
+ Promociones |
@@ -16,9 +16,10 @@
@push('page_scripts')
diff --git a/app/resources/views/proyectos/brokers/contracts/show/tipo.blade.php b/app/resources/views/proyectos/brokers/contracts/show/tipo.blade.php
index f94b9f9..c126d5b 100644
--- a/app/resources/views/proyectos/brokers/contracts/show/tipo.blade.php
+++ b/app/resources/views/proyectos/brokers/contracts/show/tipo.blade.php
@@ -14,15 +14,11 @@
@push('page_scripts')
@endpush
diff --git a/app/resources/views/proyectos/brokers/contracts/show/unidades.blade.php b/app/resources/views/proyectos/brokers/contracts/show/unidades.blade.php
index 528e594..fac66aa 100644
--- a/app/resources/views/proyectos/brokers/contracts/show/unidades.blade.php
+++ b/app/resources/views/proyectos/brokers/contracts/show/unidades.blade.php
@@ -17,7 +17,7 @@
Comisión |
Precio Operador |
UF/m² |
- Promociones |
+ Promociones |
@@ -48,109 +48,158 @@
'UF/m²',
'promociones',
]
+ set = {
+ table: false,
+ titles: false
+ }
+ table
constructor(commission) {
super(commission)
-
- const dto = structuredClone(datatables_defaults)
- dto.pageLength = 100
- dto.columnDefs = [
- {
- target: ['tipo_order', 'unidad_order', 'tipologia', 'piso', 'orientacion', 'metros'].map(column => this.columns.indexOf(column)),
- visible: false
- },
- {
- target: ['tipo'].map(column => this.columns.indexOf(column)),
- orderData: ['tipo_order'].map(column => this.columns.indexOf(column)),
- },
- {
- target: ['unidad'].map(column => this.columns.indexOf(column)),
- orderData: ['unidad_order'].map(column => this.columns.indexOf(column)),
- },
- {
- target: ['unidad', 'precio_base', 'commission', 'precio_operador', 'UF/m²', 'porcentaje', 'precio_final']
- .map(column => this.columns.indexOf(column)),
- className: 'dt-right right aligned'
- }
- ]
- dto.order = ['tipo_order', 'unidad_order'].map(column => [this.columns.indexOf(column), 'asc'])
- dto.language.searchBuilder = searchBuilder
- dto.layout = {
- top1Start: {
- searchBuilder: {
- columns: this.columns.filter(column => !['tipo_order', 'unidad_order'].includes(column))
- .map(column => this.columns.indexOf(column)),
+ }
+ setup() {
+ return {
+ titles: promotions_names => {
+ if (this.set.titles || promotions_names.size === 0) {
+ return
}
+
+ const nameArray = Array.from(promotions_names)
+
+ this.columns.pop()
+ this.columns.push(`${nameArray[0].toLowerCase().replaceAll(' ', '_')}.amount`)
+ this.columns.push(`${nameArray[0].toLowerCase().replaceAll(' ', '_')}.final`)
+
+ const table = document.getElementById(this.ids.units)
+ const thead = table.querySelector('thead')
+ const tr = thead.querySelector('tr')
+ const th = tr.querySelector('th#unit_promotions')
+ th.innerHTML = `${nameArray[0]}
Porcentaje`
+ tr.insertAdjacentHTML('beforeend', `${nameArray[0]} Precio Final | `)
+
+ if (promotions_names.size > 1) {
+ nameArray.slice(1).forEach(name => {
+ this.columns.push(`${name.toLowerCase().replaceAll(' ', '_')}.amount`)
+ this.columns.push(`${name.toLowerCase().replaceAll(' ', '_')}.final`)
+
+ tr.insertAdjacentHTML('beforeend', `${name} Porcentaje | `)
+ tr.insertAdjacentHTML('beforeend', `${name} Precio Final | `)
+ })
+ }
+ this.set.titles = true
},
- top1End: {
- buttons: [
+ table: () => {
+ if (typeof this.table !== 'undefined' || this.set.table) {
+ return
+ }
+
+ const dto = structuredClone(datatables_defaults)
+ dto.pageLength = 100
+ dto.columnDefs = [
{
- extend: 'excelHtml5',
- className: 'green',
- text: 'Exportar a Excel ',
- 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_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'
- },
- format: {
- body: (data, row, columnIdx, node) => {
- if (typeof data === 'string' && data.includes('(.*)<\/span>/, '$1')
- }
- if (['metros'].map(column => this.columns.indexOf(column)).includes(columnIdx)) {
- return data.replaceAll('.', '').replaceAll(',', '.')
- }
- return data
- }
- }
- },
+ target: ['tipo_order', 'unidad_order', 'tipologia', 'piso', 'orientacion', 'metros'].map(column => this.columns.indexOf(column)),
+ visible: false
+ },
+ {
+ target: ['tipo'].map(column => this.columns.indexOf(column)),
+ orderData: ['tipo_order'].map(column => this.columns.indexOf(column)),
+ },
+ {
+ target: ['unidad'].map(column => this.columns.indexOf(column)),
+ orderData: ['unidad_order'].map(column => this.columns.indexOf(column)),
+ },
+ {
+ target: ['unidad', 'precio_base', 'commission', 'precio_operador', 'UF/m²', 'porcentaje', 'precio_final']
+ .map(column => this.columns.indexOf(column)),
+ className: 'dt-right right aligned'
}
]
+ dto.order = ['tipo_order', 'unidad_order'].map(column => [this.columns.indexOf(column), 'asc'])
+ dto.language.searchBuilder = searchBuilder
+ const exportColumns = ['tipo', 'unidad', 'tipologia', 'piso', 'orientacion', 'metros_interior', 'metros_terraza', 'metros', 'metros_total', 'precio_operador', 'promociones']
+ if (typeof this.columns['promotions'] === 'undefined') {
+ exportColumns.pop()
+ this.columns.slice(this.columns.indexOf('UF/m²')).forEach(name => {
+ exportColumns.push(name)
+ })
+ }
+ dto.layout = {
+ top1Start: {
+ searchBuilder: {
+ columns: this.columns.filter(column => !['tipo_order', 'unidad_order'].includes(column))
+ .map(column => this.columns.indexOf(column)),
+ }
+ },
+ top1End: {
+ buttons: [
+ {
+ extend: 'excelHtml5',
+ className: 'green',
+ text: 'Exportar a Excel ',
+ title: 'Lista de Precios - {{ $contract->broker->name }} - {{ $contract->project->descripcion }} - {{ (new DateTime())->format('Y-m-d') }}',
+ download: 'open',
+ exportOptions: {
+ columns: exportColumns
+ .map(column => this.columns.indexOf(column)),
+ rows: (idx, data, node) => {
+ return data[this.columns.indexOf('estado')] === 'Libre'
+ },
+ format: {
+ body: (data, row, columnIdx, node) => {
+ if (typeof data === 'string' && data.includes('(.*)<\/span>/, '$1')
+ }
+ const formatColumns = ['metros', 'metros_interior', 'metros_terraza', 'metros_total']
+ if (this.set.titles) {
+ this.columns.filter(column => column.includes('.amount') || column.includes('.final')).forEach(name => {
+ formatColumns.push(name)
+ })
+ }
+ if (formatColumns.map(column => this.columns.indexOf(column)).includes(columnIdx)) {
+ return data.replaceAll('.', '').replaceAll(',', '.')
+ }
+ return data
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+
+ this.table = $(`#${this.ids.units}`).DataTable(dto)
+
+ this.set.table = true
}
}
- $(`#${this.ids.units}`).DataTable(dto)
}
draw({units, formatters}) {
- const table = $(`#${this.ids.units}`).DataTable()
- table.clear()
- const tableData = []
const prices = this.prices(units)
+
+ const promotions_names = new Set()
+ const tableData = []
units.forEach(unidad => {
const tipo = unidad.proyecto_tipo_unidad.tipo_unidad.descripcion
const price = prices.find(p => p.id === unidad.id)
- let subTable = false
+ let promotions = []
+ price.promotions.forEach(p => {
+ if (Object.hasOwn(promotions, p.name)) {
+ return
+ }
+ promotions[p.name] = {
+ name: p.name,
+ type: p.type,
+ amount: p.type === 1 ? 'UF ' + formatters.ufs.format(p.amount) : formatters.percent.format(p.amount),
+ final: `UF ${formatters.ufs.format(p.final)}`
+ }
+ })
- 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', [
- '',
- 'Nombre | ',
- 'Forma | ',
- 'Precio Final | ',
- '
'
- ].join("\n"))
- })
- const subTBody = document.createElement('tbody')
- price.promotions.forEach(p => {
- subTBody.insertAdjacentHTML('beforeend', [
- '',
- `${p.name} | `,
- `${p.type === 1 ? 'UF ' + formatters.ufs.format(p.amount) : formatters.percent.format(p.amount)} | `,
- `UF ${formatters.ufs.format(p.final)} | `,
- '
'
- ].join("\n"))
- })
- subTable.appendChild(subTHead).appendChild(subTBody)
- }
+ Object.keys(promotions).forEach(name => {
+ promotions_names.add(name)
+ })
+ const temp = Object.values(promotions)
- tableData.push([
+ const data = [
unidad.sold ? `Vendida` : 'Libre',
tipo.charAt(0).toUpperCase() + tipo.slice(1),
unidad.proyecto_tipo_unidad.tipo_unidad.orden,
@@ -167,9 +216,33 @@
formatters.percent.format(price.commission ?? 0),
'UF ' + formatters.ufs.format(price.broker ?? 0),
formatters.ufs.format(price.broker / unidad.proyecto_tipo_unidad.vendible),
- subTable ? subTable.outerHTML : 'UF ' + formatters.ufs.format(price.broker ?? 0),
- ])
+ ''
+ ]
+
+ if (temp.length > 0) {
+ data.pop()
+ temp.forEach((p, i) => {
+ data.push(p.amount)
+ data.push(p.final)
+ })
+ } else {
+ if (promotions_names.size > 0) {
+ Array.from(promotions_names).forEach(name => {
+ data.push('')
+ data.push('')
+ })
+ }
+ }
+
+ tableData.push(data)
})
+
+ this.setup().titles(promotions_names)
+ this.setup().table()
+
+ const table = this.table
+ table.clear()
+
table.rows.add(tableData)
table.draw()
}