diff --git a/app/resources/routes/03_proyectos.php b/app/resources/routes/03_proyectos.php index 4f31a20..7c734ea 100644 --- a/app/resources/routes/03_proyectos.php +++ b/app/resources/routes/03_proyectos.php @@ -5,3 +5,6 @@ $app->group('/proyectos', function($app) { $app->get('/unidades[/]', [Proyectos::class, 'unidades']); $app->get('[/]', Proyectos::class); }); +$app->group('/proyecto/{proyecto_id}', function($app) { + $app->get('[/]', [Proyectos::class, 'show']); +}); diff --git a/app/resources/routes/api/proyectos.php b/app/resources/routes/api/proyectos.php index 784b0d1..3d8cca7 100644 --- a/app/resources/routes/api/proyectos.php +++ b/app/resources/routes/api/proyectos.php @@ -10,4 +10,11 @@ $app->group('/proyecto/{proyecto_id}', function($app) { $app->get('/estado[/]', [Proyectos\EstadosProyectos::class, 'currentByProyecto']); $app->get('/inicio[/]', [Proyectos\EstadosProyectos::class, 'firstByProyecto']); $app->get('/recepcion[/]', [Proyectos\EstadosProyectos::class, 'recepcionByProyecto']); + $app->group('/superficies', function($app) { + $app->get('/vendible[/]', [Proyectos::class, 'superficies']); + }); + $app->group('/unidades', function($app) { + $app->get('/disponibles[/]', [Proyectos::class, 'disponibles']); + $app->get('[/]', [Proyectos::class, 'unidades']); + }); }); diff --git a/app/resources/routes/api/ventas/precios.php b/app/resources/routes/api/ventas/precios.php index 2f04166..6546f48 100644 --- a/app/resources/routes/api/ventas/precios.php +++ b/app/resources/routes/api/ventas/precios.php @@ -1,5 +1,5 @@ group('/precios', function($app) { $app->post('[/]', [Precios::class, 'proyecto']); diff --git a/app/resources/views/proyectos/list.blade.php b/app/resources/views/proyectos/list.blade.php index 3dbdb83..98fd8c2 100644 --- a/app/resources/views/proyectos/list.blade.php +++ b/app/resources/views/proyectos/list.blade.php @@ -17,7 +17,11 @@ @foreach ($proyectos as $proyecto) - {{$proyecto->descripcion}} + + + {{$proyecto->descripcion}} + + {{$proyecto->inmobiliaria()->nombreCompleto()}} diff --git a/app/resources/views/proyectos/show.blade.php b/app/resources/views/proyectos/show.blade.php new file mode 100644 index 0000000..88986fd --- /dev/null +++ b/app/resources/views/proyectos/show.blade.php @@ -0,0 +1,470 @@ +@extends('layout.base') + +@section('page_title') + Proyecto {{$proyecto->descripcion}} +@endsection + +@section('page_content') +
+

+ Proyecto {{$proyecto->descripcion}} - {{$proyecto->inmobiliaria()->razon}} +

+ @php + $today = new DateTimeImmutable(); + @endphp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Dirección{{$proyecto->direccion()}}
Inmobiliaria{{$proyecto->inmobiliaria()->nombreCompleto()}}
Inicio + {{$proyecto->estados()[0]->tipoEstadoProyecto->descripcion}} + [{{$proyecto->estados()[0]->tipoEstadoProyecto->etapa->descripcion}}] + ({{$proyecto->estados()[0]->fecha->format('d-m-Y')}}) + ({{$today->diff($proyecto->estados()[0]->fecha)->format('%y años antes')}}) +
Estado + {{$proyecto->currentEstado()->tipoEstadoProyecto->descripcion}} + [{{$proyecto->currentEstado()->tipoEstadoProyecto->etapa->descripcion}}] + ({{$proyecto->currentEstado()->fecha->format('d-m-Y')}}) + ({{$today->diff($proyecto->currentEstado()->fecha)->format('%y años antes')}}) + + + +
Superficies + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + Total + + + + {{$format->number($proyecto->superficie->total(), 2)}}m² + +
Bajo Nivel{{$format->number($proyecto->superficie->bajo_nivel, 2)}}m²
Sobre Nivel{{$format->number($proyecto->superficie->sobre_nivel, 2)}}m²
+ + Vendible + + + +
Vendido
Por Vender
+
Unidades
Ventas
Stock
Proyección
+
+@endsection + +@include('layout.body.scripts.chartjs') + +@push('page_scripts') + +@endpush diff --git a/app/src/Controller/API/Proyectos.php b/app/src/Controller/API/Proyectos.php index 5ed2152..2cf3608 100644 --- a/app/src/Controller/API/Proyectos.php +++ b/app/src/Controller/API/Proyectos.php @@ -3,13 +3,15 @@ namespace Incoviba\Controller\API; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; +use Incoviba\Common\Implement\Exception\EmptyRedis; use Incoviba\Common\Implement\Exception\EmptyResult; use Incoviba\Repository; use Incoviba\Model; +use Incoviba\Service; class Proyectos { - use withJson; + use withJson, withRedis; public function list(ServerRequestInterface $request, ResponseInterface $response, Repository\Proyecto $proyectoRepository): ResponseInterface { @@ -34,26 +36,88 @@ class Proyectos } catch (EmptyResult) {} return $this->withJson($response, $output); } - public function unidades(ServerRequestInterface $request, ResponseInterface $response, Repository\Venta\Unidad $unidadRepository, int $proyecto_id): ResponseInterface + public function unidades(ServerRequestInterface $request, ResponseInterface $response, + Repository\Venta\Unidad $unidadRepository, Service\Redis $redisService, + int $proyecto_id): ResponseInterface { $output = ['proyecto_id' => $proyecto_id, 'unidades' => [], 'total' => 0]; + $redisKey = "unidades-proyecto-{$proyecto_id}"; try { - $unidades = $unidadRepository->fetchDisponiblesByProyecto($proyecto_id); - $tipos = []; - foreach ($unidades as $unidad) { - if (!isset($tipos[$unidad->proyectoTipoUnidad->tipoUnidad->descripcion])) { - $tipos[$unidad->proyectoTipoUnidad->tipoUnidad->descripcion] = []; + $output = $this->fetchRedis($redisService, $redisKey); + } catch (EmptyRedis) { + try { + $unidades = $unidadRepository->fetchByProyecto($proyecto_id); + $tipos = []; + foreach ($unidades as $unidad) { + if (!isset($tipos[$unidad->proyectoTipoUnidad->tipoUnidad->descripcion])) { + $tipos[$unidad->proyectoTipoUnidad->tipoUnidad->descripcion] = []; + } + $tipos[$unidad->proyectoTipoUnidad->tipoUnidad->descripcion] []= $unidad; } - $tipos[$unidad->proyectoTipoUnidad->tipoUnidad->descripcion] []= $unidad; - } - foreach ($tipos as &$subtipo) { - usort($subtipo, function(Model\Venta\Unidad $a, Model\Venta\Unidad $b) { - return strcmp(str_pad($a->descripcion, 4, '0', STR_PAD_LEFT), str_pad($b->descripcion, 4, '0', STR_PAD_LEFT)); - }); - } - $output['unidades'] = $tipos; - $output['total'] = count($unidades); + foreach ($tipos as &$subtipo) { + usort($subtipo, function(Model\Venta\Unidad $a, Model\Venta\Unidad $b) { + return strcmp(str_pad($a->descripcion, 4, '0', STR_PAD_LEFT), str_pad($b->descripcion, 4, '0', STR_PAD_LEFT)); + }); + } + $output['unidades'] = $tipos; + $output['total'] = count($unidades); + $this->saveRedis($redisService, $redisKey, $output); + } catch (EmptyResult) {} + } + return $this->withJson($response, $output); + } + public function disponibles(ServerRequestInterface $request, ResponseInterface $response, Repository\Venta\Unidad $unidadRepository, int $proyecto_id): ResponseInterface + { + $output = [ + 'proyecto_id' => $proyecto_id, + 'unidades' => [] + ]; + try { + $output['unidades'] = $unidadRepository->fetchDisponiblesByProyecto($proyecto_id); } catch (EmptyResult) {} return $this->withJson($response, $output); } + public function superficies(ServerRequestInterface $request, ResponseInterface $response, + Repository\Proyecto $proyectoRepository, Repository\Venta $ventaRepository, + Repository\Venta\Unidad $unidadRepository, Service\Redis $redisService, + Service\Format $formatService, int $proyecto_id): ResponseInterface + { + $output = [ + 'proyecto_id' => $proyecto_id, + 'superficies' => [ + 'vendible' => 0, + 'vendido' => 0, + 'por_vender' => 0 + ], + 'formatted' => [ + 'vendible' => '0m²', + 'vendido' => '0m²', + 'por_vender' => '0m²' + ] + ]; + $redisKey = "superficices-proyecto-{$proyecto_id}"; + try { + $output = $this->fetchRedis($redisService, $redisKey); + } catch (EmptyRedis) { + try { + $ventas = $ventaRepository->fetchActivaByProyecto($proyecto_id); + $unidades = $unidadRepository->fetchDisponiblesByProyecto($proyecto_id); + + $output['superficies']['vendido'] = array_reduce($ventas, function($sum, Model\Venta $venta) { + return $sum + array_reduce($venta->propiedad()->unidades, function($sum, Model\Venta\Unidad $unidad) { + return $sum + $unidad->proyectoTipoUnidad->vendible(); + }); + }, 0); + $output['formatted']['vendido'] = "{$formatService->number($output['superficies']['vendido'], 2)}m²"; + $output['superficies']['por_vender'] = array_reduce($unidades, function($sum, Model\Venta\Unidad $unidad) { + return $sum + $unidad->proyectoTipoUnidad->vendible(); + }); + $output['formatted']['por_vender'] = "{$formatService->number($output['superficies']['por_vender'], 2)}m²"; + $output['superficies']['vendible'] = $output['superficies']['vendido'] + $output['superficies']['por_vender']; + $output['formatted']['vendible'] = "{$formatService->number($output['superficies']['vendible'], 2)}m²"; + $this->saveRedis($redisService, $redisKey, $output, 60 * 60); + } catch (EmptyResult) {} + } + return $this->withJson($response, $output); + } } diff --git a/app/src/Controller/API/Ventas.php b/app/src/Controller/API/Ventas.php index 87deea0..2604ae1 100644 --- a/app/src/Controller/API/Ventas.php +++ b/app/src/Controller/API/Ventas.php @@ -54,7 +54,7 @@ class Ventas $json = json_decode($body->getContents()); $proyecto_id = $json->proyecto_id; $today = new DateTimeImmutable(); - $redisKey = "promesas_por_firmar-{$proyecto_id}-{$today->format('Y-m-d')}"; + $redisKey = "promesas_por_firmar-proyecto-{$proyecto_id}-{$today->format('Y-m-d')}"; $output = [ 'proyecto_id' => $proyecto_id, @@ -80,7 +80,7 @@ class Ventas $json = json_decode($body->getContents()); $proyecto_id = $json->proyecto_id; $today = new DateTimeImmutable(); - $redisKey = "escrituras-{$proyecto_id}-{$today->format('Y-m-d')}"; + $redisKey = "escrituras-proyecto-{$proyecto_id}-{$today->format('Y-m-d')}"; $output = [ 'proyecto_id' => $proyecto_id, diff --git a/app/src/Controller/API/Ventas/Precios.php b/app/src/Controller/API/Ventas/Precios.php new file mode 100644 index 0000000..927e815 --- /dev/null +++ b/app/src/Controller/API/Ventas/Precios.php @@ -0,0 +1,36 @@ +getBody(); + $json = json_decode($body->getContents()); + $proyecto_id = $json->proyecto_id; + $output = ['total' => 0]; + try { + $precios = $precioService->getByProyecto($proyecto_id); + $output['precios'] = $precios; + $output['total'] = count($precios); + } catch (EmptyResult) {} + return $this->withJson($response, $output); + } + public function unidad(ServerRequestInterface $request, ResponseInterface $response, Service\Venta\Precio $precioService, int $unidad_id): ResponseInterface + { + try { + $precio = $precioService->getVigenteByUnidad($unidad_id); + return $this->withJson($response, compact('precio')); + } catch (EmptyResult) { + return $this->emptyBody($response); + } + } +} diff --git a/app/src/Controller/API/Ventas/Unidades.php b/app/src/Controller/API/Ventas/Unidades.php index 398f3af..9f8538f 100644 --- a/app/src/Controller/API/Ventas/Unidades.php +++ b/app/src/Controller/API/Ventas/Unidades.php @@ -22,7 +22,7 @@ class Unidades $json = json_decode($body->getContents()); $proyecto_id = $json->proyecto_id; $today = new DateTimeImmutable(); - $redisKey = "unidades_disponibles-{$proyecto_id}-{$today->format('Y-m-d')}"; + $redisKey = "unidades_disponibles-proyecto-{$proyecto_id}-{$today->format('Y-m-d')}"; $output = [ 'proyecto_id' => $proyecto_id, diff --git a/app/src/Controller/Proyectos.php b/app/src/Controller/Proyectos.php index 81c53b9..4f62910 100644 --- a/app/src/Controller/Proyectos.php +++ b/app/src/Controller/Proyectos.php @@ -4,8 +4,9 @@ namespace Incoviba\Controller; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Incoviba\Common\Alias\View; -use Incoviba\Repository; use Incoviba\Model; +use Incoviba\Repository; +use Incoviba\Service; class Proyectos { @@ -29,4 +30,9 @@ class Proyectos }); return $view->render($response, 'proyectos.unidades', compact('proyectos')); } + public function show(ServerRequestInterface $request, ResponseInterface $response, View $view, Service\Proyecto $proyectoService, int $proyecto_id): ResponseInterface + { + $proyecto = $proyectoService->getById($proyecto_id); + return $view->render($response, 'proyectos.show', compact('proyecto')); + } } diff --git a/app/src/Controller/Ventas/Precios.php b/app/src/Controller/Ventas/Precios.php index 6a96459..890d749 100644 --- a/app/src/Controller/Ventas/Precios.php +++ b/app/src/Controller/Ventas/Precios.php @@ -1,7 +1,6 @@ $proyecto->id, 'descripcion' => $proyecto->descripcion];}, $proyectoService->getVendibles()); return $view->render($response, 'ventas.precios.list', compact('proyectos')); } - public function proyecto(ServerRequestInterface $request, ResponseInterface $response, Service\Venta\Precio $precioService): ResponseInterface - { - $body = $request->getBody(); - $json = json_decode($body->getContents()); - $proyecto_id = $json->proyecto_id; - $output = ['total' => 0]; - try { - $precios = $precioService->getByProyecto($proyecto_id); - $output['precios'] = $precios; - $output['total'] = count($precios); - } catch (EmptyResult) {} - $response->getBody()->write(json_encode($output)); - return $response->withHeader('Content-Type', 'application/json'); - } - public function unidad(ServerRequestInterface $request, ResponseInterface $response, Service\Venta\Precio $precioService, int $unidad_id): ResponseInterface - { - $precio = $precioService->getVigenteByUnidad($unidad_id); - $response->getBody()->write(json_encode(['precio' => $precio])); - return $response->withHeader('Content-Type', 'application/json'); - } } diff --git a/app/src/Model/Proyecto.php b/app/src/Model/Proyecto.php index a0ab993..d4a2e69 100644 --- a/app/src/Model/Proyecto.php +++ b/app/src/Model/Proyecto.php @@ -1,6 +1,7 @@ inmobiliaria)) { @@ -29,6 +33,20 @@ class Proyecto extends Ideal\Model } return $this->direccion; } + public function estados(): array + { + if (!isset($this->estados)) { + $this->estados = $this->runFactory('estados'); + } + return $this->estados; + } + public function currentEstado(): Proyecto\EstadoProyecto + { + if (!isset($this->currentEstado)) { + $this->currentEstado = $this->runFactory('currentEstado'); + } + return $this->currentEstado; + } public function jsonSerialize(): mixed { diff --git a/app/src/Model/Proyecto/Superficie.php b/app/src/Model/Proyecto/Superficie.php index 72d6e5f..da7e1a9 100644 --- a/app/src/Model/Proyecto/Superficie.php +++ b/app/src/Model/Proyecto/Superficie.php @@ -5,4 +5,9 @@ class Superficie { public float $sobre_nivel; public float $bajo_nivel; + + public function total(): float + { + return $this->bajo_nivel + $this->sobre_nivel; + } } diff --git a/app/src/Model/Venta/Propiedad.php b/app/src/Model/Venta/Propiedad.php index 0e18cea..546a984 100644 --- a/app/src/Model/Venta/Propiedad.php +++ b/app/src/Model/Venta/Propiedad.php @@ -9,15 +9,15 @@ class Propiedad extends Ideal\Model public function departamentos(): array { - return array_filter($this->unidades, function(Unidad $unidad) {return $unidad->proyectoTipoUnidad->tipoUnidad->descripcion === 'departamento';}); + return array_values(array_filter($this->unidades, function(Unidad $unidad) {return $unidad->proyectoTipoUnidad->tipoUnidad->descripcion === 'departamento';})); } public function estacionamientos(): array { - return array_filter($this->unidades, function(Unidad $unidad) {return $unidad->proyectoTipoUnidad->tipoUnidad->descripcion === 'estacionamiento';}); + return array_values(array_filter($this->unidades, function(Unidad $unidad) {return $unidad->proyectoTipoUnidad->tipoUnidad->descripcion === 'estacionamiento';})); } public function bodegas(): array { - return array_filter($this->unidades, function(Unidad $unidad) {return $unidad->proyectoTipoUnidad->tipoUnidad->descripcion === 'bodega';}); + return array_values(array_filter($this->unidades, function(Unidad $unidad) {return $unidad->proyectoTipoUnidad->tipoUnidad->descripcion === 'bodega';})); } protected float $vendible; diff --git a/app/src/Repository/Proyecto.php b/app/src/Repository/Proyecto.php index 21b1c7e..e03de3b 100644 --- a/app/src/Repository/Proyecto.php +++ b/app/src/Repository/Proyecto.php @@ -92,6 +92,10 @@ WHERE et.`orden` BETWEEN {$etapaRecepcion->orden} AND ({$etapaTerminado->orden} ORDER BY a.`descripcion`"; return $this->fetchMany($query); } + public function fetchSuperficieVendido(int $proyecto_id): float + { + + } protected function joinEstado(): string { diff --git a/app/src/Service/Redis.php b/app/src/Service/Redis.php index 1d7f050..d8d61ce 100644 --- a/app/src/Service/Redis.php +++ b/app/src/Service/Redis.php @@ -15,8 +15,8 @@ class Redis } return $this->client->get($name); } - public function set(string $name, mixed $value): void + public function set(string $name, mixed $value, int $expirationTTL = 60 * 60 * 24): void { - $this->client->set($name, $value, 'EX', 60 * 60 * 24); + $this->client->set($name, $value, 'EX', $expirationTTL); } }