Facturacion

This commit is contained in:
Juan Pablo Vial
2024-04-19 23:19:35 -04:00
parent 9388dc17fc
commit d2511901ec
7 changed files with 126 additions and 43 deletions

View File

@ -33,6 +33,7 @@
</div>--}} </div>--}}
{{--<a class="item" href="{{$urls->base}}/ventas/precios/importar">Importar Precios</a>--}} {{--<a class="item" href="{{$urls->base}}/ventas/precios/importar">Importar Precios</a>--}}
{{--<a class="item" href="{{$urls->base}}/ventas/cierres/evaluar">Evaluar Cierre</a>--}} {{--<a class="item" href="{{$urls->base}}/ventas/cierres/evaluar">Evaluar Cierre</a>--}}
<a class="item" href="{{$urls->base}}/ventas/facturacion">Facturación</a>
<a class="item" href="{{$urls->base}}/ventas/add"> <a class="item" href="{{$urls->base}}/ventas/add">
Nueva Venta Nueva Venta
<i class="plus icon"></i> <i class="plus icon"></i>

View File

@ -24,7 +24,7 @@
@endforeach @endforeach
</div> </div>
</div> </div>
<table class="ui table" id="data"></table> <div id="data"></div>
@endsection @endsection
@include('layout.head.styles.datatables') @include('layout.head.styles.datatables')
@ -226,49 +226,104 @@
ids: {}, ids: {},
selected: 0, selected: 0,
data: JSON.parse('{!! json_encode($proyectos) !!}'), data: JSON.parse('{!! json_encode($proyectos) !!}'),
sent: false,
ufs: {},
ipcs: {},
table: null, table: null,
get: function() { get: function() {
return { return {
ventas: () => { ventas: () => {
const url = '{{$urls->api}}/ventas/facturacion/proyecto/' + this.selected if (this.sent) {
return fetchAPI(url).then(response => { return
if (response.ok) {
return response.json()
} }
this.sent = true
const url = '{{$urls->api}}/ventas/facturacion/proyecto/' + this.selected
this.draw().loading()
return fetchAPI(url).then(response => {
if (!response) {
return
}
return response.json()
}).then(json => { }).then(json => {
const idx = this.data.findIndex(proyecto => proyecto.id === json.proyecto_id) const idx = this.data.findIndex(proyecto => proyecto.id === json.proyecto_id)
const fecha_terreno = new Date(this.data[idx].terreno.date) const fecha_terreno = (typeof this.data[idx].terreno.date === 'undefined') ? new Date() : new Date(this.data[idx].terreno.date)
this.data[idx]['ventas'] = [] this.data[idx]['ventas'] = []
const ventas = [] const ventas = []
const unidadesQueue = []
const ufQueue = {}
const ipcQueue = {}
const chunkSize = 100
const url = '{{$urls->api}}/ventas/get'
for (let i = 0; i < json.ventas.length; i += chunkSize) {
const chunk = json.ventas.slice(i, i + chunkSize).map(venta => venta.id)
const body = new FormData()
body.set('ventas', chunk)
const promise = fetchAPI(url, {method: 'post', body}).then(response => {
if (!response) {
return response
}
return response.json().then(json => {
json.ventas.forEach(venta => { json.ventas.forEach(venta => {
const data = { const data = {
id: venta.id, id: venta.id,
precio: venta.valor, precio: venta.valor,
fecha: new Date(venta.fecha), fecha: new Date(venta.fecha),
escritura: null escritura: new Date(venta.fecha)
} }
if (['escriturando'].includes(venta.current_estado.tipo_estado_venta.descripcion)) { if (['escriturando'].includes(venta.current_estado.tipo_estado_venta.descripcion)) {
data.escritura = new Date(venta.current_estado.fecha) data.escritura = new Date(venta.current_estado.fecha)
} }
const v = new Venta(data) const v = new Venta(data)
const promises = []
if (v.escritura !== null) { if (v.escritura !== null) {
promises.push(money.get().uf(v.escritura).then(uf => { const dateString = v.escritura.toString()
v.uf = uf if (!Object.hasOwn(ufQueue, dateString)) {
})) ufQueue[dateString] = []
promises.push(money.get().ipc(v.escritura, fecha_terreno).then(ipc => {
v.ipc = ipc
}))
} }
promises.push(v.get().unidades()) ufQueue[dateString].push(v.id)
const promise = Promise.all(promises).then(() => { if (!Object.hasOwn(ipcQueue, dateString)) {
ipcQueue[dateString] = []
}
ipcQueue[dateString].push(v.id)
}
unidadesQueue.push(v.id)
this.data[idx].ventas.push(v) this.data[idx].ventas.push(v)
})
});
}) })
ventas.push(promise) ventas.push(promise)
}) }
Promise.all(ventas).then(() => { Promise.all(ventas).then(() => {
this.data[idx].ventas.sort((a, b) => parseInt(a.principal.descripcion) - parseInt(b.principal.descripcion)) const promises = []
Object.entries(ufQueue).forEach(([dateString, ventas]) => {
const date = new Date(dateString)
promises.push(money.get().uf(date).then(uf => {
ventas.forEach(id => {
const vidx = this.data[idx].ventas.findIndex(venta => venta.id === id)
this.data[idx].ventas[vidx].uf = uf
})
}))
})
Object.entries(ipcQueue).forEach(([dateString, ventas]) => {
const date = new Date(dateString)
promises.push(money.get().ipc(date, fecha_terreno).then(ipc => {
ventas.forEach(id => {
const vidx = this.data[idx].ventas.findIndex(venta => venta.id === id)
this.data[idx].ventas[vidx].ipc = ipc
})
}))
})
for (let i = 0; i < unidadesQueue.length; i += chunkSize) {
const chunk = unidadesQueue.slice(i, i + chunkSize)
chunk.forEach(id => {
const vidx = this.data[idx].ventas.findIndex(venta => venta.id === id)
promises.push(this.data[idx].ventas[vidx].get().unidades())
})
}
Promise.all(promises).then(() => {
this.draw().ventas(idx) this.draw().ventas(idx)
this.sent = false
})
}) })
}) })
} }
@ -277,23 +332,37 @@
draw: function() { draw: function() {
return { return {
proyectos: () => { proyectos: () => {
$(this.ids.title).html('Proyectos')
if (this.table !== null) { if (this.table !== null) {
this.table.clear() this.table.clear()
this.table.destroy()
$(this.ids.data).html('')
} }
$(this.ids.data).hide() $(this.ids.data).hide()
$(this.ids.proyectos).find('.item').css('cursor', 'pointer')
$(this.ids.proyectos).show() $(this.ids.proyectos).show()
}, },
ventas: proyecto_idx => { ventas: proyecto_idx => {
const table = $(this.ids.data) $(this.ids.title).html(this.data[proyecto_idx].descripcion)
const parent = $(this.ids.data)
if (this.table !== null) { if (this.table !== null) {
this.table.clear().destroy() this.table.clear()
this.table.destroy()
this.table = null
parent.html('')
} }
const table = $('<table></table>').addClass('ui table')
table.append(this.draw().thead()) table.append(this.draw().thead())
table.append(this.draw().tbody(proyecto_idx)) table.append(this.draw().tbody(proyecto_idx))
table.show() parent.show()
parent.html(table)
$(this.ids.proyectos).hide() $(this.ids.proyectos).hide()
if (this.table === null) { if (this.table === null) {
this.table = table.DataTable() this.table = table.DataTable({
orders: [
[0, 'asc']
]
})
} }
}, },
thead: () => { thead: () => {
@ -331,6 +400,9 @@
venta.draw({tbody, valor_terreno: this.data[proyecto_idx].terreno.valor}) venta.draw({tbody, valor_terreno: this.data[proyecto_idx].terreno.valor})
}) })
return tbody return tbody
},
loading: () => {
$(this.ids.proyectos).find('.item').css('cursor', 'wait')
} }
} }
}, },
@ -369,6 +441,7 @@
} }
$(document).ready(() => { $(document).ready(() => {
proyectos.setup({ids: { proyectos.setup({ids: {
title: '#list_title',
proyectos: '#proyectos', proyectos: '#proyectos',
data: '#data', data: '#data',
buttons: { buttons: {

View File

@ -97,8 +97,8 @@
</div> </div>
<div id="propietarios" class="fields"></div> <div id="propietarios" class="fields"></div>
</form> </form>
@if ($venta->currentEstado()->fecha->sub(new DateInterval('P1M')) > $venta->proyecto()->terreno->fecha @if ($venta->currentEstado()->fecha->sub(new DateInterval('P1M')) > $terreno?->fecha
and $IPC->get($venta->proyecto()->terreno->fecha, $venta->currentEstado()->fecha->sub(new DateInterval('P1M'))) === 0.0) and ($terreno?->valor ?? 0) === 0.0)
<div class="ui compact icon error message"> <div class="ui compact icon error message">
<i class="exclamation triangle icon"></i> <i class="exclamation triangle icon"></i>
<div class="content"> <div class="content">
@ -409,8 +409,7 @@
}, },
proyecto: { proyecto: {
direccion: '{{$venta->proyecto()->direccion()->simple()}}', direccion: '{{$venta->proyecto()->direccion()->simple()}}',
terreno: {{(isset($terreno->fecha) and $terreno->fecha >= $lastDic) ? terreno: {{$terreno?->valor ?? 0}}
$IPC->readjust($terreno->valor, $terreno->fecha, $venta->currentEstado()->fecha) : 0}},
}, },
estadoVenta: { estadoVenta: {
fecha: new Date('{{$venta->currentEstado()->fecha->format('Y-m-d')}}') fecha: new Date('{{$venta->currentEstado()->fecha->format('Y-m-d')}}')
@ -758,7 +757,7 @@
this.update().unidades() this.update().unidades()
this.update().propietarios($(count_propietarios_id).val()) this.update().propietarios($(count_propietarios_id).val())
this.draw().propietarios() this.draw().propietarios()
this.unidades.forEach((unidad, idx) => { this.propietarios.forEach((unidad, idx) => {
this.update().proporciones(idx) this.update().proporciones(idx)
}) })
this.update().facturas() this.update().facturas()

View File

@ -9,9 +9,12 @@ use Incoviba\Service;
class Facturacion class Facturacion
{ {
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, View $view, public function __invoke(ServerRequestInterface $request, ResponseInterface $response, View $view,
Service\Proyecto $proyectoService): ResponseInterface Service\Proyecto $proyectoService, Service\Proyecto\Terreno $terrenoService): ResponseInterface
{ {
$proyectos = $proyectoService->getEscriturando(); $proyectos = $proyectoService->getEscriturando();
foreach ($proyectos as &$proyecto) {
$proyecto->terreno = $terrenoService->valor($proyecto->id) ?? $proyecto->terreno;
}
return $view->render($response, 'ventas.facturacion', compact('proyectos')); return $view->render($response, 'ventas.facturacion', compact('proyectos'));
} }
public function show(ServerRequestInterface $request, ResponseInterface $response, View $view, public function show(ServerRequestInterface $request, ResponseInterface $response, View $view,

View File

@ -171,7 +171,7 @@ class Venta extends Ideal\Repository
->joined('JOIN proyecto_tipo_unidad ptu ON ptu.id = unidad.pt') ->joined('JOIN proyecto_tipo_unidad ptu ON ptu.id = unidad.pt')
->joined('JOIN (SELECT ev1.* FROM estado_venta ev1 JOIN (SELECT MAX(id) AS id, venta FROM estado_venta GROUP BY venta) ev0 ON ev0.id = ev1.id) ev ON ev.venta = a.id') ->joined('JOIN (SELECT ev1.* FROM estado_venta ev1 JOIN (SELECT MAX(id) AS id, venta FROM estado_venta GROUP BY venta) ev0 ON ev0.id = ev1.id) ev ON ev.venta = a.id')
->joined('JOIN tipo_estado_venta tev ON tev.id = ev.estado') ->joined('JOIN tipo_estado_venta tev ON tev.id = ev.estado')
->where('ptu.proyecto = ? AND tev.activa') ->where('ptu.proyecto = ? AND tev.activa = 1')
->group('a.id'); ->group('a.id');
return $this->fetchIds($query, [$proyecto_id]); return $this->fetchIds($query, [$proyecto_id]);
} }
@ -185,7 +185,7 @@ class Venta extends Ideal\Repository
->joined('JOIN `proyecto_tipo_unidad` ptu ON ptu.`id` = `unidad`.`pt`') ->joined('JOIN `proyecto_tipo_unidad` ptu ON ptu.`id` = `unidad`.`pt`')
->joined("JOIN (SELECT e1.* FROM `estado_venta` e1 JOIN (SELECT MAX(`id`) AS 'id', `venta` FROM `estado_venta` GROUP BY `venta`) e0 ON e0.`id` = e1.`id`) ev ON ev.`venta` = a.`id`") ->joined("JOIN (SELECT e1.* FROM `estado_venta` e1 JOIN (SELECT MAX(`id`) AS 'id', `venta` FROM `estado_venta` GROUP BY `venta`) e0 ON e0.`id` = e1.`id`) ev ON ev.`venta` = a.`id`")
->joined('JOIN `tipo_estado_venta` tev ON tev.`id` = ev.`estado`') ->joined('JOIN `tipo_estado_venta` tev ON tev.`id` = ev.`estado`')
->where('ptu.`proyecto` = ? AND tev.`activa`') ->where('ptu.`proyecto` = ? AND tev.`activa` = 1')
->group('a.id'); ->group('a.id');
return $this->fetchMany($query, [$proyecto_id]); return $this->fetchMany($query, [$proyecto_id]);
} }

View File

@ -31,8 +31,11 @@ class Terreno extends Ideal\Service
try { try {
return $this->getValorContable($proyecto, $lastDecember); return $this->getValorContable($proyecto, $lastDecember);
} catch (Implement\Exception\EmptyResponse) {} } catch (Implement\Exception\EmptyResponse) {}
if ($proyecto->terreno->fecha === null) {
return null;
}
if ($proyecto->terreno->fecha->getTimestamp() > 0) { if ($proyecto->terreno->fecha->getTimestamp() > 0) {
return $this->getValorReajustado($proyecto, $lastDecember); return $this->getValorReajustado($proyecto);
} }
$terreno = $proyecto->terreno; $terreno = $proyecto->terreno;
} catch (Implement\Exception\EmptyResult) {} } catch (Implement\Exception\EmptyResult) {}

View File

@ -46,6 +46,10 @@ class Venta extends Service
$ventas = $this->ventaRepository->fetchActivaByProyecto($proyecto_id); $ventas = $this->ventaRepository->fetchActivaByProyecto($proyecto_id);
return array_map([$this, 'process'], $ventas); return array_map([$this, 'process'], $ventas);
} }
public function getIdsByProyecto(int $proyecto_id): array
{
return $this->ventaRepository->fetchIdsByProyecto($proyecto_id);
}
public function getByProyectoAndUnidad(string $proyecto_nombre, int $unidad_descripcion): Model\Venta public function getByProyectoAndUnidad(string $proyecto_nombre, int $unidad_descripcion): Model\Venta
{ {
$venta = $this->ventaRepository->fetchByProyectoAndUnidad($proyecto_nombre, $unidad_descripcion); $venta = $this->ventaRepository->fetchByProyectoAndUnidad($proyecto_nombre, $unidad_descripcion);